diff options
Diffstat (limited to 'wpa_supplicant')
156 files changed, 52255 insertions, 0 deletions
diff --git a/wpa_supplicant/.gitignore b/wpa_supplicant/.gitignore new file mode 100644 index 000000000000..e7e034c7fe80 --- /dev/null +++ b/wpa_supplicant/.gitignore @@ -0,0 +1,8 @@ +*.d +.config +eapol_test +preauth_test +wpa_cli +wpa_passphrase +wpa_supplicant +wpa_priv diff --git a/wpa_supplicant/ChangeLog b/wpa_supplicant/ChangeLog new file mode 100644 index 000000000000..8f5b6fbe1a0a --- /dev/null +++ b/wpa_supplicant/ChangeLog @@ -0,0 +1,1173 @@ +ChangeLog for wpa_supplicant + +2009-02-15 - v0.6.8 + * increased wpa_cli ping interval to 5 seconds and made this + configurable with a new command line options (-G<seconds>) + * fixed scan buffer processing with WEXT to handle up to 65535 + byte result buffer (previously, limited to 32768 bytes) + +2009-01-06 - v0.6.7 + * added support for Wi-Fi Protected Setup (WPS) + (wpa_supplicant can now be configured to act as a WPS Enrollee to + enroll credentials for a network using PIN and PBC methods; in + addition, wpa_supplicant can act as a wireless WPS Registrar to + configure an AP); WPS support can be enabled by adding CONFIG_WPS=y + into .config and setting the runtime configuration variables in + wpa_supplicant.conf (see WPS section in the example configuration + file); new wpa_cli commands wps_pin, wps_pbc, and wps_reg are used to + manage WPS negotiation; see README-WPS for more details + * added support for EAP-AKA' (draft-arkko-eap-aka-kdf) + * added support for using driver_test over UDP socket + * fixed PEAPv0 Cryptobinding interoperability issue with Windows Server + 2008 NPS; optional cryptobinding is now enabled (again) by default + * fixed PSK editing in wpa_gui + * changed EAP-GPSK to use the IANA assigned EAP method type 51 + * added a Windows installer that includes WinPcap and all the needed + DLLs; in addition, it set up the registry automatically so that user + will only need start wpa_gui to get prompted to start the wpasvc + servide and add a new interface if needed through wpa_gui dialog + * updated management frame protection to use IEEE 802.11w/D7.0 + +2008-11-23 - v0.6.6 + * added Milenage SIM/USIM emulator for EAP-SIM/EAP-AKA + (can be used to simulate test SIM/USIM card with a known private key; + enable with CONFIG_SIM_SIMULATOR=y/CONFIG_USIM_SIMULATOR=y in .config + and password="Ki:OPc"/password="Ki:OPc:SQN" in network configuration) + * added a new network configuration option, wpa_ptk_rekey, that can be + used to enforce frequent PTK rekeying, e.g., to mitigate some attacks + against TKIP deficiencies + * added an optional mitigation mechanism for certain attacks against + TKIP by delaying Michael MIC error reports by a random amount of time + between 0 and 60 seconds; this can be enabled with a build option + CONFIG_DELAYED_MIC_ERROR_REPORT=y in .config + * fixed EAP-AKA to use RES Length field in AT_RES as length in bits, + not bytes + * 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) + * updated userspace MLME instructions to match with the current Linux + mac80211 implementation; please also note that this can only be used + with driver_nl80211.c (the old code from driver_wext.c was removed) + * added support (Linux only) for RoboSwitch chipsets (often found in + consumer grade routers); driver interface 'roboswitch' + * fixed canceling of PMKSA caching when using drivers that generate + RSN IE and refuse to drop PMKIDs that wpa_supplicant does not know + about + +2008-11-01 - v0.6.5 + * added support for SHA-256 as X.509 certificate digest when using the + internal X.509/TLSv1 implementation + * updated management frame protection to use IEEE 802.11w/D6.0 + * added support for using SHA256-based stronger key derivation for WPA2 + (IEEE 802.11w) + * fixed FT (IEEE 802.11r) authentication after a failed association to + use correct FTIE + * added support for configuring Phase 2 (inner/tunneled) authentication + method with wpa_gui-qt4 + +2008-08-10 - v0.6.4 + * added support for EAP Sequences in EAP-FAST Phase 2 + * added support for using TNC with EAP-FAST + * added driver_ps3 for the PS3 Linux wireless driver + * added support for optional cryptobinding with PEAPv0 + * fixed the OpenSSL patches (0.9.8g and 0.9.9) for EAP-FAST to + allow fallback to full handshake if server rejects PAC-Opaque + * added fragmentation support for EAP-TNC + * added support for parsing PKCS #8 formatted private keys into the + internal TLS implementation (both PKCS #1 RSA key and PKCS #8 + encapsulated RSA key can now be used) + * added option of using faster, but larger, routines in the internal + LibTomMath (for internal TLS implementation) to speed up DH and RSA + calculations (CONFIG_INTERNAL_LIBTOMMATH_FAST=y) + * fixed race condition between disassociation event and group key + handshake to avoid getting stuck in incorrect state [Bug 261] + * fixed opportunistic key caching (proactive_key_caching) + +2008-02-22 - v0.6.3 + * removed 'nai' and 'eappsk' network configuration variables that were + previously used for configuring user identity and key for EAP-PSK, + EAP-PAX, EAP-SAKE, and EAP-GPSK. 'identity' field is now used as the + replacement for 'nai' (if old configuration used a separate + 'identity' value, that would now be configured as + 'anonymous_identity'). 'password' field is now used as the + replacement for 'eappsk' (it can also be set using hexstring to + present random binary data) + * removed '-w' command line parameter (wait for interface to be added, + if needed); cleaner way of handling this functionality is to use an + external mechanism (e.g., hotplug scripts) that start wpa_supplicant + when an interface is added + * updated FT support to use the latest draft, IEEE 802.11r/D9.0 + * added ctrl_iface monitor event (CTRL-EVENT-SCAN-RESULTS) for + indicating when new scan results become available + * added new ctrl_iface command, BSS, to allow scan results to be + fetched without hitting the message size limits (this command + can be used to iterate through the scan results one BSS at the time) + * fixed EAP-SIM not to include AT_NONCE_MT and AT_SELECTED_VERSION + attributes in EAP-SIM Start/Response when using fast reauthentication + * fixed EAPOL not to end up in infinite loop when processing dynamic + WEP keys with IEEE 802.1X + * fixed problems in getting NDIS events from WMI on Windows 2000 + +2008-01-01 - v0.6.2 + * added support for Makefile builds to include debug-log-to-a-file + functionality (CONFIG_DEBUG_FILE=y and -f<path> on command line) + * 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 wpa_supplicant 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 (phase1="result_ind=1") + * added driver_wext workaround for race condition between scanning and + association with drivers that take very long time to scan all + channels (e.g., madwifi with dual-band cards); wpa_supplicant is now + using a longer hardcoded timeout for the scan if the driver supports + notifications for scan completion (SIOCGIWSCAN event); this helps, + e.g., in cases where wpa_supplicant and madwifi driver ended up in + loop where the driver did not even try to associate + * stop EAPOL timer tick when no timers are in use in order to reduce + power consumption (no need to wake up the process once per second) + [Bug 237] + * added support for privilege separation (run only minimal part of + wpa_supplicant functionality as root and rest as unprivileged, + non-root process); see 'Privilege separation' in README for details; + this is disabled by default and can be enabled with CONFIG_PRIVSEP=y + in .config + * changed scan results data structure to include all information + elements to make it easier to support new IEs; old get_scan_result() + driver_ops is still supported for backwards compatibility (results + are converted internally to the new format), but all drivers should + start using the new get_scan_results2() to make them more likely to + work with new features + * Qt4 version of wpa_gui (wpa_gui-qt4 subdirectory) is now native Qt4 + application, i.e., it does not require Qt3Support anymore; Windows + binary of wpa_gui.exe is now from this directory and only requires + QtCore4.dll and QtGui4.dll libraries + * updated Windows binary build to use Qt 4.3.3 and made Qt DLLs + available as a separate package to make wpa_gui installation easier: + http://w1.fi/wpa_supplicant/qt4/wpa_gui-qt433-windows-dll.zip + * 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 support for configuring password as NtPasswordHash + (16-byte MD4 hash of password) in hash:<32 hex digits> format + * added support for fallback from abbreviated TLS handshake to + full handshake when using EAP-FAST (e.g., due to an expired + PAC-Opaque) + * updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest + draft (draft-ietf-emu-eap-gpsk-07.txt) + * added support for drivers that take care of RSN 4-way handshake + internally (WPA_DRIVER_FLAGS_4WAY_HANDSHAKE in get_capa flags and + WPA_ALG_PMK in set_key) + * added an experimental port for Mac OS X (CONFIG_DRIVER_OSX=y in + .config); this version supports only ap_scan=2 mode and allow the + driver to take care of the 4-way handshake + * fixed a buffer overflow in parsing TSF from scan results when using + driver_wext.c with a driver that includes the TSF (e.g., iwl4965) + [Bug 232] + * updated FT support to use the latest draft, IEEE 802.11r/D8.0 + * fixed an integer overflow issue in the ASN.1 parser used by the + (experimental) internal TLS implementation to avoid a potential + buffer read overflow + * fixed a race condition with -W option (wait for a control interface + monitor before starting) that could have caused the first messages to + be lost + * added support for processing TNCC-TNCS-Messages to report + recommendation (allow/none/isolate) when using TNC [Bug 243] + +2007-05-28 - v0.6.0 + * added network configuration parameter 'frequency' for setting + initial channel for IBSS (adhoc) networks + * 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-PAX key derivation + * fixed EAP-PSK bit ordering of the Flags field + * fixed EAP-PEAP/TTLS/FAST to use the correct EAP identifier in + tunnelled identity request (previously, the identifier from the outer + method was used, not the tunnelled identifier which could be + different) + * added support for fragmentation of outer TLS packets during Phase 2 + of EAP-PEAP/TTLS/FAST + * fixed EAP-TTLS AVP parser processing for too short AVP lengths + * added support for EAP-FAST authentication with inner methods that + generate MSK (e.g., EAP-MSCHAPv2 that was previously only supported + for PAC provisioning) + * added support for authenticated EAP-FAST provisioning + * added support for configuring maximum number of EAP-FAST PACs to + store in a PAC list (fast_max_pac_list_len=<max> in phase1 string) + * added support for storing EAP-FAST PACs in binary format + (fast_pac_format=binary in phase1 string) + * fixed dbus ctrl_iface to validate message interface before + dispatching to avoid a possible segfault [Bug 190] + * fixed PeerKey key derivation to use the correct PRF label + * updated Windows binary build to link against OpenSSL 0.9.8d and + added support for EAP-FAST + * updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest + draft (draft-ietf-emu-eap-gpsk-04.txt) + * fixed EAP-AKA Notification processing to allow Notification to be + processed after AKA Challenge response has been sent + * updated to use IEEE 802.11w/D2.0 for management frame protection + (still experimental) + * fixed EAP-TTLS implementation not to crash on use of freed memory + if TLS library initialization fails + * added support for EAP-TNC (Trusted Network Connect) + (this version implements the EAP-TNC method and EAP-TTLS changes + needed to run two methods in sequence (IF-T) and the IF-IMC and + IF-TNCCS interfaces from TNCC) + +2006-11-24 - v0.5.6 + * added experimental, integrated TLSv1 client 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 + (total size of this internal TLS/crypto code is bit under 50 kB on + x86 and the crypto code is shared by rest of the supplicant so some + of it was already required; TLSv1/X.509/ASN.1/RSA added about 25 kB) + * 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.) + * fixed Windows named pipes ctrl_iface to not stop listening for + commands if client program opens a named pipe and closes it + immediately without sending a command + * fixed USIM PIN status determination for the case that PIN is not + needed (this allows EAP-AKA to be used with USIM cards that do not + use PIN) + * added support for reading 3G USIM AID from EF_DIR to allow EAP-AKA to + be used with cards that do not support file selection based on + partial AID + * added support for matching the subjectAltName of the authentication + server certificate against multiple name components (e.g., + altsubject_match="DNS:server.example.com;DNS:server2.example.com") + * fixed EAP-SIM/AKA key derivation for re-authentication case (only + affects IEEE 802.1X with dynamic WEP keys) + * changed ctrl_iface network configuration 'get' operations to not + return password/key material; if these fields are requested, "*" + will be returned if the password/key is set, but the value of the + parameter is not exposed + +2006-08-27 - v0.5.5 + * added support for building Windows version with UNICODE defined + (wide-char functions) + * driver_ndis: fixed static WEP configuration to avoid race condition + issues with some NDIS drivers between association and setting WEP + keys + * driver_ndis: added validation for IELength value in scan results to + avoid crashes when using buggy NDIS drivers [Bug 165] + * fixed Release|Win32 target in the Visual Studio project files + (previously, only Debug|Win32 target was set properly) + * changed control interface API call wpa_ctrl_pending() to allow it to + return -1 on error (e.g., connection lost); control interface clients + will need to make sure that they verify that the value is indeed >0 + when determining whether there are pending messages + * added an alternative control interface backend for Windows targets: + Named Pipe (CONFIG_CTRL_IFACE=named_pipe); this is now the default + control interface mechanism for Windows builds (previously, UDP to + localhost was used) + * changed ctrl_interface configuration for UNIX domain sockets: + - deprecated ctrl_interface_group variable (it may be removed in + future versions) + - allow both directory and group be configured with ctrl_interface + in following format: DIR=/var/run/wpa_supplicant GROUP=wheel + - ctrl_interface=/var/run/wpa_supplicant is still supported for the + case when group is not changed + * added support for controlling more than one interface per process in + Windows version + * added a workaround for a case where the AP is using unknown address + (e.g., MAC address of the wired interface) as the source address for + EAPOL-Key frames; previously, that source address was used as the + destination for EAPOL-Key frames and in key derivation; now, BSSID is + used even if the source address does not match with it + (this resolves an interoperability issue with Thomson SpeedTouch 580) + * added a workaround for UDP-based control interface (which was used in + Windows builds before this release) to prevent packets with forged + addresses from being accepted as local control requests + * removed ndis_events.cpp and possibility of using external + ndis_events.exe; C version (ndis_events.c) is fully functional and + there is no desire to maintain two separate versions of this + implementation + * ndis_events: Changed NDIS event notification design to use WMI to + learn the adapter description through Win32_PnPEntity class; this + should fix some cases where the adapter name was not recognized + correctly (e.g., with some USB WLAN adapters, e.g., Ralink RT2500 + USB) [Bug 113] + * fixed selection of the first network in ap_scan=2 mode; previously, + wpa_supplicant could get stuck in SCANNING state when only the first + network for enabled (e.g., after 'wpa_cli select_network 0') + * winsvc: added support for configuring ctrl_interface parameters in + registry (ctrl_interface string value in + HKLM\SOFTWARE\wpa_supplicant\interfaces\0000 key); this new value is + required to enable control interface (previously, this was hardcoded + to be enabled) + * allow wpa_gui subdirectory to be built with both Qt3 and Qt4 + * converted wpa_gui-qt4 subdirectory to use Qt4 specific project format + +2006-06-20 - v0.5.4 + * fixed build with CONFIG_STAKEY=y [Bug 143] + * added support for doing MLME (IEEE 802.11 management frame + processing) in wpa_supplicant when using Devicescape IEEE 802.11 + stack (wireless-dev.git tree) + * added a new network block configuration option, fragment_size, to + configure the maximum EAP fragment size + * driver_ndis: Disable WZC automatically for the selected interface to + avoid conflicts with two programs trying to control the radio; WZC + will be re-enabled (if it was enabled originally) when wpa_supplicant + is terminated + * added an experimental TLSv1 client implementation + (CONFIG_TLS=internal) that can be used instead of an external TLS + library, e.g., to reduce total size requirement on systems that do + not include any TLS library by default (this is not yet complete; + basic functionality is there, but certificate validation is not yet + included) + * added PeerKey handshake implementation for IEEE 802.11e + direct link setup (DLS) to replace STAKey handshake + * fixed WPA PSK update through ctrl_iface for the case where the old + PSK was derived from an ASCII passphrase and the new PSK is set as + a raw PSK (hex string) + * added new configuration option for identifying which network block + was used (id_str in wpa_supplicant.conf; included on + WPA_EVENT_CONNECT monitor event and as WPA_ID_STR environmental + variable in wpa_cli action scripts; in addition WPA_ID variable is + set to the current unique identifier that wpa_supplicant assigned + automatically for the network and that can be used with + GET_NETWORK/SET_NETWORK ctrl_iface commands) + * wpa_cli action script is now called only when the connect/disconnect + status changes or when associating with a different network + * fixed configuration parser not to remove CCMP from group cipher list + if WPA-None (adhoc) is used (pairwise=NONE in that case) + * fixed integrated NDIS events processing not to hang the process due + to a missed change in eloop_win.c API in v0.5.3 [Bug 155] + * added support for EAP Generalized Pre-Shared Key (EAP-GPSK, + draft-clancy-emu-eap-shared-secret-00.txt) + * added Microsoft Visual Studio 2005 solution and project files for + build wpa_supplicant for Windows (see vs2005 subdirectory) + * eloop_win: fixed unregistration of Windows events + * l2_packet_winpcap: fixed a deadlock in deinitializing l2_packet + at the end of RSN pre-authentication and added unregistration of + a Windows event to avoid getting eloop_win stuck with an invalid + handle + * driver_ndis: added support for selecting AP based on BSSID + * added new environmental variable for wpa_cli action scripts: + WPA_CTRL_DIR is the current control interface directory + * driver_ndis: added support for using NDISUIO instead of WinPcap for + OID set/query operations (CONFIG_USE_NDISUIO=y in .config); with new + l2_packet_ndis (CONFIG_L2_PACKET=ndis), this can be used to build + wpa_supplicant without requiring WinPcap; note that using NDISUIO + requires that WZC is disabled (net stop wzcsvc) since NDISUIO allows + only one application to open the device + * changed NDIS driver naming to only include device GUID, e.g., + {7EE3EFE5-C165-472F-986D-F6FBEDFE8C8D}, instead of including WinPcap + specific \Device\NPF_ prefix before the GUID; the prefix is still + allowed for backwards compatibility, but it is not required anymore + when specifying the interface + * driver_ndis: re-initialize driver interface is the adapter is removed + and re-inserted [Bug 159] + * driver_madwifi: fixed TKIP and CCMP sequence number configuration on + big endian hosts [Bug 146] + +2006-04-27 - v0.5.3 + * fixed EAP-GTC response to include correct user identity when run as + phase 2 method of EAP-FAST (i.e., EAP-FAST did not work in v0.5.2) + * driver_ndis: Fixed encryption mode configuration for unencrypted + networks (some NDIS drivers ignored this, but others, e.g., Broadcom, + refused to associate with open networks) [Bug 106] + * driver_ndis: use BSSID OID polling to detect when IBSS network is + formed even when ndis_events code is included since some NDIS drivers + do not generate media connect events in IBSS mode + * config_winreg: allow global ctrl_interface parameter to be configured + in Windows registry + * config_winreg: added support for saving configuration data into + Windows registry + * added support for controlling network device operational state + (dormant/up) for Linux 2.6.17 to improve DHCP processing (see + http://www.flamewarmaster.de/software/dhcpclient/ for a DHCP client + that can use this information) + * driver_wext: added support for WE-21 change to SSID configuration + * driver_wext: fixed privacy configuration for static WEP keys mode + [Bug 140] + * added an optional driver_ops callback for MLME-SETPROTECTION.request + primitive + * added support for EAP-SAKE (no EAP method number allocated yet, so + this is using the same experimental type 255 as EAP-PSK) + * added support for dynamically loading EAP methods (.so files) instead + of requiring them to be statically linked in; this is disabled by + default (see CONFIG_DYNAMIC_EAP_METHODS in defconfig for information + on how to use this) + +2006-03-19 - v0.5.2 + * do not try to use USIM APDUs when initializing PC/SC for SIM card + access for a network that has not enabled EAP-AKA + * fixed EAP phase 2 Nak for EAP-{PEAP,TTLS,FAST} (this was broken in + v0.5.1 due to the new support for expanded EAP types) + * added support for generating EAP Expanded Nak + * try to fetch scan results once before requesting new scan when + starting up in ap_scan=1 mode (this can speed up initial association + a lot with, e.g., madwifi-ng driver) + * added support for receiving EAPOL frames from a Linux bridge + interface (-bbr0 on command line) + * fixed EAPOL re-authentication for sessions that used PMKSA caching + * changed EAP method registration to use a dynamic list of methods + instead of a static list generated at build time + * fixed PMKSA cache deinitialization not to use freed memory when + removing PMKSA entries + * fixed a memory leak in EAP-TTLS re-authentication + * reject WPA/WPA2 message 3/4 if it does not include any valid + WPA/RSN IE + * driver_wext: added fallback to use SIOCSIWENCODE for setting auth_alg + if the driver does not support SIOCSIWAUTH + +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 (driver_param=test_dir=/tmp/test) + * added support for EAP expanded type (vendor specific EAP methods) + * added AP_SCAN command into ctrl_iface so that ap_scan configuration + option can be changed if needed + * wpa_cli/wpa_gui: skip non-socket files in control directory when + using UNIX domain sockets; this avoids selecting an incorrect + interface (e.g., a PID file could be in this directory, even though + use of this directory for something else than socket files is not + recommended) + * fixed TLS library deinitialization after RSN pre-authentication not + to disable TLS library for normal authentication + * driver_wext: Remove null-termination from SSID length if the driver + used it; some Linux drivers do this and they were causing problems in + wpa_supplicant not finding matching configuration block. This change + would break a case where the SSID actually ends in '\0', but that is + not likely to happen in real use. + * fixed PMKSA cache processing not to trigger deauthentication if the + current PMKSA cache entry is replaced with a valid new entry + * fixed PC/SC initialization for ap_scan != 1 modes (this fixes + EAP-SIM and EAP-AKA with real SIM/USIM card when using ap_scan=0 or + ap_scan=2) + +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) + * fixed EAP-SIM and EAP-AKA pseudonym and fast re-authentication to + decrypt AT_ENCR_DATA attributes correctly + * fixed EAP-AKA to allow resynchronization within the same session + * made code closer to ANSI C89 standard to make it easier to port to + other C libraries and compilers + * started moving operating system or C library specific functions into + wrapper functions defined in os.h and implemented in os_*.c to make + code more portable + * wpa_supplicant can now be built with Microsoft Visual C++ + (e.g., with the freely available Toolkit 2003 version or Visual + C++ 2005 Express Edition and Platform SDK); see nmake.mak for an + example makefile for nmake + * added support for using Windows registry for command line parameters + (CONFIG_MAIN=main_winsvc) and configuration data + (CONFIG_BACKEND=winreg); see win_example.reg for an example registry + contents; this version can be run both as a Windows service and as a + normal application; 'wpasvc.exe app' to start as applicant, + 'wpasvc.exe reg <full path to wpasvc.exe>' to register a service, + 'net start wpasvc' to start the service, 'wpasvc.exe unreg' to + unregister a service + * made it possible to link ndis_events.exe functionality into + wpa_supplicant.exe by defining CONFIG_NDIS_EVENTS_INTEGRATED + * added better support for multiple control interface backends + (CONFIG_CTRL_IFACE option); currently, 'unix' and 'udp' are supported + * fixed PC/SC code to use correct length for GSM AUTH command buffer + and to not use pioRecvPci with SCardTransmit() calls; these were not + causing visible problems with pcsc-lite, but Windows Winscard.dll + refused the previously used parameters; this fixes EAP-SIM and + EAP-AKA authentication using SIM/USIM card under Windows + * added new event loop implementation for Windows using + WaitForMultipleObject() instead of select() in order to allow waiting + for non-socket objects; this can be selected with + CONFIG_ELOOP=eloop_win in .config + * added support for selecting l2_packet implementation in .config + (CONFIG_L2_PACKET; following options are available now: linux, pcap, + winpcap, freebsd, none) + * added new l2_packet implementation for WinPcap + (CONFIG_L2_PACKET=winpcap) that uses a separate receive thread to + reduce latency in EAPOL receive processing from about 100 ms to about + 3 ms + * added support for EAP-FAST key derivation using other ciphers than + RC4-128-SHA for authentication and AES128-SHA for provisioning + * added support for configuring CA certificate as DER file and as a + configuration blob + * fixed private key configuration as configuration blob and added + support for using PKCS#12 as a blob + * tls_gnutls: added support for using PKCS#12 files; added support for + session resumption + * added support for loading trusted CA certificates from Windows + certificate store: ca_cert="cert_store://<name>", where <name> is + likely CA (Intermediate CA certificates) or ROOT (root certificates) + * added C version of ndis_events.cpp and made it possible to build this + with MinGW so that CONFIG_NDIS_EVENTS_INTEGRATED can be used more + easily on cross-compilation builds + * added wpasvc.exe into Windows binary release; this is an alternative + version of wpa_supplicant.exe with configuration backend using + Windows registry and with the entry point designed to run as a + Windows service + * integrated ndis_events.exe functionality into wpa_supplicant.exe and + wpasvc.exe and removed this additional tool from the Windows binary + release since it is not needed anymore + * load winscard.dll functions dynamically when building with MinGW + since MinGW does not yet include winscard library + +2005-11-20 - v0.4.7 (beginning of 0.4.x stable releases) + * l2_packet_pcap: fixed wired IEEE 802.1X authentication with libpcap + and WinPcap to receive frames sent to PAE group address + * disable EAP state machine when IEEE 802.1X authentication is not used + in order to get rid of bogus "EAP failed" messages + * fixed OpenSSL error reporting to go through all pending errors to + avoid confusing reports of old errors being reported at later point + during handshake + * fixed configuration file updating to not write empty variables + (e.g., proto or key_mgmt) that the file parser would not accept + * fixed ADD_NETWORK ctrl_iface command to use the same default values + for variables as empty network definitions read from config file + would get + * fixed EAP state machine to not discard EAP-Failure messages in many + cases (e.g., during TLS handshake) + * fixed a infinite loop in private key reading if the configured file + cannot be parsed successfully + * driver_madwifi: added support for madwifi-ng + * wpa_gui: do not display password/PSK field contents + * wpa_gui: added CA certificate configuration + * driver_ndis: fixed scan request in ap_scan=2 mode not to change SSID + * driver_ndis: include Beacon IEs in AssocInfo in order to notice if + the new AP is using different WPA/RSN IE + * use longer timeout for IEEE 802.11 association to avoid problems with + drivers that may take more than five second to associate + +2005-10-27 - v0.4.6 + * allow fallback to WPA, if mixed WPA+WPA2 networks have mismatch in + RSN IE, but WPA IE would match with wpa_supplicant configuration + * added support for named configuration blobs in order to avoid having + to use file system for external files (e.g., certificates); + variables can be set to "blob://<blob name>" instead of file path to + use a named blob; supported fields: pac_file, client_cert, + private_key + * fixed RSN pre-authentication (it was broken in the clean up of WPA + state machine interface in v0.4.5) + * driver_madwifi: set IEEE80211_KEY_GROUP flag for group keys to make + sure the driver configures broadcast decryption correctly + * added ca_path (and ca_path2) configuration variables that can be used + to configure OpenSSL CA path, e.g., /etc/ssl/certs, for using the + system-wide trusted CA list + * added support for starting wpa_supplicant without a configuration + file (-C argument must be used to set ctrl_interface parameter for + this case; in addition, -p argument can be used to provide + driver_param; these new arguments can also be used with a + configuration to override the values from the configuration) + * added global control interface that can be optionally used for adding + and removing network interfaces dynamically (-g command line argument + for both wpa_supplicant and wpa_cli) without having to restart + wpa_supplicant process + * wpa_gui: + - try to save configuration whenever something is modified + - added WEP key configuration + - added possibility to edit the current network configuration + * driver_ndis: fixed driver polling not to increase frequency on each + received EAPOL frame due to incorrectly cancelled timeout + * added simple configuration file examples (in examples subdirectory) + * fixed driver_wext.c to filter wireless events based on ifindex to + avoid interfaces receiving events from other interfaces + * delay sending initial EAPOL-Start couple of seconds to speed up + authentication for the most common case of Authenticator starting + EAP authentication immediately after association + +2005-09-25 - v0.4.5 + * added a workaround for clearing keys with ndiswrapper to allow + roaming from WPA enabled AP to plaintext one + * added docbook documentation (doc/docbook) that can be used to + generate, e.g., man pages + * l2_packet_linux: use socket type SOCK_DGRAM instead of SOCK_RAW for + PF_PACKET in order to prepare for network devices that do not use + Ethernet headers (e.g., network stack with native IEEE 802.11 frames) + * use receipt of EAPOL-Key frame as a lower layer success indication + for EAP state machine to allow recovery from dropped EAP-Success + frame + * cleaned up internal EAPOL frame processing by not including link + layer (Ethernet) header during WPA and EAPOL/EAP processing; this + header is added only when transmitted the frame; this makes it easier + to use wpa_supplicant on link layers that use different header than + Ethernet + * updated EAP-PSK to use draft 9 by default since this can now be + tested with hostapd; removed support for draft 3, including + server_nai configuration option from network blocks + * driver_wired: add PAE address to the multicast address list in order + to be able to receive EAPOL frames with drivers that do not include + these multicast addresses by default + * driver_wext: add support for WE-19 + * added support for multiple configuration backends (CONFIG_BACKEND + option); currently, only 'file' is supported (i.e., the format used + in wpa_supplicant.conf) + * added support for updating configuration ('wpa_cli save_config'); + this is disabled by default and can be enabled with global + update_config=1 variable in wpa_supplicant.conf; this allows wpa_cli + and wpa_gui to store the configuration changes in a permanent store + * added GET_NETWORK ctrl_iface command + (e.g., 'wpa_cli get_network 0 ssid') + +2005-08-21 - v0.4.4 + * replaced OpenSSL patch for EAP-FAST support + (openssl-tls-extensions.patch) with a more generic and correct + patch (the new patch is not compatible with the previous one, so the + OpenSSL library will need to be patched with the new patch in order + to be able to build wpa_supplicant with EAP-FAST support) + * added support for using Windows certificate store (through CryptoAPI) + for client certificate and private key operations (EAP-TLS) + (see wpa_supplicant.conf for more information on how to configure + this with private_key) + * ported wpa_gui to Windows + * added Qt4 version of wpa_gui (wpa_gui-qt4 directory); this can be + built with the open source version of the Qt4 for Windows + * allow non-WPA modes (e.g., IEEE 802.1X with dynamic WEP) to be used + with drivers that do not support WPA + * ndis_events: fixed Windows 2000 support + * added support for enabling/disabling networks from the list of all + configured networks ('wpa_cli enable_network <network id>' and + 'wpa_cli disable_network <network id>') + * added support for adding and removing network from the current + configuration ('wpa_cli add_network' and 'wpa_cli remove_network + <network id>'); added networks are disabled by default and they can + be enabled with enable_network command once the configuration is done + for the new network; note: configuration file is not yet updated, so + these new networks are lost when wpa_supplicant is restarted + * added support for setting network configuration parameters through + the control interface, for example: + wpa_cli set_network 0 ssid "\"my network\"" + * fixed parsing of strings that include both " and # within double + quoted area (e.g., "start"#end") + * added EAP workaround for PEAP session resumption: allow outer, + i.e., not tunneled, EAP-Success to terminate session since; this can + be disabled with eap_workaround=0 + (this was allowed for PEAPv1 before, but now it is also allowed for + PEAPv0 since at least one RADIUS authentication server seems to be + doing this for PEAPv0, too) + * wpa_gui: added preliminary support for adding new networks to the + wpa_supplicant configuration (double click on the scan results to + open network configuration) + +2005-06-26 - v0.4.3 + * removed interface for external EAPOL/EAP supplicant (e.g., + Xsupplicant), (CONFIG_XSUPPLICANT_IFACE) since it is not required + anymore and is unlikely to be used by anyone + * driver_ndis: fixed WinPcap 3.0 support + * fixed build with CONFIG_DNET_PCAP=y on Linux + * l2_packet: moved different implementations into separate files + (l2_packet_*.c) + +2005-06-12 - v0.4.2 + * driver_ipw: updated driver structures to match with ipw2200-1.0.4 + (note: ipw2100-1.1.0 is likely to require an update to work with + this) + * added support for using ap_scan=2 mode with multiple network blocks; + wpa_supplicant will go through the networks one by one until the + driver reports a successful association; this uses the same order for + networks as scan_ssid=1 scans, i.e., the priority field is ignored + and the network block order in the file is used instead + * fixed a potential issue in RSN pre-authentication ending up using + freed memory if pre-authentication times out + * added support for matching alternative subject name extensions of the + authentication server certificate; new configuration variables + altsubject_match and altsubject_match2 + * driver_ndis: added support for IEEE 802.1X authentication with wired + NDIS drivers + * added support for querying private key password (EAP-TLS) through the + control interface (wpa_cli/wpa_gui) if one is not included in the + configuration file + * driver_broadcom: fixed couple of memory leaks in scan result + processing + * EAP-PAX is now registered as EAP type 46 + * fixed EAP-PAX MAC calculation + * fixed EAP-PAX CK and ICK key derivation + * added support for using password with EAP-PAX (as an alternative to + entering key with eappsk); SHA-1 hash of the password will be used as + the key in this case + * added support for arbitrary driver interface parameters through the + configuration file with a new driver_param field; this adds a new + driver_ops function set_param() + * added possibility to override l2_packet module with driver interface + API (new send_eapol handler); this can be used to implement driver + specific TX/RX functions for EAPOL frames + * fixed ctrl_interface_group processing for the case where gid is + entered as a number, not group name + * 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 + * driver_madwifi: fixed WPA/WPA2 mode configuration to allow EAPOL + packets to be encrypted; this was apparently broken by the changed + ioctl order in v0.4.0 + * driver_madwifi: added preliminary support for compiling against 'BSD' + branch of madwifi CVS tree + * added support for EAP-MSCHAPv2 password retries within the same EAP + authentication session + * added support for password changes with EAP-MSCHAPv2 (used when the + password has expired) + * added support for reading additional certificates from PKCS#12 files + and adding them to the certificate chain + * fixed association with IEEE 802.1X (no WPA) when dynamic WEP keys + were used + * fixed a possible double free in EAP-TTLS fast-reauthentication when + identity or password is entered through control interface + * display EAP Notification messages to user through control interface + with "CTRL-EVENT-EAP-NOTIFICATION" prefix + * added GUI version of wpa_cli, wpa_gui; this is not build + automatically with 'make'; use 'make wpa_gui' to build (this requires + Qt development tools) + * added 'disconnect' command to control interface for setting + wpa_supplicant in state where it will not associate before + 'reassociate' command has been used + * added support for selecting a network from the list of all configured + networks ('wpa_cli select_network <network id>'; this disabled all + other networks; to re-enable, 'wpa_cli select_network any') + * added support for getting scan results through control interface + * added EAP workaround for PEAPv1 session resumption: allow outer, + i.e., not tunneled, EAP-Success to terminate session since; this can + be disabled with eap_workaround=0 + +2005-04-25 - v0.4.0 (beginning of 0.4.x development releases) + * added a new build time option, CONFIG_NO_STDOUT_DEBUG, that can be + used to reduce the size of the wpa_supplicant considerably if + debugging code is not needed + * fixed EAPOL-Key validation to drop packets with invalid Key Data + Length; such frames could have crashed wpa_supplicant due to buffer + overflow + * added support for wired authentication (IEEE 802.1X on wired + Ethernet); driver interface 'wired' + * obsoleted set_wpa() handler in the driver interface API (it can be + replaced by moving enable/disable functionality into init()/deinit()) + (calls to set_wpa() are still present for backwards compatibility, + but they may be removed in the future) + * driver_madwifi: fixed association in plaintext mode + * modified the EAP workaround that accepts EAP-Success with incorrect + Identifier to be even less strict about verification in order to + interoperate with some authentication servers + * added support for sending TLS alerts + * added support for 'any' SSID wildcard; if ssid is not configured or + is set to an empty string, any SSID will be accepted for non-WPA AP + * added support for asking PIN (for SIM) from frontends (e.g., + wpa_cli); if a PIN is needed, but not included in the configuration + file, a control interface request is sent and EAP processing is + delayed until the PIN is available + * added support for using external devices (e.g., a smartcard) for + private key operations in EAP-TLS (CONFIG_SMARTCARD=y in .config); + new wpa_supplicant.conf variables: + - global: opensc_engine_path, pkcs11_engine_path, pkcs11_module_path + - network: engine, engine_id, key_id + * added experimental support for EAP-PAX + * added monitor mode for wpa_cli (-a<path to a program to run>) that + allows external commands (e.g., shell scripts) to be run based on + wpa_supplicant events, e.g., when authentication has been completed + and data connection is ready; other related wpa_cli arguments: + -B (run in background), -P (write PID file); wpa_supplicant has a new + command line argument (-W) that can be used to make it wait until a + control interface command is received in order to avoid missing + events + * added support for opportunistic WPA2 PMKSA key caching (disabled by + default, can be enabled with proactive_key_caching=1) + * fixed RSN IE in 4-Way Handshake message 2/4 for the case where + Authenticator rejects PMKSA caching attempt and the driver is not + using assoc_info events + * added -P<pid file> argument for wpa_supplicant to write the current + process id into a file + +2005-02-12 - v0.3.7 (beginning of 0.3.x stable releases) + * added new phase1 option parameter, include_tls_length=1, to force + wpa_supplicant to add TLS Message Length field to all TLS messages + even if the packet is not fragmented; this may be needed with some + authentication servers + * fixed WPA/RSN IE verification in message 3 of 4-Way Handshake when + using drivers that take care of AP selection (e.g., when using + ap_scan=2) + * fixed reprocessing of pending request after ctrl_iface requests for + identity/password/otp + * fixed ctrl_iface requests for identity/password/otp in Phase 2 of + EAP-PEAP and EAP-TTLS + * all drivers using driver_wext: set interface up and select Managed + mode when starting wpa_supplicant; set interface down when exiting + * renamed driver_ipw2100.c to driver_ipw.c since it now supports both + ipw2100 and ipw2200; please note that this also changed the + configuration variable in .config to CONFIG_DRIVER_IPW + +2005-01-24 - v0.3.6 + * fixed a busy loop introduced in v0.3.5 for scan result processing + when no matching AP is found + +2005-01-23 - v0.3.5 + * added a workaround for an interoperability issue with a Cisco AP + when using WPA2-PSK + * fixed non-WPA IEEE 802.1X to use the same authentication timeout as + WPA with IEEE 802.1X (i.e., timeout 10 -> 70 sec to allow + retransmission of dropped frames) + * fixed issues with 64-bit CPUs and SHA1 cleanup in previous version + (e.g., segfault when processing EAPOL-Key frames) + * fixed EAP workaround and fast reauthentication configuration for + RSN pre-authentication; previously these were disabled and + pre-authentication would fail if the used authentication server + requires EAP workarounds + * added support for blacklisting APs that fail or timeout + authentication in ap_scan=1 mode so that all APs are tried in cases + where the ones with strongest signal level are failing authentication + * fixed CA certificate loading after a failed EAP-TLS/PEAP/TTLS + authentication attempt + * allow EAP-PEAP/TTLS fast reauthentication only if Phase 2 succeeded + in the previous authentication (previously, only Phase 1 success was + verified) + +2005-01-09 - v0.3.4 + * added preliminary support for IBSS (ad-hoc) mode configuration + (mode=1 in network block); this included a new key_mgmt mode + WPA-NONE, i.e., TKIP or CCMP with a fixed key (based on psk) and no + key management; see wpa_supplicant.conf for more details and an + example on how to configure this (note: this is currently implemented + only for driver_hostapd.c, but the changes should be trivial to add + in associate() handler for other drivers, too (assuming the driver + supports WPA-None) + * added preliminary port for native Windows (i.e., no cygwin) using + mingw + +2005-01-02 - v0.3.3 + * added optional support for GNU Readline and History Libraries for + wpa_cli (CONFIG_READLINE) + * cleaned up EAP state machine <-> method interface and number of + small problems with error case processing not terminating on + EAP-Failure but waiting for timeout + * added couple of workarounds for interoperability issues with a + Cisco AP when using WPA2 + * added support for EAP-FAST (draft-cam-winget-eap-fast-00.txt); + Note: This requires a patch for openssl to add support for TLS + extensions and number of workarounds for operations without + certificates. Proof of concept type of experimental patch is + included in openssl-tls-extensions.patch. + +2004-12-19 - v0.3.2 + * fixed private key loading for cases where passphrase is not set + * fixed Windows/cygwin L2 packet handler freeing; previous version + could cause a segfault when RSN pre-authentication was completed + * added support for PMKSA caching with drivers that generate RSN IEs + (e.g., NDIS); currently, this is only implemented in driver_ndis.c, + but similar code can be easily added to driver_ndiswrapper.c once + ndiswrapper gets full support for RSN PMKSA caching + * improved recovery from PMKID mismatches by requesting full EAP + authentication in case of failed PMKSA caching attempt + * driver_ndis: added support for NDIS NdisMIncidateStatus() events + (this requires that ndis_events is ran while wpa_supplicant is + running) + * driver_ndis: use ADD_WEP/REMOVE_WEP when configuring WEP keys + * added support for driver interfaces to replace the interface name + based on driver/OS specific mapping, e.g., in case of driver_ndis, + this allows the beginning of the adapter description to be used as + the interface name + * added support for CR+LF (Windows-style) line ends in configuration + file + * driver_ndis: enable radio before starting scanning, disable radio + when exiting + * modified association event handler to set portEnabled = FALSE before + clearing port Valid in order to reset EAP state machine and avoid + problems with new authentication getting ignored because of state + machines ending up in AUTHENTICATED/SUCCESS state based on old + information + * added support for driver events to add PMKID candidates in order to + allow drivers to give priority to most likely roaming candidates + * driver_hostap: moved PrivacyInvoked configuration to associate() + function so that this will not be set for plaintext connections + * added KEY_MGMT_802_1X_NO_WPA as a new key_mgmt type so that driver + interface can distinguish plaintext and IEEE 802.1X (no WPA) + authentication + * fixed static WEP key configuration to use broadcast/default type for + all keys (previously, the default TX key was configured as pairwise/ + unicast key) + * driver_ndis: added legacy WPA capability detection for non-WPA2 + drivers + * added support for setting static WEP keys for IEEE 802.1X without + dynamic WEP keying (eapol_flags=0) + +2004-12-12 - v0.3.1 + * added support for reading PKCS#12 (PFX) files (as a replacement for + PEM/DER) to get certificate and private key (CONFIG_PKCS12) + * fixed compilation with CONFIG_PCSC=y + * added new ap_scan mode, ap_scan=2, for drivers that take care of + association, but need to be configured with security policy and SSID, + e.g., ndiswrapper and NDIS driver; this mode should allow such + drivers to work with hidden SSIDs and optimized roaming; when + ap_scan=2 is used, only the first network block in the configuration + file is used and this configuration should have explicit security + policy (i.e., only one option in the lists) for key_mgmt, pairwise, + group, proto variables + * added experimental port of wpa_supplicant for Windows + - driver_ndis.c driver interface (NDIS OIDs) + - currently, this requires cygwin and WinPcap + - small utility, win_if_list, can be used to get interface name + * control interface can now be removed at build time; add + CONFIG_CTRL_IFACE=y to .config to maintain old functionality + * optional Xsupplicant interface can now be removed at build time; + (CONFIG_XSUPPLICANT_IFACE=y in .config to bring it back) + * added auth_alg to driver interface associate() parameters to make it + easier for drivers to configure authentication algorithm as part of + the association + +2004-12-05 - v0.3.0 (beginning of 0.3.x development releases) + * driver_broadcom: added new driver interface for Broadcom wl.o driver + (a generic driver for Broadcom IEEE 802.11a/g cards) + * wpa_cli: fixed parsing of -p <path> command line argument + * PEAPv1: fixed tunneled EAP-Success reply handling to reply with TLS + ACK, not tunneled EAP-Success (of which only the first byte was + actually send due to a bug in previous code); this seems to + interoperate with most RADIUS servers that implements PEAPv1 + * PEAPv1: added support for terminating PEAP authentication on tunneled + EAP-Success message; this can be configured by adding + peap_outer_success=0 on phase1 parameters in wpa_supplicant.conf + (some RADIUS servers require this whereas others require a tunneled + reply + * PEAPv1: changed phase1 option peaplabel to use default to 0, i.e., to + the old label for key derivation; previously, the default was 1, + but it looks like most existing PEAPv1 implementations use the old + label which is thus more suitable default option + * added support for EAP-PSK (draft-bersani-eap-psk-03.txt) + * fixed parsing of wep_tx_keyidx + * added support for configuring list of allowed Phase 2 EAP types + (for both EAP-PEAP and EAP-TTLS) instead of only one type + * added support for configuring IEEE 802.11 authentication algorithm + (auth_alg; mainly for using Shared Key authentication with static + WEP keys) + * added support for EAP-AKA (with UMTS SIM) + * fixed couple of errors in PCSC handling that could have caused + random-looking errors for EAP-SIM + * added support for EAP-SIM pseudonyms and fast re-authentication + * added support for EAP-TLS/PEAP/TTLS fast re-authentication (TLS + session resumption) + * added support for EAP-SIM with two challanges + (phase1="sim_min_num_chal=3" can be used to require three challenges) + * added support for configuring DH/DSA parameters for an ephemeral DH + key exchange (EAP-TLS/PEAP/TTLS) using new configuration parameters + dh_file and dh_file2 (phase 2); this adds support for using DSA keys + and optional DH key exchange to achieve forward secracy with RSA keys + * added support for matching subject of the authentication server + certificate with a substring when using EAP-TLS/PEAP/TTLS; new + configuration variables subject_match and subject_match2 + * changed SSID configuration in driver_wext.c (used by many driver + interfaces) to use ssid_len+1 as the length for SSID since some Linux + drivers expect this + * fixed couple of unaligned reads in scan result parsing to fix WPA + connection on some platforms (e.g., ARM) + * added driver interface for Intel ipw2100 driver + * added support for LEAP with WPA + * added support for larger scan results report (old limit was 4 kB of + data, i.e., about 35 or so APs) when using Linux wireless extensions + v17 or newer + * fixed a bug in PMKSA cache processing: skip sending of EAPOL-Start + only if there is a PMKSA cache entry for the current AP + * fixed error handling for case where reading of scan results fails: + must schedule a new scan or wpa_supplicant will remain waiting + forever + * changed debug output to remove shared password/key material by + default; all key information can be included with -K command line + argument to match the previous behavior + * added support for timestamping debug log messages (disabled by + default, can be enabled with -t command line argument) + * set pairwise/group cipher suite for non-WPA IEEE 802.1X to WEP-104 + if keys are not configured to be used; this fixes IEEE 802.1X mode + with drivers that use this information to configure whether Privacy + bit can be in Beacon frames (e.g., ndiswrapper) + * avoid clearing driver keys if no keys have been configured since last + key clear request; this seems to improve reliability of group key + handshake for ndiswrapper & NDIS driver which seems to be suffering + of some kind of timing issue when the keys are cleared again after + association + * changed driver interface API: + - WPA_SUPPLICANT_DRIVER_VERSION define can be used to determine which + version is being used (now, this is set to 2; previously, it was + not defined) + - pass pointer to private data structure to all calls + - the new API is not backwards compatible; all in-tree driver + interfaces has been converted to the new API + * added support for controlling multiple interfaces (radios) per + wpa_supplicant process; each interface needs to be listed on the + command line (-c, -i, -D arguments) with -N as a separator + (-cwpa1.conf -iwlan0 -Dhostap -N -cwpa2.conf -iath0 -Dmadwifi) + * added a workaround for EAP servers that incorrectly use same Id for + sequential EAP packets + * changed libpcap/libdnet configuration to use .config variable, + CONFIG_DNET_PCAP, instead of requiring Makefile modification + * improved downgrade attack detection in IE verification of msg 3/4: + verify both WPA and RSN IEs, if present, not only the selected one; + reject the AP if an RSN IE is found in msg 3/4, but not in Beacon or + Probe Response frame, and RSN is enabled in wpa_supplicant + configuration + * fixed WPA msg 3/4 processing to allow Key Data field contain other + IEs than just one WPA IE + * added support for FreeBSD and driver interface for the BSD net80211 + layer (CONFIG_DRIVER_BSD=y in .config); please note that some of the + required kernel mods have not yet been committed + * made EAP workarounds configurable; enabled by default, can be + disabled with network block option eap_workaround=0 + +2004-07-17 - v0.2.4 (beginning of 0.2.x stable releases) + * resolved couple of interoperability issues with EAP-PEAPv1 and + Phase 2 (inner EAP) fragment reassembly + * driver_madwifi: fixed WEP key configuration for IEEE 802.1X when the + AP is using non-zero key index for the unicast key and key index zero + for the broadcast key + * driver_hostap: fixed IEEE 802.1X WEP key updates and + re-authentication by allowing unencrypted EAPOL frames when not using + WPA + * added a new driver interface, 'wext', which uses only standard, + driver independent functionality in Linux wireless extensions; + currently, this can be used only for non-WPA IEEE 802.1X mode, but + eventually, this is to be extended to support full WPA/WPA2 once + Linux wireless extensions get support for this + * added support for mode in which the driver is responsible for AP + scanning and selection; this is disabled by default and can be + enabled with global ap_scan=0 variable in wpa_supplicant.conf; + this mode can be used, e.g., with generic 'wext' driver interface to + use wpa_supplicant as IEEE 802.1X Supplicant with any Linux driver + supporting wireless extensions. + * driver_madwifi: fixed WPA2 configuration and scan_ssid=1 (e.g., + operation with an AP that does not include SSID in the Beacon frames) + * added support for new EAP authentication methods: + EAP-TTLS/EAP-OTP, EAP-PEAPv0/OTP, EAP-PEAPv1/OTP, EAP-OTP + * added support for asking one-time-passwords from frontends (e.g., + wpa_cli); this 'otp' command works otherwise like 'password' command, + but the password is used only once and the frontend will be asked for + a new password whenever a request from authenticator requires a + password; this can be used with both EAP-OTP and EAP-GTC + * changed wpa_cli to automatically re-establish connection so that it + does not need to be re-started when wpa_supplicant is terminated and + started again + * improved user data (identity/password/otp) requests through + frontends: process pending EAPOL packets after getting new + information so that full authentication does not need to be + restarted; in addition, send pending requests again whenever a new + frontend is attached + * changed control frontends to use a new directory for socket files to + make it easier for wpa_cli to automatically select between interfaces + and to provide access control for the control interface; + wpa_supplicant.conf: ctrl_interface is now a path + (/var/run/wpa_supplicant is the recommended path) and + ctrl_interface_group can be used to select which group gets access to + the control interface; + wpa_cli: by default, try to connect to the first interface available + in /var/run/wpa_supplicant; this path can be overriden with -p option + and an interface can be selected with -i option (i.e., in most common + cases, wpa_cli does not need to get any arguments) + * added support for LEAP + * added driver interface for Linux ndiswrapper + * added priority option for network blocks in the configuration file; + this allows networks to be grouped based on priority (the scan + results are searched for matches with network blocks in this order) + +2004-06-20 - v0.2.3 + * sort scan results to improve AP selection + * fixed control interface socket removal for some error cases + * improved scan requesting and authentication timeout + * small improvements/bug fixes for EAP-MSCHAPv2, EAP-PEAP, and + TLS processing + * PEAP version can now be forced with phase1="peapver=<ver>" + (mostly for testing; by default, the highest version supported by + both the Supplicant and Authentication Server is selected + automatically) + * added support for madwifi driver (Atheros ar521x) + * added a workaround for cases where AP sets Install Tx/Rx bit for + WPA Group Key messages when pairwise keys are used (without this, + the Group Key would be used for Tx and the AP would drop frames + from the station) + * added GSM SIM/USIM interface for GSM authentication algorithm for + EAP-SIM; this requires pcsc-lite + * added support for ATMEL AT76C5XXx driver + * fixed IEEE 802.1X WEP key derivation in the case where Authenticator + does not include key data in the EAPOL-Key frame (i.e., part of + EAP keying material is used as data encryption key) + * added support for using plaintext and static WEP networks + (key_mgmt=NONE) + +2004-05-31 - v0.2.2 + * added support for new EAP authentication methods: + EAP-TTLS/EAP-MD5-Challenge + EAP-TTLS/EAP-GTC + EAP-TTLS/EAP-MSCHAPv2 + EAP-TTLS/EAP-TLS + EAP-TTLS/MSCHAPv2 + EAP-TTLS/MSCHAP + EAP-TTLS/PAP + EAP-TTLS/CHAP + EAP-PEAP/TLS + EAP-PEAP/GTC + EAP-PEAP/MD5-Challenge + EAP-GTC + EAP-SIM (not yet complete; needs GSM/SIM authentication interface) + * added support for anonymous identity (to be used when identity is + sent in plaintext; real identity will be used within TLS protected + tunnel (e.g., with EAP-TTLS) + * added event messages from wpa_supplicant to frontends, e.g., wpa_cli + * added support for requesting identity and password information using + control interface; in other words, the password for EAP-PEAP or + EAP-TTLS does not need to be included in the configuration file since + a frontand (e.g., wpa_cli) can ask it from the user + * improved RSN pre-authentication to use a candidate list and process + all candidates from each scan; not only one per scan + * fixed RSN IE and WPA IE capabilities field parsing + * ignore Tx bit in GTK IE when Pairwise keys are used + * avoid making new scan requests during IEEE 802.1X negotiation + * use openssl/libcrypto for MD5 and SHA-1 when compiling wpa_supplicant + with TLS support (this replaces the included implementation with + library code to save about 8 kB since the library code is needed + anyway for TLS) + * fixed WPA-PSK only mode when compiled without IEEE 802.1X support + (i.e., without CONFIG_IEEE8021X_EAPOL=y in .config) + +2004-05-06 - v0.2.1 + * added support for internal IEEE 802.1X (actually, IEEE 802.1aa/D6.1) + Supplicant + - EAPOL state machines for Supplicant [IEEE 802.1aa/D6.1] + - EAP peer state machine [draft-ietf-eap-statemachine-02.pdf] + - EAP-MD5 (cannot be used with WPA-RADIUS) + [draft-ietf-eap-rfc2284bis-09.txt] + - EAP-TLS [RFC 2716] + - EAP-MSCHAPv2 (currently used only with EAP-PEAP) + - EAP-PEAP/MSCHAPv2 [draft-josefsson-pppext-eap-tls-eap-07.txt] + [draft-kamath-pppext-eap-mschapv2-00.txt] + (PEAP version 0, 1, and parts of 2; only 0 and 1 are enabled by + default; tested with FreeRADIUS, Microsoft IAS, and Funk Odyssey) + - new configuration file options: eap, identity, password, ca_cert, + client_cert, privatekey, private_key_passwd + - Xsupplicant is not required anymore, but it can be used by + disabling the internal IEEE 802.1X Supplicant with -e command line + option + - this code is not included in the default build; Makefile need to + be edited for this (uncomment lines for selected functionality) + - EAP-TLS and EAP-PEAP require openssl libraries + * use module prefix in debug messages (WPA, EAP, EAP-TLS, ..) + * added support for non-WPA IEEE 802.1X mode with dynamic WEP keys + (i.e., complete IEEE 802.1X/EAP authentication and use IEEE 802.1X + EAPOL-Key frames instead of WPA key handshakes) + * added support for IEEE 802.11i/RSN (WPA2) + - improved PTK Key Handshake + - PMKSA caching, pre-authentication + * fixed wpa_supplicant to ignore possible extra data after WPA + EAPOL-Key packets (this fixes 'Invalid EAPOL-Key MIC when using + TPTK' error from message 3 of 4-Way Handshake in case the AP + includes extra data after the EAPOL-Key) + * added interface for external programs (frontends) to control + wpa_supplicant + - CLI example (wpa_cli) with interactive mode and command line + mode + - replaced SIGUSR1 status/statistics with the new control interface + * made some feature compile time configurable + - .config file for make + - driver interfaces (hostap, hermes, ..) + - EAPOL/EAP functions + +2004-02-15 - v0.2.0 + * Initial version of wpa_supplicant diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile new file mode 100644 index 000000000000..0a50ceef0b97 --- /dev/null +++ b/wpa_supplicant/Makefile @@ -0,0 +1,1246 @@ +ifndef CC +CC=gcc +endif + +ifndef CFLAGS +CFLAGS = -MMD -O2 -Wall -g +endif + +export LIBDIR ?= /usr/local/lib/ +export BINDIR ?= /usr/local/sbin/ + +CFLAGS += -I../src +CFLAGS += -I../src/crypto +CFLAGS += -I../src/utils +CFLAGS += -I../src/common +CFLAGS += -I../src/rsn_supp + +ALL=wpa_supplicant wpa_passphrase wpa_cli + +all: verify_config $(ALL) dynamic_eap_methods + +verify_config: + @if [ ! -r .config ]; then \ + echo 'Building wpa_supplicant 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 + +mkconfig: + @if [ -e .config ]; then \ + echo '.config exists - did not replace it'; \ + exit 1; \ + fi + echo CONFIG_DRIVER_HOSTAP=y >> .config + echo CONFIG_DRIVER_WEXT=y >> .config + echo CONFIG_WIRELESS_EXTENSION=y >> .config + +install: all + mkdir -p $(DESTDIR)$(BINDIR) + for i in $(ALL); do cp $$i $(DESTDIR)$(BINDIR)/$$i; done + $(MAKE) -C ../src install + +OBJS = config.o +OBJS += ../src/utils/common.o +OBJS += ../src/utils/wpa_debug.o +OBJS += ../src/utils/wpabuf.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_p = wpa_passphrase.o +OBJS_p += ../src/utils/common.o +OBJS_p += ../src/utils/wpa_debug.o +OBJS_p += ../src/crypto/md5.o +OBJS_p += ../src/crypto/md4.o +OBJS_p += ../src/crypto/sha1.o +OBJS_p += ../src/crypto/des.o +OBJS_c = wpa_cli.o ../src/common/wpa_ctrl.o + +-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 + +OBJS += ../src/utils/os_$(CONFIG_OS).o +OBJS_p += ../src/utils/os_$(CONFIG_OS).o +OBJS_c += ../src/utils/os_$(CONFIG_OS).o + +ifndef CONFIG_ELOOP +CONFIG_ELOOP=eloop +endif +OBJS += ../src/utils/$(CONFIG_ELOOP).o + + +ifdef CONFIG_EAPOL_TEST +CFLAGS += -Werror -DEAPOL_TEST +endif + +ifndef CONFIG_BACKEND +CONFIG_BACKEND=file +endif + +ifeq ($(CONFIG_BACKEND), file) +OBJS += config_file.o +ifndef CONFIG_NO_CONFIG_BLOBS +NEED_BASE64=y +endif +CFLAGS += -DCONFIG_BACKEND_FILE +endif + +ifeq ($(CONFIG_BACKEND), winreg) +OBJS += config_winreg.o +endif + +ifeq ($(CONFIG_BACKEND), none) +OBJS += config_none.o +endif + +ifdef CONFIG_NO_CONFIG_WRITE +CFLAGS += -DCONFIG_NO_CONFIG_WRITE +endif + +ifdef CONFIG_NO_CONFIG_BLOBS +CFLAGS += -DCONFIG_NO_CONFIG_BLOBS +endif + +ifdef CONFIG_NO_SCAN_PROCESSING +CFLAGS += -DCONFIG_NO_SCAN_PROCESSING +endif + +ifdef CONFIG_DRIVER_HOSTAP +CFLAGS += -DCONFIG_DRIVER_HOSTAP +OBJS_d += ../src/drivers/driver_hostap.o +CONFIG_WIRELESS_EXTENSION=y +endif + +ifdef CONFIG_DRIVER_WEXT +CFLAGS += -DCONFIG_DRIVER_WEXT +CONFIG_WIRELESS_EXTENSION=y +endif + +ifdef CONFIG_DRIVER_NL80211 +CFLAGS += -DCONFIG_DRIVER_NL80211 +OBJS_d += ../src/drivers/driver_nl80211.o +LIBS += -lnl +ifdef CONFIG_CLIENT_MLME +OBJS_d += ../src/drivers/radiotap.o +endif +endif + +ifdef CONFIG_DRIVER_PRISM54 +CFLAGS += -DCONFIG_DRIVER_PRISM54 +OBJS_d += ../src/drivers/driver_prism54.o +CONFIG_WIRELESS_EXTENSION=y +endif + +ifdef CONFIG_DRIVER_HERMES +CFLAGS += -DCONFIG_DRIVER_HERMES +OBJS_d += ../src/drivers/driver_hermes.o +CONFIG_WIRELESS_EXTENSION=y +endif + +ifdef CONFIG_DRIVER_MADWIFI +CFLAGS += -DCONFIG_DRIVER_MADWIFI +OBJS_d += ../src/drivers/driver_madwifi.o +CONFIG_WIRELESS_EXTENSION=y +endif + +ifdef CONFIG_DRIVER_ATMEL +CFLAGS += -DCONFIG_DRIVER_ATMEL +OBJS_d += ../src/drivers/driver_atmel.o +CONFIG_WIRELESS_EXTENSION=y +endif + +ifdef CONFIG_DRIVER_NDISWRAPPER +CFLAGS += -DCONFIG_DRIVER_NDISWRAPPER +OBJS_d += ../src/drivers/driver_ndiswrapper.o +CONFIG_WIRELESS_EXTENSION=y +endif + +ifdef CONFIG_DRIVER_RALINK +CFLAGS += -DCONFIG_DRIVER_RALINK +OBJS_d += ../src/drivers/driver_ralink.o +endif + +ifdef CONFIG_DRIVER_BROADCOM +CFLAGS += -DCONFIG_DRIVER_BROADCOM +OBJS_d += ../src/drivers/driver_broadcom.o +endif + +ifdef CONFIG_DRIVER_IPW +CFLAGS += -DCONFIG_DRIVER_IPW +OBJS_d += ../src/drivers/driver_ipw.o +CONFIG_WIRELESS_EXTENSION=y +endif + +ifdef CONFIG_DRIVER_BSD +CFLAGS += -DCONFIG_DRIVER_BSD +OBJS_d += ../src/drivers/driver_bsd.o +ifndef CONFIG_L2_PACKET +CONFIG_L2_PACKET=freebsd +endif +endif + +ifdef CONFIG_DRIVER_NDIS +CFLAGS += -DCONFIG_DRIVER_NDIS +OBJS_d += ../src/drivers/driver_ndis.o +ifdef CONFIG_NDIS_EVENTS_INTEGRATED +OBJS_d += ../src/drivers/driver_ndis_.o +endif +ifndef CONFIG_L2_PACKET +CONFIG_L2_PACKET=pcap +endif +CONFIG_WINPCAP=y +ifdef CONFIG_USE_NDISUIO +CFLAGS += -DCONFIG_USE_NDISUIO +endif +endif + +ifdef CONFIG_DRIVER_WIRED +CFLAGS += -DCONFIG_DRIVER_WIRED +OBJS_d += ../src/drivers/driver_wired.o +endif + +ifdef CONFIG_DRIVER_TEST +CFLAGS += -DCONFIG_DRIVER_TEST +OBJS_d += ../src/drivers/driver_test.o +endif + +ifdef CONFIG_DRIVER_OSX +CFLAGS += -DCONFIG_DRIVER_OSX +OBJS_d += ../src/drivers/driver_osx.o +LDFLAGS += -framework CoreFoundation +LDFLAGS += -F/System/Library/PrivateFrameworks -framework Apple80211 +endif + +ifdef CONFIG_DRIVER_PS3 +CFLAGS += -DCONFIG_DRIVER_PS3 -m64 +OBJS_d += ../src/drivers/driver_ps3.o +LDFLAGS += -m64 +endif + +ifdef CONFIG_DRIVER_IPHONE +CFLAGS += -DCONFIG_DRIVER_IPHONE +OBJS_d += ../src/drivers/driver_iphone.o +OBJS_d += ../src/drivers/MobileApple80211.o +LIBS += -framework CoreFoundation +endif + +ifdef CONFIG_DRIVER_ROBOSWITCH +CFLAGS += -DCONFIG_DRIVER_ROBOSWITCH +OBJS_d += ../src/drivers/driver_roboswitch.o +endif + +ifndef CONFIG_L2_PACKET +CONFIG_L2_PACKET=linux +endif + +OBJS_l2 += ../src/l2_packet/l2_packet_$(CONFIG_L2_PACKET).o + +ifeq ($(CONFIG_L2_PACKET), pcap) +ifdef CONFIG_WINPCAP +CFLAGS += -DCONFIG_WINPCAP +LIBS += -lwpcap -lpacket +LIBS_w += -lwpcap +else +LIBS += -ldnet -lpcap +endif +endif + +ifeq ($(CONFIG_L2_PACKET), winpcap) +LIBS += -lwpcap -lpacket +LIBS_w += -lwpcap +endif + +ifeq ($(CONFIG_L2_PACKET), freebsd) +LIBS += -lpcap +endif + +ifdef CONFIG_EAP_TLS +# EAP-TLS +ifeq ($(CONFIG_EAP_TLS), dyn) +CFLAGS += -DEAP_TLS_DYNAMIC +EAPDYN += ../src/eap_peer/eap_tls.so +else +CFLAGS += -DEAP_TLS +OBJS += ../src/eap_peer/eap_tls.o +OBJS_h += ../src/eap_server/eap_tls.o +endif +TLS_FUNCS=y +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_PEAP +# EAP-PEAP +ifeq ($(CONFIG_EAP_PEAP), dyn) +CFLAGS += -DEAP_PEAP_DYNAMIC +EAPDYN += ../src/eap_peer/eap_peap.so +else +CFLAGS += -DEAP_PEAP +OBJS += ../src/eap_peer/eap_peap.o +OBJS += ../src/eap_common/eap_peap_common.o +OBJS_h += ../src/eap_server/eap_peap.o +endif +TLS_FUNCS=y +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_TTLS +# EAP-TTLS +ifeq ($(CONFIG_EAP_TTLS), dyn) +CFLAGS += -DEAP_TTLS_DYNAMIC +EAPDYN += ../src/eap_peer/eap_ttls.so +else +CFLAGS += -DEAP_TTLS +OBJS += ../src/eap_peer/eap_ttls.o +OBJS_h += ../src/eap_server/eap_ttls.o +endif +MS_FUNCS=y +TLS_FUNCS=y +CHAP=y +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_MD5 +# EAP-MD5 +ifeq ($(CONFIG_EAP_MD5), dyn) +CFLAGS += -DEAP_MD5_DYNAMIC +EAPDYN += ../src/eap_peer/eap_md5.so +else +CFLAGS += -DEAP_MD5 +OBJS += ../src/eap_peer/eap_md5.o +OBJS_h += ../src/eap_server/eap_md5.o +endif +CHAP=y +CONFIG_IEEE8021X_EAPOL=y +endif + +# backwards compatibility for old spelling +ifdef CONFIG_MSCHAPV2 +ifndef CONFIG_EAP_MSCHAPV2 +CONFIG_EAP_MSCHAPV2=y +endif +endif + +ifdef CONFIG_EAP_MSCHAPV2 +# EAP-MSCHAPv2 +ifeq ($(CONFIG_EAP_MSCHAPV2), dyn) +CFLAGS += -DEAP_MSCHAPv2_DYNAMIC +EAPDYN += ../src/eap_peer/eap_mschapv2.so +EAPDYN += ../src/eap_peer/mschapv2.so +else +CFLAGS += -DEAP_MSCHAPv2 +OBJS += ../src/eap_peer/eap_mschapv2.o +OBJS += ../src/eap_peer/mschapv2.o +OBJS_h += ../src/eap_server/eap_mschapv2.o +endif +MS_FUNCS=y +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_GTC +# EAP-GTC +ifeq ($(CONFIG_EAP_GTC), dyn) +CFLAGS += -DEAP_GTC_DYNAMIC +EAPDYN += ../src/eap_peer/eap_gtc.so +else +CFLAGS += -DEAP_GTC +OBJS += ../src/eap_peer/eap_gtc.o +OBJS_h += ../src/eap_server/eap_gtc.o +endif +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_OTP +# EAP-OTP +ifeq ($(CONFIG_EAP_OTP), dyn) +CFLAGS += -DEAP_OTP_DYNAMIC +EAPDYN += ../src/eap_peer/eap_otp.so +else +CFLAGS += -DEAP_OTP +OBJS += ../src/eap_peer/eap_otp.o +endif +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_SIM +# EAP-SIM +ifeq ($(CONFIG_EAP_SIM), dyn) +CFLAGS += -DEAP_SIM_DYNAMIC +EAPDYN += ../src/eap_peer/eap_sim.so +else +CFLAGS += -DEAP_SIM +OBJS += ../src/eap_peer/eap_sim.o +OBJS_h += ../src/eap_server/eap_sim.o +endif +CONFIG_IEEE8021X_EAPOL=y +CONFIG_EAP_SIM_COMMON=y +endif + +ifdef CONFIG_EAP_LEAP +# EAP-LEAP +ifeq ($(CONFIG_EAP_LEAP), dyn) +CFLAGS += -DEAP_LEAP_DYNAMIC +EAPDYN += ../src/eap_peer/eap_leap.so +else +CFLAGS += -DEAP_LEAP +OBJS += ../src/eap_peer/eap_leap.o +endif +MS_FUNCS=y +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_PSK +# EAP-PSK +ifeq ($(CONFIG_EAP_PSK), dyn) +CFLAGS += -DEAP_PSK_DYNAMIC +EAPDYN += ../src/eap_peer/eap_psk.so +else +CFLAGS += -DEAP_PSK +OBJS += ../src/eap_peer/eap_psk.o ../src/eap_common/eap_psk_common.o +OBJS_h += ../src/eap_server/eap_psk.o +endif +CONFIG_IEEE8021X_EAPOL=y +NEED_AES=y +endif + +ifdef CONFIG_EAP_AKA +# EAP-AKA +ifeq ($(CONFIG_EAP_AKA), dyn) +CFLAGS += -DEAP_AKA_DYNAMIC +EAPDYN += ../src/eap_peer/eap_aka.so +else +CFLAGS += -DEAP_AKA +OBJS += ../src/eap_peer/eap_aka.o +OBJS_h += ../src/eap_server/eap_aka.o +endif +CONFIG_IEEE8021X_EAPOL=y +CONFIG_EAP_SIM_COMMON=y +endif + +ifdef CONFIG_EAP_AKA_PRIME +# EAP-AKA' +ifeq ($(CONFIG_EAP_AKA_PRIME), dyn) +CFLAGS += -DEAP_AKA_PRIME_DYNAMIC +else +CFLAGS += -DEAP_AKA_PRIME +endif +NEED_SHA256=y +endif + +ifdef CONFIG_EAP_SIM_COMMON +OBJS += ../src/eap_common/eap_sim_common.o +OBJS_h += ../src/eap_server/eap_sim_db.o +NEED_AES=y +NEED_FIPS186_2_PRF=y +endif + +ifdef CONFIG_EAP_FAST +# EAP-FAST +ifeq ($(CONFIG_EAP_FAST), dyn) +CFLAGS += -DEAP_FAST_DYNAMIC +EAPDYN += ../src/eap_peer/eap_fast.so +EAPDYN += ../src/eap_common/eap_fast_common.o +else +CFLAGS += -DEAP_FAST +OBJS += ../src/eap_peer/eap_fast.o ../src/eap_peer/eap_fast_pac.o +OBJS += ../src/eap_common/eap_fast_common.o +OBJS_h += ../src/eap_server/eap_fast.o +endif +TLS_FUNCS=y +NEED_T_PRF=y +endif + +ifdef CONFIG_EAP_PAX +# EAP-PAX +ifeq ($(CONFIG_EAP_PAX), dyn) +CFLAGS += -DEAP_PAX_DYNAMIC +EAPDYN += ../src/eap_peer/eap_pax.so +else +CFLAGS += -DEAP_PAX +OBJS += ../src/eap_peer/eap_pax.o ../src/eap_common/eap_pax_common.o +OBJS_h += ../src/eap_server/eap_pax.o +endif +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_SAKE +# EAP-SAKE +ifeq ($(CONFIG_EAP_SAKE), dyn) +CFLAGS += -DEAP_SAKE_DYNAMIC +EAPDYN += ../src/eap_peer/eap_sake.so +else +CFLAGS += -DEAP_SAKE +OBJS += ../src/eap_peer/eap_sake.o ../src/eap_common/eap_sake_common.o +OBJS_h += ../src/eap_server/eap_sake.o +endif +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_GPSK +# EAP-GPSK +ifeq ($(CONFIG_EAP_GPSK), dyn) +CFLAGS += -DEAP_GPSK_DYNAMIC +EAPDYN += ../src/eap_peer/eap_gpsk.so +else +CFLAGS += -DEAP_GPSK +OBJS += ../src/eap_peer/eap_gpsk.o ../src/eap_common/eap_gpsk_common.o +OBJS_h += ../src/eap_server/eap_gpsk.o +endif +CONFIG_IEEE8021X_EAPOL=y +ifdef CONFIG_EAP_GPSK_SHA256 +CFLAGS += -DEAP_GPSK_SHA256 +endif +NEED_SHA256=y +endif + +ifdef CONFIG_WPS +# EAP-WSC +CFLAGS += -DCONFIG_WPS -DEAP_WSC +OBJS += wps_supplicant.o +OBJS += ../src/utils/uuid.o +OBJS += ../src/eap_peer/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 +OBJS_h += ../src/eap_server/eap_wsc.o +CONFIG_IEEE8021X_EAPOL=y +NEED_DH_GROUPS=y +NEED_SHA256=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 +# EAP-IKEv2 +ifeq ($(CONFIG_EAP_IKEV2), dyn) +CFLAGS += -DEAP_IKEV2_DYNAMIC +EAPDYN += ../src/eap_peer/eap_ikev2.so ../src/eap_peer/ikev2.o +EAPDYN += ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.o +else +CFLAGS += -DEAP_IKEV2 +OBJS += ../src/eap_peer/eap_ikev2.o ../src/eap_peer/ikev2.o +OBJS += ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.o +OBJS_h += ../src/eap_server/eap_ikev2.o +OBJS_h += ../src/eap_server/ikev2.o +endif +CONFIG_IEEE8021X_EAPOL=y +NEED_DH_GROUPS=y +endif + +ifdef CONFIG_EAP_VENDOR_TEST +ifeq ($(CONFIG_EAP_VENDOR_TEST), dyn) +CFLAGS += -DEAP_VENDOR_TEST_DYNAMIC +EAPDYN += ../src/eap_peer/eap_vendor_test.so +else +CFLAGS += -DEAP_VENDOR_TEST +OBJS += ../src/eap_peer/eap_vendor_test.o +OBJS_h += ../src/eap_server/eap_vendor_test.o +endif +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_TNC +# EAP-TNC +CFLAGS += -DEAP_TNC +OBJS += ../src/eap_peer/eap_tnc.o +OBJS += ../src/eap_peer/tncc.o +NEED_BASE64=y +ifndef CONFIG_NATIVE_WINDOWS +LIBS += -ldl +endif +endif + +ifdef CONFIG_IEEE8021X_EAPOL +# IEEE 802.1X/EAPOL state machines (e.g., for RADIUS authentication) +CFLAGS += -DIEEE8021X_EAPOL +OBJS += ../src/eapol_supp/eapol_supp_sm.o ../src/eap_peer/eap.o ../src/eap_common/eap_common.o ../src/eap_peer/eap_methods.o +ifdef CONFIG_DYNAMIC_EAP_METHODS +CFLAGS += -DCONFIG_DYNAMIC_EAP_METHODS +LIBS += -ldl -rdynamic +endif +endif + +ifdef CONFIG_EAP_SERVER +CFLAGS += -DEAP_SERVER +OBJS_h += ../src/eap_server/eap.o +OBJS_h += ../src/eap_server/eap_identity.o +OBJS_h += ../src/eap_server/eap_methods.o +endif + +ifdef CONFIG_RADIUS_CLIENT +OBJS_h += ../src/utils/ip_addr.o +OBJS_h += ../src/radius/radius.o +OBJS_h += ../src/radius/radius_client.o +endif + +ifdef CONFIG_AUTHENTICATOR +OBJS_h += ../hostapd/eapol_sm.o +OBJS_h += ../hostapd/ieee802_1x.o +endif + +ifdef CONFIG_WPA_AUTHENTICATOR +OBJS_h += ../hostapd/wpa.o +OBJS_h += ../hostapd/wpa_auth_ie.o +ifdef CONFIG_IEEE80211R +OBJS_h += ../hostapd/wpa_ft.o +endif +ifdef CONFIG_PEERKEY +OBJS_h += ../hostapd/peerkey.o +endif +endif + +ifdef CONFIG_PCSC +# PC/SC interface for smartcards (USIM, GSM SIM) +CFLAGS += -DPCSC_FUNCS -I/usr/include/PCSC +OBJS += ../src/utils/pcsc_funcs.o +# -lpthread may not be needed depending on how pcsc-lite was configured +ifdef CONFIG_NATIVE_WINDOWS +#Once MinGW gets support for WinScard, -lwinscard could be used instead of the +#dynamic symbol loading that is now used in pcsc_funcs.c +#LIBS += -lwinscard +else +LIBS += -lpcsclite -lpthread +endif +endif + +ifdef CONFIG_SIM_SIMULATOR +CFLAGS += -DCONFIG_SIM_SIMULATOR +NEED_MILENAGE=y +endif + +ifdef CONFIG_USIM_SIMULATOR +CFLAGS += -DCONFIG_USIM_SIMULATOR +NEED_MILENAGE=y +endif + +ifdef NEED_MILENAGE +OBJS += ../src/hlr_auc_gw/milenage.o +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, EAP_TTLS, and EAP_FAST) +CFLAGS += -DEAP_TLS_FUNCS +OBJS += ../src/eap_peer/eap_tls_common.o +OBJS_h += ../src/eap_server/eap_tls_common.o +NEED_TLS_PRF=y +ifeq ($(CONFIG_TLS), openssl) +CFLAGS += -DEAP_TLS_OPENSSL +OBJS += ../src/crypto/tls_openssl.o +LIBS += -lssl -lcrypto +LIBS_p += -lcrypto +endif +ifeq ($(CONFIG_TLS), gnutls) +OBJS += ../src/crypto/tls_gnutls.o +LIBS += -lgnutls -lgcrypt -lgpg-error +LIBS_p += -lgcrypt +ifdef CONFIG_GNUTLS_EXTRA +CFLAGS += -DCONFIG_GNUTLS_EXTRA +LIBS += -lgnutls-extra +endif +endif +ifeq ($(CONFIG_TLS), schannel) +OBJS += ../src/crypto/tls_schannel.o +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_client.o +OBJS += ../src/tls/tlsv1_client_write.o ../src/tls/tlsv1_client_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 +NEED_TLS_PRF=y +CFLAGS += -DCONFIG_TLS_INTERNAL +CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT +ifeq ($(CONFIG_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 +endif +ifeq ($(CONFIG_CRYPTO), libtomcrypt) +LIBS += -ltomcrypt -ltfm +LIBS_p += -ltomcrypt -ltfm +endif +endif +ifeq ($(CONFIG_TLS), none) +OBJS += ../src/crypto/tls_none.o +CFLAGS += -DEAP_TLS_NONE +CONFIG_INTERNAL_AES=y +CONFIG_INTERNAL_SHA1=y +CONFIG_INTERNAL_MD5=y +CONFIG_INTERNAL_SHA256=y +endif +ifdef CONFIG_SMARTCARD +ifndef CONFIG_NATIVE_WINDOWS +ifneq ($(CONFIG_L2_PACKET), freebsd) +LIBS += -ldl +endif +endif +endif +NEED_CRYPTO=y +else +OBJS += ../src/crypto/tls_none.o +endif + +ifdef CONFIG_PKCS12 +CFLAGS += -DPKCS12_FUNCS +endif + +ifdef CONFIG_SMARTCARD +CFLAGS += -DCONFIG_SMARTCARD +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 +endif +ifeq ($(CONFIG_TLS), gnutls) +LIBS += -lgcrypt +LIBS_p += -lgcrypt +endif +ifeq ($(CONFIG_TLS), schannel) +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 +CONFIG_INTERNAL_SHA256=y +endif +ifeq ($(CONFIG_TLS), gnutls) +OBJS += ../src/crypto/crypto_gnutls.o +OBJS_p += ../src/crypto/crypto_gnutls.o +CONFIG_INTERNAL_SHA256=y +endif +ifeq ($(CONFIG_TLS), schannel) +OBJS += ../src/crypto/crypto_cryptoapi.o +OBJS_p += ../src/crypto/crypto_cryptoapi.o +CONFIG_INTERNAL_SHA256=y +endif +ifeq ($(CONFIG_TLS), internal) +ifeq ($(CONFIG_CRYPTO), libtomcrypt) +OBJS += ../src/crypto/crypto_libtomcrypt.o +OBJS_p += ../src/crypto/crypto_libtomcrypt.o +CONFIG_INTERNAL_SHA256=y +endif +ifeq ($(CONFIG_CRYPTO), internal) +OBJS += ../src/crypto/crypto_internal.o ../src/tls/rsa.o ../src/tls/bignum.o +OBJS_p += ../src/crypto/crypto_internal.o ../src/tls/rsa.o ../src/tls/bignum.o +CFLAGS += -DCONFIG_CRYPTO_INTERNAL +CONFIG_INTERNAL_AES=y +CONFIG_INTERNAL_DES=y +CONFIG_INTERNAL_SHA1=y +CONFIG_INTERNAL_MD4=y +CONFIG_INTERNAL_MD5=y +CONFIG_INTERNAL_SHA256=y +endif +ifeq ($(CONFIG_CRYPTO), cryptoapi) +OBJS += ../src/crypto/crypto_cryptoapi.o +OBJS_p += ../src/crypto/crypto_cryptoapi.o +CFLAGS += -DCONFIG_CRYPTO_CRYPTOAPI +CONFIG_INTERNAL_SHA256=y +endif +endif +ifeq ($(CONFIG_TLS), none) +OBJS += ../src/crypto/crypto_none.o +OBJS_p += ../src/crypto/crypto_none.o +CONFIG_INTERNAL_SHA256=y +endif +else +CONFIG_INTERNAL_AES=y +CONFIG_INTERNAL_SHA1=y +CONFIG_INTERNAL_MD5=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 CONFIG_IEEE80211R +NEED_SHA256=y +endif + +ifdef CONFIG_IEEE80211W +CFLAGS += -DCONFIG_IEEE80211W +NEED_SHA256=y +endif + +ifdef NEED_SHA256 +OBJS += ../src/crypto/sha256.o +CFLAGS += -DNEED_SHA256 +endif + +ifdef CONFIG_WIRELESS_EXTENSION +CFLAGS += -DCONFIG_WIRELESS_EXTENSION +OBJS_d += ../src/drivers/driver_wext.o +endif + +ifdef CONFIG_CTRL_IFACE +ifeq ($(CONFIG_CTRL_IFACE), y) +ifdef CONFIG_NATIVE_WINDOWS +CONFIG_CTRL_IFACE=named_pipe +else +CONFIG_CTRL_IFACE=unix +endif +endif +CFLAGS += -DCONFIG_CTRL_IFACE +ifeq ($(CONFIG_CTRL_IFACE), unix) +CFLAGS += -DCONFIG_CTRL_IFACE_UNIX +endif +ifeq ($(CONFIG_CTRL_IFACE), udp) +CFLAGS += -DCONFIG_CTRL_IFACE_UDP +endif +ifeq ($(CONFIG_CTRL_IFACE), named_pipe) +CFLAGS += -DCONFIG_CTRL_IFACE_NAMED_PIPE +endif +OBJS += ctrl_iface.o ctrl_iface_$(CONFIG_CTRL_IFACE).o +endif + +ifdef CONFIG_CTRL_IFACE_DBUS +CFLAGS += -DCONFIG_CTRL_IFACE_DBUS -DDBUS_API_SUBJECT_TO_CHANGE +OBJS += ctrl_iface_dbus.o ctrl_iface_dbus_handlers.o dbus_dict_helpers.o +ifndef DBUS_LIBS +DBUS_LIBS := $(shell pkg-config --libs dbus-1) +endif +LIBS += $(DBUS_LIBS) +ifndef DBUS_INCLUDE +DBUS_INCLUDE := $(shell pkg-config --cflags dbus-1) +endif +dbus_version=$(subst ., ,$(shell pkg-config --modversion dbus-1)) +DBUS_VERSION_MAJOR=$(word 1,$(dbus_version)) +DBUS_VERSION_MINOR=$(word 2,$(dbus_version)) +ifeq ($(DBUS_VERSION_MAJOR),) +DBUS_VERSION_MAJOR=0 +endif +ifeq ($(DBUS_VERSION_MINOR),) +DBUS_VERSION_MINOR=0 +endif +DBUS_INCLUDE += -DDBUS_VERSION_MAJOR=$(DBUS_VERSION_MAJOR) +DBUS_INCLUDE += -DDBUS_VERSION_MINOR=$(DBUS_VERSION_MINOR) +CFLAGS += $(DBUS_INCLUDE) +endif + +ifdef CONFIG_READLINE +CFLAGS += -DCONFIG_READLINE +LIBS_c += -lncurses -lreadline +endif + +ifdef CONFIG_NATIVE_WINDOWS +CFLAGS += -DCONFIG_NATIVE_WINDOWS +LIBS += -lws2_32 -lgdi32 -lcrypt32 +LIBS_c += -lws2_32 +LIBS_p += -lws2_32 -lgdi32 +ifeq ($(CONFIG_CRYPTO), cryptoapi) +LIBS_p += -lcrypt32 +endif +endif + +ifdef CONFIG_NO_STDOUT_DEBUG +CFLAGS += -DCONFIG_NO_STDOUT_DEBUG +ifndef CONFIG_CTRL_IFACE +CFLAGS += -DCONFIG_NO_WPA_MSG +endif +endif + +ifdef CONFIG_IPV6 +# for eapol_test only +CFLAGS += -DCONFIG_IPV6 +endif + +ifdef CONFIG_PEERKEY +CFLAGS += -DCONFIG_PEERKEY +endif + +ifdef CONFIG_IEEE80211R +CFLAGS += -DCONFIG_IEEE80211R +OBJS += ../src/rsn_supp/wpa_ft.o +endif + +ifndef CONFIG_NO_WPA +OBJS += ../src/rsn_supp/wpa.o +OBJS += ../src/rsn_supp/preauth.o +OBJS += ../src/rsn_supp/pmksa_cache.o +OBJS += ../src/rsn_supp/peerkey.o +OBJS += ../src/rsn_supp/wpa_ie.o +OBJS += ../src/common/wpa_common.o +NEED_AES=y +else +CFLAGS += -DCONFIG_NO_WPA -DCONFIG_NO_WPA2 +endif + +ifdef CONFIG_NO_WPA2 +CFLAGS += -DCONFIG_NO_WPA2 +endif + +ifdef CONFIG_NO_WPA_PASSPHRASE +CFLAGS += -DCONFIG_NO_PBKDF2 +endif + +ifdef CONFIG_NO_AES_EXTRAS +CFLAGS += -DCONFIG_NO_AES_WRAP +CFLAGS += -DCONFIG_NO_AES_CTR -DCONFIG_NO_AES_OMAC1 +CFLAGS += -DCONFIG_NO_AES_EAX -DCONFIG_NO_AES_CBC +CFLAGS += -DCONFIG_NO_AES_ENCRYPT +CFLAGS += -DCONFIG_NO_AES_ENCRYPT_BLOCK +endif + +ifdef NEED_AES +OBJS += ../src/crypto/aes_wrap.o ../src/crypto/aes.o +endif + +ifdef NEED_DH_GROUPS +OBJS += ../src/crypto/dh_groups.o +endif + +ifndef NEED_FIPS186_2_PRF +CFLAGS += -DCONFIG_NO_FIPS186_2_PRF +endif + +ifndef NEED_T_PRF +CFLAGS += -DCONFIG_NO_T_PRF +endif + +ifndef NEED_TLS_PRF +CFLAGS += -DCONFIG_NO_TLS_PRF +endif + +ifdef NEED_BASE64 +OBJS += ../src/utils/base64.o +endif + +ifdef CONFIG_CLIENT_MLME +OBJS += mlme.o ../src/common/ieee802_11_common.o +CFLAGS += -DCONFIG_CLIENT_MLME +endif + +ifndef CONFIG_MAIN +CONFIG_MAIN=main +endif + +ifdef CONFIG_DEBUG_FILE +CFLAGS += -DCONFIG_DEBUG_FILE +endif + +ifdef CONFIG_DELAYED_MIC_ERROR_REPORT +CFLAGS += -DCONFIG_DELAYED_MIC_ERROR_REPORT +endif + +OBJS += ../src/drivers/scan_helpers.o + +OBJS_wpa_rm := ctrl_iface.o mlme.o ctrl_iface_unix.o +OBJS_wpa := $(filter-out $(OBJS_wpa_rm),$(OBJS)) $(OBJS_h) tests/test_wpa.o +ifdef CONFIG_AUTHENTICATOR +OBJS_wpa += tests/link_test.o +endif +OBJS_wpa += $(OBJS_l2) +OBJS += wpa_supplicant.o events.o blacklist.o wpas_glue.o scan.o +OBJS_t := $(OBJS) $(OBJS_l2) eapol_test.o ../src/radius/radius.o ../src/radius/radius_client.o +OBJS_t += ../src/utils/ip_addr.o +OBJS_t2 := $(OBJS) $(OBJS_l2) preauth_test.o +OBJS += $(CONFIG_MAIN).o + +ifdef CONFIG_PRIVSEP +OBJS_priv += $(OBJS_d) ../src/drivers/drivers.o ../src/drivers/scan_helpers.o +OBJS_priv += $(OBJS_l2) +OBJS_priv += ../src/utils/os_$(CONFIG_OS).o +OBJS_priv += ../src/utils/$(CONFIG_ELOOP).o +OBJS_priv += ../src/utils/common.o +OBJS_priv += ../src/utils/wpa_debug.o +OBJS_priv += ../src/utils/wpabuf.o +OBJS_priv += wpa_priv.o +ifdef CONFIG_DRIVER_TEST +OBJS_priv += ../src/crypto/sha1.o +OBJS_priv += ../src/crypto/md5.o +ifeq ($(CONFIG_TLS), openssl) +OBJS_priv += ../src/crypto/crypto_openssl.o +endif +ifeq ($(CONFIG_TLS), gnutls) +OBJS_priv += ../src/crypto/crypto_gnutls.o +endif +ifeq ($(CONFIG_TLS), internal) +ifeq ($(CONFIG_CRYPTO), libtomcrypt) +OBJS_priv += ../src/crypto/crypto_libtomcrypt.o +else +OBJS_priv += ../src/crypto/crypto_internal.o +endif +endif +endif # CONFIG_DRIVER_TEST +OBJS += ../src/l2_packet/l2_packet_privsep.o +OBJS += ../src/drivers/driver_privsep.o +EXTRA_progs += wpa_priv +else +OBJS += $(OBJS_d) ../src/drivers/drivers.o +OBJS += $(OBJS_l2) +endif + +ifdef CONFIG_NDIS_EVENTS_INTEGRATED +CFLAGS += -DCONFIG_NDIS_EVENTS_INTEGRATED +OBJS += ../src/drivers/ndis_events.o +EXTRALIBS += -loleaut32 -lole32 -luuid +ifdef PLATFORMSDKLIB +EXTRALIBS += $(PLATFORMSDKLIB)/WbemUuid.Lib +else +EXTRALIBS += WbemUuid.Lib +endif +endif + +ifndef LDO +LDO=$(CC) +endif + +dynamic_eap_methods: $(EAPDYN) + +wpa_priv: $(OBJS_priv) + $(LDO) $(LDFLAGS) -o wpa_priv $(OBJS_priv) $(LIBS) + +wpa_supplicant: .config $(OBJS) $(EXTRA_progs) + $(LDO) $(LDFLAGS) -o wpa_supplicant $(OBJS) $(LIBS) $(EXTRALIBS) + +eapol_test: .config $(OBJS_t) + $(LDO) $(LDFLAGS) -o eapol_test $(OBJS_t) $(LIBS) + +preauth_test: .config $(OBJS_t2) + $(LDO) $(LDFLAGS) -o preauth_test $(OBJS_t2) $(LIBS) + +wpa_passphrase: $(OBJS_p) + $(LDO) $(LDFLAGS) -o wpa_passphrase $(OBJS_p) $(LIBS_p) + +wpa_cli: $(OBJS_c) + $(LDO) $(LDFLAGS) -o wpa_cli $(OBJS_c) $(LIBS_c) + +link_test: $(OBJS) $(OBJS_h) tests/link_test.o + $(LDO) $(LDFLAGS) -o link_test $(OBJS) $(OBJS_h) tests/link_test.o $(LIBS) + +test_wpa: $(OBJS_wpa) $(OBJS_h) + $(LDO) $(LDFLAGS) -o test_wpa $(OBJS_wpa) $(LIBS) + +OBJSa=../src/tls/asn1_test.o ../src/tls/asn1.o ../src/tls/x509v3.o ../src/utils/common.o ../src/utils/wpa_debug.o ../src/utils/os_unix.o \ + ../src/crypto/crypto_$(CONFIG_CRYPTO).o ../src/crypto/md5.o ../src/crypto/sha1.o \ + ../src/crypto/rc4.o ../src/crypto/des.o ../src/crypto/aes_wrap.o \ + ../src/crypto/aes.o ../src/tls/bignum.o ../src/tls/rsa.o +asn1_test: $(OBJSa) + $(LDO) $(LDFLAGS) -o asn1_test $(OBJSa) + +OBJSx=tests/test_x509v3.o ../src/tls/asn1.o ../src/tls/x509v3.o \ + ../src/utils/common.o ../src/utils/wpa_debug.o ../src/utils/os_unix.o \ + ../src/crypto/crypto_$(CONFIG_CRYPTO).o \ + ../src/crypto/md5.o ../src/crypto/sha1.o ../src/crypto/aes.o \ + ../src/crypto/rc4.o ../src/crypto/des.o ../src/crypto/aes_wrap.o \ + ../src/crypto/sha256.o \ + ../src/tls/bignum.o ../src/tls/rsa.o +test_x509v3: $(OBJSx) + $(LDO) $(LDFLAGS) -o test_x509v3 $(OBJSx) + +win_if_list: win_if_list.c + $(LDO) $(LDFLAGS) -o $@ win_if_list.c $(CFLAGS) $(LIBS_w) + +eap_psk.so: ../src/eap_peer/eap_psk.c ../src/eap_common/eap_psk_common.c + $(CC) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \ + -Deap_peer_psk_register=eap_peer_method_dynamic_init + +eap_pax.so: ../src/eap_peer/eap_pax.c ../src/eap_common/eap_pax_common.c + $(CC) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \ + -Deap_peer_pax_register=eap_peer_method_dynamic_init + +eap_sake.so: ../src/eap_peer/eap_sake.c ../src/eap_common/eap_sake_common.c + $(CC) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \ + -Deap_peer_sake_register=eap_peer_method_dynamic_init + +eap_wsc.so: ../src/eap_peer/eap_wsc.c ../src/eap_common/eap_wsc_common.c ../src/wps/wps.c + $(CC) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \ + -Deap_peer_wsc_register=eap_peer_method_dynamic_init + +eap_ikev2.so: ../src/eap_peer/eap_ikev2.c ../src/eap_peer/ikev2.c ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.c + $(CC) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \ + -Deap_peer_ikev2_register=eap_peer_method_dynamic_init + +%.so: %.c + $(CC) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $< \ + -D$(*F:eap_%=eap_peer_%)_register=eap_peer_method_dynamic_init + + +wpa_supplicant.exe: wpa_supplicant + mv -f $< $@ +wpa_cli.exe: wpa_cli + mv -f $< $@ +wpa_passphrase.exe: wpa_passphrase + mv -f $< $@ +win_if_list.exe: win_if_list + mv -f $< $@ +eapol_test.exe: eapol_test + mv -f $< $@ + +WINALL=wpa_supplicant.exe wpa_cli.exe wpa_passphrase.exe win_if_list.exe + +windows-bin: $(WINALL) + $(STRIP) $(WINALL) + +wpa_gui/Makefile: + qmake -o wpa_gui/Makefile wpa_gui/wpa_gui.pro + +wpa_gui: wpa_gui/Makefile + $(MAKE) -C wpa_gui + +wpa_gui-qt4/Makefile: + qmake -o wpa_gui-qt4/Makefile wpa_gui-qt4/wpa_gui.pro + +wpa_gui-qt4: wpa_gui-qt4/Makefile + $(MAKE) -C wpa_gui-qt4 + +TEST_MS_FUNCS_OBJS = ../src/crypto/crypto_openssl.o ../src/crypto/sha1.o ../src/crypto/md5.o \ + ../src/utils/os_unix.o ../src/crypto/rc4.o tests/test_ms_funcs.o +test-ms_funcs: $(TEST_MS_FUNCS_OBJS) + $(LDO) $(LDFLAGS) -o $@ $(TEST_MS_FUNCS_OBJS) $(LIBS) -lcrypto + ./test-ms_funcs + rm test-ms_funcs + +TEST_SHA1_OBJS = ../src/crypto/sha1.o ../src/crypto/md5.o tests/test_sha1.o #../src/crypto/crypto_openssl.o +test-sha1: $(TEST_SHA1_OBJS) + $(LDO) $(LDFLAGS) -o $@ $(TEST_SHA1_OBJS) $(LIBS) + ./test-sha1 + rm test-sha1 + +TEST_SHA256_OBJS = ../src/crypto/sha256.o ../src/crypto/md5.o tests/test_sha256.o ../src/utils/os_unix.o ../src/crypto/crypto_openssl.o +test-sha256: $(TEST_SHA256_OBJS) + $(LDO) $(LDFLAGS) -o $@ $(TEST_SHA256_OBJS) $(LIBS) + ./test-sha256 + rm test-sha256 + +TEST_AES_OBJS = ../src/crypto/aes_wrap.o ../src/crypto/aes.o tests/test_aes.o +test-aes: $(TEST_AES_OBJS) + $(LDO) $(LDFLAGS) -o $@ $(TEST_AES_OBJS) $(LIBS) + ./test-aes + rm test-aes + +TEST_EAP_SIM_COMMON_OBJS = ../src/crypto/sha1.o ../src/crypto/md5.o \ + ../src/crypto/aes_wrap.o ../src/utils/common.o ../src/utils/os_unix.o \ + ../src/utils/wpa_debug.o ../src/crypto/aes.o \ + tests/test_eap_sim_common.o +test-eap_sim_common: $(TEST_EAP_SIM_COMMON_OBJS) + $(LDO) $(LDFLAGS) -o $@ $(TEST_AES_OBJS) $(LIBS) + ./test-eap_sim_common + rm test-eap_sim_common + +TEST_MD4_OBJS = ../src/crypto/md4.o tests/test_md4.o #../src/crypto/crypto_openssl.o +test-md4: $(TEST_MD4_OBJS) + $(LDO) $(LDFLAGS) -o $@ $(TEST_MD4_OBJS) $(LIBS) + ./test-md4 + rm test-md4 + +TEST_MD5_OBJS = ../src/crypto/md5.o tests/test_md5.o #../src/crypto/crypto_openssl.o +test-md5: $(TEST_MD5_OBJS) + $(LDO) $(LDFLAGS) -o $@ $(TEST_MD5_OBJS) $(LIBS) + ./test-md5 + rm test-md5 + +tests: test-ms_funcs test-sha1 test-aes test-eap_sim_common test-md4 test-md5 + +clean: + $(MAKE) -C ../src clean + rm -f core *~ *.o *.d eap_*.so $(ALL) $(WINALL) + +%.eps: %.fig + fig2dev -L eps $*.fig $*.eps + +%.png: %.fig + fig2dev -L png -m 3 $*.fig | pngtopnm | pnmscale 0.4 | pnmtopng \ + > $*.png + +docs-pics: doc/wpa_supplicant.png doc/wpa_supplicant.eps + +docs: docs-pics + (cd ..; doxygen wpa_supplicant/doc/doxygen.full; cd wpa_supplicant) + $(MAKE) -C doc/latex + cp doc/latex/refman.pdf wpa_supplicant-devel.pdf + +docs-fast: docs-pics + (cd ..; doxygen wpa_supplicant/doc/doxygen.fast; cd wpa_supplicant) + +clean-docs: + rm -rf doc/latex doc/html + rm -f doc/wpa_supplicant.{eps,png} wpa_supplicant-devel.pdf + +-include $(OBJS:%.o=%.d) diff --git a/wpa_supplicant/README b/wpa_supplicant/README new file mode 100644 index 000000000000..2b94c2309d8a --- /dev/null +++ b/wpa_supplicant/README @@ -0,0 +1,1028 @@ +WPA Supplicant +============== + +Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi> and contributors +All Rights Reserved. + +This program is dual-licensed under both the GPL version 2 and BSD +license. Either license may be used at your option. + + + +License +------- + +GPL v2: + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +(this copy of the license is in COPYING file) + + +Alternatively, this software may be distributed, used, and modified +under the terms of BSD license: + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name(s) of the above-listed copyright holder(s) nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +Features +-------- + +Supported WPA/IEEE 802.11i features: +- WPA-PSK ("WPA-Personal") +- WPA with EAP (e.g., with RADIUS authentication server) ("WPA-Enterprise") + Following authentication methods are supported with an integrate IEEE 802.1X + Supplicant: + * EAP-TLS + * EAP-PEAP/MSCHAPv2 (both PEAPv0 and PEAPv1) + * EAP-PEAP/TLS (both PEAPv0 and PEAPv1) + * EAP-PEAP/GTC (both PEAPv0 and PEAPv1) + * EAP-PEAP/OTP (both PEAPv0 and PEAPv1) + * EAP-PEAP/MD5-Challenge (both PEAPv0 and PEAPv1) + * EAP-TTLS/EAP-MD5-Challenge + * EAP-TTLS/EAP-GTC + * EAP-TTLS/EAP-OTP + * EAP-TTLS/EAP-MSCHAPv2 + * EAP-TTLS/EAP-TLS + * EAP-TTLS/MSCHAPv2 + * EAP-TTLS/MSCHAP + * EAP-TTLS/PAP + * EAP-TTLS/CHAP + * EAP-SIM + * EAP-AKA + * EAP-PSK + * EAP-PAX + * EAP-SAKE + * EAP-IKEv2 + * EAP-GPSK + * LEAP (note: requires special support from the driver for IEEE 802.11 + authentication) + (following methods are supported, but since they do not generate keying + material, they cannot be used with WPA or IEEE 802.1X WEP keying) + * EAP-MD5-Challenge + * EAP-MSCHAPv2 + * EAP-GTC + * EAP-OTP +- key management for CCMP, TKIP, WEP104, WEP40 +- RSN/WPA2 (IEEE 802.11i) + * pre-authentication + * PMKSA caching + +Supported TLS/crypto libraries: +- OpenSSL (default) +- GnuTLS + +Internal TLS/crypto implementation (optional): +- can be used in place of an external TLS/crypto library +- TLSv1 +- X.509 certificate processing +- PKCS #1 +- ASN.1 +- RSA +- bignum +- minimal size (ca. 50 kB binary, parts of which are already needed for WPA; + TLSv1/X.509/ASN.1/RSA/bignum parts are about 25 kB on x86) + + +Requirements +------------ + +Current hardware/software requirements: +- Linux kernel 2.4.x or 2.6.x with Linux Wireless Extensions v15 or newer +- FreeBSD 6-CURRENT +- NetBSD-current +- Microsoft Windows with WinPcap (at least WinXP, may work with other versions) +- drivers: + Linux drivers that support WPA/WPA2 configuration with the generic + Linux wireless extensions (WE-18 or newer). Even though there are + number of driver specific interface included in wpa_supplicant, please + note that Linux drivers are moving to use generic wireless extensions + and driver_wext (-Dwext on wpa_supplicant command line) should be the + default option to start with before falling back to driver specific + interface. + + Host AP driver for Prism2/2.5/3 (development snapshot/v0.2.x) + (http://hostap.epitest.fi/) + Driver need to be set in Managed mode ('iwconfig wlan0 mode managed'). + Please note that station firmware version needs to be 1.7.0 or newer + to work in WPA mode. + + Linuxant DriverLoader (http://www.linuxant.com/driverloader/) + with Windows NDIS driver for your wlan card supporting WPA. + + Agere Systems Inc. Linux Driver + (http://www.agere.com/support/drivers/) + Please note that the driver interface file (driver_hermes.c) and + hardware specific include files are not included in the + wpa_supplicant distribution. You will need to copy these from the + source package of the Agere driver. + + madwifi driver for cards based on Atheros chip set (ar521x) + (http://sourceforge.net/projects/madwifi/) + Please note that you will need to modify the wpa_supplicant .config + file to use the correct path for the madwifi driver root directory + (CFLAGS += -I../madwifi/wpa line in example defconfig). + + ATMEL AT76C5XXx driver for USB and PCMCIA cards + (http://atmelwlandriver.sourceforge.net/). + + Linux ndiswrapper (http://ndiswrapper.sourceforge.net/) with + Windows NDIS driver. + + Broadcom wl.o driver (old version only) + This is a generic Linux driver for Broadcom IEEE 802.11a/g cards. + However, it is proprietary driver that is not publicly available + except for couple of exceptions, mainly Broadcom-based APs/wireless + routers that use Linux. The driver binary can be downloaded, e.g., + from Linksys support site (http://www.linksys.com/support/gpl.asp) + for Linksys WRT54G. The GPL tarball includes cross-compiler and + the needed header file, wlioctl.h, for compiling wpa_supplicant. + This driver support in wpa_supplicant is expected to work also with + other devices based on Broadcom driver (assuming the driver includes + client mode support). Please note that the newer Broadcom driver + ("hybrid Linux driver") supports Linux wireless extensions and does + not need (or even work) with the specific driver wrapper. Use -Dwext + with that driver. + + Intel ipw2100 driver + (http://sourceforge.net/projects/ipw2100/) + + Intel ipw2200 driver + (http://sourceforge.net/projects/ipw2200/) + + In theory, any driver that supports Linux wireless extensions can be + used with IEEE 802.1X (i.e., not WPA) when using ap_scan=0 option in + configuration file. + + Wired Ethernet drivers (with ap_scan=0) + + BSD net80211 layer (e.g., Atheros driver) + At the moment, this is for FreeBSD 6-CURRENT branch and NetBSD-current. + + Windows NDIS + The current Windows port requires WinPcap (http://winpcap.polito.it/). + See README-Windows.txt for more information. + +wpa_supplicant was designed to be portable for different drivers and +operating systems. Hopefully, support for more wlan cards and OSes will be +added in the future. See developer's documentation +(http://hostap.epitest.fi/wpa_supplicant/devel/) for more information about the +design of wpa_supplicant and porting to other drivers. One main goal +is to add full WPA/WPA2 support to Linux wireless extensions to allow +new drivers to be supported without having to implement new +driver-specific interface code in wpa_supplicant. + +Optional libraries for layer2 packet processing: +- libpcap (tested with 0.7.2, most relatively recent versions assumed to work, + this is likely to be available with most distributions, + http://tcpdump.org/) +- libdnet (tested with v1.4, most versions assumed to work, + http://libdnet.sourceforge.net/) + +These libraries are _not_ used in the default Linux build. Instead, +internal Linux specific implementation is used. libpcap/libdnet are +more portable and they can be used by adding CONFIG_L2_PACKET=pcap into +.config. They may also be selected automatically for other operating +systems. In case of Windows builds, WinPcap is used by default +(CONFIG_L2_PACKET=winpcap). + + +Optional libraries for EAP-TLS, EAP-PEAP, and EAP-TTLS: +- OpenSSL (tested with 0.9.7c and 0.9.7d, and 0.9.8 versions; assumed to + work with most relatively recent versions; this is likely to be + available with most distributions, http://www.openssl.org/) +- GnuTLS +- internal TLSv1 implementation + +TLS options for EAP-FAST: +- OpenSSL 0.9.8d _with_ openssl-0.9.8d-tls-extensions.patch applied + (i.e., the default OpenSSL package does not include support for + extensions needed for EAP-FAST) +- internal TLSv1 implementation + +One of these libraries is needed when EAP-TLS, EAP-PEAP, EAP-TTLS, or +EAP-FAST support is enabled. WPA-PSK mode does not require this or EAPOL/EAP +implementation. A configuration file, .config, for compilation is +needed to enable IEEE 802.1X/EAPOL and EAP methods. Note that EAP-MD5, +EAP-GTC, EAP-OTP, and EAP-MSCHAPV2 cannot be used alone with WPA, so +they should only be enabled if testing the EAPOL/EAP state +machines. However, there can be used as inner authentication +algorithms with EAP-PEAP and EAP-TTLS. + +See Building and installing section below for more detailed +information about the wpa_supplicant build time configuration. + + + +WPA +--- + +The original security mechanism of IEEE 802.11 standard was not +designed to be strong and has proven 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 published in July 2004. + +Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version of the +IEEE 802.11i work (draft 3.0) to define a subset of the security +enhancements that can be implemented with existing wlan hardware. This +is called Wi-Fi Protected Access<TM> (WPA). This has now become a +mandatory component of interoperability testing and certification done +by Wi-Fi Alliance. Wi-Fi provides information about WPA at its web +site (http://www.wi-fi.org/OpenSection/protected_access.asp). + +IEEE 802.11 standard defined wired equivalent privacy (WEP) algorithm +for protecting wireless networks. WEP uses RC4 with 40-bit keys, +24-bit initialization vector (IV), and CRC32 to protect against packet +forgery. All these choices have proven to be insufficient: key space is +too small against current attacks, RC4 key scheduling is insufficient +(beginning of the pseudorandom stream should be skipped), IV space is +too small and IV reuse makes attacks easier, there is no replay +protection, and non-keyed authentication does not protect against bit +flipping packet data. + +WPA is an intermediate solution for the security issues. It uses +Temporal Key Integrity Protocol (TKIP) to replace WEP. TKIP is a +compromise on strong security and possibility to use existing +hardware. It still uses RC4 for the encryption like WEP, but with +per-packet RC4 keys. In addition, it implements replay protection, +keyed packet authentication mechanism (Michael MIC). + +Keys can be managed using two different mechanisms. WPA can either use +an external authentication server (e.g., RADIUS) and EAP just like +IEEE 802.1X is using or pre-shared keys without need for additional +servers. Wi-Fi calls these "WPA-Enterprise" and "WPA-Personal", +respectively. Both mechanisms will generate a master session key for +the Authenticator (AP) and Supplicant (client station). + +WPA implements a new key handshake (4-Way Handshake and Group Key +Handshake) for generating and exchanging data encryption keys between +the Authenticator and Supplicant. This handshake is also used to +verify that both Authenticator and Supplicant know the master session +key. These handshakes are identical regardless of the selected key +management mechanism (only the method for generating master session +key changes). + + + +IEEE 802.11i / WPA2 +------------------- + +The design for parts of IEEE 802.11i that were not included in WPA has +finished (May 2004) and this amendment to IEEE 802.11 was approved in +June 2004. Wi-Fi Alliance is using the final IEEE 802.11i as a new +version of WPA called WPA2. This includes, e.g., support for more +robust encryption algorithm (CCMP: AES in Counter mode with CBC-MAC) +to replace TKIP and optimizations for handoff (reduced number of +messages in initial key handshake, pre-authentication, and PMKSA caching). + + + +wpa_supplicant +-------------- + +wpa_supplicant is an implementation of the WPA Supplicant component, +i.e., the part that runs in the client stations. It implements WPA key +negotiation with a WPA Authenticator and EAP authentication with +Authentication Server. In addition, it controls the roaming and IEEE +802.11 authentication/association of the wlan driver. + +wpa_supplicant is designed to be a "daemon" program that runs in the +background and acts as the backend component controlling the wireless +connection. wpa_supplicant supports separate frontend programs and an +example text-based frontend, wpa_cli, is included with wpa_supplicant. + +Following steps are used when associating with an AP using WPA: + +- wpa_supplicant requests the kernel driver to scan neighboring BSSes +- wpa_supplicant selects a BSS based on its configuration +- wpa_supplicant requests the kernel driver to associate with the chosen + BSS +- If WPA-EAP: integrated IEEE 802.1X Supplicant completes EAP + authentication with the authentication server (proxied by the + Authenticator in the AP) +- If WPA-EAP: master key is received from the IEEE 802.1X Supplicant +- If WPA-PSK: wpa_supplicant uses PSK as the master session key +- wpa_supplicant completes WPA 4-Way Handshake and Group Key Handshake + with the Authenticator (AP) +- wpa_supplicant configures encryption keys for unicast and broadcast +- normal data packets can be transmitted and received + + + +Building and installing +----------------------- + +In order to be able to build wpa_supplicant, you will first need to +select which parts of it will be included. This is done by creating a +build time configuration file, .config, in the wpa_supplicant root +directory. Configuration options are text lines using following +format: CONFIG_<option>=y. Lines starting with # are considered +comments and are ignored. See defconfig file for an example configuration +and a list of available options and additional notes. + +The build time configuration can be used to select only the needed +features and limit the binary size and requirements for external +libraries. The main configuration parts are the selection of which +driver interfaces (e.g., hostap, madwifi, ..) and which authentication +methods (e.g., EAP-TLS, EAP-PEAP, ..) are included. + +Following build time configuration options are used to control IEEE +802.1X/EAPOL and EAP state machines and all EAP methods. Including +TLS, PEAP, or TTLS will require linking wpa_supplicant with OpenSSL +library for TLS implementation. Alternatively, GnuTLS or the internal +TLSv1 implementation can be used for TLS functionaly. + +CONFIG_IEEE8021X_EAPOL=y +CONFIG_EAP_MD5=y +CONFIG_EAP_MSCHAPV2=y +CONFIG_EAP_TLS=y +CONFIG_EAP_PEAP=y +CONFIG_EAP_TTLS=y +CONFIG_EAP_GTC=y +CONFIG_EAP_OTP=y +CONFIG_EAP_SIM=y +CONFIG_EAP_AKA=y +CONFIG_EAP_PSK=y +CONFIG_EAP_SAKE=y +CONFIG_EAP_GPSK=y +CONFIG_EAP_PAX=y +CONFIG_EAP_LEAP=y +CONFIG_EAP_IKEV2=y + +Following option can be used to include GSM SIM/USIM interface for GSM/UMTS +authentication algorithm (for EAP-SIM/EAP-AKA). This requires pcsc-lite +(http://www.linuxnet.com/) for smart card access. + +CONFIG_PCSC=y + +Following options can be added to .config to select which driver +interfaces are included. Hermes driver interface needs to be downloaded +from Agere (see above). CONFIG_WIRELESS_EXTENSION will be used +automatically if any of the selected drivers need it. + +CONFIG_WIRELESS_EXTENSION=y +CONFIG_DRIVER_HOSTAP=y +CONFIG_DRIVER_HERMES=y +CONFIG_DRIVER_MADWIFI=y +CONFIG_DRIVER_ATMEL=y +CONFIG_DRIVER_WEXT=y +CONFIG_DRIVER_RALINK=y +CONFIG_DRIVER_NDISWRAPPER=y +CONFIG_DRIVER_BROADCOM=y +CONFIG_DRIVER_IPW=y +CONFIG_DRIVER_BSD=y +CONFIG_DRIVER_NDIS=y + +Following example includes all features and driver interfaces that are +included in the wpa_supplicant package: + +CONFIG_DRIVER_HOSTAP=y +CONFIG_DRIVER_HERMES=y +CONFIG_DRIVER_MADWIFI=y +CONFIG_DRIVER_ATMEL=y +CONFIG_DRIVER_WEXT=y +CONFIG_DRIVER_NDISWRAPPER=y +CONFIG_DRIVER_BROADCOM=y +CONFIG_DRIVER_IPW=y +CONFIG_DRIVER_BSD=y +CONFIG_DRIVER_NDIS=y +CONFIG_WIRELESS_EXTENSION=y +CONFIG_IEEE8021X_EAPOL=y +CONFIG_EAP_MD5=y +CONFIG_EAP_MSCHAPV2=y +CONFIG_EAP_TLS=y +CONFIG_EAP_PEAP=y +CONFIG_EAP_TTLS=y +CONFIG_EAP_GTC=y +CONFIG_EAP_OTP=y +CONFIG_EAP_SIM=y +CONFIG_EAP_AKA=y +CONFIG_EAP_PSK=y +CONFIG_EAP_SAKE=y +CONFIG_EAP_GPSK=y +CONFIG_EAP_PAX=y +CONFIG_EAP_LEAP=y +CONFIG_EAP_IKEV2=y +CONFIG_PCSC=y + +EAP-PEAP and EAP-TTLS will automatically include configured EAP +methods (MD5, OTP, GTC, MSCHAPV2) for inner authentication selection. + + +After you have created a configuration file, you can build +wpa_supplicant and wpa_cli with 'make' command. You may then install +the binaries to a suitable system directory, e.g., /usr/local/bin. + +Example commands: + +# build wpa_supplicant and wpa_cli +make +# install binaries (this may need root privileges) +cp wpa_cli wpa_supplicant /usr/local/bin + + +You will need to make a configuration file, e.g., +/etc/wpa_supplicant.conf, with network configuration for the networks +you are going to use. Configuration file section below includes +explanation fo the configuration file format and includes various +examples. Once the configuration is ready, you can test whether the +configuration work by first running wpa_supplicant with following +command to start it on foreground with debugging enabled: + +wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -d + +Assuming everything goes fine, you can start using following command +to start wpa_supplicant on background without debugging: + +wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -B + +Please note that if you included more than one driver interface in the +build time configuration (.config), you may need to specify which +interface to use by including -D<driver name> option on the command +line. See following section for more details on command line options +for wpa_supplicant. + + + +Command line options +-------------------- + +usage: + wpa_supplicant [-BddfhKLqqtuvwW] [-P<pid file>] [-g<global ctrl>] \ + -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] [-p<driver_param>] \ + [-b<br_ifname> [-N -i<ifname> -c<conf> [-C<ctrl>] [-D<driver>] \ + [-p<driver_param>] [-b<br_ifname>] ...] + +options: + -b = optional bridge interface name + -B = run daemon in the background + -c = Configuration file + -C = ctrl_interface parameter (only used if -c is not) + -i = interface name + -d = increase debugging verbosity (-dd even more) + -D = driver name + -f = Log output to default log location (normally /tmp) + -g = global ctrl_interface + -K = include keys (passwords, etc.) in debug output + -t = include timestamp in debug messages + -h = show this help text + -L = show license (GPL and BSD) + -p = driver parameters + -P = PID file + -q = decrease debugging verbosity (-qq even less) + -u = enable DBus control interface + -v = show version + -w = wait for interface to be added, if needed + -W = wait for a control interface monitor before starting + -N = start describing new interface + +drivers: + hostap = Host AP driver (Intersil Prism2/2.5/3) [default] + (this can also be used with Linuxant DriverLoader) + hermes = Agere Systems Inc. driver (Hermes-I/Hermes-II) + madwifi = MADWIFI 802.11 support (Atheros, etc.) + atmel = ATMEL AT76C5XXx (USB, PCMCIA) + wext = Linux wireless extensions (generic) + ralink = Ralink Client driver + ndiswrapper = Linux ndiswrapper + broadcom = Broadcom wl.o driver + ipw = Intel ipw2100/2200 driver (old; use wext with Linux 2.6.13 or newer) + wired = wpa_supplicant wired Ethernet driver + roboswitch = wpa_supplicant Broadcom switch driver + bsd = BSD 802.11 support (Atheros, etc.) + ndis = Windows NDIS driver + +In most common cases, wpa_supplicant is started with + +wpa_supplicant -B -c/etc/wpa_supplicant.conf -iwlan0 + +This makes the process fork into background. + +The easiest way to debug problems, and to get debug log for bug +reports, is to start wpa_supplicant on foreground with debugging +enabled: + +wpa_supplicant -c/etc/wpa_supplicant.conf -iwlan0 -d + + +wpa_supplicant can control multiple interfaces (radios) either by +running one process for each interface separately or by running just +one process and list of options at command line. Each interface is +separated with -N argument. As an example, following command would +start wpa_supplicant for two interfaces: + +wpa_supplicant \ + -c wpa1.conf -i wlan0 -D hostap -N \ + -c wpa2.conf -i ath0 -D madwifi + + +If the interface is added in a Linux bridge (e.g., br0), the bridge +interface needs to be configured to wpa_supplicant in addition to the +main interface: + +wpa_supplicant -cw.conf -Dmadwifi -iath0 -bbr0 + + +Configuration file +------------------ + +wpa_supplicant is configured using a text file that lists all accepted +networks and security policies, including pre-shared keys. See +example configuration file, wpa_supplicant.conf, for detailed +information about the configuration format and supported fields. + +Changes to configuration file can be reloaded be sending SIGHUP signal +to wpa_supplicant ('killall -HUP wpa_supplicant'). Similarly, +reloading can be triggered with 'wpa_cli reconfigure' command. + +Configuration file can include one or more network blocks, e.g., one +for each used SSID. wpa_supplicant will automatically select the best +betwork based on the order of network blocks in the configuration +file, network security level (WPA/WPA2 is preferred), and signal +strength. + +Example configuration files for some common configurations: + +1) WPA-Personal (PSK) as home network and WPA-Enterprise with EAP-TLS as work + network + +# allow frontend (e.g., wpa_cli) to be used by all users in 'wheel' group +ctrl_interface=/var/run/wpa_supplicant +ctrl_interface_group=wheel +# +# home network; allow all valid ciphers +network={ + ssid="home" + scan_ssid=1 + key_mgmt=WPA-PSK + psk="very secret passphrase" +} +# +# work network; use EAP-TLS with WPA; allow only CCMP and TKIP ciphers +network={ + ssid="work" + scan_ssid=1 + key_mgmt=WPA-EAP + pairwise=CCMP TKIP + group=CCMP TKIP + eap=TLS + identity="user@example.com" + ca_cert="/etc/cert/ca.pem" + client_cert="/etc/cert/user.pem" + private_key="/etc/cert/user.prv" + private_key_passwd="password" +} + + +2) WPA-RADIUS/EAP-PEAP/MSCHAPv2 with RADIUS servers that use old peaplabel + (e.g., Funk Odyssey and SBR, Meetinghouse Aegis, Interlink RAD-Series) + +ctrl_interface=/var/run/wpa_supplicant +ctrl_interface_group=wheel +network={ + ssid="example" + scan_ssid=1 + key_mgmt=WPA-EAP + eap=PEAP + identity="user@example.com" + password="foobar" + ca_cert="/etc/cert/ca.pem" + phase1="peaplabel=0" + phase2="auth=MSCHAPV2" +} + + +3) EAP-TTLS/EAP-MD5-Challenge configuration with anonymous identity for the + unencrypted use. Real identity is sent only within an encrypted TLS tunnel. + +ctrl_interface=/var/run/wpa_supplicant +ctrl_interface_group=wheel +network={ + ssid="example" + scan_ssid=1 + key_mgmt=WPA-EAP + eap=TTLS + identity="user@example.com" + anonymous_identity="anonymous@example.com" + password="foobar" + ca_cert="/etc/cert/ca.pem" + phase2="auth=MD5" +} + + +4) IEEE 802.1X (i.e., no WPA) with dynamic WEP keys (require both unicast and + broadcast); use EAP-TLS for authentication + +ctrl_interface=/var/run/wpa_supplicant +ctrl_interface_group=wheel +network={ + ssid="1x-test" + scan_ssid=1 + key_mgmt=IEEE8021X + eap=TLS + identity="user@example.com" + ca_cert="/etc/cert/ca.pem" + client_cert="/etc/cert/user.pem" + private_key="/etc/cert/user.prv" + private_key_passwd="password" + eapol_flags=3 +} + + +5) Catch all example that allows more or less all configuration modes. The + configuration options are used based on what security policy is used in the + selected SSID. This is mostly for testing and is not recommended for normal + use. + +ctrl_interface=/var/run/wpa_supplicant +ctrl_interface_group=wheel +network={ + ssid="example" + scan_ssid=1 + key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE + pairwise=CCMP TKIP + group=CCMP TKIP WEP104 WEP40 + psk="very secret passphrase" + eap=TTLS PEAP TLS + identity="user@example.com" + password="foobar" + ca_cert="/etc/cert/ca.pem" + client_cert="/etc/cert/user.pem" + private_key="/etc/cert/user.prv" + private_key_passwd="password" + phase1="peaplabel=0" + ca_cert2="/etc/cert/ca2.pem" + client_cert2="/etc/cer/user.pem" + private_key2="/etc/cer/user.prv" + private_key2_passwd="password" +} + + +6) Authentication for wired Ethernet. This can be used with 'wired' or + 'roboswitch' interface (-Dwired or -Droboswitch on command line). + +ctrl_interface=/var/run/wpa_supplicant +ctrl_interface_group=wheel +ap_scan=0 +network={ + key_mgmt=IEEE8021X + eap=MD5 + identity="user" + password="password" + eapol_flags=0 +} + + + +Certificates +------------ + +Some EAP authentication methods require use of certificates. EAP-TLS +uses both server side and client certificates whereas EAP-PEAP and +EAP-TTLS only require the server side certificate. When client +certificate is used, a matching private key file has to also be +included in configuration. If the private key uses a passphrase, this +has to be configured in wpa_supplicant.conf ("private_key_passwd"). + +wpa_supplicant supports X.509 certificates in PEM and DER +formats. User certificate and private key can be included in the same +file. + +If the user certificate and private key is received in PKCS#12/PFX +format, they need to be converted to suitable PEM/DER format for +wpa_supplicant. This can be done, e.g., with following commands: + +# convert client certificate and private key to PEM format +openssl pkcs12 -in example.pfx -out user.pem -clcerts +# convert CA certificate (if included in PFX file) to PEM format +openssl pkcs12 -in example.pfx -out ca.pem -cacerts -nokeys + + + +wpa_cli +------- + +wpa_cli is a text-based frontend program for interacting with +wpa_supplicant. It is used to query current status, change +configuration, trigger events, and request interactive user input. + +wpa_cli can show the current authentication status, selected security +mode, dot11 and dot1x MIBs, etc. In addition, it can configure some +variables like EAPOL state machine parameters and trigger events like +reassociation and IEEE 802.1X logoff/logon. wpa_cli provides a user +interface to request authentication information, like username and +password, if these are not included in the configuration. This can be +used to implement, e.g., one-time-passwords or generic token card +authentication where the authentication is based on a +challenge-response that uses an external device for generating the +response. + +The control interface of wpa_supplicant can be configured to allow +non-root user access (ctrl_interface_group in the configuration +file). This makes it possible to run wpa_cli with a normal user +account. + +wpa_cli supports two modes: interactive and command line. Both modes +share the same command set and the main difference is in interactive +mode providing access to unsolicited messages (event messages, +username/password requests). + +Interactive mode is started when wpa_cli is executed without including +the command as a command line parameter. Commands are then entered on +the wpa_cli prompt. In command line mode, the same commands are +entered as command line arguments for wpa_cli. + + +Interactive authentication parameters request + +When wpa_supplicant need authentication parameters, like username and +password, which are not present in the configuration file, it sends a +request message to all attached frontend programs, e.g., wpa_cli in +interactive mode. wpa_cli shows these requests with +"CTRL-REQ-<type>-<id>:<text>" prefix. <type> is IDENTITY, PASSWORD, or +OTP (one-time-password). <id> is a unique identifier for the current +network. <text> is description of the request. In case of OTP request, +it includes the challenge from the authentication server. + +The reply to these requests can be given with 'identity', 'password', +and 'otp' commands. <id> needs to be copied from the the matching +request. 'password' and 'otp' commands can be used regardless of +whether the request was for PASSWORD or OTP. The main difference +between these two commands is that values given with 'password' are +remembered as long as wpa_supplicant is running whereas values given +with 'otp' are used only once and then forgotten, i.e., wpa_supplicant +will ask frontend for a new value for every use. This can be used to +implement one-time-password lists and generic token card -based +authentication. + +Example request for password and a matching reply: + +CTRL-REQ-PASSWORD-1:Password needed for SSID foobar +> password 1 mysecretpassword + +Example request for generic token card challenge-response: + +CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar +> otp 2 9876 + + +wpa_cli commands + + status = get current WPA/EAPOL/EAP status + mib = get MIB variables (dot1x, dot11) + help = show this usage help + interface [ifname] = show interfaces/select interface + level <debug level> = change debug level + license = show full wpa_cli license + logoff = IEEE 802.1X EAPOL state machine logoff + logon = IEEE 802.1X EAPOL state machine logon + set = set variables (shows list of variables when run without arguments) + pmksa = show PMKSA cache + reassociate = force reassociation + reconfigure = force wpa_supplicant to re-read its configuration file + preauthenticate <BSSID> = force preauthentication + identity <network id> <identity> = configure identity for an SSID + password <network id> <password> = configure password for an SSID + pin <network id> <pin> = configure pin for an SSID + otp <network id> <password> = configure one-time-password for an SSID + passphrase <network id> <passphrase> = configure private key passphrase + for an SSID + bssid <network id> <BSSID> = set preferred BSSID for an SSID + list_networks = list configured networks + select_network <network id> = select a network (disable others) + enable_network <network id> = enable a network + disable_network <network id> = disable a network + add_network = add a network + remove_network <network id> = remove a network + set_network <network id> <variable> <value> = set network variables (shows + list of variables when run without arguments) + get_network <network id> <variable> = get network variables + save_config = save the current configuration + disconnect = disconnect and wait for reassociate command before connecting + scan = request new BSS scan + scan_results = get latest scan results + get_capability <eap/pairwise/group/key_mgmt/proto/auth_alg> = get capabilies + terminate = terminate wpa_supplicant + quit = exit wpa_cli + + +wpa_cli command line options + +wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hvB] [-a<action file>] \ + [-P<pid file>] [-g<global ctrl>] [command..] + -h = help (show this usage text) + -v = shown version information + -a = run in daemon mode executing the action file based on events from + wpa_supplicant + -B = run a daemon in the background + default path: /var/run/wpa_supplicant + default interface: first interface found in socket path + + +Using wpa_cli to run external program on connect/disconnect +----------------------------------------------------------- + +wpa_cli can used to run external programs whenever wpa_supplicant +connects or disconnects from a network. This can be used, e.g., to +update network configuration and/or trigget DHCP client to update IP +addresses, etc. + +One wpa_cli process in "action" mode needs to be started for each +interface. For example, the following command starts wpa_cli for the +default ingterface (-i can be used to select the interface in case of +more than one interface being used at the same time): + +wpa_cli -a/sbin/wpa_action.sh -B + +The action file (-a option, /sbin/wpa_action.sh in this example) will +be executed whenever wpa_supplicant completes authentication (connect +event) or detects disconnection). The action script will be called +with two command line arguments: interface name and event (CONNECTED +or DISCONNECTED). If the action script needs to get more information +about the current network, it can use 'wpa_cli status' to query +wpa_supplicant for more information. + +Following example can be used as a simple template for an action +script: + +#!/bin/sh + +IFNAME=$1 +CMD=$2 + +if [ "$CMD" == "CONNECTED" ]; then + SSID=`wpa_cli -i$IFNAME status | grep ^ssid= | cut -f2- -d=` + # configure network, signal DHCP client, etc. +fi + +if [ "$CMD" == "DISCONNECTED" ]; then + # remove network configuration, if needed +fi + + + +Integrating with pcmcia-cs/cardmgr scripts +------------------------------------------ + +wpa_supplicant needs to be running when using a wireless network with +WPA. It can be started either from system startup scripts or from +pcmcia-cs/cardmgr scripts (when using PC Cards). WPA handshake must be +completed before data frames can be exchanged, so wpa_supplicant +should be started before DHCP client. + +For example, following small changes to pcmcia-cs scripts can be used +to enable WPA support: + +Add MODE="Managed" and WPA="y" to the network scheme in +/etc/pcmcia/wireless.opts. + +Add the following block to the end of 'start' action handler in +/etc/pcmcia/wireless: + + if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then + /usr/local/bin/wpa_supplicant -B -c/etc/wpa_supplicant.conf \ + -i$DEVICE + fi + +Add the following block to the end of 'stop' action handler (may need +to be separated from other actions) in /etc/pcmcia/wireless: + + if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then + killall wpa_supplicant + fi + +This will make cardmgr start wpa_supplicant when the card is plugged +in. + + + +Dynamic interface add and operation without configuration files +--------------------------------------------------------------- + +wpa_supplicant can be started without any configuration files or +network interfaces. When used in this way, a global (i.e., per +wpa_supplicant process) control interface is used to add and remove +network interfaces. Each network interface can then be configured +through a per-network interface control interface. For example, +following commands show how to start wpa_supplicant without any +network interfaces and then add a network interface and configure a +network (SSID): + +# Start wpa_supplicant in the background +wpa_supplicant -g/var/run/wpa_supplicant-global -B + +# Add a new interface (wlan0, no configuration file, driver=wext, and +# enable control interface) +wpa_cli -g/var/run/wpa_supplicant-global interface_add wlan0 \ + "" wext /var/run/wpa_supplicant + +# Configure a network using the newly added network interface: +wpa_cli -iwlan0 add_network +wpa_cli -iwlan0 set_network 0 ssid '"test"' +wpa_cli -iwlan0 set_network 0 key_mgmt WPA-PSK +wpa_cli -iwlan0 set_network 0 psk '"12345678"' +wpa_cli -iwlan0 set_network 0 pairwise TKIP +wpa_cli -iwlan0 set_network 0 group TKIP +wpa_cli -iwlan0 set_network 0 proto WPA +wpa_cli -iwlan0 enable_network 0 + +# At this point, the new network interface should start trying to associate +# with the WPA-PSK network using SSID test. + +# Remove network interface +wpa_cli -g/var/run/wpa_supplicant-global interface_remove wlan0 + + +Privilege separation +-------------------- + +To minimize the size of code that needs to be run with root privileges +(e.g., to control wireless interface operation), wpa_supplicant +supports optional privilege separation. If enabled, this separates the +privileged operations into a separate process (wpa_priv) while leaving +rest of the code (e.g., EAP authentication and WPA handshakes) into an +unprivileged process (wpa_supplicant) that can be run as non-root +user. Privilege separation restricts the effects of potential software +errors by containing the majority of the code in an unprivileged +process to avoid full system compromise. + +Privilege separation is not enabled by default and it can be enabled +by adding CONFIG_PRIVSEP=y to the build configuration (.config). When +enabled, the privileged operations (driver wrapper and l2_packet) are +linked into a separate daemon program, wpa_priv. The unprivileged +program, wpa_supplicant, will be built with a special driver/l2_packet +wrappers that communicate with the privileged wpa_priv process to +perform the needed operations. wpa_priv can control what privileged +are allowed. + +wpa_priv needs to be run with network admin privileges (usually, root +user). It opens a UNIX domain socket for each interface that is +included on the command line; any other interface will be off limits +for wpa_supplicant in this kind of configuration. After this, +wpa_supplicant can be run as a non-root user (e.g., all standard users +on a laptop or as a special non-privileged user account created just +for this purpose to limit access to user files even further). + + +Example configuration: +- create user group for users that are allowed to use wpa_supplicant + ('wpapriv' in this example) and assign users that should be able to + use wpa_supplicant into that group +- create /var/run/wpa_priv directory for UNIX domain sockets and control + user access by setting it accessible only for the wpapriv group: + mkdir /var/run/wpa_priv + chown root:wpapriv /var/run/wpa_priv + chmod 0750 /var/run/wpa_priv +- start wpa_priv as root (e.g., from system startup scripts) with the + enabled interfaces configured on the command line: + wpa_priv -B -P /var/run/wpa_priv.pid wext:ath0 +- run wpa_supplicant as non-root with a user that is in wpapriv group: + wpa_supplicant -i ath0 -c wpa_supplicant.conf + +wpa_priv does not use the network interface before wpa_supplicant is +started, so it is fine to include network interfaces that are not +available at the time wpa_priv is started. As an alternative, wpa_priv +can be started when an interface is added (hotplug/udev/etc. scripts). +wpa_priv can control multiple interface with one process, but it is +also possible to run multiple wpa_priv processes at the same time, if +desired. diff --git a/wpa_supplicant/README-WPS b/wpa_supplicant/README-WPS new file mode 100644 index 000000000000..7fd358dbec66 --- /dev/null +++ b/wpa_supplicant/README-WPS @@ -0,0 +1,184 @@ +wpa_supplicant and Wi-Fi Protected Setup (WPS) +============================================== + +This document describes how the WPS implementation in wpa_supplicant +can be configured and how an external component on the client (e.g., +management GUI) is used to enable WPS enrollment and registrar +registration. + + +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 + + +wpa_supplicant implementation +----------------------------- + +wpa_supplicant includes an optional WPS component that can be used as +an Enrollee to enroll new network credential or as a Registrar to +configure an AP. The current version of wpa_supplicant does not +support operation as an external WLAN Management Registrar for adding +new client devices or configuring the AP over UPnP. + + +wpa_supplicant configuration +---------------------------- + +WPS is an optional component that needs to be enabled in +wpa_supplicant build configuration (.config). Here is an example +configuration that includes WPS support and Linux wireless extensions +-based driver interface: + +CONFIG_DRIVER_WEXT=y +CONFIG_EAP=y +CONFIG_WPS=y + + +WPS needs the Universally Unique IDentifier (UUID; see RFC 4122) for +the device. This is configured in the runtime configuration for +wpa_supplicant (if not set, UUID will be generated based on local MAC +address): + +# example UUID for WPS +uuid=12345678-9abc-def0-1234-56789abcdef0 + +The network configuration blocks needed for WPS are added +automatically based on control interface commands, so they do not need +to be added explicitly in the configuration file. + +WPS registration will generate new network blocks for the acquired +credentials. If these are to be stored for future use (after +restarting wpa_supplicant), wpa_supplicant will need to be configured +to allow configuration file updates: + +update_config=1 + + + +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. wpa_supplicant uses the control interface as an input channel +for these events. + +If the client device has a display, a random PIN has to be generated +for each WPS registration session. wpa_supplicant can do this with a +control interface request, e.g., by calling wpa_cli: + +wpa_cli wps_pin any + +This will return the generated 8-digit PIN which will then need to be +entered at the Registrar to complete WPS registration. At that point, +the client will be enrolled with credentials needed to connect to the +AP to access the network. + + +If the client device does not have a display that could show the +random PIN, a hardcoded PIN that is printed on a label can be +used. wpa_supplicant is notified this with a control interface +request, e.g., by calling wpa_cli: + +wpa_cli wps_pin any 12345670 + +This starts the WPS negotiation in the same way as above with the +generated PIN. + + +If the client design wants to support optional WPS PBC mode, this can +be enabled by either a physical button in the client device or a +virtual button in the user interface. The PBC operation requires that +a button is also pressed at the AP/Registrar at about the same time (2 +minute window). wpa_supplicant is notified of the local button event +over the control interface, e.g., by calling wpa_cli: + +wpa_cli wps_pbc + +At this point, the AP/Registrar has two minutes to complete WPS +negotiation which will generate a new WPA PSK in the same way as the +PIN method described above. + + +If the client wants to operation in the Registrar role to configure an +AP, wpa_supplicant is notified over the control interface, e.g., with +wpa_cli: + +wpa_cli wps_reg <AP BSSID> <AP PIN> +(example: wpa_cli wps_reg 02:34:56:78:9a:bc 12345670) + + +Scanning +-------- + +Scan results ('wpa_cli scan_results' or 'wpa_cli bss <idx>') include a +flags field that is used to indicate whether the BSS support WPS. If +the AP support WPS, but has not recently activated a Registrar, [WPS] +flag will be included. If PIN method has been recently selected, +[WPS-PIN] is shown instead. Similarly, [WPS-PBC] is shown if PBC mode +is in progress. GUI programs can use these as triggers for suggesting +a guided WPS configuration to the user. In addition, control interface +monitor events WPS-AP-AVAILABLE{,-PBC,-PIN} can be used to find out if +there are WPS enabled APs in scan results without having to go through +all the details in the GUI. These notification could be used, e.g., to +suggest possible WPS connection to the user. + + +wpa_gui +------- + +wpa_gui-qt4 directory contains a sample GUI that shows an example of +how WPS support can be integrated into the GUI. Its main window has a +WPS tab that guides user through WPS registration with automatic AP +selection. In addition, it shows how WPS can be started manually by +selecting an AP from scan results. + + +Credential processing +--------------------- + +By default, wpa_supplicant processes received credentials and updates +its configuration internally. However, it is possible to +control these operations from external programs, if desired. + +This internal processing can be disabled with wps_cred_processing=1 +option. When this is used, an external program is responsible for +processing the credential attributes and updating wpa_supplicant +configuration based on them. + +Following control interface messages are sent out for external programs: + +WPS-CRED-RECEIVED <hexdump of Credential attribute(s)> +For example: +<2>WPS-CRED-RECEIVED 100e006f10260001011045000c6a6b6d2d7770732d74657374100300020020100f000200081027004030653462303435366332363666653064333961643135353461316634626637313234333761636664623766333939653534663166316230323061643434386235102000060266a0ee1727 diff --git a/wpa_supplicant/README-Windows.txt b/wpa_supplicant/README-Windows.txt new file mode 100644 index 000000000000..292223d2d5fe --- /dev/null +++ b/wpa_supplicant/README-Windows.txt @@ -0,0 +1,450 @@ +wpa_supplicant for Windows +========================== + +Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi> and contributors +All Rights Reserved. + +This program is dual-licensed under both the GPL version 2 and BSD +license. Either license may be used at your option. + +This product includes software developed by the OpenSSL Project +for use in the OpenSSL Toolkit (http://www.openssl.org/). This +product includes cryptographic software written by Eric Young +(eay@cryptsoft.com). + + +wpa_supplicant has support for being used as a WPA/WPA2/IEEE 802.1X +Supplicant on Windows. The current port requires that WinPcap +(http://winpcap.polito.it/) is installed for accessing packets and the +driver interface. Both release versions 3.0 and 3.1 are supported. + +The current port is still somewhat experimental. It has been tested +mainly on Windows XP (SP2) with limited set of NDIS drivers. In +addition, the current version has been reported to work with Windows +2000. + +All security modes have been verified to work (at least complete +authentication and successfully ping a wired host): +- plaintext +- static WEP / open system authentication +- static WEP / shared key authentication +- IEEE 802.1X with dynamic WEP keys +- WPA-PSK, TKIP, CCMP, TKIP+CCMP +- WPA-EAP, TKIP, CCMP, TKIP+CCMP +- WPA2-PSK, TKIP, CCMP, TKIP+CCMP +- WPA2-EAP, TKIP, CCMP, TKIP+CCMP + + +Binary version +-------------- + +Compiled binary version of the wpa_supplicant and additional tools is +available from http://w1.fi/wpa_supplicant/. These binaries can be +used after installing WinPcap. + +wpa_gui uses Qt 4 framework and may need additional dynamic libraries +(DLLs). These libraries are available from +http://w1.fi/wpa_supplicant/qt4/wpa_gui-qt433-windows-dll.zip +You can copy the DLL files from this ZIP package into the same directory +with wpa_gui.exe to allow wpa_gui to be started. + + +Building wpa_supplicant with mingw +---------------------------------- + +The default build setup for wpa_supplicant is to use MinGW and +cross-compiling from Linux to MinGW/Windows. It should also be +possible to build this under Windows using the MinGW tools, but that +is not tested nor supported and is likely to require some changes to +the Makefile unless cygwin is used. + + +Building wpa_supplicant with MSVC +--------------------------------- + +wpa_supplicant can be built with Microsoft Visual C++ compiler. This +has been tested with Microsoft Visual C++ Toolkit 2003 and Visual +Studio 2005 using the included nmake.mak as a Makefile for nmake. IDE +can also be used by creating a project that includes the files and +defines mentioned in nmake.mak. Example VS2005 solution and project +files are included in vs2005 subdirectory. This can be used as a +starting point for building the programs with VS2005 IDE. Visual Studio +2008 Express Edition is also able to use these project files. + +WinPcap development package is needed for the build and this can be +downloaded from http://www.winpcap.org/install/bin/WpdPack_4_0_2.zip. The +default nmake.mak expects this to be unpacked into C:\dev\WpdPack so +that Include and Lib directories are in this directory. The files can be +stored elsewhere as long as the WINPCAPDIR in nmake.mak is updated to +match with the selected directory. In case a project file in the IDE is +used, these Include and Lib directories need to be added to project +properties as additional include/library directories. + +OpenSSL source package can be downloaded from +http://www.openssl.org/source/openssl-0.9.8i.tar.gz and built and +installed following instructions in INSTALL.W32. Note that if EAP-FAST +support will be included in the wpa_supplicant, OpenSSL needs to be +patched to# support it openssl-0.9.8i-tls-extensions.patch. The example +nmake.mak file expects OpenSSL to be installed into C:\dev\openssl, but +this directory can be modified by changing OPENSSLDIR variable in +nmake.mak. + +If you do not need EAP-FAST support, you may also be able to use Win32 +binary installation package of OpenSSL from +http://www.slproweb.com/products/Win32OpenSSL.html instead of building +the library yourself. In this case, you will need to copy Include and +Lib directories in suitable directory, e.g., C:\dev\openssl for the +default nmake.mak. Copy {Win32OpenSSLRoot}\include into +C:\dev\openssl\include and make C:\dev\openssl\lib subdirectory with +files from {Win32OpenSSLRoot}\VC (i.e., libeay*.lib and ssleay*.lib). +This will end up using dynamically linked OpenSSL (i.e., .dll files are +needed) for it. Alternative, you can copy files from +{Win32OpenSSLRoot}\VC\static to create a static build (no OpenSSL .dll +files needed). + + +Building wpa_supplicant for cygwin +---------------------------------- + +wpa_supplicant can be built for cygwin by installing the needed +development packages for cygwin. This includes things like compiler, +make, openssl development package, etc. In addition, developer's pack +for WinPcap (WPdpack.zip) from +http://winpcap.polito.it/install/default.htm is needed. + +.config file should enable only one driver interface, +CONFIG_DRIVER_NDIS. In addition, include directories may need to be +added to match the system. An example configuration is available in +defconfig. The library and include files for WinPcap will either need +to be installed in compiler/linker default directories or their +location will need to be adding to .config when building +wpa_supplicant. + +Othen than this, the build should be more or less identical to Linux +version, i.e., just run make after having created .config file. An +additional tool, win_if_list.exe, can be built by running "make +win_if_list". + + +Building wpa_gui +---------------- + +wpa_gui uses Qt application framework from Trolltech. It can be built +with the open source version of Qt4 and MinGW. Following commands can +be used to build the binary in the Qt 4 Command Prompt: + +# go to the root directory of wpa_supplicant source code +cd wpa_gui-qt4 +qmake -o Makefile wpa_gui.pro +make +# the wpa_gui.exe binary is created into 'release' subdirectory + + +Using wpa_supplicant for Windows +-------------------------------- + +wpa_supplicant, wpa_cli, and wpa_gui behave more or less identically to +Linux version, so instructions in README and example wpa_supplicant.conf +should be applicable for most parts. In addition, there is another +version of wpa_supplicant, wpasvc.exe, which can be used as a Windows +service and which reads its configuration from registry instead of +text file. + +When using access points in "hidden SSID" mode, ap_scan=2 mode need to +be used (see wpa_supplicant.conf for more information). + +Windows NDIS/WinPcap uses quite long interface names, so some care +will be needed when starting wpa_supplicant. Alternatively, the +adapter description can be used as the interface name which may be +easier since it is usually in more human-readable +format. win_if_list.exe can be used to find out the proper interface +name. + +Example steps in starting up wpa_supplicant: + +# win_if_list.exe +ifname: \Device\NPF_GenericNdisWanAdapter +description: Generic NdisWan adapter + +ifname: \Device\NPF_{769E012B-FD17-4935-A5E3-8090C38E25D2} +description: Atheros Wireless Network Adapter (Microsoft's Packet Scheduler) + +ifname: \Device\NPF_{732546E7-E26C-48E3-9871-7537B020A211} +description: Intel 8255x-based Integrated Fast Ethernet (Microsoft's Packet Scheduler) + + +Since the example configuration used Atheros WLAN card, the middle one +is the correct interface in this case. The interface name for -i +command line option is the full string following "ifname:" (the +"\Device\NPF_" prefix can be removed). In other words, wpa_supplicant +would be started with the following command: + +# wpa_supplicant.exe -i'{769E012B-FD17-4935-A5E3-8090C38E25D2}' -c wpa_supplicant.conf -d + +-d optional enables some more debugging (use -dd for even more, if +needed). It can be left out if debugging information is not needed. + +With the alternative mechanism for selecting the interface, this +command has identical results in this case: + +# wpa_supplicant.exe -iAtheros -c wpa_supplicant.conf -d + + +Simple configuration example for WPA-PSK: + +#ap_scan=2 +ctrl_interface= +network={ + ssid="test" + key_mgmt=WPA-PSK + proto=WPA + pairwise=TKIP + psk="secret passphrase" +} + +(remove '#' from the comment out ap_scan line to enable mode in which +wpa_supplicant tries to associate with the SSID without doing +scanning; this allows APs with hidden SSIDs to be used) + + +wpa_cli.exe and wpa_gui.exe can be used to interact with the +wpa_supplicant.exe program in the same way as with Linux. Note that +ctrl_interface is using UNIX domain sockets when built for cygwin, but +the native build for Windows uses named pipes and the contents of the +ctrl_interface configuration item is used to control access to the +interface. Anyway, this variable has to be included in the configuration +to enable the control interface. + + +Example SDDL string formats: + +(local admins group has permission, but nobody else): + +ctrl_interface=SDDL=D:(A;;GA;;;BA) + +("A" == "access allowed", "GA" == GENERIC_ALL == all permissions, and +"BA" == "builtin administrators" == the local admins. The empty fields +are for flags and object GUIDs, none of which should be required in this +case.) + +(local admins and the local "power users" group have permissions, +but nobody else): + +ctrl_interface=SDDL=D:(A;;GA;;;BA)(A;;GA;;;PU) + +(One ACCESS_ALLOWED ACE for GENERIC_ALL for builtin administrators, and +one ACCESS_ALLOWED ACE for GENERIC_ALL for power users.) + +(close to wide open, but you have to be a valid user on +the machine): + +ctrl_interface=SDDL=D:(A;;GA;;;AU) + +(One ACCESS_ALLOWED ACE for GENERIC_ALL for the "authenticated users" +group.) + +This one would allow absolutely everyone (including anonymous +users) -- this is *not* recommended, since named pipes can be attached +to from anywhere on the network (i.e. there's no "this machine only" +like there is with 127.0.0.1 sockets): + +ctrl_interface=SDDL=D:(A;;GA;;;BU)(A;;GA;;;AN) + +(BU == "builtin users", "AN" == "anonymous") + +See also [1] for the format of ACEs, and [2] for the possible strings +that can be used for principal names. + +[1] +http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthz/security/ace_strings.asp +[2] +http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthz/security/sid_strings.asp + + +Starting wpa_supplicant as a Windows service (wpasvc.exe) +--------------------------------------------------------- + +wpa_supplicant can be started as a Windows service by using wpasvc.exe +program that is alternative build of wpa_supplicant.exe. Most of the +core functionality of wpasvc.exe is identical to wpa_supplicant.exe, +but it is using Windows registry for configuration information instead +of a text file and command line parameters. In addition, it can be +registered as a service that can be started automatically or manually +like any other Windows service. + +The root of wpa_supplicant configuration in registry is +HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant. This level includes global +parameters and a 'interfaces' subkey with all the interface configuration +(adapter to confname mapping). Each such mapping is a subkey that has +'adapter', 'config', and 'ctrl_interface' values. + +This program can be run either as a normal command line application, +e.g., for debugging, with 'wpasvc.exe app' or as a Windows service. +Service need to be registered with 'wpasvc.exe reg <full path to +wpasvc.exe>'. Alternatively, 'wpasvc.exe reg' can be used to register +the service with the current location of wpasvc.exe. After this, wpasvc +can be started like any other Windows service (e.g., 'net start wpasvc') +or it can be configured to start automatically through the Services tool +in administrative tasks. The service can be unregistered with +'wpasvc.exe unreg'. + +If the service is set to start during system bootup to make the +network connection available before any user has logged in, there may +be a long (half a minute or so) delay in starting up wpa_supplicant +due to WinPcap needing a driver called "Network Monitor Driver" which +is started by default on demand. + +To speed up wpa_supplicant start during system bootup, "Network +Monitor Driver" can be configured to be started sooner by setting its +startup type to System instead of the default Demand. To do this, open +up Device Manager, select Show Hidden Devices, expand the "Non +Plug-and-Play devices" branch, double click "Network Monitor Driver", +go to the Driver tab, and change the Demand setting to System instead. + +Configuration data is in HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs +key. Each configuration profile has its own key under this. In terms of text +files, each profile would map to a separate text file with possibly multiple +networks. Under each profile, there is a networks key that lists all +networks as a subkey. Each network has set of values in the same way as +network block in the configuration file. In addition, blobs subkey has +possible blobs as values. + +HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\networks\0000 + ssid="example" + key_mgmt=WPA-PSK + +See win_example.reg for an example on how to setup wpasvc.exe +parameters in registry. It can also be imported to registry as a +starting point for the configuration. + + + +License information for third party software used in this product: + + OpenSSL License + --------------- + +/* ==================================================================== + * Copyright (c) 1998-2004 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED 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 OpenSSL PROJECT OR + * ITS 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. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + + Original SSLeay License + ----------------------- + +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC 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 THE AUTHOR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + + + + Qt Open Source Edition + ---------------------- + +The Qt GUI Toolkit is Copyright (C) 1994-2007 Trolltech ASA. +Qt Open Source Edition is licensed under GPL version 2. + +Source code for the library is available at +http://w1.fi/wpa_supplicant/qt4/qt-win-opensource-src-4.3.3.zip diff --git a/wpa_supplicant/blacklist.c b/wpa_supplicant/blacklist.c new file mode 100644 index 000000000000..4ffb22097370 --- /dev/null +++ b/wpa_supplicant/blacklist.c @@ -0,0 +1,133 @@ +/* + * wpa_supplicant - Temporary BSSID blacklist + * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "wpa_supplicant_i.h" +#include "blacklist.h" + +/** + * wpa_blacklist_get - Get the blacklist entry for a BSSID + * @wpa_s: Pointer to wpa_supplicant data + * @bssid: BSSID + * Returns: Matching blacklist entry for the BSSID or %NULL if not found + */ +struct wpa_blacklist * wpa_blacklist_get(struct wpa_supplicant *wpa_s, + const u8 *bssid) +{ + struct wpa_blacklist *e; + + e = wpa_s->blacklist; + while (e) { + if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0) + return e; + e = e->next; + } + + return NULL; +} + + +/** + * wpa_blacklist_add - Add an BSSID to the blacklist + * @wpa_s: Pointer to wpa_supplicant data + * @bssid: BSSID to be added to the blacklist + * Returns: 0 on success, -1 on failure + * + * This function adds the specified BSSID to the blacklist or increases the + * blacklist count if the BSSID was already listed. It should be called when + * an association attempt fails either due to the selected BSS rejecting + * association or due to timeout. + * + * This blacklist is used to force %wpa_supplicant to go through all available + * BSSes before retrying to associate with an BSS that rejected or timed out + * association. It does not prevent the listed BSS from being used; it only + * changes the order in which they are tried. + */ +int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid) +{ + struct wpa_blacklist *e; + + e = wpa_blacklist_get(wpa_s, bssid); + if (e) { + e->count++; + wpa_printf(MSG_DEBUG, "BSSID " MACSTR " blacklist count " + "incremented to %d", + MAC2STR(bssid), e->count); + return 0; + } + + e = os_zalloc(sizeof(*e)); + if (e == NULL) + return -1; + os_memcpy(e->bssid, bssid, ETH_ALEN); + e->count = 1; + e->next = wpa_s->blacklist; + wpa_s->blacklist = e; + wpa_printf(MSG_DEBUG, "Added BSSID " MACSTR " into blacklist", + MAC2STR(bssid)); + + return 0; +} + + +/** + * wpa_blacklist_del - Remove an BSSID from the blacklist + * @wpa_s: Pointer to wpa_supplicant data + * @bssid: BSSID to be removed from the blacklist + * Returns: 0 on success, -1 on failure + */ +int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid) +{ + struct wpa_blacklist *e, *prev = NULL; + + e = wpa_s->blacklist; + while (e) { + if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0) { + if (prev == NULL) { + wpa_s->blacklist = e->next; + } else { + prev->next = e->next; + } + wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR " from " + "blacklist", MAC2STR(bssid)); + os_free(e); + return 0; + } + prev = e; + e = e->next; + } + return -1; +} + + +/** + * wpa_blacklist_clear - Clear the blacklist of all entries + * @wpa_s: Pointer to wpa_supplicant data + */ +void wpa_blacklist_clear(struct wpa_supplicant *wpa_s) +{ + struct wpa_blacklist *e, *prev; + + e = wpa_s->blacklist; + wpa_s->blacklist = NULL; + while (e) { + prev = e; + e = e->next; + wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR " from " + "blacklist (clear)", MAC2STR(prev->bssid)); + os_free(prev); + } +} diff --git a/wpa_supplicant/blacklist.h b/wpa_supplicant/blacklist.h new file mode 100644 index 000000000000..de280cd71568 --- /dev/null +++ b/wpa_supplicant/blacklist.h @@ -0,0 +1,30 @@ +/* + * wpa_supplicant - Temporary BSSID blacklist + * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef BLACKLIST_H +#define BLACKLIST_H + +struct wpa_blacklist { + struct wpa_blacklist *next; + u8 bssid[ETH_ALEN]; + int count; +}; + +struct wpa_blacklist * wpa_blacklist_get(struct wpa_supplicant *wpa_s, + const u8 *bssid); +int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid); +int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid); +void wpa_blacklist_clear(struct wpa_supplicant *wpa_s); + +#endif /* BLACKLIST_H */ diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c new file mode 100644 index 000000000000..9a7937417df1 --- /dev/null +++ b/wpa_supplicant/config.c @@ -0,0 +1,1978 @@ +/* + * WPA Supplicant / Configuration parser and common functions + * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "wpa.h" +#include "sha1.h" +#include "eap_peer/eap.h" +#include "config.h" + + +#if !defined(CONFIG_CTRL_IFACE) && defined(CONFIG_NO_CONFIG_WRITE) +#define NO_CONFIG_WRITE +#endif + +/* + * Structure for network configuration parsing. This data is used to implement + * a generic parser for each network block variable. The table of configuration + * variables is defined below in this file (ssid_fields[]). + */ +struct parse_data { + /* Configuration variable name */ + char *name; + + /* Parser function for this variable */ + int (*parser)(const struct parse_data *data, struct wpa_ssid *ssid, + int line, const char *value); + +#ifndef NO_CONFIG_WRITE + /* Writer function (i.e., to get the variable in text format from + * internal presentation). */ + char * (*writer)(const struct parse_data *data, struct wpa_ssid *ssid); +#endif /* NO_CONFIG_WRITE */ + + /* Variable specific parameters for the parser. */ + void *param1, *param2, *param3, *param4; + + /* 0 = this variable can be included in debug output and ctrl_iface + * 1 = this variable contains key/private data and it must not be + * included in debug output unless explicitly requested. In + * addition, this variable will not be readable through the + * ctrl_iface. + */ + int key_data; +}; + + +static char * wpa_config_parse_string(const char *value, size_t *len) +{ + if (*value == '"') { + const char *pos; + char *str; + value++; + pos = os_strrchr(value, '"'); + if (pos == NULL || pos[1] != '\0') + return NULL; + *len = pos - value; + str = os_malloc(*len + 1); + if (str == NULL) + return NULL; + os_memcpy(str, value, *len); + str[*len] = '\0'; + return str; + } else { + u8 *str; + size_t tlen, hlen = os_strlen(value); + if (hlen & 1) + return NULL; + tlen = hlen / 2; + str = os_malloc(tlen + 1); + if (str == NULL) + return NULL; + if (hexstr2bin(value, str, tlen)) { + os_free(str); + return NULL; + } + str[tlen] = '\0'; + *len = tlen; + return (char *) str; + } +} + + +static int wpa_config_parse_str(const struct parse_data *data, + struct wpa_ssid *ssid, + int line, const char *value) +{ + size_t res_len, *dst_len; + char **dst, *tmp; + + if (os_strcmp(value, "NULL") == 0) { + wpa_printf(MSG_DEBUG, "Unset configuration string '%s'", + data->name); + tmp = NULL; + res_len = 0; + goto set; + } + + tmp = wpa_config_parse_string(value, &res_len); + if (tmp == NULL) { + wpa_printf(MSG_ERROR, "Line %d: failed to parse %s '%s'.", + line, data->name, + data->key_data ? "[KEY DATA REMOVED]" : value); + return -1; + } + + if (data->key_data) { + wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name, + (u8 *) tmp, res_len); + } else { + wpa_hexdump_ascii(MSG_MSGDUMP, data->name, + (u8 *) tmp, res_len); + } + + if (data->param3 && res_len < (size_t) data->param3) { + wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu " + "min_len=%ld)", line, data->name, + (unsigned long) res_len, (long) data->param3); + os_free(tmp); + return -1; + } + + if (data->param4 && res_len > (size_t) data->param4) { + wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu " + "max_len=%ld)", line, data->name, + (unsigned long) res_len, (long) data->param4); + os_free(tmp); + return -1; + } + +set: + dst = (char **) (((u8 *) ssid) + (long) data->param1); + dst_len = (size_t *) (((u8 *) ssid) + (long) data->param2); + os_free(*dst); + *dst = tmp; + if (data->param2) + *dst_len = res_len; + + return 0; +} + + +#ifndef NO_CONFIG_WRITE +static int is_hex(const u8 *data, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) { + if (data[i] < 32 || data[i] >= 127) + return 1; + } + return 0; +} + + +static char * wpa_config_write_string_ascii(const u8 *value, size_t len) +{ + char *buf; + + buf = os_malloc(len + 3); + if (buf == NULL) + return NULL; + buf[0] = '"'; + os_memcpy(buf + 1, value, len); + buf[len + 1] = '"'; + buf[len + 2] = '\0'; + + return buf; +} + + +static char * wpa_config_write_string_hex(const u8 *value, size_t len) +{ + char *buf; + + buf = os_zalloc(2 * len + 1); + if (buf == NULL) + return NULL; + wpa_snprintf_hex(buf, 2 * len + 1, value, len); + + return buf; +} + + +static char * wpa_config_write_string(const u8 *value, size_t len) +{ + if (value == NULL) + return NULL; + + if (is_hex(value, len)) + return wpa_config_write_string_hex(value, len); + else + return wpa_config_write_string_ascii(value, len); +} + + +static char * wpa_config_write_str(const struct parse_data *data, + struct wpa_ssid *ssid) +{ + size_t len; + char **src; + + src = (char **) (((u8 *) ssid) + (long) data->param1); + if (*src == NULL) + return NULL; + + if (data->param2) + len = *((size_t *) (((u8 *) ssid) + (long) data->param2)); + else + len = os_strlen(*src); + + return wpa_config_write_string((const u8 *) *src, len); +} +#endif /* NO_CONFIG_WRITE */ + + +static int wpa_config_parse_int(const struct parse_data *data, + struct wpa_ssid *ssid, + int line, const char *value) +{ + int *dst; + + dst = (int *) (((u8 *) ssid) + (long) data->param1); + *dst = atoi(value); + wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst); + + if (data->param3 && *dst < (long) data->param3) { + wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d " + "min_value=%ld)", line, data->name, *dst, + (long) data->param3); + *dst = (long) data->param3; + return -1; + } + + if (data->param4 && *dst > (long) data->param4) { + wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d " + "max_value=%ld)", line, data->name, *dst, + (long) data->param4); + *dst = (long) data->param4; + return -1; + } + + return 0; +} + + +#ifndef NO_CONFIG_WRITE +static char * wpa_config_write_int(const struct parse_data *data, + struct wpa_ssid *ssid) +{ + int *src, res; + char *value; + + src = (int *) (((u8 *) ssid) + (long) data->param1); + + value = os_malloc(20); + if (value == NULL) + return NULL; + res = os_snprintf(value, 20, "%d", *src); + if (res < 0 || res >= 20) { + os_free(value); + return NULL; + } + value[20 - 1] = '\0'; + return value; +} +#endif /* NO_CONFIG_WRITE */ + + +static int wpa_config_parse_bssid(const struct parse_data *data, + struct wpa_ssid *ssid, int line, + const char *value) +{ + if (hwaddr_aton(value, ssid->bssid)) { + wpa_printf(MSG_ERROR, "Line %d: Invalid BSSID '%s'.", + line, value); + return -1; + } + ssid->bssid_set = 1; + wpa_hexdump(MSG_MSGDUMP, "BSSID", ssid->bssid, ETH_ALEN); + return 0; +} + + +#ifndef NO_CONFIG_WRITE +static char * wpa_config_write_bssid(const struct parse_data *data, + struct wpa_ssid *ssid) +{ + char *value; + int res; + + if (!ssid->bssid_set) + return NULL; + + value = os_malloc(20); + if (value == NULL) + return NULL; + res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->bssid)); + if (res < 0 || res >= 20) { + os_free(value); + return NULL; + } + value[20 - 1] = '\0'; + return value; +} +#endif /* NO_CONFIG_WRITE */ + + +static int wpa_config_parse_psk(const struct parse_data *data, + struct wpa_ssid *ssid, int line, + const char *value) +{ + if (*value == '"') { +#ifndef CONFIG_NO_PBKDF2 + const char *pos; + size_t len; + + value++; + pos = os_strrchr(value, '"'); + if (pos) + len = pos - value; + else + len = os_strlen(value); + if (len < 8 || len > 63) { + wpa_printf(MSG_ERROR, "Line %d: Invalid passphrase " + "length %lu (expected: 8..63) '%s'.", + line, (unsigned long) len, value); + return -1; + } + wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)", + (u8 *) value, len); + if (ssid->passphrase && os_strlen(ssid->passphrase) == len && + os_memcmp(ssid->passphrase, value, len) == 0) + return 0; + ssid->psk_set = 0; + os_free(ssid->passphrase); + ssid->passphrase = os_malloc(len + 1); + if (ssid->passphrase == NULL) + return -1; + os_memcpy(ssid->passphrase, value, len); + ssid->passphrase[len] = '\0'; + return 0; +#else /* CONFIG_NO_PBKDF2 */ + wpa_printf(MSG_ERROR, "Line %d: ASCII passphrase not " + "supported.", line); + return -1; +#endif /* CONFIG_NO_PBKDF2 */ + } + + if (hexstr2bin(value, ssid->psk, PMK_LEN) || + value[PMK_LEN * 2] != '\0') { + wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.", + line, value); + return -1; + } + + os_free(ssid->passphrase); + ssid->passphrase = NULL; + + ssid->psk_set = 1; + wpa_hexdump_key(MSG_MSGDUMP, "PSK", ssid->psk, PMK_LEN); + return 0; +} + + +#ifndef NO_CONFIG_WRITE +static char * wpa_config_write_psk(const struct parse_data *data, + struct wpa_ssid *ssid) +{ + if (ssid->passphrase) + return wpa_config_write_string_ascii( + (const u8 *) ssid->passphrase, + os_strlen(ssid->passphrase)); + + if (ssid->psk_set) + return wpa_config_write_string_hex(ssid->psk, PMK_LEN); + + return NULL; +} +#endif /* NO_CONFIG_WRITE */ + + +static int wpa_config_parse_proto(const struct parse_data *data, + struct wpa_ssid *ssid, int line, + const char *value) +{ + int val = 0, last, errors = 0; + 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") == 0) + val |= WPA_PROTO_WPA; + else if (os_strcmp(start, "RSN") == 0 || + os_strcmp(start, "WPA2") == 0) + val |= WPA_PROTO_RSN; + else { + wpa_printf(MSG_ERROR, "Line %d: invalid proto '%s'", + line, start); + errors++; + } + + if (last) + break; + start = end + 1; + } + os_free(buf); + + if (val == 0) { + wpa_printf(MSG_ERROR, + "Line %d: no proto values configured.", line); + errors++; + } + + wpa_printf(MSG_MSGDUMP, "proto: 0x%x", val); + ssid->proto = val; + return errors ? -1 : 0; +} + + +#ifndef NO_CONFIG_WRITE +static char * wpa_config_write_proto(const struct parse_data *data, + struct wpa_ssid *ssid) +{ + int first = 1, ret; + char *buf, *pos, *end; + + pos = buf = os_zalloc(10); + if (buf == NULL) + return NULL; + end = buf + 10; + + if (ssid->proto & WPA_PROTO_WPA) { + ret = os_snprintf(pos, end - pos, "%sWPA", first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return buf; + pos += ret; + first = 0; + } + + if (ssid->proto & WPA_PROTO_RSN) { + ret = os_snprintf(pos, end - pos, "%sRSN", first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return buf; + pos += ret; + first = 0; + } + + return buf; +} +#endif /* NO_CONFIG_WRITE */ + + +static int wpa_config_parse_key_mgmt(const struct parse_data *data, + struct wpa_ssid *ssid, int line, + const char *value) +{ + int val = 0, last, errors = 0; + 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; + else if (os_strcmp(start, "IEEE8021X") == 0) + val |= WPA_KEY_MGMT_IEEE8021X_NO_WPA; + else if (os_strcmp(start, "NONE") == 0) + val |= WPA_KEY_MGMT_NONE; + else if (os_strcmp(start, "WPA-NONE") == 0) + val |= WPA_KEY_MGMT_WPA_NONE; +#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 */ +#ifdef CONFIG_WPS + else if (os_strcmp(start, "WPS") == 0) + val |= WPA_KEY_MGMT_WPS; +#endif /* CONFIG_WPS */ + else { + wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'", + line, start); + errors++; + } + + if (last) + break; + start = end + 1; + } + os_free(buf); + + if (val == 0) { + wpa_printf(MSG_ERROR, + "Line %d: no key_mgmt values configured.", line); + errors++; + } + + wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", val); + ssid->key_mgmt = val; + return errors ? -1 : 0; +} + + +#ifndef NO_CONFIG_WRITE +static char * wpa_config_write_key_mgmt(const struct parse_data *data, + struct wpa_ssid *ssid) +{ + char *buf, *pos, *end; + int ret; + + pos = buf = os_zalloc(50); + if (buf == NULL) + return NULL; + end = buf + 50; + + if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) { + ret = os_snprintf(pos, end - pos, "%sWPA-PSK", + pos == buf ? "" : " "); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return buf; + } + pos += ret; + } + + if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X) { + ret = os_snprintf(pos, end - pos, "%sWPA-EAP", + pos == buf ? "" : " "); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return buf; + } + pos += ret; + } + + if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) { + ret = os_snprintf(pos, end - pos, "%sIEEE8021X", + pos == buf ? "" : " "); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return buf; + } + pos += ret; + } + + if (ssid->key_mgmt & WPA_KEY_MGMT_NONE) { + ret = os_snprintf(pos, end - pos, "%sNONE", + pos == buf ? "" : " "); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return buf; + } + pos += ret; + } + + if (ssid->key_mgmt & WPA_KEY_MGMT_WPA_NONE) { + ret = os_snprintf(pos, end - pos, "%sWPA-NONE", + pos == buf ? "" : " "); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return buf; + } + pos += ret; + } + +#ifdef CONFIG_IEEE80211R + if (ssid->key_mgmt & WPA_KEY_MGMT_FT_PSK) + pos += os_snprintf(pos, end - pos, "%sFT-PSK", + pos == buf ? "" : " "); + + if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) + pos += os_snprintf(pos, end - pos, "%sFT-EAP", + pos == buf ? "" : " "); +#endif /* CONFIG_IEEE80211R */ + +#ifdef CONFIG_IEEE80211W + if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) + pos += os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256", + pos == buf ? "" : " "); + + if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) + pos += os_snprintf(pos, end - pos, "%sWPA-EAP-SHA256", + pos == buf ? "" : " "); +#endif /* CONFIG_IEEE80211W */ + +#ifdef CONFIG_WPS + if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) + pos += os_snprintf(pos, end - pos, "%sWPS", + pos == buf ? "" : " "); +#endif /* CONFIG_WPS */ + + return buf; +} +#endif /* NO_CONFIG_WRITE */ + + +static int wpa_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; +} + + +#ifndef NO_CONFIG_WRITE +static char * wpa_config_write_cipher(int cipher) +{ + char *buf, *pos, *end; + int ret; + + pos = buf = os_zalloc(50); + if (buf == NULL) + return NULL; + end = buf + 50; + + if (cipher & WPA_CIPHER_CCMP) { + ret = os_snprintf(pos, end - pos, "%sCCMP", + pos == buf ? "" : " "); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return buf; + } + pos += ret; + } + + if (cipher & WPA_CIPHER_TKIP) { + ret = os_snprintf(pos, end - pos, "%sTKIP", + pos == buf ? "" : " "); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return buf; + } + pos += ret; + } + + if (cipher & WPA_CIPHER_WEP104) { + ret = os_snprintf(pos, end - pos, "%sWEP104", + pos == buf ? "" : " "); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return buf; + } + pos += ret; + } + + if (cipher & WPA_CIPHER_WEP40) { + ret = os_snprintf(pos, end - pos, "%sWEP40", + pos == buf ? "" : " "); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return buf; + } + pos += ret; + } + + if (cipher & WPA_CIPHER_NONE) { + ret = os_snprintf(pos, end - pos, "%sNONE", + pos == buf ? "" : " "); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return buf; + } + pos += ret; + } + + return buf; +} +#endif /* NO_CONFIG_WRITE */ + + +static int wpa_config_parse_pairwise(const struct parse_data *data, + struct wpa_ssid *ssid, int line, + const char *value) +{ + int val; + val = wpa_config_parse_cipher(line, value); + if (val == -1) + return -1; + if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE)) { + wpa_printf(MSG_ERROR, "Line %d: not allowed pairwise cipher " + "(0x%x).", line, val); + return -1; + } + + wpa_printf(MSG_MSGDUMP, "pairwise: 0x%x", val); + ssid->pairwise_cipher = val; + return 0; +} + + +#ifndef NO_CONFIG_WRITE +static char * wpa_config_write_pairwise(const struct parse_data *data, + struct wpa_ssid *ssid) +{ + return wpa_config_write_cipher(ssid->pairwise_cipher); +} +#endif /* NO_CONFIG_WRITE */ + + +static int wpa_config_parse_group(const struct parse_data *data, + struct wpa_ssid *ssid, int line, + const char *value) +{ + int val; + val = wpa_config_parse_cipher(line, value); + if (val == -1) + return -1; + if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_WEP104 | + WPA_CIPHER_WEP40)) { + wpa_printf(MSG_ERROR, "Line %d: not allowed group cipher " + "(0x%x).", line, val); + return -1; + } + + wpa_printf(MSG_MSGDUMP, "group: 0x%x", val); + ssid->group_cipher = val; + return 0; +} + + +#ifndef NO_CONFIG_WRITE +static char * wpa_config_write_group(const struct parse_data *data, + struct wpa_ssid *ssid) +{ + return wpa_config_write_cipher(ssid->group_cipher); +} +#endif /* NO_CONFIG_WRITE */ + + +static int wpa_config_parse_auth_alg(const struct parse_data *data, + struct wpa_ssid *ssid, int line, + const char *value) +{ + int val = 0, last, errors = 0; + 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, "OPEN") == 0) + val |= WPA_AUTH_ALG_OPEN; + else if (os_strcmp(start, "SHARED") == 0) + val |= WPA_AUTH_ALG_SHARED; + else if (os_strcmp(start, "LEAP") == 0) + val |= WPA_AUTH_ALG_LEAP; + else { + wpa_printf(MSG_ERROR, "Line %d: invalid auth_alg '%s'", + line, start); + errors++; + } + + if (last) + break; + start = end + 1; + } + os_free(buf); + + if (val == 0) { + wpa_printf(MSG_ERROR, + "Line %d: no auth_alg values configured.", line); + errors++; + } + + wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", val); + ssid->auth_alg = val; + return errors ? -1 : 0; +} + + +#ifndef NO_CONFIG_WRITE +static char * wpa_config_write_auth_alg(const struct parse_data *data, + struct wpa_ssid *ssid) +{ + char *buf, *pos, *end; + int ret; + + pos = buf = os_zalloc(30); + if (buf == NULL) + return NULL; + end = buf + 30; + + if (ssid->auth_alg & WPA_AUTH_ALG_OPEN) { + ret = os_snprintf(pos, end - pos, "%sOPEN", + pos == buf ? "" : " "); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return buf; + } + pos += ret; + } + + if (ssid->auth_alg & WPA_AUTH_ALG_SHARED) { + ret = os_snprintf(pos, end - pos, "%sSHARED", + pos == buf ? "" : " "); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return buf; + } + pos += ret; + } + + if (ssid->auth_alg & WPA_AUTH_ALG_LEAP) { + ret = os_snprintf(pos, end - pos, "%sLEAP", + pos == buf ? "" : " "); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return buf; + } + pos += ret; + } + + return buf; +} +#endif /* NO_CONFIG_WRITE */ + + +#ifdef IEEE8021X_EAPOL +static int wpa_config_parse_eap(const struct parse_data *data, + struct wpa_ssid *ssid, int line, + const char *value) +{ + int last, errors = 0; + char *start, *end, *buf; + struct eap_method_type *methods = NULL, *tmp; + size_t num_methods = 0; + + 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'; + tmp = methods; + methods = os_realloc(methods, + (num_methods + 1) * sizeof(*methods)); + if (methods == NULL) { + os_free(tmp); + os_free(buf); + return -1; + } + methods[num_methods].method = eap_peer_get_type( + start, &methods[num_methods].vendor); + if (methods[num_methods].vendor == EAP_VENDOR_IETF && + methods[num_methods].method == EAP_TYPE_NONE) { + wpa_printf(MSG_ERROR, "Line %d: unknown EAP method " + "'%s'", line, start); + wpa_printf(MSG_ERROR, "You may need to add support for" + " this EAP method during wpa_supplicant\n" + "build time configuration.\n" + "See README for more information."); + errors++; + } else if (methods[num_methods].vendor == EAP_VENDOR_IETF && + methods[num_methods].method == EAP_TYPE_LEAP) + ssid->leap++; + else + ssid->non_leap++; + num_methods++; + if (last) + break; + start = end + 1; + } + os_free(buf); + + tmp = methods; + methods = os_realloc(methods, (num_methods + 1) * sizeof(*methods)); + if (methods == NULL) { + os_free(tmp); + return -1; + } + methods[num_methods].vendor = EAP_VENDOR_IETF; + methods[num_methods].method = EAP_TYPE_NONE; + num_methods++; + + wpa_hexdump(MSG_MSGDUMP, "eap methods", + (u8 *) methods, num_methods * sizeof(*methods)); + ssid->eap.eap_methods = methods; + return errors ? -1 : 0; +} + + +static char * wpa_config_write_eap(const struct parse_data *data, + struct wpa_ssid *ssid) +{ + int i, ret; + char *buf, *pos, *end; + const struct eap_method_type *eap_methods = ssid->eap.eap_methods; + const char *name; + + if (eap_methods == NULL) + return NULL; + + pos = buf = os_zalloc(100); + if (buf == NULL) + return NULL; + end = buf + 100; + + for (i = 0; eap_methods[i].vendor != EAP_VENDOR_IETF || + eap_methods[i].method != EAP_TYPE_NONE; i++) { + name = eap_get_name(eap_methods[i].vendor, + eap_methods[i].method); + if (name) { + ret = os_snprintf(pos, end - pos, "%s%s", + pos == buf ? "" : " ", name); + if (ret < 0 || ret >= end - pos) + break; + pos += ret; + } + } + + end[-1] = '\0'; + + return buf; +} + + +static int wpa_config_parse_password(const struct parse_data *data, + struct wpa_ssid *ssid, int line, + const char *value) +{ + u8 *hash; + + if (os_strcmp(value, "NULL") == 0) { + wpa_printf(MSG_DEBUG, "Unset configuration string 'password'"); + os_free(ssid->eap.password); + ssid->eap.password = NULL; + ssid->eap.password_len = 0; + return 0; + } + + if (os_strncmp(value, "hash:", 5) != 0) { + char *tmp; + size_t res_len; + + tmp = wpa_config_parse_string(value, &res_len); + if (tmp == NULL) { + wpa_printf(MSG_ERROR, "Line %d: failed to parse " + "password.", line); + return -1; + } + wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name, + (u8 *) tmp, res_len); + + os_free(ssid->eap.password); + ssid->eap.password = (u8 *) tmp; + ssid->eap.password_len = res_len; + ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH; + + return 0; + } + + + /* NtPasswordHash: hash:<32 hex digits> */ + if (os_strlen(value + 5) != 2 * 16) { + wpa_printf(MSG_ERROR, "Line %d: Invalid password hash length " + "(expected 32 hex digits)", line); + return -1; + } + + hash = os_malloc(16); + if (hash == NULL) + return -1; + + if (hexstr2bin(value + 5, hash, 16)) { + os_free(hash); + wpa_printf(MSG_ERROR, "Line %d: Invalid password hash", line); + return -1; + } + + wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16); + + os_free(ssid->eap.password); + ssid->eap.password = hash; + ssid->eap.password_len = 16; + ssid->eap.flags |= EAP_CONFIG_FLAGS_PASSWORD_NTHASH; + + return 0; +} + + +static char * wpa_config_write_password(const struct parse_data *data, + struct wpa_ssid *ssid) +{ + char *buf; + + if (ssid->eap.password == NULL) + return NULL; + + if (!(ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) { + return wpa_config_write_string( + ssid->eap.password, ssid->eap.password_len); + } + + buf = os_malloc(5 + 32 + 1); + if (buf == NULL) + return NULL; + + os_memcpy(buf, "hash:", 5); + wpa_snprintf_hex(buf + 5, 32 + 1, ssid->eap.password, 16); + + return buf; +} +#endif /* IEEE8021X_EAPOL */ + + +static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line, + const char *value, int idx) +{ + char *buf, title[20]; + int res; + + buf = wpa_config_parse_string(value, len); + if (buf == NULL) { + wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key %d '%s'.", + line, idx, value); + return -1; + } + if (*len > MAX_WEP_KEY_LEN) { + wpa_printf(MSG_ERROR, "Line %d: Too long WEP key %d '%s'.", + line, idx, value); + os_free(buf); + return -1; + } + os_memcpy(key, buf, *len); + os_free(buf); + res = os_snprintf(title, sizeof(title), "wep_key%d", idx); + if (res >= 0 && (size_t) res < sizeof(title)) + wpa_hexdump_key(MSG_MSGDUMP, title, key, *len); + return 0; +} + + +static int wpa_config_parse_wep_key0(const struct parse_data *data, + struct wpa_ssid *ssid, int line, + const char *value) +{ + return wpa_config_parse_wep_key(ssid->wep_key[0], + &ssid->wep_key_len[0], line, + value, 0); +} + + +static int wpa_config_parse_wep_key1(const struct parse_data *data, + struct wpa_ssid *ssid, int line, + const char *value) +{ + return wpa_config_parse_wep_key(ssid->wep_key[1], + &ssid->wep_key_len[1], line, + value, 1); +} + + +static int wpa_config_parse_wep_key2(const struct parse_data *data, + struct wpa_ssid *ssid, int line, + const char *value) +{ + return wpa_config_parse_wep_key(ssid->wep_key[2], + &ssid->wep_key_len[2], line, + value, 2); +} + + +static int wpa_config_parse_wep_key3(const struct parse_data *data, + struct wpa_ssid *ssid, int line, + const char *value) +{ + return wpa_config_parse_wep_key(ssid->wep_key[3], + &ssid->wep_key_len[3], line, + value, 3); +} + + +#ifndef NO_CONFIG_WRITE +static char * wpa_config_write_wep_key(struct wpa_ssid *ssid, int idx) +{ + if (ssid->wep_key_len[idx] == 0) + return NULL; + return wpa_config_write_string(ssid->wep_key[idx], + ssid->wep_key_len[idx]); +} + + +static char * wpa_config_write_wep_key0(const struct parse_data *data, + struct wpa_ssid *ssid) +{ + return wpa_config_write_wep_key(ssid, 0); +} + + +static char * wpa_config_write_wep_key1(const struct parse_data *data, + struct wpa_ssid *ssid) +{ + return wpa_config_write_wep_key(ssid, 1); +} + + +static char * wpa_config_write_wep_key2(const struct parse_data *data, + struct wpa_ssid *ssid) +{ + return wpa_config_write_wep_key(ssid, 2); +} + + +static char * wpa_config_write_wep_key3(const struct parse_data *data, + struct wpa_ssid *ssid) +{ + return wpa_config_write_wep_key(ssid, 3); +} +#endif /* NO_CONFIG_WRITE */ + + +/* Helper macros for network block parser */ + +#ifdef OFFSET +#undef OFFSET +#endif /* OFFSET */ +/* OFFSET: Get offset of a variable within the wpa_ssid structure */ +#define OFFSET(v) ((void *) &((struct wpa_ssid *) 0)->v) + +/* STR: Define a string variable for an ASCII string; f = field name */ +#ifdef NO_CONFIG_WRITE +#define _STR(f) #f, wpa_config_parse_str, OFFSET(f) +#define _STRe(f) #f, wpa_config_parse_str, OFFSET(eap.f) +#else /* NO_CONFIG_WRITE */ +#define _STR(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(f) +#define _STRe(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(eap.f) +#endif /* NO_CONFIG_WRITE */ +#define STR(f) _STR(f), NULL, NULL, NULL, 0 +#define STRe(f) _STRe(f), NULL, NULL, NULL, 0 +#define STR_KEY(f) _STR(f), NULL, NULL, NULL, 1 +#define STR_KEYe(f) _STRe(f), NULL, NULL, NULL, 1 + +/* STR_LEN: Define a string variable with a separate variable for storing the + * data length. Unlike STR(), this can be used to store arbitrary binary data + * (i.e., even nul termination character). */ +#define _STR_LEN(f) _STR(f), OFFSET(f ## _len) +#define _STR_LENe(f) _STRe(f), OFFSET(eap.f ## _len) +#define STR_LEN(f) _STR_LEN(f), NULL, NULL, 0 +#define STR_LENe(f) _STR_LENe(f), NULL, NULL, 0 +#define STR_LEN_KEY(f) _STR_LEN(f), NULL, NULL, 1 + +/* STR_RANGE: Like STR_LEN(), but with minimum and maximum allowed length + * explicitly specified. */ +#define _STR_RANGE(f, min, max) _STR_LEN(f), (void *) (min), (void *) (max) +#define STR_RANGE(f, min, max) _STR_RANGE(f, min, max), 0 +#define STR_RANGE_KEY(f, min, max) _STR_RANGE(f, min, max), 1 + +#ifdef NO_CONFIG_WRITE +#define _INT(f) #f, wpa_config_parse_int, OFFSET(f), (void *) 0 +#define _INTe(f) #f, wpa_config_parse_int, OFFSET(eap.f), (void *) 0 +#else /* NO_CONFIG_WRITE */ +#define _INT(f) #f, wpa_config_parse_int, wpa_config_write_int, \ + OFFSET(f), (void *) 0 +#define _INTe(f) #f, wpa_config_parse_int, wpa_config_write_int, \ + OFFSET(eap.f), (void *) 0 +#endif /* NO_CONFIG_WRITE */ + +/* INT: Define an integer variable */ +#define INT(f) _INT(f), NULL, NULL, 0 +#define INTe(f) _INTe(f), NULL, NULL, 0 + +/* INT_RANGE: Define an integer variable with allowed value range */ +#define INT_RANGE(f, min, max) _INT(f), (void *) (min), (void *) (max), 0 + +/* FUNC: Define a configuration variable that uses a custom function for + * parsing and writing the value. */ +#ifdef NO_CONFIG_WRITE +#define _FUNC(f) #f, wpa_config_parse_ ## f, NULL, NULL, NULL, NULL +#else /* NO_CONFIG_WRITE */ +#define _FUNC(f) #f, wpa_config_parse_ ## f, wpa_config_write_ ## f, \ + NULL, NULL, NULL, NULL +#endif /* NO_CONFIG_WRITE */ +#define FUNC(f) _FUNC(f), 0 +#define FUNC_KEY(f) _FUNC(f), 1 + +/* + * Table of network configuration variables. This table is used to parse each + * network configuration variable, e.g., each line in wpa_supplicant.conf file + * that is inside a network block. + * + * This table is generated using the helper macros defined above and with + * generous help from the C pre-processor. The field name is stored as a string + * into .name and for STR and INT types, the offset of the target buffer within + * struct wpa_ssid is stored in .param1. .param2 (if not NULL) is similar + * offset to the field containing the length of the configuration variable. + * .param3 and .param4 can be used to mark the allowed range (length for STR + * and value for INT). + * + * For each configuration line in wpa_supplicant.conf, the parser goes through + * this table and select the entry that matches with the field name. The parser + * function (.parser) is then called to parse the actual value of the field. + * + * This kind of mechanism makes it easy to add new configuration parameters, + * since only one line needs to be added into this table and into the + * struct wpa_ssid definition if the new variable is either a string or + * integer. More complex types will need to use their own parser and writer + * functions. + */ +static const struct parse_data ssid_fields[] = { + { STR_RANGE(ssid, 0, MAX_SSID_LEN) }, + { INT_RANGE(scan_ssid, 0, 1) }, + { FUNC(bssid) }, + { FUNC_KEY(psk) }, + { FUNC(proto) }, + { FUNC(key_mgmt) }, + { FUNC(pairwise) }, + { FUNC(group) }, + { FUNC(auth_alg) }, +#ifdef IEEE8021X_EAPOL + { FUNC(eap) }, + { STR_LENe(identity) }, + { STR_LENe(anonymous_identity) }, + { FUNC_KEY(password) }, + { STRe(ca_cert) }, + { STRe(ca_path) }, + { STRe(client_cert) }, + { STRe(private_key) }, + { STR_KEYe(private_key_passwd) }, + { STRe(dh_file) }, + { STRe(subject_match) }, + { STRe(altsubject_match) }, + { STRe(ca_cert2) }, + { STRe(ca_path2) }, + { STRe(client_cert2) }, + { STRe(private_key2) }, + { STR_KEYe(private_key2_passwd) }, + { STRe(dh_file2) }, + { STRe(subject_match2) }, + { STRe(altsubject_match2) }, + { STRe(phase1) }, + { STRe(phase2) }, + { STRe(pcsc) }, + { STR_KEYe(pin) }, + { STRe(engine_id) }, + { STRe(key_id) }, + { STRe(cert_id) }, + { STRe(ca_cert_id) }, + { STR_KEYe(pin2) }, + { STRe(engine2_id) }, + { STRe(key2_id) }, + { STRe(cert2_id) }, + { STRe(ca_cert2_id) }, + { INTe(engine) }, + { INTe(engine2) }, + { INT(eapol_flags) }, +#endif /* IEEE8021X_EAPOL */ + { FUNC_KEY(wep_key0) }, + { FUNC_KEY(wep_key1) }, + { FUNC_KEY(wep_key2) }, + { FUNC_KEY(wep_key3) }, + { INT(wep_tx_keyidx) }, + { INT(priority) }, +#ifdef IEEE8021X_EAPOL + { INT(eap_workaround) }, + { STRe(pac_file) }, + { INTe(fragment_size) }, +#endif /* IEEE8021X_EAPOL */ + { INT_RANGE(mode, 0, 1) }, + { INT_RANGE(proactive_key_caching, 0, 1) }, + { INT_RANGE(disabled, 0, 1) }, + { STR(id_str) }, +#ifdef CONFIG_IEEE80211W + { INT_RANGE(ieee80211w, 0, 2) }, +#endif /* CONFIG_IEEE80211W */ + { INT_RANGE(peerkey, 0, 1) }, + { INT_RANGE(mixed_cell, 0, 1) }, + { INT_RANGE(frequency, 0, 10000) }, + { INT(wpa_ptk_rekey) } +}; + +#undef OFFSET +#undef _STR +#undef STR +#undef STR_KEY +#undef _STR_LEN +#undef STR_LEN +#undef STR_LEN_KEY +#undef _STR_RANGE +#undef STR_RANGE +#undef STR_RANGE_KEY +#undef _INT +#undef INT +#undef INT_RANGE +#undef _FUNC +#undef FUNC +#undef FUNC_KEY +#define NUM_SSID_FIELDS (sizeof(ssid_fields) / sizeof(ssid_fields[0])) + + +/** + * wpa_config_add_prio_network - Add a network to priority lists + * @config: Configuration data from wpa_config_read() + * @ssid: Pointer to the network configuration to be added to the list + * Returns: 0 on success, -1 on failure + * + * This function is used to add a network block to the priority list of + * networks. This must be called for each network when reading in the full + * configuration. In addition, this can be used indirectly when updating + * priorities by calling wpa_config_update_prio_list(). + */ +int wpa_config_add_prio_network(struct wpa_config *config, + struct wpa_ssid *ssid) +{ + int prio; + struct wpa_ssid *prev, **nlist; + + /* + * Add to an existing priority list if one is available for the + * configured priority level for this network. + */ + for (prio = 0; prio < config->num_prio; prio++) { + prev = config->pssid[prio]; + if (prev->priority == ssid->priority) { + while (prev->pnext) + prev = prev->pnext; + prev->pnext = ssid; + return 0; + } + } + + /* First network for this priority - add a new priority list */ + nlist = os_realloc(config->pssid, + (config->num_prio + 1) * sizeof(struct wpa_ssid *)); + if (nlist == NULL) + return -1; + + for (prio = 0; prio < config->num_prio; prio++) { + if (nlist[prio]->priority < ssid->priority) + break; + } + + os_memmove(&nlist[prio + 1], &nlist[prio], + (config->num_prio - prio) * sizeof(struct wpa_ssid *)); + + nlist[prio] = ssid; + config->num_prio++; + config->pssid = nlist; + + return 0; +} + + +/** + * wpa_config_update_prio_list - Update network priority list + * @config: Configuration data from wpa_config_read() + * Returns: 0 on success, -1 on failure + * + * This function is called to update the priority list of networks in the + * configuration when a network is being added or removed. This is also called + * if a priority for a network is changed. + */ +static int wpa_config_update_prio_list(struct wpa_config *config) +{ + struct wpa_ssid *ssid; + int ret = 0; + + os_free(config->pssid); + config->pssid = NULL; + config->num_prio = 0; + + ssid = config->ssid; + while (ssid) { + ssid->pnext = NULL; + if (wpa_config_add_prio_network(config, ssid) < 0) + ret = -1; + ssid = ssid->next; + } + + return ret; +} + + +#ifdef IEEE8021X_EAPOL +static void eap_peer_config_free(struct eap_peer_config *eap) +{ + os_free(eap->eap_methods); + os_free(eap->identity); + os_free(eap->anonymous_identity); + os_free(eap->password); + os_free(eap->ca_cert); + os_free(eap->ca_path); + os_free(eap->client_cert); + os_free(eap->private_key); + os_free(eap->private_key_passwd); + os_free(eap->dh_file); + os_free(eap->subject_match); + os_free(eap->altsubject_match); + os_free(eap->ca_cert2); + os_free(eap->ca_path2); + os_free(eap->client_cert2); + os_free(eap->private_key2); + os_free(eap->private_key2_passwd); + os_free(eap->dh_file2); + os_free(eap->subject_match2); + os_free(eap->altsubject_match2); + os_free(eap->phase1); + os_free(eap->phase2); + os_free(eap->pcsc); + os_free(eap->pin); + os_free(eap->engine_id); + os_free(eap->key_id); + os_free(eap->cert_id); + os_free(eap->ca_cert_id); + os_free(eap->key2_id); + os_free(eap->cert2_id); + os_free(eap->ca_cert2_id); + os_free(eap->pin2); + os_free(eap->engine2_id); + os_free(eap->otp); + os_free(eap->pending_req_otp); + os_free(eap->pac_file); + os_free(eap->new_password); +} +#endif /* IEEE8021X_EAPOL */ + + +/** + * wpa_config_free_ssid - Free network/ssid configuration data + * @ssid: Configuration data for the network + * + * This function frees all resources allocated for the network configuration + * data. + */ +void wpa_config_free_ssid(struct wpa_ssid *ssid) +{ + os_free(ssid->ssid); + os_free(ssid->passphrase); +#ifdef IEEE8021X_EAPOL + eap_peer_config_free(&ssid->eap); +#endif /* IEEE8021X_EAPOL */ + os_free(ssid->id_str); + os_free(ssid); +} + + +/** + * wpa_config_free - Free configuration data + * @config: Configuration data from wpa_config_read() + * + * This function frees all resources allocated for the configuration data by + * wpa_config_read(). + */ +void wpa_config_free(struct wpa_config *config) +{ +#ifndef CONFIG_NO_CONFIG_BLOBS + struct wpa_config_blob *blob, *prevblob; +#endif /* CONFIG_NO_CONFIG_BLOBS */ + struct wpa_ssid *ssid, *prev = NULL; + ssid = config->ssid; + while (ssid) { + prev = ssid; + ssid = ssid->next; + wpa_config_free_ssid(prev); + } + +#ifndef CONFIG_NO_CONFIG_BLOBS + blob = config->blobs; + prevblob = NULL; + while (blob) { + prevblob = blob; + blob = blob->next; + wpa_config_free_blob(prevblob); + } +#endif /* CONFIG_NO_CONFIG_BLOBS */ + + os_free(config->ctrl_interface); + os_free(config->ctrl_interface_group); +#ifdef EAP_TLS_OPENSSL + os_free(config->opensc_engine_path); + os_free(config->pkcs11_engine_path); + os_free(config->pkcs11_module_path); +#endif /* EAP_TLS_OPENSSL */ + os_free(config->driver_param); + os_free(config->device_name); + os_free(config->manufacturer); + os_free(config->model_name); + os_free(config->model_number); + os_free(config->serial_number); + os_free(config->device_type); + os_free(config->pssid); + os_free(config); +} + + +/** + * wpa_config_get_network - Get configured network based on id + * @config: Configuration data from wpa_config_read() + * @id: Unique network id to search for + * Returns: Network configuration or %NULL if not found + */ +struct wpa_ssid * wpa_config_get_network(struct wpa_config *config, int id) +{ + struct wpa_ssid *ssid; + + ssid = config->ssid; + while (ssid) { + if (id == ssid->id) + break; + ssid = ssid->next; + } + + return ssid; +} + + +/** + * wpa_config_add_network - Add a new network with empty configuration + * @config: Configuration data from wpa_config_read() + * Returns: The new network configuration or %NULL if operation failed + */ +struct wpa_ssid * wpa_config_add_network(struct wpa_config *config) +{ + int id; + struct wpa_ssid *ssid, *last = NULL; + + id = -1; + ssid = config->ssid; + while (ssid) { + if (ssid->id > id) + id = ssid->id; + last = ssid; + ssid = ssid->next; + } + id++; + + ssid = os_zalloc(sizeof(*ssid)); + if (ssid == NULL) + return NULL; + ssid->id = id; + if (last) + last->next = ssid; + else + config->ssid = ssid; + + wpa_config_update_prio_list(config); + + return ssid; +} + + +/** + * wpa_config_remove_network - Remove a configured network based on id + * @config: Configuration data from wpa_config_read() + * @id: Unique network id to search for + * Returns: 0 on success, or -1 if the network was not found + */ +int wpa_config_remove_network(struct wpa_config *config, int id) +{ + struct wpa_ssid *ssid, *prev = NULL; + + ssid = config->ssid; + while (ssid) { + if (id == ssid->id) + break; + prev = ssid; + ssid = ssid->next; + } + + if (ssid == NULL) + return -1; + + if (prev) + prev->next = ssid->next; + else + config->ssid = ssid->next; + + wpa_config_update_prio_list(config); + wpa_config_free_ssid(ssid); + return 0; +} + + +/** + * wpa_config_set_network_defaults - Set network default values + * @ssid: Pointer to network configuration data + */ +void wpa_config_set_network_defaults(struct wpa_ssid *ssid) +{ + ssid->proto = DEFAULT_PROTO; + ssid->pairwise_cipher = DEFAULT_PAIRWISE; + ssid->group_cipher = DEFAULT_GROUP; + ssid->key_mgmt = DEFAULT_KEY_MGMT; +#ifdef IEEE8021X_EAPOL + ssid->eapol_flags = DEFAULT_EAPOL_FLAGS; + ssid->eap_workaround = DEFAULT_EAP_WORKAROUND; + ssid->eap.fragment_size = DEFAULT_FRAGMENT_SIZE; +#endif /* IEEE8021X_EAPOL */ +} + + +/** + * wpa_config_set - Set a variable in network configuration + * @ssid: Pointer to network configuration data + * @var: Variable name, e.g., "ssid" + * @value: Variable value + * @line: Line number in configuration file or 0 if not used + * Returns: 0 on success, -1 on failure + * + * This function can be used to set network configuration variables based on + * both the configuration file and management interface input. The value + * parameter must be in the same format as the text-based configuration file is + * using. For example, strings are using double quotation marks. + */ +int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value, + int line) +{ + size_t i; + int ret = 0; + + if (ssid == NULL || var == NULL || value == NULL) + return -1; + + for (i = 0; i < NUM_SSID_FIELDS; i++) { + const struct parse_data *field = &ssid_fields[i]; + if (os_strcmp(var, field->name) != 0) + continue; + + if (field->parser(field, ssid, line, value)) { + if (line) { + wpa_printf(MSG_ERROR, "Line %d: failed to " + "parse %s '%s'.", line, var, value); + } + ret = -1; + } + break; + } + if (i == NUM_SSID_FIELDS) { + if (line) { + wpa_printf(MSG_ERROR, "Line %d: unknown network field " + "'%s'.", line, var); + } + ret = -1; + } + + return ret; +} + + +#ifndef NO_CONFIG_WRITE +/** + * wpa_config_get - Get a variable in network configuration + * @ssid: Pointer to network configuration data + * @var: Variable name, e.g., "ssid" + * Returns: Value of the variable or %NULL on failure + * + * This function can be used to get network configuration variables. The + * returned value is a copy of the configuration variable in text format, i.e,. + * the same format that the text-based configuration file and wpa_config_set() + * are using for the value. The caller is responsible for freeing the returned + * value. + */ +char * wpa_config_get(struct wpa_ssid *ssid, const char *var) +{ + size_t i; + + if (ssid == NULL || var == NULL) + return NULL; + + for (i = 0; i < NUM_SSID_FIELDS; i++) { + const struct parse_data *field = &ssid_fields[i]; + if (os_strcmp(var, field->name) == 0) + return field->writer(field, ssid); + } + + return NULL; +} + + +/** + * wpa_config_get_no_key - Get a variable in network configuration (no keys) + * @ssid: Pointer to network configuration data + * @var: Variable name, e.g., "ssid" + * Returns: Value of the variable or %NULL on failure + * + * This function can be used to get network configuration variable like + * wpa_config_get(). The only difference is that this functions does not expose + * key/password material from the configuration. In case a key/password field + * is requested, the returned value is an empty string or %NULL if the variable + * is not set or "*" if the variable is set (regardless of its value). The + * returned value is a copy of the configuration variable in text format, i.e,. + * the same format that the text-based configuration file and wpa_config_set() + * are using for the value. The caller is responsible for freeing the returned + * value. + */ +char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var) +{ + size_t i; + + if (ssid == NULL || var == NULL) + return NULL; + + for (i = 0; i < NUM_SSID_FIELDS; i++) { + const struct parse_data *field = &ssid_fields[i]; + if (os_strcmp(var, field->name) == 0) { + char *res = field->writer(field, ssid); + if (field->key_data) { + if (res && res[0]) { + wpa_printf(MSG_DEBUG, "Do not allow " + "key_data field to be " + "exposed"); + os_free(res); + return os_strdup("*"); + } + + os_free(res); + return NULL; + } + return res; + } + } + + return NULL; +} +#endif /* NO_CONFIG_WRITE */ + + +/** + * wpa_config_update_psk - Update WPA PSK based on passphrase and SSID + * @ssid: Pointer to network configuration data + * + * This function must be called to update WPA PSK when either SSID or the + * passphrase has changed for the network configuration. + */ +void wpa_config_update_psk(struct wpa_ssid *ssid) +{ +#ifndef CONFIG_NO_PBKDF2 + pbkdf2_sha1(ssid->passphrase, + (char *) ssid->ssid, ssid->ssid_len, 4096, + ssid->psk, PMK_LEN); + wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)", + ssid->psk, PMK_LEN); + ssid->psk_set = 1; +#endif /* CONFIG_NO_PBKDF2 */ +} + + +#ifndef CONFIG_NO_CONFIG_BLOBS +/** + * wpa_config_get_blob - Get a named configuration blob + * @config: Configuration data from wpa_config_read() + * @name: Name of the blob + * Returns: Pointer to blob data or %NULL if not found + */ +const struct wpa_config_blob * wpa_config_get_blob(struct wpa_config *config, + const char *name) +{ + struct wpa_config_blob *blob = config->blobs; + + while (blob) { + if (os_strcmp(blob->name, name) == 0) + return blob; + blob = blob->next; + } + return NULL; +} + + +/** + * wpa_config_set_blob - Set or add a named configuration blob + * @config: Configuration data from wpa_config_read() + * @blob: New value for the blob + * + * Adds a new configuration blob or replaces the current value of an existing + * blob. + */ +void wpa_config_set_blob(struct wpa_config *config, + struct wpa_config_blob *blob) +{ + wpa_config_remove_blob(config, blob->name); + blob->next = config->blobs; + config->blobs = blob; +} + + +/** + * wpa_config_free_blob - Free blob data + * @blob: Pointer to blob to be freed + */ +void wpa_config_free_blob(struct wpa_config_blob *blob) +{ + if (blob) { + os_free(blob->name); + os_free(blob->data); + os_free(blob); + } +} + + +/** + * wpa_config_remove_blob - Remove a named configuration blob + * @config: Configuration data from wpa_config_read() + * @name: Name of the blob to remove + * Returns: 0 if blob was removed or -1 if blob was not found + */ +int wpa_config_remove_blob(struct wpa_config *config, const char *name) +{ + struct wpa_config_blob *pos = config->blobs, *prev = NULL; + + while (pos) { + if (os_strcmp(pos->name, name) == 0) { + if (prev) + prev->next = pos->next; + else + config->blobs = pos->next; + wpa_config_free_blob(pos); + return 0; + } + prev = pos; + pos = pos->next; + } + + return -1; +} +#endif /* CONFIG_NO_CONFIG_BLOBS */ + + +/** + * wpa_config_alloc_empty - Allocate an empty configuration + * @ctrl_interface: Control interface parameters, e.g., path to UNIX domain + * socket + * @driver_param: Driver parameters + * Returns: Pointer to allocated configuration data or %NULL on failure + */ +struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, + const char *driver_param) +{ + struct wpa_config *config; + + config = os_zalloc(sizeof(*config)); + if (config == NULL) + return NULL; + config->eapol_version = DEFAULT_EAPOL_VERSION; + config->ap_scan = DEFAULT_AP_SCAN; + config->fast_reauth = DEFAULT_FAST_REAUTH; + + if (ctrl_interface) + config->ctrl_interface = os_strdup(ctrl_interface); + if (driver_param) + config->driver_param = os_strdup(driver_param); + + return config; +} + + +#ifndef CONFIG_NO_STDOUT_DEBUG +/** + * wpa_config_debug_dump_networks - Debug dump of configured networks + * @config: Configuration data from wpa_config_read() + */ +void wpa_config_debug_dump_networks(struct wpa_config *config) +{ + int prio; + struct wpa_ssid *ssid; + + for (prio = 0; prio < config->num_prio; prio++) { + ssid = config->pssid[prio]; + wpa_printf(MSG_DEBUG, "Priority group %d", + ssid->priority); + while (ssid) { + wpa_printf(MSG_DEBUG, " id=%d ssid='%s'", + ssid->id, + wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); + ssid = ssid->pnext; + } + } +} +#endif /* CONFIG_NO_STDOUT_DEBUG */ diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h new file mode 100644 index 000000000000..4484e91d9215 --- /dev/null +++ b/wpa_supplicant/config.h @@ -0,0 +1,392 @@ +/* + * WPA Supplicant / Configuration file structures + * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef CONFIG_H +#define CONFIG_H + +#define DEFAULT_EAPOL_VERSION 1 +#ifdef CONFIG_NO_SCAN_PROCESSING +#define DEFAULT_AP_SCAN 2 +#else /* CONFIG_NO_SCAN_PROCESSING */ +#define DEFAULT_AP_SCAN 1 +#endif /* CONFIG_NO_SCAN_PROCESSING */ +#define DEFAULT_FAST_REAUTH 1 + +#include "config_ssid.h" + + +/** + * struct wpa_config - wpa_supplicant configuration data + * + * This data structure is presents the per-interface (radio) configuration + * data. In many cases, there is only one struct wpa_config instance, but if + * more than one network interface is being controlled, one instance is used + * for each. + */ +struct wpa_config { + /** + * ssid - Head of the global network list + * + * This is the head for the list of all the configured networks. + */ + struct wpa_ssid *ssid; + + /** + * pssid - Per-priority network lists (in priority order) + */ + struct wpa_ssid **pssid; + + /** + * num_prio - Number of different priorities used in the pssid lists + * + * This indicates how many per-priority network lists are included in + * pssid. + */ + int num_prio; + + /** + * eapol_version - IEEE 802.1X/EAPOL version number + * + * wpa_supplicant is implemented based on IEEE Std 802.1X-2004 which + * defines EAPOL version 2. However, there are many APs that do not + * handle the new version number correctly (they seem to drop the + * frames completely). In order to make wpa_supplicant interoperate + * with these APs, the version number is set to 1 by default. This + * configuration value can be used to set it to the new version (2). + */ + int eapol_version; + + /** + * ap_scan - AP scanning/selection + * + * By default, wpa_supplicant requests driver to perform AP + * scanning and then uses the scan results to select a + * suitable AP. Another alternative is to allow the driver to + * take care of AP scanning and selection and use + * wpa_supplicant just to process EAPOL frames based on IEEE + * 802.11 association information from the driver. + * + * 1: wpa_supplicant initiates scanning and AP selection (default). + * + * 0: Driver takes care of scanning, AP selection, and IEEE 802.11 + * association parameters (e.g., WPA IE generation); this mode can + * also be used with non-WPA drivers when using IEEE 802.1X mode; + * do not try to associate with APs (i.e., external program needs + * to control association). This mode must also be used when using + * wired Ethernet drivers. + * + * 2: like 0, but associate with APs using security policy and SSID + * (but not BSSID); this can be used, e.g., with ndiswrapper and NDIS + * drivers to enable operation with hidden SSIDs and optimized roaming; + * in this mode, the network blocks in the configuration are tried + * one by one until the driver reports successful association; each + * network block should have explicit security policy (i.e., only one + * option in the lists) for key_mgmt, pairwise, group, proto variables. + */ + int ap_scan; + + /** + * ctrl_interface - Parameters for the control interface + * + * If this is specified, %wpa_supplicant will open a control interface + * that is available for external programs to manage %wpa_supplicant. + * The meaning of this string depends on which control interface + * mechanism is used. For all cases, the existance of this parameter + * in configuration is used to determine whether the control interface + * is enabled. + * + * For UNIX domain sockets (default on Linux and BSD): This is a + * directory that will be created for UNIX domain sockets 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 %wpa_supplicant processes can be + * run at the same time if more than one interface is used. + * /var/run/wpa_supplicant is the recommended directory for sockets and + * by default, wpa_cli will use it when trying to connect with + * %wpa_supplicant. + * + * 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 + * %wpa_supplicant 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, %wpa_supplicant is configured to use gid + * 0 (root). If you want to allow non-root users to use the + * control 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. + * + * When configuring both the directory and group, use following format: + * DIR=/var/run/wpa_supplicant GROUP=wheel + * DIR=/var/run/wpa_supplicant GROUP=0 + * (group can be either group name or gid) + * + * For UDP connections (default on Windows): The value will be ignored. + * This variable is just used to select that the control interface is + * to be created. The value can be set to, e.g., udp + * (ctrl_interface=udp). + * + * For Windows Named Pipe: This value can be used to set the security + * descriptor for controlling access to the control interface. Security + * descriptor can be set using Security Descriptor String Format (see + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthz/security/security_descriptor_string_format.asp). + * The descriptor string needs to be prefixed with SDDL=. For example, + * ctrl_interface=SDDL=D: would set an empty DACL (which will reject + * all connections). + */ + char *ctrl_interface; + + /** + * ctrl_interface_group - Control interface group (DEPRECATED) + * + * This variable is only used for backwards compatibility. Group for + * UNIX domain sockets should now be specified using GROUP=group in + * ctrl_interface variable. + */ + char *ctrl_interface_group; + + /** + * fast_reauth - EAP fast re-authentication (session resumption) + * + * By default, fast re-authentication is enabled for all EAP methods + * that support it. This variable can be used to disable fast + * re-authentication (by setting fast_reauth=0). Normally, there is no + * need to disable fast re-authentication. + */ + int fast_reauth; + +#ifdef EAP_TLS_OPENSSL + /** + * opensc_engine_path - Path to the OpenSSL engine for opensc + * + * This is an OpenSSL specific configuration option for loading OpenSC + * engine (engine_opensc.so); if %NULL, this engine is not loaded. + */ + char *opensc_engine_path; + + /** + * pkcs11_engine_path - Path to the OpenSSL engine for PKCS#11 + * + * This is an OpenSSL specific configuration option for loading PKCS#11 + * engine (engine_pkcs11.so); if %NULL, this engine is not loaded. + */ + char *pkcs11_engine_path; + + /** + * pkcs11_module_path - Path to the OpenSSL OpenSC/PKCS#11 module + * + * This is an OpenSSL specific configuration option for configuring + * path to OpenSC/PKCS#11 engine (opensc-pkcs11.so); if %NULL, this + * module is not loaded. + */ + char *pkcs11_module_path; +#endif /* EAP_TLS_OPENSSL */ + + /** + * driver_param - Driver interface parameters + * + * This text string is passed to the selected driver interface with the + * optional struct wpa_driver_ops::set_param() handler. This can be + * used to configure driver specific options without having to add new + * driver interface functionality. + */ + char *driver_param; + + /** + * dot11RSNAConfigPMKLifetime - Maximum lifetime of a PMK + * + * dot11 MIB variable for the maximum lifetime of a PMK in the PMK + * cache (unit: seconds). + */ + unsigned int dot11RSNAConfigPMKLifetime; + + /** + * dot11RSNAConfigPMKReauthThreshold - PMK re-authentication threshold + * + * dot11 MIB variable for the percentage of the PMK lifetime + * that should expire before an IEEE 802.1X reauthentication occurs. + */ + unsigned int dot11RSNAConfigPMKReauthThreshold; + + /** + * dot11RSNAConfigSATimeout - Security association timeout + * + * dot11 MIB variable for the maximum time a security association + * shall take to set up (unit: seconds). + */ + unsigned int dot11RSNAConfigSATimeout; + + /** + * update_config - Is wpa_supplicant allowed to update configuration + * + * This variable control whether wpa_supplicant is allow to re-write + * its configuration with wpa_config_write(). If this is zero, + * configuration data is only changed in memory and the external data + * is not overriden. If this is non-zero, wpa_supplicant will update + * the configuration data (e.g., a file) whenever configuration is + * changed. This update may replace the old configuration which can + * remove comments from it in case of a text file configuration. + */ + int update_config; + + /** + * blobs - Configuration blobs + */ + struct wpa_config_blob *blobs; + + /** + * uuid - Universally Unique IDentifier (UUID; see RFC 4122) for WPS + */ + u8 uuid[16]; + + /** + * device_name - Device Name (WPS) + * User-friendly description of device; up to 32 octets encoded in + * UTF-8 + */ + char *device_name; + + /** + * manufacturer - Manufacturer (WPS) + * The manufacturer of the device (up to 64 ASCII characters) + */ + char *manufacturer; + + /** + * model_name - Model Name (WPS) + * Model of the device (up to 32 ASCII characters) + */ + char *model_name; + + /** + * model_number - Model Number (WPS) + * Additional device description (up to 32 ASCII characters) + */ + char *model_number; + + /** + * serial_number - Serial Number (WPS) + * Serial number of the device (up to 32 characters) + */ + char *serial_number; + + /** + * device_type - Primary Device Type (WPS) + * Used format: categ-OUI-subcateg + * categ = Category as an integer value + * OUI = OUI and type octet as a 4-octet hex-encoded value; + * 0050F204 for default WPS OUI + * subcateg = OUI-specific Sub Category as an integer value + * Examples: + * 1-0050F204-1 (Computer / PC) + * 1-0050F204-2 (Computer / Server) + * 5-0050F204-1 (Storage / NAS) + * 6-0050F204-1 (Network Infrastructure / AP) + */ + char *device_type; + + /** + * os_version - OS Version (WPS) + * 4-octet operating system version number + */ + u8 os_version[4]; + + /** + * country - Country code + * + * This is the ISO/IEC alpha2 country code for which we are operating + * in + */ + char country[2]; + + /** + * wps_cred_processing - Credential processing + * + * 0 = process received credentials internally + * 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) + */ + int wps_cred_processing; +}; + + +/* Prototypes for common functions from config.c */ + +void wpa_config_free(struct wpa_config *ssid); +void wpa_config_free_ssid(struct wpa_ssid *ssid); +struct wpa_ssid * wpa_config_get_network(struct wpa_config *config, int id); +struct wpa_ssid * wpa_config_add_network(struct wpa_config *config); +int wpa_config_remove_network(struct wpa_config *config, int id); +void wpa_config_set_network_defaults(struct wpa_ssid *ssid); +int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value, + int line); +char * wpa_config_get(struct wpa_ssid *ssid, const char *var); +char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var); +void wpa_config_update_psk(struct wpa_ssid *ssid); +int wpa_config_add_prio_network(struct wpa_config *config, + struct wpa_ssid *ssid); +const struct wpa_config_blob * wpa_config_get_blob(struct wpa_config *config, + const char *name); +void wpa_config_set_blob(struct wpa_config *config, + struct wpa_config_blob *blob); +void wpa_config_free_blob(struct wpa_config_blob *blob); +int wpa_config_remove_blob(struct wpa_config *config, const char *name); + +struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, + const char *driver_param); +#ifndef CONFIG_NO_STDOUT_DEBUG +void wpa_config_debug_dump_networks(struct wpa_config *config); +#else /* CONFIG_NO_STDOUT_DEBUG */ +#define wpa_config_debug_dump_networks(c) do { } while (0) +#endif /* CONFIG_NO_STDOUT_DEBUG */ + + +/* Prototypes for backend specific functions from the selected config_*.c */ + +/** + * wpa_config_read - Read and parse configuration database + * @name: Name of the configuration (e.g., path and file name for the + * configuration file) + * Returns: Pointer to allocated configuration data or %NULL on failure + * + * This function reads configuration data, parses its contents, and allocates + * data structures needed for storing configuration information. The allocated + * data can be freed with wpa_config_free(). + * + * Each configuration backend needs to implement this function. + */ +struct wpa_config * wpa_config_read(const char *name); + +/** + * wpa_config_write - Write or update configuration data + * @name: Name of the configuration (e.g., path and file name for the + * configuration file) + * @config: Configuration data from wpa_config_read() + * Returns: 0 on success, -1 on failure + * + * This function write all configuration data into an external database (e.g., + * a text file) in a format that can be read with wpa_config_read(). This can + * be used to allow wpa_supplicant to update its configuration, e.g., when a + * new network is added or a password is changed. + * + * Each configuration backend needs to implement this function. + */ +int wpa_config_write(const char *name, struct wpa_config *config); + +#endif /* CONFIG_H */ diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c new file mode 100644 index 000000000000..29e494c1e3b0 --- /dev/null +++ b/wpa_supplicant/config_file.c @@ -0,0 +1,942 @@ +/* + * WPA Supplicant / Configuration backend: text file + * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + * + * This file implements a configuration backend for text files. All the + * configuration information is stored in a text file that uses a format + * described in the sample configuration file, wpa_supplicant.conf. + */ + +#include "includes.h" + +#include "common.h" +#include "config.h" +#include "base64.h" +#include "uuid.h" +#include "eap_peer/eap_methods.h" + + +/** + * wpa_config_get_line - Read the next configuration file line + * @s: Buffer for the line + * @size: The buffer length + * @stream: File stream to read from + * @line: Pointer to a variable storing the file line number + * @_pos: Buffer for the pointer to the beginning of data on the text line or + * %NULL if not needed (returned value used instead) + * Returns: Pointer to the beginning of data on the text line or %NULL if no + * more text lines are available. + * + * This function reads the next non-empty line from the configuration file and + * removes comments. The returned string is guaranteed to be null-terminated. + */ +static char * wpa_config_get_line(char *s, int size, FILE *stream, int *line, + char **_pos) +{ + char *pos, *end, *sstart; + + while (fgets(s, size, stream)) { + (*line)++; + s[size - 1] = '\0'; + pos = s; + + /* Skip white space from the beginning of line. */ + while (*pos == ' ' || *pos == '\t' || *pos == '\r') + pos++; + + /* Skip comment lines and empty lines */ + if (*pos == '#' || *pos == '\n' || *pos == '\0') + continue; + + /* + * Remove # comments unless they are within a double quoted + * string. + */ + sstart = os_strchr(pos, '"'); + if (sstart) + sstart = os_strrchr(sstart + 1, '"'); + if (!sstart) + sstart = pos; + end = os_strchr(sstart, '#'); + if (end) + *end-- = '\0'; + else + end = pos + os_strlen(pos) - 1; + + /* Remove trailing white space. */ + while (end > pos && + (*end == '\n' || *end == ' ' || *end == '\t' || + *end == '\r')) + *end-- = '\0'; + + if (*pos == '\0') + continue; + + if (_pos) + *_pos = pos; + return pos; + } + + if (_pos) + *_pos = NULL; + return NULL; +} + + +static int wpa_config_validate_network(struct wpa_ssid *ssid, int line) +{ + int errors = 0; + + if (ssid->passphrase) { + if (ssid->psk_set) { + wpa_printf(MSG_ERROR, "Line %d: both PSK and " + "passphrase configured.", line); + errors++; + } + wpa_config_update_psk(ssid); + } + + if ((ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK | + WPA_KEY_MGMT_PSK_SHA256)) && + !ssid->psk_set) { + wpa_printf(MSG_ERROR, "Line %d: WPA-PSK accepted for key " + "management, but no PSK configured.", line); + errors++; + } + + if ((ssid->group_cipher & WPA_CIPHER_CCMP) && + !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) && + !(ssid->pairwise_cipher & WPA_CIPHER_NONE)) { + /* Group cipher cannot be stronger than the pairwise cipher. */ + wpa_printf(MSG_DEBUG, "Line %d: removed CCMP from group cipher" + " list since it was not allowed for pairwise " + "cipher", line); + ssid->group_cipher &= ~WPA_CIPHER_CCMP; + } + + return errors; +} + + +static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id) +{ + struct wpa_ssid *ssid; + int errors = 0, end = 0; + char buf[256], *pos, *pos2; + + wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new network block", + *line); + ssid = os_zalloc(sizeof(*ssid)); + if (ssid == NULL) + return NULL; + ssid->id = id; + + wpa_config_set_network_defaults(ssid); + + while (wpa_config_get_line(buf, sizeof(buf), f, line, &pos)) { + if (os_strcmp(pos, "}") == 0) { + end = 1; + break; + } + + pos2 = os_strchr(pos, '='); + if (pos2 == NULL) { + wpa_printf(MSG_ERROR, "Line %d: Invalid SSID line " + "'%s'.", *line, pos); + errors++; + continue; + } + + *pos2++ = '\0'; + if (*pos2 == '"') { + if (os_strchr(pos2 + 1, '"') == NULL) { + wpa_printf(MSG_ERROR, "Line %d: invalid " + "quotation '%s'.", *line, pos2); + errors++; + continue; + } + } + + if (wpa_config_set(ssid, pos, pos2, *line) < 0) + errors++; + } + + if (!end) { + wpa_printf(MSG_ERROR, "Line %d: network block was not " + "terminated properly.", *line); + errors++; + } + + errors += wpa_config_validate_network(ssid, *line); + + if (errors) { + wpa_config_free_ssid(ssid); + ssid = NULL; + } + + return ssid; +} + + +#ifndef CONFIG_NO_CONFIG_BLOBS +static struct wpa_config_blob * wpa_config_read_blob(FILE *f, int *line, + const char *name) +{ + struct wpa_config_blob *blob; + char buf[256], *pos; + unsigned char *encoded = NULL, *nencoded; + int end = 0; + size_t encoded_len = 0, len; + + wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new named blob '%s'", + *line, name); + + while (wpa_config_get_line(buf, sizeof(buf), f, line, &pos)) { + if (os_strcmp(pos, "}") == 0) { + end = 1; + break; + } + + len = os_strlen(pos); + nencoded = os_realloc(encoded, encoded_len + len); + if (nencoded == NULL) { + wpa_printf(MSG_ERROR, "Line %d: not enough memory for " + "blob", *line); + os_free(encoded); + return NULL; + } + encoded = nencoded; + os_memcpy(encoded + encoded_len, pos, len); + encoded_len += len; + } + + if (!end) { + wpa_printf(MSG_ERROR, "Line %d: blob was not terminated " + "properly", *line); + os_free(encoded); + return NULL; + } + + blob = os_zalloc(sizeof(*blob)); + if (blob == NULL) { + os_free(encoded); + return NULL; + } + blob->name = os_strdup(name); + blob->data = base64_decode(encoded, encoded_len, &blob->len); + os_free(encoded); + + if (blob->name == NULL || blob->data == NULL) { + wpa_config_free_blob(blob); + return NULL; + } + + return blob; +} + + +static int wpa_config_process_blob(struct wpa_config *config, FILE *f, + int *line, char *bname) +{ + char *name_end; + struct wpa_config_blob *blob; + + name_end = os_strchr(bname, '='); + if (name_end == NULL) { + wpa_printf(MSG_ERROR, "Line %d: no blob name terminator", + *line); + return -1; + } + *name_end = '\0'; + + blob = wpa_config_read_blob(f, line, bname); + if (blob == NULL) { + wpa_printf(MSG_ERROR, "Line %d: failed to read blob %s", + *line, bname); + return -1; + } + wpa_config_set_blob(config, blob); + return 0; +} +#endif /* CONFIG_NO_CONFIG_BLOBS */ + + +struct global_parse_data { + char *name; + int (*parser)(const struct global_parse_data *data, + struct wpa_config *config, int line, const char *value); + void *param1, *param2, *param3; +}; + + +static int wpa_config_parse_int(const struct global_parse_data *data, + struct wpa_config *config, int line, + const char *pos) +{ + int *dst; + dst = (int *) (((u8 *) config) + (long) data->param1); + *dst = atoi(pos); + wpa_printf(MSG_DEBUG, "%s=%d", data->name, *dst); + + if (data->param2 && *dst < (long) data->param2) { + wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d " + "min_value=%ld)", line, data->name, *dst, + (long) data->param2); + *dst = (long) data->param2; + return -1; + } + + if (data->param3 && *dst > (long) data->param3) { + wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d " + "max_value=%ld)", line, data->name, *dst, + (long) data->param3); + *dst = (long) data->param3; + return -1; + } + + return 0; +} + + +static int wpa_config_parse_str(const struct global_parse_data *data, + struct wpa_config *config, int line, + const char *pos) +{ + size_t len; + char **dst, *tmp; + + len = os_strlen(pos); + if (data->param2 && len < (size_t) data->param2) { + wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu " + "min_len=%ld)", line, data->name, + (unsigned long) len, (long) data->param2); + return -1; + } + + if (data->param3 && len > (size_t) data->param3) { + wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu " + "max_len=%ld)", line, data->name, + (unsigned long) len, (long) data->param3); + return -1; + } + + tmp = os_strdup(pos); + if (tmp == NULL) + return -1; + + dst = (char **) (((u8 *) config) + (long) data->param1); + os_free(*dst); + *dst = tmp; + wpa_printf(MSG_DEBUG, "%s='%s'", data->name, *dst); + + return 0; +} + + +static int wpa_config_process_country(const struct global_parse_data *data, + struct wpa_config *config, int line, + const char *pos) +{ + if (!pos[0] || !pos[1]) { + wpa_printf(MSG_DEBUG, "Invalid country set"); + return -1; + } + config->country[0] = pos[0]; + config->country[1] = pos[1]; + wpa_printf(MSG_DEBUG, "country='%c%c'", + config->country[0], config->country[1]); + return 0; +} + + +static int wpa_config_process_load_dynamic_eap( + const struct global_parse_data *data, struct wpa_config *config, + int line, const char *so) +{ + int ret; + wpa_printf(MSG_DEBUG, "load_dynamic_eap=%s", so); + ret = eap_peer_method_load(so); + if (ret == -2) { + wpa_printf(MSG_DEBUG, "This EAP type was already loaded - not " + "reloading."); + } else if (ret) { + wpa_printf(MSG_ERROR, "Line %d: Failed to load dynamic EAP " + "method '%s'.", line, so); + return -1; + } + + return 0; +} + + +#ifdef CONFIG_WPS + +static int wpa_config_process_uuid(const struct global_parse_data *data, + struct wpa_config *config, int line, + const char *pos) +{ + char buf[40]; + if (uuid_str2bin(pos, config->uuid)) { + wpa_printf(MSG_ERROR, "Line %d: invalid UUID", line); + return -1; + } + uuid_bin2str(config->uuid, buf, sizeof(buf)); + wpa_printf(MSG_DEBUG, "uuid=%s", buf); + return 0; +} + + +static int wpa_config_process_os_version(const struct global_parse_data *data, + struct wpa_config *config, int line, + const char *pos) +{ + if (hexstr2bin(pos, config->os_version, 4)) { + wpa_printf(MSG_ERROR, "Line %d: invalid os_version", line); + return -1; + } + wpa_printf(MSG_DEBUG, "os_version=%08x", + WPA_GET_BE32(config->os_version)); + return 0; +} + +#endif /* CONFIG_WPS */ + + +#ifdef OFFSET +#undef OFFSET +#endif /* OFFSET */ +/* OFFSET: Get offset of a variable within the wpa_config structure */ +#define OFFSET(v) ((void *) &((struct wpa_config *) 0)->v) + +#define FUNC(f) #f, wpa_config_process_ ## f, OFFSET(f), NULL, NULL +#define FUNC_NO_VAR(f) #f, wpa_config_process_ ## f, NULL, NULL, NULL +#define _INT(f) #f, wpa_config_parse_int, OFFSET(f) +#define INT(f) _INT(f), NULL, NULL +#define INT_RANGE(f, min, max) _INT(f), (void *) min, (void *) max +#define _STR(f) #f, wpa_config_parse_str, OFFSET(f) +#define STR(f) _STR(f), NULL, NULL +#define STR_RANGE(f, min, max) _STR(f), (void *) min, (void *) max + +static const struct global_parse_data global_fields[] = { +#ifdef CONFIG_CTRL_IFACE + { STR(ctrl_interface) }, + { STR(ctrl_interface_group) } /* deprecated */, +#endif /* CONFIG_CTRL_IFACE */ + { INT_RANGE(eapol_version, 1, 2) }, + { INT(ap_scan) }, + { INT(fast_reauth) }, +#ifdef EAP_TLS_OPENSSL + { STR(opensc_engine_path) }, + { STR(pkcs11_engine_path) }, + { STR(pkcs11_module_path) }, +#endif /* EAP_TLS_OPENSSL */ + { STR(driver_param) }, + { INT(dot11RSNAConfigPMKLifetime) }, + { INT(dot11RSNAConfigPMKReauthThreshold) }, + { INT(dot11RSNAConfigSATimeout) }, +#ifndef CONFIG_NO_CONFIG_WRITE + { INT(update_config) }, +#endif /* CONFIG_NO_CONFIG_WRITE */ + { FUNC_NO_VAR(load_dynamic_eap) }, +#ifdef CONFIG_WPS + { FUNC(uuid) }, + { STR_RANGE(device_name, 0, 32) }, + { STR_RANGE(manufacturer, 0, 64) }, + { STR_RANGE(model_name, 0, 32) }, + { STR_RANGE(model_number, 0, 32) }, + { STR_RANGE(serial_number, 0, 32) }, + { STR(device_type) }, + { FUNC(os_version) }, + { INT_RANGE(wps_cred_processing, 0, 2) }, +#endif /* CONFIG_WPS */ + { FUNC(country) } +}; + +#undef FUNC +#undef _INT +#undef INT +#undef INT_RANGE +#undef _STR +#undef STR +#undef STR_RANGE +#define NUM_GLOBAL_FIELDS (sizeof(global_fields) / sizeof(global_fields[0])) + + +static int wpa_config_process_global(struct wpa_config *config, char *pos, + int line) +{ + size_t i; + int ret = 0; + + for (i = 0; i < NUM_GLOBAL_FIELDS; i++) { + const struct global_parse_data *field = &global_fields[i]; + size_t flen = os_strlen(field->name); + if (os_strncmp(pos, field->name, flen) != 0 || + pos[flen] != '=') + continue; + + if (field->parser(field, config, line, pos + flen + 1)) { + wpa_printf(MSG_ERROR, "Line %d: failed to " + "parse '%s'.", line, pos); + ret = -1; + } + break; + } + if (i == NUM_GLOBAL_FIELDS) { + wpa_printf(MSG_ERROR, "Line %d: unknown global field '%s'.", + line, pos); + ret = -1; + } + + return ret; +} + + +struct wpa_config * wpa_config_read(const char *name) +{ + FILE *f; + char buf[256], *pos; + int errors = 0, line = 0; + struct wpa_ssid *ssid, *tail = NULL, *head = NULL; + struct wpa_config *config; + int id = 0; + + config = wpa_config_alloc_empty(NULL, NULL); + if (config == NULL) + return NULL; + wpa_printf(MSG_DEBUG, "Reading configuration file '%s'", name); + f = fopen(name, "r"); + if (f == NULL) { + os_free(config); + return NULL; + } + + while (wpa_config_get_line(buf, sizeof(buf), f, &line, &pos)) { + if (os_strcmp(pos, "network={") == 0) { + ssid = wpa_config_read_network(f, &line, id++); + if (ssid == NULL) { + wpa_printf(MSG_ERROR, "Line %d: failed to " + "parse network block.", line); + errors++; + continue; + } + if (head == NULL) { + head = tail = ssid; + } else { + tail->next = ssid; + tail = ssid; + } + if (wpa_config_add_prio_network(config, ssid)) { + wpa_printf(MSG_ERROR, "Line %d: failed to add " + "network block to priority list.", + line); + errors++; + continue; + } +#ifndef CONFIG_NO_CONFIG_BLOBS + } else if (os_strncmp(pos, "blob-base64-", 12) == 0) { + if (wpa_config_process_blob(config, f, &line, pos + 12) + < 0) { + errors++; + continue; + } +#endif /* CONFIG_NO_CONFIG_BLOBS */ + } else if (wpa_config_process_global(config, pos, line) < 0) { + wpa_printf(MSG_ERROR, "Line %d: Invalid configuration " + "line '%s'.", line, pos); + errors++; + continue; + } + } + + fclose(f); + + config->ssid = head; + wpa_config_debug_dump_networks(config); + + if (errors) { + wpa_config_free(config); + config = NULL; + head = NULL; + } + + return config; +} + + +#ifndef CONFIG_NO_CONFIG_WRITE + +static void write_str(FILE *f, const char *field, struct wpa_ssid *ssid) +{ + char *value = wpa_config_get(ssid, field); + if (value == NULL) + return; + fprintf(f, "\t%s=%s\n", field, value); + os_free(value); +} + + +static void write_int(FILE *f, const char *field, int value, int def) +{ + if (value == def) + return; + fprintf(f, "\t%s=%d\n", field, value); +} + + +static void write_bssid(FILE *f, struct wpa_ssid *ssid) +{ + char *value = wpa_config_get(ssid, "bssid"); + if (value == NULL) + return; + fprintf(f, "\tbssid=%s\n", value); + os_free(value); +} + + +static void write_psk(FILE *f, struct wpa_ssid *ssid) +{ + char *value = wpa_config_get(ssid, "psk"); + if (value == NULL) + return; + fprintf(f, "\tpsk=%s\n", value); + os_free(value); +} + + +static void write_proto(FILE *f, struct wpa_ssid *ssid) +{ + char *value; + + if (ssid->proto == DEFAULT_PROTO) + return; + + value = wpa_config_get(ssid, "proto"); + if (value == NULL) + return; + if (value[0]) + fprintf(f, "\tproto=%s\n", value); + os_free(value); +} + + +static void write_key_mgmt(FILE *f, struct wpa_ssid *ssid) +{ + char *value; + + if (ssid->key_mgmt == DEFAULT_KEY_MGMT) + return; + + value = wpa_config_get(ssid, "key_mgmt"); + if (value == NULL) + return; + if (value[0]) + fprintf(f, "\tkey_mgmt=%s\n", value); + os_free(value); +} + + +static void write_pairwise(FILE *f, struct wpa_ssid *ssid) +{ + char *value; + + if (ssid->pairwise_cipher == DEFAULT_PAIRWISE) + return; + + value = wpa_config_get(ssid, "pairwise"); + if (value == NULL) + return; + if (value[0]) + fprintf(f, "\tpairwise=%s\n", value); + os_free(value); +} + + +static void write_group(FILE *f, struct wpa_ssid *ssid) +{ + char *value; + + if (ssid->group_cipher == DEFAULT_GROUP) + return; + + value = wpa_config_get(ssid, "group"); + if (value == NULL) + return; + if (value[0]) + fprintf(f, "\tgroup=%s\n", value); + os_free(value); +} + + +static void write_auth_alg(FILE *f, struct wpa_ssid *ssid) +{ + char *value; + + if (ssid->auth_alg == 0) + return; + + value = wpa_config_get(ssid, "auth_alg"); + if (value == NULL) + return; + if (value[0]) + fprintf(f, "\tauth_alg=%s\n", value); + os_free(value); +} + + +#ifdef IEEE8021X_EAPOL +static void write_eap(FILE *f, struct wpa_ssid *ssid) +{ + char *value; + + value = wpa_config_get(ssid, "eap"); + if (value == NULL) + return; + + if (value[0]) + fprintf(f, "\teap=%s\n", value); + os_free(value); +} +#endif /* IEEE8021X_EAPOL */ + + +static void write_wep_key(FILE *f, int idx, struct wpa_ssid *ssid) +{ + char field[20], *value; + int res; + + res = os_snprintf(field, sizeof(field), "wep_key%d", idx); + if (res < 0 || (size_t) res >= sizeof(field)) + return; + value = wpa_config_get(ssid, field); + if (value) { + fprintf(f, "\t%s=%s\n", field, value); + os_free(value); + } +} + + +static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) +{ + int i; + +#define STR(t) write_str(f, #t, ssid) +#define INT(t) write_int(f, #t, ssid->t, 0) +#define INTe(t) write_int(f, #t, ssid->eap.t, 0) +#define INT_DEF(t, def) write_int(f, #t, ssid->t, def) +#define INT_DEFe(t, def) write_int(f, #t, ssid->eap.t, def) + + STR(ssid); + INT(scan_ssid); + write_bssid(f, ssid); + write_psk(f, ssid); + write_proto(f, ssid); + write_key_mgmt(f, ssid); + write_pairwise(f, ssid); + write_group(f, ssid); + write_auth_alg(f, ssid); +#ifdef IEEE8021X_EAPOL + write_eap(f, ssid); + STR(identity); + STR(anonymous_identity); + STR(password); + STR(ca_cert); + STR(ca_path); + STR(client_cert); + STR(private_key); + STR(private_key_passwd); + STR(dh_file); + STR(subject_match); + STR(altsubject_match); + STR(ca_cert2); + STR(ca_path2); + STR(client_cert2); + STR(private_key2); + STR(private_key2_passwd); + STR(dh_file2); + STR(subject_match2); + STR(altsubject_match2); + STR(phase1); + STR(phase2); + STR(pcsc); + STR(pin); + STR(engine_id); + STR(key_id); + STR(cert_id); + STR(ca_cert_id); + STR(key2_id); + STR(pin2); + STR(engine2_id); + STR(cert2_id); + STR(ca_cert2_id); + INTe(engine); + INTe(engine2); + INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS); +#endif /* IEEE8021X_EAPOL */ + for (i = 0; i < 4; i++) + write_wep_key(f, i, ssid); + INT(wep_tx_keyidx); + INT(priority); +#ifdef IEEE8021X_EAPOL + INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND); + STR(pac_file); + INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE); +#endif /* IEEE8021X_EAPOL */ + INT(mode); + INT(proactive_key_caching); + INT(disabled); + INT(peerkey); +#ifdef CONFIG_IEEE80211W + INT(ieee80211w); +#endif /* CONFIG_IEEE80211W */ + STR(id_str); + +#undef STR +#undef INT +#undef INT_DEF +} + + +#ifndef CONFIG_NO_CONFIG_BLOBS +static int wpa_config_write_blob(FILE *f, struct wpa_config_blob *blob) +{ + unsigned char *encoded; + + encoded = base64_encode(blob->data, blob->len, NULL); + if (encoded == NULL) + return -1; + + fprintf(f, "\nblob-base64-%s={\n%s}\n", blob->name, encoded); + os_free(encoded); + return 0; +} +#endif /* CONFIG_NO_CONFIG_BLOBS */ + + +static void wpa_config_write_global(FILE *f, struct wpa_config *config) +{ +#ifdef CONFIG_CTRL_IFACE + if (config->ctrl_interface) + fprintf(f, "ctrl_interface=%s\n", config->ctrl_interface); + if (config->ctrl_interface_group) + fprintf(f, "ctrl_interface_group=%s\n", + config->ctrl_interface_group); +#endif /* CONFIG_CTRL_IFACE */ + if (config->eapol_version != DEFAULT_EAPOL_VERSION) + fprintf(f, "eapol_version=%d\n", config->eapol_version); + if (config->ap_scan != DEFAULT_AP_SCAN) + fprintf(f, "ap_scan=%d\n", config->ap_scan); + if (config->fast_reauth != DEFAULT_FAST_REAUTH) + fprintf(f, "fast_reauth=%d\n", config->fast_reauth); +#ifdef EAP_TLS_OPENSSL + if (config->opensc_engine_path) + fprintf(f, "opensc_engine_path=%s\n", + config->opensc_engine_path); + if (config->pkcs11_engine_path) + fprintf(f, "pkcs11_engine_path=%s\n", + config->pkcs11_engine_path); + if (config->pkcs11_module_path) + fprintf(f, "pkcs11_module_path=%s\n", + config->pkcs11_module_path); +#endif /* EAP_TLS_OPENSSL */ + if (config->driver_param) + fprintf(f, "driver_param=%s\n", config->driver_param); + if (config->dot11RSNAConfigPMKLifetime) + fprintf(f, "dot11RSNAConfigPMKLifetime=%d\n", + config->dot11RSNAConfigPMKLifetime); + if (config->dot11RSNAConfigPMKReauthThreshold) + fprintf(f, "dot11RSNAConfigPMKReauthThreshold=%d\n", + config->dot11RSNAConfigPMKReauthThreshold); + if (config->dot11RSNAConfigSATimeout) + fprintf(f, "dot11RSNAConfigSATimeout=%d\n", + config->dot11RSNAConfigSATimeout); + if (config->update_config) + fprintf(f, "update_config=%d\n", config->update_config); +#ifdef CONFIG_WPS + if (!is_nil_uuid(config->uuid)) { + char buf[40]; + uuid_bin2str(config->uuid, buf, sizeof(buf)); + fprintf(f, "uuid=%s\n", buf); + } + if (config->device_name) + fprintf(f, "device_name=%s\n", config->device_name); + if (config->manufacturer) + fprintf(f, "manufacturer=%s\n", config->manufacturer); + if (config->model_name) + fprintf(f, "model_name=%s\n", config->model_name); + if (config->model_number) + fprintf(f, "model_number=%s\n", config->model_number); + if (config->serial_number) + fprintf(f, "serial_number=%s\n", config->serial_number); + if (config->device_type) + fprintf(f, "device_type=%s\n", config->device_type); + if (WPA_GET_BE32(config->os_version)) + fprintf(f, "os_version=%08x\n", + WPA_GET_BE32(config->os_version)); + if (config->wps_cred_processing) + fprintf(f, "wps_cred_processing=%d\n", + config->wps_cred_processing); +#endif /* CONFIG_WPS */ + if (config->country[0] && config->country[1]) { + fprintf(f, "country=%c%c\n", + config->country[0], config->country[1]); + } +} + +#endif /* CONFIG_NO_CONFIG_WRITE */ + + +int wpa_config_write(const char *name, struct wpa_config *config) +{ +#ifndef CONFIG_NO_CONFIG_WRITE + FILE *f; + struct wpa_ssid *ssid; +#ifndef CONFIG_NO_CONFIG_BLOBS + struct wpa_config_blob *blob; +#endif /* CONFIG_NO_CONFIG_BLOBS */ + int ret = 0; + + wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", name); + + f = fopen(name, "w"); + if (f == NULL) { + wpa_printf(MSG_DEBUG, "Failed to open '%s' for writing", name); + return -1; + } + + wpa_config_write_global(f, config); + + for (ssid = config->ssid; ssid; ssid = ssid->next) { + if (ssid->key_mgmt == WPA_KEY_MGMT_WPS) + continue; /* do not save temporary WPS networks */ + fprintf(f, "\nnetwork={\n"); + wpa_config_write_network(f, ssid); + fprintf(f, "}\n"); + } + +#ifndef CONFIG_NO_CONFIG_BLOBS + for (blob = config->blobs; blob; blob = blob->next) { + ret = wpa_config_write_blob(f, blob); + if (ret) + break; + } +#endif /* CONFIG_NO_CONFIG_BLOBS */ + + fclose(f); + + wpa_printf(MSG_DEBUG, "Configuration file '%s' written %ssuccessfully", + name, ret ? "un" : ""); + return ret; +#else /* CONFIG_NO_CONFIG_WRITE */ + return -1; +#endif /* CONFIG_NO_CONFIG_WRITE */ +} diff --git a/wpa_supplicant/config_none.c b/wpa_supplicant/config_none.c new file mode 100644 index 000000000000..2e9ccc0a2835 --- /dev/null +++ b/wpa_supplicant/config_none.c @@ -0,0 +1,57 @@ +/* + * WPA Supplicant / Configuration backend: empty starting point + * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + * + * This file implements dummy example of a configuration backend. None of the + * functions are actually implemented so this can be used as a simple + * compilation test or a starting point for a new configuration backend. + */ + +#include "includes.h" + +#include "common.h" +#include "config.h" +#include "base64.h" + + +struct wpa_config * wpa_config_read(const char *name) +{ + struct wpa_config *config; + + config = wpa_config_alloc_empty(NULL, NULL); + if (config == NULL) + return NULL; + /* TODO: fill in configuration data */ + return config; +} + + +int wpa_config_write(const char *name, struct wpa_config *config) +{ + struct wpa_ssid *ssid; + struct wpa_config_blob *blob; + + wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", name); + + /* TODO: write global config parameters */ + + + for (ssid = config->ssid; ssid; ssid = ssid->next) { + /* TODO: write networks */ + } + + for (blob = config->blobs; blob; blob = blob->next) { + /* TODO: write blobs */ + } + + return 0; +} diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h new file mode 100644 index 000000000000..5510639c147c --- /dev/null +++ b/wpa_supplicant/config_ssid.h @@ -0,0 +1,347 @@ +/* + * WPA Supplicant / Network configuration structures + * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef CONFIG_SSID_H +#define CONFIG_SSID_H + +#include "defs.h" +#include "eap_peer/eap_config.h" + +#define MAX_SSID_LEN 32 + + +#define DEFAULT_EAP_WORKAROUND ((unsigned int) -1) +#define DEFAULT_EAPOL_FLAGS (EAPOL_FLAG_REQUIRE_KEY_UNICAST | \ + EAPOL_FLAG_REQUIRE_KEY_BROADCAST) +#define DEFAULT_PROTO (WPA_PROTO_WPA | WPA_PROTO_RSN) +#define DEFAULT_KEY_MGMT (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X) +#define DEFAULT_PAIRWISE (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP) +#define DEFAULT_GROUP (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | \ + WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40) +#define DEFAULT_FRAGMENT_SIZE 1398 + +/** + * struct wpa_ssid - Network configuration data + * + * This structure includes all the configuration variables for a network. This + * data is included in the per-interface configuration data as an element of + * the network list, struct wpa_config::ssid. Each network block in the + * configuration is mapped to a struct wpa_ssid instance. + */ +struct wpa_ssid { + /** + * next - Next network in global list + * + * This pointer can be used to iterate over all networks. The head of + * this list is stored in the ssid field of struct wpa_config. + */ + struct wpa_ssid *next; + + /** + * pnext - Next network in per-priority list + * + * This pointer can be used to iterate over all networks in the same + * priority class. The heads of these list are stored in the pssid + * fields of struct wpa_config. + */ + struct wpa_ssid *pnext; + + /** + * id - Unique id for the network + * + * This identifier is used as a unique identifier for each network + * block when using the control interface. Each network is allocated an + * id when it is being created, either when reading the configuration + * file or when a new network is added through the control interface. + */ + int id; + + /** + * priority - Priority group + * + * By default, all networks will get same priority group (0). If some + * of the networks are more desirable, this field can be used to change + * the order in which wpa_supplicant goes through the networks when + * selecting a BSS. The priority groups will be iterated in decreasing + * priority (i.e., the larger the priority value, the sooner the + * network is matched against the scan results). Within each priority + * group, networks will be selected based on security policy, signal + * strength, etc. + * + * Please note that AP scanning with scan_ssid=1 and ap_scan=2 mode are + * not using this priority to select the order for scanning. Instead, + * they try the networks in the order that used in the configuration + * file. + */ + int priority; + + /** + * ssid - Service set identifier (network name) + * + * This is the SSID for the network. For wireless interfaces, this is + * used to select which network will be used. If set to %NULL (or + * ssid_len=0), any SSID can be used. For wired interfaces, this must + * be set to %NULL. Note: SSID may contain any characters, even nul + * (ASCII 0) and as such, this should not be assumed to be a nul + * terminated string. ssid_len defines how many characters are valid + * and the ssid field is not guaranteed to be nul terminated. + */ + u8 *ssid; + + /** + * ssid_len - Length of the SSID + */ + size_t ssid_len; + + /** + * bssid - BSSID + * + * If set, this network block is used only when associating with the AP + * using the configured BSSID + */ + u8 bssid[ETH_ALEN]; + + /** + * bssid_set - Whether BSSID is configured for this network + */ + int bssid_set; + + /** + * psk - WPA pre-shared key (256 bits) + */ + u8 psk[32]; + + /** + * psk_set - Whether PSK field is configured + */ + int psk_set; + + /** + * passphrase - WPA ASCII passphrase + * + * If this is set, psk will be generated using the SSID and passphrase + * configured for the network. ASCII passphrase must be between 8 and + * 63 characters (inclusive). + */ + char *passphrase; + + /** + * pairwise_cipher - Bitfield of allowed pairwise ciphers, WPA_CIPHER_* + */ + int pairwise_cipher; + + /** + * group_cipher - Bitfield of allowed group ciphers, WPA_CIPHER_* + */ + int group_cipher; + + /** + * key_mgmt - Bitfield of allowed key management protocols + * + * WPA_KEY_MGMT_* + */ + int key_mgmt; + + /** + * proto - Bitfield of allowed protocols, WPA_PROTO_* + */ + int proto; + + /** + * auth_alg - Bitfield of allowed authentication algorithms + * + * WPA_AUTH_ALG_* + */ + int auth_alg; + + /** + * scan_ssid - Scan this SSID with Probe Requests + * + * scan_ssid can be used to scan for APs using hidden SSIDs. + * Note: Many drivers do not support this. ap_mode=2 can be used with + * such drivers to use hidden SSIDs. + */ + int scan_ssid; + +#ifdef IEEE8021X_EAPOL +#define EAPOL_FLAG_REQUIRE_KEY_UNICAST BIT(0) +#define EAPOL_FLAG_REQUIRE_KEY_BROADCAST BIT(1) + /** + * eapol_flags - Bit field of IEEE 802.1X/EAPOL options (EAPOL_FLAG_*) + */ + int eapol_flags; + + /** + * eap - EAP peer configuration for this network + */ + struct eap_peer_config eap; +#endif /* IEEE8021X_EAPOL */ + +#define NUM_WEP_KEYS 4 +#define MAX_WEP_KEY_LEN 16 + /** + * wep_key - WEP keys + */ + u8 wep_key[NUM_WEP_KEYS][MAX_WEP_KEY_LEN]; + + /** + * wep_key_len - WEP key lengths + */ + size_t wep_key_len[NUM_WEP_KEYS]; + + /** + * wep_tx_keyidx - Default key index for TX frames using WEP + */ + int wep_tx_keyidx; + + /** + * proactive_key_caching - Enable proactive key caching + * + * This field can be used to enable proactive key caching which is also + * known as opportunistic PMKSA caching for WPA2. This is disabled (0) + * by default. Enable by setting this to 1. + * + * Proactive key caching is used to make supplicant assume that the APs + * are using the same PMK and generate PMKSA cache entries without + * doing RSN pre-authentication. This requires support from the AP side + * and is normally used with wireless switches that co-locate the + * authenticator. + */ + int proactive_key_caching; + + /** + * mixed_cell - Whether mixed cells are allowed + * + * This option can be used to configure whether so called mixed cells, + * i.e., networks that use both plaintext and encryption in the same + * SSID, are allowed. This is disabled (0) by default. Enable by + * setting this to 1. + */ + int mixed_cell; + +#ifdef IEEE8021X_EAPOL + + /** + * leap - Number of EAP methods using LEAP + * + * This field should be set to 1 if LEAP is enabled. This is used to + * select IEEE 802.11 authentication algorithm. + */ + int leap; + + /** + * non_leap - Number of EAP methods not using LEAP + * + * This field should be set to >0 if any EAP method other than LEAP is + * enabled. This is used to select IEEE 802.11 authentication + * algorithm. + */ + int non_leap; + + /** + * eap_workaround - EAP workarounds enabled + * + * wpa_supplicant supports number of "EAP workarounds" to work around + * interoperability issues with incorrectly behaving authentication + * servers. This is recommended to be enabled by default because some + * of the issues are present in large number of authentication servers. + * + * Strict EAP conformance mode can be configured by disabling + * workarounds with eap_workaround = 0. + */ + unsigned int eap_workaround; + +#endif /* IEEE8021X_EAPOL */ + + /** + * mode - IEEE 802.11 operation mode (Infrastucture/IBSS) + * + * 0 = infrastructure (Managed) mode, i.e., associate with an AP. + * + * 1 = IBSS (ad-hoc, peer-to-peer) + * + * Note: IBSS can only be used with key_mgmt NONE (plaintext and + * static WEP) and key_mgmt=WPA-NONE (fixed group key TKIP/CCMP). In + * addition, ap_scan has to be set to 2 for IBSS. WPA-None requires + * following network block options: proto=WPA, key_mgmt=WPA-NONE, + * pairwise=NONE, group=TKIP (or CCMP, but not both), and psk must also + * be set (either directly or using ASCII passphrase). + */ + int mode; + + /** + * disabled - Whether this network is currently disabled + * + * 0 = this network can be used (default). + * 1 = this network block is disabled (can be enabled through + * ctrl_iface, e.g., with wpa_cli or wpa_gui). + */ + int disabled; + + /** + * peerkey - Whether PeerKey handshake for direct links is allowed + * + * This is only used when both RSN/WPA2 and IEEE 802.11e (QoS) are + * enabled. + * + * 0 = disabled (default) + * 1 = enabled + */ + int peerkey; + + /** + * id_str - Network identifier string for external scripts + * + * This value is passed to external ctrl_iface monitors in + * WPA_EVENT_CONNECTED event and wpa_cli sets this as WPA_ID_STR + * environment variable for action scripts. + */ + char *id_str; + +#ifdef CONFIG_IEEE80211W + /** + * ieee80211w - Whether management frame protection is enabled + * + * This value is used to configure policy for management frame + * protection (IEEE 802.11w). 0 = disabled, 1 = optional, 2 = required. + */ + enum { + NO_IEEE80211W = 0, + IEEE80211W_OPTIONAL = 1, + IEEE80211W_REQUIRED = 2 + } ieee80211w; +#endif /* CONFIG_IEEE80211W */ + + /** + * frequency - Channel frequency in megahertz (MHz) for IBSS + * + * This value is used to configure the initial channel for IBSS (adhoc) + * networks, e.g., 2412 = IEEE 802.11b/g channel 1. It is ignored in + * the infrastructure mode. In addition, this value is only used by the + * station that creates the IBSS. If an IBSS network with the + * configured SSID is already present, the frequency of the network + * will be used instead of this configured value. + */ + int frequency; + + /** + * wpa_ptk_rekey - Maximum lifetime for PTK in seconds + * + * This value can be used to enforce rekeying of PTK to mitigate some + * attacks against TKIP deficiencies. + */ + int wpa_ptk_rekey; +}; + +#endif /* CONFIG_SSID_H */ diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c new file mode 100644 index 000000000000..456d41792245 --- /dev/null +++ b/wpa_supplicant/config_winreg.c @@ -0,0 +1,980 @@ +/* + * WPA Supplicant / Configuration backend: Windows registry + * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + * + * This file implements a configuration backend for Windows registry. All the + * configuration information is stored in the registry and the format for + * network configuration fields is same as described in the sample + * configuration file, wpa_supplicant.conf. + * + * Configuration data is in + * \a HKEY_LOCAL_MACHINE\\SOFTWARE\\%wpa_supplicant\\configs + * key. Each configuration profile has its own key under this. In terms of text + * files, each profile would map to a separate text file with possibly multiple + * networks. Under each profile, there is a networks key that lists all + * networks as a subkey. Each network has set of values in the same way as + * network block in the configuration file. In addition, blobs subkey has + * possible blobs as values. + * + * Example network configuration block: + * \verbatim +HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\networks\0000 + ssid="example" + key_mgmt=WPA-PSK +\endverbatim + */ + +#include "includes.h" + +#include "common.h" +#include "uuid.h" +#include "config.h" + +#ifndef WPA_KEY_ROOT +#define WPA_KEY_ROOT HKEY_LOCAL_MACHINE +#endif +#ifndef WPA_KEY_PREFIX +#define WPA_KEY_PREFIX TEXT("SOFTWARE\\wpa_supplicant") +#endif + +#ifdef UNICODE +#define TSTR "%S" +#else /* UNICODE */ +#define TSTR "%s" +#endif /* UNICODE */ + + +static int wpa_config_read_blobs(struct wpa_config *config, HKEY hk) +{ + struct wpa_config_blob *blob; + int errors = 0; + HKEY bhk; + LONG ret; + DWORD i; + + ret = RegOpenKeyEx(hk, TEXT("blobs"), 0, KEY_QUERY_VALUE, &bhk); + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_DEBUG, "Could not open wpa_supplicant config " + "blobs key"); + return 0; /* assume no blobs */ + } + + for (i = 0; ; i++) { +#define TNAMELEN 255 + TCHAR name[TNAMELEN]; + char data[4096]; + DWORD namelen, datalen, type; + + namelen = TNAMELEN; + datalen = sizeof(data); + ret = RegEnumValue(bhk, i, name, &namelen, NULL, &type, + (LPBYTE) data, &datalen); + + if (ret == ERROR_NO_MORE_ITEMS) + break; + + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_DEBUG, "RegEnumValue failed: 0x%x", + (unsigned int) ret); + break; + } + + if (namelen >= TNAMELEN) + namelen = TNAMELEN - 1; + name[namelen] = TEXT('\0'); + wpa_unicode2ascii_inplace(name); + + if (datalen >= sizeof(data)) + datalen = sizeof(data) - 1; + + wpa_printf(MSG_MSGDUMP, "blob %d: field='%s' len %d", + (int) i, name, (int) datalen); + + blob = os_zalloc(sizeof(*blob)); + if (blob == NULL) { + errors++; + break; + } + blob->name = os_strdup((char *) name); + blob->data = os_malloc(datalen); + if (blob->name == NULL || blob->data == NULL) { + wpa_config_free_blob(blob); + errors++; + break; + } + os_memcpy(blob->data, data, datalen); + blob->len = datalen; + + wpa_config_set_blob(config, blob); + } + + RegCloseKey(bhk); + + return errors ? -1 : 0; +} + + +static int wpa_config_read_reg_dword(HKEY hk, const TCHAR *name, int *_val) +{ + DWORD val, buflen; + LONG ret; + + buflen = sizeof(val); + ret = RegQueryValueEx(hk, name, NULL, NULL, (LPBYTE) &val, &buflen); + if (ret == ERROR_SUCCESS && buflen == sizeof(val)) { + wpa_printf(MSG_DEBUG, TSTR "=%d", name, (int) val); + *_val = val; + return 0; + } + + return -1; +} + + +static char * wpa_config_read_reg_string(HKEY hk, const TCHAR *name) +{ + DWORD buflen; + LONG ret; + TCHAR *val; + + buflen = 0; + ret = RegQueryValueEx(hk, name, NULL, NULL, NULL, &buflen); + if (ret != ERROR_SUCCESS) + return NULL; + val = os_malloc(buflen); + if (val == NULL) + return NULL; + + ret = RegQueryValueEx(hk, name, NULL, NULL, (LPBYTE) val, &buflen); + if (ret != ERROR_SUCCESS) { + os_free(val); + return NULL; + } + + wpa_unicode2ascii_inplace(val); + wpa_printf(MSG_DEBUG, TSTR "=%s", name, (char *) val); + return (char *) val; +} + + +#ifdef CONFIG_WPS +static int wpa_config_read_global_uuid(struct wpa_config *config, HKEY hk) +{ + char *str; + int ret = 0; + + str = wpa_config_read_reg_string(hk, TEXT("uuid")); + if (str == NULL) + return 0; + + if (uuid_str2bin(str, config->uuid)) + ret = -1; + + os_free(str); + + return ret; +} + + +static int wpa_config_read_global_os_version(struct wpa_config *config, + HKEY hk) +{ + char *str; + int ret = 0; + + str = wpa_config_read_reg_string(hk, TEXT("os_version")); + if (str == NULL) + return 0; + + if (hexstr2bin(str, config->os_version, 4)) + ret = -1; + + os_free(str); + + return ret; +} +#endif /* CONFIG_WPS */ + + +static int wpa_config_read_global(struct wpa_config *config, HKEY hk) +{ + int errors = 0; + + wpa_config_read_reg_dword(hk, TEXT("ap_scan"), &config->ap_scan); + wpa_config_read_reg_dword(hk, TEXT("fast_reauth"), + &config->fast_reauth); + wpa_config_read_reg_dword(hk, TEXT("dot11RSNAConfigPMKLifetime"), + (int *) &config->dot11RSNAConfigPMKLifetime); + wpa_config_read_reg_dword(hk, + TEXT("dot11RSNAConfigPMKReauthThreshold"), + (int *) + &config->dot11RSNAConfigPMKReauthThreshold); + wpa_config_read_reg_dword(hk, TEXT("dot11RSNAConfigSATimeout"), + (int *) &config->dot11RSNAConfigSATimeout); + wpa_config_read_reg_dword(hk, TEXT("update_config"), + &config->update_config); + + if (wpa_config_read_reg_dword(hk, TEXT("eapol_version"), + &config->eapol_version) == 0) { + if (config->eapol_version < 1 || + config->eapol_version > 2) { + wpa_printf(MSG_ERROR, "Invalid EAPOL version (%d)", + config->eapol_version); + errors++; + } + } + + config->ctrl_interface = wpa_config_read_reg_string( + hk, TEXT("ctrl_interface")); + +#ifdef CONFIG_WPS + if (wpa_config_read_global_uuid(config, hk)) + errors++; + config->device_name = wpa_config_read_reg_string( + hk, TEXT("device_name")); + config->manufacturer = wpa_config_read_reg_string( + hk, TEXT("manufacturer")); + config->model_name = wpa_config_read_reg_string( + hk, TEXT("model_name")); + config->serial_number = wpa_config_read_reg_string( + hk, TEXT("serial_number")); + config->device_type = wpa_config_read_reg_string( + hk, TEXT("device_type")); + if (wpa_config_read_global_os_version(config, hk)) + errors++; + wpa_config_read_reg_dword(hk, TEXT("wps_cred_processing"), + &config->wps_cred_processing); +#endif /* CONFIG_WPS */ + + return errors ? -1 : 0; +} + + +static struct wpa_ssid * wpa_config_read_network(HKEY hk, const TCHAR *netw, + int id) +{ + HKEY nhk; + LONG ret; + DWORD i; + struct wpa_ssid *ssid; + int errors = 0; + + ret = RegOpenKeyEx(hk, netw, 0, KEY_QUERY_VALUE, &nhk); + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_DEBUG, "Could not open wpa_supplicant config " + "network '" TSTR "'", netw); + return NULL; + } + + wpa_printf(MSG_MSGDUMP, "Start of a new network '" TSTR "'", netw); + ssid = os_zalloc(sizeof(*ssid)); + if (ssid == NULL) { + RegCloseKey(nhk); + return NULL; + } + ssid->id = id; + + wpa_config_set_network_defaults(ssid); + + for (i = 0; ; i++) { + TCHAR name[255], data[1024]; + DWORD namelen, datalen, type; + + namelen = 255; + datalen = sizeof(data); + ret = RegEnumValue(nhk, i, name, &namelen, NULL, &type, + (LPBYTE) data, &datalen); + + if (ret == ERROR_NO_MORE_ITEMS) + break; + + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_ERROR, "RegEnumValue failed: 0x%x", + (unsigned int) ret); + break; + } + + if (namelen >= 255) + namelen = 255 - 1; + name[namelen] = TEXT('\0'); + + if (datalen >= 1024) + datalen = 1024 - 1; + data[datalen] = TEXT('\0'); + + wpa_unicode2ascii_inplace(name); + wpa_unicode2ascii_inplace(data); + if (wpa_config_set(ssid, (char *) name, (char *) data, 0) < 0) + errors++; + } + + RegCloseKey(nhk); + + if (ssid->passphrase) { + if (ssid->psk_set) { + wpa_printf(MSG_ERROR, "Both PSK and passphrase " + "configured for network '" TSTR "'.", netw); + errors++; + } + wpa_config_update_psk(ssid); + } + + if ((ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK | + WPA_KEY_MGMT_PSK_SHA256)) && + !ssid->psk_set) { + wpa_printf(MSG_ERROR, "WPA-PSK accepted for key management, " + "but no PSK configured for network '" TSTR "'.", + netw); + errors++; + } + + if ((ssid->group_cipher & WPA_CIPHER_CCMP) && + !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) && + !(ssid->pairwise_cipher & WPA_CIPHER_NONE)) { + /* Group cipher cannot be stronger than the pairwise cipher. */ + wpa_printf(MSG_DEBUG, "Removed CCMP from group cipher " + "list since it was not allowed for pairwise " + "cipher for network '" TSTR "'.", netw); + ssid->group_cipher &= ~WPA_CIPHER_CCMP; + } + + if (errors) { + wpa_config_free_ssid(ssid); + ssid = NULL; + } + + return ssid; +} + + +static int wpa_config_read_networks(struct wpa_config *config, HKEY hk) +{ + HKEY nhk; + struct wpa_ssid *ssid, *tail = NULL, *head = NULL; + int errors = 0; + LONG ret; + DWORD i; + + ret = RegOpenKeyEx(hk, TEXT("networks"), 0, KEY_ENUMERATE_SUB_KEYS, + &nhk); + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_ERROR, "Could not open wpa_supplicant networks " + "registry key"); + return -1; + } + + for (i = 0; ; i++) { + TCHAR name[255]; + DWORD namelen; + + namelen = 255; + ret = RegEnumKeyEx(nhk, i, name, &namelen, NULL, NULL, NULL, + NULL); + + if (ret == ERROR_NO_MORE_ITEMS) + break; + + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_DEBUG, "RegEnumKeyEx failed: 0x%x", + (unsigned int) ret); + break; + } + + if (namelen >= 255) + namelen = 255 - 1; + name[namelen] = '\0'; + + ssid = wpa_config_read_network(nhk, name, i); + if (ssid == NULL) { + wpa_printf(MSG_ERROR, "Failed to parse network " + "profile '%s'.", name); + errors++; + continue; + } + if (head == NULL) { + head = tail = ssid; + } else { + tail->next = ssid; + tail = ssid; + } + if (wpa_config_add_prio_network(config, ssid)) { + wpa_printf(MSG_ERROR, "Failed to add network profile " + "'%s' to priority list.", name); + errors++; + continue; + } + } + + RegCloseKey(nhk); + + config->ssid = head; + + return errors ? -1 : 0; +} + + +struct wpa_config * wpa_config_read(const char *name) +{ + TCHAR buf[256]; + int errors = 0; + struct wpa_config *config; + HKEY hk; + LONG ret; + + config = wpa_config_alloc_empty(NULL, NULL); + if (config == NULL) + return NULL; + wpa_printf(MSG_DEBUG, "Reading configuration profile '%s'", name); + +#ifdef UNICODE + _snwprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%S"), name); +#else /* UNICODE */ + os_snprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%s"), name); +#endif /* UNICODE */ + + ret = RegOpenKeyEx(WPA_KEY_ROOT, buf, 0, KEY_QUERY_VALUE, &hk); + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_ERROR, "Could not open wpa_supplicant " + "configuration registry HKLM\\" TSTR, buf); + os_free(config); + return NULL; + } + + if (wpa_config_read_global(config, hk)) + errors++; + + if (wpa_config_read_networks(config, hk)) + errors++; + + if (wpa_config_read_blobs(config, hk)) + errors++; + + wpa_config_debug_dump_networks(config); + + RegCloseKey(hk); + + if (errors) { + wpa_config_free(config); + config = NULL; + } + + return config; +} + + +static int wpa_config_write_reg_dword(HKEY hk, const TCHAR *name, int val, + int def) +{ + LONG ret; + DWORD _val = val; + + if (val == def) { + RegDeleteValue(hk, name); + return 0; + } + + ret = RegSetValueEx(hk, name, 0, REG_DWORD, (LPBYTE) &_val, + sizeof(_val)); + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_ERROR, "WINREG: Failed to set %s=%d: error %d", + name, val, (int) GetLastError()); + return -1; + } + + return 0; +} + + +static int wpa_config_write_reg_string(HKEY hk, const char *name, + const char *val) +{ + LONG ret; + TCHAR *_name, *_val; + + _name = wpa_strdup_tchar(name); + if (_name == NULL) + return -1; + + if (val == NULL) { + RegDeleteValue(hk, _name); + os_free(_name); + return 0; + } + + _val = wpa_strdup_tchar(val); + if (_val == NULL) { + os_free(_name); + return -1; + } + ret = RegSetValueEx(hk, _name, 0, REG_SZ, (BYTE *) _val, + (os_strlen(val) + 1) * sizeof(TCHAR)); + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_ERROR, "WINREG: Failed to set %s='%s': " + "error %d", name, val, (int) GetLastError()); + os_free(_name); + os_free(_val); + return -1; + } + + os_free(_name); + os_free(_val); + return 0; +} + + +static int wpa_config_write_global(struct wpa_config *config, HKEY hk) +{ +#ifdef CONFIG_CTRL_IFACE + wpa_config_write_reg_string(hk, "ctrl_interface", + config->ctrl_interface); +#endif /* CONFIG_CTRL_IFACE */ + + wpa_config_write_reg_dword(hk, TEXT("eapol_version"), + config->eapol_version, + DEFAULT_EAPOL_VERSION); + wpa_config_write_reg_dword(hk, TEXT("ap_scan"), config->ap_scan, + DEFAULT_AP_SCAN); + wpa_config_write_reg_dword(hk, TEXT("fast_reauth"), + config->fast_reauth, DEFAULT_FAST_REAUTH); + wpa_config_write_reg_dword(hk, TEXT("dot11RSNAConfigPMKLifetime"), + config->dot11RSNAConfigPMKLifetime, 0); + wpa_config_write_reg_dword(hk, + TEXT("dot11RSNAConfigPMKReauthThreshold"), + config->dot11RSNAConfigPMKReauthThreshold, + 0); + wpa_config_write_reg_dword(hk, TEXT("dot11RSNAConfigSATimeout"), + config->dot11RSNAConfigSATimeout, 0); + wpa_config_write_reg_dword(hk, TEXT("update_config"), + config->update_config, + 0); +#ifdef CONFIG_WPS + if (!is_nil_uuid(config->uuid)) { + char buf[40]; + uuid_bin2str(config->uuid, buf, sizeof(buf)); + wpa_config_write_reg_string(hk, "uuid", buf); + } + wpa_config_write_reg_string(hk, "device_name", config->device_name); + wpa_config_write_reg_string(hk, "manufacturer", config->manufacturer); + wpa_config_write_reg_string(hk, "model_name", config->model_name); + wpa_config_write_reg_string(hk, "model_number", config->model_number); + wpa_config_write_reg_string(hk, "serial_number", + config->serial_number); + wpa_config_write_reg_string(hk, "device_type", config->device_type); + if (WPA_GET_BE32(config->os_version)) { + char vbuf[10]; + os_snprintf(vbuf, sizeof(vbuf), "%08x", + WPA_GET_BE32(config->os_version)); + wpa_config_write_reg_string(hk, "os_version", vbuf); + } + wpa_config_write_reg_dword(hk, TEXT("wps_cred_processing"), + config->wps_cred_processing, 0); +#endif /* CONFIG_WPS */ + + return 0; +} + + +static int wpa_config_delete_subkeys(HKEY hk, const TCHAR *key) +{ + HKEY nhk; + int i, errors = 0; + LONG ret; + + ret = RegOpenKeyEx(hk, key, 0, KEY_ENUMERATE_SUB_KEYS | DELETE, &nhk); + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_DEBUG, "WINREG: Could not open key '" TSTR + "' for subkey deletion: error 0x%x (%d)", key, + (unsigned int) ret, (int) GetLastError()); + return 0; + } + + for (i = 0; ; i++) { + TCHAR name[255]; + DWORD namelen; + + namelen = 255; + ret = RegEnumKeyEx(nhk, i, name, &namelen, NULL, NULL, NULL, + NULL); + + if (ret == ERROR_NO_MORE_ITEMS) + break; + + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_DEBUG, "RegEnumKeyEx failed: 0x%x (%d)", + (unsigned int) ret, (int) GetLastError()); + break; + } + + if (namelen >= 255) + namelen = 255 - 1; + name[namelen] = TEXT('\0'); + + ret = RegDeleteKey(nhk, name); + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_DEBUG, "RegDeleteKey failed: 0x%x (%d)", + (unsigned int) ret, (int) GetLastError()); + errors++; + } + } + + RegCloseKey(nhk); + + return errors ? -1 : 0; +} + + +static void write_str(HKEY hk, const char *field, struct wpa_ssid *ssid) +{ + char *value = wpa_config_get(ssid, field); + if (value == NULL) + return; + wpa_config_write_reg_string(hk, field, value); + os_free(value); +} + + +static void write_int(HKEY hk, const char *field, int value, int def) +{ + char val[20]; + if (value == def) + return; + os_snprintf(val, sizeof(val), "%d", value); + wpa_config_write_reg_string(hk, field, val); +} + + +static void write_bssid(HKEY hk, struct wpa_ssid *ssid) +{ + char *value = wpa_config_get(ssid, "bssid"); + if (value == NULL) + return; + wpa_config_write_reg_string(hk, "bssid", value); + os_free(value); +} + + +static void write_psk(HKEY hk, struct wpa_ssid *ssid) +{ + char *value = wpa_config_get(ssid, "psk"); + if (value == NULL) + return; + wpa_config_write_reg_string(hk, "psk", value); + os_free(value); +} + + +static void write_proto(HKEY hk, struct wpa_ssid *ssid) +{ + char *value; + + if (ssid->proto == DEFAULT_PROTO) + return; + + value = wpa_config_get(ssid, "proto"); + if (value == NULL) + return; + if (value[0]) + wpa_config_write_reg_string(hk, "proto", value); + os_free(value); +} + + +static void write_key_mgmt(HKEY hk, struct wpa_ssid *ssid) +{ + char *value; + + if (ssid->key_mgmt == DEFAULT_KEY_MGMT) + return; + + value = wpa_config_get(ssid, "key_mgmt"); + if (value == NULL) + return; + if (value[0]) + wpa_config_write_reg_string(hk, "key_mgmt", value); + os_free(value); +} + + +static void write_pairwise(HKEY hk, struct wpa_ssid *ssid) +{ + char *value; + + if (ssid->pairwise_cipher == DEFAULT_PAIRWISE) + return; + + value = wpa_config_get(ssid, "pairwise"); + if (value == NULL) + return; + if (value[0]) + wpa_config_write_reg_string(hk, "pairwise", value); + os_free(value); +} + + +static void write_group(HKEY hk, struct wpa_ssid *ssid) +{ + char *value; + + if (ssid->group_cipher == DEFAULT_GROUP) + return; + + value = wpa_config_get(ssid, "group"); + if (value == NULL) + return; + if (value[0]) + wpa_config_write_reg_string(hk, "group", value); + os_free(value); +} + + +static void write_auth_alg(HKEY hk, struct wpa_ssid *ssid) +{ + char *value; + + if (ssid->auth_alg == 0) + return; + + value = wpa_config_get(ssid, "auth_alg"); + if (value == NULL) + return; + if (value[0]) + wpa_config_write_reg_string(hk, "auth_alg", value); + os_free(value); +} + + +#ifdef IEEE8021X_EAPOL +static void write_eap(HKEY hk, struct wpa_ssid *ssid) +{ + char *value; + + value = wpa_config_get(ssid, "eap"); + if (value == NULL) + return; + + if (value[0]) + wpa_config_write_reg_string(hk, "eap", value); + os_free(value); +} +#endif /* IEEE8021X_EAPOL */ + + +static void write_wep_key(HKEY hk, int idx, struct wpa_ssid *ssid) +{ + char field[20], *value; + + os_snprintf(field, sizeof(field), "wep_key%d", idx); + value = wpa_config_get(ssid, field); + if (value) { + wpa_config_write_reg_string(hk, field, value); + os_free(value); + } +} + + +static int wpa_config_write_network(HKEY hk, struct wpa_ssid *ssid, int id) +{ + int i, errors = 0; + HKEY nhk, netw; + LONG ret; + TCHAR name[5]; + + ret = RegOpenKeyEx(hk, TEXT("networks"), 0, KEY_CREATE_SUB_KEY, &nhk); + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_DEBUG, "WINREG: Could not open networks key " + "for subkey addition: error 0x%x (%d)", + (unsigned int) ret, (int) GetLastError()); + return 0; + } + +#ifdef UNICODE + wsprintf(name, L"%04d", id); +#else /* UNICODE */ + os_snprintf(name, sizeof(name), "%04d", id); +#endif /* UNICODE */ + ret = RegCreateKeyEx(nhk, name, 0, NULL, 0, KEY_WRITE, NULL, &netw, + NULL); + RegCloseKey(nhk); + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_DEBUG, "WINREG: Could not add network key '%s':" + " error 0x%x (%d)", + name, (unsigned int) ret, (int) GetLastError()); + return -1; + } + +#define STR(t) write_str(netw, #t, ssid) +#define INT(t) write_int(netw, #t, ssid->t, 0) +#define INTe(t) write_int(netw, #t, ssid->eap.t, 0) +#define INT_DEF(t, def) write_int(netw, #t, ssid->t, def) +#define INT_DEFe(t, def) write_int(netw, #t, ssid->eap.t, def) + + STR(ssid); + INT(scan_ssid); + write_bssid(netw, ssid); + write_psk(netw, ssid); + write_proto(netw, ssid); + write_key_mgmt(netw, ssid); + write_pairwise(netw, ssid); + write_group(netw, ssid); + write_auth_alg(netw, ssid); +#ifdef IEEE8021X_EAPOL + write_eap(netw, ssid); + STR(identity); + STR(anonymous_identity); + STR(password); + STR(ca_cert); + STR(ca_path); + STR(client_cert); + STR(private_key); + STR(private_key_passwd); + STR(dh_file); + STR(subject_match); + STR(altsubject_match); + STR(ca_cert2); + STR(ca_path2); + STR(client_cert2); + STR(private_key2); + STR(private_key2_passwd); + STR(dh_file2); + STR(subject_match2); + STR(altsubject_match2); + STR(phase1); + STR(phase2); + STR(pcsc); + STR(pin); + STR(engine_id); + STR(key_id); + STR(cert_id); + STR(ca_cert_id); + STR(key2_id); + STR(pin2); + STR(engine2_id); + STR(cert2_id); + STR(ca_cert2_id); + INTe(engine); + INTe(engine2); + INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS); +#endif /* IEEE8021X_EAPOL */ + for (i = 0; i < 4; i++) + write_wep_key(netw, i, ssid); + INT(wep_tx_keyidx); + INT(priority); +#ifdef IEEE8021X_EAPOL + INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND); + STR(pac_file); + INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE); +#endif /* IEEE8021X_EAPOL */ + INT(mode); + INT(proactive_key_caching); + INT(disabled); + INT(peerkey); +#ifdef CONFIG_IEEE80211W + INT(ieee80211w); +#endif /* CONFIG_IEEE80211W */ + STR(id_str); + +#undef STR +#undef INT +#undef INT_DEF + + RegCloseKey(netw); + + return errors ? -1 : 0; +} + + +static int wpa_config_write_blob(HKEY hk, struct wpa_config_blob *blob) +{ + HKEY bhk; + LONG ret; + TCHAR *name; + + ret = RegCreateKeyEx(hk, TEXT("blobs"), 0, NULL, 0, KEY_WRITE, NULL, + &bhk, NULL); + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_DEBUG, "WINREG: Could not add blobs key: " + "error 0x%x (%d)", + (unsigned int) ret, (int) GetLastError()); + return -1; + } + + name = wpa_strdup_tchar(blob->name); + ret = RegSetValueEx(bhk, name, 0, REG_BINARY, blob->data, + blob->len); + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_ERROR, "WINREG: Failed to set blob %s': " + "error 0x%x (%d)", blob->name, (unsigned int) ret, + (int) GetLastError()); + RegCloseKey(bhk); + os_free(name); + return -1; + } + os_free(name); + + RegCloseKey(bhk); + + return 0; +} + + +int wpa_config_write(const char *name, struct wpa_config *config) +{ + TCHAR buf[256]; + HKEY hk; + LONG ret; + int errors = 0; + struct wpa_ssid *ssid; + struct wpa_config_blob *blob; + int id; + + wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", name); + +#ifdef UNICODE + _snwprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%S"), name); +#else /* UNICODE */ + os_snprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%s"), name); +#endif /* UNICODE */ + + ret = RegOpenKeyEx(WPA_KEY_ROOT, buf, 0, KEY_SET_VALUE | DELETE, &hk); + if (ret != ERROR_SUCCESS) { + wpa_printf(MSG_ERROR, "Could not open wpa_supplicant " + "configuration registry %s: error %d", buf, + (int) GetLastError()); + return -1; + } + + if (wpa_config_write_global(config, hk)) { + wpa_printf(MSG_ERROR, "Failed to write global configuration " + "data"); + errors++; + } + + wpa_config_delete_subkeys(hk, TEXT("networks")); + for (ssid = config->ssid, id = 0; ssid; ssid = ssid->next, id++) { + if (ssid->key_mgmt == WPA_KEY_MGMT_WPS) + continue; /* do not save temporary WPS networks */ + if (wpa_config_write_network(hk, ssid, id)) + errors++; + } + + RegDeleteKey(hk, TEXT("blobs")); + for (blob = config->blobs; blob; blob = blob->next) { + if (wpa_config_write_blob(hk, blob)) + errors++; + } + + RegCloseKey(hk); + + wpa_printf(MSG_DEBUG, "Configuration '%s' written %ssuccessfully", + name, errors ? "un" : ""); + return errors ? -1 : 0; +} diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c new file mode 100644 index 000000000000..2b737bc1aa56 --- /dev/null +++ b/wpa_supplicant/ctrl_iface.c @@ -0,0 +1,1875 @@ +/* + * WPA Supplicant / Control interface (shared code for all backends) + * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "eloop.h" +#include "wpa.h" +#include "config.h" +#include "eapol_supp/eapol_supp_sm.h" +#include "wpa_supplicant_i.h" +#include "ctrl_iface.h" +#include "l2_packet/l2_packet.h" +#include "preauth.h" +#include "pmksa_cache.h" +#include "wpa_ctrl.h" +#include "eap_peer/eap.h" +#include "ieee802_11_defs.h" +#include "wps_supplicant.h" +#include "wps/wps.h" + +static int wpa_supplicant_global_iface_list(struct wpa_global *global, + char *buf, int len); +static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global, + char *buf, int len); + + +static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, + char *cmd) +{ + char *value; + int ret = 0; + + value = os_strchr(cmd, ' '); + if (value == NULL) + return -1; + *value++ = '\0'; + + wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value); + if (os_strcasecmp(cmd, "EAPOL::heldPeriod") == 0) { + eapol_sm_configure(wpa_s->eapol, + atoi(value), -1, -1, -1); + } else if (os_strcasecmp(cmd, "EAPOL::authPeriod") == 0) { + eapol_sm_configure(wpa_s->eapol, + -1, atoi(value), -1, -1); + } else if (os_strcasecmp(cmd, "EAPOL::startPeriod") == 0) { + eapol_sm_configure(wpa_s->eapol, + -1, -1, atoi(value), -1); + } else if (os_strcasecmp(cmd, "EAPOL::maxStart") == 0) { + eapol_sm_configure(wpa_s->eapol, + -1, -1, -1, atoi(value)); + } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) { + if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, + atoi(value))) + ret = -1; + } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") == + 0) { + if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD, + atoi(value))) + ret = -1; + } else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) { + if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, atoi(value))) + ret = -1; + } else + ret = -1; + + return ret; +} + + +#ifdef IEEE8021X_EAPOL +static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s, + char *addr) +{ + u8 bssid[ETH_ALEN]; + struct wpa_ssid *ssid = wpa_s->current_ssid; + + if (hwaddr_aton(addr, bssid)) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH: invalid address " + "'%s'", addr); + return -1; + } + + wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH " MACSTR, MAC2STR(bssid)); + rsn_preauth_deinit(wpa_s->wpa); + if (rsn_preauth_init(wpa_s->wpa, bssid, ssid ? &ssid->eap : NULL)) + return -1; + + return 0; +} +#endif /* IEEE8021X_EAPOL */ + + +#ifdef CONFIG_PEERKEY +/* MLME-STKSTART.request(peer) */ +static int wpa_supplicant_ctrl_iface_stkstart( + struct wpa_supplicant *wpa_s, char *addr) +{ + u8 peer[ETH_ALEN]; + + if (hwaddr_aton(addr, peer)) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART: invalid " + "address '%s'", peer); + return -1; + } + + wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART " MACSTR, + MAC2STR(peer)); + + return wpa_sm_stkstart(wpa_s->wpa, peer); +} +#endif /* CONFIG_PEERKEY */ + + +#ifdef CONFIG_IEEE80211R +static int wpa_supplicant_ctrl_iface_ft_ds( + struct wpa_supplicant *wpa_s, char *addr) +{ + u8 target_ap[ETH_ALEN]; + + if (hwaddr_aton(addr, target_ap)) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS: invalid " + "address '%s'", target_ap); + return -1; + } + + wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS " MACSTR, MAC2STR(target_ap)); + + return wpa_ft_start_over_ds(wpa_s->wpa, target_ap); +} +#endif /* CONFIG_IEEE80211R */ + + +#ifdef CONFIG_WPS +static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s, + char *cmd) +{ + u8 bssid[ETH_ALEN]; + + if (cmd == NULL || os_strcmp(cmd, "any") == 0) + return wpas_wps_start_pbc(wpa_s, NULL); + + if (hwaddr_aton(cmd, bssid)) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'", + cmd); + return -1; + } + + return wpas_wps_start_pbc(wpa_s, bssid); +} + + +static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s, + char *cmd, char *buf, + size_t buflen) +{ + u8 bssid[ETH_ALEN], *_bssid = bssid; + char *pin; + int ret; + + pin = os_strchr(cmd, ' '); + if (pin) + *pin++ = '\0'; + + if (os_strcmp(cmd, "any") == 0) + _bssid = NULL; + else if (hwaddr_aton(cmd, bssid)) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'", + cmd); + return -1; + } + + if (pin) { + ret = wpas_wps_start_pin(wpa_s, _bssid, pin); + if (ret < 0) + return -1; + ret = os_snprintf(buf, buflen, "%s", pin); + if (ret < 0 || (size_t) ret >= buflen) + return -1; + return ret; + } + + ret = wpas_wps_start_pin(wpa_s, _bssid, NULL); + if (ret < 0) + return -1; + + /* Return the generated PIN */ + ret = os_snprintf(buf, buflen, "%08d", ret); + if (ret < 0 || (size_t) ret >= buflen) + return -1; + return ret; +} + + +static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s, + char *cmd) +{ + u8 bssid[ETH_ALEN], *_bssid = bssid; + char *pin; + + pin = os_strchr(cmd, ' '); + if (pin == NULL) + return -1; + *pin++ = '\0'; + + if (os_strcmp(cmd, "any") == 0) + _bssid = NULL; + else if (hwaddr_aton(cmd, bssid)) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_REG: invalid BSSID '%s'", + cmd); + return -1; + } + + return wpas_wps_start_reg(wpa_s, _bssid, pin); +} +#endif /* CONFIG_WPS */ + + +static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s, + char *rsp) +{ +#ifdef IEEE8021X_EAPOL + char *pos, *id_pos; + int id; + struct wpa_ssid *ssid; + struct eap_peer_config *eap; + + pos = os_strchr(rsp, '-'); + if (pos == NULL) + return -1; + *pos++ = '\0'; + id_pos = pos; + pos = os_strchr(pos, ':'); + if (pos == NULL) + return -1; + *pos++ = '\0'; + id = atoi(id_pos); + wpa_printf(MSG_DEBUG, "CTRL_IFACE: field=%s id=%d", rsp, id); + wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value", + (u8 *) pos, os_strlen(pos)); + + ssid = wpa_config_get_network(wpa_s->conf, id); + if (ssid == NULL) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d " + "to update", id); + return -1; + } + eap = &ssid->eap; + + if (os_strcmp(rsp, "IDENTITY") == 0) { + os_free(eap->identity); + eap->identity = (u8 *) os_strdup(pos); + eap->identity_len = os_strlen(pos); + eap->pending_req_identity = 0; + if (ssid == wpa_s->current_ssid) + wpa_s->reassociate = 1; + } else if (os_strcmp(rsp, "PASSWORD") == 0) { + os_free(eap->password); + eap->password = (u8 *) os_strdup(pos); + eap->password_len = os_strlen(pos); + eap->pending_req_password = 0; + if (ssid == wpa_s->current_ssid) + wpa_s->reassociate = 1; + } else if (os_strcmp(rsp, "NEW_PASSWORD") == 0) { + os_free(eap->new_password); + eap->new_password = (u8 *) os_strdup(pos); + eap->new_password_len = os_strlen(pos); + eap->pending_req_new_password = 0; + if (ssid == wpa_s->current_ssid) + wpa_s->reassociate = 1; + } else if (os_strcmp(rsp, "PIN") == 0) { + os_free(eap->pin); + eap->pin = os_strdup(pos); + eap->pending_req_pin = 0; + if (ssid == wpa_s->current_ssid) + wpa_s->reassociate = 1; + } else if (os_strcmp(rsp, "OTP") == 0) { + os_free(eap->otp); + eap->otp = (u8 *) os_strdup(pos); + eap->otp_len = os_strlen(pos); + os_free(eap->pending_req_otp); + eap->pending_req_otp = NULL; + eap->pending_req_otp_len = 0; + } else if (os_strcmp(rsp, "PASSPHRASE") == 0) { + os_free(eap->private_key_passwd); + eap->private_key_passwd = (u8 *) os_strdup(pos); + eap->pending_req_passphrase = 0; + if (ssid == wpa_s->current_ssid) + wpa_s->reassociate = 1; + } else { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", rsp); + return -1; + } + + return 0; +#else /* IEEE8021X_EAPOL */ + wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included"); + return -1; +#endif /* IEEE8021X_EAPOL */ +} + + +static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s, + const char *params, + char *buf, size_t buflen) +{ + char *pos, *end, tmp[30]; + int res, verbose, ret; + + verbose = os_strcmp(params, "-VERBOSE") == 0; + pos = buf; + end = buf + buflen; + if (wpa_s->wpa_state >= WPA_ASSOCIATED) { + struct wpa_ssid *ssid = wpa_s->current_ssid; + ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n", + MAC2STR(wpa_s->bssid)); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + if (ssid) { + u8 *_ssid = ssid->ssid; + size_t ssid_len = ssid->ssid_len; + u8 ssid_buf[MAX_SSID_LEN]; + if (ssid_len == 0) { + int _res = wpa_drv_get_ssid(wpa_s, ssid_buf); + if (_res < 0) + ssid_len = 0; + else + ssid_len = _res; + _ssid = ssid_buf; + } + ret = os_snprintf(pos, end - pos, "ssid=%s\nid=%d\n", + wpa_ssid_txt(_ssid, ssid_len), + ssid->id); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + + if (ssid->id_str) { + ret = os_snprintf(pos, end - pos, + "id_str=%s\n", + ssid->id_str); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + } + } + + pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose); + } + ret = os_snprintf(pos, end - pos, "wpa_state=%s\n", + wpa_supplicant_state_txt(wpa_s->wpa_state)); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + + if (wpa_s->l2 && + l2_packet_get_ip_addr(wpa_s->l2, tmp, sizeof(tmp)) >= 0) { + ret = os_snprintf(pos, end - pos, "ip_address=%s\n", tmp); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + } + + if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) || + wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { + res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos, + verbose); + if (res >= 0) + pos += res; + } + + res = rsn_preauth_get_status(wpa_s->wpa, pos, end - pos, verbose); + if (res >= 0) + pos += res; + + return pos - buf; +} + + +static int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s, + char *cmd) +{ + char *pos; + int id; + struct wpa_ssid *ssid; + u8 bssid[ETH_ALEN]; + + /* cmd: "<network id> <BSSID>" */ + pos = os_strchr(cmd, ' '); + if (pos == NULL) + return -1; + *pos++ = '\0'; + id = atoi(cmd); + wpa_printf(MSG_DEBUG, "CTRL_IFACE: id=%d bssid='%s'", id, pos); + if (hwaddr_aton(pos, bssid)) { + wpa_printf(MSG_DEBUG ,"CTRL_IFACE: invalid BSSID '%s'", pos); + return -1; + } + + ssid = wpa_config_get_network(wpa_s->conf, id); + if (ssid == NULL) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d " + "to update", id); + return -1; + } + + os_memcpy(ssid->bssid, bssid, ETH_ALEN); + ssid->bssid_set = !is_zero_ether_addr(bssid); + + return 0; +} + + +static int wpa_supplicant_ctrl_iface_list_networks( + struct wpa_supplicant *wpa_s, char *buf, size_t buflen) +{ + char *pos, *end; + struct wpa_ssid *ssid; + int ret; + + pos = buf; + end = buf + buflen; + ret = os_snprintf(pos, end - pos, + "network id / ssid / bssid / flags\n"); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + + ssid = wpa_s->conf->ssid; + while (ssid) { + ret = os_snprintf(pos, end - pos, "%d\t%s", + ssid->id, + wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + if (ssid->bssid_set) { + ret = os_snprintf(pos, end - pos, "\t" MACSTR, + MAC2STR(ssid->bssid)); + } else { + ret = os_snprintf(pos, end - pos, "\tany"); + } + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + ret = os_snprintf(pos, end - pos, "\t%s%s", + ssid == wpa_s->current_ssid ? + "[CURRENT]" : "", + ssid->disabled ? "[DISABLED]" : ""); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + ret = os_snprintf(pos, end - pos, "\n"); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + + ssid = ssid->next; + } + + return pos - buf; +} + + +static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher) +{ + int first = 1, ret; + ret = os_snprintf(pos, end - pos, "-"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; + if (cipher & WPA_CIPHER_NONE) { + ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : "+"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; + first = 0; + } + if (cipher & WPA_CIPHER_WEP40) { + ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : "+"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; + first = 0; + } + if (cipher & WPA_CIPHER_WEP104) { + ret = os_snprintf(pos, end - pos, "%sWEP104", + first ? "" : "+"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; + first = 0; + } + if (cipher & WPA_CIPHER_TKIP) { + ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : "+"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; + first = 0; + } + if (cipher & WPA_CIPHER_CCMP) { + ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : "+"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; + first = 0; + } + return pos; +} + + +static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto, + const u8 *ie, size_t ie_len) +{ + struct wpa_ie_data data; + int first, ret; + + ret = os_snprintf(pos, end - pos, "[%s-", proto); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; + + if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) { + ret = os_snprintf(pos, end - pos, "?]"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; + return pos; + } + + first = 1; + if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) { + ret = os_snprintf(pos, end - pos, "%sEAP", first ? "" : "+"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; + first = 0; + } + if (data.key_mgmt & WPA_KEY_MGMT_PSK) { + ret = os_snprintf(pos, end - pos, "%sPSK", first ? "" : "+"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; + first = 0; + } + if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) { + ret = os_snprintf(pos, end - pos, "%sNone", first ? "" : "+"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; + first = 0; + } +#ifdef CONFIG_IEEE80211R + if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) { + ret = os_snprintf(pos, end - pos, "%sFT/EAP", + first ? "" : "+"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; + first = 0; + } + if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) { + ret = os_snprintf(pos, end - pos, "%sFT/PSK", + first ? "" : "+"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; + first = 0; + } +#endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_IEEE80211W + if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) { + ret = os_snprintf(pos, end - pos, "%sEAP-SHA256", + first ? "" : "+"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; + first = 0; + } + if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) { + ret = os_snprintf(pos, end - pos, "%sPSK-SHA256", + first ? "" : "+"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; + first = 0; + } +#endif /* CONFIG_IEEE80211W */ + + pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher); + + if (data.capabilities & WPA_CAPABILITY_PREAUTH) { + ret = os_snprintf(pos, end - pos, "-preauth"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; + } + + ret = os_snprintf(pos, end - pos, "]"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; + + return pos; +} + +static char * wpa_supplicant_wps_ie_txt(char *pos, char *end, + const struct wpa_scan_res *res) +{ +#ifdef CONFIG_WPS + struct wpabuf *wps_ie; + int ret; + const char *txt; + + wps_ie = wpa_scan_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE); + if (wps_ie == NULL) + return pos; + + if (wps_is_selected_pbc_registrar(wps_ie)) + txt = "[WPS-PBC]"; + else if (wps_is_selected_pin_registrar(wps_ie)) + txt = "[WPS-PIN]"; + else + txt = "[WPS]"; + + ret = os_snprintf(pos, end - pos, "%s", txt); + if (ret >= 0 && ret < end - pos) + pos += ret; + wpabuf_free(wps_ie); +#endif /* CONFIG_WPS */ + + return pos; +} + + +/* Format one result on one text line into a buffer. */ +static int wpa_supplicant_ctrl_iface_scan_result( + const struct wpa_scan_res *res, char *buf, size_t buflen) +{ + char *pos, *end; + int ret; + const u8 *ie, *ie2; + + pos = buf; + end = buf + buflen; + + ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t", + MAC2STR(res->bssid), res->freq, res->level); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + ie = wpa_scan_get_vendor_ie(res, WPA_IE_VENDOR_TYPE); + if (ie) + pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]); + ie2 = wpa_scan_get_ie(res, WLAN_EID_RSN); + if (ie2) + pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]); + pos = wpa_supplicant_wps_ie_txt(pos, end, res); + if (!ie && !ie2 && res->caps & IEEE80211_CAP_PRIVACY) { + ret = os_snprintf(pos, end - pos, "[WEP]"); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + } + if (res->caps & IEEE80211_CAP_IBSS) { + ret = os_snprintf(pos, end - pos, "[IBSS]"); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + } + + ie = wpa_scan_get_ie(res, WLAN_EID_SSID); + ret = os_snprintf(pos, end - pos, "\t%s", + ie ? wpa_ssid_txt(ie + 2, ie[1]) : ""); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + + ret = os_snprintf(pos, end - pos, "\n"); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + + return pos - buf; +} + + +static int wpa_supplicant_ctrl_iface_scan_results( + struct wpa_supplicant *wpa_s, char *buf, size_t buflen) +{ + char *pos, *end; + struct wpa_scan_res *res; + int ret; + size_t i; + + if (wpa_s->scan_res == NULL && + wpa_supplicant_get_scan_results(wpa_s) < 0) + return 0; + + pos = buf; + end = buf + buflen; + ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / " + "flags / ssid\n"); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + + for (i = 0; i < wpa_s->scan_res->num; i++) { + res = wpa_s->scan_res->res[i]; + ret = wpa_supplicant_ctrl_iface_scan_result(res, pos, + end - pos); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + } + + return pos - buf; +} + + +static int wpa_supplicant_ctrl_iface_select_network( + struct wpa_supplicant *wpa_s, char *cmd) +{ + int id; + struct wpa_ssid *ssid; + + /* cmd: "<network id>" or "any" */ + if (os_strcmp(cmd, "any") == 0) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK any"); + ssid = wpa_s->conf->ssid; + while (ssid) { + ssid->disabled = 0; + ssid = ssid->next; + } + wpa_s->reassociate = 1; + wpa_supplicant_req_scan(wpa_s, 0, 0); + return 0; + } + + id = atoi(cmd); + wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK id=%d", id); + + ssid = wpa_config_get_network(wpa_s->conf, id); + if (ssid == NULL) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network " + "id=%d", id); + return -1; + } + + if (ssid != wpa_s->current_ssid && wpa_s->current_ssid) + wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); + + /* Mark all other networks disabled and trigger reassociation */ + ssid = wpa_s->conf->ssid; + while (ssid) { + ssid->disabled = id != ssid->id; + ssid = ssid->next; + } + wpa_s->reassociate = 1; + wpa_supplicant_req_scan(wpa_s, 0, 0); + + return 0; +} + + +static int wpa_supplicant_ctrl_iface_enable_network( + struct wpa_supplicant *wpa_s, char *cmd) +{ + int id; + struct wpa_ssid *ssid; + + /* cmd: "<network id>" or "all" */ + if (os_strcmp(cmd, "all") == 0) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK all"); + ssid = wpa_s->conf->ssid; + while (ssid) { + if (ssid == wpa_s->current_ssid && ssid->disabled) + wpa_s->reassociate = 1; + ssid->disabled = 0; + ssid = ssid->next; + } + if (wpa_s->reassociate) + wpa_supplicant_req_scan(wpa_s, 0, 0); + return 0; + } + + id = atoi(cmd); + wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK id=%d", id); + + ssid = wpa_config_get_network(wpa_s->conf, id); + if (ssid == NULL) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network " + "id=%d", id); + return -1; + } + + if (wpa_s->current_ssid == NULL && ssid->disabled) { + /* + * Try to reassociate since there is no current configuration + * and a new network was made available. */ + wpa_s->reassociate = 1; + wpa_supplicant_req_scan(wpa_s, 0, 0); + } + ssid->disabled = 0; + + return 0; +} + + +static int wpa_supplicant_ctrl_iface_disable_network( + struct wpa_supplicant *wpa_s, char *cmd) +{ + int id; + struct wpa_ssid *ssid; + + /* cmd: "<network id>" or "all" */ + if (os_strcmp(cmd, "all") == 0) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK all"); + ssid = wpa_s->conf->ssid; + while (ssid) { + ssid->disabled = 1; + ssid = ssid->next; + } + if (wpa_s->current_ssid) + wpa_supplicant_disassociate(wpa_s, + WLAN_REASON_DEAUTH_LEAVING); + return 0; + } + + id = atoi(cmd); + wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK id=%d", id); + + ssid = wpa_config_get_network(wpa_s->conf, id); + if (ssid == NULL) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network " + "id=%d", id); + return -1; + } + + if (ssid == wpa_s->current_ssid) + wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); + ssid->disabled = 1; + + return 0; +} + + +static int wpa_supplicant_ctrl_iface_add_network( + struct wpa_supplicant *wpa_s, char *buf, size_t buflen) +{ + struct wpa_ssid *ssid; + int ret; + + wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK"); + + ssid = wpa_config_add_network(wpa_s->conf); + if (ssid == NULL) + return -1; + ssid->disabled = 1; + wpa_config_set_network_defaults(ssid); + + ret = os_snprintf(buf, buflen, "%d\n", ssid->id); + if (ret < 0 || (size_t) ret >= buflen) + return -1; + return ret; +} + + +static int wpa_supplicant_ctrl_iface_remove_network( + struct wpa_supplicant *wpa_s, char *cmd) +{ + int id; + struct wpa_ssid *ssid; + + /* cmd: "<network id>" or "all" */ + if (os_strcmp(cmd, "all") == 0) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all"); + ssid = wpa_s->conf->ssid; + while (ssid) { + id = ssid->id; + ssid = ssid->next; + wpa_config_remove_network(wpa_s->conf, id); + } + if (wpa_s->current_ssid) { + eapol_sm_invalidate_cached_session(wpa_s->eapol); + wpa_supplicant_disassociate(wpa_s, + WLAN_REASON_DEAUTH_LEAVING); + } + return 0; + } + + id = atoi(cmd); + wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id); + + ssid = wpa_config_get_network(wpa_s->conf, id); + if (ssid == NULL || + wpa_config_remove_network(wpa_s->conf, id) < 0) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network " + "id=%d", id); + return -1; + } + + if (ssid == wpa_s->current_ssid) { + /* + * Invalidate the EAP session cache if the current network is + * removed. + */ + eapol_sm_invalidate_cached_session(wpa_s->eapol); + + wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); + } + + return 0; +} + + +static int wpa_supplicant_ctrl_iface_set_network( + struct wpa_supplicant *wpa_s, char *cmd) +{ + int id; + struct wpa_ssid *ssid; + char *name, *value; + + /* cmd: "<network id> <variable name> <value>" */ + name = os_strchr(cmd, ' '); + if (name == NULL) + return -1; + *name++ = '\0'; + + value = os_strchr(name, ' '); + if (value == NULL) + return -1; + *value++ = '\0'; + + id = atoi(cmd); + wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK id=%d name='%s'", + id, name); + wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value", + (u8 *) value, os_strlen(value)); + + ssid = wpa_config_get_network(wpa_s->conf, id); + if (ssid == NULL) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network " + "id=%d", id); + return -1; + } + + if (wpa_config_set(ssid, name, value, 0) < 0) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network " + "variable '%s'", name); + return -1; + } + + if (wpa_s->current_ssid == ssid) { + /* + * Invalidate the EAP session cache if anything in the current + * configuration changes. + */ + eapol_sm_invalidate_cached_session(wpa_s->eapol); + } + + if ((os_strcmp(name, "psk") == 0 && + value[0] == '"' && ssid->ssid_len) || + (os_strcmp(name, "ssid") == 0 && ssid->passphrase)) + wpa_config_update_psk(ssid); + + return 0; +} + + +static int wpa_supplicant_ctrl_iface_get_network( + struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) +{ + int id; + size_t res; + struct wpa_ssid *ssid; + char *name, *value; + + /* cmd: "<network id> <variable name>" */ + name = os_strchr(cmd, ' '); + if (name == NULL || buflen == 0) + return -1; + *name++ = '\0'; + + id = atoi(cmd); + wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_NETWORK id=%d name='%s'", + id, name); + + ssid = wpa_config_get_network(wpa_s->conf, id); + if (ssid == NULL) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network " + "id=%d", id); + return -1; + } + + value = wpa_config_get_no_key(ssid, name); + if (value == NULL) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network " + "variable '%s'", name); + return -1; + } + + res = os_strlcpy(buf, value, buflen); + if (res >= buflen) { + os_free(value); + return -1; + } + + os_free(value); + + return res; +} + + +#ifndef CONFIG_NO_CONFIG_WRITE +static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s) +{ + int ret; + + if (!wpa_s->conf->update_config) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed " + "to update configuration (update_config=0)"); + return -1; + } + + ret = wpa_config_write(wpa_s->confname, wpa_s->conf); + if (ret) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to " + "update configuration"); + } else { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration" + " updated"); + } + + return ret; +} +#endif /* CONFIG_NO_CONFIG_WRITE */ + + +static int ctrl_iface_get_capability_pairwise(int res, char *strict, + struct wpa_driver_capa *capa, + char *buf, size_t buflen) +{ + int ret, first = 1; + char *pos, *end; + size_t len; + + pos = buf; + end = pos + buflen; + + if (res < 0) { + if (strict) + return 0; + len = os_strlcpy(buf, "CCMP TKIP NONE", buflen); + if (len >= buflen) + return -1; + return len; + } + + if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) { + ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + first = 0; + } + + if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) { + ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + first = 0; + } + + if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) { + ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + first = 0; + } + + return pos - buf; +} + + +static int ctrl_iface_get_capability_group(int res, char *strict, + struct wpa_driver_capa *capa, + char *buf, size_t buflen) +{ + int ret, first = 1; + char *pos, *end; + size_t len; + + pos = buf; + end = pos + buflen; + + if (res < 0) { + if (strict) + return 0; + len = os_strlcpy(buf, "CCMP TKIP WEP104 WEP40", buflen); + if (len >= buflen) + return -1; + return len; + } + + if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) { + ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + first = 0; + } + + if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) { + ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + first = 0; + } + + if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP104) { + ret = os_snprintf(pos, end - pos, "%sWEP104", + first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + first = 0; + } + + if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP40) { + ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + first = 0; + } + + return pos - buf; +} + + +static int ctrl_iface_get_capability_key_mgmt(int res, char *strict, + struct wpa_driver_capa *capa, + char *buf, size_t buflen) +{ + int ret; + char *pos, *end; + size_t len; + + pos = buf; + end = pos + buflen; + + if (res < 0) { + if (strict) + return 0; + len = os_strlcpy(buf, "WPA-PSK WPA-EAP IEEE8021X WPA-NONE " + "NONE", buflen); + if (len >= buflen) + return -1; + return len; + } + + ret = os_snprintf(pos, end - pos, "NONE IEEE8021X"); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + + if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | + WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) { + ret = os_snprintf(pos, end - pos, " WPA-EAP"); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + } + + if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | + WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { + ret = os_snprintf(pos, end - pos, " WPA-PSK"); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + } + + if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) { + ret = os_snprintf(pos, end - pos, " WPA-NONE"); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + } + + return pos - buf; +} + + +static int ctrl_iface_get_capability_proto(int res, char *strict, + struct wpa_driver_capa *capa, + char *buf, size_t buflen) +{ + int ret, first = 1; + char *pos, *end; + size_t len; + + pos = buf; + end = pos + buflen; + + if (res < 0) { + if (strict) + return 0; + len = os_strlcpy(buf, "RSN WPA", buflen); + if (len >= buflen) + return -1; + return len; + } + + if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | + WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { + ret = os_snprintf(pos, end - pos, "%sRSN", first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + first = 0; + } + + if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | + WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) { + ret = os_snprintf(pos, end - pos, "%sWPA", first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + first = 0; + } + + return pos - buf; +} + + +static int ctrl_iface_get_capability_auth_alg(int res, char *strict, + struct wpa_driver_capa *capa, + char *buf, size_t buflen) +{ + int ret, first = 1; + char *pos, *end; + size_t len; + + pos = buf; + end = pos + buflen; + + if (res < 0) { + if (strict) + return 0; + len = os_strlcpy(buf, "OPEN SHARED LEAP", buflen); + if (len >= buflen) + return -1; + return len; + } + + if (capa->auth & (WPA_DRIVER_AUTH_OPEN)) { + ret = os_snprintf(pos, end - pos, "%sOPEN", first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + first = 0; + } + + if (capa->auth & (WPA_DRIVER_AUTH_SHARED)) { + ret = os_snprintf(pos, end - pos, "%sSHARED", + first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + first = 0; + } + + if (capa->auth & (WPA_DRIVER_AUTH_LEAP)) { + ret = os_snprintf(pos, end - pos, "%sLEAP", first ? "" : " "); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + first = 0; + } + + return pos - buf; +} + + +static int wpa_supplicant_ctrl_iface_get_capability( + struct wpa_supplicant *wpa_s, const char *_field, char *buf, + size_t buflen) +{ + struct wpa_driver_capa capa; + int res; + char *strict; + char field[30]; + size_t len; + + /* Determine whether or not strict checking was requested */ + len = os_strlcpy(field, _field, sizeof(field)); + if (len >= sizeof(field)) + return -1; + strict = os_strchr(field, ' '); + if (strict != NULL) { + *strict++ = '\0'; + if (os_strcmp(strict, "strict") != 0) + return -1; + } + + wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s' %s", + field, strict ? strict : ""); + + if (os_strcmp(field, "eap") == 0) { + return eap_get_names(buf, buflen); + } + + res = wpa_drv_get_capa(wpa_s, &capa); + + if (os_strcmp(field, "pairwise") == 0) + return ctrl_iface_get_capability_pairwise(res, strict, &capa, + buf, buflen); + + if (os_strcmp(field, "group") == 0) + return ctrl_iface_get_capability_group(res, strict, &capa, + buf, buflen); + + if (os_strcmp(field, "key_mgmt") == 0) + return ctrl_iface_get_capability_key_mgmt(res, strict, &capa, + buf, buflen); + + if (os_strcmp(field, "proto") == 0) + return ctrl_iface_get_capability_proto(res, strict, &capa, + buf, buflen); + + if (os_strcmp(field, "auth_alg") == 0) + return ctrl_iface_get_capability_auth_alg(res, strict, &capa, + buf, buflen); + + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'", + field); + + return -1; +} + + +static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s, + const char *cmd, char *buf, + size_t buflen) +{ + u8 bssid[ETH_ALEN]; + size_t i; + struct wpa_scan_results *results; + struct wpa_scan_res *bss; + int ret; + char *pos, *end; + const u8 *ie, *ie2; + + if (wpa_s->scan_res == NULL && + wpa_supplicant_get_scan_results(wpa_s) < 0) + return 0; + + results = wpa_s->scan_res; + if (results == NULL) + return 0; + + if (hwaddr_aton(cmd, bssid) == 0) { + for (i = 0; i < results->num; i++) { + if (os_memcmp(bssid, results->res[i]->bssid, ETH_ALEN) + == 0) + break; + } + } else + i = atoi(cmd); + + if (i >= results->num || results->res[i] == NULL) + return 0; /* no match found */ + + bss = results->res[i]; + pos = buf; + end = buf + buflen; + ret = os_snprintf(pos, end - pos, + "bssid=" MACSTR "\n" + "freq=%d\n" + "beacon_int=%d\n" + "capabilities=0x%04x\n" + "qual=%d\n" + "noise=%d\n" + "level=%d\n" + "tsf=%016llu\n" + "ie=", + MAC2STR(bss->bssid), bss->freq, bss->beacon_int, + bss->caps, bss->qual, bss->noise, bss->level, + (unsigned long long) bss->tsf); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + + ie = (const u8 *) (bss + 1); + for (i = 0; i < bss->ie_len; i++) { + ret = os_snprintf(pos, end - pos, "%02x", *ie++); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + } + + ret = os_snprintf(pos, end - pos, "\n"); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + + ret = os_snprintf(pos, end - pos, "flags="); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + + ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); + if (ie) + pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]); + ie2 = wpa_scan_get_ie(bss, WLAN_EID_RSN); + if (ie2) + pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]); + pos = wpa_supplicant_wps_ie_txt(pos, end, bss); + if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) { + ret = os_snprintf(pos, end - pos, "[WEP]"); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + } + if (bss->caps & IEEE80211_CAP_IBSS) { + ret = os_snprintf(pos, end - pos, "[IBSS]"); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + } + + ret = os_snprintf(pos, end - pos, "\n"); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + + ie = wpa_scan_get_ie(bss, WLAN_EID_SSID); + ret = os_snprintf(pos, end - pos, "ssid=%s\n", + ie ? wpa_ssid_txt(ie + 2, ie[1]) : ""); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + + return pos - buf; +} + + +static int wpa_supplicant_ctrl_iface_ap_scan( + struct wpa_supplicant *wpa_s, char *cmd) +{ + int ap_scan = atoi(cmd); + + if (ap_scan < 0 || ap_scan > 2) + return -1; + wpa_s->conf->ap_scan = ap_scan; + return 0; +} + + +char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, + char *buf, size_t *resp_len) +{ + char *reply; + const int reply_size = 2048; + int ctrl_rsp = 0; + int reply_len; + + if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 || + os_strncmp(buf, "SET_NETWORK ", 12) == 0) { + wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface", + (const u8 *) buf, os_strlen(buf)); + } else { + wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", + (const u8 *) buf, os_strlen(buf)); + } + + reply = os_malloc(reply_size); + if (reply == NULL) { + *resp_len = 1; + return NULL; + } + + 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 = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size); + if (reply_len >= 0) { + int res; + res = eapol_sm_get_mib(wpa_s->eapol, reply + reply_len, + reply_size - reply_len); + if (res < 0) + reply_len = -1; + else + reply_len += res; + } + } else if (os_strncmp(buf, "STATUS", 6) == 0) { + reply_len = wpa_supplicant_ctrl_iface_status( + wpa_s, buf + 6, reply, reply_size); + } else if (os_strcmp(buf, "PMKSA") == 0) { + reply_len = pmksa_cache_list(wpa_s->wpa, reply, reply_size); + } else if (os_strncmp(buf, "SET ", 4) == 0) { + if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4)) + reply_len = -1; + } else if (os_strcmp(buf, "LOGON") == 0) { + eapol_sm_notify_logoff(wpa_s->eapol, FALSE); + } else if (os_strcmp(buf, "LOGOFF") == 0) { + eapol_sm_notify_logoff(wpa_s->eapol, TRUE); + } else if (os_strcmp(buf, "REASSOCIATE") == 0) { + wpa_s->disconnected = 0; + wpa_s->reassociate = 1; + wpa_supplicant_req_scan(wpa_s, 0, 0); + } else if (os_strcmp(buf, "RECONNECT") == 0) { + if (wpa_s->disconnected) { + wpa_s->disconnected = 0; + wpa_s->reassociate = 1; + wpa_supplicant_req_scan(wpa_s, 0, 0); + } +#ifdef IEEE8021X_EAPOL + } else if (os_strncmp(buf, "PREAUTH ", 8) == 0) { + if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8)) + reply_len = -1; +#endif /* IEEE8021X_EAPOL */ +#ifdef CONFIG_PEERKEY + } else if (os_strncmp(buf, "STKSTART ", 9) == 0) { + if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9)) + reply_len = -1; +#endif /* CONFIG_PEERKEY */ +#ifdef CONFIG_IEEE80211R + } else if (os_strncmp(buf, "FT_DS ", 6) == 0) { + if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6)) + reply_len = -1; +#endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_WPS + } else if (os_strcmp(buf, "WPS_PBC") == 0) { + if (wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, NULL)) + reply_len = -1; + } else if (os_strncmp(buf, "WPS_PBC ", 8) == 0) { + if (wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, buf + 8)) + reply_len = -1; + } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) { + reply_len = wpa_supplicant_ctrl_iface_wps_pin(wpa_s, buf + 8, + reply, + reply_size); + } else if (os_strncmp(buf, "WPS_REG ", 8) == 0) { + if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8)) + reply_len = -1; +#endif /* CONFIG_WPS */ + } else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0) + { + if (wpa_supplicant_ctrl_iface_ctrl_rsp( + wpa_s, buf + os_strlen(WPA_CTRL_RSP))) + reply_len = -1; + else + ctrl_rsp = 1; + } else if (os_strcmp(buf, "RECONFIGURE") == 0) { + if (wpa_supplicant_reload_configuration(wpa_s)) + reply_len = -1; + } else if (os_strcmp(buf, "TERMINATE") == 0) { + eloop_terminate(); + } else if (os_strncmp(buf, "BSSID ", 6) == 0) { + if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6)) + reply_len = -1; + } else if (os_strcmp(buf, "LIST_NETWORKS") == 0) { + reply_len = wpa_supplicant_ctrl_iface_list_networks( + wpa_s, reply, reply_size); + } else if (os_strcmp(buf, "DISCONNECT") == 0) { + wpa_s->reassociate = 0; + wpa_s->disconnected = 1; + wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); + } else if (os_strcmp(buf, "SCAN") == 0) { + wpa_s->scan_req = 2; + wpa_supplicant_req_scan(wpa_s, 0, 0); + } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) { + reply_len = wpa_supplicant_ctrl_iface_scan_results( + wpa_s, reply, reply_size); + } else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) { + if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15)) + reply_len = -1; + } else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) { + if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15)) + reply_len = -1; + } else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) { + if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16)) + reply_len = -1; + } else if (os_strcmp(buf, "ADD_NETWORK") == 0) { + reply_len = wpa_supplicant_ctrl_iface_add_network( + wpa_s, reply, reply_size); + } else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) { + if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15)) + reply_len = -1; + } else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) { + if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12)) + reply_len = -1; + } else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) { + reply_len = wpa_supplicant_ctrl_iface_get_network( + wpa_s, buf + 12, reply, reply_size); +#ifndef CONFIG_NO_CONFIG_WRITE + } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) { + if (wpa_supplicant_ctrl_iface_save_config(wpa_s)) + reply_len = -1; +#endif /* CONFIG_NO_CONFIG_WRITE */ + } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) { + reply_len = wpa_supplicant_ctrl_iface_get_capability( + wpa_s, buf + 15, reply, reply_size); + } else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) { + if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8)) + reply_len = -1; + } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) { + reply_len = wpa_supplicant_global_iface_list( + wpa_s->global, reply, reply_size); + } else if (os_strcmp(buf, "INTERFACES") == 0) { + reply_len = wpa_supplicant_global_iface_interfaces( + wpa_s->global, reply, reply_size); + } else if (os_strncmp(buf, "BSS ", 4) == 0) { + reply_len = wpa_supplicant_ctrl_iface_bss( + wpa_s, buf + 4, reply, reply_size); + } else { + os_memcpy(reply, "UNKNOWN COMMAND\n", 16); + reply_len = 16; + } + + if (reply_len < 0) { + os_memcpy(reply, "FAIL\n", 5); + reply_len = 5; + } + + if (ctrl_rsp) + eapol_sm_notify_ctrl_response(wpa_s->eapol); + + *resp_len = reply_len; + return reply; +} + + +static int wpa_supplicant_global_iface_add(struct wpa_global *global, + char *cmd) +{ + struct wpa_interface iface; + char *pos; + + /* + * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param> + * TAB<bridge_ifname> + */ + wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd); + + os_memset(&iface, 0, sizeof(iface)); + + do { + iface.ifname = pos = cmd; + pos = os_strchr(pos, '\t'); + if (pos) + *pos++ = '\0'; + if (iface.ifname[0] == '\0') + return -1; + if (pos == NULL) + break; + + iface.confname = pos; + pos = os_strchr(pos, '\t'); + if (pos) + *pos++ = '\0'; + if (iface.confname[0] == '\0') + iface.confname = NULL; + if (pos == NULL) + break; + + iface.driver = pos; + pos = os_strchr(pos, '\t'); + if (pos) + *pos++ = '\0'; + if (iface.driver[0] == '\0') + iface.driver = NULL; + if (pos == NULL) + break; + + iface.ctrl_interface = pos; + pos = os_strchr(pos, '\t'); + if (pos) + *pos++ = '\0'; + if (iface.ctrl_interface[0] == '\0') + iface.ctrl_interface = NULL; + if (pos == NULL) + break; + + iface.driver_param = pos; + pos = os_strchr(pos, '\t'); + if (pos) + *pos++ = '\0'; + if (iface.driver_param[0] == '\0') + iface.driver_param = NULL; + if (pos == NULL) + break; + + iface.bridge_ifname = pos; + pos = os_strchr(pos, '\t'); + if (pos) + *pos++ = '\0'; + if (iface.bridge_ifname[0] == '\0') + iface.bridge_ifname = NULL; + if (pos == NULL) + break; + } while (0); + + if (wpa_supplicant_get_iface(global, iface.ifname)) + return -1; + + return wpa_supplicant_add_iface(global, &iface) ? 0 : -1; +} + + +static int wpa_supplicant_global_iface_remove(struct wpa_global *global, + char *cmd) +{ + struct wpa_supplicant *wpa_s; + + wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd); + + wpa_s = wpa_supplicant_get_iface(global, cmd); + if (wpa_s == NULL) + return -1; + return wpa_supplicant_remove_iface(global, wpa_s); +} + + +static void wpa_free_iface_info(struct wpa_interface_info *iface) +{ + struct wpa_interface_info *prev; + + while (iface) { + prev = iface; + iface = iface->next; + + os_free(prev->ifname); + os_free(prev->desc); + os_free(prev); + } +} + + +static int wpa_supplicant_global_iface_list(struct wpa_global *global, + char *buf, int len) +{ + int i, res; + struct wpa_interface_info *iface = NULL, *last = NULL, *tmp; + char *pos, *end; + + for (i = 0; wpa_supplicant_drivers[i]; i++) { + struct wpa_driver_ops *drv = wpa_supplicant_drivers[i]; + if (drv->get_interfaces == NULL) + continue; + tmp = drv->get_interfaces(global->drv_priv); + if (tmp == NULL) + continue; + + if (last == NULL) + iface = last = tmp; + else + last->next = tmp; + while (last->next) + last = last->next; + } + + pos = buf; + end = buf + len; + for (tmp = iface; tmp; tmp = tmp->next) { + res = os_snprintf(pos, end - pos, "%s\t%s\t%s\n", + tmp->drv_name, tmp->ifname, + tmp->desc ? tmp->desc : ""); + if (res < 0 || res >= end - pos) { + *pos = '\0'; + break; + } + pos += res; + } + + wpa_free_iface_info(iface); + + return pos - buf; +} + + +static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global, + char *buf, int len) +{ + int res; + char *pos, *end; + struct wpa_supplicant *wpa_s; + + wpa_s = global->ifaces; + pos = buf; + end = buf + len; + + while (wpa_s) { + res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname); + if (res < 0 || res >= end - pos) { + *pos = '\0'; + break; + } + pos += res; + wpa_s = wpa_s->next; + } + return pos - buf; +} + + +char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global, + char *buf, size_t *resp_len) +{ + char *reply; + const int reply_size = 2048; + int reply_len; + + wpa_hexdump_ascii(MSG_DEBUG, "RX global ctrl_iface", + (const u8 *) buf, os_strlen(buf)); + + reply = os_malloc(reply_size); + if (reply == NULL) { + *resp_len = 1; + return NULL; + } + + 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_strncmp(buf, "INTERFACE_ADD ", 14) == 0) { + if (wpa_supplicant_global_iface_add(global, buf + 14)) + reply_len = -1; + } else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) { + if (wpa_supplicant_global_iface_remove(global, buf + 17)) + reply_len = -1; + } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) { + reply_len = wpa_supplicant_global_iface_list( + global, reply, reply_size); + } else if (os_strcmp(buf, "INTERFACES") == 0) { + reply_len = wpa_supplicant_global_iface_interfaces( + global, reply, reply_size); + } else if (os_strcmp(buf, "TERMINATE") == 0) { + eloop_terminate(); + } else { + os_memcpy(reply, "UNKNOWN COMMAND\n", 16); + reply_len = 16; + } + + if (reply_len < 0) { + os_memcpy(reply, "FAIL\n", 5); + reply_len = 5; + } + + *resp_len = reply_len; + return reply; +} diff --git a/wpa_supplicant/ctrl_iface.h b/wpa_supplicant/ctrl_iface.h new file mode 100644 index 000000000000..051d99a67dc6 --- /dev/null +++ b/wpa_supplicant/ctrl_iface.h @@ -0,0 +1,159 @@ +/* + * WPA Supplicant / UNIX domain socket -based control interface + * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef CTRL_IFACE_H +#define CTRL_IFACE_H + +#ifdef CONFIG_CTRL_IFACE + +/* Shared functions from ctrl_iface.c; to be called by ctrl_iface backends */ + +/** + * wpa_supplicant_ctrl_iface_process - Process ctrl_iface command + * @wpa_s: Pointer to wpa_supplicant data + * @buf: Received command buffer (nul terminated string) + * @resp_len: Variable to be set to the response length + * Returns: Response (*resp_len bytes) or %NULL on failure + * + * Control interface backends call this function when receiving a message that + * they do not process internally, i.e., anything else than ATTACH, DETACH, + * and LEVEL. The return response value is then sent to the external program + * that sent the command. Caller is responsible for freeing the buffer after + * this. If %NULL is returned, *resp_len can be set to two special values: + * 1 = send "FAIL\n" response, 2 = send "OK\n" response. If *resp_len has any + * other value, no response is sent. + */ +char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, + char *buf, size_t *resp_len); + +/** + * wpa_supplicant_ctrl_iface_process - Process global ctrl_iface command + * @global: Pointer to global data from wpa_supplicant_init() + * @buf: Received command buffer (nul terminated string) + * @resp_len: Variable to be set to the response length + * Returns: Response (*resp_len bytes) or %NULL on failure + * + * Control interface backends call this function when receiving a message from + * the global ctrl_iface connection. The return response value is then sent to + * the external program that sent the command. Caller is responsible for + * freeing the buffer after this. If %NULL is returned, *resp_len can be set to + * two special values: 1 = send "FAIL\n" response, 2 = send "OK\n" response. If + * *resp_len has any other value, no response is sent. + */ +char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global, + char *buf, size_t *resp_len); + + +/* Functions that each ctrl_iface backend must implement */ + +/** + * wpa_supplicant_ctrl_iface_init - Initialize control interface + * @wpa_s: Pointer to wpa_supplicant data + * Returns: Pointer to private data on success, %NULL on failure + * + * Initialize the control interface and start receiving commands from external + * programs. + * + * Required to be implemented in each control interface backend. + */ +struct ctrl_iface_priv * +wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s); + +/** + * wpa_supplicant_ctrl_iface_deinit - Deinitialize control interface + * @priv: Pointer to private data from wpa_supplicant_ctrl_iface_init() + * + * Deinitialize the control interface that was initialized with + * wpa_supplicant_ctrl_iface_init(). + * + * Required to be implemented in each control interface backend. + */ +void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv); + +/** + * wpa_supplicant_ctrl_iface_wait - Wait for ctrl_iface monitor + * @priv: Pointer to private data from wpa_supplicant_ctrl_iface_init() + * + * Wait until the first message from an external program using the control + * interface is received. This function can be used to delay normal startup + * processing to allow control interface programs to attach with + * %wpa_supplicant before normal operations are started. + * + * Required to be implemented in each control interface backend. + */ +void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv); + +/** + * wpa_supplicant_global_ctrl_iface_init - Initialize global control interface + * @global: Pointer to global data from wpa_supplicant_init() + * Returns: Pointer to private data on success, %NULL on failure + * + * Initialize the global control interface and start receiving commands from + * external programs. + * + * Required to be implemented in each control interface backend. + */ +struct ctrl_iface_global_priv * +wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global); + +/** + * wpa_supplicant_global_ctrl_iface_deinit - Deinitialize global ctrl interface + * @priv: Pointer to private data from wpa_supplicant_global_ctrl_iface_init() + * + * Deinitialize the global control interface that was initialized with + * wpa_supplicant_global_ctrl_iface_init(). + * + * Required to be implemented in each control interface backend. + */ +void wpa_supplicant_global_ctrl_iface_deinit( + struct ctrl_iface_global_priv *priv); + +#else /* CONFIG_CTRL_IFACE */ + +static inline struct ctrl_iface_priv * +wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) +{ + return (void *) -1; +} + +static inline void +wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) +{ +} + +static inline void +wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, int level, + char *buf, size_t len) +{ +} + +static inline void +wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) +{ +} + +static inline struct ctrl_iface_global_priv * +wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) +{ + return (void *) 1; +} + +static inline void +wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) +{ +} + +#endif /* CONFIG_CTRL_IFACE */ + +#endif /* CTRL_IFACE_H */ diff --git a/wpa_supplicant/ctrl_iface_dbus.c b/wpa_supplicant/ctrl_iface_dbus.c new file mode 100644 index 000000000000..c4e329c53e45 --- /dev/null +++ b/wpa_supplicant/ctrl_iface_dbus.c @@ -0,0 +1,1115 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, 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 "common.h" +#include "eloop.h" +#include "config.h" +#include "wpa_supplicant_i.h" +#include "wps/wps.h" +#include "ctrl_iface_dbus.h" +#include "ctrl_iface_dbus_handlers.h" + +#define _DBUS_VERSION (DBUS_VERSION_MAJOR << 8 | DBUS_VERSION_MINOR) +#define DBUS_VER(major, minor) ((major) << 8 | (minor)) + +#if _DBUS_VERSION < DBUS_VER(1,1) +#define dbus_watch_get_unix_fd dbus_watch_get_fd +#endif + + +struct ctrl_iface_dbus_priv { + DBusConnection *con; + int should_dispatch; + struct wpa_global *global; + + u32 next_objid; +}; + + +static void process_watch(struct ctrl_iface_dbus_priv *iface, + DBusWatch *watch, eloop_event_type type) +{ + dbus_connection_ref(iface->con); + + iface->should_dispatch = 0; + + if (type == EVENT_TYPE_READ) + dbus_watch_handle(watch, DBUS_WATCH_READABLE); + else if (type == EVENT_TYPE_WRITE) + dbus_watch_handle(watch, DBUS_WATCH_WRITABLE); + else if (type == EVENT_TYPE_EXCEPTION) + dbus_watch_handle(watch, DBUS_WATCH_ERROR); + + if (iface->should_dispatch) { + while (dbus_connection_get_dispatch_status(iface->con) == + DBUS_DISPATCH_DATA_REMAINS) + dbus_connection_dispatch(iface->con); + iface->should_dispatch = 0; + } + + dbus_connection_unref(iface->con); +} + + +static void process_watch_exception(int sock, void *eloop_ctx, void *sock_ctx) +{ + process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_EXCEPTION); +} + + +static void process_watch_read(int sock, void *eloop_ctx, void *sock_ctx) +{ + process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_READ); +} + + +static void process_watch_write(int sock, void *eloop_ctx, void *sock_ctx) +{ + process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_WRITE); +} + + +static void connection_setup_add_watch(struct ctrl_iface_dbus_priv *iface, + DBusWatch *watch) +{ + unsigned int flags; + int fd; + + if (!dbus_watch_get_enabled(watch)) + return; + + flags = dbus_watch_get_flags(watch); + fd = dbus_watch_get_unix_fd(watch); + + eloop_register_sock(fd, EVENT_TYPE_EXCEPTION, process_watch_exception, + iface, watch); + + if (flags & DBUS_WATCH_READABLE) { + eloop_register_sock(fd, EVENT_TYPE_READ, process_watch_read, + iface, watch); + } + if (flags & DBUS_WATCH_WRITABLE) { + eloop_register_sock(fd, EVENT_TYPE_WRITE, process_watch_write, + iface, watch); + } + + dbus_watch_set_data(watch, iface, NULL); +} + + +static void connection_setup_remove_watch(struct ctrl_iface_dbus_priv *iface, + DBusWatch *watch) +{ + unsigned int flags; + int fd; + + flags = dbus_watch_get_flags(watch); + fd = dbus_watch_get_unix_fd(watch); + + eloop_unregister_sock(fd, EVENT_TYPE_EXCEPTION); + + if (flags & DBUS_WATCH_READABLE) + eloop_unregister_sock(fd, EVENT_TYPE_READ); + if (flags & DBUS_WATCH_WRITABLE) + eloop_unregister_sock(fd, EVENT_TYPE_WRITE); + + dbus_watch_set_data(watch, NULL, NULL); +} + + +static dbus_bool_t add_watch(DBusWatch *watch, void *data) +{ + connection_setup_add_watch(data, watch); + return TRUE; +} + + +static void remove_watch(DBusWatch *watch, void *data) +{ + connection_setup_remove_watch(data, watch); +} + + +static void watch_toggled(DBusWatch *watch, void *data) +{ + if (dbus_watch_get_enabled(watch)) + add_watch(watch, data); + else + remove_watch(watch, data); +} + + +static void process_timeout(void *eloop_ctx, void *sock_ctx) +{ + DBusTimeout *timeout = sock_ctx; + + dbus_timeout_handle(timeout); +} + + +static void connection_setup_add_timeout(struct ctrl_iface_dbus_priv *iface, + DBusTimeout *timeout) +{ + if (!dbus_timeout_get_enabled(timeout)) + return; + + eloop_register_timeout(0, dbus_timeout_get_interval(timeout) * 1000, + process_timeout, iface, timeout); + + dbus_timeout_set_data(timeout, iface, NULL); +} + + +static void connection_setup_remove_timeout(struct ctrl_iface_dbus_priv *iface, + DBusTimeout *timeout) +{ + eloop_cancel_timeout(process_timeout, iface, timeout); + dbus_timeout_set_data(timeout, NULL, NULL); +} + + +static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) +{ + if (!dbus_timeout_get_enabled(timeout)) + return TRUE; + + connection_setup_add_timeout(data, timeout); + + return TRUE; +} + + +static void remove_timeout(DBusTimeout *timeout, void *data) +{ + connection_setup_remove_timeout(data, timeout); +} + + +static void timeout_toggled(DBusTimeout *timeout, void *data) +{ + if (dbus_timeout_get_enabled(timeout)) + add_timeout(timeout, data); + else + remove_timeout(timeout, data); +} + + +static void process_wakeup_main(int sig, void *eloop_ctx, void *signal_ctx) +{ + struct ctrl_iface_dbus_priv *iface = signal_ctx; + + if (sig != SIGPOLL || !iface->con) + return; + + if (dbus_connection_get_dispatch_status(iface->con) != + DBUS_DISPATCH_DATA_REMAINS) + return; + + /* Only dispatch once - we do not want to starve other events */ + dbus_connection_ref(iface->con); + dbus_connection_dispatch(iface->con); + dbus_connection_unref(iface->con); +} + + +/** + * wakeup_main - Attempt to wake our mainloop up + * @data: dbus control interface private data + * + * Try to wake up the main eloop so it will process + * dbus events that may have happened. + */ +static void wakeup_main(void *data) +{ + struct ctrl_iface_dbus_priv *iface = data; + + /* Use SIGPOLL to break out of the eloop select() */ + raise(SIGPOLL); + iface->should_dispatch = 1; +} + + +/** + * connection_setup_wakeup_main - Tell dbus about our wakeup_main function + * @iface: dbus control interface private data + * Returns: 0 on success, -1 on failure + * + * Register our wakeup_main handler with dbus + */ +static int connection_setup_wakeup_main(struct ctrl_iface_dbus_priv *iface) +{ + if (eloop_register_signal(SIGPOLL, process_wakeup_main, iface)) + return -1; + + dbus_connection_set_wakeup_main_function(iface->con, wakeup_main, + iface, NULL); + + return 0; +} + + +/** + * wpa_supplicant_dbus_next_objid - Return next available object id + * @iface: dbus control interface private data + * Returns: Object id + */ +u32 wpa_supplicant_dbus_next_objid (struct ctrl_iface_dbus_priv *iface) +{ + return iface->next_objid++; +} + + +/** + * wpas_dbus_decompose_object_path - Decompose an interface object path into parts + * @path: The dbus object path + * @network: (out) the configured network this object path refers to, if any + * @bssid: (out) the scanned bssid this object path refers to, if any + * Returns: The object path of the network interface this path refers to + * + * For a given object path, decomposes the object path into object id, network, + * and BSSID parts, if those parts exist. + */ +char * wpas_dbus_decompose_object_path(const char *path, char **network, + char **bssid) +{ + const unsigned int dev_path_prefix_len = + strlen(WPAS_DBUS_PATH_INTERFACES "/"); + char *obj_path_only; + char *next_sep; + + /* Be a bit paranoid about path */ + if (!path || strncmp(path, WPAS_DBUS_PATH_INTERFACES "/", + dev_path_prefix_len)) + return NULL; + + /* Ensure there's something at the end of the path */ + if ((path + dev_path_prefix_len)[0] == '\0') + return NULL; + + obj_path_only = strdup(path); + if (obj_path_only == NULL) + return NULL; + + next_sep = strchr(obj_path_only + dev_path_prefix_len, '/'); + if (next_sep != NULL) { + const char *net_part = strstr(next_sep, + WPAS_DBUS_NETWORKS_PART "/"); + const char *bssid_part = strstr(next_sep, + WPAS_DBUS_BSSIDS_PART "/"); + + if (network && net_part) { + /* Deal with a request for a configured network */ + const char *net_name = net_part + + strlen(WPAS_DBUS_NETWORKS_PART "/"); + *network = NULL; + if (strlen(net_name)) + *network = strdup(net_name); + } else if (bssid && bssid_part) { + /* Deal with a request for a scanned BSSID */ + const char *bssid_name = bssid_part + + strlen(WPAS_DBUS_BSSIDS_PART "/"); + if (strlen(bssid_name)) + *bssid = strdup(bssid_name); + else + *bssid = NULL; + } + + /* Cut off interface object path before "/" */ + *next_sep = '\0'; + } + + return obj_path_only; +} + + +/** + * wpas_dbus_new_invalid_iface_error - Return a new invalid interface error message + * @message: Pointer to incoming dbus message this error refers to + * Returns: A dbus error message + * + * Convenience function to create and return an invalid interface error + */ +DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message) +{ + return dbus_message_new_error(message, WPAS_ERROR_INVALID_IFACE, + "wpa_supplicant knows nothing about " + "this interface."); +} + + +/** + * wpas_dbus_new_invalid_network_error - Return a new invalid network error message + * @message: Pointer to incoming dbus message this error refers to + * Returns: a dbus error message + * + * Convenience function to create and return an invalid network error + */ +DBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message) +{ + return dbus_message_new_error(message, WPAS_ERROR_INVALID_NETWORK, + "The requested network does not exist."); +} + + +/** + * wpas_dbus_new_invalid_bssid_error - Return a new invalid bssid error message + * @message: Pointer to incoming dbus message this error refers to + * Returns: a dbus error message + * + * Convenience function to create and return an invalid bssid error + */ +static DBusMessage * wpas_dbus_new_invalid_bssid_error(DBusMessage *message) +{ + return dbus_message_new_error(message, WPAS_ERROR_INVALID_BSSID, + "The BSSID requested was invalid."); +} + + +/** + * wpas_dispatch_network_method - dispatch messages for configured networks + * @message: the incoming dbus message + * @wpa_s: a network interface's data + * @network_id: id of the configured network we're interested in + * Returns: a reply dbus message, or a dbus error message + * + * This function dispatches all incoming dbus messages for configured networks. + */ +static DBusMessage * wpas_dispatch_network_method(DBusMessage *message, + struct wpa_supplicant *wpa_s, + int network_id) +{ + DBusMessage *reply = NULL; + const char *method = dbus_message_get_member(message); + struct wpa_ssid *ssid; + + ssid = wpa_config_get_network(wpa_s->conf, network_id); + if (ssid == NULL) + return wpas_dbus_new_invalid_network_error(message); + + if (!strcmp(method, "set")) + reply = wpas_dbus_iface_set_network(message, wpa_s, ssid); + else if (!strcmp(method, "enable")) + reply = wpas_dbus_iface_enable_network(message, wpa_s, ssid); + else if (!strcmp(method, "disable")) + reply = wpas_dbus_iface_disable_network(message, wpa_s, ssid); + + return reply; +} + + +/** + * wpas_dispatch_bssid_method - dispatch messages for scanned networks + * @message: the incoming dbus message + * @wpa_s: a network interface's data + * @bssid: bssid of the scanned network we're interested in + * Returns: a reply dbus message, or a dbus error message + * + * This function dispatches all incoming dbus messages for scanned networks. + */ +static DBusMessage * wpas_dispatch_bssid_method(DBusMessage *message, + struct wpa_supplicant *wpa_s, + const char *bssid) +{ + DBusMessage *reply = NULL; + const char *method = dbus_message_get_member(message); + struct wpa_scan_res *res = NULL; + size_t i; + + /* Ensure we actually have scan data */ + if (wpa_s->scan_res == NULL && + wpa_supplicant_get_scan_results(wpa_s) < 0) { + reply = wpas_dbus_new_invalid_bssid_error(message); + goto out; + } + + /* Find the bssid's scan data */ + for (i = 0; i < wpa_s->scan_res->num; i++) { + struct wpa_scan_res *search_res = wpa_s->scan_res->res[i]; + char mac_str[18]; + + memset(mac_str, 0, sizeof(mac_str)); + snprintf(mac_str, sizeof(mac_str) - 1, WPAS_DBUS_BSSID_FORMAT, + MAC2STR(search_res->bssid)); + if (!strcmp(bssid, mac_str)) { + res = search_res; + break; + } + } + + if (!res) { + reply = wpas_dbus_new_invalid_bssid_error(message); + goto out; + } + + /* Dispatch the method call against the scanned bssid */ + if (!strcmp(method, "properties")) + reply = wpas_dbus_bssid_properties(message, wpa_s, res); + +out: + return reply; +} + + +/** + * wpas_iface_message_handler - Dispatch messages for interfaces or networks + * @connection: Connection to the system message bus + * @message: An incoming dbus message + * @user_data: A pointer to a dbus control interface data structure + * Returns: Whether or not the message was handled + * + * This function dispatches all incoming dbus messages for network interfaces, + * or objects owned by them, such as scanned BSSIDs and configured networks. + */ +static DBusHandlerResult wpas_iface_message_handler(DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + const char *method = dbus_message_get_member(message); + const char *path = dbus_message_get_path(message); + const char *msg_interface = dbus_message_get_interface(message); + char *iface_obj_path = NULL; + char *network = NULL; + char *bssid = NULL; + DBusMessage *reply = NULL; + + /* Caller must specify a message interface */ + if (!msg_interface) + goto out; + + iface_obj_path = wpas_dbus_decompose_object_path(path, &network, + &bssid); + if (iface_obj_path == NULL) { + reply = wpas_dbus_new_invalid_iface_error(message); + goto out; + } + + /* Make sure the message's object path actually refers to the + * wpa_supplicant structure it's supposed to (which is wpa_s) + */ + if (wpa_supplicant_get_iface_by_dbus_path(wpa_s->global, + iface_obj_path) != wpa_s) { + reply = wpas_dbus_new_invalid_iface_error(message); + goto out; + } + + if (network && !strcmp(msg_interface, WPAS_DBUS_IFACE_NETWORK)) { + /* A method for one of this interface's configured networks */ + int nid = strtoul(network, NULL, 10); + if (errno != EINVAL) + reply = wpas_dispatch_network_method(message, wpa_s, + nid); + else + reply = wpas_dbus_new_invalid_network_error(message); + } else if (bssid && !strcmp(msg_interface, WPAS_DBUS_IFACE_BSSID)) { + /* A method for one of this interface's scanned BSSIDs */ + reply = wpas_dispatch_bssid_method(message, wpa_s, bssid); + } else if (!strcmp(msg_interface, WPAS_DBUS_IFACE_INTERFACE)) { + /* A method for an interface only. */ + if (!strcmp(method, "scan")) + reply = wpas_dbus_iface_scan(message, wpa_s); + else if (!strcmp(method, "scanResults")) + reply = wpas_dbus_iface_scan_results(message, wpa_s); + else if (!strcmp(method, "addNetwork")) + reply = wpas_dbus_iface_add_network(message, wpa_s); + else if (!strcmp(method, "removeNetwork")) + reply = wpas_dbus_iface_remove_network(message, wpa_s); + else if (!strcmp(method, "selectNetwork")) + reply = wpas_dbus_iface_select_network(message, wpa_s); + else if (!strcmp(method, "capabilities")) + reply = wpas_dbus_iface_capabilities(message, wpa_s); + else if (!strcmp(method, "disconnect")) + reply = wpas_dbus_iface_disconnect(message, wpa_s); + else if (!strcmp(method, "setAPScan")) + reply = wpas_dbus_iface_set_ap_scan(message, wpa_s); + else if (!strcmp(method, "setSmartcardModules")) + reply = wpas_dbus_iface_set_smartcard_modules(message, + wpa_s); + else if (!strcmp(method, "state")) + reply = wpas_dbus_iface_get_state(message, wpa_s); + else if (!strcmp(method, "setBlobs")) + reply = wpas_dbus_iface_set_blobs(message, wpa_s); + else if (!strcmp(method, "removeBlobs")) + reply = wpas_dbus_iface_remove_blobs(message, wpa_s); + } + + /* If the message was handled, send back the reply */ + if (reply) { + if (!dbus_message_get_no_reply(message)) + dbus_connection_send(connection, reply, NULL); + dbus_message_unref(reply); + } + +out: + free(iface_obj_path); + free(network); + free(bssid); + return reply ? DBUS_HANDLER_RESULT_HANDLED : + DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + + +/** + * wpas_message_handler - dispatch incoming dbus messages + * @connection: connection to the system message bus + * @message: an incoming dbus message + * @user_data: a pointer to a dbus control interface data structure + * Returns: whether or not the message was handled + * + * This function dispatches all incoming dbus messages to the correct + * handlers, depending on what the message's target object path is, + * and what the method call is. + */ +static DBusHandlerResult wpas_message_handler(DBusConnection *connection, + DBusMessage *message, void *user_data) +{ + struct ctrl_iface_dbus_priv *ctrl_iface = user_data; + const char *method; + const char *path; + const char *msg_interface; + DBusMessage *reply = NULL; + + method = dbus_message_get_member(message); + path = dbus_message_get_path(message); + msg_interface = dbus_message_get_interface(message); + if (!method || !path || !ctrl_iface || !msg_interface) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + /* Validate the method interface */ + if (strcmp(msg_interface, WPAS_DBUS_INTERFACE) != 0) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + if (!strcmp(path, WPAS_DBUS_PATH)) { + /* dispatch methods against our global dbus interface here */ + if (!strcmp(method, "addInterface")) { + reply = wpas_dbus_global_add_interface( + message, ctrl_iface->global); + } else if (!strcmp(method, "removeInterface")) { + reply = wpas_dbus_global_remove_interface( + message, ctrl_iface->global); + } else if (!strcmp(method, "getInterface")) { + reply = wpas_dbus_global_get_interface( + message, ctrl_iface->global); + } + } + + /* If the message was handled, send back the reply */ + if (reply) { + if (!dbus_message_get_no_reply(message)) + dbus_connection_send(connection, reply, NULL); + dbus_message_unref(reply); + } + + return reply ? DBUS_HANDLER_RESULT_HANDLED : + DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + + +/** + * wpa_supplicant_dbus_notify_scan_results - Send a scan results signal + * @wpa_s: %wpa_supplicant network interface data + * Returns: 0 on success, -1 on failure + * + * Notify listeners that this interface has updated scan results. + */ +void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s) +{ + struct ctrl_iface_dbus_priv *iface = wpa_s->global->dbus_ctrl_iface; + DBusMessage *_signal; + const char *path; + + /* Do nothing if the control interface is not turned on */ + if (iface == NULL) + return; + + path = wpa_supplicant_get_dbus_path(wpa_s); + if (path == NULL) { + perror("wpa_supplicant_dbus_notify_scan_results[dbus]: " + "interface didn't have a dbus path"); + wpa_printf(MSG_ERROR, + "wpa_supplicant_dbus_notify_scan_results[dbus]: " + "interface didn't have a dbus path; can't send " + "scan result signal."); + return; + } + _signal = dbus_message_new_signal(path, WPAS_DBUS_IFACE_INTERFACE, + "ScanResultsAvailable"); + if (_signal == NULL) { + perror("wpa_supplicant_dbus_notify_scan_results[dbus]: " + "couldn't create dbus signal; likely out of memory"); + wpa_printf(MSG_ERROR, "dbus control interface: not enough " + "memory to send scan results signal."); + return; + } + dbus_connection_send(iface->con, _signal, NULL); + dbus_message_unref(_signal); +} + + +/** + * wpa_supplicant_dbus_notify_state_change - Send a state change signal + * @wpa_s: %wpa_supplicant network interface data + * @new_state: new state wpa_supplicant is entering + * @old_state: old state wpa_supplicant is leaving + * Returns: 0 on success, -1 on failure + * + * Notify listeners that wpa_supplicant has changed state + */ +void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s, + wpa_states new_state, + wpa_states old_state) +{ + struct ctrl_iface_dbus_priv *iface; + DBusMessage *_signal = NULL; + const char *path; + const char *new_state_str, *old_state_str; + + /* Do nothing if the control interface is not turned on */ + if (wpa_s->global == NULL) + return; + iface = wpa_s->global->dbus_ctrl_iface; + if (iface == NULL) + return; + + /* Only send signal if state really changed */ + if (new_state == old_state) + return; + + path = wpa_supplicant_get_dbus_path(wpa_s); + if (path == NULL) { + perror("wpa_supplicant_dbus_notify_state_change[dbus]: " + "interface didn't have a dbus path"); + wpa_printf(MSG_ERROR, + "wpa_supplicant_dbus_notify_state_change[dbus]: " + "interface didn't have a dbus path; can't send " + "signal."); + return; + } + _signal = dbus_message_new_signal(path, WPAS_DBUS_IFACE_INTERFACE, + "StateChange"); + if (_signal == NULL) { + perror("wpa_supplicant_dbus_notify_state_change[dbus]: " + "couldn't create dbus signal; likely out of memory"); + wpa_printf(MSG_ERROR, + "wpa_supplicant_dbus_notify_state_change[dbus]: " + "couldn't create dbus signal; likely out of " + "memory."); + return; + } + + new_state_str = wpa_supplicant_state_txt(new_state); + old_state_str = wpa_supplicant_state_txt(old_state); + if (new_state_str == NULL || old_state_str == NULL) { + perror("wpa_supplicant_dbus_notify_state_change[dbus]: " + "couldn't convert state strings"); + wpa_printf(MSG_ERROR, + "wpa_supplicant_dbus_notify_state_change[dbus]: " + "couldn't convert state strings."); + goto out; + } + + if (!dbus_message_append_args(_signal, + DBUS_TYPE_STRING, &new_state_str, + DBUS_TYPE_STRING, &old_state_str, + DBUS_TYPE_INVALID)) { + perror("wpa_supplicant_dbus_notify_state_change[dbus]: " + "not enough memory to construct state change signal."); + wpa_printf(MSG_ERROR, + "wpa_supplicant_dbus_notify_state_change[dbus]: " + "not enough memory to construct state change " + "signal."); + goto out; + } + + dbus_connection_send(iface->con, _signal, NULL); + +out: + dbus_message_unref(_signal); +} + + +#ifdef CONFIG_WPS +void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s, + const struct wps_credential *cred) +{ + struct ctrl_iface_dbus_priv *iface; + DBusMessage *_signal = NULL; + const char *path; + + /* Do nothing if the control interface is not turned on */ + if (wpa_s->global == NULL) + return; + iface = wpa_s->global->dbus_ctrl_iface; + if (iface == NULL) + return; + + path = wpa_supplicant_get_dbus_path(wpa_s); + if (path == NULL) { + perror("wpa_supplicant_dbus_notify_wps_cred[dbus]: " + "interface didn't have a dbus path"); + wpa_printf(MSG_ERROR, + "wpa_supplicant_dbus_notify_wps_cred[dbus]: " + "interface didn't have a dbus path; can't send " + "signal."); + return; + } + _signal = dbus_message_new_signal(path, WPAS_DBUS_IFACE_INTERFACE, + "WpsCred"); + if (_signal == NULL) { + perror("wpa_supplicant_dbus_notify_wps_cred[dbus]: " + "couldn't create dbus signal; likely out of memory"); + wpa_printf(MSG_ERROR, + "wpa_supplicant_dbus_notify_wps_cred[dbus]: " + "couldn't create dbus signal; likely out of " + "memory."); + return; + } + + if (!dbus_message_append_args(_signal, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, + &cred->cred_attr, cred->cred_attr_len, + DBUS_TYPE_INVALID)) { + perror("wpa_supplicant_dbus_notify_wps_cred[dbus]: " + "not enough memory to construct signal."); + wpa_printf(MSG_ERROR, + "wpa_supplicant_dbus_notify_wps_cred[dbus]: " + "not enough memory to construct signal."); + goto out; + } + + dbus_connection_send(iface->con, _signal, NULL); + +out: + dbus_message_unref(_signal); +} +#endif /* CONFIG_WPS */ + + +/** + * integrate_with_eloop - Register our mainloop integration with dbus + * @connection: connection to the system message bus + * @iface: a dbus control interface data structure + * Returns: 0 on success, -1 on failure + * + * We register our mainloop integration functions with dbus here. + */ +static int integrate_with_eloop(DBusConnection *connection, + struct ctrl_iface_dbus_priv *iface) +{ + if (!dbus_connection_set_watch_functions(connection, add_watch, + remove_watch, watch_toggled, + iface, NULL)) { + perror("dbus_connection_set_watch_functions[dbus]"); + wpa_printf(MSG_ERROR, "Not enough memory to set up dbus."); + return -1; + } + + if (!dbus_connection_set_timeout_functions(connection, add_timeout, + remove_timeout, + timeout_toggled, iface, + NULL)) { + perror("dbus_connection_set_timeout_functions[dbus]"); + wpa_printf(MSG_ERROR, "Not enough memory to set up dbus."); + return -1; + } + + if (connection_setup_wakeup_main(iface) < 0) { + perror("connection_setup_wakeup_main[dbus]"); + wpa_printf(MSG_ERROR, "Could not setup main wakeup function."); + return -1; + } + + return 0; +} + + +/** + * dispatch_initial_dbus_messages - Dispatch initial dbus messages after + * claiming bus name + * @eloop_ctx: the DBusConnection to dispatch on + * @timeout_ctx: unused + * + * If clients are quick to notice that wpa_supplicant claimed its bus name, + * there may have been messages that came in before initialization was + * all finished. Dispatch those here. + */ +static void dispatch_initial_dbus_messages(void *eloop_ctx, void *timeout_ctx) +{ + DBusConnection *con = eloop_ctx; + + while (dbus_connection_get_dispatch_status(con) == + DBUS_DISPATCH_DATA_REMAINS) + dbus_connection_dispatch(con); +} + + +/** + * wpa_supplicant_dbus_ctrl_iface_init - Initialize dbus control interface + * @global: Pointer to global data from wpa_supplicant_init() + * Returns: Pointer to dbus_ctrl_iface date or %NULL on failure + * + * Initialize the dbus control interface and start receiving commands from + * external programs over the bus. + */ +struct ctrl_iface_dbus_priv * +wpa_supplicant_dbus_ctrl_iface_init(struct wpa_global *global) +{ + struct ctrl_iface_dbus_priv *iface; + DBusError error; + int ret = -1; + DBusObjectPathVTable wpas_vtable = { + NULL, &wpas_message_handler, NULL, NULL, NULL, NULL + }; + + iface = os_zalloc(sizeof(struct ctrl_iface_dbus_priv)); + if (iface == NULL) + return NULL; + + iface->global = global; + + /* Get a reference to the system bus */ + dbus_error_init(&error); + iface->con = dbus_bus_get(DBUS_BUS_SYSTEM, &error); + dbus_error_free(&error); + if (!iface->con) { + perror("dbus_bus_get[ctrl_iface_dbus]"); + wpa_printf(MSG_ERROR, "Could not acquire the system bus."); + goto fail; + } + + /* Tell dbus about our mainloop integration functions */ + if (integrate_with_eloop(iface->con, iface)) + goto fail; + + /* Register the message handler for the global dbus interface */ + if (!dbus_connection_register_object_path(iface->con, + WPAS_DBUS_PATH, &wpas_vtable, + iface)) { + perror("dbus_connection_register_object_path[dbus]"); + wpa_printf(MSG_ERROR, "Could not set up DBus message " + "handler."); + goto fail; + } + + /* Register our service with the message bus */ + dbus_error_init(&error); + switch (dbus_bus_request_name(iface->con, WPAS_DBUS_SERVICE, + 0, &error)) { + case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER: + ret = 0; + break; + case DBUS_REQUEST_NAME_REPLY_EXISTS: + case DBUS_REQUEST_NAME_REPLY_IN_QUEUE: + case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER: + perror("dbus_bus_request_name[dbus]"); + wpa_printf(MSG_ERROR, "Could not request DBus service name: " + "already registered."); + break; + default: + perror("dbus_bus_request_name[dbus]"); + wpa_printf(MSG_ERROR, "Could not request DBus service name: " + "%s %s.", error.name, error.message); + break; + } + dbus_error_free(&error); + + if (ret != 0) + goto fail; + + wpa_printf(MSG_DEBUG, "Providing DBus service '" WPAS_DBUS_SERVICE + "'."); + + /* + * Dispatch initial DBus messages that may have come in since the bus + * name was claimed above. Happens when clients are quick to notice the + * wpa_supplicant service. + * + * FIXME: is there a better solution to this problem? + */ + eloop_register_timeout(0, 50, dispatch_initial_dbus_messages, + iface->con, NULL); + + return iface; + +fail: + wpa_supplicant_dbus_ctrl_iface_deinit(iface); + return NULL; +} + + +/** + * wpa_supplicant_dbus_ctrl_iface_deinit - Deinitialize dbus ctrl interface + * @iface: Pointer to dbus private data from + * wpa_supplicant_dbus_ctrl_iface_init() + * + * Deinitialize the dbus control interface that was initialized with + * wpa_supplicant_dbus_ctrl_iface_init(). + */ +void wpa_supplicant_dbus_ctrl_iface_deinit(struct ctrl_iface_dbus_priv *iface) +{ + if (iface == NULL) + return; + + if (iface->con) { + eloop_cancel_timeout(dispatch_initial_dbus_messages, + iface->con, NULL); + dbus_connection_set_watch_functions(iface->con, NULL, NULL, + NULL, NULL, NULL); + dbus_connection_set_timeout_functions(iface->con, NULL, NULL, + NULL, NULL, NULL); + dbus_connection_unref(iface->con); + } + + memset(iface, 0, sizeof(struct ctrl_iface_dbus_priv)); + free(iface); +} + + +/** + * wpas_dbus_register_new_iface - Register a new interface with dbus + * @wpa_s: %wpa_supplicant interface description structure to register + * Returns: 0 on success, -1 on error + * + * Registers a new interface with dbus and assigns it a dbus object path. + */ +int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s) +{ + struct ctrl_iface_dbus_priv *ctrl_iface = + wpa_s->global->dbus_ctrl_iface; + DBusConnection * con; + u32 next; + DBusObjectPathVTable vtable = { + NULL, &wpas_iface_message_handler, NULL, NULL, NULL, NULL + }; + char *path; + int ret = -1; + + /* Do nothing if the control interface is not turned on */ + if (ctrl_iface == NULL) + return 0; + + con = ctrl_iface->con; + next = wpa_supplicant_dbus_next_objid(ctrl_iface); + + /* Create and set the interface's object path */ + path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); + if (path == NULL) + return -1; + snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, + WPAS_DBUS_PATH_INTERFACES "/%u", + next); + if (wpa_supplicant_set_dbus_path(wpa_s, path)) { + wpa_printf(MSG_DEBUG, + "Failed to set dbus path for interface %s", + wpa_s->ifname); + goto out; + } + + /* Register the message handler for the interface functions */ + if (!dbus_connection_register_fallback(con, path, &vtable, wpa_s)) { + perror("wpas_dbus_register_iface [dbus]"); + wpa_printf(MSG_ERROR, "Could not set up DBus message " + "handler for interface %s.", wpa_s->ifname); + goto out; + } + ret = 0; + +out: + free(path); + return ret; +} + + +/** + * wpas_dbus_unregister_iface - Unregister an interface from dbus + * @wpa_s: wpa_supplicant interface structure + * Returns: 0 on success, -1 on failure + * + * Unregisters the interface with dbus + */ +int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s) +{ + struct ctrl_iface_dbus_priv *ctrl_iface; + DBusConnection *con; + const char *path; + + /* Do nothing if the control interface is not turned on */ + if (wpa_s == NULL || wpa_s->global == NULL) + return 0; + ctrl_iface = wpa_s->global->dbus_ctrl_iface; + if (ctrl_iface == NULL) + return 0; + + con = ctrl_iface->con; + path = wpa_supplicant_get_dbus_path(wpa_s); + + if (!dbus_connection_unregister_object_path(con, path)) + return -1; + + free(wpa_s->dbus_path); + wpa_s->dbus_path = NULL; + + return 0; +} + + +/** + * wpa_supplicant_get_iface_by_dbus_path - Get a new network interface + * @global: Pointer to global data from wpa_supplicant_init() + * @path: Pointer to a dbus object path representing an interface + * Returns: Pointer to the interface or %NULL if not found + */ +struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path( + struct wpa_global *global, const char *path) +{ + struct wpa_supplicant *wpa_s; + + for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { + if (strcmp(wpa_s->dbus_path, path) == 0) + return wpa_s; + } + return NULL; +} + + +/** + * wpa_supplicant_set_dbus_path - Assign a dbus path to an interface + * @wpa_s: wpa_supplicant interface structure + * @path: dbus path to set on the interface + * Returns: 0 on succes, -1 on error + */ +int wpa_supplicant_set_dbus_path(struct wpa_supplicant *wpa_s, + const char *path) +{ + u32 len = strlen (path); + if (len >= WPAS_DBUS_OBJECT_PATH_MAX) + return -1; + if (wpa_s->dbus_path) + return -1; + wpa_s->dbus_path = strdup(path); + return 0; +} + + +/** + * wpa_supplicant_get_dbus_path - Get an interface's dbus path + * @wpa_s: %wpa_supplicant interface structure + * Returns: Interface's dbus object path, or %NULL on error + */ +const char * wpa_supplicant_get_dbus_path(struct wpa_supplicant *wpa_s) +{ + return wpa_s->dbus_path; +} diff --git a/wpa_supplicant/ctrl_iface_dbus.h b/wpa_supplicant/ctrl_iface_dbus.h new file mode 100644 index 000000000000..68919de0235e --- /dev/null +++ b/wpa_supplicant/ctrl_iface_dbus.h @@ -0,0 +1,156 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, 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 CTRL_IFACE_DBUS_H +#define CTRL_IFACE_DBUS_H + +struct wps_credential; + +#ifdef CONFIG_CTRL_IFACE_DBUS + +#ifndef SIGPOLL +#ifdef SIGIO +/* + * If we do not have SIGPOLL, try to use SIGIO instead. This is needed for + * FreeBSD. + */ +#define SIGPOLL SIGIO +#endif +#endif + +#include <dbus/dbus.h> + +#define WPAS_DBUS_OBJECT_PATH_MAX 150 + +#define WPAS_DBUS_SERVICE "fi.epitest.hostap.WPASupplicant" +#define WPAS_DBUS_PATH "/fi/epitest/hostap/WPASupplicant" +#define WPAS_DBUS_INTERFACE "fi.epitest.hostap.WPASupplicant" + +#define WPAS_DBUS_PATH_INTERFACES WPAS_DBUS_PATH "/Interfaces" +#define WPAS_DBUS_IFACE_INTERFACE WPAS_DBUS_INTERFACE ".Interface" + +#define WPAS_DBUS_NETWORKS_PART "Networks" +#define WPAS_DBUS_IFACE_NETWORK WPAS_DBUS_INTERFACE ".Network" + +#define WPAS_DBUS_BSSIDS_PART "BSSIDs" +#define WPAS_DBUS_IFACE_BSSID WPAS_DBUS_INTERFACE ".BSSID" + + +/* Errors */ +#define WPAS_ERROR_INVALID_NETWORK \ + WPAS_DBUS_IFACE_INTERFACE ".InvalidNetwork" +#define WPAS_ERROR_INVALID_BSSID \ + WPAS_DBUS_IFACE_INTERFACE ".InvalidBSSID" + +#define WPAS_ERROR_INVALID_OPTS \ + WPAS_DBUS_INTERFACE ".InvalidOptions" +#define WPAS_ERROR_INVALID_IFACE \ + WPAS_DBUS_INTERFACE ".InvalidInterface" + +#define WPAS_ERROR_ADD_ERROR \ + WPAS_DBUS_INTERFACE ".AddError" +#define WPAS_ERROR_EXISTS_ERROR \ + WPAS_DBUS_INTERFACE ".ExistsError" +#define WPAS_ERROR_REMOVE_ERROR \ + WPAS_DBUS_INTERFACE ".RemoveError" + +#define WPAS_ERROR_SCAN_ERROR \ + WPAS_DBUS_IFACE_INTERFACE ".ScanError" +#define WPAS_ERROR_ADD_NETWORK_ERROR \ + WPAS_DBUS_IFACE_INTERFACE ".AddNetworkError" +#define WPAS_ERROR_INTERNAL_ERROR \ + WPAS_DBUS_IFACE_INTERFACE ".InternalError" +#define WPAS_ERROR_REMOVE_NETWORK_ERROR \ + WPAS_DBUS_IFACE_INTERFACE ".RemoveNetworkError" + +#define WPAS_DBUS_BSSID_FORMAT "%02x%02x%02x%02x%02x%02x" + +struct wpa_global; +struct wpa_supplicant; + +struct ctrl_iface_dbus_priv * +wpa_supplicant_dbus_ctrl_iface_init(struct wpa_global *global); +void wpa_supplicant_dbus_ctrl_iface_deinit(struct ctrl_iface_dbus_priv *iface); +void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s); +void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s, + wpa_states new_state, + wpa_states old_state); +void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s, + const struct wps_credential *cred); + +char * wpas_dbus_decompose_object_path(const char *path, char **network, + char **bssid); + +int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s); +int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s); + + +/* Methods internal to the dbus control interface */ +u32 wpa_supplicant_dbus_next_objid(struct ctrl_iface_dbus_priv *iface); + +int wpa_supplicant_set_dbus_path(struct wpa_supplicant *wpa_s, + const char *path); +const char *wpa_supplicant_get_dbus_path(struct wpa_supplicant *wpa_s); +struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path( + struct wpa_global *global, const char *path); + +DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message); +DBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message); + +#else /* CONFIG_CTRL_IFACE_DBUS */ + +static inline struct ctrl_iface_dbus_priv * +wpa_supplicant_dbus_ctrl_iface_init(struct wpa_global *global) +{ + return (struct ctrl_iface_dbus_priv *) 1; +} + +static inline void +wpa_supplicant_dbus_ctrl_iface_deinit(struct ctrl_iface_dbus_priv *iface) +{ +} + +static inline void +wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s) +{ +} + +static inline void +wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s, + wpa_states new_state, + wpa_states old_state) +{ +} + +static inline void +wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s, + const struct wps_credential *cred) +{ +} + +static inline int +wpas_dbus_register_iface(struct wpa_supplicant *wpa_s) +{ + return 0; +} + +static inline int +wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s) +{ + return 0; +} + +#endif /* CONFIG_CTRL_IFACE_DBUS */ + +#endif /* CTRL_IFACE_DBUS_H */ diff --git a/wpa_supplicant/ctrl_iface_dbus_handlers.c b/wpa_supplicant/ctrl_iface_dbus_handlers.c new file mode 100644 index 000000000000..3c298043b3f7 --- /dev/null +++ b/wpa_supplicant/ctrl_iface_dbus_handlers.c @@ -0,0 +1,1410 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, 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 "common.h" +#include "config.h" +#include "wpa_supplicant_i.h" +#include "ctrl_iface_dbus.h" +#include "ctrl_iface_dbus_handlers.h" +#include "eap_peer/eap_methods.h" +#include "dbus_dict_helpers.h" +#include "ieee802_11_defs.h" +#include "wpas_glue.h" +#include "eapol_supp/eapol_supp_sm.h" + + +/** + * wpas_dbus_new_invalid_opts_error - Return a new invalid options error message + * @message: Pointer to incoming dbus message this error refers to + * Returns: a dbus error message + * + * Convenience function to create and return an invalid options error + */ +static DBusMessage * wpas_dbus_new_invalid_opts_error(DBusMessage *message, + const char *arg) +{ + DBusMessage *reply; + + reply = dbus_message_new_error(message, WPAS_ERROR_INVALID_OPTS, + "Did not receive correct message " + "arguments."); + if (arg != NULL) + dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg, + DBUS_TYPE_INVALID); + + return reply; +} + + +/** + * wpas_dbus_new_success_reply - Return a new success reply message + * @message: Pointer to incoming dbus message this reply refers to + * Returns: a dbus message containing a single UINT32 that indicates + * success (ie, a value of 1) + * + * Convenience function to create and return a success reply message + */ +static DBusMessage * wpas_dbus_new_success_reply(DBusMessage *message) +{ + DBusMessage *reply; + unsigned int success = 1; + + reply = dbus_message_new_method_return(message); + dbus_message_append_args(reply, DBUS_TYPE_UINT32, &success, + DBUS_TYPE_INVALID); + return reply; +} + + +static void wpas_dbus_free_wpa_interface(struct wpa_interface *iface) +{ + free((char *) iface->driver); + free((char *) iface->driver_param); + free((char *) iface->confname); + free((char *) iface->bridge_ifname); +} + + +/** + * wpas_dbus_global_add_interface - Request registration of a network interface + * @message: Pointer to incoming dbus message + * @global: %wpa_supplicant global data structure + * Returns: The object path of the new interface object, + * or a dbus error message with more information + * + * Handler function for "addInterface" method call. Handles requests + * by dbus clients to register a network interface that wpa_supplicant + * will manage. + */ +DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message, + struct wpa_global *global) +{ + struct wpa_interface iface; + char *ifname = NULL; + DBusMessage *reply = NULL; + DBusMessageIter iter; + + memset(&iface, 0, sizeof(iface)); + + dbus_message_iter_init(message, &iter); + + /* First argument: interface name (DBUS_TYPE_STRING) + * Required; must be non-zero length + */ + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) + goto error; + dbus_message_iter_get_basic(&iter, &ifname); + if (!strlen(ifname)) + goto error; + iface.ifname = ifname; + + /* Second argument: dict of options */ + if (dbus_message_iter_next(&iter)) { + DBusMessageIter iter_dict; + struct wpa_dbus_dict_entry entry; + + if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) + goto error; + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) + goto error; + if (!strcmp(entry.key, "driver") && + (entry.type == DBUS_TYPE_STRING)) { + iface.driver = strdup(entry.str_value); + if (iface.driver == NULL) + goto error; + } else if (!strcmp(entry.key, "driver-params") && + (entry.type == DBUS_TYPE_STRING)) { + iface.driver_param = strdup(entry.str_value); + if (iface.driver_param == NULL) + goto error; + } else if (!strcmp(entry.key, "config-file") && + (entry.type == DBUS_TYPE_STRING)) { + iface.confname = strdup(entry.str_value); + if (iface.confname == NULL) + goto error; + } else if (!strcmp(entry.key, "bridge-ifname") && + (entry.type == DBUS_TYPE_STRING)) { + iface.bridge_ifname = strdup(entry.str_value); + if (iface.bridge_ifname == NULL) + goto error; + } else { + wpa_dbus_dict_entry_clear(&entry); + goto error; + } + wpa_dbus_dict_entry_clear(&entry); + } + } + + /* + * Try to get the wpa_supplicant record for this iface, return + * an error if we already control it. + */ + if (wpa_supplicant_get_iface(global, iface.ifname) != NULL) { + reply = dbus_message_new_error(message, + WPAS_ERROR_EXISTS_ERROR, + "wpa_supplicant already " + "controls this interface."); + } else { + struct wpa_supplicant *wpa_s; + /* Otherwise, have wpa_supplicant attach to it. */ + if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) { + const char *path = wpa_supplicant_get_dbus_path(wpa_s); + reply = dbus_message_new_method_return(message); + dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, + &path, DBUS_TYPE_INVALID); + } else { + reply = dbus_message_new_error(message, + WPAS_ERROR_ADD_ERROR, + "wpa_supplicant " + "couldn't grab this " + "interface."); + } + } + wpas_dbus_free_wpa_interface(&iface); + return reply; + +error: + wpas_dbus_free_wpa_interface(&iface); + return wpas_dbus_new_invalid_opts_error(message, NULL); +} + + +/** + * wpas_dbus_global_remove_interface - Request deregistration of an interface + * @message: Pointer to incoming dbus message + * @global: wpa_supplicant global data structure + * Returns: a dbus message containing a UINT32 indicating success (1) or + * failure (0), or returns a dbus error message with more information + * + * Handler function for "removeInterface" method call. Handles requests + * by dbus clients to deregister a network interface that wpa_supplicant + * currently manages. + */ +DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message, + struct wpa_global *global) +{ + struct wpa_supplicant *wpa_s; + char *path; + DBusMessage *reply = NULL; + + if (!dbus_message_get_args(message, NULL, + DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID)) { + reply = wpas_dbus_new_invalid_opts_error(message, NULL); + goto out; + } + + wpa_s = wpa_supplicant_get_iface_by_dbus_path(global, path); + if (wpa_s == NULL) { + reply = wpas_dbus_new_invalid_iface_error(message); + goto out; + } + + if (!wpa_supplicant_remove_iface(global, wpa_s)) { + reply = wpas_dbus_new_success_reply(message); + } else { + reply = dbus_message_new_error(message, + WPAS_ERROR_REMOVE_ERROR, + "wpa_supplicant couldn't " + "remove this interface."); + } + +out: + return reply; +} + + +/** + * wpas_dbus_global_get_interface - Get the object path for an interface name + * @message: Pointer to incoming dbus message + * @global: %wpa_supplicant global data structure + * Returns: The object path of the interface object, + * or a dbus error message with more information + * + * Handler function for "getInterface" method call. Handles requests + * by dbus clients for the object path of an specific network interface. + */ +DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message, + struct wpa_global *global) +{ + DBusMessage *reply = NULL; + const char *ifname; + const char *path; + struct wpa_supplicant *wpa_s; + + if (!dbus_message_get_args(message, NULL, + DBUS_TYPE_STRING, &ifname, + DBUS_TYPE_INVALID)) { + reply = wpas_dbus_new_invalid_opts_error(message, NULL); + goto out; + } + + wpa_s = wpa_supplicant_get_iface(global, ifname); + if (wpa_s == NULL) { + reply = wpas_dbus_new_invalid_iface_error(message); + goto out; + } + + path = wpa_supplicant_get_dbus_path(wpa_s); + if (path == NULL) { + reply = dbus_message_new_error(message, + WPAS_ERROR_INTERNAL_ERROR, + "an internal error occurred " + "getting the interface."); + goto out; + } + + reply = dbus_message_new_method_return(message); + dbus_message_append_args(reply, + DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID); + +out: + return reply; +} + + +/** + * wpas_dbus_iface_scan - Request a wireless scan on an interface + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: a dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Handler function for "scan" method call of a network device. Requests + * that wpa_supplicant perform a wireless scan as soon as possible + * on a particular wireless interface. + */ +DBusMessage * wpas_dbus_iface_scan(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + wpa_s->scan_req = 2; + wpa_supplicant_req_scan(wpa_s, 0, 0); + return wpas_dbus_new_success_reply(message); +} + + +/** + * wpas_dbus_iface_scan_results - Get the results of a recent scan request + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: a dbus message containing a dbus array of objects paths, or returns + * a dbus error message if not scan results could be found + * + * Handler function for "scanResults" method call of a network device. Returns + * a dbus message containing the object paths of wireless networks found. + */ +DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter; + DBusMessageIter sub_iter; + size_t i; + + /* Ensure we've actually got scan results to return */ + if (wpa_s->scan_res == NULL && + wpa_supplicant_get_scan_results(wpa_s) < 0) { + reply = dbus_message_new_error(message, WPAS_ERROR_SCAN_ERROR, + "An error ocurred getting scan " + "results."); + goto out; + } + + /* Create and initialize the return message */ + reply = dbus_message_new_method_return(message); + dbus_message_iter_init_append(reply, &iter); + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_OBJECT_PATH_AS_STRING, + &sub_iter); + + /* Loop through scan results and append each result's object path */ + for (i = 0; i < wpa_s->scan_res->num; i++) { + struct wpa_scan_res *res = wpa_s->scan_res->res[i]; + char *path; + + path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); + if (path == NULL) { + perror("wpas_dbus_iface_scan_results[dbus]: out of " + "memory."); + wpa_printf(MSG_ERROR, "dbus control interface: not " + "enough memory to send scan results " + "signal."); + break; + } + /* Construct the object path for this network. Note that ':' + * is not a valid character in dbus object paths. + */ + snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_BSSIDS_PART "/" + WPAS_DBUS_BSSID_FORMAT, + wpa_supplicant_get_dbus_path(wpa_s), + MAC2STR(res->bssid)); + dbus_message_iter_append_basic(&sub_iter, + DBUS_TYPE_OBJECT_PATH, &path); + free(path); + } + + dbus_message_iter_close_container(&iter, &sub_iter); + +out: + return reply; +} + + +/** + * wpas_dbus_bssid_properties - Return the properties of a scanned network + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * @res: wpa_supplicant scan result for which to get properties + * Returns: a dbus message containing the properties for the requested network + * + * Handler function for "properties" method call of a scanned network. + * Returns a dbus message containing the the properties. + */ +DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message, + struct wpa_supplicant *wpa_s, + struct wpa_scan_res *res) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter, iter_dict; + const u8 *ie; + + /* Dump the properties into a dbus message */ + reply = dbus_message_new_method_return(message); + + dbus_message_iter_init_append(reply, &iter); + if (!wpa_dbus_dict_open_write(&iter, &iter_dict)) + goto error; + + if (!wpa_dbus_dict_append_byte_array(&iter_dict, "bssid", + (const char *) res->bssid, + ETH_ALEN)) + goto error; + + ie = wpa_scan_get_ie(res, WLAN_EID_SSID); + if (ie) { + if (!wpa_dbus_dict_append_byte_array(&iter_dict, "ssid", + (const char *) (ie + 2), + ie[1])) + goto error; + } + + ie = wpa_scan_get_vendor_ie(res, WPA_IE_VENDOR_TYPE); + if (ie) { + if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpaie", + (const char *) ie, + ie[1] + 2)) + goto error; + } + + ie = wpa_scan_get_ie(res, WLAN_EID_RSN); + if (ie) { + if (!wpa_dbus_dict_append_byte_array(&iter_dict, "rsnie", + (const char *) ie, + ie[1] + 2)) + goto error; + } + + ie = wpa_scan_get_vendor_ie(res, WPS_IE_VENDOR_TYPE); + if (ie) { + if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpsie", + (const char *) ie, + ie[1] + 2)) + goto error; + } + + if (res->freq) { + if (!wpa_dbus_dict_append_int32(&iter_dict, "frequency", + res->freq)) + goto error; + } + if (!wpa_dbus_dict_append_uint16(&iter_dict, "capabilities", + res->caps)) + goto error; + if (!wpa_dbus_dict_append_int32(&iter_dict, "quality", res->qual)) + goto error; + if (!wpa_dbus_dict_append_int32(&iter_dict, "noise", res->noise)) + goto error; + if (!wpa_dbus_dict_append_int32(&iter_dict, "level", res->level)) + goto error; + if (!wpa_dbus_dict_append_int32(&iter_dict, "maxrate", + wpa_scan_get_max_rate(res) * 500000)) + goto error; + + if (!wpa_dbus_dict_close_write(&iter, &iter_dict)) + goto error; + + return reply; + +error: + if (reply) + dbus_message_unref(reply); + return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR, + "an internal error occurred returning " + "BSSID properties."); +} + + +/** + * wpas_dbus_iface_capabilities - Return interface capabilities + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing a dict of strings + * + * Handler function for "capabilities" method call of an interface. + */ +DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + struct wpa_driver_capa capa; + int res; + DBusMessageIter iter, iter_dict; + char **eap_methods; + size_t num_items; + dbus_bool_t strict = FALSE; + DBusMessageIter iter_dict_entry, iter_dict_val, iter_array; + + if (!dbus_message_get_args(message, NULL, + DBUS_TYPE_BOOLEAN, &strict, + DBUS_TYPE_INVALID)) + strict = FALSE; + + reply = dbus_message_new_method_return(message); + + dbus_message_iter_init_append(reply, &iter); + if (!wpa_dbus_dict_open_write(&iter, &iter_dict)) + goto error; + + /* EAP methods */ + eap_methods = eap_get_names_as_string_array(&num_items); + if (eap_methods) { + dbus_bool_t success = FALSE; + size_t i = 0; + + success = wpa_dbus_dict_append_string_array( + &iter_dict, "eap", (const char **) eap_methods, + num_items); + + /* free returned method array */ + while (eap_methods[i]) + free(eap_methods[i++]); + free(eap_methods); + + if (!success) + goto error; + } + + res = wpa_drv_get_capa(wpa_s, &capa); + + /***** pairwise cipher */ + if (res < 0) { + if (!strict) { + const char *args[] = {"CCMP", "TKIP", "NONE"}; + if (!wpa_dbus_dict_append_string_array( + &iter_dict, "pairwise", args, + sizeof(args) / sizeof(char*))) + goto error; + } + } else { + if (!wpa_dbus_dict_begin_string_array(&iter_dict, "pairwise", + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto error; + + if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "CCMP")) + goto error; + } + + if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "TKIP")) + goto error; + } + + if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "NONE")) + goto error; + } + + if (!wpa_dbus_dict_end_string_array(&iter_dict, + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto error; + } + + /***** group cipher */ + if (res < 0) { + if (!strict) { + const char *args[] = { + "CCMP", "TKIP", "WEP104", "WEP40" + }; + if (!wpa_dbus_dict_append_string_array( + &iter_dict, "group", args, + sizeof(args) / sizeof(char*))) + goto error; + } + } else { + if (!wpa_dbus_dict_begin_string_array(&iter_dict, "group", + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto error; + + if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "CCMP")) + goto error; + } + + if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "TKIP")) + goto error; + } + + if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "WEP104")) + goto error; + } + + if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "WEP40")) + goto error; + } + + if (!wpa_dbus_dict_end_string_array(&iter_dict, + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto error; + } + + /***** key management */ + if (res < 0) { + if (!strict) { + const char *args[] = { + "WPA-PSK", "WPA-EAP", "IEEE8021X", "WPA-NONE", + "NONE" + }; + if (!wpa_dbus_dict_append_string_array( + &iter_dict, "key_mgmt", args, + sizeof(args) / sizeof(char*))) + goto error; + } + } else { + if (!wpa_dbus_dict_begin_string_array(&iter_dict, "key_mgmt", + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto error; + + if (!wpa_dbus_dict_string_array_add_element(&iter_array, + "NONE")) + goto error; + + if (!wpa_dbus_dict_string_array_add_element(&iter_array, + "IEEE8021X")) + goto error; + + if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | + WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "WPA-EAP")) + goto error; + } + + if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | + WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "WPA-PSK")) + goto error; + } + + if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "WPA-NONE")) + goto error; + } + + if (!wpa_dbus_dict_end_string_array(&iter_dict, + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto error; + } + + /***** WPA protocol */ + if (res < 0) { + if (!strict) { + const char *args[] = { "RSN", "WPA" }; + if (!wpa_dbus_dict_append_string_array( + &iter_dict, "proto", args, + sizeof(args) / sizeof(char*))) + goto error; + } + } else { + if (!wpa_dbus_dict_begin_string_array(&iter_dict, "proto", + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto error; + + if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | + WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "RSN")) + goto error; + } + + if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | + WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "WPA")) + goto error; + } + + if (!wpa_dbus_dict_end_string_array(&iter_dict, + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto error; + } + + /***** auth alg */ + if (res < 0) { + if (!strict) { + const char *args[] = { "OPEN", "SHARED", "LEAP" }; + if (!wpa_dbus_dict_append_string_array( + &iter_dict, "auth_alg", args, + sizeof(args) / sizeof(char*))) + goto error; + } + } else { + if (!wpa_dbus_dict_begin_string_array(&iter_dict, "auth_alg", + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto error; + + if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "OPEN")) + goto error; + } + + if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "SHARED")) + goto error; + } + + if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) { + if (!wpa_dbus_dict_string_array_add_element( + &iter_array, "LEAP")) + goto error; + } + + if (!wpa_dbus_dict_end_string_array(&iter_dict, + &iter_dict_entry, + &iter_dict_val, + &iter_array)) + goto error; + } + + if (!wpa_dbus_dict_close_write(&iter, &iter_dict)) + goto error; + + return reply; + +error: + if (reply) + dbus_message_unref(reply); + return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR, + "an internal error occurred returning " + "interface capabilities."); +} + + +/** + * wpas_dbus_iface_add_network - Add a new configured network + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing the object path of the new network + * + * Handler function for "addNetwork" method call of a network interface. + */ +DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + struct wpa_ssid *ssid; + char *path = NULL; + + path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); + if (path == NULL) { + perror("wpas_dbus_iface_scan_results[dbus]: out of " + "memory."); + wpa_printf(MSG_ERROR, "dbus control interface: not " + "enough memory to send scan results " + "signal."); + goto out; + } + + ssid = wpa_config_add_network(wpa_s->conf); + if (ssid == NULL) { + reply = dbus_message_new_error(message, + WPAS_ERROR_ADD_NETWORK_ERROR, + "wpa_supplicant could not add " + "a network on this interface."); + goto out; + } + ssid->disabled = 1; + wpa_config_set_network_defaults(ssid); + + /* Construct the object path for this network. */ + snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NETWORKS_PART "/%d", + wpa_supplicant_get_dbus_path(wpa_s), + ssid->id); + + reply = dbus_message_new_method_return(message); + dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, + &path, DBUS_TYPE_INVALID); + +out: + free(path); + return reply; +} + + +/** + * wpas_dbus_iface_remove_network - Remove a configured network + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Handler function for "removeNetwork" method call of a network interface. + */ +DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + const char *op; + char *iface = NULL, *net_id = NULL; + int id; + struct wpa_ssid *ssid; + + if (!dbus_message_get_args(message, NULL, + DBUS_TYPE_OBJECT_PATH, &op, + DBUS_TYPE_INVALID)) { + reply = wpas_dbus_new_invalid_opts_error(message, NULL); + goto out; + } + + /* Extract the network ID */ + iface = wpas_dbus_decompose_object_path(op, &net_id, NULL); + if (iface == NULL) { + reply = wpas_dbus_new_invalid_network_error(message); + goto out; + } + /* Ensure the network is actually a child of this interface */ + if (strcmp(iface, wpa_supplicant_get_dbus_path(wpa_s)) != 0) { + reply = wpas_dbus_new_invalid_network_error(message); + goto out; + } + + id = strtoul(net_id, NULL, 10); + ssid = wpa_config_get_network(wpa_s->conf, id); + if (ssid == NULL) { + reply = wpas_dbus_new_invalid_network_error(message); + goto out; + } + + if (wpa_config_remove_network(wpa_s->conf, id) < 0) { + reply = dbus_message_new_error(message, + WPAS_ERROR_REMOVE_NETWORK_ERROR, + "error removing the specified " + "on this interface."); + goto out; + } + + if (ssid == wpa_s->current_ssid) + wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); + reply = wpas_dbus_new_success_reply(message); + +out: + free(iface); + free(net_id); + return reply; +} + + +static const char *dont_quote[] = { + "key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap", + "opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path", + "bssid", NULL +}; + +static dbus_bool_t should_quote_opt(const char *key) +{ + int i = 0; + while (dont_quote[i] != NULL) { + if (strcmp(key, dont_quote[i]) == 0) + return FALSE; + i++; + } + return TRUE; +} + +/** + * wpas_dbus_iface_set_network - Set options for a configured network + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * @ssid: wpa_ssid structure for a configured network + * Returns: a dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Handler function for "set" method call of a configured network. + */ +DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message, + struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + DBusMessage *reply = NULL; + struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING }; + DBusMessageIter iter, iter_dict; + + dbus_message_iter_init(message, &iter); + + if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) { + reply = wpas_dbus_new_invalid_opts_error(message, NULL); + goto out; + } + + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + char *value = NULL; + size_t size = 50; + int ret; + + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) { + reply = wpas_dbus_new_invalid_opts_error(message, + NULL); + goto out; + } + + /* Type conversions, since wpa_supplicant wants strings */ + if (entry.type == DBUS_TYPE_ARRAY && + entry.array_type == DBUS_TYPE_BYTE) { + if (entry.array_len <= 0) + goto error; + + size = entry.array_len * 2 + 1; + value = os_zalloc(size); + if (value == NULL) + goto error; + ret = wpa_snprintf_hex(value, size, + (u8 *) entry.bytearray_value, + entry.array_len); + if (ret <= 0) + goto error; + } else if (entry.type == DBUS_TYPE_STRING) { + if (should_quote_opt(entry.key)) { + size = strlen(entry.str_value); + /* Zero-length option check */ + if (size <= 0) + goto error; + size += 3; /* For quotes and terminator */ + value = os_zalloc(size); + if (value == NULL) + goto error; + ret = snprintf(value, size, "\"%s\"", + entry.str_value); + if (ret < 0 || (size_t) ret != (size - 1)) + goto error; + } else { + value = strdup(entry.str_value); + if (value == NULL) + goto error; + } + } else if (entry.type == DBUS_TYPE_UINT32) { + value = os_zalloc(size); + if (value == NULL) + goto error; + ret = snprintf(value, size, "%u", entry.uint32_value); + if (ret <= 0) + goto error; + } else if (entry.type == DBUS_TYPE_INT32) { + value = os_zalloc(size); + if (value == NULL) + goto error; + ret = snprintf(value, size, "%d", entry.int32_value); + if (ret <= 0) + goto error; + } else + goto error; + + if (wpa_config_set(ssid, entry.key, value, 0) < 0) + goto error; + + if ((strcmp(entry.key, "psk") == 0 && + value[0] == '"' && ssid->ssid_len) || + (strcmp(entry.key, "ssid") == 0 && ssid->passphrase)) + wpa_config_update_psk(ssid); + + free(value); + wpa_dbus_dict_entry_clear(&entry); + continue; + + error: + free(value); + reply = wpas_dbus_new_invalid_opts_error(message, entry.key); + wpa_dbus_dict_entry_clear(&entry); + break; + } + + if (!reply) + reply = wpas_dbus_new_success_reply(message); + +out: + return reply; +} + + +/** + * wpas_dbus_iface_enable_network - Mark a configured network as enabled + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * @ssid: wpa_ssid structure for a configured network + * Returns: A dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Handler function for "enable" method call of a configured network. + */ +DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message, + struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + if (wpa_s->current_ssid == NULL && ssid->disabled) { + /* + * Try to reassociate since there is no current configuration + * and a new network was made available. + */ + wpa_s->reassociate = 1; + wpa_supplicant_req_scan(wpa_s, 0, 0); + } + ssid->disabled = 0; + + return wpas_dbus_new_success_reply(message); +} + + +/** + * wpas_dbus_iface_disable_network - Mark a configured network as disabled + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * @ssid: wpa_ssid structure for a configured network + * Returns: A dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Handler function for "disable" method call of a configured network. + */ +DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message, + struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + if (ssid == wpa_s->current_ssid) + wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); + ssid->disabled = 1; + + return wpas_dbus_new_success_reply(message); +} + + +/** + * wpas_dbus_iface_select_network - Attempt association with a configured network + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Handler function for "selectNetwork" method call of network interface. + */ +DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + const char *op; + struct wpa_ssid *ssid; + char *iface_obj_path = NULL; + char *network = NULL; + + if (strlen(dbus_message_get_signature(message)) == 0) { + /* Any network */ + ssid = wpa_s->conf->ssid; + while (ssid) { + ssid->disabled = 0; + ssid = ssid->next; + } + wpa_s->reassociate = 1; + wpa_supplicant_req_scan(wpa_s, 0, 0); + } else { + const char *obj_path; + int nid; + + if (!dbus_message_get_args(message, NULL, + DBUS_TYPE_OBJECT_PATH, &op, + DBUS_TYPE_INVALID)) { + reply = wpas_dbus_new_invalid_opts_error(message, + NULL); + goto out; + } + + /* Extract the network number */ + iface_obj_path = wpas_dbus_decompose_object_path(op, + &network, + NULL); + if (iface_obj_path == NULL) { + reply = wpas_dbus_new_invalid_iface_error(message); + goto out; + } + /* Ensure the object path really points to this interface */ + obj_path = wpa_supplicant_get_dbus_path(wpa_s); + if (strcmp(iface_obj_path, obj_path) != 0) { + reply = wpas_dbus_new_invalid_network_error(message); + goto out; + } + + nid = strtoul(network, NULL, 10); + if (errno == EINVAL) { + reply = wpas_dbus_new_invalid_network_error(message); + goto out; + } + + ssid = wpa_config_get_network(wpa_s->conf, nid); + if (ssid == NULL) { + reply = wpas_dbus_new_invalid_network_error(message); + goto out; + } + + /* Finally, associate with the network */ + if (ssid != wpa_s->current_ssid && wpa_s->current_ssid) + wpa_supplicant_disassociate( + wpa_s, WLAN_REASON_DEAUTH_LEAVING); + + /* Mark all other networks disabled and trigger reassociation + */ + ssid = wpa_s->conf->ssid; + while (ssid) { + ssid->disabled = (nid != ssid->id); + ssid = ssid->next; + } + wpa_s->disconnected = 0; + wpa_s->reassociate = 1; + wpa_supplicant_req_scan(wpa_s, 0, 0); + } + + reply = wpas_dbus_new_success_reply(message); + +out: + free(iface_obj_path); + free(network); + return reply; +} + + +/** + * wpas_dbus_iface_disconnect - Terminate the current connection + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Handler function for "disconnect" method call of network interface. + */ +DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + wpa_s->disconnected = 1; + wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); + + return wpas_dbus_new_success_reply(message); +} + + +/** + * wpas_dbus_iface_set_ap_scan - Control roaming mode + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Handler function for "setAPScan" method call. + */ +DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + dbus_uint32_t ap_scan = 1; + + if (!dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &ap_scan, + DBUS_TYPE_INVALID)) { + reply = wpas_dbus_new_invalid_opts_error(message, NULL); + goto out; + } + + if (ap_scan > 2) { + reply = wpas_dbus_new_invalid_opts_error(message, NULL); + goto out; + } + wpa_s->conf->ap_scan = ap_scan; + reply = wpas_dbus_new_success_reply(message); + +out: + return reply; +} + + +/** + * wpas_dbus_iface_set_smartcard_modules - Set smartcard related module paths + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Handler function for "setSmartcardModules" method call. + */ +DBusMessage * wpas_dbus_iface_set_smartcard_modules( + DBusMessage *message, struct wpa_supplicant *wpa_s) +{ + DBusMessageIter iter, iter_dict; + char *opensc_engine_path = NULL; + char *pkcs11_engine_path = NULL; + char *pkcs11_module_path = NULL; + struct wpa_dbus_dict_entry entry; + + if (!dbus_message_iter_init(message, &iter)) + goto error; + + if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) + goto error; + + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) + goto error; + if (!strcmp(entry.key, "opensc_engine_path") && + (entry.type == DBUS_TYPE_STRING)) { + opensc_engine_path = os_strdup(entry.str_value); + if (opensc_engine_path == NULL) + goto error; + } else if (!strcmp(entry.key, "pkcs11_engine_path") && + (entry.type == DBUS_TYPE_STRING)) { + pkcs11_engine_path = os_strdup(entry.str_value); + if (pkcs11_engine_path == NULL) + goto error; + } else if (!strcmp(entry.key, "pkcs11_module_path") && + (entry.type == DBUS_TYPE_STRING)) { + pkcs11_module_path = os_strdup(entry.str_value); + if (pkcs11_module_path == NULL) + goto error; + } else { + wpa_dbus_dict_entry_clear(&entry); + goto error; + } + wpa_dbus_dict_entry_clear(&entry); + } + +#ifdef EAP_TLS_OPENSSL + os_free(wpa_s->conf->opensc_engine_path); + wpa_s->conf->opensc_engine_path = opensc_engine_path; + os_free(wpa_s->conf->pkcs11_engine_path); + wpa_s->conf->pkcs11_engine_path = pkcs11_engine_path; + os_free(wpa_s->conf->pkcs11_module_path); + wpa_s->conf->pkcs11_module_path = pkcs11_module_path; +#endif /* EAP_TLS_OPENSSL */ + + eapol_sm_deinit(wpa_s->eapol); + wpa_supplicant_init_eapol(wpa_s); + + return wpas_dbus_new_success_reply(message); + +error: + os_free(opensc_engine_path); + os_free(pkcs11_engine_path); + os_free(pkcs11_module_path); + return wpas_dbus_new_invalid_opts_error(message, NULL); +} + +/** + * wpas_dbus_iface_get_state - Get interface state + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing a STRING representing the current + * interface state + * + * Handler function for "state" method call. + */ +DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + const char *str_state; + + reply = dbus_message_new_method_return(message); + if (reply != NULL) { + str_state = wpa_supplicant_state_txt(wpa_s->wpa_state); + dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_state, + DBUS_TYPE_INVALID); + } + + return reply; +} + + +/** + * wpas_dbus_iface_set_blobs - Store named binary blobs (ie, for certificates) + * @message: Pointer to incoming dbus message + * @wpa_s: %wpa_supplicant data structure + * Returns: A dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Asks wpa_supplicant to internally store a one or more binary blobs. + */ +DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING }; + DBusMessageIter iter, iter_dict; + + dbus_message_iter_init(message, &iter); + + if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) + return wpas_dbus_new_invalid_opts_error(message, NULL); + + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + struct wpa_config_blob *blob; + + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) { + reply = wpas_dbus_new_invalid_opts_error(message, + NULL); + break; + } + + if (entry.type != DBUS_TYPE_ARRAY || + entry.array_type != DBUS_TYPE_BYTE) { + reply = wpas_dbus_new_invalid_opts_error( + message, "Byte array expected."); + break; + } + + if ((entry.array_len <= 0) || (entry.array_len > 65536) || + !strlen(entry.key)) { + reply = wpas_dbus_new_invalid_opts_error( + message, "Invalid array size."); + break; + } + + blob = os_zalloc(sizeof(*blob)); + if (blob == NULL) { + reply = dbus_message_new_error( + message, WPAS_ERROR_ADD_ERROR, + "Not enough memory to add blob."); + break; + } + blob->data = os_zalloc(entry.array_len); + if (blob->data == NULL) { + reply = dbus_message_new_error( + message, WPAS_ERROR_ADD_ERROR, + "Not enough memory to add blob data."); + os_free(blob); + break; + } + + blob->name = os_strdup(entry.key); + blob->len = entry.array_len; + os_memcpy(blob->data, (u8 *) entry.bytearray_value, + entry.array_len); + if (blob->name == NULL || blob->data == NULL) { + wpa_config_free_blob(blob); + reply = dbus_message_new_error( + message, WPAS_ERROR_ADD_ERROR, + "Error adding blob."); + break; + } + + /* Success */ + wpa_config_remove_blob(wpa_s->conf, blob->name); + wpa_config_set_blob(wpa_s->conf, blob); + wpa_dbus_dict_entry_clear(&entry); + } + wpa_dbus_dict_entry_clear(&entry); + + return reply ? reply : wpas_dbus_new_success_reply(message); +} + + +/** + * wpas_dbus_iface_remove_blob - Remove named binary blobs + * @message: Pointer to incoming dbus message + * @wpa_s: %wpa_supplicant data structure + * Returns: A dbus message containing a UINT32 indicating success (1) or + * failure (0) + * + * Asks wpa_supplicant to remove one or more previously stored binary blobs. + */ +DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessageIter iter, array; + char *err_msg = NULL; + + dbus_message_iter_init(message, &iter); + + if ((dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) || + (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_STRING)) + return wpas_dbus_new_invalid_opts_error(message, NULL); + + dbus_message_iter_recurse(&iter, &array); + while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) { + const char *name; + + dbus_message_iter_get_basic(&array, &name); + if (!strlen(name)) + err_msg = "Invalid blob name."; + + if (wpa_config_remove_blob(wpa_s->conf, name) != 0) + err_msg = "Error removing blob."; + dbus_message_iter_next(&array); + } + + if (err_msg) { + return dbus_message_new_error(message, WPAS_ERROR_REMOVE_ERROR, + err_msg); + } + + return wpas_dbus_new_success_reply(message); +} diff --git a/wpa_supplicant/ctrl_iface_dbus_handlers.h b/wpa_supplicant/ctrl_iface_dbus_handlers.h new file mode 100644 index 000000000000..9660f9598a3c --- /dev/null +++ b/wpa_supplicant/ctrl_iface_dbus_handlers.h @@ -0,0 +1,86 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, 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 CTRL_IFACE_DBUS_HANDLERS_H +#define CTRL_IFACE_DBUS_HANDLERS_H + +#ifdef CONFIG_CTRL_IFACE_DBUS + +DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message); + +DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message, + struct wpa_global *global); + +DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message, + struct wpa_global *global); + +DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message, + struct wpa_global *global); + +DBusMessage * wpas_dbus_iface_scan(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message, + struct wpa_supplicant *wpa_s, + struct wpa_scan_res *res); + +DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message, + struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid); + +DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message, + struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid); + +DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message, + struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid); + +DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_set_smartcard_modules( + DBusMessage *message, struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +#endif /* CONFIG_CTRL_IFACE_DBUS */ + +#endif /* CTRL_IFACE_DBUS_HANDLERS_H */ + diff --git a/wpa_supplicant/ctrl_iface_named_pipe.c b/wpa_supplicant/ctrl_iface_named_pipe.c new file mode 100644 index 000000000000..e8b53b194581 --- /dev/null +++ b/wpa_supplicant/ctrl_iface_named_pipe.c @@ -0,0 +1,835 @@ +/* + * WPA Supplicant / Windows Named Pipe -based control interface + * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "eloop.h" +#include "config.h" +#include "eapol_supp/eapol_supp_sm.h" +#include "wpa_supplicant_i.h" +#include "ctrl_iface.h" +#include "wpa_ctrl.h" + +#ifdef __MINGW32_VERSION +/* mingw-w32api v3.1 does not yet include sddl.h, so define needed parts here + */ +#define SDDL_REVISION_1 1 +BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorA( + LPCSTR, DWORD, PSECURITY_DESCRIPTOR *, PULONG); +BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorW( + LPCWSTR, DWORD, PSECURITY_DESCRIPTOR *, PULONG); +#ifdef UNICODE +#define ConvertStringSecurityDescriptorToSecurityDescriptor \ +ConvertStringSecurityDescriptorToSecurityDescriptorW +#else +#define ConvertStringSecurityDescriptorToSecurityDescriptor \ +ConvertStringSecurityDescriptorToSecurityDescriptorA +#endif +#else /* __MINGW32_VERSION */ +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0500 +#endif +#include <sddl.h> +#endif /* __MINGW32_VERSION */ + +#ifndef WPA_SUPPLICANT_NAMED_PIPE +#define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant" +#endif +#define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE) + +/* Per-interface ctrl_iface */ + +#define REQUEST_BUFSIZE 256 +#define REPLY_BUFSIZE 4096 + +struct ctrl_iface_priv; + +/** + * struct wpa_ctrl_dst - Internal data structure of control interface clients + * + * This structure is used to store information about registered control + * interface monitors into struct wpa_supplicant. This data is private to + * ctrl_iface_named_pipe.c and should not be touched directly from other files. + */ +struct wpa_ctrl_dst { + /* Note: OVERLAPPED must be the first member of struct wpa_ctrl_dst */ + OVERLAPPED overlap; + struct wpa_ctrl_dst *next, *prev; + struct ctrl_iface_priv *priv; + HANDLE pipe; + int attached; + int debug_level; + int errors; + char req_buf[REQUEST_BUFSIZE]; + char *rsp_buf; + int used; +}; + + +struct ctrl_iface_priv { + struct wpa_supplicant *wpa_s; + struct wpa_ctrl_dst *ctrl_dst; + SECURITY_ATTRIBUTES attr; + int sec_attr_set; +}; + + +static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, + int level, const char *buf, + size_t len); + +static void ctrl_close_pipe(struct wpa_ctrl_dst *dst); +static void wpa_supplicant_ctrl_iface_receive(void *, void *); +static VOID WINAPI ctrl_iface_read_completed(DWORD err, DWORD bytes, + LPOVERLAPPED overlap); + +struct wpa_global_dst; +static void global_close_pipe(struct wpa_global_dst *dst); +static void wpa_supplicant_global_iface_receive(void *eloop_data, + void *user_ctx); +static VOID WINAPI global_iface_read_completed(DWORD err, DWORD bytes, + LPOVERLAPPED overlap); + + +static int ctrl_broken_pipe(HANDLE pipe, int used) +{ + DWORD err; + + if (PeekNamedPipe(pipe, NULL, 0, NULL, NULL, NULL)) + return 0; + + err = GetLastError(); + if (err == ERROR_BROKEN_PIPE || (err == ERROR_BAD_PIPE && used)) + return 1; + return 0; +} + + +static void ctrl_flush_broken_pipes(struct ctrl_iface_priv *priv) +{ + struct wpa_ctrl_dst *dst, *next; + + dst = priv->ctrl_dst; + + while (dst) { + next = dst->next; + if (ctrl_broken_pipe(dst->pipe, dst->used)) { + wpa_printf(MSG_DEBUG, "CTRL: closing broken pipe %p", + dst); + ctrl_close_pipe(dst); + } + dst = next; + } +} + + +static int ctrl_open_pipe(struct ctrl_iface_priv *priv) +{ + struct wpa_ctrl_dst *dst; + DWORD err; + TCHAR name[256]; + + dst = os_zalloc(sizeof(*dst)); + if (dst == NULL) + return -1; + wpa_printf(MSG_DEBUG, "CTRL: Open pipe %p", dst); + + dst->priv = priv; + dst->debug_level = MSG_INFO; + dst->pipe = INVALID_HANDLE_VALUE; + + dst->overlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); + if (dst->overlap.hEvent == NULL) { + wpa_printf(MSG_ERROR, "CTRL: CreateEvent failed: %d", + (int) GetLastError()); + goto fail; + } + + eloop_register_event(dst->overlap.hEvent, + sizeof(dst->overlap.hEvent), + wpa_supplicant_ctrl_iface_receive, dst, NULL); + +#ifdef UNICODE + _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"), + priv->wpa_s->ifname); +#else /* UNICODE */ + os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s", + priv->wpa_s->ifname); +#endif /* UNICODE */ + + /* TODO: add support for configuring access list for the pipe */ + dst->pipe = CreateNamedPipe(name, + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_MESSAGE | + PIPE_READMODE_MESSAGE | + PIPE_WAIT, + 15, REPLY_BUFSIZE, REQUEST_BUFSIZE, + 1000, + priv->sec_attr_set ? &priv->attr : NULL); + if (dst->pipe == INVALID_HANDLE_VALUE) { + wpa_printf(MSG_ERROR, "CTRL: CreateNamedPipe failed: %d", + (int) GetLastError()); + goto fail; + } + + if (ConnectNamedPipe(dst->pipe, &dst->overlap)) { + wpa_printf(MSG_ERROR, "CTRL: ConnectNamedPipe failed: %d", + (int) GetLastError()); + CloseHandle(dst->pipe); + os_free(dst); + return -1; + } + + err = GetLastError(); + switch (err) { + case ERROR_IO_PENDING: + wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: connection in " + "progress"); + break; + case ERROR_PIPE_CONNECTED: + wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: already " + "connected"); + if (SetEvent(dst->overlap.hEvent)) + break; + /* fall through */ + default: + wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe error: %d", + (int) err); + CloseHandle(dst->pipe); + os_free(dst); + return -1; + } + + dst->next = priv->ctrl_dst; + if (dst->next) + dst->next->prev = dst; + priv->ctrl_dst = dst; + + return 0; + +fail: + ctrl_close_pipe(dst); + return -1; +} + + +static void ctrl_close_pipe(struct wpa_ctrl_dst *dst) +{ + wpa_printf(MSG_DEBUG, "CTRL: close pipe %p", dst); + + if (dst->overlap.hEvent) { + eloop_unregister_event(dst->overlap.hEvent, + sizeof(dst->overlap.hEvent)); + CloseHandle(dst->overlap.hEvent); + } + + if (dst->pipe != INVALID_HANDLE_VALUE) { + /* + * Could use FlushFileBuffers() here to guarantee that all data + * gets delivered to the client, but that can block, so let's + * not do this for now. + * FlushFileBuffers(dst->pipe); + */ + CloseHandle(dst->pipe); + } + + if (dst->prev) + dst->prev->next = dst->next; + else + dst->priv->ctrl_dst = dst->next; + if (dst->next) + dst->next->prev = dst->prev; + + os_free(dst->rsp_buf); + os_free(dst); +} + + +static VOID WINAPI ctrl_iface_write_completed(DWORD err, DWORD bytes, + LPOVERLAPPED overlap) +{ + struct wpa_ctrl_dst *dst = (struct wpa_ctrl_dst *) overlap; + wpa_printf(MSG_DEBUG, "CTRL: Overlapped write completed: dst=%p " + "err=%d bytes=%d", dst, (int) err, (int) bytes); + if (err) { + ctrl_close_pipe(dst); + return; + } + + os_free(dst->rsp_buf); + dst->rsp_buf = NULL; + + if (!ReadFileEx(dst->pipe, dst->req_buf, sizeof(dst->req_buf), + &dst->overlap, ctrl_iface_read_completed)) { + wpa_printf(MSG_DEBUG, "CTRL: ReadFileEx failed: %d", + (int) GetLastError()); + ctrl_close_pipe(dst); + return; + } + wpa_printf(MSG_DEBUG, "CTRL: Overlapped read started for %p", dst); +} + + +static void wpa_supplicant_ctrl_iface_rx(struct wpa_ctrl_dst *dst, size_t len) +{ + struct wpa_supplicant *wpa_s = dst->priv->wpa_s; + char *reply = NULL, *send_buf; + size_t reply_len = 0, send_len; + int new_attached = 0; + char *buf = dst->req_buf; + + dst->used = 1; + if (len >= REQUEST_BUFSIZE) + len = REQUEST_BUFSIZE - 1; + buf[len] = '\0'; + + if (os_strcmp(buf, "ATTACH") == 0) { + dst->attached = 1; + wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached"); + new_attached = 1; + reply_len = 2; + } else if (os_strcmp(buf, "DETACH") == 0) { + dst->attached = 0; + wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached"); + reply_len = 2; + } else if (os_strncmp(buf, "LEVEL ", 6) == 0) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", buf + 6); + dst->debug_level = atoi(buf + 6); + reply_len = 2; + } else { + reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf, + &reply_len); + } + + if (reply) { + send_buf = reply; + send_len = reply_len; + } else if (reply_len == 2) { + send_buf = "OK\n"; + send_len = 3; + } else { + send_buf = "FAIL\n"; + send_len = 5; + } + + os_free(dst->rsp_buf); + dst->rsp_buf = os_malloc(send_len); + if (dst->rsp_buf == NULL) { + ctrl_close_pipe(dst); + os_free(reply); + return; + } + os_memcpy(dst->rsp_buf, send_buf, send_len); + os_free(reply); + + if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap, + ctrl_iface_write_completed)) { + wpa_printf(MSG_DEBUG, "CTRL: WriteFileEx failed: %d", + (int) GetLastError()); + ctrl_close_pipe(dst); + } else { + wpa_printf(MSG_DEBUG, "CTRL: Overlapped write started for %p", + dst); + } + + if (new_attached) + eapol_sm_notify_ctrl_attached(wpa_s->eapol); +} + + +static VOID WINAPI ctrl_iface_read_completed(DWORD err, DWORD bytes, + LPOVERLAPPED overlap) +{ + struct wpa_ctrl_dst *dst = (struct wpa_ctrl_dst *) overlap; + wpa_printf(MSG_DEBUG, "CTRL: Overlapped read completed: dst=%p err=%d " + "bytes=%d", dst, (int) err, (int) bytes); + if (err == 0 && bytes > 0) + wpa_supplicant_ctrl_iface_rx(dst, bytes); +} + + +static void wpa_supplicant_ctrl_iface_receive(void *eloop_data, void *user_ctx) +{ + struct wpa_ctrl_dst *dst = eloop_data; + struct ctrl_iface_priv *priv = dst->priv; + DWORD bytes; + + wpa_printf(MSG_DEBUG, "CTRL: wpa_supplicant_ctrl_iface_receive"); + ResetEvent(dst->overlap.hEvent); + + if (!GetOverlappedResult(dst->pipe, &dst->overlap, &bytes, FALSE)) { + wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult failed: %d", + (int) GetLastError()); + return; + } + wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult: New client " + "connected"); + + /* Open a new named pipe for the next client. */ + ctrl_open_pipe(priv); + + /* Use write completion function to start reading a command */ + ctrl_iface_write_completed(0, 0, &dst->overlap); + + ctrl_flush_broken_pipes(priv); +} + + +static int ctrl_iface_parse(struct ctrl_iface_priv *priv, const char *params) +{ + const char *sddl = NULL; + TCHAR *t_sddl; + + if (os_strncmp(params, "SDDL=", 5) == 0) + sddl = params + 5; + if (!sddl) { + sddl = os_strstr(params, " SDDL="); + if (sddl) + sddl += 6; + } + + if (!sddl) + return 0; + + wpa_printf(MSG_DEBUG, "CTRL: SDDL='%s'", sddl); + os_memset(&priv->attr, 0, sizeof(priv->attr)); + priv->attr.nLength = sizeof(priv->attr); + priv->attr.bInheritHandle = FALSE; + t_sddl = wpa_strdup_tchar(sddl); + if (t_sddl == NULL) + return -1; + if (!ConvertStringSecurityDescriptorToSecurityDescriptor( + t_sddl, SDDL_REVISION_1, + (PSECURITY_DESCRIPTOR *) (void *) + &priv->attr.lpSecurityDescriptor, + NULL)) { + os_free(t_sddl); + wpa_printf(MSG_ERROR, "CTRL: SDDL='%s' - could not convert to " + "security descriptor: %d", + sddl, (int) GetLastError()); + return -1; + } + os_free(t_sddl); + + priv->sec_attr_set = 1; + + return 0; +} + + +static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, + const char *txt, size_t len) +{ + struct wpa_supplicant *wpa_s = ctx; + if (wpa_s == NULL || wpa_s->ctrl_iface == NULL) + return; + wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len); +} + + +struct ctrl_iface_priv * +wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) +{ + struct ctrl_iface_priv *priv; + + priv = os_zalloc(sizeof(*priv)); + if (priv == NULL) + return NULL; + priv->wpa_s = wpa_s; + + if (wpa_s->conf->ctrl_interface == NULL) + return priv; + + if (ctrl_iface_parse(priv, wpa_s->conf->ctrl_interface) < 0) { + os_free(priv); + return NULL; + } + + if (ctrl_open_pipe(priv) < 0) { + os_free(priv); + return NULL; + } + + wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); + + return priv; +} + + +void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) +{ + while (priv->ctrl_dst) + ctrl_close_pipe(priv->ctrl_dst); + if (priv->sec_attr_set) + LocalFree(priv->attr.lpSecurityDescriptor); + os_free(priv); +} + + +static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, + int level, const char *buf, + size_t len) +{ + struct wpa_ctrl_dst *dst, *next; + char levelstr[10]; + int idx; + char *sbuf; + int llen; + DWORD written; + + dst = priv->ctrl_dst; + if (dst == NULL) + return; + + os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); + + llen = os_strlen(levelstr); + sbuf = os_malloc(llen + len); + if (sbuf == NULL) + return; + + os_memcpy(sbuf, levelstr, llen); + os_memcpy(sbuf + llen, buf, len); + + idx = 0; + while (dst) { + next = dst->next; + if (dst->attached && level >= dst->debug_level) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %p", + dst); + if (!WriteFile(dst->pipe, sbuf, llen + len, &written, + NULL)) { + wpa_printf(MSG_DEBUG, "CTRL: WriteFile to dst " + "%p failed: %d", + dst, (int) GetLastError()); + dst->errors++; + if (dst->errors > 10) + ctrl_close_pipe(dst); + } else + dst->errors = 0; + } + idx++; + dst = next; + } + os_free(sbuf); +} + + +void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) +{ + wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor", + priv->wpa_s->ifname); + if (priv->ctrl_dst == NULL) + return; + WaitForSingleObject(priv->ctrl_dst->pipe, INFINITE); +} + + +/* Global ctrl_iface */ + +struct ctrl_iface_global_priv; + +struct wpa_global_dst { + /* Note: OVERLAPPED must be the first member of struct wpa_global_dst + */ + OVERLAPPED overlap; + struct wpa_global_dst *next, *prev; + struct ctrl_iface_global_priv *priv; + HANDLE pipe; + char req_buf[REQUEST_BUFSIZE]; + char *rsp_buf; + int used; +}; + +struct ctrl_iface_global_priv { + struct wpa_global *global; + struct wpa_global_dst *ctrl_dst; +}; + + +static void global_flush_broken_pipes(struct ctrl_iface_global_priv *priv) +{ + struct wpa_global_dst *dst, *next; + + dst = priv->ctrl_dst; + + while (dst) { + next = dst->next; + if (ctrl_broken_pipe(dst->pipe, dst->used)) { + wpa_printf(MSG_DEBUG, "CTRL: closing broken pipe %p", + dst); + global_close_pipe(dst); + } + dst = next; + } +} + + +static int global_open_pipe(struct ctrl_iface_global_priv *priv) +{ + struct wpa_global_dst *dst; + DWORD err; + + dst = os_zalloc(sizeof(*dst)); + if (dst == NULL) + return -1; + wpa_printf(MSG_DEBUG, "CTRL: Open pipe %p", dst); + + dst->priv = priv; + dst->pipe = INVALID_HANDLE_VALUE; + + dst->overlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); + if (dst->overlap.hEvent == NULL) { + wpa_printf(MSG_ERROR, "CTRL: CreateEvent failed: %d", + (int) GetLastError()); + goto fail; + } + + eloop_register_event(dst->overlap.hEvent, + sizeof(dst->overlap.hEvent), + wpa_supplicant_global_iface_receive, dst, NULL); + + /* TODO: add support for configuring access list for the pipe */ + dst->pipe = CreateNamedPipe(NAMED_PIPE_PREFIX, + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_MESSAGE | + PIPE_READMODE_MESSAGE | + PIPE_WAIT, + 10, REPLY_BUFSIZE, REQUEST_BUFSIZE, + 1000, NULL); + if (dst->pipe == INVALID_HANDLE_VALUE) { + wpa_printf(MSG_ERROR, "CTRL: CreateNamedPipe failed: %d", + (int) GetLastError()); + goto fail; + } + + if (ConnectNamedPipe(dst->pipe, &dst->overlap)) { + wpa_printf(MSG_ERROR, "CTRL: ConnectNamedPipe failed: %d", + (int) GetLastError()); + CloseHandle(dst->pipe); + os_free(dst); + return -1; + } + + err = GetLastError(); + switch (err) { + case ERROR_IO_PENDING: + wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: connection in " + "progress"); + break; + case ERROR_PIPE_CONNECTED: + wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: already " + "connected"); + if (SetEvent(dst->overlap.hEvent)) + break; + /* fall through */ + default: + wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe error: %d", + (int) err); + CloseHandle(dst->pipe); + os_free(dst); + return -1; + } + + dst->next = priv->ctrl_dst; + if (dst->next) + dst->next->prev = dst; + priv->ctrl_dst = dst; + + return 0; + +fail: + global_close_pipe(dst); + return -1; +} + + +static void global_close_pipe(struct wpa_global_dst *dst) +{ + wpa_printf(MSG_DEBUG, "CTRL: close pipe %p", dst); + + if (dst->overlap.hEvent) { + eloop_unregister_event(dst->overlap.hEvent, + sizeof(dst->overlap.hEvent)); + CloseHandle(dst->overlap.hEvent); + } + + if (dst->pipe != INVALID_HANDLE_VALUE) { + /* + * Could use FlushFileBuffers() here to guarantee that all data + * gets delivered to the client, but that can block, so let's + * not do this for now. + * FlushFileBuffers(dst->pipe); + */ + CloseHandle(dst->pipe); + } + + if (dst->prev) + dst->prev->next = dst->next; + else + dst->priv->ctrl_dst = dst->next; + if (dst->next) + dst->next->prev = dst->prev; + + os_free(dst->rsp_buf); + os_free(dst); +} + + +static VOID WINAPI global_iface_write_completed(DWORD err, DWORD bytes, + LPOVERLAPPED overlap) +{ + struct wpa_global_dst *dst = (struct wpa_global_dst *) overlap; + wpa_printf(MSG_DEBUG, "CTRL: Overlapped write completed: dst=%p " + "err=%d bytes=%d", dst, (int) err, (int) bytes); + if (err) { + global_close_pipe(dst); + return; + } + + os_free(dst->rsp_buf); + dst->rsp_buf = NULL; + + if (!ReadFileEx(dst->pipe, dst->req_buf, sizeof(dst->req_buf), + &dst->overlap, global_iface_read_completed)) { + wpa_printf(MSG_DEBUG, "CTRL: ReadFileEx failed: %d", + (int) GetLastError()); + global_close_pipe(dst); + /* FIX: if this was the pipe waiting for new global + * connections, at this point there are no open global pipes.. + * Should try to open a new pipe.. */ + return; + } + wpa_printf(MSG_DEBUG, "CTRL: Overlapped read started for %p", dst); +} + + +static void wpa_supplicant_global_iface_rx(struct wpa_global_dst *dst, + size_t len) +{ + struct wpa_global *global = dst->priv->global; + char *reply = NULL, *send_buf; + size_t reply_len = 0, send_len; + char *buf = dst->req_buf; + + dst->used = 1; + if (len >= REQUEST_BUFSIZE) + len = REQUEST_BUFSIZE - 1; + buf[len] = '\0'; + + reply = wpa_supplicant_global_ctrl_iface_process(global, buf, + &reply_len); + if (reply) { + send_buf = reply; + send_len = reply_len; + } else if (reply_len) { + send_buf = "FAIL\n"; + send_len = 5; + } else { + os_free(dst->rsp_buf); + dst->rsp_buf = NULL; + return; + } + + os_free(dst->rsp_buf); + dst->rsp_buf = os_malloc(send_len); + if (dst->rsp_buf == NULL) { + global_close_pipe(dst); + os_free(reply); + return; + } + os_memcpy(dst->rsp_buf, send_buf, send_len); + os_free(reply); + + if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap, + global_iface_write_completed)) { + wpa_printf(MSG_DEBUG, "CTRL: WriteFileEx failed: %d", + (int) GetLastError()); + global_close_pipe(dst); + } else { + wpa_printf(MSG_DEBUG, "CTRL: Overlapped write started for %p", + dst); + } +} + + +static VOID WINAPI global_iface_read_completed(DWORD err, DWORD bytes, + LPOVERLAPPED overlap) +{ + struct wpa_global_dst *dst = (struct wpa_global_dst *) overlap; + wpa_printf(MSG_DEBUG, "CTRL: Overlapped read completed: dst=%p err=%d " + "bytes=%d", dst, (int) err, (int) bytes); + if (err == 0 && bytes > 0) + wpa_supplicant_global_iface_rx(dst, bytes); +} + + +static void wpa_supplicant_global_iface_receive(void *eloop_data, + void *user_ctx) +{ + struct wpa_global_dst *dst = eloop_data; + struct ctrl_iface_global_priv *priv = dst->priv; + DWORD bytes; + + wpa_printf(MSG_DEBUG, "CTRL: wpa_supplicant_global_iface_receive"); + ResetEvent(dst->overlap.hEvent); + + if (!GetOverlappedResult(dst->pipe, &dst->overlap, &bytes, FALSE)) { + wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult failed: %d", + (int) GetLastError()); + return; + } + wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult: New client " + "connected"); + + /* Open a new named pipe for the next client. */ + if (global_open_pipe(priv) < 0) { + wpa_printf(MSG_DEBUG, "CTRL: global_open_pipe failed"); + return; + } + + /* Use write completion function to start reading a command */ + global_iface_write_completed(0, 0, &dst->overlap); + + global_flush_broken_pipes(priv); +} + + +struct ctrl_iface_global_priv * +wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) +{ + struct ctrl_iface_global_priv *priv; + + priv = os_zalloc(sizeof(*priv)); + if (priv == NULL) + return NULL; + priv->global = global; + + if (global_open_pipe(priv) < 0) { + os_free(priv); + return NULL; + } + + return priv; +} + + +void +wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) +{ + while (priv->ctrl_dst) + global_close_pipe(priv->ctrl_dst); + os_free(priv); +} diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c new file mode 100644 index 000000000000..18e40405a737 --- /dev/null +++ b/wpa_supplicant/ctrl_iface_udp.c @@ -0,0 +1,561 @@ +/* + * WPA Supplicant / UDP socket -based control interface + * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "eloop.h" +#include "config.h" +#include "eapol_supp/eapol_supp_sm.h" +#include "wpa_supplicant_i.h" +#include "ctrl_iface.h" +#include "wpa_ctrl.h" + + +#define COOKIE_LEN 8 + +/* Per-interface ctrl_iface */ + +/** + * struct wpa_ctrl_dst - Internal data structure of control interface monitors + * + * This structure is used to store information about registered control + * interface monitors into struct wpa_supplicant. This data is private to + * ctrl_iface_udp.c and should not be touched directly from other files. + */ +struct wpa_ctrl_dst { + struct wpa_ctrl_dst *next; + struct sockaddr_in addr; + socklen_t addrlen; + int debug_level; + int errors; +}; + + +struct ctrl_iface_priv { + struct wpa_supplicant *wpa_s; + int sock; + struct wpa_ctrl_dst *ctrl_dst; + u8 cookie[COOKIE_LEN]; +}; + + +static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, + int level, const char *buf, + size_t len); + + +static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv, + struct sockaddr_in *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_in)); + dst->addrlen = fromlen; + dst->debug_level = MSG_INFO; + dst->next = priv->ctrl_dst; + priv->ctrl_dst = dst; + wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d", + inet_ntoa(from->sin_addr), ntohs(from->sin_port)); + return 0; +} + + +static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv, + struct sockaddr_in *from, + socklen_t fromlen) +{ + struct wpa_ctrl_dst *dst, *prev = NULL; + + dst = priv->ctrl_dst; + while (dst) { + if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr && + from->sin_port == dst->addr.sin_port) { + if (prev == NULL) + priv->ctrl_dst = dst->next; + else + prev->next = dst->next; + os_free(dst); + wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached " + "%s:%d", inet_ntoa(from->sin_addr), + ntohs(from->sin_port)); + return 0; + } + prev = dst; + dst = dst->next; + } + return -1; +} + + +static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv, + struct sockaddr_in *from, + socklen_t fromlen, + char *level) +{ + struct wpa_ctrl_dst *dst; + + wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); + + dst = priv->ctrl_dst; + while (dst) { + if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr && + from->sin_port == dst->addr.sin_port) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor " + "level %s:%d", inet_ntoa(from->sin_addr), + ntohs(from->sin_port)); + dst->debug_level = atoi(level); + return 0; + } + dst = dst->next; + } + + return -1; +} + + +static char * +wpa_supplicant_ctrl_iface_get_cookie(struct ctrl_iface_priv *priv, + size_t *reply_len) +{ + char *reply; + reply = os_malloc(7 + 2 * COOKIE_LEN + 1); + if (reply == NULL) { + *reply_len = 1; + return NULL; + } + + os_memcpy(reply, "COOKIE=", 7); + wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1, + priv->cookie, COOKIE_LEN); + + *reply_len = 7 + 2 * COOKIE_LEN; + return reply; +} + + +static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, + void *sock_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + struct ctrl_iface_priv *priv = sock_ctx; + char buf[256], *pos; + int res; + struct sockaddr_in from; + socklen_t fromlen = sizeof(from); + char *reply = NULL; + size_t reply_len = 0; + int new_attached = 0; + u8 cookie[COOKIE_LEN]; + + res = recvfrom(sock, buf, sizeof(buf) - 1, 0, + (struct sockaddr *) &from, &fromlen); + if (res < 0) { + perror("recvfrom(ctrl_iface)"); + return; + } + if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) { + /* + * The OS networking stack is expected to drop this kind of + * frames since the socket is bound to only localhost address. + * Just in case, drop the frame if it is coming from any other + * address. + */ + wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected " + "source %s", inet_ntoa(from.sin_addr)); + return; + } + buf[res] = '\0'; + + if (os_strcmp(buf, "GET_COOKIE") == 0) { + reply = wpa_supplicant_ctrl_iface_get_cookie(priv, &reply_len); + goto done; + } + + /* + * Require that the client includes a prefix with the 'cookie' value + * fetched with GET_COOKIE command. This is used to verify that the + * client has access to a bidirectional link over UDP in order to + * avoid attacks using forged localhost IP address even if the OS does + * not block such frames from remote destinations. + */ + if (os_strncmp(buf, "COOKIE=", 7) != 0) { + wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - " + "drop request"); + return; + } + + if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) { + wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the " + "request - drop request"); + return; + } + + if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) { + wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - " + "drop request"); + return; + } + + pos = buf + 7 + 2 * COOKIE_LEN; + while (*pos == ' ') + pos++; + + if (os_strcmp(pos, "ATTACH") == 0) { + if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen)) + reply_len = 1; + else { + new_attached = 1; + reply_len = 2; + } + } else if (os_strcmp(pos, "DETACH") == 0) { + if (wpa_supplicant_ctrl_iface_detach(priv, &from, fromlen)) + reply_len = 1; + else + reply_len = 2; + } else if (os_strncmp(pos, "LEVEL ", 6) == 0) { + if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen, + pos + 6)) + reply_len = 1; + else + reply_len = 2; + } else { + reply = wpa_supplicant_ctrl_iface_process(wpa_s, pos, + &reply_len); + } + + done: + if (reply) { + sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, + fromlen); + os_free(reply); + } else if (reply_len == 1) { + sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, + fromlen); + } else if (reply_len == 2) { + sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from, + fromlen); + } + + if (new_attached) + eapol_sm_notify_ctrl_attached(wpa_s->eapol); +} + + +static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, + const char *txt, size_t len) +{ + struct wpa_supplicant *wpa_s = ctx; + if (wpa_s == NULL || wpa_s->ctrl_iface == NULL) + return; + wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len); +} + + +struct ctrl_iface_priv * +wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) +{ + struct ctrl_iface_priv *priv; + struct sockaddr_in addr; + + priv = os_zalloc(sizeof(*priv)); + if (priv == NULL) + return NULL; + priv->wpa_s = wpa_s; + priv->sock = -1; + os_get_random(priv->cookie, COOKIE_LEN); + + if (wpa_s->conf->ctrl_interface == NULL) + return priv; + + priv->sock = socket(PF_INET, SOCK_DGRAM, 0); + if (priv->sock < 0) { + perror("socket(PF_INET)"); + goto fail; + } + + os_memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl((127 << 24) | 1); + addr.sin_port = htons(WPA_CTRL_IFACE_PORT); + if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + perror("bind(AF_INET)"); + goto fail; + } + + eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive, + wpa_s, priv); + wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); + + return priv; + +fail: + if (priv->sock >= 0) + close(priv->sock); + os_free(priv); + return NULL; +} + + +void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) +{ + struct wpa_ctrl_dst *dst, *prev; + + if (priv->sock > -1) { + eloop_unregister_read_sock(priv->sock); + if (priv->ctrl_dst) { + /* + * Wait a second before closing the control socket if + * there are any attached monitors in order to allow + * them to receive any pending messages. + */ + wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached " + "monitors to receive messages"); + os_sleep(1, 0); + } + close(priv->sock); + priv->sock = -1; + } + + dst = priv->ctrl_dst; + while (dst) { + prev = dst; + dst = dst->next; + os_free(prev); + } + os_free(priv); +} + + +static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, + int level, const char *buf, + size_t len) +{ + struct wpa_ctrl_dst *dst, *next; + char levelstr[10]; + int idx; + char *sbuf; + int llen; + + dst = priv->ctrl_dst; + if (priv->sock < 0 || dst == NULL) + return; + + os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); + + llen = os_strlen(levelstr); + sbuf = os_malloc(llen + len); + if (sbuf == NULL) + return; + + os_memcpy(sbuf, levelstr, llen); + os_memcpy(sbuf + llen, buf, len); + + idx = 0; + while (dst) { + next = dst->next; + if (level >= dst->debug_level) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %s:%d", + inet_ntoa(dst->addr.sin_addr), + ntohs(dst->addr.sin_port)); + if (sendto(priv->sock, sbuf, llen + len, 0, + (struct sockaddr *) &dst->addr, + sizeof(dst->addr)) < 0) { + perror("sendto(CTRL_IFACE monitor)"); + dst->errors++; + if (dst->errors > 10) { + wpa_supplicant_ctrl_iface_detach( + priv, &dst->addr, + dst->addrlen); + } + } else + dst->errors = 0; + } + idx++; + dst = next; + } + os_free(sbuf); +} + + +void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) +{ + wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor", + priv->wpa_s->ifname); + eloop_wait_for_read_sock(priv->sock); +} + + +/* Global ctrl_iface */ + +struct ctrl_iface_global_priv { + int sock; + u8 cookie[COOKIE_LEN]; +}; + + +static char * +wpa_supplicant_global_get_cookie(struct ctrl_iface_global_priv *priv, + size_t *reply_len) +{ + char *reply; + reply = os_malloc(7 + 2 * COOKIE_LEN + 1); + if (reply == NULL) { + *reply_len = 1; + return NULL; + } + + os_memcpy(reply, "COOKIE=", 7); + wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1, + priv->cookie, COOKIE_LEN); + + *reply_len = 7 + 2 * COOKIE_LEN; + return reply; +} + + +static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx, + void *sock_ctx) +{ + struct wpa_global *global = eloop_ctx; + struct ctrl_iface_global_priv *priv = sock_ctx; + char buf[256], *pos; + int res; + struct sockaddr_in from; + socklen_t fromlen = sizeof(from); + char *reply; + size_t reply_len; + u8 cookie[COOKIE_LEN]; + + res = recvfrom(sock, buf, sizeof(buf) - 1, 0, + (struct sockaddr *) &from, &fromlen); + if (res < 0) { + perror("recvfrom(ctrl_iface)"); + return; + } + if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) { + /* + * The OS networking stack is expected to drop this kind of + * frames since the socket is bound to only localhost address. + * Just in case, drop the frame if it is coming from any other + * address. + */ + wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected " + "source %s", inet_ntoa(from.sin_addr)); + return; + } + buf[res] = '\0'; + + if (os_strcmp(buf, "GET_COOKIE") == 0) { + reply = wpa_supplicant_global_get_cookie(priv, &reply_len); + goto done; + } + + if (os_strncmp(buf, "COOKIE=", 7) != 0) { + wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - " + "drop request"); + return; + } + + if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) { + wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the " + "request - drop request"); + return; + } + + if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) { + wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - " + "drop request"); + return; + } + + pos = buf + 7 + 2 * COOKIE_LEN; + while (*pos == ' ') + pos++; + + reply = wpa_supplicant_global_ctrl_iface_process(global, pos, + &reply_len); + + done: + if (reply) { + sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, + fromlen); + os_free(reply); + } else if (reply_len) { + sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, + fromlen); + } +} + + +struct ctrl_iface_global_priv * +wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) +{ + struct ctrl_iface_global_priv *priv; + struct sockaddr_in addr; + + priv = os_zalloc(sizeof(*priv)); + if (priv == NULL) + return NULL; + priv->sock = -1; + os_get_random(priv->cookie, COOKIE_LEN); + + if (global->params.ctrl_interface == NULL) + return priv; + + wpa_printf(MSG_DEBUG, "Global control interface '%s'", + global->params.ctrl_interface); + + priv->sock = socket(PF_INET, SOCK_DGRAM, 0); + if (priv->sock < 0) { + perror("socket(PF_INET)"); + goto fail; + } + + os_memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl((127 << 24) | 1); + addr.sin_port = htons(WPA_GLOBAL_CTRL_IFACE_PORT); + if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + perror("bind(AF_INET)"); + goto fail; + } + + eloop_register_read_sock(priv->sock, + wpa_supplicant_global_ctrl_iface_receive, + global, priv); + + return priv; + +fail: + if (priv->sock >= 0) + close(priv->sock); + os_free(priv); + return NULL; +} + + +void +wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) +{ + if (priv->sock >= 0) { + eloop_unregister_read_sock(priv->sock); + close(priv->sock); + } + os_free(priv); +} diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c new file mode 100644 index 000000000000..bf6328e75e5a --- /dev/null +++ b/wpa_supplicant/ctrl_iface_unix.c @@ -0,0 +1,699 @@ +/* + * WPA Supplicant / UNIX domain socket -based control interface + * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" +#include <sys/un.h> +#include <sys/stat.h> +#include <grp.h> + +#include "common.h" +#include "eloop.h" +#include "config.h" +#include "eapol_supp/eapol_supp_sm.h" +#include "wpa_supplicant_i.h" +#include "ctrl_iface.h" + +/* Per-interface ctrl_iface */ + +/** + * struct wpa_ctrl_dst - Internal data structure of control interface monitors + * + * This structure is used to store information about registered control + * interface monitors into struct wpa_supplicant. This data is private to + * ctrl_iface_unix.c and should not be touched directly from other files. + */ +struct wpa_ctrl_dst { + struct wpa_ctrl_dst *next; + struct sockaddr_un addr; + socklen_t addrlen; + int debug_level; + int errors; +}; + + +struct ctrl_iface_priv { + struct wpa_supplicant *wpa_s; + int sock; + struct wpa_ctrl_dst *ctrl_dst; +}; + + +static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, + int level, const char *buf, + size_t len); + + +static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv, + 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 = priv->ctrl_dst; + priv->ctrl_dst = dst; + wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached", + (u8 *) from->sun_path, fromlen - sizeof(from->sun_family)); + return 0; +} + + +static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv, + struct sockaddr_un *from, + socklen_t fromlen) +{ + struct wpa_ctrl_dst *dst, *prev = NULL; + + dst = priv->ctrl_dst; + while (dst) { + if (fromlen == dst->addrlen && + os_memcmp(from->sun_path, dst->addr.sun_path, + fromlen - sizeof(from->sun_family)) == 0) { + if (prev == NULL) + priv->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 - sizeof(from->sun_family)); + return 0; + } + prev = dst; + dst = dst->next; + } + return -1; +} + + +static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv, + struct sockaddr_un *from, + socklen_t fromlen, + char *level) +{ + struct wpa_ctrl_dst *dst; + + wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); + + dst = priv->ctrl_dst; + while (dst) { + if (fromlen == dst->addrlen && + os_memcmp(from->sun_path, dst->addr.sun_path, + fromlen - sizeof(from->sun_family)) == 0) { + wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor " + "level", (u8 *) from->sun_path, + fromlen - sizeof(from->sun_family)); + dst->debug_level = atoi(level); + return 0; + } + dst = dst->next; + } + + return -1; +} + + +static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, + void *sock_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + struct ctrl_iface_priv *priv = sock_ctx; + char buf[256]; + int res; + struct sockaddr_un from; + socklen_t fromlen = sizeof(from); + char *reply = NULL; + size_t reply_len = 0; + int new_attached = 0; + + res = recvfrom(sock, buf, sizeof(buf) - 1, 0, + (struct sockaddr *) &from, &fromlen); + if (res < 0) { + perror("recvfrom(ctrl_iface)"); + return; + } + buf[res] = '\0'; + + if (os_strcmp(buf, "ATTACH") == 0) { + if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen)) + reply_len = 1; + else { + new_attached = 1; + reply_len = 2; + } + } else if (os_strcmp(buf, "DETACH") == 0) { + if (wpa_supplicant_ctrl_iface_detach(priv, &from, fromlen)) + reply_len = 1; + else + reply_len = 2; + } else if (os_strncmp(buf, "LEVEL ", 6) == 0) { + if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen, + buf + 6)) + reply_len = 1; + else + reply_len = 2; + } else { + reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf, + &reply_len); + } + + if (reply) { + sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, + fromlen); + os_free(reply); + } else if (reply_len == 1) { + sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, + fromlen); + } else if (reply_len == 2) { + sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from, + fromlen); + } + + if (new_attached) + eapol_sm_notify_ctrl_attached(wpa_s->eapol); +} + + +static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s) +{ + char *buf; + size_t len; + char *pbuf, *dir = NULL, *gid_str = NULL; + int res; + + if (wpa_s->conf->ctrl_interface == NULL) + return NULL; + + pbuf = os_strdup(wpa_s->conf->ctrl_interface); + if (pbuf == NULL) + return NULL; + if (os_strncmp(pbuf, "DIR=", 4) == 0) { + dir = pbuf + 4; + gid_str = os_strstr(dir, " GROUP="); + if (gid_str) { + *gid_str = '\0'; + gid_str += 7; + } + } else + dir = pbuf; + + len = os_strlen(dir) + os_strlen(wpa_s->ifname) + 2; + buf = os_malloc(len); + if (buf == NULL) { + os_free(pbuf); + return NULL; + } + + res = os_snprintf(buf, len, "%s/%s", dir, wpa_s->ifname); + if (res < 0 || (size_t) res >= len) { + os_free(pbuf); + os_free(buf); + return NULL; + } +#ifdef __CYGWIN__ + { + /* Windows/WinPcap uses interface names that are not suitable + * as a file name - convert invalid chars to underscores */ + char *pos = buf; + while (*pos) { + if (*pos == '\\') + *pos = '_'; + pos++; + } + } +#endif /* __CYGWIN__ */ + os_free(pbuf); + return buf; +} + + +static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, + const char *txt, size_t len) +{ + struct wpa_supplicant *wpa_s = ctx; + if (wpa_s == NULL || wpa_s->ctrl_iface == NULL) + return; + wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len); +} + + +struct ctrl_iface_priv * +wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) +{ + struct ctrl_iface_priv *priv; + struct sockaddr_un addr; + char *fname = NULL; + gid_t gid = 0; + int gid_set = 0; + char *buf, *dir = NULL, *gid_str = NULL; + struct group *grp; + char *endp; + + priv = os_zalloc(sizeof(*priv)); + if (priv == NULL) + return NULL; + priv->wpa_s = wpa_s; + priv->sock = -1; + + if (wpa_s->conf->ctrl_interface == NULL) + return priv; + + buf = os_strdup(wpa_s->conf->ctrl_interface); + if (buf == NULL) + goto fail; + if (os_strncmp(buf, "DIR=", 4) == 0) { + dir = buf + 4; + gid_str = os_strstr(dir, " GROUP="); + if (gid_str) { + *gid_str = '\0'; + gid_str += 7; + } + } else { + dir = buf; + gid_str = wpa_s->conf->ctrl_interface_group; + } + + if (mkdir(dir, 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 (gid_str) { + grp = getgrnam(gid_str); + if (grp) { + gid = grp->gr_gid; + gid_set = 1; + wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d" + " (from group name '%s')", + (int) gid, gid_str); + } else { + /* Group name not found - try to parse this as gid */ + gid = strtol(gid_str, &endp, 10); + if (*gid_str == '\0' || *endp != '\0') { + wpa_printf(MSG_ERROR, "CTRL: Invalid group " + "'%s'", gid_str); + goto fail; + } + gid_set = 1; + wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d", + (int) gid); + } + } + + if (gid_set && chown(dir, -1, gid) < 0) { + perror("chown[ctrl_interface]"); + goto fail; + } + + if (os_strlen(dir) + 1 + os_strlen(wpa_s->ifname) >= + sizeof(addr.sun_path)) { + wpa_printf(MSG_ERROR, "ctrl_iface path limit exceeded"); + goto fail; + } + + priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0); + if (priv->sock < 0) { + perror("socket(PF_UNIX)"); + goto fail; + } + + os_memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + fname = wpa_supplicant_ctrl_iface_path(wpa_s); + if (fname == NULL) + goto fail; + os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path)); + if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s", + strerror(errno)); + if (connect(priv->sock, (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(priv->sock, (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 (gid_set && chown(fname, -1, 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); + + eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive, + wpa_s, priv); + wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); + + os_free(buf); + return priv; + +fail: + if (priv->sock >= 0) + close(priv->sock); + os_free(priv); + if (fname) { + unlink(fname); + os_free(fname); + } + os_free(buf); + return NULL; +} + + +void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) +{ + struct wpa_ctrl_dst *dst, *prev; + + if (priv->sock > -1) { + char *fname; + char *buf, *dir = NULL, *gid_str = NULL; + eloop_unregister_read_sock(priv->sock); + if (priv->ctrl_dst) { + /* + * Wait a second before closing the control socket if + * there are any attached monitors in order to allow + * them to receive any pending messages. + */ + wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached " + "monitors to receive messages"); + os_sleep(1, 0); + } + close(priv->sock); + priv->sock = -1; + fname = wpa_supplicant_ctrl_iface_path(priv->wpa_s); + if (fname) { + unlink(fname); + os_free(fname); + } + + buf = os_strdup(priv->wpa_s->conf->ctrl_interface); + if (buf == NULL) + goto free_dst; + if (os_strncmp(buf, "DIR=", 4) == 0) { + dir = buf + 4; + gid_str = os_strstr(dir, " GROUP="); + if (gid_str) { + *gid_str = '\0'; + gid_str += 7; + } + } else + dir = buf; + + if (rmdir(dir) < 0) { + if (errno == ENOTEMPTY) { + wpa_printf(MSG_DEBUG, "Control interface " + "directory not empty - leaving it " + "behind"); + } else { + perror("rmdir[ctrl_interface]"); + } + } + os_free(buf); + } + +free_dst: + dst = priv->ctrl_dst; + while (dst) { + prev = dst; + dst = dst->next; + os_free(prev); + } + os_free(priv); +} + + +/** + * wpa_supplicant_ctrl_iface_send - Send a control interface packet to monitors + * @priv: Pointer to private data from wpa_supplicant_ctrl_iface_init() + * @level: Priority level of the message + * @buf: Message data + * @len: Message length + * + * Send a packet to all monitor programs attached to the control interface. + */ +static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, + int level, const char *buf, + size_t len) +{ + struct wpa_ctrl_dst *dst, *next; + char levelstr[10]; + int idx, res; + struct msghdr msg; + struct iovec io[2]; + + dst = priv->ctrl_dst; + if (priv->sock < 0 || dst == NULL) + return; + + res = os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); + if (res < 0 || (size_t) res >= sizeof(levelstr)) + return; + 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 - + sizeof(dst->addr.sun_family)); + msg.msg_name = (void *) &dst->addr; + msg.msg_namelen = dst->addrlen; + if (sendmsg(priv->sock, &msg, 0) < 0) { + perror("sendmsg(CTRL_IFACE monitor)"); + dst->errors++; + if (dst->errors > 10) { + wpa_supplicant_ctrl_iface_detach( + priv, &dst->addr, + dst->addrlen); + } + } else + dst->errors = 0; + } + idx++; + dst = next; + } +} + + +void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) +{ + char buf[256]; + int res; + struct sockaddr_un from; + socklen_t fromlen = sizeof(from); + + for (;;) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor to " + "attach", priv->wpa_s->ifname); + eloop_wait_for_read_sock(priv->sock); + + res = recvfrom(priv->sock, buf, sizeof(buf) - 1, 0, + (struct sockaddr *) &from, &fromlen); + if (res < 0) { + perror("recvfrom(ctrl_iface)"); + continue; + } + buf[res] = '\0'; + + if (os_strcmp(buf, "ATTACH") == 0) { + /* handle ATTACH signal of first monitor interface */ + if (!wpa_supplicant_ctrl_iface_attach(priv, &from, + fromlen)) { + sendto(priv->sock, "OK\n", 3, 0, + (struct sockaddr *) &from, fromlen); + /* OK to continue */ + return; + } else { + sendto(priv->sock, "FAIL\n", 5, 0, + (struct sockaddr *) &from, fromlen); + } + } else { + /* return FAIL for all other signals */ + sendto(priv->sock, "FAIL\n", 5, 0, + (struct sockaddr *) &from, fromlen); + } + } +} + + +/* Global ctrl_iface */ + +struct ctrl_iface_global_priv { + struct wpa_global *global; + int sock; +}; + + +static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx, + void *sock_ctx) +{ + struct wpa_global *global = eloop_ctx; + char buf[256]; + int res; + struct sockaddr_un from; + socklen_t fromlen = sizeof(from); + char *reply; + size_t 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'; + + reply = wpa_supplicant_global_ctrl_iface_process(global, buf, + &reply_len); + + if (reply) { + sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, + fromlen); + os_free(reply); + } else if (reply_len) { + sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, + fromlen); + } +} + + +struct ctrl_iface_global_priv * +wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) +{ + struct ctrl_iface_global_priv *priv; + struct sockaddr_un addr; + + priv = os_zalloc(sizeof(*priv)); + if (priv == NULL) + return NULL; + priv->global = global; + priv->sock = -1; + + if (global->params.ctrl_interface == NULL) + return priv; + + wpa_printf(MSG_DEBUG, "Global control interface '%s'", + global->params.ctrl_interface); + + priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0); + if (priv->sock < 0) { + perror("socket(PF_UNIX)"); + goto fail; + } + + os_memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + os_strlcpy(addr.sun_path, global->params.ctrl_interface, + sizeof(addr.sun_path)); + if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + perror("bind(PF_UNIX)"); + if (connect(priv->sock, (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(global->params.ctrl_interface) < 0) { + perror("unlink[ctrl_iface]"); + wpa_printf(MSG_ERROR, "Could not unlink " + "existing ctrl_iface socket '%s'", + global->params.ctrl_interface); + goto fail; + } + if (bind(priv->sock, (struct sockaddr *) &addr, + sizeof(addr)) < 0) { + perror("bind(PF_UNIX)"); + goto fail; + } + wpa_printf(MSG_DEBUG, "Successfully replaced leftover " + "ctrl_iface socket '%s'", + global->params.ctrl_interface); + } 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", + global->params.ctrl_interface); + goto fail; + } + } + + eloop_register_read_sock(priv->sock, + wpa_supplicant_global_ctrl_iface_receive, + global, NULL); + + return priv; + +fail: + if (priv->sock >= 0) + close(priv->sock); + os_free(priv); + return NULL; +} + + +void +wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) +{ + if (priv->sock >= 0) { + eloop_unregister_read_sock(priv->sock); + close(priv->sock); + } + if (priv->global->params.ctrl_interface) + unlink(priv->global->params.ctrl_interface); + os_free(priv); +} diff --git a/wpa_supplicant/dbus-wpa_supplicant.conf b/wpa_supplicant/dbus-wpa_supplicant.conf new file mode 100644 index 000000000000..51a29e3a89c0 --- /dev/null +++ b/wpa_supplicant/dbus-wpa_supplicant.conf @@ -0,0 +1,16 @@ +<!DOCTYPE busconfig PUBLIC + "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" + "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> +<busconfig> + <policy user="root"> + <allow own="fi.epitest.hostap.WPASupplicant"/> + + <allow send_destination="fi.epitest.hostap.WPASupplicant"/> + <allow send_interface="fi.epitest.hostap.WPASupplicant"/> + </policy> + <policy context="default"> + <deny own="fi.epitest.hostap.WPASupplicant"/> + <deny send_destination="fi.epitest.hostap.WPASupplicant"/> + <deny send_interface="fi.epitest.hostap.WPASupplicant"/> + </policy> +</busconfig> diff --git a/wpa_supplicant/dbus-wpa_supplicant.service b/wpa_supplicant/dbus-wpa_supplicant.service new file mode 100644 index 000000000000..a9ce1ecda63f --- /dev/null +++ b/wpa_supplicant/dbus-wpa_supplicant.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=fi.epitest.hostap.WPASupplicant +Exec=/sbin/wpa_supplicant -u +User=root diff --git a/wpa_supplicant/dbus_dict_helpers.c b/wpa_supplicant/dbus_dict_helpers.c new file mode 100644 index 000000000000..f93fc9d70013 --- /dev/null +++ b/wpa_supplicant/dbus_dict_helpers.c @@ -0,0 +1,976 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, 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 <dbus/dbus.h> + +#include "common.h" +#include "dbus_dict_helpers.h" + + +/** + * Start a dict in a dbus message. Should be paired with a call to + * wpa_dbus_dict_close_write(). + * + * @param iter A valid dbus message iterator + * @param iter_dict (out) A dict iterator to pass to further dict functions + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_open_write(DBusMessageIter *iter, + DBusMessageIter *iter_dict) +{ + dbus_bool_t result; + + if (!iter || !iter_dict) + return FALSE; + + result = dbus_message_iter_open_container( + iter, + DBUS_TYPE_ARRAY, + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_VARIANT_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, + iter_dict); + return result; +} + + +/** + * End a dict element in a dbus message. Should be paired with + * a call to wpa_dbus_dict_open_write(). + * + * @param iter valid dbus message iterator, same as passed to + * wpa_dbus_dict_open_write() + * @param iter_dict a dbus dict iterator returned from + * wpa_dbus_dict_open_write() + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_close_write(DBusMessageIter *iter, + DBusMessageIter *iter_dict) +{ + if (!iter || !iter_dict) + return FALSE; + + return dbus_message_iter_close_container(iter, iter_dict); +} + + +static const char * _wpa_get_type_as_string_from_type(const int type) +{ + switch(type) { + case DBUS_TYPE_BYTE: + return DBUS_TYPE_BYTE_AS_STRING; + case DBUS_TYPE_BOOLEAN: + return DBUS_TYPE_BOOLEAN_AS_STRING; + case DBUS_TYPE_INT16: + return DBUS_TYPE_INT16_AS_STRING; + case DBUS_TYPE_UINT16: + return DBUS_TYPE_UINT16_AS_STRING; + case DBUS_TYPE_INT32: + return DBUS_TYPE_INT32_AS_STRING; + case DBUS_TYPE_UINT32: + return DBUS_TYPE_UINT32_AS_STRING; + case DBUS_TYPE_INT64: + return DBUS_TYPE_INT64_AS_STRING; + case DBUS_TYPE_UINT64: + return DBUS_TYPE_UINT64_AS_STRING; + case DBUS_TYPE_DOUBLE: + return DBUS_TYPE_DOUBLE_AS_STRING; + case DBUS_TYPE_STRING: + return DBUS_TYPE_STRING_AS_STRING; + case DBUS_TYPE_OBJECT_PATH: + return DBUS_TYPE_OBJECT_PATH_AS_STRING; + case DBUS_TYPE_ARRAY: + return DBUS_TYPE_ARRAY_AS_STRING; + default: + return NULL; + } +} + + +static dbus_bool_t _wpa_dbus_add_dict_entry_start( + DBusMessageIter *iter_dict, DBusMessageIter *iter_dict_entry, + const char *key, const int value_type) +{ + if (!dbus_message_iter_open_container(iter_dict, + DBUS_TYPE_DICT_ENTRY, NULL, + iter_dict_entry)) + return FALSE; + + if (!dbus_message_iter_append_basic(iter_dict_entry, DBUS_TYPE_STRING, + &key)) + return FALSE; + + return TRUE; +} + + +static dbus_bool_t _wpa_dbus_add_dict_entry_end( + DBusMessageIter *iter_dict, DBusMessageIter *iter_dict_entry, + DBusMessageIter *iter_dict_val) +{ + if (!dbus_message_iter_close_container(iter_dict_entry, iter_dict_val)) + return FALSE; + if (!dbus_message_iter_close_container(iter_dict, iter_dict_entry)) + return FALSE; + + return TRUE; +} + + +static dbus_bool_t _wpa_dbus_add_dict_entry_basic(DBusMessageIter *iter_dict, + const char *key, + const int value_type, + const void *value) +{ + DBusMessageIter iter_dict_entry, iter_dict_val; + const char *type_as_string = NULL; + + type_as_string = _wpa_get_type_as_string_from_type(value_type); + if (!type_as_string) + return FALSE; + + if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry, + key, value_type)) + return FALSE; + + if (!dbus_message_iter_open_container(&iter_dict_entry, + DBUS_TYPE_VARIANT, + type_as_string, &iter_dict_val)) + return FALSE; + + if (!dbus_message_iter_append_basic(&iter_dict_val, value_type, value)) + return FALSE; + + if (!_wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry, + &iter_dict_val)) + return FALSE; + + return TRUE; +} + + +static dbus_bool_t _wpa_dbus_add_dict_entry_byte_array( + DBusMessageIter *iter_dict, const char *key, + const char *value, const dbus_uint32_t value_len) +{ + DBusMessageIter iter_dict_entry, iter_dict_val, iter_array; + dbus_uint32_t i; + + if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry, + key, DBUS_TYPE_ARRAY)) + return FALSE; + + if (!dbus_message_iter_open_container(&iter_dict_entry, + DBUS_TYPE_VARIANT, + DBUS_TYPE_ARRAY_AS_STRING + DBUS_TYPE_BYTE_AS_STRING, + &iter_dict_val)) + return FALSE; + + if (!dbus_message_iter_open_container(&iter_dict_val, DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, + &iter_array)) + return FALSE; + + for (i = 0; i < value_len; i++) { + if (!dbus_message_iter_append_basic(&iter_array, + DBUS_TYPE_BYTE, + &(value[i]))) + return FALSE; + } + + if (!dbus_message_iter_close_container(&iter_dict_val, &iter_array)) + return FALSE; + + if (!_wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry, + &iter_dict_val)) + return FALSE; + + return TRUE; +} + + +/** + * Add a string entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param key The key of the dict item + * @param value The string value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_string(DBusMessageIter *iter_dict, + const char *key, const char *value) +{ + if (!key || !value) + return FALSE; + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_STRING, + &value); +} + + +/** + * Add a byte entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param key The key of the dict item + * @param value The byte value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_byte(DBusMessageIter *iter_dict, + const char *key, const char value) +{ + if (!key) + return FALSE; + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_BYTE, + &value); +} + + +/** + * Add a boolean entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param key The key of the dict item + * @param value The boolean value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_bool(DBusMessageIter *iter_dict, + const char *key, const dbus_bool_t value) +{ + if (!key) + return FALSE; + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, + DBUS_TYPE_BOOLEAN, &value); +} + + +/** + * Add a 16-bit signed integer entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param key The key of the dict item + * @param value The 16-bit signed integer value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_int16(DBusMessageIter *iter_dict, + const char *key, + const dbus_int16_t value) +{ + if (!key) + return FALSE; + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT16, + &value); +} + + +/** + * Add a 16-bit unsigned integer entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param key The key of the dict item + * @param value The 16-bit unsigned integer value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_uint16(DBusMessageIter *iter_dict, + const char *key, + const dbus_uint16_t value) +{ + if (!key) + return FALSE; + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT16, + &value); +} + + +/** + * Add a 32-bit signed integer to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param key The key of the dict item + * @param value The 32-bit signed integer value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_int32(DBusMessageIter *iter_dict, + const char *key, + const dbus_int32_t value) +{ + if (!key) + return FALSE; + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT32, + &value); +} + + +/** + * Add a 32-bit unsigned integer entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param key The key of the dict item + * @param value The 32-bit unsigned integer value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_uint32(DBusMessageIter *iter_dict, + const char *key, + const dbus_uint32_t value) +{ + if (!key) + return FALSE; + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT32, + &value); +} + + +/** + * Add a 64-bit integer entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param key The key of the dict item + * @param value The 64-bit integer value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_int64(DBusMessageIter *iter_dict, + const char *key, + const dbus_int64_t value) +{ + if (!key) + return FALSE; + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT64, + &value); +} + + +/** + * Add a 64-bit unsigned integer entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param key The key of the dict item + * @param value The 64-bit unsigned integer value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict, + const char *key, + const dbus_uint64_t value) +{ + if (!key) + return FALSE; + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT64, + &value); +} + + +/** + * Add a double-precision floating point entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param key The key of the dict item + * @param value The double-precision floating point value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_double(DBusMessageIter *iter_dict, + const char * key, + const double value) +{ + if (!key) + return FALSE; + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_DOUBLE, + &value); +} + + +/** + * Add a DBus object path entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param key The key of the dict item + * @param value The DBus object path value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_object_path(DBusMessageIter *iter_dict, + const char *key, + const char *value) +{ + if (!key || !value) + return FALSE; + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, + DBUS_TYPE_OBJECT_PATH, &value); +} + + +/** + * Add a byte array entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param key The key of the dict item + * @param value The byte array + * @param value_len The length of the byte array, in bytes + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict, + const char *key, + const char *value, + const dbus_uint32_t value_len) +{ + if (!key) + return FALSE; + if (!value && (value_len != 0)) + return FALSE; + return _wpa_dbus_add_dict_entry_byte_array(iter_dict, key, value, + value_len); +} + + +/** + * Begin a string array entry in the dict + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param key The key of the dict item + * @param iter_dict_entry A private DBusMessageIter provided by the caller to + * be passed to wpa_dbus_dict_end_string_array() + * @param iter_dict_val A private DBusMessageIter provided by the caller to + * be passed to wpa_dbus_dict_end_string_array() + * @param iter_array On return, the DBusMessageIter to be passed to + * wpa_dbus_dict_string_array_add_element() + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict, + const char *key, + DBusMessageIter *iter_dict_entry, + DBusMessageIter *iter_dict_val, + DBusMessageIter *iter_array) +{ + if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array) + return FALSE; + + if (!_wpa_dbus_add_dict_entry_start(iter_dict, iter_dict_entry, + key, DBUS_TYPE_ARRAY)) + return FALSE; + + if (!dbus_message_iter_open_container(iter_dict_entry, + DBUS_TYPE_VARIANT, + DBUS_TYPE_ARRAY_AS_STRING + DBUS_TYPE_STRING_AS_STRING, + iter_dict_val)) + return FALSE; + + if (!dbus_message_iter_open_container(iter_dict_val, DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, + iter_array)) + return FALSE; + + return TRUE; +} + + +/** + * Add a single string element to a string array dict entry + * + * @param iter_array A valid DBusMessageIter returned from + * wpa_dbus_dict_begin_string_array()'s + * iter_array parameter + * @param elem The string element to be added to the dict entry's string array + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array, + const char *elem) +{ + if (!iter_array || !elem) + return FALSE; + + return dbus_message_iter_append_basic(iter_array, DBUS_TYPE_STRING, + &elem); +} + + +/** + * End a string array dict entry + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param iter_dict_entry A private DBusMessageIter returned from + * wpa_dbus_dict_end_string_array() + * @param iter_dict_val A private DBusMessageIter returned from + * wpa_dbus_dict_end_string_array() + * @param iter_array A DBusMessageIter returned from + * wpa_dbus_dict_end_string_array() + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_end_string_array(DBusMessageIter *iter_dict, + DBusMessageIter *iter_dict_entry, + DBusMessageIter *iter_dict_val, + DBusMessageIter *iter_array) +{ + if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array) + return FALSE; + + if (!dbus_message_iter_close_container(iter_dict_val, iter_array)) + return FALSE; + + if (!_wpa_dbus_add_dict_entry_end(iter_dict, iter_dict_entry, + iter_dict_val)) + return FALSE; + + return TRUE; +} + + +/** + * Convenience function to add an entire string array to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param key The key of the dict item + * @param items The array of strings + * @param num_items The number of strings in the array + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict, + const char *key, + const char **items, + const dbus_uint32_t num_items) +{ + DBusMessageIter iter_dict_entry, iter_dict_val, iter_array; + dbus_uint32_t i; + + if (!key) + return FALSE; + if (!items && (num_items != 0)) + return FALSE; + + if (!wpa_dbus_dict_begin_string_array(iter_dict, key, + &iter_dict_entry, &iter_dict_val, + &iter_array)) + return FALSE; + + for (i = 0; i < num_items; i++) { + if (!wpa_dbus_dict_string_array_add_element(&iter_array, + items[i])) + return FALSE; + } + + if (!wpa_dbus_dict_end_string_array(iter_dict, &iter_dict_entry, + &iter_dict_val, &iter_array)) + return FALSE; + + return TRUE; +} + + +/*****************************************************/ +/* Stuff for reading dicts */ +/*****************************************************/ + +/** + * Start reading from a dbus dict. + * + * @param iter A valid DBusMessageIter pointing to the start of the dict + * @param iter_dict (out) A DBusMessageIter to be passed to + * wpa_dbus_dict_read_next_entry() + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter, + DBusMessageIter *iter_dict) +{ + if (!iter || !iter_dict) + return FALSE; + + if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY || + dbus_message_iter_get_element_type(iter) != DBUS_TYPE_DICT_ENTRY) + return FALSE; + + dbus_message_iter_recurse(iter, iter_dict); + return TRUE; +} + + +#define BYTE_ARRAY_CHUNK_SIZE 34 +#define BYTE_ARRAY_ITEM_SIZE (sizeof(char)) + +static dbus_bool_t _wpa_dbus_dict_entry_get_byte_array( + DBusMessageIter *iter, int array_type, + struct wpa_dbus_dict_entry *entry) +{ + dbus_uint32_t count = 0; + dbus_bool_t success = FALSE; + char *buffer; + + entry->bytearray_value = NULL; + entry->array_type = DBUS_TYPE_BYTE; + + buffer = os_zalloc(BYTE_ARRAY_ITEM_SIZE * BYTE_ARRAY_CHUNK_SIZE); + if (!buffer) { + perror("_wpa_dbus_dict_entry_get_byte_array[dbus]: out of " + "memory"); + goto done; + } + + entry->bytearray_value = buffer; + entry->array_len = 0; + while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_BYTE) { + char byte; + + if ((count % BYTE_ARRAY_CHUNK_SIZE) == 0 && count != 0) { + buffer = realloc(buffer, BYTE_ARRAY_ITEM_SIZE * + (count + BYTE_ARRAY_CHUNK_SIZE)); + if (buffer == NULL) { + perror("_wpa_dbus_dict_entry_get_byte_array[" + "dbus] out of memory trying to " + "retrieve the string array"); + goto done; + } + } + entry->bytearray_value = buffer; + + dbus_message_iter_get_basic(iter, &byte); + entry->bytearray_value[count] = byte; + entry->array_len = ++count; + dbus_message_iter_next(iter); + } + + /* Zero-length arrays are valid. */ + if (entry->array_len == 0) { + free(entry->bytearray_value); + entry->bytearray_value = NULL; + } + + success = TRUE; + +done: + return success; +} + + +#define STR_ARRAY_CHUNK_SIZE 8 +#define STR_ARRAY_ITEM_SIZE (sizeof(char *)) + +static dbus_bool_t _wpa_dbus_dict_entry_get_string_array( + DBusMessageIter *iter, int array_type, + struct wpa_dbus_dict_entry *entry) +{ + dbus_uint32_t count = 0; + dbus_bool_t success = FALSE; + char **buffer; + + entry->strarray_value = NULL; + entry->array_type = DBUS_TYPE_STRING; + + buffer = os_zalloc(STR_ARRAY_ITEM_SIZE * STR_ARRAY_CHUNK_SIZE); + if (buffer == NULL) { + perror("_wpa_dbus_dict_entry_get_string_array[dbus] out of " + "memory trying to retrieve a string array"); + goto done; + } + + entry->strarray_value = buffer; + entry->array_len = 0; + while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) { + const char *value; + char *str; + + if ((count % STR_ARRAY_CHUNK_SIZE) == 0 && count != 0) { + buffer = realloc(buffer, STR_ARRAY_ITEM_SIZE * + (count + STR_ARRAY_CHUNK_SIZE)); + if (buffer == NULL) { + perror("_wpa_dbus_dict_entry_get_string_array[" + "dbus] out of memory trying to " + "retrieve the string array"); + goto done; + } + } + entry->strarray_value = buffer; + + dbus_message_iter_get_basic(iter, &value); + str = strdup(value); + if (str == NULL) { + perror("_wpa_dbus_dict_entry_get_string_array[dbus] " + "out of memory trying to duplicate the string " + "array"); + goto done; + } + entry->strarray_value[count] = str; + entry->array_len = ++count; + dbus_message_iter_next(iter); + } + + /* Zero-length arrays are valid. */ + if (entry->array_len == 0) { + free(entry->strarray_value); + entry->strarray_value = NULL; + } + + success = TRUE; + +done: + return success; +} + + +static dbus_bool_t _wpa_dbus_dict_entry_get_array( + DBusMessageIter *iter_dict_val, struct wpa_dbus_dict_entry *entry) +{ + int array_type = dbus_message_iter_get_element_type(iter_dict_val); + dbus_bool_t success = FALSE; + DBusMessageIter iter_array; + + if (!entry) + return FALSE; + + dbus_message_iter_recurse(iter_dict_val, &iter_array); + + switch (array_type) { + case DBUS_TYPE_BYTE: + success = _wpa_dbus_dict_entry_get_byte_array(&iter_array, + array_type, + entry); + break; + case DBUS_TYPE_STRING: + success = _wpa_dbus_dict_entry_get_string_array(&iter_array, + array_type, + entry); + break; + default: + break; + } + + return success; +} + + +static dbus_bool_t _wpa_dbus_dict_fill_value_from_variant( + struct wpa_dbus_dict_entry *entry, DBusMessageIter *iter_dict_val) +{ + dbus_bool_t success = TRUE; + + switch (entry->type) { + case DBUS_TYPE_STRING: { + const char *v; + dbus_message_iter_get_basic(iter_dict_val, &v); + entry->str_value = strdup(v); + break; + } + case DBUS_TYPE_BOOLEAN: { + dbus_bool_t v; + dbus_message_iter_get_basic(iter_dict_val, &v); + entry->bool_value = v; + break; + } + case DBUS_TYPE_BYTE: { + char v; + dbus_message_iter_get_basic(iter_dict_val, &v); + entry->byte_value = v; + break; + } + case DBUS_TYPE_INT16: { + dbus_int16_t v; + dbus_message_iter_get_basic(iter_dict_val, &v); + entry->int16_value = v; + break; + } + case DBUS_TYPE_UINT16: { + dbus_uint16_t v; + dbus_message_iter_get_basic(iter_dict_val, &v); + entry->uint16_value = v; + break; + } + case DBUS_TYPE_INT32: { + dbus_int32_t v; + dbus_message_iter_get_basic(iter_dict_val, &v); + entry->int32_value = v; + break; + } + case DBUS_TYPE_UINT32: { + dbus_uint32_t v; + dbus_message_iter_get_basic(iter_dict_val, &v); + entry->uint32_value = v; + break; + } + case DBUS_TYPE_INT64: { + dbus_int64_t v; + dbus_message_iter_get_basic(iter_dict_val, &v); + entry->int64_value = v; + break; + } + case DBUS_TYPE_UINT64: { + dbus_uint64_t v; + dbus_message_iter_get_basic(iter_dict_val, &v); + entry->uint64_value = v; + break; + } + case DBUS_TYPE_DOUBLE: { + double v; + dbus_message_iter_get_basic(iter_dict_val, &v); + entry->double_value = v; + break; + } + case DBUS_TYPE_OBJECT_PATH: { + char *v; + dbus_message_iter_get_basic(iter_dict_val, &v); + entry->str_value = strdup(v); + break; + } + case DBUS_TYPE_ARRAY: { + success = _wpa_dbus_dict_entry_get_array(iter_dict_val, entry); + break; + } + default: + success = FALSE; + break; + } + + return success; +} + + +/** + * Read the current key/value entry from the dict. Entries are dynamically + * allocated when needed and must be freed after use with the + * wpa_dbus_dict_entry_clear() function. + * + * The returned entry object will be filled with the type and value of the next + * entry in the dict, or the type will be DBUS_TYPE_INVALID if an error + * occurred. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_read() + * @param entry A valid dict entry object into which the dict key and value + * will be placed + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_get_entry(DBusMessageIter *iter_dict, + struct wpa_dbus_dict_entry * entry) +{ + DBusMessageIter iter_dict_entry, iter_dict_val; + int type; + const char *key; + + if (!iter_dict || !entry) + goto error; + + if (dbus_message_iter_get_arg_type(iter_dict) != DBUS_TYPE_DICT_ENTRY) + goto error; + + dbus_message_iter_recurse(iter_dict, &iter_dict_entry); + dbus_message_iter_get_basic(&iter_dict_entry, &key); + entry->key = key; + + if (!dbus_message_iter_next(&iter_dict_entry)) + goto error; + type = dbus_message_iter_get_arg_type(&iter_dict_entry); + if (type != DBUS_TYPE_VARIANT) + goto error; + + dbus_message_iter_recurse(&iter_dict_entry, &iter_dict_val); + entry->type = dbus_message_iter_get_arg_type(&iter_dict_val); + if (!_wpa_dbus_dict_fill_value_from_variant(entry, &iter_dict_val)) + goto error; + + dbus_message_iter_next(iter_dict); + return TRUE; + +error: + if (entry) { + wpa_dbus_dict_entry_clear(entry); + entry->type = DBUS_TYPE_INVALID; + entry->array_type = DBUS_TYPE_INVALID; + } + + return FALSE; +} + + +/** + * Return whether or not there are additional dictionary entries. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_read() + * @return TRUE if more dict entries exists, FALSE if no more dict entries + * exist + */ +dbus_bool_t wpa_dbus_dict_has_dict_entry(DBusMessageIter *iter_dict) +{ + if (!iter_dict) { + perror("wpa_dbus_dict_has_dict_entry[dbus]: out of memory"); + return FALSE; + } + return dbus_message_iter_get_arg_type(iter_dict) == + DBUS_TYPE_DICT_ENTRY; +} + + +/** + * Free any memory used by the entry object. + * + * @param entry The entry object + */ +void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry) +{ + unsigned int i; + + if (!entry) + return; + switch (entry->type) { + case DBUS_TYPE_OBJECT_PATH: + case DBUS_TYPE_STRING: + free(entry->str_value); + break; + case DBUS_TYPE_ARRAY: + switch (entry->array_type) { + case DBUS_TYPE_BYTE: + free(entry->bytearray_value); + break; + case DBUS_TYPE_STRING: + for (i = 0; i < entry->array_len; i++) + free(entry->strarray_value[i]); + free(entry->strarray_value); + break; + } + break; + } + + memset(entry, 0, sizeof(struct wpa_dbus_dict_entry)); +} diff --git a/wpa_supplicant/dbus_dict_helpers.h b/wpa_supplicant/dbus_dict_helpers.h new file mode 100644 index 000000000000..f873efcbcb13 --- /dev/null +++ b/wpa_supplicant/dbus_dict_helpers.h @@ -0,0 +1,135 @@ +/* + * WPA Supplicant / dbus-based control interface + * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, 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 DBUS_DICT_HELPERS_H +#define DBUS_DICT_HELPERS_H + +/* + * Adding a dict to a DBusMessage + */ + +dbus_bool_t wpa_dbus_dict_open_write(DBusMessageIter *iter, + DBusMessageIter *iter_dict); + +dbus_bool_t wpa_dbus_dict_close_write(DBusMessageIter *iter, + DBusMessageIter *iter_dict); + +dbus_bool_t wpa_dbus_dict_append_string(DBusMessageIter *iter_dict, + const char *key, const char *value); + +dbus_bool_t wpa_dbus_dict_append_byte(DBusMessageIter *iter_dict, + const char *key, const char value); + +dbus_bool_t wpa_dbus_dict_append_bool(DBusMessageIter *iter_dict, + const char *key, + const dbus_bool_t value); + +dbus_bool_t wpa_dbus_dict_append_int16(DBusMessageIter *iter_dict, + const char *key, + const dbus_int16_t value); + +dbus_bool_t wpa_dbus_dict_append_uint16(DBusMessageIter *iter_dict, + const char *key, + const dbus_uint16_t value); + +dbus_bool_t wpa_dbus_dict_append_int32(DBusMessageIter *iter_dict, + const char *key, + const dbus_int32_t value); + +dbus_bool_t wpa_dbus_dict_append_uint32(DBusMessageIter *iter_dict, + const char *key, + const dbus_uint32_t value); + +dbus_bool_t wpa_dbus_dict_append_int64(DBusMessageIter *iter_dict, + const char *key, + const dbus_int64_t value); + +dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict, + const char *key, + const dbus_uint64_t value); + +dbus_bool_t wpa_dbus_dict_append_double(DBusMessageIter *iter_dict, + const char *key, + const double value); + +dbus_bool_t wpa_dbus_dict_append_object_path(DBusMessageIter *iter_dict, + const char *key, + const char *value); + +dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict, + const char *key, + const char *value, + const dbus_uint32_t value_len); + +/* Manual construction and addition of string array elements */ +dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict, + const char *key, + DBusMessageIter *iter_dict_entry, + DBusMessageIter *iter_dict_val, + DBusMessageIter *iter_array); + +dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array, + const char *elem); + +dbus_bool_t wpa_dbus_dict_end_string_array(DBusMessageIter *iter_dict, + DBusMessageIter *iter_dict_entry, + DBusMessageIter *iter_dict_val, + DBusMessageIter *iter_array); + +/* Convenience function to add a whole string list */ +dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict, + const char *key, + const char **items, + const dbus_uint32_t num_items); + +/* + * Reading a dict from a DBusMessage + */ + +struct wpa_dbus_dict_entry { + int type; /** the dbus type of the dict entry's value */ + int array_type; /** the dbus type of the array elements if the dict + entry value contains an array */ + const char *key; /** key of the dict entry */ + + /** Possible values of the property */ + union { + char *str_value; + char byte_value; + dbus_bool_t bool_value; + dbus_int16_t int16_value; + dbus_uint16_t uint16_value; + dbus_int32_t int32_value; + dbus_uint32_t uint32_value; + dbus_int64_t int64_value; + dbus_uint64_t uint64_value; + double double_value; + char *bytearray_value; + char **strarray_value; + }; + dbus_uint32_t array_len; /** length of the array if the dict entry's + value contains an array */ +}; + +dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter, + DBusMessageIter *iter_dict); + +dbus_bool_t wpa_dbus_dict_get_entry(DBusMessageIter *iter_dict, + struct wpa_dbus_dict_entry *entry); + +dbus_bool_t wpa_dbus_dict_has_dict_entry(DBusMessageIter *iter_dict); + +void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry); + +#endif /* DBUS_DICT_HELPERS_H */ diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig new file mode 100644 index 000000000000..dd9460d7b8e7 --- /dev/null +++ b/wpa_supplicant/defconfig @@ -0,0 +1,382 @@ +# Example wpa_supplicant 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 cases, these lines should use += in order not +# to override previous values of the variables. + + +# Uncomment following two lines and fix the paths if you have installed OpenSSL +# or GnuTLS in non-default location +#CFLAGS += -I/usr/local/openssl/include +#LIBS += -L/usr/local/openssl/lib + +# Some Red Hat versions seem to include kerberos header files from OpenSSL, but +# the kerberos files are not in the default include path. Following line can be +# used to fix build issues on such systems (krb5.h not found). +#CFLAGS += -I/usr/include/kerberos + +# Example configuration for various cross-compilation platforms + +#### sveasoft (e.g., for Linksys WRT54G) ###################################### +#CC=mipsel-uclibc-gcc +#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc +#CFLAGS += -Os +#CPPFLAGS += -I../src/include -I../../src/router/openssl/include +#LIBS += -L/opt/brcm/hndtools-mipsel-uclibc-0.9.19/lib -lssl +############################################################################### + +#### openwrt (e.g., for Linksys WRT54G) ####################################### +#CC=mipsel-uclibc-gcc +#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc +#CFLAGS += -Os +#CPPFLAGS=-I../src/include -I../openssl-0.9.7d/include \ +# -I../WRT54GS/release/src/include +#LIBS = -lssl +############################################################################### + + +# Driver interface for Host AP driver +CONFIG_DRIVER_HOSTAP=y + +# Driver interface for Agere driver +#CONFIG_DRIVER_HERMES=y +# Change include directories to match with the local setup +#CFLAGS += -I../../hcf -I../../include -I../../include/hcf +#CFLAGS += -I../../include/wireless + +# Driver interface for madwifi driver +#CONFIG_DRIVER_MADWIFI=y +# Set include directory to the madwifi source tree +#CFLAGS += -I../../madwifi + +# Driver interface for Prism54 driver +# (Note: Prism54 is not yet supported, i.e., this will not work as-is and is +# for developers only) +#CONFIG_DRIVER_PRISM54=y + +# Driver interface for ndiswrapper +#CONFIG_DRIVER_NDISWRAPPER=y + +# Driver interface for Atmel driver +CONFIG_DRIVER_ATMEL=y + +# Driver interface for old Broadcom driver +# Please note that the newer Broadcom driver ("hybrid Linux driver") supports +# Linux wireless extensions and does not need (or even work) with the old +# driver wrapper. Use CONFIG_DRIVER_WEXT=y with that driver. +#CONFIG_DRIVER_BROADCOM=y +# Example path for wlioctl.h; change to match your configuration +#CFLAGS += -I/opt/WRT54GS/release/src/include + +# Driver interface for Intel ipw2100/2200 driver +#CONFIG_DRIVER_IPW=y + +# Driver interface for Ralink driver +#CONFIG_DRIVER_RALINK=y + +# Driver interface for generic Linux wireless extensions +CONFIG_DRIVER_WEXT=y + +# Driver interface for Linux drivers using the nl80211 kernel interface +#CONFIG_DRIVER_NL80211=y + +# 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 Windows NDIS +#CONFIG_DRIVER_NDIS=y +#CFLAGS += -I/usr/include/w32api/ddk +#LIBS += -L/usr/local/lib +# For native build using mingw +#CONFIG_NATIVE_WINDOWS=y +# Additional directories for cross-compilation on Linux host for mingw target +#CFLAGS += -I/opt/mingw/mingw32/include/ddk +#LIBS += -L/opt/mingw/mingw32/lib +#CC=mingw32-gcc +# By default, driver_ndis uses WinPcap for low-level operations. This can be +# replaced with the following option which replaces WinPcap calls with NDISUIO. +# However, this requires that WZC is disabled (net stop wzcsvc) before starting +# wpa_supplicant. +# CONFIG_USE_NDISUIO=y + +# Driver interface for development testing +#CONFIG_DRIVER_TEST=y + +# Driver interface for wired Ethernet drivers +CONFIG_DRIVER_WIRED=y + +# Driver interface for the Broadcom RoboSwitch family +#CONFIG_DRIVER_ROBOSWITCH=y + +# Enable IEEE 802.1X Supplicant (automatically included if any EAP method is +# included) +CONFIG_IEEE8021X_EAPOL=y + +# EAP-MD5 +CONFIG_EAP_MD5=y + +# EAP-MSCHAPv2 +CONFIG_EAP_MSCHAPV2=y + +# EAP-TLS +CONFIG_EAP_TLS=y + +# EAL-PEAP +CONFIG_EAP_PEAP=y + +# EAP-TTLS +CONFIG_EAP_TTLS=y + +# EAP-FAST +# 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.8d-tls-extensions.patch) +# to add the needed functions. +#CONFIG_EAP_FAST=y + +# EAP-GTC +CONFIG_EAP_GTC=y + +# EAP-OTP +CONFIG_EAP_OTP=y + +# EAP-SIM (enable CONFIG_PCSC, if EAP-SIM is used) +#CONFIG_EAP_SIM=y + +# EAP-PSK (experimental; this is _not_ needed for WPA-PSK) +#CONFIG_EAP_PSK=y + +# EAP-PAX +#CONFIG_EAP_PAX=y + +# LEAP +CONFIG_EAP_LEAP=y + +# EAP-AKA (enable CONFIG_PCSC, if EAP-AKA is used) +#CONFIG_EAP_AKA=y + +# EAP-AKA' (enable CONFIG_PCSC, if EAP-AKA' is used). +# This requires CONFIG_EAP_AKA to be enabled, too. +#CONFIG_EAP_AKA_PRIME=y + +# Enable USIM simulator (Milenage) for EAP-AKA +#CONFIG_USIM_SIMULATOR=y + +# EAP-SAKE +#CONFIG_EAP_SAKE=y + +# EAP-GPSK +#CONFIG_EAP_GPSK=y +# Include support for optional SHA256 cipher suite in EAP-GPSK +#CONFIG_EAP_GPSK_SHA256=y + +# EAP-TNC and related Trusted Network Connect support (experimental) +#CONFIG_EAP_TNC=y + +# Wi-Fi Protected Setup (WPS) +#CONFIG_WPS=y + +# EAP-IKEv2 +#CONFIG_EAP_IKEV2=y + +# PKCS#12 (PFX) support (used to read private key and certificate file from +# a file that usually has extension .p12 or .pfx) +CONFIG_PKCS12=y + +# Smartcard support (i.e., private key on a smartcard), e.g., with openssl +# engine. +CONFIG_SMARTCARD=y + +# PC/SC interface for smartcards (USIM, GSM SIM) +# Enable this if EAP-SIM or EAP-AKA is included +#CONFIG_PCSC=y + +# Development testing +#CONFIG_EAPOL_TEST=y + +# Select control interface backend for external programs, e.g, wpa_cli: +# unix = UNIX domain sockets (default for Linux/*BSD) +# udp = UDP sockets using localhost (127.0.0.1) +# named_pipe = Windows Named Pipe (default for Windows) +# y = use default (backwards compatibility) +# If this option is commented out, control interface is not included in the +# build. +CONFIG_CTRL_IFACE=y + +# Include support for GNU Readline and History Libraries in wpa_cli. +# When building a wpa_cli binary for distribution, please note that these +# libraries are licensed under GPL and as such, BSD license may not apply for +# the resulting binary. +#CONFIG_READLINE=y + +# Remove debugging code that is printing out debug message to stdout. +# This can be used to reduce the size of the wpa_supplicant considerably +# if debugging code is not needed. The size reduction can be around 35% +# (e.g., 90 kB). +#CONFIG_NO_STDOUT_DEBUG=y + +# Remove WPA support, e.g., for wired-only IEEE 802.1X supplicant, to save +# 35-50 kB in code size. +#CONFIG_NO_WPA=y + +# Remove WPA2 support. This allows WPA to be used, but removes WPA2 code to +# save about 1 kB in code size when building only WPA-Personal (no EAP support) +# or 6 kB if building for WPA-Enterprise. +#CONFIG_NO_WPA2=y + +# Remove IEEE 802.11i/WPA-Personal ASCII passphrase support +# This option can be used to reduce code size by removing support for +# converting ASCII passphrases into PSK. If this functionality is removed, the +# PSK can only be configured as the 64-octet hexstring (e.g., from +# wpa_passphrase). This saves about 0.5 kB in code size. +#CONFIG_NO_WPA_PASSPHRASE=y + +# Remove AES extra functions. This can be used to reduce code size by about +# 1.5 kB by removing extra AES modes that are not needed for commonly used +# client configurations (they are needed for some EAP types). +#CONFIG_NO_AES_EXTRAS=y + +# Disable scan result processing (ap_mode=1) to save code size by about 1 kB. +# This can be used if ap_scan=1 mode is never enabled. +#CONFIG_NO_SCAN_PROCESSING=y + +# Select configuration backend: +# file = text file (e.g., wpa_supplicant.conf; note: the configuration file +# path is given on command line, not here; this option is just used to +# select the backend that allows configuration files to be used) +# winreg = Windows registry (see win_example.reg for an example) +CONFIG_BACKEND=file + +# Remove configuration write functionality (i.e., to allow the configuration +# file to be updated based on runtime configuration changes). The runtime +# configuration can still be changed, the changes are just not going to be +# persistent over restarts. This option can be used to reduce code size by +# about 3.5 kB. +#CONFIG_NO_CONFIG_WRITE=y + +# Remove support for configuration blobs to reduce code size by about 1.5 kB. +#CONFIG_NO_CONFIG_BLOBS=y + +# Select program entry point implementation: +# main = UNIX/POSIX like main() function (default) +# main_winsvc = Windows service (read parameters from registry) +# main_none = Very basic example (development use only) +#CONFIG_MAIN=main + +# Select wrapper for operatins system and C library specific functions +# unix = UNIX/POSIX like systems (default) +# win32 = Windows systems +# none = Empty template +#CONFIG_OS=unix + +# Select event loop implementation +# eloop = select() loop (default) +# eloop_win = Windows events and WaitForMultipleObject() loop +# eloop_none = Empty template +#CONFIG_ELOOP=eloop + +# Select layer 2 packet implementation +# linux = Linux packet socket (default) +# pcap = libpcap/libdnet/WinPcap +# freebsd = FreeBSD libpcap +# winpcap = WinPcap with receive thread +# ndis = Windows NDISUIO (note: requires CONFIG_USE_NDISUIO=y) +# none = Empty template +#CONFIG_L2_PACKET=linux + +# 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 + +# Select TLS implementation +# openssl = OpenSSL (default) +# gnutls = GnuTLS (needed for TLS/IA, see also CONFIG_GNUTLS_EXTRA) +# internal = Internal TLSv1 implementation (experimental) +# none = Empty template +#CONFIG_TLS=openssl + +# Whether to enable TLS/IA support, which is required for EAP-TTLSv1. +# You need CONFIG_TLS=gnutls for this to have any effect. Please note that +# even though the core GnuTLS library is released under LGPL, this extra +# library uses GPL and as such, the terms of GPL apply to the combination +# of wpa_supplicant and GnuTLS if this option is enabled. BSD license may not +# apply for distribution of the resulting binary. +#CONFIG_GNUTLS_EXTRA=y + +# If CONFIG_TLS=internal is used, additional library and include paths are +# needed for LibTomMath. Alternatively, an integrated, minimal version of +# LibTomMath can be used. See beginning of libtommath.c for details on benefits +# and drawbacks of this option. +#CONFIG_INTERNAL_LIBTOMMATH=y +#ifndef CONFIG_INTERNAL_LIBTOMMATH +#LTM_PATH=/usr/src/libtommath-0.39 +#CFLAGS += -I$(LTM_PATH) +#LIBS += -L$(LTM_PATH) +#LIBS_p += -L$(LTM_PATH) +#endif +# At the cost of about 4 kB of additional binary size, the internal LibTomMath +# can be configured to include faster routines for exptmod, sqr, and div to +# speed up DH and RSA calculation considerably +#CONFIG_INTERNAL_LIBTOMMATH_FAST=y + +# Include NDIS event processing through WMI into wpa_supplicant/wpasvc. +# This is only for Windows builds and requires WMI-related header files and +# WbemUuid.Lib from Platform SDK even when building with MinGW. +#CONFIG_NDIS_EVENTS_INTEGRATED=y +#PLATFORMSDKLIB="/opt/Program Files/Microsoft Platform SDK/Lib" + +# Add support for DBus control interface +#CONFIG_CTRL_IFACE_DBUS=y + +# Add support for loading EAP methods dynamically as shared libraries. +# When this option is enabled, each EAP method can be either included +# statically (CONFIG_EAP_<method>=y) or dynamically (CONFIG_EAP_<method>=dyn). +# Dynamic EAP methods are build as shared objects (eap_*.so) and they need to +# be loaded in the beginning of the wpa_supplicant configuration file +# (see load_dynamic_eap parameter in the example file) before being used in +# the network blocks. +# +# Note that some shared parts of EAP methods are included in the main program +# and in order to be able to use dynamic EAP methods using these parts, the +# main program must have been build with the EAP method enabled (=y or =dyn). +# This means that EAP-TLS/PEAP/TTLS/FAST cannot be added as dynamic libraries +# unless at least one of them was included in the main build to force inclusion +# of the shared code. Similarly, at least one of EAP-SIM/AKA must be included +# in the main build to be able to load these methods dynamically. +# +# Please also note that using dynamic libraries will increase the total binary +# size. Thus, it may not be the best option for targets that have limited +# amount of memory/flash. +#CONFIG_DYNAMIC_EAP_METHODS=y + +# Include client MLME (management frame processing). +# This can be used to move MLME processing of Linux mac80211 stack into user +# space. Please note that this is currently only available with +# driver_nl80211.c and only with a modified version of Linux kernel and +# wpa_supplicant. +#CONFIG_CLIENT_MLME=y + +# IEEE Std 802.11r-2008 (Fast BSS Transition) +#CONFIG_IEEE80211R=y + +# Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt) +#CONFIG_DEBUG_FILE=y + +# Enable privilege separation (see README 'Privilege separation' for details) +#CONFIG_PRIVSEP=y + +# Enable mitigation against certain attacks against TKIP by delaying Michael +# MIC error reports by a random amount of time between 0 and 60 seconds +#CONFIG_DELAYED_MIC_ERROR_REPORT=y diff --git a/wpa_supplicant/doc/.gitignore b/wpa_supplicant/doc/.gitignore new file mode 100644 index 000000000000..59e4eb89ac2d --- /dev/null +++ b/wpa_supplicant/doc/.gitignore @@ -0,0 +1,4 @@ +html +latex +wpa_supplicant.eps +wpa_supplicant.png diff --git a/wpa_supplicant/doc/code_structure.doxygen b/wpa_supplicant/doc/code_structure.doxygen new file mode 100644 index 000000000000..6398ff344330 --- /dev/null +++ b/wpa_supplicant/doc/code_structure.doxygen @@ -0,0 +1,322 @@ +/** +\page code_structure Structure of the source code + +[ \ref wpa_supplicant_core "wpa_supplicant core functionality" | +\ref generic_helper_func "Generic helper functions" | +\ref crypto_func "Cryptographic functions" | +\ref tls_func "TLS library" | +\ref configuration "Configuration" | +\ref ctrl_iface "Control interface" | +\ref wpa_code "WPA supplicant" | +\ref eap_peer "EAP peer" | +\ref eapol_supp "EAPOL supplicant" | +\ref win_port "Windows port" | +\ref test_programs "Test programs" ] + +%wpa_supplicant implementation is divided into number of independent +modules. Core code includes functionality for controlling the network +selection, association, and configuration. Independent modules include +WPA code (key handshake, PMKSA caching, pre-authentication), EAPOL +state machine, and EAP state machine and methods. In addition, there +are number of separate files for generic helper functions. + +Both WPA and EAPOL/EAP state machines can be used separately in other +programs than %wpa_supplicant. As an example, the included test +programs eapol_test and preauth_test are using these modules. + +\ref driver_wrapper "Driver interface API" is defined in driver.h and +all hardware/driver dependent functionality is implemented in +driver_*.c. + + +\section wpa_supplicant_core wpa_supplicant core functionality + +wpa_supplicant.c + Program initialization, main control loop + +main.c + main() for UNIX-like operating systems and MinGW (Windows); this + uses command line arguments to configure wpa_supplicant + +events.c + Driver event processing; wpa_supplicant_event() and related functions + +wpa_supplicant_i.h + Internal definitions for %wpa_supplicant core; should not be + included into independent modules + + +\section generic_helper_func Generic helper functions + +%wpa_supplicant uses generic helper functions some of which are shared +with with hostapd. The following C files are currently used: + +eloop.c and eloop.h + Event loop (select() loop with registerable timeouts, socket read + callbacks, and signal callbacks) + +common.c and common.h + Common helper functions + +defs.h + Definitions shared by multiple files + +l2_packet.h, l2_packet_linux.c, and l2_packet_pcap.c + Layer 2 (link) access wrapper (includes native Linux implementation + and wrappers for libdnet/libpcap). A new l2_packet implementation + may need to be added when porting to new operating systems that are + not supported by libdnet/libpcap. Makefile can be used to select which + l2_packet implementation is included. l2_packet_linux.c uses Linux + packet sockets and l2_packet_pcap.c has a more portable version using + libpcap and libdnet. + +pcsc_funcs.c and pcsc_funcs.h + Wrapper for PC/SC lite SIM and smart card readers + +priv_netlink.h + Private version of netlink definitions from Linux kernel header files; + this could be replaced with C library header file once suitable + version becomes commonly available + +version.h + Version number definitions + +wireless_copy.h + Private version of Linux wireless extensions definitions from kernel + header files; this could be replaced with C library header file once + suitable version becomes commonly available + + +\section crypto_func Cryptographic functions + +md5.c and md5.h + MD5 (replaced with a crypto library if TLS support is included) + HMAC-MD5 (keyed checksum for message authenticity validation) + +rc4.c and rc4.h + RC4 (broadcast/default key encryption) + +sha1.c and sha1.h + SHA-1 (replaced with a crypto library if TLS support is included) + HMAC-SHA-1 (keyed checksum for message authenticity validation) + PRF-SHA-1 (pseudorandom (key/nonce generation) function) + PBKDF2-SHA-1 (ASCII passphrase to shared secret) + T-PRF (for EAP-FAST) + TLS-PRF (RFC 2246) + +sha256.c and sha256.h + SHA-256 (replaced with a crypto library if TLS support is included) + +aes_wrap.c, aes_wrap.h, aes.c + AES (replaced with a crypto library if TLS support is included), + AES Key Wrap Algorithm with 128-bit KEK, RFC3394 (broadcast/default + key encryption), + One-Key CBC MAC (OMAC1) hash with AES-128, + AES-128 CTR mode encryption, + AES-128 EAX mode encryption/decryption, + AES-128 CBC + +crypto.h + Definition of crypto library wrapper + +crypto_openssl.c + Wrapper functions for libcrypto (OpenSSL) + +crypto_internal.c + Wrapper functions for internal crypto implementation + +crypto_gnutls.c + Wrapper functions for libgcrypt (used by GnuTLS) + +ms_funcs.c and ms_funcs.h + Helper functions for MSCHAPV2 and LEAP + +tls.h + Definition of TLS library wrapper + +tls_none.c + Dummy implementation of TLS library wrapper for cases where TLS + functionality is not included. + +tls_openssl.c + TLS library wrapper for openssl + +tls_internal.c + TLS library for internal TLS implementation + +tls_gnutls.c + TLS library wrapper for GnuTLS + + +\section tls_func TLS library + +asn1.c and asn1.h + ASN.1 DER parsing + +bignum.c and bignum.h + Big number math + +rsa.c and rsa.h + RSA + +x509v3.c and x509v3.h + X.509v3 certificate parsing and processing + +tlsv1_client.c, tlsv1_client.h + TLSv1 client (RFC 2246) + +tlsv1_client_i.h + Internal structures for TLSv1 client + +tlsv1_client_read.c + TLSv1 client: read handshake messages + +tlsv1_client_write.c + TLSv1 client: write handshake messages + +tlsv1_common.c and tlsv1_common.h + Common TLSv1 routines and definitions + +tlsv1_cred.c and tlsv1_cred.h + TLSv1 credentials + +tlsv1_record.c and tlsv1_record.h + TLSv1 record protocol + + +\section configuration Configuration + +config_ssid.h + Definition of per network configuration items + +config.h + Definition of the %wpa_supplicant configuration + +config.c + Configuration parser and common functions + +config_file.c + Configuration backend for text files (e.g., wpa_supplicant.conf) + +config_winreg.c + Configuration backend for Windows registry + + +\section ctrl_iface Control interface + +%wpa_supplicant has a \ref ctrl_iface_page "control interface" +that can be used to get status +information and manage operations from external programs. An example +command line interface (wpa_cli) and GUI (wpa_gui) for this interface +are included in the %wpa_supplicant distribution. + +ctrl_iface.c and ctrl_iface.h + %wpa_supplicant-side of the control interface + +ctrl_iface_unix.c + UNIX domain sockets -based control interface backend + +ctrl_iface_udp.c + UDP sockets -based control interface backend + +ctrl_iface_named_pipe.c + Windows named pipes -based control interface backend + +wpa_ctrl.c and wpa_ctrl.h + Library functions for external programs to provide access to the + %wpa_supplicant control interface + +wpa_cli.c + Example program for using %wpa_supplicant control interface + + +\section wpa_code WPA supplicant + +wpa.c and wpa.h + WPA state machine and 4-Way/Group Key Handshake processing + +preauth.c and preauth.h + PMKSA caching and pre-authentication (RSN/WPA2) + +wpa_i.h + Internal definitions for WPA code; not to be included to other modules. + +\section eap_peer EAP peer + +\ref eap_module "EAP peer implementation" is a separate module that +can be used by other programs than just %wpa_supplicant. + +eap.c and eap.h + EAP state machine and method interface + +eap_defs.h + Common EAP definitions + +eap_i.h + Internal definitions for EAP state machine and EAP methods; not to be + included in other modules + +eap_sim_common.c and eap_sim_common.h + Common code for EAP-SIM and EAP-AKA + +eap_tls_common.c and eap_tls_common.h + Common code for EAP-PEAP, EAP-TTLS, and EAP-FAST + +eap_tlv.c and eap_tlv.h + EAP-TLV code for EAP-PEAP and EAP-FAST + +eap_ttls.c and eap_ttls.h + EAP-TTLS + +eap_pax.c, eap_pax_common.h, eap_pax_common.c + EAP-PAX + +eap_psk.c, eap_psk_common.h, eap_psk_common.c + EAP-PSK (note: this is not needed for WPA-PSK) + +eap_sake.c, eap_sake_common.h, eap_sake_common.c + EAP-SAKE + +eap_gpsk.c, eap_gpsk_common.h, eap_gpsk_common.c + EAP-GPSK + +eap_aka.c, eap_fast.c, eap_gtc.c, eap_leap.c, eap_md5.c, eap_mschapv2.c, +eap_otp.c, eap_peap.c, eap_sim.c, eap_tls.c + Other EAP method implementations + + +\section eapol_supp EAPOL supplicant + +eapol_supp_sm.c and eapol_supp_sm.h + EAPOL supplicant state machine and IEEE 802.1X processing + + +\section win_port Windows port + +ndis_events.c + Code for receiving NdisMIndicateStatus() events and delivering them to + %wpa_supplicant driver_ndis.c in more easier to use form + +win_if_list.c + External program for listing current network interface + + +\section test_programs Test programs + +radius_client.c and radius_client.h + RADIUS authentication client implementation for eapol_test + +radius.c and radius.h + RADIUS message processing for eapol_test + +eapol_test.c + Standalone EAP testing tool with integrated RADIUS authentication + client + +preauth_test.c + Standalone RSN pre-authentication tool + +wpa_passphrase.c + WPA ASCII passphrase to PSK conversion + +*/ diff --git a/wpa_supplicant/doc/ctrl_iface.doxygen b/wpa_supplicant/doc/ctrl_iface.doxygen new file mode 100644 index 000000000000..e908e0f97b01 --- /dev/null +++ b/wpa_supplicant/doc/ctrl_iface.doxygen @@ -0,0 +1,481 @@ +/** +\page ctrl_iface_page Control interface + +%wpa_supplicant implements a control interface that can be used by +external programs to control the operations of the %wpa_supplicant +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++. wpa_cli.c and +wpa_gui are example programs using this library. + +There are multiple mechanisms for inter-process communication. For +example, Linux version of %wpa_supplicant is using UNIX domain sockets +for the control interface and Windows version UDP sockets. 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 %wpa_supplicant 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(). + +%wpa_supplicant 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 +%wpa_supplicant. These can be executed using wpa_ctrl_request(). +Unsolicited event messages are sent by %wpa_supplicant 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 %wpa_supplicant is replying +to the control interface commands. The expected reply is \c PONG if the +connection is open and %wpa_supplicant is processing commands. + + +\subsection ctrl_iface_MIB MIB + +Request a list of MIB variables (dot1x, dot11). The output is a text +block with each line in \c variable=value format. For example: + +\verbatim +dot11RSNAOptionImplemented=TRUE +dot11RSNAPreauthenticationImplemented=TRUE +dot11RSNAEnabled=FALSE +dot11RSNAPreauthenticationEnabled=FALSE +dot11RSNAConfigVersion=1 +dot11RSNAConfigPairwiseKeysSupported=5 +dot11RSNAConfigGroupCipherSize=128 +dot11RSNAConfigPMKLifetime=43200 +dot11RSNAConfigPMKReauthThreshold=70 +dot11RSNAConfigNumberOfPTKSAReplayCounters=1 +dot11RSNAConfigSATimeout=60 +dot11RSNAAuthenticationSuiteSelected=00-50-f2-2 +dot11RSNAPairwiseCipherSelected=00-50-f2-4 +dot11RSNAGroupCipherSelected=00-50-f2-4 +dot11RSNAPMKIDUsed= +dot11RSNAAuthenticationSuiteRequested=00-50-f2-2 +dot11RSNAPairwiseCipherRequested=00-50-f2-4 +dot11RSNAGroupCipherRequested=00-50-f2-4 +dot11RSNAConfigNumberOfGTKSAReplayCounters=0 +dot11RSNA4WayHandshakeFailures=0 +dot1xSuppPaeState=5 +dot1xSuppHeldPeriod=60 +dot1xSuppAuthPeriod=30 +dot1xSuppStartPeriod=30 +dot1xSuppMaxStart=3 +dot1xSuppSuppControlledPortStatus=Authorized +dot1xSuppBackendPaeState=2 +dot1xSuppEapolFramesRx=0 +dot1xSuppEapolFramesTx=440 +dot1xSuppEapolStartFramesTx=2 +dot1xSuppEapolLogoffFramesTx=0 +dot1xSuppEapolRespFramesTx=0 +dot1xSuppEapolReqIdFramesRx=0 +dot1xSuppEapolReqFramesRx=0 +dot1xSuppInvalidEapolFramesRx=0 +dot1xSuppEapLengthErrorFramesRx=0 +dot1xSuppLastEapolFrameVersion=0 +dot1xSuppLastEapolFrameSource=00:00:00:00:00:00 +\endverbatim + + +\subsection ctrl_iface_STATUS STATUS + +Request current WPA/EAPOL/EAP status information. The output is a text +block with each line in \c variable=value format. For example: + +\verbatim +bssid=02:00:01:02:03:04 +ssid=test network +pairwise_cipher=CCMP +group_cipher=CCMP +key_mgmt=WPA-PSK +wpa_state=COMPLETED +ip_address=192.168.1.21 +Supplicant PAE state=AUTHENTICATED +suppPortStatus=Authorized +EAP state=SUCCESS +\endverbatim + + +\subsection ctrl_iface_STATUS-VERBOSE STATUS-VERBOSE + +Same as STATUS, but with more verbosity (i.e., more \c variable=value pairs). + +\verbatim +bssid=02:00:01:02:03:04 +ssid=test network +id=0 +pairwise_cipher=CCMP +group_cipher=CCMP +key_mgmt=WPA-PSK +wpa_state=COMPLETED +ip_address=192.168.1.21 +Supplicant PAE state=AUTHENTICATED +suppPortStatus=Authorized +heldPeriod=60 +authPeriod=30 +startPeriod=30 +maxStart=3 +portControl=Auto +Supplicant Backend state=IDLE +EAP state=SUCCESS +reqMethod=0 +methodState=NONE +decision=COND_SUCC +ClientTimeout=60 +\endverbatim + + +\subsection ctrl_iface_PMKSA PMKSA + +Show PMKSA cache + +\verbatim +Index / AA / PMKID / expiration (in seconds) / opportunistic +1 / 02:00:01:02:03:04 / 000102030405060708090a0b0c0d0e0f / 41362 / 0 +2 / 02:00:01:33:55:77 / 928389281928383b34afb34ba4212345 / 362 / 1 +\endverbatim + + +\subsection ctrl_iface_SET SET <variable> <value> + +Set variables: +- EAPOL::heldPeriod +- EAPOL::authPeriod +- EAPOL::startPeriod +- EAPOL::maxStart +- dot11RSNAConfigPMKLifetime +- dot11RSNAConfigPMKReauthThreshold +- dot11RSNAConfigSATimeout + +Example command: +\verbatim +SET EAPOL::heldPeriod 45 +\endverbatim + + +\subsection ctrl_iface_LOGON LOGON + +IEEE 802.1X EAPOL state machine logon. + + +\subsection ctrl_iface_LOGOFF LOGOFF + +IEEE 802.1X EAPOL state machine logoff. + + +\subsection ctrl_iface_REASSOCIATE REASSOCIATE + +Force reassociation. + + +\subsection ctrl_iface_RECONNECT RECONNECT + +Connect if disconnected (i.e., like \c REASSOCIATE, but only connect +if in disconnected state). + + +\subsection ctrl_iface_PREAUTH PREAUTH <BSSID> + +Start pre-authentication with the given BSSID. + + +\subsection ctrl_iface_ATTACH ATTACH + +Attach the connection as a monitor for unsolicited events. This can +be done with wpa_ctrl_attach(). + + +\subsection ctrl_iface_DETACH DETACH + +Detach the connection as a monitor for unsolicited events. This can +be done with wpa_ctrl_detach(). + + +\subsection ctrl_iface_LEVEL LEVEL <debug level> + +Change debug level. + + +\subsection ctrl_iface_RECONFIGURE RECONFIGURE + +Force %wpa_supplicant to re-read its configuration data. + + +\subsection ctrl_iface_TERMINATE TERMINATE + +Terminate %wpa_supplicant process. + + +\subsection ctrl_iface_BSSID BSSID <network id> <BSSID> + +Set preferred BSSID for a network. Network id can be received from the +\c LIST_NETWORKS command output. + + +\subsection ctrl_iface_LIST_NETWORKS LIST_NETWORKS + +List configured networks. + +\verbatim +network id / ssid / bssid / flags +0 example network any [CURRENT] +\endverbatim + +(note: fields are separated with tabs) + + +\subsection ctrl_iface_DISCONNECT DISCONNECT + +Disconnect and wait for \c REASSOCIATE or \c RECONNECT command before +connecting. + + +\subsection ctrl_iface_SCAN SCAN + +Request a new BSS scan. + + +\subsection ctrl_iface_SCAN_RESULTS SCAN_RESULTS + +Get the latest scan results. + +\verbatim +bssid / frequency / signal level / flags / ssid +00:09:5b:95:e0:4e 2412 208 [WPA-PSK-CCMP] jkm private +02:55:24:33:77:a3 2462 187 [WPA-PSK-TKIP] testing +00:09:5b:95:e0:4f 2412 209 jkm guest +\endverbatim + +(note: fields are separated with tabs) + + +\subsection ctrl_iface_BSS BSS + +Get detailed per-BSS scan results. \c BSS command can be used to +iterate through scan results one BSS at a time and to fetch all +information from the found BSSes. This provides access to the same +data that is available through \c SCAN_RESULTS but in a way that +avoids problems with large number of scan results not fitting in the +ctrl_iface messages. + +There are two options for selecting the BSS with the \c BSS command: +"BSS <idx>" requests information for the BSS identified by the index +(0 .. size-1) in the scan results table and "BSS <BSSID>" requests +information for the given BSS (based on BSSID in 00:01:02:03:04:05 +format). + +BSS information is presented in following format. Please note that new +fields may be added to this field=value data, so the ctrl_iface user +should be prepared to ignore values it does not understand. + +\verbatim +bssid=00:09:5b:95:e0:4e +freq=2412 +beacon_int=0 +capabilities=0x0011 +qual=51 +noise=161 +level=212 +tsf=0000000000000000 +ie=000b6a6b6d2070726976617465010180dd180050f20101000050f20401000050f20401000050f2020000 +ssid=jkm private +\endverbatim + + + +\subsection ctrl_iface_SELECT_NETWORK SELECT_NETWORK <network id> + +Select a network (disable others). Network id can be received from the +\c LIST_NETWORKS command output. + + +\subsection ctrl_iface_ENABLE_NETWORK ENABLE_NETWORK <network id> + +Enable a network. Network id can be received from the +\c LIST_NETWORKS command output. Special network id \c all can be +used to enable all network. + + +\subsection ctrl_iface_DISABLE_NETWORK DISABLE_NETWORK <network id> + +Disable a network. Network id can be received from the +\c LIST_NETWORKS command output. Special network id \c all can be +used to disable all network. + + +\subsection ctrl_iface_ADD_NETWORK ADD_NETWORK + +Add a new network. This command creates a new network with empty +configuration. The new network is disabled and once it has been +configured it can be enabled with \c ENABLE_NETWORK command. \c ADD_NETWORK +returns the network id of the new network or FAIL on failure. + + +\subsection ctrl_iface_REMOVE_NETWORK REMOVE_NETWORK <network id> + +Remove a network. Network id can be received from the +\c LIST_NETWORKS command output. Special network id \c all can be +used to remove all network. + + +\subsection ctrl_iface_SET_NETWORK SET_NETWORK <network id> <variable> <value> + +Set network variables. Network id can be received from the +\c LIST_NETWORKS command output. + +This command uses the same variables and data formats as the +configuration file. See example wpa_supplicant.conf for more details. + +- ssid (network name, SSID) +- psk (WPA passphrase or pre-shared key) +- key_mgmt (key management protocol) +- identity (EAP identity) +- password (EAP password) +- ... + + +\subsection ctrl_iface_GET_NETWORK GET_NETWORK <network id> <variable> + +Get network variables. Network id can be received from the +\c LIST_NETWORKS command output. + + +\subsection ctrl_iface_SAVE_CONFIG SAVE_CONFIG + +Save the current configuration. + + +\section ctrl_iface_interactive Interactive requests + +If %wpa_supplicant needs additional information during authentication +(e.g., password), it will use a specific prefix, \c CTRL-REQ- +(\a WPA_CTRL_REQ macro) in an unsolicited event message. An external +program, e.g., a GUI, can provide such information by using +\c CTRL-RSP- (\a WPA_CTRL_RSP macro) prefix in a command with matching +field name. + +The following fields can be requested in this way from the user: +- IDENTITY (EAP identity/user name) +- PASSWORD (EAP password) +- NEW_PASSWORD (New password if the server is requesting password change) +- PIN (PIN code for accessing a SIM or smartcard) +- OTP (one-time password; like password, but the value is used only once) +- PASSPHRASE (passphrase for a private key file) + +\verbatim +CTRL-REQ-<field name>-<network id>-<human readable text> +CTRL-RSP-<field name>-<network id>-<value> +\endverbatim + +For example, request from %wpa_supplicant: +\verbatim +CTRL-REQ-PASSWORD-1-Password needed for SSID test-network +\endverbatim + +And a matching reply from the GUI: +\verbatim +CTRL-RSP-PASSWORD-1-secret +\endverbatim + + +\subsection ctrl_iface_GET_CAPABILITY GET_CAPABILITY <option> [strict] + +Get list of supported functionality (eap, pairwise, group, +proto). Supported functionality is shown as space separate lists of +values used in the same format as in %wpa_supplicant configuration. +If optional argument, 'strict', is added, only the values that the +driver claims to explicitly support are included. Without this, all +available capabilities are included if the driver does not provide +a mechanism for querying capabilities. + +Example request/reply pairs: + +\verbatim +GET_CAPABILITY eap +AKA FAST GTC LEAP MD5 MSCHAPV2 OTP PAX PEAP PSK SIM TLS TTLS +\endverbatim + +\verbatim +GET_CAPABILITY pairwise +CCMP TKIP NONE +\endverbatim + +\verbatim +GET_CAPABILITY pairwise strict +\endverbatim + +\verbatim +GET_CAPABILITY group +CCMP TKIP WEP104 WEP40 +\endverbatim + +\verbatim +GET_CAPABILITY key_mgmt +WPA-PSK WPA-EAP IEEE8021X NONE +\endverbatim + +\verbatim +GET_CAPABILITY proto +RSN WPA +\endverbatim + +\verbatim +GET_CAPABILITY auth_alg +OPEN SHARED LEAP +\endverbatim + + +\subsection ctrl_iface_AP_SCAN AP_SCAN <ap_scan value> + +Change ap_scan value: +0 = no scanning, +1 = %wpa_supplicant requests scans and uses scan results to select the AP, +2 = %wpa_supplicant does not use scanning and just requests driver to +associate and take care of AP selection + + +\subsection ctrl_iface_INTERFACES INTERFACES + +List configured interfaces. + +\verbatim +wlan0 +eth0 +\endverbatim + +*/ diff --git a/wpa_supplicant/doc/docbook/.gitignore b/wpa_supplicant/doc/docbook/.gitignore new file mode 100644 index 000000000000..8c3945c526b5 --- /dev/null +++ b/wpa_supplicant/doc/docbook/.gitignore @@ -0,0 +1,6 @@ +manpage.links +manpage.refs +*.8 +*.5 +*.html +*.pdf diff --git a/wpa_supplicant/doc/docbook/Makefile b/wpa_supplicant/doc/docbook/Makefile new file mode 100644 index 000000000000..aaeee2eee453 --- /dev/null +++ b/wpa_supplicant/doc/docbook/Makefile @@ -0,0 +1,27 @@ +all: man html pdf + +FILES += wpa_background +FILES += wpa_cli +FILES += wpa_gui +FILES += wpa_passphrase +FILES += wpa_priv +FILES += wpa_supplicant.conf +FILES += wpa_supplicant + +man: + for i in $(FILES); do docbook2man $$i.sgml; done + +html: + for i in $(FILES); do docbook2html $$i.sgml && \ + mv index.html $$i.html; done + +pdf: + for i in $(FILES); do docbook2pdf $$i.sgml; done + + +clean: + rm -f wpa_background.8 wpa_cli.8 wpa_gui.8 wpa_passphrase.8 wpa_priv.8 wpa_supplicant.8 + rm -f wpa_supplicant.conf.5 + rm -f manpage.links manpage.refs + rm -f $(FILES:%=%.pdf) + rm -f $(FILES:%=%.html) diff --git a/wpa_supplicant/doc/docbook/manpage.links b/wpa_supplicant/doc/docbook/manpage.links new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/wpa_supplicant/doc/docbook/manpage.links diff --git a/wpa_supplicant/doc/docbook/manpage.refs b/wpa_supplicant/doc/docbook/manpage.refs new file mode 100644 index 000000000000..16ffc791b0e1 --- /dev/null +++ b/wpa_supplicant/doc/docbook/manpage.refs @@ -0,0 +1,4 @@ +{ + '' => '', + '' => '' +} diff --git a/wpa_supplicant/doc/docbook/wpa_background.8 b/wpa_supplicant/doc/docbook/wpa_background.8 new file mode 100644 index 000000000000..3bda3f4e5033 --- /dev/null +++ b/wpa_supplicant/doc/docbook/wpa_background.8 @@ -0,0 +1,84 @@ +.\" This manpage has been automatically generated by docbook2man +.\" from a DocBook document. This tool can be found at: +.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> +.\" Please send any bug reports, improvements, comments, patches, +.\" etc. to Steve Cheng <steve@ggi-project.org>. +.TH "WPA_BACKGROUND" "8" "15 February 2009" "" "" + +.SH NAME +wpa_background \- Background information on Wi-Fi Protected Access and IEEE 802.11i +.SH "WPA" +.PP +The original security mechanism of IEEE 802.11 standard was +not designed to be strong and has proven 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 published in July 2004. +.PP +Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version +of the IEEE 802.11i work (draft 3.0) to define a subset of the +security enhancements that can be implemented with existing wlan +hardware. This is called Wi-Fi Protected Access<TM> (WPA). This +has now become a mandatory component of interoperability testing +and certification done by Wi-Fi Alliance. Wi-Fi provides +information about WPA at its web site +(http://www.wi-fi.org/OpenSection/protected_access.asp). +.PP +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. +.PP +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). +.PP +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). +.PP +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). +.SH "IEEE 802.11I / WPA2" +.PP +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). +.SH "SEE ALSO" +.PP +\fBwpa_supplicant\fR(8) +.SH "LEGAL" +.PP +wpa_supplicant is copyright (c) 2003-2007, +Jouni Malinen <j@w1.fi> and +contributors. +All Rights Reserved. +.PP +This program is dual-licensed under both the GPL version 2 +and BSD license. Either license may be used at your option. diff --git a/wpa_supplicant/doc/docbook/wpa_background.sgml b/wpa_supplicant/doc/docbook/wpa_background.sgml new file mode 100644 index 000000000000..f47235b17118 --- /dev/null +++ b/wpa_supplicant/doc/docbook/wpa_background.sgml @@ -0,0 +1,101 @@ +<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN"> + +<refentry> + <refmeta> + <refentrytitle>wpa_background</refentrytitle> + <manvolnum>8</manvolnum> + </refmeta> + <refnamediv> + <refname>wpa_background</refname> + <refpurpose>Background information on Wi-Fi Protected Access and IEEE 802.11i</refpurpose> + </refnamediv> + <refsect1> + <title>WPA</title> + + <para>The original security mechanism of IEEE 802.11 standard was + not designed to be strong and has proven 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 published in July 2004.</para> + + <para>Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version + of the IEEE 802.11i work (draft 3.0) to define a subset of the + security enhancements that can be implemented with existing wlan + hardware. This is called Wi-Fi Protected Access<TM> (WPA). This + has now become a mandatory component of interoperability testing + and certification done by Wi-Fi Alliance. Wi-Fi provides + information about WPA at its web site + (http://www.wi-fi.org/OpenSection/protected_access.asp).</para> + + <para>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.</para> + + <para>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).</para> + + <para>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).</para> + + <para>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).</para> + </refsect1> + + <refsect1> + <title>IEEE 802.11i / WPA2</title> + + <para>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).</para> + </refsect1> + + <refsect1> + <title>See Also</title> + <para> + <citerefentry> + <refentrytitle>wpa_supplicant</refentrytitle> + <manvolnum>8</manvolnum> + </citerefentry> + </para> + </refsect1> + + <refsect1> + <title>Legal</title> + <para>wpa_supplicant is copyright (c) 2003-2007, + Jouni Malinen <email>j@w1.fi</email> and + contributors. + All Rights Reserved.</para> + + <para>This program is dual-licensed under both the GPL version 2 + and BSD license. Either license may be used at your option.</para> + </refsect1> +</refentry> diff --git a/wpa_supplicant/doc/docbook/wpa_cli.8 b/wpa_supplicant/doc/docbook/wpa_cli.8 new file mode 100644 index 000000000000..4e4aa461166c --- /dev/null +++ b/wpa_supplicant/doc/docbook/wpa_cli.8 @@ -0,0 +1,210 @@ +.\" This manpage has been automatically generated by docbook2man +.\" from a DocBook document. This tool can be found at: +.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> +.\" Please send any bug reports, improvements, comments, patches, +.\" etc. to Steve Cheng <steve@ggi-project.org>. +.TH "WPA_CLI" "8" "15 February 2009" "" "" + +.SH NAME +wpa_cli \- WPA command line client +.SH SYNOPSIS + +\fBwpa_cli\fR [ \fB-p \fIpath to ctrl sockets\fB\fR ] [ \fB-i \fIifname\fB\fR ] [ \fB-hvB\fR ] [ \fB-a \fIaction file\fB\fR ] [ \fB-P \fIpid file\fB\fR ] [ \fB\fIcommand ...\fB\fR ] + +.SH "OVERVIEW" +.PP +wpa_cli is a text-based frontend program for interacting +with wpa_supplicant. It is used to query current status, change +configuration, trigger events, and request interactive user +input. +.PP +wpa_cli can show the current authentication status, selected +security mode, dot11 and dot1x MIBs, etc. In addition, it can +configure some variables like EAPOL state machine parameters and +trigger events like reassociation and IEEE 802.1X +logoff/logon. wpa_cli provides a user interface to request +authentication information, like username and password, if these +are not included in the configuration. This can be used to +implement, e.g., one-time-passwords or generic token card +authentication where the authentication is based on a +challenge-response that uses an external device for generating the +response. +.PP +The control interface of wpa_supplicant can be configured to +allow non-root user access (ctrl_interface GROUP= parameter in the +configuration file). This makes it possible to run wpa_cli with a +normal user account. +.PP +wpa_cli supports two modes: interactive and command +line. Both modes share the same command set and the main +difference is in interactive mode providing access to unsolicited +messages (event messages, username/password requests). +.PP +Interactive mode is started when wpa_cli is executed without +including the command as a command line parameter. Commands are +then entered on the wpa_cli prompt. In command line mode, the same +commands are entered as command line arguments for wpa_cli. +.SH "INTERACTIVE AUTHENTICATION PARAMETERS REQUEST" +.PP +When wpa_supplicant need authentication parameters, like +username and password, which are not present in the configuration +file, it sends a request message to all attached frontend programs, +e.g., wpa_cli in interactive mode. wpa_cli shows these requests +with "CTRL-REQ-<type>-<id>:<text>" +prefix. <type> is IDENTITY, PASSWORD, or OTP +(one-time-password). <id> is a unique identifier for the +current network. <text> is description of the request. In +case of OTP request, it includes the challenge from the +authentication server. +.PP +The reply to these requests can be given with +\fBidentity\fR, \fBpassword\fR, and +\fBotp\fR commands. <id> needs to be copied from +the matching request. \fBpassword\fR and +\fBotp\fR commands can be used regardless of whether +the request was for PASSWORD or OTP. The main difference between these +two commands is that values given with \fBpassword\fR are +remembered as long as wpa_supplicant is running whereas values given +with \fBotp\fR are used only once and then forgotten, +i.e., wpa_supplicant will ask frontend for a new value for every use. +This can be used to implement one-time-password lists and generic token +card -based authentication. +.PP +Example request for password and a matching reply: +.sp +.RS + +.nf +CTRL-REQ-PASSWORD-1:Password needed for SSID foobar +> password 1 mysecretpassword +.fi +.RE +.PP +Example request for generic token card challenge-response: +.sp +.RS + +.nf +CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar +> otp 2 9876 +.fi +.RE +.SH "COMMAND ARGUMENTS" +.TP +\fB-p path\fR +Change the path where control sockets should +be found. +.TP +\fB-i ifname\fR +Specify the interface that is being +configured. By default, choose the first interface found with +a control socket in the socket path. +.TP +\fB-h\fR +Help. Show a usage message. +.TP +\fB-v\fR +Show version information. +.TP +\fB-B\fR +Run as a daemon in the background. +.TP +\fB-a file\fR +Run in daemon mode executing the action file +based on events from wpa_supplicant. The specified file will +be executed with the first argument set to interface name and +second to "CONNECTED" or "DISCONNECTED" depending on the event. +This can be used to execute networking tools required to configure +the interface. + +Additionally, three environmental variables are available to +the file: WPA_CTRL_DIR, WPA_ID, and WPA_ID_STR. WPA_CTRL_DIR +contains the absolute path to the ctrl_interface socket. WPA_ID +contains the unique network_id identifier assigned to the active +network, and WPA_ID_STR contains the content of the id_str option. +.TP +\fB-P file\fR +Set the location of the PID +file. +.TP +\fBcommand\fR +Run a command. The available commands are +listed in the next section. +.SH "COMMANDS" +.PP +The following commands are available: +.TP +\fBstatus\fR +get current WPA/EAPOL/EAP status +.TP +\fBmib\fR +get MIB variables (dot1x, dot11) +.TP +\fBhelp\fR +show this usage help +.TP +\fBinterface [ifname]\fR +show interfaces/select interface +.TP +\fBlevel <debug level>\fR +change debug level +.TP +\fBlicense\fR +show full wpa_cli license +.TP +\fBlogoff\fR +IEEE 802.1X EAPOL state machine logoff +.TP +\fBlogon\fR +IEEE 802.1X EAPOL state machine logon +.TP +\fBset\fR +set variables (shows list of variables when run without arguments) +.TP +\fBpmksa\fR +show PMKSA cache +.TP +\fBreassociate\fR +force reassociation +.TP +\fBreconfigure\fR +force wpa_supplicant to re-read its configuration file +.TP +\fBpreauthenticate <BSSID>\fR +force preauthentication +.TP +\fBidentity <network id> <identity>\fR +configure identity for an SSID +.TP +\fBpassword <network id> <password>\fR +configure password for an SSID +.TP +\fBpin <network id> <pin>\fR +configure pin for an SSID +.TP +\fBotp <network id> <password>\fR +configure one-time-password for an SSID +.TP +\fBbssid <network id> <BSSID>\fR +set preferred BSSID for an SSID +.TP +\fBlist_networks\fR +list configured networks +.TP +\fBterminate\fR +terminate \fBwpa_supplicant\fR +.TP +\fBquit\fR +exit wpa_cli +.SH "SEE ALSO" +.PP +\fBwpa_supplicant\fR(8) +.SH "LEGAL" +.PP +wpa_supplicant is copyright (c) 2003-2007, +Jouni Malinen <j@w1.fi> and +contributors. +All Rights Reserved. +.PP +This program is dual-licensed under both the GPL version 2 +and BSD license. Either license may be used at your option. diff --git a/wpa_supplicant/doc/docbook/wpa_cli.sgml b/wpa_supplicant/doc/docbook/wpa_cli.sgml new file mode 100644 index 000000000000..1fe98f4fc56e --- /dev/null +++ b/wpa_supplicant/doc/docbook/wpa_cli.sgml @@ -0,0 +1,339 @@ +<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN"> + +<refentry> + <refmeta> + <refentrytitle>wpa_cli</refentrytitle> + <manvolnum>8</manvolnum> + </refmeta> + <refnamediv> + <refname>wpa_cli</refname> + + <refpurpose>WPA command line client</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <cmdsynopsis> + <command>wpa_cli</command> + <arg>-p <replaceable>path to ctrl sockets</replaceable></arg> + <arg>-i <replaceable>ifname</replaceable></arg> + <arg>-hvB</arg> + <arg>-a <replaceable>action file</replaceable></arg> + <arg>-P <replaceable>pid file</replaceable></arg> + <arg><replaceable>command ...</replaceable></arg> + </cmdsynopsis> + </refsynopsisdiv> + + <refsect1> + <title>Overview</title> + + <para>wpa_cli is a text-based frontend program for interacting + with wpa_supplicant. It is used to query current status, change + configuration, trigger events, and request interactive user + input.</para> + + <para>wpa_cli can show the current authentication status, selected + security mode, dot11 and dot1x MIBs, etc. In addition, it can + configure some variables like EAPOL state machine parameters and + trigger events like reassociation and IEEE 802.1X + logoff/logon. wpa_cli provides a user interface to request + authentication information, like username and password, if these + are not included in the configuration. This can be used to + implement, e.g., one-time-passwords or generic token card + authentication where the authentication is based on a + challenge-response that uses an external device for generating the + response.</para> + + <para>The control interface of wpa_supplicant can be configured to + allow non-root user access (ctrl_interface GROUP= parameter in the + configuration file). This makes it possible to run wpa_cli with a + normal user account.</para> + + <para>wpa_cli supports two modes: interactive and command + line. Both modes share the same command set and the main + difference is in interactive mode providing access to unsolicited + messages (event messages, username/password requests).</para> + + <para>Interactive mode is started when wpa_cli is executed without + including the command as a command line parameter. Commands are + then entered on the wpa_cli prompt. In command line mode, the same + commands are entered as command line arguments for wpa_cli.</para> + </refsect1> + <refsect1> + <title>Interactive authentication parameters request</title> + + <para>When wpa_supplicant need authentication parameters, like + username and password, which are not present in the configuration + file, it sends a request message to all attached frontend programs, + e.g., wpa_cli in interactive mode. wpa_cli shows these requests + with "CTRL-REQ-<type>-<id>:<text>" + prefix. <type> is IDENTITY, PASSWORD, or OTP + (one-time-password). <id> is a unique identifier for the + current network. <text> is description of the request. In + case of OTP request, it includes the challenge from the + authentication server.</para> + + <para>The reply to these requests can be given with + <emphasis>identity</emphasis>, <emphasis>password</emphasis>, and + <emphasis>otp</emphasis> commands. <id> needs to be copied from + the matching request. <emphasis>password</emphasis> and + <emphasis>otp</emphasis> commands can be used regardless of whether + the request was for PASSWORD or OTP. The main difference between these + two commands is that values given with <emphasis>password</emphasis> are + remembered as long as wpa_supplicant is running whereas values given + with <emphasis>otp</emphasis> are used only once and then forgotten, + i.e., wpa_supplicant will ask frontend for a new value for every use. + This can be used to implement one-time-password lists and generic token + card -based authentication.</para> + + <para>Example request for password and a matching reply:</para> + +<blockquote><programlisting> +CTRL-REQ-PASSWORD-1:Password needed for SSID foobar +> password 1 mysecretpassword +</programlisting></blockquote> + + <para>Example request for generic token card challenge-response:</para> + +<blockquote><programlisting> +CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar +> otp 2 9876 +</programlisting></blockquote> + + </refsect1> + <refsect1> + <title>Command Arguments</title> + <variablelist> + <varlistentry> + <term>-p path</term> + + <listitem><para>Change the path where control sockets should + be found.</para></listitem> + </varlistentry> + + <varlistentry> + <term>-i ifname</term> + + <listitem><para>Specify the interface that is being + configured. By default, choose the first interface found with + a control socket in the socket path.</para></listitem> + </varlistentry> + + <varlistentry> + <term>-h</term> + <listitem><para>Help. Show a usage message.</para></listitem> + </varlistentry> + + + <varlistentry> + <term>-v</term> + <listitem><para>Show version information.</para></listitem> + </varlistentry> + + + <varlistentry> + <term>-B</term> + <listitem><para>Run as a daemon in the background.</para></listitem> + </varlistentry> + + <varlistentry> + <term>-a file</term> + + <listitem><para>Run in daemon mode executing the action file + based on events from wpa_supplicant. The specified file will + be executed with the first argument set to interface name and + second to "CONNECTED" or "DISCONNECTED" depending on the event. + This can be used to execute networking tools required to configure + the interface.</para> + + <para>Additionally, three environmental variables are available to + the file: WPA_CTRL_DIR, WPA_ID, and WPA_ID_STR. WPA_CTRL_DIR + contains the absolute path to the ctrl_interface socket. WPA_ID + contains the unique network_id identifier assigned to the active + network, and WPA_ID_STR contains the content of the id_str option. + </para></listitem> + </varlistentry> + + <varlistentry> + <term>-P file</term> + + <listitem><para>Set the location of the PID + file.</para></listitem> + </varlistentry> + + <varlistentry> + <term>command</term> + + <listitem><para>Run a command. The available commands are + listed in the next section.</para></listitem> + + </varlistentry> + </variablelist> + </refsect1> + <refsect1> + <title>Commands</title> + <para>The following commands are available:</para> + + <variablelist> + <varlistentry> + <term>status</term> + <listitem> + <para>get current WPA/EAPOL/EAP status</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>mib</term> + <listitem> + <para>get MIB variables (dot1x, dot11)</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>help</term> + <listitem> + <para>show this usage help</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>interface [ifname]</term> + <listitem> + <para>show interfaces/select interface</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>level <debug level></term> + <listitem> + <para>change debug level</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>license</term> + <listitem> + <para>show full wpa_cli license</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>logoff</term> + <listitem> + <para>IEEE 802.1X EAPOL state machine logoff</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>logon</term> + <listitem> + <para>IEEE 802.1X EAPOL state machine logon</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>set</term> + <listitem> + <para>set variables (shows list of variables when run without arguments)</para> + </listitem> + </varlistentry> + <varlistentry> + <term>pmksa</term> + <listitem> + <para>show PMKSA cache</para> + </listitem> + </varlistentry> + <varlistentry> + <term>reassociate</term> + <listitem> + <para>force reassociation</para> + </listitem> + </varlistentry> + <varlistentry> + <term>reconfigure</term> + <listitem> + <para>force wpa_supplicant to re-read its configuration file</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>preauthenticate <BSSID></term> + <listitem> + <para>force preauthentication</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>identity <network id> <identity></term> + <listitem> + <para>configure identity for an SSID</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>password <network id> <password></term> + <listitem> + <para>configure password for an SSID</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>pin <network id> <pin></term> + <listitem> + <para>configure pin for an SSID</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>otp <network id> <password></term> + <listitem> + <para>configure one-time-password for an SSID</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>bssid <network id> <BSSID></term> + <listitem> + <para>set preferred BSSID for an SSID</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>list_networks</term> + <listitem> + <para>list configured networks</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>terminate</term> + <listitem> + <para>terminate <command>wpa_supplicant</command></para> + </listitem> + </varlistentry> + + <varlistentry> + <term>quit</term> + <listitem><para>exit wpa_cli</para></listitem> + </varlistentry> + </variablelist> + </refsect1> + <refsect1> + <title>See Also</title> + <para> + <citerefentry> + <refentrytitle>wpa_supplicant</refentrytitle> + <manvolnum>8</manvolnum> + </citerefentry> + </para> + </refsect1> + <refsect1> + <title>Legal</title> + <para>wpa_supplicant is copyright (c) 2003-2007, + Jouni Malinen <email>j@w1.fi</email> and + contributors. + All Rights Reserved.</para> + + <para>This program is dual-licensed under both the GPL version 2 + and BSD license. Either license may be used at your option.</para> + </refsect1> +</refentry> diff --git a/wpa_supplicant/doc/docbook/wpa_gui.8 b/wpa_supplicant/doc/docbook/wpa_gui.8 new file mode 100644 index 000000000000..2f4f638d28b1 --- /dev/null +++ b/wpa_supplicant/doc/docbook/wpa_gui.8 @@ -0,0 +1,51 @@ +.\" This manpage has been automatically generated by docbook2man +.\" from a DocBook document. This tool can be found at: +.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> +.\" Please send any bug reports, improvements, comments, patches, +.\" etc. to Steve Cheng <steve@ggi-project.org>. +.TH "WPA_GUI" "8" "15 February 2009" "" "" + +.SH NAME +wpa_gui \- WPA Graphical User Interface +.SH SYNOPSIS + +\fBwpa_gui\fR [ \fB-p \fIpath to ctrl sockets\fB\fR ] [ \fB-i \fIifname\fB\fR ] [ \fB-t\fR ] + +.SH "OVERVIEW" +.PP +wpa_gui is a QT graphical frontend program for interacting +with wpa_supplicant. It is used to query current status, change +configuration and request interactive user input. +.PP +wpa_gui supports (almost) all of the interactive status and +configuration features of the command line client, wpa_cli. Refer +to the wpa_cli manpage for a comprehensive list of the +interactive mode features. +.SH "COMMAND ARGUMENTS" +.TP +\fB-p path\fR +Change the path where control sockets should +be found. +.TP +\fB-i ifname\fR +Specify the interface that is being +configured. By default, choose the first interface found with +a control socket in the socket path. +.TP +\fB-t\fR +Start program in the system tray only (if the window +manager supports it). By default the main status window is +shown. +.SH "SEE ALSO" +.PP +\fBwpa_cli\fR(8) +\fBwpa_supplicant\fR(8) +.SH "LEGAL" +.PP +wpa_supplicant is copyright (c) 2003-2007, +Jouni Malinen <j@w1.fi> and +contributors. +All Rights Reserved. +.PP +This program is dual-licensed under both the GPL version 2 +and BSD license. Either license may be used at your option. diff --git a/wpa_supplicant/doc/docbook/wpa_gui.sgml b/wpa_supplicant/doc/docbook/wpa_gui.sgml new file mode 100644 index 000000000000..41b58492440e --- /dev/null +++ b/wpa_supplicant/doc/docbook/wpa_gui.sgml @@ -0,0 +1,85 @@ +<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN"> + +<refentry> + <refmeta> + <refentrytitle>wpa_gui</refentrytitle> + <manvolnum>8</manvolnum> + </refmeta> + <refnamediv> + <refname>wpa_gui</refname> + + <refpurpose>WPA Graphical User Interface</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <cmdsynopsis> + <command>wpa_gui</command> + <arg>-p <replaceable>path to ctrl sockets</replaceable></arg> + <arg>-i <replaceable>ifname</replaceable></arg> + <arg>-t</arg> + </cmdsynopsis> + </refsynopsisdiv> + + <refsect1> + <title>Overview</title> + + <para>wpa_gui is a QT graphical frontend program for interacting + with wpa_supplicant. It is used to query current status, change + configuration and request interactive user input.</para> + + <para>wpa_gui supports (almost) all of the interactive status and + configuration features of the command line client, wpa_cli. Refer + to the wpa_cli manpage for a comprehensive list of the + interactive mode features.</para> + </refsect1> + <refsect1> + <title>Command Arguments</title> + <variablelist> + <varlistentry> + <term>-p path</term> + + <listitem><para>Change the path where control sockets should + be found.</para></listitem> + </varlistentry> + + <varlistentry> + <term>-i ifname</term> + + <listitem><para>Specify the interface that is being + configured. By default, choose the first interface found with + a control socket in the socket path.</para></listitem> + </varlistentry> + + <varlistentry> + <term>-t</term> + + <listitem><para>Start program in the system tray only (if the window + manager supports it). By default the main status window is + shown.</para></listitem> + </varlistentry> + </variablelist> + </refsect1> + <refsect1> + <title>See Also</title> + <para> + <citerefentry> + <refentrytitle>wpa_cli</refentrytitle> + <manvolnum>8</manvolnum> + </citerefentry> + <citerefentry> + <refentrytitle>wpa_supplicant</refentrytitle> + <manvolnum>8</manvolnum> + </citerefentry> + </para> + </refsect1> + <refsect1> + <title>Legal</title> + <para>wpa_supplicant is copyright (c) 2003-2007, + Jouni Malinen <email>j@w1.fi</email> and + contributors. + All Rights Reserved.</para> + + <para>This program is dual-licensed under both the GPL version 2 + and BSD license. Either license may be used at your option.</para> + </refsect1> +</refentry> diff --git a/wpa_supplicant/doc/docbook/wpa_passphrase.8 b/wpa_supplicant/doc/docbook/wpa_passphrase.8 new file mode 100644 index 000000000000..b123daad8091 --- /dev/null +++ b/wpa_supplicant/doc/docbook/wpa_passphrase.8 @@ -0,0 +1,40 @@ +.\" This manpage has been automatically generated by docbook2man +.\" from a DocBook document. This tool can be found at: +.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> +.\" Please send any bug reports, improvements, comments, patches, +.\" etc. to Steve Cheng <steve@ggi-project.org>. +.TH "WPA_PASSPHRASE" "8" "15 February 2009" "" "" + +.SH NAME +wpa_passphrase \- Generate a WPA PSK from an ASCII passphrase for a SSID +.SH SYNOPSIS + +\fBwpa_passphrase\fR [ \fB\fIssid\fB\fR ] [ \fB\fIpassphrase\fB\fR ] + +.SH "OVERVIEW" +.PP +\fBwpa_passphrase\fR pre-computes PSK entries for +network configuration blocks of a +\fIwpa_supplicant.conf\fR file. An ASCII passphrase +and SSID are used to generate a 256-bit PSK. +.SH "OPTIONS" +.TP +\fBssid\fR +The SSID whose passphrase should be derived. +.TP +\fBpassphrase\fR +The passphrase to use. If not included on the command line, +passphrase will be read from standard input. +.SH "SEE ALSO" +.PP +\fBwpa_supplicant.conf\fR(5) +\fBwpa_supplicant\fR(8) +.SH "LEGAL" +.PP +wpa_supplicant is copyright (c) 2003-2007, +Jouni Malinen <j@w1.fi> and +contributors. +All Rights Reserved. +.PP +This program is dual-licensed under both the GPL version 2 +and BSD license. Either license may be used at your option. diff --git a/wpa_supplicant/doc/docbook/wpa_passphrase.sgml b/wpa_supplicant/doc/docbook/wpa_passphrase.sgml new file mode 100644 index 000000000000..402ea091f9af --- /dev/null +++ b/wpa_supplicant/doc/docbook/wpa_passphrase.sgml @@ -0,0 +1,73 @@ +<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN"> + +<refentry> + <refmeta> + <refentrytitle>wpa_passphrase</refentrytitle> + <manvolnum>8</manvolnum> + </refmeta> + <refnamediv> + <refname>wpa_passphrase</refname> + <refpurpose>Generate a WPA PSK from an ASCII passphrase for a SSID</refpurpose> + </refnamediv> + <refsynopsisdiv> + <cmdsynopsis> + <command>wpa_passphrase</command> + <arg><replaceable>ssid</replaceable></arg> + <arg><replaceable>passphrase</replaceable></arg> + </cmdsynopsis> + </refsynopsisdiv> + + <refsect1> + <title>Overview</title> + + <para><command>wpa_passphrase</command> pre-computes PSK entries for + network configuration blocks of a + <filename>wpa_supplicant.conf</filename> file. An ASCII passphrase + and SSID are used to generate a 256-bit PSK.</para> + </refsect1> + + <refsect1> + <title>Options</title> + <variablelist> + <varlistentry> + <term>ssid</term> + <listitem> + <para>The SSID whose passphrase should be derived.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>passphrase</term> + <listitem> + <para>The passphrase to use. If not included on the command line, + passphrase will be read from standard input.</para> + </listitem> + </varlistentry> + </variablelist> + </refsect1> + + <refsect1> + <title>See Also</title> + <para> + <citerefentry> + <refentrytitle>wpa_supplicant.conf</refentrytitle> + <manvolnum>5</manvolnum> + </citerefentry> + <citerefentry> + <refentrytitle>wpa_supplicant</refentrytitle> + <manvolnum>8</manvolnum> + </citerefentry> + </para> + + </refsect1> + <refsect1> + <title>Legal</title> + <para>wpa_supplicant is copyright (c) 2003-2007, + Jouni Malinen <email>j@w1.fi</email> and + contributors. + All Rights Reserved.</para> + + <para>This program is dual-licensed under both the GPL version 2 + and BSD license. Either license may be used at your option.</para> + </refsect1> +</refentry> diff --git a/wpa_supplicant/doc/docbook/wpa_priv.8 b/wpa_supplicant/doc/docbook/wpa_priv.8 new file mode 100644 index 000000000000..2191cec94e9c --- /dev/null +++ b/wpa_supplicant/doc/docbook/wpa_priv.8 @@ -0,0 +1,120 @@ +.\" This manpage has been automatically generated by docbook2man +.\" from a DocBook document. This tool can be found at: +.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> +.\" Please send any bug reports, improvements, comments, patches, +.\" etc. to Steve Cheng <steve@ggi-project.org>. +.TH "WPA_PRIV" "8" "15 February 2009" "" "" + +.SH NAME +wpa_priv \- wpa_supplicant privilege separation helper +.SH SYNOPSIS + +\fBwpa_priv\fR [ \fB-c \fIctrl path\fB\fR ] [ \fB-Bdd\fR ] [ \fB-P \fIpid file\fB\fR ] [ \fBdriver:ifname \fI[driver:ifname ...]\fB\fR ] + +.SH "OVERVIEW" +.PP +\fBwpa_priv\fR is a privilege separation helper that +minimizes the size of \fBwpa_supplicant\fR code that needs +to be run with root privileges. +.PP +If enabled, privileged operations are done in the wpa_priv process +while leaving rest of the code (e.g., EAP authentication and WPA +handshakes) to operate in an unprivileged process (wpa_supplicant) that +can be run as non-root user. Privilege separation restricts the effects +of potential software errors by containing the majority of the code in an +unprivileged process to avoid the possibility of a full system +compromise. +.PP +\fBwpa_priv\fR needs to be run with network admin +privileges (usually, root user). It opens a UNIX domain socket for each +interface that is included on the command line; any other interface will +be off limits for \fBwpa_supplicant\fR in this kind of +configuration. After this, \fBwpa_supplicant\fR can be run as +a non-root user (e.g., all standard users on a laptop or as a special +non-privileged user account created just for this purpose to limit access +to user files even further). +.SH "EXAMPLE CONFIGURATION" +.PP +The following steps are an example of how to configure +\fBwpa_priv\fR to allow users in the +\fBwpapriv\fR group to communicate with +\fBwpa_supplicant\fR with privilege separation: +.PP +Create user group (e.g., wpapriv) and assign users that +should be able to use wpa_supplicant into that group. +.PP +Create /var/run/wpa_priv directory for UNIX domain sockets and +control user access by setting it accessible only for the wpapriv +group: +.sp +.RS + +.nf +mkdir /var/run/wpa_priv +chown root:wpapriv /var/run/wpa_priv +chmod 0750 /var/run/wpa_priv +.fi +.RE +.PP +Start \fBwpa_priv\fR as root (e.g., from system +startup scripts) with the enabled interfaces configured on the +command line: +.sp +.RS + +.nf +wpa_priv -B -c /var/run/wpa_priv -P /var/run/wpa_priv.pid wext:wlan0 +.fi +.RE +.PP +Run \fBwpa_supplicant\fR as non-root with a user +that is in the wpapriv group: +.sp +.RS + +.nf +wpa_supplicant -i ath0 -c wpa_supplicant.conf +.fi +.RE +.SH "COMMAND ARGUMENTS" +.TP +\fB-c ctrl path\fR +Specify the path to wpa_priv control directory +(Default: /var/run/wpa_priv/). +.TP +\fB-B\fR +Run as a daemon in the background. +.TP +\fB-P file\fR +Set the location of the PID +file. +.TP +\fBdriver:ifname [driver:ifname ...]\fR +The <driver> string dictates which of the +supported \fBwpa_supplicant\fR driver backends is to be +used. To get a list of supported driver types see wpa_supplicant help +(e.g, wpa_supplicant -h). The driver backend supported by most good +drivers is \fBwext\fR\&. + +The <ifname> string specifies which network +interface is to be managed by \fBwpa_supplicant\fR +(e.g., wlan0 or ath0). + +\fBwpa_priv\fR does not use the network interface +before \fBwpa_supplicant\fR is started, so it is fine to +include network interfaces that are not available at the time wpa_priv +is started. wpa_priv can control multiple interfaces with one process, +but it is also possible to run multiple \fBwpa_priv\fR +processes at the same time, if desired. +.SH "SEE ALSO" +.PP +\fBwpa_supplicant\fR(8) +.SH "LEGAL" +.PP +wpa_supplicant is copyright (c) 2003-2007, +Jouni Malinen <j@w1.fi> and +contributors. +All Rights Reserved. +.PP +This program is dual-licensed under both the GPL version 2 +and BSD license. Either license may be used at your option. diff --git a/wpa_supplicant/doc/docbook/wpa_priv.sgml b/wpa_supplicant/doc/docbook/wpa_priv.sgml new file mode 100644 index 000000000000..89b8a9221965 --- /dev/null +++ b/wpa_supplicant/doc/docbook/wpa_priv.sgml @@ -0,0 +1,148 @@ +<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN"> + +<refentry> + <refmeta> + <refentrytitle>wpa_priv</refentrytitle> + <manvolnum>8</manvolnum> + </refmeta> + <refnamediv> + <refname>wpa_priv</refname> + + <refpurpose>wpa_supplicant privilege separation helper</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <cmdsynopsis> + <command>wpa_priv</command> + <arg>-c <replaceable>ctrl path</replaceable></arg> + <arg>-Bdd</arg> + <arg>-P <replaceable>pid file</replaceable></arg> + <arg>driver:ifname <replaceable>[driver:ifname ...]</replaceable></arg> + </cmdsynopsis> + </refsynopsisdiv> + + <refsect1> + <title>Overview</title> + + <para><command>wpa_priv</command> is a privilege separation helper that + minimizes the size of <command>wpa_supplicant</command> code that needs + to be run with root privileges.</para> + + <para>If enabled, privileged operations are done in the wpa_priv process + while leaving rest of the code (e.g., EAP authentication and WPA + handshakes) to operate in an unprivileged process (wpa_supplicant) that + can be run as non-root user. Privilege separation restricts the effects + of potential software errors by containing the majority of the code in an + unprivileged process to avoid the possibility of a full system + compromise.</para> + + <para><command>wpa_priv</command> needs to be run with network admin + privileges (usually, root user). It opens a UNIX domain socket for each + interface that is included on the command line; any other interface will + be off limits for <command>wpa_supplicant</command> in this kind of + configuration. After this, <command>wpa_supplicant</command> can be run as + a non-root user (e.g., all standard users on a laptop or as a special + non-privileged user account created just for this purpose to limit access + to user files even further).</para> + </refsect1> + <refsect1> + <title>Example configuration</title> + + <para>The following steps are an example of how to configure + <command>wpa_priv</command> to allow users in the + <emphasis>wpapriv</emphasis> group to communicate with + <command>wpa_supplicant</command> with privilege separation:</para> + + <para>Create user group (e.g., wpapriv) and assign users that + should be able to use wpa_supplicant into that group.</para> + + <para>Create /var/run/wpa_priv directory for UNIX domain sockets and + control user access by setting it accessible only for the wpapriv + group:</para> + +<blockquote><programlisting> +mkdir /var/run/wpa_priv +chown root:wpapriv /var/run/wpa_priv +chmod 0750 /var/run/wpa_priv +</programlisting></blockquote> + + <para>Start <command>wpa_priv</command> as root (e.g., from system + startup scripts) with the enabled interfaces configured on the + command line:</para> + +<blockquote><programlisting> +wpa_priv -B -c /var/run/wpa_priv -P /var/run/wpa_priv.pid wext:wlan0 +</programlisting></blockquote> + + <para>Run <command>wpa_supplicant</command> as non-root with a user + that is in the wpapriv group:</para> + +<blockquote><programlisting> +wpa_supplicant -i ath0 -c wpa_supplicant.conf +</programlisting></blockquote> + + </refsect1> + <refsect1> + <title>Command Arguments</title> + <variablelist> + <varlistentry> + <term>-c ctrl path</term> + + <listitem><para>Specify the path to wpa_priv control directory + (Default: /var/run/wpa_priv/).</para></listitem> + </varlistentry> + + <varlistentry> + <term>-B</term> + <listitem><para>Run as a daemon in the background.</para></listitem> + </varlistentry> + + <varlistentry> + <term>-P file</term> + + <listitem><para>Set the location of the PID + file.</para></listitem> + </varlistentry> + + <varlistentry> + <term>driver:ifname [driver:ifname ...]</term> + + <listitem><para>The <driver> string dictates which of the + supported <command>wpa_supplicant</command> driver backends is to be + used. To get a list of supported driver types see wpa_supplicant help + (e.g, wpa_supplicant -h). The driver backend supported by most good + drivers is <emphasis>wext</emphasis>.</para> + + <para>The <ifname> string specifies which network + interface is to be managed by <command>wpa_supplicant</command> + (e.g., wlan0 or ath0).</para> + + <para><command>wpa_priv</command> does not use the network interface + before <command>wpa_supplicant</command> is started, so it is fine to + include network interfaces that are not available at the time wpa_priv + is started. wpa_priv can control multiple interfaces with one process, + but it is also possible to run multiple <command>wpa_priv</command> + processes at the same time, if desired.</para></listitem> + </varlistentry> + </variablelist> + </refsect1> + <refsect1> + <title>See Also</title> + <para> + <citerefentry> + <refentrytitle>wpa_supplicant</refentrytitle> + <manvolnum>8</manvolnum> + </citerefentry> + </para> + </refsect1> + <refsect1> + <title>Legal</title> + <para>wpa_supplicant is copyright (c) 2003-2007, + Jouni Malinen <email>j@w1.fi</email> and + contributors. + All Rights Reserved.</para> + + <para>This program is dual-licensed under both the GPL version 2 + and BSD license. Either license may be used at your option.</para> + </refsect1> +</refentry> diff --git a/wpa_supplicant/doc/docbook/wpa_supplicant.8 b/wpa_supplicant/doc/docbook/wpa_supplicant.8 new file mode 100644 index 000000000000..0106c69697f0 --- /dev/null +++ b/wpa_supplicant/doc/docbook/wpa_supplicant.8 @@ -0,0 +1,571 @@ +.\" This manpage has been automatically generated by docbook2man +.\" from a DocBook document. This tool can be found at: +.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> +.\" Please send any bug reports, improvements, comments, patches, +.\" etc. to Steve Cheng <steve@ggi-project.org>. +.TH "WPA_SUPPLICANT" "8" "15 February 2009" "" "" + +.SH NAME +wpa_supplicant \- Wi-Fi Protected Access client and IEEE 802.1X supplicant +.SH SYNOPSIS + +\fBwpa_supplicant\fR [ \fB-BddfhKLqqtuvW\fR ] [ \fB-i\fIifname\fB\fR ] [ \fB-c\fIconfig file\fB\fR ] [ \fB-D\fIdriver\fB\fR ] [ \fB-P\fIPID_file\fB\fR ] [ \fB-f\fIoutput file\fB\fR ] + +.SH "OVERVIEW" +.PP +Wireless networks do not require physical access to the network equipment +in the same way as wired networks. This makes it easier for unauthorized +users to passively monitor a network and capture all transmitted frames. +In addition, unauthorized use of the network is much easier. In many cases, +this can happen even without user's explicit knowledge since the wireless +LAN adapter may have been configured to automatically join any available +network. +.PP +Link-layer encryption can be used to provide a layer of security for +wireless networks. The original wireless LAN standard, IEEE 802.11, +included a simple encryption mechanism, WEP. However, that proved to +be flawed in many areas and network protected with WEP cannot be consider +secure. IEEE 802.1X authentication and frequently changed dynamic WEP keys +can be used to improve the network security, but even that has inherited +security issues due to the use of WEP for encryption. Wi-Fi Protected +Access and IEEE 802.11i amendment to the wireless LAN standard introduce +a much improvement mechanism for securing wireless networks. IEEE 802.11i +enabled networks that are using CCMP (encryption mechanism based on strong +cryptographic algorithm AES) can finally be called secure used for +applications which require efficient protection against unauthorized +access. +.PP +\fBwpa_supplicant\fR is an implementation of +the WPA Supplicant component, i.e., the part that runs in the +client stations. It implements WPA key negotiation with a WPA +Authenticator and EAP authentication with Authentication +Server. In addition, it controls the roaming and IEEE 802.11 +authentication/association of the wireless LAN driver. +.PP +\fBwpa_supplicant\fR is designed to be a +"daemon" program that runs in the background and acts as the +backend component controlling the wireless +connection. \fBwpa_supplicant\fR supports separate +frontend programs and an example text-based frontend, +\fBwpa_cli\fR, is included with +wpa_supplicant. +.PP +Before wpa_supplicant can do its work, the network interface +must be available. That means that the physical device must be +present and enabled, and the driver for the device must be +loaded. The daemon will exit immediately if the device is not already +available. +.PP +After \fBwpa_supplicant\fR has configured the +network device, higher level configuration such as DHCP may +proceed. There are a variety of ways to integrate wpa_supplicant +into a machine's networking scripts, a few of which are described +in sections below. +.PP +The following steps are used when associating with an AP +using WPA: +.TP 0.2i +\(bu +\fBwpa_supplicant\fR requests the kernel +driver to scan neighboring BSSes +.TP 0.2i +\(bu +\fBwpa_supplicant\fR selects a BSS based on +its configuration +.TP 0.2i +\(bu +\fBwpa_supplicant\fR requests the kernel +driver to associate with the chosen BSS +.TP 0.2i +\(bu +If WPA-EAP: integrated IEEE 802.1X Supplicant +completes EAP authentication with the +authentication server (proxied by the Authenticator in the +AP) +.TP 0.2i +\(bu +If WPA-EAP: master key is received from the IEEE 802.1X +Supplicant +.TP 0.2i +\(bu +If WPA-PSK: \fBwpa_supplicant\fR uses PSK +as the master session key +.TP 0.2i +\(bu +\fBwpa_supplicant\fR completes WPA 4-Way +Handshake and Group Key Handshake with the Authenticator +(AP) +.TP 0.2i +\(bu +\fBwpa_supplicant\fR configures encryption +keys for unicast and broadcast +.TP 0.2i +\(bu +normal data packets can be transmitted and received +.SH "SUPPORTED FEATURES" +.PP +Supported WPA/IEEE 802.11i features: +.TP 0.2i +\(bu +WPA-PSK ("WPA-Personal") +.TP 0.2i +\(bu +WPA with EAP (e.g., with RADIUS authentication server) +("WPA-Enterprise") Following authentication methods are +supported with an integrate IEEE 802.1X Supplicant: +.RS +.TP 0.2i +\(bu +EAP-TLS +.RE +.RS +.TP 0.2i +\(bu +EAP-PEAP/MSCHAPv2 (both PEAPv0 and PEAPv1) +.TP 0.2i +\(bu +EAP-PEAP/TLS (both PEAPv0 and PEAPv1) +.TP 0.2i +\(bu +EAP-PEAP/GTC (both PEAPv0 and PEAPv1) +.TP 0.2i +\(bu +EAP-PEAP/OTP (both PEAPv0 and PEAPv1) +.TP 0.2i +\(bu +EAP-PEAP/MD5-Challenge (both PEAPv0 and PEAPv1) +.TP 0.2i +\(bu +EAP-TTLS/EAP-MD5-Challenge +.TP 0.2i +\(bu +EAP-TTLS/EAP-GTC +.TP 0.2i +\(bu +EAP-TTLS/EAP-OTP +.TP 0.2i +\(bu +EAP-TTLS/EAP-MSCHAPv2 +.TP 0.2i +\(bu +EAP-TTLS/EAP-TLS +.TP 0.2i +\(bu +EAP-TTLS/MSCHAPv2 +.TP 0.2i +\(bu +EAP-TTLS/MSCHAP +.TP 0.2i +\(bu +EAP-TTLS/PAP +.TP 0.2i +\(bu +EAP-TTLS/CHAP +.TP 0.2i +\(bu +EAP-SIM +.TP 0.2i +\(bu +EAP-AKA +.TP 0.2i +\(bu +EAP-PSK +.TP 0.2i +\(bu +EAP-PAX +.TP 0.2i +\(bu +LEAP (note: requires special support from +the driver for IEEE 802.11 authentication) +.TP 0.2i +\(bu +(following methods are supported, but since +they do not generate keying material, they cannot be used +with WPA or IEEE 802.1X WEP keying) +.TP 0.2i +\(bu +EAP-MD5-Challenge +.TP 0.2i +\(bu +EAP-MSCHAPv2 +.TP 0.2i +\(bu +EAP-GTC +.TP 0.2i +\(bu +EAP-OTP +.RE +.TP 0.2i +\(bu +key management for CCMP, TKIP, WEP104, WEP40 +.TP 0.2i +\(bu +RSN/WPA2 (IEEE 802.11i) +.RS +.TP 0.2i +\(bu +pre-authentication +.TP 0.2i +\(bu +PMKSA caching +.RE +.SH "AVAILABLE DRIVERS" +.PP +A summary of available driver backends is below. Support for each +of the driver backends is chosen at wpa_supplicant compile time. For a +list of supported driver backends that may be used with the -D option on +your system, refer to the help output of wpa_supplicant +(\fBwpa_supplicant -h\fR). +.TP +\fBhostap\fR +(default) Host AP driver (Intersil Prism2/2.5/3). +(this can also be used with Linuxant DriverLoader). +.TP +\fBhermes\fR +Agere Systems Inc. driver (Hermes-I/Hermes-II). +.TP +\fBmadwifi\fR +MADWIFI 802.11 support (Atheros, etc.). +.TP +\fBatmel\fR +ATMEL AT76C5XXx (USB, PCMCIA). +.TP +\fBwext\fR +Linux wireless extensions (generic). +.TP +\fBndiswrapper\fR +Linux ndiswrapper. +.TP +\fBbroadcom\fR +Broadcom wl.o driver. +.TP +\fBipw\fR +Intel ipw2100/2200 driver. +.TP +\fBwired\fR +wpa_supplicant wired Ethernet driver +.TP +\fBroboswitch\fR +wpa_supplicant Broadcom switch driver +.TP +\fBbsd\fR +BSD 802.11 support (Atheros, etc.). +.TP +\fBndis\fR +Windows NDIS driver. +.SH "COMMAND LINE OPTIONS" +.PP +Most command line options have global scope. Some are given per +interface, and are only valid if at least one \fB-i\fR option +is specified, otherwise they're ignored. Option groups for different +interfaces must be separated by \fB-N\fR option. +.TP +\fB-b br_ifname\fR +Optional bridge interface name. (Per interface) +.TP +\fB-B\fR +Run daemon in the background. +.TP +\fB-c filename\fR +Path to configuration file. (Per interface) +.TP +\fB-C ctrl_interface\fR +Path to ctrl_interface socket (Per interface. Only used if +\fB-c\fR is not). +.TP +\fB-i ifname\fR +Interface to listen on. Multiple instances of this option can +be present, one per interface, separated by \fB-N\fR +option (see below). +.TP +\fB-d\fR +Increase debugging verbosity (\fB-dd\fR even +more). +.TP +\fB-D driver\fR +Driver to use. (Per interface, see the available options +below.) +.TP +\fB-f output file\fR +Log output to specified file instead of stdout. +.TP +\fB-g global ctrl_interface\fR +Path to global ctrl_interface socket. If specified, interface +definitions may be omitted. +.TP +\fB-K\fR +Include keys (passwords, etc.) in debug output. +.TP +\fB-t\fR +Include timestamp in debug messages. +.TP +\fB-h\fR +Help. Show a usage message. +.TP +\fB-L\fR +Show license (GPL and BSD). +.TP +\fB-p\fR +Driver parameters. (Per interface) +.TP +\fB-P PID_file\fR +Path to PID file. +.TP +\fB-q\fR +Decrease debugging verbosity (\fB-qq\fR even +less). +.TP +\fB-u\fR +Enabled DBus control interface. If enabled, interface +definitions may be omitted. +.TP +\fB-v\fR +Show version. +.TP +\fB-W\fR +Wait for a control interface monitor before starting. +.TP +\fB-N\fR +Start describing new interface. +.SH "EXAMPLES" +.PP +In most common cases, \fBwpa_supplicant\fR is +started with: +.sp +.RS + +.nf +wpa_supplicant -B -c/etc/wpa_supplicant.conf -iwlan0 +.fi +.RE +.PP +This makes the process fork into background. +.PP +The easiest way to debug problems, and to get debug log for +bug reports, is to start \fBwpa_supplicant\fR on +foreground with debugging enabled: +.sp +.RS + +.nf +wpa_supplicant -c/etc/wpa_supplicant.conf -iwlan0 -d +.fi +.RE +.PP +\fBwpa_supplicant\fR can control multiple +interfaces (radios) either by running one process for each +interface separately or by running just one process and list of +options at command line. Each interface is separated with -N +argument. As an example, following command would start +wpa_supplicant for two interfaces: +.sp +.RS + +.nf +wpa_supplicant \\ + -c wpa1.conf -i wlan0 -D hostap -N \\ + -c wpa2.conf -i ath0 -D madwifi +.fi +.RE +.SH "OS REQUIREMENTS" +.PP +Current hardware/software requirements: +.TP 0.2i +\(bu +Linux kernel 2.4.x or 2.6.x with Linux Wireless +Extensions v15 or newer +.TP 0.2i +\(bu +FreeBSD 6-CURRENT +.TP 0.2i +\(bu +Microsoft Windows with WinPcap (at least WinXP, may work +with other versions) +.SH "SUPPORTED DRIVERS" +.TP +\fBHost AP driver for Prism2/2.5/3 (development snapshot/v0.2.x)\fR +(http://hostap.epitest.fi/) Driver needs to be set in +Managed mode (\fBiwconfig wlan0 mode managed\fR). +Please note that station firmware version needs to be 1.7.0 or +newer to work in WPA mode. +.TP +\fBLinuxant DriverLoader\fR +(http://www.linuxant.com/driverloader/) +with Windows NDIS driver for your wlan card supporting WPA. +.TP +\fBAgere Systems Inc. Linux Driver\fR +(http://www.agere.com/support/drivers/) Please note +that the driver interface file (driver_hermes.c) and hardware +specific include files are not included in the wpa_supplicant +distribution. You will need to copy these from the source +package of the Agere driver. +.TP +\fBmadwifi driver for cards based on Atheros chip set (ar521x)\fR +(http://sourceforge.net/projects/madwifi/) Please +note that you will need to modify the wpa_supplicant .config +file to use the correct path for the madwifi driver root +directory (CFLAGS += -I../madwifi/wpa line in example +defconfig). +.TP +\fBATMEL AT76C5XXx driver for USB and PCMCIA cards\fR +(http://atmelwlandriver.sourceforge.net/). +.TP +\fBLinux ndiswrapper\fR +(http://ndiswrapper.sourceforge.net/) with Windows +NDIS driver. +.TP +\fBBroadcom wl.o driver\fR +This is a generic Linux driver for Broadcom IEEE +802.11a/g cards. However, it is proprietary driver that is +not publicly available except for couple of exceptions, mainly +Broadcom-based APs/wireless routers that use Linux. The driver +binary can be downloaded, e.g., from Linksys support site +(http://www.linksys.com/support/gpl.asp) for Linksys +WRT54G. The GPL tarball includes cross-compiler and the needed +header file, wlioctl.h, for compiling wpa_supplicant. This +driver support in wpa_supplicant is expected to work also with +other devices based on Broadcom driver (assuming the driver +includes client mode support). +.TP +\fB Intel ipw2100 driver\fR +(http://sourceforge.net/projects/ipw2100/) +.TP +\fBIntel ipw2200 driver\fR +(http://sourceforge.net/projects/ipw2200/) +.TP +\fBLinux wireless extensions\fR +In theory, any driver that supports Linux wireless +extensions can be used with IEEE 802.1X (i.e., not WPA) when +using ap_scan=0 option in configuration file. +.TP +\fBWired Ethernet drivers\fR +Use ap_scan=0. +.TP +\fBBSD net80211 layer (e.g., Atheros driver)\fR +At the moment, this is for FreeBSD 6-CURRENT branch. +.TP +\fBWindows NDIS\fR +The current Windows port requires WinPcap +(http://winpcap.polito.it/). See README-Windows.txt for more +information. +.PP +wpa_supplicant was designed to be portable for different +drivers and operating systems. Hopefully, support for more wlan +cards and OSes will be added in the future. See developer.txt for +more information about the design of wpa_supplicant and porting to +other drivers. One main goal is to add full WPA/WPA2 support to +Linux wireless extensions to allow new drivers to be supported +without having to implement new driver-specific interface code in +wpa_supplicant. +.SH "ARCHITECTURE" +.PP +The +\fBwpa_supplicant\fR system consists of the following +components: +.TP +\fB\fIwpa_supplicant.conf\fB \fR +the configuration file describing all networks that the +user wants the computer to connect to. +.TP +\fBwpa_supplicant\fR +the program that directly interacts with the +network interface. +.TP +\fBwpa_cli\fR +the +client program that provides a high-level interface to the +functionality of the daemon. +.TP +\fBwpa_passphrase\fR +a utility needed to construct +\fIwpa_supplicant.conf\fR files that include +encrypted passwords. +.SH "QUICK START" +.PP +First, make a configuration file, e.g. +\fI/etc/wpa_supplicant.conf\fR, that describes the networks +you are interested in. See \fBwpa_supplicant.conf\fR(5) +for details. +.PP +Once the configuration is ready, you can test whether the +configuration works by running \fBwpa_supplicant\fR +with following command to start it on foreground with debugging +enabled: +.sp +.RS + +.nf +wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -d + +.fi +.RE +.PP +Assuming everything goes fine, you can start using following +command to start \fBwpa_supplicant\fR on background +without debugging: +.sp +.RS + +.nf +wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -B + +.fi +.RE +.PP +Please note that if you included more than one driver +interface in the build time configuration (.config), you may need +to specify which interface to use by including -D<driver +name> option on the command line. +.SH "INTERFACE TO PCMCIA-CS/CARDMRG" +.PP +For example, following small changes to pcmcia-cs scripts +can be used to enable WPA support: +.PP +Add MODE="Managed" and WPA="y" to the network scheme in +\fI/etc/pcmcia/wireless.opts\fR\&. +.PP +Add the following block to the end of \fBstart\fR +action handler in \fI/etc/pcmcia/wireless\fR: +.sp +.RS + +.nf +if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then + /usr/local/bin/wpa_supplicant -B -c/etc/wpa_supplicant.conf -i$DEVICE +fi + +.fi +.RE +.PP +Add the following block to the end of \fBstop\fR +action handler (may need to be separated from other actions) in +\fI/etc/pcmcia/wireless\fR: +.sp +.RS + +.nf +if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then + killall wpa_supplicant +fi + +.fi +.RE +.PP +This will make \fBcardmgr\fR start +\fBwpa_supplicant\fR when the card is plugged +in. +.SH "SEE ALSO" +.PP +\fBwpa_background\fR(8) +\fBwpa_supplicant.conf\fR(5) +\fBwpa_cli\fR(8) +\fBwpa_passphrase\fR(8) +.SH "LEGAL" +.PP +wpa_supplicant is copyright (c) 2003-2007, +Jouni Malinen <j@w1.fi> and +contributors. +All Rights Reserved. +.PP +This program is dual-licensed under both the GPL version 2 +and BSD license. Either license may be used at your option. diff --git a/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5 b/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5 new file mode 100644 index 000000000000..7a01ea2f5d31 --- /dev/null +++ b/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5 @@ -0,0 +1,225 @@ +.\" This manpage has been automatically generated by docbook2man +.\" from a DocBook document. This tool can be found at: +.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> +.\" Please send any bug reports, improvements, comments, patches, +.\" etc. to Steve Cheng <steve@ggi-project.org>. +.TH "WPA_SUPPLICANT.CONF" "5" "15 February 2009" "" "" + +.SH NAME +wpa_supplicant.conf \- configuration file for wpa_supplicant +.SH "OVERVIEW" +.PP +\fBwpa_supplicant\fR is configured using a text +file that lists all accepted networks and security policies, +including pre-shared keys. See the example configuration file, +probably in \fB/usr/share/doc/wpa_supplicant/\fR, for +detailed information about the configuration format and supported +fields. +.PP +All file paths in this configuration file should use full +(absolute, not relative to working directory) path in order to allow +working directory to be changed. This can happen if wpa_supplicant is +run in the background. +.PP +Changes to configuration file can be reloaded be sending +SIGHUP signal to \fBwpa_supplicant\fR ('killall -HUP +wpa_supplicant'). Similarly, reloading can be triggered with +the \fBwpa_cli reconfigure\fR command. +.PP +Configuration file can include one or more network blocks, +e.g., one for each used SSID. wpa_supplicant will automatically +select the best network based on the order of network blocks in +the configuration file, network security level (WPA/WPA2 is +preferred), and signal strength. +.SH "QUICK EXAMPLES" +.TP 3 +1. +WPA-Personal (PSK) as home network and WPA-Enterprise with +EAP-TLS as work network. +.sp +.RS + +.nf +# allow frontend (e.g., wpa_cli) to be used by all users in 'wheel' group +ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel +# +# home network; allow all valid ciphers +network={ + ssid="home" + scan_ssid=1 + key_mgmt=WPA-PSK + psk="very secret passphrase" +} +# +# work network; use EAP-TLS with WPA; allow only CCMP and TKIP ciphers +network={ + ssid="work" + scan_ssid=1 + key_mgmt=WPA-EAP + pairwise=CCMP TKIP + group=CCMP TKIP + eap=TLS + identity="user@example.com" + ca_cert="/etc/cert/ca.pem" + client_cert="/etc/cert/user.pem" + private_key="/etc/cert/user.prv" + private_key_passwd="password" +} +.fi +.RE +.TP 3 +2. +WPA-RADIUS/EAP-PEAP/MSCHAPv2 with RADIUS servers that +use old peaplabel (e.g., Funk Odyssey and SBR, Meetinghouse +Aegis, Interlink RAD-Series) +.sp +.RS + +.nf +ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel +network={ + ssid="example" + scan_ssid=1 + key_mgmt=WPA-EAP + eap=PEAP + identity="user@example.com" + password="foobar" + ca_cert="/etc/cert/ca.pem" + phase1="peaplabel=0" + phase2="auth=MSCHAPV2" +} +.fi +.RE +.TP 3 +3. +EAP-TTLS/EAP-MD5-Challenge configuration with anonymous +identity for the unencrypted use. Real identity is sent only +within an encrypted TLS tunnel. +.sp +.RS + +.nf +ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel +network={ + ssid="example" + scan_ssid=1 + key_mgmt=WPA-EAP + eap=TTLS + identity="user@example.com" + anonymous_identity="anonymous@example.com" + password="foobar" + ca_cert="/etc/cert/ca.pem" + phase2="auth=MD5" +} +.fi +.RE +.TP 3 +4. +IEEE 802.1X (i.e., no WPA) with dynamic WEP keys +(require both unicast and broadcast); use EAP-TLS for +authentication +.sp +.RS + +.nf +ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel +network={ + ssid="1x-test" + scan_ssid=1 + key_mgmt=IEEE8021X + eap=TLS + identity="user@example.com" + ca_cert="/etc/cert/ca.pem" + client_cert="/etc/cert/user.pem" + private_key="/etc/cert/user.prv" + private_key_passwd="password" + eapol_flags=3 +} +.fi +.RE +.TP 3 +5. +Catch all example that allows more or less all +configuration modes. The configuration options are used based +on what security policy is used in the selected SSID. This is +mostly for testing and is not recommended for normal +use. +.sp +.RS + +.nf +ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel +network={ + ssid="example" + scan_ssid=1 + key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE + pairwise=CCMP TKIP + group=CCMP TKIP WEP104 WEP40 + psk="very secret passphrase" + eap=TTLS PEAP TLS + identity="user@example.com" + password="foobar" + ca_cert="/etc/cert/ca.pem" + client_cert="/etc/cert/user.pem" + private_key="/etc/cert/user.prv" + private_key_passwd="password" + phase1="peaplabel=0" + ca_cert2="/etc/cert/ca2.pem" + client_cert2="/etc/cer/user.pem" + private_key2="/etc/cer/user.prv" + private_key2_passwd="password" +} +.fi +.RE +.TP 3 +6. +Authentication for wired Ethernet. This can be used with +\fBwired\fR or \fBroboswitch\fR interface +(-Dwired or -Droboswitch on command line). +.sp +.RS + +.nf +ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel +ap_scan=0 +network={ + key_mgmt=IEEE8021X + eap=MD5 + identity="user" + password="password" + eapol_flags=0 +} +.fi +.RE +.SH "CERTIFICATES" +.PP +Some EAP authentication methods require use of +certificates. EAP-TLS uses both server side and client +certificates whereas EAP-PEAP and EAP-TTLS only require the server +side certificate. When client certificate is used, a matching +private key file has to also be included in configuration. If the +private key uses a passphrase, this has to be configured in +wpa_supplicant.conf ("private_key_passwd"). +.PP +wpa_supplicant supports X.509 certificates in PEM and DER +formats. User certificate and private key can be included in the +same file. +.PP +If the user certificate and private key is received in +PKCS#12/PFX format, they need to be converted to suitable PEM/DER +format for wpa_supplicant. This can be done, e.g., with following +commands: +.sp +.RS + +.nf +# convert client certificate and private key to PEM format +openssl pkcs12 -in example.pfx -out user.pem -clcerts +# convert CA certificate (if included in PFX file) to PEM format +openssl pkcs12 -in example.pfx -out ca.pem -cacerts -nokeys +.fi +.RE +.SH "SEE ALSO" +.PP +\fBwpa_supplicant\fR(8) +\fBopenssl\fR(1) diff --git a/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml b/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml new file mode 100644 index 000000000000..462039d9ed93 --- /dev/null +++ b/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml @@ -0,0 +1,239 @@ +<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN"> +<refentry> + <refmeta> + <refentrytitle>wpa_supplicant.conf</refentrytitle> + <manvolnum>5</manvolnum> + </refmeta> + <refnamediv> + <refname>wpa_supplicant.conf</refname> + <refpurpose>configuration file for wpa_supplicant</refpurpose> + </refnamediv> + <refsect1> + <title>Overview</title> + + <para><command>wpa_supplicant</command> is configured using a text + file that lists all accepted networks and security policies, + including pre-shared keys. See the example configuration file, + probably in <command>/usr/share/doc/wpa_supplicant/</command>, for + detailed information about the configuration format and supported + fields.</para> + + <para>All file paths in this configuration file should use full + (absolute, not relative to working directory) path in order to allow + working directory to be changed. This can happen if wpa_supplicant is + run in the background.</para> + + <para>Changes to configuration file can be reloaded be sending + SIGHUP signal to <command>wpa_supplicant</command> ('killall -HUP + wpa_supplicant'). Similarly, reloading can be triggered with + the <emphasis>wpa_cli reconfigure</emphasis> command.</para> + + <para>Configuration file can include one or more network blocks, + e.g., one for each used SSID. wpa_supplicant will automatically + select the best network based on the order of network blocks in + the configuration file, network security level (WPA/WPA2 is + preferred), and signal strength.</para> + </refsect1> + + <refsect1> + <title>Quick Examples</title> + + <orderedlist> + <listitem> + + <para>WPA-Personal (PSK) as home network and WPA-Enterprise with + EAP-TLS as work network.</para> + +<blockquote><programlisting> +# allow frontend (e.g., wpa_cli) to be used by all users in 'wheel' group +ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel +# +# home network; allow all valid ciphers +network={ + ssid="home" + scan_ssid=1 + key_mgmt=WPA-PSK + psk="very secret passphrase" +} +# +# work network; use EAP-TLS with WPA; allow only CCMP and TKIP ciphers +network={ + ssid="work" + scan_ssid=1 + key_mgmt=WPA-EAP + pairwise=CCMP TKIP + group=CCMP TKIP + eap=TLS + identity="user@example.com" + ca_cert="/etc/cert/ca.pem" + client_cert="/etc/cert/user.pem" + private_key="/etc/cert/user.prv" + private_key_passwd="password" +} +</programlisting></blockquote> + </listitem> + + <listitem> + <para>WPA-RADIUS/EAP-PEAP/MSCHAPv2 with RADIUS servers that + use old peaplabel (e.g., Funk Odyssey and SBR, Meetinghouse + Aegis, Interlink RAD-Series)</para> + +<blockquote><programlisting> +ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel +network={ + ssid="example" + scan_ssid=1 + key_mgmt=WPA-EAP + eap=PEAP + identity="user@example.com" + password="foobar" + ca_cert="/etc/cert/ca.pem" + phase1="peaplabel=0" + phase2="auth=MSCHAPV2" +} +</programlisting></blockquote> + </listitem> + + <listitem> + <para>EAP-TTLS/EAP-MD5-Challenge configuration with anonymous + identity for the unencrypted use. Real identity is sent only + within an encrypted TLS tunnel.</para> + + +<blockquote><programlisting> +ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel +network={ + ssid="example" + scan_ssid=1 + key_mgmt=WPA-EAP + eap=TTLS + identity="user@example.com" + anonymous_identity="anonymous@example.com" + password="foobar" + ca_cert="/etc/cert/ca.pem" + phase2="auth=MD5" +} +</programlisting></blockquote> + + </listitem> + + <listitem> + <para>IEEE 802.1X (i.e., no WPA) with dynamic WEP keys + (require both unicast and broadcast); use EAP-TLS for + authentication</para> + +<blockquote><programlisting> +ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel +network={ + ssid="1x-test" + scan_ssid=1 + key_mgmt=IEEE8021X + eap=TLS + identity="user@example.com" + ca_cert="/etc/cert/ca.pem" + client_cert="/etc/cert/user.pem" + private_key="/etc/cert/user.prv" + private_key_passwd="password" + eapol_flags=3 +} +</programlisting></blockquote> + </listitem> + + + <listitem> + <para>Catch all example that allows more or less all + configuration modes. The configuration options are used based + on what security policy is used in the selected SSID. This is + mostly for testing and is not recommended for normal + use.</para> + +<blockquote><programlisting> +ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel +network={ + ssid="example" + scan_ssid=1 + key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE + pairwise=CCMP TKIP + group=CCMP TKIP WEP104 WEP40 + psk="very secret passphrase" + eap=TTLS PEAP TLS + identity="user@example.com" + password="foobar" + ca_cert="/etc/cert/ca.pem" + client_cert="/etc/cert/user.pem" + private_key="/etc/cert/user.prv" + private_key_passwd="password" + phase1="peaplabel=0" + ca_cert2="/etc/cert/ca2.pem" + client_cert2="/etc/cer/user.pem" + private_key2="/etc/cer/user.prv" + private_key2_passwd="password" +} +</programlisting></blockquote> + </listitem> + + <listitem> + <para>Authentication for wired Ethernet. This can be used with + <emphasis>wired</emphasis> or <emphasis>roboswitch</emphasis> interface + (-Dwired or -Droboswitch on command line).</para> + +<blockquote><programlisting> +ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel +ap_scan=0 +network={ + key_mgmt=IEEE8021X + eap=MD5 + identity="user" + password="password" + eapol_flags=0 +} +</programlisting></blockquote> + </listitem> + </orderedlist> + + + + + + </refsect1> + <refsect1> + <title>Certificates</title> + + <para>Some EAP authentication methods require use of + certificates. EAP-TLS uses both server side and client + certificates whereas EAP-PEAP and EAP-TTLS only require the server + side certificate. When client certificate is used, a matching + private key file has to also be included in configuration. If the + private key uses a passphrase, this has to be configured in + wpa_supplicant.conf ("private_key_passwd").</para> + + <para>wpa_supplicant supports X.509 certificates in PEM and DER + formats. User certificate and private key can be included in the + same file.</para> + + <para>If the user certificate and private key is received in + PKCS#12/PFX format, they need to be converted to suitable PEM/DER + format for wpa_supplicant. This can be done, e.g., with following + commands:</para> +<blockquote><programlisting> +# convert client certificate and private key to PEM format +openssl pkcs12 -in example.pfx -out user.pem -clcerts +# convert CA certificate (if included in PFX file) to PEM format +openssl pkcs12 -in example.pfx -out ca.pem -cacerts -nokeys +</programlisting></blockquote> + </refsect1> + + <refsect1> + <title>See Also</title> + <para> + <citerefentry> + <refentrytitle>wpa_supplicant</refentrytitle> + <manvolnum>8</manvolnum> + </citerefentry> + <citerefentry> + <refentrytitle>openssl</refentrytitle> + <manvolnum>1</manvolnum> + </citerefentry> + </para> + </refsect1> +</refentry> diff --git a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml new file mode 100644 index 000000000000..9798cedf16a3 --- /dev/null +++ b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml @@ -0,0 +1,818 @@ +<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN"> + +<refentry> + <refmeta> + <refentrytitle>wpa_supplicant</refentrytitle> + <manvolnum>8</manvolnum> + </refmeta> + <refnamediv> + <refname>wpa_supplicant</refname> + <refpurpose>Wi-Fi Protected Access client and IEEE 802.1X supplicant</refpurpose> + </refnamediv> + <refsynopsisdiv> + <cmdsynopsis> + <command>wpa_supplicant</command> + <arg>-BddfhKLqqtuvW</arg> + <arg>-i<replaceable>ifname</replaceable></arg> + <arg>-c<replaceable>config file</replaceable></arg> + <arg>-D<replaceable>driver</replaceable></arg> + <arg>-P<replaceable>PID_file</replaceable></arg> + <arg>-f<replaceable>output file</replaceable></arg> + </cmdsynopsis> + </refsynopsisdiv> + <refsect1> + <title>Overview</title> + + <para> + Wireless networks do not require physical access to the network equipment + in the same way as wired networks. This makes it easier for unauthorized + users to passively monitor a network and capture all transmitted frames. + In addition, unauthorized use of the network is much easier. In many cases, + this can happen even without user's explicit knowledge since the wireless + LAN adapter may have been configured to automatically join any available + network. + </para> + + <para> + Link-layer encryption can be used to provide a layer of security for + wireless networks. The original wireless LAN standard, IEEE 802.11, + included a simple encryption mechanism, WEP. However, that proved to + be flawed in many areas and network protected with WEP cannot be consider + secure. IEEE 802.1X authentication and frequently changed dynamic WEP keys + can be used to improve the network security, but even that has inherited + security issues due to the use of WEP for encryption. Wi-Fi Protected + Access and IEEE 802.11i amendment to the wireless LAN standard introduce + a much improvement mechanism for securing wireless networks. IEEE 802.11i + enabled networks that are using CCMP (encryption mechanism based on strong + cryptographic algorithm AES) can finally be called secure used for + applications which require efficient protection against unauthorized + access. + </para> + + <para><command>wpa_supplicant</command> is an implementation of + the WPA Supplicant component, i.e., the part that runs in the + client stations. It implements WPA key negotiation with a WPA + Authenticator and EAP authentication with Authentication + Server. In addition, it controls the roaming and IEEE 802.11 + authentication/association of the wireless LAN driver.</para> + + <para><command>wpa_supplicant</command> is designed to be a + "daemon" program that runs in the background and acts as the + backend component controlling the wireless + connection. <command>wpa_supplicant</command> supports separate + frontend programs and an example text-based frontend, + <command>wpa_cli</command>, is included with + wpa_supplicant.</para> + + <para>Before wpa_supplicant can do its work, the network interface + must be available. That means that the physical device must be + present and enabled, and the driver for the device must be + loaded. The daemon will exit immediately if the device is not already + available.</para> + + <para>After <command>wpa_supplicant</command> has configured the + network device, higher level configuration such as DHCP may + proceed. There are a variety of ways to integrate wpa_supplicant + into a machine's networking scripts, a few of which are described + in sections below.</para> + + <para>The following steps are used when associating with an AP + using WPA:</para> + + <itemizedlist> + <listitem> + <para><command>wpa_supplicant</command> requests the kernel + driver to scan neighboring BSSes</para> + </listitem> + + <listitem> + <para><command>wpa_supplicant</command> selects a BSS based on + its configuration</para> + </listitem> + + <listitem> + <para><command>wpa_supplicant</command> requests the kernel + driver to associate with the chosen BSS</para> + </listitem> + + <listitem> + <para>If WPA-EAP: integrated IEEE 802.1X Supplicant + completes EAP authentication with the + authentication server (proxied by the Authenticator in the + AP)</para> + </listitem> + + <listitem> + <para>If WPA-EAP: master key is received from the IEEE 802.1X + Supplicant</para> + </listitem> + + <listitem> + <para>If WPA-PSK: <command>wpa_supplicant</command> uses PSK + as the master session key</para> + </listitem> + + <listitem> + <para><command>wpa_supplicant</command> completes WPA 4-Way + Handshake and Group Key Handshake with the Authenticator + (AP)</para> + </listitem> + + <listitem> + <para><command>wpa_supplicant</command> configures encryption + keys for unicast and broadcast</para> + </listitem> + + <listitem> + <para>normal data packets can be transmitted and received</para> + </listitem> + </itemizedlist> + </refsect1> + + <refsect1> + <title>Supported Features</title> + <para>Supported WPA/IEEE 802.11i features:</para> + <itemizedlist> + <listitem> + <para>WPA-PSK ("WPA-Personal")</para> + </listitem> + + <listitem> + <para>WPA with EAP (e.g., with RADIUS authentication server) + ("WPA-Enterprise") Following authentication methods are + supported with an integrate IEEE 802.1X Supplicant:</para> + + <itemizedlist> + <listitem> + <para>EAP-TLS</para> + </listitem> + </itemizedlist> + + <itemizedlist> + <listitem> + <para>EAP-PEAP/MSCHAPv2 (both PEAPv0 and PEAPv1)</para> + </listitem> + + + <listitem> + <para>EAP-PEAP/TLS (both PEAPv0 and PEAPv1)</para> + </listitem> + + <listitem> + <para>EAP-PEAP/GTC (both PEAPv0 and PEAPv1)</para> + </listitem> + + <listitem> + <para>EAP-PEAP/OTP (both PEAPv0 and PEAPv1)</para> + </listitem> + + <listitem> + <para>EAP-PEAP/MD5-Challenge (both PEAPv0 and PEAPv1)</para> + </listitem> + + <listitem> + <para>EAP-TTLS/EAP-MD5-Challenge</para> + </listitem> + + <listitem> + <para>EAP-TTLS/EAP-GTC</para> + </listitem> + + <listitem><para>EAP-TTLS/EAP-OTP</para></listitem> + + <listitem><para>EAP-TTLS/EAP-MSCHAPv2</para></listitem> + + <listitem><para>EAP-TTLS/EAP-TLS</para></listitem> + + <listitem><para>EAP-TTLS/MSCHAPv2</para></listitem> + + <listitem><para>EAP-TTLS/MSCHAP</para></listitem> + + <listitem><para>EAP-TTLS/PAP</para></listitem> + + <listitem><para>EAP-TTLS/CHAP</para></listitem> + + <listitem><para>EAP-SIM</para></listitem> + + <listitem><para>EAP-AKA</para></listitem> + + <listitem><para>EAP-PSK</para></listitem> + + <listitem><para>EAP-PAX</para></listitem> + + <listitem><para>LEAP (note: requires special support from + the driver for IEEE 802.11 authentication)</para></listitem> + + <listitem><para>(following methods are supported, but since + they do not generate keying material, they cannot be used + with WPA or IEEE 802.1X WEP keying)</para></listitem> + + <listitem><para>EAP-MD5-Challenge </para></listitem> + + <listitem><para>EAP-MSCHAPv2</para></listitem> + + <listitem><para>EAP-GTC</para></listitem> + + <listitem><para>EAP-OTP</para></listitem> + </itemizedlist> + </listitem> + + <listitem> + <para>key management for CCMP, TKIP, WEP104, WEP40</para> + </listitem> + + <listitem> + <para>RSN/WPA2 (IEEE 802.11i)</para> + <itemizedlist> + <listitem> + <para>pre-authentication</para> + </listitem> + + <listitem> + <para>PMKSA caching</para> + </listitem> + </itemizedlist> + </listitem> + </itemizedlist> + </refsect1> + + <refsect1> + <title>Available Drivers</title> + <para>A summary of available driver backends is below. Support for each + of the driver backends is chosen at wpa_supplicant compile time. For a + list of supported driver backends that may be used with the -D option on + your system, refer to the help output of wpa_supplicant + (<emphasis>wpa_supplicant -h</emphasis>).</para> + + <variablelist> + <varlistentry> + <term>hostap</term> + <listitem> + <para>(default) Host AP driver (Intersil Prism2/2.5/3). + (this can also be used with Linuxant DriverLoader).</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>hermes</term> + <listitem> + <para>Agere Systems Inc. driver (Hermes-I/Hermes-II).</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>madwifi</term> + <listitem> + <para>MADWIFI 802.11 support (Atheros, etc.).</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>atmel</term> + <listitem> + <para>ATMEL AT76C5XXx (USB, PCMCIA).</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>wext</term> + <listitem> + <para>Linux wireless extensions (generic).</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>ndiswrapper</term> + <listitem> + <para>Linux ndiswrapper.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>broadcom</term> + <listitem> + <para>Broadcom wl.o driver.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>ipw</term> + <listitem> + <para>Intel ipw2100/2200 driver.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>wired</term> + <listitem> + <para>wpa_supplicant wired Ethernet driver</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>roboswitch</term> + <listitem> + <para>wpa_supplicant Broadcom switch driver</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>bsd</term> + <listitem> + <para>BSD 802.11 support (Atheros, etc.).</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>ndis</term> + <listitem> + <para>Windows NDIS driver.</para> + </listitem> + </varlistentry> + </variablelist> + </refsect1> + + <refsect1> + <title>Command Line Options</title> + <para>Most command line options have global scope. Some are given per + interface, and are only valid if at least one <option>-i</option> option + is specified, otherwise they're ignored. Option groups for different + interfaces must be separated by <option>-N</option> option.</para> + <variablelist> + <varlistentry> + <term>-b br_ifname</term> + <listitem> + <para>Optional bridge interface name. (Per interface)</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>-B</term> + <listitem> + <para>Run daemon in the background.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>-c filename</term> + <listitem> + <para>Path to configuration file. (Per interface)</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>-C ctrl_interface</term> + <listitem> + <para>Path to ctrl_interface socket (Per interface. Only used if + <option>-c</option> is not).</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>-i ifname</term> + <listitem> + <para>Interface to listen on. Multiple instances of this option can + be present, one per interface, separated by <option>-N</option> + option (see below).</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>-d</term> + <listitem> + <para>Increase debugging verbosity (<option>-dd</option> even + more).</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>-D driver</term> + <listitem> + <para>Driver to use. (Per interface, see the available options + below.)</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>-f output file</term> + <listitem> + <para>Log output to specified file instead of stdout.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>-g global ctrl_interface</term> + <listitem> + <para>Path to global ctrl_interface socket. If specified, interface + definitions may be omitted.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>-K</term> + <listitem> + <para>Include keys (passwords, etc.) in debug output.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>-t</term> + <listitem> + <para>Include timestamp in debug messages.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>-h</term> + <listitem> + <para>Help. Show a usage message.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>-L</term> + <listitem> + <para>Show license (GPL and BSD).</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>-p</term> + <listitem> + <para>Driver parameters. (Per interface)</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>-P PID_file</term> + <listitem> + <para>Path to PID file.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>-q</term> + <listitem> + <para>Decrease debugging verbosity (<option>-qq</option> even + less).</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>-u</term> + <listitem> + <para>Enabled DBus control interface. If enabled, interface + definitions may be omitted.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>-v</term> + <listitem> + <para>Show version.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>-W</term> + <listitem> + <para>Wait for a control interface monitor before starting.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>-N</term> + <listitem> + <para>Start describing new interface.</para> + </listitem> + </varlistentry> + </variablelist> + </refsect1> + + <refsect1> + <title>Examples</title> + + <para>In most common cases, <command>wpa_supplicant</command> is + started with:</para> + +<blockquote><programlisting> +wpa_supplicant -B -c/etc/wpa_supplicant.conf -iwlan0 +</programlisting></blockquote> + + <para>This makes the process fork into background.</para> + + <para>The easiest way to debug problems, and to get debug log for + bug reports, is to start <command>wpa_supplicant</command> on + foreground with debugging enabled:</para> + +<blockquote><programlisting> +wpa_supplicant -c/etc/wpa_supplicant.conf -iwlan0 -d +</programlisting></blockquote> + + <para><command>wpa_supplicant</command> can control multiple + interfaces (radios) either by running one process for each + interface separately or by running just one process and list of + options at command line. Each interface is separated with -N + argument. As an example, following command would start + wpa_supplicant for two interfaces:</para> + +<blockquote><programlisting> +wpa_supplicant \ + -c wpa1.conf -i wlan0 -D hostap -N \ + -c wpa2.conf -i ath0 -D madwifi +</programlisting></blockquote> + </refsect1> + + <refsect1> + <title>OS Requirements</title> + <para>Current hardware/software requirements:</para> + + <itemizedlist> + <listitem> + <para>Linux kernel 2.4.x or 2.6.x with Linux Wireless + Extensions v15 or newer</para> + </listitem> + + + <listitem> + <para>FreeBSD 6-CURRENT</para> + </listitem> + + <listitem> + <para>Microsoft Windows with WinPcap (at least WinXP, may work + with other versions)</para> + </listitem> + </itemizedlist> + </refsect1> + + <refsect1> + <title>Supported Drivers</title> + <variablelist> + <varlistentry> + <term>Host AP driver for Prism2/2.5/3 (development + snapshot/v0.2.x)</term> + <listitem> + <para> (http://hostap.epitest.fi/) Driver needs to be set in + Managed mode (<emphasis>iwconfig wlan0 mode managed</emphasis>). + Please note that station firmware version needs to be 1.7.0 or + newer to work in WPA mode.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>Linuxant DriverLoader</term> + <listitem> + <para>(http://www.linuxant.com/driverloader/) + with Windows NDIS driver for your wlan card supporting WPA.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>Agere Systems Inc. Linux Driver</term> + <listitem> + <para> (http://www.agere.com/support/drivers/) Please note + that the driver interface file (driver_hermes.c) and hardware + specific include files are not included in the wpa_supplicant + distribution. You will need to copy these from the source + package of the Agere driver.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>madwifi driver for cards based on Atheros chip set (ar521x)</term> + <listitem> + <para> (http://sourceforge.net/projects/madwifi/) Please + note that you will need to modify the wpa_supplicant .config + file to use the correct path for the madwifi driver root + directory (CFLAGS += -I../madwifi/wpa line in example + defconfig).</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>ATMEL AT76C5XXx driver for USB and PCMCIA cards</term> + <listitem> + <para> (http://atmelwlandriver.sourceforge.net/).</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>Linux ndiswrapper</term> + <listitem> + <para> (http://ndiswrapper.sourceforge.net/) with Windows + NDIS driver.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>Broadcom wl.o driver</term> + <listitem> + <para> This is a generic Linux driver for Broadcom IEEE + 802.11a/g cards. However, it is proprietary driver that is + not publicly available except for couple of exceptions, mainly + Broadcom-based APs/wireless routers that use Linux. The driver + binary can be downloaded, e.g., from Linksys support site + (http://www.linksys.com/support/gpl.asp) for Linksys + WRT54G. The GPL tarball includes cross-compiler and the needed + header file, wlioctl.h, for compiling wpa_supplicant. This + driver support in wpa_supplicant is expected to work also with + other devices based on Broadcom driver (assuming the driver + includes client mode support).</para> + </listitem> + </varlistentry> + + <varlistentry> + <term> Intel ipw2100 driver</term> + <listitem> + <para> (http://sourceforge.net/projects/ipw2100/)</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>Intel ipw2200 driver</term> + <listitem> + <para> (http://sourceforge.net/projects/ipw2200/)</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>Linux wireless extensions</term> + <listitem> + <para>In theory, any driver that supports Linux wireless + extensions can be used with IEEE 802.1X (i.e., not WPA) when + using ap_scan=0 option in configuration file.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>Wired Ethernet drivers</term> + <listitem> + <para>Use ap_scan=0.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>BSD net80211 layer (e.g., Atheros driver)</term> + <listitem> + <para>At the moment, this is for FreeBSD 6-CURRENT branch.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>Windows NDIS</term> + <listitem> + <para>The current Windows port requires WinPcap + (http://winpcap.polito.it/). See README-Windows.txt for more + information.</para> + </listitem> + </varlistentry> + </variablelist> + + + <para>wpa_supplicant was designed to be portable for different + drivers and operating systems. Hopefully, support for more wlan + cards and OSes will be added in the future. See developer.txt for + more information about the design of wpa_supplicant and porting to + other drivers. One main goal is to add full WPA/WPA2 support to + Linux wireless extensions to allow new drivers to be supported + without having to implement new driver-specific interface code in + wpa_supplicant.</para> + </refsect1> + + <refsect1> + <title>Architecture</title> <para>The + <command>wpa_supplicant</command> system consists of the following + components:</para> + + <variablelist> + <varlistentry> + <term><filename>wpa_supplicant.conf</filename> </term> + <listitem> + <para>the configuration file describing all networks that the + user wants the computer to connect to. </para> + </listitem> + </varlistentry> + <varlistentry> + <term><command>wpa_supplicant</command></term> + <listitem><para>the program that directly interacts with the + network interface. </para></listitem> + </varlistentry> + <varlistentry> + <term><command>wpa_cli</command></term> <listitem><para> the + client program that provides a high-level interface to the + functionality of the daemon. </para></listitem> + </varlistentry> + <varlistentry> + <term><command>wpa_passphrase</command></term> + <listitem><para>a utility needed to construct + <filename>wpa_supplicant.conf</filename> files that include + encrypted passwords.</para></listitem> + </varlistentry> + </variablelist> + </refsect1> + + <refsect1> + <title>Quick Start</title> + + <para>First, make a configuration file, e.g. + <filename>/etc/wpa_supplicant.conf</filename>, that describes the networks + you are interested in. See <citerefentry> + <refentrytitle>wpa_supplicant.conf</refentrytitle> + <manvolnum>5</manvolnum> + </citerefentry> + for details.</para> + + <para>Once the configuration is ready, you can test whether the + configuration works by running <command>wpa_supplicant</command> + with following command to start it on foreground with debugging + enabled:</para> + + <blockquote><programlisting> +wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -d + </programlisting></blockquote> + + <para>Assuming everything goes fine, you can start using following + command to start <command>wpa_supplicant</command> on background + without debugging:</para> + + <blockquote><programlisting> +wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -B + </programlisting></blockquote> + + <para>Please note that if you included more than one driver + interface in the build time configuration (.config), you may need + to specify which interface to use by including -D<driver + name> option on the command line.</para> + + <!-- XXX at this point, the page could include a little script + based on wpa_cli to wait for a connection and then run + dhclient --> + + </refsect1> + + <refsect1> + <title>Interface to pcmcia-cs/cardmrg</title> + + <para>For example, following small changes to pcmcia-cs scripts + can be used to enable WPA support:</para> + + <para>Add MODE="Managed" and WPA="y" to the network scheme in + <filename>/etc/pcmcia/wireless.opts</filename>.</para> + + <para>Add the following block to the end of <emphasis>start</emphasis> + action handler in <filename>/etc/pcmcia/wireless</filename>:</para> + + <blockquote><programlisting> +if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then + /usr/local/bin/wpa_supplicant -B -c/etc/wpa_supplicant.conf -i$DEVICE +fi + </programlisting></blockquote> + + + <para>Add the following block to the end of <emphasis>stop</emphasis> + action handler (may need to be separated from other actions) in + <filename>/etc/pcmcia/wireless</filename>:</para> + + <blockquote><programlisting> +if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then + killall wpa_supplicant +fi + </programlisting></blockquote> + + <para>This will make <command>cardmgr</command> start + <command>wpa_supplicant</command> when the card is plugged + in.</para> + </refsect1> + + <refsect1> + <title>See Also</title> + <para> + <citerefentry> + <refentrytitle>wpa_background</refentrytitle> + <manvolnum>8</manvolnum> + </citerefentry> + <citerefentry> + <refentrytitle>wpa_supplicant.conf</refentrytitle> + <manvolnum>5</manvolnum> + </citerefentry> + <citerefentry> + <refentrytitle>wpa_cli</refentrytitle> + <manvolnum>8</manvolnum> + </citerefentry> + <citerefentry> + <refentrytitle>wpa_passphrase</refentrytitle> + <manvolnum>8</manvolnum> + </citerefentry> + </para> + </refsect1> + <refsect1> + <title>Legal</title> + <para>wpa_supplicant is copyright (c) 2003-2007, + Jouni Malinen <email>j@w1.fi</email> and + contributors. + All Rights Reserved.</para> + + <para>This program is dual-licensed under both the GPL version 2 + and BSD license. Either license may be used at your option.</para> + </refsect1> +</refentry> diff --git a/wpa_supplicant/doc/doxygen.fast b/wpa_supplicant/doc/doxygen.fast new file mode 100644 index 000000000000..c6012a9c91ec --- /dev/null +++ b/wpa_supplicant/doc/doxygen.fast @@ -0,0 +1,239 @@ +# Doxyfile 1.4.4 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = wpa_supplicant +PROJECT_NUMBER = 0.6.x +OUTPUT_DIRECTORY = wpa_supplicant/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 = wpa_supplicant \ + src/common \ + src/crypto \ + src/drivers \ + src/eap_common \ + src/eapol_supp \ + src/eap_peer \ + src/l2_packet \ + src/rsn_supp \ + src/tls \ + src/utils \ + src/wps +FILE_PATTERNS = *.c *.h *.cpp *.m *.doxygen +RECURSIVE = YES +EXCLUDE = wpa_supplicant/wpa_gui +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = */.moc/* */.ui/* +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = wpa_supplicant/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 = IEEE8021X_EAPOL CONFIG_CTRL_IFACE +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/wpa_supplicant/doc/doxygen.full b/wpa_supplicant/doc/doxygen.full new file mode 100644 index 000000000000..6884c62771d0 --- /dev/null +++ b/wpa_supplicant/doc/doxygen.full @@ -0,0 +1,239 @@ +# Doxyfile 1.4.4 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = wpa_supplicant +PROJECT_NUMBER = 0.6.x +OUTPUT_DIRECTORY = wpa_supplicant/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 = wpa_supplicant \ + src/common \ + src/crypto \ + src/drivers \ + src/eap_common \ + src/eapol_supp \ + src/eap_peer \ + src/l2_packet \ + src/rsn_supp \ + src/tls \ + src/utils \ + src/wps +FILE_PATTERNS = *.c *.h *.cpp *.m *.doxygen +RECURSIVE = YES +EXCLUDE = wpa_supplicant/wpa_gui +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = */.moc/* */.ui/* +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = wpa_supplicant/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 = IEEE8021X_EAPOL CONFIG_CTRL_IFACE +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/wpa_supplicant/doc/driver_wrapper.doxygen b/wpa_supplicant/doc/driver_wrapper.doxygen new file mode 100644 index 000000000000..28aea50d2ab4 --- /dev/null +++ b/wpa_supplicant/doc/driver_wrapper.doxygen @@ -0,0 +1,180 @@ +/** +\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 %wpa_supplicant 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. + +A driver wrapper needs to implement some or all of the functions +defined in driver.h. These functions are registered by filling struct +wpa_driver_ops with function pointers. Hardware independent parts of +%wpa_supplicant will call these functions to control the driver/wlan +card. In addition, support for driver events is required. The event +callback function, wpa_supplicant_event(), and its parameters are +documented in driver.h. In addition, a pointer to the 'struct +wpa_driver_ops' needs to be registered in drivers.c file. + +When porting to other operating systems, the driver wrapper should be +modified to use the native interface of the target OS. It is possible +that some extra requirements for the interface between the driver +wrapper and generic %wpa_supplicant code are discovered during porting +to a new operating system. These will be addressed on case by case +basis by modifying the interface and updating the other driver +wrappers for this. The goal is to avoid changing this interface +without very good reasons in order to limit the number of changes +needed to other wrappers and hardware independent parts of +%wpa_supplicant. When changes are required, recommended way is to +make them in backwards compatible way that allows existing driver +interface implementations to be compiled without any modification. + +Generic Linux Wireless Extensions functions are implemented in +driver_wext.c. All Linux driver wrappers can use these when the kernel +driver supports the generic ioctl()s and wireless events. Driver +specific functions are implemented in separate C files, e.g., +driver_hostap.c. These files need to define struct wpa_driver_ops +entry that will be used in wpa_supplicant.c when calling driver +functions. struct wpa_driver_ops entries are registered in drivers.c. + +In general, it is likely to be useful to first take a look at couple +of driver interface examples before starting on implementing a new +one. driver_hostap.c and driver_wext.c include a complete +implementation for Linux drivers that use %wpa_supplicant-based control +of WPA IE and roaming. driver_ndis.c (with help from driver_ndis_.c) +is an example of a complete interface for Windows NDIS interface for +drivers that generate WPA IE themselves and decide when to roam. These +example implementations include full support for all security modes. + + +\section driver_req Driver requirements for WPA + +WPA introduces new requirements for the device driver. At least some +of these need to be implemented in order to provide enough support for +%wpa_supplicant. + +\subsection driver_tkip_ccmp TKIP/CCMP + +WPA requires that the pairwise cipher suite (encryption algorithm for +unicast data packets) is TKIP or CCMP. These are new encryption +protocols and thus, the driver will need to be modified to support +them. Depending on the used wlan hardware, some parts of these may be +implemented by the hardware/firmware. + +Specification for both TKIP and CCMP is available from IEEE (IEEE +802.11i amendment). Fully functional, hardware independent +implementation of both encryption protocols is also available in Host +AP driver (driver/modules/hostap_{tkip,ccmp}.c). In addition, Linux 2.6 +kernel tree has generic implementations for WEP, TKIP, and CCMP that can +be used in Linux drivers. + +The driver will also need to provide configuration mechanism to allow +user space programs to configure TKIP and CCMP. Linux Wireless Extensions +v18 added support for configuring these algorithms and +individual/non-default keys. If the target kernel does not include WE-18, +private ioctls can be used to provide similar functionality. + +\subsection driver_roaming Roaming control and scanning support + +%wpa_supplicant can optionally control AP selection based on the +information received from Beacon and/or Probe Response frames +(ap_scan=1 mode in configuration). This means that the driver should +support external control for scan process. In case of Linux, use of +new Wireless Extensions scan support (i.e., 'iwlist wlan0 scan') is +recommended. The current driver wrapper (driver_wext.c) uses this for +scan results. + +Scan results must also include the WPA information element. Support for +this was added in WE-18. With older versions, a custom event can be used +to provide the full WPA IE (including element id and length) as a hex +string that is included in the scan results. + +%wpa_supplicant needs to also be able to request the driver to +associate with a specific BSS. Current Host AP driver and matching +driver_hostap.c wrapper uses following sequence for this +request. Similar/identical mechanism should be usable also with other +drivers. + +- set WPA IE for AssocReq with private ioctl +- set SSID with SIOCSIWESSID +- set channel/frequency with SIOCSIWFREQ +- set BSSID with SIOCSIWAP + (this last ioctl will trigger the driver to request association) + +\subsection driver_wpa_ie WPA IE generation + +%wpa_supplicant selects which cipher suites and key management suites +are used. Based on this information, it generates a WPA IE. This is +provided to the driver interface in the associate call. This does not +match with Windows NDIS drivers which generate the WPA IE +themselves. + +%wpa_supplicant allows Windows NDIS-like behavior by providing the +selected cipher and key management suites in the associate call. If +the driver generates its own WPA IE and that differs from the one +generated by %wpa_supplicant, the driver has to inform %wpa_supplicant +about the used WPA IE (i.e., the one it used in (Re)Associate +Request). This notification is done using EVENT_ASSOCINFO event (see +driver.h). %wpa_supplicant is normally configured to use +ap_scan=2 mode with drivers that control WPA IE generation and roaming. + +\subsection driver_events Driver events + +%wpa_supplicant needs to receive event callbacks when certain events +occur (association, disassociation, Michael MIC failure, scan results +available, PMKSA caching candidate). These events and the callback +details are defined in driver.h (wpa_supplicant_event() function +and enum wpa_event_type). + +On Linux, association and disassociation can use existing Wireless +Extensions event that is reporting new AP with SIOCGIWAP +event. Similarly, completion of a scan can be reported with SIOCGIWSCAN +event. + +Michael MIC failure event was added in WE-18. Older versions of Wireless +Extensions will need to use a custom event. Host AP driver used a custom +event with following contents: MLME-MICHAELMICFAILURE.indication(keyid=# +broadcast/unicast addr=addr2). This is the recommended format until +the driver can be moved to use WE-18 mechanism. + +\subsection driver_wext_summary Summary of Linux Wireless Extensions use + +AP selection depends on ap_scan configuration: + +ap_scan=1: + +- %wpa_supplicant requests scan with SIOCSIWSCAN +- driver reports scan complete with wireless event SIOCGIWSCAN +- %wpa_supplicant reads scan results with SIOCGIWSCAN (multiple call if + a larget buffer is needed) +- %wpa_supplicant decides which AP to use based on scan results +- %wpa_supplicant configures driver to associate with the selected BSS + (SIOCSIWMODE, SIOCSIWGENIE, SIOCSIWAUTH, SIOCSIWFREQ, + SIOCSIWESSID, SIOCSIWAP) + +ap_scan=2: + +- %wpa_supplicant configures driver to associate with an SSID + (SIOCSIWMODE, SIOCSIWGENIE, SIOCSIWAUTH, SIOCSIWESSID) + + +After this, both modes use similar steps: + +- optionally (or required for drivers that generate WPA/RSN IE for + (Re)AssocReq), driver reports association parameters (AssocReq IEs) + with wireless event IWEVASSOCREQIE (and optionally IWEVASSOCRESPIE) +- driver reports association with wireless event SIOCGIWAP +- %wpa_supplicant takes care of EAPOL frame handling (validating + information from associnfo and if needed, from scan results if WPA/RSN + IE from the Beacon frame is not reported through associnfo) +*/ diff --git a/wpa_supplicant/doc/eap.doxygen b/wpa_supplicant/doc/eap.doxygen new file mode 100644 index 000000000000..0646128a8598 --- /dev/null +++ b/wpa_supplicant/doc/eap.doxygen @@ -0,0 +1,87 @@ +/** +\page eap_module EAP peer implementation + +Extensible Authentication Protocol (EAP) is an authentication framework +defined in RFC 3748. %wpa_supplicant uses a separate code module for EAP +peer 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 peer state +machine and methods. As such, this RFC provides useful information for +understanding the EAP peer implementation in %wpa_supplicant. + +Some of the terminology used in EAP state machine is referring to +EAPOL (IEEE 802.1X), but there is no strict requirement on the lower +layer being IEEE 802.1X if EAP module is built for other programs than +%wpa_supplicant. These terms should be understood to refer to the +lower layer as defined in RFC 4137. + + +\section adding_eap_methods Adding EAP methods + +Each EAP method is implemented as a separate module, usually as one C +file named eap_<name of the method>.c, e.g., eap_md5.c. All EAP +methods use the same interface between the peer 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_peer_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_peer_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. + + +\section used_eap_library Using EAP implementation as a library + +The Git repository has an eap_example directory that contains an +example showing how EAP peer and server code from %wpa_supplicant and +hostapd can be used as a library. The example program initializes both +an EAP server and an EAP peer entities and then runs through an +EAP-PEAP/MSCHAPv2 authentication. + +eap_example_peer.c shows the initialization and glue code needed to +control the EAP peer implementation. eap_example_server.c does the +same for EAP server. eap_example.c is an example that ties in both the +EAP server and client parts to allow an EAP authentication to be +shown. + +In this example, the EAP messages are passed between the server and +the peer are passed by direct function calls within the same process. +In practice, server and peer functionalities would likely reside in +separate devices and the EAP messages would be transmitted between the +devices based on an external protocol. For example, in IEEE 802.11 +uses IEEE 802.1X EAPOL state machines to control the transmission of +EAP messages and WiMax supports optional PMK EAP authentication +mechanism that transmits EAP messages as defined in IEEE 802.16e. + +The EAP library links in number of helper functions from src/utils and +src/crypto directories. Most of these are suitable as-is, but it may +be desirable to replace the debug output code in src/utils/wpa_debug.c +by dropping this file from the library and re-implementing the +functions there in a way that better fits in with the main +application. + +*/ diff --git a/wpa_supplicant/doc/kerneldoc2doxygen.pl b/wpa_supplicant/doc/kerneldoc2doxygen.pl new file mode 100755 index 000000000000..61bc367b4964 --- /dev/null +++ b/wpa_supplicant/doc/kerneldoc2doxygen.pl @@ -0,0 +1,134 @@ +#!/usr/bin/perl -w +# +########################################################################## +# Convert kernel-doc style comments to Doxygen comments. +########################################################################## +# +# This script reads a C source file from stdin, and writes +# to stdout. Normal usage: +# +# $ mv file.c file.c.gtkdoc +# $ kerneldoc2doxygen.pl <file.c.gtkdoc >file.c +# +# Or to do the same thing with multiple files: +# $ perl -i.gtkdoc kerneldoc2doxygen.pl *.c *.h +# +# This script may also be suitable for use as a Doxygen input filter, +# but that has not been tested. +# +# Back up your source files before using this script!! +# +########################################################################## +# Copyright (C) 2003 Jonathan Foster <jon@jon-foster.co.uk> +# Copyright (C) 2005-2008 Jouni Malinen <j@w1.fi> +# (modified for kerneldoc format used in wpa_supplicant) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# or look at http://www.gnu.org/licenses/gpl.html +########################################################################## + + +########################################################################## +# +# This function converts a single comment from gtk-doc to Doxygen format. +# The parameter does not include the opening or closing lines +# (i.e. given a comment like this: +# "/**\n" +# " * FunctionName:\n" +# " * @foo: This describes the foo parameter\n" +# " * @bar: This describes the bar parameter\n" +# " * @Returns: This describes the return value\n" +# " *\n" +# " * This describes the function.\n" +# " */\n" +# This function gets: +# " * FunctionName:\n" +# " * @foo: This describes the foo parameter\n" +# " * @bar: This describes the bar parameter\n" +# " * @Returns: This describes the return value\n" +# " *\n" +# " * This describes the function.\n" +# And it returns: +# " * This describes the function.\n" +# " *\n" +# " * @param foo This describes the foo parameter\n" +# " * @param bar This describes the bar parameter\n" +# " * @return This describes the return value\n" +# ) +# +sub fixcomment { + $t = $_[0]; + + # wpa_supplicant -> %wpa_supplicant except for struct wpa_supplicant + $t =~ s/struct wpa_supplicant/struct STRUCTwpa_supplicant/sg; + $t =~ s/ wpa_supplicant/ \%wpa_supplicant/sg; + $t =~ s/struct STRUCTwpa_supplicant/struct wpa_supplicant/sg; + + # " * 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/wpa_supplicant/doc/mainpage.doxygen b/wpa_supplicant/doc/mainpage.doxygen new file mode 100644 index 000000000000..ed63f27e970d --- /dev/null +++ b/wpa_supplicant/doc/mainpage.doxygen @@ -0,0 +1,56 @@ +/** +\mainpage Developers' documentation for wpa_supplicant + +%wpa_supplicant is a WPA Supplicant for Linux, BSD and Windows with +support for WPA and WPA2 (IEEE 802.11i / RSN). Supplicant is the IEEE +802.1X/WPA component that is used in the client stations. It +implements key negotiation with a WPA Authenticator and it can optionally +control roaming and IEEE 802.11 authentication/association of the wlan +driver. + +The goal of this documentation and comments in the source code is to +give enough information for other developers to understand how +%wpa_supplicant has been implemented, how it can be modified, how new +drivers can be supported, and how %wpa_supplicant can be ported to +other operating systems. If any information is missing, feel free to +contact Jouni Malinen <j@w1.fi> for more +information. Contributions as patch files are also very welcome at the +same address. Please note that %wpa_supplicant is licensed under dual +license, GPLv2 or BSD at user's choice. All contributions to +%wpa_supplicant are expected to use compatible licensing terms. + +The source code and read-only access to %wpa_supplicant Git repository +is available from the project home page at +http://w1.fi/wpa_supplicant/. This developers' documentation +is also available as a PDF file from +http://w1.fi/wpa_supplicant/wpa_supplicant-devel.pdf . + +The design goal for %wpa_supplicant 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 peer implementation". +In addition to programs aimed at normal production use, +%wpa_supplicant source tree includes number of \ref testing_tools +"testing and development tools" that make it easier to test the +programs without having to setup a full test setup with wireless +cards. These tools can also be used to implement automatic test +suites. + +%wpa_supplicant implements a +\ref ctrl_iface_page "control interface" that can be used by +external programs to control the operations of the %wpa_supplicant +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 wpa_supplicant.png "wpa_supplicant modules" +\image latex wpa_supplicant.eps "wpa_supplicant modules" width=15cm + +*/ diff --git a/wpa_supplicant/doc/porting.doxygen b/wpa_supplicant/doc/porting.doxygen new file mode 100644 index 000000000000..03111346603b --- /dev/null +++ b/wpa_supplicant/doc/porting.doxygen @@ -0,0 +1,208 @@ +/** +\page porting Porting to different target boards and operating systems + +%wpa_supplicant was designed to be easily portable to different +hardware (board, CPU) and software (OS, drivers) targets. It is +already used with number of operating systems and numerous wireless +card models and drivers. The main %wpa_supplicant repository includes +support for Linux, FreeBSD, and Windows. In addition, at least VxWorks, +PalmOS, Windows CE, and Windows Mobile are supported in separate +repositories. On the hardware +side, %wpa_supplicant is used on various systems: desktops, laptops, +PDAs, and embedded devices with CPUs including x86, PowerPC, +arm/xscale, and MIPS. Both big and little endian configurations are +supported. + + +\section ansi_c_extra Extra functions on top of ANSI C + +%wpa_supplicant is mostly using ANSI C functions that are available on +most targets. However, couple of additional functions that are common +on modern UNIX systems are used. Number of these are listed with +prototypes in common.h (the \verbatim #ifdef CONFIG_ANSI_C_EXTRA \endverbatim +block). These functions may need to be implemented or at least defined +as macros to native functions in the target OS or C library. + +Many of the common ANSI C functions are used through a wrapper +definitions in os.h to allow these to be replaced easily with a +platform specific version in case standard C libraries are not +available. In addition, os.h defines couple of common platform +specific functions that are implemented in os_unix.c for UNIX like +targets and in os_win32.c for Win32 API. If the target platform does +not support either of these examples, a new os_*.c file may need to be +added. + +Unless OS_NO_C_LIB_DEFINES is defined, the standard ANSI C and POSIX +functions are used by defining the os_*() wrappers to use them +directly in order to avoid extra cost in size and speed. If the target +platform needs different versions of the functions, os.h can be +modified to define the suitable macros or alternatively, +OS_NO_C_LIB_DEFINES may be defined for the build and the wrapper +functions can then be implemented in a new os_*.c wrapper file. + +common.h defines number of helper macros for handling integers of +different size and byte order. Suitable version of these definitions +may need to be added for the target platform. + + +\section configuration_backend Configuration backend + +%wpa_supplicant implements a configuration interface that allows the +backend to be easily replaced in order to read configuration data from +a suitable source depending on the target platform. config.c +implements the generic code that can be shared with all configuration +backends. Each backend is implemented in its own config_*.c file. + +The included config_file.c backend uses a text file for configuration +and config_winreg.c uses Windows registry. These files can be used as +an example for a new configuration backend if the target platform uses +different mechanism for configuration parameters. In addition, +config_none.c can be used as an empty starting point for building a +new configuration backend. + + +\section driver_iface_porting Driver interface + +Unless the target OS and driver is already supported, most porting +projects have to implement a driver wrapper. This may be done by +adding a new driver interface module or modifying an existing module +(driver_*.c) if the new target is similar to one of them. \ref +driver_wrapper "Driver wrapper implementation" describes the details +of the driver interface and discusses the tasks involved in porting +this part of %wpa_supplicant. + + +\section l2_packet_porting l2_packet (link layer access) + +%wpa_supplicant needs to have access to sending and receiving layer 2 +(link layer) packets with two Ethertypes: EAP-over-LAN (EAPOL) 0x888e +and RSN pre-authentication 0x88c7. l2_packet.h defines the interfaces +used for this in the core %wpa_supplicant implementation. + +If the target operating system supports a generic mechanism for link +layer access, that is likely the best mechanism for providing the +needed functionality for %wpa_supplicant. Linux packet socket is an +example of such a generic mechanism. If this is not available, a +separate interface may need to be implemented to the network stack or +driver. This is usually an intermediate or protocol driver that is +operating between the device driver and the OS network stack. If such +a mechanism is not feasible, the interface can also be implemented +directly in the device driver. + +The main %wpa_supplicant repository includes l2_packet implementations +for Linux using packet sockets (l2_packet_linux.c), more portable +version using libpcap/libdnet libraries (l2_packet_pcap.c; this +supports WinPcap, too), and FreeBSD specific version of libpcap +interface (l2_packet_freebsd.c). + +If the target operating system is supported by libpcap (receiving) and +libdnet (sending), l2_packet_pcap.c can likely be used with minimal or +no changes. If this is not a case or a proprietary interface for link +layer is required, a new l2_packet module may need to be +added. Alternatively, struct wpa_driver_ops::send_eapol() handler can +be used to override the l2_packet library if the link layer access is +integrated with the driver interface implementation. + + +\section eloop_porting Event loop + +%wpa_supplicant uses a single process/thread model and an event loop +to provide callbacks on events (registered timeout, received packet, +signal). eloop.h defines the event loop interface. eloop.c is an +implementation of such an event loop using select() and sockets. This +is suitable for most UNIX/POSIX systems. When porting to other +operating systems, it may be necessary to replace that implementation +with OS specific mechanisms that provide similar functionality. + + +\section ctrl_iface_porting Control interface + +%wpa_supplicant uses a \ref ctrl_iface_page "control interface" +to allow external processed +to get status information and to control the operations. Currently, +this is implemented with socket based communication; both UNIX domain +sockets and UDP sockets are supported. If the target OS does not +support sockets, this interface will likely need to be modified to use +another mechanism like message queues. The control interface is +optional component, so it is also possible to run %wpa_supplicant +without porting this part. + +The %wpa_supplicant side of the control interface is implemented in +ctrl_iface.c. Matching client side is implemented as a control +interface library in wpa_ctrl.c. + + +\section entry_point Program entry point + +%wpa_supplicant defines a set of functions that can be used to +initialize main supplicant processing. Each operating system has a +mechanism for starting new processing or threads. This is usually a +function with a specific set of arguments and calling convention. This +function is responsible on initializing %wpa_supplicant. + +main.c includes an entry point for UNIX-like operating system, i.e., +main() function that uses command line arguments for setting +parameters for %wpa_supplicant. When porting to other operating +systems, similar OS-specific entry point implementation is needed. It +can be implemented in a new file that is then linked with +%wpa_supplicant instead of main.o. main.c is also a good example on +how the initialization process should be done. + +The supplicant initialization functions are defined in +wpa_supplicant_i.h. In most cases, the entry point function should +start by fetching configuration parameters. After this, a global +%wpa_supplicant context is initialized with a call to +wpa_supplicant_init(). After this, existing network interfaces can be +added with wpa_supplicant_add_iface(). wpa_supplicant_run() is then +used to start the main event loop. Once this returns at program +termination time, wpa_supplicant_deinit() is used to release global +context data. + +wpa_supplicant_add_iface() and wpa_supplicant_remove_iface() can be +used dynamically to add and remove interfaces based on when +%wpa_supplicant processing is needed for them. This can be done, e.g., +when hotplug network adapters are being inserted and ejected. It is +also possible to do this when a network interface is being +enabled/disabled if it is desirable that %wpa_supplicant processing +for the interface is fully enabled/disabled at the same time. + + +\section simple_build Simple build example + +One way to start a porting project is to begin with a very simple +build of %wpa_supplicant with WPA-PSK support and once that is +building correctly, start adding features. + +Following command can be used to build very simple version of +%wpa_supplicant: + +\verbatim +cc -o wpa_supplicant config.c eloop.c common.c md5.c rc4.c sha1.c \ + config_none.c l2_packet_none.c tls_none.c wpa.c preauth.c \ + aes_wrap.c wpa_supplicant.c events.c main_none.c drivers.c +\endverbatim + +The end result is not really very useful since it uses empty functions +for configuration parsing and layer 2 packet access and does not +include a driver interface. However, this is a good starting point +since the build is complete in the sense that all functions are +present and this is easy to configure to a build system by just +including the listed C files. + +Once this version can be build successfully, the end result can be +made functional by adding a proper program entry point (main*.c), +driver interface (driver_*.c and matching CONFIG_DRIVER_* define for +registration in drivers.c), configuration parser/writer (config_*.c), +and layer 2 packet access implementation (l2_packet_*.c). After these +components have been added, the end result should be a working +WPA/WPA2-PSK enabled supplicant. + +After the basic functionality has been verified to work, more features +can be added by linking in more files and defining C pre-processor +defines. Currently, the best source of information for what options +are available and which files needs to be included is in the Makefile +used for building the supplicant with make. Similar configuration will +be needed for build systems that either use different type of make +tool or a GUI-based project configuration. + +*/ diff --git a/wpa_supplicant/doc/testing_tools.doxygen b/wpa_supplicant/doc/testing_tools.doxygen new file mode 100644 index 000000000000..a2ae0c250fdd --- /dev/null +++ b/wpa_supplicant/doc/testing_tools.doxygen @@ -0,0 +1,295 @@ +/** +\page testing_tools Testing and development tools + +[ \ref eapol_test "eapol_test" | +\ref preauth_test "preauth_test" | +\ref driver_test "driver_test" | +\ref unit_tests "Unit tests" ] + +%wpa_supplicant source tree includes number of testing and development +tools that make it easier to test the programs without having to setup +a full test setup with wireless cards. In addition, these tools can be +used to implement automatic tests suites. + +\section eapol_test eapol_test - EAP peer and RADIUS client testing + +eapol_test is a program that links together the same EAP peer +implementation that %wpa_supplicant is using and the RADIUS +authentication client code from hostapd. In addition, it has minimal +glue code to combine these two components in similar ways to IEEE +802.1X/EAPOL Authenticator state machines. In other words, it +integrates IEEE 802.1X Authenticator (normally, an access point) and +IEEE 802.1X Supplicant (normally, a wireless client) together to +generate a single program that can be used to test EAP methods without +having to setup an access point and a wireless client. + +The main uses for eapol_test are in interoperability testing of EAP +methods against RADIUS servers and in development testing for new EAP +methods. It can be easily used to automate EAP testing for +interoperability and regression since the program can be run from +shell scripts without require additional test components apart from a +RADIUS server. For example, the automated EAP tests described in +eap_testing.txt are implemented with eapol_test. Similarly, eapol_test +could be used to implement an automated regression test suite for a +RADIUS authentication server. + +eapol_test uses the same build time configuration file, .config, as +%wpa_supplicant. This file is used to select which EAP methods are +included in eapol_test. This program is not built with the default +Makefile target, so a separate make command needs to be used to +compile the tool: + +\verbatim +make eapol_test +\endverbatim + +The resulting eapol_test binary has following command like options: + +\verbatim +usage: +eapol_test [-nWS] -c<conf> [-a<AS IP>] [-p<AS port>] [-s<AS secret>] \ + [-r<count>] [-t<timeout>] [-C<Connect-Info>] \ + [-M<client MAC address>] +eapol_test scard +eapol_test sim <PIN> <num triplets> [debug] + +options: + -c<conf> = configuration file + -a<AS IP> = IP address of the authentication server, default 127.0.0.1 + -p<AS port> = UDP port of the authentication server, default 1812 + -s<AS secret> = shared secret with the authentication server, default 'radius' + -r<count> = number of re-authentications + -W = wait for a control interface monitor before starting + -S = save configuration after authentiation + -n = no MPPE keys expected + -t<timeout> = sets timeout in seconds (default: 30 s) + -C<Connect-Info> = RADIUS Connect-Info (default: CONNECT 11Mbps 802.11b) + -M<client MAC address> = Set own MAC address (Calling-Station-Id, + default: 02:00:00:00:00:01) +\endverbatim + + +As an example, +\verbatim +eapol_test -ctest.conf -a127.0.0.1 -p1812 -ssecret -r1 +\endverbatim +tries to complete EAP authentication based on the network +configuration from test.conf against the RADIUS server running on the +local host. A re-authentication is triggered to test fast +re-authentication. The configuration file uses the same format for +network blocks as %wpa_supplicant. + + +\section preauth_test preauth_test - WPA2 pre-authentication and EAP peer testing + +preauth_test is similar to eapol_test in the sense that in combines +EAP peer implementation with something else, in this case, with WPA2 +pre-authentication. This tool can be used to test pre-authentication +based on the code that %wpa_supplicant is using. As such, it tests +both the %wpa_supplicant implementation and the functionality of an +access point. + +preauth_test is built with: + +\verbatim +make preauth_test +\endverbatim + +and it uses following command line arguments: + +\verbatim +usage: preauth_test <conf> <target MAC address> <ifname> +\endverbatim + +For example, +\verbatim +preauth_test test.conf 02:11:22:33:44:55 eth0 +\endverbatim +would use network configuration from test.conf to try to complete +pre-authentication with AP using BSSID 02:11:22:33:44:55. The +pre-authentication packets would be sent using the eth0 interface. + + +\section driver_test driver_test - driver interface for testing wpa_supplicant + +%wpa_supplicant was designed to support number of different ways to +communicate with a network device driver. This design uses \ref +driver_wrapper "driver interface API" and number of driver interface +implementations. One of these is driver_test.c, i.e., a test driver +interface that is actually not using any drivers. Instead, it provides +a mechanism for running %wpa_supplicant without having to have a +device driver or wireless LAN hardware for that matter. + +driver_test can be used to talk directly with hostapd's driver_test +component to create a test setup where one or more clients and access +points can be tested within one test host and without having to have +multiple wireless cards. This makes it easier to test the core code in +%wpa_supplicant, and hostapd for that matter. Since driver_test uses +the same driver API than any other driver interface implementation, +the core code of %wpa_supplicant and hostapd can be tested with the +same coverage as one would get when using real wireless cards. The +only area that is not tested is the driver interface implementation +(driver_*.c). + +Having the possibility to use simulated network components makes it +much easier to do development testing while adding new features and to +reproduce reported bugs. As such, it is often easiest to just do most +of the development and bug fixing without using real hardware. Once +the driver_test setup has been used to implement a new feature or fix +a bug, the end result can be verified with wireless LAN cards. In many +cases, this may even be unnecessary, depending on what area the +feature/bug is relating to. Of course, changes to driver interfaces +will still require use of real hardware. + +Since multiple components can be run within a single host, testing of +complex network configuration, e.g., large number of clients +association with an access point, becomes quite easy. All the tests +can also be automated without having to resort to complex test setup +using remote access to multiple computers. + +driver_test can be included in the %wpa_supplicant build in the same +way as any other driver interface, i.e., by adding the following line +into .config: + +\verbatim +CONFIG_DRIVER_TEST=y +\endverbatim + +When running %wpa_supplicant, the test interface is selected by using +\a -Dtest command line argument. The interface name (\a -i argument) +can be selected arbitrarily, i.e., it does not need to match with any +existing network interface. The interface name is used to generate a +MAC address, so when using multiple clients, each should use a +different interface, e.g., \a sta1, \a sta2, and so on. + +%wpa_supplicant and hostapd are configured in the same way as they +would be for normal use. Following example shows a simple test setup +for WPA-PSK. + +hostapd is configured with following psk-test.conf configuration file: + +\verbatim +driver=test + +interface=ap1 +logger_stdout=-1 +logger_stdout_level=0 +debug=2 +dump_file=/tmp/hostapd.dump + +test_socket=/tmp/Test/ap1 + +ssid=jkm-test-psk + +wpa=1 +wpa_key_mgmt=WPA-PSK +wpa_pairwise=TKIP +wpa_passphrase=12345678 +\endverbatim + +and started with following command: + +\verbatim +hostapd psk-test.conf +\endverbatim + +%wpa_supplicant uses following configuration file: + +\verbatim +driver_param=test_socket=/tmp/Test/ap1 + +network={ + ssid="jkm-test-psk" + key_mgmt=WPA-PSK + psk="12345678" +} +\endverbatim + +%wpa_supplicant can then be started with following command: + +\verbatim +wpa_supplicant -Dtest -cpsk-test.conf -ista1 -ddK +\endverbatim + +If run without debug information, i.e., with + +\verbatim +wpa_supplicant -Dtest -cpsk-test.conf -ista1 +\endverbatim + +%wpa_supplicant completes authentication and prints following events: + +\verbatim +Trying to associate with 02:b8:a6:62:08:5a (SSID='jkm-test-psk' freq=0 MHz) +Associated with 02:b8:a6:62:08:5a +WPA: Key negotiation completed with 02:b8:a6:62:08:5a [PTK=TKIP GTK=TKIP] +CTRL-EVENT-CONNECTED - Connection to 02:b8:a6:62:08:5a completed (auth) +\endverbatim + +If test setup is using multiple clients, it is possible to run +multiple %wpa_supplicant processes. Alternatively, the support for +multiple interfaces can be used with just one process to save some +resources on single-CPU systems. For example, following command runs +two clients: + +\verbatim +./wpa_supplicant -Dtest -cpsk-test.conf -ista1 \ + -N -Dtest -cpsk-test.conf -ista2 +\endverbatim + +This shows following event log: + +\verbatim +Trying to associate with 02:b8:a6:62:08:5a (SSID='jkm-test-psk' freq=0 MHz) +Associated with 02:b8:a6:62:08:5a +WPA: Key negotiation completed with 02:b8:a6:62:08:5a [PTK=TKIP GTK=TKIP] +CTRL-EVENT-CONNECTED - Connection to 02:b8:a6:62:08:5a completed (auth) +Trying to associate with 02:b8:a6:62:08:5a (SSID='jkm-test-psk' freq=0 MHz) +Associated with 02:b8:a6:62:08:5a +WPA: Key negotiation completed with 02:b8:a6:62:08:5a [PTK=TKIP GTK=TKIP] +CTRL-EVENT-CONNECTED - Connection to 02:b8:a6:62:08:5a completed (auth) +\endverbatim + +hostapd shows this with following events: + +\verbatim +ap1: STA 02:b5:64:63:30:63 IEEE 802.11: associated +ap1: STA 02:b5:64:63:30:63 WPA: pairwise key handshake completed (WPA) +ap1: STA 02:b5:64:63:30:63 WPA: group key handshake completed (WPA) +ap1: STA 02:2a:c4:18:5b:f3 IEEE 802.11: associated +ap1: STA 02:2a:c4:18:5b:f3 WPA: pairwise key handshake completed (WPA) +ap1: STA 02:2a:c4:18:5b:f3 WPA: group key handshake completed (WPA) +\endverbatim + +By default, driver_param is simulating a driver that uses the WPA/RSN +IE generated by %wpa_supplicant. Driver-generated IE and AssocInfo +events can be tested by adding \a use_associnfo=1 to the \a driver_param +line in the configuration file. For example: + +\verbatim +driver_param=test_socket=/tmp/Test/ap1 use_associnfo=1 +\endverbatim + + +\section unit_tests Unit tests + +Number of the components (.c files) used in %wpa_supplicant define +their own unit tests for automated validation of the basic +functionality. Most of the tests for cryptographic algorithms are +using standard test vectors to validate functionality. These tests can +be useful especially when verifying port to a new CPU target. + +In most cases, these tests are implemented in the end of the same file +with functions that are normally commented out, but ca be included by +defining a pre-processor variable when building the file separately. +The details of the needed build options are included in the Makefile +(test-* targets). All automated unit tests can be run with + +\verbatim +make tests +\endverbatim + +This make target builds and runs each test and terminates with zero +exit code if all tests were completed successfully. + +*/ diff --git a/wpa_supplicant/doc/wpa_supplicant.fig b/wpa_supplicant/doc/wpa_supplicant.fig new file mode 100644 index 000000000000..06abfb54b61b --- /dev/null +++ b/wpa_supplicant/doc/wpa_supplicant.fig @@ -0,0 +1,247 @@ +#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 3450 1200 4275 1500 +2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 + 3450 1200 4275 1200 4275 1500 3450 1500 3450 1200 +4 0 0 50 -1 0 12 0.0000 4 180 585 3600 1425 wpa_cli\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 8700 3000 9375 3300 +2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 + 8700 3000 9375 3000 9375 3300 8700 3300 8700 3000 +4 0 0 50 -1 0 12 0.0000 4 150 480 8775 3225 crypto\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 1800 6000 7800 8100 +6 1800 6000 7800 7200 +6 1800 6900 2700 7200 +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 +4 0 0 50 -1 0 12 0.0000 4 105 375 1875 7125 wext\001 +-6 +6 4725 6900 5625 7200 +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 +4 0 0 50 -1 0 12 0.0000 4 135 555 4800 7125 hermes\001 +-6 +6 6675 6900 7800 7200 +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 +4 0 0 50 -1 0 12 0.0000 4 180 930 6750 7125 ndiswrapper\001 +-6 +6 5700 6900 6600 7200 +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 +4 0 0 50 -1 0 12 0.0000 4 135 420 5775 7125 atmel\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 +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 +4 0 0 50 -1 0 12 0.0000 4 180 510 2850 7125 hostap\001 +4 0 0 50 -1 0 12 0.0000 4 135 600 3825 7125 madwifi\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 +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 +-6 +6 9600 3000 10275 3300 +2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 + 9600 3000 10275 3000 10275 3300 9600 3300 9600 3000 +4 0 0 50 -1 0 12 0.0000 4 135 315 9750 3225 TLS\001 +-6 +6 8100 4425 10425 7350 +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 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 765 9375 5700 EAP-OTP\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 9300 6225 10350 6525 +2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 + 9300 6225 10350 6225 10350 6525 9300 6525 9300 6225 +4 0 0 50 -1 0 12 0.0000 4 135 465 9375 6450 LEAP\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 8175 6975 9675 7275 +2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 + 8175 6975 9675 6975 9675 7275 8175 7275 8175 6975 +4 0 0 50 -1 0 12 0.0000 4 135 1365 8250 7200 EAP-MSCHAPv2\001 +-6 +6 9300 6600 10350 6900 +2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 + 9300 6600 10350 6600 10350 6900 9300 6900 9300 6600 +4 0 0 50 -1 0 12 0.0000 4 135 870 9375 6825 EAP-FAST\001 +-6 +6 8175 6600 9225 6900 +2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 + 8175 6600 9225 6600 9225 6900 8175 6900 8175 6600 +4 0 0 50 -1 0 12 0.0000 4 135 795 8250 6825 EAP-PAX\001 +-6 +2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 + 8100 7350 10425 7350 10425 4425 8100 4425 8100 7350 +4 0 0 50 -1 0 12 0.0000 4 135 1050 8700 4650 EAP methods\001 +-6 +6 2775 5025 4050 5325 +2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 + 2775 5025 4050 5025 4050 5325 2775 5325 2775 5025 +4 0 0 50 -1 0 12 0.0000 4 135 990 2925 5250 driver events\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 +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 3300 +2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 7200 3000 8700 3150 +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 3300 +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 3300 +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 5025 +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 210 1440 1637 2371 wpa_supplicant\001 diff --git a/wpa_supplicant/eap_testing.txt b/wpa_supplicant/eap_testing.txt new file mode 100644 index 000000000000..8d132223f6a0 --- /dev/null +++ b/wpa_supplicant/eap_testing.txt @@ -0,0 +1,392 @@ +Automatic regression and interoperability testing of wpa_supplicant's +IEEE 802.1X/EAPOL authentication + +Test program: +- Linked some parts of IEEE 802.1X Authenticator implementation from + hostapd (RADIUS client and RADIUS processing, EAP<->RADIUS + encapsulation/decapsulation) into wpa_supplicant. +- Replaced wpa_supplicant.c and wpa.c with test code that trigger + IEEE 802.1X authentication automatically without need for wireless + client card or AP. +- For EAP methods that generate keying material, the key derived by the + Supplicant is verified to match with the one received by the (now + integrated) Authenticator. + +The full automated test suite can now be run in couple of seconds, but +I'm more than willing to add new RADIUS authentication servers to make +this take a bit more time.. ;-) As an extra bonus, this can also be +seen as automatic regression/interoperability testing for the RADIUS +server, too. + +In order for me to be able to use a new authentication server, the +server need to be available from Internet (at least from one static IP +address) and I will need to get suitable user name/password pairs, +certificates, and private keys for testing use. Other alternative +would be to get an evaluation version of the server so that I can +install it on my own test setup. If you are interested in providing +either server access or evaluation version, please contact me +(j@w1.fi). + + +Test matrix + ++) tested successfully +F) failed +-) server did not support +?) not tested + +Cisco ACS ----------------------------------------------------------. +hostapd --------------------------------------------------------. | +Cisco Aironet 1200 AP (local RADIUS server) ----------------. | | +Periodik Labs Elektron ---------------------------------. | | | +Lucent NavisRadius ---------------------------------. | | | | +Interlink RAD-Series ---------------------------. | | | | | +Radiator -----------------------------------. | | | | | | +Meetinghouse Aegis ---------------------. | | | | | | | +Funk Steel-Belted ------------------. | | | | | | | | +Funk Odyssey -------------------. | | | | | | | | | +Microsoft IAS --------------. | | | | | | | | | | +FreeRADIUS -------------. | | | | | | | | | | | + | | | | | | | | | | | | + +EAP-MD5 + - - + + + + + - - + + +EAP-GTC + - - ? + + + + - - + - +EAP-OTP - - - - - + - - - - - - +EAP-MSCHAPv2 + - - + + + + + - - + - +EAP-TLS + + + + + + + + - - + + +EAP-PEAPv0/MSCHAPv2 + + + + + + + + + - + + +EAP-PEAPv0/GTC + - + - + + + + - - + + +EAP-PEAPv0/OTP - - - - - + - - - - - - +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 - - + + + +1 + +5 +8 - + + +EAP-PEAPv1/GTC - - + + + +1 + +5 +8 - + + +EAP-PEAPv1/OTP - - - - - +1 - - - - - - +EAP-PEAPv1/MD5 - - - + + +1 + +5 - - + - +EAP-PEAPv1/TLS - - - + + +1 F +5 - - + + +EAP-PEAPv1/SIM - - - - - - - - - - + - +EAP-PEAPv1/AKA - - - - - - - - - - + - +EAP-PEAPv1/PSK - - - - - - - - - - + - +EAP-PEAPv1/PAX - - - - - - - - - - + - +EAP-PEAPv1/SAKE - - - - - - - - - - + - +EAP-PEAPv1/GPSK - - - - - - - - - - + - +EAP-TTLS/CHAP + - +2 + + + + + + - + - +EAP-TTLS/MSCHAP + - + + + + + + + - + - +EAP-TTLS/MSCHAPv2 + - + + + + + + + - + - +EAP-TTLS/PAP + - + + + + + + + - + - +EAP-TTLS/EAP-MD5 + - +2 + + + + + + - + - +EAP-TTLS/EAP-GTC + - +2 ? + + + + - - + - +EAP-TTLS/EAP-OTP - - - - - + - - - - - - +EAP-TTLS/EAP-MSCHAPv2 + - +2 + + + + + + - + - +EAP-TTLS/EAP-TLS + - +2 + F + + + - - + - +EAP-TTLS/EAP-SIM - - - - - - - - - - + - +EAP-TTLS/EAP-AKA - - - - - - - - - - + - +EAP-TTLS/EAP-PSK - - - - - - - - - - + - +EAP-TTLS/EAP-PAX - - - - - - - - - - + - +EAP-TTLS/EAP-SAKE - - - - - - - - - - + - +EAP-TTLS/EAP-GPSK - - - - - - - - - - + - +EAP-TTLS + TNC - - - - - + - - - - + - +EAP-SIM + - - ? - + - ? - - + - +EAP-AKA - - - - - + - - - - + - +EAP-AKA' - - - - - - - - - - + - +EAP-PSK +7 - - - - + - - - - + - +EAP-PAX - - - - - + - - - - + - +EAP-SAKE - - - - - - - - - - + - +EAP-GPSK - - - - - - - - - - + - +EAP-FAST/MSCHAPv2(prov) - - - + - + - - - + + + +EAP-FAST/GTC(auth) - - - + - + - - - + + + +EAP-FAST/MSCHAPv2(aprov)- - - - - + - - - - + + +EAP-FAST/GTC(aprov) - - - - - + - - - - + + +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 - - - - - - - - - - + - +LEAP + - + + + + F +6 - + - + +EAP-TNC +9 - - - - + - - - - + - +EAP-IKEv2 +10 - - - - - - - - - + - + +1) PEAPv1 required new label, "client PEAP encryption" instead of "client EAP + encryption", during key derivation (requires phase1="peaplabel=1" in the + network configuration in wpa_supplicant.conf) +2) used FreeRADIUS as inner auth server +5) PEAPv1 required termination of negotiation on tunneled EAP-Success and new + label in key deriviation + (phase1="peap_outer_success=0 peaplabel=1") (in "IETF Draft 5" mode) +6) Authenticator simulator required patching for handling Access-Accept within + negotiation (for the first EAP-Success of LEAP) +7) tested only with an older (incompatible) draft of EAP-PSK; FreeRADIUS does + not support the current EAP-PSK (RFC) specification +8) PEAPv1 used non-standard version negotiation (client had to force v1 even + though server reported v0 as the highest supported version) +9) only EAP-TTLS/EAP-TNC tested, i.e., test did not include proper sequence of + client authentication followed by TNC inside the tunnel +10) worked only with special compatibility code to match the IKEv2 server + implementation + + +Automated tests: + +FreeRADIUS (2.0-beta/CVS snapshot) +- EAP-MD5-Challenge +- EAP-GTC +- EAP-MSCHAPv2 +- EAP-TLS +- EAP-PEAPv0 / MSCHAPv2 +- EAP-PEAPv0 / GTC +- EAP-PEAPv0 / MD5-Challenge +- EAP-PEAPv0 / TLS +- EAP-TTLS / EAP-MD5-Challenge +- EAP-TTLS / EAP-GTC +- EAP-TTLS / EAP-MSCHAPv2 +- EAP-TTLS / EAP-TLS +- EAP-TTLS / CHAP +- EAP-TTLS / PAP +- EAP-TTLS / MSCHAP +- EAP-TTLS / MSCHAPv2 +- EAP-TTLS / EAP-TNC (partial support; no authentication sequence) +- EAP-SIM +- LEAP + +Microsoft Windows Server 2003 / IAS +- EAP-TLS +- EAP-PEAPv0 / MSCHAPv2 +- EAP-PEAPv0 / TLS +- EAP-MD5 +* IAS does not seem to support other EAP methods + +Funk Odyssey 2.01.00.653 +- EAP-TLS +- EAP-PEAPv0 / MSCHAPv2 +- EAP-PEAPv0 / GTC +- EAP-PEAPv1 / MSCHAPv2 +- EAP-PEAPv1 / GTC + Note: PEAPv1 requires TLS key derivation to use label "client EAP encryption" +- EAP-TTLS / CHAP (using FreeRADIUS as inner auth srv) +- EAP-TTLS / MSCHAP +- EAP-TTLS / MSCHAPv2 +- EAP-TTLS / PAP +- EAP-TTLS / EAP-MD5-Challenge (using FreeRADIUS as inner auth srv) +- EAP-TTLS / EAP-GTC (using FreeRADIUS as inner auth srv) +- EAP-TTLS / EAP-MSCHAPv2 (using FreeRADIUS as inner auth srv) +- EAP-TTLS / EAP-TLS (using FreeRADIUS as inner auth srv) +* not supported in Odyssey: + - EAP-MD5-Challenge + - EAP-GTC + - EAP-MSCHAPv2 + - EAP-PEAP / MD5-Challenge + - EAP-PEAP / TLS + +Funk Steel-Belted Radius Enterprise Edition v4.71.739 +- EAP-MD5-Challenge +- EAP-MSCHAPv2 +- EAP-TLS +- EAP-PEAPv0 / MSCHAPv2 +- EAP-PEAPv0 / MD5 +- EAP-PEAPv0 / TLS +- EAP-PEAPv1 / MSCHAPv2 +- EAP-PEAPv1 / MD5 +- EAP-PEAPv1 / GTC +- EAP-PEAPv1 / TLS + Note: PEAPv1 requires TLS key derivation to use label "client EAP encryption" +- EAP-TTLS / CHAP +- EAP-TTLS / MSCHAP +- EAP-TTLS / MSCHAPv2 +- EAP-TTLS / PAP +- EAP-TTLS / EAP-MD5-Challenge +- EAP-TTLS / EAP-MSCHAPv2 +- EAP-TTLS / EAP-TLS + +Meetinghouse Aegis 1.1.4 +- EAP-MD5-Challenge +- EAP-GTC +- EAP-MSCHAPv2 +- EAP-TLS +- EAP-PEAPv0 / MSCHAPv2 +- EAP-PEAPv0 / TLS +- EAP-PEAPv0 / GTC +- EAP-PEAPv0 / MD5-Challenge +- EAP-PEAPv1 / MSCHAPv2 +- EAP-PEAPv1 / TLS +- EAP-PEAPv1 / GTC +- EAP-PEAPv1 / MD5-Challenge + Note: PEAPv1 requires TLS key derivation to use label "client EAP encryption" +- EAP-TTLS / CHAP +- EAP-TTLS / MSCHAP +- EAP-TTLS / MSCHAPv2 +- EAP-TTLS / PAP +- EAP-TTLS / EAP-MD5-Challenge +- EAP-TTLS / EAP-GTC +- EAP-TTLS / EAP-MSCHAPv2 +* did not work + - EAP-TTLS / EAP-TLS + (Server rejects authentication without any reason in debug log. It + looks like the inner TLS negotiation starts properly and the last + packet from Supplicant looks like the one sent in the Phase 1. The + server generates a valid looking reply in the same way as in Phase + 1, but then ends up sending Access-Reject. Maybe an issue with TTLS + fragmentation in the Aegis server(?) The packet seems to include + 1328 bytes of EAP-Message and this may go beyond the fragmentation + limit with AVP encapsulation and TLS tunneling. Note: EAP-PEAP/TLS + did work, so this issue seems to be with something TTLS specific.) + +Radiator 3.17.1 (eval, with all patches up to and including 2007-05-25) +- EAP-MD5-Challenge +- EAP-GTC +- EAP-OTP +- EAP-MSCHAPv2 +- EAP-TLS +- EAP-PEAPv0 / MSCHAPv2 +- EAP-PEAPv0 / GTC +- EAP-PEAPv0 / OTP +- EAP-PEAPv0 / MD5-Challenge +- EAP-PEAPv0 / TLS + Note: Needed to use unknown identity in outer auth and some times the server + seems to get confused and fails to send proper Phase 2 data. +- EAP-PEAPv1 / MSCHAPv2 +- EAP-PEAPv1 / GTC +- EAP-PEAPv1 / OTP +- EAP-PEAPv1 / MD5-Challenge +- EAP-PEAPv1 / TLS + Note: This has some additional requirements for EAPTLS_MaxFragmentSize. + Using 1300 for outer auth and 500 for inner auth seemed to work. + Note: Needed to use unknown identity in outer auth and some times the server + seems to get confused and fails to send proper Phase 2 data. +- EAP-TTLS / CHAP +- EAP-TTLS / MSCHAP +- EAP-TTLS / MSCHAPv2 +- EAP-TTLS / PAP +- EAP-TTLS / EAP-MD5-Challenge +- EAP-TTLS / EAP-GTC +- EAP-TTLS / EAP-OTP +- EAP-TTLS / EAP-MSCHAPv2 +- EAP-TTLS / EAP-TLS + Note: This has some additional requirements for EAPTLS_MaxFragmentSize. + Using 1300 for outer auth and 500 for inner auth seemed to work. +- EAP-SIM +- EAP-AKA +- EAP-PSK +- EAP-PAX +- EAP-TNC + +Interlink Networks RAD-Series 6.1.2.7 +- EAP-MD5-Challenge +- EAP-GTC +- EAP-MSCHAPv2 +- EAP-TLS +- EAP-PEAPv0 / MSCHAPv2 +- EAP-PEAPv0 / GTC +- EAP-PEAPv0 / MD5-Challenge +- EAP-PEAPv1 / MSCHAPv2 +- EAP-PEAPv1 / GTC +- EAP-PEAPv1 / MD5-Challenge + Note: PEAPv1 requires TLS key derivation to use label "client EAP encryption" +- EAP-TTLS / CHAP +- EAP-TTLS / MSCHAP +- EAP-TTLS / MSCHAPv2 +- EAP-TTLS / PAP +- EAP-TTLS / EAP-MD5-Challenge +- EAP-TTLS / EAP-GTC +- EAP-TTLS / EAP-MSCHAPv2 +- EAP-TTLS / EAP-TLS +* did not work + - EAP-PEAPv0 / TLS + - EAP-PEAPv1 / TLS + (Failed to decrypt Phase 2 data) + +Lucent NavisRadius 4.4.0 +- EAP-MD5-Challenge +- EAP-GTC +- EAP-MSCHAPv2 +- EAP-TLS +- EAP-PEAPv0 / MD5-Challenge +- EAP-PEAPv0 / MSCHAPv2 +- EAP-PEAPv0 / GTC +- EAP-PEAPv0 / TLS +- EAP-PEAPv1 / MD5-Challenge +- EAP-PEAPv1 / MSCHAPv2 +- EAP-PEAPv1 / GTC +- EAP-PEAPv1 / TLS + "IETF Draft 5" mode requires phase1="peap_outer_success=0 peaplabel=1" + 'Cisco ACU 5.05' mode works without phase1 configuration +- EAP-TTLS / CHAP +- EAP-TTLS / MSCHAP +- EAP-TTLS / MSCHAPv2 +- EAP-TTLS / PAP +- EAP-TTLS / EAP-MD5-Challenge +- EAP-TTLS / EAP-MSCHAPv2 +- EAP-TTLS / EAP-GTC +- EAP-TTLS / EAP-TLS + +Note: user certificate from NavisRadius had private key in a format +that wpa_supplicant could not use. Converting this to PKCS#12 and then +back to PEM allowed wpa_supplicant to use the key. + + +hostapd v0.3.3 +- EAP-MD5-Challenge +- EAP-GTC +- EAP-MSCHAPv2 +- EAP-TLS +- EAP-PEAPv0 / MSCHAPv2 +- EAP-PEAPv0 / GTC +- EAP-PEAPv0 / MD5-Challenge +- EAP-PEAPv1 / MSCHAPv2 +- EAP-PEAPv1 / GTC +- EAP-PEAPv1 / MD5-Challenge +- EAP-TTLS / CHAP +- EAP-TTLS / MSCHAP +- EAP-TTLS / MSCHAPv2 +- EAP-TTLS / PAP +- EAP-TTLS / EAP-MD5-Challenge +- EAP-TTLS / EAP-GTC +- EAP-TTLS / EAP-MSCHAPv2 +- EAP-SIM +- EAP-PAX + +PEAPv1: + +Funk Odyssey 2.01.00.653: +- uses tunneled EAP-Success, expects reply in tunnel or TLS ACK, sends MPPE + keys with outer EAP-Success message after this +- uses label "client EAP encryption" +- (peap_outer_success 1 and 2 work) + +Funk Steel-Belted Radius Enterprise Edition v4.71.739 +- uses tunneled EAP-Success, expects reply in tunnel or TLS ACK, sends MPPE + keys with outer EAP-Success message after this +- uses label "client EAP encryption" +- (peap_outer_success 1 and 2 work) + +Radiator 3.9: +- uses TLV Success and Reply, sends MPPE keys with outer EAP-Success message + after this +- uses label "client PEAP encryption" + +Lucent NavisRadius 4.4.0 (in "IETF Draft 5" mode): +- sends tunneled EAP-Success with MPPE keys and expects the authentication to + terminate at this point (gets somewhat confused with reply to this) +- uses label "client PEAP encryption" +- phase1="peap_outer_success=0 peaplabel=1" + +Lucent NavisRadius 4.4.0 (in "Cisco ACU 5.05" mode): +- sends tunneled EAP-Success with MPPE keys and expects to receive TLS ACK + as a reply +- uses label "client EAP encryption" + +Meetinghouse Aegis 1.1.4 +- uses tunneled EAP-Success, expects reply in tunnel or TLS ACK, sends MPPE + keys with outer EAP-Success message after this +- uses label "client EAP encryption" +- peap_outer_success 1 and 2 work diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c new file mode 100644 index 000000000000..d87aad7349ac --- /dev/null +++ b/wpa_supplicant/eapol_test.c @@ -0,0 +1,1216 @@ +/* + * WPA Supplicant - test code + * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + * + * IEEE 802.1X Supplicant test code (to be used in place of wpa_supplicant.c. + * Not used in production version. + */ + +#include "includes.h" +#include <assert.h> + +#include "common.h" +#include "config.h" +#include "eapol_supp/eapol_supp_sm.h" +#include "eap_peer/eap.h" +#include "eloop.h" +#include "wpa.h" +#include "eap_peer/eap_i.h" +#include "wpa_supplicant_i.h" +#include "radius/radius.h" +#include "radius/radius_client.h" +#include "ctrl_iface.h" +#include "pcsc_funcs.h" + + +extern int wpa_debug_level; +extern int wpa_debug_show_keys; + +struct wpa_driver_ops *wpa_supplicant_drivers[] = { NULL }; + + +struct extra_radius_attr { + u8 type; + char syntax; + char *data; + struct extra_radius_attr *next; +}; + +struct eapol_test_data { + struct wpa_supplicant *wpa_s; + + int eapol_test_num_reauths; + int no_mppe_keys; + int num_mppe_ok, num_mppe_mismatch; + + u8 radius_identifier; + struct radius_msg *last_recv_radius; + struct in_addr own_ip_addr; + struct radius_client_data *radius; + struct hostapd_radius_servers *radius_conf; + + u8 *last_eap_radius; /* last received EAP Response from Authentication + * Server */ + size_t last_eap_radius_len; + + u8 authenticator_pmk[PMK_LEN]; + size_t authenticator_pmk_len; + int radius_access_accept_received; + int radius_access_reject_received; + int auth_timed_out; + + u8 *eap_identity; + size_t eap_identity_len; + + char *connect_info; + u8 own_addr[ETH_ALEN]; + struct extra_radius_attr *extra_attrs; +}; + +static struct eapol_test_data eapol_test; + + +static void send_eap_request_identity(void *eloop_ctx, void *timeout_ctx); + + +static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module, + int level, const char *txt, size_t len) +{ + if (addr) + wpa_printf(MSG_DEBUG, "STA " MACSTR ": %s\n", + MAC2STR(addr), txt); + else + wpa_printf(MSG_DEBUG, "%s", txt); +} + + +static int add_extra_attr(struct radius_msg *msg, + struct extra_radius_attr *attr) +{ + size_t len; + char *pos; + u32 val; + char buf[128]; + + switch (attr->syntax) { + case 's': + os_snprintf(buf, sizeof(buf), "%s", attr->data); + len = os_strlen(buf); + break; + case 'n': + buf[0] = '\0'; + len = 1; + break; + case 'x': + pos = attr->data; + if (pos[0] == '0' && pos[1] == 'x') + pos += 2; + len = os_strlen(pos); + if ((len & 1) || (len / 2) > sizeof(buf)) { + printf("Invalid extra attribute hexstring\n"); + return -1; + } + len /= 2; + if (hexstr2bin(pos, (u8 *) buf, len) < 0) { + printf("Invalid extra attribute hexstring\n"); + return -1; + } + break; + case 'd': + val = htonl(atoi(attr->data)); + os_memcpy(buf, &val, 4); + len = 4; + break; + default: + printf("Incorrect extra attribute syntax specification\n"); + return -1; + } + + if (!radius_msg_add_attr(msg, attr->type, (u8 *) buf, len)) { + printf("Could not add attribute %d\n", attr->type); + return -1; + } + + return 0; +} + + +static int add_extra_attrs(struct radius_msg *msg, + struct extra_radius_attr *attrs) +{ + struct extra_radius_attr *p; + for (p = attrs; p; p = p->next) { + if (add_extra_attr(msg, p) < 0) + return -1; + } + return 0; +} + + +static struct extra_radius_attr * +find_extra_attr(struct extra_radius_attr *attrs, u8 type) +{ + struct extra_radius_attr *p; + for (p = attrs; p; p = p->next) { + if (p->type == type) + return p; + } + return NULL; +} + + +static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e, + const u8 *eap, size_t len) +{ + struct radius_msg *msg; + char buf[128]; + const struct eap_hdr *hdr; + const u8 *pos; + + wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS " + "packet"); + + e->radius_identifier = radius_client_get_id(e->radius); + msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, + e->radius_identifier); + if (msg == NULL) { + printf("Could not create net RADIUS packet\n"); + return; + } + + radius_msg_make_authenticator(msg, (u8 *) e, sizeof(*e)); + + hdr = (const struct eap_hdr *) eap; + pos = (const u8 *) (hdr + 1); + if (len > sizeof(*hdr) && hdr->code == EAP_CODE_RESPONSE && + pos[0] == EAP_TYPE_IDENTITY) { + pos++; + os_free(e->eap_identity); + e->eap_identity_len = len - sizeof(*hdr) - 1; + e->eap_identity = os_malloc(e->eap_identity_len); + if (e->eap_identity) { + os_memcpy(e->eap_identity, pos, e->eap_identity_len); + wpa_hexdump(MSG_DEBUG, "Learned identity from " + "EAP-Response-Identity", + e->eap_identity, e->eap_identity_len); + } + } + + if (e->eap_identity && + !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, + e->eap_identity, e->eap_identity_len)) { + printf("Could not add User-Name\n"); + goto fail; + } + + if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_NAS_IP_ADDRESS) && + !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, + (u8 *) &e->own_ip_addr, 4)) { + printf("Could not add NAS-IP-Address\n"); + goto fail; + } + + os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, + MAC2STR(e->wpa_s->own_addr)); + if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_CALLING_STATION_ID) + && + !radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, + (u8 *) buf, os_strlen(buf))) { + printf("Could not add Calling-Station-Id\n"); + goto fail; + } + + /* TODO: should probably check MTU from driver config; 2304 is max for + * IEEE 802.11, but use 1400 to avoid problems with too large packets + */ + if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_FRAMED_MTU) && + !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) { + printf("Could not add Framed-MTU\n"); + goto fail; + } + + if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_NAS_PORT_TYPE) && + !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE, + RADIUS_NAS_PORT_TYPE_IEEE_802_11)) { + printf("Could not add NAS-Port-Type\n"); + goto fail; + } + + os_snprintf(buf, sizeof(buf), "%s", e->connect_info); + if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_CONNECT_INFO) && + !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, + (u8 *) buf, os_strlen(buf))) { + printf("Could not add Connect-Info\n"); + goto fail; + } + + if (add_extra_attrs(msg, e->extra_attrs) < 0) + goto fail; + + if (eap && !radius_msg_add_eap(msg, eap, len)) { + printf("Could not add EAP-Message\n"); + goto fail; + } + + /* State attribute must be copied if and only if this packet is + * Access-Request reply to the previous Access-Challenge */ + if (e->last_recv_radius && e->last_recv_radius->hdr->code == + RADIUS_CODE_ACCESS_CHALLENGE) { + int res = radius_msg_copy_attr(msg, e->last_recv_radius, + RADIUS_ATTR_STATE); + if (res < 0) { + printf("Could not copy State attribute from previous " + "Access-Challenge\n"); + goto fail; + } + if (res > 0) { + wpa_printf(MSG_DEBUG, " Copied RADIUS State " + "Attribute"); + } + } + + radius_client_send(e->radius, msg, RADIUS_AUTH, e->wpa_s->own_addr); + return; + + fail: + radius_msg_free(msg); + os_free(msg); +} + + +static int eapol_test_eapol_send(void *ctx, int type, const u8 *buf, + size_t len) +{ + /* struct wpa_supplicant *wpa_s = ctx; */ + printf("WPA: eapol_test_eapol_send(type=%d len=%lu)\n", + type, (unsigned long) len); + if (type == IEEE802_1X_TYPE_EAP_PACKET) { + wpa_hexdump(MSG_DEBUG, "TX EAP -> RADIUS", buf, len); + ieee802_1x_encapsulate_radius(&eapol_test, buf, len); + } + return 0; +} + + +static void eapol_test_set_config_blob(void *ctx, + struct wpa_config_blob *blob) +{ + struct wpa_supplicant *wpa_s = ctx; + wpa_config_set_blob(wpa_s->conf, blob); +} + + +static const struct wpa_config_blob * +eapol_test_get_config_blob(void *ctx, const char *name) +{ + struct wpa_supplicant *wpa_s = ctx; + return wpa_config_get_blob(wpa_s->conf, name); +} + + +static void eapol_test_eapol_done_cb(void *ctx) +{ + printf("WPA: EAPOL processing complete\n"); +} + + +static void eapol_sm_reauth(void *eloop_ctx, void *timeout_ctx) +{ + struct eapol_test_data *e = eloop_ctx; + printf("\n\n\n\n\neapol_test: Triggering EAP reauthentication\n\n"); + e->radius_access_accept_received = 0; + send_eap_request_identity(e->wpa_s, NULL); +} + + +static int eapol_test_compare_pmk(struct eapol_test_data *e) +{ + u8 pmk[PMK_LEN]; + int ret = 1; + + if (eapol_sm_get_key(e->wpa_s->eapol, pmk, PMK_LEN) == 0) { + wpa_hexdump(MSG_DEBUG, "PMK from EAPOL", pmk, PMK_LEN); + if (os_memcmp(pmk, e->authenticator_pmk, PMK_LEN) != 0) { + printf("WARNING: PMK mismatch\n"); + wpa_hexdump(MSG_DEBUG, "PMK from AS", + e->authenticator_pmk, PMK_LEN); + } else if (e->radius_access_accept_received) + ret = 0; + } else if (e->authenticator_pmk_len == 16 && + eapol_sm_get_key(e->wpa_s->eapol, pmk, 16) == 0) { + wpa_hexdump(MSG_DEBUG, "LEAP PMK from EAPOL", pmk, 16); + if (os_memcmp(pmk, e->authenticator_pmk, 16) != 0) { + printf("WARNING: PMK mismatch\n"); + wpa_hexdump(MSG_DEBUG, "PMK from AS", + e->authenticator_pmk, 16); + } else if (e->radius_access_accept_received) + ret = 0; + } else if (e->radius_access_accept_received && e->no_mppe_keys) { + /* No keying material expected */ + ret = 0; + } + + if (ret && !e->no_mppe_keys) + e->num_mppe_mismatch++; + else if (!e->no_mppe_keys) + e->num_mppe_ok++; + + return ret; +} + + +static void eapol_sm_cb(struct eapol_sm *eapol, int success, void *ctx) +{ + struct eapol_test_data *e = ctx; + printf("eapol_sm_cb: success=%d\n", success); + e->eapol_test_num_reauths--; + if (e->eapol_test_num_reauths < 0) + eloop_terminate(); + else { + eapol_test_compare_pmk(e); + eloop_register_timeout(0, 100000, eapol_sm_reauth, e, NULL); + } +} + + +static int test_eapol(struct eapol_test_data *e, struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + struct eapol_config eapol_conf; + struct eapol_ctx *ctx; + + ctx = os_zalloc(sizeof(*ctx)); + if (ctx == NULL) { + printf("Failed to allocate EAPOL context.\n"); + return -1; + } + ctx->ctx = wpa_s; + ctx->msg_ctx = wpa_s; + ctx->scard_ctx = wpa_s->scard; + ctx->cb = eapol_sm_cb; + ctx->cb_ctx = e; + ctx->eapol_send_ctx = wpa_s; + ctx->preauth = 0; + ctx->eapol_done_cb = eapol_test_eapol_done_cb; + ctx->eapol_send = eapol_test_eapol_send; + ctx->set_config_blob = eapol_test_set_config_blob; + ctx->get_config_blob = eapol_test_get_config_blob; +#ifdef EAP_TLS_OPENSSL + ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path; + ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path; + ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path; +#endif /* EAP_TLS_OPENSSL */ + + wpa_s->eapol = eapol_sm_init(ctx); + if (wpa_s->eapol == NULL) { + os_free(ctx); + printf("Failed to initialize EAPOL state machines.\n"); + return -1; + } + + wpa_s->current_ssid = ssid; + os_memset(&eapol_conf, 0, sizeof(eapol_conf)); + eapol_conf.accept_802_1x_keys = 1; + eapol_conf.required_keys = 0; + eapol_conf.fast_reauth = wpa_s->conf->fast_reauth; + eapol_conf.workaround = ssid->eap_workaround; + eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf); + eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard); + + + eapol_sm_notify_portValid(wpa_s->eapol, FALSE); + /* 802.1X::portControl = Auto */ + eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE); + + return 0; +} + + +static void test_eapol_clean(struct eapol_test_data *e, + struct wpa_supplicant *wpa_s) +{ + struct extra_radius_attr *p, *prev; + + radius_client_deinit(e->radius); + os_free(e->last_eap_radius); + if (e->last_recv_radius) { + radius_msg_free(e->last_recv_radius); + os_free(e->last_recv_radius); + } + os_free(e->eap_identity); + e->eap_identity = NULL; + eapol_sm_deinit(wpa_s->eapol); + wpa_s->eapol = NULL; + if (e->radius_conf && e->radius_conf->auth_server) { + os_free(e->radius_conf->auth_server->shared_secret); + os_free(e->radius_conf->auth_server); + } + os_free(e->radius_conf); + e->radius_conf = NULL; + scard_deinit(wpa_s->scard); + if (wpa_s->ctrl_iface) { + wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface); + wpa_s->ctrl_iface = NULL; + } + wpa_config_free(wpa_s->conf); + + p = e->extra_attrs; + while (p) { + prev = p; + p = p->next; + os_free(prev); + } +} + + +static void send_eap_request_identity(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + u8 buf[100], *pos; + struct ieee802_1x_hdr *hdr; + struct eap_hdr *eap; + + hdr = (struct ieee802_1x_hdr *) buf; + hdr->version = EAPOL_VERSION; + hdr->type = IEEE802_1X_TYPE_EAP_PACKET; + hdr->length = htons(5); + + eap = (struct eap_hdr *) (hdr + 1); + eap->code = EAP_CODE_REQUEST; + eap->identifier = 0; + eap->length = htons(5); + pos = (u8 *) (eap + 1); + *pos = EAP_TYPE_IDENTITY; + + printf("Sending fake EAP-Request-Identity\n"); + eapol_sm_rx_eapol(wpa_s->eapol, wpa_s->bssid, buf, + sizeof(*hdr) + 5); +} + + +static void eapol_test_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct eapol_test_data *e = eloop_ctx; + printf("EAPOL test timed out\n"); + e->auth_timed_out = 1; + eloop_terminate(); +} + + +static 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_TLS: return "TLS"; + case EAP_TYPE_TTLS: return "TTLS"; + case EAP_TYPE_PEAP: return "PEAP"; + case EAP_TYPE_SIM: return "SIM"; + case EAP_TYPE_GTC: return "GTC"; + case EAP_TYPE_MD5: return "MD5"; + case EAP_TYPE_OTP: return "OTP"; + case EAP_TYPE_FAST: return "FAST"; + case EAP_TYPE_SAKE: return "SAKE"; + case EAP_TYPE_PSK: return "PSK"; + default: return "Unknown"; + } +} + + +static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e) +{ + u8 *eap; + size_t len; + struct eap_hdr *hdr; + int eap_type = -1; + char buf[64]; + struct radius_msg *msg; + + if (e->last_recv_radius == NULL) + return; + + msg = e->last_recv_radius; + + eap = radius_msg_get_eap(msg, &len); + if (eap == NULL) { + /* draft-aboba-radius-rfc2869bis-20.txt, Chap. 2.6.3: + * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message + * attribute */ + wpa_printf(MSG_DEBUG, "could not extract " + "EAP-Message from RADIUS message"); + os_free(e->last_eap_radius); + e->last_eap_radius = NULL; + e->last_eap_radius_len = 0; + return; + } + + if (len < sizeof(*hdr)) { + wpa_printf(MSG_DEBUG, "too short EAP packet " + "received from authentication server"); + os_free(eap); + return; + } + + if (len > sizeof(*hdr)) + eap_type = eap[sizeof(*hdr)]; + + hdr = (struct eap_hdr *) eap; + switch (hdr->code) { + case EAP_CODE_REQUEST: + os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)", + eap_type >= 0 ? eap_type_text(eap_type) : "??", + eap_type); + break; + case EAP_CODE_RESPONSE: + os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)", + eap_type >= 0 ? eap_type_text(eap_type) : "??", + eap_type); + break; + case EAP_CODE_SUCCESS: + os_strlcpy(buf, "EAP Success", sizeof(buf)); + /* LEAP uses EAP Success within an authentication, so must not + * stop here with eloop_terminate(); */ + break; + case EAP_CODE_FAILURE: + os_strlcpy(buf, "EAP Failure", sizeof(buf)); + eloop_terminate(); + break; + default: + os_strlcpy(buf, "unknown EAP code", sizeof(buf)); + wpa_hexdump(MSG_DEBUG, "Decapsulated EAP packet", eap, len); + break; + } + wpa_printf(MSG_DEBUG, "decapsulated EAP packet (code=%d " + "id=%d len=%d) from RADIUS server: %s", + hdr->code, hdr->identifier, ntohs(hdr->length), buf); + + /* sta->eapol_sm->be_auth.idFromServer = hdr->identifier; */ + + os_free(e->last_eap_radius); + e->last_eap_radius = eap; + e->last_eap_radius_len = len; + + { + struct ieee802_1x_hdr *dot1x; + dot1x = os_malloc(sizeof(*dot1x) + len); + assert(dot1x != NULL); + dot1x->version = EAPOL_VERSION; + dot1x->type = IEEE802_1X_TYPE_EAP_PACKET; + dot1x->length = htons(len); + os_memcpy((u8 *) (dot1x + 1), eap, len); + eapol_sm_rx_eapol(e->wpa_s->eapol, e->wpa_s->bssid, + (u8 *) dot1x, sizeof(*dot1x) + len); + os_free(dot1x); + } +} + + +static void ieee802_1x_get_keys(struct eapol_test_data *e, + struct radius_msg *msg, struct radius_msg *req, + u8 *shared_secret, size_t shared_secret_len) +{ + struct radius_ms_mppe_keys *keys; + + keys = radius_msg_get_ms_keys(msg, req, shared_secret, + shared_secret_len); + if (keys && keys->send == NULL && keys->recv == NULL) { + os_free(keys); + keys = radius_msg_get_cisco_keys(msg, req, shared_secret, + shared_secret_len); + } + + if (keys) { + if (keys->send) { + wpa_hexdump(MSG_DEBUG, "MS-MPPE-Send-Key (sign)", + keys->send, keys->send_len); + } + if (keys->recv) { + wpa_hexdump(MSG_DEBUG, "MS-MPPE-Recv-Key (crypt)", + keys->recv, keys->recv_len); + e->authenticator_pmk_len = + keys->recv_len > PMK_LEN ? PMK_LEN : + keys->recv_len; + os_memcpy(e->authenticator_pmk, keys->recv, + e->authenticator_pmk_len); + if (e->authenticator_pmk_len == 16 && keys->send && + keys->send_len == 16) { + /* MS-CHAP-v2 derives 16 octet keys */ + wpa_printf(MSG_DEBUG, "Use MS-MPPE-Send-Key " + "to extend PMK to 32 octets"); + os_memcpy(e->authenticator_pmk + + e->authenticator_pmk_len, + keys->send, keys->send_len); + e->authenticator_pmk_len += keys->send_len; + } + } + + os_free(keys->send); + os_free(keys->recv); + os_free(keys); + } +} + + +/* Process the RADIUS frames from Authentication Server */ +static RadiusRxResult +ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, + u8 *shared_secret, size_t shared_secret_len, + void *data) +{ + struct eapol_test_data *e = data; + + /* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be + * present when packet contains an EAP-Message attribute */ + if (msg->hdr->code == RADIUS_CODE_ACCESS_REJECT && + radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL, + 0) < 0 && + radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) { + wpa_printf(MSG_DEBUG, "Allowing RADIUS " + "Access-Reject without Message-Authenticator " + "since it does not include EAP-Message\n"); + } else if (radius_msg_verify(msg, shared_secret, shared_secret_len, + req, 1)) { + printf("Incoming RADIUS packet did not have correct " + "Message-Authenticator - dropped\n"); + return RADIUS_RX_UNKNOWN; + } + + if (msg->hdr->code != RADIUS_CODE_ACCESS_ACCEPT && + msg->hdr->code != RADIUS_CODE_ACCESS_REJECT && + msg->hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) { + printf("Unknown RADIUS message code\n"); + return RADIUS_RX_UNKNOWN; + } + + e->radius_identifier = -1; + wpa_printf(MSG_DEBUG, "RADIUS packet matching with station"); + + if (e->last_recv_radius) { + radius_msg_free(e->last_recv_radius); + os_free(e->last_recv_radius); + } + + e->last_recv_radius = msg; + + switch (msg->hdr->code) { + case RADIUS_CODE_ACCESS_ACCEPT: + e->radius_access_accept_received = 1; + ieee802_1x_get_keys(e, msg, req, shared_secret, + shared_secret_len); + break; + case RADIUS_CODE_ACCESS_REJECT: + e->radius_access_reject_received = 1; + break; + } + + ieee802_1x_decapsulate_radius(e); + + if ((msg->hdr->code == RADIUS_CODE_ACCESS_ACCEPT && + e->eapol_test_num_reauths < 0) || + msg->hdr->code == RADIUS_CODE_ACCESS_REJECT) { + eloop_terminate(); + } + + return RADIUS_RX_QUEUED; +} + + +static void wpa_init_conf(struct eapol_test_data *e, + struct wpa_supplicant *wpa_s, const char *authsrv, + int port, const char *secret, + const char *cli_addr) +{ + struct hostapd_radius_server *as; + int res; + + wpa_s->bssid[5] = 1; + os_memcpy(wpa_s->own_addr, e->own_addr, ETH_ALEN); + e->own_ip_addr.s_addr = htonl((127 << 24) | 1); + os_strlcpy(wpa_s->ifname, "test", sizeof(wpa_s->ifname)); + + e->radius_conf = os_zalloc(sizeof(struct hostapd_radius_servers)); + assert(e->radius_conf != NULL); + e->radius_conf->num_auth_servers = 1; + as = os_zalloc(sizeof(struct hostapd_radius_server)); + assert(as != NULL); +#if defined(CONFIG_NATIVE_WINDOWS) || defined(CONFIG_ANSI_C_EXTRA) + { + int a[4]; + u8 *pos; + sscanf(authsrv, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]); + pos = (u8 *) &as->addr.u.v4; + *pos++ = a[0]; + *pos++ = a[1]; + *pos++ = a[2]; + *pos++ = a[3]; + } +#else /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */ + inet_aton(authsrv, &as->addr.u.v4); +#endif /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */ + as->addr.af = AF_INET; + as->port = port; + as->shared_secret = (u8 *) os_strdup(secret); + as->shared_secret_len = os_strlen(secret); + e->radius_conf->auth_server = as; + e->radius_conf->auth_servers = as; + e->radius_conf->msg_dumps = 1; + if (cli_addr) { + if (hostapd_parse_ip_addr(cli_addr, + &e->radius_conf->client_addr) == 0) + e->radius_conf->force_client_addr = 1; + else { + wpa_printf(MSG_ERROR, "Invalid IP address '%s'", + cli_addr); + assert(0); + } + } + + e->radius = radius_client_init(wpa_s, e->radius_conf); + assert(e->radius != NULL); + + res = radius_client_register(e->radius, RADIUS_AUTH, + ieee802_1x_receive_auth, e); + assert(res == 0); +} + + +static int scard_test(void) +{ + struct scard_data *scard; + size_t len; + char imsi[20]; + unsigned char _rand[16]; +#ifdef PCSC_FUNCS + unsigned char sres[4]; + unsigned char kc[8]; +#endif /* PCSC_FUNCS */ +#define num_triplets 5 + unsigned char rand_[num_triplets][16]; + unsigned char sres_[num_triplets][4]; + unsigned char kc_[num_triplets][8]; + int i, res; + size_t j; + +#define AKA_RAND_LEN 16 +#define AKA_AUTN_LEN 16 +#define AKA_AUTS_LEN 14 +#define RES_MAX_LEN 16 +#define IK_LEN 16 +#define CK_LEN 16 + unsigned char aka_rand[AKA_RAND_LEN]; + unsigned char aka_autn[AKA_AUTN_LEN]; + unsigned char aka_auts[AKA_AUTS_LEN]; + unsigned char aka_res[RES_MAX_LEN]; + size_t aka_res_len; + unsigned char aka_ik[IK_LEN]; + unsigned char aka_ck[CK_LEN]; + + scard = scard_init(SCARD_TRY_BOTH); + if (scard == NULL) + return -1; + if (scard_set_pin(scard, "1234")) { + wpa_printf(MSG_WARNING, "PIN validation failed"); + scard_deinit(scard); + return -1; + } + + len = sizeof(imsi); + if (scard_get_imsi(scard, imsi, &len)) + goto failed; + wpa_hexdump_ascii(MSG_DEBUG, "SCARD: IMSI", (u8 *) imsi, len); + /* NOTE: Permanent Username: 1 | IMSI */ + + os_memset(_rand, 0, sizeof(_rand)); + if (scard_gsm_auth(scard, _rand, sres, kc)) + goto failed; + + os_memset(_rand, 0xff, sizeof(_rand)); + if (scard_gsm_auth(scard, _rand, sres, kc)) + goto failed; + + for (i = 0; i < num_triplets; i++) { + os_memset(rand_[i], i, sizeof(rand_[i])); + if (scard_gsm_auth(scard, rand_[i], sres_[i], kc_[i])) + goto failed; + } + + for (i = 0; i < num_triplets; i++) { + printf("1"); + for (j = 0; j < len; j++) + printf("%c", imsi[j]); + printf(","); + for (j = 0; j < 16; j++) + printf("%02X", rand_[i][j]); + printf(","); + for (j = 0; j < 4; j++) + printf("%02X", sres_[i][j]); + printf(","); + for (j = 0; j < 8; j++) + printf("%02X", kc_[i][j]); + printf("\n"); + } + + wpa_printf(MSG_DEBUG, "Trying to use UMTS authentication"); + + /* seq 39 (0x28) */ + os_memset(aka_rand, 0xaa, 16); + os_memcpy(aka_autn, "\x86\x71\x31\xcb\xa2\xfc\x61\xdf" + "\xa3\xb3\x97\x9d\x07\x32\xa2\x12", 16); + + res = scard_umts_auth(scard, aka_rand, aka_autn, aka_res, &aka_res_len, + aka_ik, aka_ck, aka_auts); + if (res == 0) { + wpa_printf(MSG_DEBUG, "UMTS auth completed successfully"); + wpa_hexdump(MSG_DEBUG, "RES", aka_res, aka_res_len); + wpa_hexdump(MSG_DEBUG, "IK", aka_ik, IK_LEN); + wpa_hexdump(MSG_DEBUG, "CK", aka_ck, CK_LEN); + } else if (res == -2) { + wpa_printf(MSG_DEBUG, "UMTS auth resulted in synchronization " + "failure"); + wpa_hexdump(MSG_DEBUG, "AUTS", aka_auts, AKA_AUTS_LEN); + } else { + wpa_printf(MSG_DEBUG, "UMTS auth failed"); + } + +failed: + scard_deinit(scard); + + return 0; +#undef num_triplets +} + + +static int scard_get_triplets(int argc, char *argv[]) +{ + struct scard_data *scard; + size_t len; + char imsi[20]; + unsigned char _rand[16]; + unsigned char sres[4]; + unsigned char kc[8]; + int num_triplets; + int i; + size_t j; + + if (argc < 2 || ((num_triplets = atoi(argv[1])) <= 0)) { + printf("invalid parameters for sim command\n"); + return -1; + } + + if (argc <= 2 || os_strcmp(argv[2], "debug") != 0) { + /* disable debug output */ + wpa_debug_level = 99; + } + + scard = scard_init(SCARD_GSM_SIM_ONLY); + if (scard == NULL) { + printf("Failed to open smartcard connection\n"); + return -1; + } + if (scard_set_pin(scard, argv[0])) { + wpa_printf(MSG_WARNING, "PIN validation failed"); + scard_deinit(scard); + return -1; + } + + len = sizeof(imsi); + if (scard_get_imsi(scard, imsi, &len)) { + scard_deinit(scard); + return -1; + } + + for (i = 0; i < num_triplets; i++) { + os_memset(_rand, i, sizeof(_rand)); + if (scard_gsm_auth(scard, _rand, sres, kc)) + break; + + /* IMSI:Kc:SRES:RAND */ + for (j = 0; j < len; j++) + printf("%c", imsi[j]); + printf(":"); + for (j = 0; j < 8; j++) + printf("%02X", kc[j]); + printf(":"); + for (j = 0; j < 4; j++) + printf("%02X", sres[j]); + printf(":"); + for (j = 0; j < 16; j++) + printf("%02X", _rand[j]); + printf("\n"); + } + + scard_deinit(scard); + + return 0; +} + + +static void eapol_test_terminate(int sig, void *eloop_ctx, + void *signal_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + wpa_msg(wpa_s, MSG_INFO, "Signal %d received - terminating", sig); + eloop_terminate(); +} + + +static void usage(void) +{ + printf("usage:\n" + "eapol_test [-nWS] -c<conf> [-a<AS IP>] [-p<AS port>] " + "[-s<AS secret>]\\\n" + " [-r<count>] [-t<timeout>] [-C<Connect-Info>] \\\n" + " [-M<client MAC address>] \\\n" + " [-N<attr spec>] \\\n" + " [-A<client IP>]\n" + "eapol_test scard\n" + "eapol_test sim <PIN> <num triplets> [debug]\n" + "\n"); + printf("options:\n" + " -c<conf> = configuration file\n" + " -a<AS IP> = IP address of the authentication server, " + "default 127.0.0.1\n" + " -p<AS port> = UDP port of the authentication server, " + "default 1812\n" + " -s<AS secret> = shared secret with the authentication " + "server, default 'radius'\n" + " -A<client IP> = IP address of the client, default: select " + "automatically\n" + " -r<count> = number of re-authentications\n" + " -W = wait for a control interface monitor before starting\n" + " -S = save configuration after authentication\n" + " -n = no MPPE keys expected\n" + " -t<timeout> = sets timeout in seconds (default: 30 s)\n" + " -C<Connect-Info> = RADIUS Connect-Info (default: " + "CONNECT 11Mbps 802.11b)\n" + " -M<client MAC address> = Set own MAC address " + "(Calling-Station-Id,\n" + " default: 02:00:00:00:00:01)\n" + " -N<attr spec> = send arbitrary attribute specified by:\n" + " attr_id:syntax:value or attr_id\n" + " attr_id - number id of the attribute\n" + " syntax - one of: s, d, x\n" + " s = string\n" + " d = integer\n" + " x = octet string\n" + " value - attribute value.\n" + " When only attr_id is specified, NULL will be used as " + "value.\n" + " Multiple attributes can be specified by using the " + "option several times.\n"); +} + + +int main(int argc, char *argv[]) +{ + struct wpa_supplicant wpa_s; + int c, ret = 1, wait_for_monitor = 0, save_config = 0; + char *as_addr = "127.0.0.1"; + int as_port = 1812; + char *as_secret = "radius"; + char *cli_addr = NULL; + char *conf = NULL; + int timeout = 30; + char *pos; + struct extra_radius_attr *p = NULL, *p1; + + if (os_program_init()) + return -1; + + hostapd_logger_register_cb(hostapd_logger_cb); + + os_memset(&eapol_test, 0, sizeof(eapol_test)); + eapol_test.connect_info = "CONNECT 11Mbps 802.11b"; + os_memcpy(eapol_test.own_addr, "\x02\x00\x00\x00\x00\x01", ETH_ALEN); + + wpa_debug_level = 0; + wpa_debug_show_keys = 1; + + for (;;) { + c = getopt(argc, argv, "a:A:c:C:M:nN:p:r:s:St:W"); + if (c < 0) + break; + switch (c) { + case 'a': + as_addr = optarg; + break; + case 'A': + cli_addr = optarg; + break; + case 'c': + conf = optarg; + break; + case 'C': + eapol_test.connect_info = optarg; + break; + case 'M': + if (hwaddr_aton(optarg, eapol_test.own_addr)) { + usage(); + return -1; + } + break; + case 'n': + eapol_test.no_mppe_keys++; + break; + case 'p': + as_port = atoi(optarg); + break; + case 'r': + eapol_test.eapol_test_num_reauths = atoi(optarg); + break; + case 's': + as_secret = optarg; + break; + case 'S': + save_config++; + break; + case 't': + timeout = atoi(optarg); + break; + case 'W': + wait_for_monitor++; + break; + case 'N': + p1 = os_zalloc(sizeof(p1)); + if (p1 == NULL) + break; + if (!p) + eapol_test.extra_attrs = p1; + else + p->next = p1; + p = p1; + + p->type = atoi(optarg); + pos = os_strchr(optarg, ':'); + if (pos == NULL) { + p->syntax = 'n'; + p->data = NULL; + break; + } + + pos++; + if (pos[0] == '\0' || pos[1] != ':') { + printf("Incorrect format of attribute " + "specification\n"); + break; + } + + p->syntax = pos[0]; + p->data = pos + 2; + break; + default: + usage(); + return -1; + } + } + + if (argc > optind && os_strcmp(argv[optind], "scard") == 0) { + return scard_test(); + } + + if (argc > optind && os_strcmp(argv[optind], "sim") == 0) { + return scard_get_triplets(argc - optind - 1, + &argv[optind + 1]); + } + + if (conf == NULL) { + usage(); + printf("Configuration file is required.\n"); + return -1; + } + + if (eap_peer_register_methods()) { + wpa_printf(MSG_ERROR, "Failed to register EAP methods"); + return -1; + } + + if (eloop_init(&wpa_s)) { + wpa_printf(MSG_ERROR, "Failed to initialize event loop"); + return -1; + } + + os_memset(&wpa_s, 0, sizeof(wpa_s)); + eapol_test.wpa_s = &wpa_s; + wpa_s.conf = wpa_config_read(conf); + if (wpa_s.conf == NULL) { + printf("Failed to parse configuration file '%s'.\n", conf); + return -1; + } + if (wpa_s.conf->ssid == NULL) { + printf("No networks defined.\n"); + return -1; + } + + wpa_init_conf(&eapol_test, &wpa_s, as_addr, as_port, as_secret, + cli_addr); + wpa_s.ctrl_iface = wpa_supplicant_ctrl_iface_init(&wpa_s); + if (wpa_s.ctrl_iface == NULL) { + printf("Failed to initialize control interface '%s'.\n" + "You may have another eapol_test process already " + "running or the file was\n" + "left by an unclean termination of eapol_test in " + "which case you will need\n" + "to manually remove this file before starting " + "eapol_test again.\n", + wpa_s.conf->ctrl_interface); + return -1; + } + if (wpa_supplicant_scard_init(&wpa_s, wpa_s.conf->ssid)) + return -1; + + if (test_eapol(&eapol_test, &wpa_s, wpa_s.conf->ssid)) + return -1; + + if (wait_for_monitor) + wpa_supplicant_ctrl_iface_wait(wpa_s.ctrl_iface); + + eloop_register_timeout(timeout, 0, eapol_test_timeout, &eapol_test, + NULL); + eloop_register_timeout(0, 0, send_eap_request_identity, &wpa_s, NULL); + eloop_register_signal_terminate(eapol_test_terminate, NULL); + eloop_register_signal_reconfig(eapol_test_terminate, NULL); + eloop_run(); + + eloop_cancel_timeout(eapol_test_timeout, &eapol_test, NULL); + eloop_cancel_timeout(eapol_sm_reauth, &eapol_test, NULL); + + if (eapol_test_compare_pmk(&eapol_test) == 0 || + eapol_test.no_mppe_keys) + ret = 0; + if (eapol_test.auth_timed_out) + ret = -2; + if (eapol_test.radius_access_reject_received) + ret = -3; + + if (save_config) + wpa_config_write(conf, wpa_s.conf); + + test_eapol_clean(&eapol_test, &wpa_s); + + eap_peer_unregister_methods(); + + eloop_destroy(); + + printf("MPPE keys OK: %d mismatch: %d\n", + eapol_test.num_mppe_ok, eapol_test.num_mppe_mismatch); + if (eapol_test.num_mppe_mismatch) + ret = -4; + if (ret) + printf("FAILURE\n"); + else + printf("SUCCESS\n"); + + os_program_deinit(); + + return ret; +} diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c new file mode 100644 index 000000000000..dd4595a911f2 --- /dev/null +++ b/wpa_supplicant/events.c @@ -0,0 +1,1116 @@ +/* + * WPA Supplicant - Driver event processing + * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "eapol_supp/eapol_supp_sm.h" +#include "wpa.h" +#include "eloop.h" +#include "drivers/driver.h" +#include "config.h" +#include "l2_packet/l2_packet.h" +#include "wpa_supplicant_i.h" +#include "pcsc_funcs.h" +#include "preauth.h" +#include "pmksa_cache.h" +#include "wpa_ctrl.h" +#include "eap_peer/eap.h" +#include "ctrl_iface_dbus.h" +#include "ieee802_11_defs.h" +#include "blacklist.h" +#include "wpas_glue.h" +#include "wps_supplicant.h" + + +static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s) +{ + struct wpa_ssid *ssid; + + if (wpa_s->conf->ap_scan == 1 && wpa_s->current_ssid) + return 0; + + wpa_printf(MSG_DEBUG, "Select network based on association " + "information"); + ssid = wpa_supplicant_get_ssid(wpa_s); + if (ssid == NULL) { + wpa_printf(MSG_INFO, "No network configuration found for the " + "current AP"); + return -1; + } + + if (ssid->disabled) { + wpa_printf(MSG_DEBUG, "Selected network is disabled"); + return -1; + } + + wpa_printf(MSG_DEBUG, "Network configuration found for the current " + "AP"); + if (ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X | + WPA_KEY_MGMT_WPA_NONE | + WPA_KEY_MGMT_FT_PSK | WPA_KEY_MGMT_FT_IEEE8021X | + WPA_KEY_MGMT_PSK_SHA256 | + WPA_KEY_MGMT_IEEE8021X_SHA256)) { + u8 wpa_ie[80]; + size_t wpa_ie_len = sizeof(wpa_ie); + wpa_supplicant_set_suites(wpa_s, NULL, ssid, + wpa_ie, &wpa_ie_len); + } else { + wpa_supplicant_set_non_wpa_policy(wpa_s, ssid); + } + + if (wpa_s->current_ssid && wpa_s->current_ssid != ssid) + eapol_sm_invalidate_cached_session(wpa_s->eapol); + wpa_s->current_ssid = ssid; + wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid); + wpa_supplicant_initiate_eapol(wpa_s); + + return 0; +} + + +static void wpa_supplicant_stop_countermeasures(void *eloop_ctx, + void *sock_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + + if (wpa_s->countermeasures) { + wpa_s->countermeasures = 0; + wpa_drv_set_countermeasures(wpa_s, 0); + wpa_msg(wpa_s, MSG_INFO, "WPA: TKIP countermeasures stopped"); + wpa_supplicant_req_scan(wpa_s, 0, 0); + } +} + + +void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s) +{ + wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); + os_memset(wpa_s->bssid, 0, ETH_ALEN); + os_memset(wpa_s->pending_bssid, 0, ETH_ALEN); + eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE); + eapol_sm_notify_portValid(wpa_s->eapol, FALSE); + if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) + eapol_sm_notify_eap_success(wpa_s->eapol, FALSE); + wpa_s->ap_ies_from_associnfo = 0; +} + + +static void wpa_find_assoc_pmkid(struct wpa_supplicant *wpa_s) +{ + struct wpa_ie_data ie; + int pmksa_set = -1; + size_t i; + + if (wpa_sm_parse_own_wpa_ie(wpa_s->wpa, &ie) < 0 || + ie.pmkid == NULL) + return; + + for (i = 0; i < ie.num_pmkid; i++) { + pmksa_set = pmksa_cache_set_current(wpa_s->wpa, + ie.pmkid + i * PMKID_LEN, + NULL, NULL, 0); + if (pmksa_set == 0) { + eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1); + break; + } + } + + wpa_printf(MSG_DEBUG, "RSN: PMKID from assoc IE %sfound from PMKSA " + "cache", pmksa_set == 0 ? "" : "not "); +} + + +static void wpa_supplicant_event_pmkid_candidate(struct wpa_supplicant *wpa_s, + union wpa_event_data *data) +{ + if (data == NULL) { + wpa_printf(MSG_DEBUG, "RSN: No data in PMKID candidate event"); + return; + } + wpa_printf(MSG_DEBUG, "RSN: PMKID candidate event - bssid=" MACSTR + " index=%d preauth=%d", + MAC2STR(data->pmkid_candidate.bssid), + data->pmkid_candidate.index, + data->pmkid_candidate.preauth); + + pmksa_candidate_add(wpa_s->wpa, data->pmkid_candidate.bssid, + data->pmkid_candidate.index, + data->pmkid_candidate.preauth); +} + + +static int wpa_supplicant_dynamic_keys(struct wpa_supplicant *wpa_s) +{ + if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE || + wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) + return 0; + +#ifdef IEEE8021X_EAPOL + if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA && + wpa_s->current_ssid && + !(wpa_s->current_ssid->eapol_flags & + (EAPOL_FLAG_REQUIRE_KEY_UNICAST | + EAPOL_FLAG_REQUIRE_KEY_BROADCAST))) { + /* IEEE 802.1X, but not using dynamic WEP keys (i.e., either + * plaintext or static WEP keys). */ + return 0; + } +#endif /* IEEE8021X_EAPOL */ + + return 1; +} + + +/** + * wpa_supplicant_scard_init - Initialize SIM/USIM access with PC/SC + * @wpa_s: pointer to wpa_supplicant data + * @ssid: Configuration data for the network + * Returns: 0 on success, -1 on failure + * + * This function is called when starting authentication with a network that is + * configured to use PC/SC for SIM/USIM access (EAP-SIM or EAP-AKA). + */ +int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ +#ifdef IEEE8021X_EAPOL + int aka = 0, sim = 0, type; + + if (ssid->eap.pcsc == NULL || wpa_s->scard != NULL) + return 0; + + if (ssid->eap.eap_methods == NULL) { + sim = 1; + aka = 1; + } else { + struct eap_method_type *eap = ssid->eap.eap_methods; + while (eap->vendor != EAP_VENDOR_IETF || + eap->method != EAP_TYPE_NONE) { + if (eap->vendor == EAP_VENDOR_IETF) { + if (eap->method == EAP_TYPE_SIM) + sim = 1; + else if (eap->method == EAP_TYPE_AKA) + aka = 1; + } + eap++; + } + } + + if (eap_peer_get_eap_method(EAP_VENDOR_IETF, EAP_TYPE_SIM) == NULL) + sim = 0; + if (eap_peer_get_eap_method(EAP_VENDOR_IETF, EAP_TYPE_AKA) == NULL) + aka = 0; + + if (!sim && !aka) { + wpa_printf(MSG_DEBUG, "Selected network is configured to use " + "SIM, but neither EAP-SIM nor EAP-AKA are enabled"); + return 0; + } + + wpa_printf(MSG_DEBUG, "Selected network is configured to use SIM " + "(sim=%d aka=%d) - initialize PCSC", sim, aka); + if (sim && aka) + type = SCARD_TRY_BOTH; + else if (aka) + type = SCARD_USIM_ONLY; + else + type = SCARD_GSM_SIM_ONLY; + + wpa_s->scard = scard_init(type); + if (wpa_s->scard == NULL) { + wpa_printf(MSG_WARNING, "Failed to initialize SIM " + "(pcsc-lite)"); + return -1; + } + wpa_sm_set_scard_ctx(wpa_s->wpa, wpa_s->scard); + eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard); +#endif /* IEEE8021X_EAPOL */ + + return 0; +} + + +#ifndef CONFIG_NO_SCAN_PROCESSING +static int wpa_supplicant_match_privacy(struct wpa_scan_res *bss, + struct wpa_ssid *ssid) +{ + int i, privacy = 0; + + if (ssid->mixed_cell) + return 1; + + for (i = 0; i < NUM_WEP_KEYS; i++) { + if (ssid->wep_key_len[i]) { + privacy = 1; + break; + } + } +#ifdef IEEE8021X_EAPOL + if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && + ssid->eapol_flags & (EAPOL_FLAG_REQUIRE_KEY_UNICAST | + EAPOL_FLAG_REQUIRE_KEY_BROADCAST)) + privacy = 1; +#endif /* IEEE8021X_EAPOL */ + + if (bss->caps & IEEE80211_CAP_PRIVACY) + return privacy; + return !privacy; +} + + +static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, + struct wpa_scan_res *bss) +{ + struct wpa_ie_data ie; + int proto_match = 0; + const u8 *rsn_ie, *wpa_ie; + int ret; + + ret = wpas_wps_ssid_bss_match(wpa_s, ssid, bss); + if (ret >= 0) + return ret; + + rsn_ie = wpa_scan_get_ie(bss, WLAN_EID_RSN); + while ((ssid->proto & WPA_PROTO_RSN) && rsn_ie) { + proto_match++; + + if (wpa_parse_wpa_ie(rsn_ie, 2 + rsn_ie[1], &ie)) { + wpa_printf(MSG_DEBUG, " skip RSN IE - parse failed"); + break; + } + if (!(ie.proto & ssid->proto)) { + wpa_printf(MSG_DEBUG, " skip RSN IE - proto " + "mismatch"); + break; + } + + if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) { + wpa_printf(MSG_DEBUG, " skip RSN IE - PTK cipher " + "mismatch"); + break; + } + + if (!(ie.group_cipher & ssid->group_cipher)) { + wpa_printf(MSG_DEBUG, " skip RSN IE - GTK cipher " + "mismatch"); + break; + } + + if (!(ie.key_mgmt & ssid->key_mgmt)) { + wpa_printf(MSG_DEBUG, " skip RSN IE - key mgmt " + "mismatch"); + break; + } + +#ifdef CONFIG_IEEE80211W + if (!(ie.capabilities & WPA_CAPABILITY_MFPC) && + ssid->ieee80211w == IEEE80211W_REQUIRED) { + wpa_printf(MSG_DEBUG, " skip RSN IE - no mgmt frame " + "protection"); + break; + } +#endif /* CONFIG_IEEE80211W */ + + wpa_printf(MSG_DEBUG, " selected based on RSN IE"); + return 1; + } + + wpa_ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); + while ((ssid->proto & WPA_PROTO_WPA) && wpa_ie) { + proto_match++; + + if (wpa_parse_wpa_ie(wpa_ie, 2 + wpa_ie[1], &ie)) { + wpa_printf(MSG_DEBUG, " skip WPA IE - parse failed"); + break; + } + if (!(ie.proto & ssid->proto)) { + wpa_printf(MSG_DEBUG, " skip WPA IE - proto " + "mismatch"); + break; + } + + if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) { + wpa_printf(MSG_DEBUG, " skip WPA IE - PTK cipher " + "mismatch"); + break; + } + + if (!(ie.group_cipher & ssid->group_cipher)) { + wpa_printf(MSG_DEBUG, " skip WPA IE - GTK cipher " + "mismatch"); + break; + } + + if (!(ie.key_mgmt & ssid->key_mgmt)) { + wpa_printf(MSG_DEBUG, " skip WPA IE - key mgmt " + "mismatch"); + break; + } + + wpa_printf(MSG_DEBUG, " selected based on WPA IE"); + return 1; + } + + if (proto_match == 0) + wpa_printf(MSG_DEBUG, " skip - no WPA/RSN proto match"); + + return 0; +} + + +static struct wpa_scan_res * +wpa_supplicant_select_bss_wpa(struct wpa_supplicant *wpa_s, + struct wpa_ssid *group, + struct wpa_ssid **selected_ssid) +{ + struct wpa_ssid *ssid; + struct wpa_scan_res *bss; + size_t i; + struct wpa_blacklist *e; + const u8 *ie; + + wpa_printf(MSG_DEBUG, "Try to find WPA-enabled AP"); + for (i = 0; i < wpa_s->scan_res->num; i++) { + const u8 *ssid_; + u8 wpa_ie_len, rsn_ie_len, ssid_len; + bss = wpa_s->scan_res->res[i]; + + ie = wpa_scan_get_ie(bss, WLAN_EID_SSID); + ssid_ = ie ? ie + 2 : (u8 *) ""; + ssid_len = ie ? ie[1] : 0; + + ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); + wpa_ie_len = ie ? ie[1] : 0; + + ie = wpa_scan_get_ie(bss, WLAN_EID_RSN); + rsn_ie_len = ie ? ie[1] : 0; + + wpa_printf(MSG_DEBUG, "%d: " MACSTR " ssid='%s' " + "wpa_ie_len=%u rsn_ie_len=%u caps=0x%x", + (int) i, MAC2STR(bss->bssid), + wpa_ssid_txt(ssid_, ssid_len), + wpa_ie_len, rsn_ie_len, bss->caps); + + e = wpa_blacklist_get(wpa_s, bss->bssid); + if (e && e->count > 1) { + wpa_printf(MSG_DEBUG, " skip - blacklisted"); + continue; + } + + if (wpa_ie_len == 0 && rsn_ie_len == 0) { + wpa_printf(MSG_DEBUG, " skip - no WPA/RSN IE"); + continue; + } + + for (ssid = group; ssid; ssid = ssid->pnext) { + int check_ssid = 1; + + if (ssid->disabled) { + wpa_printf(MSG_DEBUG, " skip - disabled"); + continue; + } + +#ifdef CONFIG_WPS + if (ssid->ssid_len == 0 && + wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss)) + check_ssid = 0; +#endif /* CONFIG_WPS */ + + if (check_ssid && + (ssid_len != ssid->ssid_len || + os_memcmp(ssid_, ssid->ssid, ssid_len) != 0)) { + wpa_printf(MSG_DEBUG, " skip - " + "SSID mismatch"); + continue; + } + + if (ssid->bssid_set && + os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) + { + wpa_printf(MSG_DEBUG, " skip - " + "BSSID mismatch"); + continue; + } + + if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss)) + continue; + + wpa_printf(MSG_DEBUG, " selected WPA AP " + MACSTR " ssid='%s'", + MAC2STR(bss->bssid), + wpa_ssid_txt(ssid_, ssid_len)); + *selected_ssid = ssid; + return bss; + } + } + + return NULL; +} + + +static struct wpa_scan_res * +wpa_supplicant_select_bss_non_wpa(struct wpa_supplicant *wpa_s, + struct wpa_ssid *group, + struct wpa_ssid **selected_ssid) +{ + struct wpa_ssid *ssid; + struct wpa_scan_res *bss; + size_t i; + struct wpa_blacklist *e; + const u8 *ie; + + wpa_printf(MSG_DEBUG, "Try to find non-WPA AP"); + for (i = 0; i < wpa_s->scan_res->num; i++) { + const u8 *ssid_; + u8 wpa_ie_len, rsn_ie_len, ssid_len; + bss = wpa_s->scan_res->res[i]; + + ie = wpa_scan_get_ie(bss, WLAN_EID_SSID); + ssid_ = ie ? ie + 2 : (u8 *) ""; + ssid_len = ie ? ie[1] : 0; + + ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); + wpa_ie_len = ie ? ie[1] : 0; + + ie = wpa_scan_get_ie(bss, WLAN_EID_RSN); + rsn_ie_len = ie ? ie[1] : 0; + + wpa_printf(MSG_DEBUG, "%d: " MACSTR " ssid='%s' " + "wpa_ie_len=%u rsn_ie_len=%u caps=0x%x", + (int) i, MAC2STR(bss->bssid), + wpa_ssid_txt(ssid_, ssid_len), + wpa_ie_len, rsn_ie_len, bss->caps); + + e = wpa_blacklist_get(wpa_s, bss->bssid); + if (e && e->count > 1) { + wpa_printf(MSG_DEBUG, " skip - blacklisted"); + continue; + } + + for (ssid = group; ssid; ssid = ssid->pnext) { + int check_ssid = ssid->ssid_len != 0; + + if (ssid->disabled) { + wpa_printf(MSG_DEBUG, " skip - disabled"); + continue; + } + +#ifdef CONFIG_WPS + if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) { + /* Only allow wildcard SSID match if an AP + * advertises active WPS operation that matches + * with our mode. */ + check_ssid = 1; + if (ssid->ssid_len == 0 && + wpas_wps_ssid_wildcard_ok(wpa_s, ssid, + bss)) + check_ssid = 0; + } +#endif /* CONFIG_WPS */ + + if (check_ssid && + (ssid_len != ssid->ssid_len || + os_memcmp(ssid_, ssid->ssid, ssid_len) != 0)) { + wpa_printf(MSG_DEBUG, " skip - " + "SSID mismatch"); + continue; + } + + if (ssid->bssid_set && + os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) + { + wpa_printf(MSG_DEBUG, " skip - " + "BSSID mismatch"); + continue; + } + + if (!(ssid->key_mgmt & WPA_KEY_MGMT_NONE) && + !(ssid->key_mgmt & WPA_KEY_MGMT_WPS) && + !(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) + { + wpa_printf(MSG_DEBUG, " skip - " + "non-WPA network not allowed"); + continue; + } + + if ((ssid->key_mgmt & + (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK | + WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK | + WPA_KEY_MGMT_IEEE8021X_SHA256 | + WPA_KEY_MGMT_PSK_SHA256)) && + (wpa_ie_len != 0 || rsn_ie_len != 0)) { + wpa_printf(MSG_DEBUG, " skip - " + "WPA network"); + continue; + } + + if (!wpa_supplicant_match_privacy(bss, ssid)) { + wpa_printf(MSG_DEBUG, " skip - " + "privacy mismatch"); + continue; + } + + if (bss->caps & IEEE80211_CAP_IBSS) { + wpa_printf(MSG_DEBUG, " skip - " + "IBSS (adhoc) network"); + continue; + } + + wpa_printf(MSG_DEBUG, " selected non-WPA AP " + MACSTR " ssid='%s'", + MAC2STR(bss->bssid), + wpa_ssid_txt(ssid_, ssid_len)); + *selected_ssid = ssid; + return bss; + } + } + + return NULL; +} + + +static struct wpa_scan_res * +wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, struct wpa_ssid *group, + struct wpa_ssid **selected_ssid) +{ + struct wpa_scan_res *selected; + + wpa_printf(MSG_DEBUG, "Selecting BSS from priority group %d", + group->priority); + + /* First, try to find WPA-enabled AP */ + selected = wpa_supplicant_select_bss_wpa(wpa_s, group, selected_ssid); + if (selected) + return selected; + + /* If no WPA-enabled AP found, try to find non-WPA AP, if configuration + * allows this. */ + return wpa_supplicant_select_bss_non_wpa(wpa_s, group, selected_ssid); +} + + +static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s) +{ + int prio, timeout; + struct wpa_scan_res *selected = NULL; + struct wpa_ssid *ssid = NULL; + + if (wpa_supplicant_get_scan_results(wpa_s) < 0) { + if (wpa_s->conf->ap_scan == 2) + return; + wpa_printf(MSG_DEBUG, "Failed to get scan results - try " + "scanning again"); + timeout = 1; + goto req_scan; + } + + /* + * Don't post the results if this was the initial cached + * and there were no results. + */ + if (wpa_s->scan_res_tried == 1 && wpa_s->conf->ap_scan == 1 && + wpa_s->scan_res->num == 0) { + wpa_msg(wpa_s, MSG_DEBUG, "Cached scan results are " + "empty - not posting"); + } else { + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS); + wpa_supplicant_dbus_notify_scan_results(wpa_s); + wpas_wps_notify_scan_results(wpa_s); + } + + if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s)) || + wpa_s->disconnected) + return; + + while (selected == NULL) { + for (prio = 0; prio < wpa_s->conf->num_prio; prio++) { + selected = wpa_supplicant_select_bss( + wpa_s, wpa_s->conf->pssid[prio], &ssid); + if (selected) + break; + } + + if (selected == NULL && wpa_s->blacklist) { + wpa_printf(MSG_DEBUG, "No APs found - clear blacklist " + "and try again"); + wpa_blacklist_clear(wpa_s); + wpa_s->blacklist_cleared++; + } else if (selected == NULL) { + break; + } + } + + if (selected) { + if (wpas_wps_scan_pbc_overlap(wpa_s, selected, ssid)) { + wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OVERLAP + "PBC session overlap"); + timeout = 10; + goto req_scan; + } + + /* Do not trigger new association unless the BSSID has changed + * or if reassociation is requested. If we are in process of + * associating with the selected BSSID, do not trigger new + * attempt. */ + if (wpa_s->reassociate || + (os_memcmp(selected->bssid, wpa_s->bssid, ETH_ALEN) != 0 && + (wpa_s->wpa_state != WPA_ASSOCIATING || + os_memcmp(selected->bssid, wpa_s->pending_bssid, + ETH_ALEN) != 0))) { + if (wpa_supplicant_scard_init(wpa_s, ssid)) { + wpa_supplicant_req_scan(wpa_s, 10, 0); + return; + } + wpa_supplicant_associate(wpa_s, selected, ssid); + } else { + wpa_printf(MSG_DEBUG, "Already associated with the " + "selected AP."); + } + rsn_preauth_scan_results(wpa_s->wpa, wpa_s->scan_res); + } else { + wpa_printf(MSG_DEBUG, "No suitable AP found."); + timeout = 5; + goto req_scan; + } + + return; + +req_scan: + if (wpa_s->scan_res_tried == 1 && wpa_s->conf->ap_scan == 1) { + /* + * Quick recovery if the initial scan results were not + * complete when fetched before the first scan request. + */ + wpa_s->scan_res_tried++; + timeout = 0; + } + wpa_supplicant_req_scan(wpa_s, timeout, 0); +} +#endif /* CONFIG_NO_SCAN_PROCESSING */ + + +static void wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, + union wpa_event_data *data) +{ + int l, len, found = 0, wpa_found, rsn_found; + u8 *p; + + wpa_printf(MSG_DEBUG, "Association info event"); + if (data->assoc_info.req_ies) + wpa_hexdump(MSG_DEBUG, "req_ies", data->assoc_info.req_ies, + data->assoc_info.req_ies_len); + if (data->assoc_info.resp_ies) + wpa_hexdump(MSG_DEBUG, "resp_ies", data->assoc_info.resp_ies, + data->assoc_info.resp_ies_len); + if (data->assoc_info.beacon_ies) + wpa_hexdump(MSG_DEBUG, "beacon_ies", + data->assoc_info.beacon_ies, + data->assoc_info.beacon_ies_len); + + p = data->assoc_info.req_ies; + l = data->assoc_info.req_ies_len; + + /* Go through the IEs and make a copy of the WPA/RSN IE, if present. */ + while (p && l >= 2) { + len = p[1] + 2; + if (len > l) { + wpa_hexdump(MSG_DEBUG, "Truncated IE in assoc_info", + p, l); + break; + } + if ((p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 && + (os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) || + (p[0] == WLAN_EID_RSN && p[1] >= 2)) { + if (wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, p, len)) + break; + found = 1; + wpa_find_assoc_pmkid(wpa_s); + break; + } + l -= len; + p += len; + } + if (!found && data->assoc_info.req_ies) + wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0); + + /* WPA/RSN IE from Beacon/ProbeResp */ + p = data->assoc_info.beacon_ies; + l = data->assoc_info.beacon_ies_len; + + /* Go through the IEs and make a copy of the WPA/RSN IEs, if present. + */ + wpa_found = rsn_found = 0; + while (p && l >= 2) { + len = p[1] + 2; + if (len > l) { + wpa_hexdump(MSG_DEBUG, "Truncated IE in beacon_ies", + p, l); + break; + } + if (!wpa_found && + p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 && + os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0) { + wpa_found = 1; + wpa_sm_set_ap_wpa_ie(wpa_s->wpa, p, len); + } + + if (!rsn_found && + p[0] == WLAN_EID_RSN && p[1] >= 2) { + rsn_found = 1; + wpa_sm_set_ap_rsn_ie(wpa_s->wpa, p, len); + } + + l -= len; + p += len; + } + + if (!wpa_found && data->assoc_info.beacon_ies) + wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0); + if (!rsn_found && data->assoc_info.beacon_ies) + wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0); + if (wpa_found || rsn_found) + wpa_s->ap_ies_from_associnfo = 1; +} + + +static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, + union wpa_event_data *data) +{ + u8 bssid[ETH_ALEN]; + int ft_completed = wpa_ft_is_completed(wpa_s->wpa); + + if (data) + wpa_supplicant_event_associnfo(wpa_s, data); + + wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED); + if (wpa_s->use_client_mlme) + os_memcpy(bssid, wpa_s->bssid, ETH_ALEN); + if (wpa_s->use_client_mlme || + (wpa_drv_get_bssid(wpa_s, bssid) >= 0 && + os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0)) { + wpa_msg(wpa_s, MSG_DEBUG, "Associated to a new BSS: BSSID=" + MACSTR, MAC2STR(bssid)); + os_memcpy(wpa_s->bssid, bssid, ETH_ALEN); + os_memset(wpa_s->pending_bssid, 0, ETH_ALEN); + if (wpa_supplicant_dynamic_keys(wpa_s) && !ft_completed) { + wpa_clear_keys(wpa_s, bssid); + } + if (wpa_supplicant_select_config(wpa_s) < 0) { + wpa_supplicant_disassociate( + wpa_s, WLAN_REASON_DEAUTH_LEAVING); + return; + } + } + + wpa_msg(wpa_s, MSG_INFO, "Associated with " MACSTR, MAC2STR(bssid)); + if (wpa_s->current_ssid) { + /* When using scanning (ap_scan=1), SIM PC/SC interface can be + * initialized before association, but for other modes, + * initialize PC/SC here, if the current configuration needs + * smartcard or SIM/USIM. */ + wpa_supplicant_scard_init(wpa_s, wpa_s->current_ssid); + } + wpa_sm_notify_assoc(wpa_s->wpa, bssid); + l2_packet_notify_auth_start(wpa_s->l2); + + /* + * Set portEnabled first to FALSE in order to get EAP state machine out + * of the SUCCESS state and eapSuccess cleared. Without this, EAPOL PAE + * state machine may transit to AUTHENTICATING state based on obsolete + * eapSuccess and then trigger BE_AUTH to SUCCESS and PAE to + * AUTHENTICATED without ever giving chance to EAP state machine to + * reset the state. + */ + if (!ft_completed) { + eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE); + eapol_sm_notify_portValid(wpa_s->eapol, FALSE); + } + if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) || ft_completed) + eapol_sm_notify_eap_success(wpa_s->eapol, FALSE); + /* 802.1X::portControl = Auto */ + eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE); + wpa_s->eapol_received = 0; + if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE || + wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) { + wpa_supplicant_cancel_auth_timeout(wpa_s); + wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); + } else if (!ft_completed) { + /* Timeout for receiving the first EAPOL packet */ + wpa_supplicant_req_auth_timeout(wpa_s, 10, 0); + } + wpa_supplicant_cancel_scan(wpa_s); + + if (wpa_s->driver_4way_handshake && + wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) { + /* + * We are done; the driver will take care of RSN 4-way + * handshake. + */ + wpa_supplicant_cancel_auth_timeout(wpa_s); + wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); + eapol_sm_notify_portValid(wpa_s->eapol, TRUE); + eapol_sm_notify_eap_success(wpa_s->eapol, TRUE); + } +} + + +static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s) +{ + const u8 *bssid; + + if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) { + /* + * At least Host AP driver and a Prism3 card seemed to be + * generating streams of disconnected events when configuring + * IBSS for WPA-None. Ignore them for now. + */ + wpa_printf(MSG_DEBUG, "Disconnect event - ignore in " + "IBSS/WPA-None mode"); + return; + } + + if (wpa_s->wpa_state == WPA_4WAY_HANDSHAKE && + wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) { + wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - " + "pre-shared key may be incorrect"); + } + if (wpa_s->wpa_state >= WPA_ASSOCIATED) + wpa_supplicant_req_scan(wpa_s, 0, 100000); + bssid = wpa_s->bssid; + if (is_zero_ether_addr(bssid)) + bssid = wpa_s->pending_bssid; + wpa_blacklist_add(wpa_s, bssid); + wpa_sm_notify_disassoc(wpa_s->wpa); + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "- Disconnect event - " + "remove keys"); + if (wpa_supplicant_dynamic_keys(wpa_s)) { + wpa_s->keys_cleared = 0; + wpa_clear_keys(wpa_s, wpa_s->bssid); + } + wpa_supplicant_mark_disassoc(wpa_s); +} + + +#ifdef CONFIG_DELAYED_MIC_ERROR_REPORT +static void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx, + void *sock_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + + if (!wpa_s->pending_mic_error_report) + return; + + wpa_printf(MSG_DEBUG, "WPA: Sending pending MIC error report"); + wpa_sm_key_request(wpa_s->wpa, 1, wpa_s->pending_mic_error_pairwise); + wpa_s->pending_mic_error_report = 0; +} +#endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */ + + +static void +wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s, + union wpa_event_data *data) +{ + int pairwise; + struct os_time t; + + wpa_msg(wpa_s, MSG_WARNING, "Michael MIC failure detected"); + pairwise = (data && data->michael_mic_failure.unicast); + os_get_time(&t); + if ((wpa_s->last_michael_mic_error && + t.sec - wpa_s->last_michael_mic_error <= 60) || + wpa_s->pending_mic_error_report) { + if (wpa_s->pending_mic_error_report) { + /* + * Send the pending MIC error report immediately since + * we are going to start countermeasures and AP better + * do the same. + */ + wpa_sm_key_request(wpa_s->wpa, 1, + wpa_s->pending_mic_error_pairwise); + } + + /* Send the new MIC error report immediately since we are going + * to start countermeasures and AP better do the same. + */ + wpa_sm_key_request(wpa_s->wpa, 1, pairwise); + + /* initialize countermeasures */ + wpa_s->countermeasures = 1; + wpa_msg(wpa_s, MSG_WARNING, "TKIP countermeasures started"); + + /* + * Need to wait for completion of request frame. We do not get + * any callback for the message completion, so just wait a + * short while and hope for the best. */ + os_sleep(0, 10000); + + wpa_drv_set_countermeasures(wpa_s, 1); + wpa_supplicant_deauthenticate(wpa_s, + WLAN_REASON_MICHAEL_MIC_FAILURE); + eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, + wpa_s, NULL); + eloop_register_timeout(60, 0, + wpa_supplicant_stop_countermeasures, + wpa_s, NULL); + /* TODO: mark the AP rejected for 60 second. STA is + * allowed to associate with another AP.. */ + } else { +#ifdef CONFIG_DELAYED_MIC_ERROR_REPORT + if (wpa_s->mic_errors_seen) { + /* + * Reduce the effectiveness of Michael MIC error + * reports as a means for attacking against TKIP if + * more than one MIC failure is noticed with the same + * PTK. We delay the transmission of the reports by a + * random time between 0 and 60 seconds in order to + * force the attacker wait 60 seconds before getting + * the information on whether a frame resulted in a MIC + * failure. + */ + u8 rval[4]; + int sec; + + if (os_get_random(rval, sizeof(rval)) < 0) + sec = os_random() % 60; + else + sec = WPA_GET_BE32(rval) % 60; + wpa_printf(MSG_DEBUG, "WPA: Delay MIC error report %d " + "seconds", sec); + wpa_s->pending_mic_error_report = 1; + wpa_s->pending_mic_error_pairwise = pairwise; + eloop_cancel_timeout( + wpa_supplicant_delayed_mic_error_report, + wpa_s, NULL); + eloop_register_timeout( + sec, os_random() % 1000000, + wpa_supplicant_delayed_mic_error_report, + wpa_s, NULL); + } else { + wpa_sm_key_request(wpa_s->wpa, 1, pairwise); + } +#else /* CONFIG_DELAYED_MIC_ERROR_REPORT */ + wpa_sm_key_request(wpa_s->wpa, 1, pairwise); +#endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */ + } + wpa_s->last_michael_mic_error = t.sec; + wpa_s->mic_errors_seen++; +} + + +static void +wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s, + union wpa_event_data *data) +{ + if (os_strcmp(wpa_s->ifname, data->interface_status.ifname) != 0) + return; + + switch (data->interface_status.ievent) { + case EVENT_INTERFACE_ADDED: + if (!wpa_s->interface_removed) + break; + wpa_s->interface_removed = 0; + wpa_printf(MSG_DEBUG, "Configured interface was added."); + if (wpa_supplicant_driver_init(wpa_s) < 0) { + wpa_printf(MSG_INFO, "Failed to initialize the driver " + "after interface was added."); + } + break; + case EVENT_INTERFACE_REMOVED: + wpa_printf(MSG_DEBUG, "Configured interface was removed."); + wpa_s->interface_removed = 1; + wpa_supplicant_mark_disassoc(wpa_s); + l2_packet_deinit(wpa_s->l2); + wpa_s->l2 = NULL; + break; + } +} + + +#ifdef CONFIG_PEERKEY +static void +wpa_supplicant_event_stkstart(struct wpa_supplicant *wpa_s, + union wpa_event_data *data) +{ + if (data == NULL) + return; + wpa_sm_stkstart(wpa_s->wpa, data->stkstart.peer); +} +#endif /* CONFIG_PEERKEY */ + + +#ifdef CONFIG_IEEE80211R +static void +wpa_supplicant_event_ft_response(struct wpa_supplicant *wpa_s, + union wpa_event_data *data) +{ + if (data == NULL) + return; + + if (wpa_ft_process_response(wpa_s->wpa, data->ft_ies.ies, + data->ft_ies.ies_len, + data->ft_ies.ft_action, + data->ft_ies.target_ap) < 0) { + /* TODO: prevent MLME/driver from trying to associate? */ + } +} +#endif /* CONFIG_IEEE80211R */ + + +void wpa_supplicant_event(void *ctx, wpa_event_type event, + union wpa_event_data *data) +{ + struct wpa_supplicant *wpa_s = ctx; + + switch (event) { + case EVENT_ASSOC: + wpa_supplicant_event_assoc(wpa_s, data); + break; + case EVENT_DISASSOC: + wpa_supplicant_event_disassoc(wpa_s); + break; + case EVENT_MICHAEL_MIC_FAILURE: + wpa_supplicant_event_michael_mic_failure(wpa_s, data); + break; +#ifndef CONFIG_NO_SCAN_PROCESSING + case EVENT_SCAN_RESULTS: + wpa_supplicant_event_scan_results(wpa_s); + break; +#endif /* CONFIG_NO_SCAN_PROCESSING */ + case EVENT_ASSOCINFO: + wpa_supplicant_event_associnfo(wpa_s, data); + break; + case EVENT_INTERFACE_STATUS: + wpa_supplicant_event_interface_status(wpa_s, data); + break; + case EVENT_PMKID_CANDIDATE: + wpa_supplicant_event_pmkid_candidate(wpa_s, data); + break; +#ifdef CONFIG_PEERKEY + case EVENT_STKSTART: + wpa_supplicant_event_stkstart(wpa_s, data); + break; +#endif /* CONFIG_PEERKEY */ +#ifdef CONFIG_IEEE80211R + case EVENT_FT_RESPONSE: + wpa_supplicant_event_ft_response(wpa_s, data); + break; +#endif /* CONFIG_IEEE80211R */ + default: + wpa_printf(MSG_INFO, "Unknown event %d", event); + break; + } +} diff --git a/wpa_supplicant/examples/ieee8021x.conf b/wpa_supplicant/examples/ieee8021x.conf new file mode 100644 index 000000000000..e8a5503d8359 --- /dev/null +++ b/wpa_supplicant/examples/ieee8021x.conf @@ -0,0 +1,13 @@ +# IEEE 802.1X with dynamic WEP keys using EAP-PEAP/MSCHAPv2 + +ctrl_interface=/var/run/wpa_supplicant + +network={ + ssid="example 802.1x network" + key_mgmt=IEEE8021X + eap=PEAP + phase2="auth=MSCHAPV2" + identity="user name" + password="password" + ca_cert="/etc/cert/ca.pem" +} diff --git a/wpa_supplicant/examples/openCryptoki.conf b/wpa_supplicant/examples/openCryptoki.conf new file mode 100644 index 000000000000..e2301a61cabf --- /dev/null +++ b/wpa_supplicant/examples/openCryptoki.conf @@ -0,0 +1,41 @@ +# EAP-TLS using private key and certificates via OpenSSL PKCS#11 engine and +# openCryptoki (e.g., with TPM token) + +# This example uses following PKCS#11 objects: +# $ pkcs11-tool --module /usr/lib/opencryptoki/libopencryptoki.so -O -l +# Please enter User PIN: +# Private Key Object; RSA +# label: rsakey +# ID: 04 +# Usage: decrypt, sign, unwrap +# Certificate Object, type = X.509 cert +# label: ca +# ID: 01 +# Certificate Object, type = X.509 cert +# label: cert +# ID: 04 + +# Configure OpenSSL to load the PKCS#11 engine and openCryptoki module +pkcs11_engine_path=/usr/lib/engines/engine_pkcs11.so +pkcs11_module_path=/usr/lib/opencryptoki/libopencryptoki.so + +network={ + ssid="test network" + key_mgmt=WPA-EAP + eap=TLS + identity="User" + + # use OpenSSL PKCS#11 engine for this network + engine=1 + engine_id="pkcs11" + + # select the private key and certificates based on ID (see pkcs11-tool + # output above) + key_id="4" + cert_id="4" + ca_cert_id="1" + + # set the PIN code; leave this out to configure the PIN to be requested + # interactively when needed (e.g., via wpa_gui or wpa_cli) + pin="123456" +} diff --git a/wpa_supplicant/examples/plaintext.conf b/wpa_supplicant/examples/plaintext.conf new file mode 100644 index 000000000000..542ac1dd3b96 --- /dev/null +++ b/wpa_supplicant/examples/plaintext.conf @@ -0,0 +1,8 @@ +# Plaintext (no encryption) network + +ctrl_interface=/var/run/wpa_supplicant + +network={ + ssid="example open network" + key_mgmt=NONE +} diff --git a/wpa_supplicant/examples/wep.conf b/wpa_supplicant/examples/wep.conf new file mode 100644 index 000000000000..9c7b55f2722a --- /dev/null +++ b/wpa_supplicant/examples/wep.conf @@ -0,0 +1,11 @@ +# Static WEP keys + +ctrl_interface=/var/run/wpa_supplicant + +network={ + ssid="example wep network" + key_mgmt=NONE + wep_key0="abcde" + wep_key1=0102030405 + wep_tx_keyidx=0 +} diff --git a/wpa_supplicant/examples/wpa-psk-tkip.conf b/wpa_supplicant/examples/wpa-psk-tkip.conf new file mode 100644 index 000000000000..93d7fc2444ea --- /dev/null +++ b/wpa_supplicant/examples/wpa-psk-tkip.conf @@ -0,0 +1,12 @@ +# WPA-PSK/TKIP + +ctrl_interface=/var/run/wpa_supplicant + +network={ + ssid="example wpa-psk network" + key_mgmt=WPA-PSK + proto=WPA + pairwise=TKIP + group=TKIP + psk="secret passphrase" +} diff --git a/wpa_supplicant/examples/wpa2-eap-ccmp.conf b/wpa_supplicant/examples/wpa2-eap-ccmp.conf new file mode 100644 index 000000000000..d7a64d87b254 --- /dev/null +++ b/wpa_supplicant/examples/wpa2-eap-ccmp.conf @@ -0,0 +1,15 @@ +# WPA2-EAP/CCMP using EAP-TLS + +ctrl_interface=/var/run/wpa_supplicant + +network={ + ssid="example wpa2-eap network" + key_mgmt=WPA-EAP + proto=WPA2 + pairwise=CCMP + group=CCMP + eap=TLS + ca_cert="/etc/cert/ca.pem" + private_key="/etc/cert/user.p12" + private_key_passwd="PKCS#12 passhrase" +} diff --git a/wpa_supplicant/examples/wpas-test.py b/wpa_supplicant/examples/wpas-test.py new file mode 100755 index 000000000000..fd7f73d428b8 --- /dev/null +++ b/wpa_supplicant/examples/wpas-test.py @@ -0,0 +1,91 @@ +#!/usr/bin/python + +import dbus +import sys, os +import time + +WPAS_DBUS_SERVICE = "fi.epitest.hostap.WPASupplicant" +WPAS_DBUS_INTERFACE = "fi.epitest.hostap.WPASupplicant" +WPAS_DBUS_OPATH = "/fi/epitest/hostap/WPASupplicant" + +WPAS_DBUS_INTERFACES_INTERFACE = "fi.epitest.hostap.WPASupplicant.Interface" +WPAS_DBUS_INTERFACES_OPATH = "/fi/epitest/hostap/WPASupplicant/Interfaces" +WPAS_DBUS_BSSID_INTERFACE = "fi.epitest.hostap.WPASupplicant.BSSID" + +def byte_array_to_string(s): + import urllib + r = "" + for c in s: + if c >= 32 and c < 127: + r += "%c" % c + else: + r += urllib.quote(chr(c)) + return r + +def main(): + if len(sys.argv) != 2: + print "Usage: wpas-test.py <interface>" + os._exit(1) + + ifname = sys.argv[1] + + bus = dbus.SystemBus() + wpas_obj = bus.get_object(WPAS_DBUS_SERVICE, WPAS_DBUS_OPATH) + wpas = dbus.Interface(wpas_obj, WPAS_DBUS_INTERFACE) + + # See if wpa_supplicant already knows about this interface + path = None + try: + path = wpas.getInterface(ifname) + except dbus.dbus_bindings.DBusException, exc: + if str(exc) != "wpa_supplicant knows nothing about this interface.": + raise exc + try: + path = wpas.addInterface(ifname, {'driver': dbus.Variant('wext')}) + except dbus.dbus_bindings.DBusException, exc: + if str(exc) != "wpa_supplicant already controls this interface.": + raise exc + + if_obj = bus.get_object(WPAS_DBUS_SERVICE, path) + iface = dbus.Interface(if_obj, WPAS_DBUS_INTERFACES_INTERFACE) + iface.scan() + # Should really wait for the "scanResults" signal instead of sleeping + time.sleep(5) + res = iface.scanResults() + + print "Scanned wireless networks:" + for opath in res: + net_obj = bus.get_object(WPAS_DBUS_SERVICE, opath) + net = dbus.Interface(net_obj, WPAS_DBUS_BSSID_INTERFACE) + props = net.properties() + + # Convert the byte-array for SSID and BSSID to printable strings + bssid = "" + for item in props["bssid"]: + bssid = bssid + ":%02x" % item + bssid = bssid[1:] + ssid = byte_array_to_string(props["ssid"]) + wpa = "no" + if props.has_key("wpaie"): + wpa = "yes" + wpa2 = "no" + if props.has_key("rsnie"): + wpa2 = "yes" + freq = 0 + if props.has_key("frequency"): + freq = props["frequency"] + caps = props["capabilities"] + qual = props["quality"] + level = props["level"] + noise = props["noise"] + maxrate = props["maxrate"] / 1000000 + + print " %s :: ssid='%s' wpa=%s wpa2=%s quality=%d%% rate=%d freq=%d" % (bssid, ssid, wpa, wpa2, qual, maxrate, freq) + + wpas.removeInterface(dbus.ObjectPath(path)) + # Should fail here with unknown interface error + iface.scan() + +if __name__ == "__main__": + main() + diff --git a/wpa_supplicant/main.c b/wpa_supplicant/main.c new file mode 100644 index 000000000000..6f90cc509b36 --- /dev/null +++ b/wpa_supplicant/main.c @@ -0,0 +1,264 @@ +/* + * WPA Supplicant / main() function for UNIX like OSes and MinGW + * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" +#ifdef __linux__ +#include <fcntl.h> +#endif /* __linux__ */ + +#include "common.h" +#include "wpa_supplicant_i.h" + + +static void usage(void) +{ + int i; + printf("%s\n\n%s\n" + "usage:\n" + " wpa_supplicant [-BddhKLqqtuvW] [-P<pid file>] " + "[-g<global ctrl>] \\\n" + " -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] " + "[-p<driver_param>] \\\n" + " [-b<br_ifname>] [-f<debug file>] \\\n" + " [-N -i<ifname> -c<conf> [-C<ctrl>] " + "[-D<driver>] \\\n" + " [-p<driver_param>] [-b<br_ifname>] ...]\n" + "\n" + "drivers:\n", + wpa_supplicant_version, wpa_supplicant_license); + + for (i = 0; wpa_supplicant_drivers[i]; i++) { + printf(" %s = %s\n", + wpa_supplicant_drivers[i]->name, + wpa_supplicant_drivers[i]->desc); + } + +#ifndef CONFIG_NO_STDOUT_DEBUG + printf("options:\n" + " -b = optional bridge interface name\n" + " -B = run daemon in the background\n" + " -c = Configuration file\n" + " -C = ctrl_interface parameter (only used if -c is not)\n" + " -i = interface name\n" + " -d = increase debugging verbosity (-dd even more)\n" + " -D = driver name\n" +#ifdef CONFIG_DEBUG_FILE + " -f = log output to debug file instead of stdout\n" +#endif /* CONFIG_DEBUG_FILE */ + " -g = global ctrl_interface\n" + " -K = include keys (passwords, etc.) in debug output\n" + " -t = include timestamp in debug messages\n" + " -h = show this help text\n" + " -L = show license (GPL and BSD)\n"); + printf(" -p = driver parameters\n" + " -P = PID file\n" + " -q = decrease debugging verbosity (-qq even less)\n" +#ifdef CONFIG_CTRL_IFACE_DBUS + " -u = enable DBus control interface\n" +#endif /* CONFIG_CTRL_IFACE_DBUS */ + " -v = show version\n" + " -W = wait for a control interface monitor before starting\n" + " -N = start describing new interface\n"); + + printf("example:\n" + " wpa_supplicant -Dwext -iwlan0 -c/etc/wpa_supplicant.conf\n"); +#endif /* CONFIG_NO_STDOUT_DEBUG */ +} + + +static void license(void) +{ +#ifndef CONFIG_NO_STDOUT_DEBUG + printf("%s\n\n%s%s%s%s%s\n", + wpa_supplicant_version, + wpa_supplicant_full_license1, + wpa_supplicant_full_license2, + wpa_supplicant_full_license3, + wpa_supplicant_full_license4, + wpa_supplicant_full_license5); +#endif /* CONFIG_NO_STDOUT_DEBUG */ +} + + +static void wpa_supplicant_fd_workaround(void) +{ +#ifdef __linux__ + int s, i; + /* When started from pcmcia-cs scripts, wpa_supplicant might start with + * fd 0, 1, and 2 closed. This will cause some issues because many + * places in wpa_supplicant are still printing out to stdout. As a + * workaround, make sure that fd's 0, 1, and 2 are not used for other + * sockets. */ + for (i = 0; i < 3; i++) { + s = open("/dev/null", O_RDWR); + if (s > 2) { + close(s); + break; + } + } +#endif /* __linux__ */ +} + + +int main(int argc, char *argv[]) +{ + int c, i; + struct wpa_interface *ifaces, *iface; + int iface_count, exitcode = -1; + struct wpa_params params; + struct wpa_global *global; + + if (os_program_init()) + return -1; + + os_memset(¶ms, 0, sizeof(params)); + params.wpa_debug_level = MSG_INFO; + + iface = ifaces = os_zalloc(sizeof(struct wpa_interface)); + if (ifaces == NULL) + return -1; + iface_count = 1; + + wpa_supplicant_fd_workaround(); + + for (;;) { + c = getopt(argc, argv, "b:Bc:C:D:df:g:hi:KLNp:P:qtuvW"); + if (c < 0) + break; + switch (c) { + case 'b': + iface->bridge_ifname = optarg; + break; + case 'B': + params.daemonize++; + break; + case 'c': + iface->confname = optarg; + break; + case 'C': + iface->ctrl_interface = optarg; + break; + case 'D': + iface->driver = optarg; + break; + case 'd': +#ifdef CONFIG_NO_STDOUT_DEBUG + printf("Debugging disabled with " + "CONFIG_NO_STDOUT_DEBUG=y build time " + "option.\n"); + goto out; +#else /* CONFIG_NO_STDOUT_DEBUG */ + params.wpa_debug_level--; + break; +#endif /* CONFIG_NO_STDOUT_DEBUG */ +#ifdef CONFIG_DEBUG_FILE + case 'f': + params.wpa_debug_file_path = optarg; + break; +#endif /* CONFIG_DEBUG_FILE */ + case 'g': + params.ctrl_interface = optarg; + break; + case 'h': + usage(); + exitcode = 0; + goto out; + case 'i': + iface->ifname = optarg; + break; + case 'K': + params.wpa_debug_show_keys++; + break; + case 'L': + license(); + exitcode = 0; + goto out; + case 'p': + iface->driver_param = optarg; + break; + case 'P': + os_free(params.pid_file); + params.pid_file = os_rel2abs_path(optarg); + break; + case 'q': + params.wpa_debug_level++; + break; + case 't': + params.wpa_debug_timestamp++; + break; +#ifdef CONFIG_CTRL_IFACE_DBUS + case 'u': + params.dbus_ctrl_interface = 1; + break; +#endif /* CONFIG_CTRL_IFACE_DBUS */ + case 'v': + printf("%s\n", wpa_supplicant_version); + exitcode = 0; + goto out; + case 'W': + params.wait_for_monitor++; + break; + case 'N': + iface_count++; + iface = os_realloc(ifaces, iface_count * + sizeof(struct wpa_interface)); + if (iface == NULL) + goto out; + ifaces = iface; + iface = &ifaces[iface_count - 1]; + os_memset(iface, 0, sizeof(*iface)); + break; + default: + usage(); + exitcode = 0; + goto out; + } + } + + exitcode = 0; + global = wpa_supplicant_init(¶ms); + if (global == NULL) { + wpa_printf(MSG_ERROR, "Failed to initialize wpa_supplicant"); + exitcode = -1; + goto out; + } + + for (i = 0; exitcode == 0 && i < iface_count; i++) { + if ((ifaces[i].confname == NULL && + ifaces[i].ctrl_interface == NULL) || + ifaces[i].ifname == NULL) { + if (iface_count == 1 && (params.ctrl_interface || + params.dbus_ctrl_interface)) + break; + usage(); + exitcode = -1; + break; + } + if (wpa_supplicant_add_iface(global, &ifaces[i]) == NULL) + exitcode = -1; + } + + if (exitcode == 0) + exitcode = wpa_supplicant_run(global); + + wpa_supplicant_deinit(global); + +out: + os_free(ifaces); + os_free(params.pid_file); + + os_program_deinit(); + + return exitcode; +} diff --git a/wpa_supplicant/main_none.c b/wpa_supplicant/main_none.c new file mode 100644 index 000000000000..993338a9f900 --- /dev/null +++ b/wpa_supplicant/main_none.c @@ -0,0 +1,46 @@ +/* + * WPA Supplicant / Example program entrypoint + * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "wpa_supplicant_i.h" + +int main(int argc, char *argv[]) +{ + struct wpa_interface iface; + int exitcode = 0; + struct wpa_params params; + struct wpa_global *global; + + memset(¶ms, 0, sizeof(params)); + params.wpa_debug_level = MSG_INFO; + + global = wpa_supplicant_init(¶ms); + if (global == NULL) + return -1; + + memset(&iface, 0, sizeof(iface)); + /* TODO: set interface parameters */ + + if (wpa_supplicant_add_iface(global, &iface) == NULL) + exitcode = -1; + + if (exitcode == 0) + exitcode = wpa_supplicant_run(global); + + wpa_supplicant_deinit(global); + + return exitcode; +} diff --git a/wpa_supplicant/main_symbian.cpp b/wpa_supplicant/main_symbian.cpp new file mode 100644 index 000000000000..4ff364be3cca --- /dev/null +++ b/wpa_supplicant/main_symbian.cpp @@ -0,0 +1,48 @@ +/* + * WPA Supplicant / Program entrypoint for Symbian + * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +extern "C" { +#include "common.h" +#include "wpa_supplicant_i.h" +} + +GLDEF_C TInt E32Main(void) +{ + struct wpa_interface iface; + int exitcode = 0; + struct wpa_params params; + struct wpa_global *global; + + memset(¶ms, 0, sizeof(params)); + params.wpa_debug_level = MSG_INFO; + + global = wpa_supplicant_init(¶ms); + if (global == NULL) + return -1; + + memset(&iface, 0, sizeof(iface)); + /* TODO: set interface parameters */ + + if (wpa_supplicant_add_iface(global, &iface) == NULL) + exitcode = -1; + + if (exitcode == 0) + exitcode = wpa_supplicant_run(global); + + wpa_supplicant_deinit(global); + + return exitcode; +} diff --git a/wpa_supplicant/main_winmain.c b/wpa_supplicant/main_winmain.c new file mode 100644 index 000000000000..19d9950ab34e --- /dev/null +++ b/wpa_supplicant/main_winmain.c @@ -0,0 +1,84 @@ +/* + * WPA Supplicant / WinMain() function for Windows-based applications + * Copyright (c) 2006, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "wpa_supplicant_i.h" + +#ifdef _WIN32_WCE +#define CMDLINE LPWSTR +#else /* _WIN32_WCE */ +#define CMDLINE LPSTR +#endif /* _WIN32_WCE */ + + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, + CMDLINE lpCmdLine, int nShowCmd) +{ + int i; + struct wpa_interface *ifaces, *iface; + int iface_count, exitcode = -1; + struct wpa_params params; + struct wpa_global *global; + + if (os_program_init()) + return -1; + + os_memset(¶ms, 0, sizeof(params)); + params.wpa_debug_level = MSG_MSGDUMP; + params.wpa_debug_file_path = "\\Temp\\wpa_supplicant-log.txt"; + params.wpa_debug_show_keys = 1; + + iface = ifaces = os_zalloc(sizeof(struct wpa_interface)); + if (ifaces == NULL) + return -1; + iface_count = 1; + + iface->confname = "default"; + iface->driver = "ndis"; + iface->ifname = ""; + + exitcode = 0; + global = wpa_supplicant_init(¶ms); + if (global == NULL) { + printf("Failed to initialize wpa_supplicant\n"); + exitcode = -1; + } + + for (i = 0; exitcode == 0 && i < iface_count; i++) { + if ((ifaces[i].confname == NULL && + ifaces[i].ctrl_interface == NULL) || + ifaces[i].ifname == NULL) { + if (iface_count == 1 && (params.ctrl_interface || + params.dbus_ctrl_interface)) + break; + exitcode = -1; + break; + } + if (wpa_supplicant_add_iface(global, &ifaces[i]) == NULL) + exitcode = -1; + } + + if (exitcode == 0) + exitcode = wpa_supplicant_run(global); + + wpa_supplicant_deinit(global); + + os_free(ifaces); + + os_program_deinit(); + + return exitcode; +} diff --git a/wpa_supplicant/main_winsvc.c b/wpa_supplicant/main_winsvc.c new file mode 100644 index 000000000000..4a46ed5f1049 --- /dev/null +++ b/wpa_supplicant/main_winsvc.c @@ -0,0 +1,464 @@ +/* + * WPA Supplicant / main() function for Win32 service + * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + * + * The root of wpa_supplicant configuration in registry is + * HKEY_LOCAL_MACHINE\\SOFTWARE\\%wpa_supplicant. This level includes global + * parameters and a 'interfaces' subkey with all the interface configuration + * (adapter to confname mapping). Each such mapping is a subkey that has + * 'adapter' and 'config' values. + * + * This program can be run either as a normal command line application, e.g., + * for debugging, with 'wpasvc.exe app' or as a Windows service. Service need + * to be registered with 'wpasvc.exe reg <full path to wpasvc.exe>'. After + * this, it can be started like any other Windows service (e.g., 'net start + * wpasvc') or it can be configured to start automatically through the Services + * tool in administrative tasks. The service can be unregistered with + * 'wpasvc.exe unreg'. + */ + +#include "includes.h" +#include <windows.h> + +#include "common.h" +#include "wpa_supplicant_i.h" +#include "eloop.h" + +#ifndef WPASVC_NAME +#define WPASVC_NAME TEXT("wpasvc") +#endif +#ifndef WPASVC_DISPLAY_NAME +#define WPASVC_DISPLAY_NAME TEXT("wpa_supplicant service") +#endif +#ifndef WPASVC_DESCRIPTION +#define WPASVC_DESCRIPTION \ +TEXT("Provides IEEE 802.1X and WPA/WPA2 supplicant functionality") +#endif + +static HANDLE kill_svc; + +static SERVICE_STATUS_HANDLE svc_status_handle; +static SERVICE_STATUS svc_status; + + +#ifndef WPA_KEY_ROOT +#define WPA_KEY_ROOT HKEY_LOCAL_MACHINE +#endif +#ifndef WPA_KEY_PREFIX +#define WPA_KEY_PREFIX TEXT("SOFTWARE\\wpa_supplicant") +#endif + +#ifdef UNICODE +#define TSTR "%S" +#else /* UNICODE */ +#define TSTR "%s" +#endif /* UNICODE */ + + +static int read_interface(struct wpa_global *global, HKEY _hk, + const TCHAR *name) +{ + HKEY hk; +#define TBUFLEN 255 + TCHAR adapter[TBUFLEN], config[TBUFLEN], ctrl_interface[TBUFLEN]; + DWORD buflen, val; + LONG ret; + struct wpa_interface iface; + int skip_on_error = 0; + + ret = RegOpenKeyEx(_hk, name, 0, KEY_QUERY_VALUE, &hk); + if (ret != ERROR_SUCCESS) { + printf("Could not open wpa_supplicant interface key\n"); + return -1; + } + + os_memset(&iface, 0, sizeof(iface)); + iface.driver = "ndis"; + + buflen = sizeof(ctrl_interface); + ret = RegQueryValueEx(hk, TEXT("ctrl_interface"), NULL, NULL, + (LPBYTE) ctrl_interface, &buflen); + if (ret == ERROR_SUCCESS) { + ctrl_interface[TBUFLEN - 1] = TEXT('\0'); + wpa_unicode2ascii_inplace(ctrl_interface); + printf("ctrl_interface[len=%d] '%s'\n", + (int) buflen, (char *) ctrl_interface); + iface.ctrl_interface = (char *) ctrl_interface; + } + + buflen = sizeof(adapter); + ret = RegQueryValueEx(hk, TEXT("adapter"), NULL, NULL, + (LPBYTE) adapter, &buflen); + if (ret == ERROR_SUCCESS) { + adapter[TBUFLEN - 1] = TEXT('\0'); + wpa_unicode2ascii_inplace(adapter); + printf("adapter[len=%d] '%s'\n", + (int) buflen, (char *) adapter); + iface.ifname = (char *) adapter; + } + + buflen = sizeof(config); + ret = RegQueryValueEx(hk, TEXT("config"), NULL, NULL, + (LPBYTE) config, &buflen); + if (ret == ERROR_SUCCESS) { + config[sizeof(config) - 1] = '\0'; + wpa_unicode2ascii_inplace(config); + printf("config[len=%d] '%s'\n", + (int) buflen, (char *) config); + iface.confname = (char *) config; + } + + buflen = sizeof(val); + ret = RegQueryValueEx(hk, TEXT("skip_on_error"), NULL, NULL, + (LPBYTE) &val, &buflen); + if (ret == ERROR_SUCCESS && buflen == sizeof(val)) + skip_on_error = val; + + RegCloseKey(hk); + + if (wpa_supplicant_add_iface(global, &iface) == NULL) { + if (skip_on_error) + wpa_printf(MSG_DEBUG, "Skipped interface '%s' due to " + "initialization failure", iface.ifname); + else + return -1; + } + + return 0; +} + + +static int wpa_supplicant_thread(void) +{ + int exitcode; + struct wpa_params params; + struct wpa_global *global; + HKEY hk, ihk; + DWORD val, buflen, i; + LONG ret; + + if (os_program_init()) + return -1; + + os_memset(¶ms, 0, sizeof(params)); + params.wpa_debug_level = MSG_INFO; + + ret = RegOpenKeyEx(WPA_KEY_ROOT, WPA_KEY_PREFIX, + 0, KEY_QUERY_VALUE, &hk); + if (ret != ERROR_SUCCESS) { + printf("Could not open wpa_supplicant registry key\n"); + return -1; + } + + buflen = sizeof(val); + ret = RegQueryValueEx(hk, TEXT("debug_level"), NULL, NULL, + (LPBYTE) &val, &buflen); + if (ret == ERROR_SUCCESS && buflen == sizeof(val)) { + params.wpa_debug_level = val; + } + + buflen = sizeof(val); + ret = RegQueryValueEx(hk, TEXT("debug_show_keys"), NULL, NULL, + (LPBYTE) &val, &buflen); + if (ret == ERROR_SUCCESS && buflen == sizeof(val)) { + params.wpa_debug_show_keys = val; + } + + buflen = sizeof(val); + ret = RegQueryValueEx(hk, TEXT("debug_timestamp"), NULL, NULL, + (LPBYTE) &val, &buflen); + if (ret == ERROR_SUCCESS && buflen == sizeof(val)) { + params.wpa_debug_timestamp = val; + } + + buflen = sizeof(val); + ret = RegQueryValueEx(hk, TEXT("debug_use_file"), NULL, NULL, + (LPBYTE) &val, &buflen); + if (ret == ERROR_SUCCESS && buflen == sizeof(val) && val) { + params.wpa_debug_file_path = "\\Temp\\wpa_supplicant-log.txt"; + } + + exitcode = 0; + global = wpa_supplicant_init(¶ms); + if (global == NULL) { + printf("Failed to initialize wpa_supplicant\n"); + exitcode = -1; + } + + ret = RegOpenKeyEx(hk, TEXT("interfaces"), 0, KEY_ENUMERATE_SUB_KEYS, + &ihk); + RegCloseKey(hk); + if (ret != ERROR_SUCCESS) { + printf("Could not open wpa_supplicant interfaces registry " + "key\n"); + return -1; + } + + for (i = 0; ; i++) { + TCHAR name[255]; + DWORD namelen; + + namelen = 255; + ret = RegEnumKeyEx(ihk, i, name, &namelen, NULL, NULL, NULL, + NULL); + + if (ret == ERROR_NO_MORE_ITEMS) + break; + + if (ret != ERROR_SUCCESS) { + printf("RegEnumKeyEx failed: 0x%x\n", + (unsigned int) ret); + break; + } + + if (namelen >= 255) + namelen = 255 - 1; + name[namelen] = '\0'; + + wpa_printf(MSG_DEBUG, "interface %d: %s\n", (int) i, name); + if (read_interface(global, ihk, name) < 0) + exitcode = -1; + } + + RegCloseKey(ihk); + + if (exitcode == 0) + exitcode = wpa_supplicant_run(global); + + wpa_supplicant_deinit(global); + + os_program_deinit(); + + return exitcode; +} + + +static DWORD svc_thread(LPDWORD param) +{ + int ret = wpa_supplicant_thread(); + + svc_status.dwCurrentState = SERVICE_STOPPED; + svc_status.dwWaitHint = 0; + if (!SetServiceStatus(svc_status_handle, &svc_status)) { + printf("SetServiceStatus() failed: %d\n", + (int) GetLastError()); + } + + return ret; +} + + +static int register_service(const TCHAR *exe) +{ + SC_HANDLE svc, scm; + SERVICE_DESCRIPTION sd; + + printf("Registering service: " TSTR "\n", WPASVC_NAME); + + scm = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE); + if (!scm) { + printf("OpenSCManager failed: %d\n", (int) GetLastError()); + return -1; + } + + svc = CreateService(scm, WPASVC_NAME, WPASVC_DISPLAY_NAME, + SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, + SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, + exe, NULL, NULL, NULL, NULL, NULL); + + if (!svc) { + printf("CreateService failed: %d\n\n", (int) GetLastError()); + CloseServiceHandle(scm); + return -1; + } + + os_memset(&sd, 0, sizeof(sd)); + sd.lpDescription = WPASVC_DESCRIPTION; + if (!ChangeServiceConfig2(svc, SERVICE_CONFIG_DESCRIPTION, &sd)) { + printf("ChangeServiceConfig2 failed: %d\n", + (int) GetLastError()); + /* This is not a fatal error, so continue anyway. */ + } + + CloseServiceHandle(svc); + CloseServiceHandle(scm); + + printf("Service registered successfully.\n"); + + return 0; +} + + +static int unregister_service(void) +{ + SC_HANDLE svc, scm; + SERVICE_STATUS status; + + printf("Unregistering service: " TSTR "\n", WPASVC_NAME); + + scm = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE); + if (!scm) { + printf("OpenSCManager failed: %d\n", (int) GetLastError()); + return -1; + } + + svc = OpenService(scm, WPASVC_NAME, SERVICE_ALL_ACCESS | DELETE); + if (!svc) { + printf("OpenService failed: %d\n\n", (int) GetLastError()); + CloseServiceHandle(scm); + return -1; + } + + if (QueryServiceStatus(svc, &status)) { + if (status.dwCurrentState != SERVICE_STOPPED) { + printf("Service currently active - stopping " + "service...\n"); + if (!ControlService(svc, SERVICE_CONTROL_STOP, + &status)) { + printf("ControlService failed: %d\n", + (int) GetLastError()); + } + Sleep(500); + } + } + + if (DeleteService(svc)) { + printf("Service unregistered successfully.\n"); + } else { + printf("DeleteService failed: %d\n", (int) GetLastError()); + } + + CloseServiceHandle(svc); + CloseServiceHandle(scm); + + return 0; +} + + +static void WINAPI service_ctrl_handler(DWORD control_code) +{ + switch (control_code) { + case SERVICE_CONTROL_INTERROGATE: + break; + case SERVICE_CONTROL_SHUTDOWN: + case SERVICE_CONTROL_STOP: + svc_status.dwCurrentState = SERVICE_STOP_PENDING; + svc_status.dwWaitHint = 2000; + eloop_terminate(); + SetEvent(kill_svc); + break; + } + + if (!SetServiceStatus(svc_status_handle, &svc_status)) { + printf("SetServiceStatus() failed: %d\n", + (int) GetLastError()); + } +} + + +static void WINAPI service_start(DWORD argc, LPTSTR *argv) +{ + DWORD id; + + svc_status_handle = RegisterServiceCtrlHandler(WPASVC_NAME, + service_ctrl_handler); + if (svc_status_handle == (SERVICE_STATUS_HANDLE) 0) { + printf("RegisterServiceCtrlHandler failed: %d\n", + (int) GetLastError()); + return; + } + + os_memset(&svc_status, 0, sizeof(svc_status)); + svc_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + svc_status.dwCurrentState = SERVICE_START_PENDING; + svc_status.dwWaitHint = 1000; + + if (!SetServiceStatus(svc_status_handle, &svc_status)) { + printf("SetServiceStatus() failed: %d\n", + (int) GetLastError()); + return; + } + + kill_svc = CreateEvent(0, TRUE, FALSE, 0); + if (!kill_svc) { + printf("CreateEvent failed: %d\n", (int) GetLastError()); + return; + } + + if (CreateThread(0, 0, (LPTHREAD_START_ROUTINE) svc_thread, 0, 0, &id) + == 0) { + printf("CreateThread failed: %d\n", (int) GetLastError()); + return; + } + + if (svc_status.dwCurrentState == SERVICE_START_PENDING) { + svc_status.dwCurrentState = SERVICE_RUNNING; + svc_status.dwWaitHint = 0; + svc_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | + SERVICE_ACCEPT_SHUTDOWN; + } + + if (!SetServiceStatus(svc_status_handle, &svc_status)) { + printf("SetServiceStatus() failed: %d\n", + (int) GetLastError()); + return; + } + + /* wait until service gets killed */ + WaitForSingleObject(kill_svc, INFINITE); +} + + +int main(int argc, char *argv[]) +{ + SERVICE_TABLE_ENTRY dt[] = { + { WPASVC_NAME, service_start }, + { NULL, NULL } + }; + + if (argc > 1) { + if (os_strcmp(argv[1], "reg") == 0) { + TCHAR *path; + int ret; + + if (argc < 3) { + path = os_malloc(MAX_PATH * sizeof(TCHAR)); + if (path == NULL) + return -1; + if (!GetModuleFileName(NULL, path, MAX_PATH)) { + printf("GetModuleFileName failed: " + "%d\n", (int) GetLastError()); + os_free(path); + return -1; + } + } else { + path = wpa_strdup_tchar(argv[2]); + if (path == NULL) + return -1; + } + ret = register_service(path); + os_free(path); + return ret; + } else if (os_strcmp(argv[1], "unreg") == 0) { + return unregister_service(); + } else if (os_strcmp(argv[1], "app") == 0) { + return wpa_supplicant_thread(); + } + } + + if (!StartServiceCtrlDispatcher(dt)) { + printf("StartServiceCtrlDispatcher failed: %d\n", + (int) GetLastError()); + } + + return 0; +} diff --git a/wpa_supplicant/mlme.c b/wpa_supplicant/mlme.c new file mode 100644 index 000000000000..0c630673a09a --- /dev/null +++ b/wpa_supplicant/mlme.c @@ -0,0 +1,2994 @@ +/* + * WPA Supplicant - Client mode MLME + * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004, Instant802 Networks, Inc. + * Copyright (c) 2005-2006, Devicescape Software, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "eloop.h" +#include "config_ssid.h" +#include "wpa_supplicant_i.h" +#include "wpa.h" +#include "drivers/driver.h" +#include "ieee802_11_defs.h" +#include "ieee802_11_common.h" +#include "mlme.h" + + +/* Timeouts and intervals in milliseconds */ +#define IEEE80211_AUTH_TIMEOUT (200) +#define IEEE80211_AUTH_MAX_TRIES 3 +#define IEEE80211_ASSOC_TIMEOUT (200) +#define IEEE80211_ASSOC_MAX_TRIES 3 +#define IEEE80211_MONITORING_INTERVAL (2000) +#define IEEE80211_PROBE_INTERVAL (60000) +#define IEEE80211_RETRY_AUTH_INTERVAL (1000) +#define IEEE80211_SCAN_INTERVAL (2000) +#define IEEE80211_SCAN_INTERVAL_SLOW (15000) +#define IEEE80211_IBSS_JOIN_TIMEOUT (20000) + +#define IEEE80211_PROBE_DELAY (33) +#define IEEE80211_CHANNEL_TIME (33) +#define IEEE80211_PASSIVE_CHANNEL_TIME (200) +#define IEEE80211_SCAN_RESULT_EXPIRE (10000) +#define IEEE80211_IBSS_MERGE_INTERVAL (30000) +#define IEEE80211_IBSS_INACTIVITY_LIMIT (60000) + +#define IEEE80211_IBSS_MAX_STA_ENTRIES 128 + + +#define IEEE80211_FC(type, stype) host_to_le16((type << 2) | (stype << 4)) + + +struct ieee80211_sta_bss { + struct ieee80211_sta_bss *next; + struct ieee80211_sta_bss *hnext; + + u8 bssid[ETH_ALEN]; + u8 ssid[MAX_SSID_LEN]; + size_t ssid_len; + u16 capability; /* host byte order */ + int hw_mode; + int channel; + int freq; + int rssi; + u8 *ie; + size_t ie_len; + u8 *wpa_ie; + size_t wpa_ie_len; + u8 *rsn_ie; + size_t rsn_ie_len; + u8 *wmm_ie; + size_t wmm_ie_len; + u8 *mdie; + size_t mdie_len; +#define IEEE80211_MAX_SUPP_RATES 32 + u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; + size_t supp_rates_len; + int beacon_int; + u64 timestamp; + + int probe_resp; + struct os_time last_update; +}; + + +static void ieee80211_send_probe_req(struct wpa_supplicant *wpa_s, + const u8 *dst, + const u8 *ssid, size_t ssid_len); +static struct ieee80211_sta_bss * +ieee80211_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid); +static int ieee80211_sta_find_ibss(struct wpa_supplicant *wpa_s); +static int ieee80211_sta_wep_configured(struct wpa_supplicant *wpa_s); +static void ieee80211_sta_timer(void *eloop_ctx, void *timeout_ctx); +static void ieee80211_sta_scan_timer(void *eloop_ctx, void *timeout_ctx); + + +static int ieee80211_sta_set_channel(struct wpa_supplicant *wpa_s, + wpa_hw_mode phymode, int chan, + int freq) +{ + size_t i; + struct wpa_hw_modes *mode; + + for (i = 0; i < wpa_s->mlme.num_modes; i++) { + mode = &wpa_s->mlme.modes[i]; + if (mode->mode == phymode) { + wpa_s->mlme.curr_rates = mode->rates; + wpa_s->mlme.num_curr_rates = mode->num_rates; + break; + } + } + + return wpa_drv_set_channel(wpa_s, phymode, chan, freq); +} + + + +#if 0 /* FIX */ +static int ecw2cw(int ecw) +{ + int cw = 1; + while (ecw > 0) { + cw <<= 1; + ecw--; + } + return cw - 1; +} +#endif + + +static void ieee80211_sta_wmm_params(struct wpa_supplicant *wpa_s, + u8 *wmm_param, size_t wmm_param_len) +{ + size_t left; + int count; + u8 *pos; + + if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) + return; + count = wmm_param[6] & 0x0f; + if (count == wpa_s->mlme.wmm_last_param_set) + return; + wpa_s->mlme.wmm_last_param_set = count; + + pos = wmm_param + 8; + left = wmm_param_len - 8; + +#if 0 /* FIX */ + wmm_acm = 0; + for (; left >= 4; left -= 4, pos += 4) { + int aci = (pos[0] >> 5) & 0x03; + int acm = (pos[0] >> 4) & 0x01; + int queue; + + switch (aci) { + case 1: + queue = IEEE80211_TX_QUEUE_DATA3; + if (acm) + wmm_acm |= BIT(1) | BIT(2); + break; + case 2: + queue = IEEE80211_TX_QUEUE_DATA1; + if (acm) + wmm_acm |= BIT(4) | BIT(5); + break; + case 3: + queue = IEEE80211_TX_QUEUE_DATA0; + if (acm) + wmm_acm |= BIT(6) | BIT(7); + break; + case 0: + default: + queue = IEEE80211_TX_QUEUE_DATA2; + if (acm) + wpa_s->mlme.wmm_acm |= BIT(0) | BIT(3); + break; + } + + params.aifs = pos[0] & 0x0f; + params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4); + params.cw_min = ecw2cw(pos[1] & 0x0f); + /* TXOP is in units of 32 usec; burst_time in 0.1 ms */ + params.burst_time = (pos[2] | (pos[3] << 8)) * 32 / 100; + wpa_printf(MSG_DEBUG, "MLME: WMM queue=%d aci=%d acm=%d " + "aifs=%d cWmin=%d cWmax=%d burst=%d", + queue, aci, acm, params.aifs, params.cw_min, + params.cw_max, params.burst_time); + /* TODO: handle ACM (block TX, fallback to next lowest allowed + * AC for now) */ + if (local->hw->conf_tx(local->mdev, queue, ¶ms)) { + wpa_printf(MSG_DEBUG, "MLME: failed to set TX queue " + "parameters for queue %d", queue); + } + } +#endif +} + + +static void ieee80211_set_associated(struct wpa_supplicant *wpa_s, int assoc) +{ + if (wpa_s->mlme.associated == assoc && !assoc) + return; + + wpa_s->mlme.associated = assoc; + + if (assoc) { + union wpa_event_data data; + os_memset(&data, 0, sizeof(data)); + wpa_s->mlme.prev_bssid_set = 1; + os_memcpy(wpa_s->mlme.prev_bssid, wpa_s->bssid, ETH_ALEN); + data.assoc_info.req_ies = wpa_s->mlme.assocreq_ies; + data.assoc_info.req_ies_len = wpa_s->mlme.assocreq_ies_len; + data.assoc_info.resp_ies = wpa_s->mlme.assocresp_ies; + data.assoc_info.resp_ies_len = wpa_s->mlme.assocresp_ies_len; + wpa_supplicant_event(wpa_s, EVENT_ASSOC, &data); + } else { + wpa_supplicant_event(wpa_s, EVENT_DISASSOC, NULL); + } + os_get_time(&wpa_s->mlme.last_probe); +} + + +static int ieee80211_sta_tx(struct wpa_supplicant *wpa_s, const u8 *buf, + size_t len) +{ + return wpa_drv_send_mlme(wpa_s, buf, len); +} + + +static void ieee80211_send_auth(struct wpa_supplicant *wpa_s, + int transaction, u8 *extra, size_t extra_len, + int encrypt) +{ + u8 *buf; + size_t len; + struct ieee80211_mgmt *mgmt; + + buf = os_malloc(sizeof(*mgmt) + 6 + extra_len); + if (buf == NULL) { + wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for " + "auth frame"); + return; + } + + mgmt = (struct ieee80211_mgmt *) buf; + len = 24 + 6; + os_memset(mgmt, 0, 24 + 6); + mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_AUTH); + if (encrypt) + mgmt->frame_control |= host_to_le16(WLAN_FC_ISWEP); + os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); + os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); + os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); + mgmt->u.auth.auth_alg = host_to_le16(wpa_s->mlme.auth_alg); + mgmt->u.auth.auth_transaction = host_to_le16(transaction); + wpa_s->mlme.auth_transaction = transaction + 1; + mgmt->u.auth.status_code = host_to_le16(0); + if (extra) { + os_memcpy(buf + len, extra, extra_len); + len += extra_len; + } + + ieee80211_sta_tx(wpa_s, buf, len); + os_free(buf); +} + + +static void ieee80211_reschedule_timer(struct wpa_supplicant *wpa_s, int ms) +{ + eloop_cancel_timeout(ieee80211_sta_timer, wpa_s, NULL); + eloop_register_timeout(ms / 1000, 1000 * (ms % 1000), + ieee80211_sta_timer, wpa_s, NULL); +} + + +static void ieee80211_authenticate(struct wpa_supplicant *wpa_s) +{ + u8 *extra; + size_t extra_len; + + wpa_s->mlme.auth_tries++; + if (wpa_s->mlme.auth_tries > IEEE80211_AUTH_MAX_TRIES) { + wpa_printf(MSG_DEBUG, "MLME: authentication with AP " MACSTR + " timed out", MAC2STR(wpa_s->bssid)); + return; + } + + wpa_s->mlme.state = IEEE80211_AUTHENTICATE; + wpa_printf(MSG_DEBUG, "MLME: authenticate with AP " MACSTR, + MAC2STR(wpa_s->bssid)); + + extra = NULL; + extra_len = 0; + +#ifdef CONFIG_IEEE80211R + if ((wpa_s->mlme.key_mgmt == KEY_MGMT_FT_802_1X || + wpa_s->mlme.key_mgmt == KEY_MGMT_FT_PSK) && + wpa_s->mlme.ft_ies) { + struct ieee80211_sta_bss *bss; + struct rsn_mdie *mdie = NULL; + bss = ieee80211_bss_get(wpa_s, wpa_s->bssid); + if (bss && bss->mdie_len >= 2 + sizeof(*mdie)) + mdie = (struct rsn_mdie *) (bss->mdie + 2); + if (mdie && + os_memcmp(mdie->mobility_domain, wpa_s->mlme.current_md, + MOBILITY_DOMAIN_ID_LEN) == 0) { + wpa_printf(MSG_DEBUG, "MLME: Trying to use FT " + "over-the-air"); + wpa_s->mlme.auth_alg = WLAN_AUTH_FT; + extra = wpa_s->mlme.ft_ies; + extra_len = wpa_s->mlme.ft_ies_len; + } + } +#endif /* CONFIG_IEEE80211R */ + + ieee80211_send_auth(wpa_s, 1, extra, extra_len, 0); + + ieee80211_reschedule_timer(wpa_s, IEEE80211_AUTH_TIMEOUT); +} + + +static void ieee80211_send_assoc(struct wpa_supplicant *wpa_s) +{ + struct ieee80211_mgmt *mgmt; + u8 *pos, *ies, *buf; + int i, len; + u16 capab; + struct ieee80211_sta_bss *bss; + int wmm = 0; + size_t blen, buflen; + + if (wpa_s->mlme.curr_rates == NULL) { + wpa_printf(MSG_DEBUG, "MLME: curr_rates not set for assoc"); + return; + } + + buflen = sizeof(*mgmt) + 200 + wpa_s->mlme.extra_ie_len + + wpa_s->mlme.ssid_len; +#ifdef CONFIG_IEEE80211R + if (wpa_s->mlme.ft_ies) + buflen += wpa_s->mlme.ft_ies_len; +#endif /* CONFIG_IEEE80211R */ + buf = os_malloc(buflen); + if (buf == NULL) { + wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for " + "assoc frame"); + return; + } + blen = 0; + + capab = wpa_s->mlme.capab; + if (wpa_s->mlme.phymode == WPA_MODE_IEEE80211G) { + capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME | + WLAN_CAPABILITY_SHORT_PREAMBLE; + } + bss = ieee80211_bss_get(wpa_s, wpa_s->bssid); + if (bss) { + if (bss->capability & WLAN_CAPABILITY_PRIVACY) + capab |= WLAN_CAPABILITY_PRIVACY; + if (bss->wmm_ie) { + wmm = 1; + } + } + + mgmt = (struct ieee80211_mgmt *) buf; + blen += 24; + os_memset(mgmt, 0, 24); + os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); + os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); + os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); + + if (wpa_s->mlme.prev_bssid_set) { + blen += 10; + mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_REASSOC_REQ); + mgmt->u.reassoc_req.capab_info = host_to_le16(capab); + mgmt->u.reassoc_req.listen_interval = host_to_le16(1); + os_memcpy(mgmt->u.reassoc_req.current_ap, + wpa_s->mlme.prev_bssid, + ETH_ALEN); + } else { + blen += 4; + mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_ASSOC_REQ); + mgmt->u.assoc_req.capab_info = host_to_le16(capab); + mgmt->u.assoc_req.listen_interval = host_to_le16(1); + } + + /* SSID */ + ies = pos = buf + blen; + blen += 2 + wpa_s->mlme.ssid_len; + *pos++ = WLAN_EID_SSID; + *pos++ = wpa_s->mlme.ssid_len; + os_memcpy(pos, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len); + + len = wpa_s->mlme.num_curr_rates; + if (len > 8) + len = 8; + pos = buf + blen; + blen += len + 2; + *pos++ = WLAN_EID_SUPP_RATES; + *pos++ = len; + for (i = 0; i < len; i++) { + int rate = wpa_s->mlme.curr_rates[i].rate; + *pos++ = (u8) (rate / 5); + } + + if (wpa_s->mlme.num_curr_rates > len) { + pos = buf + blen; + blen += wpa_s->mlme.num_curr_rates - len + 2; + *pos++ = WLAN_EID_EXT_SUPP_RATES; + *pos++ = wpa_s->mlme.num_curr_rates - len; + for (i = len; i < wpa_s->mlme.num_curr_rates; i++) { + int rate = wpa_s->mlme.curr_rates[i].rate; + *pos++ = (u8) (rate / 5); + } + } + + if (wpa_s->mlme.extra_ie && wpa_s->mlme.auth_alg != WLAN_AUTH_FT) { + pos = buf + blen; + blen += wpa_s->mlme.extra_ie_len; + os_memcpy(pos, wpa_s->mlme.extra_ie, wpa_s->mlme.extra_ie_len); + } + +#ifdef CONFIG_IEEE80211R + if ((wpa_s->mlme.key_mgmt == KEY_MGMT_FT_802_1X || + wpa_s->mlme.key_mgmt == KEY_MGMT_FT_PSK) && + wpa_s->mlme.auth_alg != WLAN_AUTH_FT && + bss && bss->mdie && + bss->mdie_len >= 2 + sizeof(struct rsn_mdie) && + bss->mdie[1] >= sizeof(struct rsn_mdie)) { + pos = buf + blen; + blen += 2 + sizeof(struct rsn_mdie); + *pos++ = WLAN_EID_MOBILITY_DOMAIN; + *pos++ = sizeof(struct rsn_mdie); + os_memcpy(pos, bss->mdie + 2, MOBILITY_DOMAIN_ID_LEN); + pos += MOBILITY_DOMAIN_ID_LEN; + *pos++ = 0; /* FIX: copy from the target AP's MDIE */ + } + + if ((wpa_s->mlme.key_mgmt == KEY_MGMT_FT_802_1X || + wpa_s->mlme.key_mgmt == KEY_MGMT_FT_PSK) && + wpa_s->mlme.auth_alg == WLAN_AUTH_FT && wpa_s->mlme.ft_ies) { + pos = buf + blen; + os_memcpy(pos, wpa_s->mlme.ft_ies, wpa_s->mlme.ft_ies_len); + pos += wpa_s->mlme.ft_ies_len; + blen += wpa_s->mlme.ft_ies_len; + } +#endif /* CONFIG_IEEE80211R */ + + if (wmm && wpa_s->mlme.wmm_enabled) { + pos = buf + blen; + blen += 9; + *pos++ = WLAN_EID_VENDOR_SPECIFIC; + *pos++ = 7; /* len */ + *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ + *pos++ = 0x50; + *pos++ = 0xf2; + *pos++ = 2; /* WME */ + *pos++ = 0; /* WME info */ + *pos++ = 1; /* WME ver */ + *pos++ = 0; + } + + os_free(wpa_s->mlme.assocreq_ies); + wpa_s->mlme.assocreq_ies_len = (buf + blen) - ies; + wpa_s->mlme.assocreq_ies = os_malloc(wpa_s->mlme.assocreq_ies_len); + if (wpa_s->mlme.assocreq_ies) { + os_memcpy(wpa_s->mlme.assocreq_ies, ies, + wpa_s->mlme.assocreq_ies_len); + } + + ieee80211_sta_tx(wpa_s, buf, blen); + os_free(buf); +} + + +static void ieee80211_send_deauth(struct wpa_supplicant *wpa_s, u16 reason) +{ + u8 *buf; + size_t len; + struct ieee80211_mgmt *mgmt; + + buf = os_zalloc(sizeof(*mgmt)); + if (buf == NULL) { + wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for " + "deauth frame"); + return; + } + + mgmt = (struct ieee80211_mgmt *) buf; + len = 24; + os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); + os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); + os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); + mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_DEAUTH); + len += 2; + mgmt->u.deauth.reason_code = host_to_le16(reason); + + ieee80211_sta_tx(wpa_s, buf, len); + os_free(buf); +} + + +static void ieee80211_send_disassoc(struct wpa_supplicant *wpa_s, u16 reason) +{ + u8 *buf; + size_t len; + struct ieee80211_mgmt *mgmt; + + buf = os_zalloc(sizeof(*mgmt)); + if (buf == NULL) { + wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for " + "disassoc frame"); + return; + } + + mgmt = (struct ieee80211_mgmt *) buf; + len = 24; + os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); + os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); + os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); + mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_DISASSOC); + len += 2; + mgmt->u.disassoc.reason_code = host_to_le16(reason); + + ieee80211_sta_tx(wpa_s, buf, len); + os_free(buf); +} + + +static int ieee80211_privacy_mismatch(struct wpa_supplicant *wpa_s) +{ + struct ieee80211_sta_bss *bss; + int res = 0; + + if (wpa_s->mlme.mixed_cell || + wpa_s->mlme.key_mgmt != KEY_MGMT_NONE) + return 0; + + bss = ieee80211_bss_get(wpa_s, wpa_s->bssid); + if (bss == NULL) + return 0; + + if (ieee80211_sta_wep_configured(wpa_s) != + !!(bss->capability & WLAN_CAPABILITY_PRIVACY)) + res = 1; + + return res; +} + + +static void ieee80211_associate(struct wpa_supplicant *wpa_s) +{ + wpa_s->mlme.assoc_tries++; + if (wpa_s->mlme.assoc_tries > IEEE80211_ASSOC_MAX_TRIES) { + wpa_printf(MSG_DEBUG, "MLME: association with AP " MACSTR + " timed out", MAC2STR(wpa_s->bssid)); + return; + } + + wpa_s->mlme.state = IEEE80211_ASSOCIATE; + wpa_printf(MSG_DEBUG, "MLME: associate with AP " MACSTR, + MAC2STR(wpa_s->bssid)); + if (ieee80211_privacy_mismatch(wpa_s)) { + wpa_printf(MSG_DEBUG, "MLME: mismatch in privacy " + "configuration and mixed-cell disabled - abort " + "association"); + return; + } + + ieee80211_send_assoc(wpa_s); + + ieee80211_reschedule_timer(wpa_s, IEEE80211_ASSOC_TIMEOUT); +} + + +static void ieee80211_associated(struct wpa_supplicant *wpa_s) +{ + int disassoc; + + /* TODO: start monitoring current AP signal quality and number of + * missed beacons. Scan other channels every now and then and search + * for better APs. */ + /* TODO: remove expired BSSes */ + + wpa_s->mlme.state = IEEE80211_ASSOCIATED; + +#if 0 /* FIX */ + sta = sta_info_get(local, wpa_s->bssid); + if (sta == NULL) { + wpa_printf(MSG_DEBUG "MLME: No STA entry for own AP " MACSTR, + MAC2STR(wpa_s->bssid)); + disassoc = 1; + } else { + disassoc = 0; + if (time_after(jiffies, + sta->last_rx + IEEE80211_MONITORING_INTERVAL)) { + if (wpa_s->mlme.probereq_poll) { + wpa_printf(MSG_DEBUG "MLME: No ProbeResp from " + "current AP " MACSTR " - assume " + "out of range", + MAC2STR(wpa_s->bssid)); + disassoc = 1; + } else { + ieee80211_send_probe_req( + wpa_s->bssid, + wpa_s->mlme.scan_ssid, + wpa_s->mlme.scan_ssid_len); + wpa_s->mlme.probereq_poll = 1; + } + } else { + wpa_s->mlme.probereq_poll = 0; + if (time_after(jiffies, wpa_s->mlme.last_probe + + IEEE80211_PROBE_INTERVAL)) { + wpa_s->mlme.last_probe = jiffies; + ieee80211_send_probe_req(wpa_s->bssid, + wpa_s->mlme.ssid, + wpa_s->mlme.ssid_len); + } + } + sta_info_release(local, sta); + } +#else + disassoc = 0; +#endif + if (disassoc) { + wpa_supplicant_event(wpa_s, EVENT_DISASSOC, NULL); + ieee80211_reschedule_timer(wpa_s, + IEEE80211_MONITORING_INTERVAL + + 30000); + } else { + ieee80211_reschedule_timer(wpa_s, + IEEE80211_MONITORING_INTERVAL); + } +} + + +static void ieee80211_send_probe_req(struct wpa_supplicant *wpa_s, + const u8 *dst, + const u8 *ssid, size_t ssid_len) +{ + u8 *buf; + size_t len; + struct ieee80211_mgmt *mgmt; + u8 *pos, *supp_rates; + u8 *esupp_rates = NULL; + int i; + + buf = os_malloc(sizeof(*mgmt) + 200 + wpa_s->mlme.extra_probe_ie_len); + if (buf == NULL) { + wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for " + "probe request"); + return; + } + + mgmt = (struct ieee80211_mgmt *) buf; + len = 24; + os_memset(mgmt, 0, 24); + mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_PROBE_REQ); + os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); + if (dst) { + os_memcpy(mgmt->da, dst, ETH_ALEN); + os_memcpy(mgmt->bssid, dst, ETH_ALEN); + } else { + os_memset(mgmt->da, 0xff, ETH_ALEN); + os_memset(mgmt->bssid, 0xff, ETH_ALEN); + } + pos = buf + len; + len += 2 + ssid_len; + *pos++ = WLAN_EID_SSID; + *pos++ = ssid_len; + os_memcpy(pos, ssid, ssid_len); + + supp_rates = buf + len; + len += 2; + supp_rates[0] = WLAN_EID_SUPP_RATES; + supp_rates[1] = 0; + for (i = 0; i < wpa_s->mlme.num_curr_rates; i++) { + struct wpa_rate_data *rate = &wpa_s->mlme.curr_rates[i]; + if (esupp_rates) { + pos = buf + len; + len++; + esupp_rates[1]++; + } else if (supp_rates[1] == 8) { + esupp_rates = pos; + esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES; + esupp_rates[1] = 1; + pos = &esupp_rates[2]; + len += 3; + } else { + pos = buf + len; + len++; + supp_rates[1]++; + } + *pos++ = rate->rate / 5; + } + + if (wpa_s->mlme.extra_probe_ie) { + os_memcpy(pos, wpa_s->mlme.extra_probe_ie, + wpa_s->mlme.extra_probe_ie_len); + len += wpa_s->mlme.extra_probe_ie_len; + } + + ieee80211_sta_tx(wpa_s, buf, len); + os_free(buf); +} + + +static int ieee80211_sta_wep_configured(struct wpa_supplicant *wpa_s) +{ +#if 0 /* FIX */ + if (sdata == NULL || sdata->default_key == NULL || + sdata->default_key->alg != ALG_WEP) + return 0; + return 1; +#else + return 0; +#endif +} + + +static void ieee80211_auth_completed(struct wpa_supplicant *wpa_s) +{ + wpa_printf(MSG_DEBUG, "MLME: authenticated"); + wpa_s->mlme.authenticated = 1; + ieee80211_associate(wpa_s); +} + + +static void ieee80211_auth_challenge(struct wpa_supplicant *wpa_s, + struct ieee80211_mgmt *mgmt, + size_t len, + struct ieee80211_rx_status *rx_status) +{ + u8 *pos; + struct ieee802_11_elems elems; + + wpa_printf(MSG_DEBUG, "MLME: replying to auth challenge"); + pos = mgmt->u.auth.variable; + if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems, 0) + == ParseFailed) { + wpa_printf(MSG_DEBUG, "MLME: failed to parse Auth(challenge)"); + return; + } + if (elems.challenge == NULL) { + wpa_printf(MSG_DEBUG, "MLME: no challenge IE in shared key " + "auth frame"); + return; + } + ieee80211_send_auth(wpa_s, 3, elems.challenge - 2, + elems.challenge_len + 2, 1); +} + + +static void ieee80211_rx_mgmt_auth(struct wpa_supplicant *wpa_s, + struct ieee80211_mgmt *mgmt, + size_t len, + struct ieee80211_rx_status *rx_status) +{ + struct wpa_ssid *ssid = wpa_s->current_ssid; + u16 auth_alg, auth_transaction, status_code; + int adhoc; + + adhoc = ssid && ssid->mode == 1; + + if (wpa_s->mlme.state != IEEE80211_AUTHENTICATE && !adhoc) { + wpa_printf(MSG_DEBUG, "MLME: authentication frame received " + "from " MACSTR ", but not in authenticate state - " + "ignored", MAC2STR(mgmt->sa)); + return; + } + + if (len < 24 + 6) { + wpa_printf(MSG_DEBUG, "MLME: too short (%lu) authentication " + "frame received from " MACSTR " - ignored", + (unsigned long) len, MAC2STR(mgmt->sa)); + return; + } + + if (!adhoc && os_memcmp(wpa_s->bssid, mgmt->sa, ETH_ALEN) != 0) { + wpa_printf(MSG_DEBUG, "MLME: authentication frame received " + "from unknown AP (SA=" MACSTR " BSSID=" MACSTR + ") - ignored", + MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid)); + return; + } + + if (adhoc && os_memcmp(wpa_s->bssid, mgmt->bssid, ETH_ALEN) != 0) { + wpa_printf(MSG_DEBUG, "MLME: authentication frame received " + "from unknown BSSID (SA=" MACSTR " BSSID=" MACSTR + ") - ignored", + MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid)); + return; + } + + auth_alg = le_to_host16(mgmt->u.auth.auth_alg); + auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction); + status_code = le_to_host16(mgmt->u.auth.status_code); + + wpa_printf(MSG_DEBUG, "MLME: RX authentication from " MACSTR + " (alg=%d transaction=%d status=%d)", + MAC2STR(mgmt->sa), auth_alg, auth_transaction, status_code); + + if (adhoc) { + /* IEEE 802.11 standard does not require authentication in IBSS + * networks and most implementations do not seem to use it. + * However, try to reply to authentication attempts if someone + * has actually implemented this. + * TODO: Could implement shared key authentication. */ + if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) { + wpa_printf(MSG_DEBUG, "MLME: unexpected IBSS " + "authentication frame (alg=%d " + "transaction=%d)", + auth_alg, auth_transaction); + return; + } + ieee80211_send_auth(wpa_s, 2, NULL, 0, 0); + } + + if (auth_alg != wpa_s->mlme.auth_alg || + auth_transaction != wpa_s->mlme.auth_transaction) { + wpa_printf(MSG_DEBUG, "MLME: unexpected authentication frame " + "(alg=%d transaction=%d)", + auth_alg, auth_transaction); + return; + } + + if (status_code != WLAN_STATUS_SUCCESS) { + wpa_printf(MSG_DEBUG, "MLME: AP denied authentication " + "(auth_alg=%d code=%d)", wpa_s->mlme.auth_alg, + status_code); + if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) { + const int num_algs = 3; + u8 algs[num_algs]; + int i, pos; + algs[0] = algs[1] = algs[2] = 0xff; + if (wpa_s->mlme.auth_algs & IEEE80211_AUTH_ALG_OPEN) + algs[0] = WLAN_AUTH_OPEN; + if (wpa_s->mlme.auth_algs & + IEEE80211_AUTH_ALG_SHARED_KEY) + algs[1] = WLAN_AUTH_SHARED_KEY; + if (wpa_s->mlme.auth_algs & IEEE80211_AUTH_ALG_LEAP) + algs[2] = WLAN_AUTH_LEAP; + if (wpa_s->mlme.auth_alg == WLAN_AUTH_OPEN) + pos = 0; + else if (wpa_s->mlme.auth_alg == WLAN_AUTH_SHARED_KEY) + pos = 1; + else + pos = 2; + for (i = 0; i < num_algs; i++) { + pos++; + if (pos >= num_algs) + pos = 0; + if (algs[pos] == wpa_s->mlme.auth_alg || + algs[pos] == 0xff) + continue; + if (algs[pos] == WLAN_AUTH_SHARED_KEY && + !ieee80211_sta_wep_configured(wpa_s)) + continue; + wpa_s->mlme.auth_alg = algs[pos]; + wpa_printf(MSG_DEBUG, "MLME: set auth_alg=%d " + "for next try", + wpa_s->mlme.auth_alg); + break; + } + } + return; + } + + switch (wpa_s->mlme.auth_alg) { + case WLAN_AUTH_OPEN: + case WLAN_AUTH_LEAP: + ieee80211_auth_completed(wpa_s); + break; + case WLAN_AUTH_SHARED_KEY: + if (wpa_s->mlme.auth_transaction == 4) + ieee80211_auth_completed(wpa_s); + else + ieee80211_auth_challenge(wpa_s, mgmt, len, + rx_status); + break; +#ifdef CONFIG_IEEE80211R + case WLAN_AUTH_FT: + { + union wpa_event_data data; + os_memset(&data, 0, sizeof(data)); + data.ft_ies.ies = mgmt->u.auth.variable; + data.ft_ies.ies_len = len - + (mgmt->u.auth.variable - (u8 *) mgmt); + os_memcpy(data.ft_ies.target_ap, wpa_s->bssid, ETH_ALEN); + wpa_supplicant_event(wpa_s, EVENT_FT_RESPONSE, &data); + ieee80211_auth_completed(wpa_s); + break; + } +#endif /* CONFIG_IEEE80211R */ + } +} + + +static void ieee80211_rx_mgmt_deauth(struct wpa_supplicant *wpa_s, + struct ieee80211_mgmt *mgmt, + size_t len, + struct ieee80211_rx_status *rx_status) +{ + u16 reason_code; + + if (len < 24 + 2) { + wpa_printf(MSG_DEBUG, "MLME: too short (%lu) deauthentication " + "frame received from " MACSTR " - ignored", + (unsigned long) len, MAC2STR(mgmt->sa)); + return; + } + + if (os_memcmp(wpa_s->bssid, mgmt->sa, ETH_ALEN) != 0) { + wpa_printf(MSG_DEBUG, "MLME: deauthentication frame received " + "from unknown AP (SA=" MACSTR " BSSID=" MACSTR + ") - ignored", + MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid)); + return; + } + + reason_code = le_to_host16(mgmt->u.deauth.reason_code); + + wpa_printf(MSG_DEBUG, "MLME: RX deauthentication from " MACSTR + " (reason=%d)", MAC2STR(mgmt->sa), reason_code); + + if (wpa_s->mlme.authenticated) + wpa_printf(MSG_DEBUG, "MLME: deauthenticated"); + + if (wpa_s->mlme.state == IEEE80211_AUTHENTICATE || + wpa_s->mlme.state == IEEE80211_ASSOCIATE || + wpa_s->mlme.state == IEEE80211_ASSOCIATED) { + wpa_s->mlme.state = IEEE80211_AUTHENTICATE; + ieee80211_reschedule_timer(wpa_s, + IEEE80211_RETRY_AUTH_INTERVAL); + } + + ieee80211_set_associated(wpa_s, 0); + wpa_s->mlme.authenticated = 0; +} + + +static void ieee80211_rx_mgmt_disassoc(struct wpa_supplicant *wpa_s, + struct ieee80211_mgmt *mgmt, + size_t len, + struct ieee80211_rx_status *rx_status) +{ + u16 reason_code; + + if (len < 24 + 2) { + wpa_printf(MSG_DEBUG, "MLME: too short (%lu) disassociation " + "frame received from " MACSTR " - ignored", + (unsigned long) len, MAC2STR(mgmt->sa)); + return; + } + + if (os_memcmp(wpa_s->bssid, mgmt->sa, ETH_ALEN) != 0) { + wpa_printf(MSG_DEBUG, "MLME: disassociation frame received " + "from unknown AP (SA=" MACSTR " BSSID=" MACSTR + ") - ignored", + MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid)); + return; + } + + reason_code = le_to_host16(mgmt->u.disassoc.reason_code); + + wpa_printf(MSG_DEBUG, "MLME: RX disassociation from " MACSTR + " (reason=%d)", MAC2STR(mgmt->sa), reason_code); + + if (wpa_s->mlme.associated) + wpa_printf(MSG_DEBUG, "MLME: disassociated"); + + if (wpa_s->mlme.state == IEEE80211_ASSOCIATED) { + wpa_s->mlme.state = IEEE80211_ASSOCIATE; + ieee80211_reschedule_timer(wpa_s, + IEEE80211_RETRY_AUTH_INTERVAL); + } + + ieee80211_set_associated(wpa_s, 0); +} + + +static int ieee80211_ft_assoc_resp(struct wpa_supplicant *wpa_s, + struct ieee802_11_elems *elems) +{ +#ifdef CONFIG_IEEE80211R + const u8 *mobility_domain = NULL; + const u8 *r0kh_id = NULL; + size_t r0kh_id_len = 0; + const u8 *r1kh_id = NULL; + struct rsn_ftie *hdr; + const u8 *pos, *end; + + if (elems->mdie && elems->mdie_len >= MOBILITY_DOMAIN_ID_LEN) + mobility_domain = elems->mdie; + if (elems->ftie && elems->ftie_len >= sizeof(struct rsn_ftie)) { + end = elems->ftie + elems->ftie_len; + hdr = (struct rsn_ftie *) elems->ftie; + pos = (const u8 *) (hdr + 1); + while (pos + 1 < end) { + if (pos + 2 + pos[1] > end) + break; + if (pos[0] == FTIE_SUBELEM_R1KH_ID && + pos[1] == FT_R1KH_ID_LEN) + r1kh_id = pos + 2; + else if (pos[0] == FTIE_SUBELEM_R0KH_ID && + pos[1] >= 1 && pos[1] <= FT_R0KH_ID_MAX_LEN) { + r0kh_id = pos + 2; + r0kh_id_len = pos[1]; + } + pos += 2 + pos[1]; + } + } + return wpa_sm_set_ft_params(wpa_s->wpa, mobility_domain, r0kh_id, + r0kh_id_len, r1kh_id); +#else /* CONFIG_IEEE80211R */ + return 0; +#endif /* CONFIG_IEEE80211R */ +} + + +static void ieee80211_rx_mgmt_assoc_resp(struct wpa_supplicant *wpa_s, + struct ieee80211_mgmt *mgmt, + size_t len, + struct ieee80211_rx_status *rx_status, + int reassoc) +{ + u8 rates[32]; + size_t rates_len; + u16 capab_info, status_code, aid; + struct ieee802_11_elems elems; + u8 *pos; + + /* AssocResp and ReassocResp have identical structure, so process both + * of them in this function. */ + + if (wpa_s->mlme.state != IEEE80211_ASSOCIATE) { + wpa_printf(MSG_DEBUG, "MLME: association frame received from " + MACSTR ", but not in associate state - ignored", + MAC2STR(mgmt->sa)); + return; + } + + if (len < 24 + 6) { + wpa_printf(MSG_DEBUG, "MLME: too short (%lu) association " + "frame received from " MACSTR " - ignored", + (unsigned long) len, MAC2STR(mgmt->sa)); + return; + } + + if (os_memcmp(wpa_s->bssid, mgmt->sa, ETH_ALEN) != 0) { + wpa_printf(MSG_DEBUG, "MLME: association frame received from " + "unknown AP (SA=" MACSTR " BSSID=" MACSTR ") - " + "ignored", MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid)); + return; + } + + capab_info = le_to_host16(mgmt->u.assoc_resp.capab_info); + status_code = le_to_host16(mgmt->u.assoc_resp.status_code); + aid = le_to_host16(mgmt->u.assoc_resp.aid); + if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) + wpa_printf(MSG_DEBUG, "MLME: invalid aid value %d; bits 15:14 " + "not set", aid); + aid &= ~(BIT(15) | BIT(14)); + + wpa_printf(MSG_DEBUG, "MLME: RX %sssocResp from " MACSTR + " (capab=0x%x status=%d aid=%d)", + reassoc ? "Rea" : "A", MAC2STR(mgmt->sa), + capab_info, status_code, aid); + + pos = mgmt->u.assoc_resp.variable; + if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems, 0) + == ParseFailed) { + wpa_printf(MSG_DEBUG, "MLME: failed to parse AssocResp"); + return; + } + + if (status_code != WLAN_STATUS_SUCCESS) { + wpa_printf(MSG_DEBUG, "MLME: AP denied association (code=%d)", + status_code); +#ifdef CONFIG_IEEE80211W + if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY && + elems.timeout_int && elems.timeout_int_len == 5 && + elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) { + u32 tu, ms; + tu = WPA_GET_LE32(elems.timeout_int + 1); + ms = tu * 1024 / 1000; + wpa_printf(MSG_DEBUG, "MLME: AP rejected association " + "temporarily; comeback duration %u TU " + "(%u ms)", tu, ms); + if (ms > IEEE80211_ASSOC_TIMEOUT) { + wpa_printf(MSG_DEBUG, "MLME: Update timer " + "based on comeback duration"); + ieee80211_reschedule_timer(wpa_s, ms); + } + } +#endif /* CONFIG_IEEE80211W */ + return; + } + + if (elems.supp_rates == NULL) { + wpa_printf(MSG_DEBUG, "MLME: no SuppRates element in " + "AssocResp"); + return; + } + + if (wpa_s->mlme.auth_alg == WLAN_AUTH_FT) { + if (!reassoc) { + wpa_printf(MSG_DEBUG, "MLME: AP tried to use " + "association, not reassociation, response " + "with FT"); + return; + } + if (wpa_ft_validate_reassoc_resp( + wpa_s->wpa, pos, len - (pos - (u8 *) mgmt), + mgmt->sa) < 0) { + wpa_printf(MSG_DEBUG, "MLME: FT validation of Reassoc" + "Resp failed"); + return; + } + } else if (ieee80211_ft_assoc_resp(wpa_s, &elems) < 0) + return; + + wpa_printf(MSG_DEBUG, "MLME: associated"); + wpa_s->mlme.aid = aid; + wpa_s->mlme.ap_capab = capab_info; + + os_free(wpa_s->mlme.assocresp_ies); + wpa_s->mlme.assocresp_ies_len = len - (pos - (u8 *) mgmt); + wpa_s->mlme.assocresp_ies = os_malloc(wpa_s->mlme.assocresp_ies_len); + if (wpa_s->mlme.assocresp_ies) { + os_memcpy(wpa_s->mlme.assocresp_ies, pos, + wpa_s->mlme.assocresp_ies_len); + } + + ieee80211_set_associated(wpa_s, 1); + + rates_len = elems.supp_rates_len; + if (rates_len > sizeof(rates)) + rates_len = sizeof(rates); + os_memcpy(rates, elems.supp_rates, rates_len); + if (elems.ext_supp_rates) { + size_t _len = elems.ext_supp_rates_len; + if (_len > sizeof(rates) - rates_len) + _len = sizeof(rates) - rates_len; + os_memcpy(rates + rates_len, elems.ext_supp_rates, _len); + rates_len += _len; + } + + if (wpa_drv_set_bssid(wpa_s, wpa_s->bssid) < 0) { + wpa_printf(MSG_DEBUG, "MLME: failed to set BSSID for the " + "netstack"); + } + if (wpa_drv_set_ssid(wpa_s, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len) < + 0) { + wpa_printf(MSG_DEBUG, "MLME: failed to set SSID for the " + "netstack"); + } + + /* Remove STA entry before adding a new one just in case to avoid + * problems with existing configuration (e.g., keys). */ + wpa_drv_mlme_remove_sta(wpa_s, wpa_s->bssid); + if (wpa_drv_mlme_add_sta(wpa_s, wpa_s->bssid, rates, rates_len) < 0) { + wpa_printf(MSG_DEBUG, "MLME: failed to add STA entry to the " + "netstack"); + } + +#if 0 /* FIX? */ + sta->assoc_ap = 1; + + if (elems.wme && wpa_s->mlme.wmm_enabled) { + sta->flags |= WLAN_STA_WME; + ieee80211_sta_wmm_params(wpa_s, elems.wme, elems.wme_len); + } +#endif + + ieee80211_associated(wpa_s); +} + + +/* Caller must hold local->sta_bss_lock */ +static void __ieee80211_bss_hash_add(struct wpa_supplicant *wpa_s, + struct ieee80211_sta_bss *bss) +{ + bss->hnext = wpa_s->mlme.sta_bss_hash[STA_HASH(bss->bssid)]; + wpa_s->mlme.sta_bss_hash[STA_HASH(bss->bssid)] = bss; +} + + +/* Caller must hold local->sta_bss_lock */ +static void __ieee80211_bss_hash_del(struct wpa_supplicant *wpa_s, + struct ieee80211_sta_bss *bss) +{ + struct ieee80211_sta_bss *b, *prev = NULL; + b = wpa_s->mlme.sta_bss_hash[STA_HASH(bss->bssid)]; + while (b) { + if (b == bss) { + if (prev == NULL) { + wpa_s->mlme.sta_bss_hash[STA_HASH(bss->bssid)] + = bss->hnext; + } else { + prev->hnext = bss->hnext; + } + break; + } + prev = b; + b = b->hnext; + } +} + + +static struct ieee80211_sta_bss * +ieee80211_bss_add(struct wpa_supplicant *wpa_s, const u8 *bssid) +{ + struct ieee80211_sta_bss *bss; + + bss = os_zalloc(sizeof(*bss)); + if (bss == NULL) + return NULL; + os_memcpy(bss->bssid, bssid, ETH_ALEN); + + /* TODO: order by RSSI? */ + bss->next = wpa_s->mlme.sta_bss_list; + wpa_s->mlme.sta_bss_list = bss; + __ieee80211_bss_hash_add(wpa_s, bss); + return bss; +} + + +static struct ieee80211_sta_bss * +ieee80211_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid) +{ + struct ieee80211_sta_bss *bss; + + bss = wpa_s->mlme.sta_bss_hash[STA_HASH(bssid)]; + while (bss) { + if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0) + break; + bss = bss->hnext; + } + return bss; +} + + +static void ieee80211_bss_free(struct wpa_supplicant *wpa_s, + struct ieee80211_sta_bss *bss) +{ + __ieee80211_bss_hash_del(wpa_s, bss); + os_free(bss->ie); + os_free(bss->wpa_ie); + os_free(bss->rsn_ie); + os_free(bss->wmm_ie); + os_free(bss->mdie); + os_free(bss); +} + + +static void ieee80211_bss_list_deinit(struct wpa_supplicant *wpa_s) +{ + struct ieee80211_sta_bss *bss, *prev; + + bss = wpa_s->mlme.sta_bss_list; + wpa_s->mlme.sta_bss_list = NULL; + while (bss) { + prev = bss; + bss = bss->next; + ieee80211_bss_free(wpa_s, prev); + } +} + + +static void ieee80211_bss_info(struct wpa_supplicant *wpa_s, + struct ieee80211_mgmt *mgmt, + size_t len, + struct ieee80211_rx_status *rx_status, + int beacon) +{ + struct ieee802_11_elems elems; + size_t baselen; + int channel, invalid = 0, clen; + struct ieee80211_sta_bss *bss; + u64 timestamp; + u8 *pos, *ie_pos; + size_t ie_len; + + if (!beacon && os_memcmp(mgmt->da, wpa_s->own_addr, ETH_ALEN)) + return; /* ignore ProbeResp to foreign address */ + +#if 0 + wpa_printf(MSG_MSGDUMP, "MLME: RX %s from " MACSTR " to " MACSTR, + beacon ? "Beacon" : "Probe Response", + MAC2STR(mgmt->sa), MAC2STR(mgmt->da)); +#endif + + baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; + if (baselen > len) + return; + + pos = mgmt->u.beacon.timestamp; + timestamp = WPA_GET_LE64(pos); + +#if 0 /* FIX */ + if (local->conf.mode == IW_MODE_ADHOC && beacon && + os_memcmp(mgmt->bssid, local->bssid, ETH_ALEN) == 0) { +#ifdef IEEE80211_IBSS_DEBUG + static unsigned long last_tsf_debug = 0; + u64 tsf; + if (local->hw->get_tsf) + tsf = local->hw->get_tsf(local->mdev); + else + tsf = -1LLU; + if (time_after(jiffies, last_tsf_debug + 5 * HZ)) { + wpa_printf(MSG_DEBUG, "RX beacon SA=" MACSTR " BSSID=" + MACSTR " TSF=0x%llx BCN=0x%llx diff=%lld " + "@%ld", + MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid), + tsf, timestamp, tsf - timestamp, jiffies); + last_tsf_debug = jiffies; + } +#endif /* IEEE80211_IBSS_DEBUG */ + } +#endif + + ie_pos = mgmt->u.beacon.variable; + ie_len = len - baselen; + if (ieee802_11_parse_elems(ie_pos, ie_len, &elems, 0) == ParseFailed) + invalid = 1; + +#if 0 /* FIX */ + if (local->conf.mode == IW_MODE_ADHOC && elems.supp_rates && + os_memcmp(mgmt->bssid, local->bssid, ETH_ALEN) == 0 && + (sta = sta_info_get(local, mgmt->sa))) { + struct ieee80211_rate *rates; + size_t num_rates; + u32 supp_rates, prev_rates; + int i, j, oper_mode; + + rates = local->curr_rates; + num_rates = local->num_curr_rates; + oper_mode = wpa_s->mlme.sta_scanning ? + local->scan_oper_phymode : local->conf.phymode; + for (i = 0; i < local->hw->num_modes; i++) { + struct ieee80211_hw_modes *mode = &local->hw->modes[i]; + if (oper_mode == mode->mode) { + rates = mode->rates; + num_rates = mode->num_rates; + break; + } + } + + supp_rates = 0; + for (i = 0; i < elems.supp_rates_len + + elems.ext_supp_rates_len; i++) { + u8 rate = 0; + int own_rate; + if (i < elems.supp_rates_len) + rate = elems.supp_rates[i]; + else if (elems.ext_supp_rates) + rate = elems.ext_supp_rates + [i - elems.supp_rates_len]; + own_rate = 5 * (rate & 0x7f); + if (oper_mode == MODE_ATHEROS_TURBO) + own_rate *= 2; + for (j = 0; j < num_rates; j++) + if (rates[j].rate == own_rate) + supp_rates |= BIT(j); + } + + prev_rates = sta->supp_rates; + sta->supp_rates &= supp_rates; + if (sta->supp_rates == 0) { + /* No matching rates - this should not really happen. + * Make sure that at least one rate is marked + * supported to avoid issues with TX rate ctrl. */ + sta->supp_rates = wpa_s->mlme.supp_rates_bits; + } + if (sta->supp_rates != prev_rates) { + wpa_printf(MSG_DEBUG, "MLME: updated supp_rates set " + "for " MACSTR " based on beacon info " + "(0x%x & 0x%x -> 0x%x)", + MAC2STR(sta->addr), prev_rates, + supp_rates, sta->supp_rates); + } + sta_info_release(local, sta); + } +#endif + + if (elems.ssid == NULL) + return; + + if (elems.ds_params && elems.ds_params_len == 1) + channel = elems.ds_params[0]; + else + channel = rx_status->channel; + + bss = ieee80211_bss_get(wpa_s, mgmt->bssid); + if (bss == NULL) { + bss = ieee80211_bss_add(wpa_s, mgmt->bssid); + if (bss == NULL) + return; + } else { +#if 0 + /* TODO: order by RSSI? */ + spin_lock_bh(&local->sta_bss_lock); + list_move_tail(&bss->list, &local->sta_bss_list); + spin_unlock_bh(&local->sta_bss_lock); +#endif + } + + if (bss->probe_resp && beacon) { + /* Do not allow beacon to override data from Probe Response. */ + return; + } + + bss->beacon_int = le_to_host16(mgmt->u.beacon.beacon_int); + bss->capability = le_to_host16(mgmt->u.beacon.capab_info); + + if (bss->ie == NULL || bss->ie_len < ie_len) { + os_free(bss->ie); + bss->ie = os_malloc(ie_len); + } + if (bss->ie) { + os_memcpy(bss->ie, ie_pos, ie_len); + bss->ie_len = ie_len; + } + + if (elems.ssid && elems.ssid_len <= MAX_SSID_LEN) { + os_memcpy(bss->ssid, elems.ssid, elems.ssid_len); + bss->ssid_len = elems.ssid_len; + } + + bss->supp_rates_len = 0; + if (elems.supp_rates) { + clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len; + if (clen > elems.supp_rates_len) + clen = elems.supp_rates_len; + os_memcpy(&bss->supp_rates[bss->supp_rates_len], + elems.supp_rates, clen); + bss->supp_rates_len += clen; + } + if (elems.ext_supp_rates) { + clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len; + if (clen > elems.ext_supp_rates_len) + clen = elems.ext_supp_rates_len; + os_memcpy(&bss->supp_rates[bss->supp_rates_len], + elems.ext_supp_rates, clen); + bss->supp_rates_len += clen; + } + + if (elems.wpa_ie && + (bss->wpa_ie == NULL || bss->wpa_ie_len != elems.wpa_ie_len || + os_memcmp(bss->wpa_ie, elems.wpa_ie, elems.wpa_ie_len))) { + os_free(bss->wpa_ie); + bss->wpa_ie = os_malloc(elems.wpa_ie_len + 2); + if (bss->wpa_ie) { + os_memcpy(bss->wpa_ie, elems.wpa_ie - 2, + elems.wpa_ie_len + 2); + bss->wpa_ie_len = elems.wpa_ie_len + 2; + } else + bss->wpa_ie_len = 0; + } else if (!elems.wpa_ie && bss->wpa_ie) { + os_free(bss->wpa_ie); + bss->wpa_ie = NULL; + bss->wpa_ie_len = 0; + } + + if (elems.rsn_ie && + (bss->rsn_ie == NULL || bss->rsn_ie_len != elems.rsn_ie_len || + os_memcmp(bss->rsn_ie, elems.rsn_ie, elems.rsn_ie_len))) { + os_free(bss->rsn_ie); + bss->rsn_ie = os_malloc(elems.rsn_ie_len + 2); + if (bss->rsn_ie) { + os_memcpy(bss->rsn_ie, elems.rsn_ie - 2, + elems.rsn_ie_len + 2); + bss->rsn_ie_len = elems.rsn_ie_len + 2; + } else + bss->rsn_ie_len = 0; + } else if (!elems.rsn_ie && bss->rsn_ie) { + os_free(bss->rsn_ie); + bss->rsn_ie = NULL; + bss->rsn_ie_len = 0; + } + + if (elems.wme && + (bss->wmm_ie == NULL || bss->wmm_ie_len != elems.wme_len || + os_memcmp(bss->wmm_ie, elems.wme, elems.wme_len))) { + os_free(bss->wmm_ie); + bss->wmm_ie = os_malloc(elems.wme_len + 2); + if (bss->wmm_ie) { + os_memcpy(bss->wmm_ie, elems.wme - 2, + elems.wme_len + 2); + bss->wmm_ie_len = elems.wme_len + 2; + } else + bss->wmm_ie_len = 0; + } else if (!elems.wme && bss->wmm_ie) { + os_free(bss->wmm_ie); + bss->wmm_ie = NULL; + bss->wmm_ie_len = 0; + } + +#ifdef CONFIG_IEEE80211R + if (elems.mdie && + (bss->mdie == NULL || bss->mdie_len != elems.mdie_len || + os_memcmp(bss->mdie, elems.mdie, elems.mdie_len))) { + os_free(bss->mdie); + bss->mdie = os_malloc(elems.mdie_len + 2); + if (bss->mdie) { + os_memcpy(bss->mdie, elems.mdie - 2, + elems.mdie_len + 2); + bss->mdie_len = elems.mdie_len + 2; + } else + bss->mdie_len = 0; + } else if (!elems.mdie && bss->mdie) { + os_free(bss->mdie); + bss->mdie = NULL; + bss->mdie_len = 0; + } +#endif /* CONFIG_IEEE80211R */ + + bss->hw_mode = wpa_s->mlme.phymode; + bss->channel = channel; + bss->freq = wpa_s->mlme.freq; + if (channel != wpa_s->mlme.channel && + (wpa_s->mlme.phymode == WPA_MODE_IEEE80211G || + wpa_s->mlme.phymode == WPA_MODE_IEEE80211B) && + channel >= 1 && channel <= 14) { + static const int freq_list[] = { + 2412, 2417, 2422, 2427, 2432, 2437, 2442, + 2447, 2452, 2457, 2462, 2467, 2472, 2484 + }; + /* IEEE 802.11g/b mode can receive packets from neighboring + * channels, so map the channel into frequency. */ + bss->freq = freq_list[channel - 1]; + } + bss->timestamp = timestamp; + os_get_time(&bss->last_update); + bss->rssi = rx_status->ssi; + if (!beacon) + bss->probe_resp++; +} + + +static void ieee80211_rx_mgmt_probe_resp(struct wpa_supplicant *wpa_s, + struct ieee80211_mgmt *mgmt, + size_t len, + struct ieee80211_rx_status *rx_status) +{ + ieee80211_bss_info(wpa_s, mgmt, len, rx_status, 0); +} + + +static void ieee80211_rx_mgmt_beacon(struct wpa_supplicant *wpa_s, + struct ieee80211_mgmt *mgmt, + size_t len, + struct ieee80211_rx_status *rx_status) +{ + int use_protection; + size_t baselen; + struct ieee802_11_elems elems; + + ieee80211_bss_info(wpa_s, mgmt, len, rx_status, 1); + + if (!wpa_s->mlme.associated || + os_memcmp(wpa_s->bssid, mgmt->bssid, ETH_ALEN) != 0) + return; + + /* Process beacon from the current BSS */ + baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; + if (baselen > len) + return; + + if (ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, + &elems, 0) == ParseFailed) + return; + + use_protection = 0; + if (elems.erp_info && elems.erp_info_len >= 1) { + use_protection = + (elems.erp_info[0] & ERP_INFO_USE_PROTECTION) != 0; + } + + if (use_protection != !!wpa_s->mlme.use_protection) { + wpa_printf(MSG_DEBUG, "MLME: CTS protection %s (BSSID=" MACSTR + ")", + use_protection ? "enabled" : "disabled", + MAC2STR(wpa_s->bssid)); + wpa_s->mlme.use_protection = use_protection ? 1 : 0; + wpa_s->mlme.cts_protect_erp_frames = use_protection; + } + + if (elems.wme && wpa_s->mlme.wmm_enabled) { + ieee80211_sta_wmm_params(wpa_s, elems.wme, + elems.wme_len); + } +} + + +static void ieee80211_rx_mgmt_probe_req(struct wpa_supplicant *wpa_s, + struct ieee80211_mgmt *mgmt, + size_t len, + struct ieee80211_rx_status *rx_status) +{ + int tx_last_beacon, adhoc; +#if 0 /* FIX */ + struct ieee80211_mgmt *resp; +#endif + u8 *pos, *end; + struct wpa_ssid *ssid = wpa_s->current_ssid; + + adhoc = ssid && ssid->mode == 1; + + if (!adhoc || wpa_s->mlme.state != IEEE80211_IBSS_JOINED || + len < 24 + 2 || wpa_s->mlme.probe_resp == NULL) + return; + +#if 0 /* FIX */ + if (local->hw->tx_last_beacon) + tx_last_beacon = local->hw->tx_last_beacon(local->mdev); + else +#endif + tx_last_beacon = 1; + +#ifdef IEEE80211_IBSS_DEBUG + wpa_printf(MSG_DEBUG, "MLME: RX ProbeReq SA=" MACSTR " DA=" MACSTR + " BSSID=" MACSTR " (tx_last_beacon=%d)", + MAC2STR(mgmt->sa), MAC2STR(mgmt->da), + MAC2STR(mgmt->bssid), tx_last_beacon); +#endif /* IEEE80211_IBSS_DEBUG */ + + if (!tx_last_beacon) + return; + + if (os_memcmp(mgmt->bssid, wpa_s->bssid, ETH_ALEN) != 0 && + os_memcmp(mgmt->bssid, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0) + return; + + end = ((u8 *) mgmt) + len; + pos = mgmt->u.probe_req.variable; + if (pos[0] != WLAN_EID_SSID || + pos + 2 + pos[1] > end) { + wpa_printf(MSG_DEBUG, "MLME: Invalid SSID IE in ProbeReq from " + MACSTR, MAC2STR(mgmt->sa)); + return; + } + if (pos[1] != 0 && + (pos[1] != wpa_s->mlme.ssid_len || + os_memcmp(pos + 2, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len) != 0)) + { + /* Ignore ProbeReq for foreign SSID */ + return; + } + +#if 0 /* FIX */ + /* Reply with ProbeResp */ + skb = skb_copy(wpa_s->mlme.probe_resp, GFP_ATOMIC); + if (skb == NULL) + return; + + resp = (struct ieee80211_mgmt *) skb->data; + os_memcpy(resp->da, mgmt->sa, ETH_ALEN); +#ifdef IEEE80211_IBSS_DEBUG + wpa_printf(MSG_DEBUG, "MLME: Sending ProbeResp to " MACSTR, + MAC2STR(resp->da)); +#endif /* IEEE80211_IBSS_DEBUG */ + ieee80211_sta_tx(wpa_s, skb, 0, 1); +#endif +} + + +#ifdef CONFIG_IEEE80211R +static void ieee80211_rx_mgmt_ft_action(struct wpa_supplicant *wpa_s, + struct ieee80211_mgmt *mgmt, + size_t len, + struct ieee80211_rx_status *rx_status) +{ + union wpa_event_data data; + u16 status; + u8 *sta_addr, *target_ap_addr; + + if (len < 24 + 1 + sizeof(mgmt->u.action.u.ft_action_resp)) { + wpa_printf(MSG_DEBUG, "MLME: Too short FT Action frame"); + return; + } + + /* + * Only FT Action Response is needed for now since reservation + * protocol is not supported. + */ + if (mgmt->u.action.u.ft_action_resp.action != 2) { + wpa_printf(MSG_DEBUG, "MLME: Unexpected FT Action %d", + mgmt->u.action.u.ft_action_resp.action); + return; + } + + status = le_to_host16(mgmt->u.action.u.ft_action_resp.status_code); + sta_addr = mgmt->u.action.u.ft_action_resp.sta_addr; + target_ap_addr = mgmt->u.action.u.ft_action_resp.target_ap_addr; + wpa_printf(MSG_DEBUG, "MLME: Received FT Action Response: STA " MACSTR + " TargetAP " MACSTR " Status Code %d", + MAC2STR(sta_addr), MAC2STR(target_ap_addr), status); + if (os_memcmp(sta_addr, wpa_s->own_addr, ETH_ALEN) != 0) { + wpa_printf(MSG_DEBUG, "MLME: Foreign STA Address " MACSTR + " in FT Action Response", MAC2STR(sta_addr)); + return; + + } + + if (status) { + wpa_printf(MSG_DEBUG, "MLME: FT Action Response indicates " + "failure (status code %d)", status); + /* TODO: report error to FT code(?) */ + return; + } + + os_memset(&data, 0, sizeof(data)); + data.ft_ies.ies = mgmt->u.action.u.ft_action_resp.variable; + data.ft_ies.ies_len = len - (mgmt->u.action.u.ft_action_resp.variable - + (u8 *) mgmt); + data.ft_ies.ft_action = 1; + os_memcpy(data.ft_ies.target_ap, target_ap_addr, ETH_ALEN); + wpa_supplicant_event(wpa_s, EVENT_FT_RESPONSE, &data); + /* TODO: should only re-associate, if EVENT_FT_RESPONSE was processed + * successfully */ + wpa_s->mlme.prev_bssid_set = 1; + wpa_s->mlme.auth_alg = WLAN_AUTH_FT; + os_memcpy(wpa_s->mlme.prev_bssid, wpa_s->bssid, ETH_ALEN); + os_memcpy(wpa_s->bssid, target_ap_addr, ETH_ALEN); + ieee80211_associate(wpa_s); +} +#endif /* CONFIG_IEEE80211R */ + + +#ifdef CONFIG_IEEE80211W + +/* MLME-SAQuery.response */ +static int ieee80211_sta_send_sa_query_resp(struct wpa_supplicant *wpa_s, + const u8 *addr, const u8 *trans_id) +{ + struct ieee80211_mgmt *mgmt; + int res; + size_t len; + + mgmt = os_zalloc(sizeof(*mgmt)); + if (mgmt == NULL) { + wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for " + "SA Query action frame"); + return -1; + } + + len = 24; + os_memcpy(mgmt->da, addr, ETH_ALEN); + os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); + os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); + mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_ACTION); + mgmt->u.action.category = WLAN_ACTION_SA_QUERY; + mgmt->u.action.u.sa_query_resp.action = WLAN_SA_QUERY_RESPONSE; + os_memcpy(mgmt->u.action.u.sa_query_resp.trans_id, trans_id, + WLAN_SA_QUERY_TR_ID_LEN); + len += 1 + sizeof(mgmt->u.action.u.sa_query_resp); + + res = ieee80211_sta_tx(wpa_s, (u8 *) mgmt, len); + os_free(mgmt); + + return res; +} + + +static void ieee80211_rx_mgmt_sa_query_action( + struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len, + struct ieee80211_rx_status *rx_status) +{ + if (len < 24 + 1 + sizeof(mgmt->u.action.u.sa_query_req)) { + wpa_printf(MSG_DEBUG, "MLME: Too short SA Query Action frame"); + return; + } + + if (mgmt->u.action.u.sa_query_req.action != WLAN_SA_QUERY_REQUEST) { + wpa_printf(MSG_DEBUG, "MLME: Unexpected SA Query Action %d", + mgmt->u.action.u.sa_query_req.action); + return; + } + + if (os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) { + wpa_printf(MSG_DEBUG, "MLME: Ignore SA Query from unknown " + "source " MACSTR, MAC2STR(mgmt->sa)); + return; + } + + if (wpa_s->mlme.state == IEEE80211_ASSOCIATE) { + wpa_printf(MSG_DEBUG, "MLME: Ignore SA query request during " + "association process"); + return; + } + + wpa_printf(MSG_DEBUG, "MLME: Replying to SA Query request"); + ieee80211_sta_send_sa_query_resp(wpa_s, mgmt->sa, mgmt->u.action.u. + sa_query_req.trans_id); +} + +#endif /* CONFIG_IEEE80211W */ + + +static void ieee80211_rx_mgmt_action(struct wpa_supplicant *wpa_s, + struct ieee80211_mgmt *mgmt, + size_t len, + struct ieee80211_rx_status *rx_status) +{ + wpa_printf(MSG_DEBUG, "MLME: received Action frame"); + + if (len < 25) + return; + + switch (mgmt->u.action.category) { +#ifdef CONFIG_IEEE80211R + case WLAN_ACTION_FT: + ieee80211_rx_mgmt_ft_action(wpa_s, mgmt, len, rx_status); + break; +#endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_IEEE80211W + case WLAN_ACTION_SA_QUERY: + ieee80211_rx_mgmt_sa_query_action(wpa_s, mgmt, len, rx_status); + break; +#endif /* CONFIG_IEEE80211W */ + default: + wpa_printf(MSG_DEBUG, "MLME: unknown Action Category %d", + mgmt->u.action.category); + break; + } +} + + +static void ieee80211_sta_rx_mgmt(struct wpa_supplicant *wpa_s, + const u8 *buf, size_t len, + struct ieee80211_rx_status *rx_status) +{ + struct ieee80211_mgmt *mgmt; + u16 fc; + + if (len < 24) + return; + + mgmt = (struct ieee80211_mgmt *) buf; + fc = le_to_host16(mgmt->frame_control); + + switch (WLAN_FC_GET_STYPE(fc)) { + case WLAN_FC_STYPE_PROBE_REQ: + ieee80211_rx_mgmt_probe_req(wpa_s, mgmt, len, rx_status); + break; + case WLAN_FC_STYPE_PROBE_RESP: + ieee80211_rx_mgmt_probe_resp(wpa_s, mgmt, len, rx_status); + break; + case WLAN_FC_STYPE_BEACON: + ieee80211_rx_mgmt_beacon(wpa_s, mgmt, len, rx_status); + break; + case WLAN_FC_STYPE_AUTH: + ieee80211_rx_mgmt_auth(wpa_s, mgmt, len, rx_status); + break; + case WLAN_FC_STYPE_ASSOC_RESP: + ieee80211_rx_mgmt_assoc_resp(wpa_s, mgmt, len, rx_status, 0); + break; + case WLAN_FC_STYPE_REASSOC_RESP: + ieee80211_rx_mgmt_assoc_resp(wpa_s, mgmt, len, rx_status, 1); + break; + case WLAN_FC_STYPE_DEAUTH: + ieee80211_rx_mgmt_deauth(wpa_s, mgmt, len, rx_status); + break; + case WLAN_FC_STYPE_DISASSOC: + ieee80211_rx_mgmt_disassoc(wpa_s, mgmt, len, rx_status); + break; + case WLAN_FC_STYPE_ACTION: + ieee80211_rx_mgmt_action(wpa_s, mgmt, len, rx_status); + break; + default: + wpa_printf(MSG_DEBUG, "MLME: received unknown management " + "frame - stype=%d", WLAN_FC_GET_STYPE(fc)); + break; + } +} + + +static void ieee80211_sta_rx_scan(struct wpa_supplicant *wpa_s, + const u8 *buf, size_t len, + struct ieee80211_rx_status *rx_status) +{ + struct ieee80211_mgmt *mgmt; + u16 fc; + + if (len < 24) + return; + + mgmt = (struct ieee80211_mgmt *) buf; + fc = le_to_host16(mgmt->frame_control); + + if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT) { + if (WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) { + ieee80211_rx_mgmt_probe_resp(wpa_s, mgmt, + len, rx_status); + } else if (WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) { + ieee80211_rx_mgmt_beacon(wpa_s, mgmt, len, rx_status); + } + } +} + + +static int ieee80211_sta_active_ibss(struct wpa_supplicant *wpa_s) +{ + int active = 0; + +#if 0 /* FIX */ + list_for_each(ptr, &local->sta_list) { + sta = list_entry(ptr, struct sta_info, list); + if (sta->dev == dev && + time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, + jiffies)) { + active++; + break; + } + } +#endif + + return active; +} + + +static void ieee80211_sta_expire(struct wpa_supplicant *wpa_s) +{ +#if 0 /* FIX */ + list_for_each_safe(ptr, n, &local->sta_list) { + sta = list_entry(ptr, struct sta_info, list); + if (time_after(jiffies, sta->last_rx + + IEEE80211_IBSS_INACTIVITY_LIMIT)) { + wpa_printf(MSG_DEBUG, "MLME: expiring inactive STA " + MACSTR, MAC2STR(sta->addr)); + sta_info_free(local, sta, 1); + } + } +#endif +} + + +static void ieee80211_sta_merge_ibss(struct wpa_supplicant *wpa_s) +{ + ieee80211_reschedule_timer(wpa_s, IEEE80211_IBSS_MERGE_INTERVAL); + + ieee80211_sta_expire(wpa_s); + if (ieee80211_sta_active_ibss(wpa_s)) + return; + + wpa_printf(MSG_DEBUG, "MLME: No active IBSS STAs - trying to scan for " + "other IBSS networks with same SSID (merge)"); + ieee80211_sta_req_scan(wpa_s, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len); +} + + +static void ieee80211_sta_timer(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + + switch (wpa_s->mlme.state) { + case IEEE80211_DISABLED: + break; + case IEEE80211_AUTHENTICATE: + ieee80211_authenticate(wpa_s); + break; + case IEEE80211_ASSOCIATE: + ieee80211_associate(wpa_s); + break; + case IEEE80211_ASSOCIATED: + ieee80211_associated(wpa_s); + break; + case IEEE80211_IBSS_SEARCH: + ieee80211_sta_find_ibss(wpa_s); + break; + case IEEE80211_IBSS_JOINED: + ieee80211_sta_merge_ibss(wpa_s); + break; + default: + wpa_printf(MSG_DEBUG, "ieee80211_sta_timer: Unknown state %d", + wpa_s->mlme.state); + break; + } + + if (ieee80211_privacy_mismatch(wpa_s)) { + wpa_printf(MSG_DEBUG, "MLME: privacy configuration mismatch " + "and mixed-cell disabled - disassociate"); + + ieee80211_send_disassoc(wpa_s, WLAN_REASON_UNSPECIFIED); + ieee80211_set_associated(wpa_s, 0); + } +} + + +static void ieee80211_sta_new_auth(struct wpa_supplicant *wpa_s) +{ + struct wpa_ssid *ssid = wpa_s->current_ssid; + if (ssid && ssid->mode != 0) + return; + +#if 0 /* FIX */ + if (local->hw->reset_tsf) { + /* Reset own TSF to allow time synchronization work. */ + local->hw->reset_tsf(local->mdev); + } +#endif + + wpa_s->mlme.wmm_last_param_set = -1; /* allow any WMM update */ + + + if (wpa_s->mlme.auth_algs & IEEE80211_AUTH_ALG_OPEN) + wpa_s->mlme.auth_alg = WLAN_AUTH_OPEN; + else if (wpa_s->mlme.auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY) + wpa_s->mlme.auth_alg = WLAN_AUTH_SHARED_KEY; + else if (wpa_s->mlme.auth_algs & IEEE80211_AUTH_ALG_LEAP) + wpa_s->mlme.auth_alg = WLAN_AUTH_LEAP; + else + wpa_s->mlme.auth_alg = WLAN_AUTH_OPEN; + wpa_printf(MSG_DEBUG, "MLME: Initial auth_alg=%d", + wpa_s->mlme.auth_alg); + wpa_s->mlme.auth_transaction = -1; + wpa_s->mlme.auth_tries = wpa_s->mlme.assoc_tries = 0; + ieee80211_authenticate(wpa_s); +} + + +static int ieee80211_ibss_allowed(struct wpa_supplicant *wpa_s) +{ +#if 0 /* FIX */ + int m, c; + + for (m = 0; m < local->hw->num_modes; m++) { + struct ieee80211_hw_modes *mode = &local->hw->modes[m]; + if (mode->mode != local->conf.phymode) + continue; + for (c = 0; c < mode->num_channels; c++) { + struct ieee80211_channel *chan = &mode->channels[c]; + if (chan->flag & IEEE80211_CHAN_W_SCAN && + chan->chan == local->conf.channel) { + if (chan->flag & IEEE80211_CHAN_W_IBSS) + return 1; + break; + } + } + } +#endif + + return 0; +} + + +static int ieee80211_sta_join_ibss(struct wpa_supplicant *wpa_s, + struct ieee80211_sta_bss *bss) +{ + int res = 0, rates, done = 0; + struct ieee80211_mgmt *mgmt; +#if 0 /* FIX */ + struct ieee80211_tx_control control; + struct ieee80211_rate *rate; + struct rate_control_extra extra; +#endif + u8 *pos, *buf; + size_t len; + + /* Remove possible STA entries from other IBSS networks. */ +#if 0 /* FIX */ + sta_info_flush(local, NULL); + + if (local->hw->reset_tsf) { + /* Reset own TSF to allow time synchronization work. */ + local->hw->reset_tsf(local->mdev); + } +#endif + os_memcpy(wpa_s->bssid, bss->bssid, ETH_ALEN); + +#if 0 /* FIX */ + local->conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10; + + sdata->drop_unencrypted = bss->capability & + host_to_le16(WLAN_CAPABILITY_PRIVACY) ? 1 : 0; +#endif + +#if 0 /* FIX */ + os_memset(&rq, 0, sizeof(rq)); + rq.m = bss->freq * 100000; + rq.e = 1; + res = ieee80211_ioctl_siwfreq(wpa_s, NULL, &rq, NULL); +#endif + + if (!ieee80211_ibss_allowed(wpa_s)) { +#if 0 /* FIX */ + wpa_printf(MSG_DEBUG, "MLME: IBSS not allowed on channel %d " + "(%d MHz)", local->conf.channel, + local->conf.freq); +#endif + return -1; + } + + /* Set beacon template based on scan results */ + buf = os_malloc(400); + len = 0; + do { + if (buf == NULL) + break; + + mgmt = (struct ieee80211_mgmt *) buf; + len += 24 + sizeof(mgmt->u.beacon); + os_memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); + mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_BEACON); + os_memset(mgmt->da, 0xff, ETH_ALEN); + os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); + os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); +#if 0 /* FIX */ + mgmt->u.beacon.beacon_int = + host_to_le16(local->conf.beacon_int); +#endif + mgmt->u.beacon.capab_info = host_to_le16(bss->capability); + + pos = buf + len; + len += 2 + wpa_s->mlme.ssid_len; + *pos++ = WLAN_EID_SSID; + *pos++ = wpa_s->mlme.ssid_len; + os_memcpy(pos, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len); + + rates = bss->supp_rates_len; + if (rates > 8) + rates = 8; + pos = buf + len; + len += 2 + rates; + *pos++ = WLAN_EID_SUPP_RATES; + *pos++ = rates; + os_memcpy(pos, bss->supp_rates, rates); + + pos = buf + len; + len += 2 + 1; + *pos++ = WLAN_EID_DS_PARAMS; + *pos++ = 1; + *pos++ = bss->channel; + + pos = buf + len; + len += 2 + 2; + *pos++ = WLAN_EID_IBSS_PARAMS; + *pos++ = 2; + /* FIX: set ATIM window based on scan results */ + *pos++ = 0; + *pos++ = 0; + + if (bss->supp_rates_len > 8) { + rates = bss->supp_rates_len - 8; + pos = buf + len; + len += 2 + rates; + *pos++ = WLAN_EID_EXT_SUPP_RATES; + *pos++ = rates; + os_memcpy(pos, &bss->supp_rates[8], rates); + } + +#if 0 /* FIX */ + os_memset(&control, 0, sizeof(control)); + control.pkt_type = PKT_PROBE_RESP; + os_memset(&extra, 0, sizeof(extra)); + extra.endidx = local->num_curr_rates; + rate = rate_control_get_rate(wpa_s, skb, &extra); + if (rate == NULL) { + wpa_printf(MSG_DEBUG, "MLME: Failed to determine TX " + "rate for IBSS beacon"); + break; + } + control.tx_rate = (wpa_s->mlme.short_preamble && + (rate->flags & IEEE80211_RATE_PREAMBLE2)) ? + rate->val2 : rate->val; + control.antenna_sel = local->conf.antenna_sel; + control.power_level = local->conf.power_level; + control.no_ack = 1; + control.retry_limit = 1; + control.rts_cts_duration = 0; +#endif + +#if 0 /* FIX */ + wpa_s->mlme.probe_resp = skb_copy(skb, GFP_ATOMIC); + if (wpa_s->mlme.probe_resp) { + mgmt = (struct ieee80211_mgmt *) + wpa_s->mlme.probe_resp->data; + mgmt->frame_control = + IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_PROBE_RESP); + } else { + wpa_printf(MSG_DEBUG, "MLME: Could not allocate " + "ProbeResp template for IBSS"); + } + + if (local->hw->beacon_update && + local->hw->beacon_update(wpa_s, skb, &control) == 0) { + wpa_printf(MSG_DEBUG, "MLME: Configured IBSS beacon " + "template based on scan results"); + skb = NULL; + } + + rates = 0; + for (i = 0; i < bss->supp_rates_len; i++) { + int rate = (bss->supp_rates[i] & 0x7f) * 5; + if (local->conf.phymode == MODE_ATHEROS_TURBO) + rate *= 2; + for (j = 0; j < local->num_curr_rates; j++) + if (local->curr_rates[j].rate == rate) + rates |= BIT(j); + } + wpa_s->mlme.supp_rates_bits = rates; +#endif + done = 1; + } while (0); + + os_free(buf); + if (!done) { + wpa_printf(MSG_DEBUG, "MLME: Failed to configure IBSS beacon " + "template"); + } + + wpa_s->mlme.state = IEEE80211_IBSS_JOINED; + ieee80211_reschedule_timer(wpa_s, IEEE80211_IBSS_MERGE_INTERVAL); + + return res; +} + + +#if 0 /* FIX */ +static int ieee80211_sta_create_ibss(struct wpa_supplicant *wpa_s) +{ + struct ieee80211_sta_bss *bss; + u8 bssid[ETH_ALEN], *pos; + int i; + +#if 0 + /* Easier testing, use fixed BSSID. */ + os_memset(bssid, 0xfe, ETH_ALEN); +#else + /* Generate random, not broadcast, locally administered BSSID. Mix in + * own MAC address to make sure that devices that do not have proper + * random number generator get different BSSID. */ + os_get_random(bssid, ETH_ALEN); + for (i = 0; i < ETH_ALEN; i++) + bssid[i] ^= wpa_s->own_addr[i]; + bssid[0] &= ~0x01; + bssid[0] |= 0x02; +#endif + + wpa_printf(MSG_DEBUG, "MLME: Creating new IBSS network, BSSID " + MACSTR "", MAC2STR(bssid)); + + bss = ieee80211_bss_add(wpa_s, bssid); + if (bss == NULL) + return -ENOMEM; + +#if 0 /* FIX */ + if (local->conf.beacon_int == 0) + local->conf.beacon_int = 100; + bss->beacon_int = local->conf.beacon_int; + bss->hw_mode = local->conf.phymode; + bss->channel = local->conf.channel; + bss->freq = local->conf.freq; +#endif + os_get_time(&bss->last_update); + bss->capability = host_to_le16(WLAN_CAPABILITY_IBSS); +#if 0 /* FIX */ + if (sdata->default_key) { + bss->capability |= host_to_le16(WLAN_CAPABILITY_PRIVACY); + } else + sdata->drop_unencrypted = 0; + bss->supp_rates_len = local->num_curr_rates; +#endif + pos = bss->supp_rates; +#if 0 /* FIX */ + for (i = 0; i < local->num_curr_rates; i++) { + int rate = local->curr_rates[i].rate; + if (local->conf.phymode == MODE_ATHEROS_TURBO) + rate /= 2; + *pos++ = (u8) (rate / 5); + } +#endif + + return ieee80211_sta_join_ibss(wpa_s, bss); +} +#endif + + +static int ieee80211_sta_find_ibss(struct wpa_supplicant *wpa_s) +{ + struct ieee80211_sta_bss *bss; + int found = 0; + u8 bssid[ETH_ALEN]; + int active_ibss; + struct os_time now; + + if (wpa_s->mlme.ssid_len == 0) + return -EINVAL; + + active_ibss = ieee80211_sta_active_ibss(wpa_s); +#ifdef IEEE80211_IBSS_DEBUG + wpa_printf(MSG_DEBUG, "MLME: sta_find_ibss (active_ibss=%d)", + active_ibss); +#endif /* IEEE80211_IBSS_DEBUG */ + for (bss = wpa_s->mlme.sta_bss_list; bss; bss = bss->next) { + if (wpa_s->mlme.ssid_len != bss->ssid_len || + os_memcmp(wpa_s->mlme.ssid, bss->ssid, bss->ssid_len) != 0 + || !(bss->capability & WLAN_CAPABILITY_IBSS)) + continue; +#ifdef IEEE80211_IBSS_DEBUG + wpa_printf(MSG_DEBUG, " bssid=" MACSTR " found", + MAC2STR(bss->bssid)); +#endif /* IEEE80211_IBSS_DEBUG */ + os_memcpy(bssid, bss->bssid, ETH_ALEN); + found = 1; + if (active_ibss || + os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) + break; + } + +#ifdef IEEE80211_IBSS_DEBUG + wpa_printf(MSG_DEBUG, " sta_find_ibss: selected " MACSTR " current " + MACSTR, MAC2STR(bssid), MAC2STR(wpa_s->bssid)); +#endif /* IEEE80211_IBSS_DEBUG */ + if (found && os_memcmp(wpa_s->bssid, bssid, ETH_ALEN) != 0 && + (bss = ieee80211_bss_get(wpa_s, bssid))) { + wpa_printf(MSG_DEBUG, "MLME: Selected IBSS BSSID " MACSTR + " based on configured SSID", + MAC2STR(bssid)); + return ieee80211_sta_join_ibss(wpa_s, bss); + } +#ifdef IEEE80211_IBSS_DEBUG + wpa_printf(MSG_DEBUG, " did not try to join ibss"); +#endif /* IEEE80211_IBSS_DEBUG */ + + /* Selected IBSS not found in current scan results - try to scan */ + os_get_time(&now); +#if 0 /* FIX */ + if (wpa_s->mlme.state == IEEE80211_IBSS_JOINED && + !ieee80211_sta_active_ibss(wpa_s)) { + ieee80211_reschedule_timer(wpa_s, + IEEE80211_IBSS_MERGE_INTERVAL); + } else if (time_after(jiffies, wpa_s->mlme.last_scan_completed + + IEEE80211_SCAN_INTERVAL)) { + wpa_printf(MSG_DEBUG, "MLME: Trigger new scan to find an IBSS " + "to join"); + return ieee80211_sta_req_scan(wpa_s->mlme.ssid, + wpa_s->mlme.ssid_len); + } else if (wpa_s->mlme.state != IEEE80211_IBSS_JOINED) { + int interval = IEEE80211_SCAN_INTERVAL; + + if (time_after(jiffies, wpa_s->mlme.ibss_join_req + + IEEE80211_IBSS_JOIN_TIMEOUT)) { + if (wpa_s->mlme.create_ibss && + ieee80211_ibss_allowed(wpa_s)) + return ieee80211_sta_create_ibss(wpa_s); + if (wpa_s->mlme.create_ibss) { + wpa_printf(MSG_DEBUG, "MLME: IBSS not allowed " + "on the configured channel %d " + "(%d MHz)", + local->conf.channel, + local->conf.freq); + } + + /* No IBSS found - decrease scan interval and continue + * scanning. */ + interval = IEEE80211_SCAN_INTERVAL_SLOW; + } + + wpa_s->mlme.state = IEEE80211_IBSS_SEARCH; + ieee80211_reschedule_timer(wpa_s, interval); + return 0; + } +#endif + + return 0; +} + + +int ieee80211_sta_get_ssid(struct wpa_supplicant *wpa_s, u8 *ssid, + size_t *len) +{ + os_memcpy(ssid, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len); + *len = wpa_s->mlme.ssid_len; + return 0; +} + + +int ieee80211_sta_associate(struct wpa_supplicant *wpa_s, + struct wpa_driver_associate_params *params) +{ + struct ieee80211_sta_bss *bss; + + wpa_s->mlme.bssid_set = 0; + wpa_s->mlme.freq = params->freq; + if (params->bssid) { + os_memcpy(wpa_s->bssid, params->bssid, ETH_ALEN); + if (!is_zero_ether_addr(params->bssid)) + wpa_s->mlme.bssid_set = 1; + bss = ieee80211_bss_get(wpa_s, wpa_s->bssid); + if (bss) { + wpa_s->mlme.phymode = bss->hw_mode; + wpa_s->mlme.channel = bss->channel; + wpa_s->mlme.freq = bss->freq; + } + } + +#if 0 /* FIX */ + /* TODO: This should always be done for IBSS, even if IEEE80211_QOS is + * not defined. */ + if (local->hw->conf_tx) { + struct ieee80211_tx_queue_params qparam; + int i; + + os_memset(&qparam, 0, sizeof(qparam)); + /* TODO: are these ok defaults for all hw_modes? */ + qparam.aifs = 2; + qparam.cw_min = + local->conf.phymode == MODE_IEEE80211B ? 31 : 15; + qparam.cw_max = 1023; + qparam.burst_time = 0; + for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++) + { + local->hw->conf_tx(wpa_s, i + IEEE80211_TX_QUEUE_DATA0, + &qparam); + } + /* IBSS uses different parameters for Beacon sending */ + qparam.cw_min++; + qparam.cw_min *= 2; + qparam.cw_min--; + local->hw->conf_tx(wpa_s, IEEE80211_TX_QUEUE_BEACON, &qparam); + } +#endif + + if (wpa_s->mlme.ssid_len != params->ssid_len || + os_memcmp(wpa_s->mlme.ssid, params->ssid, params->ssid_len) != 0) + wpa_s->mlme.prev_bssid_set = 0; + os_memcpy(wpa_s->mlme.ssid, params->ssid, params->ssid_len); + os_memset(wpa_s->mlme.ssid + params->ssid_len, 0, + MAX_SSID_LEN - params->ssid_len); + wpa_s->mlme.ssid_len = params->ssid_len; + wpa_s->mlme.ssid_set = 1; + + os_free(wpa_s->mlme.extra_ie); + if (params->wpa_ie == NULL || params->wpa_ie_len == 0) { + wpa_s->mlme.extra_ie = NULL; + wpa_s->mlme.extra_ie_len = 0; + } else { + wpa_s->mlme.extra_ie = os_malloc(params->wpa_ie_len); + if (wpa_s->mlme.extra_ie == NULL) { + wpa_s->mlme.extra_ie_len = 0; + return -1; + } + os_memcpy(wpa_s->mlme.extra_ie, params->wpa_ie, + params->wpa_ie_len); + wpa_s->mlme.extra_ie_len = params->wpa_ie_len; + } + + wpa_s->mlme.key_mgmt = params->key_mgmt_suite; + + ieee80211_sta_set_channel(wpa_s, wpa_s->mlme.phymode, + wpa_s->mlme.channel, wpa_s->mlme.freq); + + if (params->mode == 1 && !wpa_s->mlme.bssid_set) { + os_get_time(&wpa_s->mlme.ibss_join_req); + wpa_s->mlme.state = IEEE80211_IBSS_SEARCH; + return ieee80211_sta_find_ibss(wpa_s); + } + + if (wpa_s->mlme.bssid_set) + ieee80211_sta_new_auth(wpa_s); + + return 0; +} + + +static void ieee80211_sta_save_oper_chan(struct wpa_supplicant *wpa_s) +{ + wpa_s->mlme.scan_oper_channel = wpa_s->mlme.channel; + wpa_s->mlme.scan_oper_freq = wpa_s->mlme.freq; + wpa_s->mlme.scan_oper_phymode = wpa_s->mlme.phymode; +} + + +static int ieee80211_sta_restore_oper_chan(struct wpa_supplicant *wpa_s) +{ + wpa_s->mlme.channel = wpa_s->mlme.scan_oper_channel; + wpa_s->mlme.freq = wpa_s->mlme.scan_oper_freq; + wpa_s->mlme.phymode = wpa_s->mlme.scan_oper_phymode; + if (wpa_s->mlme.freq == 0) + return 0; + return ieee80211_sta_set_channel(wpa_s, wpa_s->mlme.phymode, + wpa_s->mlme.channel, + wpa_s->mlme.freq); +} + + +static int ieee80211_active_scan(struct wpa_supplicant *wpa_s) +{ + size_t m; + int c; + + for (m = 0; m < wpa_s->mlme.num_modes; m++) { + struct wpa_hw_modes *mode = &wpa_s->mlme.modes[m]; + if ((int) mode->mode != (int) wpa_s->mlme.phymode) + continue; + for (c = 0; c < mode->num_channels; c++) { + struct wpa_channel_data *chan = &mode->channels[c]; + if (chan->flag & WPA_CHAN_W_SCAN && + chan->chan == wpa_s->mlme.channel) { + if (chan->flag & WPA_CHAN_W_ACTIVE_SCAN) + return 1; + break; + } + } + } + + return 0; +} + + +static void ieee80211_sta_scan_timer(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + struct wpa_hw_modes *mode; + struct wpa_channel_data *chan; + int skip = 0; + int timeout = 0; + struct wpa_ssid *ssid = wpa_s->current_ssid; + int adhoc; + + if (!wpa_s->mlme.sta_scanning || wpa_s->mlme.modes == NULL) + return; + + adhoc = ssid && ssid->mode == 1; + + switch (wpa_s->mlme.scan_state) { + case SCAN_SET_CHANNEL: + mode = &wpa_s->mlme.modes[wpa_s->mlme.scan_hw_mode_idx]; + if (wpa_s->mlme.scan_hw_mode_idx >= + (int) wpa_s->mlme.num_modes || + (wpa_s->mlme.scan_hw_mode_idx + 1 == + (int) wpa_s->mlme.num_modes + && wpa_s->mlme.scan_channel_idx >= mode->num_channels)) { + if (ieee80211_sta_restore_oper_chan(wpa_s)) { + wpa_printf(MSG_DEBUG, "MLME: failed to " + "restore operational channel after " + "scan"); + } + wpa_printf(MSG_DEBUG, "MLME: scan completed"); + wpa_s->mlme.sta_scanning = 0; + os_get_time(&wpa_s->mlme.last_scan_completed); + wpa_supplicant_event(wpa_s, EVENT_SCAN_RESULTS, NULL); + if (adhoc) { + if (!wpa_s->mlme.bssid_set || + (wpa_s->mlme.state == + IEEE80211_IBSS_JOINED && + !ieee80211_sta_active_ibss(wpa_s))) + ieee80211_sta_find_ibss(wpa_s); + } + return; + } + skip = !(wpa_s->mlme.hw_modes & (1 << mode->mode)); + chan = &mode->channels[wpa_s->mlme.scan_channel_idx]; + if (!(chan->flag & WPA_CHAN_W_SCAN) || + (adhoc && !(chan->flag & WPA_CHAN_W_IBSS)) || + (wpa_s->mlme.hw_modes & (1 << WPA_MODE_IEEE80211G) && + mode->mode == WPA_MODE_IEEE80211B && + wpa_s->mlme.scan_skip_11b)) + skip = 1; + + if (!skip) { + wpa_printf(MSG_MSGDUMP, + "MLME: scan channel %d (%d MHz)", + chan->chan, chan->freq); + + wpa_s->mlme.channel = chan->chan; + wpa_s->mlme.freq = chan->freq; + wpa_s->mlme.phymode = mode->mode; + if (ieee80211_sta_set_channel(wpa_s, mode->mode, + chan->chan, chan->freq)) + { + wpa_printf(MSG_DEBUG, "MLME: failed to set " + "channel %d (%d MHz) for scan", + chan->chan, chan->freq); + skip = 1; + } + } + + wpa_s->mlme.scan_channel_idx++; + if (wpa_s->mlme.scan_channel_idx >= + wpa_s->mlme.modes[wpa_s->mlme.scan_hw_mode_idx]. + num_channels) { + wpa_s->mlme.scan_hw_mode_idx++; + wpa_s->mlme.scan_channel_idx = 0; + } + + if (skip) { + timeout = 0; + break; + } + + timeout = IEEE80211_PROBE_DELAY; + wpa_s->mlme.scan_state = SCAN_SEND_PROBE; + break; + case SCAN_SEND_PROBE: + if (ieee80211_active_scan(wpa_s)) { + ieee80211_send_probe_req(wpa_s, NULL, + wpa_s->mlme.scan_ssid, + wpa_s->mlme.scan_ssid_len); + timeout = IEEE80211_CHANNEL_TIME; + } else { + timeout = IEEE80211_PASSIVE_CHANNEL_TIME; + } + wpa_s->mlme.scan_state = SCAN_SET_CHANNEL; + break; + } + + eloop_register_timeout(timeout / 1000, 1000 * (timeout % 1000), + ieee80211_sta_scan_timer, wpa_s, NULL); +} + + +int ieee80211_sta_req_scan(struct wpa_supplicant *wpa_s, const u8 *ssid, + size_t ssid_len) +{ + if (ssid_len > MAX_SSID_LEN) + return -1; + + /* MLME-SCAN.request (page 118) page 144 (11.1.3.1) + * BSSType: INFRASTRUCTURE, INDEPENDENT, ANY_BSS + * BSSID: MACAddress + * SSID + * ScanType: ACTIVE, PASSIVE + * ProbeDelay: delay (in microseconds) to be used prior to transmitting + * a Probe frame during active scanning + * ChannelList + * MinChannelTime (>= ProbeDelay), in TU + * MaxChannelTime: (>= MinChannelTime), in TU + */ + + /* MLME-SCAN.confirm + * BSSDescriptionSet + * ResultCode: SUCCESS, INVALID_PARAMETERS + */ + + /* TODO: if assoc, move to power save mode for the duration of the + * scan */ + + if (wpa_s->mlme.sta_scanning) + return -1; + + wpa_printf(MSG_DEBUG, "MLME: starting scan"); + + ieee80211_sta_save_oper_chan(wpa_s); + + wpa_s->mlme.sta_scanning = 1; + /* TODO: stop TX queue? */ + + if (ssid) { + wpa_s->mlme.scan_ssid_len = ssid_len; + os_memcpy(wpa_s->mlme.scan_ssid, ssid, ssid_len); + } else + wpa_s->mlme.scan_ssid_len = 0; + wpa_s->mlme.scan_skip_11b = 1; /* FIX: clear this is 11g is not + * supported */ + wpa_s->mlme.scan_state = SCAN_SET_CHANNEL; + wpa_s->mlme.scan_hw_mode_idx = 0; + wpa_s->mlme.scan_channel_idx = 0; + eloop_register_timeout(0, 1, ieee80211_sta_scan_timer, wpa_s, NULL); + + return 0; +} + + +struct wpa_scan_results * +ieee80211_sta_get_scan_results(struct wpa_supplicant *wpa_s) +{ + size_t ap_num = 0; + struct wpa_scan_results *res; + struct wpa_scan_res *r; + struct ieee80211_sta_bss *bss; + + res = os_zalloc(sizeof(*res)); + for (bss = wpa_s->mlme.sta_bss_list; bss; bss = bss->next) + ap_num++; + res->res = os_zalloc(ap_num * sizeof(struct wpa_scan_res *)); + if (res->res == NULL) { + os_free(res); + return NULL; + } + + for (bss = wpa_s->mlme.sta_bss_list; bss; bss = bss->next) { + r = os_zalloc(sizeof(*r) + bss->ie_len); + if (r == NULL) + break; + os_memcpy(r->bssid, bss->bssid, ETH_ALEN); + r->freq = bss->freq; + r->beacon_int = bss->beacon_int; + r->caps = bss->capability; + r->level = bss->rssi; + r->tsf = bss->timestamp; + if (bss->ie) { + r->ie_len = bss->ie_len; + os_memcpy(r + 1, bss->ie, bss->ie_len); + } + + res->res[res->num++] = r; + } + + return res; +} + + +#if 0 /* FIX */ +struct sta_info * ieee80211_ibss_add_sta(struct wpa_supplicant *wpa_s, + struct sk_buff *skb, u8 *bssid, + u8 *addr) +{ + struct ieee80211_local *local = dev->priv; + struct list_head *ptr; + struct sta_info *sta; + struct wpa_supplicant *sta_dev = NULL; + + /* TODO: Could consider removing the least recently used entry and + * allow new one to be added. */ + if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { + if (net_ratelimit()) { + wpa_printf(MSG_DEBUG, "MLME: No room for a new IBSS " + "STA entry " MACSTR, MAC2STR(addr)); + } + return NULL; + } + + spin_lock_bh(&local->sub_if_lock); + list_for_each(ptr, &local->sub_if_list) { + sdata = list_entry(ptr, struct ieee80211_sub_if_data, list); + if (sdata->type == IEEE80211_SUB_IF_TYPE_STA && + os_memcmp(bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) { + sta_dev = sdata->dev; + break; + } + } + spin_unlock_bh(&local->sub_if_lock); + + if (sta_dev == NULL) + return NULL; + + wpa_printf(MSG_DEBUG, "MLME: Adding new IBSS station " MACSTR + " (dev=%s)", MAC2STR(addr), sta_dev->name); + + sta = sta_info_add(wpa_s, addr); + if (sta == NULL) { + return NULL; + } + + sta->dev = sta_dev; + sta->supp_rates = wpa_s->mlme.supp_rates_bits; + + rate_control_rate_init(local, sta); + + return sta; /* caller will call sta_info_release() */ +} +#endif + + +int ieee80211_sta_deauthenticate(struct wpa_supplicant *wpa_s, u16 reason) +{ + wpa_printf(MSG_DEBUG, "MLME: deauthenticate(reason=%d)", reason); + + ieee80211_send_deauth(wpa_s, reason); + ieee80211_set_associated(wpa_s, 0); + return 0; +} + + +int ieee80211_sta_disassociate(struct wpa_supplicant *wpa_s, u16 reason) +{ + wpa_printf(MSG_DEBUG, "MLME: disassociate(reason=%d)", reason); + + if (!wpa_s->mlme.associated) + return -1; + + ieee80211_send_disassoc(wpa_s, reason); + ieee80211_set_associated(wpa_s, 0); + return 0; +} + + +void ieee80211_sta_rx(struct wpa_supplicant *wpa_s, const u8 *buf, size_t len, + struct ieee80211_rx_status *rx_status) +{ + struct ieee80211_mgmt *mgmt; + u16 fc; + const u8 *pos; + + /* wpa_hexdump(MSG_MSGDUMP, "MLME: Received frame", buf, len); */ + + if (wpa_s->mlme.sta_scanning) { + ieee80211_sta_rx_scan(wpa_s, buf, len, rx_status); + return; + } + + if (len < 24) + return; + + mgmt = (struct ieee80211_mgmt *) buf; + fc = le_to_host16(mgmt->frame_control); + + if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT) + ieee80211_sta_rx_mgmt(wpa_s, buf, len, rx_status); + else if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA) { + if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) != + WLAN_FC_FROMDS) + return; + /* mgmt->sa is actually BSSID for FromDS data frames */ + if (os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) + return; + /* Skip IEEE 802.11 and LLC headers */ + pos = buf + 24 + 6; + if (WPA_GET_BE16(pos) != ETH_P_EAPOL) + return; + pos += 2; + /* mgmt->bssid is actually BSSID for SA data frames */ + wpa_supplicant_rx_eapol(wpa_s, mgmt->bssid, + pos, buf + len - pos); + } +} + + +void ieee80211_sta_free_hw_features(struct wpa_hw_modes *hw_features, + size_t num_hw_features) +{ + size_t i; + + if (hw_features == NULL) + return; + + for (i = 0; i < num_hw_features; i++) { + os_free(hw_features[i].channels); + os_free(hw_features[i].rates); + } + + os_free(hw_features); +} + + +int ieee80211_sta_init(struct wpa_supplicant *wpa_s) +{ + u16 num_modes, flags; + + wpa_s->mlme.modes = wpa_drv_get_hw_feature_data(wpa_s, &num_modes, + &flags); + if (wpa_s->mlme.modes == NULL) { + wpa_printf(MSG_ERROR, "MLME: Failed to read supported " + "channels and rates from the driver"); + return -1; + } + + wpa_s->mlme.num_modes = num_modes; + + wpa_s->mlme.hw_modes = 1 << WPA_MODE_IEEE80211A; + wpa_s->mlme.hw_modes |= 1 << WPA_MODE_IEEE80211B; + wpa_s->mlme.hw_modes |= 1 << WPA_MODE_IEEE80211G; + + return 0; +} + + +void ieee80211_sta_deinit(struct wpa_supplicant *wpa_s) +{ + eloop_cancel_timeout(ieee80211_sta_timer, wpa_s, NULL); + eloop_cancel_timeout(ieee80211_sta_scan_timer, wpa_s, NULL); + os_free(wpa_s->mlme.extra_ie); + wpa_s->mlme.extra_ie = NULL; + os_free(wpa_s->mlme.extra_probe_ie); + wpa_s->mlme.extra_probe_ie = NULL; + os_free(wpa_s->mlme.assocreq_ies); + wpa_s->mlme.assocreq_ies = NULL; + os_free(wpa_s->mlme.assocresp_ies); + wpa_s->mlme.assocresp_ies = NULL; + ieee80211_bss_list_deinit(wpa_s); + ieee80211_sta_free_hw_features(wpa_s->mlme.modes, + wpa_s->mlme.num_modes); +#ifdef CONFIG_IEEE80211R + os_free(wpa_s->mlme.ft_ies); + wpa_s->mlme.ft_ies = NULL; + wpa_s->mlme.ft_ies_len = 0; +#endif /* CONFIG_IEEE80211R */ +} + + +#ifdef CONFIG_IEEE80211R + +int ieee80211_sta_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md, + const u8 *ies, size_t ies_len) +{ + if (md == NULL) { + wpa_printf(MSG_DEBUG, "MLME: Clear FT mobility domain"); + os_memset(wpa_s->mlme.current_md, 0, MOBILITY_DOMAIN_ID_LEN); + } else { + wpa_printf(MSG_DEBUG, "MLME: Update FT IEs for MD " MACSTR, + MAC2STR(md)); + os_memcpy(wpa_s->mlme.current_md, md, MOBILITY_DOMAIN_ID_LEN); + } + + wpa_hexdump(MSG_DEBUG, "MLME: FT IEs", ies, ies_len); + os_free(wpa_s->mlme.ft_ies); + wpa_s->mlme.ft_ies = os_malloc(ies_len); + if (wpa_s->mlme.ft_ies == NULL) + return -1; + os_memcpy(wpa_s->mlme.ft_ies, ies, ies_len); + wpa_s->mlme.ft_ies_len = ies_len; + + return 0; +} + + +int ieee80211_sta_send_ft_action(struct wpa_supplicant *wpa_s, u8 action, + const u8 *target_ap, + const u8 *ies, size_t ies_len) +{ + u8 *buf; + size_t len; + struct ieee80211_mgmt *mgmt; + int res; + + /* + * Action frame payload: + * Category[1] = 6 (Fast BSS Transition) + * Action[1] = 1 (Fast BSS Transition Request) + * STA Address + * Target AP Address + * FT IEs + */ + + buf = os_zalloc(sizeof(*mgmt) + ies_len); + if (buf == NULL) { + wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for " + "FT action frame"); + return -1; + } + + mgmt = (struct ieee80211_mgmt *) buf; + len = 24; + os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); + os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); + os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); + mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_ACTION); + mgmt->u.action.category = WLAN_ACTION_FT; + mgmt->u.action.u.ft_action_req.action = action; + os_memcpy(mgmt->u.action.u.ft_action_req.sta_addr, wpa_s->own_addr, + ETH_ALEN); + os_memcpy(mgmt->u.action.u.ft_action_req.target_ap_addr, target_ap, + ETH_ALEN); + os_memcpy(mgmt->u.action.u.ft_action_req.variable, ies, ies_len); + len += 1 + sizeof(mgmt->u.action.u.ft_action_req) + ies_len; + + wpa_printf(MSG_DEBUG, "MLME: Send FT Action Frame: Action=%d " + "Target AP=" MACSTR " body_len=%lu", + action, MAC2STR(target_ap), (unsigned long) ies_len); + + res = ieee80211_sta_tx(wpa_s, buf, len); + os_free(buf); + + return res; +} + +#endif /* CONFIG_IEEE80211R */ + + +int ieee80211_sta_set_probe_req_ie(struct wpa_supplicant *wpa_s, const u8 *ies, + size_t ies_len) +{ + os_free(wpa_s->mlme.extra_probe_ie); + wpa_s->mlme.extra_probe_ie = NULL; + wpa_s->mlme.extra_probe_ie_len = 0; + + if (ies == NULL) + return 0; + + wpa_s->mlme.extra_probe_ie = os_malloc(ies_len); + if (wpa_s->mlme.extra_probe_ie == NULL) + return -1; + + os_memcpy(wpa_s->mlme.extra_probe_ie, ies, ies_len); + wpa_s->mlme.extra_probe_ie_len = ies_len; + + return 0; +} diff --git a/wpa_supplicant/mlme.h b/wpa_supplicant/mlme.h new file mode 100644 index 000000000000..cc58a5b40868 --- /dev/null +++ b/wpa_supplicant/mlme.h @@ -0,0 +1,132 @@ +/* + * WPA Supplicant - Client mode MLME + * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004, Instant802 Networks, Inc. + * Copyright (c) 2005-2006, Devicescape Software, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef MLME_H +#define MLME_H + +struct wpa_supplicant; + +#ifdef CONFIG_CLIENT_MLME + +int ieee80211_sta_init(struct wpa_supplicant *wpa_s); +void ieee80211_sta_deinit(struct wpa_supplicant *wpa_s); +int ieee80211_sta_req_scan(struct wpa_supplicant *wpa_s, const u8 *ssid, + size_t ssid_len); +int ieee80211_sta_deauthenticate(struct wpa_supplicant *wpa_s, u16 reason); +int ieee80211_sta_disassociate(struct wpa_supplicant *wpa_s, u16 reason); +int ieee80211_sta_associate(struct wpa_supplicant *wpa_s, + struct wpa_driver_associate_params *params); +int ieee80211_sta_get_ssid(struct wpa_supplicant *wpa_s, u8 *ssid, + size_t *len); +void ieee80211_sta_free_hw_features(struct wpa_hw_modes *hw_features, + size_t num_hw_features); +void ieee80211_sta_rx(struct wpa_supplicant *wpa_s, const u8 *buf, size_t len, + struct ieee80211_rx_status *rx_status); +struct wpa_scan_results * +ieee80211_sta_get_scan_results(struct wpa_supplicant *wpa_s); +int ieee80211_sta_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md, + const u8 *ies, size_t ies_len); +int ieee80211_sta_send_ft_action(struct wpa_supplicant *wpa_s, u8 action, + const u8 *target_ap, + const u8 *ies, size_t ies_len); +int ieee80211_sta_set_probe_req_ie(struct wpa_supplicant *wpa_s, const u8 *ies, + size_t ies_len); + +#else /* CONFIG_CLIENT_MLME */ + +static inline int ieee80211_sta_init(struct wpa_supplicant *wpa_s) +{ + return 0; +} + +static inline void ieee80211_sta_deinit(struct wpa_supplicant *wpa_s) +{ +} + +static inline int ieee80211_sta_req_scan(struct wpa_supplicant *wpa_s, + const u8 *ssid, size_t ssid_len) +{ + return -1; +} + +static inline int ieee80211_sta_deauthenticate(struct wpa_supplicant *wpa_s, + u16 reason) +{ + return -1; +} + +static inline int ieee80211_sta_disassociate(struct wpa_supplicant *wpa_s, + u16 reason) +{ + return -1; +} + +static inline int +ieee80211_sta_associate(struct wpa_supplicant *wpa_s, + struct wpa_driver_associate_params *params) +{ + return -1; +} + +static inline int ieee80211_sta_get_ssid(struct wpa_supplicant *wpa_s, + u8 *ssid, size_t *len) +{ + return -1; +} + +static inline void +ieee80211_sta_free_hw_features(struct wpa_hw_modes *hw_features, + size_t num_hw_features) +{ +} + +static inline void +ieee80211_sta_rx(struct wpa_supplicant *wpa_s, const u8 *buf, size_t len, + struct ieee80211_rx_status *rx_status) +{ +} + +static inline struct wpa_scan_results * +ieee80211_sta_get_scan_results(struct wpa_supplicant *wpa_s) +{ + return NULL; +} + +static inline int +ieee80211_sta_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md, + const u8 *ies, size_t ies_len) +{ + return -1; +} + +static inline int +ieee80211_sta_send_ft_action(struct wpa_supplicant *wpa_s, u8 action, + const u8 *target_ap, + const u8 *ies, size_t ies_len) +{ + return -1; +} + +static inline int +ieee80211_sta_set_probe_req_ie(struct wpa_supplicant *wpa_s, const u8 *ies, + size_t ies_len) +{ + return -1; +} + +#endif /* CONFIG_CLIENT_MLME */ + +#endif /* MLME_H */ diff --git a/wpa_supplicant/nmake.mak b/wpa_supplicant/nmake.mak new file mode 100644 index 000000000000..5e39c117d396 --- /dev/null +++ b/wpa_supplicant/nmake.mak @@ -0,0 +1,228 @@ +# Makefile for Microsoft nmake to build wpa_supplicant + +# This can be run in Visual Studio 2005 Command Prompt + +# Note: Make sure that cl.exe is configured to include Platform SDK +# include and lib directories (vsvars32.bat) + +all: wpa_supplicant.exe wpa_cli.exe wpa_passphrase.exe wpasvc.exe win_if_list.exe + +# Root directory for WinPcap developer's pack +# (http://www.winpcap.org/install/bin/WpdPack_3_1.zip) +WINPCAPDIR=C:\dev\WpdPack + +# Root directory for OpenSSL +# (http://www.openssl.org/source/openssl-0.9.8a.tar.gz) +# Build and installed following instructions in INSTALL.W32 +# Note: If EAP-FAST is included in the build, OpenSSL needs to be patched to +# support it (openssl-tls-extensions.patch) +# Alternatively, see README-Windows.txt for information about binary +# installation package for OpenSSL. +OPENSSLDIR=C:\dev\openssl + +CC = cl +OBJDIR = objs + +CFLAGS = /DCONFIG_NATIVE_WINDOWS +CFLAGS = $(CFLAGS) /DCONFIG_NDIS_EVENTS_INTEGRATED +CFLAGS = $(CFLAGS) /DCONFIG_ANSI_C_EXTRA +CFLAGS = $(CFLAGS) /DCONFIG_WINPCAP +CFLAGS = $(CFLAGS) /DIEEE8021X_EAPOL +CFLAGS = $(CFLAGS) /DEAP_TLS_FUNCS +CFLAGS = $(CFLAGS) /DPKCS12_FUNCS +CFLAGS = $(CFLAGS) /DEAP_MD5 +CFLAGS = $(CFLAGS) /DEAP_TLS +CFLAGS = $(CFLAGS) /DEAP_MSCHAPv2 +CFLAGS = $(CFLAGS) /DEAP_PEAP +CFLAGS = $(CFLAGS) /DEAP_TTLS +CFLAGS = $(CFLAGS) /DEAP_GTC +CFLAGS = $(CFLAGS) /DEAP_OTP +CFLAGS = $(CFLAGS) /DEAP_SIM +CFLAGS = $(CFLAGS) /DEAP_LEAP +CFLAGS = $(CFLAGS) /DEAP_PSK +CFLAGS = $(CFLAGS) /DEAP_AKA +#CFLAGS = $(CFLAGS) /DEAP_FAST +CFLAGS = $(CFLAGS) /DEAP_PAX +CFLAGS = $(CFLAGS) /DEAP_TNC +CFLAGS = $(CFLAGS) /DPCSC_FUNCS +CFLAGS = $(CFLAGS) /DCONFIG_CTRL_IFACE +CFLAGS = $(CFLAGS) /DCONFIG_CTRL_IFACE_NAMED_PIPE +CFLAGS = $(CFLAGS) /DCONFIG_DRIVER_NDIS +CFLAGS = $(CFLAGS) /I..\src /I..\src\utils /I..\src\common /I..\src\crypto +CFLAGS = $(CFLAGS) /I..\src\rsn_supp /I..\src\eapol_supp /I. +CFLAGS = $(CFLAGS) /DWIN32 +CFLAGS = $(CFLAGS) /Fo$(OBJDIR)\\ /c +CFLAGS = $(CFLAGS) /W3 + +#CFLAGS = $(CFLAGS) /WX + +# VS 2005 complains about lot of deprecated string functions; let's ignore them +# at least for now since snprintf and strncpy can be used in a safe way +CFLAGS = $(CFLAGS) /D_CRT_SECURE_NO_DEPRECATE + +OBJS = \ + $(OBJDIR)\os_win32.obj \ + $(OBJDIR)\eloop_win.obj \ + $(OBJDIR)\sha1.obj \ + $(OBJDIR)\md5.obj \ + $(OBJDIR)\rc4.obj \ + $(OBJDIR)\aes_wrap.obj \ + $(OBJDIR)\common.obj \ + $(OBJDIR)\wpa_debug.obj \ + $(OBJDIR)\wpabuf.obj \ + $(OBJDIR)\wpa_supplicant.obj \ + $(OBJDIR)\wpa.obj \ + $(OBJDIR)\wpa_common.obj \ + $(OBJDIR)\wpa_ie.obj \ + $(OBJDIR)\preauth.obj \ + $(OBJDIR)\pmksa_cache.obj \ + $(OBJDIR)\eapol_supp_sm.obj \ + $(OBJDIR)\eap.obj \ + $(OBJDIR)\eap_common.obj \ + $(OBJDIR)\chap.obj \ + $(OBJDIR)\eap_methods.obj \ + $(OBJDIR)\eap_md5.obj \ + $(OBJDIR)\eap_tls.obj \ + $(OBJDIR)\eap_tls_common.obj \ + $(OBJDIR)\eap_mschapv2.obj \ + $(OBJDIR)\mschapv2.obj \ + $(OBJDIR)\eap_peap.obj \ + $(OBJDIR)\eap_peap_common.obj \ + $(OBJDIR)\eap_ttls.obj \ + $(OBJDIR)\eap_gtc.obj \ + $(OBJDIR)\eap_otp.obj \ + $(OBJDIR)\eap_leap.obj \ + $(OBJDIR)\eap_sim.obj \ + $(OBJDIR)\eap_sim_common.obj \ + $(OBJDIR)\eap_aka.obj \ + $(OBJDIR)\eap_pax.obj \ + $(OBJDIR)\eap_pax_common.obj \ + $(OBJDIR)\eap_psk.obj \ + $(OBJDIR)\eap_psk_common.obj \ + $(OBJDIR)\eap_tnc.obj \ + $(OBJDIR)\tncc.obj \ + $(OBJDIR)\base64.obj \ + $(OBJDIR)\ctrl_iface.obj \ + $(OBJDIR)\ctrl_iface_named_pipe.obj \ + $(OBJDIR)\driver_ndis.obj \ + $(OBJDIR)\driver_ndis_.obj \ + $(OBJDIR)\scan_helpers.obj \ + $(OBJDIR)\events.obj \ + $(OBJDIR)\blacklist.obj \ + $(OBJDIR)\scan.obj \ + $(OBJDIR)\wpas_glue.obj \ + $(OBJDIR)\config.obj \ + $(OBJDIR)\l2_packet_winpcap.obj \ + $(OBJDIR)\tls_openssl.obj \ + $(OBJDIR)\ms_funcs.obj \ + $(OBJDIR)\crypto_openssl.obj \ + $(OBJDIR)\pcsc_funcs.obj \ + $(OBJDIR)\ndis_events.obj + +# OBJS = $(OBJS) $(OBJDIR)\eap_fast.obj + +OBJS_t = $(OBJS) \ + $(OBJDIR)\eapol_test.obj \ + $(OBJDIR)\radius.obj \ + $(OBJDIR)\radius_client.obj \ + $(OBJDIR)\config_file.obj $(OBJDIR)\base64.obj + +OBJS_t2 = $(OBJS) \ + $(OBJDIR)\preauth_test.obj \ + $(OBJDIR)\config_file.obj $(OBJDIR)\base64.obj + +OBJS2 = $(OBJDIR)\drivers.obj \ + $(OBJDIR)\config_file.obj \ + $(OBJS2) $(OBJDIR)\main.obj + +OBJS3 = $(OBJDIR)\drivers.obj \ + $(OBJDIR)\config_winreg.obj \ + $(OBJS3) $(OBJDIR)\main_winsvc.obj + +OBJS_c = \ + $(OBJDIR)\os_win32.obj \ + $(OBJDIR)\wpa_cli.obj \ + $(OBJDIR)\wpa_ctrl.obj \ + $(OBJDIR)\common.obj + +OBJS_p = \ + $(OBJDIR)\os_win32.obj \ + $(OBJDIR)\common.obj \ + $(OBJDIR)\sha1.obj \ + $(OBJDIR)\md5.obj \ + $(OBJDIR)\crypto_openssl.obj \ + $(OBJDIR)\wpa_passphrase.obj + +LIBS = wbemuuid.lib libcmt.lib kernel32.lib uuid.lib ole32.lib oleaut32.lib \ + ws2_32.lib Advapi32.lib Crypt32.lib Winscard.lib \ + Packet.lib wpcap.lib \ + libeay32.lib ssleay32.lib +# If using Win32 OpenSSL binary installation from Shining Light Productions, +# replace the last line with this for dynamic libraries +# libeay32MT.lib ssleay32MT.lib +# and this for static libraries +# libeay32MT.lib ssleay32MT.lib Gdi32.lib User32.lib + +CFLAGS = $(CFLAGS) /I"$(WINPCAPDIR)/Include" /I"$(OPENSSLDIR)\include" +LFLAGS = /libpath:"$(WINPCAPDIR)\Lib" /libpath:"$(OPENSSLDIR)\lib" + +wpa_supplicant.exe: $(OBJDIR) $(OBJS) $(OBJS2) + link.exe /out:wpa_supplicant.exe $(LFLAGS) $(OBJS) $(OBJS2) $(LIBS) + +wpasvc.exe: $(OBJDIR) $(OBJS) $(OBJS3) + link.exe /out:wpasvc.exe $(LFLAGS) $(OBJS) $(OBJS3) $(LIBS) + +wpa_cli.exe: $(OBJDIR) $(OBJS_c) + link.exe /out:wpa_cli.exe $(LFLAGS) $(OBJS_c) $(LIBS) + +wpa_passphrase.exe: $(OBJDIR) $(OBJS_p) + link.exe /out:wpa_passphrase.exe $(LFLAGS) $(OBJS_p) $(LIBS) + +eapol_test.exe: $(OBJDIR) $(OBJS_t) + link.exe /out:eapol_test.exe $(LFLAGS) $(OBJS_t) $(LIBS) + +preauth_test.exe: $(OBJDIR) $(OBJS_t2) + link.exe /out:preauth_test.exe $(LFLAGS) $(OBJS_t2) $(LIBS) + +win_if_list.exe: $(OBJDIR) $(OBJDIR)\win_if_list.obj + link.exe /out:win_if_list.exe $(LFLAGS) $(OBJDIR)\win_if_list.obj $(LIBS) + + +{..\src\utils}.c{$(OBJDIR)}.obj:: + $(CC) $(CFLAGS) $< + +{..\src\common}.c{$(OBJDIR)}.obj:: + $(CC) $(CFLAGS) $< + +{..\src\rsn_supp}.c{$(OBJDIR)}.obj:: + $(CC) $(CFLAGS) $< + +{..\src\eapol_supp}.c{$(OBJDIR)}.obj:: + $(CC) $(CFLAGS) $< + +{..\src\crypto}.c{$(OBJDIR)}.obj:: + $(CC) $(CFLAGS) $< + +{..\src\eap_peer}.c{$(OBJDIR)}.obj:: + $(CC) $(CFLAGS) $< + +{..\src\eap_common}.c{$(OBJDIR)}.obj:: + $(CC) $(CFLAGS) $< + +{..\src\drivers}.c{$(OBJDIR)}.obj:: + $(CC) $(CFLAGS) $< + +{..\src\l2_packet}.c{$(OBJDIR)}.obj:: + $(CC) $(CFLAGS) $< + +{.\}.c{$(OBJDIR)}.obj:: + $(CC) $(CFLAGS) $< + +{.\}.cpp{$(OBJDIR)}.obj:: + $(CC) $(CFLAGS) $< + +$(OBJDIR): + if not exist "$(OBJDIR)" mkdir "$(OBJDIR)" + +clean: + erase $(OBJDIR)\*.obj wpa_supplicant.exe diff --git a/wpa_supplicant/preauth_test.c b/wpa_supplicant/preauth_test.c new file mode 100644 index 000000000000..86307a883cf7 --- /dev/null +++ b/wpa_supplicant/preauth_test.c @@ -0,0 +1,375 @@ +/* + * WPA Supplicant - test code for pre-authentication + * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + * + * IEEE 802.1X Supplicant test code (to be used in place of wpa_supplicant.c. + * Not used in production version. + */ + +#include "includes.h" +#include <assert.h> + +#include "common.h" +#include "config.h" +#include "eapol_supp/eapol_supp_sm.h" +#include "eloop.h" +#include "wpa.h" +#include "eap_peer/eap.h" +#include "wpa_supplicant_i.h" +#include "l2_packet/l2_packet.h" +#include "ctrl_iface.h" +#include "pcsc_funcs.h" +#include "preauth.h" +#include "pmksa_cache.h" + + +extern int wpa_debug_level; +extern int wpa_debug_show_keys; + +struct wpa_driver_ops *wpa_supplicant_drivers[] = { NULL }; + + +struct preauth_test_data { + int auth_timed_out; +}; + + +static void _wpa_supplicant_disassociate(void *wpa_s, int reason_code) +{ + wpa_supplicant_disassociate(wpa_s, reason_code); +} + + +static void _wpa_supplicant_deauthenticate(void *wpa_s, int reason_code) +{ + wpa_supplicant_deauthenticate(wpa_s, reason_code); +} + + +static u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type, + const void *data, u16 data_len, + size_t *msg_len, void **data_pos) +{ + struct ieee802_1x_hdr *hdr; + + *msg_len = sizeof(*hdr) + data_len; + hdr = os_malloc(*msg_len); + if (hdr == NULL) + return NULL; + + hdr->version = wpa_s->conf->eapol_version; + hdr->type = type; + hdr->length = htons(data_len); + + if (data) + os_memcpy(hdr + 1, data, data_len); + else + os_memset(hdr + 1, 0, data_len); + + if (data_pos) + *data_pos = hdr + 1; + + return (u8 *) hdr; +} + + +static u8 * _wpa_alloc_eapol(void *wpa_s, u8 type, + const void *data, u16 data_len, + size_t *msg_len, void **data_pos) +{ + return wpa_alloc_eapol(wpa_s, type, data, data_len, msg_len, data_pos); +} + + +static void _wpa_supplicant_set_state(void *ctx, wpa_states state) +{ + struct wpa_supplicant *wpa_s = ctx; + wpa_s->wpa_state = state; +} + + +static wpa_states _wpa_supplicant_get_state(void *ctx) +{ + struct wpa_supplicant *wpa_s = ctx; + return wpa_s->wpa_state; +} + + +static int wpa_ether_send(void *wpa_s, const u8 *dest, u16 proto, + const u8 *buf, size_t len) +{ + printf("%s - not implemented\n", __func__); + return -1; +} + + +static void * wpa_supplicant_get_network_ctx(void *wpa_s) +{ + return wpa_supplicant_get_ssid(wpa_s); +} + + +static void _wpa_supplicant_cancel_auth_timeout(void *wpa_s) +{ + wpa_supplicant_cancel_auth_timeout(wpa_s); +} + + +static int wpa_supplicant_get_beacon_ie(void *wpa_s) +{ + printf("%s - not implemented\n", __func__); + return -1; +} + + +static int wpa_supplicant_get_bssid(void *wpa_s, u8 *bssid) +{ + printf("%s - not implemented\n", __func__); + return -1; +} + + +static int wpa_supplicant_set_key(void *wpa_s, 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) +{ + printf("%s - not implemented\n", __func__); + return -1; +} + + +static int wpa_supplicant_mlme_setprotection(void *wpa_s, const u8 *addr, + int protection_type, + int key_type) +{ + printf("%s - not implemented\n", __func__); + return -1; +} + + +static int wpa_supplicant_add_pmkid(void *wpa_s, + const u8 *bssid, const u8 *pmkid) +{ + printf("%s - not implemented\n", __func__); + return -1; +} + + +static int wpa_supplicant_remove_pmkid(void *wpa_s, + const u8 *bssid, const u8 *pmkid) +{ + printf("%s - not implemented\n", __func__); + return -1; +} + + +static void wpa_supplicant_set_config_blob(void *ctx, + struct wpa_config_blob *blob) +{ + struct wpa_supplicant *wpa_s = ctx; + wpa_config_set_blob(wpa_s->conf, blob); +} + + +static const struct wpa_config_blob * +wpa_supplicant_get_config_blob(void *ctx, const char *name) +{ + struct wpa_supplicant *wpa_s = ctx; + return wpa_config_get_blob(wpa_s->conf, name); +} + + +static void test_eapol_clean(struct wpa_supplicant *wpa_s) +{ + rsn_preauth_deinit(wpa_s->wpa); + pmksa_candidate_free(wpa_s->wpa); + wpa_sm_deinit(wpa_s->wpa); + scard_deinit(wpa_s->scard); + if (wpa_s->ctrl_iface) { + wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface); + wpa_s->ctrl_iface = NULL; + } + wpa_config_free(wpa_s->conf); +} + + +static void eapol_test_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct preauth_test_data *p = eloop_ctx; + printf("EAPOL test timed out\n"); + p->auth_timed_out = 1; + eloop_terminate(); +} + + +static void eapol_test_poll(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + if (!rsn_preauth_in_progress(wpa_s->wpa)) + eloop_terminate(); + else { + eloop_register_timeout(0, 100000, eapol_test_poll, eloop_ctx, + timeout_ctx); + } +} + + +static struct wpa_driver_ops dummy_driver; + + +static void wpa_init_conf(struct wpa_supplicant *wpa_s, const char *ifname) +{ + struct l2_packet_data *l2; + struct wpa_sm_ctx *ctx; + + os_memset(&dummy_driver, 0, sizeof(dummy_driver)); + wpa_s->driver = &dummy_driver; + + ctx = os_zalloc(sizeof(*ctx)); + assert(ctx != NULL); + + ctx->ctx = wpa_s; + ctx->set_state = _wpa_supplicant_set_state; + ctx->get_state = _wpa_supplicant_get_state; + ctx->deauthenticate = _wpa_supplicant_deauthenticate; + ctx->disassociate = _wpa_supplicant_disassociate; + ctx->set_key = wpa_supplicant_set_key; + ctx->get_network_ctx = wpa_supplicant_get_network_ctx; + ctx->get_bssid = wpa_supplicant_get_bssid; + ctx->ether_send = wpa_ether_send; + ctx->get_beacon_ie = wpa_supplicant_get_beacon_ie; + ctx->alloc_eapol = _wpa_alloc_eapol; + ctx->cancel_auth_timeout = _wpa_supplicant_cancel_auth_timeout; + ctx->add_pmkid = wpa_supplicant_add_pmkid; + ctx->remove_pmkid = wpa_supplicant_remove_pmkid; + ctx->set_config_blob = wpa_supplicant_set_config_blob; + ctx->get_config_blob = wpa_supplicant_get_config_blob; + ctx->mlme_setprotection = wpa_supplicant_mlme_setprotection; + + wpa_s->wpa = wpa_sm_init(ctx); + assert(wpa_s->wpa != NULL); + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, WPA_PROTO_RSN); + + os_strlcpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname)); + wpa_sm_set_ifname(wpa_s->wpa, wpa_s->ifname, NULL); + + l2 = l2_packet_init(wpa_s->ifname, NULL, ETH_P_RSN_PREAUTH, NULL, + NULL, 0); + assert(l2 != NULL); + if (l2_packet_get_own_addr(l2, wpa_s->own_addr)) { + wpa_printf(MSG_WARNING, "Failed to get own L2 address\n"); + exit(-1); + } + l2_packet_deinit(l2); + wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr); +} + + +static void eapol_test_terminate(int sig, void *eloop_ctx, + void *signal_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + wpa_msg(wpa_s, MSG_INFO, "Signal %d received - terminating", sig); + eloop_terminate(); +} + + +int main(int argc, char *argv[]) +{ + struct wpa_supplicant wpa_s; + int ret = 1; + u8 bssid[ETH_ALEN]; + struct preauth_test_data preauth_test; + + if (os_program_init()) + return -1; + + os_memset(&preauth_test, 0, sizeof(preauth_test)); + + wpa_debug_level = 0; + wpa_debug_show_keys = 1; + + if (argc != 4) { + printf("usage: preauth_test <conf> <target MAC address> " + "<ifname>\n"); + return -1; + } + + if (hwaddr_aton(argv[2], bssid)) { + printf("Failed to parse target address '%s'.\n", argv[2]); + return -1; + } + + if (eap_peer_register_methods()) { + wpa_printf(MSG_ERROR, "Failed to register EAP methods"); + return -1; + } + + if (eloop_init(&wpa_s)) { + wpa_printf(MSG_ERROR, "Failed to initialize event loop"); + return -1; + } + + os_memset(&wpa_s, 0, sizeof(wpa_s)); + wpa_s.conf = wpa_config_read(argv[1]); + if (wpa_s.conf == NULL) { + printf("Failed to parse configuration file '%s'.\n", argv[1]); + return -1; + } + if (wpa_s.conf->ssid == NULL) { + printf("No networks defined.\n"); + return -1; + } + + wpa_init_conf(&wpa_s, argv[3]); + wpa_s.ctrl_iface = wpa_supplicant_ctrl_iface_init(&wpa_s); + if (wpa_s.ctrl_iface == NULL) { + printf("Failed to initialize control interface '%s'.\n" + "You may have another preauth_test process already " + "running or the file was\n" + "left by an unclean termination of preauth_test in " + "which case you will need\n" + "to manually remove this file before starting " + "preauth_test again.\n", + wpa_s.conf->ctrl_interface); + return -1; + } + if (wpa_supplicant_scard_init(&wpa_s, wpa_s.conf->ssid)) + return -1; + + if (rsn_preauth_init(wpa_s.wpa, bssid, &wpa_s.conf->ssid->eap)) + return -1; + + eloop_register_timeout(30, 0, eapol_test_timeout, &preauth_test, NULL); + eloop_register_timeout(0, 100000, eapol_test_poll, &wpa_s, NULL); + eloop_register_signal_terminate(eapol_test_terminate, NULL); + eloop_register_signal_reconfig(eapol_test_terminate, NULL); + eloop_run(); + + if (preauth_test.auth_timed_out) + ret = -2; + else { + ret = pmksa_cache_set_current(wpa_s.wpa, NULL, bssid, NULL, 0) + ? 0 : -3; + } + + test_eapol_clean(&wpa_s); + + eap_peer_unregister_methods(); + + eloop_destroy(); + + os_program_deinit(); + + return ret; +} diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c new file mode 100644 index 000000000000..67e2282efd72 --- /dev/null +++ b/wpa_supplicant/scan.c @@ -0,0 +1,263 @@ +/* + * WPA Supplicant - Scanning + * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "eloop.h" +#include "config.h" +#include "wpa_supplicant_i.h" +#include "mlme.h" +#include "wps_supplicant.h" + + +static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s) +{ + struct wpa_ssid *ssid; + union wpa_event_data data; + + ssid = wpa_supplicant_get_ssid(wpa_s); + if (ssid == NULL) + return; + + if (wpa_s->current_ssid == NULL) + wpa_s->current_ssid = ssid; + wpa_supplicant_initiate_eapol(wpa_s); + wpa_printf(MSG_DEBUG, "Already associated with a configured network - " + "generating associated event"); + os_memset(&data, 0, sizeof(data)); + wpa_supplicant_event(wpa_s, EVENT_ASSOC, &data); +} + + +#ifdef CONFIG_WPS +static int wpas_wps_in_use(struct wpa_config *conf, + enum wps_request_type *req_type) +{ + struct wpa_ssid *ssid; + int wps = 0; + + for (ssid = conf->ssid; ssid; ssid = ssid->next) { + if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS)) + continue; + + wps = 1; + *req_type = wpas_wps_get_req_type(ssid); + if (!ssid->eap.phase1) + continue; + + if (os_strstr(ssid->eap.phase1, "pbc=1")) + return 2; + } + + return wps; +} +#endif /* CONFIG_WPS */ + +static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + struct wpa_ssid *ssid; + int enabled, scan_req = 0, ret; + struct wpabuf *wps_ie = NULL; + const u8 *extra_ie = NULL; + size_t extra_ie_len = 0; + int wps = 0; +#ifdef CONFIG_WPS + enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO; +#endif /* CONFIG_WPS */ + + if (wpa_s->disconnected && !wpa_s->scan_req) + return; + + enabled = 0; + ssid = wpa_s->conf->ssid; + while (ssid) { + if (!ssid->disabled) { + enabled++; + break; + } + ssid = ssid->next; + } + if (!enabled && !wpa_s->scan_req) { + wpa_printf(MSG_DEBUG, "No enabled networks - do not scan"); + wpa_supplicant_set_state(wpa_s, WPA_INACTIVE); + return; + } + scan_req = wpa_s->scan_req; + wpa_s->scan_req = 0; + + if (wpa_s->conf->ap_scan != 0 && + wpa_s->driver && IS_WIRED(wpa_s->driver)) { + wpa_printf(MSG_DEBUG, "Using wired authentication - " + "overriding ap_scan configuration"); + wpa_s->conf->ap_scan = 0; + } + + if (wpa_s->conf->ap_scan == 0) { + wpa_supplicant_gen_assoc_event(wpa_s); + return; + } + + if (wpa_s->wpa_state == WPA_DISCONNECTED || + wpa_s->wpa_state == WPA_INACTIVE) + wpa_supplicant_set_state(wpa_s, WPA_SCANNING); + + ssid = wpa_s->conf->ssid; + if (wpa_s->prev_scan_ssid != BROADCAST_SSID_SCAN) { + while (ssid) { + if (ssid == wpa_s->prev_scan_ssid) { + ssid = ssid->next; + break; + } + ssid = ssid->next; + } + } + while (ssid) { + if (!ssid->disabled && + (ssid->scan_ssid || wpa_s->conf->ap_scan == 2)) + break; + ssid = ssid->next; + } + + if (scan_req != 2 && wpa_s->conf->ap_scan == 2) { + /* + * ap_scan=2 mode - try to associate with each SSID instead of + * scanning for each scan_ssid=1 network. + */ + if (ssid == NULL) { + wpa_printf(MSG_DEBUG, "wpa_supplicant_scan: Reached " + "end of scan list - go back to beginning"); + wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN; + wpa_supplicant_req_scan(wpa_s, 0, 0); + return; + } + if (ssid->next) { + /* Continue from the next SSID on the next attempt. */ + wpa_s->prev_scan_ssid = ssid; + } else { + /* Start from the beginning of the SSID list. */ + wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN; + } + wpa_supplicant_associate(wpa_s, NULL, ssid); + return; + } + + wpa_printf(MSG_DEBUG, "Starting AP scan (%s SSID)", + ssid ? "specific": "broadcast"); + if (ssid) { + wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID", + ssid->ssid, ssid->ssid_len); + wpa_s->prev_scan_ssid = ssid; + } else + wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN; + +#ifdef CONFIG_WPS + wps = wpas_wps_in_use(wpa_s->conf, &req_type); +#endif /* CONFIG_WPS */ + + if (wpa_s->scan_res_tried == 0 && wpa_s->conf->ap_scan == 1 && + !wpa_s->use_client_mlme && wps != 2) { + wpa_s->scan_res_tried++; + wpa_s->scan_req = scan_req; + wpa_printf(MSG_DEBUG, "Trying to get current scan results " + "first without requesting a new scan to speed up " + "initial association"); + wpa_supplicant_event(wpa_s, EVENT_SCAN_RESULTS, NULL); + return; + } + +#ifdef CONFIG_WPS + if (wps) { + wps_ie = wps_build_probe_req_ie(wps == 2, &wpa_s->wps->dev, + wpa_s->wps->uuid, req_type); + if (wps_ie) { + extra_ie = wpabuf_head(wps_ie); + extra_ie_len = wpabuf_len(wps_ie); + } + } +#endif /* CONFIG_WPS */ + + if (wpa_s->use_client_mlme) { + ieee80211_sta_set_probe_req_ie(wpa_s, extra_ie, extra_ie_len); + ret = ieee80211_sta_req_scan(wpa_s, ssid ? ssid->ssid : NULL, + ssid ? ssid->ssid_len : 0); + } else { + wpa_drv_set_probe_req_ie(wpa_s, extra_ie, extra_ie_len); + ret = wpa_drv_scan(wpa_s, ssid ? ssid->ssid : NULL, + ssid ? ssid->ssid_len : 0); + } + + wpabuf_free(wps_ie); + + if (ret) { + wpa_printf(MSG_WARNING, "Failed to initiate AP scan."); + wpa_supplicant_req_scan(wpa_s, 10, 0); + } else + wpa_s->scan_runs++; +} + + +/** + * wpa_supplicant_req_scan - Schedule a scan for neighboring access points + * @wpa_s: Pointer to wpa_supplicant data + * @sec: Number of seconds after which to scan + * @usec: Number of microseconds after which to scan + * + * This function is used to schedule a scan for neighboring access points after + * the specified time. + */ +void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec) +{ + /* If there's at least one network that should be specifically scanned + * then don't cancel the scan and reschedule. Some drivers do + * background scanning which generates frequent scan results, and that + * causes the specific SSID scan to get continually pushed back and + * never happen, which causes hidden APs to never get probe-scanned. + */ + if (eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL) && + wpa_s->conf->ap_scan == 1) { + struct wpa_ssid *ssid = wpa_s->conf->ssid; + + while (ssid) { + if (!ssid->disabled && ssid->scan_ssid) + break; + ssid = ssid->next; + } + if (ssid) { + wpa_msg(wpa_s, MSG_DEBUG, "Not rescheduling scan to " + "ensure that specific SSID scans occur"); + return; + } + } + + wpa_msg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec", + sec, usec); + eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); + eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL); +} + + +/** + * wpa_supplicant_cancel_scan - Cancel a scheduled scan request + * @wpa_s: Pointer to wpa_supplicant data + * + * This function is used to cancel a scan request scheduled with + * wpa_supplicant_req_scan(). + */ +void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s) +{ + wpa_msg(wpa_s, MSG_DEBUG, "Cancelling scan request"); + eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); +} diff --git a/wpa_supplicant/symbian/README.symbian b/wpa_supplicant/symbian/README.symbian new file mode 100644 index 000000000000..9d3b811f0fc0 --- /dev/null +++ b/wpa_supplicant/symbian/README.symbian @@ -0,0 +1,24 @@ +wpa_supplicant for Symbian +========================== + +Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi> and +contributors +All Rights Reserved. + +This program is dual-licensed under both the GPL version 2 and BSD +license. Either license may be used at your option. + + +This directory includes project files for testing experimental Symbian +(e.g., Nokia S60 3rd Ed) builds. The Symbian port is not really +complete or expected to work, but these files can be used to verify +that the build itself can be completed successfully. + +These files have been successfully tested with Nokia S60 3rd Edition +MR SDK. + +Build files can be created and a phone release build can be run with +following commands: + +bldmake bldfiles +abld build gcce urel diff --git a/wpa_supplicant/symbian/bld.inf b/wpa_supplicant/symbian/bld.inf new file mode 100644 index 000000000000..a1fc582c52b5 --- /dev/null +++ b/wpa_supplicant/symbian/bld.inf @@ -0,0 +1,8 @@ +PRJ_PLATFORMS +WINSCW GCCE + +PRJ_EXPORTS + +PRJ_MMPFILES + +wpa_supplicant.mmp diff --git a/wpa_supplicant/symbian/wpa_supplicant.mmp b/wpa_supplicant/symbian/wpa_supplicant.mmp new file mode 100644 index 000000000000..fad9626b8388 --- /dev/null +++ b/wpa_supplicant/symbian/wpa_supplicant.mmp @@ -0,0 +1,38 @@ +TARGET wpa_supplicant.exe +UID 0x0 0x0 +VENDORID 0 +TARGETTYPE exe + +SYSTEMINCLUDE \epoc32\include \epoc32\include\variant \epoc32\include\ecom \epoc32\include\libc + +USERINCLUDE .. ..\..\src ..\..\src\utils ..\..\src\common ..\..\src\crypto ..\..\src\rsn_supp + +SOURCEPATH .. +SOURCE main_symbian.cpp +SOURCE config.c config_file.c +SOURCE eapol_sm.c +SOURCE wpa_supplicant.c events.c +SOURCEPATH ..\..\src\rsn_supp +SOURCE wpa.c preauth.c pmksa_cache.c peerkey.c wpa_ie.c +SOURCEPATH ..\..\src\drivers +SOURCE drivers.c +SOURCEPATH ..\..\src\common +SOURCE wpa_common.c +SOURCEPATH ..\..\src\utils +SOURCE os_none.c common.c wpa_debug.c eloop_none.c base64.c +SOURCEPATH ..\..\src\crypto +SOURCE sha1.c md5.c rc4.c md4.c des.c aes_wrap.c aes.c ms_funcs.c +SOURCE tls_internal.c crypto_internal.c +SOURCEPATH ..\..\src\tls +SOURCE asn1.c bignum.c rsa.c x509v3.c tlsv1_client.c tlsv1_common.c +SOURCEPATH ..\..\src\l2_packet +SOURCE l2_packet_none.c +SOURCEPATH ..\..\src\eap_peer +SOURCE eap.c eap_methods.c +SOURCE eap_md5.c eap_tls.c eap_mschapv2.c eap_peap.c eap_gtc.c +SOURCE eap_ttls.c eap_otp.c eap_leap.c eap_tls_common.c eap_tlv.c +SOURCE eap_fast.c eap_fast_pac.c +SOURCEPATH ..\..\src\eap_common +SOURCE eap_common.c + +LIBRARY euser.lib estlib.lib diff --git a/wpa_supplicant/tests/link_test.c b/wpa_supplicant/tests/link_test.c new file mode 100644 index 000000000000..3bfbed577d8c --- /dev/null +++ b/wpa_supplicant/tests/link_test.c @@ -0,0 +1,83 @@ +/* + * Dummy functions to allow link_test to be linked. The need for these + * functions should be removed to allow IEEE 802.1X/EAPOL authenticator to + * be built outside hostapd. + */ + +#include "includes.h" + +#include "common.h" + + +struct hostapd_data; +struct sta_info; +struct rsn_pmksa_cache_entry; +struct eapol_state_machine; +struct hostapd_eap_user; +struct hostapd_bss_config; +struct hostapd_vlan; + + +struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta) +{ + return NULL; +} + + +int ap_for_each_sta(struct hostapd_data *hapd, + int (*cb)(struct hostapd_data *hapd, struct sta_info *sta, + void *ctx), + void *ctx) +{ + return 0; +} + + +void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta, + u32 session_timeout) +{ +} + + +int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta, + int old_vlanid) +{ + return 0; +} + + +void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta, + int success) +{ +} + + +void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta, + u8 *buf, size_t len) +{ +} + + +void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta) +{ +} + + +void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry, + struct eapol_state_machine *eapol) +{ +} + + +const struct hostapd_eap_user * +hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity, + size_t identity_len, int phase2) +{ + return NULL; +} + + +const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id) +{ + return NULL; +} diff --git a/wpa_supplicant/tests/test_aes.c b/wpa_supplicant/tests/test_aes.c new file mode 100644 index 000000000000..38a9cf58d430 --- /dev/null +++ b/wpa_supplicant/tests/test_aes.c @@ -0,0 +1,307 @@ +/* + * Test program for AES + * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "crypto.h" +#include "aes_wrap.h" + +#define BLOCK_SIZE 16 + +static void test_aes_perf(void) +{ +#if 0 /* this did not seem to work with new compiler?! */ +#ifdef __i386__ +#define rdtscll(val) \ + __asm__ __volatile__("rdtsc" : "=A" (val)) + const int num_iters = 10; + int i; + unsigned int start, end; + u8 key[16], pt[16], ct[16]; + void *ctx; + + printf("keySetupEnc:"); + for (i = 0; i < num_iters; i++) { + rdtscll(start); + ctx = aes_encrypt_init(key, 16); + rdtscll(end); + aes_encrypt_deinit(ctx); + printf(" %d", end - start); + } + printf("\n"); + + printf("Encrypt:"); + ctx = aes_encrypt_init(key, 16); + for (i = 0; i < num_iters; i++) { + rdtscll(start); + aes_encrypt(ctx, pt, ct); + rdtscll(end); + printf(" %d", end - start); + } + aes_encrypt_deinit(ctx); + printf("\n"); +#endif /* __i386__ */ +#endif +} + + +static int test_eax(void) +{ + u8 msg[] = { 0xF7, 0xFB }; + u8 key[] = { 0x91, 0x94, 0x5D, 0x3F, 0x4D, 0xCB, 0xEE, 0x0B, + 0xF4, 0x5E, 0xF5, 0x22, 0x55, 0xF0, 0x95, 0xA4 }; + u8 nonce[] = { 0xBE, 0xCA, 0xF0, 0x43, 0xB0, 0xA2, 0x3D, 0x84, + 0x31, 0x94, 0xBA, 0x97, 0x2C, 0x66, 0xDE, 0xBD }; + u8 hdr[] = { 0xFA, 0x3B, 0xFD, 0x48, 0x06, 0xEB, 0x53, 0xFA }; + u8 cipher[] = { 0x19, 0xDD, 0x5C, 0x4C, 0x93, 0x31, 0x04, 0x9D, + 0x0B, 0xDA, 0xB0, 0x27, 0x74, 0x08, 0xF6, 0x79, + 0x67, 0xE5 }; + u8 data[sizeof(msg)], tag[BLOCK_SIZE]; + + memcpy(data, msg, sizeof(msg)); + if (aes_128_eax_encrypt(key, nonce, sizeof(nonce), hdr, sizeof(hdr), + data, sizeof(data), tag)) { + printf("AES-128 EAX mode encryption failed\n"); + return 1; + } + if (memcmp(data, cipher, sizeof(data)) != 0) { + printf("AES-128 EAX mode encryption returned invalid cipher " + "text\n"); + return 1; + } + if (memcmp(tag, cipher + sizeof(data), BLOCK_SIZE) != 0) { + printf("AES-128 EAX mode encryption returned invalid tag\n"); + return 1; + } + + if (aes_128_eax_decrypt(key, nonce, sizeof(nonce), hdr, sizeof(hdr), + data, sizeof(data), tag)) { + printf("AES-128 EAX mode decryption failed\n"); + return 1; + } + if (memcmp(data, msg, sizeof(data)) != 0) { + printf("AES-128 EAX mode decryption returned invalid plain " + "text\n"); + return 1; + } + + return 0; +} + + +static int test_cbc(void) +{ + struct cbc_test_vector { + u8 key[16]; + u8 iv[16]; + u8 plain[32]; + u8 cipher[32]; + size_t len; + } vectors[] = { + { + { 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b, + 0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06 }, + { 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30, + 0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41 }, + "Single block msg", + { 0xe3, 0x53, 0x77, 0x9c, 0x10, 0x79, 0xae, 0xb8, + 0x27, 0x08, 0x94, 0x2d, 0xbe, 0x77, 0x18, 0x1a }, + 16 + }, + { + { 0xc2, 0x86, 0x69, 0x6d, 0x88, 0x7c, 0x9a, 0xa0, + 0x61, 0x1b, 0xbb, 0x3e, 0x20, 0x25, 0xa4, 0x5a }, + { 0x56, 0x2e, 0x17, 0x99, 0x6d, 0x09, 0x3d, 0x28, + 0xdd, 0xb3, 0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58 }, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }, + { 0xd2, 0x96, 0xcd, 0x94, 0xc2, 0xcc, 0xcf, 0x8a, + 0x3a, 0x86, 0x30, 0x28, 0xb5, 0xe1, 0xdc, 0x0a, + 0x75, 0x86, 0x60, 0x2d, 0x25, 0x3c, 0xff, 0xf9, + 0x1b, 0x82, 0x66, 0xbe, 0xa6, 0xd6, 0x1a, 0xb1 }, + 32 + } + }; + int ret = 0; + u8 *buf; + unsigned int i; + + for (i = 0; i < sizeof(vectors) / sizeof(vectors[0]); i++) { + struct cbc_test_vector *tv = &vectors[i]; + buf = malloc(tv->len); + if (buf == NULL) { + ret++; + break; + } + memcpy(buf, tv->plain, tv->len); + aes_128_cbc_encrypt(tv->key, tv->iv, buf, tv->len); + if (memcmp(buf, tv->cipher, tv->len) != 0) { + printf("AES-CBC encrypt %d failed\n", i); + ret++; + } + memcpy(buf, tv->cipher, tv->len); + aes_128_cbc_decrypt(tv->key, tv->iv, buf, tv->len); + if (memcmp(buf, tv->plain, tv->len) != 0) { + printf("AES-CBC decrypt %d failed\n", i); + ret++; + } + free(buf); + } + + return ret; +} + + +/* OMAC1 AES-128 test vectors from + * http://csrc.nist.gov/CryptoToolkit/modes/proposedmodes/omac/omac-ad.pdf + * which are same as the examples from NIST SP800-38B + * http://csrc.nist.gov/CryptoToolkit/modes/800-38_Series_Publications/SP800-38B.pdf + */ + +struct omac1_test_vector { + u8 k[16]; + u8 msg[64]; + int msg_len; + u8 tag[16]; +}; + +static struct omac1_test_vector test_vectors[] = +{ + { + { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }, + { }, + 0, + { 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28, + 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46 } + }, + { + { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }, + { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a}, + 16, + { 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, + 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c } + }, + { + { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }, + { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11 }, + 40, + { 0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30, + 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27 } + }, + { + { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }, + { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 }, + 64, + { 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, + 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe } + }, +}; + + +int main(int argc, char *argv[]) +{ + u8 kek[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f + }; + u8 plain[] = { + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff + }; + u8 crypt[] = { + 0x1F, 0xA6, 0x8B, 0x0A, 0x81, 0x12, 0xB4, 0x47, + 0xAE, 0xF3, 0x4B, 0xD8, 0xFB, 0x5A, 0x7B, 0x82, + 0x9D, 0x3E, 0x86, 0x23, 0x71, 0xD2, 0xCF, 0xE5 + }; + u8 result[24]; + int ret = 0; + unsigned int i; + struct omac1_test_vector *tv; + + if (aes_wrap(kek, 2, plain, result)) { + printf("AES-WRAP-128-128 reported failure\n"); + ret++; + } + if (memcmp(result, crypt, 24) != 0) { + printf("AES-WRAP-128-128 failed\n"); + ret++; + } + if (aes_unwrap(kek, 2, crypt, result)) { + printf("AES-UNWRAP-128-128 reported failure\n"); + ret++; + } + if (memcmp(result, plain, 16) != 0) { + printf("AES-UNWRAP-128-128 failed\n"); + ret++; + for (i = 0; i < 16; i++) + printf(" %02x", result[i]); + printf("\n"); + } + + test_aes_perf(); + + for (i = 0; i < sizeof(test_vectors) / sizeof(test_vectors[0]); i++) { + tv = &test_vectors[i]; + omac1_aes_128(tv->k, tv->msg, tv->msg_len, result); + if (memcmp(result, tv->tag, 16) != 0) { + printf("OMAC1-AES-128 test vector %d failed\n", i); + ret++; + } + + if (tv->msg_len > 1) { + const u8 *addr[2]; + size_t len[2]; + + addr[0] = tv->msg; + len[0] = 1; + addr[1] = tv->msg + 1; + len[1] = tv->msg_len - 1; + + omac1_aes_128_vector(tv->k, 2, addr, len, result); + if (memcmp(result, tv->tag, 16) != 0) { + printf("OMAC1-AES-128(vector) test vector %d " + "failed\n", i); + ret++; + } + } + } + + ret += test_eax(); + + ret += test_cbc(); + + if (ret) + printf("FAILED!\n"); + + return ret; +} diff --git a/wpa_supplicant/tests/test_eap_sim_common.c b/wpa_supplicant/tests/test_eap_sim_common.c new file mode 100644 index 000000000000..ee3eee4d2911 --- /dev/null +++ b/wpa_supplicant/tests/test_eap_sim_common.c @@ -0,0 +1,53 @@ +/* + * Test program for EAP-SIM PRF + * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "eap_sim_common.c" + + +static int test_eap_sim_prf(void) +{ + /* http://csrc.nist.gov/encryption/dss/Examples-1024bit.pdf */ + u8 xkey[] = { + 0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b, + 0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f, + 0xeb, 0x5a, 0x38, 0xb6 + }; + u8 w[] = { + 0x20, 0x70, 0xb3, 0x22, 0x3d, 0xba, 0x37, 0x2f, + 0xde, 0x1c, 0x0f, 0xfc, 0x7b, 0x2e, 0x3b, 0x49, + 0x8b, 0x26, 0x06, 0x14, 0x3c, 0x6c, 0x18, 0xba, + 0xcb, 0x0f, 0x6c, 0x55, 0xba, 0xbb, 0x13, 0x78, + 0x8e, 0x20, 0xd7, 0x37, 0xa3, 0x27, 0x51, 0x16 + }; + u8 buf[40]; + + printf("Testing EAP-SIM PRF (FIPS 186-2 + change notice 1)\n"); + eap_sim_prf(xkey, buf, sizeof(buf)); + if (memcmp(w, buf, sizeof(w) != 0)) { + printf("eap_sim_prf failed\n"); + return 1; + } + + return 0; +} + + +int main(int argc, char *argv[]) +{ + int errors = 0; + + errors += test_eap_sim_prf(); + + return errors; +} diff --git a/wpa_supplicant/tests/test_md4.c b/wpa_supplicant/tests/test_md4.c new file mode 100644 index 000000000000..e92e9a5fafdd --- /dev/null +++ b/wpa_supplicant/tests/test_md4.c @@ -0,0 +1,99 @@ +/* + * Test program for MD4 (test vectors from RFC 1320) + * Copyright (c) 2006, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "crypto.h" + +int main(int argc, char *argv[]) +{ + struct { + char *data; + u8 *hash; + } tests[] = { + { + "", + "\x31\xd6\xcf\xe0\xd1\x6a\xe9\x31" + "\xb7\x3c\x59\xd7\xe0\xc0\x89\xc0" + }, + { + "a", + "\xbd\xe5\x2c\xb3\x1d\xe3\x3e\x46" + "\x24\x5e\x05\xfb\xdb\xd6\xfb\x24" + }, + { + "abc", + "\xa4\x48\x01\x7a\xaf\x21\xd8\x52" + "\x5f\xc1\x0a\xe8\x7a\xa6\x72\x9d" + }, + { + "message digest", + "\xd9\x13\x0a\x81\x64\x54\x9f\xe8" + "\x18\x87\x48\x06\xe1\xc7\x01\x4b" + }, + { + "abcdefghijklmnopqrstuvwxyz", + "\xd7\x9e\x1c\x30\x8a\xa5\xbb\xcd" + "\xee\xa8\xed\x63\xdf\x41\x2d\xa9" + }, + { + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789", + "\x04\x3f\x85\x82\xf2\x41\xdb\x35" + "\x1c\xe6\x27\xe1\x53\xe7\xf0\xe4" + }, + { + "12345678901234567890123456789012345678901234567890" + "123456789012345678901234567890", + "\xe3\x3b\x4d\xdc\x9c\x38\xf2\x19" + "\x9c\x3e\x7b\x16\x4f\xcc\x05\x36" + } + }; + unsigned int i; + u8 hash[16]; + const u8 *addr[2]; + size_t len[2]; + int errors = 0; + + for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { + printf("MD4 test case %d:", i); + + addr[0] = tests[i].data; + len[0] = strlen(tests[i].data); + md4_vector(1, addr, len, hash); + if (memcmp(hash, tests[i].hash, 16) != 0) { + printf(" FAIL"); + errors++; + } else + printf(" OK"); + + if (len[0]) { + addr[0] = tests[i].data; + len[0] = strlen(tests[i].data); + addr[1] = tests[i].data + 1; + len[1] = strlen(tests[i].data) - 1; + md4_vector(1, addr, len, hash); + if (memcmp(hash, tests[i].hash, 16) != 0) { + printf(" FAIL"); + errors++; + } else + printf(" OK"); + } + + printf("\n"); + } + + return errors; +} diff --git a/wpa_supplicant/tests/test_md5.c b/wpa_supplicant/tests/test_md5.c new file mode 100644 index 000000000000..d8fb41ef694e --- /dev/null +++ b/wpa_supplicant/tests/test_md5.c @@ -0,0 +1,99 @@ +/* + * Test program for MD5 (test vectors from RFC 1321) + * Copyright (c) 2006, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "crypto.h" + +int main(int argc, char *argv[]) +{ + struct { + char *data; + u8 *hash; + } tests[] = { + { + "", + "\xd4\x1d\x8c\xd9\x8f\x00\xb2\x04" + "\xe9\x80\x09\x98\xec\xf8\x42\x7e" + }, + { + "a", + "\x0c\xc1\x75\xb9\xc0\xf1\xb6\xa8" + "\x31\xc3\x99\xe2\x69\x77\x26\x61" + }, + { + "abc", + "\x90\x01\x50\x98\x3c\xd2\x4f\xb0" + "\xd6\x96\x3f\x7d\x28\xe1\x7f\x72" + }, + { + "message digest", + "\xf9\x6b\x69\x7d\x7c\xb7\x93\x8d" + "\x52\x5a\x2f\x31\xaa\xf1\x61\xd0" + }, + { + "abcdefghijklmnopqrstuvwxyz", + "\xc3\xfc\xd3\xd7\x61\x92\xe4\x00" + "\x7d\xfb\x49\x6c\xca\x67\xe1\x3b" + }, + { + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789", + "\xd1\x74\xab\x98\xd2\x77\xd9\xf5" + "\xa5\x61\x1c\x2c\x9f\x41\x9d\x9f" + }, + { + "12345678901234567890123456789012345678901234567890" + "123456789012345678901234567890", + "\x57\xed\xf4\xa2\x2b\xe3\xc9\x55" + "\xac\x49\xda\x2e\x21\x07\xb6\x7a" + } + }; + unsigned int i; + u8 hash[16]; + const u8 *addr[2]; + size_t len[2]; + int errors = 0; + + for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { + printf("MD5 test case %d:", i); + + addr[0] = tests[i].data; + len[0] = strlen(tests[i].data); + md5_vector(1, addr, len, hash); + if (memcmp(hash, tests[i].hash, 16) != 0) { + printf(" FAIL"); + errors++; + } else + printf(" OK"); + + if (len[0]) { + addr[0] = tests[i].data; + len[0] = strlen(tests[i].data); + addr[1] = tests[i].data + 1; + len[1] = strlen(tests[i].data) - 1; + md5_vector(1, addr, len, hash); + if (memcmp(hash, tests[i].hash, 16) != 0) { + printf(" FAIL"); + errors++; + } else + printf(" OK"); + } + + printf("\n"); + } + + return errors; +} diff --git a/wpa_supplicant/tests/test_ms_funcs.c b/wpa_supplicant/tests/test_ms_funcs.c new file mode 100644 index 000000000000..09b53c46f34f --- /dev/null +++ b/wpa_supplicant/tests/test_ms_funcs.c @@ -0,0 +1,119 @@ +/* + * Test program for ms_funcs + * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "ms_funcs.c" + + +int main(int argc, char *argv[]) +{ + /* Test vector from RFC2759 example */ + u8 *username = "User"; + u8 *password = "clientPass"; + u8 auth_challenge[] = { + 0x5B, 0x5D, 0x7C, 0x7D, 0x7B, 0x3F, 0x2F, 0x3E, + 0x3C, 0x2C, 0x60, 0x21, 0x32, 0x26, 0x26, 0x28 + }; + u8 peer_challenge[] = { + 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A, + 0x28, 0x29, 0x5F, 0x2B, 0x3A, 0x33, 0x7C, 0x7E + }; + u8 challenge[] = { 0xD0, 0x2E, 0x43, 0x86, 0xBC, 0xE9, 0x12, 0x26 }; + u8 password_hash[] = { + 0x44, 0xEB, 0xBA, 0x8D, 0x53, 0x12, 0xB8, 0xD6, + 0x11, 0x47, 0x44, 0x11, 0xF5, 0x69, 0x89, 0xAE + }; + u8 nt_response[] = { + 0x82, 0x30, 0x9E, 0xCD, 0x8D, 0x70, 0x8B, 0x5E, + 0xA0, 0x8F, 0xAA, 0x39, 0x81, 0xCD, 0x83, 0x54, + 0x42, 0x33, 0x11, 0x4A, 0x3D, 0x85, 0xD6, 0xDF + }; + u8 password_hash_hash[] = { + 0x41, 0xC0, 0x0C, 0x58, 0x4B, 0xD2, 0xD9, 0x1C, + 0x40, 0x17, 0xA2, 0xA1, 0x2F, 0xA5, 0x9F, 0x3F + }; + u8 authenticator_response[] = { + 0x40, 0x7A, 0x55, 0x89, 0x11, 0x5F, 0xD0, 0xD6, + 0x20, 0x9F, 0x51, 0x0F, 0xE9, 0xC0, 0x45, 0x66, + 0x93, 0x2C, 0xDA, 0x56 + }; + u8 master_key[] = { + 0xFD, 0xEC, 0xE3, 0x71, 0x7A, 0x8C, 0x83, 0x8C, + 0xB3, 0x88, 0xE5, 0x27, 0xAE, 0x3C, 0xDD, 0x31 + }; + u8 send_start_key[] = { + 0x8B, 0x7C, 0xDC, 0x14, 0x9B, 0x99, 0x3A, 0x1B, + 0xA1, 0x18, 0xCB, 0x15, 0x3F, 0x56, 0xDC, 0xCB + }; + u8 buf[32]; + + int errors = 0; + + printf("Testing ms_funcs.c\n"); + + challenge_hash(peer_challenge, auth_challenge, + username, strlen(username), + buf); + if (memcmp(challenge, buf, sizeof(challenge)) != 0) { + printf("challenge_hash failed\n"); + errors++; + } + + nt_password_hash(password, strlen(password), buf); + if (memcmp(password_hash, buf, sizeof(password_hash)) != 0) { + printf("nt_password_hash failed\n"); + errors++; + } + + generate_nt_response(auth_challenge, peer_challenge, + username, strlen(username), + password, strlen(password), + buf); + if (memcmp(nt_response, buf, sizeof(nt_response)) != 0) { + printf("generate_nt_response failed\n"); + errors++; + } + + hash_nt_password_hash(password_hash, buf); + if (memcmp(password_hash_hash, buf, sizeof(password_hash_hash)) != 0) { + printf("hash_nt_password_hash failed\n"); + errors++; + } + + generate_authenticator_response(password, strlen(password), + peer_challenge, auth_challenge, + username, strlen(username), + nt_response, buf); + if (memcmp(authenticator_response, buf, sizeof(authenticator_response)) + != 0) { + printf("generate_authenticator_response failed\n"); + errors++; + } + + get_master_key(password_hash_hash, nt_response, buf); + if (memcmp(master_key, buf, sizeof(master_key)) != 0) { + printf("get_master_key failed\n"); + errors++; + } + + get_asymetric_start_key(master_key, buf, sizeof(send_start_key), 1, 1); + if (memcmp(send_start_key, buf, sizeof(send_start_key)) != 0) { + printf("get_asymetric_start_key failed\n"); + errors++; + } + + if (errors) + printf("FAILED! %d errors\n", errors); + + return errors; +} diff --git a/wpa_supplicant/tests/test_sha1.c b/wpa_supplicant/tests/test_sha1.c new file mode 100644 index 000000000000..d2e6a9942597 --- /dev/null +++ b/wpa_supplicant/tests/test_sha1.c @@ -0,0 +1,347 @@ +/* + * Test program for SHA1 and MD5 + * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "sha1.h" +#include "md5.h" +#include "crypto.h" + + +static int test_eap_fast(void) +{ + /* RFC 4851, Appendix B.1 */ + const u8 pac_key[] = { + 0x0B, 0x97, 0x39, 0x0F, 0x37, 0x51, 0x78, 0x09, + 0x81, 0x1E, 0xFD, 0x9C, 0x6E, 0x65, 0x94, 0x2B, + 0x63, 0x2C, 0xE9, 0x53, 0x89, 0x38, 0x08, 0xBA, + 0x36, 0x0B, 0x03, 0x7C, 0xD1, 0x85, 0xE4, 0x14 + }; + const u8 seed[] = { + 0x3F, 0xFB, 0x11, 0xC4, 0x6C, 0xBF, 0xA5, 0x7A, + 0x54, 0x40, 0xDA, 0xE8, 0x22, 0xD3, 0x11, 0xD3, + 0xF7, 0x6D, 0xE4, 0x1D, 0xD9, 0x33, 0xE5, 0x93, + 0x70, 0x97, 0xEB, 0xA9, 0xB3, 0x66, 0xF4, 0x2A, + 0x00, 0x00, 0x00, 0x02, 0x6A, 0x66, 0x43, 0x2A, + 0x8D, 0x14, 0x43, 0x2C, 0xEC, 0x58, 0x2D, 0x2F, + 0xC7, 0x9C, 0x33, 0x64, 0xBA, 0x04, 0xAD, 0x3A, + 0x52, 0x54, 0xD6, 0xA5, 0x79, 0xAD, 0x1E, 0x00 + }; + const u8 master_secret[] = { + 0x4A, 0x1A, 0x51, 0x2C, 0x01, 0x60, 0xBC, 0x02, + 0x3C, 0xCF, 0xBC, 0x83, 0x3F, 0x03, 0xBC, 0x64, + 0x88, 0xC1, 0x31, 0x2F, 0x0B, 0xA9, 0xA2, 0x77, + 0x16, 0xA8, 0xD8, 0xE8, 0xBD, 0xC9, 0xD2, 0x29, + 0x38, 0x4B, 0x7A, 0x85, 0xBE, 0x16, 0x4D, 0x27, + 0x33, 0xD5, 0x24, 0x79, 0x87, 0xB1, 0xC5, 0xA2 + }; + const u8 key_block[] = { + 0x59, 0x59, 0xBE, 0x8E, 0x41, 0x3A, 0x77, 0x74, + 0x8B, 0xB2, 0xE5, 0xD3, 0x60, 0xAC, 0x4D, 0x35, + 0xDF, 0xFB, 0xC8, 0x1E, 0x9C, 0x24, 0x9C, 0x8B, + 0x0E, 0xC3, 0x1D, 0x72, 0xC8, 0x84, 0x9D, 0x57, + 0x48, 0x51, 0x2E, 0x45, 0x97, 0x6C, 0x88, 0x70, + 0xBE, 0x5F, 0x01, 0xD3, 0x64, 0xE7, 0x4C, 0xBB, + 0x11, 0x24, 0xE3, 0x49, 0xE2, 0x3B, 0xCD, 0xEF, + 0x7A, 0xB3, 0x05, 0x39, 0x5D, 0x64, 0x8A, 0x44, + 0x11, 0xB6, 0x69, 0x88, 0x34, 0x2E, 0x8E, 0x29, + 0xD6, 0x4B, 0x7D, 0x72, 0x17, 0x59, 0x28, 0x05, + 0xAF, 0xF9, 0xB7, 0xFF, 0x66, 0x6D, 0xA1, 0x96, + 0x8F, 0x0B, 0x5E, 0x06, 0x46, 0x7A, 0x44, 0x84, + 0x64, 0xC1, 0xC8, 0x0C, 0x96, 0x44, 0x09, 0x98, + 0xFF, 0x92, 0xA8, 0xB4, 0xC6, 0x42, 0x28, 0x71 + }; + const u8 sks[] = { + 0xD6, 0x4B, 0x7D, 0x72, 0x17, 0x59, 0x28, 0x05, + 0xAF, 0xF9, 0xB7, 0xFF, 0x66, 0x6D, 0xA1, 0x96, + 0x8F, 0x0B, 0x5E, 0x06, 0x46, 0x7A, 0x44, 0x84, + 0x64, 0xC1, 0xC8, 0x0C, 0x96, 0x44, 0x09, 0x98, + 0xFF, 0x92, 0xA8, 0xB4, 0xC6, 0x42, 0x28, 0x71 + }; + const u8 isk[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + const u8 imck[] = { + 0x16, 0x15, 0x3C, 0x3F, 0x21, 0x55, 0xEF, 0xD9, + 0x7F, 0x34, 0xAE, 0xC8, 0x1A, 0x4E, 0x66, 0x80, + 0x4C, 0xC3, 0x76, 0xF2, 0x8A, 0xA9, 0x6F, 0x96, + 0xC2, 0x54, 0x5F, 0x8C, 0xAB, 0x65, 0x02, 0xE1, + 0x18, 0x40, 0x7B, 0x56, 0xBE, 0xEA, 0xA7, 0xC5, + 0x76, 0x5D, 0x8F, 0x0B, 0xC5, 0x07, 0xC6, 0xB9, + 0x04, 0xD0, 0x69, 0x56, 0x72, 0x8B, 0x6B, 0xB8, + 0x15, 0xEC, 0x57, 0x7B + }; + const u8 msk[] = { + 0x4D, 0x83, 0xA9, 0xBE, 0x6F, 0x8A, 0x74, 0xED, + 0x6A, 0x02, 0x66, 0x0A, 0x63, 0x4D, 0x2C, 0x33, + 0xC2, 0xDA, 0x60, 0x15, 0xC6, 0x37, 0x04, 0x51, + 0x90, 0x38, 0x63, 0xDA, 0x54, 0x3E, 0x14, 0xB9, + 0x27, 0x99, 0x18, 0x1E, 0x07, 0xBF, 0x0F, 0x5A, + 0x5E, 0x3C, 0x32, 0x93, 0x80, 0x8C, 0x6C, 0x49, + 0x67, 0xED, 0x24, 0xFE, 0x45, 0x40, 0xA0, 0x59, + 0x5E, 0x37, 0xC2, 0xE9, 0xD0, 0x5D, 0x0A, 0xE3 + }; + const u8 emsk[] = { + 0x3A, 0xD4, 0xAB, 0xDB, 0x76, 0xB2, 0x7F, 0x3B, + 0xEA, 0x32, 0x2C, 0x2B, 0x74, 0xF4, 0x28, 0x55, + 0xEF, 0x2D, 0xBA, 0x78, 0xC9, 0x57, 0x2F, 0x0D, + 0x06, 0xCD, 0x51, 0x7C, 0x20, 0x93, 0x98, 0xA9, + 0x76, 0xEA, 0x70, 0x21, 0xD7, 0x0E, 0x25, 0x54, + 0x97, 0xED, 0xB2, 0x8A, 0xF6, 0xED, 0xFD, 0x0A, + 0x2A, 0xE7, 0xA1, 0x58, 0x90, 0x10, 0x50, 0x44, + 0xB3, 0x82, 0x85, 0xDB, 0x06, 0x14, 0xD2, 0xF9 + }; + /* RFC 4851, Appendix B.2 */ + u8 tlv[] = { + 0x80, 0x0C, 0x00, 0x38, 0x00, 0x01, 0x01, 0x00, + 0xD8, 0x6A, 0x8C, 0x68, 0x3C, 0x32, 0x31, 0xA8, + 0x56, 0x63, 0xB6, 0x40, 0x21, 0xFE, 0x21, 0x14, + 0x4E, 0xE7, 0x54, 0x20, 0x79, 0x2D, 0x42, 0x62, + 0xC9, 0xBF, 0x53, 0x7F, 0x54, 0xFD, 0xAC, 0x58, + 0x43, 0x24, 0x6E, 0x30, 0x92, 0x17, 0x6D, 0xCF, + 0xE6, 0xE0, 0x69, 0xEB, 0x33, 0x61, 0x6A, 0xCC, + 0x05, 0xC5, 0x5B, 0xB7 + }; + const u8 compound_mac[] = { + 0x43, 0x24, 0x6E, 0x30, 0x92, 0x17, 0x6D, 0xCF, + 0xE6, 0xE0, 0x69, 0xEB, 0x33, 0x61, 0x6A, 0xCC, + 0x05, 0xC5, 0x5B, 0xB7 + }; + u8 buf[512]; + const u8 *simck, *cmk; + int errors = 0; + + printf("EAP-FAST test cases\n"); + + printf("- T-PRF (SHA1) test case / master_secret\n"); + sha1_t_prf(pac_key, sizeof(pac_key), "PAC to master secret label hash", + seed, sizeof(seed), buf, sizeof(master_secret)); + if (memcmp(master_secret, buf, sizeof(master_secret)) != 0) { + printf("T-PRF test - FAILED!\n"); + errors++; + } + + printf("- PRF (TLS, SHA1/MD5) test case / key_block\n"); + tls_prf(master_secret, sizeof(master_secret), "key expansion", + seed, sizeof(seed), buf, sizeof(key_block)); + if (memcmp(key_block, buf, sizeof(key_block)) != 0) { + printf("PRF test - FAILED!\n"); + errors++; + } + + printf("- T-PRF (SHA1) test case / IMCK\n"); + sha1_t_prf(sks, sizeof(sks), "Inner Methods Compound Keys", + isk, sizeof(isk), buf, sizeof(imck)); + if (memcmp(imck, buf, sizeof(imck)) != 0) { + printf("T-PRF test - FAILED!\n"); + errors++; + } + + simck = imck; + cmk = imck + 40; + + printf("- T-PRF (SHA1) test case / MSK\n"); + sha1_t_prf(simck, 40, "Session Key Generating Function", + (u8 *) "", 0, buf, sizeof(msk)); + if (memcmp(msk, buf, sizeof(msk)) != 0) { + printf("T-PRF test - FAILED!\n"); + errors++; + } + + printf("- T-PRF (SHA1) test case / EMSK\n"); + sha1_t_prf(simck, 40, "Extended Session Key Generating Function", + (u8 *) "", 0, buf, sizeof(msk)); + if (memcmp(emsk, buf, sizeof(emsk)) != 0) { + printf("T-PRF test - FAILED!\n"); + errors++; + } + + printf("- Compound MAC test case\n"); + memset(tlv + sizeof(tlv) - 20, 0, 20); + hmac_sha1(cmk, 20, tlv, sizeof(tlv), tlv + sizeof(tlv) - 20); + if (memcmp(tlv + sizeof(tlv) - 20, compound_mac, sizeof(compound_mac)) + != 0) { + printf("Compound MAC test - FAILED!\n"); + errors++; + } + + return errors; +} + + +static u8 key0[] = +{ + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b +}; +static u8 data0[] = "Hi There"; +static u8 prf0[] = +{ + 0xbc, 0xd4, 0xc6, 0x50, 0xb3, 0x0b, 0x96, 0x84, + 0x95, 0x18, 0x29, 0xe0, 0xd7, 0x5f, 0x9d, 0x54, + 0xb8, 0x62, 0x17, 0x5e, 0xd9, 0xf0, 0x06, 0x06, + 0xe1, 0x7d, 0x8d, 0xa3, 0x54, 0x02, 0xff, 0xee, + 0x75, 0xdf, 0x78, 0xc3, 0xd3, 0x1e, 0x0f, 0x88, + 0x9f, 0x01, 0x21, 0x20, 0xc0, 0x86, 0x2b, 0xeb, + 0x67, 0x75, 0x3e, 0x74, 0x39, 0xae, 0x24, 0x2e, + 0xdb, 0x83, 0x73, 0x69, 0x83, 0x56, 0xcf, 0x5a +}; + +static u8 key1[] = "Jefe"; +static u8 data1[] = "what do ya want for nothing?"; +static u8 prf1[] = +{ + 0x51, 0xf4, 0xde, 0x5b, 0x33, 0xf2, 0x49, 0xad, + 0xf8, 0x1a, 0xeb, 0x71, 0x3a, 0x3c, 0x20, 0xf4, + 0xfe, 0x63, 0x14, 0x46, 0xfa, 0xbd, 0xfa, 0x58, + 0x24, 0x47, 0x59, 0xae, 0x58, 0xef, 0x90, 0x09, + 0xa9, 0x9a, 0xbf, 0x4e, 0xac, 0x2c, 0xa5, 0xfa, + 0x87, 0xe6, 0x92, 0xc4, 0x40, 0xeb, 0x40, 0x02, + 0x3e, 0x7b, 0xab, 0xb2, 0x06, 0xd6, 0x1d, 0xe7, + 0xb9, 0x2f, 0x41, 0x52, 0x90, 0x92, 0xb8, 0xfc +}; + + +static u8 key2[] = +{ + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa +}; +static u8 data2[] = +{ + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd +}; +static u8 prf2[] = +{ + 0xe1, 0xac, 0x54, 0x6e, 0xc4, 0xcb, 0x63, 0x6f, + 0x99, 0x76, 0x48, 0x7b, 0xe5, 0xc8, 0x6b, 0xe1, + 0x7a, 0x02, 0x52, 0xca, 0x5d, 0x8d, 0x8d, 0xf1, + 0x2c, 0xfb, 0x04, 0x73, 0x52, 0x52, 0x49, 0xce, + 0x9d, 0xd8, 0xd1, 0x77, 0xea, 0xd7, 0x10, 0xbc, + 0x9b, 0x59, 0x05, 0x47, 0x23, 0x91, 0x07, 0xae, + 0xf7, 0xb4, 0xab, 0xd4, 0x3d, 0x87, 0xf0, 0xa6, + 0x8f, 0x1c, 0xbd, 0x9e, 0x2b, 0x6f, 0x76, 0x07 +}; + + +struct passphrase_test { + char *passphrase; + char *ssid; + char psk[32]; +}; + +static struct passphrase_test passphrase_tests[] = +{ + { + "password", + "IEEE", + { + 0xf4, 0x2c, 0x6f, 0xc5, 0x2d, 0xf0, 0xeb, 0xef, + 0x9e, 0xbb, 0x4b, 0x90, 0xb3, 0x8a, 0x5f, 0x90, + 0x2e, 0x83, 0xfe, 0x1b, 0x13, 0x5a, 0x70, 0xe2, + 0x3a, 0xed, 0x76, 0x2e, 0x97, 0x10, 0xa1, 0x2e + } + }, + { + "ThisIsAPassword", + "ThisIsASSID", + { + 0x0d, 0xc0, 0xd6, 0xeb, 0x90, 0x55, 0x5e, 0xd6, + 0x41, 0x97, 0x56, 0xb9, 0xa1, 0x5e, 0xc3, 0xe3, + 0x20, 0x9b, 0x63, 0xdf, 0x70, 0x7d, 0xd5, 0x08, + 0xd1, 0x45, 0x81, 0xf8, 0x98, 0x27, 0x21, 0xaf + } + }, + { + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ", + { + 0xbe, 0xcb, 0x93, 0x86, 0x6b, 0xb8, 0xc3, 0x83, + 0x2c, 0xb7, 0x77, 0xc2, 0xf5, 0x59, 0x80, 0x7c, + 0x8c, 0x59, 0xaf, 0xcb, 0x6e, 0xae, 0x73, 0x48, + 0x85, 0x00, 0x13, 0x00, 0xa9, 0x81, 0xcc, 0x62 + } + }, +}; + +#define NUM_PASSPHRASE_TESTS \ +(sizeof(passphrase_tests) / sizeof(passphrase_tests[0])) + + +int main(int argc, char *argv[]) +{ + u8 res[512]; + int ret = 0; + unsigned int i; + + printf("PRF-SHA1 test cases:\n"); + + sha1_prf(key0, sizeof(key0), "prefix", data0, sizeof(data0) - 1, + res, sizeof(prf0)); + if (memcmp(res, prf0, sizeof(prf0)) == 0) + printf("Test case 0 - OK\n"); + else { + printf("Test case 0 - FAILED!\n"); + ret++; + } + + sha1_prf(key1, sizeof(key1) - 1, "prefix", data1, sizeof(data1) - 1, + res, sizeof(prf1)); + if (memcmp(res, prf1, sizeof(prf1)) == 0) + printf("Test case 1 - OK\n"); + else { + printf("Test case 1 - FAILED!\n"); + ret++; + } + + sha1_prf(key2, sizeof(key2), "prefix", data2, sizeof(data2), + res, sizeof(prf2)); + if (memcmp(res, prf2, sizeof(prf2)) == 0) + printf("Test case 2 - OK\n"); + else { + printf("Test case 2 - FAILED!\n"); + ret++; + } + + ret += test_eap_fast(); + + printf("PBKDF2-SHA1 Passphrase test cases:\n"); + for (i = 0; i < NUM_PASSPHRASE_TESTS; i++) { + u8 psk[32]; + struct passphrase_test *test = &passphrase_tests[i]; + pbkdf2_sha1(test->passphrase, + test->ssid, strlen(test->ssid), + 4096, psk, 32); + if (memcmp(psk, test->psk, 32) == 0) + printf("Test case %d - OK\n", i); + else { + printf("Test case %d - FAILED!\n", i); + ret++; + } + } + + return ret; +} diff --git a/wpa_supplicant/tests/test_sha256.c b/wpa_supplicant/tests/test_sha256.c new file mode 100644 index 000000000000..7dc460d483e8 --- /dev/null +++ b/wpa_supplicant/tests/test_sha256.c @@ -0,0 +1,331 @@ +/* + * Test program for SHA256 + * Copyright (c) 2006, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "sha256.h" +#include "crypto.h" + +struct { + char *data; + u8 hash[32]; +} tests[] = { + { + "abc", + { + 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, + 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, + 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, + 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad + } + }, + { + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + { + 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, + 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, + 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, + 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 + } + } +}; + +struct hmac_test { + u8 key[80]; + size_t key_len; + u8 data[128]; + size_t data_len; + u8 hash[32]; +} hmac_tests[] = { + /* draft-ietf-ipsec-ciph-sha-256-01.txt */ + { + { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20 + }, + 32, + "abc", 3, + { + 0xa2, 0x1b, 0x1f, 0x5d, 0x4c, 0xf4, 0xf7, 0x3a, + 0x4d, 0xd9, 0x39, 0x75, 0x0f, 0x7a, 0x06, 0x6a, + 0x7f, 0x98, 0xcc, 0x13, 0x1c, 0xb1, 0x6a, 0x66, + 0x92, 0x75, 0x90, 0x21, 0xcf, 0xab, 0x81, 0x81 + } + }, + { + { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20 + }, + 32, + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + 56, + { + 0x10, 0x4f, 0xdc, 0x12, 0x57, 0x32, 0x8f, 0x08, + 0x18, 0x4b, 0xa7, 0x31, 0x31, 0xc5, 0x3c, 0xae, + 0xe6, 0x98, 0xe3, 0x61, 0x19, 0x42, 0x11, 0x49, + 0xea, 0x8c, 0x71, 0x24, 0x56, 0x69, 0x7d, 0x30 + } + }, + { + { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20 + }, + 32, + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + 112, + { + 0x47, 0x03, 0x05, 0xfc, 0x7e, 0x40, 0xfe, 0x34, + 0xd3, 0xee, 0xb3, 0xe7, 0x73, 0xd9, 0x5a, 0xab, + 0x73, 0xac, 0xf0, 0xfd, 0x06, 0x04, 0x47, 0xa5, + 0xeb, 0x45, 0x95, 0xbf, 0x33, 0xa9, 0xd1, 0xa3 + } + }, + { + { + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b + }, + 32, + "Hi There", + 8, + { + 0x19, 0x8a, 0x60, 0x7e, 0xb4, 0x4b, 0xfb, 0xc6, + 0x99, 0x03, 0xa0, 0xf1, 0xcf, 0x2b, 0xbd, 0xc5, + 0xba, 0x0a, 0xa3, 0xf3, 0xd9, 0xae, 0x3c, 0x1c, + 0x7a, 0x3b, 0x16, 0x96, 0xa0, 0xb6, 0x8c, 0xf7 + } + }, + { + "Jefe", + 4, + "what do ya want for nothing?", + 28, + { + 0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e, + 0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7, + 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83, + 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43 + } + }, + { + { + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa + }, + 32, + { + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd + }, + 50, + { + 0xcd, 0xcb, 0x12, 0x20, 0xd1, 0xec, 0xcc, 0xea, + 0x91, 0xe5, 0x3a, 0xba, 0x30, 0x92, 0xf9, 0x62, + 0xe5, 0x49, 0xfe, 0x6c, 0xe9, 0xed, 0x7f, 0xdc, + 0x43, 0x19, 0x1f, 0xbd, 0xe4, 0x5c, 0x30, 0xb0 + } + }, + { + { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25 + }, + 37, + { + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd + }, + 50, + { + 0xd4, 0x63, 0x3c, 0x17, 0xf6, 0xfb, 0x8d, 0x74, + 0x4c, 0x66, 0xde, 0xe0, 0xf8, 0xf0, 0x74, 0x55, + 0x6e, 0xc4, 0xaf, 0x55, 0xef, 0x07, 0x99, 0x85, + 0x41, 0x46, 0x8e, 0xb4, 0x9b, 0xd2, 0xe9, 0x17 + } + }, + { + { + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c + }, + 32, + "Test With Truncation", + 20, + { + 0x75, 0x46, 0xaf, 0x01, 0x84, 0x1f, 0xc0, 0x9b, + 0x1a, 0xb9, 0xc3, 0x74, 0x9a, 0x5f, 0x1c, 0x17, + 0xd4, 0xf5, 0x89, 0x66, 0x8a, 0x58, 0x7b, 0x27, + 0x00, 0xa9, 0xc9, 0x7c, 0x11, 0x93, 0xcf, 0x42 + } + }, + { + { + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa + }, + 80, + "Test Using Larger Than Block-Size Key - Hash Key First", + 54, + { + 0x69, 0x53, 0x02, 0x5e, 0xd9, 0x6f, 0x0c, 0x09, + 0xf8, 0x0a, 0x96, 0xf7, 0x8e, 0x65, 0x38, 0xdb, + 0xe2, 0xe7, 0xb8, 0x20, 0xe3, 0xdd, 0x97, 0x0e, + 0x7d, 0xdd, 0x39, 0x09, 0x1b, 0x32, 0x35, 0x2f + } + }, + { + { + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa + }, + 80, + "Test Using Larger Than Block-Size Key and Larger Than One " + "Block-Size Data", + 73, + { + 0x63, 0x55, 0xac, 0x22, 0xe8, 0x90, 0xd0, 0xa3, + 0xc8, 0x48, 0x1a, 0x5c, 0xa4, 0x82, 0x5b, 0xc8, + 0x84, 0xd3, 0xe7, 0xa1, 0xff, 0x98, 0xa2, 0xfc, + 0x2a, 0xc7, 0xd8, 0xe0, 0x64, 0xc3, 0xb2, 0xe6 + } + } +}; + + +int main(int argc, char *argv[]) +{ + + unsigned int i; + u8 hash[32]; + const u8 *addr[2]; + size_t len[2]; + int errors = 0; + + for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { + printf("SHA256 test case %d:", i + 1); + + addr[0] = (u8 *) tests[i].data; + len[0] = strlen(tests[i].data); + sha256_vector(1, addr, len, hash); + if (memcmp(hash, tests[i].hash, 32) != 0) { + printf(" FAIL"); + errors++; + } else + printf(" OK"); + + if (len[0]) { + addr[0] = (u8 *) tests[i].data; + len[0] = 1; + addr[1] = (u8 *) tests[i].data + 1; + len[1] = strlen(tests[i].data) - 1; + sha256_vector(2, addr, len, hash); + if (memcmp(hash, tests[i].hash, 32) != 0) { + printf(" FAIL"); + errors++; + } else + printf(" OK"); + } + + printf("\n"); + } + + for (i = 0; i < sizeof(hmac_tests) / sizeof(hmac_tests[0]); i++) { + struct hmac_test *t = &hmac_tests[i]; + printf("HMAC-SHA256 test case %d:", i + 1); + + hmac_sha256(t->key, t->key_len, t->data, t->data_len, hash); + if (memcmp(hash, t->hash, 32) != 0) { + printf(" FAIL"); + errors++; + } else + printf(" OK"); + + addr[0] = t->data; + len[0] = t->data_len; + hmac_sha256_vector(t->key, t->key_len, 1, addr, len, hash); + if (memcmp(hash, t->hash, 32) != 0) { + printf(" FAIL"); + errors++; + } else + printf(" OK"); + + if (len[0]) { + addr[0] = t->data; + len[0] = 1; + addr[1] = t->data + 1; + len[1] = t->data_len - 1; + hmac_sha256_vector(t->key, t->key_len, 2, addr, len, + hash); + if (memcmp(hash, t->hash, 32) != 0) { + printf(" FAIL"); + errors++; + } else + printf(" OK"); + } + + printf("\n"); + } + + printf("Test IEEE 802.11r KDF\n"); + sha256_prf((u8 *) "abc", 3, "KDF test", (u8 *) "data", 4, + hash, sizeof(hash)); + /* TODO: add proper test case for this */ + + return errors; +} diff --git a/wpa_supplicant/tests/test_wpa.c b/wpa_supplicant/tests/test_wpa.c new file mode 100644 index 000000000000..74bb5f8c9adf --- /dev/null +++ b/wpa_supplicant/tests/test_wpa.c @@ -0,0 +1,394 @@ +/* + * Test program for combined WPA authenticator/supplicant + * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "eloop.h" +#include "ieee802_11_defs.h" +#include "config.h" +#include "wpa.h" +#include "wpa_ie.h" +#include "../hostapd/wpa.h" + + +extern int wpa_debug_level; +extern int wpa_debug_show_keys; + + +struct wpa { + u8 auth_addr[ETH_ALEN]; + u8 supp_addr[ETH_ALEN]; + u8 psk[PMK_LEN]; + + /* from authenticator */ + u8 auth_eapol_dst[ETH_ALEN]; + u8 *auth_eapol; + size_t auth_eapol_len; + + /* from supplicant */ + u8 *supp_eapol; + size_t supp_eapol_len; + + struct wpa_sm *supp; + struct wpa_authenticator *auth_group; + struct wpa_state_machine *auth; + + struct wpa_ssid ssid; + u8 supp_ie[80]; + size_t supp_ie_len; +}; + + +static struct wpa_ssid * supp_get_ssid(void *ctx) +{ + struct wpa *wpa = ctx; + wpa_printf(MSG_DEBUG, "SUPP: %s", __func__); + return &wpa->ssid; +} + + +static int supp_get_bssid(void *ctx, u8 *bssid) +{ + struct wpa *wpa = ctx; + wpa_printf(MSG_DEBUG, "SUPP: %s", __func__); + os_memcpy(bssid, wpa->auth_addr, ETH_ALEN); + return 0; +} + + +static void supp_set_state(void *ctx, wpa_states state) +{ + wpa_printf(MSG_DEBUG, "SUPP: %s(state=%d)", __func__, state); +} + + +static void auth_eapol_rx(void *eloop_data, void *user_ctx) +{ + struct wpa *wpa = eloop_data; + + wpa_printf(MSG_DEBUG, "AUTH: RX EAPOL frame"); + wpa_receive(wpa->auth_group, wpa->auth, wpa->supp_eapol, + wpa->supp_eapol_len); +} + + +static int supp_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *buf, + size_t len) +{ + struct wpa *wpa = ctx; + + wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR " proto=0x%04x " + "len=%lu)", + __func__, MAC2STR(dest), proto, (unsigned long) len); + + os_free(wpa->supp_eapol); + wpa->supp_eapol = os_malloc(len); + if (wpa->supp_eapol == NULL) + return -1; + os_memcpy(wpa->supp_eapol, buf, len); + wpa->supp_eapol_len = len; + eloop_register_timeout(0, 0, auth_eapol_rx, wpa, NULL); + + return 0; +} + + +static u8 * supp_alloc_eapol(void *ctx, u8 type, const void *data, + u16 data_len, size_t *msg_len, void **data_pos) +{ + struct ieee802_1x_hdr *hdr; + + wpa_printf(MSG_DEBUG, "SUPP: %s(type=%d data_len=%d)", + __func__, type, data_len); + + *msg_len = sizeof(*hdr) + data_len; + hdr = os_malloc(*msg_len); + if (hdr == NULL) + return NULL; + + hdr->version = 2; + hdr->type = type; + hdr->length = host_to_be16(data_len); + + if (data) + os_memcpy(hdr + 1, data, data_len); + else + os_memset(hdr + 1, 0, data_len); + + if (data_pos) + *data_pos = hdr + 1; + + return (u8 *) hdr; +} + + +static int supp_get_beacon_ie(void *ctx) +{ + struct wpa *wpa = ctx; + const u8 *ie; + size_t ielen; + + wpa_printf(MSG_DEBUG, "SUPP: %s", __func__); + + ie = wpa_auth_get_wpa_ie(wpa->auth_group, &ielen); + if (ie == NULL || ielen < 1) + return -1; + if (ie[0] == WLAN_EID_RSN) + return wpa_sm_set_ap_rsn_ie(wpa->supp, ie, 2 + ie[1]); + return wpa_sm_set_ap_wpa_ie(wpa->supp, ie, 2 + ie[1]); +} + + +static int supp_set_key(void *ctx, 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, "SUPP: %s(alg=%d addr=" MACSTR " key_idx=%d " + "set_tx=%d)", + __func__, alg, MAC2STR(addr), key_idx, set_tx); + wpa_hexdump(MSG_DEBUG, "SUPP: set_key - seq", seq, seq_len); + wpa_hexdump(MSG_DEBUG, "SUPP: set_key - key", key, key_len); + return 0; +} + + +static int supp_mlme_setprotection(void *ctx, const u8 *addr, + int protection_type, int key_type) +{ + wpa_printf(MSG_DEBUG, "SUPP: %s(addr=" MACSTR " protection_type=%d " + "key_type=%d)", + __func__, MAC2STR(addr), protection_type, key_type); + return 0; +} + + +static void supp_cancel_scan(void *ctx) +{ + wpa_printf(MSG_DEBUG, "SUPP: %s", __func__); +} + + +static void supp_cancel_auth_timeout(void *ctx) +{ + wpa_printf(MSG_DEBUG, "SUPP: %s", __func__); +} + + +static int supp_init(struct wpa *wpa) +{ + struct wpa_sm_ctx *ctx = os_zalloc(sizeof(*ctx)); + if (ctx == NULL) + return -1; + + ctx->ctx = wpa; + ctx->set_state = supp_set_state; + ctx->get_ssid = supp_get_ssid; + ctx->get_bssid = supp_get_bssid; + ctx->ether_send = supp_ether_send; + ctx->get_beacon_ie = supp_get_beacon_ie; + ctx->alloc_eapol = supp_alloc_eapol; + ctx->set_key = supp_set_key; + ctx->mlme_setprotection = supp_mlme_setprotection; + ctx->cancel_scan = supp_cancel_scan; + ctx->cancel_auth_timeout = supp_cancel_auth_timeout; + wpa->supp = wpa_sm_init(ctx); + if (wpa->supp == NULL) { + wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed"); + return -1; + } + + wpa_sm_set_own_addr(wpa->supp, wpa->supp_addr); + wpa_sm_set_param(wpa->supp, WPA_PARAM_RSN_ENABLED, 1); + wpa_sm_set_param(wpa->supp, WPA_PARAM_PROTO, WPA_PROTO_RSN); + wpa_sm_set_param(wpa->supp, WPA_PARAM_PAIRWISE, WPA_CIPHER_CCMP); + wpa_sm_set_param(wpa->supp, WPA_PARAM_GROUP, WPA_CIPHER_CCMP); + wpa_sm_set_param(wpa->supp, WPA_PARAM_KEY_MGMT, WPA_KEY_MGMT_PSK); + wpa_sm_set_pmk(wpa->supp, wpa->psk, PMK_LEN); + + wpa->supp_ie_len = sizeof(wpa->supp_ie); + if (wpa_sm_set_assoc_wpa_ie_default(wpa->supp, wpa->supp_ie, + &wpa->supp_ie_len) < 0) { + wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_set_assoc_wpa_ie_default()" + " failed"); + return -1; + } + + wpa_sm_notify_assoc(wpa->supp, wpa->auth_addr); + + return 0; +} + + +static void auth_logger(void *ctx, const u8 *addr, logger_level level, + const char *txt) +{ + if (addr) + wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " - %s", + MAC2STR(addr), txt); + else + wpa_printf(MSG_DEBUG, "AUTH: %s", txt); +} + + +static void supp_eapol_rx(void *eloop_data, void *user_ctx) +{ + struct wpa *wpa = eloop_data; + + wpa_printf(MSG_DEBUG, "SUPP: RX EAPOL frame"); + wpa_sm_rx_eapol(wpa->supp, wpa->auth_addr, wpa->auth_eapol, + wpa->auth_eapol_len); +} + + +static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data, + size_t data_len, int encrypt) +{ + struct wpa *wpa = ctx; + + wpa_printf(MSG_DEBUG, "AUTH: %s(addr=" MACSTR " data_len=%lu " + "encrypt=%d)", + __func__, MAC2STR(addr), (unsigned long) data_len, encrypt); + + os_free(wpa->auth_eapol); + wpa->auth_eapol = os_malloc(data_len); + if (wpa->auth_eapol == NULL) + return -1; + os_memcpy(wpa->auth_eapol_dst, addr, ETH_ALEN); + os_memcpy(wpa->auth_eapol, data, data_len); + wpa->auth_eapol_len = data_len; + eloop_register_timeout(0, 0, supp_eapol_rx, wpa, NULL); + + return 0; +} + + +static const u8 * auth_get_psk(void *ctx, const u8 *addr, const u8 *prev_psk) +{ + struct wpa *wpa = ctx; + wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)", + __func__, MAC2STR(addr), prev_psk); + if (prev_psk) + return NULL; + return wpa->psk; +} + + +static int auth_init_group(struct wpa *wpa) +{ + struct wpa_auth_config conf; + struct wpa_auth_callbacks cb; + + wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine"); + + os_memset(&conf, 0, sizeof(conf)); + conf.wpa = 2; + conf.wpa_key_mgmt = WPA_KEY_MGMT_PSK; + conf.wpa_pairwise = WPA_CIPHER_CCMP; + conf.rsn_pairwise = WPA_CIPHER_CCMP; + conf.wpa_group = WPA_CIPHER_CCMP; + conf.eapol_version = 2; + + os_memset(&cb, 0, sizeof(cb)); + cb.ctx = wpa; + cb.logger = auth_logger; + cb.send_eapol = auth_send_eapol; + cb.get_psk = auth_get_psk; + + wpa->auth_group = wpa_init(wpa->auth_addr, &conf, &cb); + if (wpa->auth_group == NULL) { + wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed"); + return -1; + } + + return 0; +} + + +static int auth_init(struct wpa *wpa) +{ + wpa->auth = wpa_auth_sta_init(wpa->auth_group, wpa->supp_addr); + if (wpa->auth == NULL) { + wpa_printf(MSG_DEBUG, "AUTH: wpa_auth_sta_init() failed"); + return -1; + } + + if (wpa_validate_wpa_ie(wpa->auth_group, wpa->auth, wpa->supp_ie, + wpa->supp_ie_len, NULL, 0) != WPA_IE_OK) { + wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed"); + return -1; + } + + wpa_auth_sm_event(wpa->auth, WPA_ASSOC); + + wpa_auth_sta_associated(wpa->auth_group, wpa->auth); + + return 0; +} + + +static void deinit(struct wpa *wpa) +{ + wpa_auth_sta_deinit(wpa->auth); + wpa_sm_deinit(wpa->supp); + wpa_deinit(wpa->auth_group); + os_free(wpa->auth_eapol); + wpa->auth_eapol = NULL; + os_free(wpa->supp_eapol); + wpa->supp_eapol = NULL; +} + + +int main(int argc, char *argv[]) +{ + struct wpa wpa; + + if (os_program_init()) + return -1; + + os_memset(&wpa, 0, sizeof(wpa)); + os_memset(wpa.auth_addr, 0x12, ETH_ALEN); + os_memset(wpa.supp_addr, 0x32, ETH_ALEN); + os_memset(wpa.psk, 0x44, PMK_LEN); + + wpa_debug_level = 0; + wpa_debug_show_keys = 1; + + if (eloop_init(&wpa)) { + wpa_printf(MSG_ERROR, "Failed to initialize event loop"); + return -1; + } + + if (auth_init_group(&wpa) < 0) + return -1; + + if (supp_init(&wpa) < 0) + return -1; + + if (auth_init(&wpa) < 0) + return -1; + + wpa_printf(MSG_DEBUG, "Starting eloop"); + eloop_run(); + wpa_printf(MSG_DEBUG, "eloop done"); + + deinit(&wpa); + + eloop_destroy(); + + os_program_deinit(); + + return 0; +} diff --git a/wpa_supplicant/tests/test_x509v3.c b/wpa_supplicant/tests/test_x509v3.c new file mode 100644 index 000000000000..c472c8a66074 --- /dev/null +++ b/wpa_supplicant/tests/test_x509v3.c @@ -0,0 +1,69 @@ +/* + * Testing tool for X.509v3 routines + * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "tls/asn1.h" +#include "tls/x509v3.h" + +extern int wpa_debug_level; + + +int main(int argc, char *argv[]) +{ + char *buf; + size_t len; + struct x509_certificate *certs = NULL, *last = NULL, *cert; + int i, reason; + + wpa_debug_level = 0; + + if (argc < 3 || strcmp(argv[1], "-v") != 0) { + printf("usage: test_x509v3 -v <cert1.der> <cert2.der> ..\n"); + return -1; + } + + for (i = 2; i < argc; i++) { + printf("Reading: %s\n", argv[i]); + buf = os_readfile(argv[i], &len); + if (buf == NULL) { + printf("Failed to read '%s'\n", argv[i]); + return -1; + } + + cert = x509_certificate_parse((u8 *) buf, len); + if (cert == NULL) { + printf("Failed to parse X.509 certificate\n"); + return -1; + } + + free(buf); + + if (certs == NULL) + certs = cert; + else + last->next = cert; + last = cert; + } + + printf("\n\nValidating certificate chain\n"); + if (x509_certificate_chain_validate(last, certs, &reason) < 0) { + printf("\nCertificate chain validation failed: %d\n", reason); + return -1; + } + printf("\nCertificate chain is valid\n"); + + return 0; +} diff --git a/wpa_supplicant/tests/test_x509v3_nist.sh b/wpa_supplicant/tests/test_x509v3_nist.sh new file mode 100755 index 000000000000..c33e36289dcb --- /dev/null +++ b/wpa_supplicant/tests/test_x509v3_nist.sh @@ -0,0 +1,144 @@ +#!/bin/sh + +# X.509 Path Validation Test Suite, Version 1.07 +# http://csrc.nist.gov/pki/testing/x509paths_old.html +# http://csrc.nist.gov/pki/testing/x509tests.tgz + +if [ -z "$1" ]; then + echo "usage: $0 <path to X509tests directory>" + exit 1 +fi + +TESTS=$1 + +if [ ! -d $TESTS ]; then + echo "Not a directory: $TESTS" + exit 1 +fi + +X509TEST="./test_x509v3 -v" +TMPOUT=test_x509v3_nist.out + +# TODO: add support for validating CRLs + +END="End Certificate " +ROOT="Trust Anchor " +ICA="Intermediate Certificate " + +SUCCESS="" +FAILURE="" + +function run_test +{ + NUM=$1 + RES=$2 + shift 2 + $X509TEST "$@" > $TMPOUT.$NUM + VALRES=$? + OK=0 + if [ $RES -eq 0 ]; then + # expecting success + if [ $VALRES -eq 0 ]; then + OK=1 + else + echo "test$NUM failed - expected validation success" + OK=0 + fi + else + # expecting failure + if [ $VALRES -eq 0 ]; then + echo "test$NUM failed - expected validation failure" + OK=0 + else + REASON=`grep "Certificate chain validation failed: " $TMPOUT.$NUM` + if [ $? -eq 0 ]; then + REASONNUM=`echo "$REASON" | colrm 1 37` + if [ $REASONNUM -eq $RES ]; then + OK=1 + else + echo "test$NUM failed - expected validation result $RES; result was $REASONNUM" + OK=0 + fi + else + echo "test$NUM failed - expected validation failure; other type of error detected" + OK=0 + fi + fi + fi + if [ $OK -eq 1 ]; then + rm $TMPOUT.$NUM + SUCCESS="$SUCCESS $NUM" + else + FAILURE="$FAILURE $NUM" + fi +} + +P=$TESTS/test + +run_test 1 0 "${P}1/${END}CP.01.01.crt" "${P}1/${ROOT}CP.01.01.crt" +run_test 2 1 "${P}2/${END}CP.01.02.crt" "${P}2/${ICA}CP.01.02.crt" "${P}2/${ROOT}CP.01.01.crt" +run_test 3 1 "${P}3/${END}CP.01.03.crt" "${P}3/${ICA}CP.01.03.crt" "${P}3/${ROOT}CP.01.01.crt" +run_test 4 0 "${P}4/${END}CP.02.01.crt" "${P}4/${ICA}2 CP.02.01.crt" "${P}4/${ICA}1 CP.02.01.crt" "${P}4/${ROOT}CP.01.01.crt" +run_test 5 4 "${P}5/${END}CP.02.02.crt" "${P}5/${ICA}CP.02.02.crt" "${P}5/${ROOT}CP.01.01.crt" +run_test 6 4 "${P}6/${END}CP.02.03.crt" "${P}6/${ICA}CP.02.03.crt" "${P}6/${ROOT}CP.01.01.crt" +run_test 7 0 "${P}7/${END}CP.02.04.crt" "${P}7/${ICA}CP.02.04.crt" "${P}7/${ROOT}CP.01.01.crt" +run_test 8 4 "${P}8/${END}CP.02.05.crt" "${P}8/${ICA}CP.02.05.crt" "${P}8/${ROOT}CP.01.01.crt" +run_test 9 4 "${P}9/${END}CP.03.01.crt" "${P}9/${ICA}CP.03.01.crt" "${P}9/${ROOT}CP.01.01.crt" +run_test 10 4 "${P}10/${END}CP.03.02.crt" "${P}10/${ICA}CP.03.02.crt" "${P}10/${ROOT}CP.01.01.crt" +run_test 11 4 "${P}11/${END}CP.03.03.crt" "${P}11/${ICA}CP.03.03.crt" "${P}11/${ROOT}CP.01.01.crt" +run_test 12 0 "${P}12/${END}CP.03.04.crt" "${P}12/${ICA}CP.03.04.crt" "${P}12/${ROOT}CP.01.01.crt" +run_test 13 5 "${P}13/${END}CP.04.01.crt" "${P}13/${ICA}CP.04.01.crt" "${P}13/${ROOT}CP.01.01.crt" +run_test 14 5 "${P}14/${END}CP.04.02.crt" "${P}14/${ICA}CP.04.02.crt" "${P}14/${ROOT}CP.01.01.crt" +run_test 15 0 "${P}15/${END}CP.04.03.crt" "${P}15/${ICA}CP.04.03.crt" "${P}15/${ROOT}CP.01.01.crt" +run_test 16 0 "${P}16/${END}CP.04.04.crt" "${P}16/${ICA}CP.04.04.crt" "${P}16/${ROOT}CP.01.01.crt" +run_test 17 0 "${P}17/${END}CP.04.05.crt" "${P}17/${ICA}CP.04.05.crt" "${P}17/${ROOT}CP.01.01.crt" +run_test 18 0 "${P}18/${END}CP.04.06.crt" "${P}18/${ICA}CP.04.06.crt" "${P}18/${ROOT}CP.01.01.crt" +run_test 19 1 "${P}19/${END}CP.05.01.crt" "${P}19/${ICA}CP.05.01.crt" "${P}19/${ROOT}CP.01.01.crt" +run_test 20 3 "${P}20/${END}CP.06.01.crt" "${P}20/${ICA}CP.06.01.crt" "${P}20/${ROOT}CP.01.01.crt" +run_test 21 3 "${P}21/${END}CP.06.02.crt" "${P}21/${ICA}CP.06.02.crt" "${P}21/${ROOT}CP.01.01.crt" +run_test 22 1 "${P}22/${END}IC.01.01.crt" "${P}22/${ICA}IC.01.01.crt" "${P}22/${ROOT}CP.01.01.crt" +run_test 23 1 "${P}23/${END}IC.02.01.crt" "${P}23/${ICA}IC.02.01.crt" "${P}23/${ROOT}CP.01.01.crt" +run_test 24 0 "${P}24/${END}IC.02.02.crt" "${P}24/${ICA}IC.02.02.crt" "${P}24/${ROOT}CP.01.01.crt" +run_test 25 1 "${P}25/${END}IC.02.03.crt" "${P}25/${ICA}IC.02.03.crt" "${P}25/${ROOT}CP.01.01.crt" +run_test 26 0 "${P}26/${END}IC.02.04.crt" "${P}26/${ICA}IC.02.04.crt" "${P}26/${ROOT}CP.01.01.crt" +run_test 27 0 "${P}27/${END}IC.04.01.crt" "${P}27/${ICA}IC.04.01.crt" "${P}27/${ROOT}CP.01.01.crt" +run_test 28 1 "${P}28/${END}IC.05.01.crt" "${P}28/${ICA}IC.05.01.crt" "${P}28/${ROOT}CP.01.01.crt" +run_test 29 1 "${P}29/${END}IC.05.02.crt" "${P}29/${ICA}IC.05.02.crt" "${P}29/${ROOT}CP.01.01.crt" +run_test 30 0 "${P}30/${END}IC.05.03.crt" "${P}30/${ICA}IC.05.03.crt" "${P}30/${ROOT}CP.01.01.crt" +run_test 31 1 "${P}31/${END}IC.06.01.crt" "${P}31/${ICA}IC.06.01.crt" "${P}31/${ROOT}CP.01.01.crt" +run_test 32 1 "${P}32/${END}IC.06.02.crt" "${P}32/${ICA}IC.06.02.crt" "${P}32/${ROOT}CP.01.01.crt" +run_test 33 0 "${P}33/${END}IC.06.03.crt" "${P}33/${ICA}IC.06.03.crt" "${P}33/${ROOT}CP.01.01.crt" +run_test 34 0 "${P}34/${END}PP.01.01.crt" "${P}34/${ICA}PP.01.01.crt" "${P}34/${ROOT}CP.01.01.crt" +run_test 35 0 "${P}35/${END}PP.01.02.crt" "${P}35/${ICA}PP.01.02.crt" "${P}35/${ROOT}CP.01.01.crt" +run_test 36 0 "${P}36/${END}PP.01.03.crt" "${P}36/${ICA}2 PP.01.03.crt" "${P}36/${ICA}1 PP.01.03.crt" "${P}36/${ROOT}CP.01.01.crt" +run_test 37 0 "${P}37/${END}PP.01.04.crt" "${P}37/${ICA}2 PP.01.04.crt" "${P}37/${ICA}1 PP.01.04.crt" "${P}37/${ROOT}CP.01.01.crt" +run_test 38 0 "${P}38/${END}PP.01.05.crt" "${P}38/${ICA}2 PP.01.05.crt" "${P}38/${ICA}1 PP.01.05.crt" "${P}38/${ROOT}CP.01.01.crt" +run_test 39 0 "${P}39/${END}PP.01.06.crt" "${P}39/${ICA}3 PP.01.06.crt" "${P}39/${ICA}2 PP.01.06.crt" "${P}39/${ICA}1 PP.01.06.crt" "${P}39/${ROOT}CP.01.01.crt" +run_test 40 0 "${P}40/${END}PP.01.07.crt" "${P}40/${ICA}3 PP.01.07.crt" "${P}40/${ICA}2 PP.01.07.crt" "${P}40/${ICA}1 PP.01.07.crt" "${P}40/${ROOT}CP.01.01.crt" +run_test 41 0 "${P}41/${END}PP.01.08.crt" "${P}41/${ICA}3 PP.01.08.crt" "${P}41/${ICA}2 PP.01.08.crt" "${P}41/${ICA}1 PP.01.08.crt" "${P}41/${ROOT}CP.01.01.crt" +run_test 42 0 "${P}42/${END}PP.01.09.crt" "${P}42/${ICA}4 PP.01.09.crt" "${P}42/${ICA}3 PP.01.09.crt" "${P}42/${ICA}2 PP.01.09.crt" "${P}42/${ICA}1 PP.01.09.crt" "${P}42/${ROOT}CP.01.01.crt" +run_test 43 0 "${P}43/${END}PP.06.01.crt" "${P}43/${ICA}4 PP.06.01.crt" "${P}43/${ICA}3 PP.06.01.crt" "${P}43/${ICA}2 PP.06.01.crt" "${P}43/${ICA}1 PP.06.01.crt" "${P}43/${ROOT}CP.01.01.crt" +run_test 44 0 "${P}44/${END}PP.06.02.crt" "${P}44/${ICA}4 PP.06.02.crt" "${P}44/${ICA}3 PP.06.02.crt" "${P}44/${ICA}2 PP.06.02.crt" "${P}44/${ICA}1 PP.06.02.crt" "${P}44/${ROOT}CP.01.01.crt" +run_test 45 0 "${P}45/${END}PP.06.03.crt" "${P}45/${ICA}4 PP.06.03.crt" "${P}45/${ICA}3 PP.06.03.crt" "${P}45/${ICA}2 PP.06.03.crt" "${P}45/${ICA}1 PP.06.03.crt" "${P}45/${ROOT}CP.01.01.crt" +run_test 46 0 "${P}46/${END}PP.06.04.crt" "${P}46/${ICA}4 PP.06.04.crt" "${P}46/${ICA}3 PP.06.04.crt" "${P}46/${ICA}2 PP.06.04.crt" "${P}46/${ICA}1 PP.06.04.crt" "${P}46/${ROOT}CP.01.01.crt" +run_test 47 0 "${P}47/${END}PP.06.05.crt" "${P}47/${ICA}4 PP.06.05.crt" "${P}47/${ICA}3 PP.06.05.crt" "${P}47/${ICA}2 PP.06.05.crt" "${P}47/${ICA}1 PP.06.05.crt" "${P}47/${ROOT}CP.01.01.crt" +run_test 48 0 "${P}48/${END}PP.08.01.crt" "${P}48/${ICA}PP.08.01.crt" "${P}48/${ROOT}CP.01.01.crt" +run_test 49 0 "${P}49/${END}PP.08.02.crt" "${P}49/${ICA}PP.08.02.crt" "${P}49/${ROOT}CP.01.01.crt" +run_test 50 0 "${P}50/${END}PP.08.03.crt" "${P}50/${ICA}PP.08.03.crt" "${P}50/${ROOT}CP.01.01.crt" +run_test 51 0 "${P}51/${END}PP.08.04.crt" "${P}51/${ICA}PP.08.04.crt" "${P}51/${ROOT}CP.01.01.crt" +run_test 52 0 "${P}52/${END}PP.08.05.crt" "${P}52/${ICA}PP.08.05.crt" "${P}52/${ROOT}CP.01.01.crt" +run_test 53 0 "${P}53/${END}PP.08.06.crt" "${P}53/${ICA}PP.08.06.crt" "${P}53/${ROOT}CP.01.01.crt" +run_test 54 1 "${P}54/${END}PL.01.01.crt" "${P}54/${ICA}2 PL.01.01.crt" "${P}54/${ICA}1 PL.01.01.crt" "${P}54/${ROOT}CP.01.01.crt" +run_test 55 1 "${P}55/${END}PL.01.02.crt" "${P}55/${ICA}2 PL.01.02.crt" "${P}55/${ICA}1 PL.01.02.crt" "${P}55/${ROOT}CP.01.01.crt" +run_test 56 0 "${P}56/${END}PL.01.03.crt" "${P}56/${ICA}PL.01.03.crt" "${P}56/${ROOT}CP.01.01.crt" +run_test 57 0 "${P}57/${END}PL.01.04.crt" "${P}57/${ICA}PL.01.04.crt" "${P}57/${ROOT}CP.01.01.crt" +run_test 58 1 "${P}58/${END}PL.01.05.crt" "${P}58/${ICA}3 PL.01.05.crt" "${P}58/${ICA}2 PL.01.05.crt" "${P}58/${ICA}1 PL.01.05.crt" "${P}58/${ROOT}CP.01.01.crt" +run_test 59 1 "${P}59/${END}PL.01.06.crt" "${P}59/${ICA}3 PL.01.06.crt" "${P}59/${ICA}2 PL.01.06.crt" "${P}59/${ICA}1 PL.01.06.crt" "${P}59/${ROOT}CP.01.01.crt" +run_test 60 1 "${P}60/${END}PL.01.07.crt" "${P}60/${ICA}4 PL.01.07.crt" "${P}60/${ICA}3 PL.01.07.crt" "${P}60/${ICA}2 PL.01.07.crt" "${P}60/${ICA}1 PL.01.07.crt" "${P}60/${ROOT}CP.01.01.crt" +run_test 61 1 "${P}61/${END}PL.01.08.crt" "${P}61/${ICA}4 PL.01.08.crt" "${P}61/${ICA}3 PL.01.08.crt" "${P}61/${ICA}2 PL.01.08.crt" "${P}61/${ICA}1 PL.01.08.crt" "${P}61/${ROOT}CP.01.01.crt" +run_test 62 0 "${P}62/${END}PL.01.09.crt" "${P}62/${ICA}4 PL.01.09.crt" "${P}62/${ICA}3 PL.01.09.crt" "${P}62/${ICA}2 PL.01.09.crt" "${P}62/${ICA}1 PL.01.09.crt" "${P}62/${ROOT}CP.01.01.crt" +run_test 63 0 "${P}63/${END}PL.01.10.crt" "${P}63/${ICA}4 PL.01.10.crt" "${P}63/${ICA}3 PL.01.10.crt" "${P}63/${ICA}2 PL.01.10.crt" "${P}63/${ICA}1 PL.01.10.crt" "${P}63/${ROOT}CP.01.01.crt" + + +echo "Successful tests:$SUCCESS" +echo "Failed tests:$FAILURE" diff --git a/wpa_supplicant/tests/test_x509v3_nist2.sh b/wpa_supplicant/tests/test_x509v3_nist2.sh new file mode 100755 index 000000000000..0be29b7feb31 --- /dev/null +++ b/wpa_supplicant/tests/test_x509v3_nist2.sh @@ -0,0 +1,165 @@ +#!/bin/sh + +# Public Key Interoperability Test Suite (PKITS) +# http://csrc.nist.gov/pki/testing/x509paths.html +# http://csrc.nist.gov/pki/testing/PKITS_data.zip + +if [ -z "$1" ]; then + echo "usage: $0 <path to root test directory>" + exit 1 +fi + +TESTS=$1 + +if [ ! -d $TESTS ]; then + echo "Not a directory: $TESTS" + exit 1 +fi + +X509TEST="$PWD/test_x509v3 -v" +TMPOUT="$PWD/test_x509v3_nist2.out" + +# TODO: add support for validating CRLs + +SUCCESS="" +FAILURE="" + +function run_test +{ + NUM=$1 + RES=$2 + shift 2 + $X509TEST "$@" TrustAnchorRootCertificate.crt > $TMPOUT.$NUM + VALRES=$? + OK=0 + if [ $RES -eq 0 ]; then + # expecting success + if [ $VALRES -eq 0 ]; then + OK=1 + else + echo "$NUM failed - expected validation success" + OK=0 + fi + else + # expecting failure + if [ $VALRES -eq 0 ]; then + echo "$NUM failed - expected validation failure" + OK=0 + else + REASON=`grep "Certificate chain validation failed: " $TMPOUT.$NUM` + if [ $? -eq 0 ]; then + REASONNUM=`echo "$REASON" | colrm 1 37` + if [ $REASONNUM -eq $RES ]; then + OK=1 + else + echo "$NUM failed - expected validation result $RES; result was $REASONNUM" + OK=0 + fi + else + echo "$NUM failed - expected validation failure; other type of error detected" + OK=0 + fi + fi + fi + if [ $OK -eq 1 ]; then + rm $TMPOUT.$NUM + SUCCESS="$SUCCESS $NUM" + else + FAILURE="$FAILURE $NUM" + fi +} + +pushd $TESTS/certs + +run_test 4.1.1 0 ValidCertificatePathTest1EE.crt GoodCACert.crt +run_test 4.1.2 1 InvalidCASignatureTest2EE.crt BadSignedCACert.crt +run_test 4.1.3 1 InvalidEESignatureTest3EE.crt GoodCACert.crt + +run_test 4.2.1 4 InvalidCAnotBeforeDateTest1EE.crt BadnotBeforeDateCACert.crt +run_test 4.2.2 4 InvalidEEnotBeforeDateTest2EE.crt GoodCACert.crt +run_test 4.2.3 0 Validpre2000UTCnotBeforeDateTest3EE.crt GoodCACert.crt +run_test 4.2.4 0 ValidGeneralizedTimenotBeforeDateTest4EE.crt GoodCACert.crt +run_test 4.2.5 4 InvalidCAnotAfterDateTest5EE.crt BadnotAfterDateCACert.crt +run_test 4.2.6 4 InvalidEEnotAfterDateTest6EE.crt GoodCACert.crt +run_test 4.2.7 4 Invalidpre2000UTCEEnotAfterDateTest7EE.crt GoodCACert.crt +run_test 4.2.8 0 ValidGeneralizedTimenotAfterDateTest8EE.crt GoodCACert.crt + +run_test 4.3.1 5 InvalidNameChainingTest1EE.crt GoodCACert.crt +run_test 4.3.2 5 InvalidNameChainingOrderTest2EE.crt NameOrderingCACert.crt +run_test 4.3.3 0 ValidNameChainingWhitespaceTest3EE.crt GoodCACert.crt +run_test 4.3.4 0 ValidNameChainingWhitespaceTest4EE.crt GoodCACert.crt +run_test 4.3.5 0 ValidNameChainingCapitalizationTest5EE.crt GoodCACert.crt +run_test 4.3.6 0 ValidNameUIDsTest6EE.crt UIDCACert.crt +run_test 4.3.7 0 ValidRFC3280MandatoryAttributeTypesTest7EE.crt RFC3280MandatoryAttributeTypesCACert.crt +run_test 4.3.8 0 ValidRFC3280OptionalAttributeTypesTest8EE.crt RFC3280OptionalAttributeTypesCACert.crt +run_test 4.3.9 0 ValidUTF8StringEncodedNamesTest9EE.crt UTF8StringEncodedNamesCACert.crt +run_test 4.3.10 0 ValidRolloverfromPrintableStringtoUTF8StringTest10EE.crt RolloverfromPrintableStringtoUTF8StringCACert.crt +run_test 4.3.11 0 ValidUTF8StringCaseInsensitiveMatchTest11EE.crt UTF8StringCaseInsensitiveMatchCACert.crt + +run_test 4.4.1 1 InvalidMissingCRLTest1EE.crt NoCRLCACert.crt +# skip rest of 4.4.x tests since CRLs are not yet supported + +run_test 4.5.1 0 ValidBasicSelfIssuedOldWithNewTest1EE.crt BasicSelfIssuedNewKeyOldWithNewCACert.crt BasicSelfIssuedNewKeyCACert.crt +run_test 4.5.2 3 InvalidBasicSelfIssuedOldWithNewTest2EE.crt BasicSelfIssuedNewKeyOldWithNewCACert.crt BasicSelfIssuedNewKeyCACert.crt +run_test 4.5.3 0 ValidBasicSelfIssuedNewWithOldTest3EE.crt BasicSelfIssuedOldKeyNewWithOldCACert.crt BasicSelfIssuedOldKeyCACert.crt +run_test 4.5.4 0 ValidBasicSelfIssuedNewWithOldTest4EE.crt BasicSelfIssuedOldKeyNewWithOldCACert.crt BasicSelfIssuedOldKeyCACert.crt +run_test 4.5.5 3 InvalidBasicSelfIssuedNewWithOldTest5EE.crt BasicSelfIssuedOldKeyNewWithOldCACert.crt BasicSelfIssuedOldKeyCACert.crt +run_test 4.5.6 0 ValidBasicSelfIssuedCRLSigningKeyTest6EE.crt BasicSelfIssuedCRLSigningKeyCRLCert.crt BasicSelfIssuedCRLSigningKeyCACert.crt +run_test 4.5.7 3 InvalidBasicSelfIssuedCRLSigningKeyTest7EE.crt BasicSelfIssuedCRLSigningKeyCRLCert.crt BasicSelfIssuedCRLSigningKeyCACert.crt +run_test 4.5.8 1 InvalidBasicSelfIssuedCRLSigningKeyTest8EE.crt BasicSelfIssuedCRLSigningKeyCRLCert.crt BasicSelfIssuedCRLSigningKeyCACert.crt + +run_test 4.6.1 1 InvalidMissingbasicConstraintsTest1EE.crt MissingbasicConstraintsCACert.crt +run_test 4.6.2 1 InvalidcAFalseTest2EE.crt basicConstraintsCriticalcAFalseCACert.crt +run_test 4.6.3 1 InvalidcAFalseTest3EE.crt basicConstraintsNotCriticalcAFalseCACert.crt +run_test 4.6.4 0 ValidbasicConstraintsNotCriticalTest4EE.crt basicConstraintsNotCriticalCACert.crt +run_test 4.6.5 1 InvalidpathLenConstraintTest5EE.crt pathLenConstraint0subCACert.crt pathLenConstraint0CACert.crt +run_test 4.6.6 1 InvalidpathLenConstraintTest6EE.crt pathLenConstraint0subCACert.crt pathLenConstraint0CACert.crt +run_test 4.6.7 0 ValidpathLenConstraintTest7EE.crt pathLenConstraint0CACert.crt +run_test 4.6.8 0 ValidpathLenConstraintTest8EE.crt pathLenConstraint0CACert.crt +run_test 4.6.9 1 InvalidpathLenConstraintTest9EE.crt pathLenConstraint6subsubCA00Cert.crt pathLenConstraint6subCA0Cert.crt pathLenConstraint6CACert.crt +run_test 4.6.10 1 InvalidpathLenConstraintTest10EE.crt pathLenConstraint6subsubCA00Cert.crt pathLenConstraint6subCA0Cert.crt pathLenConstraint6CACert.crt +run_test 4.6.11 1 InvalidpathLenConstraintTest11EE.crt pathLenConstraint6subsubsubCA11XCert.crt pathLenConstraint6subsubCA11Cert.crt pathLenConstraint6subCA1Cert.crt pathLenConstraint6CACert.crt +run_test 4.6.12 1 InvalidpathLenConstraintTest12EE.crt pathLenConstraint6subsubsubCA11XCert.crt pathLenConstraint6subsubCA11Cert.crt pathLenConstraint6subCA1Cert.crt pathLenConstraint6CACert.crt +run_test 4.6.13 0 ValidpathLenConstraintTest13EE.crt pathLenConstraint6subsubsubCA41XCert.crt pathLenConstraint6subsubCA41Cert.crt pathLenConstraint6subCA4Cert.crt pathLenConstraint6CACert.crt +run_test 4.6.14 0 ValidpathLenConstraintTest14EE.crt pathLenConstraint6subsubsubCA41XCert.crt pathLenConstraint6subsubCA41Cert.crt pathLenConstraint6subCA4Cert.crt pathLenConstraint6CACert.crt +run_test 4.6.15 0 ValidSelfIssuedpathLenConstraintTest15EE.crt pathLenConstraint0SelfIssuedCACert.crt pathLenConstraint0CACert.crt +run_test 4.6.16 1 InvalidSelfIssuedpathLenConstraintTest16EE.crt pathLenConstraint0subCA2Cert.crt pathLenConstraint0SelfIssuedCACert.crt pathLenConstraint0CACert.crt +run_test 4.6.17 0 ValidSelfIssuedpathLenConstraintTest17EE.crt pathLenConstraint1SelfIssuedsubCACert.crt pathLenConstraint1subCACert.crt pathLenConstraint1SelfIssuedCACert.crt pathLenConstraint1CACert.crt + +run_test 4.7.1 1 InvalidkeyUsageCriticalkeyCertSignFalseTest1EE.crt keyUsageCriticalkeyCertSignFalseCACert.crt +run_test 4.7.2 1 InvalidkeyUsageNotCriticalkeyCertSignFalseTest2EE.crt keyUsageNotCriticalkeyCertSignFalseCACert.crt +run_test 4.7.3 0 ValidkeyUsageNotCriticalTest3EE.crt keyUsageNotCriticalCACert.crt +run_test 4.7.4 1 InvalidkeyUsageCriticalcRLSignFalseTest4EE.crt keyUsageCriticalcRLSignFalseCACert.crt +run_test 4.7.5 1 InvalidkeyUsageNotCriticalcRLSignFalseTest5EE.crt keyUsageNotCriticalcRLSignFalseCACert.crt + +run_test 4.8.1 0 ValidCertificatePathTest1EE.crt GoodCACert.crt +run_test 4.8.2 0 AllCertificatesNoPoliciesTest2EE.crt NoPoliciesCACert.crt +run_test 4.8.3 0 DifferentPoliciesTest3EE.crt PoliciesP2subCACert.crt GoodCACert.crt +run_test 4.8.4 0 DifferentPoliciesTest4EE.crt GoodsubCACert.crt GoodCACert.crt +run_test 4.8.5 0 DifferentPoliciesTest5EE.crt PoliciesP2subCA2Cert.crt GoodCACert.crt +run_test 4.8.6 0 OverlappingPoliciesTest6EE.crt PoliciesP1234subsubCAP123P12Cert.crt PoliciesP1234subCAP123Cert.crt PoliciesP1234CACert.crt +run_test 4.8.7 0 DifferentPoliciesTest7EE.crt PoliciesP123subsubCAP12P1Cert.crt PoliciesP123subCAP12Cert.crt PoliciesP123CACert.crt +run_test 4.8.8 0 DifferentPoliciesTest8EE.crt PoliciesP12subsubCAP1P2Cert.crt PoliciesP12subCAP1Cert.crt PoliciesP12CACert.crt +run_test 4.8.9 0 DifferentPoliciesTest9EE.crt PoliciesP123subsubsubCAP12P2P1Cert.crt PoliciesP123subsubCAP12P2Cert.crt PoliciesP123subCAP12Cert.crt PoliciesP123CACert.crt +run_test 4.8.10 0 AllCertificatesSamePoliciesTest10EE.crt PoliciesP12CACert.crt +run_test 4.8.11 0 AllCertificatesanyPolicyTest11EE.crt anyPolicyCACert.crt +run_test 4.8.12 0 DifferentPoliciesTest12EE.crt PoliciesP3CACert.crt +run_test 4.8.13 0 AllCertificatesSamePoliciesTest13EE.crt PoliciesP123CACert.crt +run_test 4.8.14 0 AnyPolicyTest14EE.crt anyPolicyCACert.crt +run_test 4.8.15 0 UserNoticeQualifierTest15EE.crt +run_test 4.8.16 0 UserNoticeQualifierTest16EE.crt GoodCACert.crt +run_test 4.8.17 0 UserNoticeQualifierTest17EE.crt GoodCACert.crt +run_test 4.8.18 0 UserNoticeQualifierTest18EE.crt PoliciesP12CACert.crt +run_test 4.8.19 0 UserNoticeQualifierTest19EE.crt TrustAnchorRootCertificate.crt +run_test 4.8.20 0 CPSPointerQualifierTest20EE.crt GoodCACert.crt + +if false; then +# DSA tests +run_test 4.1.4 0 ValidDSASignaturesTest4EE.crt DSACACert.crt +fi + +popd + + +echo "Successful tests:$SUCCESS" +echo "Failed tests:$FAILURE" diff --git a/wpa_supplicant/todo.txt b/wpa_supplicant/todo.txt new file mode 100644 index 000000000000..a02a937e63df --- /dev/null +++ b/wpa_supplicant/todo.txt @@ -0,0 +1,92 @@ +To do: +- hostap: try other roaming modes + NOTE: current mode (manual roaming) does not really roam at all.. + Firmware did not notice the current AP disappearing.. +- add support for WPA with ap_scan=0 (update selected cipher etc. based on + AssocInfo; make sure these match with configuration) +- consider closing smart card / PCSC connection when EAP-SIM/EAP-AKA + authentication has been completed (cache scard data based on serial#(?) + and try to optimize next connection if the same card is present for next + auth) +- on disconnect event, could try to associate with another AP if one is + present in scan results; would need to update scan results periodically.. +- if driver/hw is not WPA2 capable, must remove WPA_PROTO_RSN flag from + ssid->proto fields to avoid detecting downgrade attacks when the driver + is not reporting RSN IE, but msg 3/4 has one +- Cisco AP and non-zero keyidx for unicast -> map to broadcast + (actually, this already works with driver_ndis; so maybe just change + driver_*.c to do the mapping for drivers that cannot handle non-zero keyidx + for unicast); worked also with Host AP driver and madwifi +- IEEE 802.1X and key update with driver_ndis?? wpa_supplicant did not seem + to see unencrypted EAPOL-Key frames at all.. +- EAP-PAX with PAX_SEC +- EAP (RFC 3748) + * OTP Extended Responses (Sect. 5.5) +- test what happens if authenticator sends EAP-Success before real EAP + authentication ("canned" Success); this should be ignored based on + RFC 3748 Sect. 4.2 +- test compilation with gcc -W options (more warnings?) + (Done once; number of unused function arguments still present) +- add proper support for using dot11RSNAConfigSATimeout +- ctrl_iface: get/set/remove blob +- use doc/docbook/*.sgml and docbook2{txt,html,pdf} to replace README and + web pages including the same information.. i.e., have this information only + in one page; how to build a PDF file with all the SGML included? +- EAP-POTP/RSA SecurID profile (RFC 4793) +- document wpa_gui build and consider adding it to 'make install' +- test madwifi with pairwise=TKIP group=WEP104 +- possibility to link in WPA Authenticator state machine to wpa_supplicant + (new PeerKey handshake, WPA2/IEEE 802.11 (RSN) IBSS) +- consider merging hostapd and wpa_supplicant PMKSA cache implementations +- consider redesigning pending EAP requests (identity/password/otp from + ctrl_iface) by moving the retrying of the previous request into EAP + state machine so that EAPOL state machine is not needed for this +- rfc4284.txt (network selection for eap) +- www pages about configuring wpa_supplicant: + * global options (ap_scan, ctrl_interfaces) based on OS/driver + * network block + * key_mgmt selection + * WPA parameters + * EAP options (one page for each method) + * "configuration wizard" (step 1: select OS, step 2: select driver, ...) to + generate example configuration +- error path in rsn_preauth_init: should probably deinit l2_packet handlers + if something fails; does something else need deinit? +- consider moving SIM card functionality (IMSI fetching) away from eap.c; + this should likely happen before EAP is initialized for authentication; + now IMSI is read only after receiving EAP-Identity/Request, but since it is + really needed for all cases, reading IMSI and generating Identity string + could very well be done before EAP has been started +- try to work around race in receiving association event and first EAPOL + message +- add wpa_secure_memzero() macro and secure implementation (volatile u8*) to + clear memory; this would be used to clear temporary buffers containing + private data (e.g., keys); the macro can be defined to NOP in order to save + space (i.e., no code should depend on the macro doing something) +- make sure that TLS session cache is not shared between EAP types or if it + is, that the cache entries are bound to only one EAP type; e.g., cache entry + created with EAP-TLS must not be allowed to do fast re-auth with EAP-TTLS +- consider moving eap_tls_build_ack() call into eap_tls_process_helper() + (it seems to be called always if helper returns 1) + * could need to modify eap_{ttls,peap,fast}_decrypt to do same +- add support for fetching full user cert chain from Windows certificate + stores even when there are intermediate CA certs that are not in the + configured ca_cert store (e.g., ROOT) (they could be, e.g., in CA store) + + +0.6.x branch: +- clean up common.[ch] +- change TLS/crypto library interface to use a structure of function + pointers and helper inline functions (like driver_ops) instead of + requiring every TLS wrapper to implement all functions +- add support for encrypted configuration fields (e.g., password, psk, + passphrase, pin) +- wpa_gui: add support for setting and showing priority, auth_alg + (open/shared for static WEP) + +- cleanup TLS/PEAP/TTLS/FAST fragmentation: both the handshake and Appl. Data + phases should be able to use the same functions for this; + the last step in processing sent should be this code and rest of the code + should not need to care about fragmentation at all +- test EAP-FAST peer with OpenSSL and verify that fallback to full handshake + (ServerHello followed by something else than ChangeCipherSpec) diff --git a/wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj b/wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj new file mode 100755 index 000000000000..ffe12c46ad34 --- /dev/null +++ b/wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj @@ -0,0 +1,425 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="8.00" + Name="eapol_test" + ProjectGUID="{0E3F2C6D-1372-48D6-BCAB-E584917C4DE3}" + RootNamespace="eapol_test" + Keyword="Win32Proj" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="..\..;..\..\..\src;..\..\..\src\utils;..\..\..\src\common;..\..\..\src\crypto;..\..\..\src\rsn_supp;C:\dev\WpdPack\include;C:\dev\openssl\include" + PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="3" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="4" + DisableSpecificWarnings="4244;4267;4311" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="ws2_32.lib Crypt32.lib Winscard.lib Packet.lib wpcap.lib libeay32MT.lib ssleay32Mt.lib" + LinkIncremental="2" + AdditionalLibraryDirectories="C:\dev\WpdPack\lib;C:\dev\openssl\lib" + GenerateDebugInformation="true" + SubSystem="1" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="1" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="..\..;..\..\..\src;..\..\..\src\utils;..\..\..\src\common;..\..\..\src\crypto;..\..\..\src\rsn_supp;C:\dev\WpdPack\include;C:\dev\openssl\include" + PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS" + RuntimeLibrary="2" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + DisableSpecificWarnings="4244;4267;4311" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="ws2_32.lib Crypt32.lib Winscard.lib Packet.lib wpcap.lib libeay32MT.lib ssleay32Mt.lib" + LinkIncremental="1" + AdditionalLibraryDirectories="C:\dev\WpdPack\lib;C:\dev\openssl\lib" + GenerateDebugInformation="true" + SubSystem="1" + OptimizeReferences="2" + EnableCOMDATFolding="2" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" + > + <File + RelativePath="..\..\..\src\crypto\aes_wrap.c" + > + </File> + <File + RelativePath="..\..\..\src\utils\base64.c" + > + </File> + <File + RelativePath="..\..\blacklist.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_common\chap.c" + > + </File> + <File + RelativePath="..\..\..\src\utils\common.c" + > + </File> + <File + RelativePath="..\..\config.c" + > + </File> + <File + RelativePath="..\..\config_file.c" + > + </File> + <File + RelativePath="..\..\..\src\crypto\crypto_openssl.c" + > + </File> + <File + RelativePath="..\..\ctrl_iface.c" + > + </File> + <File + RelativePath="..\..\ctrl_iface_named_pipe.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_aka.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_common\eap_common.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_gtc.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_leap.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_md5.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_methods.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_mschapv2.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_otp.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_peap.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_common\eap_peap_common.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_sim.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_common\eap_sim_common.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_tls.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_tls_common.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_tnc.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_ttls.c" + > + </File> + <File + RelativePath="..\..\..\src\eapol_supp\eapol_supp_sm.c" + > + </File> + <File + RelativePath="..\..\eapol_test.c" + > + </File> + <File + RelativePath="..\..\..\src\utils\eloop_win.c" + > + </File> + <File + RelativePath="..\..\events.c" + > + </File> + <File + RelativePath="..\..\..\src\utils\ip_addr.c" + > + </File> + <File + RelativePath="..\..\..\src\l2_packet\l2_packet_winpcap.c" + > + </File> + <File + RelativePath="..\..\..\src\crypto\md5.c" + > + </File> + <File + RelativePath="..\..\..\src\crypto\ms_funcs.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\mschapv2.c" + > + </File> + <File + RelativePath="..\..\..\src\utils\os_win32.c" + > + </File> + <File + RelativePath="..\..\..\src\utils\pcsc_funcs.c" + > + </File> + <File + RelativePath="..\..\..\src\rsn_supp\peerkey.c" + > + </File> + <File + RelativePath="..\..\..\src\rsn_supp\pmksa_cache.c" + > + </File> + <File + RelativePath="..\..\..\src\rsn_supp\preauth.c" + > + </File> + <File + RelativePath="..\..\..\src\radius\radius.c" + > + </File> + <File + RelativePath="..\..\..\src\radius\radius_client.c" + > + </File> + <File + RelativePath="..\..\..\src\crypto\rc4.c" + > + </File> + <File + RelativePath="..\..\scan.c" + > + </File> + <File + RelativePath="..\..\..\src\drivers\scan_helpers.c" + > + </File> + <File + RelativePath="..\..\..\src\crypto\sha1.c" + > + </File> + <File + RelativePath="..\..\..\src\crypto\tls_openssl.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\tncc.c" + > + </File> + <File + RelativePath="..\..\..\src\rsn_supp\wpa.c" + > + </File> + <File + RelativePath="..\..\..\src\common\wpa_common.c" + > + </File> + <File + RelativePath="..\..\..\src\utils\wpa_debug.c" + > + </File> + <File + RelativePath="..\..\..\src\rsn_supp\wpa_ie.c" + > + </File> + <File + RelativePath="..\..\wpa_supplicant.c" + > + </File> + <File + RelativePath="..\..\..\src\utils\wpabuf.c" + > + </File> + <File + RelativePath="..\..\wpas_glue.c" + > + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" + > + </Filter> + <Filter + Name="Resource Files" + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" + UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" + > + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/wpa_supplicant/vs2005/win_if_list/win_if_list.vcproj b/wpa_supplicant/vs2005/win_if_list/win_if_list.vcproj new file mode 100755 index 000000000000..89122f80cc79 --- /dev/null +++ b/wpa_supplicant/vs2005/win_if_list/win_if_list.vcproj @@ -0,0 +1,203 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="8.00" + Name="win_if_list" + ProjectGUID="{9E87CD9C-60CE-4533-85CF-85CA3A9BF26A}" + RootNamespace="win_if_list" + Keyword="Win32Proj" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="0" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="..\..\..\src\utils;C:\dev\WpdPack\include" + PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="3" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="wpcap.lib" + LinkIncremental="2" + AdditionalLibraryDirectories="C:\dev\WpdPack\lib" + GenerateDebugInformation="true" + SubSystem="1" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="0" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="..\..\..\src\utils;C:\dev\WpdPack\include" + PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS" + RuntimeLibrary="2" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="wpcap.lib" + LinkIncremental="1" + AdditionalLibraryDirectories="C:\dev\WpdPack\lib" + GenerateDebugInformation="true" + SubSystem="1" + OptimizeReferences="2" + EnableCOMDATFolding="2" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" + > + <File + RelativePath="..\..\win_if_list.c" + > + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" + > + </Filter> + <Filter + Name="Resource Files" + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" + UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" + > + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/wpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj b/wpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj new file mode 100755 index 000000000000..1cc31a6c487d --- /dev/null +++ b/wpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj @@ -0,0 +1,215 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="8.00" + Name="wpa_cli" + ProjectGUID="{E3A7B181-22CC-4DA3-8410-6AD69879A9EC}" + RootNamespace="wpa_cli" + Keyword="Win32Proj" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="0" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="..\..\..\src\utils;..\..\..\src\common" + PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="3" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="4" + DisableSpecificWarnings="4244;4267" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="ws2_32.lib" + LinkIncremental="2" + GenerateDebugInformation="true" + SubSystem="1" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="0" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="..\..\..\src\utils;..\..\..\src\common" + PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS" + RuntimeLibrary="2" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + DisableSpecificWarnings="4244;4267" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="ws2_32.lib" + LinkIncremental="1" + GenerateDebugInformation="true" + SubSystem="1" + OptimizeReferences="2" + EnableCOMDATFolding="2" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" + > + <File + RelativePath="..\..\..\src\utils\common.c" + > + </File> + <File + RelativePath="..\..\..\src\utils\os_win32.c" + > + </File> + <File + RelativePath="..\..\wpa_cli.c" + > + </File> + <File + RelativePath="..\..\..\src\common\wpa_ctrl.c" + > + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" + > + </Filter> + <Filter + Name="Resource Files" + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" + UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" + > + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj b/wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj new file mode 100755 index 000000000000..2a9a590aebff --- /dev/null +++ b/wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj @@ -0,0 +1,220 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="8.00" + Name="wpa_passphrase" + ProjectGUID="{ADBE4EA8-F0C5-40C2-AE89-C56D0F2EC1DF}" + RootNamespace="wpa_passphrase" + Keyword="Win32Proj" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="0" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="..\..\..\src\utils;..\..\..\src\crypto;C:\dev\openssl\include" + PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS;INTERNAL_SHA1;INTERNAL_MD5" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="3" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="4" + DisableSpecificWarnings="4244;4267" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="ws2_32.lib" + LinkIncremental="2" + AdditionalLibraryDirectories="" + GenerateDebugInformation="true" + SubSystem="1" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="0" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="..\..\..\src\utils;..\..\..\src\crypto;C:\dev\openssl\include" + PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS;INTERNAL_SHA1;INTERNAL_MD5" + RuntimeLibrary="2" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + DisableSpecificWarnings="4244;4267" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="ws2_32.lib" + LinkIncremental="1" + GenerateDebugInformation="true" + SubSystem="1" + OptimizeReferences="2" + EnableCOMDATFolding="2" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" + > + <File + RelativePath="..\..\..\src\utils\common.c" + > + </File> + <File + RelativePath="..\..\..\src\crypto\md5.c" + > + </File> + <File + RelativePath="..\..\..\src\utils\os_win32.c" + > + </File> + <File + RelativePath="..\..\..\src\crypto\sha1.c" + > + </File> + <File + RelativePath="..\..\wpa_passphrase.c" + > + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" + > + </Filter> + <Filter + Name="Resource Files" + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" + UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" + > + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/wpa_supplicant/vs2005/wpa_supplicant.sln b/wpa_supplicant/vs2005/wpa_supplicant.sln new file mode 100755 index 000000000000..97b756652dad --- /dev/null +++ b/wpa_supplicant/vs2005/wpa_supplicant.sln @@ -0,0 +1,52 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wpa_supplicant", "wpa_supplicant\wpa_supplicant.vcproj", "{8BCFDA77-AEDC-4168-8897-5B73105BBB87}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wpa_cli", "wpa_cli\wpa_cli.vcproj", "{E3A7B181-22CC-4DA3-8410-6AD69879A9EC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wpasvc", "wpasvc\wpasvc.vcproj", "{E2A4A85F-CA77-406D-8ABF-63EF94545ACC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wpa_passphrase", "wpa_passphrase\wpa_passphrase.vcproj", "{ADBE4EA8-F0C5-40C2-AE89-C56D0F2EC1DF}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "win_if_list", "win_if_list\win_if_list.vcproj", "{9E87CD9C-60CE-4533-85CF-85CA3A9BF26A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "eapol_test", "eapol_test\eapol_test.vcproj", "{0E3F2C6D-1372-48D6-BCAB-E584917C4DE3}" +EndProject +Global + GlobalSection(DPCodeReviewSolutionGUID) = preSolution + DPCodeReviewSolutionGUID = {00000000-0000-0000-0000-000000000000} + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8BCFDA77-AEDC-4168-8897-5B73105BBB87}.Debug|Win32.ActiveCfg = Debug|Win32 + {8BCFDA77-AEDC-4168-8897-5B73105BBB87}.Debug|Win32.Build.0 = Debug|Win32 + {8BCFDA77-AEDC-4168-8897-5B73105BBB87}.Release|Win32.ActiveCfg = Release|Win32 + {8BCFDA77-AEDC-4168-8897-5B73105BBB87}.Release|Win32.Build.0 = Release|Win32 + {E3A7B181-22CC-4DA3-8410-6AD69879A9EC}.Debug|Win32.ActiveCfg = Debug|Win32 + {E3A7B181-22CC-4DA3-8410-6AD69879A9EC}.Debug|Win32.Build.0 = Debug|Win32 + {E3A7B181-22CC-4DA3-8410-6AD69879A9EC}.Release|Win32.ActiveCfg = Release|Win32 + {E3A7B181-22CC-4DA3-8410-6AD69879A9EC}.Release|Win32.Build.0 = Release|Win32 + {E2A4A85F-CA77-406D-8ABF-63EF94545ACC}.Debug|Win32.ActiveCfg = Debug|Win32 + {E2A4A85F-CA77-406D-8ABF-63EF94545ACC}.Debug|Win32.Build.0 = Debug|Win32 + {E2A4A85F-CA77-406D-8ABF-63EF94545ACC}.Release|Win32.ActiveCfg = Release|Win32 + {E2A4A85F-CA77-406D-8ABF-63EF94545ACC}.Release|Win32.Build.0 = Release|Win32 + {ADBE4EA8-F0C5-40C2-AE89-C56D0F2EC1DF}.Debug|Win32.ActiveCfg = Debug|Win32 + {ADBE4EA8-F0C5-40C2-AE89-C56D0F2EC1DF}.Debug|Win32.Build.0 = Debug|Win32 + {ADBE4EA8-F0C5-40C2-AE89-C56D0F2EC1DF}.Release|Win32.ActiveCfg = Release|Win32 + {ADBE4EA8-F0C5-40C2-AE89-C56D0F2EC1DF}.Release|Win32.Build.0 = Release|Win32 + {9E87CD9C-60CE-4533-85CF-85CA3A9BF26A}.Debug|Win32.ActiveCfg = Debug|Win32 + {9E87CD9C-60CE-4533-85CF-85CA3A9BF26A}.Debug|Win32.Build.0 = Debug|Win32 + {9E87CD9C-60CE-4533-85CF-85CA3A9BF26A}.Release|Win32.ActiveCfg = Release|Win32 + {9E87CD9C-60CE-4533-85CF-85CA3A9BF26A}.Release|Win32.Build.0 = Release|Win32 + {0E3F2C6D-1372-48D6-BCAB-E584917C4DE3}.Debug|Win32.ActiveCfg = Debug|Win32 + {0E3F2C6D-1372-48D6-BCAB-E584917C4DE3}.Debug|Win32.Build.0 = Debug|Win32 + {0E3F2C6D-1372-48D6-BCAB-E584917C4DE3}.Release|Win32.ActiveCfg = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj b/wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj new file mode 100755 index 000000000000..2227f32de818 --- /dev/null +++ b/wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj @@ -0,0 +1,421 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="8.00" + Name="wpa_supplicant" + ProjectGUID="{8BCFDA77-AEDC-4168-8897-5B73105BBB87}" + RootNamespace="wpa_supplicant" + Keyword="Win32Proj" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="0" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="..\..;..\..\..\src;..\..\..\src\utils;..\..\..\src\common;..\..\..\src\crypto;..\..\..\src\rsn_supp;C:\dev\WpdPack\include;C:\dev\openssl\include" + PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="3" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="4" + DisableSpecificWarnings="4244;4267;4311" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="wbemuuid.lib ws2_32.lib Crypt32.lib Winscard.lib Packet.lib wpcap.lib libeay32MT.lib ssleay32Mt.lib" + LinkIncremental="2" + AdditionalLibraryDirectories="C:\dev\WpdPack\lib;C:\dev\openssl\lib" + GenerateDebugInformation="true" + SubSystem="1" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="0" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="..\..;..\..\..\src;..\..\..\src\utils;..\..\..\src\common;..\..\..\src\crypto;..\..\..\src\rsn_supp;C:\dev\WpdPack\include;C:\dev\openssl\include" + PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS" + RuntimeLibrary="2" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + DisableSpecificWarnings="4244;4267;4311" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="wbemuuid.lib ws2_32.lib Crypt32.lib Winscard.lib Packet.lib wpcap.lib libeay32MT.lib ssleay32Mt.lib" + LinkIncremental="1" + AdditionalLibraryDirectories="C:\dev\WpdPack\lib;C:\dev\openssl\lib" + GenerateDebugInformation="true" + SubSystem="1" + OptimizeReferences="2" + EnableCOMDATFolding="2" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" + > + <File + RelativePath="..\..\..\src\crypto\aes_wrap.c" + > + </File> + <File + RelativePath="..\..\..\src\utils\base64.c" + > + </File> + <File + RelativePath="..\..\blacklist.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_common\chap.c" + > + </File> + <File + RelativePath="..\..\..\src\utils\common.c" + > + </File> + <File + RelativePath="..\..\config.c" + > + </File> + <File + RelativePath="..\..\config_file.c" + > + </File> + <File + RelativePath="..\..\..\src\crypto\crypto_openssl.c" + > + </File> + <File + RelativePath="..\..\ctrl_iface.c" + > + </File> + <File + RelativePath="..\..\ctrl_iface_named_pipe.c" + > + </File> + <File + RelativePath="..\..\..\src\drivers\driver_ndis.c" + > + </File> + <File + RelativePath="..\..\..\src\drivers\driver_ndis_.c" + > + </File> + <File + RelativePath="..\..\..\src\drivers\drivers.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_common\eap_common.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_gtc.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_leap.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_md5.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_methods.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_mschapv2.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_otp.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_peap.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_common\eap_peap_common.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_tls.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_tls_common.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_tnc.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_ttls.c" + > + </File> + <File + RelativePath="..\..\..\src\eapol_supp\eapol_supp_sm.c" + > + </File> + <File + RelativePath="..\..\..\src\utils\eloop_win.c" + > + </File> + <File + RelativePath="..\..\events.c" + > + </File> + <File + RelativePath="..\..\..\src\l2_packet\l2_packet_winpcap.c" + > + </File> + <File + RelativePath="..\..\main.c" + > + </File> + <File + RelativePath="..\..\..\src\crypto\md4.c" + > + </File> + <File + RelativePath="..\..\..\src\crypto\md5.c" + > + </File> + <File + RelativePath="..\..\..\src\crypto\ms_funcs.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\mschapv2.c" + > + </File> + <File + RelativePath="..\..\..\src\drivers\ndis_events.c" + > + </File> + <File + RelativePath="..\..\..\src\utils\os_win32.c" + > + </File> + <File + RelativePath="..\..\..\src\utils\pcsc_funcs.c" + > + </File> + <File + RelativePath="..\..\..\src\rsn_supp\peerkey.c" + > + </File> + <File + RelativePath="..\..\..\src\rsn_supp\pmksa_cache.c" + > + </File> + <File + RelativePath="..\..\..\src\rsn_supp\preauth.c" + > + </File> + <File + RelativePath="..\..\..\src\crypto\rc4.c" + > + </File> + <File + RelativePath="..\..\scan.c" + > + </File> + <File + RelativePath="..\..\..\src\drivers\scan_helpers.c" + > + </File> + <File + RelativePath="..\..\..\src\crypto\sha1.c" + > + </File> + <File + RelativePath="..\..\..\src\crypto\tls_openssl.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\tncc.c" + > + </File> + <File + RelativePath="..\..\..\src\rsn_supp\wpa.c" + > + </File> + <File + RelativePath="..\..\..\src\common\wpa_common.c" + > + </File> + <File + RelativePath="..\..\..\src\utils\wpa_debug.c" + > + </File> + <File + RelativePath="..\..\..\src\rsn_supp\wpa_ie.c" + > + </File> + <File + RelativePath="..\..\wpa_supplicant.c" + > + </File> + <File + RelativePath="..\..\..\src\utils\wpabuf.c" + > + </File> + <File + RelativePath="..\..\wpas_glue.c" + > + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" + > + </Filter> + <Filter + Name="Resource Files" + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" + UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" + > + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj b/wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj new file mode 100755 index 000000000000..676f1446c8ba --- /dev/null +++ b/wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj @@ -0,0 +1,421 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="8.00" + Name="wpasvc" + ProjectGUID="{E2A4A85F-CA77-406D-8ABF-63EF94545ACC}" + RootNamespace="wpasvc" + Keyword="Win32Proj" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="0" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="..\..;..\..\..\src;..\..\..\src\utils;..\..\..\src\common;..\..\..\src\crypto;..\..\..\src\rsn_supp;C:\dev\WpdPack\include;C:\dev\openssl\include" + PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="3" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="4" + DisableSpecificWarnings="4244;4267;4311" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="wbemuuid.lib ws2_32.lib Crypt32.lib Winscard.lib Packet.lib wpcap.lib libeay32MT.lib ssleay32Mt.lib" + LinkIncremental="2" + AdditionalLibraryDirectories="C:\dev\WpdPack\lib;C:\dev\openssl\lib" + GenerateDebugInformation="true" + SubSystem="1" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="0" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="..\..;..\..\..\src;..\..\..\src\utils;..\..\..\src\common;..\..\..\src\crypto;..\..\..\src\rsn_supp;C:\dev\WpdPack\include;C:\dev\openssl\include" + PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS" + RuntimeLibrary="2" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + DisableSpecificWarnings="4244;4267;4311" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="wbemuuid.lib ws2_32.lib Crypt32.lib Winscard.lib Packet.lib wpcap.lib libeay32MT.lib ssleay32Mt.lib" + LinkIncremental="1" + AdditionalLibraryDirectories="C:\dev\WpdPack\lib;C:\dev\openssl\lib" + GenerateDebugInformation="true" + SubSystem="1" + OptimizeReferences="2" + EnableCOMDATFolding="2" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" + > + <File + RelativePath="..\..\..\src\crypto\aes_wrap.c" + > + </File> + <File + RelativePath="..\..\..\src\utils\base64.c" + > + </File> + <File + RelativePath="..\..\blacklist.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_common\chap.c" + > + </File> + <File + RelativePath="..\..\..\src\utils\common.c" + > + </File> + <File + RelativePath="..\..\config.c" + > + </File> + <File + RelativePath="..\..\config_winreg.c" + > + </File> + <File + RelativePath="..\..\..\src\crypto\crypto_openssl.c" + > + </File> + <File + RelativePath="..\..\ctrl_iface.c" + > + </File> + <File + RelativePath="..\..\ctrl_iface_named_pipe.c" + > + </File> + <File + RelativePath="..\..\..\src\drivers\driver_ndis.c" + > + </File> + <File + RelativePath="..\..\..\src\drivers\driver_ndis_.c" + > + </File> + <File + RelativePath="..\..\..\src\drivers\drivers.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_common\eap_common.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_gtc.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_leap.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_md5.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_methods.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_mschapv2.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_otp.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_peap.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_common\eap_peap_common.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_tls.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_tls_common.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_tnc.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\eap_ttls.c" + > + </File> + <File + RelativePath="..\..\..\src\eapol_supp\eapol_supp_sm.c" + > + </File> + <File + RelativePath="..\..\..\src\utils\eloop_win.c" + > + </File> + <File + RelativePath="..\..\events.c" + > + </File> + <File + RelativePath="..\..\..\src\l2_packet\l2_packet_winpcap.c" + > + </File> + <File + RelativePath="..\..\main_winsvc.c" + > + </File> + <File + RelativePath="..\..\..\src\crypto\md4.c" + > + </File> + <File + RelativePath="..\..\..\src\crypto\md5.c" + > + </File> + <File + RelativePath="..\..\..\src\crypto\ms_funcs.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\mschapv2.c" + > + </File> + <File + RelativePath="..\..\..\src\drivers\ndis_events.c" + > + </File> + <File + RelativePath="..\..\..\src\utils\os_win32.c" + > + </File> + <File + RelativePath="..\..\..\src\utils\pcsc_funcs.c" + > + </File> + <File + RelativePath="..\..\..\src\rsn_supp\peerkey.c" + > + </File> + <File + RelativePath="..\..\..\src\rsn_supp\pmksa_cache.c" + > + </File> + <File + RelativePath="..\..\..\src\rsn_supp\preauth.c" + > + </File> + <File + RelativePath="..\..\..\src\crypto\rc4.c" + > + </File> + <File + RelativePath="..\..\scan.c" + > + </File> + <File + RelativePath="..\..\..\src\drivers\scan_helpers.c" + > + </File> + <File + RelativePath="..\..\..\src\crypto\sha1.c" + > + </File> + <File + RelativePath="..\..\..\src\crypto\tls_openssl.c" + > + </File> + <File + RelativePath="..\..\..\src\eap_peer\tncc.c" + > + </File> + <File + RelativePath="..\..\..\src\rsn_supp\wpa.c" + > + </File> + <File + RelativePath="..\..\..\src\common\wpa_common.c" + > + </File> + <File + RelativePath="..\..\..\src\utils\wpa_debug.c" + > + </File> + <File + RelativePath="..\..\..\src\rsn_supp\wpa_ie.c" + > + </File> + <File + RelativePath="..\..\wpa_supplicant.c" + > + </File> + <File + RelativePath="..\..\..\src\utils\wpabuf.c" + > + </File> + <File + RelativePath="..\..\wpas_glue.c" + > + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" + > + </Filter> + <Filter + Name="Resource Files" + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" + UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" + > + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/wpa_supplicant/win_example.reg b/wpa_supplicant/win_example.reg new file mode 100755 index 000000000000..6e42037e143c --- /dev/null +++ b/wpa_supplicant/win_example.reg @@ -0,0 +1,42 @@ +REGEDIT4 + +[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant] +"debug_level"=dword:00000000 +"debug_show_keys"=dword:00000001 +"debug_timestamp"=dword:00000000 +"debug_use_file"=dword:00000000 + +[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs] + +[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test] +"ap_scan"=dword:00000002 +"update_config"=dword:00000001 +"uuid"="12345678-9abc-def0-1234-56789abcdef0" +"device_name"="Wireless Client" +"manufacturer"="Company" +"model_name"="cmodel" +"serial_number"="12345" +"device_type"="1-0050F204-1" +"os_version"="01020300" + +[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\blobs] +"testblob"=hex:01,02,03,04,05 + +[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\networks] + +[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\networks\0000] +"ssid"="\"example network\"" +"key_mgmt"="WPA-PSK" +"psk"="\"secret password\"" +"pairwise"="CCMP" +"group"="CCMP" +"proto"="WPA" + +[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\interfaces] + +[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\interfaces\0000] +"adapter"="{A7627643-C310-49E5-BD89-7E77709C04AB}" +"config"="test" +"ctrl_interface"="" +"skip_on_error"=dword:00000000 + diff --git a/wpa_supplicant/win_if_list.c b/wpa_supplicant/win_if_list.c new file mode 100644 index 000000000000..0e1532ed71f1 --- /dev/null +++ b/wpa_supplicant/win_if_list.c @@ -0,0 +1,179 @@ +/* + * win_if_list - Display network interfaces with description (for Windows) + * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + * + * This small tool is for the Windows build to provide an easy way of fetching + * a list of available network interfaces. + */ + +#include "includes.h" +#include <stdio.h> +#ifdef CONFIG_USE_NDISUIO +#include <winsock2.h> +#include <ntddndis.h> +#else /* CONFIG_USE_NDISUIO */ +#include "pcap.h" +#include <winsock.h> +#endif /* CONFIG_USE_NDISUIO */ + +#ifdef CONFIG_USE_NDISUIO + +/* from nuiouser.h */ +#define FSCTL_NDISUIO_BASE FILE_DEVICE_NETWORK + +#define _NDISUIO_CTL_CODE(_Function, _Method, _Access) \ + CTL_CODE(FSCTL_NDISUIO_BASE, _Function, _Method, _Access) + +#define IOCTL_NDISUIO_QUERY_BINDING \ + _NDISUIO_CTL_CODE(0x203, METHOD_BUFFERED, \ + FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +#define IOCTL_NDISUIO_BIND_WAIT \ + _NDISUIO_CTL_CODE(0x204, METHOD_BUFFERED, \ + FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +typedef struct _NDISUIO_QUERY_BINDING +{ + ULONG BindingIndex; + ULONG DeviceNameOffset; + ULONG DeviceNameLength; + ULONG DeviceDescrOffset; + ULONG DeviceDescrLength; +} NDISUIO_QUERY_BINDING, *PNDISUIO_QUERY_BINDING; + + +static HANDLE ndisuio_open(void) +{ + DWORD written; + HANDLE h; + + h = CreateFile(TEXT("\\\\.\\\\Ndisuio"), + GENERIC_READ | GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, + INVALID_HANDLE_VALUE); + if (h == INVALID_HANDLE_VALUE) + return h; + +#ifndef _WIN32_WCE + if (!DeviceIoControl(h, IOCTL_NDISUIO_BIND_WAIT, NULL, 0, NULL, 0, + &written, NULL)) { + printf("IOCTL_NDISUIO_BIND_WAIT failed: %d", + (int) GetLastError()); + CloseHandle(h); + return INVALID_HANDLE_VALUE; + } +#endif /* _WIN32_WCE */ + + return h; +} + + +static void ndisuio_query_bindings(HANDLE ndisuio) +{ + NDISUIO_QUERY_BINDING *b; + size_t blen = sizeof(*b) + 1024; + int i, error; + DWORD written; + char name[256], desc[256]; + WCHAR *pos; + size_t j, len; + + b = malloc(blen); + if (b == NULL) + return; + + for (i = 0; ; i++) { + memset(b, 0, blen); + b->BindingIndex = i; + if (!DeviceIoControl(ndisuio, IOCTL_NDISUIO_QUERY_BINDING, + b, sizeof(NDISUIO_QUERY_BINDING), b, + (DWORD) blen, &written, NULL)) { + error = (int) GetLastError(); + if (error == ERROR_NO_MORE_ITEMS) + break; + printf("IOCTL_NDISUIO_QUERY_BINDING failed: %d", + error); + break; + } + + pos = (WCHAR *) ((char *) b + b->DeviceNameOffset); + len = b->DeviceNameLength; + if (len >= sizeof(name)) + len = sizeof(name) - 1; + for (j = 0; j < len; j++) + name[j] = (char) pos[j]; + name[len] = '\0'; + + pos = (WCHAR *) ((char *) b + b->DeviceDescrOffset); + len = b->DeviceDescrLength; + if (len >= sizeof(desc)) + len = sizeof(desc) - 1; + for (j = 0; j < len; j++) + desc[j] = (char) pos[j]; + desc[len] = '\0'; + + printf("ifname: %s\ndescription: %s\n\n", name, desc); + } + + free(b); +} + + +static void ndisuio_enum_bindings(void) +{ + HANDLE ndisuio = ndisuio_open(); + if (ndisuio == INVALID_HANDLE_VALUE) + return; + + ndisuio_query_bindings(ndisuio); + CloseHandle(ndisuio); +} + +#else /* CONFIG_USE_NDISUIO */ + +static void show_dev(pcap_if_t *dev) +{ + printf("ifname: %s\ndescription: %s\n\n", + dev->name, dev->description); +} + + +static void pcap_enum_devs(void) +{ + pcap_if_t *devs, *dev; + char err[PCAP_ERRBUF_SIZE + 1]; + + if (pcap_findalldevs(&devs, err) < 0) { + fprintf(stderr, "Error - pcap_findalldevs: %s\n", err); + return; + } + + for (dev = devs; dev; dev = dev->next) { + show_dev(dev); + } + + pcap_freealldevs(devs); +} + +#endif /* CONFIG_USE_NDISUIO */ + + +int main(int argc, char *argv[]) +{ +#ifdef CONFIG_USE_NDISUIO + ndisuio_enum_bindings(); +#else /* CONFIG_USE_NDISUIO */ + pcap_enum_devs(); +#endif /* CONFIG_USE_NDISUIO */ + + return 0; +} diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c new file mode 100644 index 000000000000..7de65348cb79 --- /dev/null +++ b/wpa_supplicant/wpa_cli.c @@ -0,0 +1,1921 @@ +/* + * WPA Supplicant - command line interface for wpa_supplicant daemon + * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#ifdef CONFIG_CTRL_IFACE + +#ifdef CONFIG_CTRL_IFACE_UNIX +#include <dirent.h> +#endif /* CONFIG_CTRL_IFACE_UNIX */ +#ifdef CONFIG_READLINE +#include <readline/readline.h> +#include <readline/history.h> +#endif /* CONFIG_READLINE */ + +#include "wpa_ctrl.h" +#include "common.h" +#include "version.h" + + +static const char *wpa_cli_version = +"wpa_cli v" VERSION_STR "\n" +"Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi> and contributors"; + + +static const char *wpa_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 *wpa_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 struct wpa_ctrl *ctrl_conn; +static int wpa_cli_quit = 0; +static int wpa_cli_attached = 0; +static int wpa_cli_connected = 0; +static int wpa_cli_last_id = 0; +static const char *ctrl_iface_dir = "/var/run/wpa_supplicant"; +static char *ctrl_ifname = NULL; +static const char *pid_file = NULL; +static const char *action_file = NULL; +static int ping_interval = 5; + + +static void print_help(); + + +static void usage(void) +{ + printf("wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hvB] " + "[-a<action file>] \\\n" + " [-P<pid file>] [-g<global ctrl>] [-G<ping interval>] " + "[command..]\n" + " -h = help (show this usage text)\n" + " -v = shown version information\n" + " -a = run in daemon mode executing the action file based on " + "events from\n" + " wpa_supplicant\n" + " -B = run a daemon in the background\n" + " default path: /var/run/wpa_supplicant\n" + " default interface: first interface found in socket path\n"); + print_help(); +} + + +static struct wpa_ctrl * wpa_cli_open_connection(const char *ifname) +{ +#if defined(CONFIG_CTRL_IFACE_UDP) || defined(CONFIG_CTRL_IFACE_NAMED_PIPE) + ctrl_conn = wpa_ctrl_open(ifname); + return ctrl_conn; +#else /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */ + char *cfile; + int flen, res; + + if (ifname == NULL) + return NULL; + + flen = os_strlen(ctrl_iface_dir) + os_strlen(ifname) + 2; + cfile = os_malloc(flen); + if (cfile == NULL) + return NULL; + res = os_snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname); + if (res < 0 || res >= flen) { + os_free(cfile); + return NULL; + } + + ctrl_conn = wpa_ctrl_open(cfile); + os_free(cfile); + return ctrl_conn; +#endif /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */ +} + + +static void wpa_cli_close_connection(void) +{ + if (ctrl_conn == NULL) + return; + + if (wpa_cli_attached) { + wpa_ctrl_detach(ctrl_conn); + wpa_cli_attached = 0; + } + wpa_ctrl_close(ctrl_conn); + ctrl_conn = NULL; +} + + +static void wpa_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[2048]; + size_t len; + int ret; + + if (ctrl_conn == NULL) { + printf("Not connected to wpa_supplicant - command dropped.\n"); + return -1; + } + len = sizeof(buf) - 1; + ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, + wpa_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 int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd) +{ + return _wpa_ctrl_command(ctrl, cmd, 1); +} + + +static int wpa_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + int verbose = argc > 0 && os_strcmp(argv[0], "verbose") == 0; + return wpa_ctrl_command(ctrl, verbose ? "STATUS-VERBOSE" : "STATUS"); +} + + +static int wpa_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "PING"); +} + + +static int wpa_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "MIB"); +} + + +static int wpa_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "PMKSA"); +} + + +static int wpa_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + print_help(); + return 0; +} + + +static int wpa_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + printf("%s\n\n%s\n", wpa_cli_version, wpa_cli_full_license); + return 0; +} + + +static int wpa_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + wpa_cli_quit = 1; + return 0; +} + + +static void wpa_cli_show_variables(void) +{ + printf("set variables:\n" + " EAPOL::heldPeriod (EAPOL state machine held period, " + "in seconds)\n" + " EAPOL::authPeriod (EAPOL state machine authentication " + "period, in seconds)\n" + " EAPOL::startPeriod (EAPOL state machine start period, in " + "seconds)\n" + " EAPOL::maxStart (EAPOL state machine maximum start " + "attempts)\n"); + printf(" dot11RSNAConfigPMKLifetime (WPA/WPA2 PMK lifetime in " + "seconds)\n" + " dot11RSNAConfigPMKReauthThreshold (WPA/WPA2 reauthentication" + " threshold\n\tpercentage)\n" + " dot11RSNAConfigSATimeout (WPA/WPA2 timeout for completing " + "security\n\tassociation in seconds)\n"); +} + + +static int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + char cmd[256]; + int res; + + if (argc == 0) { + wpa_cli_show_variables(); + return 0; + } + + if (argc != 2) { + printf("Invalid SET command: needs two arguments (variable " + "name and value)\n"); + return -1; + } + + res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]); + if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { + printf("Too long SET command.\n"); + return -1; + } + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_logoff(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "LOGOFF"); +} + + +static int wpa_cli_cmd_logon(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "LOGON"); +} + + +static int wpa_cli_cmd_reassociate(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "REASSOCIATE"); +} + + +static int wpa_cli_cmd_preauthenticate(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[256]; + int res; + + if (argc != 1) { + printf("Invalid PREAUTH command: needs one argument " + "(BSSID)\n"); + return -1; + } + + res = os_snprintf(cmd, sizeof(cmd), "PREAUTH %s", argv[0]); + if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { + printf("Too long PREAUTH command.\n"); + return -1; + } + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_ap_scan(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + char cmd[256]; + int res; + + if (argc != 1) { + printf("Invalid AP_SCAN command: needs one argument (ap_scan " + "value)\n"); + return -1; + } + res = os_snprintf(cmd, sizeof(cmd), "AP_SCAN %s", argv[0]); + if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { + printf("Too long AP_SCAN command.\n"); + return -1; + } + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_stkstart(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[256]; + int res; + + if (argc != 1) { + printf("Invalid STKSTART command: needs one argument " + "(Peer STA MAC address)\n"); + return -1; + } + + res = os_snprintf(cmd, sizeof(cmd), "STKSTART %s", argv[0]); + if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { + printf("Too long STKSTART command.\n"); + return -1; + } + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_ft_ds(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + char cmd[256]; + int res; + + if (argc != 1) { + printf("Invalid FT_DS command: needs one argument " + "(Target AP MAC address)\n"); + return -1; + } + + res = os_snprintf(cmd, sizeof(cmd), "FT_DS %s", argv[0]); + if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { + printf("Too long FT_DS command.\n"); + return -1; + } + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + char cmd[256]; + int res; + + if (argc == 0) { + /* Any BSSID */ + return wpa_ctrl_command(ctrl, "WPS_PBC"); + } + + /* Specific BSSID */ + res = os_snprintf(cmd, sizeof(cmd), "WPS_PBC %s", argv[0]); + if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { + printf("Too long WPS_PBC command.\n"); + return -1; + } + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + char cmd[256]; + int res; + + if (argc == 0) { + printf("Invalid WPS_PIN command: need one or two arguments:\n" + "- BSSID: use 'any' to select any\n" + "- PIN: optional, used only with devices that have no " + "display\n"); + return -1; + } + + if (argc == 1) { + /* Use dynamically generated PIN (returned as reply) */ + res = os_snprintf(cmd, sizeof(cmd), "WPS_PIN %s", argv[0]); + if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { + printf("Too long WPS_PIN command.\n"); + return -1; + } + return wpa_ctrl_command(ctrl, cmd); + } + + /* Use hardcoded PIN from a label */ + res = os_snprintf(cmd, sizeof(cmd), "WPS_PIN %s %s", argv[0], argv[1]); + if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { + printf("Too long WPS_PIN command.\n"); + return -1; + } + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + char cmd[256]; + int res; + + if (argc != 2) { + printf("Invalid WPS_REG command: need two arguments:\n" + "- BSSID: use 'any' to select any\n" + "- AP PIN\n"); + return -1; + } + + res = os_snprintf(cmd, sizeof(cmd), "WPS_REG %s %s", argv[0], argv[1]); + if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { + printf("Too long WPS_REG command.\n"); + return -1; + } + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + char cmd[256]; + int res; + + if (argc != 1) { + printf("Invalid LEVEL command: needs one argument (debug " + "level)\n"); + return -1; + } + res = os_snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]); + if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { + printf("Too long LEVEL command.\n"); + return -1; + } + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_identity(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + char cmd[256], *pos, *end; + int i, ret; + + if (argc < 2) { + printf("Invalid IDENTITY command: needs two arguments " + "(network id and identity)\n"); + return -1; + } + + end = cmd + sizeof(cmd); + pos = cmd; + ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "IDENTITY-%s:%s", + argv[0], argv[1]); + if (ret < 0 || ret >= end - pos) { + printf("Too long IDENTITY command.\n"); + return -1; + } + pos += ret; + for (i = 2; i < argc; i++) { + ret = os_snprintf(pos, end - pos, " %s", argv[i]); + if (ret < 0 || ret >= end - pos) { + printf("Too long IDENTITY command.\n"); + return -1; + } + pos += ret; + } + + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_password(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + char cmd[256], *pos, *end; + int i, ret; + + if (argc < 2) { + printf("Invalid PASSWORD command: needs two arguments " + "(network id and password)\n"); + return -1; + } + + end = cmd + sizeof(cmd); + pos = cmd; + ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSWORD-%s:%s", + argv[0], argv[1]); + if (ret < 0 || ret >= end - pos) { + printf("Too long PASSWORD command.\n"); + return -1; + } + pos += ret; + for (i = 2; i < argc; i++) { + ret = os_snprintf(pos, end - pos, " %s", argv[i]); + if (ret < 0 || ret >= end - pos) { + printf("Too long PASSWORD command.\n"); + return -1; + } + pos += ret; + } + + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_new_password(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[256], *pos, *end; + int i, ret; + + if (argc < 2) { + printf("Invalid NEW_PASSWORD command: needs two arguments " + "(network id and password)\n"); + return -1; + } + + end = cmd + sizeof(cmd); + pos = cmd; + ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "NEW_PASSWORD-%s:%s", + argv[0], argv[1]); + if (ret < 0 || ret >= end - pos) { + printf("Too long NEW_PASSWORD command.\n"); + return -1; + } + pos += ret; + for (i = 2; i < argc; i++) { + ret = os_snprintf(pos, end - pos, " %s", argv[i]); + if (ret < 0 || ret >= end - pos) { + printf("Too long NEW_PASSWORD command.\n"); + return -1; + } + pos += ret; + } + + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_pin(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + char cmd[256], *pos, *end; + int i, ret; + + if (argc < 2) { + printf("Invalid PIN command: needs two arguments " + "(network id and pin)\n"); + return -1; + } + + end = cmd + sizeof(cmd); + pos = cmd; + ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PIN-%s:%s", + argv[0], argv[1]); + if (ret < 0 || ret >= end - pos) { + printf("Too long PIN command.\n"); + return -1; + } + pos += ret; + for (i = 2; i < argc; i++) { + ret = os_snprintf(pos, end - pos, " %s", argv[i]); + if (ret < 0 || ret >= end - pos) { + printf("Too long PIN command.\n"); + return -1; + } + pos += ret; + } + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_otp(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + char cmd[256], *pos, *end; + int i, ret; + + if (argc < 2) { + printf("Invalid OTP command: needs two arguments (network " + "id and password)\n"); + return -1; + } + + end = cmd + sizeof(cmd); + pos = cmd; + ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "OTP-%s:%s", + argv[0], argv[1]); + if (ret < 0 || ret >= end - pos) { + printf("Too long OTP command.\n"); + return -1; + } + pos += ret; + for (i = 2; i < argc; i++) { + ret = os_snprintf(pos, end - pos, " %s", argv[i]); + if (ret < 0 || ret >= end - pos) { + printf("Too long OTP command.\n"); + return -1; + } + pos += ret; + } + + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[256], *pos, *end; + int i, ret; + + if (argc < 2) { + printf("Invalid PASSPHRASE command: needs two arguments " + "(network id and passphrase)\n"); + return -1; + } + + end = cmd + sizeof(cmd); + pos = cmd; + ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSPHRASE-%s:%s", + argv[0], argv[1]); + if (ret < 0 || ret >= end - pos) { + printf("Too long PASSPHRASE command.\n"); + return -1; + } + pos += ret; + for (i = 2; i < argc; i++) { + ret = os_snprintf(pos, end - pos, " %s", argv[i]); + if (ret < 0 || ret >= end - pos) { + printf("Too long PASSPHRASE command.\n"); + return -1; + } + pos += ret; + } + + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_bssid(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + char cmd[256], *pos, *end; + int i, ret; + + if (argc < 2) { + printf("Invalid BSSID command: needs two arguments (network " + "id and BSSID)\n"); + return -1; + } + + end = cmd + sizeof(cmd); + pos = cmd; + ret = os_snprintf(pos, end - pos, "BSSID"); + if (ret < 0 || ret >= end - pos) { + printf("Too long BSSID command.\n"); + return -1; + } + pos += ret; + for (i = 0; i < argc; i++) { + ret = os_snprintf(pos, end - pos, " %s", argv[i]); + if (ret < 0 || ret >= end - pos) { + printf("Too long BSSID command.\n"); + return -1; + } + pos += ret; + } + + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_list_networks(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "LIST_NETWORKS"); +} + + +static int wpa_cli_cmd_select_network(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[32]; + int res; + + if (argc < 1) { + printf("Invalid SELECT_NETWORK command: needs one argument " + "(network id)\n"); + return -1; + } + + res = os_snprintf(cmd, sizeof(cmd), "SELECT_NETWORK %s", argv[0]); + if (res < 0 || (size_t) res >= sizeof(cmd)) + return -1; + cmd[sizeof(cmd) - 1] = '\0'; + + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_enable_network(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[32]; + int res; + + if (argc < 1) { + printf("Invalid ENABLE_NETWORK command: needs one argument " + "(network id)\n"); + return -1; + } + + res = os_snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %s", argv[0]); + if (res < 0 || (size_t) res >= sizeof(cmd)) + return -1; + cmd[sizeof(cmd) - 1] = '\0'; + + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_disable_network(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[32]; + int res; + + if (argc < 1) { + printf("Invalid DISABLE_NETWORK command: needs one argument " + "(network id)\n"); + return -1; + } + + res = os_snprintf(cmd, sizeof(cmd), "DISABLE_NETWORK %s", argv[0]); + if (res < 0 || (size_t) res >= sizeof(cmd)) + return -1; + cmd[sizeof(cmd) - 1] = '\0'; + + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_add_network(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "ADD_NETWORK"); +} + + +static int wpa_cli_cmd_remove_network(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[32]; + int res; + + if (argc < 1) { + printf("Invalid REMOVE_NETWORK command: needs one argument " + "(network id)\n"); + return -1; + } + + res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %s", argv[0]); + if (res < 0 || (size_t) res >= sizeof(cmd)) + return -1; + cmd[sizeof(cmd) - 1] = '\0'; + + return wpa_ctrl_command(ctrl, cmd); +} + + +static void wpa_cli_show_network_variables(void) +{ + printf("set_network variables:\n" + " ssid (network name, SSID)\n" + " psk (WPA passphrase or pre-shared key)\n" + " key_mgmt (key management protocol)\n" + " identity (EAP identity)\n" + " password (EAP password)\n" + " ...\n" + "\n" + "Note: Values are entered in the same format as the " + "configuration file is using,\n" + "i.e., strings values need to be inside double quotation " + "marks.\n" + "For example: set_network 1 ssid \"network name\"\n" + "\n" + "Please see wpa_supplicant.conf documentation for full list " + "of\navailable variables.\n"); +} + + +static int wpa_cli_cmd_set_network(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[256]; + int res; + + if (argc == 0) { + wpa_cli_show_network_variables(); + return 0; + } + + if (argc != 3) { + printf("Invalid SET_NETWORK command: needs three arguments\n" + "(network id, variable name, and value)\n"); + return -1; + } + + res = os_snprintf(cmd, sizeof(cmd), "SET_NETWORK %s %s %s", + argv[0], argv[1], argv[2]); + if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { + printf("Too long SET_NETWORK command.\n"); + return -1; + } + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[256]; + int res; + + if (argc == 0) { + wpa_cli_show_network_variables(); + return 0; + } + + if (argc != 2) { + printf("Invalid GET_NETWORK command: needs two arguments\n" + "(network id and variable name)\n"); + return -1; + } + + res = os_snprintf(cmd, sizeof(cmd), "GET_NETWORK %s %s", + argv[0], argv[1]); + if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { + printf("Too long GET_NETWORK command.\n"); + return -1; + } + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_disconnect(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "DISCONNECT"); +} + + +static int wpa_cli_cmd_reconnect(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "RECONNECT"); +} + + +static int wpa_cli_cmd_save_config(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "SAVE_CONFIG"); +} + + +static int wpa_cli_cmd_scan(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "SCAN"); +} + + +static int wpa_cli_cmd_scan_results(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "SCAN_RESULTS"); +} + + +static int wpa_cli_cmd_bss(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + char cmd[64]; + int res; + + if (argc != 1) { + printf("Invalid BSS command: need one argument (index or " + "BSSID)\n"); + return -1; + } + + res = os_snprintf(cmd, sizeof(cmd), "BSS %s", argv[0]); + if (res < 0 || (size_t) res >= sizeof(cmd)) + return -1; + cmd[sizeof(cmd) - 1] = '\0'; + + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[64]; + int res; + + if (argc < 1 || argc > 2) { + printf("Invalid GET_CAPABILITY command: need either one or " + "two arguments\n"); + return -1; + } + + if ((argc == 2) && os_strcmp(argv[1], "strict") != 0) { + printf("Invalid GET_CAPABILITY command: second argument, " + "if any, must be 'strict'\n"); + return -1; + } + + res = os_snprintf(cmd, sizeof(cmd), "GET_CAPABILITY %s%s", argv[0], + (argc == 2) ? " strict" : ""); + if (res < 0 || (size_t) res >= sizeof(cmd)) + return -1; + cmd[sizeof(cmd) - 1] = '\0'; + + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_list_interfaces(struct wpa_ctrl *ctrl) +{ + printf("Available interfaces:\n"); + return wpa_ctrl_command(ctrl, "INTERFACES"); +} + + +static int wpa_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + if (argc < 1) { + wpa_cli_list_interfaces(ctrl); + return 0; + } + + wpa_cli_close_connection(); + os_free(ctrl_ifname); + ctrl_ifname = os_strdup(argv[0]); + + if (wpa_cli_open_connection(ctrl_ifname)) { + printf("Connected to interface '%s.\n", ctrl_ifname); + if (wpa_ctrl_attach(ctrl_conn) == 0) { + wpa_cli_attached = 1; + } else { + printf("Warning: Failed to attach to " + "wpa_supplicant.\n"); + } + } else { + printf("Could not connect to interface '%s' - re-trying\n", + ctrl_ifname); + } + return 0; +} + + +static int wpa_cli_cmd_reconfigure(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "RECONFIGURE"); +} + + +static int wpa_cli_cmd_terminate(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "TERMINATE"); +} + + +static int wpa_cli_cmd_interface_add(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[256]; + int res; + + if (argc < 1) { + printf("Invalid INTERFACE_ADD command: needs at least one " + "argument (interface name)\n" + "All arguments: ifname confname driver ctrl_interface " + "driver_param bridge_name\n"); + return -1; + } + + /* + * INTERFACE_ADD <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB + * <driver_param>TAB<bridge_name> + */ + res = os_snprintf(cmd, sizeof(cmd), + "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s", + argv[0], + argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : "", + argc > 3 ? argv[3] : "", argc > 4 ? argv[4] : "", + argc > 5 ? argv[5] : ""); + if (res < 0 || (size_t) res >= sizeof(cmd)) + return -1; + cmd[sizeof(cmd) - 1] = '\0'; + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_interface_remove(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[128]; + int res; + + if (argc != 1) { + printf("Invalid INTERFACE_REMOVE command: needs one argument " + "(interface name)\n"); + return -1; + } + + res = os_snprintf(cmd, sizeof(cmd), "INTERFACE_REMOVE %s", argv[0]); + if (res < 0 || (size_t) res >= sizeof(cmd)) + return -1; + cmd[sizeof(cmd) - 1] = '\0'; + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_interface_list(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "INTERFACE_LIST"); +} + + +enum wpa_cli_cmd_flags { + cli_cmd_flag_none = 0x00, + cli_cmd_flag_sensitive = 0x01 +}; + +struct wpa_cli_cmd { + const char *cmd; + int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]); + enum wpa_cli_cmd_flags flags; + const char *usage; +}; + +static struct wpa_cli_cmd wpa_cli_commands[] = { + { "status", wpa_cli_cmd_status, + cli_cmd_flag_none, + "[verbose] = get current WPA/EAPOL/EAP status" }, + { "ping", wpa_cli_cmd_ping, + cli_cmd_flag_none, + "= pings wpa_supplicant" }, + { "mib", wpa_cli_cmd_mib, + cli_cmd_flag_none, + "= get MIB variables (dot1x, dot11)" }, + { "help", wpa_cli_cmd_help, + cli_cmd_flag_none, + "= show this usage help" }, + { "interface", wpa_cli_cmd_interface, + cli_cmd_flag_none, + "[ifname] = show interfaces/select interface" }, + { "level", wpa_cli_cmd_level, + cli_cmd_flag_none, + "<debug level> = change debug level" }, + { "license", wpa_cli_cmd_license, + cli_cmd_flag_none, + "= show full wpa_cli license" }, + { "quit", wpa_cli_cmd_quit, + cli_cmd_flag_none, + "= exit wpa_cli" }, + { "set", wpa_cli_cmd_set, + cli_cmd_flag_none, + "= set variables (shows list of variables when run without " + "arguments)" }, + { "logon", wpa_cli_cmd_logon, + cli_cmd_flag_none, + "= IEEE 802.1X EAPOL state machine logon" }, + { "logoff", wpa_cli_cmd_logoff, + cli_cmd_flag_none, + "= IEEE 802.1X EAPOL state machine logoff" }, + { "pmksa", wpa_cli_cmd_pmksa, + cli_cmd_flag_none, + "= show PMKSA cache" }, + { "reassociate", wpa_cli_cmd_reassociate, + cli_cmd_flag_none, + "= force reassociation" }, + { "preauthenticate", wpa_cli_cmd_preauthenticate, + cli_cmd_flag_none, + "<BSSID> = force preauthentication" }, + { "identity", wpa_cli_cmd_identity, + cli_cmd_flag_none, + "<network id> <identity> = configure identity for an SSID" }, + { "password", wpa_cli_cmd_password, + cli_cmd_flag_sensitive, + "<network id> <password> = configure password for an SSID" }, + { "new_password", wpa_cli_cmd_new_password, + cli_cmd_flag_sensitive, + "<network id> <password> = change password for an SSID" }, + { "pin", wpa_cli_cmd_pin, + cli_cmd_flag_sensitive, + "<network id> <pin> = configure pin for an SSID" }, + { "otp", wpa_cli_cmd_otp, + cli_cmd_flag_sensitive, + "<network id> <password> = configure one-time-password for an SSID" + }, + { "passphrase", wpa_cli_cmd_passphrase, + cli_cmd_flag_sensitive, + "<network id> <passphrase> = configure private key passphrase\n" + " for an SSID" }, + { "bssid", wpa_cli_cmd_bssid, + cli_cmd_flag_none, + "<network id> <BSSID> = set preferred BSSID for an SSID" }, + { "list_networks", wpa_cli_cmd_list_networks, + cli_cmd_flag_none, + "= list configured networks" }, + { "select_network", wpa_cli_cmd_select_network, + cli_cmd_flag_none, + "<network id> = select a network (disable others)" }, + { "enable_network", wpa_cli_cmd_enable_network, + cli_cmd_flag_none, + "<network id> = enable a network" }, + { "disable_network", wpa_cli_cmd_disable_network, + cli_cmd_flag_none, + "<network id> = disable a network" }, + { "add_network", wpa_cli_cmd_add_network, + cli_cmd_flag_none, + "= add a network" }, + { "remove_network", wpa_cli_cmd_remove_network, + cli_cmd_flag_none, + "<network id> = remove a network" }, + { "set_network", wpa_cli_cmd_set_network, + cli_cmd_flag_sensitive, + "<network id> <variable> <value> = set network variables (shows\n" + " list of variables when run without arguments)" }, + { "get_network", wpa_cli_cmd_get_network, + cli_cmd_flag_none, + "<network id> <variable> = get network variables" }, + { "save_config", wpa_cli_cmd_save_config, + cli_cmd_flag_none, + "= save the current configuration" }, + { "disconnect", wpa_cli_cmd_disconnect, + cli_cmd_flag_none, + "= disconnect and wait for reassociate/reconnect command before\n" + " connecting" }, + { "reconnect", wpa_cli_cmd_reconnect, + cli_cmd_flag_none, + "= like reassociate, but only takes effect if already disconnected" + }, + { "scan", wpa_cli_cmd_scan, + cli_cmd_flag_none, + "= request new BSS scan" }, + { "scan_results", wpa_cli_cmd_scan_results, + cli_cmd_flag_none, + "= get latest scan results" }, + { "bss", wpa_cli_cmd_bss, + cli_cmd_flag_none, + "<<idx> | <bssid>> = get detailed scan result info" }, + { "get_capability", wpa_cli_cmd_get_capability, + cli_cmd_flag_none, + "<eap/pairwise/group/key_mgmt/proto/auth_alg> = get capabilies" }, + { "reconfigure", wpa_cli_cmd_reconfigure, + cli_cmd_flag_none, + "= force wpa_supplicant to re-read its configuration file" }, + { "terminate", wpa_cli_cmd_terminate, + cli_cmd_flag_none, + "= terminate wpa_supplicant" }, + { "interface_add", wpa_cli_cmd_interface_add, + cli_cmd_flag_none, + "<ifname> <confname> <driver> <ctrl_interface> <driver_param>\n" + " <bridge_name> = adds new interface, all parameters but <ifname>\n" + " are optional" }, + { "interface_remove", wpa_cli_cmd_interface_remove, + cli_cmd_flag_none, + "<ifname> = removes the interface" }, + { "interface_list", wpa_cli_cmd_interface_list, + cli_cmd_flag_none, + "= list available interfaces" }, + { "ap_scan", wpa_cli_cmd_ap_scan, + cli_cmd_flag_none, + "<value> = set ap_scan parameter" }, + { "stkstart", wpa_cli_cmd_stkstart, + cli_cmd_flag_none, + "<addr> = request STK negotiation with <addr>" }, + { "ft_ds", wpa_cli_cmd_ft_ds, + cli_cmd_flag_none, + "<addr> = request over-the-DS FT with <addr>" }, + { "wps_pbc", wpa_cli_cmd_wps_pbc, + cli_cmd_flag_none, + "[BSSID] = start Wi-Fi Protected Setup: Push Button Configuration" }, + { "wps_pin", wpa_cli_cmd_wps_pin, + cli_cmd_flag_sensitive, + "<BSSID> [PIN] = start WPS PIN method (returns PIN, if not " + "hardcoded)" }, + { "wps_reg", wpa_cli_cmd_wps_reg, + cli_cmd_flag_sensitive, + "<BSSID> <AP PIN> = start WPS Registrar to configure an AP" }, + { NULL, NULL, cli_cmd_flag_none, NULL } +}; + + +/* + * Prints command usage, lines are padded with the specified string. + */ +static void print_cmd_help(struct wpa_cli_cmd *cmd, const char *pad) +{ + char c; + size_t n; + + printf("%s%s ", pad, cmd->cmd); + for (n = 0; (c = cmd->usage[n]); n++) { + printf("%c", c); + if (c == '\n') + printf("%s", pad); + } + printf("\n"); +} + + +static void print_help(void) +{ + int n; + printf("commands:\n"); + for (n = 0; wpa_cli_commands[n].cmd; n++) + print_cmd_help(&wpa_cli_commands[n], " "); +} + + +#ifdef CONFIG_READLINE +static int cmd_has_sensitive_data(const char *cmd) +{ + const char *c, *delim; + int n; + size_t len; + + delim = os_strchr(cmd, ' '); + if (delim) + len = delim - cmd; + else + len = os_strlen(cmd); + + for (n = 0; (c = wpa_cli_commands[n].cmd); n++) { + if (os_strncasecmp(cmd, c, len) == 0 && len == os_strlen(c)) + return (wpa_cli_commands[n].flags & + cli_cmd_flag_sensitive); + } + return 0; +} +#endif /* CONFIG_READLINE */ + + +static int wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + struct wpa_cli_cmd *cmd, *match = NULL; + int count; + int ret = 0; + + count = 0; + cmd = wpa_cli_commands; + while (cmd->cmd) { + if (os_strncasecmp(cmd->cmd, argv[0], os_strlen(argv[0])) == 0) + { + match = cmd; + if (os_strcasecmp(cmd->cmd, argv[0]) == 0) { + /* we have an exact match */ + count = 1; + break; + } + count++; + } + cmd++; + } + + if (count > 1) { + printf("Ambiguous command '%s'; possible commands:", argv[0]); + cmd = wpa_cli_commands; + while (cmd->cmd) { + if (os_strncasecmp(cmd->cmd, argv[0], + os_strlen(argv[0])) == 0) { + printf(" %s", cmd->cmd); + } + cmd++; + } + printf("\n"); + ret = 1; + } else if (count == 0) { + printf("Unknown command '%s'\n", argv[0]); + ret = 1; + } else { + ret = match->handler(ctrl, argc - 1, &argv[1]); + } + + return ret; +} + + +static int str_match(const char *a, const char *b) +{ + return os_strncmp(a, b, os_strlen(b)) == 0; +} + + +static int wpa_cli_exec(const char *program, const char *arg1, + const char *arg2) +{ + char *cmd; + size_t len; + int res; + int ret = 0; + + len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3; + cmd = os_malloc(len); + if (cmd == NULL) + return -1; + res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2); + if (res < 0 || (size_t) res >= len) { + os_free(cmd); + return -1; + } + cmd[len - 1] = '\0'; +#ifndef _WIN32_WCE + if (system(cmd) < 0) + ret = -1; +#endif /* _WIN32_WCE */ + os_free(cmd); + + return ret; +} + + +static void wpa_cli_action_process(const char *msg) +{ + const char *pos; + char *copy = NULL, *id, *pos2; + + pos = msg; + if (*pos == '<') { + /* skip priority */ + pos = os_strchr(pos, '>'); + if (pos) + pos++; + else + pos = msg; + } + + if (str_match(pos, WPA_EVENT_CONNECTED)) { + int new_id = -1; + os_unsetenv("WPA_ID"); + os_unsetenv("WPA_ID_STR"); + os_unsetenv("WPA_CTRL_DIR"); + + pos = os_strstr(pos, "[id="); + if (pos) + copy = os_strdup(pos + 4); + + if (copy) { + pos2 = id = copy; + while (*pos2 && *pos2 != ' ') + pos2++; + *pos2++ = '\0'; + new_id = atoi(id); + os_setenv("WPA_ID", id, 1); + while (*pos2 && *pos2 != '=') + pos2++; + if (*pos2 == '=') + pos2++; + id = pos2; + while (*pos2 && *pos2 != ']') + pos2++; + *pos2 = '\0'; + os_setenv("WPA_ID_STR", id, 1); + os_free(copy); + } + + os_setenv("WPA_CTRL_DIR", ctrl_iface_dir, 1); + + if (!wpa_cli_connected || new_id != wpa_cli_last_id) { + wpa_cli_connected = 1; + wpa_cli_last_id = new_id; + wpa_cli_exec(action_file, ctrl_ifname, "CONNECTED"); + } + } else if (str_match(pos, WPA_EVENT_DISCONNECTED)) { + if (wpa_cli_connected) { + wpa_cli_connected = 0; + wpa_cli_exec(action_file, ctrl_ifname, "DISCONNECTED"); + } + } else if (str_match(pos, WPA_EVENT_TERMINATING)) { + printf("wpa_supplicant is terminating - stop monitoring\n"); + wpa_cli_quit = 1; + } +} + + +#ifndef CONFIG_ANSI_C_EXTRA +static void wpa_cli_action_cb(char *msg, size_t len) +{ + wpa_cli_action_process(msg); +} +#endif /* CONFIG_ANSI_C_EXTRA */ + + +static void wpa_cli_reconnect(void) +{ + wpa_cli_close_connection(); + ctrl_conn = wpa_cli_open_connection(ctrl_ifname); + if (ctrl_conn) { + printf("Connection to wpa_supplicant re-established\n"); + if (wpa_ctrl_attach(ctrl_conn) == 0) { + wpa_cli_attached = 1; + } else { + printf("Warning: Failed to attach to " + "wpa_supplicant.\n"); + } + } +} + + +static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read, + int action_monitor) +{ + int first = 1; + if (ctrl_conn == NULL) { + wpa_cli_reconnect(); + return; + } + while (wpa_ctrl_pending(ctrl) > 0) { + char buf[256]; + size_t len = sizeof(buf) - 1; + if (wpa_ctrl_recv(ctrl, buf, &len) == 0) { + buf[len] = '\0'; + if (action_monitor) + wpa_cli_action_process(buf); + else { + if (in_read && first) + printf("\n"); + first = 0; + printf("%s\n", buf); + } + } else { + printf("Could not read pending message.\n"); + break; + } + } + + if (wpa_ctrl_pending(ctrl) < 0) { + printf("Connection to wpa_supplicant lost - trying to " + "reconnect\n"); + wpa_cli_reconnect(); + } +} + + +#ifdef CONFIG_READLINE +static char * wpa_cli_cmd_gen(const char *text, int state) +{ + static int i, len; + const char *cmd; + + if (state == 0) { + i = 0; + len = os_strlen(text); + } + + while ((cmd = wpa_cli_commands[i].cmd)) { + i++; + if (os_strncasecmp(cmd, text, len) == 0) + return os_strdup(cmd); + } + + return NULL; +} + + +static char * wpa_cli_dummy_gen(const char *text, int state) +{ + return NULL; +} + + +static char ** wpa_cli_completion(const char *text, int start, int end) +{ + return rl_completion_matches(text, start == 0 ? + wpa_cli_cmd_gen : wpa_cli_dummy_gen); +} +#endif /* CONFIG_READLINE */ + + +static void wpa_cli_interactive(void) +{ +#define max_args 10 + char cmdbuf[256], *cmd, *argv[max_args], *pos; + int argc; +#ifdef CONFIG_READLINE + char *home, *hfile = NULL; +#endif /* CONFIG_READLINE */ + + printf("\nInteractive mode\n\n"); + +#ifdef CONFIG_READLINE + rl_attempted_completion_function = wpa_cli_completion; + home = getenv("HOME"); + if (home) { + const char *fname = ".wpa_cli_history"; + int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1; + hfile = os_malloc(hfile_len); + if (hfile) { + int res; + res = os_snprintf(hfile, hfile_len, "%s/%s", home, + fname); + if (res >= 0 && res < hfile_len) { + hfile[hfile_len - 1] = '\0'; + read_history(hfile); + stifle_history(100); + } + } + } +#endif /* CONFIG_READLINE */ + + do { + wpa_cli_recv_pending(ctrl_conn, 0, 0); +#ifndef CONFIG_NATIVE_WINDOWS + alarm(ping_interval); +#endif /* CONFIG_NATIVE_WINDOWS */ +#ifdef CONFIG_READLINE + cmd = readline("> "); + if (cmd && *cmd) { + HIST_ENTRY *h; + while (next_history()) + ; + h = previous_history(); + if (h == NULL || os_strcmp(cmd, h->line) != 0) + add_history(cmd); + next_history(); + } +#else /* CONFIG_READLINE */ + printf("> "); + cmd = fgets(cmdbuf, sizeof(cmdbuf), stdin); +#endif /* CONFIG_READLINE */ +#ifndef CONFIG_NATIVE_WINDOWS + alarm(0); +#endif /* CONFIG_NATIVE_WINDOWS */ + if (cmd == NULL) + break; + wpa_cli_recv_pending(ctrl_conn, 0, 0); + 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; + if (*pos == '"') { + char *pos2 = os_strrchr(pos, '"'); + if (pos2) + pos = pos2 + 1; + } + while (*pos != '\0' && *pos != ' ') + pos++; + if (*pos == ' ') + *pos++ = '\0'; + } + if (argc) + wpa_request(ctrl_conn, argc, argv); + + if (cmd != cmdbuf) + os_free(cmd); + } while (!wpa_cli_quit); + +#ifdef CONFIG_READLINE + if (hfile) { + /* Save command history, excluding lines that may contain + * passwords. */ + HIST_ENTRY *h; + history_set_pos(0); + while ((h = current_history())) { + char *p = h->line; + while (*p == ' ' || *p == '\t') + p++; + if (cmd_has_sensitive_data(p)) { + h = remove_history(where_history()); + if (h) { + os_free(h->line); + os_free(h->data); + os_free(h); + } else + next_history(); + } else + next_history(); + } + write_history(hfile); + os_free(hfile); + } +#endif /* CONFIG_READLINE */ +} + + +static void wpa_cli_action(struct wpa_ctrl *ctrl) +{ +#ifdef CONFIG_ANSI_C_EXTRA + /* TODO: ANSI C version(?) */ + printf("Action processing not supported in ANSI C build.\n"); +#else /* CONFIG_ANSI_C_EXTRA */ + fd_set rfds; + int fd, res; + struct timeval tv; + char buf[256]; /* note: large enough to fit in unsolicited messages */ + size_t len; + + fd = wpa_ctrl_get_fd(ctrl); + + while (!wpa_cli_quit) { + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + tv.tv_sec = ping_interval; + tv.tv_usec = 0; + res = select(fd + 1, &rfds, NULL, NULL, &tv); + if (res < 0 && errno != EINTR) { + perror("select"); + break; + } + + if (FD_ISSET(fd, &rfds)) + wpa_cli_recv_pending(ctrl, 0, 1); + else { + /* verify that connection is still working */ + len = sizeof(buf) - 1; + if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len, + wpa_cli_action_cb) < 0 || + len < 4 || os_memcmp(buf, "PONG", 4) != 0) { + printf("wpa_supplicant did not reply to PING " + "command - exiting\n"); + break; + } + } + } +#endif /* CONFIG_ANSI_C_EXTRA */ +} + + +static void wpa_cli_cleanup(void) +{ + wpa_cli_close_connection(); + if (pid_file) + os_daemonize_terminate(pid_file); + + os_program_deinit(); +} + +static void wpa_cli_terminate(int sig) +{ + wpa_cli_cleanup(); + exit(0); +} + + +#ifndef CONFIG_NATIVE_WINDOWS +static void wpa_cli_alarm(int sig) +{ + if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) { + printf("Connection to wpa_supplicant lost - trying to " + "reconnect\n"); + wpa_cli_close_connection(); + } + if (!ctrl_conn) + wpa_cli_reconnect(); + if (ctrl_conn) + wpa_cli_recv_pending(ctrl_conn, 1, 0); + alarm(ping_interval); +} +#endif /* CONFIG_NATIVE_WINDOWS */ + + +static char * wpa_cli_get_default_ifname(void) +{ + char *ifname = NULL; + +#ifdef CONFIG_CTRL_IFACE_UNIX + struct dirent *dent; + DIR *dir = opendir(ctrl_iface_dir); + if (!dir) + return NULL; + 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; + printf("Selected interface '%s'\n", dent->d_name); + ifname = os_strdup(dent->d_name); + break; + } + closedir(dir); +#endif /* CONFIG_CTRL_IFACE_UNIX */ + +#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE + char buf[2048], *pos; + size_t len; + struct wpa_ctrl *ctrl; + int ret; + + ctrl = wpa_ctrl_open(NULL); + if (ctrl == NULL) + return NULL; + + len = sizeof(buf) - 1; + ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf, &len, NULL); + if (ret >= 0) { + buf[len] = '\0'; + pos = os_strchr(buf, '\n'); + if (pos) + *pos = '\0'; + ifname = os_strdup(buf); + } + wpa_ctrl_close(ctrl); +#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ + + return ifname; +} + + +int main(int argc, char *argv[]) +{ + int interactive; + int warning_displayed = 0; + int c; + int daemonize = 0; + int ret = 0; + const char *global = NULL; + + if (os_program_init()) + return -1; + + for (;;) { + c = getopt(argc, argv, "a:Bg:G:hi:p:P:v"); + if (c < 0) + break; + switch (c) { + case 'a': + action_file = optarg; + break; + case 'B': + daemonize = 1; + break; + case 'g': + global = optarg; + break; + case 'G': + ping_interval = atoi(optarg); + break; + case 'h': + usage(); + return 0; + case 'v': + printf("%s\n", wpa_cli_version); + return 0; + case 'i': + os_free(ctrl_ifname); + ctrl_ifname = os_strdup(optarg); + break; + case 'p': + ctrl_iface_dir = optarg; + break; + case 'P': + pid_file = optarg; + break; + default: + usage(); + return -1; + } + } + + interactive = (argc == optind) && (action_file == NULL); + + if (interactive) + printf("%s\n\n%s\n\n", wpa_cli_version, wpa_cli_license); + + if (global) { +#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE + ctrl_conn = wpa_ctrl_open(NULL); +#else /* CONFIG_CTRL_IFACE_NAMED_PIPE */ + ctrl_conn = wpa_ctrl_open(global); +#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ + if (ctrl_conn == NULL) { + perror("Failed to connect to wpa_supplicant - " + "wpa_ctrl_open"); + return -1; + } + } + + for (; !global;) { + if (ctrl_ifname == NULL) + ctrl_ifname = wpa_cli_get_default_ifname(); + ctrl_conn = wpa_cli_open_connection(ctrl_ifname); + if (ctrl_conn) { + if (warning_displayed) + printf("Connection established.\n"); + break; + } + + if (!interactive) { + perror("Failed to connect to wpa_supplicant - " + "wpa_ctrl_open"); + return -1; + } + + if (!warning_displayed) { + printf("Could not connect to wpa_supplicant - " + "re-trying\n"); + warning_displayed = 1; + } + os_sleep(1, 0); + continue; + } + +#ifndef _WIN32_WCE + signal(SIGINT, wpa_cli_terminate); + signal(SIGTERM, wpa_cli_terminate); +#endif /* _WIN32_WCE */ +#ifndef CONFIG_NATIVE_WINDOWS + signal(SIGALRM, wpa_cli_alarm); +#endif /* CONFIG_NATIVE_WINDOWS */ + + if (interactive || action_file) { + if (wpa_ctrl_attach(ctrl_conn) == 0) { + wpa_cli_attached = 1; + } else { + printf("Warning: Failed to attach to " + "wpa_supplicant.\n"); + if (!interactive) + return -1; + } + } + + if (daemonize && os_daemonize(pid_file)) + return -1; + + if (interactive) + wpa_cli_interactive(); + else if (action_file) + wpa_cli_action(ctrl_conn); + else + ret = wpa_request(ctrl_conn, argc - optind, &argv[optind]); + + os_free(ctrl_ifname); + wpa_cli_cleanup(); + + return ret; +} + +#else /* CONFIG_CTRL_IFACE */ +int main(int argc, char *argv[]) +{ + printf("CONFIG_CTRL_IFACE not defined - wpa_cli disabled\n"); + return -1; +} +#endif /* CONFIG_CTRL_IFACE */ diff --git a/wpa_supplicant/wpa_gui-qt4/.gitignore b/wpa_supplicant/wpa_gui-qt4/.gitignore new file mode 100644 index 000000000000..efcb6660002e --- /dev/null +++ b/wpa_supplicant/wpa_gui-qt4/.gitignore @@ -0,0 +1,6 @@ +.moc +.obj +.ui +Makefile +wpa_gui +qrc_icons.cpp diff --git a/wpa_supplicant/wpa_gui-qt4/addinterface.cpp b/wpa_supplicant/wpa_gui-qt4/addinterface.cpp new file mode 100644 index 000000000000..02fecfea42cd --- /dev/null +++ b/wpa_supplicant/wpa_gui-qt4/addinterface.cpp @@ -0,0 +1,245 @@ +/* + * wpa_gui - AddInterface class + * Copyright (c) 2008, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include <cstdio> +#include "wpa_ctrl.h" + +#include <QMessageBox> + +#include "wpagui.h" +#include "addinterface.h" + +#ifdef CONFIG_NATIVE_WINDOWS +#include <windows.h> + +#ifndef WPA_KEY_ROOT +#define WPA_KEY_ROOT HKEY_LOCAL_MACHINE +#endif +#ifndef WPA_KEY_PREFIX +#define WPA_KEY_PREFIX TEXT("SOFTWARE\\wpa_supplicant") +#endif +#endif /* CONFIG_NATIVE_WINDOWS */ + + +AddInterface::AddInterface(WpaGui *_wpagui, QWidget *parent) + : QDialog(parent), wpagui(_wpagui) +{ + setWindowTitle("Select network interface to add"); + resize(400, 200); + vboxLayout = new QVBoxLayout(this); + + interfaceWidget = new QTreeWidget(this); + interfaceWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); + interfaceWidget->setUniformRowHeights(true); + interfaceWidget->setSortingEnabled(true); + interfaceWidget->setColumnCount(3); + interfaceWidget->headerItem()->setText(0, "driver"); + interfaceWidget->headerItem()->setText(1, "interface"); + interfaceWidget->headerItem()->setText(2, "description"); + interfaceWidget->setItemsExpandable(FALSE); + interfaceWidget->setRootIsDecorated(FALSE); + vboxLayout->addWidget(interfaceWidget); + + connect(interfaceWidget, + SIGNAL(itemActivated(QTreeWidgetItem *, int)), this, + SLOT(interfaceSelected(QTreeWidgetItem *))); + + addInterfaces(); +} + + +void AddInterface::addInterfaces() +{ +#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE + struct wpa_ctrl *ctrl; + int ret; + char buf[2048]; + size_t len; + + ctrl = wpa_ctrl_open(NULL); + if (ctrl == NULL) + return; + + len = sizeof(buf) - 1; + ret = wpa_ctrl_request(ctrl, "INTERFACE_LIST", 14, buf, &len, NULL); + if (ret < 0) { + wpa_ctrl_close(ctrl); + return; + } + buf[len] = '\0'; + + wpa_ctrl_close(ctrl); + + QString ifaces(buf); + QStringList lines = ifaces.split(QRegExp("\\n")); + for (QStringList::Iterator it = lines.begin(); + it != lines.end(); it++) { + QStringList arg = (*it).split(QChar('\t')); + if (arg.size() < 3) + continue; + QTreeWidgetItem *item = new QTreeWidgetItem(interfaceWidget); + if (!item) + break; + + item->setText(0, arg[0]); + item->setText(1, arg[1]); + item->setText(2, arg[2]); + } + + interfaceWidget->resizeColumnToContents(0); + interfaceWidget->resizeColumnToContents(1); + interfaceWidget->resizeColumnToContents(2); +#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ +} + + +#ifdef CONFIG_NATIVE_WINDOWS +bool AddInterface::addRegistryInterface(const QString &ifname) +{ + HKEY hk, ihk; + LONG ret; + int id, tmp; + TCHAR name[10]; + DWORD val, i; + + ret = RegOpenKeyEx(WPA_KEY_ROOT, WPA_KEY_PREFIX TEXT("\\interfaces"), + 0, KEY_ENUMERATE_SUB_KEYS | KEY_CREATE_SUB_KEY, + &hk); + if (ret != ERROR_SUCCESS) + return false; + + id = -1; + + for (i = 0; ; i++) { + TCHAR name[255]; + DWORD namelen; + + namelen = 255; + ret = RegEnumKeyEx(hk, i, name, &namelen, NULL, NULL, NULL, + NULL); + + if (ret == ERROR_NO_MORE_ITEMS) + break; + + if (ret != ERROR_SUCCESS) + break; + + if (namelen >= 255) + namelen = 255 - 1; + name[namelen] = '\0'; + +#ifdef UNICODE + QString s((QChar *) name, namelen); +#else /* UNICODE */ + QString s(name); +#endif /* UNICODE */ + tmp = s.toInt(); + if (tmp > id) + id = tmp; + } + + id += 1; + +#ifdef UNICODE + wsprintf(name, L"%04d", id); +#else /* UNICODE */ + os_snprintf(name, sizeof(name), "%04d", id); +#endif /* UNICODE */ + ret = RegCreateKeyEx(hk, name, 0, NULL, 0, KEY_WRITE, NULL, &ihk, + NULL); + RegCloseKey(hk); + if (ret != ERROR_SUCCESS) + return false; + +#ifdef UNICODE + RegSetValueEx(ihk, TEXT("adapter"), 0, REG_SZ, + (LPBYTE) ifname.unicode(), + (ifname.length() + 1) * sizeof(TCHAR)); + +#else /* UNICODE */ + RegSetValueEx(ihk, TEXT("adapter"), 0, REG_SZ, + (LPBYTE) ifname.toLocal8Bit(), ifname.length() + 1); +#endif /* UNICODE */ + RegSetValueEx(ihk, TEXT("config"), 0, REG_SZ, + (LPBYTE) TEXT("default"), 8 * sizeof(TCHAR)); + RegSetValueEx(ihk, TEXT("ctrl_interface"), 0, REG_SZ, + (LPBYTE) TEXT(""), 1 * sizeof(TCHAR)); + val = 1; + RegSetValueEx(ihk, TEXT("skip_on_error"), 0, REG_DWORD, (LPBYTE) &val, + sizeof(val)); + + RegCloseKey(ihk); + return true; +} +#endif /* CONFIG_NATIVE_WINDOWS */ + + +void AddInterface::interfaceSelected(QTreeWidgetItem *sel) +{ + if (!sel) + return; + +#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE + struct wpa_ctrl *ctrl; + int ret; + char buf[20], cmd[256]; + size_t len; + + /* + * INTERFACE_ADD <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB + * <driver_param>TAB<bridge_name> + */ + snprintf(cmd, sizeof(cmd), + "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s", + sel->text(1).toAscii().constData(), + "default", + sel->text(0).toAscii().constData(), + "yes", "", ""); + cmd[sizeof(cmd) - 1] = '\0'; + + ctrl = wpa_ctrl_open(NULL); + if (ctrl == NULL) + return; + + len = sizeof(buf) - 1; + ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len, NULL); + wpa_ctrl_close(ctrl); + + if (ret < 0) { + QMessageBox::warning(this, "wpa_gui", + "Add interface command could not be " + "completed."); + return; + } + + buf[len] = '\0'; + if (buf[0] != 'O' || buf[1] != 'K') { + QMessageBox::warning(this, "wpa_gui", + "Failed to add the interface."); + return; + } + +#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ + +#ifdef CONFIG_NATIVE_WINDOWS + if (!addRegistryInterface(sel->text(1))) { + QMessageBox::information(this, "wpa_gui", + "Failed to add the interface into " + "registry."); + } +#endif /* CONFIG_NATIVE_WINDOWS */ + + wpagui->selectAdapter(sel->text(1)); + close(); +} diff --git a/wpa_supplicant/wpa_gui-qt4/addinterface.h b/wpa_supplicant/wpa_gui-qt4/addinterface.h new file mode 100644 index 000000000000..9d9476a46d99 --- /dev/null +++ b/wpa_supplicant/wpa_gui-qt4/addinterface.h @@ -0,0 +1,45 @@ +/* + * wpa_gui - AddInterface class + * Copyright (c) 2008, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef ADDINTERFACE_H +#define ADDINTERFACE_H + +#include <QObject> + +#include <QtGui/QDialog> +#include <QtGui/QTreeWidget> +#include <QtGui/QVBoxLayout> + +class WpaGui; + +class AddInterface : public QDialog +{ + Q_OBJECT + +public: + AddInterface(WpaGui *_wpagui, QWidget *parent = 0); + +public slots: + virtual void interfaceSelected(QTreeWidgetItem *sel); + +private: + void addInterfaces(); + bool addRegistryInterface(const QString &ifname); + + QVBoxLayout *vboxLayout; + QTreeWidget *interfaceWidget; + WpaGui *wpagui; +}; + +#endif /* ADDINTERFACE_H */ diff --git a/wpa_supplicant/wpa_gui-qt4/eventhistory.cpp b/wpa_supplicant/wpa_gui-qt4/eventhistory.cpp new file mode 100644 index 000000000000..46deb96a53d9 --- /dev/null +++ b/wpa_supplicant/wpa_gui-qt4/eventhistory.cpp @@ -0,0 +1,130 @@ +/* + * wpa_gui - EventHistory class + * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include <QHeaderView> +#include <QScrollBar> + +#include "eventhistory.h" + + +int EventListModel::rowCount(const QModelIndex &) const +{ + return msgList.count(); +} + + +int EventListModel::columnCount(const QModelIndex &) const +{ + return 2; +} + + +QVariant EventListModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (role == Qt::DisplayRole) + if (index.column() == 0) { + if (index.row() >= timeList.size()) + return QVariant(); + return timeList.at(index.row()); + } else { + if (index.row() >= msgList.size()) + return QVariant(); + return msgList.at(index.row()); + } + else + return QVariant(); +} + + +QVariant EventListModel::headerData(int section, Qt::Orientation orientation, + int role) const +{ + if (role != Qt::DisplayRole) + return QVariant(); + + if (orientation == Qt::Horizontal) { + switch (section) { + case 0: + return QString("Timestamp"); + case 1: + return QString("Message"); + default: + return QVariant(); + } + } else + return QString("%1").arg(section); +} + + +void EventListModel::addEvent(QString time, QString msg) +{ + beginInsertRows(QModelIndex(), msgList.size(), msgList.size() + 1); + timeList << time; + msgList << msg; + endInsertRows(); +} + + +EventHistory::EventHistory(QWidget *parent, const char *, bool, Qt::WFlags) + : QDialog(parent) +{ + setupUi(this); + + connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); + + eventListView->setItemsExpandable(FALSE); + eventListView->setRootIsDecorated(FALSE); + elm = new EventListModel(parent); + eventListView->setModel(elm); +} + + +EventHistory::~EventHistory() +{ + destroy(); + delete elm; +} + + +void EventHistory::languageChange() +{ + retranslateUi(this); +} + + +void EventHistory::addEvents(WpaMsgList msgs) +{ + WpaMsgList::iterator it; + for (it = msgs.begin(); it != msgs.end(); it++) + addEvent(*it); +} + + +void EventHistory::addEvent(WpaMsg msg) +{ + bool scroll = true; + + if (eventListView->verticalScrollBar()->value() < + eventListView->verticalScrollBar()->maximum()) + scroll = false; + + elm->addEvent(msg.getTimestamp().toString("yyyy-MM-dd hh:mm:ss.zzz"), + msg.getMsg()); + + if (scroll) + eventListView->scrollToBottom(); +} diff --git a/wpa_supplicant/wpa_gui-qt4/eventhistory.h b/wpa_supplicant/wpa_gui-qt4/eventhistory.h new file mode 100644 index 000000000000..40dff6d6d779 --- /dev/null +++ b/wpa_supplicant/wpa_gui-qt4/eventhistory.h @@ -0,0 +1,63 @@ +/* + * wpa_gui - EventHistory class + * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef EVENTHISTORY_H +#define EVENTHISTORY_H + +#include <QObject> +#include "ui_eventhistory.h" + + +class EventListModel : public QAbstractTableModel +{ + Q_OBJECT + +public: + EventListModel(QObject *parent = 0) + : QAbstractTableModel(parent) {} + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + QVariant data(const QModelIndex &index, int role) const; + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const; + void addEvent(QString time, QString msg); + +private: + QStringList timeList; + QStringList msgList; +}; + + +class EventHistory : public QDialog, public Ui::EventHistory +{ + Q_OBJECT + +public: + EventHistory(QWidget *parent = 0, const char *name = 0, + bool modal = false, Qt::WFlags fl = 0); + ~EventHistory(); + +public slots: + virtual void addEvents(WpaMsgList msgs); + virtual void addEvent(WpaMsg msg); + +protected slots: + virtual void languageChange(); + +private: + EventListModel *elm; +}; + +#endif /* EVENTHISTORY_H */ diff --git a/wpa_supplicant/wpa_gui-qt4/eventhistory.ui b/wpa_supplicant/wpa_gui-qt4/eventhistory.ui new file mode 100644 index 000000000000..afe9149cfa0f --- /dev/null +++ b/wpa_supplicant/wpa_gui-qt4/eventhistory.ui @@ -0,0 +1,61 @@ +<ui version="4.0" > + <class>EventHistory</class> + <widget class="QDialog" name="EventHistory" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>533</width> + <height>285</height> + </rect> + </property> + <property name="windowTitle" > + <string>Event history</string> + </property> + <layout class="QGridLayout" > + <item row="0" column="0" colspan="2" > + <widget class="QTreeView" name="eventListView" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Expanding" hsizetype="Expanding" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="verticalScrollBarPolicy" > + <enum>Qt::ScrollBarAlwaysOn</enum> + </property> + <property name="selectionMode" > + <enum>QAbstractItemView::NoSelection</enum> + </property> + </widget> + </item> + <item row="1" column="0" > + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="1" > + <widget class="QPushButton" name="closeButton" > + <property name="text" > + <string>Close</string> + </property> + </widget> + </item> + </layout> + </widget> + <layoutdefault spacing="6" margin="11" /> + <pixmapfunction></pixmapfunction> + <includes> + <include location="local" >wpamsg.h</include> + </includes> + <resources/> + <connections/> +</ui> diff --git a/wpa_supplicant/wpa_gui-qt4/icons.qrc b/wpa_supplicant/wpa_gui-qt4/icons.qrc new file mode 100644 index 000000000000..93e94fce24cc --- /dev/null +++ b/wpa_supplicant/wpa_gui-qt4/icons.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/icons" > + <file alias="wpa_gui.svg">icons/wpa_gui.svg</file> + </qresource> +</RCC> diff --git a/wpa_supplicant/wpa_gui-qt4/icons/Makefile b/wpa_supplicant/wpa_gui-qt4/icons/Makefile new file mode 100644 index 000000000000..cb5c65e701f4 --- /dev/null +++ b/wpa_supplicant/wpa_gui-qt4/icons/Makefile @@ -0,0 +1,27 @@ +#!/usr/bin/make -f + +NAME := wpa_gui +SVG := $(NAME).svg +SIZES := 16x16 22x22 32x32 48x48 64x64 128x128 +ICONS := $(addsuffix .png,$(SIZES)) +ICONS += $(addsuffix .xpm,$(NAME) $(NAME)-16) + +all: $(ICONS) + +%.png: + mkdir -p hicolor/$(@:.png=)/apps/ + inkscape $(SVG) --without-gui \ + --export-width=$(word 1,$(subst x, ,$(@:.png=))) \ + --export-height=$(word 2,$(subst x, ,$(@:.png=))) \ + --export-png=hicolor/$(@:.png=)/apps/$(NAME).png + +$(NAME).xpm: + mkdir -p pixmaps/ + convert hicolor/32x32/apps/$(NAME).png pixmaps/$@ + +$(NAME)-16.xpm: + mkdir -p pixmaps/ + convert hicolor/16x16/apps/$(NAME).png pixmaps/$@ + +clean: + $(RM) -r pixmaps hicolor diff --git a/wpa_supplicant/wpa_gui-qt4/icons/README b/wpa_supplicant/wpa_gui-qt4/icons/README new file mode 100644 index 000000000000..1584eb51d62e --- /dev/null +++ b/wpa_supplicant/wpa_gui-qt4/icons/README @@ -0,0 +1,7 @@ +Copyright (c) 2008 Bernard Gray <bernard.gray@gmail.com> + +The wpa_gui icon is licensed under the GPL version 2. Alternatively, the icon +may be distributed under the terms of BSD license. + +To convert the svg icon to other formats, make sure inkscape and imagemagick +are installed and use `make' to create various sized png and xpm icons. diff --git a/wpa_supplicant/wpa_gui-qt4/icons/wpa_gui.svg b/wpa_supplicant/wpa_gui-qt4/icons/wpa_gui.svg new file mode 100644 index 000000000000..b3abf0a288d8 --- /dev/null +++ b/wpa_supplicant/wpa_gui-qt4/icons/wpa_gui.svg @@ -0,0 +1,256 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.0" + width="128" + height="128" + id="svg2" + sodipodi:version="0.32" + inkscape:version="0.46" + sodipodi:docname="wpa_gui.svg" + inkscape:output_extension="org.inkscape.output.svg.inkscape"> + <metadata + id="metadata47"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <sodipodi:namedview + inkscape:window-height="771" + inkscape:window-width="640" + inkscape:pageshadow="2" + inkscape:pageopacity="0.0" + guidetolerance="10.0" + gridtolerance="10.0" + objecttolerance="10.0" + borderopacity="1.0" + bordercolor="#666666" + pagecolor="#ffffff" + id="base" + showgrid="false" + inkscape:zoom="4.2421875" + inkscape:cx="64" + inkscape:cy="64" + inkscape:window-x="634" + inkscape:window-y="0" + inkscape:current-layer="svg2" /> + <defs + id="defs4"> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 64 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="128 : 64 : 1" + inkscape:persp3d-origin="64 : 42.666667 : 1" + id="perspective49" /> + <linearGradient + id="linearGradient39133"> + <stop + id="stop39135" + style="stop-color:#252525;stop-opacity:1" + offset="0" /> + <stop + id="stop39137" + style="stop-color:#515151;stop-opacity:1" + offset="0" /> + <stop + id="stop39139" + style="stop-color:#878787;stop-opacity:1" + offset="0.28677997" /> + <stop + id="stop39141" + style="stop-color:#000000;stop-opacity:1" + offset="0.92151743" /> + <stop + id="stop39143" + style="stop-color:#ffffff;stop-opacity:0.73786408" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient39119"> + <stop + id="stop39121" + style="stop-color:#ffffff;stop-opacity:0.82905984" + offset="0" /> + <stop + id="stop39123" + style="stop-color:#ffffff;stop-opacity:0" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient39106"> + <stop + id="stop39108" + style="stop-color:#ffffff;stop-opacity:1" + offset="0" /> + <stop + id="stop39110" + style="stop-color:#a8a8a8;stop-opacity:0" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient39094"> + <stop + id="stop39096" + style="stop-color:#000000;stop-opacity:1" + offset="0" /> + <stop + id="stop39098" + style="stop-color:#333333;stop-opacity:1" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient39062"> + <stop + id="stop39064" + style="stop-color:#252525;stop-opacity:1" + offset="0" /> + <stop + id="stop39086" + style="stop-color:#515151;stop-opacity:1" + offset="0.21101321" /> + <stop + id="stop39088" + style="stop-color:#878787;stop-opacity:1" + offset="0.75" /> + <stop + id="stop39090" + style="stop-color:#6c6c6c;stop-opacity:1" + offset="0.875" /> + <stop + id="stop39066" + style="stop-color:#1e1e1e;stop-opacity:1" + offset="1" /> + </linearGradient> + <linearGradient + x1="4" + y1="40" + x2="124" + y2="60" + id="linearGradient39068" + xlink:href="#linearGradient39062" + gradientUnits="userSpaceOnUse" /> + <radialGradient + cx="100.70589" + cy="96" + r="60" + fx="158.07428" + fy="95.718063" + id="radialGradient39100" + xlink:href="#linearGradient39094" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(2.7837903e-8,-1,0.99999999,-2.1864248e-6,-32.000004,164.7061)" /> + <radialGradient + cx="100.44444" + cy="34.363636" + r="32" + fx="83.18" + fy="34.228985" + id="radialGradient39104" + xlink:href="#linearGradient39106" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(3.1472435e-6,1.0227273,-0.87499999,-9.5061964e-8,94.067865,-4.7272712)" /> + <radialGradient + cx="75.999977" + cy="-2.7730541" + r="48" + fx="55.266491" + fy="-2.5338216" + id="radialGradient39125" + xlink:href="#linearGradient39119" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0,0.83333324,-1.6666667,2.518705e-6,59.378243,-35.333302)" /> + <radialGradient + cx="64.066589" + cy="63.713329" + r="60" + fx="64.066589" + fy="63.713329" + id="radialGradient39131" + xlink:href="#linearGradient39133" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.1333333,5.1768857e-8,5.2556881e-6,1.1666667,-8.6091298,-10.332226)" /> + <filter + id="filter39153"> + <feGaussianBlur + id="feGaussianBlur39155" + stdDeviation="2.28" + inkscape:collect="always" /> + </filter> + <filter + id="filter39159"> + <feGaussianBlur + inkscape:collect="always" + stdDeviation="1.68" + id="feGaussianBlur39161" /> + </filter> + </defs> + <g + id="layer1" + style="display:inline"> + <path + d="M 29,4 C 15.147058,4 4,15.14706 4,29 l 0,70 c 0,13.85294 11.147058,25 25,25 l 70,0 c 13.85294,0 25,-11.14706 25,-25 l 0,-70 C 124,15.14706 112.85294,4 99,4 L 29,4 z" + id="path39151" + style="opacity:1;fill:#000000;fill-opacity:1;stroke:none;filter:url(#filter39153)" /> + <path + d="M 29,4 C 15.147058,4 4,15.14706 4,29 l 0,70 c 0,13.85294 11.147058,25 25,25 l 70,0 c 13.85294,0 25,-11.14706 25,-25 l 0,-70 C 124,15.14706 112.85294,4 99,4 L 29,4 z" + id="path39157" + style="opacity:1;fill:#000000;fill-opacity:1;stroke:none;filter:url(#filter39159)" /> + <rect + width="120" + height="120" + ry="25.00531" + x="4" + y="0" + id="rect2573" + style="opacity:1;fill:url(#radialGradient39100);fill-opacity:1;stroke:none" /> + <path + d="M 29,0 C 15.147058,0 4,11.14706 4,25 l 0,70 c 0,13.85294 11.147058,25 25,25 l 70,0 c 13.85294,0 25,-11.14706 25,-25 l 0,-70 C 124,11.14706 112.85294,0 99,0 L 29,0 z" + id="path39127" + style="opacity:0.20512821;fill:url(#radialGradient39131);fill-opacity:1;stroke:none" /> + <path + d="m 44,68 40,0 12,40 c -20,7.27273 -44,7.27273 -64,0 L 44,68 z" + id="path39102" + style="opacity:0.53418801;fill:url(#radialGradient39104);fill-opacity:1;stroke:none" /> + <path + d="M 25.339207,12 C 52,8 76,8 102.66079,12 107.83471,12 112,16.165286 112,21.339207 L 116,52 C 100,73.339207 28,73.339207 12,52 L 16,21.339207 C 16,16.165286 20.165286,12 25.339207,12 z" + id="rect39116" + style="opacity:0.92307691;fill:url(#radialGradient39125);fill-opacity:1;stroke:none" /> + <path + d="M 29,8 C 15.147058,8 4,19.14706 4,33 l 0,70 c 0,13.85294 11.147058,25 25,25 l 70,0 c 13.85294,0 25,-11.14706 25,-25 l 0,-70 C 124,19.14706 112.85294,8 99,8 L 29,8 z" + id="path39147" + style="opacity:0.20512821;fill:#000000;fill-opacity:1;stroke:none" /> + <path + d="M 29,0 C 15.147058,0 4,11.147058 4,25 l 0,70 c 0,13.85294 11.147058,25 25,25 l 70,0 c 13.85294,0 25,-11.14706 25,-25 l 0,-70 C 124,11.147058 112.85294,0 99,0 L 29,0 z m 0,4 70,0 c 11.70613,0 21,9.293869 21,21 l 0,70 c 0,11.70613 -9.29387,21 -21,21 l -70,0 C 17.293869,116 8,106.70613 8,95 L 8,25 C 8,13.293869 17.293869,4 29,4 z" + id="rect39029" + style="opacity:1;fill:url(#linearGradient39068);fill-opacity:1;stroke:none" /> + <path + d="M 66.35081,74.771345 A 36,36 0 1 1 54.34964,35.777782" + transform="matrix(-0.16680323,0.53082142,-0.53082142,-0.16680323,103.31027,53.117897)" + id="path3351" + style="opacity:1;fill:none;stroke:#ffffff;stroke-width:21.56673813;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + d="m 36,56 a 4,4 0 1 1 -8,0 4,4 0 1 1 8,0 z" + transform="matrix(1.4851301,0,0,1.4851301,16.475837,-23.948973)" + id="path3353" + style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none" /> + <path + d="M 66.35081,74.771345 A 36,36 0 1 1 54.34964,35.777782" + transform="matrix(-0.35033273,1.1148712,-1.1148712,-0.35033273,146.5624,46.88078)" + id="path2622" + style="opacity:1;fill:none;stroke:#ffffff;stroke-width:10.26852894;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + </g> +</svg> diff --git a/wpa_supplicant/wpa_gui-qt4/icons_png.qrc b/wpa_supplicant/wpa_gui-qt4/icons_png.qrc new file mode 100644 index 000000000000..09f3d962008b --- /dev/null +++ b/wpa_supplicant/wpa_gui-qt4/icons_png.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/icons" > + <file alias="wpa_gui.png">icons/hicolor/16x16/apps/wpa_gui.png</file> + </qresource> +</RCC> diff --git a/wpa_supplicant/wpa_gui-qt4/main.cpp b/wpa_supplicant/wpa_gui-qt4/main.cpp new file mode 100644 index 000000000000..9585e1ef0b64 --- /dev/null +++ b/wpa_supplicant/wpa_gui-qt4/main.cpp @@ -0,0 +1,66 @@ +/* + * wpa_gui - Application startup + * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifdef CONFIG_NATIVE_WINDOWS +#include <winsock.h> +#endif /* CONFIG_NATIVE_WINDOWS */ +#include <QApplication> +#include "wpagui.h" + + +class WpaGuiApp : public QApplication +{ +public: + WpaGuiApp(int &argc, char **argv); + + virtual void saveState(QSessionManager &manager); + + WpaGui *w; +}; + +WpaGuiApp::WpaGuiApp(int &argc, char **argv) : QApplication(argc, argv) +{ +} + +void WpaGuiApp::saveState(QSessionManager &manager) +{ + QApplication::saveState(manager); + w->saveState(); +} + + +int main(int argc, char *argv[]) +{ + WpaGuiApp app(argc, argv); + WpaGui w(&app); + int ret; + +#ifdef CONFIG_NATIVE_WINDOWS + WSADATA wsaData; + if (WSAStartup(MAKEWORD(2, 0), &wsaData)) { + /* printf("Could not find a usable WinSock.dll\n"); */ + return -1; + } +#endif /* CONFIG_NATIVE_WINDOWS */ + + app.w = &w; + + ret = app.exec(); + +#ifdef CONFIG_NATIVE_WINDOWS + WSACleanup(); +#endif /* CONFIG_NATIVE_WINDOWS */ + + return ret; +} diff --git a/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp b/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp new file mode 100644 index 000000000000..dae9edd38d39 --- /dev/null +++ b/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp @@ -0,0 +1,823 @@ +/* + * wpa_gui - NetworkConfig class + * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include <cstdio> +#include <QMessageBox> + +#include "networkconfig.h" +#include "wpagui.h" + +enum { + AUTH_NONE = 0, + AUTH_IEEE8021X = 1, + AUTH_WPA_PSK = 2, + AUTH_WPA_EAP = 3, + AUTH_WPA2_PSK = 4, + AUTH_WPA2_EAP = 5 +}; + +#define WPA_GUI_KEY_DATA "[key is configured]" + + +NetworkConfig::NetworkConfig(QWidget *parent, const char *, bool, Qt::WFlags) + : QDialog(parent) +{ + setupUi(this); + + connect(authSelect, SIGNAL(activated(int)), this, + SLOT(authChanged(int))); + connect(cancelButton, SIGNAL(clicked()), this, SLOT(close())); + connect(addButton, SIGNAL(clicked()), this, SLOT(addNetwork())); + connect(encrSelect, SIGNAL(activated(const QString &)), this, + SLOT(encrChanged(const QString &))); + connect(removeButton, SIGNAL(clicked()), this, SLOT(removeNetwork())); + connect(eapSelect, SIGNAL(activated(int)), this, + SLOT(eapChanged(int))); + connect(useWpsButton, SIGNAL(clicked()), this, SLOT(useWps())); + + wpagui = NULL; + new_network = false; +} + + +NetworkConfig::~NetworkConfig() +{ +} + + +void NetworkConfig::languageChange() +{ + retranslateUi(this); +} + + +void NetworkConfig::paramsFromScanResults(QTreeWidgetItem *sel) +{ + new_network = true; + + /* SSID BSSID frequency signal flags */ + setWindowTitle(sel->text(0)); + ssidEdit->setText(sel->text(0)); + + QString flags = sel->text(4); + int auth, encr = 0; + if (flags.indexOf("[WPA2-EAP") >= 0) + auth = AUTH_WPA2_EAP; + else if (flags.indexOf("[WPA-EAP") >= 0) + auth = AUTH_WPA_EAP; + else if (flags.indexOf("[WPA2-PSK") >= 0) + auth = AUTH_WPA2_PSK; + else if (flags.indexOf("[WPA-PSK") >= 0) + auth = AUTH_WPA_PSK; + else + auth = AUTH_NONE; + + if (flags.indexOf("-CCMP") >= 0) + encr = 1; + else if (flags.indexOf("-TKIP") >= 0) + encr = 0; + else if (flags.indexOf("WEP") >= 0) + encr = 1; + else + encr = 0; + + authSelect->setCurrentIndex(auth); + authChanged(auth); + encrSelect->setCurrentIndex(encr); + + wepEnabled(auth == AUTH_NONE && encr == 1); + + getEapCapa(); + + if (flags.indexOf("[WPS") >= 0) + useWpsButton->setEnabled(true); + bssid = sel->text(1); +} + + +void NetworkConfig::authChanged(int sel) +{ + pskEdit->setEnabled(sel == AUTH_WPA_PSK || sel == AUTH_WPA2_PSK); + bool eap = sel == AUTH_IEEE8021X || sel == AUTH_WPA_EAP || + sel == AUTH_WPA2_EAP; + eapSelect->setEnabled(eap); + identityEdit->setEnabled(eap); + passwordEdit->setEnabled(eap); + cacertEdit->setEnabled(eap); + phase2Select->setEnabled(eap); + if (eap) + eapChanged(eapSelect->currentIndex()); + + while (encrSelect->count()) + encrSelect->removeItem(0); + + if (sel == AUTH_NONE || sel == AUTH_IEEE8021X) { + encrSelect->addItem("None"); + encrSelect->addItem("WEP"); + encrSelect->setCurrentIndex(sel == AUTH_NONE ? 0 : 1); + } else { + encrSelect->addItem("TKIP"); + encrSelect->addItem("CCMP"); + encrSelect->setCurrentIndex((sel == AUTH_WPA2_PSK || + sel == AUTH_WPA2_EAP) ? 1 : 0); + } + + wepEnabled(sel == AUTH_IEEE8021X); +} + + +void NetworkConfig::eapChanged(int sel) +{ + QString prev_val = phase2Select->currentText(); + while (phase2Select->count()) + phase2Select->removeItem(0); + + QStringList inner; + inner << "PEAP" << "TTLS" << "FAST"; + if (!inner.contains(eapSelect->itemText(sel))) + return; + + phase2Select->addItem("[ any ]"); + + /* Add special cases based on outer method */ + if (eapSelect->currentText().compare("TTLS") == 0) { + phase2Select->addItem("PAP"); + phase2Select->addItem("CHAP"); + phase2Select->addItem("MSCHAP"); + phase2Select->addItem("MSCHAPv2"); + } else if (eapSelect->currentText().compare("FAST") == 0) + phase2Select->addItem("GTC(auth) + MSCHAPv2(prov)"); + + /* Add all enabled EAP methods that can be used in the tunnel */ + int i; + QStringList allowed; + allowed << "MSCHAPV2" << "MD5" << "GTC" << "TLS" << "OTP" << "SIM" + << "AKA"; + for (i = 0; i < eapSelect->count(); i++) { + if (allowed.contains(eapSelect->itemText(i))) { + phase2Select->addItem("EAP-" + eapSelect->itemText(i)); + } + } + + for (i = 0; i < phase2Select->count(); i++) { + if (phase2Select->itemText(i).compare(prev_val) == 0) { + phase2Select->setCurrentIndex(i); + break; + } + } +} + + +void NetworkConfig::addNetwork() +{ + char reply[10], cmd[256]; + size_t reply_len; + int id; + int psklen = pskEdit->text().length(); + int auth = authSelect->currentIndex(); + + if (auth == AUTH_WPA_PSK || auth == AUTH_WPA2_PSK) { + if (psklen < 8 || psklen > 64) { + QMessageBox::warning(this, "WPA Pre-Shared Key Error", + "WPA-PSK requires a passphrase " + "of 8 to 63 characters\n" + "or 64 hex digit PSK"); + pskEdit->setFocus(); + return; + } + } + + if (idstrEdit->isEnabled() && !idstrEdit->text().isEmpty()) { + QRegExp rx("^(\\w|-)+$"); + if (rx.indexIn(idstrEdit->text()) < 0) { + QMessageBox::warning(this, "Network ID Error", + "Network ID String contains " + "non-word characters.\n" + "It must be a simple string, " + "without spaces, containing\n" + "only characters in this range: " + "[A-Za-z0-9_-]\n"); + idstrEdit->setFocus(); + return; + } + } + + if (wpagui == NULL) + return; + + memset(reply, 0, sizeof(reply)); + reply_len = sizeof(reply) - 1; + + if (new_network) { + wpagui->ctrlRequest("ADD_NETWORK", reply, &reply_len); + if (reply[0] == 'F') { + QMessageBox::warning(this, "wpa_gui", "Failed to add " + "network to wpa_supplicant\n" + "configuration."); + return; + } + id = atoi(reply); + } else + id = edit_network_id; + + setNetworkParam(id, "ssid", ssidEdit->text().toAscii().constData(), + true); + + const char *key_mgmt = NULL, *proto = NULL, *pairwise = NULL; + switch (auth) { + case AUTH_NONE: + key_mgmt = "NONE"; + break; + case AUTH_IEEE8021X: + key_mgmt = "IEEE8021X"; + break; + case AUTH_WPA_PSK: + key_mgmt = "WPA-PSK"; + proto = "WPA"; + break; + case AUTH_WPA_EAP: + key_mgmt = "WPA-EAP"; + proto = "WPA"; + break; + case AUTH_WPA2_PSK: + key_mgmt = "WPA-PSK"; + proto = "WPA2"; + break; + case AUTH_WPA2_EAP: + key_mgmt = "WPA-EAP"; + proto = "WPA2"; + break; + } + + if (auth == AUTH_WPA_PSK || auth == AUTH_WPA_EAP || + auth == AUTH_WPA2_PSK || auth == AUTH_WPA2_EAP) { + int encr = encrSelect->currentIndex(); + if (encr == 0) + pairwise = "TKIP"; + else + pairwise = "CCMP"; + } + + if (proto) + setNetworkParam(id, "proto", proto, false); + if (key_mgmt) + setNetworkParam(id, "key_mgmt", key_mgmt, false); + if (pairwise) { + setNetworkParam(id, "pairwise", pairwise, false); + setNetworkParam(id, "group", "TKIP CCMP WEP104 WEP40", false); + } + if (pskEdit->isEnabled() && + strcmp(pskEdit->text().toAscii().constData(), + WPA_GUI_KEY_DATA) != 0) + setNetworkParam(id, "psk", + pskEdit->text().toAscii().constData(), + psklen != 64); + if (eapSelect->isEnabled()) { + const char *eap = + eapSelect->currentText().toAscii().constData(); + setNetworkParam(id, "eap", eap, false); + if (strcmp(eap, "SIM") == 0 || strcmp(eap, "AKA") == 0) + setNetworkParam(id, "pcsc", "", true); + else + setNetworkParam(id, "pcsc", "NULL", false); + } + if (phase2Select->isEnabled()) { + QString eap = eapSelect->currentText(); + QString inner = phase2Select->currentText(); + char phase2[32]; + phase2[0] = '\0'; + if (eap.compare("PEAP") == 0) { + if (inner.startsWith("EAP-")) + snprintf(phase2, sizeof(phase2), "auth=%s", + inner.right(inner.size() - 4). + toAscii().constData()); + } else if (eap.compare("TTLS") == 0) { + if (inner.startsWith("EAP-")) + snprintf(phase2, sizeof(phase2), "autheap=%s", + inner.right(inner.size() - 4). + toAscii().constData()); + else + snprintf(phase2, sizeof(phase2), "auth=%s", + inner.toAscii().constData()); + } else if (eap.compare("FAST") == 0) { + const char *provisioning = NULL; + if (inner.startsWith("EAP-")) { + snprintf(phase2, sizeof(phase2), "auth=%s", + inner.right(inner.size() - 4). + toAscii().constData()); + provisioning = "fast_provisioning=2"; + } else if (inner.compare("GTC(auth) + MSCHAPv2(prov)") + == 0) { + snprintf(phase2, sizeof(phase2), + "auth=GTC auth=MSCHAPV2"); + provisioning = "fast_provisioning=1"; + } else + provisioning = "fast_provisioning=3"; + if (provisioning) { + char blob[32]; + setNetworkParam(id, "phase1", provisioning, + true); + snprintf(blob, sizeof(blob), + "blob://fast-pac-%d", id); + setNetworkParam(id, "pac_file", blob, true); + } + } + if (phase2[0]) + setNetworkParam(id, "phase2", phase2, true); + else + setNetworkParam(id, "phase2", "NULL", false); + } else + setNetworkParam(id, "phase2", "NULL", false); + if (identityEdit->isEnabled() && identityEdit->text().length() > 0) + setNetworkParam(id, "identity", + identityEdit->text().toAscii().constData(), + true); + else + setNetworkParam(id, "identity", "NULL", false); + if (passwordEdit->isEnabled() && passwordEdit->text().length() > 0 && + strcmp(passwordEdit->text().toAscii().constData(), + WPA_GUI_KEY_DATA) != 0) + setNetworkParam(id, "password", + passwordEdit->text().toAscii().constData(), + true); + else if (passwordEdit->text().length() == 0) + setNetworkParam(id, "password", "NULL", false); + if (cacertEdit->isEnabled() && cacertEdit->text().length() > 0) + setNetworkParam(id, "ca_cert", + cacertEdit->text().toAscii().constData(), + true); + else + setNetworkParam(id, "ca_cert", "NULL", false); + writeWepKey(id, wep0Edit, 0); + writeWepKey(id, wep1Edit, 1); + writeWepKey(id, wep2Edit, 2); + writeWepKey(id, wep3Edit, 3); + + if (wep0Radio->isEnabled() && wep0Radio->isChecked()) + setNetworkParam(id, "wep_tx_keyidx", "0", false); + else if (wep1Radio->isEnabled() && wep1Radio->isChecked()) + setNetworkParam(id, "wep_tx_keyidx", "1", false); + else if (wep2Radio->isEnabled() && wep2Radio->isChecked()) + setNetworkParam(id, "wep_tx_keyidx", "2", false); + else if (wep3Radio->isEnabled() && wep3Radio->isChecked()) + setNetworkParam(id, "wep_tx_keyidx", "3", false); + + if (idstrEdit->isEnabled() && idstrEdit->text().length() > 0) + setNetworkParam(id, "id_str", + idstrEdit->text().toAscii().constData(), + true); + else + setNetworkParam(id, "id_str", "NULL", false); + + if (prioritySpinBox->isEnabled()) { + QString prio; + prio = prio.setNum(prioritySpinBox->value()); + setNetworkParam(id, "priority", prio.toAscii().constData(), + false); + } + + snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %d", id); + reply_len = sizeof(reply); + wpagui->ctrlRequest(cmd, reply, &reply_len); + if (strncmp(reply, "OK", 2) != 0) { + QMessageBox::warning(this, "wpa_gui", "Failed to enable " + "network in wpa_supplicant\n" + "configuration."); + /* Network was added, so continue anyway */ + } + wpagui->triggerUpdate(); + wpagui->ctrlRequest("SAVE_CONFIG", reply, &reply_len); + + close(); +} + + +void NetworkConfig::setWpaGui(WpaGui *_wpagui) +{ + wpagui = _wpagui; +} + + +int NetworkConfig::setNetworkParam(int id, const char *field, + const char *value, bool quote) +{ + char reply[10], cmd[256]; + size_t reply_len; + snprintf(cmd, sizeof(cmd), "SET_NETWORK %d %s %s%s%s", + id, field, quote ? "\"" : "", value, quote ? "\"" : ""); + reply_len = sizeof(reply); + wpagui->ctrlRequest(cmd, reply, &reply_len); + return strncmp(reply, "OK", 2) == 0 ? 0 : -1; +} + + +void NetworkConfig::encrChanged(const QString &sel) +{ + wepEnabled(sel.indexOf("WEP") == 0); +} + + +void NetworkConfig::wepEnabled(bool enabled) +{ + wep0Edit->setEnabled(enabled); + wep1Edit->setEnabled(enabled); + wep2Edit->setEnabled(enabled); + wep3Edit->setEnabled(enabled); + wep0Radio->setEnabled(enabled); + wep1Radio->setEnabled(enabled); + wep2Radio->setEnabled(enabled); + wep3Radio->setEnabled(enabled); +} + + +void NetworkConfig::writeWepKey(int network_id, QLineEdit *edit, int id) +{ + char buf[10]; + bool hex; + const char *txt, *pos; + size_t len; + + if (!edit->isEnabled() || edit->text().isEmpty()) + return; + + /* + * Assume hex key if only hex characters are present and length matches + * with 40, 104, or 128-bit key + */ + txt = edit->text().toAscii().constData(); + if (strcmp(txt, WPA_GUI_KEY_DATA) == 0) + return; + len = strlen(txt); + if (len == 0) + return; + pos = txt; + hex = true; + while (*pos) { + if (!((*pos >= '0' && *pos <= '9') || + (*pos >= 'a' && *pos <= 'f') || + (*pos >= 'A' && *pos <= 'F'))) { + hex = false; + break; + } + pos++; + } + if (hex && len != 10 && len != 26 && len != 32) + hex = false; + snprintf(buf, sizeof(buf), "wep_key%d", id); + setNetworkParam(network_id, buf, txt, !hex); +} + + +static int key_value_isset(const char *reply, size_t reply_len) +{ + return reply_len > 0 && (reply_len < 4 || memcmp(reply, "FAIL", 4) != 0); +} + + +void NetworkConfig::paramsFromConfig(int network_id) +{ + int i, res; + + edit_network_id = network_id; + getEapCapa(); + + char reply[1024], cmd[256], *pos; + size_t reply_len; + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ssid", network_id); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && + reply_len >= 2 && reply[0] == '"') { + reply[reply_len] = '\0'; + pos = strchr(reply + 1, '"'); + if (pos) + *pos = '\0'; + ssidEdit->setText(reply + 1); + } + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d proto", network_id); + reply_len = sizeof(reply) - 1; + int wpa = 0; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) { + reply[reply_len] = '\0'; + if (strstr(reply, "RSN") || strstr(reply, "WPA2")) + wpa = 2; + else if (strstr(reply, "WPA")) + wpa = 1; + } + + int auth = AUTH_NONE, encr = 0; + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d key_mgmt", network_id); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) { + reply[reply_len] = '\0'; + if (strstr(reply, "WPA-EAP")) + auth = wpa & 2 ? AUTH_WPA2_EAP : AUTH_WPA_EAP; + else if (strstr(reply, "WPA-PSK")) + auth = wpa & 2 ? AUTH_WPA2_PSK : AUTH_WPA_PSK; + else if (strstr(reply, "IEEE8021X")) { + auth = AUTH_IEEE8021X; + encr = 1; + } + } + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d pairwise", network_id); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) { + reply[reply_len] = '\0'; + if (strstr(reply, "CCMP") && auth != AUTH_NONE) + encr = 1; + else if (strstr(reply, "TKIP")) + encr = 0; + else if (strstr(reply, "WEP")) + encr = 1; + else + encr = 0; + } + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d psk", network_id); + reply_len = sizeof(reply) - 1; + res = wpagui->ctrlRequest(cmd, reply, &reply_len); + if (res >= 0 && reply_len >= 2 && reply[0] == '"') { + reply[reply_len] = '\0'; + pos = strchr(reply + 1, '"'); + if (pos) + *pos = '\0'; + pskEdit->setText(reply + 1); + } else if (res >= 0 && key_value_isset(reply, reply_len)) { + pskEdit->setText(WPA_GUI_KEY_DATA); + } + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d identity", network_id); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && + reply_len >= 2 && reply[0] == '"') { + reply[reply_len] = '\0'; + pos = strchr(reply + 1, '"'); + if (pos) + *pos = '\0'; + identityEdit->setText(reply + 1); + } + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d password", network_id); + reply_len = sizeof(reply) - 1; + res = wpagui->ctrlRequest(cmd, reply, &reply_len); + if (res >= 0 && reply_len >= 2 && reply[0] == '"') { + reply[reply_len] = '\0'; + pos = strchr(reply + 1, '"'); + if (pos) + *pos = '\0'; + passwordEdit->setText(reply + 1); + } else if (res >= 0 && key_value_isset(reply, reply_len)) { + passwordEdit->setText(WPA_GUI_KEY_DATA); + } + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ca_cert", network_id); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && + reply_len >= 2 && reply[0] == '"') { + reply[reply_len] = '\0'; + pos = strchr(reply + 1, '"'); + if (pos) + *pos = '\0'; + cacertEdit->setText(reply + 1); + } + + enum { NO_INNER, PEAP_INNER, TTLS_INNER, FAST_INNER } eap = NO_INNER; + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d eap", network_id); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && + reply_len >= 1) { + reply[reply_len] = '\0'; + for (i = 0; i < eapSelect->count(); i++) { + if (eapSelect->itemText(i).compare(reply) == 0) { + eapSelect->setCurrentIndex(i); + if (strcmp(reply, "PEAP") == 0) + eap = PEAP_INNER; + else if (strcmp(reply, "TTLS") == 0) + eap = TTLS_INNER; + else if (strcmp(reply, "FAST") == 0) + eap = FAST_INNER; + break; + } + } + } + + if (eap != NO_INNER) { + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d phase2", + network_id); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && + reply_len >= 1) { + reply[reply_len] = '\0'; + eapChanged(eapSelect->currentIndex()); + } else + eap = NO_INNER; + } + + char *val; + val = reply + 1; + while (*(val + 1)) + val++; + if (*val == '"') + *val = '\0'; + + switch (eap) { + case PEAP_INNER: + if (strncmp(reply, "\"auth=", 6)) + break; + val = reply + 2; + memcpy(val, "EAP-", 4); + break; + case TTLS_INNER: + if (strncmp(reply, "\"autheap=", 9) == 0) { + val = reply + 5; + memcpy(val, "EAP-", 4); + } else if (strncmp(reply, "\"auth=", 6) == 0) + val = reply + 6; + break; + case FAST_INNER: + if (strncmp(reply, "\"auth=", 6)) + break; + if (strcmp(reply + 6, "GTC auth=MSCHAPV2") == 0) { + val = (char *) "GTC(auth) + MSCHAPv2(prov)"; + break; + } + val = reply + 2; + memcpy(val, "EAP-", 4); + break; + case NO_INNER: + break; + } + + for (i = 0; i < phase2Select->count(); i++) { + if (phase2Select->itemText(i).compare(val) == 0) { + phase2Select->setCurrentIndex(i); + break; + } + } + + for (i = 0; i < 4; i++) { + QLineEdit *wepEdit; + switch (i) { + default: + case 0: + wepEdit = wep0Edit; + break; + case 1: + wepEdit = wep1Edit; + break; + case 2: + wepEdit = wep2Edit; + break; + case 3: + wepEdit = wep3Edit; + break; + } + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_key%d", + network_id, i); + reply_len = sizeof(reply) - 1; + res = wpagui->ctrlRequest(cmd, reply, &reply_len); + if (res >= 0 && reply_len >= 2 && reply[0] == '"') { + reply[reply_len] = '\0'; + pos = strchr(reply + 1, '"'); + if (pos) + *pos = '\0'; + if (auth == AUTH_NONE || auth == AUTH_IEEE8021X) + encr = 1; + + wepEdit->setText(reply + 1); + } else if (res >= 0 && key_value_isset(reply, reply_len)) { + if (auth == AUTH_NONE || auth == AUTH_IEEE8021X) + encr = 1; + wepEdit->setText(WPA_GUI_KEY_DATA); + } + } + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_tx_keyidx", network_id); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 1) + { + reply[reply_len] = '\0'; + switch (atoi(reply)) { + case 0: + wep0Radio->setChecked(true); + break; + case 1: + wep1Radio->setChecked(true); + break; + case 2: + wep2Radio->setChecked(true); + break; + case 3: + wep3Radio->setChecked(true); + break; + } + } + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d id_str", network_id); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && + reply_len >= 2 && reply[0] == '"') { + reply[reply_len] = '\0'; + pos = strchr(reply + 1, '"'); + if (pos) + *pos = '\0'; + idstrEdit->setText(reply + 1); + } + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d priority", network_id); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 1) + { + reply[reply_len] = '\0'; + prioritySpinBox->setValue(atoi(reply)); + } + + authSelect->setCurrentIndex(auth); + authChanged(auth); + encrSelect->setCurrentIndex(encr); + if (auth == AUTH_NONE || auth == AUTH_IEEE8021X) + wepEnabled(encr == 1); + + removeButton->setEnabled(true); + addButton->setText("Save"); +} + + +void NetworkConfig::removeNetwork() +{ + char reply[10], cmd[256]; + size_t reply_len; + + if (QMessageBox::information(this, "wpa_gui", + "This will permanently remove the " + "network\n" + "from the configuration. Do you really " + "want\n" + "to remove this network?", "Yes", "No") + != 0) + return; + + snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %d", edit_network_id); + reply_len = sizeof(reply); + wpagui->ctrlRequest(cmd, reply, &reply_len); + if (strncmp(reply, "OK", 2) != 0) { + QMessageBox::warning(this, "wpa_gui", + "Failed to remove network from " + "wpa_supplicant\n" + "configuration."); + } else { + wpagui->triggerUpdate(); + wpagui->ctrlRequest("SAVE_CONFIG", reply, &reply_len); + } + + close(); +} + + +void NetworkConfig::newNetwork() +{ + new_network = true; + getEapCapa(); +} + + +void NetworkConfig::getEapCapa() +{ + char reply[256]; + size_t reply_len; + + if (wpagui == NULL) + return; + + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest("GET_CAPABILITY eap", reply, &reply_len) < 0) + return; + reply[reply_len] = '\0'; + + QString res(reply); + QStringList types = res.split(QChar(' ')); + eapSelect->insertItems(-1, types); +} + + +void NetworkConfig::useWps() +{ + if (wpagui == NULL) + return; + wpagui->setBssFromScan(bssid); + wpagui->wpsDialog(); + close(); +} diff --git a/wpa_supplicant/wpa_gui-qt4/networkconfig.h b/wpa_supplicant/wpa_gui-qt4/networkconfig.h new file mode 100644 index 000000000000..0ceeb417f028 --- /dev/null +++ b/wpa_supplicant/wpa_gui-qt4/networkconfig.h @@ -0,0 +1,61 @@ +/* + * wpa_gui - NetworkConfig class + * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef NETWORKCONFIG_H +#define NETWORKCONFIG_H + +#include <QObject> +#include "ui_networkconfig.h" + +class WpaGui; + +class NetworkConfig : public QDialog, public Ui::NetworkConfig +{ + Q_OBJECT + +public: + NetworkConfig(QWidget *parent = 0, const char *name = 0, + bool modal = false, Qt::WFlags fl = 0); + ~NetworkConfig(); + + virtual void paramsFromScanResults(QTreeWidgetItem *sel); + virtual void setWpaGui(WpaGui *_wpagui); + virtual int setNetworkParam(int id, const char *field, + const char *value, bool quote); + virtual void paramsFromConfig(int network_id); + virtual void newNetwork(); + +public slots: + virtual void authChanged(int sel); + virtual void addNetwork(); + virtual void encrChanged(const QString &sel); + virtual void writeWepKey(int network_id, QLineEdit *edit, int id); + virtual void removeNetwork(); + virtual void eapChanged(int sel); + virtual void useWps(); + +protected slots: + virtual void languageChange(); + +private: + WpaGui *wpagui; + int edit_network_id; + bool new_network; + QString bssid; + + virtual void wepEnabled(bool enabled); + virtual void getEapCapa(); +}; + +#endif /* NETWORKCONFIG_H */ diff --git a/wpa_supplicant/wpa_gui-qt4/networkconfig.ui b/wpa_supplicant/wpa_gui-qt4/networkconfig.ui new file mode 100644 index 000000000000..ede462f67d91 --- /dev/null +++ b/wpa_supplicant/wpa_gui-qt4/networkconfig.ui @@ -0,0 +1,425 @@ +<ui version="4.0" > + <class>NetworkConfig</class> + <widget class="QDialog" name="NetworkConfig" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>410</width> + <height>534</height> + </rect> + </property> + <property name="windowTitle" > + <string>NetworkConfig</string> + </property> + <layout class="QGridLayout" > + <item row="1" column="3" > + <widget class="QPushButton" name="cancelButton" > + <property name="text" > + <string>Cancel</string> + </property> + </widget> + </item> + <item row="0" column="0" colspan="4" > + <widget class="QFrame" name="frame9" > + <property name="frameShape" > + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow" > + <enum>QFrame::Plain</enum> + </property> + <layout class="QGridLayout" > + <item row="0" column="0" > + <widget class="QLabel" name="ssidLabel" > + <property name="text" > + <string>SSID</string> + </property> + </widget> + </item> + <item row="0" column="1" > + <widget class="QLineEdit" name="ssidEdit" > + <property name="toolTip" > + <string>Network name (Service Set IDentifier)</string> + </property> + <property name="text" > + <string/> + </property> + </widget> + </item> + <item row="1" column="0" > + <widget class="QLabel" name="authLabel" > + <property name="text" > + <string>Authentication</string> + </property> + </widget> + </item> + <item row="1" column="1" > + <widget class="QComboBox" name="authSelect" > + <item> + <property name="text" > + <string>Plaintext or static WEP</string> + </property> + </item> + <item> + <property name="text" > + <string>IEEE 802.1X</string> + </property> + </item> + <item> + <property name="text" > + <string>WPA-Personal (PSK)</string> + </property> + </item> + <item> + <property name="text" > + <string>WPA-Enterprise (EAP)</string> + </property> + </item> + <item> + <property name="text" > + <string>WPA2-Personal (PSK)</string> + </property> + </item> + <item> + <property name="text" > + <string>WPA2-Enterprise (EAP)</string> + </property> + </item> + </widget> + </item> + <item row="2" column="0" > + <widget class="QLabel" name="encrLabel" > + <property name="text" > + <string>Encryption</string> + </property> + </widget> + </item> + <item row="2" column="1" > + <widget class="QComboBox" name="encrSelect" > + <item> + <property name="text" > + <string>None</string> + </property> + </item> + <item> + <property name="text" > + <string>WEP</string> + </property> + </item> + <item> + <property name="text" > + <string>TKIP</string> + </property> + </item> + <item> + <property name="text" > + <string>CCMP</string> + </property> + </item> + </widget> + </item> + <item row="3" column="0" > + <widget class="QLabel" name="pskLabel" > + <property name="text" > + <string>PSK</string> + </property> + </widget> + </item> + <item row="3" column="1" > + <widget class="QLineEdit" name="pskEdit" > + <property name="enabled" > + <bool>false</bool> + </property> + <property name="toolTip" > + <string>WPA/WPA2 pre-shared key or passphrase</string> + </property> + <property name="whatsThis" > + <string/> + </property> + <property name="echoMode" > + <enum>QLineEdit::Password</enum> + </property> + </widget> + </item> + <item row="4" column="0" > + <widget class="QLabel" name="eapLabel" > + <property name="text" > + <string>EAP method</string> + </property> + </widget> + </item> + <item row="4" column="1" > + <widget class="QComboBox" name="eapSelect" > + <property name="enabled" > + <bool>false</bool> + </property> + </widget> + </item> + <item row="5" column="0" > + <widget class="QLabel" name="identityLabel" > + <property name="text" > + <string>Identity</string> + </property> + </widget> + </item> + <item row="5" column="1" > + <widget class="QLineEdit" name="identityEdit" > + <property name="enabled" > + <bool>false</bool> + </property> + <property name="toolTip" > + <string>Username/Identity for EAP methods</string> + </property> + </widget> + </item> + <item row="6" column="0" > + <widget class="QLabel" name="passwordLabel" > + <property name="text" > + <string>Password</string> + </property> + </widget> + </item> + <item row="6" column="1" > + <widget class="QLineEdit" name="passwordEdit" > + <property name="enabled" > + <bool>false</bool> + </property> + <property name="toolTip" > + <string>Password for EAP methods</string> + </property> + <property name="echoMode" > + <enum>QLineEdit::Password</enum> + </property> + </widget> + </item> + <item row="7" column="0" > + <widget class="QLabel" name="cacertLabel" > + <property name="text" > + <string>CA certificate</string> + </property> + </widget> + </item> + <item row="7" column="1" > + <widget class="QLineEdit" name="cacertEdit" > + <property name="enabled" > + <bool>false</bool> + </property> + </widget> + </item> + <item row="8" column="0" colspan="2" > + <widget class="QGroupBox" name="wepBox" > + <property name="enabled" > + <bool>true</bool> + </property> + <property name="title" > + <string>WEP keys</string> + </property> + <layout class="QGridLayout" > + <item row="0" column="0" > + <widget class="QRadioButton" name="wep0Radio" > + <property name="enabled" > + <bool>false</bool> + </property> + <property name="text" > + <string>key 0</string> + </property> + </widget> + </item> + <item row="1" column="0" > + <widget class="QRadioButton" name="wep1Radio" > + <property name="enabled" > + <bool>false</bool> + </property> + <property name="text" > + <string>key 1</string> + </property> + </widget> + </item> + <item row="3" column="0" > + <widget class="QRadioButton" name="wep3Radio" > + <property name="enabled" > + <bool>false</bool> + </property> + <property name="text" > + <string>key 3</string> + </property> + </widget> + </item> + <item row="2" column="0" > + <widget class="QRadioButton" name="wep2Radio" > + <property name="enabled" > + <bool>false</bool> + </property> + <property name="text" > + <string>key 2</string> + </property> + </widget> + </item> + <item row="0" column="1" > + <widget class="QLineEdit" name="wep0Edit" > + <property name="enabled" > + <bool>false</bool> + </property> + </widget> + </item> + <item row="1" column="1" > + <widget class="QLineEdit" name="wep1Edit" > + <property name="enabled" > + <bool>false</bool> + </property> + </widget> + </item> + <item row="2" column="1" > + <widget class="QLineEdit" name="wep2Edit" > + <property name="enabled" > + <bool>false</bool> + </property> + </widget> + </item> + <item row="3" column="1" > + <widget class="QLineEdit" name="wep3Edit" > + <property name="enabled" > + <bool>false</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="9" column="0" colspan="2" > + <widget class="QGroupBox" name="optionalSettingsBox" > + <property name="enabled" > + <bool>true</bool> + </property> + <property name="title" > + <string>Optional Settings</string> + </property> + <layout class="QGridLayout" > + <item row="0" column="1" > + <widget class="QLineEdit" name="idstrEdit" > + <property name="toolTip" > + <string>Network Identification String</string> + </property> + </widget> + </item> + <item row="0" column="3" > + <widget class="QSpinBox" name="prioritySpinBox" > + <property name="toolTip" > + <string>Network Priority</string> + </property> + <property name="maximum" > + <number>10000</number> + </property> + <property name="singleStep" > + <number>10</number> + </property> + </widget> + </item> + <item row="0" column="0" > + <widget class="QLabel" name="idstrLabel" > + <property name="text" > + <string>IDString</string> + </property> + </widget> + </item> + <item row="0" column="2" > + <widget class="QLabel" name="priorityLabel" > + <property name="text" > + <string>Priority</string> + </property> + </widget> + </item> + <item row="1" column="0" > + <widget class="QLabel" name="phase2Label" > + <property name="text" > + <string>Inner auth</string> + </property> + </widget> + </item> + <item row="1" column="1" > + <widget class="QComboBox" name="phase2Select" > + <property name="enabled" > + <bool>false</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </item> + <item row="1" column="2" > + <widget class="QPushButton" name="addButton" > + <property name="text" > + <string>Add</string> + </property> + </widget> + </item> + <item row="1" column="3" > + <widget class="QPushButton" name="removeButton" > + <property name="enabled" > + <bool>false</bool> + </property> + <property name="text" > + <string>Remove</string> + </property> + </widget> + </item> + <item row="1" column="0" > + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="1" > + <widget class="QPushButton" name="useWpsButton" > + <property name="enabled" > + <bool>false</bool> + </property> + <property name="text" > + <string>WPS</string> + </property> + </widget> + </item> + </layout> + </widget> + <layoutdefault spacing="6" margin="11" /> + <pixmapfunction></pixmapfunction> + <tabstops> + <tabstop>ssidEdit</tabstop> + <tabstop>authSelect</tabstop> + <tabstop>encrSelect</tabstop> + <tabstop>pskEdit</tabstop> + <tabstop>eapSelect</tabstop> + <tabstop>identityEdit</tabstop> + <tabstop>passwordEdit</tabstop> + <tabstop>cacertEdit</tabstop> + <tabstop>wep0Radio</tabstop> + <tabstop>wep0Edit</tabstop> + <tabstop>wep1Radio</tabstop> + <tabstop>wep1Edit</tabstop> + <tabstop>wep2Radio</tabstop> + <tabstop>wep2Edit</tabstop> + <tabstop>wep3Radio</tabstop> + <tabstop>wep3Edit</tabstop> + <tabstop>idstrEdit</tabstop> + <tabstop>prioritySpinBox</tabstop> + <tabstop>phase2Select</tabstop> + <tabstop>addButton</tabstop> + <tabstop>removeButton</tabstop> + <tabstop>cancelButton</tabstop> + </tabstops> + <includes> + <include location="global" >qtreewidget.h</include> + </includes> + <resources/> + <connections/> +</ui> diff --git a/wpa_supplicant/wpa_gui-qt4/scanresults.cpp b/wpa_supplicant/wpa_gui-qt4/scanresults.cpp new file mode 100644 index 000000000000..459aa8c69637 --- /dev/null +++ b/wpa_supplicant/wpa_gui-qt4/scanresults.cpp @@ -0,0 +1,144 @@ +/* + * wpa_gui - ScanResults class + * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include <cstdio> + +#include "scanresults.h" +#include "wpagui.h" +#include "networkconfig.h" + + +ScanResults::ScanResults(QWidget *parent, const char *, bool, Qt::WFlags) + : QDialog(parent) +{ + setupUi(this); + + connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); + connect(scanButton, SIGNAL(clicked()), this, SLOT(scanRequest())); + connect(scanResultsWidget, + SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, + SLOT(bssSelected(QTreeWidgetItem *))); + + wpagui = NULL; + scanResultsWidget->setItemsExpandable(FALSE); + scanResultsWidget->setRootIsDecorated(FALSE); +} + + +ScanResults::~ScanResults() +{ +} + + +void ScanResults::languageChange() +{ + retranslateUi(this); +} + + +void ScanResults::setWpaGui(WpaGui *_wpagui) +{ + wpagui = _wpagui; + updateResults(); +} + + +void ScanResults::updateResults() +{ + char reply[2048]; + size_t reply_len; + int index; + char cmd[20]; + + scanResultsWidget->clear(); + + index = 0; + while (wpagui) { + snprintf(cmd, sizeof(cmd), "BSS %d", index++); + if (index > 1000) + break; + + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) + break; + reply[reply_len] = '\0'; + + QString bss(reply); + if (bss.isEmpty() || bss.startsWith("FAIL")) + break; + + QString ssid, bssid, freq, signal, flags; + + QStringList lines = bss.split(QRegExp("\\n")); + for (QStringList::Iterator it = lines.begin(); + it != lines.end(); it++) { + int pos = (*it).indexOf('=') + 1; + if (pos < 1) + continue; + + if ((*it).startsWith("bssid=")) + bssid = (*it).mid(pos); + else if ((*it).startsWith("freq=")) + freq = (*it).mid(pos); + else if ((*it).startsWith("qual=")) + signal = (*it).mid(pos); + else if ((*it).startsWith("flags=")) + flags = (*it).mid(pos); + else if ((*it).startsWith("ssid=")) + ssid = (*it).mid(pos); + } + + QTreeWidgetItem *item = new QTreeWidgetItem(scanResultsWidget); + if (item) { + item->setText(0, ssid); + item->setText(1, bssid); + item->setText(2, freq); + item->setText(3, signal); + item->setText(4, flags); + } + + if (bssid.isEmpty()) + break; + } +} + + +void ScanResults::scanRequest() +{ + char reply[10]; + size_t reply_len = sizeof(reply); + + if (wpagui == NULL) + return; + + wpagui->ctrlRequest("SCAN", reply, &reply_len); +} + + +void ScanResults::getResults() +{ + updateResults(); +} + + +void ScanResults::bssSelected(QTreeWidgetItem *sel) +{ + NetworkConfig *nc = new NetworkConfig(); + if (nc == NULL) + return; + nc->setWpaGui(wpagui); + nc->paramsFromScanResults(sel); + nc->show(); + nc->exec(); +} diff --git a/wpa_supplicant/wpa_gui-qt4/scanresults.h b/wpa_supplicant/wpa_gui-qt4/scanresults.h new file mode 100644 index 000000000000..2c4a1b0ace11 --- /dev/null +++ b/wpa_supplicant/wpa_gui-qt4/scanresults.h @@ -0,0 +1,46 @@ +/* + * wpa_gui - ScanResults class + * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef SCANRESULTS_H +#define SCANRESULTS_H + +#include <QObject> +#include "ui_scanresults.h" + +class WpaGui; + +class ScanResults : public QDialog, public Ui::ScanResults +{ + Q_OBJECT + +public: + ScanResults(QWidget *parent = 0, const char *name = 0, + bool modal = false, Qt::WFlags fl = 0); + ~ScanResults(); + +public slots: + virtual void setWpaGui(WpaGui *_wpagui); + virtual void updateResults(); + virtual void scanRequest(); + virtual void getResults(); + virtual void bssSelected(QTreeWidgetItem *sel); + +protected slots: + virtual void languageChange(); + +private: + WpaGui *wpagui; +}; + +#endif /* SCANRESULTS_H */ diff --git a/wpa_supplicant/wpa_gui-qt4/scanresults.ui b/wpa_supplicant/wpa_gui-qt4/scanresults.ui new file mode 100644 index 000000000000..81e405efc319 --- /dev/null +++ b/wpa_supplicant/wpa_gui-qt4/scanresults.ui @@ -0,0 +1,94 @@ +<ui version="4.0" > + <class>ScanResults</class> + <widget class="QDialog" name="ScanResults" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>452</width> + <height>244</height> + </rect> + </property> + <property name="windowTitle" > + <string>Scan results</string> + </property> + <layout class="QVBoxLayout" > + <item> + <widget class="QTreeWidget" name="scanResultsWidget" > + <property name="editTriggers" > + <set>QAbstractItemView::NoEditTriggers</set> + </property> + <property name="uniformRowHeights" > + <bool>true</bool> + </property> + <property name="sortingEnabled" > + <bool>true</bool> + </property> + <property name="columnCount" > + <number>5</number> + </property> + <column> + <property name="text" > + <string>SSID</string> + </property> + </column> + <column> + <property name="text" > + <string>BSSID</string> + </property> + </column> + <column> + <property name="text" > + <string>frequency</string> + </property> + </column> + <column> + <property name="text" > + <string>signal</string> + </property> + </column> + <column> + <property name="text" > + <string>flags</string> + </property> + </column> + </widget> + </item> + <item> + <layout class="QHBoxLayout" > + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="scanButton" > + <property name="text" > + <string>Scan</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="closeButton" > + <property name="text" > + <string>Close</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <layoutdefault spacing="6" margin="11" /> + <pixmapfunction></pixmapfunction> + <resources/> + <connections/> +</ui> diff --git a/wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp b/wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp new file mode 100644 index 000000000000..42fbdbc7b4e4 --- /dev/null +++ b/wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp @@ -0,0 +1,100 @@ +/* + * wpa_gui - UserDataRequest class + * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "userdatarequest.h" +#include "wpagui.h" +#include "wpa_ctrl.h" + + +UserDataRequest::UserDataRequest(QWidget *parent, const char *, bool, + Qt::WFlags) + : QDialog(parent) +{ + setupUi(this); + + connect(buttonOk, SIGNAL(clicked()), this, SLOT(sendReply())); + connect(buttonCancel, SIGNAL(clicked()), this, SLOT(reject())); + connect(queryEdit, SIGNAL(returnPressed()), this, SLOT(sendReply())); +} + + +UserDataRequest::~UserDataRequest() +{ +} + + +void UserDataRequest::languageChange() +{ + retranslateUi(this); +} + + +int UserDataRequest::setParams(WpaGui *_wpagui, const char *reqMsg) +{ + char *tmp, *pos, *pos2; + wpagui = _wpagui; + tmp = strdup(reqMsg); + if (tmp == NULL) + return -1; + pos = strchr(tmp, '-'); + if (pos == NULL) { + free(tmp); + return -1; + } + *pos++ = '\0'; + field = tmp; + pos2 = strchr(pos, ':'); + if (pos2 == NULL) { + free(tmp); + return -1; + } + *pos2++ = '\0'; + + networkid = atoi(pos); + queryInfo->setText(pos2); + if (strcmp(tmp, "PASSWORD") == 0) { + queryField->setText("Password: "); + queryEdit->setEchoMode(QLineEdit::Password); + } else if (strcmp(tmp, "NEW_PASSWORD") == 0) { + queryField->setText("New password: "); + queryEdit->setEchoMode(QLineEdit::Password); + } else if (strcmp(tmp, "IDENTITY") == 0) + queryField->setText("Identity: "); + else if (strcmp(tmp, "PASSPHRASE") == 0) { + queryField->setText("Private key passphrase: "); + queryEdit->setEchoMode(QLineEdit::Password); + } else + queryField->setText(field + ":"); + free(tmp); + + return 0; +} + + +void UserDataRequest::sendReply() +{ + char reply[10]; + size_t reply_len = sizeof(reply); + + if (wpagui == NULL) { + reject(); + return; + } + + QString cmd = QString(WPA_CTRL_RSP) + field + '-' + + QString::number(networkid) + ':' + + queryEdit->text(); + wpagui->ctrlRequest(cmd.toAscii().constData(), reply, &reply_len); + accept(); +} diff --git a/wpa_supplicant/wpa_gui-qt4/userdatarequest.h b/wpa_supplicant/wpa_gui-qt4/userdatarequest.h new file mode 100644 index 000000000000..2b6e8371bc65 --- /dev/null +++ b/wpa_supplicant/wpa_gui-qt4/userdatarequest.h @@ -0,0 +1,46 @@ +/* + * wpa_gui - UserDataRequest class + * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef USERDATAREQUEST_H +#define USERDATAREQUEST_H + +#include <QObject> +#include "ui_userdatarequest.h" + +class WpaGui; + +class UserDataRequest : public QDialog, public Ui::UserDataRequest +{ + Q_OBJECT + +public: + UserDataRequest(QWidget *parent = 0, const char *name = 0, + bool modal = false, Qt::WFlags fl = 0); + ~UserDataRequest(); + + int setParams(WpaGui *_wpagui, const char *reqMsg); + +public slots: + virtual void sendReply(); + +protected slots: + virtual void languageChange(); + +private: + WpaGui *wpagui; + int networkid; + QString field; +}; + +#endif /* USERDATAREQUEST_H */ diff --git a/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui b/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui new file mode 100644 index 000000000000..1de2a26da1cd --- /dev/null +++ b/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui @@ -0,0 +1,109 @@ +<ui version="4.0" stdsetdef="1" > + <author></author> + <comment></comment> + <exportmacro></exportmacro> + <class>UserDataRequest</class> + <widget class="QDialog" name="UserDataRequest" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>216</width> + <height>103</height> + </rect> + </property> + <property name="windowTitle" > + <string>Authentication credentials required</string> + </property> + <property name="sizeGripEnabled" > + <bool>true</bool> + </property> + <layout class="QVBoxLayout" > + <item> + <widget class="QLabel" name="queryInfo" > + <property name="text" > + <string/> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" > + <property name="margin" > + <number>0</number> + </property> + <item> + <widget class="QLabel" name="queryField" > + <property name="text" > + <string/> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="queryEdit" > + <property name="enabled" > + <bool>true</bool> + </property> + <property name="echoMode" > + <enum>QLineEdit::Password</enum> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" > + <property name="margin" > + <number>0</number> + </property> + <item> + <spacer name="spacer4" > + <property name="sizeHint" > + <size> + <width>20</width> + <height>20</height> + </size> + </property> + <property name="sizeType" > + <enum>Expanding</enum> + </property> + <property name="orientation" > + <enum>Horizontal</enum> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="buttonOk" > + <property name="text" > + <string>&OK</string> + </property> + <property name="shortcut" > + <string/> + </property> + <property name="autoDefault" > + <bool>true</bool> + </property> + <property name="default" > + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="buttonCancel" > + <property name="text" > + <string>&Cancel</string> + </property> + <property name="shortcut" > + <string/> + </property> + <property name="autoDefault" > + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <layoutdefault spacing="6" margin="11" /> + <pixmapfunction></pixmapfunction> +</ui> diff --git a/wpa_supplicant/wpa_gui-qt4/wpa_gui.desktop b/wpa_supplicant/wpa_gui-qt4/wpa_gui.desktop new file mode 100644 index 000000000000..ccc7d8741d02 --- /dev/null +++ b/wpa_supplicant/wpa_gui-qt4/wpa_gui.desktop @@ -0,0 +1,10 @@ +[Desktop Entry] +Version=1.0 +Name=wpa_gui +Comment=Graphical user interface for wpa_supplicant +Exec=wpa_gui +Icon=wpa_gui +GenericName=wpa_supplicant user interface +Terminal=false +Type=Application +Categories=Qt;Network; diff --git a/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro b/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro new file mode 100644 index 000000000000..2317cbd48d04 --- /dev/null +++ b/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro @@ -0,0 +1,62 @@ +TEMPLATE = app +LANGUAGE = C++ + +CONFIG += qt warn_on release + +DEFINES += CONFIG_CTRL_IFACE + +win32 { + LIBS += -lws2_32 -static + DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE + SOURCES += ../../src/utils/os_win32.c +} else:win32-g++ { + # cross compilation to win32 + LIBS += -lws2_32 -static -mwindows + DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE + SOURCES += ../../src/utils/os_win32.c + RESOURCES += icons_png.qrc +} else:win32-x-g++ { + # cross compilation to win32 + LIBS += -lws2_32 -static -mwindows + DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE + DEFINES += _X86_ + SOURCES += ../../src/utils/os_win32.c + RESOURCES += icons_png.qrc +} else { + DEFINES += CONFIG_CTRL_IFACE_UNIX + SOURCES += ../../src/utils/os_unix.c +} + +INCLUDEPATH += . .. ../../src/utils ../../src/common + +HEADERS += wpamsg.h \ + wpagui.h \ + eventhistory.h \ + scanresults.h \ + userdatarequest.h \ + networkconfig.h \ + addinterface.h + +SOURCES += main.cpp \ + wpagui.cpp \ + eventhistory.cpp \ + scanresults.cpp \ + userdatarequest.cpp \ + networkconfig.cpp \ + addinterface.cpp \ + ../../src/common/wpa_ctrl.c + +RESOURCES += icons.qrc + +FORMS = wpagui.ui \ + eventhistory.ui \ + scanresults.ui \ + userdatarequest.ui \ + networkconfig.ui + + +unix { + UI_DIR = .ui + MOC_DIR = .moc + OBJECTS_DIR = .obj +} diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp new file mode 100644 index 000000000000..dcd33b9450f2 --- /dev/null +++ b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp @@ -0,0 +1,1699 @@ +/* + * wpa_gui - WpaGui class + * Copyright (c) 2005-2008, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifdef __MINGW32__ +/* Need to get getopt() */ +#include <unistd.h> +#endif + +#ifdef CONFIG_NATIVE_WINDOWS +#include <windows.h> +#endif /* CONFIG_NATIVE_WINDOWS */ + +#include <cstdio> +#include <QMessageBox> +#include <QCloseEvent> +#include <QImageReader> +#include <QSettings> + +#include "wpagui.h" +#include "dirent.h" +#include "wpa_ctrl.h" +#include "userdatarequest.h" +#include "networkconfig.h" + +#if 1 +/* Silence stdout */ +#define printf wpagui_printf +static int wpagui_printf(const char *, ...) +{ + return 0; +} +#endif + +WpaGui::WpaGui(QApplication *_app, QWidget *parent, const char *, Qt::WFlags) + : QMainWindow(parent), app(_app) +{ + setupUi(this); + +#ifdef CONFIG_NATIVE_WINDOWS + fileStopServiceAction = new QAction(this); + fileStopServiceAction->setObjectName("Stop Service"); + fileStopServiceAction->setIconText("Stop Service"); + fileMenu->insertAction(actionWPS, fileStopServiceAction); + + fileStartServiceAction = new QAction(this); + fileStartServiceAction->setObjectName("Start Service"); + fileStartServiceAction->setIconText("Start Service"); + fileMenu->insertAction(fileStopServiceAction, fileStartServiceAction); + + connect(fileStartServiceAction, SIGNAL(triggered()), this, + SLOT(startService())); + connect(fileStopServiceAction, SIGNAL(triggered()), this, + SLOT(stopService())); + + addInterfaceAction = new QAction(this); + addInterfaceAction->setIconText("Add Interface"); + fileMenu->insertAction(fileStartServiceAction, addInterfaceAction); + + connect(addInterfaceAction, SIGNAL(triggered()), this, + SLOT(addInterface())); +#endif /* CONFIG_NATIVE_WINDOWS */ + + (void) statusBar(); + + /* + * Disable WPS tab by default; it will be enabled if wpa_supplicant is + * built with WPS support. + */ + wpsTab->setEnabled(false); + wpaguiTab->setTabEnabled(wpaguiTab->indexOf(wpsTab), false); + + connect(fileEventHistoryAction, SIGNAL(triggered()), this, + SLOT(eventHistory())); + connect(fileSaveConfigAction, SIGNAL(triggered()), this, + SLOT(saveConfig())); + connect(actionWPS, SIGNAL(triggered()), this, SLOT(wpsDialog())); + connect(fileExitAction, SIGNAL(triggered()), qApp, SLOT(quit())); + connect(networkAddAction, SIGNAL(triggered()), this, + SLOT(addNetwork())); + connect(networkEditAction, SIGNAL(triggered()), this, + SLOT(editSelectedNetwork())); + connect(networkRemoveAction, SIGNAL(triggered()), this, + SLOT(removeSelectedNetwork())); + connect(networkEnableAllAction, SIGNAL(triggered()), this, + SLOT(enableAllNetworks())); + connect(networkDisableAllAction, SIGNAL(triggered()), this, + SLOT(disableAllNetworks())); + connect(networkRemoveAllAction, SIGNAL(triggered()), this, + SLOT(removeAllNetworks())); + connect(helpIndexAction, SIGNAL(triggered()), this, SLOT(helpIndex())); + connect(helpContentsAction, SIGNAL(triggered()), this, + SLOT(helpContents())); + connect(helpAboutAction, SIGNAL(triggered()), this, SLOT(helpAbout())); + connect(disconnectButton, SIGNAL(clicked()), this, SLOT(disconnect())); + connect(scanButton, SIGNAL(clicked()), this, SLOT(scan())); + connect(connectButton, SIGNAL(clicked()), this, SLOT(connectB())); + connect(adapterSelect, SIGNAL(activated(const QString&)), this, + SLOT(selectAdapter(const QString&))); + connect(networkSelect, SIGNAL(activated(const QString&)), this, + SLOT(selectNetwork(const QString&))); + connect(addNetworkButton, SIGNAL(clicked()), this, SLOT(addNetwork())); + connect(editNetworkButton, SIGNAL(clicked()), this, + SLOT(editListedNetwork())); + connect(removeNetworkButton, SIGNAL(clicked()), this, + SLOT(removeListedNetwork())); + connect(networkList, SIGNAL(itemSelectionChanged()), this, + SLOT(updateNetworkDisabledStatus())); + connect(enableRadioButton, SIGNAL(toggled(bool)), this, + SLOT(enableListedNetwork(bool))); + connect(disableRadioButton, SIGNAL(toggled(bool)), this, + SLOT(disableListedNetwork(bool))); + connect(scanNetworkButton, SIGNAL(clicked()), this, SLOT(scan())); + connect(networkList, SIGNAL(itemDoubleClicked(QListWidgetItem *)), + this, SLOT(editListedNetwork())); + connect(wpaguiTab, SIGNAL(currentChanged(int)), this, + SLOT(tabChanged(int))); + connect(wpsPbcButton, SIGNAL(clicked()), this, SLOT(wpsPbc())); + connect(wpsPinButton, SIGNAL(clicked()), this, SLOT(wpsGeneratePin())); + connect(wpsApPinEdit, SIGNAL(textChanged(const QString &)), this, + SLOT(wpsApPinChanged(const QString &))); + connect(wpsApPinButton, SIGNAL(clicked()), this, SLOT(wpsApPin())); + + eh = NULL; + scanres = NULL; + add_iface = NULL; + udr = NULL; + tray_icon = NULL; + startInTray = false; + ctrl_iface = NULL; + ctrl_conn = NULL; + monitor_conn = NULL; + msgNotifier = NULL; + ctrl_iface_dir = strdup("/var/run/wpa_supplicant"); + + parse_argv(); + + if (app->isSessionRestored()) { + QSettings settings("wpa_supplicant", "wpa_gui"); + settings.beginGroup("state"); + if (app->sessionId().compare(settings.value("session_id"). + toString()) == 0) + startInTray = settings.value("in_tray").toBool(); + settings.endGroup(); + } + + if (QSystemTrayIcon::isSystemTrayAvailable()) + createTrayIcon(startInTray); + else + show(); + + connectedToService = false; + textStatus->setText("connecting to wpa_supplicant"); + timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), SLOT(ping())); + timer->setSingleShot(FALSE); + timer->start(1000); + + if (openCtrlConnection(ctrl_iface) < 0) { + printf("Failed to open control connection to " + "wpa_supplicant.\n"); + } + + updateStatus(); + networkMayHaveChanged = true; + updateNetworks(); +} + + +WpaGui::~WpaGui() +{ + delete msgNotifier; + + if (monitor_conn) { + wpa_ctrl_detach(monitor_conn); + wpa_ctrl_close(monitor_conn); + monitor_conn = NULL; + } + if (ctrl_conn) { + wpa_ctrl_close(ctrl_conn); + ctrl_conn = NULL; + } + + if (eh) { + eh->close(); + delete eh; + eh = NULL; + } + + if (scanres) { + scanres->close(); + delete scanres; + scanres = NULL; + } + + if (add_iface) { + add_iface->close(); + delete add_iface; + add_iface = NULL; + } + + if (udr) { + udr->close(); + delete udr; + udr = NULL; + } + + free(ctrl_iface); + ctrl_iface = NULL; + + free(ctrl_iface_dir); + ctrl_iface_dir = NULL; +} + + +void WpaGui::languageChange() +{ + retranslateUi(this); +} + + +void WpaGui::parse_argv() +{ + int c; + for (;;) { + c = getopt(qApp->argc(), qApp->argv(), "i:p:t"); + if (c < 0) + break; + switch (c) { + case 'i': + free(ctrl_iface); + ctrl_iface = strdup(optarg); + break; + case 'p': + free(ctrl_iface_dir); + ctrl_iface_dir = strdup(optarg); + break; + case 't': + startInTray = true; + break; + } + } +} + + +int WpaGui::openCtrlConnection(const char *ifname) +{ + char *cfile; + int flen; + char buf[2048], *pos, *pos2; + size_t len; + + if (ifname) { + if (ifname != ctrl_iface) { + free(ctrl_iface); + ctrl_iface = strdup(ifname); + } + } else { +#ifdef CONFIG_CTRL_IFACE_UDP + free(ctrl_iface); + ctrl_iface = strdup("udp"); +#endif /* CONFIG_CTRL_IFACE_UDP */ +#ifdef CONFIG_CTRL_IFACE_UNIX + struct dirent *dent; + DIR *dir = opendir(ctrl_iface_dir); + free(ctrl_iface); + ctrl_iface = NULL; + if (dir) { + 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; + printf("Selected interface '%s'\n", + dent->d_name); + ctrl_iface = strdup(dent->d_name); + break; + } + closedir(dir); + } +#endif /* CONFIG_CTRL_IFACE_UNIX */ +#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE + struct wpa_ctrl *ctrl; + int ret; + + free(ctrl_iface); + ctrl_iface = NULL; + + ctrl = wpa_ctrl_open(NULL); + if (ctrl) { + len = sizeof(buf) - 1; + ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf, + &len, NULL); + if (ret >= 0) { + connectedToService = true; + buf[len] = '\0'; + pos = strchr(buf, '\n'); + if (pos) + *pos = '\0'; + ctrl_iface = strdup(buf); + } + wpa_ctrl_close(ctrl); + } +#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ + } + + if (ctrl_iface == NULL) { +#ifdef CONFIG_NATIVE_WINDOWS + static bool first = true; + if (first && !serviceRunning()) { + first = false; + if (QMessageBox::warning( + this, qAppName(), + "wpa_supplicant service is not running.\n" + "Do you want to start it?", + QMessageBox::Yes | QMessageBox::No) == + QMessageBox::Yes) + startService(); + } +#endif /* CONFIG_NATIVE_WINDOWS */ + return -1; + } + +#ifdef CONFIG_CTRL_IFACE_UNIX + flen = strlen(ctrl_iface_dir) + strlen(ctrl_iface) + 2; + cfile = (char *) malloc(flen); + if (cfile == NULL) + return -1; + snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ctrl_iface); +#else /* CONFIG_CTRL_IFACE_UNIX */ + flen = strlen(ctrl_iface) + 1; + cfile = (char *) malloc(flen); + if (cfile == NULL) + return -1; + snprintf(cfile, flen, "%s", ctrl_iface); +#endif /* CONFIG_CTRL_IFACE_UNIX */ + + if (ctrl_conn) { + wpa_ctrl_close(ctrl_conn); + ctrl_conn = NULL; + } + + if (monitor_conn) { + delete msgNotifier; + msgNotifier = NULL; + wpa_ctrl_detach(monitor_conn); + wpa_ctrl_close(monitor_conn); + monitor_conn = NULL; + } + + printf("Trying to connect to '%s'\n", cfile); + ctrl_conn = wpa_ctrl_open(cfile); + if (ctrl_conn == NULL) { + free(cfile); + return -1; + } + monitor_conn = wpa_ctrl_open(cfile); + free(cfile); + if (monitor_conn == NULL) { + wpa_ctrl_close(ctrl_conn); + return -1; + } + if (wpa_ctrl_attach(monitor_conn)) { + printf("Failed to attach to wpa_supplicant\n"); + wpa_ctrl_close(monitor_conn); + monitor_conn = NULL; + wpa_ctrl_close(ctrl_conn); + ctrl_conn = NULL; + return -1; + } + +#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP) + msgNotifier = new QSocketNotifier(wpa_ctrl_get_fd(monitor_conn), + QSocketNotifier::Read, this); + connect(msgNotifier, SIGNAL(activated(int)), SLOT(receiveMsgs())); +#endif + + adapterSelect->clear(); + adapterSelect->addItem(ctrl_iface); + adapterSelect->setCurrentIndex(0); + + len = sizeof(buf) - 1; + if (wpa_ctrl_request(ctrl_conn, "INTERFACES", 10, buf, &len, NULL) >= + 0) { + buf[len] = '\0'; + pos = buf; + while (*pos) { + pos2 = strchr(pos, '\n'); + if (pos2) + *pos2 = '\0'; + if (strcmp(pos, ctrl_iface) != 0) + adapterSelect->addItem(pos); + if (pos2) + pos = pos2 + 1; + else + break; + } + } + + len = sizeof(buf) - 1; + if (wpa_ctrl_request(ctrl_conn, "GET_CAPABILITY eap", 18, buf, &len, + NULL) >= 0) { + buf[len] = '\0'; + + QString res(buf); + QStringList types = res.split(QChar(' ')); + bool wps = types.contains("WSC"); + actionWPS->setEnabled(wps); + wpsTab->setEnabled(wps); + wpaguiTab->setTabEnabled(wpaguiTab->indexOf(wpsTab), wps); + } + + return 0; +} + + +static void wpa_gui_msg_cb(char *msg, size_t) +{ + /* This should not happen anymore since two control connections are + * used. */ + printf("missed message: %s\n", msg); +} + + +int WpaGui::ctrlRequest(const char *cmd, char *buf, size_t *buflen) +{ + int ret; + + if (ctrl_conn == NULL) + return -3; + ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, buflen, + wpa_gui_msg_cb); + if (ret == -2) + printf("'%s' command timed out.\n", cmd); + else if (ret < 0) + printf("'%s' command failed.\n", cmd); + + return ret; +} + + +void WpaGui::updateStatus() +{ + char buf[2048], *start, *end, *pos; + size_t len; + + pingsToStatusUpdate = 10; + + len = sizeof(buf) - 1; + if (ctrl_conn == NULL || ctrlRequest("STATUS", buf, &len) < 0) { + textStatus->setText("Could not get status from " + "wpa_supplicant"); + textAuthentication->clear(); + textEncryption->clear(); + textSsid->clear(); + textBssid->clear(); + textIpAddress->clear(); + +#ifdef CONFIG_NATIVE_WINDOWS + static bool first = true; + if (first && connectedToService && + (ctrl_iface == NULL || *ctrl_iface == '\0')) { + first = false; + if (QMessageBox::information( + this, qAppName(), + "No network interfaces in use.\n" + "Would you like to add one?", + QMessageBox::Yes | QMessageBox::No) == + QMessageBox::Yes) + addInterface(); + } +#endif /* CONFIG_NATIVE_WINDOWS */ + return; + } + + buf[len] = '\0'; + + bool auth_updated = false, ssid_updated = false; + bool bssid_updated = false, ipaddr_updated = false; + bool status_updated = false; + char *pairwise_cipher = NULL, *group_cipher = NULL; + + start = buf; + while (*start) { + bool last = false; + end = strchr(start, '\n'); + if (end == NULL) { + last = true; + end = start; + while (end[0] && end[1]) + end++; + } + *end = '\0'; + + pos = strchr(start, '='); + if (pos) { + *pos++ = '\0'; + if (strcmp(start, "bssid") == 0) { + bssid_updated = true; + textBssid->setText(pos); + } else if (strcmp(start, "ssid") == 0) { + ssid_updated = true; + textSsid->setText(pos); + } else if (strcmp(start, "ip_address") == 0) { + ipaddr_updated = true; + textIpAddress->setText(pos); + } else if (strcmp(start, "wpa_state") == 0) { + status_updated = true; + textStatus->setText(pos); + } else if (strcmp(start, "key_mgmt") == 0) { + auth_updated = true; + textAuthentication->setText(pos); + /* TODO: could add EAP status to this */ + } else if (strcmp(start, "pairwise_cipher") == 0) { + pairwise_cipher = pos; + } else if (strcmp(start, "group_cipher") == 0) { + group_cipher = pos; + } + } + + if (last) + break; + start = end + 1; + } + + if (pairwise_cipher || group_cipher) { + QString encr; + if (pairwise_cipher && group_cipher && + strcmp(pairwise_cipher, group_cipher) != 0) { + encr.append(pairwise_cipher); + encr.append(" + "); + encr.append(group_cipher); + } else if (pairwise_cipher) { + encr.append(pairwise_cipher); + } else { + encr.append(group_cipher); + encr.append(" [group key only]"); + } + textEncryption->setText(encr); + } else + textEncryption->clear(); + + if (!status_updated) + textStatus->clear(); + if (!auth_updated) + textAuthentication->clear(); + if (!ssid_updated) + textSsid->clear(); + if (!bssid_updated) + textBssid->clear(); + if (!ipaddr_updated) + textIpAddress->clear(); +} + + +void WpaGui::updateNetworks() +{ + char buf[2048], *start, *end, *id, *ssid, *bssid, *flags; + size_t len; + int first_active = -1; + int was_selected = -1; + bool current = false; + + if (!networkMayHaveChanged) + return; + + if (networkList->currentRow() >= 0) + was_selected = networkList->currentRow(); + + networkSelect->clear(); + networkList->clear(); + + if (ctrl_conn == NULL) + return; + + len = sizeof(buf) - 1; + if (ctrlRequest("LIST_NETWORKS", buf, &len) < 0) + return; + + buf[len] = '\0'; + start = strchr(buf, '\n'); + if (start == NULL) + return; + start++; + + while (*start) { + bool last = false; + end = strchr(start, '\n'); + if (end == NULL) { + last = true; + end = start; + while (end[0] && end[1]) + end++; + } + *end = '\0'; + + id = start; + ssid = strchr(id, '\t'); + if (ssid == NULL) + break; + *ssid++ = '\0'; + bssid = strchr(ssid, '\t'); + if (bssid == NULL) + break; + *bssid++ = '\0'; + flags = strchr(bssid, '\t'); + if (flags == NULL) + break; + *flags++ = '\0'; + + QString network(id); + network.append(": "); + network.append(ssid); + networkSelect->addItem(network); + networkList->addItem(network); + + if (strstr(flags, "[CURRENT]")) { + networkSelect->setCurrentIndex(networkSelect->count() - + 1); + current = true; + } else if (first_active < 0 && + strstr(flags, "[DISABLED]") == NULL) + first_active = networkSelect->count() - 1; + + if (last) + break; + start = end + 1; + } + + if (networkSelect->count() > 1) + networkSelect->addItem("Select any network"); + + if (!current && first_active >= 0) + networkSelect->setCurrentIndex(first_active); + + if (was_selected >= 0 && networkList->count() > 0) { + if (was_selected < networkList->count()) + networkList->setCurrentRow(was_selected); + else + networkList->setCurrentRow(networkList->count() - 1); + } + else + networkList->setCurrentRow(networkSelect->currentIndex()); + + networkMayHaveChanged = false; +} + + +void WpaGui::helpIndex() +{ + printf("helpIndex\n"); +} + + +void WpaGui::helpContents() +{ + printf("helpContents\n"); +} + + +void WpaGui::helpAbout() +{ + QMessageBox::about(this, "wpa_gui for wpa_supplicant", + "Copyright (c) 2003-2008,\n" + "Jouni Malinen <j@w1.fi>\n" + "and contributors.\n" + "\n" + "This program is free software. You can\n" + "distribute it and/or modify it under the terms " + "of\n" + "the GNU General Public License version 2.\n" + "\n" + "Alternatively, this software may be distributed\n" + "under the terms of the BSD license.\n" + "\n" + "This product includes software developed\n" + "by the OpenSSL Project for use in the\n" + "OpenSSL Toolkit (http://www.openssl.org/)\n"); +} + + +void WpaGui::disconnect() +{ + char reply[10]; + size_t reply_len = sizeof(reply); + ctrlRequest("DISCONNECT", reply, &reply_len); + stopWpsRun(false); +} + + +void WpaGui::scan() +{ + if (scanres) { + scanres->close(); + delete scanres; + } + + scanres = new ScanResults(); + if (scanres == NULL) + return; + scanres->setWpaGui(this); + scanres->show(); + scanres->exec(); +} + + +void WpaGui::eventHistory() +{ + if (eh) { + eh->close(); + delete eh; + } + + eh = new EventHistory(); + if (eh == NULL) + return; + eh->addEvents(msgs); + eh->show(); + eh->exec(); +} + + +void WpaGui::ping() +{ + char buf[10]; + size_t len; + +#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE + /* + * QSocketNotifier cannot be used with Windows named pipes, so use a + * timer to check for received messages for now. This could be + * optimized be doing something specific to named pipes or Windows + * events, but it is not clear what would be the best way of doing that + * in Qt. + */ + receiveMsgs(); +#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ + + if (scanres && !scanres->isVisible()) { + delete scanres; + scanres = NULL; + } + + if (eh && !eh->isVisible()) { + delete eh; + eh = NULL; + } + + if (udr && !udr->isVisible()) { + delete udr; + udr = NULL; + } + + len = sizeof(buf) - 1; + if (ctrlRequest("PING", buf, &len) < 0) { + printf("PING failed - trying to reconnect\n"); + if (openCtrlConnection(ctrl_iface) >= 0) { + printf("Reconnected successfully\n"); + pingsToStatusUpdate = 0; + } + } + + pingsToStatusUpdate--; + if (pingsToStatusUpdate <= 0) { + updateStatus(); + updateNetworks(); + } + +#ifndef CONFIG_CTRL_IFACE_NAMED_PIPE + /* Use less frequent pings and status updates when the main window is + * hidden (running in taskbar). */ + int interval = isHidden() ? 5000 : 1000; + if (timer->interval() != interval) + timer->setInterval(interval); +#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ +} + + +static int str_match(const char *a, const char *b) +{ + return strncmp(a, b, strlen(b)) == 0; +} + + +void WpaGui::processMsg(char *msg) +{ + char *pos = msg, *pos2; + int priority = 2; + + if (*pos == '<') { + /* skip priority */ + pos++; + priority = atoi(pos); + pos = strchr(pos, '>'); + if (pos) + pos++; + else + pos = msg; + } + + WpaMsg wm(pos, priority); + if (eh) + eh->addEvent(wm); + msgs.append(wm); + while (msgs.count() > 100) + msgs.pop_front(); + + /* Update last message with truncated version of the event */ + if (strncmp(pos, "CTRL-", 5) == 0) { + pos2 = strchr(pos, str_match(pos, WPA_CTRL_REQ) ? ':' : ' '); + if (pos2) + pos2++; + else + pos2 = pos; + } else + pos2 = pos; + QString lastmsg = pos2; + lastmsg.truncate(40); + textLastMessage->setText(lastmsg); + + pingsToStatusUpdate = 0; + networkMayHaveChanged = true; + + if (str_match(pos, WPA_CTRL_REQ)) + processCtrlReq(pos + strlen(WPA_CTRL_REQ)); + else if (str_match(pos, WPA_EVENT_SCAN_RESULTS) && scanres) + scanres->updateResults(); + else if (str_match(pos, WPA_EVENT_DISCONNECTED)) + showTrayMessage(QSystemTrayIcon::Information, 3, + "Disconnected from network."); + else if (str_match(pos, WPA_EVENT_CONNECTED)) { + showTrayMessage(QSystemTrayIcon::Information, 3, + "Connection to network established."); + QTimer::singleShot(5 * 1000, this, SLOT(showTrayStatus())); + stopWpsRun(true); + } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_PBC)) { + showTrayMessage(QSystemTrayIcon::Information, 3, + "Wi-Fi Protected Setup (WPS) AP\n" + "in active PBC mode found."); + wpsStatusText->setText("WPS AP in active PBC mode found"); + wpaguiTab->setCurrentWidget(wpsTab); + wpsInstructions->setText("Press the PBC button on the screen " + "to start registration"); + } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_PIN)) { + showTrayMessage(QSystemTrayIcon::Information, 3, + "Wi-Fi Protected Setup (WPS) AP\n" + " in active PIN mode found."); + wpsStatusText->setText("WPS AP with recently selected " + "registrar"); + wpaguiTab->setCurrentWidget(wpsTab); + } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE)) { + showTrayMessage(QSystemTrayIcon::Information, 3, + "Wi-Fi Protected Setup (WPS)\n" + "AP detected."); + wpsStatusText->setText("WPS AP detected"); + wpaguiTab->setCurrentWidget(wpsTab); + } else if (str_match(pos, WPS_EVENT_OVERLAP)) { + showTrayMessage(QSystemTrayIcon::Information, 3, + "Wi-Fi Protected Setup (WPS)\n" + "PBC mode overlap detected."); + wpsStatusText->setText("PBC mode overlap detected"); + wpsInstructions->setText("More than one AP is currently in " + "active WPS PBC mode. Wait couple of " + "minutes and try again"); + wpaguiTab->setCurrentWidget(wpsTab); + } else if (str_match(pos, WPS_EVENT_CRED_RECEIVED)) { + wpsStatusText->setText("Network configuration received"); + wpaguiTab->setCurrentWidget(wpsTab); + } else if (str_match(pos, WPA_EVENT_EAP_METHOD)) { + if (strstr(pos, "(WSC)")) + wpsStatusText->setText("Registration started"); + } else if (str_match(pos, WPS_EVENT_M2D)) { + wpsStatusText->setText("Registrar does not yet know PIN"); + } else if (str_match(pos, WPS_EVENT_FAIL)) { + wpsStatusText->setText("Registration failed"); + } else if (str_match(pos, WPS_EVENT_SUCCESS)) { + wpsStatusText->setText("Registration succeeded"); + } +} + + +void WpaGui::processCtrlReq(const char *req) +{ + if (udr) { + udr->close(); + delete udr; + } + udr = new UserDataRequest(); + if (udr == NULL) + return; + if (udr->setParams(this, req) < 0) { + delete udr; + udr = NULL; + return; + } + udr->show(); + udr->exec(); +} + + +void WpaGui::receiveMsgs() +{ + char buf[256]; + size_t len; + + while (monitor_conn && wpa_ctrl_pending(monitor_conn) > 0) { + len = sizeof(buf) - 1; + if (wpa_ctrl_recv(monitor_conn, buf, &len) == 0) { + buf[len] = '\0'; + processMsg(buf); + } + } +} + + +void WpaGui::connectB() +{ + char reply[10]; + size_t reply_len = sizeof(reply); + ctrlRequest("REASSOCIATE", reply, &reply_len); +} + + +void WpaGui::selectNetwork( const QString &sel ) +{ + QString cmd(sel); + char reply[10]; + size_t reply_len = sizeof(reply); + + if (cmd.startsWith("Select any")) { + cmd = "any"; + } else { + int pos = cmd.indexOf(':'); + if (pos < 0) { + printf("Invalid selectNetwork '%s'\n", + cmd.toAscii().constData()); + return; + } + cmd.truncate(pos); + } + cmd.prepend("SELECT_NETWORK "); + ctrlRequest(cmd.toAscii().constData(), reply, &reply_len); + triggerUpdate(); + stopWpsRun(false); +} + + +void WpaGui::enableNetwork(const QString &sel) +{ + QString cmd(sel); + char reply[10]; + size_t reply_len = sizeof(reply); + + if (!cmd.startsWith("all")) { + int pos = cmd.indexOf(':'); + if (pos < 0) { + printf("Invalid enableNetwork '%s'\n", + cmd.toAscii().constData()); + return; + } + cmd.truncate(pos); + } + cmd.prepend("ENABLE_NETWORK "); + ctrlRequest(cmd.toAscii().constData(), reply, &reply_len); + triggerUpdate(); +} + + +void WpaGui::disableNetwork(const QString &sel) +{ + QString cmd(sel); + char reply[10]; + size_t reply_len = sizeof(reply); + + if (!cmd.startsWith("all")) { + int pos = cmd.indexOf(':'); + if (pos < 0) { + printf("Invalid disableNetwork '%s'\n", + cmd.toAscii().constData()); + return; + } + cmd.truncate(pos); + } + cmd.prepend("DISABLE_NETWORK "); + ctrlRequest(cmd.toAscii().constData(), reply, &reply_len); + triggerUpdate(); +} + + +void WpaGui::editNetwork(const QString &sel) +{ + QString cmd(sel); + int id = -1; + + if (!cmd.startsWith("Select any")) { + int pos = sel.indexOf(':'); + if (pos < 0) { + printf("Invalid editNetwork '%s'\n", + cmd.toAscii().constData()); + return; + } + cmd.truncate(pos); + id = cmd.toInt(); + } + + NetworkConfig *nc = new NetworkConfig(); + if (nc == NULL) + return; + nc->setWpaGui(this); + + if (id >= 0) + nc->paramsFromConfig(id); + else + nc->newNetwork(); + + nc->show(); + nc->exec(); +} + + +void WpaGui::editSelectedNetwork() +{ + if (networkSelect->count() < 1) { + QMessageBox::information(this, "No Networks", + "There are no networks to edit.\n"); + return; + } + QString sel(networkSelect->currentText()); + editNetwork(sel); +} + + +void WpaGui::editListedNetwork() +{ + if (networkList->currentRow() < 0) { + QMessageBox::information(this, "Select A Network", + "Select a network from the list to" + " edit it.\n"); + return; + } + QString sel(networkList->currentItem()->text()); + editNetwork(sel); +} + + +void WpaGui::triggerUpdate() +{ + updateStatus(); + networkMayHaveChanged = true; + updateNetworks(); +} + + +void WpaGui::addNetwork() +{ + NetworkConfig *nc = new NetworkConfig(); + if (nc == NULL) + return; + nc->setWpaGui(this); + nc->newNetwork(); + nc->show(); + nc->exec(); +} + + +void WpaGui::removeNetwork(const QString &sel) +{ + QString cmd(sel); + char reply[10]; + size_t reply_len = sizeof(reply); + + if (cmd.startsWith("Select any")) + return; + + if (!cmd.startsWith("all")) { + int pos = cmd.indexOf(':'); + if (pos < 0) { + printf("Invalid removeNetwork '%s'\n", + cmd.toAscii().constData()); + return; + } + cmd.truncate(pos); + } + cmd.prepend("REMOVE_NETWORK "); + ctrlRequest(cmd.toAscii().constData(), reply, &reply_len); + triggerUpdate(); +} + + +void WpaGui::removeSelectedNetwork() +{ + if (networkSelect->count() < 1) { + QMessageBox::information(this, "No Networks", + "There are no networks to remove.\n"); + return; + } + QString sel(networkSelect->currentText()); + removeNetwork(sel); +} + + +void WpaGui::removeListedNetwork() +{ + if (networkList->currentRow() < 0) { + QMessageBox::information(this, "Select A Network", + "Select a network from the list to" + " remove it.\n"); + return; + } + QString sel(networkList->currentItem()->text()); + removeNetwork(sel); +} + + +void WpaGui::enableAllNetworks() +{ + QString sel("all"); + enableNetwork(sel); +} + + +void WpaGui::disableAllNetworks() +{ + QString sel("all"); + disableNetwork(sel); +} + + +void WpaGui::removeAllNetworks() +{ + QString sel("all"); + removeNetwork(sel); +} + + +int WpaGui::getNetworkDisabled(const QString &sel) +{ + QString cmd(sel); + char reply[10]; + size_t reply_len = sizeof(reply) - 1; + int pos = cmd.indexOf(':'); + if (pos < 0) { + printf("Invalid getNetworkDisabled '%s'\n", + cmd.toAscii().constData()); + return -1; + } + cmd.truncate(pos); + cmd.prepend("GET_NETWORK "); + cmd.append(" disabled"); + + if (ctrlRequest(cmd.toAscii().constData(), reply, &reply_len) >= 0 + && reply_len >= 1) { + reply[reply_len] = '\0'; + if (!str_match(reply, "FAIL")) + return atoi(reply); + } + + return -1; +} + + +void WpaGui::updateNetworkDisabledStatus() +{ + if (networkList->currentRow() < 0) + return; + + QString sel(networkList->currentItem()->text()); + + switch (getNetworkDisabled(sel)) { + case 0: + if (!enableRadioButton->isChecked()) + enableRadioButton->setChecked(true); + return; + case 1: + if (!disableRadioButton->isChecked()) + disableRadioButton->setChecked(true); + return; + } +} + + +void WpaGui::enableListedNetwork(bool enabled) +{ + if (networkList->currentRow() < 0 || !enabled) + return; + + QString sel(networkList->currentItem()->text()); + + if (getNetworkDisabled(sel) == 1) + enableNetwork(sel); +} + + +void WpaGui::disableListedNetwork(bool disabled) +{ + if (networkList->currentRow() < 0 || !disabled) + return; + + QString sel(networkList->currentItem()->text()); + + if (getNetworkDisabled(sel) == 0) + disableNetwork(sel); +} + + +void WpaGui::saveConfig() +{ + char buf[10]; + size_t len; + + len = sizeof(buf) - 1; + ctrlRequest("SAVE_CONFIG", buf, &len); + + buf[len] = '\0'; + + if (str_match(buf, "FAIL")) + QMessageBox::warning(this, "Failed to save configuration", + "The configuration could not be saved.\n" + "\n" + "The update_config=1 configuration option\n" + "must be used for configuration saving to\n" + "be permitted.\n"); + else + QMessageBox::information(this, "Saved configuration", + "The current configuration was saved." + "\n"); +} + + +void WpaGui::selectAdapter( const QString & sel ) +{ + if (openCtrlConnection(sel.toAscii().constData()) < 0) + printf("Failed to open control connection to " + "wpa_supplicant.\n"); + updateStatus(); + updateNetworks(); +} + + +void WpaGui::createTrayIcon(bool trayOnly) +{ + QApplication::setQuitOnLastWindowClosed(false); + + tray_icon = new QSystemTrayIcon(this); + tray_icon->setToolTip(qAppName() + " - wpa_supplicant user interface"); + if (QImageReader::supportedImageFormats().contains(QByteArray("svg"))) + tray_icon->setIcon(QIcon(":/icons/wpa_gui.svg")); + else + tray_icon->setIcon(QIcon(":/icons/wpa_gui.png")); + + connect(tray_icon, + SIGNAL(activated(QSystemTrayIcon::ActivationReason)), + this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason))); + + ackTrayIcon = false; + + tray_menu = new QMenu(this); + + disconnectAction = new QAction("&Disconnect", this); + reconnectAction = new QAction("Re&connect", this); + connect(disconnectAction, SIGNAL(triggered()), this, + SLOT(disconnect())); + connect(reconnectAction, SIGNAL(triggered()), this, + SLOT(connectB())); + tray_menu->addAction(disconnectAction); + tray_menu->addAction(reconnectAction); + tray_menu->addSeparator(); + + eventAction = new QAction("&Event History", this); + scanAction = new QAction("Scan &Results", this); + statAction = new QAction("S&tatus", this); + connect(eventAction, SIGNAL(triggered()), this, SLOT(eventHistory())); + connect(scanAction, SIGNAL(triggered()), this, SLOT(scan())); + connect(statAction, SIGNAL(triggered()), this, SLOT(showTrayStatus())); + tray_menu->addAction(eventAction); + tray_menu->addAction(scanAction); + tray_menu->addAction(statAction); + tray_menu->addSeparator(); + + showAction = new QAction("&Show Window", this); + hideAction = new QAction("&Hide Window", this); + quitAction = new QAction("&Quit", this); + connect(showAction, SIGNAL(triggered()), this, SLOT(show())); + connect(hideAction, SIGNAL(triggered()), this, SLOT(hide())); + connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); + tray_menu->addAction(showAction); + tray_menu->addAction(hideAction); + tray_menu->addSeparator(); + tray_menu->addAction(quitAction); + + tray_icon->setContextMenu(tray_menu); + + tray_icon->show(); + + if (!trayOnly) + show(); + inTray = trayOnly; +} + + +void WpaGui::showTrayMessage(QSystemTrayIcon::MessageIcon type, int sec, + const QString & msg) +{ + if (!QSystemTrayIcon::supportsMessages()) + return; + + if (isVisible() || !tray_icon || !tray_icon->isVisible()) + return; + + tray_icon->showMessage(qAppName(), msg, type, sec * 1000); +} + + +void WpaGui::trayActivated(QSystemTrayIcon::ActivationReason how) + { + switch (how) { + /* use close() here instead of hide() and allow the + * custom closeEvent handler take care of children */ + case QSystemTrayIcon::Trigger: + ackTrayIcon = true; + if (isVisible()) { + close(); + inTray = true; + } else { + show(); + inTray = false; + } + break; + case QSystemTrayIcon::MiddleClick: + showTrayStatus(); + break; + default: + break; + } +} + + +void WpaGui::showTrayStatus() +{ + char buf[2048]; + size_t len; + + len = sizeof(buf) - 1; + if (ctrlRequest("STATUS", buf, &len) < 0) + return; + buf[len] = '\0'; + + QString msg, status(buf); + + QStringList lines = status.split(QRegExp("\\n")); + for (QStringList::Iterator it = lines.begin(); + it != lines.end(); it++) { + int pos = (*it).indexOf('=') + 1; + if (pos < 1) + continue; + + if ((*it).startsWith("bssid=")) + msg.append("BSSID:\t" + (*it).mid(pos) + "\n"); + else if ((*it).startsWith("ssid=")) + msg.append("SSID: \t" + (*it).mid(pos) + "\n"); + else if ((*it).startsWith("pairwise_cipher=")) + msg.append("PAIR: \t" + (*it).mid(pos) + "\n"); + else if ((*it).startsWith("group_cipher=")) + msg.append("GROUP:\t" + (*it).mid(pos) + "\n"); + else if ((*it).startsWith("key_mgmt=")) + msg.append("AUTH: \t" + (*it).mid(pos) + "\n"); + else if ((*it).startsWith("wpa_state=")) + msg.append("STATE:\t" + (*it).mid(pos) + "\n"); + else if ((*it).startsWith("ip_address=")) + msg.append("IP: \t" + (*it).mid(pos) + "\n"); + else if ((*it).startsWith("Supplicant PAE state=")) + msg.append("PAE: \t" + (*it).mid(pos) + "\n"); + else if ((*it).startsWith("EAP state=")) + msg.append("EAP: \t" + (*it).mid(pos) + "\n"); + } + + if (!msg.isEmpty()) + showTrayMessage(QSystemTrayIcon::Information, 10, msg); +} + + +void WpaGui::closeEvent(QCloseEvent *event) +{ + if (eh) { + eh->close(); + delete eh; + eh = NULL; + } + + if (scanres) { + scanres->close(); + delete scanres; + scanres = NULL; + } + + if (udr) { + udr->close(); + delete udr; + udr = NULL; + } + + if (tray_icon && !ackTrayIcon) { + /* give user a visual hint that the tray icon exists */ + if (QSystemTrayIcon::supportsMessages()) { + hide(); + showTrayMessage(QSystemTrayIcon::Information, 3, + qAppName() + " will keep running in " + "the system tray."); + } else { + QMessageBox::information(this, qAppName() + " systray", + "The program will keep " + "running in the system " + "tray."); + } + ackTrayIcon = true; + } + + event->accept(); +} + + +void WpaGui::wpsDialog() +{ + wpaguiTab->setCurrentWidget(wpsTab); +} + + +void WpaGui::tabChanged(int index) +{ + if (index != 2) + return; + + if (wpsRunning) + return; + + wpsApPinEdit->setEnabled(!bssFromScan.isEmpty()); + if (bssFromScan.isEmpty()) + wpsApPinButton->setEnabled(false); +} + + +void WpaGui::wpsPbc() +{ + char reply[20]; + size_t reply_len = sizeof(reply); + + if (ctrlRequest("WPS_PBC", reply, &reply_len) < 0) + return; + + wpsPinEdit->setEnabled(false); + if (wpsStatusText->text().compare("WPS AP in active PBC mode found")) { + wpsInstructions->setText("Press the push button on the AP to " + "start the PBC mode."); + } else { + wpsInstructions->setText("If you have not yet done so, press " + "the push button on the AP to start " + "the PBC mode."); + } + wpsStatusText->setText("Waiting for Registrar"); + wpsRunning = true; +} + + +void WpaGui::wpsGeneratePin() +{ + char reply[20]; + size_t reply_len = sizeof(reply) - 1; + + if (ctrlRequest("WPS_PIN any", reply, &reply_len) < 0) + return; + + reply[reply_len] = '\0'; + + wpsPinEdit->setText(reply); + wpsPinEdit->setEnabled(true); + wpsInstructions->setText("Enter the generated PIN into the Registrar " + "(either the internal one in the AP or an " + "external one)."); + wpsStatusText->setText("Waiting for Registrar"); + wpsRunning = true; +} + + +void WpaGui::setBssFromScan(const QString &bssid) +{ + bssFromScan = bssid; + wpsApPinEdit->setEnabled(!bssFromScan.isEmpty()); + wpsApPinButton->setEnabled(wpsApPinEdit->text().length() == 8); + wpsStatusText->setText("WPS AP selected from scan results"); + wpsInstructions->setText("If you want to use an AP device PIN, e.g., " + "from a label in the device, enter the eight " + "digit AP PIN and click Use AP PIN button."); +} + + +void WpaGui::wpsApPinChanged(const QString &text) +{ + wpsApPinButton->setEnabled(text.length() == 8); +} + + +void WpaGui::wpsApPin() +{ + char reply[20]; + size_t reply_len = sizeof(reply); + + QString cmd("WPS_REG " + bssFromScan + " " + wpsApPinEdit->text()); + if (ctrlRequest(cmd.toAscii().constData(), reply, &reply_len) < 0) + return; + + wpsStatusText->setText("Waiting for AP/Enrollee"); + wpsRunning = true; +} + + +void WpaGui::stopWpsRun(bool success) +{ + if (wpsRunning) + wpsStatusText->setText(success ? "Connected to the network" : + "Stopped"); + else + wpsStatusText->setText(""); + wpsPinEdit->setEnabled(false); + wpsInstructions->setText(""); + wpsRunning = false; + bssFromScan = ""; + wpsApPinEdit->setEnabled(false); + wpsApPinButton->setEnabled(false); +} + + +#ifdef CONFIG_NATIVE_WINDOWS + +#ifndef WPASVC_NAME +#define WPASVC_NAME TEXT("wpasvc") +#endif + +class ErrorMsg : public QMessageBox { +public: + ErrorMsg(QWidget *parent, DWORD last_err = GetLastError()); + void showMsg(QString msg); +private: + DWORD err; +}; + +ErrorMsg::ErrorMsg(QWidget *parent, DWORD last_err) : + QMessageBox(parent), err(last_err) +{ + setWindowTitle("wpa_gui error"); + setIcon(QMessageBox::Warning); +} + +void ErrorMsg::showMsg(QString msg) +{ + LPTSTR buf; + + setText(msg); + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, err, 0, (LPTSTR) (void *) &buf, + 0, NULL) > 0) { + QString msg = QString::fromWCharArray(buf); + setInformativeText(QString("[%1] %2").arg(err).arg(msg)); + LocalFree(buf); + } else { + setInformativeText(QString("[%1]").arg(err)); + } + + exec(); +} + + +void WpaGui::startService() +{ + SC_HANDLE svc, scm; + + scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT); + if (!scm) { + ErrorMsg(this).showMsg("OpenSCManager failed"); + return; + } + + svc = OpenService(scm, WPASVC_NAME, SERVICE_START); + if (!svc) { + ErrorMsg(this).showMsg("OpenService failed"); + CloseServiceHandle(scm); + return; + } + + if (!StartService(svc, 0, NULL)) { + ErrorMsg(this).showMsg("Failed to start wpa_supplicant " + "service"); + } + + CloseServiceHandle(svc); + CloseServiceHandle(scm); +} + + +void WpaGui::stopService() +{ + SC_HANDLE svc, scm; + SERVICE_STATUS status; + + scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT); + if (!scm) { + ErrorMsg(this).showMsg("OpenSCManager failed"); + return; + } + + svc = OpenService(scm, WPASVC_NAME, SERVICE_STOP); + if (!svc) { + ErrorMsg(this).showMsg("OpenService failed"); + CloseServiceHandle(scm); + return; + } + + if (!ControlService(svc, SERVICE_CONTROL_STOP, &status)) { + ErrorMsg(this).showMsg("Failed to stop wpa_supplicant " + "service"); + } + + CloseServiceHandle(svc); + CloseServiceHandle(scm); +} + + +bool WpaGui::serviceRunning() +{ + SC_HANDLE svc, scm; + SERVICE_STATUS status; + bool running = false; + + scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT); + if (!scm) { + printf("OpenSCManager failed: %d\n", (int) GetLastError()); + return false; + } + + svc = OpenService(scm, WPASVC_NAME, SERVICE_QUERY_STATUS); + if (!svc) { + printf("OpenService failed: %d\n\n", (int) GetLastError()); + CloseServiceHandle(scm); + return false; + } + + if (QueryServiceStatus(svc, &status)) { + if (status.dwCurrentState != SERVICE_STOPPED) + running = true; + } + + CloseServiceHandle(svc); + CloseServiceHandle(scm); + + return running; +} + +#endif /* CONFIG_NATIVE_WINDOWS */ + + +void WpaGui::addInterface() +{ + if (add_iface) { + add_iface->close(); + delete add_iface; + } + add_iface = new AddInterface(this, this); + add_iface->show(); + add_iface->exec(); +} + + +void WpaGui::saveState() +{ + QSettings settings("wpa_supplicant", "wpa_gui"); + settings.beginGroup("state"); + settings.setValue("session_id", app->sessionId()); + settings.setValue("in_tray", inTray); + settings.endGroup(); +} diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.h b/wpa_supplicant/wpa_gui-qt4/wpagui.h new file mode 100644 index 000000000000..a53396541e64 --- /dev/null +++ b/wpa_supplicant/wpa_gui-qt4/wpagui.h @@ -0,0 +1,145 @@ +/* + * wpa_gui - WpaGui class + * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef WPAGUI_H +#define WPAGUI_H + +#include <QSystemTrayIcon> +#include <QObject> +#include "ui_wpagui.h" +#include "addinterface.h" + +class UserDataRequest; + + +class WpaGui : public QMainWindow, public Ui::WpaGui +{ + Q_OBJECT + +public: + WpaGui(QApplication *app, QWidget *parent = 0, const char *name = 0, + Qt::WFlags fl = 0); + ~WpaGui(); + + virtual int ctrlRequest(const char *cmd, char *buf, size_t *buflen); + virtual void triggerUpdate(); + virtual void editNetwork(const QString &sel); + virtual void removeNetwork(const QString &sel); + virtual void enableNetwork(const QString &sel); + virtual void disableNetwork(const QString &sel); + virtual int getNetworkDisabled(const QString &sel); + void setBssFromScan(const QString &bssid); + void saveState(); + +public slots: + virtual void parse_argv(); + virtual void updateStatus(); + virtual void updateNetworks(); + virtual void helpIndex(); + virtual void helpContents(); + virtual void helpAbout(); + virtual void disconnect(); + virtual void scan(); + virtual void eventHistory(); + virtual void ping(); + virtual void processMsg(char *msg); + virtual void processCtrlReq(const char *req); + virtual void receiveMsgs(); + virtual void connectB(); + virtual void selectNetwork(const QString &sel); + virtual void editSelectedNetwork(); + virtual void editListedNetwork(); + virtual void removeSelectedNetwork(); + virtual void removeListedNetwork(); + virtual void addNetwork(); + virtual void enableAllNetworks(); + virtual void disableAllNetworks(); + virtual void removeAllNetworks(); + virtual void saveConfig(); + virtual void selectAdapter(const QString &sel); + virtual void updateNetworkDisabledStatus(); + virtual void enableListedNetwork(bool); + virtual void disableListedNetwork(bool); + virtual void showTrayMessage(QSystemTrayIcon::MessageIcon type, + int sec, const QString &msg); + virtual void showTrayStatus(); + virtual void wpsDialog(); + virtual void tabChanged(int index); + virtual void wpsPbc(); + virtual void wpsGeneratePin(); + virtual void wpsApPinChanged(const QString &text); + virtual void wpsApPin(); +#ifdef CONFIG_NATIVE_WINDOWS + virtual void startService(); + virtual void stopService(); +#endif /* CONFIG_NATIVE_WINDOWS */ + virtual void addInterface(); + +protected slots: + virtual void languageChange(); + virtual void trayActivated(QSystemTrayIcon::ActivationReason how); + virtual void closeEvent(QCloseEvent *event); + +private: + ScanResults *scanres; + bool networkMayHaveChanged; + char *ctrl_iface; + EventHistory *eh; + struct wpa_ctrl *ctrl_conn; + QSocketNotifier *msgNotifier; + QTimer *timer; + int pingsToStatusUpdate; + WpaMsgList msgs; + char *ctrl_iface_dir; + struct wpa_ctrl *monitor_conn; + UserDataRequest *udr; + QAction *disconnectAction; + QAction *reconnectAction; + QAction *eventAction; + QAction *scanAction; + QAction *statAction; + QAction *showAction; + QAction *hideAction; + QAction *quitAction; + QMenu *tray_menu; + QSystemTrayIcon *tray_icon; + void createTrayIcon(bool); + bool ackTrayIcon; + bool startInTray; + + int openCtrlConnection(const char *ifname); + + bool wpsRunning; + + QString bssFromScan; + + void stopWpsRun(bool success); + +#ifdef CONFIG_NATIVE_WINDOWS + QAction *fileStartServiceAction; + QAction *fileStopServiceAction; + + bool serviceRunning(); +#endif /* CONFIG_NATIVE_WINDOWS */ + + QAction *addInterfaceAction; + AddInterface *add_iface; + + bool connectedToService; + + QApplication *app; + bool inTray; +}; + +#endif /* WPAGUI_H */ diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.ui b/wpa_supplicant/wpa_gui-qt4/wpagui.ui new file mode 100644 index 000000000000..cd67ecb78301 --- /dev/null +++ b/wpa_supplicant/wpa_gui-qt4/wpagui.ui @@ -0,0 +1,517 @@ +<ui version="4.0" > + <class>WpaGui</class> + <widget class="QMainWindow" name="WpaGui" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>345</width> + <height>330</height> + </rect> + </property> + <property name="windowTitle" > + <string>wpa_gui</string> + </property> + <property name="windowIcon" > + <iconset resource="icons.qrc" > + <normaloff>:/icons/wpa_gui.svg</normaloff>:/icons/wpa_gui.svg</iconset> + </property> + <widget class="QWidget" name="widget" > + <layout class="QGridLayout" > + <item row="0" column="0" > + <widget class="QLabel" name="adapterLabel" > + <property name="text" > + <string>Adapter:</string> + </property> + </widget> + </item> + <item row="0" column="1" > + <widget class="QComboBox" name="adapterSelect" /> + </item> + <item row="1" column="0" > + <widget class="QLabel" name="networkLabel" > + <property name="text" > + <string>Network:</string> + </property> + </widget> + </item> + <item row="1" column="1" > + <widget class="QComboBox" name="networkSelect" /> + </item> + <item row="2" column="0" colspan="2" > + <widget class="QTabWidget" name="wpaguiTab" > + <property name="currentIndex" > + <number>0</number> + </property> + <widget class="QWidget" name="statusTab" > + <attribute name="title" > + <string>Current Status</string> + </attribute> + <layout class="QGridLayout" > + <item row="0" column="0" colspan="5" > + <widget class="QFrame" name="frame3" > + <property name="frameShape" > + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow" > + <enum>QFrame::Plain</enum> + </property> + <layout class="QGridLayout" > + <item row="0" column="0" > + <widget class="QLabel" name="statusLabel" > + <property name="text" > + <string>Status:</string> + </property> + </widget> + </item> + <item row="1" column="0" > + <widget class="QLabel" name="lastMessageLabel" > + <property name="text" > + <string>Last message:</string> + </property> + </widget> + </item> + <item row="2" column="0" > + <widget class="QLabel" name="authenticationLabel" > + <property name="text" > + <string>Authentication:</string> + </property> + </widget> + </item> + <item row="3" column="0" > + <widget class="QLabel" name="encryptionLabel" > + <property name="text" > + <string>Encryption:</string> + </property> + </widget> + </item> + <item row="4" column="0" > + <widget class="QLabel" name="ssidLabel" > + <property name="text" > + <string>SSID:</string> + </property> + </widget> + </item> + <item row="5" column="0" > + <widget class="QLabel" name="bssidLabel" > + <property name="text" > + <string>BSSID:</string> + </property> + </widget> + </item> + <item row="6" column="0" > + <widget class="QLabel" name="ipAddressLabel" > + <property name="text" > + <string>IP address:</string> + </property> + </widget> + </item> + <item row="0" column="1" > + <widget class="QLabel" name="textStatus" > + <property name="text" > + <string/> + </property> + </widget> + </item> + <item row="1" column="1" colspan="3" > + <widget class="QLabel" name="textLastMessage" > + <property name="text" > + <string/> + </property> + </widget> + </item> + <item row="2" column="1" > + <widget class="QLabel" name="textAuthentication" > + <property name="text" > + <string/> + </property> + </widget> + </item> + <item row="3" column="1" > + <widget class="QLabel" name="textEncryption" > + <property name="text" > + <string/> + </property> + </widget> + </item> + <item row="4" column="1" > + <widget class="QLabel" name="textSsid" > + <property name="text" > + <string/> + </property> + </widget> + </item> + <item row="5" column="1" > + <widget class="QLabel" name="textBssid" > + <property name="text" > + <string/> + </property> + </widget> + </item> + <item row="6" column="1" > + <widget class="QLabel" name="textIpAddress" > + <property name="text" > + <string/> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="1" column="0" > + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="1" > + <widget class="QPushButton" name="connectButton" > + <property name="text" > + <string>Connect</string> + </property> + </widget> + </item> + <item row="1" column="2" > + <widget class="QPushButton" name="disconnectButton" > + <property name="text" > + <string>Disconnect</string> + </property> + </widget> + </item> + <item row="1" column="3" > + <widget class="QPushButton" name="scanButton" > + <property name="text" > + <string>Scan</string> + </property> + </widget> + </item> + <item row="1" column="4" > + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <widget class="QWidget" name="networkconfigTab" > + <attribute name="title" > + <string>Manage Networks</string> + </attribute> + <layout class="QGridLayout" > + <item row="0" column="0" colspan="5" > + <widget class="QListWidget" name="networkList" > + <property name="selectionRectVisible" > + <bool>true</bool> + </property> + </widget> + </item> + <item rowspan="2" row="1" column="0" > + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>61</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="1" > + <widget class="QRadioButton" name="enableRadioButton" > + <property name="text" > + <string>Enabled</string> + </property> + </widget> + </item> + <item row="1" column="2" > + <widget class="QPushButton" name="editNetworkButton" > + <property name="text" > + <string>Edit</string> + </property> + </widget> + </item> + <item row="1" column="3" > + <widget class="QPushButton" name="removeNetworkButton" > + <property name="text" > + <string>Remove</string> + </property> + </widget> + </item> + <item rowspan="2" row="1" column="4" > + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>61</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="1" > + <widget class="QRadioButton" name="disableRadioButton" > + <property name="text" > + <string>Disabled</string> + </property> + </widget> + </item> + <item row="2" column="2" > + <widget class="QPushButton" name="addNetworkButton" > + <property name="text" > + <string>Add</string> + </property> + </widget> + </item> + <item row="2" column="3" > + <widget class="QPushButton" name="scanNetworkButton" > + <property name="text" > + <string>Scan</string> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="wpsTab" > + <attribute name="title" > + <string>WPS</string> + </attribute> + <layout class="QGridLayout" name="wpsGridLayout" > + <item row="0" column="0" > + <widget class="QLabel" name="label_2" > + <property name="text" > + <string>Status:</string> + </property> + </widget> + </item> + <item row="0" column="1" colspan="3" > + <widget class="QLabel" name="wpsStatusText" > + <property name="text" > + <string/> + </property> + </widget> + </item> + <item row="1" column="0" colspan="2" > + <widget class="QPushButton" name="wpsPbcButton" > + <property name="text" > + <string>PBC - push button</string> + </property> + </widget> + </item> + <item row="2" column="0" colspan="2" > + <widget class="QPushButton" name="wpsPinButton" > + <property name="text" > + <string>Generate PIN</string> + </property> + </widget> + </item> + <item row="2" column="2" > + <widget class="QLabel" name="label" > + <property name="text" > + <string>PIN:</string> + </property> + </widget> + </item> + <item row="2" column="3" > + <widget class="QLineEdit" name="wpsPinEdit" > + <property name="enabled" > + <bool>false</bool> + </property> + <property name="readOnly" > + <bool>true</bool> + </property> + </widget> + </item> + <item row="3" column="0" colspan="2" > + <widget class="QPushButton" name="wpsApPinButton" > + <property name="enabled" > + <bool>false</bool> + </property> + <property name="text" > + <string>Use AP PIN</string> + </property> + </widget> + </item> + <item row="3" column="2" > + <widget class="QLabel" name="label_3" > + <property name="text" > + <string>AP PIN:</string> + </property> + </widget> + </item> + <item row="3" column="3" > + <widget class="QLineEdit" name="wpsApPinEdit" > + <property name="enabled" > + <bool>false</bool> + </property> + </widget> + </item> + <item row="4" column="0" colspan="4" > + <widget class="QTextEdit" name="wpsInstructions" > + <property name="readOnly" > + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + <widget class="QMenuBar" name="MenuBar" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>345</width> + <height>24</height> + </rect> + </property> + <widget class="QMenu" name="fileMenu" > + <property name="title" > + <string>&File</string> + </property> + <addaction name="fileEventHistoryAction" /> + <addaction name="fileSaveConfigAction" /> + <addaction name="actionWPS" /> + <addaction name="separator" /> + <addaction name="fileExitAction" /> + </widget> + <widget class="QMenu" name="networkMenu" > + <property name="title" > + <string>&Network</string> + </property> + <addaction name="networkAddAction" /> + <addaction name="networkEditAction" /> + <addaction name="networkRemoveAction" /> + <addaction name="separator" /> + <addaction name="networkEnableAllAction" /> + <addaction name="networkDisableAllAction" /> + <addaction name="networkRemoveAllAction" /> + </widget> + <widget class="QMenu" name="helpMenu" > + <property name="title" > + <string>&Help</string> + </property> + <addaction name="helpContentsAction" /> + <addaction name="helpIndexAction" /> + <addaction name="separator" /> + <addaction name="helpAboutAction" /> + </widget> + <addaction name="fileMenu" /> + <addaction name="networkMenu" /> + <addaction name="helpMenu" /> + </widget> + <action name="fileEventHistoryAction" > + <property name="text" > + <string>Event &History</string> + </property> + </action> + <action name="fileSaveConfigAction" > + <property name="text" > + <string>&Save Configuration</string> + </property> + <property name="shortcut" > + <string>Ctrl+S</string> + </property> + </action> + <action name="fileExitAction" > + <property name="text" > + <string>E&xit</string> + </property> + <property name="shortcut" > + <string>Ctrl+Q</string> + </property> + </action> + <action name="networkAddAction" > + <property name="text" > + <string>&Add</string> + </property> + </action> + <action name="networkEditAction" > + <property name="text" > + <string>&Edit</string> + </property> + </action> + <action name="networkRemoveAction" > + <property name="text" > + <string>&Remove</string> + </property> + </action> + <action name="networkEnableAllAction" > + <property name="text" > + <string>E&nable All</string> + </property> + </action> + <action name="networkDisableAllAction" > + <property name="text" > + <string>&Disable All</string> + </property> + </action> + <action name="networkRemoveAllAction" > + <property name="text" > + <string>Re&move All</string> + </property> + </action> + <action name="helpContentsAction" > + <property name="enabled" > + <bool>false</bool> + </property> + <property name="text" > + <string>&Contents...</string> + </property> + </action> + <action name="helpIndexAction" > + <property name="enabled" > + <bool>false</bool> + </property> + <property name="text" > + <string>&Index...</string> + </property> + </action> + <action name="helpAboutAction" > + <property name="text" > + <string>&About</string> + </property> + </action> + <action name="actionWPS" > + <property name="enabled" > + <bool>false</bool> + </property> + <property name="text" > + <string>&Wi-Fi Protected Setup</string> + </property> + </action> + </widget> + <layoutdefault spacing="6" margin="11" /> + <pixmapfunction></pixmapfunction> + <includes> + <include location="global" >qtimer.h</include> + <include location="global" >qsocketnotifier.h</include> + <include location="local" >wpamsg.h</include> + <include location="local" >eventhistory.h</include> + <include location="local" >scanresults.h</include> + </includes> + <resources> + <include location="icons.qrc" /> + </resources> + <connections/> +</ui> diff --git a/wpa_supplicant/wpa_gui-qt4/wpamsg.h b/wpa_supplicant/wpa_gui-qt4/wpamsg.h new file mode 100644 index 000000000000..4950b213a2e3 --- /dev/null +++ b/wpa_supplicant/wpa_gui-qt4/wpamsg.h @@ -0,0 +1,41 @@ +/* + * wpa_gui - WpaMsg class for storing event messages + * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef WPAMSG_H +#define WPAMSG_H + +#include <QDateTime> +#include <QLinkedList> + +class WpaMsg { +public: + WpaMsg(const QString &_msg, int _priority = 2) + : msg(_msg), priority(_priority) + { + timestamp = QDateTime::currentDateTime(); + } + + QString getMsg() const { return msg; } + int getPriority() const { return priority; } + QDateTime getTimestamp() const { return timestamp; } + +private: + QString msg; + int priority; + QDateTime timestamp; +}; + +typedef QLinkedList<WpaMsg> WpaMsgList; + +#endif /* WPAMSG_H */ diff --git a/wpa_supplicant/wpa_gui/.gitignore b/wpa_supplicant/wpa_gui/.gitignore new file mode 100644 index 000000000000..11963c84daa3 --- /dev/null +++ b/wpa_supplicant/wpa_gui/.gitignore @@ -0,0 +1,5 @@ +.moc +.obj +.ui +Makefile +wpa_gui diff --git a/wpa_supplicant/wpa_gui/eventhistory.ui b/wpa_supplicant/wpa_gui/eventhistory.ui new file mode 100644 index 000000000000..3735fb70e8f9 --- /dev/null +++ b/wpa_supplicant/wpa_gui/eventhistory.ui @@ -0,0 +1,125 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>EventHistory</class> +<widget class="QDialog"> + <property name="name"> + <cstring>EventHistory</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>533</width> + <height>285</height> + </rect> + </property> + <property name="caption"> + <string>Event history</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QListView"> + <column> + <property name="text"> + <string>Timestamp</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Message</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>eventListView</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="resizePolicy"> + <enum>Manual</enum> + </property> + <property name="selectionMode"> + <enum>NoSelection</enum> + </property> + <property name="resizeMode"> + <enum>LastColumn</enum> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout30</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>closeButton</cstring> + </property> + <property name="text"> + <string>Close</string> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<connections> + <connection> + <sender>closeButton</sender> + <signal>clicked()</signal> + <receiver>EventHistory</receiver> + <slot>close()</slot> + </connection> +</connections> +<includes> + <include location="local" impldecl="in declaration">wpamsg.h</include> + <include location="local" impldecl="in implementation">eventhistory.ui.h</include> +</includes> +<slots> + <slot>addEvents( WpaMsgList msgs )</slot> + <slot>addEvent( WpaMsg msg )</slot> +</slots> +<functions> + <function access="private" specifier="non virtual">init()</function> + <function access="private" specifier="non virtual">destroy()</function> +</functions> +<pixmapinproject/> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/wpa_supplicant/wpa_gui/eventhistory.ui.h b/wpa_supplicant/wpa_gui/eventhistory.ui.h new file mode 100644 index 000000000000..cb2caab2e4e1 --- /dev/null +++ b/wpa_supplicant/wpa_gui/eventhistory.ui.h @@ -0,0 +1,41 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you want to add, delete, or rename functions or slots, use +** Qt Designer to update this file, preserving your code. +** +** You should not define a constructor or destructor in this file. +** Instead, write your code in functions called init() and destroy(). +** These will automatically be called by the form's constructor and +** destructor. +*****************************************************************************/ + +void EventHistory::init() +{ +} + + +void EventHistory::destroy() +{ +} + + +void EventHistory::addEvents(WpaMsgList msgs) +{ + WpaMsgList::iterator it; + for (it = msgs.begin(); it != msgs.end(); it++) { + addEvent(*it); + } +} + + +void EventHistory::addEvent(WpaMsg msg) +{ + Q3ListViewItem *item; + item = new Q3ListViewItem(eventListView, + msg.getTimestamp().toString("yyyy-MM-dd hh:mm:ss.zzz"), + msg.getMsg()); + if (item == NULL) + return; + eventListView->setSelected(item, false); +} diff --git a/wpa_supplicant/wpa_gui/main.cpp b/wpa_supplicant/wpa_gui/main.cpp new file mode 100644 index 000000000000..a78473a8c6b1 --- /dev/null +++ b/wpa_supplicant/wpa_gui/main.cpp @@ -0,0 +1,30 @@ +#ifdef CONFIG_NATIVE_WINDOWS +#include <winsock.h> +#endif /* CONFIG_NATIVE_WINDOWS */ +#include <qapplication.h> +#include "wpagui.h" + +int main( int argc, char ** argv ) +{ + QApplication a( argc, argv ); + WpaGui w; + int ret; + +#ifdef CONFIG_NATIVE_WINDOWS + WSADATA wsaData; + if (WSAStartup(MAKEWORD(2, 0), &wsaData)) { + printf("Could not find a usable WinSock.dll\n"); + return -1; + } +#endif /* CONFIG_NATIVE_WINDOWS */ + + w.show(); + a.connect( &a, SIGNAL( lastWindowClosed() ), &a, SLOT( quit() ) ); + ret = a.exec(); + +#ifdef CONFIG_NATIVE_WINDOWS + WSACleanup(); +#endif /* CONFIG_NATIVE_WINDOWS */ + + return ret; +} diff --git a/wpa_supplicant/wpa_gui/networkconfig.ui b/wpa_supplicant/wpa_gui/networkconfig.ui new file mode 100644 index 000000000000..019ecf7e259d --- /dev/null +++ b/wpa_supplicant/wpa_gui/networkconfig.ui @@ -0,0 +1,475 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>NetworkConfig</class> +<widget class="QDialog"> + <property name="name"> + <cstring>NetworkConfig</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>380</width> + <height>430</height> + </rect> + </property> + <property name="caption"> + <string>NetworkConfig</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton" row="1" column="3"> + <property name="name"> + <cstring>cancelButton</cstring> + </property> + <property name="text"> + <string>Cancel</string> + </property> + </widget> + <widget class="QFrame" row="0" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>frame9</cstring> + </property> + <property name="frameShape"> + <enum>StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>Raised</enum> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel0</cstring> + </property> + <property name="text"> + <string>SSID</string> + </property> + </widget> + <widget class="QLineEdit" row="0" column="1"> + <property name="name"> + <cstring>ssidEdit</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="toolTip" stdset="0"> + <string>Network name (Service Set IDentifier)</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Network ID</string> + </property> + </widget> + <widget class="QLineEdit" row="1" column="1"> + <property name="name"> + <cstring>idstrEdit</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="toolTip" stdset="0"> + <string>Network Identification String</string> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Authentication</string> + </property> + </widget> + <widget class="QComboBox" row="2" column="1"> + <item> + <property name="text"> + <string>Plaintext or static WEP</string> + </property> + </item> + <item> + <property name="text"> + <string>IEEE 802.1X</string> + </property> + </item> + <item> + <property name="text"> + <string>WPA-Personal (PSK)</string> + </property> + </item> + <item> + <property name="text"> + <string>WPA-Enterprise (EAP)</string> + </property> + </item> + <item> + <property name="text"> + <string>WPA2-Personal (PSK)</string> + </property> + </item> + <item> + <property name="text"> + <string>WPA2-Enterprise (EAP)</string> + </property> + </item> + <property name="name"> + <cstring>authSelect</cstring> + </property> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Encryption</string> + </property> + </widget> + <widget class="QComboBox" row="3" column="1"> + <item> + <property name="text"> + <string>None</string> + </property> + </item> + <item> + <property name="text"> + <string>WEP</string> + </property> + </item> + <item> + <property name="text"> + <string>TKIP</string> + </property> + </item> + <item> + <property name="text"> + <string>CCMP</string> + </property> + </item> + <property name="name"> + <cstring>encrSelect</cstring> + </property> + </widget> + <widget class="QLabel" row="4" column="0"> + <property name="name"> + <cstring>textLabel4</cstring> + </property> + <property name="text"> + <string>PSK</string> + </property> + </widget> + <widget class="QLineEdit" row="4" column="1"> + <property name="name"> + <cstring>pskEdit</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="echoMode"> + <enum>Password</enum> + </property> + <property name="toolTip" stdset="0"> + <string>WPA/WPA2 pre-shared key or passphrase</string> + </property> + <property name="whatsThis" stdset="0"> + <string></string> + </property> + </widget> + <widget class="QLabel" row="5" column="0"> + <property name="name"> + <cstring>textLabel5</cstring> + </property> + <property name="text"> + <string>EAP method</string> + </property> + </widget> + <widget class="QComboBox" row="5" column="1"> + <property name="name"> + <cstring>eapSelect</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + <widget class="QLabel" row="6" column="0"> + <property name="name"> + <cstring>textLabel6</cstring> + </property> + <property name="text"> + <string>Identity</string> + </property> + </widget> + <widget class="QLineEdit" row="6" column="1"> + <property name="name"> + <cstring>identityEdit</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Username/Identity for EAP methods</string> + </property> + </widget> + <widget class="QLabel" row="7" column="0"> + <property name="name"> + <cstring>textLabel7</cstring> + </property> + <property name="text"> + <string>Password</string> + </property> + </widget> + <widget class="QLineEdit" row="7" column="1"> + <property name="name"> + <cstring>passwordEdit</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="echoMode"> + <enum>Password</enum> + </property> + <property name="toolTip" stdset="0"> + <string>Password for EAP methods</string> + </property> + </widget> + <widget class="QLabel" row="8" column="0"> + <property name="name"> + <cstring>textLabel1_2</cstring> + </property> + <property name="text"> + <string>CA certificate</string> + </property> + </widget> + <widget class="QLineEdit" row="8" column="1"> + <property name="name"> + <cstring>cacertEdit</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + <widget class="QButtonGroup" row="9" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>buttonGroup1</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="title"> + <string>WEP keys</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QRadioButton" row="0" column="0"> + <property name="name"> + <cstring>wep0Radio</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>key 0</string> + </property> + </widget> + <widget class="QRadioButton" row="1" column="0"> + <property name="name"> + <cstring>wep1Radio</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>key 1</string> + </property> + </widget> + <widget class="QRadioButton" row="3" column="0"> + <property name="name"> + <cstring>wep3Radio</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>key 3</string> + </property> + </widget> + <widget class="QRadioButton" row="2" column="0"> + <property name="name"> + <cstring>wep2Radio</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>key 2</string> + </property> + </widget> + <widget class="QLineEdit" row="0" column="1"> + <property name="name"> + <cstring>wep0Edit</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + <widget class="QLineEdit" row="1" column="1"> + <property name="name"> + <cstring>wep1Edit</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + <widget class="QLineEdit" row="2" column="1"> + <property name="name"> + <cstring>wep2Edit</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + <widget class="QLineEdit" row="3" column="1"> + <property name="name"> + <cstring>wep3Edit</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + </grid> + </widget> + </grid> + </widget> + <spacer row="1" column="0"> + <property name="name"> + <cstring>spacer5</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>130</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton" row="1" column="1"> + <property name="name"> + <cstring>addButton</cstring> + </property> + <property name="text"> + <string>Add</string> + </property> + </widget> + <widget class="QPushButton" row="1" column="2"> + <property name="name"> + <cstring>removeButton</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Remove</string> + </property> + </widget> + </grid> +</widget> +<connections> + <connection> + <sender>authSelect</sender> + <signal>activated(int)</signal> + <receiver>NetworkConfig</receiver> + <slot>authChanged(int)</slot> + </connection> + <connection> + <sender>cancelButton</sender> + <signal>clicked()</signal> + <receiver>NetworkConfig</receiver> + <slot>close()</slot> + </connection> + <connection> + <sender>addButton</sender> + <signal>clicked()</signal> + <receiver>NetworkConfig</receiver> + <slot>addNetwork()</slot> + </connection> + <connection> + <sender>encrSelect</sender> + <signal>activated(const QString&)</signal> + <receiver>NetworkConfig</receiver> + <slot>encrChanged(const QString&)</slot> + </connection> + <connection> + <sender>removeButton</sender> + <signal>clicked()</signal> + <receiver>NetworkConfig</receiver> + <slot>removeNetwork()</slot> + </connection> +</connections> +<tabstops> + <tabstop>ssidEdit</tabstop> + <tabstop>idstrEdit</tabstop> + <tabstop>authSelect</tabstop> + <tabstop>encrSelect</tabstop> + <tabstop>pskEdit</tabstop> + <tabstop>eapSelect</tabstop> + <tabstop>identityEdit</tabstop> + <tabstop>passwordEdit</tabstop> + <tabstop>cacertEdit</tabstop> + <tabstop>wep0Radio</tabstop> + <tabstop>wep1Radio</tabstop> + <tabstop>wep2Radio</tabstop> + <tabstop>wep3Radio</tabstop> + <tabstop>wep0Edit</tabstop> + <tabstop>wep1Edit</tabstop> + <tabstop>wep2Edit</tabstop> + <tabstop>wep3Edit</tabstop> + <tabstop>addButton</tabstop> + <tabstop>removeButton</tabstop> + <tabstop>cancelButton</tabstop> +</tabstops> +<includes> + <include location="global" impldecl="in declaration">qlistview.h</include> + <include location="global" impldecl="in implementation">qmessagebox.h</include> + <include location="local" impldecl="in implementation">wpagui.h</include> + <include location="local" impldecl="in implementation">networkconfig.ui.h</include> +</includes> +<forwards> + <forward>class WpaGui;</forward> +</forwards> +<variables> + <variable access="private">WpaGui *wpagui;</variable> + <variable access="private">int edit_network_id;</variable> + <variable access="private">bool new_network;</variable> +</variables> +<slots> + <slot>authChanged( int sel )</slot> + <slot>addNetwork()</slot> + <slot>encrChanged( const QString & sel )</slot> + <slot>writeWepKey( int network_id, QLineEdit * edit, int id )</slot> + <slot>removeNetwork()</slot> +</slots> +<functions> + <function access="private" specifier="non virtual">init()</function> + <function>paramsFromScanResults( QListViewItem * sel )</function> + <function>setWpaGui( WpaGui * _wpagui )</function> + <function returnType="int">setNetworkParam( int id, const char * field, const char * value, bool quote )</function> + <function access="private">wepEnabled( bool enabled )</function> + <function>paramsFromConfig( int network_id )</function> + <function>newNetwork()</function> + <function access="private">getEapCapa()</function> +</functions> +<pixmapinproject/> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/wpa_supplicant/wpa_gui/networkconfig.ui.h b/wpa_supplicant/wpa_gui/networkconfig.ui.h new file mode 100644 index 000000000000..501d5d26556a --- /dev/null +++ b/wpa_supplicant/wpa_gui/networkconfig.ui.h @@ -0,0 +1,552 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you want to add, delete, or rename functions or slots, use +** Qt Designer to update this file, preserving your code. +** +** You should not define a constructor or destructor in this file. +** Instead, write your code in functions called init() and destroy(). +** These will automatically be called by the form's constructor and +** destructor. +*****************************************************************************/ + +#include <stdlib.h> + +enum { + AUTH_NONE = 0, + AUTH_IEEE8021X = 1, + AUTH_WPA_PSK = 2, + AUTH_WPA_EAP = 3, + AUTH_WPA2_PSK = 4, + AUTH_WPA2_EAP = 5 +}; + +#define WPA_GUI_KEY_DATA "[key is configured]" + +void NetworkConfig::init() +{ + wpagui = NULL; + new_network = false; +} + +void NetworkConfig::paramsFromScanResults(Q3ListViewItem *sel) +{ + new_network = true; + + /* SSID BSSID frequency signal flags */ + setCaption(sel->text(0)); + ssidEdit->setText(sel->text(0)); + + QString flags = sel->text(4); + int auth, encr = 0; + if (flags.find("[WPA2-EAP") >= 0) + auth = AUTH_WPA2_EAP; + else if (flags.find("[WPA-EAP") >= 0) + auth = AUTH_WPA_EAP; + else if (flags.find("[WPA2-PSK") >= 0) + auth = AUTH_WPA2_PSK; + else if (flags.find("[WPA-PSK") >= 0) + auth = AUTH_WPA_PSK; + else + auth = AUTH_NONE; + + if (flags.find("-CCMP") >= 0) + encr = 1; + else if (flags.find("-TKIP") >= 0) + encr = 0; + else if (flags.find("WEP") >= 0) + encr = 1; + else + encr = 0; + + authSelect->setCurrentItem(auth); + authChanged(auth); + encrSelect->setCurrentItem(encr); + + getEapCapa(); +} + + +void NetworkConfig::authChanged(int sel) +{ + pskEdit->setEnabled(sel == AUTH_WPA_PSK || sel == AUTH_WPA2_PSK); + bool eap = sel == AUTH_IEEE8021X || sel == AUTH_WPA_EAP || + sel == AUTH_WPA2_EAP; + eapSelect->setEnabled(eap); + identityEdit->setEnabled(eap); + passwordEdit->setEnabled(eap); + cacertEdit->setEnabled(eap); + + while (encrSelect->count()) + encrSelect->removeItem(0); + + if (sel == AUTH_NONE || sel == AUTH_IEEE8021X) { + encrSelect->insertItem("None"); + encrSelect->insertItem("WEP"); + encrSelect->setCurrentItem(sel == AUTH_NONE ? 0 : 1); + } else { + encrSelect->insertItem("TKIP"); + encrSelect->insertItem("CCMP"); + encrSelect->setCurrentItem((sel == AUTH_WPA2_PSK || + sel == AUTH_WPA2_EAP) ? 1 : 0); + } + + wepEnabled(sel == AUTH_IEEE8021X); +} + + +void NetworkConfig::addNetwork() +{ + char reply[10], cmd[256]; + size_t reply_len; + int id; + int psklen = pskEdit->text().length(); + int auth = authSelect->currentItem(); + + if (auth == AUTH_WPA_PSK || auth == AUTH_WPA2_PSK) { + if (psklen < 8 || psklen > 64) { + QMessageBox::warning(this, "wpa_gui", "WPA-PSK requires a passphrase " + "of 8 to 63 characters\n" + "or 64 hex digit PSK"); + return; + } + } + + if (wpagui == NULL) + return; + + memset(reply, 0, sizeof(reply)); + reply_len = sizeof(reply) - 1; + + if (new_network) { + wpagui->ctrlRequest("ADD_NETWORK", reply, &reply_len); + if (reply[0] == 'F') { + QMessageBox::warning(this, "wpa_gui", "Failed to add network to wpa_supplicant\n" + "configuration."); + return; + } + id = atoi(reply); + } else { + id = edit_network_id; + } + + setNetworkParam(id, "ssid", ssidEdit->text().ascii(), true); + + if (idstrEdit->isEnabled()) + setNetworkParam(id, "id_str", idstrEdit->text().ascii(), true); + + const char *key_mgmt = NULL, *proto = NULL, *pairwise = NULL; + switch (auth) { + case AUTH_NONE: + key_mgmt = "NONE"; + break; + case AUTH_IEEE8021X: + key_mgmt = "IEEE8021X"; + break; + case AUTH_WPA_PSK: + key_mgmt = "WPA-PSK"; + proto = "WPA"; + break; + case AUTH_WPA_EAP: + key_mgmt = "WPA-EAP"; + proto = "WPA"; + break; + case AUTH_WPA2_PSK: + key_mgmt = "WPA-PSK"; + proto = "WPA2"; + break; + case AUTH_WPA2_EAP: + key_mgmt = "WPA-EAP"; + proto = "WPA2"; + break; + } + + if (auth == AUTH_WPA_PSK || auth == AUTH_WPA_EAP || + auth == AUTH_WPA2_PSK || auth == AUTH_WPA2_EAP) { + int encr = encrSelect->currentItem(); + if (encr == 0) + pairwise = "TKIP"; + else + pairwise = "CCMP"; + } + + if (proto) + setNetworkParam(id, "proto", proto, false); + if (key_mgmt) + setNetworkParam(id, "key_mgmt", key_mgmt, false); + if (pairwise) { + setNetworkParam(id, "pairwise", pairwise, false); + setNetworkParam(id, "group", "TKIP CCMP WEP104 WEP40", false); + } + if (pskEdit->isEnabled() && + strcmp(pskEdit->text().ascii(), WPA_GUI_KEY_DATA) != 0) + setNetworkParam(id, "psk", pskEdit->text().ascii(), psklen != 64); + if (eapSelect->isEnabled()) + setNetworkParam(id, "eap", eapSelect->currentText().ascii(), false); + if (identityEdit->isEnabled()) + setNetworkParam(id, "identity", identityEdit->text().ascii(), true); + if (passwordEdit->isEnabled() && + strcmp(passwordEdit->text().ascii(), WPA_GUI_KEY_DATA) != 0) + setNetworkParam(id, "password", passwordEdit->text().ascii(), true); + if (cacertEdit->isEnabled()) + setNetworkParam(id, "ca_cert", cacertEdit->text().ascii(), true); + writeWepKey(id, wep0Edit, 0); + writeWepKey(id, wep1Edit, 1); + writeWepKey(id, wep2Edit, 2); + writeWepKey(id, wep3Edit, 3); + + if (wep0Radio->isEnabled() && wep0Radio->isChecked()) + setNetworkParam(id, "wep_tx_keyidx", "0", false); + else if (wep1Radio->isEnabled() && wep1Radio->isChecked()) + setNetworkParam(id, "wep_tx_keyidx", "1", false); + else if (wep2Radio->isEnabled() && wep2Radio->isChecked()) + setNetworkParam(id, "wep_tx_keyidx", "2", false); + else if (wep3Radio->isEnabled() && wep3Radio->isChecked()) + setNetworkParam(id, "wep_tx_keyidx", "3", false); + + snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %d", id); + reply_len = sizeof(reply); + wpagui->ctrlRequest(cmd, reply, &reply_len); + if (strncmp(reply, "OK", 2) != 0) { + QMessageBox::warning(this, "wpa_gui", "Failed to enable network in wpa_supplicant\n" + "configuration."); + /* Network was added, so continue anyway */ + } + wpagui->triggerUpdate(); + wpagui->ctrlRequest("SAVE_CONFIG", reply, &reply_len); + + close(); +} + + +void NetworkConfig::setWpaGui( WpaGui *_wpagui ) +{ + wpagui = _wpagui; +} + + +int NetworkConfig::setNetworkParam(int id, const char *field, const char *value, bool quote) +{ + char reply[10], cmd[256]; + size_t reply_len; + snprintf(cmd, sizeof(cmd), "SET_NETWORK %d %s %s%s%s", + id, field, quote ? "\"" : "", value, quote ? "\"" : ""); + reply_len = sizeof(reply); + wpagui->ctrlRequest(cmd, reply, &reply_len); + return strncmp(reply, "OK", 2) == 0 ? 0 : -1; +} + + +void NetworkConfig::encrChanged( const QString &sel ) +{ + wepEnabled(sel.find("WEP") == 0); +} + + +void NetworkConfig::wepEnabled( bool enabled ) +{ + wep0Edit->setEnabled(enabled); + wep1Edit->setEnabled(enabled); + wep2Edit->setEnabled(enabled); + wep3Edit->setEnabled(enabled); + wep0Radio->setEnabled(enabled); + wep1Radio->setEnabled(enabled); + wep2Radio->setEnabled(enabled); + wep3Radio->setEnabled(enabled); +} + + +void NetworkConfig::writeWepKey( int network_id, QLineEdit *edit, int id ) +{ + char buf[10]; + bool hex; + const char *txt, *pos; + size_t len; + + if (!edit->isEnabled() || edit->text().isEmpty()) + return; + + /* + * Assume hex key if only hex characters are present and length matches + * with 40, 104, or 128-bit key + */ + txt = edit->text().ascii(); + if (strcmp(txt, WPA_GUI_KEY_DATA) == 0) + return; + len = strlen(txt); + if (len == 0) + return; + pos = txt; + hex = true; + while (*pos) { + if (!((*pos >= '0' && *pos <= '9') || (*pos >= 'a' && *pos <= 'f') || + (*pos >= 'A' && *pos <= 'F'))) { + hex = false; + break; + } + pos++; + } + if (hex && len != 10 && len != 26 && len != 32) + hex = false; + snprintf(buf, sizeof(buf), "wep_key%d", id); + setNetworkParam(network_id, buf, txt, !hex); +} + + +static int key_value_isset(const char *reply, size_t reply_len) +{ + return reply_len > 0 && (reply_len < 4 || memcmp(reply, "FAIL", 4) != 0); +} + + +void NetworkConfig::paramsFromConfig( int network_id ) +{ + int i, res; + + edit_network_id = network_id; + getEapCapa(); + + char reply[1024], cmd[256], *pos; + size_t reply_len; + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ssid", network_id); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 && + reply[0] == '"') { + reply[reply_len] = '\0'; + pos = strchr(reply + 1, '"'); + if (pos) + *pos = '\0'; + ssidEdit->setText(reply + 1); + } + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d id_str", network_id); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 && + reply[0] == '"') { + reply[reply_len] = '\0'; + pos = strchr(reply + 1, '"'); + if (pos) + *pos = '\0'; + idstrEdit->setText(reply + 1); + } + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d proto", network_id); + reply_len = sizeof(reply) - 1; + int wpa = 0; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) { + reply[reply_len] = '\0'; + if (strstr(reply, "RSN") || strstr(reply, "WPA2")) + wpa = 2; + else if (strstr(reply, "WPA")) + wpa = 1; + } + + int auth = AUTH_NONE, encr = 0; + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d key_mgmt", network_id); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) { + reply[reply_len] = '\0'; + if (strstr(reply, "WPA-EAP")) + auth = wpa & 2 ? AUTH_WPA2_EAP : AUTH_WPA_EAP; + else if (strstr(reply, "WPA-PSK")) + auth = wpa & 2 ? AUTH_WPA2_PSK : AUTH_WPA_PSK; + else if (strstr(reply, "IEEE8021X")) { + auth = AUTH_IEEE8021X; + encr = 1; + } + } + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d pairwise", network_id); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) { + reply[reply_len] = '\0'; + if (strstr(reply, "CCMP") && auth != AUTH_NONE) + encr = 1; + else if (strstr(reply, "TKIP")) + encr = 0; + else if (strstr(reply, "WEP")) + encr = 1; + else + encr = 0; + } + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d psk", network_id); + reply_len = sizeof(reply) - 1; + res = wpagui->ctrlRequest(cmd, reply, &reply_len); + if (res >= 0 && reply_len >= 2 && reply[0] == '"') { + reply[reply_len] = '\0'; + pos = strchr(reply + 1, '"'); + if (pos) + *pos = '\0'; + pskEdit->setText(reply + 1); + } else if (res >= 0 && key_value_isset(reply, reply_len)) { + pskEdit->setText(WPA_GUI_KEY_DATA); + } + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d identity", network_id); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 && + reply[0] == '"') { + reply[reply_len] = '\0'; + pos = strchr(reply + 1, '"'); + if (pos) + *pos = '\0'; + identityEdit->setText(reply + 1); + } + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d password", network_id); + reply_len = sizeof(reply) - 1; + res = wpagui->ctrlRequest(cmd, reply, &reply_len); + if (res >= 0 && reply_len >= 2 && + reply[0] == '"') { + reply[reply_len] = '\0'; + pos = strchr(reply + 1, '"'); + if (pos) + *pos = '\0'; + passwordEdit->setText(reply + 1); + } else if (res >= 0 && key_value_isset(reply, reply_len)) { + passwordEdit->setText(WPA_GUI_KEY_DATA); + } + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ca_cert", network_id); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 && + reply[0] == '"') { + reply[reply_len] = '\0'; + pos = strchr(reply + 1, '"'); + if (pos) + *pos = '\0'; + cacertEdit->setText(reply + 1); + } + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d eap", network_id); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 1) { + reply[reply_len] = '\0'; + for (i = 0; i < eapSelect->count(); i++) { + if (eapSelect->text(i).compare(reply) == 0) { + eapSelect->setCurrentItem(i); + break; + } + } + } + + for (i = 0; i < 4; i++) { + QLineEdit *wepEdit; + switch (i) { + default: + case 0: + wepEdit = wep0Edit; + break; + case 1: + wepEdit = wep1Edit; + break; + case 2: + wepEdit = wep2Edit; + break; + case 3: + wepEdit = wep3Edit; + break; + } + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_key%d", network_id, i); + reply_len = sizeof(reply) - 1; + res = wpagui->ctrlRequest(cmd, reply, &reply_len); + if (res >= 0 && reply_len >= 2 && reply[0] == '"') { + reply[reply_len] = '\0'; + pos = strchr(reply + 1, '"'); + if (pos) + *pos = '\0'; + if (auth == AUTH_NONE || auth == AUTH_IEEE8021X) + encr = 1; + + wepEdit->setText(reply + 1); + } else if (res >= 0 && key_value_isset(reply, reply_len)) { + if (auth == AUTH_NONE || auth == AUTH_IEEE8021X) + encr = 1; + wepEdit->setText(WPA_GUI_KEY_DATA); + } + } + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_tx_keyidx", network_id); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 1) { + reply[reply_len] = '\0'; + switch (atoi(reply)) { + case 0: + wep0Radio->setChecked(true); + break; + case 1: + wep1Radio->setChecked(true); + break; + case 2: + wep2Radio->setChecked(true); + break; + case 3: + wep3Radio->setChecked(true); + break; + } + } + + authSelect->setCurrentItem(auth); + authChanged(auth); + encrSelect->setCurrentItem(encr); + if (auth == AUTH_NONE || auth == AUTH_IEEE8021X) + wepEnabled(encr == 1); + + removeButton->setEnabled(true); + addButton->setText("Save"); +} + + +void NetworkConfig::removeNetwork() +{ + char reply[10], cmd[256]; + size_t reply_len; + + if (QMessageBox::information(this, "wpa_gui", + "This will permanently remove the network\n" + "from the configuration. Do you really want\n" + "to remove this network?", "Yes", "No") != 0) + return; + + snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %d", edit_network_id); + reply_len = sizeof(reply); + wpagui->ctrlRequest(cmd, reply, &reply_len); + if (strncmp(reply, "OK", 2) != 0) { + QMessageBox::warning(this, "wpa_gui", + "Failed to remove network from wpa_supplicant\n" + "configuration."); + } else { + wpagui->triggerUpdate(); + wpagui->ctrlRequest("SAVE_CONFIG", reply, &reply_len); + } + + close(); +} + + +void NetworkConfig::newNetwork() +{ + new_network = true; + getEapCapa(); +} + + +void NetworkConfig::getEapCapa() +{ + char reply[256]; + size_t reply_len; + + if (wpagui == NULL) + return; + + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest("GET_CAPABILITY eap", reply, &reply_len) < 0) + return; + reply[reply_len] = '\0'; + + QString res(reply); + QStringList types = QStringList::split(QChar(' '), res); + eapSelect->insertStringList(types); +} diff --git a/wpa_supplicant/wpa_gui/scanresults.ui b/wpa_supplicant/wpa_gui/scanresults.ui new file mode 100644 index 000000000000..66c8b4b76f32 --- /dev/null +++ b/wpa_supplicant/wpa_gui/scanresults.ui @@ -0,0 +1,179 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>ScanResults</class> +<widget class="QDialog"> + <property name="name"> + <cstring>ScanResults</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>452</width> + <height>225</height> + </rect> + </property> + <property name="caption"> + <string>Scan results</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QListView"> + <column> + <property name="text"> + <string>SSID</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>BSSID</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>frequency</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>signal</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>flags</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>scanResultsView</cstring> + </property> + <property name="frameShape"> + <enum>StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout24</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer6</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>50</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>scanButton</cstring> + </property> + <property name="text"> + <string>Scan</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>closeButton</cstring> + </property> + <property name="text"> + <string>Close</string> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<connections> + <connection> + <sender>closeButton</sender> + <signal>clicked()</signal> + <receiver>ScanResults</receiver> + <slot>close()</slot> + </connection> + <connection> + <sender>scanButton</sender> + <signal>clicked()</signal> + <receiver>ScanResults</receiver> + <slot>scanRequest()</slot> + </connection> + <connection> + <sender>scanResultsView</sender> + <signal>doubleClicked(QListViewItem*)</signal> + <receiver>ScanResults</receiver> + <slot>bssSelected(QListViewItem*)</slot> + </connection> +</connections> +<includes> + <include location="local" impldecl="in implementation">wpa_ctrl.h</include> + <include location="local" impldecl="in implementation">wpagui.h</include> + <include location="local" impldecl="in implementation">networkconfig.h</include> + <include location="local" impldecl="in implementation">scanresults.ui.h</include> +</includes> +<forwards> + <forward>class WpaGui;</forward> +</forwards> +<variables> + <variable access="private">WpaGui *wpagui;</variable> + <variable access="private">QTimer *timer;</variable> +</variables> +<slots> + <slot>setWpaGui( WpaGui * _wpagui )</slot> + <slot>updateResults()</slot> + <slot>scanRequest()</slot> + <slot>getResults()</slot> + <slot>bssSelected( QListViewItem * sel )</slot> +</slots> +<functions> + <function access="private" specifier="non virtual">init()</function> + <function access="private" specifier="non virtual">destroy()</function> +</functions> +<pixmapinproject/> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/wpa_supplicant/wpa_gui/scanresults.ui.h b/wpa_supplicant/wpa_gui/scanresults.ui.h new file mode 100644 index 000000000000..530d2e6a495c --- /dev/null +++ b/wpa_supplicant/wpa_gui/scanresults.ui.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you want to add, delete, or rename functions or slots, use +** Qt Designer to update this file, preserving your code. +** +** You should not define a constructor or destructor in this file. +** Instead, write your code in functions called init() and destroy(). +** These will automatically be called by the form's constructor and +** destructor. +*****************************************************************************/ + +void ScanResults::init() +{ + wpagui = NULL; +} + + +void ScanResults::destroy() +{ + delete timer; +} + + +void ScanResults::setWpaGui(WpaGui *_wpagui) +{ + wpagui = _wpagui; + updateResults(); + + timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), SLOT(getResults())); + timer->start(10000, FALSE); +} + + +void ScanResults::updateResults() +{ + char reply[8192]; + size_t reply_len; + + if (wpagui == NULL) + return; + + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest("SCAN_RESULTS", reply, &reply_len) < 0) + return; + reply[reply_len] = '\0'; + + scanResultsView->clear(); + + QString res(reply); + QStringList lines = QStringList::split(QChar('\n'), res); + bool first = true; + for (QStringList::Iterator it = lines.begin(); it != lines.end(); it++) { + if (first) { + first = false; + continue; + } + + QStringList cols = QStringList::split(QChar('\t'), *it, true); + QString ssid, bssid, freq, signal, flags; + bssid = cols.count() > 0 ? cols[0] : ""; + freq = cols.count() > 1 ? cols[1] : ""; + signal = cols.count() > 2 ? cols[2] : ""; + flags = cols.count() > 3 ? cols[3] : ""; + ssid = cols.count() > 4 ? cols[4] : ""; + new Q3ListViewItem(scanResultsView, ssid, bssid, freq, signal, flags); + } +} + + +void ScanResults::scanRequest() +{ + char reply[10]; + size_t reply_len = sizeof(reply); + + if (wpagui == NULL) + return; + + wpagui->ctrlRequest("SCAN", reply, &reply_len); +} + + +void ScanResults::getResults() +{ + updateResults(); +} + + + + +void ScanResults::bssSelected( Q3ListViewItem * sel ) +{ + NetworkConfig *nc = new NetworkConfig(); + if (nc == NULL) + return; + nc->setWpaGui(wpagui); + nc->paramsFromScanResults(sel); + nc->show(); + nc->exec(); +} diff --git a/wpa_supplicant/wpa_gui/setup-mingw-cross-compiling b/wpa_supplicant/wpa_gui/setup-mingw-cross-compiling new file mode 100755 index 000000000000..e173b0013781 --- /dev/null +++ b/wpa_supplicant/wpa_gui/setup-mingw-cross-compiling @@ -0,0 +1,11 @@ +#!/bin/sh + +# qmake seems to be forcing include and lib paths from the original build +# and I have no idea how to change these. For now, just override the +# directories in the Makefile.Release file after qmake run. + +qmake -spec /q/jm/qt4-win/4.0.0/mkspecs/win32-g++ wpa_gui.pro -o Makefile +cat Makefile.Release | + sed s%qt4/lib%qt4-win/4.0.0/lib%g | + sed s%qt4/include%qt4-win/4.0.0/include%g > tmp.Makefile.Release && +mv -f tmp.Makefile.Release Makefile.Release diff --git a/wpa_supplicant/wpa_gui/userdatarequest.ui b/wpa_supplicant/wpa_gui/userdatarequest.ui new file mode 100644 index 000000000000..c3d545fa620a --- /dev/null +++ b/wpa_supplicant/wpa_gui/userdatarequest.ui @@ -0,0 +1,163 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>UserDataRequest</class> +<widget class="QDialog"> + <property name="name"> + <cstring>UserDataRequest</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>216</width> + <height>103</height> + </rect> + </property> + <property name="caption"> + <string>Authentication credentials required</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>queryInfo</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout28</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>queryField</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QLineEdit"> + <property name="name"> + <cstring>queryEdit</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="echoMode"> + <enum>Password</enum> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout27</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer4</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>buttonOk</cstring> + </property> + <property name="text"> + <string>&OK</string> + </property> + <property name="accel"> + <string></string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>buttonCancel</cstring> + </property> + <property name="text"> + <string>&Cancel</string> + </property> + <property name="accel"> + <string></string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<connections> + <connection> + <sender>buttonOk</sender> + <signal>clicked()</signal> + <receiver>UserDataRequest</receiver> + <slot>sendReply()</slot> + </connection> + <connection> + <sender>buttonCancel</sender> + <signal>clicked()</signal> + <receiver>UserDataRequest</receiver> + <slot>reject()</slot> + </connection> + <connection> + <sender>queryEdit</sender> + <signal>returnPressed()</signal> + <receiver>UserDataRequest</receiver> + <slot>sendReply()</slot> + </connection> +</connections> +<includes> + <include location="local" impldecl="in implementation">wpa_ctrl.h</include> + <include location="local" impldecl="in implementation">wpagui.h</include> + <include location="local" impldecl="in implementation">userdatarequest.ui.h</include> +</includes> +<forwards> + <forward>class WpaGui;</forward> +</forwards> +<variables> + <variable access="private">WpaGui *wpagui;</variable> + <variable access="private">int networkid;</variable> + <variable access="private">QString field;</variable> +</variables> +<slots> + <slot>sendReply()</slot> +</slots> +<functions> + <function specifier="non virtual" returnType="int">setParams( WpaGui * _wpagui, const char * reqMsg )</function> +</functions> +<pixmapinproject/> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/wpa_supplicant/wpa_gui/userdatarequest.ui.h b/wpa_supplicant/wpa_gui/userdatarequest.ui.h new file mode 100644 index 000000000000..66d4478d23e2 --- /dev/null +++ b/wpa_supplicant/wpa_gui/userdatarequest.ui.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you want to add, delete, or rename functions or slots, use +** Qt Designer to update this file, preserving your code. +** +** You should not define a constructor or destructor in this file. +** Instead, write your code in functions called init() and destroy(). +** These will automatically be called by the form's constructor and +** destructor. +*****************************************************************************/ + +#include <stdlib.h> + +int UserDataRequest::setParams(WpaGui *_wpagui, const char *reqMsg) +{ + char *tmp, *pos, *pos2; + wpagui = _wpagui; + tmp = strdup(reqMsg); + if (tmp == NULL) + return -1; + pos = strchr(tmp, '-'); + if (pos == NULL) { + free(tmp); + return -1; + } + *pos++ = '\0'; + field = tmp; + pos2 = strchr(pos, ':'); + if (pos2 == NULL) { + free(tmp); + return -1; + } + *pos2++ = '\0'; + + networkid = atoi(pos); + queryInfo->setText(pos2); + if (strcmp(tmp, "PASSWORD") == 0) { + queryField->setText("Password: "); + queryEdit->setEchoMode(QLineEdit::Password); + } else if (strcmp(tmp, "NEW_PASSWORD") == 0) { + queryField->setText("New password: "); + queryEdit->setEchoMode(QLineEdit::Password); + } else if (strcmp(tmp, "IDENTITY") == 0) + queryField->setText("Identity: "); + else if (strcmp(tmp, "PASSPHRASE") == 0) { + queryField->setText("Private key passphrase: "); + queryEdit->setEchoMode(QLineEdit::Password); + } else + queryField->setText(field + ":"); + free(tmp); + + return 0; +} + + +void UserDataRequest::sendReply() +{ + char reply[10]; + size_t reply_len = sizeof(reply); + + if (wpagui == NULL) { + reject(); + return; + } + + QString cmd = QString(WPA_CTRL_RSP) + field + '-' + + QString::number(networkid) + ':' + + queryEdit->text(); + wpagui->ctrlRequest(cmd.ascii(), reply, &reply_len); + accept(); +} diff --git a/wpa_supplicant/wpa_gui/wpa_gui.pro b/wpa_supplicant/wpa_gui/wpa_gui.pro new file mode 100644 index 000000000000..6363db92287c --- /dev/null +++ b/wpa_supplicant/wpa_gui/wpa_gui.pro @@ -0,0 +1,50 @@ +TEMPLATE = app +LANGUAGE = C++ + +CONFIG += qt warn_on release + +DEFINES += CONFIG_CTRL_IFACE + +win32 { + LIBS += -lws2_32 -static + DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE + SOURCES += ../../src/utils/os_win32.c +} else:win32-g++ { + # cross compilation to win32 + LIBS += -lws2_32 -static + DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE + SOURCES += ../../src/utils/os_win32.c +} else { + DEFINES += CONFIG_CTRL_IFACE_UNIX + SOURCES += ../../src/utils/os_unix.c +} + +INCLUDEPATH += . .. ../../src/utils ../../src/common + +HEADERS += wpamsg.h + +SOURCES += main.cpp \ + ../../src/common/wpa_ctrl.c + +FORMS = wpagui.ui \ + eventhistory.ui \ + scanresults.ui \ + userdatarequest.ui \ + networkconfig.ui + + +unix { + UI_DIR = .ui + MOC_DIR = .moc + OBJECTS_DIR = .obj +} + +qtver = $$[QT_VERSION] +isEmpty( qtver ) { + message(Compiling for Qt 3.x) + DEFINES += Q3ListViewItem=QListViewItem +} else { + message(Compiling for Qt $$qtver) + QT += qt3support + CONFIG += uic3 +} diff --git a/wpa_supplicant/wpa_gui/wpagui.ui b/wpa_supplicant/wpa_gui/wpagui.ui new file mode 100644 index 000000000000..01666a363479 --- /dev/null +++ b/wpa_supplicant/wpa_gui/wpagui.ui @@ -0,0 +1,471 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>WpaGui</class> +<widget class="QMainWindow"> + <property name="name"> + <cstring>WpaGui</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>279</width> + <height>308</height> + </rect> + </property> + <property name="caption"> + <string>wpa_gui</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>textLabel16</cstring> + </property> + <property name="text"> + <string>Adapter:</string> + </property> + </widget> + <widget class="QComboBox" row="0" column="2" rowspan="1" colspan="2"> + <property name="name"> + <cstring>adapterSelect</cstring> + </property> + </widget> + <widget class="QLabel" row="1" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>textLabel8</cstring> + </property> + <property name="text"> + <string>Network:</string> + </property> + </widget> + <widget class="QComboBox" row="1" column="2" rowspan="1" colspan="2"> + <property name="name"> + <cstring>networkSelect</cstring> + </property> + </widget> + <widget class="QFrame" row="2" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>frame3</cstring> + </property> + <property name="frameShape"> + <enum>StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>Raised</enum> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Status:</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Last message:</string> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Authentication:</string> + </property> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>textLabel4</cstring> + </property> + <property name="text"> + <string>Encryption:</string> + </property> + </widget> + <widget class="QLabel" row="4" column="0"> + <property name="name"> + <cstring>textLabel5</cstring> + </property> + <property name="text"> + <string>SSID:</string> + </property> + </widget> + <widget class="QLabel" row="5" column="0"> + <property name="name"> + <cstring>textLabel6</cstring> + </property> + <property name="text"> + <string>BSSID:</string> + </property> + </widget> + <widget class="QLabel" row="6" column="0"> + <property name="name"> + <cstring>textLabel7</cstring> + </property> + <property name="text"> + <string>IP address:</string> + </property> + </widget> + <widget class="QLabel" row="0" column="1"> + <property name="name"> + <cstring>textStatus</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QLabel" row="1" column="1" rowspan="1" colspan="3"> + <property name="name"> + <cstring>textLastMessage</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QLabel" row="2" column="1"> + <property name="name"> + <cstring>textAuthentication</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QLabel" row="3" column="1"> + <property name="name"> + <cstring>textEncryption</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QLabel" row="4" column="1"> + <property name="name"> + <cstring>textSsid</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QLabel" row="5" column="1"> + <property name="name"> + <cstring>textBssid</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QLabel" row="6" column="1"> + <property name="name"> + <cstring>textIpAddress</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + </grid> + </widget> + <spacer row="3" column="0"> + <property name="name"> + <cstring>spacer7</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>16</width> + <height>16</height> + </size> + </property> + </spacer> + <widget class="QPushButton" row="3" column="1"> + <property name="name"> + <cstring>connectButton</cstring> + </property> + <property name="text"> + <string>Connect</string> + </property> + </widget> + <widget class="QPushButton" row="3" column="2"> + <property name="name"> + <cstring>disconnectButton</cstring> + </property> + <property name="text"> + <string>Disconnect</string> + </property> + </widget> + <widget class="QPushButton" row="3" column="3"> + <property name="name"> + <cstring>scanButton</cstring> + </property> + <property name="text"> + <string>Scan</string> + </property> + </widget> + </grid> +</widget> +<menubar> + <property name="name"> + <cstring>MenuBar</cstring> + </property> + <item text="&File" name="fileMenu"> + <separator/> + <action name="fileEventHistoryAction"/> + <action name="fileAdd_NetworkAction"/> + <action name="fileEdit_networkAction"/> + <separator/> + <action name="fileExitAction"/> + </item> + <item text="&Help" name="helpMenu"> + <action name="helpContentsAction"/> + <action name="helpIndexAction"/> + <separator/> + <action name="helpAboutAction"/> + </item> +</menubar> +<toolbars> +</toolbars> +<actions> + <action> + <property name="name"> + <cstring>fileExitAction</cstring> + </property> + <property name="text"> + <string>Exit</string> + </property> + <property name="menuText"> + <string>E&xit</string> + </property> + <property name="accel"> + <string>Ctrl+Q</string> + </property> + </action> + <action> + <property name="name"> + <cstring>helpContentsAction</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Contents</string> + </property> + <property name="menuText"> + <string>&Contents...</string> + </property> + <property name="accel"> + <string></string> + </property> + </action> + <action> + <property name="name"> + <cstring>helpIndexAction</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Index</string> + </property> + <property name="menuText"> + <string>&Index...</string> + </property> + <property name="accel"> + <string></string> + </property> + </action> + <action> + <property name="name"> + <cstring>helpAboutAction</cstring> + </property> + <property name="text"> + <string>About</string> + </property> + <property name="menuText"> + <string>&About</string> + </property> + <property name="accel"> + <string></string> + </property> + </action> + <action> + <property name="name"> + <cstring>fileEventHistoryAction</cstring> + </property> + <property name="text"> + <string>Event History</string> + </property> + <property name="menuText"> + <string>Event &History</string> + </property> + </action> + <action> + <property name="name"> + <cstring>fileAdd_NetworkAction</cstring> + </property> + <property name="text"> + <string>Add Network</string> + </property> + <property name="menuText"> + <string>&Add Network</string> + </property> + </action> + <action> + <property name="name"> + <cstring>fileEdit_networkAction</cstring> + </property> + <property name="text"> + <string>Edit Network</string> + </property> + <property name="menuText"> + <string>&Edit Network</string> + </property> + </action> +</actions> +<connections> + <connection> + <sender>helpIndexAction</sender> + <signal>activated()</signal> + <receiver>WpaGui</receiver> + <slot>helpIndex()</slot> + </connection> + <connection> + <sender>helpContentsAction</sender> + <signal>activated()</signal> + <receiver>WpaGui</receiver> + <slot>helpContents()</slot> + </connection> + <connection> + <sender>helpAboutAction</sender> + <signal>activated()</signal> + <receiver>WpaGui</receiver> + <slot>helpAbout()</slot> + </connection> + <connection> + <sender>fileExitAction</sender> + <signal>activated()</signal> + <receiver>WpaGui</receiver> + <slot>close()</slot> + </connection> + <connection> + <sender>disconnectButton</sender> + <signal>clicked()</signal> + <receiver>WpaGui</receiver> + <slot>disconnect()</slot> + </connection> + <connection> + <sender>scanButton</sender> + <signal>clicked()</signal> + <receiver>WpaGui</receiver> + <slot>scan()</slot> + </connection> + <connection> + <sender>connectButton</sender> + <signal>clicked()</signal> + <receiver>WpaGui</receiver> + <slot>connectB()</slot> + </connection> + <connection> + <sender>fileEventHistoryAction</sender> + <signal>activated()</signal> + <receiver>WpaGui</receiver> + <slot>eventHistory()</slot> + </connection> + <connection> + <sender>networkSelect</sender> + <signal>activated(const QString&)</signal> + <receiver>WpaGui</receiver> + <slot>selectNetwork(const QString&)</slot> + </connection> + <connection> + <sender>fileEdit_networkAction</sender> + <signal>activated()</signal> + <receiver>WpaGui</receiver> + <slot>editNetwork()</slot> + </connection> + <connection> + <sender>fileAdd_NetworkAction</sender> + <signal>activated()</signal> + <receiver>WpaGui</receiver> + <slot>addNetwork()</slot> + </connection> + <connection> + <sender>adapterSelect</sender> + <signal>activated(const QString&)</signal> + <receiver>WpaGui</receiver> + <slot>selectAdapter(const QString&)</slot> + </connection> +</connections> +<includes> + <include location="global" impldecl="in declaration">qtimer.h</include> + <include location="global" impldecl="in declaration">qsocketnotifier.h</include> + <include location="local" impldecl="in declaration">wpamsg.h</include> + <include location="local" impldecl="in declaration">eventhistory.h</include> + <include location="local" impldecl="in declaration">scanresults.h</include> + <include location="local" impldecl="in implementation">wpa_ctrl.h</include> + <include location="global" impldecl="in implementation">dirent.h</include> + <include location="global" impldecl="in implementation">qmessagebox.h</include> + <include location="global" impldecl="in implementation">qapplication.h</include> + <include location="local" impldecl="in implementation">userdatarequest.h</include> + <include location="local" impldecl="in implementation">networkconfig.h</include> + <include location="local" impldecl="in implementation">wpagui.ui.h</include> +</includes> +<forwards> + <forward>class UserDataRequest;</forward> +</forwards> +<variables> + <variable access="private">ScanResults *scanres;</variable> + <variable access="private">bool networkMayHaveChanged;</variable> + <variable access="private">char *ctrl_iface;</variable> + <variable access="private">EventHistory *eh;</variable> + <variable access="private">struct wpa_ctrl *ctrl_conn;</variable> + <variable access="private">QSocketNotifier *msgNotifier;</variable> + <variable access="private">QTimer *timer;</variable> + <variable access="private">int pingsToStatusUpdate;</variable> + <variable access="private">WpaMsgList msgs;</variable> + <variable access="private">char *ctrl_iface_dir;</variable> + <variable access="private">struct wpa_ctrl *monitor_conn;</variable> + <variable access="private">UserDataRequest *udr;</variable> +</variables> +<slots> + <slot>parse_argv()</slot> + <slot>updateStatus()</slot> + <slot>updateNetworks()</slot> + <slot>helpIndex()</slot> + <slot>helpContents()</slot> + <slot>helpAbout()</slot> + <slot>disconnect()</slot> + <slot>scan()</slot> + <slot>eventHistory()</slot> + <slot>ping()</slot> + <slot>processMsg( char * msg )</slot> + <slot>processCtrlReq( const char * req )</slot> + <slot>receiveMsgs()</slot> + <slot>connectB()</slot> + <slot>selectNetwork( const QString & sel )</slot> + <slot>editNetwork()</slot> + <slot>addNetwork()</slot> + <slot>selectAdapter( const QString & sel )</slot> +</slots> +<functions> + <function access="private" specifier="non virtual">init()</function> + <function access="private" specifier="non virtual">destroy()</function> + <function access="private" specifier="non virtual" returnType="int">openCtrlConnection( const char * ifname )</function> + <function returnType="int">ctrlRequest( const char * cmd, char * buf, size_t * buflen )</function> + <function>triggerUpdate()</function> +</functions> +<pixmapinproject/> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/wpa_supplicant/wpa_gui/wpagui.ui.h b/wpa_supplicant/wpa_gui/wpagui.ui.h new file mode 100644 index 000000000000..678ff1be354b --- /dev/null +++ b/wpa_supplicant/wpa_gui/wpagui.ui.h @@ -0,0 +1,730 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you want to add, delete, or rename functions or slots, use +** Qt Designer to update this file, preserving your code. +** +** You should not define a constructor or destructor in this file. +** Instead, write your code in functions called init() and destroy(). +** These will automatically be called by the form's constructor and +** destructor. +*****************************************************************************/ + + +#ifdef __MINGW32__ +/* Need to get getopt() */ +#include <unistd.h> +#endif + +#include <stdlib.h> + +void WpaGui::init() +{ + eh = NULL; + scanres = NULL; + udr = NULL; + ctrl_iface = NULL; + ctrl_conn = NULL; + monitor_conn = NULL; + msgNotifier = NULL; + ctrl_iface_dir = strdup("/var/run/wpa_supplicant"); + + parse_argv(); + + textStatus->setText("connecting to wpa_supplicant"); + timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), SLOT(ping())); + timer->start(1000, FALSE); + + if (openCtrlConnection(ctrl_iface) < 0) { + printf("Failed to open control connection to wpa_supplicant.\n"); + } + + updateStatus(); + networkMayHaveChanged = true; + updateNetworks(); +} + + +void WpaGui::destroy() +{ + delete msgNotifier; + + if (monitor_conn) { + wpa_ctrl_detach(monitor_conn); + wpa_ctrl_close(monitor_conn); + monitor_conn = NULL; + } + if (ctrl_conn) { + wpa_ctrl_close(ctrl_conn); + ctrl_conn = NULL; + } + + if (eh) { + eh->close(); + delete eh; + eh = NULL; + } + + if (scanres) { + scanres->close(); + delete scanres; + scanres = NULL; + } + + if (udr) { + udr->close(); + delete udr; + udr = NULL; + } + + free(ctrl_iface); + ctrl_iface = NULL; + + free(ctrl_iface_dir); + ctrl_iface_dir = NULL; +} + + +void WpaGui::parse_argv() +{ + int c; + for (;;) { + c = getopt(qApp->argc(), qApp->argv(), "i:p:"); + if (c < 0) + break; + switch (c) { + case 'i': + free(ctrl_iface); + ctrl_iface = strdup(optarg); + break; + case 'p': + free(ctrl_iface_dir); + ctrl_iface_dir = strdup(optarg); + break; + } + } +} + + +int WpaGui::openCtrlConnection(const char *ifname) +{ + char *cfile; + int flen; + char buf[2048], *pos, *pos2; + size_t len; + + if (ifname) { + if (ifname != ctrl_iface) { + free(ctrl_iface); + ctrl_iface = strdup(ifname); + } + } else { +#ifdef CONFIG_CTRL_IFACE_UDP + free(ctrl_iface); + ctrl_iface = strdup("udp"); +#endif /* CONFIG_CTRL_IFACE_UDP */ +#ifdef CONFIG_CTRL_IFACE_UNIX + struct dirent *dent; + DIR *dir = opendir(ctrl_iface_dir); + free(ctrl_iface); + ctrl_iface = NULL; + if (dir) { + 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; + printf("Selected interface '%s'\n", dent->d_name); + ctrl_iface = strdup(dent->d_name); + break; + } + closedir(dir); + } +#endif /* CONFIG_CTRL_IFACE_UNIX */ +#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE + struct wpa_ctrl *ctrl; + int ret; + + free(ctrl_iface); + ctrl_iface = NULL; + + ctrl = wpa_ctrl_open(NULL); + if (ctrl) { + len = sizeof(buf) - 1; + ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf, &len, NULL); + if (ret >= 0) { + buf[len] = '\0'; + pos = strchr(buf, '\n'); + if (pos) + *pos = '\0'; + ctrl_iface = strdup(buf); + } + wpa_ctrl_close(ctrl); + } +#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ + } + + if (ctrl_iface == NULL) + return -1; + +#ifdef CONFIG_CTRL_IFACE_UNIX + flen = strlen(ctrl_iface_dir) + strlen(ctrl_iface) + 2; + cfile = (char *) malloc(flen); + if (cfile == NULL) + return -1; + snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ctrl_iface); +#else /* CONFIG_CTRL_IFACE_UNIX */ + flen = strlen(ctrl_iface) + 1; + cfile = (char *) malloc(flen); + if (cfile == NULL) + return -1; + snprintf(cfile, flen, "%s", ctrl_iface); +#endif /* CONFIG_CTRL_IFACE_UNIX */ + + if (ctrl_conn) { + wpa_ctrl_close(ctrl_conn); + ctrl_conn = NULL; + } + + if (monitor_conn) { + delete msgNotifier; + msgNotifier = NULL; + wpa_ctrl_detach(monitor_conn); + wpa_ctrl_close(monitor_conn); + monitor_conn = NULL; + } + + printf("Trying to connect to '%s'\n", cfile); + ctrl_conn = wpa_ctrl_open(cfile); + if (ctrl_conn == NULL) { + free(cfile); + return -1; + } + monitor_conn = wpa_ctrl_open(cfile); + free(cfile); + if (monitor_conn == NULL) { + wpa_ctrl_close(ctrl_conn); + return -1; + } + if (wpa_ctrl_attach(monitor_conn)) { + printf("Failed to attach to wpa_supplicant\n"); + wpa_ctrl_close(monitor_conn); + monitor_conn = NULL; + wpa_ctrl_close(ctrl_conn); + ctrl_conn = NULL; + return -1; + } + +#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP) + msgNotifier = new QSocketNotifier(wpa_ctrl_get_fd(monitor_conn), + QSocketNotifier::Read, this); + connect(msgNotifier, SIGNAL(activated(int)), SLOT(receiveMsgs())); +#endif + + adapterSelect->clear(); + adapterSelect->insertItem(ctrl_iface); + adapterSelect->setCurrentItem(0); + + len = sizeof(buf) - 1; + if (wpa_ctrl_request(ctrl_conn, "INTERFACES", 10, buf, &len, NULL) >= 0) { + buf[len] = '\0'; + pos = buf; + while (*pos) { + pos2 = strchr(pos, '\n'); + if (pos2) + *pos2 = '\0'; + if (strcmp(pos, ctrl_iface) != 0) + adapterSelect->insertItem(pos); + if (pos2) + pos = pos2 + 1; + else + break; + } + } + + return 0; +} + + +static void wpa_gui_msg_cb(char *msg, size_t) +{ + /* This should not happen anymore since two control connections are used. */ + printf("missed message: %s\n", msg); +} + + +int WpaGui::ctrlRequest(const char *cmd, char *buf, size_t *buflen) +{ + int ret; + + if (ctrl_conn == NULL) + return -3; + ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, buflen, + wpa_gui_msg_cb); + if (ret == -2) { + printf("'%s' command timed out.\n", cmd); + } else if (ret < 0) { + printf("'%s' command failed.\n", cmd); + } + + return ret; +} + + +void WpaGui::updateStatus() +{ + char buf[2048], *start, *end, *pos; + size_t len; + + pingsToStatusUpdate = 10; + + len = sizeof(buf) - 1; + if (ctrl_conn == NULL || ctrlRequest("STATUS", buf, &len) < 0) { + textStatus->setText("Could not get status from wpa_supplicant"); + textAuthentication->clear(); + textEncryption->clear(); + textSsid->clear(); + textBssid->clear(); + textIpAddress->clear(); + return; + } + + buf[len] = '\0'; + + bool auth_updated = false, ssid_updated = false; + bool bssid_updated = false, ipaddr_updated = false; + bool status_updated = false; + char *pairwise_cipher = NULL, *group_cipher = NULL; + + start = buf; + while (*start) { + bool last = false; + end = strchr(start, '\n'); + if (end == NULL) { + last = true; + end = start; + while (end[0] && end[1]) + end++; + } + *end = '\0'; + + pos = strchr(start, '='); + if (pos) { + *pos++ = '\0'; + if (strcmp(start, "bssid") == 0) { + bssid_updated = true; + textBssid->setText(pos); + } else if (strcmp(start, "ssid") == 0) { + ssid_updated = true; + textSsid->setText(pos); + } else if (strcmp(start, "ip_address") == 0) { + ipaddr_updated = true; + textIpAddress->setText(pos); + } else if (strcmp(start, "wpa_state") == 0) { + status_updated = true; + textStatus->setText(pos); + } else if (strcmp(start, "key_mgmt") == 0) { + auth_updated = true; + textAuthentication->setText(pos); + /* TODO: could add EAP status to this */ + } else if (strcmp(start, "pairwise_cipher") == 0) { + pairwise_cipher = pos; + } else if (strcmp(start, "group_cipher") == 0) { + group_cipher = pos; + } + } + + if (last) + break; + start = end + 1; + } + + if (pairwise_cipher || group_cipher) { + QString encr; + if (pairwise_cipher && group_cipher && + strcmp(pairwise_cipher, group_cipher) != 0) { + encr.append(pairwise_cipher); + encr.append(" + "); + encr.append(group_cipher); + } else if (pairwise_cipher) { + encr.append(pairwise_cipher); + } else { + encr.append(group_cipher); + encr.append(" [group key only]"); + } + textEncryption->setText(encr); + } else + textEncryption->clear(); + + if (!status_updated) + textStatus->clear(); + if (!auth_updated) + textAuthentication->clear(); + if (!ssid_updated) + textSsid->clear(); + if (!bssid_updated) + textBssid->clear(); + if (!ipaddr_updated) + textIpAddress->clear(); +} + + +void WpaGui::updateNetworks() +{ + char buf[2048], *start, *end, *id, *ssid, *bssid, *flags; + size_t len; + int first_active = -1; + bool selected = false; + + if (!networkMayHaveChanged) + return; + + networkSelect->clear(); + + if (ctrl_conn == NULL) + return; + + len = sizeof(buf) - 1; + if (ctrlRequest("LIST_NETWORKS", buf, &len) < 0) + return; + + buf[len] = '\0'; + start = strchr(buf, '\n'); + if (start == NULL) + return; + start++; + + while (*start) { + bool last = false; + end = strchr(start, '\n'); + if (end == NULL) { + last = true; + end = start; + while (end[0] && end[1]) + end++; + } + *end = '\0'; + + id = start; + ssid = strchr(id, '\t'); + if (ssid == NULL) + break; + *ssid++ = '\0'; + bssid = strchr(ssid, '\t'); + if (bssid == NULL) + break; + *bssid++ = '\0'; + flags = strchr(bssid, '\t'); + if (flags == NULL) + break; + *flags++ = '\0'; + + QString network(id); + network.append(": "); + network.append(ssid); + networkSelect->insertItem(network); + + if (strstr(flags, "[CURRENT]")) { + networkSelect->setCurrentItem(networkSelect->count() - 1); + selected = true; + } else if (first_active < 0 && strstr(flags, "[DISABLED]") == NULL) + first_active = networkSelect->count() - 1; + + if (last) + break; + start = end + 1; + } + + if (!selected && first_active >= 0) + networkSelect->setCurrentItem(first_active); + + networkMayHaveChanged = false; +} + + +void WpaGui::helpIndex() +{ + printf("helpIndex\n"); +} + + +void WpaGui::helpContents() +{ + printf("helpContents\n"); +} + + +void WpaGui::helpAbout() +{ + QMessageBox::about(this, "wpa_gui for wpa_supplicant", + "Copyright (c) 2003-2008,\n" + "Jouni Malinen <j@w1.fi>\n" + "and contributors.\n" + "\n" + "This program is free software. You can\n" + "distribute it and/or modify it under the terms of\n" + "the GNU General Public License version 2.\n" + "\n" + "Alternatively, this software may be distributed\n" + "under the terms of the BSD license.\n" + "\n" + "This product includes software developed\n" + "by the OpenSSL Project for use in the\n" + "OpenSSL Toolkit (http://www.openssl.org/)\n"); +} + + +void WpaGui::disconnect() +{ + char reply[10]; + size_t reply_len = sizeof(reply); + ctrlRequest("DISCONNECT", reply, &reply_len); +} + + +void WpaGui::scan() +{ + if (scanres) { + scanres->close(); + delete scanres; + } + + scanres = new ScanResults(); + if (scanres == NULL) + return; + scanres->setWpaGui(this); + scanres->show(); + scanres->exec(); +} + + +void WpaGui::eventHistory() +{ + if (eh) { + eh->close(); + delete eh; + } + + eh = new EventHistory(); + if (eh == NULL) + return; + eh->addEvents(msgs); + eh->show(); + eh->exec(); +} + + +void WpaGui::ping() +{ + char buf[10]; + size_t len; + +#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE + /* + * QSocketNotifier cannot be used with Windows named pipes, so use a timer + * to check for received messages for now. This could be optimized be doing + * something specific to named pipes or Windows events, but it is not clear + * what would be the best way of doing that in Qt. + */ + receiveMsgs(); +#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ + + if (scanres && !scanres->isVisible()) { + delete scanres; + scanres = NULL; + } + + if (eh && !eh->isVisible()) { + delete eh; + eh = NULL; + } + + if (udr && !udr->isVisible()) { + delete udr; + udr = NULL; + } + + len = sizeof(buf) - 1; + if (ctrlRequest("PING", buf, &len) < 0) { + printf("PING failed - trying to reconnect\n"); + if (openCtrlConnection(ctrl_iface) >= 0) { + printf("Reconnected successfully\n"); + pingsToStatusUpdate = 0; + } + } + + pingsToStatusUpdate--; + if (pingsToStatusUpdate <= 0) { + updateStatus(); + updateNetworks(); + } +} + + +static int str_match(const char *a, const char *b) +{ + return strncmp(a, b, strlen(b)) == 0; +} + + +void WpaGui::processMsg(char *msg) +{ + char *pos = msg, *pos2; + int priority = 2; + + if (*pos == '<') { + /* skip priority */ + pos++; + priority = atoi(pos); + pos = strchr(pos, '>'); + if (pos) + pos++; + else + pos = msg; + } + + WpaMsg wm(pos, priority); + if (eh) + eh->addEvent(wm); + msgs.append(wm); + while (msgs.count() > 100) + msgs.pop_front(); + + /* Update last message with truncated version of the event */ + if (strncmp(pos, "CTRL-", 5) == 0) { + pos2 = strchr(pos, str_match(pos, WPA_CTRL_REQ) ? ':' : ' '); + if (pos2) + pos2++; + else + pos2 = pos; + } else + pos2 = pos; + QString lastmsg = pos2; + lastmsg.truncate(40); + textLastMessage->setText(lastmsg); + + pingsToStatusUpdate = 0; + networkMayHaveChanged = true; + + if (str_match(pos, WPA_CTRL_REQ)) + processCtrlReq(pos + strlen(WPA_CTRL_REQ)); +} + + +void WpaGui::processCtrlReq(const char *req) +{ + if (udr) { + udr->close(); + delete udr; + } + udr = new UserDataRequest(); + if (udr == NULL) + return; + if (udr->setParams(this, req) < 0) { + delete udr; + udr = NULL; + return; + } + udr->show(); + udr->exec(); +} + + +void WpaGui::receiveMsgs() +{ + char buf[256]; + size_t len; + + while (monitor_conn && wpa_ctrl_pending(monitor_conn) > 0) { + len = sizeof(buf) - 1; + if (wpa_ctrl_recv(monitor_conn, buf, &len) == 0) { + buf[len] = '\0'; + processMsg(buf); + } + } +} + + +void WpaGui::connectB() +{ + char reply[10]; + size_t reply_len = sizeof(reply); + ctrlRequest("REASSOCIATE", reply, &reply_len); +} + + +void WpaGui::selectNetwork( const QString &sel ) +{ + QString cmd(sel); + char reply[10]; + size_t reply_len = sizeof(reply); + + int pos = cmd.find(':'); + if (pos < 0) { + printf("Invalid selectNetwork '%s'\n", cmd.ascii()); + return; + } + cmd.truncate(pos); + cmd.prepend("SELECT_NETWORK "); + ctrlRequest(cmd.ascii(), reply, &reply_len); +} + + +void WpaGui::editNetwork() +{ + QString sel(networkSelect->currentText()); + int pos = sel.find(':'); + if (pos < 0) { + printf("Invalid selectNetwork '%s'\n", sel.ascii()); + return; + } + sel.truncate(pos); + + NetworkConfig *nc = new NetworkConfig(); + if (nc == NULL) + return; + nc->setWpaGui(this); + + nc->paramsFromConfig(sel.toInt()); + nc->show(); + nc->exec(); +} + + +void WpaGui::triggerUpdate() +{ + updateStatus(); + networkMayHaveChanged = true; + updateNetworks(); +} + + +void WpaGui::addNetwork() +{ + NetworkConfig *nc = new NetworkConfig(); + if (nc == NULL) + return; + nc->setWpaGui(this); + nc->newNetwork(); + nc->show(); + nc->exec(); +} + + +void WpaGui::selectAdapter( const QString & sel ) +{ + if (openCtrlConnection(sel.ascii()) < 0) + printf("Failed to open control connection to wpa_supplicant.\n"); + updateStatus(); + updateNetworks(); +} diff --git a/wpa_supplicant/wpa_gui/wpamsg.h b/wpa_supplicant/wpa_gui/wpamsg.h new file mode 100644 index 000000000000..f3fce06978c7 --- /dev/null +++ b/wpa_supplicant/wpa_gui/wpamsg.h @@ -0,0 +1,34 @@ +#ifndef WPAMSG_H +#define WPAMSG_H + +class WpaMsg; + +#if QT_VERSION >= 0x040000 +#include <QDateTime> +#include <QLinkedList> +typedef QLinkedList<WpaMsg> WpaMsgList; +#else +#include <qdatetime.h> +typedef QValueList<WpaMsg> WpaMsgList; +#endif + +class WpaMsg { +public: + WpaMsg() {} + WpaMsg(const QString &_msg, int _priority = 2) + : msg(_msg), priority(_priority) + { + timestamp = QDateTime::currentDateTime(); + } + + QString getMsg() const { return msg; } + int getPriority() const { return priority; } + QDateTime getTimestamp() const { return timestamp; } + +private: + QString msg; + int priority; + QDateTime timestamp; +}; + +#endif /* WPAMSG_H */ diff --git a/wpa_supplicant/wpa_passphrase.c b/wpa_supplicant/wpa_passphrase.c new file mode 100644 index 000000000000..96b0c32c2cee --- /dev/null +++ b/wpa_supplicant/wpa_passphrase.c @@ -0,0 +1,73 @@ +/* + * WPA Supplicant - ASCII passphrase to WPA PSK tool + * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "sha1.h" + + +int main(int argc, char *argv[]) +{ + unsigned char psk[32]; + int i; + char *ssid, *passphrase, buf[64], *pos; + + if (argc < 2) { + printf("usage: wpa_passphrase <ssid> [passphrase]\n" + "\nIf passphrase is left out, it will be read from " + "stdin\n"); + return 1; + } + + ssid = argv[1]; + + if (argc > 2) { + passphrase = argv[2]; + } else { + printf("# reading passphrase from stdin\n"); + if (fgets(buf, sizeof(buf), stdin) == NULL) { + printf("Failed to read passphrase\n"); + return 1; + } + buf[sizeof(buf) - 1] = '\0'; + pos = buf; + while (*pos != '\0') { + if (*pos == '\r' || *pos == '\n') { + *pos = '\0'; + break; + } + pos++; + } + passphrase = buf; + } + + if (os_strlen(passphrase) < 8 || os_strlen(passphrase) > 63) { + printf("Passphrase must be 8..63 characters\n"); + return 1; + } + + pbkdf2_sha1(passphrase, ssid, os_strlen(ssid), 4096, psk, 32); + + printf("network={\n"); + printf("\tssid=\"%s\"\n", ssid); + printf("\t#psk=\"%s\"\n", passphrase); + printf("\tpsk="); + for (i = 0; i < 32; i++) + printf("%02x", psk[i]); + printf("\n"); + printf("}\n"); + + return 0; +} diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c new file mode 100644 index 000000000000..4a27125d9c87 --- /dev/null +++ b/wpa_supplicant/wpa_priv.c @@ -0,0 +1,1220 @@ +/* + * WPA Supplicant / privileged helper program + * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" +#ifdef __linux__ +#include <fcntl.h> +#endif /* __linux__ */ +#include <sys/un.h> +#include <sys/stat.h> + +#include "common.h" +#include "eloop.h" +#include "version.h" +#include "drivers/driver.h" +#include "l2_packet/l2_packet.h" +#include "privsep_commands.h" +#include "ieee802_11_defs.h" + +#ifndef ETH_P_EAPOL +#define ETH_P_EAPOL 0x888e +#endif + +#ifndef ETH_P_RSN_PREAUTH +#define ETH_P_RSN_PREAUTH 0x88c7 +#endif + + +struct wpa_priv_interface { + struct wpa_priv_interface *next; + char *driver_name; + char *ifname; + char *sock_name; + int fd; + + struct wpa_driver_ops *driver; + void *drv_priv; + struct sockaddr_un drv_addr; + int wpas_registered; + + /* TODO: add support for multiple l2 connections */ + struct l2_packet_data *l2; + struct sockaddr_un l2_addr; +}; + + +static void wpa_priv_cmd_register(struct wpa_priv_interface *iface, + struct sockaddr_un *from) +{ + if (iface->drv_priv) { + wpa_printf(MSG_DEBUG, "Cleaning up forgotten driver instance"); + if (iface->driver->set_wpa) + iface->driver->set_wpa(iface->drv_priv, 0); + if (iface->driver->deinit) + iface->driver->deinit(iface->drv_priv); + iface->drv_priv = NULL; + iface->wpas_registered = 0; + } + + if (iface->l2) { + wpa_printf(MSG_DEBUG, "Cleaning up forgotten l2_packet " + "instance"); + l2_packet_deinit(iface->l2); + iface->l2 = NULL; + } + + if (iface->driver->init == NULL) + return; + + iface->drv_priv = iface->driver->init(iface, iface->ifname); + if (iface->drv_priv == NULL) { + wpa_printf(MSG_DEBUG, "Failed to initialize driver wrapper"); + return; + } + + wpa_printf(MSG_DEBUG, "Driver wrapper '%s' initialized for interface " + "'%s'", iface->driver_name, iface->ifname); + + os_memcpy(&iface->drv_addr, from, sizeof(iface->drv_addr)); + iface->wpas_registered = 1; + + if (iface->driver->set_param && + iface->driver->set_param(iface->drv_priv, NULL) < 0) { + wpa_printf(MSG_ERROR, "Driver interface rejected param"); + } + + if (iface->driver->set_wpa) + iface->driver->set_wpa(iface->drv_priv, 1); +} + + +static void wpa_priv_cmd_unregister(struct wpa_priv_interface *iface, + struct sockaddr_un *from) +{ + if (iface->drv_priv) { + if (iface->driver->set_wpa) + iface->driver->set_wpa(iface->drv_priv, 0); + if (iface->driver->deinit) + iface->driver->deinit(iface->drv_priv); + iface->drv_priv = NULL; + iface->wpas_registered = 0; + } +} + + +static void wpa_priv_cmd_set_wpa(struct wpa_priv_interface *iface, + char *buf, size_t len) +{ + if (iface->drv_priv == NULL || len != sizeof(int)) + return; + + if (iface->driver->set_wpa) + iface->driver->set_wpa(iface->drv_priv, *((int *) buf)); +} + + +static void wpa_priv_cmd_scan(struct wpa_priv_interface *iface, + char *buf, size_t len) +{ + if (iface->drv_priv == NULL) + return; + + if (iface->driver->scan) + iface->driver->scan(iface->drv_priv, len ? (u8 *) buf : NULL, + len); +} + + +static void wpa_priv_get_scan_results2(struct wpa_priv_interface *iface, + struct sockaddr_un *from) +{ + struct wpa_scan_results *res; + u8 *buf = NULL, *pos, *end; + int val; + size_t i; + + res = iface->driver->get_scan_results2(iface->drv_priv); + if (res == NULL) + goto fail; + + buf = os_malloc(60000); + if (buf == NULL) + goto fail; + pos = buf; + end = buf + 60000; + val = res->num; + os_memcpy(pos, &val, sizeof(int)); + pos += sizeof(int); + + for (i = 0; i < res->num; i++) { + struct wpa_scan_res *r = res->res[i]; + val = sizeof(*r) + r->ie_len; + if (end - pos < (int) sizeof(int) + val) + break; + os_memcpy(pos, &val, sizeof(int)); + pos += sizeof(int); + os_memcpy(pos, r, val); + pos += val; + } + + sendto(iface->fd, buf, pos - buf, 0, (struct sockaddr *) from, + sizeof(*from)); + + os_free(buf); + os_free(res); + return; + +fail: + os_free(buf); + os_free(res); + sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from)); +} + + +static void wpa_priv_send_old_scan_results(struct wpa_priv_interface *iface, + struct sockaddr_un *from) +{ +#define SCAN_AP_LIMIT 128 + int i, res, val; + struct wpa_scan_result *results = NULL; + u8 *buf = NULL, *pos, *end; + struct wpa_scan_res nres; + + results = os_malloc(SCAN_AP_LIMIT * sizeof(*results)); + if (results == NULL) + goto fail; + + res = iface->driver->get_scan_results(iface->drv_priv, results, + SCAN_AP_LIMIT); + if (res < 0 || res > SCAN_AP_LIMIT) + goto fail; + + buf = os_malloc(60000); + if (buf == NULL) + goto fail; + pos = buf; + end = buf + 60000; + os_memcpy(pos, &res, sizeof(int)); + pos += sizeof(int); + + os_memset(&nres, 0, sizeof(nres)); + for (i = 0; i < res; i++) { + struct wpa_scan_result *r = &results[i]; + size_t ie_len; + + ie_len = 2 + r->ssid_len + r->rsn_ie_len + r->wpa_ie_len; + if (r->maxrate) + ie_len += 3; + if (r->mdie_present) + ie_len += 5; + + val = sizeof(nres) + ie_len; + if (end - pos < (int) sizeof(int) + val) + break; + os_memcpy(pos, &val, sizeof(int)); + pos += sizeof(int); + + os_memcpy(nres.bssid, r->bssid, ETH_ALEN); + nres.freq = r->freq; + nres.caps = r->caps; + nres.qual = r->qual; + nres.noise = r->noise; + nres.level = r->level; + nres.tsf = r->tsf; + nres.ie_len = ie_len; + + os_memcpy(pos, &nres, sizeof(nres)); + pos += sizeof(nres); + + /* SSID IE */ + *pos++ = WLAN_EID_SSID; + *pos++ = r->ssid_len; + os_memcpy(pos, r->ssid, r->ssid_len); + pos += r->ssid_len; + + if (r->maxrate) { + /* Fake Supported Rate IE to include max rate */ + *pos++ = WLAN_EID_SUPP_RATES; + *pos++ = 1; + *pos++ = r->maxrate; + } + + if (r->rsn_ie_len) { + os_memcpy(pos, r->rsn_ie, r->rsn_ie_len); + pos += r->rsn_ie_len; + } + + if (r->mdie_present) { + os_memcpy(pos, r->mdie, 5); + pos += 5; + } + + if (r->wpa_ie_len) { + os_memcpy(pos, r->wpa_ie, r->wpa_ie_len); + pos += r->wpa_ie_len; + } + } + + sendto(iface->fd, buf, pos - buf, 0, (struct sockaddr *) from, + sizeof(*from)); + + os_free(buf); + os_free(results); + return; + +fail: + os_free(buf); + os_free(results); + sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from)); +} + + +static void wpa_priv_cmd_get_scan_results(struct wpa_priv_interface *iface, + struct sockaddr_un *from) +{ + if (iface->drv_priv == NULL) + return; + + if (iface->driver->get_scan_results2) + wpa_priv_get_scan_results2(iface, from); + else if (iface->driver->get_scan_results) + wpa_priv_send_old_scan_results(iface, from); + else + sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, + sizeof(*from)); +} + + +static void wpa_priv_cmd_associate(struct wpa_priv_interface *iface, + void *buf, size_t len) +{ + struct wpa_driver_associate_params params; + struct privsep_cmd_associate *assoc; + u8 *bssid; + int res; + + if (iface->drv_priv == NULL || iface->driver->associate == NULL) + return; + + if (len < sizeof(*assoc)) { + wpa_printf(MSG_DEBUG, "Invalid association request"); + return; + } + + assoc = buf; + if (sizeof(*assoc) + assoc->wpa_ie_len > len) { + wpa_printf(MSG_DEBUG, "Association request overflow"); + return; + } + + os_memset(¶ms, 0, sizeof(params)); + bssid = assoc->bssid; + if (bssid[0] | bssid[1] | bssid[2] | bssid[3] | bssid[4] | bssid[5]) + params.bssid = bssid; + params.ssid = assoc->ssid; + if (assoc->ssid_len > 32) + return; + params.ssid_len = assoc->ssid_len; + params.freq = assoc->freq; + if (assoc->wpa_ie_len) { + params.wpa_ie = (u8 *) (assoc + 1); + params.wpa_ie_len = assoc->wpa_ie_len; + } + params.pairwise_suite = assoc->pairwise_suite; + params.group_suite = assoc->group_suite; + params.key_mgmt_suite = assoc->key_mgmt_suite; + params.auth_alg = assoc->auth_alg; + params.mode = assoc->mode; + + res = iface->driver->associate(iface->drv_priv, ¶ms); + wpa_printf(MSG_DEBUG, "drv->associate: res=%d", res); +} + + +static void wpa_priv_cmd_get_bssid(struct wpa_priv_interface *iface, + struct sockaddr_un *from) +{ + u8 bssid[ETH_ALEN]; + + if (iface->drv_priv == NULL) + goto fail; + + if (iface->driver->get_bssid == NULL || + iface->driver->get_bssid(iface->drv_priv, bssid) < 0) + goto fail; + + sendto(iface->fd, bssid, ETH_ALEN, 0, (struct sockaddr *) from, + sizeof(*from)); + return; + +fail: + sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from)); +} + + +static void wpa_priv_cmd_get_ssid(struct wpa_priv_interface *iface, + struct sockaddr_un *from) +{ + u8 ssid[sizeof(int) + 32]; + int res; + + if (iface->drv_priv == NULL) + goto fail; + + if (iface->driver->get_ssid == NULL) + goto fail; + + res = iface->driver->get_ssid(iface->drv_priv, &ssid[sizeof(int)]); + if (res < 0 || res > 32) + goto fail; + os_memcpy(ssid, &res, sizeof(int)); + + sendto(iface->fd, ssid, sizeof(ssid), 0, (struct sockaddr *) from, + sizeof(*from)); + return; + +fail: + sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from)); +} + + +static void wpa_priv_cmd_set_key(struct wpa_priv_interface *iface, + void *buf, size_t len) +{ + struct privsep_cmd_set_key *params; + int res; + + if (iface->drv_priv == NULL || iface->driver->set_key == NULL) + return; + + if (len != sizeof(*params)) { + wpa_printf(MSG_DEBUG, "Invalid set_key request"); + return; + } + + params = buf; + + res = iface->driver->set_key(iface->drv_priv, params->alg, + params->addr, params->key_idx, + params->set_tx, + params->seq_len ? params->seq : NULL, + params->seq_len, + params->key_len ? params->key : NULL, + params->key_len); + wpa_printf(MSG_DEBUG, "drv->set_key: res=%d", res); +} + + +static void wpa_priv_cmd_get_capa(struct wpa_priv_interface *iface, + struct sockaddr_un *from) +{ + struct wpa_driver_capa capa; + + if (iface->drv_priv == NULL) + goto fail; + + if (iface->driver->get_capa == NULL || + iface->driver->get_capa(iface->drv_priv, &capa) < 0) + goto fail; + + sendto(iface->fd, &capa, sizeof(capa), 0, (struct sockaddr *) from, + sizeof(*from)); + return; + +fail: + sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from)); +} + + +static void wpa_priv_l2_rx(void *ctx, const u8 *src_addr, const u8 *buf, + size_t len) +{ + struct wpa_priv_interface *iface = ctx; + struct msghdr msg; + struct iovec io[2]; + + io[0].iov_base = (u8 *) src_addr; + io[0].iov_len = ETH_ALEN; + io[1].iov_base = (u8 *) buf; + io[1].iov_len = len; + + os_memset(&msg, 0, sizeof(msg)); + msg.msg_iov = io; + msg.msg_iovlen = 2; + msg.msg_name = &iface->l2_addr; + msg.msg_namelen = sizeof(iface->l2_addr); + + if (sendmsg(iface->fd, &msg, 0) < 0) { + perror("sendmsg(l2 rx)"); + } +} + + +static void wpa_priv_cmd_l2_register(struct wpa_priv_interface *iface, + struct sockaddr_un *from, + void *buf, size_t len) +{ + int *reg_cmd = buf; + u8 own_addr[ETH_ALEN]; + int res; + u16 proto; + + if (len != 2 * sizeof(int)) { + wpa_printf(MSG_DEBUG, "Invalid l2_register length %lu", + (unsigned long) len); + return; + } + + proto = reg_cmd[0]; + if (proto != ETH_P_EAPOL && proto != ETH_P_RSN_PREAUTH) { + wpa_printf(MSG_DEBUG, "Refused l2_packet connection for " + "ethertype 0x%x", proto); + return; + } + + if (iface->l2) { + wpa_printf(MSG_DEBUG, "Cleaning up forgotten l2_packet " + "instance"); + l2_packet_deinit(iface->l2); + iface->l2 = NULL; + } + + os_memcpy(&iface->l2_addr, from, sizeof(iface->l2_addr)); + + iface->l2 = l2_packet_init(iface->ifname, NULL, proto, + wpa_priv_l2_rx, iface, reg_cmd[1]); + if (iface->l2 == NULL) { + wpa_printf(MSG_DEBUG, "Failed to initialize l2_packet " + "instance for protocol %d", proto); + return; + } + + if (l2_packet_get_own_addr(iface->l2, own_addr) < 0) { + wpa_printf(MSG_DEBUG, "Failed to get own address from " + "l2_packet"); + l2_packet_deinit(iface->l2); + iface->l2 = NULL; + return; + } + + res = sendto(iface->fd, own_addr, ETH_ALEN, 0, + (struct sockaddr *) from, sizeof(*from)); + wpa_printf(MSG_DEBUG, "L2 registration: res=%d", res); +} + + +static void wpa_priv_cmd_l2_unregister(struct wpa_priv_interface *iface, + struct sockaddr_un *from) +{ + if (iface->l2) { + l2_packet_deinit(iface->l2); + iface->l2 = NULL; + } +} + + +static void wpa_priv_cmd_l2_notify_auth_start(struct wpa_priv_interface *iface, + struct sockaddr_un *from) +{ + if (iface->l2) + l2_packet_notify_auth_start(iface->l2); +} + + +static void wpa_priv_cmd_l2_send(struct wpa_priv_interface *iface, + struct sockaddr_un *from, + void *buf, size_t len) +{ + u8 *dst_addr; + u16 proto; + int res; + + if (iface->l2 == NULL) + return; + + if (len < ETH_ALEN + 2) { + wpa_printf(MSG_DEBUG, "Too short L2 send packet (len=%lu)", + (unsigned long) len); + return; + } + + dst_addr = buf; + os_memcpy(&proto, buf + ETH_ALEN, 2); + + if (proto != ETH_P_EAPOL && proto != ETH_P_RSN_PREAUTH) { + wpa_printf(MSG_DEBUG, "Refused l2_packet send for ethertype " + "0x%x", proto); + return; + } + + res = l2_packet_send(iface->l2, dst_addr, proto, buf + ETH_ALEN + 2, + len - ETH_ALEN - 2); + wpa_printf(MSG_DEBUG, "L2 send: res=%d", res); +} + + +static void wpa_priv_cmd_set_mode(struct wpa_priv_interface *iface, + void *buf, size_t len) +{ + if (iface->drv_priv == NULL || iface->driver->set_mode == NULL || + len != sizeof(int)) + return; + + iface->driver->set_mode(iface->drv_priv, *((int *) buf)); +} + + +static void wpa_priv_cmd_set_country(struct wpa_priv_interface *iface, + char *buf) +{ + if (iface->drv_priv == NULL || iface->driver->set_country == NULL || + *buf == '\0') + return; + + iface->driver->set_country(iface->drv_priv, buf); +} + + +static void wpa_priv_receive(int sock, void *eloop_ctx, void *sock_ctx) +{ + struct wpa_priv_interface *iface = eloop_ctx; + char buf[2000], *pos; + void *cmd_buf; + size_t cmd_len; + int res, cmd; + struct sockaddr_un from; + socklen_t fromlen = sizeof(from); + + res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &from, + &fromlen); + if (res < 0) { + perror("recvfrom"); + return; + } + + if (res < (int) sizeof(int)) { + wpa_printf(MSG_DEBUG, "Too short command (len=%d)", res); + return; + } + + os_memcpy(&cmd, buf, sizeof(int)); + wpa_printf(MSG_DEBUG, "Command %d for interface %s", + cmd, iface->ifname); + cmd_buf = &buf[sizeof(int)]; + cmd_len = res - sizeof(int); + + switch (cmd) { + case PRIVSEP_CMD_REGISTER: + wpa_priv_cmd_register(iface, &from); + break; + case PRIVSEP_CMD_UNREGISTER: + wpa_priv_cmd_unregister(iface, &from); + break; + case PRIVSEP_CMD_SET_WPA: + wpa_priv_cmd_set_wpa(iface, cmd_buf, cmd_len); + break; + case PRIVSEP_CMD_SCAN: + wpa_priv_cmd_scan(iface, cmd_buf, cmd_len); + break; + case PRIVSEP_CMD_GET_SCAN_RESULTS: + wpa_priv_cmd_get_scan_results(iface, &from); + break; + case PRIVSEP_CMD_ASSOCIATE: + wpa_priv_cmd_associate(iface, cmd_buf, cmd_len); + break; + case PRIVSEP_CMD_GET_BSSID: + wpa_priv_cmd_get_bssid(iface, &from); + break; + case PRIVSEP_CMD_GET_SSID: + wpa_priv_cmd_get_ssid(iface, &from); + break; + case PRIVSEP_CMD_SET_KEY: + wpa_priv_cmd_set_key(iface, cmd_buf, cmd_len); + break; + case PRIVSEP_CMD_GET_CAPA: + wpa_priv_cmd_get_capa(iface, &from); + break; + case PRIVSEP_CMD_L2_REGISTER: + wpa_priv_cmd_l2_register(iface, &from, cmd_buf, cmd_len); + break; + case PRIVSEP_CMD_L2_UNREGISTER: + wpa_priv_cmd_l2_unregister(iface, &from); + break; + case PRIVSEP_CMD_L2_NOTIFY_AUTH_START: + wpa_priv_cmd_l2_notify_auth_start(iface, &from); + break; + case PRIVSEP_CMD_L2_SEND: + wpa_priv_cmd_l2_send(iface, &from, cmd_buf, cmd_len); + break; + case PRIVSEP_CMD_SET_MODE: + wpa_priv_cmd_set_mode(iface, cmd_buf, cmd_len); + break; + case PRIVSEP_CMD_SET_COUNTRY: + pos = cmd_buf; + if (pos + cmd_len >= buf + sizeof(buf)) + break; + pos[cmd_len] = '\0'; + wpa_priv_cmd_set_country(iface, pos); + break; + } +} + + +static void wpa_priv_interface_deinit(struct wpa_priv_interface *iface) +{ + if (iface->drv_priv && iface->driver->deinit) + iface->driver->deinit(iface->drv_priv); + + if (iface->fd >= 0) { + eloop_unregister_read_sock(iface->fd); + close(iface->fd); + unlink(iface->sock_name); + } + + if (iface->l2) + l2_packet_deinit(iface->l2); + + os_free(iface->ifname); + os_free(iface->driver_name); + os_free(iface->sock_name); + os_free(iface); +} + + +extern struct wpa_driver_ops *wpa_supplicant_drivers[]; + +static struct wpa_priv_interface * +wpa_priv_interface_init(const char *dir, const char *params) +{ + struct wpa_priv_interface *iface; + char *pos; + size_t len; + struct sockaddr_un addr; + int i; + + pos = os_strchr(params, ':'); + if (pos == NULL) + return NULL; + + iface = os_zalloc(sizeof(*iface)); + if (iface == NULL) + return NULL; + iface->fd = -1; + + len = pos - params; + iface->driver_name = os_malloc(len + 1); + if (iface->driver_name == NULL) { + wpa_priv_interface_deinit(iface); + return NULL; + } + os_memcpy(iface->driver_name, params, len); + iface->driver_name[len] = '\0'; + + for (i = 0; wpa_supplicant_drivers[i]; i++) { + if (os_strcmp(iface->driver_name, + wpa_supplicant_drivers[i]->name) == 0) { + iface->driver = wpa_supplicant_drivers[i]; + break; + } + } + if (iface->driver == NULL) { + wpa_printf(MSG_ERROR, "Unsupported driver '%s'", + iface->driver_name); + wpa_priv_interface_deinit(iface); + return NULL; + } + + pos++; + iface->ifname = os_strdup(pos); + if (iface->ifname == NULL) { + wpa_priv_interface_deinit(iface); + return NULL; + } + + len = os_strlen(dir) + 1 + os_strlen(iface->ifname); + iface->sock_name = os_malloc(len + 1); + if (iface->sock_name == NULL) { + wpa_priv_interface_deinit(iface); + return NULL; + } + + os_snprintf(iface->sock_name, len + 1, "%s/%s", dir, iface->ifname); + if (os_strlen(iface->sock_name) >= sizeof(addr.sun_path)) { + wpa_priv_interface_deinit(iface); + return NULL; + } + + iface->fd = socket(PF_UNIX, SOCK_DGRAM, 0); + if (iface->fd < 0) { + perror("socket(PF_UNIX)"); + wpa_priv_interface_deinit(iface); + return NULL; + } + + os_memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + os_strlcpy(addr.sun_path, iface->sock_name, sizeof(addr.sun_path)); + + if (bind(iface->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + wpa_printf(MSG_DEBUG, "bind(PF_UNIX) failed: %s", + strerror(errno)); + if (connect(iface->fd, (struct sockaddr *) &addr, + sizeof(addr)) < 0) { + wpa_printf(MSG_DEBUG, "Socket exists, but does not " + "allow connections - assuming it was " + "leftover from forced program termination"); + if (unlink(iface->sock_name) < 0) { + perror("unlink[ctrl_iface]"); + wpa_printf(MSG_ERROR, "Could not unlink " + "existing ctrl_iface socket '%s'", + iface->sock_name); + goto fail; + } + if (bind(iface->fd, (struct sockaddr *) &addr, + sizeof(addr)) < 0) { + perror("bind(PF_UNIX)"); + goto fail; + } + wpa_printf(MSG_DEBUG, "Successfully replaced leftover " + "socket '%s'", iface->sock_name); + } else { + wpa_printf(MSG_INFO, "Socket exists and seems to be " + "in use - cannot override it"); + wpa_printf(MSG_INFO, "Delete '%s' manually if it is " + "not used anymore", iface->sock_name); + goto fail; + } + } + + if (chmod(iface->sock_name, S_IRWXU | S_IRWXG | S_IRWXO) < 0) { + perror("chmod"); + goto fail; + } + + eloop_register_read_sock(iface->fd, wpa_priv_receive, iface, NULL); + + return iface; + +fail: + wpa_priv_interface_deinit(iface); + return NULL; +} + + +static int wpa_priv_send_event(struct wpa_priv_interface *iface, int event, + const void *data, size_t data_len) +{ + struct msghdr msg; + struct iovec io[2]; + + io[0].iov_base = &event; + io[0].iov_len = sizeof(event); + io[1].iov_base = (u8 *) data; + io[1].iov_len = data_len; + + os_memset(&msg, 0, sizeof(msg)); + msg.msg_iov = io; + msg.msg_iovlen = data ? 2 : 1; + msg.msg_name = &iface->drv_addr; + msg.msg_namelen = sizeof(iface->drv_addr); + + if (sendmsg(iface->fd, &msg, 0) < 0) { + perror("sendmsg(wpas_socket)"); + return -1; + } + + return 0; +} + + +static void wpa_priv_send_assoc(struct wpa_priv_interface *iface, int event, + union wpa_event_data *data) +{ + size_t buflen = 3 * sizeof(int); + u8 *buf, *pos; + int len; + + if (data) { + buflen += data->assoc_info.req_ies_len + + data->assoc_info.resp_ies_len + + data->assoc_info.beacon_ies_len; + } + + buf = os_malloc(buflen); + if (buf == NULL) + return; + + pos = buf; + + if (data && data->assoc_info.req_ies) { + len = data->assoc_info.req_ies_len; + os_memcpy(pos, &len, sizeof(int)); + pos += sizeof(int); + os_memcpy(pos, data->assoc_info.req_ies, len); + pos += len; + } else { + len = 0; + os_memcpy(pos, &len, sizeof(int)); + pos += sizeof(int); + } + + if (data && data->assoc_info.resp_ies) { + len = data->assoc_info.resp_ies_len; + os_memcpy(pos, &len, sizeof(int)); + pos += sizeof(int); + os_memcpy(pos, data->assoc_info.resp_ies, len); + pos += len; + } else { + len = 0; + os_memcpy(pos, &len, sizeof(int)); + pos += sizeof(int); + } + + if (data && data->assoc_info.beacon_ies) { + len = data->assoc_info.beacon_ies_len; + os_memcpy(pos, &len, sizeof(int)); + pos += sizeof(int); + os_memcpy(pos, data->assoc_info.beacon_ies, len); + pos += len; + } else { + len = 0; + os_memcpy(pos, &len, sizeof(int)); + pos += sizeof(int); + } + + wpa_priv_send_event(iface, event, buf, buflen); + + os_free(buf); +} + + +static void wpa_priv_send_interface_status(struct wpa_priv_interface *iface, + union wpa_event_data *data) +{ + int ievent; + size_t len, maxlen; + u8 *buf; + char *ifname; + + if (data == NULL) + return; + + ievent = data->interface_status.ievent; + maxlen = sizeof(data->interface_status.ifname); + ifname = data->interface_status.ifname; + for (len = 0; len < maxlen && ifname[len]; len++) + ; + + buf = os_malloc(sizeof(int) + len); + if (buf == NULL) + return; + + os_memcpy(buf, &ievent, sizeof(int)); + os_memcpy(buf + sizeof(int), ifname, len); + + wpa_priv_send_event(iface, PRIVSEP_EVENT_INTERFACE_STATUS, + buf, sizeof(int) + len); + + os_free(buf); + +} + + +static void wpa_priv_send_ft_response(struct wpa_priv_interface *iface, + union wpa_event_data *data) +{ + size_t len; + u8 *buf, *pos; + + if (data == NULL || data->ft_ies.ies == NULL) + return; + + len = sizeof(int) + ETH_ALEN + data->ft_ies.ies_len; + buf = os_malloc(len); + if (buf == NULL) + return; + + pos = buf; + os_memcpy(pos, &data->ft_ies.ft_action, sizeof(int)); + pos += sizeof(int); + os_memcpy(pos, data->ft_ies.target_ap, ETH_ALEN); + pos += ETH_ALEN; + os_memcpy(pos, data->ft_ies.ies, data->ft_ies.ies_len); + + wpa_priv_send_event(iface, PRIVSEP_EVENT_FT_RESPONSE, buf, len); + + os_free(buf); + +} + + +void wpa_supplicant_event(void *ctx, wpa_event_type event, + union wpa_event_data *data) +{ + struct wpa_priv_interface *iface = ctx; + + wpa_printf(MSG_DEBUG, "%s - event=%d", __func__, event); + + if (!iface->wpas_registered) { + wpa_printf(MSG_DEBUG, "Driver event received, but " + "wpa_supplicant not registered"); + return; + } + + switch (event) { + case EVENT_ASSOC: + wpa_priv_send_assoc(iface, PRIVSEP_EVENT_ASSOC, data); + break; + case EVENT_DISASSOC: + wpa_priv_send_event(iface, PRIVSEP_EVENT_DISASSOC, NULL, 0); + break; + case EVENT_ASSOCINFO: + if (data == NULL) + return; + wpa_priv_send_assoc(iface, PRIVSEP_EVENT_ASSOCINFO, data); + break; + case EVENT_MICHAEL_MIC_FAILURE: + if (data == NULL) + return; + wpa_priv_send_event(iface, PRIVSEP_EVENT_MICHAEL_MIC_FAILURE, + &data->michael_mic_failure.unicast, + sizeof(int)); + break; + case EVENT_SCAN_RESULTS: + wpa_priv_send_event(iface, PRIVSEP_EVENT_SCAN_RESULTS, NULL, + 0); + break; + case EVENT_INTERFACE_STATUS: + wpa_priv_send_interface_status(iface, data); + break; + case EVENT_PMKID_CANDIDATE: + if (data == NULL) + return; + wpa_priv_send_event(iface, PRIVSEP_EVENT_PMKID_CANDIDATE, + &data->pmkid_candidate, + sizeof(struct pmkid_candidate)); + break; + case EVENT_STKSTART: + if (data == NULL) + return; + wpa_priv_send_event(iface, PRIVSEP_EVENT_STKSTART, + &data->stkstart.peer, ETH_ALEN); + break; + case EVENT_FT_RESPONSE: + wpa_priv_send_ft_response(iface, data); + break; + default: + wpa_printf(MSG_DEBUG, "Unsupported driver event %d - TODO", + event); + break; + } +} + + +void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, + const u8 *buf, size_t len) +{ + struct wpa_priv_interface *iface = ctx; + struct msghdr msg; + struct iovec io[3]; + int event = PRIVSEP_EVENT_RX_EAPOL; + + wpa_printf(MSG_DEBUG, "RX EAPOL from driver"); + io[0].iov_base = &event; + io[0].iov_len = sizeof(event); + io[1].iov_base = (u8 *) src_addr; + io[1].iov_len = ETH_ALEN; + io[2].iov_base = (u8 *) buf; + io[2].iov_len = len; + + os_memset(&msg, 0, sizeof(msg)); + msg.msg_iov = io; + msg.msg_iovlen = 3; + msg.msg_name = &iface->drv_addr; + msg.msg_namelen = sizeof(iface->drv_addr); + + if (sendmsg(iface->fd, &msg, 0) < 0) + perror("sendmsg(wpas_socket)"); +} + + +#ifdef CONFIG_CLIENT_MLME +void wpa_supplicant_sta_free_hw_features(struct wpa_hw_modes *hw_features, + size_t num_hw_features) +{ + size_t i; + + if (hw_features == NULL) + return; + + for (i = 0; i < num_hw_features; i++) { + os_free(hw_features[i].channels); + os_free(hw_features[i].rates); + } + + os_free(hw_features); +} + + +void wpa_supplicant_sta_rx(void *ctx, const u8 *buf, size_t len, + struct ieee80211_rx_status *rx_status) +{ + struct wpa_priv_interface *iface = ctx; + struct msghdr msg; + struct iovec io[3]; + int event = PRIVSEP_EVENT_STA_RX; + + wpa_printf(MSG_DEBUG, "STA RX from driver"); + io[0].iov_base = &event; + io[0].iov_len = sizeof(event); + io[1].iov_base = (u8 *) rx_status; + io[1].iov_len = sizeof(*rx_status); + io[2].iov_base = (u8 *) buf; + io[2].iov_len = len; + + os_memset(&msg, 0, sizeof(msg)); + msg.msg_iov = io; + msg.msg_iovlen = 3; + msg.msg_name = &iface->drv_addr; + msg.msg_namelen = sizeof(iface->drv_addr); + + if (sendmsg(iface->fd, &msg, 0) < 0) + perror("sendmsg(wpas_socket)"); +} +#endif /* CONFIG_CLIENT_MLME */ + + +static void wpa_priv_terminate(int sig, void *eloop_ctx, void *signal_ctx) +{ + wpa_printf(MSG_DEBUG, "wpa_priv termination requested"); + eloop_terminate(); +} + + +static void wpa_priv_fd_workaround(void) +{ +#ifdef __linux__ + int s, i; + /* When started from pcmcia-cs scripts, wpa_supplicant might start with + * fd 0, 1, and 2 closed. This will cause some issues because many + * places in wpa_supplicant are still printing out to stdout. As a + * workaround, make sure that fd's 0, 1, and 2 are not used for other + * sockets. */ + for (i = 0; i < 3; i++) { + s = open("/dev/null", O_RDWR); + if (s > 2) { + close(s); + break; + } + } +#endif /* __linux__ */ +} + + +static void usage(void) +{ + printf("wpa_priv v" VERSION_STR "\n" + "Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi> and " + "contributors\n" + "\n" + "usage:\n" + " wpa_priv [-Bdd] [-P<pid file>] <driver:ifname> " + "[driver:ifname ...]\n"); +} + + +extern int wpa_debug_level; + +int main(int argc, char *argv[]) +{ + int c, i; + int ret = -1; + char *pid_file = NULL; + int daemonize = 0; + char *ctrl_dir = "/var/run/wpa_priv"; + struct wpa_priv_interface *interfaces = NULL, *iface; + + if (os_program_init()) + return -1; + + wpa_priv_fd_workaround(); + + for (;;) { + c = getopt(argc, argv, "Bc:dP:"); + if (c < 0) + break; + switch (c) { + case 'B': + daemonize++; + break; + case 'c': + ctrl_dir = optarg; + break; + case 'd': + wpa_debug_level--; + break; + case 'P': + pid_file = os_rel2abs_path(optarg); + break; + default: + usage(); + goto out; + } + } + + if (optind >= argc) { + usage(); + goto out; + } + + wpa_printf(MSG_DEBUG, "wpa_priv control directory: '%s'", ctrl_dir); + + if (eloop_init(NULL)) { + wpa_printf(MSG_ERROR, "Failed to initialize event loop"); + goto out; + } + + for (i = optind; i < argc; i++) { + wpa_printf(MSG_DEBUG, "Adding driver:interface %s", argv[i]); + iface = wpa_priv_interface_init(ctrl_dir, argv[i]); + if (iface == NULL) + goto out; + iface->next = interfaces; + interfaces = iface; + } + + if (daemonize && os_daemonize(pid_file)) + goto out; + + eloop_register_signal_terminate(wpa_priv_terminate, NULL); + eloop_run(); + + ret = 0; + +out: + iface = interfaces; + while (iface) { + struct wpa_priv_interface *prev = iface; + iface = iface->next; + wpa_priv_interface_deinit(prev); + } + + eloop_destroy(); + + os_daemonize_terminate(pid_file); + os_free(pid_file); + os_program_deinit(); + + return ret; +} diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c new file mode 100644 index 000000000000..c1f95cb73ad2 --- /dev/null +++ b/wpa_supplicant/wpa_supplicant.c @@ -0,0 +1,2170 @@ +/* + * WPA Supplicant + * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + * + * This file implements functions for registering and unregistering + * %wpa_supplicant interfaces. In addition, this file contains number of + * functions for managing network connections. + */ + +#include "includes.h" + +#include "common.h" +#include "eapol_supp/eapol_supp_sm.h" +#include "eap_peer/eap.h" +#include "wpa.h" +#include "eloop.h" +#include "drivers/driver.h" +#include "config.h" +#include "l2_packet/l2_packet.h" +#include "wpa_supplicant_i.h" +#include "ctrl_iface.h" +#include "ctrl_iface_dbus.h" +#include "pcsc_funcs.h" +#include "version.h" +#include "preauth.h" +#include "pmksa_cache.h" +#include "wpa_ctrl.h" +#include "mlme.h" +#include "ieee802_11_defs.h" +#include "blacklist.h" +#include "wpas_glue.h" +#include "wps_supplicant.h" + +const char *wpa_supplicant_version = +"wpa_supplicant v" VERSION_STR "\n" +"Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi> and contributors"; + +const char *wpa_supplicant_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" +#ifdef EAP_TLS_OPENSSL +"\nThis product includes software developed by the OpenSSL Project\n" +"for use in the OpenSSL Toolkit (http://www.openssl.org/)\n" +#endif /* EAP_TLS_OPENSSL */ +; + +#ifndef CONFIG_NO_STDOUT_DEBUG +/* Long text divided into parts in order to fit in C89 strings size limits. */ +const char *wpa_supplicant_full_license1 = +"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"; +const char *wpa_supplicant_full_license2 = +"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"; +const char *wpa_supplicant_full_license3 = +"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"; +const char *wpa_supplicant_full_license4 = +"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"; +const char *wpa_supplicant_full_license5 = +"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"; +#endif /* CONFIG_NO_STDOUT_DEBUG */ + +extern int wpa_debug_level; +extern int wpa_debug_show_keys; +extern int wpa_debug_timestamp; + +/* Configure default/group WEP keys for static WEP */ +static int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + int i, set = 0; + + for (i = 0; i < NUM_WEP_KEYS; i++) { + if (ssid->wep_key_len[i] == 0) + continue; + + set = 1; + wpa_drv_set_key(wpa_s, WPA_ALG_WEP, + (u8 *) "\xff\xff\xff\xff\xff\xff", + i, i == ssid->wep_tx_keyidx, (u8 *) "", 0, + ssid->wep_key[i], ssid->wep_key_len[i]); + } + + return set; +} + + +static int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + u8 key[32]; + size_t keylen; + wpa_alg alg; + u8 seq[6] = { 0 }; + + /* IBSS/WPA-None uses only one key (Group) for both receiving and + * sending unicast and multicast packets. */ + + if (ssid->mode != IEEE80211_MODE_IBSS) { + wpa_printf(MSG_INFO, "WPA: Invalid mode %d (not IBSS/ad-hoc) " + "for WPA-None", ssid->mode); + return -1; + } + + if (!ssid->psk_set) { + wpa_printf(MSG_INFO, "WPA: No PSK configured for WPA-None"); + return -1; + } + + switch (wpa_s->group_cipher) { + case WPA_CIPHER_CCMP: + os_memcpy(key, ssid->psk, 16); + keylen = 16; + alg = WPA_ALG_CCMP; + break; + case WPA_CIPHER_TKIP: + /* WPA-None uses the same Michael MIC key for both TX and RX */ + os_memcpy(key, ssid->psk, 16 + 8); + os_memcpy(key + 16 + 8, ssid->psk + 16, 8); + keylen = 32; + alg = WPA_ALG_TKIP; + break; + default: + wpa_printf(MSG_INFO, "WPA: Invalid group cipher %d for " + "WPA-None", wpa_s->group_cipher); + return -1; + } + + /* TODO: should actually remember the previously used seq#, both for TX + * and RX from each STA.. */ + + return wpa_drv_set_key(wpa_s, alg, (u8 *) "\xff\xff\xff\xff\xff\xff", + 0, 1, seq, 6, key, keylen); +} + + +static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + const u8 *bssid = wpa_s->bssid; + if (is_zero_ether_addr(bssid)) + bssid = wpa_s->pending_bssid; + wpa_msg(wpa_s, MSG_INFO, "Authentication with " MACSTR " timed out.", + MAC2STR(bssid)); + wpa_blacklist_add(wpa_s, bssid); + wpa_sm_notify_disassoc(wpa_s->wpa); + wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); + wpa_s->reassociate = 1; + wpa_supplicant_req_scan(wpa_s, 0, 0); +} + + +/** + * wpa_supplicant_req_auth_timeout - Schedule a timeout for authentication + * @wpa_s: Pointer to wpa_supplicant data + * @sec: Number of seconds after which to time out authentication + * @usec: Number of microseconds after which to time out authentication + * + * This function is used to schedule a timeout for the current authentication + * attempt. + */ +void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s, + int sec, int usec) +{ + if (wpa_s->conf && wpa_s->conf->ap_scan == 0 && + wpa_s->driver && IS_WIRED(wpa_s->driver)) + return; + + wpa_msg(wpa_s, MSG_DEBUG, "Setting authentication timeout: %d sec " + "%d usec", sec, usec); + eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL); + eloop_register_timeout(sec, usec, wpa_supplicant_timeout, wpa_s, NULL); +} + + +/** + * wpa_supplicant_cancel_auth_timeout - Cancel authentication timeout + * @wpa_s: Pointer to wpa_supplicant data + * + * This function is used to cancel authentication timeout scheduled with + * wpa_supplicant_req_auth_timeout() and it is called when authentication has + * been completed. + */ +void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s) +{ + wpa_msg(wpa_s, MSG_DEBUG, "Cancelling authentication timeout"); + eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL); + wpa_blacklist_del(wpa_s, wpa_s->bssid); +} + + +/** + * wpa_supplicant_initiate_eapol - Configure EAPOL state machine + * @wpa_s: Pointer to wpa_supplicant data + * + * This function is used to configure EAPOL state machine based on the selected + * authentication mode. + */ +void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s) +{ +#ifdef IEEE8021X_EAPOL + struct eapol_config eapol_conf; + struct wpa_ssid *ssid = wpa_s->current_ssid; + + eapol_sm_notify_eap_success(wpa_s->eapol, FALSE); + eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE); + + if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE || + wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) + eapol_sm_notify_portControl(wpa_s->eapol, ForceAuthorized); + else + eapol_sm_notify_portControl(wpa_s->eapol, Auto); + + os_memset(&eapol_conf, 0, sizeof(eapol_conf)); + if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { + eapol_conf.accept_802_1x_keys = 1; + eapol_conf.required_keys = 0; + if (ssid->eapol_flags & EAPOL_FLAG_REQUIRE_KEY_UNICAST) { + eapol_conf.required_keys |= EAPOL_REQUIRE_KEY_UNICAST; + } + if (ssid->eapol_flags & EAPOL_FLAG_REQUIRE_KEY_BROADCAST) { + eapol_conf.required_keys |= + EAPOL_REQUIRE_KEY_BROADCAST; + } + + if (wpa_s->conf && wpa_s->driver && IS_WIRED(wpa_s->driver)) { + eapol_conf.required_keys = 0; + } + } + if (wpa_s->conf) + eapol_conf.fast_reauth = wpa_s->conf->fast_reauth; + eapol_conf.workaround = ssid->eap_workaround; + eapol_conf.eap_disabled = + !wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) && + wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA && + wpa_s->key_mgmt != WPA_KEY_MGMT_WPS; + eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf); +#endif /* IEEE8021X_EAPOL */ +} + + +/** + * wpa_supplicant_set_non_wpa_policy - Set WPA parameters to non-WPA mode + * @wpa_s: Pointer to wpa_supplicant data + * @ssid: Configuration data for the network + * + * This function is used to configure WPA state machine and related parameters + * to a mode where WPA is not enabled. This is called as part of the + * authentication configuration when the selected network does not use WPA. + */ +void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + int i; + + if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) + wpa_s->key_mgmt = WPA_KEY_MGMT_WPS; + else if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) + wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_NO_WPA; + else + wpa_s->key_mgmt = WPA_KEY_MGMT_NONE; + wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0); + wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0); + wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0); + wpa_s->pairwise_cipher = WPA_CIPHER_NONE; + wpa_s->group_cipher = WPA_CIPHER_NONE; + wpa_s->mgmt_group_cipher = 0; + + for (i = 0; i < NUM_WEP_KEYS; i++) { + if (ssid->wep_key_len[i] > 5) { + wpa_s->pairwise_cipher = WPA_CIPHER_WEP104; + wpa_s->group_cipher = WPA_CIPHER_WEP104; + break; + } else if (ssid->wep_key_len[i] > 0) { + wpa_s->pairwise_cipher = WPA_CIPHER_WEP40; + wpa_s->group_cipher = WPA_CIPHER_WEP40; + break; + } + } + + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED, 0); + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt); + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE, + wpa_s->pairwise_cipher); + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher); +#ifdef CONFIG_IEEE80211W + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP, + wpa_s->mgmt_group_cipher); +#endif /* CONFIG_IEEE80211W */ + + pmksa_cache_clear_current(wpa_s->wpa); +} + + +static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) +{ + scard_deinit(wpa_s->scard); + wpa_s->scard = NULL; + wpa_sm_set_scard_ctx(wpa_s->wpa, NULL); + eapol_sm_register_scard_ctx(wpa_s->eapol, NULL); + l2_packet_deinit(wpa_s->l2); + wpa_s->l2 = NULL; + if (wpa_s->l2_br) { + l2_packet_deinit(wpa_s->l2_br); + wpa_s->l2_br = NULL; + } + + if (wpa_s->ctrl_iface) { + wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface); + wpa_s->ctrl_iface = NULL; + } + if (wpa_s->conf != NULL) { + wpa_config_free(wpa_s->conf); + wpa_s->conf = NULL; + } + + os_free(wpa_s->confname); + wpa_s->confname = NULL; + + wpa_sm_set_eapol(wpa_s->wpa, NULL); + eapol_sm_deinit(wpa_s->eapol); + wpa_s->eapol = NULL; + + rsn_preauth_deinit(wpa_s->wpa); + + pmksa_candidate_free(wpa_s->wpa); + wpa_sm_deinit(wpa_s->wpa); + wpa_s->wpa = NULL; + wpa_blacklist_clear(wpa_s); + + wpa_scan_results_free(wpa_s->scan_res); + wpa_s->scan_res = NULL; + + wpa_supplicant_cancel_scan(wpa_s); + wpa_supplicant_cancel_auth_timeout(wpa_s); + + ieee80211_sta_deinit(wpa_s); + + wpas_wps_deinit(wpa_s); +} + + +/** + * wpa_clear_keys - Clear keys configured for the driver + * @wpa_s: Pointer to wpa_supplicant data + * @addr: Previously used BSSID or %NULL if not available + * + * This function clears the encryption keys that has been previously configured + * for the driver. + */ +void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr) +{ + u8 *bcast = (u8 *) "\xff\xff\xff\xff\xff\xff"; + + if (wpa_s->keys_cleared) { + /* Some drivers (e.g., ndiswrapper & NDIS drivers) seem to have + * timing issues with keys being cleared just before new keys + * are set or just after association or something similar. This + * shows up in group key handshake failing often because of the + * client not receiving the first encrypted packets correctly. + * Skipping some of the extra key clearing steps seems to help + * in completing group key handshake more reliably. */ + wpa_printf(MSG_DEBUG, "No keys have been configured - " + "skip key clearing"); + return; + } + + /* MLME-DELETEKEYS.request */ + wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 0, 0, NULL, 0, NULL, 0); + wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 1, 0, NULL, 0, NULL, 0); + wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 2, 0, NULL, 0, NULL, 0); + wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 3, 0, NULL, 0, NULL, 0); + if (addr) { + wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL, + 0); + /* MLME-SETPROTECTION.request(None) */ + wpa_drv_mlme_setprotection( + wpa_s, addr, + MLME_SETPROTECTION_PROTECT_TYPE_NONE, + MLME_SETPROTECTION_KEY_TYPE_PAIRWISE); + } + wpa_s->keys_cleared = 1; +} + + +/** + * wpa_supplicant_state_txt - Get the connection state name as a text string + * @state: State (wpa_state; WPA_*) + * Returns: The state name as a printable text string + */ +const char * wpa_supplicant_state_txt(int state) +{ + switch (state) { + case WPA_DISCONNECTED: + return "DISCONNECTED"; + case WPA_INACTIVE: + return "INACTIVE"; + case WPA_SCANNING: + return "SCANNING"; + case WPA_ASSOCIATING: + return "ASSOCIATING"; + case WPA_ASSOCIATED: + return "ASSOCIATED"; + case WPA_4WAY_HANDSHAKE: + return "4WAY_HANDSHAKE"; + case WPA_GROUP_HANDSHAKE: + return "GROUP_HANDSHAKE"; + case WPA_COMPLETED: + return "COMPLETED"; + default: + return "UNKNOWN"; + } +} + + +/** + * wpa_supplicant_set_state - Set current connection state + * @wpa_s: Pointer to wpa_supplicant data + * @state: The new connection state + * + * This function is called whenever the connection state changes, e.g., + * association is completed for WPA/WPA2 4-Way Handshake is started. + */ +void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s, wpa_states state) +{ + wpa_printf(MSG_DEBUG, "State: %s -> %s", + wpa_supplicant_state_txt(wpa_s->wpa_state), + wpa_supplicant_state_txt(state)); + + wpa_supplicant_dbus_notify_state_change(wpa_s, state, + wpa_s->wpa_state); + + if (state == WPA_COMPLETED && wpa_s->new_connection) { +#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) + struct wpa_ssid *ssid = wpa_s->current_ssid; + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- Connection to " + MACSTR " completed %s [id=%d id_str=%s]", + MAC2STR(wpa_s->bssid), wpa_s->reassociated_connection ? + "(reauth)" : "(auth)", + ssid ? ssid->id : -1, + ssid && ssid->id_str ? ssid->id_str : ""); +#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ + wpa_s->new_connection = 0; + wpa_s->reassociated_connection = 1; + wpa_drv_set_operstate(wpa_s, 1); + } else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING || + state == WPA_ASSOCIATED) { + wpa_s->new_connection = 1; + wpa_drv_set_operstate(wpa_s, 0); + } + wpa_s->wpa_state = state; +} + + +static void wpa_supplicant_terminate(int sig, void *eloop_ctx, + void *signal_ctx) +{ + struct wpa_global *global = eloop_ctx; + struct wpa_supplicant *wpa_s; + for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TERMINATING "- signal %d " + "received", sig); + } + eloop_terminate(); +} + + +static void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s) +{ + wpa_s->pairwise_cipher = 0; + wpa_s->group_cipher = 0; + wpa_s->mgmt_group_cipher = 0; + wpa_s->key_mgmt = 0; + wpa_s->wpa_state = WPA_DISCONNECTED; +} + + +/** + * wpa_supplicant_reload_configuration - Reload configuration data + * @wpa_s: Pointer to wpa_supplicant data + * Returns: 0 on success or -1 if configuration parsing failed + * + * This function can be used to request that the configuration data is reloaded + * (e.g., after configuration file change). This function is reloading + * configuration only for one interface, so this may need to be called multiple + * times if %wpa_supplicant is controlling multiple interfaces and all + * interfaces need reconfiguration. + */ +int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s) +{ + struct wpa_config *conf; + int reconf_ctrl; + if (wpa_s->confname == NULL) + return -1; + conf = wpa_config_read(wpa_s->confname); + if (conf == NULL) { + wpa_msg(wpa_s, MSG_ERROR, "Failed to parse the configuration " + "file '%s' - exiting", wpa_s->confname); + return -1; + } + + reconf_ctrl = !!conf->ctrl_interface != !!wpa_s->conf->ctrl_interface + || (conf->ctrl_interface && wpa_s->conf->ctrl_interface && + os_strcmp(conf->ctrl_interface, + wpa_s->conf->ctrl_interface) != 0); + + if (reconf_ctrl && wpa_s->ctrl_iface) { + wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface); + wpa_s->ctrl_iface = NULL; + } + + eapol_sm_invalidate_cached_session(wpa_s->eapol); + wpa_s->current_ssid = NULL; + /* + * TODO: should notify EAPOL SM about changes in opensc_engine_path, + * pkcs11_engine_path, pkcs11_module_path. + */ + if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) { + /* + * Clear forced success to clear EAP state for next + * authentication. + */ + eapol_sm_notify_eap_success(wpa_s->eapol, FALSE); + } + eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); + wpa_sm_set_config(wpa_s->wpa, NULL); + wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth); + rsn_preauth_deinit(wpa_s->wpa); + wpa_config_free(wpa_s->conf); + wpa_s->conf = conf; + if (reconf_ctrl) + wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s); + + wpa_supplicant_clear_status(wpa_s); + wpa_s->reassociate = 1; + wpa_supplicant_req_scan(wpa_s, 0, 0); + wpa_msg(wpa_s, MSG_DEBUG, "Reconfiguration completed"); + return 0; +} + + +static void wpa_supplicant_reconfig(int sig, void *eloop_ctx, + void *signal_ctx) +{ + struct wpa_global *global = eloop_ctx; + struct wpa_supplicant *wpa_s; + wpa_printf(MSG_DEBUG, "Signal %d received - reconfiguring", sig); + for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { + if (wpa_supplicant_reload_configuration(wpa_s) < 0) { + eloop_terminate(); + } + } +} + + +static wpa_cipher cipher_suite2driver(int cipher) +{ + switch (cipher) { + case WPA_CIPHER_NONE: + return CIPHER_NONE; + case WPA_CIPHER_WEP40: + return CIPHER_WEP40; + case WPA_CIPHER_WEP104: + return CIPHER_WEP104; + case WPA_CIPHER_CCMP: + return CIPHER_CCMP; + case WPA_CIPHER_TKIP: + default: + return CIPHER_TKIP; + } +} + + +static wpa_key_mgmt key_mgmt2driver(int key_mgmt) +{ + switch (key_mgmt) { + case WPA_KEY_MGMT_NONE: + return KEY_MGMT_NONE; + case WPA_KEY_MGMT_IEEE8021X_NO_WPA: + return KEY_MGMT_802_1X_NO_WPA; + case WPA_KEY_MGMT_IEEE8021X: + return KEY_MGMT_802_1X; + case WPA_KEY_MGMT_WPA_NONE: + return KEY_MGMT_WPA_NONE; + case WPA_KEY_MGMT_FT_IEEE8021X: + return KEY_MGMT_FT_802_1X; + case WPA_KEY_MGMT_FT_PSK: + return KEY_MGMT_FT_PSK; + case WPA_KEY_MGMT_IEEE8021X_SHA256: + return KEY_MGMT_802_1X_SHA256; + case WPA_KEY_MGMT_PSK_SHA256: + return KEY_MGMT_PSK_SHA256; + case WPA_KEY_MGMT_WPS: + return KEY_MGMT_WPS; + case WPA_KEY_MGMT_PSK: + default: + return KEY_MGMT_PSK; + } +} + + +static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, + struct wpa_ie_data *ie) +{ + int ret = wpa_sm_parse_own_wpa_ie(wpa_s->wpa, ie); + if (ret) { + if (ret == -2) { + wpa_msg(wpa_s, MSG_INFO, "WPA: Failed to parse WPA IE " + "from association info"); + } + return -1; + } + + wpa_printf(MSG_DEBUG, "WPA: Using WPA IE from AssocReq to set cipher " + "suites"); + if (!(ie->group_cipher & ssid->group_cipher)) { + wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled group " + "cipher 0x%x (mask 0x%x) - reject", + ie->group_cipher, ssid->group_cipher); + return -1; + } + if (!(ie->pairwise_cipher & ssid->pairwise_cipher)) { + wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled pairwise " + "cipher 0x%x (mask 0x%x) - reject", + ie->pairwise_cipher, ssid->pairwise_cipher); + return -1; + } + if (!(ie->key_mgmt & ssid->key_mgmt)) { + wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled key " + "management 0x%x (mask 0x%x) - reject", + ie->key_mgmt, ssid->key_mgmt); + return -1; + } + +#ifdef CONFIG_IEEE80211W + if (!(ie->capabilities & WPA_CAPABILITY_MFPC) && + ssid->ieee80211w == IEEE80211W_REQUIRED) { + wpa_msg(wpa_s, MSG_INFO, "WPA: Driver associated with an AP " + "that does not support management frame protection - " + "reject"); + return -1; + } +#endif /* CONFIG_IEEE80211W */ + + return 0; +} + + +/** + * wpa_supplicant_set_suites - Set authentication and encryption parameters + * @wpa_s: Pointer to wpa_supplicant data + * @bss: Scan results for the selected BSS, or %NULL if not available + * @ssid: Configuration data for the selected network + * @wpa_ie: Buffer for the WPA/RSN IE + * @wpa_ie_len: Maximum wpa_ie buffer size on input. This is changed to be the + * used buffer length in case the functions returns success. + * Returns: 0 on success or -1 on failure + * + * This function is used to configure authentication and encryption parameters + * based on the network configuration and scan result for the selected BSS (if + * available). + */ +int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, + struct wpa_scan_res *bss, + struct wpa_ssid *ssid, + u8 *wpa_ie, size_t *wpa_ie_len) +{ + struct wpa_ie_data ie; + int sel, proto; + const u8 *bss_wpa, *bss_rsn; + + if (bss) { + bss_wpa = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); + bss_rsn = wpa_scan_get_ie(bss, WLAN_EID_RSN); + } else + bss_wpa = bss_rsn = NULL; + + if (bss_rsn && (ssid->proto & WPA_PROTO_RSN) && + wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 && + (ie.group_cipher & ssid->group_cipher) && + (ie.pairwise_cipher & ssid->pairwise_cipher) && + (ie.key_mgmt & ssid->key_mgmt)) { + wpa_msg(wpa_s, MSG_DEBUG, "RSN: using IEEE 802.11i/D9.0"); + proto = WPA_PROTO_RSN; + } else if (bss_wpa && (ssid->proto & WPA_PROTO_WPA) && + wpa_parse_wpa_ie(bss_wpa, 2 +bss_wpa[1], &ie) == 0 && + (ie.group_cipher & ssid->group_cipher) && + (ie.pairwise_cipher & ssid->pairwise_cipher) && + (ie.key_mgmt & ssid->key_mgmt)) { + wpa_msg(wpa_s, MSG_DEBUG, "WPA: using IEEE 802.11i/D3.0"); + proto = WPA_PROTO_WPA; + } else if (bss) { + wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select WPA/RSN"); + return -1; + } else { + if (ssid->proto & WPA_PROTO_RSN) + proto = WPA_PROTO_RSN; + else + proto = WPA_PROTO_WPA; + if (wpa_supplicant_suites_from_ai(wpa_s, ssid, &ie) < 0) { + os_memset(&ie, 0, sizeof(ie)); + ie.group_cipher = ssid->group_cipher; + ie.pairwise_cipher = ssid->pairwise_cipher; + ie.key_mgmt = ssid->key_mgmt; +#ifdef CONFIG_IEEE80211W + ie.mgmt_group_cipher = + ssid->ieee80211w != NO_IEEE80211W ? + WPA_CIPHER_AES_128_CMAC : 0; +#endif /* CONFIG_IEEE80211W */ + wpa_printf(MSG_DEBUG, "WPA: Set cipher suites based " + "on configuration"); + } else + proto = ie.proto; + } + + wpa_printf(MSG_DEBUG, "WPA: Selected cipher suites: group %d " + "pairwise %d key_mgmt %d proto %d", + ie.group_cipher, ie.pairwise_cipher, ie.key_mgmt, proto); +#ifdef CONFIG_IEEE80211W + if (ssid->ieee80211w) { + wpa_printf(MSG_DEBUG, "WPA: Selected mgmt group cipher %d", + ie.mgmt_group_cipher); + } +#endif /* CONFIG_IEEE80211W */ + + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, proto); + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED, + !!(ssid->proto & WPA_PROTO_RSN)); + + if (bss || !wpa_s->ap_ies_from_associnfo) { + if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa, + bss_wpa ? 2 + bss_wpa[1] : 0) || + wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn, + bss_rsn ? 2 + bss_rsn[1] : 0)) + return -1; + } + + sel = ie.group_cipher & ssid->group_cipher; + if (sel & WPA_CIPHER_CCMP) { + wpa_s->group_cipher = WPA_CIPHER_CCMP; + wpa_msg(wpa_s, MSG_DEBUG, "WPA: using GTK CCMP"); + } else if (sel & WPA_CIPHER_TKIP) { + wpa_s->group_cipher = WPA_CIPHER_TKIP; + wpa_msg(wpa_s, MSG_DEBUG, "WPA: using GTK TKIP"); + } else if (sel & WPA_CIPHER_WEP104) { + wpa_s->group_cipher = WPA_CIPHER_WEP104; + wpa_msg(wpa_s, MSG_DEBUG, "WPA: using GTK WEP104"); + } else if (sel & WPA_CIPHER_WEP40) { + wpa_s->group_cipher = WPA_CIPHER_WEP40; + wpa_msg(wpa_s, MSG_DEBUG, "WPA: using GTK WEP40"); + } else { + wpa_printf(MSG_WARNING, "WPA: Failed to select group cipher."); + return -1; + } + + sel = ie.pairwise_cipher & ssid->pairwise_cipher; + if (sel & WPA_CIPHER_CCMP) { + wpa_s->pairwise_cipher = WPA_CIPHER_CCMP; + wpa_msg(wpa_s, MSG_DEBUG, "WPA: using PTK CCMP"); + } else if (sel & WPA_CIPHER_TKIP) { + wpa_s->pairwise_cipher = WPA_CIPHER_TKIP; + wpa_msg(wpa_s, MSG_DEBUG, "WPA: using PTK TKIP"); + } else if (sel & WPA_CIPHER_NONE) { + wpa_s->pairwise_cipher = WPA_CIPHER_NONE; + wpa_msg(wpa_s, MSG_DEBUG, "WPA: using PTK NONE"); + } else { + wpa_printf(MSG_WARNING, "WPA: Failed to select pairwise " + "cipher."); + return -1; + } + + sel = ie.key_mgmt & ssid->key_mgmt; + if (0) { +#ifdef CONFIG_IEEE80211R + } else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) { + wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X; + wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/802.1X"); + } else if (sel & WPA_KEY_MGMT_FT_PSK) { + wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK; + wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK"); +#endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_IEEE80211W + } else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA256) { + wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256; + wpa_msg(wpa_s, MSG_DEBUG, + "WPA: using KEY_MGMT 802.1X with SHA256"); + } else if (sel & WPA_KEY_MGMT_PSK_SHA256) { + wpa_s->key_mgmt = WPA_KEY_MGMT_PSK_SHA256; + wpa_msg(wpa_s, MSG_DEBUG, + "WPA: using KEY_MGMT PSK with SHA256"); +#endif /* CONFIG_IEEE80211W */ + } else if (sel & WPA_KEY_MGMT_IEEE8021X) { + wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X; + wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT 802.1X"); + } else if (sel & WPA_KEY_MGMT_PSK) { + wpa_s->key_mgmt = WPA_KEY_MGMT_PSK; + wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-PSK"); + } else if (sel & WPA_KEY_MGMT_WPA_NONE) { + wpa_s->key_mgmt = WPA_KEY_MGMT_WPA_NONE; + wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-NONE"); + } else { + wpa_printf(MSG_WARNING, "WPA: Failed to select authenticated " + "key management type."); + return -1; + } + + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt); + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE, + wpa_s->pairwise_cipher); + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher); + +#ifdef CONFIG_IEEE80211W + sel = ie.mgmt_group_cipher; + if (ssid->ieee80211w == NO_IEEE80211W || + !(ie.capabilities & WPA_CAPABILITY_MFPC)) + sel = 0; + if (sel & WPA_CIPHER_AES_128_CMAC) { + wpa_s->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC; + wpa_msg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher " + "AES-128-CMAC"); + } else { + wpa_s->mgmt_group_cipher = 0; + wpa_msg(wpa_s, MSG_DEBUG, "WPA: not using MGMT group cipher"); + } + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP, + wpa_s->mgmt_group_cipher); +#endif /* CONFIG_IEEE80211W */ + + if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) { + wpa_printf(MSG_WARNING, "WPA: Failed to generate WPA IE."); + return -1; + } + + if (ssid->key_mgmt & + (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK | WPA_KEY_MGMT_PSK_SHA256)) + wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN); + else + wpa_sm_set_pmk_from_pmksa(wpa_s->wpa); + + return 0; +} + + +/** + * wpa_supplicant_associate - Request association + * @wpa_s: Pointer to wpa_supplicant data + * @bss: Scan results for the selected BSS, or %NULL if not available + * @ssid: Configuration data for the selected network + * + * This function is used to request %wpa_supplicant to associate with a BSS. + */ +void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, + struct wpa_scan_res *bss, struct wpa_ssid *ssid) +{ + u8 wpa_ie[80]; + size_t wpa_ie_len; + int use_crypt, ret, i; + int algs = AUTH_ALG_OPEN_SYSTEM; + wpa_cipher cipher_pairwise, cipher_group; + struct wpa_driver_associate_params params; + int wep_keys_set = 0; + struct wpa_driver_capa capa; + int assoc_failed = 0; + + wpa_s->reassociate = 0; + if (bss) { +#ifdef CONFIG_IEEE80211R + const u8 *md = NULL; +#endif /* CONFIG_IEEE80211R */ + const u8 *ie = wpa_scan_get_ie(bss, WLAN_EID_SSID); + wpa_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR + " (SSID='%s' freq=%d MHz)", MAC2STR(bss->bssid), + ie ? wpa_ssid_txt(ie + 2, ie[1]) : "", bss->freq); + os_memset(wpa_s->bssid, 0, ETH_ALEN); + os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN); +#ifdef CONFIG_IEEE80211R + ie = wpa_scan_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN); + if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN) + md = ie + 2; + wpa_sm_set_ft_params(wpa_s->wpa, md, NULL, 0, NULL); + if (md) { + /* Prepare for the next transition */ + wpa_ft_prepare_auth_request(wpa_s->wpa); + } +#endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_WPS + } else if ((ssid->ssid == NULL || ssid->ssid_len == 0) && + wpa_s->conf->ap_scan == 2 && + (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) { + /* Use ap_scan==1 style network selection to find the network + */ + wpa_s->scan_req = 2; + wpa_s->reassociate = 1; + wpa_supplicant_req_scan(wpa_s, 0, 0); + return; +#endif /* CONFIG_WPS */ + } else { + wpa_msg(wpa_s, MSG_INFO, "Trying to associate with SSID '%s'", + wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); + os_memset(wpa_s->pending_bssid, 0, ETH_ALEN); + } + wpa_supplicant_cancel_scan(wpa_s); + + /* Starting new association, so clear the possibly used WPA IE from the + * previous association. */ + wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0); + + if (wpa_drv_set_mode(wpa_s, ssid->mode)) { + wpa_printf(MSG_WARNING, "Failed to set operating mode"); + assoc_failed = 1; + } + +#ifdef IEEE8021X_EAPOL + if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) { + if (ssid->leap) { + if (ssid->non_leap == 0) + algs = AUTH_ALG_LEAP; + else + algs |= AUTH_ALG_LEAP; + } + } +#endif /* IEEE8021X_EAPOL */ + wpa_printf(MSG_DEBUG, "Automatic auth_alg selection: 0x%x", algs); + if (ssid->auth_alg) { + algs = 0; + if (ssid->auth_alg & WPA_AUTH_ALG_OPEN) + algs |= AUTH_ALG_OPEN_SYSTEM; + if (ssid->auth_alg & WPA_AUTH_ALG_SHARED) + algs |= AUTH_ALG_SHARED_KEY; + if (ssid->auth_alg & WPA_AUTH_ALG_LEAP) + algs |= AUTH_ALG_LEAP; + wpa_printf(MSG_DEBUG, "Overriding auth_alg selection: 0x%x", + algs); + } + wpa_drv_set_auth_alg(wpa_s, algs); + + if (bss && (wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) || + wpa_scan_get_ie(bss, WLAN_EID_RSN)) && + (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK | + WPA_KEY_MGMT_FT_IEEE8021X | + WPA_KEY_MGMT_FT_PSK | + WPA_KEY_MGMT_IEEE8021X_SHA256 | + WPA_KEY_MGMT_PSK_SHA256))) { + int try_opportunistic; + try_opportunistic = ssid->proactive_key_caching && + (ssid->proto & WPA_PROTO_RSN); + if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, + wpa_s->current_ssid, + try_opportunistic) == 0) + eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1); + wpa_ie_len = sizeof(wpa_ie); + if (wpa_supplicant_set_suites(wpa_s, bss, ssid, + wpa_ie, &wpa_ie_len)) { + wpa_printf(MSG_WARNING, "WPA: Failed to set WPA key " + "management and encryption suites"); + return; + } + } else if (ssid->key_mgmt & + (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X | + WPA_KEY_MGMT_WPA_NONE | WPA_KEY_MGMT_FT_PSK | + WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_PSK_SHA256 | + WPA_KEY_MGMT_IEEE8021X_SHA256)) { + wpa_ie_len = sizeof(wpa_ie); + if (wpa_supplicant_set_suites(wpa_s, NULL, ssid, + wpa_ie, &wpa_ie_len)) { + wpa_printf(MSG_WARNING, "WPA: Failed to set WPA key " + "management and encryption suites (no scan " + "results)"); + return; + } +#ifdef CONFIG_WPS + } else if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) { + struct wpabuf *wps_ie; + wps_ie = wps_build_assoc_req_ie(wpas_wps_get_req_type(ssid)); + if (wps_ie && wpabuf_len(wps_ie) <= sizeof(wpa_ie)) { + wpa_ie_len = wpabuf_len(wps_ie); + os_memcpy(wpa_ie, wpabuf_head(wps_ie), wpa_ie_len); + } else + wpa_ie_len = 0; + wpabuf_free(wps_ie); + wpa_supplicant_set_non_wpa_policy(wpa_s, ssid); +#endif /* CONFIG_WPS */ + } else { + wpa_supplicant_set_non_wpa_policy(wpa_s, ssid); + wpa_ie_len = 0; + } + + wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL); + use_crypt = 1; + cipher_pairwise = cipher_suite2driver(wpa_s->pairwise_cipher); + cipher_group = cipher_suite2driver(wpa_s->group_cipher); + if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE || + wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { + if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) + use_crypt = 0; + if (wpa_set_wep_keys(wpa_s, ssid)) { + use_crypt = 1; + wep_keys_set = 1; + } + } + if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) + use_crypt = 0; + +#ifdef IEEE8021X_EAPOL + if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { + if ((ssid->eapol_flags & + (EAPOL_FLAG_REQUIRE_KEY_UNICAST | + EAPOL_FLAG_REQUIRE_KEY_BROADCAST)) == 0 && + !wep_keys_set) { + use_crypt = 0; + } else { + /* Assume that dynamic WEP-104 keys will be used and + * set cipher suites in order for drivers to expect + * encryption. */ + cipher_pairwise = cipher_group = CIPHER_WEP104; + } + } +#endif /* IEEE8021X_EAPOL */ + + if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) { + /* Set the key before (and later after) association */ + wpa_supplicant_set_wpa_none_key(wpa_s, ssid); + } + + wpa_drv_set_drop_unencrypted(wpa_s, use_crypt); + wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING); + os_memset(¶ms, 0, sizeof(params)); + if (bss) { + const u8 *ie = wpa_scan_get_ie(bss, WLAN_EID_SSID); + params.bssid = bss->bssid; + params.ssid = ie ? ie + 2 : (u8 *) ""; + params.ssid_len = ie ? ie[1] : 0; + params.freq = bss->freq; + } else { + params.ssid = ssid->ssid; + params.ssid_len = ssid->ssid_len; + } + if (ssid->mode == 1 && ssid->frequency > 0 && params.freq == 0) + params.freq = ssid->frequency; /* Initial channel for IBSS */ + params.wpa_ie = wpa_ie; + params.wpa_ie_len = wpa_ie_len; + params.pairwise_suite = cipher_pairwise; + params.group_suite = cipher_group; + params.key_mgmt_suite = key_mgmt2driver(wpa_s->key_mgmt); + params.auth_alg = algs; + params.mode = ssid->mode; + for (i = 0; i < NUM_WEP_KEYS; i++) { + if (ssid->wep_key_len[i]) + params.wep_key[i] = ssid->wep_key[i]; + params.wep_key_len[i] = ssid->wep_key_len[i]; + } + params.wep_tx_keyidx = ssid->wep_tx_keyidx; + + if (wpa_s->driver_4way_handshake && + (params.key_mgmt_suite == KEY_MGMT_PSK || + params.key_mgmt_suite == KEY_MGMT_FT_PSK)) { + params.passphrase = ssid->passphrase; + if (ssid->psk_set) + params.psk = ssid->psk; + } + +#ifdef CONFIG_IEEE80211W + switch (ssid->ieee80211w) { + case NO_IEEE80211W: + params.mgmt_frame_protection = NO_MGMT_FRAME_PROTECTION; + break; + case IEEE80211W_OPTIONAL: + params.mgmt_frame_protection = MGMT_FRAME_PROTECTION_OPTIONAL; + break; + case IEEE80211W_REQUIRED: + params.mgmt_frame_protection = MGMT_FRAME_PROTECTION_REQUIRED; + break; + } + if (ssid->ieee80211w != NO_IEEE80211W && bss) { + const u8 *rsn = wpa_scan_get_ie(bss, WLAN_EID_RSN); + struct wpa_ie_data ie; + if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie) == 0 && + ie.capabilities & + (WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) { + wpa_printf(MSG_DEBUG, "WPA: Selected AP supports MFP: " + "require MFP"); + params.mgmt_frame_protection = + MGMT_FRAME_PROTECTION_REQUIRED; + } + } +#endif /* CONFIG_IEEE80211W */ + + if (wpa_s->use_client_mlme) + ret = ieee80211_sta_associate(wpa_s, ¶ms); + else + ret = wpa_drv_associate(wpa_s, ¶ms); + if (ret < 0) { + wpa_msg(wpa_s, MSG_INFO, "Association request to the driver " + "failed"); + /* try to continue anyway; new association will be tried again + * after timeout */ + assoc_failed = 1; + } + + if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) { + /* Set the key after the association just in case association + * cleared the previously configured key. */ + wpa_supplicant_set_wpa_none_key(wpa_s, ssid); + /* No need to timeout authentication since there is no key + * management. */ + wpa_supplicant_cancel_auth_timeout(wpa_s); + wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); + } else { + /* Timeout for IEEE 802.11 authentication and association */ + int timeout = 60; + + if (assoc_failed) { + /* give IBSS a bit more time */ + timeout = ssid->mode ? 10 : 5; + } else if (wpa_s->conf->ap_scan == 1) { + /* give IBSS a bit more time */ + timeout = ssid->mode ? 20 : 10; + } + wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0); + } + + if (wep_keys_set && wpa_drv_get_capa(wpa_s, &capa) == 0 && + capa.flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC) { + /* Set static WEP keys again */ + wpa_set_wep_keys(wpa_s, ssid); + } + + if (wpa_s->current_ssid && wpa_s->current_ssid != ssid) { + /* + * Do not allow EAP session resumption between different + * network configurations. + */ + eapol_sm_invalidate_cached_session(wpa_s->eapol); + } + wpa_s->current_ssid = ssid; + wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid); + wpa_supplicant_initiate_eapol(wpa_s); +} + + +/** + * wpa_supplicant_disassociate - Disassociate the current connection + * @wpa_s: Pointer to wpa_supplicant data + * @reason_code: IEEE 802.11 reason code for the disassociate frame + * + * This function is used to request %wpa_supplicant to disassociate with the + * current AP. + */ +void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s, + int reason_code) +{ + u8 *addr = NULL; + if (!is_zero_ether_addr(wpa_s->bssid)) { + if (wpa_s->use_client_mlme) + ieee80211_sta_disassociate(wpa_s, reason_code); + else + wpa_drv_disassociate(wpa_s, wpa_s->bssid, reason_code); + addr = wpa_s->bssid; + } + wpa_clear_keys(wpa_s, addr); + wpa_supplicant_mark_disassoc(wpa_s); + wpa_s->current_ssid = NULL; + wpa_sm_set_config(wpa_s->wpa, NULL); + eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); +} + + +/** + * wpa_supplicant_deauthenticate - Deauthenticate the current connection + * @wpa_s: Pointer to wpa_supplicant data + * @reason_code: IEEE 802.11 reason code for the deauthenticate frame + * + * This function is used to request %wpa_supplicant to deauthenticate from the + * current AP. + */ +void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s, + int reason_code) +{ + u8 *addr = NULL; + wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); + if (!is_zero_ether_addr(wpa_s->bssid)) { + if (wpa_s->use_client_mlme) + ieee80211_sta_deauthenticate(wpa_s, reason_code); + else + wpa_drv_deauthenticate(wpa_s, wpa_s->bssid, + reason_code); + addr = wpa_s->bssid; + } + wpa_clear_keys(wpa_s, addr); + wpa_s->current_ssid = NULL; + wpa_sm_set_config(wpa_s->wpa, NULL); + eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); + eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE); + eapol_sm_notify_portValid(wpa_s->eapol, FALSE); +} + + +static int wpa_supplicant_get_scan_results_old(struct wpa_supplicant *wpa_s) +{ +#define SCAN_AP_LIMIT 128 + struct wpa_scan_result *results; + int num, i; + struct wpa_scan_results *res; + + results = os_malloc(SCAN_AP_LIMIT * sizeof(struct wpa_scan_result)); + if (results == NULL) { + wpa_printf(MSG_WARNING, "Failed to allocate memory for scan " + "results"); + return -1; + } + + num = wpa_drv_get_scan_results(wpa_s, results, SCAN_AP_LIMIT); + wpa_printf(MSG_DEBUG, "Scan results: %d", num); + if (num < 0) { + wpa_printf(MSG_DEBUG, "Failed to get scan results"); + os_free(results); + return -1; + } + if (num > SCAN_AP_LIMIT) { + wpa_printf(MSG_INFO, "Not enough room for all APs (%d < %d)", + num, SCAN_AP_LIMIT); + num = SCAN_AP_LIMIT; + } + + wpa_scan_results_free(wpa_s->scan_res); + wpa_s->scan_res = NULL; + + /* Convert old scan result data structure to the new one */ + res = os_zalloc(sizeof(*res)); + if (res == NULL) { + os_free(results); + return -1; + } + res->res = os_zalloc(num * sizeof(struct wpa_scan_res *)); + if (res->res == NULL) { + os_free(results); + os_free(res); + return -1; + } + + for (i = 0; i < num; i++) { + struct wpa_scan_result *bss = &results[i]; + struct wpa_scan_res *r; + size_t ie_len; + u8 *pos; + + ie_len = 2 + bss->ssid_len + bss->rsn_ie_len + bss->wpa_ie_len; + if (bss->maxrate) + ie_len += 3; + if (bss->mdie_present) + ie_len += 5; + + r = os_zalloc(sizeof(*r) + ie_len); + if (r == NULL) + break; + + os_memcpy(r->bssid, bss->bssid, ETH_ALEN); + r->freq = bss->freq; + r->caps = bss->caps; + r->qual = bss->qual; + r->noise = bss->noise; + r->level = bss->level; + r->tsf = bss->tsf; + r->ie_len = ie_len; + + pos = (u8 *) (r + 1); + + /* SSID IE */ + *pos++ = WLAN_EID_SSID; + *pos++ = bss->ssid_len; + os_memcpy(pos, bss->ssid, bss->ssid_len); + pos += bss->ssid_len; + + if (bss->maxrate) { + /* Fake Supported Rate IE to include max rate */ + *pos++ = WLAN_EID_SUPP_RATES; + *pos++ = 1; + *pos++ = bss->maxrate; + } + + if (bss->rsn_ie_len) { + os_memcpy(pos, bss->rsn_ie, bss->rsn_ie_len); + pos += bss->rsn_ie_len; + } + + if (bss->mdie_present) { + os_memcpy(pos, bss->mdie, 5); + pos += 5; + } + + if (bss->wpa_ie_len) { + os_memcpy(pos, bss->wpa_ie, bss->wpa_ie_len); + pos += bss->wpa_ie_len; + } + + res->res[res->num++] = r; + } + + os_free(results); + wpa_s->scan_res = res; + + return 0; +} + + +/** + * wpa_supplicant_get_scan_results - Get scan results + * @wpa_s: Pointer to wpa_supplicant data + * Returns: 0 on success, -1 on failure + * + * This function is request the current scan results from the driver and stores + * a local copy of the results in wpa_s->scan_res. + */ +int wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s) +{ + int ret; + + if (wpa_s->use_client_mlme) { + wpa_scan_results_free(wpa_s->scan_res); + wpa_s->scan_res = ieee80211_sta_get_scan_results(wpa_s); + if (wpa_s->scan_res == NULL) { + wpa_printf(MSG_DEBUG, "Failed to get scan results"); + ret = -1; + } else + ret = 0; + } else if (wpa_s->driver->get_scan_results2 == NULL) + ret = wpa_supplicant_get_scan_results_old(wpa_s); + else { + wpa_scan_results_free(wpa_s->scan_res); + wpa_s->scan_res = wpa_drv_get_scan_results2(wpa_s); + if (wpa_s->scan_res == NULL) { + wpa_printf(MSG_DEBUG, "Failed to get scan results"); + ret = -1; + } else + ret = 0; + } + + if (wpa_s->scan_res) + wpa_scan_sort_results(wpa_s->scan_res); + + return ret; +} + + +/** + * wpa_supplicant_get_ssid - Get a pointer to the current network structure + * @wpa_s: Pointer to wpa_supplicant data + * Returns: A pointer to the current network structure or %NULL on failure + */ +struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s) +{ + struct wpa_ssid *entry; + u8 ssid[MAX_SSID_LEN]; + int res; + size_t ssid_len; + u8 bssid[ETH_ALEN]; + int wired; + + if (wpa_s->use_client_mlme) { + if (ieee80211_sta_get_ssid(wpa_s, ssid, &ssid_len)) { + wpa_printf(MSG_WARNING, "Could not read SSID from " + "MLME."); + return NULL; + } + } else { + res = wpa_drv_get_ssid(wpa_s, ssid); + if (res < 0) { + wpa_printf(MSG_WARNING, "Could not read SSID from " + "driver."); + return NULL; + } + ssid_len = res; + } + + if (wpa_s->use_client_mlme) + os_memcpy(bssid, wpa_s->bssid, ETH_ALEN); + else if (wpa_drv_get_bssid(wpa_s, bssid) < 0) { + wpa_printf(MSG_WARNING, "Could not read BSSID from driver."); + return NULL; + } + + wired = wpa_s->conf->ap_scan == 0 && wpa_s->driver && + IS_WIRED(wpa_s->driver); + + entry = wpa_s->conf->ssid; + while (entry) { + if (!entry->disabled && + ((ssid_len == entry->ssid_len && + os_memcmp(ssid, entry->ssid, ssid_len) == 0) || wired) && + (!entry->bssid_set || + os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)) + return entry; +#ifdef CONFIG_WPS + if (!entry->disabled && + (entry->key_mgmt & WPA_KEY_MGMT_WPS) && + (entry->ssid == NULL || entry->ssid_len == 0) && + (!entry->bssid_set || + os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)) + return entry; +#endif /* CONFIG_WPS */ + entry = entry->next; + } + + return NULL; +} + + +static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s, + const char *name) +{ + int i; + + if (wpa_s == NULL) + return -1; + + if (wpa_supplicant_drivers[0] == NULL) { + wpa_printf(MSG_ERROR, "No driver interfaces build into " + "wpa_supplicant."); + return -1; + } + + if (name == NULL) { + /* default to first driver in the list */ + wpa_s->driver = wpa_supplicant_drivers[0]; + return 0; + } + + for (i = 0; wpa_supplicant_drivers[i]; i++) { + if (os_strcmp(name, wpa_supplicant_drivers[i]->name) == 0) { + wpa_s->driver = wpa_supplicant_drivers[i]; + return 0; + } + } + + wpa_printf(MSG_ERROR, "Unsupported driver '%s'.\n", name); + return -1; +} + + +void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, + const u8 *buf, size_t len) +{ + struct wpa_supplicant *wpa_s = ctx; + + wpa_printf(MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr)); + wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len); + + if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) { + wpa_printf(MSG_DEBUG, "Ignored received EAPOL frame since " + "no key management is configured"); + return; + } + + if (wpa_s->eapol_received == 0 && + (!wpa_s->driver_4way_handshake || + !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) || + wpa_s->wpa_state != WPA_COMPLETED)) { + /* Timeout for completing IEEE 802.1X and WPA authentication */ + wpa_supplicant_req_auth_timeout( + wpa_s, + (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) || + wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA || + wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) ? + 70 : 10, 0); + } + wpa_s->eapol_received++; + + if (wpa_s->countermeasures) { + wpa_printf(MSG_INFO, "WPA: Countermeasures - dropped EAPOL " + "packet"); + return; + } + + /* Source address of the incoming EAPOL frame could be compared to the + * current BSSID. However, it is possible that a centralized + * Authenticator could be using another MAC address than the BSSID of + * an AP, so just allow any address to be used for now. The replies are + * still sent to the current BSSID (if available), though. */ + + os_memcpy(wpa_s->last_eapol_src, src_addr, ETH_ALEN); + if (!wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) && + eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0) + return; + wpa_drv_poll(wpa_s); + if (!wpa_s->driver_4way_handshake) + wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len); + else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) { + /* + * Set portValid = TRUE here since we are going to skip 4-way + * handshake processing which would normally set portValid. We + * need this to allow the EAPOL state machines to be completed + * without going through EAPOL-Key handshake. + */ + eapol_sm_notify_portValid(wpa_s->eapol, TRUE); + } +} + + +void wpa_supplicant_sta_free_hw_features(struct wpa_hw_modes *hw_features, + size_t num_hw_features) +{ + ieee80211_sta_free_hw_features(hw_features, num_hw_features); +} + + +void wpa_supplicant_sta_rx(void *ctx, const u8 *buf, size_t len, + struct ieee80211_rx_status *rx_status) +{ + struct wpa_supplicant *wpa_s = ctx; + ieee80211_sta_rx(wpa_s, buf, len, rx_status); +} + + +/** + * wpa_supplicant_driver_init - Initialize driver interface parameters + * @wpa_s: Pointer to wpa_supplicant data + * Returns: 0 on success, -1 on failure + * + * This function is called to initialize driver interface parameters. + * wpa_drv_init() must have been called before this function to initialize the + * driver interface. + */ +int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s) +{ + static int interface_count = 0; + + if (wpa_s->driver->send_eapol) { + const u8 *addr = wpa_drv_get_mac_addr(wpa_s); + if (addr) + os_memcpy(wpa_s->own_addr, addr, ETH_ALEN); + } else { + wpa_s->l2 = l2_packet_init(wpa_s->ifname, + wpa_drv_get_mac_addr(wpa_s), + ETH_P_EAPOL, + wpa_supplicant_rx_eapol, wpa_s, 0); + if (wpa_s->l2 == NULL) + return -1; + } + + if (wpa_s->l2 && l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) { + wpa_printf(MSG_ERROR, "Failed to get own L2 address"); + return -1; + } + + wpa_printf(MSG_DEBUG, "Own MAC address: " MACSTR, + MAC2STR(wpa_s->own_addr)); + + if (wpa_s->bridge_ifname[0]) { + wpa_printf(MSG_DEBUG, "Receiving packets from bridge interface" + " '%s'", wpa_s->bridge_ifname); + wpa_s->l2_br = l2_packet_init(wpa_s->bridge_ifname, + wpa_s->own_addr, + ETH_P_EAPOL, + wpa_supplicant_rx_eapol, wpa_s, + 0); + if (wpa_s->l2_br == NULL) { + wpa_printf(MSG_ERROR, "Failed to open l2_packet " + "connection for the bridge interface '%s'", + wpa_s->bridge_ifname); + return -1; + } + } + + /* Backwards compatibility call to set_wpa() handler. This is called + * only just after init and just before deinit, so these handler can be + * used to implement same functionality. */ + if (wpa_drv_set_wpa(wpa_s, 1) < 0) { + struct wpa_driver_capa capa; + if (wpa_drv_get_capa(wpa_s, &capa) < 0 || + !(capa.flags & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | + WPA_DRIVER_CAPA_KEY_MGMT_WPA2))) { + wpa_printf(MSG_DEBUG, "Driver does not support WPA."); + /* Continue to allow non-WPA modes to be used. */ + } else { + wpa_printf(MSG_ERROR, "Failed to enable WPA in the " + "driver."); + return -1; + } + } + + wpa_clear_keys(wpa_s, NULL); + + /* Make sure that TKIP countermeasures are not left enabled (could + * happen if wpa_supplicant is killed during countermeasures. */ + wpa_drv_set_countermeasures(wpa_s, 0); + + wpa_drv_set_drop_unencrypted(wpa_s, 1); + + wpa_printf(MSG_DEBUG, "RSN: flushing PMKID list in the driver"); + wpa_drv_flush_pmkid(wpa_s); + + wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN; + wpa_supplicant_req_scan(wpa_s, interface_count, 100000); + interface_count++; + + return 0; +} + + +static int wpa_supplicant_daemon(const char *pid_file) +{ + wpa_printf(MSG_DEBUG, "Daemonize.."); + return os_daemonize(pid_file); +} + + +static struct wpa_supplicant * wpa_supplicant_alloc(void) +{ + struct wpa_supplicant *wpa_s; + + wpa_s = os_zalloc(sizeof(*wpa_s)); + if (wpa_s == NULL) + return NULL; + wpa_s->scan_req = 1; + + return wpa_s; +} + + +static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, + struct wpa_interface *iface) +{ + wpa_printf(MSG_DEBUG, "Initializing interface '%s' conf '%s' driver " + "'%s' ctrl_interface '%s' bridge '%s'", iface->ifname, + iface->confname ? iface->confname : "N/A", + iface->driver ? iface->driver : "default", + iface->ctrl_interface ? iface->ctrl_interface : "N/A", + iface->bridge_ifname ? iface->bridge_ifname : "N/A"); + + if (wpa_supplicant_set_driver(wpa_s, iface->driver) < 0) { + return -1; + } + + if (iface->confname) { +#ifdef CONFIG_BACKEND_FILE + wpa_s->confname = os_rel2abs_path(iface->confname); + if (wpa_s->confname == NULL) { + wpa_printf(MSG_ERROR, "Failed to get absolute path " + "for configuration file '%s'.", + iface->confname); + return -1; + } + wpa_printf(MSG_DEBUG, "Configuration file '%s' -> '%s'", + iface->confname, wpa_s->confname); +#else /* CONFIG_BACKEND_FILE */ + wpa_s->confname = os_strdup(iface->confname); +#endif /* CONFIG_BACKEND_FILE */ + wpa_s->conf = wpa_config_read(wpa_s->confname); + if (wpa_s->conf == NULL) { + wpa_printf(MSG_ERROR, "Failed to read or parse " + "configuration '%s'.", wpa_s->confname); + return -1; + } + + /* + * Override ctrl_interface and driver_param if set on command + * line. + */ + if (iface->ctrl_interface) { + os_free(wpa_s->conf->ctrl_interface); + wpa_s->conf->ctrl_interface = + os_strdup(iface->ctrl_interface); + } + + if (iface->driver_param) { + os_free(wpa_s->conf->driver_param); + wpa_s->conf->driver_param = + os_strdup(iface->driver_param); + } + } else + wpa_s->conf = wpa_config_alloc_empty(iface->ctrl_interface, + iface->driver_param); + + if (wpa_s->conf == NULL) { + wpa_printf(MSG_ERROR, "\nNo configuration found."); + return -1; + } + + if (iface->ifname == NULL) { + wpa_printf(MSG_ERROR, "\nInterface name is required."); + return -1; + } + if (os_strlen(iface->ifname) >= sizeof(wpa_s->ifname)) { + wpa_printf(MSG_ERROR, "\nToo long interface name '%s'.", + iface->ifname); + return -1; + } + os_strlcpy(wpa_s->ifname, iface->ifname, sizeof(wpa_s->ifname)); + + if (iface->bridge_ifname) { + if (os_strlen(iface->bridge_ifname) >= + sizeof(wpa_s->bridge_ifname)) { + wpa_printf(MSG_ERROR, "\nToo long bridge interface " + "name '%s'.", iface->bridge_ifname); + return -1; + } + os_strlcpy(wpa_s->bridge_ifname, iface->bridge_ifname, + sizeof(wpa_s->bridge_ifname)); + } + + return 0; +} + + +static int wpa_supplicant_init_iface2(struct wpa_supplicant *wpa_s) +{ + const char *ifname; + struct wpa_driver_capa capa; + + wpa_printf(MSG_DEBUG, "Initializing interface (2) '%s'", + wpa_s->ifname); + + /* RSNA Supplicant Key Management - INITIALIZE */ + eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE); + eapol_sm_notify_portValid(wpa_s->eapol, FALSE); + + /* Initialize driver interface and register driver event handler before + * L2 receive handler so that association events are processed before + * EAPOL-Key packets if both become available for the same select() + * call. */ + wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname); + if (wpa_s->drv_priv == NULL) { + wpa_printf(MSG_ERROR, "Failed to initialize driver interface"); + return -1; + } + if (wpa_drv_set_param(wpa_s, wpa_s->conf->driver_param) < 0) { + wpa_printf(MSG_ERROR, "Driver interface rejected " + "driver_param '%s'", wpa_s->conf->driver_param); + return -1; + } + + ifname = wpa_drv_get_ifname(wpa_s); + if (ifname && os_strcmp(ifname, wpa_s->ifname) != 0) { + wpa_printf(MSG_DEBUG, "Driver interface replaced interface " + "name with '%s'", ifname); + os_strlcpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname)); + } + + if (wpa_supplicant_init_wpa(wpa_s) < 0) + return -1; + + wpa_sm_set_ifname(wpa_s->wpa, wpa_s->ifname, + wpa_s->bridge_ifname[0] ? wpa_s->bridge_ifname : + NULL); + wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth); + + if (wpa_s->conf->dot11RSNAConfigPMKLifetime && + wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, + wpa_s->conf->dot11RSNAConfigPMKLifetime)) { + wpa_printf(MSG_ERROR, "Invalid WPA parameter value for " + "dot11RSNAConfigPMKLifetime"); + return -1; + } + + if (wpa_s->conf->dot11RSNAConfigPMKReauthThreshold && + wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD, + wpa_s->conf->dot11RSNAConfigPMKReauthThreshold)) { + wpa_printf(MSG_ERROR, "Invalid WPA parameter value for " + "dot11RSNAConfigPMKReauthThreshold"); + return -1; + } + + if (wpa_s->conf->dot11RSNAConfigSATimeout && + wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, + wpa_s->conf->dot11RSNAConfigSATimeout)) { + wpa_printf(MSG_ERROR, "Invalid WPA parameter value for " + "dot11RSNAConfigSATimeout"); + return -1; + } + + if (wpa_supplicant_driver_init(wpa_s) < 0) + return -1; + + if (wpa_s->conf->country[0] && wpa_s->conf->country[1] && + wpa_drv_set_country(wpa_s, wpa_s->conf->country)) { + wpa_printf(MSG_DEBUG, "Failed to set country"); + return -1; + } + + wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr); + + if (wpas_wps_init(wpa_s)) + return -1; + + if (wpa_supplicant_init_eapol(wpa_s) < 0) + return -1; + wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol); + + wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s); + if (wpa_s->ctrl_iface == NULL) { + wpa_printf(MSG_ERROR, + "Failed to initialize control interface '%s'.\n" + "You may have another wpa_supplicant process " + "already running or the file was\n" + "left by an unclean termination of wpa_supplicant " + "in which case you will need\n" + "to manually remove this file before starting " + "wpa_supplicant again.\n", + wpa_s->conf->ctrl_interface); + return -1; + } + + if (wpa_drv_get_capa(wpa_s, &capa) == 0) { + if (capa.flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) { + wpa_s->use_client_mlme = 1; + if (ieee80211_sta_init(wpa_s)) + return -1; + } + if (capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) + wpa_s->driver_4way_handshake = 1; + } + + return 0; +} + + +static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s) +{ + if (wpa_s->drv_priv) { + wpa_supplicant_deauthenticate(wpa_s, + WLAN_REASON_DEAUTH_LEAVING); + + /* Backwards compatibility call to set_wpa() handler. This is + * called only just after init and just before deinit, so these + * handler can be used to implement same functionality. */ + if (wpa_drv_set_wpa(wpa_s, 0) < 0) { + wpa_printf(MSG_ERROR, "Failed to disable WPA in the " + "driver."); + } + + wpa_drv_set_drop_unencrypted(wpa_s, 0); + wpa_drv_set_countermeasures(wpa_s, 0); + wpa_clear_keys(wpa_s, NULL); + } + + wpas_dbus_unregister_iface(wpa_s); + + wpa_supplicant_cleanup(wpa_s); + + if (wpa_s->drv_priv) + wpa_drv_deinit(wpa_s); +} + + +/** + * wpa_supplicant_add_iface - Add a new network interface + * @global: Pointer to global data from wpa_supplicant_init() + * @iface: Interface configuration options + * Returns: Pointer to the created interface or %NULL on failure + * + * This function is used to add new network interfaces for %wpa_supplicant. + * This can be called before wpa_supplicant_run() to add interfaces before the + * main event loop has been started. In addition, new interfaces can be added + * dynamically while %wpa_supplicant is already running. This could happen, + * e.g., when a hotplug network adapter is inserted. + */ +struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global, + struct wpa_interface *iface) +{ + struct wpa_supplicant *wpa_s; + + if (global == NULL || iface == NULL) + return NULL; + + wpa_s = wpa_supplicant_alloc(); + if (wpa_s == NULL) + return NULL; + + if (wpa_supplicant_init_iface(wpa_s, iface) || + wpa_supplicant_init_iface2(wpa_s)) { + wpa_printf(MSG_DEBUG, "Failed to add interface %s", + iface->ifname); + wpa_supplicant_deinit_iface(wpa_s); + os_free(wpa_s); + return NULL; + } + + wpa_s->global = global; + + /* Register the interface with the dbus control interface */ + if (wpas_dbus_register_iface(wpa_s)) { + wpa_supplicant_deinit_iface(wpa_s); + os_free(wpa_s); + return NULL; + } + + wpa_s->next = global->ifaces; + global->ifaces = wpa_s; + + wpa_printf(MSG_DEBUG, "Added interface %s", wpa_s->ifname); + + return wpa_s; +} + + +/** + * wpa_supplicant_remove_iface - Remove a network interface + * @global: Pointer to global data from wpa_supplicant_init() + * @wpa_s: Pointer to the network interface to be removed + * Returns: 0 if interface was removed, -1 if interface was not found + * + * This function can be used to dynamically remove network interfaces from + * %wpa_supplicant, e.g., when a hotplug network adapter is ejected. In + * addition, this function is used to remove all remaining interfaces when + * %wpa_supplicant is terminated. + */ +int wpa_supplicant_remove_iface(struct wpa_global *global, + struct wpa_supplicant *wpa_s) +{ + struct wpa_supplicant *prev; + + /* Remove interface from the global list of interfaces */ + prev = global->ifaces; + if (prev == wpa_s) { + global->ifaces = wpa_s->next; + } else { + while (prev && prev->next != wpa_s) + prev = prev->next; + if (prev == NULL) + return -1; + prev->next = wpa_s->next; + } + + wpa_printf(MSG_DEBUG, "Removing interface %s", wpa_s->ifname); + + wpa_supplicant_deinit_iface(wpa_s); + os_free(wpa_s); + + return 0; +} + + +/** + * wpa_supplicant_get_iface - Get a new network interface + * @global: Pointer to global data from wpa_supplicant_init() + * @ifname: Interface name + * Returns: Pointer to the interface or %NULL if not found + */ +struct wpa_supplicant * wpa_supplicant_get_iface(struct wpa_global *global, + const char *ifname) +{ + struct wpa_supplicant *wpa_s; + + for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { + if (os_strcmp(wpa_s->ifname, ifname) == 0) + return wpa_s; + } + return NULL; +} + + +/** + * wpa_supplicant_init - Initialize %wpa_supplicant + * @params: Parameters for %wpa_supplicant + * Returns: Pointer to global %wpa_supplicant data, or %NULL on failure + * + * This function is used to initialize %wpa_supplicant. After successful + * initialization, the returned data pointer can be used to add and remove + * network interfaces, and eventually, to deinitialize %wpa_supplicant. + */ +struct wpa_global * wpa_supplicant_init(struct wpa_params *params) +{ + struct wpa_global *global; + int ret, i; + + if (params == NULL) + return NULL; + + wpa_debug_open_file(params->wpa_debug_file_path); + + ret = eap_peer_register_methods(); + if (ret) { + wpa_printf(MSG_ERROR, "Failed to register EAP methods"); + if (ret == -2) + wpa_printf(MSG_ERROR, "Two or more EAP methods used " + "the same EAP type."); + return NULL; + } + + global = os_zalloc(sizeof(*global)); + if (global == NULL) + return NULL; + global->params.daemonize = params->daemonize; + global->params.wait_for_monitor = params->wait_for_monitor; + global->params.dbus_ctrl_interface = params->dbus_ctrl_interface; + if (params->pid_file) + global->params.pid_file = os_strdup(params->pid_file); + if (params->ctrl_interface) + global->params.ctrl_interface = + os_strdup(params->ctrl_interface); + wpa_debug_level = global->params.wpa_debug_level = + params->wpa_debug_level; + wpa_debug_show_keys = global->params.wpa_debug_show_keys = + params->wpa_debug_show_keys; + wpa_debug_timestamp = global->params.wpa_debug_timestamp = + params->wpa_debug_timestamp; + + if (eloop_init(global)) { + wpa_printf(MSG_ERROR, "Failed to initialize event loop"); + wpa_supplicant_deinit(global); + return NULL; + } + + global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global); + if (global->ctrl_iface == NULL) { + wpa_supplicant_deinit(global); + return NULL; + } + + if (global->params.dbus_ctrl_interface) { + global->dbus_ctrl_iface = + wpa_supplicant_dbus_ctrl_iface_init(global); + if (global->dbus_ctrl_iface == NULL) { + wpa_supplicant_deinit(global); + return NULL; + } + } + + for (i = 0; wpa_supplicant_drivers[i]; i++) + global->drv_count++; + if (global->drv_count == 0) { + wpa_printf(MSG_ERROR, "No drivers enabled"); + wpa_supplicant_deinit(global); + return NULL; + } + global->drv_priv = os_zalloc(global->drv_count * sizeof(void *)); + if (global->drv_priv == NULL) { + wpa_supplicant_deinit(global); + return NULL; + } + for (i = 0; wpa_supplicant_drivers[i]; i++) { + if (!wpa_supplicant_drivers[i]->global_init) + continue; + global->drv_priv[i] = wpa_supplicant_drivers[i]->global_init(); + if (global->drv_priv[i] == NULL) { + wpa_printf(MSG_ERROR, "Failed to initialize driver " + "'%s'", wpa_supplicant_drivers[i]->name); + wpa_supplicant_deinit(global); + return NULL; + } + } + + return global; +} + + +/** + * wpa_supplicant_run - Run the %wpa_supplicant main event loop + * @global: Pointer to global data from wpa_supplicant_init() + * Returns: 0 after successful event loop run, -1 on failure + * + * This function starts the main event loop and continues running as long as + * there are any remaining events. In most cases, this function is running as + * long as the %wpa_supplicant process in still in use. + */ +int wpa_supplicant_run(struct wpa_global *global) +{ + struct wpa_supplicant *wpa_s; + + if (global->params.daemonize && + wpa_supplicant_daemon(global->params.pid_file)) + return -1; + + if (global->params.wait_for_monitor) { + for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) + if (wpa_s->ctrl_iface) + wpa_supplicant_ctrl_iface_wait( + wpa_s->ctrl_iface); + } + + eloop_register_signal_terminate(wpa_supplicant_terminate, NULL); + eloop_register_signal_reconfig(wpa_supplicant_reconfig, NULL); + + eloop_run(); + + return 0; +} + + +/** + * wpa_supplicant_deinit - Deinitialize %wpa_supplicant + * @global: Pointer to global data from wpa_supplicant_init() + * + * This function is called to deinitialize %wpa_supplicant and to free all + * allocated resources. Remaining network interfaces will also be removed. + */ +void wpa_supplicant_deinit(struct wpa_global *global) +{ + int i; + + if (global == NULL) + return; + + while (global->ifaces) + wpa_supplicant_remove_iface(global, global->ifaces); + + if (global->ctrl_iface) + wpa_supplicant_global_ctrl_iface_deinit(global->ctrl_iface); + if (global->dbus_ctrl_iface) + wpa_supplicant_dbus_ctrl_iface_deinit(global->dbus_ctrl_iface); + + eap_peer_unregister_methods(); + + for (i = 0; wpa_supplicant_drivers[i] && global->drv_priv; i++) { + if (!global->drv_priv[i]) + continue; + wpa_supplicant_drivers[i]->global_deinit(global->drv_priv[i]); + } + os_free(global->drv_priv); + + eloop_destroy(); + + if (global->params.pid_file) { + os_daemonize_terminate(global->params.pid_file); + os_free(global->params.pid_file); + } + os_free(global->params.ctrl_interface); + + os_free(global); + wpa_debug_close_file(); +} diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf new file mode 100644 index 000000000000..43e81a16d2c8 --- /dev/null +++ b/wpa_supplicant/wpa_supplicant.conf @@ -0,0 +1,840 @@ +##### Example wpa_supplicant configuration file ############################### +# +# This file describes configuration file format and lists all available option. +# Please also take a look at simpler configuration examples in 'examples' +# subdirectory. +# +# Empty lines and lines starting with # are ignored + +# NOTE! This file may contain password information and should probably be made +# readable only by root user on multiuser systems. + +# Note: All file paths in this configuration file should use full (absolute, +# not relative to working directory) path in order to allow working directory +# to be changed. This can happen if wpa_supplicant is run in the background. + +# Whether to allow wpa_supplicant to update (overwrite) configuration +# +# This option can be used to allow wpa_supplicant to overwrite configuration +# file whenever configuration is changed (e.g., new network block is added with +# wpa_cli or wpa_gui, or a password is changed). This is required for +# wpa_cli/wpa_gui to be able to store the configuration changes permanently. +# Please note that overwriting configuration file will remove the comments from +# it. +#update_config=1 + +# global configuration (shared by all network blocks) +# +# Parameters for the control interface. If this is specified, wpa_supplicant +# will open a control interface that is available for external programs to +# manage wpa_supplicant. The meaning of this string depends on which control +# interface mechanism is used. For all cases, the existance of this parameter +# in configuration is used to determine whether the control interface is +# enabled. +# +# For UNIX domain sockets (default on Linux and BSD): This is a directory that +# will be created for UNIX domain sockets 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 +# wpa_supplicant processes can be run at the same time if more than one +# interface is used. +# /var/run/wpa_supplicant is the recommended directory for sockets and by +# default, wpa_cli will use it when trying to connect with wpa_supplicant. +# +# 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 wpa_supplicant 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, wpa_supplicant is configured to use gid 0 (root). If you +# want to allow non-root users to use the control 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. If this variable is commented out or +# not included in the configuration file, group will not be changed from the +# value it got by default when the directory or socket was created. +# +# When configuring both the directory and group, use following format: +# DIR=/var/run/wpa_supplicant GROUP=wheel +# DIR=/var/run/wpa_supplicant GROUP=0 +# (group can be either group name or gid) +# +# For UDP connections (default on Windows): The value will be ignored. This +# variable is just used to select that the control interface is to be created. +# The value can be set to, e.g., udp (ctrl_interface=udp) +# +# For Windows Named Pipe: This value can be used to set the security descriptor +# for controlling access to the control interface. Security descriptor can be +# set using Security Descriptor String Format (see http://msdn.microsoft.com/ +# library/default.asp?url=/library/en-us/secauthz/security/ +# security_descriptor_string_format.asp). The descriptor string needs to be +# prefixed with SDDL=. For example, ctrl_interface=SDDL=D: would set an empty +# DACL (which will reject all connections). See README-Windows.txt for more +# information about SDDL string format. +# +ctrl_interface=/var/run/wpa_supplicant + +# IEEE 802.1X/EAPOL version +# wpa_supplicant is implemented based on IEEE Std 802.1X-2004 which defines +# EAPOL version 2. However, there are many APs that do not handle the new +# version number correctly (they seem to drop the frames completely). In order +# to make wpa_supplicant interoperate with these APs, the version number is set +# to 1 by default. This configuration value can be used to set it to the new +# version (2). +eapol_version=1 + +# AP scanning/selection +# By default, wpa_supplicant requests driver to perform AP scanning and then +# uses the scan results to select a suitable AP. Another alternative is to +# allow the driver to take care of AP scanning and selection and use +# wpa_supplicant just to process EAPOL frames based on IEEE 802.11 association +# information from the driver. +# 1: wpa_supplicant initiates scanning and AP selection +# 0: driver takes care of scanning, AP selection, and IEEE 802.11 association +# parameters (e.g., WPA IE generation); this mode can also be used with +# non-WPA drivers when using IEEE 802.1X mode; do not try to associate with +# APs (i.e., external program needs to control association). This mode must +# also be used when using wired Ethernet drivers. +# 2: like 0, but associate with APs using security policy and SSID (but not +# BSSID); this can be used, e.g., with ndiswrapper and NDIS drivers to +# enable operation with hidden SSIDs and optimized roaming; in this mode, +# the network blocks in the configuration file are tried one by one until +# the driver reports successful association; each network block should have +# explicit security policy (i.e., only one option in the lists) for +# key_mgmt, pairwise, group, proto variables +ap_scan=1 + +# EAP fast re-authentication +# By default, fast re-authentication is enabled for all EAP methods that +# support it. This variable can be used to disable fast re-authentication. +# Normally, there is no need to disable this. +fast_reauth=1 + +# OpenSSL Engine support +# These options can be used to load OpenSSL engines. +# The two engines that are supported currently are shown below: +# They are both from the opensc project (http://www.opensc.org/) +# By default no engines are loaded. +# make the opensc engine available +#opensc_engine_path=/usr/lib/opensc/engine_opensc.so +# make the pkcs11 engine available +#pkcs11_engine_path=/usr/lib/opensc/engine_pkcs11.so +# configure the path to the pkcs11 module required by the pkcs11 engine +#pkcs11_module_path=/usr/lib/pkcs11/opensc-pkcs11.so + +# Dynamic EAP methods +# If EAP methods were built dynamically as shared object files, they need to be +# loaded here before being used in the network blocks. By default, EAP methods +# are included statically in the build, so these lines are not needed +#load_dynamic_eap=/usr/lib/wpa_supplicant/eap_tls.so +#load_dynamic_eap=/usr/lib/wpa_supplicant/eap_md5.so + +# Driver interface parameters +# This field can be used to configure arbitrary driver interace parameters. The +# format is specific to the selected driver interface. This field is not used +# in most cases. +#driver_param="field=value" + +# Country code +# The ISO/IEC alpha2 country code for the country in which this device is +# currently operating. +#country=US + +# Maximum lifetime for PMKSA in seconds; default 43200 +#dot11RSNAConfigPMKLifetime=43200 +# Threshold for reauthentication (percentage of PMK lifetime); default 70 +#dot11RSNAConfigPMKReauthThreshold=70 +# Timeout for security association negotiation in seconds; default 60 +#dot11RSNAConfigSATimeout=60 + +# Wi-Fi Protected Setup (WPS) parameters + +# Universally Unique IDentifier (UUID; see RFC 4122) of the device +# If not configured, UUID will be generated based on the local MAC address. +#uuid=12345678-9abc-def0-1234-56789abcdef0 + +# Device Name +# User-friendly description of device; up to 32 octets encoded in UTF-8 +#device_name=Wireless Client + +# 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=cmodel + +# Model Number +# Additional device description (up to 32 ASCII characters) +#model_number=123 + +# Serial Number +# Serial number of the device (up to 32 characters) +#serial_number=12345 + +# Primary Device Type +# Used format: <categ>-<OUI>-<subcateg> +# categ = Category as an integer value +# OUI = OUI and type octet as a 4-octet hex-encoded value; 0050F204 for +# default WPS OUI +# subcateg = OUI-specific Sub Category as an integer value +# Examples: +# 1-0050F204-1 (Computer / PC) +# 1-0050F204-2 (Computer / Server) +# 5-0050F204-1 (Storage / NAS) +# 6-0050F204-1 (Network Infrastructure / AP) +#device_type=1-0050F204-1 + +# OS Version +# 4-octet operating system version number (hex string) +#os_version=01020300 + +# 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) +#wps_cred_processing=0 + +# network block +# +# Each network (usually AP's sharing the same SSID) is configured as a separate +# block in this configuration file. The network blocks are in preference order +# (the first match is used). +# +# network block fields: +# +# disabled: +# 0 = this network can be used (default) +# 1 = this network block is disabled (can be enabled through ctrl_iface, +# e.g., with wpa_cli or wpa_gui) +# +# id_str: Network identifier string for external scripts. This value is passed +# to external action script through wpa_cli as WPA_ID_STR environment +# variable to make it easier to do network specific configuration. +# +# ssid: SSID (mandatory); either as an ASCII string with double quotation or +# as hex string; network name +# +# scan_ssid: +# 0 = do not scan this SSID with specific Probe Request frames (default) +# 1 = scan with SSID-specific Probe Request frames (this can be used to +# find APs that do not accept broadcast SSID or use multiple SSIDs; +# this will add latency to scanning, so enable this only when needed) +# +# bssid: BSSID (optional); if set, this network block is used only when +# associating with the AP using the configured BSSID +# +# priority: priority group (integer) +# By default, all networks will get same priority group (0). If some of the +# networks are more desirable, this field can be used to change the order in +# which wpa_supplicant goes through the networks when selecting a BSS. The +# priority groups will be iterated in decreasing priority (i.e., the larger the +# priority value, the sooner the network is matched against the scan results). +# Within each priority group, networks will be selected based on security +# policy, signal strength, etc. +# Please note that AP scanning with scan_ssid=1 and ap_scan=2 mode are not +# using this priority to select the order for scanning. Instead, they try the +# networks in the order that used in the configuration file. +# +# mode: IEEE 802.11 operation mode +# 0 = infrastructure (Managed) mode, i.e., associate with an AP (default) +# 1 = IBSS (ad-hoc, peer-to-peer) +# Note: IBSS can only be used with key_mgmt NONE (plaintext and static WEP) +# and key_mgmt=WPA-NONE (fixed group key TKIP/CCMP). In addition, ap_scan has +# to be set to 2 for IBSS. WPA-None requires following network block options: +# proto=WPA, key_mgmt=WPA-NONE, pairwise=NONE, group=TKIP (or CCMP, but not +# both), and psk must also be set. +# +# frequency: Channel frequency in megahertz (MHz) for IBSS, e.g., +# 2412 = IEEE 802.11b/g channel 1. This value is used to configure the initial +# channel for IBSS (adhoc) networks. It is ignored in the infrastructure mode. +# In addition, this value is only used by the station that creates the IBSS. If +# an IBSS network with the configured SSID is already present, the frequency of +# the network will be used instead of this configured value. +# +# proto: list of accepted protocols +# WPA = WPA/IEEE 802.11i/D3.0 +# RSN = WPA2/IEEE 802.11i (also WPA2 can be used as an alias for RSN) +# If not set, this defaults to: WPA RSN +# +# key_mgmt: list of accepted authenticated key management protocols +# WPA-PSK = WPA pre-shared key (this requires 'psk' field) +# WPA-EAP = WPA using EAP authentication +# IEEE8021X = IEEE 802.1X using EAP authentication and (optionally) dynamically +# generated WEP keys +# NONE = WPA is not used; plaintext or static WEP could be used +# WPA-PSK-SHA256 = Like WPA-PSK but using stronger SHA256-based algorithms +# WPA-EAP-SHA256 = Like WPA-EAP but using stronger SHA256-based algorithms +# If not set, this defaults to: WPA-PSK WPA-EAP +# +# auth_alg: list of allowed IEEE 802.11 authentication algorithms +# OPEN = Open System authentication (required for WPA/WPA2) +# SHARED = Shared Key authentication (requires static WEP keys) +# LEAP = LEAP/Network EAP (only used with LEAP) +# If not set, automatic selection is used (Open System with LEAP enabled if +# LEAP is allowed as one of the EAP methods). +# +# pairwise: list of accepted pairwise (unicast) ciphers for WPA +# 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] +# NONE = Use only Group Keys (deprecated, should not be included if APs support +# pairwise keys) +# If not set, this defaults to: CCMP TKIP +# +# group: list of accepted group (broadcast/multicast) ciphers for WPA +# 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] +# WEP104 = WEP (Wired Equivalent Privacy) with 104-bit key +# WEP40 = WEP (Wired Equivalent Privacy) with 40-bit key [IEEE 802.11] +# If not set, this defaults to: CCMP TKIP WEP104 WEP40 +# +# psk: WPA preshared key; 256-bit pre-shared key +# The key used in WPA-PSK mode can be entered either as 64 hex-digits, i.e., +# 32 bytes or as an ASCII passphrase (in which case, the real PSK will be +# generated using the passphrase and SSID). ASCII passphrase must be between +# 8 and 63 characters (inclusive). +# This field is not needed, if WPA-EAP is used. +# Note: Separate tool, wpa_passphrase, can be used to generate 256-bit keys +# from ASCII passphrase. This process uses lot of CPU and wpa_supplicant +# startup and reconfiguration time can be optimized by generating the PSK only +# only when the passphrase or SSID has actually changed. +# +# eapol_flags: IEEE 802.1X/EAPOL options (bit field) +# Dynamic WEP key required for non-WPA mode +# bit0 (1): require dynamically generated unicast WEP key +# bit1 (2): require dynamically generated broadcast WEP key +# (3 = require both keys; default) +# Note: When using wired authentication, eapol_flags must be set to 0 for the +# authentication to be completed successfully. +# +# mixed_cell: This option can be used to configure whether so called mixed +# cells, i.e., networks that use both plaintext and encryption in the same +# SSID, are allowed when selecting a BSS form scan results. +# 0 = disabled (default) +# 1 = enabled +# +# proactive_key_caching: +# Enable/disable opportunistic PMKSA caching for WPA2. +# 0 = disabled (default) +# 1 = enabled +# +# wep_key0..3: Static WEP key (ASCII in double quotation, e.g. "abcde" or +# hex without quotation, e.g., 0102030405) +# wep_tx_keyidx: Default WEP key index (TX) (0..3) +# +# peerkey: Whether PeerKey negotiation for direct links (IEEE 802.11e DLS) is +# allowed. This is only used with RSN/WPA2. +# 0 = disabled (default) +# 1 = enabled +#peerkey=1 +# +# wpa_ptk_rekey: Maximum lifetime for PTK in seconds. This can be used to +# enforce rekeying of PTK to mitigate some attacks against TKIP deficiencies. +# +# Following fields are only used with internal EAP implementation. +# eap: space-separated list of accepted EAP methods +# MD5 = EAP-MD5 (unsecure and does not generate keying material -> +# cannot be used with WPA; to be used as a Phase 2 method +# with EAP-PEAP or EAP-TTLS) +# MSCHAPV2 = EAP-MSCHAPv2 (cannot be used separately with WPA; to be used +# as a Phase 2 method with EAP-PEAP or EAP-TTLS) +# OTP = EAP-OTP (cannot be used separately with WPA; to be used +# as a Phase 2 method with EAP-PEAP or EAP-TTLS) +# GTC = EAP-GTC (cannot be used separately with WPA; to be used +# as a Phase 2 method with EAP-PEAP or EAP-TTLS) +# TLS = EAP-TLS (client and server certificate) +# PEAP = EAP-PEAP (with tunnelled EAP authentication) +# TTLS = EAP-TTLS (with tunnelled EAP or PAP/CHAP/MSCHAP/MSCHAPV2 +# authentication) +# If not set, all compiled in methods are allowed. +# +# identity: Identity string for EAP +# This field is also used to configure user NAI for +# EAP-PSK/PAX/SAKE/GPSK. +# anonymous_identity: Anonymous identity string for EAP (to be used as the +# unencrypted identity with EAP types that support different tunnelled +# identity, e.g., EAP-TTLS) +# password: Password string for EAP. This field can include either the +# plaintext password (using ASCII or hex string) or a NtPasswordHash +# (16-byte MD4 hash of password) in hash:<32 hex digits> format. +# NtPasswordHash can only be used when the password is for MSCHAPv2 or +# MSCHAP (EAP-MSCHAPv2, EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP). +# EAP-PSK (128-bit PSK), EAP-PAX (128-bit PSK), and EAP-SAKE (256-bit +# PSK) is also configured using this field. For EAP-GPSK, this is a +# variable length PSK. +# ca_cert: File path to CA certificate file (PEM/DER). This file can have one +# or more trusted CA certificates. If ca_cert and ca_path are not +# included, server certificate will not be verified. This is insecure and +# a trusted CA certificate should always be configured when using +# EAP-TLS/TTLS/PEAP. Full path should be used since working directory may +# change when wpa_supplicant is run in the background. +# 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". +# Note that when running wpa_supplicant as an application, the user +# certificate store (My user account) is used, whereas computer store +# (Computer account) is used when running wpasvc as a service. +# ca_path: Directory path for CA certificate files (PEM). This path may +# contain multiple CA certificates in OpenSSL format. Common use for this +# is to point to system trusted CA list which is often installed into +# directory like /etc/ssl/certs. If configured, these certificates are +# added to the list of trusted CAs. ca_cert may also be included in that +# case, but it is not required. +# client_cert: File path to client certificate file (PEM/DER) +# Full path should be used since working directory may change when +# wpa_supplicant is run in the background. +# Alternatively, a named configuration blob can be used by setting this +# to blob://<blob name>. +# private_key: File path to client private key file (PEM/DER/PFX) +# When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be +# commented out. Both the private key and certificate will be read from +# the PKCS#12 file in this case. Full path should be used since working +# directory may change when wpa_supplicant is run in the background. +# Windows certificate store can be used by leaving client_cert out and +# configuring private_key in one of the following formats: +# cert://substring_to_match +# hash://certificate_thumbprint_in_hex +# for example: private_key="hash://63093aa9c47f56ae88334c7b65a4" +# Note that when running wpa_supplicant as an application, the user +# certificate store (My user account) is used, whereas computer store +# (Computer account) is used when running wpasvc as a service. +# Alternatively, a named configuration blob can be used by setting this +# to blob://<blob name>. +# private_key_passwd: Password for private key file (if left out, this will be +# asked through control interface) +# 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. +# subject_match: Substring to be matched against the subject of the +# authentication server certificate. If this string is set, the server +# sertificate is only accepted if it contains this string in the subject. +# The subject string is in following format: +# /C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as@example.com +# altsubject_match: Semicolon separated string of entries to be matched against +# the alternative subject name of the authentication server certificate. +# If this string is set, the server sertificate is only accepted if it +# contains one of the entries in an alternative subject name extension. +# altSubjectName string is in following format: TYPE:VALUE +# Example: EMAIL:server@example.com +# Example: DNS:server.example.com;DNS:server2.example.com +# Following types are supported: EMAIL, DNS, URI +# phase1: Phase1 (outer authentication, i.e., TLS tunnel) parameters +# (string with field-value pairs, e.g., "peapver=0" or +# "peapver=1 peaplabel=1") +# 'peapver' can be used to force which PEAP version (0 or 1) is used. +# 'peaplabel=1' can be used to force new label, "client PEAP encryption", +# to be used during key derivation when PEAPv1 or newer. Most existing +# PEAPv1 implementation seem to be using the old label, "client EAP +# encryption", and wpa_supplicant is now using that as the default value. +# Some servers, e.g., Radiator, may require peaplabel=1 configuration to +# interoperate with PEAPv1; see eap_testing.txt for more details. +# 'peap_outer_success=0' can be used to terminate PEAP authentication on +# tunneled EAP-Success. This is required with some RADIUS servers that +# implement draft-josefsson-pppext-eap-tls-eap-05.txt (e.g., +# Lucent NavisRadius v4.4.0 with PEAP in "IETF Draft 5" mode) +# include_tls_length=1 can be used to force wpa_supplicant to include +# TLS Message Length field in all TLS messages even if they are not +# fragmented. +# sim_min_num_chal=3 can be used to configure EAP-SIM to require three +# challenges (by default, it accepts 2 or 3) +# result_ind=1 can be used to enable EAP-SIM and EAP-AKA to use +# protected result indication. +# 'crypto_binding' option can be used to control PEAPv0 cryptobinding +# behavior: +# * 0 = do not use cryptobinding (default) +# * 1 = use cryptobinding if server supports it +# * 2 = require cryptobinding +# EAP-WSC (WPS) uses following options: pin=<Device Password> or +# pbc=1. +# phase2: Phase2 (inner authentication with TLS tunnel) parameters +# (string with field-value pairs, e.g., "auth=MSCHAPV2" for EAP-PEAP or +# "autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS) +# Following certificate/private key fields are used in inner Phase2 +# authentication when using EAP-TTLS or EAP-PEAP. +# ca_cert2: File path to CA certificate file. This file can have one or more +# trusted CA certificates. If ca_cert2 and ca_path2 are not included, +# server certificate will not be verified. This is insecure and a trusted +# CA certificate should always be configured. +# ca_path2: Directory path for CA certificate files (PEM) +# client_cert2: File path to client certificate file +# private_key2: File path to client private key file +# private_key2_passwd: Password for private key file +# dh_file2: File path to DH/DSA parameters file (in PEM format) +# subject_match2: Substring to be matched against the subject of the +# authentication server certificate. +# altsubject_match2: Substring to be matched against the alternative subject +# name of the authentication server certificate. +# +# fragment_size: Maximum EAP fragment size in bytes (default 1398). +# This value limits the fragment size for EAP methods that support +# fragmentation (e.g., EAP-TLS and EAP-PEAP). This value should be set +# small enough to make the EAP messages fit in MTU of the network +# interface used for EAPOL. The default value is suitable for most +# cases. +# +# EAP-FAST variables: +# pac_file: File path for the PAC entries. wpa_supplicant will need to be able +# to create this file and write updates to it when PAC is being +# provisioned or refreshed. Full path to the file should be used since +# working directory may change when wpa_supplicant is run in the +# background. Alternatively, a named configuration blob can be used by +# setting this to blob://<blob name> +# phase1: fast_provisioning option can be used to enable in-line provisioning +# of EAP-FAST credentials (PAC): +# 0 = disabled, +# 1 = allow unauthenticated provisioning, +# 2 = allow authenticated provisioning, +# 3 = allow both unauthenticated and authenticated provisioning +# fast_max_pac_list_len=<num> option can be used to set the maximum +# number of PAC entries to store in a PAC list (default: 10) +# fast_pac_format=binary option can be used to select binary format for +# storing PAC entries in order to save some space (the default +# text format uses about 2.5 times the size of minimal binary +# format) +# +# wpa_supplicant supports number of "EAP workarounds" to work around +# interoperability issues with incorrectly behaving authentication servers. +# These are enabled by default because some of the issues are present in large +# number of authentication servers. Strict EAP conformance mode can be +# configured by disabling workarounds with eap_workaround=0. + +# Example blocks: + +# Simple case: WPA-PSK, PSK as an ASCII passphrase, allow all valid ciphers +network={ + ssid="simple" + psk="very secret passphrase" + priority=5 +} + +# Same as previous, but request SSID-specific scanning (for APs that reject +# broadcast SSID) +network={ + ssid="second ssid" + scan_ssid=1 + psk="very secret passphrase" + priority=2 +} + +# Only WPA-PSK is used. Any valid cipher combination is accepted. +network={ + ssid="example" + proto=WPA + key_mgmt=WPA-PSK + pairwise=CCMP TKIP + group=CCMP TKIP WEP104 WEP40 + psk=06b4be19da289f475aa46a33cb793029d4ab3db7a23ee92382eb0106c72ac7bb + priority=2 +} + +# WPA-Personal(PSK) with TKIP and enforcement for frequent PTK rekeying +network={ + ssid="example" + proto=WPA + key_mgmt=WPA-PSK + pairwise=TKIP + group=TKIP + psk="not so secure passphrase" + wpa_ptk_rekey=600 +} + +# Only WPA-EAP is used. Both CCMP and TKIP is accepted. An AP that used WEP104 +# or WEP40 as the group cipher will not be accepted. +network={ + ssid="example" + proto=RSN + key_mgmt=WPA-EAP + pairwise=CCMP TKIP + group=CCMP TKIP + eap=TLS + identity="user@example.com" + ca_cert="/etc/cert/ca.pem" + client_cert="/etc/cert/user.pem" + private_key="/etc/cert/user.prv" + private_key_passwd="password" + priority=1 +} + +# EAP-PEAP/MSCHAPv2 configuration for RADIUS servers that use the new peaplabel +# (e.g., Radiator) +network={ + ssid="example" + key_mgmt=WPA-EAP + eap=PEAP + identity="user@example.com" + password="foobar" + ca_cert="/etc/cert/ca.pem" + phase1="peaplabel=1" + phase2="auth=MSCHAPV2" + priority=10 +} + +# EAP-TTLS/EAP-MD5-Challenge configuration with anonymous identity for the +# unencrypted use. Real identity is sent only within an encrypted TLS tunnel. +network={ + ssid="example" + key_mgmt=WPA-EAP + eap=TTLS + identity="user@example.com" + anonymous_identity="anonymous@example.com" + password="foobar" + ca_cert="/etc/cert/ca.pem" + priority=2 +} + +# EAP-TTLS/MSCHAPv2 configuration with anonymous identity for the unencrypted +# use. Real identity is sent only within an encrypted TLS tunnel. +network={ + ssid="example" + key_mgmt=WPA-EAP + eap=TTLS + identity="user@example.com" + anonymous_identity="anonymous@example.com" + password="foobar" + ca_cert="/etc/cert/ca.pem" + phase2="auth=MSCHAPV2" +} + +# WPA-EAP, EAP-TTLS with different CA certificate used for outer and inner +# authentication. +network={ + ssid="example" + key_mgmt=WPA-EAP + eap=TTLS + # Phase1 / outer authentication + anonymous_identity="anonymous@example.com" + ca_cert="/etc/cert/ca.pem" + # Phase 2 / inner authentication + phase2="autheap=TLS" + ca_cert2="/etc/cert/ca2.pem" + client_cert2="/etc/cer/user.pem" + private_key2="/etc/cer/user.prv" + private_key2_passwd="password" + priority=2 +} + +# Both WPA-PSK and WPA-EAP is accepted. Only CCMP is accepted as pairwise and +# group cipher. +network={ + ssid="example" + bssid=00:11:22:33:44:55 + proto=WPA RSN + key_mgmt=WPA-PSK WPA-EAP + pairwise=CCMP + group=CCMP + psk=06b4be19da289f475aa46a33cb793029d4ab3db7a23ee92382eb0106c72ac7bb +} + +# Special characters in SSID, so use hex string. Default to WPA-PSK, WPA-EAP +# and all valid ciphers. +network={ + ssid=00010203 + psk=000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f +} + + +# EAP-SIM with a GSM SIM or USIM +network={ + ssid="eap-sim-test" + key_mgmt=WPA-EAP + eap=SIM + pin="1234" + pcsc="" +} + + +# EAP-PSK +network={ + ssid="eap-psk-test" + key_mgmt=WPA-EAP + eap=PSK + anonymous_identity="eap_psk_user" + password=06b4be19da289f475aa46a33cb793029 + identity="eap_psk_user@example.com" +} + + +# IEEE 802.1X/EAPOL with dynamically generated WEP keys (i.e., no WPA) using +# EAP-TLS for authentication and key generation; require both unicast and +# broadcast WEP keys. +network={ + ssid="1x-test" + key_mgmt=IEEE8021X + eap=TLS + identity="user@example.com" + ca_cert="/etc/cert/ca.pem" + client_cert="/etc/cert/user.pem" + private_key="/etc/cert/user.prv" + private_key_passwd="password" + eapol_flags=3 +} + + +# LEAP with dynamic WEP keys +network={ + ssid="leap-example" + key_mgmt=IEEE8021X + eap=LEAP + identity="user" + password="foobar" +} + +# EAP-IKEv2 using shared secrets for both server and peer authentication +network={ + ssid="ikev2-example" + key_mgmt=WPA-EAP + eap=IKEV2 + identity="user" + password="foobar" +} + +# EAP-FAST with WPA (WPA or WPA2) +network={ + ssid="eap-fast-test" + key_mgmt=WPA-EAP + eap=FAST + anonymous_identity="FAST-000102030405" + identity="username" + password="password" + phase1="fast_provisioning=1" + pac_file="/etc/wpa_supplicant.eap-fast-pac" +} + +network={ + ssid="eap-fast-test" + key_mgmt=WPA-EAP + eap=FAST + anonymous_identity="FAST-000102030405" + identity="username" + password="password" + phase1="fast_provisioning=1" + pac_file="blob://eap-fast-pac" +} + +# Plaintext connection (no WPA, no IEEE 802.1X) +network={ + ssid="plaintext-test" + key_mgmt=NONE +} + + +# Shared WEP key connection (no WPA, no IEEE 802.1X) +network={ + ssid="static-wep-test" + key_mgmt=NONE + wep_key0="abcde" + wep_key1=0102030405 + wep_key2="1234567890123" + wep_tx_keyidx=0 + priority=5 +} + + +# Shared WEP key connection (no WPA, no IEEE 802.1X) using Shared Key +# IEEE 802.11 authentication +network={ + ssid="static-wep-test2" + key_mgmt=NONE + wep_key0="abcde" + wep_key1=0102030405 + wep_key2="1234567890123" + wep_tx_keyidx=0 + priority=5 + auth_alg=SHARED +} + + +# IBSS/ad-hoc network with WPA-None/TKIP. +network={ + ssid="test adhoc" + mode=1 + frequency=2412 + proto=WPA + key_mgmt=WPA-NONE + pairwise=NONE + group=TKIP + psk="secret passphrase" +} + + +# Catch all example that allows more or less all configuration modes +network={ + ssid="example" + scan_ssid=1 + key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE + pairwise=CCMP TKIP + group=CCMP TKIP WEP104 WEP40 + psk="very secret passphrase" + eap=TTLS PEAP TLS + identity="user@example.com" + password="foobar" + ca_cert="/etc/cert/ca.pem" + client_cert="/etc/cert/user.pem" + private_key="/etc/cert/user.prv" + private_key_passwd="password" + phase1="peaplabel=0" +} + +# Example of EAP-TLS with smartcard (openssl engine) +network={ + ssid="example" + key_mgmt=WPA-EAP + eap=TLS + proto=RSN + pairwise=CCMP TKIP + group=CCMP TKIP + identity="user@example.com" + ca_cert="/etc/cert/ca.pem" + client_cert="/etc/cert/user.pem" + + engine=1 + + # The engine configured here must be available. Look at + # OpenSSL engine support in the global section. + # The key available through the engine must be the private key + # matching the client certificate configured above. + + # use the opensc engine + #engine_id="opensc" + #key_id="45" + + # use the pkcs11 engine + engine_id="pkcs11" + key_id="id_45" + + # Optional PIN configuration; this can be left out and PIN will be + # asked through the control interface + pin="1234" +} + +# Example configuration showing how to use an inlined blob as a CA certificate +# data instead of using external file +network={ + ssid="example" + key_mgmt=WPA-EAP + eap=TTLS + identity="user@example.com" + anonymous_identity="anonymous@example.com" + password="foobar" + ca_cert="blob://exampleblob" + priority=20 +} + +blob-base64-exampleblob={ +SGVsbG8gV29ybGQhCg== +} + + +# Wildcard match for SSID (plaintext APs only). This example select any +# open AP regardless of its SSID. +network={ + key_mgmt=NONE +} diff --git a/wpa_supplicant/wpa_supplicant.nsi b/wpa_supplicant/wpa_supplicant.nsi new file mode 100644 index 000000000000..2783ca3c8e64 --- /dev/null +++ b/wpa_supplicant/wpa_supplicant.nsi @@ -0,0 +1,108 @@ +!define PRODUCT_NAME "wpa_supplicant" +!define PRODUCT_VERSION "@WPAVER@" +!define PRODUCT_PUBLISHER "Jouni Malinen" + +Name "${PRODUCT_NAME} ${PRODUCT_VERSION}" +outfile "../wpa_supplicant-@WPAVER@.exe" + +installDir "$PROGRAMFILES\wpa_supplicant" + +Page Directory +Page InstFiles + +section -Prerequisites + SetOutPath $INSTDIR\Prerequisites + MessageBox MB_YESNO "Install WinPcap?" /SD IDYES IDNO endWinPcap + File "/opt/Qt-Win/files/WinPcap_4_0_2.exe" + ExecWait "$INSTDIR\Prerequisites\WinPcap_4_0_2.exe" + Goto endWinPcap + endWinPcap: +sectionEnd + + +section + setOutPath $INSTDIR + + File wpa_gui.exe + File wpa_cli.exe + File COPYING + File README + File README-Windows.txt + File win_example.reg + File win_if_list.exe + File wpa_passphrase.exe + File wpa_supplicant.conf + File wpa_supplicant.exe + File wpasvc.exe + + File /opt/Qt-Win/files/mingwm10.dll + File /opt/Qt-Win/files/QtCore4.dll + File /opt/Qt-Win/files/QtGui4.dll + + WriteRegDWORD HKLM "Software\wpa_supplicant" "debug_level" 0 + WriteRegDWORD HKLM "Software\wpa_supplicant" "debug_show_keys" 0 + WriteRegDWORD HKLM "Software\wpa_supplicant" "debug_timestamp" 0 + WriteRegDWORD HKLM "Software\wpa_supplicant" "debug_use_file" 0 + + WriteRegDWORD HKLM "Software\wpa_supplicant\configs\default" "ap_scan" 2 + WriteRegDWORD HKLM "Software\wpa_supplicant\configs\default" "update_config" 1 + WriteRegDWORD HKLM "Software\wpa_supplicant\configs\default\networks" "dummy" 1 + DeleteRegValue HKLM "Software\wpa_supplicant\configs\default\networks" "dummy" + + WriteRegDWORD HKLM "Software\wpa_supplicant\interfaces" "dummy" 1 + DeleteRegValue HKLM "Software\wpa_supplicant\interfaces" "dummy" + + writeUninstaller "$INSTDIR\uninstall.exe" + + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\wpa_supplicant" \ + "DisplayName" "wpa_supplicant" +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\wpa_supplicant" \ + "UninstallString" "$INSTDIR\uninstall.exe" + + CreateDirectory "$SMPROGRAMS\wpa_supplicant" + CreateShortCut "$SMPROGRAMS\wpa_supplicant\wpa_gui.lnk" "$INSTDIR\wpa_gui.exe" + CreateShortCut "$SMPROGRAMS\wpa_supplicant\Uninstall.lnk" "$INSTDIR\uninstall.exe" + + ExecWait "$INSTDIR\wpasvc.exe reg" +sectionEnd + + +Function un.onInit + MessageBox MB_YESNO "This will uninstall wpa_supplicant. Continue?" IDYES NoAbort + Abort + NoAbort: +FunctionEnd + +section "uninstall" + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\wpa_supplicant" + delete "$INSTDIR\uninstall.exe" + + ExecWait "$INSTDIR\wpasvc.exe unreg" + + DeleteRegKey HKLM "Software\wpa_supplicant" + + delete "$INSTDIR\wpa_gui.exe" + delete "$INSTDIR\wpa_cli.exe" + delete "$INSTDIR\COPYING" + delete "$INSTDIR\README" + delete "$INSTDIR\README-Windows.txt" + delete "$INSTDIR\win_example.reg" + delete "$INSTDIR\win_if_list.exe" + delete "$INSTDIR\wpa_passphrase.exe" + delete "$INSTDIR\wpa_supplicant.conf" + delete "$INSTDIR\wpa_supplicant.exe" + delete "$INSTDIR\wpasvc.exe" + + delete "$INSTDIR\mingwm10.dll" + delete "$INSTDIR\QtCore4.dll" + delete "$INSTDIR\QtGui4.dll" + + delete "$INSTDIR\Prerequisites\WinPcap_4_0_2.exe" + rmdir "$INSTDIR\Prerequisites" + + rmdir "$INSTDIR" + + delete "$SMPROGRAMS\wpa_supplicant\wpa_gui.lnk" + delete "$SMPROGRAMS\wpa_supplicant\Uninstall.lnk" + rmdir "$SMPROGRAMS\wpa_supplicant" +sectionEnd diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h new file mode 100644 index 000000000000..5e4dcc1b9fca --- /dev/null +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -0,0 +1,763 @@ +/* + * wpa_supplicant - Internal definitions + * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef WPA_SUPPLICANT_I_H +#define WPA_SUPPLICANT_I_H + +#include "drivers/driver.h" + +extern const char *wpa_supplicant_version; +extern const char *wpa_supplicant_license; +#ifndef CONFIG_NO_STDOUT_DEBUG +extern const char *wpa_supplicant_full_license1; +extern const char *wpa_supplicant_full_license2; +extern const char *wpa_supplicant_full_license3; +extern const char *wpa_supplicant_full_license4; +extern const char *wpa_supplicant_full_license5; +#endif /* CONFIG_NO_STDOUT_DEBUG */ + +extern struct wpa_driver_ops *wpa_supplicant_drivers[]; + + +struct wpa_scan_result; +struct wpa_sm; +struct wpa_supplicant; + +/* + * Forward declarations of private structures used within the ctrl_iface + * backends. Other parts of wpa_supplicant do not have access to data stored in + * these structures. + */ +struct ctrl_iface_priv; +struct ctrl_iface_global_priv; +struct ctrl_iface_dbus_priv; + +/** + * struct wpa_interface - Parameters for wpa_supplicant_add_iface() + */ +struct wpa_interface { + /** + * confname - Configuration name (file or profile) name + * + * This can also be %NULL when a configuration file is not used. In + * that case, ctrl_interface must be set to allow the interface to be + * configured. + */ + const char *confname; + + /** + * ctrl_interface - Control interface parameter + * + * If a configuration file is not used, this variable can be used to + * set the ctrl_interface parameter that would have otherwise been read + * from the configuration file. If both confname and ctrl_interface are + * set, ctrl_interface is used to override the value from configuration + * file. + */ + const char *ctrl_interface; + + /** + * driver - Driver interface name, or %NULL to use the default driver + */ + const char *driver; + + /** + * driver_param - Driver interface parameters + * + * If a configuration file is not used, this variable can be used to + * set the driver_param parameters that would have otherwise been read + * from the configuration file. If both confname and driver_param are + * set, driver_param is used to override the value from configuration + * file. + */ + const char *driver_param; + + /** + * ifname - Interface name + */ + const char *ifname; + + /** + * bridge_ifname - Optional bridge interface name + * + * If the driver interface (ifname) is included in a Linux bridge + * device, the bridge interface may need to be used for receiving EAPOL + * frames. This can be enabled by setting this variable to enable + * receiving of EAPOL frames from an additional interface. + */ + const char *bridge_ifname; +}; + +/** + * struct wpa_params - Parameters for wpa_supplicant_init() + */ +struct wpa_params { + /** + * daemonize - Run %wpa_supplicant in the background + */ + int daemonize; + + /** + * wait_for_monitor - Wait for a monitor program before starting + */ + int wait_for_monitor; + + /** + * pid_file - Path to a PID (process ID) file + * + * If this and daemonize are set, process ID of the background process + * will be written to the specified file. + */ + char *pid_file; + + /** + * wpa_debug_level - Debugging verbosity level (e.g., MSG_INFO) + */ + int wpa_debug_level; + + /** + * wpa_debug_show_keys - Whether keying material is included in debug + * + * This parameter can be used to allow keying material to be included + * in debug messages. This is a security risk and this option should + * not be enabled in normal configuration. If needed during + * development or while troubleshooting, this option can provide more + * details for figuring out what is happening. + */ + int wpa_debug_show_keys; + + /** + * wpa_debug_timestamp - Whether to include timestamp in debug messages + */ + int wpa_debug_timestamp; + + /** + * ctrl_interface - Global ctrl_iface path/parameter + */ + char *ctrl_interface; + + /** + * dbus_ctrl_interface - Enable the DBus control interface + */ + int dbus_ctrl_interface; + + /** + * wpa_debug_file_path - Path of debug file or %NULL to use stdout + */ + const char *wpa_debug_file_path; +}; + +/** + * struct wpa_global - Internal, global data for all %wpa_supplicant interfaces + * + * This structure is initialized by calling wpa_supplicant_init() when starting + * %wpa_supplicant. + */ +struct wpa_global { + struct wpa_supplicant *ifaces; + struct wpa_params params; + struct ctrl_iface_global_priv *ctrl_iface; + struct ctrl_iface_dbus_priv *dbus_ctrl_iface; + void **drv_priv; + size_t drv_count; +}; + + +struct wpa_client_mlme { +#ifdef CONFIG_CLIENT_MLME + enum { + IEEE80211_DISABLED, IEEE80211_AUTHENTICATE, + IEEE80211_ASSOCIATE, IEEE80211_ASSOCIATED, + IEEE80211_IBSS_SEARCH, IEEE80211_IBSS_JOINED + } state; + u8 prev_bssid[ETH_ALEN]; + u8 ssid[32]; + size_t ssid_len; + u16 aid; + u16 ap_capab, capab; + u8 *extra_ie; /* to be added to the end of AssocReq */ + size_t extra_ie_len; + u8 *extra_probe_ie; /* to be added to the end of ProbeReq */ + size_t extra_probe_ie_len; + wpa_key_mgmt key_mgmt; + + /* The last AssocReq/Resp IEs */ + u8 *assocreq_ies, *assocresp_ies; + size_t assocreq_ies_len, assocresp_ies_len; + + int auth_tries, assoc_tries; + + unsigned int ssid_set:1; + unsigned int bssid_set:1; + unsigned int prev_bssid_set:1; + unsigned int authenticated:1; + unsigned int associated:1; + unsigned int probereq_poll:1; + unsigned int use_protection:1; + unsigned int create_ibss:1; + unsigned int mixed_cell:1; + unsigned int wmm_enabled:1; + + struct os_time last_probe; + +#define IEEE80211_AUTH_ALG_OPEN BIT(0) +#define IEEE80211_AUTH_ALG_SHARED_KEY BIT(1) +#define IEEE80211_AUTH_ALG_LEAP BIT(2) + unsigned int auth_algs; /* bitfield of allowed auth algs */ + int auth_alg; /* currently used IEEE 802.11 authentication algorithm */ + int auth_transaction; + + struct os_time ibss_join_req; + u8 *probe_resp; /* ProbeResp template for IBSS */ + size_t probe_resp_len; + u32 supp_rates_bits; + + int wmm_last_param_set; + + int sta_scanning; + int scan_hw_mode_idx; + int scan_channel_idx; + enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state; + struct os_time last_scan_completed; + int scan_oper_channel; + int scan_oper_freq; + int scan_oper_phymode; + u8 scan_ssid[32]; + size_t scan_ssid_len; + int scan_skip_11b; + + struct ieee80211_sta_bss *sta_bss_list; +#define STA_HASH_SIZE 256 +#define STA_HASH(sta) (sta[5]) + struct ieee80211_sta_bss *sta_bss_hash[STA_HASH_SIZE]; + + int cts_protect_erp_frames; + + int phymode; /* current mode; WPA_MODE_IEEE80211A, .. */ + struct wpa_hw_modes *modes; + size_t num_modes; + unsigned int hw_modes; /* bitfield of allowed hardware modes; + * (1 << MODE_*) */ + int num_curr_rates; + struct wpa_rate_data *curr_rates; + int freq; /* The current frequency in MHz */ + int channel; /* The current IEEE 802.11 channel number */ + +#ifdef CONFIG_IEEE80211R + u8 current_md[6]; + u8 *ft_ies; + size_t ft_ies_len; +#endif /* CONFIG_IEEE80211R */ + +#else /* CONFIG_CLIENT_MLME */ + int dummy; /* to keep MSVC happy */ +#endif /* CONFIG_CLIENT_MLME */ +}; + +/** + * struct wpa_supplicant - Internal data for wpa_supplicant interface + * + * This structure contains the internal data for core wpa_supplicant code. This + * should be only used directly from the core code. However, a pointer to this + * data is used from other files as an arbitrary context pointer in calls to + * core functions. + */ +struct wpa_supplicant { + struct wpa_global *global; + struct wpa_supplicant *next; + struct l2_packet_data *l2; + struct l2_packet_data *l2_br; + unsigned char own_addr[ETH_ALEN]; + char ifname[100]; +#ifdef CONFIG_CTRL_IFACE_DBUS + char *dbus_path; +#endif /* CONFIG_CTRL_IFACE_DBUS */ + char bridge_ifname[16]; + + char *confname; + struct wpa_config *conf; + int countermeasures; + os_time_t last_michael_mic_error; + u8 bssid[ETH_ALEN]; + u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this + * field contains the targer BSSID. */ + int reassociate; /* reassociation requested */ + int disconnected; /* all connections disabled; i.e., do no reassociate + * before this has been cleared */ + struct wpa_ssid *current_ssid; + int ap_ies_from_associnfo; + + /* Selected configuration (based on Beacon/ProbeResp WPA IE) */ + int pairwise_cipher; + int group_cipher; + int key_mgmt; + int mgmt_group_cipher; + + void *drv_priv; /* private data used by driver_ops */ + + struct wpa_ssid *prev_scan_ssid; /* previously scanned SSID; + * NULL = not yet initialized (start + * with broadcast SSID) + * BROADCAST_SSID_SCAN = broadcast + * SSID was used in the previous scan + */ +#define BROADCAST_SSID_SCAN ((struct wpa_ssid *) 1) + + struct wpa_scan_results *scan_res; + + struct wpa_driver_ops *driver; + int interface_removed; /* whether the network interface has been + * removed */ + struct wpa_sm *wpa; + struct eapol_sm *eapol; + + struct ctrl_iface_priv *ctrl_iface; + + wpa_states wpa_state; + int new_connection; + int reassociated_connection; + + int eapol_received; /* number of EAPOL packets received after the + * previous association event */ + + struct scard_data *scard; + + unsigned char last_eapol_src[ETH_ALEN]; + + int keys_cleared; + + struct wpa_blacklist *blacklist; + + int scan_req; /* manual scan request; this forces a scan even if there + * are no enabled networks in the configuration */ + int scan_res_tried; /* whether ap_scan=1 mode has tried to fetch scan + * results without a new scan request; this is used + * to speed up the first association if the driver + * has already available scan results. */ + int scan_runs; /* number of scan runs since WPS was started */ + + struct wpa_client_mlme mlme; + int use_client_mlme; + int driver_4way_handshake; + + int pending_mic_error_report; + int pending_mic_error_pairwise; + int mic_errors_seen; /* Michael MIC errors with the current PTK */ + + struct wps_context *wps; + int wps_success; /* WPS success event received */ + int blacklist_cleared; +}; + + +/* wpa_supplicant.c */ +int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s); + +const char * wpa_supplicant_state_txt(int state); +int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s); +int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, + struct wpa_scan_res *bss, + struct wpa_ssid *ssid, + u8 *wpa_ie, size_t *wpa_ie_len); +void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, + struct wpa_scan_res *bss, + struct wpa_ssid *ssid); +void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid); +void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s); +int wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s); +void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr); +void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s, + int sec, int usec); +void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s, wpa_states state); +struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s); +void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s); +void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s, + int reason_code); +void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s, + int reason_code); + +void wpa_show_license(void); + +struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global, + struct wpa_interface *iface); +int wpa_supplicant_remove_iface(struct wpa_global *global, + struct wpa_supplicant *wpa_s); +struct wpa_supplicant * wpa_supplicant_get_iface(struct wpa_global *global, + const char *ifname); +struct wpa_global * wpa_supplicant_init(struct wpa_params *params); +int wpa_supplicant_run(struct wpa_global *global); +void wpa_supplicant_deinit(struct wpa_global *global); + +int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid); + +/* scan.c */ +void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec); +void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s); + +/* events.c */ +void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s); + +/* driver_ops */ +static inline void * wpa_drv_init(struct wpa_supplicant *wpa_s, + const char *ifname) +{ + if (wpa_s->driver->init2) + return wpa_s->driver->init2(wpa_s, ifname, wpa_s->global); + if (wpa_s->driver->init) { + return wpa_s->driver->init(wpa_s, ifname); + } + return NULL; +} + +static inline void wpa_drv_deinit(struct wpa_supplicant *wpa_s) +{ + if (wpa_s->driver->deinit) + wpa_s->driver->deinit(wpa_s->drv_priv); +} + +static inline int wpa_drv_set_param(struct wpa_supplicant *wpa_s, + const char *param) +{ + if (wpa_s->driver->set_param) + return wpa_s->driver->set_param(wpa_s->drv_priv, param); + return 0; +} + +static inline int wpa_drv_set_drop_unencrypted(struct wpa_supplicant *wpa_s, + int enabled) +{ + if (wpa_s->driver->set_drop_unencrypted) { + return wpa_s->driver->set_drop_unencrypted(wpa_s->drv_priv, + enabled); + } + return -1; +} + +static inline int wpa_drv_set_countermeasures(struct wpa_supplicant *wpa_s, + int enabled) +{ + if (wpa_s->driver->set_countermeasures) { + return wpa_s->driver->set_countermeasures(wpa_s->drv_priv, + enabled); + } + return -1; +} + +static inline int wpa_drv_set_auth_alg(struct wpa_supplicant *wpa_s, + int auth_alg) +{ + if (wpa_s->driver->set_auth_alg) { + return wpa_s->driver->set_auth_alg(wpa_s->drv_priv, + auth_alg); + } + return -1; +} + +static inline int wpa_drv_set_wpa(struct wpa_supplicant *wpa_s, int enabled) +{ + if (wpa_s->driver->set_wpa) { + return wpa_s->driver->set_wpa(wpa_s->drv_priv, enabled); + } + return 0; +} + +static inline int wpa_drv_set_mode(struct wpa_supplicant *wpa_s, int mode) +{ + if (wpa_s->driver->set_mode) { + return wpa_s->driver->set_mode(wpa_s->drv_priv, mode); + } + return 0; +} + +static inline int wpa_drv_associate(struct wpa_supplicant *wpa_s, + struct wpa_driver_associate_params *params) +{ + if (wpa_s->driver->associate) { + return wpa_s->driver->associate(wpa_s->drv_priv, params); + } + return -1; +} + +static inline int wpa_drv_scan(struct wpa_supplicant *wpa_s, const u8 *ssid, + size_t ssid_len) +{ + if (wpa_s->driver->scan) { + return wpa_s->driver->scan(wpa_s->drv_priv, ssid, ssid_len); + } + return -1; +} + +static inline int wpa_drv_get_scan_results(struct wpa_supplicant *wpa_s, + struct wpa_scan_result *results, + size_t max_size) +{ + if (wpa_s->driver->get_scan_results) { + return wpa_s->driver->get_scan_results(wpa_s->drv_priv, + results, max_size); + } + return -1; +} + +static inline struct wpa_scan_results * wpa_drv_get_scan_results2( + struct wpa_supplicant *wpa_s) +{ + if (wpa_s->driver->get_scan_results2) + return wpa_s->driver->get_scan_results2(wpa_s->drv_priv); + return NULL; +} + +static inline int wpa_drv_get_bssid(struct wpa_supplicant *wpa_s, u8 *bssid) +{ + if (wpa_s->driver->get_bssid) { + return wpa_s->driver->get_bssid(wpa_s->drv_priv, bssid); + } + return -1; +} + +static inline int wpa_drv_get_ssid(struct wpa_supplicant *wpa_s, u8 *ssid) +{ + if (wpa_s->driver->get_ssid) { + return wpa_s->driver->get_ssid(wpa_s->drv_priv, ssid); + } + return -1; +} + +static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s, 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 (wpa_s->driver->set_key) { + wpa_s->keys_cleared = 0; + return wpa_s->driver->set_key(wpa_s->drv_priv, alg, addr, + key_idx, set_tx, seq, seq_len, + key, key_len); + } + return -1; +} + +static inline int wpa_drv_deauthenticate(struct wpa_supplicant *wpa_s, + const u8 *addr, int reason_code) +{ + if (wpa_s->driver->deauthenticate) { + return wpa_s->driver->deauthenticate(wpa_s->drv_priv, addr, + reason_code); + } + return -1; +} + +static inline int wpa_drv_disassociate(struct wpa_supplicant *wpa_s, + const u8 *addr, int reason_code) +{ + if (wpa_s->driver->disassociate) { + return wpa_s->driver->disassociate(wpa_s->drv_priv, addr, + reason_code); + } + return -1; +} + +static inline int wpa_drv_add_pmkid(struct wpa_supplicant *wpa_s, + const u8 *bssid, const u8 *pmkid) +{ + if (wpa_s->driver->add_pmkid) { + return wpa_s->driver->add_pmkid(wpa_s->drv_priv, bssid, pmkid); + } + return -1; +} + +static inline int wpa_drv_remove_pmkid(struct wpa_supplicant *wpa_s, + const u8 *bssid, const u8 *pmkid) +{ + if (wpa_s->driver->remove_pmkid) { + return wpa_s->driver->remove_pmkid(wpa_s->drv_priv, bssid, + pmkid); + } + return -1; +} + +static inline int wpa_drv_flush_pmkid(struct wpa_supplicant *wpa_s) +{ + if (wpa_s->driver->flush_pmkid) { + return wpa_s->driver->flush_pmkid(wpa_s->drv_priv); + } + return -1; +} + +static inline int wpa_drv_get_capa(struct wpa_supplicant *wpa_s, + struct wpa_driver_capa *capa) +{ + if (wpa_s->driver->get_capa) { + return wpa_s->driver->get_capa(wpa_s->drv_priv, capa); + } + return -1; +} + +static inline void wpa_drv_poll(struct wpa_supplicant *wpa_s) +{ + if (wpa_s->driver->poll) { + wpa_s->driver->poll(wpa_s->drv_priv); + } +} + +static inline const char * wpa_drv_get_ifname(struct wpa_supplicant *wpa_s) +{ + if (wpa_s->driver->get_ifname) { + return wpa_s->driver->get_ifname(wpa_s->drv_priv); + } + return NULL; +} + +static inline const u8 * wpa_drv_get_mac_addr(struct wpa_supplicant *wpa_s) +{ + if (wpa_s->driver->get_mac_addr) { + return wpa_s->driver->get_mac_addr(wpa_s->drv_priv); + } + return NULL; +} + +static inline int wpa_drv_send_eapol(struct wpa_supplicant *wpa_s, + const u8 *dst, u16 proto, + const u8 *data, size_t data_len) +{ + if (wpa_s->driver->send_eapol) + return wpa_s->driver->send_eapol(wpa_s->drv_priv, dst, proto, + data, data_len); + return -1; +} + +static inline int wpa_drv_set_operstate(struct wpa_supplicant *wpa_s, + int state) +{ + if (wpa_s->driver->set_operstate) + return wpa_s->driver->set_operstate(wpa_s->drv_priv, state); + return 0; +} + +static inline int wpa_drv_mlme_setprotection(struct wpa_supplicant *wpa_s, + const u8 *addr, int protect_type, + int key_type) +{ + if (wpa_s->driver->mlme_setprotection) + return wpa_s->driver->mlme_setprotection(wpa_s->drv_priv, addr, + protect_type, + key_type); + return 0; +} + +static inline struct wpa_hw_modes * +wpa_drv_get_hw_feature_data(struct wpa_supplicant *wpa_s, u16 *num_modes, + u16 *flags) +{ + if (wpa_s->driver->get_hw_feature_data) + return wpa_s->driver->get_hw_feature_data(wpa_s->drv_priv, + num_modes, flags); + return NULL; +} + +static inline int wpa_drv_set_channel(struct wpa_supplicant *wpa_s, + wpa_hw_mode phymode, int chan, + int freq) +{ + if (wpa_s->driver->set_channel) + return wpa_s->driver->set_channel(wpa_s->drv_priv, phymode, + chan, freq); + return -1; +} + +static inline int wpa_drv_set_ssid(struct wpa_supplicant *wpa_s, + const u8 *ssid, size_t ssid_len) +{ + if (wpa_s->driver->set_ssid) { + return wpa_s->driver->set_ssid(wpa_s->drv_priv, ssid, + ssid_len); + } + return -1; +} + +static inline int wpa_drv_set_bssid(struct wpa_supplicant *wpa_s, + const u8 *bssid) +{ + if (wpa_s->driver->set_bssid) { + return wpa_s->driver->set_bssid(wpa_s->drv_priv, bssid); + } + return -1; +} + +static inline int wpa_drv_set_country(struct wpa_supplicant *wpa_s, + const char *alpha2) +{ + if (wpa_s->driver->set_country) + return wpa_s->driver->set_country(wpa_s->drv_priv, alpha2); + return 0; +} + +static inline int wpa_drv_send_mlme(struct wpa_supplicant *wpa_s, + const u8 *data, size_t data_len) +{ + if (wpa_s->driver->send_mlme) + return wpa_s->driver->send_mlme(wpa_s->drv_priv, + data, data_len); + return -1; +} + +static inline int wpa_drv_mlme_add_sta(struct wpa_supplicant *wpa_s, + const u8 *addr, const u8 *supp_rates, + size_t supp_rates_len) +{ + if (wpa_s->driver->mlme_add_sta) + return wpa_s->driver->mlme_add_sta(wpa_s->drv_priv, addr, + supp_rates, supp_rates_len); + return -1; +} + +static inline int wpa_drv_mlme_remove_sta(struct wpa_supplicant *wpa_s, + const u8 *addr) +{ + if (wpa_s->driver->mlme_remove_sta) + return wpa_s->driver->mlme_remove_sta(wpa_s->drv_priv, addr); + return -1; +} + +static inline int wpa_drv_update_ft_ies(struct wpa_supplicant *wpa_s, + const u8 *md, + const u8 *ies, size_t ies_len) +{ + if (wpa_s->driver->update_ft_ies) + return wpa_s->driver->update_ft_ies(wpa_s->drv_priv, md, + ies, ies_len); + return -1; +} + +static inline int wpa_drv_send_ft_action(struct wpa_supplicant *wpa_s, + u8 action, const u8 *target_ap, + const u8 *ies, size_t ies_len) +{ + if (wpa_s->driver->send_ft_action) + return wpa_s->driver->send_ft_action(wpa_s->drv_priv, action, + target_ap, ies, ies_len); + return -1; +} + +static inline int wpa_drv_set_probe_req_ie(struct wpa_supplicant *wpa_s, + const u8 *ies, size_t ies_len) +{ + if (wpa_s->driver->set_probe_req_ie) + return wpa_s->driver->set_probe_req_ie(wpa_s->drv_priv, ies, + ies_len); + return -1; +} + +#endif /* WPA_SUPPLICANT_I_H */ diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c new file mode 100644 index 000000000000..2b96aa7071ea --- /dev/null +++ b/wpa_supplicant/wpas_glue.c @@ -0,0 +1,642 @@ +/* + * WPA Supplicant - Glue code to setup EAPOL and RSN modules + * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "eapol_supp/eapol_supp_sm.h" +#include "wpa.h" +#include "eloop.h" +#include "config.h" +#include "l2_packet/l2_packet.h" +#include "wpa_common.h" +#include "wpa_supplicant_i.h" +#include "pmksa_cache.h" +#include "mlme.h" +#include "ieee802_11_defs.h" +#include "wpa_ctrl.h" +#include "wpas_glue.h" +#include "wps_supplicant.h" + + +#ifndef CONFIG_NO_CONFIG_BLOBS +#if defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA) +static void wpa_supplicant_set_config_blob(void *ctx, + struct wpa_config_blob *blob) +{ + struct wpa_supplicant *wpa_s = ctx; + wpa_config_set_blob(wpa_s->conf, blob); + if (wpa_s->conf->update_config) { + int ret = wpa_config_write(wpa_s->confname, wpa_s->conf); + if (ret) { + wpa_printf(MSG_DEBUG, "Failed to update config after " + "blob set"); + } + } +} + + +static const struct wpa_config_blob * +wpa_supplicant_get_config_blob(void *ctx, const char *name) +{ + struct wpa_supplicant *wpa_s = ctx; + return wpa_config_get_blob(wpa_s->conf, name); +} +#endif /* defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA) */ +#endif /* CONFIG_NO_CONFIG_BLOBS */ + + +#if defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA) +static u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type, + const void *data, u16 data_len, + size_t *msg_len, void **data_pos) +{ + struct ieee802_1x_hdr *hdr; + + *msg_len = sizeof(*hdr) + data_len; + hdr = os_malloc(*msg_len); + if (hdr == NULL) + return NULL; + + hdr->version = wpa_s->conf->eapol_version; + hdr->type = type; + hdr->length = host_to_be16(data_len); + + if (data) + os_memcpy(hdr + 1, data, data_len); + else + os_memset(hdr + 1, 0, data_len); + + if (data_pos) + *data_pos = hdr + 1; + + return (u8 *) hdr; +} + + +/** + * wpa_ether_send - Send Ethernet frame + * @wpa_s: Pointer to wpa_supplicant data + * @dest: Destination MAC address + * @proto: Ethertype in host byte order + * @buf: Frame payload starting from IEEE 802.1X header + * @len: Frame payload length + * Returns: >=0 on success, <0 on failure + */ +static int wpa_ether_send(struct wpa_supplicant *wpa_s, const u8 *dest, + u16 proto, const u8 *buf, size_t len) +{ + if (wpa_s->l2) { + return l2_packet_send(wpa_s->l2, dest, proto, buf, len); + } + + return wpa_drv_send_eapol(wpa_s, dest, proto, buf, len); +} +#endif /* IEEE8021X_EAPOL || !CONFIG_NO_WPA */ + + +#ifdef IEEE8021X_EAPOL + +/** + * wpa_supplicant_eapol_send - Send IEEE 802.1X EAPOL packet to Authenticator + * @ctx: Pointer to wpa_supplicant data (wpa_s) + * @type: IEEE 802.1X packet type (IEEE802_1X_TYPE_*) + * @buf: EAPOL payload (after IEEE 802.1X header) + * @len: EAPOL payload length + * Returns: >=0 on success, <0 on failure + * + * This function adds Ethernet and IEEE 802.1X header and sends the EAPOL frame + * to the current Authenticator. + */ +static int wpa_supplicant_eapol_send(void *ctx, int type, const u8 *buf, + size_t len) +{ + struct wpa_supplicant *wpa_s = ctx; + u8 *msg, *dst, bssid[ETH_ALEN]; + size_t msglen; + int res; + + /* TODO: could add l2_packet_sendmsg that allows fragments to avoid + * extra copy here */ + + if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) || + wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) { + /* Current SSID is not using IEEE 802.1X/EAP, so drop possible + * EAPOL frames (mainly, EAPOL-Start) from EAPOL state + * machines. */ + wpa_printf(MSG_DEBUG, "WPA: drop TX EAPOL in non-IEEE 802.1X " + "mode (type=%d len=%lu)", type, + (unsigned long) len); + return -1; + } + + if (pmksa_cache_get_current(wpa_s->wpa) && + type == IEEE802_1X_TYPE_EAPOL_START) { + /* Trying to use PMKSA caching - do not send EAPOL-Start frames + * since they will trigger full EAPOL authentication. */ + wpa_printf(MSG_DEBUG, "RSN: PMKSA caching - do not send " + "EAPOL-Start"); + return -1; + } + + if (is_zero_ether_addr(wpa_s->bssid)) { + wpa_printf(MSG_DEBUG, "BSSID not set when trying to send an " + "EAPOL frame"); + if (wpa_drv_get_bssid(wpa_s, bssid) == 0 && + !is_zero_ether_addr(bssid)) { + dst = bssid; + wpa_printf(MSG_DEBUG, "Using current BSSID " MACSTR + " from the driver as the EAPOL destination", + MAC2STR(dst)); + } else { + dst = wpa_s->last_eapol_src; + wpa_printf(MSG_DEBUG, "Using the source address of the" + " last received EAPOL frame " MACSTR " as " + "the EAPOL destination", + MAC2STR(dst)); + } + } else { + /* BSSID was already set (from (Re)Assoc event, so use it as + * the EAPOL destination. */ + dst = wpa_s->bssid; + } + + msg = wpa_alloc_eapol(wpa_s, type, buf, len, &msglen, NULL); + if (msg == NULL) + return -1; + + wpa_printf(MSG_DEBUG, "TX EAPOL: dst=" MACSTR, MAC2STR(dst)); + wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", msg, msglen); + res = wpa_ether_send(wpa_s, dst, ETH_P_EAPOL, msg, msglen); + os_free(msg); + return res; +} + + +/** + * wpa_eapol_set_wep_key - set WEP key for the driver + * @ctx: Pointer to wpa_supplicant data (wpa_s) + * @unicast: 1 = individual unicast key, 0 = broadcast key + * @keyidx: WEP key index (0..3) + * @key: Pointer to key data + * @keylen: Key length in bytes + * Returns: 0 on success or < 0 on error. + */ +static int wpa_eapol_set_wep_key(void *ctx, int unicast, int keyidx, + const u8 *key, size_t keylen) +{ + struct wpa_supplicant *wpa_s = ctx; + if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { + int cipher = (keylen == 5) ? WPA_CIPHER_WEP40 : + WPA_CIPHER_WEP104; + if (unicast) + wpa_s->pairwise_cipher = cipher; + else + wpa_s->group_cipher = cipher; + } + return wpa_drv_set_key(wpa_s, WPA_ALG_WEP, + unicast ? wpa_s->bssid : + (u8 *) "\xff\xff\xff\xff\xff\xff", + keyidx, unicast, (u8 *) "", 0, key, keylen); +} + + +static void wpa_supplicant_aborted_cached(void *ctx) +{ + struct wpa_supplicant *wpa_s = ctx; + wpa_sm_aborted_cached(wpa_s->wpa); +} + + +static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, int success, + void *ctx) +{ + struct wpa_supplicant *wpa_s = ctx; + int res, pmk_len; + u8 pmk[PMK_LEN]; + + wpa_printf(MSG_DEBUG, "EAPOL authentication completed %ssuccessfully", + success ? "" : "un"); + + if (wpas_wps_eapol_cb(wpa_s) > 0) + return; + + if (!success) { + /* + * Make sure we do not get stuck here waiting for long EAPOL + * timeout if the AP does not disconnect in case of + * authentication failure. + */ + wpa_supplicant_req_auth_timeout(wpa_s, 2, 0); + } + + if (!success || !wpa_s->driver_4way_handshake) + return; + + if (!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) + return; + + wpa_printf(MSG_DEBUG, "Configure PMK for driver-based RSN 4-way " + "handshake"); + + pmk_len = PMK_LEN; + res = eapol_sm_get_key(eapol, pmk, PMK_LEN); + if (res) { + /* + * EAP-LEAP is an exception from other EAP methods: it + * uses only 16-byte PMK. + */ + res = eapol_sm_get_key(eapol, pmk, 16); + pmk_len = 16; + } + + if (res) { + wpa_printf(MSG_DEBUG, "Failed to get PMK from EAPOL state " + "machines"); + return; + } + + if (wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0, NULL, 0, pmk, + pmk_len)) { + wpa_printf(MSG_DEBUG, "Failed to set PMK to the driver"); + } + + wpa_supplicant_cancel_scan(wpa_s); + wpa_supplicant_cancel_auth_timeout(wpa_s); + wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); + +} + + +static void wpa_supplicant_notify_eapol_done(void *ctx) +{ + struct wpa_supplicant *wpa_s = ctx; + wpa_msg(wpa_s, MSG_DEBUG, "WPA: EAPOL processing complete"); + if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) { + wpa_supplicant_set_state(wpa_s, WPA_4WAY_HANDSHAKE); + } else { + wpa_supplicant_cancel_auth_timeout(wpa_s); + wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); + } +} + +#endif /* IEEE8021X_EAPOL */ + + +#ifndef CONFIG_NO_WPA + +static int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s) +{ + size_t i; + int ret = 0; + struct wpa_scan_res *curr = NULL; + struct wpa_ssid *ssid = wpa_s->current_ssid; + const u8 *ie; + + if (wpa_s->scan_res == NULL) + return -1; + + for (i = 0; i < wpa_s->scan_res->num; i++) { + struct wpa_scan_res *r = wpa_s->scan_res->res[i]; + if (os_memcmp(r->bssid, wpa_s->bssid, ETH_ALEN) != 0) + continue; + ie = wpa_scan_get_ie(r, WLAN_EID_SSID); + if (ssid == NULL || + ((ie && ie[1] == ssid->ssid_len && + os_memcmp(ie + 2, ssid->ssid, ssid->ssid_len) == 0) || + ssid->ssid_len == 0)) { + curr = r; + break; + } + } + + if (curr) { + ie = wpa_scan_get_vendor_ie(curr, WPA_IE_VENDOR_TYPE); + if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0)) + ret = -1; + + ie = wpa_scan_get_ie(curr, WLAN_EID_RSN); + if (wpa_sm_set_ap_rsn_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0)) + ret = -1; + } else { + ret = -1; + } + + return ret; +} + + +static int wpa_supplicant_get_beacon_ie(void *ctx) +{ + struct wpa_supplicant *wpa_s = ctx; + if (wpa_get_beacon_ie(wpa_s) == 0) { + return 0; + } + + /* No WPA/RSN IE found in the cached scan results. Try to get updated + * scan results from the driver. */ + if (wpa_supplicant_get_scan_results(wpa_s) < 0) { + return -1; + } + + return wpa_get_beacon_ie(wpa_s); +} + + +static u8 * _wpa_alloc_eapol(void *wpa_s, u8 type, + const void *data, u16 data_len, + size_t *msg_len, void **data_pos) +{ + return wpa_alloc_eapol(wpa_s, type, data, data_len, msg_len, data_pos); +} + + +static int _wpa_ether_send(void *wpa_s, const u8 *dest, u16 proto, + const u8 *buf, size_t len) +{ + return wpa_ether_send(wpa_s, dest, proto, buf, len); +} + + +static void _wpa_supplicant_cancel_auth_timeout(void *wpa_s) +{ + wpa_supplicant_cancel_auth_timeout(wpa_s); +} + + +static void _wpa_supplicant_set_state(void *wpa_s, wpa_states state) +{ + wpa_supplicant_set_state(wpa_s, state); +} + + +/** + * wpa_supplicant_get_state - Get the connection state + * @wpa_s: Pointer to wpa_supplicant data + * Returns: The current connection state (WPA_*) + */ +static wpa_states wpa_supplicant_get_state(struct wpa_supplicant *wpa_s) +{ + return wpa_s->wpa_state; +} + + +static wpa_states _wpa_supplicant_get_state(void *wpa_s) +{ + return wpa_supplicant_get_state(wpa_s); +} + + +static void _wpa_supplicant_disassociate(void *wpa_s, int reason_code) +{ + wpa_supplicant_disassociate(wpa_s, reason_code); + /* Schedule a scan to make sure we continue looking for networks */ + wpa_supplicant_req_scan(wpa_s, 0, 0); +} + + +static void _wpa_supplicant_deauthenticate(void *wpa_s, int reason_code) +{ + wpa_supplicant_deauthenticate(wpa_s, reason_code); + /* Schedule a scan to make sure we continue looking for networks */ + wpa_supplicant_req_scan(wpa_s, 0, 0); +} + + +static void * wpa_supplicant_get_network_ctx(void *wpa_s) +{ + return wpa_supplicant_get_ssid(wpa_s); +} + + +static int wpa_supplicant_get_bssid(void *ctx, u8 *bssid) +{ + struct wpa_supplicant *wpa_s = ctx; + if (wpa_s->use_client_mlme) { + os_memcpy(bssid, wpa_s->bssid, ETH_ALEN); + return 0; + } + return wpa_drv_get_bssid(wpa_s, bssid); +} + + +static int wpa_supplicant_set_key(void *_wpa_s, 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_supplicant *wpa_s = _wpa_s; + if (alg == WPA_ALG_TKIP && key_idx == 0 && key_len == 32) { + /* Clear the MIC error counter when setting a new PTK. */ + wpa_s->mic_errors_seen = 0; + } + return wpa_drv_set_key(wpa_s, alg, addr, key_idx, set_tx, seq, seq_len, + key, key_len); +} + + +static int wpa_supplicant_mlme_setprotection(void *wpa_s, const u8 *addr, + int protection_type, + int key_type) +{ + return wpa_drv_mlme_setprotection(wpa_s, addr, protection_type, + key_type); +} + + +static int wpa_supplicant_add_pmkid(void *wpa_s, + const u8 *bssid, const u8 *pmkid) +{ + return wpa_drv_add_pmkid(wpa_s, bssid, pmkid); +} + + +static int wpa_supplicant_remove_pmkid(void *wpa_s, + const u8 *bssid, const u8 *pmkid) +{ + return wpa_drv_remove_pmkid(wpa_s, bssid, pmkid); +} + + +#ifdef CONFIG_IEEE80211R +static int wpa_supplicant_update_ft_ies(void *ctx, const u8 *md, + const u8 *ies, size_t ies_len) +{ + struct wpa_supplicant *wpa_s = ctx; + if (wpa_s->use_client_mlme) + return ieee80211_sta_update_ft_ies(wpa_s, md, ies, ies_len); + return wpa_drv_update_ft_ies(wpa_s, md, ies, ies_len); +} + + +static int wpa_supplicant_send_ft_action(void *ctx, u8 action, + const u8 *target_ap, + const u8 *ies, size_t ies_len) +{ + struct wpa_supplicant *wpa_s = ctx; + if (wpa_s->use_client_mlme) + return ieee80211_sta_send_ft_action(wpa_s, action, target_ap, + ies, ies_len); + return wpa_drv_send_ft_action(wpa_s, action, target_ap, ies, ies_len); +} +#endif /* CONFIG_IEEE80211R */ + +#endif /* CONFIG_NO_WPA */ + + +#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) +static void wpa_supplicant_eap_param_needed(void *ctx, const char *field, + const char *txt) +{ + struct wpa_supplicant *wpa_s = ctx; + struct wpa_ssid *ssid = wpa_s->current_ssid; + char *buf; + size_t buflen; + int len; + + if (ssid == NULL) + return; + + buflen = 100 + os_strlen(txt) + ssid->ssid_len; + buf = os_malloc(buflen); + if (buf == NULL) + return; + len = os_snprintf(buf, buflen, + WPA_CTRL_REQ "%s-%d:%s needed for SSID ", + field, ssid->id, txt); + if (len < 0 || (size_t) len >= buflen) { + os_free(buf); + return; + } + if (ssid->ssid && buflen > len + ssid->ssid_len) { + os_memcpy(buf + len, ssid->ssid, ssid->ssid_len); + len += ssid->ssid_len; + buf[len] = '\0'; + } + buf[buflen - 1] = '\0'; + wpa_msg(wpa_s, MSG_INFO, "%s", buf); + os_free(buf); +} +#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ +#define wpa_supplicant_eap_param_needed NULL +#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ + + +int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s) +{ +#ifdef IEEE8021X_EAPOL + struct eapol_ctx *ctx; + ctx = os_zalloc(sizeof(*ctx)); + if (ctx == NULL) { + wpa_printf(MSG_ERROR, "Failed to allocate EAPOL context."); + return -1; + } + + ctx->ctx = wpa_s; + ctx->msg_ctx = wpa_s; + ctx->eapol_send_ctx = wpa_s; + ctx->preauth = 0; + ctx->eapol_done_cb = wpa_supplicant_notify_eapol_done; + ctx->eapol_send = wpa_supplicant_eapol_send; + ctx->set_wep_key = wpa_eapol_set_wep_key; + ctx->set_config_blob = wpa_supplicant_set_config_blob; + ctx->get_config_blob = wpa_supplicant_get_config_blob; + ctx->aborted_cached = wpa_supplicant_aborted_cached; +#ifdef EAP_TLS_OPENSSL + ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path; + ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path; + ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path; +#endif /* EAP_TLS_OPENSSL */ + ctx->wps = wpa_s->wps; + ctx->eap_param_needed = wpa_supplicant_eap_param_needed; + ctx->cb = wpa_supplicant_eapol_cb; + ctx->cb_ctx = wpa_s; + wpa_s->eapol = eapol_sm_init(ctx); + if (wpa_s->eapol == NULL) { + os_free(ctx); + wpa_printf(MSG_ERROR, "Failed to initialize EAPOL state " + "machines."); + return -1; + } +#endif /* IEEE8021X_EAPOL */ + + return 0; +} + + +int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s) +{ +#ifndef CONFIG_NO_WPA + struct wpa_sm_ctx *ctx; + ctx = os_zalloc(sizeof(*ctx)); + if (ctx == NULL) { + wpa_printf(MSG_ERROR, "Failed to allocate WPA context."); + return -1; + } + + ctx->ctx = wpa_s; + ctx->set_state = _wpa_supplicant_set_state; + ctx->get_state = _wpa_supplicant_get_state; + ctx->deauthenticate = _wpa_supplicant_deauthenticate; + ctx->disassociate = _wpa_supplicant_disassociate; + ctx->set_key = wpa_supplicant_set_key; + ctx->get_network_ctx = wpa_supplicant_get_network_ctx; + ctx->get_bssid = wpa_supplicant_get_bssid; + ctx->ether_send = _wpa_ether_send; + ctx->get_beacon_ie = wpa_supplicant_get_beacon_ie; + ctx->alloc_eapol = _wpa_alloc_eapol; + ctx->cancel_auth_timeout = _wpa_supplicant_cancel_auth_timeout; + ctx->add_pmkid = wpa_supplicant_add_pmkid; + ctx->remove_pmkid = wpa_supplicant_remove_pmkid; +#ifndef CONFIG_NO_CONFIG_BLOBS + ctx->set_config_blob = wpa_supplicant_set_config_blob; + ctx->get_config_blob = wpa_supplicant_get_config_blob; +#endif /* CONFIG_NO_CONFIG_BLOBS */ + ctx->mlme_setprotection = wpa_supplicant_mlme_setprotection; +#ifdef CONFIG_IEEE80211R + ctx->update_ft_ies = wpa_supplicant_update_ft_ies; + ctx->send_ft_action = wpa_supplicant_send_ft_action; +#endif /* CONFIG_IEEE80211R */ + + wpa_s->wpa = wpa_sm_init(ctx); + if (wpa_s->wpa == NULL) { + wpa_printf(MSG_ERROR, "Failed to initialize WPA state " + "machine"); + return -1; + } +#endif /* CONFIG_NO_WPA */ + + return 0; +} + + +void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + struct rsn_supp_config conf; + if (ssid) { + os_memset(&conf, 0, sizeof(conf)); + conf.network_ctx = ssid; + conf.peerkey_enabled = ssid->peerkey; + conf.allowed_pairwise_cipher = ssid->pairwise_cipher; +#ifdef IEEE8021X_EAPOL + conf.eap_workaround = ssid->eap_workaround; + conf.eap_conf_ctx = &ssid->eap; +#endif /* IEEE8021X_EAPOL */ + conf.ssid = ssid->ssid; + conf.ssid_len = ssid->ssid_len; + conf.wpa_ptk_rekey = ssid->wpa_ptk_rekey; + } + wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL); +} diff --git a/wpa_supplicant/wpas_glue.h b/wpa_supplicant/wpas_glue.h new file mode 100644 index 000000000000..b571e4df1714 --- /dev/null +++ b/wpa_supplicant/wpas_glue.h @@ -0,0 +1,23 @@ +/* + * WPA Supplicant - Glue code to setup EAPOL and RSN modules + * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef WPAS_GLUE_H +#define WPAS_GLUE_H + +int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s); +int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s); +void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid); + +#endif /* WPAS_GLUE_H */ diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c new file mode 100644 index 000000000000..9b7360176259 --- /dev/null +++ b/wpa_supplicant/wps_supplicant.c @@ -0,0 +1,770 @@ +/* + * wpa_supplicant / WPS integration + * Copyright (c) 2008, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "ieee802_11_defs.h" +#include "wpa_common.h" +#include "config.h" +#include "eap_peer/eap.h" +#include "wpa_supplicant_i.h" +#include "eloop.h" +#include "uuid.h" +#include "wpa_ctrl.h" +#include "ctrl_iface_dbus.h" +#include "eap_common/eap_wsc_common.h" +#include "blacklist.h" +#include "wps_supplicant.h" + +#define WPS_PIN_SCAN_IGNORE_SEL_REG 3 + +static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx); +static void wpas_clear_wps(struct wpa_supplicant *wpa_s); + + +int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s) +{ + if (!wpa_s->wps_success && + wpa_s->current_ssid && + eap_is_wps_pin_enrollee(&wpa_s->current_ssid->eap)) { + const u8 *bssid = wpa_s->bssid; + if (is_zero_ether_addr(bssid)) + bssid = wpa_s->pending_bssid; + + wpa_printf(MSG_DEBUG, "WPS: PIN registration with " MACSTR + " did not succeed - continue trying to find " + "suitable AP", MAC2STR(bssid)); + wpa_blacklist_add(wpa_s, bssid); + + wpa_supplicant_deauthenticate(wpa_s, + WLAN_REASON_DEAUTH_LEAVING); + wpa_s->reassociate = 1; + wpa_supplicant_req_scan(wpa_s, + wpa_s->blacklist_cleared ? 5 : 0, 0); + wpa_s->blacklist_cleared = 0; + return 1; + } + + eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL); + + if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid && + !(wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS)) { + wpa_printf(MSG_DEBUG, "WPS: Network configuration replaced - " + "try to associate with the received credential"); + wpa_supplicant_deauthenticate(wpa_s, + WLAN_REASON_DEAUTH_LEAVING); + wpa_s->reassociate = 1; + wpa_supplicant_req_scan(wpa_s, 0, 0); + return 1; + } + + if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid) { + wpa_printf(MSG_DEBUG, "WPS: Registration completed - waiting " + "for external credential processing"); + wpas_clear_wps(wpa_s); + wpa_supplicant_deauthenticate(wpa_s, + WLAN_REASON_DEAUTH_LEAVING); + return 1; + } + + return 0; +} + + +static int wpa_supplicant_wps_cred(void *ctx, + const struct wps_credential *cred) +{ + struct wpa_supplicant *wpa_s = ctx; + struct wpa_ssid *ssid = wpa_s->current_ssid; + + if ((wpa_s->conf->wps_cred_processing == 1 || + wpa_s->conf->wps_cred_processing == 2) && cred->cred_attr) { + size_t blen = cred->cred_attr_len * 2 + 1; + char *buf = os_malloc(blen); + if (buf) { + wpa_snprintf_hex(buf, blen, + cred->cred_attr, cred->cred_attr_len); + wpa_msg(wpa_s, MSG_INFO, "%s%s", + WPS_EVENT_CRED_RECEIVED, buf); + os_free(buf); + } + wpa_supplicant_dbus_notify_wps_cred(wpa_s, cred); + } else + wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_CRED_RECEIVED); + + wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute", + cred->cred_attr, cred->cred_attr_len); + + if (wpa_s->conf->wps_cred_processing == 1) + return 0; + + if (cred->auth_type != WPS_AUTH_OPEN && + cred->auth_type != WPS_AUTH_SHARED && + cred->auth_type != WPS_AUTH_WPAPSK && + cred->auth_type != WPS_AUTH_WPA2PSK) { + wpa_printf(MSG_DEBUG, "WPS: Ignored credentials for " + "unsupported authentication type %d", + cred->auth_type); + return 0; + } + + if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) { + wpa_printf(MSG_DEBUG, "WPS: Replace WPS network block based " + "on the received credential"); + os_free(ssid->eap.identity); + ssid->eap.identity = NULL; + ssid->eap.identity_len = 0; + os_free(ssid->eap.phase1); + ssid->eap.phase1 = NULL; + os_free(ssid->eap.eap_methods); + ssid->eap.eap_methods = NULL; + } else { + wpa_printf(MSG_DEBUG, "WPS: Create a new network based on the " + "received credential"); + ssid = wpa_config_add_network(wpa_s->conf); + if (ssid == NULL) + return -1; + } + + wpa_config_set_network_defaults(ssid); + + os_free(ssid->ssid); + ssid->ssid = os_malloc(cred->ssid_len); + if (ssid->ssid) { + os_memcpy(ssid->ssid, cred->ssid, cred->ssid_len); + ssid->ssid_len = cred->ssid_len; + } + + switch (cred->encr_type) { + case WPS_ENCR_NONE: + break; + case WPS_ENCR_WEP: + if (cred->key_len > 0 && cred->key_len <= MAX_WEP_KEY_LEN && + cred->key_idx < NUM_WEP_KEYS) { + os_memcpy(ssid->wep_key[cred->key_idx], cred->key, + cred->key_len); + ssid->wep_key_len[cred->key_idx] = cred->key_len; + ssid->wep_tx_keyidx = cred->key_idx; + } + break; + case WPS_ENCR_TKIP: + ssid->pairwise_cipher = WPA_CIPHER_TKIP; + break; + case WPS_ENCR_AES: + ssid->pairwise_cipher = WPA_CIPHER_CCMP; + break; + } + + switch (cred->auth_type) { + case WPS_AUTH_OPEN: + ssid->auth_alg = WPA_AUTH_ALG_OPEN; + ssid->key_mgmt = WPA_KEY_MGMT_NONE; + ssid->proto = 0; + break; + case WPS_AUTH_SHARED: + ssid->auth_alg = WPA_AUTH_ALG_SHARED; + ssid->key_mgmt = WPA_KEY_MGMT_NONE; + ssid->proto = 0; + break; + case WPS_AUTH_WPAPSK: + ssid->auth_alg = WPA_AUTH_ALG_OPEN; + ssid->key_mgmt = WPA_KEY_MGMT_PSK; + ssid->proto = WPA_PROTO_WPA; + break; + case WPS_AUTH_WPA: + ssid->auth_alg = WPA_AUTH_ALG_OPEN; + ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X; + ssid->proto = WPA_PROTO_WPA; + break; + case WPS_AUTH_WPA2: + ssid->auth_alg = WPA_AUTH_ALG_OPEN; + ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X; + ssid->proto = WPA_PROTO_RSN; + break; + case WPS_AUTH_WPA2PSK: + ssid->auth_alg = WPA_AUTH_ALG_OPEN; + ssid->key_mgmt = WPA_KEY_MGMT_PSK; + ssid->proto = WPA_PROTO_RSN; + break; + } + + if (ssid->key_mgmt == WPA_KEY_MGMT_PSK) { + if (cred->key_len == 2 * PMK_LEN) { + if (hexstr2bin((const char *) cred->key, ssid->psk, + PMK_LEN)) { + wpa_printf(MSG_ERROR, "WPS: Invalid Network " + "Key"); + return -1; + } + ssid->psk_set = 1; + } else if (cred->key_len >= 8 && cred->key_len < 2 * PMK_LEN) { + os_free(ssid->passphrase); + ssid->passphrase = os_malloc(cred->key_len + 1); + if (ssid->passphrase == NULL) + return -1; + os_memcpy(ssid->passphrase, cred->key, cred->key_len); + ssid->passphrase[cred->key_len] = '\0'; + wpa_config_update_psk(ssid); + } else { + wpa_printf(MSG_ERROR, "WPS: Invalid Network Key " + "length %lu", + (unsigned long) cred->key_len); + return -1; + } + } + +#ifndef CONFIG_NO_CONFIG_WRITE + if (wpa_s->conf->update_config && + wpa_config_write(wpa_s->confname, wpa_s->conf)) { + wpa_printf(MSG_DEBUG, "WPS: Failed to update configuration"); + return -1; + } +#endif /* CONFIG_NO_CONFIG_WRITE */ + + return 0; +} + + +static void wpa_supplicant_wps_event_m2d(struct wpa_supplicant *wpa_s, + struct wps_event_m2d *m2d) +{ + wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_M2D + "dev_password_id=%d config_error=%d", + m2d->dev_password_id, m2d->config_error); +} + + +static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s, + struct wps_event_fail *fail) +{ + wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_FAIL "msg=%d", fail->msg); + wpas_clear_wps(wpa_s); +} + + +static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s) +{ + wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_SUCCESS); + wpa_s->wps_success = 1; +} + + +static void wpa_supplicant_wps_event(void *ctx, enum wps_event event, + union wps_event_data *data) +{ + struct wpa_supplicant *wpa_s = ctx; + switch (event) { + case WPS_EV_M2D: + wpa_supplicant_wps_event_m2d(wpa_s, &data->m2d); + break; + case WPS_EV_FAIL: + wpa_supplicant_wps_event_fail(wpa_s, &data->fail); + break; + case WPS_EV_SUCCESS: + wpa_supplicant_wps_event_success(wpa_s); + break; + case WPS_EV_PWD_AUTH_FAIL: + break; + } +} + + +enum wps_request_type wpas_wps_get_req_type(struct wpa_ssid *ssid) +{ + if (eap_is_wps_pbc_enrollee(&ssid->eap) || + eap_is_wps_pin_enrollee(&ssid->eap)) + return WPS_REQ_ENROLLEE; + else + return WPS_REQ_REGISTRAR; +} + + +static void wpas_clear_wps(struct wpa_supplicant *wpa_s) +{ + int id; + struct wpa_ssid *ssid; + + eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL); + + /* Remove any existing WPS network from configuration */ + ssid = wpa_s->conf->ssid; + while (ssid) { + if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) { + if (ssid == wpa_s->current_ssid) + wpa_s->current_ssid = NULL; + id = ssid->id; + } else + id = -1; + ssid = ssid->next; + if (id >= 0) + wpa_config_remove_network(wpa_s->conf, id); + } +} + + +static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + wpa_printf(MSG_INFO, WPS_EVENT_TIMEOUT "Requested operation timed " + "out"); + wpas_clear_wps(wpa_s); +} + + +static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s, + int registrar, const u8 *bssid) +{ + struct wpa_ssid *ssid; + + ssid = wpa_config_add_network(wpa_s->conf); + if (ssid == NULL) + return NULL; + wpa_config_set_network_defaults(ssid); + if (wpa_config_set(ssid, "key_mgmt", "WPS", 0) < 0 || + wpa_config_set(ssid, "eap", "WSC", 0) < 0 || + wpa_config_set(ssid, "identity", registrar ? + "\"" WSC_ID_REGISTRAR "\"" : + "\"" WSC_ID_ENROLLEE "\"", 0) < 0) { + wpa_config_remove_network(wpa_s->conf, ssid->id); + return NULL; + } + + if (bssid) { + size_t i; + struct wpa_scan_res *res; + + os_memcpy(ssid->bssid, bssid, ETH_ALEN); + ssid->bssid_set = 1; + + /* Try to get SSID from scan results */ + if (wpa_s->scan_res == NULL && + wpa_supplicant_get_scan_results(wpa_s) < 0) + return ssid; /* Could not find any scan results */ + + for (i = 0; i < wpa_s->scan_res->num; i++) { + const u8 *ie; + + res = wpa_s->scan_res->res[i]; + if (os_memcmp(bssid, res->bssid, ETH_ALEN) != 0) + continue; + + ie = wpa_scan_get_ie(res, WLAN_EID_SSID); + if (ie == NULL) + break; + os_free(ssid->ssid); + ssid->ssid = os_malloc(ie[1]); + if (ssid->ssid == NULL) + break; + os_memcpy(ssid->ssid, ie + 2, ie[1]); + ssid->ssid_len = ie[1]; + break; + } + } + + return ssid; +} + + +static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s, + struct wpa_ssid *selected) +{ + struct wpa_ssid *ssid; + + /* Mark all other networks disabled and trigger reassociation */ + ssid = wpa_s->conf->ssid; + while (ssid) { + ssid->disabled = ssid != selected; + ssid = ssid->next; + } + wpa_s->disconnected = 0; + wpa_s->reassociate = 1; + wpa_s->scan_runs = 0; + wpa_s->wps_success = 0; + wpa_s->blacklist_cleared = 0; + wpa_supplicant_req_scan(wpa_s, 0, 0); +} + + +int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid) +{ + struct wpa_ssid *ssid; + wpas_clear_wps(wpa_s); + ssid = wpas_wps_add_network(wpa_s, 0, bssid); + if (ssid == NULL) + return -1; + wpa_config_set(ssid, "phase1", "\"pbc=1\"", 0); + eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout, + wpa_s, NULL); + wpas_wps_reassoc(wpa_s, ssid); + return 0; +} + + +int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid, + const char *pin) +{ + struct wpa_ssid *ssid; + char val[30]; + unsigned int rpin = 0; + + wpas_clear_wps(wpa_s); + ssid = wpas_wps_add_network(wpa_s, 0, bssid); + if (ssid == NULL) + return -1; + if (pin) + os_snprintf(val, sizeof(val), "\"pin=%s\"", pin); + else { + rpin = wps_generate_pin(); + os_snprintf(val, sizeof(val), "\"pin=%08d\"", rpin); + } + wpa_config_set(ssid, "phase1", val, 0); + eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout, + wpa_s, NULL); + wpas_wps_reassoc(wpa_s, ssid); + return rpin; +} + + +int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid, + const char *pin) +{ + struct wpa_ssid *ssid; + char val[30]; + + if (!pin) + return -1; + wpas_clear_wps(wpa_s); + ssid = wpas_wps_add_network(wpa_s, 1, bssid); + if (ssid == NULL) + return -1; + os_snprintf(val, sizeof(val), "\"pin=%s\"", pin); + wpa_config_set(ssid, "phase1", val, 0); + eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout, + wpa_s, NULL); + wpas_wps_reassoc(wpa_s, ssid); + return 0; +} + + +static int wpas_wps_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *psk, + size_t psk_len) +{ + wpa_printf(MSG_DEBUG, "WPS: Received new WPA/WPA2-PSK from WPS for " + "STA " MACSTR, MAC2STR(mac_addr)); + wpa_hexdump_key(MSG_DEBUG, "Per-device PSK", psk, psk_len); + + /* TODO */ + + return 0; +} + + +static void wpas_wps_pin_needed_cb(void *ctx, const u8 *uuid_e, + const struct wps_device_data *dev) +{ + char uuid[40], txt[400]; + int len; + if (uuid_bin2str(uuid_e, uuid, sizeof(uuid))) + return; + wpa_printf(MSG_DEBUG, "WPS: PIN needed for UUID-E %s", uuid); + len = os_snprintf(txt, sizeof(txt), "WPS-EVENT-PIN-NEEDED %s " MACSTR + " [%s|%s|%s|%s|%s|%d-%08X-%d]", + uuid, MAC2STR(dev->mac_addr), dev->device_name, + dev->manufacturer, dev->model_name, + dev->model_number, dev->serial_number, + dev->categ, dev->oui, dev->sub_categ); + if (len > 0 && len < (int) sizeof(txt)) + wpa_printf(MSG_INFO, "%s", txt); +} + + +int wpas_wps_init(struct wpa_supplicant *wpa_s) +{ + struct wps_context *wps; + struct wps_registrar_config rcfg; + + wps = os_zalloc(sizeof(*wps)); + if (wps == NULL) + return -1; + + wps->cred_cb = wpa_supplicant_wps_cred; + wps->event_cb = wpa_supplicant_wps_event; + wps->cb_ctx = wpa_s; + + wps->dev.device_name = wpa_s->conf->device_name; + wps->dev.manufacturer = wpa_s->conf->manufacturer; + wps->dev.model_name = wpa_s->conf->model_name; + wps->dev.model_number = wpa_s->conf->model_number; + wps->dev.serial_number = wpa_s->conf->serial_number; + if (wpa_s->conf->device_type) { + char *pos; + u8 oui[4]; + /* <categ>-<OUI>-<subcateg> */ + wps->dev.categ = atoi(wpa_s->conf->device_type); + pos = os_strchr(wpa_s->conf->device_type, '-'); + if (pos == NULL) { + wpa_printf(MSG_ERROR, "WPS: Invalid device_type"); + os_free(wps); + return -1; + } + pos++; + if (hexstr2bin(pos, oui, 4)) { + wpa_printf(MSG_ERROR, "WPS: Invalid device_type OUI"); + os_free(wps); + return -1; + } + wps->dev.oui = WPA_GET_BE32(oui); + pos = os_strchr(pos, '-'); + if (pos == NULL) { + wpa_printf(MSG_ERROR, "WPS: Invalid device_type"); + os_free(wps); + return -1; + } + pos++; + wps->dev.sub_categ = atoi(pos); + } + wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version); + wps->dev.rf_bands = WPS_RF_24GHZ | WPS_RF_50GHZ; /* TODO: config */ + os_memcpy(wps->dev.mac_addr, wpa_s->own_addr, ETH_ALEN); + if (is_nil_uuid(wpa_s->conf->uuid)) { + uuid_gen_mac_addr(wpa_s->own_addr, wps->uuid); + wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC address", + wps->uuid, WPS_UUID_LEN); + } else + os_memcpy(wps->uuid, wpa_s->conf->uuid, WPS_UUID_LEN); + + wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK; + wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP; + + os_memset(&rcfg, 0, sizeof(rcfg)); + rcfg.new_psk_cb = wpas_wps_new_psk_cb; + rcfg.pin_needed_cb = wpas_wps_pin_needed_cb; + rcfg.cb_ctx = wpa_s; + + wps->registrar = wps_registrar_init(wps, &rcfg); + if (wps->registrar == NULL) { + wpa_printf(MSG_DEBUG, "Failed to initialize WPS Registrar"); + os_free(wps); + return -1; + } + + wpa_s->wps = wps; + + return 0; +} + + +void wpas_wps_deinit(struct wpa_supplicant *wpa_s) +{ + eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL); + + if (wpa_s->wps == NULL) + return; + + wps_registrar_deinit(wpa_s->wps->registrar); + os_free(wpa_s->wps->network_key); + os_free(wpa_s->wps); + wpa_s->wps = NULL; +} + + +int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, struct wpa_scan_res *bss) +{ + struct wpabuf *wps_ie; + + if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS)) + return -1; + + wps_ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); + if (eap_is_wps_pbc_enrollee(&ssid->eap)) { + if (!wps_ie) { + wpa_printf(MSG_DEBUG, " skip - non-WPS AP"); + return 0; + } + + if (!wps_is_selected_pbc_registrar(wps_ie)) { + wpa_printf(MSG_DEBUG, " skip - WPS AP " + "without active PBC Registrar"); + wpabuf_free(wps_ie); + return 0; + } + + /* TODO: overlap detection */ + wpa_printf(MSG_DEBUG, " selected based on WPS IE " + "(Active PBC)"); + wpabuf_free(wps_ie); + return 1; + } + + if (eap_is_wps_pin_enrollee(&ssid->eap)) { + if (!wps_ie) { + wpa_printf(MSG_DEBUG, " skip - non-WPS AP"); + return 0; + } + + /* + * Start with WPS APs that advertise active PIN Registrar and + * allow any WPS AP after third scan since some APs do not set + * Selected Registrar attribute properly when using external + * Registrar. + */ + if (!wps_is_selected_pin_registrar(wps_ie)) { + if (wpa_s->scan_runs < WPS_PIN_SCAN_IGNORE_SEL_REG) { + wpa_printf(MSG_DEBUG, " skip - WPS AP " + "without active PIN Registrar"); + wpabuf_free(wps_ie); + return 0; + } + wpa_printf(MSG_DEBUG, " selected based on WPS IE"); + } else { + wpa_printf(MSG_DEBUG, " selected based on WPS IE " + "(Active PIN)"); + } + wpabuf_free(wps_ie); + return 1; + } + + if (wps_ie) { + wpa_printf(MSG_DEBUG, " selected based on WPS IE"); + wpabuf_free(wps_ie); + return 1; + } + + return -1; +} + + +int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, + struct wpa_scan_res *bss) +{ + struct wpabuf *wps_ie = NULL; + int ret = 0; + + if (eap_is_wps_pbc_enrollee(&ssid->eap)) { + wps_ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); + if (wps_ie && wps_is_selected_pbc_registrar(wps_ie)) { + /* allow wildcard SSID for WPS PBC */ + ret = 1; + } + } else if (eap_is_wps_pin_enrollee(&ssid->eap)) { + wps_ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); + if (wps_ie && + (wps_is_selected_pin_registrar(wps_ie) || + wpa_s->scan_runs >= WPS_PIN_SCAN_IGNORE_SEL_REG)) { + /* allow wildcard SSID for WPS PIN */ + ret = 1; + } + } + + if (!ret && ssid->bssid_set && + os_memcmp(ssid->bssid, bss->bssid, ETH_ALEN) == 0) { + /* allow wildcard SSID due to hardcoded BSSID match */ + ret = 1; + } + + wpabuf_free(wps_ie); + + return ret; +} + + +int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s, + struct wpa_scan_res *selected, + struct wpa_ssid *ssid) +{ + const u8 *sel_uuid, *uuid; + size_t i; + struct wpabuf *wps_ie; + int ret = 0; + + if (!eap_is_wps_pbc_enrollee(&ssid->eap)) + return 0; + + /* Make sure that only one AP is in active PBC mode */ + wps_ie = wpa_scan_get_vendor_ie_multi(selected, WPS_IE_VENDOR_TYPE); + if (wps_ie) + sel_uuid = wps_get_uuid_e(wps_ie); + else + sel_uuid = NULL; + + for (i = 0; i < wpa_s->scan_res->num; i++) { + struct wpa_scan_res *bss = wpa_s->scan_res->res[i]; + struct wpabuf *ie; + if (bss == selected) + continue; + ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); + if (!ie) + continue; + if (!wps_is_selected_pbc_registrar(ie)) { + wpabuf_free(ie); + continue; + } + uuid = wps_get_uuid_e(ie); + if (sel_uuid == NULL || uuid == NULL || + os_memcmp(sel_uuid, uuid, 16) != 0) { + ret = 1; /* PBC overlap */ + wpabuf_free(ie); + break; + } + + /* TODO: verify that this is reasonable dual-band situation */ + + wpabuf_free(ie); + } + + wpabuf_free(wps_ie); + + return ret; +} + + +void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s) +{ + size_t i; + + if (wpa_s->disconnected || wpa_s->wpa_state >= WPA_ASSOCIATED) + return; + + for (i = 0; i < wpa_s->scan_res->num; i++) { + struct wpa_scan_res *bss = wpa_s->scan_res->res[i]; + struct wpabuf *ie; + ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); + if (!ie) + continue; + if (wps_is_selected_pbc_registrar(ie)) + wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE_PBC); + else if (wps_is_selected_pin_registrar(ie)) + wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE_PIN); + else + wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE); + wpabuf_free(ie); + break; + } +} + + +int wpas_wps_searching(struct wpa_supplicant *wpa_s) +{ + struct wpa_ssid *ssid; + + for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { + if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && !ssid->disabled) + return 1; + } + + return 0; +} diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h new file mode 100644 index 000000000000..8f81dc4bda10 --- /dev/null +++ b/wpa_supplicant/wps_supplicant.h @@ -0,0 +1,95 @@ +/* + * wpa_supplicant / WPS integration + * Copyright (c) 2008, Jouni Malinen <j@w1.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef WPS_SUPPLICANT_H +#define WPS_SUPPLICANT_H + +#ifdef CONFIG_WPS + +#include "wps/wps.h" +#include "wps/wps_defs.h" + +int wpas_wps_init(struct wpa_supplicant *wpa_s); +void wpas_wps_deinit(struct wpa_supplicant *wpa_s); +int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s); +enum wps_request_type wpas_wps_get_req_type(struct wpa_ssid *ssid); +int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid); +int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid, + const char *pin); +int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid, + const char *pin); +int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, struct wpa_scan_res *bss); +int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, struct wpa_scan_res *bss); +int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s, + struct wpa_scan_res *selected, + struct wpa_ssid *ssid); +void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s); +int wpas_wps_searching(struct wpa_supplicant *wpa_s); + +#else /* CONFIG_WPS */ + +static inline int wpas_wps_init(struct wpa_supplicant *wpa_s) +{ + return 0; +} + +static inline void wpas_wps_deinit(struct wpa_supplicant *wpa_s) +{ +} + +static inline int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s) +{ + return 0; +} + +static inline u8 wpas_wps_get_req_type(struct wpa_ssid *ssid) +{ + return 0; +} + +static inline int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, + struct wpa_scan_res *bss) +{ + return -1; +} + +static inline int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, + struct wpa_scan_res *bss) +{ + return 0; +} + +static inline int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s, + struct wpa_scan_res *selected, + struct wpa_ssid *ssid) +{ + return 0; +} + +static inline void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s) +{ +} + +static inline int wpas_wps_searching(struct wpa_supplicant *wpa_s) +{ + return 0; +} + +#endif /* CONFIG_WPS */ + +#endif /* WPS_SUPPLICANT_H */ |