OSDN Git Service

wpa_supplicant: Update to 07-Jul-2012 TOT
authorDmitry Shmidt <dimitrysh@google.com>
Thu, 19 Jul 2012 19:16:46 +0000 (12:16 -0700)
committerDmitry Shmidt <dimitrysh@google.com>
Thu, 19 Jul 2012 23:03:19 +0000 (16:03 -0700)
commit a5ed45586c63ffd8f9d2b44e27c251d7bacbeaf4
Author: Jouni Malinen <j@w1.fi>
Date:   Sat Jul 7 13:01:45 2012 +0300

    WPS SSDP: Fix socket leaks on error paths

Change-Id: I0864aac7fc88fa2a60f5cca7d524b94363410c85
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
212 files changed:
hostapd/ChangeLog
hostapd/Makefile
hostapd/README-WPS
hostapd/config_file.c
hostapd/config_file.h
hostapd/ctrl_iface.c
hostapd/defconfig
hostapd/hlr_auc_gw.c
hostapd/hostapd.conf
hostapd/hostapd.eap_user
hostapd/hostapd_cli.c
hostapd/main.c
src/ap/accounting.c
src/ap/ap_config.c
src/ap/ap_config.h
src/ap/ap_drv_ops.c
src/ap/ap_drv_ops.h
src/ap/ap_list.c
src/ap/ap_list.h
src/ap/beacon.c
src/ap/beacon.h
src/ap/ctrl_iface_ap.c
src/ap/ctrl_iface_ap.h
src/ap/drv_callbacks.c
src/ap/gas_serv.c [new file with mode: 0644]
src/ap/gas_serv.h [new file with mode: 0644]
src/ap/hostapd.c
src/ap/hostapd.h
src/ap/hw_features.c
src/ap/ieee802_11.c
src/ap/ieee802_11.h
src/ap/ieee802_11_auth.c
src/ap/ieee802_11_shared.c
src/ap/ieee802_11_vht.c [new file with mode: 0644]
src/ap/ieee802_1x.c
src/ap/ieee802_1x.h
src/ap/pmksa_cache_auth.c
src/ap/pmksa_cache_auth.h
src/ap/sta_info.c
src/ap/sta_info.h
src/ap/tkip_countermeasures.c
src/ap/utils.c
src/ap/wpa_auth.c
src/ap/wps_hostapd.c
src/ap/wps_hostapd.h
src/common/ieee802_11_common.c
src/common/ieee802_11_common.h
src/common/ieee802_11_defs.h
src/common/wpa_ctrl.h
src/crypto/crypto_openssl.c
src/crypto/dh_group5.c
src/crypto/dh_group5.h
src/crypto/random.c
src/crypto/tls.h
src/crypto/tls_openssl.c
src/drivers/driver.h
src/drivers/driver_atheros.c
src/drivers/driver_bsd.c
src/drivers/driver_common.c
src/drivers/driver_madwifi.c
src/drivers/driver_nl80211.c
src/drivers/driver_privsep.c
src/drivers/driver_roboswitch.c
src/drivers/driver_test.c
src/drivers/driver_wext.c
src/drivers/driver_wired.c
src/drivers/nl80211_copy.h
src/eap_common/eap_defs.h
src/eap_common/eap_pwd_common.c
src/eap_common/eap_pwd_common.h
src/eap_peer/eap.c
src/eap_peer/eap.h
src/eap_peer/eap_aka.c
src/eap_peer/eap_i.h
src/eap_peer/eap_pwd.c
src/eap_peer/eap_tls.c
src/eap_peer/eap_tls_common.c
src/eap_peer/eap_tls_common.h
src/eap_peer/eap_ttls.c
src/eap_peer/eap_wsc.c
src/eap_server/eap_server_aka.c
src/eap_server/eap_server_pwd.c
src/eap_server/eap_server_sim.c
src/eap_server/eap_sim_db.c
src/eap_server/eap_sim_db.h
src/eapol_auth/eapol_auth_sm_i.h
src/eapol_supp/eapol_supp_sm.c
src/eapol_supp/eapol_supp_sm.h
src/l2_packet/l2_packet_freebsd.c
src/l2_packet/l2_packet_privsep.c
src/p2p/p2p.c
src/p2p/p2p.h
src/p2p/p2p_build.c
src/p2p/p2p_go_neg.c
src/p2p/p2p_group.c
src/p2p/p2p_i.h
src/p2p/p2p_invitation.c
src/p2p/p2p_pd.c
src/p2p/p2p_sd.c
src/radius/radius.c
src/radius/radius.h
src/radius/radius_client.c
src/radius/radius_das.c [new file with mode: 0644]
src/radius/radius_das.h [new file with mode: 0644]
src/rsn_supp/tdls.c
src/tls/libtommath.c
src/utils/build_config.h
src/utils/common.h
src/utils/eloop.c
src/utils/includes.h
src/utils/pcsc_funcs.c
src/utils/pcsc_funcs.h
src/utils/wpa_debug.c
src/utils/wpa_debug.h
src/wps/ndef.c
src/wps/wps.c
src/wps/wps.h
src/wps/wps_attr_build.c
src/wps/wps_attr_parse.c
src/wps/wps_attr_parse.h [new file with mode: 0644]
src/wps/wps_common.c
src/wps/wps_defs.h
src/wps/wps_dev_attr.c
src/wps/wps_dev_attr.h
src/wps/wps_enrollee.c
src/wps/wps_er.c
src/wps/wps_i.h
src/wps/wps_nfc.c
src/wps/wps_nfc_pn531.c
src/wps/wps_registrar.c
src/wps/wps_ufd.c
src/wps/wps_upnp.c
src/wps/wps_upnp_ssdp.c
wpa_supplicant/Android.mk
wpa_supplicant/ChangeLog
wpa_supplicant/Makefile
wpa_supplicant/README
wpa_supplicant/README-P2P
wpa_supplicant/README-WPS
wpa_supplicant/README-Windows.txt
wpa_supplicant/android.config
wpa_supplicant/ap.c
wpa_supplicant/ap.h
wpa_supplicant/autoscan.c [new file with mode: 0644]
wpa_supplicant/autoscan.h [new file with mode: 0644]
wpa_supplicant/autoscan_exponential.c [new file with mode: 0644]
wpa_supplicant/autoscan_periodic.c [new file with mode: 0644]
wpa_supplicant/bss.c
wpa_supplicant/bss.h
wpa_supplicant/config.c
wpa_supplicant/config.h
wpa_supplicant/config_file.c
wpa_supplicant/config_ssid.h
wpa_supplicant/ctrl_iface.c
wpa_supplicant/ctrl_iface.h
wpa_supplicant/ctrl_iface_unix.c
wpa_supplicant/dbus/dbus_common.c
wpa_supplicant/dbus/dbus_common.h
wpa_supplicant/dbus/dbus_common_i.h
wpa_supplicant/dbus/dbus_dict_helpers.c
wpa_supplicant/dbus/dbus_dict_helpers.h
wpa_supplicant/dbus/dbus_new.c
wpa_supplicant/dbus/dbus_new.h
wpa_supplicant/dbus/dbus_new_handlers.c
wpa_supplicant/dbus/dbus_new_handlers.h
wpa_supplicant/dbus/dbus_new_handlers_p2p.c
wpa_supplicant/dbus/dbus_new_handlers_p2p.h
wpa_supplicant/dbus/dbus_new_handlers_wps.c
wpa_supplicant/dbus/dbus_new_helpers.c
wpa_supplicant/dbus/dbus_new_helpers.h
wpa_supplicant/dbus/dbus_new_introspect.c
wpa_supplicant/dbus/dbus_old.c
wpa_supplicant/dbus/dbus_old.h
wpa_supplicant/dbus/dbus_old_handlers.c
wpa_supplicant/dbus/dbus_old_handlers.h
wpa_supplicant/dbus/dbus_old_handlers_wps.c
wpa_supplicant/defconfig
wpa_supplicant/doc/docbook/wpa_background.sgml
wpa_supplicant/doc/docbook/wpa_cli.sgml
wpa_supplicant/doc/docbook/wpa_gui.sgml
wpa_supplicant/doc/docbook/wpa_passphrase.sgml
wpa_supplicant/doc/docbook/wpa_priv.sgml
wpa_supplicant/doc/docbook/wpa_supplicant.sgml
wpa_supplicant/driver_i.h
wpa_supplicant/eapol_test.c
wpa_supplicant/events.c
wpa_supplicant/examples/dbus-listen-preq.py [new file with mode: 0755]
wpa_supplicant/hs20_supplicant.c [new file with mode: 0644]
wpa_supplicant/hs20_supplicant.h [new file with mode: 0644]
wpa_supplicant/interworking.c
wpa_supplicant/main.c
wpa_supplicant/main_symbian.cpp [deleted file]
wpa_supplicant/nfc_pw_token.c [new file with mode: 0644]
wpa_supplicant/notify.c
wpa_supplicant/notify.h
wpa_supplicant/p2p_supplicant.c
wpa_supplicant/p2p_supplicant.h
wpa_supplicant/scan.c
wpa_supplicant/scan.h
wpa_supplicant/sme.c
wpa_supplicant/sme.h
wpa_supplicant/wpa_cli.c
wpa_supplicant/wpa_gui-qt4/signalbar.cpp
wpa_supplicant/wpa_gui-qt4/signalbar.h
wpa_supplicant/wpa_gui-qt4/wpagui.cpp
wpa_supplicant/wpa_priv.c
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant.conf
wpa_supplicant/wpa_supplicant_i.h
wpa_supplicant/wpas_glue.c
wpa_supplicant/wps_supplicant.c
wpa_supplicant/wps_supplicant.h

index 47f2423..9fc05f7 100644 (file)
@@ -1,5 +1,112 @@
 ChangeLog for hostapd
 
+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.
+
 2010-04-18 - v0.7.2
        * fix WPS internal Registrar use when an external Registrar is also
          active
index 22c09c1..b43aa75 100644 (file)
@@ -110,6 +110,7 @@ CONFIG_NO_ACCOUNTING=y
 else
 OBJS += ../src/radius/radius.o
 OBJS += ../src/radius/radius_client.o
+OBJS += ../src/radius/radius_das.o
 endif
 
 ifdef CONFIG_NO_ACCOUNTING
@@ -168,6 +169,14 @@ ifdef CONFIG_IEEE80211N
 CFLAGS += -DCONFIG_IEEE80211N
 endif
 
+ifdef CONFIG_WNM
+CFLAGS += -DCONFIG_WNM
+endif
+
+ifdef CONFIG_IEEE80211AC
+CFLAGS += -DCONFIG_IEEE80211AC
+endif
+
 include ../src/drivers/drivers.mak
 OBJS += $(DRV_AP_OBJS)
 CFLAGS += $(DRV_AP_CFLAGS)
@@ -752,6 +761,10 @@ ifdef CONFIG_IEEE80211N
 OBJS += ../src/ap/ieee802_11_ht.o
 endif
 
+ifdef CONFIG_IEEE80211AC
+OBJS += ../src/ap/ieee802_11_vht.o
+endif
+
 ifdef CONFIG_P2P_MANAGER
 CFLAGS += -DCONFIG_P2P_MANAGER
 OBJS += ../src/ap/p2p_hostapd.o
@@ -759,6 +772,8 @@ endif
 
 ifdef CONFIG_INTERWORKING
 CFLAGS += -DCONFIG_INTERWORKING
+OBJS += ../src/common/gas.o
+OBJS += ../src/ap/gas_serv.o
 endif
 
 OBJS += ../src/drivers/driver_common.o
index 17988d4..87a6f91 100644 (file)
@@ -66,6 +66,10 @@ CONFIG_WPS=y
 CONFIG_WPS2=y
 CONFIG_WPS_UPNP=y
 
+Following parameter can be used to enable support for NFC config method:
+
+CONFIG_WPS_NFC=y
+
 
 Following section shows an example runtime configuration
 (hostapd.conf) that enables WPS:
@@ -289,3 +293,48 @@ For example:
 
 This can be used to update the externally stored AP configuration and
 then update hostapd configuration (followed by restarting of hostapd).
+
+
+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 AP acts as an Enrollee, a local NFC tag with a password token
+can be used by touching the NFC interface of an external Registrar. The
+wps_nfc_token command is used to manage use of the NFC password token
+from the AP. "wps_nfc_token enable" enables the use of the AP's NFC
+password token (in place of AP PIN) and "wps_nfc_token disable" disables
+the NFC password token.
+
+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 nfc_pw_token tool from
+wpa_supplicant can be used to generate NFC password tokens during
+manufacturing (each AP needs to have its own random keys).
+
+The "wps_nfc_config_token <WPS/NDEF>" command can be used to build an
+NFC configuration token. The output value from this command is a hexdump
+of the current AP configuration (WPS parameter requests this to include
+only the WPS attributes; NDEF parameter requests additional NDEF
+encapsulation to be included). This data needs to be written to an NFC
+tag with an external program. Once written, the NFC configuration token
+can be used to touch an NFC interface on a station to provision the
+credentials needed to access the network.
+
+When the NFC device on the AP 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 hostapd using the
+following hostapd_cli command:
+
+wps_nfc_tag_read <hexdump of payload>
+
+If the NFC tag contains a password token, the token is added to the
+internal Registrar. This allows station Enrollee from which the password
+token was received to run through WPS protocol to provision the
+credential.
index 78f1e3d..eebbaa6 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / Configuration file parser
- * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -491,6 +491,104 @@ hostapd_config_read_radius_addr(struct hostapd_radius_server **server,
 
        return ret;
 }
+
+
+static struct hostapd_radius_attr *
+hostapd_parse_radius_attr(const char *value)
+{
+       const char *pos;
+       char syntax;
+       struct hostapd_radius_attr *attr;
+       size_t len;
+
+       attr = os_zalloc(sizeof(*attr));
+       if (attr == NULL)
+               return NULL;
+
+       attr->type = atoi(value);
+
+       pos = os_strchr(value, ':');
+       if (pos == NULL) {
+               attr->val = wpabuf_alloc(1);
+               if (attr->val == NULL) {
+                       os_free(attr);
+                       return NULL;
+               }
+               wpabuf_put_u8(attr->val, 0);
+               return attr;
+       }
+
+       pos++;
+       if (pos[0] == '\0' || pos[1] != ':') {
+               os_free(attr);
+               return NULL;
+       }
+       syntax = *pos++;
+       pos++;
+
+       switch (syntax) {
+       case 's':
+               attr->val = wpabuf_alloc_copy(pos, os_strlen(pos));
+               break;
+       case 'x':
+               len = os_strlen(pos);
+               if (len & 1)
+                       break;
+               len /= 2;
+               attr->val = wpabuf_alloc(len);
+               if (attr->val == NULL)
+                       break;
+               if (hexstr2bin(pos, wpabuf_put(attr->val, len), len) < 0) {
+                       wpabuf_free(attr->val);
+                       os_free(attr);
+                       return NULL;
+               }
+               break;
+       case 'd':
+               attr->val = wpabuf_alloc(4);
+               if (attr->val)
+                       wpabuf_put_be32(attr->val, atoi(pos));
+               break;
+       default:
+               os_free(attr);
+               return NULL;
+       }
+
+       if (attr->val == NULL) {
+               os_free(attr);
+               return NULL;
+       }
+
+       return attr;
+}
+
+
+static int hostapd_parse_das_client(struct hostapd_bss_config *bss,
+                                   const char *val)
+{
+       char *secret;
+       size_t len;
+
+       secret = os_strchr(val, ' ');
+       if (secret == NULL)
+               return -1;
+
+       secret++;
+       len = os_strlen(secret);
+
+       if (hostapd_parse_ip_addr(val, &bss->radius_das_client_addr))
+               return -1;
+
+       os_free(bss->radius_das_shared_secret);
+       bss->radius_das_shared_secret = os_malloc(len);
+       if (bss->radius_das_shared_secret == NULL)
+               return -1;
+
+       os_memcpy(bss->radius_das_shared_secret, secret, len);
+       bss->radius_das_shared_secret_len = len;
+
+       return 0;
+}
 #endif /* CONFIG_NO_RADIUS */
 
 
@@ -1034,6 +1132,71 @@ static int hostapd_config_ht_capab(struct hostapd_config *conf,
 #endif /* CONFIG_IEEE80211N */
 
 
+#ifdef CONFIG_IEEE80211AC
+static int hostapd_config_vht_capab(struct hostapd_config *conf,
+                                   const char *capab)
+{
+       if (os_strstr(capab, "[MAX-MPDU-7991]"))
+               conf->vht_capab |= VHT_CAP_MAX_MPDU_LENGTH_7991;
+       if (os_strstr(capab, "[MAX-MPDU-11454]"))
+               conf->vht_capab |= VHT_CAP_MAX_MPDU_LENGTH_11454;
+       if (os_strstr(capab, "[VHT160]"))
+               conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+       if (os_strstr(capab, "[VHT160-80PLUS80]"))
+               conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
+       if (os_strstr(capab, "[VHT160-80PLUS80]"))
+               conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
+       if (os_strstr(capab, "[RXLDPC]"))
+               conf->vht_capab |= VHT_CAP_RXLDPC;
+       if (os_strstr(capab, "[SHORT-GI-80]"))
+               conf->vht_capab |= VHT_CAP_SHORT_GI_80;
+       if (os_strstr(capab, "[SHORT-GI-160]"))
+               conf->vht_capab |= VHT_CAP_SHORT_GI_160;
+       if (os_strstr(capab, "[TX-STBC-2BY1]"))
+               conf->vht_capab |= VHT_CAP_TXSTBC;
+       if (os_strstr(capab, "[RX-STBC-1]"))
+               conf->vht_capab |= VHT_CAP_RXSTBC_1;
+       if (os_strstr(capab, "[RX-STBC-12]"))
+               conf->vht_capab |= VHT_CAP_RXSTBC_2;
+       if (os_strstr(capab, "[RX-STBC-123]"))
+               conf->vht_capab |= VHT_CAP_RXSTBC_3;
+       if (os_strstr(capab, "[RX-STBC-1234]"))
+               conf->vht_capab |= VHT_CAP_RXSTBC_4;
+       if (os_strstr(capab, "[SU-BEAMFORMER]"))
+               conf->vht_capab |= VHT_CAP_MU_BEAMFORMER_CAPABLE;
+       if (os_strstr(capab, "[SU-BEAMFORMEE]"))
+               conf->vht_capab |= VHT_CAP_MU_BEAMFORMEE_CAPABLE;
+       if (os_strstr(capab, "[BF-ANTENNA-2]") &&
+           (conf->vht_capab & VHT_CAP_MU_BEAMFORMER_CAPABLE))
+               conf->vht_capab |= VHT_CAP_BEAMFORMER_ANTENNAS_MAX;
+       if (os_strstr(capab, "[SOUNDING-DIMENSION-2]") &&
+           (conf->vht_capab & VHT_CAP_MU_BEAMFORMER_CAPABLE))
+               conf->vht_capab |= VHT_CAP_SOUNDING_DIMENTION_MAX;
+       if (os_strstr(capab, "[MU-BEAMFORMER]"))
+               conf->vht_capab |= VHT_CAP_MU_BEAMFORMER_CAPABLE;
+       if (os_strstr(capab, "[MU-BEAMFORMEE]"))
+               conf->vht_capab |= VHT_CAP_MU_BEAMFORMEE_CAPABLE;
+       if (os_strstr(capab, "[VHT-TXOP-PS]"))
+               conf->vht_capab |= VHT_CAP_VHT_TXOP_PS;
+       if (os_strstr(capab, "[HTC-VHT]"))
+               conf->vht_capab |= VHT_CAP_HTC_VHT;
+       if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP0]"))
+               conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT;
+       if (os_strstr(capab, "[VHT-LINK-ADAPT2]") &&
+           (conf->vht_capab & VHT_CAP_HTC_VHT))
+               conf->vht_capab |= VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB;
+       if (os_strstr(capab, "[VHT-LINK-ADAPT3]") &&
+           (conf->vht_capab & VHT_CAP_HTC_VHT))
+               conf->vht_capab |= VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
+       if (os_strstr(capab, "[RX-ANTENNA-PATTERN]"))
+               conf->vht_capab |= VHT_CAP_RX_ANTENNA_PATTERN;
+       if (os_strstr(capab, "[TX-ANTENNA-PATTERN]"))
+               conf->vht_capab |= VHT_CAP_TX_ANTENNA_PATTERN;
+       return 0;
+}
+#endif /* CONFIG_IEEE80211AC */
+
+
 static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
                                    struct hostapd_config *conf)
 {
@@ -1090,6 +1253,12 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
 #endif /* CONFIG_IEEE80211R */
 
 #ifdef CONFIG_IEEE80211N
+       if (conf->ieee80211n && conf->hw_mode == HOSTAPD_MODE_IEEE80211B) {
+               bss->disable_11n = 1;
+               wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) in 11b mode is not "
+                          "allowed, disabling HT capabilites");
+       }
+
        if (conf->ieee80211n &&
            bss->ssid.security_policy == SECURITY_STATIC_WEP) {
                bss->disable_11n = 1;
@@ -1175,76 +1344,84 @@ static int parse_roaming_consortium(struct hostapd_bss_config *bss, char *pos,
 
        return 0;
 }
+
+
+static int parse_venue_name(struct hostapd_bss_config *bss, char *pos,
+                           int line)
+{
+       char *sep;
+       size_t clen, nlen;
+       struct hostapd_venue_name *vn;
+
+       sep = os_strchr(pos, ':');
+       if (sep == NULL)
+               goto fail;
+       *sep++ = '\0';
+
+       clen = os_strlen(pos);
+       if (clen < 2)
+               goto fail;
+       nlen = os_strlen(sep);
+       if (nlen > 252)
+               goto fail;
+
+       vn = os_realloc(bss->venue_name,
+                       sizeof(struct hostapd_venue_name) *
+                       (bss->venue_name_count + 1));
+       if (vn == NULL)
+               return -1;
+
+       bss->venue_name = vn;
+       vn = &bss->venue_name[bss->venue_name_count];
+       bss->venue_name_count++;
+
+       os_memset(vn->lang, 0, sizeof(vn->lang));
+       os_memcpy(vn->lang, pos, clen);
+       vn->name_len = nlen;
+       os_memcpy(vn->name, sep, nlen);
+
+       return 0;
+
+fail:
+       wpa_printf(MSG_ERROR, "Line %d: Invalid venue_name '%s'",
+                  line, pos);
+       return -1;
+}
 #endif /* CONFIG_INTERWORKING */
 
 
-/**
- * hostapd_config_read - Read and parse a configuration file
- * @fname: Configuration file name (including path, if needed)
- * Returns: Allocated configuration data structure
- */
-struct hostapd_config * hostapd_config_read(const char *fname)
+#ifdef CONFIG_WPS_NFC
+static struct wpabuf * hostapd_parse_bin(const char *buf)
 {
-       struct hostapd_config *conf;
-       struct hostapd_bss_config *bss;
-       FILE *f;
-       char buf[256], *pos;
-       int line = 0;
-       int errors = 0;
-       int pairwise;
-       size_t i;
+       size_t len;
+       struct wpabuf *ret;
 
-       f = fopen(fname, "r");
-       if (f == NULL) {
-               wpa_printf(MSG_ERROR, "Could not open configuration file '%s' "
-                          "for reading.", fname);
+       len = os_strlen(buf);
+       if (len & 0x01)
                return NULL;
-       }
+       len /= 2;
 
-       conf = hostapd_config_defaults();
-       if (conf == NULL) {
-               fclose(f);
+       ret = wpabuf_alloc(len);
+       if (ret == NULL)
                return NULL;
-       }
 
-       /* set default driver based on configuration */
-       conf->driver = wpa_drivers[0];
-       if (conf->driver == NULL) {
-               wpa_printf(MSG_ERROR, "No driver wrappers registered!");
-               hostapd_config_free(conf);
-               fclose(f);
+       if (hexstr2bin(buf, wpabuf_put(ret, len), len)) {
+               wpabuf_free(ret);
                return NULL;
        }
 
-       bss = conf->last_bss = conf->bss;
-
-       while (fgets(buf, sizeof(buf), f)) {
-               bss = conf->last_bss;
-               line++;
+       return ret;
+}
+#endif /* CONFIG_WPS_NFC */
 
-               if (buf[0] == '#')
-                       continue;
-               pos = buf;
-               while (*pos != '\0') {
-                       if (*pos == '\n') {
-                               *pos = '\0';
-                               break;
-                       }
-                       pos++;
-               }
-               if (buf[0] == '\0')
-                       continue;
 
-               pos = os_strchr(buf, '=');
-               if (pos == NULL) {
-                       wpa_printf(MSG_ERROR, "Line %d: invalid line '%s'",
-                                  line, buf);
-                       errors++;
-                       continue;
-               }
-               *pos = '\0';
-               pos++;
+static int hostapd_config_fill(struct hostapd_config *conf,
+                              struct hostapd_bss_config *bss,
+                              char *buf, char *pos, int line)
+{
+       int errors = 0;
 
+       {
                if (os_strcmp(buf, "interface") == 0) {
                        os_strlcpy(conf->bss[0].iface, pos,
                                   sizeof(conf->bss[0].iface));
@@ -1446,7 +1623,7 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                                           "allocate memory for "
                                           "eap_req_id_text", line);
                                errors++;
-                               continue;
+                               return errors;
                        }
                        bss->eap_req_id_text_len =
                                os_strlen(bss->eap_req_id_text);
@@ -1566,6 +1743,51 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                } else if (os_strcmp(buf, "radius_acct_interim_interval") == 0)
                {
                        bss->acct_interim_interval = atoi(pos);
+               } else if (os_strcmp(buf, "radius_request_cui") == 0) {
+                       bss->radius_request_cui = atoi(pos);
+               } else if (os_strcmp(buf, "radius_auth_req_attr") == 0) {
+                       struct hostapd_radius_attr *attr, *a;
+                       attr = hostapd_parse_radius_attr(pos);
+                       if (attr == NULL) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid "
+                                          "radius_auth_req_attr", line);
+                               errors++;
+                       } else if (bss->radius_auth_req_attr == NULL) {
+                               bss->radius_auth_req_attr = attr;
+                       } else {
+                               a = bss->radius_auth_req_attr;
+                               while (a->next)
+                                       a = a->next;
+                               a->next = attr;
+                       }
+               } else if (os_strcmp(buf, "radius_acct_req_attr") == 0) {
+                       struct hostapd_radius_attr *attr, *a;
+                       attr = hostapd_parse_radius_attr(pos);
+                       if (attr == NULL) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid "
+                                          "radius_acct_req_attr", line);
+                               errors++;
+                       } else if (bss->radius_acct_req_attr == NULL) {
+                               bss->radius_acct_req_attr = attr;
+                       } else {
+                               a = bss->radius_acct_req_attr;
+                               while (a->next)
+                                       a = a->next;
+                               a->next = attr;
+                       }
+               } else if (os_strcmp(buf, "radius_das_port") == 0) {
+                       bss->radius_das_port = atoi(pos);
+               } else if (os_strcmp(buf, "radius_das_client") == 0) {
+                       if (hostapd_parse_das_client(bss, pos) < 0) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid "
+                                          "DAS client", line);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "radius_das_time_window") == 0) {
+                       bss->radius_das_time_window = atoi(pos);
+               } else if (os_strcmp(buf, "radius_das_require_event_timestamp")
+                          == 0) {
+                       bss->radius_das_require_event_timestamp = atoi(pos);
 #endif /* CONFIG_NO_RADIUS */
                } else if (os_strcmp(buf, "auth_algs") == 0) {
                        bss->auth_algs = atoi(pos);
@@ -1605,6 +1827,8 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                        } else {
                                os_free(bss->ssid.wpa_passphrase);
                                bss->ssid.wpa_passphrase = os_strdup(pos);
+                               os_free(bss->ssid.wpa_psk);
+                               bss->ssid.wpa_psk = NULL;
                        }
                } else if (os_strcmp(buf, "wpa_psk") == 0) {
                        os_free(bss->ssid.wpa_psk);
@@ -1620,6 +1844,8 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                                errors++;
                        } else {
                                bss->ssid.wpa_psk->group = 1;
+                               os_free(bss->ssid.wpa_passphrase);
+                               bss->ssid.wpa_passphrase = NULL;
                        }
                } else if (os_strcmp(buf, "wpa_psk_file") == 0) {
                        os_free(bss->ssid.wpa_psk_file);
@@ -1690,7 +1916,7 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                                wpa_printf(MSG_DEBUG, "Line %d: Invalid "
                                           "mobility_domain '%s'", line, pos);
                                errors++;
-                               continue;
+                               return errors;
                        }
                } else if (os_strcmp(buf, "r1_key_holder") == 0) {
                        if (os_strlen(pos) != 2 * FT_R1KH_ID_LEN ||
@@ -1699,7 +1925,7 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                                wpa_printf(MSG_DEBUG, "Line %d: Invalid "
                                           "r1_key_holder '%s'", line, pos);
                                errors++;
-                               continue;
+                               return errors;
                        }
                } else if (os_strcmp(buf, "r0_key_lifetime") == 0) {
                        bss->r0_key_lifetime = atoi(pos);
@@ -1710,14 +1936,14 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                                wpa_printf(MSG_DEBUG, "Line %d: Invalid "
                                           "r0kh '%s'", line, pos);
                                errors++;
-                               continue;
+                               return errors;
                        }
                } else if (os_strcmp(buf, "r1kh") == 0) {
                        if (add_r1kh(bss, pos) < 0) {
                                wpa_printf(MSG_DEBUG, "Line %d: Invalid "
                                           "r1kh '%s'", line, pos);
                                errors++;
-                               continue;
+                               return errors;
                        }
                } else if (os_strcmp(buf, "pmk_r1_push") == 0) {
                        bss->pmk_r1_push = atoi(pos);
@@ -1741,7 +1967,7 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                                wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
                                           " (from group name '%s')",
                                           bss->ctrl_interface_gid, group);
-                               continue;
+                               return errors;
                        }
 
                        /* Group name not found - try to parse this as gid */
@@ -1750,7 +1976,7 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                                wpa_printf(MSG_DEBUG, "Line %d: Invalid group "
                                           "'%s'", line, group);
                                errors++;
-                               continue;
+                               return errors;
                        }
                        bss->ctrl_interface_gid_set = 1;
                        wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
@@ -1965,6 +2191,18 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                } else if (os_strcmp(buf, "require_ht") == 0) {
                        conf->require_ht = atoi(pos);
 #endif /* CONFIG_IEEE80211N */
+#ifdef CONFIG_IEEE80211AC
+               } else if (os_strcmp(buf, "ieee80211ac") == 0) {
+                       conf->ieee80211ac = atoi(pos);
+               } else if (os_strcmp(buf, "vht_capab") == 0) {
+                       if (hostapd_config_vht_capab(conf, pos) < 0) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid "
+                                          "vht_capab", line);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "vht_oper_chwidth") == 0) {
+                   conf->vht_oper_chwidth = atoi(pos);
+#endif /* CONFIG_IEEE80211AC */
                } else if (os_strcmp(buf, "max_listen_interval") == 0) {
                        bss->max_listen_interval = atoi(pos);
                } else if (os_strcmp(buf, "disable_pmksa_caching") == 0) {
@@ -2088,6 +2326,25 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                        bss->upc = os_strdup(pos);
                } else if (os_strcmp(buf, "pbc_in_m1") == 0) {
                        bss->pbc_in_m1 = atoi(pos);
+#ifdef CONFIG_WPS_NFC
+               } else if (os_strcmp(buf, "wps_nfc_dev_pw_id") == 0) {
+                       bss->wps_nfc_dev_pw_id = atoi(pos);
+                       if (bss->wps_nfc_dev_pw_id < 0x10 ||
+                           bss->wps_nfc_dev_pw_id > 0xffff) {
+                               wpa_printf(MSG_ERROR, "Line %d: Invalid "
+                                          "wps_nfc_dev_pw_id value", line);
+                               errors++;
+                       }
+               } else if (os_strcmp(buf, "wps_nfc_dh_pubkey") == 0) {
+                       wpabuf_free(bss->wps_nfc_dh_pubkey);
+                       bss->wps_nfc_dh_pubkey = hostapd_parse_bin(pos);
+               } else if (os_strcmp(buf, "wps_nfc_dh_privkey") == 0) {
+                       wpabuf_free(bss->wps_nfc_dh_privkey);
+                       bss->wps_nfc_dh_privkey = hostapd_parse_bin(pos);
+               } else if (os_strcmp(buf, "wps_nfc_dev_pw") == 0) {
+                       wpabuf_free(bss->wps_nfc_dev_pw);
+                       bss->wps_nfc_dev_pw = hostapd_parse_bin(pos);
+#endif /* CONFIG_WPS_NFC */
 #endif /* CONFIG_WPS */
 #ifdef CONFIG_P2P_MANAGER
                } else if (os_strcmp(buf, "manage_p2p") == 0) {
@@ -2129,7 +2386,7 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                                wpa_printf(MSG_DEBUG, "Line %d: invalid "
                                           "time_zone", line);
                                errors++;
-                               continue;
+                               return errors;
                        }
                        os_free(bss->time_zone);
                        bss->time_zone = os_strdup(pos);
@@ -2169,6 +2426,13 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                } else if (os_strcmp(buf, "roaming_consortium") == 0) {
                        if (parse_roaming_consortium(bss, pos, line) < 0)
                                errors++;
+               } else if (os_strcmp(buf, "venue_name") == 0) {
+                       if (parse_venue_name(bss, pos, line) < 0)
+                               errors++;
+               } else if (os_strcmp(buf, "gas_frag_limit") == 0) {
+                       bss->gas_frag_limit = atoi(pos);
+               } else if (os_strcmp(buf, "gas_comeback_delay") == 0) {
+                       bss->gas_comeback_delay = atoi(pos);
 #endif /* CONFIG_INTERWORKING */
 #ifdef CONFIG_RADIUS_TEST
                } else if (os_strcmp(buf, "dump_msk_file") == 0) {
@@ -2182,65 +2446,142 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                }
        }
 
-       fclose(f);
+       return errors;
+}
 
-       for (i = 0; i < conf->num_bss; i++) {
-               bss = &conf->bss[i];
 
-               if (bss->individual_wep_key_len == 0) {
-                       /* individual keys are not use; can use key idx0 for
-                        * broadcast keys */
-                       bss->broadcast_key_idx_min = 0;
-               }
+static void hostapd_set_security_params(struct hostapd_bss_config *bss)
+{
+       int pairwise;
+
+       if (bss->individual_wep_key_len == 0) {
+               /* individual keys are not use; can use key idx0 for
+                * broadcast keys */
+               bss->broadcast_key_idx_min = 0;
+       }
+
+       /* Select group cipher based on the enabled pairwise cipher
+        * suites */
+       pairwise = 0;
+       if (bss->wpa & 1)
+               pairwise |= bss->wpa_pairwise;
+       if (bss->wpa & 2) {
+               if (bss->rsn_pairwise == 0)
+                       bss->rsn_pairwise = bss->wpa_pairwise;
+               pairwise |= bss->rsn_pairwise;
+       }
+       if (pairwise & WPA_CIPHER_TKIP)
+               bss->wpa_group = WPA_CIPHER_TKIP;
+       else
+               bss->wpa_group = WPA_CIPHER_CCMP;
+
+       bss->radius->auth_server = bss->radius->auth_servers;
+       bss->radius->acct_server = bss->radius->acct_servers;
+
+       if (bss->wpa && bss->ieee802_1x) {
+               bss->ssid.security_policy = SECURITY_WPA;
+       } else if (bss->wpa) {
+               bss->ssid.security_policy = SECURITY_WPA_PSK;
+       } else if (bss->ieee802_1x) {
+               int cipher = WPA_CIPHER_NONE;
+               bss->ssid.security_policy = SECURITY_IEEE_802_1X;
+               bss->ssid.wep.default_len = bss->default_wep_key_len;
+               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;
+               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;
+       }
+}
+
 
-               /* Select group cipher based on the enabled pairwise cipher
-                * suites */
-               pairwise = 0;
-               if (bss->wpa & 1)
-                       pairwise |= bss->wpa_pairwise;
-               if (bss->wpa & 2) {
-                       if (bss->rsn_pairwise == 0)
-                               bss->rsn_pairwise = bss->wpa_pairwise;
-                       pairwise |= bss->rsn_pairwise;
+/**
+ * hostapd_config_read - Read and parse a configuration file
+ * @fname: Configuration file name (including path, if needed)
+ * Returns: Allocated configuration data structure
+ */
+struct hostapd_config * hostapd_config_read(const char *fname)
+{
+       struct hostapd_config *conf;
+       struct hostapd_bss_config *bss;
+       FILE *f;
+       char buf[512], *pos;
+       int line = 0;
+       int errors = 0;
+       size_t i;
+
+       f = fopen(fname, "r");
+       if (f == NULL) {
+               wpa_printf(MSG_ERROR, "Could not open configuration file '%s' "
+                          "for reading.", fname);
+               return NULL;
+       }
+
+       conf = hostapd_config_defaults();
+       if (conf == NULL) {
+               fclose(f);
+               return NULL;
+       }
+
+       /* set default driver based on configuration */
+       conf->driver = wpa_drivers[0];
+       if (conf->driver == NULL) {
+               wpa_printf(MSG_ERROR, "No driver wrappers registered!");
+               hostapd_config_free(conf);
+               fclose(f);
+               return NULL;
+       }
+
+       bss = conf->last_bss = conf->bss;
+
+       while (fgets(buf, sizeof(buf), f)) {
+               bss = conf->last_bss;
+               line++;
+
+               if (buf[0] == '#')
+                       continue;
+               pos = buf;
+               while (*pos != '\0') {
+                       if (*pos == '\n') {
+                               *pos = '\0';
+                               break;
+                       }
+                       pos++;
                }
-               if (pairwise & WPA_CIPHER_TKIP)
-                       bss->wpa_group = WPA_CIPHER_TKIP;
-               else
-                       bss->wpa_group = WPA_CIPHER_CCMP;
-
-               bss->radius->auth_server = bss->radius->auth_servers;
-               bss->radius->acct_server = bss->radius->acct_servers;
-
-               if (bss->wpa && bss->ieee802_1x) {
-                       bss->ssid.security_policy = SECURITY_WPA;
-               } else if (bss->wpa) {
-                       bss->ssid.security_policy = SECURITY_WPA_PSK;
-               } else if (bss->ieee802_1x) {
-                       int cipher = WPA_CIPHER_NONE;
-                       bss->ssid.security_policy = SECURITY_IEEE_802_1X;
-                       bss->ssid.wep.default_len = bss->default_wep_key_len;
-                       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;
-                       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;
+               if (buf[0] == '\0')
+                       continue;
+
+               pos = os_strchr(buf, '=');
+               if (pos == NULL) {
+                       wpa_printf(MSG_ERROR, "Line %d: invalid line '%s'",
+                                  line, buf);
+                       errors++;
+                       continue;
                }
+               *pos = '\0';
+               pos++;
+               errors += hostapd_config_fill(conf, bss, buf, pos, line);
        }
 
+       fclose(f);
+
+       for (i = 0; i < conf->num_bss; i++)
+               hostapd_set_security_params(&conf->bss[i]);
+
        if (hostapd_config_check(conf))
                errors++;
 
@@ -2255,3 +2596,28 @@ struct hostapd_config * hostapd_config_read(const char *fname)
 
        return conf;
 }
+
+
+int hostapd_set_iface(struct hostapd_config *conf,
+                     struct hostapd_bss_config *bss, char *field, char *value)
+{
+       int errors;
+       size_t i;
+
+       errors = hostapd_config_fill(conf, bss, field, value, 0);
+       if (errors) {
+               wpa_printf(MSG_INFO, "Failed to set configuration field '%s' "
+                          "to value '%s'", field, value);
+               return -1;
+       }
+
+       for (i = 0; i < conf->num_bss; i++)
+               hostapd_set_security_params(&conf->bss[i]);
+
+       if (hostapd_config_check(conf)) {
+               wpa_printf(MSG_ERROR, "Configuration check failed");
+               return -1;
+       }
+
+       return 0;
+}
index 80d182e..fba57b8 100644 (file)
@@ -10,5 +10,8 @@
 #define CONFIG_FILE_H
 
 struct hostapd_config * hostapd_config_read(const char *fname);
+int hostapd_set_iface(struct hostapd_config *conf,
+                     struct hostapd_bss_config *bss, char *field,
+                     char *value);
 
 #endif /* CONFIG_FILE_H */
index 9d5a67e..7587e03 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / UNIX domain socket -based control interface
- * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -31,6 +31,7 @@
 #include "ap/ap_drv_ops.h"
 #include "wps/wps_defs.h"
 #include "wps/wps.h"
+#include "config_file.h"
 #include "ctrl_iface.h"
 
 
@@ -152,173 +153,6 @@ static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
 }
 
 
-#ifdef CONFIG_P2P_MANAGER
-static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
-                                 u8 minor_reason_code, const u8 *addr)
-{
-       struct ieee80211_mgmt *mgmt;
-       int ret;
-       u8 *pos;
-
-       if (hapd->driver->send_frame == NULL)
-               return -1;
-
-       mgmt = os_zalloc(sizeof(*mgmt) + 100);
-       if (mgmt == NULL)
-               return -1;
-
-       wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
-               " with minor reason code %u (stype=%u)",
-               MAC2STR(addr), minor_reason_code, stype);
-
-       mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
-       os_memcpy(mgmt->da, addr, ETH_ALEN);
-       os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
-       os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
-       if (stype == WLAN_FC_STYPE_DEAUTH) {
-               mgmt->u.deauth.reason_code =
-                       host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
-               pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
-       } else {
-               mgmt->u.disassoc.reason_code =
-                       host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
-               pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
-       }
-
-       *pos++ = WLAN_EID_VENDOR_SPECIFIC;
-       *pos++ = 4 + 3 + 1;
-       WPA_PUT_BE24(pos, OUI_WFA);
-       pos += 3;
-       *pos++ = P2P_OUI_TYPE;
-
-       *pos++ = P2P_ATTR_MINOR_REASON_CODE;
-       WPA_PUT_LE16(pos, 1);
-       pos += 2;
-       *pos++ = minor_reason_code;
-
-       ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
-                                      pos - (u8 *) mgmt, 1);
-       os_free(mgmt);
-
-       return ret < 0 ? -1 : 0;
-}
-#endif /* CONFIG_P2P_MANAGER */
-
-
-static int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
-                                            const char *txtaddr)
-{
-       u8 addr[ETH_ALEN];
-       struct sta_info *sta;
-       const char *pos;
-
-       wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
-               txtaddr);
-
-       if (hwaddr_aton(txtaddr, addr))
-               return -1;
-
-       pos = os_strstr(txtaddr, " test=");
-       if (pos) {
-               struct ieee80211_mgmt mgmt;
-               int encrypt;
-               if (hapd->driver->send_frame == NULL)
-                       return -1;
-               pos += 6;
-               encrypt = atoi(pos);
-               os_memset(&mgmt, 0, sizeof(mgmt));
-               mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-                                                 WLAN_FC_STYPE_DEAUTH);
-               os_memcpy(mgmt.da, addr, ETH_ALEN);
-               os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
-               os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
-               mgmt.u.deauth.reason_code =
-                       host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
-               if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
-                                            IEEE80211_HDRLEN +
-                                            sizeof(mgmt.u.deauth),
-                                            encrypt) < 0)
-                       return -1;
-               return 0;
-       }
-
-#ifdef CONFIG_P2P_MANAGER
-       pos = os_strstr(txtaddr, " p2p=");
-       if (pos) {
-               return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
-                                             atoi(pos + 5), addr);
-       }
-#endif /* CONFIG_P2P_MANAGER */
-
-       hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
-       sta = ap_get_sta(hapd, addr);
-       if (sta)
-               ap_sta_deauthenticate(hapd, sta,
-                                     WLAN_REASON_PREV_AUTH_NOT_VALID);
-       else if (addr[0] == 0xff)
-               hostapd_free_stas(hapd);
-
-       return 0;
-}
-
-
-static int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
-                                          const char *txtaddr)
-{
-       u8 addr[ETH_ALEN];
-       struct sta_info *sta;
-       const char *pos;
-
-       wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
-               txtaddr);
-
-       if (hwaddr_aton(txtaddr, addr))
-               return -1;
-
-       pos = os_strstr(txtaddr, " test=");
-       if (pos) {
-               struct ieee80211_mgmt mgmt;
-               int encrypt;
-               if (hapd->driver->send_frame == NULL)
-                       return -1;
-               pos += 6;
-               encrypt = atoi(pos);
-               os_memset(&mgmt, 0, sizeof(mgmt));
-               mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-                                                 WLAN_FC_STYPE_DISASSOC);
-               os_memcpy(mgmt.da, addr, ETH_ALEN);
-               os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
-               os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
-               mgmt.u.disassoc.reason_code =
-                       host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
-               if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
-                                            IEEE80211_HDRLEN +
-                                            sizeof(mgmt.u.deauth),
-                                            encrypt) < 0)
-                       return -1;
-               return 0;
-       }
-
-#ifdef CONFIG_P2P_MANAGER
-       pos = os_strstr(txtaddr, " p2p=");
-       if (pos) {
-               return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
-                                             atoi(pos + 5), addr);
-       }
-#endif /* CONFIG_P2P_MANAGER */
-
-       hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
-       sta = ap_get_sta(hapd, addr);
-       if (sta)
-               ap_sta_disassociate(hapd, sta,
-                                   WLAN_REASON_PREV_AUTH_NOT_VALID);
-       else if (addr[0] == 0xff)
-               hostapd_free_stas(hapd);
-
-       return 0;
-}
-
-
 #ifdef CONFIG_IEEE80211W
 #ifdef NEED_AP_MLME
 static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
@@ -440,6 +274,111 @@ static int hostapd_ctrl_iface_wps_oob(struct hostapd_data *hapd, char *txt)
 #endif /* CONFIG_WPS_OOB */
 
 
+#ifdef CONFIG_WPS_NFC
+static int hostapd_ctrl_iface_wps_nfc_tag_read(struct hostapd_data *hapd,
+                                              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 = hostapd_wps_nfc_tag_read(hapd, buf);
+       wpabuf_free(buf);
+
+       return ret;
+}
+
+
+static int hostapd_ctrl_iface_wps_nfc_config_token(struct hostapd_data *hapd,
+                                                  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 = hostapd_wps_nfc_config_token(hapd, 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 hostapd_ctrl_iface_wps_nfc_token_gen(struct hostapd_data *hapd,
+                                               char *reply, size_t max_len,
+                                               int ndef)
+{
+       struct wpabuf *buf;
+       int res;
+
+       buf = hostapd_wps_nfc_token_gen(hapd, 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 hostapd_ctrl_iface_wps_nfc_token(struct hostapd_data *hapd,
+                                           char *cmd, char *reply,
+                                           size_t max_len)
+{
+       if (os_strcmp(cmd, "WPS") == 0)
+               return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
+                                                           max_len, 0);
+
+       if (os_strcmp(cmd, "NDEF") == 0)
+               return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
+                                                           max_len, 1);
+
+       if (os_strcmp(cmd, "enable") == 0)
+               return hostapd_wps_nfc_token_enable(hapd);
+
+       if (os_strcmp(cmd, "disable") == 0) {
+               hostapd_wps_nfc_token_disable(hapd);
+               return 0;
+       }
+
+       return -1;
+}
+#endif /* CONFIG_WPS_NFC */
+
+
 static int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt,
                                         char *buf, size_t buflen)
 {
@@ -773,8 +712,16 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
                wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
                           wps_testing_dummy_cred);
 #endif /* CONFIG_WPS_TESTING */
+#ifdef CONFIG_INTERWORKING
+       } else if (os_strcasecmp(cmd, "gas_frag_limit") == 0) {
+               int val = atoi(value);
+               if (val <= 0)
+                       ret = -1;
+               else
+                       hapd->gas_frag_limit = val;
+#endif /* CONFIG_INTERWORKING */
        } else {
-               ret = -1;
+               ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
        }
 
        return ret;
@@ -913,6 +860,9 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
        } else if (os_strcmp(buf, "WPS_PBC") == 0) {
                if (hostapd_wps_button_pushed(hapd, NULL))
                        reply_len = -1;
+       } else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
+               if (hostapd_wps_cancel(hapd))
+                       reply_len = -1;
 #ifdef CONFIG_WPS_OOB
        } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
                if (hostapd_ctrl_iface_wps_oob(hapd, buf + 8))
@@ -924,6 +874,17 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
        } else if (os_strncmp(buf, "WPS_CONFIG ", 11) == 0) {
                if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0)
                        reply_len = -1;
+#ifdef CONFIG_WPS_NFC
+       } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
+               if (hostapd_ctrl_iface_wps_nfc_tag_read(hapd, buf + 17))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) {
+               reply_len = hostapd_ctrl_iface_wps_nfc_config_token(
+                       hapd, buf + 21, reply, reply_size);
+       } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
+               reply_len = hostapd_ctrl_iface_wps_nfc_token(
+                       hapd, buf + 14, reply, reply_size);
+#endif /* CONFIG_WPS_NFC */
 #endif /* CONFIG_WPS */
        } else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
                if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13))
@@ -988,7 +949,10 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
        int s = -1;
        char *fname = NULL;
 
-       hapd->ctrl_sock = -1;
+       if (hapd->ctrl_sock > -1) {
+               wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
+               return 0;
+       }
 
        if (hapd->conf->ctrl_interface == NULL)
                return 0;
@@ -1045,7 +1009,7 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
                        }
                        if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
                            0) {
-                               perror("bind(PF_UNIX)");
+                               perror("hostapd-ctrl-iface: bind(PF_UNIX)");
                                goto fail;
                        }
                        wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
index 3cf0d13..9c5b13a 100644 (file)
@@ -108,6 +108,8 @@ CONFIG_EAP_TTLS=y
 #CONFIG_WPS2=y
 # Enable UPnP support for external WPS Registrars
 #CONFIG_WPS_UPNP=y
+# Enable WPS support with NFC config method
+#CONFIG_WPS_NFC=y
 
 # EAP-IKEv2
 #CONFIG_EAP_IKEV2=y
@@ -136,6 +138,13 @@ CONFIG_IPV6=y
 # IEEE 802.11n (High Throughput) support
 #CONFIG_IEEE80211N=y
 
+# Wireless Network Management (IEEE Std 802.11v-2011)
+# Note: This is experimental and not complete implementation.
+#CONFIG_WNM=y
+
+# IEEE 802.11ac (Very High Throughput) support
+#CONFIG_IEEE80211AC=y
+
 # Remove debugging code that is printing out debug messages to stdout.
 # This can be used to reduce the size of the hostapd considerably if debugging
 # code is not needed.
index b59ea1b..516d859 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
- * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2007, 2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
  * text file in IMSI:Kc:SRES:RAND format, IMSI in ASCII, other fields as hex
  * strings. This is used to simulate an HLR/AuC. As such, it is not very useful
  * for real life authentication, but it is useful both as an example
- * implementation and for EAP-SIM testing.
+ * implementation and for EAP-SIM/AKA/AKA' testing.
+ *
+ * SQN generation follows the not time-based Profile 2 described in
+ * 3GPP TS 33.102 Annex C.3.2. The length of IND is 5 bits by default, but this
+ * can be changed with a command line options if needed.
  */
 
 #include "includes.h"
 static const char *default_socket_path = "/tmp/hlr_auc_gw.sock";
 static const char *socket_path;
 static int serv_sock = -1;
+static char *milenage_file = NULL;
+static int update_milenage = 0;
+static int sqn_changes = 0;
+static int ind_len = 5;
 
 /* GSM triplets */
 struct gsm_triplet {
@@ -96,7 +104,7 @@ static int open_socket(const char *path)
        addr.sun_family = AF_UNIX;
        os_strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
        if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-               perror("bind(PF_UNIX)");
+               perror("hlr-auc-gw: bind(PF_UNIX)");
                close(s);
                return -1;
        }
@@ -210,7 +218,7 @@ static int read_gsm_triplets(const char *fname)
                gsm_db = g;
                g = NULL;
        }
-       free(g);
+       os_free(g);
 
        fclose(f);
 
@@ -360,7 +368,7 @@ static int read_milenage(const char *fname)
                milenage_db = m;
                m = NULL;
        }
-       free(m);
+       os_free(m);
 
        fclose(f);
 
@@ -368,6 +376,80 @@ static int read_milenage(const char *fname)
 }
 
 
+static void update_milenage_file(const char *fname)
+{
+       FILE *f, *f2;
+       char buf[500], *pos;
+       char *end = buf + sizeof(buf);
+       struct milenage_parameters *m;
+       size_t imsi_len;
+
+       f = fopen(fname, "r");
+       if (f == NULL) {
+               printf("Could not open Milenage data file '%s'\n", fname);
+               return;
+       }
+
+       snprintf(buf, sizeof(buf), "%s.new", fname);
+       f2 = fopen(buf, "w");
+       if (f2 == NULL) {
+               printf("Could not write Milenage data file '%s'\n", buf);
+               fclose(f);
+               return;
+       }
+
+       while (fgets(buf, sizeof(buf), f)) {
+               /* IMSI Ki OPc AMF SQN */
+               buf[sizeof(buf) - 1] = '\0';
+
+               pos = strchr(buf, ' ');
+               if (buf[0] == '#' || pos == NULL || pos - buf >= 20)
+                       goto no_update;
+
+               imsi_len = pos - buf;
+
+               for (m = milenage_db; m; m = m->next) {
+                       if (strncmp(buf, m->imsi, imsi_len) == 0 &&
+                           m->imsi[imsi_len] == '\0')
+                               break;
+               }
+
+               if (!m)
+                       goto no_update;
+
+               pos = buf;
+               pos += snprintf(pos, end - pos, "%s ", m->imsi);
+               pos += wpa_snprintf_hex(pos, end - pos, m->ki, 16);
+               *pos++ = ' ';
+               pos += wpa_snprintf_hex(pos, end - pos, m->opc, 16);
+               *pos++ = ' ';
+               pos += wpa_snprintf_hex(pos, end - pos, m->amf, 2);
+               *pos++ = ' ';
+               pos += wpa_snprintf_hex(pos, end - pos, m->sqn, 6);
+               *pos++ = '\n';
+
+       no_update:
+               fprintf(f2, "%s", buf);
+       }
+
+       fclose(f2);
+       fclose(f);
+
+       snprintf(buf, sizeof(buf), "%s.bak", fname);
+       if (rename(fname, buf) < 0) {
+               perror("rename");
+               return;
+       }
+
+       snprintf(buf, sizeof(buf), "%s.new", fname);
+       if (rename(buf, fname) < 0) {
+               perror("rename");
+               return;
+       }
+
+}
+
+
 static struct milenage_parameters * get_milenage(const char *imsi)
 {
        struct milenage_parameters *m = milenage_db;
@@ -460,6 +542,28 @@ send:
 }
 
 
+static void inc_sqn(u8 *sqn)
+{
+       u64 val, seq, ind;
+
+       /*
+        * SQN = SEQ | IND = SEQ1 | SEQ2 | IND
+        *
+        * The mechanism used here is not time-based, so SEQ2 is void and
+        * SQN = SEQ1 | IND. The length of IND is ind_len bits and the length
+        * of SEQ1 is 48 - ind_len bits.
+        */
+
+       /* Increment both SEQ and IND by one */
+       val = ((u64) WPA_GET_BE32(sqn) << 16) | ((u64) WPA_GET_BE16(sqn + 4));
+       seq = (val >> ind_len) + 1;
+       ind = (val + 1) & ((1 << ind_len) - 1);
+       val = (seq << ind_len) | ind;
+       WPA_PUT_BE32(sqn, val >> 16);
+       WPA_PUT_BE16(sqn + 4, val & 0xffff);
+}
+
+
 static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
                         char *imsi)
 {
@@ -479,7 +583,8 @@ static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
                if (random_get_bytes(_rand, EAP_AKA_RAND_LEN) < 0)
                        return;
                res_len = EAP_AKA_RES_MAX_LEN;
-               inc_byte_array(m->sqn, 6);
+               inc_sqn(m->sqn);
+               sqn_changes = 1;
                printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n",
                       m->sqn[0], m->sqn[1], m->sqn[2],
                       m->sqn[3], m->sqn[4], m->sqn[5]);
@@ -563,6 +668,7 @@ static void aka_auts(int s, struct sockaddr_un *from, socklen_t fromlen,
                printf("AKA-AUTS: Re-synchronized: "
                       "SQN=%02x%02x%02x%02x%02x%02x\n",
                       sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]);
+               sqn_changes = 1;
        }
 }
 
@@ -609,18 +715,21 @@ static void cleanup(void)
        struct gsm_triplet *g, *gprev;
        struct milenage_parameters *m, *prev;
 
+       if (update_milenage && milenage_file && sqn_changes)
+               update_milenage_file(milenage_file);
+
        g = gsm_db;
        while (g) {
                gprev = g;
                g = g->next;
-               free(gprev);
+               os_free(gprev);
        }
 
        m = milenage_db;
        while (m) {
                prev = m;
                m = m->next;
-               free(prev);
+               os_free(prev);
        }
 
        close(serv_sock);
@@ -639,18 +748,21 @@ static void usage(void)
 {
        printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA "
               "database/authenticator\n"
-              "Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>\n"
+              "Copyright (c) 2005-2007, 2012, Jouni Malinen <j@w1.fi>\n"
               "\n"
               "usage:\n"
-              "hlr_auc_gw [-h] [-s<socket path>] [-g<triplet file>] "
-              "[-m<milenage file>]\n"
+              "hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] "
+              "[-m<milenage file>] \\\n"
+              "        [-i<IND len in bits>]\n"
               "\n"
               "options:\n"
               "  -h = show this usage help\n"
+              "  -u = update SQN in Milenage file on exit\n"
               "  -s<socket path> = path for UNIX domain socket\n"
               "                    (default: %s)\n"
               "  -g<triplet file> = path for GSM authentication triplets\n"
-              "  -m<milenage file> = path for Milenage keys\n",
+              "  -m<milenage file> = path for Milenage keys\n"
+              "  -i<IND len in bits> = IND length for SQN (default: 5)\n",
               default_socket_path);
 }
 
@@ -658,13 +770,15 @@ static void usage(void)
 int main(int argc, char *argv[])
 {
        int c;
-       char *milenage_file = NULL;
        char *gsm_triplet_file = NULL;
 
+       if (os_program_init())
+               return -1;
+
        socket_path = default_socket_path;
 
        for (;;) {
-               c = getopt(argc, argv, "g:hm:s:");
+               c = getopt(argc, argv, "g:hi:m:s:u");
                if (c < 0)
                        break;
                switch (c) {
@@ -674,12 +788,22 @@ int main(int argc, char *argv[])
                case 'h':
                        usage();
                        return 0;
+               case 'i':
+                       ind_len = atoi(optarg);
+                       if (ind_len < 0 || ind_len > 32) {
+                               printf("Invalid IND length\n");
+                               return -1;
+                       }
+                       break;
                case 'm':
                        milenage_file = optarg;
                        break;
                case 's':
                        socket_path = optarg;
                        break;
+               case 'u':
+                       update_milenage = 1;
+                       break;
                default:
                        usage();
                        return -1;
@@ -705,5 +829,7 @@ int main(int argc, char *argv[])
        for (;;)
                process(serv_sock);
 
+       os_program_deinit();
+
        return 0;
 }
index 4e6202b..daa03d2 100644 (file)
@@ -416,6 +416,137 @@ wmm_ac_vo_acm=0
 # Require stations to support HT PHY (reject association if they do not)
 #require_ht=1
 
+##### IEEE 802.11ac related configuration #####################################
+
+# ieee80211ac: Whether IEEE 802.11ac (VHT) is enabled
+# 0 = disabled (default)
+# 1 = enabled
+# Note: You will also need to enable WMM for full VHT functionality.
+#ieee80211ac=1
+
+# vht_capab: VHT capabilities (list of flags)
+#
+# vht_max_mpdu_len: [MAX-MPDU-7991] [MAX-MPDU-11454]
+# Indicates maximum MPDU length
+# 0 = 3895 octets (default)
+# 1 = 7991 octets
+# 2 = 11454 octets
+# 3 = reserved
+#
+# supported_chan_width: [VHT160] [VHT160-80PLUS80]
+# Indicates supported Channel widths
+# 0 = 160 MHz & 80+80 channel widths are not supported (default)
+# 1 = 160 MHz channel width is supported
+# 2 = 160 MHz & 80+80 channel widths are supported
+# 3 = reserved
+#
+# Rx LDPC coding capability: [RXLDPC]
+# Indicates support for receiving LDPC coded pkts
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Short GI for 80 MHz: [SHORT-GI-80]
+# Indicates short GI support for reception of packets transmitted with TXVECTOR
+# params format equal to VHT and CBW = 80Mhz
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Short GI for 160 MHz: [SHORT-GI-160]
+# Indicates short GI support for reception of packets transmitted with TXVECTOR
+# params format equal to VHT and CBW = 160Mhz
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Tx STBC: [TX-STBC-2BY1]
+# Indicates support for the transmission of at least 2x1 STBC
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Rx STBC: [RX-STBC-1] [RX-STBC-12] [RX-STBC-123] [RX-STBC-1234]
+# Indicates support for the reception of PPDUs using STBC
+# 0 = Not supported (default)
+# 1 = support of one spatial stream
+# 2 = support of one and two spatial streams
+# 3 = support of one, two and three spatial streams
+# 4 = support of one, two, three and four spatial streams
+# 5,6,7 = reserved
+#
+# SU Beamformer Capable: [SU-BEAMFORMER]
+# Indicates support for operation as a single user beamformer
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# SU Beamformee Capable: [SU-BEAMFORMEE]
+# Indicates support for operation as a single user beamformee
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Compressed Steering Number of Beamformer Antennas Supported: [BF-ANTENNA-2]
+#   Beamformee's capability indicating the maximum number of beamformer
+#   antennas the beamformee can support when sending compressed beamforming
+#   feedback
+# If SU beamformer capable, set to maximum value minus 1
+# else reserved (default)
+#
+# Number of Sounding Dimensions: [SOUNDING-DIMENSION-2]
+# Beamformer\92s capability indicating the maximum value of the NUM_STS parameter
+# in the TXVECTOR of a VHT NDP
+# If SU beamformer capable, set to maximum value minus 1
+# else reserved (default)
+#
+# MU Beamformer Capable: [MU-BEAMFORMER]
+# Indicates support for operation as an MU beamformer
+# 0 = Not supported or sent by Non-AP STA (default)
+# 1 = Supported
+#
+# MU Beamformee Capable: [MU-BEAMFORMEE]
+# Indicates support for operation as an MU beamformee
+# 0 = Not supported or sent by AP (default)
+# 1 = Supported
+#
+# VHT TXOP PS: [VHT-TXOP-PS]
+# Indicates whether or not the AP supports VHT TXOP Power Save Mode
+#  or whether or not the STA is in VHT TXOP Power Save mode
+# 0 = VHT AP doesnt support VHT TXOP PS mode (OR) VHT Sta not in VHT TXOP PS
+#  mode
+# 1 = VHT AP supports VHT TXOP PS mode (OR) VHT Sta is in VHT TXOP power save
+#  mode
+#
+# +HTC-VHT Capable: [HTC-VHT]
+# Indicates whether or not the STA supports receiving a VHT variant HT Control
+# field.
+# 0 = Not supported (default)
+# 1 = supported
+#
+# Maximum A-MPDU Length Exponent: [MAX-A-MPDU-LEN-EXP0]..[MAX-A-MPDU-LEN-EXP7]
+# Indicates the maximum length of A-MPDU pre-EOF padding that the STA can recv
+# This field is an integer in the range of 0 to 7.
+# The length defined by this field is equal to
+# 2 pow(13 + Maximum A-MPDU Length Exponent) \961 octets
+#
+# VHT Link Adaptation Capable: [VHT-LINK-ADAPT2] [VHT-LINK-ADAPT3]
+# Indicates whether or not the STA supports link adaptation using VHT variant
+# HT Control field
+# If +HTC-VHTcapable is 1
+#  0 = (no feedback) if the STA does not provide VHT MFB (default)
+#  1 = reserved
+#  2 = (Unsolicited) if the STA provides only unsolicited VHT MFB
+#  3 = (Both) if the STA can provide VHT MFB in response to VHT MRQ and if the
+#      STA provides unsolicited VHT MFB
+# Reserved if +HTC-VHTcapable is 0
+#
+# Rx Antenna Pattern Consistency: [RX-ANTENNA-PATTERN]
+# Indicates the possibility of Rx antenna pattern change
+# 0 = Rx antenna pattern might change during the lifetime of an association
+# 1 = Rx antenna pattern does not change during the lifetime of an association
+#
+# Tx Antenna Pattern Consistency: [TX-ANTENNA-PATTERN]
+# Indicates the possibility of Tx antenna pattern change
+# 0 = Tx antenna pattern might change during the lifetime of an association
+# 1 = Tx antenna pattern does not change during the lifetime of an association
+#vht_capab=[SHORT-GI-80][HTC-VHT]
+#vht_oper_chwidth=1
+
 ##### IEEE 802.1X-2004 related configuration ##################################
 
 # Require IEEE 802.1X authorization
@@ -632,6 +763,12 @@ own_ip_addr=127.0.0.1
 # 60 (1 minute).
 #radius_acct_interim_interval=600
 
+# Request Chargeable-User-Identity (RFC 4372)
+# This parameter can be used to configure hostapd to request CUI from the
+# RADIUS server by including Chargeable-User-Identity attribute into
+# Access-Request packets.
+#radius_request_cui=1
+
 # Dynamic VLAN mode; allow RADIUS authentication server to decide which VLAN
 # is used for the stations. This information is parsed from following RADIUS
 # attributes based on RFC 3580 and RFC 2868: Tunnel-Type (value 13 = VLAN),
@@ -659,6 +796,55 @@ own_ip_addr=127.0.0.1
 # to the bridge.
 #vlan_tagged_interface=eth0
 
+# Arbitrary RADIUS attributes can be added into Access-Request and
+# Accounting-Request packets by specifying the contents of the attributes with
+# the following configuration parameters. There can be multiple of these to
+# add multiple attributes. These parameters can also be used to override some
+# of the attributes added automatically by hostapd.
+# Format: <attr_id>[:<syntax:value>]
+# attr_id: RADIUS attribute type (e.g., 26 = Vendor-Specific)
+# syntax: s = string (UTF-8), d = integer, x = octet string
+# value: attribute value in format indicated by the syntax
+# If syntax and value parts are omitted, a null value (single 0x00 octet) is
+# used.
+#
+# Additional Access-Request attributes
+# radius_auth_req_attr=<attr_id>[:<syntax:value>]
+# Examples:
+# Operator-Name = "Operator"
+#radius_auth_req_attr=126:s:Operator
+# Service-Type = Framed (2)
+#radius_auth_req_attr=6:d:2
+# Connect-Info = "testing" (this overrides the automatically generated value)
+#radius_auth_req_attr=77:s:testing
+# Same Connect-Info value set as a hexdump
+#radius_auth_req_attr=77:x:74657374696e67
+
+#
+# Additional Accounting-Request attributes
+# radius_acct_req_attr=<attr_id>[:<syntax:value>]
+# Examples:
+# Operator-Name = "Operator"
+#radius_acct_req_attr=126:s:Operator
+
+# Dynamic Authorization Extensions (RFC 5176)
+# This mechanism can be used to allow dynamic changes to user session based on
+# commands from a RADIUS server (or some other disconnect client that has the
+# needed session information). For example, Disconnect message can be used to
+# request an associated station to be disconnected.
+#
+# This is disabled by default. Set radius_das_port to non-zero UDP port
+# number to enable.
+#radius_das_port=3799
+#
+# DAS client (the host that can send Disconnect/CoA requests) and shared secret
+#radius_das_client=192.168.1.123 shared secret here
+#
+# DAS Event-Timestamp time window in seconds
+#radius_das_time_window=300
+#
+# DAS require Event-Timestamp
+#radius_das_require_event_timestamp=1
 
 ##### RADIUS authentication server configuration ##############################
 
@@ -1033,6 +1219,18 @@ own_ip_addr=127.0.0.1
 # set to ag to allow both RF bands to be advertized.
 #wps_rf_bands=ag
 
+# NFC password token for WPS
+# These parameters can be used to configure a fixed NFC password token for the
+# AP. This can be generated, e.g., with nfc_pw_token from wpa_supplicant. When
+# these parameters are used, the AP is assumed to be deployed with a NFC tag
+# that includes the matching NFC password token (e.g., written based on the
+# NDEF record from nfc_pw_token).
+#
+#wps_nfc_dev_pw_id: Device Password ID (16..65535)
+#wps_nfc_dh_pubkey: Hexdump of DH Public Key
+#wps_nfc_dh_privkey: Hexdump of DH Private Key
+#wps_nfc_dev_pw: Hexdump of Device Password
+
 ##### Wi-Fi Direct (P2P) ######################################################
 
 # Enable P2P Device management
@@ -1118,6 +1316,15 @@ own_ip_addr=127.0.0.1
 #roaming_consortium=021122
 #roaming_consortium=2233445566
 
+# Venue Name information
+# This parameter can be used to configure one or more Venue Name Duples for
+# Venue Name ANQP information. Each entry has a two or three character language
+# code (ISO-639) separated by colon from the venue name string.
+# Note that venue_group and venue_type have to be set for Venue Name
+# information to be complete.
+#venue_name=eng:Example venue
+#venue_name=fin:Esimerkkipaikka
+
 ##### Multiple BSSID support ##################################################
 #
 # Above configuration is using the default interface (wlan#, or multi-SSID VLAN
index ac9a5d8..12a2c61 100644 (file)
@@ -69,6 +69,9 @@
 "3"*           SIM,TTLS,TLS,PEAP,AKA
 "4"*           AKA,TTLS,TLS,PEAP,SIM
 "5"*           SIM,TTLS,TLS,PEAP,AKA
+"6"*           AKA'
+"7"*           AKA'
+"8"*           AKA'
 
 # Wildcard for all other identities
 *              PEAP,TTLS,TLS,SIM,AKA
@@ -89,3 +92,6 @@
 "3"*           SIM     [2]
 "4"*           AKA     [2]
 "5"*           SIM     [2]
+"6"*           AKA'    [2]
+"7"*           AKA'    [2]
+"8"*           AKA'    [2]
index 89125fd..0c33d5b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd - command line interface for hostapd daemon
- * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -74,6 +74,11 @@ static const char *commands_help =
 #ifdef CONFIG_WPS_OOB
 "   wps_oob <type> <path> <method>  use WPS with out-of-band (UFD)\n"
 #endif /* CONFIG_WPS_OOB */
+#ifdef CONFIG_WPS_NFC
+"   wps_nfc_tag_read <hexdump>  report read NFC tag with WPS data\n"
+"   wps_nfc_config_token <WPS/NDEF>  build NFC configuration token\n"
+"   wps_nfc_token <WPS/NDEF/enable/disable>  manager NFC password token\n"
+#endif /* CONFIG_WPS_NFC */
 "   wps_ap_pin <cmd> [params..]  enable/disable AP PIN\n"
 "   wps_config <SSID> <auth> <encr> <key>  configure AP\n"
 #endif /* CONFIG_WPS */
@@ -392,6 +397,13 @@ static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
 }
 
 
+static int hostapd_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
+                                     char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "WPS_CANCEL");
+}
+
+
 #ifdef CONFIG_WPS_OOB
 static int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc,
                                   char *argv[])
@@ -426,6 +438,77 @@ static int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc,
 #endif /* CONFIG_WPS_OOB */
 
 
+#ifdef CONFIG_WPS_NFC
+static int hostapd_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
+                                           char *argv[])
+{
+       int ret;
+       char *buf;
+       size_t buflen;
+
+       if (argc != 1) {
+               printf("Invalid 'wps_nfc_tag_read' command - one argument "
+                      "is required.\n");
+               return -1;
+       }
+
+       buflen = 18 + os_strlen(argv[0]);
+       buf = os_malloc(buflen);
+       if (buf == NULL)
+               return -1;
+       os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]);
+
+       ret = wpa_ctrl_command(ctrl, buf);
+       os_free(buf);
+
+       return ret;
+}
+
+
+static int hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl,
+                                               int argc, char *argv[])
+{
+       char cmd[64];
+       int res;
+
+       if (argc != 1) {
+               printf("Invalid 'wps_nfc_config_token' command - one argument "
+                      "is required.\n");
+               return -1;
+       }
+
+       res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s",
+                         argv[0]);
+       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+               printf("Too long WPS_NFC_CONFIG_TOKEN command.\n");
+               return -1;
+       }
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl,
+                                        int argc, char *argv[])
+{
+       char cmd[64];
+       int res;
+
+       if (argc != 1) {
+               printf("Invalid 'wps_nfc_token' command - one argument is "
+                      "required.\n");
+               return -1;
+       }
+
+       res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]);
+       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+               printf("Too long WPS_NFC_TOKEN command.\n");
+               return -1;
+       }
+       return wpa_ctrl_command(ctrl, cmd);
+}
+#endif /* CONFIG_WPS_NFC */
+
+
 static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
                                      char *argv[])
 {
@@ -719,9 +802,15 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
        { "wps_pin", hostapd_cli_cmd_wps_pin },
        { "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
        { "wps_pbc", hostapd_cli_cmd_wps_pbc },
+       { "wps_cancel", hostapd_cli_cmd_wps_cancel },
 #ifdef CONFIG_WPS_OOB
        { "wps_oob", hostapd_cli_cmd_wps_oob },
 #endif /* CONFIG_WPS_OOB */
+#ifdef CONFIG_WPS_NFC
+       { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read },
+       { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token },
+       { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token },
+#endif /* CONFIG_WPS_NFC */
        { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
        { "wps_config", hostapd_cli_cmd_wps_config },
 #endif /* CONFIG_WPS */
index 3918737..d8c2776 100644 (file)
@@ -21,6 +21,7 @@
 #include "eap_server/tncs.h"
 #include "ap/hostapd.h"
 #include "ap/ap_config.h"
+#include "ap/ap_drv_ops.h"
 #include "config_file.h"
 #include "eap_register.h"
 #include "dump_state.h"
@@ -42,29 +43,6 @@ struct hapd_global {
 static struct hapd_global global;
 
 
-struct hapd_interfaces {
-       size_t count;
-       struct hostapd_iface **iface;
-};
-
-
-static int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
-                                     int (*cb)(struct hostapd_iface *iface,
-                                               void *ctx), void *ctx)
-{
-       size_t i;
-       int ret;
-
-       for (i = 0; i < interfaces->count; i++) {
-               ret = cb(interfaces->iface[i], ctx);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
-
-
 #ifndef CONFIG_NO_HOSTAPD_LOGGER
 static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
                              int level, const char *txt, size_t len)
@@ -315,7 +293,7 @@ static void hostapd_interface_deinit_free(struct hostapd_iface *iface)
        driver = iface->bss[0]->driver;
        drv_priv = iface->bss[0]->drv_priv;
        hostapd_interface_deinit(iface);
-       if (driver && driver->hapd_deinit)
+       if (driver && driver->hapd_deinit && drv_priv)
                driver->hapd_deinit(drv_priv);
        hostapd_interface_free(iface);
 }
@@ -339,10 +317,13 @@ hostapd_interface_init(struct hapd_interfaces *interfaces,
                        iface->bss[0]->conf->logger_stdout_level--;
        }
 
-       if (hostapd_driver_init(iface) ||
-           hostapd_setup_interface(iface)) {
-               hostapd_interface_deinit_free(iface);
-               return NULL;
+       if (iface->conf->bss[0].iface[0] != 0 ||
+           hostapd_drv_none(iface->bss[0])) {
+               if (hostapd_driver_init(iface) ||
+                       hostapd_setup_interface(iface)) {
+                       hostapd_interface_deinit_free(iface);
+                       return NULL;
+               }
        }
 
        return iface;
index 2a04560..2c3a6d9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / RADIUS Accounting
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -39,6 +39,8 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
        u8 *val;
        size_t len;
        int i;
+       struct wpabuf *b;
+       struct hostapd_radius_attr *attr;
 
        msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
                             radius_client_get_id(hapd->radius));
@@ -67,7 +69,9 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
                goto fail;
        }
 
-       if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC,
+       if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
+                                           RADIUS_ATTR_ACCT_AUTHENTIC) &&
+           !radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC,
                                       hapd->conf->ieee802_1x ?
                                       RADIUS_ACCT_AUTHENTIC_RADIUS :
                                       RADIUS_ACCT_AUTHENTIC_LOCAL)) {
@@ -91,7 +95,9 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
                }
        }
 
-       if (hapd->conf->own_ip_addr.af == AF_INET &&
+       if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
+                                           RADIUS_ATTR_NAS_IP_ADDRESS) &&
+           hapd->conf->own_ip_addr.af == AF_INET &&
            !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
                                 (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
                printf("Could not add NAS-IP-Address\n");
@@ -99,7 +105,9 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
        }
 
 #ifdef CONFIG_IPV6
-       if (hapd->conf->own_ip_addr.af == AF_INET6 &&
+       if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
+                                           RADIUS_ATTR_NAS_IPV6_ADDRESS) &&
+           hapd->conf->own_ip_addr.af == AF_INET6 &&
            !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
                                 (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
                printf("Could not add NAS-IPv6-Address\n");
@@ -107,7 +115,9 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
        }
 #endif /* CONFIG_IPV6 */
 
-       if (hapd->conf->nas_identifier &&
+       if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
+                                           RADIUS_ATTR_NAS_IDENTIFIER) &&
+           hapd->conf->nas_identifier &&
            !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
                                 (u8 *) hapd->conf->nas_identifier,
                                 os_strlen(hapd->conf->nas_identifier))) {
@@ -115,7 +125,9 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
                goto fail;
        }
 
-       if (sta &&
+       if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
+                                           RADIUS_ATTR_NAS_PORT) &&
+           sta &&
            !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
                printf("Could not add NAS-Port\n");
                goto fail;
@@ -123,7 +135,9 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
 
        os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
                    MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
-       if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
+       if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
+                                           RADIUS_ATTR_CALLED_STATION_ID) &&
+           !radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
                                 (u8 *) buf, os_strlen(buf))) {
                printf("Could not add Called-Station-Id\n");
                goto fail;
@@ -138,7 +152,10 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
                        goto fail;
                }
 
-               if (!radius_msg_add_attr_int32(
+               if (!hostapd_config_get_radius_attr(
+                           hapd->conf->radius_acct_req_attr,
+                           RADIUS_ATTR_NAS_PORT_TYPE) &&
+                   !radius_msg_add_attr_int32(
                            msg, RADIUS_ATTR_NAS_PORT_TYPE,
                            RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
                        printf("Could not add NAS-Port-Type\n");
@@ -149,7 +166,10 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
                            radius_sta_rate(hapd, sta) / 2,
                            (radius_sta_rate(hapd, sta) & 1) ? ".5" : "",
                            radius_mode_txt(hapd));
-               if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
+               if (!hostapd_config_get_radius_attr(
+                           hapd->conf->radius_acct_req_attr,
+                           RADIUS_ATTR_CONNECT_INFO) &&
+                   !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
                                         (u8 *) buf, os_strlen(buf))) {
                        printf("Could not add Connect-Info\n");
                        goto fail;
@@ -167,6 +187,26 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
                                goto fail;
                        }
                }
+
+               b = ieee802_1x_get_radius_cui(sta->eapol_sm);
+               if (b &&
+                   !radius_msg_add_attr(msg,
+                                        RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+                                        wpabuf_head(b), wpabuf_len(b))) {
+                       wpa_printf(MSG_ERROR, "Could not add CUI");
+                       goto fail;
+               }
+       }
+
+       for (attr = hapd->conf->radius_acct_req_attr; attr; attr = attr->next)
+       {
+               if (!radius_msg_add_attr(msg, attr->type,
+                                        wpabuf_head(attr->val),
+                                        wpabuf_len(attr->val))) {
+                       wpa_printf(MSG_ERROR, "Could not add RADIUS "
+                                  "attribute");
+                       goto fail;
+               }
        }
 
        return msg;
@@ -259,8 +299,9 @@ void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
                               hapd, sta);
 
        msg = accounting_msg(hapd, sta, RADIUS_ACCT_STATUS_TYPE_START);
-       if (msg)
-               radius_client_send(hapd->radius, msg, RADIUS_ACCT, sta->addr);
+       if (msg &&
+           radius_client_send(hapd->radius, msg, RADIUS_ACCT, sta->addr) < 0)
+               radius_msg_free(msg);
 
        sta->acct_session_started = 1;
 }
@@ -358,9 +399,10 @@ static void accounting_sta_report(struct hostapd_data *hapd,
                goto fail;
        }
 
-       radius_client_send(hapd->radius, msg,
-                          stop ? RADIUS_ACCT : RADIUS_ACCT_INTERIM,
-                          sta->addr);
+       if (radius_client_send(hapd->radius, msg,
+                              stop ? RADIUS_ACCT : RADIUS_ACCT_INTERIM,
+                              sta->addr) < 0)
+               goto fail;
        return;
 
  fail:
@@ -463,7 +505,8 @@ static void accounting_report_state(struct hostapd_data *hapd, int on)
                return;
        }
 
-       radius_client_send(hapd->radius, msg, RADIUS_ACCT, NULL);
+       if (radius_client_send(hapd->radius, msg, RADIUS_ACCT, NULL) < 0)
+               radius_msg_free(msg);
 }
 
 
index b9f5994..811ffc1 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / Configuration helper functions
- * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -87,6 +87,8 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
 #ifdef CONFIG_IEEE80211R
        bss->ft_over_ds = 1;
 #endif /* CONFIG_IEEE80211R */
+
+       bss->radius_das_time_window = 300;
 }
 
 
@@ -336,6 +338,30 @@ static void hostapd_config_free_radius(struct hostapd_radius_server *servers,
 }
 
 
+struct hostapd_radius_attr *
+hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type)
+{
+       for (; attr; attr = attr->next) {
+               if (attr->type == type)
+                       return attr;
+       }
+       return NULL;
+}
+
+
+static void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr)
+{
+       struct hostapd_radius_attr *prev;
+
+       while (attr) {
+               prev = attr;
+               attr = attr->next;
+               wpabuf_free(prev->val);
+               os_free(prev);
+       }
+}
+
+
 static void hostapd_config_free_eap_user(struct hostapd_eap_user *user)
 {
        os_free(user->identity);
@@ -392,6 +418,8 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
                                   conf->radius->num_auth_servers);
        hostapd_config_free_radius(conf->radius->acct_servers,
                                   conf->radius->num_acct_servers);
+       hostapd_config_free_radius_attr(conf->radius_auth_req_attr);
+       hostapd_config_free_radius_attr(conf->radius_acct_req_attr);
        os_free(conf->rsn_preauth_interfaces);
        os_free(conf->ctrl_interface);
        os_free(conf->ca_cert);
@@ -406,6 +434,7 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
        os_free(conf->radius_server_clients);
        os_free(conf->test_socket);
        os_free(conf->radius);
+       os_free(conf->radius_das_shared_secret);
        hostapd_config_free_vlan(conf);
        if (conf->ssid.dyn_vlan_keys) {
                struct hostapd_ssid *ssid = &conf->ssid;
@@ -465,9 +494,13 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
        os_free(conf->model_description);
        os_free(conf->model_url);
        os_free(conf->upc);
+       wpabuf_free(conf->wps_nfc_dh_pubkey);
+       wpabuf_free(conf->wps_nfc_dh_privkey);
+       wpabuf_free(conf->wps_nfc_dev_pw);
 #endif /* CONFIG_WPS */
 
        os_free(conf->roaming_consortium);
+       os_free(conf->venue_name);
 
 #ifdef CONFIG_RADIUS_TEST
        os_free(conf->dump_msk_file);
index 2ec25ad..13d5549 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / Configuration definitions and helpers functions
- * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -116,6 +116,12 @@ struct hostapd_eap_user {
        int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */
 };
 
+struct hostapd_radius_attr {
+       u8 type;
+       struct wpabuf *val;
+       struct hostapd_radius_attr *next;
+};
+
 
 #define NUM_TX_QUEUES 4
 
@@ -142,6 +148,12 @@ struct hostapd_roaming_consortium {
        u8 oi[MAX_ROAMING_CONSORTIUM_LEN];
 };
 
+struct hostapd_venue_name {
+       u8 lang[3];
+       u8 name_len;
+       u8 name[252];
+};
+
 /**
  * struct hostapd_bss_config - Per-BSS configuration
  */
@@ -171,6 +183,15 @@ struct hostapd_bss_config {
        char *nas_identifier;
        struct hostapd_radius_servers *radius;
        int acct_interim_interval;
+       int radius_request_cui;
+       struct hostapd_radius_attr *radius_auth_req_attr;
+       struct hostapd_radius_attr *radius_acct_req_attr;
+       int radius_das_port;
+       unsigned int radius_das_time_window;
+       int radius_das_require_event_timestamp;
+       struct hostapd_ip_addr radius_das_client_addr;
+       u8 *radius_das_shared_secret;
+       size_t radius_das_shared_secret_len;
 
        struct hostapd_ssid ssid;
 
@@ -326,6 +347,10 @@ struct hostapd_bss_config {
        char *model_url;
        char *upc;
        struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
+       int wps_nfc_dev_pw_id;
+       struct wpabuf *wps_nfc_dh_pubkey;
+       struct wpabuf *wps_nfc_dh_privkey;
+       struct wpabuf *wps_nfc_dev_pw;
 #endif /* CONFIG_WPS */
        int pbc_in_m1;
 
@@ -343,6 +368,7 @@ struct hostapd_bss_config {
 #define TDLS_PROHIBIT_CHAN_SWITCH BIT(1)
        int tdls;
        int disable_11n;
+       int disable_11ac;
 
        /* IEEE 802.11v */
        int time_advertisement;
@@ -364,6 +390,13 @@ struct hostapd_bss_config {
        unsigned int roaming_consortium_count;
        struct hostapd_roaming_consortium *roaming_consortium;
 
+       /* IEEE 802.11u - Venue Name duples */
+       unsigned int venue_name_count;
+       struct hostapd_venue_name *venue_name;
+
+       u16 gas_comeback_delay;
+       int gas_frag_limit;
+
        u8 wps_rf_bands; /* RF bands for WPS (WPS_RF_*) */
 
 #ifdef CONFIG_RADIUS_TEST
@@ -423,6 +456,9 @@ struct hostapd_config {
        int ieee80211n;
        int secondary_channel;
        int require_ht;
+       u32 vht_capab;
+       int ieee80211ac;
+       u8 vht_oper_chwidth;
 };
 
 
@@ -444,5 +480,7 @@ const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan,
 const struct hostapd_eap_user *
 hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
                     size_t identity_len, int phase2);
+struct hostapd_radius_attr *
+hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type);
 
 #endif /* HOSTAPD_CONFIG_H */
index d07cc6b..859b529 100644 (file)
@@ -584,3 +584,15 @@ int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
        return hapd->driver->sta_disassoc(hapd->drv_priv, hapd->own_addr, addr,
                                          reason);
 }
+
+
+int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
+                           unsigned int wait, const u8 *dst, const u8 *data,
+                           size_t len)
+{
+       if (hapd->driver == NULL || hapd->driver->send_action == NULL)
+               return 0;
+       return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst,
+                                        hapd->own_addr, hapd->own_addr, data,
+                                        len, 0);
+}
index 8038fa2..169c91b 100644 (file)
@@ -86,6 +86,9 @@ int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
                           const u8 *addr, int reason);
 int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
                             const u8 *addr, int reason);
+int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
+                           unsigned int wait, const u8 *dst, const u8 *data,
+                           size_t len);
 int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
                         u16 auth_alg);
 int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
index b4252cf..933b158 100644 (file)
@@ -289,10 +289,8 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
        ap->num_beacons++;
        os_get_time(&now);
        ap->last_beacon = now.sec;
-       if (fi) {
-               ap->ssi_signal = fi->ssi_signal;
+       if (fi)
                ap->datarate = fi->datarate;
-       }
 
        if (!new_ap && ap != iface->ap_list) {
                /* move AP entry into the beginning of the list so that the
@@ -320,7 +318,7 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
 #endif /* CONFIG_IEEE80211N */
 
        if (set_beacon)
-               ieee802_11_set_beacons(iface);
+               ieee802_11_update_beacons(iface);
 }
 
 
@@ -375,7 +373,7 @@ static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
        }
 
        if (set_beacon)
-               ieee802_11_set_beacons(iface);
+               ieee802_11_update_beacons(iface);
 }
 
 
index 201f6ec..f0b4125 100644 (file)
@@ -34,7 +34,6 @@ struct ap_info {
 
        int channel;
        int datarate; /* in 100 kbps */
-       int ssi_signal;
 
        int ht_support;
 
index 4ea8684..0f29ccd 100644 (file)
@@ -262,6 +262,11 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
        pos = hostapd_eid_adv_proto(hapd, pos);
        pos = hostapd_eid_roaming_consortium(hapd, pos);
 
+#ifdef CONFIG_IEEE80211AC
+       pos = hostapd_eid_vht_capabilities(hapd, pos);
+       pos = hostapd_eid_vht_operation(hapd, pos);
+#endif /* CONFIG_IEEE80211AC */
+
        /* Wi-Fi Alliance WMM */
        pos = hostapd_eid_wmm(hapd, pos);
 
@@ -293,7 +298,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
 
 
 void handle_probe_req(struct hostapd_data *hapd,
-                     const struct ieee80211_mgmt *mgmt, size_t len)
+                     const struct ieee80211_mgmt *mgmt, size_t len,
+                     int ssi_signal)
 {
        u8 *resp;
        struct ieee802_11_elems elems;
@@ -311,7 +317,7 @@ void handle_probe_req(struct hostapd_data *hapd,
        for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
                if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
                                            mgmt->sa, mgmt->da, mgmt->bssid,
-                                           ie, ie_len) > 0)
+                                           ie, ie_len, ssi_signal) > 0)
                        return;
 
        if (!hapd->iconf->send_probe_response)
@@ -594,6 +600,11 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
        tailpos = hostapd_eid_adv_proto(hapd, tailpos);
        tailpos = hostapd_eid_roaming_consortium(hapd, tailpos);
 
+#ifdef CONFIG_IEEE80211AC
+       tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
+       tailpos = hostapd_eid_vht_operation(hapd, tailpos);
+#endif /* CONFIG_IEEE80211AC */
+
        /* Wi-Fi Alliance WMM */
        tailpos = hostapd_eid_wmm(hapd, tailpos);
 
@@ -682,6 +693,7 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
            !is_zero_ether_addr(hapd->conf->hessid))
                params.hessid = hapd->conf->hessid;
        params.access_network_type = hapd->conf->access_network_type;
+       params.ap_max_inactivity = hapd->conf->ap_max_inactivity;
        if (hostapd_drv_set_ap(hapd, &params))
                wpa_printf(MSG_ERROR, "Failed to set beacon parameters");
        hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
@@ -699,4 +711,14 @@ void ieee802_11_set_beacons(struct hostapd_iface *iface)
                ieee802_11_set_beacon(iface->bss[i]);
 }
 
+
+/* only update beacons if started */
+void ieee802_11_update_beacons(struct hostapd_iface *iface)
+{
+       size_t i;
+       for (i = 0; i < iface->num_bss; i++)
+               if (iface->bss[i]->beacon_set_done)
+                       ieee802_11_set_beacon(iface->bss[i]);
+}
+
 #endif /* CONFIG_NATIVE_WINDOWS */
index a944f5f..37f10d2 100644 (file)
 struct ieee80211_mgmt;
 
 void handle_probe_req(struct hostapd_data *hapd,
-                     const struct ieee80211_mgmt *mgmt, size_t len);
+                     const struct ieee80211_mgmt *mgmt, size_t len,
+                     int ssi_signal);
 void ieee802_11_set_beacon(struct hostapd_data *hapd);
 void ieee802_11_set_beacons(struct hostapd_iface *iface);
+void ieee802_11_update_beacons(struct hostapd_iface *iface);
 
 #endif /* BEACON_H */
index d76b381..ab9c83e 100644 (file)
@@ -9,6 +9,7 @@
 #include "utils/includes.h"
 
 #include "utils/common.h"
+#include "common/ieee802_11_defs.h"
 #include "hostapd.h"
 #include "ieee802_1x.h"
 #include "wpa_auth.h"
@@ -17,6 +18,7 @@
 #include "wps_hostapd.h"
 #include "p2p_hostapd.h"
 #include "ctrl_iface_ap.h"
+#include "ap_drv_ops.h"
 
 
 static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
@@ -100,3 +102,170 @@ int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
        }               
        return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
 }
+
+
+#ifdef CONFIG_P2P_MANAGER
+static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
+                                 u8 minor_reason_code, const u8 *addr)
+{
+       struct ieee80211_mgmt *mgmt;
+       int ret;
+       u8 *pos;
+
+       if (hapd->driver->send_frame == NULL)
+               return -1;
+
+       mgmt = os_zalloc(sizeof(*mgmt) + 100);
+       if (mgmt == NULL)
+               return -1;
+
+       wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
+               " with minor reason code %u (stype=%u)",
+               MAC2STR(addr), minor_reason_code, stype);
+
+       mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
+       os_memcpy(mgmt->da, addr, ETH_ALEN);
+       os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+       os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+       if (stype == WLAN_FC_STYPE_DEAUTH) {
+               mgmt->u.deauth.reason_code =
+                       host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+               pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
+       } else {
+               mgmt->u.disassoc.reason_code =
+                       host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+               pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
+       }
+
+       *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+       *pos++ = 4 + 3 + 1;
+       WPA_PUT_BE24(pos, OUI_WFA);
+       pos += 3;
+       *pos++ = P2P_OUI_TYPE;
+
+       *pos++ = P2P_ATTR_MINOR_REASON_CODE;
+       WPA_PUT_LE16(pos, 1);
+       pos += 2;
+       *pos++ = minor_reason_code;
+
+       ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
+                                      pos - (u8 *) mgmt, 1);
+       os_free(mgmt);
+
+       return ret < 0 ? -1 : 0;
+}
+#endif /* CONFIG_P2P_MANAGER */
+
+
+int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
+                                     const char *txtaddr)
+{
+       u8 addr[ETH_ALEN];
+       struct sta_info *sta;
+       const char *pos;
+
+       wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
+               txtaddr);
+
+       if (hwaddr_aton(txtaddr, addr))
+               return -1;
+
+       pos = os_strstr(txtaddr, " test=");
+       if (pos) {
+               struct ieee80211_mgmt mgmt;
+               int encrypt;
+               if (hapd->driver->send_frame == NULL)
+                       return -1;
+               pos += 6;
+               encrypt = atoi(pos);
+               os_memset(&mgmt, 0, sizeof(mgmt));
+               mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+                                                 WLAN_FC_STYPE_DEAUTH);
+               os_memcpy(mgmt.da, addr, ETH_ALEN);
+               os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
+               os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
+               mgmt.u.deauth.reason_code =
+                       host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+               if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
+                                            IEEE80211_HDRLEN +
+                                            sizeof(mgmt.u.deauth),
+                                            encrypt) < 0)
+                       return -1;
+               return 0;
+       }
+
+#ifdef CONFIG_P2P_MANAGER
+       pos = os_strstr(txtaddr, " p2p=");
+       if (pos) {
+               return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
+                                             atoi(pos + 5), addr);
+       }
+#endif /* CONFIG_P2P_MANAGER */
+
+       hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+       sta = ap_get_sta(hapd, addr);
+       if (sta)
+               ap_sta_deauthenticate(hapd, sta,
+                                     WLAN_REASON_PREV_AUTH_NOT_VALID);
+       else if (addr[0] == 0xff)
+               hostapd_free_stas(hapd);
+
+       return 0;
+}
+
+
+int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
+                                   const char *txtaddr)
+{
+       u8 addr[ETH_ALEN];
+       struct sta_info *sta;
+       const char *pos;
+
+       wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
+               txtaddr);
+
+       if (hwaddr_aton(txtaddr, addr))
+               return -1;
+
+       pos = os_strstr(txtaddr, " test=");
+       if (pos) {
+               struct ieee80211_mgmt mgmt;
+               int encrypt;
+               if (hapd->driver->send_frame == NULL)
+                       return -1;
+               pos += 6;
+               encrypt = atoi(pos);
+               os_memset(&mgmt, 0, sizeof(mgmt));
+               mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+                                                 WLAN_FC_STYPE_DISASSOC);
+               os_memcpy(mgmt.da, addr, ETH_ALEN);
+               os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
+               os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
+               mgmt.u.disassoc.reason_code =
+                       host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+               if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
+                                            IEEE80211_HDRLEN +
+                                            sizeof(mgmt.u.deauth),
+                                            encrypt) < 0)
+                       return -1;
+               return 0;
+       }
+
+#ifdef CONFIG_P2P_MANAGER
+       pos = os_strstr(txtaddr, " p2p=");
+       if (pos) {
+               return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
+                                             atoi(pos + 5), addr);
+       }
+#endif /* CONFIG_P2P_MANAGER */
+
+       hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+       sta = ap_get_sta(hapd, addr);
+       if (sta)
+               ap_sta_disassociate(hapd, sta,
+                                   WLAN_REASON_PREV_AUTH_NOT_VALID);
+       else if (addr[0] == 0xff)
+               hostapd_free_stas(hapd);
+
+       return 0;
+}
index 0e4286d..e83f894 100644 (file)
@@ -15,5 +15,9 @@ int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
                           char *buf, size_t buflen);
 int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
                                char *buf, size_t buflen);
+int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
+                                     const char *txtaddr);
+int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
+                                   const char *txtaddr);
 
 #endif /* CTRL_IFACE_AP_H */
index 820a903..cf06a4f 100644 (file)
@@ -26,6 +26,7 @@
 #include "wps_hostapd.h"
 #include "ap_drv_ops.h"
 #include "ap_config.h"
+#include "hw_features.h"
 
 
 int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
@@ -78,10 +79,19 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
        sta = ap_get_sta(hapd, addr);
        if (sta) {
                accounting_sta_stop(hapd, sta);
+
+               /*
+                * Make sure that the previously registered inactivity timer
+                * will not remove the STA immediately.
+                */
+               sta->timeout_next = STA_NULLFUNC;
        } else {
                sta = ap_sta_add(hapd, addr);
-               if (sta == NULL)
+               if (sta == NULL) {
+                       hostapd_drv_sta_disassoc(hapd, addr,
+                                                WLAN_REASON_DISASSOC_AP_BUSY);
                        return -1;
+               }
        }
        sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
 
@@ -264,8 +274,36 @@ void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr)
 }
 
 
+void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
+                            int offset)
+{
+#ifdef NEED_AP_MLME
+       int channel;
+
+       hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+                      HOSTAPD_LEVEL_INFO, "driver had channel switch: "
+                      "freq=%d, ht=%d, offset=%d", freq, ht, offset);
+
+       hapd->iface->freq = freq;
+
+       channel = hostapd_hw_get_channel(hapd, freq);
+       if (!channel) {
+               hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+                              HOSTAPD_LEVEL_WARNING, "driver switched to "
+                              "bad channel!");
+               return;
+       }
+
+       hapd->iconf->channel = channel;
+       hapd->iconf->ieee80211n = ht;
+       hapd->iconf->secondary_channel = offset;
+#endif /* NEED_AP_MLME */
+}
+
+
 int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
-                        const u8 *bssid, const u8 *ie, size_t ie_len)
+                        const u8 *bssid, const u8 *ie, size_t ie_len,
+                        int ssi_signal)
 {
        size_t i;
        int ret = 0;
@@ -276,7 +314,8 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
        random_add_randomness(sa, ETH_ALEN);
        for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) {
                if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
-                                           sa, da, bssid, ie, ie_len) > 0) {
+                                           sa, da, bssid, ie, ie_len,
+                                           ssi_signal) > 0) {
                        ret = 1;
                        break;
                }
@@ -541,7 +580,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                     data->rx_probe_req.da,
                                     data->rx_probe_req.bssid,
                                     data->rx_probe_req.ie,
-                                    data->rx_probe_req.ie_len);
+                                    data->rx_probe_req.ie_len,
+                                    data->rx_probe_req.ssi_signal);
                break;
        case EVENT_NEW_STA:
                hostapd_event_new_sta(hapd, data->new_sta.addr);
@@ -578,6 +618,13 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                hostapd_rx_action(hapd, &data->rx_action);
                break;
 #endif /* NEED_AP_MLME */
+       case EVENT_CH_SWITCH:
+               if (!data)
+                       break;
+               hostapd_event_ch_switch(hapd, data->ch_switch.freq,
+                                       data->ch_switch.ht_enabled,
+                                       data->ch_switch.ch_offset);
+               break;
        default:
                wpa_printf(MSG_DEBUG, "Unknown event %d", event);
                break;
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
new file mode 100644 (file)
index 0000000..2177b02
--- /dev/null
@@ -0,0 +1,673 @@
+/*
+ * Generic advertisement service (GAS) server
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * 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 "common/gas.h"
+#include "utils/eloop.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "sta_info.h"
+#include "gas_serv.h"
+
+
+static struct gas_dialog_info *
+gas_dialog_create(struct hostapd_data *hapd, const u8 *addr, u8 dialog_token)
+{
+       struct sta_info *sta;
+       struct gas_dialog_info *dia = NULL;
+       int i, j;
+
+       sta = ap_get_sta(hapd, addr);
+       if (!sta) {
+               /*
+                * We need a STA entry to be able to maintain state for
+                * the GAS query.
+                */
+               wpa_printf(MSG_DEBUG, "ANQP: Add a temporary STA entry for "
+                          "GAS query");
+               sta = ap_sta_add(hapd, addr);
+               if (!sta) {
+                       wpa_printf(MSG_DEBUG, "Failed to add STA " MACSTR
+                                  " for GAS query", MAC2STR(addr));
+                       return NULL;
+               }
+               sta->flags |= WLAN_STA_GAS;
+               /*
+                * The default inactivity is 300 seconds. We don't need
+                * it to be that long.
+                */
+               ap_sta_session_timeout(hapd, sta, 5);
+       }
+
+       if (sta->gas_dialog == NULL) {
+               sta->gas_dialog = os_zalloc(GAS_DIALOG_MAX *
+                                           sizeof(struct gas_dialog_info));
+               if (sta->gas_dialog == NULL)
+                       return NULL;
+       }
+
+       for (i = sta->gas_dialog_next, j = 0; j < GAS_DIALOG_MAX; i++, j++) {
+               if (i == GAS_DIALOG_MAX)
+                       i = 0;
+               if (sta->gas_dialog[i].valid)
+                       continue;
+               dia = &sta->gas_dialog[i];
+               dia->valid = 1;
+               dia->index = i;
+               dia->dialog_token = dialog_token;
+               sta->gas_dialog_next = (++i == GAS_DIALOG_MAX) ? 0 : i;
+               return dia;
+       }
+
+       wpa_msg(hapd->msg_ctx, MSG_ERROR, "ANQP: Could not create dialog for "
+               MACSTR " dialog_token %u. Consider increasing "
+               "GAS_DIALOG_MAX.", MAC2STR(addr), dialog_token);
+
+       return NULL;
+}
+
+
+struct gas_dialog_info *
+gas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr,
+                    u8 dialog_token)
+{
+       struct sta_info *sta;
+       int i;
+
+       sta = ap_get_sta(hapd, addr);
+       if (!sta) {
+               wpa_printf(MSG_DEBUG, "ANQP: could not find STA " MACSTR,
+                          MAC2STR(addr));
+               return NULL;
+       }
+       for (i = 0; sta->gas_dialog && i < GAS_DIALOG_MAX; i++) {
+               if (sta->gas_dialog[i].dialog_token != dialog_token ||
+                   !sta->gas_dialog[i].valid)
+                       continue;
+               return &sta->gas_dialog[i];
+       }
+       wpa_printf(MSG_DEBUG, "ANQP: Could not find dialog for "
+                  MACSTR " dialog_token %u", MAC2STR(addr), dialog_token);
+       return NULL;
+}
+
+
+void gas_serv_dialog_clear(struct gas_dialog_info *dia)
+{
+       wpabuf_free(dia->sd_resp);
+       os_memset(dia, 0, sizeof(*dia));
+}
+
+
+static void gas_serv_free_dialogs(struct hostapd_data *hapd,
+                                 const u8 *sta_addr)
+{
+       struct sta_info *sta;
+       int i;
+
+       sta = ap_get_sta(hapd, sta_addr);
+       if (sta == NULL || sta->gas_dialog == NULL)
+               return;
+
+       for (i = 0; i < GAS_DIALOG_MAX; i++) {
+               if (sta->gas_dialog[i].valid)
+                       return;
+       }
+
+       os_free(sta->gas_dialog);
+       sta->gas_dialog = NULL;
+}
+
+
+static void anqp_add_capab_list(struct hostapd_data *hapd,
+                               struct wpabuf *buf)
+{
+       u8 *len;
+
+       len = gas_anqp_add_element(buf, ANQP_CAPABILITY_LIST);
+       wpabuf_put_le16(buf, ANQP_CAPABILITY_LIST);
+       if (hapd->conf->venue_name)
+               wpabuf_put_le16(buf, ANQP_VENUE_NAME);
+       if (hapd->conf->roaming_consortium)
+               wpabuf_put_le16(buf, ANQP_ROAMING_CONSORTIUM);
+       gas_anqp_set_element_len(buf, len);
+}
+
+
+static void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf)
+{
+       if (hapd->conf->venue_name) {
+               u8 *len;
+               unsigned int i;
+               len = gas_anqp_add_element(buf, ANQP_VENUE_NAME);
+               wpabuf_put_u8(buf, hapd->conf->venue_group);
+               wpabuf_put_u8(buf, hapd->conf->venue_type);
+               for (i = 0; i < hapd->conf->venue_name_count; i++) {
+                       struct hostapd_venue_name *vn;
+                       vn = &hapd->conf->venue_name[i];
+                       wpabuf_put_u8(buf, 3 + vn->name_len);
+                       wpabuf_put_data(buf, vn->lang, 3);
+                       wpabuf_put_data(buf, vn->name, vn->name_len);
+               }
+               gas_anqp_set_element_len(buf, len);
+       }
+}
+
+
+static void anqp_add_roaming_consortium(struct hostapd_data *hapd,
+                                       struct wpabuf *buf)
+{
+       unsigned int i;
+       u8 *len;
+
+       len = gas_anqp_add_element(buf, ANQP_ROAMING_CONSORTIUM);
+       for (i = 0; i < hapd->conf->roaming_consortium_count; i++) {
+               struct hostapd_roaming_consortium *rc;
+               rc = &hapd->conf->roaming_consortium[i];
+               wpabuf_put_u8(buf, rc->len);
+               wpabuf_put_data(buf, rc->oi, rc->len);
+       }
+       gas_anqp_set_element_len(buf, len);
+}
+
+
+static struct wpabuf *
+gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
+                               unsigned int request,
+                               struct gas_dialog_info *di)
+{
+       struct wpabuf *buf;
+
+       buf = wpabuf_alloc(1400);
+       if (buf == NULL)
+               return NULL;
+
+       if (request & ANQP_REQ_CAPABILITY_LIST)
+               anqp_add_capab_list(hapd, buf);
+       if (request & ANQP_REQ_VENUE_NAME)
+               anqp_add_venue_name(hapd, buf);
+       if (request & ANQP_REQ_ROAMING_CONSORTIUM)
+               anqp_add_roaming_consortium(hapd, buf);
+
+       return buf;
+}
+
+
+static void gas_serv_clear_cached_ies(void *eloop_data, void *user_ctx)
+{
+       struct gas_dialog_info *dia = eloop_data;
+
+       wpa_printf(MSG_DEBUG, "GAS: Timeout triggered, clearing dialog for "
+                  "dialog token %d", dia->dialog_token);
+
+       gas_serv_dialog_clear(dia);
+}
+
+
+struct anqp_query_info {
+       unsigned int request;
+       unsigned int remote_request;
+       const void *param;
+       u32 param_arg;
+       u16 remote_delay;
+};
+
+
+static void set_anqp_req(unsigned int bit, const char *name, int local,
+                        unsigned int remote, u16 remote_delay,
+                        struct anqp_query_info *qi)
+{
+       qi->request |= bit;
+       if (local) {
+               wpa_printf(MSG_DEBUG, "ANQP: %s (local)", name);
+       } else if (bit & remote) {
+               wpa_printf(MSG_DEBUG, "ANQP: %s (remote)", name);
+               qi->remote_request |= bit;
+               if (remote_delay > qi->remote_delay)
+                       qi->remote_delay = remote_delay;
+       } else {
+               wpa_printf(MSG_DEBUG, "ANQP: %s not available", name);
+       }
+}
+
+
+static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id,
+                                 struct anqp_query_info *qi)
+{
+       switch (info_id) {
+       case ANQP_CAPABILITY_LIST:
+               set_anqp_req(ANQP_REQ_CAPABILITY_LIST, "Capability List", 1, 0,
+                            0, qi);
+               break;
+       case ANQP_VENUE_NAME:
+               set_anqp_req(ANQP_REQ_VENUE_NAME, "Venue Name",
+                            hapd->conf->venue_name != NULL, 0, 0, qi);
+               break;
+       case ANQP_ROAMING_CONSORTIUM:
+               set_anqp_req(ANQP_REQ_ROAMING_CONSORTIUM, "Roaming Consortium",
+                            hapd->conf->roaming_consortium != NULL, 0, 0, qi);
+               break;
+       default:
+               wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
+                          info_id);
+               break;
+       }
+}
+
+
+static void rx_anqp_query_list(struct hostapd_data *hapd,
+                              const u8 *pos, const u8 *end,
+                              struct anqp_query_info *qi)
+{
+       wpa_printf(MSG_DEBUG, "ANQP: %u Info IDs requested in Query list",
+                  (unsigned int) (end - pos) / 2);
+
+       while (pos + 2 <= end) {
+               rx_anqp_query_list_id(hapd, WPA_GET_LE16(pos), qi);
+               pos += 2;
+       }
+}
+
+
+static void gas_serv_req_local_processing(struct hostapd_data *hapd,
+                                         const u8 *sa, u8 dialog_token,
+                                         struct anqp_query_info *qi)
+{
+       struct wpabuf *buf, *tx_buf;
+
+       buf = gas_serv_build_gas_resp_payload(hapd, qi->request, NULL);
+       wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Locally generated ANQP responses",
+                       buf);
+       if (!buf)
+               return;
+
+       if (wpabuf_len(buf) > hapd->gas_frag_limit ||
+           hapd->conf->gas_comeback_delay) {
+               struct gas_dialog_info *di;
+               u16 comeback_delay = 1;
+
+               if (hapd->conf->gas_comeback_delay) {
+                       /* Testing - allow overriding of the delay value */
+                       comeback_delay = hapd->conf->gas_comeback_delay;
+               }
+
+               wpa_printf(MSG_DEBUG, "ANQP: Too long response to fit in "
+                          "initial response - use GAS comeback");
+               di = gas_dialog_create(hapd, sa, dialog_token);
+               if (!di) {
+                       wpa_printf(MSG_INFO, "ANQP: Could not create dialog "
+                                  "for " MACSTR " (dialog token %u)",
+                                  MAC2STR(sa), dialog_token);
+                       wpabuf_free(buf);
+                       return;
+               }
+               di->sd_resp = buf;
+               di->sd_resp_pos = 0;
+               tx_buf = gas_anqp_build_initial_resp_buf(
+                       dialog_token, WLAN_STATUS_SUCCESS, comeback_delay,
+                       NULL);
+       } else {
+               wpa_printf(MSG_DEBUG, "ANQP: Initial response (no comeback)");
+               tx_buf = gas_anqp_build_initial_resp_buf(
+                       dialog_token, WLAN_STATUS_SUCCESS, 0, buf);
+               wpabuf_free(buf);
+       }
+       if (!tx_buf)
+               return;
+
+       hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+                               wpabuf_head(tx_buf), wpabuf_len(tx_buf));
+       wpabuf_free(tx_buf);
+}
+
+
+static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
+                                       const u8 *sa,
+                                       const u8 *data, size_t len)
+{
+       const u8 *pos = data;
+       const u8 *end = data + len;
+       const u8 *next;
+       u8 dialog_token;
+       u16 slen;
+       struct anqp_query_info qi;
+       const u8 *adv_proto;
+
+       if (len < 1 + 2)
+               return;
+
+       os_memset(&qi, 0, sizeof(qi));
+
+       dialog_token = *pos++;
+       wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+               "GAS: GAS Initial Request from " MACSTR " (dialog token %u) ",
+               MAC2STR(sa), dialog_token);
+
+       if (*pos != WLAN_EID_ADV_PROTO) {
+               wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+                       "GAS: Unexpected IE in GAS Initial Request: %u", *pos);
+               return;
+       }
+       adv_proto = pos++;
+
+       slen = *pos++;
+       next = pos + slen;
+       if (next > end || slen < 2) {
+               wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+                       "GAS: Invalid IE in GAS Initial Request");
+               return;
+       }
+       pos++; /* skip QueryRespLenLimit and PAME-BI */
+
+       if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
+               struct wpabuf *buf;
+               wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+                       "GAS: Unsupported GAS advertisement protocol id %u",
+                       *pos);
+               if (sa[0] & 0x01)
+                       return; /* Invalid source address - drop silently */
+               buf = gas_build_initial_resp(
+                       dialog_token, WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED,
+                       0, 2 + slen + 2);
+               if (buf == NULL)
+                       return;
+               wpabuf_put_data(buf, adv_proto, 2 + slen);
+               wpabuf_put_le16(buf, 0); /* Query Response Length */
+               hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+                                       wpabuf_head(buf), wpabuf_len(buf));
+               wpabuf_free(buf);
+               return;
+       }
+
+       pos = next;
+       /* Query Request */
+       if (pos + 2 > end)
+               return;
+       slen = WPA_GET_LE16(pos);
+       pos += 2;
+       if (pos + slen > end)
+               return;
+       end = pos + slen;
+
+       /* ANQP Query Request */
+       while (pos < end) {
+               u16 info_id, elen;
+
+               if (pos + 4 > end)
+                       return;
+
+               info_id = WPA_GET_LE16(pos);
+               pos += 2;
+               elen = WPA_GET_LE16(pos);
+               pos += 2;
+
+               if (pos + elen > end) {
+                       wpa_printf(MSG_DEBUG, "ANQP: Invalid Query Request");
+                       return;
+               }
+
+               switch (info_id) {
+               case ANQP_QUERY_LIST:
+                       rx_anqp_query_list(hapd, pos, pos + elen, &qi);
+                       break;
+               default:
+                       wpa_printf(MSG_DEBUG, "ANQP: Unsupported Query "
+                                  "Request element %u", info_id);
+                       break;
+               }
+
+               pos += elen;
+       }
+
+       gas_serv_req_local_processing(hapd, sa, dialog_token, &qi);
+}
+
+
+void gas_serv_tx_gas_response(struct hostapd_data *hapd, const u8 *dst,
+                             struct gas_dialog_info *dialog)
+{
+       struct wpabuf *buf, *tx_buf;
+       u8 dialog_token = dialog->dialog_token;
+       size_t frag_len;
+
+       if (dialog->sd_resp == NULL) {
+               buf = gas_serv_build_gas_resp_payload(hapd,
+                                                     dialog->all_requested,
+                                                     dialog);
+               wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses",
+                       buf);
+               if (!buf)
+                       goto tx_gas_response_done;
+               dialog->sd_resp = buf;
+               dialog->sd_resp_pos = 0;
+       }
+       frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
+       if (frag_len > hapd->gas_frag_limit || dialog->comeback_delay ||
+           hapd->conf->gas_comeback_delay) {
+               u16 comeback_delay_tus = dialog->comeback_delay +
+                       GAS_SERV_COMEBACK_DELAY_FUDGE;
+               u32 comeback_delay_secs, comeback_delay_usecs;
+
+               if (hapd->conf->gas_comeback_delay) {
+                       /* Testing - allow overriding of the delay value */
+                       comeback_delay_tus = hapd->conf->gas_comeback_delay;
+               }
+
+               wpa_printf(MSG_DEBUG, "GAS: Response frag_len %u (frag limit "
+                          "%u) and comeback delay %u, "
+                          "requesting comebacks", (unsigned int) frag_len,
+                          (unsigned int) hapd->gas_frag_limit,
+                          dialog->comeback_delay);
+               tx_buf = gas_anqp_build_initial_resp_buf(dialog_token,
+                                                        WLAN_STATUS_SUCCESS,
+                                                        comeback_delay_tus,
+                                                        NULL);
+               if (tx_buf) {
+                       wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+                               "GAS: Tx GAS Initial Resp (comeback = 10TU)");
+                       hostapd_drv_send_action(hapd, hapd->iface->freq, 0,
+                                               dst,
+                                               wpabuf_head(tx_buf),
+                                               wpabuf_len(tx_buf));
+               }
+               wpabuf_free(tx_buf);
+
+               /* start a timer of 1.5 * comeback-delay */
+               comeback_delay_tus = comeback_delay_tus +
+                       (comeback_delay_tus / 2);
+               comeback_delay_secs = (comeback_delay_tus * 1024) / 1000000;
+               comeback_delay_usecs = (comeback_delay_tus * 1024) -
+                       (comeback_delay_secs * 1000000);
+               eloop_register_timeout(comeback_delay_secs,
+                                      comeback_delay_usecs,
+                                      gas_serv_clear_cached_ies, dialog,
+                                      NULL);
+               goto tx_gas_response_done;
+       }
+
+       buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) +
+                               dialog->sd_resp_pos, frag_len);
+       if (buf == NULL) {
+               wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Buffer allocation "
+                       "failed");
+               goto tx_gas_response_done;
+       }
+       tx_buf = gas_anqp_build_initial_resp_buf(dialog_token,
+                                                WLAN_STATUS_SUCCESS, 0, buf);
+       wpabuf_free(buf);
+       if (tx_buf == NULL)
+               goto tx_gas_response_done;
+       wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Initial "
+               "Response (frag_id %d frag_len %d)",
+               dialog->sd_frag_id, (int) frag_len);
+       dialog->sd_frag_id++;
+
+       hostapd_drv_send_action(hapd, hapd->iface->freq, 0, dst,
+                               wpabuf_head(tx_buf), wpabuf_len(tx_buf));
+       wpabuf_free(tx_buf);
+tx_gas_response_done:
+       gas_serv_clear_cached_ies(dialog, NULL);
+}
+
+
+static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
+                                        const u8 *sa,
+                                        const u8 *data, size_t len)
+{
+       struct gas_dialog_info *dialog;
+       struct wpabuf *buf, *tx_buf;
+       u8 dialog_token;
+       size_t frag_len;
+       int more = 0;
+
+       wpa_hexdump(MSG_DEBUG, "GAS: RX GAS Comeback Request", data, len);
+       if (len < 1)
+               return;
+       dialog_token = *data;
+       wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Dialog Token: %u",
+               dialog_token);
+
+       dialog = gas_serv_dialog_find(hapd, sa, dialog_token);
+       if (!dialog) {
+               wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: No pending SD "
+                       "response fragment for " MACSTR " dialog token %u",
+                       MAC2STR(sa), dialog_token);
+
+               if (sa[0] & 0x01)
+                       return; /* Invalid source address - drop silently */
+               tx_buf = gas_anqp_build_comeback_resp_buf(
+                       dialog_token, WLAN_STATUS_NO_OUTSTANDING_GAS_REQ, 0, 0,
+                       0, NULL);
+               if (tx_buf == NULL)
+                       return;
+               goto send_resp;
+       }
+
+       if (dialog->sd_resp == NULL) {
+               wpa_printf(MSG_DEBUG, "GAS: Remote request 0x%x received 0x%x",
+                          dialog->requested, dialog->received);
+               if ((dialog->requested & dialog->received) !=
+                   dialog->requested) {
+                       wpa_printf(MSG_DEBUG, "GAS: Did not receive response "
+                                  "from remote processing");
+                       gas_serv_dialog_clear(dialog);
+                       tx_buf = gas_anqp_build_comeback_resp_buf(
+                               dialog_token,
+                               WLAN_STATUS_GAS_RESP_NOT_RECEIVED, 0, 0, 0,
+                               NULL);
+                       if (tx_buf == NULL)
+                               return;
+                       goto send_resp;
+               }
+
+               buf = gas_serv_build_gas_resp_payload(hapd,
+                                                     dialog->all_requested,
+                                                     dialog);
+               wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses",
+                       buf);
+               if (!buf)
+                       goto rx_gas_comeback_req_done;
+               dialog->sd_resp = buf;
+               dialog->sd_resp_pos = 0;
+       }
+       frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
+       if (frag_len > hapd->gas_frag_limit) {
+               frag_len = hapd->gas_frag_limit;
+               more = 1;
+       }
+       wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: resp frag_len %u",
+               (unsigned int) frag_len);
+       buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) +
+                               dialog->sd_resp_pos, frag_len);
+       if (buf == NULL) {
+               wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Failed to allocate "
+                       "buffer");
+               goto rx_gas_comeback_req_done;
+       }
+       tx_buf = gas_anqp_build_comeback_resp_buf(dialog_token,
+                                                 WLAN_STATUS_SUCCESS,
+                                                 dialog->sd_frag_id,
+                                                 more, 0, buf);
+       wpabuf_free(buf);
+       if (tx_buf == NULL)
+               goto rx_gas_comeback_req_done;
+       wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Comeback Response "
+               "(frag_id %d more=%d frag_len=%d)",
+               dialog->sd_frag_id, more, (int) frag_len);
+       dialog->sd_frag_id++;
+       dialog->sd_resp_pos += frag_len;
+
+       if (more) {
+               wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: %d more bytes remain "
+                       "to be sent",
+                       (int) (wpabuf_len(dialog->sd_resp) -
+                              dialog->sd_resp_pos));
+       } else {
+               wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: All fragments of "
+                       "SD response sent");
+               gas_serv_dialog_clear(dialog);
+               gas_serv_free_dialogs(hapd, sa);
+       }
+
+send_resp:
+       hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+                               wpabuf_head(tx_buf), wpabuf_len(tx_buf));
+       wpabuf_free(tx_buf);
+       return;
+
+rx_gas_comeback_req_done:
+       gas_serv_clear_cached_ies(dialog, NULL);
+}
+
+
+static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len,
+                                     int freq)
+{
+       struct hostapd_data *hapd = ctx;
+       const struct ieee80211_mgmt *mgmt;
+       size_t hdr_len;
+       const u8 *sa, *data;
+
+       mgmt = (const struct ieee80211_mgmt *) buf;
+       hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf;
+       if (hdr_len > len)
+               return;
+       if (mgmt->u.action.category != WLAN_ACTION_PUBLIC)
+               return;
+       sa = mgmt->sa;
+       len -= hdr_len;
+       data = &mgmt->u.action.u.public_action.action;
+       switch (data[0]) {
+       case WLAN_PA_GAS_INITIAL_REQ:
+               gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1);
+               break;
+       case WLAN_PA_GAS_COMEBACK_REQ:
+               gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1);
+               break;
+       }
+}
+
+
+int gas_serv_init(struct hostapd_data *hapd)
+{
+       hapd->public_action_cb = gas_serv_rx_public_action;
+       hapd->public_action_cb_ctx = hapd;
+       hapd->gas_frag_limit = 1400;
+       if (hapd->conf->gas_frag_limit > 0)
+               hapd->gas_frag_limit = hapd->conf->gas_frag_limit;
+       return 0;
+}
+
+
+void gas_serv_deinit(struct hostapd_data *hapd)
+{
+}
diff --git a/src/ap/gas_serv.h b/src/ap/gas_serv.h
new file mode 100644 (file)
index 0000000..0e2eaf6
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Generic advertisement service (GAS) server
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef GAS_SERV_H
+#define GAS_SERV_H
+
+#define ANQP_REQ_CAPABILITY_LIST \
+       (1 << (ANQP_CAPABILITY_LIST - ANQP_QUERY_LIST))
+#define ANQP_REQ_VENUE_NAME \
+       (1 << (ANQP_VENUE_NAME - ANQP_QUERY_LIST))
+#define ANQP_REQ_ROAMING_CONSORTIUM \
+       (1 << (ANQP_ROAMING_CONSORTIUM - ANQP_QUERY_LIST))
+
+/* To account for latencies between hostapd and external ANQP processor */
+#define GAS_SERV_COMEBACK_DELAY_FUDGE 10
+#define GAS_SERV_MIN_COMEBACK_DELAY 100 /* in TU */
+
+struct gas_dialog_info {
+       u8 valid;
+       u8 index;
+       struct wpabuf *sd_resp; /* Fragmented response */
+       u8 dialog_token;
+       size_t sd_resp_pos; /* Offset in sd_resp */
+       u8 sd_frag_id;
+       u16 comeback_delay;
+
+       unsigned int requested;
+       unsigned int received;
+       unsigned int all_requested;
+};
+
+struct hostapd_data;
+
+void gas_serv_tx_gas_response(struct hostapd_data *hapd, const u8 *dst,
+                             struct gas_dialog_info *dialog);
+struct gas_dialog_info *
+gas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr,
+                    u8 dialog_token);
+void gas_serv_dialog_clear(struct gas_dialog_info *dialog);
+
+int gas_serv_init(struct hostapd_data *hapd);
+void gas_serv_deinit(struct hostapd_data *hapd);
+
+#endif /* GAS_SERV_H */
index c5cbdf7..22c5e65 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / Initialization and configuration
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -12,6 +12,7 @@
 #include "utils/eloop.h"
 #include "common/ieee802_11_defs.h"
 #include "radius/radius_client.h"
+#include "radius/radius_das.h"
 #include "drivers/driver.h"
 #include "hostapd.h"
 #include "authsrv.h"
 #include "ap_drv_ops.h"
 #include "ap_config.h"
 #include "p2p_hostapd.h"
+#include "gas_serv.h"
 
 
-static int hostapd_flush_old_stations(struct hostapd_data *hapd);
+static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
 static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd);
 static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd);
 
 extern int wpa_debug_level;
 
 
+int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
+                              int (*cb)(struct hostapd_iface *iface,
+                                        void *ctx), void *ctx)
+{
+       size_t i;
+       int ret;
+
+       for (i = 0; i < interfaces->count; i++) {
+               ret = cb(interfaces->iface[i], ctx);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+
 static void hostapd_reload_bss(struct hostapd_data *hapd)
 {
 #ifndef CONFIG_NO_RADIUS
@@ -105,7 +124,8 @@ int hostapd_reload_config(struct hostapd_iface *iface)
         * allow them to use the BSS anymore.
         */
        for (j = 0; j < iface->num_bss; j++) {
-               hostapd_flush_old_stations(iface->bss[j]);
+               hostapd_flush_old_stations(iface->bss[j],
+                                          WLAN_REASON_PREV_AUTH_NOT_VALID);
                hostapd_broadcast_wep_clear(iface->bss[j]);
 
 #ifndef CONFIG_NO_RADIUS
@@ -210,21 +230,9 @@ static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
        return errors;
 }
 
-/**
- * hostapd_cleanup - Per-BSS cleanup (deinitialization)
- * @hapd: Pointer to BSS data
- *
- * This function is used to free all per-BSS data structures and resources.
- * This gets called in a loop for each BSS between calls to
- * hostapd_cleanup_iface_pre() and hostapd_cleanup_iface() when an interface
- * is deinitialized. Most of the modules that are initialized in
- * hostapd_setup_bss() are deinitialized here.
- */
-static void hostapd_cleanup(struct hostapd_data *hapd)
-{
-       if (hapd->iface->ctrl_iface_deinit)
-               hapd->iface->ctrl_iface_deinit(hapd);
 
+static void hostapd_free_hapd_data(struct hostapd_data *hapd)
+{
        iapp_deinit(hapd->iapp);
        hapd->iapp = NULL;
        accounting_deinit(hapd);
@@ -234,6 +242,8 @@ static void hostapd_cleanup(struct hostapd_data *hapd)
 #ifndef CONFIG_NO_RADIUS
        radius_client_deinit(hapd->radius);
        hapd->radius = NULL;
+       radius_das_deinit(hapd->radius_das);
+       hapd->radius_das = NULL;
 #endif /* CONFIG_NO_RADIUS */
 
        hostapd_deinit_wps(hapd);
@@ -257,6 +267,28 @@ static void hostapd_cleanup(struct hostapd_data *hapd)
 #endif /* CONFIG_P2P */
 
        wpabuf_free(hapd->time_adv);
+
+#ifdef CONFIG_INTERWORKING
+       gas_serv_deinit(hapd);
+#endif /* CONFIG_INTERWORKING */
+}
+
+
+/**
+ * hostapd_cleanup - Per-BSS cleanup (deinitialization)
+ * @hapd: Pointer to BSS data
+ *
+ * This function is used to free all per-BSS data structures and resources.
+ * This gets called in a loop for each BSS between calls to
+ * hostapd_cleanup_iface_pre() and hostapd_cleanup_iface() when an interface
+ * is deinitialized. Most of the modules that are initialized in
+ * hostapd_setup_bss() are deinitialized here.
+ */
+static void hostapd_cleanup(struct hostapd_data *hapd)
+{
+       if (hapd->iface->ctrl_iface_deinit)
+               hapd->iface->ctrl_iface_deinit(hapd);
+       hostapd_free_hapd_data(hapd);
 }
 
 
@@ -272,6 +304,18 @@ static void hostapd_cleanup_iface_pre(struct hostapd_iface *iface)
 }
 
 
+static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
+{
+       hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
+       iface->hw_features = NULL;
+       os_free(iface->current_rates);
+       iface->current_rates = NULL;
+       os_free(iface->basic_rates);
+       iface->basic_rates = NULL;
+       ap_list_deinit(iface);
+}
+
+
 /**
  * hostapd_cleanup_iface - Complete per-interface cleanup
  * @iface: Pointer to interface data
@@ -281,13 +325,7 @@ static void hostapd_cleanup_iface_pre(struct hostapd_iface *iface)
  */
 static void hostapd_cleanup_iface(struct hostapd_iface *iface)
 {
-       hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
-       iface->hw_features = NULL;
-       os_free(iface->current_rates);
-       iface->current_rates = NULL;
-       os_free(iface->basic_rates);
-       iface->basic_rates = NULL;
-       ap_list_deinit(iface);
+       hostapd_cleanup_iface_partial(iface);
        hostapd_config_free(iface->conf);
        iface->conf = NULL;
 
@@ -297,6 +335,15 @@ static void hostapd_cleanup_iface(struct hostapd_iface *iface)
 }
 
 
+static void hostapd_clear_wep(struct hostapd_data *hapd)
+{
+       if (hapd->drv_priv) {
+               hostapd_set_privacy(hapd, 0);
+               hostapd_broadcast_wep_clear(hapd);
+       }
+}
+
+
 static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd)
 {
        int i;
@@ -333,7 +380,7 @@ static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd)
 }
 
 
-static int hostapd_flush_old_stations(struct hostapd_data *hapd)
+static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason)
 {
        int ret = 0;
        u8 addr[ETH_ALEN];
@@ -349,7 +396,7 @@ static int hostapd_flush_old_stations(struct hostapd_data *hapd)
        }
        wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Deauthenticate all stations");
        os_memset(addr, 0xff, ETH_ALEN);
-       hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+       hostapd_drv_sta_deauth(hapd, addr, reason);
        hostapd_free_stas(hapd);
 
        return ret;
@@ -464,6 +511,86 @@ static int mac_in_conf(struct hostapd_config *conf, const void *a)
 }
 
 
+#ifndef CONFIG_NO_RADIUS
+
+static int hostapd_das_nas_mismatch(struct hostapd_data *hapd,
+                                   struct radius_das_attrs *attr)
+{
+       /* TODO */
+       return 0;
+}
+
+
+static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
+                                             struct radius_das_attrs *attr)
+{
+       struct sta_info *sta = NULL;
+       char buf[128];
+
+       if (attr->sta_addr)
+               sta = ap_get_sta(hapd, attr->sta_addr);
+
+       if (sta == NULL && attr->acct_session_id &&
+           attr->acct_session_id_len == 17) {
+               for (sta = hapd->sta_list; sta; sta = sta->next) {
+                       os_snprintf(buf, sizeof(buf), "%08X-%08X",
+                                   sta->acct_session_id_hi,
+                                   sta->acct_session_id_lo);
+                       if (os_memcmp(attr->acct_session_id, buf, 17) == 0)
+                               break;
+               }
+       }
+
+       if (sta == NULL && attr->cui) {
+               for (sta = hapd->sta_list; sta; sta = sta->next) {
+                       struct wpabuf *cui;
+                       cui = ieee802_1x_get_radius_cui(sta->eapol_sm);
+                       if (cui && wpabuf_len(cui) == attr->cui_len &&
+                           os_memcmp(wpabuf_head(cui), attr->cui,
+                                     attr->cui_len) == 0)
+                               break;
+               }
+       }
+
+       if (sta == NULL && attr->user_name) {
+               for (sta = hapd->sta_list; sta; sta = sta->next) {
+                       u8 *identity;
+                       size_t identity_len;
+                       identity = ieee802_1x_get_identity(sta->eapol_sm,
+                                                          &identity_len);
+                       if (identity &&
+                           identity_len == attr->user_name_len &&
+                           os_memcmp(identity, attr->user_name, identity_len)
+                           == 0)
+                               break;
+               }
+       }
+
+       return sta;
+}
+
+
+static enum radius_das_res
+hostapd_das_disconnect(void *ctx, struct radius_das_attrs *attr)
+{
+       struct hostapd_data *hapd = ctx;
+       struct sta_info *sta;
+
+       if (hostapd_das_nas_mismatch(hapd, attr))
+               return RADIUS_DAS_NAS_MISMATCH;
+
+       sta = hostapd_das_find_sta(hapd, attr);
+       if (sta == NULL)
+               return RADIUS_DAS_SESSION_NOT_FOUND;
+
+       hostapd_drv_sta_deauth(hapd, sta->addr,
+                              WLAN_REASON_PREV_AUTH_NOT_VALID);
+       ap_sta_deauthenticate(hapd, sta, WLAN_REASON_PREV_AUTH_NOT_VALID);
+
+       return RADIUS_DAS_SUCCESS;
+}
+
+#endif /* CONFIG_NO_RADIUS */
 
 
 /**
@@ -519,7 +646,7 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
        if (conf->wmm_enabled < 0)
                conf->wmm_enabled = hapd->iconf->ieee80211n;
 
-       hostapd_flush_old_stations(hapd);
+       hostapd_flush_old_stations(hapd, WLAN_REASON_PREV_AUTH_NOT_VALID);
        hostapd_set_privacy(hapd, 0);
 
        hostapd_broadcast_wep_clear(hapd);
@@ -583,6 +710,27 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
                wpa_printf(MSG_ERROR, "RADIUS client initialization failed.");
                return -1;
        }
+
+       if (hapd->conf->radius_das_port) {
+               struct radius_das_conf das_conf;
+               os_memset(&das_conf, 0, sizeof(das_conf));
+               das_conf.port = hapd->conf->radius_das_port;
+               das_conf.shared_secret = hapd->conf->radius_das_shared_secret;
+               das_conf.shared_secret_len =
+                       hapd->conf->radius_das_shared_secret_len;
+               das_conf.client_addr = &hapd->conf->radius_das_client_addr;
+               das_conf.time_window = hapd->conf->radius_das_time_window;
+               das_conf.require_event_timestamp =
+                       hapd->conf->radius_das_require_event_timestamp;
+               das_conf.ctx = hapd;
+               das_conf.disconnect = hostapd_das_disconnect;
+               hapd->radius_das = radius_das_init(&das_conf);
+               if (hapd->radius_das == NULL) {
+                       wpa_printf(MSG_ERROR, "RADIUS DAS initialization "
+                                  "failed.");
+                       return -1;
+               }
+       }
 #endif /* CONFIG_NO_RADIUS */
 
        if (hostapd_acl_init(hapd)) {
@@ -615,6 +763,13 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
                return -1;
        }
 
+#ifdef CONFIG_INTERWORKING
+       if (gas_serv_init(hapd)) {
+               wpa_printf(MSG_ERROR, "GAS server initialization failed");
+               return -1;
+       }
+#endif /* CONFIG_INTERWORKING */
+
        if (hapd->iface->ctrl_iface_init &&
            hapd->iface->ctrl_iface_init(hapd)) {
                wpa_printf(MSG_ERROR, "Failed to setup control interface");
@@ -857,6 +1012,7 @@ hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
        hapd->conf = bss;
        hapd->iface = hapd_iface;
        hapd->driver = hapd->iconf->driver;
+       hapd->ctrl_sock = -1;
 
        return hapd;
 }
@@ -873,7 +1029,8 @@ void hostapd_interface_deinit(struct hostapd_iface *iface)
        for (j = 0; j < iface->num_bss; j++) {
                struct hostapd_data *hapd = iface->bss[j];
                hostapd_free_stas(hapd);
-               hostapd_flush_old_stations(hapd);
+               hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
+               hostapd_clear_wep(hapd);
                hostapd_cleanup(hapd);
        }
 }
@@ -937,4 +1094,12 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
                        wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH);
        } else
                wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
+
+       wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
+                  "for " MACSTR " (%d seconds - ap_max_inactivity)",
+                  __func__, MAC2STR(sta->addr),
+                  hapd->conf->ap_max_inactivity);
+       eloop_cancel_timeout(ap_handle_timer, hapd, sta);
+       eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
+                              ap_handle_timer, hapd, sta);
 }
index bc28805..f7ed311 100644 (file)
@@ -15,7 +15,6 @@ struct wpa_driver_ops;
 struct wpa_ctrl_dst;
 struct radius_server_data;
 struct upnp_wps_device_sm;
-struct hapd_interfaces;
 struct hostapd_data;
 struct sta_info;
 struct hostap_sta_driver_data;
@@ -24,9 +23,15 @@ struct full_dynamic_vlan;
 enum wps_event;
 union wps_event_data;
 
+struct hapd_interfaces {
+       size_t count;
+       struct hostapd_iface **iface;
+};
+
+
 struct hostapd_probereq_cb {
        int (*cb)(void *ctx, const u8 *sa, const u8 *da, const u8 *bssid,
-                 const u8 *ie, size_t ie_len);
+                 const u8 *ie, size_t ie_len, int ssi_signal);
        void *ctx;
 };
 
@@ -40,7 +45,7 @@ struct hostapd_rate_data {
 struct hostapd_frame_info {
        u32 channel;
        u32 datarate;
-       u32 ssi_signal;
+       int ssi_signal; /* dBm */
 };
 
 
@@ -80,6 +85,7 @@ struct hostapd_data {
 
        struct radius_client_data *radius;
        u32 acct_session_id_hi, acct_session_id_lo;
+       struct radius_das_data *radius_das;
 
        struct iapp_data *iapp;
 
@@ -164,6 +170,9 @@ struct hostapd_data {
        int noa_start;
        int noa_duration;
 #endif /* CONFIG_P2P */
+#ifdef CONFIG_INTERWORKING
+       size_t gas_frag_limit;
+#endif /* CONFIG_INTERWORKING */
 };
 
 
@@ -242,6 +251,9 @@ struct hostapd_iface {
 };
 
 /* hostapd.c */
+int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
+                              int (*cb)(struct hostapd_iface *iface,
+                                        void *ctx), void *ctx);
 int hostapd_reload_config(struct hostapd_iface *iface);
 struct hostapd_data *
 hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
@@ -258,7 +270,8 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
 int hostapd_register_probereq_cb(struct hostapd_data *hapd,
                                 int (*cb)(void *ctx, const u8 *sa,
                                           const u8 *da, const u8 *bssid,
-                                          const u8 *ie, size_t ie_len),
+                                          const u8 *ie, size_t ie_len,
+                                          int ssi_signal),
                                 void *ctx);
 void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr);
 
@@ -268,6 +281,9 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
 void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr);
 void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr);
 int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
-                        const u8 *bssid, const u8 *ie, size_t ie_len);
+                        const u8 *bssid, const u8 *ie, size_t ie_len,
+                        int ssi_signal);
+void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
+                            int offset);
 
 #endif /* HOSTAPD_H */
index 8c6fef2..76c4211 100644 (file)
@@ -2,7 +2,7 @@
  * hostapd / Hardware feature query and different modes
  * Copyright 2002-2003, Instant802 Networks, Inc.
  * Copyright 2005-2006, Devicescape Software, Inc.
- * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-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
@@ -416,7 +416,7 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
        int res;
 
        /* Check list of neighboring BSSes (from scan) to see whether 40 MHz is
-        * allowed per IEEE 802.11n/D7.0, 11.14.3.2 */
+        * allowed per IEEE Std 802.11-2012, 10.15.3.2 */
 
        iface->scan_cb = NULL;
 
@@ -447,6 +447,46 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
 }
 
 
+static void ieee80211n_scan_channels_2g4(struct hostapd_iface *iface,
+                                        struct wpa_driver_scan_params *params)
+{
+       /* Scan only the affected frequency range */
+       int pri_freq, sec_freq;
+       int affected_start, affected_end;
+       int i, pos;
+       struct hostapd_hw_modes *mode;
+
+       if (iface->current_mode == NULL)
+               return;
+
+       pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
+       if (iface->conf->secondary_channel > 0)
+               sec_freq = pri_freq + 20;
+       else
+               sec_freq = pri_freq - 20;
+       affected_start = (pri_freq + sec_freq) / 2 - 25;
+       affected_end = (pri_freq + sec_freq) / 2 + 25;
+       wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
+                  affected_start, affected_end);
+
+       mode = iface->current_mode;
+       params->freqs = os_zalloc((mode->num_channels + 1) * sizeof(int));
+       if (params->freqs == NULL)
+               return;
+       pos = 0;
+
+       for (i = 0; i < mode->num_channels; i++) {
+               struct hostapd_channel_data *chan = &mode->channels[i];
+               if (chan->flag & HOSTAPD_CHAN_DISABLED)
+                       continue;
+               if (chan->freq < affected_start ||
+                   chan->freq > affected_end)
+                       continue;
+               params->freqs[pos++] = chan->freq;
+       }
+}
+
+
 static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
 {
        struct wpa_driver_scan_params params;
@@ -457,12 +497,15 @@ static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
        wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling "
                   "40 MHz channel");
        os_memset(&params, 0, sizeof(params));
-       /* TODO: scan only the needed frequency */
+       if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
+               ieee80211n_scan_channels_2g4(iface, &params);
        if (hostapd_driver_scan(iface->bss[0], &params) < 0) {
                wpa_printf(MSG_ERROR, "Failed to request a scan of "
                           "neighboring BSSes");
+               os_free(params.freqs);
                return -1;
        }
+       os_free(params.freqs);
 
        iface->scan_cb = ieee80211n_check_scan;
        return 1;
index 9c931ca..3996c90 100644 (file)
@@ -876,6 +876,7 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
 #endif /* CONFIG_IEEE80211N */
 
        p = hostapd_eid_ext_capab(hapd, p);
+       p = hostapd_eid_bss_max_idle_period(hapd, p);
 
        if (sta->flags & WLAN_STA_WMM)
                p = hostapd_eid_wmm(hapd, p);
@@ -1392,7 +1393,7 @@ void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
 
 
        if (stype == WLAN_FC_STYPE_PROBE_REQ) {
-               handle_probe_req(hapd, mgmt, len);
+               handle_probe_req(hapd, mgmt, len, fi->ssi_signal);
                return;
        }
 
index d30e90f..9993bee 100644 (file)
@@ -45,6 +45,8 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
 int hostapd_ht_operation_update(struct hostapd_iface *iface);
 void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
                                  const u8 *addr, const u8 *trans_id);
@@ -72,5 +74,6 @@ u8 * hostapd_eid_time_adv(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid);
 int hostapd_update_time_adv(struct hostapd_data *hapd);
 void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr);
+u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid);
 
 #endif /* IEEE802_11_H */
index 109c4bc..0c4c5f3 100644 (file)
@@ -193,7 +193,8 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
                goto fail;
        }
 
-       radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr);
+       if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr) < 0)
+               goto fail;
        return 0;
 
  fail:
@@ -492,7 +493,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
                }
 
                if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
-                   cache->psk == NULL)
+                   !cache->has_psk)
                        cache->accepted = HOSTAPD_ACL_REJECT;
        } else
                cache->accepted = HOSTAPD_ACL_REJECT;
index 0935cd5..b3fdf3d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / IEEE 802.11 Management
- * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -397,3 +397,31 @@ int hostapd_update_time_adv(struct hostapd_data *hapd)
 
        return 0;
 }
+
+
+u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
+{
+       u8 *pos = eid;
+
+#ifdef CONFIG_WNM
+       if (hapd->conf->ap_max_inactivity > 0) {
+               unsigned int val;
+               *pos++ = WLAN_EID_BSS_MAX_IDLE_PERIOD;
+               *pos++ = 3;
+               val = hapd->conf->ap_max_inactivity;
+               if (val > 68000)
+                       val = 68000;
+               val *= 1000;
+               val /= 1024;
+               if (val == 0)
+                       val = 1;
+               if (val > 65535)
+                       val = 65535;
+               WPA_PUT_LE16(pos, val);
+               pos += 2;
+               *pos++ = 0x00; /* TODO: Protected Keep-Alive Required */
+       }
+#endif /* CONFIG_WNM */
+
+       return pos;
+}
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
new file mode 100644 (file)
index 0000000..3ad33c8
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * hostapd / IEEE 802.11ac VHT
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of BSD license
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "drivers/driver.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "sta_info.h"
+#include "beacon.h"
+#include "ieee802_11.h"
+
+
+u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid)
+{
+       struct ieee80211_vht_capabilities *cap;
+       u8 *pos = eid;
+
+       if (!hapd->iconf->ieee80211ac || !hapd->iface->current_mode ||
+           hapd->conf->disable_11ac)
+               return eid;
+
+       *pos++ = WLAN_EID_VHT_CAP;
+       *pos++ = sizeof(*cap);
+
+       cap = (struct ieee80211_vht_capabilities *) pos;
+       os_memset(cap, 0, sizeof(*cap));
+       cap->vht_capabilities_info = host_to_le32(
+               hapd->iface->current_mode->vht_capab);
+
+       /* Supported MCS set comes from hw */
+       os_memcpy(cap->vht_supported_mcs_set,
+                 hapd->iface->current_mode->vht_mcs_set, 8);
+
+       pos += sizeof(*cap);
+
+       return pos;
+}
+
+
+u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
+{
+       struct ieee80211_vht_operation *oper;
+       u8 *pos = eid;
+
+       if (!hapd->iconf->ieee80211ac || hapd->conf->disable_11ac)
+               return eid;
+
+       *pos++ = WLAN_EID_VHT_OPERATION;
+       *pos++ = sizeof(*oper);
+
+       oper = (struct ieee80211_vht_operation *) pos;
+       os_memset(oper, 0, sizeof(*oper));
+
+       oper->vht_op_info_chwidth = hapd->iconf->vht_oper_chwidth;
+
+       /* VHT Basic MCS set comes from hw */
+       /* Hard code 1 stream, MCS0-7 is a min Basic VHT MCS rates */
+       oper->vht_basic_mcs_set = 0xfffc;
+       pos += sizeof(*oper);
+
+       return pos;
+}
index a329777..dd0df1d 100644 (file)
@@ -416,6 +416,7 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
        struct radius_msg *msg;
        char buf[128];
        struct eapol_state_machine *sm = sta->eapol_sm;
+       struct hostapd_radius_attr *attr;
 
        if (sm == NULL)
                return;
@@ -442,7 +443,9 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
                goto fail;
        }
 
-       if (hapd->conf->own_ip_addr.af == AF_INET &&
+       if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+                                           RADIUS_ATTR_NAS_IP_ADDRESS) &&
+           hapd->conf->own_ip_addr.af == AF_INET &&
            !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
                                 (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
                printf("Could not add NAS-IP-Address\n");
@@ -450,7 +453,9 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
        }
 
 #ifdef CONFIG_IPV6
-       if (hapd->conf->own_ip_addr.af == AF_INET6 &&
+       if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+                                           RADIUS_ATTR_NAS_IPV6_ADDRESS) &&
+           hapd->conf->own_ip_addr.af == AF_INET6 &&
            !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
                                 (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
                printf("Could not add NAS-IPv6-Address\n");
@@ -458,7 +463,9 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
        }
 #endif /* CONFIG_IPV6 */
 
-       if (hapd->conf->nas_identifier &&
+       if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+                                           RADIUS_ATTR_NAS_IDENTIFIER) &&
+           hapd->conf->nas_identifier &&
            !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
                                 (u8 *) hapd->conf->nas_identifier,
                                 os_strlen(hapd->conf->nas_identifier))) {
@@ -466,7 +473,9 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
                goto fail;
        }
 
-       if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
+       if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+                                           RADIUS_ATTR_NAS_PORT) &&
+           !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
                printf("Could not add NAS-Port\n");
                goto fail;
        }
@@ -474,7 +483,9 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
        os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
                    MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
        buf[sizeof(buf) - 1] = '\0';
-       if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
+       if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+                                           RADIUS_ATTR_CALLED_STATION_ID) &&
+           !radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
                                 (u8 *) buf, os_strlen(buf))) {
                printf("Could not add Called-Station-Id\n");
                goto fail;
@@ -492,12 +503,16 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
        /* TODO: should probably check MTU from driver config; 2304 is max for
         * IEEE 802.11, but use 1400 to avoid problems with too large packets
         */
-       if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) {
+       if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+                                           RADIUS_ATTR_FRAMED_MTU) &&
+           !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) {
                printf("Could not add Framed-MTU\n");
                goto fail;
        }
 
-       if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
+       if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+                                           RADIUS_ATTR_NAS_PORT_TYPE) &&
+           !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
                                       RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
                printf("Could not add NAS-Port-Type\n");
                goto fail;
@@ -513,7 +528,9 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
                            radius_mode_txt(hapd));
                buf[sizeof(buf) - 1] = '\0';
        }
-       if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
+       if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+                                           RADIUS_ATTR_CONNECT_INFO) &&
+           !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
                                 (u8 *) buf, os_strlen(buf))) {
                printf("Could not add Connect-Info\n");
                goto fail;
@@ -541,6 +558,36 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
                }
        }
 
+       if (hapd->conf->radius_request_cui) {
+               const u8 *cui;
+               size_t cui_len;
+               /* Add previously learned CUI or nul CUI to request CUI */
+               if (sm->radius_cui) {
+                       cui = wpabuf_head(sm->radius_cui);
+                       cui_len = wpabuf_len(sm->radius_cui);
+               } else {
+                       cui = (const u8 *) "\0";
+                       cui_len = 1;
+               }
+               if (!radius_msg_add_attr(msg,
+                                        RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+                                        cui, cui_len)) {
+                       wpa_printf(MSG_ERROR, "Could not add CUI");
+                       goto fail;
+               }
+       }
+
+       for (attr = hapd->conf->radius_auth_req_attr; attr; attr = attr->next)
+       {
+               if (!radius_msg_add_attr(msg, attr->type,
+                                        wpabuf_head(attr->val),
+                                        wpabuf_len(attr->val))) {
+                       wpa_printf(MSG_ERROR, "Could not add RADIUS "
+                                  "attribute");
+                       goto fail;
+               }
+       }
+
        if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr) < 0)
                goto fail;
 
@@ -861,12 +908,22 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
        if (!force_1x && !hapd->conf->ieee802_1x) {
                wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - "
                           "802.1X not enabled or forced for WPS");
+               /*
+                * Clear any possible EAPOL authenticator state to support
+                * reassociation change from WPS to PSK.
+                */
+               ieee802_1x_free_station(sta);
                return;
        }
 
        key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm);
        if (key_mgmt != -1 && wpa_key_mgmt_wpa_psk(key_mgmt)) {
                wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - using PSK");
+               /*
+                * Clear any possible EAPOL authenticator state to support
+                * reassociation change from WPA-EAP to PSK.
+                */
+               ieee802_1x_free_station(sta);
                return;
        }
 
@@ -968,6 +1025,7 @@ void ieee802_1x_free_station(struct sta_info *sta)
 #ifndef CONFIG_NO_RADIUS
        radius_msg_free(sm->last_recv_radius);
        radius_free_class(&sm->radius_class);
+       wpabuf_free(sm->radius_cui);
 #endif /* CONFIG_NO_RADIUS */
 
        os_free(sm->identity);
@@ -1189,6 +1247,32 @@ static void ieee802_1x_update_sta_identity(struct hostapd_data *hapd,
 }
 
 
+/* Update CUI based on Chargeable-User-Identity attribute in Access-Accept */
+static void ieee802_1x_update_sta_cui(struct hostapd_data *hapd,
+                                     struct sta_info *sta,
+                                     struct radius_msg *msg)
+{
+       struct eapol_state_machine *sm = sta->eapol_sm;
+       struct wpabuf *cui;
+       u8 *buf;
+       size_t len;
+
+       if (sm == NULL)
+               return;
+
+       if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+                                   &buf, &len, NULL) < 0)
+               return;
+
+       cui = wpabuf_alloc_copy(buf, len);
+       if (cui == NULL)
+               return;
+
+       wpabuf_free(sm->radius_cui);
+       sm->radius_cui = cui;
+}
+
+
 struct sta_id_search {
        u8 identifier;
        struct eapol_state_machine *sm;
@@ -1348,6 +1432,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
                                    shared_secret_len);
                ieee802_1x_store_radius_class(hapd, sta, msg);
                ieee802_1x_update_sta_identity(hapd, sta, msg);
+               ieee802_1x_update_sta_cui(hapd, sta, msg);
                if (sm->eap_if->eapKeyAvailable &&
                    wpa_auth_pmksa_add(sta->wpa_sm, sm->eapol_key_crypt,
                                       session_timeout_set ?
@@ -1865,6 +1950,14 @@ u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
 }
 
 
+struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm)
+{
+       if (sm == NULL)
+               return NULL;
+       return sm->radius_cui;
+}
+
+
 const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len)
 {
        *len = 0;
index 58f6084..f9b05ca 100644 (file)
@@ -67,6 +67,7 @@ int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
 u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len);
 u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
                                 int idx);
+struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm);
 const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len);
 void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
                                    int enabled);
index 9eb4840..ba2c033 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd - PMKSA cache for IEEE 802.11i RSN
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -40,6 +40,7 @@ static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
        if (entry == NULL)
                return;
        os_free(entry->identity);
+       wpabuf_free(entry->cui);
 #ifndef CONFIG_NO_RADIUS
        radius_free_class(&entry->radius_class);
 #endif /* CONFIG_NO_RADIUS */
@@ -136,6 +137,9 @@ static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
                }
        }
 
+       if (eapol->radius_cui)
+               entry->cui = wpabuf_dup(eapol->radius_cui);
+
 #ifndef CONFIG_NO_RADIUS
        radius_copy_class(&entry->radius_class, &eapol->radius_class);
 #endif /* CONFIG_NO_RADIUS */
@@ -163,6 +167,11 @@ void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
                                  eapol->identity, eapol->identity_len);
        }
 
+       if (entry->cui) {
+               wpabuf_free(eapol->radius_cui);
+               eapol->radius_cui = wpabuf_dup(entry->cui);
+       }
+
 #ifndef CONFIG_NO_RADIUS
        radius_free_class(&eapol->radius_class);
        radius_copy_class(&eapol->radius_class, &entry->radius_class);
@@ -299,6 +308,8 @@ pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
                                  old_entry->identity_len);
                }
        }
+       if (old_entry->cui)
+               entry->cui = wpabuf_dup(old_entry->cui);
 #ifndef CONFIG_NO_RADIUS
        radius_copy_class(&entry->radius_class, &old_entry->radius_class);
 #endif /* CONFIG_NO_RADIUS */
index 74b73c4..d473f3f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd - PMKSA cache for IEEE 802.11i RSN
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -25,6 +25,7 @@ struct rsn_pmksa_cache_entry {
 
        u8 *identity;
        size_t identity_len;
+       struct wpabuf *cui;
        struct radius_class_data radius_class;
        u8 eap_type_authsrv;
        int vlan_id;
index afabdaa..95b701c 100644 (file)
@@ -28,6 +28,7 @@
 #include "vlan_init.h"
 #include "p2p_hostapd.h"
 #include "ap_drv_ops.h"
+#include "gas_serv.h"
 #include "sta_info.h"
 
 static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
@@ -194,6 +195,8 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
        if (set_beacon)
                ieee802_11_set_beacons(hapd->iface);
 
+       wpa_printf(MSG_DEBUG, "%s: cancel ap_handle_timer for " MACSTR,
+                  __func__, MAC2STR(sta->addr));
        eloop_cancel_timeout(ap_handle_timer, hapd, sta);
        eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
        eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
@@ -218,6 +221,15 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
        p2p_group_notif_disassoc(hapd->p2p_group, sta->addr);
 #endif /* CONFIG_P2P */
 
+#ifdef CONFIG_INTERWORKING
+       if (sta->gas_dialog) {
+               int i;
+               for (i = 0; i < GAS_DIALOG_MAX; i++)
+                       gas_serv_dialog_clear(&sta->gas_dialog[i]);
+               os_free(sta->gas_dialog);
+       }
+#endif /* CONFIG_INTERWORKING */
+
        wpabuf_free(sta->wps_ie);
        wpabuf_free(sta->p2p_ie);
 
@@ -262,6 +274,9 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
        struct sta_info *sta = timeout_ctx;
        unsigned long next_time = 0;
 
+       wpa_printf(MSG_DEBUG, "%s: " MACSTR " flags=0x%x timeout_next=%d",
+                  __func__, MAC2STR(sta->addr), sta->flags,
+                  sta->timeout_next);
        if (sta->timeout_next == STA_REMOVE) {
                hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
                               HOSTAPD_LEVEL_INFO, "deauthenticated due to "
@@ -274,6 +289,12 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
            (sta->timeout_next == STA_NULLFUNC ||
             sta->timeout_next == STA_DISASSOC)) {
                int inactive_sec;
+               /*
+                * Add random value to timeout so that we don't end up bouncing
+                * all stations at the same time if we have lots of associated
+                * stations that are idle (but keep re-associating).
+                */
+               int fuzz = os_random() % 20;
                inactive_sec = hostapd_drv_get_inact_sec(hapd, sta->addr);
                if (inactive_sec == -1) {
                        wpa_msg(hapd->msg_ctx, MSG_DEBUG,
@@ -285,7 +306,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
                         * Anyway, try again after the next inactivity timeout,
                         * but do not disconnect the station now.
                         */
-                       next_time = hapd->conf->ap_max_inactivity;
+                       next_time = hapd->conf->ap_max_inactivity + fuzz;
                } else if (inactive_sec < hapd->conf->ap_max_inactivity &&
                           sta->flags & WLAN_STA_ASSOC) {
                        /* station activity detected; reset timeout state */
@@ -293,7 +314,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
                                "Station " MACSTR " has been active %is ago",
                                MAC2STR(sta->addr), inactive_sec);
                        sta->timeout_next = STA_NULLFUNC;
-                       next_time = hapd->conf->ap_max_inactivity -
+                       next_time = hapd->conf->ap_max_inactivity + fuzz -
                                inactive_sec;
                } else {
                        wpa_msg(hapd->msg_ctx, MSG_DEBUG,
@@ -320,6 +341,9 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
        }
 
        if (next_time) {
+               wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
+                          "for " MACSTR " (%lu seconds)",
+                          __func__, MAC2STR(sta->addr), next_time);
                eloop_register_timeout(next_time, 0, ap_handle_timer, hapd,
                                       sta);
                return;
@@ -353,6 +377,9 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
        switch (sta->timeout_next) {
        case STA_NULLFUNC:
                sta->timeout_next = STA_DISASSOC;
+               wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
+                          "for " MACSTR " (%d seconds - AP_DISASSOC_DELAY)",
+                          __func__, MAC2STR(sta->addr), AP_DISASSOC_DELAY);
                eloop_register_timeout(AP_DISASSOC_DELAY, 0, ap_handle_timer,
                                       hapd, sta);
                break;
@@ -369,6 +396,9 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
                               HOSTAPD_LEVEL_INFO, "disassociated due to "
                               "inactivity");
                sta->timeout_next = STA_DEAUTH;
+               wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
+                          "for " MACSTR " (%d seconds - AP_DEAUTH_DELAY)",
+                          __func__, MAC2STR(sta->addr), AP_DEAUTH_DELAY);
                eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
                                       hapd, sta);
                mlme_disassociate_indication(
@@ -397,8 +427,14 @@ static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
        struct sta_info *sta = timeout_ctx;
        u8 addr[ETH_ALEN];
 
-       if (!(sta->flags & WLAN_STA_AUTH))
+       if (!(sta->flags & WLAN_STA_AUTH)) {
+               if (sta->flags & WLAN_STA_GAS) {
+                       wpa_printf(MSG_DEBUG, "GAS: Remove temporary STA "
+                                  "entry " MACSTR, MAC2STR(sta->addr));
+                       ap_free_sta(hapd, sta);
+               }
                return;
+       }
 
        mlme_deauthenticate_indication(hapd, sta,
                                       WLAN_REASON_PREV_AUTH_NOT_VALID);
@@ -455,6 +491,10 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
        sta->acct_interim_interval = hapd->conf->acct_interim_interval;
 
        /* initialize STA info data */
+       wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
+                  "for " MACSTR " (%d seconds - ap_max_inactivity)",
+                  __func__, MAC2STR(addr),
+                  hapd->conf->ap_max_inactivity);
        eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
                               ap_handle_timer, hapd, sta);
        os_memcpy(sta->addr, addr, ETH_ALEN);
@@ -528,6 +568,11 @@ void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
        sta->flags &= ~WLAN_STA_ASSOC;
        ap_sta_set_authorized(hapd, sta, 0);
        sta->timeout_next = STA_DEAUTH;
+       wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
+                  "for " MACSTR " (%d seconds - "
+                  "AP_MAX_INACTIVITY_AFTER_DISASSOC)",
+                  __func__, MAC2STR(sta->addr),
+                  AP_MAX_INACTIVITY_AFTER_DISASSOC);
        eloop_cancel_timeout(ap_handle_timer, hapd, sta);
        eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0,
                               ap_handle_timer, hapd, sta);
@@ -561,6 +606,11 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
        sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
        ap_sta_set_authorized(hapd, sta, 0);
        sta->timeout_next = STA_REMOVE;
+       wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
+                  "for " MACSTR " (%d seconds - "
+                  "AP_MAX_INACTIVITY_AFTER_DEAUTH)",
+                  __func__, MAC2STR(sta->addr),
+                  AP_MAX_INACTIVITY_AFTER_DEAUTH);
        eloop_cancel_timeout(ap_handle_timer, hapd, sta);
        eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
                               ap_handle_timer, hapd, sta);
@@ -576,6 +626,23 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
 }
 
 
+#ifdef CONFIG_WPS
+int ap_sta_wps_cancel(struct hostapd_data *hapd,
+                     struct sta_info *sta, void *ctx)
+{
+       if (sta && (sta->flags & WLAN_STA_WPS)) {
+               ap_sta_deauthenticate(hapd, sta,
+                                     WLAN_REASON_PREV_AUTH_NOT_VALID);
+               wpa_printf(MSG_DEBUG, "WPS: %s: Deauth sta=" MACSTR,
+                          __func__, MAC2STR(sta->addr));
+               return 1;
+       }
+
+       return 0;
+}
+#endif /* CONFIG_WPS */
+
+
 int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
                     int old_vlanid)
 {
@@ -778,11 +845,20 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
                           int authorized)
 {
        const u8 *dev_addr = NULL;
+#ifdef CONFIG_P2P
+       u8 addr[ETH_ALEN];
+#endif /* CONFIG_P2P */
+
        if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED))
                return;
 
 #ifdef CONFIG_P2P
-       dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr);
+       if (hapd->p2p_group == NULL) {
+               if (sta->p2p_ie != NULL &&
+                   p2p_parse_dev_addr_in_p2p_ie(sta->p2p_ie, addr) == 0)
+                       dev_addr = addr;
+       } else
+               dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr);
 #endif /* CONFIG_P2P */
 
        if (authorized) {
@@ -848,6 +924,11 @@ void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
        wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
        ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
        sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+       wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
+                  "for " MACSTR " (%d seconds - "
+                  "AP_MAX_INACTIVITY_AFTER_DEAUTH)",
+                  __func__, MAC2STR(sta->addr),
+                  AP_MAX_INACTIVITY_AFTER_DEAUTH);
        eloop_cancel_timeout(ap_handle_timer, hapd, sta);
        eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
                               ap_handle_timer, hapd, sta);
index 60b3a7b..cef428d 100644 (file)
@@ -27,6 +27,7 @@
 #define WLAN_STA_WDS BIT(14)
 #define WLAN_STA_ASSOC_REQ_OK BIT(15)
 #define WLAN_STA_WPS2 BIT(16)
+#define WLAN_STA_GAS BIT(17)
 #define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
 #define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
 #define WLAN_STA_NONERP BIT(31)
@@ -107,6 +108,12 @@ struct sta_info {
        struct os_time sa_query_start;
 #endif /* CONFIG_IEEE80211W */
 
+#ifdef CONFIG_INTERWORKING
+#define GAS_DIALOG_MAX 8 /* Max concurrent dialog number */
+       struct gas_dialog_info *gas_dialog;
+       u8 gas_dialog_next;
+#endif /* CONFIG_INTERWORKING */
+
        struct wpabuf *wps_ie; /* WPS IE from (Re)Association Request */
        struct wpabuf *p2p_ie; /* P2P IE from (Re)Association Request */
 };
@@ -137,7 +144,6 @@ int ap_for_each_sta(struct hostapd_data *hapd,
 struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta);
 void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta);
 void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
-void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
 void hostapd_free_stas(struct hostapd_data *hapd);
 void ap_handle_timer(void *eloop_ctx, void *timeout_ctx);
 void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
@@ -149,6 +155,10 @@ void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
                         u16 reason);
 void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
                           u16 reason);
+#ifdef CONFIG_WPS
+int ap_sta_wps_cancel(struct hostapd_data *hapd,
+                     struct sta_info *sta, void *ctx);
+#endif /* CONFIG_WPS */
 int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
                     int old_vlanid);
 void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
index 60088ee..dd5aa68 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / TKIP countermeasures
- * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -11,6 +11,7 @@
 #include "utils/common.h"
 #include "utils/eloop.h"
 #include "common/ieee802_11_defs.h"
+#include "radius/radius.h"
 #include "hostapd.h"
 #include "sta_info.h"
 #include "ap_mlme.h"
@@ -44,12 +45,17 @@ static void ieee80211_tkip_countermeasures_start(struct hostapd_data *hapd)
        eloop_cancel_timeout(ieee80211_tkip_countermeasures_stop, hapd, NULL);
        eloop_register_timeout(60, 0, ieee80211_tkip_countermeasures_stop,
                               hapd, NULL);
-       for (sta = hapd->sta_list; sta != NULL; sta = sta->next) {
+       while ((sta = hapd->sta_list)) {
+               sta->acct_terminate_cause =
+                       RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_RESET;
+               if (sta->flags & WLAN_STA_AUTH) {
+                       mlme_deauthenticate_indication(
+                               hapd, sta,
+                               WLAN_REASON_MICHAEL_MIC_FAILURE);
+               }
                hostapd_drv_sta_deauth(hapd, sta->addr,
                                       WLAN_REASON_MICHAEL_MIC_FAILURE);
-               ap_sta_set_authorized(hapd, sta, 0);
-               sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
-               hostapd_drv_sta_remove(hapd, sta->addr);
+               ap_free_sta(hapd, sta);
        }
 }
 
index 36c1182..3e9fc08 100644 (file)
@@ -17,7 +17,8 @@
 int hostapd_register_probereq_cb(struct hostapd_data *hapd,
                                 int (*cb)(void *ctx, const u8 *sa,
                                           const u8 *da, const u8 *bssid,
-                                          const u8 *ie, size_t ie_len),
+                                          const u8 *ie, size_t ie_len,
+                                          int ssi_signal),
                                 void *ctx)
 {
        struct hostapd_probereq_cb *n;
index d1b9b4d..1d942a4 100644 (file)
@@ -1641,10 +1641,23 @@ SM_STATE(WPA_PTK, AUTHENTICATION2)
 
        wpa_group_ensure_init(sm->wpa_auth, sm->group);
 
-       os_memcpy(sm->ANonce, sm->group->Counter, WPA_NONCE_LEN);
+       /*
+        * Definition of ANonce selection in IEEE Std 802.11i-2004 is somewhat
+        * ambiguous. The Authenticator state machine uses a counter that is
+        * incremented by one for each 4-way handshake. However, the security
+        * analysis of 4-way handshake points out that unpredictable nonces
+        * help in preventing precomputation attacks. Instead of the state
+        * machine definition, use an unpredictable nonce value here to provide
+        * stronger protection against potential precomputation attacks.
+        */
+       if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
+               wpa_printf(MSG_ERROR, "WPA: Failed to get random data for "
+                          "ANonce.");
+               wpa_sta_disconnect(sm->wpa_auth, sm->addr);
+               return;
+       }
        wpa_hexdump(MSG_DEBUG, "WPA: Assign ANonce", sm->ANonce,
                    WPA_NONCE_LEN);
-       inc_byte_array(sm->group->Counter, WPA_NONCE_LEN);
        sm->ReAuthenticationRequest = FALSE;
        /* IEEE 802.11i does not clear TimeoutCtr here, but this is more
         * logical place than INITIALIZE since AUTHENTICATION2 can be
index 8999217..07ce06c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / WPS integration
- * Copyright (c) 2008-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -12,6 +12,8 @@
 #include "utils/eloop.h"
 #include "utils/uuid.h"
 #include "crypto/dh_groups.h"
+#include "crypto/dh_group5.h"
+#include "crypto/random.h"
 #include "common/wpa_ctrl.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
@@ -20,6 +22,7 @@
 #include "wps/wps.h"
 #include "wps/wps_defs.h"
 #include "wps/wps_dev_attr.h"
+#include "wps/wps_attr_parse.h"
 #include "hostapd.h"
 #include "ap_config.h"
 #include "ap_drv_ops.h"
@@ -37,7 +40,8 @@ static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd);
 
 static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da,
                                    const u8 *bssid,
-                                   const u8 *ie, size_t ie_len);
+                                   const u8 *ie, size_t ie_len,
+                                   int ssi_signal);
 static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
 
 
@@ -183,19 +187,23 @@ static void hostapd_wps_pin_needed_cb(void *ctx, const u8 *uuid_e,
 struct wps_stop_reg_data {
        struct hostapd_data *current_hapd;
        const u8 *uuid_e;
+       const u8 *dev_pw;
+       size_t dev_pw_len;
 };
 
 static int wps_stop_registrar(struct hostapd_data *hapd, void *ctx)
 {
        struct wps_stop_reg_data *data = ctx;
        if (hapd != data->current_hapd && hapd->wps != NULL)
-               wps_registrar_complete(hapd->wps->registrar, data->uuid_e);
+               wps_registrar_complete(hapd->wps->registrar, data->uuid_e,
+                                      data->dev_pw, data->dev_pw_len);
        return 0;
 }
 
 
 static void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr,
-                                      const u8 *uuid_e)
+                                      const u8 *uuid_e, const u8 *dev_pw,
+                                      size_t dev_pw_len)
 {
        struct hostapd_data *hapd = ctx;
        char uuid[40];
@@ -209,6 +217,8 @@ static void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr,
                                         mac_addr, uuid_e);
        data.current_hapd = hapd;
        data.uuid_e = uuid_e;
+       data.dev_pw = dev_pw;
+       data.dev_pw_len = dev_pw_len;
        hostapd_wps_for_each(hapd, wps_stop_registrar, &data);
 }
 
@@ -984,6 +994,20 @@ int hostapd_init_wps_complete(struct hostapd_data *hapd)
 }
 
 
+static void hostapd_wps_nfc_clear(struct wps_context *wps)
+{
+#ifdef CONFIG_WPS_NFC
+       wps->ap_nfc_dev_pw_id = 0;
+       wpabuf_free(wps->ap_nfc_dh_pubkey);
+       wps->ap_nfc_dh_pubkey = NULL;
+       wpabuf_free(wps->ap_nfc_dh_privkey);
+       wps->ap_nfc_dh_privkey = NULL;
+       wpabuf_free(wps->ap_nfc_dev_pw);
+       wps->ap_nfc_dev_pw = NULL;
+#endif /* CONFIG_WPS_NFC */
+}
+
+
 void hostapd_deinit_wps(struct hostapd_data *hapd)
 {
        eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
@@ -1001,6 +1025,7 @@ void hostapd_deinit_wps(struct hostapd_data *hapd)
        wpabuf_free(hapd->wps->oob_conf.pubkey_hash);
        wpabuf_free(hapd->wps->oob_conf.dev_password);
        wps_free_pending_msgs(hapd->wps->upnp_msgs);
+       hostapd_wps_nfc_clear(hapd->wps);
        os_free(hapd->wps);
        hapd->wps = NULL;
        hostapd_wps_clear_ies(hapd);
@@ -1098,6 +1123,24 @@ int hostapd_wps_button_pushed(struct hostapd_data *hapd,
 }
 
 
+static int wps_cancel(struct hostapd_data *hapd, void *ctx)
+{
+       if (hapd->wps == NULL)
+               return 0;
+
+       wps_registrar_wps_cancel(hapd->wps->registrar);
+       ap_for_each_sta(hapd, ap_sta_wps_cancel, NULL);
+
+       return 0;
+}
+
+
+int hostapd_wps_cancel(struct hostapd_data *hapd)
+{
+       return hostapd_wps_for_each(hapd, wps_cancel, NULL);
+}
+
+
 #ifdef CONFIG_WPS_OOB
 int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type,
                          char *path, char *method, char *name)
@@ -1154,7 +1197,8 @@ error:
 
 static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da,
                                    const u8 *bssid,
-                                   const u8 *ie, size_t ie_len)
+                                   const u8 *ie, size_t ie_len,
+                                   int ssi_signal)
 {
        struct hostapd_data *hapd = ctx;
        struct wpabuf *wps_ie;
@@ -1471,3 +1515,156 @@ int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid,
 
        return wps_registrar_config_ap(hapd->wps->registrar, &cred);
 }
+
+
+#ifdef CONFIG_WPS_NFC
+
+struct wps_nfc_password_token_data {
+       const u8 *oob_dev_pw;
+       size_t oob_dev_pw_len;
+       int added;
+};
+
+
+static int wps_add_nfc_password_token(struct hostapd_data *hapd, void *ctx)
+{
+       struct wps_nfc_password_token_data *data = ctx;
+       int ret;
+
+       if (hapd->wps == NULL)
+               return 0;
+       ret = wps_registrar_add_nfc_password_token(hapd->wps->registrar,
+                                                  data->oob_dev_pw,
+                                                  data->oob_dev_pw_len);
+       if (ret == 0)
+               data->added++;
+       return ret;
+}
+
+
+static int hostapd_wps_add_nfc_password_token(struct hostapd_data *hapd,
+                                             struct wps_parse_attr *attr)
+{
+       struct wps_nfc_password_token_data data;
+
+       data.oob_dev_pw = attr->oob_dev_password;
+       data.oob_dev_pw_len = attr->oob_dev_password_len;
+       data.added = 0;
+       if (hostapd_wps_for_each(hapd, wps_add_nfc_password_token, &data) < 0)
+               return -1;
+       return data.added ? 0 : -1;
+}
+
+
+static int hostapd_wps_nfc_tag_process(struct hostapd_data *hapd,
+                                      const struct wpabuf *wps)
+{
+       struct wps_parse_attr attr;
+
+       wpa_hexdump_buf(MSG_DEBUG, "WPS: Received NFC tag payload", wps);
+
+       if (wps_parse_msg(wps, &attr)) {
+               wpa_printf(MSG_DEBUG, "WPS: Ignore invalid data from NFC tag");
+               return -1;
+       }
+
+       if (attr.oob_dev_password)
+               return hostapd_wps_add_nfc_password_token(hapd, &attr);
+
+       wpa_printf(MSG_DEBUG, "WPS: Ignore unrecognized NFC tag");
+       return -1;
+}
+
+
+int hostapd_wps_nfc_tag_read(struct hostapd_data *hapd,
+                            const struct wpabuf *data)
+{
+       const struct wpabuf *wps = data;
+       struct wpabuf *tmp = NULL;
+       int ret;
+
+       if (wpabuf_len(data) < 4)
+               return -1;
+
+       if (*wpabuf_head_u8(data) != 0x10) {
+               /* Assume this contains full NDEF record */
+               tmp = ndef_parse_wifi(data);
+               if (tmp == NULL) {
+                       wpa_printf(MSG_DEBUG, "WPS: Could not parse NDEF");
+                       return -1;
+               }
+               wps = tmp;
+       }
+
+       ret = hostapd_wps_nfc_tag_process(hapd, wps);
+       wpabuf_free(tmp);
+       return ret;
+}
+
+
+struct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd,
+                                            int ndef)
+{
+       struct wpabuf *ret;
+
+       if (hapd->wps == NULL)
+               return NULL;
+
+       ret = wps_get_oob_cred(hapd->wps);
+       if (ndef && ret) {
+               struct wpabuf *tmp;
+               tmp = ndef_build_wifi(ret);
+               wpabuf_free(ret);
+               if (tmp == NULL)
+                       return NULL;
+               ret = tmp;
+       }
+
+       return ret;
+}
+
+
+struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef)
+{
+       return wps_nfc_token_gen(ndef, &hapd->conf->wps_nfc_dev_pw_id,
+                                &hapd->conf->wps_nfc_dh_pubkey,
+                                &hapd->conf->wps_nfc_dh_privkey,
+                                &hapd->conf->wps_nfc_dev_pw);
+}
+
+
+int hostapd_wps_nfc_token_enable(struct hostapd_data *hapd)
+{
+       struct wps_context *wps = hapd->wps;
+
+       if (wps == NULL)
+               return -1;
+
+       if (!hapd->conf->wps_nfc_dh_pubkey ||
+           !hapd->conf->wps_nfc_dh_privkey ||
+           !hapd->conf->wps_nfc_dev_pw ||
+           !hapd->conf->wps_nfc_dev_pw_id)
+               return -1;
+
+       hostapd_wps_nfc_clear(wps);
+       wps->ap_nfc_dev_pw_id = hapd->conf->wps_nfc_dev_pw_id;
+       wps->ap_nfc_dh_pubkey = wpabuf_dup(hapd->conf->wps_nfc_dh_pubkey);
+       wps->ap_nfc_dh_privkey = wpabuf_dup(hapd->conf->wps_nfc_dh_privkey);
+       wps->ap_nfc_dev_pw = wpabuf_dup(hapd->conf->wps_nfc_dev_pw);
+
+       if (!wps->ap_nfc_dh_pubkey || !wps->ap_nfc_dh_privkey ||
+           !wps->ap_nfc_dev_pw) {
+               hostapd_wps_nfc_clear(wps);
+               return -1;
+       }
+
+       return 0;
+}
+
+
+void hostapd_wps_nfc_token_disable(struct hostapd_data *hapd)
+{
+       hostapd_wps_nfc_clear(hapd->wps);
+}
+
+#endif /* CONFIG_WPS_NFC */
index 9194225..f968e15 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / WPS integration
- * Copyright (c) 2008-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -20,6 +20,7 @@ int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr,
                        const char *uuid, const char *pin, int timeout);
 int hostapd_wps_button_pushed(struct hostapd_data *hapd,
                              const u8 *p2p_dev_addr);
+int hostapd_wps_cancel(struct hostapd_data *hapd);
 int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type,
                          char *path, char *method, char *name);
 int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr,
@@ -32,6 +33,13 @@ int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin,
 void hostapd_wps_update_ie(struct hostapd_data *hapd);
 int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid,
                          const char *auth, const char *encr, const char *key);
+int hostapd_wps_nfc_tag_read(struct hostapd_data *hapd,
+                            const struct wpabuf *data);
+struct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd,
+                                            int ndef);
+struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef);
+int hostapd_wps_nfc_token_enable(struct hostapd_data *hapd);
+void hostapd_wps_nfc_token_disable(struct hostapd_data *hapd);
 
 #else /* CONFIG_WPS */
 
@@ -67,6 +75,11 @@ static inline int hostapd_wps_button_pushed(struct hostapd_data *hapd,
        return 0;
 }
 
+static inline int hostapd_wps_cancel(struct hostapd_data *hapd)
+{
+       return 0;
+}
+
 #endif /* CONFIG_WPS */
 
 #endif /* WPS_HOSTAPD_H */
index b0d310d..d65675c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * IEEE 802.11 Common routines
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -97,6 +97,11 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
                        elems->p2p = pos;
                        elems->p2p_len = elen;
                        break;
+               case HS20_INDICATION_OUI_TYPE:
+                       /* Hotspot 2.0 */
+                       elems->hs20 = pos;
+                       elems->hs20_len = elen;
+                       break;
                default:
                        wpa_printf(MSG_MSGDUMP, "Unknown WFA "
                                   "information element ignored "
@@ -257,6 +262,15 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
                        elems->interworking = pos;
                        elems->interworking_len = elen;
                        break;
+               case WLAN_EID_EXT_CAPAB:
+                       elems->ext_capab = pos;
+                       elems->ext_capab_len = elen;
+                       break;
+               case WLAN_EID_BSS_MAX_IDLE_PERIOD:
+                       if (elen < 3)
+                               break;
+                       elems->bss_max_idle_period = pos;
+                       break;
                default:
                        unknown++;
                        if (!show_errors)
index bfac88c..d9b2b6c 100644 (file)
@@ -37,6 +37,9 @@ struct ieee802_11_elems {
        const u8 *p2p;
        const u8 *link_id;
        const u8 *interworking;
+       const u8 *hs20;
+       const u8 *ext_capab;
+       const u8 *bss_max_idle_period;
 
        u8 ssid_len;
        u8 supp_rates_len;
@@ -63,6 +66,8 @@ struct ieee802_11_elems {
        u8 vendor_ht_cap_len;
        u8 p2p_len;
        u8 interworking_len;
+       u8 hs20_len;
+       u8 ext_capab_len;
 };
 
 typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
index 3bef006..b4f9275 100644 (file)
 #define WLAN_EID_20_40_BSS_INTOLERANT 73
 #define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74
 #define WLAN_EID_MMIE 76
+#define WLAN_EID_BSS_MAX_IDLE_PERIOD 90
+#define WLAN_EID_TFS_REQ 91
+#define WLAN_EID_TFS_RESP 92
+#define WLAN_EID_WNMSLEEP 93
 #define WLAN_EID_TIME_ZONE 98
 #define WLAN_EID_LINK_ID 101
 #define WLAN_EID_INTERWORKING 107
 #define WLAN_EID_ADV_PROTO 108
 #define WLAN_EID_ROAMING_CONSORTIUM 111
 #define WLAN_EID_EXT_CAPAB 127
+#define WLAN_EID_VHT_CAP 191
+#define WLAN_EID_VHT_OPERATION 192
+#define WLAN_EID_VHT_EXTENDED_BSS_LOAD 193
+#define WLAN_EID_VHT_WIDE_BW_CHSWITCH  194
+#define WLAN_EID_VHT_TRANSMIT_POWER_ENVELOPE 195
+#define WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER 196
+#define WLAN_EID_VHT_AID 197
+#define WLAN_EID_VHT_QUIET_CHANNEL 198
+#define WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION 199
 #define WLAN_EID_VENDOR_SPECIFIC 221
 
 
 #define WLAN_ACTION_VENDOR_SPECIFIC 127
 
 /* Public action codes */
+#define WLAN_PA_20_40_BSS_COEX 0
 #define WLAN_PA_VENDOR_SPECIFIC 9
 #define WLAN_PA_GAS_INITIAL_REQ 10
 #define WLAN_PA_GAS_INITIAL_RESP 11
@@ -487,6 +501,17 @@ struct ieee80211_mgmt {
                                } STRUCT_PACKED sa_query_resp;
                                struct {
                                        u8 action;
+                                       u8 dialogtoken;
+                                       u8 variable[0];
+                               } STRUCT_PACKED wnm_sleep_req;
+                               struct {
+                                       u8 action;
+                                       u8 dialogtoken;
+                                       le16 keydata_len;
+                                       u8 variable[0];
+                               } STRUCT_PACKED wnm_sleep_resp;
+                               struct {
+                                       u8 action;
                                        u8 variable[0];
                                } STRUCT_PACKED public_action;
                                struct {
@@ -534,6 +559,19 @@ struct ieee80211_ht_operation {
        u8 basic_set[16];
 } STRUCT_PACKED;
 
+
+struct ieee80211_vht_capabilities {
+       le32 vht_capabilities_info;
+       u8 vht_supported_mcs_set[8];
+} STRUCT_PACKED;
+
+struct ieee80211_vht_operation {
+       u8 vht_op_info_chwidth;
+       u8 vht_op_info_chan_center_freq_seg0_idx;
+       u8 vht_op_info_chan_center_freq_seg1_idx;
+       le16 vht_basic_mcs_set;
+} STRUCT_PACKED;
+
 #ifdef _MSC_VER
 #pragma pack(pop)
 #endif /* _MSC_VER */
@@ -630,12 +668,40 @@ struct ieee80211_ht_operation {
 
 #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
 
+/* VHT Defines */
+#define VHT_CAP_MAX_MPDU_LENGTH_7991                ((u32) BIT(0))
+#define VHT_CAP_MAX_MPDU_LENGTH_11454               ((u32) BIT(1))
+#define VHT_CAP_SUPP_CHAN_WIDTH_160MHZ              ((u32) BIT(2))
+#define VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ     ((u32) BIT(3))
+#define VHT_CAP_RXLDPC                              ((u32) BIT(4))
+#define VHT_CAP_SHORT_GI_80                         ((u32) BIT(5))
+#define VHT_CAP_SHORT_GI_160                        ((u32) BIT(6))
+#define VHT_CAP_TXSTBC                              ((u32) BIT(7))
+#define VHT_CAP_RXSTBC_1                            ((u32) BIT(8))
+#define VHT_CAP_RXSTBC_2                            ((u32) BIT(9))
+#define VHT_CAP_RXSTBC_3                            ((u32) BIT(8) | BIT(9))
+#define VHT_CAP_RXSTBC_4                            ((u32) BIT(10))
+#define VHT_CAP_SU_BEAMFORMER_CAPABLE               ((u32) BIT(11))
+#define VHT_CAP_SU_BEAMFORMEE_CAPABLE               ((u32) BIT(12))
+#define VHT_CAP_BEAMFORMER_ANTENNAS_MAX             ((u32) BIT(13) | BIT(14))
+#define VHT_CAP_SOUNDING_DIMENTION_MAX              ((u32) BIT(16) | BIT(17))
+#define VHT_CAP_MU_BEAMFORMER_CAPABLE               ((u32) BIT(19))
+#define VHT_CAP_MU_BEAMFORMEE_CAPABLE               ((u32) BIT(20))
+#define VHT_CAP_VHT_TXOP_PS                         ((u32) BIT(21))
+#define VHT_CAP_HTC_VHT                             ((u32) BIT(22))
+#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT          ((u32) BIT(23))
+#define VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB   ((u32) BIT(27))
+#define VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB     ((u32) BIT(26) | BIT(27))
+#define VHT_CAP_RX_ANTENNA_PATTERN                  ((u32) BIT(28))
+#define VHT_CAP_TX_ANTENNA_PATTERN                  ((u32) BIT(29))
+
 #define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs)
                                * 00:50:F2 */
 #define WPA_IE_VENDOR_TYPE 0x0050f201
 #define WPS_IE_VENDOR_TYPE 0x0050f204
 #define OUI_WFA 0x506f9a
 #define P2P_IE_VENDOR_TYPE 0x506f9a09
+#define HS20_IE_VENDOR_TYPE 0x506f9a10
 
 #define WMM_OUI_TYPE 2
 #define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0
@@ -749,6 +815,16 @@ enum {
 };
 
 
+#define HS20_INDICATION_OUI_TYPE 16
+#define HS20_ANQP_OUI_TYPE 17
+#define HS20_STYPE_QUERY_LIST 1
+#define HS20_STYPE_CAPABILITY_LIST 2
+#define HS20_STYPE_OPERATOR_FRIENDLY_NAME 3
+#define HS20_STYPE_WAN_METRICS 4
+#define HS20_STYPE_CONNECTION_CAPABILITY 5
+#define HS20_STYPE_NAI_HOME_REALM_QUERY 6
+#define HS20_STYPE_OPERATING_CLASS 7
+
 /* Wi-Fi Direct (P2P) */
 
 #define P2P_OUI_TYPE 9
@@ -915,4 +991,48 @@ enum wnm_action {
 #define WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED BIT(3)
 #define WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT BIT(4)
 
+/* IEEE Std 802.11-2012, 8.4.2.62 20/40 BSS Coexistence element */
+#define WLAN_20_40_BSS_COEX_INFO_REQ            BIT(0)
+#define WLAN_20_40_BSS_COEX_40MHZ_INTOL         BIT(1)
+#define WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ     BIT(2)
+#define WLAN_20_40_BSS_COEX_OBSS_EXEMPT_REQ     BIT(3)
+#define WLAN_20_40_BSS_COEX_OBSS_EXEMPT_GRNT    BIT(4)
+
+struct ieee80211_2040_bss_coex_ie {
+       u8 element_id;
+       u8 length;
+       u8 coex_param;
+} STRUCT_PACKED;
+
+struct ieee80211_2040_intol_chan_report {
+       u8 element_id;
+       u8 length;
+       u8 op_class;
+       u8 variable[0]; /* Channel List */
+} STRUCT_PACKED;
+
+/* IEEE 802.11v - WNM-Sleep Mode element */
+struct wnm_sleep_element {
+       u8 eid;     /* WLAN_EID_WNMSLEEP */
+       u8 len;
+       u8 action_type; /* WLAN_WNM_SLEEP_ENTER/EXIT */
+       u8 status;
+       le16 intval;
+} STRUCT_PACKED;
+
+enum wnm_sleep_mode_response_status {
+       WNM_STATUS_SLEEP_ACCEPT = 0,
+       WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE = 1,
+       WNM_STATUS_DENIED_ACTION = 2,
+       WNM_STATUS_DENIED_TMP = 3,
+       WNM_STATUS_DENIED_KEY = 4,
+       WNM_STATUS_DENIED_OTHER_WNM_SERVICE = 5
+};
+
+/* WNM-Sleep Mode subelement IDs */
+enum wnm_sleep_mode_subelement_id {
+       WNM_SLEEP_SUBELEM_GTK = 0,
+       WNM_SLEEP_SUBELEM_IGTK = 1
+};
+
 #endif /* IEEE802_11_DEFS_H */
index 5768fdd..a440b69 100644 (file)
@@ -120,6 +120,8 @@ extern "C" {
 #define P2P_EVENT_PROV_DISC_PBC_REQ "P2P-PROV-DISC-PBC-REQ "
 /* parameters: <peer address> */
 #define P2P_EVENT_PROV_DISC_PBC_RESP "P2P-PROV-DISC-PBC-RESP "
+/* parameters: <peer address> <status> */
+#define P2P_EVENT_PROV_DISC_FAILURE "P2P-PROV-DISC-FAILURE"
 /* parameters: <freq> <src addr> <dialog token> <update indicator> <TLVs> */
 #define P2P_EVENT_SERV_DISC_REQ "P2P-SERV-DISC-REQ "
 /* parameters: <src addr> <update indicator> <TLVs> */
@@ -143,6 +145,27 @@ extern "C" {
 #define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED "
 
 
+/* BSS command information masks */
+
+#define WPA_BSS_MASK_ALL               0xFFFFFFFF
+#define WPA_BSS_MASK_ID                        BIT(0)
+#define WPA_BSS_MASK_BSSID             BIT(1)
+#define WPA_BSS_MASK_FREQ              BIT(2)
+#define WPA_BSS_MASK_BEACON_INT                BIT(3)
+#define WPA_BSS_MASK_CAPABILITIES      BIT(4)
+#define WPA_BSS_MASK_QUAL              BIT(5)
+#define WPA_BSS_MASK_NOISE             BIT(6)
+#define WPA_BSS_MASK_LEVEL             BIT(7)
+#define WPA_BSS_MASK_TSF               BIT(8)
+#define WPA_BSS_MASK_AGE               BIT(9)
+#define WPA_BSS_MASK_IE                        BIT(10)
+#define WPA_BSS_MASK_FLAGS             BIT(11)
+#define WPA_BSS_MASK_SSID              BIT(12)
+#define WPA_BSS_MASK_WPS_SCAN          BIT(13)
+#define WPA_BSS_MASK_P2P_SCAN          BIT(14)
+#define WPA_BSS_MASK_INTERNETW         BIT(15)
+
+
 /* wpa_supplicant/hostapd control interface access */
 
 /**
index 1171f29..8506fff 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / wrapper functions for libcrypto
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -14,6 +14,7 @@
 #include <openssl/bn.h>
 #include <openssl/evp.h>
 #include <openssl/dh.h>
+#include <openssl/hmac.h>
 
 #include "common.h"
 #include "wpabuf.h"
@@ -452,6 +453,41 @@ err:
 }
 
 
+void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
+{
+       DH *dh;
+
+       dh = DH_new();
+       if (dh == NULL)
+               return NULL;
+
+       dh->g = BN_new();
+       if (dh->g == NULL || BN_set_word(dh->g, 2) != 1)
+               goto err;
+
+       dh->p = get_group5_prime();
+       if (dh->p == NULL)
+               goto err;
+
+       dh->priv_key = BN_bin2bn(wpabuf_head(priv), wpabuf_len(priv), NULL);
+       if (dh->priv_key == NULL)
+               goto err;
+
+       dh->pub_key = BN_bin2bn(wpabuf_head(publ), wpabuf_len(publ), NULL);
+       if (dh->pub_key == NULL)
+               goto err;
+
+       if (DH_generate_key(dh) != 1)
+               goto err;
+
+       return dh;
+
+err:
+       DH_free(dh);
+       return NULL;
+}
+
+
 struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
                                  const struct wpabuf *own_private)
 {
@@ -497,3 +533,93 @@ void dh5_free(void *ctx)
        dh = ctx;
        DH_free(dh);
 }
+
+
+struct crypto_hash {
+       HMAC_CTX ctx;
+};
+
+
+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
+                                     size_t key_len)
+{
+       struct crypto_hash *ctx;
+       const EVP_MD *md;
+
+       switch (alg) {
+#ifndef OPENSSL_NO_MD5
+       case CRYPTO_HASH_ALG_HMAC_MD5:
+               md = EVP_md5();
+               break;
+#endif /* OPENSSL_NO_MD5 */
+#ifndef OPENSSL_NO_SHA
+       case CRYPTO_HASH_ALG_HMAC_SHA1:
+               md = EVP_sha1();
+               break;
+#endif /* OPENSSL_NO_SHA */
+#ifndef OPENSSL_NO_SHA256
+#ifdef CONFIG_SHA256
+       case CRYPTO_HASH_ALG_HMAC_SHA256:
+               md = EVP_sha256();
+               break;
+#endif /* CONFIG_SHA256 */
+#endif /* OPENSSL_NO_SHA256 */
+       default:
+               return NULL;
+       }
+
+       ctx = os_zalloc(sizeof(*ctx));
+       if (ctx == NULL)
+               return NULL;
+
+#if OPENSSL_VERSION_NUMBER < 0x00909000
+       HMAC_Init_ex(&ctx->ctx, key, key_len, md, NULL);
+#else /* openssl < 0.9.9 */
+       if (HMAC_Init_ex(&ctx->ctx, key, key_len, md, NULL) != 1) {
+               os_free(ctx);
+               return NULL;
+       }
+#endif /* openssl < 0.9.9 */
+
+       return ctx;
+}
+
+
+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
+{
+       if (ctx == NULL)
+               return;
+       HMAC_Update(&ctx->ctx, data, len);
+}
+
+
+int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
+{
+       unsigned int mdlen;
+       int res;
+
+       if (ctx == NULL)
+               return -2;
+
+       if (mac == NULL || len == NULL) {
+               os_free(ctx);
+               return 0;
+       }
+
+       mdlen = *len;
+#if OPENSSL_VERSION_NUMBER < 0x00909000
+       HMAC_Final(&ctx->ctx, mac, &mdlen);
+       res = 1;
+#else /* openssl < 0.9.9 */
+       res = HMAC_Final(&ctx->ctx, mac, &mdlen);
+#endif /* openssl < 0.9.9 */
+       HMAC_CTX_cleanup(&ctx->ctx);
+       os_free(ctx);
+
+       if (res == 1) {
+               *len = mdlen;
+               return 0;
+       }
+
+       return -1;
+}
index 9a94ca5..ccdbfc8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Diffie-Hellman group 5 operations
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009, 2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -22,6 +22,12 @@ void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
 }
 
 
+void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
+{
+       return (void *) 1;
+}
+
+
 struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
                                  const struct wpabuf *own_private)
 {
index 8813427..abee8ea 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Diffie-Hellman group 5 operations
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009, 2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -10,6 +10,7 @@
 #define DH_GROUP5_H
 
 void * dh5_init(struct wpabuf **priv, struct wpabuf **publ);
+void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ);
 struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
                                  const struct wpabuf *own_private);
 void dh5_free(void *ctx);
index 55e9391..d85c3e6 100644 (file)
@@ -128,8 +128,6 @@ void random_add_randomness(const void *buf, size_t len)
        static unsigned int count = 0;
 
        count++;
-       wpa_printf(MSG_MSGDUMP, "Add randomness: count=%u entropy=%u",
-                  count, entropy);
        if (entropy > MIN_COLLECT_ENTROPY && (count & 0x3ff) != 0) {
                /*
                 * No need to add more entropy at this point, so save CPU and
@@ -137,6 +135,8 @@ void random_add_randomness(const void *buf, size_t len)
                 */
                return;
        }
+       wpa_printf(MSG_EXCESSIVE, "Add randomness: count=%u entropy=%u",
+                  count, entropy);
 
        os_get_time(&t);
        wpa_hexdump_key(MSG_EXCESSIVE, "random pool",
index 2bd3bbb..990f6e6 100644 (file)
@@ -21,8 +21,10 @@ struct tls_keys {
 };
 
 enum tls_event {
+       TLS_CERT_CHAIN_SUCCESS,
        TLS_CERT_CHAIN_FAILURE,
-       TLS_PEER_CERTIFICATE
+       TLS_PEER_CERTIFICATE,
+       TLS_ALERT
 };
 
 /*
@@ -57,6 +59,12 @@ union tls_event_data {
                const u8 *hash;
                size_t hash_len;
        } peer_cert;
+
+       struct {
+               int is_local;
+               const char *type;
+               const char *description;
+       } alert;
 };
 
 struct tls_config {
index aaa920b..09b02e4 100644 (file)
@@ -527,6 +527,15 @@ static void ssl_info_cb(const SSL *ssl, int where, int ret)
                        else
                                conn->write_alerts++;
                }
+               if (tls_global->event_cb != NULL) {
+                       union tls_event_data ev;
+                       os_memset(&ev, 0, sizeof(ev));
+                       ev.alert.is_local = !(where & SSL_CB_READ);
+                       ev.alert.type = SSL_alert_type_string_long(ret);
+                       ev.alert.description = SSL_alert_desc_string_long(ret);
+                       tls_global->event_cb(tls_global->cb_ctx, TLS_ALERT,
+                                            &ev);
+               }
        } else if (where & SSL_CB_EXIT && ret <= 0) {
                wpa_printf(MSG_DEBUG, "SSL: %s:%s in %s",
                           str, ret == 0 ? "failed" : "error",
@@ -1274,6 +1283,10 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
                                       TLS_FAIL_SERVER_CHAIN_PROBE);
        }
 
+       if (preverify_ok && tls_global->event_cb != NULL)
+               tls_global->event_cb(tls_global->cb_ctx,
+                                    TLS_CERT_CHAIN_SUCCESS, NULL);
+
        return preverify_ok;
 }
 
index f1d4a14..0aab61e 100644 (file)
@@ -100,6 +100,16 @@ struct hostapd_hw_modes {
         */
        u8 a_mpdu_params;
 
+       /**
+        * vht_capab - VHT (IEEE 802.11ac) capabilities
+        */
+       u32 vht_capab;
+
+       /**
+        * vht_mcs_set - VHT MCS (IEEE 802.11ac) rate parameters
+        */
+       u8 vht_mcs_set[8];
+
        unsigned int flags; /* HOSTAPD_MODE_FLAG_* */
 };
 
@@ -333,6 +343,13 @@ struct wpa_driver_associate_params {
        int freq;
 
        /**
+        * bg_scan_period - Background scan period in seconds, 0 to disable
+        * background scan, or -1 to indicate no change to default driver
+        * configuration
+        */
+       int bg_scan_period;
+
+       /**
         * wpa_ie - WPA information element for (Re)Association Request
         * WPA information element to be included in (Re)Association
         * Request (including information element id and length). Use
@@ -707,6 +724,13 @@ struct wpa_driver_ap_params {
         * enabled.
         */
        u8 access_network_type;
+
+       /**
+        * ap_max_inactivity - Timeout in seconds to detect STA's inactivity
+        *
+        * This is used by driver which advertises this capability.
+        */
+       int ap_max_inactivity;
 };
 
 /**
@@ -726,6 +750,7 @@ struct wpa_driver_capa {
 #define WPA_DRIVER_CAPA_ENC_WEP104     0x00000002
 #define WPA_DRIVER_CAPA_ENC_TKIP       0x00000004
 #define WPA_DRIVER_CAPA_ENC_CCMP       0x00000008
+#define WPA_DRIVER_CAPA_ENC_WEP128     0x00000010
        unsigned int enc;
 
 #define WPA_DRIVER_AUTH_OPEN           0x00000001
@@ -790,6 +815,8 @@ struct wpa_driver_capa {
 #define WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD            0x00200000
 /* Driver supports U-APSD in AP mode */
 #define WPA_DRIVER_FLAGS_AP_UAPSD                      0x00400000
+/* Driver supports inactivity timer in AP mode */
+#define WPA_DRIVER_FLAGS_INACTIVITY_TIMER              0x00800000
        unsigned int flags;
 
        int max_scan_ssids;
@@ -2003,6 +2030,16 @@ struct wpa_driver_ops {
        int (*deinit_ap)(void *priv);
 
        /**
+        * deinit_p2p_cli - Deinitialize P2P client mode
+        * @priv: Private driver interface data
+        * Returns: 0 on success, -1 on failure (or if not supported)
+        *
+        * This optional function can be used to disable P2P client mode. It
+        * can be used to change the interface type back to station mode.
+        */
+       int (*deinit_p2p_cli)(void *priv);
+
+       /**
         * suspend - Notification on system suspend/hibernate event
         * @priv: Private driver interface data
         */
@@ -2508,19 +2545,30 @@ struct wpa_driver_ops {
         */
        void (*poll_client)(void *priv, const u8 *own_addr,
                            const u8 *addr, int qos);
-#ifdef ANDROID_P2P
+
        /**
-        * switch_channel - Announce channel switch and migrate the GO to a
-        * given frequency.
+        * radio_disable - Disable/enable radio
         * @priv: Private driver interface data
-        * @freq: frequency in MHz
+        * @disabled: 1=disable 0=enable radio
         * Returns: 0 on success, -1 on failure
         *
-        * This function is used to move the GO to the legacy STA channel to avoid
-        * frequency conflict in single channel concurrency.
+        * This optional command is for testing purposes. It can be used to
+        * disable the radio on a testbed device to simulate out-of-radio-range
+        * conditions.
+        */
+       int (*radio_disable)(void *priv, int disabled);
+
+       /**
+        * switch_channel - Announce channel switch and migrate the GO to the
+        * given frequency
+        * @priv: Private driver interface data
+        * @freq: Frequency in MHz
+        * Returns: 0 on success, -1 on failure
+        *
+        * This function is used to move the GO to the legacy STA channel to
+        * avoid frequency conflict in single channel concurrency.
         */
        int (*switch_channel)(void *priv, unsigned int freq);
-#endif
 };
 
 
@@ -2951,7 +2999,14 @@ enum wpa_event_type {
        /**
         * EVENT_EAPOL_TX_STATUS - notify of EAPOL TX status
         */
-       EVENT_EAPOL_TX_STATUS
+       EVENT_EAPOL_TX_STATUS,
+
+       /**
+        * EVENT_CH_SWITCH - AP or GO decided to switch channels
+        *
+        * Described in wpa_event_data.ch_switch
+        * */
+       EVENT_CH_SWITCH
 };
 
 
@@ -3267,7 +3322,7 @@ union wpa_event_data {
                const u8 *frame;
                size_t frame_len;
                u32 datarate;
-               u32 ssi_signal;
+               int ssi_signal; /* dBm */
        } rx_mgmt;
 
        /**
@@ -3385,6 +3440,11 @@ union wpa_event_data {
                 * ie_len - Length of ie buffer in octets
                 */
                size_t ie_len;
+
+               /**
+                * signal - signal strength in dBm (or 0 if not available)
+                */
+               int ssi_signal;
        } rx_probe_req;
 
        /**
@@ -3541,6 +3601,18 @@ union wpa_event_data {
                int data_len;
                int ack;
        } eapol_tx_status;
+
+       /**
+        * struct ch_switch
+        * @freq: Frequency of new channel in MHz
+        * @ht_enabled: Whether this is an HT channel
+        * @ch_offset: Secondary channel offset
+        */
+       struct ch_switch {
+               int freq;
+               int ht_enabled;
+               int ch_offset;
+       } ch_switch;
 };
 
 /**
index b17d1a6..73898d3 100644 (file)
@@ -5,14 +5,8 @@
  * Copyright (c) 2005-2007, 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 "includes.h"
 
 #ifdef CONFIG_WPS
 #include <netpacket/packet.h>
+#endif /* CONFIG_WPS */
 
 #ifndef ETH_P_80211_RAW
 #define ETH_P_80211_RAW 0x0019
 #endif
-#endif /* CONFIG_WPS */
 
 #include "linux_wext.h"
 
@@ -73,6 +67,7 @@ struct atheros_driver_data {
        struct wpabuf *wpa_ie;
        struct wpabuf *wps_beacon_ie;
        struct wpabuf *wps_probe_resp_ie;
+       u8      own_addr[ETH_ALEN];
 };
 
 static int atheros_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
@@ -732,8 +727,8 @@ atheros_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
 }
 
 #ifdef CONFIG_WPS
-static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
-                               size_t len)
+static void atheros_raw_recv_wps(void *ctx, const u8 *src_addr, const u8 *buf,
+                                size_t len)
 {
        struct atheros_driver_data *drv = ctx;
        const struct ieee80211_mgmt *mgmt;
@@ -762,28 +757,139 @@ static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
 }
 #endif /* CONFIG_WPS */
 
-static int atheros_receive_probe_req(struct atheros_driver_data *drv)
+#ifdef CONFIG_IEEE80211R
+static void atheros_raw_recv_11r(void *ctx, const u8 *src_addr, const u8 *buf,
+                                size_t len)
+{
+       struct atheros_driver_data *drv = ctx;
+       union wpa_event_data event;
+       const struct ieee80211_mgmt *mgmt;
+       u16 fc;
+       u16 stype;
+       int ielen;
+       const u8 *iebuf;
+
+       /* Do 11R processing for ASSOC/AUTH/FT ACTION frames */
+       if (len < IEEE80211_HDRLEN)
+               return;
+       mgmt = (const struct ieee80211_mgmt *) buf;
+
+       fc = le_to_host16(mgmt->frame_control);
+
+       if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT)
+               return;
+       stype = WLAN_FC_GET_STYPE(fc);
+
+       wpa_printf(MSG_DEBUG, "%s: subtype 0x%x len %d", __func__, stype,
+                  (int) len);
+
+       if (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) != 0) {
+               wpa_printf(MSG_DEBUG, "%s: BSSID does not match - ignore",
+                          __func__);
+               return;
+       }
+       switch (stype) {
+       case WLAN_FC_STYPE_ASSOC_REQ:
+               if (len - IEEE80211_HDRLEN < sizeof(mgmt->u.assoc_req))
+                       break;
+               ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
+               iebuf = mgmt->u.assoc_req.variable;
+               drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 0);
+               break;
+       case WLAN_FC_STYPE_REASSOC_REQ:
+               if (len - IEEE80211_HDRLEN < sizeof(mgmt->u.reassoc_req))
+                       break;
+               ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
+               iebuf = mgmt->u.reassoc_req.variable;
+               drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 1);
+               break;
+       case WLAN_FC_STYPE_ACTION:
+               if (&mgmt->u.action.category > buf + len)
+                       break;
+               os_memset(&event, 0, sizeof(event));
+               event.rx_action.da = mgmt->da;
+               event.rx_action.sa = mgmt->sa;
+               event.rx_action.bssid = mgmt->bssid;
+               event.rx_action.category = mgmt->u.action.category;
+               event.rx_action.data = &mgmt->u.action.category;
+               event.rx_action.len = buf + len - event.rx_action.data;
+               wpa_supplicant_event(drv->hapd, EVENT_RX_ACTION, &event);
+               break;
+       case WLAN_FC_STYPE_AUTH:
+               if (len - IEEE80211_HDRLEN < sizeof(mgmt->u.auth))
+                       break;
+               os_memset(&event, 0, sizeof(event));
+               os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
+               os_memcpy(event.auth.bssid, mgmt->bssid, ETH_ALEN);
+               event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg);
+               event.auth.status_code =
+                       le_to_host16(mgmt->u.auth.status_code);
+               event.auth.auth_transaction =
+                       le_to_host16(mgmt->u.auth.auth_transaction);
+               event.auth.ies = mgmt->u.auth.variable;
+               event.auth.ies_len = len - IEEE80211_HDRLEN -
+                       sizeof(mgmt->u.auth);
+               wpa_supplicant_event(drv->hapd, EVENT_AUTH, &event);
+               break;
+       default:
+               break;
+       }
+}
+#endif /* CONFIG_IEEE80211R */
+
+#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R)
+static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
+                               size_t len)
 {
-       int ret = 0;
 #ifdef CONFIG_WPS
+       atheros_raw_recv_wps(ctx, src_addr, buf, len);
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_IEEE80211R
+       atheros_raw_recv_11r(ctx, src_addr, buf, len);
+#endif /* CONFIG_IEEE80211R */
+}
+#endif /* CONFIG_WPS || CONFIG_IEEE80211R */
+
+static int atheros_receive_pkt(struct atheros_driver_data *drv)
+{
+       int ret = 0;
        struct ieee80211req_set_filter filt;
 
        wpa_printf(MSG_DEBUG, "%s Enter", __func__);
-       filt.app_filterype = IEEE80211_FILTER_TYPE_PROBE_REQ;
-
-       ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt,
-                          sizeof(struct ieee80211req_set_filter));
-       if (ret)
-               return ret;
+       filt.app_filterype = 0;
+#ifdef CONFIG_WPS
+       filt.app_filterype |= IEEE80211_FILTER_TYPE_PROBE_REQ;
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_IEEE80211R
+       filt.app_filterype |= (IEEE80211_FILTER_TYPE_ASSOC_REQ |
+                              IEEE80211_FILTER_TYPE_AUTH);
+#endif
+       if (filt.app_filterype) {
+               ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt,
+                                  sizeof(struct ieee80211req_set_filter));
+               if (ret)
+                       return ret;
+       }
 
+#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R)
        drv->sock_raw = l2_packet_init(drv->iface, NULL, ETH_P_80211_RAW,
                                       atheros_raw_receive, drv, 1);
        if (drv->sock_raw == NULL)
                return -1;
-#endif /* CONFIG_WPS */
+#endif /* CONFIG_WPS || CONFIG_IEEE80211R */
+       if (l2_packet_get_own_addr(drv->sock_xmit, drv->own_addr))
+               return -1;
        return ret;
 }
 
+static int atheros_reset_appfilter(struct atheros_driver_data *drv)
+{
+       struct ieee80211req_set_filter filt;
+       filt.app_filterype = 0;
+       return set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt,
+                           sizeof(struct ieee80211req_set_filter));
+}
+
 #ifdef CONFIG_WPS
 static int
 atheros_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype)
@@ -852,6 +958,84 @@ atheros_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
 #define atheros_set_ap_wps_ie NULL
 #endif /* CONFIG_WPS */
 
+#ifdef CONFIG_IEEE80211R
+static int
+atheros_sta_auth(void *priv, const u8 *own_addr, const u8 *addr, u16 seq,
+                u16 status_code, const u8 *ie, size_t len)
+{
+       struct atheros_driver_data *drv = priv;
+       struct ieee80211req_mlme mlme;
+       int ret;
+
+       wpa_printf(MSG_DEBUG, "%s: addr=%s status_code=%d",
+                  __func__, ether_sprintf(addr), status_code);
+
+       mlme.im_op = IEEE80211_MLME_AUTH;
+       mlme.im_reason = status_code;
+       mlme.im_seq = seq;
+       os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+       mlme.im_optie_len = len;
+       if (len) {
+               if (len < IEEE80211_MAX_OPT_IE) {
+                       os_memcpy(mlme.im_optie, ie, len);
+               } else {
+                       wpa_printf(MSG_DEBUG, "%s: Not enough space to copy "
+                                  "opt_ie STA (addr " MACSTR " reason %d, "
+                                  "ie_len %d)",
+                                  __func__, MAC2STR(addr), status_code,
+                                  (int) len);
+                       return -1;
+               }
+       }
+       ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
+       if (ret < 0) {
+               wpa_printf(MSG_DEBUG, "%s: Failed to auth STA (addr " MACSTR
+                          " reason %d)",
+                          __func__, MAC2STR(addr), status_code);
+       }
+       return ret;
+}
+
+static int
+atheros_sta_assoc(void *priv, const u8 *own_addr, const u8 *addr,
+                 int reassoc, u16 status_code, const u8 *ie, size_t len)
+{
+       struct atheros_driver_data *drv = priv;
+       struct ieee80211req_mlme mlme;
+       int ret;
+
+       wpa_printf(MSG_DEBUG, "%s: addr=%s status_code=%d reassoc %d",
+                  __func__, ether_sprintf(addr), status_code, reassoc);
+
+       if (reassoc)
+               mlme.im_op = IEEE80211_MLME_REASSOC;
+       else
+               mlme.im_op = IEEE80211_MLME_ASSOC;
+       mlme.im_reason = status_code;
+       os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+       mlme.im_optie_len = len;
+       if (len) {
+               if (len < IEEE80211_MAX_OPT_IE) {
+                       os_memcpy(mlme.im_optie, ie, len);
+               } else {
+                       wpa_printf(MSG_DEBUG, "%s: Not enough space to copy "
+                                  "opt_ie STA (addr " MACSTR " reason %d, "
+                                  "ie_len %d)",
+                                  __func__, MAC2STR(addr), status_code,
+                                  (int) len);
+                       return -1;
+               }
+       }
+       ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
+       if (ret < 0) {
+               wpa_printf(MSG_DEBUG, "%s: Failed to assoc STA (addr " MACSTR
+                          " reason %d)",
+                          __func__, MAC2STR(addr), status_code);
+       }
+       return ret;
+}
+#endif /* CONFIG_IEEE80211R */
+
 static void
 atheros_new_sta(struct atheros_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
 {
@@ -980,6 +1164,9 @@ atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv,
                 * so all are enabled for WPS... ugh.
                 */
                wpa_supplicant_event(drv->hapd, EVENT_WPS_BUTTON_PUSHED, NULL);
+#endif /* CONFIG_WPS */
+#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R)
+#define WPS_FRAM_TAG_SIZE 30 /* hardcoded in driver */
        } else if (strncmp(custom, "Manage.prob_req ", 16) == 0) {
                /*
                 * Atheros driver uses a hack to pass Probe Request frames as a
@@ -987,7 +1174,6 @@ atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv,
                 * packet sniffing) didn't work when bridging.
                 * Format: "Manage.prob_req <frame len>" | zero padding | frame
                 */
-#define WPS_FRAM_TAG_SIZE 30 /* hardcoded in driver */
                int len = atoi(custom + 16);
                if (len < 0 || custom + WPS_FRAM_TAG_SIZE + len > end) {
                        wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req event "
@@ -996,7 +1182,40 @@ atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv,
                }
                atheros_raw_receive(drv, NULL,
                                    (u8 *) custom + WPS_FRAM_TAG_SIZE, len);
-#endif /* CONFIG_WPS */
+       } else if (strncmp(custom, "Manage.assoc_req ", 17) == 0) {
+               /* Format: "Manage.assoc_req <frame len>" | zero padding |
+                * frame */
+               int len = atoi(custom + 17);
+               if (len < 0 || custom + WPS_FRAM_TAG_SIZE + len > end) {
+                       wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/"
+                                  "assoc_req/auth event length %d", len);
+                       return;
+               }
+               atheros_raw_receive(drv, NULL,
+                                   (u8 *) custom + WPS_FRAM_TAG_SIZE, len);
+       } else if (strncmp(custom, "Manage.action ", 14) == 0) {
+               /* Format: "Manage.assoc_req <frame len>" | zero padding |
+                * frame */
+               int len = atoi(custom + 14);
+               if (len < 0 || custom + WPS_FRAM_TAG_SIZE + len > end) {
+                       wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/"
+                                  "assoc_req/auth event length %d", len);
+                       return;
+               }
+               atheros_raw_receive(drv, NULL,
+                                   (u8 *) custom + WPS_FRAM_TAG_SIZE, len);
+       } else if (strncmp(custom, "Manage.auth ", 12) == 0) {
+               /* Format: "Manage.auth <frame len>" | zero padding | frame
+                */
+               int len = atoi(custom + 12);
+               if (len < 0 || custom + WPS_FRAM_TAG_SIZE + len > end) {
+                       wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/"
+                                  "assoc_req/auth event length %d", len);
+                       return;
+               }
+               atheros_raw_receive(drv, NULL,
+                                   (u8 *) custom + WPS_FRAM_TAG_SIZE, len);
+#endif /* CONFIG_WPS or CONFIG_IEEE80211R */
        }
 }
 
@@ -1278,7 +1497,7 @@ atheros_init(struct hostapd_data *hapd, struct wpa_init_params *params)
        linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
        atheros_set_privacy(drv, 0); /* default to no privacy */
 
-       atheros_receive_probe_req(drv);
+       atheros_receive_pkt(drv);
 
        if (atheros_wireless_event_init(drv))
                goto bad;
@@ -1302,6 +1521,7 @@ atheros_deinit(void *priv)
 {
        struct atheros_driver_data *drv = priv;
 
+       atheros_reset_appfilter(drv);
        netlink_deinit(drv->netlink);
        (void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
        if (drv->ioctl_sock >= 0)
@@ -1348,7 +1568,6 @@ atheros_get_ssid(void *priv, u8 *buf, int len)
        memset(&iwr, 0, sizeof(iwr));
        os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
        iwr.u.essid.pointer = (caddr_t) buf;
-       iwr.u.essid.length = len;
        iwr.u.essid.length = (len > IW_ESSID_MAX_SIZE) ?
                IW_ESSID_MAX_SIZE : len;
 
@@ -1421,6 +1640,75 @@ static int atheros_set_ap(void *priv, struct wpa_driver_ap_params *params)
        return 0;
 }
 
+
+#ifdef CONFIG_IEEE80211R
+
+static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len,
+                            int noack)
+{
+       struct atheros_driver_data *drv = priv;
+       u8 buf[1510];
+       const struct ieee80211_mgmt *mgmt;
+       struct ieee80211req_mgmtbuf *mgmt_frm;
+
+       mgmt = (const struct ieee80211_mgmt *) frm;
+       wpa_printf(MSG_DEBUG, "%s frmlen = %lu " MACSTR, __func__,
+                  (unsigned long) data_len, MAC2STR(mgmt->da));
+       mgmt_frm = (struct ieee80211req_mgmtbuf *) buf;
+       memcpy(mgmt_frm->macaddr, (u8 *)mgmt->da, IEEE80211_ADDR_LEN);
+       mgmt_frm->buflen = data_len;
+       if (&mgmt_frm->buf[0] + data_len > buf + sizeof(buf)) {
+               wpa_printf(MSG_INFO, "atheros: Too long frame for "
+                          "atheros_send_mgmt (%u)", (unsigned int) data_len);
+               return -1;
+       }
+       os_memcpy(&mgmt_frm->buf[0], frm, data_len);
+       return set80211priv(drv, IEEE80211_IOCTL_SEND_MGMT, mgmt_frm,
+                           sizeof(struct ieee80211req_mgmtbuf) + data_len);
+}
+
+
+static int atheros_add_tspec(void *priv, const u8 *addr, u8 *tspec_ie,
+                            size_t tspec_ielen)
+{
+       struct atheros_driver_data *drv = priv;
+       int retv;
+       struct ieee80211req_res req;
+       struct ieee80211req_res_addts *addts = &req.u.addts;
+
+       wpa_printf(MSG_DEBUG, "%s", __func__);
+       req.type = IEEE80211_RESREQ_ADDTS;
+       os_memcpy(&req.macaddr[0], addr, IEEE80211_ADDR_LEN);
+       os_memcpy(addts->tspecie, tspec_ie, tspec_ielen);
+       retv = set80211priv(drv, IEEE80211_IOCTL_RES_REQ, &req,
+                           sizeof(struct ieee80211req_res));
+       if (retv < 0) {
+               wpa_printf(MSG_DEBUG, "%s IEEE80211_IOCTL_RES_REQ FAILED "
+                          "retv = %d", __func__, retv);
+               return -1;
+       }
+       os_memcpy(tspec_ie, addts->tspecie, tspec_ielen);
+       return addts->status;
+}
+
+
+static int atheros_add_sta_node(void *priv, const u8 *addr, u16 auth_alg)
+{
+       struct atheros_driver_data *drv = priv;
+       struct ieee80211req_res req;
+       struct ieee80211req_res_addnode *addnode = &req.u.addnode;
+
+       wpa_printf(MSG_DEBUG, "%s", __func__);
+       req.type = IEEE80211_RESREQ_ADDNODE;
+       os_memcpy(&req.macaddr[0], addr, IEEE80211_ADDR_LEN);
+       addnode->auth_alg = auth_alg;
+       return set80211priv(drv, IEEE80211_IOCTL_RES_REQ, &req,
+                           sizeof(struct ieee80211req_res));
+}
+
+#endif /* CONFIG_IEEE80211R */
+
+
 const struct wpa_driver_ops wpa_driver_atheros_ops = {
        .name                   = "atheros",
        .hapd_init              = atheros_init,
@@ -1444,4 +1732,11 @@ const struct wpa_driver_ops wpa_driver_atheros_ops = {
        .set_ap_wps_ie          = atheros_set_ap_wps_ie,
        .set_authmode           = atheros_set_authmode,
        .set_ap                 = atheros_set_ap,
+#ifdef CONFIG_IEEE80211R
+       .sta_assoc              = atheros_sta_assoc,
+       .sta_auth               = atheros_sta_auth,
+       .send_mlme              = atheros_send_mgmt,
+       .add_tspec              = atheros_add_tspec,
+       .add_sta_node           = atheros_add_sta_node,
+#endif /* CONFIG_IEEE80211R */
 };
index 4596a51..67abb67 100644 (file)
@@ -3,14 +3,8 @@
  * Copyright (c) 2004, Sam Leffler <sam@errno.com>
  * Copyright (c) 2004, 2Wire, Inc
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 345e851..81856aa 100644 (file)
@@ -77,6 +77,7 @@ const char * event_to_string(enum wpa_event_type event)
        E2S(SCHED_SCAN_STOPPED);
        E2S(DRIVER_CLIENT_POLL_OK);
        E2S(EAPOL_TX_STATUS);
+       E2S(CH_SWITCH);
        }
 
        return "UNKNOWN";
index edb086f..bb48011 100644 (file)
@@ -4,14 +4,8 @@
  * Copyright (c) 2004, Video54 Technologies
  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  *
  * While this driver wrapper supports both AP (hostapd) and station
  * (wpa_supplicant) operations, the station side is deprecated and
index 8795104..d54d0f5 100644 (file)
@@ -189,6 +189,7 @@ struct i802_bss {
        unsigned int beacon_set:1;
        unsigned int added_if_into_bridge:1;
        unsigned int added_bridge:1;
+       unsigned int in_deinit:1;
 
        u8 addr[ETH_ALEN];
 
@@ -456,6 +457,7 @@ static int send_and_recv_msgs_global(struct nl80211_global *global,
                             valid_data);
 }
 
+
 int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
                              struct nl_msg *msg,
                              int (*valid_handler)(struct nl_msg *, void *),
@@ -797,10 +799,28 @@ static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv,
                   del ? "removed" : "added");
 
        if (os_strcmp(drv->first_bss.ifname, event.interface_status.ifname) == 0) {
-               if (del)
+               if (del) {
+                       if (drv->if_removed) {
+                               wpa_printf(MSG_DEBUG, "nl80211: if_removed "
+                                          "already set - ignore event");
+                               return;
+                       }
                        drv->if_removed = 1;
-               else
+               } else {
+                       if (if_nametoindex(drv->first_bss.ifname) == 0) {
+                               wpa_printf(MSG_DEBUG, "nl80211: Interface %s "
+                                          "does not exist - ignore "
+                                          "RTM_NEWLINK",
+                                          drv->first_bss.ifname);
+                               return;
+                       }
+                       if (!drv->if_removed) {
+                               wpa_printf(MSG_DEBUG, "nl80211: if_removed "
+                                          "already cleared - ignore event");
+                               return;
+                       }
                        drv->if_removed = 0;
+               }
        }
 
        wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
@@ -917,6 +937,14 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
                        wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
                                   "event since interface %s is down",
                                   namebuf);
+               } else if (if_nametoindex(drv->first_bss.ifname) == 0) {
+                       wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
+                                  "event since interface %s does not exist",
+                                  drv->first_bss.ifname);
+               } else if (drv->if_removed) {
+                       wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
+                                  "event since interface %s is marked "
+                                  "removed", drv->first_bss.ifname);
                } else {
                        wpa_printf(MSG_DEBUG, "nl80211: Interface up");
                        drv->if_disabled = 0;
@@ -1103,6 +1131,7 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
        }
 
        event.assoc_info.freq = drv->assoc_freq;
+
        wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
 }
 
@@ -1176,9 +1205,43 @@ static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
        drv->associated = 0;
        os_memset(&data, 0, sizeof(data));
        if (reason)
-               data.disassoc_info.reason_code = nla_get_u16(reason);
-       data.disassoc_info.locally_generated = by_ap == NULL;
-       wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, &data);
+               data.deauth_info.reason_code = nla_get_u16(reason);
+       data.deauth_info.locally_generated = by_ap == NULL;
+       wpa_supplicant_event(drv->ctx, EVENT_DEAUTH, &data);
+}
+
+
+static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
+                                struct nlattr *freq, struct nlattr *type)
+{
+       union wpa_event_data data;
+       int ht_enabled = 1;
+       int chan_offset = 0;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Channel switch event");
+
+       if (!freq || !type)
+               return;
+
+       switch (nla_get_u32(type)) {
+       case NL80211_CHAN_NO_HT:
+               ht_enabled = 0;
+               break;
+       case NL80211_CHAN_HT20:
+               break;
+       case NL80211_CHAN_HT40PLUS:
+               chan_offset = 1;
+               break;
+       case NL80211_CHAN_HT40MINUS:
+               chan_offset = -1;
+               break;
+       }
+
+       data.ch_switch.freq = nla_get_u32(freq);
+       data.ch_switch.ht_enabled = ht_enabled;
+       data.ch_switch.ch_offset = chan_offset;
+
+       wpa_supplicant_event(drv->ctx, EVENT_CH_SWITCH, &data);
 }
 
 
@@ -1208,11 +1271,13 @@ static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
 
 
 static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv,
-                           struct nlattr *freq, const u8 *frame, size_t len)
+                           struct nlattr *freq, struct nlattr *sig,
+                           const u8 *frame, size_t len)
 {
        const struct ieee80211_mgmt *mgmt;
        union wpa_event_data event;
        u16 fc, stype;
+       int ssi_signal = 0;
 
        mgmt = (const struct ieee80211_mgmt *) frame;
        if (len < 24) {
@@ -1223,6 +1288,9 @@ static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv,
        fc = le_to_host16(mgmt->frame_control);
        stype = WLAN_FC_GET_STYPE(fc);
 
+       if (sig)
+               ssi_signal = (s32) nla_get_u32(sig);
+
        os_memset(&event, 0, sizeof(event));
        if (freq) {
                event.rx_action.freq = nla_get_u32(freq);
@@ -1239,6 +1307,7 @@ static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv,
        } else {
                event.rx_mgmt.frame = frame;
                event.rx_mgmt.frame_len = len;
+               event.rx_mgmt.ssi_signal = ssi_signal;
                wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
        }
 }
@@ -1379,7 +1448,7 @@ static void mlme_event(struct wpa_driver_nl80211_data *drv,
                       enum nl80211_commands cmd, struct nlattr *frame,
                       struct nlattr *addr, struct nlattr *timed_out,
                       struct nlattr *freq, struct nlattr *ack,
-                      struct nlattr *cookie)
+                      struct nlattr *cookie, struct nlattr *sig)
 {
        if (timed_out && addr) {
                mlme_timeout_event(drv, cmd, addr);
@@ -1412,7 +1481,8 @@ static void mlme_event(struct wpa_driver_nl80211_data *drv,
                                           nla_data(frame), nla_len(frame));
                break;
        case NL80211_CMD_FRAME:
-               mlme_event_mgmt(drv, freq, nla_data(frame), nla_len(frame));
+               mlme_event_mgmt(drv, freq, sig, nla_data(frame),
+                               nla_len(frame));
                break;
        case NL80211_CMD_FRAME_TX_STATUS:
                mlme_event_mgmt_tx_status(drv, cookie, nla_data(frame),
@@ -2084,7 +2154,8 @@ static void do_process_drv_event(struct wpa_driver_nl80211_data *drv,
                mlme_event(drv, cmd, tb[NL80211_ATTR_FRAME],
                           tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
                           tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
-                          tb[NL80211_ATTR_COOKIE]);
+                          tb[NL80211_ATTR_COOKIE],
+                          tb[NL80211_ATTR_RX_SIGNAL_DBM]);
                break;
        case NL80211_CMD_CONNECT:
        case NL80211_CMD_ROAM:
@@ -2094,6 +2165,10 @@ static void do_process_drv_event(struct wpa_driver_nl80211_data *drv,
                                   tb[NL80211_ATTR_REQ_IE],
                                   tb[NL80211_ATTR_RESP_IE]);
                break;
+       case NL80211_CMD_CH_SWITCH_NOTIFY:
+               mlme_event_ch_switch(drv, tb[NL80211_ATTR_WIPHY_FREQ],
+                                    tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+               break;
        case NL80211_CMD_DISCONNECT:
                mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
                                      tb[NL80211_ATTR_MAC],
@@ -2176,7 +2251,7 @@ static int process_global_event(struct nl_msg *msg, void *arg)
        struct nl80211_global *global = arg;
        struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
        struct nlattr *tb[NL80211_ATTR_MAX + 1];
-       struct wpa_driver_nl80211_data *drv;
+       struct wpa_driver_nl80211_data *drv, *tmp;
        int ifidx = -1;
 
        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
@@ -2185,15 +2260,11 @@ static int process_global_event(struct nl_msg *msg, void *arg)
        if (tb[NL80211_ATTR_IFINDEX])
                ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
 
-       dl_list_for_each(drv, &global->interfaces,
-                        struct wpa_driver_nl80211_data, list) {
+       dl_list_for_each_safe(drv, tmp, &global->interfaces,
+                             struct wpa_driver_nl80211_data, list) {
                if (ifidx == -1 || ifidx == drv->ifindex ||
-                   have_ifidx(drv, ifidx)) {
+                   have_ifidx(drv, ifidx))
                        do_process_drv_event(drv, gnlh->cmd, tb);
-#ifdef ANDROID_P2P
-                       break;
-#endif
-               }
        }
 
        return NL_SKIP;
@@ -2215,7 +2286,8 @@ static int process_bss_event(struct nl_msg *msg, void *arg)
                mlme_event(bss->drv, gnlh->cmd, tb[NL80211_ATTR_FRAME],
                           tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
                           tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
-                          tb[NL80211_ATTR_COOKIE]);
+                          tb[NL80211_ATTR_COOKIE],
+                          tb[NL80211_ATTR_RX_SIGNAL_DBM]);
                break;
        case NL80211_CMD_UNEXPECTED_FRAME:
                nl80211_spurious_frame(bss, tb, 0);
@@ -2504,6 +2576,9 @@ broken_combination:
 
                if (flags & NL80211_FEATURE_SK_TX_STATUS)
                        info->data_tx_status = 1;
+
+               if (flags & NL80211_FEATURE_INACTIVITY_TIMER)
+                       capa->flags |= WPA_DRIVER_FLAGS_INACTIVITY_TIMER;
        }
 
        if (tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]) {
@@ -2571,17 +2646,29 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
        drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES;
        drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
        drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
-       drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
+#ifndef ANDROID_P2P
+       if (!info.device_ap_sme)
+#endif
+               drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
 
        drv->device_ap_sme = info.device_ap_sme;
        drv->poll_command_supported = info.poll_command_supported;
        drv->data_tx_status = info.data_tx_status;
 
+#ifdef ANDROID_P2P
+       if(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) {
+               /* Driver is new enough to support monitorless mode*/
+               wpa_printf(MSG_DEBUG, "nl80211: Driver is new "
+                         "enough to support monitor-less mode");
+               drv->use_monitor = 0;
+       }
+#else
        /*
         * If poll command is supported mac80211 is new enough to
         * have everything we need to not need monitor interfaces.
         */
        drv->use_monitor = !info.poll_command_supported;
+#endif
 
        if (drv->device_ap_sme && drv->use_monitor) {
                /*
@@ -2803,10 +2890,7 @@ static void wpa_driver_nl80211_handle_eapol_tx_status(int sock,
        u8 data[2048];
        struct msghdr msg;
        struct iovec entry;
-       struct {
-               struct cmsghdr cm;
-               char control[512];
-       } control;
+       u8 control[512];
        struct cmsghdr *cmsg;
        int res, found_ee = 0, found_wifi = 0, acked = 0;
        union wpa_event_data event;
@@ -3309,6 +3393,7 @@ static void wpa_driver_nl80211_deinit(void *priv)
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
 
+       bss->in_deinit = 1;
        if (drv->data_tx_status)
                eloop_unregister_read_sock(drv->eapol_tx_sock);
        if (drv->eapol_tx_sock >= 0)
@@ -3467,6 +3552,8 @@ static int wpa_driver_nl80211_scan(void *priv,
        }
 
        if (params->p2p_probe) {
+               wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");
+
                /*
                 * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates
                 * by masking out everything else apart from the OFDM rates 6,
@@ -4731,6 +4818,18 @@ static int phy_info_handler(struct nl_msg *msg, void *arg)
                        os_memcpy(mode->mcs_set, mcs, 16);
                }
 
+               if (tb_band[NL80211_BAND_ATTR_VHT_CAPA]) {
+                       mode->vht_capab = nla_get_u32(
+                               tb_band[NL80211_BAND_ATTR_VHT_CAPA]);
+               }
+
+               if (tb_band[NL80211_BAND_ATTR_VHT_MCS_SET] &&
+                   nla_len(tb_band[NL80211_BAND_ATTR_VHT_MCS_SET])) {
+                       u8 *mcs;
+                       mcs = nla_data(tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]);
+                       os_memcpy(mode->vht_mcs_set, mcs, 8);
+               }
+
                nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
                        nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq),
                                  nla_len(nl_freq), freq_policy);
@@ -5191,7 +5290,9 @@ static int wpa_driver_nl80211_send_mlme_freq(struct i802_bss *bss,
        if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
                if (freq == 0)
                        freq = bss->freq;
-               return nl80211_send_frame_cmd(bss, freq, 0,
+               return nl80211_send_frame_cmd(bss, freq,
+                                             (int) freq == bss->freq ? 0 :
+                                             wait_time,
                                              data, data_len,
                                              &drv->send_action_cookie,
                                              no_cck, noack, offchanok);
@@ -5403,6 +5504,11 @@ static int wpa_driver_nl80211_set_ap(void *priv,
                        wpabuf_head(params->assocresp_ies));
        }
 
+       if (drv->capa.flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)  {
+               NLA_PUT_U16(msg, NL80211_ATTR_INACTIVITY_TIMEOUT,
+                           params->ap_max_inactivity);
+       }
+
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        if (ret) {
                wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
@@ -5413,7 +5519,6 @@ static int wpa_driver_nl80211_set_ap(void *priv,
                                params->short_slot_time, params->ht_opmode,
                                params->isolate, params->basic_rates);
        }
-
        return ret;
  nla_put_failure:
        nlmsg_free(msg);
@@ -5851,8 +5956,8 @@ static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
                case IEEE80211_RADIOTAP_RATE:
                        datarate = *iter.this_arg * 5;
                        break;
-               case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
-                       ssi_signal = *iter.this_arg;
+               case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
+                       ssi_signal = (s8) *iter.this_arg;
                        break;
                }
        }
@@ -6149,7 +6254,6 @@ static int nl80211_setup_ap(struct i802_bss *bss)
                if (nl80211_mgmt_subscribe_ap(bss))
                        return -1;
 
-#ifndef ANDROID_P2P
        if (drv->device_ap_sme && !drv->use_monitor)
                if (nl80211_mgmt_subscribe_ap_dev_sme(bss))
                        return -1;
@@ -6157,15 +6261,17 @@ static int nl80211_setup_ap(struct i802_bss *bss)
        if (!drv->device_ap_sme && drv->use_monitor &&
            nl80211_create_monitor_interface(drv) &&
            !drv->device_ap_sme)
-#else
-       if (drv->device_ap_sme)
+               return -1;
+
+#ifdef ANDROID_P2P
+       if (drv->device_ap_sme && drv->use_monitor)
                if (nl80211_mgmt_subscribe_ap_dev_sme(bss))
                        return -1;
 
        if (drv->use_monitor &&
            nl80211_create_monitor_interface(drv))
-#endif
                return -1;
+#endif
 
        if (drv->device_ap_sme &&
            wpa_driver_nl80211_probe_req_report(bss, 1) < 0) {
@@ -6568,6 +6674,12 @@ static int wpa_driver_nl80211_connect(
                wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq);
                NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
        }
+       if (params->bg_scan_period >= 0) {
+               wpa_printf(MSG_DEBUG, "  * bg scan period=%d",
+                          params->bg_scan_period);
+               NLA_PUT_U16(msg, NL80211_ATTR_BG_SCAN_PERIOD,
+                           params->bg_scan_period);
+       }
        if (params->ssid) {
                wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
                                  params->ssid, params->ssid_len);
@@ -6765,6 +6877,12 @@ static int wpa_driver_nl80211_associate(
                drv->assoc_freq = params->freq;
        } else
                drv->assoc_freq = 0;
+       if (params->bg_scan_period >= 0) {
+               wpa_printf(MSG_DEBUG, "  * bg scan period=%d",
+                          params->bg_scan_period);
+               NLA_PUT_U16(msg, NL80211_ATTR_BG_SCAN_PERIOD,
+                           params->bg_scan_period);
+       }
        if (params->ssid) {
                wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
                                  params->ssid, params->ssid_len);
@@ -6980,7 +7098,7 @@ done:
                nl80211_mgmt_unsubscribe(bss, "mode change");
        }
 
-       if (!is_ap_interface(nlmode) &&
+       if (!bss->in_deinit && !is_ap_interface(nlmode) &&
            nl80211_mgmt_subscribe_non_ap(bss) < 0)
                wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
                           "frame processing - ignore for now");
@@ -7402,8 +7520,12 @@ static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
                           int reason)
 {
        struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct ieee80211_mgmt mgmt;
 
+       if (drv->device_ap_sme)
+               return wpa_driver_nl80211_sta_remove(bss, addr);
+
        memset(&mgmt, 0, sizeof(mgmt));
        mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
                                          WLAN_FC_STYPE_DEAUTH);
@@ -7421,8 +7543,12 @@ static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
                             int reason)
 {
        struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
        struct ieee80211_mgmt mgmt;
 
+       if (drv->device_ap_sme)
+               return wpa_driver_nl80211_sta_remove(bss, addr);
+
        memset(&mgmt, 0, sizeof(mgmt));
        mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
                                          WLAN_FC_STYPE_DISASSOC);
@@ -7967,6 +8093,9 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss,
        if (!msg)
                return -1;
 
+       wpa_printf(MSG_DEBUG, "nl80211: CMD_FRAME freq=%u wait=%u no_cck=%d "
+                  "no_ack=%d offchanok=%d",
+                  freq, wait, no_cck, no_ack, offchanok);
        nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME);
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
@@ -8269,6 +8398,16 @@ static int wpa_driver_nl80211_deinit_ap(void *priv)
 }
 
 
+static int wpa_driver_nl80211_deinit_p2p_cli(void *priv)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       if (drv->nlmode != NL80211_IFTYPE_P2P_CLIENT)
+               return -1;
+       return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
+}
+
+
 static void wpa_driver_nl80211_resume(void *priv)
 {
        struct i802_bss *bss = priv;
@@ -8407,11 +8546,9 @@ static int wpa_driver_nl80211_shared_freq(void *priv)
                           MACSTR,
                           driver->phyname, driver->first_bss.ifname,
                           MAC2STR(driver->first_bss.addr));
-#ifdef ANDROID_P2P
-               if(is_ap_interface(driver->nlmode))
+               if (is_ap_interface(driver->nlmode))
                        freq = driver->first_bss.freq;
                else
-#endif
                        freq = nl80211_get_assoc_freq(driver);
                wpa_printf(MSG_DEBUG, "nl80211: Shared freq for PHY %s: %d",
                           drv->phyname, freq);
@@ -9016,6 +9153,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        wpa_driver_nl80211_cancel_remain_on_channel,
        .probe_req_report = wpa_driver_nl80211_probe_req_report,
        .deinit_ap = wpa_driver_nl80211_deinit_ap,
+       .deinit_p2p_cli = wpa_driver_nl80211_deinit_p2p_cli,
        .resume = wpa_driver_nl80211_resume,
        .send_ft_action = nl80211_send_ft_action,
        .signal_monitor = nl80211_signal_monitor,
index 81a328a..c8916f0 100644 (file)
@@ -651,7 +651,7 @@ static int wpa_driver_privsep_set_param(void *priv, const char *param)
        os_strlcpy(addr.sun_path, drv->own_socket_path, sizeof(addr.sun_path));
        if (bind(drv->priv_socket, (struct sockaddr *) &addr, sizeof(addr)) <
            0) {
-               perror("bind(PF_UNIX)");
+               perror("privsep-set-params priv-sock: bind(PF_UNIX)");
                close(drv->priv_socket);
                drv->priv_socket = -1;
                unlink(drv->own_socket_path);
@@ -676,7 +676,7 @@ static int wpa_driver_privsep_set_param(void *priv, const char *param)
        os_strlcpy(addr.sun_path, drv->own_cmd_path, sizeof(addr.sun_path));
        if (bind(drv->cmd_socket, (struct sockaddr *) &addr, sizeof(addr)) < 0)
        {
-               perror("bind(PF_UNIX)");
+               perror("privsep-set-params cmd-sock: bind(PF_UNIX)");
                close(drv->cmd_socket);
                drv->cmd_socket = -1;
                unlink(drv->own_cmd_path);
index 61b75b1..0a9078a 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant - roboswitch driver interface
  * Copyright (c) 2008-2009 Jouke Witteveen
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published 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"
index 43b30e9..f011651 100644 (file)
@@ -1275,7 +1275,7 @@ static void * test_driver_init(struct hostapd_data *hapd,
                        alen = sizeof(addr_un);
                }
                if (bind(drv->test_socket, addr, alen) < 0) {
-                       perror("bind(PF_UNIX)");
+                       perror("test-driver-init: bind(PF_UNIX)");
                        close(drv->test_socket);
                        if (drv->own_socket_path)
                                unlink(drv->own_socket_path);
@@ -2252,7 +2252,7 @@ static int wpa_driver_test_attach(struct wpa_driver_test_data *drv,
        os_strlcpy(addr.sun_path, drv->own_socket_path, sizeof(addr.sun_path));
        if (bind(drv->test_socket, (struct sockaddr *) &addr,
                 sizeof(addr)) < 0) {
-               perror("bind(PF_UNIX)");
+               perror("test-driver-attach: bind(PF_UNIX)");
                close(drv->test_socket);
                unlink(drv->own_socket_path);
                os_free(drv->own_socket_path);
@@ -2867,7 +2867,8 @@ static int wpa_driver_test_p2p_connect(void *priv, const u8 *peer_addr,
        if (!drv->p2p)
                return -1;
        return p2p_connect(drv->p2p, peer_addr, wps_method, go_intent,
-                          own_interface_addr, force_freq, persistent_group);
+                          own_interface_addr, force_freq, persistent_group,
+                          NULL, 0, 0);
 }
 
 
@@ -2912,7 +2913,7 @@ static int wpa_driver_test_p2p_set_params(void *priv,
 
 static int test_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
                         unsigned int num_req_dev_types,
-                        const u8 *req_dev_types, const u8 *dev_id)
+                        const u8 *req_dev_types, const u8 *dev_id, u16 pw_id)
 {
        struct wpa_driver_test_data *drv = ctx;
        struct wpa_driver_scan_params params;
@@ -2933,8 +2934,8 @@ static int test_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
 
 #if 0 /* TODO: WPS IE */
        wpa_s->wps->dev.p2p = 1;
-       wps_ie = wps_build_probe_req_ie(0, &wpa_s->wps->dev, wpa_s->wps->uuid,
-                                       WPS_REQ_ENROLLEE);
+       wps_ie = wps_build_probe_req_ie(pw_id, &wpa_s->wps->dev,
+                                       wpa_s->wps->uuid, WPS_REQ_ENROLLEE);
 #else
        wps_ie = wpabuf_alloc(1);
 #endif
@@ -2961,11 +2962,6 @@ static int test_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
                break;
        case P2P_SCAN_FULL:
                break;
-       case P2P_SCAN_SPECIFIC:
-               social_channels[0] = freq;
-               social_channels[1] = 0;
-               params.freqs = social_channels;
-               break;
        case P2P_SCAN_SOCIAL_PLUS_ONE:
                social_channels[3] = freq;
                params.freqs = social_channels;
index 204de34..fd90438 100644 (file)
@@ -584,10 +584,28 @@ static void wpa_driver_wext_event_link(struct wpa_driver_wext_data *drv,
                   del ? "removed" : "added");
 
        if (os_strcmp(drv->ifname, event.interface_status.ifname) == 0) {
-               if (del)
+               if (del) {
+                       if (drv->if_removed) {
+                               wpa_printf(MSG_DEBUG, "WEXT: if_removed "
+                                          "already set - ignore event");
+                               return;
+                       }
                        drv->if_removed = 1;
-               else
+               } else {
+                       if (if_nametoindex(drv->ifname) == 0) {
+                               wpa_printf(MSG_DEBUG, "WEXT: Interface %s "
+                                          "does not exist - ignore "
+                                          "RTM_NEWLINK",
+                                          drv->ifname);
+                               return;
+                       }
+                       if (!drv->if_removed) {
+                               wpa_printf(MSG_DEBUG, "WEXT: if_removed "
+                                          "already cleared - ignore event");
+                               return;
+                       }
                        drv->if_removed = 0;
+               }
        }
 
        wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
@@ -643,6 +661,7 @@ static void wpa_driver_wext_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi,
        struct wpa_driver_wext_data *drv = ctx;
        int attrlen, rta_len;
        struct rtattr *attr;
+       char namebuf[IFNAMSIZ];
 
        if (!wpa_driver_wext_own_ifindex(drv, ifi->ifi_index, buf, len)) {
                wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d",
@@ -665,9 +684,25 @@ static void wpa_driver_wext_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi,
        }
 
        if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
-               wpa_printf(MSG_DEBUG, "WEXT: Interface up");
-               drv->if_disabled = 0;
-               wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, NULL);
+               if (if_indextoname(ifi->ifi_index, namebuf) &&
+                   linux_iface_up(drv->ioctl_sock, drv->ifname) == 0) {
+                       wpa_printf(MSG_DEBUG, "WEXT: Ignore interface up "
+                                  "event since interface %s is down",
+                                  namebuf);
+               } else if (if_nametoindex(drv->ifname) == 0) {
+                       wpa_printf(MSG_DEBUG, "WEXT: Ignore interface up "
+                                  "event since interface %s does not exist",
+                                  drv->ifname);
+               } else if (drv->if_removed) {
+                       wpa_printf(MSG_DEBUG, "WEXT: Ignore interface up "
+                                  "event since interface %s is marked "
+                                  "removed", drv->ifname);
+               } else {
+                       wpa_printf(MSG_DEBUG, "WEXT: Interface up");
+                       drv->if_disabled = 0;
+                       wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
+                                            NULL);
+               }
        }
 
        /*
@@ -1566,6 +1601,7 @@ static int wpa_driver_wext_get_range(void *priv)
                }
                drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
                        WPA_DRIVER_CAPA_ENC_WEP104;
+               drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP128;
                if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP)
                        drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
                if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP)
index 618db26..e0f0f22 100644 (file)
@@ -3,14 +3,8 @@
  * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
  * Copyright (c) 2004, Gunter Burchardt <tira@isx.de>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
index 4f98fae..74cc55c 100644 (file)
  * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
  *     or %NL80211_ATTR_MAC.
  *
- * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a
- *     %NL80222_CMD_NEW_BEACON message)
- * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface
- *     using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD,
- *     %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL attributes.
- *     Following attributes are provided for drivers that generate full Beacon
- *     and Probe Response frames internally: %NL80211_ATTR_SSID,
+ * @NL80211_CMD_GET_BEACON: (not used)
+ * @NL80211_CMD_SET_BEACON: change the beacon on an access point interface
+ *     using the %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL
+ *     attributes. For drivers that generate the beacon and probe responses
+ *     internally, the following attributes must be provided: %NL80211_ATTR_IE,
+ *     %NL80211_ATTR_IE_PROBE_RESP and %NL80211_ATTR_IE_ASSOC_RESP.
+ * @NL80211_CMD_START_AP: Start AP operation on an AP interface, parameters
+ *     are like for %NL80211_CMD_SET_BEACON, and additionally parameters that
+ *     do not change are used, these include %NL80211_ATTR_BEACON_INTERVAL,
+ *     %NL80211_ATTR_DTIM_PERIOD, %NL80211_ATTR_SSID,
  *     %NL80211_ATTR_HIDDEN_SSID, %NL80211_ATTR_CIPHERS_PAIRWISE,
  *     %NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS,
  *     %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY,
- *     %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_IE, %NL80211_ATTR_IE_PROBE_RESP,
- *     %NL80211_ATTR_IE_ASSOC_RESP.
- * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface,
- *     parameters are like for %NL80211_CMD_SET_BEACON.
- * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
+ *     %NL80211_ATTR_AUTH_TYPE and %NL80211_ATTR_INACTIVITY_TIMEOUT.
+ *     The channel to use can be set on the interface or be given using the
+ *     %NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_WIPHY_CHANNEL_TYPE attrs.
+ * @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP
+ * @NL80211_CMD_STOP_AP: Stop AP operation on the given interface
+ * @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP
  *
  * @NL80211_CMD_GET_STATION: Get station attributes for station identified by
  *     %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
  * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to
  *     NL80211_CMD_GET_SURVEY and on the "scan" multicast group)
  *
+ * @NL80211_CMD_SET_PMKSA: Add a PMKSA cache entry, using %NL80211_ATTR_MAC
+ *     (for the BSSID) and %NL80211_ATTR_PMKID.
+ * @NL80211_CMD_DEL_PMKSA: Delete a PMKSA cache entry, using %NL80211_ATTR_MAC
+ *     (for the BSSID) and %NL80211_ATTR_PMKID.
+ * @NL80211_CMD_FLUSH_PMKSA: Flush all PMKSA cache entries.
+ *
  * @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain
  *     has been changed and provides details of the request information
  *     that caused the change such as who initiated the regulatory request
  *     %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
  *     %NL80211_ATTR_CONTROL_PORT_ETHERTYPE and
  *     %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT.
+ *     Background scan period can optionally be
+ *     specified in %NL80211_ATTR_BG_SCAN_PERIOD,
+ *     if not specified default background scan configuration
+ *     in driver is used and if period value is 0, bg scan will be disabled.
+ *     This attribute is ignored if driver does not support roam scan.
  *     It is also sent as an event, with the BSSID and response IEs when the
  *     connection is established or failed to be established. This can be
  *     determined by the STATUS_CODE attribute.
  *     the frame.
  * @NL80211_CMD_ACTION_TX_STATUS: Alias for @NL80211_CMD_FRAME_TX_STATUS for
  *     backward compatibility.
+ *
+ * @NL80211_CMD_SET_POWER_SAVE: Set powersave, using %NL80211_ATTR_PS_STATE
+ * @NL80211_CMD_GET_POWER_SAVE: Get powersave status in %NL80211_ATTR_PS_STATE
+ *
  * @NL80211_CMD_SET_CQM: Connection quality monitor configuration. This command
  *     is used to configure connection quality monitoring notification trigger
  *     levels.
  * @NL80211_CMD_SET_NOACK_MAP: sets a bitmap for the individual TIDs whether
  *      No Acknowledgement Policy should be applied.
  *
+ * @NL80211_CMD_CH_SWITCH_NOTIFY: An AP or GO may decide to switch channels
+ *     independently of the userspace SME, send this event indicating
+ *     %NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ with
+ *     %NL80211_ATTR_WIPHY_CHANNEL_TYPE.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -565,8 +589,10 @@ enum nl80211_commands {
 
        NL80211_CMD_GET_BEACON,
        NL80211_CMD_SET_BEACON,
-       NL80211_CMD_NEW_BEACON,
-       NL80211_CMD_DEL_BEACON,
+       NL80211_CMD_START_AP,
+       NL80211_CMD_NEW_BEACON = NL80211_CMD_START_AP,
+       NL80211_CMD_STOP_AP,
+       NL80211_CMD_DEL_BEACON = NL80211_CMD_STOP_AP,
 
        NL80211_CMD_GET_STATION,
        NL80211_CMD_SET_STATION,
@@ -680,6 +706,8 @@ enum nl80211_commands {
 
        NL80211_CMD_SET_NOACK_MAP,
 
+       NL80211_CMD_CH_SWITCH_NOTIFY,
+
        /* add new commands above here */
 
        /* used to define NL80211_CMD_MAX below */
@@ -753,6 +781,13 @@ enum nl80211_commands {
  *     section 7.3.2.25.1, e.g. 0x000FAC04)
  * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
  *     CCMP keys, each six bytes in little endian
+ * @NL80211_ATTR_KEY_DEFAULT: Flag attribute indicating the key is default key
+ * @NL80211_ATTR_KEY_DEFAULT_MGMT: Flag attribute indicating the key is the
+ *     default management key
+ * @NL80211_ATTR_CIPHER_SUITES_PAIRWISE: For crypto settings for connect or
+ *     other commands, indicates which pairwise cipher suites are used
+ * @NL80211_ATTR_CIPHER_SUITE_GROUP: For crypto settings for connect or
+ *     other commands, indicates which group cipher suite is used
  *
  * @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU
  * @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing
@@ -988,6 +1023,8 @@ enum nl80211_commands {
  * @NL80211_ATTR_ACK: Flag attribute indicating that the frame was
  *     acknowledged by the recipient.
  *
+ * @NL80211_ATTR_PS_STATE: powersave state, using &enum nl80211_ps_state values.
+ *
  * @NL80211_ATTR_CQM: connection quality monitor configuration in a
  *     nested attribute with %NL80211_ATTR_CQM_* sub-attributes.
  *
@@ -1045,7 +1082,7 @@ enum nl80211_commands {
  *     flag isn't set, the frame will be rejected. This is also used as an
  *     nl80211 capability flag.
  *
- * @NL80211_ATTR_BSS_HTOPMODE: HT operation mode (u16)
+ * @NL80211_ATTR_BSS_HT_OPMODE: HT operation mode (u16)
  *
  * @NL80211_ATTR_KEY_DEFAULT_TYPES: A nested attribute containing flags
  *     attributes, specifying what a key should be set as default as.
@@ -1069,10 +1106,10 @@ enum nl80211_commands {
  *     indicate which WoW triggers should be enabled. This is also
  *     used by %NL80211_CMD_GET_WOWLAN to get the currently enabled WoWLAN
  *     triggers.
-
+ *
  * @NL80211_ATTR_SCHED_SCAN_INTERVAL: Interval between scheduled scan
  *     cycles, in msecs.
-
+ *
  * @NL80211_ATTR_SCHED_SCAN_MATCH: Nested attribute with one or more
  *     sets of attributes to match during scheduled scans.  Only BSSs
  *     that match any of the sets will be reported.  These are
@@ -1099,7 +1136,7 @@ enum nl80211_commands {
  *     are managed in software: interfaces of these types aren't subject to
  *     any restrictions in their number or combinations.
  *
- * @%NL80211_ATTR_REKEY_DATA: nested attribute containing the information
+ * @NL80211_ATTR_REKEY_DATA: nested attribute containing the information
  *     necessary for GTK rekeying in the device, see &enum nl80211_rekey_data.
  *
  * @NL80211_ATTR_SCAN_SUPP_RATES: rates per to be advertised as supported in scan,
@@ -1166,7 +1203,6 @@ enum nl80211_commands {
  * @NL80211_ATTR_FEATURE_FLAGS: This u32 attribute contains flags from
  *     &enum nl80211_feature_flags and is advertised in wiphy information.
  * @NL80211_ATTR_PROBE_RESP_OFFLOAD: Indicates that the HW responds to probe
- *
  *     requests while operating in AP-mode.
  *     This attribute holds a bitmap of the supported protocols for
  *     offloading (see &enum nl80211_probe_resp_offload_support_attr).
@@ -1193,6 +1229,19 @@ enum nl80211_commands {
  * @NL80211_ATTR_NOACK_MAP: This u16 bitmap contains the No Ack Policy of
  *      up to 16 TIDs.
  *
+ * @NL80211_ATTR_INACTIVITY_TIMEOUT: timeout value in seconds, this can be
+ *     used by the drivers which has MLME in firmware and does not have support
+ *     to report per station tx/rx activity to free up the staion entry from
+ *     the list. This needs to be used when the driver advertises the
+ *     capability to timeout the stations.
+ *
+ * @NL80211_ATTR_RX_SIGNAL_DBM: signal strength in dBm (as a 32-bit int);
+ *     this attribute is (depending on the driver capabilities) added to
+ *     received frames indicated with %NL80211_CMD_FRAME.
+ *
+ * @NL80211_ATTR_BG_SCAN_PERIOD: Background scan period in seconds
+ *      or 0 to disable background scan.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1438,6 +1487,12 @@ enum nl80211_attrs {
 
        NL80211_ATTR_NOACK_MAP,
 
+       NL80211_ATTR_INACTIVITY_TIMEOUT,
+
+       NL80211_ATTR_RX_SIGNAL_DBM,
+
+       NL80211_ATTR_BG_SCAN_PERIOD,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -1475,6 +1530,7 @@ enum nl80211_attrs {
 #define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS
 
 #define NL80211_MAX_SUPP_RATES                 32
+#define NL80211_MAX_SUPP_HT_RATES              77
 #define NL80211_MAX_SUPP_REG_RULES             32
 #define NL80211_TKIP_DATA_OFFSET_ENCR_KEY      0
 #define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY    16
@@ -1484,6 +1540,11 @@ enum nl80211_attrs {
 #define NL80211_MAX_NR_CIPHER_SUITES           5
 #define NL80211_MAX_NR_AKM_SUITES              2
 
+#define NL80211_MIN_REMAIN_ON_CHANNEL_TIME     10
+
+/* default RSSI threshold for scan results if none specified. */
+#define NL80211_SCAN_RSSI_THOLD_OFF            -300
+
 /**
  * enum nl80211_iftype - (virtual) interface types
  *
@@ -1558,6 +1619,8 @@ enum nl80211_sta_flags {
        NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
 };
 
+#define NL80211_STA_FLAG_MAX_OLD_API   NL80211_STA_FLAG_TDLS_PEER
+
 /**
  * struct nl80211_sta_flag_update - station flags mask/set
  * @mask: mask of station flags to set
@@ -1656,6 +1719,7 @@ enum nl80211_sta_bss_param {
  * @NL80211_STA_INFO_CONNECTED_TIME: time since the station is last connected
  * @NL80211_STA_INFO_STA_FLAGS: Contains a struct nl80211_sta_flag_update.
  * @NL80211_STA_INFO_BEACON_LOSS: count of times beacon loss was detected (u32)
+ * @NL80211_STA_INFO_T_OFFSET: timing offset with respect to this STA (s64)
  * @__NL80211_STA_INFO_AFTER_LAST: internal
  * @NL80211_STA_INFO_MAX: highest possible station info attribute
  */
@@ -1679,6 +1743,7 @@ enum nl80211_sta_info {
        NL80211_STA_INFO_CONNECTED_TIME,
        NL80211_STA_INFO_STA_FLAGS,
        NL80211_STA_INFO_BEACON_LOSS,
+       NL80211_STA_INFO_T_OFFSET,
 
        /* keep last */
        __NL80211_STA_INFO_AFTER_LAST,
@@ -1748,6 +1813,9 @@ enum nl80211_mpath_info {
  * @NL80211_BAND_ATTR_HT_CAPA: HT capabilities, as in the HT information IE
  * @NL80211_BAND_ATTR_HT_AMPDU_FACTOR: A-MPDU factor, as in 11n
  * @NL80211_BAND_ATTR_HT_AMPDU_DENSITY: A-MPDU density, as in 11n
+ * @NL80211_BAND_ATTR_VHT_MCS_SET: 32-byte attribute containing the MCS set as
+ *     defined in 802.11ac
+ * @NL80211_BAND_ATTR_VHT_CAPA: VHT capabilities, as in the HT information IE
  * @NL80211_BAND_ATTR_MAX: highest band attribute currently defined
  * @__NL80211_BAND_ATTR_AFTER_LAST: internal use
  */
@@ -1761,6 +1829,9 @@ enum nl80211_band_attr {
        NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
        NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
 
+       NL80211_BAND_ATTR_VHT_MCS_SET,
+       NL80211_BAND_ATTR_VHT_CAPA,
+
        /* keep last */
        __NL80211_BAND_ATTR_AFTER_LAST,
        NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1
@@ -1912,6 +1983,8 @@ enum nl80211_reg_rule_attr {
  * @__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID: attribute number 0 is reserved
  * @NL80211_SCHED_SCAN_MATCH_ATTR_SSID: SSID to be used for matching,
  * only report BSS with matching SSID.
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_RSSI: RSSI threshold (in dBm) for reporting a
+ *     BSS in scan results. Filtering is turned off if not specified.
  * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter
  *     attribute number currently defined
  * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use
@@ -1919,7 +1992,8 @@ enum nl80211_reg_rule_attr {
 enum nl80211_sched_scan_match_attr {
        __NL80211_SCHED_SCAN_MATCH_ATTR_INVALID,
 
-       NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
+       NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
+       NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
 
        /* keep last */
        __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST,
@@ -1927,6 +2001,9 @@ enum nl80211_sched_scan_match_attr {
                __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST - 1
 };
 
+/* only for backward compatibility */
+#define NL80211_ATTR_SCHED_SCAN_MATCH_SSID NL80211_SCHED_SCAN_MATCH_ATTR_SSID
+
 /**
  * enum nl80211_reg_rule_flags - regulatory rule flags
  *
@@ -1956,9 +2033,9 @@ enum nl80211_reg_rule_flags {
  * enum nl80211_dfs_regions - regulatory DFS regions
  *
  * @NL80211_DFS_UNSET: Country has no DFS master region specified
- * @NL80211_DFS_FCC_: Country follows DFS master rules from FCC
- * @NL80211_DFS_FCC_: Country follows DFS master rules from ETSI
- * @NL80211_DFS_JP_: Country follows DFS master rules from JP/MKK/Telec
+ * @NL80211_DFS_FCC: Country follows DFS master rules from FCC
+ * @NL80211_DFS_ETSI: Country follows DFS master rules from ETSI
+ * @NL80211_DFS_JP: Country follows DFS master rules from JP/MKK/Telec
  */
 enum nl80211_dfs_regions {
        NL80211_DFS_UNSET       = 0,
@@ -2046,69 +2123,91 @@ enum nl80211_mntr_flags {
  * @__NL80211_MESHCONF_INVALID: internal use
  *
  * @NL80211_MESHCONF_RETRY_TIMEOUT: specifies the initial retry timeout in
- * millisecond units, used by the Peer Link Open message
+ *     millisecond units, used by the Peer Link Open message
  *
  * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the initial confirm timeout, in
- * millisecond units, used by the peer link management to close a peer link
+ *     millisecond units, used by the peer link management to close a peer link
  *
  * @NL80211_MESHCONF_HOLDING_TIMEOUT: specifies the holding timeout, in
- * millisecond units
+ *     millisecond units
  *
  * @NL80211_MESHCONF_MAX_PEER_LINKS: maximum number of peer links allowed
- * on this mesh interface
+ *     on this mesh interface
  *
  * @NL80211_MESHCONF_MAX_RETRIES: specifies the maximum number of peer link
- * open retries that can be sent to establish a new peer link instance in a
- * mesh
+ *     open retries that can be sent to establish a new peer link instance in a
+ *     mesh
  *
  * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh
- * point.
+ *     point.
  *
  * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically
- * open peer links when we detect compatible mesh peers.
+ *     open peer links when we detect compatible mesh peers.
  *
  * @NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES: the number of action frames
- * containing a PREQ that an MP can send to a particular destination (path
- * target)
+ *     containing a PREQ that an MP can send to a particular destination (path
+ *     target)
  *
  * @NL80211_MESHCONF_PATH_REFRESH_TIME: how frequently to refresh mesh paths
- * (in milliseconds)
+ *     (in milliseconds)
  *
  * @NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT: minimum length of time to wait
- * until giving up on a path discovery (in milliseconds)
+ *     until giving up on a path discovery (in milliseconds)
  *
  * @NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT: The time (in TUs) for which mesh
- * points receiving a PREQ shall consider the forwarding information from the
- * root to be valid. (TU = time unit)
+ *     points receiving a PREQ shall consider the forwarding information from
+ *     the root to be valid. (TU = time unit)
  *
  * @NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL: The minimum interval of time (in
- * TUs) during which an MP can send only one action frame containing a PREQ
- * reference element
+ *     TUs) during which an MP can send only one action frame containing a PREQ
+ *     reference element
  *
  * @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs)
- * that it takes for an HWMP information element to propagate across the mesh
+ *     that it takes for an HWMP information element to propagate across the
+ *     mesh
  *
  * @NL80211_MESHCONF_HWMP_ROOTMODE: whether root mode is enabled or not
  *
  * @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a
- * source mesh point for path selection elements.
+ *     source mesh point for path selection elements.
  *
  * @NL80211_MESHCONF_HWMP_RANN_INTERVAL:  The interval of time (in TUs) between
- * root announcements are transmitted.
+ *     root announcements are transmitted.
  *
  * @NL80211_MESHCONF_GATE_ANNOUNCEMENTS: Advertise that this mesh station has
- * access to a broader network beyond the MBSS.  This is done via Root
- * Announcement frames.
+ *     access to a broader network beyond the MBSS.  This is done via Root
+ *     Announcement frames.
  *
  * @NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL: The minimum interval of time (in
- * TUs) during which a mesh STA can send only one Action frame containing a
- * PERR element.
+ *     TUs) during which a mesh STA can send only one Action frame containing a
+ *     PERR element.
  *
  * @NL80211_MESHCONF_FORWARDING: set Mesh STA as forwarding or non-forwarding
- * or forwarding entity (default is TRUE - forwarding entity)
+ *     or forwarding entity (default is TRUE - forwarding entity)
+ *
+ * @NL80211_MESHCONF_RSSI_THRESHOLD: RSSI threshold in dBm. This specifies the
+ *     threshold for average signal strength of candidate station to establish
+ *     a peer link.
+ *
+ * @NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR: maximum number of neighbors
+ *     to synchronize to for 11s default synchronization method
+ *     (see 11C.12.2.2)
+ *
+ * @NL80211_MESHCONF_HT_OPMODE: set mesh HT protection mode.
  *
  * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
  *
+ * @NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT: The time (in TUs) for
+ *     which mesh STAs receiving a proactive PREQ shall consider the forwarding
+ *     information to the root mesh STA to be valid.
+ *
+ * @NL80211_MESHCONF_HWMP_ROOT_INTERVAL: The interval of time (in TUs) between
+ *     proactive PREQs are transmitted.
+ *
+ * @NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL: The minimum interval of time
+ *     (in TUs) during which a mesh STA can send only one Action frame
+ *     containing a PREQ element for root path confirmation.
+ *
  * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
  */
 enum nl80211_meshconf_params {
@@ -2132,6 +2231,12 @@ enum nl80211_meshconf_params {
        NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
        NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
        NL80211_MESHCONF_FORWARDING,
+       NL80211_MESHCONF_RSSI_THRESHOLD,
+       NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
+       NL80211_MESHCONF_HT_OPMODE,
+       NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
+       NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
+       NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
 
        /* keep last */
        __NL80211_MESHCONF_ATTR_AFTER_LAST,
@@ -2147,30 +2252,37 @@ enum nl80211_meshconf_params {
  * @__NL80211_MESH_SETUP_INVALID: Internal use
  *
  * @NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL: Enable this option to use a
- * vendor specific path selection algorithm or disable it to use the default
- * HWMP.
+ *     vendor specific path selection algorithm or disable it to use the
+ *     default HWMP.
  *
  * @NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC: Enable this option to use a
- * vendor specific path metric or disable it to use the default Airtime
- * metric.
+ *     vendor specific path metric or disable it to use the default Airtime
+ *     metric.
  *
  * @NL80211_MESH_SETUP_IE: Information elements for this mesh, for instance, a
- * robust security network ie, or a vendor specific information element that
- * vendors will use to identify the path selection methods and metrics in use.
+ *     robust security network ie, or a vendor specific information element
+ *     that vendors will use to identify the path selection methods and
+ *     metrics in use.
  *
  * @NL80211_MESH_SETUP_USERSPACE_AUTH: Enable this option if an authentication
- * daemon will be authenticating mesh candidates.
+ *     daemon will be authenticating mesh candidates.
  *
  * @NL80211_MESH_SETUP_USERSPACE_AMPE: Enable this option if an authentication
- * daemon will be securing peer link frames.  AMPE is a secured version of Mesh
- * Peering Management (MPM) and is implemented with the assistance of a
- * userspace daemon.  When this flag is set, the kernel will send peer
- * management frames to a userspace daemon that will implement AMPE
- * functionality (security capabilities selection, key confirmation, and key
- * management).  When the flag is unset (default), the kernel can autonomously
- * complete (unsecured) mesh peering without the need of a userspace daemon.
+ *     daemon will be securing peer link frames.  AMPE is a secured version of
+ *     Mesh Peering Management (MPM) and is implemented with the assistance of
+ *     a userspace daemon.  When this flag is set, the kernel will send peer
+ *     management frames to a userspace daemon that will implement AMPE
+ *     functionality (security capabilities selection, key confirmation, and
+ *     key management).  When the flag is unset (default), the kernel can
+ *     autonomously complete (unsecured) mesh peering without the need of a
+ *     userspace daemon.
+ *
+ * @NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC: Enable this option to use a
+ *     vendor specific synchronization method or disable it to use the default
+ *     neighbor offset synchronization
  *
  * @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number
+ *
  * @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use
  */
 enum nl80211_mesh_setup_params {
@@ -2180,6 +2292,7 @@ enum nl80211_mesh_setup_params {
        NL80211_MESH_SETUP_IE,
        NL80211_MESH_SETUP_USERSPACE_AUTH,
        NL80211_MESH_SETUP_USERSPACE_AMPE,
+       NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC,
 
        /* keep last */
        __NL80211_MESH_SETUP_ATTR_AFTER_LAST,
@@ -2189,7 +2302,7 @@ enum nl80211_mesh_setup_params {
 /**
  * enum nl80211_txq_attr - TX queue parameter attributes
  * @__NL80211_TXQ_ATTR_INVALID: Attribute number 0 is reserved
- * @NL80211_TXQ_ATTR_QUEUE: TX queue identifier (NL80211_TXQ_Q_*)
+ * @NL80211_TXQ_ATTR_AC: AC identifier (NL80211_AC_*)
  * @NL80211_TXQ_ATTR_TXOP: Maximum burst time in units of 32 usecs, 0 meaning
  *     disabled
  * @NL80211_TXQ_ATTR_CWMIN: Minimum contention window [a value of the form
@@ -2202,7 +2315,7 @@ enum nl80211_mesh_setup_params {
  */
 enum nl80211_txq_attr {
        __NL80211_TXQ_ATTR_INVALID,
-       NL80211_TXQ_ATTR_QUEUE,
+       NL80211_TXQ_ATTR_AC,
        NL80211_TXQ_ATTR_TXOP,
        NL80211_TXQ_ATTR_CWMIN,
        NL80211_TXQ_ATTR_CWMAX,
@@ -2213,13 +2326,21 @@ enum nl80211_txq_attr {
        NL80211_TXQ_ATTR_MAX = __NL80211_TXQ_ATTR_AFTER_LAST - 1
 };
 
-enum nl80211_txq_q {
-       NL80211_TXQ_Q_VO,
-       NL80211_TXQ_Q_VI,
-       NL80211_TXQ_Q_BE,
-       NL80211_TXQ_Q_BK
+enum nl80211_ac {
+       NL80211_AC_VO,
+       NL80211_AC_VI,
+       NL80211_AC_BE,
+       NL80211_AC_BK,
+       NL80211_NUM_ACS
 };
 
+/* backward compat */
+#define NL80211_TXQ_ATTR_QUEUE NL80211_TXQ_ATTR_AC
+#define NL80211_TXQ_Q_VO       NL80211_AC_VO
+#define NL80211_TXQ_Q_VI       NL80211_AC_VI
+#define NL80211_TXQ_Q_BE       NL80211_AC_BE
+#define NL80211_TXQ_Q_BK       NL80211_AC_BK
+
 enum nl80211_channel_type {
        NL80211_CHAN_NO_HT,
        NL80211_CHAN_HT20,
@@ -2405,12 +2526,15 @@ enum nl80211_key_attributes {
  *     in an array of rates as defined in IEEE 802.11 7.3.2.2 (u8 values with
  *     1 = 500 kbps) but without the IE length restriction (at most
  *     %NL80211_MAX_SUPP_RATES in a single array).
+ * @NL80211_TXRATE_MCS: HT (MCS) rates allowed for TX rate selection
+ *     in an array of MCS numbers.
  * @__NL80211_TXRATE_AFTER_LAST: internal
  * @NL80211_TXRATE_MAX: highest TX rate attribute
  */
 enum nl80211_tx_rate_attributes {
        __NL80211_TXRATE_INVALID,
        NL80211_TXRATE_LEGACY,
+       NL80211_TXRATE_MCS,
 
        /* keep last */
        __NL80211_TXRATE_AFTER_LAST,
@@ -2421,12 +2545,19 @@ enum nl80211_tx_rate_attributes {
  * enum nl80211_band - Frequency band
  * @NL80211_BAND_2GHZ: 2.4 GHz ISM band
  * @NL80211_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz)
+ * @NL80211_BAND_60GHZ: around 60 GHz band (58.32 - 64.80 GHz)
  */
 enum nl80211_band {
        NL80211_BAND_2GHZ,
        NL80211_BAND_5GHZ,
+       NL80211_BAND_60GHZ,
 };
 
+/**
+ * enum nl80211_ps_state - powersave state
+ * @NL80211_PS_DISABLED: powersave is disabled
+ * @NL80211_PS_ENABLED: powersave is enabled
+ */
 enum nl80211_ps_state {
        NL80211_PS_DISABLED,
        NL80211_PS_ENABLED,
@@ -2465,10 +2596,14 @@ enum nl80211_attr_cqm {
  *      configured threshold
  * @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH: The RSSI is higher than the
  *      configured threshold
+ * @NL80211_CQM_RSSI_BEACON_LOSS_EVENT: The device experienced beacon loss.
+ *     (Note that deauth/disassoc will still follow if the AP is not
+ *     available. This event might get used as roaming event, etc.)
  */
 enum nl80211_cqm_rssi_threshold_event {
        NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
        NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
+       NL80211_CQM_RSSI_BEACON_LOSS_EVENT,
 };
 
 
@@ -2796,10 +2931,13 @@ enum nl80211_ap_sme_features {
  *     TX status to the socket error queue when requested with the
  *     socket option.
  * @NL80211_FEATURE_HT_IBSS: This driver supports IBSS with HT datarates.
+ * @NL80211_FEATURE_INACTIVITY_TIMER: This driver takes care of freeing up
+ *     the connected inactive stations in AP mode.
  */
 enum nl80211_feature_flags {
        NL80211_FEATURE_SK_TX_STATUS    = 1 << 0,
        NL80211_FEATURE_HT_IBSS         = 1 << 1,
+       NL80211_FEATURE_INACTIVITY_TIMER = 1 << 2,
 };
 
 /**
index af0a29a..360193a 100644 (file)
@@ -60,7 +60,7 @@ typedef enum {
        EAP_TYPE_PSK = 47 /* RFC 4764 */,
        EAP_TYPE_SAKE = 48 /* RFC 4763 */,
        EAP_TYPE_IKEV2 = 49 /* RFC 5106 */,
-       EAP_TYPE_AKA_PRIME = 50 /* draft-arkko-eap-aka-kdf-10.txt */,
+       EAP_TYPE_AKA_PRIME = 50 /* RFC 5448 */,
        EAP_TYPE_GPSK = 51 /* RFC 5433 */,
        EAP_TYPE_PWD = 52 /* RFC 5931 */,
        EAP_TYPE_EXPANDED = 254 /* RFC 3748 */
index 5b6bf3c..7d6e6b8 100644 (file)
@@ -8,70 +8,76 @@
 
 #include "includes.h"
 #include "common.h"
+#include "crypto/sha256.h"
+#include "crypto/crypto.h"
 #include "eap_defs.h"
 #include "eap_pwd_common.h"
 
 /* The random function H(x) = HMAC-SHA256(0^32, x) */
-void H_Init(HMAC_CTX *ctx)
+struct crypto_hash * eap_pwd_h_init(void)
 {
-       u8 allzero[SHA256_DIGEST_LENGTH];
-
-       os_memset(allzero, 0, SHA256_DIGEST_LENGTH);
-       HMAC_Init(ctx, allzero, SHA256_DIGEST_LENGTH, EVP_sha256());
+       u8 allzero[SHA256_MAC_LEN];
+       os_memset(allzero, 0, SHA256_MAC_LEN);
+       return crypto_hash_init(CRYPTO_HASH_ALG_HMAC_SHA256, allzero,
+                               SHA256_MAC_LEN);
 }
 
 
-void H_Update(HMAC_CTX *ctx, const u8 *data, int len)
+void eap_pwd_h_update(struct crypto_hash *hash, const u8 *data, size_t len)
 {
-       HMAC_Update(ctx, data, len);
+       crypto_hash_update(hash, data, len);
 }
 
 
-void H_Final(HMAC_CTX *ctx, u8 *digest)
+void eap_pwd_h_final(struct crypto_hash *hash, u8 *digest)
 {
-       unsigned int mdlen = SHA256_DIGEST_LENGTH;
-
-       HMAC_Final(ctx, digest, &mdlen);
-       HMAC_CTX_cleanup(ctx);
+       size_t len = SHA256_MAC_LEN;
+       crypto_hash_finish(hash, digest, &len);
 }
 
 
 /* a counter-based KDF based on NIST SP800-108 */
-void eap_pwd_kdf(u8 *key, int keylen, u8 *label, int labellen,
-                u8 *result, int resultbitlen)
+static int eap_pwd_kdf(const u8 *key, size_t keylen, const u8 *label,
+                      size_t labellen, u8 *result, size_t resultbitlen)
 {
-       HMAC_CTX hctx;
-       unsigned char digest[SHA256_DIGEST_LENGTH];
+       struct crypto_hash *hash;
+       u8 digest[SHA256_MAC_LEN];
        u16 i, ctr, L;
-       int resultbytelen, len = 0;
-       unsigned int mdlen = SHA256_DIGEST_LENGTH;
-       unsigned char mask = 0xff;
+       size_t resultbytelen, len = 0, mdlen;
 
-       resultbytelen = (resultbitlen + 7)/8;
+       resultbytelen = (resultbitlen + 7) / 8;
        ctr = 0;
        L = htons(resultbitlen);
        while (len < resultbytelen) {
-               ctr++; i = htons(ctr);
-               HMAC_Init(&hctx, key, keylen, EVP_sha256());
+               ctr++;
+               i = htons(ctr);
+               hash = crypto_hash_init(CRYPTO_HASH_ALG_HMAC_SHA256,
+                                       key, keylen);
+               if (hash == NULL)
+                       return -1;
                if (ctr > 1)
-                       HMAC_Update(&hctx, digest, mdlen);
-               HMAC_Update(&hctx, (u8 *) &i, sizeof(u16));
-               HMAC_Update(&hctx, label, labellen);
-               HMAC_Update(&hctx, (u8 *) &L, sizeof(u16));
-               HMAC_Final(&hctx, digest, &mdlen);
-               if ((len + (int) mdlen) > resultbytelen)
+                       crypto_hash_update(hash, digest, SHA256_MAC_LEN);
+               crypto_hash_update(hash, (u8 *) &i, sizeof(u16));
+               crypto_hash_update(hash, label, labellen);
+               crypto_hash_update(hash, (u8 *) &L, sizeof(u16));
+               mdlen = SHA256_MAC_LEN;
+               if (crypto_hash_finish(hash, digest, &mdlen) < 0)
+                       return -1;
+               if ((len + mdlen) > resultbytelen)
                        os_memcpy(result + len, digest, resultbytelen - len);
                else
                        os_memcpy(result + len, digest, mdlen);
                len += mdlen;
-               HMAC_CTX_cleanup(&hctx);
        }
 
        /* since we're expanding to a bit length, mask off the excess */
        if (resultbitlen % 8) {
+               u8 mask = 0xff;
                mask <<= (8 - (resultbitlen % 8));
                result[resultbytelen - 1] &= mask;
        }
+
+       return 0;
 }
 
 
@@ -85,9 +91,10 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
                             u8 *id_peer, int id_peer_len, u8 *token)
 {
        BIGNUM *x_candidate = NULL, *rnd = NULL, *cofactor = NULL;
-       HMAC_CTX ctx;
-       unsigned char pwe_digest[SHA256_DIGEST_LENGTH], *prfbuf = NULL, ctr;
-       int nid, is_odd, primebitlen, primebytelen, ret = 0;
+       struct crypto_hash *hash;
+       unsigned char pwe_digest[SHA256_MAC_LEN], *prfbuf = NULL, ctr;
+       int nid, is_odd, ret = 0;
+       size_t primebytelen, primebitlen;
 
        switch (num) { /* from IANA registry for IKE D-H groups */
         case 19:
@@ -154,7 +161,7 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
        os_memset(prfbuf, 0, primebytelen);
        ctr = 0;
        while (1) {
-               if (ctr > 10) {
+               if (ctr > 30) {
                        wpa_printf(MSG_INFO, "EAP-pwd: unable to find random "
                                   "point on curve for group %d, something's "
                                   "fishy", num);
@@ -167,20 +174,23 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
                 *    pwd-seed = H(token | peer-id | server-id | password |
                 *                 counter)
                 */
-               H_Init(&ctx);
-               H_Update(&ctx, token, sizeof(u32));
-               H_Update(&ctx, id_peer, id_peer_len);
-               H_Update(&ctx, id_server, id_server_len);
-               H_Update(&ctx, password, password_len);
-               H_Update(&ctx, &ctr, sizeof(ctr));
-               H_Final(&ctx, pwe_digest);
-
-               BN_bin2bn(pwe_digest, SHA256_DIGEST_LENGTH, rnd);
-
-               eap_pwd_kdf(pwe_digest, SHA256_DIGEST_LENGTH,
-                           (unsigned char *) "EAP-pwd Hunting And Pecking",
-                           os_strlen("EAP-pwd Hunting And Pecking"),
-                           prfbuf, primebitlen);
+               hash = eap_pwd_h_init();
+               if (hash == NULL)
+                       goto fail;
+               eap_pwd_h_update(hash, token, sizeof(u32));
+               eap_pwd_h_update(hash, id_peer, id_peer_len);
+               eap_pwd_h_update(hash, id_server, id_server_len);
+               eap_pwd_h_update(hash, password, password_len);
+               eap_pwd_h_update(hash, &ctr, sizeof(ctr));
+               eap_pwd_h_final(hash, pwe_digest);
+
+               BN_bin2bn(pwe_digest, SHA256_MAC_LEN, rnd);
+
+               if (eap_pwd_kdf(pwe_digest, SHA256_MAC_LEN,
+                               (u8 *) "EAP-pwd Hunting And Pecking",
+                               os_strlen("EAP-pwd Hunting And Pecking"),
+                               prfbuf, primebitlen) < 0)
+                       goto fail;
 
                BN_bin2bn(prfbuf, primebytelen, x_candidate);
 
@@ -252,11 +262,13 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
        if (0) {
  fail:
                EC_GROUP_free(grp->group);
+               grp->group = NULL;
                EC_POINT_free(grp->pwe);
+               grp->pwe = NULL;
                BN_free(grp->order);
+               grp->order = NULL;
                BN_free(grp->prime);
-               os_free(grp);
-               grp = NULL;
+               grp->prime = NULL;
                ret = 1;
        }
        /* cleanliness and order.... */
@@ -274,9 +286,9 @@ int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, BIGNUM *k,
                 u8 *confirm_peer, u8 *confirm_server,
                 u32 *ciphersuite, u8 *msk, u8 *emsk)
 {
-       HMAC_CTX ctx;
-       u8 mk[SHA256_DIGEST_LENGTH], *cruft;
-       u8 session_id[SHA256_DIGEST_LENGTH + 1];
+       struct crypto_hash *hash;
+       u8 mk[SHA256_MAC_LEN], *cruft;
+       u8 session_id[SHA256_MAC_LEN + 1];
        u8 msk_emsk[EAP_MSK_LEN + EAP_EMSK_LEN];
        int offset;
 
@@ -288,37 +300,46 @@ int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, BIGNUM *k,
         *      scal_s)
         */
        session_id[0] = EAP_TYPE_PWD;
-       H_Init(&ctx);
-       H_Update(&ctx, (u8 *)ciphersuite, sizeof(u32));
+       hash = eap_pwd_h_init();
+       if (hash == NULL) {
+               os_free(cruft);
+               return -1;
+       }
+       eap_pwd_h_update(hash, (u8 *) ciphersuite, sizeof(u32));
        offset = BN_num_bytes(grp->order) - BN_num_bytes(peer_scalar);
        os_memset(cruft, 0, BN_num_bytes(grp->prime));
        BN_bn2bin(peer_scalar, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(grp->order));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(grp->order));
        offset = BN_num_bytes(grp->order) - BN_num_bytes(server_scalar);
        os_memset(cruft, 0, BN_num_bytes(grp->prime));
        BN_bn2bin(server_scalar, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(grp->order));
-       H_Final(&ctx, &session_id[1]);
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(grp->order));
+       eap_pwd_h_final(hash, &session_id[1]);
 
        /* then compute MK = H(k | confirm-peer | confirm-server) */
-       H_Init(&ctx);
+       hash = eap_pwd_h_init();
+       if (hash == NULL) {
+               os_free(cruft);
+               return -1;
+       }
        offset = BN_num_bytes(grp->prime) - BN_num_bytes(k);
        os_memset(cruft, 0, BN_num_bytes(grp->prime));
        BN_bn2bin(k, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(grp->prime));
-       H_Update(&ctx, confirm_peer, SHA256_DIGEST_LENGTH);
-       H_Update(&ctx, confirm_server, SHA256_DIGEST_LENGTH);
-       H_Final(&ctx, mk);
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(grp->prime));
+       os_free(cruft);
+       eap_pwd_h_update(hash, confirm_peer, SHA256_MAC_LEN);
+       eap_pwd_h_update(hash, confirm_server, SHA256_MAC_LEN);
+       eap_pwd_h_final(hash, mk);
 
        /* stretch the mk with the session-id to get MSK | EMSK */
-       eap_pwd_kdf(mk, SHA256_DIGEST_LENGTH,
-                   session_id, SHA256_DIGEST_LENGTH+1,
-                   msk_emsk, (EAP_MSK_LEN + EAP_EMSK_LEN) * 8);
+       if (eap_pwd_kdf(mk, SHA256_MAC_LEN,
+                       session_id, SHA256_MAC_LEN + 1,
+                       msk_emsk, (EAP_MSK_LEN + EAP_EMSK_LEN) * 8) < 0) {
+               return -1;
+       }
 
        os_memcpy(msk, msk_emsk, EAP_MSK_LEN);
        os_memcpy(emsk, msk_emsk + EAP_MSK_LEN, EAP_EMSK_LEN);
 
-       os_free(cruft);
-
        return 1;
 }
index 358d008..816e58c 100644 (file)
 #define EAP_PWD_COMMON_H
 
 #include <openssl/bn.h>
-#include <openssl/sha.h>
 #include <openssl/ec.h>
 #include <openssl/evp.h>
-#include <openssl/hmac.h>
 
 /*
  * definition of a finite cyclic group
@@ -62,8 +60,8 @@ int compute_password_element(EAP_PWD_group *, u16, u8 *, int, u8 *, int, u8 *,
                             int, u8 *);
 int compute_keys(EAP_PWD_group *, BN_CTX *, BIGNUM *, BIGNUM *, BIGNUM *,
                 u8 *, u8 *, u32 *, u8 *, u8 *);
-void H_Init(HMAC_CTX *);
-void H_Update(HMAC_CTX *, const u8 *, int);
-void H_Final(HMAC_CTX *, u8 *);
+struct crypto_hash * eap_pwd_h_init(void);
+void eap_pwd_h_update(struct crypto_hash *hash, const u8 *data, size_t len);
+void eap_pwd_h_final(struct crypto_hash *hash, u8 *digest);
 
 #endif  /* EAP_PWD_COMMON_H */
index 6a88589..8b43be4 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * EAP peer state machines (RFC 4137)
- * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -81,6 +81,16 @@ static struct wpabuf * eapol_get_eapReqData(struct eap_sm *sm)
 }
 
 
+static void eap_notify_status(struct eap_sm *sm, const char *status,
+                                     const char *parameter)
+{
+       wpa_printf(MSG_DEBUG, "EAP: Status notification: %s (param=%s)",
+                  status, parameter);
+       if (sm->eapol_cb->notify_status)
+               sm->eapol_cb->notify_status(sm->eapol_ctx, status, parameter);
+}
+
+
 static void eap_deinit_prev_method(struct eap_sm *sm, const char *txt)
 {
        if (sm->m == NULL || sm->eap_method_priv == NULL)
@@ -213,6 +223,7 @@ SM_STATE(EAP, GET_METHOD)
 {
        int reinit;
        EapType method;
+       const struct eap_method *eap_method;
 
        SM_ENTRY(EAP, GET_METHOD);
 
@@ -221,18 +232,24 @@ SM_STATE(EAP, GET_METHOD)
        else
                method = sm->reqMethod;
 
+       eap_method = eap_peer_get_eap_method(sm->reqVendor, method);
+
        if (!eap_sm_allowMethod(sm, sm->reqVendor, method)) {
                wpa_printf(MSG_DEBUG, "EAP: vendor %u method %u not allowed",
                           sm->reqVendor, method);
                wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
                        "vendor=%u method=%u -> NAK",
                        sm->reqVendor, method);
+               eap_notify_status(sm, "refuse proposed method",
+                                 eap_method ?  eap_method->name : "unknown");
                goto nak;
        }
 
        wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
                "vendor=%u method=%u", sm->reqVendor, method);
 
+       eap_notify_status(sm, "accept proposed method",
+                         eap_method ?  eap_method->name : "unknown");
        /*
         * RFC 4137 does not define specific operation for fast
         * re-authentication (session resumption). The design here is to allow
@@ -256,7 +273,7 @@ SM_STATE(EAP, GET_METHOD)
 
        sm->selectedMethod = sm->reqMethod;
        if (sm->m == NULL)
-               sm->m = eap_peer_get_eap_method(sm->reqVendor, method);
+               sm->m = eap_method;
        if (!sm->m) {
                wpa_printf(MSG_DEBUG, "EAP: Could not find selected method: "
                           "vendor %d method %d",
@@ -938,7 +955,7 @@ static int eap_sm_append_3gpp_realm(struct eap_sm *sm, char *imsi,
 static int eap_sm_imsi_identity(struct eap_sm *sm,
                                struct eap_peer_config *conf)
 {
-       int aka = 0;
+       enum { EAP_SM_SIM, EAP_SM_AKA, EAP_SM_AKA_PRIME } method = EAP_SM_SIM;
        char imsi[100];
        size_t imsi_len;
        struct eap_method_type *m = conf->eap_methods;
@@ -966,8 +983,14 @@ static int eap_sm_imsi_identity(struct eap_sm *sm,
        for (i = 0; m && (m[i].vendor != EAP_VENDOR_IETF ||
                          m[i].method != EAP_TYPE_NONE); i++) {
                if (m[i].vendor == EAP_VENDOR_IETF &&
+                   m[i].method == EAP_TYPE_AKA_PRIME) {
+                       method = EAP_SM_AKA_PRIME;
+                       break;
+               }
+
+               if (m[i].vendor == EAP_VENDOR_IETF &&
                    m[i].method == EAP_TYPE_AKA) {
-                       aka = 1;
+                       method = EAP_SM_AKA;
                        break;
                }
        }
@@ -980,7 +1003,17 @@ static int eap_sm_imsi_identity(struct eap_sm *sm,
                return -1;
        }
 
-       conf->identity[0] = aka ? '0' : '1';
+       switch (method) {
+       case EAP_SM_SIM:
+               conf->identity[0] = '1';
+               break;
+       case EAP_SM_AKA:
+               conf->identity[0] = '0';
+               break;
+       case EAP_SM_AKA_PRIME:
+               conf->identity[0] = '6';
+               break;
+       }
        os_memcpy(conf->identity + 1, imsi, imsi_len);
        conf->identity_len = 1 + imsi_len;
 
@@ -1219,10 +1252,12 @@ static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req)
                break;
        case EAP_CODE_SUCCESS:
                wpa_printf(MSG_DEBUG, "EAP: Received EAP-Success");
+               eap_notify_status(sm, "completion", "success");
                sm->rxSuccess = TRUE;
                break;
        case EAP_CODE_FAILURE:
                wpa_printf(MSG_DEBUG, "EAP: Received EAP-Failure");
+               eap_notify_status(sm, "completion", "failure");
                sm->rxFailure = TRUE;
                break;
        default:
@@ -1240,6 +1275,10 @@ static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev,
        char *hash_hex = NULL;
 
        switch (ev) {
+       case TLS_CERT_CHAIN_SUCCESS:
+               eap_notify_status(sm, "remote certificate verification",
+                                 "success");
+               break;
        case TLS_CERT_CHAIN_FAILURE:
                wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TLS_CERT_ERROR
                        "reason=%d depth=%d subject='%s' err='%s'",
@@ -1247,6 +1286,8 @@ static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev,
                        data->cert_fail.depth,
                        data->cert_fail.subject,
                        data->cert_fail.reason_txt);
+               eap_notify_status(sm, "remote certificate verification",
+                                 data->cert_fail.reason_txt);
                break;
        case TLS_PEER_CERTIFICATE:
                if (!sm->eapol_cb->notify_cert)
@@ -1267,6 +1308,14 @@ static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev,
                                          data->peer_cert.subject,
                                          hash_hex, data->peer_cert.cert);
                break;
+       case TLS_ALERT:
+               if (data->alert.is_local)
+                       eap_notify_status(sm, "local TLS alert",
+                                         data->alert.description);
+               else
+                       eap_notify_status(sm, "remote TLS alert",
+                                         data->alert.description);
+               break;
        }
 
        os_free(hash_hex);
@@ -1321,6 +1370,13 @@ struct eap_sm * eap_peer_sm_init(void *eapol_ctx,
                return NULL;
        }
 
+       sm->ssl_ctx2 = tls_init(&tlsconf);
+       if (sm->ssl_ctx2 == NULL) {
+               wpa_printf(MSG_INFO, "SSL: Failed to initialize TLS "
+                          "context (2).");
+               /* Run without separate TLS context within TLS tunnel */
+       }
+
        return sm;
 }
 
@@ -1338,6 +1394,8 @@ void eap_peer_sm_deinit(struct eap_sm *sm)
                return;
        eap_deinit_prev_method(sm, "EAP deinit");
        eap_sm_abort(sm);
+       if (sm->ssl_ctx2)
+               tls_deinit(sm->ssl_ctx2);
        tls_deinit(sm->ssl_ctx);
        os_free(sm);
 }
index b95a285..6e87475 100644 (file)
@@ -226,6 +226,15 @@ struct eapol_callbacks {
         */
        void (*notify_cert)(void *ctx, int depth, const char *subject,
                            const char *cert_hash, const struct wpabuf *cert);
+
+       /**
+        * notify_status - Notification of the current EAP state
+        * @ctx: eapol_ctx from eap_peer_sm_init() call
+        * @status: Step in the process of EAP authentication
+        * @parameter: Step-specific parameter, e.g., EAP method name
+        */
+       void (*notify_status)(void *ctx, const char *status,
+                             const char *parameter);
 };
 
 /**
index 7e37e44..1cec4d8 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * EAP peer method: EAP-AKA (RFC 4187) and EAP-AKA' (draft-arkko-eap-aka-kdf)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * EAP peer method: EAP-AKA (RFC 4187) and EAP-AKA' (RFC 5448)
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -229,19 +229,19 @@ static int eap_aka_umts_auth(struct eap_sm *sm, struct eap_aka_data *data)
 
 static void eap_aka_clear_identities(struct eap_aka_data *data, int id)
 {
-       if (id & CLEAR_PSEUDONYM) {
+       if ((id & CLEAR_PSEUDONYM) && data->pseudonym) {
                wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old pseudonym");
                os_free(data->pseudonym);
                data->pseudonym = NULL;
                data->pseudonym_len = 0;
        }
-       if (id & CLEAR_REAUTH_ID) {
+       if ((id & CLEAR_REAUTH_ID) && data->reauth_id) {
                wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old reauth_id");
                os_free(data->reauth_id);
                data->reauth_id = NULL;
                data->reauth_id_len = 0;
        }
-       if (id & CLEAR_EAP_ID) {
+       if ((id & CLEAR_EAP_ID) && data->last_eap_identity) {
                wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old eap_id");
                os_free(data->last_eap_identity);
                data->last_eap_identity = NULL;
index 06d6db6..3318b81 100644 (file)
@@ -317,6 +317,7 @@ struct eap_sm {
        void *msg_ctx;
        void *scard_ctx;
        void *ssl_ctx;
+       void *ssl_ctx2;
 
        unsigned int workaround;
 
index 37e9234..267d0a5 100644 (file)
@@ -9,6 +9,7 @@
 #include "includes.h"
 
 #include "common.h"
+#include "crypto/sha256.h"
 #include "eap_peer/eap_i.h"
 #include "eap_common/eap_pwd_common.h"
 
@@ -459,10 +460,10 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
                                 const u8 *payload, size_t payload_len)
 {
        BIGNUM *x = NULL, *y = NULL;
-       HMAC_CTX ctx;
+       struct crypto_hash *hash;
        u32 cs;
        u16 grp;
-       u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr;
+       u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
        int offset;
 
        /*
@@ -489,7 +490,9 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
         * server's commit is H(k | server_element | server_scalar |
         *                      peer_element | peer_scalar | ciphersuite)
         */
-       H_Init(&ctx);
+       hash = eap_pwd_h_init();
+       if (hash == NULL)
+               goto fin;
 
        /*
         * zero the memory each time because this is mod prime math and some
@@ -498,7 +501,7 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
        os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
        offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
        BN_bn2bin(data->k, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
 
        /* server element: x, y */
        if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
@@ -511,18 +514,18 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
        os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
        offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
        BN_bn2bin(x, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
        os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
        offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
        BN_bn2bin(y, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
 
        /* server scalar */
        os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
        offset = BN_num_bytes(data->grp->order) -
                BN_num_bytes(data->server_scalar);
        BN_bn2bin(data->server_scalar, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
 
        /* my element: x, y */
        if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
@@ -536,27 +539,27 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
        os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
        offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
        BN_bn2bin(x, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
        os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
        offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
        BN_bn2bin(y, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
 
        /* my scalar */
        os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
        offset = BN_num_bytes(data->grp->order) -
                BN_num_bytes(data->my_scalar);
        BN_bn2bin(data->my_scalar, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
 
        /* the ciphersuite */
-       H_Update(&ctx, (u8 *) &cs, sizeof(u32));
+       eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
 
        /* random function fin */
-       H_Final(&ctx, conf);
+       eap_pwd_h_final(hash, conf);
 
        ptr = (u8 *) payload;
-       if (os_memcmp(conf, ptr, SHA256_DIGEST_LENGTH)) {
+       if (os_memcmp(conf, ptr, SHA256_MAC_LEN)) {
                wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm did not verify");
                goto fin;
        }
@@ -568,13 +571,15 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
         *  H(k | peer_element | peer_scalar | server_element | server_scalar |
         *    ciphersuite)
         */
-       H_Init(&ctx);
+       hash = eap_pwd_h_init();
+       if (hash == NULL)
+               goto fin;
 
        /* k */
        os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
        offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
        BN_bn2bin(data->k, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
 
        /* my element */
        if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
@@ -587,18 +592,18 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
        os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
        offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
        BN_bn2bin(x, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
        os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
        offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
        BN_bn2bin(y, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
 
        /* my scalar */
        os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
        offset = BN_num_bytes(data->grp->order) -
                BN_num_bytes(data->my_scalar);
        BN_bn2bin(data->my_scalar, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
 
        /* server element: x, y */
        if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
@@ -611,24 +616,24 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
        os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
        offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
        BN_bn2bin(x, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
        os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
        offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
        BN_bn2bin(y, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
 
        /* server scalar */
        os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
        offset = BN_num_bytes(data->grp->order) -
                BN_num_bytes(data->server_scalar);
        BN_bn2bin(data->server_scalar, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
 
        /* the ciphersuite */
-       H_Update(&ctx, (u8 *) &cs, sizeof(u32));
+       eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
 
        /* all done */
-       H_Final(&ctx, conf);
+       eap_pwd_h_final(hash, conf);
 
        if (compute_keys(data->grp, data->bnctx, data->k,
                         data->my_scalar, data->server_scalar, conf, ptr,
@@ -638,11 +643,11 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
                goto fin;
        }
 
-       data->outbuf = wpabuf_alloc(SHA256_DIGEST_LENGTH);
+       data->outbuf = wpabuf_alloc(SHA256_MAC_LEN);
        if (data->outbuf == NULL)
                goto fin;
 
-       wpabuf_put_data(data->outbuf, conf, SHA256_DIGEST_LENGTH);
+       wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);
 
 fin:
        os_free(cruft);
@@ -725,6 +730,7 @@ eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret,
                 */
                if (data->out_frag_pos >= wpabuf_len(data->outbuf)) {
                        wpabuf_free(data->outbuf);
+                       data->outbuf = NULL;
                        data->out_frag_pos = 0;
                }
                wpa_printf(MSG_DEBUG, "EAP-pwd: Send %s fragment of %d bytes",
@@ -856,8 +862,11 @@ eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret,
        /*
         * if we're not fragmenting then there's no need to carry this around
         */
-       if (data->out_frag_pos == 0)
+       if (data->out_frag_pos == 0) {
                wpabuf_free(data->outbuf);
+               data->outbuf = NULL;
+               data->out_frag_pos = 0;
+       }
 
        return resp;
 }
index a3067fa..ed52fb6 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * EAP peer method: EAP-TLS (RFC 2716)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -21,6 +21,7 @@ static void eap_tls_deinit(struct eap_sm *sm, void *priv);
 struct eap_tls_data {
        struct eap_ssl_data ssl;
        u8 *key_data;
+       void *ssl_ctx;
 };
 
 
@@ -40,6 +41,9 @@ static void * eap_tls_init(struct eap_sm *sm)
        if (data == NULL)
                return NULL;
 
+       data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 :
+               sm->ssl_ctx;
+
        if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
                wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
                eap_tls_deinit(sm, data);
@@ -165,7 +169,7 @@ static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,
                return eap_tls_failure(sm, data, ret, res, resp, id);
        }
 
-       if (tls_connection_established(sm->ssl_ctx, data->ssl.conn))
+       if (tls_connection_established(data->ssl_ctx, data->ssl.conn))
                eap_tls_success(sm, data, ret);
 
        if (res == 1) {
@@ -180,7 +184,7 @@ static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,
 static Boolean eap_tls_has_reauth_data(struct eap_sm *sm, void *priv)
 {
        struct eap_tls_data *data = priv;
-       return tls_connection_established(sm->ssl_ctx, data->ssl.conn);
+       return tls_connection_established(data->ssl_ctx, data->ssl.conn);
 }
 
 
index 52549f4..69e83d9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -136,14 +136,14 @@ static int eap_tls_init_connection(struct eap_sm *sm,
 {
        int res;
 
-       data->conn = tls_connection_init(sm->ssl_ctx);
+       data->conn = tls_connection_init(data->ssl_ctx);
        if (data->conn == NULL) {
                wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
                           "connection");
                return -1;
        }
 
-       res = tls_connection_set_params(sm->ssl_ctx, data->conn, params);
+       res = tls_connection_set_params(data->ssl_ctx, data->conn, params);
        if (res == TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED) {
                /*
                 * At this point with the pkcs11 engine the PIN might be wrong.
@@ -162,13 +162,13 @@ static int eap_tls_init_connection(struct eap_sm *sm,
                config->pin = NULL;
                eap_sm_request_pin(sm);
                sm->ignore = TRUE;
-               tls_connection_deinit(sm->ssl_ctx, data->conn);
+               tls_connection_deinit(data->ssl_ctx, data->conn);
                data->conn = NULL;
                return -1;
        } else if (res) {
                wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection "
                           "parameters");
-               tls_connection_deinit(sm->ssl_ctx, data->conn);
+               tls_connection_deinit(data->ssl_ctx, data->conn);
                data->conn = NULL;
                return -1;
        }
@@ -197,6 +197,8 @@ int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
 
        data->eap = sm;
        data->phase2 = sm->init_phase2;
+       data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 :
+               sm->ssl_ctx;
        if (eap_tls_params_from_conf(sm, data, &params, config, data->phase2) <
            0)
                return -1;
@@ -234,7 +236,7 @@ int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
  */
 void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
 {
-       tls_connection_deinit(sm->ssl_ctx, data->conn);
+       tls_connection_deinit(data->ssl_ctx, data->conn);
        eap_peer_tls_reset_input(data);
        eap_peer_tls_reset_output(data);
 }
@@ -265,8 +267,8 @@ u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
                return NULL;
 
        /* First, try to use TLS library function for PRF, if available. */
-       if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len) ==
-           0)
+       if (tls_connection_prf(data->ssl_ctx, data->conn, label, 0, out, len)
+           == 0)
                return out;
 
        /*
@@ -274,7 +276,7 @@ u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
         * session parameters and use an internal implementation of TLS PRF to
         * derive the key.
         */
-       if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
+       if (tls_connection_get_keys(data->ssl_ctx, data->conn, &keys))
                goto fail;
 
        if (keys.client_random == NULL || keys.server_random == NULL ||
@@ -441,14 +443,14 @@ static int eap_tls_process_input(struct eap_sm *sm, struct eap_ssl_data *data,
                WPA_ASSERT(data->tls_out == NULL);
        }
        appl_data = NULL;
-       data->tls_out = tls_connection_handshake(sm->ssl_ctx, data->conn,
+       data->tls_out = tls_connection_handshake(data->ssl_ctx, data->conn,
                                                 msg, &appl_data);
 
        eap_peer_tls_reset_input(data);
 
        if (appl_data &&
-           tls_connection_established(sm->ssl_ctx, data->conn) &&
-           !tls_connection_get_failed(sm->ssl_ctx, data->conn)) {
+           tls_connection_established(data->ssl_ctx, data->conn) &&
+           !tls_connection_get_failed(data->ssl_ctx, data->conn)) {
                wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application data",
                                    appl_data);
                *out_data = appl_data;
@@ -616,7 +618,7 @@ int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
                return -1;
        }
 
-       if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) {
+       if (tls_connection_get_failed(data->ssl_ctx, data->conn)) {
                /* TLS processing has failed - return error */
                wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to "
                           "report error");
@@ -675,7 +677,7 @@ int eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data)
 {
        eap_peer_tls_reset_input(data);
        eap_peer_tls_reset_output(data);
-       return tls_connection_shutdown(sm->ssl_ctx, data->conn);
+       return tls_connection_shutdown(data->ssl_ctx, data->conn);
 }
 
 
@@ -694,7 +696,8 @@ int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data,
        char name[128];
        int len = 0, ret;
 
-       if (tls_get_cipher(sm->ssl_ctx, data->conn, name, sizeof(name)) == 0) {
+       if (tls_get_cipher(data->ssl_ctx, data->conn, name, sizeof(name)) == 0)
+       {
                ret = os_snprintf(buf + len, buflen - len,
                                  "EAP TLS cipher=%s\n", name);
                if (ret < 0 || (size_t) ret >= buflen - len)
@@ -741,7 +744,7 @@ const u8 * eap_peer_tls_process_init(struct eap_sm *sm,
        size_t left;
        unsigned int tls_msg_len;
 
-       if (tls_get_errors(sm->ssl_ctx)) {
+       if (tls_get_errors(data->ssl_ctx)) {
                wpa_printf(MSG_INFO, "SSL: TLS errors detected");
                ret->ignore = TRUE;
                return NULL;
@@ -849,7 +852,7 @@ int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data,
        if (msg == NULL)
                return need_more_input ? 1 : -1;
 
-       *in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->conn, msg);
+       *in_decrypted = tls_connection_decrypt(data->ssl_ctx, data->conn, msg);
        eap_peer_tls_reset_input(data);
        if (*in_decrypted == NULL) {
                wpa_printf(MSG_INFO, "SSL: Failed to decrypt Phase 2 data");
@@ -877,8 +880,8 @@ int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data,
 {
        if (in_data) {
                eap_peer_tls_reset_output(data);
-               data->tls_out = tls_connection_encrypt(sm->ssl_ctx, data->conn,
-                                                      in_data);
+               data->tls_out = tls_connection_encrypt(data->ssl_ctx,
+                                                      data->conn, in_data);
                if (data->tls_out == NULL) {
                        wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 "
                                   "data (in_len=%lu)",
index 7426467..771385b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2009, 2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -63,6 +63,11 @@ struct eap_ssl_data {
         * eap - EAP state machine allocated with eap_peer_sm_init()
         */
        struct eap_sm *eap;
+
+       /**
+        * ssl_ctx - TLS library context to use for the connection
+        */
+       void *ssl_ctx;
 };
 
 
index 0204ba2..e09f5e5 100644 (file)
@@ -435,7 +435,6 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
                           "implicit challenge");
                return -1;
        }
-       peer_challenge = challenge + 1 + EAP_TTLS_MSCHAPV2_CHALLENGE_LEN;
 
        pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE,
                               RADIUS_VENDOR_ID_MICROSOFT, 1,
@@ -448,7 +447,14 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
        data->ident = challenge[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN];
        *pos++ = data->ident;
        *pos++ = 0; /* Flags */
-       os_memcpy(pos, peer_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN);
+       if (os_get_random(pos, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN) < 0) {
+               os_free(challenge);
+               wpabuf_free(msg);
+               wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to get "
+                          "random data for peer challenge");
+               return -1;
+       }
+       peer_challenge = pos;
        pos += EAP_TTLS_MSCHAPV2_CHALLENGE_LEN;
        os_memset(pos, 0, 8); /* Reserved, must be zero */
        pos += 8;
@@ -456,6 +462,7 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
                                     password_len, pwhash, challenge,
                                     peer_challenge, pos, data->auth_response,
                                     data->master_key)) {
+               os_free(challenge);
                wpabuf_free(msg);
                wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive "
                           "response");
index 4473b90..d007a57 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * EAP-WSC peer for Wi-Fi Protected Setup
- * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2009, 2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -137,6 +137,8 @@ static void * eap_wsc_init(struct eap_sm *sm)
        struct wps_context *wps;
        struct wps_credential new_ap_settings;
        int res;
+       u8 dev_pw[WPS_OOB_DEVICE_PASSWORD_LEN];
+       int nfc = 0;
 
        wps = sm->wps;
        if (wps == NULL) {
@@ -184,13 +186,26 @@ static void * eap_wsc_init(struct eap_sm *sm)
                while (*pos != '\0' && *pos != ' ')
                        pos++;
                cfg.pin_len = pos - (const char *) cfg.pin;
+               if (cfg.pin_len >= WPS_OOB_DEVICE_PASSWORD_MIN_LEN * 2 &&
+                   cfg.pin_len <= WPS_OOB_DEVICE_PASSWORD_LEN * 2 &&
+                   hexstr2bin((const char *) cfg.pin, dev_pw,
+                              cfg.pin_len / 2) == 0) {
+                       /* Convert OOB Device Password to binary */
+                       cfg.pin = dev_pw;
+                       cfg.pin_len /= 2;
+               }
+               if (cfg.pin_len == 6 && os_strncmp(pos, "nfc-pw", 6) == 0) {
+                       cfg.pin = NULL;
+                       cfg.pin_len = 0;
+                       nfc = 1;
+               }
        } else {
                pos = os_strstr(phase1, "pbc=1");
                if (pos)
                        cfg.pbc = 1;
        }
 
-       if (cfg.pin == NULL && !cfg.pbc) {
+       if (cfg.pin == NULL && !cfg.pbc && !nfc) {
                wpa_printf(MSG_INFO, "EAP-WSC: PIN or PBC not set in phase1 "
                           "configuration data");
                os_free(data);
index 135c02b..9cd5509 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * hostapd / EAP-AKA (RFC 4187) and EAP-AKA' (draft-arkko-eap-aka-kdf)
- * Copyright (c) 2005-2008, Jouni Malinen <j@w1.fi>
+ * hostapd / EAP-AKA (RFC 4187) and EAP-AKA' (RFC 5448)
+ * Copyright (c) 2005-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -266,8 +266,18 @@ static struct wpabuf * eap_aka_build_identity(struct eap_sm *sm,
                               EAP_AKA_SUBTYPE_IDENTITY);
        if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
                                      sm->identity_len)) {
-               wpa_printf(MSG_DEBUG, "   AT_PERMANENT_ID_REQ");
-               eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
+               if (sm->identity_len > 0 &&
+                   (sm->identity[0] == EAP_AKA_REAUTH_ID_PREFIX ||
+                    sm->identity[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX)) {
+                       /* Reauth id may have expired - try fullauth */
+                       wpa_printf(MSG_DEBUG, "   AT_FULLAUTH_ID_REQ");
+                       eap_sim_msg_add(msg, EAP_SIM_AT_FULLAUTH_ID_REQ, 0,
+                                       NULL, 0);
+               } else {
+                       wpa_printf(MSG_DEBUG, "   AT_PERMANENT_ID_REQ");
+                       eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0,
+                                       NULL, 0);
+               }
        } else {
                /*
                 * RFC 4187, Chap. 4.1.4 recommends that identity from EAP is
@@ -292,12 +302,23 @@ static int eap_aka_build_encr(struct eap_sm *sm, struct eap_aka_data *data,
                              const u8 *nonce_s)
 {
        os_free(data->next_pseudonym);
-       data->next_pseudonym =
-               eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 1);
+       if (nonce_s == NULL) {
+               data->next_pseudonym =
+                       eap_sim_db_get_next_pseudonym(
+                               sm->eap_sim_db_priv,
+                               data->eap_method == EAP_TYPE_AKA_PRIME ?
+                               EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA);
+       } else {
+               /* Do not update pseudonym during re-authentication */
+               data->next_pseudonym = NULL;
+       }
        os_free(data->next_reauth_id);
        if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) {
                data->next_reauth_id =
-                       eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, 1);
+                       eap_sim_db_get_next_reauth_id(
+                               sm->eap_sim_db_priv,
+                               data->eap_method == EAP_TYPE_AKA_PRIME ?
+                               EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA);
        } else {
                wpa_printf(MSG_DEBUG, "EAP-AKA: Max fast re-authentication "
                           "count exceeded - force full authentication");
@@ -615,7 +636,8 @@ static void eap_aka_determine_identity(struct eap_sm *sm,
                identity = data->reauth->identity;
                identity_len = data->reauth->identity_len;
        } else if (sm->identity && sm->identity_len > 0 &&
-                  sm->identity[0] == EAP_AKA_PERMANENT_PREFIX) {
+                  (sm->identity[0] == EAP_AKA_PERMANENT_PREFIX ||
+                   sm->identity[0] == EAP_AKA_PRIME_PERMANENT_PREFIX)) {
                identity = sm->identity;
                identity_len = sm->identity_len;
        } else {
@@ -731,7 +753,7 @@ static void eap_aka_determine_identity(struct eap_sm *sm,
                          sm->identity, identity_len);
 
        if (data->eap_method == EAP_TYPE_AKA_PRIME) {
-               eap_aka_prime_derive_keys(identity, identity_len, data->ik,
+               eap_aka_prime_derive_keys(sm->identity, identity_len, data->ik,
                                          data->ck, data->k_encr, data->k_aut,
                                          data->k_re, data->msk, data->emsk);
        } else {
@@ -1017,11 +1039,6 @@ static void eap_aka_process_reauth(struct eap_sm *sm,
                identity_len = id2_len;
        }
 
-       if (data->next_pseudonym) {
-               eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
-                                        identity_len, data->next_pseudonym);
-               data->next_pseudonym = NULL;
-       }
        if (data->next_reauth_id) {
                if (data->eap_method == EAP_TYPE_AKA_PRIME) {
 #ifdef EAP_SERVER_AKA_PRIME
index 6c47dee..b61061b 100644 (file)
@@ -9,6 +9,7 @@
 #include "includes.h"
 
 #include "common.h"
+#include "crypto/sha256.h"
 #include "eap_server/eap_i.h"
 #include "eap_common/eap_pwd_common.h"
 
@@ -40,7 +41,7 @@ struct eap_pwd_data {
        EC_POINT *my_element;
        EC_POINT *peer_element;
 
-       u8 my_confirm[SHA256_DIGEST_LENGTH];
+       u8 my_confirm[SHA256_MAC_LEN];
 
        u8 msk[EAP_MSK_LEN];
        u8 emsk[EAP_EMSK_LEN];
@@ -288,8 +289,8 @@ static void eap_pwd_build_confirm_req(struct eap_sm *sm,
                                      struct eap_pwd_data *data, u8 id)
 {
        BIGNUM *x = NULL, *y = NULL;
-       HMAC_CTX ctx;
-       u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr;
+       struct crypto_hash *hash;
+       u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
        u16 grp;
        int offset;
 
@@ -313,7 +314,9 @@ static void eap_pwd_build_confirm_req(struct eap_sm *sm,
         * commit is H(k | server_element | server_scalar | peer_element |
         *             peer_scalar | ciphersuite)
         */
-       H_Init(&ctx);
+       hash = eap_pwd_h_init();
+       if (hash == NULL)
+               goto fin;
 
        /*
         * Zero the memory each time because this is mod prime math and some
@@ -324,7 +327,7 @@ static void eap_pwd_build_confirm_req(struct eap_sm *sm,
        os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
        offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
        BN_bn2bin(data->k, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
 
        /* server element: x, y */
        if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
@@ -338,18 +341,18 @@ static void eap_pwd_build_confirm_req(struct eap_sm *sm,
        os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
        offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
        BN_bn2bin(x, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
        os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
        offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
        BN_bn2bin(y, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
 
        /* server scalar */
        os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
        offset = BN_num_bytes(data->grp->order) -
                BN_num_bytes(data->my_scalar);
        BN_bn2bin(data->my_scalar, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
 
        /* peer element: x, y */
        if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
@@ -363,18 +366,18 @@ static void eap_pwd_build_confirm_req(struct eap_sm *sm,
        os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
        offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
        BN_bn2bin(x, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
        os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
        offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
        BN_bn2bin(y, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
 
        /* peer scalar */
        os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
        offset = BN_num_bytes(data->grp->order) -
                BN_num_bytes(data->peer_scalar);
        BN_bn2bin(data->peer_scalar, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
 
        /* ciphersuite */
        grp = htons(data->group_num);
@@ -386,17 +389,17 @@ static void eap_pwd_build_confirm_req(struct eap_sm *sm,
        ptr += sizeof(u8);
        *ptr = EAP_PWD_DEFAULT_PRF;
        ptr += sizeof(u8);
-       H_Update(&ctx, cruft, ptr-cruft);
+       eap_pwd_h_update(hash, cruft, ptr - cruft);
 
        /* all done with the random function */
-       H_Final(&ctx, conf);
-       os_memcpy(data->my_confirm, conf, SHA256_DIGEST_LENGTH);
+       eap_pwd_h_final(hash, conf);
+       os_memcpy(data->my_confirm, conf, SHA256_MAC_LEN);
 
-       data->outbuf = wpabuf_alloc(SHA256_DIGEST_LENGTH);
+       data->outbuf = wpabuf_alloc(SHA256_MAC_LEN);
        if (data->outbuf == NULL)
                goto fin;
 
-       wpabuf_put_data(data->outbuf, conf, SHA256_DIGEST_LENGTH);
+       wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);
 
 fin:
        os_free(cruft);
@@ -404,8 +407,6 @@ fin:
        BN_free(y);
        if (data->outbuf == NULL)
                eap_pwd_state(data, FAILURE);
-
-       return;
 }
 
 
@@ -735,10 +736,10 @@ eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
                             const u8 *payload, size_t payload_len)
 {
        BIGNUM *x = NULL, *y = NULL;
-       HMAC_CTX ctx;
+       struct crypto_hash *hash;
        u32 cs;
        u16 grp;
-       u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr;
+       u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
        int offset;
 
        /* build up the ciphersuite: group | random_function | prf */
@@ -761,13 +762,15 @@ eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
         * commit is H(k | peer_element | peer_scalar | server_element |
         *             server_scalar | ciphersuite)
         */
-       H_Init(&ctx);
+       hash = eap_pwd_h_init();
+       if (hash == NULL)
+               goto fin;
 
        /* k */
        os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
        offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
        BN_bn2bin(data->k, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
 
        /* peer element: x, y */
        if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
@@ -780,18 +783,18 @@ eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
        os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
        offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
        BN_bn2bin(x, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
        os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
        offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
        BN_bn2bin(y, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
 
        /* peer scalar */
        os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
        offset = BN_num_bytes(data->grp->order) -
                BN_num_bytes(data->peer_scalar);
        BN_bn2bin(data->peer_scalar, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
 
        /* server element: x, y */
        if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
@@ -805,28 +808,28 @@ eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
        os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
        offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
        BN_bn2bin(x, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
        os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
        offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
        BN_bn2bin(y, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
 
        /* server scalar */
        os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
        offset = BN_num_bytes(data->grp->order) -
                BN_num_bytes(data->my_scalar);
        BN_bn2bin(data->my_scalar, cruft + offset);
-       H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
+       eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
 
        /* ciphersuite */
        os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-       H_Update(&ctx, (u8 *)&cs, sizeof(u32));
+       eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
 
        /* all done */
-       H_Final(&ctx, conf);
+       eap_pwd_h_final(hash, conf);
 
        ptr = (u8 *) payload;
-       if (os_memcmp(conf, ptr, SHA256_DIGEST_LENGTH)) {
+       if (os_memcmp(conf, ptr, SHA256_MAC_LEN)) {
                wpa_printf(MSG_INFO, "EAP-PWD (server): confirm did not "
                           "verify");
                goto fin;
index f49f70e..6658d9c 100644 (file)
@@ -107,8 +107,17 @@ static struct wpabuf * eap_sim_build_start(struct eap_sm *sm,
                               EAP_SIM_SUBTYPE_START);
        if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
                                      sm->identity_len)) {
-               wpa_printf(MSG_DEBUG, "   AT_PERMANENT_ID_REQ");
-               eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
+               if (sm->identity_len > 0 &&
+                   sm->identity[0] == EAP_SIM_REAUTH_ID_PREFIX) {
+                       /* Reauth id may have expired - try fullauth */
+                       wpa_printf(MSG_DEBUG, "   AT_FULLAUTH_ID_REQ");
+                       eap_sim_msg_add(msg, EAP_SIM_AT_FULLAUTH_ID_REQ, 0,
+                                       NULL, 0);
+               } else {
+                       wpa_printf(MSG_DEBUG, "   AT_PERMANENT_ID_REQ");
+                       eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0,
+                                       NULL, 0);
+               }
        } else {
                /*
                 * RFC 4186, Chap. 4.2.4 recommends that identity from EAP is
@@ -131,12 +140,19 @@ static int eap_sim_build_encr(struct eap_sm *sm, struct eap_sim_data *data,
                              const u8 *nonce_s)
 {
        os_free(data->next_pseudonym);
-       data->next_pseudonym =
-               eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 0);
+       if (nonce_s == NULL) {
+               data->next_pseudonym =
+                       eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv,
+                                                     EAP_SIM_DB_SIM);
+       } else {
+               /* Do not update pseudonym during re-authentication */
+               data->next_pseudonym = NULL;
+       }
        os_free(data->next_reauth_id);
        if (data->counter <= EAP_SIM_MAX_FAST_REAUTHS) {
                data->next_reauth_id =
-                       eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, 0);
+                       eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv,
+                                                     EAP_SIM_DB_SIM);
        } else {
                wpa_printf(MSG_DEBUG, "EAP-SIM: Max fast re-authentication "
                           "count exceeded - force full authentication");
@@ -616,11 +632,6 @@ static void eap_sim_process_reauth(struct eap_sm *sm,
                identity_len = id2_len;
        }
 
-       if (data->next_pseudonym) {
-               eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
-                                        identity_len, data->next_pseudonym);
-               data->next_pseudonym = NULL;
-       }
        if (data->next_reauth_id) {
                eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
                                      identity_len, data->next_reauth_id,
index 9db26dc..ce3238c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / EAP-SIM database/authenticator gateway
- * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2010, 2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -647,7 +647,8 @@ eap_sim_db_get_pseudonym(struct eap_sim_db_data *data, const u8 *identity,
 
        if (identity_len == 0 ||
            (identity[0] != EAP_SIM_PSEUDONYM_PREFIX &&
-            identity[0] != EAP_AKA_PSEUDONYM_PREFIX))
+            identity[0] != EAP_AKA_PSEUDONYM_PREFIX &&
+            identity[0] != EAP_AKA_PRIME_PSEUDONYM_PREFIX))
                return NULL;
 
        /* Remove possible realm from identity */
@@ -685,7 +686,8 @@ eap_sim_db_get_pseudonym_id(struct eap_sim_db_data *data, const u8 *identity,
 
        if (identity_len == 0 ||
            (identity[0] != EAP_SIM_PERMANENT_PREFIX &&
-            identity[0] != EAP_AKA_PERMANENT_PREFIX))
+            identity[0] != EAP_AKA_PERMANENT_PREFIX &&
+            identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX))
                return NULL;
 
        p = data->pseudonyms;
@@ -710,7 +712,8 @@ eap_sim_db_get_reauth(struct eap_sim_db_data *data, const u8 *identity,
 
        if (identity_len == 0 ||
            (identity[0] != EAP_SIM_REAUTH_ID_PREFIX &&
-            identity[0] != EAP_AKA_REAUTH_ID_PREFIX))
+            identity[0] != EAP_AKA_REAUTH_ID_PREFIX &&
+            identity[0] != EAP_AKA_PRIME_REAUTH_ID_PREFIX))
                return NULL;
 
        /* Remove possible realm from identity */
@@ -777,8 +780,9 @@ eap_sim_db_get_reauth_id(struct eap_sim_db_data *data, const u8 *identity,
  * @identity_len: Length of identity in bytes 
  * Returns: 0 if the user is found or -1 on failure
  *
- * In most cases, the user name is ['0','1'] | IMSI, i.e., 1 followed by the
- * IMSI in ASCII format, ['2','3'] | pseudonym, or ['4','5'] | reauth_id.
+ * In most cases, the user name is ['0','1','6'] | IMSI, i.e., 1 followed by
+ * the IMSI in ASCII format for EAP-SIM, ['2','3','7'] | pseudonym, or
+ * ['4','5','7'] | reauth_id.
  */
 int eap_sim_db_identity_known(void *priv, const u8 *identity,
                              size_t identity_len)
@@ -789,21 +793,24 @@ int eap_sim_db_identity_known(void *priv, const u8 *identity,
                return -1;
 
        if (identity[0] == EAP_SIM_PSEUDONYM_PREFIX ||
-           identity[0] == EAP_AKA_PSEUDONYM_PREFIX) {
+           identity[0] == EAP_AKA_PSEUDONYM_PREFIX ||
+           identity[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) {
                struct eap_sim_pseudonym *p =
                        eap_sim_db_get_pseudonym(data, identity, identity_len);
                return p ? 0 : -1;
        }
 
        if (identity[0] == EAP_SIM_REAUTH_ID_PREFIX ||
-           identity[0] == EAP_AKA_REAUTH_ID_PREFIX) {
+           identity[0] == EAP_AKA_REAUTH_ID_PREFIX ||
+           identity[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX) {
                struct eap_sim_reauth *r =
                        eap_sim_db_get_reauth(data, identity, identity_len);
                return r ? 0 : -1;
        }
 
        if (identity[0] != EAP_SIM_PERMANENT_PREFIX &&
-           identity[0] != EAP_AKA_PERMANENT_PREFIX) {
+           identity[0] != EAP_AKA_PERMANENT_PREFIX &&
+           identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) {
                /* Unknown identity prefix */
                return -1;
        }
@@ -843,7 +850,7 @@ static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix)
 /**
  * eap_sim_db_get_next_pseudonym - EAP-SIM DB: Get next pseudonym
  * @priv: Private data pointer from eap_sim_db_init()
- * @aka: Using EAP-AKA instead of EAP-SIM
+ * @method: EAP method (SIM/AKA/AKA')
  * Returns: Next pseudonym (allocated string) or %NULL on failure
  *
  * This function is used to generate a pseudonym for EAP-SIM. The returned
@@ -851,18 +858,31 @@ static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix)
  * with eap_sim_db_add_pseudonym() once the authentication has been completed
  * successfully. Caller is responsible for freeing the returned buffer.
  */
-char * eap_sim_db_get_next_pseudonym(void *priv, int aka)
+char * eap_sim_db_get_next_pseudonym(void *priv, enum eap_sim_db_method method)
 {
        struct eap_sim_db_data *data = priv;
-       return eap_sim_db_get_next(data, aka ? EAP_AKA_PSEUDONYM_PREFIX :
-                                  EAP_SIM_PSEUDONYM_PREFIX);
+       char prefix = EAP_SIM_REAUTH_ID_PREFIX;
+
+       switch (method) {
+       case EAP_SIM_DB_SIM:
+               prefix = EAP_SIM_PSEUDONYM_PREFIX;
+               break;
+       case EAP_SIM_DB_AKA:
+               prefix = EAP_AKA_PSEUDONYM_PREFIX;
+               break;
+       case EAP_SIM_DB_AKA_PRIME:
+               prefix = EAP_AKA_PRIME_PSEUDONYM_PREFIX;
+               break;
+       }
+
+       return eap_sim_db_get_next(data, prefix);
 }
 
 
 /**
  * eap_sim_db_get_next_reauth_id - EAP-SIM DB: Get next reauth_id
  * @priv: Private data pointer from eap_sim_db_init()
- * @aka: Using EAP-AKA instead of EAP-SIM
+ * @method: EAP method (SIM/AKA/AKA')
  * Returns: Next reauth_id (allocated string) or %NULL on failure
  *
  * This function is used to generate a fast re-authentication identity for
@@ -871,11 +891,24 @@ char * eap_sim_db_get_next_pseudonym(void *priv, int aka)
  * has been completed successfully. Caller is responsible for freeing the
  * returned buffer.
  */
-char * eap_sim_db_get_next_reauth_id(void *priv, int aka)
+char * eap_sim_db_get_next_reauth_id(void *priv, enum eap_sim_db_method method)
 {
        struct eap_sim_db_data *data = priv;
-       return eap_sim_db_get_next(data, aka ? EAP_AKA_REAUTH_ID_PREFIX :
-                                  EAP_SIM_REAUTH_ID_PREFIX);
+       char prefix = EAP_SIM_REAUTH_ID_PREFIX;
+
+       switch (method) {
+       case EAP_SIM_DB_SIM:
+               prefix = EAP_SIM_REAUTH_ID_PREFIX;
+               break;
+       case EAP_SIM_DB_AKA:
+               prefix = EAP_AKA_REAUTH_ID_PREFIX;
+               break;
+       case EAP_SIM_DB_AKA_PRIME:
+               prefix = EAP_AKA_PRIME_REAUTH_ID_PREFIX;
+               break;
+       }
+
+       return eap_sim_db_get_next(data, prefix);
 }
 
 
@@ -1156,7 +1189,7 @@ void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth)
  * called once the results become available.
  *
  * In most cases, the user name is '0' | IMSI, i.e., 0 followed by the IMSI in
- * ASCII format.
+ * ASCII format for EAP-AKA and '6' | IMSI for EAP-AKA'.
  *
  * When using an external server for AKA authentication, this function can
  * always start a request and return EAP_SIM_DB_PENDING immediately if
@@ -1178,7 +1211,8 @@ int eap_sim_db_get_aka_auth(void *priv, const u8 *identity,
        char msg[40];
 
        if (identity_len < 2 || identity == NULL ||
-           identity[0] != EAP_AKA_PERMANENT_PREFIX) {
+           (identity[0] != EAP_AKA_PERMANENT_PREFIX &&
+            identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX)) {
                wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
                                  identity, identity_len);
                return EAP_SIM_DB_FAILURE;
@@ -1281,7 +1315,8 @@ int eap_sim_db_resynchronize(void *priv, const u8 *identity,
        size_t i;
 
        if (identity_len < 2 || identity == NULL ||
-           identity[0] != EAP_AKA_PERMANENT_PREFIX) {
+           (identity[0] != EAP_AKA_PERMANENT_PREFIX &&
+            identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX)) {
                wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
                                  identity, identity_len);
                return -1;
index abe185e..1f6375a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / EAP-SIM database/authenticator gateway
- * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2008, 2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
 #define EAP_AKA_PERMANENT_PREFIX '0'
 #define EAP_AKA_PSEUDONYM_PREFIX '2'
 #define EAP_AKA_REAUTH_ID_PREFIX '4'
+#define EAP_AKA_PRIME_PERMANENT_PREFIX '6'
+#define EAP_AKA_PRIME_PSEUDONYM_PREFIX '7'
+#define EAP_AKA_PRIME_REAUTH_ID_PREFIX '8'
+
+enum eap_sim_db_method {
+       EAP_SIM_DB_SIM,
+       EAP_SIM_DB_AKA,
+       EAP_SIM_DB_AKA_PRIME
+};
 
 void * eap_sim_db_init(const char *config,
                       void (*get_complete_cb)(void *ctx, void *session_ctx),
@@ -36,9 +45,11 @@ int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity,
 int eap_sim_db_identity_known(void *priv, const u8 *identity,
                              size_t identity_len);
 
-char * eap_sim_db_get_next_pseudonym(void *priv, int aka);
+char * eap_sim_db_get_next_pseudonym(void *priv,
+                                    enum eap_sim_db_method method);
 
-char * eap_sim_db_get_next_reauth_id(void *priv, int aka);
+char * eap_sim_db_get_next_reauth_id(void *priv,
+                                    enum eap_sim_db_method method);
 
 int eap_sim_db_add_pseudonym(void *priv, const u8 *identity,
                             size_t identity_len, char *pseudonym);
index d0b7641..d7f893a 100644 (file)
@@ -157,6 +157,7 @@ struct eapol_state_machine {
                              * Authentication server */
        u8 eap_type_supp; /* EAP type of the last EAP packet from Supplicant */
        struct radius_class_data radius_class;
+       struct wpabuf *radius_cui; /* Chargeable-User-Identity */
 
        /* Keys for encrypting and signing EAPOL-Key frames */
        u8 *eapol_key_sign;
index c83709f..f0cae70 100644 (file)
@@ -1847,6 +1847,17 @@ static void eapol_sm_notify_cert(void *ctx, int depth, const char *subject,
                                 cert_hash, cert);
 }
 
+
+static void eapol_sm_notify_status(void *ctx, const char *status,
+                                  const char *parameter)
+{
+       struct eapol_sm *sm = ctx;
+
+       if (sm->ctx->status_cb)
+               sm->ctx->status_cb(sm->ctx->ctx, status, parameter);
+}
+
+
 static struct eapol_callbacks eapol_cb =
 {
        eapol_sm_get_config,
@@ -1859,7 +1870,8 @@ static struct eapol_callbacks eapol_cb =
        eapol_sm_get_config_blob,
        eapol_sm_notify_pending,
        eapol_sm_eap_param_needed,
-       eapol_sm_notify_cert
+       eapol_sm_notify_cert,
+       eapol_sm_notify_status
 };
 
 
index 3260c61..1a20e4b 100644 (file)
@@ -230,6 +230,15 @@ struct eapol_ctx {
         * cert_in_cb - Include server certificates in callback
         */
        int cert_in_cb;
+
+       /**
+        * status_cb - Notification of a change in EAP status
+        * @ctx: Callback context (ctx)
+        * @status: Step in the process of EAP authentication
+        * @parameter: Step-specific parameter, e.g., EAP method name
+        */
+       void (*status_cb)(void *ctx, const char *status,
+                         const char *parameter);
 };
 
 
index e24277c..2e9a04c 100644 (file)
@@ -3,14 +3,8 @@
  * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
  * Copyright (c) 2005, Sam Leffler <sam@errno.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.
  */
 
 #include "includes.h"
index aacd76b..6b117ca 100644 (file)
@@ -173,7 +173,7 @@ struct l2_packet_data * l2_packet_init(
        addr.sun_family = AF_UNIX;
        os_strlcpy(addr.sun_path, l2->own_socket_path, sizeof(addr.sun_path));
        if (bind(l2->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-               perror("bind(PF_UNIX)");
+               perror("l2-pkt-privsep: bind(PF_UNIX)");
                goto fail;
        }
 
index aeeaccb..58ada3b 100644 (file)
@@ -119,7 +119,7 @@ static void p2p_expire_peers(struct p2p_data *p2p)
                        continue;
 #endif
 
-               wpa_msg(p2p->cfg->msg_ctx, MSG_ERROR, "P2P: Expiring old peer "
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Expiring old peer "
                        "entry " MACSTR, MAC2STR(dev->info.p2p_device_addr));
 #ifdef ANDROID_P2P
                /* SD_FAIR_POLICY: Update the current sd_dev_list pointer to next device */
@@ -193,14 +193,14 @@ u16 p2p_get_provisioning_info(struct p2p_data *p2p, const u8 *addr)
 }
 
 
-void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *iface_addr)
+void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *addr)
 {
        struct p2p_device *dev = NULL;
 
-       if (!iface_addr || !p2p)
+       if (!addr || !p2p)
                return;
 
-       dev = p2p_get_device_interface(p2p, iface_addr);
+       dev = p2p_get_device(p2p, addr);
        if (dev)
                dev->wps_prov_info = 0;
 }
@@ -315,7 +315,7 @@ int p2p_listen(struct p2p_data *p2p, unsigned int timeout)
        p2p->pending_listen_usec = (timeout % 1000) * 1000;
 
        if (p2p->p2p_scan_running) {
-               if (p2p->start_after_scan == P2P_AFTER_SCAN_NOTHING) {
+               if (p2p->start_after_scan == P2P_AFTER_SCAN_CONNECT) {
                        wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
                                "P2P: p2p_scan running - connect is already "
                                "pending - skip listen");
@@ -484,13 +484,25 @@ static int p2p_add_group_clients(struct p2p_data *p2p, const u8 *go_dev_addr,
                        continue; /* ignore our own entry */
                dev = p2p_get_device(p2p, cli->p2p_device_addr);
                if (dev) {
-                       /*
-                        * Update information only if we have not received this
-                        * directly from the client.
-                        */
                        if (dev->flags & (P2P_DEV_GROUP_CLIENT_ONLY |
-                                         P2P_DEV_PROBE_REQ_ONLY))
+                                         P2P_DEV_PROBE_REQ_ONLY)) {
+                               /*
+                                * Update information since we have not
+                                * received this directly from the client.
+                                */
                                p2p_copy_client_info(dev, cli);
+                       } else {
+                               /*
+                                * Need to update P2P Client Discoverability
+                                * flag since it is valid only in P2P Group
+                                * Info attribute.
+                                */
+                               dev->info.dev_capab &=
+                                       ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
+                               dev->info.dev_capab |=
+                                       cli->dev_capab &
+                                       P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
+                       }
                        if (dev->flags & P2P_DEV_PROBE_REQ_ONLY) {
                                dev->flags &= ~P2P_DEV_PROBE_REQ_ONLY;
                        }
@@ -573,7 +585,13 @@ static void p2p_copy_wps_info(struct p2p_device *dev, int probe_req,
        }
 
        if (msg->capability) {
-               dev->info.dev_capab = msg->capability[0];
+               /*
+                * P2P Client Discoverability bit is reserved in all frames
+                * that use this function, so do not change its value here.
+                */
+               dev->info.dev_capab &= P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
+               dev->info.dev_capab |= msg->capability[0] &
+                       ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
                dev->info.group_capab = msg->capability[1];
        }
 
@@ -582,6 +600,7 @@ static void p2p_copy_wps_info(struct p2p_device *dev, int probe_req,
                dev->ext_listen_interval =
                        WPA_GET_LE16(msg->ext_listen_timing + 2);
        }
+
        if (!probe_req) {
                dev->info.config_methods = msg->config_methods ?
                        msg->config_methods : msg->wps_config_methods;
@@ -590,7 +609,7 @@ static void p2p_copy_wps_info(struct p2p_device *dev, int probe_req,
 
 
 /**
- * p2p_add_device - Add peer entries based on scan results
+ * p2p_add_device - Add peer entries based on scan results or P2P frames
  * @p2p: P2P module context from p2p_init()
  * @addr: Source address of Beacon or Probe Response frame (may be either
  *     P2P Device Address or P2P Interface Address)
@@ -598,6 +617,7 @@ static void p2p_copy_wps_info(struct p2p_device *dev, int probe_req,
  * @freq: Frequency on which the Beacon or Probe Response frame was received
  * @ies: IEs from the Beacon or Probe Response frame
  * @ies_len: Length of ies buffer in octets
+ * @scan_res: Whether this was based on scan results
  * Returns: 0 on success, -1 on failure
  *
  * If the scan result is for a GO, the clients in the group will also be added
@@ -606,7 +626,7 @@ static void p2p_copy_wps_info(struct p2p_device *dev, int probe_req,
  * Info attributes.
  */
 int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level,
-                  const u8 *ies, size_t ies_len)
+                  const u8 *ies, size_t ies_len, int scan_res)
 {
        struct p2p_device *dev;
        struct p2p_message msg;
@@ -675,16 +695,18 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level,
                }
        }
 
-       if (dev->listen_freq && dev->listen_freq != freq) {
+       if (dev->listen_freq && dev->listen_freq != freq && scan_res) {
                wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
                        "P2P: Update Listen frequency based on scan "
                        "results (" MACSTR " %d -> %d MHz (DS param %d)",
                        MAC2STR(dev->info.p2p_device_addr), dev->listen_freq,
                        freq, msg.ds_params ? *msg.ds_params : -1);
        }
-       dev->listen_freq = freq;
-       if (msg.group_info)
-               dev->oper_freq = freq;
+       if (scan_res) {
+               dev->listen_freq = freq;
+               if (msg.group_info)
+                       dev->oper_freq = freq;
+       }
        dev->info.level = level;
 
        p2p_copy_wps_info(dev, 0, &msg);
@@ -703,8 +725,10 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level,
                        break;
        }
 
-       p2p_add_group_clients(p2p, p2p_dev_addr, addr, freq, msg.group_info,
-                             msg.group_info_len);
+       if (scan_res) {
+               p2p_add_group_clients(p2p, p2p_dev_addr, addr, freq,
+                                     msg.group_info, msg.group_info_len);
+       }
 
        p2p_parse_free(&msg);
 
@@ -821,6 +845,7 @@ static void p2p_search(struct p2p_data *p2p)
 {
        int freq = 0;
        enum p2p_scan_type type;
+       u16 pw_id = DEV_PW_DEFAULT;
 
        if (p2p->drv_in_listen) {
                wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Driver is still "
@@ -830,30 +855,8 @@ static void p2p_search(struct p2p_data *p2p)
        }
        p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
 
-       if (p2p->go_neg_peer) {
-               /*
-                * Only scan the known listen frequency of the peer
-                * during GO Negotiation start.
-                */
-               freq = p2p->go_neg_peer->listen_freq;
-               if (freq <= 0)
-                       freq = p2p->go_neg_peer->oper_freq;
-               type = P2P_SCAN_SPECIFIC;
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting search "
-                       "for freq %u (GO Neg)", freq);
-       } else if (p2p->invite_peer) {
-               /*
-                * Only scan the known listen frequency of the peer
-                * during Invite start.
-                */
-               freq = p2p->invite_peer->listen_freq;
-               if (freq <= 0)
-                       freq = p2p->invite_peer->oper_freq;
-               type = P2P_SCAN_SPECIFIC;
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting search "
-                       "for freq %u (Invite)", freq);
-       } else if (p2p->find_type == P2P_FIND_PROGRESSIVE &&
-                  (freq = p2p_get_next_prog_freq(p2p)) > 0) {
+       if (p2p->find_type == P2P_FIND_PROGRESSIVE &&
+           (freq = p2p_get_next_prog_freq(p2p)) > 0) {
                type = P2P_SCAN_SOCIAL_PLUS_ONE;
                wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting search "
                        "(+ freq %u)", freq);
@@ -864,7 +867,7 @@ static void p2p_search(struct p2p_data *p2p)
 
        if (p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, type, freq,
                               p2p->num_req_dev_types, p2p->req_dev_types,
-                              p2p->find_dev_id)) {
+                              p2p->find_dev_id, pw_id)) {
                wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
                        "P2P: Scan request failed");
                p2p_continue_find(p2p);
@@ -1016,12 +1019,14 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
        case P2P_FIND_PROGRESSIVE:
                res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_FULL, 0,
                                         p2p->num_req_dev_types,
-                                        p2p->req_dev_types, dev_id);
+                                        p2p->req_dev_types, dev_id,
+                                        DEV_PW_DEFAULT);
                break;
        case P2P_FIND_ONLY_SOCIAL:
                res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_SOCIAL, 0,
                                         p2p->num_req_dev_types,
-                                        p2p->req_dev_types, dev_id);
+                                        p2p->req_dev_types, dev_id,
+                                        DEV_PW_DEFAULT);
                break;
        default:
                return -1;
@@ -1090,11 +1095,21 @@ void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq)
        p2p->go_neg_peer = NULL;
        p2p->sd_peer = NULL;
        p2p->invite_peer = NULL;
+       p2p_stop_listen_for_freq(p2p, freq);
+}
+
+
+void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq)
+{
        if (freq > 0 && p2p->drv_in_listen == freq && p2p->in_listen) {
                wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Skip stop_listen "
                        "since we are on correct channel for response");
                return;
        }
+       if (p2p->in_listen) {
+               p2p->in_listen = 0;
+               p2p_clear_timeout(p2p);
+       }
        if (p2p->drv_in_listen) {
                /*
                 * The driver may not deliver callback to p2p_listen_end()
@@ -1217,21 +1232,22 @@ static void p2p_set_dev_persistent(struct p2p_device *dev,
 int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
                enum p2p_wps_method wps_method,
                int go_intent, const u8 *own_interface_addr,
-               unsigned int force_freq, int persistent_group)
+               unsigned int force_freq, int persistent_group,
+               const u8 *force_ssid, size_t force_ssid_len,
+               int pd_before_go_neg)
 {
        struct p2p_device *dev;
 
        wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
                "P2P: Request to start group negotiation - peer=" MACSTR
                "  GO Intent=%d  Intended Interface Address=" MACSTR
-               " wps_method=%d persistent_group=%d",
+               " wps_method=%d persistent_group=%d pd_before_go_neg=%d",
                MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr),
-               wps_method, persistent_group);
+               wps_method, persistent_group, pd_before_go_neg);
 
        if (p2p_prepare_channel(p2p, force_freq) < 0)
                return -1;
 
-       p2p->ssid_set = 0;
        dev = p2p_get_device(p2p, peer_addr);
        if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
                wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
@@ -1264,10 +1280,23 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
                 */
        }
 
+       p2p->ssid_set = 0;
+       if (force_ssid) {
+               wpa_hexdump_ascii(MSG_DEBUG, "P2P: Forced SSID",
+                                 force_ssid, force_ssid_len);
+               os_memcpy(p2p->ssid, force_ssid, force_ssid_len);
+               p2p->ssid_len = force_ssid_len;
+               p2p->ssid_set = 1;
+       }
+
        dev->flags &= ~P2P_DEV_NOT_YET_READY;
        dev->flags &= ~P2P_DEV_USER_REJECTED;
        dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE;
        dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM;
+       if (pd_before_go_neg)
+               dev->flags |= P2P_DEV_PD_BEFORE_GO_NEG;
+       else
+               dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG;
        dev->connect_reqs = 0;
        dev->go_neg_req_sent = 0;
        dev->go_state = UNKNOWN_GO;
@@ -1315,7 +1344,8 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
 int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr,
                  enum p2p_wps_method wps_method,
                  int go_intent, const u8 *own_interface_addr,
-                 unsigned int force_freq, int persistent_group)
+                 unsigned int force_freq, int persistent_group,
+                 const u8 *force_ssid, size_t force_ssid_len)
 {
        struct p2p_device *dev;
 
@@ -1337,6 +1367,15 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr,
                return -1;
        }
 
+       p2p->ssid_set = 0;
+       if (force_ssid) {
+               wpa_hexdump_ascii(MSG_DEBUG, "P2P: Forced SSID",
+                                 force_ssid, force_ssid_len);
+               os_memcpy(p2p->ssid, force_ssid, force_ssid_len);
+               p2p->ssid_len = force_ssid_len;
+               p2p->ssid_set = 1;
+       }
+
        dev->flags &= ~P2P_DEV_NOT_YET_READY;
        dev->flags &= ~P2P_DEV_USER_REJECTED;
        dev->go_neg_req_sent = 0;
@@ -1821,16 +1860,23 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p)
 {
        struct wpabuf *buf;
        u8 *len;
+       int pw_id = -1;
 
        buf = wpabuf_alloc(1000);
        if (buf == NULL)
                return NULL;
 
-       p2p_build_wps_ie(p2p, buf, DEV_PW_DEFAULT, 1);
+       if (p2p->go_neg_peer) {
+               /* Advertise immediate availability of WPS credential */
+               pw_id = p2p_wps_method_pw_id(p2p->go_neg_peer->wps_method);
+       }
+
+       p2p_build_wps_ie(p2p, buf, pw_id, 1);
 
        /* P2P IE */
        len = p2p_buf_add_ie_hdr(buf);
-       p2p_buf_add_capability(buf, p2p->dev_capab, 0);
+       p2p_buf_add_capability(buf, p2p->dev_capab &
+                              ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0);
        if (p2p->ext_listen_interval)
                p2p_buf_add_ext_listen_timing(buf, p2p->ext_listen_period,
                                              p2p->ext_listen_interval);
@@ -1874,9 +1920,9 @@ static int supp_rates_11b_only(struct ieee802_11_elems *elems)
 }
 
 
-static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr,
-                           const u8 *dst, const u8 *bssid, const u8 *ie,
-                           size_t ie_len)
+static enum p2p_probe_req_status
+p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
+               const u8 *bssid, const u8 *ie, size_t ie_len)
 {
        struct ieee802_11_elems elems;
        struct wpabuf *buf;
@@ -1886,55 +1932,55 @@ static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr,
 
        if (!p2p->in_listen || !p2p->drv_in_listen) {
                /* not in Listen state - ignore Probe Request */
-               return;
+               return P2P_PREQ_NOT_LISTEN;
        }
 
        if (ieee802_11_parse_elems((u8 *) ie, ie_len, &elems, 0) ==
            ParseFailed) {
                /* Ignore invalid Probe Request frames */
-               return;
+               return P2P_PREQ_MALFORMED;
        }
 
        if (elems.p2p == NULL) {
                /* not a P2P probe - ignore it */
-               return;
+               return P2P_PREQ_NOT_P2P;
        }
 
        if (dst && !is_broadcast_ether_addr(dst) &&
            os_memcmp(dst, p2p->cfg->dev_addr, ETH_ALEN) != 0) {
                /* Not sent to the broadcast address or our P2P Device Address
                 */
-               return;
+               return P2P_PREQ_NOT_PROCESSED;
        }
 
        if (bssid && !is_broadcast_ether_addr(bssid)) {
                /* Not sent to the Wildcard BSSID */
-               return;
+               return P2P_PREQ_NOT_PROCESSED;
        }
 
        if (elems.ssid == NULL || elems.ssid_len != P2P_WILDCARD_SSID_LEN ||
            os_memcmp(elems.ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) !=
            0) {
                /* not using P2P Wildcard SSID - ignore */
-               return;
+               return P2P_PREQ_NOT_PROCESSED;
        }
 
        if (supp_rates_11b_only(&elems)) {
                /* Indicates support for 11b rates only */
-               return;
+               return P2P_PREQ_NOT_P2P;
        }
 
        os_memset(&msg, 0, sizeof(msg));
        if (p2p_parse_ies(ie, ie_len, &msg) < 0) {
                /* Could not parse P2P attributes */
-               return;
+               return P2P_PREQ_NOT_P2P;
        }
 
        if (msg.device_id &&
-           os_memcmp(msg.device_id, p2p->cfg->dev_addr, ETH_ALEN != 0)) {
+           os_memcmp(msg.device_id, p2p->cfg->dev_addr, ETH_ALEN) != 0) {
                /* Device ID did not match */
                p2p_parse_free(&msg);
-               return;
+               return P2P_PREQ_NOT_PROCESSED;
        }
 
        /* Check Requested Device Type match */
@@ -1942,12 +1988,14 @@ static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr,
            !p2p_match_dev_type(p2p, msg.wps_attributes)) {
                /* No match with Requested Device Type */
                p2p_parse_free(&msg);
-               return;
+               return P2P_PREQ_NOT_PROCESSED;
        }
        p2p_parse_free(&msg);
 
-       if (!p2p->cfg->send_probe_resp)
-               return; /* Response generated elsewhere */
+       if (!p2p->cfg->send_probe_resp) {
+               /* Response generated elsewhere */
+               return P2P_PREQ_NOT_PROCESSED;
+       }
 
        wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
                "P2P: Reply to P2P Probe Request in Listen state");
@@ -1960,12 +2008,12 @@ static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr,
         */
        ies = p2p_build_probe_resp_ies(p2p);
        if (ies == NULL)
-               return;
+               return P2P_PREQ_NOT_PROCESSED;
 
        buf = wpabuf_alloc(200 + wpabuf_len(ies));
        if (buf == NULL) {
                wpabuf_free(ies);
-               return;
+               return P2P_PREQ_NOT_PROCESSED;
        }
 
        resp = NULL;
@@ -2008,15 +2056,20 @@ static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr,
        p2p->cfg->send_probe_resp(p2p->cfg->cb_ctx, buf);
 
        wpabuf_free(buf);
+
+       return P2P_PREQ_NOT_PROCESSED;
 }
 
 
-int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
-                    const u8 *bssid, const u8 *ie, size_t ie_len)
+enum p2p_probe_req_status
+p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
+                const u8 *bssid, const u8 *ie, size_t ie_len)
 {
+       enum p2p_probe_req_status res;
+
        p2p_add_dev_from_probe_req(p2p, addr, ie, ie_len);
 
-       p2p_reply_probe(p2p, addr, dst, bssid, ie, ie_len);
+       res = p2p_reply_probe(p2p, addr, dst, bssid, ie, ie_len);
 
        if ((p2p->state == P2P_CONNECT || p2p->state == P2P_CONNECT_LISTEN) &&
            p2p->go_neg_peer &&
@@ -2027,7 +2080,7 @@ int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
                        "P2P: Found GO Negotiation peer - try to start GO "
                        "negotiation from timeout");
                eloop_register_timeout(0, 0, p2p_go_neg_start, p2p, NULL);
-               return 1;
+               return P2P_PREQ_PROCESSED;
        }
 
        if ((p2p->state == P2P_INVITE || p2p->state == P2P_INVITE_LISTEN) &&
@@ -2039,10 +2092,10 @@ int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
                        "P2P: Found Invite peer - try to start Invite from "
                        "timeout");
                eloop_register_timeout(0, 0, p2p_invite_start, p2p, NULL);
-               return 1;
+               return P2P_PREQ_PROCESSED;
        }
 
-       return 0;
+       return res;
 }
 
 
@@ -2156,29 +2209,37 @@ int p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf, char *end)
 }
 
 
-int p2p_parse_dev_addr(const u8 *ies, size_t ies_len, u8 *dev_addr)
+int p2p_parse_dev_addr_in_p2p_ie(struct wpabuf *p2p_ie, u8 *dev_addr)
 {
-       struct wpabuf *p2p_ie;
        struct p2p_message msg;
 
-       p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
-                                            P2P_IE_VENDOR_TYPE);
-       if (p2p_ie == NULL)
-               return -1;
        os_memset(&msg, 0, sizeof(msg));
-       if (p2p_parse_p2p_ie(p2p_ie, &msg)) {
-               wpabuf_free(p2p_ie);
+       if (p2p_parse_p2p_ie(p2p_ie, &msg))
                return -1;
-       }
 
-       if (msg.p2p_device_addr == NULL) {
-               wpabuf_free(p2p_ie);
-               return -1;
+       if (msg.p2p_device_addr) {
+               os_memcpy(dev_addr, msg.p2p_device_addr, ETH_ALEN);
+               return 0;
+       } else if (msg.device_id) {
+               os_memcpy(dev_addr, msg.device_id, ETH_ALEN);
+               return 0;
        }
+       return -1;
+}
 
-       os_memcpy(dev_addr, msg.p2p_device_addr, ETH_ALEN);
+
+int p2p_parse_dev_addr(const u8 *ies, size_t ies_len, u8 *dev_addr)
+{
+       struct wpabuf *p2p_ie;
+       int ret;
+
+       p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
+                                            P2P_IE_VENDOR_TYPE);
+       if (p2p_ie == NULL)
+               return -1;
+       ret = p2p_parse_dev_addr_in_p2p_ie(p2p_ie, dev_addr);
        wpabuf_free(p2p_ie);
-       return 0;
+       return ret;
 }
 
 
@@ -2256,6 +2317,17 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg)
                p2p->cfg->model_number = os_strdup(cfg->model_number);
        if (cfg->serial_number)
                p2p->cfg->serial_number = os_strdup(cfg->serial_number);
+       if (cfg->pref_chan) {
+               p2p->cfg->pref_chan = os_malloc(cfg->num_pref_chan *
+                                               sizeof(struct p2p_channel));
+               if (p2p->cfg->pref_chan) {
+                       os_memcpy(p2p->cfg->pref_chan, cfg->pref_chan,
+                                 cfg->num_pref_chan *
+                                 sizeof(struct p2p_channel));
+               } else
+                       p2p->cfg->num_pref_chan = 0;
+       }
+
 #ifdef ANDROID_P2P
        /* 100ms listen time is too less to receive the response frames in some scenarios
         * increasing min listen time to 200ms.
@@ -2298,6 +2370,7 @@ void p2p_deinit(struct p2p_data *p2p)
        os_free(p2p->cfg->model_name);
        os_free(p2p->cfg->model_number);
        os_free(p2p->cfg->serial_number);
+       os_free(p2p->cfg->pref_chan);
        os_free(p2p->groups);
        wpabuf_free(p2p->sd_resp);
        os_free(p2p->after_scan_tx);
@@ -2309,16 +2382,7 @@ void p2p_deinit(struct p2p_data *p2p)
 void p2p_flush(struct p2p_data *p2p)
 {
        struct p2p_device *dev, *prev;
-       p2p_clear_timeout(p2p);
-#ifdef ANDROID_P2P
-       if (p2p->state == P2P_SEARCH)
-               wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
-                                               P2P_EVENT_FIND_STOPPED);
-#endif
-       p2p_set_state(p2p, P2P_IDLE);
-       p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
-       p2p->go_neg_peer = NULL;
-       eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
+       p2p_stop_find(p2p);
        dl_list_for_each_safe(dev, prev, &p2p->devices, struct p2p_device,
                              list) {
                dl_list_del(&dev->list);
@@ -2671,17 +2735,7 @@ static void p2p_prov_disc_cb(struct p2p_data *p2p, int success)
 int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
                         int level, const u8 *ies, size_t ies_len)
 {
-       p2p_add_device(p2p, bssid, freq, level, ies, ies_len);
-
-       if (p2p->go_neg_peer && p2p->state == P2P_SEARCH &&
-           os_memcmp(p2p->go_neg_peer->info.p2p_device_addr, bssid, ETH_ALEN)
-           == 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-                       "P2P: Found GO Negotiation peer - try to start GO "
-                       "negotiation");
-               p2p_connect_send(p2p, p2p->go_neg_peer);
-               return 1;
-       }
+       p2p_add_device(p2p, bssid, freq, level, ies, ies_len, 1);
 
        return 0;
 }
@@ -2706,7 +2760,8 @@ void p2p_scan_res_handled(struct p2p_data *p2p)
 void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id)
 {
        u8 *len = p2p_buf_add_ie_hdr(ies);
-       p2p_buf_add_capability(ies, p2p->dev_capab, 0);
+       p2p_buf_add_capability(ies, p2p->dev_capab &
+                              ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0);
        if (dev_id)
                p2p_buf_add_device_id(ies, dev_id);
        if (p2p->cfg->reg_class && p2p->cfg->channel)
@@ -2748,19 +2803,14 @@ static void p2p_go_neg_req_cb(struct p2p_data *p2p, int success)
        }
 
        if (success) {
-#ifndef ANDROID_P2P
-               dev->go_neg_req_sent++;
-#endif
                if (dev->flags & P2P_DEV_USER_REJECTED) {
                        p2p_set_state(p2p, P2P_IDLE);
                        return;
                }
-       }
-#ifdef ANDROID_P2P
-       else {
+       } else if (dev->go_neg_req_sent) {
+               /* Cancel the increment from p2p_connect_send() on failure */
                dev->go_neg_req_sent--;
        }
-#endif
 
        if (!success &&
            (dev->info.dev_capab & P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY) &&
@@ -2978,6 +3028,18 @@ int p2p_listen_end(struct p2p_data *p2p, unsigned int freq)
                                "new one");
                        return 1;
                }
+               if (p2p->pending_listen_freq) {
+                       /*
+                        * Better wait a bit if the driver is unable to start
+                        * offchannel operation for some reason. p2p_search()
+                        * will be started from internal timeout.
+                        */
+                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Listen "
+                               "operation did not seem to start - delay "
+                               "search phase to avoid busy loop");
+                       p2p_set_timeout(p2p, 0, 100000);
+                       return 1;
+               }
                p2p_search(p2p);
                return 1;
        }
@@ -2989,6 +3051,14 @@ int p2p_listen_end(struct p2p_data *p2p, unsigned int freq)
 static void p2p_timeout_connect(struct p2p_data *p2p)
 {
        p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+       if (p2p->go_neg_peer &&
+           (p2p->go_neg_peer->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM)) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Wait for GO "
+                       "Negotiation Confirm timed out - assume GO "
+                       "Negotiation failed");
+               p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
+               return;
+       }
        p2p_set_state(p2p, P2P_CONNECT_LISTEN);
        p2p_listen_in_find(p2p);
 }
@@ -3802,6 +3872,28 @@ int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel,
 }
 
 
+int p2p_set_pref_chan(struct p2p_data *p2p, unsigned int num_pref_chan,
+                     const struct p2p_channel *pref_chan)
+{
+       struct p2p_channel *n;
+
+       if (pref_chan) {
+               n = os_malloc(num_pref_chan * sizeof(struct p2p_channel));
+               if (n == NULL)
+                       return -1;
+               os_memcpy(n, pref_chan,
+                         num_pref_chan * sizeof(struct p2p_channel));
+       } else
+               n = NULL;
+
+       os_free(p2p->cfg->pref_chan);
+       p2p->cfg->pref_chan = n;
+       p2p->cfg->num_pref_chan = num_pref_chan;
+
+       return 0;
+}
+
+
 int p2p_get_interface_addr(struct p2p_data *p2p, const u8 *dev_addr,
                           u8 *iface_addr)
 {
index fe98f5e..7006707 100644 (file)
@@ -131,7 +131,6 @@ struct p2p_data;
 enum p2p_scan_type {
        P2P_SCAN_SOCIAL,
        P2P_SCAN_FULL,
-       P2P_SCAN_SPECIFIC,
        P2P_SCAN_SOCIAL_PLUS_ONE
 };
 
@@ -218,6 +217,11 @@ enum p2p_prov_disc_status {
        P2P_PROV_DISC_REJECTED,
 };
 
+struct p2p_channel {
+       u8 op_class;
+       u8 chan;
+};
+
 /**
  * struct p2p_config - P2P configuration
  *
@@ -265,6 +269,16 @@ struct p2p_config {
        struct p2p_channels channels;
 
        /**
+        * num_pref_chan - Number of pref_chan entries
+        */
+       unsigned int num_pref_chan;
+
+       /**
+        * pref_chan - Preferred channels for GO Negotiation
+        */
+       struct p2p_channel *pref_chan;
+
+       /**
         * pri_dev_type - Primary Device Type (see WPS)
         */
        u8 pri_dev_type[8];
@@ -354,14 +368,14 @@ struct p2p_config {
         * @num_req_dev_types: Number of requested device types
         * @req_dev_types: Array containing requested device types
         * @dev_id: Device ID to search for or %NULL to find all devices
+        * @pw_id: Device Password ID
         * Returns: 0 on success, -1 on failure
         *
         * This callback function is used to request a P2P scan or search
         * operation to be completed. Type type argument specifies which type
         * of scan is to be done. @P2P_SCAN_SOCIAL indicates that only the
         * social channels (1, 6, 11) should be scanned. @P2P_SCAN_FULL
-        * indicates that all channels are to be scanned. @P2P_SCAN_SPECIFIC
-        * request a scan of a single channel specified by freq.
+        * indicates that all channels are to be scanned.
         * @P2P_SCAN_SOCIAL_PLUS_ONE request scan of all the social channels
         * plus one extra channel specified by freq.
         *
@@ -377,7 +391,7 @@ struct p2p_config {
         */
        int (*p2p_scan)(void *ctx, enum p2p_scan_type type, int freq,
                        unsigned int num_req_dev_types,
-                       const u8 *req_dev_types, const u8 *dev_id);
+                       const u8 *req_dev_types, const u8 *dev_id, u16 pw_id);
 
        /**
         * send_probe_resp - Transmit a Probe Response frame
@@ -861,12 +875,20 @@ int p2p_listen(struct p2p_data *p2p, unsigned int timeout);
  * @persistent_group: Whether to create a persistent group (0 = no, 1 =
  * persistent group without persistent reconnect, 2 = persistent group with
  * persistent reconnect)
+ * @force_ssid: Forced SSID for the group if we become GO or %NULL to generate
+ *     a new SSID
+ * @force_ssid_len: Length of $force_ssid buffer
+ * @pd_before_go_neg: Whether to send Provision Discovery prior to GO
+ *     Negotiation as an interoperability workaround when initiating group
+ *     formation
  * Returns: 0 on success, -1 on failure
  */
 int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
                enum p2p_wps_method wps_method,
                int go_intent, const u8 *own_interface_addr,
-               unsigned int force_freq, int persistent_group);
+               unsigned int force_freq, int persistent_group,
+               const u8 *force_ssid, size_t force_ssid_len,
+               int pd_before_go_neg);
 
 /**
  * p2p_authorize - Authorize P2P group formation (GO negotiation)
@@ -879,6 +901,9 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
  * @persistent_group: Whether to create a persistent group (0 = no, 1 =
  * persistent group without persistent reconnect, 2 = persistent group with
  * persistent reconnect)
+ * @force_ssid: Forced SSID for the group if we become GO or %NULL to generate
+ *     a new SSID
+ * @force_ssid_len: Length of $force_ssid buffer
  * Returns: 0 on success, -1 on failure
  *
  * This is like p2p_connect(), but the actual group negotiation is not
@@ -887,7 +912,8 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
 int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr,
                  enum p2p_wps_method wps_method,
                  int go_intent, const u8 *own_interface_addr,
-                 unsigned int force_freq, int persistent_group);
+                 unsigned int force_freq, int persistent_group,
+                 const u8 *force_ssid, size_t force_ssid_len);
 
 /**
  * p2p_reject - Reject peer device (explicitly block connection attempts)
@@ -1060,17 +1086,34 @@ u16 p2p_get_provisioning_info(struct p2p_data *p2p, const u8 *addr);
 /**
  * p2p_clear_provisioning_info - Clear any stored provisioning info
  * @p2p: P2P module context from p2p_init()
- * @iface_addr: Peer P2P Interface Address
+ * @iface_addr: Peer P2P Device Address
  *
  * This function is used to clear stored WPS provisioning info for the given
  * peer.
  */
-void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *iface_addr);
+void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *addr);
 
 
 /* Event notifications from lower layer driver operations */
 
 /**
+ * enum p2p_probe_req_status
+ *
+ * @P2P_PREQ_MALFORMED: frame was not well-formed
+ * @P2P_PREQ_NOT_LISTEN: device isn't in listen state, frame ignored
+ * @P2P_PREQ_NOT_P2P: frame was not a P2P probe request
+ * @P2P_PREQ_P2P_NOT_PROCESSED: frame was P2P but wasn't processed
+ * @P2P_PREQ_P2P_PROCESSED: frame has been processed by P2P
+ */
+enum p2p_probe_req_status {
+       P2P_PREQ_MALFORMED,
+       P2P_PREQ_NOT_LISTEN,
+       P2P_PREQ_NOT_P2P,
+       P2P_PREQ_NOT_PROCESSED,
+       P2P_PREQ_PROCESSED
+};
+
+/**
  * p2p_probe_req_rx - Report reception of a Probe Request frame
  * @p2p: P2P module context from p2p_init()
  * @addr: Source MAC address
@@ -1078,10 +1121,11 @@ void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *iface_addr);
  * @bssid: BSSID if available or %NULL
  * @ie: Information elements from the Probe Request frame body
  * @ie_len: Length of ie buffer in octets
- * Returns: 0 to indicate the frame was not processed or 1 if it was
+ * Returns: value indicating the type and status of the probe request
  */
-int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
-                    const u8 *bssid, const u8 *ie, size_t ie_len);
+enum p2p_probe_req_status
+p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
+                const u8 *bssid, const u8 *ie, size_t ie_len);
 
 /**
  * p2p_rx_action - Report received Action frame
@@ -1220,6 +1264,16 @@ struct p2p_group_config {
        unsigned int max_clients;
 
        /**
+        * ssid - Group SSID
+        */
+       u8 ssid[32];
+
+       /**
+        * ssid_len - Length of SSID
+        */
+       size_t ssid_len;
+
+       /**
         * cb_ctx - Context to use with callback functions
         */
        void *cb_ctx;
@@ -1371,6 +1425,15 @@ int p2p_ie_text(struct wpabuf *p2p_ie, char *buf, char *end);
 int p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf, char *end);
 
 /**
+ * p2p_parse_dev_addr_in_p2p_ie - Parse P2P Device Address from a concatenated
+ * P2P IE
+ * @p2p_ie: P2P IE
+ * @dev_addr: Buffer for returning P2P Device Address
+ * Returns: 0 on success or -1 if P2P Device Address could not be parsed
+ */
+int p2p_parse_dev_addr_in_p2p_ie(struct wpabuf *p2p_ie, u8 *dev_addr);
+
+/**
  * p2p_parse_dev_addr - Parse P2P Device Address from P2P IE(s)
  * @ies: Information elements from scan results
  * @ies_len: ies buffer length in octets
@@ -1608,6 +1671,16 @@ int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel,
                         int cfg_op_channel);
 
 /**
+ * p2p_set_pref_chan - Set P2P preferred channel list
+ * @p2p: P2P module context from p2p_init()
+ * @num_pref_chan: Number of entries in pref_chan list
+ * @pref_chan: Preferred channels or %NULL to remove preferences
+ * Returns: 0 on success, -1 on failure
+ */
+int p2p_set_pref_chan(struct p2p_data *p2p, unsigned int num_pref_chan,
+                     const struct p2p_channel *pref_chan);
+
+/**
  * p2p_in_progress - Check whether a P2P operation is progress
  * @p2p: P2P module context from p2p_init()
  * Returns: 0 if P2P module is idle or 1 if an operation is in progress
index 2106964..def422d 100644 (file)
@@ -351,7 +351,7 @@ static void p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr,
 }
 
 
-void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, u16 pw_id,
+void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
                      int all_attr)
 {
        u8 *len;
@@ -369,11 +369,14 @@ void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, u16 pw_id,
                wpabuf_put_u8(buf, WPS_STATE_NOT_CONFIGURED);
        }
 
-       /* Device Password ID */
-       wpabuf_put_be16(buf, ATTR_DEV_PASSWORD_ID);
-       wpabuf_put_be16(buf, 2);
-       wpa_printf(MSG_DEBUG, "P2P: WPS IE Device Password ID: %d", pw_id);
-       wpabuf_put_be16(buf, pw_id);
+       if (pw_id >= 0) {
+               /* Device Password ID */
+               wpabuf_put_be16(buf, ATTR_DEV_PASSWORD_ID);
+               wpabuf_put_be16(buf, 2);
+               wpa_printf(MSG_DEBUG, "P2P: WPS IE Device Password ID: %d",
+                          pw_id);
+               wpabuf_put_be16(buf, pw_id);
+       }
 
        if (all_attr) {
                wpabuf_put_be16(buf, ATTR_RESPONSE_TYPE);
index 6e818c2..248b2a0 100644 (file)
@@ -98,7 +98,7 @@ static int p2p_peer_channels(struct p2p_data *p2p, struct p2p_device *dev,
 }
 
 
-static u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method)
+u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method)
 {
        switch (wps_method) {
        case WPS_PIN_DISPLAY:
@@ -155,7 +155,9 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
                group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
        if (p2p->cfg->p2p_intra_bss)
                group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
-       p2p_buf_add_capability(buf, p2p->dev_capab, group_capab);
+       p2p_buf_add_capability(buf, p2p->dev_capab &
+                              ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
+                              group_capab);
        p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) |
                              p2p->next_tie_breaker);
        p2p->next_tie_breaker = !p2p->next_tie_breaker;
@@ -184,6 +186,23 @@ int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev)
        struct wpabuf *req;
        int freq;
 
+       if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG) {
+               u16 config_method;
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "P2P: Use PD-before-GO-Neg workaround for " MACSTR,
+                       MAC2STR(dev->info.p2p_device_addr));
+               if (dev->wps_method == WPS_PIN_DISPLAY)
+                       config_method = WPS_CONFIG_KEYPAD;
+               else if (dev->wps_method == WPS_PIN_KEYPAD)
+                       config_method = WPS_CONFIG_DISPLAY;
+               else if (dev->wps_method == WPS_PBC)
+                       config_method = WPS_CONFIG_PUSHBUTTON;
+               else
+                       return -1;
+               return p2p_prov_disc_req(p2p, dev->info.p2p_device_addr,
+                                        config_method, 0, 0);
+       }
+
        freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
        if (freq <= 0) {
                wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
@@ -203,9 +222,6 @@ int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev)
        p2p->go_neg_peer = dev;
        dev->flags |= P2P_DEV_WAIT_GO_NEG_RESPONSE;
        dev->connect_reqs++;
-#ifdef ANDROID_P2P
-       dev->go_neg_req_sent++;
-#endif
        if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
                            p2p->cfg->dev_addr, dev->info.p2p_device_addr,
                            wpabuf_head(req), wpabuf_len(req), 200) < 0) {
@@ -213,7 +229,8 @@ int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev)
                        "P2P: Failed to send Action frame");
                /* Use P2P find to recover and retry */
                p2p_set_timeout(p2p, 0, 0);
-       }
+       } else
+               dev->go_neg_req_sent++;
 
        wpabuf_free(req);
 
@@ -253,7 +270,9 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
                if (p2p->cfg->p2p_intra_bss)
                        group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
        }
-       p2p_buf_add_capability(buf, p2p->dev_capab, group_capab);
+       p2p_buf_add_capability(buf, p2p->dev_capab &
+                              ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
+                              group_capab);
        p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | tie_breaker);
        p2p_buf_add_config_timeout(buf, 100, 20);
        if (peer && peer->go_state == REMOTE_GO) {
@@ -299,6 +318,7 @@ static void p2p_reselect_channel(struct p2p_data *p2p,
        struct p2p_reg_class *cl;
        int freq;
        u8 op_reg_class, op_channel;
+       unsigned int i;
 
        wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Selected operating "
                "channel (reg_class %u channel %u) not acceptable to the "
@@ -331,6 +351,21 @@ static void p2p_reselect_channel(struct p2p_data *p2p,
                return;
        }
 
+       /* Select channel with highest preference if the peer supports it */
+       for (i = 0; p2p->cfg->pref_chan && i < p2p->cfg->num_pref_chan; i++) {
+               if (p2p_channels_includes(intersection,
+                                         p2p->cfg->pref_chan[i].op_class,
+                                         p2p->cfg->pref_chan[i].chan)) {
+                       p2p->op_reg_class = p2p->cfg->pref_chan[i].op_class;
+                       p2p->op_channel = p2p->cfg->pref_chan[i].chan;
+                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick "
+                               "highest preferred chnnel (op_class %u "
+                               "channel %u) from intersection",
+                               p2p->op_reg_class, p2p->op_channel);
+                       return;
+               }
+       }
+
        /*
         * Fall back to whatever is included in the channel intersection since
         * no better options seems to be available.
@@ -641,6 +676,17 @@ fail:
        if (status == P2P_SC_SUCCESS) {
                p2p->pending_action_state = P2P_PENDING_GO_NEG_RESPONSE;
                dev->flags |= P2P_DEV_WAIT_GO_NEG_CONFIRM;
+               if (os_memcmp(sa, p2p->cfg->dev_addr, ETH_ALEN) < 0) {
+                       /*
+                        * Peer has smaller address, so the GO Negotiation
+                        * Response from us is expected to complete
+                        * negotiation. Ignore a GO Negotiation Response from
+                        * the peer if it happens to be received after this
+                        * point due to a race condition in GO Negotiation
+                        * Request transmission and processing.
+                        */
+                       dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE;
+               }
        } else
                p2p->pending_action_state =
                        P2P_PENDING_GO_NEG_RESPONSE_FAILURE;
@@ -688,7 +734,9 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p,
                if (p2p->cfg->p2p_intra_bss)
                        group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
        }
-       p2p_buf_add_capability(buf, p2p->dev_capab, group_capab);
+       p2p_buf_add_capability(buf, p2p->dev_capab &
+                              ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
+                              group_capab);
        if (go || resp_chan == NULL)
                p2p_buf_add_operating_channel(buf, p2p->cfg->country,
                                              p2p->op_reg_class,
@@ -992,7 +1040,7 @@ fail:
        else
                freq = dev->listen_freq;
        if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, sa,
-                           wpabuf_head(conf), wpabuf_len(conf), 200) < 0) {
+                           wpabuf_head(conf), wpabuf_len(conf), 0) < 0) {
                wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
                        "P2P: Failed to send Action frame");
                p2p_go_neg_failed(p2p, dev, -1);
index fafd135..8d4a3cb 100644 (file)
@@ -135,11 +135,10 @@ static void p2p_client_info(struct wpabuf *ie, struct p2p_group_member *m)
 static void p2p_group_add_common_ies(struct p2p_group *group,
                                     struct wpabuf *ie)
 {
-       u8 dev_capab = 0, group_capab = 0;
+       u8 dev_capab = group->p2p->dev_capab, group_capab = 0;
 
        /* P2P Capability */
-       dev_capab |= P2P_DEV_CAPAB_SERVICE_DISCOVERY;
-       dev_capab |= P2P_DEV_CAPAB_INVITATION_PROCEDURE;
+       dev_capab &= ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
        group_capab |= P2P_GROUP_CAPAB_GROUP_OWNER;
        if (group->cfg->persistent_group) {
                group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
@@ -731,3 +730,15 @@ int p2p_group_is_client_connected(struct p2p_group *group, const u8 *dev_addr)
 
        return 0;
 }
+
+
+int p2p_group_is_group_id_match(struct p2p_group *group, const u8 *group_id,
+                               size_t group_id_len)
+{
+       if (group_id_len != ETH_ALEN + group->cfg->ssid_len)
+               return 0;
+       if (os_memcmp(group_id, group->p2p->cfg->dev_addr, ETH_ALEN) != 0)
+               return 0;
+       return os_memcmp(group_id + ETH_ALEN, group->cfg->ssid,
+                        group->cfg->ssid_len) == 0;
+}
index 4ccd38d..5e21249 100644 (file)
@@ -90,6 +90,7 @@ struct p2p_device {
 #define P2P_DEV_PD_FOR_JOIN BIT(14)
 #define P2P_DEV_REPORTED_ONCE BIT(15)
 #define P2P_DEV_PREFER_PERSISTENT_RECONN BIT(16)
+#define P2P_DEV_PD_BEFORE_GO_NEG BIT(17)
        unsigned int flags;
 
        int status; /* enum p2p_status_code */
@@ -557,6 +558,8 @@ const u8 * p2p_group_get_interface_addr(struct p2p_group *group);
 u8 p2p_group_presence_req(struct p2p_group *group,
                          const u8 *client_interface_addr,
                          const u8 *noa, size_t noa_len);
+int p2p_group_is_group_id_match(struct p2p_group *group, const u8 *group_id,
+                               size_t group_id_len);
 
 
 void p2p_buf_add_action_hdr(struct wpabuf *buf, u8 subtype, u8 dialog_token);
@@ -588,7 +591,7 @@ void p2p_buf_add_noa(struct wpabuf *buf, u8 noa_index, u8 opp_ps, u8 ctwindow,
 void p2p_buf_add_ext_listen_timing(struct wpabuf *buf, u16 period,
                                   u16 interval);
 void p2p_buf_add_p2p_interface(struct wpabuf *buf, struct p2p_data *p2p);
-void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, u16 pw_id,
+void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
                      int all_attr);
 
 /* p2p_sd.c */
@@ -616,6 +619,7 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
 void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
                             const u8 *data, size_t len);
 int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev);
+u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method);
 
 /* p2p_pd.c */
 void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
@@ -660,7 +664,7 @@ struct p2p_device * p2p_add_dev_from_go_neg_req(struct p2p_data *p2p,
 void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr,
                      struct p2p_device *dev, struct p2p_message *msg);
 int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level,
-                  const u8 *ies, size_t ies_len);
+                  const u8 *ies, size_t ies_len, int scan_res);
 struct p2p_device * p2p_get_device(struct p2p_data *p2p, const u8 *addr);
 struct p2p_device * p2p_get_device_interface(struct p2p_data *p2p,
                                             const u8 *addr);
@@ -675,5 +679,6 @@ void p2p_build_ssid(struct p2p_data *p2p, u8 *ssid, size_t *ssid_len);
 int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
                    const u8 *src, const u8 *bssid, const u8 *buf,
                    size_t len, unsigned int wait_time);
+void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq);
 
 #endif /* P2P_I_H */
index 417f1e7..5925549 100644 (file)
@@ -121,7 +121,8 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
                        "P2P: Invitation Request from unknown peer "
                        MACSTR, MAC2STR(sa));
 
-               if (p2p_add_device(p2p, sa, rx_freq, 0, data + 1, len - 1)) {
+               if (p2p_add_device(p2p, sa, rx_freq, 0, data + 1, len - 1, 0))
+               {
                        wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
                                "P2P: Invitation Request add device failed "
                                MACSTR, MAC2STR(sa));
@@ -344,6 +345,8 @@ int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev,
        req = p2p_build_invitation_req(p2p, dev, go_dev_addr);
        if (req == NULL)
                return -1;
+       if (p2p->state != P2P_IDLE)
+               p2p_stop_listen_for_freq(p2p, freq);
        wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
                "P2P: Sending Invitation Request");
        p2p_set_state(p2p, P2P_INVITE);
index 55a3b90..38a9dd8 100644 (file)
@@ -54,7 +54,8 @@ static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
        p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_REQ, dialog_token);
 
        len = p2p_buf_add_ie_hdr(buf);
-       p2p_buf_add_capability(buf, p2p->dev_capab, 0);
+       p2p_buf_add_capability(buf, p2p->dev_capab &
+                              ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0);
        p2p_buf_add_device_info(buf, p2p, NULL);
        if (go) {
                p2p_buf_add_group_id(buf, go->info.p2p_device_addr,
@@ -110,7 +111,8 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
                wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
                        "P2P: Provision Discovery Request from "
                        "unknown peer " MACSTR, MAC2STR(sa));
-               if (p2p_add_device(p2p, sa, rx_freq, 0, data + 1, len - 1)) {
+               if (p2p_add_device(p2p, sa, rx_freq, 0, data + 1, len - 1, 0))
+               {
                        wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
                                "P2P: Provision Discovery Request add device "
                                "failed " MACSTR, MAC2STR(sa));
@@ -125,6 +127,21 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
                goto out;
        }
 
+       if (msg.group_id) {
+               size_t i;
+               for (i = 0; i < p2p->num_groups; i++) {
+                       if (p2p_group_is_group_id_match(p2p->groups[i],
+                                                       msg.group_id,
+                                                       msg.group_id_len))
+                               break;
+               }
+               if (i == p2p->num_groups) {
+                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: PD "
+                               "request for unknown P2P Group ID - reject");
+                       goto out;
+               }
+       }
+
        if (dev)
                dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
                                P2P_DEV_PD_PEER_KEYPAD);
@@ -198,6 +215,7 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
        struct p2p_message msg;
        struct p2p_device *dev;
        u16 report_config_methods = 0;
+       int success = 0;
 
        if (p2p_parse(data, len, &msg))
                return;
@@ -266,11 +284,21 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
        dev->wps_prov_info = msg.wps_config_methods;
 
        p2p_parse_free(&msg);
+       success = 1;
 
 out:
        dev->req_config_methods = 0;
        p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
-       if (p2p->cfg->prov_disc_resp)
+       if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "P2P: Start GO Neg after the PD-before-GO-Neg "
+                       "workaround with " MACSTR,
+                       MAC2STR(dev->info.p2p_device_addr));
+               dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG;
+               p2p_connect_send(p2p, dev);
+               return;
+       }
+       if (success && p2p->cfg->prov_disc_resp)
                p2p->cfg->prov_disc_resp(p2p->cfg->cb_ctx, sa,
                                         report_config_methods);
 }
@@ -316,6 +344,8 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
        if (req == NULL)
                return -1;
 
+       if (p2p->state != P2P_IDLE)
+               p2p_stop_listen_for_freq(p2p, freq);
        p2p->pending_action_state = P2P_PENDING_PD;
        if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
                            p2p->cfg->dev_addr, dev->info.p2p_device_addr,
index 37b3f7b..0509767 100644 (file)
@@ -364,9 +364,14 @@ void p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst,
                                "previous SD response");
                        wpabuf_free(p2p->sd_resp);
                }
+               p2p->sd_resp = wpabuf_dup(resp_tlvs);
+               if (p2p->sd_resp == NULL) {
+                       wpa_msg(p2p->cfg->msg_ctx, MSG_ERROR, "P2P: Failed to "
+                               "allocate SD response fragmentation area");
+                       return;
+               }
                os_memcpy(p2p->sd_resp_addr, dst, ETH_ALEN);
                p2p->sd_resp_dialog_token = dialog_token;
-               p2p->sd_resp = wpabuf_dup(resp_tlvs);
                p2p->sd_resp_pos = 0;
                p2p->sd_frag_id = 0;
                resp = p2p_build_sd_response(dialog_token, WLAN_STATUS_SUCCESS,
@@ -404,9 +409,18 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
        u16 slen;
        u16 update_indic;
 
+#ifdef ANDROID_P2P
+       if (p2p->state != P2P_SD_DURING_FIND) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "P2P: #### Not ignoring unexpected GAS Initial Response from "
+                       MACSTR " state %d", MAC2STR(sa), p2p->state);
+       }
+       if (p2p->sd_peer == NULL ||
+#else
        if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL ||
+#endif
            os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_ERROR,
+               wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
                        "P2P: Ignore unexpected GAS Initial Response from "
                        MACSTR, MAC2STR(sa));
                return;
@@ -645,9 +659,18 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
 
        wpa_hexdump(MSG_DEBUG, "P2P: RX GAS Comeback Response", data, len);
 
+#ifdef ANDROID_P2P
+       if (p2p->state != P2P_SD_DURING_FIND) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                       "P2P: #### Not ignoring unexpected GAS Comeback Response from "
+                       MACSTR " state %d", MAC2STR(sa), p2p->state);
+       }
+       if (p2p->sd_peer == NULL ||
+#else
        if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL ||
+#endif
            os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) {
-               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+               wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
                        "P2P: Ignore unexpected GAS Comeback Response from "
                        MACSTR, MAC2STR(sa));
                return;
@@ -842,7 +865,7 @@ void * p2p_sd_request(struct p2p_data *p2p, const u8 *dst,
 {
        struct p2p_sd_query *q;
 #ifdef ANDROID_P2P
-       /* Currently, supplicant doesn't support more than one pending broadcast SD request. 
+       /* Currently, supplicant doesn't support more than one pending broadcast SD request.
         * So reject if application is registering another one before cancelling the existing one.
         */
        for (q = p2p->sd_queries; q; q = q->next) {
@@ -872,7 +895,7 @@ void * p2p_sd_request(struct p2p_data *p2p, const u8 *dst,
 
        q->next = p2p->sd_queries;
        p2p->sd_queries = q;
-       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Added SD Query %p for_all_peers %d", q, q->for_all_peers);
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Added SD Query %p", q);
 
        if (dst == NULL) {
                struct p2p_device *dev;
@@ -893,24 +916,10 @@ void p2p_sd_service_update(struct p2p_data *p2p)
 int p2p_sd_cancel_request(struct p2p_data *p2p, void *req)
 {
        if (p2p_unlink_sd_query(p2p, req)) {
-#ifdef ANDROID_P2P
-       struct p2p_device *dev;
-       struct p2p_sd_query *q = (struct p2p_sd_query *)req;
-#endif
                wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
                        "P2P: Cancel pending SD query %p", req);
 #ifdef ANDROID_P2P
-               /* If the request is a bcast query, then clear the
-                * P2P_DEV_SD_INFO flag so that when new sd query is registered,
-                * we will send the SD request frames to peer devices.
-                */
-               if(q->for_all_peers) {
-                       p2p->sd_dev_list = NULL;
-                       dl_list_for_each(dev, &p2p->devices,
-                                                       struct p2p_device, list) {
-                               dev->flags &= ~P2P_DEV_SD_INFO;
-                       }
-               }
+               p2p->sd_dev_list = NULL;
 #endif
                p2p_free_sd_query(req);
                return 0;
index 0dd6b12..2b9cbca 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * RADIUS message processing
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2011-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -147,6 +147,12 @@ static const char *radius_code_string(u8 code)
        case RADIUS_CODE_STATUS_SERVER: return "Status-Server";
        case RADIUS_CODE_STATUS_CLIENT: return "Status-Client";
        case RADIUS_CODE_RESERVED: return "Reserved";
+       case RADIUS_CODE_DISCONNECT_REQUEST: return "Disconnect-Request";
+       case RADIUS_CODE_DISCONNECT_ACK: return "Disconnect-ACK";
+       case RADIUS_CODE_DISCONNECT_NAK: return "Disconnect-NAK";
+       case RADIUS_CODE_COA_REQUEST: return "CoA-Request";
+       case RADIUS_CODE_COA_ACK: return "CoA-ACK";
+       case RADIUS_CODE_COA_NAK: return "CoA-NAK";
        default: return "?Unknown?";
        }
 }
@@ -222,9 +228,10 @@ static struct radius_attr_type radius_attrs[] =
          RADIUS_ATTR_HEXDUMP },
        { RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval",
          RADIUS_ATTR_INT32 },
-       { RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargable-User-Identity",
+       { RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargeable-User-Identity",
          RADIUS_ATTR_TEXT },
        { RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 },
+       { RADIUS_ATTR_ERROR_CAUSE, "Error-Cause", RADIUS_ATTR_INT32 }
 };
 #define RADIUS_ATTRS (sizeof(radius_attrs) / sizeof(radius_attrs[0]))
 
@@ -406,6 +413,45 @@ int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
 }
 
 
+int radius_msg_finish_das_resp(struct radius_msg *msg, const u8 *secret,
+                              size_t secret_len,
+                              const struct radius_hdr *req_hdr)
+{
+       const u8 *addr[2];
+       size_t len[2];
+       u8 auth[MD5_MAC_LEN];
+       struct radius_attr_hdr *attr;
+
+       os_memset(auth, 0, MD5_MAC_LEN);
+       attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
+                                  auth, MD5_MAC_LEN);
+       if (attr == NULL) {
+               wpa_printf(MSG_WARNING, "Could not add Message-Authenticator");
+               return -1;
+       }
+
+       msg->hdr->length = htons(wpabuf_len(msg->buf));
+       os_memcpy(msg->hdr->authenticator, req_hdr->authenticator, 16);
+       hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
+                wpabuf_len(msg->buf), (u8 *) (attr + 1));
+
+       /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
+       addr[0] = wpabuf_head_u8(msg->buf);
+       len[0] = wpabuf_len(msg->buf);
+       addr[1] = secret;
+       len[1] = secret_len;
+       if (md5_vector(2, addr, len, msg->hdr->authenticator) < 0)
+               return -1;
+
+       if (wpabuf_len(msg->buf) > 0xffff) {
+               wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
+                          (unsigned long) wpabuf_len(msg->buf));
+               return -1;
+       }
+       return 0;
+}
+
+
 void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
                            size_t secret_len)
 {
@@ -427,6 +473,88 @@ void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
 }
 
 
+int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret,
+                              size_t secret_len)
+{
+       const u8 *addr[4];
+       size_t len[4];
+       u8 zero[MD5_MAC_LEN];
+       u8 hash[MD5_MAC_LEN];
+
+       os_memset(zero, 0, sizeof(zero));
+       addr[0] = (u8 *) msg->hdr;
+       len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN;
+       addr[1] = zero;
+       len[1] = MD5_MAC_LEN;
+       addr[2] = (u8 *) (msg->hdr + 1);
+       len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
+       addr[3] = secret;
+       len[3] = secret_len;
+       md5_vector(4, addr, len, hash);
+       return os_memcmp(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0;
+}
+
+
+int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
+                             size_t secret_len)
+{
+       const u8 *addr[4];
+       size_t len[4];
+       u8 zero[MD5_MAC_LEN];
+       u8 hash[MD5_MAC_LEN];
+       u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN];
+       u8 orig_authenticator[16];
+
+       struct radius_attr_hdr *attr = NULL, *tmp;
+       size_t i;
+
+       os_memset(zero, 0, sizeof(zero));
+       addr[0] = (u8 *) msg->hdr;
+       len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN;
+       addr[1] = zero;
+       len[1] = MD5_MAC_LEN;
+       addr[2] = (u8 *) (msg->hdr + 1);
+       len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
+       addr[3] = secret;
+       len[3] = secret_len;
+       md5_vector(4, addr, len, hash);
+       if (os_memcmp(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0)
+               return 1;
+
+       for (i = 0; i < msg->attr_used; i++) {
+               tmp = radius_get_attr_hdr(msg, i);
+               if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) {
+                       if (attr != NULL) {
+                               wpa_printf(MSG_WARNING, "Multiple "
+                                          "Message-Authenticator attributes "
+                                          "in RADIUS message");
+                               return 1;
+                       }
+                       attr = tmp;
+               }
+       }
+
+       if (attr == NULL) {
+               /* Message-Authenticator is MAY; not required */
+               return 0;
+       }
+
+       os_memcpy(orig, attr + 1, MD5_MAC_LEN);
+       os_memset(attr + 1, 0, MD5_MAC_LEN);
+       os_memcpy(orig_authenticator, msg->hdr->authenticator,
+                 sizeof(orig_authenticator));
+       os_memset(msg->hdr->authenticator, 0,
+                 sizeof(msg->hdr->authenticator));
+       hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
+                wpabuf_len(msg->buf), auth);
+       os_memcpy(attr + 1, orig, MD5_MAC_LEN);
+       os_memcpy(msg->hdr->authenticator, orig_authenticator,
+                 sizeof(orig_authenticator));
+
+       return os_memcmp(orig, auth, MD5_MAC_LEN) != 0;
+}
+
+
 static int radius_msg_add_attr_to_array(struct radius_msg *msg,
                                        struct radius_attr_hdr *attr)
 {
@@ -1424,3 +1552,24 @@ int radius_copy_class(struct radius_class_data *dst,
 
        return 0;
 }
+
+
+u8 radius_msg_find_unlisted_attr(struct radius_msg *msg, u8 *attrs)
+{
+       size_t i, j;
+       struct radius_attr_hdr *attr;
+
+       for (i = 0; i < msg->attr_used; i++) {
+               attr = radius_get_attr_hdr(msg, i);
+
+               for (j = 0; attrs[j]; j++) {
+                       if (attr->type == attrs[j])
+                               break;
+               }
+
+               if (attrs[j] == 0)
+                       return attr->type; /* unlisted attr */
+       }
+
+       return 0;
+}
index 44123bd..2d059df 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * RADIUS message processing
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -31,6 +31,12 @@ enum { RADIUS_CODE_ACCESS_REQUEST = 1,
        RADIUS_CODE_ACCESS_CHALLENGE = 11,
        RADIUS_CODE_STATUS_SERVER = 12,
        RADIUS_CODE_STATUS_CLIENT = 13,
+       RADIUS_CODE_DISCONNECT_REQUEST = 40,
+       RADIUS_CODE_DISCONNECT_ACK = 41,
+       RADIUS_CODE_DISCONNECT_NAK = 42,
+       RADIUS_CODE_COA_REQUEST = 43,
+       RADIUS_CODE_COA_ACK = 44,
+       RADIUS_CODE_COA_NAK = 45,
        RADIUS_CODE_RESERVED = 255
 };
 
@@ -83,7 +89,8 @@ enum { RADIUS_ATTR_USER_NAME = 1,
        RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID = 81,
        RADIUS_ATTR_ACCT_INTERIM_INTERVAL = 85,
        RADIUS_ATTR_CHARGEABLE_USER_IDENTITY = 89,
-       RADIUS_ATTR_NAS_IPV6_ADDRESS = 95
+       RADIUS_ATTR_NAS_IPV6_ADDRESS = 95,
+       RADIUS_ATTR_ERROR_CAUSE = 101
 };
 
 
@@ -192,8 +199,15 @@ int radius_msg_finish(struct radius_msg *msg, const u8 *secret,
                      size_t secret_len);
 int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
                          size_t secret_len, const u8 *req_authenticator);
+int radius_msg_finish_das_resp(struct radius_msg *msg, const u8 *secret,
+                              size_t secret_len,
+                              const struct radius_hdr *req_hdr);
 void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
                            size_t secret_len);
+int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret,
+                              size_t secret_len);
+int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
+                              size_t secret_len);
 struct radius_attr_hdr * radius_msg_add_attr(struct radius_msg *msg, u8 type,
                                             const u8 *data, size_t data_len);
 struct radius_msg * radius_msg_parse(const u8 *data, size_t len);
@@ -268,4 +282,6 @@ void radius_free_class(struct radius_class_data *c);
 int radius_copy_class(struct radius_class_data *dst,
                      const struct radius_class_data *src);
 
+u8 radius_msg_find_unlisted_attr(struct radius_msg *msg, u8 *attrs);
+
 #endif /* RADIUS_H */
index bcd471b..1ee7131 100644 (file)
@@ -505,7 +505,7 @@ static void radius_client_update_timeout(struct radius_client_data *radius)
                               NULL);
        hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
                       HOSTAPD_LEVEL_DEBUG, "Next RADIUS client retransmit in"
-                      " %ld seconds\n", (long int) (first - now.sec));
+                      " %ld seconds", (long int) (first - now.sec));
 }
 
 
@@ -678,7 +678,7 @@ int radius_client_send(struct radius_client_data *radius,
        radius_client_list_add(radius, msg, msg_type, shared_secret,
                               shared_secret_len, addr);
 
-       return res;
+       return 0;
 }
 
 
diff --git a/src/radius/radius_das.c b/src/radius/radius_das.c
new file mode 100644 (file)
index 0000000..8ecfffc
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ * RADIUS Dynamic Authorization Server (DAS) (RFC 5176)
+ * Copyright (c) 2012, 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 <net/if.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/ip_addr.h"
+#include "radius.h"
+#include "radius_das.h"
+
+
+extern int wpa_debug_level;
+
+
+struct radius_das_data {
+       int sock;
+       u8 *shared_secret;
+       size_t shared_secret_len;
+       struct hostapd_ip_addr client_addr;
+       unsigned int time_window;
+       int require_event_timestamp;
+       void *ctx;
+       enum radius_das_res (*disconnect)(void *ctx,
+                                         struct radius_das_attrs *attr);
+};
+
+
+static struct radius_msg * radius_das_disconnect(struct radius_das_data *das,
+                                                struct radius_msg *msg,
+                                                const char *abuf,
+                                                int from_port)
+{
+       struct radius_hdr *hdr;
+       struct radius_msg *reply;
+       u8 allowed[] = {
+               RADIUS_ATTR_USER_NAME,
+               RADIUS_ATTR_CALLING_STATION_ID,
+               RADIUS_ATTR_ACCT_SESSION_ID,
+               RADIUS_ATTR_EVENT_TIMESTAMP,
+               RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
+               RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+               0
+       };
+       int error = 405;
+       u8 attr;
+       enum radius_das_res res;
+       struct radius_das_attrs attrs;
+       u8 *buf;
+       size_t len;
+       char tmp[100];
+       u8 sta_addr[ETH_ALEN];
+
+       hdr = radius_msg_get_hdr(msg);
+
+       attr = radius_msg_find_unlisted_attr(msg, allowed);
+       if (attr) {
+               wpa_printf(MSG_INFO, "DAS: Unsupported attribute %u in "
+                          "Disconnect-Request from %s:%d", attr,
+                          abuf, from_port);
+               error = 401;
+               goto fail;
+       }
+
+       os_memset(&attrs, 0, sizeof(attrs));
+
+       if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CALLING_STATION_ID,
+                                   &buf, &len, NULL) == 0) {
+               if (len >= sizeof(tmp))
+                       len = sizeof(tmp) - 1;
+               os_memcpy(tmp, buf, len);
+               tmp[len] = '\0';
+               if (hwaddr_aton2(tmp, sta_addr) < 0) {
+                       wpa_printf(MSG_INFO, "DAS: Invalid Calling-Station-Id "
+                                  "'%s' from %s:%d", tmp, abuf, from_port);
+                       error = 407;
+                       goto fail;
+               }
+               attrs.sta_addr = sta_addr;
+       }
+
+       if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
+                                   &buf, &len, NULL) == 0) {
+               attrs.user_name = buf;
+               attrs.user_name_len = len;
+       }
+
+       if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
+                                   &buf, &len, NULL) == 0) {
+               attrs.acct_session_id = buf;
+               attrs.acct_session_id_len = len;
+       }
+
+       if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+                                   &buf, &len, NULL) == 0) {
+               attrs.cui = buf;
+               attrs.cui_len = len;
+       }
+
+       res = das->disconnect(das->ctx, &attrs);
+       switch (res) {
+       case RADIUS_DAS_NAS_MISMATCH:
+               wpa_printf(MSG_INFO, "DAS: NAS mismatch from %s:%d",
+                          abuf, from_port);
+               error = 403;
+               break;
+       case RADIUS_DAS_SESSION_NOT_FOUND:
+               wpa_printf(MSG_INFO, "DAS: Session not found for request from "
+                          "%s:%d", abuf, from_port);
+               error = 503;
+               break;
+       case RADIUS_DAS_SUCCESS:
+               error = 0;
+               break;
+       }
+
+fail:
+       reply = radius_msg_new(error ? RADIUS_CODE_DISCONNECT_NAK :
+                              RADIUS_CODE_DISCONNECT_ACK, hdr->identifier);
+       if (reply == NULL)
+               return NULL;
+
+       if (error) {
+               radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE,
+                                         error);
+       }
+
+       return reply;
+}
+
+
+static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+       struct radius_das_data *das = eloop_ctx;
+       u8 buf[1500];
+       union {
+               struct sockaddr_storage ss;
+               struct sockaddr_in sin;
+#ifdef CONFIG_IPV6
+               struct sockaddr_in6 sin6;
+#endif /* CONFIG_IPV6 */
+       } from;
+       char abuf[50];
+       int from_port = 0;
+       socklen_t fromlen;
+       int len;
+       struct radius_msg *msg, *reply = NULL;
+       struct radius_hdr *hdr;
+       struct wpabuf *rbuf;
+       u32 val;
+       int res;
+       struct os_time now;
+
+       fromlen = sizeof(from);
+       len = recvfrom(sock, buf, sizeof(buf), 0,
+                      (struct sockaddr *) &from.ss, &fromlen);
+       if (len < 0) {
+               wpa_printf(MSG_ERROR, "DAS: recvfrom: %s", strerror(errno));
+               return;
+       }
+
+       os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
+       from_port = ntohs(from.sin.sin_port);
+
+       wpa_printf(MSG_DEBUG, "DAS: Received %d bytes from %s:%d",
+                  len, abuf, from_port);
+       if (das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr) {
+               wpa_printf(MSG_DEBUG, "DAS: Drop message from unknown client");
+               return;
+       }
+
+       msg = radius_msg_parse(buf, len);
+       if (msg == NULL) {
+               wpa_printf(MSG_DEBUG, "DAS: Parsing incoming RADIUS packet "
+                          "from %s:%d failed", abuf, from_port);
+               return;
+       }
+
+       if (wpa_debug_level <= MSG_MSGDUMP)
+               radius_msg_dump(msg);
+
+       if (radius_msg_verify_das_req(msg, das->shared_secret,
+                                      das->shared_secret_len)) {
+               wpa_printf(MSG_DEBUG, "DAS: Invalid authenticator in packet "
+                          "from %s:%d - drop", abuf, from_port);
+               goto fail;
+       }
+
+       os_get_time(&now);
+       res = radius_msg_get_attr(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
+                                 (u8 *) &val, 4);
+       if (res == 4) {
+               u32 timestamp = ntohl(val);
+               if (abs(now.sec - timestamp) > das->time_window) {
+                       wpa_printf(MSG_DEBUG, "DAS: Unacceptable "
+                                  "Event-Timestamp (%u; local time %u) in "
+                                  "packet from %s:%d - drop",
+                                  timestamp, (unsigned int) now.sec,
+                                  abuf, from_port);
+                       goto fail;
+               }
+       } else if (das->require_event_timestamp) {
+               wpa_printf(MSG_DEBUG, "DAS: Missing Event-Timestamp in packet "
+                          "from %s:%d - drop", abuf, from_port);
+               goto fail;
+       }
+
+       hdr = radius_msg_get_hdr(msg);
+
+       switch (hdr->code) {
+       case RADIUS_CODE_DISCONNECT_REQUEST:
+               reply = radius_das_disconnect(das, msg, abuf, from_port);
+               break;
+       case RADIUS_CODE_COA_REQUEST:
+               /* TODO */
+               reply = radius_msg_new(RADIUS_CODE_COA_NAK,
+                                      hdr->identifier);
+               if (reply == NULL)
+                       break;
+
+               /* Unsupported Service */
+               radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE, 405);
+               break;
+       default:
+               wpa_printf(MSG_DEBUG, "DAS: Unexpected RADIUS code %u in "
+                          "packet from %s:%d",
+                          hdr->code, abuf, from_port);
+       }
+
+       if (reply) {
+               wpa_printf(MSG_DEBUG, "DAS: Reply to %s:%d", abuf, from_port);
+
+               if (!radius_msg_add_attr_int32(reply,
+                                              RADIUS_ATTR_EVENT_TIMESTAMP,
+                                              now.sec)) {
+                       wpa_printf(MSG_DEBUG, "DAS: Failed to add "
+                                  "Event-Timestamp attribute");
+               }
+
+               if (radius_msg_finish_das_resp(reply, das->shared_secret,
+                                              das->shared_secret_len, hdr) <
+                   0) {
+                       wpa_printf(MSG_DEBUG, "DAS: Failed to add "
+                                  "Message-Authenticator attribute");
+               }
+
+               if (wpa_debug_level <= MSG_MSGDUMP)
+                       radius_msg_dump(reply);
+
+               rbuf = radius_msg_get_buf(reply);
+               res = sendto(das->sock, wpabuf_head(rbuf),
+                            wpabuf_len(rbuf), 0,
+                            (struct sockaddr *) &from.ss, fromlen);
+               if (res < 0) {
+                       wpa_printf(MSG_ERROR, "DAS: sendto(to %s:%d): %s",
+                                  abuf, from_port, strerror(errno));
+               }
+       }
+
+fail:
+       radius_msg_free(msg);
+       radius_msg_free(reply);
+}
+
+
+static int radius_das_open_socket(int port)
+{
+       int s;
+       struct sockaddr_in addr;
+
+       s = socket(PF_INET, SOCK_DGRAM, 0);
+       if (s < 0) {
+               perror("socket");
+               return -1;
+       }
+
+       os_memset(&addr, 0, sizeof(addr));
+       addr.sin_family = AF_INET;
+       addr.sin_port = htons(port);
+       if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               perror("bind");
+               close(s);
+               return -1;
+       }
+
+       return s;
+}
+
+
+struct radius_das_data *
+radius_das_init(struct radius_das_conf *conf)
+{
+       struct radius_das_data *das;
+
+       if (conf->port == 0 || conf->shared_secret == NULL ||
+           conf->client_addr == NULL)
+               return NULL;
+
+       das = os_zalloc(sizeof(*das));
+       if (das == NULL)
+               return NULL;
+
+       das->time_window = conf->time_window;
+       das->require_event_timestamp = conf->require_event_timestamp;
+       das->ctx = conf->ctx;
+       das->disconnect = conf->disconnect;
+
+       os_memcpy(&das->client_addr, conf->client_addr,
+                 sizeof(das->client_addr));
+
+       das->shared_secret = os_malloc(conf->shared_secret_len);
+       if (das->shared_secret == NULL) {
+               radius_das_deinit(das);
+               return NULL;
+       }
+       os_memcpy(das->shared_secret, conf->shared_secret,
+                 conf->shared_secret_len);
+       das->shared_secret_len = conf->shared_secret_len;
+
+       das->sock = radius_das_open_socket(conf->port);
+       if (das->sock < 0) {
+               wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS "
+                          "DAS");
+               radius_das_deinit(das);
+               return NULL;
+       }
+
+       if (eloop_register_read_sock(das->sock, radius_das_receive, das, NULL))
+       {
+               radius_das_deinit(das);
+               return NULL;
+       }
+
+       return das;
+}
+
+
+void radius_das_deinit(struct radius_das_data *das)
+{
+       if (das == NULL)
+               return;
+
+       if (das->sock >= 0) {
+               eloop_unregister_read_sock(das->sock);
+               close(das->sock);
+       }
+
+       os_free(das->shared_secret);
+       os_free(das);
+}
diff --git a/src/radius/radius_das.h b/src/radius/radius_das.h
new file mode 100644 (file)
index 0000000..738b18b
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * RADIUS Dynamic Authorization Server (DAS)
+ * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef RADIUS_DAS_H
+#define RADIUS_DAS_H
+
+struct radius_das_data;
+
+enum radius_das_res {
+       RADIUS_DAS_SUCCESS,
+       RADIUS_DAS_NAS_MISMATCH,
+       RADIUS_DAS_SESSION_NOT_FOUND
+};
+
+struct radius_das_attrs {
+       const u8 *sta_addr;
+       const u8 *user_name;
+       size_t user_name_len;
+       const u8 *acct_session_id;
+       size_t acct_session_id_len;
+       const u8 *cui;
+       size_t cui_len;
+};
+
+struct radius_das_conf {
+       int port;
+       const u8 *shared_secret;
+       size_t shared_secret_len;
+       const struct hostapd_ip_addr *client_addr;
+       unsigned int time_window;
+       int require_event_timestamp;
+       void *ctx;
+       enum radius_das_res (*disconnect)(void *ctx,
+                                         struct radius_das_attrs *attr);
+};
+
+struct radius_das_data *
+radius_das_init(struct radius_das_conf *conf);
+
+void radius_das_deinit(struct radius_das_data *data);
+
+#endif /* RADIUS_DAS_H */
index 6ebc37a..7646ca8 100644 (file)
@@ -2202,7 +2202,9 @@ int wpa_tdls_init(struct wpa_sm *sm)
        if (sm == NULL)
                return -1;
 
-       sm->l2_tdls = l2_packet_init(sm->ifname, sm->own_addr,
+       sm->l2_tdls = l2_packet_init(sm->bridge_ifname ? sm->bridge_ifname :
+                                    sm->ifname,
+                                    sm->own_addr,
                                     ETH_P_80211_ENCAP, wpa_supplicant_rx_tdls,
                                     sm, 0);
        if (sm->l2_tdls == NULL) {
index 7c9857f..741b442 100644 (file)
 
 #define  OPT_CAST(x)
 
+#ifdef __x86_64__
+typedef unsigned long mp_digit;
+typedef unsigned long mp_word __attribute__((mode(TI)));
+
+#define DIGIT_BIT 60
+#define MP_64BIT
+#else
 typedef unsigned long mp_digit;
 typedef u64 mp_word;
 
 #define DIGIT_BIT          28
 #define MP_28BIT
+#endif
 
 
 #define XMALLOC  os_malloc
index 04b8d98..f947388 100644 (file)
 #endif /* USE_INTERNAL_CRYPTO */
 #endif /* CONFIG_WIN32_DEFAULTS */
 
-#ifdef __SYMBIAN32__
-#define OS_NO_C_LIB_DEFINES
-#define CONFIG_ANSI_C_EXTRA
-#define CONFIG_NO_WPA_MSG
-#define CONFIG_NO_HOSTAPD_LOGGER
-#define CONFIG_NO_STDOUT_DEBUG
-#define CONFIG_BACKEND_FILE
-#define CONFIG_INTERNAL_LIBTOMMATH
-#define CONFIG_CRYPTO_INTERNAL
-#define IEEE8021X_EAPOL
-#define PKCS12_FUNCS
-#define EAP_MD5
-#define EAP_TLS
-#define EAP_MSCHAPv2
-#define EAP_PEAP
-#define EAP_TTLS
-#define EAP_GTC
-#define EAP_OTP
-#define EAP_LEAP
-#define EAP_FAST
-#endif /* __SYMBIAN32__ */
-
 #ifdef CONFIG_XCODE_DEFAULTS
 #define CONFIG_DRIVER_OSX
 #define CONFIG_BACKEND_FILE
index 43ceb54..7f115ef 100644 (file)
@@ -63,12 +63,6 @@ static inline unsigned int bswap_32(unsigned int v)
 #endif
 #endif /* CONFIG_TI_COMPILER */
 
-#ifdef __SYMBIAN32__
-#define __BIG_ENDIAN 4321
-#define __LITTLE_ENDIAN 1234
-#define __BYTE_ORDER __LITTLE_ENDIAN
-#endif /* __SYMBIAN32__ */
-
 #ifdef CONFIG_NATIVE_WINDOWS
 #include <winsock.h>
 
@@ -132,16 +126,6 @@ typedef unsigned char u8;
 #define WPA_TYPES_DEFINED
 #endif /* CONFIG_TI_COMPILER */
 
-#ifdef __SYMBIAN32__
-#define __REMOVE_PLATSEC_DIAGNOSTICS__
-#include <e32def.h>
-typedef TUint64 u64;
-typedef TUint32 u32;
-typedef TUint16 u16;
-typedef TUint8 u8;
-#define WPA_TYPES_DEFINED
-#endif /* __SYMBIAN32__ */
-
 #ifndef WPA_TYPES_DEFINED
 #ifdef CONFIG_USE_INTTYPES_H
 #include <inttypes.h>
index 5691f15..bb32401 100644 (file)
@@ -278,7 +278,7 @@ static int eloop_sock_table_set_fds(struct eloop_sock_table *readers,
                                pollfds_map[fd] = pfd;
                                nxt++;
                        }
-                       pfd->events |= POLLIN;
+                       pfd->events |= POLLOUT;
                }
        }
 
@@ -350,7 +350,8 @@ static void eloop_sock_table_dispatch(struct eloop_sock_table *readers,
                                      int max_pollfd_map)
 {
        if (eloop_sock_table_dispatch_table(readers, pollfds_map,
-                                           max_pollfd_map, POLLIN))
+                                           max_pollfd_map, POLLIN | POLLERR |
+                                           POLLHUP))
                return; /* pollfds may be invalid at this point */
 
        if (eloop_sock_table_dispatch_table(writers, pollfds_map,
index 787be18..6c6ec87 100644 (file)
@@ -41,9 +41,7 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #ifndef __vxworks
-#ifndef __SYMBIAN32__
 #include <sys/uio.h>
-#endif /* __SYMBIAN32__ */
 #include <sys/time.h>
 #endif /* __vxworks */
 #endif /* CONFIG_TI_COMPILER */
index a97f9fa..08510d0 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2007, 2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -70,6 +70,9 @@
 #define USIM_TLV_TOTAL_FILE_SIZE       0x81
 #define USIM_TLV_PIN_STATUS_TEMPLATE   0xC6
 #define USIM_TLV_SHORT_FILE_ID         0x88
+#define USIM_TLV_SECURITY_ATTR_8B      0x8B
+#define USIM_TLV_SECURITY_ATTR_8C      0x8C
+#define USIM_TLV_SECURITY_ATTR_AB      0xAB
 
 #define USIM_PS_DO_TAG                 0x90
 
 #define CK_LEN 16
 
 
+/* GSM files
+ * File type in first octet:
+ * 3F = Master File
+ * 7F = Dedicated File
+ * 2F = Elementary File under the Master File
+ * 6F = Elementary File under a Dedicated File
+ */
+#define SCARD_FILE_MF          0x3F00
+#define SCARD_FILE_GSM_DF      0x7F20
+#define SCARD_FILE_UMTS_DF     0x7F50
+#define SCARD_FILE_GSM_EF_IMSI 0x6F07
+#define SCARD_FILE_GSM_EF_AD   0x6FAD
+#define SCARD_FILE_EF_DIR      0x2F00
+#define SCARD_FILE_EF_ICCID    0x2FE2
+#define SCARD_FILE_EF_CK       0x6FE1
+#define SCARD_FILE_EF_IK       0x6FE2
+
+#define SCARD_CHV1_OFFSET      13
+#define SCARD_CHV1_FLAG                0x80
+
+
 typedef enum { SCARD_GSM_SIM, SCARD_USIM } sim_types;
 
 struct scard_data {
@@ -234,37 +258,60 @@ static int scard_read_record(struct scard_data *scard,
 static int scard_parse_fsp_templ(unsigned char *buf, size_t buf_len,
                                 int *ps_do, int *file_len)
 {
-               unsigned char *pos, *end;
-
-               if (ps_do)
-                       *ps_do = -1;
-               if (file_len)
-                       *file_len = -1;
-
-               pos = buf;
-               end = pos + buf_len;
-               if (*pos != USIM_FSP_TEMPL_TAG) {
-                       wpa_printf(MSG_DEBUG, "SCARD: file header did not "
-                                  "start with FSP template tag");
-                       return -1;
-               }
-               pos++;
-               if (pos >= end)
-                       return -1;
-               if ((pos + pos[0]) < end)
-                       end = pos + 1 + pos[0];
-               pos++;
-               wpa_hexdump(MSG_DEBUG, "SCARD: file header FSP template",
-                           pos, end - pos);
-
-               while (pos + 1 < end) {
-                       wpa_printf(MSG_MSGDUMP, "SCARD: file header TLV "
-                                  "0x%02x len=%d", pos[0], pos[1]);
-                       if (pos + 2 + pos[1] > end)
-                               break;
+       unsigned char *pos, *end;
+
+       if (ps_do)
+               *ps_do = -1;
+       if (file_len)
+               *file_len = -1;
+
+       pos = buf;
+       end = pos + buf_len;
+       if (*pos != USIM_FSP_TEMPL_TAG) {
+               wpa_printf(MSG_DEBUG, "SCARD: file header did not "
+                          "start with FSP template tag");
+               return -1;
+       }
+       pos++;
+       if (pos >= end)
+               return -1;
+       if ((pos + pos[0]) < end)
+               end = pos + 1 + pos[0];
+       pos++;
+       wpa_hexdump(MSG_DEBUG, "SCARD: file header FSP template",
+                   pos, end - pos);
+
+       while (pos + 1 < end) {
+               wpa_printf(MSG_MSGDUMP, "SCARD: file header TLV 0x%02x len=%d",
+                          pos[0], pos[1]);
+               if (pos + 2 + pos[1] > end)
+                       break;
 
-                       if (pos[0] == USIM_TLV_FILE_SIZE &&
-                           (pos[1] == 1 || pos[1] == 2) && file_len) {
+               switch (pos[0]) {
+               case USIM_TLV_FILE_DESC:
+                       wpa_hexdump(MSG_MSGDUMP, "SCARD: File Descriptor TLV",
+                                   pos + 2, pos[1]);
+                       break;
+               case USIM_TLV_FILE_ID:
+                       wpa_hexdump(MSG_MSGDUMP, "SCARD: File Identifier TLV",
+                                   pos + 2, pos[1]);
+                       break;
+               case USIM_TLV_DF_NAME:
+                       wpa_hexdump(MSG_MSGDUMP, "SCARD: DF name (AID) TLV",
+                                   pos + 2, pos[1]);
+                       break;
+               case USIM_TLV_PROPR_INFO:
+                       wpa_hexdump(MSG_MSGDUMP, "SCARD: Proprietary "
+                                   "information TLV", pos + 2, pos[1]);
+                       break;
+               case USIM_TLV_LIFE_CYCLE_STATUS:
+                       wpa_hexdump(MSG_MSGDUMP, "SCARD: Life Cycle Status "
+                                   "Integer TLV", pos + 2, pos[1]);
+                       break;
+               case USIM_TLV_FILE_SIZE:
+                       wpa_hexdump(MSG_MSGDUMP, "SCARD: File size TLV",
+                                   pos + 2, pos[1]);
+                       if ((pos[1] == 1 || pos[1] == 2) && file_len) {
                                if (pos[1] == 1)
                                        *file_len = (int) pos[2];
                                else
@@ -273,21 +320,43 @@ static int scard_parse_fsp_templ(unsigned char *buf, size_t buf_len,
                                wpa_printf(MSG_DEBUG, "SCARD: file_size=%d",
                                           *file_len);
                        }
-
-                       if (pos[0] == USIM_TLV_PIN_STATUS_TEMPLATE &&
-                           pos[1] >= 2 && pos[2] == USIM_PS_DO_TAG &&
+                       break;
+               case USIM_TLV_TOTAL_FILE_SIZE:
+                       wpa_hexdump(MSG_MSGDUMP, "SCARD: Total file size TLV",
+                                   pos + 2, pos[1]);
+                       break;
+               case USIM_TLV_PIN_STATUS_TEMPLATE:
+                       wpa_hexdump(MSG_MSGDUMP, "SCARD: PIN Status Template "
+                                   "DO TLV", pos + 2, pos[1]);
+                       if (pos[1] >= 2 && pos[2] == USIM_PS_DO_TAG &&
                            pos[3] >= 1 && ps_do) {
                                wpa_printf(MSG_DEBUG, "SCARD: PS_DO=0x%02x",
                                           pos[4]);
                                *ps_do = (int) pos[4];
                        }
+                       break;
+               case USIM_TLV_SHORT_FILE_ID:
+                       wpa_hexdump(MSG_MSGDUMP, "SCARD: Short File "
+                                   "Identifier (SFI) TLV", pos + 2, pos[1]);
+                       break;
+               case USIM_TLV_SECURITY_ATTR_8B:
+               case USIM_TLV_SECURITY_ATTR_8C:
+               case USIM_TLV_SECURITY_ATTR_AB:
+                       wpa_hexdump(MSG_MSGDUMP, "SCARD: Security attribute "
+                                   "TLV", pos + 2, pos[1]);
+                       break;
+               default:
+                       wpa_hexdump(MSG_MSGDUMP, "SCARD: Unrecognized TLV",
+                                   pos, 2 + pos[1]);
+                       break;
+               }
 
-                       pos += 2 + pos[1];
+               pos += 2 + pos[1];
 
-                       if (pos == end)
-                               return 0;
-               }
-               return -1;
+               if (pos == end)
+                       return 0;
+       }
+       return -1;
 }
 
 
@@ -328,7 +397,7 @@ static int scard_get_aid(struct scard_data *scard, unsigned char *aid,
                unsigned char rid[5];
                unsigned char appl_code[2]; /* 0x1002 for 3G USIM */
        } *efdir;
-       unsigned char buf[100];
+       unsigned char buf[127];
        size_t blen;
 
        efdir = (struct efdir *) buf;
@@ -417,6 +486,7 @@ static int scard_get_aid(struct scard_data *scard, unsigned char *aid,
 /**
  * scard_init - Initialize SIM/USIM connection using PC/SC
  * @sim_type: Allowed SIM types (SIM, USIM, or both)
+ * @reader: Reader name prefix to search for
  * Returns: Pointer to private data structure, or %NULL on failure
  *
  * This function is used to initialize SIM/USIM connection. PC/SC is used to
@@ -425,10 +495,10 @@ static int scard_get_aid(struct scard_data *scard, unsigned char *aid,
  * access some of the card functions. Once the connection is not needed
  * anymore, scard_deinit() can be used to close it.
  */
-struct scard_data * scard_init(scard_sim_type sim_type)
+struct scard_data * scard_init(scard_sim_type sim_type, const char *reader)
 {
        long ret;
-       unsigned long len;
+       unsigned long len, pos;
        struct scard_data *scard;
 #ifdef CONFIG_NATIVE_WINDOWS
        TCHAR *readers = NULL;
@@ -482,18 +552,41 @@ struct scard_data * scard_init(scard_sim_type sim_type)
                           "available.");
                goto failed;
        }
-       /* readers is a list of available reader. Last entry is terminated with
-        * double NUL.
-        * TODO: add support for selecting the reader; now just use the first
-        * one.. */
+       wpa_hexdump_ascii(MSG_DEBUG, "SCARD: Readers", (u8 *) readers, len);
+       /*
+        * readers is a list of available readers. The last entry is terminated
+        * with double null.
+        */
+       pos = 0;
+#ifdef UNICODE
+       /* TODO */
+#else /* UNICODE */
+       while (pos < len) {
+               if (reader == NULL ||
+                   os_strncmp(&readers[pos], reader, os_strlen(reader)) == 0)
+                       break;
+               while (pos < len && readers[pos])
+                       pos++;
+               pos++; /* skip separating null */
+               if (pos < len && readers[pos] == '\0')
+                       pos = len; /* double null terminates list */
+       }
+#endif /* UNICODE */
+       if (pos >= len) {
+               wpa_printf(MSG_WARNING, "SCARD: No reader with prefix '%s' "
+                          "found", reader);
+               goto failed;
+       }
+
 #ifdef UNICODE
-       wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%S'", readers);
+       wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%S'", &readers[pos]);
 #else /* UNICODE */
-       wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%s'", readers);
+       wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%s'", &readers[pos]);
 #endif /* UNICODE */
 
-       ret = SCardConnect(scard->ctx, readers, SCARD_SHARE_SHARED,
-                          SCARD_PROTOCOL_T0, &scard->card, &scard->protocol);
+       ret = SCardConnect(scard->ctx, &readers[pos], SCARD_SHARE_SHARED,
+                          SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
+                          &scard->card, &scard->protocol);
        if (ret != SCARD_S_SUCCESS) {
                if (ret == (long) SCARD_E_NO_SMARTCARD)
                        wpa_printf(MSG_INFO, "No smart card inserted.");
@@ -582,7 +675,8 @@ struct scard_data * scard_init(scard_sim_type sim_type)
        }
        if (pin_needed) {
                scard->pin1_required = 1;
-               wpa_printf(MSG_DEBUG, "PIN1 needed for SIM access");
+               wpa_printf(MSG_DEBUG, "PIN1 needed for SIM access (retry "
+                          "counter=%d)", scard_get_pin_retry_counter(scard));
        }
 
        ret = SCardEndTransaction(scard->card, SCARD_LEAVE_CARD);
@@ -939,6 +1033,46 @@ static int scard_verify_pin(struct scard_data *scard, const char *pin)
 }
 
 
+int scard_get_pin_retry_counter(struct scard_data *scard)
+{
+       long ret;
+       unsigned char resp[3];
+       unsigned char cmd[5] = { SIM_CMD_VERIFY_CHV1 };
+       size_t len;
+       u16 val;
+
+       wpa_printf(MSG_DEBUG, "SCARD: fetching PIN retry counter");
+
+       if (scard->sim_type == SCARD_USIM)
+               cmd[0] = USIM_CLA;
+       cmd[4] = 0; /* Empty data */
+
+       len = sizeof(resp);
+       ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len);
+       if (ret != SCARD_S_SUCCESS)
+               return -2;
+
+       if (len != 2) {
+               wpa_printf(MSG_WARNING, "SCARD: failed to fetch PIN retry "
+                          "counter");
+               return -1;
+       }
+
+       val = WPA_GET_BE16(resp);
+       if (val == 0x63c0 || val == 0x6983) {
+               wpa_printf(MSG_DEBUG, "SCARD: PIN has been blocked");
+               return 0;
+       }
+
+       if (val >= 0x63c0 && val <= 0x63cf)
+               return val & 0x000f;
+
+       wpa_printf(MSG_DEBUG, "SCARD: Unexpected PIN retry counter response "
+                  "value 0x%x", val);
+       return 0;
+}
+
+
 /**
  * scard_get_imsi - Read IMSI from SIM/USIM card
  * @scard: Pointer to private data from scard_init()
@@ -1285,3 +1419,9 @@ int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand,
        wpa_printf(MSG_DEBUG, "SCARD: Unrecognized response");
        return -1;
 }
+
+
+int scard_supports_umts(struct scard_data *scard)
+{
+       return scard->sim_type == SCARD_USIM;
+}
index 2fd3610..b4ebc99 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM
- * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2006, 2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -9,26 +9,6 @@
 #ifndef PCSC_FUNCS_H
 #define PCSC_FUNCS_H
 
-/* GSM files
- * File type in first octet:
- * 3F = Master File
- * 7F = Dedicated File
- * 2F = Elementary File under the Master File
- * 6F = Elementary File under a Dedicated File
- */
-#define SCARD_FILE_MF          0x3F00
-#define SCARD_FILE_GSM_DF      0x7F20
-#define SCARD_FILE_UMTS_DF     0x7F50
-#define SCARD_FILE_GSM_EF_IMSI 0x6F07
-#define SCARD_FILE_GSM_EF_AD   0x6FAD
-#define SCARD_FILE_EF_DIR      0x2F00
-#define SCARD_FILE_EF_ICCID    0x2FE2
-#define SCARD_FILE_EF_CK       0x6FE1
-#define SCARD_FILE_EF_IK       0x6FE2
-
-#define SCARD_CHV1_OFFSET      13
-#define SCARD_CHV1_FLAG                0x80
-
 typedef enum {
        SCARD_GSM_SIM_ONLY,
        SCARD_USIM_ONLY,
@@ -37,7 +17,7 @@ typedef enum {
 
 
 #ifdef PCSC_FUNCS
-struct scard_data * scard_init(scard_sim_type sim_type);
+struct scard_data * scard_init(scard_sim_type sim_type, const char *reader);
 void scard_deinit(struct scard_data *scard);
 
 int scard_set_pin(struct scard_data *scard, const char *pin);
@@ -49,15 +29,20 @@ int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand,
                    const unsigned char *autn,
                    unsigned char *res, size_t *res_len,
                    unsigned char *ik, unsigned char *ck, unsigned char *auts);
+int scard_get_pin_retry_counter(struct scard_data *scard);
+int scard_supports_umts(struct scard_data *scard);
 
 #else /* PCSC_FUNCS */
 
-#define scard_init(s) NULL
+#define scard_init(s, r) NULL
 #define scard_deinit(s) do { } while (0)
 #define scard_set_pin(s, p) -1
 #define scard_get_imsi(s, i, l) -1
+#define scard_get_mnc_len(s) -1
 #define scard_gsm_auth(s, r, s2, k) -1
 #define scard_umts_auth(s, r, a, r2, rl, i, c, a2) -1
+#define scard_get_pin_retry_counter(s) -1
+#define scard_supports_umts(s) 0
 
 #endif /* PCSC_FUNCS */
 
index a8b9106..5511ef1 100644 (file)
 static int wpa_debug_syslog = 0;
 #endif /* CONFIG_DEBUG_SYSLOG */
 
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+
+static FILE *wpa_debug_tracing_file = NULL;
+
+#define WPAS_TRACE_PFX "wpas <%d>: "
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
+
 
 int wpa_debug_level = MSG_INFO;
 int wpa_debug_show_keys = 0;
@@ -30,25 +42,18 @@ int wpa_debug_timestamp = 0;
 #define ANDROID_LOG_NAME       "wpa_supplicant"
 #endif /* ANDROID_LOG_NAME */
 
-void android_printf(int level, char *format, ...)
+static int wpa_to_android_level(int level)
 {
-       if (level >= wpa_debug_level) {
-               va_list ap;
-               if (level == MSG_ERROR)
-                       level = ANDROID_LOG_ERROR;
-               else if (level == MSG_WARNING)
-                       level = ANDROID_LOG_WARN;
-               else if (level == MSG_INFO)
-                       level = ANDROID_LOG_INFO;
-               else
-                       level = ANDROID_LOG_DEBUG;
-               va_start(ap, format);
-               __android_log_vprint(level, ANDROID_LOG_NAME, format, ap);
-               va_end(ap);
-       }
+       if (level == MSG_ERROR)
+               return ANDROID_LOG_ERROR;
+       if (level == MSG_WARNING)
+               return ANDROID_LOG_WARN;
+       if (level == MSG_INFO)
+               return ANDROID_LOG_INFO;
+       return ANDROID_LOG_DEBUG;
 }
 
-#else /* CONFIG_ANDROID_LOG */
+#endif /* CONFIG_ANDROID_LOG */
 
 #ifndef CONFIG_NO_STDOUT_DEBUG
 
@@ -59,6 +64,7 @@ static FILE *out_file = NULL;
 
 void wpa_debug_print_timestamp(void)
 {
+#ifndef CONFIG_ANDROID_LOG
        struct os_time tv;
 
        if (!wpa_debug_timestamp)
@@ -72,6 +78,7 @@ void wpa_debug_print_timestamp(void)
        } else
 #endif /* CONFIG_DEBUG_FILE */
        printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec);
+#endif /* CONFIG_ANDROID_LOG */
 }
 
 
@@ -112,6 +119,77 @@ static int syslog_priority(int level)
 #endif /* CONFIG_DEBUG_SYSLOG */
 
 
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+
+int wpa_debug_open_linux_tracing(void)
+{
+       int mounts, trace_fd;
+       char buf[4096] = {};
+       ssize_t buflen;
+       char *line, *tmp1, *path = NULL;
+
+       mounts = open("/proc/mounts", O_RDONLY);
+       if (mounts < 0) {
+               printf("no /proc/mounts\n");
+               return -1;
+       }
+
+       buflen = read(mounts, buf, sizeof(buf) - 1);
+       close(mounts);
+       if (buflen < 0) {
+               printf("failed to read /proc/mounts\n");
+               return -1;
+       }
+
+       line = strtok_r(buf, "\n", &tmp1);
+       while (line) {
+               char *tmp2, *tmp_path, *fstype;
+               /* "<dev> <mountpoint> <fs type> ..." */
+               strtok_r(line, " ", &tmp2);
+               tmp_path = strtok_r(NULL, " ", &tmp2);
+               fstype = strtok_r(NULL, " ", &tmp2);
+               if (strcmp(fstype, "debugfs") == 0) {
+                       path = tmp_path;
+                       break;
+               }
+
+               line = strtok_r(NULL, "\n", &tmp1);
+       }
+
+       if (path == NULL) {
+               printf("debugfs mountpoint not found\n");
+               return -1;
+       }
+
+       snprintf(buf, sizeof(buf) - 1, "%s/tracing/trace_marker", path);
+
+       trace_fd = open(buf, O_WRONLY);
+       if (trace_fd < 0) {
+               printf("failed to open trace_marker file\n");
+               return -1;
+       }
+       wpa_debug_tracing_file = fdopen(trace_fd, "w");
+       if (wpa_debug_tracing_file == NULL) {
+               close(trace_fd);
+               printf("failed to fdopen()\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+
+void wpa_debug_close_linux_tracing(void)
+{
+       if (wpa_debug_tracing_file == NULL)
+               return;
+       fclose(wpa_debug_tracing_file);
+       wpa_debug_tracing_file = NULL;
+}
+
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
+
+
 /**
  * wpa_printf - conditional printf
  * @level: priority level (MSG_*) of the message
@@ -129,6 +207,10 @@ void wpa_printf(int level, const char *fmt, ...)
 
        va_start(ap, fmt);
        if (level >= wpa_debug_level) {
+#ifdef CONFIG_ANDROID_LOG
+               __android_log_vprint(wpa_to_android_level(level),
+                                    ANDROID_LOG_NAME, fmt, ap);
+#else /* CONFIG_ANDROID_LOG */
 #ifdef CONFIG_DEBUG_SYSLOG
                if (wpa_debug_syslog) {
                        vsyslog(syslog_priority(level), fmt, ap);
@@ -149,8 +231,20 @@ void wpa_printf(int level, const char *fmt, ...)
 #ifdef CONFIG_DEBUG_SYSLOG
                }
 #endif /* CONFIG_DEBUG_SYSLOG */
+#endif /* CONFIG_ANDROID_LOG */
        }
        va_end(ap);
+
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+       if (wpa_debug_tracing_file != NULL) {
+               va_start(ap, fmt);
+               fprintf(wpa_debug_tracing_file, WPAS_TRACE_PFX, level);
+               vfprintf(wpa_debug_tracing_file, fmt, ap);
+               fprintf(wpa_debug_tracing_file, "\n");
+               fflush(wpa_debug_tracing_file);
+               va_end(ap);
+       }
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
 }
 
 
@@ -158,8 +252,65 @@ static void _wpa_hexdump(int level, const char *title, const u8 *buf,
                         size_t len, int show)
 {
        size_t i;
+
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+       if (wpa_debug_tracing_file != NULL) {
+               fprintf(wpa_debug_tracing_file,
+                       WPAS_TRACE_PFX "%s - hexdump(len=%lu):",
+                       level, title, (unsigned long) len);
+               if (buf == NULL) {
+                       fprintf(wpa_debug_tracing_file, " [NULL]\n");
+               } else if (!show) {
+                       fprintf(wpa_debug_tracing_file, " [REMOVED]\n");
+               } else {
+                       for (i = 0; i < len; i++)
+                               fprintf(wpa_debug_tracing_file,
+                                       " %02x", buf[i]);
+               }
+               fflush(wpa_debug_tracing_file);
+       }
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
+
        if (level < wpa_debug_level)
                return;
+#ifdef CONFIG_ANDROID_LOG
+       {
+               const char *display;
+               char *strbuf = NULL;
+               size_t slen = len;
+               if (buf == NULL) {
+                       display = " [NULL]";
+               } else if (len == 0) {
+                       display = "";
+               } else if (show && len) {
+                       /* Limit debug message length for Android log */
+                       if (slen > 32)
+                               slen = 32;
+                       strbuf = os_malloc(1 + 3 * slen);
+                       if (strbuf == NULL) {
+                               wpa_printf(MSG_ERROR, "wpa_hexdump: Failed to "
+                                          "allocate message buffer");
+                               return;
+                       }
+
+                       for (i = 0; i < slen; i++)
+                               os_snprintf(&strbuf[i * 3], 4, " %02x",
+                                           buf[i]);
+
+                       display = strbuf;
+               } else {
+                       display = " [REMOVED]";
+               }
+
+               __android_log_print(wpa_to_android_level(level),
+                                   ANDROID_LOG_NAME,
+                                   "%s - hexdump(len=%lu):%s%s",
+                                   title, (long unsigned int) len, display,
+                                   len > slen ? " ..." : "");
+               os_free(strbuf);
+               return;
+       }
+#else /* CONFIG_ANDROID_LOG */
 #ifdef CONFIG_DEBUG_SYSLOG
        if (wpa_debug_syslog) {
                const char *display;
@@ -187,7 +338,7 @@ static void _wpa_hexdump(int level, const char *title, const u8 *buf,
                }
 
                syslog(syslog_priority(level), "%s - hexdump(len=%lu):%s",
-                      title, len, display);
+                      title, (unsigned long) len, display);
                os_free(strbuf);
                return;
        }
@@ -221,6 +372,7 @@ static void _wpa_hexdump(int level, const char *title, const u8 *buf,
 #ifdef CONFIG_DEBUG_FILE
        }
 #endif /* CONFIG_DEBUG_FILE */
+#endif /* CONFIG_ANDROID_LOG */
 }
 
 void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len)
@@ -242,8 +394,30 @@ static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
        const u8 *pos = buf;
        const size_t line_len = 16;
 
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+       if (wpa_debug_tracing_file != NULL) {
+               fprintf(wpa_debug_tracing_file,
+                       WPAS_TRACE_PFX "%s - hexdump_ascii(len=%lu):",
+                       level, title, (unsigned long) len);
+               if (buf == NULL) {
+                       fprintf(wpa_debug_tracing_file, " [NULL]\n");
+               } else if (!show) {
+                       fprintf(wpa_debug_tracing_file, " [REMOVED]\n");
+               } else {
+                       /* can do ascii processing in userspace */
+                       for (i = 0; i < len; i++)
+                               fprintf(wpa_debug_tracing_file,
+                                       " %02x", buf[i]);
+               }
+               fflush(wpa_debug_tracing_file);
+       }
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
+
        if (level < wpa_debug_level)
                return;
+#ifdef CONFIG_ANDROID_LOG
+       _wpa_hexdump(level, title, buf, len, show);
+#else /* CONFIG_ANDROID_LOG */
        wpa_debug_print_timestamp();
 #ifdef CONFIG_DEBUG_FILE
        if (out_file) {
@@ -317,6 +491,7 @@ static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
 #ifdef CONFIG_DEBUG_FILE
        }
 #endif /* CONFIG_DEBUG_FILE */
+#endif /* CONFIG_ANDROID_LOG */
 }
 
 
@@ -398,7 +573,6 @@ void wpa_debug_close_file(void)
 
 #endif /* CONFIG_NO_STDOUT_DEBUG */
 
-#endif /* CONFIG_ANDROID_LOG */
 
 #ifndef CONFIG_NO_WPA_MSG
 static wpa_msg_cb_func wpa_msg_cb = NULL;
index bbef49b..339c749 100644 (file)
@@ -18,32 +18,6 @@ enum {
        MSG_EXCESSIVE, MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR
 };
 
-#ifdef CONFIG_ANDROID_LOG
-
-#define wpa_debug_print_timestamp() do {} while (0)
-#define wpa_hexdump(...)            do {} while (0)
-#define wpa_hexdump_key(...)        do {} while (0)
-#define wpa_hexdump_buf(l,t,b)      do {} while (0)
-#define wpa_hexdump_buf_key(l,t,b)  do {} while (0)
-#define wpa_hexdump_ascii(...)      do {} while (0)
-#define wpa_hexdump_ascii_key(...)  do {} while (0)
-#define wpa_debug_open_file(...)    do {} while (0)
-#define wpa_debug_close_file()      do {} while (0)
-#define wpa_dbg(...)                do {} while (0)
-
-static inline int wpa_debug_reopen_file(void)
-{
-       return 0;
-}
-
-
-void android_printf(int level, char *format, ...)
-PRINTF_FORMAT(2, 3);
-
-#define wpa_printf android_printf
-
-#else /* CONFIG_ANDROID_LOG */
-
 #ifdef CONFIG_NO_STDOUT_DEBUG
 
 #define wpa_debug_print_timestamp() do { } while (0)
@@ -177,8 +151,6 @@ void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
 
 #endif /* CONFIG_NO_STDOUT_DEBUG */
 
-#endif /* CONFIG_ANDROID_LOG */
-
 
 #ifdef CONFIG_NO_WPA_MSG
 #define wpa_msg(args...) do { } while (0)
@@ -283,6 +255,24 @@ static inline void wpa_debug_close_syslog(void)
 
 #endif /* CONFIG_DEBUG_SYSLOG */
 
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+
+int wpa_debug_open_linux_tracing(void);
+void wpa_debug_close_linux_tracing(void);
+
+#else /* CONFIG_DEBUG_LINUX_TRACING */
+
+static inline int wpa_debug_open_linux_tracing(void)
+{
+       return 0;
+}
+
+static inline void wpa_debug_close_linux_tracing(void)
+{
+}
+
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
+
 
 #ifdef EAPOL_TEST
 #define WPA_ASSERT(a)                                                 \
index 9baec7f..7630ecb 100644 (file)
@@ -1,16 +1,10 @@
 /*
  * NDEF(NFC Data Exchange Format) routines for Wi-Fi Protected Setup
  *   Reference is "NFCForum-TS-NDEF_1.0 2006-07-24".
- * Copyright (c) 2009, Masashi Honma <honma@ictec.co.jp>
+ * Copyright (c) 2009-2012, Masashi Honma <masashi.honma@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.
  */
 
 #include "includes.h"
@@ -26,9 +20,9 @@
 #define FLAG_TNF_RFC2046 (0x02)
 
 struct ndef_record {
-       u8 *type;
-       u8 *id;
-       u8 *payload;
+       const u8 *type;
+       const u8 *id;
+       const u8 *payload;
        u8 type_length;
        u8 id_length;
        u32 payload_length;
@@ -37,9 +31,10 @@ struct ndef_record {
 
 static char wifi_handover_type[] = "application/vnd.wfa.wsc";
 
-static int ndef_parse_record(u8 *data, u32 size, struct ndef_record *record)
+static int ndef_parse_record(const u8 *data, u32 size,
+                            struct ndef_record *record)
 {
-       u8 *pos = data + 1;
+       const u8 *pos = data + 1;
 
        if (size < 2)
                return -1;
@@ -78,12 +73,12 @@ static int ndef_parse_record(u8 *data, u32 size, struct ndef_record *record)
 }
 
 
-static struct wpabuf * ndef_parse_records(struct wpabuf *buf,
+static struct wpabuf * ndef_parse_records(const struct wpabuf *buf,
                                          int (*filter)(struct ndef_record *))
 {
        struct ndef_record record;
        int len = wpabuf_len(buf);
-       u8 *data = wpabuf_mhead(buf);
+       const u8 *data = wpabuf_head(buf);
 
        while (len > 0) {
                if (ndef_parse_record(data, len, &record) < 0) {
@@ -103,13 +98,14 @@ static struct wpabuf * ndef_parse_records(struct wpabuf *buf,
 
 static struct wpabuf * ndef_build_record(u8 flags, void *type,
                                         u8 type_length, void *id,
-                                        u8 id_length, void *payload,
-                                        u32 payload_length)
+                                        u8 id_length,
+                                        const struct wpabuf *payload)
 {
        struct wpabuf *record;
        size_t total_len;
        int short_record;
        u8 local_flag;
+       size_t payload_length = wpabuf_len(payload);
 
        short_record = payload_length < 256 ? 1 : 0;
 
@@ -144,7 +140,7 @@ static struct wpabuf * ndef_build_record(u8 flags, void *type,
                wpabuf_put_u8(record, id_length);
        wpabuf_put_data(record, type, type_length);
        wpabuf_put_data(record, id, id_length);
-       wpabuf_put_data(record, payload, payload_length);
+       wpabuf_put_buf(record, payload);
        return record;
 }
 
@@ -160,16 +156,15 @@ static int wifi_filter(struct ndef_record *record)
 }
 
 
-struct wpabuf * ndef_parse_wifi(struct wpabuf *buf)
+struct wpabuf * ndef_parse_wifi(const struct wpabuf *buf)
 {
        return ndef_parse_records(buf, wifi_filter);
 }
 
 
-struct wpabuf * ndef_build_wifi(struct wpabuf *buf)
+struct wpabuf * ndef_build_wifi(const struct wpabuf *buf)
 {
        return ndef_build_record(FLAG_MESSAGE_BEGIN | FLAG_MESSAGE_END |
                                 FLAG_TNF_RFC2046, wifi_handover_type,
-                                os_strlen(wifi_handover_type), NULL, 0,
-                                wpabuf_mhead(buf), wpabuf_len(buf));
+                                os_strlen(wifi_handover_type), NULL, 0, buf);
 }
index 9422c71..5453962 100644 (file)
@@ -56,6 +56,23 @@ struct wps_data * wps_init(const struct wps_config *cfg)
                data->dev_password_len = cfg->pin_len;
        }
 
+#ifdef CONFIG_WPS_NFC
+       if (cfg->wps->ap && !cfg->registrar && cfg->wps->ap_nfc_dev_pw_id) {
+               data->dev_pw_id = cfg->wps->ap_nfc_dev_pw_id;
+               os_free(data->dev_password);
+               data->dev_password =
+                       os_malloc(wpabuf_len(cfg->wps->ap_nfc_dev_pw));
+               if (data->dev_password == NULL) {
+                       os_free(data);
+                       return NULL;
+               }
+               os_memcpy(data->dev_password,
+                         wpabuf_head(cfg->wps->ap_nfc_dev_pw),
+                         wpabuf_len(cfg->wps->ap_nfc_dev_pw));
+               data->dev_password_len = wpabuf_len(cfg->wps->ap_nfc_dev_pw);
+       }
+#endif /* CONFIG_WPS_NFC */
+
        data->pbc = cfg->pbc;
        if (cfg->pbc) {
                /* Use special PIN '00000000' for PBC */
@@ -118,6 +135,12 @@ struct wps_data * wps_init(const struct wps_config *cfg)
  */
 void wps_deinit(struct wps_data *data)
 {
+#ifdef CONFIG_WPS_NFC
+       if (data->registrar && data->nfc_pw_token)
+               wps_registrar_remove_nfc_pw_token(data->wps->registrar,
+                                                 data->nfc_pw_token);
+#endif /* CONFIG_WPS_NFC */
+
        if (data->wps_pin_revealed) {
                wpa_printf(MSG_DEBUG, "WPS: Full PIN information revealed and "
                           "negotiation failed");
@@ -136,6 +159,7 @@ void wps_deinit(struct wps_data *data)
        wps_device_data_free(&data->peer_dev);
        os_free(data->new_ap_settings);
        dh5_free(data->dh_ctx);
+       os_free(data->nfc_pw_token);
        os_free(data);
 }
 
@@ -431,7 +455,8 @@ struct wpabuf * wps_build_assoc_resp_ie(void)
 
 /**
  * wps_build_probe_req_ie - Build WPS IE for Probe Request
- * @pbc: Whether searching for PBC mode APs
+ * @pw_id: Password ID (DEV_PW_PUSHBUTTON for active PBC and DEV_PW_DEFAULT for
+ * most other use cases)
  * @dev: Device attributes
  * @uuid: Own UUID
  * @req_type: Value for Request Type attribute
@@ -442,7 +467,7 @@ struct wpabuf * wps_build_assoc_resp_ie(void)
  *
  * The caller is responsible for freeing the buffer.
  */
-struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev,
+struct wpabuf * wps_build_probe_req_ie(u16 pw_id, struct wps_device_data *dev,
                                       const u8 *uuid,
                                       enum wps_request_type req_type,
                                       unsigned int num_req_dev_types,
@@ -464,8 +489,7 @@ struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev,
            wps_build_rf_bands(dev, ie) ||
            wps_build_assoc_state(NULL, ie) ||
            wps_build_config_error(ie, WPS_CFG_NO_ERROR) ||
-           wps_build_dev_password_id(ie, pbc ? DEV_PW_PUSHBUTTON :
-                                     DEV_PW_DEFAULT) ||
+           wps_build_dev_password_id(ie, pw_id) ||
 #ifdef CONFIG_WPS2
            wps_build_manufacturer(dev, ie) ||
            wps_build_model_name(dev, ie) ||
index 22e029f..c45b68c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Wi-Fi Protected Setup
- * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -27,6 +27,7 @@ enum wsc_op_code {
 struct wps_registrar;
 struct upnp_wps_device_sm;
 struct wps_er;
+struct wps_parse_attr;
 
 /**
  * struct wps_credential - WPS Credential
@@ -94,6 +95,7 @@ struct wps_device_data {
        u32 os_version;
        u8 rf_bands;
        u16 config_methods;
+       struct wpabuf *vendor_ext_m1;
        struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
 
        int p2p;
@@ -238,7 +240,7 @@ int wps_is_20(const struct wpabuf *msg);
 
 struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type);
 struct wpabuf * wps_build_assoc_resp_ie(void);
-struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev,
+struct wpabuf * wps_build_probe_req_ie(u16 pw_id, struct wps_device_data *dev,
                                       const u8 *uuid,
                                       enum wps_request_type req_type,
                                       unsigned int num_req_dev_types,
@@ -294,12 +296,15 @@ struct wps_registrar_config {
         * @ctx: Higher layer context data (cb_ctx)
         * @mac_addr: MAC address of the Enrollee
         * @uuid_e: UUID-E of the Enrollee
+        * @dev_pw: Device Password (PIN) used during registration
+        * @dev_pw_len: Length of dev_pw in octets
         *
         * This callback is called whenever an Enrollee completes registration
         * successfully.
         */
        void (*reg_success_cb)(void *ctx, const u8 *mac_addr,
-                              const u8 *uuid_e);
+                              const u8 *uuid_e, const u8 *dev_pw,
+                              size_t dev_pw_len);
 
        /**
         * set_sel_reg_cb - Callback for reporting selected registrar changes
@@ -752,6 +757,11 @@ struct wps_context {
 
        /* Pending messages from UPnP PutWLANResponse */
        struct upnp_pending_message *upnp_msgs;
+
+       u16 ap_nfc_dev_pw_id;
+       struct wpabuf *ap_nfc_dh_pubkey;
+       struct wpabuf *ap_nfc_dh_privkey;
+       struct wpabuf *ap_nfc_dev_pw;
 };
 
 struct oob_device_data {
@@ -783,7 +793,8 @@ int wps_registrar_wps_cancel(struct wps_registrar *reg);
 int wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid);
 int wps_registrar_button_pushed(struct wps_registrar *reg,
                                const u8 *p2p_dev_addr);
-void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e);
+void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e,
+                           const u8 *dev_pw, size_t dev_pw_len);
 void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,
                                const struct wpabuf *wps_data,
                                int p2p_wildcard);
@@ -792,6 +803,12 @@ int wps_registrar_get_info(struct wps_registrar *reg, const u8 *addr,
                           char *buf, size_t buflen);
 int wps_registrar_config_ap(struct wps_registrar *reg,
                            struct wps_credential *cred);
+int wps_registrar_add_nfc_pw_token(struct wps_registrar *reg,
+                                  const u8 *pubkey_hash, u16 pw_id,
+                                  const u8 *dev_pw, size_t dev_pw_len);
+int wps_registrar_add_nfc_password_token(struct wps_registrar *reg,
+                                        const u8 *oob_dev_pw,
+                                        size_t oob_dev_pw_len);
 
 int wps_build_credential_wrap(struct wpabuf *msg,
                              const struct wps_credential *cred);
@@ -799,6 +816,7 @@ int wps_build_credential_wrap(struct wpabuf *msg,
 unsigned int wps_pin_checksum(unsigned int pin);
 unsigned int wps_pin_valid(unsigned int pin);
 unsigned int wps_generate_pin(void);
+int wps_pin_str_valid(const char *pin);
 void wps_free_pending_msgs(struct upnp_pending_message *msgs);
 
 struct oob_device_data * wps_get_oob_device(char *device_type);
@@ -806,6 +824,8 @@ struct oob_nfc_device_data * wps_get_oob_nfc_device(char *device_name);
 int wps_get_oob_method(char *method);
 int wps_process_oob(struct wps_context *wps, struct oob_device_data *oob_dev,
                    int registrar);
+struct wpabuf * wps_get_oob_cred(struct wps_context *wps);
+int wps_oob_use_cred(struct wps_context *wps, struct wps_parse_attr *attr);
 int wps_attr_text(struct wpabuf *data, char *buf, char *end);
 
 struct wps_er * wps_er_init(struct wps_context *wps, const char *ifname,
@@ -821,12 +841,23 @@ int wps_er_set_config(struct wps_er *er, const u8 *uuid,
                      const struct wps_credential *cred);
 int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *pin,
                  size_t pin_len, const struct wps_credential *cred);
+struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid);
 
 int wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN]);
 char * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf,
                            size_t buf_len);
 void uuid_gen_mac_addr(const u8 *mac_addr, u8 *uuid);
 u16 wps_config_methods_str2bin(const char *str);
+struct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id,
+                                      const struct wpabuf *pubkey,
+                                      const struct wpabuf *dev_pw);
+struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,
+                                 struct wpabuf **privkey,
+                                 struct wpabuf **dev_pw);
+
+/* ndef.c */
+struct wpabuf * ndef_parse_wifi(const struct wpabuf *buf);
+struct wpabuf * ndef_build_wifi(const struct wpabuf *buf);
 
 #ifdef CONFIG_WPS_STRICT
 int wps_validate_beacon(const struct wpabuf *wps_ie);
index 753083d..9be30b9 100644 (file)
@@ -30,6 +30,14 @@ int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg)
                wps->dh_ctx = wps->wps->dh_ctx;
                wps->wps->dh_ctx = NULL;
                pubkey = wpabuf_dup(wps->wps->dh_pubkey);
+#ifdef CONFIG_WPS_NFC
+       } else if (wps->dev_pw_id >= 0x10 && wps->wps->ap &&
+                  wps->dev_pw_id == wps->wps->ap_nfc_dev_pw_id) {
+               wpa_printf(MSG_DEBUG, "WPS: Using NFC password token DH keys");
+               wps->dh_privkey = wpabuf_dup(wps->wps->ap_nfc_dh_privkey);
+               pubkey = wpabuf_dup(wps->wps->ap_nfc_dh_pubkey);
+               wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, pubkey);
+#endif /* CONFIG_WPS_NFC */
        } else {
                wpa_printf(MSG_DEBUG, "WPS: Generate new DH keys");
                wps->dh_privkey = NULL;
@@ -340,19 +348,34 @@ int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg,
 
 
 #ifdef CONFIG_WPS_OOB
-int wps_build_oob_dev_password(struct wpabuf *msg, struct wps_context *wps)
+int wps_build_oob_dev_pw(struct wpabuf *msg, u16 dev_pw_id,
+                        const struct wpabuf *pubkey, const u8 *dev_pw,
+                        size_t dev_pw_len)
 {
        size_t hash_len;
        const u8 *addr[1];
        u8 pubkey_hash[WPS_HASH_LEN];
+
+       addr[0] = wpabuf_head(pubkey);
+       hash_len = wpabuf_len(pubkey);
+       sha256_vector(1, addr, &hash_len, pubkey_hash);
+
+       wpabuf_put_be16(msg, ATTR_OOB_DEVICE_PASSWORD);
+       wpabuf_put_be16(msg, WPS_OOB_PUBKEY_HASH_LEN + 2 + dev_pw_len);
+       wpabuf_put_data(msg, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
+       wpabuf_put_be16(msg, dev_pw_id);
+       wpabuf_put_data(msg, dev_pw, dev_pw_len);
+
+       return 0;
+}
+
+
+int wps_build_oob_dev_password(struct wpabuf *msg, struct wps_context *wps)
+{
        u8 dev_password_bin[WPS_OOB_DEVICE_PASSWORD_LEN];
 
        wpa_printf(MSG_DEBUG, "WPS:  * OOB Device Password");
 
-       addr[0] = wpabuf_head(wps->dh_pubkey);
-       hash_len = wpabuf_len(wps->dh_pubkey);
-       sha256_vector(1, addr, &hash_len, pubkey_hash);
-
        if (os_get_random((u8 *) &wps->oob_dev_pw_id, sizeof(u16)) < 0) {
                wpa_printf(MSG_ERROR, "WPS: device password id "
                           "generation error");
@@ -367,19 +390,15 @@ int wps_build_oob_dev_password(struct wpabuf *msg, struct wps_context *wps)
                return -1;
        }
 
-       wpabuf_put_be16(msg, ATTR_OOB_DEVICE_PASSWORD);
-       wpabuf_put_be16(msg, WPS_OOB_DEVICE_PASSWORD_ATTR_LEN);
-       wpabuf_put_data(msg, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
-       wpabuf_put_be16(msg, wps->oob_dev_pw_id);
-       wpabuf_put_data(msg, dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN);
-
        wpa_snprintf_hex_uppercase(
                wpabuf_put(wps->oob_conf.dev_password,
                           wpabuf_size(wps->oob_conf.dev_password)),
                wpabuf_size(wps->oob_conf.dev_password),
                dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN);
 
-       return 0;
+       return wps_build_oob_dev_pw(msg, wps->oob_dev_pw_id, wps->dh_pubkey,
+                                   dev_password_bin,
+                                   WPS_OOB_DEVICE_PASSWORD_LEN);
 }
 #endif /* CONFIG_WPS_OOB */
 
index f5ad403..5aa9b00 100644 (file)
@@ -9,7 +9,8 @@
 #include "includes.h"
 
 #include "common.h"
-#include "wps_i.h"
+#include "wps_defs.h"
+#include "wps_attr_parse.h"
 
 #ifndef CONFIG_WPS_STRICT
 #define WPS_WORKAROUNDS
@@ -262,12 +263,16 @@ static int wps_set_attr(struct wps_parse_attr *attr, u16 type,
                attr->dev_password_id = pos;
                break;
        case ATTR_OOB_DEVICE_PASSWORD:
-               if (len != WPS_OOB_DEVICE_PASSWORD_ATTR_LEN) {
+               if (len < WPS_OOB_PUBKEY_HASH_LEN + 2 +
+                   WPS_OOB_DEVICE_PASSWORD_MIN_LEN ||
+                   len > WPS_OOB_PUBKEY_HASH_LEN + 2 +
+                   WPS_OOB_DEVICE_PASSWORD_LEN) {
                        wpa_printf(MSG_DEBUG, "WPS: Invalid OOB Device "
                                   "Password length %u", len);
                        return -1;
                }
                attr->oob_dev_password = pos;
+               attr->oob_dev_password_len = len;
                break;
        case ATTR_OS_VERSION:
                if (len != 4) {
diff --git a/src/wps/wps_attr_parse.h b/src/wps/wps_attr_parse.h
new file mode 100644 (file)
index 0000000..332e966
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Wi-Fi Protected Setup - attribute parsing
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPS_ATTR_PARSE_H
+#define WPS_ATTR_PARSE_H
+
+#include "wps.h"
+
+struct wps_parse_attr {
+       /* fixed length fields */
+       const u8 *version; /* 1 octet */
+       const u8 *version2; /* 1 octet */
+       const u8 *msg_type; /* 1 octet */
+       const u8 *enrollee_nonce; /* WPS_NONCE_LEN (16) octets */
+       const u8 *registrar_nonce; /* WPS_NONCE_LEN (16) octets */
+       const u8 *uuid_r; /* WPS_UUID_LEN (16) octets */
+       const u8 *uuid_e; /* WPS_UUID_LEN (16) octets */
+       const u8 *auth_type_flags; /* 2 octets */
+       const u8 *encr_type_flags; /* 2 octets */
+       const u8 *conn_type_flags; /* 1 octet */
+       const u8 *config_methods; /* 2 octets */
+       const u8 *sel_reg_config_methods; /* 2 octets */
+       const u8 *primary_dev_type; /* 8 octets */
+       const u8 *rf_bands; /* 1 octet */
+       const u8 *assoc_state; /* 2 octets */
+       const u8 *config_error; /* 2 octets */
+       const u8 *dev_password_id; /* 2 octets */
+       const u8 *os_version; /* 4 octets */
+       const u8 *wps_state; /* 1 octet */
+       const u8 *authenticator; /* WPS_AUTHENTICATOR_LEN (8) octets */
+       const u8 *r_hash1; /* WPS_HASH_LEN (32) octets */
+       const u8 *r_hash2; /* WPS_HASH_LEN (32) octets */
+       const u8 *e_hash1; /* WPS_HASH_LEN (32) octets */
+       const u8 *e_hash2; /* WPS_HASH_LEN (32) octets */
+       const u8 *r_snonce1; /* WPS_SECRET_NONCE_LEN (16) octets */
+       const u8 *r_snonce2; /* WPS_SECRET_NONCE_LEN (16) octets */
+       const u8 *e_snonce1; /* WPS_SECRET_NONCE_LEN (16) octets */
+       const u8 *e_snonce2; /* WPS_SECRET_NONCE_LEN (16) octets */
+       const u8 *key_wrap_auth; /* WPS_KWA_LEN (8) octets */
+       const u8 *auth_type; /* 2 octets */
+       const u8 *encr_type; /* 2 octets */
+       const u8 *network_idx; /* 1 octet */
+       const u8 *network_key_idx; /* 1 octet */
+       const u8 *mac_addr; /* ETH_ALEN (6) octets */
+       const u8 *key_prov_auto; /* 1 octet (Bool) */
+       const u8 *dot1x_enabled; /* 1 octet (Bool) */
+       const u8 *selected_registrar; /* 1 octet (Bool) */
+       const u8 *request_type; /* 1 octet */
+       const u8 *response_type; /* 1 octet */
+       const u8 *ap_setup_locked; /* 1 octet */
+       const u8 *settings_delay_time; /* 1 octet */
+       const u8 *network_key_shareable; /* 1 octet (Bool) */
+       const u8 *request_to_enroll; /* 1 octet (Bool) */
+
+       /* variable length fields */
+       const u8 *manufacturer;
+       size_t manufacturer_len;
+       const u8 *model_name;
+       size_t model_name_len;
+       const u8 *model_number;
+       size_t model_number_len;
+       const u8 *serial_number;
+       size_t serial_number_len;
+       const u8 *dev_name;
+       size_t dev_name_len;
+       const u8 *public_key;
+       size_t public_key_len;
+       const u8 *encr_settings;
+       size_t encr_settings_len;
+       const u8 *ssid; /* <= 32 octets */
+       size_t ssid_len;
+       const u8 *network_key; /* <= 64 octets */
+       size_t network_key_len;
+       const u8 *eap_type; /* <= 8 octets */
+       size_t eap_type_len;
+       const u8 *eap_identity; /* <= 64 octets */
+       size_t eap_identity_len;
+       const u8 *authorized_macs; /* <= 30 octets */
+       size_t authorized_macs_len;
+       const u8 *sec_dev_type_list; /* <= 128 octets */
+       size_t sec_dev_type_list_len;
+       const u8 *oob_dev_password; /* 38..54 octets */
+       size_t oob_dev_password_len;
+
+       /* attributes that can occur multiple times */
+#define MAX_CRED_COUNT 10
+       const u8 *cred[MAX_CRED_COUNT];
+       size_t cred_len[MAX_CRED_COUNT];
+       size_t num_cred;
+
+#define MAX_REQ_DEV_TYPE_COUNT 10
+       const u8 *req_dev_type[MAX_REQ_DEV_TYPE_COUNT];
+       size_t num_req_dev_type;
+
+       const u8 *vendor_ext[MAX_WPS_PARSE_VENDOR_EXT];
+       size_t vendor_ext_len[MAX_WPS_PARSE_VENDOR_EXT];
+       size_t num_vendor_ext;
+};
+
+int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr);
+
+#endif /* WPS_ATTR_PARSE_H */
index 2dff4b2..5a8817f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Wi-Fi Protected Setup - common functionality
- * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -249,6 +249,22 @@ unsigned int wps_generate_pin(void)
 }
 
 
+int wps_pin_str_valid(const char *pin)
+{
+       const char *p;
+       size_t len;
+
+       p = pin;
+       while (*p >= '0' && *p <= '9')
+               p++;
+       if (*p != '\0')
+               return 0;
+
+       len = p - pin;
+       return len == 4 || len == 8;
+}
+
+
 void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg,
                    u16 config_error, u16 error_indication)
 {
@@ -308,7 +324,7 @@ void wps_pbc_timeout_event(struct wps_context *wps)
 
 #ifdef CONFIG_WPS_OOB
 
-static struct wpabuf * wps_get_oob_cred(struct wps_context *wps)
+struct wpabuf * wps_get_oob_cred(struct wps_context *wps)
 {
        struct wps_data data;
        struct wpabuf *plain;
@@ -335,11 +351,35 @@ static struct wpabuf * wps_get_oob_cred(struct wps_context *wps)
 }
 
 
+struct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id,
+                                      const struct wpabuf *pubkey,
+                                      const struct wpabuf *dev_pw)
+{
+       struct wpabuf *data;
+
+       data = wpabuf_alloc(200);
+       if (data == NULL)
+               return NULL;
+
+       if (wps_build_version(data) ||
+           wps_build_oob_dev_pw(data, dev_pw_id, pubkey,
+                                wpabuf_head(dev_pw), wpabuf_len(dev_pw)) ||
+           wps_build_wfa_ext(data, 0, NULL, 0)) {
+               wpa_printf(MSG_ERROR, "WPS: Failed to build NFC password "
+                          "token");
+               wpabuf_free(data);
+               return NULL;
+       }
+
+       return data;
+}
+
+
 static struct wpabuf * wps_get_oob_dev_pwd(struct wps_context *wps)
 {
        struct wpabuf *data;
 
-       data = wpabuf_alloc(9 + WPS_OOB_DEVICE_PASSWORD_ATTR_LEN);
+       data = wpabuf_alloc(200);
        if (data == NULL) {
                wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
                           "device password attribute");
@@ -375,6 +415,7 @@ static int wps_parse_oob_dev_pwd(struct wps_context *wps,
        struct oob_conf_data *oob_conf = &wps->oob_conf;
        struct wps_parse_attr attr;
        const u8 *pos;
+       size_t pw_len;
 
        if (wps_parse_msg(data, &attr) < 0 ||
            attr.oob_dev_password == NULL) {
@@ -384,6 +425,7 @@ static int wps_parse_oob_dev_pwd(struct wps_context *wps,
 
        pos = attr.oob_dev_password;
 
+       wpabuf_free(oob_conf->pubkey_hash);
        oob_conf->pubkey_hash =
                wpabuf_alloc_copy(pos, WPS_OOB_PUBKEY_HASH_LEN);
        if (oob_conf->pubkey_hash == NULL) {
@@ -396,39 +438,32 @@ static int wps_parse_oob_dev_pwd(struct wps_context *wps,
        wps->oob_dev_pw_id = WPA_GET_BE16(pos);
        pos += sizeof(wps->oob_dev_pw_id);
 
-       oob_conf->dev_password =
-               wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN * 2 + 1);
+       pw_len = attr.oob_dev_password_len - WPS_OOB_PUBKEY_HASH_LEN - 2;
+       oob_conf->dev_password = wpabuf_alloc(pw_len * 2 + 1);
        if (oob_conf->dev_password == NULL) {
                wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
                           "device password");
                return -1;
        }
        wpa_snprintf_hex_uppercase(wpabuf_put(oob_conf->dev_password,
-                                  wpabuf_size(oob_conf->dev_password)),
-                                  wpabuf_size(oob_conf->dev_password), pos,
-                                  WPS_OOB_DEVICE_PASSWORD_LEN);
+                                             pw_len * 2 + 1),
+                                  pw_len * 2 + 1, pos, pw_len);
 
        return 0;
 }
 
 
-static int wps_parse_oob_cred(struct wps_context *wps, struct wpabuf *data)
+int wps_oob_use_cred(struct wps_context *wps, struct wps_parse_attr *attr)
 {
        struct wpabuf msg;
-       struct wps_parse_attr attr;
        size_t i;
 
-       if (wps_parse_msg(data, &attr) < 0 || attr.num_cred <= 0) {
-               wpa_printf(MSG_ERROR, "WPS: OOB credential not found");
-               return -1;
-       }
-
-       for (i = 0; i < attr.num_cred; i++) {
+       for (i = 0; i < attr->num_cred; i++) {
                struct wps_credential local_cred;
                struct wps_parse_attr cattr;
 
                os_memset(&local_cred, 0, sizeof(local_cred));
-               wpabuf_set(&msg, attr.cred[i], attr.cred_len[i]);
+               wpabuf_set(&msg, attr->cred[i], attr->cred_len[i]);
                if (wps_parse_msg(&msg, &cattr) < 0 ||
                    wps_process_cred(&cattr, &local_cred)) {
                        wpa_printf(MSG_ERROR, "WPS: Failed to parse OOB "
@@ -442,6 +477,19 @@ static int wps_parse_oob_cred(struct wps_context *wps, struct wpabuf *data)
 }
 
 
+static int wps_parse_oob_cred(struct wps_context *wps, struct wpabuf *data)
+{
+       struct wps_parse_attr attr;
+
+       if (wps_parse_msg(data, &attr) < 0 || attr.num_cred <= 0) {
+               wpa_printf(MSG_ERROR, "WPS: OOB credential not found");
+               return -1;
+       }
+
+       return wps_oob_use_cred(wps, &attr);
+}
+
+
 int wps_process_oob(struct wps_context *wps, struct oob_device_data *oob_dev,
                    int registrar)
 {
@@ -695,3 +743,53 @@ struct wpabuf * wps_build_wsc_nack(struct wps_data *wps)
 
        return msg;
 }
+
+
+#ifdef CONFIG_WPS_NFC
+struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,
+                                 struct wpabuf **privkey,
+                                 struct wpabuf **dev_pw)
+{
+       struct wpabuf *priv = NULL, *pub = NULL, *pw, *ret;
+       void *dh_ctx;
+       u16 val;
+
+       pw = wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN);
+       if (pw == NULL)
+               return NULL;
+
+       if (random_get_bytes(wpabuf_put(pw, WPS_OOB_DEVICE_PASSWORD_LEN),
+                            WPS_OOB_DEVICE_PASSWORD_LEN) ||
+           random_get_bytes((u8 *) &val, sizeof(val))) {
+               wpabuf_free(pw);
+               return NULL;
+       }
+
+       dh_ctx = dh5_init(&priv, &pub);
+       if (dh_ctx == NULL) {
+               wpabuf_free(pw);
+               return NULL;
+       }
+       dh5_free(dh_ctx);
+
+       *id = 0x10 + val % 0xfff0;
+       wpabuf_free(*pubkey);
+       *pubkey = pub;
+       wpabuf_free(*privkey);
+       *privkey = priv;
+       wpabuf_free(*dev_pw);
+       *dev_pw = pw;
+
+       ret = wps_build_nfc_pw_token(*id, *pubkey, *dev_pw);
+       if (ndef && ret) {
+               struct wpabuf *tmp;
+               tmp = ndef_build_wifi(ret);
+               wpabuf_free(ret);
+               if (tmp == NULL)
+                       return NULL;
+               ret = tmp;
+       }
+
+       return ret;
+}
+#endif /* CONFIG_WPS_NFC */
index e128a19..2f42603 100644 (file)
@@ -41,7 +41,7 @@ extern int wps_testing_dummy_cred;
 #define WPS_MGMTAUTHKEY_LEN 32
 #define WPS_MGMTENCKEY_LEN 16
 #define WPS_MGMT_KEY_ID_LEN 16
-#define WPS_OOB_DEVICE_PASSWORD_ATTR_LEN 54
+#define WPS_OOB_DEVICE_PASSWORD_MIN_LEN 16
 #define WPS_OOB_DEVICE_PASSWORD_LEN 32
 #define WPS_OOB_PUBKEY_HASH_LEN 20
 
index 559582d..3c94a43 100644 (file)
@@ -203,6 +203,20 @@ int wps_build_os_version(struct wps_device_data *dev, struct wpabuf *msg)
 }
 
 
+int wps_build_vendor_ext_m1(struct wps_device_data *dev, struct wpabuf *msg)
+{
+       if (dev->vendor_ext_m1 != NULL) {
+               wpa_hexdump(MSG_DEBUG, "WPS:  * Vendor Extension M1",
+                           wpabuf_head_u8(dev->vendor_ext_m1),
+                           wpabuf_len(dev->vendor_ext_m1));
+               wpabuf_put_be16(msg, ATTR_VENDOR_EXT);
+               wpabuf_put_be16(msg, wpabuf_len(dev->vendor_ext_m1));
+               wpabuf_put_buf(msg, dev->vendor_ext_m1);
+       }
+       return 0;
+}
+
+
 int wps_build_rf_bands(struct wps_device_data *dev, struct wpabuf *msg)
 {
        wpa_printf(MSG_DEBUG, "WPS:  * RF Bands (%x)", dev->rf_bands);
index 7ca81ad..200c9c4 100644 (file)
@@ -17,6 +17,7 @@ int wps_build_model_number(struct wps_device_data *dev, struct wpabuf *msg);
 int wps_build_dev_name(struct wps_device_data *dev, struct wpabuf *msg);
 int wps_build_device_attrs(struct wps_device_data *dev, struct wpabuf *msg);
 int wps_build_os_version(struct wps_device_data *dev, struct wpabuf *msg);
+int wps_build_vendor_ext_m1(struct wps_device_data *dev, struct wpabuf *msg);
 int wps_build_rf_bands(struct wps_device_data *dev, struct wpabuf *msg);
 int wps_build_primary_dev_type(struct wps_device_data *dev,
                               struct wpabuf *msg);
index 85d2e95..da0c101 100644 (file)
@@ -163,7 +163,8 @@ static struct wpabuf * wps_build_m1(struct wps_data *wps)
            wps_build_dev_password_id(msg, wps->dev_pw_id) ||
            wps_build_config_error(msg, WPS_CFG_NO_ERROR) ||
            wps_build_os_version(&wps->wps->dev, msg) ||
-           wps_build_wfa_ext(msg, 0, NULL, 0)) {
+           wps_build_wfa_ext(msg, 0, NULL, 0) ||
+           wps_build_vendor_ext_m1(&wps->wps->dev, msg)) {
                wpabuf_free(msg);
                return NULL;
        }
index 0655a3a..95a0dec 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Wi-Fi Protected Setup - External Registrar
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -1996,3 +1996,41 @@ int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *pin,
 
        return 0;
 }
+
+
+#ifdef CONFIG_WPS_NFC
+struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid)
+{
+       struct wps_er_ap *ap;
+       struct wpabuf *ret;
+       struct wps_data data;
+
+       if (er == NULL)
+               return NULL;
+
+       ap = wps_er_ap_get(er, NULL, uuid);
+       if (ap == NULL)
+               return NULL;
+       if (ap->ap_settings == NULL) {
+               wpa_printf(MSG_DEBUG, "WPS ER: No settings known for the "
+                          "selected AP");
+               return NULL;
+       }
+
+       ret = wpabuf_alloc(500);
+       if (ret == NULL)
+               return NULL;
+
+       os_memset(&data, 0, sizeof(data));
+       data.wps = er->wps;
+       data.use_cred = ap->ap_settings;
+       if (wps_build_version(ret) ||
+           wps_build_cred(&data, ret) ||
+           wps_build_wfa_ext(ret, 0, NULL, 0)) {
+               wpabuf_free(ret);
+               return NULL;
+       }
+
+       return ret;
+}
+#endif /* CONFIG_WPS_NFC */
index 1297f65..86ad248 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Wi-Fi Protected Setup - internal definitions
- * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -10,6 +10,9 @@
 #define WPS_I_H
 
 #include "wps.h"
+#include "wps_attr_parse.h"
+
+struct wps_nfc_pw_token;
 
 /**
  * struct wps_data - WPS registration protocol data
@@ -114,100 +117,11 @@ struct wps_data {
        u8 p2p_dev_addr[ETH_ALEN]; /* P2P Device Address of the client or
                                    * 00:00:00:00:00:00 if not a P2p client */
        int pbc_in_m1;
-};
-
 
-struct wps_parse_attr {
-       /* fixed length fields */
-       const u8 *version; /* 1 octet */
-       const u8 *version2; /* 1 octet */
-       const u8 *msg_type; /* 1 octet */
-       const u8 *enrollee_nonce; /* WPS_NONCE_LEN (16) octets */
-       const u8 *registrar_nonce; /* WPS_NONCE_LEN (16) octets */
-       const u8 *uuid_r; /* WPS_UUID_LEN (16) octets */
-       const u8 *uuid_e; /* WPS_UUID_LEN (16) octets */
-       const u8 *auth_type_flags; /* 2 octets */
-       const u8 *encr_type_flags; /* 2 octets */
-       const u8 *conn_type_flags; /* 1 octet */
-       const u8 *config_methods; /* 2 octets */
-       const u8 *sel_reg_config_methods; /* 2 octets */
-       const u8 *primary_dev_type; /* 8 octets */
-       const u8 *rf_bands; /* 1 octet */
-       const u8 *assoc_state; /* 2 octets */
-       const u8 *config_error; /* 2 octets */
-       const u8 *dev_password_id; /* 2 octets */
-       const u8 *oob_dev_password; /* WPS_OOB_DEVICE_PASSWORD_ATTR_LEN (54)
-                                    * octets */
-       const u8 *os_version; /* 4 octets */
-       const u8 *wps_state; /* 1 octet */
-       const u8 *authenticator; /* WPS_AUTHENTICATOR_LEN (8) octets */
-       const u8 *r_hash1; /* WPS_HASH_LEN (32) octets */
-       const u8 *r_hash2; /* WPS_HASH_LEN (32) octets */
-       const u8 *e_hash1; /* WPS_HASH_LEN (32) octets */
-       const u8 *e_hash2; /* WPS_HASH_LEN (32) octets */
-       const u8 *r_snonce1; /* WPS_SECRET_NONCE_LEN (16) octets */
-       const u8 *r_snonce2; /* WPS_SECRET_NONCE_LEN (16) octets */
-       const u8 *e_snonce1; /* WPS_SECRET_NONCE_LEN (16) octets */
-       const u8 *e_snonce2; /* WPS_SECRET_NONCE_LEN (16) octets */
-       const u8 *key_wrap_auth; /* WPS_KWA_LEN (8) octets */
-       const u8 *auth_type; /* 2 octets */
-       const u8 *encr_type; /* 2 octets */
-       const u8 *network_idx; /* 1 octet */
-       const u8 *network_key_idx; /* 1 octet */
-       const u8 *mac_addr; /* ETH_ALEN (6) octets */
-       const u8 *key_prov_auto; /* 1 octet (Bool) */
-       const u8 *dot1x_enabled; /* 1 octet (Bool) */
-       const u8 *selected_registrar; /* 1 octet (Bool) */
-       const u8 *request_type; /* 1 octet */
-       const u8 *response_type; /* 1 octet */
-       const u8 *ap_setup_locked; /* 1 octet */
-       const u8 *settings_delay_time; /* 1 octet */
-       const u8 *network_key_shareable; /* 1 octet (Bool) */
-       const u8 *request_to_enroll; /* 1 octet (Bool) */
-
-       /* variable length fields */
-       const u8 *manufacturer;
-       size_t manufacturer_len;
-       const u8 *model_name;
-       size_t model_name_len;
-       const u8 *model_number;
-       size_t model_number_len;
-       const u8 *serial_number;
-       size_t serial_number_len;
-       const u8 *dev_name;
-       size_t dev_name_len;
-       const u8 *public_key;
-       size_t public_key_len;
-       const u8 *encr_settings;
-       size_t encr_settings_len;
-       const u8 *ssid; /* <= 32 octets */
-       size_t ssid_len;
-       const u8 *network_key; /* <= 64 octets */
-       size_t network_key_len;
-       const u8 *eap_type; /* <= 8 octets */
-       size_t eap_type_len;
-       const u8 *eap_identity; /* <= 64 octets */
-       size_t eap_identity_len;
-       const u8 *authorized_macs; /* <= 30 octets */
-       size_t authorized_macs_len;
-       const u8 *sec_dev_type_list; /* <= 128 octets */
-       size_t sec_dev_type_list_len;
-
-       /* attributes that can occur multiple times */
-#define MAX_CRED_COUNT 10
-       const u8 *cred[MAX_CRED_COUNT];
-       size_t cred_len[MAX_CRED_COUNT];
-       size_t num_cred;
-
-#define MAX_REQ_DEV_TYPE_COUNT 10
-       const u8 *req_dev_type[MAX_REQ_DEV_TYPE_COUNT];
-       size_t num_req_dev_type;
-
-       const u8 *vendor_ext[MAX_WPS_PARSE_VENDOR_EXT];
-       size_t vendor_ext_len[MAX_WPS_PARSE_VENDOR_EXT];
-       size_t num_vendor_ext;
+       struct wps_nfc_pw_token *nfc_pw_token;
 };
 
+
 /* wps_common.c */
 void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len,
             const char *label, u8 *res, size_t res_len);
@@ -230,9 +144,6 @@ extern struct oob_nfc_device_data oob_nfc_pn531_device_data;
 struct wpabuf * wps_build_wsc_ack(struct wps_data *wps);
 struct wpabuf * wps_build_wsc_nack(struct wps_data *wps);
 
-/* wps_attr_parse.c */
-int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr);
-
 /* wps_attr_build.c */
 int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg);
 int wps_build_req_type(struct wpabuf *msg, enum wps_request_type type);
@@ -255,6 +166,9 @@ int wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg);
 int wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg);
 int wps_build_conn_type_flags(struct wps_data *wps, struct wpabuf *msg);
 int wps_build_assoc_state(struct wps_data *wps, struct wpabuf *msg);
+int wps_build_oob_dev_pw(struct wpabuf *msg, u16 dev_pw_id,
+                        const struct wpabuf *pubkey, const u8 *dev_pw,
+                        size_t dev_pw_len);
 int wps_build_oob_dev_password(struct wpabuf *msg, struct wps_context *wps);
 struct wpabuf * wps_ie_encapsulate(struct wpabuf *data);
 
@@ -288,9 +202,7 @@ void wps_registrar_selected_registrar_changed(struct wps_registrar *reg);
 const u8 * wps_authorized_macs(struct wps_registrar *reg, size_t *count);
 int wps_registrar_pbc_overlap(struct wps_registrar *reg,
                              const u8 *addr, const u8 *uuid_e);
-
-/* ndef.c */
-struct wpabuf * ndef_parse_wifi(struct wpabuf *buf);
-struct wpabuf * ndef_build_wifi(struct wpabuf *buf);
+void wps_registrar_remove_nfc_pw_token(struct wps_registrar *reg,
+                                      struct wps_nfc_pw_token *token);
 
 #endif /* WPS_I_H */
index ff12000..6804350 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * NFC routines for Wi-Fi Protected Setup
- * Copyright (c) 2009, Masashi Honma <honma@ictec.co.jp>
+ * Copyright (c) 2009-2012, Masashi Honma <masashi.honma@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.
  */
 
 #include "includes.h"
index 7e05e4d..c2bf457 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * NFC PN531 routines for Wi-Fi Protected Setup
- * Copyright (c) 2009, Masashi Honma <honma@ictec.co.jp>
+ * Copyright (c) 2009-2012, Masashi Honma <masashi.honma@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.
  */
 
 #include "includes.h"
index 5ed7ea4..44bb006 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Wi-Fi Protected Setup - Registrar
- * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
 #define WPS_WORKAROUNDS
 #endif /* CONFIG_WPS_STRICT */
 
+#ifdef CONFIG_WPS_NFC
+
+struct wps_nfc_pw_token {
+       struct dl_list list;
+       u8 pubkey_hash[WPS_OOB_PUBKEY_HASH_LEN];
+       u16 pw_id;
+       u8 dev_pw[WPS_OOB_DEVICE_PASSWORD_LEN];
+       size_t dev_pw_len;
+};
+
+
+static void wps_remove_nfc_pw_token(struct wps_nfc_pw_token *token)
+{
+       dl_list_del(&token->list);
+       os_free(token);
+}
+
+
+static void wps_free_nfc_pw_tokens(struct dl_list *tokens, u16 pw_id)
+{
+       struct wps_nfc_pw_token *token, *prev;
+       dl_list_for_each_safe(token, prev, tokens, struct wps_nfc_pw_token,
+                             list) {
+               if (pw_id == 0 || pw_id == token->pw_id)
+                       wps_remove_nfc_pw_token(token);
+       }
+}
+
+
+static struct wps_nfc_pw_token * wps_get_nfc_pw_token(struct dl_list *tokens,
+                                                     u16 pw_id)
+{
+       struct wps_nfc_pw_token *token;
+       dl_list_for_each(token, tokens, struct wps_nfc_pw_token, list) {
+               if (pw_id == token->pw_id)
+                       return token;
+       }
+       return NULL;
+}
+
+#else /* CONFIG_WPS_NFC */
+
+#define wps_free_nfc_pw_tokens(t, p) do { } while (0)
+
+#endif /* CONFIG_WPS_NFC */
+
+
 struct wps_uuid_pin {
        struct dl_list list;
        u8 uuid[WPS_UUID_LEN];
@@ -102,7 +149,8 @@ struct wps_registrar {
        void (*pin_needed_cb)(void *ctx, const u8 *uuid_e,
                              const struct wps_device_data *dev);
        void (*reg_success_cb)(void *ctx, const u8 *mac_addr,
-                              const u8 *uuid_e);
+                              const u8 *uuid_e, const u8 *dev_pw,
+                              size_t dev_pw_len);
        void (*set_sel_reg_cb)(void *ctx, int sel_reg, u16 dev_passwd_id,
                               u16 sel_reg_config_methods);
        void (*enrollee_seen_cb)(void *ctx, const u8 *addr, const u8 *uuid_e,
@@ -112,6 +160,7 @@ struct wps_registrar {
        void *cb_ctx;
 
        struct dl_list pins;
+       struct dl_list nfc_pw_tokens;
        struct wps_pbc_session *pbc_sessions;
 
        int skip_cred_build;
@@ -484,12 +533,16 @@ static void wps_set_pushbutton(u16 *methods, u16 conf_methods)
 {
        *methods |= WPS_CONFIG_PUSHBUTTON;
 #ifdef CONFIG_WPS2
-       if (conf_methods & WPS_CONFIG_VIRT_PUSHBUTTON)
+       if ((conf_methods & WPS_CONFIG_VIRT_PUSHBUTTON) ==
+           WPS_CONFIG_VIRT_PUSHBUTTON)
                *methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
-       if (conf_methods & WPS_CONFIG_PHY_PUSHBUTTON)
+       if ((conf_methods & WPS_CONFIG_PHY_PUSHBUTTON) ==
+           WPS_CONFIG_PHY_PUSHBUTTON)
                *methods |= WPS_CONFIG_PHY_PUSHBUTTON;
-       if (!(*methods & (WPS_CONFIG_VIRT_PUSHBUTTON |
-                         WPS_CONFIG_PHY_PUSHBUTTON))) {
+       if ((*methods & WPS_CONFIG_VIRT_PUSHBUTTON) !=
+           WPS_CONFIG_VIRT_PUSHBUTTON &&
+           (*methods & WPS_CONFIG_PHY_PUSHBUTTON) !=
+           WPS_CONFIG_PHY_PUSHBUTTON) {
                /*
                 * Required to include virtual/physical flag, but we were not
                 * configured with push button type, so have to default to one
@@ -591,6 +644,7 @@ wps_registrar_init(struct wps_context *wps,
                return NULL;
 
        dl_list_init(&reg->pins);
+       dl_list_init(&reg->nfc_pw_tokens);
        reg->wps = wps;
        reg->new_psk_cb = cfg->new_psk_cb;
        reg->set_ie_cb = cfg->set_ie_cb;
@@ -634,6 +688,7 @@ void wps_registrar_deinit(struct wps_registrar *reg)
        eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
        eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
        wps_free_pins(&reg->pins);
+       wps_free_nfc_pw_tokens(&reg->nfc_pw_tokens, 0);
        wps_free_pbc_sessions(reg->pbc_sessions);
        wpabuf_free(reg->extra_cred);
        wps_free_devices(reg->devices);
@@ -740,14 +795,22 @@ static void wps_registrar_expire_pins(struct wps_registrar *reg)
 /**
  * wps_registrar_invalidate_wildcard_pin - Invalidate a wildcard PIN
  * @reg: Registrar data from wps_registrar_init()
+ * @dev_pw: PIN to search for or %NULL to match any
+ * @dev_pw_len: Length of dev_pw in octets
  * Returns: 0 on success, -1 if not wildcard PIN is enabled
  */
-static int wps_registrar_invalidate_wildcard_pin(struct wps_registrar *reg)
+static int wps_registrar_invalidate_wildcard_pin(struct wps_registrar *reg,
+                                                const u8 *dev_pw,
+                                                size_t dev_pw_len)
 {
        struct wps_uuid_pin *pin, *prev;
 
        dl_list_for_each_safe(pin, prev, &reg->pins, struct wps_uuid_pin, list)
        {
+               if (dev_pw && pin->pin &&
+                   (dev_pw_len != pin->pin_len ||
+                    os_memcmp(dev_pw, pin->pin, dev_pw_len) != 0))
+                       continue; /* different PIN */
                if (pin->wildcard_uuid) {
                        wpa_hexdump(MSG_DEBUG, "WPS: Invalidated PIN for UUID",
                                    pin->uuid, WPS_UUID_LEN);
@@ -945,7 +1008,8 @@ static void wps_registrar_pin_completed(struct wps_registrar *reg)
 }
 
 
-void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e)
+void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e,
+                           const u8 *dev_pw, size_t dev_pw_len)
 {
        if (registrar->pbc) {
                wps_registrar_remove_pbc_session(registrar,
@@ -954,6 +1018,13 @@ void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e)
        } else {
                wps_registrar_pin_completed(registrar);
        }
+
+       if (dev_pw &&
+           wps_registrar_invalidate_wildcard_pin(registrar, dev_pw,
+                                                 dev_pw_len) == 0) {
+               wpa_hexdump_key(MSG_DEBUG, "WPS: Invalidated wildcard PIN",
+                               dev_pw, dev_pw_len);
+       }
 }
 
 
@@ -968,7 +1039,7 @@ int wps_registrar_wps_cancel(struct wps_registrar *reg)
                /* PIN Method */
                wpa_printf(MSG_DEBUG, "WPS: PIN is set - cancelling it");
                wps_registrar_pin_completed(reg);
-               wps_registrar_invalidate_wildcard_pin(reg);
+               wps_registrar_invalidate_wildcard_pin(reg, NULL, 0);
                return 1;
        }
        return 0;
@@ -1071,12 +1142,13 @@ static void wps_cb_pin_needed(struct wps_registrar *reg, const u8 *uuid_e,
 
 
 static void wps_cb_reg_success(struct wps_registrar *reg, const u8 *mac_addr,
-                              const u8 *uuid_e)
+                              const u8 *uuid_e, const u8 *dev_pw,
+                              size_t dev_pw_len)
 {
        if (reg->reg_success_cb == NULL)
                return;
 
-       reg->reg_success_cb(reg->cb_ctx, mac_addr, uuid_e);
+       reg->reg_success_cb(reg->cb_ctx, mac_addr, uuid_e, dev_pw, dev_pw_len);
 }
 
 
@@ -1238,6 +1310,13 @@ static int wps_get_dev_password(struct wps_data *wps)
                wpa_printf(MSG_DEBUG, "WPS: Use default PIN for PBC");
                pin = (const u8 *) "00000000";
                pin_len = 8;
+#ifdef CONFIG_WPS_NFC
+       } else if (wps->nfc_pw_token) {
+               wpa_printf(MSG_DEBUG, "WPS: Use OOB Device Password from NFC "
+                          "Password Token");
+               pin = wps->nfc_pw_token->dev_pw;
+               pin_len = wps->nfc_pw_token->dev_pw_len;
+#endif /* CONFIG_WPS_NFC */
        } else {
                pin = wps_registrar_get_pin(wps->wps->registrar, wps->uuid_e,
                                            &pin_len);
@@ -2424,8 +2503,34 @@ static enum wps_process_res wps_process_m1(struct wps_data *wps,
                return WPS_CONTINUE;
        }
 
+#ifdef CONFIG_WPS_NFC
+       if (wps->dev_pw_id >= 0x10) {
+               struct wps_nfc_pw_token *token;
+               const u8 *addr[1];
+               u8 hash[WPS_HASH_LEN];
+
+               token = wps_get_nfc_pw_token(
+                       &wps->wps->registrar->nfc_pw_tokens, wps->dev_pw_id);
+               if (token) {
+                       wpa_printf(MSG_DEBUG, "WPS: Found matching NFC "
+                                  "Password Token");
+                       dl_list_del(&token->list);
+                       wps->nfc_pw_token = token;
+
+                       addr[0] = attr->public_key;
+                       sha256_vector(1, addr, &attr->public_key_len, hash);
+                       if (os_memcmp(hash, wps->nfc_pw_token->pubkey_hash,
+                                     WPS_OOB_PUBKEY_HASH_LEN) != 0) {
+                               wpa_printf(MSG_ERROR, "WPS: Public Key hash "
+                                          "mismatch");
+                               return WPS_FAILURE;
+                       }
+               }
+       }
+#endif /* CONFIG_WPS_NFC */
+
 #ifdef CONFIG_WPS_OOB
-       if (wps->dev_pw_id >= 0x10 &&
+       if (wps->dev_pw_id >= 0x10 && wps->nfc_pw_token == NULL &&
            wps->dev_pw_id != wps->wps->oob_dev_pw_id) {
                wpa_printf(MSG_DEBUG, "WPS: OOB Device Password ID "
                           "%d mismatch", wps->dev_pw_id);
@@ -3055,7 +3160,8 @@ static enum wps_process_res wps_process_wsc_done(struct wps_data *wps,
                wps->new_psk = NULL;
        }
 
-       wps_cb_reg_success(wps->wps->registrar, wps->mac_addr_e, wps->uuid_e);
+       wps_cb_reg_success(wps->wps->registrar, wps->mac_addr_e, wps->uuid_e,
+                          wps->dev_password, wps->dev_password_len);
 
        if (wps->pbc) {
                wps_registrar_remove_pbc_session(wps->wps->registrar,
@@ -3348,3 +3454,84 @@ int wps_registrar_config_ap(struct wps_registrar *reg,
 
        return -1;
 }
+
+
+#ifdef CONFIG_WPS_NFC
+
+int wps_registrar_add_nfc_pw_token(struct wps_registrar *reg,
+                                  const u8 *pubkey_hash, u16 pw_id,
+                                  const u8 *dev_pw, size_t dev_pw_len)
+{
+       struct wps_nfc_pw_token *token;
+
+       if (dev_pw_len > WPS_OOB_DEVICE_PASSWORD_LEN)
+               return -1;
+
+       wps_free_nfc_pw_tokens(&reg->nfc_pw_tokens, pw_id);
+
+       token = os_zalloc(sizeof(*token));
+       if (token == NULL)
+               return -1;
+
+       os_memcpy(token->pubkey_hash, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
+       token->pw_id = pw_id;
+       os_memcpy(token->dev_pw, dev_pw, dev_pw_len);
+       token->dev_pw_len = dev_pw_len;
+
+       dl_list_add(&reg->nfc_pw_tokens, &token->list);
+
+       reg->selected_registrar = 1;
+       reg->pbc = 0;
+       wps_registrar_add_authorized_mac(reg,
+                                        (u8 *) "\xff\xff\xff\xff\xff\xff");
+       wps_registrar_selected_registrar_changed(reg);
+       eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
+       eloop_register_timeout(WPS_PBC_WALK_TIME, 0,
+                              wps_registrar_set_selected_timeout,
+                              reg, NULL);
+
+       return 0;
+}
+
+
+int wps_registrar_add_nfc_password_token(struct wps_registrar *reg,
+                                        const u8 *oob_dev_pw,
+                                        size_t oob_dev_pw_len)
+{
+       const u8 *pos, *hash, *dev_pw;
+       u16 id;
+       size_t dev_pw_len;
+
+       if (oob_dev_pw_len < WPS_OOB_PUBKEY_HASH_LEN + 2 +
+           WPS_OOB_DEVICE_PASSWORD_MIN_LEN ||
+           oob_dev_pw_len > WPS_OOB_PUBKEY_HASH_LEN + 2 +
+           WPS_OOB_DEVICE_PASSWORD_LEN)
+               return -1;
+
+       hash = oob_dev_pw;
+       pos = oob_dev_pw + WPS_OOB_PUBKEY_HASH_LEN;
+       id = WPA_GET_BE16(pos);
+       dev_pw = pos + 2;
+       dev_pw_len = oob_dev_pw + oob_dev_pw_len - dev_pw;
+
+       wpa_printf(MSG_DEBUG, "WPS: Add NFC Password Token for Password ID %u",
+                  id);
+
+       wpa_hexdump(MSG_DEBUG, "WPS: Public Key Hash",
+                   hash, WPS_OOB_PUBKEY_HASH_LEN);
+       wpa_hexdump_key(MSG_DEBUG, "WPS: Device Password", dev_pw, dev_pw_len);
+
+       return wps_registrar_add_nfc_pw_token(reg, hash, id, dev_pw,
+                                             dev_pw_len);
+}
+
+
+void wps_registrar_remove_nfc_pw_token(struct wps_registrar *reg,
+                                      struct wps_nfc_pw_token *token)
+{
+       wps_registrar_remove_authorized_mac(reg,
+                                           (u8 *) "\xff\xff\xff\xff\xff\xff");
+       wps_registrar_selected_registrar_changed(reg);
+}
+
+#endif /* CONFIG_WPS_NFC */
index 61f6553..f83bdf4 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * UFD routines for Wi-Fi Protected Setup
- * Copyright (c) 2009, Masashi Honma <honma@ictec.co.jp>
+ * Copyright (c) 2009-2012, Masashi Honma <masashi.honma@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.
  */
 
 #include "includes.h"
@@ -165,8 +159,10 @@ static void * init_ufd(struct wps_context *wps,
        }
 
        data = os_zalloc(sizeof(*data));
-       if (data == NULL)
+       if (data == NULL) {
+               close(ufd_fd);
                return NULL;
+       }
        data->ufd_fd = ufd_fd;
        return data;
 }
index 766cac4..09a46a2 100644 (file)
@@ -305,15 +305,15 @@ static void subscr_addr_add_url(struct subscription *s, const char *url,
        int alloc_len;
        char *scratch_mem = NULL;
        char *mem;
-       char *domain_and_port;
+       char *host;
        char *delim;
        char *path;
-       char *domain;
        int port = 80;  /* port to send to (default is port 80) */
        struct addrinfo hints;
        struct addrinfo *result = NULL;
        struct addrinfo *rp;
        int rerr;
+       size_t host_len, path_len;
 
        /* url MUST begin with http: */
        if (url_len < 7 || os_strncasecmp(url, "http://", 7))
@@ -321,30 +321,24 @@ static void subscr_addr_add_url(struct subscription *s, const char *url,
        url += 7;
        url_len -= 7;
 
-       /* allocate memory for the extra stuff we need */
-       alloc_len = 2 * (url_len + 1);
-       scratch_mem = os_zalloc(alloc_len);
+       /* Make a copy of the string to allow modification during parsing */
+       scratch_mem = os_malloc(url_len + 1);
        if (scratch_mem == NULL)
                goto fail;
-       mem = scratch_mem;
-       os_strncpy(mem, url, url_len);
-       wpa_printf(MSG_DEBUG, "WPS UPnP: Adding URL '%s'", mem);
-       domain_and_port = mem;
-       mem += 1 + os_strlen(mem);
-       delim = os_strchr(domain_and_port, '/');
+       os_memcpy(scratch_mem, url, url_len);
+       scratch_mem[url_len] = '\0';
+       wpa_printf(MSG_DEBUG, "WPS UPnP: Adding URL '%s'", scratch_mem);
+       host = scratch_mem;
+       path = os_strchr(host, '/');
+       if (path)
+               *path++ = '\0'; /* null terminate host */
+
+       /* Process and remove optional port component */
+       delim = os_strchr(host, ':');
        if (delim) {
-               *delim++ = 0;   /* null terminate domain and port */
-               path = delim;
-       } else {
-               path = domain_and_port + os_strlen(domain_and_port);
-       }
-       domain = mem;
-       strcpy(domain, domain_and_port);
-       delim = os_strchr(domain, ':');
-       if (delim) {
-               *delim++ = 0;   /* null terminate domain */
-               if (isdigit(*delim))
-                       port = atol(delim);
+               *delim = '\0'; /* null terminate host name for now */
+               if (isdigit(delim[1]))
+                       port = atol(delim + 1);
        }
 
        /*
@@ -367,13 +361,21 @@ static void subscr_addr_add_url(struct subscription *s, const char *url,
        hints.ai_flags = 0;
 #endif
        hints.ai_protocol = 0;          /* Any protocol? */
-       rerr = getaddrinfo(domain, NULL /* fill in port ourselves */,
+       rerr = getaddrinfo(host, NULL /* fill in port ourselves */,
                           &hints, &result);
        if (rerr) {
                wpa_printf(MSG_INFO, "WPS UPnP: Resolve error %d (%s) on: %s",
-                          rerr, gai_strerror(rerr), domain);
+                          rerr, gai_strerror(rerr), host);
                goto fail;
        }
+
+       if (delim)
+               *delim = ':'; /* Restore port */
+
+       host_len = os_strlen(host);
+       path_len = path ? os_strlen(path) : 0;
+       alloc_len = host_len + 1 + 1 + path_len + 1;
+
        for (rp = result; rp; rp = rp->ai_next) {
                struct subscr_addr *a;
 
@@ -386,16 +388,16 @@ static void subscr_addr_add_url(struct subscription *s, const char *url,
 
                a = os_zalloc(sizeof(*a) + alloc_len);
                if (a == NULL)
-                       continue;
-               mem = (void *) (a + 1);
+                       break;
+               mem = (char *) (a + 1);
                a->domain_and_port = mem;
-               strcpy(mem, domain_and_port);
-               mem += 1 + strlen(mem);
+               os_memcpy(mem, host, host_len);
+               mem += host_len + 1;
                a->path = mem;
-               if (path[0] != '/')
+               if (path == NULL || path[0] != '/')
                        *mem++ = '/';
-               strcpy(mem, path);
-               mem += 1 + os_strlen(mem);
+               if (path)
+                       os_memcpy(mem, path, path_len);
                os_memcpy(&a->saddr, rp->ai_addr, sizeof(a->saddr));
                a->saddr.sin_port = htons(port);
 
index 4c4aebf..17a8207 100644 (file)
@@ -866,20 +866,24 @@ int ssdp_open_multicast_sock(u32 ip_addr)
                return -1;
 
 #if 0   /* maybe ok if we sometimes block on writes */
-       if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0)
+       if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0) {
+               close(sd);
                return -1;
+       }
 #endif
 
        if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF,
                       &ip_addr, sizeof(ip_addr))) {
                wpa_printf(MSG_DEBUG, "WPS: setsockopt(IP_MULTICAST_IF) %x: "
                           "%d (%s)", ip_addr, errno, strerror(errno));
+               close(sd);
                return -1;
        }
        if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL,
                       &ttl, sizeof(ttl))) {
                wpa_printf(MSG_DEBUG, "WPS: setsockopt(IP_MULTICAST_TTL): "
                           "%d (%s)", errno, strerror(errno));
+               close(sd);
                return -1;
        }
 
@@ -898,6 +902,7 @@ int ssdp_open_multicast_sock(u32 ip_addr)
                                   "WPS UPnP: setsockopt "
                                   "IP_ADD_MEMBERSHIP errno %d (%s)",
                                   errno, strerror(errno));
+                       close(sd);
                        return -1;
                }
        }
index c6cf80b..231cd57 100644 (file)
@@ -1310,6 +1310,23 @@ L_CFLAGS += -DCONFIG_BGSCAN
 OBJS += bgscan.c
 endif
 
+ifdef CONFIG_AUTOSCAN_EXPONENTIAL
+L_CFLAGS += -DCONFIG_AUTOSCAN_EXPONENTIAL
+OBJS += autoscan_exponential.c
+NEED_AUTOSCAN=y
+endif
+
+ifdef CONFIG_AUTOSCAN_PERIODIC
+CFLAGS += -DCONFIG_AUTOSCAN_PERIODIC
+OBJS += autoscan_periodic.c
+NEED_AUTOSCAN=y
+endif
+
+ifdef NEED_AUTOSCAN
+L_CFLAGS += -DCONFIG_AUTOSCAN
+OBJS += autoscan.c
+endif
+
 ifdef NEED_GAS
 OBJS += ../src/common/gas.c
 OBJS += gas_query.c
index 06119c6..650b8a0 100644 (file)
@@ -1,5 +1,179 @@
 ChangeLog for wpa_supplicant
 
+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
        * avoid unnecessary roaming if multiple APs with similar signal
index 03241c5..6756e54 100644 (file)
@@ -227,6 +227,12 @@ CFLAGS += -DCONFIG_P2P_STRICT
 endif
 endif
 
+ifdef CONFIG_HS20
+OBJS += hs20_supplicant.o
+CFLAGS += -DCONFIG_HS20
+CONFIG_INTERWORKING=y
+endif
+
 ifdef CONFIG_INTERWORKING
 OBJS += interworking.o
 CFLAGS += -DCONFIG_INTERWORKING
@@ -716,6 +722,10 @@ ifdef CONFIG_IEEE80211N
 CFLAGS += -DCONFIG_IEEE80211N
 endif
 
+ifdef CONFIG_WNM
+CFLAGS += -DCONFIG_WNM
+endif
+
 ifdef NEED_AP_MLME
 OBJS += ../src/ap/wmm.o
 OBJS += ../src/ap/ap_list.o
@@ -728,6 +738,9 @@ 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
 endif
 
 ifdef NEED_RSN_AUTHENTICATOR
@@ -1270,6 +1283,10 @@ CFLAGS += -DLOG_HOSTAPD="$(CONFIG_DEBUG_SYSLOG_FACILITY)"
 endif
 endif
 
+ifdef CONFIG_DEBUG_LINUX_TRACING
+CFLAGS += -DCONFIG_DEBUG_LINUX_TRACING
+endif
+
 ifdef CONFIG_DEBUG_FILE
 CFLAGS += -DCONFIG_DEBUG_FILE
 endif
@@ -1304,6 +1321,23 @@ CFLAGS += -DCONFIG_BGSCAN
 OBJS += bgscan.o
 endif
 
+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 NEED_GAS
 OBJS += ../src/common/gas.o
 OBJS += gas_query.o
@@ -1332,6 +1366,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
@@ -1440,6 +1478,10 @@ test_wpa: $(OBJS_wpa) $(OBJS_h)
        $(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
        $(Q)$(LDO) $(LDFLAGS) -o $@ win_if_list.c $(CFLAGS) $(LIBS_w)
        @$(E) "  LD " $@
@@ -1522,5 +1564,6 @@ 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)
index 9ee82a2..a06e5c1 100644 (file)
@@ -425,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)
index db6e4ae..bb4c2ad 100644 (file)
@@ -101,7 +101,7 @@ Flush P2P peer table and state.
 
 Group Formation
 
-p2p_prov_disc <peer device address> <display|keypad|pbc> [join]
+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
@@ -112,10 +112,14 @@ 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.
+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] [join|auth] [go_intent=<0..15>] [freq=<in MHz>]
+       [persistent|persistent=<network id>] [join|auth]
+       [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
 
 Start P2P group formation with a discovered P2P peer. This includes
 optional group owner negotiation, group interface setup, provisioning,
@@ -128,7 +132,12 @@ 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.
+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
@@ -146,6 +155,11 @@ 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>]
 
 Set up a P2P group owner manually (i.e., without group owner
@@ -322,7 +336,7 @@ p2p_invite [persistent=<network id>|group=<group ifname>] [peer=address]
 
 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 persisten group, the peer parameter is not needed. Otherwise it is
+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
index bf75cb4..692d5f5 100644 (file)
@@ -67,6 +67,10 @@ 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
 the device. This is configured in the runtime configuration for
@@ -303,3 +307,41 @@ 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).
index 292223d..7288abd 100644 (file)
@@ -4,13 +4,8 @@ wpa_supplicant for Windows
 Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi> and contributors
 All Rights Reserved.
 
-This program is dual-licensed under both the GPL version 2 and BSD
-license. Either license may be used at your option.
-
-This product includes software developed by the OpenSSL Project
-for use in the OpenSSL Toolkit (http://www.openssl.org/). This
-product includes cryptographic software written by Eric Young
-(eay@cryptsoft.com).
+This program is licensed under the BSD license (the one with
+advertisement clause removed).
 
 
 wpa_supplicant has support for being used as a WPA/WPA2/IEEE 802.1X
@@ -35,20 +30,6 @@ authentication and successfully ping a wired host):
 - WPA2-EAP, TKIP, CCMP, TKIP+CCMP
 
 
-Binary version
---------------
-
-Compiled binary version of the wpa_supplicant and additional tools is
-available from http://w1.fi/wpa_supplicant/. These binaries can be
-used after installing WinPcap.
-
-wpa_gui uses Qt 4 framework and may need additional dynamic libraries
-(DLLs). These libraries are available from
-http://w1.fi/wpa_supplicant/qt4/wpa_gui-qt433-windows-dll.zip
-You can copy the DLL files from this ZIP package into the same directory
-with wpa_gui.exe to allow wpa_gui to be started.
-
-
 Building wpa_supplicant with mingw
 ----------------------------------
 
@@ -316,135 +297,3 @@ HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\networks\0000
 See win_example.reg for an example on how to setup wpasvc.exe
 parameters in registry. It can also be imported to registry as a
 starting point for the configuration.
-
-
-
-License information for third party software used in this product:
-
-  OpenSSL License
-  ---------------
-
-/* ====================================================================
- * Copyright (c) 1998-2004 The OpenSSL Project.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer. 
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- *    software must display the following acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- *    endorse or promote products derived from this software without
- *    prior written permission. For written permission, please contact
- *    openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- *    nor may "OpenSSL" appear in their names without prior written
- *    permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- *    acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com).  This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
- Original SSLeay License
- -----------------------
-
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- * 
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to.  The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- * 
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    "This product includes cryptographic software written by
- *     Eric Young (eay@cryptsoft.com)"
- *    The word 'cryptographic' can be left out if the rouines from the library
- *    being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from 
- *    the apps directory (application code) you must include an acknowledgement:
- *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- * 
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * 
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed.  i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-
-
-   Qt Open Source Edition
-   ----------------------
-
-The Qt GUI Toolkit is Copyright (C) 1994-2007 Trolltech ASA.
-Qt Open Source Edition is licensed under GPL version 2.
-
-Source code for the library is available at
-http://w1.fi/wpa_supplicant/qt4/qt-win-opensource-src-4.3.3.zip
index 5aa4fcc..fc0614d 100644 (file)
 # Set include directory to the madwifi source tree
 #CFLAGS += -I../../madwifi
 
-# Driver interface for Prism54 driver
-# (Note: Prism54 is not yet supported, i.e., this will not work as-is and is
-# for developers only)
-#CONFIG_DRIVER_PRISM54=y
-
 # Driver interface for ndiswrapper
 # Deprecated; use CONFIG_DRIVER_WEXT=y instead.
 #CONFIG_DRIVER_NDISWRAPPER=y
 #CONFIG_DRIVER_RALINK=y
 
 # Driver interface for generic Linux wireless extensions
+# Note: WEXT is deprecated in the current Linux kernel version and no new
+# functionality is added to it. nl80211-based interface is the new
+# replacement for WEXT and its use allows wpa_supplicant to properly control
+# the driver to improve existing functionality like roaming and to support new
+# functionality.
 #CONFIG_DRIVER_WEXT=y
 
 # Driver interface for Linux drivers using the nl80211 kernel interface
@@ -93,6 +93,8 @@ CONFIG_LIBNL20=y
 #CONFIG_DRIVER_BSD=y
 #CFLAGS += -I/usr/local/include
 #LIBS += -L/usr/local/lib
+#LIBS_p += -L/usr/local/lib
+#LIBS_c += -L/usr/local/lib
 
 # Driver interface for Windows NDIS
 #CONFIG_DRIVER_NDIS=y
@@ -113,11 +115,6 @@ CONFIG_LIBNL20=y
 # Driver interface for development testing
 #CONFIG_DRIVER_TEST=y
 
-# Include client MLME (management frame processing) for test driver
-# This can be used to test MLME operations in hostapd with the test interface.
-# space.
-#CONFIG_CLIENT_MLME=y
-
 # Driver interface for wired Ethernet drivers
 #CONFIG_DRIVER_WIRED=y
 
@@ -127,6 +124,10 @@ CONFIG_LIBNL20=y
 # Driver interface for no driver (e.g., WPS ER only)
 #CONFIG_DRIVER_NONE=y
 
+# Solaris libraries
+#LIBS += -lsocket -ldlpi -lnsl
+#LIBS_c += -lsocket
+
 # Enable IEEE 802.1X Supplicant (automatically included if any EAP method is
 # included)
 CONFIG_IEEE8021X_EAPOL=y
@@ -165,6 +166,9 @@ CONFIG_EAP_SIM=y
 # EAP-PSK (experimental; this is _not_ needed for WPA-PSK)
 #CONFIG_EAP_PSK=y
 
+# EAP-pwd (secure authentication using only a password)
+CONFIG_EAP_PWD=y
+
 # EAP-PAX
 #CONFIG_EAP_PAX=y
 
@@ -196,13 +200,15 @@ CONFIG_EAP_LEAP=y
 CONFIG_WPS=y
 # Enable WSC 2.0 support
 CONFIG_WPS2=y
+# Enable WPS external registrar functionality
+#CONFIG_WPS_ER=y
+# Disable credentials for an open network by default when acting as a WPS
+# registrar.
+#CONFIG_WPS_REG_DISABLE_OPEN=y
 
 # EAP-IKEv2
 #CONFIG_EAP_IKEV2=y
 
-# EAP-PWD
-CONFIG_EAP_PWD=y
-
 # PKCS#12 (PFX) support (used to read private key and certificate file from
 # a file that usually has extension .p12 or .pfx)
 CONFIG_PKCS12=y
@@ -215,6 +221,9 @@ CONFIG_SMARTCARD=y
 # Enable this if EAP-SIM or EAP-AKA is included
 #CONFIG_PCSC=y
 
+# Support HT overrides (disable HT/HT40, mask MCS rates, etc.)
+#CONFIG_HT_OVERRIDES=y
+
 # Development testing
 #CONFIG_EAPOL_TEST=y
 
@@ -233,6 +242,10 @@ CONFIG_CTRL_IFACE=y
 # the resulting binary.
 #CONFIG_READLINE=y
 
+# Include internal line edit mode in wpa_cli. This can be used as a replacement
+# for GNU Readline to provide limited command line editing and history support.
+CONFIG_WPA_CLI_EDIT=y
+
 # Remove debugging code that is printing out debug message to stdout.
 # This can be used to reduce the size of the wpa_supplicant considerably
 # if debugging code is not needed. The size reduction can be around 35%
@@ -294,6 +307,9 @@ CONFIG_OS=unix
 # eloop_none = Empty template
 CONFIG_ELOOP=eloop
 
+# Should we use poll instead of select? Select is used by default.
+#CONFIG_ELOOP_POLL=y
+
 # Select layer 2 packet implementation
 # linux = Linux packet socket (default)
 # pcap = libpcap/libdnet/WinPcap
@@ -314,18 +330,24 @@ CONFIG_PEERKEY=y
 
 # Select TLS implementation
 # openssl = OpenSSL (default)
-# gnutls = GnuTLS (needed for TLS/IA, see also CONFIG_GNUTLS_EXTRA)
+# gnutls = GnuTLS
 # internal = Internal TLSv1 implementation (experimental)
 # none = Empty template
 #CONFIG_TLS=openssl
 
-# Whether to enable TLS/IA support, which is required for EAP-TTLSv1.
-# You need CONFIG_TLS=gnutls for this to have any effect. Please note that
-# even though the core GnuTLS library is released under LGPL, this extra
-# library uses GPL and as such, the terms of GPL apply to the combination
-# of wpa_supplicant and GnuTLS if this option is enabled. BSD license may not
-# apply for distribution of the resulting binary.
-#CONFIG_GNUTLS_EXTRA=y
+# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.1)
+# can be enabled to get a stronger construction of messages when block ciphers
+# are used. It should be noted that some existing TLS v1.0 -based
+# implementation may not be compatible with TLS v1.1 message (ClientHello is
+# sent prior to negotiating which version will be used)
+#CONFIG_TLSV11=y
+
+# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.2)
+# can be enabled to enable use of stronger crypto algorithms. It should be
+# noted that some existing TLS v1.0 -based implementation may not be compatible
+# with TLS v1.2 message (ClientHello is sent prior to negotiating which version
+# will be used)
+#CONFIG_TLSV12=y
 
 # If CONFIG_TLS=internal is used, additional library and include paths are
 # needed for LibTomMath. Alternatively, an integrated, minimal version of
@@ -357,7 +379,7 @@ CONFIG_PEERKEY=y
 # (fi.w1.hostap.wpa_supplicant1)
 #CONFIG_CTRL_IFACE_DBUS_NEW=y
 
-# Add introspection support for new DBus control interface (requires libxml2)
+# Add introspection support for new DBus control interface
 #CONFIG_CTRL_IFACE_DBUS_INTRO=y
 
 # Add support for loading EAP methods dynamically as shared libraries.
@@ -387,7 +409,19 @@ CONFIG_PEERKEY=y
 # Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt)
 #CONFIG_DEBUG_FILE=y
 
-# Add support for writing debug log to Android logcat instead of standard output
+# Send debug messages to syslog instead of stdout
+#CONFIG_DEBUG_SYSLOG=y
+# Set syslog facility for debug messages
+#CONFIG_DEBUG_SYSLOG_FACILITY=LOG_DAEMON
+
+# Add support for sending all debug messages (regardless of debug verbosity)
+# to the Linux kernel tracing facility. This helps debug the entire stack by
+# making it easy to record everything happening from the driver up into the
+# same file, e.g., using trace-cmd.
+#CONFIG_DEBUG_LINUX_TRACING=y
+
+# Add support for writing debug log to Android logcat instead of standard
+# output
 CONFIG_ANDROID_LOG=y
 
 # Enable privilege separation (see README 'Privilege separation' for details)
@@ -397,11 +431,67 @@ CONFIG_ANDROID_LOG=y
 # MIC error reports by a random amount of time between 0 and 60 seconds
 #CONFIG_DELAYED_MIC_ERROR_REPORT=y
 
+# Enable tracing code for developer debugging
+# This tracks use of memory allocations and other registrations and reports
+# incorrect use with a backtrace of call (or allocation) location.
+#CONFIG_WPA_TRACE=y
+# For BSD, uncomment these.
+#LIBS += -lexecinfo
+#LIBS_p += -lexecinfo
+#LIBS_c += -lexecinfo
+
+# Use libbfd to get more details for developer debugging
+# This enables use of libbfd to get more detailed symbols for the backtraces
+# generated by CONFIG_WPA_TRACE=y.
+#CONFIG_WPA_TRACE_BFD=y
+# For BSD, uncomment these.
+#LIBS += -lbfd -liberty -lz
+#LIBS_p += -lbfd -liberty -lz
+#LIBS_c += -lbfd -liberty -lz
+
+# wpa_supplicant depends on strong random number generation being available
+# from the operating system. os_get_random() function is used to fetch random
+# data when needed, e.g., for key generation. On Linux and BSD systems, this
+# works by reading /dev/urandom. It should be noted that the OS entropy pool
+# needs to be properly initialized before wpa_supplicant is started. This is
+# important especially on embedded devices that do not have a hardware random
+# number generator and may by default start up with minimal entropy available
+# for random number generation.
+#
+# As a safety net, wpa_supplicant is by default trying to internally collect
+# additional entropy for generating random data to mix in with the data fetched
+# from the OS. This by itself is not considered to be very strong, but it may
+# help in cases where the system pool is not initialized properly. However, it
+# is very strongly recommended that the system pool is initialized with enough
+# entropy either by using hardware assisted random number generator or by
+# storing state over device reboots.
+#
+# wpa_supplicant can be configured to maintain its own entropy store over
+# restarts to enhance random number generation. This is not perfect, but it is
+# much more secure than using the same sequence of random numbers after every
+# reboot. This can be enabled with -e<entropy file> command line option. The
+# specified file needs to be readable and writable by wpa_supplicant.
+#
+# If the os_get_random() is known to provide strong random data (e.g., on
+# Linux/BSD, the board in question is known to have reliable source of random
+# data from /dev/urandom), the internal wpa_supplicant random pool can be
+# disabled. This will save some in binary size and CPU use. However, this
+# should only be considered for builds that are known to be used on devices
+# that meet the requirements described above.
+#CONFIG_NO_RANDOM_POOL=y
+
+# IEEE 802.11n (High Throughput) support (mainly for AP mode)
+CONFIG_IEEE80211N=y
+
+# Interworking (IEEE 802.11u)
+# This can be used to enable functionality to improve interworking with
+# external networks (GAS/ANQP to learn more about the networks and network
+# selection based on available credentials).
+#CONFIG_INTERWORKING=y
+
 # Disable roaming in wpa_supplicant
 CONFIG_NO_ROAMING=y
 
 # Enable P2P
-# IEEE 802.11n (High Throughput) support (mainly for AP mode)
-CONFIG_IEEE80211N=y
 CONFIG_P2P=y
 CONFIG_AP=y
index 6046249..f9e0045 100644 (file)
@@ -81,14 +81,23 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
         */
        if (wpa_s->hw.modes) {
                struct hostapd_hw_modes *mode = NULL;
-               int i;
+               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;
                        }
                }
-               if (mode && mode->ht_capab) {
+
+#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;
 
                        /*
@@ -145,6 +154,8 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
        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;
 
@@ -179,6 +190,12 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
                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)
@@ -238,7 +255,10 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
                              * configuration */
 #endif /* CONFIG_WPS2 */
        bss->eap_server = 1;
-       bss->wps_state = 2;
+
+       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);
@@ -261,6 +281,7 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
        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 */
 
@@ -349,11 +370,13 @@ static int ap_vendor_action_rx(void *ctx, const u8 *buf, size_t len, int freq)
 
 
 static int ap_probe_req_rx(void *ctx, const u8 *sa, const u8 *da,
-                          const u8 *bssid, const u8 *ie, size_t ie_len)
+                          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);
+       return wpas_p2p_probe_req_rx(wpa_s, sa, da, bssid, ie, ie_len,
+                                    ssi_signal);
 #else /* CONFIG_P2P */
        return 0;
 #endif /* CONFIG_P2P */
@@ -520,9 +543,8 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
                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->p2p_persistent_group,
-                       ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION);
+               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;
@@ -651,21 +673,6 @@ int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
 }
 
 
-static int wpa_supplicant_ap_wps_sta_cancel(struct hostapd_data *hapd,
-                                           struct sta_info *sta, void *ctx)
-{
-       if (sta && (sta->flags & WLAN_STA_WPS)) {
-               ap_sta_deauthenticate(hapd, sta,
-                                     WLAN_REASON_PREV_AUTH_NOT_VALID);
-               wpa_printf(MSG_DEBUG, "WPS: %s: Deauth sta=" MACSTR,
-                          __func__, MAC2STR(sta->addr));
-               return 1;
-       }
-
-       return 0;
-}
-
-
 int wpa_supplicant_ap_wps_cancel(struct wpa_supplicant *wpa_s)
 {
        struct wps_registrar *reg;
@@ -677,7 +684,7 @@ int wpa_supplicant_ap_wps_cancel(struct wpa_supplicant *wpa_s)
        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],
-                                 wpa_supplicant_ap_wps_sta_cancel, NULL);
+                                 ap_sta_wps_cancel, NULL);
 
        if (!reg_sel && !wps_sta) {
                wpa_printf(MSG_DEBUG, "No WPS operation in progress at this "
@@ -870,6 +877,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)
 {
@@ -930,6 +957,17 @@ int wpa_supplicant_ap_update_beacon(struct wpa_supplicant *wpa_s)
 }
 
 
+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)
 {
index f0eb67d..bc953d9 100644 (file)
@@ -31,6 +31,10 @@ 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,
@@ -45,5 +49,7 @@ 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 (file)
index 0000000..d0c040a
--- /dev/null
@@ -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 = 2;
+
+       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 (file)
index 0000000..e2a7652
--- /dev/null
@@ -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 (file)
index 0000000..424477b
--- /dev/null
@@ -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 (file)
index 0000000..102d723
--- /dev/null
@@ -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,
+};
index cbed2e0..580a82a 100644 (file)
 #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_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+                          const char *reason)
 {
        dl_list_del(&bss->list);
        dl_list_del(&bss->list_id);
        wpa_s->num_bss--;
        wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Remove id %u BSSID " MACSTR
-               " SSID '%s'", bss->id, MAC2STR(bss->bssid),
-               wpa_ssid_txt(bss->ssid, bss->ssid_len));
+               " 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);
 #ifdef CONFIG_INTERWORKING
        wpabuf_free(bss->anqp_venue_name);
@@ -53,6 +54,12 @@ static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
        wpabuf_free(bss->anqp_3gpp);
        wpabuf_free(bss->anqp_domain_name);
 #endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+       wpabuf_free(bss->hs20_operator_friendly_name);
+       wpabuf_free(bss->hs20_wan_metrics);
+       wpabuf_free(bss->hs20_connection_capability);
+       wpabuf_free(bss->hs20_operating_class);
+#endif /* CONFIG_HS20 */
        os_free(bss);
 }
 
@@ -61,6 +68,8 @@ 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,13 +121,21 @@ static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *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;
+}
+
+
 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);
+                       wpa_bss_remove(wpa_s, bss, __func__);
                        return 0;
                }
        }
@@ -127,21 +144,28 @@ static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s)
 }
 
 
-static void wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s)
+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;
+               return 0;
 
        /*
-        * Remove the oldest entry since no better candidate for removal was
-        * found.
+        * Remove the oldest entry that isn't currently in use.
         */
-       wpa_bss_remove(wpa_s, dl_list_first(&wpa_s->bss,
-                                           struct wpa_bss, list));
+       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;
 }
 
 
@@ -170,8 +194,13 @@ static void wpa_bss_add(struct wpa_supplicant *wpa_s,
                " 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)
-               wpa_bss_remove_oldest(wpa_s);
+       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;
+       }
 }
 
 
@@ -326,6 +355,8 @@ 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) {
+                       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);
@@ -340,14 +371,6 @@ static void wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *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;
-}
-
-
 void wpa_bss_update_start(struct wpa_supplicant *wpa_s)
 {
        wpa_s->bss_update_idx++;
@@ -375,6 +398,18 @@ void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
        }
 
        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 */
@@ -447,9 +482,7 @@ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
                        bss->scan_miss_count++;
                if (bss->scan_miss_count >=
                    wpa_s->conf->bss_expiration_scan_count) {
-                       wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Expire BSS %u due to "
-                               "no match in scan", bss->id);
-                       wpa_bss_remove(wpa_s, bss);
+                       wpa_bss_remove(wpa_s, bss, "no match in scan");
                }
        }
 }
@@ -471,9 +504,7 @@ void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age)
                        continue;
 
                if (os_time_before(&bss->last_update, &t)) {
-                       wpa_dbg(wpa_s, 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;
        }
@@ -510,7 +541,7 @@ void wpa_bss_flush(struct wpa_supplicant *wpa_s)
        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);
+               wpa_bss_remove(wpa_s, bss, __func__);
        }
 }
 
@@ -526,6 +557,8 @@ struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
                                   const u8 *bssid)
 {
        struct wpa_bss *bss;
+       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;
index 2bc9f82..65e962b 100644 (file)
@@ -19,24 +19,6 @@ struct wpa_scan_res;
 #define WPA_BSS_ASSOCIATED             BIT(5)
 #define WPA_BSS_ANQP_FETCH_TRIED       BIT(6)
 
-#define WPA_BSS_MASK_ALL               0xFFFFFFFF
-#define WPA_BSS_MASK_ID                        BIT(0)
-#define WPA_BSS_MASK_BSSID             BIT(1)
-#define WPA_BSS_MASK_FREQ              BIT(2)
-#define WPA_BSS_MASK_BEACON_INT                BIT(3)
-#define WPA_BSS_MASK_CAPABILITIES      BIT(4)
-#define WPA_BSS_MASK_QUAL              BIT(5)
-#define WPA_BSS_MASK_NOISE             BIT(6)
-#define WPA_BSS_MASK_LEVEL             BIT(7)
-#define WPA_BSS_MASK_TSF               BIT(8)
-#define WPA_BSS_MASK_AGE               BIT(9)
-#define WPA_BSS_MASK_IE                        BIT(10)
-#define WPA_BSS_MASK_FLAGS             BIT(11)
-#define WPA_BSS_MASK_SSID              BIT(12)
-#define WPA_BSS_MASK_WPS_SCAN          BIT(13)
-#define WPA_BSS_MASK_P2P_SCAN          BIT(14)
-#define WPA_BSS_MASK_INTERNETW         BIT(15)
-
 /**
  * struct wpa_bss - BSS table
  * @list: List entry for struct wpa_supplicant::bss
@@ -87,6 +69,12 @@ struct wpa_bss {
        struct wpabuf *anqp_3gpp;
        struct wpabuf *anqp_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 */
        size_t ie_len;
        size_t beacon_ie_len;
        /* followed by ie_len octets of IEs */
index d36d027..a795c41 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * 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 software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -13,6 +13,7 @@
 #include "crypto/sha1.h"
 #include "rsn_supp/wpa.h"
 #include "eap_peer/eap.h"
+#include "p2p/p2p.h"
 #include "config.h"
 
 
@@ -1130,6 +1131,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;
 }
@@ -1277,6 +1279,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);
@@ -1556,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) },
@@ -1622,6 +1630,7 @@ static const struct parse_data ssid_fields[] = {
        { INT_RANGE(frequency, 0, 10000) },
        { INT(wpa_ptk_rekey) },
        { STR(bgscan) },
+       { INT_RANGE(ignore_broadcast_ssid, 0, 2) },
 #ifdef CONFIG_P2P
        { FUNC(p2p_client_list) },
 #endif /* CONFIG_P2P */
@@ -1633,6 +1642,8 @@ static const struct parse_data ssid_fields[] = {
        { INT_RANGE(ampdu_density, -1, 7) },
        { STR(ht_mcs) },
 #endif /* CONFIG_HT_OVERRIDES */
+       { INT(ap_max_inactivity) },
+       { INT(dtim_period) },
 };
 
 #ifdef WPA_UNICODE_SSID
@@ -1701,13 +1712,14 @@ int wpa_config_add_prio_network(struct wpa_config *config,
                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;
@@ -1816,6 +1828,22 @@ void wpa_config_free_ssid(struct wpa_ssid *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);
+}
+
+
 /**
  * wpa_config_free - Free configuration data
  * @config: Configuration data from wpa_config_read()
@@ -1829,6 +1857,7 @@ 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) {
@@ -1837,6 +1866,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;
@@ -1847,11 +1883,14 @@ 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);
@@ -1861,12 +1900,11 @@ void wpa_config_free(struct wpa_config *config)
        os_free(config->config_methods);
        os_free(config->p2p_ssid_postfix);
        os_free(config->pssid);
-       os_free(config->home_realm);
-       os_free(config->home_username);
-       os_free(config->home_password);
-       os_free(config->home_ca_cert);
-       os_free(config->home_imsi);
-       os_free(config->home_milenage);
+       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);
 #ifdef ANDROID_P2P
        os_free(config->prioritize);
 #endif
@@ -1997,6 +2035,7 @@ 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;
@@ -2241,6 +2280,168 @@ 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;
+       }
+
+       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;
+               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 (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
@@ -2454,6 +2655,35 @@ static int wpa_global_config_parse_str(const struct global_parse_data *data,
 }
 
 
+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)
@@ -2528,6 +2758,43 @@ static int wpa_config_process_os_version(const struct global_parse_data *data,
        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
@@ -2551,6 +2818,55 @@ static int wpa_config_process_sec_device_type(
        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(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 */
 
 
@@ -2582,6 +2898,7 @@ static int wpa_config_process_hessid(
 #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
@@ -2590,10 +2907,13 @@ static const struct global_parse_data global_fields[] = {
 #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 },
@@ -2613,6 +2933,7 @@ static const struct global_parse_data global_fields[] = {
        { 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 },
@@ -2625,6 +2946,7 @@ static const struct global_parse_data global_fields[] = {
        { 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 },
 #endif /* CONFIG_P2P */
 #ifdef ANDROID_P2P
        { STR_RANGE(prioritize, 0, 32), CFG_CHANGED_IFACE_PRIORITY },
@@ -2636,15 +2958,18 @@ static const struct global_parse_data global_fields[] = {
        { INT_RANGE(filter_ssids, 0, 1), 0 },
        { INT(max_num_sta), 0 },
        { INT_RANGE(disassoc_low_ack, 0, 1), 0 },
-       { STR(home_realm), 0 },
-       { STR(home_username), 0 },
-       { STR(home_password), 0 },
-       { STR(home_ca_cert), 0 },
-       { STR(home_imsi), 0 },
-       { STR(home_milenage), 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(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 }
 };
 
 #undef FUNC
@@ -2654,6 +2979,7 @@ static const struct global_parse_data global_fields[] = {
 #undef _STR
 #undef STR
 #undef STR_RANGE
+#undef BIN
 #define NUM_GLOBAL_FIELDS (sizeof(global_fields) / sizeof(global_fields[0]))
 
 
index 432a5d4..074e384 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / Configuration file structures
- * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
 #include "wps/wps.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;
+
+       /**
+        * 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;
+};
+
+
 #define CFG_CHANGED_DEVICE_NAME BIT(0)
 #define CFG_CHANGED_CONFIG_METHODS BIT(1)
 #define CFG_CHANGED_DEVICE_TYPE BIT(2)
 #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)
 #ifdef ANDROID_P2P
-#define CFG_CHANGED_IFACE_PRIORITY BIT(13)
+#define CFG_CHANGED_IFACE_PRIORITY BIT(14)
 #endif
 
 /**
@@ -75,6 +199,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
@@ -116,6 +247,15 @@ 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
@@ -214,6 +354,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
@@ -359,6 +516,10 @@ struct wpa_config {
        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
        /**
@@ -377,9 +538,12 @@ struct wpa_config {
         * 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.
+        * 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.
         */
-       unsigned int p2p_group_idle;
+       int p2p_group_idle;
 
        /**
         * bss_max_count - Maximum number of BSS entries to keep in memory
@@ -452,35 +616,55 @@ struct wpa_config {
        u8 hessid[ETH_ALEN];
 
        /**
-        * home_realm - Home Realm for Interworking
+        * hs20 - Hotspot 2.0
         */
-       char *home_realm;
+       int hs20;
 
        /**
-        * home_username - Username for Interworking network selection
+        * 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).
         */
-       char *home_username;
+       int pbc_in_m1;
 
        /**
-        * home_password - Password for Interworking network selection
+        * 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 *home_password;
+       char *autoscan;
 
        /**
-        * home_ca_cert - CA certificate for Interworking network selection
+        * wps_nfc_dev_pw_id - NFC Device Password ID for password token
         */
-       char *home_ca_cert;
+       int wps_nfc_dev_pw_id;
 
        /**
-        * home_imsi - IMSI in <MCC> | <MNC> | '-' | <MSIN> format
+        * wps_nfc_dh_pubkey - NFC DH Public Key for password token
         */
-       char *home_imsi;
+       struct wpabuf *wps_nfc_dh_pubkey;
 
        /**
-        * home_milenage - Milenage parameters for SIM/USIM simulator in
-        *      <Ki>:<OPc>:<SQN> format
+        * wps_nfc_dh_pubkey - NFC DH Private Key for password token
         */
-       char *home_milenage;
+       struct wpabuf *wps_nfc_dh_privkey;
+
+       /**
+        * wps_nfc_dh_pubkey - NFC Device Password for password token
+        */
+       struct wpabuf *wps_nfc_dev_pw;
+
 #ifdef ANDROID_P2P
        /**
         * prioritize - Prioritize an Interface
@@ -522,6 +706,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
index a1955d4..8badc7b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * 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 software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -16,6 +16,7 @@
 #include "config.h"
 #include "base64.h"
 #include "uuid.h"
+#include "p2p/p2p.h"
 
 
 /**
@@ -178,6 +179,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)
@@ -264,11 +320,13 @@ static int wpa_config_process_blob(struct wpa_config *config, FILE *f,
 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)
@@ -302,6 +360,20 @@ 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)
@@ -322,6 +394,7 @@ 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) {
@@ -515,9 +588,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);
@@ -583,6 +659,29 @@ 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)
+               fprintf(f, "\tpassword=\"%s\"\n", cred->password);
+       if (cred->ca_cert)
+               fprintf(f, "\tca_cert=\"%s\"\n", cred->ca_cert);
+       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);
+}
+
+
 #ifndef CONFIG_NO_CONFIG_BLOBS
 static int wpa_config_write_blob(FILE *f, struct wpa_config_blob *blob)
 {
@@ -599,6 +698,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
@@ -612,6 +728,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)
@@ -623,6 +742,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)
@@ -667,6 +790,16 @@ 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)
@@ -691,6 +824,16 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
                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");
+       }
 #endif /* CONFIG_P2P */
        if (config->country[0] && config->country[1]) {
                fprintf(f, "country=%c%c\n",
@@ -711,19 +854,11 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
                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->home_realm)
-               fprintf(f, "home_realm=%s\n", config->home_realm);
-       if (config->home_username)
-               fprintf(f, "home_username=%s\n", config->home_username);
-       if (config->home_password)
-               fprintf(f, "home_password=%s\n", config->home_password);
-       if (config->home_ca_cert)
-               fprintf(f, "home_ca_cert=%s\n", config->home_ca_cert);
-       if (config->home_imsi)
-               fprintf(f, "home_imsi=%s\n", config->home_imsi);
-       if (config->home_milenage)
-               fprintf(f, "home_milenage=%s\n", config->home_milenage);
        if (config->interworking)
                fprintf(f, "interworking=%u\n", config->interworking);
        if (!is_zero_ether_addr(config->hessid))
@@ -732,6 +867,14 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
                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);
 }
 
 #endif /* CONFIG_NO_CONFIG_WRITE */
@@ -742,6 +885,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 */
@@ -757,6 +901,12 @@ 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 || ssid->temporary)
                        continue; /* do not save temporary networks */
index 3be6c26..59ec309 100644 (file)
@@ -25,6 +25,7 @@
                       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_MAX_AMSDU -1 /* no change */
@@ -157,6 +158,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;
@@ -377,6 +384,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
@@ -476,6 +497,20 @@ struct wpa_ssid {
         */
        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;
 };
 
 #endif /* CONFIG_SSID_H */
index a22cce5..2224738 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * 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 software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -28,6 +28,7 @@
 #include "ap.h"
 #include "p2p_supplicant.h"
 #include "p2p/p2p.h"
+#include "hs20_supplicant.h"
 #include "notify.h"
 #include "bss.h"
 #include "scan.h"
@@ -35,6 +36,7 @@
 #include "interworking.h"
 #include "blacklist.h"
 #include "wpas_glue.h"
+#include "autoscan.h"
 
 extern struct wpa_driver_ops *wpa_drivers[];
 
@@ -59,7 +61,7 @@ static int pno_start(struct wpa_supplicant *wpa_s)
        num_ssid = 0;
        ssid = wpa_s->conf->ssid;
        while (ssid) {
-               if (!ssid->disabled)
+               if (!wpas_network_disabled(wpa_s, ssid))
                        num_ssid++;
                ssid = ssid->next;
        }
@@ -81,7 +83,7 @@ static int pno_start(struct wpa_supplicant *wpa_s)
        i = 0;
        ssid = wpa_s->conf->ssid;
        while (ssid) {
-               if (!ssid->disabled) {
+               if (!wpas_network_disabled(wpa_s, ssid)) {
                        params.ssids[i].ssid = ssid->ssid;
                        params.ssids[i].ssid_len = ssid->ssid_len;
                        params.num_ssids++;
@@ -114,6 +116,43 @@ static int pno_stop(struct wpa_supplicant *wpa_s)
 }
 
 
+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(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 wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
                                         char *cmd)
 {
@@ -197,8 +236,52 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
                        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);
+       } else if (os_strcasecmp(cmd, "bssid_filter") == 0) {
+               ret = set_bssid_filter(wpa_s, value);
        } else {
                value[-1] = '=';
                ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
@@ -539,6 +622,80 @@ static int wpa_supplicant_ctrl_iface_wps_oob(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_WPS_OOB */
 
 
+#ifdef CONFIG_WPS_NFC
+
+static int wpa_supplicant_ctrl_iface_wps_nfc(struct wpa_supplicant *wpa_s,
+                                            char *cmd)
+{
+       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;
+}
+
+#endif /* CONFIG_WPS_NFC */
+
+
 static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
                                             char *cmd)
 {
@@ -735,6 +892,43 @@ static int wpa_supplicant_ctrl_iface_wps_er_config(
        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 */
@@ -760,78 +954,6 @@ static int wpa_supplicant_ctrl_iface_ibss_rsn(
 #endif /* CONFIG_IBSS_RSN */
 
 
-int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
-                                             struct wpa_ssid *ssid,
-                                             const char *field,
-                                             const char *value)
-{
-#ifdef IEEE8021X_EAPOL
-       struct eap_peer_config *eap = &ssid->eap;
-
-       wpa_printf(MSG_DEBUG, "CTRL_IFACE: response handle field=%s", field);
-       wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: response value",
-                             (const u8 *) value, os_strlen(value));
-
-       switch (wpa_supplicant_ctrl_req_from_string(field)) {
-       case WPA_CTRL_REQ_EAP_IDENTITY:
-               os_free(eap->identity);
-               eap->identity = (u8 *) os_strdup(value);
-               eap->identity_len = os_strlen(value);
-               eap->pending_req_identity = 0;
-               if (ssid == wpa_s->current_ssid)
-                       wpa_s->reassociate = 1;
-               break;
-       case WPA_CTRL_REQ_EAP_PASSWORD:
-               os_free(eap->password);
-               eap->password = (u8 *) os_strdup(value);
-               eap->password_len = os_strlen(value);
-               eap->pending_req_password = 0;
-               if (ssid == wpa_s->current_ssid)
-                       wpa_s->reassociate = 1;
-               break;
-       case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
-               os_free(eap->new_password);
-               eap->new_password = (u8 *) os_strdup(value);
-               eap->new_password_len = os_strlen(value);
-               eap->pending_req_new_password = 0;
-               if (ssid == wpa_s->current_ssid)
-                       wpa_s->reassociate = 1;
-               break;
-       case WPA_CTRL_REQ_EAP_PIN:
-               os_free(eap->pin);
-               eap->pin = os_strdup(value);
-               eap->pending_req_pin = 0;
-               if (ssid == wpa_s->current_ssid)
-                       wpa_s->reassociate = 1;
-               break;
-       case WPA_CTRL_REQ_EAP_OTP:
-               os_free(eap->otp);
-               eap->otp = (u8 *) os_strdup(value);
-               eap->otp_len = os_strlen(value);
-               os_free(eap->pending_req_otp);
-               eap->pending_req_otp = NULL;
-               eap->pending_req_otp_len = 0;
-               break;
-       case WPA_CTRL_REQ_EAP_PASSPHRASE:
-               os_free(eap->private_key_passwd);
-               eap->private_key_passwd = (u8 *) os_strdup(value);
-               eap->pending_req_passphrase = 0;
-               if (ssid == wpa_s->current_ssid)
-                       wpa_s->reassociate = 1;
-               break;
-       default:
-               wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field);
-               return -1;
-       }
-
-       return 0;
-#else /* IEEE8021X_EAPOL */
-       wpa_printf(MSG_DEBUG, "CTRL_IFACE: IEEE 802.1X not included");
-       return -1;
-#endif /* IEEE8021X_EAPOL */
-}
-
-
 static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
                                              char *rsp)
 {
@@ -997,6 +1119,16 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
                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)) {
+               ret = os_snprintf(pos, end - pos, "hs20=1\n");
+               if (ret < 0 || ret >= end - pos)
+                       return pos - buf;
+               pos += ret;
+       }
+#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,
@@ -1507,6 +1639,14 @@ static int wpa_supplicant_ctrl_iface_scan_result(
                        return -1;
                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, "\t%s",
                          wpa_ssid_txt(bss->ssid, bss->ssid_len));
@@ -1608,6 +1748,11 @@ static int wpa_supplicant_ctrl_iface_enable_network(
                                   "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);
 
@@ -1691,6 +1836,9 @@ static int wpa_supplicant_ctrl_iface_remove_network(
                }
                eapol_sm_invalidate_cached_session(wpa_s->eapol);
                if (wpa_s->current_ssid) {
+#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_disassociate(wpa_s,
@@ -1713,6 +1861,9 @@ static int wpa_supplicant_ctrl_iface_remove_network(
        }
 
        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 or
                 * previously used network is removed.
@@ -1833,6 +1984,132 @@ 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 wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s,
+                                                char *cmd)
+{
+       int id;
+       struct wpa_cred *cred;
+
+       /* cmd: "<cred id>" or "all" */
+       if (os_strcmp(cmd, "all") == 0) {
+               wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED all");
+               cred = wpa_s->conf->cred;
+               while (cred) {
+                       id = cred->id;
+                       cred = cred->next;
+                       wpa_config_remove_cred(wpa_s->conf, id);
+               }
+               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);
+       if (cred == NULL ||
+           wpa_config_remove_cred(wpa_s->conf, id) < 0) {
+               wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d",
+                          id);
+               return -1;
+       }
+
+       return 0;
+}
+
+
+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)
 {
@@ -2254,9 +2531,7 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
        int ret;
        char *pos, *end;
        const u8 *ie, *ie2;
-       struct os_time now;
 
-       os_get_time(&now);
        pos = buf;
        end = buf + buflen;
 
@@ -2328,6 +2603,9 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
        }
 
        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)
@@ -2394,6 +2672,14 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
                                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)
@@ -2444,19 +2730,28 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
                pos = anqp_add_hex(pos, end, "anqp_3gpp", bss->anqp_3gpp);
                pos = anqp_add_hex(pos, end, "anqp_domain_name",
                                   bss->anqp_domain_name);
+#ifdef CONFIG_HS20
+               pos = anqp_add_hex(pos, end, "hs20_operator_friendly_name",
+                                  bss->hs20_operator_friendly_name);
+               pos = anqp_add_hex(pos, end, "hs20_wan_metrics",
+                                  bss->hs20_wan_metrics);
+               pos = anqp_add_hex(pos, end, "hs20_connection_capability",
+                                  bss->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)
 {
        u8 bssid[ETH_ALEN];
        size_t i;
-       struct wpa_bss *bss = NULL;
+       struct wpa_bss *bss;
        struct wpa_bss *bsslast = NULL;
        struct dl_list *next;
        int ret = 0;
@@ -2467,33 +2762,45 @@ static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
        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);
+                                           list_id);
                        bsslast = dl_list_last(&wpa_s->bss_id, struct wpa_bss,
                                               list_id);
                } else { /* N1-N2 */
-                       if ((ctmp = os_strchr(cmd + 6, '-')) != NULL) {
-                               int id1, id2;
-                               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);
-                       } else {
-                               wpa_printf(MSG_ERROR, "Wrong range format");
+                       unsigned int id1, id2;
+
+                       if ((ctmp = os_strchr(cmd + 6, '-')) == NULL) {
+                               wpa_printf(MSG_INFO, "Wrong BSS range "
+                                          "format");
                                return 0;
                        }
-               }
-               if ((ctmp = os_strstr(cmd, "MASK=")) != NULL) {
-                       mask = strtoul(ctmp + 5, NULL, 0x10);
-                       if (mask == 0)
-                               mask = WPA_BSS_MASK_ALL;
+
+                       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, struct wpa_bss, list);
+               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);
@@ -2530,6 +2837,12 @@ 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;
 
@@ -2564,10 +2877,7 @@ static int wpa_supplicant_ctrl_iface_scan_interval(
        struct wpa_supplicant *wpa_s, char *cmd)
 {
        int scan_int = atoi(cmd);
-       if (scan_int < 0)
-               return -1;
-       wpa_s->scan_interval = scan_int;
-       return 0;
+       return wpa_supplicant_set_scan_interval(wpa_s, scan_int);
 }
 
 
@@ -2688,14 +2998,17 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
        enum p2p_wps_method wps_method;
        int new_pin;
        int ret;
-       int persistent_group;
+       int persistent_group, persistent_id = -1;
        int join;
        int auth;
+       int automatic;
        int go_intent = -1;
        int freq = 0;
+       int pd;
 
-       /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad] [persistent]
-        * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] */
+       /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad]
+        * [persistent|persistent=<network id>]
+        * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc] */
 
        if (hwaddr_aton(cmd, addr))
                return -1;
@@ -2706,8 +3019,23 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
        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;
 
        pos2 = os_strstr(pos, " go_intent=");
        if (pos2) {
@@ -2739,11 +3067,15 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
                        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, join, auth, go_intent,
-                                  freq);
+                                  persistent_group, automatic, join,
+                                  auth, go_intent, freq, persistent_id, pd);
        if (new_pin == -2) {
                os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
                return 25;
@@ -2777,8 +3109,9 @@ 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] */
+       /* <addr> <config method> [join|auto] */
 
        if (hwaddr_aton(cmd, addr))
                return -1;
@@ -2788,8 +3121,12 @@ static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd)
                return -1;
        pos++;
 
-       return wpas_p2p_prov_disc(wpa_s, addr, pos,
-                                 os_strstr(pos, "join") != NULL);
+       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);
 }
 
 
@@ -2926,6 +3263,8 @@ static int p2p_ctrl_serv_disc_resp(struct wpa_supplicant *wpa_s, char *cmd)
 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;
 }
@@ -3278,6 +3617,56 @@ static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
 }
 
 
+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(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;
@@ -3356,7 +3745,7 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
                }
                return 0;
        }
-#ifdef ANDROID_P2P
+
        if (os_strcmp(cmd, "conc_pref") == 0) {
                if (os_strcmp(param, "sta") == 0)
                        wpa_s->global->conc_pref = WPA_CONC_PREF_STA;
@@ -3367,10 +3756,10 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
                        return -1;
                }
                wpa_printf(MSG_DEBUG, "Single channel concurrency preference: "
-                       "%s", param);
+                          "%s", param);
                return 0;
        }
-#endif
+
        if (os_strcmp(cmd, "force_long_sd") == 0) {
                wpa_s->force_long_sd = atoi(param);
                return 0;
@@ -3436,6 +3825,9 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
                return 0;
        }
 
+       if (os_strcmp(cmd, "disallow_freq") == 0)
+               return p2p_ctrl_disallow_freq(wpa_s, param);
+
        wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
                   cmd);
 
@@ -3548,6 +3940,111 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
 #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)
 {
@@ -3556,6 +4053,36 @@ static int wpa_supplicant_ctrl_iface_sta_autoconnect(
 }
 
 
+#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 */
+
+
 static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
                                      size_t buflen)
 {
@@ -3654,6 +4181,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
        } else if (os_strcmp(buf, "REASSOCIATE") == 0) {
                wpa_s->normal_scans = 0;
+               wpa_supplicant_reinit_autoscan(wpa_s);
                if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
                        reply_len = -1;
                else {
@@ -3663,6 +4191,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                }
        } else if (os_strcmp(buf, "RECONNECT") == 0) {
                wpa_s->normal_scans = 0;
+               wpa_supplicant_reinit_autoscan(wpa_s);
                if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
                        reply_len = -1;
                else if (wpa_s->disconnected) {
@@ -3715,6 +4244,21 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                if (wpa_supplicant_ctrl_iface_wps_oob(wpa_s, buf + 8))
                        reply_len = -1;
 #endif /* CONFIG_WPS_OOB */
+#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;
+       } 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;
+#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;
@@ -3759,6 +4303,11 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } 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
@@ -3873,6 +4422,14 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                if (get_anqp(wpa_s, buf + 9) < 0)
                        reply_len = -1;
 #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(
@@ -3898,19 +4455,30 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                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->normal_scans = 0;
                if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
                        reply_len = -1;
                else {
                        if (!wpa_s->scanning &&
                            ((wpa_s->wpa_state <= WPA_SCANNING) ||
                             (wpa_s->wpa_state == WPA_COMPLETED))) {
+                               wpa_s->normal_scans = 0;
+                               wpa_s->scan_req = 2;
+                               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 = 2;
                                wpa_supplicant_req_scan(wpa_s, 0, 0);
                        } else {
@@ -3944,6 +4512,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))
@@ -3976,6 +4556,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);
@@ -4010,6 +4596,11 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) {
                reply_len = wpa_supplicant_signal_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 */
 #ifdef ANDROID
        } else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
                reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply,
index 3f1c6a0..a329ef3 100644 (file)
@@ -89,21 +89,6 @@ void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv);
 void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv);
 
 /**
- * wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
- * @wpa_s: Pointer to wpa_supplicant data
- * @ssid: Pointer to the network block the reply is for
- * @field: field the response is a reply for
- * @value: value (ie, password, etc) for @field
- * Returns: 0 on success, non-zero on error
- *
- * Helper function to handle replies to control interface requests.
- */
-int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
-                                             struct wpa_ssid *ssid,
-                                             const char *field,
-                                             const char *value);
-
-/**
  * wpa_supplicant_global_ctrl_iface_init - Initialize global control interface
  * @global: Pointer to global data from wpa_supplicant_init()
  * Returns: Pointer to private data on success, %NULL on failure
index 301156e..8dba46d 100644 (file)
@@ -184,6 +184,7 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
                                wpa_s = eloop_ctx;
                        }
                        os_memmove(ifname, ifend, strlen(ifend) + 1);
+                       wpa_printf(MSG_DEBUG, "wpa_s %p cmd %s", wpa_s, buf);
                }
 #endif /* defined CONFIG_P2P && defined ANDROID_P2P */
                reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
@@ -397,7 +398,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 "
@@ -689,7 +690,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"
@@ -704,7 +706,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 "
index 5850636..5d0e31e 100644 (file)
@@ -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"
index 50da09b..aea7db7 100644 (file)
@@ -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
index 9dab1ee..a551ccd 100644 (file)
@@ -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 */
index 68a9c28..67924e0 100644 (file)
@@ -2,14 +2,8 @@
  * 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"
@@ -1104,5 +1098,5 @@ void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry)
                break;
        }
 
-       memset(entry, 0, sizeof(struct wpa_dbus_dict_entry));
+       os_memset(entry, 0, sizeof(struct wpa_dbus_dict_entry));
 }
index 2f6eb45..9666349 100644 (file)
@@ -2,14 +2,8 @@
  * 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
index ce7cffb..a9957ab 100644 (file)
@@ -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"
 #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 */
+
 
 /**
  * wpas_dbus_signal_interface - Send a interface related event signal
@@ -747,6 +834,41 @@ 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
 
 /**
@@ -953,7 +1075,7 @@ static int wpas_dbus_get_group_obj_path(struct wpa_supplicant *wpa_s,
        if (os_memcmp(ssid->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN))
                return -1;
 
-       memcpy(group_name, ssid->ssid + P2P_WILDCARD_SSID_LEN, 2);
+       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,
@@ -1607,10 +1729,12 @@ void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
                                   enum wpas_dbus_prop property)
 {
        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:
                prop = "ApScan";
@@ -1633,6 +1757,10 @@ void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
        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);
@@ -1642,6 +1770,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);
+       }
 }
 
 
@@ -1792,6 +1924,15 @@ 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 } }
 };
 
@@ -2029,11 +2170,11 @@ 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);
 
-#ifdef CONFIG_P2P
        /* 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);
@@ -2487,6 +2628,20 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
                  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 } }
 };
 
@@ -2559,6 +2714,10 @@ static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
          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",
          wpas_dbus_getter_process_credentials,
@@ -2566,9 +2725,9 @@ static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
        },
 #endif /* CONFIG_WPS */
 #ifdef CONFIG_P2P
-       { "P2PDeviceProperties", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "a{sv}",
-         wpas_dbus_getter_p2p_device_properties,
-         wpas_dbus_setter_p2p_device_properties
+       { "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,
@@ -2591,6 +2750,10 @@ static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
          NULL
        },
 #endif /* CONFIG_P2P */
+       { "DisconnectReason", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
+         wpas_dbus_getter_disconnect_reason,
+         NULL
+       },
        { NULL, NULL, NULL, NULL, NULL }
 };
 
@@ -2809,12 +2972,27 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
          }
        },
 #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 } }
 };
 
@@ -2882,6 +3060,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;
@@ -2921,11 +3108,11 @@ static const struct wpa_dbus_property_desc wpas_dbus_p2p_peer_properties[] = {
          wpas_dbus_getter_p2p_peer_group_capability,
          NULL
        },
-       { "SecondaryDeviceTypes", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
+       { "SecondaryDeviceTypes", WPAS_DBUS_NEW_IFACE_P2P_PEER, "aay",
          wpas_dbus_getter_p2p_peer_secondary_device_types,
          NULL
        },
-       { "VendorExtension", WPAS_DBUS_NEW_IFACE_P2P_PEER, "as",
+       { "VendorExtension", WPAS_DBUS_NEW_IFACE_P2P_PEER, "aay",
          wpas_dbus_getter_p2p_peer_vendor_extension,
          NULL
        },
@@ -3126,10 +3313,37 @@ static const struct wpa_dbus_property_desc wpas_dbus_p2p_group_properties[] = {
          wpas_dbus_getter_p2p_group_members,
          NULL
        },
-       { "Properties",
-         WPAS_DBUS_NEW_IFACE_P2P_GROUP, "a{sv}",
-         wpas_dbus_getter_p2p_group_properties,
-         wpas_dbus_setter_p2p_group_properties
+       { "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 }
 };
@@ -3251,10 +3465,6 @@ void wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s,
 
 static const struct wpa_dbus_property_desc
 wpas_dbus_p2p_groupmember_properties[] = {
-       { "Properties", WPAS_DBUS_NEW_IFACE_P2P_GROUPMEMBER, "a{sv}",
-         wpas_dbus_getter_p2p_group_properties,
-         NULL
-       },
        { NULL, NULL, NULL, NULL, NULL }
 };
 
index 93ce722..44cde42 100644 (file)
@@ -3,14 +3,8 @@
  * 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
@@ -34,6 +28,7 @@ enum wpas_dbus_prop {
        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 {
@@ -115,6 +110,17 @@ enum wpas_dbus_bss_prop {
 #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
 
@@ -210,6 +216,11 @@ 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 */
 
@@ -467,6 +478,20 @@ static inline void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
 {
 }
 
+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 */
index da67bea..8145a70 100644 (file)
@@ -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"
 #include "../bss.h"
 #include "../scan.h"
 #include "../ctrl_iface.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;
@@ -253,7 +249,7 @@ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
 
                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);
@@ -448,6 +444,76 @@ dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter,
 
 
 /**
+ * wpas_dbus_simple_array_array_property_getter - Get array array type property
+ * @iter: Pointer to incoming dbus message iterator
+ * @type: DBus type of property array elements (must be basic type)
+ * @array: pointer to array of elements to put into response message
+ * @array_len: length of above array
+ * @error: a pointer to an error to fill on failure
+ * Returns: TRUE if the request succeeded, FALSE if it failed
+ *
+ * Generic getter for array type properties. Array elements type is
+ * required to be basic.
+ */
+dbus_bool_t wpas_dbus_simple_array_array_property_getter(DBusMessageIter *iter,
+                                                        const int type,
+                                                        struct wpabuf **array,
+                                                        size_t array_len,
+                                                        DBusError *error)
+{
+       DBusMessageIter variant_iter, array_iter;
+       char type_str[] = "aa?";
+       char inner_type_str[] = "a?";
+       const char *sub_type_str;
+       size_t i;
+
+       if (!dbus_type_is_basic(type)) {
+               dbus_set_error(error, DBUS_ERROR_FAILED,
+                              "%s: given type is not basic", __func__);
+               return FALSE;
+       }
+
+       sub_type_str = wpa_dbus_type_as_string(type);
+       type_str[2] = sub_type_str[0];
+       inner_type_str[1] = sub_type_str[0];
+
+       if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+                                             type_str, &variant_iter)) {
+               dbus_set_error(error, DBUS_ERROR_FAILED,
+                              "%s: failed to construct message 1", __func__);
+               return FALSE;
+       }
+       if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+                                             inner_type_str, &array_iter)) {
+               dbus_set_error(error, DBUS_ERROR_FAILED,
+                              "%s: failed to construct message 2", __func__);
+               return FALSE;
+       }
+
+       for (i = 0; i < array_len; i++) {
+               wpa_dbus_dict_bin_array_add_element(&array_iter,
+                                                   wpabuf_head(array[i]),
+                                                   wpabuf_len(array[i]));
+
+       }
+
+       if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) {
+               dbus_set_error(error, DBUS_ERROR_FAILED,
+                              "%s: failed to close message 2", __func__);
+               return FALSE;
+       }
+
+       if (!dbus_message_iter_close_container(iter, &variant_iter)) {
+               dbus_set_error(error, DBUS_ERROR_FAILED,
+                              "%s: failed to close message 1", __func__);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+
+/**
  * wpas_dbus_handler_create_interface - Request registration of a network iface
  * @message: Pointer to incoming dbus message
  * @global: %wpa_supplicant global data structure
@@ -477,25 +543,25 @@ DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
        while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
                if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
                        goto error;
-               if (!strcmp(entry.key, "Driver") &&
+               if (!os_strcmp(entry.key, "Driver") &&
                    (entry.type == DBUS_TYPE_STRING)) {
                        driver = os_strdup(entry.str_value);
                        wpa_dbus_dict_entry_clear(&entry);
                        if (driver == NULL)
                                goto error;
-               } else if (!strcmp(entry.key, "Ifname") &&
+               } else if (!os_strcmp(entry.key, "Ifname") &&
                           (entry.type == DBUS_TYPE_STRING)) {
                        ifname = os_strdup(entry.str_value);
                        wpa_dbus_dict_entry_clear(&entry);
                        if (ifname == NULL)
                                goto error;
-               } else if (!strcmp(entry.key, "ConfigFile") &&
+               } else if (!os_strcmp(entry.key, "ConfigFile") &&
                           (entry.type == DBUS_TYPE_STRING)) {
                        confname = os_strdup(entry.str_value);
                        wpa_dbus_dict_entry_clear(&entry);
                        if (confname == NULL)
                                goto error;
-               } else if (!strcmp(entry.key, "BridgeIfname") &&
+               } else if (!os_strcmp(entry.key, "BridgeIfname") &&
                           (entry.type == DBUS_TYPE_STRING)) {
                        bridge_ifname = os_strdup(entry.str_value);
                        wpa_dbus_dict_entry_clear(&entry);
@@ -1216,6 +1282,9 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
                        /* Add wildcard ssid */
                        params.num_ssids++;
                }
+#ifdef CONFIG_AUTOSCAN
+               autoscan_deinit(wpa_s);
+#endif /* CONFIG_AUTOSCAN */
                wpa_supplicant_trigger_scan(wpa_s, &params);
        } else {
                wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
@@ -1736,6 +1805,54 @@ DBusMessage * wpas_dbus_handler_flush_bss(DBusMessage *message,
 }
 
 
+#ifdef CONFIG_AUTOSCAN
+/**
+ * wpas_dbus_handler_autoscan - Set autoscan parameters for the interface
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL
+ *
+ * Handler function for "AutoScan" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_autoscan(DBusMessage *message,
+                                        struct wpa_supplicant *wpa_s)
+{
+       DBusMessage *reply = NULL;
+       enum wpa_states state = wpa_s->wpa_state;
+       char *arg;
+
+       dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg,
+                             DBUS_TYPE_INVALID);
+
+       if (arg != NULL && os_strlen(arg) > 0) {
+               char *tmp;
+               tmp = os_strdup(arg);
+               if (tmp == NULL) {
+                       reply = dbus_message_new_error(message,
+                                                      DBUS_ERROR_NO_MEMORY,
+                                                      NULL);
+               } else {
+                       os_free(wpa_s->conf->autoscan);
+                       wpa_s->conf->autoscan = tmp;
+                       if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
+                               autoscan_init(wpa_s, 1);
+                       else if (state == WPA_SCANNING)
+                               wpa_supplicant_reinit_autoscan(wpa_s);
+               }
+       } else if (arg != NULL && os_strlen(arg) == 0) {
+               os_free(wpa_s->conf->autoscan);
+               wpa_s->conf->autoscan = NULL;
+               autoscan_deinit(wpa_s);
+       } else
+               reply = dbus_message_new_error(message,
+                                              DBUS_ERROR_INVALID_ARGS,
+                                              NULL);
+
+       return reply;
+}
+#endif /* CONFIG_AUTOSCAN */
+
+
 /**
  * wpas_dbus_getter_capabilities - Return interface capabilities
  * @iter: Pointer to incoming dbus message iter
@@ -2229,6 +2346,27 @@ dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter,
 
 
 /**
+ * wpas_dbus_getter_disconnect_reason - Get most recent reason for disconnect
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "DisconnectReason" property.  The reason is negative if it is
+ * locally generated.
+ */
+dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter,
+                                              DBusError *error,
+                                              void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       dbus_int32_t reason = wpa_s->disconnect_reason;
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
+                                               &reason, error);
+}
+
+
+/**
  * wpas_dbus_getter_bss_expire_age - Get BSS entry expiration age
  * @iter: Pointer to incoming dbus message iter
  * @error: Location to store error on failure
@@ -2392,6 +2530,56 @@ dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error,
 
 
 /**
+ * wpas_dbus_getter_scan_interval - Get scan interval
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter function for "ScanInterval" property.
+ */
+dbus_bool_t wpas_dbus_getter_scan_interval(DBusMessageIter *iter,
+                                          DBusError *error,
+                                          void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       dbus_int32_t scan_interval = wpa_s->scan_interval;
+
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
+                                               &scan_interval, error);
+}
+
+
+/**
+ * wpas_dbus_setter_scan_interval - Control scan interval
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter function for "ScanInterval" property.
+ */
+dbus_bool_t wpas_dbus_setter_scan_interval(DBusMessageIter *iter,
+                                          DBusError *error,
+                                          void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       dbus_int32_t scan_interval;
+
+       if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_INT32,
+                                             &scan_interval))
+               return FALSE;
+
+       if (wpa_supplicant_set_scan_interval(wpa_s, scan_interval)) {
+               dbus_set_error_const(error, DBUS_ERROR_FAILED,
+                                    "scan_interval must be >= 0");
+               return FALSE;
+       }
+       return TRUE;
+}
+
+
+/**
  * wpas_dbus_getter_ifname - Get interface name
  * @iter: Pointer to incoming dbus message iter
  * @error: Location to store error on failure
@@ -3292,3 +3480,139 @@ dbus_bool_t wpas_dbus_setter_network_properties(DBusMessageIter *iter,
        dbus_message_iter_recurse(iter, &variant_iter);
        return set_network_properties(net->wpa_s, ssid, &variant_iter, error);
 }
+
+
+#ifdef CONFIG_AP
+
+DBusMessage * wpas_dbus_handler_subscribe_preq(
+       DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+       struct wpas_dbus_priv *priv = wpa_s->global->dbus;
+       char *name;
+
+       if (wpa_s->preq_notify_peer != NULL) {
+               if (os_strcmp(dbus_message_get_sender(message),
+                             wpa_s->preq_notify_peer) == 0)
+                       return NULL;
+
+               return dbus_message_new_error(message,
+                       WPAS_DBUS_ERROR_SUBSCRIPTION_IN_USE,
+                       "Another application is already subscribed");
+       }
+
+       name = os_strdup(dbus_message_get_sender(message));
+       if (!name)
+               return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+                                             "out of memory");
+
+       wpa_s->preq_notify_peer = name;
+
+       /* Subscribe to clean up if application closes socket */
+       wpas_dbus_subscribe_noc(priv);
+
+       /*
+        * Double-check it's still alive to make sure that we didn't
+        * miss the NameOwnerChanged signal, e.g. while strdup'ing.
+        */
+       if (!dbus_bus_name_has_owner(priv->con, name, NULL)) {
+               /*
+                * Application no longer exists, clean up.
+                * The return value is irrelevant now.
+                *
+                * Need to check if the NameOwnerChanged handling
+                * already cleaned up because we have processed
+                * DBus messages while checking if the name still
+                * has an owner.
+                */
+               if (!wpa_s->preq_notify_peer)
+                       return NULL;
+               os_free(wpa_s->preq_notify_peer);
+               wpa_s->preq_notify_peer = NULL;
+               wpas_dbus_unsubscribe_noc(priv);
+       }
+
+       return NULL;
+}
+
+
+DBusMessage * wpas_dbus_handler_unsubscribe_preq(
+       DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+       struct wpas_dbus_priv *priv = wpa_s->global->dbus;
+
+       if (!wpa_s->preq_notify_peer)
+               return dbus_message_new_error(message,
+                       WPAS_DBUS_ERROR_NO_SUBSCRIPTION,
+                       "Not subscribed");
+
+       if (os_strcmp(wpa_s->preq_notify_peer,
+                     dbus_message_get_sender(message)))
+               return dbus_message_new_error(message,
+                       WPAS_DBUS_ERROR_SUBSCRIPTION_EPERM,
+                       "Can't unsubscribe others");
+
+       os_free(wpa_s->preq_notify_peer);
+       wpa_s->preq_notify_peer = NULL;
+       wpas_dbus_unsubscribe_noc(priv);
+       return NULL;
+}
+
+
+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)
+{
+       DBusMessage *msg;
+       DBusMessageIter iter, dict_iter;
+       struct wpas_dbus_priv *priv = wpa_s->global->dbus;
+
+       /* Do nothing if the control interface is not turned on */
+       if (priv == NULL)
+               return;
+
+       if (wpa_s->preq_notify_peer == NULL)
+               return;
+
+       msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+                                     WPAS_DBUS_NEW_IFACE_INTERFACE,
+                                     "ProbeRequest");
+       if (msg == NULL)
+               return;
+
+       dbus_message_set_destination(msg, wpa_s->preq_notify_peer);
+
+       dbus_message_iter_init_append(msg, &iter);
+
+       if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+               goto fail;
+       if (addr && !wpa_dbus_dict_append_byte_array(&dict_iter, "addr",
+                                                    (const char *) addr,
+                                                    ETH_ALEN))
+               goto fail;
+       if (dst && !wpa_dbus_dict_append_byte_array(&dict_iter, "dst",
+                                                   (const char *) dst,
+                                                   ETH_ALEN))
+               goto fail;
+       if (bssid && !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid",
+                                                     (const char *) bssid,
+                                                     ETH_ALEN))
+               goto fail;
+       if (ie && ie_len && !wpa_dbus_dict_append_byte_array(&dict_iter, "ies",
+                                                            (const char *) ie,
+                                                            ie_len))
+               goto fail;
+       if (ssi_signal && !wpa_dbus_dict_append_int32(&dict_iter, "signal",
+                                                     ssi_signal))
+               goto fail;
+       if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
+               goto fail;
+
+       dbus_connection_send(priv->con, msg, NULL);
+       goto out;
+fail:
+       wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+out:
+       dbus_message_unref(msg);
+}
+
+#endif /* CONFIG_AP */
index c0272d5..cff218f 100644 (file)
@@ -3,14 +3,8 @@
  * 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_HANDLERS_H
@@ -41,6 +35,12 @@ dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter,
                                                   size_t array_len,
                                                   DBusError *error);
 
+dbus_bool_t wpas_dbus_simple_array_array_property_getter(DBusMessageIter *iter,
+                                                        const int type,
+                                                        struct wpabuf **array,
+                                                        size_t array_len,
+                                                        DBusError *error);
+
 DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
                                                 struct wpa_global *global);
 
@@ -118,6 +118,9 @@ DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message,
 DBusMessage * wpas_dbus_handler_flush_bss(DBusMessage *message,
                                          struct wpa_supplicant *wpa_s);
 
+DBusMessage * wpas_dbus_handler_autoscan(DBusMessage *message,
+                                        struct wpa_supplicant *wpa_s);
+
 dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
                                          DBusError *error, void *user_data);
 
@@ -141,6 +144,10 @@ dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter,
                                         DBusError *error,
                                         void *user_data);
 
+dbus_bool_t wpas_dbus_getter_disconnect_reason(DBusMessageIter *iter,
+                                              DBusError *error,
+                                              void *user_data);
+
 dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter,
                                            DBusError *error, void *user_data);
 
@@ -162,6 +169,14 @@ dbus_bool_t wpas_dbus_getter_country(DBusMessageIter *iter, DBusError *error,
 dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error,
                                     void *user_data);
 
+dbus_bool_t wpas_dbus_getter_scan_interval(DBusMessageIter *iter,
+                                          DBusError *error,
+                                          void *user_data);
+
+dbus_bool_t wpas_dbus_setter_scan_interval(DBusMessageIter *iter,
+                                          DBusError *error,
+                                          void *user_data);
+
 dbus_bool_t wpas_dbus_getter_ifname(DBusMessageIter *iter, DBusError *error,
                                    void *user_data);
 
@@ -252,4 +267,9 @@ DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
 DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
                                            const char *arg);
 
+DBusMessage * wpas_dbus_handler_subscribe_preq(
+       DBusMessage *message, struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_unsubscribe_preq(
+       DBusMessage *message, struct wpa_supplicant *wpa_s);
+
 #endif /* CTRL_IFACE_DBUS_HANDLERS_NEW_H */
index 79373b4..f4541f7 100644 (file)
@@ -1,14 +1,9 @@
 /*
  * WPA Supplicant / dbus-based control interface (P2P)
+ * Copyright (c) 2011-2012, Intel Corporation
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
@@ -45,7 +40,7 @@ static int parse_peer_object_path(char *peer_path, u8 addr[ETH_ALEN])
 
        if (!peer_path)
                return -1;
-       p = strrchr(peer_path, '/');
+       p = os_strrchr(peer_path, '/');
        if (!p)
                return -1;
        p++;
@@ -508,8 +503,8 @@ DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message,
                goto inv_args;
 
        new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
-                                  persistent_group, join, authorize_only,
-                                  go_intent, freq);
+                                  persistent_group, 0, join, authorize_only,
+                                  go_intent, freq, -1, 0);
 
        if (new_pin >= 0) {
                char npin[9];
@@ -692,7 +687,8 @@ DBusMessage * wpas_dbus_handler_p2p_prov_disc_req(DBusMessage *message,
            os_strcmp(config_method, "pushbutton"))
                return wpas_dbus_error_invalid_args(message, NULL);
 
-       if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method, 0) < 0)
+       if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method,
+                              WPAS_P2P_PD_FOR_GO_NEG) < 0)
                return wpas_dbus_error_unknown_error(message,
                                "Failed to send provision discovery request");
 
@@ -704,9 +700,9 @@ DBusMessage * wpas_dbus_handler_p2p_prov_disc_req(DBusMessage *message,
  * P2P Device property accessor methods.
  */
 
-dbus_bool_t wpas_dbus_getter_p2p_device_properties(DBusMessageIter *iter,
-                                                  DBusError *error,
-                                                  void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_device_config(DBusMessageIter *iter,
+                                              DBusError *error,
+                                              void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        DBusMessageIter variant_iter, dict_iter;
@@ -782,7 +778,7 @@ dbus_bool_t wpas_dbus_getter_p2p_device_properties(DBusMessageIter *iter,
                goto err_no_mem;
 
        /* Persistent Reconnect */
-       if (!wpa_dbus_dict_append_bool(&dict_iter, "PersistantReconnect",
+       if (!wpa_dbus_dict_append_bool(&dict_iter, "PersistentReconnect",
                                       wpa_s->conf->persistent_reconnect))
                goto err_no_mem;
 
@@ -839,9 +835,9 @@ err_no_mem:
 }
 
 
-dbus_bool_t wpas_dbus_setter_p2p_device_properties(DBusMessageIter *iter,
-                                                  DBusError *error,
-                                                  void *user_data)
+dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter,
+                                              DBusError *error,
+                                              void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
        DBusMessageIter variant_iter, iter_dict;
@@ -927,7 +923,7 @@ dbus_bool_t wpas_dbus_setter_p2p_device_properties(DBusMessageIter *iter,
                           (entry.type == DBUS_TYPE_UINT32) &&
                           (entry.uint32_value <= 15))
                        wpa_s->conf->p2p_go_intent = entry.uint32_value;
-               else if ((os_strcmp(entry.key, "PersistantReconnect") == 0) &&
+               else if ((os_strcmp(entry.key, "PersistentReconnect") == 0) &&
                         (entry.type == DBUS_TYPE_BOOLEAN))
                        wpa_s->conf->persistent_reconnect = entry.bool_value;
                else if ((os_strcmp(entry.key, "ListenRegClass") == 0) &&
@@ -1140,13 +1136,18 @@ dbus_bool_t wpas_dbus_getter_p2p_group(DBusMessageIter *iter, DBusError *error,
                                       void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
+       char path_buf[WPAS_DBUS_OBJECT_PATH_MAX];
+       char *dbus_groupobj_path = path_buf;
 
        if (wpa_s->dbus_groupobj_path == NULL)
-               return FALSE;
+               os_snprintf(dbus_groupobj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+                           "/");
+       else
+               os_snprintf(dbus_groupobj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+                           "%s", wpa_s->dbus_groupobj_path);
 
        return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
-                                               &wpa_s->dbus_groupobj_path,
-                                               error);
+                                               &dbus_groupobj_path, error);
 }
 
 
@@ -1157,11 +1158,13 @@ dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter,
        char go_peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
 
        if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_CLIENT)
-               return FALSE;
+               os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
+       else
+               os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+                           "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
+                           COMPACT_MACSTR,
+                           wpa_s->dbus_new_path, MAC2STR(wpa_s->go_dev_addr));
 
-       os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
-                   "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
-                   wpa_s->dbus_new_path, MAC2STR(wpa_s->go_dev_addr));
        path = go_peer_obj_path;
        return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
                                                &path, error);
@@ -1341,6 +1344,7 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types(
 {
        struct peer_handler_args *peer_args = user_data;
        const struct p2p_peer_info *info;
+       DBusMessageIter variant_iter, array_iter;
 
        info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
                                  peer_args->p2p_device_addr, 0);
@@ -1350,29 +1354,80 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types(
                return FALSE;
        }
 
+       if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+                                             DBUS_TYPE_ARRAY_AS_STRING
+                                             DBUS_TYPE_ARRAY_AS_STRING
+                                             DBUS_TYPE_BYTE_AS_STRING,
+                                             &variant_iter)) {
+               dbus_set_error(error, DBUS_ERROR_FAILED,
+                              "%s: failed to construct message 1", __func__);
+               return FALSE;
+       }
+
+       if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+                                             DBUS_TYPE_ARRAY_AS_STRING
+                                             DBUS_TYPE_BYTE_AS_STRING,
+                                             &array_iter)) {
+               dbus_set_error(error, DBUS_ERROR_FAILED,
+                              "%s: failed to construct message 2", __func__);
+               return FALSE;
+       }
+
        if (info->wps_sec_dev_type_list_len) {
                const u8 *sec_dev_type_list = info->wps_sec_dev_type_list;
-               int num_sec_dev_types = info->wps_sec_dev_type_list_len;
+               int num_sec_device_types =
+                       info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN;
+               int i;
+               DBusMessageIter inner_array_iter;
+
+               for (i = 0; i < num_sec_device_types; i++) {
+                       if (!dbus_message_iter_open_container(
+                                   &array_iter, DBUS_TYPE_ARRAY,
+                                   DBUS_TYPE_BYTE_AS_STRING,
+                                   &inner_array_iter)) {
+                               dbus_set_error(error, DBUS_ERROR_FAILED,
+                                              "%s: failed to construct "
+                                              "message 3 (%d)",
+                                              __func__, i);
+                               return FALSE;
+                       }
 
-               if (!wpas_dbus_simple_array_property_getter(iter,
-                                                           DBUS_TYPE_BYTE,
-                                                           sec_dev_type_list,
-                                                           num_sec_dev_types,
-                                                           error))
-                       goto err_no_mem;
-               else
-                       return TRUE;
+                       if (!dbus_message_iter_append_fixed_array(
+                                   &inner_array_iter, DBUS_TYPE_BYTE,
+                                   &sec_dev_type_list, WPS_DEV_TYPE_LEN)) {
+                               dbus_set_error(error, DBUS_ERROR_FAILED,
+                                              "%s: failed to construct "
+                                              "message 4 (%d)",
+                                              __func__, i);
+                               return FALSE;
+                       }
+
+                       if (!dbus_message_iter_close_container(
+                                   &array_iter, &inner_array_iter)) {
+                               dbus_set_error(error, DBUS_ERROR_FAILED,
+                                              "%s: failed to construct "
+                                              "message 5 (%d)",
+                                              __func__, i);
+                               return FALSE;
+                       }
+
+                       sec_dev_type_list += WPS_DEV_TYPE_LEN;
+               }
        }
 
-       if (!wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, NULL,
-                                                   0, error))
-               goto err_no_mem;
+       if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) {
+               dbus_set_error(error, DBUS_ERROR_FAILED,
+                              "%s: failed to construct message 6", __func__);
+               return FALSE;
+       }
 
-       return TRUE;
+       if (!dbus_message_iter_close_container(iter, &variant_iter)) {
+               dbus_set_error(error, DBUS_ERROR_FAILED,
+                              "%s: failed to construct message 7", __func__);
+               return FALSE;
+       }
 
-err_no_mem:
-       dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
-       return FALSE;
+       return TRUE;
 }
 
 
@@ -1380,7 +1435,7 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(DBusMessageIter *iter,
                                                       DBusError *error,
                                                       void *user_data)
 {
-       const struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT];
+       struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT];
        int i, num;
        struct peer_handler_args *peer_args = user_data;
        const struct p2p_peer_info *info;
@@ -1401,12 +1456,10 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(DBusMessageIter *iter,
                num++;
        }
 
-       if (!wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_STRING,
-                                                   vendor_extension, num,
-                                                   error)) {
-               dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+       if (!wpas_dbus_simple_array_array_property_getter(iter, DBUS_TYPE_BYTE,
+                                                         vendor_extension,
+                                                         num, error))
                return FALSE;
-       }
 
        return TRUE;
 }
@@ -1415,10 +1468,12 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(DBusMessageIter *iter,
 dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter,
                                          DBusError *error, void *user_data)
 {
+       dbus_bool_t success;
        /* struct peer_handler_args *peer_args = user_data; */
 
-       dbus_set_error_const(error, DBUS_ERROR_FAILED, "not implemented");
-       return FALSE;
+       success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+                                                        NULL, 0, error);
+       return success;
 }
 
 
@@ -1746,9 +1801,11 @@ dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter,
        const u8 *addr;
        dbus_bool_t success = FALSE;
 
-       /* Ensure we are a GO */
-       if (wpa_s->wpa_state != WPA_COMPLETED)
-               return FALSE;
+       /* Verify correct role for this property */
+       if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_GO) {
+               return wpas_dbus_simple_array_property_getter(
+                       iter, DBUS_TYPE_OBJECT_PATH, NULL, 0, error);
+       }
 
        ssid = wpa_s->conf->ssid;
        /* At present WPAS P2P_GO mode only applicable for p2p_go */
@@ -1796,111 +1853,145 @@ out_of_memory:
 }
 
 
-dbus_bool_t wpas_dbus_getter_p2p_group_properties(DBusMessageIter *iter,
-                                                 DBusError *error,
-                                                 void *user_data)
+dbus_bool_t wpas_dbus_getter_p2p_group_ssid(DBusMessageIter *iter,
+                                           DBusError *error, void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       if (wpa_s->current_ssid == NULL)
+               return FALSE;
+       return wpas_dbus_simple_array_property_getter(
+               iter, DBUS_TYPE_BYTE, wpa_s->current_ssid->ssid,
+               wpa_s->current_ssid->ssid_len, error);
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_group_bssid(DBusMessageIter *iter,
+                                            DBusError *error,
+                                            void *user_data)
 {
        struct wpa_supplicant *wpa_s = user_data;
-       DBusMessageIter variant_iter, dict_iter;
-       struct hostapd_data *hapd = NULL;
-       const struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
-       int num_vendor_ext = 0;
-       int i;
        u8 role = wpas_get_p2p_role(wpa_s);
-       u16 op_freq = 0;
-       u8 *p_bssid = NULL;
-       char *role_name = NULL;
+       u8 *p_bssid;
 
-       if (!wpa_s->current_ssid)
-               return FALSE;
+       if (role == WPAS_P2P_ROLE_CLIENT) {
+               if (wpa_s->current_ssid == NULL)
+                       return FALSE;
+               p_bssid = wpa_s->current_ssid->bssid;
+       } else {
+               if (wpa_s->ap_iface == NULL)
+                       return FALSE;
+               p_bssid = wpa_s->ap_iface->bss[0]->own_addr;
+       }
 
-       /* Check current role and adjust information accordingly */
-       switch (role) {
-       case WPAS_P2P_ROLE_CLIENT:
-               /* go_params is only valid for a client */
-               if (wpa_s->go_params) {
-                       op_freq = wpa_s->go_params->freq;
-                       p_bssid = wpa_s->current_ssid->bssid;
-                       role_name = "client";
-               } else
+       return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+                                                     p_bssid, ETH_ALEN,
+                                                     error);
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_group_frequency(DBusMessageIter *iter,
+                                                DBusError *error,
+                                                void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       u16 op_freq;
+       u8 role = wpas_get_p2p_role(wpa_s);
+
+       if (role == WPAS_P2P_ROLE_CLIENT) {
+               if (wpa_s->go_params == NULL)
                        return FALSE;
-               break;
-       case WPAS_P2P_ROLE_GO:
-               /* ap_iface is only valid for a GO */
-               if (wpa_s->ap_iface) {
-                       hapd = wpa_s->ap_iface->bss[0];
-                       p_bssid = hapd->own_addr;
-                       op_freq = wpa_s->ap_iface->freq;
-                       role_name = "GO";
-               } else
+               op_freq = wpa_s->go_params->freq;
+       } else {
+               if (wpa_s->ap_iface == NULL)
                        return FALSE;
-               break;
-       default:
-               /* Error condition; this should NEVER occur */
-               return FALSE;
+               op_freq = wpa_s->ap_iface->freq;
        }
 
-       if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
-                                             "a{sv}", &variant_iter) ||
-           !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
-               goto err_no_mem;
-       /* Provide the SSID */
-       if (!wpa_dbus_dict_append_byte_array(
-                   &dict_iter, "SSID",
-                   (const char *) wpa_s->current_ssid->ssid,
-                   wpa_s->current_ssid->ssid_len))
-               goto err_no_mem;
-       /* Provide the BSSID */
-       if (p_bssid &&
-           !wpa_dbus_dict_append_byte_array(&dict_iter, "BSSID",
-                                            (const char *) p_bssid, ETH_ALEN))
-               goto err_no_mem;
-       /* Provide the role within the group */
-       if (role_name &&
-           !wpa_dbus_dict_append_string(&dict_iter, "Role", role_name))
-               goto err_no_mem;
-       /* Provide the operational frequency */
-       if (!wpa_dbus_dict_append_uint16(&dict_iter, "Frequency", op_freq))
-               goto err_no_mem;
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
+                                               &op_freq, error);
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_group_passphrase(DBusMessageIter *iter,
+                                                 DBusError *error,
+                                                 void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       u8 role = wpas_get_p2p_role(wpa_s);
+       char *p_pass = NULL;
 
-       /* Additional information for group owners */
+       /* Verify correct role for this property */
        if (role == WPAS_P2P_ROLE_GO) {
-               /* Provide the passphrase */
-               if (!wpa_dbus_dict_append_string(&dict_iter, "Passphrase",
-                                       wpa_s->current_ssid->passphrase))
-                       goto err_no_mem;
+               if (wpa_s->current_ssid == NULL)
+                       return FALSE;
+               p_pass = wpa_s->current_ssid->passphrase;
+       } else
+               p_pass = "";
+
+       return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+                                               &p_pass, error);
+
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_group_psk(DBusMessageIter *iter,
+                                          DBusError *error, void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       u8 role = wpas_get_p2p_role(wpa_s);
+       u8 *p_psk = NULL;
+       u8 psk_len = 0;
+
+       /* Verify correct role for this property */
+       if (role == WPAS_P2P_ROLE_CLIENT) {
+               if (wpa_s->current_ssid == NULL)
+                       return FALSE;
+               p_psk = wpa_s->current_ssid->psk;
+               psk_len = 32;
+       }
+
+       return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+                                                     &p_psk, psk_len, error);
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(DBusMessageIter *iter,
+                                                 DBusError *error,
+                                                 void *user_data)
+{
+       struct wpa_supplicant *wpa_s = user_data;
+       struct hostapd_data *hapd;
+       struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
+       int num_vendor_ext = 0;
+       int i;
+
+       /* Verify correct role for this property */
+       if (wpas_get_p2p_role(wpa_s) == WPAS_P2P_ROLE_GO) {
+               if (wpa_s->ap_iface == NULL)
+                       return FALSE;
+               hapd = wpa_s->ap_iface->bss[0];
+
                /* Parse WPS Vendor Extensions sent in Beacon/Probe Response */
-               for (i = 0; hapd && i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
+               for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
                        if (hapd->conf->wps_vendor_ext[i] == NULL)
-                               continue;
-                       vendor_ext[num_vendor_ext++] =
-                               hapd->conf->wps_vendor_ext[i];
+                               vendor_ext[i] = NULL;
+                       else {
+                               vendor_ext[num_vendor_ext++] =
+                                       hapd->conf->wps_vendor_ext[i];
+                       }
                }
-               if (!wpa_dbus_dict_append_wpabuf_array(&dict_iter,
-                                       "WPSVendorExtensions",
-                                       vendor_ext, num_vendor_ext))
-                       goto err_no_mem;
-       } else {
-               /* If not a GO, provide the PSK */
-               if (!wpa_dbus_dict_append_byte_array(
-                           &dict_iter, "PSK",
-                           (const char *) wpa_s->current_ssid->psk, 32))
-                       goto err_no_mem;
        }
 
-       if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
-           !dbus_message_iter_close_container(iter, &variant_iter))
-               goto err_no_mem;
-
-       return TRUE;
-
-err_no_mem:
-       dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
-       return FALSE;
+       /* Return vendor extensions or no data */
+       return wpas_dbus_simple_array_array_property_getter(iter,
+                                                           DBUS_TYPE_BYTE,
+                                                           vendor_ext,
+                                                           num_vendor_ext,
+                                                error);
 }
 
 
-dbus_bool_t wpas_dbus_setter_p2p_group_properties(DBusMessageIter *iter,
+dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(DBusMessageIter *iter,
                                                  DBusError *error,
                                                  void *user_data)
 {
@@ -1978,7 +2069,7 @@ DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message,
        if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
                goto error;
 
-       if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+       while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
                if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
                        goto error;
 
@@ -1990,23 +2081,30 @@ DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message,
                                bonjour = 1;
                        else
                                goto error_clear;
-                       wpa_dbus_dict_entry_clear(&entry);
+               } else if (!os_strcmp(entry.key, "version") &&
+                          entry.type == DBUS_TYPE_INT32) {
+                       version = entry.uint32_value;
+               } else if (!os_strcmp(entry.key, "service") &&
+                            (entry.type == DBUS_TYPE_STRING)) {
+                       service = os_strdup(entry.str_value);
+               } else if (!os_strcmp(entry.key, "query")) {
+                       if ((entry.type != DBUS_TYPE_ARRAY) ||
+                           (entry.array_type != DBUS_TYPE_BYTE))
+                               goto error_clear;
+                       query = wpabuf_alloc_copy(
+                               entry.bytearray_value,
+                               entry.array_len);
+               } else if (!os_strcmp(entry.key, "response")) {
+                       if ((entry.type != DBUS_TYPE_ARRAY) ||
+                           (entry.array_type != DBUS_TYPE_BYTE))
+                               goto error_clear;
+                       resp = wpabuf_alloc_copy(entry.bytearray_value,
+                                                entry.array_len);
                }
+               wpa_dbus_dict_entry_clear(&entry);
        }
 
        if (upnp == 1) {
-               while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
-                       if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
-                               goto error;
-
-                       if (!os_strcmp(entry.key, "version") &&
-                           entry.type == DBUS_TYPE_INT32)
-                               version = entry.uint32_value;
-                       else if (!os_strcmp(entry.key, "service") &&
-                                entry.type == DBUS_TYPE_STRING)
-                               service = os_strdup(entry.str_value);
-                       wpa_dbus_dict_entry_clear(&entry);
-               }
                if (version <= 0 || service == NULL)
                        goto error;
 
@@ -2014,37 +2112,15 @@ DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message,
                        goto error;
 
                os_free(service);
+               service = NULL;
        } else if (bonjour == 1) {
-               while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
-                       if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
-                               goto error;
-
-                       if (!os_strcmp(entry.key, "query")) {
-                               if ((entry.type != DBUS_TYPE_ARRAY) ||
-                                   (entry.array_type != DBUS_TYPE_BYTE))
-                                       goto error_clear;
-                               query = wpabuf_alloc_copy(
-                                       entry.bytearray_value,
-                                       entry.array_len);
-                       } else if (!os_strcmp(entry.key, "response")) {
-                               if ((entry.type != DBUS_TYPE_ARRAY) ||
-                                   (entry.array_type != DBUS_TYPE_BYTE))
-                                       goto error_clear;
-                               resp = wpabuf_alloc_copy(entry.bytearray_value,
-                                                        entry.array_len);
-                       }
-
-                       wpa_dbus_dict_entry_clear(&entry);
-               }
-
                if (query == NULL || resp == NULL)
                        goto error;
 
-               if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
-                       wpabuf_free(query);
-                       wpabuf_free(resp);
+               if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0)
                        goto error;
-               }
+               query = NULL;
+               resp = NULL;
        } else
                goto error;
 
@@ -2052,6 +2128,9 @@ DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message,
 error_clear:
        wpa_dbus_dict_entry_clear(&entry);
 error:
+       os_free(service);
+       wpabuf_free(query);
+       wpabuf_free(resp);
        return wpas_dbus_error_invalid_args(message, NULL);
 }
 
@@ -2170,7 +2249,7 @@ DBusMessage * wpas_dbus_handler_p2p_service_sd_req(
        struct wpabuf *tlv = NULL;
        u8 version = 0;
        u64 ref = 0;
-       u8 addr[ETH_ALEN];
+       u8 addr_buf[ETH_ALEN], *addr;
 
        dbus_message_iter_init(message, &iter);
 
@@ -2207,10 +2286,15 @@ DBusMessage * wpas_dbus_handler_p2p_service_sd_req(
                wpa_dbus_dict_entry_clear(&entry);
        }
 
-       if (!peer_object_path ||
-           (parse_peer_object_path(peer_object_path, addr) < 0) ||
-           !p2p_peer_known(wpa_s->global->p2p, addr))
-               goto error;
+       if (!peer_object_path) {
+               addr = NULL;
+       } else {
+               if (parse_peer_object_path(peer_object_path, addr_buf) < 0 ||
+                   !p2p_peer_known(wpa_s->global->p2p, addr_buf))
+                       goto error;
+
+               addr = addr_buf;
+       }
 
        if (upnp == 1) {
                if (version <= 0 || service == NULL)
index 293eb6b..a11b3c8 100644 (file)
@@ -1,15 +1,9 @@
-
 /*
  * WPA Supplicant / dbus-based control interface for p2p
+ * Copyright (c) 2011-2012, Intel Corporation
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef DBUS_NEW_HANDLERS_P2P_H
@@ -94,13 +88,13 @@ DBusMessage *wpas_dbus_handler_p2p_serv_disc_external(
 /*
  * P2P Device property accessor methods.
  */
-dbus_bool_t wpas_dbus_setter_p2p_device_properties(DBusMessageIter *iter,
-                                                  DBusError *error,
-                                                  void *user_data);
+dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter,
+                                              DBusError *error,
+                                              void *user_data);
 
-dbus_bool_t wpas_dbus_getter_p2p_device_properties(DBusMessageIter *iter,
-                                                  DBusError *error,
-                                                  void *user_data);
+dbus_bool_t wpas_dbus_getter_p2p_device_config(DBusMessageIter *iter,
+                                              DBusError *error,
+                                              void *user_data);
 
 dbus_bool_t wpas_dbus_getter_p2p_peers(DBusMessageIter *iter, DBusError *error,
                                       void *user_data);
@@ -161,11 +155,31 @@ dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter,
                                               DBusError *error,
                                               void *user_data);
 
-dbus_bool_t wpas_dbus_getter_p2p_group_properties(DBusMessageIter *iter,
+dbus_bool_t wpas_dbus_getter_p2p_group_ssid(DBusMessageIter *iter,
+                                           DBusError *error,
+                                           void *user_data);
+
+dbus_bool_t wpas_dbus_getter_p2p_group_bssid(DBusMessageIter *iter,
+                                            DBusError *error,
+                                            void *user_data);
+
+dbus_bool_t wpas_dbus_getter_p2p_group_frequency(DBusMessageIter *iter,
+                                                DBusError *error,
+                                                void *user_data);
+
+dbus_bool_t wpas_dbus_getter_p2p_group_passphrase(DBusMessageIter *iter,
+                                                 DBusError *error,
+                                                 void *user_data);
+
+dbus_bool_t wpas_dbus_getter_p2p_group_psk(DBusMessageIter *iter,
+                                          DBusError *error,
+                                          void *user_data);
+
+dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(DBusMessageIter *iter,
                                                  DBusError *error,
                                                  void *user_data);
 
-dbus_bool_t wpas_dbus_setter_p2p_group_properties(DBusMessageIter *iter,
+dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(DBusMessageIter *iter,
                                                  DBusError *error,
                                                  void *user_data);
 
index a72cfb3..8489ce7 100644 (file)
@@ -3,14 +3,8 @@
  * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
  * Copyright (c) 2009, 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.
  */
 
 #include "includes.h"
index e254365..cfa6a15 100644 (file)
@@ -3,14 +3,8 @@
  * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
  * Copyright (c) 2009, 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.
  */
 
 #include "utils/includes.h"
index d6e7b48..6d31ad5 100644 (file)
@@ -3,14 +3,8 @@
  * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
  * Copyright (c) 2009, 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 WPA_DBUS_CTRL_H
index d443269..3b090c0 100644 (file)
@@ -4,14 +4,8 @@
  * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
  * Copyright (c) 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 "utils/includes.h"
index 71ab61e..5f298e7 100644 (file)
@@ -2,14 +2,8 @@
  * 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"
index 9523867..e668231 100644 (file)
@@ -2,14 +2,8 @@
  * 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 CTRL_IFACE_DBUS_H
index 8370a95..e217a72 100644 (file)
@@ -2,14 +2,8 @@
  * 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"
index 009e807..825bc6d 100644 (file)
@@ -2,14 +2,8 @@
  * 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 CTRL_IFACE_DBUS_HANDLERS_H
index c04b844..bb79382 100644 (file)
@@ -2,14 +2,8 @@
  * WPA Supplicant / dbus-based control interface (WPS)
  * 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"
index 480bc64..fe1401f 100644 (file)
@@ -204,6 +204,8 @@ CONFIG_EAP_LEAP=y
 # Disable credentials for an open network by default when acting as a WPS
 # registrar.
 #CONFIG_WPS_REG_DISABLE_OPEN=y
+# Enable WPS support with NFC config method
+#CONFIG_WPS_NFC=y
 
 # EAP-IKEv2
 #CONFIG_EAP_IKEV2=y
@@ -321,9 +323,7 @@ CONFIG_BACKEND=file
 # PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
 CONFIG_PEERKEY=y
 
-# IEEE 802.11w (management frame protection)
-# This version is an experimental implementation based on IEEE 802.11w/D1.0
-# draft and is subject to change since the standard has not yet been finalized.
+# IEEE 802.11w (management frame protection), also known as PMF
 # Driver support is also needed for IEEE 802.11w.
 #CONFIG_IEEE80211W=y
 
@@ -413,6 +413,12 @@ CONFIG_PEERKEY=y
 # Set syslog facility for debug messages
 #CONFIG_DEBUG_SYSLOG_FACILITY=LOG_DAEMON
 
+# Add support for sending all debug messages (regardless of debug verbosity)
+# to the Linux kernel tracing facility. This helps debug the entire stack by
+# making it easy to record everything happening from the driver up into the
+# same file, e.g., using trace-cmd.
+#CONFIG_DEBUG_LINUX_TRACING=y
+
 # Enable privilege separation (see README 'Privilege separation' for details)
 #CONFIG_PRIVSEP=y
 
@@ -424,7 +430,7 @@ CONFIG_PEERKEY=y
 # This tracks use of memory allocations and other registrations and reports
 # incorrect use with a backtrace of call (or allocation) location.
 #CONFIG_WPA_TRACE=y
-# For BSD, comment out these.
+# For BSD, uncomment these.
 #LIBS += -lexecinfo
 #LIBS_p += -lexecinfo
 #LIBS_c += -lexecinfo
@@ -433,7 +439,7 @@ CONFIG_PEERKEY=y
 # This enables use of libbfd to get more detailed symbols for the backtraces
 # generated by CONFIG_WPA_TRACE=y.
 #CONFIG_WPA_TRACE_BFD=y
-# For BSD, comment out these.
+# For BSD, uncomment these.
 #LIBS += -lbfd -liberty -lz
 #LIBS_p += -lbfd -liberty -lz
 #LIBS_c += -lbfd -liberty -lz
@@ -472,8 +478,37 @@ CONFIG_PEERKEY=y
 # IEEE 802.11n (High Throughput) support (mainly for AP mode)
 #CONFIG_IEEE80211N=y
 
+# Wireless Network Management (IEEE Std 802.11v-2011)
+# Note: This is experimental and not complete implementation.
+#CONFIG_WNM=y
+
 # Interworking (IEEE 802.11u)
 # This can be used to enable functionality to improve interworking with
 # external networks (GAS/ANQP to learn more about the networks and network
 # selection based on available credentials).
 #CONFIG_INTERWORKING=y
+
+# Hotspot 2.0
+#CONFIG_HS20=y
+
+# AP mode operations with wpa_supplicant
+# This can be used for controlling AP mode operations with wpa_supplicant. It
+# should be noted that this is mainly aimed at simple cases like
+# WPA2-Personal while more complex configurations like WPA2-Enterprise with an
+# external RADIUS server can be supported with hostapd.
+#CONFIG_AP=y
+
+# P2P (Wi-Fi Direct)
+# This can be used to enable P2P support in wpa_supplicant. See README-P2P for
+# more information on P2P operations.
+#CONFIG_P2P=y
+
+# Autoscan
+# This can be used to enable automatic scan support in wpa_supplicant.
+# See wpa_supplicant.conf for more information on autoscan usage.
+#
+# Enabling directly a module will enable autoscan support.
+# For exponential module:
+#CONFIG_AUTOSCAN_EXPONENTIAL=y
+# For periodic module:
+#CONFIG_AUTOSCAN_PERIODIC=y
index f47235b..eb3a089 100644 (file)
 
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2007,
+    <para>wpa_supplicant is copyright (c) 2003-2012,
     Jouni Malinen <email>j@w1.fi</email> and
     contributors.
     All Rights Reserved.</para>
 
-    <para>This program is dual-licensed under both the GPL version 2
-    and BSD license. Either license may be used at your option.</para>
+    <para>This program is licensed under the BSD license (the one with
+    advertisement clause removed).</para>
   </refsect1>
 </refentry>
index 1fe98f4..c080c07 100644 (file)
@@ -328,12 +328,12 @@ CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2007,
+    <para>wpa_supplicant is copyright (c) 2003-2012,
     Jouni Malinen <email>j@w1.fi</email> and
     contributors.
     All Rights Reserved.</para>
 
-    <para>This program is dual-licensed under both the GPL version 2
-    and BSD license. Either license may be used at your option.</para>
+    <para>This program is licensed under the BSD license (the one with
+    advertisement clause removed).</para>
   </refsect1>
 </refentry>
index 41b5849..0ab6419 100644 (file)
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2007,
+    <para>wpa_supplicant is copyright (c) 2003-2012,
     Jouni Malinen <email>j@w1.fi</email> and
     contributors.
     All Rights Reserved.</para>
 
-    <para>This program is dual-licensed under both the GPL version 2
-    and BSD license. Either license may be used at your option.</para>
+    <para>This program is licensed under the BSD license (the one with
+    advertisement clause removed).</para>
   </refsect1>
 </refentry>
index 402ea09..336c03b 100644 (file)
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2007,
+    <para>wpa_supplicant is copyright (c) 2003-2012,
     Jouni Malinen <email>j@w1.fi</email> and
     contributors.
     All Rights Reserved.</para>
 
-    <para>This program is dual-licensed under both the GPL version 2
-    and BSD license. Either license may be used at your option.</para>
+    <para>This program is licensed under the BSD license (the one with
+    advertisement clause removed).</para>
   </refsect1>
 </refentry>
index 89b8a92..eb907a8 100644 (file)
@@ -137,12 +137,12 @@ wpa_supplicant -i ath0 -c wpa_supplicant.conf
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2007,
+    <para>wpa_supplicant is copyright (c) 2003-2012,
     Jouni Malinen <email>j@w1.fi</email> and
     contributors.
     All Rights Reserved.</para>
 
-    <para>This program is dual-licensed under both the GPL version 2
-    and BSD license. Either license may be used at your option.</para>
+    <para>This program is licensed under the BSD license (the one with
+    advertisement clause removed).</para>
   </refsect1>
 </refentry>
index 0ab4e15..aa20e57 100644 (file)
 
     <variablelist>
       <varlistentry>
-       <term>hostap</term>
-       <listitem>
-         <para>(default) Host AP driver (Intersil Prism2/2.5/3).
-         (this can also be used with Linuxant DriverLoader).</para>
-       </listitem>
-      </varlistentry>
-
-      <varlistentry>
-       <term>hermes</term>
-       <listitem>
-         <para>Agere Systems Inc. driver (Hermes-I/Hermes-II).</para>
-       </listitem>
-      </varlistentry>
-
-      <varlistentry>
-       <term>madwifi</term>
-       <listitem>
-         <para>MADWIFI 802.11 support (Atheros, etc.).</para>
-       </listitem>
-      </varlistentry>
-
-      <varlistentry>
        <term>wext</term>
        <listitem>
          <para>Linux wireless extensions (generic).</para>
       </varlistentry>
 
       <varlistentry>
-       <term>broadcom</term>
-       <listitem>
-         <para>Broadcom wl.o driver.</para>
-       </listitem>
-      </varlistentry>
-
-      <varlistentry>
        <term>wired</term>
        <listitem>
          <para>wpa_supplicant wired Ethernet driver</para>
       <varlistentry>
        <term>-L</term>
        <listitem>
-         <para>Show license (GPL and BSD).</para>
+         <para>Show license (BSD).</para>
        </listitem>
       </varlistentry>
 
@@ -506,8 +477,8 @@ wpa_supplicant -Dnl80211,wext -c/etc/wpa_supplicant.conf -iwlan0
 
 <blockquote><programlisting>
 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 ath0 -D wext
 </programlisting></blockquote>
   </refsect1>
 
@@ -537,86 +508,6 @@ wpa_supplicant \
     <title>Supported Drivers</title>
     <variablelist>
       <varlistentry>
-       <term>Host AP driver for Prism2/2.5/3 (development
-       snapshot/v0.2.x)</term>
-       <listitem>
-         <para> (http://hostap.epitest.fi/) Driver needs to be set in
-         Managed mode (<emphasis>iwconfig wlan0 mode managed</emphasis>).
-         Please note that station firmware version needs to be 1.7.0 or
-         newer to work in WPA mode.</para>
-       </listitem>
-      </varlistentry>
-
-      <varlistentry>
-       <term>Linuxant DriverLoader</term>
-       <listitem>
-         <para>(http://www.linuxant.com/driverloader/)
-       with Windows NDIS driver for your wlan card supporting WPA.</para>
-       </listitem>
-      </varlistentry>
-
-      <varlistentry>
-       <term>Agere Systems Inc. Linux Driver</term>
-       <listitem>
-         <para> (http://www.agere.com/support/drivers/) Please note
-       that the driver interface file (driver_hermes.c) and hardware
-       specific include files are not included in the wpa_supplicant
-       distribution. You will need to copy these from the source
-       package of the Agere driver.</para>
-       </listitem>
-      </varlistentry>
-
-      <varlistentry>
-       <term>madwifi driver for cards based on Atheros chip set (ar521x)</term>
-       <listitem>
-         <para> (http://sourceforge.net/projects/madwifi/) Please
-       note that you will need to modify the wpa_supplicant .config
-       file to use the correct path for the madwifi driver root
-       directory (CFLAGS += -I../madwifi/wpa line in example
-       defconfig).</para>
-       </listitem>
-      </varlistentry>
-
-      <varlistentry>
-       <term>Linux ndiswrapper</term>
-       <listitem>
-         <para> (http://ndiswrapper.sourceforge.net/) with Windows
-       NDIS driver.</para>
-       </listitem>
-      </varlistentry>
-
-      <varlistentry>
-       <term>Broadcom wl.o driver</term>
-       <listitem>
-         <para> This is a generic Linux driver for Broadcom IEEE
-       802.11a/g cards.  However, it is proprietary driver that is
-       not publicly available except for couple of exceptions, mainly
-       Broadcom-based APs/wireless routers that use Linux. The driver
-       binary can be downloaded, e.g., from Linksys support site
-       (http://www.linksys.com/support/gpl.asp) for Linksys
-       WRT54G. The GPL tarball includes cross-compiler and the needed
-       header file, wlioctl.h, for compiling wpa_supplicant.  This
-       driver support in wpa_supplicant is expected to work also with
-       other devices based on Broadcom driver (assuming the driver
-       includes client mode support).</para>
-       </listitem>
-      </varlistentry>
-
-      <varlistentry>
-       <term> Intel ipw2100 driver</term>
-       <listitem>
-         <para> (http://sourceforge.net/projects/ipw2100/)</para>
-       </listitem>
-      </varlistentry>
-
-      <varlistentry>
-       <term>Intel ipw2200 driver</term>
-       <listitem>
-         <para> (http://sourceforge.net/projects/ipw2200/)</para>
-       </listitem>
-      </varlistentry>
-
-      <varlistentry>
        <term>Linux wireless extensions</term>
        <listitem>
          <para>In theory, any driver that supports Linux wireless
@@ -788,12 +679,12 @@ fi
   </refsect1>
   <refsect1>
     <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2007,
+    <para>wpa_supplicant is copyright (c) 2003-2012,
     Jouni Malinen <email>j@w1.fi</email> and
     contributors.
     All Rights Reserved.</para>
 
-    <para>This program is dual-licensed under both the GPL version 2
-    and BSD license. Either license may be used at your option.</para>
+    <para>This program is licensed under the BSD license (the one with
+    advertisement clause removed).</para>
   </refsect1>
 </refentry>
index b9ea291..f968251 100644 (file)
@@ -427,6 +427,13 @@ static inline int wpa_drv_deinit_ap(struct wpa_supplicant *wpa_s)
        return 0;
 }
 
+static inline int wpa_drv_deinit_p2p_cli(struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->driver->deinit_p2p_cli)
+               return wpa_s->driver->deinit_p2p_cli(wpa_s->drv_priv);
+       return 0;
+}
+
 static inline void wpa_drv_suspend(struct wpa_supplicant *wpa_s)
 {
        if (wpa_s->driver->suspend)
@@ -667,13 +674,20 @@ static inline void wpa_drv_set_rekey_info(struct wpa_supplicant *wpa_s,
        wpa_s->driver->set_rekey_info(wpa_s->drv_priv, kek, kck, replay_ctr);
 }
 
-#ifdef ANDROID_P2P
+static inline int wpa_drv_radio_disable(struct wpa_supplicant *wpa_s,
+                                       int disabled)
+{
+       if (!wpa_s->driver->radio_disable)
+               return -1;
+       return wpa_s->driver->radio_disable(wpa_s->drv_priv, disabled);
+}
+
 static inline int wpa_drv_switch_channel(struct wpa_supplicant *wpa_s,
-                                         int freq)
+                                        unsigned int freq)
 {
        if (!wpa_s->driver->switch_channel)
                return -1;
        return wpa_s->driver->switch_channel(wpa_s->drv_priv, freq);
 }
-#endif
+
 #endif /* DRIVER_I_H */
index 65e6742..e53e156 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - test code
- * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -278,7 +278,9 @@ static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e,
                }
        }
 
-       radius_client_send(e->radius, msg, RADIUS_AUTH, e->wpa_s->own_addr);
+       if (radius_client_send(e->radius, msg, RADIUS_AUTH, e->wpa_s->own_addr)
+           < 0)
+               goto fail;
        return;
 
  fail:
@@ -856,7 +858,7 @@ static int scard_test(void)
        unsigned char aka_ik[IK_LEN];
        unsigned char aka_ck[CK_LEN];
 
-       scard = scard_init(SCARD_TRY_BOTH);
+       scard = scard_init(SCARD_TRY_BOTH, NULL);
        if (scard == NULL)
                return -1;
        if (scard_set_pin(scard, "1234")) {
@@ -956,7 +958,7 @@ static int scard_get_triplets(int argc, char *argv[])
                wpa_debug_level = 99;
        }
 
-       scard = scard_init(SCARD_GSM_SIM_ONLY);
+       scard = scard_init(SCARD_GSM_SIM_ONLY, NULL);
        if (scard == NULL) {
                printf("Failed to open smartcard connection\n");
                return -1;
index 5ce5b72..c4b3862 100644 (file)
@@ -35,6 +35,7 @@
 #include "gas_query.h"
 #include "p2p_supplicant.h"
 #include "bgscan.h"
+#include "autoscan.h"
 #include "ap.h"
 #include "bss.h"
 #include "scan.h"
@@ -57,7 +58,7 @@ static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
                return -1;
        }
 
-       if (ssid->disabled) {
+       if (wpas_network_disabled(wpa_s, ssid)) {
                wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is disabled");
                return -1;
        }
@@ -103,6 +104,8 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
 {
        int bssid_changed;
 
+       wnm_bss_keep_alive_deinit(wpa_s);
+
 #ifdef CONFIG_IBSS_RSN
        ibss_rsn_deinit(wpa_s->ibss_rsn);
        wpa_s->ibss_rsn = NULL;
@@ -122,6 +125,9 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
        bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
        os_memset(wpa_s->bssid, 0, ETH_ALEN);
        os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
+#ifdef CONFIG_SME
+       wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
 #ifdef CONFIG_P2P
        os_memset(wpa_s->go_dev_addr, 0, ETH_ALEN);
 #endif /* CONFIG_P2P */
@@ -241,7 +247,8 @@ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
                        if (eap->vendor == EAP_VENDOR_IETF) {
                                if (eap->method == EAP_TYPE_SIM)
                                        sim = 1;
-                               else if (eap->method == EAP_TYPE_AKA)
+                               else if (eap->method == EAP_TYPE_AKA ||
+                                        eap->method == EAP_TYPE_AKA_PRIME)
                                        aka = 1;
                        }
                        eap++;
@@ -250,7 +257,9 @@ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
 
        if (eap_peer_get_eap_method(EAP_VENDOR_IETF, EAP_TYPE_SIM) == NULL)
                sim = 0;
-       if (eap_peer_get_eap_method(EAP_VENDOR_IETF, EAP_TYPE_AKA) == NULL)
+       if (eap_peer_get_eap_method(EAP_VENDOR_IETF, EAP_TYPE_AKA) == NULL &&
+           eap_peer_get_eap_method(EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME) ==
+           NULL)
                aka = 0;
 
        if (!sim && !aka) {
@@ -269,7 +278,7 @@ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
        else
                type = SCARD_GSM_SIM_ONLY;
 
-       wpa_s->scard = scard_init(type);
+       wpa_s->scard = scard_init(type, NULL);
        if (wpa_s->scard == NULL) {
                wpa_msg(wpa_s, MSG_WARNING, "Failed to initialize SIM "
                        "(pcsc-lite)");
@@ -612,7 +621,7 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
        e = wpa_blacklist_get(wpa_s, bss->bssid);
        if (e) {
                int limit = 1;
-               if (wpa_supplicant_enabled_networks(wpa_s->conf) == 1) {
+               if (wpa_supplicant_enabled_networks(wpa_s) == 1) {
                        /*
                         * When only a single network is enabled, we can
                         * trigger blacklisting on the first failure. This
@@ -640,7 +649,7 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
        for (ssid = group; ssid; ssid = ssid->pnext) {
                int check_ssid = wpa ? 1 : (ssid->ssid_len != 0);
 
-               if (ssid->disabled) {
+               if (wpas_network_disabled(wpa_s, ssid)) {
                        wpa_dbg(wpa_s, MSG_DEBUG, "   skip - disabled");
                        continue;
                }
@@ -805,7 +814,7 @@ wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
 static void wpa_supplicant_req_new_scan(struct wpa_supplicant *wpa_s,
                                        int timeout_sec, int timeout_usec)
 {
-       if (!wpa_supplicant_enabled_networks(wpa_s->conf)) {
+       if (!wpa_supplicant_enabled_networks(wpa_s)) {
                /*
                 * No networks are enabled; short-circuit request so
                 * we don't wait timeout seconds before transitioning
@@ -876,7 +885,7 @@ wpa_supplicant_pick_new_network(struct wpa_supplicant *wpa_s)
        for (prio = 0; prio < wpa_s->conf->num_prio; prio++) {
                for (ssid = wpa_s->conf->pssid[prio]; ssid; ssid = ssid->pnext)
                {
-                       if (ssid->disabled)
+                       if (wpas_network_disabled(wpa_s, ssid))
                                continue;
                        if (ssid->mode == IEEE80211_MODE_IBSS ||
                            ssid->mode == IEEE80211_MODE_AP)
@@ -989,13 +998,14 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
        }
 
        return 1;
-#else
+#else /* CONFIG_NO_ROAMING */
        return 0;
-#endif
+#endif /* CONFIG_NO_ROAMING */
 }
 
 
-/* Return < 0 if no scan results could be fetched. */
+/* Return < 0 if no scan results could be fetched or if scan results should not
+ * be shared with other virtual interfaces. */
 #ifdef ANDROID_P2P
 static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
                                              union wpa_event_data *data, int suppress_event)
@@ -1070,7 +1080,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
                scan_res_handler(wpa_s, scan_res);
 
                wpa_scan_results_free(scan_res);
-               return 0;
+               return -2;
        }
 
        if (ap) {
@@ -1084,20 +1094,34 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
        }
 #ifdef ANDROID_P2P
        if(!suppress_event)
-#endif
        {
                wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available");
                wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
                wpas_notify_scan_results(wpa_s);
        }
+#else
+       wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available");
+       wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
+       wpas_notify_scan_results(wpa_s);
+#endif
 
        wpas_notify_scan_done(wpa_s, 1);
 
+       if (sme_proc_obss_scan(wpa_s) > 0) {
+               wpa_scan_results_free(scan_res);
+               return 0;
+       }
+
        if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s))) {
                wpa_scan_results_free(scan_res);
                return 0;
        }
 
+       if (autoscan_notify_scan(wpa_s, scan_res)) {
+               wpa_scan_results_free(scan_res);
+               return 0;
+       }
+
        if (wpa_s->disconnected) {
                wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
                wpa_scan_results_free(scan_res);
@@ -1139,6 +1163,9 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
                        int timeout_sec = wpa_s->scan_interval;
                        int timeout_usec = 0;
 #ifdef CONFIG_P2P
+                       if (wpas_p2p_scan_no_go_seen(wpa_s) == 1)
+                               return 0;
+
                        if (wpa_s->p2p_in_provisioning) {
                                /*
                                 * Use shorter wait during P2P Provisioning
@@ -1228,6 +1255,82 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_NO_SCAN_PROCESSING */
 
 
+#ifdef CONFIG_WNM
+
+static void wnm_bss_keep_alive(void *eloop_ctx, void *sock_ctx)
+{
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+
+       if (wpa_s->wpa_state < WPA_ASSOCIATED)
+               return;
+
+       wpa_printf(MSG_DEBUG, "WNM: Send keep-alive to AP " MACSTR,
+                  MAC2STR(wpa_s->bssid));
+       /* TODO: could skip this if normal data traffic has been sent */
+       /* TODO: Consider using some more appropriate data frame for this */
+       if (wpa_s->l2)
+               l2_packet_send(wpa_s->l2, wpa_s->bssid, 0x0800, (u8 *) "", 0);
+
+#ifdef CONFIG_SME
+       if (wpa_s->sme.bss_max_idle_period) {
+               unsigned int msec;
+               msec = wpa_s->sme.bss_max_idle_period * 1024; /* times 1000 */
+               if (msec > 100)
+                       msec -= 100;
+               eloop_register_timeout(msec / 1000, msec % 1000 * 1000,
+                                      wnm_bss_keep_alive, wpa_s, NULL);
+       }
+#endif /* CONFIG_SME */
+}
+
+
+static void wnm_process_assoc_resp(struct wpa_supplicant *wpa_s,
+                                  const u8 *ies, size_t ies_len)
+{
+       struct ieee802_11_elems elems;
+
+       if (ies == NULL)
+               return;
+
+       if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed)
+               return;
+
+#ifdef CONFIG_SME
+       if (elems.bss_max_idle_period) {
+               unsigned int msec;
+               wpa_s->sme.bss_max_idle_period =
+                       WPA_GET_LE16(elems.bss_max_idle_period);
+               wpa_printf(MSG_DEBUG, "WNM: BSS Max Idle Period: %u (* 1000 "
+                          "TU)%s", wpa_s->sme.bss_max_idle_period,
+                          (elems.bss_max_idle_period[2] & 0x01) ?
+                          " (protected keep-live required)" : "");
+               if (wpa_s->sme.bss_max_idle_period == 0)
+                       wpa_s->sme.bss_max_idle_period = 1;
+               if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) {
+                       eloop_cancel_timeout(wnm_bss_keep_alive, wpa_s, NULL);
+                        /* msec times 1000 */
+                       msec = wpa_s->sme.bss_max_idle_period * 1024;
+                       if (msec > 100)
+                               msec -= 100;
+                       eloop_register_timeout(msec / 1000, msec % 1000 * 1000,
+                                              wnm_bss_keep_alive, wpa_s,
+                                              NULL);
+               }
+       }
+#endif /* CONFIG_SME */
+}
+
+#endif /* CONFIG_WNM */
+
+
+void wnm_bss_keep_alive_deinit(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_WNM
+       eloop_cancel_timeout(wnm_bss_keep_alive, wpa_s, NULL);
+#endif /* CONFIG_WNM */
+}
+
+
 static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
                                          union wpa_event_data *data)
 {
@@ -1245,6 +1348,10 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
                wpa_tdls_assoc_resp_ies(wpa_s->wpa, data->assoc_info.resp_ies,
                                        data->assoc_info.resp_ies_len);
 #endif /* CONFIG_TDLS */
+#ifdef CONFIG_WNM
+               wnm_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
+                                      data->assoc_info.resp_ies_len);
+#endif /* CONFIG_WNM */
        }
        if (data->assoc_info.beacon_ies)
                wpa_hexdump(MSG_DEBUG, "beacon_ies",
@@ -1702,9 +1809,18 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
        if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
                wpas_connection_failed(wpa_s, bssid);
        wpa_sm_notify_disassoc(wpa_s->wpa);
-       wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid=" MACSTR
-               " reason=%d",
-               MAC2STR(bssid), reason_code);
+       if (locally_generated)
+               wpa_s->disconnect_reason = -reason_code;
+       else
+               wpa_s->disconnect_reason = reason_code;
+       wpas_notify_disconnect_reason(wpa_s);
+       if (!is_zero_ether_addr(bssid) ||
+           wpa_s->wpa_state >= WPA_AUTHENTICATING) {
+               wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid=" MACSTR
+                       " reason=%d%s",
+                       MAC2STR(bssid), reason_code,
+                       locally_generated ? " locally_generated=1" : "");
+       }
        if (wpa_supplicant_dynamic_keys(wpa_s)) {
                wpa_dbg(wpa_s, MSG_DEBUG, "Disconnect event - remove keys");
                wpa_s->keys_cleared = 0;
@@ -1867,11 +1983,13 @@ wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s,
                        wpa_msg(wpa_s, MSG_INFO, "Failed to initialize the "
                                "driver after interface was added");
                }
+               wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
                break;
        case EVENT_INTERFACE_REMOVED:
                wpa_dbg(wpa_s, MSG_DEBUG, "Configured interface was removed");
                wpa_s->interface_removed = 1;
                wpa_supplicant_mark_disassoc(wpa_s);
+               wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
                l2_packet_deinit(wpa_s->l2);
                wpa_s->l2 = NULL;
 #ifdef CONFIG_IBSS_RSN
@@ -2104,8 +2222,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 {
        int level = MSG_DEBUG;
 
-       if (event == EVENT_RX_MGMT && data && data->rx_mgmt.frame &&
-           data->rx_mgmt.frame_len >= 24) {
+       if (event == EVENT_RX_MGMT && data->rx_mgmt.frame_len >= 24) {
                const struct ieee80211_hdr *hdr;
                u16 fc;
                hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame;
@@ -2161,7 +2278,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                        wpas_p2p_disassoc_notif(
                                wpa_s, data->disassoc_info.addr, reason_code,
                                data->disassoc_info.ie,
-                               data->disassoc_info.ie_len);
+                               data->disassoc_info.ie_len,
+                               locally_generated);
 #endif /* CONFIG_P2P */
                }
                if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
@@ -2189,13 +2307,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                            "Deauthentication frame IE(s)",
                                            data->deauth_info.ie,
                                            data->deauth_info.ie_len);
-#ifdef CONFIG_P2P
-                               wpas_p2p_deauth_notif(
-                                       wpa_s, data->deauth_info.addr,
-                                       reason_code,
-                                       data->deauth_info.ie,
-                                       data->deauth_info.ie_len);
-#endif /* CONFIG_P2P */
                        }
                }
 #ifdef CONFIG_AP
@@ -2212,6 +2323,15 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 #endif /* CONFIG_AP */
                wpa_supplicant_event_disassoc(wpa_s, reason_code,
                                              locally_generated);
+#ifdef CONFIG_P2P
+               if (event == EVENT_DEAUTH && data) {
+                       wpas_p2p_deauth_notif(wpa_s, data->deauth_info.addr,
+                                             reason_code,
+                                             data->deauth_info.ie,
+                                             data->deauth_info.ie_len,
+                                             locally_generated);
+               }
+#endif /* CONFIG_P2P */
                break;
        case EVENT_MICHAEL_MIC_FAILURE:
                wpa_supplicant_event_michael_mic_failure(wpa_s, data);
@@ -2263,8 +2383,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
                        sme_event_assoc_reject(wpa_s, data);
 #ifdef ANDROID_P2P
-#ifdef CONFIG_P2P
-               else if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
+               else {
 
                        if(!wpa_s->current_ssid) {
                                wpa_printf(MSG_ERROR, "current_ssid == NULL");
@@ -2291,12 +2410,13 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                 */
                                wpa_printf(MSG_ERROR, "Assoc retry threshold reached. "
                                "Disabling the network");
-                               wpa_s->current_ssid->assoc_retry = 0;
                                wpa_supplicant_disable_network(wpa_s, wpa_s->current_ssid);
-                               wpas_p2p_group_remove(wpa_s, wpa_s->ifname);
+#ifdef CONFIG_P2P
+                               if(wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE)
+                                       wpas_p2p_group_remove(wpa_s, wpa_s->ifname);
+#endif
                        }
                }
-#endif
 #endif /* ANDROID_P2P */
                break;
        case EVENT_AUTH_TIMED_OUT:
@@ -2382,15 +2502,32 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                ap_rx_from_unknown_sta(wpa_s, data->rx_from_unknown.addr,
                                       data->rx_from_unknown.wds);
                break;
-       case EVENT_RX_MGMT:
+       case EVENT_CH_SWITCH:
+               if (!data)
+                       break;
+               if (!wpa_s->ap_iface) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "AP: Ignore channel switch "
+                               "event in non-AP mode");
+                       break;
+               }
+
+#ifdef CONFIG_AP
+               wpas_ap_ch_switch(wpa_s, data->ch_switch.freq,
+                                 data->ch_switch.ht_enabled,
+                                 data->ch_switch.ch_offset);
+#endif /* CONFIG_AP */
+               break;
+       case EVENT_RX_MGMT: {
+               u16 fc, stype;
+               const struct ieee80211_mgmt *mgmt;
+
+               mgmt = (const struct ieee80211_mgmt *)
+                       data->rx_mgmt.frame;
+               fc = le_to_host16(mgmt->frame_control);
+               stype = WLAN_FC_GET_STYPE(fc);
+
                if (wpa_s->ap_iface == NULL) {
 #ifdef CONFIG_P2P
-                       u16 fc, stype;
-                       const struct ieee80211_mgmt *mgmt;
-                       mgmt = (const struct ieee80211_mgmt *)
-                               data->rx_mgmt.frame;
-                       fc = le_to_host16(mgmt->frame_control);
-                       stype = WLAN_FC_GET_STYPE(fc);
                        if (stype == WLAN_FC_STYPE_PROBE_REQ &&
                            data->rx_mgmt.frame_len > 24) {
                                const u8 *src = mgmt->sa;
@@ -2398,8 +2535,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                size_t ie_len = data->rx_mgmt.frame_len -
                                        (mgmt->u.probe_req.variable -
                                         data->rx_mgmt.frame);
-                               wpas_p2p_probe_req_rx(wpa_s, src, mgmt->da,
-                                                     mgmt->bssid, ie, ie_len);
+                               wpas_p2p_probe_req_rx(
+                                       wpa_s, src, mgmt->da,
+                                       mgmt->bssid, ie, ie_len,
+                                       data->rx_mgmt.ssi_signal);
                                break;
                        }
 #endif /* CONFIG_P2P */
@@ -2407,8 +2546,22 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                "management frame in non-AP mode");
                        break;
                }
+
+               if (stype == WLAN_FC_STYPE_PROBE_REQ &&
+                   data->rx_mgmt.frame_len > 24) {
+                       const u8 *ie = mgmt->u.probe_req.variable;
+                       size_t ie_len = data->rx_mgmt.frame_len -
+                               (mgmt->u.probe_req.variable -
+                                data->rx_mgmt.frame);
+
+                       wpas_notify_preq(wpa_s, mgmt->sa, mgmt->da,
+                                        mgmt->bssid, ie, ie_len,
+                                        data->rx_mgmt.ssi_signal);
+               }
+
                ap_mgmt_rx(wpa_s, &data->rx_mgmt);
                break;
+               }
 #endif /* CONFIG_AP */
        case EVENT_RX_ACTION:
                wpa_dbg(wpa_s, MSG_DEBUG, "Received Action frame: SA=" MACSTR
@@ -2475,7 +2628,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                             data->rx_probe_req.da,
                                             data->rx_probe_req.bssid,
                                             data->rx_probe_req.ie,
-                                            data->rx_probe_req.ie_len);
+                                            data->rx_probe_req.ie_len,
+                                            data->rx_probe_req.ssi_signal);
                        break;
                }
 #endif /* CONFIG_AP */
@@ -2484,7 +2638,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                      data->rx_probe_req.da,
                                      data->rx_probe_req.bssid,
                                      data->rx_probe_req.ie,
-                                     data->rx_probe_req.ie_len);
+                                     data->rx_probe_req.ie_len,
+                                     data->rx_probe_req.ssi_signal);
 #endif /* CONFIG_P2P */
                break;
        case EVENT_REMAIN_ON_CHANNEL:
@@ -2612,6 +2767,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
        case EVENT_CHANNEL_LIST_CHANGED:
                if (wpa_s->drv_priv == NULL)
                        break; /* Ignore event during drv initialization */
+
+               free_hw_features(wpa_s);
+               wpa_s->hw.modes = wpa_drv_get_hw_feature_data(
+                       wpa_s, &wpa_s->hw.num_modes, &wpa_s->hw.flags);
+
 #ifdef CONFIG_P2P
                wpas_p2p_update_channel_list(wpa_s);
 #endif /* CONFIG_P2P */
diff --git a/wpa_supplicant/examples/dbus-listen-preq.py b/wpa_supplicant/examples/dbus-listen-preq.py
new file mode 100755 (executable)
index 0000000..5ac9859
--- /dev/null
@@ -0,0 +1,62 @@
+#!/usr/bin/python
+
+import dbus
+import sys
+import time
+import gobject
+from dbus.mainloop.glib import DBusGMainLoop
+
+WPAS_DBUS_SERVICE = "fi.w1.wpa_supplicant1"
+WPAS_DBUS_INTERFACE = "fi.w1.wpa_supplicant1"
+WPAS_DBUS_OPATH = "/fi/w1/wpa_supplicant1"
+WPAS_DBUS_INTERFACES_INTERFACE = "fi.w1.wpa_supplicant1.Interface"
+
+def usage():
+       print "Usage: %s <ifname>" % sys.argv[0]
+       print "Press Ctrl-C to stop"
+
+def ProbeRequest(args):
+       if 'addr' in args:
+               print '%.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % tuple(args['addr']),
+       if 'dst' in args:
+               print '-> %.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % tuple(args['dst']),
+       if 'bssid' in args:
+               print '(bssid %.2x:%.2x:%.2x:%.2x:%.2x:%.2x)' % tuple(args['dst']),
+       if 'signal' in args:
+               print 'signal:%d' % args['signal'],
+       if 'ies' in args:
+               print 'have IEs (%d bytes)' % len(args['ies']),
+        print ''
+
+if __name__ == "__main__":
+       global bus
+       global wpas_obj
+       global if_obj
+       global p2p_iface
+
+       dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+       bus = dbus.SystemBus()
+       wpas_obj = bus.get_object(WPAS_DBUS_SERVICE, WPAS_DBUS_OPATH)
+
+       # Print list of i/f if no one is specified
+       if (len(sys.argv) < 2)  :
+               usage()
+               sys.exit(0)
+
+       wpas = dbus.Interface(wpas_obj, WPAS_DBUS_INTERFACE)
+
+       ifname = sys.argv[1]
+
+       path = wpas.GetInterface(ifname)
+
+       if_obj = bus.get_object(WPAS_DBUS_SERVICE, path)
+       iface = dbus.Interface(if_obj, WPAS_DBUS_INTERFACES_INTERFACE)
+
+       bus.add_signal_receiver(ProbeRequest,
+                               dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE,
+                               signal_name="ProbeRequest")
+
+       iface.SubscribeProbeReq()
+
+       gobject.MainLoop().run()
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
new file mode 100644 (file)
index 0000000..2afa16c
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2009, Atheros Communications, Inc.
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * 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 "common/ieee802_11_common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/gas.h"
+#include "common/wpa_ctrl.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "config.h"
+#include "bss.h"
+#include "gas_query.h"
+#include "interworking.h"
+#include "hs20_supplicant.h"
+
+
+void wpas_hs20_add_indication(struct wpabuf *buf)
+{
+       wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
+       wpabuf_put_u8(buf, 5);
+       wpabuf_put_be24(buf, OUI_WFA);
+       wpabuf_put_u8(buf, HS20_INDICATION_OUI_TYPE);
+       wpabuf_put_u8(buf, 0x00); /* Hotspot Configuration */
+}
+
+
+struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
+                                   size_t payload_len)
+{
+       struct wpabuf *buf;
+       u8 *len_pos;
+
+       buf = gas_anqp_build_initial_req(0, 100 + payload_len);
+       if (buf == NULL)
+               return NULL;
+
+       len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+       wpabuf_put_be24(buf, OUI_WFA);
+       wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
+       if (stypes == BIT(HS20_STYPE_NAI_HOME_REALM_QUERY)) {
+               wpabuf_put_u8(buf, HS20_STYPE_NAI_HOME_REALM_QUERY);
+               wpabuf_put_u8(buf, 0); /* Reserved */
+               if (payload)
+                       wpabuf_put_data(buf, payload, payload_len);
+       } else {
+               u8 i;
+               wpabuf_put_u8(buf, HS20_STYPE_QUERY_LIST);
+               wpabuf_put_u8(buf, 0); /* Reserved */
+               for (i = 0; i < 32; i++) {
+                       if (stypes & BIT(i))
+                               wpabuf_put_u8(buf, i);
+               }
+       }
+       gas_anqp_set_element_len(buf, len_pos);
+
+       gas_anqp_set_len(buf);
+
+       return buf;
+}
+
+
+int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
+                      const u8 *payload, size_t payload_len)
+{
+       struct wpabuf *buf;
+       int ret = 0;
+       int freq;
+       struct wpa_bss *bss;
+       int res;
+
+       freq = wpa_s->assoc_freq;
+       bss = wpa_bss_get_bssid(wpa_s, dst);
+       if (bss)
+               freq = bss->freq;
+       if (freq <= 0)
+               return -1;
+
+       wpa_printf(MSG_DEBUG, "HS20: ANQP Query Request to " MACSTR " for "
+                  "subtypes 0x%x", MAC2STR(dst), stypes);
+
+       buf = hs20_build_anqp_req(stypes, payload, payload_len);
+       if (buf == NULL)
+               return -1;
+
+       res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
+       if (res < 0) {
+               wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+               ret = -1;
+       } else
+               wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
+                          "%u", res);
+
+       wpabuf_free(buf);
+       return ret;
+}
+
+
+void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
+                                 const u8 *sa, const u8 *data, size_t slen)
+{
+       const u8 *pos = data;
+       u8 subtype;
+       struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
+
+       if (slen < 2)
+               return;
+
+       subtype = *pos++;
+       slen--;
+
+       pos++; /* Reserved */
+       slen--;
+
+       switch (subtype) {
+       case HS20_STYPE_CAPABILITY_LIST:
+               wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+                       " HS Capability List", MAC2STR(sa));
+               wpa_hexdump_ascii(MSG_DEBUG, "HS Capability List", pos, slen);
+               break;
+       case HS20_STYPE_OPERATOR_FRIENDLY_NAME:
+               wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+                       " Operator Friendly Name", MAC2STR(sa));
+               wpa_hexdump_ascii(MSG_DEBUG, "oper friendly name", pos, slen);
+               if (bss) {
+                       wpabuf_free(bss->hs20_operator_friendly_name);
+                       bss->hs20_operator_friendly_name =
+                               wpabuf_alloc_copy(pos, slen);
+               }
+               break;
+       case HS20_STYPE_WAN_METRICS:
+               wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+                       " WAN Metrics", MAC2STR(sa));
+               wpa_hexdump_ascii(MSG_DEBUG, "WAN Metrics", pos, slen);
+               if (bss) {
+                       wpabuf_free(bss->hs20_wan_metrics);
+                       bss->hs20_wan_metrics = wpabuf_alloc_copy(pos, slen);
+               }
+               break;
+       case HS20_STYPE_CONNECTION_CAPABILITY:
+               wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+                       " Connection Capability", MAC2STR(sa));
+               wpa_hexdump_ascii(MSG_DEBUG, "conn capability", pos, slen);
+               if (bss) {
+                       wpabuf_free(bss->hs20_connection_capability);
+                       bss->hs20_connection_capability =
+                               wpabuf_alloc_copy(pos, slen);
+               }
+               break;
+       case HS20_STYPE_OPERATING_CLASS:
+               wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+                       " Operating Class", MAC2STR(sa));
+               wpa_hexdump_ascii(MSG_DEBUG, "Operating Class", pos, slen);
+               if (bss) {
+                       wpabuf_free(bss->hs20_operating_class);
+                       bss->hs20_operating_class =
+                               wpabuf_alloc_copy(pos, slen);
+               }
+               break;
+       default:
+               wpa_printf(MSG_DEBUG, "HS20: Unsupported subtype %u", subtype);
+               break;
+       }
+}
diff --git a/wpa_supplicant/hs20_supplicant.h b/wpa_supplicant/hs20_supplicant.h
new file mode 100644 (file)
index 0000000..6eb3926
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef HS20_SUPPLICANT_H
+#define HS20_SUPPLICANT_H
+
+void wpas_hs20_add_indication(struct wpabuf *buf);
+
+int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
+                      const u8 *payload, size_t payload_len);
+struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
+                                   size_t payload_len);
+void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
+                                 const u8 *sa, const u8 *data, size_t slen);
+
+#endif /* HS20_SUPPLICANT_H */
index ac89ff8..515d94b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Interworking (IEEE 802.11u)
- * Copyright (c) 2011, Qualcomm Atheros
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
 #include "common/ieee802_11_defs.h"
 #include "common/gas.h"
 #include "common/wpa_ctrl.h"
+#include "utils/pcsc_funcs.h"
 #include "drivers/driver.h"
 #include "eap_common/eap_defs.h"
 #include "eap_peer/eap_methods.h"
 #include "wpa_supplicant_i.h"
 #include "config.h"
+#include "config_ssid.h"
 #include "bss.h"
 #include "scan.h"
 #include "notify.h"
 #include "gas_query.h"
+#include "hs20_supplicant.h"
 #include "interworking.h"
 
 
 static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s);
 
 
+static void interworking_reconnect(struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
+               wpa_supplicant_cancel_sched_scan(wpa_s);
+               wpa_supplicant_deauthenticate(wpa_s,
+                                             WLAN_REASON_DEAUTH_LEAVING);
+       }
+       wpa_s->disconnected = 0;
+       wpa_s->reassociate = 1;
+       wpa_supplicant_req_scan(wpa_s, 0, 0);
+}
+
+
 static struct wpabuf * anqp_build_req(u16 info_ids[], size_t num_ids,
                                      struct wpabuf *extra)
 {
@@ -100,6 +116,28 @@ static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s,
        wpa_printf(MSG_DEBUG, "Interworking: ANQP Query Request to " MACSTR,
                   MAC2STR(bss->bssid));
 
+#ifdef CONFIG_HS20
+       if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
+               u8 *len_pos;
+
+               extra = wpabuf_alloc(100);
+               if (!extra)
+                       return -1;
+
+               len_pos = gas_anqp_add_element(extra, ANQP_VENDOR_SPECIFIC);
+               wpabuf_put_be24(extra, OUI_WFA);
+               wpabuf_put_u8(extra, HS20_ANQP_OUI_TYPE);
+               wpabuf_put_u8(extra, HS20_STYPE_QUERY_LIST);
+               wpabuf_put_u8(extra, 0); /* Reserved */
+               wpabuf_put_u8(extra, HS20_STYPE_CAPABILITY_LIST);
+               wpabuf_put_u8(extra, HS20_STYPE_OPERATOR_FRIENDLY_NAME);
+               wpabuf_put_u8(extra, HS20_STYPE_WAN_METRICS);
+               wpabuf_put_u8(extra, HS20_STYPE_CONNECTION_CAPABILITY);
+               wpabuf_put_u8(extra, HS20_STYPE_OPERATING_CLASS);
+               gas_anqp_set_element_len(extra, len_pos);
+       }
+#endif /* CONFIG_HS20 */
+
        buf = anqp_build_req(info_ids, sizeof(info_ids) / sizeof(info_ids[0]),
                             extra);
        wpabuf_free(extra);
@@ -416,20 +454,41 @@ static int nai_realm_cred_username(struct nai_realm_eap *eap)
 }
 
 
-static struct nai_realm_eap * nai_realm_find_eap(struct wpa_supplicant *wpa_s,
+static int nai_realm_cred_cert(struct nai_realm_eap *eap)
+{
+       if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL)
+               return 0; /* method not supported */
+
+       if (eap->method != EAP_TYPE_TLS) {
+               /* Only EAP-TLS supported for credential authentication */
+               return 0;
+       }
+
+       return 1;
+}
+
+
+static struct nai_realm_eap * nai_realm_find_eap(struct wpa_cred *cred,
                                                 struct nai_realm *realm)
 {
        u8 e;
 
-       if (wpa_s->conf->home_username == NULL ||
-           wpa_s->conf->home_username[0] == '\0' ||
-           wpa_s->conf->home_password == NULL ||
-           wpa_s->conf->home_password[0] == '\0')
+       if (cred == NULL ||
+           cred->username == NULL ||
+           cred->username[0] == '\0' ||
+           ((cred->password == NULL ||
+             cred->password[0] == '\0') &&
+            (cred->private_key == NULL ||
+             cred->private_key[0] == '\0')))
                return NULL;
 
        for (e = 0; e < realm->eap_count; e++) {
                struct nai_realm_eap *eap = &realm->eap[e];
-               if (nai_realm_cred_username(eap))
+               if (cred->password && cred->password[0] &&
+                   nai_realm_cred_username(eap))
+                       return eap;
+               if (cred->private_key && cred->private_key[0] &&
+                   nai_realm_cred_cert(eap))
                        return eap;
        }
 
@@ -439,21 +498,17 @@ static struct nai_realm_eap * nai_realm_find_eap(struct wpa_supplicant *wpa_s,
 
 #ifdef INTERWORKING_3GPP
 
-static int plmn_id_match(struct wpabuf *anqp, const char *imsi)
+static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
 {
-       const char *sep;
        u8 plmn[3];
        const u8 *pos, *end;
        u8 udhl;
 
-       sep = os_strchr(imsi, '-');
-       if (sep == NULL || (sep - imsi != 5 && sep - imsi != 6))
-               return 0;
-
        /* See Annex A of 3GPP TS 24.234 v8.1.0 for description */
        plmn[0] = (imsi[0] - '0') | ((imsi[1] - '0') << 4);
        plmn[1] = imsi[2] - '0';
-       if (sep - imsi == 6)
+       /* default to MNC length 3 if unknown */
+       if (mnc_len != 2)
                plmn[1] |= (imsi[5] - '0') << 4;
        else
                plmn[1] |= 0xf0;
@@ -505,10 +560,11 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi)
 }
 
 
-static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix)
+static int build_root_nai(char *nai, size_t nai_len, const char *imsi,
+                         char prefix)
 {
        const char *sep, *msin;
-       char nai[100], *end, *pos;
+       char *end, *pos;
        size_t msin_len, plmn_len;
 
        /*
@@ -532,8 +588,9 @@ static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix)
        msin_len = os_strlen(msin);
 
        pos = nai;
-       end = pos + sizeof(nai);
-       *pos++ = prefix;
+       end = nai + nai_len;
+       if (prefix)
+               *pos++ = prefix;
        os_memcpy(pos, imsi, plmn_len);
        pos += plmn_len;
        os_memcpy(pos, msin, msin_len);
@@ -551,6 +608,15 @@ static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix)
        pos += os_snprintf(pos, end - pos, ".mcc%c%c%c.3gppnetwork.org",
                           imsi[0], imsi[1], imsi[2]);
 
+       return 0;
+}
+
+
+static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix)
+{
+       char nai[100];
+       if (build_root_nai(nai, sizeof(nai), imsi, prefix) < 0)
+               return -1;
        return wpa_config_set_quoted(ssid, "identity", nai);
 }
 
@@ -561,9 +627,47 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
                                     struct wpa_bss *bss)
 {
 #ifdef INTERWORKING_3GPP
+       struct wpa_cred *cred;
        struct wpa_ssid *ssid;
        const u8 *ie;
 
+       if (bss->anqp_3gpp == NULL)
+               return -1;
+
+       for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+               char *sep;
+               const char *imsi;
+               int mnc_len;
+
+#ifdef PCSC_FUNCS
+               if (cred->pcsc && wpa_s->conf->pcsc_reader && wpa_s->scard &&
+                   wpa_s->imsi[0]) {
+                       imsi = wpa_s->imsi;
+                       mnc_len = wpa_s->mnc_len;
+                       goto compare;
+               }
+#endif /* PCSC_FUNCS */
+
+               if (cred->imsi == NULL || !cred->imsi[0] ||
+                   cred->milenage == NULL || !cred->milenage[0])
+                       continue;
+
+               sep = os_strchr(cred->imsi, '-');
+               if (sep == NULL ||
+                   (sep - cred->imsi != 5 && sep - cred->imsi != 6))
+                       continue;
+               mnc_len = sep - cred->imsi - 3;
+               imsi = cred->imsi;
+
+#ifdef PCSC_FUNCS
+       compare:
+#endif /* PCSC_FUNCS */
+               if (plmn_id_match(bss->anqp_3gpp, imsi, mnc_len))
+                       break;
+       }
+       if (cred == NULL)
+               return -1;
+
        ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
        if (ie == NULL)
                return -1;
@@ -576,6 +680,7 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
 
        wpas_notify_network_added(wpa_s, ssid);
        wpa_config_set_network_defaults(ssid);
+       ssid->priority = cred->priority;
        ssid->temporary = 1;
        ssid->ssid = os_zalloc(ie[1] + 1);
        if (ssid->ssid == NULL)
@@ -588,27 +693,32 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
                wpa_printf(MSG_DEBUG, "EAP-SIM not supported");
                goto fail;
        }
-       if (set_root_nai(ssid, wpa_s->conf->home_imsi, '1') < 0) {
+       if (cred->pcsc && wpa_s->scard && scard_supports_umts(wpa_s->scard))
+               wpa_config_set(ssid, "eap", "AKA", 0);
+       if (!cred->pcsc && set_root_nai(ssid, cred->imsi, '1') < 0) {
                wpa_printf(MSG_DEBUG, "Failed to set Root NAI");
                goto fail;
        }
 
-       if (wpa_s->conf->home_milenage && wpa_s->conf->home_milenage[0]) {
+       if (cred->milenage && cred->milenage[0]) {
                if (wpa_config_set_quoted(ssid, "password",
-                                         wpa_s->conf->home_milenage) < 0)
+                                         cred->milenage) < 0)
                        goto fail;
-       } else {
-               /* TODO: PIN */
+       } else if (cred->pcsc) {
                if (wpa_config_set_quoted(ssid, "pcsc", "") < 0)
                        goto fail;
+               if (wpa_s->conf->pcsc_pin &&
+                   wpa_config_set_quoted(ssid, "pin", wpa_s->conf->pcsc_pin)
+                   < 0)
+                       goto fail;
        }
 
-       if (wpa_s->conf->home_password && wpa_s->conf->home_password[0] &&
-           wpa_config_set_quoted(ssid, "password", wpa_s->conf->home_password)
-           < 0)
+       if (cred->password && cred->password[0] &&
+           wpa_config_set_quoted(ssid, "password", cred->password) < 0)
                goto fail;
 
-       wpa_supplicant_select_network(wpa_s, ssid);
+       wpa_config_update_prio_list(wpa_s->conf);
+       interworking_reconnect(wpa_s);
 
        return 0;
 
@@ -622,6 +732,7 @@ fail:
 
 int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
 {
+       struct wpa_cred *cred;
        struct wpa_ssid *ssid;
        struct nai_realm *realm;
        struct nai_realm_eap *eap = NULL;
@@ -629,7 +740,7 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
        char buf[100];
        const u8 *ie;
 
-       if (bss == NULL)
+       if (wpa_s->conf->cred == NULL || bss == NULL)
                return -1;
        ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
        if (ie == NULL || ie[1] == 0) {
@@ -645,10 +756,14 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
                count = 0;
        }
 
-       for (i = 0; i < count; i++) {
-               if (!nai_realm_match(&realm[i], wpa_s->conf->home_realm))
-                       continue;
-               eap = nai_realm_find_eap(wpa_s, &realm[i]);
+       for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+               for (i = 0; i < count; i++) {
+                       if (!nai_realm_match(&realm[i], cred->realm))
+                               continue;
+                       eap = nai_realm_find_eap(cred, &realm[i]);
+                       if (eap)
+                               break;
+               }
                if (eap)
                        break;
        }
@@ -677,6 +792,7 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
        }
        wpas_notify_network_added(wpa_s, ssid);
        wpa_config_set_network_defaults(ssid);
+       ssid->priority = cred->priority;
        ssid->temporary = 1;
        ssid->ssid = os_zalloc(ie[1] + 1);
        if (ssid->ssid == NULL)
@@ -688,14 +804,56 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
                                                     eap->method), 0) < 0)
                goto fail;
 
-       if (wpa_s->conf->home_username && wpa_s->conf->home_username[0] &&
-           wpa_config_set_quoted(ssid, "identity",
-                                 wpa_s->conf->home_username) < 0)
+       if (eap->method == EAP_TYPE_TTLS &&
+           cred->username && cred->username[0]) {
+               const char *pos;
+               char *anon;
+               /* Use anonymous NAI in Phase 1 */
+               pos = os_strchr(cred->username, '@');
+               if (pos) {
+                       size_t buflen = 9 + os_strlen(pos) + 1;
+                       anon = os_malloc(buflen);
+                       if (anon == NULL)
+                               goto fail;
+                       os_snprintf(anon, buflen, "anonymous%s", pos);
+               } else if (cred->realm) {
+                       size_t buflen = 10 + os_strlen(cred->realm) + 1;
+                       anon = os_malloc(buflen);
+                       if (anon == NULL)
+                               goto fail;
+                       os_snprintf(anon, buflen, "anonymous@%s", cred->realm);
+               } else {
+                       anon = os_strdup("anonymous");
+                       if (anon == NULL)
+                               goto fail;
+               }
+               if (wpa_config_set_quoted(ssid, "anonymous_identity", anon) <
+                   0) {
+                       os_free(anon);
+                       goto fail;
+               }
+               os_free(anon);
+       }
+
+       if (cred->username && cred->username[0] &&
+           wpa_config_set_quoted(ssid, "identity", cred->username) < 0)
+               goto fail;
+
+       if (cred->password && cred->password[0] &&
+           wpa_config_set_quoted(ssid, "password", cred->password) < 0)
+               goto fail;
+
+       if (cred->client_cert && cred->client_cert[0] &&
+           wpa_config_set_quoted(ssid, "client_cert", cred->client_cert) < 0)
                goto fail;
 
-       if (wpa_s->conf->home_password && wpa_s->conf->home_password[0] &&
-           wpa_config_set_quoted(ssid, "password", wpa_s->conf->home_password)
-           < 0)
+       if (cred->private_key && cred->private_key[0] &&
+           wpa_config_set_quoted(ssid, "private_key", cred->private_key) < 0)
+               goto fail;
+
+       if (cred->private_key_passwd && cred->private_key_passwd[0] &&
+           wpa_config_set_quoted(ssid, "private_key_passwd",
+                                 cred->private_key_passwd) < 0)
                goto fail;
 
        switch (eap->method) {
@@ -737,16 +895,18 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
                if (wpa_config_set(ssid, "phase2", buf, 0) < 0)
                        goto fail;
                break;
+       case EAP_TYPE_TLS:
+               break;
        }
 
-       if (wpa_s->conf->home_ca_cert && wpa_s->conf->home_ca_cert[0] &&
-           wpa_config_set_quoted(ssid, "ca_cert", wpa_s->conf->home_ca_cert) <
-           0)
+       if (cred->ca_cert && cred->ca_cert[0] &&
+           wpa_config_set_quoted(ssid, "ca_cert", cred->ca_cert) < 0)
                goto fail;
 
        nai_realm_free(realm, count);
 
-       wpa_supplicant_select_network(wpa_s, ssid);
+       wpa_config_update_prio_list(wpa_s->conf);
+       interworking_reconnect(wpa_s);
 
        return 0;
 
@@ -758,41 +918,71 @@ fail:
 }
 
 
-static int interworking_credentials_available_3gpp(
+static struct wpa_cred * interworking_credentials_available_3gpp(
        struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
 {
-       int ret = 0;
+       struct wpa_cred *cred, *selected = NULL;
+       int ret;
 
 #ifdef INTERWORKING_3GPP
        if (bss->anqp_3gpp == NULL)
-               return ret;
+               return NULL;
 
-       if (wpa_s->conf->home_imsi == NULL || !wpa_s->conf->home_imsi[0] ||
-           wpa_s->conf->home_milenage == NULL ||
-           !wpa_s->conf->home_milenage[0])
-               return ret;
+       for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+               char *sep;
+               const char *imsi;
+               int mnc_len;
+
+#ifdef PCSC_FUNCS
+               if (cred->pcsc && wpa_s->conf->pcsc_reader && wpa_s->scard &&
+                   wpa_s->imsi[0]) {
+                       imsi = wpa_s->imsi;
+                       mnc_len = wpa_s->mnc_len;
+                       goto compare;
+               }
+#endif /* PCSC_FUNCS */
 
-       wpa_printf(MSG_DEBUG, "Interworking: Parsing 3GPP info from " MACSTR,
-                  MAC2STR(bss->bssid));
-       ret = plmn_id_match(bss->anqp_3gpp, wpa_s->conf->home_imsi);
-       wpa_printf(MSG_DEBUG, "PLMN match %sfound", ret ? "" : "not ");
+               if (cred->imsi == NULL || !cred->imsi[0] ||
+                   cred->milenage == NULL || !cred->milenage[0])
+                       continue;
+
+               sep = os_strchr(cred->imsi, '-');
+               if (sep == NULL ||
+                   (sep - cred->imsi != 5 && sep - cred->imsi != 6))
+                       continue;
+               mnc_len = sep - cred->imsi - 3;
+               imsi = cred->imsi;
+
+#ifdef PCSC_FUNCS
+       compare:
+#endif /* PCSC_FUNCS */
+               wpa_printf(MSG_DEBUG, "Interworking: Parsing 3GPP info from "
+                          MACSTR, MAC2STR(bss->bssid));
+               ret = plmn_id_match(bss->anqp_3gpp, imsi, mnc_len);
+               wpa_printf(MSG_DEBUG, "PLMN match %sfound", ret ? "" : "not ");
+               if (ret) {
+                       if (selected == NULL ||
+                           selected->priority < cred->priority)
+                               selected = cred;
+               }
+       }
 #endif /* INTERWORKING_3GPP */
-       return ret;
+       return selected;
 }
 
 
-static int interworking_credentials_available_realm(
+static struct wpa_cred * interworking_credentials_available_realm(
        struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
 {
+       struct wpa_cred *cred, *selected = NULL;
        struct nai_realm *realm;
        u16 count, i;
-       int found = 0;
 
        if (bss->anqp_nai_realm == NULL)
-               return 0;
+               return NULL;
 
-       if (wpa_s->conf->home_realm == NULL)
-               return 0;
+       if (wpa_s->conf->cred == NULL)
+               return NULL;
 
        wpa_printf(MSG_DEBUG, "Interworking: Parsing NAI Realm list from "
                   MACSTR, MAC2STR(bss->bssid));
@@ -800,50 +990,198 @@ static int interworking_credentials_available_realm(
        if (realm == NULL) {
                wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
                           "Realm list from " MACSTR, MAC2STR(bss->bssid));
-               return 0;
+               return NULL;
        }
 
-       for (i = 0; i < count; i++) {
-               if (!nai_realm_match(&realm[i], wpa_s->conf->home_realm))
+       for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+               if (cred->realm == NULL)
                        continue;
-               if (nai_realm_find_eap(wpa_s, &realm[i])) {
-                       found++;
-                       break;
+
+               for (i = 0; i < count; i++) {
+                       if (!nai_realm_match(&realm[i], cred->realm))
+                               continue;
+                       if (nai_realm_find_eap(cred, &realm[i])) {
+                               if (selected == NULL ||
+                                   selected->priority < cred->priority)
+                                       selected = cred;
+                               break;
+                       }
                }
        }
 
        nai_realm_free(realm, count);
 
-       return found;
+       return selected;
+}
+
+
+static struct wpa_cred * interworking_credentials_available(
+       struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+       struct wpa_cred *cred, *cred2;
+
+       cred = interworking_credentials_available_realm(wpa_s, bss);
+       cred2 = interworking_credentials_available_3gpp(wpa_s, bss);
+       if (cred && cred2 && cred2->priority >= cred->priority)
+               cred = cred2;
+       if (!cred)
+               cred = cred2;
+
+       return cred;
 }
 
 
-static int interworking_credentials_available(struct wpa_supplicant *wpa_s,
-                                             struct wpa_bss *bss)
+static int domain_name_list_contains(struct wpabuf *domain_names,
+                                    const char *domain)
 {
-       return interworking_credentials_available_realm(wpa_s, bss) ||
-               interworking_credentials_available_3gpp(wpa_s, bss);
+       const u8 *pos, *end;
+       size_t len;
+
+       len = os_strlen(domain);
+       pos = wpabuf_head(domain_names);
+       end = pos + wpabuf_len(domain_names);
+
+       while (pos + 1 < end) {
+               if (pos + 1 + pos[0] > end)
+                       break;
+
+               wpa_hexdump_ascii(MSG_DEBUG, "Interworking: AP domain name",
+                                 pos + 1, pos[0]);
+               if (pos[0] == len &&
+                   os_strncasecmp(domain, (const char *) (pos + 1), len) == 0)
+                       return 1;
+
+               pos += 1 + pos[0];
+       }
+
+       return 0;
+}
+
+
+static int interworking_home_sp(struct wpa_supplicant *wpa_s,
+                               struct wpabuf *domain_names)
+{
+       struct wpa_cred *cred;
+#ifdef INTERWORKING_3GPP
+       char nai[100], *realm;
+#endif /* INTERWORKING_3GPP */
+
+       if (domain_names == NULL || wpa_s->conf->cred == NULL)
+               return -1;
+
+       for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+#ifdef INTERWORKING_3GPP
+               if (cred->imsi &&
+                   build_root_nai(nai, sizeof(nai), cred->imsi, 0) == 0) {
+                       realm = os_strchr(nai, '@');
+                       if (realm)
+                               realm++;
+                       wpa_printf(MSG_DEBUG, "Interworking: Search for match "
+                                  "with SIM/USIM domain %s", realm);
+                       if (realm &&
+                           domain_name_list_contains(domain_names, realm))
+                               return 1;
+               }
+#endif /* INTERWORKING_3GPP */
+
+               if (cred->domain == NULL)
+                       continue;
+
+               wpa_printf(MSG_DEBUG, "Interworking: Search for match with "
+                          "home SP FQDN %s", cred->domain);
+               if (domain_name_list_contains(domain_names, cred->domain))
+                       return 1;
+       }
+
+       return 0;
+}
+
+
+static int interworking_find_network_match(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_bss *bss;
+       struct wpa_ssid *ssid;
+
+       dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+               for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+                       if (wpas_network_disabled(wpa_s, ssid) ||
+                           ssid->mode != WPAS_MODE_INFRA)
+                               continue;
+                       if (ssid->ssid_len != bss->ssid_len ||
+                           os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) !=
+                           0)
+                               continue;
+                       /*
+                        * TODO: Consider more accurate matching of security
+                        * configuration similarly to what is done in events.c
+                        */
+                       return 1;
+               }
+       }
+
+       return 0;
 }
 
 
 static void interworking_select_network(struct wpa_supplicant *wpa_s)
 {
-       struct wpa_bss *bss, *selected = NULL;
+       struct wpa_bss *bss, *selected = NULL, *selected_home = NULL;
+       int selected_prio = -999999, selected_home_prio = -999999;
        unsigned int count = 0;
+       const char *type;
+       int res;
+       struct wpa_cred *cred;
 
        wpa_s->network_select = 0;
 
        dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
-               if (!interworking_credentials_available(wpa_s, bss))
+               cred = interworking_credentials_available(wpa_s, bss);
+               if (!cred)
                        continue;
                count++;
-               wpa_msg(wpa_s, MSG_INFO, INTERWORKING_AP MACSTR,
-                       MAC2STR(bss->bssid));
-               if (selected == NULL && wpa_s->auto_select)
-                       selected = bss;
+               res = interworking_home_sp(wpa_s, bss->anqp_domain_name);
+               if (res > 0)
+                       type = "home";
+               else if (res == 0)
+                       type = "roaming";
+               else
+                       type = "unknown";
+               wpa_msg(wpa_s, MSG_INFO, INTERWORKING_AP MACSTR " type=%s",
+                       MAC2STR(bss->bssid), type);
+               if (wpa_s->auto_select) {
+                       if (selected == NULL ||
+                           cred->priority > selected_prio) {
+                               selected = bss;
+                               selected_prio = cred->priority;
+                       }
+                       if (res > 0 &&
+                           (selected_home == NULL ||
+                            cred->priority > selected_home_prio)) {
+                               selected_home = bss;
+                               selected_home_prio = cred->priority;
+                       }
+               }
+       }
+
+       if (selected_home && selected_home != selected &&
+           selected_home_prio >= selected_prio) {
+               /* Prefer network operated by the Home SP */
+               selected = selected_home;
        }
 
        if (count == 0) {
+               /*
+                * No matching network was found based on configured
+                * credentials. Check whether any of the enabled network blocks
+                * have matching APs.
+                */
+               if (interworking_find_network_match(wpa_s)) {
+                       wpa_printf(MSG_DEBUG, "Interworking: Possible BSS "
+                                  "match for enabled network configurations");
+                       interworking_reconnect(wpa_s);
+                       return;
+               }
+
                wpa_msg(wpa_s, MSG_INFO, INTERWORKING_NO_MATCH "No network "
                        "with matching credentials found");
        }
@@ -964,6 +1302,9 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
 {
        const u8 *pos = data;
        struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
+#ifdef CONFIG_HS20
+       u8 type;
+#endif /* CONFIG_HS20 */
 
        switch (info_id) {
        case ANQP_CAPABILITY_LIST:
@@ -1047,6 +1388,28 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
                        return;
 
                switch (WPA_GET_BE24(pos)) {
+#ifdef CONFIG_HS20
+               case OUI_WFA:
+                       pos += 3;
+                       slen -= 3;
+
+                       if (slen < 1)
+                               return;
+                       type = *pos++;
+                       slen--;
+
+                       switch (type) {
+                       case HS20_ANQP_OUI_TYPE:
+                               hs20_parse_rx_hs20_anqp_resp(wpa_s, sa, pos,
+                                                            slen);
+                               break;
+                       default:
+                               wpa_printf(MSG_DEBUG, "HS20: Unsupported ANQP "
+                                          "vendor type %u", type);
+                               break;
+                       }
+                       break;
+#endif /* CONFIG_HS20 */
                default:
                        wpa_printf(MSG_DEBUG, "Interworking: Unsupported "
                                   "vendor-specific ANQP OUI %06x",
index c124ca2..80aac77 100644 (file)
@@ -61,6 +61,10 @@ static void usage(void)
 #ifdef CONFIG_DEBUG_SYSLOG
        printf("  -s = log output to syslog instead of stdout\n");
 #endif /* CONFIG_DEBUG_SYSLOG */
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+       printf("  -T = record to Linux tracing in addition to logging\n");
+       printf("       (records all messages regardless of debug verbosity)\n");
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
        printf("  -t = include timestamp in debug messages\n"
               "  -h = show this help text\n"
               "  -L = show license (BSD)\n"
@@ -139,7 +143,8 @@ int main(int argc, char *argv[])
        wpa_supplicant_fd_workaround();
 
        for (;;) {
-               c = getopt(argc, argv, "b:Bc:C:D:de:f:g:hi:KLNo:O:p:P:qstuvW");
+               c = getopt(argc, argv,
+                          "b:Bc:C:D:de:f:g:hi:KLNo:O:p:P:qsTtuvW");
                if (c < 0)
                        break;
                switch (c) {
@@ -214,6 +219,11 @@ int main(int argc, char *argv[])
                        params.wpa_debug_syslog++;
                        break;
 #endif /* CONFIG_DEBUG_SYSLOG */
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+               case 'T':
+                       params.wpa_debug_tracing++;
+                       break;
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
                case 't':
                        params.wpa_debug_timestamp++;
                        break;
@@ -252,6 +262,9 @@ int main(int argc, char *argv[])
                wpa_printf(MSG_ERROR, "Failed to initialize wpa_supplicant");
                exitcode = -1;
                goto out;
+       } else {
+               wpa_printf(MSG_INFO, "Successfully initialized "
+                          "wpa_supplicant");
        }
 
        for (i = 0; exitcode == 0 && i < iface_count; i++) {
diff --git a/wpa_supplicant/main_symbian.cpp b/wpa_supplicant/main_symbian.cpp
deleted file mode 100644 (file)
index 254fead..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * WPA Supplicant / Program entrypoint for Symbian
- * Copyright (c) 2003-2007, 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"
-
-extern "C" {
-#include "common.h"
-#include "wpa_supplicant_i.h"
-}
-
-GLDEF_C TInt E32Main(void)
-{
-       struct wpa_interface iface;
-       int exitcode = 0;
-       struct wpa_params params;
-       struct wpa_global *global;
-
-       memset(&params, 0, sizeof(params));
-       params.wpa_debug_level = MSG_INFO;
-
-       global = wpa_supplicant_init(&params);
-       if (global == NULL)
-               return -1;
-
-       memset(&iface, 0, sizeof(iface));
-       /* TODO: set interface parameters */
-
-       if (wpa_supplicant_add_iface(global, &iface) == NULL)
-               exitcode = -1;
-
-       if (exitcode == 0)
-               exitcode = wpa_supplicant_run(global);
-
-       wpa_supplicant_deinit(global);
-
-       return exitcode;
-}
diff --git a/wpa_supplicant/nfc_pw_token.c b/wpa_supplicant/nfc_pw_token.c
new file mode 100644 (file)
index 0000000..11afb5b
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * nfc_pw_token - Tool for building NFC password tokens for WPS
+ * Copyright (c) 2012, 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 "utils/common.h"
+#include "crypto/random.h"
+#include "wpa_supplicant_i.h"
+#include "config.h"
+#include "wps_supplicant.h"
+
+
+static void print_bin(const char *title, const struct wpabuf *buf)
+{
+       size_t i, len;
+       const u8 *pos;
+
+       if (buf == NULL)
+               return;
+
+       printf("%s=", title);
+
+       pos = wpabuf_head(buf);
+       len = wpabuf_len(buf);
+       for (i = 0; i < len; i++)
+               printf("%02X", *pos++);
+
+       printf("\n");
+}
+
+
+int main(int argc, char *argv[])
+{
+       struct wpa_supplicant wpa_s;
+       int ret = -1;
+       struct wpabuf *buf = NULL, *ndef = NULL;
+       char txt[1000];
+
+       if (os_program_init())
+               return -1;
+       random_init(NULL);
+
+       os_memset(&wpa_s, 0, sizeof(wpa_s));
+       wpa_s.conf = os_zalloc(sizeof(*wpa_s.conf));
+       if (wpa_s.conf == NULL)
+               goto fail;
+
+       buf = wpas_wps_nfc_token(&wpa_s, 0);
+       if (buf == NULL)
+               goto fail;
+
+       ndef = ndef_build_wifi(buf);
+       if (ndef == NULL)
+               goto fail;
+
+       wpa_snprintf_hex_uppercase(txt, sizeof(txt), wpabuf_head(buf),
+                                  wpabuf_len(buf));
+       printf("#WPS=%s\n", txt);
+
+       wpa_snprintf_hex_uppercase(txt, sizeof(txt), wpabuf_head(ndef),
+                                  wpabuf_len(ndef));
+       printf("#NDEF=%s\n", txt);
+
+       printf("wps_nfc_dev_pw_id=%d\n", wpa_s.conf->wps_nfc_dev_pw_id);
+       print_bin("wps_nfc_dh_pubkey", wpa_s.conf->wps_nfc_dh_pubkey);
+       print_bin("wps_nfc_dh_privkey", wpa_s.conf->wps_nfc_dh_privkey);
+       print_bin("wps_nfc_dev_pw", wpa_s.conf->wps_nfc_dev_pw);
+
+       ret = 0;
+fail:
+       wpabuf_free(ndef);
+       wpabuf_free(buf);
+       wpa_config_free(wpa_s.conf);
+       random_deinit();
+       os_program_deinit();
+
+       return ret;
+}
index f613897..59e6975 100644 (file)
@@ -82,7 +82,7 @@ void wpas_notify_state_changed(struct wpa_supplicant *wpa_s,
 #ifdef CONFIG_P2P
        if (new_state == WPA_COMPLETED)
                wpas_p2p_notif_connected(wpa_s);
-       else if (new_state < WPA_ASSOCIATED)
+       else if (old_state >= WPA_ASSOCIATED && new_state < WPA_ASSOCIATED)
                wpas_p2p_notif_disconnected(wpa_s);
 #endif /* CONFIG_P2P */
 
@@ -101,6 +101,12 @@ void wpas_notify_state_changed(struct wpa_supplicant *wpa_s,
 }
 
 
+void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s)
+{
+       wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_DISCONNECT_REASON);
+}
+
+
 void wpas_notify_network_changed(struct wpa_supplicant *wpa_s)
 {
        wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_CURRENT_NETWORK);
@@ -606,3 +612,20 @@ void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth,
        /* notify the new DBus API */
        wpas_dbus_signal_certification(wpa_s, depth, subject, cert_hash, cert);
 }
+
+
+void wpas_notify_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)
+{
+#ifdef CONFIG_AP
+       wpas_dbus_signal_preq(wpa_s, addr, dst, bssid, ie, ie_len, ssi_signal);
+#endif /* CONFIG_AP */
+}
+
+
+void wpas_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status,
+                           const char *parameter)
+{
+       wpas_dbus_signal_eap_status(wpa_s, status, parameter);
+}
index bd99a76..58675ac 100644 (file)
@@ -22,6 +22,7 @@ void wpas_notify_iface_removed(struct wpa_supplicant *wpa_s);
 void wpas_notify_state_changed(struct wpa_supplicant *wpa_s,
                               enum wpa_states new_state,
                               enum wpa_states old_state);
+void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s);
 void wpas_notify_network_changed(struct wpa_supplicant *wpa_s);
 void wpas_notify_ap_scan_changed(struct wpa_supplicant *wpa_s);
 void wpas_notify_bssid_changed(struct wpa_supplicant *wpa_s);
@@ -121,5 +122,10 @@ void wpas_notify_p2p_wps_failed(struct wpa_supplicant *wpa_s,
 void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth,
                               const char *subject, const char *cert_hash,
                               const struct wpabuf *cert);
+void wpas_notify_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_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status,
+                           const char *parameter);
 
 #endif /* NOTIFY_H */
index 5f1329e..e0c3580 100644 (file)
@@ -39,6 +39,8 @@
  */
 #define P2P_MAX_JOIN_SCAN_ATTEMPTS 10
 
+#define P2P_AUTO_PD_SCAN_ATTEMPTS 5
+
 #ifndef P2P_MAX_CLIENT_IDLE
 /*
  * How many seconds to try to reconnect to the GO when connection in P2P client
 #endif /* ANDROID_P2P */
 #endif /* P2P_MAX_CLIENT_IDLE */
 
+#ifndef P2P_MAX_INITIAL_CONN_WAIT
+/*
+ * How many seconds to wait for initial 4-way handshake to get completed after
+ * WPS provisioning step.
+ */
+#define P2P_MAX_INITIAL_CONN_WAIT 10
+#endif /* P2P_MAX_INITIAL_CONN_WAIT */
+
 #ifdef ANDROID_P2P
 static int wpas_global_scan_in_progress(struct wpa_supplicant *wpa_s);
 #endif
@@ -59,15 +69,19 @@ static struct wpa_supplicant *
 wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
                         int go);
 static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s);
+static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq);
 static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx);
 static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr,
-                        const u8 *dev_addr, enum p2p_wps_method wps_method);
+                        const u8 *dev_addr, enum p2p_wps_method wps_method,
+                        int auto_join);
 static void wpas_p2p_pd_before_join_timeout(void *eloop_ctx,
                                            void *timeout_ctx);
 static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s);
 static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s);
 static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx);
 static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s);
+static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
+                                       int group_added);
 
 #ifdef ANDROID_P2P
 static int wpas_global_scan_in_progress(struct wpa_supplicant *wpa_s)
@@ -112,7 +126,7 @@ static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
 
 static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
                         unsigned int num_req_dev_types,
-                        const u8 *req_dev_types, const u8 *dev_id)
+                        const u8 *req_dev_types, const u8 *dev_id, u16 pw_id)
 {
        struct wpa_supplicant *wpa_s = ctx;
        struct wpa_driver_scan_params params;
@@ -120,7 +134,6 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
        struct wpabuf *wps_ie, *ies;
        int social_channels[] = { 2412, 2437, 2462, 0, 0 };
        size_t ielen;
-       int was_in_p2p_scan;
 
        if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
                return -1;
@@ -133,8 +146,8 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
        params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
 
        wpa_s->wps->dev.p2p = 1;
-       wps_ie = wps_build_probe_req_ie(0, &wpa_s->wps->dev, wpa_s->wps->uuid,
-                                       WPS_REQ_ENROLLEE,
+       wps_ie = wps_build_probe_req_ie(pw_id, &wpa_s->wps->dev,
+                                       wpa_s->wps->uuid, WPS_REQ_ENROLLEE,
                                        num_req_dev_types, req_dev_types);
        if (wps_ie == NULL)
                return -1;
@@ -160,34 +173,24 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
                break;
        case P2P_SCAN_FULL:
                break;
-       case P2P_SCAN_SPECIFIC:
-               social_channels[0] = freq;
-               social_channels[1] = 0;
-               params.freqs = social_channels;
-               break;
        case P2P_SCAN_SOCIAL_PLUS_ONE:
                social_channels[3] = freq;
                params.freqs = social_channels;
                break;
        }
 
-       was_in_p2p_scan = wpa_s->scan_res_handler == wpas_p2p_scan_res_handler;
-       wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
        ret = wpa_drv_scan(wpa_s, &params);
 
        wpabuf_free(ies);
 
        if (ret) {
-               wpa_s->scan_res_handler = NULL;
-#ifdef ANDROID_P2P
-               if (wpa_s->scanning || was_in_p2p_scan || wpas_global_scan_in_progress(wpa_s)) {
-#else
-               if (wpa_s->scanning || was_in_p2p_scan) {
-#endif
+               if (wpa_s->scanning ||
+                   wpa_s->scan_res_handler == wpas_p2p_scan_res_handler) {
                        wpa_s->p2p_cb_on_scan_complete = 1;
                        ret = 1;
                }
-       }
+       } else
+               wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
 
        return ret;
 }
@@ -233,14 +236,12 @@ static struct wpa_supplicant * wpas_get_p2p_group(struct wpa_supplicant *wpa_s,
 }
 
 
-static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s)
+static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, int silent)
 {
        struct wpa_ssid *ssid;
        char *gtype;
        const char *reason;
 
-       eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
-
        ssid = wpa_s->current_ssid;
        if (ssid == NULL) {
                /*
@@ -283,6 +284,9 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s)
        case P2P_GROUP_REMOVAL_UNAVAILABLE:
                reason = " reason=UNAVAILABLE";
                break;
+       case P2P_GROUP_REMOVAL_GO_ENDING_SESSION:
+               reason = " reason=GO_ENDING_SESSION";
+               break;
 #ifdef ANDROID_P2P
        case P2P_GROUP_REMOVAL_FREQ_CONFLICT:
                reason = " reason=FREQ_CONFLICT";
@@ -292,10 +296,16 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s)
                reason = "";
                break;
        }
-       wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_REMOVED "%s %s%s",
-               wpa_s->ifname, gtype, reason);
+       if (!silent) {
+               wpa_msg(wpa_s->parent, MSG_INFO,
+                       P2P_EVENT_GROUP_REMOVED "%s %s%s",
+                       wpa_s->ifname, gtype, reason);
+       }
 
-       if (ssid)
+       if (eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0)
+               wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout");
+
+       if (!silent && ssid)
                wpas_notify_p2p_group_removed(wpa_s, ssid, gtype);
 
        if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
@@ -341,7 +351,10 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s)
                wpa_printf(MSG_DEBUG, "P2P: Temporary group network not "
                           "found");
        }
-       wpa_supplicant_ap_deinit(wpa_s);
+       if (wpa_s->ap_iface)
+               wpa_supplicant_ap_deinit(wpa_s);
+       else
+               wpa_drv_deinit_p2p_cli(wpa_s);
 }
 
 
@@ -562,7 +575,7 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
        if (!success) {
                wpa_msg(wpa_s->parent, MSG_INFO,
                        P2P_EVENT_GROUP_FORMATION_FAILURE);
-               wpas_p2p_group_delete(wpa_s);
+               wpas_p2p_group_delete(wpa_s, 0);
                return;
        }
 
@@ -670,6 +683,13 @@ static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s,
            (os_memcmp(dst, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
             os_memcmp(dst, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0)) {
                wpa_s->pending_pd_before_join = 0;
+               if (wpa_s->p2p_fallback_to_go_neg) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No ACK for PD Req "
+                               "during p2p_connect-auto");
+                       wpas_p2p_fallback_to_go_neg(wpa_s, 0);
+                       return;
+               }
+
                wpa_printf(MSG_DEBUG, "P2P: Starting pending "
                           "join-existing-group operation (no ACK for PD "
                           "Req)");
@@ -851,6 +871,8 @@ static void wpas_p2p_clone_config(struct wpa_supplicant *dst,
        d->p2p_group_idle = s->p2p_group_idle;
        d->p2p_intra_bss = s->p2p_intra_bss;
        d->persistent_reconnect = s->persistent_reconnect;
+       d->max_num_sta = s->max_num_sta;
+       d->pbc_in_m1 = s->pbc_in_m1;
 }
 
 
@@ -1002,6 +1024,20 @@ void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
        wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS);
        wpas_notify_p2p_go_neg_completed(wpa_s, res);
 
+       if (res->role_go && wpa_s->p2p_persistent_id >= 0) {
+               struct wpa_ssid *ssid;
+               ssid = wpa_config_get_network(wpa_s->conf,
+                                             wpa_s->p2p_persistent_id);
+               if (ssid && ssid->disabled == 2 &&
+                   ssid->mode == WPAS_MODE_P2P_GO && ssid->passphrase) {
+                       size_t len = os_strlen(ssid->passphrase);
+                       wpa_printf(MSG_DEBUG, "P2P: Override passphrase based "
+                                  "on requested persistent group");
+                       os_memcpy(res->passphrase, ssid->passphrase, len);
+                       res->passphrase[len] = '\0';
+               }
+       }
+
        if (wpa_s->create_p2p_iface) {
                struct wpa_supplicant *group_wpa_s =
                        wpas_p2p_init_group_interface(wpa_s, res->role_go);
@@ -1836,6 +1872,7 @@ void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
 {
        struct wpa_supplicant *wpa_s = ctx;
        unsigned int generated_pin = 0;
+       char params[20];
 
        if (wpa_s->pending_pd_before_join &&
            (os_memcmp(peer, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
@@ -1847,14 +1884,22 @@ void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
                return;
        }
 
+       if (wpa_s->pending_pd_use == AUTO_PD_JOIN ||
+           wpa_s->pending_pd_use == AUTO_PD_GO_NEG)
+               os_snprintf(params, sizeof(params), " peer_go=%d",
+                           wpa_s->pending_pd_use == AUTO_PD_JOIN);
+       else
+               params[0] = '\0';
+
        if (config_methods & WPS_CONFIG_DISPLAY)
-               wpas_prov_disc_local_keypad(wpa_s, peer, "");
+               wpas_prov_disc_local_keypad(wpa_s, peer, params);
        else if (config_methods & WPS_CONFIG_KEYPAD) {
                generated_pin = wps_generate_pin();
-               wpas_prov_disc_local_display(wpa_s, peer, "", generated_pin);
+               wpas_prov_disc_local_display(wpa_s, peer, params,
+                                            generated_pin);
        } else if (config_methods & WPS_CONFIG_PUSHBUTTON)
-               wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_RESP MACSTR,
-                       MAC2STR(peer));
+               wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_RESP MACSTR
+                       "%s", MAC2STR(peer), params);
 
        wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */,
                                            P2P_PROV_DISC_SUCCESS,
@@ -1867,6 +1912,17 @@ static void wpas_prov_disc_fail(void *ctx, const u8 *peer,
 {
        struct wpa_supplicant *wpa_s = ctx;
 
+       if (wpa_s->p2p_fallback_to_go_neg) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "P2P: PD for p2p_connect-auto "
+                       "failed - fall back to GO Negotiation");
+               wpas_p2p_fallback_to_go_neg(wpa_s, 0);
+               return;
+       }
+
+       wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
+               " p2p_dev_addr=" MACSTR " status=%d",
+               MAC2STR(peer), status);
+
        wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */,
                                            status, 0, 0);
 }
@@ -1993,7 +2049,7 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
                                wpa_s, s, s->mode == WPAS_MODE_P2P_GO, 0);
                } else if (bssid) {
                        wpas_p2p_join(wpa_s, bssid, go_dev_addr,
-                                     wpa_s->p2p_wps_method);
+                                     wpa_s->p2p_wps_method, 0);
                }
                return;
        }
@@ -2061,6 +2117,31 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid)
 }
 
 
+static int wpas_p2p_disallowed_freq(struct wpa_global *global,
+                                   unsigned int freq)
+{
+       unsigned int i;
+
+       if (global->p2p_disallow_freq == NULL)
+               return 0;
+
+       for (i = 0; i < global->num_p2p_disallow_freq; i++) {
+               if (freq >= global->p2p_disallow_freq[i].min &&
+                   freq <= global->p2p_disallow_freq[i].max)
+                       return 1;
+       }
+
+       return 0;
+}
+
+
+static void wpas_p2p_add_chan(struct p2p_reg_class *reg, u8 chan)
+{
+       reg->channel[reg->channels] = chan;
+       reg->channels++;
+}
+
+
 static int wpas_p2p_default_channels(struct wpa_supplicant *wpa_s,
                                     struct p2p_channels *chan)
 {
@@ -2071,34 +2152,47 @@ static int wpas_p2p_default_channels(struct wpa_supplicant *wpa_s,
 
        /* Operating class 81 - 2.4 GHz band channels 1..13 */
        chan->reg_class[cla].reg_class = 81;
-       chan->reg_class[cla].channels = 11;
-       for (i = 0; i < 11; i++)
-               chan->reg_class[cla].channel[i] = i + 1;
-       cla++;
+       chan->reg_class[cla].channels = 0;
+       for (i = 0; i < 11; i++) {
+               if (!wpas_p2p_disallowed_freq(wpa_s->global, 2412 + i * 5))
+                       wpas_p2p_add_chan(&chan->reg_class[cla], i + 1);
+       }
+       if (chan->reg_class[cla].channels)
+               cla++;
 
        wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for lower 5 GHz "
                   "band");
 
        /* Operating class 115 - 5 GHz, channels 36-48 */
        chan->reg_class[cla].reg_class = 115;
-       chan->reg_class[cla].channels = 4;
-       chan->reg_class[cla].channel[0] = 36;
-       chan->reg_class[cla].channel[1] = 40;
-       chan->reg_class[cla].channel[2] = 44;
-       chan->reg_class[cla].channel[3] = 48;
-       cla++;
+       chan->reg_class[cla].channels = 0;
+       if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 36 * 5))
+               wpas_p2p_add_chan(&chan->reg_class[cla], 36);
+       if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 40 * 5))
+               wpas_p2p_add_chan(&chan->reg_class[cla], 40);
+       if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 44 * 5))
+               wpas_p2p_add_chan(&chan->reg_class[cla], 44);
+       if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 48 * 5))
+               wpas_p2p_add_chan(&chan->reg_class[cla], 48);
+       if (chan->reg_class[cla].channels)
+               cla++;
 
        wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for higher 5 GHz "
                   "band");
 
        /* Operating class 124 - 5 GHz, channels 149,153,157,161 */
        chan->reg_class[cla].reg_class = 124;
-       chan->reg_class[cla].channels = 4;
-       chan->reg_class[cla].channel[0] = 149;
-       chan->reg_class[cla].channel[1] = 153;
-       chan->reg_class[cla].channel[2] = 157;
-       chan->reg_class[cla].channel[3] = 161;
-       cla++;
+       chan->reg_class[cla].channels = 0;
+       if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 149 * 5))
+               wpas_p2p_add_chan(&chan->reg_class[cla], 149);
+       if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 153 * 5))
+               wpas_p2p_add_chan(&chan->reg_class[cla], 153);
+       if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 156 * 5))
+               wpas_p2p_add_chan(&chan->reg_class[cla], 157);
+       if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 161 * 5))
+               wpas_p2p_add_chan(&chan->reg_class[cla], 161);
+       if (chan->reg_class[cla].channels)
+               cla++;
 
        chan->reg_classes = cla;
        return 0;
@@ -2120,9 +2214,16 @@ static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
 }
 
 
-static int has_channel(struct hostapd_hw_modes *mode, u8 chan, int *flags)
+static int has_channel(struct wpa_global *global,
+                      struct hostapd_hw_modes *mode, u8 chan, int *flags)
 {
        int i;
+       unsigned int freq;
+
+       freq = (mode->mode == HOSTAPD_MODE_IEEE80211A ? 5000 : 2407) +
+               chan * 5;
+       if (wpas_p2p_disallowed_freq(global, freq))
+               return 0;
 
        for (i = 0; i < mode->num_channels; i++) {
                if (mode->channels[i].chan == chan) {
@@ -2189,15 +2290,15 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
                        continue;
                for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
                        int flag;
-                       if (!has_channel(mode, ch, &flag))
+                       if (!has_channel(wpa_s->global, mode, ch, &flag))
                                continue;
                        if (o->bw == BW40MINUS &&
                            (!(flag & HOSTAPD_CHAN_HT40MINUS) ||
-                            !has_channel(mode, ch - 4, NULL)))
+                            !has_channel(wpa_s->global, mode, ch - 4, NULL)))
                                continue;
                        if (o->bw == BW40PLUS &&
                            (!(flag & HOSTAPD_CHAN_HT40PLUS) ||
-                            !has_channel(mode, ch + 4, NULL)))
+                            !has_channel(wpa_s->global, mode, ch + 4, NULL)))
                                continue;
                        if (reg == NULL) {
                                wpa_printf(MSG_DEBUG, "P2P: Add operating "
@@ -2404,6 +2505,7 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
        global->p2p = p2p_init(&p2p);
        if (global->p2p == NULL)
                return -1;
+       global->p2p_init_wpa_s = wpa_s;
 
        for (i = 0; i < MAX_WPS_VENDOR_EXT; i++) {
                if (wpa_s->conf->wps_vendor_ext[i] == NULL)
@@ -2431,7 +2533,7 @@ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s)
                /* Clear any stored provisioning info */
                p2p_clear_provisioning_info(
                        wpa_s->global->p2p,
-                       wpa_s->go_params->peer_interface_addr);
+                       wpa_s->go_params->peer_device_addr);
        }
 
        os_free(wpa_s->go_params);
@@ -2458,7 +2560,6 @@ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s)
 void wpas_p2p_deinit_global(struct wpa_global *global)
 {
        struct wpa_supplicant *wpa_s, *tmp;
-       char *ifname;
 
        if (global->p2p == NULL)
                return;
@@ -2470,7 +2571,6 @@ void wpas_p2p_deinit_global(struct wpa_global *global)
        while (wpa_s && wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE)
                wpa_s = wpa_s->next;
        while (wpa_s) {
-               enum wpa_driver_if_type type;
                tmp = global->ifaces;
                while (tmp &&
                       (tmp == wpa_s ||
@@ -2479,12 +2579,8 @@ void wpas_p2p_deinit_global(struct wpa_global *global)
                }
                if (tmp == NULL)
                        break;
-               ifname = os_strdup(tmp->ifname);
-               type = wpas_p2p_if_type(tmp->p2p_group_interface);
-               wpa_supplicant_remove_iface(global, tmp, 0);
-               if (ifname)
-                       wpa_drv_if_remove(wpa_s, type, ifname);
-               os_free(ifname);
+               /* Disconnect from the P2P group and deinit the interface */
+               wpas_p2p_disconnect(tmp);
        }
 
        /*
@@ -2498,6 +2594,7 @@ void wpas_p2p_deinit_global(struct wpa_global *global)
 
        p2p_deinit(global->p2p);
        global->p2p = NULL;
+       global->p2p_init_wpa_s = NULL;
 }
 
 
@@ -2522,7 +2619,8 @@ static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s,
                                 const u8 *peer_addr,
                                 enum p2p_wps_method wps_method,
                                 int go_intent, const u8 *own_interface_addr,
-                                unsigned int force_freq, int persistent_group)
+                                unsigned int force_freq, int persistent_group,
+                                struct wpa_ssid *ssid)
 {
        if (persistent_group && wpa_s->conf->persistent_reconnect)
                persistent_group = 2;
@@ -2535,7 +2633,9 @@ static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s,
 
        return p2p_connect(wpa_s->global->p2p, peer_addr, wps_method,
                           go_intent, own_interface_addr, force_freq,
-                          persistent_group);
+                          persistent_group, ssid ? ssid->ssid : NULL,
+                          ssid ? ssid->ssid_len : 0,
+                          wpa_s->p2p_pd_before_go_neg);
 }
 
 
@@ -2543,7 +2643,8 @@ static int wpas_p2p_auth_go_neg(struct wpa_supplicant *wpa_s,
                                const u8 *peer_addr,
                                enum p2p_wps_method wps_method,
                                int go_intent, const u8 *own_interface_addr,
-                               unsigned int force_freq, int persistent_group)
+                               unsigned int force_freq, int persistent_group,
+                               struct wpa_ssid *ssid)
 {
        if (persistent_group && wpa_s->conf->persistent_reconnect)
                persistent_group = 2;
@@ -2553,7 +2654,8 @@ static int wpas_p2p_auth_go_neg(struct wpa_supplicant *wpa_s,
 
        return p2p_authorize(wpa_s->global->p2p, peer_addr, wps_method,
                             go_intent, own_interface_addr, force_freq,
-                            persistent_group);
+                            persistent_group, ssid ? ssid->ssid : NULL,
+                            ssid ? ssid->ssid_len : 0);
 }
 
 
@@ -2567,6 +2669,13 @@ static void wpas_p2p_check_join_scan_limit(struct wpa_supplicant *wpa_s)
                           " for join operationg - stop join attempt",
                           MAC2STR(wpa_s->pending_join_iface_addr));
                eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
+               if (wpa_s->p2p_auto_pd) {
+                       wpa_s->p2p_auto_pd = 0;
+                       wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
+                               " p2p_dev_addr=" MACSTR " status=N/A",
+                               MAC2STR(wpa_s->pending_join_dev_addr));
+                       return;
+               }
                wpa_msg(wpa_s->parent, MSG_INFO,
                        P2P_EVENT_GROUP_FORMATION_FAILURE);
        }
@@ -2588,26 +2697,155 @@ static void wpas_p2p_pd_before_join_timeout(void *eloop_ctx, void *timeout_ctx)
 }
 
 
+static int wpas_check_freq_conflict(struct wpa_supplicant *wpa_s, int freq)
+{
+       struct wpa_supplicant *iface;
+       int shared_freq;
+       u8 bssid[ETH_ALEN];
+
+       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)
+               return 0;
+
+       for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
+               if (!wpas_p2p_create_iface(wpa_s) && iface == wpa_s)
+                       continue;
+               if (iface->current_ssid == NULL || iface->assoc_freq == 0)
+                       continue;
+               if (iface->current_ssid->mode == WPAS_MODE_AP ||
+                   iface->current_ssid->mode == WPAS_MODE_P2P_GO)
+                       shared_freq = iface->current_ssid->frequency;
+               else if (wpa_drv_get_bssid(iface, bssid) == 0)
+                       shared_freq = iface->assoc_freq;
+               else
+                       shared_freq = 0;
+
+               if (shared_freq && freq != shared_freq) {
+                       wpa_printf(MSG_DEBUG, "P2P: Frequency conflict - %s "
+                                  "connected on %d MHz - new connection on "
+                                  "%d MHz", iface->ifname, shared_freq, freq);
+                       return 1;
+               }
+       }
+
+       shared_freq = wpa_drv_shared_freq(wpa_s);
+       if (shared_freq > 0 && shared_freq != freq) {
+               wpa_printf(MSG_DEBUG, "P2P: Frequency conflict - shared "
+                          "virtual interface connected on %d MHz - new "
+                          "connection on %d MHz", shared_freq, freq);
+               return 1;
+       }
+
+       return 0;
+}
+
+
+static int wpas_p2p_peer_go(struct wpa_supplicant *wpa_s,
+                           const u8 *peer_dev_addr)
+{
+       struct wpa_bss *bss;
+       int updated;
+
+       bss = wpa_bss_get_p2p_dev_addr(wpa_s, peer_dev_addr);
+       if (bss == NULL)
+               return -1;
+       if (bss->last_update_idx < wpa_s->bss_update_idx) {
+               wpa_printf(MSG_DEBUG, "P2P: Peer BSS entry not updated in the "
+                          "last scan");
+               return 0;
+       }
+
+       updated = os_time_before(&wpa_s->p2p_auto_started, &bss->last_update);
+       wpa_printf(MSG_DEBUG, "P2P: Current BSS entry for peer updated at "
+                  "%ld.%06ld (%supdated in last scan)",
+                  bss->last_update.sec, bss->last_update.usec,
+                  updated ? "": "not ");
+
+       return updated;
+}
+
+
 static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
                                   struct wpa_scan_results *scan_res)
 {
        struct wpa_bss *bss;
        int freq;
        u8 iface_addr[ETH_ALEN];
-#ifdef ANDROID_P2P     
-       int shared_freq = 0;
-#endif
+
        eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
 
        if (wpa_s->global->p2p_disabled)
                return;
 
-       wpa_printf(MSG_DEBUG, "P2P: Scan results received (%d BSS) for join",
-                  scan_res ? (int) scan_res->num : -1);
+       wpa_printf(MSG_DEBUG, "P2P: Scan results received (%d BSS) for %sjoin",
+                  scan_res ? (int) scan_res->num : -1,
+                  wpa_s->p2p_auto_join ? "auto_" : "");
 
        if (scan_res)
                wpas_p2p_scan_res_handler(wpa_s, scan_res);
 
+       if (wpa_s->p2p_auto_pd) {
+               int join = wpas_p2p_peer_go(wpa_s,
+                                           wpa_s->pending_join_dev_addr);
+               if (join == 0 &&
+                   wpa_s->auto_pd_scan_retry < P2P_AUTO_PD_SCAN_ATTEMPTS) {
+                       wpa_s->auto_pd_scan_retry++;
+                       bss = wpa_bss_get_bssid(wpa_s,
+                                               wpa_s->pending_join_dev_addr);
+                       if (bss) {
+                               freq = bss->freq;
+                               wpa_printf(MSG_DEBUG, "P2P: Scan retry %d for "
+                                          "the peer " MACSTR " at %d MHz",
+                                          wpa_s->auto_pd_scan_retry,
+                                          MAC2STR(wpa_s->
+                                                  pending_join_dev_addr),
+                                          freq);
+                               wpas_p2p_join_scan_req(wpa_s, freq);
+                               return;
+                       }
+               }
+
+               if (join < 0)
+                       join = 0;
+
+               wpa_s->p2p_auto_pd = 0;
+               wpa_s->pending_pd_use = join ? AUTO_PD_JOIN : AUTO_PD_GO_NEG;
+               wpa_printf(MSG_DEBUG, "P2P: Auto PD with " MACSTR " join=%d",
+                          MAC2STR(wpa_s->pending_join_dev_addr), join);
+               if (p2p_prov_disc_req(wpa_s->global->p2p,
+                                     wpa_s->pending_join_dev_addr,
+                                     wpa_s->pending_pd_config_methods, join,
+                                     0) < 0) {
+                       wpa_s->p2p_auto_pd = 0;
+                       wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
+                               " p2p_dev_addr=" MACSTR " status=N/A",
+                               MAC2STR(wpa_s->pending_join_dev_addr));
+               }
+               return;
+       }
+
+       if (wpa_s->p2p_auto_join) {
+               int join = wpas_p2p_peer_go(wpa_s,
+                                           wpa_s->pending_join_dev_addr);
+               if (join < 0) {
+                       wpa_printf(MSG_DEBUG, "P2P: Peer was not found to be "
+                                  "running a GO -> use GO Negotiation");
+                       wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr,
+                                        wpa_s->p2p_pin, wpa_s->p2p_wps_method,
+                                        wpa_s->p2p_persistent_group, 0, 0, 0,
+                                        wpa_s->p2p_go_intent,
+                                        wpa_s->p2p_connect_freq,
+                                        wpa_s->p2p_persistent_id,
+                                        wpa_s->p2p_pd_before_go_neg);
+                       return;
+               }
+
+               wpa_printf(MSG_DEBUG, "P2P: Peer was found running GO%s -> "
+                          "try to join the group", join ? "" :
+                          " in older scan");
+               if (!join)
+                       wpa_s->p2p_fallback_to_go_neg = 1;
+       }
+
        freq = p2p_get_oper_freq(wpa_s->global->p2p,
                                 wpa_s->pending_join_iface_addr);
        if (freq < 0 &&
@@ -2631,16 +2869,6 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
                wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
                           "from P2P peer table: %d MHz", freq);
        }
-
-#ifdef ANDROID_P2P
-       if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) && 
-               ((shared_freq = wpa_drv_shared_freq(wpa_s)) > 0) && (shared_freq != freq)) {
-               wpa_msg(wpa_s->parent, MSG_INFO,
-                                       P2P_EVENT_GROUP_FORMATION_FAILURE "reason=FREQ_CONFLICT");
-               return;
-       }
-#endif
-
        bss = wpa_bss_get_bssid(wpa_s, wpa_s->pending_join_iface_addr);
        if (bss) {
                freq = bss->freq;
@@ -2650,6 +2878,13 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
        if (freq > 0) {
                u16 method;
 
+               if (wpas_check_freq_conflict(wpa_s, freq) > 0) {
+                       wpa_msg(wpa_s->parent, MSG_INFO,
+                               P2P_EVENT_GROUP_FORMATION_FAILURE
+                               "reason=FREQ_CONFLICT");
+                       return;
+               }
+
                wpa_printf(MSG_DEBUG, "P2P: Send Provision Discovery Request "
                           "prior to joining an existing group (GO " MACSTR
                           " freq=%u MHz)",
@@ -2722,13 +2957,13 @@ start:
 }
 
 
-static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx)
+static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq)
 {
-       struct wpa_supplicant *wpa_s = eloop_ctx;
        int ret;
        struct wpa_driver_scan_params params;
        struct wpabuf *wps_ie, *ies;
        size_t ielen;
+       int freqs[2] = { 0, 0 };
 
        os_memset(&params, 0, sizeof(params));
 
@@ -2738,8 +2973,9 @@ static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx)
        params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
 
        wpa_s->wps->dev.p2p = 1;
-       wps_ie = wps_build_probe_req_ie(0, &wpa_s->wps->dev, wpa_s->wps->uuid,
-                                       WPS_REQ_ENROLLEE, 0, NULL);
+       wps_ie = wps_build_probe_req_ie(DEV_PW_DEFAULT, &wpa_s->wps->dev,
+                                       wpa_s->wps->uuid, WPS_REQ_ENROLLEE, 0,
+                                       NULL);
        if (wps_ie == NULL) {
                wpas_p2p_scan_res_join(wpa_s, NULL);
                return;
@@ -2760,13 +2996,18 @@ static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx)
        params.p2p_probe = 1;
        params.extra_ies = wpabuf_head(ies);
        params.extra_ies_len = wpabuf_len(ies);
+       if (freq > 0) {
+               freqs[0] = freq;
+               params.freqs = freqs;
+       }
 
        /*
         * Run a scan to update BSS table and start Provision Discovery once
         * the new scan results become available.
         */
-       wpa_s->scan_res_handler = wpas_p2p_scan_res_join;
        ret = wpa_drv_scan(wpa_s, &params);
+       if (!ret)
+               wpa_s->scan_res_handler = wpas_p2p_scan_res_join;
 
        wpabuf_free(ies);
 
@@ -2780,13 +3021,24 @@ static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx)
 }
 
 
+static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+       wpas_p2p_join_scan_req(wpa_s, 0);
+}
+
+
 static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr,
-                        const u8 *dev_addr, enum p2p_wps_method wps_method)
+                        const u8 *dev_addr, enum p2p_wps_method wps_method,
+                        int auto_join)
 {
        wpa_printf(MSG_DEBUG, "P2P: Request to join existing group (iface "
-                  MACSTR " dev " MACSTR ")",
-                  MAC2STR(iface_addr), MAC2STR(dev_addr));
+                  MACSTR " dev " MACSTR ")%s",
+                  MAC2STR(iface_addr), MAC2STR(dev_addr),
+                  auto_join ? " (auto_join)" : "");
 
+       wpa_s->p2p_auto_pd = 0;
+       wpa_s->p2p_auto_join = !!auto_join;
        os_memcpy(wpa_s->pending_join_iface_addr, iface_addr, ETH_ALEN);
        os_memcpy(wpa_s->pending_join_dev_addr, dev_addr, ETH_ALEN);
        wpa_s->pending_join_wps_method = wps_method;
@@ -2804,6 +3056,7 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
 {
        struct wpa_supplicant *group;
        struct p2p_go_neg_results res;
+       struct wpa_bss *bss;
 
        eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s, NULL);
        group = wpas_p2p_get_group_iface(wpa_s, 0, 0);
@@ -2816,11 +3069,19 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
        }
 
        group->p2p_in_provisioning = 1;
+       group->p2p_fallback_to_go_neg = wpa_s->p2p_fallback_to_go_neg;
 
        os_memset(&res, 0, sizeof(res));
        os_memcpy(res.peer_interface_addr, wpa_s->pending_join_iface_addr,
                  ETH_ALEN);
        res.wps_method = wpa_s->pending_join_wps_method;
+       bss = wpa_bss_get_bssid(wpa_s, wpa_s->pending_join_iface_addr);
+       if (bss) {
+               res.freq = bss->freq;
+               res.ssid_len = bss->ssid_len;
+               os_memcpy(res.ssid, bss->ssid, bss->ssid_len);
+       }
+
        if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
                wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel prior to "
                           "starting client");
@@ -2849,30 +3110,43 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
  * @peer_addr: Address of the peer P2P Device
  * @pin: PIN to use during provisioning or %NULL to indicate PBC mode
  * @persistent_group: Whether to create a persistent group
+ * @auto_join: Whether to select join vs. GO Negotiation automatically
  * @join: Whether to join an existing group (as a client) instead of starting
  *     Group Owner negotiation; @peer_addr is BSSID in that case
  * @auth: Whether to only authorize the connection instead of doing that and
  *     initiating Group Owner negotiation
  * @go_intent: GO Intent or -1 to use default
  * @freq: Frequency for the group or 0 for auto-selection
+ * @persistent_id: Persistent group credentials to use for forcing GO
+ *     parameters or -1 to generate new values (SSID/passphrase)
+ * @pd: Whether to send Provision Discovery prior to GO Negotiation as an
+ *     interoperability workaround when initiating group formation
  * Returns: 0 or new PIN (if pin was %NULL) on success, -1 on unspecified
  *     failure, -2 on failure due to channel not currently available,
  *     -3 if forced channel is not supported
  */
 int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                     const char *pin, enum p2p_wps_method wps_method,
-                    int persistent_group, int join, int auth, int go_intent,
-                    int freq)
+                    int persistent_group, int auto_join, int join, int auth,
+                    int go_intent, int freq, int persistent_id, int pd)
 {
        int force_freq = 0, oper_freq = 0;
        u8 bssid[ETH_ALEN];
        int ret = 0;
        enum wpa_driver_if_type iftype;
        const u8 *if_addr;
+       struct wpa_ssid *ssid = NULL;
 
        if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
                return -1;
 
+       if (persistent_id >= 0) {
+               ssid = wpa_config_get_network(wpa_s->conf, persistent_id);
+               if (ssid == NULL || ssid->disabled != 2 ||
+                   ssid->mode != WPAS_MODE_P2P_GO)
+                       return -1;
+       }
+
        if (go_intent < 0)
                go_intent = wpa_s->conf->p2p_go_intent;
 
@@ -2880,6 +3154,12 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                wpa_s->p2p_long_listen = 0;
 
        wpa_s->p2p_wps_method = wps_method;
+       wpa_s->p2p_persistent_group = !!persistent_group;
+       wpa_s->p2p_persistent_id = persistent_id;
+       wpa_s->p2p_go_intent = go_intent;
+       wpa_s->p2p_connect_freq = freq;
+       wpa_s->p2p_fallback_to_go_neg = 0;
+       wpa_s->p2p_pd_before_go_neg = !!pd;
 
        if (pin)
                os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
@@ -2892,7 +3172,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
        } else
                wpa_s->p2p_pin[0] = '\0';
 
-       if (join) {
+       if (join || auto_join) {
                u8 iface_addr[ETH_ALEN], dev_addr[ETH_ALEN];
                if (auth) {
                        wpa_printf(MSG_DEBUG, "P2P: Authorize invitation to "
@@ -2908,8 +3188,15 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                        p2p_get_dev_addr(wpa_s->global->p2p, peer_addr,
                                         dev_addr);
                }
-               if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method) <
-                   0)
+               if (auto_join) {
+                       os_get_time(&wpa_s->p2p_auto_started);
+                       wpa_printf(MSG_DEBUG, "P2P: Auto join started at "
+                                  "%ld.%06ld",
+                                  wpa_s->p2p_auto_started.sec,
+                                  wpa_s->p2p_auto_started.usec);
+               }
+               if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method,
+                                 auto_join) < 0)
                        return -1;
                return ret;
        }
@@ -2982,14 +3269,15 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
        if (auth) {
                if (wpas_p2p_auth_go_neg(wpa_s, peer_addr, wps_method,
                                         go_intent, if_addr,
-                                        force_freq, persistent_group) < 0)
+                                        force_freq, persistent_group, ssid) <
+                   0)
                        return -1;
                return ret;
        }
 
        if (wpas_p2p_start_go_neg(wpa_s, peer_addr, wps_method,
                                  go_intent, if_addr, force_freq,
-                                 persistent_group) < 0) {
+                                 persistent_group, ssid) < 0) {
                if (wpa_s->create_p2p_iface)
                        wpas_p2p_remove_pending_group_interface(wpa_s);
                return -1;
@@ -3147,7 +3435,18 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
                wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 5 GHz "
                           "channel %d MHz", params->freq);
        } else {
-               params->freq = 2412;
+               int chan;
+               for (chan = 0; chan < 11; chan++) {
+                       params->freq = 2412 + chan * 5;
+                       if (!wpas_p2p_disallowed_freq(wpa_s->global,
+                                                     params->freq))
+                               break;
+               }
+               if (chan == 11) {
+                       wpa_printf(MSG_DEBUG, "P2P: No 2.4 GHz channel "
+                                  "allowed");
+                       return -1;
+               }
                wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz (no preference "
                           "known)", params->freq);
        }
@@ -3270,6 +3569,13 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
 
        if (wpas_p2p_init_go_params(wpa_s, &params, freq))
                return -1;
+       if (params.freq &&
+           !p2p_supported_freq(wpa_s->global->p2p, params.freq)) {
+               wpa_printf(MSG_DEBUG, "P2P: The selected channel for GO "
+                          "(%u MHz) is not supported for P2P uses",
+                          params.freq);
+               return -1;
+       }
        p2p_go_params(wpa_s->global->p2p, &params);
        params.persistent_group = persistent_group;
 
@@ -3346,6 +3652,8 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
        /* Make sure we are not running find during connection establishment */
        wpas_p2p_stop_find(wpa_s);
 
+       wpa_s->p2p_fallback_to_go_neg = 0;
+
        if (ssid->mode == WPAS_MODE_INFRA)
                return wpas_start_p2p_client(wpa_s, ssid, addr_allocated);
 
@@ -3409,18 +3717,15 @@ static void wpas_p2p_idle_update(void *ctx, int idle)
        if (!wpa_s->ap_iface)
                return;
        wpa_printf(MSG_DEBUG, "P2P: GO - group %sidle", idle ? "" : "not ");
-       if (idle) {
-               wpa_printf(MSG_DEBUG,"Calling set group idle time out from idle_update");
+       if (idle)
                wpas_p2p_set_group_idle_timeout(wpa_s);
-       }
        else
                eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
 }
 
 
 struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
-                                      int persistent_group,
-                                      int group_formation)
+                                      struct wpa_ssid *ssid)
 {
        struct p2p_group *group;
        struct p2p_group_config *cfg;
@@ -3434,9 +3739,9 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
        if (cfg == NULL)
                return NULL;
 
-       if (persistent_group && wpa_s->conf->persistent_reconnect)
+       if (ssid->p2p_persistent_group && wpa_s->conf->persistent_reconnect)
                cfg->persistent_group = 2;
-       else if (persistent_group)
+       else if (ssid->p2p_persistent_group)
                cfg->persistent_group = 1;
        os_memcpy(cfg->interface_addr, wpa_s->own_addr, ETH_ALEN);
        if (wpa_s->max_stations &&
@@ -3444,6 +3749,8 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
                cfg->max_clients = wpa_s->max_stations;
        else
                cfg->max_clients = wpa_s->conf->max_num_sta;
+       os_memcpy(cfg->ssid, ssid->ssid, ssid->ssid_len);
+       cfg->ssid_len = ssid->ssid_len;
        cfg->cb_ctx = wpa_s;
        cfg->ie_update = wpas_p2p_ie_update;
        cfg->idle_update = wpas_p2p_idle_update;
@@ -3451,7 +3758,7 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
        group = p2p_group_init(wpa_s->global->p2p, cfg);
        if (group == NULL)
                os_free(cfg);
-       if (!group_formation)
+       if (ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION)
                p2p_group_notif_formation_done(group);
        wpa_s->p2p_group = group;
        return group;
@@ -3461,17 +3768,36 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
 void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                          int registrar)
 {
+       struct wpa_ssid *ssid = wpa_s->current_ssid;
+
        if (!wpa_s->p2p_in_provisioning) {
                wpa_printf(MSG_DEBUG, "P2P: Ignore WPS success event - P2P "
                           "provisioning not in progress");
                return;
        }
 
-       /* Clear any stored provisioning info */
-       p2p_clear_provisioning_info(wpa_s->global->p2p, peer_addr);
+       if (ssid && ssid->mode == WPAS_MODE_INFRA) {
+               u8 go_dev_addr[ETH_ALEN];
+               os_memcpy(go_dev_addr, wpa_s->bssid, ETH_ALEN);
+               wpas_p2p_persistent_group(wpa_s, go_dev_addr, ssid->ssid,
+                                         ssid->ssid_len);
+               /* Clear any stored provisioning info */
+               p2p_clear_provisioning_info(wpa_s->global->p2p, go_dev_addr);
+       }
 
        eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent,
                             NULL);
+       if (ssid && ssid->mode == WPAS_MODE_INFRA) {
+               /*
+                * Use a separate timeout for initial data connection to
+                * complete to allow the group to be removed automatically if
+                * something goes wrong in this step before the P2P group idle
+                * timeout mechanism is taken into use.
+                */
+               eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0,
+                                      wpas_p2p_group_formation_timeout,
+                                      wpa_s->parent, NULL);
+       }
        if (wpa_s->global->p2p)
                p2p_wps_success_cb(wpa_s->global->p2p, peer_addr);
        else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
@@ -3492,7 +3818,7 @@ void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
        if (wpa_s->go_params) {
                p2p_clear_provisioning_info(
                        wpa_s->global->p2p,
-                       wpa_s->go_params->peer_interface_addr);
+                       wpa_s->go_params->peer_device_addr);
        }
 
        wpas_notify_p2p_wps_failed(wpa_s, fail);
@@ -3500,10 +3826,13 @@ void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
 
 
 int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
-                      const char *config_method, int join)
+                      const char *config_method,
+                      enum wpas_p2p_prov_disc_use use)
 {
        u16 config_methods;
 
+       wpa_s->p2p_fallback_to_go_neg = 0;
+       wpa_s->pending_pd_use = NORMAL_PD;
        if (os_strncmp(config_method, "display", 7) == 0)
                config_methods = WPS_CONFIG_DISPLAY;
        else if (os_strncmp(config_method, "keypad", 6) == 0)
@@ -3516,16 +3845,35 @@ int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                return -1;
        }
 
+       if (use == WPAS_P2P_PD_AUTO) {
+               os_memcpy(wpa_s->pending_join_dev_addr, peer_addr, ETH_ALEN);
+               wpa_s->pending_pd_config_methods = config_methods;
+               wpa_s->p2p_auto_pd = 1;
+               wpa_s->p2p_auto_join = 0;
+               wpa_s->pending_pd_before_join = 0;
+               wpa_s->auto_pd_scan_retry = 0;
+               wpas_p2p_stop_find(wpa_s);
+               wpa_s->p2p_join_scan_count = 0;
+               os_get_time(&wpa_s->p2p_auto_started);
+               wpa_printf(MSG_DEBUG, "P2P: Auto PD started at %ld.%06ld",
+                          wpa_s->p2p_auto_started.sec,
+                          wpa_s->p2p_auto_started.usec);
+               wpas_p2p_join_scan(wpa_s, NULL);
+               return 0;
+       }
+
        if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
                return wpa_drv_p2p_prov_disc_req(wpa_s, peer_addr,
-                                                config_methods, join);
+                                                config_methods,
+                                                use == WPAS_P2P_PD_FOR_JOIN);
        }
 
        if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
                return -1;
 
        return p2p_prov_disc_req(wpa_s->global->p2p, peer_addr,
-                                config_methods, join, 0);
+                                config_methods, use == WPAS_P2P_PD_FOR_JOIN,
+                                0);
 }
 
 
@@ -3559,7 +3907,8 @@ int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
        if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
                return wpa_drv_p2p_find(wpa_s, timeout, type);
 
-       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+       if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL ||
+           wpa_s->p2p_in_provisioning)
                return -1;
 
        wpa_supplicant_cancel_sched_scan(wpa_s);
@@ -3661,15 +4010,27 @@ int wpas_p2p_assoc_req_ie(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
 
 int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr,
                          const u8 *dst, const u8 *bssid,
-                         const u8 *ie, size_t ie_len)
+                         const u8 *ie, size_t ie_len, int ssi_signal)
 {
        if (wpa_s->global->p2p_disabled)
                return 0;
        if (wpa_s->global->p2p == NULL)
                return 0;
 
-       return p2p_probe_req_rx(wpa_s->global->p2p, addr, dst, bssid,
-                               ie, ie_len);
+       switch (p2p_probe_req_rx(wpa_s->global->p2p, addr, dst, bssid,
+                                ie, ie_len)) {
+       case P2P_PREQ_NOT_P2P:
+               wpas_notify_preq(wpa_s, addr, dst, bssid, ie, ie_len,
+                                ssi_signal);
+               /* fall through */
+       case P2P_PREQ_MALFORMED:
+       case P2P_PREQ_NOT_LISTEN:
+       case P2P_PREQ_NOT_PROCESSED:
+       default: /* make gcc happy */
+               return 0;
+       case P2P_PREQ_PROCESSED:
+               return 1;
+       }
 }
 
 
@@ -3840,6 +4201,11 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
        int persistent;
        int freq;
 
+       if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION) {
+               eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+                                    wpa_s->parent, NULL);
+       }
+
        if (!wpa_s->show_group_started || !ssid)
                return;
 
@@ -3936,18 +4302,20 @@ static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx)
                return;
        }
 
-       wpa_printf(MSG_DEBUG, "P2P: Group idle timeout reached - terminate %d"
-                  "group",wpa_s->conf->p2p_group_idle);
+       wpa_printf(MSG_DEBUG, "P2P: Group idle timeout reached - terminate "
+                  "group");
        wpa_s->removal_reason = P2P_GROUP_REMOVAL_IDLE_TIMEOUT;
-       wpas_p2p_group_delete(wpa_s);
+       wpas_p2p_group_delete(wpa_s, 0);
 }
 
 
 static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s)
 {
-       unsigned int timeout;
+       int timeout;
+
+       if (eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0)
+               wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout");
 
-       eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
        if (wpa_s->current_ssid == NULL || !wpa_s->current_ssid->p2p_group)
                return;
 
@@ -3959,6 +4327,37 @@ static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s)
        if (timeout == 0)
                return;
 
+       if (timeout < 0) {
+               if (wpa_s->current_ssid->mode == WPAS_MODE_INFRA)
+                       timeout = 0; /* special client mode no-timeout */
+               else
+                       return;
+       }
+
+       if (wpa_s->p2p_in_provisioning) {
+               /*
+                * Use the normal group formation timeout during the
+                * provisioning phase to avoid terminating this process too
+                * early due to group idle timeout.
+                */
+               wpa_printf(MSG_DEBUG, "P2P: Do not use P2P group idle timeout "
+                          "during provisioning");
+               return;
+       }
+
+       if (wpa_s->show_group_started) {
+               /*
+                * Use the normal group formation timeout between the end of
+                * the provisioning phase and completion of 4-way handshake to
+                * avoid terminating this process too early due to group idle
+                * timeout.
+                */
+               wpa_printf(MSG_DEBUG, "P2P: Do not use P2P group idle timeout "
+                          "while waiting for initial 4-way handshake to "
+                          "complete");
+               return;
+       }
+
        wpa_printf(MSG_DEBUG, "P2P: Set P2P group idle timeout to %u seconds",
                   timeout);
        eloop_register_timeout(timeout, 0, wpas_p2p_group_idle_timeout,
@@ -3967,26 +4366,42 @@ static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s)
 
 
 void wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
-                          u16 reason_code, const u8 *ie, size_t ie_len)
+                          u16 reason_code, const u8 *ie, size_t ie_len,
+                          int locally_generated)
 {
        if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
                return;
        if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
                return;
 
-       p2p_deauth_notif(wpa_s->global->p2p, bssid, reason_code, ie, ie_len);
+       if (!locally_generated)
+               p2p_deauth_notif(wpa_s->global->p2p, bssid, reason_code, ie,
+                                ie_len);
+
+       if (reason_code == WLAN_REASON_DEAUTH_LEAVING && !locally_generated &&
+           wpa_s->current_ssid &&
+           wpa_s->current_ssid->p2p_group &&
+           wpa_s->current_ssid->mode == WPAS_MODE_INFRA) {
+               wpa_printf(MSG_DEBUG, "P2P: GO indicated that the P2P Group "
+                          "session is ending");
+               wpa_s->removal_reason = P2P_GROUP_REMOVAL_GO_ENDING_SESSION;
+               wpas_p2p_group_delete(wpa_s, 0);
+       }
 }
 
 
 void wpas_p2p_disassoc_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
-                            u16 reason_code, const u8 *ie, size_t ie_len)
+                            u16 reason_code, const u8 *ie, size_t ie_len,
+                            int locally_generated)
 {
        if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
                return;
        if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
                return;
 
-       p2p_disassoc_notif(wpa_s->global->p2p, bssid, reason_code, ie, ie_len);
+       if (!locally_generated)
+               p2p_disassoc_notif(wpa_s->global->p2p, bssid, reason_code, ie,
+                                  ie_len);
 }
 
 
@@ -4102,6 +4517,14 @@ void wpas_p2p_update_config(struct wpa_supplicant *wpa_s)
                        wpa_printf(MSG_ERROR, "P2P: Own oper channel update "
                                   "failed: %d", ret);
        }
+
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_PREF_CHAN) {
+               if (p2p_set_pref_chan(p2p, wpa_s->conf->num_p2p_pref_chan,
+                                     wpa_s->conf->p2p_pref_chan) < 0) {
+                       wpa_printf(MSG_ERROR, "P2P: Preferred channel list "
+                                  "update failed");
+               }
+       }
 }
 
 
@@ -4200,8 +4623,9 @@ void wpas_p2p_notif_connected(struct wpa_supplicant *wpa_s)
                wpas_p2p_disable_cross_connect(wpa_s);
        else
                wpas_p2p_enable_cross_connect(wpa_s);
-       if (!wpa_s->ap_iface)
-               eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
+       if (!wpa_s->ap_iface &&
+           eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0)
+               wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout");
 }
 
 
@@ -4211,10 +4635,7 @@ void wpas_p2p_notif_disconnected(struct wpa_supplicant *wpa_s)
        if (!wpa_s->ap_iface &&
            !eloop_is_timeout_registered(wpas_p2p_group_idle_timeout,
                                         wpa_s, NULL))
-       {
-               wpa_printf(MSG_DEBUG,"Calling set grouple idle_timeout from notif_disconnected");
                wpas_p2p_set_group_idle_timeout(wpa_s);
-       }
 }
 
 
@@ -4316,6 +4737,7 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s)
                wpa_printf(MSG_DEBUG, "P2P: Unauthorize pending GO Neg peer "
                           MACSTR, MAC2STR(peer));
                p2p_unauthorize(global->p2p, peer);
+               found = 1;
        }
 
        wpas_p2p_stop_find(wpa_s);
@@ -4331,7 +4753,7 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s)
                        found = 1;
                        eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
                                             wpa_s->parent, NULL);
-                       wpas_p2p_group_delete(wpa_s);
+                       wpas_p2p_group_delete(wpa_s, 0);
                        break;
                }
        }
@@ -4353,7 +4775,7 @@ void wpas_p2p_interface_unavailable(struct wpa_supplicant *wpa_s)
        wpa_printf(MSG_DEBUG, "P2P: Remove group due to driver resource not "
                   "being available anymore");
        wpa_s->removal_reason = P2P_GROUP_REMOVAL_UNAVAILABLE;
-       wpas_p2p_group_delete(wpa_s);
+       wpas_p2p_group_delete(wpa_s, 0);
 }
 
 
@@ -4400,7 +4822,7 @@ int wpas_p2p_disconnect(struct wpa_supplicant *wpa_s)
                return -1;
 
        wpa_s->removal_reason = P2P_GROUP_REMOVAL_REQUESTED;
-       wpas_p2p_group_delete(wpa_s);
+       wpas_p2p_group_delete(wpa_s, 0);
 
        return 0;
 }
@@ -4417,20 +4839,22 @@ int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s)
 
 void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s,
                              struct wpa_ssid *ssid)
-
 {
        if (wpa_s->p2p_in_provisioning && ssid->p2p_group &&
            eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
                                 wpa_s->parent, NULL) > 0) {
+               /**
+                * Remove the network by scheduling the group formation
+                * timeout to happen immediately. The teardown code
+                * needs to be scheduled to run asynch later so that we
+                * don't delete data from under ourselves unexpectedly.
+                * Calling wpas_p2p_group_formation_timeout directly
+                * causes a series of crashes in WPS failure scenarios.
+                */
                wpa_printf(MSG_DEBUG, "P2P: Canceled group formation due to "
                           "P2P group network getting removed");
-#ifdef ANDROID_P2P
-               /* Give time for any Pending WPS Frame exchange */
-               eloop_register_timeout(5, 0, wpas_p2p_group_formation_timeout,
-                       wpa_s->parent, NULL);
-#else
-               wpas_p2p_group_formation_timeout(wpa_s->parent, NULL);
-#endif
+               eloop_register_timeout(0, 0, wpas_p2p_group_formation_timeout,
+                                      wpa_s->parent, NULL);
        }
 }
 
@@ -4473,6 +4897,43 @@ void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
        wpas_p2p_add_persistent_group_client(wpa_s, addr);
 }
 
+
+static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
+                                       int group_added)
+{
+       struct wpa_supplicant *group = wpa_s;
+       eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s, NULL);
+       if (wpa_s->global->p2p_group_formation)
+               group = wpa_s->global->p2p_group_formation;
+       wpa_s = wpa_s->parent;
+       offchannel_send_action_done(wpa_s);
+       if (group_added)
+               wpas_p2p_group_delete(group, 1);
+       wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Fall back to GO Negotiation");
+       wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr, wpa_s->p2p_pin,
+                        wpa_s->p2p_wps_method, wpa_s->p2p_persistent_group, 0,
+                        0, 0, wpa_s->p2p_go_intent, wpa_s->p2p_connect_freq,
+                        wpa_s->p2p_persistent_id,
+                        wpa_s->p2p_pd_before_go_neg);
+}
+
+
+int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s)
+{
+       if (!wpa_s->p2p_fallback_to_go_neg ||
+           wpa_s->p2p_in_provisioning <= 5)
+               return 0;
+
+       if (wpas_p2p_peer_go(wpa_s, wpa_s->pending_join_dev_addr) > 0)
+               return 0; /* peer operating as a GO */
+
+       wpa_dbg(wpa_s, MSG_DEBUG, "P2P: GO not found for p2p_connect-auto - "
+               "fallback to GO Negotiation");
+       wpas_p2p_fallback_to_go_neg(wpa_s, 1);
+
+       return 1;
+}
+
 #ifdef ANDROID_P2P
 int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq)
 {
@@ -4503,7 +4964,7 @@ int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq)
                                wpa_printf(MSG_DEBUG, "P2P: Removing P2P connection due to Single channel"
                                                "concurrent mode frequency conflict");
                                iface->removal_reason = P2P_GROUP_REMOVAL_FREQ_CONFLICT;
-                               wpas_p2p_group_delete(iface);
+                               wpas_p2p_group_delete(iface, 0);
                        } else {
                                /* Existing connection has the priority. Disable the newly
                  * selected network and let the application know about it.
index 05c648a..24fb81e 100644 (file)
@@ -19,8 +19,9 @@ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s);
 void wpas_p2p_deinit_global(struct wpa_global *global);
 int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                     const char *pin, enum p2p_wps_method wps_method,
-                    int persistent_group, int join, int auth, int go_intent,
-                    int freq);
+                    int persistent_group, int auto_join, int join,
+                    int auth, int go_intent, int freq, int persistent_id,
+                    int pd);
 void wpas_p2p_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
                                   unsigned int freq, unsigned int duration);
 void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
@@ -36,12 +37,17 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
                                  struct wpa_ssid *ssid, int addr_allocated,
                                  int freq);
 struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
-                                      int persistent_group,
-                                      int group_formation);
+                                      struct wpa_ssid *ssid);
 void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                          int registrar);
+enum wpas_p2p_prov_disc_use {
+       WPAS_P2P_PD_FOR_GO_NEG,
+       WPAS_P2P_PD_FOR_JOIN,
+       WPAS_P2P_PD_AUTO
+};
 int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
-                      const char *config_method, int join);
+                      const char *config_method,
+                      enum wpas_p2p_prov_disc_use use);
 void wpas_send_action_tx_status(struct wpa_supplicant *wpa_s, const u8 *dst,
                                const u8 *data, size_t data_len,
                                enum p2p_send_action_result result);
@@ -58,7 +64,8 @@ int wpas_p2p_assoc_req_ie(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
                          u8 *buf, size_t len, int p2p_group);
 int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr,
                          const u8 *dst, const u8 *bssid,
-                         const u8 *ie, size_t ie_len);
+                         const u8 *ie, size_t ie_len,
+                         int ssi_signal);
 void wpas_p2p_rx_action(struct wpa_supplicant *wpa_s, const u8 *da,
                        const u8 *sa, const u8 *bssid,
                        u8 category, const u8 *data, size_t len, int freq);
@@ -108,9 +115,11 @@ int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1,
 int wpas_p2p_ext_listen(struct wpa_supplicant *wpa_s, unsigned int period,
                        unsigned int interval);
 void wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
-                          u16 reason_code, const u8 *ie, size_t ie_len);
+                          u16 reason_code, const u8 *ie, size_t ie_len,
+                          int locally_generated);
 void wpas_p2p_disassoc_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
-                            u16 reason_code, const u8 *ie, size_t ie_len);
+                            u16 reason_code, const u8 *ie, size_t ie_len,
+                            int locally_generated);
 void wpas_p2p_update_config(struct wpa_supplicant *wpa_s);
 int wpas_p2p_set_noa(struct wpa_supplicant *wpa_s, u8 count, int start,
                     int duration);
@@ -135,5 +144,6 @@ struct wpa_ssid * wpas_p2p_get_persistent(struct wpa_supplicant *wpa_s,
                                          size_t ssid_len);
 void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
                                       const u8 *addr);
+int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s);
 
 #endif /* P2P_SUPPLICANT_H */
index 5aee7ff..8df21d9 100644 (file)
@@ -17,6 +17,7 @@
 #include "wps_supplicant.h"
 #include "p2p_supplicant.h"
 #include "p2p/p2p.h"
+#include "hs20_supplicant.h"
 #include "notify.h"
 #include "bss.h"
 #include "scan.h"
@@ -79,12 +80,12 @@ static int wpas_wps_in_use(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_WPS */
 
 
-int wpa_supplicant_enabled_networks(struct wpa_config *conf)
+int wpa_supplicant_enabled_networks(struct wpa_supplicant *wpa_s)
 {
-       struct wpa_ssid *ssid = conf->ssid;
+       struct wpa_ssid *ssid = wpa_s->conf->ssid;
        int count = 0;
        while (ssid) {
-               if (!ssid->disabled)
+               if (!wpas_network_disabled(wpa_s, ssid))
                        count++;
                ssid = ssid->next;
        }
@@ -96,7 +97,7 @@ static void wpa_supplicant_assoc_try(struct wpa_supplicant *wpa_s,
                                     struct wpa_ssid *ssid)
 {
        while (ssid) {
-               if (!ssid->disabled)
+               if (!wpas_network_disabled(wpa_s, ssid))
                        break;
                ssid = ssid->next;
        }
@@ -405,7 +406,9 @@ wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s,
 
        if (wps) {
                struct wpabuf *wps_ie;
-               wps_ie = wps_build_probe_req_ie(wps == 2, &wpa_s->wps->dev,
+               wps_ie = wps_build_probe_req_ie(wps == 2 ? DEV_PW_PUSHBUTTON :
+                                               DEV_PW_DEFAULT,
+                                               &wpa_s->wps->dev,
                                                wpa_s->wps->uuid, req_type,
                                                0, NULL);
                if (wps_ie) {
@@ -434,8 +437,9 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
        struct wpa_supplicant *wpa_s = eloop_ctx;
        struct wpa_ssid *ssid;
        int scan_req = 0, ret;
-       struct wpabuf *extra_ie;
+       struct wpabuf *extra_ie = NULL;
        struct wpa_driver_scan_params params;
+       struct wpa_driver_scan_params *scan_params;
        size_t max_ssids;
        enum wpa_states prev_state;
 
@@ -449,7 +453,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
                return;
        }
 
-       if (!wpa_supplicant_enabled_networks(wpa_s->conf) &&
+       if (!wpa_supplicant_enabled_networks(wpa_s) &&
            !wpa_s->scan_req) {
                wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan");
                wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
@@ -501,6 +505,14 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
            wpa_s->wpa_state == WPA_INACTIVE)
                wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
 
+       /*
+        * If autoscan has set its own scanning parameters
+        */
+       if (wpa_s->autoscan_params != NULL) {
+               scan_params = wpa_s->autoscan_params;
+               goto scan;
+       }
+
        if (scan_req != 2 && wpa_s->connect_without_scan) {
                for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
                        if (ssid == wpa_s->connect_without_scan)
@@ -515,6 +527,18 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
                }
        }
 
+#ifdef CONFIG_P2P
+       if ((wpa_s->p2p_in_provisioning || wpa_s->show_group_started) &&
+           wpa_s->go_params) {
+               wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during "
+                          "P2P group formation");
+               params.ssids[0].ssid = wpa_s->go_params->ssid;
+               params.ssids[0].ssid_len = wpa_s->go_params->ssid_len;
+               params.num_ssids = 1;
+               goto ssid_list_set;
+       }
+#endif /* CONFIG_P2P */
+
        /* Find the starting point from which to continue scanning */
        ssid = wpa_s->conf->ssid;
        if (wpa_s->prev_scan_ssid != WILDCARD_SSID_SCAN) {
@@ -546,7 +570,8 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
                if (ssid == NULL && max_ssids > 1)
                        ssid = wpa_s->conf->ssid;
                while (ssid) {
-                       if (!ssid->disabled && ssid->scan_ssid) {
+                       if (!wpas_network_disabled(wpa_s, ssid) &&
+                           ssid->scan_ssid) {
                                wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID",
                                                  ssid->ssid, ssid->ssid_len);
                                params.ssids[params.num_ssids].ssid =
@@ -566,7 +591,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
                }
 
                for (tssid = wpa_s->conf->ssid; tssid; tssid = tssid->next) {
-                       if (tssid->disabled)
+                       if (wpas_network_disabled(wpa_s, tssid))
                                continue;
                        if ((params.freqs || !freqs_set) && tssid->scan_freq) {
                                int_array_concat(&params.freqs,
@@ -612,10 +637,18 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
                wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for wildcard "
                        "SSID");
        }
+#ifdef CONFIG_P2P
+ssid_list_set:
+#endif /* CONFIG_P2P */
 
        wpa_supplicant_optimize_freqs(wpa_s, &params);
        extra_ie = wpa_supplicant_extra_ies(wpa_s, &params);
 
+#ifdef CONFIG_HS20
+       if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 6) == 0)
+               wpas_hs20_add_indication(extra_ie);
+#endif /* CONFIG_HS20 */
+
        if (params.freqs == NULL && wpa_s->next_scan_freqs) {
                wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously "
                        "generated frequency list");
@@ -632,7 +665,8 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
        }
 
 #ifdef CONFIG_P2P
-       if (wpa_s->p2p_in_provisioning) {
+       if (wpa_s->p2p_in_provisioning ||
+           (wpa_s->show_group_started && wpa_s->go_params)) {
                /*
                 * The interface may not yet be in P2P mode, so we have to
                 * explicitly request P2P probe to disable CCK rates.
@@ -641,7 +675,10 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
        }
 #endif /* CONFIG_P2P */
 
-       ret = wpa_supplicant_trigger_scan(wpa_s, &params);
+       scan_params = &params;
+
+scan:
+       ret = wpa_supplicant_trigger_scan(wpa_s, scan_params);
 
        wpabuf_free(extra_ie);
        os_free(params.freqs);
@@ -679,7 +716,8 @@ void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
                struct wpa_ssid *ssid = wpa_s->conf->ssid;
 
                while (ssid) {
-                       if (!ssid->disabled && ssid->scan_ssid)
+                       if (!wpas_network_disabled(wpa_s, ssid) &&
+                           ssid->scan_ssid)
                                break;
                        ssid = ssid->next;
                }
@@ -730,8 +768,9 @@ int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s,
 int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
 {
        struct wpa_driver_scan_params params;
+       struct wpa_driver_scan_params *scan_params;
        enum wpa_states prev_state;
-       struct wpa_ssid *ssid;
+       struct wpa_ssid *ssid = NULL;
        struct wpabuf *wps_ie = NULL;
        int ret;
        unsigned int max_sched_scan_ssids;
@@ -745,7 +784,7 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
                max_sched_scan_ssids = WPAS_MAX_SCAN_SSIDS;
        else
                max_sched_scan_ssids = wpa_s->max_sched_scan_ssids;
-       if (max_sched_scan_ssids < 1)
+       if (max_sched_scan_ssids < 1 || wpa_s->conf->disable_scan_offload)
                return -1;
 
        if (wpa_s->sched_scanning) {
@@ -755,11 +794,27 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
 
        need_ssids = 0;
        for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
-               if (!ssid->disabled && !ssid->scan_ssid) {
+               if (!wpas_network_disabled(wpa_s, ssid) && !ssid->scan_ssid) {
                        /* Use wildcard SSID to find this network */
                        wildcard = 1;
-               } else if (!ssid->disabled && ssid->ssid_len)
+               } else if (!wpas_network_disabled(wpa_s, ssid) &&
+                          ssid->ssid_len)
                        need_ssids++;
+
+#ifdef CONFIG_WPS
+               if (!wpas_network_disabled(wpa_s, ssid) &&
+                   ssid->key_mgmt == WPA_KEY_MGMT_WPS) {
+                       /*
+                        * Normal scan is more reliable and faster for WPS
+                        * operations and since these are for short periods of
+                        * time, the benefit of trying to use sched_scan would
+                        * be limited.
+                        */
+                       wpa_dbg(wpa_s, MSG_DEBUG, "Use normal scan instead of "
+                               "sched_scan for WPS");
+                       return -1;
+               }
+#endif /* CONFIG_WPS */
        }
        if (wildcard)
                need_ssids++;
@@ -793,6 +848,11 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
                wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
 #endif
 
+       if (wpa_s->autoscan_params != NULL) {
+               scan_params = wpa_s->autoscan_params;
+               goto scan;
+       }
+
        /* Find the starting point from which to continue scanning */
        ssid = wpa_s->conf->ssid;
        if (wpa_s->prev_sched_ssid) {
@@ -808,7 +868,8 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
        if (!ssid || !wpa_s->prev_sched_ssid) {
                wpa_dbg(wpa_s, MSG_DEBUG, "Beginning of SSID list");
 
-               wpa_s->sched_scan_interval = 10;
+               if (wpa_s->sched_scan_interval == 0)
+                       wpa_s->sched_scan_interval = 10;
                wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2;
                wpa_s->first_sched_scan = 1;
                ssid = wpa_s->conf->ssid;
@@ -821,7 +882,7 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
        }
 
        while (ssid) {
-               if (ssid->disabled)
+               if (wpas_network_disabled(wpa_s, ssid))
                        goto next;
 
                if (params.num_filter_ssids < wpa_s->max_match_sets &&
@@ -855,6 +916,11 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
                        params.num_ssids++;
                        if (params.num_ssids >= max_sched_scan_ssids) {
                                wpa_s->prev_sched_ssid = ssid;
+                               do {
+                                       ssid = ssid->next;
+                               } while (ssid &&
+                                        (wpas_network_disabled(wpa_s, ssid) ||
+                                         !ssid->scan_ssid));
                                break;
                        }
                }
@@ -872,17 +938,20 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
        if (wpa_s->wps)
                wps_ie = wpa_supplicant_extra_ies(wpa_s, &params);
 
+       scan_params = &params;
+
+scan:
        if (ssid || !wpa_s->first_sched_scan) {
                wpa_dbg(wpa_s, MSG_DEBUG,
-                       "Starting sched scan: interval %d (no timeout)",
-                       wpa_s->sched_scan_interval);
-       } else {
-               wpa_dbg(wpa_s, MSG_DEBUG,
                        "Starting sched scan: interval %d timeout %d",
                        wpa_s->sched_scan_interval, wpa_s->sched_scan_timeout);
+       } else {
+               wpa_dbg(wpa_s, MSG_DEBUG,
+                       "Starting sched scan: interval %d (no timeout)",
+                       wpa_s->sched_scan_interval);
        }
 
-       ret = wpa_supplicant_start_sched_scan(wpa_s, &params,
+       ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params,
                                              wpa_s->sched_scan_interval);
        wpabuf_free(wps_ie);
        os_free(params.filter_ssids);
@@ -1220,6 +1289,7 @@ static void dump_scan_res(struct wpa_scan_results *scan_res)
 
        for (i = 0; i < scan_res->num; i++) {
                struct wpa_scan_res *r = scan_res->res[i];
+               u8 *pos;
                if ((r->flags & (WPA_SCAN_LEVEL_DBM | WPA_SCAN_NOISE_INVALID))
                    == WPA_SCAN_LEVEL_DBM) {
                        int snr = r->level - r->noise;
@@ -1234,11 +1304,62 @@ static void dump_scan_res(struct wpa_scan_results *scan_res)
                                   MAC2STR(r->bssid), r->freq, r->qual,
                                   r->noise, r->level, r->flags);
                }
+               pos = (u8 *) (r + 1);
+               if (r->ie_len)
+                       wpa_hexdump(MSG_EXCESSIVE, "IEs", pos, r->ie_len);
+               pos += r->ie_len;
+               if (r->beacon_ie_len)
+                       wpa_hexdump(MSG_EXCESSIVE, "Beacon IEs",
+                                   pos, r->beacon_ie_len);
        }
 #endif /* CONFIG_NO_STDOUT_DEBUG */
 }
 
 
+int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s,
+                                     const u8 *bssid)
+{
+       size_t i;
+
+       if (wpa_s->bssid_filter == NULL)
+               return 1;
+
+       for (i = 0; i < wpa_s->bssid_filter_count; i++) {
+               if (os_memcmp(wpa_s->bssid_filter + i * ETH_ALEN, bssid,
+                             ETH_ALEN) == 0)
+                       return 1;
+       }
+
+       return 0;
+}
+
+
+static void filter_scan_res(struct wpa_supplicant *wpa_s,
+                           struct wpa_scan_results *res)
+{
+       size_t i, j;
+
+       if (wpa_s->bssid_filter == NULL)
+               return;
+
+       for (i = 0, j = 0; i < res->num; i++) {
+               if (wpa_supplicant_filter_bssid_match(wpa_s,
+                                                     res->res[i]->bssid)) {
+                       res->res[j++] = res->res[i];
+               } else {
+                       os_free(res->res[i]);
+                       res->res[i] = NULL;
+               }
+       }
+
+       if (res->num != j) {
+               wpa_printf(MSG_DEBUG, "Filtered out %d scan results",
+                          (int) (res->num - j));
+               res->num = j;
+       }
+}
+
+
 /**
  * wpa_supplicant_get_scan_results - Get scan results
  * @wpa_s: Pointer to wpa_supplicant data
@@ -1263,6 +1384,7 @@ wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
                wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results");
                return NULL;
        }
+       filter_scan_res(wpa_s, scan_res);
 
 #ifdef CONFIG_WPS
        if (wpas_wps_in_progress(wpa_s)) {
index b794105..b0ddf97 100644 (file)
@@ -9,7 +9,7 @@
 #ifndef SCAN_H
 #define SCAN_H
 
-int wpa_supplicant_enabled_networks(struct wpa_config *conf);
+int wpa_supplicant_enabled_networks(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec);
 int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s,
                                      int sec, int usec);
@@ -32,5 +32,7 @@ struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
                                             u32 vendor_type);
 struct wpabuf * wpa_scan_get_vendor_ie_multi_beacon(
        const struct wpa_scan_res *res, u32 vendor_type);
+int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s,
+                                     const u8 *bssid);
 
 #endif /* SCAN_H */
index 690f395..c7187e4 100644 (file)
 #include "bss.h"
 #include "scan.h"
 #include "sme.h"
+#include "hs20_supplicant.h"
 
 #define SME_AUTH_TIMEOUT 5
 #define SME_ASSOC_TIMEOUT 5
 
 static void sme_auth_timer(void *eloop_ctx, void *timeout_ctx);
 static void sme_assoc_timer(void *eloop_ctx, void *timeout_ctx);
+static void sme_obss_scan_timeout(void *eloop_ctx, void *timeout_ctx);
 #ifdef CONFIG_IEEE80211W
 static void sme_stop_sa_query(struct wpa_supplicant *wpa_s);
 #endif /* CONFIG_IEEE80211W */
@@ -221,6 +223,21 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
        }
 #endif /* CONFIG_P2P */
 
+#ifdef CONFIG_HS20
+       if (wpa_s->conf->hs20) {
+               struct wpabuf *hs20;
+               hs20 = wpabuf_alloc(20);
+               if (hs20) {
+                       wpas_hs20_add_indication(hs20);
+                       os_memcpy(wpa_s->sme.assoc_req_ie +
+                                 wpa_s->sme.assoc_req_ie_len,
+                                 wpabuf_head(hs20), wpabuf_len(hs20));
+                       wpa_s->sme.assoc_req_ie_len += wpabuf_len(hs20);
+                       wpabuf_free(hs20);
+               }
+       }
+#endif /* CONFIG_HS20 */
+
 #ifdef CONFIG_INTERWORKING
        if (wpa_s->conf->interworking) {
                u8 *pos = wpa_s->sme.assoc_req_ie;
@@ -315,6 +332,7 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
                    wpa_s->sme.auth_alg == data->auth.auth_type ||
                    wpa_s->current_ssid->auth_alg == WPA_AUTH_ALG_LEAP) {
                        wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+                       wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
                        return;
                }
 
@@ -371,6 +389,8 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
        params.ssid = wpa_s->sme.ssid;
        params.ssid_len = wpa_s->sme.ssid_len;
        params.freq = wpa_s->sme.freq;
+       params.bg_scan_period = wpa_s->current_ssid ?
+               wpa_s->current_ssid->bg_scan_period : -1;
        params.wpa_ie = wpa_s->sme.assoc_req_ie_len ?
                wpa_s->sme.assoc_req_ie : NULL;
        params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len;
@@ -429,6 +449,7 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
                wpa_msg(wpa_s, MSG_INFO, "SME: Association request to the "
                        "driver failed");
                wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+               wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
                os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
                return;
        }
@@ -604,6 +625,263 @@ void sme_deinit(struct wpa_supplicant *wpa_s)
 
        eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
        eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
+       eloop_cancel_timeout(sme_obss_scan_timeout, wpa_s, NULL);
+}
+
+
+static void sme_send_2040_bss_coex(struct wpa_supplicant *wpa_s,
+                                  const u8 *chan_list, u8 num_channels,
+                                  u8 num_intol)
+{
+       struct ieee80211_2040_bss_coex_ie *bc_ie;
+       struct ieee80211_2040_intol_chan_report *ic_report;
+       struct wpabuf *buf;
+
+       wpa_printf(MSG_DEBUG, "SME: Send 20/40 BSS Coexistence to " MACSTR,
+                  MAC2STR(wpa_s->bssid));
+
+       buf = wpabuf_alloc(2 + /* action.category + action_code */
+                          sizeof(struct ieee80211_2040_bss_coex_ie) +
+                          sizeof(struct ieee80211_2040_intol_chan_report) +
+                          num_channels);
+       if (buf == NULL)
+               return;
+
+       wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
+       wpabuf_put_u8(buf, WLAN_PA_20_40_BSS_COEX);
+
+       bc_ie = wpabuf_put(buf, sizeof(*bc_ie));
+       bc_ie->element_id = WLAN_EID_20_40_BSS_COEXISTENCE;
+       bc_ie->length = 1;
+       if (num_intol)
+               bc_ie->coex_param |= WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ;
+
+       if (num_channels > 0) {
+               ic_report = wpabuf_put(buf, sizeof(*ic_report));
+               ic_report->element_id = WLAN_EID_20_40_BSS_INTOLERANT;
+               ic_report->length = num_channels + 1;
+               ic_report->op_class = 0;
+               os_memcpy(wpabuf_put(buf, num_channels), chan_list,
+                         num_channels);
+       }
+
+       if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+                               wpa_s->own_addr, wpa_s->bssid,
+                               wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
+               wpa_msg(wpa_s, MSG_INFO,
+                       "SME: Failed to send 20/40 BSS Coexistence frame");
+       }
+
+       wpabuf_free(buf);
+}
+
+
+/**
+ * enum wpas_band - Frequency band
+ * @WPAS_BAND_2GHZ: 2.4 GHz ISM band
+ * @WPAS_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz)
+ */
+enum wpas_band {
+       WPAS_BAND_2GHZ,
+       WPAS_BAND_5GHZ,
+       WPAS_BAND_INVALID
+};
+
+/**
+ * freq_to_channel - Convert frequency into channel info
+ * @channel: Buffer for returning channel number
+ * Returns: Band (2 or 5 GHz)
+ */
+static enum wpas_band freq_to_channel(int freq, u8 *channel)
+{
+       enum wpas_band band = (freq <= 2484) ? WPAS_BAND_2GHZ : WPAS_BAND_5GHZ;
+       u8 chan = 0;
+
+       if (freq >= 2412 && freq <= 2472)
+               chan = (freq - 2407) / 5;
+       else if (freq == 2484)
+               chan = 14;
+       else if (freq >= 5180 && freq <= 5805)
+               chan = (freq - 5000) / 5;
+
+       *channel = chan;
+       return band;
+}
+
+
+int sme_proc_obss_scan(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_bss *bss;
+       const u8 *ie;
+       u16 ht_cap;
+       u8 chan_list[P2P_MAX_CHANNELS], channel;
+       u8 num_channels = 0, num_intol = 0, i;
+
+       if (!wpa_s->sme.sched_obss_scan)
+               return 0;
+
+       wpa_s->sme.sched_obss_scan = 0;
+       if (!wpa_s->current_bss || wpa_s->wpa_state != WPA_COMPLETED)
+               return 1;
+
+       /*
+        * Check whether AP uses regulatory triplet or channel triplet in
+        * country info. Right now the operating class of the BSS channel
+        * width trigger event is "unknown" (IEEE Std 802.11-2012 10.15.12),
+        * based on the assumption that operating class triplet is not used in
+        * beacon frame. If the First Channel Number/Operating Extension
+        * Identifier octet has a positive integer value of 201 or greater,
+        * then its operating class triplet.
+        *
+        * TODO: If Supported Operating Classes element is present in beacon
+        * frame, have to lookup operating class in Annex E and fill them in
+        * 2040 coex frame.
+        */
+       ie = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_COUNTRY);
+       if (ie && (ie[1] >= 6) && (ie[5] >= 201))
+               return 1;
+
+       os_memset(chan_list, 0, sizeof(chan_list));
+
+       dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+               /* Skip other band bss */
+               if (freq_to_channel(bss->freq, &channel) != WPAS_BAND_2GHZ)
+                       continue;
+
+               ie = wpa_bss_get_ie(bss, WLAN_EID_HT_CAP);
+               ht_cap = (ie && (ie[1] == 26)) ? WPA_GET_LE16(ie + 2) : 0;
+
+               if (!ht_cap || (ht_cap & HT_CAP_INFO_40MHZ_INTOLERANT)) {
+                       /* Check whether the channel is already considered */
+                       for (i = 0; i < num_channels; i++) {
+                               if (channel == chan_list[i])
+                                       break;
+                       }
+                       if (i != num_channels)
+                               continue;
+
+                       if (ht_cap & HT_CAP_INFO_40MHZ_INTOLERANT)
+                               num_intol++;
+
+                       chan_list[num_channels++] = channel;
+               }
+       }
+
+       sme_send_2040_bss_coex(wpa_s, chan_list, num_channels, num_intol);
+       return 1;
+}
+
+
+static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
+                                         u16 num_modes,
+                                         enum hostapd_hw_mode mode)
+{
+       u16 i;
+
+       for (i = 0; i < num_modes; i++) {
+               if (modes[i].mode == mode)
+                       return &modes[i];
+       }
+
+       return NULL;
+}
+
+
+static void wpa_setband_scan_freqs_list(struct wpa_supplicant *wpa_s,
+                                       enum hostapd_hw_mode band,
+                                       struct wpa_driver_scan_params *params)
+{
+       /* Include only supported channels for the specified band */
+       struct hostapd_hw_modes *mode;
+       int count, i;
+
+       mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band);
+       if (mode == NULL) {
+               /* No channels supported in this band - use empty list */
+               params->freqs = os_zalloc(sizeof(int));
+               return;
+       }
+
+       params->freqs = os_zalloc((mode->num_channels + 1) * sizeof(int));
+       if (params->freqs == NULL)
+               return;
+       for (count = 0, i = 0; i < mode->num_channels; i++) {
+               if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED)
+                       continue;
+               params->freqs[count++] = mode->channels[i].freq;
+       }
+}
+
+
+static void sme_obss_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+       struct wpa_driver_scan_params params;
+
+       if (!wpa_s->current_bss) {
+               wpa_printf(MSG_DEBUG, "SME OBSS: Ignore scan request");
+               return;
+       }
+
+       os_memset(&params, 0, sizeof(params));
+       wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, &params);
+       wpa_printf(MSG_DEBUG, "SME OBSS: Request an OBSS scan");
+
+       if (wpa_supplicant_trigger_scan(wpa_s, &params))
+               wpa_printf(MSG_DEBUG, "SME OBSS: Failed to trigger scan");
+       else
+               wpa_s->sme.sched_obss_scan = 1;
+       os_free(params.freqs);
+
+       eloop_register_timeout(wpa_s->sme.obss_scan_int, 0,
+                              sme_obss_scan_timeout, wpa_s, NULL);
+}
+
+
+void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable)
+{
+       const u8 *ie;
+       struct wpa_bss *bss = wpa_s->current_bss;
+       struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+       eloop_cancel_timeout(sme_obss_scan_timeout, wpa_s, NULL);
+       wpa_s->sme.sched_obss_scan = 0;
+       if (!enable)
+               return;
+
+       if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) || ssid == NULL ||
+           ssid->mode != IEEE80211_MODE_INFRA)
+               return; /* Not using station SME in wpa_supplicant */
+
+       if (!wpa_s->hw.modes ||
+           !(wpa_s->hw.modes->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+               return; /* Driver does not support HT40 */
+
+       if (bss == NULL || bss->freq < 2400 || bss->freq > 2500)
+               return; /* Not associated on 2.4 GHz band */
+
+       /* Check whether AP supports HT40 */
+       ie = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_HT_CAP);
+       if (!ie || ie[1] < 2 ||
+           !(WPA_GET_LE16(ie + 2) & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+               return; /* AP does not support HT40 */
+
+       ie = wpa_bss_get_ie(wpa_s->current_bss,
+                           WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS);
+       if (!ie || ie[1] < 14)
+               return; /* AP does not request OBSS scans */
+
+       wpa_s->sme.obss_scan_int = WPA_GET_LE16(ie + 6);
+       if (wpa_s->sme.obss_scan_int < 10) {
+               wpa_printf(MSG_DEBUG, "SME: Invalid OBSS Scan Interval %u "
+                          "replaced with the minimum 10 sec",
+                          wpa_s->sme.obss_scan_int);
+               wpa_s->sme.obss_scan_int = 10;
+       }
+       wpa_printf(MSG_DEBUG, "SME: OBSS Scan Interval %u sec",
+                  wpa_s->sme.obss_scan_int);
+       eloop_register_timeout(wpa_s->sme.obss_scan_int, 0,
+                              sme_obss_scan_timeout, wpa_s, NULL);
 }
 
 
index 33530bb..a7cc507 100644 (file)
@@ -35,6 +35,9 @@ void sme_disassoc_while_authenticating(struct wpa_supplicant *wpa_s,
                                       const u8 *prev_pending_bssid);
 void sme_deinit(struct wpa_supplicant *wpa_s);
 
+int sme_proc_obss_scan(struct wpa_supplicant *wpa_s);
+void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable);
+
 #else /* CONFIG_SME */
 
 static inline void sme_authenticate(struct wpa_supplicant *wpa_s,
@@ -95,6 +98,16 @@ static inline void sme_deinit(struct wpa_supplicant *wpa_s)
 {
 }
 
+static inline int sme_proc_obss_scan(struct wpa_supplicant *wpa_s)
+{
+       return 0;
+}
+
+static inline void sme_sched_obss_scan(struct wpa_supplicant *wpa_s,
+                                      int enable)
+{
+}
+
 #endif /* CONFIG_SME */
 
 #endif /* SME_H */
index 8abf2ae..c631cd1 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - command line interface for wpa_supplicant daemon
- * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -20,6 +20,7 @@
 #include "utils/edit.h"
 #include "utils/list.h"
 #include "common/version.h"
+#include "common/ieee802_11_defs.h"
 #ifdef ANDROID
 #include <cutils/properties.h>
 #endif /* ANDROID */
@@ -873,6 +874,78 @@ static int wpa_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc, char *argv[])
 #endif /* CONFIG_WPS_OOB */
 
 
+#ifdef CONFIG_WPS_NFC
+
+static int wpa_cli_cmd_wps_nfc(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       char cmd[256];
+       int res;
+
+       if (argc >= 1)
+               res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC %s",
+                                 argv[0]);
+       else
+               res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC");
+       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+               printf("Too long WPS_NFC command.\n");
+               return -1;
+       }
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl, int argc,
+                                    char *argv[])
+{
+       char cmd[256];
+       int res;
+
+       if (argc != 1) {
+               printf("Invalid WPS_NFC_TOKEN command: need one argument:\n"
+                      "format: WPS or NDEF\n");
+               return -1;
+       }
+       if (argc >= 1)
+               res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s",
+                                 argv[0]);
+       else
+               res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN");
+       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+               printf("Too long WPS_NFC_TOKEN command.\n");
+               return -1;
+       }
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
+                                       char *argv[])
+{
+       int ret;
+       char *buf;
+       size_t buflen;
+
+       if (argc != 1) {
+               printf("Invalid 'wps_nfc_tag_read' command - one argument "
+                      "is required.\n");
+               return -1;
+       }
+
+       buflen = 18 + os_strlen(argv[0]);
+       buf = os_malloc(buflen);
+       if (buf == NULL)
+               return -1;
+       os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]);
+
+       ret = wpa_ctrl_command(ctrl, buf);
+       os_free(buf);
+
+       return ret;
+}
+
+#endif /* CONFIG_WPS_NFC */
+
+
 static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
        char cmd[256];
@@ -1128,6 +1201,32 @@ static int wpa_cli_cmd_wps_er_config(struct wpa_ctrl *ctrl, int argc,
 }
 
 
+#ifdef CONFIG_WPS_NFC
+static int wpa_cli_cmd_wps_er_nfc_config_token(struct wpa_ctrl *ctrl, int argc,
+                                              char *argv[])
+{
+       char cmd[256];
+       int res;
+
+       if (argc != 2) {
+               printf("Invalid WPS_ER_NFC_CONFIG_TOKEN command: need two "
+                      "arguments:\n"
+                      "- WPS/NDEF: token format\n"
+                      "- UUID: specify which AP to use\n");
+               return -1;
+       }
+
+       res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_NFC_CONFIG_TOKEN %s %s",
+                         argv[0], argv[1]);
+       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+               printf("Too long WPS_ER_NFC_CONFIG_TOKEN command.\n");
+               return -1;
+       }
+       return wpa_ctrl_command(ctrl, cmd);
+}
+#endif /* CONFIG_WPS_NFC */
+
+
 static int wpa_cli_cmd_ibss_rsn(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
        char cmd[256];
@@ -1490,7 +1589,12 @@ static int wpa_cli_cmd_enable_network(struct wpa_ctrl *ctrl, int argc,
                return -1;
        }
 
-       res = os_snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %s", argv[0]);
+       if (argc > 1)
+               res = os_snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %s %s",
+                                 argv[0], argv[1]);
+       else
+               res = os_snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %s",
+                                 argv[0]);
        if (res < 0 || (size_t) res >= sizeof(cmd))
                return -1;
        cmd[sizeof(cmd) - 1] = '\0';
@@ -1623,6 +1727,61 @@ static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc,
 }
 
 
+static int wpa_cli_cmd_list_creds(struct wpa_ctrl *ctrl, int argc,
+                                 char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "LIST_CREDS");
+}
+
+
+static int wpa_cli_cmd_add_cred(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "ADD_CRED");
+}
+
+
+static int wpa_cli_cmd_remove_cred(struct wpa_ctrl *ctrl, int argc,
+                                  char *argv[])
+{
+       char cmd[32];
+       int res;
+
+       if (argc < 1) {
+               printf("Invalid REMOVE_CRED command: needs one argument "
+                      "(cred id)\n");
+               return -1;
+       }
+
+       res = os_snprintf(cmd, sizeof(cmd), "REMOVE_CRED %s", argv[0]);
+       if (res < 0 || (size_t) res >= sizeof(cmd))
+               return -1;
+       cmd[sizeof(cmd) - 1] = '\0';
+
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_set_cred(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       char cmd[256];
+       int res;
+
+       if (argc != 3) {
+               printf("Invalid SET_CRED command: needs three arguments\n"
+                      "(cred id, variable name, and value)\n");
+               return -1;
+       }
+
+       res = os_snprintf(cmd, sizeof(cmd), "SET_CRED %s %s %s",
+                         argv[0], argv[1], argv[2]);
+       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+               printf("Too long SET_CRED command.\n");
+               return -1;
+       }
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
 static int wpa_cli_cmd_disconnect(struct wpa_ctrl *ctrl, int argc,
                                  char *argv[])
 {
@@ -1668,8 +1827,9 @@ static int wpa_cli_cmd_bss(struct wpa_ctrl *ctrl, int argc, char *argv[])
                return -1;
        }
 
-       res = os_snprintf(cmd, sizeof(cmd), "BSS %s\t%s\t%s", argv[0],
-                         argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : "");
+       res = os_snprintf(cmd, sizeof(cmd), "BSS %s%s%s%s%s", argv[0],
+                         argc > 1 ? " " : "", argc > 1 ? argv[1] : "",
+                         argc > 2 ? " " : "", argc > 2 ? argv[2] : "");
 
        if (res < 0 || (size_t) res >= sizeof(cmd))
                return -1;
@@ -1848,7 +2008,7 @@ static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
                return -1;
        }
        len = sizeof(buf) - 1;
-       ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
+       ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
                               wpa_cli_msg_cb);
        if (ret == -2) {
                printf("'%s' command timed out.\n", cmd);
@@ -1859,7 +2019,7 @@ static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
        }
 
        buf[len] = '\0';
-       if (memcmp(buf, "FAIL", 4) == 0)
+       if (os_memcmp(buf, "FAIL", 4) == 0)
                return -1;
        printf("%s", buf);
 
@@ -1884,6 +2044,42 @@ static int wpa_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
 
        return -1;
 }
+
+
+static int wpa_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
+                                     char *argv[])
+{
+       char buf[64];
+       if (argc < 1) {
+               printf("Invalid 'deauthenticate' command - exactly one "
+                      "argument, STA address, is required.\n");
+               return -1;
+       }
+       if (argc > 1)
+               os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
+                           argv[0], argv[1]);
+       else
+               os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
+       return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int wpa_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
+                                   char *argv[])
+{
+       char buf[64];
+       if (argc < 1) {
+               printf("Invalid 'disassociate' command - exactly one "
+                      "argument, STA address, is required.\n");
+               return -1;
+       }
+       if (argc > 1)
+               os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
+                           argv[0], argv[1]);
+       else
+               os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
+       return wpa_ctrl_command(ctrl, buf);
+}
 #endif /* CONFIG_AP */
 
 
@@ -1968,7 +2164,14 @@ static int wpa_cli_cmd_p2p_connect(struct wpa_ctrl *ctrl, int argc,
                       "arguments (address and pbc/PIN)\n");
                return -1;
        }
-
+#ifdef ANDROID_P2P
+       if (argc > 5)
+               res = os_snprintf(cmd, sizeof(cmd),
+                                 "P2P_CONNECT %s %s %s %s %s %s",
+                                 argv[0], argv[1], argv[2], argv[3],
+                                 argv[4], argv[5]);
+       else
+#endif
        if (argc > 4)
                res = os_snprintf(cmd, sizeof(cmd),
                                  "P2P_CONNECT %s %s %s %s %s",
@@ -2357,7 +2560,7 @@ static int wpa_ctrl_command_p2p_peer(struct wpa_ctrl *ctrl, char *cmd,
        if (ctrl_conn == NULL)
                return -1;
        len = sizeof(buf) - 1;
-       ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
+       ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
                               wpa_cli_msg_cb);
        if (ret == -2) {
                printf("'%s' command timed out.\n", cmd);
@@ -2368,7 +2571,7 @@ static int wpa_ctrl_command_p2p_peer(struct wpa_ctrl *ctrl, char *cmd,
        }
 
        buf[len] = '\0';
-       if (memcmp(buf, "FAIL", 4) == 0)
+       if (os_memcmp(buf, "FAIL", 4) == 0)
                return -1;
 
        pos = buf;
@@ -2588,6 +2791,60 @@ static int wpa_cli_cmd_anqp_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
 #endif /* CONFIG_INTERWORKING */
 
 
+#ifdef CONFIG_HS20
+
+static int wpa_cli_cmd_hs20_anqp_get(struct wpa_ctrl *ctrl, int argc,
+                                    char *argv[])
+{
+       char cmd[100];
+       int res;
+
+       if (argc != 2) {
+               printf("Invalid HS20_ANQP_GET command: needs two arguments "
+                      "(addr and subtype list)\n");
+               return -1;
+       }
+
+       res = os_snprintf(cmd, sizeof(cmd), "HS20_ANQP_GET %s %s",
+                         argv[0], argv[1]);
+       if (res < 0 || (size_t) res >= sizeof(cmd))
+               return -1;
+       cmd[sizeof(cmd) - 1] = '\0';
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_get_nai_home_realm_list(struct wpa_ctrl *ctrl, int argc,
+                                              char *argv[])
+{
+       char cmd[512];
+       int res;
+
+       if (argc == 0) {
+               printf("Command needs one or two arguments (dst mac addr and "
+                      "optional home realm)\n");
+               return -1;
+       }
+
+       if (argc == 1)
+               res = os_snprintf(cmd, sizeof(cmd),
+                                 "HS20_GET_NAI_HOME_REALM_LIST %s",
+                                 argv[0]);
+       else
+               res = os_snprintf(cmd, sizeof(cmd),
+                                 "HS20_GET_NAI_HOME_REALM_LIST %s %s",
+                                 argv[0], argv[1]);
+       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+               printf("Too long command.\n");
+               return -1;
+       }
+
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+#endif /* CONFIG_HS20 */
+
+
 static int wpa_cli_cmd_sta_autoconnect(struct wpa_ctrl *ctrl, int argc,
                                       char *argv[])
 {
@@ -2684,6 +2941,29 @@ static int wpa_cli_cmd_reauthenticate(struct wpa_ctrl *ctrl, int argc,
        return wpa_ctrl_command(ctrl, "REAUTHENTICATE");
 }
 
+
+#ifdef CONFIG_AUTOSCAN
+
+static int wpa_cli_cmd_autoscan(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+       char cmd[256];
+       int res;
+
+       if (argc == 0)
+               return wpa_ctrl_command(ctrl, "AUTOSCAN ");
+
+       res = os_snprintf(cmd, sizeof(cmd), "AUTOSCAN %s", argv[0]);
+       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+               printf("Too long AUTOSCAN command.\n");
+               return -1;
+       }
+
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+#endif /* CONFIG_AUTOSCAN */
+
+
 #ifdef ANDROID
 static int wpa_cli_cmd_driver(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
@@ -2827,6 +3107,18 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
        { "get_network", wpa_cli_cmd_get_network,
          cli_cmd_flag_none,
          "<network id> <variable> = get network variables" },
+       { "list_creds", wpa_cli_cmd_list_creds,
+         cli_cmd_flag_none,
+         "= list configured credentials" },
+       { "add_cred", wpa_cli_cmd_add_cred,
+         cli_cmd_flag_none,
+         "= add a credential" },
+       { "remove_cred", wpa_cli_cmd_remove_cred,
+         cli_cmd_flag_none,
+         "<cred id> = remove a credential" },
+       { "set_cred", wpa_cli_cmd_set_cred,
+         cli_cmd_flag_sensitive,
+         "<cred id> <variable> <value> = set credential variables" },
        { "save_config", wpa_cli_cmd_save_config,
          cli_cmd_flag_none,
          "= save the current configuration" },
@@ -2903,6 +3195,17 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
          cli_cmd_flag_sensitive,
          "<DEV_TYPE> <PATH> <METHOD> [DEV_NAME] = start WPS OOB" },
 #endif /* CONFIG_WPS_OOB */
+#ifdef CONFIG_WPS_NFC
+       { "wps_nfc", wpa_cli_cmd_wps_nfc,
+         cli_cmd_flag_none,
+         "[BSSID] = start Wi-Fi Protected Setup: NFC" },
+       { "wps_nfc_token", wpa_cli_cmd_wps_nfc_token,
+         cli_cmd_flag_none,
+         "<WPS|NDEF> = create password token" },
+       { "wps_nfc_tag_read", wpa_cli_cmd_wps_nfc_tag_read,
+         cli_cmd_flag_sensitive,
+         "<hexdump of payload> = report read NFC tag with WPS data" },
+#endif /* CONFIG_WPS_NFC */
        { "wps_reg", wpa_cli_cmd_wps_reg,
          cli_cmd_flag_sensitive,
          "<BSSID> <AP PIN> = start WPS Registrar to configure an AP" },
@@ -2930,6 +3233,11 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
        { "wps_er_config", wpa_cli_cmd_wps_er_config,
          cli_cmd_flag_sensitive,
          "<UUID> <PIN> <SSID> <auth> <encr> <key> = configure AP" },
+#ifdef CONFIG_WPS_NFC
+       { "wps_er_nfc_config_token", wpa_cli_cmd_wps_er_nfc_config_token,
+         cli_cmd_flag_none,
+         "<WPS/NDEF> <UUID> = build NFC configuration token" },
+#endif /* CONFIG_WPS_NFC */
        { "ibss_rsn", wpa_cli_cmd_ibss_rsn,
          cli_cmd_flag_none,
          "<addr> = request RSN authentication with <addr> in IBSS" },
@@ -2940,6 +3248,12 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
        { "all_sta", wpa_cli_cmd_all_sta,
          cli_cmd_flag_none,
          "= get information about all associated stations (AP)" },
+       { "deauthenticate", wpa_cli_cmd_deauthenticate,
+         cli_cmd_flag_none,
+         "<addr> = deauthenticate a station" },
+       { "disassociate", wpa_cli_cmd_disassociate,
+         cli_cmd_flag_none,
+         "<addr> = disassociate a station" },
 #endif /* CONFIG_AP */
        { "suspend", wpa_cli_cmd_suspend, cli_cmd_flag_none,
          "= notification of suspend/hibernate" },
@@ -3034,6 +3348,14 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
        { "anqp_get", wpa_cli_cmd_anqp_get, cli_cmd_flag_none,
          "<addr> <info id>[,<info id>]... = request ANQP information" },
 #endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+       { "hs20_anqp_get", wpa_cli_cmd_hs20_anqp_get, cli_cmd_flag_none,
+         "<addr> <subtype>[,<subtype>]... = request HS 2.0 ANQP information"
+       },
+       { "nai_home_realm_list", wpa_cli_cmd_get_nai_home_realm_list,
+         cli_cmd_flag_none,
+         "<addr> <home realm> = get HS20 nai home realm list" },
+#endif /* CONFIG_HS20 */
        { "sta_autoconnect", wpa_cli_cmd_sta_autoconnect, cli_cmd_flag_none,
          "<0/1> = disable/enable automatic reconnection" },
        { "tdls_discover", wpa_cli_cmd_tdls_discover,
@@ -3050,6 +3372,10 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
          "= get signal parameters" },
        { "reauthenticate", wpa_cli_cmd_reauthenticate, cli_cmd_flag_none,
          "= trigger IEEE 802.1X/EAPOL reauthentication" },
+#ifdef CONFIG_AUTOSCAN
+       { "autoscan", wpa_cli_cmd_autoscan, cli_cmd_flag_none,
+         "[params] = Set or unset (if none) autoscan parameters" },
+#endif /* CONFIG_AUTOSCAN */
 #ifdef ANDROID
        { "driver", wpa_cli_cmd_driver,
          cli_cmd_flag_none,
@@ -3758,8 +4084,9 @@ int main(int argc, char *argv[])
                ctrl_conn = wpa_ctrl_open(global);
 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
                if (ctrl_conn == NULL) {
-                       perror("Failed to connect to wpa_supplicant - "
-                              "wpa_ctrl_open");
+                       fprintf(stderr, "Failed to connect to wpa_supplicant "
+                               "global interface: %s  error: %s\n",
+                               global, strerror(errno));
                        return -1;
                }
        }
@@ -3781,8 +4108,8 @@ int main(int argc, char *argv[])
                        }
 
                        if (!warning_displayed) {
-                               printf("Could not connect to wpa_supplicant - "
-                                      "re-trying\n");
+                               printf("Could not connect to wpa_supplicant: "
+                                      "%s - re-trying\n", ctrl_ifname);
                                warning_displayed = 1;
                        }
                        os_sleep(1, 0);
@@ -3791,8 +4118,9 @@ int main(int argc, char *argv[])
        } else {
                if (!global &&
                    wpa_cli_open_connection(ctrl_ifname, 0) < 0) {
-                       perror("Failed to connect to wpa_supplicant - "
-                              "wpa_ctrl_open");
+                       fprintf(stderr, "Failed to connect to non-global "
+                               "ctrl_ifname: %s  error: %s\n",
+                               ctrl_ifname, strerror(errno));
                        return -1;
                }
 
index f2688d5..2bba582 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_gui - SignalBar class
  * Copyright (c) 2011, Kel Modderman <kel@otaku42.de>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include <cstdio>
index 3d5dec1..37da5dd 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_gui - SignalBar class
  * Copyright (c) 2011, Kel Modderman <kel@otaku42.de>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef SIGNALBAR_H
index 97211e4..42e14f0 100644 (file)
@@ -6,16 +6,12 @@
  * See README for more details.
  */
 
-#ifdef __MINGW32__
-/* Need to get getopt() */
-#include <unistd.h>
-#endif
-
 #ifdef CONFIG_NATIVE_WINDOWS
 #include <windows.h>
 #endif /* CONFIG_NATIVE_WINDOWS */
 
 #include <cstdio>
+#include <unistd.h>
 #include <QMessageBox>
 #include <QCloseEvent>
 #include <QImageReader>
@@ -713,17 +709,13 @@ void WpaGui::helpContents()
 void WpaGui::helpAbout()
 {
        QMessageBox::about(this, "wpa_gui for wpa_supplicant",
-                          "Copyright (c) 2003-2011,\n"
+                          "Copyright (c) 2003-2012,\n"
                           "Jouni Malinen <j@w1.fi>\n"
                           "and contributors.\n"
                           "\n"
-                          "This program is free software. You can\n"
-                          "distribute it and/or modify it under the terms "
-                          "of\n"
-                          "the GNU General Public License version 2.\n"
-                          "\n"
-                          "Alternatively, this software may be distributed\n"
-                          "under the terms of the BSD license.\n"
+                          "This software may be distributed under\n"
+                          "the terms of the BSD license.\n"
+                          "See README for more details.\n"
                           "\n"
                           "This product includes software developed\n"
                           "by the OpenSSL Project for use in the\n"
index 74476e2..ad6a080 100644 (file)
@@ -643,7 +643,7 @@ wpa_priv_interface_init(const char *dir, const char *params)
                        }
                        if (bind(iface->fd, (struct sockaddr *) &addr,
                                 sizeof(addr)) < 0) {
-                               perror("bind(PF_UNIX)");
+                               perror("wpa-priv-iface-init: bind(PF_UNIX)");
                                goto fail;
                        }
                        wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
index e1ad4d9..47abd9a 100644 (file)
 #include "p2p_supplicant.h"
 #include "notify.h"
 #include "bgscan.h"
+#include "autoscan.h"
 #include "bss.h"
 #include "scan.h"
 #include "offchannel.h"
+#include "hs20_supplicant.h"
 
 const char *wpa_supplicant_version =
 "wpa_supplicant v" VERSION_STR "\n"
@@ -348,7 +350,7 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
 }
 
 
-static void free_hw_features(struct wpa_supplicant *wpa_s)
+void free_hw_features(struct wpa_supplicant *wpa_s)
 {
        int i;
        if (wpa_s->hw.modes == NULL)
@@ -367,6 +369,7 @@ static void free_hw_features(struct wpa_supplicant *wpa_s)
 static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 {
        bgscan_deinit(wpa_s);
+       autoscan_deinit(wpa_s);
        scard_deinit(wpa_s->scard);
        wpa_s->scard = NULL;
        wpa_sm_set_scard_ctx(wpa_s->wpa, NULL);
@@ -445,6 +448,11 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
        wpa_s->gas = NULL;
 
        free_hw_features(wpa_s);
+
+       os_free(wpa_s->bssid_filter);
+       wpa_s->bssid_filter = NULL;
+
+       wnm_bss_keep_alive_deinit(wpa_s);
 }
 
 
@@ -564,6 +572,29 @@ static void wpa_supplicant_stop_bgscan(struct wpa_supplicant *wpa_s)
 #endif /* CONFIG_BGSCAN */
 
 
+static void wpa_supplicant_start_autoscan(struct wpa_supplicant *wpa_s)
+{
+       if (autoscan_init(wpa_s, 0))
+               wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize autoscan");
+}
+
+
+static void wpa_supplicant_stop_autoscan(struct wpa_supplicant *wpa_s)
+{
+       autoscan_deinit(wpa_s);
+}
+
+
+void wpa_supplicant_reinit_autoscan(struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->wpa_state == WPA_DISCONNECTED ||
+           wpa_s->wpa_state == WPA_SCANNING) {
+               autoscan_deinit(wpa_s);
+               wpa_supplicant_start_autoscan(wpa_s);
+       }
+}
+
+
 /**
  * wpa_supplicant_set_state - Set current connection state
  * @wpa_s: Pointer to wpa_supplicant data
@@ -610,6 +641,8 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
 #ifdef CONFIG_P2P
                wpas_p2p_completed(wpa_s);
 #endif /* CONFIG_P2P */
+
+               sme_sched_obss_scan(wpa_s, 1);
        } else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
                   state == WPA_ASSOCIATED) {
                wpa_s->new_connection = 1;
@@ -617,6 +650,7 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
 #ifndef IEEE8021X_EAPOL
                wpa_drv_set_supp_port(wpa_s, 0);
 #endif /* IEEE8021X_EAPOL */
+               sme_sched_obss_scan(wpa_s, 0);
        }
        wpa_s->wpa_state = state;
 
@@ -627,6 +661,12 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
                wpa_supplicant_stop_bgscan(wpa_s);
 #endif /* CONFIG_BGSCAN */
 
+       if (state == WPA_AUTHENTICATING)
+               wpa_supplicant_stop_autoscan(wpa_s);
+
+       if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
+               wpa_supplicant_start_autoscan(wpa_s);
+
        if (wpa_s->wpa_state != old_state) {
                wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
 
@@ -670,7 +710,7 @@ void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s)
        wpa_s->mgmt_group_cipher = 0;
        wpa_s->key_mgmt = 0;
        if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED)
-               wpa_s->wpa_state = WPA_DISCONNECTED;
+               wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
 
        if (wpa_s->wpa_state != old_state)
                wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
@@ -749,7 +789,7 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
        wpa_supplicant_update_config(wpa_s);
 
        wpa_supplicant_clear_status(wpa_s);
-       if (wpa_supplicant_enabled_networks(wpa_s->conf)) {
+       if (wpa_supplicant_enabled_networks(wpa_s)) {
                wpa_s->reassociate = 1;
                wpa_supplicant_req_scan(wpa_s, 0, 0);
        }
@@ -1254,11 +1294,10 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                u8 *pos;
                size_t len;
                int res;
-               int p2p_group;
-               p2p_group = wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE;
                pos = wpa_ie + wpa_ie_len;
                len = sizeof(wpa_ie) - wpa_ie_len;
-               res = wpas_p2p_assoc_req_ie(wpa_s, bss, pos, len, p2p_group);
+               res = wpas_p2p_assoc_req_ie(wpa_s, bss, pos, len,
+                                           ssid->p2p_group);
                if (res >= 0)
                        wpa_ie_len += res;
        }
@@ -1279,6 +1318,20 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        }
 #endif /* CONFIG_P2P */
 
+#ifdef CONFIG_HS20
+       if (wpa_s->conf->hs20) {
+               struct wpabuf *hs20;
+               hs20 = wpabuf_alloc(20);
+               if (hs20) {
+                       wpas_hs20_add_indication(hs20);
+                       os_memcpy(wpa_ie + wpa_ie_len, wpabuf_head(hs20),
+                                 wpabuf_len(hs20));
+                       wpa_ie_len += wpabuf_len(hs20);
+                       wpabuf_free(hs20);
+               }
+       }
+#endif /* CONFIG_HS20 */
+
 #ifdef CONFIG_INTERWORKING
        if (wpa_s->conf->interworking) {
                u8 *pos = wpa_ie;
@@ -1336,7 +1389,12 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        if (bss) {
                params.ssid = bss->ssid;
                params.ssid_len = bss->ssid_len;
-               if (!wpas_driver_bss_selection(wpa_s)) {
+               if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set) {
+                       wpa_printf(MSG_DEBUG, "Limit connection to BSSID "
+                                  MACSTR " freq=%u MHz based on scan results "
+                                  "(bssid_set=%d)",
+                                  MAC2STR(bss->bssid), bss->freq,
+                                  ssid->bssid_set);
                        params.bssid = bss->bssid;
                        params.freq = bss->freq;
                }
@@ -1362,6 +1420,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        params.wpa_proto = wpa_s->wpa_proto;
        params.auth_alg = algs;
        params.mode = ssid->mode;
+       params.bg_scan_period = ssid->bg_scan_period;
        for (i = 0; i < NUM_WEP_KEYS; i++) {
                if (ssid->wep_key_len[i])
                        params.wep_key[i] = ssid->wep_key[i];
@@ -1441,6 +1500,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                         * succeed.
                         */
                        wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+                       wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
                        os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
                        return;
                }
@@ -1534,10 +1594,15 @@ void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
                                 int reason_code)
 {
        u8 *addr = NULL;
+       union wpa_event_data event;
 
        if (!is_zero_ether_addr(wpa_s->bssid)) {
                wpa_drv_disassociate(wpa_s, wpa_s->bssid, reason_code);
                addr = wpa_s->bssid;
+               os_memset(&event, 0, sizeof(event));
+               event.disassoc_info.reason_code = (u16) reason_code;
+               event.disassoc_info.locally_generated = 1;
+               wpa_supplicant_event(wpa_s, EVENT_DISASSOC, &event);
        }
 
        wpa_supplicant_clear_connection(wpa_s, addr);
@@ -1556,10 +1621,15 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
                                   int reason_code)
 {
        u8 *addr = NULL;
+       union wpa_event_data event;
 
        if (!is_zero_ether_addr(wpa_s->bssid)) {
                wpa_drv_deauthenticate(wpa_s, wpa_s->bssid, reason_code);
                addr = wpa_s->bssid;
+               os_memset(&event, 0, sizeof(event));
+               event.deauth_info.reason_code = (u16) reason_code;
+               event.deauth_info.locally_generated = 1;
+               wpa_supplicant_event(wpa_s, EVENT_DEAUTH, &event);
        }
 
        wpa_supplicant_clear_connection(wpa_s, addr);
@@ -1799,6 +1869,29 @@ int wpa_supplicant_set_bss_expiration_count(struct wpa_supplicant *wpa_s,
 
 
 /**
+ * wpa_supplicant_set_scan_interval - Set scan interval
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @scan_interval: scan interval in seconds
+ * Returns: 0 if succeed or -1 if scan_interval has an invalid value
+ *
+ */
+int wpa_supplicant_set_scan_interval(struct wpa_supplicant *wpa_s,
+                                    int scan_interval)
+{
+       if (scan_interval < 0) {
+               wpa_msg(wpa_s, MSG_ERROR, "Invalid scan interval %d",
+                       scan_interval);
+               return -1;
+       }
+       wpa_msg(wpa_s, MSG_DEBUG, "Setting scan interval: %d sec",
+               scan_interval);
+       wpa_s->scan_interval = scan_interval;
+
+       return 0;
+}
+
+
+/**
  * wpa_supplicant_set_debug_params - Set global debug params
  * @global: wpa_global structure
  * @debug_level: debug level
@@ -1873,14 +1966,14 @@ struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
 
        entry = wpa_s->conf->ssid;
        while (entry) {
-               if (!entry->disabled &&
+               if (!wpas_network_disabled(wpa_s, entry) &&
                    ((ssid_len == entry->ssid_len &&
                      os_memcmp(ssid, entry->ssid, ssid_len) == 0) || wired) &&
                    (!entry->bssid_set ||
                     os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
                        return entry;
 #ifdef CONFIG_WPS
-               if (!entry->disabled &&
+               if (!wpas_network_disabled(wpa_s, entry) &&
                    (entry->key_mgmt & WPA_KEY_MGMT_WPS) &&
                    (entry->ssid == NULL || entry->ssid_len == 0) &&
                    (!entry->bssid_set ||
@@ -1888,7 +1981,7 @@ struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
                        return entry;
 #endif /* CONFIG_WPS */
 
-               if (!entry->disabled && entry->bssid_set &&
+               if (!wpas_network_disabled(wpa_s, entry) && entry->bssid_set &&
                    entry->ssid_len == 0 &&
                    os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)
                        return entry;
@@ -2111,6 +2204,31 @@ int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
 }
 
 
+static void wpa_supplicant_rx_eapol_bridge(void *ctx, const u8 *src_addr,
+                                          const u8 *buf, size_t len)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+       const struct l2_ethhdr *eth;
+
+       if (len < sizeof(*eth))
+               return;
+       eth = (const struct l2_ethhdr *) buf;
+
+       if (os_memcmp(eth->h_dest, wpa_s->own_addr, ETH_ALEN) != 0 &&
+           !(eth->h_dest[0] & 0x01)) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " to " MACSTR
+                       " (bridge - not for this interface - ignore)",
+                       MAC2STR(src_addr), MAC2STR(eth->h_dest));
+               return;
+       }
+
+       wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " to " MACSTR
+               " (bridge)", MAC2STR(src_addr), MAC2STR(eth->h_dest));
+       wpa_supplicant_rx_eapol(wpa_s, src_addr, buf + sizeof(*eth),
+                               len - sizeof(*eth));
+}
+
+
 /**
  * wpa_supplicant_driver_init - Initialize driver interface parameters
  * @wpa_s: Pointer to wpa_supplicant data
@@ -2133,8 +2251,8 @@ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
                wpa_s->l2_br = l2_packet_init(wpa_s->bridge_ifname,
                                              wpa_s->own_addr,
                                              ETH_P_EAPOL,
-                                             wpa_supplicant_rx_eapol, wpa_s,
-                                             0);
+                                             wpa_supplicant_rx_eapol_bridge,
+                                             wpa_s, 1);
                if (wpa_s->l2_br == NULL) {
                        wpa_msg(wpa_s, MSG_ERROR, "Failed to open l2_packet "
                                "connection for the bridge interface '%s'",
@@ -2155,7 +2273,7 @@ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
        wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
        wpa_s->prev_scan_wildcard = 0;
 
-       if (wpa_supplicant_enabled_networks(wpa_s->conf)) {
+       if (wpa_supplicant_enabled_networks(wpa_s)) {
                if (wpa_supplicant_delayed_sched_scan(wpa_s, interface_count,
                                                      100000))
                        wpa_supplicant_req_scan(wpa_s, interface_count,
@@ -2369,6 +2487,48 @@ void wpa_supplicant_apply_ht_overrides(
 #endif /* CONFIG_HT_OVERRIDES */
 
 
+static int pcsc_reader_init(struct wpa_supplicant *wpa_s)
+{
+#ifdef PCSC_FUNCS
+       size_t len;
+
+       if (!wpa_s->conf->pcsc_reader)
+               return 0;
+
+       wpa_s->scard = scard_init(SCARD_TRY_BOTH, wpa_s->conf->pcsc_reader);
+       if (!wpa_s->scard)
+               return 1;
+
+       if (wpa_s->conf->pcsc_pin &&
+           scard_set_pin(wpa_s->scard, wpa_s->conf->pcsc_pin) < 0) {
+               scard_deinit(wpa_s->scard);
+               wpa_s->scard = NULL;
+               wpa_msg(wpa_s, MSG_ERROR, "PC/SC PIN validation failed");
+               return -1;
+       }
+
+       len = sizeof(wpa_s->imsi) - 1;
+       if (scard_get_imsi(wpa_s->scard, wpa_s->imsi, &len)) {
+               scard_deinit(wpa_s->scard);
+               wpa_s->scard = NULL;
+               wpa_msg(wpa_s, MSG_ERROR, "Could not read IMSI");
+               return -1;
+       }
+       wpa_s->imsi[len] = '\0';
+
+       wpa_s->mnc_len = scard_get_mnc_len(wpa_s->scard);
+
+       wpa_printf(MSG_DEBUG, "SCARD: IMSI %s (MNC length %d)",
+                  wpa_s->imsi, wpa_s->mnc_len);
+
+       wpa_sm_set_scard_ctx(wpa_s->wpa, wpa_s->scard);
+       eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
+#endif /* PCSC_FUNCS */
+
+       return 0;
+}
+
+
 static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
                                     struct wpa_interface *iface)
 {
@@ -2528,6 +2688,7 @@ next_driver:
        if (wpa_drv_get_capa(wpa_s, &capa) == 0) {
                wpa_s->drv_capa_known = 1;
                wpa_s->drv_flags = capa.flags;
+               wpa_s->drv_enc = capa.enc;
                wpa_s->probe_resp_offloads = capa.probe_resp_offloads;
                wpa_s->max_scan_ssids = capa.max_scan_ssids;
                wpa_s->max_sched_scan_ssids = capa.max_sched_scan_ssids;
@@ -2590,6 +2751,9 @@ next_driver:
        if (wpa_bss_init(wpa_s) < 0)
                return -1;
 
+       if (pcsc_reader_init(wpa_s) < 0)
+               return -1;
+
        return 0;
 }
 
@@ -2607,6 +2771,14 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
 
        wpa_supplicant_cleanup(wpa_s);
 
+#ifdef CONFIG_P2P
+       if (wpa_s == wpa_s->global->p2p_init_wpa_s && wpa_s->global->p2p) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Disable P2P since removing "
+                       "the management interface is being removed");
+               wpas_p2p_deinit_global(wpa_s->global);
+       }
+#endif /* CONFIG_P2P */
+
        if (wpa_s->drv_priv)
                wpa_drv_deinit(wpa_s);
 
@@ -2693,6 +2865,7 @@ struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
        global->ifaces = wpa_s;
 
        wpa_dbg(wpa_s, MSG_DEBUG, "Added interface %s", wpa_s->ifname);
+       wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
 
        return wpa_s;
 }
@@ -2821,6 +2994,14 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
        wpa_debug_open_file(params->wpa_debug_file_path);
        if (params->wpa_debug_syslog)
                wpa_debug_open_syslog();
+       if (params->wpa_debug_tracing) {
+               ret = wpa_debug_open_linux_tracing();
+               if (ret) {
+                       wpa_printf(MSG_ERROR,
+                                  "Failed to enable trace logging");
+                       return NULL;
+               }
+       }
 
        ret = eap_register_methods();
        if (ret) {
@@ -2978,9 +3159,12 @@ void wpa_supplicant_deinit(struct wpa_global *global)
        os_free(global->params.override_driver);
        os_free(global->params.override_ctrl_interface);
 
+       os_free(global->p2p_disallow_freq);
+
        os_free(global);
        wpa_debug_close_syslog();
        wpa_debug_close_file();
+       wpa_debug_close_linux_tracing();
 }
 
 
@@ -3129,15 +3313,119 @@ int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s)
                (wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION);
 }
 
-#ifdef ANDROID_P2P
+
+#if defined(CONFIG_CTRL_IFACE) || defined(CONFIG_CTRL_IFACE_DBUS_NEW)
+int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
+                                             struct wpa_ssid *ssid,
+                                             const char *field,
+                                             const char *value)
+{
+#ifdef IEEE8021X_EAPOL
+       struct eap_peer_config *eap = &ssid->eap;
+
+       wpa_printf(MSG_DEBUG, "CTRL_IFACE: response handle field=%s", field);
+       wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: response value",
+                             (const u8 *) value, os_strlen(value));
+
+       switch (wpa_supplicant_ctrl_req_from_string(field)) {
+       case WPA_CTRL_REQ_EAP_IDENTITY:
+               os_free(eap->identity);
+               eap->identity = (u8 *) os_strdup(value);
+               eap->identity_len = os_strlen(value);
+               eap->pending_req_identity = 0;
+               if (ssid == wpa_s->current_ssid)
+                       wpa_s->reassociate = 1;
+               break;
+       case WPA_CTRL_REQ_EAP_PASSWORD:
+               os_free(eap->password);
+               eap->password = (u8 *) os_strdup(value);
+               eap->password_len = os_strlen(value);
+               eap->pending_req_password = 0;
+               if (ssid == wpa_s->current_ssid)
+                       wpa_s->reassociate = 1;
+               break;
+       case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
+               os_free(eap->new_password);
+               eap->new_password = (u8 *) os_strdup(value);
+               eap->new_password_len = os_strlen(value);
+               eap->pending_req_new_password = 0;
+               if (ssid == wpa_s->current_ssid)
+                       wpa_s->reassociate = 1;
+               break;
+       case WPA_CTRL_REQ_EAP_PIN:
+               os_free(eap->pin);
+               eap->pin = os_strdup(value);
+               eap->pending_req_pin = 0;
+               if (ssid == wpa_s->current_ssid)
+                       wpa_s->reassociate = 1;
+               break;
+       case WPA_CTRL_REQ_EAP_OTP:
+               os_free(eap->otp);
+               eap->otp = (u8 *) os_strdup(value);
+               eap->otp_len = os_strlen(value);
+               os_free(eap->pending_req_otp);
+               eap->pending_req_otp = NULL;
+               eap->pending_req_otp_len = 0;
+               break;
+       case WPA_CTRL_REQ_EAP_PASSPHRASE:
+               os_free(eap->private_key_passwd);
+               eap->private_key_passwd = (u8 *) os_strdup(value);
+               eap->pending_req_passphrase = 0;
+               if (ssid == wpa_s->current_ssid)
+                       wpa_s->reassociate = 1;
+               break;
+       default:
+               wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field);
+               return -1;
+       }
+
+       return 0;
+#else /* IEEE8021X_EAPOL */
+       wpa_printf(MSG_DEBUG, "CTRL_IFACE: IEEE 802.1X not included");
+       return -1;
+#endif /* IEEE8021X_EAPOL */
+}
+#endif /* CONFIG_CTRL_IFACE || CONFIG_CTRL_IFACE_DBUS_NEW */
+
+
+int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+       int i;
+       unsigned int drv_enc;
+
+       if (ssid == NULL)
+               return 1;
+
+       if (ssid->disabled)
+               return 1;
+
+       if (wpa_s && wpa_s->drv_capa_known)
+               drv_enc = wpa_s->drv_enc;
+       else
+               drv_enc = (unsigned int) -1;
+
+       for (i = 0; i < NUM_WEP_KEYS; i++) {
+               size_t len = ssid->wep_key_len[i];
+               if (len == 0)
+                       continue;
+               if (len == 5 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP40))
+                       continue;
+               if (len == 13 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP104))
+                       continue;
+               if (len == 16 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP128))
+                       continue;
+               return 1; /* invalid WEP key */
+       }
+
+       return 0;
+}
+
+
 int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s)
 {
        if (wpa_s->global->conc_pref == WPA_CONC_PREF_P2P)
                return 1;
        if (wpa_s->global->conc_pref == WPA_CONC_PREF_STA)
                return 0;
-
-       /* IF conc_priority is not set, return -1 */
        return -1;
 }
-#endif
index d393015..3ebbcc2 100644 (file)
@@ -214,6 +214,22 @@ fast_reauth=1
 #      to external program(s)
 #wps_cred_processing=0
 
+# Vendor attribute in WPS M1, e.g., Windows 7 Vertical Pairing
+# The vendor attribute contents to be added in M1 (hex string)
+#wps_vendor_ext_m1=000137100100020001
+
+# NFC password token for WPS
+# These parameters can be used to configure a fixed NFC password token for the
+# station. This can be generated, e.g., with nfc_pw_token. When these
+# parameters are used, the station is assumed to be deployed with a NFC tag
+# that includes the matching NFC password token (e.g., written based on the
+# NDEF record from nfc_pw_token).
+#
+#wps_nfc_dev_pw_id: Device Password ID (16..65535)
+#wps_nfc_dh_pubkey: Hexdump of DH Public Key
+#wps_nfc_dh_privkey: Hexdump of DH Private Key
+#wps_nfc_dev_pw: Hexdump of Device Password
+
 # Maximum number of BSS entries to keep in memory
 # Default: 200
 # This can be used to limit memory use on the BSS entries (cached scan
@@ -221,6 +237,18 @@ fast_reauth=1
 # of APs when using ap_scan=1 mode.
 #bss_max_count=200
 
+# Automatic scan
+# This is an optional set of parameters for automatic scanning
+# within an interface in following format:
+#autoscan=<autoscan module name>:<module parameters>
+# autoscan is like bgscan but on disconnected or inactive state.
+# For instance, on exponential module parameters would be <base>:<limit>
+#autoscan=exponential:3:300
+# Which means a delay between scans on a base exponential of 3,
+# up to the limit of 300 seconds (3, 9, 27 ... 300)
+# For periodic module, parameters would be <fixed interval>
+#autoscan=periodic:30
+# So a delay of 30 seconds will be applied between each scan
 
 # filter_ssids - SSID-based scan result filtering
 # 0 = do not filter scan results (default)
@@ -239,23 +267,92 @@ fast_reauth=1
 # is enabled.
 # hessid=00:11:22:33:44:55
 
-# Home Realm for Interworking
-#home_realm=example.com
-
-# Username for Interworking network selection
-#home_username=user
-
-# Password for Interworking network selection
-#home_password=secret
-
-# CA certificate for Interworking network selection
-#home_ca_cert=/etc/cert/ca.pem
-
-# IMSI in <MCC> | <MNC> | '-' | <MSIN> format
-#home_imsi=232010000000000
+# 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.
+#
+# 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"
+#}
 
-# Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN> format
-#home_milenage=90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123
+# Hotspot 2.0
+# hs20=1
 
 # network block
 #
@@ -341,6 +438,16 @@ fast_reauth=1
 # WPA-EAP-SHA256 = Like WPA-EAP but using stronger SHA256-based algorithms
 # If not set, this defaults to: WPA-PSK WPA-EAP
 #
+# ieee80211w: whether management frame protection is enabled
+# 0 = disabled (default)
+# 1 = optional
+# 2 = required
+# The most common configuration options for this based on the PMF (protected
+# management frames) certification program are:
+# PMF enabled: ieee80211w=1 and key_mgmt=WPA-EAP WPA-EAP-SHA256
+# PMF required: ieee80211w=2 and key_mgmt=WPA-EAP-SHA256
+# (and similarly for WPA-PSK and WPA-WPSK-SHA256 if WPA2-Personal is used)
+#
 # auth_alg: list of allowed IEEE 802.11 authentication algorithms
 # OPEN = Open System authentication (required for WPA/WPA2)
 # SHARED = Shared Key authentication (requires static WEP keys)
@@ -587,6 +694,26 @@ fast_reauth=1
 # number of authentication servers. Strict EAP conformance mode can be
 # configured by disabling workarounds with eap_workaround=0.
 
+# Station inactivity limit
+#
+# If a station does not send anything in ap_max_inactivity seconds, an
+# empty data frame is sent to it in order to verify whether it is
+# still in range. If this frame is not ACKed, the station will be
+# disassociated and then deauthenticated. This feature is used to
+# clear station table of old entries when the STAs move out of the
+# range.
+#
+# The station can associate again with the AP if it is still in range;
+# this inactivity poll is just used as a nicer way of verifying
+# inactivity; i.e., client will not report broken connection because
+# disassociation frame is not sent immediately without first polling
+# the STA with a data frame.
+# default: 300 (i.e., 5 minutes)
+#ap_max_inactivity=300
+
+# DTIM period in Beacon intervals for AP mode (default: 2)
+#dtim_period=2
+
 # Example blocks:
 
 # Simple case: WPA-PSK, PSK as an ASCII passphrase, allow all valid ciphers
index 21fe5cc..3f6669d 100644 (file)
@@ -161,6 +161,11 @@ struct wpa_params {
        int wpa_debug_syslog;
 
        /**
+        * wpa_debug_tracing - Enable log output through Linux tracing
+        */
+       int wpa_debug_tracing;
+
+       /**
         * override_driver - Optional driver parameter override
         *
         * This parameter can be used to override the driver parameter in
@@ -199,6 +204,12 @@ struct p2p_srv_upnp {
        char *service;
 };
 
+struct wpa_freq_range {
+       unsigned int min;
+       unsigned int max;
+};
+
+
 /**
  * struct wpa_global - Internal, global data for all %wpa_supplicant interfaces
  *
@@ -214,19 +225,20 @@ struct wpa_global {
        size_t drv_count;
        struct os_time suspend_time;
        struct p2p_data *p2p;
+       struct wpa_supplicant *p2p_init_wpa_s;
        struct wpa_supplicant *p2p_group_formation;
        u8 p2p_dev_addr[ETH_ALEN];
        struct dl_list p2p_srv_bonjour; /* struct p2p_srv_bonjour */
        struct dl_list p2p_srv_upnp; /* struct p2p_srv_upnp */
        int p2p_disabled;
-#ifdef ANDROID_P2P
+       int cross_connection;
+       struct wpa_freq_range *p2p_disallow_freq;
+       unsigned int num_p2p_disallow_freq;
        enum wpa_conc_pref {
                WPA_CONC_PREF_NOT_SET,
                WPA_CONC_PREF_STA,
                WPA_CONC_PREF_P2P
        } conc_pref;
-#endif
-       int cross_connection;
 };
 
 
@@ -259,6 +271,9 @@ struct wpa_supplicant {
 #ifdef CONFIG_CTRL_IFACE_DBUS_NEW
        char *dbus_new_path;
        char *dbus_groupobj_path;
+#ifdef CONFIG_AP
+       char *preq_notify_peer;
+#endif /* CONFIG_AP */
 #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
        char bridge_ifname[16];
 
@@ -287,6 +302,9 @@ struct wpa_supplicant {
        void *drv_priv; /* private data used by driver_ops */
        void *global_drv_priv;
 
+       u8 *bssid_filter;
+       size_t bssid_filter_count;
+
        /* previous scan was wildcard when interleaving between
         * wildcard scans and specific SSID scan when max_ssids=1 */
        int prev_scan_wildcard;
@@ -330,6 +348,10 @@ struct wpa_supplicant {
                             * previous association event */
 
        struct scard_data *scard;
+#ifdef PCSC_FUNCS
+       char imsi[20];
+       int mnc_len;
+#endif /* PCSC_FUNCS */
 
        unsigned char last_eapol_src[ETH_ALEN];
 
@@ -345,6 +367,7 @@ struct wpa_supplicant {
        int normal_scans; /* normal scans run before sched_scan */
 
        unsigned int drv_flags;
+       unsigned int drv_enc;
 
        /*
         * A bitmap of supported protocols for probe response offload. See
@@ -403,6 +426,9 @@ struct wpa_supplicant {
                                        * sa_query_count octets of pending
                                        * SA Query transaction identifiers */
                struct os_time sa_query_start;
+               u8 sched_obss_scan;
+               u16 obss_scan_int;
+               u16 bss_max_idle_period;
        } sme;
 #endif /* CONFIG_SME */
 
@@ -460,7 +486,12 @@ struct wpa_supplicant {
        u8 pending_join_dev_addr[ETH_ALEN];
        int pending_join_wps_method;
        int p2p_join_scan_count;
+       int auto_pd_scan_retry;
        int force_long_sd;
+       u16 pending_pd_config_methods;
+       enum {
+               NORMAL_PD, AUTO_PD_GO_NEG, AUTO_PD_JOIN
+       } pending_pd_use;
 
        /*
         * Whether cross connection is disallowed by the AP to which this
@@ -488,18 +519,32 @@ struct wpa_supplicant {
                P2P_GROUP_REMOVAL_REQUESTED,
                P2P_GROUP_REMOVAL_IDLE_TIMEOUT,
                P2P_GROUP_REMOVAL_UNAVAILABLE,
+               P2P_GROUP_REMOVAL_GO_ENDING_SESSION,
 #ifdef ANDROID_P2P
                P2P_GROUP_REMOVAL_FREQ_CONFLICT
 #endif
        } removal_reason;
 
        unsigned int p2p_cb_on_scan_complete:1;
+       unsigned int p2p_auto_join:1;
+       unsigned int p2p_auto_pd:1;
+       unsigned int p2p_persistent_group:1;
+       unsigned int p2p_fallback_to_go_neg:1;
+       unsigned int p2p_pd_before_go_neg:1;
+       int p2p_persistent_id;
+       int p2p_go_intent;
+       int p2p_connect_freq;
+       struct os_time p2p_auto_started;
 #endif /* CONFIG_P2P */
 
        struct wpa_ssid *bgscan_ssid;
        const struct bgscan_ops *bgscan;
        void *bgscan_priv;
 
+       const struct autoscan_ops *autoscan;
+       struct wpa_driver_scan_params *autoscan_params;
+       void *autoscan_priv;
+
        struct wpa_ssid *connect_without_scan;
 
        int after_wps;
@@ -529,6 +574,9 @@ struct wpa_supplicant {
        } hw;
 
        int pno;
+
+       /* WLAN_REASON_* reason codes. Negative if locally generated. */
+       int disconnect_reason;
 };
 
 
@@ -556,6 +604,7 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s);
 void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr);
 void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
                                     int sec, int usec);
+void wpa_supplicant_reinit_autoscan(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
                              enum wpa_states state);
 struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s);
@@ -578,9 +627,12 @@ int wpa_supplicant_set_bss_expiration_age(struct wpa_supplicant *wpa_s,
                                          unsigned int expire_age);
 int wpa_supplicant_set_bss_expiration_count(struct wpa_supplicant *wpa_s,
                                            unsigned int expire_count);
+int wpa_supplicant_set_scan_interval(struct wpa_supplicant *wpa_s,
+                                    int scan_interval);
 int wpa_supplicant_set_debug_params(struct wpa_global *global,
                                    int debug_level, int debug_timestamp,
                                    int debug_show_keys);
+void free_hw_features(struct wpa_supplicant *wpa_s);
 
 void wpa_show_license(void);
 
@@ -606,9 +658,23 @@ void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s);
 void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid);
 int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s);
-#ifdef ANDROID_P2P
 int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s);
-#endif
+void wpa_supplicant_proc_40mhz_intolerant(struct wpa_supplicant *wpa_s);
+
+/**
+ * wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @ssid: Pointer to the network block the reply is for
+ * @field: field the response is a reply for
+ * @value: value (ie, password, etc) for @field
+ * Returns: 0 on success, non-zero on error
+ *
+ * Helper function to handle replies to control interface requests.
+ */
+int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
+                                             struct wpa_ssid *ssid,
+                                             const char *field,
+                                             const char *value);
 
 /* events.c */
 void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s);
@@ -617,6 +683,7 @@ int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
                           struct wpa_ssid *ssid);
 void wpa_supplicant_stop_countermeasures(void *eloop_ctx, void *sock_ctx);
 void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx, void *sock_ctx);
+void wnm_bss_keep_alive_deinit(struct wpa_supplicant *wpa_s);
 
 /* eap_register.c */
 int eap_register_methods(void);
@@ -631,4 +698,6 @@ static inline int network_is_persistent_group(struct wpa_ssid *ssid)
        return ((ssid->disabled == 2) || ssid->p2p_persistent_group);
 }
 
+int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+
 #endif /* WPA_SUPPLICANT_I_H */
index 5b9dc9e..fb4fa22 100644 (file)
@@ -720,6 +720,15 @@ static void wpa_supplicant_cert_cb(void *ctx, int depth, const char *subject,
 
        wpas_notify_certification(wpa_s, depth, subject, cert_hash, cert);
 }
+
+
+static void wpa_supplicant_status_cb(void *ctx, const char *status,
+                                    const char *parameter)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+
+       wpas_notify_eap_status(wpa_s, status, parameter);
+}
 #endif /* IEEE8021X_EAPOL */
 
 
@@ -751,6 +760,7 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
        ctx->port_cb = wpa_supplicant_port_cb;
        ctx->cb = wpa_supplicant_eapol_cb;
        ctx->cert_cb = wpa_supplicant_cert_cb;
+       ctx->status_cb = wpa_supplicant_status_cb;
        ctx->cb_ctx = wpa_s;
        wpa_s->eapol = eapol_sm_init(ctx);
        if (wpa_s->eapol == NULL) {
index 4965439..7356d1a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * wpa_supplicant / WPS integration
- * Copyright (c) 2008-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -11,6 +11,7 @@
 #include "common.h"
 #include "eloop.h"
 #include "uuid.h"
+#include "crypto/random.h"
 #include "crypto/dh_group5.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
@@ -20,6 +21,7 @@
 #include "eap_peer/eap.h"
 #include "eapol_supp/eapol_supp_sm.h"
 #include "rsn_supp/wpa.h"
+#include "wps/wps_attr_parse.h"
 #include "config.h"
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
@@ -263,6 +265,7 @@ static int wpa_supplicant_wps_cred(void *ctx,
                ssid->eap.eap_methods = NULL;
                if (!ssid->p2p_group)
                        ssid->temporary = 0;
+               ssid->bssid_set = 0;
        } else {
                wpa_printf(MSG_DEBUG, "WPS: Create a new network based on the "
                           "received credential");
@@ -919,7 +922,8 @@ int wpas_wps_cancel(struct wpa_supplicant *wpa_s)
        }
 #endif /* CONFIG_AP */
 
-       if (wpa_s->wpa_state == WPA_SCANNING) {
+       if (wpa_s->wpa_state == WPA_SCANNING ||
+           wpa_s->wpa_state == WPA_DISCONNECTED) {
                wpa_printf(MSG_DEBUG, "WPS: Cancel operation - cancel scan");
                wpa_supplicant_cancel_scan(wpa_s);
                wpas_clear_wps(wpa_s);
@@ -1113,8 +1117,10 @@ static void wpas_wps_set_uuid(struct wpa_supplicant *wpa_s,
                while (first && first->next)
                        first = first->next;
                if (first && first != wpa_s) {
-                       os_memcpy(wps->uuid, wpa_s->global->ifaces->wps->uuid,
-                                 WPS_UUID_LEN);
+                       if (wps != wpa_s->global->ifaces->wps)
+                               os_memcpy(wps->uuid,
+                                         wpa_s->global->ifaces->wps->uuid,
+                                         WPS_UUID_LEN);
                        wpa_hexdump(MSG_DEBUG, "WPS: UUID from the first "
                                    "interface", wps->uuid, WPS_UUID_LEN);
                } else {
@@ -1130,6 +1136,23 @@ static void wpas_wps_set_uuid(struct wpa_supplicant *wpa_s,
 }
 
 
+static void wpas_wps_set_vendor_ext_m1(struct wpa_supplicant *wpa_s,
+                                      struct wps_context *wps)
+{
+       wpabuf_free(wps->dev.vendor_ext_m1);
+       wps->dev.vendor_ext_m1 = NULL;
+
+       if (wpa_s->conf->wps_vendor_ext_m1) {
+               wps->dev.vendor_ext_m1 =
+                       wpabuf_dup(wpa_s->conf->wps_vendor_ext_m1);
+               if (!wps->dev.vendor_ext_m1) {
+                       wpa_printf(MSG_ERROR, "WPS: Cannot "
+                                  "allocate memory for vendor_ext_m1");
+               }
+       }
+}
+
+
 int wpas_wps_init(struct wpa_supplicant *wpa_s)
 {
        struct wps_context *wps;
@@ -1168,6 +1191,8 @@ int wpas_wps_init(struct wpa_supplicant *wpa_s)
        os_memcpy(wps->dev.sec_dev_type, wpa_s->conf->sec_device_type,
                  WPS_DEV_TYPE_LEN * wps->dev.num_sec_dev_types);
 
+       wpas_wps_set_vendor_ext_m1(wpa_s, wps);
+
        wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version);
        modes = wpa_s->hw.modes;
        if (modes) {
@@ -1228,6 +1253,7 @@ void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
        wpabuf_free(wpa_s->wps->dh_privkey);
        wpabuf_free(wpa_s->wps->oob_conf.pubkey_hash);
        wpabuf_free(wpa_s->wps->oob_conf.dev_password);
+       wpabuf_free(wpa_s->wps->dev.vendor_ext_m1);
        os_free(wpa_s->wps->network_key);
        os_free(wpa_s->wps);
        wpa_s->wps = NULL;
@@ -1648,6 +1674,34 @@ int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid,
 }
 
 
+#ifdef CONFIG_WPS_NFC
+struct wpabuf * wpas_wps_er_nfc_config_token(struct wpa_supplicant *wpa_s,
+                                            int ndef, const char *uuid)
+{
+       struct wpabuf *ret;
+       u8 u[UUID_LEN];
+
+       if (!wpa_s->wps_er)
+               return NULL;
+
+       if (uuid_str2bin(uuid, u))
+               return NULL;
+
+       ret = wps_er_nfc_config_token(wpa_s->wps_er, u);
+       if (ndef && ret) {
+               struct wpabuf *tmp;
+               tmp = ndef_build_wifi(ret);
+               wpabuf_free(ret);
+               if (tmp == NULL)
+                       return NULL;
+               ret = tmp;
+       }
+
+       return ret;
+}
+#endif /* CONFIG_WPS_NFC */
+
+
 static int callbacks_pending = 0;
 
 static void wpas_wps_terminate_cb(void *ctx)
@@ -1717,6 +1771,9 @@ void wpas_wps_update_config(struct wpa_supplicant *wpa_s)
                          wps->dev.num_sec_dev_types * WPS_DEV_TYPE_LEN);
        }
 
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_VENDOR_EXTENSION)
+               wpas_wps_set_vendor_ext_m1(wpa_s, wps);
+
        if (wpa_s->conf->changed_parameters & CFG_CHANGED_OS_VERSION)
                wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version);
 
@@ -1733,3 +1790,132 @@ void wpas_wps_update_config(struct wpa_supplicant *wpa_s)
                wps->dev.serial_number = wpa_s->conf->serial_number;
        }
 }
+
+
+#ifdef CONFIG_WPS_NFC
+
+struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef)
+{
+       return wps_nfc_token_gen(ndef, &wpa_s->conf->wps_nfc_dev_pw_id,
+                                &wpa_s->conf->wps_nfc_dh_pubkey,
+                                &wpa_s->conf->wps_nfc_dh_privkey,
+                                &wpa_s->conf->wps_nfc_dev_pw);
+}
+
+
+int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+       struct wps_context *wps = wpa_s->wps;
+       char pw[32 * 2 + 1];
+
+       if (wpa_s->conf->wps_nfc_dh_pubkey == NULL ||
+           wpa_s->conf->wps_nfc_dh_privkey == NULL ||
+           wpa_s->conf->wps_nfc_dev_pw == NULL)
+               return -1;
+
+       dh5_free(wps->dh_ctx);
+       wpabuf_free(wps->dh_pubkey);
+       wpabuf_free(wps->dh_privkey);
+       wps->dh_privkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_privkey);
+       wps->dh_pubkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_pubkey);
+       if (wps->dh_privkey == NULL || wps->dh_pubkey == NULL) {
+               wps->dh_ctx = NULL;
+               wpabuf_free(wps->dh_pubkey);
+               wps->dh_pubkey = NULL;
+               wpabuf_free(wps->dh_privkey);
+               wps->dh_privkey = NULL;
+               return -1;
+       }
+       wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, wps->dh_pubkey);
+       if (wps->dh_ctx == NULL)
+               return -1;
+
+       wpa_snprintf_hex_uppercase(pw, sizeof(pw),
+                                  wpabuf_head(wpa_s->conf->wps_nfc_dev_pw),
+                                  wpabuf_len(wpa_s->conf->wps_nfc_dev_pw));
+       return wpas_wps_start_pin(wpa_s, bssid, pw, 0,
+                                 wpa_s->conf->wps_nfc_dev_pw_id);
+}
+
+
+static int wpas_wps_use_cred(struct wpa_supplicant *wpa_s,
+                            struct wps_parse_attr *attr)
+{
+       if (wps_oob_use_cred(wpa_s->wps, attr) < 0)
+               return -1;
+
+       if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
+               return 0;
+
+       wpa_printf(MSG_DEBUG, "WPS: Request reconnection with new network "
+                  "based on the received credential added");
+       wpa_s->normal_scans = 0;
+       wpa_supplicant_reinit_autoscan(wpa_s);
+       wpa_s->disconnected = 0;
+       wpa_s->reassociate = 1;
+       wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+       return 0;
+}
+
+
+static int wpas_wps_add_nfc_password_token(struct wpa_supplicant *wpa_s,
+                                          struct wps_parse_attr *attr)
+{
+       return wps_registrar_add_nfc_password_token(
+               wpa_s->wps->registrar, attr->oob_dev_password,
+               attr->oob_dev_password_len);
+}
+
+
+static int wpas_wps_nfc_tag_process(struct wpa_supplicant *wpa_s,
+                                   const struct wpabuf *wps)
+{
+       struct wps_parse_attr attr;
+
+       wpa_hexdump_buf(MSG_DEBUG, "WPS: Received NFC tag payload", wps);
+
+       if (wps_parse_msg(wps, &attr)) {
+               wpa_printf(MSG_DEBUG, "WPS: Ignore invalid data from NFC tag");
+               return -1;
+       }
+
+       if (attr.num_cred)
+               return wpas_wps_use_cred(wpa_s, &attr);
+
+#ifdef CONFIG_WPS_ER
+       if (attr.oob_dev_password)
+               return wpas_wps_add_nfc_password_token(wpa_s, &attr);
+#endif /* CONFIG_WPS_ER */
+
+       wpa_printf(MSG_DEBUG, "WPS: Ignore unrecognized NFC tag");
+       return -1;
+}
+
+
+int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,
+                         const struct wpabuf *data)
+{
+       const struct wpabuf *wps = data;
+       struct wpabuf *tmp = NULL;
+       int ret;
+
+       if (wpabuf_len(data) < 4)
+               return -1;
+
+       if (*wpabuf_head_u8(data) != 0x10) {
+               /* Assume this contains full NDEF record */
+               tmp = ndef_parse_wifi(data);
+               if (tmp == NULL) {
+                       wpa_printf(MSG_DEBUG, "WPS: Could not parse NDEF");
+                       return -1;
+               }
+               wps = tmp;
+       }
+
+       ret = wpas_wps_nfc_tag_process(wpa_s, wps);
+       wpabuf_free(tmp);
+       return ret;
+}
+
+#endif /* CONFIG_WPS_NFC */
index a5472a0..5a49a8f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * wpa_supplicant / WPS integration
- * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -59,9 +59,15 @@ int wpas_wps_er_set_config(struct wpa_supplicant *wpa_s, const char *uuid,
                           int id);
 int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid,
                       const char *pin, struct wps_new_ap_settings *settings);
+struct wpabuf * wpas_wps_er_nfc_config_token(struct wpa_supplicant *wpa_s,
+                                            int ndef, const char *uuid);
 int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s);
 int wpas_wps_in_progress(struct wpa_supplicant *wpa_s);
 void wpas_wps_update_config(struct wpa_supplicant *wpa_s);
+struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef);
+int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,
+                         const struct wpabuf *data);
 
 #else /* CONFIG_WPS */