aboutsummaryrefslogtreecommitdiffstats
path: root/wpa_supplicant
diff options
context:
space:
mode:
authorRui Paulo <rpaulo@FreeBSD.org>2013-06-25 02:47:41 +0000
committerRui Paulo <rpaulo@FreeBSD.org>2013-06-25 02:47:41 +0000
commit5e2639d568f6bb660501a77cc83413c3412562e3 (patch)
treedb97ebf07cc76b41926fb6696433b541307fbc19 /wpa_supplicant
parent19f9885f6aafcd7c3eee4df8a014287d12279851 (diff)
downloadsrc-vendor/wpa/2.0.tar.gz
src-vendor/wpa/2.0.zip
Import wpa_supplicant / hostapd 2.0.vendor/wpa/2.0
2013-01-12 - v2.0 * added AP-STA-DISCONNECTED ctrl_iface event * improved debug logging (human readable event names, interface name included in more entries) * added number of small changes to make it easier for static analyzers to understand the implementation * added a workaround for Windows 7 Michael MIC failure reporting and use of the Secure bit in EAPOL-Key msg 3/4 * fixed number of small bugs (see git logs for more details) * changed OpenSSL to read full certificate chain from server_cert file * nl80211: number of updates to use new cfg80211/nl80211 functionality - replace monitor interface with nl80211 commands - additional information for driver-based AP SME * EAP-pwd: - fix KDF for group 21 and zero-padding - added support for fragmentation - increased maximum number of hunting-and-pecking iterations * avoid excessive Probe Response retries for broadcast Probe Request frames (only with drivers using hostapd SME/MLME) * added preliminary support for using TLS v1.2 (CONFIG_TLSV12=y) * fixed WPS operation stopping on dual concurrent AP * added wps_rf_bands configuration parameter for overriding RF Bands value for WPS * added support for getting per-device PSK from RADIUS Tunnel-Password * added support for libnl 3.2 and newer * increased initial group key handshake retransmit timeout to 500 ms * added a workaround for 4-way handshake to update SNonce even after having sent EAPOL-Key 3/4 to avoid issues with some supplicant implementations that can change SNonce for each EAP-Key 2/4 * added a workaround for EAPOL-Key 4/4 using incorrect type value in WPA2 mode (some deployed stations use WPA type in that message) * added a WPS workaround for mixed mode AP Settings with Windows 7 * changed WPS AP PIN disabling mechanism to disable the PIN after 10 consecutive failures in addition to using the exponential lockout period * added support for WFA Hotspot 2.0 - GAS/ANQP advertisement of network information - disable_dgaf parameter to disable downstream group-addressed forwarding * simplified licensing terms by selecting the BSD license as the only alternative * EAP-SIM: fixed re-authentication not to update pseudonym * EAP-SIM: use Notification round before EAP-Failure * EAP-AKA: added support for AT_COUNTER_TOO_SMALL * EAP-AKA: skip AKA/Identity exchange if EAP identity is recognized * EAP-AKA': fixed identity for MK derivation * EAP-AKA': updated to RFC 5448 (username prefixes changed); note: this breaks interoperability with older versions * EAP-SIM/AKA: allow pseudonym to be used after unknown reauth id * changed ANonce to be a random number instead of Counter-based * added support for canceling WPS operations with hostapd_cli wps_cancel * fixed EAP/WPS to PSK transition on reassociation in cases where deauthentication is missed * hlr_auc_gw enhancements: - a new command line parameter -u can be used to enable updating of SQN in Milenage file - use 5 bit IND for SQN updates - SQLite database can now be used to store Milenage information * EAP-SIM/AKA DB: added optional use of SQLite database for pseudonyms and reauth data * added support for Chargeable-User-Identity (RFC 4372) * added radius_auth_req_attr and radius_acct_req_attr configuration parameters to allow adding/overriding of RADIUS attributes in Access-Request and Accounting-Request packets * added support for RADIUS dynamic authorization server (RFC 5176) * added initial support for WNM operations - BSS max idle period - WNM-Sleep Mode * added new WPS NFC ctrl_iface mechanism - removed obsoleted WPS_OOB command (including support for deprecated UFD config_method) * added FT support for drivers that implement MLME internally * added SA Query support for drivers that implement MLME internally * removed default ACM=1 from AC_VO and AC_VI * changed VENDOR-TEST EAP method to use proper private enterprise number (this will not interoperate with older versions) * added hostapd.conf parameter vendor_elements to allow arbitrary vendor specific elements to be added to the Beacon and Probe Response frames * added support for configuring GCMP cipher for IEEE 802.11ad * added support for 256-bit AES with internal TLS implementation * changed EAPOL transmission to use AC_VO if WMM is active * fixed EAP-TLS/PEAP/TTLS/FAST server to validate TLS Message Length correctly; invalid messages could have caused the hostapd process to terminate before this fix [CVE-2012-4445] * limit number of active wildcard PINs for WPS Registrar to one to avoid confusing behavior with multiple wildcard PINs * added a workaround for WPS PBC session overlap detection to avoid interop issues with deployed station implementations that do not remove active PBC indication from Probe Request frames properly * added support for using SQLite for the eap_user database * added Acct-Session-Id attribute into Access-Request messages * fixed EAPOL frame transmission to non-QoS STAs with nl80211 (do not send QoS frames if the STA did not negotiate use of QoS for this association) 2012-05-10 - v1.0 * Add channel selection support in hostapd. See hostapd.conf. * Add support for IEEE 802.11v Time Advertisement mechanism with UTC TSF offset. See hostapd.conf for config info. * Delay STA entry removal until Deauth/Disassoc TX status in AP mode. This allows the driver to use PS buffering of Deauthentication and Disassociation frames when the STA is in power save sleep. Only available with drivers that provide TX status events for Deauth/ Disassoc frames (nl80211). * Allow PMKSA caching to be disabled on the Authenticator. See hostap.conf config parameter disable_pmksa_caching. * atheros: Add support for IEEE 802.11w configuration. * bsd: Add support for setting HT values in IFM_MMASK. * Allow client isolation to be configured with ap_isolate. Client isolation can be used to prevent low-level bridging of frames between associated stations in the BSS. By default, this bridging is allowed. * Allow coexistance of HT BSSes with WEP/TKIP BSSes. * Add require_ht config parameter, which can be used to configure hostapd to reject association with any station that does not support HT PHY. * Add support for writing debug log to a file using "-f" option. Also add relog CLI command to re-open the log file. * Add bridge handling for WDS STA interfaces. By default they are added to the configured bridge of the AP interface (if present), but the user can also specify a separate bridge using cli command wds_bridge. * hostapd_cli: - Add wds_bridge command for specifying bridge for WDS STA interfaces. - Add relog command for reopening log file. - Send AP-STA-DISCONNECTED event when an AP disconnects a station due to inactivity. - Add wps_config ctrl_interface command for configuring AP. This command can be used to configure the AP using the internal WPS registrar. It works in the same way as new AP settings received from an ER. - Many WPS/WPS ER commands - see WPS/WPS ER sections for details. - Add command get version, that returns hostapd version string. * WNM: Add BSS Transition Management Request for ESS Disassoc Imminent. Use hostapd_cli ess_disassoc (STA addr) (URL) to send the notification to the STA. * Allow AP mode to disconnect STAs based on low ACK condition (when the data connection is not working properly, e.g., due to the STA going outside the range of the AP). Disabled by default, enable by config option disassoc_low_ack. * Add WPA_IGNORE_CONFIG_ERRORS build option to continue in case of bad config file. * WPS: - Send AP Settings as a wrapped Credential attribute to ctrl_iface in WPS-NEW-AP-SETTINGS. - Dispatch more WPS events through hostapd ctrl_iface. - Add mechanism for indicating non-standard WPS errors. - Change concurrent radio AP to use only one WPS UPnP instance. - Add wps_check_pin command for processing PIN from user input. UIs can use this command to process a PIN entered by a user and to validate the checksum digit (if present). - Add hostap_cli get_config command to display current AP config. - Add new hostapd_cli command, wps_ap_pin, to manage AP PIN at runtime and support dynamic AP PIN management. - Disable AP PIN after 10 consecutive failures. Slow down attacks on failures up to 10. - Allow AP to start in Enrollee mode without AP PIN for probing, to be compatible with Windows 7. - Add Config Error into WPS-FAIL events to provide more info to the user on how to resolve the issue. - When controlling multiple interfaces: - apply WPS commands to all interfaces configured to use WPS - apply WPS config changes to all interfaces that use WPS - when an attack is detected on any interface, disable AP PIN on all interfaces * WPS ER: - Show SetSelectedRegistrar events as ctrl_iface events. - Add special AP Setup Locked mode to allow read only ER. ap_setup_locked=2 can now be used to enable a special mode where WPS ER can learn the current AP settings, but cannot change them. * WPS 2.0: Add support for WPS 2.0 (CONFIG_WPS2) - Add build option CONFIG_WPS_EXTENSIBILITY_TESTING to enable tool for testing protocol extensibility. - Add build option CONFIG_WPS_STRICT to allow disabling of WPS workarounds. - Add support for AuthorizedMACs attribute. * TDLS: - Allow TDLS use or TDLS channel switching in the BSS to be prohibited in the BSS, using config params tdls_prohibit and tdls_prohibit_chan_switch. * EAP server: Add support for configuring fragment size (see fragment_size in hostapd.conf). * wlantest: Add a tool wlantest for IEEE802.11 protocol testing. wlantest can be used to capture frames from a monitor interface for realtime capturing or from pcap files for offline analysis. * Interworking: Support added for 802.11u. Enable in .config with CONFIG_INTERWORKING. See hostapd.conf for config parameters for interworking. * Android: Add build and runtime support for Android hostapd. * Add a new debug message level for excessive information. Use -ddd to enable. * TLS: Add support for tls_disable_time_checks=1 in client mode. * Internal TLS: - Add support for TLS v1.1 (RFC 4346). Enable with build parameter CONFIG_TLSV11. - Add domainComponent parser for X.509 names * Reorder some IEs to get closer to IEEE 802.11 standard. Move WMM into end of Beacon, Probe Resp and (Re)Assoc Resp frames. Move HT IEs to be later in (Re)Assoc Resp. * Many bugfixes.
Diffstat (limited to 'wpa_supplicant')
-rw-r--r--wpa_supplicant/.gitignore9
-rw-r--r--wpa_supplicant/ChangeLog421
-rw-r--r--wpa_supplicant/Makefile414
-rw-r--r--wpa_supplicant/README128
-rw-r--r--wpa_supplicant/README-HS20475
-rw-r--r--wpa_supplicant/README-P2P560
-rw-r--r--wpa_supplicant/README-WPS189
-rw-r--r--wpa_supplicant/ap.c648
-rw-r--r--wpa_supplicant/ap.h35
-rw-r--r--wpa_supplicant/autoscan.c143
-rw-r--r--wpa_supplicant/autoscan.h49
-rw-r--r--wpa_supplicant/autoscan_exponential.c104
-rw-r--r--wpa_supplicant/autoscan_periodic.c85
-rw-r--r--wpa_supplicant/bgscan.c31
-rw-r--r--wpa_supplicant/bgscan.h31
-rw-r--r--wpa_supplicant/bgscan_learn.c607
-rw-r--r--wpa_supplicant/bgscan_simple.c79
-rw-r--r--wpa_supplicant/blacklist.c30
-rw-r--r--wpa_supplicant/blacklist.h10
-rw-r--r--wpa_supplicant/bss.c618
-rw-r--r--wpa_supplicant/bss.h82
-rw-r--r--wpa_supplicant/config.c1123
-rw-r--r--wpa_supplicant/config.h514
-rw-r--r--wpa_supplicant/config_file.c601
-rw-r--r--wpa_supplicant/config_none.c10
-rw-r--r--wpa_supplicant/config_ssid.h211
-rw-r--r--wpa_supplicant/config_winreg.c69
-rw-r--r--wpa_supplicant/ctrl_iface.c3869
-rw-r--r--wpa_supplicant/ctrl_iface.h10
-rw-r--r--wpa_supplicant/ctrl_iface_named_pipe.c10
-rw-r--r--wpa_supplicant/ctrl_iface_udp.c49
-rw-r--r--wpa_supplicant/ctrl_iface_unix.c74
-rw-r--r--wpa_supplicant/dbus/Makefile17
-rw-r--r--wpa_supplicant/dbus/dbus_common.c10
-rw-r--r--wpa_supplicant/dbus/dbus_common.h10
-rw-r--r--wpa_supplicant/dbus/dbus_common_i.h14
-rw-r--r--wpa_supplicant/dbus/dbus_dict_helpers.c261
-rw-r--r--wpa_supplicant/dbus/dbus_dict_helpers.h56
-rw-r--r--wpa_supplicant/dbus/dbus_new.c2414
-rw-r--r--wpa_supplicant/dbus/dbus_new.h282
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers.c2322
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers.h277
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers_p2p.c2438
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers_p2p.h211
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers_wps.c120
-rw-r--r--wpa_supplicant/dbus/dbus_new_helpers.c540
-rw-r--r--wpa_supplicant/dbus/dbus_new_helpers.h41
-rw-r--r--wpa_supplicant/dbus/dbus_new_introspect.c27
-rw-r--r--wpa_supplicant/dbus/dbus_old.c66
-rw-r--r--wpa_supplicant/dbus/dbus_old.h22
-rw-r--r--wpa_supplicant/dbus/dbus_old_handlers.c54
-rw-r--r--wpa_supplicant/dbus/dbus_old_handlers.h13
-rw-r--r--wpa_supplicant/dbus/dbus_old_handlers_wps.c20
-rw-r--r--wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service4
-rw-r--r--wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in5
-rw-r--r--wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service4
-rw-r--r--wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service.in5
-rw-r--r--wpa_supplicant/defconfig157
-rw-r--r--wpa_supplicant/doc/docbook/wpa_background.88
-rw-r--r--wpa_supplicant/doc/docbook/wpa_background.sgml6
-rw-r--r--wpa_supplicant/doc/docbook/wpa_cli.88
-rw-r--r--wpa_supplicant/doc/docbook/wpa_cli.sgml6
-rw-r--r--wpa_supplicant/doc/docbook/wpa_gui.88
-rw-r--r--wpa_supplicant/doc/docbook/wpa_gui.sgml6
-rw-r--r--wpa_supplicant/doc/docbook/wpa_passphrase.88
-rw-r--r--wpa_supplicant/doc/docbook/wpa_passphrase.sgml6
-rw-r--r--wpa_supplicant/doc/docbook/wpa_priv.88
-rw-r--r--wpa_supplicant/doc/docbook/wpa_priv.sgml6
-rw-r--r--wpa_supplicant/doc/docbook/wpa_supplicant.886
-rw-r--r--wpa_supplicant/doc/docbook/wpa_supplicant.conf.52
-rw-r--r--wpa_supplicant/doc/docbook/wpa_supplicant.sgml149
-rw-r--r--wpa_supplicant/driver_i.h384
-rw-r--r--wpa_supplicant/eap_register.c30
-rw-r--r--wpa_supplicant/eapol_test.c200
-rw-r--r--wpa_supplicant/events.c2142
-rwxr-xr-xwpa_supplicant/examples/dbus-listen-preq.py62
-rwxr-xr-xwpa_supplicant/examples/p2p-action-udhcp.sh69
-rwxr-xr-xwpa_supplicant/examples/p2p-action.sh83
-rw-r--r--wpa_supplicant/examples/p2p/p2p_connect.py299
-rw-r--r--wpa_supplicant/examples/p2p/p2p_disconnect.py169
-rw-r--r--wpa_supplicant/examples/p2p/p2p_find.py192
-rw-r--r--wpa_supplicant/examples/p2p/p2p_flush.py168
-rw-r--r--wpa_supplicant/examples/p2p/p2p_group_add.py222
-rw-r--r--wpa_supplicant/examples/p2p/p2p_invite.py201
-rw-r--r--wpa_supplicant/examples/p2p/p2p_listen.py182
-rw-r--r--wpa_supplicant/examples/p2p/p2p_stop_find.py174
-rw-r--r--wpa_supplicant/examples/udhcpd-p2p.conf120
-rwxr-xr-xwpa_supplicant/examples/wpas-dbus-new-signals.py4
-rwxr-xr-xwpa_supplicant/examples/wps-ap-cli78
-rwxr-xr-xwpa_supplicant/examples/wps-nfc.py162
-rw-r--r--wpa_supplicant/gas_query.c519
-rw-r--r--wpa_supplicant/gas_query.h58
-rw-r--r--wpa_supplicant/hs20_supplicant.c185
-rw-r--r--wpa_supplicant/hs20_supplicant.h20
-rw-r--r--wpa_supplicant/ibss_rsn.c176
-rw-r--r--wpa_supplicant/ibss_rsn.h11
-rw-r--r--wpa_supplicant/interworking.c2107
-rw-r--r--wpa_supplicant/interworking.h32
-rw-r--r--wpa_supplicant/main.c68
-rw-r--r--wpa_supplicant/main_none.c10
-rw-r--r--wpa_supplicant/main_symbian.cpp48
-rw-r--r--wpa_supplicant/main_winmain.c10
-rw-r--r--wpa_supplicant/main_winsvc.c10
-rw-r--r--wpa_supplicant/mlme.c3198
-rw-r--r--wpa_supplicant/mlme.h129
-rw-r--r--wpa_supplicant/nfc_pw_token.c83
-rw-r--r--wpa_supplicant/notify.c311
-rw-r--r--wpa_supplicant/notify.h66
-rw-r--r--wpa_supplicant/offchannel.c397
-rw-r--r--wpa_supplicant/offchannel.h35
-rw-r--r--wpa_supplicant/p2p_supplicant.c5484
-rw-r--r--wpa_supplicant/p2p_supplicant.h151
-rw-r--r--wpa_supplicant/preauth_test.c17
-rw-r--r--wpa_supplicant/scan.c1092
-rw-r--r--wpa_supplicant/scan.h19
-rw-r--r--wpa_supplicant/sme.c971
-rw-r--r--wpa_supplicant/sme.h51
-rw-r--r--wpa_supplicant/tests/test_eap_sim_common.c12
-rw-r--r--wpa_supplicant/tests/test_wpa.c10
-rwxr-xr-xwpa_supplicant/utils/log2pcap.py54
-rw-r--r--wpa_supplicant/wifi_display.c251
-rw-r--r--wpa_supplicant/wifi_display.h20
-rwxr-xr-xwpa_supplicant/win_example.reg42
-rw-r--r--wpa_supplicant/win_if_list.c173
-rw-r--r--wpa_supplicant/wnm_sta.c423
-rw-r--r--wpa_supplicant/wnm_sta.h21
-rw-r--r--wpa_supplicant/wpa_cli.c2659
-rw-r--r--wpa_supplicant/wpa_passphrase.c12
-rw-r--r--wpa_supplicant/wpa_priv.c16
-rw-r--r--wpa_supplicant/wpa_supplicant.c2080
-rw-r--r--wpa_supplicant/wpa_supplicant.conf316
-rw-r--r--wpa_supplicant/wpa_supplicant.nsi112
-rw-r--r--wpa_supplicant/wpa_supplicant_conf.mk34
-rwxr-xr-xwpa_supplicant/wpa_supplicant_conf.sh16
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h520
-rw-r--r--wpa_supplicant/wpa_supplicant_template.conf6
-rw-r--r--wpa_supplicant/wpas_glue.c300
-rw-r--r--wpa_supplicant/wpas_glue.h18
-rw-r--r--wpa_supplicant/wps_supplicant.c1193
-rw-r--r--wpa_supplicant/wps_supplicant.h67
140 files changed, 40856 insertions, 8683 deletions
diff --git a/wpa_supplicant/.gitignore b/wpa_supplicant/.gitignore
index e7e034c7fe80..0e3ad1b06cc8 100644
--- a/wpa_supplicant/.gitignore
+++ b/wpa_supplicant/.gitignore
@@ -1,8 +1 @@
-*.d
-.config
-eapol_test
-preauth_test
-wpa_cli
-wpa_passphrase
-wpa_supplicant
-wpa_priv
+*.service
diff --git a/wpa_supplicant/ChangeLog b/wpa_supplicant/ChangeLog
index 56046c34bb33..8abafb24d126 100644
--- a/wpa_supplicant/ChangeLog
+++ b/wpa_supplicant/ChangeLog
@@ -1,23 +1,408 @@
ChangeLog for wpa_supplicant
-2010-09-07 - v0.7.3
- * fixed fallback from failed PMKSA caching into full EAP authentication
- [Bug 355]
- * fixed issue with early D-Bus signals during initialization
- * fixed X.509 name handling in internal TLS
- * fixed WPS ER to use corrent Enrollee MAC Address in Credential
- * fixed scanning routines ot improve AP selection for WPS
- * added WPS workaround for open networks
- * fixed WPS Diffie-Hellman derivation to use correct public key length
- * fixed wpa_supplicant AP mode operations to ignore Supplicant and
- scan result events
- * improved SME operations with nl80211
- * fixed WPS ER event_id handling in some cases
- * fixed some issues with bgscan simple to avoid unnecessary scans
- * fixed issue with l2_packet_ndis overlapped writes corrupting stack
- [Bug 328]
- * updated WinPcap to the latest stable version 4.1.2 in Windows
- installer
+2013-01-12 - v2.0
+ * removed Qt3-based wpa_gui (obsoleted by wpa_qui-qt4)
+ * removed unmaintained driver wrappers broadcom, iphone, osx, ralink,
+ hostap, madwifi (hostap and madwifi remain available for hostapd;
+ their wpa_supplicant functionality is obsoleted by wext)
+ * improved debug logging (human readable event names, interface name
+ included in more entries)
+ * changed AP mode behavior to enable WPS only for open and
+ WPA/WPA2-Personal configuration
+ * improved P2P concurrency operations
+ - better coordination of concurrent scan and P2P search operations
+ - avoid concurrent remain-on-channel operation requests by canceling
+ previous operations prior to starting a new one
+ - reject operations that would require multi-channel concurrency if
+ the driver does not support it
+ - add parameter to select whether STA or P2P connection is preferred
+ if the driver cannot support both at the same time
+ - allow driver to indicate channel changes
+ - added optional delay=<search delay in milliseconds> parameter for
+ p2p_find to avoid taking all radio resources
+ - use 500 ms p2p_find search delay by default during concurrent
+ operations
+ - allow all channels in GO Negotiation if the driver supports
+ multi-channel concurrency
+ * added number of small changes to make it easier for static analyzers
+ to understand the implementation
+ * fixed number of small bugs (see git logs for more details)
+ * nl80211: number of updates to use new cfg80211/nl80211 functionality
+ - replace monitor interface with nl80211 commands for AP mode
+ - additional information for driver-based AP SME
+ - STA entry authorization in RSN IBSS
+ * EAP-pwd:
+ - fixed KDF for group 21 and zero-padding
+ - added support for fragmentation
+ - increased maximum number of hunting-and-pecking iterations
+ * avoid excessive Probe Response retries for broadcast Probe Request
+ frames (only with drivers using wpa_supplicant AP mode SME/MLME)
+ * added "GET country" ctrl_iface command
+ * do not save an invalid network block in wpa_supplicant.conf to avoid
+ problems reading the file on next start
+ * send STA connected/disconnected ctrl_iface events to both the P2P
+ group and parent interfaces
+ * added preliminary support for using TLS v1.2 (CONFIG_TLSV12=y)
+ * added "SET pno <1/0>" ctrl_iface command to start/stop preferred
+ network offload with sched_scan driver command
+ * merged in number of changes from Android repository for P2P, nl80211,
+ and build parameters
+ * changed P2P GO mode configuration to use driver capabilities to
+ automatically enable HT operations when supported
+ * added "wpa_cli status wps" command to fetch WPA2-Personal passhrase
+ for WPS use cases in AP mode
+ * EAP-AKA: keep pseudonym identity across EAP exchanges to match EAP-SIM
+ behavior
+ * improved reassociation behavior in cases where association is rejected
+ or when an AP disconnects us to handle common load balancing
+ mechanisms
+ - try to avoid extra scans when the needed information is available
+ * added optional "join" argument for p2p_prov_disc ctrl_iface command
+ * added group ifname to P2P-PROV-DISC-* events
+ * added P2P Device Address to AP-STA-DISCONNECTED event and use
+ p2p_dev_addr parameter name with AP-STA-CONNECTED
+ * added workarounds for WPS PBC overlap detection for some P2P use cases
+ where deployed stations work incorrectly
+ * optimize WPS connection speed by disconnecting prior to WPS scan and
+ by using single channel scans when AP channel is known
+ * PCSC and SIM/USIM improvements:
+ - accept 0x67 (Wrong length) as a response to READ RECORD to fix
+ issues with some USIM cards
+ - try to read MNC length from SIM/USIM
+ - build realm according to 3GPP TS 23.003 with identity from the SIM
+ - allow T1 protocol to be enabled
+ * added more WPS and P2P information available through D-Bus
+ * improve P2P negotiation robustness
+ - extra waits to get ACK frames through
+ - longer timeouts for cases where deployed devices have been
+ identified have issues meeting the specification requirements
+ - more retries for some P2P frames
+ - handle race conditions in GO Negotiation start by both devices
+ - ignore unexpected GO Negotiation Response frame
+ * added support for libnl 3.2 and newer
+ * added P2P persistent group info to P2P_PEER data
+ * maintain a list of P2P Clients for persistent group on GO
+ * AP: increased initial group key handshake retransmit timeout to 500 ms
+ * added optional dev_id parameter for p2p_find
+ * added P2P-FIND-STOPPED ctrl_iface event
+ * fixed issues in WPA/RSN element validation when roaming with ap_scan=1
+ and driver-based BSS selection
+ * do not expire P2P peer entries while connected with the peer in a
+ group
+ * fixed WSC element inclusion in cases where P2P is disabled
+ * AP: added a WPS workaround for mixed mode AP Settings with Windows 7
+ * EAP-SIM: fixed AT_COUNTER_TOO_SMALL use
+ * EAP-SIM/AKA: append realm to pseudonym identity
+ * EAP-SIM/AKA: store pseudonym identity in network configuration to
+ allow it to persist over multiple EAP sessions and wpa_supplicant
+ restarts
+ * EAP-AKA': updated to RFC 5448 (username prefixes changed); note: this
+ breaks interoperability with older versions
+ * added support for WFA Hotspot 2.0
+ - GAS/ANQP to fetch network information
+ - credential configuration and automatic network selections based on
+ credential match with ANQP information
+ * limited PMKSA cache entries to be used only with the network context
+ that was used to create them
+ * improved PMKSA cache expiration to avoid unnecessary disconnections
+ * adjusted bgscan_simple fast-scan backoff to avoid too frequent
+ background scans
+ * removed ctrl_iface event on P2P PD Response in join-group case
+ * added option to fetch BSS table entry based on P2P Device Address
+ ("BSS p2p_dev_addr=<P2P Device Address>")
+ * added BSS entry age to ctrl_iface BSS command output
+ * added optional MASK=0xH option for ctrl_iface BSS command to select
+ which fields are included in the response
+ * added optional RANGE=ALL|N1-N2 option for ctrl_iface BSS command to
+ fetch information about several BSSes in one call
+ * simplified licensing terms by selecting the BSD license as the only
+ alternative
+ * added "P2P_SET disallow_freq <freq list>" ctrl_iface command to
+ disable channels from P2P use
+ * added p2p_pref_chan configuration parameter to allow preferred P2P
+ channels to be specified
+ * added support for advertising immediate availability of a WPS
+ credential for P2P use cases
+ * optimized scan operations for P2P use cases (use single channel scan
+ for a specific SSID when possible)
+ * EAP-TTLS: fixed peer challenge generation for MSCHAPv2
+ * SME: do not use reassociation after explicit disconnection request
+ (local or a notification from an AP)
+ * added support for sending debug info to Linux tracing (-T on command
+ line)
+ * added support for using Deauthentication reason code 3 as an
+ indication of P2P group termination
+ * added wps_vendor_ext_m1 configuration parameter to allow vendor
+ specific attributes to be added to WPS M1
+ * started using separate TLS library context for tunneled TLS
+ (EAP-PEAP/TLS, EAP-TTLS/TLS, EAP-FAST/TLS) to support different CA
+ certificate configuration between Phase 1 and Phase 2
+ * added optional "auto" parameter for p2p_connect to request automatic
+ GO Negotiation vs. join-a-group selection
+ * added disabled_scan_offload parameter to disable automatic scan
+ offloading (sched_scan)
+ * added optional persistent=<network id> parameter for p2p_connect to
+ allow forcing of a specific SSID/passphrase for GO Negotiation
+ * added support for OBSS scan requests and 20/40 BSS coexistence reports
+ * reject PD Request for unknown group
+ * removed scripts and notes related to Windows binary releases (which
+ have not been used starting from 1.x)
+ * added initial support for WNM operations
+ - Keep-alive based on BSS max idle period
+ - WNM-Sleep Mode
+ - minimal BSS Transition Management processing
+ * added autoscan module to control scanning behavior while not connected
+ - autoscan_periodic and autoscan_exponential modules
+ * added new WPS NFC ctrl_iface mechanism
+ - added initial support NFC connection handover
+ - removed obsoleted WPS_OOB command (including support for deprecated
+ UFD config_method)
+ * added optional framework for external password storage ("ext:<name>")
+ * wpa_cli: added optional support for controlling wpa_supplicant
+ remotely over UDP (CONFIG_CTRL_IFACE=udp-remote) for testing purposes
+ * wpa_cli: extended tab completion to more commands
+ * changed SSID output to use printf-escaped strings instead of masking
+ of non-ASCII characters
+ - SSID can now be configured in the same format: ssid=P"abc\x00test"
+ * removed default ACM=1 from AC_VO and AC_VI
+ * added optional "ht40" argument for P2P ctrl_iface commands to allow
+ 40 MHz channels to be requested on the 5 GHz band
+ * added optional parameters for p2p_invite command to specify channel
+ when reinvoking a persistent group as the GO
+ * improved FIPS mode builds with OpenSSL
+ - "make fips" with CONFIG_FIPS=y to build wpa_supplicant with the
+ OpenSSL FIPS object module
+ - replace low level OpenSSL AES API calls to use EVP
+ - use OpenSSL keying material exporter when possible
+ - do not export TLS keys in FIPS mode
+ - remove MD5 from CONFIG_FIPS=y builds
+ - use OpenSSL function for PKBDF2 passphrase-to-PSK
+ - use OpenSSL HMAC implementation
+ - mix RAND_bytes() output into random_get_bytes() to force OpenSSL
+ DRBG to be used in FIPS mode
+ - use OpenSSL CMAC implementation
+ * added mechanism to disable TLS Session Ticket extension
+ - a workaround for servers that do not support TLS extensions that
+ was enabled by default in recent OpenSSL versions
+ - tls_disable_session_ticket=1
+ - automatically disable TLS Session Ticket extension by default when
+ using EAP-TLS/PEAP/TTLS (i.e., only use it with EAP-FAST)
+ * changed VENDOR-TEST EAP method to use proper private enterprise number
+ (this will not interoperate with older versions)
+ * disable network block temporarily on authentication failures
+ * improved WPS AP selection during WPS PIN iteration
+ * added support for configuring GCMP cipher for IEEE 802.11ad
+ * added support for Wi-Fi Display extensions
+ - WFD_SUBELEMENT_SET ctrl_iface command to configure WFD subelements
+ - SET wifi_display <0/1> to disable/enable WFD support
+ - WFD service discovery
+ - an external program is needed to manage the audio/video streaming
+ and codecs
+ * optimized scan result use for network selection
+ - use the internal BSS table instead of raw scan results
+ - allow unnecessary scans to be skipped if fresh information is
+ available (e.g., after GAS/ANQP round for Interworking)
+ * added support for 256-bit AES with internal TLS implementation
+ * allow peer to propose channel in P2P invitation process for a
+ persistent group
+ * added disallow_aps parameter to allow BSSIDs/SSIDs to be disallowed
+ from network selection
+ * re-enable the networks disabled during WPS operations
+ * allow P2P functionality to be disabled per interface (p2p_disabled=1)
+ * added secondary device types into P2P_PEER output
+ * added an option to disable use of a separate P2P group interface
+ (p2p_no_group_iface=1)
+ * fixed P2P Bonjour SD to match entries with both compressed and not
+ compressed domain name format and support multiple Bonjour PTR matches
+ for the same key
+ * use deauthentication instead of disassociation for all disconnection
+ operations; this removes the now unused disassociate() wpa_driver_ops
+ callback
+ * optimized PSK generation on P2P GO by caching results to avoid
+ multiple PBKDF2 operations
+ * added okc=1 global configuration parameter to allow OKC to be enabled
+ by default for all network blocks
+ * added a workaround for WPS PBC session overlap detection to avoid
+ interop issues with deployed station implementations that do not
+ remove active PBC indication from Probe Request frames properly
+ * added basic support for 60 GHz band
+ * extend EAPOL frames processing workaround for roaming cases
+ (postpone processing of unexpected EAPOL frame until association
+ event to handle reordered events)
+
+2012-05-10 - v1.0
+ * bsd: Add support for setting HT values in IFM_MMASK.
+ * Delay STA entry removal until Deauth/Disassoc TX status in AP mode.
+ This allows the driver to use PS buffering of Deauthentication and
+ Disassociation frames when the STA is in power save sleep. Only
+ available with drivers that provide TX status events for Deauth/
+ Disassoc frames (nl80211).
+ * Drop oldest unknown BSS table entries first. This makes it less
+ likely to hit connection issues in environments with huge number
+ of visible APs.
+ * Add systemd support.
+ * Add support for setting the syslog facility from the config file
+ at build time.
+ * atheros: Add support for IEEE 802.11w configuration.
+ * AP mode: Allow enable HT20 if driver supports it, by setting the
+ config parameter ieee80211n.
+ * Allow AP mode to disconnect STAs based on low ACK condition (when
+ the data connection is not working properly, e.g., due to the STA
+ going outside the range of the AP). Disabled by default, enable by
+ config option disassoc_low_ack.
+ * nl80211:
+ - Support GTK rekey offload.
+ - Support PMKSA candidate events. This adds support for RSN
+ pre-authentication with nl80211 interface and drivers that handle
+ roaming internally.
+ * dbus:
+ - Add a DBus signal for EAP SM requests, emitted on the Interface
+ object.
+ - Export max scan ssids supported by the driver as MaxScanSSID.
+ - Add signal Certification for information about server certification.
+ - Add BSSExpireAge and BSSExpireCount interface properties and
+ support set/get, which allows for setting BSS cache expiration age
+ and expiration scan count.
+ - Add ConfigFile to AddInterface properties.
+ - Add Interface.Country property and support to get/set the value.
+ - Add DBus property CurrentAuthMode.
+ - P2P DBus API added.
+ - Emit property changed events (for property BSSs) when adding/
+ removing BSSs.
+ - Treat '' in SSIDs of Interface.Scan as a request for broadcast
+ scan, instead of ignoring it.
+ - Add DBus getter/setter for FastReauth.
+ - Raise PropertiesChanged on org.freedesktop.DBus.Properties.
+ * wpa_cli:
+ - Send AP-STA-DISCONNECTED event when an AP disconnects a station
+ due to inactivity.
+ - Make second argument to set command optional. This can be used to
+ indicate a zero length value.
+ - Add signal_poll command.
+ - Add bss_expire_age and bss_expire_count commands to set/get BSS
+ cache expiration age and expiration scan count.
+ - Add ability to set scan interval (the time in seconds wpa_s waits
+ before requesting a new scan after failing to find a suitable
+ network in scan results) using scan_interval command.
+ - Add event CTRL-EVENT-ASSOC-REJECT for association rejected.
+ - Add command get version, that returns wpa_supplicant version string.
+ - Add command sta_autoconnect for disabling automatic reconnection
+ on receiving disconnection event.
+ - Setting bssid parameter to an empty string "" or any can now be
+ used to clear the bssid_set flag in a network block, i.e., to remove
+ bssid filtering.
+ - Add tdls_testing command to add a special testing feature for
+ changing TDLS behavior. Build param CONFIG_TDLS_TESTING must be
+ enabled as well.
+ - For interworking, add wpa_cli commands interworking_select,
+ interworking_connect, anqp_get, fetch_anqp, and stop_fetch_anqp.
+ - Many P2P commands were added. See README-P2P.
+ - Many WPS/WPS ER commands - see WPS/WPS ER sections for details.
+ - Allow set command to change global config parameters.
+ - Add log_level command, which can be used to display the current
+ debugging level and to change the log level during run time.
+ - Add note command, which can be used to insert notes to the debug
+ log.
+ - Add internal line edit implementation. CONFIG_WPA_CLI_EDIT=y
+ can now be used to build wpa_cli with internal implementation of
+ line editing and history support. This can be used as a replacement
+ for CONFIG_READLINE=y.
+ * AP mode: Add max_num_sta config option, which can be used to limit
+ the number of stations allowed to connect to the AP.
+ * Add WPA_IGNORE_CONFIG_ERRORS build option to continue in case of bad
+ config file.
+ * wext: Increase scan timeout from 5 to 10 seconds.
+ * Add blacklist command, allowing an external program to
+ manage the BSS blacklist and display its current contents.
+ * WPS:
+ - Add wpa_cli wps_pin get command for generating random PINs. This can
+ be used in a UI to generate a PIN without starting WPS (or P2P)
+ operation.
+ - Set RF bands based on driver capabilities, instead of hardcoding
+ them.
+ - Add mechanism for indicating non-standard WPS errors.
+ - Add CONFIG_WPS_REG_DISABLE_OPEN=y option to disable open networks
+ by default.
+ - Add wps_ap_pin cli command for wpa_supplicant AP mode.
+ - Add wps_check_pin cli command for processing PIN from user input.
+ UIs can use this command to process a PIN entered by a user and to
+ validate the checksum digit (if present).
+ - Cancel WPS operation on PBC session overlap detection.
+ - New wps_cancel command in wpa_cli will cancel a pending WPS
+ operation.
+ - wpa_cli action: Add WPS_EVENT_SUCCESS and WPS_EVENT_FAIL handlers.
+ - Trigger WPS config update on Manufacturer, Model Name, Model
+ Number, and Serial Number changes.
+ - Fragment size is now configurable for EAP-WSC peer. Use
+ wpa_cli set wps_fragment_size <val>.
+ - Disable AP PIN after 10 consecutive failures. Slow down attacks on
+ failures up to 10.
+ - Allow AP to start in Enrollee mode without AP PIN for probing, to
+ be compatible with Windows 7.
+ - Add Config Error into WPS-FAIL events to provide more info to the
+ user on how to resolve the issue.
+ - Label and Display config methods are not allowed to be enabled
+ at the same time, since it is unclear which PIN to use if both
+ methods are advertised.
+ - When controlling multiple interfaces:
+ - apply WPS commands to all interfaces configured to use WPS
+ - apply WPS config changes to all interfaces that use WPS
+ - when an attack is detected on any interface, disable AP PIN on
+ all interfaces
+ * WPS ER:
+ - Add special AP Setup Locked mode to allow read only ER.
+ ap_setup_locked=2 can now be used to enable a special mode where
+ WPS ER can learn the current AP settings, but cannot change them.
+ - Show SetSelectedRegistrar events as ctrl_iface events
+ - Add wps_er_set_config to enroll a network based on a local
+ network configuration block instead of having to (re-)learn the
+ current AP settings with wps_er_learn.
+ - Allow AP filtering based on IP address, add ctrl_iface event for
+ learned AP settings, add wps_er_config command to configure an AP.
+ * WPS 2.0: Add support for WPS 2.0 (CONFIG_WPS2)
+ - Add build option CONFIG_WPS_EXTENSIBILITY_TESTING to enable tool
+ for testing protocol extensibility.
+ - Add build option CONFIG_WPS_STRICT to allow disabling of WPS
+ workarounds.
+ - Add support for AuthorizedMACs attribute.
+ * TDLS:
+ - Propogate TDLS related nl80211 capability flags from kernel and
+ add them as driver capability flags. If the driver doesn't support
+ capabilities, assume TDLS is supported internally. When TDLS is
+ explicitly not supported, disable all user facing TDLS operations.
+ - Allow TDLS to be disabled at runtime (mostly for testing).
+ Use set tdls_disabled.
+ - Honor AP TDLS settings that prohibit/allow TDLS.
+ - Add a special testing feature for changing TDLS behavior. Use
+ CONFIG_TDLS_TESTING build param to enable. Configure at runtime
+ with tdls_testing cli command.
+ - Add support for TDLS 802.11z.
+ * wlantest: Add a tool wlantest for IEEE802.11 protocol testing.
+ wlantest can be used to capture frames from a monitor interface
+ for realtime capturing or from pcap files for offline analysis.
+ * Interworking: Support added for 802.11u. Enable in .config with
+ CONFIG_INTERWORKING. See wpa_supplicant.conf for config parameters
+ for interworking. wpa_cli commands added to support this are
+ interworking_select, interworking_connect, anqp_get, fetch_anqp,
+ and stop_fetch_anqp.
+ * Android: Add build and runtime support for Android wpa_supplicant.
+ * bgscan learn: Add new bgscan that learns BSS information based on
+ previous scans, and uses that information to dynamically generate
+ the list of channels for background scans.
+ * Add a new debug message level for excessive information. Use
+ -ddd to enable.
+ * TLS: Add support for tls_disable_time_checks=1 in client mode.
+ * Internal TLS:
+ - Add support for TLS v1.1 (RFC 4346). Enable with build parameter
+ CONFIG_TLSV11.
+ - Add domainComponent parser for X.509 names.
+ * Linux: Add RFKill support by adding an interface state "disabled".
+ * Reorder some IEs to get closer to IEEE 802.11 standard. Move
+ WMM into end of Beacon, Probe Resp and (Re)Assoc Resp frames.
+ Move HT IEs to be later in (Re)Assoc Resp.
+ * Solaris: Add support for wired 802.1X client.
+ * Wi-Fi Direct support. See README-P2P for more information.
+ * Many bugfixes.
2010-04-18 - v0.7.2
* nl80211: fixed number of issues with roaming
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 1d2562372518..65fef41652be 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -8,11 +8,27 @@ endif
export LIBDIR ?= /usr/local/lib/
export BINDIR ?= /usr/local/sbin/
+PKG_CONFIG ?= pkg-config
CFLAGS += -I../src
CFLAGS += -I../src/utils
-ALL=wpa_supplicant wpa_passphrase wpa_cli
+-include .config
+
+BINALL=wpa_supplicant wpa_cli
+
+ifndef CONFIG_NO_WPA_PASSPHRASE
+BINALL += wpa_passphrase
+endif
+
+ALL = $(BINALL)
+ALL += systemd/wpa_supplicant.service
+ALL += systemd/wpa_supplicant@.service
+ALL += systemd/wpa_supplicant-nl80211@.service
+ALL += systemd/wpa_supplicant-wired@.service
+ALL += dbus/fi.epitest.hostap.WPASupplicant.service
+ALL += dbus/fi.w1.wpa_supplicant1.service
+
all: verify_config $(ALL) dynamic_eap_methods
@@ -33,11 +49,17 @@ mkconfig:
echo CONFIG_DRIVER_HOSTAP=y >> .config
echo CONFIG_DRIVER_WEXT=y >> .config
-install: all
- mkdir -p $(DESTDIR)$(BINDIR)
- for i in $(ALL); do cp $$i $(DESTDIR)$(BINDIR)/$$i; done
+$(DESTDIR)$(BINDIR)/%: %
+ install -D $(<) $(@)
+
+install: $(addprefix $(DESTDIR)$(BINDIR)/,$(BINALL))
$(MAKE) -C ../src install
+ifdef CONFIG_FIPS
+CONFIG_NO_RANDOM_POOL=
+CONFIG_OPENSSL_CMAC=y
+endif
+
OBJS = config.o
OBJS += notify.o
OBJS += bss.o
@@ -50,8 +72,8 @@ OBJS_p += ../src/utils/common.o
OBJS_p += ../src/utils/wpa_debug.o
OBJS_p += ../src/utils/wpabuf.o
OBJS_c = wpa_cli.o ../src/common/wpa_ctrl.o
-
--include .config
+OBJS_c += ../src/utils/wpa_debug.o
+OBJS_c += ../src/utils/common.o
ifndef CONFIG_OS
ifdef CONFIG_NATIVE_WINDOWS
@@ -74,7 +96,7 @@ CFLAGS += -DWPA_TRACE
OBJS += ../src/utils/trace.o
OBJS_p += ../src/utils/trace.o
OBJS_c += ../src/utils/trace.o
-OBJS_c += ../src/utils/wpa_debug.o
+OBJS_priv += ../src/utils/trace.o
LDFLAGS += -rdynamic
CFLAGS += -funwind-tables
ifdef CONFIG_WPA_TRACE_BFD
@@ -89,12 +111,21 @@ ifndef CONFIG_ELOOP
CONFIG_ELOOP=eloop
endif
OBJS += ../src/utils/$(CONFIG_ELOOP).o
+OBJS_c += ../src/utils/$(CONFIG_ELOOP).o
+
+ifdef CONFIG_ELOOP_POLL
+CFLAGS += -DCONFIG_ELOOP_POLL
+endif
ifdef CONFIG_EAPOL_TEST
CFLAGS += -Werror -DEAPOL_TEST
endif
+ifdef CONFIG_HT_OVERRIDES
+CFLAGS += -DCONFIG_HT_OVERRIDES
+endif
+
ifndef CONFIG_BACKEND
CONFIG_BACKEND=file
endif
@@ -141,6 +172,26 @@ NEED_SHA256=y
NEED_AES_OMAC1=y
endif
+ifdef CONFIG_SAE
+CFLAGS += -DCONFIG_SAE
+endif
+
+ifdef CONFIG_WNM
+CFLAGS += -DCONFIG_WNM
+OBJS += wnm_sta.o
+endif
+
+ifdef CONFIG_TDLS
+CFLAGS += -DCONFIG_TDLS
+OBJS += ../src/rsn_supp/tdls.o
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_TDLS_TESTING
+CFLAGS += -DCONFIG_TDLS_TESTING
+endif
+
ifdef CONFIG_PEERKEY
CFLAGS += -DCONFIG_PEERKEY
endif
@@ -166,6 +217,47 @@ CFLAGS += -DCONFIG_IBSS_RSN
OBJS += ibss_rsn.o
endif
+ifdef CONFIG_P2P
+OBJS += p2p_supplicant.o
+OBJS += ../src/p2p/p2p.o
+OBJS += ../src/p2p/p2p_utils.o
+OBJS += ../src/p2p/p2p_parse.o
+OBJS += ../src/p2p/p2p_build.o
+OBJS += ../src/p2p/p2p_go_neg.o
+OBJS += ../src/p2p/p2p_sd.o
+OBJS += ../src/p2p/p2p_pd.o
+OBJS += ../src/p2p/p2p_invitation.o
+OBJS += ../src/p2p/p2p_dev_disc.o
+OBJS += ../src/p2p/p2p_group.o
+OBJS += ../src/ap/p2p_hostapd.o
+CFLAGS += -DCONFIG_P2P
+NEED_GAS=y
+NEED_OFFCHANNEL=y
+NEED_80211_COMMON=y
+CONFIG_WPS=y
+CONFIG_AP=y
+ifdef CONFIG_P2P_STRICT
+CFLAGS += -DCONFIG_P2P_STRICT
+endif
+endif
+
+ifdef CONFIG_WIFI_DISPLAY
+CFLAGS += -DCONFIG_WIFI_DISPLAY
+OBJS += wifi_display.o
+endif
+
+ifdef CONFIG_HS20
+OBJS += hs20_supplicant.o
+CFLAGS += -DCONFIG_HS20
+CONFIG_INTERWORKING=y
+endif
+
+ifdef CONFIG_INTERWORKING
+OBJS += interworking.o
+CFLAGS += -DCONFIG_INTERWORKING
+NEED_GAS=y
+endif
+
ifdef CONFIG_NO_WPA2
CFLAGS += -DCONFIG_NO_WPA2
endif
@@ -223,6 +315,17 @@ TLS_FUNCS=y
CONFIG_IEEE8021X_EAPOL=y
endif
+ifdef CONFIG_EAP_UNAUTH_TLS
+# EAP-UNAUTH-TLS
+CFLAGS += -DEAP_UNAUTH_TLS
+ifndef CONFIG_EAP_UNAUTH_TLS
+OBJS += ../src/eap_peer/eap_tls.o
+OBJS_h += ../src/eap_server/eap_server_tls.o
+TLS_FUNCS=y
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
ifdef CONFIG_EAP_PEAP
# EAP-PEAP
ifeq ($(CONFIG_EAP_PEAP), dyn)
@@ -454,7 +557,19 @@ NEED_SHA256=y
NEED_AES_OMAC1=y
endif
+ifdef CONFIG_EAP_PWD
+CFLAGS += -DEAP_PWD
+OBJS += ../src/eap_peer/eap_pwd.o ../src/eap_common/eap_pwd_common.o
+OBJS_h += ../src/eap_server/eap_pwd.o
+CONFIG_IEEE8021X_EAPOL=y
+NEED_SHA256=y
+endif
+
ifdef CONFIG_WPS
+ifdef CONFIG_WPS2
+CFLAGS += -DCONFIG_WPS2
+endif
+
# EAP-WSC
CFLAGS += -DCONFIG_WPS -DEAP_WSC
OBJS += wps_supplicant.o
@@ -477,25 +592,10 @@ NEED_80211_COMMON=y
NEED_AES_CBC=y
NEED_MODEXP=y
-ifdef CONFIG_WPS_UFD
-CFLAGS += -DCONFIG_WPS_UFD
-OBJS += ../src/wps/wps_ufd.o
-NEED_WPS_OOB=y
-endif
-
ifdef CONFIG_WPS_NFC
CFLAGS += -DCONFIG_WPS_NFC
OBJS += ../src/wps/ndef.o
-OBJS += ../src/wps/wps_nfc.o
NEED_WPS_OOB=y
-ifdef CONFIG_WPS_NFC_PN531
-PN531_PATH ?= /usr/local/src/nfc
-CFLAGS += -DCONFIG_WPS_NFC_PN531
-CFLAGS += -I${PN531_PATH}/inc
-OBJS += ../src/wps/wps_nfc_pn531.o
-LIBS += ${PN531_PATH}/lib/wpsnfc.dll
-LIBS += ${PN531_PATH}/lib/libnfc_mapping_pn53x.dll
-endif
endif
ifdef NEED_WPS_OOB
@@ -522,6 +622,19 @@ OBJS += ../src/wps/http_client.o
OBJS += ../src/wps/http_server.o
endif
+ifdef CONFIG_WPS_STRICT
+CFLAGS += -DCONFIG_WPS_STRICT
+OBJS += ../src/wps/wps_validate.o
+endif
+
+ifdef CONFIG_WPS_TESTING
+CFLAGS += -DCONFIG_WPS_TESTING
+endif
+
+ifdef CONFIG_WPS_REG_DISABLE_OPEN
+CFLAGS += -DCONFIG_WPS_REG_DISABLE_OPEN
+endif
+
endif
ifdef CONFIG_EAP_IKEV2
@@ -604,8 +717,17 @@ OBJS += ../src/ap/ap_mlme.o
OBJS += ../src/ap/ieee802_1x.o
OBJS += ../src/eapol_auth/eapol_auth_sm.o
OBJS += ../src/ap/ieee802_11_auth.o
+OBJS += ../src/ap/ieee802_11_shared.o
OBJS += ../src/ap/drv_callbacks.o
OBJS += ../src/ap/ap_drv_ops.o
+OBJS += ../src/ap/beacon.o
+OBJS += ../src/ap/eap_user_db.o
+ifdef CONFIG_IEEE80211N
+OBJS += ../src/ap/ieee802_11_ht.o
+endif
+ifdef CONFIG_WNM
+OBJS += ../src/ap/wnm_ap.o
+endif
ifdef CONFIG_CTRL_IFACE
OBJS += ../src/ap/ctrl_iface_ap.o
endif
@@ -620,14 +742,10 @@ CFLAGS += -DCONFIG_IEEE80211N
endif
ifdef NEED_AP_MLME
-OBJS += ../src/ap/beacon.o
OBJS += ../src/ap/wmm.o
OBJS += ../src/ap/ap_list.o
OBJS += ../src/ap/ieee802_11.o
OBJS += ../src/ap/hw_features.o
-ifdef CONFIG_IEEE80211N
-OBJS += ../src/ap/ieee802_11_ht.o
-endif
CFLAGS += -DNEED_AP_MLME
endif
ifdef CONFIG_WPS
@@ -635,6 +753,12 @@ CFLAGS += -DEAP_SERVER_WSC
OBJS += ../src/ap/wps_hostapd.o
OBJS += ../src/eap_server/eap_server_wsc.o
endif
+ifdef CONFIG_INTERWORKING
+OBJS += ../src/ap/gas_serv.o
+endif
+ifdef CONFIG_HS20
+OBJS += ../src/ap/hs20.o
+endif
endif
ifdef NEED_RSN_AUTHENTICATOR
@@ -707,6 +831,7 @@ endif
ifdef NEED_MILENAGE
OBJS += ../src/crypto/milenage.o
+NEED_AES_ENCBLOCK=y
endif
ifdef CONFIG_PKCS12
@@ -732,13 +857,26 @@ NEED_DES=y
# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, EAP_TTLS, and EAP_FAST)
OBJS += ../src/eap_peer/eap_tls_common.o
OBJS_h += ../src/eap_server/eap_server_tls_common.o
+ifndef CONFIG_FIPS
NEED_TLS_PRF=y
+NEED_SHA1=y
+NEED_MD5=y
+endif
endif
ifndef CONFIG_TLS
CONFIG_TLS=openssl
endif
+ifdef CONFIG_TLSV11
+CFLAGS += -DCONFIG_TLSV11
+endif
+
+ifdef CONFIG_TLSV12
+CFLAGS += -DCONFIG_TLSV12
+NEED_SHA256=y
+endif
+
ifeq ($(CONFIG_TLS), openssl)
ifdef TLS_FUNCS
CFLAGS += -DEAP_TLS_OPENSSL
@@ -752,16 +890,16 @@ OBJS += ../src/crypto/fips_prf_openssl.o
endif
LIBS += -lcrypto
LIBS_p += -lcrypto
+ifdef CONFIG_TLS_ADD_DL
+LIBS += -ldl
+LIBS_p += -ldl
+endif
endif
ifeq ($(CONFIG_TLS), gnutls)
ifdef TLS_FUNCS
OBJS += ../src/crypto/tls_gnutls.o
LIBS += -lgnutls -lgpg-error
-ifdef CONFIG_GNUTLS_EXTRA
-CFLAGS += -DCONFIG_GNUTLS_EXTRA
-LIBS += -lgnutls-extra
-endif
endif
OBJS += ../src/crypto/crypto_gnutls.o
OBJS_p += ../src/crypto/crypto_gnutls.o
@@ -827,6 +965,9 @@ OBJS += ../src/tls/pkcs8.o
NEED_SHA256=y
NEED_BASE64=y
NEED_TLS_PRF=y
+ifdef CONFIG_TLSV12
+NEED_TLS_PRF_SHA256=y
+endif
NEED_MODEXP=y
NEED_CIPHER=y
CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
@@ -932,8 +1073,12 @@ AESOBJS += ../src/crypto/aes-encblock.o
endif
ifdef NEED_AES_OMAC1
NEED_AES_ENC=y
+ifdef CONFIG_OPENSSL_CMAC
+CFLAGS += -DCONFIG_OPENSSL_CMAC
+else
AESOBJS += ../src/crypto/aes-omac1.o
endif
+endif
ifdef NEED_AES_WRAP
NEED_AES_ENC=y
AESOBJS += ../src/crypto/aes-wrap.o
@@ -952,16 +1097,23 @@ OBJS += $(AESOBJS)
endif
ifdef NEED_SHA1
+ifneq ($(CONFIG_TLS), openssl)
SHA1OBJS += ../src/crypto/sha1.o
+endif
+SHA1OBJS += ../src/crypto/sha1-prf.o
ifdef CONFIG_INTERNAL_SHA1
SHA1OBJS += ../src/crypto/sha1-internal.o
ifdef NEED_FIPS186_2_PRF
SHA1OBJS += ../src/crypto/fips_prf_internal.o
endif
endif
-ifndef CONFIG_NO_WPA_PASSPHRASE
+ifdef CONFIG_NO_WPA_PASSPHRASE
+CFLAGS += -DCONFIG_NO_PBKDF2
+else
+ifneq ($(CONFIG_TLS), openssl)
SHA1OBJS += ../src/crypto/sha1-pbkdf2.o
endif
+endif
ifdef NEED_T_PRF
SHA1OBJS += ../src/crypto/sha1-tprf.o
endif
@@ -970,14 +1122,13 @@ SHA1OBJS += ../src/crypto/sha1-tlsprf.o
endif
endif
-MD5OBJS = ../src/crypto/md5.o
+ifndef CONFIG_FIPS
+MD5OBJS += ../src/crypto/md5.o
+endif
ifdef NEED_MD5
ifdef CONFIG_INTERNAL_MD5
MD5OBJS += ../src/crypto/md5-internal.o
endif
-ifdef CONFIG_FIPS
-MD5OBJS += ../src/crypto/md5-non-fips.o
-endif
OBJS += $(MD5OBJS)
OBJS_p += $(MD5OBJS)
endif
@@ -1004,10 +1155,16 @@ endif
SHA256OBJS = # none by default
ifdef NEED_SHA256
CFLAGS += -DCONFIG_SHA256
+ifneq ($(CONFIG_TLS), openssl)
SHA256OBJS += ../src/crypto/sha256.o
+endif
+SHA256OBJS += ../src/crypto/sha256-prf.o
ifdef CONFIG_INTERNAL_SHA256
SHA256OBJS += ../src/crypto/sha256-internal.o
endif
+ifdef NEED_TLS_PRF_SHA256
+SHA256OBJS += ../src/crypto/sha256-tlsprf.o
+endif
OBJS += $(SHA256OBJS)
endif
@@ -1023,6 +1180,12 @@ OBJS += ../src/crypto/dh_group5.o
endif
endif
+ifdef CONFIG_NO_RANDOM_POOL
+CFLAGS += -DCONFIG_NO_RANDOM_POOL
+else
+OBJS += ../src/crypto/random.o
+endif
+
ifdef CONFIG_CTRL_IFACE
ifeq ($(CONFIG_CTRL_IFACE), y)
ifdef CONFIG_NATIVE_WINDOWS
@@ -1041,6 +1204,11 @@ endif
ifeq ($(CONFIG_CTRL_IFACE), named_pipe)
CFLAGS += -DCONFIG_CTRL_IFACE_NAMED_PIPE
endif
+ifeq ($(CONFIG_CTRL_IFACE), udp-remote)
+CONFIG_CTRL_IFACE=udp
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE
+endif
OBJS += ctrl_iface.o ctrl_iface_$(CONFIG_CTRL_IFACE).o
endif
@@ -1053,22 +1221,11 @@ DBUS_OBJS += dbus/dbus_old_handlers_wps.o
endif
DBUS_OBJS += dbus/dbus_dict_helpers.o
ifndef DBUS_LIBS
-DBUS_LIBS := $(shell pkg-config --libs dbus-1)
+DBUS_LIBS := $(shell $(PKG_CONFIG) --libs dbus-1)
endif
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
+DBUS_INCLUDE := $(shell $(PKG_CONFIG) --cflags dbus-1)
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)
DBUS_CFLAGS += $(DBUS_INCLUDE)
endif
@@ -1081,11 +1238,14 @@ DBUS_OBJS += dbus/dbus_new.o dbus/dbus_new_handlers.o
ifdef CONFIG_WPS
DBUS_OBJS += dbus/dbus_new_handlers_wps.o
endif
+ifdef CONFIG_P2P
+DBUS_OBJS += dbus/dbus_new_handlers_p2p.o
+endif
ifndef DBUS_LIBS
-DBUS_LIBS := $(shell pkg-config --libs dbus-1)
+DBUS_LIBS := $(shell $(PKG_CONFIG) --libs dbus-1)
endif
ifndef DBUS_INCLUDE
-DBUS_INCLUDE := $(shell pkg-config --cflags dbus-1)
+DBUS_INCLUDE := $(shell $(PKG_CONFIG) --cflags dbus-1)
endif
ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
DBUS_OBJS += dbus/dbus_new_introspect.o
@@ -1104,8 +1264,14 @@ CFLAGS += $(DBUS_CFLAGS)
LIBS += $(DBUS_LIBS)
ifdef CONFIG_READLINE
-CFLAGS += -DCONFIG_READLINE
+OBJS_c += ../src/utils/edit_readline.o
LIBS_c += -lncurses -lreadline
+else
+ifdef CONFIG_WPA_CLI_EDIT
+OBJS_c += ../src/utils/edit.o
+else
+OBJS_c += ../src/utils/edit_simple.o
+endif
endif
ifdef CONFIG_NATIVE_WINDOWS
@@ -1140,12 +1306,6 @@ OBJS += sme.o
CFLAGS += -DCONFIG_SME
endif
-ifdef CONFIG_CLIENT_MLME
-OBJS += mlme.o
-CFLAGS += -DCONFIG_CLIENT_MLME
-NEED_80211_COMMON=y
-endif
-
ifdef NEED_80211_COMMON
OBJS += ../src/common/ieee802_11_common.o
endif
@@ -1160,6 +1320,13 @@ endif
ifdef CONFIG_DEBUG_SYSLOG
CFLAGS += -DCONFIG_DEBUG_SYSLOG
+ifdef CONFIG_DEBUG_SYSLOG_FACILITY
+CFLAGS += -DLOG_HOSTAPD="$(CONFIG_DEBUG_SYSLOG_FACILITY)"
+endif
+endif
+
+ifdef CONFIG_DEBUG_LINUX_TRACING
+CFLAGS += -DCONFIG_DEBUG_LINUX_TRACING
endif
ifdef CONFIG_DEBUG_FILE
@@ -1172,11 +1339,15 @@ endif
ifdef CONFIG_FIPS
CFLAGS += -DCONFIG_FIPS
+ifneq ($(CONFIG_TLS), openssl)
+$(error CONFIG_FIPS=y requires CONFIG_TLS=openssl)
+endif
endif
OBJS += $(SHA1OBJS) $(DESOBJS)
OBJS_p += $(SHA1OBJS)
+OBJS_p += $(SHA256OBJS)
ifdef CONFIG_BGSCAN_SIMPLE
CFLAGS += -DCONFIG_BGSCAN_SIMPLE
@@ -1184,12 +1355,60 @@ OBJS += bgscan_simple.o
NEED_BGSCAN=y
endif
+ifdef CONFIG_BGSCAN_LEARN
+CFLAGS += -DCONFIG_BGSCAN_LEARN
+OBJS += bgscan_learn.o
+NEED_BGSCAN=y
+endif
+
ifdef NEED_BGSCAN
CFLAGS += -DCONFIG_BGSCAN
OBJS += bgscan.o
endif
-OBJS_wpa_rm := ctrl_iface.o mlme.o ctrl_iface_unix.o
+ifdef CONFIG_AUTOSCAN_EXPONENTIAL
+CFLAGS += -DCONFIG_AUTOSCAN_EXPONENTIAL
+OBJS += autoscan_exponential.o
+NEED_AUTOSCAN=y
+endif
+
+ifdef CONFIG_AUTOSCAN_PERIODIC
+CFLAGS += -DCONFIG_AUTOSCAN_PERIODIC
+OBJS += autoscan_periodic.o
+NEED_AUTOSCAN=y
+endif
+
+ifdef NEED_AUTOSCAN
+CFLAGS += -DCONFIG_AUTOSCAN
+OBJS += autoscan.o
+endif
+
+ifdef CONFIG_EXT_PASSWORD_TEST
+OBJS += ../src/utils/ext_password_test.o
+CFLAGS += -DCONFIG_EXT_PASSWORD_TEST
+NEED_EXT_PASSWORD=y
+endif
+
+ifdef NEED_EXT_PASSWORD
+OBJS += ../src/utils/ext_password.o
+CFLAGS += -DCONFIG_EXT_PASSWORD
+endif
+
+ifdef NEED_GAS
+OBJS += ../src/common/gas.o
+OBJS += gas_query.o
+CFLAGS += -DCONFIG_GAS
+NEED_OFFCHANNEL=y
+endif
+
+ifdef NEED_OFFCHANNEL
+OBJS += offchannel.o
+CFLAGS += -DCONFIG_OFFCHANNEL
+endif
+
+OBJS += ../src/drivers/driver_common.o
+
+OBJS_wpa_rm := ctrl_iface.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
@@ -1203,6 +1422,10 @@ ifndef CONFIG_AP
OBJS_t += ../src/utils/ip_addr.o
endif
OBJS_t2 := $(OBJS) $(OBJS_l2) preauth_test.o
+
+OBJS_nfc := $(OBJS) $(OBJS_l2) nfc_pw_token.o
+OBJS_nfc += $(OBJS_d) ../src/drivers/drivers.o
+
OBJS += $(CONFIG_MAIN).o
ifdef CONFIG_PRIVSEP
@@ -1214,6 +1437,9 @@ 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_NL80211
+OBJS_priv += ../src/common/ieee802_11_common.o
+endif
ifdef CONFIG_DRIVER_TEST
OBJS_priv += $(SHA1OBJS)
OBJS_priv += $(MD5OBJS)
@@ -1257,6 +1483,13 @@ ifndef LDO
LDO=$(CC)
endif
+Q=@
+E=echo
+ifeq ($(V), 1)
+Q=
+E=true
+endif
+
dynamic_eap_methods: $(EAPDYN)
../src/drivers/build.wpa_supplicant:
@@ -1268,31 +1501,46 @@ dynamic_eap_methods: $(EAPDYN)
BCHECK=../src/drivers/build.wpa_supplicant
wpa_priv: $(BCHECK) $(OBJS_priv)
- $(LDO) $(LDFLAGS) -o wpa_priv $(OBJS_priv) $(LIBS)
+ $(Q)$(LDO) $(LDFLAGS) -o wpa_priv $(OBJS_priv) $(LIBS)
+ @$(E) " LD " $@
+
+$(OBJS_c) $(OBJS_t) $(OBJS_t2) $(OBJS) $(BCHECK) $(EXTRA_progs): .config
-wpa_supplicant: .config $(BCHECK) $(OBJS) $(EXTRA_progs)
- $(LDO) $(LDFLAGS) -o wpa_supplicant $(OBJS) $(LIBS) $(EXTRALIBS)
+wpa_supplicant: $(BCHECK) $(OBJS) $(EXTRA_progs)
+ $(Q)$(LDO) $(LDFLAGS) -o wpa_supplicant $(OBJS) $(LIBS) $(EXTRALIBS)
+ @$(E) " LD " $@
-eapol_test: .config $(OBJS_t)
- $(LDO) $(LDFLAGS) -o eapol_test $(OBJS_t) $(LIBS)
+eapol_test: $(OBJS_t)
+ $(Q)$(LDO) $(LDFLAGS) -o eapol_test $(OBJS_t) $(LIBS)
+ @$(E) " LD " $@
-preauth_test: .config $(OBJS_t2)
- $(LDO) $(LDFLAGS) -o preauth_test $(OBJS_t2) $(LIBS)
+preauth_test: $(OBJS_t2)
+ $(Q)$(LDO) $(LDFLAGS) -o preauth_test $(OBJS_t2) $(LIBS)
+ @$(E) " LD " $@
wpa_passphrase: $(OBJS_p)
- $(LDO) $(LDFLAGS) -o wpa_passphrase $(OBJS_p) $(LIBS_p)
+ $(Q)$(LDO) $(LDFLAGS) -o wpa_passphrase $(OBJS_p) $(LIBS_p)
+ @$(E) " LD " $@
wpa_cli: $(OBJS_c)
- $(LDO) $(LDFLAGS) -o wpa_cli $(OBJS_c) $(LIBS_c)
+ $(Q)$(LDO) $(LDFLAGS) -o wpa_cli $(OBJS_c) $(LIBS_c)
+ @$(E) " LD " $@
link_test: $(OBJS) $(OBJS_h) tests/link_test.o
- $(LDO) $(LDFLAGS) -o link_test $(OBJS) $(OBJS_h) tests/link_test.o $(LIBS)
+ $(Q)$(LDO) $(LDFLAGS) -o link_test $(OBJS) $(OBJS_h) tests/link_test.o $(LIBS)
+ @$(E) " LD " $@
test_wpa: $(OBJS_wpa) $(OBJS_h)
- $(LDO) $(LDFLAGS) -o test_wpa $(OBJS_wpa) $(LIBS)
+ $(Q)$(LDO) $(LDFLAGS) -o test_wpa $(OBJS_wpa) $(LIBS)
+ @$(E) " LD " $@
+
+nfc_pw_token: $(OBJS_nfc)
+ $(Q)$(LDO) $(LDFLAGS) -o nfc_pw_token $(OBJS_nfc) $(LIBS)
+ @$(E) " LD " $@
win_if_list: win_if_list.c
- $(LDO) $(LDFLAGS) -o $@ win_if_list.c $(CFLAGS) $(LIBS_w)
+ $(Q)$(LDO) $(LDFLAGS) -o $@ win_if_list.c $(CFLAGS) $(LIBS_w)
+ @$(E) " LD " $@
eap_psk.so: ../src/eap_peer/eap_psk.c ../src/eap_common/eap_psk_common.c
$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
@@ -1318,17 +1566,16 @@ eap_ikev2.so: ../src/eap_peer/eap_ikev2.c ../src/eap_peer/ikev2.c ../src/eap_com
$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $< \
-D$(*F:eap_%=eap_peer_%)_register=eap_peer_method_dynamic_init
-Q=@
-E=echo
-ifeq ($(V), 1)
-Q=
-E=true
-endif
-
%.o: %.c
$(Q)$(CC) -c -o $@ $(CFLAGS) $<
@$(E) " CC " $<
+%.service: %.service.in
+ sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
+
+%@.service: %.service.arg.in
+ sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
+
wpa_supplicant.exe: wpa_supplicant
mv -f $< $@
wpa_cli.exe: wpa_cli
@@ -1345,11 +1592,8 @@ 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:
+ @echo "wpa_gui has been removed - see wpa_gui-qt4 for replacement"
wpa_gui-qt4/Makefile:
qmake -o wpa_gui-qt4/Makefile wpa_gui-qt4/wpa_gui.pro
@@ -1371,10 +1615,16 @@ test-eap_sim_common: $(TEST_EAP_SIM_COMMON_OBJS)
tests: test-eap_sim_common
+FIPSDIR=/usr/local/ssl/fips-2.0
+FIPSLD=$(FIPSDIR)/bin/fipsld
+fips:
+ $(MAKE) CC=$(FIPSLD) FIPSLD_CC="$(CC)"
+
clean:
$(MAKE) -C ../src clean
$(MAKE) -C dbus clean
rm -f core *~ *.o *.d eap_*.so $(ALL) $(WINALL) eapol_test preauth_test
rm -f wpa_priv
+ rm -f nfc_pw_token
-include $(OBJS:%.o=%.d)
diff --git a/wpa_supplicant/README b/wpa_supplicant/README
index 45c8bae150b3..a06e5c1fafa5 100644
--- a/wpa_supplicant/README
+++ b/wpa_supplicant/README
@@ -1,37 +1,22 @@
WPA Supplicant
==============
-Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2003-2012, 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 program is licensed under the BSD license (the one with
+advertisement clause removed).
+
+If you are submitting changes to the project, please see CONTRIBUTIONS
+file for more instructions.
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:
+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
@@ -138,55 +123,6 @@ Current hardware/software requirements:
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.
@@ -363,7 +299,7 @@ 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
+driver interfaces (e.g., nl80211, wext, ..) and which authentication
methods (e.g., EAP-TLS, EAP-PEAP, ..) are included.
Following build time configuration options are used to control IEEE
@@ -396,32 +332,18 @@ authentication algorithm (for EAP-SIM/EAP-AKA). This requires pcsc-lite
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).
+interfaces are included.
-CONFIG_DRIVER_HOSTAP=y
-CONFIG_DRIVER_HERMES=y
-CONFIG_DRIVER_MADWIFI=y
-CONFIG_DRIVER_ATMEL=y
+CONFIG_DRIVER_NL80211=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:
+Following example includes some more 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_NL80211=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_IEEE8021X_EAPOL=y
@@ -503,7 +425,7 @@ options:
-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)
+ -L = show license (BSD)
-p = driver parameters
-P = PID file
-q = decrease debugging verbosity (-qq even less)
@@ -514,16 +436,7 @@ options:
-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.) (deprecated; use wext)
- atmel = ATMEL AT76C5XXx (USB, PCMCIA)
wext = Linux wireless extensions (generic)
- ralink = Ralink Client driver
- ndiswrapper = Linux ndiswrapper (deprecated; use wext)
- 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.)
@@ -556,15 +469,15 @@ 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
+ -c wpa1.conf -i wlan0 -D nl80211 -N \
+ -c wpa2.conf -i wlan1 -D wext
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
+wpa_supplicant -cw.conf -Dwext -iwlan0 -bbr0
Configuration file
@@ -894,13 +807,14 @@ script:
IFNAME=$1
CMD=$2
-if [ "$CMD" == "CONNECTED" ]; then
+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
+if [ "$CMD" = "DISCONNECTED" ]; then
# remove network configuration, if needed
+ SSID=
fi
diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20
new file mode 100644
index 000000000000..5669c55c32d5
--- /dev/null
+++ b/wpa_supplicant/README-HS20
@@ -0,0 +1,475 @@
+wpa_supplicant and Hotspot 2.0
+==============================
+
+This document describe how the IEEE 802.11u Interworking and Wi-Fi
+Hotspot 2.0 (Release 1) implementation in wpa_supplicant can be
+configured and how an external component on the client e.g., management
+GUI or Wi-Fi framework) is used to manage this functionality.
+
+
+Introduction to Wi-Fi Hotspot 2.0
+---------------------------------
+
+Hotspot 2.0 is the name of the Wi-Fi Alliance specification that is used
+in the Wi-Fi CERTIFIED Passpoint<TM> program. More information about
+this is available in this white paper:
+
+http://www.wi-fi.org/knowledge-center/white-papers/wi-fi-certified-passpoint%E2%84%A2-new-program-wi-fi-alliance%C2%AE-enable-seamless
+
+The Hotspot 2.0 specification is also available from WFA:
+https://www.wi-fi.org/knowledge-center/published-specifications
+
+The core Interworking functionality (network selection, GAS/ANQP) were
+standardized in IEEE Std 802.11u-2011 which is now part of the IEEE Std
+802.11-2012.
+
+
+wpa_supplicant network selection
+--------------------------------
+
+Interworking support added option for configuring credentials that can
+work with multiple networks as an alternative to configuration of
+network blocks (e.g., per-SSID parameters). When requested to perform
+network selection, wpa_supplicant picks the highest priority enabled
+network block or credential. If a credential is picked (based on ANQP
+information from APs), a temporary network block is created
+automatically for the matching network. This temporary network block is
+used similarly to the network blocks that can be configured by the user,
+but it is not stored into the configuration file and is meant to be used
+only for temporary period of time since a new one can be created
+whenever needed based on ANQP information and the credential.
+
+By default, wpa_supplicant is not using automatic network selection
+unless requested explicitly with the interworking_select command. This
+can be changed with the auto_interworking=1 parameter to perform network
+selection automatically whenever trying to find a network for connection
+and none of the enabled network blocks match with the scan results. This
+case works similarly to "interworking_select auto", i.e., wpa_supplicant
+will internally determine which network or credential is going to be
+used based on configured priorities, scan results, and ANQP information.
+
+
+wpa_supplicant configuration
+----------------------------
+
+Interworking and Hotspot 2.0 functionality are optional components that
+need to be enabled in the wpa_supplicant build configuration
+(.config). This is done by adding following parameters into that file:
+
+CONFIG_INTERWORKING=y
+CONFIG_HS20=y
+
+It should be noted that this functionality requires a driver that
+supports GAS/ANQP operations. This uses the same design as P2P, i.e.,
+Action frame processing and building in user space within
+wpa_supplicant. The Linux nl80211 driver interface provides the needed
+functionality for this.
+
+
+There are number of run-time configuration parameters (e.g., in
+wpa_supplicant.conf when using the configuration file) that can be used
+to control Hotspot 2.0 operations.
+
+# Enable Interworking
+interworking=1
+
+# Enable Hotspot 2.0
+hs20=1
+
+# Parameters for controlling scanning
+
+# Homogenous ESS identifier
+# If this is set, scans will be used to request response only from BSSes
+# belonging to the specified Homogeneous ESS. This is used only if interworking
+# is enabled.
+#hessid=00:11:22:33:44:55
+
+# Access Network Type
+# When Interworking is enabled, scans can be limited to APs that advertise the
+# specified Access Network Type (0..15; with 15 indicating wildcard match).
+# This value controls the Access Network Type value in Probe Request frames.
+#access_network_type=15
+
+# Automatic network selection behavior
+# 0 = do not automatically go through Interworking network selection
+# (i.e., require explicit interworking_select command for this; default)
+# 1 = perform Interworking network selection if one or more
+# credentials have been configured and scan did not find a
+# matching network block
+#auto_interworking=0
+
+
+Credentials can be pre-configured for automatic network selection:
+
+# credential block
+#
+# Each credential used for automatic network selection is configured as a set
+# of parameters that are compared to the information advertised by the APs when
+# interworking_select and interworking_connect commands are used.
+#
+# credential fields:
+#
+# priority: Priority group
+# By default, all networks and credentials get the same priority group
+# (0). This field can be used to give higher priority for credentials
+# (and similarly in struct wpa_ssid for network blocks) to change the
+# Interworking automatic networking selection behavior. The matching
+# network (based on either an enabled network block or a credential)
+# with the highest priority value will be selected.
+#
+# pcsc: Use PC/SC and SIM/USIM card
+#
+# realm: Home Realm for Interworking
+#
+# username: Username for Interworking network selection
+#
+# password: Password for Interworking network selection
+#
+# ca_cert: CA certificate for Interworking network selection
+#
+# client_cert: File path to client certificate file (PEM/DER)
+# This field is used with Interworking networking selection for a case
+# where client certificate/private key is used for authentication
+# (EAP-TLS). 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.
+#
+# 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 to the file 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
+#
+# imsi: IMSI in <MCC> | <MNC> | '-' | <MSIN> format
+#
+# milenage: Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN>
+# format
+#
+# domain: Home service provider FQDN
+# This is used to compare against the Domain Name List to figure out
+# whether the AP is operated by the Home SP.
+#
+# roaming_consortium: Roaming Consortium OI
+# If roaming_consortium_len is non-zero, this field contains the
+# Roaming Consortium OI that can be used to determine which access
+# points support authentication with this credential. This is an
+# alternative to the use of the realm parameter. When using Roaming
+# Consortium to match the network, the EAP parameters need to be
+# pre-configured with the credential since the NAI Realm information
+# may not be available or fetched.
+#
+# eap: Pre-configured EAP method
+# This optional field can be used to specify which EAP method will be
+# used with this credential. If not set, the EAP method is selected
+# automatically based on ANQP information (e.g., NAI Realm).
+#
+# phase1: Pre-configure Phase 1 (outer authentication) parameters
+# This optional field is used with like the 'eap' parameter.
+#
+# phase2: Pre-configure Phase 2 (inner authentication) parameters
+# This optional field is used with like the 'eap' parameter.
+#
+# excluded_ssid: Excluded SSID
+# This optional field can be used to excluded specific SSID(s) from
+# matching with the network. Multiple entries can be used to specify more
+# than one SSID.
+#
+# for example:
+#
+#cred={
+# realm="example.com"
+# username="user@example.com"
+# password="password"
+# ca_cert="/etc/wpa_supplicant/ca.pem"
+# domain="example.com"
+#}
+#
+#cred={
+# imsi="310026-000000000"
+# milenage="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82"
+#}
+#
+#cred={
+# realm="example.com"
+# username="user"
+# password="password"
+# ca_cert="/etc/wpa_supplicant/ca.pem"
+# domain="example.com"
+# roaming_consortium=223344
+# eap=TTLS
+# phase2="auth=MSCHAPV2"
+#}
+
+
+Control interface
+-----------------
+
+wpa_supplicant provides a control interface that can be used from
+external programs to manage various operations. The included command
+line tool, wpa_cli, can be used for manual testing with this interface.
+
+Following wpa_cli interactive mode commands show some examples of manual
+operations related to Hotspot 2.0:
+
+Remove configured networks and credentials:
+
+> remove_network all
+OK
+> remove_cred all
+OK
+
+
+Add a username/password credential:
+
+> add_cred
+0
+> set_cred 0 realm "mail.example.com"
+OK
+> set_cred 0 username "username"
+OK
+> set_cred 0 password "password"
+OK
+> set_cred 0 priority 1
+OK
+
+Add a SIM credential using a simulated SIM/USIM card for testing:
+
+> add_cred
+1
+> set_cred 1 imsi "23456-0000000000"
+OK
+> set_cred 1 milenage "90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123"
+OK
+> set_cred 1 priority 1
+OK
+
+Note: the return value of add_cred is used as the first argument to
+the following set_cred commands.
+
+
+Add a WPA2-Enterprise network:
+
+> add_network
+0
+> set_network 0 key_mgmt WPA-EAP
+OK
+> set_network 0 ssid "enterprise"
+OK
+> set_network 0 eap TTLS
+OK
+> set_network 0 anonymous_identity "anonymous"
+OK
+> set_network 0 identity "user"
+OK
+> set_network 0 password "password"
+OK
+> set_network 0 priority 0
+OK
+> enable_network 0 no-connect
+OK
+
+
+Add an open network:
+
+> add_network
+3
+> set_network 3 key_mgmt NONE
+OK
+> set_network 3 ssid "coffee-shop"
+OK
+> select_network 3
+OK
+
+Note: the return value of add_network is used as the first argument to
+the following set_network commands.
+
+The preferred credentials/networks can be indicated with the priority
+parameter (1 is higher priority than 0).
+
+
+Interworking network selection can be started with interworking_select
+command. This instructs wpa_supplicant to run a network scan and iterate
+through the discovered APs to request ANQP information from the APs that
+advertise support for Interworking/Hotspot 2.0:
+
+> interworking_select
+OK
+<3>Starting ANQP fetch for 02:00:00:00:01:00
+<3>RX-ANQP 02:00:00:00:01:00 ANQP Capability list
+<3>RX-ANQP 02:00:00:00:01:00 Roaming Consortium list
+<3>RX-HS20-ANQP 02:00:00:00:01:00 HS Capability List
+<3>ANQP fetch completed
+<3>INTERWORKING-AP 02:00:00:00:01:00 type=unknown
+
+
+INTERWORKING-AP event messages indicate the APs that support network
+selection and for which there is a matching
+credential. interworking_connect command can be used to select a network
+to connect with:
+
+
+> interworking_connect 02:00:00:00:01:00
+OK
+<3>CTRL-EVENT-SCAN-RESULTS
+<3>SME: Trying to authenticate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz)
+<3>Trying to associate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz)
+<3>Associated with 02:00:00:00:01:00
+<3>CTRL-EVENT-EAP-STARTED EAP authentication started
+<3>CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=21
+<3>CTRL-EVENT-EAP-METHOD EAP vendor 0 method 21 (TTLS) selected
+<3>CTRL-EVENT-EAP-SUCCESS EAP authentication completed successfully
+<3>WPA: Key negotiation completed with 02:00:00:00:01:00 [PTK=CCMP GTK=CCMP]
+<3>CTRL-EVENT-CONNECTED - Connection to 02:00:00:00:01:00 completed (auth) [id=0 id_str=]
+
+
+wpa_supplicant creates a temporary network block for the selected
+network based on the configured credential and ANQP information from the
+AP:
+
+> list_networks
+network id / ssid / bssid / flags
+0 Example Network any [CURRENT]
+> get_network 0 key_mgmt
+WPA-EAP
+> get_network 0 eap
+TTLS
+
+
+Alternatively to using an external program to select the network,
+"interworking_select auto" command can be used to request wpa_supplicant
+to select which network to use based on configured priorities:
+
+
+> remove_network all
+OK
+<3>CTRL-EVENT-DISCONNECTED bssid=02:00:00:00:01:00 reason=1 locally_generated=1
+> interworking_select auto
+OK
+<3>Starting ANQP fetch for 02:00:00:00:01:00
+<3>RX-ANQP 02:00:00:00:01:00 ANQP Capability list
+<3>RX-ANQP 02:00:00:00:01:00 Roaming Consortium list
+<3>RX-HS20-ANQP 02:00:00:00:01:00 HS Capability List
+<3>ANQP fetch completed
+<3>INTERWORKING-AP 02:00:00:00:01:00 type=unknown
+<3>CTRL-EVENT-SCAN-RESULTS
+<3>SME: Trying to authenticate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz)
+<3>Trying to associate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz)
+<3>Associated with 02:00:00:00:01:00
+<3>CTRL-EVENT-EAP-STARTED EAP authentication started
+<3>CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=21
+<3>CTRL-EVENT-EAP-METHOD EAP vendor 0 method 21 (TTLS) selected
+<3>CTRL-EVENT-EAP-SUCCESS EAP authentication completed successfully
+<3>WPA: Key negotiation completed with 02:00:00:00:01:00 [PTK=CCMP GTK=CCMP]
+<3>CTRL-EVENT-CONNECTED - Connection to 02:00:00:00:01:00 completed (reauth) [id=0 id_str=]
+
+
+The connection status can be shown with the status command:
+
+> status
+bssid=02:00:00:00:01:00
+ssid=Example Network
+id=0
+mode=station
+pairwise_cipher=CCMP <--- link layer security indication
+group_cipher=CCMP
+key_mgmt=WPA2/IEEE 802.1X/EAP
+wpa_state=COMPLETED
+p2p_device_address=02:00:00:00:00:00
+address=02:00:00:00:00:00
+hs20=1 <--- HS 2.0 indication
+Supplicant PAE state=AUTHENTICATED
+suppPortStatus=Authorized
+EAP state=SUCCESS
+selectedMethod=21 (EAP-TTLS)
+EAP TLS cipher=AES-128-SHA
+EAP-TTLSv0 Phase2 method=PAP
+
+
+> status
+bssid=02:00:00:00:02:00
+ssid=coffee-shop
+id=3
+mode=station
+pairwise_cipher=NONE
+group_cipher=NONE
+key_mgmt=NONE
+wpa_state=COMPLETED
+p2p_device_address=02:00:00:00:00:00
+address=02:00:00:00:00:00
+
+
+Note: The Hotspot 2.0 indication is shown as "hs20=1" in the status
+command output. Link layer security is indicated with the
+pairwise_cipher (CCMP = secure, NONE = no encryption used).
+
+
+Also the scan results include the Hotspot 2.0 indication:
+
+> scan_results
+bssid / frequency / signal level / flags / ssid
+02:00:00:00:01:00 2412 -30 [WPA2-EAP-CCMP][ESS][HS20] Example Network
+
+
+ANQP information for the BSS can be fetched using the BSS command:
+
+> bss 02:00:00:00:01:00
+id=1
+bssid=02:00:00:00:01:00
+freq=2412
+beacon_int=100
+capabilities=0x0411
+qual=0
+noise=-92
+level=-30
+tsf=1345573286517276
+age=105
+ie=000f4578616d706c65204e6574776f726b010882848b960c1218240301012a010432043048606c30140100000fac040100000fac040100000fac0100007f04000000806b091e07010203040506076c027f006f1001531122331020304050010203040506dd05506f9a1000
+flags=[WPA2-EAP-CCMP][ESS][HS20]
+ssid=Example Network
+anqp_roaming_consortium=031122330510203040500601020304050603fedcba
+
+
+ANQP queries can also be requested with the anqp_get and hs20_anqp_get
+commands:
+
+> anqp_get 02:00:00:00:01:00 261
+OK
+<3>RX-ANQP 02:00:00:00:01:00 Roaming Consortium list
+> hs20_anqp_get 02:00:00:00:01:00 2
+OK
+<3>RX-HS20-ANQP 02:00:00:00:01:00 HS Capability List
+
+In addition, fetch_anqp command can be used to request similar set of
+ANQP queries to be done as is run as part of interworking_select:
+
+> scan
+OK
+<3>CTRL-EVENT-SCAN-RESULTS
+> fetch_anqp
+OK
+<3>Starting ANQP fetch for 02:00:00:00:01:00
+<3>RX-ANQP 02:00:00:00:01:00 ANQP Capability list
+<3>RX-ANQP 02:00:00:00:01:00 Roaming Consortium list
+<3>RX-HS20-ANQP 02:00:00:00:01:00 HS Capability List
+<3>ANQP fetch completed
diff --git a/wpa_supplicant/README-P2P b/wpa_supplicant/README-P2P
new file mode 100644
index 000000000000..5e98c959f947
--- /dev/null
+++ b/wpa_supplicant/README-P2P
@@ -0,0 +1,560 @@
+wpa_supplicant and Wi-Fi P2P
+============================
+
+This document describes how the Wi-Fi P2P 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 Wi-Fi P2P
+-------------------------
+
+TODO
+
+More information about Wi-Fi P2P is available from Wi-Fi Alliance:
+http://www.wi-fi.org/Wi-Fi_Direct.php
+
+
+wpa_supplicant implementation
+-----------------------------
+
+TODO
+
+
+wpa_supplicant configuration
+----------------------------
+
+Wi-Fi P2P is an optional component that needs to be enabled in the
+wpa_supplicant build configuration (.config). Here is an example
+configuration that includes Wi-Fi P2P support and Linux nl80211
+-based driver interface:
+
+CONFIG_DRIVER_NL80211=y
+CONFIG_CTRL_IFACE=y
+CONFIG_P2P=y
+CONFIG_AP=y
+CONFIG_WPS=y
+
+
+In run-time configuration file (wpa_supplicant.conf), some parameters
+for P2P may be set. In order to make the devices easier to recognize,
+device_name and device_type should be specified. For example,
+something like this should be included:
+
+ctrl_interface=/var/run/wpa_supplicant
+device_name=My P2P Device
+device_type=1-0050F204-1
+
+
+wpa_cli
+-------
+
+Actual Wi-Fi P2P operations are requested during runtime. These can be
+done for example using wpa_cli (which is described below) or a GUI
+like wpa_gui-qt4.
+
+
+wpa_cli starts in interactive mode if no command string is included on
+the command line. By default, it will select the first network interface
+that it can find (and that wpa_supplicant controls). If more than one
+interface is in use, it may be necessary to select one of the explicitly
+by adding -i argument on the command line (e.g., 'wpa_cli -i wlan1').
+
+Most of the P2P operations are done on the main interface (e.g., the
+interface that is automatically added when the driver is loaded, e.g.,
+wlan0). When using a separate virtual interface for group operations
+(e.g., wlan1), the control interface for that group interface may need
+to be used for some operations (mainly WPS activation in GO). This may
+change in the future so that all the needed operations could be done
+over the main control interface.
+
+Device Discovery
+
+p2p_find [timeout in seconds] [type=<social|progressive>] \
+ [dev_id=<addr>] [delay=<search delay in ms>]
+
+The default behavior is to run a single full scan in the beginning and
+then scan only social channels. type=social will scan only social
+channels, i.e., it skips the initial full scan. type=progressive is
+like the default behavior, but it will scan through all the channels
+progressively one channel at the time in the Search state rounds. This
+will help in finding new groups or groups missed during the initial
+full scan.
+
+The optional dev_id option can be used to specify a single P2P peer to
+search for. The optional delay parameter can be used to request an extra
+delay to be used between search iterations (e.g., to free up radio
+resources for concurrent operations).
+
+p2p_listen [timeout in seconds]
+
+Start Listen-only state (become discoverable without searching for
+other devices). Optional parameter can be used to specify the duration
+for the Listen operation in seconds. This command may not be of that
+much use during normal operations and is mainly designed for
+testing. It can also be used to keep the device discoverable without
+having to maintain a group.
+
+p2p_stop_find
+
+Stop ongoing P2P device discovery or other operation (connect, listen
+mode).
+
+p2p_flush
+
+Flush P2P peer table and state.
+
+Group Formation
+
+p2p_prov_disc <peer device address> <display|keypad|pbc> [join|auto]
+
+Send P2P provision discovery request to the specified peer. The
+parameters for this command are the P2P device address of the peer and
+the desired configuration method. For example, "p2p_prov_disc
+02:01:02:03:04:05 display" would request the peer to display a PIN for
+us and "p2p_prov_disc 02:01:02:03:04:05 keypad" would request the peer
+to enter a PIN that we display.
+
+The optional "join" parameter can be used to indicate that this command
+is requesting an already running GO to prepare for a new client. This is
+mainly used with "display" to request it to display a PIN. The "auto"
+parameter can be used to request wpa_supplicant to automatically figure
+out whether the peer device is operating as a GO and if so, use
+join-a-group style PD instead of GO Negotiation style PD.
+
+p2p_connect <peer device address> <pbc|pin|PIN#> [display|keypad]
+ [persistent|persistent=<network id>] [join|auth]
+ [go_intent=<0..15>] [freq=<in MHz>] [ht40] [provdisc]
+
+Start P2P group formation with a discovered P2P peer. This includes
+optional group owner negotiation, group interface setup, provisioning,
+and establishing data connection.
+
+The <pbc|pin|PIN#> parameter specifies the WPS provisioning
+method. "pbc" string starts pushbutton method, "pin" string start PIN
+method using an automatically generated PIN (which will be returned as
+the command return code), PIN# means that a pre-selected PIN can be
+used (e.g., 12345670). [display|keypad] is used with PIN method
+to specify which PIN is used (display=dynamically generated random PIN
+from local display, keypad=PIN entered from peer display). "persistent"
+parameter can be used to request a persistent group to be formed. The
+"persistent=<network id>" alternative can be used to pre-populate
+SSID/passphrase configuration based on a previously used persistent
+group where this device was the GO. The previously used parameters will
+then be used if the local end becomes the GO in GO Negotiation (which
+can be forced with go_intent=15).
+
+"join" indicates that this is a command to join an existing group as a
+client. It skips the GO Negotiation part. This will send a Provision
+Discovery Request message to the target GO before associating for WPS
+provisioning.
+
+"auth" indicates that the WPS parameters are authorized for the peer
+device without actually starting GO Negotiation (i.e., the peer is
+expected to initiate GO Negotiation). This is mainly for testing
+purposes.
+
+"go_intent" can be used to override the default GO Intent for this GO
+Negotiation.
+
+"freq" can be used to set a forced operating channel (e.g., freq=2412
+to select 2.4 GHz channel 1).
+
+"provdisc" can be used to request a Provision Discovery exchange to be
+used prior to starting GO Negotiation as a workaround with some deployed
+P2P implementations that require this to allow the user to accept the
+connection.
+
+p2p_group_add [persistent|persistent=<network id>] [freq=<freq in MHz>] [ht40]
+
+Set up a P2P group owner manually (i.e., without group owner
+negotiation with a specific peer). This is also known as autonomous
+GO. Optional persistent=<network id> can be used to specify restart of
+a persistent group. Optional freq=<freq in MHz> can be used to force
+the GO to be started on a specific frequency. Special freq=2 or freq=5
+options can be used to request the best 2.4 GHz or 5 GHz band channel
+to be selected automatically.
+
+p2p_reject <peer device address>
+
+Reject connection attempt from a peer (specified with a device
+address). This is a mechanism to reject a pending GO Negotiation with
+a peer and request to automatically block any further connection or
+discovery of the peer.
+
+p2p_group_remove <group interface>
+
+Terminate a P2P group. If a new virtual network interface was used for
+the group, it will also be removed. The network interface name of the
+group interface is used as a parameter for this command.
+
+p2p_cancel
+
+Cancel an ongoing P2P group formation and joining-a-group related
+operation. This operations unauthorizes the specific peer device (if any
+had been authorized to start group formation), stops P2P find (if in
+progress), stops pending operations for join-a-group, and removes the
+P2P group interface (if one was used) that is in the WPS provisioning
+step. If the WPS provisioning step has been completed, the group is not
+terminated.
+
+Service Discovery
+
+p2p_serv_disc_req
+
+Schedule a P2P service discovery request. The parameters for this
+command are the device address of the peer device (or 00:00:00:00:00:00
+for wildcard query that is sent to every discovered P2P peer that
+supports service discovery) and P2P Service Query TLV(s) as hexdump. For
+example,
+
+p2p_serv_disc_req 00:00:00:00:00:00 02000001
+
+schedules a request for listing all available services of all service
+discovery protocols and requests this to be sent to all discovered
+peers (note: this can result in long response frames). The pending
+requests are sent during device discovery (see p2p_find).
+
+Only a single pending wildcard query is supported, but there can be
+multiple pending peer device specific queries (each will be sent in
+sequence whenever the peer is found).
+
+This command returns an identifier for the pending query (e.g.,
+"1f77628") that can be used to cancel the request. Directed requests
+will be automatically removed when the specified peer has replied to
+it.
+
+For UPnP, an alternative command format can be used to specify a
+single query TLV (i.e., a service discovery for a specific UPnP
+service):
+
+p2p_serv_disc_req 00:00:00:00:00:00 upnp <version hex> <ST: from M-SEARCH>
+
+For example:
+
+p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 urn:schemas-upnp-org:device:InternetGatewayDevice:1
+
+Additional examples for queries:
+
+# list of all Bonjour services
+p2p_serv_disc_req 00:00:00:00:00:00 02000101
+
+# list of all UPnP services
+p2p_serv_disc_req 00:00:00:00:00:00 02000201
+
+# list of all WS-Discovery services
+p2p_serv_disc_req 00:00:00:00:00:00 02000301
+
+# list of all Bonjour and UPnP services
+p2p_serv_disc_req 00:00:00:00:00:00 0200010102000202
+
+# Apple File Sharing over TCP
+p2p_serv_disc_req 00:00:00:00:00:00 130001010b5f6166706f766572746370c00c000c01
+
+# Bonjour SSTH (supported service type hash)
+p2p_serv_disc_req 00:00:00:00:00:00 05000101000000
+
+# UPnP examples
+p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 ssdp:all
+p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 upnp:rootdevice
+p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 urn:schemas-upnp-org:service:ContentDirectory:2
+p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 uuid:6859dede-8574-59ab-9332-123456789012
+p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 urn:schemas-upnp-org:device:InternetGatewayDevice:1
+
+# Wi-Fi Display examples
+# format: wifi-display <list of roles> <list of subelements>
+p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source] 2,3,4,5
+p2p_serv_disc_req 02:01:02:03:04:05 wifi-display [pri-sink] 3
+p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [sec-source] 2
+p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source+sink] 2,3,4,5
+p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source][pri-sink] 2,3,4,5
+
+p2p_serv_disc_cancel_req <query identifier>
+
+Cancel a pending P2P service discovery request. This command takes a
+single parameter: identifier for the pending query (the value returned
+by p2p_serv_disc_req, e.g., "p2p_serv_disc_cancel_req 1f77628".
+
+p2p_serv_disc_resp
+
+Reply to a service discovery query. This command takes following
+parameters: frequency in MHz, destination address, dialog token,
+response TLV(s). The first three parameters are copied from the
+request event. For example, "p2p_serv_disc_resp 2437 02:40:61:c2:f3:b7
+1 0300000101". This command is used only if external program is used
+to process the request (see p2p_serv_disc_external).
+
+p2p_service_update
+
+Indicate that local services have changed. This is used to increment
+the P2P service indicator value so that peers know when previously
+cached information may have changed. This is only needed when external
+service discovery processing is enabled since the commands to
+pre-configure services for internal processing will increment the
+indicator automatically.
+
+p2p_serv_disc_external <0|1>
+
+Configure external processing of P2P service requests: 0 (default) =
+no external processing of requests (i.e., internal code will process
+each request based on pre-configured services), 1 = external
+processing of requests (external program is responsible for replying
+to service discovery requests with p2p_serv_disc_resp). Please note
+that there is quite strict limit on how quickly the response needs to
+be transmitted, so use of the internal processing is strongly
+recommended.
+
+p2p_service_add bonjour <query hexdump> <RDATA hexdump>
+
+Add a local Bonjour service for internal SD query processing.
+
+Examples:
+
+# AFP Over TCP (PTR)
+p2p_service_add bonjour 0b5f6166706f766572746370c00c000c01 074578616d706c65c027
+# AFP Over TCP (TXT) (RDATA=null)
+p2p_service_add bonjour 076578616d706c650b5f6166706f766572746370c00c001001 00
+
+# IP Printing over TCP (PTR) (RDATA=MyPrinter._ipp._tcp.local.)
+p2p_service_add bonjour 045f697070c00c000c01 094d795072696e746572c027
+# IP Printing over TCP (TXT) (RDATA=txtvers=1,pdl=application/postscript)
+p2p_service_add bonjour 096d797072696e746572045f697070c00c001001 09747874766572733d311a70646c3d6170706c69636174696f6e2f706f7374736372797074
+
+# Supported Service Type Hash (SSTH)
+p2p_service_add bonjour 000000 <32-byte bitfield as hexdump>
+(note: see P2P spec Annex E.4 for information on how to construct the bitfield)
+
+p2p_service_del bonjour <query hexdump>
+
+Remove a local Bonjour service from internal SD query processing.
+
+p2p_service_add upnp <version hex> <service>
+
+Add a local UPnP service for internal SD query processing.
+
+Examples:
+
+p2p_service_add upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice
+p2p_service_add upnp 10 uuid:5566d33e-9774-09ab-4822-333456785632::upnp:rootdevice
+p2p_service_add upnp 10 uuid:1122de4e-8574-59ab-9322-333456789044::urn:schemas-upnp-org:service:ContentDirectory:2
+p2p_service_add upnp 10 uuid:5566d33e-9774-09ab-4822-333456785632::urn:schemas-upnp-org:service:ContentDirectory:2
+p2p_service_add upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::urn:schemas-upnp-org:device:InternetGatewayDevice:1
+
+p2p_service_del upnp <version hex> <service>
+
+Remove a local UPnP service from internal SD query processing.
+
+p2p_service_flush
+
+Remove all local services from internal SD query processing.
+
+Invitation
+
+p2p_invite [persistent=<network id>|group=<group ifname>] [peer=address]
+ [go_dev_addr=address] [freq=<freq in MHz>] [ht40]
+
+Invite a peer to join a group (e.g., group=wlan1) or to reinvoke a
+persistent group (e.g., persistent=4). If the peer device is the GO of
+the persistent group, the peer parameter is not needed. Otherwise it is
+used to specify which device to invite. go_dev_addr parameter can be
+used to override the GO device address for Invitation Request should
+it be not known for some reason (this should not be needed in most
+cases). When reinvoking a persistent group, the GO device can specify
+the frequency for the group with the freq parameter.
+
+Group Operations
+
+(These are used on the group interface.)
+
+wps_pin <any|address> <PIN>
+
+Start WPS PIN method. This allows a single WPS Enrollee to connect to
+the AP/GO. This is used on the GO when a P2P client joins an existing
+group. The second parameter is the address of the Enrollee or a string
+"any" to allow any station to use the entered PIN (which will restrict
+the PIN for one-time-use). PIN is the Enrollee PIN read either from a
+label or display on the P2P Client/WPS Enrollee.
+
+wps_pbc
+
+Start WPS PBC method (i.e., push the button). This allows a single WPS
+Enrollee to connect to the AP/GO. This is used on the GO when a P2P
+client joins an existing group.
+
+p2p_get_passphrase
+
+Get the passphrase for a group (only available when acting as a GO).
+
+p2p_presence_req [<duration> <interval>] [<duration> <interval>]
+
+Send a P2P Presence Request to the GO (this is only available when
+acting as a P2P client). If no duration/interval pairs are given, the
+request indicates that this client has no special needs for GO
+presence. the first parameter pair gives the preferred duration and
+interval values in microseconds. If the second pair is included, that
+indicates which value would be acceptable.
+
+Parameters
+
+p2p_ext_listen [<period> <interval>]
+
+Configure Extended Listen Timing. If the parameters are omitted, this
+feature is disabled. If the parameters are included, Listen State will
+be entered every interval msec for at least period msec. Both values
+have acceptable range of 1-65535 (with interval obviously having to be
+larger than or equal to duration). If the P2P module is not idle at
+the time the Extended Listen Timing timeout occurs, the Listen State
+operation will be skipped.
+
+The configured values will also be advertised to other P2P Devices. The
+received values are available in the p2p_peer command output:
+
+ext_listen_period=100 ext_listen_interval=5000
+
+p2p_set <field> <value>
+
+Change dynamic P2P parameters
+
+p2p_set discoverability <0/1>
+
+Disable/enable advertisement of client discoverability. This is
+enabled by default and this parameter is mainly used to allow testing
+of device discoverability.
+
+p2p_set managed <0/1>
+
+Disable/enable managed P2P Device operations. This is disabled by
+default.
+
+p2p_set listen_channel <1/6/11>
+
+Set P2P Listen channel. This is mainly meant for testing purposes and
+changing the Listen channel during normal operations can result in
+protocol failures.
+
+p2p_set ssid_postfix <postfix>
+
+Set postfix string to be added to the automatically generated P2P SSID
+(DIRECT-<two random characters>). For example, postfix of "-testing"
+could result in the SSID becoming DIRECT-ab-testing.
+
+set <field> <value>
+
+Set global configuration parameters which may also affect P2P
+operations. The format on these parameters is same as is used in
+wpa_supplicant.conf. Only the parameters listen here should be
+changed. Modifying other parameters may result in incorrect behavior
+since not all existing users of the parameters are updated.
+
+set uuid <UUID>
+
+Set WPS UUID (by default, this is generated based on the MAC address).
+
+set device_name <device name>
+
+Set WPS Device Name (also included in some P2P messages).
+
+set manufacturer <manufacturer>
+
+Set WPS Manufacturer.
+
+set model_name <model name>
+
+Set WPS Model Name.
+
+set model_number <model number>
+
+Set WPS Model Number.
+
+set serial_number <serial number>
+
+Set WPS Serial Number.
+
+set device_type <device type>
+
+Set WPS Device Type.
+
+set os_version <OS version>
+
+Set WPS OS Version.
+
+set config_methods <config methods>
+
+Set WPS Configuration Methods.
+
+set sec_device_type <device type>
+
+Add a new Secondary Device Type.
+
+set p2p_go_intent <GO intent>
+
+Set the default P2P GO Intent. Note: This value can be overridden in
+p2p_connect command and as such, there should be no need to change the
+default value here during normal operations.
+
+set p2p_ssid_postfix <P2P SSID postfix>
+
+Set P2P SSID postfix.
+
+set persistent_reconnect <0/1>
+
+Disable/enabled persistent reconnect for reinvocation of persistent
+groups. If enabled, invitations to reinvoke a persistent group will be
+accepted without separate authorization (e.g., user interaction).
+
+set country <two character country code>
+
+Set country code (this is included in some P2P messages).
+
+Status
+
+p2p_peers [discovered]
+
+List P2P Device Addresses of all the P2P peers we know. The optional
+"discovered" parameter filters out the peers that we have not fully
+discovered, i.e., which we have only seen in a received Probe Request
+frame.
+
+p2p_peer <P2P Device Address>
+
+Fetch information about a known P2P peer.
+
+Group Status
+
+(These are used on the group interface.)
+
+status
+
+Show status information (connection state, role, use encryption
+parameters, IP address, etc.).
+
+sta
+
+Show information about an associated station (when acting in AP/GO role).
+
+all_sta
+
+Lists the currently associated stations.
+
+Configuration data
+
+list_networks
+
+Lists the configured networks, including stored information for
+persistent groups. The identifier in this list is used with
+p2p_group_add and p2p_invite to indicate which persistent group is to
+be reinvoked.
+
+remove_network <network id>
+
+Remove a network entry from configuration.
+
+
+wpa_cli action script
+---------------------
+
+See examples/p2p-action.sh
+
+TODO: describe DHCP/DNS setup
+TODO: cross-connection
diff --git a/wpa_supplicant/README-WPS b/wpa_supplicant/README-WPS
index 8f0d0d6e6b3c..1ea98432f88f 100644
--- a/wpa_supplicant/README-WPS
+++ b/wpa_supplicant/README-WPS
@@ -47,9 +47,7 @@ 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.
+configure an AP.
wpa_supplicant configuration
@@ -57,11 +55,21 @@ 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:
+configuration that includes WPS support and Linux nl80211 -based
+driver interface:
-CONFIG_DRIVER_WEXT=y
+CONFIG_DRIVER_NL80211=y
CONFIG_WPS=y
+CONFIG_WPS2=y
+
+If you want to enable WPS external registrar (ER) functionality, you
+will also need to add following line:
+
+CONFIG_WPS_ER=y
+
+Following parameter can be used to enable support for NFC config method:
+
+CONFIG_WPS_NFC=y
WPS needs the Universally Unique IDentifier (UUID; see RFC 4122) for
@@ -93,6 +101,13 @@ 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.
+The PIN value used in the commands must be processed by an UI to
+remove non-digit characters and potentially, to verify the checksum
+digit. "wpa_cli wps_check_pin <PIN>" can be used to do such processing.
+It returns FAIL if the PIN is invalid, or FAIL-CHECKSUM if the checksum
+digit is incorrect, or the processed PIN (non-digit characters removed)
+if the PIN is valid.
+
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:
@@ -115,6 +130,17 @@ wpa_cli wps_pin any 12345670
This starts the WPS negotiation in the same way as above with the
generated PIN.
+When the wps_pin command is issued for an AP (including P2P GO) mode
+interface, an optional timeout parameter can be used to specify
+expiration timeout for the PIN in seconds. For example:
+
+wpa_cli wps_pin any 12345670 300
+
+
+If a random PIN is needed for a user interface, "wpa_cli wps_pin get"
+can be used to generate a new PIN without starting WPS negotiation.
+This random PIN can then be passed as an argument to another wps_pin
+call when the actual operation should be started.
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
@@ -198,3 +224,154 @@ 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
+
+
+wpa_supplicant as WPS External Registrar (ER)
+---------------------------------------------
+
+wpa_supplicant can be used as a WPS ER to configure an AP or enroll
+new Enrollee to join the network. This functionality uses UPnP and
+requires that a working IP connectivity is available with the AP (this
+can be either over a wired or wireless connection).
+
+Separate wpa_supplicant process can be started for WPS ER
+operations. A special "none" driver can be used in such a case to
+indicate that no local network interface is actually controlled. For
+example, following command could be used to start the ER:
+
+wpa_supplicant -Dnone -c er.conf -ieth0
+
+Sample er.conf:
+
+ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=admin
+device_name=WPS External Registrar
+
+
+wpa_cli commands for ER functionality:
+
+wps_er_start [IP address]
+- start WPS ER functionality
+- the optional IP address parameter can be used to filter operations only
+ to include a single AP
+- if run again while ER is active, the stored information (discovered APs
+ and Enrollees) are shown again
+
+wps_er_stop
+- stop WPS ER functionality
+
+wps_er_learn <UUID> <AP PIN>
+- learn AP configuration
+
+wps_er_set_config <UUID> <network id>
+- use AP configuration from a locally configured network (e.g., from
+ wps_reg command); this does not change the AP's configuration, but
+ only prepares a configuration to be used when enrolling a new device
+ to the AP
+
+wps_er_config <UUID> <AP PIN> <new SSID> <auth> <encr> <new key>
+- examples:
+ wps_er_config 87654321-9abc-def0-1234-56789abc0002 12345670 testing WPA2PSK CCMP 12345678
+ wpa_er_config 87654321-9abc-def0-1234-56789abc0002 12345670 clear OPEN NONE ""
+
+<auth> must be one of the following: OPEN WPAPSK WPA2PSK
+<encr> must be one of the following: NONE WEP TKIP CCMP
+
+
+wps_er_pbc <Enrollee UUID>
+- accept an Enrollee PBC using External Registrar
+
+wps_er_pin <Enrollee UUID> <PIN> [Enrollee MAC address]
+- add an Enrollee PIN to External Registrar
+- if Enrollee UUID is not known, "any" can be used to add a wildcard PIN
+- if the MAC address of the enrollee is known, it should be configured
+ to allow the AP to advertise list of authorized enrollees
+
+
+WPS ER events:
+
+WPS_EVENT_ER_AP_ADD
+- WPS ER discovered an AP
+
+WPS-ER-AP-ADD 87654321-9abc-def0-1234-56789abc0002 02:11:22:33:44:55 pri_dev_type=6-0050F204-1 wps_state=1 |Very friendly name|Company|Long description of the model|WAP|http://w1.fi/|http://w1.fi/hostapd/
+
+WPS_EVENT_ER_AP_REMOVE
+- WPS ER removed an AP entry
+
+WPS-ER-AP-REMOVE 87654321-9abc-def0-1234-56789abc0002
+
+WPS_EVENT_ER_ENROLLEE_ADD
+- WPS ER discovered a new Enrollee
+
+WPS-ER-ENROLLEE-ADD 2b7093f1-d6fb-5108-adbb-bea66bb87333 02:66:a0:ee:17:27 M1=1 config_methods=0x14d dev_passwd_id=0 pri_dev_type=1-0050F204-1 |Wireless Client|Company|cmodel|123|12345|
+
+WPS_EVENT_ER_ENROLLEE_REMOVE
+- WPS ER removed an Enrollee entry
+
+WPS-ER-ENROLLEE-REMOVE 2b7093f1-d6fb-5108-adbb-bea66bb87333 02:66:a0:ee:17:27
+
+WPS-ER-AP-SETTINGS
+- WPS ER learned AP settings
+
+WPS-ER-AP-SETTINGS uuid=fd91b4ec-e3fa-5891-a57d-8c59efeed1d2 ssid=test-wps auth_type=0x0020 encr_type=0x0008 key=12345678
+
+
+WPS with NFC
+------------
+
+WPS can be used with NFC-based configuration method. An NFC tag
+containing a password token from the Enrollee can be used to
+authenticate the connection instead of the PIN. In addition, an NFC tag
+with a configuration token can be used to transfer AP settings without
+going through the WPS protocol.
+
+When the station acts as an Enrollee, a local NFC tag with a password
+token can be used by touching the NFC interface of a Registrar.
+
+"wps_nfc [BSSID]" command starts WPS protocol run with the local end as
+the Enrollee using the NFC password token that is either pre-configured
+in the configuration file (wps_nfc_dev_pw_id, wps_nfc_dh_pubkey,
+wps_nfc_dh_privkey, wps_nfc_dev_pw) or generated dynamically with
+"wps_nfc_token <WPS|NDEF>" command. The included nfc_pw_token tool
+(build with "make nfc_pw_token") can be used to generate NFC password
+tokens during manufacturing (each station needs to have its own random
+keys).
+
+If the station includes NFC interface and reads an NFC tag with a MIME
+media type "application/vnd.wfa.wsc", the NDEF message payload (with or
+without NDEF encapsulation) can be delivered to wpa_supplicant using the
+following wpa_cli command:
+
+wps_nfc_tag_read <hexdump of payload>
+
+If the NFC tag contains a configuration token, the network is added to
+wpa_supplicant configuration. If the NFC tag contains a password token,
+the token is added to the WPS Registrar component. This information can
+then be used with wps_reg command (when the NFC password token was from
+an AP) using a special value "nfc-pw" in place of the PIN parameter. If
+the ER functionality has been started (wps_er_start), the NFC password
+token is used to enable enrollment of a new station (that was the source
+of the NFC password token).
+
+"nfc_get_handover_req <NDEF> <WPS>" command can be used to build the
+contents of a Handover Request Message for connection handover. The
+first argument selects the format of the output data and the second
+argument selects which type of connection handover is requested (WPS =
+Wi-Fi handover as specified in WSC 2.0).
+
+"nfc_get_handover_sel <NDEF> <WPS>" command can be used to build the
+contents of a Handover Select Message for connection handover when this
+does not depend on the contents of the Handover Request Message. The
+first argument selects the format of the output data and the second
+argument selects which type of connection handover is requested (WPS =
+Wi-Fi handover as specified in WSC 2.0).
+
+"nfc_rx_handover_req <hexdump of payload>" is used to indicate receipt
+of NFC connection handover request. The payload may include multiple
+carriers the the applicable ones are matched based on the media
+type. The reply data is contents for the Handover Select Message
+(hexdump).
+
+"nfc_rx_handover_sel <hexdump of payload>" is used to indicate receipt
+of NFC connection handover select. The payload may include multiple
+carriers the the applicable ones are matched based on the media
+type.
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 2b939847541b..c1e4acf5b8bd 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -3,37 +3,42 @@
* Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2009, Atheros Communications
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/uuid.h"
#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
#include "ap/hostapd.h"
#include "ap/ap_config.h"
+#include "ap/ap_drv_ops.h"
#ifdef NEED_AP_MLME
#include "ap/ieee802_11.h"
#endif /* NEED_AP_MLME */
+#include "ap/beacon.h"
#include "ap/ieee802_1x.h"
#include "ap/wps_hostapd.h"
#include "ap/ctrl_iface_ap.h"
-#include "eap_common/eap_defs.h"
-#include "eap_server/eap_methods.h"
-#include "eap_common/eap_wsc_common.h"
#include "wps/wps.h"
+#include "common/ieee802_11_defs.h"
#include "config_ssid.h"
#include "config.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
+#include "p2p_supplicant.h"
#include "ap.h"
+#include "ap/sta_info.h"
+#include "notify.h"
+
+
+#ifdef CONFIG_WPS
+static void wpas_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
+#endif /* CONFIG_WPS */
static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
@@ -58,39 +63,154 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
(ssid->frequency >= 5745 && ssid->frequency <= 5825)) {
conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
conf->channel = (ssid->frequency - 5000) / 5;
+ } else if (ssid->frequency >= 56160 + 2160 * 1 &&
+ ssid->frequency <= 56160 + 2160 * 4) {
+ conf->hw_mode = HOSTAPD_MODE_IEEE80211AD;
+ conf->channel = (ssid->frequency - 56160) / 2160;
} else {
wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: %d MHz",
ssid->frequency);
return -1;
}
- /* TODO: enable HT if driver supports it;
+ /* TODO: enable HT40 if driver supports it;
* drop to 11b if driver does not support 11g */
+#ifdef CONFIG_IEEE80211N
+ /*
+ * Enable HT20 if the driver supports it, by setting conf->ieee80211n
+ * and a mask of allowed capabilities within conf->ht_capab.
+ * Using default config settings for: conf->ht_op_mode_fixed,
+ * conf->secondary_channel, conf->require_ht
+ */
+ if (wpa_s->hw.modes) {
+ struct hostapd_hw_modes *mode = NULL;
+ int i, no_ht = 0;
+ for (i = 0; i < wpa_s->hw.num_modes; i++) {
+ if (wpa_s->hw.modes[i].mode == conf->hw_mode) {
+ mode = &wpa_s->hw.modes[i];
+ break;
+ }
+ }
+
+#ifdef CONFIG_HT_OVERRIDES
+ if (ssid->disable_ht) {
+ conf->ieee80211n = 0;
+ conf->ht_capab = 0;
+ no_ht = 1;
+ }
+#endif /* CONFIG_HT_OVERRIDES */
+
+ if (!no_ht && mode && mode->ht_capab) {
+ conf->ieee80211n = 1;
+#ifdef CONFIG_P2P
+ if (conf->hw_mode == HOSTAPD_MODE_IEEE80211A &&
+ (mode->ht_capab &
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
+ ssid->ht40)
+ conf->secondary_channel =
+ wpas_p2p_get_ht40_mode(wpa_s, mode,
+ conf->channel);
+ if (conf->secondary_channel)
+ conf->ht_capab |=
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
+#endif /* CONFIG_P2P */
+
+ /*
+ * white-list capabilities that won't cause issues
+ * to connecting stations, while leaving the current
+ * capabilities intact (currently disabled SMPS).
+ */
+ conf->ht_capab |= mode->ht_capab &
+ (HT_CAP_INFO_GREEN_FIELD |
+ HT_CAP_INFO_SHORT_GI20MHZ |
+ HT_CAP_INFO_SHORT_GI40MHZ |
+ HT_CAP_INFO_RX_STBC_MASK |
+ HT_CAP_INFO_MAX_AMSDU_SIZE);
+ }
+ }
+#endif /* CONFIG_IEEE80211N */
+
+#ifdef CONFIG_P2P
+ if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G) {
+ /* Remove 802.11b rates from supported and basic rate sets */
+ int *list = os_malloc(4 * sizeof(int));
+ if (list) {
+ list[0] = 60;
+ list[1] = 120;
+ list[2] = 240;
+ list[3] = -1;
+ }
+ conf->basic_rates = list;
+
+ list = os_malloc(9 * sizeof(int));
+ if (list) {
+ list[0] = 60;
+ list[1] = 90;
+ list[2] = 120;
+ list[3] = 180;
+ list[4] = 240;
+ list[5] = 360;
+ list[6] = 480;
+ list[7] = 540;
+ list[8] = -1;
+ }
+ conf->supported_rates = list;
+ }
+
+ bss->isolate = !wpa_s->conf->p2p_intra_bss;
+#endif /* CONFIG_P2P */
+
if (ssid->ssid_len == 0) {
wpa_printf(MSG_ERROR, "No SSID configured for AP mode");
return -1;
}
os_memcpy(bss->ssid.ssid, ssid->ssid, ssid->ssid_len);
- bss->ssid.ssid[ssid->ssid_len] = '\0';
bss->ssid.ssid_len = ssid->ssid_len;
bss->ssid.ssid_set = 1;
+ bss->ignore_broadcast_ssid = ssid->ignore_broadcast_ssid;
+
+ if (ssid->auth_alg)
+ bss->auth_algs = ssid->auth_alg;
+
if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt))
bss->wpa = ssid->proto;
bss->wpa_key_mgmt = ssid->key_mgmt;
bss->wpa_pairwise = ssid->pairwise_cipher;
- if (ssid->passphrase) {
- bss->ssid.wpa_passphrase = os_strdup(ssid->passphrase);
- } else if (ssid->psk_set) {
+ if (ssid->psk_set) {
os_free(bss->ssid.wpa_psk);
bss->ssid.wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
if (bss->ssid.wpa_psk == NULL)
return -1;
os_memcpy(bss->ssid.wpa_psk->psk, ssid->psk, PMK_LEN);
bss->ssid.wpa_psk->group = 1;
+ } else if (ssid->passphrase) {
+ bss->ssid.wpa_passphrase = os_strdup(ssid->passphrase);
+ } else if (ssid->wep_key_len[0] || ssid->wep_key_len[1] ||
+ ssid->wep_key_len[2] || ssid->wep_key_len[3]) {
+ struct hostapd_wep_keys *wep = &bss->ssid.wep;
+ int i;
+ for (i = 0; i < NUM_WEP_KEYS; i++) {
+ if (ssid->wep_key_len[i] == 0)
+ continue;
+ wep->key[i] = os_malloc(ssid->wep_key_len[i]);
+ if (wep->key[i] == NULL)
+ return -1;
+ os_memcpy(wep->key[i], ssid->wep_key[i],
+ ssid->wep_key_len[i]);
+ wep->len[i] = ssid->wep_key_len[i];
+ }
+ wep->idx = ssid->wep_tx_keyidx;
+ wep->keys_set = 1;
}
+ if (ssid->ap_max_inactivity)
+ bss->ap_max_inactivity = ssid->ap_max_inactivity;
+
+ if (ssid->dtim_period)
+ bss->dtim_period = ssid->dtim_period;
+
/* Select group cipher based on the enabled pairwise cipher suites */
pairwise = 0;
if (bss->wpa & 1)
@@ -102,6 +222,9 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
}
if (pairwise & WPA_CIPHER_TKIP)
bss->wpa_group = WPA_CIPHER_TKIP;
+ else if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) ==
+ WPA_CIPHER_GCMP)
+ bss->wpa_group = WPA_CIPHER_GCMP;
else
bss->wpa_group = WPA_CIPHER_CCMP;
@@ -110,46 +233,193 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
else if (bss->wpa)
bss->ssid.security_policy = SECURITY_WPA_PSK;
else if (bss->ieee802_1x) {
+ int cipher = WPA_CIPHER_NONE;
bss->ssid.security_policy = SECURITY_IEEE_802_1X;
bss->ssid.wep.default_len = bss->default_wep_key_len;
- } else if (bss->ssid.wep.keys_set)
+ if (bss->default_wep_key_len)
+ cipher = bss->default_wep_key_len >= 13 ?
+ WPA_CIPHER_WEP104 : WPA_CIPHER_WEP40;
+ bss->wpa_group = cipher;
+ bss->wpa_pairwise = cipher;
+ bss->rsn_pairwise = cipher;
+ } else if (bss->ssid.wep.keys_set) {
+ int cipher = WPA_CIPHER_WEP40;
+ if (bss->ssid.wep.len[0] >= 13)
+ cipher = WPA_CIPHER_WEP104;
bss->ssid.security_policy = SECURITY_STATIC_WEP;
- else
+ bss->wpa_group = cipher;
+ bss->wpa_pairwise = cipher;
+ bss->rsn_pairwise = cipher;
+ } else {
bss->ssid.security_policy = SECURITY_PLAINTEXT;
+ bss->wpa_group = WPA_CIPHER_NONE;
+ bss->wpa_pairwise = WPA_CIPHER_NONE;
+ bss->rsn_pairwise = WPA_CIPHER_NONE;
+ }
#ifdef CONFIG_WPS
/*
- * Enable WPS by default, but require user interaction to actually use
- * it. Only the internal Registrar is supported.
+ * Enable WPS by default for open and WPA/WPA2-Personal network, but
+ * require user interaction to actually use it. Only the internal
+ * Registrar is supported.
*/
+ if (bss->ssid.security_policy != SECURITY_WPA_PSK &&
+ bss->ssid.security_policy != SECURITY_PLAINTEXT)
+ goto no_wps;
+#ifdef CONFIG_WPS2
+ if (bss->ssid.security_policy == SECURITY_WPA_PSK &&
+ (!(pairwise & WPA_CIPHER_CCMP) || !(bss->wpa & 2)))
+ goto no_wps; /* WPS2 does not allow WPA/TKIP-only
+ * configuration */
+#endif /* CONFIG_WPS2 */
bss->eap_server = 1;
- bss->wps_state = 2;
- bss->ap_setup_locked = 1;
+
+ if (!ssid->ignore_broadcast_ssid)
+ bss->wps_state = 2;
+
+ bss->ap_setup_locked = 2;
if (wpa_s->conf->config_methods)
bss->config_methods = os_strdup(wpa_s->conf->config_methods);
- if (wpa_s->conf->device_type)
- bss->device_type = os_strdup(wpa_s->conf->device_type);
+ os_memcpy(bss->device_type, wpa_s->conf->device_type,
+ WPS_DEV_TYPE_LEN);
+ if (wpa_s->conf->device_name) {
+ bss->device_name = os_strdup(wpa_s->conf->device_name);
+ bss->friendly_name = os_strdup(wpa_s->conf->device_name);
+ }
+ if (wpa_s->conf->manufacturer)
+ bss->manufacturer = os_strdup(wpa_s->conf->manufacturer);
+ if (wpa_s->conf->model_name)
+ bss->model_name = os_strdup(wpa_s->conf->model_name);
+ if (wpa_s->conf->model_number)
+ bss->model_number = os_strdup(wpa_s->conf->model_number);
+ if (wpa_s->conf->serial_number)
+ bss->serial_number = os_strdup(wpa_s->conf->serial_number);
+ if (is_nil_uuid(wpa_s->conf->uuid))
+ os_memcpy(bss->uuid, wpa_s->wps->uuid, WPS_UUID_LEN);
+ else
+ os_memcpy(bss->uuid, wpa_s->conf->uuid, WPS_UUID_LEN);
+ os_memcpy(bss->os_version, wpa_s->conf->os_version, 4);
+ bss->pbc_in_m1 = wpa_s->conf->pbc_in_m1;
+no_wps:
#endif /* CONFIG_WPS */
+ if (wpa_s->max_stations &&
+ wpa_s->max_stations < wpa_s->conf->max_num_sta)
+ bss->max_num_sta = wpa_s->max_stations;
+ else
+ bss->max_num_sta = wpa_s->conf->max_num_sta;
+
+ bss->disassoc_low_ack = wpa_s->conf->disassoc_low_ack;
+
return 0;
}
static void ap_public_action_rx(void *ctx, const u8 *buf, size_t len, int freq)
{
+#ifdef CONFIG_P2P
+ struct wpa_supplicant *wpa_s = ctx;
+ const struct ieee80211_mgmt *mgmt;
+ size_t hdr_len;
+
+ mgmt = (const struct ieee80211_mgmt *) buf;
+ hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf;
+ if (hdr_len > len)
+ return;
+ wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
+ mgmt->u.action.category,
+ &mgmt->u.action.u.vs_public_action.action,
+ len - hdr_len, freq);
+#endif /* CONFIG_P2P */
+}
+
+
+static void ap_wps_event_cb(void *ctx, enum wps_event event,
+ union wps_event_data *data)
+{
+#ifdef CONFIG_P2P
+ struct wpa_supplicant *wpa_s = ctx;
+
+ if (event == WPS_EV_FAIL) {
+ struct wps_event_fail *fail = &data->fail;
+
+ if (wpa_s->parent && wpa_s->parent != wpa_s &&
+ wpa_s == wpa_s->global->p2p_group_formation) {
+ /*
+ * src/ap/wps_hostapd.c has already sent this on the
+ * main interface, so only send on the parent interface
+ * here if needed.
+ */
+ wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL
+ "msg=%d config_error=%d",
+ fail->msg, fail->config_error);
+ }
+ wpas_p2p_wps_failed(wpa_s, fail);
+ }
+#endif /* CONFIG_P2P */
+}
+
+
+static void ap_sta_authorized_cb(void *ctx, const u8 *mac_addr,
+ int authorized, const u8 *p2p_dev_addr)
+{
+ wpas_notify_sta_authorized(ctx, mac_addr, authorized, p2p_dev_addr);
+}
+
+
+static int ap_vendor_action_rx(void *ctx, const u8 *buf, size_t len, int freq)
+{
+#ifdef CONFIG_P2P
+ struct wpa_supplicant *wpa_s = ctx;
+ const struct ieee80211_mgmt *mgmt;
+ size_t hdr_len;
+
+ mgmt = (const struct ieee80211_mgmt *) buf;
+ hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf;
+ if (hdr_len > len)
+ return -1;
+ wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
+ mgmt->u.action.category,
+ &mgmt->u.action.u.vs_public_action.action,
+ len - hdr_len, freq);
+#endif /* CONFIG_P2P */
+ return 0;
}
-static int ap_probe_req_rx(void *ctx, const u8 *addr, const u8 *ie,
- size_t ie_len)
+static int ap_probe_req_rx(void *ctx, const u8 *sa, const u8 *da,
+ const u8 *bssid, const u8 *ie, size_t ie_len,
+ int ssi_signal)
{
+#ifdef CONFIG_P2P
+ struct wpa_supplicant *wpa_s = ctx;
+ return wpas_p2p_probe_req_rx(wpa_s, sa, da, bssid, ie, ie_len,
+ ssi_signal);
+#else /* CONFIG_P2P */
return 0;
+#endif /* CONFIG_P2P */
}
static void ap_wps_reg_success_cb(void *ctx, const u8 *mac_addr,
const u8 *uuid_e)
{
+#ifdef CONFIG_P2P
+ struct wpa_supplicant *wpa_s = ctx;
+ wpas_p2p_wps_success(wpa_s, mac_addr, 1);
+#endif /* CONFIG_P2P */
+}
+
+
+static void wpas_ap_configured_cb(void *ctx)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+
+ if (wpa_s->ap_configured_cb)
+ wpa_s->ap_configured_cb(wpa_s->ap_configured_cb_ctx,
+ wpa_s->ap_configured_cb_data);
}
@@ -182,11 +452,14 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
params.mode = IEEE80211_MODE_IBSS;
break;
case WPAS_MODE_AP:
+ case WPAS_MODE_P2P_GO:
+ case WPAS_MODE_P2P_GROUP_FORMATION:
params.mode = IEEE80211_MODE_AP;
break;
}
params.freq = ssid->frequency;
+ params.wpa_proto = ssid->proto;
if (ssid->key_mgmt & WPA_KEY_MGMT_PSK)
wpa_s->key_mgmt = WPA_KEY_MGMT_PSK;
else
@@ -195,6 +468,8 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
if (ssid->pairwise_cipher & WPA_CIPHER_CCMP)
wpa_s->pairwise_cipher = WPA_CIPHER_CCMP;
+ else if (ssid->pairwise_cipher & WPA_CIPHER_GCMP)
+ wpa_s->pairwise_cipher = WPA_CIPHER_GCMP;
else if (ssid->pairwise_cipher & WPA_CIPHER_TKIP)
wpa_s->pairwise_cipher = WPA_CIPHER_TKIP;
else if (ssid->pairwise_cipher & WPA_CIPHER_NONE)
@@ -207,6 +482,17 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
params.pairwise_suite = cipher_suite2driver(wpa_s->pairwise_cipher);
params.group_suite = params.pairwise_suite;
+#ifdef CONFIG_P2P
+ if (ssid->mode == WPAS_MODE_P2P_GO ||
+ ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
+ params.p2p = 1;
+#endif /* CONFIG_P2P */
+
+ if (wpa_s->parent->set_ap_uapsd)
+ params.uapsd = wpa_s->parent->ap_uapsd;
+ else
+ params.uapsd = -1;
+
if (wpa_drv_associate(wpa_s, &params) < 0) {
wpa_msg(wpa_s, MSG_INFO, "Failed to start AP functionality");
return -1;
@@ -216,6 +502,8 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
if (hapd_iface == NULL)
return -1;
hapd_iface->owner = wpa_s;
+ hapd_iface->drv_flags = wpa_s->drv_flags;
+ hapd_iface->probe_resp_offloads = wpa_s->probe_resp_offloads;
wpa_s->ap_iface->conf = conf = hostapd_config_defaults();
if (conf == NULL) {
@@ -223,14 +511,31 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
return -1;
}
+ os_memcpy(wpa_s->ap_iface->conf->wmm_ac_params,
+ wpa_s->conf->wmm_ac_params,
+ sizeof(wpa_s->conf->wmm_ac_params));
+
+ if (params.uapsd > 0) {
+ conf->bss->wmm_enabled = 1;
+ conf->bss->wmm_uapsd = 1;
+ }
+
if (wpa_supplicant_conf_ap(wpa_s, ssid, conf)) {
wpa_printf(MSG_ERROR, "Failed to create AP configuration");
wpa_supplicant_ap_deinit(wpa_s);
return -1;
}
+#ifdef CONFIG_P2P
+ if (ssid->mode == WPAS_MODE_P2P_GO)
+ conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER;
+ else if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
+ conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER |
+ P2P_GROUP_FORMATION;
+#endif /* CONFIG_P2P */
+
hapd_iface->num_bss = conf->num_bss;
- hapd_iface->bss = os_zalloc(conf->num_bss *
+ hapd_iface->bss = os_calloc(conf->num_bss,
sizeof(struct hostapd_data *));
if (hapd_iface->bss == NULL) {
wpa_supplicant_ap_deinit(wpa_s);
@@ -247,42 +552,62 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
}
hapd_iface->bss[i]->msg_ctx = wpa_s;
+ hapd_iface->bss[i]->msg_ctx_parent = wpa_s->parent;
hapd_iface->bss[i]->public_action_cb = ap_public_action_rx;
hapd_iface->bss[i]->public_action_cb_ctx = wpa_s;
+ hapd_iface->bss[i]->vendor_action_cb = ap_vendor_action_rx;
+ hapd_iface->bss[i]->vendor_action_cb_ctx = wpa_s;
hostapd_register_probereq_cb(hapd_iface->bss[i],
ap_probe_req_rx, wpa_s);
hapd_iface->bss[i]->wps_reg_success_cb = ap_wps_reg_success_cb;
hapd_iface->bss[i]->wps_reg_success_cb_ctx = wpa_s;
+ hapd_iface->bss[i]->wps_event_cb = ap_wps_event_cb;
+ hapd_iface->bss[i]->wps_event_cb_ctx = wpa_s;
+ hapd_iface->bss[i]->sta_authorized_cb = ap_sta_authorized_cb;
+ hapd_iface->bss[i]->sta_authorized_cb_ctx = wpa_s;
+#ifdef CONFIG_P2P
+ hapd_iface->bss[i]->p2p = wpa_s->global->p2p;
+ hapd_iface->bss[i]->p2p_group = wpas_p2p_group_init(wpa_s,
+ ssid);
+#endif /* CONFIG_P2P */
+ hapd_iface->bss[i]->setup_complete_cb = wpas_ap_configured_cb;
+ hapd_iface->bss[i]->setup_complete_cb_ctx = wpa_s;
}
os_memcpy(hapd_iface->bss[0]->own_addr, wpa_s->own_addr, ETH_ALEN);
hapd_iface->bss[0]->driver = wpa_s->driver;
hapd_iface->bss[0]->drv_priv = wpa_s->drv_priv;
+ wpa_s->current_ssid = ssid;
+ os_memcpy(wpa_s->bssid, wpa_s->own_addr, ETH_ALEN);
+ wpa_s->assoc_freq = ssid->frequency;
+
if (hostapd_setup_interface(wpa_s->ap_iface)) {
wpa_printf(MSG_ERROR, "Failed to initialize AP interface");
wpa_supplicant_ap_deinit(wpa_s);
return -1;
}
- wpa_s->current_ssid = ssid;
- os_memcpy(wpa_s->bssid, wpa_s->own_addr, ETH_ALEN);
- wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
-
- if (wpa_s->ap_configured_cb)
- wpa_s->ap_configured_cb(wpa_s->ap_configured_cb_ctx,
- wpa_s->ap_configured_cb_data);
-
return 0;
}
void wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s)
{
+#ifdef CONFIG_WPS
+ eloop_cancel_timeout(wpas_wps_ap_pin_timeout, wpa_s, NULL);
+#endif /* CONFIG_WPS */
+
if (wpa_s->ap_iface == NULL)
return;
wpa_s->current_ssid = NULL;
+ wpa_s->assoc_freq = 0;
+#ifdef CONFIG_P2P
+ if (wpa_s->ap_iface->bss)
+ wpa_s->ap_iface->bss[0]->p2p_group = NULL;
+ wpas_p2p_group_deinit(wpa_s);
+#endif /* CONFIG_P2P */
hostapd_interface_deinit(wpa_s->ap_iface);
hostapd_interface_free(wpa_s->ap_iface);
wpa_s->ap_iface = NULL;
@@ -300,16 +625,31 @@ void ap_tx_status(void *ctx, const u8 *addr,
}
-void ap_rx_from_unknown_sta(void *ctx, const u8 *frame, size_t len)
+void ap_eapol_tx_status(void *ctx, const u8 *dst,
+ const u8 *data, size_t len, int ack)
{
#ifdef NEED_AP_MLME
struct wpa_supplicant *wpa_s = ctx;
- const struct ieee80211_hdr *hdr =
- (const struct ieee80211_hdr *) frame;
- u16 fc = le_to_host16(hdr->frame_control);
- ieee802_11_rx_from_unknown(wpa_s->ap_iface->bss[0], hdr->addr2,
- (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
- (WLAN_FC_TODS | WLAN_FC_FROMDS));
+ hostapd_tx_status(wpa_s->ap_iface->bss[0], dst, data, len, ack);
+#endif /* NEED_AP_MLME */
+}
+
+
+void ap_client_poll_ok(void *ctx, const u8 *addr)
+{
+#ifdef NEED_AP_MLME
+ struct wpa_supplicant *wpa_s = ctx;
+ if (wpa_s->ap_iface)
+ hostapd_client_poll_ok(wpa_s->ap_iface->bss[0], addr);
+#endif /* NEED_AP_MLME */
+}
+
+
+void ap_rx_from_unknown_sta(void *ctx, const u8 *addr, int wds)
+{
+#ifdef NEED_AP_MLME
+ struct wpa_supplicant *wpa_s = ctx;
+ ieee802_11_rx_from_unknown(wpa_s->ap_iface->bss[0], addr, wds);
#endif /* NEED_AP_MLME */
}
@@ -346,16 +686,49 @@ void wpa_supplicant_ap_rx_eapol(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_WPS
-int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid)
+int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ const u8 *p2p_dev_addr)
{
if (!wpa_s->ap_iface)
return -1;
- return hostapd_wps_button_pushed(wpa_s->ap_iface->bss[0]);
+ return hostapd_wps_button_pushed(wpa_s->ap_iface->bss[0],
+ p2p_dev_addr);
+}
+
+
+int wpa_supplicant_ap_wps_cancel(struct wpa_supplicant *wpa_s)
+{
+ struct wps_registrar *reg;
+ int reg_sel = 0, wps_sta = 0;
+
+ if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0]->wps)
+ return -1;
+
+ reg = wpa_s->ap_iface->bss[0]->wps->registrar;
+ reg_sel = wps_registrar_wps_cancel(reg);
+ wps_sta = ap_for_each_sta(wpa_s->ap_iface->bss[0],
+ ap_sta_wps_cancel, NULL);
+
+ if (!reg_sel && !wps_sta) {
+ wpa_printf(MSG_DEBUG, "No WPS operation in progress at this "
+ "time");
+ return -1;
+ }
+
+ /*
+ * There are 2 cases to return wps cancel as success:
+ * 1. When wps cancel was initiated but no connection has been
+ * established with client yet.
+ * 2. Client is in the middle of exchanging WPS messages.
+ */
+
+ return 0;
}
int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
- const char *pin, char *buf, size_t buflen)
+ const char *pin, char *buf, size_t buflen,
+ int timeout)
{
int ret, ret_len = 0;
@@ -364,16 +737,135 @@ int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
if (pin == NULL) {
unsigned int rpin = wps_generate_pin();
- ret_len = os_snprintf(buf, buflen, "%d", rpin);
+ ret_len = os_snprintf(buf, buflen, "%08d", rpin);
pin = buf;
- }
+ } else
+ ret_len = os_snprintf(buf, buflen, "%s", pin);
- ret = hostapd_wps_add_pin(wpa_s->ap_iface->bss[0], "any", pin, 0);
+ ret = hostapd_wps_add_pin(wpa_s->ap_iface->bss[0], bssid, "any", pin,
+ timeout);
if (ret)
return -1;
return ret_len;
}
+
+static void wpas_wps_ap_pin_timeout(void *eloop_data, void *user_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_data;
+ wpa_printf(MSG_DEBUG, "WPS: AP PIN timed out");
+ wpas_wps_ap_pin_disable(wpa_s);
+}
+
+
+static void wpas_wps_ap_pin_enable(struct wpa_supplicant *wpa_s, int timeout)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface == NULL)
+ return;
+ hapd = wpa_s->ap_iface->bss[0];
+ wpa_printf(MSG_DEBUG, "WPS: Enabling AP PIN (timeout=%d)", timeout);
+ hapd->ap_pin_failures = 0;
+ eloop_cancel_timeout(wpas_wps_ap_pin_timeout, wpa_s, NULL);
+ if (timeout > 0)
+ eloop_register_timeout(timeout, 0,
+ wpas_wps_ap_pin_timeout, wpa_s, NULL);
+}
+
+
+void wpas_wps_ap_pin_disable(struct wpa_supplicant *wpa_s)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface == NULL)
+ return;
+ wpa_printf(MSG_DEBUG, "WPS: Disabling AP PIN");
+ hapd = wpa_s->ap_iface->bss[0];
+ os_free(hapd->conf->ap_pin);
+ hapd->conf->ap_pin = NULL;
+ eloop_cancel_timeout(wpas_wps_ap_pin_timeout, wpa_s, NULL);
+}
+
+
+const char * wpas_wps_ap_pin_random(struct wpa_supplicant *wpa_s, int timeout)
+{
+ struct hostapd_data *hapd;
+ unsigned int pin;
+ char pin_txt[9];
+
+ if (wpa_s->ap_iface == NULL)
+ return NULL;
+ hapd = wpa_s->ap_iface->bss[0];
+ pin = wps_generate_pin();
+ os_snprintf(pin_txt, sizeof(pin_txt), "%08u", pin);
+ os_free(hapd->conf->ap_pin);
+ hapd->conf->ap_pin = os_strdup(pin_txt);
+ if (hapd->conf->ap_pin == NULL)
+ return NULL;
+ wpas_wps_ap_pin_enable(wpa_s, timeout);
+
+ return hapd->conf->ap_pin;
+}
+
+
+const char * wpas_wps_ap_pin_get(struct wpa_supplicant *wpa_s)
+{
+ struct hostapd_data *hapd;
+ if (wpa_s->ap_iface == NULL)
+ return NULL;
+ hapd = wpa_s->ap_iface->bss[0];
+ return hapd->conf->ap_pin;
+}
+
+
+int wpas_wps_ap_pin_set(struct wpa_supplicant *wpa_s, const char *pin,
+ int timeout)
+{
+ struct hostapd_data *hapd;
+ char pin_txt[9];
+ int ret;
+
+ if (wpa_s->ap_iface == NULL)
+ return -1;
+ hapd = wpa_s->ap_iface->bss[0];
+ ret = os_snprintf(pin_txt, sizeof(pin_txt), "%s", pin);
+ if (ret < 0 || ret >= (int) sizeof(pin_txt))
+ return -1;
+ os_free(hapd->conf->ap_pin);
+ hapd->conf->ap_pin = os_strdup(pin_txt);
+ if (hapd->conf->ap_pin == NULL)
+ return -1;
+ wpas_wps_ap_pin_enable(wpa_s, timeout);
+
+ return 0;
+}
+
+
+void wpa_supplicant_ap_pwd_auth_fail(struct wpa_supplicant *wpa_s)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface == NULL)
+ return;
+ hapd = wpa_s->ap_iface->bss[0];
+
+ /*
+ * Registrar failed to prove its knowledge of the AP PIN. Disable AP
+ * PIN if this happens multiple times to slow down brute force attacks.
+ */
+ hapd->ap_pin_failures++;
+ wpa_printf(MSG_DEBUG, "WPS: AP PIN authentication failure number %u",
+ hapd->ap_pin_failures);
+ if (hapd->ap_pin_failures < 3)
+ return;
+
+ wpa_printf(MSG_DEBUG, "WPS: Disable AP PIN");
+ hapd->ap_pin_failures = 0;
+ os_free(hapd->conf->ap_pin);
+ hapd->conf->ap_pin = NULL;
+}
+
#endif /* CONFIG_WPS */
@@ -409,6 +901,26 @@ int ap_ctrl_iface_sta_next(struct wpa_supplicant *wpa_s, const char *txtaddr,
}
+int ap_ctrl_iface_sta_disassociate(struct wpa_supplicant *wpa_s,
+ const char *txtaddr)
+{
+ if (wpa_s->ap_iface == NULL)
+ return -1;
+ return hostapd_ctrl_iface_disassociate(wpa_s->ap_iface->bss[0],
+ txtaddr);
+}
+
+
+int ap_ctrl_iface_sta_deauthenticate(struct wpa_supplicant *wpa_s,
+ const char *txtaddr)
+{
+ if (wpa_s->ap_iface == NULL)
+ return -1;
+ return hostapd_ctrl_iface_deauthenticate(wpa_s->ap_iface->bss[0],
+ txtaddr);
+}
+
+
int ap_ctrl_iface_wpa_get_status(struct wpa_supplicant *wpa_s, char *buf,
size_t buflen, int verbose)
{
@@ -440,6 +952,46 @@ int ap_ctrl_iface_wpa_get_status(struct wpa_supplicant *wpa_s, char *buf,
#endif /* CONFIG_CTRL_IFACE */
+int wpa_supplicant_ap_update_beacon(struct wpa_supplicant *wpa_s)
+{
+ struct hostapd_iface *iface = wpa_s->ap_iface;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ struct hostapd_data *hapd;
+
+ if (ssid == NULL || wpa_s->ap_iface == NULL ||
+ ssid->mode == WPAS_MODE_INFRA ||
+ ssid->mode == WPAS_MODE_IBSS)
+ return -1;
+
+#ifdef CONFIG_P2P
+ if (ssid->mode == WPAS_MODE_P2P_GO)
+ iface->conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER;
+ else if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
+ iface->conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER |
+ P2P_GROUP_FORMATION;
+#endif /* CONFIG_P2P */
+
+ hapd = iface->bss[0];
+ if (hapd->drv_priv == NULL)
+ return -1;
+ ieee802_11_set_beacons(iface);
+ hostapd_set_ap_wps_ie(hapd);
+
+ return 0;
+}
+
+
+void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
+ int offset)
+{
+ if (!wpa_s->ap_iface)
+ return;
+
+ wpa_s->assoc_freq = freq;
+ hostapd_event_ch_switch(wpa_s->ap_iface->bss[0], freq, ht, offset);
+}
+
+
int wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s,
const u8 *addr)
{
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 381a432358bd..536064f7c74f 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -3,14 +3,8 @@
* Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2009, Atheros Communications
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef AP_H
@@ -21,23 +15,42 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
void wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s);
void wpa_supplicant_ap_rx_eapol(struct wpa_supplicant *wpa_s,
const u8 *src_addr, const u8 *buf, size_t len);
-int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ const u8 *p2p_dev_addr);
int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
- const char *pin, char *buf, size_t buflen);
+ const char *pin, char *buf, size_t buflen,
+ int timeout);
+int wpa_supplicant_ap_wps_cancel(struct wpa_supplicant *wpa_s);
+void wpas_wps_ap_pin_disable(struct wpa_supplicant *wpa_s);
+const char * wpas_wps_ap_pin_random(struct wpa_supplicant *wpa_s, int timeout);
+const char * wpas_wps_ap_pin_get(struct wpa_supplicant *wpa_s);
+int wpas_wps_ap_pin_set(struct wpa_supplicant *wpa_s, const char *pin,
+ int timeout);
int ap_ctrl_iface_sta_first(struct wpa_supplicant *wpa_s,
char *buf, size_t buflen);
int ap_ctrl_iface_sta(struct wpa_supplicant *wpa_s, const char *txtaddr,
char *buf, size_t buflen);
int ap_ctrl_iface_sta_next(struct wpa_supplicant *wpa_s, const char *txtaddr,
char *buf, size_t buflen);
+int ap_ctrl_iface_sta_deauthenticate(struct wpa_supplicant *wpa_s,
+ const char *txtaddr);
+int ap_ctrl_iface_sta_disassociate(struct wpa_supplicant *wpa_s,
+ const char *txtaddr);
int ap_ctrl_iface_wpa_get_status(struct wpa_supplicant *wpa_s, char *buf,
size_t buflen, int verbose);
void ap_tx_status(void *ctx, const u8 *addr,
const u8 *buf, size_t len, int ack);
-void ap_rx_from_unknown_sta(void *ctx, const u8 *frame, size_t len);
+void ap_eapol_tx_status(void *ctx, const u8 *dst,
+ const u8 *data, size_t len, int ack);
+void ap_client_poll_ok(void *ctx, const u8 *addr);
+void ap_rx_from_unknown_sta(void *ctx, const u8 *addr, int wds);
void ap_mgmt_rx(void *ctx, struct rx_mgmt *rx_mgmt);
void ap_mgmt_tx_cb(void *ctx, const u8 *buf, size_t len, u16 stype, int ok);
+int wpa_supplicant_ap_update_beacon(struct wpa_supplicant *wpa_s);
int wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s,
const u8 *addr);
+void wpa_supplicant_ap_pwd_auth_fail(struct wpa_supplicant *wpa_s);
+void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
+ int offset);
#endif /* AP_H */
diff --git a/wpa_supplicant/autoscan.c b/wpa_supplicant/autoscan.c
new file mode 100644
index 000000000000..a2cf7a5ef232
--- /dev/null
+++ b/wpa_supplicant/autoscan.c
@@ -0,0 +1,143 @@
+/*
+ * WPA Supplicant - auto scan
+ * Copyright (c) 2012, Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "config.h"
+#include "wpa_supplicant_i.h"
+#include "bss.h"
+#include "scan.h"
+#include "autoscan.h"
+
+#ifdef CONFIG_AUTOSCAN_EXPONENTIAL
+extern const struct autoscan_ops autoscan_exponential_ops;
+#endif /* CONFIG_AUTOSCAN_EXPONENTIAL */
+
+#ifdef CONFIG_AUTOSCAN_PERIODIC
+extern const struct autoscan_ops autoscan_periodic_ops;
+#endif /* CONFIG_AUTOSCAN_PERIODIC */
+
+static const struct autoscan_ops * autoscan_modules[] = {
+#ifdef CONFIG_AUTOSCAN_EXPONENTIAL
+ &autoscan_exponential_ops,
+#endif /* CONFIG_AUTOSCAN_EXPONENTIAL */
+#ifdef CONFIG_AUTOSCAN_PERIODIC
+ &autoscan_periodic_ops,
+#endif /* CONFIG_AUTOSCAN_PERIODIC */
+ NULL
+};
+
+
+static void request_scan(struct wpa_supplicant *wpa_s)
+{
+ wpa_s->scan_req = MANUAL_SCAN_REQ;
+
+ if (wpa_supplicant_req_sched_scan(wpa_s))
+ wpa_supplicant_req_scan(wpa_s, wpa_s->scan_interval, 0);
+}
+
+
+int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan)
+{
+ const char *name = wpa_s->conf->autoscan;
+ const char *params;
+ size_t nlen;
+ int i;
+ const struct autoscan_ops *ops = NULL;
+
+ if (wpa_s->autoscan && wpa_s->autoscan_priv)
+ return 0;
+
+ if (name == NULL)
+ return 0;
+
+ params = os_strchr(name, ':');
+ if (params == NULL) {
+ params = "";
+ nlen = os_strlen(name);
+ } else {
+ nlen = params - name;
+ params++;
+ }
+
+ for (i = 0; autoscan_modules[i]; i++) {
+ if (os_strncmp(name, autoscan_modules[i]->name, nlen) == 0) {
+ ops = autoscan_modules[i];
+ break;
+ }
+ }
+
+ if (ops == NULL) {
+ wpa_printf(MSG_ERROR, "autoscan: Could not find module "
+ "matching the parameter '%s'", name);
+ return -1;
+ }
+
+ wpa_s->autoscan_params = NULL;
+
+ wpa_s->autoscan_priv = ops->init(wpa_s, params);
+ if (wpa_s->autoscan_priv == NULL)
+ return -1;
+ wpa_s->autoscan = ops;
+
+ wpa_printf(MSG_DEBUG, "autoscan: Initialized module '%s' with "
+ "parameters '%s'", ops->name, params);
+ if (!req_scan)
+ return 0;
+
+ /*
+ * Cancelling existing scan requests, if any.
+ */
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_supplicant_cancel_scan(wpa_s);
+
+ /*
+ * Firing first scan, which will lead to call autoscan_notify_scan.
+ */
+ request_scan(wpa_s);
+
+ return 0;
+}
+
+
+void autoscan_deinit(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->autoscan && wpa_s->autoscan_priv) {
+ wpa_printf(MSG_DEBUG, "autoscan: Deinitializing module '%s'",
+ wpa_s->autoscan->name);
+ wpa_s->autoscan->deinit(wpa_s->autoscan_priv);
+ wpa_s->autoscan = NULL;
+ wpa_s->autoscan_priv = NULL;
+
+ wpa_s->scan_interval = 5;
+ wpa_s->sched_scan_interval = 0;
+ }
+}
+
+
+int autoscan_notify_scan(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+ int interval;
+
+ if (wpa_s->autoscan && wpa_s->autoscan_priv) {
+ interval = wpa_s->autoscan->notify_scan(wpa_s->autoscan_priv,
+ scan_res);
+
+ if (interval <= 0)
+ return -1;
+
+ wpa_s->scan_interval = interval;
+ wpa_s->sched_scan_interval = interval;
+
+ request_scan(wpa_s);
+ }
+
+ return 0;
+}
diff --git a/wpa_supplicant/autoscan.h b/wpa_supplicant/autoscan.h
new file mode 100644
index 000000000000..e2a7652213be
--- /dev/null
+++ b/wpa_supplicant/autoscan.h
@@ -0,0 +1,49 @@
+/*
+ * WPA Supplicant - auto scan
+ * Copyright (c) 2012, Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef AUTOSCAN_H
+#define AUTOSCAN_H
+
+struct wpa_supplicant;
+
+struct autoscan_ops {
+ const char *name;
+
+ void * (*init)(struct wpa_supplicant *wpa_s, const char *params);
+ void (*deinit)(void *priv);
+
+ int (*notify_scan)(void *priv, struct wpa_scan_results *scan_res);
+};
+
+#ifdef CONFIG_AUTOSCAN
+
+int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan);
+void autoscan_deinit(struct wpa_supplicant *wpa_s);
+int autoscan_notify_scan(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res);
+
+#else /* CONFIG_AUTOSCAN */
+
+static inline int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan)
+{
+ return 0;
+}
+
+static inline void autoscan_deinit(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline int autoscan_notify_scan(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+ return 0;
+}
+
+#endif /* CONFIG_AUTOSCAN */
+
+#endif /* AUTOSCAN_H */
diff --git a/wpa_supplicant/autoscan_exponential.c b/wpa_supplicant/autoscan_exponential.c
new file mode 100644
index 000000000000..424477be8d43
--- /dev/null
+++ b/wpa_supplicant/autoscan_exponential.c
@@ -0,0 +1,104 @@
+/*
+ * WPA Supplicant - auto scan exponential module
+ * Copyright (c) 2012, Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "wpa_supplicant_i.h"
+#include "autoscan.h"
+
+struct autoscan_exponential_data {
+ struct wpa_supplicant *wpa_s;
+ int base;
+ int limit;
+ int interval;
+};
+
+
+static int
+autoscan_exponential_get_params(struct autoscan_exponential_data *data,
+ const char *params)
+{
+ const char *pos;
+
+ if (params == NULL)
+ return -1;
+
+ data->base = atoi(params);
+
+ pos = os_strchr(params, ':');
+ if (pos == NULL)
+ return -1;
+
+ pos++;
+ data->limit = atoi(pos);
+
+ return 0;
+}
+
+
+static void * autoscan_exponential_init(struct wpa_supplicant *wpa_s,
+ const char *params)
+{
+ struct autoscan_exponential_data *data;
+
+ data = os_zalloc(sizeof(struct autoscan_exponential_data));
+ if (data == NULL)
+ return NULL;
+
+ if (autoscan_exponential_get_params(data, params) < 0) {
+ os_free(data);
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "autoscan exponential: base exponential is %d "
+ "and limit is %d", data->base, data->limit);
+
+ data->wpa_s = wpa_s;
+
+ return data;
+}
+
+
+static void autoscan_exponential_deinit(void *priv)
+{
+ struct autoscan_exponential_data *data = priv;
+
+ os_free(data);
+}
+
+
+static int autoscan_exponential_notify_scan(void *priv,
+ struct wpa_scan_results *scan_res)
+{
+ struct autoscan_exponential_data *data = priv;
+
+ wpa_printf(MSG_DEBUG, "autoscan exponential: scan result "
+ "notification");
+
+ if (data->interval >= data->limit)
+ return data->limit;
+
+ if (data->interval <= 0)
+ data->interval = data->base;
+ else {
+ data->interval = data->interval * data->base;
+ if (data->interval > data->limit)
+ return data->limit;
+ }
+
+ return data->interval;
+}
+
+
+const struct autoscan_ops autoscan_exponential_ops = {
+ .name = "exponential",
+ .init = autoscan_exponential_init,
+ .deinit = autoscan_exponential_deinit,
+ .notify_scan = autoscan_exponential_notify_scan,
+};
diff --git a/wpa_supplicant/autoscan_periodic.c b/wpa_supplicant/autoscan_periodic.c
new file mode 100644
index 000000000000..102d7234d35d
--- /dev/null
+++ b/wpa_supplicant/autoscan_periodic.c
@@ -0,0 +1,85 @@
+/*
+ * WPA Supplicant - auto scan periodic module
+ * Copyright (c) 2012, Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "wpa_supplicant_i.h"
+#include "autoscan.h"
+
+
+struct autoscan_periodic_data {
+ int periodic_interval;
+};
+
+
+static int autoscan_periodic_get_params(struct autoscan_periodic_data *data,
+ const char *params)
+{
+ int interval;
+
+ if (params == NULL)
+ return -1;
+
+ interval = atoi(params);
+
+ if (interval < 0)
+ return -1;
+
+ data->periodic_interval = interval;
+
+ return 0;
+}
+
+
+static void * autoscan_periodic_init(struct wpa_supplicant *wpa_s,
+ const char *params)
+{
+ struct autoscan_periodic_data *data;
+
+ data = os_zalloc(sizeof(struct autoscan_periodic_data));
+ if (data == NULL)
+ return NULL;
+
+ if (autoscan_periodic_get_params(data, params) < 0) {
+ os_free(data);
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "autoscan periodic: interval is %d",
+ data->periodic_interval);
+
+ return data;
+}
+
+
+static void autoscan_periodic_deinit(void *priv)
+{
+ struct autoscan_periodic_data *data = priv;
+
+ os_free(data);
+}
+
+
+static int autoscan_periodic_notify_scan(void *priv,
+ struct wpa_scan_results *scan_res)
+{
+ struct autoscan_periodic_data *data = priv;
+
+ wpa_printf(MSG_DEBUG, "autoscan periodic: scan result notification");
+
+ return data->periodic_interval;
+}
+
+
+const struct autoscan_ops autoscan_periodic_ops = {
+ .name = "periodic",
+ .init = autoscan_periodic_init,
+ .deinit = autoscan_periodic_deinit,
+ .notify_scan = autoscan_periodic_notify_scan,
+};
diff --git a/wpa_supplicant/bgscan.c b/wpa_supplicant/bgscan.c
index 31b5d278f3e5..9a9bd5207a90 100644
--- a/wpa_supplicant/bgscan.c
+++ b/wpa_supplicant/bgscan.c
@@ -2,14 +2,8 @@
* WPA Supplicant - background scan and roaming interface
* Copyright (c) 2009-2010, 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -22,11 +16,17 @@
#ifdef CONFIG_BGSCAN_SIMPLE
extern const struct bgscan_ops bgscan_simple_ops;
#endif /* CONFIG_BGSCAN_SIMPLE */
+#ifdef CONFIG_BGSCAN_LEARN
+extern const struct bgscan_ops bgscan_learn_ops;
+#endif /* CONFIG_BGSCAN_LEARN */
static const struct bgscan_ops * bgscan_modules[] = {
#ifdef CONFIG_BGSCAN_SIMPLE
&bgscan_simple_ops,
#endif /* CONFIG_BGSCAN_SIMPLE */
+#ifdef CONFIG_BGSCAN_LEARN
+ &bgscan_learn_ops,
+#endif /* CONFIG_BGSCAN_LEARN */
NULL
};
@@ -88,10 +88,12 @@ void bgscan_deinit(struct wpa_supplicant *wpa_s)
}
-int bgscan_notify_scan(struct wpa_supplicant *wpa_s)
+int bgscan_notify_scan(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
{
if (wpa_s->bgscan && wpa_s->bgscan_priv)
- return wpa_s->bgscan->notify_scan(wpa_s->bgscan_priv);
+ return wpa_s->bgscan->notify_scan(wpa_s->bgscan_priv,
+ scan_res);
return 0;
}
@@ -103,8 +105,13 @@ void bgscan_notify_beacon_loss(struct wpa_supplicant *wpa_s)
}
-void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s, int above)
+void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s, int above,
+ int current_signal, int current_noise,
+ int current_txrate)
{
if (wpa_s->bgscan && wpa_s->bgscan_priv)
- wpa_s->bgscan->notify_signal_change(wpa_s->bgscan_priv, above);
+ wpa_s->bgscan->notify_signal_change(wpa_s->bgscan_priv, above,
+ current_signal,
+ current_noise,
+ current_txrate);
}
diff --git a/wpa_supplicant/bgscan.h b/wpa_supplicant/bgscan.h
index 69e99b614cb2..e9d15fc5cf53 100644
--- a/wpa_supplicant/bgscan.h
+++ b/wpa_supplicant/bgscan.h
@@ -2,14 +2,8 @@
* WPA Supplicant - background scan and roaming interface
* Copyright (c) 2009-2010, 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef BGSCAN_H
@@ -25,18 +19,24 @@ struct bgscan_ops {
const struct wpa_ssid *ssid);
void (*deinit)(void *priv);
- int (*notify_scan)(void *priv);
+ int (*notify_scan)(void *priv, struct wpa_scan_results *scan_res);
void (*notify_beacon_loss)(void *priv);
- void (*notify_signal_change)(void *priv, int above);
+ void (*notify_signal_change)(void *priv, int above,
+ int current_signal,
+ int current_noise,
+ int current_txrate);
};
#ifdef CONFIG_BGSCAN
int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
void bgscan_deinit(struct wpa_supplicant *wpa_s);
-int bgscan_notify_scan(struct wpa_supplicant *wpa_s);
+int bgscan_notify_scan(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res);
void bgscan_notify_beacon_loss(struct wpa_supplicant *wpa_s);
-void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s, int above);
+void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s, int above,
+ int current_signal, int current_noise,
+ int current_txrate);
#else /* CONFIG_BGSCAN */
@@ -50,7 +50,8 @@ static inline void bgscan_deinit(struct wpa_supplicant *wpa_s)
{
}
-static inline int bgscan_notify_scan(struct wpa_supplicant *wpa_s)
+static inline int bgscan_notify_scan(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
{
return 0;
}
@@ -60,7 +61,9 @@ static inline void bgscan_notify_beacon_loss(struct wpa_supplicant *wpa_s)
}
static inline void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s,
- int above)
+ int above, int current_signal,
+ int current_noise,
+ int current_txrate)
{
}
diff --git a/wpa_supplicant/bgscan_learn.c b/wpa_supplicant/bgscan_learn.c
new file mode 100644
index 000000000000..07d31e4cb623
--- /dev/null
+++ b/wpa_supplicant/bgscan_learn.c
@@ -0,0 +1,607 @@
+/*
+ * WPA Supplicant - background scan and roaming module: learn
+ * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "list.h"
+#include "common/ieee802_11_defs.h"
+#include "drivers/driver.h"
+#include "config_ssid.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "scan.h"
+#include "bgscan.h"
+
+struct bgscan_learn_bss {
+ struct dl_list list;
+ u8 bssid[ETH_ALEN];
+ int freq;
+ u8 *neigh; /* num_neigh * ETH_ALEN buffer */
+ size_t num_neigh;
+};
+
+struct bgscan_learn_data {
+ struct wpa_supplicant *wpa_s;
+ const struct wpa_ssid *ssid;
+ int scan_interval;
+ int signal_threshold;
+ int short_interval; /* use if signal < threshold */
+ int long_interval; /* use if signal > threshold */
+ struct os_time last_bgscan;
+ char *fname;
+ struct dl_list bss;
+ int *supp_freqs;
+ int probe_idx;
+};
+
+
+static void bss_free(struct bgscan_learn_bss *bss)
+{
+ os_free(bss->neigh);
+ os_free(bss);
+}
+
+
+static int bssid_in_array(u8 *array, size_t array_len, const u8 *bssid)
+{
+ size_t i;
+
+ if (array == NULL || array_len == 0)
+ return 0;
+
+ for (i = 0; i < array_len; i++) {
+ if (os_memcmp(array + i * ETH_ALEN, bssid, ETH_ALEN) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static void bgscan_learn_add_neighbor(struct bgscan_learn_bss *bss,
+ const u8 *bssid)
+{
+ u8 *n;
+
+ if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
+ return;
+ if (bssid_in_array(bss->neigh, bss->num_neigh, bssid))
+ return;
+
+ n = os_realloc_array(bss->neigh, bss->num_neigh + 1, ETH_ALEN);
+ if (n == NULL)
+ return;
+
+ os_memcpy(n + bss->num_neigh * ETH_ALEN, bssid, ETH_ALEN);
+ bss->neigh = n;
+ bss->num_neigh++;
+}
+
+
+static struct bgscan_learn_bss * bgscan_learn_get_bss(
+ struct bgscan_learn_data *data, const u8 *bssid)
+{
+ struct bgscan_learn_bss *bss;
+
+ dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) {
+ if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
+ return bss;
+ }
+ return NULL;
+}
+
+
+static int bgscan_learn_load(struct bgscan_learn_data *data)
+{
+ FILE *f;
+ char buf[128];
+ struct bgscan_learn_bss *bss;
+
+ if (data->fname == NULL)
+ return 0;
+
+ f = fopen(data->fname, "r");
+ if (f == NULL)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "bgscan learn: Loading data from %s",
+ data->fname);
+
+ if (fgets(buf, sizeof(buf), f) == NULL ||
+ os_strncmp(buf, "wpa_supplicant-bgscan-learn\n", 28) != 0) {
+ wpa_printf(MSG_INFO, "bgscan learn: Invalid data file %s",
+ data->fname);
+ fclose(f);
+ return -1;
+ }
+
+ while (fgets(buf, sizeof(buf), f)) {
+ if (os_strncmp(buf, "BSS ", 4) == 0) {
+ bss = os_zalloc(sizeof(*bss));
+ if (!bss)
+ continue;
+ if (hwaddr_aton(buf + 4, bss->bssid) < 0) {
+ bss_free(bss);
+ continue;
+ }
+ bss->freq = atoi(buf + 4 + 18);
+ dl_list_add(&data->bss, &bss->list);
+ wpa_printf(MSG_DEBUG, "bgscan learn: Loaded BSS "
+ "entry: " MACSTR " freq=%d",
+ MAC2STR(bss->bssid), bss->freq);
+ }
+
+ if (os_strncmp(buf, "NEIGHBOR ", 9) == 0) {
+ u8 addr[ETH_ALEN];
+
+ if (hwaddr_aton(buf + 9, addr) < 0)
+ continue;
+ bss = bgscan_learn_get_bss(data, addr);
+ if (bss == NULL)
+ continue;
+ if (hwaddr_aton(buf + 9 + 18, addr) < 0)
+ continue;
+
+ bgscan_learn_add_neighbor(bss, addr);
+ }
+ }
+
+ fclose(f);
+ return 0;
+}
+
+
+static void bgscan_learn_save(struct bgscan_learn_data *data)
+{
+ FILE *f;
+ struct bgscan_learn_bss *bss;
+
+ if (data->fname == NULL)
+ return;
+
+ wpa_printf(MSG_DEBUG, "bgscan learn: Saving data to %s",
+ data->fname);
+
+ f = fopen(data->fname, "w");
+ if (f == NULL)
+ return;
+ fprintf(f, "wpa_supplicant-bgscan-learn\n");
+
+ dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) {
+ fprintf(f, "BSS " MACSTR " %d\n",
+ MAC2STR(bss->bssid), bss->freq);
+ }
+
+ dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) {
+ size_t i;
+ for (i = 0; i < bss->num_neigh; i++) {
+ fprintf(f, "NEIGHBOR " MACSTR " " MACSTR "\n",
+ MAC2STR(bss->bssid),
+ MAC2STR(bss->neigh + i * ETH_ALEN));
+ }
+ }
+
+ fclose(f);
+}
+
+
+static int in_array(int *array, int val)
+{
+ int i;
+
+ if (array == NULL)
+ return 0;
+
+ for (i = 0; array[i]; i++) {
+ if (array[i] == val)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int * bgscan_learn_get_freqs(struct bgscan_learn_data *data,
+ size_t *count)
+{
+ struct bgscan_learn_bss *bss;
+ int *freqs = NULL, *n;
+
+ *count = 0;
+
+ dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) {
+ if (in_array(freqs, bss->freq))
+ continue;
+ n = os_realloc_array(freqs, *count + 2, sizeof(int));
+ if (n == NULL)
+ return freqs;
+ freqs = n;
+ freqs[*count] = bss->freq;
+ (*count)++;
+ freqs[*count] = 0;
+ }
+
+ return freqs;
+}
+
+
+static int * bgscan_learn_get_probe_freq(struct bgscan_learn_data *data,
+ int *freqs, size_t count)
+{
+ int idx, *n;
+
+ if (data->supp_freqs == NULL)
+ return freqs;
+
+ idx = data->probe_idx + 1;
+ while (idx != data->probe_idx) {
+ if (data->supp_freqs[idx] == 0) {
+ if (data->probe_idx == 0)
+ break;
+ idx = 0;
+ }
+ if (!in_array(freqs, data->supp_freqs[idx])) {
+ wpa_printf(MSG_DEBUG, "bgscan learn: Probe new freq "
+ "%u", data->supp_freqs[idx]);
+ data->probe_idx = idx;
+ n = os_realloc_array(freqs, count + 2, sizeof(int));
+ if (n == NULL)
+ return freqs;
+ freqs = n;
+ freqs[count] = data->supp_freqs[idx];
+ count++;
+ freqs[count] = 0;
+ break;
+ }
+
+ idx++;
+ }
+
+ return freqs;
+}
+
+
+static void bgscan_learn_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct bgscan_learn_data *data = eloop_ctx;
+ struct wpa_supplicant *wpa_s = data->wpa_s;
+ struct wpa_driver_scan_params params;
+ int *freqs = NULL;
+ size_t count, i;
+ char msg[100], *pos;
+
+ os_memset(&params, 0, sizeof(params));
+ params.num_ssids = 1;
+ params.ssids[0].ssid = data->ssid->ssid;
+ params.ssids[0].ssid_len = data->ssid->ssid_len;
+ if (data->ssid->scan_freq)
+ params.freqs = data->ssid->scan_freq;
+ else {
+ freqs = bgscan_learn_get_freqs(data, &count);
+ wpa_printf(MSG_DEBUG, "bgscan learn: BSSes in this ESS have "
+ "been seen on %u channels", (unsigned int) count);
+ freqs = bgscan_learn_get_probe_freq(data, freqs, count);
+
+ msg[0] = '\0';
+ pos = msg;
+ for (i = 0; freqs && freqs[i]; i++) {
+ int ret;
+ ret = os_snprintf(pos, msg + sizeof(msg) - pos, " %d",
+ freqs[i]);
+ if (ret < 0 || ret >= msg + sizeof(msg) - pos)
+ break;
+ pos += ret;
+ }
+ pos[0] = '\0';
+ wpa_printf(MSG_DEBUG, "bgscan learn: Scanning frequencies:%s",
+ msg);
+ params.freqs = freqs;
+ }
+
+ wpa_printf(MSG_DEBUG, "bgscan learn: Request a background scan");
+ if (wpa_supplicant_trigger_scan(wpa_s, &params)) {
+ wpa_printf(MSG_DEBUG, "bgscan learn: Failed to trigger scan");
+ eloop_register_timeout(data->scan_interval, 0,
+ bgscan_learn_timeout, data, NULL);
+ } else
+ os_get_time(&data->last_bgscan);
+ os_free(freqs);
+}
+
+
+static int bgscan_learn_get_params(struct bgscan_learn_data *data,
+ const char *params)
+{
+ const char *pos;
+
+ if (params == NULL)
+ return 0;
+
+ data->short_interval = atoi(params);
+
+ pos = os_strchr(params, ':');
+ if (pos == NULL)
+ return 0;
+ pos++;
+ data->signal_threshold = atoi(pos);
+ pos = os_strchr(pos, ':');
+ if (pos == NULL) {
+ wpa_printf(MSG_ERROR, "bgscan learn: Missing scan interval "
+ "for high signal");
+ return -1;
+ }
+ pos++;
+ data->long_interval = atoi(pos);
+ pos = os_strchr(pos, ':');
+ if (pos) {
+ pos++;
+ data->fname = os_strdup(pos);
+ }
+
+ return 0;
+}
+
+
+static int * bgscan_learn_get_supp_freqs(struct wpa_supplicant *wpa_s)
+{
+ struct hostapd_hw_modes *modes;
+ int i, j, *freqs = NULL, *n;
+ size_t count = 0;
+
+ modes = wpa_s->hw.modes;
+ if (modes == NULL)
+ return NULL;
+
+ for (i = 0; i < wpa_s->hw.num_modes; i++) {
+ for (j = 0; j < modes[i].num_channels; j++) {
+ if (modes[i].channels[j].flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+ n = os_realloc_array(freqs, count + 2, sizeof(int));
+ if (n == NULL)
+ continue;
+
+ freqs = n;
+ freqs[count] = modes[i].channels[j].freq;
+ count++;
+ freqs[count] = 0;
+ }
+ }
+
+ return freqs;
+}
+
+
+static void * bgscan_learn_init(struct wpa_supplicant *wpa_s,
+ const char *params,
+ const struct wpa_ssid *ssid)
+{
+ struct bgscan_learn_data *data;
+
+ data = os_zalloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+ dl_list_init(&data->bss);
+ data->wpa_s = wpa_s;
+ data->ssid = ssid;
+ if (bgscan_learn_get_params(data, params) < 0) {
+ os_free(data->fname);
+ os_free(data);
+ return NULL;
+ }
+ if (data->short_interval <= 0)
+ data->short_interval = 30;
+ if (data->long_interval <= 0)
+ data->long_interval = 30;
+
+ if (bgscan_learn_load(data) < 0) {
+ os_free(data->fname);
+ os_free(data);
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "bgscan learn: Signal strength threshold %d "
+ "Short bgscan interval %d Long bgscan interval %d",
+ data->signal_threshold, data->short_interval,
+ data->long_interval);
+
+ if (data->signal_threshold &&
+ wpa_drv_signal_monitor(wpa_s, data->signal_threshold, 4) < 0) {
+ wpa_printf(MSG_ERROR, "bgscan learn: Failed to enable "
+ "signal strength monitoring");
+ }
+
+ data->supp_freqs = bgscan_learn_get_supp_freqs(wpa_s);
+ data->scan_interval = data->short_interval;
+ eloop_register_timeout(data->scan_interval, 0, bgscan_learn_timeout,
+ data, NULL);
+
+ /*
+ * This function is called immediately after an association, so it is
+ * reasonable to assume that a scan was completed recently. This makes
+ * us skip an immediate new scan in cases where the current signal
+ * level is below the bgscan threshold.
+ */
+ os_get_time(&data->last_bgscan);
+
+ return data;
+}
+
+
+static void bgscan_learn_deinit(void *priv)
+{
+ struct bgscan_learn_data *data = priv;
+ struct bgscan_learn_bss *bss, *n;
+
+ bgscan_learn_save(data);
+ eloop_cancel_timeout(bgscan_learn_timeout, data, NULL);
+ if (data->signal_threshold)
+ wpa_drv_signal_monitor(data->wpa_s, 0, 0);
+ os_free(data->fname);
+ dl_list_for_each_safe(bss, n, &data->bss, struct bgscan_learn_bss,
+ list) {
+ dl_list_del(&bss->list);
+ bss_free(bss);
+ }
+ os_free(data->supp_freqs);
+ os_free(data);
+}
+
+
+static int bgscan_learn_bss_match(struct bgscan_learn_data *data,
+ struct wpa_scan_res *bss)
+{
+ const u8 *ie;
+
+ ie = wpa_scan_get_ie(bss, WLAN_EID_SSID);
+ if (ie == NULL)
+ return 0;
+
+ if (data->ssid->ssid_len != ie[1] ||
+ os_memcmp(data->ssid->ssid, ie + 2, ie[1]) != 0)
+ return 0; /* SSID mismatch */
+
+ return 1;
+}
+
+
+static int bgscan_learn_notify_scan(void *priv,
+ struct wpa_scan_results *scan_res)
+{
+ struct bgscan_learn_data *data = priv;
+ size_t i, j;
+#define MAX_BSS 50
+ u8 bssid[MAX_BSS * ETH_ALEN];
+ size_t num_bssid = 0;
+
+ wpa_printf(MSG_DEBUG, "bgscan learn: scan result notification");
+
+ eloop_cancel_timeout(bgscan_learn_timeout, data, NULL);
+ eloop_register_timeout(data->scan_interval, 0, bgscan_learn_timeout,
+ data, NULL);
+
+ for (i = 0; i < scan_res->num; i++) {
+ struct wpa_scan_res *res = scan_res->res[i];
+ if (!bgscan_learn_bss_match(data, res))
+ continue;
+
+ if (num_bssid < MAX_BSS) {
+ os_memcpy(bssid + num_bssid * ETH_ALEN, res->bssid,
+ ETH_ALEN);
+ num_bssid++;
+ }
+ }
+ wpa_printf(MSG_DEBUG, "bgscan learn: %u matching BSSes in scan "
+ "results", (unsigned int) num_bssid);
+
+ for (i = 0; i < scan_res->num; i++) {
+ struct wpa_scan_res *res = scan_res->res[i];
+ struct bgscan_learn_bss *bss;
+
+ if (!bgscan_learn_bss_match(data, res))
+ continue;
+
+ bss = bgscan_learn_get_bss(data, res->bssid);
+ if (bss && bss->freq != res->freq) {
+ wpa_printf(MSG_DEBUG, "bgscan learn: Update BSS "
+ MACSTR " freq %d -> %d",
+ MAC2STR(res->bssid), bss->freq, res->freq);
+ bss->freq = res->freq;
+ } else if (!bss) {
+ wpa_printf(MSG_DEBUG, "bgscan learn: Add BSS " MACSTR
+ " freq=%d", MAC2STR(res->bssid), res->freq);
+ bss = os_zalloc(sizeof(*bss));
+ if (!bss)
+ continue;
+ os_memcpy(bss->bssid, res->bssid, ETH_ALEN);
+ bss->freq = res->freq;
+ dl_list_add(&data->bss, &bss->list);
+ }
+
+ for (j = 0; j < num_bssid; j++) {
+ u8 *addr = bssid + j * ETH_ALEN;
+ bgscan_learn_add_neighbor(bss, addr);
+ }
+ }
+
+ /*
+ * A more advanced bgscan could process scan results internally, select
+ * the BSS and request roam if needed. This sample uses the existing
+ * BSS/ESS selection routine. Change this to return 1 if selection is
+ * done inside the bgscan module.
+ */
+
+ return 0;
+}
+
+
+static void bgscan_learn_notify_beacon_loss(void *priv)
+{
+ wpa_printf(MSG_DEBUG, "bgscan learn: beacon loss");
+ /* TODO: speed up background scanning */
+}
+
+
+static void bgscan_learn_notify_signal_change(void *priv, int above,
+ int current_signal,
+ int current_noise,
+ int current_txrate)
+{
+ struct bgscan_learn_data *data = priv;
+ int scan = 0;
+ struct os_time now;
+
+ if (data->short_interval == data->long_interval ||
+ data->signal_threshold == 0)
+ return;
+
+ wpa_printf(MSG_DEBUG, "bgscan learn: signal level changed "
+ "(above=%d current_signal=%d current_noise=%d "
+ "current_txrate=%d)", above, current_signal,
+ current_noise, current_txrate);
+ if (data->scan_interval == data->long_interval && !above) {
+ wpa_printf(MSG_DEBUG, "bgscan learn: Start using short bgscan "
+ "interval");
+ data->scan_interval = data->short_interval;
+ os_get_time(&now);
+ if (now.sec > data->last_bgscan.sec + 1)
+ scan = 1;
+ } else if (data->scan_interval == data->short_interval && above) {
+ wpa_printf(MSG_DEBUG, "bgscan learn: Start using long bgscan "
+ "interval");
+ data->scan_interval = data->long_interval;
+ eloop_cancel_timeout(bgscan_learn_timeout, data, NULL);
+ eloop_register_timeout(data->scan_interval, 0,
+ bgscan_learn_timeout, data, NULL);
+ } else if (!above) {
+ /*
+ * Signal dropped further 4 dB. Request a new scan if we have
+ * not yet scanned in a while.
+ */
+ os_get_time(&now);
+ if (now.sec > data->last_bgscan.sec + 10)
+ scan = 1;
+ }
+
+ if (scan) {
+ wpa_printf(MSG_DEBUG, "bgscan learn: Trigger immediate scan");
+ eloop_cancel_timeout(bgscan_learn_timeout, data, NULL);
+ eloop_register_timeout(0, 0, bgscan_learn_timeout, data, NULL);
+ }
+}
+
+
+const struct bgscan_ops bgscan_learn_ops = {
+ .name = "learn",
+ .init = bgscan_learn_init,
+ .deinit = bgscan_learn_deinit,
+ .notify_scan = bgscan_learn_notify_scan,
+ .notify_beacon_loss = bgscan_learn_notify_beacon_loss,
+ .notify_signal_change = bgscan_learn_notify_signal_change,
+};
diff --git a/wpa_supplicant/bgscan_simple.c b/wpa_supplicant/bgscan_simple.c
index 8e80b129ebf4..479f703ba959 100644
--- a/wpa_supplicant/bgscan_simple.c
+++ b/wpa_supplicant/bgscan_simple.c
@@ -2,14 +2,8 @@
* WPA Supplicant - background scan and roaming module: simple
* Copyright (c) 2009-2010, 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -28,6 +22,8 @@ struct bgscan_simple_data {
const struct wpa_ssid *ssid;
int scan_interval;
int signal_threshold;
+ int short_scan_count; /* counter for scans using short scan interval */
+ int max_short_scans; /* maximum times we short-scan before back-off */
int short_interval; /* use if signal < threshold */
int long_interval; /* use if signal > threshold */
struct os_time last_bgscan;
@@ -57,8 +53,30 @@ static void bgscan_simple_timeout(void *eloop_ctx, void *timeout_ctx)
wpa_printf(MSG_DEBUG, "bgscan simple: Failed to trigger scan");
eloop_register_timeout(data->scan_interval, 0,
bgscan_simple_timeout, data, NULL);
- } else
+ } else {
+ if (data->scan_interval == data->short_interval) {
+ data->short_scan_count++;
+ /*
+ * Spend at most the duration of a long scan interval
+ * scanning at the short scan interval. After that,
+ * revert to the long scan interval.
+ */
+ if (data->short_scan_count > data->max_short_scans) {
+ data->scan_interval = data->long_interval;
+ wpa_printf(MSG_DEBUG, "bgscan simple: Backing "
+ "off to long scan interval");
+ }
+ } else if (data->short_scan_count > 0) {
+ /*
+ * If we lasted a long scan interval without any
+ * CQM triggers, decrease the short-scan count,
+ * which allows 1 more short-scan interval to
+ * occur in the future when CQM triggers.
+ */
+ data->short_scan_count--;
+ }
os_get_time(&data->last_bgscan);
+ }
}
@@ -122,6 +140,16 @@ static void * bgscan_simple_init(struct wpa_supplicant *wpa_s,
}
data->scan_interval = data->short_interval;
+ data->max_short_scans = data->long_interval / data->short_interval + 1;
+ if (data->signal_threshold) {
+ /* Poll for signal info to set initial scan interval */
+ struct wpa_signal_info siginfo;
+ if (wpa_drv_signal_poll(wpa_s, &siginfo) == 0 &&
+ siginfo.current_signal >= data->signal_threshold)
+ data->scan_interval = data->long_interval;
+ }
+ wpa_printf(MSG_DEBUG, "bgscan simple: Init scan interval: %d",
+ data->scan_interval);
eloop_register_timeout(data->scan_interval, 0, bgscan_simple_timeout,
data, NULL);
@@ -147,7 +175,8 @@ static void bgscan_simple_deinit(void *priv)
}
-static int bgscan_simple_notify_scan(void *priv)
+static int bgscan_simple_notify_scan(void *priv,
+ struct wpa_scan_results *scan_res)
{
struct bgscan_simple_data *data = priv;
@@ -175,7 +204,10 @@ static void bgscan_simple_notify_beacon_loss(void *priv)
}
-static void bgscan_simple_notify_signal_change(void *priv, int above)
+static void bgscan_simple_notify_signal_change(void *priv, int above,
+ int current_signal,
+ int current_noise,
+ int current_txrate)
{
struct bgscan_simple_data *data = priv;
int scan = 0;
@@ -186,14 +218,35 @@ static void bgscan_simple_notify_signal_change(void *priv, int above)
return;
wpa_printf(MSG_DEBUG, "bgscan simple: signal level changed "
- "(above=%d)", above);
+ "(above=%d current_signal=%d current_noise=%d "
+ "current_txrate=%d))", above, current_signal,
+ current_noise, current_txrate);
if (data->scan_interval == data->long_interval && !above) {
wpa_printf(MSG_DEBUG, "bgscan simple: Start using short "
"bgscan interval");
data->scan_interval = data->short_interval;
os_get_time(&now);
- if (now.sec > data->last_bgscan.sec + 1)
+ if (now.sec > data->last_bgscan.sec + 1 &&
+ data->short_scan_count <= data->max_short_scans)
+ /*
+ * If we haven't just previously (<1 second ago)
+ * performed a scan, and we haven't depleted our
+ * budget for short-scans, perform a scan
+ * immediately.
+ */
scan = 1;
+ else if (data->last_bgscan.sec + data->long_interval >
+ now.sec + data->scan_interval) {
+ /*
+ * Restart scan interval timer if currently scheduled
+ * scan is too far in the future.
+ */
+ eloop_cancel_timeout(bgscan_simple_timeout, data,
+ NULL);
+ eloop_register_timeout(data->scan_interval, 0,
+ bgscan_simple_timeout, data,
+ NULL);
+ }
} else if (data->scan_interval == data->short_interval && above) {
wpa_printf(MSG_DEBUG, "bgscan simple: Start using long bgscan "
"interval");
diff --git a/wpa_supplicant/blacklist.c b/wpa_supplicant/blacklist.c
index 4ffb22097370..e53dc38b3ec8 100644
--- a/wpa_supplicant/blacklist.c
+++ b/wpa_supplicant/blacklist.c
@@ -2,14 +2,8 @@
* 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -29,6 +23,9 @@ struct wpa_blacklist * wpa_blacklist_get(struct wpa_supplicant *wpa_s,
{
struct wpa_blacklist *e;
+ if (wpa_s == NULL || bssid == NULL)
+ return NULL;
+
e = wpa_s->blacklist;
while (e) {
if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0)
@@ -44,7 +41,7 @@ struct wpa_blacklist * wpa_blacklist_get(struct wpa_supplicant *wpa_s,
* 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
+ * Returns: Current blacklist count 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
@@ -60,13 +57,16 @@ int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
{
struct wpa_blacklist *e;
+ if (wpa_s == NULL || bssid == NULL)
+ return -1;
+
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;
+ return e->count;
}
e = os_zalloc(sizeof(*e));
@@ -79,7 +79,7 @@ int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
wpa_printf(MSG_DEBUG, "Added BSSID " MACSTR " into blacklist",
MAC2STR(bssid));
- return 0;
+ return e->count;
}
@@ -93,6 +93,9 @@ int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid)
{
struct wpa_blacklist *e, *prev = NULL;
+ if (wpa_s == NULL || bssid == NULL)
+ return -1;
+
e = wpa_s->blacklist;
while (e) {
if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0) {
@@ -120,14 +123,19 @@ int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid)
void wpa_blacklist_clear(struct wpa_supplicant *wpa_s)
{
struct wpa_blacklist *e, *prev;
+ int max_count = 0;
e = wpa_s->blacklist;
wpa_s->blacklist = NULL;
while (e) {
+ if (e->count > max_count)
+ max_count = e->count;
prev = e;
e = e->next;
wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR " from "
"blacklist (clear)", MAC2STR(prev->bssid));
os_free(prev);
}
+
+ wpa_s->extra_blacklist_count += max_count;
}
diff --git a/wpa_supplicant/blacklist.h b/wpa_supplicant/blacklist.h
index de280cd71568..ae06986f37c6 100644
--- a/wpa_supplicant/blacklist.h
+++ b/wpa_supplicant/blacklist.h
@@ -2,14 +2,8 @@
* 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef BLACKLIST_H
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index e2ac2307266a..87b7db89a76c 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -1,15 +1,9 @@
/*
* BSS table
- * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2012, 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "utils/includes.h"
@@ -30,25 +24,6 @@
*/
#define WPA_BSS_EXPIRATION_PERIOD 10
-/**
- * WPA_BSS_EXPIRATION_AGE - BSS entry age after which it can be expired
- *
- * This value control the time in seconds after which a BSS entry gets removed
- * if it has not been updated or is not in use.
- */
-#define WPA_BSS_EXPIRATION_AGE 180
-
-/**
- * WPA_BSS_EXPIRATION_SCAN_COUNT - Expire BSS after number of scans
- *
- * If the BSS entry has not been seen in this many scans, it will be removed.
- * Value 1 means that the entry is removed after the first scan without the
- * BSSID being seen. Larger values can be used to avoid BSS entries
- * disappearing if they are not visible in every scan (e.g., low signal quality
- * or interference).
- */
-#define WPA_BSS_EXPIRATION_SCAN_COUNT 2
-
#define WPA_BSS_FREQ_CHANGED_FLAG BIT(0)
#define WPA_BSS_SIGNAL_CHANGED_FLAG BIT(1)
#define WPA_BSS_PRIVACY_CHANGED_FLAG BIT(2)
@@ -60,23 +35,185 @@
#define WPA_BSS_IES_CHANGED_FLAG BIT(8)
-static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+static void wpa_bss_set_hessid(struct wpa_bss *bss)
+{
+#ifdef CONFIG_INTERWORKING
+ const u8 *ie = wpa_bss_get_ie(bss, WLAN_EID_INTERWORKING);
+ if (ie == NULL || (ie[1] != 7 && ie[1] != 9)) {
+ os_memset(bss->hessid, 0, ETH_ALEN);
+ return;
+ }
+ if (ie[1] == 7)
+ os_memcpy(bss->hessid, ie + 3, ETH_ALEN);
+ else
+ os_memcpy(bss->hessid, ie + 5, ETH_ALEN);
+#endif /* CONFIG_INTERWORKING */
+}
+
+
+/**
+ * wpa_bss_anqp_alloc - Allocate ANQP data structure for a BSS entry
+ * Returns: Allocated ANQP data structure or %NULL on failure
+ *
+ * The allocated ANQP data structure has its users count set to 1. It may be
+ * shared by multiple BSS entries and each shared entry is freed with
+ * wpa_bss_anqp_free().
+ */
+struct wpa_bss_anqp * wpa_bss_anqp_alloc(void)
+{
+ struct wpa_bss_anqp *anqp;
+ anqp = os_zalloc(sizeof(*anqp));
+ if (anqp == NULL)
+ return NULL;
+ anqp->users = 1;
+ return anqp;
+}
+
+
+/**
+ * wpa_bss_anqp_clone - Clone an ANQP data structure
+ * @anqp: ANQP data structure from wpa_bss_anqp_alloc()
+ * Returns: Cloned ANQP data structure or %NULL on failure
+ */
+static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp)
+{
+ struct wpa_bss_anqp *n;
+
+ n = os_zalloc(sizeof(*n));
+ if (n == NULL)
+ return NULL;
+
+#define ANQP_DUP(f) if (anqp->f) n->f = wpabuf_dup(anqp->f)
+#ifdef CONFIG_INTERWORKING
+ ANQP_DUP(venue_name);
+ ANQP_DUP(network_auth_type);
+ ANQP_DUP(roaming_consortium);
+ ANQP_DUP(ip_addr_type_availability);
+ ANQP_DUP(nai_realm);
+ ANQP_DUP(anqp_3gpp);
+ ANQP_DUP(domain_name);
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+ ANQP_DUP(hs20_operator_friendly_name);
+ ANQP_DUP(hs20_wan_metrics);
+ ANQP_DUP(hs20_connection_capability);
+ ANQP_DUP(hs20_operating_class);
+#endif /* CONFIG_HS20 */
+#undef ANQP_DUP
+
+ return n;
+}
+
+
+/**
+ * wpa_bss_anqp_unshare_alloc - Unshare ANQP data (if shared) in a BSS entry
+ * @bss: BSS entry
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function ensures the specific BSS entry has an ANQP data structure that
+ * is not shared with any other BSS entry.
+ */
+int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss)
{
+ struct wpa_bss_anqp *anqp;
+
+ if (bss->anqp && bss->anqp->users > 1) {
+ /* allocated, but shared - clone an unshared copy */
+ anqp = wpa_bss_anqp_clone(bss->anqp);
+ if (anqp == NULL)
+ return -1;
+ anqp->users = 1;
+ bss->anqp->users--;
+ bss->anqp = anqp;
+ return 0;
+ }
+
+ if (bss->anqp)
+ return 0; /* already allocated and not shared */
+
+ /* not allocated - allocate a new storage area */
+ bss->anqp = wpa_bss_anqp_alloc();
+ return bss->anqp ? 0 : -1;
+}
+
+
+/**
+ * wpa_bss_anqp_free - Free an ANQP data structure
+ * @anqp: ANQP data structure from wpa_bss_anqp_alloc() or wpa_bss_anqp_clone()
+ */
+static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
+{
+ if (anqp == NULL)
+ return;
+
+ anqp->users--;
+ if (anqp->users > 0) {
+ /* Another BSS entry holds a pointer to this ANQP info */
+ return;
+ }
+
+#ifdef CONFIG_INTERWORKING
+ wpabuf_free(anqp->venue_name);
+ wpabuf_free(anqp->network_auth_type);
+ wpabuf_free(anqp->roaming_consortium);
+ wpabuf_free(anqp->ip_addr_type_availability);
+ wpabuf_free(anqp->nai_realm);
+ wpabuf_free(anqp->anqp_3gpp);
+ wpabuf_free(anqp->domain_name);
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+ wpabuf_free(anqp->hs20_operator_friendly_name);
+ wpabuf_free(anqp->hs20_wan_metrics);
+ wpabuf_free(anqp->hs20_connection_capability);
+ wpabuf_free(anqp->hs20_operating_class);
+#endif /* CONFIG_HS20 */
+
+ os_free(anqp);
+}
+
+
+static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ const char *reason)
+{
+ if (wpa_s->last_scan_res) {
+ unsigned int i;
+ for (i = 0; i < wpa_s->last_scan_res_used; i++) {
+ if (wpa_s->last_scan_res[i] == bss) {
+ os_memmove(&wpa_s->last_scan_res[i],
+ &wpa_s->last_scan_res[i + 1],
+ (wpa_s->last_scan_res_used - i - 1)
+ * sizeof(struct wpa_bss *));
+ wpa_s->last_scan_res_used--;
+ break;
+ }
+ }
+ }
dl_list_del(&bss->list);
dl_list_del(&bss->list_id);
wpa_s->num_bss--;
- wpa_printf(MSG_DEBUG, "BSS: Remove id %u BSSID " MACSTR " SSID '%s'",
- bss->id, MAC2STR(bss->bssid),
- wpa_ssid_txt(bss->ssid, bss->ssid_len));
+ wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Remove id %u BSSID " MACSTR
+ " SSID '%s' due to %s", bss->id, MAC2STR(bss->bssid),
+ wpa_ssid_txt(bss->ssid, bss->ssid_len), reason);
wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id);
+ wpa_bss_anqp_free(bss->anqp);
os_free(bss);
}
+/**
+ * wpa_bss_get - Fetch a BSS table entry based on BSSID and SSID
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID
+ * @ssid: SSID
+ * @ssid_len: Length of @ssid
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ */
struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
const u8 *ssid, size_t ssid_len)
{
struct wpa_bss *bss;
+ if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
+ return NULL;
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
bss->ssid_len == ssid_len &&
@@ -112,15 +249,79 @@ static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src)
}
-static void wpa_bss_add(struct wpa_supplicant *wpa_s,
- const u8 *ssid, size_t ssid_len,
- struct wpa_scan_res *res)
+static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+ struct wpa_ssid *ssid;
+
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (ssid->ssid == NULL || ssid->ssid_len == 0)
+ continue;
+ if (ssid->ssid_len == bss->ssid_len &&
+ os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+ return bss == wpa_s->current_bss ||
+ os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
+ os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0;
+}
+
+
+static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_bss *bss;
+
+ dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+ if (!wpa_bss_known(wpa_s, bss)) {
+ wpa_bss_remove(wpa_s, bss, __func__);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+
+static int wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_bss *bss;
+
+ /*
+ * Remove the oldest entry that does not match with any configured
+ * network.
+ */
+ if (wpa_bss_remove_oldest_unknown(wpa_s) == 0)
+ return 0;
+
+ /*
+ * Remove the oldest entry that isn't currently in use.
+ */
+ dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+ if (!wpa_bss_in_use(wpa_s, bss)) {
+ wpa_bss_remove(wpa_s, bss, __func__);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+
+static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
+ const u8 *ssid, size_t ssid_len,
+ struct wpa_scan_res *res)
{
struct wpa_bss *bss;
bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len);
if (bss == NULL)
- return;
+ return NULL;
bss->id = wpa_s->bss_next_id++;
bss->last_update_idx = wpa_s->bss_update_idx;
wpa_bss_copy_res(bss, res);
@@ -129,18 +330,23 @@ static void wpa_bss_add(struct wpa_supplicant *wpa_s,
bss->ie_len = res->ie_len;
bss->beacon_ie_len = res->beacon_ie_len;
os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
+ wpa_bss_set_hessid(bss);
dl_list_add_tail(&wpa_s->bss, &bss->list);
dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
wpa_s->num_bss++;
- wpa_printf(MSG_DEBUG, "BSS: Add new id %u BSSID " MACSTR " SSID '%s'",
- bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len));
+ wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Add new id %u BSSID " MACSTR
+ " SSID '%s'",
+ bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len));
wpas_notify_bss_added(wpa_s, bss->bssid, bss->id);
- if (wpa_s->num_bss > wpa_s->conf->bss_max_count) {
- /* Remove the oldest entry */
- wpa_bss_remove(wpa_s, dl_list_first(&wpa_s->bss,
- struct wpa_bss, list));
+ if (wpa_s->num_bss > wpa_s->conf->bss_max_count &&
+ wpa_bss_remove_oldest(wpa_s) != 0) {
+ wpa_printf(MSG_ERROR, "Increasing the MAX BSS count to %d "
+ "because all BSSes are in use. We should normally "
+ "not get here!", (int) wpa_s->num_bss);
+ wpa_s->conf->bss_max_count = wpa_s->num_bss;
}
+ return bss;
}
@@ -187,8 +393,11 @@ static int are_ies_equal(const struct wpa_bss *old,
new_ie_len = new_ie ? new_ie[1] + 2 : 0;
}
- ret = (old_ie_len == new_ie_len &&
- os_memcmp(old_ie, new_ie, old_ie_len) == 0);
+ if (!old_ie || !new_ie)
+ ret = !old_ie && !new_ie;
+ else
+ ret = (old_ie_len == new_ie_len &&
+ os_memcmp(old_ie, new_ie, old_ie_len) == 0);
wpabuf_free(old_ie_buff);
wpabuf_free(new_ie_buff);
@@ -269,8 +478,9 @@ static void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
}
-static void wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
- struct wpa_scan_res *res)
+static struct wpa_bss *
+wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ struct wpa_scan_res *res)
{
u32 changes;
@@ -292,6 +502,15 @@ static void wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
nbss = os_realloc(bss, sizeof(*bss) + res->ie_len +
res->beacon_ie_len);
if (nbss) {
+ unsigned int i;
+ for (i = 0; i < wpa_s->last_scan_res_used; i++) {
+ if (wpa_s->last_scan_res[i] == bss) {
+ wpa_s->last_scan_res[i] = nbss;
+ break;
+ }
+ }
+ if (wpa_s->current_bss == bss)
+ wpa_s->current_bss = nbss;
bss = nbss;
os_memcpy(bss + 1, res + 1,
res->ie_len + res->beacon_ie_len);
@@ -300,53 +519,104 @@ static void wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
}
dl_list_add(prev, &bss->list_id);
}
+ if (changes & WPA_BSS_IES_CHANGED_FLAG)
+ wpa_bss_set_hessid(bss);
dl_list_add_tail(&wpa_s->bss, &bss->list);
notify_bss_changes(wpa_s, changes, bss);
-}
-
-static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
-{
- return bss == wpa_s->current_bss ||
- os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
- os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0;
+ return bss;
}
+/**
+ * wpa_bss_update_start - Start a BSS table update from scan results
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is called at the start of each BSS table update round for new
+ * scan results. The actual scan result entries are indicated with calls to
+ * wpa_bss_update_scan_res() and the update round is finished with a call to
+ * wpa_bss_update_end().
+ */
void wpa_bss_update_start(struct wpa_supplicant *wpa_s)
{
wpa_s->bss_update_idx++;
- wpa_printf(MSG_DEBUG, "BSS: Start scan result update %u",
- wpa_s->bss_update_idx);
+ wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Start scan result update %u",
+ wpa_s->bss_update_idx);
+ wpa_s->last_scan_res_used = 0;
}
+/**
+ * wpa_bss_update_scan_res - Update a BSS table entry based on a scan result
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @res: Scan result
+ *
+ * This function updates a BSS table entry (or adds one) based on a scan result.
+ * This is called separately for each scan result between the calls to
+ * wpa_bss_update_start() and wpa_bss_update_end().
+ */
void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
struct wpa_scan_res *res)
{
- const u8 *ssid;
+ const u8 *ssid, *p2p;
struct wpa_bss *bss;
ssid = wpa_scan_get_ie(res, WLAN_EID_SSID);
if (ssid == NULL) {
- wpa_printf(MSG_DEBUG, "BSS: No SSID IE included for " MACSTR,
- MAC2STR(res->bssid));
+ wpa_dbg(wpa_s, MSG_DEBUG, "BSS: No SSID IE included for "
+ MACSTR, MAC2STR(res->bssid));
return;
}
if (ssid[1] > 32) {
- wpa_printf(MSG_DEBUG, "BSS: Too long SSID IE included for "
- MACSTR, MAC2STR(res->bssid));
+ wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Too long SSID IE included for "
+ MACSTR, MAC2STR(res->bssid));
return;
}
+ p2p = wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE);
+#ifdef CONFIG_P2P
+ if (p2p == NULL &&
+ wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
+ /*
+ * If it's a P2P specific interface, then don't update
+ * the scan result without a P2P IE.
+ */
+ wpa_printf(MSG_DEBUG, "BSS: No P2P IE - skipping BSS " MACSTR
+ " update for P2P interface", MAC2STR(res->bssid));
+ return;
+ }
+#endif /* CONFIG_P2P */
+ if (p2p && ssid[1] == P2P_WILDCARD_SSID_LEN &&
+ os_memcmp(ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0)
+ return; /* Skip P2P listen discovery results here */
+
/* TODO: add option for ignoring BSSes we are not interested in
* (to save memory) */
bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
if (bss == NULL)
- wpa_bss_add(wpa_s, ssid + 2, ssid[1], res);
+ bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res);
else
- wpa_bss_update(wpa_s, bss, res);
+ bss = wpa_bss_update(wpa_s, bss, res);
+
+ if (bss == NULL)
+ return;
+ if (wpa_s->last_scan_res_used >= wpa_s->last_scan_res_size) {
+ struct wpa_bss **n;
+ unsigned int siz;
+ if (wpa_s->last_scan_res_size == 0)
+ siz = 32;
+ else
+ siz = wpa_s->last_scan_res_size * 2;
+ n = os_realloc_array(wpa_s->last_scan_res, siz,
+ sizeof(struct wpa_bss *));
+ if (n == NULL)
+ return;
+ wpa_s->last_scan_res = n;
+ wpa_s->last_scan_res_size = siz;
+ }
+
+ wpa_s->last_scan_res[wpa_s->last_scan_res_used++] = bss;
}
@@ -391,14 +661,41 @@ static int wpa_bss_included_in_scan(const struct wpa_bss *bss,
}
+/**
+ * wpa_bss_update_end - End a BSS table update from scan results
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @info: Information about scan parameters
+ * @new_scan: Whether this update round was based on a new scan
+ *
+ * This function is called at the end of each BSS table update round for new
+ * scan results. The start of the update was indicated with a call to
+ * wpa_bss_update_start().
+ */
void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
int new_scan)
{
struct wpa_bss *bss, *n;
+ wpa_s->last_scan_full = 0;
+ os_get_time(&wpa_s->last_scan);
if (!new_scan)
return; /* do not expire entries without new scan */
+ if (info && !info->aborted && !info->freqs) {
+ size_t i;
+ if (info->num_ssids == 0) {
+ wpa_s->last_scan_full = 1;
+ } else {
+ for (i = 0; i < info->num_ssids; i++) {
+ if (info->ssids[i].ssid == NULL ||
+ info->ssids[i].ssid_len == 0) {
+ wpa_s->last_scan_full = 1;
+ break;
+ }
+ }
+ }
+ }
+
dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
if (wpa_bss_in_use(wpa_s, bss))
continue;
@@ -406,18 +703,28 @@ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
continue; /* expire only BSSes that were scanned */
if (bss->last_update_idx < wpa_s->bss_update_idx)
bss->scan_miss_count++;
- if (bss->scan_miss_count >= WPA_BSS_EXPIRATION_SCAN_COUNT) {
- wpa_printf(MSG_DEBUG, "BSS: Expire BSS %u due to no "
- "match in scan", bss->id);
- wpa_bss_remove(wpa_s, bss);
+ if (bss->scan_miss_count >=
+ wpa_s->conf->bss_expiration_scan_count) {
+ wpa_bss_remove(wpa_s, bss, "no match in scan");
}
}
+
+ wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%u/%u "
+ "last_scan_full=%d",
+ wpa_s->last_scan_res_used, wpa_s->last_scan_res_size,
+ wpa_s->last_scan_full);
}
-static void wpa_bss_timeout(void *eloop_ctx, void *timeout_ctx)
+/**
+ * wpa_bss_flush_by_age - Flush old BSS entries
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @age: Maximum entry age in seconds
+ *
+ * Remove BSS entries that have not been updated during the last @age seconds.
+ */
+void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age)
{
- struct wpa_supplicant *wpa_s = eloop_ctx;
struct wpa_bss *bss, *n;
struct os_time t;
@@ -425,24 +732,38 @@ static void wpa_bss_timeout(void *eloop_ctx, void *timeout_ctx)
return;
os_get_time(&t);
- t.sec -= WPA_BSS_EXPIRATION_AGE;
+ t.sec -= age;
dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
if (wpa_bss_in_use(wpa_s, bss))
continue;
if (os_time_before(&bss->last_update, &t)) {
- wpa_printf(MSG_DEBUG, "BSS: Expire BSS %u due to age",
- bss->id);
- wpa_bss_remove(wpa_s, bss);
+ wpa_bss_remove(wpa_s, bss, __func__);
} else
break;
}
+}
+
+
+static void wpa_bss_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ wpa_bss_flush_by_age(wpa_s, wpa_s->conf->bss_expiration_age);
eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0,
wpa_bss_timeout, wpa_s, NULL);
}
+/**
+ * wpa_bss_init - Initialize BSS table
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This prepares BSS table lists and timer for periodic updates. The BSS table
+ * is deinitialized with wpa_bss_deinit() once not needed anymore.
+ */
int wpa_bss_init(struct wpa_supplicant *wpa_s)
{
dl_list_init(&wpa_s->bss);
@@ -453,22 +774,49 @@ int wpa_bss_init(struct wpa_supplicant *wpa_s)
}
-void wpa_bss_deinit(struct wpa_supplicant *wpa_s)
+/**
+ * wpa_bss_flush - Flush all unused BSS entries
+ * @wpa_s: Pointer to wpa_supplicant data
+ */
+void wpa_bss_flush(struct wpa_supplicant *wpa_s)
{
struct wpa_bss *bss, *n;
- eloop_cancel_timeout(wpa_bss_timeout, wpa_s, NULL);
+
if (wpa_s->bss.next == NULL)
return; /* BSS table not yet initialized */
- dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list)
- wpa_bss_remove(wpa_s, bss);
+
+ dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
+ if (wpa_bss_in_use(wpa_s, bss))
+ continue;
+ wpa_bss_remove(wpa_s, bss, __func__);
+ }
+}
+
+
+/**
+ * wpa_bss_deinit - Deinitialize BSS table
+ * @wpa_s: Pointer to wpa_supplicant data
+ */
+void wpa_bss_deinit(struct wpa_supplicant *wpa_s)
+{
+ eloop_cancel_timeout(wpa_bss_timeout, wpa_s, NULL);
+ wpa_bss_flush(wpa_s);
}
+/**
+ * wpa_bss_get_bssid - Fetch a BSS table entry based on BSSID
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ */
struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
const u8 *bssid)
{
struct wpa_bss *bss;
- dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+ if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
+ return NULL;
+ dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
return bss;
}
@@ -476,6 +824,35 @@ struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
}
+#ifdef CONFIG_P2P
+/**
+ * wpa_bss_get_p2p_dev_addr - Fetch a BSS table entry based on P2P Device Addr
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @dev_addr: P2P Device Address of the GO
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ */
+struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr)
+{
+ struct wpa_bss *bss;
+ dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
+ u8 addr[ETH_ALEN];
+ if (p2p_parse_dev_addr((const u8 *) (bss + 1), bss->ie_len,
+ addr) == 0 &&
+ os_memcmp(addr, dev_addr, ETH_ALEN) == 0)
+ return bss;
+ }
+ return NULL;
+}
+#endif /* CONFIG_P2P */
+
+
+/**
+ * wpa_bss_get_id - Fetch a BSS table entry based on identifier
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @id: Unique identifier (struct wpa_bss::id) assigned for the entry
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ */
struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
{
struct wpa_bss *bss;
@@ -487,6 +864,15 @@ struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
}
+/**
+ * wpa_bss_get_ie - Fetch a specified information element from a BSS entry
+ * @bss: BSS table entry
+ * @ie: Information element identitifier (WLAN_EID_*)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the BSS
+ * entry.
+ */
const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
{
const u8 *end, *pos;
@@ -506,6 +892,15 @@ const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
}
+/**
+ * wpa_bss_get_vendor_ie - Fetch a vendor information element from a BSS entry
+ * @bss: BSS table entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the BSS
+ * entry.
+ */
const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
{
const u8 *end, *pos;
@@ -526,6 +921,16 @@ const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
}
+/**
+ * wpa_bss_get_vendor_ie_multi - Fetch vendor IE data from a BSS entry
+ * @bss: BSS table entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element payload or %NULL if not found
+ *
+ * This function returns concatenated payload of possibly fragmented vendor
+ * specific information elements in the BSS entry. The caller is responsible for
+ * freeing the returned buffer.
+ */
struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
u32 vendor_type)
{
@@ -557,6 +962,56 @@ struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
}
+/**
+ * wpa_bss_get_vendor_ie_multi_beacon - Fetch vendor IE data from a BSS entry
+ * @bss: BSS table entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element payload or %NULL if not found
+ *
+ * This function returns concatenated payload of possibly fragmented vendor
+ * specific information elements in the BSS entry. The caller is responsible for
+ * freeing the returned buffer.
+ *
+ * This function is like wpa_bss_get_vendor_ie_multi(), but uses IE buffer only
+ * from Beacon frames instead of either Beacon or Probe Response frames.
+ */
+struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
+ u32 vendor_type)
+{
+ struct wpabuf *buf;
+ const u8 *end, *pos;
+
+ buf = wpabuf_alloc(bss->beacon_ie_len);
+ if (buf == NULL)
+ return NULL;
+
+ pos = (const u8 *) (bss + 1);
+ pos += bss->ie_len;
+ end = pos + bss->beacon_ie_len;
+
+ while (pos + 1 < end) {
+ if (pos + 2 + pos[1] > end)
+ break;
+ if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+ vendor_type == WPA_GET_BE32(&pos[2]))
+ wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
+ pos += 2 + pos[1];
+ }
+
+ if (wpabuf_len(buf) == 0) {
+ wpabuf_free(buf);
+ buf = NULL;
+ }
+
+ return buf;
+}
+
+
+/**
+ * wpa_bss_get_max_rate - Get maximum legacy TX rate supported in a BSS
+ * @bss: BSS table entry
+ * Returns: Maximum legacy rate in units of 500 kbps
+ */
int wpa_bss_get_max_rate(const struct wpa_bss *bss)
{
int rate = 0;
@@ -579,6 +1034,15 @@ int wpa_bss_get_max_rate(const struct wpa_bss *bss)
}
+/**
+ * wpa_bss_get_bit_rates - Get legacy TX rates supported in a BSS
+ * @bss: BSS table entry
+ * @rates: Buffer for returning a pointer to the rates list (units of 500 kbps)
+ * Returns: number of legacy TX rates or -1 on failure
+ *
+ * The caller is responsible for freeing the returned buffer with os_free() in
+ * case of success.
+ */
int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates)
{
const u8 *ie, *ie2;
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 1de4722a6bea..01f6c59d2388 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -2,14 +2,8 @@
* BSS table
* Copyright (c) 2009-2010, 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef BSS_H
@@ -23,49 +17,79 @@ struct wpa_scan_res;
#define WPA_BSS_LEVEL_DBM BIT(3)
#define WPA_BSS_AUTHENTICATED BIT(4)
#define WPA_BSS_ASSOCIATED BIT(5)
+#define WPA_BSS_ANQP_FETCH_TRIED BIT(6)
+
+/**
+ * struct wpa_bss_anqp - ANQP data for a BSS entry (struct wpa_bss)
+ */
+struct wpa_bss_anqp {
+ /** Number of BSS entries referring to this ANQP data instance */
+ unsigned int users;
+#ifdef CONFIG_INTERWORKING
+ struct wpabuf *venue_name;
+ struct wpabuf *network_auth_type;
+ struct wpabuf *roaming_consortium;
+ struct wpabuf *ip_addr_type_availability;
+ struct wpabuf *nai_realm;
+ struct wpabuf *anqp_3gpp;
+ struct wpabuf *domain_name;
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+ struct wpabuf *hs20_operator_friendly_name;
+ struct wpabuf *hs20_wan_metrics;
+ struct wpabuf *hs20_connection_capability;
+ struct wpabuf *hs20_operating_class;
+#endif /* CONFIG_HS20 */
+};
/**
* struct wpa_bss - BSS table
- * @list: List entry for struct wpa_supplicant::bss
- * @list_id: List entry for struct wpa_supplicant::bss_id
- * @id: Unique identifier for this BSS entry
- * @scan_miss_count: Number of counts without seeing this BSS
- * @flags: information flags about the BSS/IBSS (WPA_BSS_*)
- * @last_update_idx: Index of the last scan update
- * @bssid: BSSID
- * @freq: frequency of the channel in MHz (e.g., 2412 = channel 1)
- * @beacon_int: beacon interval in TUs (host byte order)
- * @caps: capability information field in host byte order
- * @qual: signal quality
- * @noise: noise level
- * @level: signal level
- * @tsf: Timestamp of last Beacon/Probe Response frame
- * @last_update: Time of the last update (i.e., Beacon or Probe Response RX)
- * @ie_len: length of the following IE field in octets (from Probe Response)
- * @beacon_ie_len: length of the following Beacon IE field in octets
*
* This structure is used to store information about neighboring BSSes in
* generic format. It is mainly updated based on scan results from the driver.
*/
struct wpa_bss {
+ /** List entry for struct wpa_supplicant::bss */
struct dl_list list;
+ /** List entry for struct wpa_supplicant::bss_id */
struct dl_list list_id;
+ /** Unique identifier for this BSS entry */
unsigned int id;
+ /** Number of counts without seeing this BSS */
unsigned int scan_miss_count;
+ /** Index of the last scan update */
unsigned int last_update_idx;
+ /** Information flags about the BSS/IBSS (WPA_BSS_*) */
unsigned int flags;
+ /** BSSID */
u8 bssid[ETH_ALEN];
+ /** HESSID */
+ u8 hessid[ETH_ALEN];
+ /** SSID */
u8 ssid[32];
+ /** Length of SSID */
size_t ssid_len;
+ /** Frequency of the channel in MHz (e.g., 2412 = channel 1) */
int freq;
+ /** Beacon interval in TUs (host byte order) */
u16 beacon_int;
+ /** Capability information field in host byte order */
u16 caps;
+ /** Signal quality */
int qual;
+ /** Noise level */
int noise;
+ /** Signal level */
int level;
+ /** Timestamp of last Beacon/Probe Response frame */
u64 tsf;
+ /** Time of the last update (i.e., Beacon or Probe Response RX) */
struct os_time last_update;
+ /** ANQP data */
+ struct wpa_bss_anqp *anqp;
+ /** Length of the following IE field in octets (from Probe Response) */
size_t ie_len;
+ /** Length of the following Beacon IE field in octets */
size_t beacon_ie_len;
/* followed by ie_len octets of IEs */
/* followed by beacon_ie_len octets of IEs */
@@ -78,16 +102,24 @@ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
int new_scan);
int wpa_bss_init(struct wpa_supplicant *wpa_s);
void wpa_bss_deinit(struct wpa_supplicant *wpa_s);
+void wpa_bss_flush(struct wpa_supplicant *wpa_s);
+void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age);
struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
const u8 *ssid, size_t ssid_len);
struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
const u8 *bssid);
+struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr);
struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id);
const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie);
const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type);
struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
u32 vendor_type);
+struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
+ u32 vendor_type);
int wpa_bss_get_max_rate(const struct wpa_bss *bss);
int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates);
+struct wpa_bss_anqp * wpa_bss_anqp_alloc(void);
+int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss);
#endif /* BSS_H */
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 7e2a5b44f3af..0fab07aed6dd 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1,23 +1,19 @@
/*
* WPA Supplicant / Configuration parser and common functions
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
#include "common.h"
+#include "utils/uuid.h"
#include "crypto/sha1.h"
#include "rsn_supp/wpa.h"
#include "eap_peer/eap.h"
+#include "p2p/p2p.h"
#include "config.h"
@@ -57,42 +53,6 @@ struct parse_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)
@@ -153,18 +113,6 @@ set:
#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;
@@ -283,6 +231,12 @@ static int wpa_config_parse_bssid(const struct parse_data *data,
struct wpa_ssid *ssid, int line,
const char *value)
{
+ if (value[0] == '\0' || os_strcmp(value, "\"\"") == 0 ||
+ os_strcmp(value, "any") == 0) {
+ ssid->bssid_set = 0;
+ wpa_printf(MSG_MSGDUMP, "BSSID any");
+ return 0;
+ }
if (hwaddr_aton(value, ssid->bssid)) {
wpa_printf(MSG_ERROR, "Line %d: Invalid BSSID '%s'.",
line, value);
@@ -322,6 +276,21 @@ static int wpa_config_parse_psk(const struct parse_data *data,
struct wpa_ssid *ssid, int line,
const char *value)
{
+#ifdef CONFIG_EXT_PASSWORD
+ if (os_strncmp(value, "ext:", 4) == 0) {
+ os_free(ssid->passphrase);
+ ssid->passphrase = NULL;
+ ssid->psk_set = 0;
+ os_free(ssid->ext_psk);
+ ssid->ext_psk = os_strdup(value + 4);
+ if (ssid->ext_psk == NULL)
+ return -1;
+ wpa_printf(MSG_DEBUG, "PSK: External password '%s'",
+ ssid->ext_psk);
+ return 0;
+ }
+#endif /* CONFIG_EXT_PASSWORD */
+
if (*value == '"') {
#ifndef CONFIG_NO_PBKDF2
const char *pos;
@@ -379,6 +348,17 @@ static int wpa_config_parse_psk(const struct parse_data *data,
static char * wpa_config_write_psk(const struct parse_data *data,
struct wpa_ssid *ssid)
{
+#ifdef CONFIG_EXT_PASSWORD
+ if (ssid->ext_psk) {
+ size_t len = 4 + os_strlen(ssid->ext_psk) + 1;
+ char *buf = os_malloc(len);
+ if (buf == NULL)
+ return NULL;
+ os_snprintf(buf, len, "ext:%s", ssid->ext_psk);
+ return buf;
+ }
+#endif /* CONFIG_EXT_PASSWORD */
+
if (ssid->passphrase)
return wpa_config_write_string_ascii(
(const u8 *) ssid->passphrase,
@@ -524,6 +504,12 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data,
else if (os_strcmp(start, "WPS") == 0)
val |= WPA_KEY_MGMT_WPS;
#endif /* CONFIG_WPS */
+#ifdef CONFIG_SAE
+ else if (os_strcmp(start, "SAE") == 0)
+ val |= WPA_KEY_MGMT_SAE;
+ else if (os_strcmp(start, "FT-SAE") == 0)
+ val |= WPA_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
else {
wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
line, start);
@@ -663,6 +649,8 @@ static int wpa_config_parse_cipher(int line, const char *value)
*end = '\0';
if (os_strcmp(start, "CCMP") == 0)
val |= WPA_CIPHER_CCMP;
+ else if (os_strcmp(start, "GCMP") == 0)
+ val |= WPA_CIPHER_GCMP;
else if (os_strcmp(start, "TKIP") == 0)
val |= WPA_CIPHER_TKIP;
else if (os_strcmp(start, "WEP104") == 0)
@@ -714,6 +702,16 @@ static char * wpa_config_write_cipher(int cipher)
pos += ret;
}
+ if (cipher & WPA_CIPHER_GCMP) {
+ ret = os_snprintf(pos, end - pos, "%sGCMP",
+ 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 ? "" : " ");
@@ -767,7 +765,8 @@ static int wpa_config_parse_pairwise(const struct parse_data *data,
val = wpa_config_parse_cipher(line, value);
if (val == -1)
return -1;
- if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE)) {
+ if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP |
+ WPA_CIPHER_NONE)) {
wpa_printf(MSG_ERROR, "Line %d: not allowed pairwise cipher "
"(0x%x).", line, val);
return -1;
@@ -796,8 +795,8 @@ static int wpa_config_parse_group(const struct parse_data *data,
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)) {
+ if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | 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;
@@ -927,7 +926,7 @@ static int * wpa_config_parse_freqs(const struct parse_data *data,
used = 0;
len = 10;
- freqs = os_zalloc((len + 1) * sizeof(int));
+ freqs = os_calloc(len + 1, sizeof(int));
if (freqs == NULL)
return NULL;
@@ -938,7 +937,7 @@ static int * wpa_config_parse_freqs(const struct parse_data *data,
if (used == len) {
int *n;
size_t i;
- n = os_realloc(freqs, (len * 2 + 1) * sizeof(int));
+ n = os_realloc_array(freqs, len * 2 + 1, sizeof(int));
if (n == NULL) {
os_free(freqs);
return NULL;
@@ -1067,8 +1066,8 @@ static int wpa_config_parse_eap(const struct parse_data *data,
last = *end == '\0';
*end = '\0';
tmp = methods;
- methods = os_realloc(methods,
- (num_methods + 1) * sizeof(*methods));
+ methods = os_realloc_array(methods, num_methods + 1,
+ sizeof(*methods));
if (methods == NULL) {
os_free(tmp);
os_free(buf);
@@ -1098,7 +1097,7 @@ static int wpa_config_parse_eap(const struct parse_data *data,
os_free(buf);
tmp = methods;
- methods = os_realloc(methods, (num_methods + 1) * sizeof(*methods));
+ methods = os_realloc_array(methods, num_methods + 1, sizeof(*methods));
if (methods == NULL) {
os_free(tmp);
return -1;
@@ -1109,6 +1108,7 @@ static int wpa_config_parse_eap(const struct parse_data *data,
wpa_hexdump(MSG_MSGDUMP, "eap methods",
(u8 *) methods, num_methods * sizeof(*methods));
+ os_free(ssid->eap.eap_methods);
ssid->eap.eap_methods = methods;
return errors ? -1 : 0;
}
@@ -1163,6 +1163,20 @@ static int wpa_config_parse_password(const struct parse_data *data,
return 0;
}
+#ifdef CONFIG_EXT_PASSWORD
+ if (os_strncmp(value, "ext:", 4) == 0) {
+ char *name = os_strdup(value + 4);
+ if (name == NULL)
+ return -1;
+ os_free(ssid->eap.password);
+ ssid->eap.password = (u8 *) name;
+ ssid->eap.password_len = os_strlen(name);
+ ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
+ ssid->eap.flags |= EAP_CONFIG_FLAGS_EXT_PASSWORD;
+ return 0;
+ }
+#endif /* CONFIG_EXT_PASSWORD */
+
if (os_strncmp(value, "hash:", 5) != 0) {
char *tmp;
size_t res_len;
@@ -1180,6 +1194,7 @@ static int wpa_config_parse_password(const struct parse_data *data,
ssid->eap.password = (u8 *) tmp;
ssid->eap.password_len = res_len;
ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
+ ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD;
return 0;
}
@@ -1208,6 +1223,7 @@ static int wpa_config_parse_password(const struct parse_data *data,
ssid->eap.password = hash;
ssid->eap.password_len = 16;
ssid->eap.flags |= EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
+ ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD;
return 0;
}
@@ -1221,6 +1237,17 @@ static char * wpa_config_write_password(const struct parse_data *data,
if (ssid->eap.password == NULL)
return NULL;
+#ifdef CONFIG_EXT_PASSWORD
+ if (ssid->eap.flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
+ buf = os_zalloc(4 + ssid->eap.password_len + 1);
+ if (buf == NULL)
+ return NULL;
+ os_memcpy(buf, "ext:", 4);
+ os_memcpy(buf + 4, ssid->eap.password, ssid->eap.password_len);
+ return buf;
+ }
+#endif /* CONFIG_EXT_PASSWORD */
+
if (!(ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) {
return wpa_config_write_string(
ssid->eap.password, ssid->eap.password_len);
@@ -1256,6 +1283,11 @@ static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line,
os_free(buf);
return -1;
}
+ if (*len && *len != 5 && *len != 13 && *len != 16) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key length %u - "
+ "this network block will be ignored",
+ line, (unsigned int) *len);
+ }
os_memcpy(key, buf, *len);
os_free(buf);
res = os_snprintf(title, sizeof(title), "wep_key%d", idx);
@@ -1344,6 +1376,99 @@ static char * wpa_config_write_wep_key3(const struct parse_data *data,
#endif /* NO_CONFIG_WRITE */
+#ifdef CONFIG_P2P
+
+static int wpa_config_parse_p2p_client_list(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ const char *pos;
+ u8 *buf, *n, addr[ETH_ALEN];
+ size_t count;
+
+ buf = NULL;
+ count = 0;
+
+ pos = value;
+ while (pos && *pos) {
+ while (*pos == ' ')
+ pos++;
+
+ if (hwaddr_aton(pos, addr)) {
+ if (count == 0) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "p2p_client_list address '%s'.",
+ line, value);
+ os_free(buf);
+ return -1;
+ }
+ /* continue anyway since this could have been from a
+ * truncated configuration file line */
+ wpa_printf(MSG_INFO, "Line %d: Ignore likely "
+ "truncated p2p_client_list address '%s'",
+ line, pos);
+ } else {
+ n = os_realloc_array(buf, count + 1, ETH_ALEN);
+ if (n == NULL) {
+ os_free(buf);
+ return -1;
+ }
+ buf = n;
+ os_memmove(buf + ETH_ALEN, buf, count * ETH_ALEN);
+ os_memcpy(buf, addr, ETH_ALEN);
+ count++;
+ wpa_hexdump(MSG_MSGDUMP, "p2p_client_list",
+ addr, ETH_ALEN);
+ }
+
+ pos = os_strchr(pos, ' ');
+ }
+
+ os_free(ssid->p2p_client_list);
+ ssid->p2p_client_list = buf;
+ ssid->num_p2p_clients = count;
+
+ return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_p2p_client_list(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ char *value, *end, *pos;
+ int res;
+ size_t i;
+
+ if (ssid->p2p_client_list == NULL || ssid->num_p2p_clients == 0)
+ return NULL;
+
+ value = os_malloc(20 * ssid->num_p2p_clients);
+ if (value == NULL)
+ return NULL;
+ pos = value;
+ end = value + 20 * ssid->num_p2p_clients;
+
+ for (i = ssid->num_p2p_clients; i > 0; i--) {
+ res = os_snprintf(pos, end - pos, MACSTR " ",
+ MAC2STR(ssid->p2p_client_list +
+ (i - 1) * ETH_ALEN));
+ if (res < 0 || res >= end - pos) {
+ os_free(value);
+ return NULL;
+ }
+ pos += res;
+ }
+
+ if (pos > value)
+ pos[-1] = '\0';
+
+ return value;
+}
+#endif /* NO_CONFIG_WRITE */
+
+#endif /* CONFIG_P2P */
+
/* Helper macros for network block parser */
#ifdef OFFSET
@@ -1438,6 +1563,7 @@ static const struct parse_data ssid_fields[] = {
{ FUNC_KEY(psk) },
{ FUNC(proto) },
{ FUNC(key_mgmt) },
+ { INT(bg_scan_period) },
{ FUNC(pairwise) },
{ FUNC(group) },
{ FUNC(auth_alg) },
@@ -1492,18 +1618,33 @@ static const struct parse_data ssid_fields[] = {
{ STRe(pac_file) },
{ INTe(fragment_size) },
#endif /* IEEE8021X_EAPOL */
- { INT_RANGE(mode, 0, 2) },
+ { INT_RANGE(mode, 0, 4) },
{ INT_RANGE(proactive_key_caching, 0, 1) },
- { INT_RANGE(disabled, 0, 1) },
+ { INT_RANGE(disabled, 0, 2) },
{ 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_RANGE(frequency, 0, 65000) },
{ INT(wpa_ptk_rekey) },
{ STR(bgscan) },
+ { INT_RANGE(ignore_broadcast_ssid, 0, 2) },
+#ifdef CONFIG_P2P
+ { FUNC(p2p_client_list) },
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_HT_OVERRIDES
+ { INT_RANGE(disable_ht, 0, 1) },
+ { INT_RANGE(disable_ht40, -1, 1) },
+ { INT_RANGE(disable_sgi, 0, 1) },
+ { INT_RANGE(disable_max_amsdu, -1, 1) },
+ { INT_RANGE(ampdu_factor, -1, 3) },
+ { INT_RANGE(ampdu_density, -1, 7) },
+ { STR(ht_mcs) },
+#endif /* CONFIG_HT_OVERRIDES */
+ { INT(ap_max_inactivity) },
+ { INT(dtim_period) },
};
#undef OFFSET
@@ -1557,19 +1698,20 @@ int wpa_config_add_prio_network(struct wpa_config *config,
}
/* First network for this priority - add a new priority list */
- nlist = os_realloc(config->pssid,
- (config->num_prio + 1) * sizeof(struct wpa_ssid *));
+ nlist = os_realloc_array(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)
+ if (nlist[prio]->priority < ssid->priority) {
+ os_memmove(&nlist[prio + 1], &nlist[prio],
+ (config->num_prio - prio) *
+ sizeof(struct wpa_ssid *));
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;
@@ -1663,6 +1805,7 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid)
{
os_free(ssid->ssid);
os_free(ssid->passphrase);
+ os_free(ssid->ext_psk);
#ifdef IEEE8021X_EAPOL
eap_peer_config_free(&ssid->eap);
#endif /* IEEE8021X_EAPOL */
@@ -1670,10 +1813,34 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid)
os_free(ssid->scan_freq);
os_free(ssid->freq_list);
os_free(ssid->bgscan);
+ os_free(ssid->p2p_client_list);
+#ifdef CONFIG_HT_OVERRIDES
+ os_free(ssid->ht_mcs);
+#endif /* CONFIG_HT_OVERRIDES */
os_free(ssid);
}
+void wpa_config_free_cred(struct wpa_cred *cred)
+{
+ os_free(cred->realm);
+ os_free(cred->username);
+ os_free(cred->password);
+ os_free(cred->ca_cert);
+ os_free(cred->client_cert);
+ os_free(cred->private_key);
+ os_free(cred->private_key_passwd);
+ os_free(cred->imsi);
+ os_free(cred->milenage);
+ os_free(cred->domain);
+ os_free(cred->eap_method);
+ os_free(cred->phase1);
+ os_free(cred->phase2);
+ os_free(cred->excluded_ssid);
+ os_free(cred);
+}
+
+
/**
* wpa_config_free - Free configuration data
* @config: Configuration data from wpa_config_read()
@@ -1687,6 +1854,8 @@ void wpa_config_free(struct wpa_config *config)
struct wpa_config_blob *blob, *prevblob;
#endif /* CONFIG_NO_CONFIG_BLOBS */
struct wpa_ssid *ssid, *prev = NULL;
+ struct wpa_cred *cred, *cprev;
+
ssid = config->ssid;
while (ssid) {
prev = ssid;
@@ -1694,6 +1863,13 @@ void wpa_config_free(struct wpa_config *config)
wpa_config_free_ssid(prev);
}
+ cred = config->cred;
+ while (cred) {
+ cprev = cred;
+ cred = cred->next;
+ wpa_config_free_cred(cprev);
+ }
+
#ifndef CONFIG_NO_CONFIG_BLOBS
blob = config->blobs;
prevblob = NULL;
@@ -1704,25 +1880,59 @@ void wpa_config_free(struct wpa_config *config)
}
#endif /* CONFIG_NO_CONFIG_BLOBS */
+ wpabuf_free(config->wps_vendor_ext_m1);
os_free(config->ctrl_interface);
os_free(config->ctrl_interface_group);
os_free(config->opensc_engine_path);
os_free(config->pkcs11_engine_path);
os_free(config->pkcs11_module_path);
+ os_free(config->pcsc_reader);
+ os_free(config->pcsc_pin);
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->config_methods);
+ os_free(config->p2p_ssid_postfix);
os_free(config->pssid);
+ os_free(config->p2p_pref_chan);
+ os_free(config->autoscan);
+ wpabuf_free(config->wps_nfc_dh_pubkey);
+ wpabuf_free(config->wps_nfc_dh_privkey);
+ wpabuf_free(config->wps_nfc_dev_pw);
+ os_free(config->ext_password_backend);
os_free(config);
}
/**
+ * wpa_config_foreach_network - Iterate over each configured network
+ * @config: Configuration data from wpa_config_read()
+ * @func: Callback function to process each network
+ * @arg: Opaque argument to pass to callback function
+ *
+ * Iterate over the set of configured networks calling the specified
+ * function for each item. We guard against callbacks removing the
+ * supplied network.
+ */
+void wpa_config_foreach_network(struct wpa_config *config,
+ void (*func)(void *, struct wpa_ssid *),
+ void *arg)
+{
+ struct wpa_ssid *ssid, *next;
+
+ ssid = config->ssid;
+ while (ssid) {
+ next = ssid->next;
+ func(arg, ssid);
+ ssid = next;
+ }
+}
+
+
+/**
* wpa_config_get_network - Get configured network based on id
* @config: Configuration data from wpa_config_read()
* @id: Unique network id to search for
@@ -1820,11 +2030,24 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
ssid->pairwise_cipher = DEFAULT_PAIRWISE;
ssid->group_cipher = DEFAULT_GROUP;
ssid->key_mgmt = DEFAULT_KEY_MGMT;
+ ssid->bg_scan_period = DEFAULT_BG_SCAN_PERIOD;
#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 */
+#ifdef CONFIG_HT_OVERRIDES
+ ssid->disable_ht = DEFAULT_DISABLE_HT;
+ ssid->disable_ht40 = DEFAULT_DISABLE_HT40;
+ ssid->disable_sgi = DEFAULT_DISABLE_SGI;
+ ssid->disable_max_amsdu = DEFAULT_DISABLE_MAX_AMSDU;
+ ssid->ampdu_factor = DEFAULT_AMPDU_FACTOR;
+ ssid->ampdu_density = DEFAULT_AMPDU_DENSITY;
+#endif /* CONFIG_HT_OVERRIDES */
+ ssid->proactive_key_caching = -1;
+#ifdef CONFIG_IEEE80211W
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT;
+#endif /* CONFIG_IEEE80211W */
}
@@ -1876,10 +2099,32 @@ int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
}
+int wpa_config_set_quoted(struct wpa_ssid *ssid, const char *var,
+ const char *value)
+{
+ size_t len;
+ char *buf;
+ int ret;
+
+ len = os_strlen(value);
+ buf = os_malloc(len + 3);
+ if (buf == NULL)
+ return -1;
+ buf[0] = '"';
+ os_memcpy(buf + 1, value, len);
+ buf[len + 1] = '"';
+ buf[len + 2] = '\0';
+ ret = wpa_config_set(ssid, var, buf, 0);
+ os_free(buf);
+ return ret;
+}
+
+
/**
* wpa_config_get_all - Get all options from network configuration
* @ssid: Pointer to network configuration data
* @get_keys: Determines if keys/passwords will be included in returned list
+ * (if they may be exported)
* Returns: %NULL terminated list of all set keys and their values in the form
* of [key1, val1, key2, val2, ... , NULL]
*
@@ -1895,7 +2140,9 @@ char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys)
char **props;
int fields_num;
- props = os_zalloc(sizeof(char *) * ((2 * NUM_SSID_FIELDS) + 1));
+ get_keys = get_keys && ssid->export_keys;
+
+ props = os_calloc(2 * NUM_SSID_FIELDS + 1, sizeof(char *));
if (!props)
return NULL;
@@ -2023,8 +2270,7 @@ char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var)
void wpa_config_update_psk(struct wpa_ssid *ssid)
{
#ifndef CONFIG_NO_PBKDF2
- pbkdf2_sha1(ssid->passphrase,
- (char *) ssid->ssid, ssid->ssid_len, 4096,
+ pbkdf2_sha1(ssid->passphrase, ssid->ssid, ssid->ssid_len, 4096,
ssid->psk, PMK_LEN);
wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
ssid->psk, PMK_LEN);
@@ -2033,6 +2279,248 @@ void wpa_config_update_psk(struct wpa_ssid *ssid)
}
+int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
+ const char *value, int line)
+{
+ char *val;
+ size_t len;
+
+ if (os_strcmp(var, "priority") == 0) {
+ cred->priority = atoi(value);
+ return 0;
+ }
+
+ if (os_strcmp(var, "pcsc") == 0) {
+ cred->pcsc = atoi(value);
+ return 0;
+ }
+
+ if (os_strcmp(var, "eap") == 0) {
+ struct eap_method_type method;
+ method.method = eap_peer_get_type(value, &method.vendor);
+ if (method.vendor == EAP_VENDOR_IETF &&
+ method.method == EAP_TYPE_NONE) {
+ wpa_printf(MSG_ERROR, "Line %d: unknown EAP type '%s' "
+ "for a credential", line, value);
+ return -1;
+ }
+ os_free(cred->eap_method);
+ cred->eap_method = os_malloc(sizeof(*cred->eap_method));
+ if (cred->eap_method == NULL)
+ return -1;
+ os_memcpy(cred->eap_method, &method, sizeof(method));
+ return 0;
+ }
+
+ if (os_strcmp(var, "password") == 0 &&
+ os_strncmp(value, "ext:", 4) == 0) {
+ os_free(cred->password);
+ cred->password = os_strdup(value);
+ cred->ext_password = 1;
+ return 0;
+ }
+
+ val = wpa_config_parse_string(value, &len);
+ if (val == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string "
+ "value '%s'.", line, var, value);
+ return -1;
+ }
+
+ if (os_strcmp(var, "realm") == 0) {
+ os_free(cred->realm);
+ cred->realm = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "username") == 0) {
+ os_free(cred->username);
+ cred->username = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "password") == 0) {
+ os_free(cred->password);
+ cred->password = val;
+ cred->ext_password = 0;
+ return 0;
+ }
+
+ if (os_strcmp(var, "ca_cert") == 0) {
+ os_free(cred->ca_cert);
+ cred->ca_cert = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "client_cert") == 0) {
+ os_free(cred->client_cert);
+ cred->client_cert = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "private_key") == 0) {
+ os_free(cred->private_key);
+ cred->private_key = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "private_key_passwd") == 0) {
+ os_free(cred->private_key_passwd);
+ cred->private_key_passwd = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "imsi") == 0) {
+ os_free(cred->imsi);
+ cred->imsi = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "milenage") == 0) {
+ os_free(cred->milenage);
+ cred->milenage = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "domain") == 0) {
+ os_free(cred->domain);
+ cred->domain = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "phase1") == 0) {
+ os_free(cred->phase1);
+ cred->phase1 = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "phase2") == 0) {
+ os_free(cred->phase2);
+ cred->phase2 = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "roaming_consortium") == 0) {
+ if (len < 3 || len > sizeof(cred->roaming_consortium)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "roaming_consortium length %d (3..15 "
+ "expected)", line, (int) len);
+ os_free(val);
+ return -1;
+ }
+ os_memcpy(cred->roaming_consortium, val, len);
+ cred->roaming_consortium_len = len;
+ os_free(val);
+ return 0;
+ }
+
+ if (os_strcmp(var, "excluded_ssid") == 0) {
+ struct excluded_ssid *e;
+
+ if (len > MAX_SSID_LEN) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "excluded_ssid length %d", line, (int) len);
+ os_free(val);
+ return -1;
+ }
+
+ e = os_realloc_array(cred->excluded_ssid,
+ cred->num_excluded_ssid + 1,
+ sizeof(struct excluded_ssid));
+ if (e == NULL) {
+ os_free(val);
+ return -1;
+ }
+ cred->excluded_ssid = e;
+
+ e = &cred->excluded_ssid[cred->num_excluded_ssid++];
+ os_memcpy(e->ssid, val, len);
+ e->ssid_len = len;
+
+ os_free(val);
+
+ return 0;
+ }
+
+ if (line) {
+ wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.",
+ line, var);
+ }
+
+ os_free(val);
+
+ return -1;
+}
+
+
+struct wpa_cred * wpa_config_get_cred(struct wpa_config *config, int id)
+{
+ struct wpa_cred *cred;
+
+ cred = config->cred;
+ while (cred) {
+ if (id == cred->id)
+ break;
+ cred = cred->next;
+ }
+
+ return cred;
+}
+
+
+struct wpa_cred * wpa_config_add_cred(struct wpa_config *config)
+{
+ int id;
+ struct wpa_cred *cred, *last = NULL;
+
+ id = -1;
+ cred = config->cred;
+ while (cred) {
+ if (cred->id > id)
+ id = cred->id;
+ last = cred;
+ cred = cred->next;
+ }
+ id++;
+
+ cred = os_zalloc(sizeof(*cred));
+ if (cred == NULL)
+ return NULL;
+ cred->id = id;
+ if (last)
+ last->next = cred;
+ else
+ config->cred = cred;
+
+ return cred;
+}
+
+
+int wpa_config_remove_cred(struct wpa_config *config, int id)
+{
+ struct wpa_cred *cred, *prev = NULL;
+
+ cred = config->cred;
+ while (cred) {
+ if (id == cred->id)
+ break;
+ prev = cred;
+ cred = cred->next;
+ }
+
+ if (cred == NULL)
+ return -1;
+
+ if (prev)
+ prev->next = cred->next;
+ else
+ config->cred = cred->next;
+
+ wpa_config_free_cred(cred);
+ return 0;
+}
+
+
#ifndef CONFIG_NO_CONFIG_BLOBS
/**
* wpa_config_get_blob - Get a named configuration blob
@@ -2124,6 +2612,15 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
const char *driver_param)
{
struct wpa_config *config;
+ const int aCWmin = 4, aCWmax = 10;
+ const struct hostapd_wmm_ac_params ac_bk =
+ { aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */
+ const struct hostapd_wmm_ac_params ac_be =
+ { aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */
+ const struct hostapd_wmm_ac_params ac_vi = /* video traffic */
+ { aCWmin - 1, aCWmin, 2, 3000 / 32, 0 };
+ const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */
+ { aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 0 };
config = os_zalloc(sizeof(*config));
if (config == NULL)
@@ -2131,7 +2628,18 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
config->eapol_version = DEFAULT_EAPOL_VERSION;
config->ap_scan = DEFAULT_AP_SCAN;
config->fast_reauth = DEFAULT_FAST_REAUTH;
+ config->p2p_go_intent = DEFAULT_P2P_GO_INTENT;
+ config->p2p_intra_bss = DEFAULT_P2P_INTRA_BSS;
+ config->p2p_go_max_inactivity = DEFAULT_P2P_GO_MAX_INACTIVITY;
config->bss_max_count = DEFAULT_BSS_MAX_COUNT;
+ config->bss_expiration_age = DEFAULT_BSS_EXPIRATION_AGE;
+ config->bss_expiration_scan_count = DEFAULT_BSS_EXPIRATION_SCAN_COUNT;
+ config->max_num_sta = DEFAULT_MAX_NUM_STA;
+ config->access_network_type = DEFAULT_ACCESS_NETWORK_TYPE;
+ config->wmm_ac_params[0] = ac_be;
+ config->wmm_ac_params[1] = ac_bk;
+ config->wmm_ac_params[2] = ac_vi;
+ config->wmm_ac_params[3] = ac_vo;
if (ctrl_interface)
config->ctrl_interface = os_strdup(ctrl_interface);
@@ -2165,3 +2673,462 @@ void wpa_config_debug_dump_networks(struct wpa_config *config)
}
}
#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+
+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;
+ unsigned int changed_flag;
+};
+
+
+static int wpa_global_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_global_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_global_config_parse_bin(const struct global_parse_data *data,
+ struct wpa_config *config, int line,
+ const char *pos)
+{
+ size_t len;
+ struct wpabuf **dst, *tmp;
+
+ len = os_strlen(pos);
+ if (len & 0x01)
+ return -1;
+
+ tmp = wpabuf_alloc(len / 2);
+ if (tmp == NULL)
+ return -1;
+
+ if (hexstr2bin(pos, wpabuf_put(tmp, len / 2), len / 2)) {
+ wpabuf_free(tmp);
+ return -1;
+ }
+
+ dst = (struct wpabuf **) (((u8 *) config) + (long) data->param1);
+ wpabuf_free(*dst);
+ *dst = tmp;
+ wpa_printf(MSG_DEBUG, "%s", data->name);
+
+ 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_device_type(
+ const struct global_parse_data *data,
+ struct wpa_config *config, int line, const char *pos)
+{
+ return wps_dev_type_str2bin(pos, config->device_type);
+}
+
+
+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;
+}
+
+
+static int wpa_config_process_wps_vendor_ext_m1(
+ const struct global_parse_data *data,
+ struct wpa_config *config, int line, const char *pos)
+{
+ struct wpabuf *tmp;
+ int len = os_strlen(pos) / 2;
+ u8 *p;
+
+ if (!len) {
+ wpa_printf(MSG_ERROR, "Line %d: "
+ "invalid wps_vendor_ext_m1", line);
+ return -1;
+ }
+
+ tmp = wpabuf_alloc(len);
+ if (tmp) {
+ p = wpabuf_put(tmp, len);
+
+ if (hexstr2bin(pos, p, len)) {
+ wpa_printf(MSG_ERROR, "Line %d: "
+ "invalid wps_vendor_ext_m1", line);
+ wpabuf_free(tmp);
+ return -1;
+ }
+
+ wpabuf_free(config->wps_vendor_ext_m1);
+ config->wps_vendor_ext_m1 = tmp;
+ } else {
+ wpa_printf(MSG_ERROR, "Can not allocate "
+ "memory for wps_vendor_ext_m1");
+ return -1;
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_P2P
+static int wpa_config_process_sec_device_type(
+ const struct global_parse_data *data,
+ struct wpa_config *config, int line, const char *pos)
+{
+ int idx;
+
+ if (config->num_sec_device_types >= MAX_SEC_DEVICE_TYPES) {
+ wpa_printf(MSG_ERROR, "Line %d: too many sec_device_type "
+ "items", line);
+ return -1;
+ }
+
+ idx = config->num_sec_device_types;
+
+ if (wps_dev_type_str2bin(pos, config->sec_device_type[idx]))
+ return -1;
+
+ config->num_sec_device_types++;
+ return 0;
+}
+
+
+static int wpa_config_process_p2p_pref_chan(
+ const struct global_parse_data *data,
+ struct wpa_config *config, int line, const char *pos)
+{
+ struct p2p_channel *pref = NULL, *n;
+ unsigned int num = 0;
+ const char *pos2;
+ u8 op_class, chan;
+
+ /* format: class:chan,class:chan,... */
+
+ while (*pos) {
+ op_class = atoi(pos);
+ pos2 = os_strchr(pos, ':');
+ if (pos2 == NULL)
+ goto fail;
+ pos2++;
+ chan = atoi(pos2);
+
+ n = os_realloc_array(pref, num + 1,
+ sizeof(struct p2p_channel));
+ if (n == NULL)
+ goto fail;
+ pref = n;
+ pref[num].op_class = op_class;
+ pref[num].chan = chan;
+ num++;
+
+ pos = os_strchr(pos2, ',');
+ if (pos == NULL)
+ break;
+ pos++;
+ }
+
+ os_free(config->p2p_pref_chan);
+ config->p2p_pref_chan = pref;
+ config->num_p2p_pref_chan = num;
+ wpa_hexdump(MSG_DEBUG, "P2P: Preferred class/channel pairs",
+ (u8 *) config->p2p_pref_chan,
+ config->num_p2p_pref_chan * sizeof(struct p2p_channel));
+
+ return 0;
+
+fail:
+ os_free(pref);
+ wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_pref_chan list", line);
+ return -1;
+}
+#endif /* CONFIG_P2P */
+
+
+static int wpa_config_process_hessid(
+ const struct global_parse_data *data,
+ struct wpa_config *config, int line, const char *pos)
+{
+ if (hwaddr_aton2(pos, config->hessid) < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid hessid '%s'",
+ line, pos);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+#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_global_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_global_config_parse_str, OFFSET(f)
+#define STR(f) _STR(f), NULL, NULL
+#define STR_RANGE(f, min, max) _STR(f), (void *) min, (void *) max
+#define BIN(f) #f, wpa_global_config_parse_bin, OFFSET(f), NULL, NULL
+
+static const struct global_parse_data global_fields[] = {
+#ifdef CONFIG_CTRL_IFACE
+ { STR(ctrl_interface), 0 },
+ { STR(ctrl_interface_group), 0 } /* deprecated */,
+#endif /* CONFIG_CTRL_IFACE */
+ { INT_RANGE(eapol_version, 1, 2), 0 },
+ { INT(ap_scan), 0 },
+ { INT(disable_scan_offload), 0 },
+ { INT(fast_reauth), 0 },
+ { STR(opensc_engine_path), 0 },
+ { STR(pkcs11_engine_path), 0 },
+ { STR(pkcs11_module_path), 0 },
+ { STR(pcsc_reader), 0 },
+ { STR(pcsc_pin), 0 },
+ { STR(driver_param), 0 },
+ { INT(dot11RSNAConfigPMKLifetime), 0 },
+ { INT(dot11RSNAConfigPMKReauthThreshold), 0 },
+ { INT(dot11RSNAConfigSATimeout), 0 },
+#ifndef CONFIG_NO_CONFIG_WRITE
+ { INT(update_config), 0 },
+#endif /* CONFIG_NO_CONFIG_WRITE */
+ { FUNC_NO_VAR(load_dynamic_eap), 0 },
+#ifdef CONFIG_WPS
+ { FUNC(uuid), CFG_CHANGED_UUID },
+ { STR_RANGE(device_name, 0, 32), CFG_CHANGED_DEVICE_NAME },
+ { STR_RANGE(manufacturer, 0, 64), CFG_CHANGED_WPS_STRING },
+ { STR_RANGE(model_name, 0, 32), CFG_CHANGED_WPS_STRING },
+ { STR_RANGE(model_number, 0, 32), CFG_CHANGED_WPS_STRING },
+ { STR_RANGE(serial_number, 0, 32), CFG_CHANGED_WPS_STRING },
+ { FUNC(device_type), CFG_CHANGED_DEVICE_TYPE },
+ { FUNC(os_version), CFG_CHANGED_OS_VERSION },
+ { STR(config_methods), CFG_CHANGED_CONFIG_METHODS },
+ { INT_RANGE(wps_cred_processing, 0, 2), 0 },
+ { FUNC(wps_vendor_ext_m1), CFG_CHANGED_VENDOR_EXTENSION },
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+ { FUNC(sec_device_type), CFG_CHANGED_SEC_DEVICE_TYPE },
+ { INT(p2p_listen_reg_class), 0 },
+ { INT(p2p_listen_channel), 0 },
+ { INT(p2p_oper_reg_class), 0 },
+ { INT(p2p_oper_channel), 0 },
+ { INT_RANGE(p2p_go_intent, 0, 15), 0 },
+ { STR(p2p_ssid_postfix), CFG_CHANGED_P2P_SSID_POSTFIX },
+ { INT_RANGE(persistent_reconnect, 0, 1), 0 },
+ { INT_RANGE(p2p_intra_bss, 0, 1), CFG_CHANGED_P2P_INTRA_BSS },
+ { INT(p2p_group_idle), 0 },
+ { FUNC(p2p_pref_chan), CFG_CHANGED_P2P_PREF_CHAN },
+ { INT(p2p_go_ht40), 0 },
+ { INT(p2p_disabled), 0 },
+ { INT(p2p_no_group_iface), 0 },
+#endif /* CONFIG_P2P */
+ { FUNC(country), CFG_CHANGED_COUNTRY },
+ { INT(bss_max_count), 0 },
+ { INT(bss_expiration_age), 0 },
+ { INT(bss_expiration_scan_count), 0 },
+ { INT_RANGE(filter_ssids, 0, 1), 0 },
+ { INT_RANGE(filter_rssi, -100, 0), 0 },
+ { INT(max_num_sta), 0 },
+ { INT_RANGE(disassoc_low_ack, 0, 1), 0 },
+#ifdef CONFIG_HS20
+ { INT_RANGE(hs20, 0, 1), 0 },
+#endif /* CONFIG_HS20 */
+ { INT_RANGE(interworking, 0, 1), 0 },
+ { FUNC(hessid), 0 },
+ { INT_RANGE(access_network_type, 0, 15), 0 },
+ { INT_RANGE(pbc_in_m1, 0, 1), 0 },
+ { STR(autoscan), 0 },
+ { INT_RANGE(wps_nfc_dev_pw_id, 0x10, 0xffff), 0 },
+ { BIN(wps_nfc_dh_pubkey), 0 },
+ { BIN(wps_nfc_dh_privkey), 0 },
+ { BIN(wps_nfc_dev_pw), 0 },
+ { STR(ext_password_backend), CFG_CHANGED_EXT_PW_BACKEND },
+ { INT(p2p_go_max_inactivity), 0 },
+ { INT_RANGE(auto_interworking, 0, 1), 0 },
+ { INT(okc), 0 },
+ { INT(pmf), 0 },
+};
+
+#undef FUNC
+#undef _INT
+#undef INT
+#undef INT_RANGE
+#undef _STR
+#undef STR
+#undef STR_RANGE
+#undef BIN
+#define NUM_GLOBAL_FIELDS (sizeof(global_fields) / sizeof(global_fields[0]))
+
+
+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;
+ }
+ config->changed_parameters |= field->changed_flag;
+ break;
+ }
+ if (i == NUM_GLOBAL_FIELDS) {
+#ifdef CONFIG_AP
+ if (os_strncmp(pos, "wmm_ac_", 7) == 0) {
+ char *tmp = os_strchr(pos, '=');
+ if (tmp == NULL) {
+ if (line < 0)
+ return -1;
+ wpa_printf(MSG_ERROR, "Line %d: invalid line "
+ "'%s'", line, pos);
+ return -1;
+ }
+ *tmp++ = '\0';
+ if (hostapd_config_wmm_ac(config->wmm_ac_params, pos,
+ tmp)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid WMM "
+ "AC item", line);
+ return -1;
+ }
+ }
+#endif /* CONFIG_AP */
+ if (line < 0)
+ return -1;
+ wpa_printf(MSG_ERROR, "Line %d: unknown global field '%s'.",
+ line, pos);
+ ret = -1;
+ }
+
+ return ret;
+}
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 754e4befeac3..bb70b9c55d73 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -1,15 +1,9 @@
/*
* WPA Supplicant / Configuration file structures
- * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef CONFIG_H
@@ -22,10 +16,210 @@
#define DEFAULT_AP_SCAN 1
#endif /* CONFIG_NO_SCAN_PROCESSING */
#define DEFAULT_FAST_REAUTH 1
+#define DEFAULT_P2P_GO_INTENT 7
+#define DEFAULT_P2P_INTRA_BSS 1
+#define DEFAULT_P2P_GO_MAX_INACTIVITY (5 * 60)
#define DEFAULT_BSS_MAX_COUNT 200
+#define DEFAULT_BSS_EXPIRATION_AGE 180
+#define DEFAULT_BSS_EXPIRATION_SCAN_COUNT 2
+#define DEFAULT_MAX_NUM_STA 128
+#define DEFAULT_ACCESS_NETWORK_TYPE 15
#include "config_ssid.h"
+#include "wps/wps.h"
+#include "common/ieee802_11_common.h"
+
+
+struct wpa_cred {
+ /**
+ * next - Next credential in the list
+ *
+ * This pointer can be used to iterate over all credentials. The head
+ * of this list is stored in the cred field of struct wpa_config.
+ */
+ struct wpa_cred *next;
+
+ /**
+ * id - Unique id for the credential
+ *
+ * This identifier is used as a unique identifier for each credential
+ * block when using the control interface. Each credential is allocated
+ * an id when it is being created, either when reading the
+ * configuration file or when a new credential is added through the
+ * control interface.
+ */
+ int id;
+
+ /**
+ * priority - Priority group
+ *
+ * By default, all networks and credentials get the same priority group
+ * (0). This field can be used to give higher priority for credentials
+ * (and similarly in struct wpa_ssid for network blocks) to change the
+ * Interworking automatic networking selection behavior. The matching
+ * network (based on either an enabled network block or a credential)
+ * with the highest priority value will be selected.
+ */
+ int priority;
+
+ /**
+ * pcsc - Use PC/SC and SIM/USIM card
+ */
+ int pcsc;
+
+ /**
+ * realm - Home Realm for Interworking
+ */
+ char *realm;
+
+ /**
+ * username - Username for Interworking network selection
+ */
+ char *username;
+
+ /**
+ * password - Password for Interworking network selection
+ */
+ char *password;
+
+ /**
+ * ext_password - Whether password is a name for external storage
+ */
+ int ext_password;
+
+ /**
+ * ca_cert - CA certificate for Interworking network selection
+ */
+ char *ca_cert;
+
+ /**
+ * client_cert - File path to client certificate file (PEM/DER)
+ *
+ * This field is used with Interworking networking selection for a case
+ * where client certificate/private key is used for authentication
+ * (EAP-TLS). 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.
+ */
+ char *client_cert;
+ /**
+ * 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 to the file 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.
+ */
+ char *private_key;
+
+ /**
+ * private_key_passwd - Password for private key file
+ */
+ char *private_key_passwd;
+
+ /**
+ * imsi - IMSI in <MCC> | <MNC> | '-' | <MSIN> format
+ */
+ char *imsi;
+
+ /**
+ * milenage - Milenage parameters for SIM/USIM simulator in
+ * <Ki>:<OPc>:<SQN> format
+ */
+ char *milenage;
+
+ /**
+ * domain - Home service provider FQDN
+ *
+ * This is used to compare against the Domain Name List to figure out
+ * whether the AP is operated by the Home SP.
+ */
+ char *domain;
+
+ /**
+ * roaming_consortium - Roaming Consortium OI
+ *
+ * If roaming_consortium_len is non-zero, this field contains the
+ * Roaming Consortium OI that can be used to determine which access
+ * points support authentication with this credential. This is an
+ * alternative to the use of the realm parameter. When using Roaming
+ * Consortium to match the network, the EAP parameters need to be
+ * pre-configured with the credential since the NAI Realm information
+ * may not be available or fetched.
+ */
+ u8 roaming_consortium[15];
+
+ /**
+ * roaming_consortium_len - Length of roaming_consortium
+ */
+ size_t roaming_consortium_len;
+
+ /**
+ * eap_method - EAP method to use
+ *
+ * Pre-configured EAP method to use with this credential or %NULL to
+ * indicate no EAP method is selected, i.e., the method will be
+ * selected automatically based on ANQP information.
+ */
+ struct eap_method_type *eap_method;
+
+ /**
+ * phase1 - Phase 1 (outer authentication) parameters
+ *
+ * Pre-configured EAP parameters or %NULL.
+ */
+ char *phase1;
+
+ /**
+ * phase2 - Phase 2 (inner authentication) parameters
+ *
+ * Pre-configured EAP parameters or %NULL.
+ */
+ char *phase2;
+
+ struct excluded_ssid {
+ u8 ssid[MAX_SSID_LEN];
+ size_t ssid_len;
+ } *excluded_ssid;
+ size_t num_excluded_ssid;
+};
+
+
+#define CFG_CHANGED_DEVICE_NAME BIT(0)
+#define CFG_CHANGED_CONFIG_METHODS BIT(1)
+#define CFG_CHANGED_DEVICE_TYPE BIT(2)
+#define CFG_CHANGED_OS_VERSION BIT(3)
+#define CFG_CHANGED_UUID BIT(4)
+#define CFG_CHANGED_COUNTRY BIT(5)
+#define CFG_CHANGED_SEC_DEVICE_TYPE BIT(6)
+#define CFG_CHANGED_P2P_SSID_POSTFIX BIT(7)
+#define CFG_CHANGED_WPS_STRING BIT(8)
+#define CFG_CHANGED_P2P_INTRA_BSS BIT(9)
+#define CFG_CHANGED_VENDOR_EXTENSION BIT(10)
+#define CFG_CHANGED_P2P_LISTEN_CHANNEL BIT(11)
+#define CFG_CHANGED_P2P_OPER_CHANNEL BIT(12)
+#define CFG_CHANGED_P2P_PREF_CHAN BIT(13)
+#define CFG_CHANGED_EXT_PW_BACKEND BIT(14)
/**
* struct wpa_config - wpa_supplicant configuration data
@@ -57,6 +251,13 @@ struct wpa_config {
int num_prio;
/**
+ * cred - Head of the credential list
+ *
+ * This is the head for the list of all the configured credentials.
+ */
+ struct wpa_cred *cred;
+
+ /**
* eapol_version - IEEE 802.1X/EAPOL version number
*
* wpa_supplicant is implemented based on IEEE Std 802.1X-2004 which
@@ -98,12 +299,21 @@ struct wpa_config {
int ap_scan;
/**
+ * disable_scan_offload - Disable automatic offloading of scan requests
+ *
+ * By default, %wpa_supplicant tries to offload scanning if the driver
+ * indicates support for this (sched_scan). This configuration
+ * parameter can be used to disable this offloading mechanism.
+ */
+ int disable_scan_offload;
+
+ /**
* 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
+ * mechanism is used. For all cases, the existence of this parameter
* in configuration is used to determine whether the control interface
* is enabled.
*
@@ -196,6 +406,23 @@ struct wpa_config {
char *pkcs11_module_path;
/**
+ * pcsc_reader - PC/SC reader name prefix
+ *
+ * If not %NULL, PC/SC reader with a name that matches this prefix is
+ * initialized for SIM/USIM access. Empty string can be used to match
+ * the first available reader.
+ */
+ char *pcsc_reader;
+
+ /**
+ * pcsc_pin - PIN for USIM, GSM SIM, and smartcards
+ *
+ * This field is used to configure PIN for SIM/USIM for EAP-SIM and
+ * EAP-AKA. If left out, this will be asked through control interface.
+ */
+ char *pcsc_pin;
+
+ /**
* driver_param - Driver interface parameters
*
* This text string is passed to the selected driver interface with the
@@ -285,26 +512,19 @@ struct wpa_config {
/**
* 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;
+ u8 device_type[WPS_DEV_TYPE_LEN];
/**
* config_methods - Config Methods
*
* This is a space-separated list of supported WPS configuration
- * methods. For example, "label display push_button keypad".
+ * methods. For example, "label virtual_display virtual_push_button
+ * keypad".
* Available methods: usba ethernet label display ext_nfc_token
- * int_nfc_token nfc_interface push_button keypad.
+ * int_nfc_token nfc_interface push_button keypad
+ * virtual_display physical_display
+ * virtual_push_button physical_push_button.
*/
char *config_methods;
@@ -333,18 +553,250 @@ struct wpa_config {
*/
int wps_cred_processing;
+#define MAX_SEC_DEVICE_TYPES 5
+ /**
+ * sec_device_types - Secondary Device Types (P2P)
+ */
+ u8 sec_device_type[MAX_SEC_DEVICE_TYPES][WPS_DEV_TYPE_LEN];
+ int num_sec_device_types;
+
+ int p2p_listen_reg_class;
+ int p2p_listen_channel;
+ int p2p_oper_reg_class;
+ int p2p_oper_channel;
+ int p2p_go_intent;
+ char *p2p_ssid_postfix;
+ int persistent_reconnect;
+ int p2p_intra_bss;
+ unsigned int num_p2p_pref_chan;
+ struct p2p_channel *p2p_pref_chan;
+
+ struct wpabuf *wps_vendor_ext_m1;
+
+#define MAX_WPS_VENDOR_EXT 10
+ /**
+ * wps_vendor_ext - Vendor extension attributes in WPS
+ */
+ struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXT];
+
+ /**
+ * p2p_group_idle - Maximum idle time in seconds for P2P group
+ *
+ * This value controls how long a P2P group is maintained after there
+ * is no other members in the group. As a GO, this means no associated
+ * stations in the group. As a P2P client, this means no GO seen in
+ * scan results. The maximum idle time is specified in seconds with 0
+ * indicating no time limit, i.e., the P2P group remains in active
+ * state indefinitely until explicitly removed. As a P2P client, the
+ * maximum idle time of P2P_MAX_CLIENT_IDLE seconds is enforced, i.e.,
+ * this parameter is mainly meant for GO use and for P2P client, it can
+ * only be used to reduce the default timeout to smaller value. A
+ * special value -1 can be used to configure immediate removal of the
+ * group for P2P client role on any disconnection after the data
+ * connection has been established.
+ */
+ int p2p_group_idle;
+
/**
* bss_max_count - Maximum number of BSS entries to keep in memory
*/
unsigned int bss_max_count;
/**
+ * bss_expiration_age - BSS entry age after which it can be expired
+ *
+ * This value controls the time in seconds after which a BSS entry
+ * gets removed if it has not been updated or is not in use.
+ */
+ unsigned int bss_expiration_age;
+
+ /**
+ * bss_expiration_scan_count - Expire BSS after number of scans
+ *
+ * If the BSS entry has not been seen in this many scans, it will be
+ * removed. A value of 1 means that entry is removed after the first
+ * scan in which the BSSID is not seen. Larger values can be used
+ * to avoid BSS entries disappearing if they are not visible in
+ * every scan (e.g., low signal quality or interference).
+ */
+ unsigned int bss_expiration_scan_count;
+
+ /**
* filter_ssids - SSID-based scan result filtering
*
* 0 = do not filter scan results
* 1 = only include configured SSIDs in scan results/BSS table
*/
int filter_ssids;
+
+ /**
+ * filter_rssi - RSSI-based scan result filtering
+ *
+ * 0 = do not filter scan results
+ * -n = filter scan results below -n dBm
+ */
+ int filter_rssi;
+
+ /**
+ * max_num_sta - Maximum number of STAs in an AP/P2P GO
+ */
+ unsigned int max_num_sta;
+
+ /**
+ * changed_parameters - Bitmap of changed parameters since last update
+ */
+ unsigned int changed_parameters;
+
+ /**
+ * disassoc_low_ack - Disassocicate stations with massive packet loss
+ */
+ int disassoc_low_ack;
+
+ /**
+ * interworking - Whether Interworking (IEEE 802.11u) is enabled
+ */
+ int interworking;
+
+ /**
+ * access_network_type - Access Network Type
+ *
+ * When Interworking is enabled, scans will be limited to APs that
+ * advertise the specified Access Network Type (0..15; with 15
+ * indicating wildcard match).
+ */
+ int access_network_type;
+
+ /**
+ * hessid - Homogenous ESS identifier
+ *
+ * If this is set (any octet is non-zero), scans will be used to
+ * request response only from BSSes belonging to the specified
+ * Homogeneous ESS. This is used only if interworking is enabled.
+ */
+ u8 hessid[ETH_ALEN];
+
+ /**
+ * hs20 - Hotspot 2.0
+ */
+ int hs20;
+
+ /**
+ * pbc_in_m1 - AP mode WPS probing workaround for PBC with Windows 7
+ *
+ * Windows 7 uses incorrect way of figuring out AP's WPS capabilities
+ * by acting as a Registrar and using M1 from the AP. The config
+ * methods attribute in that message is supposed to indicate only the
+ * configuration method supported by the AP in Enrollee role, i.e., to
+ * add an external Registrar. For that case, PBC shall not be used and
+ * as such, the PushButton config method is removed from M1 by default.
+ * If pbc_in_m1=1 is included in the configuration file, the PushButton
+ * config method is left in M1 (if included in config_methods
+ * parameter) to allow Windows 7 to use PBC instead of PIN (e.g., from
+ * a label in the AP).
+ */
+ int pbc_in_m1;
+
+ /**
+ * autoscan - Automatic scan parameters or %NULL if none
+ *
+ * This is an optional set of parameters for automatic scanning
+ * within an interface in following format:
+ * <autoscan module name>:<module parameters>
+ */
+ char *autoscan;
+
+ /**
+ * wps_nfc_dev_pw_id - NFC Device Password ID for password token
+ */
+ int wps_nfc_dev_pw_id;
+
+ /**
+ * wps_nfc_dh_pubkey - NFC DH Public Key for password token
+ */
+ struct wpabuf *wps_nfc_dh_pubkey;
+
+ /**
+ * wps_nfc_dh_privkey - NFC DH Private Key for password token
+ */
+ struct wpabuf *wps_nfc_dh_privkey;
+
+ /**
+ * wps_nfc_dev_pw - NFC Device Password for password token
+ */
+ struct wpabuf *wps_nfc_dev_pw;
+
+ /**
+ * ext_password_backend - External password backend or %NULL if none
+ *
+ * format: <backend name>[:<optional backend parameters>]
+ */
+ char *ext_password_backend;
+
+ /*
+ * p2p_go_max_inactivity - Timeout in seconds to detect STA inactivity
+ *
+ * This timeout value is used in P2P GO mode to clean up
+ * inactive stations.
+ * By default: 300 seconds.
+ */
+ int p2p_go_max_inactivity;
+
+ struct hostapd_wmm_ac_params wmm_ac_params[4];
+
+ /**
+ * auto_interworking - Whether to use network selection automatically
+ *
+ * 0 = do not automatically go through Interworking network selection
+ * (i.e., require explicit interworking_select command for this)
+ * 1 = perform Interworking network selection if one or more
+ * credentials have been configured and scan did not find a
+ * matching network block
+ */
+ int auto_interworking;
+
+ /**
+ * p2p_go_ht40 - Default mode for HT40 enable when operating as GO.
+ *
+ * This will take effect for p2p_group_add, p2p_connect, and p2p_invite.
+ * Note that regulatory constraints and driver capabilities are
+ * consulted anyway, so setting it to 1 can't do real harm.
+ * By default: 0 (disabled)
+ */
+ int p2p_go_ht40;
+
+ /**
+ * p2p_disabled - Whether P2P operations are disabled for this interface
+ */
+ int p2p_disabled;
+
+ /**
+ * p2p_no_group_iface - Whether group interfaces can be used
+ *
+ * By default, wpa_supplicant will create a separate interface for P2P
+ * group operations if the driver supports this. This functionality can
+ * be disabled by setting this parameter to 1. In that case, the same
+ * interface that was used for the P2P management operations is used
+ * also for the group operation.
+ */
+ int p2p_no_group_iface;
+
+ /**
+ * okc - Whether to enable opportunistic key caching by default
+ *
+ * By default, OKC is disabled unless enabled by the per-network
+ * proactive_key_caching=1 parameter. okc=1 can be used to change this
+ * default behavior.
+ */
+ int okc;
+
+ /**
+ * pmf - Whether to enable/require PMF by default
+ *
+ * By default, PMF is disabled unless enabled by the per-network
+ * ieee80211w=1 or ieee80211w=2 parameter. pmf=1/2 can be used to change
+ * this default behavior.
+ */
+ enum mfp_options pmf;
};
@@ -352,12 +804,17 @@ struct wpa_config {
void wpa_config_free(struct wpa_config *ssid);
void wpa_config_free_ssid(struct wpa_ssid *ssid);
+void wpa_config_foreach_network(struct wpa_config *config,
+ void (*func)(void *, struct wpa_ssid *),
+ void *arg);
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);
+int wpa_config_set_quoted(struct wpa_ssid *ssid, const char *var,
+ const char *value);
char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys);
char * wpa_config_get(struct wpa_ssid *ssid, const char *var);
char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var);
@@ -372,6 +829,13 @@ void wpa_config_set_blob(struct wpa_config *config,
void wpa_config_free_blob(struct wpa_config_blob *blob);
int wpa_config_remove_blob(struct wpa_config *config, const char *name);
+struct wpa_cred * wpa_config_get_cred(struct wpa_config *config, int id);
+struct wpa_cred * wpa_config_add_cred(struct wpa_config *config);
+int wpa_config_remove_cred(struct wpa_config *config, int id);
+void wpa_config_free_cred(struct wpa_cred *cred);
+int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
+ const char *value, int line);
+
struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
const char *driver_param);
#ifndef CONFIG_NO_STDOUT_DEBUG
@@ -381,6 +845,10 @@ void wpa_config_debug_dump_networks(struct wpa_config *config);
#endif /* CONFIG_NO_STDOUT_DEBUG */
+/* Prototypes for common functions from config.c */
+int wpa_config_process_global(struct wpa_config *config, char *pos, int line);
+
+
/* Prototypes for backend specific functions from the selected config_*.c */
/**
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 5f0704576a8e..8f32cc8d91e4 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -1,15 +1,9 @@
/*
* WPA Supplicant / Configuration backend: text file
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, 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 software may be distributed under the terms of the BSD license.
+ * See README 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
@@ -22,7 +16,32 @@
#include "config.h"
#include "base64.h"
#include "uuid.h"
+#include "p2p/p2p.h"
#include "eap_peer/eap_methods.h"
+#include "eap_peer/eap.h"
+
+
+static int newline_terminated(const char *buf, size_t buflen)
+{
+ size_t len = os_strlen(buf);
+ if (len == 0)
+ return 0;
+ if (len == buflen - 1 && buf[buflen - 1] != '\r' &&
+ buf[len - 1] != '\n')
+ return 0;
+ return 1;
+}
+
+
+static void skip_line_end(FILE *stream)
+{
+ char buf[100];
+ while (fgets(buf, sizeof(buf), stream)) {
+ buf[sizeof(buf) - 1] = '\0';
+ if (newline_terminated(buf, sizeof(buf)))
+ return;
+ }
+}
/**
@@ -47,6 +66,15 @@ static char * wpa_config_get_line(char *s, int size, FILE *stream, int *line,
while (fgets(s, size, stream)) {
(*line)++;
s[size - 1] = '\0';
+ if (!newline_terminated(s, size)) {
+ /*
+ * The line was truncated - skip rest of it to avoid
+ * confusing error messages.
+ */
+ wpa_printf(MSG_INFO, "Long line in configuration file "
+ "truncated");
+ skip_line_end(stream);
+ }
pos = s;
/* Skip white space from the beginning of line. */
@@ -105,14 +133,6 @@ static int wpa_config_validate_network(struct wpa_ssid *ssid, int line)
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)) {
@@ -131,7 +151,7 @@ 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;
+ char buf[2000], *pos, *pos2;
wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new network block",
*line);
@@ -187,6 +207,61 @@ static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id)
}
+static struct wpa_cred * wpa_config_read_cred(FILE *f, int *line, int id)
+{
+ struct wpa_cred *cred;
+ int errors = 0, end = 0;
+ char buf[256], *pos, *pos2;
+
+ wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new cred block", *line);
+ cred = os_zalloc(sizeof(*cred));
+ if (cred == NULL)
+ return NULL;
+ cred->id = id;
+
+ 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 cred 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_cred(cred, pos, pos2, *line) < 0)
+ errors++;
+ }
+
+ if (!end) {
+ wpa_printf(MSG_ERROR, "Line %d: cred block was not "
+ "terminated properly.", *line);
+ errors++;
+ }
+
+ if (errors) {
+ wpa_config_free_cred(cred);
+ cred = NULL;
+ }
+
+ return cred;
+}
+
+
#ifndef CONFIG_NO_CONFIG_BLOBS
static struct wpa_config_blob * wpa_config_read_blob(FILE *f, int *line,
const char *name)
@@ -270,253 +345,29 @@ static int wpa_config_process_blob(struct wpa_config *config, FILE *f,
#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) },
- { STR(opensc_engine_path) },
- { STR(pkcs11_engine_path) },
- { STR(pkcs11_module_path) },
- { 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) },
- { STR(config_methods) },
- { INT_RANGE(wps_cred_processing, 0, 2) },
-#endif /* CONFIG_WPS */
- { FUNC(country) },
- { INT(bss_max_count) },
- { INT_RANGE(filter_ssids, 0, 1) }
-};
-
-#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;
+ char buf[512], *pos;
int errors = 0, line = 0;
struct wpa_ssid *ssid, *tail = NULL, *head = NULL;
+ struct wpa_cred *cred, *cred_tail = NULL, *cred_head = NULL;
struct wpa_config *config;
int id = 0;
+ int cred_id = 0;
config = wpa_config_alloc_empty(NULL, NULL);
- if (config == NULL)
+ if (config == NULL) {
+ wpa_printf(MSG_ERROR, "Failed to allocate config file "
+ "structure");
return NULL;
+ }
+
wpa_printf(MSG_DEBUG, "Reading configuration file '%s'", name);
f = fopen(name, "r");
if (f == NULL) {
+ wpa_printf(MSG_ERROR, "Failed to open config file '%s', "
+ "error: %s", name, strerror(errno));
os_free(config);
return NULL;
}
@@ -543,10 +394,26 @@ struct wpa_config * wpa_config_read(const char *name)
errors++;
continue;
}
+ } else if (os_strcmp(pos, "cred={") == 0) {
+ cred = wpa_config_read_cred(f, &line, cred_id++);
+ if (cred == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: failed to "
+ "parse cred block.", line);
+ errors++;
+ continue;
+ }
+ if (cred_head == NULL) {
+ cred_head = cred_tail = cred;
+ } else {
+ cred_tail->next = cred;
+ cred_tail = cred;
+ }
#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) {
+ wpa_printf(MSG_ERROR, "Line %d: failed to "
+ "process blob.", line);
errors++;
continue;
}
@@ -563,12 +430,15 @@ struct wpa_config * wpa_config_read(const char *name)
config->ssid = head;
wpa_config_debug_dump_networks(config);
+ config->cred = cred_head;
+#ifndef WPA_IGNORE_CONFIG_ERRORS
if (errors) {
wpa_config_free(config);
config = NULL;
head = NULL;
}
+#endif /* WPA_IGNORE_CONFIG_ERRORS */
return config;
}
@@ -726,6 +596,18 @@ static void write_wep_key(FILE *f, int idx, struct wpa_ssid *ssid)
}
+#ifdef CONFIG_P2P
+static void write_p2p_client_list(FILE *f, struct wpa_ssid *ssid)
+{
+ char *value = wpa_config_get(ssid, "p2p_client_list");
+ if (value == NULL)
+ return;
+ fprintf(f, "\tp2p_client_list=%s\n", value);
+ os_free(value);
+}
+#endif /* CONFIG_P2P */
+
+
static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
{
int i;
@@ -742,9 +624,12 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
write_psk(f, ssid);
write_proto(f, ssid);
write_key_mgmt(f, ssid);
+ INT_DEF(bg_scan_period, DEFAULT_BG_SCAN_PERIOD);
write_pairwise(f, ssid);
write_group(f, ssid);
write_auth_alg(f, ssid);
+ STR(bgscan);
+ STR(autoscan);
#ifdef IEEE8021X_EAPOL
write_eap(f, ssid);
STR(identity);
@@ -793,13 +678,18 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE);
#endif /* IEEE8021X_EAPOL */
INT(mode);
- INT(proactive_key_caching);
+ INT(frequency);
+ write_int(f, "proactive_key_caching", ssid->proactive_key_caching, -1);
INT(disabled);
INT(peerkey);
#ifdef CONFIG_IEEE80211W
- INT(ieee80211w);
+ write_int(f, "ieee80211w", ssid->ieee80211w,
+ MGMT_FRAME_PROTECTION_DEFAULT);
#endif /* CONFIG_IEEE80211W */
STR(id_str);
+#ifdef CONFIG_P2P
+ write_p2p_client_list(f, ssid);
+#endif /* CONFIG_P2P */
#undef STR
#undef INT
@@ -807,6 +697,65 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
}
+static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred)
+{
+ if (cred->priority)
+ fprintf(f, "\tpriority=%d\n", cred->priority);
+ if (cred->pcsc)
+ fprintf(f, "\tpcsc=%d\n", cred->pcsc);
+ if (cred->realm)
+ fprintf(f, "\trealm=\"%s\"\n", cred->realm);
+ if (cred->username)
+ fprintf(f, "\tusername=\"%s\"\n", cred->username);
+ if (cred->password && cred->ext_password)
+ fprintf(f, "\tpassword=ext:%s\n", cred->password);
+ else if (cred->password)
+ fprintf(f, "\tpassword=\"%s\"\n", cred->password);
+ if (cred->ca_cert)
+ fprintf(f, "\tca_cert=\"%s\"\n", cred->ca_cert);
+ if (cred->client_cert)
+ fprintf(f, "\tclient_cert=\"%s\"\n", cred->client_cert);
+ if (cred->private_key)
+ fprintf(f, "\tprivate_key=\"%s\"\n", cred->private_key);
+ if (cred->private_key_passwd)
+ fprintf(f, "\tprivate_key_passwd=\"%s\"\n",
+ cred->private_key_passwd);
+ if (cred->imsi)
+ fprintf(f, "\timsi=\"%s\"\n", cred->imsi);
+ if (cred->milenage)
+ fprintf(f, "\tmilenage=\"%s\"\n", cred->milenage);
+ if (cred->domain)
+ fprintf(f, "\tdomain=\"%s\"\n", cred->domain);
+ if (cred->roaming_consortium_len) {
+ size_t i;
+ fprintf(f, "\troaming_consortium=");
+ for (i = 0; i < cred->roaming_consortium_len; i++)
+ fprintf(f, "%02x", cred->roaming_consortium[i]);
+ fprintf(f, "\n");
+ }
+ if (cred->eap_method) {
+ const char *name;
+ name = eap_get_name(cred->eap_method[0].vendor,
+ cred->eap_method[0].method);
+ fprintf(f, "\teap=%s\n", name);
+ }
+ if (cred->phase1)
+ fprintf(f, "\tphase1=\"%s\"\n", cred->phase1);
+ if (cred->phase2)
+ fprintf(f, "\tphase2=\"%s\"\n", cred->phase2);
+ if (cred->excluded_ssid) {
+ size_t i, j;
+ for (i = 0; i < cred->num_excluded_ssid; i++) {
+ struct excluded_ssid *e = &cred->excluded_ssid[i];
+ fprintf(f, "\texcluded_ssid=");
+ for (j = 0; j < e->ssid_len; j++)
+ fprintf(f, "%02x", e->ssid[j]);
+ fprintf(f, "\n");
+ }
+ }
+}
+
+
#ifndef CONFIG_NO_CONFIG_BLOBS
static int wpa_config_write_blob(FILE *f, struct wpa_config_blob *blob)
{
@@ -823,6 +772,23 @@ static int wpa_config_write_blob(FILE *f, struct wpa_config_blob *blob)
#endif /* CONFIG_NO_CONFIG_BLOBS */
+static void write_global_bin(FILE *f, const char *field,
+ const struct wpabuf *val)
+{
+ size_t i;
+ const u8 *pos;
+
+ if (val == NULL)
+ return;
+
+ fprintf(f, "%s=", field);
+ pos = wpabuf_head(val);
+ for (i = 0; i < wpabuf_len(val); i++)
+ fprintf(f, "%02X", *pos++);
+ fprintf(f, "\n");
+}
+
+
static void wpa_config_write_global(FILE *f, struct wpa_config *config)
{
#ifdef CONFIG_CTRL_IFACE
@@ -836,6 +802,9 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
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->disable_scan_offload)
+ fprintf(f, "disable_scan_offload=%d\n",
+ config->disable_scan_offload);
if (config->fast_reauth != DEFAULT_FAST_REAUTH)
fprintf(f, "fast_reauth=%d\n", config->fast_reauth);
if (config->opensc_engine_path)
@@ -847,6 +816,10 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
if (config->pkcs11_module_path)
fprintf(f, "pkcs11_module_path=%s\n",
config->pkcs11_module_path);
+ if (config->pcsc_reader)
+ fprintf(f, "pcsc_reader=%s\n", config->pcsc_reader);
+ if (config->pcsc_pin)
+ fprintf(f, "pcsc_pin=%s\n", config->pcsc_pin);
if (config->driver_param)
fprintf(f, "driver_param=%s\n", config->driver_param);
if (config->dot11RSNAConfigPMKLifetime)
@@ -876,8 +849,13 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
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);
+ {
+ char _buf[WPS_DEV_TYPE_BUFSIZE], *buf;
+ buf = wps_dev_type_bin2str(config->device_type,
+ _buf, sizeof(_buf));
+ if (os_strcmp(buf, "0-00000000-0") != 0)
+ fprintf(f, "device_type=%s\n", buf);
+ }
if (WPA_GET_BE32(config->os_version))
fprintf(f, "os_version=%08x\n",
WPA_GET_BE32(config->os_version));
@@ -886,15 +864,112 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
if (config->wps_cred_processing)
fprintf(f, "wps_cred_processing=%d\n",
config->wps_cred_processing);
+ if (config->wps_vendor_ext_m1) {
+ int i, len = wpabuf_len(config->wps_vendor_ext_m1);
+ const u8 *p = wpabuf_head_u8(config->wps_vendor_ext_m1);
+ if (len > 0) {
+ fprintf(f, "wps_vendor_ext_m1=");
+ for (i = 0; i < len; i++)
+ fprintf(f, "%02x", *p++);
+ fprintf(f, "\n");
+ }
+ }
#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+ if (config->p2p_listen_reg_class)
+ fprintf(f, "p2p_listen_reg_class=%u\n",
+ config->p2p_listen_reg_class);
+ if (config->p2p_listen_channel)
+ fprintf(f, "p2p_listen_channel=%u\n",
+ config->p2p_listen_channel);
+ if (config->p2p_oper_reg_class)
+ fprintf(f, "p2p_oper_reg_class=%u\n",
+ config->p2p_oper_reg_class);
+ if (config->p2p_oper_channel)
+ fprintf(f, "p2p_oper_channel=%u\n", config->p2p_oper_channel);
+ if (config->p2p_go_intent != DEFAULT_P2P_GO_INTENT)
+ fprintf(f, "p2p_go_intent=%u\n", config->p2p_go_intent);
+ if (config->p2p_ssid_postfix)
+ fprintf(f, "p2p_ssid_postfix=%s\n", config->p2p_ssid_postfix);
+ if (config->persistent_reconnect)
+ fprintf(f, "persistent_reconnect=%u\n",
+ config->persistent_reconnect);
+ if (config->p2p_intra_bss != DEFAULT_P2P_INTRA_BSS)
+ fprintf(f, "p2p_intra_bss=%u\n", config->p2p_intra_bss);
+ if (config->p2p_group_idle)
+ fprintf(f, "p2p_group_idle=%u\n", config->p2p_group_idle);
+ if (config->p2p_pref_chan) {
+ unsigned int i;
+ fprintf(f, "p2p_pref_chan=");
+ for (i = 0; i < config->num_p2p_pref_chan; i++) {
+ fprintf(f, "%s%u:%u", i > 0 ? "," : "",
+ config->p2p_pref_chan[i].op_class,
+ config->p2p_pref_chan[i].chan);
+ }
+ fprintf(f, "\n");
+ }
+ if (config->p2p_go_ht40)
+ fprintf(f, "p2p_go_ht40=%u\n", config->p2p_go_ht40);
+ if (config->p2p_disabled)
+ fprintf(f, "p2p_disabled=%u\n", config->p2p_disabled);
+ if (config->p2p_no_group_iface)
+ fprintf(f, "p2p_no_group_iface=%u\n",
+ config->p2p_no_group_iface);
+#endif /* CONFIG_P2P */
if (config->country[0] && config->country[1]) {
fprintf(f, "country=%c%c\n",
config->country[0], config->country[1]);
}
if (config->bss_max_count != DEFAULT_BSS_MAX_COUNT)
fprintf(f, "bss_max_count=%u\n", config->bss_max_count);
+ if (config->bss_expiration_age != DEFAULT_BSS_EXPIRATION_AGE)
+ fprintf(f, "bss_expiration_age=%u\n",
+ config->bss_expiration_age);
+ if (config->bss_expiration_scan_count !=
+ DEFAULT_BSS_EXPIRATION_SCAN_COUNT)
+ fprintf(f, "bss_expiration_scan_count=%u\n",
+ config->bss_expiration_scan_count);
if (config->filter_ssids)
fprintf(f, "filter_ssids=%d\n", config->filter_ssids);
+ if (config->max_num_sta != DEFAULT_MAX_NUM_STA)
+ fprintf(f, "max_num_sta=%u\n", config->max_num_sta);
+ if (config->disassoc_low_ack)
+ fprintf(f, "disassoc_low_ack=%u\n", config->disassoc_low_ack);
+#ifdef CONFIG_HS20
+ if (config->hs20)
+ fprintf(f, "hs20=1\n");
+#endif /* CONFIG_HS20 */
+#ifdef CONFIG_INTERWORKING
+ if (config->interworking)
+ fprintf(f, "interworking=%u\n", config->interworking);
+ if (!is_zero_ether_addr(config->hessid))
+ fprintf(f, "hessid=" MACSTR "\n", MAC2STR(config->hessid));
+ if (config->access_network_type != DEFAULT_ACCESS_NETWORK_TYPE)
+ fprintf(f, "access_network_type=%d\n",
+ config->access_network_type);
+#endif /* CONFIG_INTERWORKING */
+ if (config->pbc_in_m1)
+ fprintf(f, "pbc_in_m1=%u\n", config->pbc_in_m1);
+ if (config->wps_nfc_dev_pw_id)
+ fprintf(f, "wps_nfc_dev_pw_id=%d\n",
+ config->wps_nfc_dev_pw_id);
+ write_global_bin(f, "wps_nfc_dh_pubkey", config->wps_nfc_dh_pubkey);
+ write_global_bin(f, "wps_nfc_dh_privkey", config->wps_nfc_dh_privkey);
+ write_global_bin(f, "wps_nfc_dev_pw", config->wps_nfc_dev_pw);
+
+ if (config->ext_password_backend)
+ fprintf(f, "ext_password_backend=%s\n",
+ config->ext_password_backend);
+ if (config->p2p_go_max_inactivity != DEFAULT_P2P_GO_MAX_INACTIVITY)
+ fprintf(f, "p2p_go_max_inactivity=%d\n",
+ config->p2p_go_max_inactivity);
+ if (config->auto_interworking)
+ fprintf(f, "auto_interworking=%d\n",
+ config->auto_interworking);
+ if (config->okc)
+ fprintf(f, "okc=%d\n", config->okc);
+ if (config->pmf)
+ fprintf(f, "pmf=%d\n", config->pmf);
}
#endif /* CONFIG_NO_CONFIG_WRITE */
@@ -905,6 +980,7 @@ int wpa_config_write(const char *name, struct wpa_config *config)
#ifndef CONFIG_NO_CONFIG_WRITE
FILE *f;
struct wpa_ssid *ssid;
+ struct wpa_cred *cred;
#ifndef CONFIG_NO_CONFIG_BLOBS
struct wpa_config_blob *blob;
#endif /* CONFIG_NO_CONFIG_BLOBS */
@@ -920,9 +996,18 @@ int wpa_config_write(const char *name, struct wpa_config *config)
wpa_config_write_global(f, config);
+ for (cred = config->cred; cred; cred = cred->next) {
+ fprintf(f, "\ncred={\n");
+ wpa_config_write_cred(f, cred);
+ fprintf(f, "}\n");
+ }
+
for (ssid = config->ssid; ssid; ssid = ssid->next) {
- if (ssid->key_mgmt == WPA_KEY_MGMT_WPS)
- continue; /* do not save temporary WPS networks */
+ if (ssid->key_mgmt == WPA_KEY_MGMT_WPS || ssid->temporary)
+ continue; /* do not save temporary networks */
+ if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
+ !ssid->passphrase)
+ continue; /* do not save invalid network */
fprintf(f, "\nnetwork={\n");
wpa_config_write_network(f, ssid);
fprintf(f, "}\n");
diff --git a/wpa_supplicant/config_none.c b/wpa_supplicant/config_none.c
index 2e9ccc0a2835..589ea3620d15 100644
--- a/wpa_supplicant/config_none.c
+++ b/wpa_supplicant/config_none.c
@@ -2,14 +2,8 @@
* 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 software may be distributed under the terms of the BSD license.
+ * See README 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
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 25e87aad350e..9ac67c739eee 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -2,14 +2,8 @@
* 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef CONFIG_SSID_H
@@ -31,6 +25,14 @@
WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)
#define DEFAULT_FRAGMENT_SIZE 1398
+#define DEFAULT_BG_SCAN_PERIOD -1
+#define DEFAULT_DISABLE_HT 0
+#define DEFAULT_DISABLE_HT40 0
+#define DEFAULT_DISABLE_SGI 0
+#define DEFAULT_DISABLE_MAX_AMSDU -1 /* no change */
+#define DEFAULT_AMPDU_FACTOR -1 /* no change */
+#define DEFAULT_AMPDU_DENSITY -1 /* no change */
+
/**
* struct wpa_ssid - Network configuration data
*
@@ -109,6 +111,9 @@ struct wpa_ssid {
*
* If set, this network block is used only when associating with the AP
* using the configured BSSID
+ *
+ * If this is a persistent P2P group (disabled == 2), this is the GO
+ * Device Address.
*/
u8 bssid[ETH_ALEN];
@@ -137,6 +142,14 @@ struct wpa_ssid {
char *passphrase;
/**
+ * ext_psk - PSK/passphrase name in external storage
+ *
+ * If this is set, PSK/passphrase will be fetched from external storage
+ * when requesting association with the network.
+ */
+ char *ext_psk;
+
+ /**
* pairwise_cipher - Bitfield of allowed pairwise ciphers, WPA_CIPHER_*
*/
int pairwise_cipher;
@@ -154,6 +167,12 @@ struct wpa_ssid {
int key_mgmt;
/**
+ * bg_scan_period - Background scan period in seconds, 0 to disable, or
+ * -1 to indicate no change to default driver configuration
+ */
+ int bg_scan_period;
+
+ /**
* proto - Bitfield of allowed protocols, WPA_PROTO_*
*/
int proto;
@@ -210,13 +229,18 @@ struct wpa_ssid {
*
* 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.
+ * by default unless default value is changed with the global okc=1
+ * parameter. 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.
+ *
+ * Internally, special value -1 is used to indicate that the parameter
+ * was not specified in the configuration (i.e., default behavior is
+ * followed).
*/
int proactive_key_caching;
@@ -273,6 +297,11 @@ struct wpa_ssid {
*
* 2 = AP (access point)
*
+ * 3 = P2P Group Owner (can be set in the configuration file)
+ *
+ * 4 = P2P Group Formation (used internally; not in configuration
+ * files)
+ *
* 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
@@ -284,6 +313,8 @@ struct wpa_ssid {
WPAS_MODE_INFRA = 0,
WPAS_MODE_IBSS = 1,
WPAS_MODE_AP = 2,
+ WPAS_MODE_P2P_GO = 3,
+ WPAS_MODE_P2P_GROUP_FORMATION = 4,
} mode;
/**
@@ -292,10 +323,20 @@ struct wpa_ssid {
* 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).
+ * 2 = this network block includes parameters for a persistent P2P
+ * group (can be used with P2P ctrl_iface commands)
*/
int disabled;
/**
+ * disabled_for_connect - Whether this network was temporarily disabled
+ *
+ * This flag is used to reenable all the temporarily disabled networks
+ * after either the success or failure of a WPS connection.
+ */
+ int disabled_for_connect;
+
+ /**
* peerkey - Whether PeerKey handshake for direct links is allowed
*
* This is only used when both RSN/WPA2 and IEEE 802.11e (QoS) are
@@ -321,6 +362,12 @@ struct wpa_ssid {
*
* This value is used to configure policy for management frame
* protection (IEEE 802.11w). 0 = disabled, 1 = optional, 2 = required.
+ * This is disabled by default unless the default value has been changed
+ * with the global pmf=1/2 parameter.
+ *
+ * Internally, special value 3 is used to indicate that the parameter
+ * was not specified in the configuration (i.e., default behavior is
+ * followed).
*/
enum mfp_options ieee80211w;
#endif /* CONFIG_IEEE80211W */
@@ -337,6 +384,8 @@ struct wpa_ssid {
*/
int frequency;
+ int ht40;
+
/**
* wpa_ptk_rekey - Maximum lifetime for PTK in seconds
*
@@ -365,6 +414,20 @@ struct wpa_ssid {
char *bgscan;
/**
+ * ignore_broadcast_ssid - Hide SSID in AP mode
+ *
+ * Send empty SSID in beacons and ignore probe request frames that do
+ * not specify full SSID, i.e., require stations to know SSID.
+ * default: disabled (0)
+ * 1 = send empty (length=0) SSID in beacon and ignore probe request
+ * for broadcast SSID
+ * 2 = clear SSID (ASCII 0), but keep the original length (this may be
+ * required with some clients that do not support empty SSID) and
+ * ignore probe requests for broadcast SSID
+ */
+ int ignore_broadcast_ssid;
+
+ /**
* freq_list - Array of allowed frequencies or %NULL for all
*
* This is an optional zero-terminated array of frequencies in
@@ -373,6 +436,136 @@ struct wpa_ssid {
* considered when selecting a BSS.
*/
int *freq_list;
+
+ /**
+ * p2p_client_list - List of P2P Clients in a persistent group (GO)
+ *
+ * This is a list of P2P Clients (P2P Device Address) that have joined
+ * the persistent group. This is maintained on the GO for persistent
+ * group entries (disabled == 2).
+ */
+ u8 *p2p_client_list;
+
+ /**
+ * num_p2p_clients - Number of entries in p2p_client_list
+ */
+ size_t num_p2p_clients;
+
+#ifndef P2P_MAX_STORED_CLIENTS
+#define P2P_MAX_STORED_CLIENTS 100
+#endif /* P2P_MAX_STORED_CLIENTS */
+
+ /**
+ * p2p_group - Network generated as a P2P group (used internally)
+ */
+ int p2p_group;
+
+ /**
+ * p2p_persistent_group - Whether this is a persistent group
+ */
+ int p2p_persistent_group;
+
+ /**
+ * temporary - Whether this network is temporary and not to be saved
+ */
+ int temporary;
+
+ /**
+ * export_keys - Whether keys may be exported
+ *
+ * This attribute will be set when keys are determined through
+ * WPS or similar so that they may be exported.
+ */
+ int export_keys;
+
+#ifdef CONFIG_HT_OVERRIDES
+ /**
+ * disable_ht - Disable HT (IEEE 802.11n) for this network
+ *
+ * By default, use it if it is available, but this can be configured
+ * to 1 to have it disabled.
+ */
+ int disable_ht;
+
+ /**
+ * disable_ht40 - Disable HT40 for this network
+ *
+ * By default, use it if it is available, but this can be configured
+ * to 1 to have it disabled.
+ */
+ int disable_ht40;
+
+ /**
+ * disable_sgi - Disable SGI (Short Guard Interval) for this network
+ *
+ * By default, use it if it is available, but this can be configured
+ * to 1 to have it disabled.
+ */
+ int disable_sgi;
+
+ /**
+ * disable_max_amsdu - Disable MAX A-MSDU
+ *
+ * A-MDSU will be 3839 bytes when disabled, or 7935
+ * when enabled (assuming it is otherwise supported)
+ * -1 (default) means do not apply any settings to the kernel.
+ */
+ int disable_max_amsdu;
+
+ /**
+ * ampdu_factor - Maximum A-MPDU Length Exponent
+ *
+ * Value: 0-3, see 7.3.2.56.3 in IEEE Std 802.11n-2009.
+ */
+ int ampdu_factor;
+
+ /**
+ * ampdu_density - Minimum A-MPDU Start Spacing
+ *
+ * Value: 0-7, see 7.3.2.56.3 in IEEE Std 802.11n-2009.
+ */
+ int ampdu_density;
+
+ /**
+ * ht_mcs - Allowed HT-MCS rates, in ASCII hex: ffff0000...
+ *
+ * By default (empty string): Use whatever the OS has configured.
+ */
+ char *ht_mcs;
+#endif /* CONFIG_HT_OVERRIDES */
+
+ /**
+ * ap_max_inactivity - Timeout in seconds to detect STA's inactivity
+ *
+ * This timeout value is used in AP mode to clean up inactive stations.
+ * By default: 300 seconds.
+ */
+ int ap_max_inactivity;
+
+ /**
+ * dtim_period - DTIM period in Beacon intervals
+ * By default: 2
+ */
+ int dtim_period;
+
+ /**
+ * auth_failures - Number of consecutive authentication failures
+ */
+ unsigned int auth_failures;
+
+ /**
+ * disabled_until - Network block disabled until this time if non-zero
+ */
+ struct os_time disabled_until;
+
+ /**
+ * parent_cred - Pointer to parent wpa_cred entry
+ *
+ * This pointer can be used to delete temporary networks when a wpa_cred
+ * that was used to create them is removed. This pointer should not be
+ * dereferences since it may not be updated in all cases.
+ */
+ void *parent_cred;
};
#endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
index 9a7825a00153..2750b63734ae 100644
--- a/wpa_supplicant/config_winreg.c
+++ b/wpa_supplicant/config_winreg.c
@@ -2,14 +2,8 @@
* 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 software may be distributed under the terms of the BSD license.
+ * See README 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
@@ -208,6 +202,7 @@ static int wpa_config_read_global_os_version(struct wpa_config *config,
static int wpa_config_read_global(struct wpa_config *config, HKEY hk)
{
int errors = 0;
+ int val;
wpa_config_read_reg_dword(hk, TEXT("ap_scan"), &config->ap_scan);
wpa_config_read_reg_dword(hk, TEXT("fast_reauth"),
@@ -247,8 +242,13 @@ static int wpa_config_read_global(struct wpa_config *config, HKEY hk)
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"));
+ {
+ char *t = wpa_config_read_reg_string(
+ hk, TEXT("device_type"));
+ if (t && wps_dev_type_str2bin(t, config->device_type))
+ errors++;
+ os_free(t);
+ }
config->config_methods = wpa_config_read_reg_string(
hk, TEXT("config_methods"));
if (wpa_config_read_global_os_version(config, hk))
@@ -256,11 +256,25 @@ static int wpa_config_read_global(struct wpa_config *config, HKEY hk)
wpa_config_read_reg_dword(hk, TEXT("wps_cred_processing"),
&config->wps_cred_processing);
#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+ config->p2p_ssid_postfix = wpa_config_read_reg_string(
+ hk, TEXT("p2p_ssid_postfix"));
+ wpa_config_read_reg_dword(hk, TEXT("p2p_group_idle"),
+ (int *) &config->p2p_group_idle);
+#endif /* CONFIG_P2P */
wpa_config_read_reg_dword(hk, TEXT("bss_max_count"),
(int *) &config->bss_max_count);
wpa_config_read_reg_dword(hk, TEXT("filter_ssids"),
&config->filter_ssids);
+ wpa_config_read_reg_dword(hk, TEXT("max_num_sta"),
+ (int *) &config->max_num_sta);
+ wpa_config_read_reg_dword(hk, TEXT("disassoc_low_ack"),
+ (int *) &config->disassoc_low_ack);
+
+ wpa_config_read_reg_dword(hk, TEXT("okc"), &config->okc);
+ wpa_config_read_reg_dword(hk, TEXT("pmf"), &val);
+ config->pmf = val;
return errors ? -1 : 0;
}
@@ -335,15 +349,6 @@ static struct wpa_ssid * wpa_config_read_network(HKEY hk, const TCHAR *netw,
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)) {
@@ -575,7 +580,12 @@ static int wpa_config_write_global(struct wpa_config *config, HKEY hk)
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);
+ {
+ char _buf[WPS_DEV_TYPE_BUFSIZE], *buf;
+ buf = wps_dev_type_bin2str(config->device_type,
+ _buf, sizeof(_buf));
+ wpa_config_write_reg_string(hk, "device_type", buf);
+ }
wpa_config_write_reg_string(hk, "config_methods",
config->config_methods);
if (WPA_GET_BE32(config->os_version)) {
@@ -587,12 +597,25 @@ static int wpa_config_write_global(struct wpa_config *config, HKEY hk)
wpa_config_write_reg_dword(hk, TEXT("wps_cred_processing"),
config->wps_cred_processing, 0);
#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+ wpa_config_write_reg_string(hk, "p2p_ssid_postfix",
+ config->p2p_ssid_postfix);
+ wpa_config_write_reg_dword(hk, TEXT("p2p_group_idle"),
+ config->p2p_group_idle, 0);
+#endif /* CONFIG_P2P */
wpa_config_write_reg_dword(hk, TEXT("bss_max_count"),
config->bss_max_count,
DEFAULT_BSS_MAX_COUNT);
wpa_config_write_reg_dword(hk, TEXT("filter_ssids"),
config->filter_ssids, 0);
+ wpa_config_write_reg_dword(hk, TEXT("max_num_sta"),
+ config->max_num_sta, DEFAULT_MAX_NUM_STA);
+ wpa_config_write_reg_dword(hk, TEXT("disassoc_low_ack"),
+ config->disassoc_low_ack, 0);
+
+ wpa_config_write_reg_dword(hk, TEXT("okc"), config->okc, 0);
+ wpa_config_write_reg_dword(hk, TEXT("pmf"), config->pmf, 0);
return 0;
}
@@ -889,11 +912,13 @@ static int wpa_config_write_network(HKEY hk, struct wpa_ssid *ssid, int id)
INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE);
#endif /* IEEE8021X_EAPOL */
INT(mode);
- INT(proactive_key_caching);
+ write_int(netw, "proactive_key_caching", ssid->proactive_key_caching,
+ -1);
INT(disabled);
INT(peerkey);
#ifdef CONFIG_IEEE80211W
- INT(ieee80211w);
+ write_int(netw, "ieee80211w", ssid->ieee80211w,
+ MGMT_FRAME_PROTECTION_DEFAULT);
#endif /* CONFIG_IEEE80211W */
STR(id_str);
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 19fea29fdbd3..864dd7d6d76a 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -1,22 +1,18 @@
/*
* WPA Supplicant / Control interface (shared code for all backends)
- * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "utils/eloop.h"
+#include "common/version.h"
#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
#include "eap_peer/eap.h"
#include "eapol_supp/eapol_supp_sm.h"
@@ -31,10 +27,18 @@
#include "wps_supplicant.h"
#include "ibss_rsn.h"
#include "ap.h"
+#include "p2p_supplicant.h"
+#include "p2p/p2p.h"
+#include "hs20_supplicant.h"
+#include "wifi_display.h"
#include "notify.h"
#include "bss.h"
#include "scan.h"
#include "ctrl_iface.h"
+#include "interworking.h"
+#include "blacklist.h"
+#include "autoscan.h"
+#include "wnm_sta.h"
extern struct wpa_driver_ops *wpa_drivers[];
@@ -44,6 +48,249 @@ static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
char *buf, int len);
+static int pno_start(struct wpa_supplicant *wpa_s)
+{
+ int ret;
+ size_t i, num_ssid;
+ struct wpa_ssid *ssid;
+ struct wpa_driver_scan_params params;
+
+ if (wpa_s->pno)
+ return 0;
+
+ if (wpa_s->wpa_state == WPA_SCANNING) {
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_supplicant_cancel_scan(wpa_s);
+ }
+
+ os_memset(&params, 0, sizeof(params));
+
+ num_ssid = 0;
+ ssid = wpa_s->conf->ssid;
+ while (ssid) {
+ if (!wpas_network_disabled(wpa_s, ssid))
+ num_ssid++;
+ ssid = ssid->next;
+ }
+ if (num_ssid > WPAS_MAX_SCAN_SSIDS) {
+ wpa_printf(MSG_DEBUG, "PNO: Use only the first %u SSIDs from "
+ "%u", WPAS_MAX_SCAN_SSIDS, (unsigned int) num_ssid);
+ num_ssid = WPAS_MAX_SCAN_SSIDS;
+ }
+
+ if (num_ssid == 0) {
+ wpa_printf(MSG_DEBUG, "PNO: No configured SSIDs");
+ return -1;
+ }
+
+ params.filter_ssids = os_malloc(sizeof(struct wpa_driver_scan_filter) *
+ num_ssid);
+ if (params.filter_ssids == NULL)
+ return -1;
+ i = 0;
+ ssid = wpa_s->conf->ssid;
+ while (ssid) {
+ if (!wpas_network_disabled(wpa_s, ssid)) {
+ params.ssids[i].ssid = ssid->ssid;
+ params.ssids[i].ssid_len = ssid->ssid_len;
+ params.num_ssids++;
+ os_memcpy(params.filter_ssids[i].ssid, ssid->ssid,
+ ssid->ssid_len);
+ params.filter_ssids[i].ssid_len = ssid->ssid_len;
+ params.num_filter_ssids++;
+ i++;
+ if (i == num_ssid)
+ break;
+ }
+ ssid = ssid->next;
+ }
+
+ if (wpa_s->conf->filter_rssi)
+ params.filter_rssi = wpa_s->conf->filter_rssi;
+
+ ret = wpa_drv_sched_scan(wpa_s, &params, 10 * 1000);
+ os_free(params.filter_ssids);
+ if (ret == 0)
+ wpa_s->pno = 1;
+ return ret;
+}
+
+
+static int pno_stop(struct wpa_supplicant *wpa_s)
+{
+ int ret = 0;
+
+ if (wpa_s->pno) {
+ wpa_s->pno = 0;
+ ret = wpa_drv_stop_sched_scan(wpa_s);
+ }
+
+ if (wpa_s->wpa_state == WPA_SCANNING)
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+ return ret;
+}
+
+
+static int set_bssid_filter(struct wpa_supplicant *wpa_s, char *val)
+{
+ char *pos;
+ u8 addr[ETH_ALEN], *filter = NULL, *n;
+ size_t count = 0;
+
+ pos = val;
+ while (pos) {
+ if (*pos == '\0')
+ break;
+ if (hwaddr_aton(pos, addr)) {
+ os_free(filter);
+ return -1;
+ }
+ n = os_realloc_array(filter, count + 1, ETH_ALEN);
+ if (n == NULL) {
+ os_free(filter);
+ return -1;
+ }
+ filter = n;
+ os_memcpy(filter + count * ETH_ALEN, addr, ETH_ALEN);
+ count++;
+
+ pos = os_strchr(pos, ' ');
+ if (pos)
+ pos++;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "bssid_filter", filter, count * ETH_ALEN);
+ os_free(wpa_s->bssid_filter);
+ wpa_s->bssid_filter = filter;
+ wpa_s->bssid_filter_count = count;
+
+ return 0;
+}
+
+
+static int set_disallow_aps(struct wpa_supplicant *wpa_s, char *val)
+{
+ char *pos;
+ u8 addr[ETH_ALEN], *bssid = NULL, *n;
+ struct wpa_ssid_value *ssid = NULL, *ns;
+ size_t count = 0, ssid_count = 0;
+ struct wpa_ssid *c;
+
+ /*
+ * disallow_list ::= <ssid_spec> | <bssid_spec> | <disallow_list> | “”
+ * SSID_SPEC ::= ssid <SSID_HEX>
+ * BSSID_SPEC ::= bssid <BSSID_HEX>
+ */
+
+ pos = val;
+ while (pos) {
+ if (*pos == '\0')
+ break;
+ if (os_strncmp(pos, "bssid ", 6) == 0) {
+ int res;
+ pos += 6;
+ res = hwaddr_aton2(pos, addr);
+ if (res < 0) {
+ os_free(ssid);
+ os_free(bssid);
+ wpa_printf(MSG_DEBUG, "Invalid disallow_aps "
+ "BSSID value '%s'", pos);
+ return -1;
+ }
+ pos += res;
+ n = os_realloc_array(bssid, count + 1, ETH_ALEN);
+ if (n == NULL) {
+ os_free(ssid);
+ os_free(bssid);
+ return -1;
+ }
+ bssid = n;
+ os_memcpy(bssid + count * ETH_ALEN, addr, ETH_ALEN);
+ count++;
+ } else if (os_strncmp(pos, "ssid ", 5) == 0) {
+ char *end;
+ pos += 5;
+
+ end = pos;
+ while (*end) {
+ if (*end == '\0' || *end == ' ')
+ break;
+ end++;
+ }
+
+ ns = os_realloc_array(ssid, ssid_count + 1,
+ sizeof(struct wpa_ssid_value));
+ if (ns == NULL) {
+ os_free(ssid);
+ os_free(bssid);
+ return -1;
+ }
+ ssid = ns;
+
+ if ((end - pos) & 0x01 || end - pos > 2 * 32 ||
+ hexstr2bin(pos, ssid[ssid_count].ssid,
+ (end - pos) / 2) < 0) {
+ os_free(ssid);
+ os_free(bssid);
+ wpa_printf(MSG_DEBUG, "Invalid disallow_aps "
+ "SSID value '%s'", pos);
+ return -1;
+ }
+ ssid[ssid_count].ssid_len = (end - pos) / 2;
+ wpa_hexdump_ascii(MSG_DEBUG, "disallow_aps SSID",
+ ssid[ssid_count].ssid,
+ ssid[ssid_count].ssid_len);
+ ssid_count++;
+ pos = end;
+ } else {
+ wpa_printf(MSG_DEBUG, "Unexpected disallow_aps value "
+ "'%s'", pos);
+ os_free(ssid);
+ os_free(bssid);
+ return -1;
+ }
+
+ pos = os_strchr(pos, ' ');
+ if (pos)
+ pos++;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "disallow_aps_bssid", bssid, count * ETH_ALEN);
+ os_free(wpa_s->disallow_aps_bssid);
+ wpa_s->disallow_aps_bssid = bssid;
+ wpa_s->disallow_aps_bssid_count = count;
+
+ wpa_printf(MSG_DEBUG, "disallow_aps_ssid_count %d", (int) ssid_count);
+ os_free(wpa_s->disallow_aps_ssid);
+ wpa_s->disallow_aps_ssid = ssid;
+ wpa_s->disallow_aps_ssid_count = ssid_count;
+
+ if (!wpa_s->current_ssid || wpa_s->wpa_state < WPA_AUTHENTICATING)
+ return 0;
+
+ c = wpa_s->current_ssid;
+ if (c->mode != WPAS_MODE_INFRA && c->mode != WPAS_MODE_IBSS)
+ return 0;
+
+ if (!disallowed_bssid(wpa_s, wpa_s->bssid) &&
+ !disallowed_ssid(wpa_s, c->ssid, c->ssid_len))
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "Disconnect and try to find another network "
+ "because current AP was marked disallowed");
+
+#ifdef CONFIG_SME
+ wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+ wpa_s->reassociate = 1;
+ wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+ return 0;
+}
+
+
static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
char *cmd)
{
@@ -80,13 +327,148 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
} 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;
+ } else if (os_strcasecmp(cmd, "wps_fragment_size") == 0) {
+ wpa_s->wps_fragment_size = atoi(value);
+#ifdef CONFIG_WPS_TESTING
+ } else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
+ long int val;
+ val = strtol(value, NULL, 0);
+ if (val < 0 || val > 0xff) {
+ ret = -1;
+ wpa_printf(MSG_DEBUG, "WPS: Invalid "
+ "wps_version_number %ld", val);
+ } else {
+ wps_version_number = val;
+ wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
+ "version %u.%u",
+ (wps_version_number & 0xf0) >> 4,
+ wps_version_number & 0x0f);
+ }
+ } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
+ wps_testing_dummy_cred = atoi(value);
+ wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
+ wps_testing_dummy_cred);
+#endif /* CONFIG_WPS_TESTING */
+ } else if (os_strcasecmp(cmd, "ampdu") == 0) {
+ if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0)
+ ret = -1;
+#ifdef CONFIG_TDLS_TESTING
+ } else if (os_strcasecmp(cmd, "tdls_testing") == 0) {
+ extern unsigned int tdls_testing;
+ tdls_testing = strtol(value, NULL, 0);
+ wpa_printf(MSG_DEBUG, "TDLS: tdls_testing=0x%x", tdls_testing);
+#endif /* CONFIG_TDLS_TESTING */
+#ifdef CONFIG_TDLS
+ } else if (os_strcasecmp(cmd, "tdls_disabled") == 0) {
+ int disabled = atoi(value);
+ wpa_printf(MSG_DEBUG, "TDLS: tdls_disabled=%d", disabled);
+ if (disabled) {
+ if (wpa_drv_tdls_oper(wpa_s, TDLS_DISABLE, NULL) < 0)
+ ret = -1;
+ } else if (wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL) < 0)
+ ret = -1;
+ wpa_tdls_enable(wpa_s->wpa, !disabled);
+#endif /* CONFIG_TDLS */
+ } else if (os_strcasecmp(cmd, "pno") == 0) {
+ if (atoi(value))
+ ret = pno_start(wpa_s);
+ else
+ ret = pno_stop(wpa_s);
+ } else if (os_strcasecmp(cmd, "radio_disabled") == 0) {
+ int disabled = atoi(value);
+ if (wpa_drv_radio_disable(wpa_s, disabled) < 0)
+ ret = -1;
+ else if (disabled)
+ wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
+ } else if (os_strcasecmp(cmd, "uapsd") == 0) {
+ if (os_strcmp(value, "disable") == 0)
+ wpa_s->set_sta_uapsd = 0;
+ else {
+ int be, bk, vi, vo;
+ char *pos;
+ /* format: BE,BK,VI,VO;max SP Length */
+ be = atoi(value);
+ pos = os_strchr(value, ',');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ bk = atoi(pos);
+ pos = os_strchr(pos, ',');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ vi = atoi(pos);
+ pos = os_strchr(pos, ',');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ vo = atoi(pos);
+ /* ignore max SP Length for now */
+
+ wpa_s->set_sta_uapsd = 1;
+ wpa_s->sta_uapsd = 0;
+ if (be)
+ wpa_s->sta_uapsd |= BIT(0);
+ if (bk)
+ wpa_s->sta_uapsd |= BIT(1);
+ if (vi)
+ wpa_s->sta_uapsd |= BIT(2);
+ if (vo)
+ wpa_s->sta_uapsd |= BIT(3);
+ }
+ } else if (os_strcasecmp(cmd, "ps") == 0) {
+ ret = wpa_drv_set_p2p_powersave(wpa_s, atoi(value), -1, -1);
+#ifdef CONFIG_WIFI_DISPLAY
+ } else if (os_strcasecmp(cmd, "wifi_display") == 0) {
+ wifi_display_enable(wpa_s->global, !!atoi(value));
+#endif /* CONFIG_WIFI_DISPLAY */
+ } else if (os_strcasecmp(cmd, "bssid_filter") == 0) {
+ ret = set_bssid_filter(wpa_s, value);
+ } else if (os_strcasecmp(cmd, "disallow_aps") == 0) {
+ ret = set_disallow_aps(wpa_s, value);
+ } else if (os_strcasecmp(cmd, "no_keep_alive") == 0) {
+ wpa_s->no_keep_alive = !!atoi(value);
+ } else {
+ value[-1] = '=';
+ ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
+ if (ret == 0)
+ wpa_supplicant_update_config(wpa_s);
+ }
return ret;
}
+static int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s,
+ char *cmd, char *buf, size_t buflen)
+{
+ int res = -1;
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
+
+ if (os_strcmp(cmd, "version") == 0) {
+ res = os_snprintf(buf, buflen, "%s", VERSION_STR);
+ } else if (os_strcasecmp(cmd, "country") == 0) {
+ if (wpa_s->conf->country[0] && wpa_s->conf->country[1])
+ res = os_snprintf(buf, buflen, "%c%c",
+ wpa_s->conf->country[0],
+ wpa_s->conf->country[1]);
+#ifdef CONFIG_WIFI_DISPLAY
+ } else if (os_strcasecmp(cmd, "wifi_display") == 0) {
+ res = os_snprintf(buf, buflen, "%d",
+ wpa_s->global->wifi_display);
+ if (res < 0 || (unsigned int) res >= buflen)
+ return -1;
+ return res;
+#endif /* CONFIG_WIFI_DISPLAY */
+ }
+
+ if (res < 0 || (unsigned int) res >= buflen)
+ return -1;
+ return res;
+}
+
+
#ifdef IEEE8021X_EAPOL
static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
char *addr)
@@ -131,6 +513,80 @@ static int wpa_supplicant_ctrl_iface_stkstart(
#endif /* CONFIG_PEERKEY */
+#ifdef CONFIG_TDLS
+
+static int wpa_supplicant_ctrl_iface_tdls_discover(
+ struct wpa_supplicant *wpa_s, char *addr)
+{
+ u8 peer[ETH_ALEN];
+ int ret;
+
+ if (hwaddr_aton(addr, peer)) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER: invalid "
+ "address '%s'", addr);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER " MACSTR,
+ MAC2STR(peer));
+
+ if (wpa_tdls_is_external_setup(wpa_s->wpa))
+ ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
+ else
+ ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
+
+ return ret;
+}
+
+
+static int wpa_supplicant_ctrl_iface_tdls_setup(
+ struct wpa_supplicant *wpa_s, char *addr)
+{
+ u8 peer[ETH_ALEN];
+ int ret;
+
+ if (hwaddr_aton(addr, peer)) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP: invalid "
+ "address '%s'", addr);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP " MACSTR,
+ MAC2STR(peer));
+
+ ret = wpa_tdls_reneg(wpa_s->wpa, peer);
+ if (ret) {
+ if (wpa_tdls_is_external_setup(wpa_s->wpa))
+ ret = wpa_tdls_start(wpa_s->wpa, peer);
+ else
+ ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
+ }
+
+ return ret;
+}
+
+
+static int wpa_supplicant_ctrl_iface_tdls_teardown(
+ struct wpa_supplicant *wpa_s, char *addr)
+{
+ u8 peer[ETH_ALEN];
+
+ if (hwaddr_aton(addr, peer)) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN: invalid "
+ "address '%s'", addr);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN " MACSTR,
+ MAC2STR(peer));
+
+ return wpa_tdls_teardown_link(wpa_s->wpa, peer,
+ WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+}
+
+#endif /* CONFIG_TDLS */
+
+
#ifdef CONFIG_IEEE80211R
static int wpa_supplicant_ctrl_iface_ft_ds(
struct wpa_supplicant *wpa_s, char *addr)
@@ -163,10 +619,26 @@ static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
char *cmd)
{
u8 bssid[ETH_ALEN], *_bssid = bssid;
+#ifdef CONFIG_P2P
+ u8 p2p_dev_addr[ETH_ALEN];
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_AP
+ u8 *_p2p_dev_addr = NULL;
+#endif /* CONFIG_AP */
- if (cmd == NULL || os_strcmp(cmd, "any") == 0)
+ if (cmd == NULL || os_strcmp(cmd, "any") == 0) {
_bssid = NULL;
- else if (hwaddr_aton(cmd, bssid)) {
+#ifdef CONFIG_P2P
+ } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
+ if (hwaddr_aton(cmd + 13, p2p_dev_addr)) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid "
+ "P2P Device Address '%s'",
+ cmd + 13);
+ return -1;
+ }
+ _p2p_dev_addr = p2p_dev_addr;
+#endif /* CONFIG_P2P */
+ } else if (hwaddr_aton(cmd, bssid)) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'",
cmd);
return -1;
@@ -174,10 +646,10 @@ static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_AP
if (wpa_s->ap_iface)
- return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid);
+ return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid, _p2p_dev_addr);
#endif /* CONFIG_AP */
- return wpas_wps_start_pbc(wpa_s, _bssid);
+ return wpas_wps_start_pbc(wpa_s, _bssid, 0);
}
@@ -195,20 +667,36 @@ static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
if (os_strcmp(cmd, "any") == 0)
_bssid = NULL;
- else if (hwaddr_aton(cmd, bssid)) {
+ else if (os_strcmp(cmd, "get") == 0) {
+ ret = wps_generate_pin();
+ goto done;
+ } else if (hwaddr_aton(cmd, bssid)) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'",
cmd);
return -1;
}
#ifdef CONFIG_AP
- if (wpa_s->ap_iface)
+ if (wpa_s->ap_iface) {
+ int timeout = 0;
+ char *pos;
+
+ if (pin) {
+ pos = os_strchr(pin, ' ');
+ if (pos) {
+ *pos++ = '\0';
+ timeout = atoi(pos);
+ }
+ }
+
return wpa_supplicant_ap_wps_pin(wpa_s, _bssid, pin,
- buf, buflen);
+ buf, buflen, timeout);
+ }
#endif /* CONFIG_AP */
if (pin) {
- ret = wpas_wps_start_pin(wpa_s, _bssid, pin);
+ ret = wpas_wps_start_pin(wpa_s, _bssid, pin, 0,
+ DEV_PW_DEFAULT);
if (ret < 0)
return -1;
ret = os_snprintf(buf, buflen, "%s", pin);
@@ -217,10 +705,11 @@ static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
return ret;
}
- ret = wpas_wps_start_pin(wpa_s, _bssid, NULL);
+ ret = wpas_wps_start_pin(wpa_s, _bssid, NULL, 0, DEV_PW_DEFAULT);
if (ret < 0)
return -1;
+done:
/* Return the generated PIN */
ret = os_snprintf(buf, buflen, "%08d", ret);
if (ret < 0 || (size_t) ret >= buflen)
@@ -229,35 +718,272 @@ static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
}
-#ifdef CONFIG_WPS_OOB
-static int wpa_supplicant_ctrl_iface_wps_oob(struct wpa_supplicant *wpa_s,
+static int wpa_supplicant_ctrl_iface_wps_check_pin(
+ struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
+{
+ char pin[9];
+ size_t len;
+ char *pos;
+ int ret;
+
+ wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
+ (u8 *) cmd, os_strlen(cmd));
+ for (pos = cmd, len = 0; *pos != '\0'; pos++) {
+ if (*pos < '0' || *pos > '9')
+ continue;
+ pin[len++] = *pos;
+ if (len == 9) {
+ wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
+ return -1;
+ }
+ }
+ if (len != 4 && len != 8) {
+ wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
+ return -1;
+ }
+ pin[len] = '\0';
+
+ if (len == 8) {
+ unsigned int pin_val;
+ pin_val = atoi(pin);
+ if (!wps_pin_valid(pin_val)) {
+ wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
+ ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
+ if (ret < 0 || (size_t) ret >= buflen)
+ return -1;
+ return ret;
+ }
+ }
+
+ ret = os_snprintf(buf, buflen, "%s", pin);
+ if (ret < 0 || (size_t) ret >= buflen)
+ return -1;
+
+ return ret;
+}
+
+
+#ifdef CONFIG_WPS_NFC
+
+static int wpa_supplicant_ctrl_iface_wps_nfc(struct wpa_supplicant *wpa_s,
char *cmd)
{
- char *path, *method, *name;
+ u8 bssid[ETH_ALEN], *_bssid = bssid;
+
+ if (cmd == NULL || cmd[0] == '\0')
+ _bssid = NULL;
+ else if (hwaddr_aton(cmd, bssid))
+ return -1;
+
+ return wpas_wps_start_nfc(wpa_s, _bssid);
+}
+
+
+static int wpa_supplicant_ctrl_iface_wps_nfc_token(
+ struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
+{
+ int ndef;
+ struct wpabuf *buf;
+ int res;
+
+ if (os_strcmp(cmd, "WPS") == 0)
+ ndef = 0;
+ else if (os_strcmp(cmd, "NDEF") == 0)
+ ndef = 1;
+ else
+ return -1;
+
+ buf = wpas_wps_nfc_token(wpa_s, ndef);
+ if (buf == NULL)
+ return -1;
+
+ res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+ wpabuf_len(buf));
+ reply[res++] = '\n';
+ reply[res] = '\0';
+
+ wpabuf_free(buf);
+
+ return res;
+}
+
+
+static int wpa_supplicant_ctrl_iface_wps_nfc_tag_read(
+ struct wpa_supplicant *wpa_s, char *pos)
+{
+ size_t len;
+ struct wpabuf *buf;
+ int ret;
+
+ len = os_strlen(pos);
+ if (len & 0x01)
+ return -1;
+ len /= 2;
+
+ buf = wpabuf_alloc(len);
+ if (buf == NULL)
+ return -1;
+ if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
+ wpabuf_free(buf);
+ return -1;
+ }
+
+ ret = wpas_wps_nfc_tag_read(wpa_s, buf);
+ wpabuf_free(buf);
+
+ return ret;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_req_wps(struct wpa_supplicant *wpa_s,
+ char *reply, size_t max_len)
+{
+ struct wpabuf *buf;
+ int res;
+
+ buf = wpas_wps_nfc_handover_req(wpa_s);
+ if (buf == NULL)
+ return -1;
+
+ res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+ wpabuf_len(buf));
+ reply[res++] = '\n';
+ reply[res] = '\0';
+
+ wpabuf_free(buf);
+
+ return res;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_req(struct wpa_supplicant *wpa_s,
+ char *cmd, char *reply,
+ size_t max_len)
+{
+ char *pos;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
- path = os_strchr(cmd, ' ');
- if (path == NULL)
+ if (os_strcmp(cmd, "NDEF") != 0)
return -1;
- *path++ = '\0';
- method = os_strchr(path, ' ');
- if (method == NULL)
+ if (os_strcmp(pos, "WPS") == 0) {
+ return wpas_ctrl_nfc_get_handover_req_wps(wpa_s, reply,
+ max_len);
+ }
+
+ return -1;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_sel_wps(struct wpa_supplicant *wpa_s,
+ char *reply, size_t max_len)
+{
+ struct wpabuf *buf;
+ int res;
+
+ buf = wpas_wps_nfc_handover_sel(wpa_s);
+ if (buf == NULL)
return -1;
- *method++ = '\0';
- name = os_strchr(method, ' ');
- if (name != NULL)
- *name++ = '\0';
+ res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+ wpabuf_len(buf));
+ reply[res++] = '\n';
+ reply[res] = '\0';
- return wpas_wps_start_oob(wpa_s, cmd, path, method, name);
+ wpabuf_free(buf);
+
+ return res;
}
-#endif /* CONFIG_WPS_OOB */
+
+
+static int wpas_ctrl_nfc_get_handover_sel(struct wpa_supplicant *wpa_s,
+ char *cmd, char *reply,
+ size_t max_len)
+{
+ char *pos;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ if (os_strcmp(cmd, "NDEF") != 0)
+ return -1;
+
+ if (os_strcmp(pos, "WPS") == 0) {
+ return wpas_ctrl_nfc_get_handover_sel_wps(wpa_s, reply,
+ max_len);
+ }
+
+ return -1;
+}
+
+
+static int wpas_ctrl_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
+ char *cmd, char *reply,
+ size_t max_len)
+{
+ size_t len;
+ struct wpabuf *buf;
+ int ret;
+
+ len = os_strlen(cmd);
+ if (len & 0x01)
+ return -1;
+ len /= 2;
+
+ buf = wpabuf_alloc(len);
+ if (buf == NULL)
+ return -1;
+ if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
+ wpabuf_free(buf);
+ return -1;
+ }
+
+ ret = wpas_wps_nfc_rx_handover_req(wpa_s, buf);
+ wpabuf_free(buf);
+
+ return ret;
+}
+
+
+static int wpas_ctrl_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ size_t len;
+ struct wpabuf *buf;
+ int ret;
+
+ len = os_strlen(cmd);
+ if (len & 0x01)
+ return -1;
+ len /= 2;
+
+ buf = wpabuf_alloc(len);
+ if (buf == NULL)
+ return -1;
+ if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
+ wpabuf_free(buf);
+ return -1;
+ }
+
+ ret = wpas_wps_nfc_rx_handover_sel(wpa_s, buf);
+ wpabuf_free(buf);
+
+ return ret;
+}
+
+#endif /* CONFIG_WPS_NFC */
static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
char *cmd)
{
- u8 bssid[ETH_ALEN], *_bssid = bssid;
+ u8 bssid[ETH_ALEN];
char *pin;
char *new_ssid;
char *new_auth;
@@ -270,9 +996,7 @@ static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
return -1;
*pin++ = '\0';
- if (os_strcmp(cmd, "any") == 0)
- _bssid = NULL;
- else if (hwaddr_aton(cmd, bssid)) {
+ if (hwaddr_aton(cmd, bssid)) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_REG: invalid BSSID '%s'",
cmd);
return -1;
@@ -280,7 +1004,7 @@ static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
new_ssid = os_strchr(pin, ' ');
if (new_ssid == NULL)
- return wpas_wps_start_reg(wpa_s, _bssid, pin, NULL);
+ return wpas_wps_start_reg(wpa_s, bssid, pin, NULL);
*new_ssid++ = '\0';
new_auth = os_strchr(new_ssid, ' ');
@@ -303,20 +1027,86 @@ static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
ap.auth = new_auth;
ap.encr = new_encr;
ap.key_hex = new_key;
- return wpas_wps_start_reg(wpa_s, _bssid, pin, &ap);
+ return wpas_wps_start_reg(wpa_s, bssid, pin, &ap);
}
+#ifdef CONFIG_AP
+static int wpa_supplicant_ctrl_iface_wps_ap_pin(struct wpa_supplicant *wpa_s,
+ char *cmd, char *buf,
+ size_t buflen)
+{
+ int timeout = 300;
+ char *pos;
+ const char *pin_txt;
+
+ if (!wpa_s->ap_iface)
+ return -1;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos)
+ *pos++ = '\0';
+
+ if (os_strcmp(cmd, "disable") == 0) {
+ wpas_wps_ap_pin_disable(wpa_s);
+ return os_snprintf(buf, buflen, "OK\n");
+ }
+
+ if (os_strcmp(cmd, "random") == 0) {
+ if (pos)
+ timeout = atoi(pos);
+ pin_txt = wpas_wps_ap_pin_random(wpa_s, timeout);
+ if (pin_txt == NULL)
+ return -1;
+ return os_snprintf(buf, buflen, "%s", pin_txt);
+ }
+
+ if (os_strcmp(cmd, "get") == 0) {
+ pin_txt = wpas_wps_ap_pin_get(wpa_s);
+ if (pin_txt == NULL)
+ return -1;
+ return os_snprintf(buf, buflen, "%s", pin_txt);
+ }
+
+ if (os_strcmp(cmd, "set") == 0) {
+ char *pin;
+ if (pos == NULL)
+ return -1;
+ pin = pos;
+ pos = os_strchr(pos, ' ');
+ if (pos) {
+ *pos++ = '\0';
+ timeout = atoi(pos);
+ }
+ if (os_strlen(pin) > buflen)
+ return -1;
+ if (wpas_wps_ap_pin_set(wpa_s, pin, timeout) < 0)
+ return -1;
+ return os_snprintf(buf, buflen, "%s", pin);
+ }
+
+ return -1;
+}
+#endif /* CONFIG_AP */
+
+
#ifdef CONFIG_WPS_ER
static int wpa_supplicant_ctrl_iface_wps_er_pin(struct wpa_supplicant *wpa_s,
char *cmd)
{
- char *uuid = cmd, *pin;
+ char *uuid = cmd, *pin, *pos;
+ u8 addr_buf[ETH_ALEN], *addr = NULL;
pin = os_strchr(uuid, ' ');
if (pin == NULL)
return -1;
*pin++ = '\0';
- return wpas_wps_er_add_pin(wpa_s, uuid, pin);
+ pos = os_strchr(pin, ' ');
+ if (pos) {
+ *pos++ = '\0';
+ if (hwaddr_aton(pos, addr_buf) == 0)
+ addr = addr_buf;
+ }
+ return wpas_wps_er_add_pin(wpa_s, addr, uuid, pin);
}
@@ -330,6 +1120,99 @@ static int wpa_supplicant_ctrl_iface_wps_er_learn(struct wpa_supplicant *wpa_s,
*pin++ = '\0';
return wpas_wps_er_learn(wpa_s, uuid, pin);
}
+
+
+static int wpa_supplicant_ctrl_iface_wps_er_set_config(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ char *uuid = cmd, *id;
+ id = os_strchr(uuid, ' ');
+ if (id == NULL)
+ return -1;
+ *id++ = '\0';
+ return wpas_wps_er_set_config(wpa_s, uuid, atoi(id));
+}
+
+
+static int wpa_supplicant_ctrl_iface_wps_er_config(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ char *pin;
+ char *new_ssid;
+ char *new_auth;
+ char *new_encr;
+ char *new_key;
+ struct wps_new_ap_settings ap;
+
+ pin = os_strchr(cmd, ' ');
+ if (pin == NULL)
+ return -1;
+ *pin++ = '\0';
+
+ new_ssid = os_strchr(pin, ' ');
+ if (new_ssid == NULL)
+ return -1;
+ *new_ssid++ = '\0';
+
+ new_auth = os_strchr(new_ssid, ' ');
+ if (new_auth == NULL)
+ return -1;
+ *new_auth++ = '\0';
+
+ new_encr = os_strchr(new_auth, ' ');
+ if (new_encr == NULL)
+ return -1;
+ *new_encr++ = '\0';
+
+ new_key = os_strchr(new_encr, ' ');
+ if (new_key == NULL)
+ return -1;
+ *new_key++ = '\0';
+
+ os_memset(&ap, 0, sizeof(ap));
+ ap.ssid_hex = new_ssid;
+ ap.auth = new_auth;
+ ap.encr = new_encr;
+ ap.key_hex = new_key;
+ return wpas_wps_er_config(wpa_s, cmd, pin, &ap);
+}
+
+
+#ifdef CONFIG_WPS_NFC
+static int wpa_supplicant_ctrl_iface_wps_er_nfc_config_token(
+ struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
+{
+ int ndef;
+ struct wpabuf *buf;
+ int res;
+ char *uuid;
+
+ uuid = os_strchr(cmd, ' ');
+ if (uuid == NULL)
+ return -1;
+ *uuid++ = '\0';
+
+ if (os_strcmp(cmd, "WPS") == 0)
+ ndef = 0;
+ else if (os_strcmp(cmd, "NDEF") == 0)
+ ndef = 1;
+ else
+ return -1;
+
+ buf = wpas_wps_er_nfc_config_token(wpa_s, ndef, uuid);
+ if (buf == NULL)
+ return -1;
+
+ res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+ wpabuf_len(buf));
+ reply[res++] = '\n';
+ reply[res] = '\0';
+
+ wpabuf_free(buf);
+
+ return res;
+}
+#endif /* CONFIG_WPS_NFC */
#endif /* CONFIG_WPS_ER */
#endif /* CONFIG_WPS */
@@ -362,7 +1245,6 @@ static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
char *pos, *id_pos;
int id;
struct wpa_ssid *ssid;
- struct eap_peer_config *eap;
pos = os_strchr(rsp, '-');
if (pos == NULL)
@@ -384,54 +1266,9 @@ static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
"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;
+ return wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid, rsp,
+ pos);
#else /* IEEE8021X_EAPOL */
wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
return -1;
@@ -444,9 +1281,10 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
char *buf, size_t buflen)
{
char *pos, *end, tmp[30];
- int res, verbose, ret;
+ int res, verbose, wps, ret;
verbose = os_strcmp(params, "-VERBOSE") == 0;
+ wps = os_strcmp(params, "-WPS") == 0;
pos = buf;
end = buf + buflen;
if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
@@ -475,6 +1313,17 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
return pos - buf;
pos += ret;
+ if (wps && ssid->passphrase &&
+ wpa_key_mgmt_wpa_psk(ssid->key_mgmt) &&
+ (ssid->mode == WPAS_MODE_AP ||
+ ssid->mode == WPAS_MODE_P2P_GO)) {
+ ret = os_snprintf(pos, end - pos,
+ "passphrase=%s\n",
+ ssid->passphrase);
+ 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",
@@ -497,6 +1346,15 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
ret = os_snprintf(pos, end - pos,
"mode=AP\n");
break;
+ case WPAS_MODE_P2P_GO:
+ ret = os_snprintf(pos, end - pos,
+ "mode=P2P GO\n");
+ break;
+ case WPAS_MODE_P2P_GROUP_FORMATION:
+ ret = os_snprintf(pos, end - pos,
+ "mode=P2P GO - group "
+ "formation\n");
+ break;
default:
ret = 0;
break;
@@ -529,6 +1387,73 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
pos += ret;
}
+#ifdef CONFIG_P2P
+ if (wpa_s->global->p2p) {
+ ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR
+ "\n", MAC2STR(wpa_s->global->p2p_dev_addr));
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_P2P */
+
+ ret = os_snprintf(pos, end - pos, "address=" MACSTR "\n",
+ MAC2STR(wpa_s->own_addr));
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+
+#ifdef CONFIG_HS20
+ if (wpa_s->current_bss &&
+ wpa_bss_get_vendor_ie(wpa_s->current_bss, HS20_IE_VENDOR_TYPE) &&
+ wpa_s->wpa_proto == WPA_PROTO_RSN &&
+ wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
+ ret = os_snprintf(pos, end - pos, "hs20=1\n");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
+
+ if (wpa_s->current_ssid) {
+ struct wpa_cred *cred;
+ char *type;
+
+ for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ if (wpa_s->current_ssid->parent_cred != cred)
+ continue;
+ if (!cred->domain)
+ continue;
+
+ ret = os_snprintf(pos, end - pos, "home_sp=%s\n",
+ cred->domain);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+
+ if (wpa_s->current_bss == NULL ||
+ wpa_s->current_bss->anqp == NULL)
+ res = -1;
+ else
+ res = interworking_home_sp_cred(
+ wpa_s, cred,
+ wpa_s->current_bss->anqp->domain_name);
+ if (res > 0)
+ type = "home";
+ else if (res == 0)
+ type = "roaming";
+ else
+ type = "unknown";
+
+ ret = os_snprintf(pos, end - pos, "sp_type=%s\n", type);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+
+ break;
+ }
+ }
+#endif /* CONFIG_HS20 */
+
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,
@@ -579,6 +1504,152 @@ static int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s,
}
+static int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s,
+ char *cmd, char *buf,
+ size_t buflen)
+{
+ u8 bssid[ETH_ALEN];
+ struct wpa_blacklist *e;
+ char *pos, *end;
+ int ret;
+
+ /* cmd: "BLACKLIST [<BSSID>]" */
+ if (*cmd == '\0') {
+ pos = buf;
+ end = buf + buflen;
+ e = wpa_s->blacklist;
+ while (e) {
+ ret = os_snprintf(pos, end - pos, MACSTR "\n",
+ MAC2STR(e->bssid));
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ e = e->next;
+ }
+ return pos - buf;
+ }
+
+ cmd++;
+ if (os_strncmp(cmd, "clear", 5) == 0) {
+ wpa_blacklist_clear(wpa_s);
+ os_memcpy(buf, "OK\n", 3);
+ return 3;
+ }
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: BLACKLIST bssid='%s'", cmd);
+ if (hwaddr_aton(cmd, bssid)) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: invalid BSSID '%s'", cmd);
+ return -1;
+ }
+
+ /*
+ * Add the BSSID twice, so its count will be 2, causing it to be
+ * skipped when processing scan results.
+ */
+ ret = wpa_blacklist_add(wpa_s, bssid);
+ if (ret != 0)
+ return -1;
+ ret = wpa_blacklist_add(wpa_s, bssid);
+ if (ret != 0)
+ return -1;
+ os_memcpy(buf, "OK\n", 3);
+ return 3;
+}
+
+
+extern int wpa_debug_level;
+extern int wpa_debug_timestamp;
+
+static const char * debug_level_str(int level)
+{
+ switch (level) {
+ case MSG_EXCESSIVE:
+ return "EXCESSIVE";
+ case MSG_MSGDUMP:
+ return "MSGDUMP";
+ case MSG_DEBUG:
+ return "DEBUG";
+ case MSG_INFO:
+ return "INFO";
+ case MSG_WARNING:
+ return "WARNING";
+ case MSG_ERROR:
+ return "ERROR";
+ default:
+ return "?";
+ }
+}
+
+
+static int str_to_debug_level(const char *s)
+{
+ if (os_strcasecmp(s, "EXCESSIVE") == 0)
+ return MSG_EXCESSIVE;
+ if (os_strcasecmp(s, "MSGDUMP") == 0)
+ return MSG_MSGDUMP;
+ if (os_strcasecmp(s, "DEBUG") == 0)
+ return MSG_DEBUG;
+ if (os_strcasecmp(s, "INFO") == 0)
+ return MSG_INFO;
+ if (os_strcasecmp(s, "WARNING") == 0)
+ return MSG_WARNING;
+ if (os_strcasecmp(s, "ERROR") == 0)
+ return MSG_ERROR;
+ return -1;
+}
+
+
+static int wpa_supplicant_ctrl_iface_log_level(struct wpa_supplicant *wpa_s,
+ char *cmd, char *buf,
+ size_t buflen)
+{
+ char *pos, *end, *stamp;
+ int ret;
+
+ if (cmd == NULL) {
+ return -1;
+ }
+
+ /* cmd: "LOG_LEVEL [<level>]" */
+ if (*cmd == '\0') {
+ pos = buf;
+ end = buf + buflen;
+ ret = os_snprintf(pos, end - pos, "Current level: %s\n"
+ "Timestamp: %d\n",
+ debug_level_str(wpa_debug_level),
+ wpa_debug_timestamp);
+ if (ret < 0 || ret >= end - pos)
+ ret = 0;
+
+ return ret;
+ }
+
+ while (*cmd == ' ')
+ cmd++;
+
+ stamp = os_strchr(cmd, ' ');
+ if (stamp) {
+ *stamp++ = '\0';
+ while (*stamp == ' ') {
+ stamp++;
+ }
+ }
+
+ if (cmd && os_strlen(cmd)) {
+ int level = str_to_debug_level(cmd);
+ if (level < 0)
+ return -1;
+ wpa_debug_level = level;
+ }
+
+ if (stamp && os_strlen(stamp))
+ wpa_debug_timestamp = atoi(stamp);
+
+ os_memcpy(buf, "OK\n", 3);
+ return 3;
+}
+
+
static int wpa_supplicant_ctrl_iface_list_networks(
struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
{
@@ -611,10 +1682,14 @@ static int wpa_supplicant_ctrl_iface_list_networks(
if (ret < 0 || ret >= end - pos)
return pos - buf;
pos += ret;
- ret = os_snprintf(pos, end - pos, "\t%s%s",
+ ret = os_snprintf(pos, end - pos, "\t%s%s%s%s",
ssid == wpa_s->current_ssid ?
"[CURRENT]" : "",
- ssid->disabled ? "[DISABLED]" : "");
+ ssid->disabled ? "[DISABLED]" : "",
+ ssid->disabled_until.sec ?
+ "[TEMP-DISABLED]" : "",
+ ssid->disabled == 2 ? "[P2P-PERSISTENT]" :
+ "");
if (ret < 0 || ret >= end - pos)
return pos - buf;
pos += ret;
@@ -673,6 +1748,13 @@ static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher)
pos += ret;
first = 0;
}
+ if (cipher & WPA_CIPHER_GCMP) {
+ ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : "+");
+ if (ret < 0 || ret >= end - pos)
+ return pos;
+ pos += ret;
+ first = 0;
+ }
return pos;
}
@@ -774,7 +1856,8 @@ static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
#ifdef CONFIG_WPS
-static char * wpa_supplicant_wps_ie_txt_buf(char *pos, char *end,
+static char * wpa_supplicant_wps_ie_txt_buf(struct wpa_supplicant *wpa_s,
+ char *pos, char *end,
struct wpabuf *wps_ie)
{
int ret;
@@ -784,6 +1867,10 @@ static char * wpa_supplicant_wps_ie_txt_buf(char *pos, char *end,
return pos;
if (wps_is_selected_pbc_registrar(wps_ie))
txt = "[WPS-PBC]";
+#ifdef CONFIG_WPS2
+ else if (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 0))
+ txt = "[WPS-AUTH]";
+#endif /* CONFIG_WPS2 */
else if (wps_is_selected_pin_registrar(wps_ie))
txt = "[WPS-PIN]";
else
@@ -798,13 +1885,14 @@ static char * wpa_supplicant_wps_ie_txt_buf(char *pos, char *end,
#endif /* CONFIG_WPS */
-static char * wpa_supplicant_wps_ie_txt(char *pos, char *end,
+static char * wpa_supplicant_wps_ie_txt(struct wpa_supplicant *wpa_s,
+ char *pos, char *end,
const struct wpa_bss *bss)
{
#ifdef CONFIG_WPS
struct wpabuf *wps_ie;
wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
- return wpa_supplicant_wps_ie_txt_buf(pos, end, wps_ie);
+ return wpa_supplicant_wps_ie_txt_buf(wpa_s, pos, end, wps_ie);
#else /* CONFIG_WPS */
return pos;
#endif /* CONFIG_WPS */
@@ -813,11 +1901,18 @@ static char * wpa_supplicant_wps_ie_txt(char *pos, char *end,
/* Format one result on one text line into a buffer. */
static int wpa_supplicant_ctrl_iface_scan_result(
+ struct wpa_supplicant *wpa_s,
const struct wpa_bss *bss, char *buf, size_t buflen)
{
char *pos, *end;
int ret;
- const u8 *ie, *ie2;
+ const u8 *ie, *ie2, *p2p;
+
+ p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
+ if (p2p && bss->ssid_len == P2P_WILDCARD_SSID_LEN &&
+ os_memcmp(bss->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) ==
+ 0)
+ return 0; /* Do not show P2P listen discovery results here */
pos = buf;
end = buf + buflen;
@@ -825,7 +1920,7 @@ static int wpa_supplicant_ctrl_iface_scan_result(
ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t",
MAC2STR(bss->bssid), bss->freq, bss->level);
if (ret < 0 || ret >= end - pos)
- return pos - buf;
+ return -1;
pos += ret;
ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
if (ie)
@@ -833,35 +1928,49 @@ static int wpa_supplicant_ctrl_iface_scan_result(
ie2 = wpa_bss_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);
+ pos = wpa_supplicant_wps_ie_txt(wpa_s, 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;
+ return -1;
pos += ret;
}
if (bss->caps & IEEE80211_CAP_IBSS) {
ret = os_snprintf(pos, end - pos, "[IBSS]");
if (ret < 0 || ret >= end - pos)
- return pos - buf;
+ return -1;
pos += ret;
}
if (bss->caps & IEEE80211_CAP_ESS) {
ret = os_snprintf(pos, end - pos, "[ESS]");
if (ret < 0 || ret >= end - pos)
- return pos - buf;
+ return -1;
pos += ret;
}
+ if (p2p) {
+ ret = os_snprintf(pos, end - pos, "[P2P]");
+ if (ret < 0 || ret >= end - pos)
+ return -1;
+ pos += ret;
+ }
+#ifdef CONFIG_HS20
+ if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE) && ie2) {
+ ret = os_snprintf(pos, end - pos, "[HS20]");
+ if (ret < 0 || ret >= end - pos)
+ return -1;
+ pos += ret;
+ }
+#endif /* CONFIG_HS20 */
ret = os_snprintf(pos, end - pos, "\t%s",
wpa_ssid_txt(bss->ssid, bss->ssid_len));
if (ret < 0 || ret >= end - pos)
- return pos - buf;
+ return -1;
pos += ret;
ret = os_snprintf(pos, end - pos, "\n");
if (ret < 0 || ret >= end - pos)
- return pos - buf;
+ return -1;
pos += ret;
return pos - buf;
@@ -884,7 +1993,7 @@ static int wpa_supplicant_ctrl_iface_scan_results(
pos += ret;
dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
- ret = wpa_supplicant_ctrl_iface_scan_result(bss, pos,
+ ret = wpa_supplicant_ctrl_iface_scan_result(wpa_s, bss, pos,
end - pos);
if (ret < 0 || ret >= end - pos)
return pos - buf;
@@ -915,6 +2024,11 @@ static int wpa_supplicant_ctrl_iface_select_network(
"network id=%d", id);
return -1;
}
+ if (ssid->disabled == 2) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
+ "SELECT_NETWORK with persistent P2P group");
+ return -1;
+ }
}
wpa_supplicant_select_network(wpa_s, ssid);
@@ -943,6 +2057,16 @@ static int wpa_supplicant_ctrl_iface_enable_network(
"network id=%d", id);
return -1;
}
+ if (ssid->disabled == 2) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
+ "ENABLE_NETWORK with persistent P2P group");
+ return -1;
+ }
+
+ if (os_strstr(cmd, " no-connect")) {
+ ssid->disabled = 0;
+ return 0;
+ }
}
wpa_supplicant_enable_network(wpa_s, ssid);
@@ -970,6 +2094,12 @@ static int wpa_supplicant_ctrl_iface_disable_network(
"network id=%d", id);
return -1;
}
+ if (ssid->disabled == 2) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
+ "DISABLE_NETWORK with persistent P2P "
+ "group");
+ return -1;
+ }
}
wpa_supplicant_disable_network(wpa_s, ssid);
@@ -1018,10 +2148,15 @@ static int wpa_supplicant_ctrl_iface_remove_network(
wpas_notify_network_removed(wpa_s, remove_ssid);
wpa_config_remove_network(wpa_s->conf, id);
}
+ eapol_sm_invalidate_cached_session(wpa_s->eapol);
if (wpa_s->current_ssid) {
- eapol_sm_invalidate_cached_session(wpa_s->eapol);
- wpa_supplicant_disassociate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
+#ifdef CONFIG_SME
+ wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+ wpa_sm_set_config(wpa_s->wpa, NULL);
+ eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_DEAUTH_LEAVING);
}
return 0;
}
@@ -1030,21 +2165,37 @@ static int wpa_supplicant_ctrl_iface_remove_network(
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) {
+ if (ssid)
+ wpas_notify_network_removed(wpa_s, ssid);
+ if (ssid == NULL) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
"id=%d", id);
return -1;
}
- if (ssid == wpa_s->current_ssid) {
+ if (ssid == wpa_s->current_ssid || wpa_s->current_ssid == NULL) {
+#ifdef CONFIG_SME
+ wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
/*
- * Invalidate the EAP session cache if the current network is
- * removed.
+ * Invalidate the EAP session cache if the current or
+ * previously used network is removed.
*/
eapol_sm_invalidate_cached_session(wpa_s->eapol);
+ }
+
+ if (ssid == wpa_s->current_ssid) {
+ wpa_sm_set_config(wpa_s->wpa, NULL);
+ eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
- wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ wpa_supplicant_deauthenticate(wpa_s,
+ WLAN_REASON_DEAUTH_LEAVING);
+ }
+
+ if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Not able to remove the "
+ "network id=%d", id);
+ return -1;
}
return 0;
@@ -1088,10 +2239,14 @@ static int wpa_supplicant_ctrl_iface_set_network(
return -1;
}
- if (wpa_s->current_ssid == ssid) {
+ if (os_strcmp(name, "bssid") != 0 &&
+ os_strcmp(name, "priority") != 0)
+ wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
+
+ if (wpa_s->current_ssid == ssid || wpa_s->current_ssid == NULL) {
/*
* Invalidate the EAP session cache if anything in the current
- * configuration changes.
+ * or previously used configuration changes.
*/
eapol_sm_invalidate_cached_session(wpa_s->eapol);
}
@@ -1151,6 +2306,167 @@ static int wpa_supplicant_ctrl_iface_get_network(
}
+static int wpa_supplicant_ctrl_iface_list_creds(struct wpa_supplicant *wpa_s,
+ char *buf, size_t buflen)
+{
+ char *pos, *end;
+ struct wpa_cred *cred;
+ int ret;
+
+ pos = buf;
+ end = buf + buflen;
+ ret = os_snprintf(pos, end - pos,
+ "cred id / realm / username / domain / imsi\n");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+
+ cred = wpa_s->conf->cred;
+ while (cred) {
+ ret = os_snprintf(pos, end - pos, "%d\t%s\t%s\t%s\t%s\n",
+ cred->id, cred->realm ? cred->realm : "",
+ cred->username ? cred->username : "",
+ cred->domain ? cred->domain : "",
+ cred->imsi ? cred->imsi : "");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+
+ cred = cred->next;
+ }
+
+ return pos - buf;
+}
+
+
+static int wpa_supplicant_ctrl_iface_add_cred(struct wpa_supplicant *wpa_s,
+ char *buf, size_t buflen)
+{
+ struct wpa_cred *cred;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_CRED");
+
+ cred = wpa_config_add_cred(wpa_s->conf);
+ if (cred == NULL)
+ return -1;
+
+ ret = os_snprintf(buf, buflen, "%d\n", cred->id);
+ if (ret < 0 || (size_t) ret >= buflen)
+ return -1;
+ return ret;
+}
+
+
+static int wpas_ctrl_remove_cred(struct wpa_supplicant *wpa_s,
+ struct wpa_cred *cred)
+{
+ struct wpa_ssid *ssid;
+ char str[20];
+
+ if (cred == NULL || wpa_config_remove_cred(wpa_s->conf, cred->id) < 0) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred");
+ return -1;
+ }
+
+ /* Remove any network entry created based on the removed credential */
+ ssid = wpa_s->conf->ssid;
+ while (ssid) {
+ if (ssid->parent_cred == cred) {
+ wpa_printf(MSG_DEBUG, "Remove network id %d since it "
+ "used the removed credential", ssid->id);
+ os_snprintf(str, sizeof(str), "%d", ssid->id);
+ ssid = ssid->next;
+ wpa_supplicant_ctrl_iface_remove_network(wpa_s, str);
+ } else
+ ssid = ssid->next;
+ }
+
+ return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ int id;
+ struct wpa_cred *cred, *prev;
+
+ /* cmd: "<cred id>", "all", or "sp_fqdn=<FQDN>" */
+ if (os_strcmp(cmd, "all") == 0) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED all");
+ cred = wpa_s->conf->cred;
+ while (cred) {
+ prev = cred;
+ cred = cred->next;
+ wpas_ctrl_remove_cred(wpa_s, prev);
+ }
+ return 0;
+ }
+
+ if (os_strncmp(cmd, "sp_fqdn=", 8) == 0) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED SP FQDN '%s'",
+ cmd + 8);
+ cred = wpa_s->conf->cred;
+ while (cred) {
+ prev = cred;
+ cred = cred->next;
+ if (prev->domain &&
+ os_strcmp(prev->domain, cmd + 8) == 0)
+ wpas_ctrl_remove_cred(wpa_s, prev);
+ }
+ return 0;
+ }
+
+ id = atoi(cmd);
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED id=%d", id);
+
+ cred = wpa_config_get_cred(wpa_s->conf, id);
+ return wpas_ctrl_remove_cred(wpa_s, cred);
+}
+
+
+static int wpa_supplicant_ctrl_iface_set_cred(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ int id;
+ struct wpa_cred *cred;
+ char *name, *value;
+
+ /* cmd: "<cred 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_CRED id=%d name='%s'",
+ id, name);
+ wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
+ (u8 *) value, os_strlen(value));
+
+ cred = wpa_config_get_cred(wpa_s->conf, id);
+ if (cred == NULL) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d",
+ id);
+ return -1;
+ }
+
+ if (wpa_config_set_cred(cred, name, value, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set cred "
+ "variable '%s'", name);
+ return -1;
+ }
+
+ return 0;
+}
+
+
#ifndef CONFIG_NO_CONFIG_WRITE
static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s)
{
@@ -1204,6 +2520,14 @@ static int ctrl_iface_get_capability_pairwise(int res, char *strict,
first = 0;
}
+ if (capa->enc & WPA_DRIVER_CAPA_ENC_GCMP) {
+ ret = os_snprintf(pos, end - pos, "%sGCMP", 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)
@@ -1252,6 +2576,14 @@ static int ctrl_iface_get_capability_group(int res, char *strict,
first = 0;
}
+ if (capa->enc & WPA_DRIVER_CAPA_ENC_GCMP) {
+ ret = os_snprintf(pos, end - pos, "%sGCMP", 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)
@@ -1425,6 +2757,56 @@ static int ctrl_iface_get_capability_auth_alg(int res, char *strict,
}
+static int ctrl_iface_get_capability_channels(struct wpa_supplicant *wpa_s,
+ char *buf, size_t buflen)
+{
+ struct hostapd_channel_data *chnl;
+ int ret, i, j;
+ char *pos, *end, *hmode;
+
+ pos = buf;
+ end = pos + buflen;
+
+ for (j = 0; j < wpa_s->hw.num_modes; j++) {
+ switch (wpa_s->hw.modes[j].mode) {
+ case HOSTAPD_MODE_IEEE80211B:
+ hmode = "B";
+ break;
+ case HOSTAPD_MODE_IEEE80211G:
+ hmode = "G";
+ break;
+ case HOSTAPD_MODE_IEEE80211A:
+ hmode = "A";
+ break;
+ case HOSTAPD_MODE_IEEE80211AD:
+ hmode = "AD";
+ break;
+ default:
+ continue;
+ }
+ ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:", hmode);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ chnl = wpa_s->hw.modes[j].channels;
+ for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) {
+ if (chnl[i].flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+ ret = os_snprintf(pos, end - pos, " %d", chnl[i].chan);
+ 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_get_capability(
struct wpa_supplicant *wpa_s, const char *_field, char *buf,
size_t buflen)
@@ -1475,6 +2857,9 @@ static int wpa_supplicant_ctrl_iface_get_capability(
return ctrl_iface_get_capability_auth_alg(res, strict, &capa,
buf, buflen);
+ if (os_strcmp(field, "channels") == 0)
+ return ctrl_iface_get_capability_channels(wpa_s, buf, buflen);
+
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
field);
@@ -1482,6 +2867,288 @@ static int wpa_supplicant_ctrl_iface_get_capability(
}
+#ifdef CONFIG_INTERWORKING
+static char * anqp_add_hex(char *pos, char *end, const char *title,
+ struct wpabuf *data)
+{
+ char *start = pos;
+ size_t i;
+ int ret;
+ const u8 *d;
+
+ if (data == NULL)
+ return start;
+
+ ret = os_snprintf(pos, end - pos, "%s=", title);
+ if (ret < 0 || ret >= end - pos)
+ return start;
+ pos += ret;
+
+ d = wpabuf_head_u8(data);
+ for (i = 0; i < wpabuf_len(data); i++) {
+ ret = os_snprintf(pos, end - pos, "%02x", *d++);
+ if (ret < 0 || ret >= end - pos)
+ return start;
+ pos += ret;
+ }
+
+ ret = os_snprintf(pos, end - pos, "\n");
+ if (ret < 0 || ret >= end - pos)
+ return start;
+ pos += ret;
+
+ return pos;
+}
+#endif /* CONFIG_INTERWORKING */
+
+
+static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ unsigned long mask, char *buf, size_t buflen)
+{
+ size_t i;
+ int ret;
+ char *pos, *end;
+ const u8 *ie, *ie2;
+
+ pos = buf;
+ end = buf + buflen;
+
+ if (mask & WPA_BSS_MASK_ID) {
+ ret = os_snprintf(pos, end - pos, "id=%u\n", bss->id);
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+
+ if (mask & WPA_BSS_MASK_BSSID) {
+ ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
+ MAC2STR(bss->bssid));
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+
+ if (mask & WPA_BSS_MASK_FREQ) {
+ ret = os_snprintf(pos, end - pos, "freq=%d\n", bss->freq);
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+
+ if (mask & WPA_BSS_MASK_BEACON_INT) {
+ ret = os_snprintf(pos, end - pos, "beacon_int=%d\n",
+ bss->beacon_int);
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+
+ if (mask & WPA_BSS_MASK_CAPABILITIES) {
+ ret = os_snprintf(pos, end - pos, "capabilities=0x%04x\n",
+ bss->caps);
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+
+ if (mask & WPA_BSS_MASK_QUAL) {
+ ret = os_snprintf(pos, end - pos, "qual=%d\n", bss->qual);
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+
+ if (mask & WPA_BSS_MASK_NOISE) {
+ ret = os_snprintf(pos, end - pos, "noise=%d\n", bss->noise);
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+
+ if (mask & WPA_BSS_MASK_LEVEL) {
+ ret = os_snprintf(pos, end - pos, "level=%d\n", bss->level);
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+
+ if (mask & WPA_BSS_MASK_TSF) {
+ ret = os_snprintf(pos, end - pos, "tsf=%016llu\n",
+ (unsigned long long) bss->tsf);
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+
+ if (mask & WPA_BSS_MASK_AGE) {
+ struct os_time now;
+
+ os_get_time(&now);
+ ret = os_snprintf(pos, end - pos, "age=%d\n",
+ (int) (now.sec - bss->last_update.sec));
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+
+ if (mask & WPA_BSS_MASK_IE) {
+ ret = os_snprintf(pos, end - pos, "ie=");
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ 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 0;
+ pos += ret;
+ }
+
+ ret = os_snprintf(pos, end - pos, "\n");
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+
+ if (mask & WPA_BSS_MASK_FLAGS) {
+ ret = os_snprintf(pos, end - pos, "flags=");
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+
+ ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+ if (ie)
+ pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie,
+ 2 + ie[1]);
+ ie2 = wpa_bss_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(wpa_s, 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 0;
+ pos += ret;
+ }
+ if (bss->caps & IEEE80211_CAP_IBSS) {
+ ret = os_snprintf(pos, end - pos, "[IBSS]");
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+ if (bss->caps & IEEE80211_CAP_ESS) {
+ ret = os_snprintf(pos, end - pos, "[ESS]");
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+ if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE)) {
+ ret = os_snprintf(pos, end - pos, "[P2P]");
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+#ifdef CONFIG_HS20
+ if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
+ ret = os_snprintf(pos, end - pos, "[HS20]");
+ if (ret < 0 || ret >= end - pos)
+ return -1;
+ pos += ret;
+ }
+#endif /* CONFIG_HS20 */
+
+ ret = os_snprintf(pos, end - pos, "\n");
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+
+ if (mask & WPA_BSS_MASK_SSID) {
+ ret = os_snprintf(pos, end - pos, "ssid=%s\n",
+ wpa_ssid_txt(bss->ssid, bss->ssid_len));
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+
+#ifdef CONFIG_WPS
+ if (mask & WPA_BSS_MASK_WPS_SCAN) {
+ ie = (const u8 *) (bss + 1);
+ ret = wpas_wps_scan_result_text(ie, bss->ie_len, pos, end);
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_P2P
+ if (mask & WPA_BSS_MASK_P2P_SCAN) {
+ ie = (const u8 *) (bss + 1);
+ ret = wpas_p2p_scan_result_text(ie, bss->ie_len, pos, end);
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_WIFI_DISPLAY
+ if (mask & WPA_BSS_MASK_WIFI_DISPLAY) {
+ struct wpabuf *wfd;
+ ie = (const u8 *) (bss + 1);
+ wfd = ieee802_11_vendor_ie_concat(ie, bss->ie_len,
+ WFD_IE_VENDOR_TYPE);
+ if (wfd) {
+ ret = os_snprintf(pos, end - pos, "wfd_subelems=");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+
+ pos += wpa_snprintf_hex(pos, end - pos,
+ wpabuf_head(wfd),
+ wpabuf_len(wfd));
+ wpabuf_free(wfd);
+
+ ret = os_snprintf(pos, end - pos, "\n");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
+ }
+#endif /* CONFIG_WIFI_DISPLAY */
+
+#ifdef CONFIG_INTERWORKING
+ if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) {
+ struct wpa_bss_anqp *anqp = bss->anqp;
+ pos = anqp_add_hex(pos, end, "anqp_venue_name",
+ anqp->venue_name);
+ pos = anqp_add_hex(pos, end, "anqp_network_auth_type",
+ anqp->network_auth_type);
+ pos = anqp_add_hex(pos, end, "anqp_roaming_consortium",
+ anqp->roaming_consortium);
+ pos = anqp_add_hex(pos, end, "anqp_ip_addr_type_availability",
+ anqp->ip_addr_type_availability);
+ pos = anqp_add_hex(pos, end, "anqp_nai_realm",
+ anqp->nai_realm);
+ pos = anqp_add_hex(pos, end, "anqp_3gpp", anqp->anqp_3gpp);
+ pos = anqp_add_hex(pos, end, "anqp_domain_name",
+ anqp->domain_name);
+#ifdef CONFIG_HS20
+ pos = anqp_add_hex(pos, end, "hs20_operator_friendly_name",
+ anqp->hs20_operator_friendly_name);
+ pos = anqp_add_hex(pos, end, "hs20_wan_metrics",
+ anqp->hs20_wan_metrics);
+ pos = anqp_add_hex(pos, end, "hs20_connection_capability",
+ anqp->hs20_connection_capability);
+#endif /* CONFIG_HS20 */
+ }
+#endif /* CONFIG_INTERWORKING */
+
+ return pos - buf;
+}
+
+
static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
const char *cmd, char *buf,
size_t buflen)
@@ -1489,12 +3156,55 @@ static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
u8 bssid[ETH_ALEN];
size_t i;
struct wpa_bss *bss;
- int ret;
- char *pos, *end;
- const u8 *ie, *ie2;
+ struct wpa_bss *bsslast = NULL;
+ struct dl_list *next;
+ int ret = 0;
+ int len;
+ char *ctmp;
+ unsigned long mask = WPA_BSS_MASK_ALL;
+
+ if (os_strncmp(cmd, "RANGE=", 6) == 0) {
+ if (os_strncmp(cmd + 6, "ALL", 3) == 0) {
+ bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss,
+ list_id);
+ bsslast = dl_list_last(&wpa_s->bss_id, struct wpa_bss,
+ list_id);
+ } else { /* N1-N2 */
+ unsigned int id1, id2;
+
+ if ((ctmp = os_strchr(cmd + 6, '-')) == NULL) {
+ wpa_printf(MSG_INFO, "Wrong BSS range "
+ "format");
+ return 0;
+ }
- if (os_strcmp(cmd, "FIRST") == 0)
- bss = dl_list_first(&wpa_s->bss, struct wpa_bss, list);
+ id1 = atoi(cmd + 6);
+ bss = wpa_bss_get_id(wpa_s, id1);
+ id2 = atoi(ctmp + 1);
+ if (id2 == 0)
+ bsslast = dl_list_last(&wpa_s->bss_id,
+ struct wpa_bss,
+ list_id);
+ else {
+ bsslast = wpa_bss_get_id(wpa_s, id2);
+ if (bsslast == NULL && bss && id2 > id1) {
+ struct wpa_bss *tmp = bss;
+ for (;;) {
+ next = tmp->list_id.next;
+ if (next == &wpa_s->bss_id)
+ break;
+ tmp = dl_list_entry(
+ next, struct wpa_bss,
+ list_id);
+ if (tmp->id > id2)
+ break;
+ bsslast = tmp;
+ }
+ }
+ }
+ }
+ } else if (os_strcmp(cmd, "FIRST") == 0)
+ bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss, list_id);
else if (os_strncmp(cmd, "ID-", 3) == 0) {
i = atoi(cmd + 3);
bss = wpa_bss_get_id(wpa_s, i);
@@ -1502,13 +3212,20 @@ static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
i = atoi(cmd + 5);
bss = wpa_bss_get_id(wpa_s, i);
if (bss) {
- struct dl_list *next = bss->list_id.next;
+ next = bss->list_id.next;
if (next == &wpa_s->bss_id)
bss = NULL;
else
bss = dl_list_entry(next, struct wpa_bss,
list_id);
}
+#ifdef CONFIG_P2P
+ } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
+ if (hwaddr_aton(cmd + 13, bssid) == 0)
+ bss = wpa_bss_get_p2p_dev_addr(wpa_s, bssid);
+ else
+ bss = NULL;
+#endif /* CONFIG_P2P */
} else if (hwaddr_aton(cmd, bssid) == 0)
bss = wpa_bss_get_bssid(wpa_s, bssid);
else {
@@ -1524,118 +3241,90 @@ static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
}
}
+ if ((ctmp = os_strstr(cmd, "MASK=")) != NULL) {
+ mask = strtoul(ctmp + 5, NULL, 0x10);
+ if (mask == 0)
+ mask = WPA_BSS_MASK_ALL;
+ }
+
if (bss == NULL)
return 0;
- pos = buf;
- end = buf + buflen;
- ret = os_snprintf(pos, end - pos,
- "id=%u\n"
- "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=",
- bss->id,
- 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;
+ if (bsslast == NULL)
+ bsslast = bss;
+ do {
+ len = print_bss_info(wpa_s, bss, mask, buf, buflen);
+ ret += len;
+ buf += len;
+ buflen -= len;
+ if (bss == bsslast)
+ break;
+ next = bss->list_id.next;
+ if (next == &wpa_s->bss_id)
+ break;
+ bss = dl_list_entry(next, struct wpa_bss, list_id);
+ } while (bss && len);
- 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;
- }
+ return 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;
+static int wpa_supplicant_ctrl_iface_ap_scan(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ int ap_scan = atoi(cmd);
+ return wpa_supplicant_set_ap_scan(wpa_s, ap_scan);
+}
- ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
- if (ie)
- pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
- ie2 = wpa_bss_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;
- }
- if (bss->caps & IEEE80211_CAP_ESS) {
- ret = os_snprintf(pos, end - pos, "[ESS]");
- 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;
+static int wpa_supplicant_ctrl_iface_scan_interval(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ int scan_int = atoi(cmd);
+ return wpa_supplicant_set_scan_interval(wpa_s, scan_int);
+}
- ret = os_snprintf(pos, end - pos, "ssid=%s\n",
- wpa_ssid_txt(bss->ssid, bss->ssid_len));
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
-#ifdef CONFIG_WPS
- ie = (const u8 *) (bss + 1);
- ret = wpas_wps_scan_result_text(ie, bss->ie_len, pos, end);
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
-#endif /* CONFIG_WPS */
+static int wpa_supplicant_ctrl_iface_bss_expire_age(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ int expire_age = atoi(cmd);
+ return wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age);
+}
- return pos - buf;
+
+static int wpa_supplicant_ctrl_iface_bss_expire_count(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ int expire_count = atoi(cmd);
+ return wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count);
}
-static int wpa_supplicant_ctrl_iface_ap_scan(
+static int wpa_supplicant_ctrl_iface_bss_flush(
struct wpa_supplicant *wpa_s, char *cmd)
{
- int ap_scan = atoi(cmd);
- return wpa_supplicant_set_ap_scan(wpa_s, ap_scan);
+ int flush_age = atoi(cmd);
+
+ if (flush_age == 0)
+ wpa_bss_flush(wpa_s);
+ else
+ wpa_bss_flush_by_age(wpa_s, flush_age);
+ return 0;
}
static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
{
- u8 *bcast = (u8 *) "\xff\xff\xff\xff\xff\xff";
-
wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication");
/* 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);
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0);
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0);
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0);
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0);
#ifdef CONFIG_IEEE80211W
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 4, 0, NULL, 0, NULL, 0);
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 5, 0, NULL, 0, NULL, 0);
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0);
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0);
#endif /* CONFIG_IEEE80211W */
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL,
@@ -1651,6 +3340,9 @@ static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
char *addr)
{
+#ifdef CONFIG_NO_SCAN_PROCESSING
+ return -1;
+#else /* CONFIG_NO_SCAN_PROCESSING */
u8 bssid[ETH_ALEN];
struct wpa_bss *bss;
struct wpa_ssid *ssid = wpa_s->current_ssid;
@@ -1685,6 +3377,1406 @@ static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
wpa_supplicant_connect(wpa_s, bss, ssid);
return 0;
+#endif /* CONFIG_NO_SCAN_PROCESSING */
+}
+
+
+#ifdef CONFIG_P2P
+static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ unsigned int timeout = atoi(cmd);
+ enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL;
+ u8 dev_id[ETH_ALEN], *_dev_id = NULL;
+ char *pos;
+ unsigned int search_delay;
+
+ if (os_strstr(cmd, "type=social"))
+ type = P2P_FIND_ONLY_SOCIAL;
+ else if (os_strstr(cmd, "type=progressive"))
+ type = P2P_FIND_PROGRESSIVE;
+
+ pos = os_strstr(cmd, "dev_id=");
+ if (pos) {
+ pos += 7;
+ if (hwaddr_aton(pos, dev_id))
+ return -1;
+ _dev_id = dev_id;
+ }
+
+ pos = os_strstr(cmd, "delay=");
+ if (pos) {
+ pos += 6;
+ search_delay = atoi(pos);
+ } else
+ search_delay = wpas_p2p_search_delay(wpa_s);
+
+ return wpas_p2p_find(wpa_s, timeout, type, 0, NULL, _dev_id,
+ search_delay);
+}
+
+
+static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
+ char *buf, size_t buflen)
+{
+ u8 addr[ETH_ALEN];
+ char *pos, *pos2;
+ char *pin = NULL;
+ enum p2p_wps_method wps_method;
+ int new_pin;
+ int ret;
+ int persistent_group, persistent_id = -1;
+ int join;
+ int auth;
+ int automatic;
+ int go_intent = -1;
+ int freq = 0;
+ int pd;
+ int ht40;
+
+ /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad]
+ * [persistent|persistent=<network id>]
+ * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
+ * [ht40] */
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ pos = cmd + 17;
+ if (*pos != ' ')
+ return -1;
+ pos++;
+
+ persistent_group = os_strstr(pos, " persistent") != NULL;
+ pos2 = os_strstr(pos, " persistent=");
+ if (pos2) {
+ struct wpa_ssid *ssid;
+ persistent_id = atoi(pos2 + 12);
+ ssid = wpa_config_get_network(wpa_s->conf, persistent_id);
+ if (ssid == NULL || ssid->disabled != 2 ||
+ ssid->mode != WPAS_MODE_P2P_GO) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
+ "SSID id=%d for persistent P2P group (GO)",
+ persistent_id);
+ return -1;
+ }
+ }
+ join = os_strstr(pos, " join") != NULL;
+ auth = os_strstr(pos, " auth") != NULL;
+ automatic = os_strstr(pos, " auto") != NULL;
+ pd = os_strstr(pos, " provdisc") != NULL;
+ ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
+
+ pos2 = os_strstr(pos, " go_intent=");
+ if (pos2) {
+ pos2 += 11;
+ go_intent = atoi(pos2);
+ if (go_intent < 0 || go_intent > 15)
+ return -1;
+ }
+
+ pos2 = os_strstr(pos, " freq=");
+ if (pos2) {
+ pos2 += 6;
+ freq = atoi(pos2);
+ if (freq <= 0)
+ return -1;
+ }
+
+ if (os_strncmp(pos, "pin", 3) == 0) {
+ /* Request random PIN (to be displayed) and enable the PIN */
+ wps_method = WPS_PIN_DISPLAY;
+ } else if (os_strncmp(pos, "pbc", 3) == 0) {
+ wps_method = WPS_PBC;
+ } else {
+ pin = pos;
+ pos = os_strchr(pin, ' ');
+ wps_method = WPS_PIN_KEYPAD;
+ if (pos) {
+ *pos++ = '\0';
+ if (os_strncmp(pos, "display", 7) == 0)
+ wps_method = WPS_PIN_DISPLAY;
+ }
+ if (!wps_pin_str_valid(pin)) {
+ os_memcpy(buf, "FAIL-INVALID-PIN\n", 17);
+ return 17;
+ }
+ }
+
+ new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
+ persistent_group, automatic, join,
+ auth, go_intent, freq, persistent_id, pd,
+ ht40);
+ if (new_pin == -2) {
+ os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
+ return 25;
+ }
+ if (new_pin == -3) {
+ os_memcpy(buf, "FAIL-CHANNEL-UNSUPPORTED\n", 25);
+ return 25;
+ }
+ if (new_pin < 0)
+ return -1;
+ if (wps_method == WPS_PIN_DISPLAY && pin == NULL) {
+ ret = os_snprintf(buf, buflen, "%08d", new_pin);
+ if (ret < 0 || (size_t) ret >= buflen)
+ return -1;
+ return ret;
+ }
+
+ os_memcpy(buf, "OK\n", 3);
+ return 3;
+}
+
+
+static int p2p_ctrl_listen(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ unsigned int timeout = atoi(cmd);
+ return wpas_p2p_listen(wpa_s, timeout);
+}
+
+
+static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ char *pos;
+ enum wpas_p2p_prov_disc_use use = WPAS_P2P_PD_FOR_GO_NEG;
+
+ /* <addr> <config method> [join|auto] */
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ pos = cmd + 17;
+ if (*pos != ' ')
+ return -1;
+ pos++;
+
+ if (os_strstr(pos, " join") != NULL)
+ use = WPAS_P2P_PD_FOR_JOIN;
+ else if (os_strstr(pos, " auto") != NULL)
+ use = WPAS_P2P_PD_AUTO;
+
+ return wpas_p2p_prov_disc(wpa_s, addr, pos, use);
+}
+
+
+static int p2p_get_passphrase(struct wpa_supplicant *wpa_s, char *buf,
+ size_t buflen)
+{
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+ if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO ||
+ ssid->passphrase == NULL)
+ return -1;
+
+ os_strlcpy(buf, ssid->passphrase, buflen);
+ return os_strlen(buf);
+}
+
+
+static int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd,
+ char *buf, size_t buflen)
+{
+ u64 ref;
+ int res;
+ u8 dst_buf[ETH_ALEN], *dst;
+ struct wpabuf *tlvs;
+ char *pos;
+ size_t len;
+
+ if (hwaddr_aton(cmd, dst_buf))
+ return -1;
+ dst = dst_buf;
+ if (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 &&
+ dst[3] == 0 && dst[4] == 0 && dst[5] == 0)
+ dst = NULL;
+ pos = cmd + 17;
+ if (*pos != ' ')
+ return -1;
+ pos++;
+
+ if (os_strncmp(pos, "upnp ", 5) == 0) {
+ u8 version;
+ pos += 5;
+ if (hexstr2bin(pos, &version, 1) < 0)
+ return -1;
+ pos += 2;
+ if (*pos != ' ')
+ return -1;
+ pos++;
+ ref = wpas_p2p_sd_request_upnp(wpa_s, dst, version, pos);
+#ifdef CONFIG_WIFI_DISPLAY
+ } else if (os_strncmp(pos, "wifi-display ", 13) == 0) {
+ ref = wpas_p2p_sd_request_wifi_display(wpa_s, dst, pos + 13);
+#endif /* CONFIG_WIFI_DISPLAY */
+ } else {
+ len = os_strlen(pos);
+ if (len & 1)
+ return -1;
+ len /= 2;
+ tlvs = wpabuf_alloc(len);
+ if (tlvs == NULL)
+ return -1;
+ if (hexstr2bin(pos, wpabuf_put(tlvs, len), len) < 0) {
+ wpabuf_free(tlvs);
+ return -1;
+ }
+
+ ref = wpas_p2p_sd_request(wpa_s, dst, tlvs);
+ wpabuf_free(tlvs);
+ }
+ if (ref == 0)
+ return -1;
+ res = os_snprintf(buf, buflen, "%llx", (long long unsigned) ref);
+ if (res < 0 || (unsigned) res >= buflen)
+ return -1;
+ return res;
+}
+
+
+static int p2p_ctrl_serv_disc_cancel_req(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ long long unsigned val;
+ u64 req;
+ if (sscanf(cmd, "%llx", &val) != 1)
+ return -1;
+ req = val;
+ return wpas_p2p_sd_cancel_request(wpa_s, req);
+}
+
+
+static int p2p_ctrl_serv_disc_resp(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ int freq;
+ u8 dst[ETH_ALEN];
+ u8 dialog_token;
+ struct wpabuf *resp_tlvs;
+ char *pos, *pos2;
+ size_t len;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+ freq = atoi(cmd);
+ if (freq == 0)
+ return -1;
+
+ if (hwaddr_aton(pos, dst))
+ return -1;
+ pos += 17;
+ if (*pos != ' ')
+ return -1;
+ pos++;
+
+ pos2 = os_strchr(pos, ' ');
+ if (pos2 == NULL)
+ return -1;
+ *pos2++ = '\0';
+ dialog_token = atoi(pos);
+
+ len = os_strlen(pos2);
+ if (len & 1)
+ return -1;
+ len /= 2;
+ resp_tlvs = wpabuf_alloc(len);
+ if (resp_tlvs == NULL)
+ return -1;
+ if (hexstr2bin(pos2, wpabuf_put(resp_tlvs, len), len) < 0) {
+ wpabuf_free(resp_tlvs);
+ return -1;
+ }
+
+ wpas_p2p_sd_response(wpa_s, freq, dst, dialog_token, resp_tlvs);
+ wpabuf_free(resp_tlvs);
+ return 0;
+}
+
+
+static int p2p_ctrl_serv_disc_external(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ if (os_strcmp(cmd, "0") && os_strcmp(cmd, "1"))
+ return -1;
+ wpa_s->p2p_sd_over_ctrl_iface = atoi(cmd);
+ return 0;
+}
+
+
+static int p2p_ctrl_service_add_bonjour(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ char *pos;
+ size_t len;
+ struct wpabuf *query, *resp;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ len = os_strlen(cmd);
+ if (len & 1)
+ return -1;
+ len /= 2;
+ query = wpabuf_alloc(len);
+ if (query == NULL)
+ return -1;
+ if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
+ wpabuf_free(query);
+ return -1;
+ }
+
+ len = os_strlen(pos);
+ if (len & 1) {
+ wpabuf_free(query);
+ return -1;
+ }
+ len /= 2;
+ resp = wpabuf_alloc(len);
+ if (resp == NULL) {
+ wpabuf_free(query);
+ return -1;
+ }
+ if (hexstr2bin(pos, wpabuf_put(resp, len), len) < 0) {
+ wpabuf_free(query);
+ wpabuf_free(resp);
+ return -1;
+ }
+
+ if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
+ wpabuf_free(query);
+ wpabuf_free(resp);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int p2p_ctrl_service_add_upnp(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ char *pos;
+ u8 version;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ if (hexstr2bin(cmd, &version, 1) < 0)
+ return -1;
+
+ return wpas_p2p_service_add_upnp(wpa_s, version, pos);
+}
+
+
+static int p2p_ctrl_service_add(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ char *pos;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ if (os_strcmp(cmd, "bonjour") == 0)
+ return p2p_ctrl_service_add_bonjour(wpa_s, pos);
+ if (os_strcmp(cmd, "upnp") == 0)
+ return p2p_ctrl_service_add_upnp(wpa_s, pos);
+ wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
+ return -1;
+}
+
+
+static int p2p_ctrl_service_del_bonjour(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ size_t len;
+ struct wpabuf *query;
+ int ret;
+
+ len = os_strlen(cmd);
+ if (len & 1)
+ return -1;
+ len /= 2;
+ query = wpabuf_alloc(len);
+ if (query == NULL)
+ return -1;
+ if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
+ wpabuf_free(query);
+ return -1;
+ }
+
+ ret = wpas_p2p_service_del_bonjour(wpa_s, query);
+ wpabuf_free(query);
+ return ret;
+}
+
+
+static int p2p_ctrl_service_del_upnp(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ char *pos;
+ u8 version;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ if (hexstr2bin(cmd, &version, 1) < 0)
+ return -1;
+
+ return wpas_p2p_service_del_upnp(wpa_s, version, pos);
+}
+
+
+static int p2p_ctrl_service_del(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ char *pos;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ if (os_strcmp(cmd, "bonjour") == 0)
+ return p2p_ctrl_service_del_bonjour(wpa_s, pos);
+ if (os_strcmp(cmd, "upnp") == 0)
+ return p2p_ctrl_service_del_upnp(wpa_s, pos);
+ wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
+ return -1;
+}
+
+
+static int p2p_ctrl_reject(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ u8 addr[ETH_ALEN];
+
+ /* <addr> */
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ return wpas_p2p_reject(wpa_s, addr);
+}
+
+
+static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ char *pos;
+ int id;
+ struct wpa_ssid *ssid;
+ u8 *_peer = NULL, peer[ETH_ALEN];
+ int freq = 0;
+ int ht40;
+
+ id = atoi(cmd);
+ pos = os_strstr(cmd, " peer=");
+ if (pos) {
+ pos += 6;
+ if (hwaddr_aton(pos, peer))
+ return -1;
+ _peer = peer;
+ }
+ ssid = wpa_config_get_network(wpa_s->conf, id);
+ if (ssid == NULL || ssid->disabled != 2) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
+ "for persistent P2P group",
+ id);
+ return -1;
+ }
+
+ pos = os_strstr(cmd, " freq=");
+ if (pos) {
+ pos += 6;
+ freq = atoi(pos);
+ if (freq <= 0)
+ return -1;
+ }
+
+ ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
+
+ return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40);
+}
+
+
+static int p2p_ctrl_invite_group(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ char *pos;
+ u8 peer[ETH_ALEN], go_dev_addr[ETH_ALEN], *go_dev = NULL;
+
+ pos = os_strstr(cmd, " peer=");
+ if (!pos)
+ return -1;
+
+ *pos = '\0';
+ pos += 6;
+ if (hwaddr_aton(pos, peer)) {
+ wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'", pos);
+ return -1;
+ }
+
+ pos = os_strstr(pos, " go_dev_addr=");
+ if (pos) {
+ pos += 13;
+ if (hwaddr_aton(pos, go_dev_addr)) {
+ wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'",
+ pos);
+ return -1;
+ }
+ go_dev = go_dev_addr;
+ }
+
+ return wpas_p2p_invite_group(wpa_s, cmd, peer, go_dev);
+}
+
+
+static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ if (os_strncmp(cmd, "persistent=", 11) == 0)
+ return p2p_ctrl_invite_persistent(wpa_s, cmd + 11);
+ if (os_strncmp(cmd, "group=", 6) == 0)
+ return p2p_ctrl_invite_group(wpa_s, cmd + 6);
+
+ return -1;
+}
+
+
+static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
+ char *cmd, int freq, int ht40)
+{
+ int id;
+ struct wpa_ssid *ssid;
+
+ id = atoi(cmd);
+ ssid = wpa_config_get_network(wpa_s->conf, id);
+ if (ssid == NULL || ssid->disabled != 2) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
+ "for persistent P2P group",
+ id);
+ return -1;
+ }
+
+ return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40);
+}
+
+
+static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ int freq = 0, ht40;
+ char *pos;
+
+ pos = os_strstr(cmd, "freq=");
+ if (pos)
+ freq = atoi(pos + 5);
+
+ ht40 = (os_strstr(cmd, "ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
+
+ if (os_strncmp(cmd, "persistent=", 11) == 0)
+ return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq,
+ ht40);
+ if (os_strcmp(cmd, "persistent") == 0 ||
+ os_strncmp(cmd, "persistent ", 11) == 0)
+ return wpas_p2p_group_add(wpa_s, 1, freq, ht40);
+ if (os_strncmp(cmd, "freq=", 5) == 0)
+ return wpas_p2p_group_add(wpa_s, 0, freq, ht40);
+ if (ht40)
+ return wpas_p2p_group_add(wpa_s, 0, freq, ht40);
+
+ wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameters '%s'",
+ cmd);
+ return -1;
+}
+
+
+static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
+ char *buf, size_t buflen)
+{
+ u8 addr[ETH_ALEN], *addr_ptr;
+ int next, res;
+ const struct p2p_peer_info *info;
+ char *pos, *end;
+ char devtype[WPS_DEV_TYPE_BUFSIZE];
+ struct wpa_ssid *ssid;
+ size_t i;
+
+ if (!wpa_s->global->p2p)
+ return -1;
+
+ if (os_strcmp(cmd, "FIRST") == 0) {
+ addr_ptr = NULL;
+ next = 0;
+ } else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
+ if (hwaddr_aton(cmd + 5, addr) < 0)
+ return -1;
+ addr_ptr = addr;
+ next = 1;
+ } else {
+ if (hwaddr_aton(cmd, addr) < 0)
+ return -1;
+ addr_ptr = addr;
+ next = 0;
+ }
+
+ info = p2p_get_peer_info(wpa_s->global->p2p, addr_ptr, next);
+ if (info == NULL)
+ return -1;
+
+ pos = buf;
+ end = buf + buflen;
+
+ res = os_snprintf(pos, end - pos, MACSTR "\n"
+ "pri_dev_type=%s\n"
+ "device_name=%s\n"
+ "manufacturer=%s\n"
+ "model_name=%s\n"
+ "model_number=%s\n"
+ "serial_number=%s\n"
+ "config_methods=0x%x\n"
+ "dev_capab=0x%x\n"
+ "group_capab=0x%x\n"
+ "level=%d\n",
+ MAC2STR(info->p2p_device_addr),
+ wps_dev_type_bin2str(info->pri_dev_type,
+ devtype, sizeof(devtype)),
+ info->device_name,
+ info->manufacturer,
+ info->model_name,
+ info->model_number,
+ info->serial_number,
+ info->config_methods,
+ info->dev_capab,
+ info->group_capab,
+ info->level);
+ if (res < 0 || res >= end - pos)
+ return pos - buf;
+ pos += res;
+
+ for (i = 0; i < info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN; i++)
+ {
+ const u8 *t;
+ t = &info->wps_sec_dev_type_list[i * WPS_DEV_TYPE_LEN];
+ res = os_snprintf(pos, end - pos, "sec_dev_type=%s\n",
+ wps_dev_type_bin2str(t, devtype,
+ sizeof(devtype)));
+ if (res < 0 || res >= end - pos)
+ return pos - buf;
+ pos += res;
+ }
+
+ ssid = wpas_p2p_get_persistent(wpa_s, info->p2p_device_addr, NULL, 0);
+ if (ssid) {
+ res = os_snprintf(pos, end - pos, "persistent=%d\n", ssid->id);
+ if (res < 0 || res >= end - pos)
+ return pos - buf;
+ pos += res;
+ }
+
+ res = p2p_get_peer_info_txt(info, pos, end - pos);
+ if (res < 0)
+ return pos - buf;
+ pos += res;
+
+ return pos - buf;
+}
+
+
+static int p2p_ctrl_disallow_freq(struct wpa_supplicant *wpa_s,
+ const char *param)
+{
+ struct wpa_freq_range *freq = NULL, *n;
+ unsigned int count = 0, i;
+ const char *pos, *pos2, *pos3;
+
+ if (wpa_s->global->p2p == NULL)
+ return -1;
+
+ /*
+ * param includes comma separated frequency range.
+ * For example: 2412-2432,2462,5000-6000
+ */
+ pos = param;
+ while (pos && pos[0]) {
+ n = os_realloc_array(freq, count + 1,
+ sizeof(struct wpa_freq_range));
+ if (n == NULL) {
+ os_free(freq);
+ return -1;
+ }
+ freq = n;
+ freq[count].min = atoi(pos);
+ pos2 = os_strchr(pos, '-');
+ pos3 = os_strchr(pos, ',');
+ if (pos2 && (!pos3 || pos2 < pos3)) {
+ pos2++;
+ freq[count].max = atoi(pos2);
+ } else
+ freq[count].max = freq[count].min;
+ pos = pos3;
+ if (pos)
+ pos++;
+ count++;
+ }
+
+ for (i = 0; i < count; i++) {
+ wpa_printf(MSG_DEBUG, "P2P: Disallowed frequency range %u-%u",
+ freq[i].min, freq[i].max);
+ }
+
+ os_free(wpa_s->global->p2p_disallow_freq);
+ wpa_s->global->p2p_disallow_freq = freq;
+ wpa_s->global->num_p2p_disallow_freq = count;
+ wpas_p2p_update_channel_list(wpa_s);
+ return 0;
+}
+
+
+static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ char *param;
+
+ if (wpa_s->global->p2p == NULL)
+ return -1;
+
+ param = os_strchr(cmd, ' ');
+ if (param == NULL)
+ return -1;
+ *param++ = '\0';
+
+ if (os_strcmp(cmd, "discoverability") == 0) {
+ p2p_set_client_discoverability(wpa_s->global->p2p,
+ atoi(param));
+ return 0;
+ }
+
+ if (os_strcmp(cmd, "managed") == 0) {
+ p2p_set_managed_oper(wpa_s->global->p2p, atoi(param));
+ return 0;
+ }
+
+ if (os_strcmp(cmd, "listen_channel") == 0) {
+ return p2p_set_listen_channel(wpa_s->global->p2p, 81,
+ atoi(param));
+ }
+
+ if (os_strcmp(cmd, "ssid_postfix") == 0) {
+ return p2p_set_ssid_postfix(wpa_s->global->p2p, (u8 *) param,
+ os_strlen(param));
+ }
+
+ if (os_strcmp(cmd, "noa") == 0) {
+ char *pos;
+ int count, start, duration;
+ /* GO NoA parameters: count,start_offset(ms),duration(ms) */
+ count = atoi(param);
+ pos = os_strchr(param, ',');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ start = atoi(pos);
+ pos = os_strchr(pos, ',');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ duration = atoi(pos);
+ if (count < 0 || count > 255 || start < 0 || duration < 0)
+ return -1;
+ if (count == 0 && duration > 0)
+ return -1;
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: P2P_SET GO NoA: count=%d "
+ "start=%d duration=%d", count, start, duration);
+ return wpas_p2p_set_noa(wpa_s, count, start, duration);
+ }
+
+ if (os_strcmp(cmd, "ps") == 0)
+ return wpa_drv_set_p2p_powersave(wpa_s, atoi(param), -1, -1);
+
+ if (os_strcmp(cmd, "oppps") == 0)
+ return wpa_drv_set_p2p_powersave(wpa_s, -1, atoi(param), -1);
+
+ if (os_strcmp(cmd, "ctwindow") == 0)
+ return wpa_drv_set_p2p_powersave(wpa_s, -1, -1, atoi(param));
+
+ if (os_strcmp(cmd, "disabled") == 0) {
+ wpa_s->global->p2p_disabled = atoi(param);
+ wpa_printf(MSG_DEBUG, "P2P functionality %s",
+ wpa_s->global->p2p_disabled ?
+ "disabled" : "enabled");
+ if (wpa_s->global->p2p_disabled) {
+ wpas_p2p_stop_find(wpa_s);
+ os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
+ p2p_flush(wpa_s->global->p2p);
+ }
+ return 0;
+ }
+
+ if (os_strcmp(cmd, "conc_pref") == 0) {
+ if (os_strcmp(param, "sta") == 0)
+ wpa_s->global->conc_pref = WPA_CONC_PREF_STA;
+ else if (os_strcmp(param, "p2p") == 0)
+ wpa_s->global->conc_pref = WPA_CONC_PREF_P2P;
+ else {
+ wpa_printf(MSG_INFO, "Invalid conc_pref value");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "Single channel concurrency preference: "
+ "%s", param);
+ return 0;
+ }
+
+ if (os_strcmp(cmd, "force_long_sd") == 0) {
+ wpa_s->force_long_sd = atoi(param);
+ return 0;
+ }
+
+ if (os_strcmp(cmd, "peer_filter") == 0) {
+ u8 addr[ETH_ALEN];
+ if (hwaddr_aton(param, addr))
+ return -1;
+ p2p_set_peer_filter(wpa_s->global->p2p, addr);
+ return 0;
+ }
+
+ if (os_strcmp(cmd, "cross_connect") == 0)
+ return wpas_p2p_set_cross_connect(wpa_s, atoi(param));
+
+ if (os_strcmp(cmd, "go_apsd") == 0) {
+ if (os_strcmp(param, "disable") == 0)
+ wpa_s->set_ap_uapsd = 0;
+ else {
+ wpa_s->set_ap_uapsd = 1;
+ wpa_s->ap_uapsd = atoi(param);
+ }
+ return 0;
+ }
+
+ if (os_strcmp(cmd, "client_apsd") == 0) {
+ if (os_strcmp(param, "disable") == 0)
+ wpa_s->set_sta_uapsd = 0;
+ else {
+ int be, bk, vi, vo;
+ char *pos;
+ /* format: BE,BK,VI,VO;max SP Length */
+ be = atoi(param);
+ pos = os_strchr(param, ',');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ bk = atoi(pos);
+ pos = os_strchr(pos, ',');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ vi = atoi(pos);
+ pos = os_strchr(pos, ',');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ vo = atoi(pos);
+ /* ignore max SP Length for now */
+
+ wpa_s->set_sta_uapsd = 1;
+ wpa_s->sta_uapsd = 0;
+ if (be)
+ wpa_s->sta_uapsd |= BIT(0);
+ if (bk)
+ wpa_s->sta_uapsd |= BIT(1);
+ if (vi)
+ wpa_s->sta_uapsd |= BIT(2);
+ if (vo)
+ wpa_s->sta_uapsd |= BIT(3);
+ }
+ return 0;
+ }
+
+ if (os_strcmp(cmd, "disallow_freq") == 0)
+ return p2p_ctrl_disallow_freq(wpa_s, param);
+
+ if (os_strcmp(cmd, "disc_int") == 0) {
+ int min_disc_int, max_disc_int, max_disc_tu;
+ char *pos;
+
+ pos = param;
+
+ min_disc_int = atoi(pos);
+ pos = os_strchr(pos, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ max_disc_int = atoi(pos);
+ pos = os_strchr(pos, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ max_disc_tu = atoi(pos);
+
+ return p2p_set_disc_int(wpa_s->global->p2p, min_disc_int,
+ max_disc_int, max_disc_tu);
+ }
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
+ cmd);
+
+ return -1;
+}
+
+
+static int p2p_ctrl_presence_req(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ char *pos, *pos2;
+ unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
+
+ if (cmd[0]) {
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+ dur1 = atoi(cmd);
+
+ pos2 = os_strchr(pos, ' ');
+ if (pos2)
+ *pos2++ = '\0';
+ int1 = atoi(pos);
+ } else
+ pos2 = NULL;
+
+ if (pos2) {
+ pos = os_strchr(pos2, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+ dur2 = atoi(pos2);
+ int2 = atoi(pos);
+ }
+
+ return wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2);
+}
+
+
+static int p2p_ctrl_ext_listen(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ char *pos;
+ unsigned int period = 0, interval = 0;
+
+ if (cmd[0]) {
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+ period = atoi(cmd);
+ interval = atoi(pos);
+ }
+
+ return wpas_p2p_ext_listen(wpa_s, period, interval);
+}
+
+#endif /* CONFIG_P2P */
+
+
+#ifdef CONFIG_INTERWORKING
+static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst)
+{
+ u8 bssid[ETH_ALEN];
+ struct wpa_bss *bss;
+
+ if (hwaddr_aton(dst, bssid)) {
+ wpa_printf(MSG_DEBUG, "Invalid BSSID '%s'", dst);
+ return -1;
+ }
+
+ bss = wpa_bss_get_bssid(wpa_s, bssid);
+ if (bss == NULL) {
+ wpa_printf(MSG_DEBUG, "Could not find BSS " MACSTR,
+ MAC2STR(bssid));
+ return -1;
+ }
+
+ return interworking_connect(wpa_s, bss);
+}
+
+
+static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
+{
+ u8 dst_addr[ETH_ALEN];
+ int used;
+ char *pos;
+#define MAX_ANQP_INFO_ID 100
+ u16 id[MAX_ANQP_INFO_ID];
+ size_t num_id = 0;
+
+ used = hwaddr_aton2(dst, dst_addr);
+ if (used < 0)
+ return -1;
+ pos = dst + used;
+ while (num_id < MAX_ANQP_INFO_ID) {
+ id[num_id] = atoi(pos);
+ if (id[num_id])
+ num_id++;
+ pos = os_strchr(pos + 1, ',');
+ if (pos == NULL)
+ break;
+ pos++;
+ }
+
+ if (num_id == 0)
+ return -1;
+
+ return anqp_send_req(wpa_s, dst_addr, id, num_id);
+}
+
+
+static int gas_request(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ u8 dst_addr[ETH_ALEN];
+ struct wpabuf *advproto, *query = NULL;
+ int used, ret = -1;
+ char *pos, *end;
+ size_t len;
+
+ used = hwaddr_aton2(cmd, dst_addr);
+ if (used < 0)
+ return -1;
+
+ pos = cmd + used;
+ while (*pos == ' ')
+ pos++;
+
+ /* Advertisement Protocol ID */
+ end = os_strchr(pos, ' ');
+ if (end)
+ len = end - pos;
+ else
+ len = os_strlen(pos);
+ if (len & 0x01)
+ return -1;
+ len /= 2;
+ if (len == 0)
+ return -1;
+ advproto = wpabuf_alloc(len);
+ if (advproto == NULL)
+ return -1;
+ if (hexstr2bin(pos, wpabuf_put(advproto, len), len) < 0)
+ goto fail;
+
+ if (end) {
+ /* Optional Query Request */
+ pos = end + 1;
+ while (*pos == ' ')
+ pos++;
+
+ len = os_strlen(pos);
+ if (len) {
+ if (len & 0x01)
+ goto fail;
+ len /= 2;
+ if (len == 0)
+ goto fail;
+ query = wpabuf_alloc(len);
+ if (query == NULL)
+ goto fail;
+ if (hexstr2bin(pos, wpabuf_put(query, len), len) < 0)
+ goto fail;
+ }
+ }
+
+ ret = gas_send_request(wpa_s, dst_addr, advproto, query);
+
+fail:
+ wpabuf_free(advproto);
+ wpabuf_free(query);
+
+ return ret;
+}
+
+
+static int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf,
+ size_t buflen)
+{
+ u8 addr[ETH_ALEN];
+ int dialog_token;
+ int used;
+ char *pos;
+ size_t resp_len, start, requested_len;
+
+ if (!wpa_s->last_gas_resp)
+ return -1;
+
+ used = hwaddr_aton2(cmd, addr);
+ if (used < 0)
+ return -1;
+
+ pos = cmd + used;
+ while (*pos == ' ')
+ pos++;
+ dialog_token = atoi(pos);
+
+ if (os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) != 0 ||
+ dialog_token != wpa_s->last_gas_dialog_token)
+ return -1;
+
+ resp_len = wpabuf_len(wpa_s->last_gas_resp);
+ start = 0;
+ requested_len = resp_len;
+
+ pos = os_strchr(pos, ' ');
+ if (pos) {
+ start = atoi(pos);
+ if (start > resp_len)
+ return os_snprintf(buf, buflen, "FAIL-Invalid range");
+ pos = os_strchr(pos, ',');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ requested_len = atoi(pos);
+ if (start + requested_len > resp_len)
+ return os_snprintf(buf, buflen, "FAIL-Invalid range");
+ }
+
+ if (requested_len * 2 + 1 > buflen)
+ return os_snprintf(buf, buflen, "FAIL-Too long response");
+
+ return wpa_snprintf_hex(buf, buflen,
+ wpabuf_head_u8(wpa_s->last_gas_resp) + start,
+ requested_len);
+}
+#endif /* CONFIG_INTERWORKING */
+
+
+#ifdef CONFIG_HS20
+
+static int get_hs20_anqp(struct wpa_supplicant *wpa_s, char *dst)
+{
+ u8 dst_addr[ETH_ALEN];
+ int used;
+ char *pos;
+ u32 subtypes = 0;
+
+ used = hwaddr_aton2(dst, dst_addr);
+ if (used < 0)
+ return -1;
+ pos = dst + used;
+ for (;;) {
+ int num = atoi(pos);
+ if (num <= 0 || num > 31)
+ return -1;
+ subtypes |= BIT(num);
+ pos = os_strchr(pos + 1, ',');
+ if (pos == NULL)
+ break;
+ pos++;
+ }
+
+ if (subtypes == 0)
+ return -1;
+
+ return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0);
+}
+
+
+static int hs20_nai_home_realm_list(struct wpa_supplicant *wpa_s,
+ const u8 *addr, const char *realm)
+{
+ u8 *buf;
+ size_t rlen, len;
+ int ret;
+
+ rlen = os_strlen(realm);
+ len = 3 + rlen;
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return -1;
+ buf[0] = 1; /* NAI Home Realm Count */
+ buf[1] = 0; /* Formatted in accordance with RFC 4282 */
+ buf[2] = rlen;
+ os_memcpy(buf + 3, realm, rlen);
+
+ ret = hs20_anqp_send_req(wpa_s, addr,
+ BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
+ buf, len);
+
+ os_free(buf);
+
+ return ret;
+}
+
+
+static int hs20_get_nai_home_realm_list(struct wpa_supplicant *wpa_s,
+ char *dst)
+{
+ struct wpa_cred *cred = wpa_s->conf->cred;
+ u8 dst_addr[ETH_ALEN];
+ int used;
+ u8 *buf;
+ size_t len;
+ int ret;
+
+ used = hwaddr_aton2(dst, dst_addr);
+ if (used < 0)
+ return -1;
+
+ while (dst[used] == ' ')
+ used++;
+ if (os_strncmp(dst + used, "realm=", 6) == 0)
+ return hs20_nai_home_realm_list(wpa_s, dst_addr,
+ dst + used + 6);
+
+ len = os_strlen(dst + used);
+
+ if (len == 0 && cred && cred->realm)
+ return hs20_nai_home_realm_list(wpa_s, dst_addr, cred->realm);
+
+ if (len % 1)
+ return -1;
+ len /= 2;
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return -1;
+ if (hexstr2bin(dst + used, buf, len) < 0) {
+ os_free(buf);
+ return -1;
+ }
+
+ ret = hs20_anqp_send_req(wpa_s, dst_addr,
+ BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
+ buf, len);
+ os_free(buf);
+
+ return ret;
+}
+
+#endif /* CONFIG_HS20 */
+
+
+static int wpa_supplicant_ctrl_iface_sta_autoconnect(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ wpa_s->auto_reconnect_disabled = atoi(cmd) == 0 ? 1 : 0;
+ return 0;
+}
+
+
+#ifdef CONFIG_AUTOSCAN
+
+static int wpa_supplicant_ctrl_iface_autoscan(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ enum wpa_states state = wpa_s->wpa_state;
+ char *new_params = NULL;
+
+ if (os_strlen(cmd) > 0) {
+ new_params = os_strdup(cmd);
+ if (new_params == NULL)
+ return -1;
+ }
+
+ os_free(wpa_s->conf->autoscan);
+ wpa_s->conf->autoscan = new_params;
+
+ if (wpa_s->conf->autoscan == NULL)
+ autoscan_deinit(wpa_s);
+ else if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
+ autoscan_init(wpa_s, 1);
+ else if (state == WPA_SCANNING)
+ wpa_supplicant_reinit_autoscan(wpa_s);
+
+ return 0;
+}
+
+#endif /* CONFIG_AUTOSCAN */
+
+
+#ifdef CONFIG_WNM
+
+static int wpas_ctrl_iface_wnm_sleep(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ int enter;
+ int intval = 0;
+ char *pos;
+ int ret;
+ struct wpabuf *tfs_req = NULL;
+
+ if (os_strncmp(cmd, "enter", 5) == 0)
+ enter = 1;
+ else if (os_strncmp(cmd, "exit", 4) == 0)
+ enter = 0;
+ else
+ return -1;
+
+ pos = os_strstr(cmd, " interval=");
+ if (pos)
+ intval = atoi(pos + 10);
+
+ pos = os_strstr(cmd, " tfs_req=");
+ if (pos) {
+ char *end;
+ size_t len;
+ pos += 9;
+ end = os_strchr(pos, ' ');
+ if (end)
+ len = end - pos;
+ else
+ len = os_strlen(pos);
+ if (len & 1)
+ return -1;
+ len /= 2;
+ tfs_req = wpabuf_alloc(len);
+ if (tfs_req == NULL)
+ return -1;
+ if (hexstr2bin(pos, wpabuf_put(tfs_req, len), len) < 0) {
+ wpabuf_free(tfs_req);
+ return -1;
+ }
+ }
+
+ ret = ieee802_11_send_wnmsleep_req(wpa_s, enter ? WNM_SLEEP_MODE_ENTER :
+ WNM_SLEEP_MODE_EXIT, intval,
+ tfs_req);
+ wpabuf_free(tfs_req);
+
+ return ret;
+}
+
+#endif /* CONFIG_WNM */
+
+
+static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
+ size_t buflen)
+{
+ struct wpa_signal_info si;
+ int ret;
+
+ ret = wpa_drv_signal_poll(wpa_s, &si);
+ if (ret)
+ return -1;
+
+ ret = os_snprintf(buf, buflen, "RSSI=%d\nLINKSPEED=%d\n"
+ "NOISE=%d\nFREQUENCY=%u\n",
+ si.current_signal, si.current_txrate / 1000,
+ si.current_noise, si.frequency);
+ if (ret < 0 || (unsigned int) ret > buflen)
+ return -1;
+ return ret;
+}
+
+
+static int wpa_supplicant_pktcnt_poll(struct wpa_supplicant *wpa_s, char *buf,
+ size_t buflen)
+{
+ struct hostap_sta_driver_data sta;
+ int ret;
+
+ ret = wpa_drv_pktcnt_poll(wpa_s, &sta);
+ if (ret)
+ return -1;
+
+ ret = os_snprintf(buf, buflen, "TXGOOD=%lu\nTXBAD=%lu\nRXGOOD=%lu\n",
+ sta.tx_packets, sta.tx_retry_failed, sta.rx_packets);
+ if (ret < 0 || (size_t) ret > buflen)
+ return -1;
+ return ret;
}
@@ -1692,17 +4784,23 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
char *buf, size_t *resp_len)
{
char *reply;
- const int reply_size = 2048;
+ const int reply_size = 4096;
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) {
+ os_strncmp(buf, "SET_NETWORK ", 12) == 0 ||
+ os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 ||
+ os_strncmp(buf, "NFC_RX_HANDOVER_SEL", 19) == 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",
+ int level = MSG_DEBUG;
+ if (os_strcmp(buf, "PING") == 0)
+ level = MSG_EXCESSIVE;
+ wpa_hexdump_ascii(level, "RX ctrl_iface",
(const u8 *) buf, os_strlen(buf));
+ wpa_dbg(wpa_s, level, "Control interface command '%s'", buf);
}
reply = os_malloc(reply_size);
@@ -1717,6 +4815,14 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (os_strcmp(buf, "PING") == 0) {
os_memcpy(reply, "PONG\n", 5);
reply_len = 5;
+ } else if (os_strcmp(buf, "IFNAME") == 0) {
+ reply_len = os_strlen(wpa_s->ifname);
+ os_memcpy(reply, wpa_s->ifname, reply_len);
+ } else if (os_strncmp(buf, "RELOG", 5) == 0) {
+ if (wpa_debug_reopen_file() < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "NOTE ", 5) == 0) {
+ wpa_printf(MSG_INFO, "NOTE: %s", buf + 5);
} else if (os_strcmp(buf, "MIB") == 0) {
reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
if (reply_len >= 0) {
@@ -1737,20 +4843,23 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "SET ", 4) == 0) {
if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
reply_len = -1;
+ } else if (os_strncmp(buf, "GET ", 4) == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_get(wpa_s, buf + 4,
+ reply, reply_size);
} 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);
+ if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
+ reply_len = -1;
+ else
+ wpas_request_connection(wpa_s);
} 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);
- }
+ if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
+ reply_len = -1;
+ else if (wpa_s->disconnected)
+ wpas_request_connection(wpa_s);
#ifdef IEEE8021X_EAPOL
} else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
@@ -1768,26 +4877,70 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_WPS
} else if (os_strcmp(buf, "WPS_PBC") == 0) {
- if (wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, NULL))
+ int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, NULL);
+ if (res == -2) {
+ os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
+ reply_len = 17;
+ } else if (res)
reply_len = -1;
} else if (os_strncmp(buf, "WPS_PBC ", 8) == 0) {
- if (wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, buf + 8))
+ int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, buf + 8);
+ if (res == -2) {
+ os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
+ reply_len = 17;
+ } else if (res)
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);
-#ifdef CONFIG_WPS_OOB
- } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
- if (wpa_supplicant_ctrl_iface_wps_oob(wpa_s, buf + 8))
+ } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_wps_check_pin(
+ wpa_s, buf + 14, reply, reply_size);
+ } else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
+ if (wpas_wps_cancel(wpa_s))
+ reply_len = -1;
+#ifdef CONFIG_WPS_NFC
+ } else if (os_strcmp(buf, "WPS_NFC") == 0) {
+ if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, NULL))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "WPS_NFC ", 8) == 0) {
+ if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, buf + 8))
reply_len = -1;
-#endif /* CONFIG_WPS_OOB */
+ } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_wps_nfc_token(
+ wpa_s, buf + 14, reply, reply_size);
+ } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
+ if (wpa_supplicant_ctrl_iface_wps_nfc_tag_read(wpa_s,
+ buf + 17))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "NFC_GET_HANDOVER_REQ ", 21) == 0) {
+ reply_len = wpas_ctrl_nfc_get_handover_req(
+ wpa_s, buf + 21, reply, reply_size);
+ } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
+ reply_len = wpas_ctrl_nfc_get_handover_sel(
+ wpa_s, buf + 21, reply, reply_size);
+ } else if (os_strncmp(buf, "NFC_RX_HANDOVER_REQ ", 20) == 0) {
+ reply_len = wpas_ctrl_nfc_rx_handover_req(
+ wpa_s, buf + 20, reply, reply_size);
+ } else if (os_strncmp(buf, "NFC_RX_HANDOVER_SEL ", 20) == 0) {
+ if (wpas_ctrl_nfc_rx_handover_sel(wpa_s, buf + 20))
+ reply_len = -1;
+#endif /* CONFIG_WPS_NFC */
} else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
reply_len = -1;
+#ifdef CONFIG_AP
+ } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_wps_ap_pin(
+ wpa_s, buf + 11, reply, reply_size);
+#endif /* CONFIG_AP */
#ifdef CONFIG_WPS_ER
} else if (os_strcmp(buf, "WPS_ER_START") == 0) {
- if (wpas_wps_er_start(wpa_s))
+ if (wpas_wps_er_start(wpa_s, NULL))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "WPS_ER_START ", 13) == 0) {
+ if (wpas_wps_er_start(wpa_s, buf + 13))
reply_len = -1;
} else if (os_strcmp(buf, "WPS_ER_STOP") == 0) {
if (wpas_wps_er_stop(wpa_s))
@@ -1796,11 +4949,33 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (wpa_supplicant_ctrl_iface_wps_er_pin(wpa_s, buf + 11))
reply_len = -1;
} else if (os_strncmp(buf, "WPS_ER_PBC ", 11) == 0) {
- if (wpas_wps_er_pbc(wpa_s, buf + 11))
+ int ret = wpas_wps_er_pbc(wpa_s, buf + 11);
+ if (ret == -2) {
+ os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
+ reply_len = 17;
+ } else if (ret == -3) {
+ os_memcpy(reply, "FAIL-UNKNOWN-UUID\n", 18);
+ reply_len = 18;
+ } else if (ret == -4) {
+ os_memcpy(reply, "FAIL-NO-AP-SETTINGS\n", 20);
+ reply_len = 20;
+ } else if (ret)
reply_len = -1;
} else if (os_strncmp(buf, "WPS_ER_LEARN ", 13) == 0) {
if (wpa_supplicant_ctrl_iface_wps_er_learn(wpa_s, buf + 13))
reply_len = -1;
+ } else if (os_strncmp(buf, "WPS_ER_SET_CONFIG ", 18) == 0) {
+ if (wpa_supplicant_ctrl_iface_wps_er_set_config(wpa_s,
+ buf + 18))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "WPS_ER_CONFIG ", 14) == 0) {
+ if (wpa_supplicant_ctrl_iface_wps_er_config(wpa_s, buf + 14))
+ reply_len = -1;
+#ifdef CONFIG_WPS_NFC
+ } else if (os_strncmp(buf, "WPS_ER_NFC_CONFIG_TOKEN ", 24) == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_wps_er_nfc_config_token(
+ wpa_s, buf + 24, reply, reply_size);
+#endif /* CONFIG_WPS_NFC */
#endif /* CONFIG_WPS_ER */
#endif /* CONFIG_WPS */
#ifdef CONFIG_IBSS_RSN
@@ -1808,6 +4983,135 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (wpa_supplicant_ctrl_iface_ibss_rsn(wpa_s, buf + 9))
reply_len = -1;
#endif /* CONFIG_IBSS_RSN */
+#ifdef CONFIG_P2P
+ } else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
+ if (p2p_ctrl_find(wpa_s, buf + 9))
+ reply_len = -1;
+ } else if (os_strcmp(buf, "P2P_FIND") == 0) {
+ if (p2p_ctrl_find(wpa_s, ""))
+ reply_len = -1;
+ } else if (os_strcmp(buf, "P2P_STOP_FIND") == 0) {
+ wpas_p2p_stop_find(wpa_s);
+ } else if (os_strncmp(buf, "P2P_CONNECT ", 12) == 0) {
+ reply_len = p2p_ctrl_connect(wpa_s, buf + 12, reply,
+ reply_size);
+ } else if (os_strncmp(buf, "P2P_LISTEN ", 11) == 0) {
+ if (p2p_ctrl_listen(wpa_s, buf + 11))
+ reply_len = -1;
+ } else if (os_strcmp(buf, "P2P_LISTEN") == 0) {
+ if (p2p_ctrl_listen(wpa_s, ""))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "P2P_GROUP_REMOVE ", 17) == 0) {
+ if (wpas_p2p_group_remove(wpa_s, buf + 17))
+ reply_len = -1;
+ } else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) {
+ if (wpas_p2p_group_add(wpa_s, 0, 0, 0))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
+ if (p2p_ctrl_group_add(wpa_s, buf + 14))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "P2P_PROV_DISC ", 14) == 0) {
+ if (p2p_ctrl_prov_disc(wpa_s, buf + 14))
+ reply_len = -1;
+ } else if (os_strcmp(buf, "P2P_GET_PASSPHRASE") == 0) {
+ reply_len = p2p_get_passphrase(wpa_s, reply, reply_size);
+ } else if (os_strncmp(buf, "P2P_SERV_DISC_REQ ", 18) == 0) {
+ reply_len = p2p_ctrl_serv_disc_req(wpa_s, buf + 18, reply,
+ reply_size);
+ } else if (os_strncmp(buf, "P2P_SERV_DISC_CANCEL_REQ ", 25) == 0) {
+ if (p2p_ctrl_serv_disc_cancel_req(wpa_s, buf + 25) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "P2P_SERV_DISC_RESP ", 19) == 0) {
+ if (p2p_ctrl_serv_disc_resp(wpa_s, buf + 19) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "P2P_SERVICE_UPDATE") == 0) {
+ wpas_p2p_sd_service_update(wpa_s);
+ } else if (os_strncmp(buf, "P2P_SERV_DISC_EXTERNAL ", 23) == 0) {
+ if (p2p_ctrl_serv_disc_external(wpa_s, buf + 23) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "P2P_SERVICE_FLUSH") == 0) {
+ wpas_p2p_service_flush(wpa_s);
+ } else if (os_strncmp(buf, "P2P_SERVICE_ADD ", 16) == 0) {
+ if (p2p_ctrl_service_add(wpa_s, buf + 16) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "P2P_SERVICE_DEL ", 16) == 0) {
+ if (p2p_ctrl_service_del(wpa_s, buf + 16) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "P2P_REJECT ", 11) == 0) {
+ if (p2p_ctrl_reject(wpa_s, buf + 11) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "P2P_INVITE ", 11) == 0) {
+ if (p2p_ctrl_invite(wpa_s, buf + 11) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "P2P_PEER ", 9) == 0) {
+ reply_len = p2p_ctrl_peer(wpa_s, buf + 9, reply,
+ reply_size);
+ } else if (os_strncmp(buf, "P2P_SET ", 8) == 0) {
+ if (p2p_ctrl_set(wpa_s, buf + 8) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "P2P_FLUSH") == 0) {
+ os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
+ wpa_s->force_long_sd = 0;
+ if (wpa_s->global->p2p)
+ p2p_flush(wpa_s->global->p2p);
+ } else if (os_strncmp(buf, "P2P_UNAUTHORIZE ", 16) == 0) {
+ if (wpas_p2p_unauthorize(wpa_s, buf + 16) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "P2P_CANCEL") == 0) {
+ if (wpas_p2p_cancel(wpa_s))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "P2P_PRESENCE_REQ ", 17) == 0) {
+ if (p2p_ctrl_presence_req(wpa_s, buf + 17) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "P2P_PRESENCE_REQ") == 0) {
+ if (p2p_ctrl_presence_req(wpa_s, "") < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "P2P_EXT_LISTEN ", 15) == 0) {
+ if (p2p_ctrl_ext_listen(wpa_s, buf + 15) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "P2P_EXT_LISTEN") == 0) {
+ if (p2p_ctrl_ext_listen(wpa_s, "") < 0)
+ reply_len = -1;
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_WIFI_DISPLAY
+ } else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) {
+ if (wifi_display_subelem_set(wpa_s->global, buf + 16) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0) {
+ reply_len = wifi_display_subelem_get(wpa_s->global, buf + 16,
+ reply, reply_size);
+#endif /* CONFIG_WIFI_DISPLAY */
+#ifdef CONFIG_INTERWORKING
+ } else if (os_strcmp(buf, "FETCH_ANQP") == 0) {
+ if (interworking_fetch_anqp(wpa_s) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "STOP_FETCH_ANQP") == 0) {
+ interworking_stop_fetch_anqp(wpa_s);
+ } else if (os_strncmp(buf, "INTERWORKING_SELECT", 19) == 0) {
+ if (interworking_select(wpa_s, os_strstr(buf + 19, "auto") !=
+ NULL) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) {
+ if (ctrl_interworking_connect(wpa_s, buf + 21) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "ANQP_GET ", 9) == 0) {
+ if (get_anqp(wpa_s, buf + 9) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "GAS_REQUEST ", 12) == 0) {
+ if (gas_request(wpa_s, buf + 12) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "GAS_RESPONSE_GET ", 17) == 0) {
+ reply_len = gas_response_get(wpa_s, buf + 17, reply,
+ reply_size);
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+ } else if (os_strncmp(buf, "HS20_ANQP_GET ", 14) == 0) {
+ if (get_hs20_anqp(wpa_s, buf + 14) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "HS20_GET_NAI_HOME_REALM_LIST ", 29) == 0) {
+ if (hs20_get_nai_home_realm_list(wpa_s, buf + 29) < 0)
+ reply_len = -1;
+#endif /* CONFIG_HS20 */
} else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
{
if (wpa_supplicant_ctrl_iface_ctrl_rsp(
@@ -1823,17 +5127,49 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "BSSID ", 6) == 0) {
if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6))
reply_len = -1;
+ } else if (os_strncmp(buf, "BLACKLIST", 9) == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_blacklist(
+ wpa_s, buf + 9, reply, reply_size);
+ } else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_log_level(
+ wpa_s, buf + 9, reply, reply_size);
} 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) {
+#ifdef CONFIG_SME
+ wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
wpa_s->reassociate = 0;
wpa_s->disconnected = 1;
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_supplicant_cancel_scan(wpa_s);
wpa_supplicant_deauthenticate(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);
+ if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
+ reply_len = -1;
+ else {
+ if (!wpa_s->sched_scanning && !wpa_s->scanning &&
+ ((wpa_s->wpa_state <= WPA_SCANNING) ||
+ (wpa_s->wpa_state == WPA_COMPLETED))) {
+ wpa_s->normal_scans = 0;
+ wpa_s->scan_req = MANUAL_SCAN_REQ;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ } else if (wpa_s->sched_scanning) {
+ wpa_printf(MSG_DEBUG, "Stop ongoing "
+ "sched_scan to allow requested "
+ "full scan to proceed");
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_s->scan_req = MANUAL_SCAN_REQ;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ } else {
+ wpa_printf(MSG_DEBUG, "Ongoing scan action - "
+ "reject new request");
+ reply_len = os_snprintf(reply, reply_size,
+ "FAIL-BUSY\n");
+ }
+ }
} else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
reply_len = wpa_supplicant_ctrl_iface_scan_results(
wpa_s, reply, reply_size);
@@ -1858,6 +5194,18 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) {
reply_len = wpa_supplicant_ctrl_iface_get_network(
wpa_s, buf + 12, reply, reply_size);
+ } else if (os_strcmp(buf, "LIST_CREDS") == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_list_creds(
+ wpa_s, reply, reply_size);
+ } else if (os_strcmp(buf, "ADD_CRED") == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_add_cred(
+ wpa_s, reply, reply_size);
+ } else if (os_strncmp(buf, "REMOVE_CRED ", 12) == 0) {
+ if (wpa_supplicant_ctrl_iface_remove_cred(wpa_s, buf + 12))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "SET_CRED ", 9) == 0) {
+ if (wpa_supplicant_ctrl_iface_set_cred(wpa_s, buf + 9))
+ reply_len = -1;
#ifndef CONFIG_NO_CONFIG_WRITE
} else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
if (wpa_supplicant_ctrl_iface_save_config(wpa_s))
@@ -1869,6 +5217,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} 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_strncmp(buf, "SCAN_INTERVAL ", 14) == 0) {
+ if (wpa_supplicant_ctrl_iface_scan_interval(wpa_s, buf + 14))
+ reply_len = -1;
} else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
reply_len = wpa_supplicant_global_iface_list(
wpa_s->global, reply, reply_size);
@@ -1887,6 +5238,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply,
reply_size);
+ } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
+ if (ap_ctrl_iface_sta_deauthenticate(wpa_s, buf + 15))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
+ if (ap_ctrl_iface_sta_disassociate(wpa_s, buf + 13))
+ reply_len = -1;
#endif /* CONFIG_AP */
} else if (os_strcmp(buf, "SUSPEND") == 0) {
wpas_notify_suspend(wpa_s->global);
@@ -1897,6 +5254,49 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "ROAM ", 5) == 0) {
if (wpa_supplicant_ctrl_iface_roam(wpa_s, buf + 5))
reply_len = -1;
+ } else if (os_strncmp(buf, "STA_AUTOCONNECT ", 16) == 0) {
+ if (wpa_supplicant_ctrl_iface_sta_autoconnect(wpa_s, buf + 16))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "BSS_EXPIRE_AGE ", 15) == 0) {
+ if (wpa_supplicant_ctrl_iface_bss_expire_age(wpa_s, buf + 15))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "BSS_EXPIRE_COUNT ", 17) == 0) {
+ if (wpa_supplicant_ctrl_iface_bss_expire_count(wpa_s,
+ buf + 17))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "BSS_FLUSH ", 10) == 0) {
+ if (wpa_supplicant_ctrl_iface_bss_flush(wpa_s, buf + 10))
+ reply_len = -1;
+#ifdef CONFIG_TDLS
+ } else if (os_strncmp(buf, "TDLS_DISCOVER ", 14) == 0) {
+ if (wpa_supplicant_ctrl_iface_tdls_discover(wpa_s, buf + 14))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "TDLS_SETUP ", 11) == 0) {
+ if (wpa_supplicant_ctrl_iface_tdls_setup(wpa_s, buf + 11))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "TDLS_TEARDOWN ", 14) == 0) {
+ if (wpa_supplicant_ctrl_iface_tdls_teardown(wpa_s, buf + 14))
+ reply_len = -1;
+#endif /* CONFIG_TDLS */
+ } else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) {
+ reply_len = wpa_supplicant_signal_poll(wpa_s, reply,
+ reply_size);
+ } else if (os_strncmp(buf, "PKTCNT_POLL", 11) == 0) {
+ reply_len = wpa_supplicant_pktcnt_poll(wpa_s, reply,
+ reply_size);
+#ifdef CONFIG_AUTOSCAN
+ } else if (os_strncmp(buf, "AUTOSCAN ", 9) == 0) {
+ if (wpa_supplicant_ctrl_iface_autoscan(wpa_s, buf + 9))
+ reply_len = -1;
+#endif /* CONFIG_AUTOSCAN */
+ } else if (os_strcmp(buf, "REAUTHENTICATE") == 0) {
+ pmksa_cache_clear_current(wpa_s->wpa);
+ eapol_sm_request_reauth(wpa_s->eapol);
+#ifdef CONFIG_WNM
+ } else if (os_strncmp(buf, "WNM_SLEEP ", 10) == 0) {
+ if (wpas_ctrl_iface_wnm_sleep(wpa_s, buf + 10))
+ reply_len = -1;
+#endif /* CONFIG_WNM */
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
@@ -2002,7 +5402,7 @@ static int wpa_supplicant_global_iface_remove(struct wpa_global *global,
wpa_s = wpa_supplicant_get_iface(global, cmd);
if (wpa_s == NULL)
return -1;
- return wpa_supplicant_remove_iface(global, wpa_s);
+ return wpa_supplicant_remove_iface(global, wpa_s, 0);
}
@@ -2093,8 +5493,11 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
char *reply;
const int reply_size = 2048;
int reply_len;
+ int level = MSG_DEBUG;
- wpa_hexdump_ascii(MSG_DEBUG, "RX global ctrl_iface",
+ if (os_strcmp(buf, "PING") == 0)
+ level = MSG_EXCESSIVE;
+ wpa_hexdump_ascii(level, "RX global ctrl_iface",
(const u8 *) buf, os_strlen(buf));
reply = os_malloc(reply_size);
diff --git a/wpa_supplicant/ctrl_iface.h b/wpa_supplicant/ctrl_iface.h
index 051d99a67dc6..a329ef32a239 100644
--- a/wpa_supplicant/ctrl_iface.h
+++ b/wpa_supplicant/ctrl_iface.h
@@ -2,14 +2,8 @@
* 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef CTRL_IFACE_H
diff --git a/wpa_supplicant/ctrl_iface_named_pipe.c b/wpa_supplicant/ctrl_iface_named_pipe.c
index 5f7e24de7943..fd417ff5178d 100644
--- a/wpa_supplicant/ctrl_iface_named_pipe.c
+++ b/wpa_supplicant/ctrl_iface_named_pipe.c
@@ -2,14 +2,8 @@
* 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c
index 110ca4f677d9..994f9b18c091 100644
--- a/wpa_supplicant/ctrl_iface_udp.c
+++ b/wpa_supplicant/ctrl_iface_udp.c
@@ -2,14 +2,8 @@
* 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -169,6 +163,8 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
perror("recvfrom(ctrl_iface)");
return;
}
+
+#ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
/*
* The OS networking stack is expected to drop this kind of
@@ -180,6 +176,8 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
"source %s", inet_ntoa(from.sin_addr));
return;
}
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
buf[res] = '\0';
if (os_strcmp(buf, "GET_COOKIE") == 0) {
@@ -272,6 +270,7 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
{
struct ctrl_iface_priv *priv;
struct sockaddr_in addr;
+ int port = WPA_CTRL_IFACE_PORT;
priv = os_zalloc(sizeof(*priv));
if (priv == NULL)
@@ -291,13 +290,25 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
os_memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ addr.sin_addr.s_addr = INADDR_ANY;
+#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
addr.sin_addr.s_addr = htonl((127 << 24) | 1);
- addr.sin_port = htons(WPA_CTRL_IFACE_PORT);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+try_again:
+ addr.sin_port = htons(port);
if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ port--;
+ if ((WPA_CTRL_IFACE_PORT - port) < WPA_CTRL_IFACE_PORT_LIMIT)
+ goto try_again;
perror("bind(AF_INET)");
goto fail;
}
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ wpa_msg(wpa_s, MSG_DEBUG, "ctrl_iface_init UDP port: %d", port);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,
wpa_s, priv);
wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
@@ -448,6 +459,8 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
perror("recvfrom(ctrl_iface)");
return;
}
+
+#ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
/*
* The OS networking stack is expected to drop this kind of
@@ -459,6 +472,8 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
"source %s", inet_ntoa(from.sin_addr));
return;
}
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
buf[res] = '\0';
if (os_strcmp(buf, "GET_COOKIE") == 0) {
@@ -508,6 +523,7 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
{
struct ctrl_iface_global_priv *priv;
struct sockaddr_in addr;
+ int port = WPA_GLOBAL_CTRL_IFACE_PORT;
priv = os_zalloc(sizeof(*priv));
if (priv == NULL)
@@ -529,13 +545,26 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
os_memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ addr.sin_addr.s_addr = INADDR_ANY;
+#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
addr.sin_addr.s_addr = htonl((127 << 24) | 1);
- addr.sin_port = htons(WPA_GLOBAL_CTRL_IFACE_PORT);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+try_again:
+ addr.sin_port = htons(port);
if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ port++;
+ if ((port - WPA_GLOBAL_CTRL_IFACE_PORT) <
+ WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT)
+ goto try_again;
perror("bind(AF_INET)");
goto fail;
}
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ wpa_printf(MSG_DEBUG, "global_ctrl_iface_init UDP port: %d", port);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
eloop_register_read_sock(priv->sock,
wpa_supplicant_global_ctrl_iface_receive,
global, priv);
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index 84ac760886e6..f79286369755 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -2,14 +2,8 @@
* WPA Supplicant / UNIX domain socket -based control interface
* 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -17,6 +11,11 @@
#include <sys/stat.h>
#include <grp.h>
#include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
+#ifdef ANDROID
+#include <cutils/sockets.h>
+#endif /* ANDROID */
#include "utils/common.h"
#include "utils/eloop.h"
@@ -132,7 +131,7 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
{
struct wpa_supplicant *wpa_s = eloop_ctx;
struct ctrl_iface_priv *priv = sock_ctx;
- char buf[256];
+ char buf[4096];
int res;
struct sockaddr_un from;
socklen_t fromlen = sizeof(from);
@@ -262,6 +261,7 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
char *buf, *dir = NULL, *gid_str = NULL;
struct group *grp;
char *endp;
+ int flags;
priv = os_zalloc(sizeof(*priv));
if (priv == NULL)
@@ -276,6 +276,13 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
buf = os_strdup(wpa_s->conf->ctrl_interface);
if (buf == NULL)
goto fail;
+#ifdef ANDROID
+ os_snprintf(addr.sun_path, sizeof(addr.sun_path), "wpa_%s",
+ wpa_s->conf->ctrl_interface);
+ priv->sock = android_get_control_socket(addr.sun_path);
+ if (priv->sock >= 0)
+ goto havesock;
+#endif /* ANDROID */
if (os_strncmp(buf, "DIR=", 4) == 0) {
dir = buf + 4;
gid_str = os_strstr(dir, " GROUP=");
@@ -298,6 +305,22 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
}
}
+#ifdef ANDROID
+ /*
+ * wpa_supplicant is started from /init.*.rc on Android and that seems
+ * to be using umask 0077 which would leave the control interface
+ * directory without group access. This breaks things since Wi-Fi
+ * framework assumes that this directory can be accessed by other
+ * applications in the wifi group. Fix this by adding group access even
+ * if umask value would prevent this.
+ */
+ if (chmod(dir, S_IRWXU | S_IRWXG) < 0) {
+ wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s",
+ strerror(errno));
+ /* Try to continue anyway */
+ }
+#endif /* ANDROID */
+
if (gid_str) {
grp = getgrnam(gid_str);
if (grp) {
@@ -371,7 +394,7 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
}
if (bind(priv->sock, (struct sockaddr *) &addr,
sizeof(addr)) < 0) {
- perror("bind(PF_UNIX)");
+ perror("supp-ctrl-iface-init: bind(PF_UNIX)");
goto fail;
}
wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
@@ -398,6 +421,23 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
}
os_free(fname);
+#ifdef ANDROID
+havesock:
+#endif /* ANDROID */
+
+ /*
+ * Make socket non-blocking so that we don't hang forever if
+ * target dies unexpectedly.
+ */
+ flags = fcntl(priv->sock, F_GETFL);
+ if (flags >= 0) {
+ flags |= O_NONBLOCK;
+ if (fcntl(priv->sock, F_SETFL, flags) < 0) {
+ perror("fcntl(ctrl, O_NONBLOCK)");
+ /* Not fatal, continue on.*/
+ }
+ }
+
eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,
wpa_s, priv);
wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
@@ -637,6 +677,12 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
if (global->params.ctrl_interface == NULL)
return priv;
+#ifdef ANDROID
+ priv->sock = android_get_control_socket(global->params.ctrl_interface);
+ if (priv->sock >= 0)
+ goto havesock;
+#endif /* ANDROID */
+
wpa_printf(MSG_DEBUG, "Global control interface '%s'",
global->params.ctrl_interface);
@@ -654,7 +700,8 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
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)");
+ perror("supp-global-ctrl-iface-init (will try fixup): "
+ "bind(PF_UNIX)");
if (connect(priv->sock, (struct sockaddr *) &addr,
sizeof(addr)) < 0) {
wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
@@ -669,7 +716,7 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
}
if (bind(priv->sock, (struct sockaddr *) &addr,
sizeof(addr)) < 0) {
- perror("bind(PF_UNIX)");
+ perror("supp-glb-iface-init: bind(PF_UNIX)");
goto fail;
}
wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
@@ -685,6 +732,9 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
}
}
+#ifdef ANDROID
+havesock:
+#endif /* ANDROID */
eloop_register_read_sock(priv->sock,
wpa_supplicant_global_ctrl_iface_receive,
global, NULL);
diff --git a/wpa_supplicant/dbus/Makefile b/wpa_supplicant/dbus/Makefile
index cfaf58d3ecf9..d64c65ca2f6c 100644
--- a/wpa_supplicant/dbus/Makefile
+++ b/wpa_supplicant/dbus/Makefile
@@ -15,6 +15,7 @@ ifndef CFLAGS
CFLAGS = -MMD -O2 -Wall -g
endif
+PKG_CONFIG ?= pkg-config
CFLAGS += -I../../src -I../../src/utils
@@ -38,10 +39,10 @@ CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_NEW
CFLAGS += -DCONFIG_CTRL_IFACE_DBUS
ifndef DBUS_LIBS
-DBUS_LIBS := $(shell pkg-config --libs dbus-1)
+DBUS_LIBS := $(shell $(PKG_CONFIG) --libs dbus-1)
endif
ifndef DBUS_INCLUDE
-DBUS_INCLUDE := $(shell pkg-config --cflags dbus-1)
+DBUS_INCLUDE := $(shell $(PKG_CONFIG) --cflags dbus-1)
endif
ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO
@@ -49,18 +50,6 @@ DBUS_INCLUDE += $(shell xml2-config --cflags)
DBUS_LIBS += $(shell xml2-config --libs)
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)
LIB_OBJS= \
diff --git a/wpa_supplicant/dbus/dbus_common.c b/wpa_supplicant/dbus/dbus_common.c
index 5850636d2e21..5d0e31e276c7 100644
--- a/wpa_supplicant/dbus/dbus_common.c
+++ b/wpa_supplicant/dbus/dbus_common.c
@@ -4,14 +4,8 @@
* Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
* Copyright (c) 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "utils/includes.h"
diff --git a/wpa_supplicant/dbus/dbus_common.h b/wpa_supplicant/dbus/dbus_common.h
index 50da09b9c5d1..aea7db742b41 100644
--- a/wpa_supplicant/dbus/dbus_common.h
+++ b/wpa_supplicant/dbus/dbus_common.h
@@ -4,14 +4,8 @@
* Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
* Copyright (c) 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef DBUS_COMMON_H
diff --git a/wpa_supplicant/dbus/dbus_common_i.h b/wpa_supplicant/dbus/dbus_common_i.h
index 9dab1ee72782..a551ccd554b1 100644
--- a/wpa_supplicant/dbus/dbus_common_i.h
+++ b/wpa_supplicant/dbus/dbus_common_i.h
@@ -4,14 +4,8 @@
* Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
* Copyright (c) 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef DBUS_COMMON_I_H
@@ -25,6 +19,10 @@ struct wpas_dbus_priv {
struct wpa_global *global;
u32 next_objid;
int dbus_new_initialized;
+
+#if defined(CONFIG_CTRL_IFACE_DBUS_NEW) && defined(CONFIG_AP)
+ int dbus_noc_refcnt;
+#endif /* CONFIG_CTRL_IFACE_DBUS_NEW && CONFIG_AP */
};
#endif /* DBUS_COMMON_I_H */
diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.c b/wpa_supplicant/dbus/dbus_dict_helpers.c
index b3aff40388b1..61a94304bcbe 100644
--- a/wpa_supplicant/dbus/dbus_dict_helpers.c
+++ b/wpa_supplicant/dbus/dbus_dict_helpers.c
@@ -2,20 +2,15 @@
* 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
#include <dbus/dbus.h>
#include "common.h"
+#include "wpabuf.h"
#include "dbus_dict_helpers.h"
@@ -443,11 +438,12 @@ dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict,
/**
- * Begin a string array entry in the dict
+ * Begin an 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 type The type of the contained data
* @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
@@ -457,12 +453,21 @@ dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict,
* @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)
+dbus_bool_t wpa_dbus_dict_begin_array(DBusMessageIter *iter_dict,
+ const char *key, const char *type,
+ DBusMessageIter *iter_dict_entry,
+ DBusMessageIter *iter_dict_val,
+ DBusMessageIter *iter_array)
{
+ char array_type[10];
+ int err;
+
+ err = os_snprintf(array_type, sizeof(array_type),
+ DBUS_TYPE_ARRAY_AS_STRING "%s",
+ type);
+ if (err < 0 || err > (int) sizeof(array_type))
+ return FALSE;
+
if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array)
return FALSE;
@@ -472,20 +477,31 @@ dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
if (!dbus_message_iter_open_container(iter_dict_entry,
DBUS_TYPE_VARIANT,
- DBUS_TYPE_ARRAY_AS_STRING
- DBUS_TYPE_STRING_AS_STRING,
+ array_type,
iter_dict_val))
return FALSE;
if (!dbus_message_iter_open_container(iter_dict_val, DBUS_TYPE_ARRAY,
- DBUS_TYPE_BYTE_AS_STRING,
- iter_array))
+ type, iter_array))
return FALSE;
return TRUE;
}
+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)
+{
+ return wpa_dbus_dict_begin_array(
+ iter_dict, key,
+ DBUS_TYPE_STRING_AS_STRING,
+ iter_dict_entry, iter_dict_val, iter_array);
+}
+
+
/**
* Add a single string element to a string array dict entry
*
@@ -508,23 +524,67 @@ dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array,
/**
- * End a string array dict entry
+ * Add a single byte array element to a string array dict entry
+ *
+ * @param iter_array A valid DBusMessageIter returned from
+ * wpa_dbus_dict_begin_array()'s iter_array
+ * parameter -- note that wpa_dbus_dict_begin_array()
+ * must have been called with "ay" as the type
+ * @param value The data to be added to the dict entry's array
+ * @param value_len The length of the data
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_bin_array_add_element(DBusMessageIter *iter_array,
+ const u8 *value,
+ size_t value_len)
+{
+ DBusMessageIter iter_bytes;
+ size_t i;
+
+ if (!iter_array || !value)
+ return FALSE;
+
+ if (!dbus_message_iter_open_container(iter_array, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE_AS_STRING,
+ &iter_bytes))
+ return FALSE;
+
+ for (i = 0; i < value_len; i++) {
+ if (!dbus_message_iter_append_basic(&iter_bytes,
+ DBUS_TYPE_BYTE,
+ &(value[i])))
+ return FALSE;
+ }
+
+ if (!dbus_message_iter_close_container(iter_array, &iter_bytes))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+/**
+ * End an 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()
+ * wpa_dbus_dict_begin_string_array() or
+ * wpa_dbus_dict_begin_array()
* @param iter_dict_val A private DBusMessageIter returned from
- * wpa_dbus_dict_end_string_array()
+ * wpa_dbus_dict_begin_string_array() or
+ * wpa_dbus_dict_begin_array()
* @param iter_array A DBusMessageIter returned from
- * wpa_dbus_dict_end_string_array()
+ * wpa_dbus_dict_begin_string_array() or
+ * wpa_dbus_dict_begin_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)
+dbus_bool_t wpa_dbus_dict_end_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;
@@ -583,6 +643,52 @@ dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict,
}
+/**
+ * Convenience function to add an wpabuf binary 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 wpabuf structures
+ * @param num_items The number of strings in the array
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_append_wpabuf_array(DBusMessageIter *iter_dict,
+ const char *key,
+ const struct wpabuf **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_array(iter_dict, key,
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_TYPE_BYTE_AS_STRING,
+ &iter_dict_entry, &iter_dict_val,
+ &iter_array))
+ return FALSE;
+
+ for (i = 0; i < num_items; i++) {
+ if (!wpa_dbus_dict_bin_array_add_element(&iter_array,
+ wpabuf_head(items[i]),
+ wpabuf_len(items[i])))
+ return FALSE;
+ }
+
+ if (!wpa_dbus_dict_end_array(iter_dict, &iter_dict_entry,
+ &iter_dict_val, &iter_array))
+ return FALSE;
+
+ return TRUE;
+}
+
+
/*****************************************************/
/* Stuff for reading dicts */
/*****************************************************/
@@ -593,18 +699,26 @@ dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_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()
+ * @error on failure a descriptive error
* @return TRUE on success, FALSE on failure
*
*/
dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter,
- DBusMessageIter *iter_dict)
+ DBusMessageIter *iter_dict,
+ DBusError *error)
{
- if (!iter || !iter_dict)
+ if (!iter || !iter_dict) {
+ dbus_set_error_const(error, DBUS_ERROR_FAILED,
+ "[internal] missing message iterators");
return FALSE;
+ }
if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
- dbus_message_iter_get_element_type(iter) != DBUS_TYPE_DICT_ENTRY)
+ dbus_message_iter_get_element_type(iter) != DBUS_TYPE_DICT_ENTRY) {
+ dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+ "unexpected message argument types");
return FALSE;
+ }
dbus_message_iter_recurse(iter, iter_dict);
return TRUE;
@@ -615,17 +729,16 @@ dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter,
#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)
+ DBusMessageIter *iter, struct wpa_dbus_dict_entry *entry)
{
dbus_uint32_t count = 0;
dbus_bool_t success = FALSE;
- char *buffer, *nbuffer;;
+ char *buffer, *nbuffer;
entry->bytearray_value = NULL;
entry->array_type = DBUS_TYPE_BYTE;
- buffer = os_zalloc(BYTE_ARRAY_ITEM_SIZE * BYTE_ARRAY_CHUNK_SIZE);
+ buffer = os_calloc(BYTE_ARRAY_CHUNK_SIZE, BYTE_ARRAY_ITEM_SIZE);
if (!buffer)
return FALSE;
@@ -635,8 +748,9 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_byte_array(
char byte;
if ((count % BYTE_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
- nbuffer = os_realloc(buffer, BYTE_ARRAY_ITEM_SIZE *
- (count + BYTE_ARRAY_CHUNK_SIZE));
+ nbuffer = os_realloc_array(
+ buffer, count + BYTE_ARRAY_CHUNK_SIZE,
+ BYTE_ARRAY_ITEM_SIZE);
if (nbuffer == NULL) {
os_free(buffer);
wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_"
@@ -682,7 +796,7 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_string_array(
entry->strarray_value = NULL;
entry->array_type = DBUS_TYPE_STRING;
- buffer = os_zalloc(STR_ARRAY_ITEM_SIZE * STR_ARRAY_CHUNK_SIZE);
+ buffer = os_calloc(STR_ARRAY_CHUNK_SIZE, STR_ARRAY_ITEM_SIZE);
if (buffer == NULL)
return FALSE;
@@ -693,8 +807,9 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_string_array(
char *str;
if ((count % STR_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
- nbuffer = os_realloc(buffer, STR_ARRAY_ITEM_SIZE *
- (count + STR_ARRAY_CHUNK_SIZE));
+ nbuffer = os_realloc_array(
+ buffer, count + STR_ARRAY_CHUNK_SIZE,
+ STR_ARRAY_ITEM_SIZE);
if (nbuffer == NULL) {
os_free(buffer);
wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_"
@@ -733,6 +848,66 @@ done:
}
+#define BIN_ARRAY_CHUNK_SIZE 10
+#define BIN_ARRAY_ITEM_SIZE (sizeof(struct wpabuf *))
+
+static dbus_bool_t _wpa_dbus_dict_entry_get_binarray(
+ DBusMessageIter *iter, struct wpa_dbus_dict_entry *entry)
+{
+ struct wpa_dbus_dict_entry tmpentry;
+ size_t buflen = 0;
+ int i;
+
+ if (dbus_message_iter_get_element_type(iter) != DBUS_TYPE_BYTE)
+ return FALSE;
+
+ entry->array_type = WPAS_DBUS_TYPE_BINARRAY;
+ entry->array_len = 0;
+ entry->binarray_value = NULL;
+
+ while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_ARRAY) {
+ DBusMessageIter iter_array;
+
+ if (entry->array_len == buflen) {
+ struct wpabuf **newbuf;
+
+ buflen += BIN_ARRAY_CHUNK_SIZE;
+
+ newbuf = os_realloc_array(entry->binarray_value,
+ buflen, BIN_ARRAY_ITEM_SIZE);
+ if (!newbuf)
+ goto cleanup;
+ entry->binarray_value = newbuf;
+ }
+
+ dbus_message_iter_recurse(iter, &iter_array);
+ if (_wpa_dbus_dict_entry_get_byte_array(&iter_array, &tmpentry)
+ == FALSE)
+ goto cleanup;
+
+ entry->binarray_value[entry->array_len] =
+ wpabuf_alloc_ext_data((u8 *) tmpentry.bytearray_value,
+ tmpentry.array_len);
+ if (entry->binarray_value[entry->array_len] == NULL) {
+ wpa_dbus_dict_entry_clear(&tmpentry);
+ goto cleanup;
+ }
+ entry->array_len++;
+ dbus_message_iter_next(iter);
+ }
+
+ return TRUE;
+
+ cleanup:
+ for (i = 0; i < (int) entry->array_len; i++)
+ wpabuf_free(entry->binarray_value[i]);
+ os_free(entry->binarray_value);
+ entry->array_len = 0;
+ entry->binarray_value = NULL;
+ return FALSE;
+}
+
+
static dbus_bool_t _wpa_dbus_dict_entry_get_array(
DBusMessageIter *iter_dict_val, struct wpa_dbus_dict_entry *entry)
{
@@ -748,7 +923,6 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_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:
@@ -756,6 +930,8 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_array(
array_type,
entry);
break;
+ case DBUS_TYPE_ARRAY:
+ success = _wpa_dbus_dict_entry_get_binarray(&iter_array, entry);
default:
break;
}
@@ -915,9 +1091,14 @@ void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry)
os_free(entry->strarray_value[i]);
os_free(entry->strarray_value);
break;
+ case WPAS_DBUS_TYPE_BINARRAY:
+ for (i = 0; i < entry->array_len; i++)
+ wpabuf_free(entry->binarray_value[i]);
+ os_free(entry->binarray_value);
+ break;
}
break;
}
- memset(entry, 0, sizeof(struct wpa_dbus_dict_entry));
+ os_memset(entry, 0, sizeof(struct wpa_dbus_dict_entry));
}
diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.h b/wpa_supplicant/dbus/dbus_dict_helpers.h
index eb315753174f..96663494a30f 100644
--- a/wpa_supplicant/dbus/dbus_dict_helpers.h
+++ b/wpa_supplicant/dbus/dbus_dict_helpers.h
@@ -2,19 +2,15 @@
* 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef DBUS_DICT_HELPERS_H
#define DBUS_DICT_HELPERS_H
+#include "wpabuf.h"
+
/*
* Adding a dict to a DBusMessage
*/
@@ -74,7 +70,13 @@ dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict,
const char *value,
const dbus_uint32_t value_len);
-/* Manual construction and addition of string array elements */
+/* Manual construction and addition of array elements */
+dbus_bool_t wpa_dbus_dict_begin_array(DBusMessageIter *iter_dict,
+ const char *key, const char *type,
+ DBusMessageIter *iter_dict_entry,
+ DBusMessageIter *iter_dict_val,
+ DBusMessageIter *iter_array);
+
dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
const char *key,
DBusMessageIter *iter_dict_entry,
@@ -84,10 +86,24 @@ dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
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);
+dbus_bool_t wpa_dbus_dict_bin_array_add_element(DBusMessageIter *iter_array,
+ const u8 *value,
+ size_t value_len);
+
+dbus_bool_t wpa_dbus_dict_end_array(DBusMessageIter *iter_dict,
+ DBusMessageIter *iter_dict_entry,
+ DBusMessageIter *iter_dict_val,
+ DBusMessageIter *iter_array);
+
+static inline dbus_bool_t
+wpa_dbus_dict_end_string_array(DBusMessageIter *iter_dict,
+ DBusMessageIter *iter_dict_entry,
+ DBusMessageIter *iter_dict_val,
+ DBusMessageIter *iter_array)
+{
+ return wpa_dbus_dict_end_array(iter_dict, iter_dict_entry,
+ iter_dict_val, iter_array);
+}
/* Convenience function to add a whole string list */
dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict,
@@ -95,14 +111,22 @@ dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict,
const char **items,
const dbus_uint32_t num_items);
+dbus_bool_t wpa_dbus_dict_append_wpabuf_array(DBusMessageIter *iter_dict,
+ const char *key,
+ const struct wpabuf **items,
+ const dbus_uint32_t num_items);
+
/*
* Reading a dict from a DBusMessage
*/
+#define WPAS_DBUS_TYPE_BINARRAY (DBUS_NUMBER_OF_TYPES + 100)
+
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 */
+ entry value contains an array, or the special
+ WPAS_DBUS_TYPE_BINARRAY */
const char *key; /** key of the dict entry */
/** Possible values of the property */
@@ -119,13 +143,15 @@ struct wpa_dbus_dict_entry {
double double_value;
char *bytearray_value;
char **strarray_value;
+ struct wpabuf **binarray_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);
+ DBusMessageIter *iter_dict,
+ DBusError *error);
dbus_bool_t wpa_dbus_dict_get_entry(DBusMessageIter *iter_dict,
struct wpa_dbus_dict_entry *entry);
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index bdfbbac125d0..8bc6618ab611 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -4,29 +4,119 @@
* Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com>
* Copyright (c) 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
#include "common.h"
+#include "common/ieee802_11_defs.h"
#include "wps/wps.h"
#include "../config.h"
#include "../wpa_supplicant_i.h"
#include "../bss.h"
+#include "../wpas_glue.h"
#include "dbus_new_helpers.h"
#include "dbus_dict_helpers.h"
#include "dbus_new.h"
#include "dbus_new_handlers.h"
-#include "dbus_common.h"
#include "dbus_common_i.h"
+#include "dbus_new_handlers_p2p.h"
+#include "p2p/p2p.h"
+
+#ifdef CONFIG_AP /* until needed by something else */
+
+/*
+ * NameOwnerChanged handling
+ *
+ * Some services we provide allow an application to register for
+ * a signal that it needs. While it can also unregister, we must
+ * be prepared for the case where the application simply crashes
+ * and thus doesn't clean up properly. The way to handle this in
+ * DBus is to register for the NameOwnerChanged signal which will
+ * signal an owner change to NULL if the peer closes the socket
+ * for whatever reason.
+ *
+ * Handle this signal via a filter function whenever necessary.
+ * The code below also handles refcounting in case in the future
+ * there will be multiple instances of this subscription scheme.
+ */
+static const char wpas_dbus_noc_filter_str[] =
+ "interface=org.freedesktop.DBus,member=NameOwnerChanged";
+
+
+static DBusHandlerResult noc_filter(DBusConnection *conn,
+ DBusMessage *message, void *data)
+{
+ struct wpas_dbus_priv *priv = data;
+
+ if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS,
+ "NameOwnerChanged")) {
+ const char *name;
+ const char *prev_owner;
+ const char *new_owner;
+ DBusError derr;
+ struct wpa_supplicant *wpa_s;
+
+ dbus_error_init(&derr);
+
+ if (!dbus_message_get_args(message, &derr,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_STRING, &prev_owner,
+ DBUS_TYPE_STRING, &new_owner,
+ DBUS_TYPE_INVALID)) {
+ /* Ignore this error */
+ dbus_error_free(&derr);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ for (wpa_s = priv->global->ifaces; wpa_s; wpa_s = wpa_s->next)
+ {
+ if (wpa_s->preq_notify_peer != NULL &&
+ os_strcmp(name, wpa_s->preq_notify_peer) == 0 &&
+ (new_owner == NULL || os_strlen(new_owner) == 0)) {
+ /* probe request owner disconnected */
+ os_free(wpa_s->preq_notify_peer);
+ wpa_s->preq_notify_peer = NULL;
+ wpas_dbus_unsubscribe_noc(priv);
+ }
+ }
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+
+void wpas_dbus_subscribe_noc(struct wpas_dbus_priv *priv)
+{
+ priv->dbus_noc_refcnt++;
+ if (priv->dbus_noc_refcnt > 1)
+ return;
+
+ if (!dbus_connection_add_filter(priv->con, noc_filter, priv, NULL)) {
+ wpa_printf(MSG_ERROR, "dbus: failed to add filter");
+ return;
+ }
+
+ dbus_bus_add_match(priv->con, wpas_dbus_noc_filter_str, NULL);
+}
+
+
+void wpas_dbus_unsubscribe_noc(struct wpas_dbus_priv *priv)
+{
+ priv->dbus_noc_refcnt--;
+ if (priv->dbus_noc_refcnt > 0)
+ return;
+
+ dbus_bus_remove_match(priv->con, wpas_dbus_noc_filter_str, NULL);
+ dbus_connection_remove_filter(priv->con, noc_filter, priv);
+}
+
+#endif /* CONFIG_AP */
/**
@@ -42,7 +132,7 @@ static void wpas_dbus_signal_interface(struct wpa_supplicant *wpa_s,
{
struct wpas_dbus_priv *iface;
DBusMessage *msg;
- DBusMessageIter iter, iter_dict;
+ DBusMessageIter iter;
iface = wpa_s->global->dbus;
@@ -61,14 +151,9 @@ static void wpas_dbus_signal_interface(struct wpa_supplicant *wpa_s,
goto err;
if (properties) {
- if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
- goto err;
-
- wpa_dbus_get_object_properties(iface, wpa_s->dbus_new_path,
- WPAS_DBUS_NEW_IFACE_INTERFACE,
- &iter_dict);
-
- if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
+ if (!wpa_dbus_get_object_properties(
+ iface, wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_INTERFACE, &iter))
goto err;
}
@@ -157,7 +242,7 @@ static void wpas_dbus_signal_bss(struct wpa_supplicant *wpa_s,
{
struct wpas_dbus_priv *iface;
DBusMessage *msg;
- DBusMessageIter iter, iter_dict;
+ DBusMessageIter iter;
iface = wpa_s->global->dbus;
@@ -177,14 +262,9 @@ static void wpas_dbus_signal_bss(struct wpa_supplicant *wpa_s,
goto err;
if (properties) {
- if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
- goto err;
-
- wpa_dbus_get_object_properties(iface, bss_obj_path,
- WPAS_DBUS_NEW_IFACE_BSS,
- &iter_dict);
-
- if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
+ if (!wpa_dbus_get_object_properties(iface, bss_obj_path,
+ WPAS_DBUS_NEW_IFACE_BSS,
+ &iter))
goto err;
}
@@ -304,7 +384,7 @@ static void wpas_dbus_signal_network(struct wpa_supplicant *wpa_s,
{
struct wpas_dbus_priv *iface;
DBusMessage *msg;
- DBusMessageIter iter, iter_dict;
+ DBusMessageIter iter;
char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
iface = wpa_s->global->dbus;
@@ -330,14 +410,9 @@ static void wpas_dbus_signal_network(struct wpa_supplicant *wpa_s,
goto err;
if (properties) {
- if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
- goto err;
-
- wpa_dbus_get_object_properties(iface, net_obj_path,
- WPAS_DBUS_NEW_IFACE_NETWORK,
- &iter_dict);
-
- if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
+ if (!wpa_dbus_get_object_properties(
+ iface, net_obj_path, WPAS_DBUS_NEW_IFACE_NETWORK,
+ &iter))
goto err;
}
@@ -394,6 +469,67 @@ void wpas_dbus_signal_network_selected(struct wpa_supplicant *wpa_s, int id)
/**
+ * wpas_dbus_signal_network_request - Indicate that additional information
+ * (EAP password, etc.) is required to complete the association to this SSID
+ * @wpa_s: %wpa_supplicant network interface data
+ * @rtype: The specific additional information required
+ * @default_text: Optional description of required information
+ *
+ * Request additional information or passwords to complete an association
+ * request.
+ */
+void wpas_dbus_signal_network_request(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ enum wpa_ctrl_req_type rtype,
+ const char *default_txt)
+{
+ struct wpas_dbus_priv *iface;
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+ const char *field, *txt = NULL, *net_ptr;
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ field = wpa_supplicant_ctrl_req_to_string(rtype, default_txt, &txt);
+ if (field == NULL)
+ return;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_INTERFACE,
+ "NetworkRequest");
+ if (msg == NULL)
+ return;
+
+ os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
+ wpa_s->dbus_new_path, ssid->id);
+ net_ptr = &net_obj_path[0];
+
+ dbus_message_iter_init_append(msg, &iter);
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+ &net_ptr))
+ goto err;
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &field))
+ goto err;
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &txt))
+ goto err;
+
+ dbus_connection_send(iface->con, msg, NULL);
+ dbus_message_unref(msg);
+ return;
+
+err:
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ dbus_message_unref(msg);
+}
+
+
+/**
* wpas_dbus_signal_network_enabled_changed - Signals Enabled property changes
* @wpa_s: %wpa_supplicant network interface data
* @ssid: configured network which Enabled property has changed
@@ -650,47 +786,974 @@ nomem:
#endif /* CONFIG_WPS */
+void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
+ int depth, const char *subject,
+ const char *cert_hash,
+ const struct wpabuf *cert)
+{
+ struct wpas_dbus_priv *iface;
+ DBusMessage *msg;
+ DBusMessageIter iter, dict_iter;
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_INTERFACE,
+ "Certification");
+ if (msg == NULL)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+ goto nomem;
+
+ if (!wpa_dbus_dict_append_uint32(&dict_iter, "depth", depth) ||
+ !wpa_dbus_dict_append_string(&dict_iter, "subject", subject))
+ goto nomem;
+
+ if (cert_hash &&
+ !wpa_dbus_dict_append_string(&dict_iter, "cert_hash", cert_hash))
+ goto nomem;
+
+ if (cert &&
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "cert",
+ wpabuf_head(cert),
+ wpabuf_len(cert)))
+ goto nomem;
+
+ if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
+ goto nomem;
+
+ dbus_connection_send(iface->con, msg, NULL);
+
+nomem:
+ dbus_message_unref(msg);
+}
+
+
+void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s,
+ const char *status, const char *parameter)
+{
+ struct wpas_dbus_priv *iface;
+ DBusMessage *msg;
+ DBusMessageIter iter;
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_INTERFACE,
+ "EAP");
+ if (msg == NULL)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &status)
+ ||
+ !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
+ &parameter))
+ goto nomem;
+
+ dbus_connection_send(iface->con, msg, NULL);
+
+nomem:
+ dbus_message_unref(msg);
+}
+
+
+#ifdef CONFIG_P2P
+
+/**
+ * wpas_dbus_signal_p2p_group_removed - Signals P2P group was removed
+ * @wpa_s: %wpa_supplicant network interface data
+ * @role: role of this device (client or GO)
+ * Sends signal with i/f name and role as string arguments
+ */
+void wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s,
+ const char *role)
+{
+
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ struct wpas_dbus_priv *iface = wpa_s->global->dbus;
+ char *ifname = wpa_s->ifname;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ "GroupFinished");
+ if (msg == NULL)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &ifname)) {
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct GroupFinished"
+ "signal -not enough memory for ifname ");
+ goto err;
+ }
+
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &role))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct GroupFinished"
+ "signal -not enough memory for role ");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
+
+err:
+ dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_p2p_provision_discovery - Signals various PD events
+ *
+ * @dev_addr - who sent the request or responded to our request.
+ * @request - Will be 1 if request, 0 for response.
+ * @status - valid only in case of response
+ * @config_methods - wps config methods
+ * @generated_pin - pin to be displayed in case of WPS_CONFIG_DISPLAY method
+ *
+ * Sends following provision discovery related events:
+ * ProvisionDiscoveryRequestDisplayPin
+ * ProvisionDiscoveryResponseDisplayPin
+ * ProvisionDiscoveryRequestEnterPin
+ * ProvisionDiscoveryResponseEnterPin
+ * ProvisionDiscoveryPBCRequest
+ * ProvisionDiscoveryPBCResponse
+ *
+ * TODO::
+ * ProvisionDiscoveryFailure (timeout case)
+ */
+void wpas_dbus_signal_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr, int request,
+ enum p2p_prov_disc_status status,
+ u16 config_methods,
+ unsigned int generated_pin)
+{
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ struct wpas_dbus_priv *iface;
+ char *_signal;
+ int add_pin = 0;
+ char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+ int error_ret = 1;
+ char pin[9], *p_pin = NULL;
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ if (request || !status) {
+ if (config_methods & WPS_CONFIG_DISPLAY)
+ _signal = request ?
+ "ProvisionDiscoveryRequestDisplayPin" :
+ "ProvisionDiscoveryResponseEnterPin";
+ else if (config_methods & WPS_CONFIG_KEYPAD)
+ _signal = request ?
+ "ProvisionDiscoveryRequestEnterPin" :
+ "ProvisionDiscoveryResponseDisplayPin";
+ else if (config_methods & WPS_CONFIG_PUSHBUTTON)
+ _signal = request ? "ProvisionDiscoveryPBCRequest" :
+ "ProvisionDiscoveryPBCResponse";
+ else
+ return; /* Unknown or un-supported method */
+ } else if (!request && status)
+ /* Explicit check for failure response */
+ _signal = "ProvisionDiscoveryFailure";
+
+ add_pin = ((request && (config_methods & WPS_CONFIG_DISPLAY)) ||
+ (!request && !status &&
+ (config_methods & WPS_CONFIG_KEYPAD)));
+
+ if (add_pin) {
+ os_snprintf(pin, sizeof(pin), "%08d", generated_pin);
+ p_pin = pin;
+ }
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_P2PDEVICE, _signal);
+ if (msg == NULL)
+ return;
+
+ /* Check if this is a known peer */
+ if (!p2p_peer_known(wpa_s->global->p2p, dev_addr))
+ goto error;
+
+ os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
+ COMPACT_MACSTR,
+ wpa_s->dbus_new_path, MAC2STR(dev_addr));
+
+ path = peer_obj_path;
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ if (!dbus_message_iter_append_basic(&iter,
+ DBUS_TYPE_OBJECT_PATH,
+ &path))
+ goto error;
+
+ if (!request && status)
+ /* Attach status to ProvisionDiscoveryFailure */
+ error_ret = !dbus_message_iter_append_basic(&iter,
+ DBUS_TYPE_INT32,
+ &status);
+ else
+ error_ret = (add_pin &&
+ !dbus_message_iter_append_basic(&iter,
+ DBUS_TYPE_STRING,
+ &p_pin));
+
+error:
+ if (!error_ret)
+ dbus_connection_send(iface->con, msg, NULL);
+ else
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+
+ dbus_message_unref(msg);
+}
+
+
+void wpas_dbus_signal_p2p_go_neg_req(struct wpa_supplicant *wpa_s,
+ const u8 *src, u16 dev_passwd_id)
+{
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ struct wpas_dbus_priv *iface;
+ char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
+ wpa_s->dbus_new_path, MAC2STR(src));
+ path = peer_obj_path;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ "GONegotiationRequest");
+ if (msg == NULL)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+ &path) ||
+ !dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT16,
+ &dev_passwd_id))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
+
+ dbus_message_unref(msg);
+}
+
+
+static int wpas_dbus_get_group_obj_path(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid *ssid,
+ char *group_obj_path)
+{
+ char group_name[3];
+
+ if (os_memcmp(ssid->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN))
+ return -1;
+
+ os_memcpy(group_name, ssid->ssid + P2P_WILDCARD_SSID_LEN, 2);
+ group_name[2] = '\0';
+
+ os_snprintf(group_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_GROUPS_PART "/%s",
+ wpa_s->dbus_new_path, group_name);
+
+ return 0;
+}
+
+
+/**
+ * wpas_dbus_signal_p2p_group_started - Signals P2P group has
+ * started. Emitted when a group is successfully started
+ * irrespective of the role (client/GO) of the current device
+ *
+ * @wpa_s: %wpa_supplicant network interface data
+ * @ssid: SSID object
+ * @client: this device is P2P client
+ * @network_id: network id of the group started, use instead of ssid->id
+ * to account for persistent groups
+ */
+void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid *ssid,
+ int client, int network_id)
+{
+ DBusMessage *msg;
+ DBusMessageIter iter, dict_iter;
+ struct wpas_dbus_priv *iface;
+ char group_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+ iface = wpa_s->parent->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ if (wpas_dbus_get_group_obj_path(wpa_s, ssid, group_obj_path) < 0)
+ return;
+
+ /* New interface has been created for this group */
+ msg = dbus_message_new_signal(wpa_s->parent->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ "GroupStarted");
+
+ if (msg == NULL)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+ goto nomem;
+
+ /*
+ * In case the device supports creating a separate interface the
+ * DBus client will need to know the object path for the interface
+ * object this group was created on, so include it here.
+ */
+ if (!wpa_dbus_dict_append_object_path(&dict_iter,
+ "interface_object",
+ wpa_s->dbus_new_path))
+ goto nomem;
+
+ if (!wpa_dbus_dict_append_string(&dict_iter, "role",
+ client ? "client" : "GO"))
+ goto nomem;
+
+ if (!wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
+ group_obj_path) ||
+ !wpa_dbus_dict_close_write(&iter, &dict_iter))
+ goto nomem;
+
+ dbus_connection_send(iface->con, msg, NULL);
+
+nomem:
+ dbus_message_unref(msg);
+}
+
+
+/**
+ *
+ * Method to emit GONeogtiation Success or Failure signals based
+ * on status.
+ * @status: Status of the GO neg request. 0 for success, other for errors.
+ */
+void wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s,
+ struct p2p_go_neg_results *res)
+{
+ DBusMessage *msg;
+ DBusMessageIter iter, dict_iter;
+ DBusMessageIter iter_dict_entry, iter_dict_val, iter_dict_array;
+ struct wpas_dbus_priv *iface;
+ char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+ dbus_int32_t freqs[P2P_MAX_CHANNELS];
+ dbus_int32_t *f_array = freqs;
+
+
+ iface = wpa_s->global->dbus;
+
+ os_memset(freqs, 0, sizeof(freqs));
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
+ wpa_s->dbus_new_path, MAC2STR(res->peer_device_addr));
+ path = peer_obj_path;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ res->status ? "GONegotiationFailure" :
+ "GONegotiationSuccess");
+ if (msg == NULL)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+ goto err;
+ if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
+ path) ||
+ !wpa_dbus_dict_append_int32(&dict_iter, "status", res->status))
+ goto err;
+
+ if (!res->status) {
+ int i = 0;
+ int freq_list_num = 0;
+
+ if (res->role_go) {
+ if (!wpa_dbus_dict_append_byte_array(
+ &dict_iter, "passphrase",
+ (const char *) res->passphrase,
+ sizeof(res->passphrase)))
+ goto err;
+ }
+
+ if (!wpa_dbus_dict_append_string(&dict_iter, "role_go",
+ res->role_go ? "GO" :
+ "client") ||
+ !wpa_dbus_dict_append_int32(&dict_iter, "frequency",
+ res->freq) ||
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "ssid",
+ (const char *) res->ssid,
+ res->ssid_len) ||
+ !wpa_dbus_dict_append_byte_array(&dict_iter,
+ "peer_device_addr",
+ (const char *)
+ res->peer_device_addr,
+ ETH_ALEN) ||
+ !wpa_dbus_dict_append_byte_array(&dict_iter,
+ "peer_interface_addr",
+ (const char *)
+ res->peer_interface_addr,
+ ETH_ALEN) ||
+ !wpa_dbus_dict_append_string(&dict_iter, "wps_method",
+ p2p_wps_method_text(
+ res->wps_method)))
+ goto err;
+
+ for (i = 0; i < P2P_MAX_CHANNELS; i++) {
+ if (res->freq_list[i]) {
+ freqs[i] = res->freq_list[i];
+ freq_list_num++;
+ }
+ }
+
+ if (!wpa_dbus_dict_begin_array(&dict_iter,
+ "frequency_list",
+ DBUS_TYPE_INT32_AS_STRING,
+ &iter_dict_entry,
+ &iter_dict_val,
+ &iter_dict_array))
+ goto err;
+
+ if (!dbus_message_iter_append_fixed_array(&iter_dict_array,
+ DBUS_TYPE_INT32,
+ &f_array,
+ freq_list_num))
+ goto err;
+
+ if (!wpa_dbus_dict_end_array(&dict_iter,
+ &iter_dict_entry,
+ &iter_dict_val,
+ &iter_dict_array))
+ goto err;
+
+ if (!wpa_dbus_dict_append_int32(&dict_iter, "persistent_group",
+ res->persistent_group) ||
+ !wpa_dbus_dict_append_uint32(&dict_iter,
+ "peer_config_timeout",
+ res->peer_config_timeout))
+ goto err;
+ }
+
+ if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
+ goto err;
+
+ dbus_connection_send(iface->con, msg, NULL);
+err:
+ dbus_message_unref(msg);
+}
+
+
+/**
+ *
+ * Method to emit Invitation Result signal based on status and
+ * bssid
+ * @status: Status of the Invite request. 0 for success, other
+ * for errors
+ * @bssid : Basic Service Set Identifier
+ */
+void wpas_dbus_signal_p2p_invitation_result(struct wpa_supplicant *wpa_s,
+ int status, const u8 *bssid)
+{
+ DBusMessage *msg;
+ DBusMessageIter iter, dict_iter;
+ struct wpas_dbus_priv *iface;
+
+ wpa_printf(MSG_INFO, "%s\n", __func__);
+
+ iface = wpa_s->global->dbus;
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ "InvitationResult");
+
+ if (msg == NULL)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+ goto nomem;
+
+ if (!wpa_dbus_dict_append_int32(&dict_iter, "status", status))
+ goto nomem;
+ if (bssid) {
+ if (!wpa_dbus_dict_append_byte_array(&dict_iter, "BSSID",
+ (const char *) bssid,
+ ETH_ALEN))
+ goto nomem;
+ }
+ if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
+ goto nomem;
+
+ dbus_connection_send(iface->con, msg, NULL);
+
+nomem:
+ dbus_message_unref(msg);
+}
+
+
+/**
+ *
+ * Method to emit a signal for a peer joining the group.
+ * The signal will carry path to the group member object
+ * constructed using p2p i/f addr used for connecting.
+ *
+ * @wpa_s: %wpa_supplicant network interface data
+ * @member_addr: addr (p2p i/f) of the peer joining the group
+ */
+void wpas_dbus_signal_p2p_peer_joined(struct wpa_supplicant *wpa_s,
+ const u8 *member)
+{
+ struct wpas_dbus_priv *iface;
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ char groupmember_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ if (!wpa_s->dbus_groupobj_path)
+ return;
+
+ os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/"
+ COMPACT_MACSTR,
+ wpa_s->dbus_groupobj_path, MAC2STR(member));
+
+ msg = dbus_message_new_signal(wpa_s->dbus_groupobj_path,
+ WPAS_DBUS_NEW_IFACE_P2P_GROUP,
+ "PeerJoined");
+ if (msg == NULL)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+ path = groupmember_obj_path;
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+ &path))
+ goto err;
+
+ dbus_connection_send(iface->con, msg, NULL);
+
+ dbus_message_unref(msg);
+ return;
+
+err:
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ dbus_message_unref(msg);
+}
+
+
+/**
+ *
+ * Method to emit a signal for a peer disconnecting the group.
+ * The signal will carry path to the group member object
+ * constructed using p2p i/f addr used for connecting.
+ *
+ * @wpa_s: %wpa_supplicant network interface data
+ * @member_addr: addr (p2p i/f) of the peer joining the group
+ */
+void wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s,
+ const u8 *member)
+{
+ struct wpas_dbus_priv *iface;
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ char groupmember_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ if (!wpa_s->dbus_groupobj_path)
+ return;
+
+ os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/"
+ COMPACT_MACSTR,
+ wpa_s->dbus_groupobj_path, MAC2STR(member));
+
+ msg = dbus_message_new_signal(wpa_s->dbus_groupobj_path,
+ WPAS_DBUS_NEW_IFACE_P2P_GROUP,
+ "PeerDisconnected");
+ if (msg == NULL)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+ path = groupmember_obj_path;
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+ &path))
+ goto err;
+
+ dbus_connection_send(iface->con, msg, NULL);
+
+ dbus_message_unref(msg);
+ return;
+
+err:
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct PeerDisconnected "
+ "signal");
+ dbus_message_unref(msg);
+}
+
+
+/**
+ *
+ * Method to emit a signal for a service discovery request.
+ * The signal will carry station address, frequency, dialog token,
+ * update indicator and it tlvs
+ *
+ * @wpa_s: %wpa_supplicant network interface data
+ * @sa: station addr (p2p i/f) of the peer
+ * @dialog_token: service discovery request dialog token
+ * @update_indic: service discovery request update indicator
+ * @tlvs: service discovery request genrated byte array of tlvs
+ * @tlvs_len: service discovery request tlvs length
+ */
+void wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s,
+ int freq, const u8 *sa, u8 dialog_token,
+ u16 update_indic, const u8 *tlvs,
+ size_t tlvs_len)
+{
+ DBusMessage *msg;
+ DBusMessageIter iter, dict_iter;
+ struct wpas_dbus_priv *iface;
+ char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ "ServiceDiscoveryRequest");
+ if (msg == NULL)
+ return;
+
+ /* Check if this is a known peer */
+ if (!p2p_peer_known(wpa_s->global->p2p, sa))
+ goto error;
+
+ os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
+ COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(sa));
+
+ path = peer_obj_path;
+
+ dbus_message_iter_init_append(msg, &iter);
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+ goto error;
+
+
+ if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
+ path) ||
+ !wpa_dbus_dict_append_int32(&dict_iter, "frequency", freq) ||
+ !wpa_dbus_dict_append_int32(&dict_iter, "dialog_token",
+ dialog_token) ||
+ !wpa_dbus_dict_append_uint16(&dict_iter, "update_indicator",
+ update_indic) ||
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "tlvs",
+ (const char *) tlvs,
+ tlvs_len) ||
+ !wpa_dbus_dict_close_write(&iter, &dict_iter))
+ goto error;
+
+ dbus_connection_send(iface->con, msg, NULL);
+ dbus_message_unref(msg);
+ return;
+error:
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ dbus_message_unref(msg);
+}
+
+
+/**
+ *
+ * Method to emit a signal for a service discovery response.
+ * The signal will carry station address, update indicator and it
+ * tlvs
+ *
+ * @wpa_s: %wpa_supplicant network interface data
+ * @sa: station addr (p2p i/f) of the peer
+ * @update_indic: service discovery request update indicator
+ * @tlvs: service discovery request genrated byte array of tlvs
+ * @tlvs_len: service discovery request tlvs length
+ */
+void wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s,
+ const u8 *sa, u16 update_indic,
+ const u8 *tlvs, size_t tlvs_len)
+{
+ DBusMessage *msg;
+ DBusMessageIter iter, dict_iter;
+ struct wpas_dbus_priv *iface;
+ char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ "ServiceDiscoveryResponse");
+ if (msg == NULL)
+ return;
+
+ /* Check if this is a known peer */
+ if (!p2p_peer_known(wpa_s->global->p2p, sa))
+ goto error;
+
+ os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
+ COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(sa));
+
+ path = peer_obj_path;
+
+ dbus_message_iter_init_append(msg, &iter);
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+ goto error;
+
+ if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
+ path) ||
+ !wpa_dbus_dict_append_uint16(&dict_iter, "update_indicator",
+ update_indic) ||
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "tlvs",
+ (const char *) tlvs,
+ tlvs_len) ||
+ !wpa_dbus_dict_close_write(&iter, &dict_iter))
+ goto error;
+
+
+ dbus_connection_send(iface->con, msg, NULL);
+ dbus_message_unref(msg);
+ return;
+error:
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ dbus_message_unref(msg);
+}
+
+/**
+ * wpas_dbus_signal_persistent_group - Send a persistent group related
+ * event signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @id: new persistent group id
+ * @sig_name: signal name - PersistentGroupAdded, PersistentGroupRemoved
+ * @properties: determines if add second argument with object properties
+ *
+ * Notify listeners about an event related to persistent groups.
+ */
+static void wpas_dbus_signal_persistent_group(struct wpa_supplicant *wpa_s,
+ int id, const char *sig_name,
+ int properties)
+{
+ struct wpas_dbus_priv *iface;
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ char pgrp_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u",
+ wpa_s->dbus_new_path, id);
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ sig_name);
+ if (msg == NULL)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+ path = pgrp_obj_path;
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+ &path))
+ goto err;
+
+ if (properties) {
+ if (!wpa_dbus_get_object_properties(
+ iface, pgrp_obj_path,
+ WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, &iter))
+ goto err;
+ }
+
+ dbus_connection_send(iface->con, msg, NULL);
+
+ dbus_message_unref(msg);
+ return;
+
+err:
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_persistent_group_added - Send a persistent_group
+ * added signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @id: new persistent group id
+ *
+ * Notify listeners about addition of a new persistent group.
+ */
+static void wpas_dbus_signal_persistent_group_added(
+ struct wpa_supplicant *wpa_s, int id)
+{
+ wpas_dbus_signal_persistent_group(wpa_s, id, "PersistentGroupAdded",
+ TRUE);
+}
+
+
+/**
+ * wpas_dbus_signal_persistent_group_removed - Send a persistent_group
+ * removed signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @id: persistent group id
+ *
+ * Notify listeners about removal of a persistent group.
+ */
+static void wpas_dbus_signal_persistent_group_removed(
+ struct wpa_supplicant *wpa_s, int id)
+{
+ wpas_dbus_signal_persistent_group(wpa_s, id, "PersistentGroupRemoved",
+ FALSE);
+}
+
+
+/**
+ * wpas_dbus_signal_p2p_wps_failed - Signals WpsFailed event
+ * @wpa_s: %wpa_supplicant network interface data
+ *
+ * Sends Event dbus signal with name "fail" and dictionary containing
+ * "msg" field with fail message number (int32) as arguments
+ */
+void wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+ struct wps_event_fail *fail)
+{
+
+ DBusMessage *msg;
+ DBusMessageIter iter, dict_iter;
+ struct wpas_dbus_priv *iface;
+ char *key = "fail";
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ "WpsFailed");
+ if (msg == NULL)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) ||
+ !wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+ !wpa_dbus_dict_append_int32(&dict_iter, "msg", fail->msg) ||
+ !wpa_dbus_dict_append_int16(&dict_iter, "config_error",
+ fail->config_error) ||
+ !wpa_dbus_dict_close_write(&iter, &dict_iter))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
+
+ dbus_message_unref(msg);
+}
+
+#endif /*CONFIG_P2P*/
+
/**
* wpas_dbus_signal_prop_changed - Signals change of property
* @wpa_s: %wpa_supplicant network interface data
* @property: indicates which property has changed
*
- * Sends ProertyChanged signals with path, interface and arguments
+ * Sends PropertyChanged signals with path, interface and arguments
* depending on which property has changed.
*/
void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
enum wpas_dbus_prop property)
{
- WPADBusPropertyAccessor getter;
char *prop;
+ dbus_bool_t flush;
if (wpa_s->dbus_new_path == NULL)
return; /* Skip signal since D-Bus setup is not yet ready */
+ flush = FALSE;
switch (property) {
case WPAS_DBUS_PROP_AP_SCAN:
- getter = (WPADBusPropertyAccessor) wpas_dbus_getter_ap_scan;
prop = "ApScan";
break;
case WPAS_DBUS_PROP_SCANNING:
- getter = (WPADBusPropertyAccessor) wpas_dbus_getter_scanning;
prop = "Scanning";
break;
case WPAS_DBUS_PROP_STATE:
- getter = (WPADBusPropertyAccessor) wpas_dbus_getter_state;
prop = "State";
break;
case WPAS_DBUS_PROP_CURRENT_BSS:
- getter = (WPADBusPropertyAccessor)
- wpas_dbus_getter_current_bss;
prop = "CurrentBSS";
break;
case WPAS_DBUS_PROP_CURRENT_NETWORK:
- getter = (WPADBusPropertyAccessor)
- wpas_dbus_getter_current_network;
prop = "CurrentNetwork";
break;
+ case WPAS_DBUS_PROP_BSSS:
+ prop = "BSSs";
+ break;
+ case WPAS_DBUS_PROP_CURRENT_AUTH_MODE:
+ prop = "CurrentAuthMode";
+ break;
+ case WPAS_DBUS_PROP_DISCONNECT_REASON:
+ prop = "DisconnectReason";
+ flush = TRUE;
+ break;
default:
wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
__func__, property);
@@ -700,6 +1763,10 @@ void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
wpa_dbus_mark_property_changed(wpa_s->global->dbus,
wpa_s->dbus_new_path,
WPAS_DBUS_NEW_IFACE_INTERFACE, prop);
+ if (flush) {
+ wpa_dbus_flush_object_changed_properties(
+ wpa_s->global->dbus->con, wpa_s->dbus_new_path);
+ }
}
@@ -763,7 +1830,7 @@ void wpas_dbus_bss_signal_prop_changed(struct wpa_supplicant *wpa_s,
* wpas_dbus_signal_debug_level_changed - Signals change of debug param
* @global: wpa_global structure
*
- * Sends ProertyChanged signals informing that debug level has changed.
+ * Sends PropertyChanged signals informing that debug level has changed.
*/
void wpas_dbus_signal_debug_level_changed(struct wpa_global *global)
{
@@ -777,7 +1844,7 @@ void wpas_dbus_signal_debug_level_changed(struct wpa_global *global)
* wpas_dbus_signal_debug_timestamp_changed - Signals change of debug param
* @global: wpa_global structure
*
- * Sends ProertyChanged signals informing that debug timestamp has changed.
+ * Sends PropertyChanged signals informing that debug timestamp has changed.
*/
void wpas_dbus_signal_debug_timestamp_changed(struct wpa_global *global)
{
@@ -791,7 +1858,7 @@ void wpas_dbus_signal_debug_timestamp_changed(struct wpa_global *global)
* wpas_dbus_signal_debug_show_keys_changed - Signals change of debug param
* @global: wpa_global structure
*
- * Sends ProertyChanged signals informing that debug show_keys has changed.
+ * Sends PropertyChanged signals informing that debug show_keys has changed.
*/
void wpas_dbus_signal_debug_show_keys_changed(struct wpa_global *global)
{
@@ -850,36 +1917,44 @@ static const struct wpa_dbus_method_desc wpas_dbus_global_methods[] = {
END_ARGS
}
},
+#ifdef CONFIG_AUTOSCAN
+ { "AutoScan", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) &wpas_dbus_handler_autoscan,
+ {
+ { "arg", "s", ARG_IN },
+ END_ARGS
+ }
+ },
+#endif /* CONFIG_AUTOSCAN */
{ NULL, NULL, NULL, { END_ARGS } }
};
static const struct wpa_dbus_property_desc wpas_dbus_global_properties[] = {
{ "DebugLevel", WPAS_DBUS_NEW_INTERFACE, "s",
- (WPADBusPropertyAccessor) wpas_dbus_getter_debug_level,
- (WPADBusPropertyAccessor) wpas_dbus_setter_debug_level,
- RW
+ wpas_dbus_getter_debug_level,
+ wpas_dbus_setter_debug_level
},
{ "DebugTimestamp", WPAS_DBUS_NEW_INTERFACE, "b",
- (WPADBusPropertyAccessor) wpas_dbus_getter_debug_timestamp,
- (WPADBusPropertyAccessor) wpas_dbus_setter_debug_timestamp,
- RW
+ wpas_dbus_getter_debug_timestamp,
+ wpas_dbus_setter_debug_timestamp
},
{ "DebugShowKeys", WPAS_DBUS_NEW_INTERFACE, "b",
- (WPADBusPropertyAccessor) wpas_dbus_getter_debug_show_keys,
- (WPADBusPropertyAccessor) wpas_dbus_setter_debug_show_keys,
- RW
+ wpas_dbus_getter_debug_show_keys,
+ wpas_dbus_setter_debug_show_keys
},
{ "Interfaces", WPAS_DBUS_NEW_INTERFACE, "ao",
- (WPADBusPropertyAccessor) &wpas_dbus_getter_interfaces,
- NULL,
- R
+ wpas_dbus_getter_interfaces,
+ NULL
},
{ "EapMethods", WPAS_DBUS_NEW_INTERFACE, "as",
- (WPADBusPropertyAccessor) wpas_dbus_getter_eap_methods,
- NULL,
- R
+ wpas_dbus_getter_eap_methods,
+ NULL
+ },
+ { "Capabilities", WPAS_DBUS_NEW_INTERFACE, "as",
+ wpas_dbus_getter_global_capabilities,
+ NULL
},
- { NULL, NULL, NULL, NULL, NULL, 0 }
+ { NULL, NULL, NULL, NULL, NULL }
};
static const struct wpa_dbus_signal_desc wpas_dbus_global_signals[] = {
@@ -896,6 +1971,15 @@ static const struct wpa_dbus_signal_desc wpas_dbus_global_signals[] = {
END_ARGS
}
},
+ { "NetworkRequest", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ {
+ { "path", "o", ARG_OUT },
+ { "field", "s", ARG_OUT },
+ { "text", "s", ARG_OUT },
+ END_ARGS
+ }
+ },
+ /* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
{ "PropertiesChanged", WPAS_DBUS_NEW_INTERFACE,
{
{ "properties", "a{sv}", ARG_OUT },
@@ -972,20 +2056,19 @@ static void wpa_dbus_free(void *ptr)
static const struct wpa_dbus_property_desc wpas_dbus_network_properties[] = {
{ "Properties", WPAS_DBUS_NEW_IFACE_NETWORK, "a{sv}",
- (WPADBusPropertyAccessor) wpas_dbus_getter_network_properties,
- (WPADBusPropertyAccessor) wpas_dbus_setter_network_properties,
- RW
+ wpas_dbus_getter_network_properties,
+ wpas_dbus_setter_network_properties
},
{ "Enabled", WPAS_DBUS_NEW_IFACE_NETWORK, "b",
- (WPADBusPropertyAccessor) wpas_dbus_getter_enabled,
- (WPADBusPropertyAccessor) wpas_dbus_setter_enabled,
- RW
+ wpas_dbus_getter_enabled,
+ wpas_dbus_setter_enabled
},
- { NULL, NULL, NULL, NULL, NULL, 0 }
+ { NULL, NULL, NULL, NULL, NULL }
};
static const struct wpa_dbus_signal_desc wpas_dbus_network_signals[] = {
+ /* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_NETWORK,
{
{ "properties", "a{sv}", ARG_OUT },
@@ -1012,6 +2095,16 @@ int wpas_dbus_register_network(struct wpa_supplicant *wpa_s,
struct network_handler_args *arg;
char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+#ifdef CONFIG_P2P
+ /*
+ * If it is a persistent group register it as such.
+ * This is to handle cases where an interface is being initialized
+ * with a list of networks read from config.
+ */
+ if (network_is_persistent_group(ssid))
+ return wpas_dbus_register_persistent_group(wpa_s, ssid);
+#endif /* CONFIG_P2P */
+
/* Do nothing if the control interface is not turned on */
if (wpa_s == NULL || wpa_s->global == NULL)
return 0;
@@ -1074,10 +2167,18 @@ int wpas_dbus_unregister_network(struct wpa_supplicant *wpa_s, int nid)
struct wpas_dbus_priv *ctrl_iface;
char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
int ret;
+#ifdef CONFIG_P2P
+ struct wpa_ssid *ssid;
+
+ ssid = wpa_config_get_network(wpa_s->conf, nid);
+
+ /* If it is a persistent group unregister it as such */
+ if (ssid && network_is_persistent_group(ssid))
+ return wpas_dbus_unregister_persistent_group(wpa_s, nid);
+#endif /* CONFIG_P2P */
/* Do nothing if the control interface is not turned on */
- if (wpa_s == NULL || wpa_s->global == NULL ||
- wpa_s->dbus_new_path == NULL)
+ if (wpa_s->global == NULL || wpa_s->dbus_new_path == NULL)
return 0;
ctrl_iface = wpa_s->global->dbus;
if (ctrl_iface == NULL)
@@ -1100,60 +2201,55 @@ int wpas_dbus_unregister_network(struct wpa_supplicant *wpa_s, int nid)
static const struct wpa_dbus_property_desc wpas_dbus_bss_properties[] = {
{ "SSID", WPAS_DBUS_NEW_IFACE_BSS, "ay",
- (WPADBusPropertyAccessor) wpas_dbus_getter_bss_ssid,
- NULL,
- R
+ wpas_dbus_getter_bss_ssid,
+ NULL
},
{ "BSSID", WPAS_DBUS_NEW_IFACE_BSS, "ay",
- (WPADBusPropertyAccessor) wpas_dbus_getter_bss_bssid,
- NULL,
- R
+ wpas_dbus_getter_bss_bssid,
+ NULL
},
{ "Privacy", WPAS_DBUS_NEW_IFACE_BSS, "b",
- (WPADBusPropertyAccessor) wpas_dbus_getter_bss_privacy,
- NULL,
- R
+ wpas_dbus_getter_bss_privacy,
+ NULL
},
{ "Mode", WPAS_DBUS_NEW_IFACE_BSS, "s",
- (WPADBusPropertyAccessor) wpas_dbus_getter_bss_mode,
- NULL,
- R
+ wpas_dbus_getter_bss_mode,
+ NULL
},
{ "Signal", WPAS_DBUS_NEW_IFACE_BSS, "n",
- (WPADBusPropertyAccessor) wpas_dbus_getter_bss_signal,
- NULL,
- R
+ wpas_dbus_getter_bss_signal,
+ NULL
},
{ "Frequency", WPAS_DBUS_NEW_IFACE_BSS, "q",
- (WPADBusPropertyAccessor) wpas_dbus_getter_bss_frequency,
- NULL,
- R
+ wpas_dbus_getter_bss_frequency,
+ NULL
},
{ "Rates", WPAS_DBUS_NEW_IFACE_BSS, "au",
- (WPADBusPropertyAccessor) wpas_dbus_getter_bss_rates,
- NULL,
- R
+ wpas_dbus_getter_bss_rates,
+ NULL
},
{ "WPA", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
- (WPADBusPropertyAccessor) wpas_dbus_getter_bss_wpa,
- NULL,
- R
+ wpas_dbus_getter_bss_wpa,
+ NULL
},
{ "RSN", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
- (WPADBusPropertyAccessor) wpas_dbus_getter_bss_rsn,
- NULL,
- R
+ wpas_dbus_getter_bss_rsn,
+ NULL
+ },
+ { "WPS", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
+ wpas_dbus_getter_bss_wps,
+ NULL
},
{ "IEs", WPAS_DBUS_NEW_IFACE_BSS, "ay",
- (WPADBusPropertyAccessor) wpas_dbus_getter_bss_ies,
- NULL,
- R
+ wpas_dbus_getter_bss_ies,
+ NULL
},
- { NULL, NULL, NULL, NULL, NULL, 0 }
+ { NULL, NULL, NULL, NULL, NULL }
};
static const struct wpa_dbus_signal_desc wpas_dbus_bss_signals[] = {
+ /* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_BSS,
{
{ "properties", "a{sv}", ARG_OUT },
@@ -1199,6 +2295,7 @@ int wpas_dbus_unregister_bss(struct wpa_supplicant *wpa_s,
}
wpas_dbus_signal_bss_removed(wpa_s, bss_obj_path);
+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_BSSS);
return 0;
}
@@ -1263,6 +2360,7 @@ int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s,
}
wpas_dbus_signal_bss_added(wpa_s, bss_obj_path);
+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_BSSS);
return 0;
@@ -1294,6 +2392,12 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
END_ARGS
}
},
+ { "Reassociate", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) &wpas_dbus_handler_reassociate,
+ {
+ END_ARGS
+ }
+ },
{ "RemoveNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
(WPADBusMethodHandler) &wpas_dbus_handler_remove_network,
{
@@ -1301,6 +2405,12 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
END_ARGS
}
},
+ { "RemoveAllNetworks", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) &wpas_dbus_handler_remove_all_networks,
+ {
+ END_ARGS
+ }
+ },
{ "SelectNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
(WPADBusMethodHandler) &wpas_dbus_handler_select_network,
{
@@ -1308,6 +2418,15 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
END_ARGS
}
},
+ { "NetworkReply", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) &wpas_dbus_handler_network_reply,
+ {
+ { "path", "o", ARG_IN },
+ { "field", "s", ARG_IN },
+ { "value", "s", ARG_IN },
+ END_ARGS
+ }
+ },
{ "AddBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
(WPADBusMethodHandler) &wpas_dbus_handler_add_blob,
{
@@ -1341,67 +2460,308 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
}
},
#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+ { "Find", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_find,
+ {
+ { "args", "a{sv}", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "StopFind", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_stop_find,
+ {
+ END_ARGS
+ }
+ },
+ { "Listen", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_listen,
+ {
+ { "timeout", "i", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "ExtendedListen", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_extendedlisten,
+ {
+ { "args", "a{sv}", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "PresenceRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_presence_request,
+ {
+ { "args", "a{sv}", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "ProvisionDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_prov_disc_req,
+ {
+ { "peer", "o", ARG_IN },
+ { "config_method", "s", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "Connect", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_connect,
+ {
+ { "args", "a{sv}", ARG_IN },
+ { "generated_pin", "s", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "GroupAdd", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_group_add,
+ {
+ { "args", "a{sv}", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "Invite", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_invite,
+ {
+ { "args", "a{sv}", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "Disconnect", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_disconnect,
+ {
+ END_ARGS
+ }
+ },
+ { "RejectPeer", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_rejectpeer,
+ {
+ { "peer", "o", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "Flush", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_flush,
+ {
+ END_ARGS
+ }
+ },
+ { "AddService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_add_service,
+ {
+ { "args", "a{sv}", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "DeleteService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_delete_service,
+ {
+ { "args", "a{sv}", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "FlushService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_flush_service,
+ {
+ END_ARGS
+ }
+ },
+ { "ServiceDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_req,
+ {
+ { "args", "a{sv}", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "ServiceDiscoveryResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_res,
+ {
+ { "args", "a{sv}", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "ServiceDiscoveryCancelRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_cancel_req,
+ {
+ { "args", "t", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "ServiceUpdate", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_update,
+ {
+ END_ARGS
+ }
+ },
+ { "ServiceDiscoveryExternal", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_serv_disc_external,
+ {
+ { "arg", "i", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "ServiceDiscoveryExternal", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_serv_disc_external,
+ {
+ { "arg", "i", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "AddPersistentGroup", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler) wpas_dbus_handler_add_persistent_group,
+ {
+ { "args", "a{sv}", ARG_IN },
+ { "path", "o", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "RemovePersistentGroup", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler) wpas_dbus_handler_remove_persistent_group,
+ {
+ { "path", "o", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "RemoveAllPersistentGroups", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)
+ wpas_dbus_handler_remove_all_persistent_groups,
+ {
+ END_ARGS
+ }
+ },
+#endif /* CONFIG_P2P */
+ { "FlushBSS", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) &wpas_dbus_handler_flush_bss,
+ {
+ { "age", "u", ARG_IN },
+ END_ARGS
+ }
+ },
+#ifdef CONFIG_AP
+ { "SubscribeProbeReq", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_subscribe_preq,
+ {
+ END_ARGS
+ }
+ },
+ { "UnsubscribeProbeReq", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_unsubscribe_preq,
+ {
+ END_ARGS
+ }
+ },
+#endif /* CONFIG_AP */
{ NULL, NULL, NULL, { END_ARGS } }
};
static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
{ "Capabilities", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{sv}",
- (WPADBusPropertyAccessor) wpas_dbus_getter_capabilities,
- NULL, R
+ wpas_dbus_getter_capabilities,
+ NULL
},
{ "State", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
- (WPADBusPropertyAccessor) wpas_dbus_getter_state,
- NULL, R
+ wpas_dbus_getter_state,
+ NULL
},
{ "Scanning", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
- (WPADBusPropertyAccessor) wpas_dbus_getter_scanning,
- NULL, R
+ wpas_dbus_getter_scanning,
+ NULL
},
{ "ApScan", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
- (WPADBusPropertyAccessor) wpas_dbus_getter_ap_scan,
- (WPADBusPropertyAccessor) wpas_dbus_setter_ap_scan,
- RW
+ wpas_dbus_getter_ap_scan,
+ wpas_dbus_setter_ap_scan
+ },
+ { "BSSExpireAge", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
+ wpas_dbus_getter_bss_expire_age,
+ wpas_dbus_setter_bss_expire_age
+ },
+ { "BSSExpireCount", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
+ wpas_dbus_getter_bss_expire_count,
+ wpas_dbus_setter_bss_expire_count
+ },
+ { "Country", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
+ wpas_dbus_getter_country,
+ wpas_dbus_setter_country
},
{ "Ifname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
- (WPADBusPropertyAccessor) wpas_dbus_getter_ifname,
- NULL, R
+ wpas_dbus_getter_ifname,
+ NULL
},
{ "Driver", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
- (WPADBusPropertyAccessor) wpas_dbus_getter_driver,
- NULL, R
+ wpas_dbus_getter_driver,
+ NULL
},
{ "BridgeIfname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
- (WPADBusPropertyAccessor) wpas_dbus_getter_bridge_ifname,
- NULL, R
+ wpas_dbus_getter_bridge_ifname,
+ NULL
},
{ "CurrentBSS", WPAS_DBUS_NEW_IFACE_INTERFACE, "o",
- (WPADBusPropertyAccessor) wpas_dbus_getter_current_bss,
- NULL, R
+ wpas_dbus_getter_current_bss,
+ NULL
},
{ "CurrentNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE, "o",
- (WPADBusPropertyAccessor) wpas_dbus_getter_current_network,
- NULL, R
+ wpas_dbus_getter_current_network,
+ NULL
+ },
+ { "CurrentAuthMode", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
+ wpas_dbus_getter_current_auth_mode,
+ NULL
},
{ "Blobs", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{say}",
- (WPADBusPropertyAccessor) wpas_dbus_getter_blobs,
- NULL, R
+ wpas_dbus_getter_blobs,
+ NULL
},
{ "BSSs", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
- (WPADBusPropertyAccessor) wpas_dbus_getter_bsss,
- NULL, R
+ wpas_dbus_getter_bsss,
+ NULL
},
{ "Networks", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
- (WPADBusPropertyAccessor) wpas_dbus_getter_networks,
- NULL, R
+ wpas_dbus_getter_networks,
+ NULL
+ },
+ { "FastReauth", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
+ wpas_dbus_getter_fast_reauth,
+ wpas_dbus_setter_fast_reauth
+ },
+ { "ScanInterval", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
+ wpas_dbus_getter_scan_interval,
+ wpas_dbus_setter_scan_interval
},
#ifdef CONFIG_WPS
{ "ProcessCredentials", WPAS_DBUS_NEW_IFACE_WPS, "b",
- (WPADBusPropertyAccessor) wpas_dbus_getter_process_credentials,
- (WPADBusPropertyAccessor) wpas_dbus_setter_process_credentials,
- RW
+ wpas_dbus_getter_process_credentials,
+ wpas_dbus_setter_process_credentials
},
#endif /* CONFIG_WPS */
- { NULL, NULL, NULL, NULL, NULL, 0 }
+#ifdef CONFIG_P2P
+ { "P2PDeviceConfig", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "a{sv}",
+ wpas_dbus_getter_p2p_device_config,
+ wpas_dbus_setter_p2p_device_config
+ },
+ { "Peers", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao",
+ wpas_dbus_getter_p2p_peers,
+ NULL
+ },
+ { "Role", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "s",
+ wpas_dbus_getter_p2p_role,
+ NULL
+ },
+ { "Group", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "o",
+ wpas_dbus_getter_p2p_group,
+ NULL
+ },
+ { "PeerGO", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "o",
+ wpas_dbus_getter_p2p_peergo,
+ NULL
+ },
+ { "PersistentGroups", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao",
+ wpas_dbus_getter_persistent_groups,
+ NULL
+ },
+#endif /* CONFIG_P2P */
+ { "DisconnectReason", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
+ wpas_dbus_getter_disconnect_reason,
+ NULL
+ },
+ { NULL, NULL, NULL, NULL, NULL }
};
static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
@@ -1455,6 +2815,7 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
END_ARGS
}
},
+ /* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_INTERFACE,
{
{ "properties", "a{sv}", ARG_OUT },
@@ -1475,6 +2836,7 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
END_ARGS
}
},
+ /* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_WPS,
{
{ "properties", "a{sv}", ARG_OUT },
@@ -1482,6 +2844,162 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
}
},
#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+ { "P2PStateChanged", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "states", "a{ss}", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "DeviceFound", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "path", "o", ARG_OUT },
+ { "properties", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "DeviceLost", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "path", "o", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "ProvisionDiscoveryRequestDisplayPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "peer_object", "o", ARG_OUT },
+ { "pin", "s", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "ProvisionDiscoveryResponseDisplayPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "peer_object", "o", ARG_OUT },
+ { "pin", "s", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "ProvisionDiscoveryRequestEnterPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "peer_object", "o", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "ProvisionDiscoveryResponseEnterPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "peer_object", "o", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "ProvisionDiscoveryPBCRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "peer_object", "o", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "ProvisionDiscoveryPBCResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "peer_object", "o", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "ProvisionDiscoveryFailure", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "peer_object", "o", ARG_OUT },
+ { "status", "i", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "GroupStarted", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "properties", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "GONegotiationSuccess", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ END_ARGS
+ }
+ },
+ { "GONegotiationFailure", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "status", "i", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "GONegotiationRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "path", "o", ARG_OUT },
+ { "dev_passwd_id", "i", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "InvitationResult", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "invite_result", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "GroupFinished", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "ifname", "s", ARG_OUT },
+ { "role", "s", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "ServiceDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "sd_request", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "ServiceDiscoveryResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "sd_response", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "PersistentGroupAdded", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "path", "o", ARG_OUT },
+ { "properties", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "PersistentGroupRemoved", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "path", "o", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "WpsFailed", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "name", "s", ARG_OUT },
+ { "args", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_AP
+ { "ProbeRequest", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ {
+ { "args", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+#endif /* CONFIG_AP */
+ { "Certification", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ {
+ { "certification", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "EAP", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ {
+ { "status", "s", ARG_OUT },
+ { "parameter", "s", ARG_OUT },
+ END_ARGS
+ }
+ },
{ NULL, NULL, { END_ARGS } }
};
@@ -1549,6 +3067,15 @@ int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s)
wpa_printf(MSG_DEBUG, "dbus: Unregister interface object '%s'",
wpa_s->dbus_new_path);
+
+#ifdef CONFIG_AP
+ if (wpa_s->preq_notify_peer) {
+ wpas_dbus_unsubscribe_noc(ctrl_iface);
+ os_free(wpa_s->preq_notify_peer);
+ wpa_s->preq_notify_peer = NULL;
+ }
+#endif /* CONFIG_AP */
+
if (wpa_dbus_unregister_object_per_iface(ctrl_iface,
wpa_s->dbus_new_path))
return -1;
@@ -1560,3 +3087,624 @@ int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s)
return 0;
}
+
+#ifdef CONFIG_P2P
+
+static const struct wpa_dbus_property_desc wpas_dbus_p2p_peer_properties[] = {
+ { "DeviceName", WPAS_DBUS_NEW_IFACE_P2P_PEER, "s",
+ wpas_dbus_getter_p2p_peer_device_name,
+ NULL
+ },
+ { "PrimaryDeviceType", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
+ wpas_dbus_getter_p2p_peer_primary_device_type,
+ NULL
+ },
+ { "config_method", WPAS_DBUS_NEW_IFACE_P2P_PEER, "q",
+ wpas_dbus_getter_p2p_peer_config_method,
+ NULL
+ },
+ { "level", WPAS_DBUS_NEW_IFACE_P2P_PEER, "i",
+ wpas_dbus_getter_p2p_peer_level,
+ NULL
+ },
+ { "devicecapability", WPAS_DBUS_NEW_IFACE_P2P_PEER, "y",
+ wpas_dbus_getter_p2p_peer_device_capability,
+ NULL
+ },
+ { "groupcapability", WPAS_DBUS_NEW_IFACE_P2P_PEER, "y",
+ wpas_dbus_getter_p2p_peer_group_capability,
+ NULL
+ },
+ { "SecondaryDeviceTypes", WPAS_DBUS_NEW_IFACE_P2P_PEER, "aay",
+ wpas_dbus_getter_p2p_peer_secondary_device_types,
+ NULL
+ },
+ { "VendorExtension", WPAS_DBUS_NEW_IFACE_P2P_PEER, "aay",
+ wpas_dbus_getter_p2p_peer_vendor_extension,
+ NULL
+ },
+ { "IEs", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
+ wpas_dbus_getter_p2p_peer_ies,
+ NULL
+ },
+ { NULL, NULL, NULL, NULL, NULL }
+};
+
+static const struct wpa_dbus_signal_desc wpas_dbus_p2p_peer_signals[] = {
+
+ { NULL, NULL, { END_ARGS } }
+};
+
+/**
+ * wpas_dbus_signal_peer - Send a peer related event signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @dev: peer device object
+ * @interface: name of the interface emitting this signal.
+ * In case of peer objects, it would be emitted by either
+ * the "interface object" or by "peer objects"
+ * @sig_name: signal name - DeviceFound
+ *
+ * Notify listeners about event related with newly found p2p peer device
+ */
+static void wpas_dbus_signal_peer(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr, const char *interface,
+ const char *sig_name)
+{
+ struct wpas_dbus_priv *iface;
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
+ wpa_s->dbus_new_path, MAC2STR(dev_addr));
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path, interface,
+ sig_name);
+ if (msg == NULL)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+ path = peer_obj_path;
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+ &path))
+ goto err;
+
+ dbus_connection_send(iface->con, msg, NULL);
+
+ dbus_message_unref(msg);
+ return;
+
+err:
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_peer_found - Send a peer found signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @dev: peer device object
+ *
+ * Notify listeners about find a p2p peer device found
+ */
+void wpas_dbus_signal_peer_device_found(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr)
+{
+ wpas_dbus_signal_peer(wpa_s, dev_addr,
+ WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ "DeviceFound");
+}
+
+/**
+ * wpas_dbus_signal_peer_lost - Send a peer lost signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @dev: peer device object
+ *
+ * Notify listeners about lost a p2p peer device
+ */
+void wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr)
+{
+ wpas_dbus_signal_peer(wpa_s, dev_addr,
+ WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ "DeviceLost");
+}
+
+/**
+ * wpas_dbus_register_peer - Register a discovered peer object with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @ssid: network configuration data
+ * Returns: 0 on success, -1 on failure
+ *
+ * Registers network representing object with dbus
+ */
+int wpas_dbus_register_peer(struct wpa_supplicant *wpa_s, const u8 *dev_addr)
+{
+ struct wpas_dbus_priv *ctrl_iface;
+ struct wpa_dbus_object_desc *obj_desc;
+ struct peer_handler_args *arg;
+ char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+ /* 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;
+ if (ctrl_iface == NULL)
+ return 0;
+
+ os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
+ wpa_s->dbus_new_path, MAC2STR(dev_addr));
+
+ wpa_printf(MSG_INFO, "dbus: Register peer object '%s'",
+ peer_obj_path);
+ obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
+ if (!obj_desc) {
+ wpa_printf(MSG_ERROR, "Not enough memory "
+ "to create object description");
+ goto err;
+ }
+
+ /* allocate memory for handlers arguments */
+ arg = os_zalloc(sizeof(struct peer_handler_args));
+ if (!arg) {
+ wpa_printf(MSG_ERROR, "Not enough memory "
+ "to create arguments for method");
+ goto err;
+ }
+
+ arg->wpa_s = wpa_s;
+ os_memcpy(arg->p2p_device_addr, dev_addr, ETH_ALEN);
+
+ wpas_dbus_register(obj_desc, arg, wpa_dbus_free,
+ NULL,
+ wpas_dbus_p2p_peer_properties,
+ wpas_dbus_p2p_peer_signals);
+
+ if (wpa_dbus_register_object_per_iface(ctrl_iface, peer_obj_path,
+ wpa_s->ifname, obj_desc))
+ goto err;
+
+ return 0;
+
+err:
+ free_dbus_object_desc(obj_desc);
+ return -1;
+}
+
+/**
+ * wpas_dbus_unregister_peer - Unregister a peer object with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @dev_addr: p2p device addr
+ * Returns: 0 on success, -1 on failure
+ *
+ * Registers network representing object with dbus
+ */
+int wpas_dbus_unregister_peer(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr)
+{
+ struct wpas_dbus_priv *ctrl_iface;
+ char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+ int ret;
+
+ /* Do nothing if the control interface is not turned on */
+ if (wpa_s == NULL || wpa_s->global == NULL ||
+ wpa_s->dbus_new_path == NULL)
+ return 0;
+ ctrl_iface = wpa_s->global->dbus;
+ if (ctrl_iface == NULL)
+ return 0;
+
+ os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
+ wpa_s->dbus_new_path, MAC2STR(dev_addr));
+
+ wpa_printf(MSG_INFO, "dbus: Unregister peer object '%s'",
+ peer_obj_path);
+ ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, peer_obj_path);
+
+ return ret;
+}
+
+
+static const struct wpa_dbus_property_desc wpas_dbus_p2p_group_properties[] = {
+ { "Members", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ao",
+ wpas_dbus_getter_p2p_group_members,
+ NULL
+ },
+ { "Group", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "o",
+ wpas_dbus_getter_p2p_group,
+ NULL
+ },
+ { "Role", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "s",
+ wpas_dbus_getter_p2p_role,
+ NULL
+ },
+ { "SSID", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay",
+ wpas_dbus_getter_p2p_group_ssid,
+ NULL
+ },
+ { "BSSID", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay",
+ wpas_dbus_getter_p2p_group_bssid,
+ NULL
+ },
+ { "Frequency", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "q",
+ wpas_dbus_getter_p2p_group_frequency,
+ NULL
+ },
+ { "Passphrase", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "s",
+ wpas_dbus_getter_p2p_group_passphrase,
+ NULL
+ },
+ { "PSK", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay",
+ wpas_dbus_getter_p2p_group_psk,
+ NULL
+ },
+ { "WPSVendorExtensions", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "aay",
+ wpas_dbus_getter_p2p_group_vendor_ext,
+ wpas_dbus_setter_p2p_group_vendor_ext
+ },
+ { NULL, NULL, NULL, NULL, NULL }
+};
+
+static const struct wpa_dbus_signal_desc wpas_dbus_p2p_group_signals[] = {
+ { "PeerJoined", WPAS_DBUS_NEW_IFACE_P2P_GROUP,
+ {
+ { "peer", "o", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "PeerDisconnected", WPAS_DBUS_NEW_IFACE_P2P_GROUP,
+ {
+ { "peer", "o", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { NULL, NULL, { END_ARGS } }
+};
+
+/**
+ * wpas_dbus_register_p2p_group - Register a p2p group object with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @ssid: SSID struct
+ * Returns: 0 on success, -1 on failure
+ *
+ * Registers p2p group representing object with dbus
+ */
+void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ struct wpas_dbus_priv *ctrl_iface;
+ struct wpa_dbus_object_desc *obj_desc;
+ char group_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+ /* Do nothing if the control interface is not turned on */
+ if (wpa_s == NULL || wpa_s->global == NULL)
+ return;
+
+ ctrl_iface = wpa_s->global->dbus;
+ if (ctrl_iface == NULL)
+ return;
+
+ if (wpa_s->dbus_groupobj_path) {
+ wpa_printf(MSG_INFO, "%s: Group object '%s' already exists",
+ __func__, wpa_s->dbus_groupobj_path);
+ return;
+ }
+
+ if (wpas_dbus_get_group_obj_path(wpa_s, ssid, group_obj_path) < 0)
+ return;
+
+ wpa_s->dbus_groupobj_path = os_strdup(group_obj_path);
+ if (wpa_s->dbus_groupobj_path == NULL)
+ return;
+
+ wpa_printf(MSG_INFO, "dbus: Register group object '%s'",
+ group_obj_path);
+ obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
+ if (!obj_desc) {
+ wpa_printf(MSG_ERROR, "Not enough memory "
+ "to create object description");
+ goto err;
+ }
+
+ wpas_dbus_register(obj_desc, wpa_s, NULL, NULL,
+ wpas_dbus_p2p_group_properties,
+ wpas_dbus_p2p_group_signals);
+
+ if (wpa_dbus_register_object_per_iface(ctrl_iface, group_obj_path,
+ wpa_s->ifname, obj_desc))
+ goto err;
+
+ return;
+
+err:
+ if (wpa_s->dbus_groupobj_path) {
+ os_free(wpa_s->dbus_groupobj_path);
+ wpa_s->dbus_groupobj_path = NULL;
+ }
+
+ free_dbus_object_desc(obj_desc);
+}
+
+/**
+ * wpas_dbus_unregister_p2p_group - Unregister a p2p group object from dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @ssid: network name of the p2p group started
+ */
+void wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid *ssid)
+{
+ struct wpas_dbus_priv *ctrl_iface;
+
+ /* Do nothing if the control interface is not turned on */
+ if (wpa_s == NULL || wpa_s->global == NULL)
+ return;
+
+ ctrl_iface = wpa_s->global->dbus;
+ if (ctrl_iface == NULL)
+ return;
+
+ if (!wpa_s->dbus_groupobj_path) {
+ wpa_printf(MSG_DEBUG,
+ "%s: Group object '%s' already unregistered",
+ __func__, wpa_s->dbus_groupobj_path);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "dbus: Unregister group object '%s'",
+ wpa_s->dbus_groupobj_path);
+
+ wpa_dbus_unregister_object_per_iface(ctrl_iface,
+ wpa_s->dbus_groupobj_path);
+
+ os_free(wpa_s->dbus_groupobj_path);
+ wpa_s->dbus_groupobj_path = NULL;
+}
+
+static const struct wpa_dbus_property_desc
+wpas_dbus_p2p_groupmember_properties[] = {
+ { NULL, NULL, NULL, NULL, NULL }
+};
+
+/**
+ * wpas_dbus_register_p2p_groupmember - Register a p2p groupmember
+ * object with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @p2p_if_addr: i/f addr of the device joining this group
+ *
+ * Registers p2p groupmember representing object with dbus
+ */
+void wpas_dbus_register_p2p_groupmember(struct wpa_supplicant *wpa_s,
+ const u8 *p2p_if_addr)
+{
+ struct wpas_dbus_priv *ctrl_iface;
+ struct wpa_dbus_object_desc *obj_desc = NULL;
+ struct groupmember_handler_args *arg;
+ char groupmember_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+ /* Do nothing if the control interface is not turned on */
+ if (wpa_s == NULL || wpa_s->global == NULL)
+ return;
+
+ ctrl_iface = wpa_s->global->dbus;
+ if (ctrl_iface == NULL)
+ return;
+
+ if (!wpa_s->dbus_groupobj_path)
+ return;
+
+ os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/" COMPACT_MACSTR,
+ wpa_s->dbus_groupobj_path, MAC2STR(p2p_if_addr));
+
+ obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
+ if (!obj_desc) {
+ wpa_printf(MSG_ERROR, "Not enough memory "
+ "to create object description");
+ goto err;
+ }
+
+ /* allocate memory for handlers arguments */
+ arg = os_zalloc(sizeof(struct groupmember_handler_args));
+ if (!arg) {
+ wpa_printf(MSG_ERROR, "Not enough memory "
+ "to create arguments for method");
+ goto err;
+ }
+
+ arg->wpa_s = wpa_s;
+ os_memcpy(arg->member_addr, p2p_if_addr, ETH_ALEN);
+
+ wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
+ wpas_dbus_p2p_groupmember_properties, NULL);
+
+ if (wpa_dbus_register_object_per_iface(ctrl_iface, groupmember_obj_path,
+ wpa_s->ifname, obj_desc))
+ goto err;
+
+ wpa_printf(MSG_INFO,
+ "dbus: Registered group member object '%s' successfully",
+ groupmember_obj_path);
+ return;
+
+err:
+ free_dbus_object_desc(obj_desc);
+}
+
+/**
+ * wpas_dbus_unregister_p2p_groupmember - Unregister a p2p groupmember
+ * object with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @p2p_if_addr: i/f addr of the device joining this group
+ *
+ * Unregisters p2p groupmember representing object with dbus
+ */
+void wpas_dbus_unregister_p2p_groupmember(struct wpa_supplicant *wpa_s,
+ const u8 *p2p_if_addr)
+{
+ struct wpas_dbus_priv *ctrl_iface;
+ char groupmember_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+ /* Do nothing if the control interface is not turned on */
+ if (wpa_s == NULL || wpa_s->global == NULL)
+ return;
+
+ ctrl_iface = wpa_s->global->dbus;
+ if (ctrl_iface == NULL)
+ return;
+
+ if (!wpa_s->dbus_groupobj_path)
+ return;
+
+ os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/" COMPACT_MACSTR,
+ wpa_s->dbus_groupobj_path, MAC2STR(p2p_if_addr));
+
+ wpa_dbus_unregister_object_per_iface(ctrl_iface, groupmember_obj_path);
+}
+
+
+static const struct wpa_dbus_property_desc
+ wpas_dbus_persistent_group_properties[] = {
+ { "Properties", WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, "a{sv}",
+ wpas_dbus_getter_persistent_group_properties,
+ wpas_dbus_setter_persistent_group_properties
+ },
+ { NULL, NULL, NULL, NULL, NULL }
+};
+
+/* No signals intended for persistent group objects */
+
+/**
+ * wpas_dbus_register_persistent_group - Register a configured(saved)
+ * persistent group with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @ssid: persistent group (still represented as a network within wpa)
+ * configuration data
+ * Returns: 0 on success, -1 on failure
+ *
+ * Registers a persistent group representing object with dbus.
+ */
+int wpas_dbus_register_persistent_group(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ struct wpas_dbus_priv *ctrl_iface;
+ struct wpa_dbus_object_desc *obj_desc;
+ struct network_handler_args *arg;
+ char pgrp_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+ /* Do nothing if the control interface is not turned on */
+ if (wpa_s == NULL || wpa_s->global == NULL)
+ return 0;
+
+ /* Make sure ssid is a persistent group */
+ if (ssid->disabled != 2 && !ssid->p2p_persistent_group)
+ return -1; /* should we return w/o complaining? */
+
+ ctrl_iface = wpa_s->global->dbus;
+ if (ctrl_iface == NULL)
+ return 0;
+
+ /*
+ * Intentionally not coming up with different numbering scheme
+ * for persistent groups.
+ */
+ os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u",
+ wpa_s->dbus_new_path, ssid->id);
+
+ wpa_printf(MSG_DEBUG, "dbus: Register persistent group object '%s'",
+ pgrp_obj_path);
+ obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
+ if (!obj_desc) {
+ wpa_printf(MSG_ERROR, "dbus: Not enough memory to create "
+ "object description");
+ goto err;
+ }
+
+ /*
+ * Reusing the same context structure as that for networks
+ * since these are represented using same data structure.
+ */
+ /* allocate memory for handlers arguments */
+ arg = os_zalloc(sizeof(struct network_handler_args));
+ if (!arg) {
+ wpa_printf(MSG_ERROR, "dbus: Not enough memory to create "
+ "arguments for method");
+ goto err;
+ }
+
+ arg->wpa_s = wpa_s;
+ arg->ssid = ssid;
+
+ wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
+ wpas_dbus_persistent_group_properties,
+ NULL);
+
+ if (wpa_dbus_register_object_per_iface(ctrl_iface, pgrp_obj_path,
+ wpa_s->ifname, obj_desc))
+ goto err;
+
+ wpas_dbus_signal_persistent_group_added(wpa_s, ssid->id);
+
+ return 0;
+
+err:
+ free_dbus_object_desc(obj_desc);
+ return -1;
+}
+
+
+/**
+ * wpas_dbus_unregister_persistent_group - Unregister a persistent_group
+ * from dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @nid: network id
+ * Returns: 0 on success, -1 on failure
+ *
+ * Unregisters persistent group representing object from dbus
+ *
+ * NOTE: There is a slight issue with the semantics here. While the
+ * implementation simply means the persistent group is unloaded from memory,
+ * it should not get interpreted as the group is actually being erased/removed
+ * from persistent storage as well.
+ */
+int wpas_dbus_unregister_persistent_group(struct wpa_supplicant *wpa_s,
+ int nid)
+{
+ struct wpas_dbus_priv *ctrl_iface;
+ char pgrp_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+ int ret;
+
+ /* Do nothing if the control interface is not turned on */
+ if (wpa_s == NULL || wpa_s->global == NULL ||
+ wpa_s->dbus_new_path == NULL)
+ return 0;
+ ctrl_iface = wpa_s->global->dbus;
+ if (ctrl_iface == NULL)
+ return 0;
+
+ os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u",
+ wpa_s->dbus_new_path, nid);
+
+ wpa_printf(MSG_DEBUG, "dbus: Unregister persistent group object '%s'",
+ pgrp_obj_path);
+ ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, pgrp_obj_path);
+
+ if (!ret)
+ wpas_dbus_signal_persistent_group_removed(wpa_s, nid);
+
+ return ret;
+}
+
+#endif /* CONFIG_P2P */
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index 80ea98c26e23..363a7e5d33c1 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -3,26 +3,22 @@
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
* Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#ifndef CTRL_IFACE_DBUS_NEW_H
#define CTRL_IFACE_DBUS_NEW_H
+#include "common/defs.h"
+#include "p2p/p2p.h"
+
struct wpa_global;
struct wpa_supplicant;
struct wpa_ssid;
struct wps_event_m2d;
struct wps_event_fail;
struct wps_credential;
-enum wpa_states;
enum wpas_dbus_prop {
WPAS_DBUS_PROP_AP_SCAN,
@@ -30,6 +26,9 @@ enum wpas_dbus_prop {
WPAS_DBUS_PROP_STATE,
WPAS_DBUS_PROP_CURRENT_BSS,
WPAS_DBUS_PROP_CURRENT_NETWORK,
+ WPAS_DBUS_PROP_CURRENT_AUTH_MODE,
+ WPAS_DBUS_PROP_BSSS,
+ WPAS_DBUS_PROP_DISCONNECT_REASON,
};
enum wpas_dbus_bss_prop {
@@ -40,6 +39,7 @@ enum wpas_dbus_bss_prop {
WPAS_DBUS_BSS_PROP_RATES,
WPAS_DBUS_BSS_PROP_WPA,
WPAS_DBUS_BSS_PROP_RSN,
+ WPAS_DBUS_BSS_PROP_WPS,
WPAS_DBUS_BSS_PROP_IES,
};
@@ -59,6 +59,29 @@ enum wpas_dbus_bss_prop {
#define WPAS_DBUS_NEW_BSSIDS_PART "BSSs"
#define WPAS_DBUS_NEW_IFACE_BSS WPAS_DBUS_NEW_INTERFACE ".BSS"
+#define WPAS_DBUS_NEW_IFACE_P2PDEVICE \
+ WPAS_DBUS_NEW_IFACE_INTERFACE ".P2PDevice"
+
+/*
+ * Groups correspond to P2P groups where this device is a GO (owner)
+ */
+#define WPAS_DBUS_NEW_P2P_GROUPS_PART "Groups"
+#define WPAS_DBUS_NEW_IFACE_P2P_GROUP WPAS_DBUS_NEW_INTERFACE ".Group"
+
+/*
+ * Different dbus object for persistent groups so they do not get confused
+ * with regular (configured) network objects.
+ */
+#define WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "PersistentGroups"
+#define WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP \
+ WPAS_DBUS_NEW_INTERFACE ".PersistentGroup"
+
+#define WPAS_DBUS_NEW_P2P_PEERS_PART "Peers"
+#define WPAS_DBUS_NEW_IFACE_P2P_PEER WPAS_DBUS_NEW_INTERFACE ".Peer"
+
+#define WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "Members"
+#define WPAS_DBUS_NEW_IFACE_P2P_GROUPMEMBER \
+ WPAS_DBUS_NEW_INTERFACE ".GroupMember"
/* Errors */
#define WPAS_DBUS_ERROR_UNKNOWN_ERROR \
@@ -76,11 +99,29 @@ enum wpas_dbus_bss_prop {
#define WPAS_DBUS_ERROR_NETWORK_UNKNOWN \
WPAS_DBUS_NEW_INTERFACE ".NetworkUnknown"
+#define WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNAVAILABLE \
+ WPAS_DBUS_NEW_INTERFACE ".ConnectChannelUnavailable"
+#define WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNSUPPORTED \
+ WPAS_DBUS_NEW_INTERFACE ".ConnectChannelUnsupported"
+#define WPAS_DBUS_ERROR_CONNECT_UNSPECIFIED_ERROR \
+ WPAS_DBUS_NEW_INTERFACE ".ConnectUnspecifiedError"
+
#define WPAS_DBUS_ERROR_BLOB_EXISTS \
WPAS_DBUS_NEW_INTERFACE ".BlobExists"
#define WPAS_DBUS_ERROR_BLOB_UNKNOWN \
WPAS_DBUS_NEW_INTERFACE ".BlobUnknown"
+#define WPAS_DBUS_ERROR_SUBSCRIPTION_IN_USE \
+ WPAS_DBUS_NEW_INTERFACE ".SubscriptionInUse"
+#define WPAS_DBUS_ERROR_NO_SUBSCRIPTION \
+ WPAS_DBUS_NEW_INTERFACE ".NoSubscription"
+#define WPAS_DBUS_ERROR_SUBSCRIPTION_EPERM \
+ WPAS_DBUS_NEW_INTERFACE ".SubscriptionNotYou"
+
+
+void wpas_dbus_subscribe_noc(struct wpas_dbus_priv *priv);
+void wpas_dbus_unsubscribe_noc(struct wpas_dbus_priv *priv);
+
#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
@@ -97,6 +138,10 @@ void wpas_dbus_bss_signal_prop_changed(struct wpa_supplicant *wpa_s,
void wpas_dbus_signal_network_enabled_changed(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
void wpas_dbus_signal_network_selected(struct wpa_supplicant *wpa_s, int id);
+void wpas_dbus_signal_network_request(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ enum wpa_ctrl_req_type rtype,
+ const char *default_text);
void wpas_dbus_signal_scan_done(struct wpa_supplicant *wpa_s, int success);
void wpas_dbus_signal_wps_cred(struct wpa_supplicant *wpa_s,
const struct wps_credential *cred);
@@ -120,6 +165,64 @@ void wpas_dbus_signal_debug_level_changed(struct wpa_global *global);
void wpas_dbus_signal_debug_timestamp_changed(struct wpa_global *global);
void wpas_dbus_signal_debug_show_keys_changed(struct wpa_global *global);
+int wpas_dbus_register_peer(struct wpa_supplicant *wpa_s, const u8 *dev_addr);
+void wpas_dbus_signal_peer_device_found(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr);
+int wpas_dbus_unregister_peer(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr);
+void wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr);
+void wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s,
+ const char *role);
+void wpas_dbus_signal_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr, int request,
+ enum p2p_prov_disc_status status,
+ u16 config_methods,
+ unsigned int generated_pin);
+void wpas_dbus_signal_p2p_go_neg_req(struct wpa_supplicant *wpa_s,
+ const u8 *src, u16 dev_passwd_id);
+void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid *ssid,
+ int client, int network_id);
+void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
+void wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s,
+ struct p2p_go_neg_results *res);
+void wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid *ssid);
+int wpas_dbus_register_persistent_group(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
+int wpas_dbus_unregister_persistent_group(struct wpa_supplicant *wpa_s,
+ int nid);
+void wpas_dbus_signal_p2p_invitation_result(struct wpa_supplicant *wpa_s,
+ int status, const u8 *bssid);
+void wpas_dbus_register_p2p_groupmember(struct wpa_supplicant *wpa_s,
+ const u8 *p2p_if_addr);
+void wpas_dbus_unregister_p2p_groupmember(struct wpa_supplicant *wpa_s,
+ const u8 *p2p_if_addr);
+void wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s,
+ const u8 *member);
+void wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s,
+ int freq, const u8 *sa, u8 dialog_token,
+ u16 update_indic, const u8 *tlvs,
+ size_t tlvs_len);
+void wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s,
+ const u8 *sa, u16 update_indic,
+ const u8 *tlvs, size_t tlvs_len);
+void wpas_dbus_signal_p2p_peer_joined(struct wpa_supplicant *wpa_s,
+ const u8 *member);
+void wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+ struct wps_event_fail *fail);
+void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
+ int depth, const char *subject,
+ const char *cert_hash,
+ const struct wpabuf *cert);
+void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
+ const u8 *addr, const u8 *dst, const u8 *bssid,
+ const u8 *ie, size_t ie_len, u32 ssi_signal);
+void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s,
+ const char *status, const char *parameter);
+
#else /* CONFIG_CTRL_IFACE_DBUS_NEW */
static inline int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s)
@@ -155,6 +258,12 @@ static inline void wpas_dbus_signal_network_selected(
{
}
+static inline void wpas_dbus_signal_network_request(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ enum wpa_ctrl_req_type rtype, const char *default_txt)
+{
+}
+
static inline void wpas_dbus_signal_scan_done(struct wpa_supplicant *wpa_s,
int success)
{
@@ -229,6 +338,161 @@ static inline void wpas_dbus_signal_debug_show_keys_changed(
{
}
+static inline int wpas_dbus_register_peer(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr)
+{
+ return 0;
+}
+
+static inline int wpas_dbus_unregister_peer(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr)
+{
+ return 0;
+}
+
+static inline void
+wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s,
+ const char *role)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr, int request,
+ enum p2p_prov_disc_status status,
+ u16 config_methods,
+ unsigned int generated_pin)
+{
+}
+
+static inline void wpas_dbus_signal_p2p_go_neg_req(
+ struct wpa_supplicant *wpa_s,
+ const u8 *src,
+ u16 dev_passwd_id)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid *ssid,
+ int client, int network_id)
+{
+}
+
+static inline void
+wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+}
+
+static inline int wpas_dbus_register_persistent_group(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+ return 0;
+}
+
+static inline int wpas_dbus_unregister_persistent_group(
+ struct wpa_supplicant *wpa_s, int nid)
+{
+ return 0;
+}
+
+static inline void
+wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s,
+ struct p2p_go_neg_results *res)
+{
+}
+
+static inline void
+wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid *ssid)
+{
+}
+
+static inline void wpas_dbus_signal_p2p_invitation_result(
+ struct wpa_supplicant *wpa_s, int status,
+ const u8 *bssid)
+{
+}
+
+static inline void
+wpas_dbus_register_p2p_groupmember(struct wpa_supplicant *wpa_s,
+ const u8 *p2p_if_addr)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s, int freq,
+ const u8 *sa, u8 dialog_token, u16 update_indic,
+ const u8 *tlvs, size_t tlvs_len)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s,
+ const u8 *sa, u16 update_indic,
+ const u8 *tlvs, size_t tlvs_len)
+{
+}
+
+static inline void
+wpas_dbus_unregister_p2p_groupmember(struct wpa_supplicant *wpa_s,
+ const u8 *p2p_if_addr)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_peer_joined(struct wpa_supplicant *wpa_s,
+ const u8 *member)
+{
+}
+
+static inline void
+wpas_dbus_signal_peer_device_found(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr)
+{
+}
+
+static inline void
+wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s,
+ const u8 *member)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+ struct wps_event_fail *fail)
+{
+}
+
+static inline void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
+ int depth,
+ const char *subject,
+ const char *cert_hash,
+ const struct wpabuf *cert)
+{
+}
+
+static inline void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
+ const u8 *addr, const u8 *dst,
+ const u8 *bssid,
+ const u8 *ie, size_t ie_len,
+ u32 ssi_signal)
+{
+}
+
+static inline void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s,
+ const char *status,
+ const char *parameter)
+{
+}
+
#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
#endif /* CTRL_IFACE_DBUS_H_NEW */
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index e2b5e50dd2b7..5e069326be9c 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -4,14 +4,8 @@
* Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com>
* Copyright (c) 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 software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
@@ -25,88 +19,25 @@
#include "../wpa_supplicant_i.h"
#include "../driver_i.h"
#include "../notify.h"
-#include "../wpas_glue.h"
#include "../bss.h"
#include "../scan.h"
+#include "../autoscan.h"
#include "dbus_new_helpers.h"
#include "dbus_new.h"
#include "dbus_new_handlers.h"
#include "dbus_dict_helpers.h"
+#include "dbus_common_i.h"
extern int wpa_debug_level;
extern int wpa_debug_show_keys;
extern int wpa_debug_timestamp;
static const char *debug_strings[] = {
- "msgdump", "debug", "info", "warning", "error", NULL
+ "excessive", "msgdump", "debug", "info", "warning", "error", NULL
};
/**
- * wpas_dbus_new_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.
- */
-static char * wpas_dbus_new_decompose_object_path(const char *path,
- char **network,
- char **bssid)
-{
- const unsigned int dev_path_prefix_len =
- strlen(WPAS_DBUS_NEW_PATH_INTERFACES "/");
- char *obj_path_only;
- char *next_sep;
-
- /* Be a bit paranoid about path */
- if (!path || os_strncmp(path, WPAS_DBUS_NEW_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 = os_strdup(path);
- if (obj_path_only == NULL)
- return NULL;
-
- next_sep = os_strchr(obj_path_only + dev_path_prefix_len, '/');
- if (next_sep != NULL) {
- const char *net_part = os_strstr(
- next_sep, WPAS_DBUS_NEW_NETWORKS_PART "/");
- const char *bssid_part = os_strstr(
- next_sep, WPAS_DBUS_NEW_BSSIDS_PART "/");
-
- if (network && net_part) {
- /* Deal with a request for a configured network */
- const char *net_name = net_part +
- os_strlen(WPAS_DBUS_NEW_NETWORKS_PART "/");
- *network = NULL;
- if (os_strlen(net_name))
- *network = os_strdup(net_name);
- } else if (bssid && bssid_part) {
- /* Deal with a request for a scanned BSSID */
- const char *bssid_name = bssid_part +
- os_strlen(WPAS_DBUS_NEW_BSSIDS_PART "/");
- if (strlen(bssid_name))
- *bssid = os_strdup(bssid_name);
- else
- *bssid = NULL;
- }
-
- /* Cut off interface object path before "/" */
- *next_sep = '\0';
- }
-
- return obj_path_only;
-}
-
-
-/**
* wpas_dbus_error_unknown_error - Return a new InvalidArgs error message
* @message: Pointer to incoming dbus message this error refers to
* @arg: Optional string appended to error message
@@ -117,6 +48,20 @@ static char * wpas_dbus_new_decompose_object_path(const char *path,
DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
const char *arg)
{
+ /*
+ * This function can be called as a result of a failure
+ * within internal getter calls, which will call this function
+ * with a NULL message parameter. However, dbus_message_new_error
+ * looks very unkindly (i.e, abort()) on a NULL message, so
+ * in this case, we should not call it.
+ */
+ if (message == NULL) {
+ wpa_printf(MSG_INFO, "dbus: wpas_dbus_error_unknown_error "
+ "called with NULL message (arg=%s)",
+ arg ? arg : "N/A");
+ return NULL;
+ }
+
return dbus_message_new_error(message, WPAS_DBUS_ERROR_UNKNOWN_ERROR,
arg);
}
@@ -178,7 +123,7 @@ DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
static const char *dont_quote[] = {
"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
"opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
- "bssid", NULL
+ "bssid", "scan_freq", "freq_list", NULL
};
static dbus_bool_t should_quote_opt(const char *key)
@@ -213,36 +158,35 @@ static struct wpa_supplicant * get_iface_by_dbus_path(
/**
* set_network_properties - Set properties of 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
* @iter: DBus message iterator containing dictionary of network
* properties to set.
- * Returns: NULL when succeed or DBus error on failure
+ * @error: On failure, an error describing the failure
+ * Returns: TRUE if the request succeeds, FALSE if it failed
*
* Sets network configuration with parameters given id DBus dictionary
*/
-static DBusMessage * set_network_properties(DBusMessage *message,
- struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid,
- DBusMessageIter *iter)
+dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ DBusMessageIter *iter,
+ DBusError *error)
{
-
struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
- DBusMessage *reply = NULL;
DBusMessageIter iter_dict;
+ char *value = NULL;
- if (!wpa_dbus_dict_open_read(iter, &iter_dict))
- return wpas_dbus_error_invalid_args(message, NULL);
+ if (!wpa_dbus_dict_open_read(iter, &iter_dict, error))
+ return FALSE;
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_error_invalid_args(message, NULL);
- break;
- }
+
+ if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+ goto error;
+
+ value = NULL;
if (entry.type == DBUS_TYPE_ARRAY &&
entry.array_type == DBUS_TYPE_BYTE) {
if (entry.array_len <= 0)
@@ -304,78 +248,66 @@ static DBusMessage * set_network_properties(DBusMessage *message,
if ((os_strcmp(entry.key, "psk") == 0 &&
value[0] == '"' && ssid->ssid_len) ||
- (strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
+ (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
wpa_config_update_psk(ssid);
else if (os_strcmp(entry.key, "priority") == 0)
wpa_config_update_prio_list(wpa_s->conf);
os_free(value);
wpa_dbus_dict_entry_clear(&entry);
- continue;
-
- error:
- os_free(value);
- reply = wpas_dbus_error_invalid_args(message, entry.key);
- wpa_dbus_dict_entry_clear(&entry);
- break;
}
- return reply;
+ return TRUE;
+
+error:
+ os_free(value);
+ wpa_dbus_dict_entry_clear(&entry);
+ dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+ "invalid message format");
+ return FALSE;
}
/**
* wpas_dbus_simple_property_getter - Get basic type property
- * @message: Pointer to incoming dbus message
+ * @iter: Message iter to use when appending arguments
* @type: DBus type of property (must be basic type)
* @val: pointer to place holding property value
- * Returns: The DBus message containing response for Properties.Get call
- * or DBus error message if error occurred.
+ * @error: On failure an error describing the f