OSDN Git Service

Accumulative patch from commit f5f37d3a4fc2df2a24676b4f95afca15ed793cba
authorDmitry Shmidt <dimitrysh@google.com>
Mon, 3 Dec 2012 23:08:10 +0000 (15:08 -0800)
committerDmitry Shmidt <dimitrysh@google.com>
Thu, 20 Dec 2012 18:35:12 +0000 (10:35 -0800)
Author: Jouni Malinen <j@w1.fi>
Date:   Sun Nov 25 22:05:32 2012 +0200

   Fix REAUTHENTICATE command after PMKSA caching

   The current PMKSA cache entry needs to be clear to allow EAPOL
   reauthentication to be started in case this association used PMKSA
   caching.

 - Remove old WPS_OOB NCF
 - WPS: Add preliminary NFC connection handover support for Enrollee
 - WPS: Reenable the networks disabled during wpa_wpas_reassoc
 - P2P: Avoid multi-channel scans when they are not needed
 - P2P: Allow discoverable interval for p2p_find to be configured
 - P2P: Allow all channels with multi-channel concurrency
 - Bonjour changes
 - Remove disassociate
 - HS 2.0 changes
 - Add preliminary support for using SQLite for eap_user database
 - Add SAE support
 - Add disallow_aps parameter to disallow BSSIDs/SSIDs

Change-Id: I85358a05b39d46b8db49acdad667e771c580b05c
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
130 files changed:
hostapd/Android.mk
hostapd/ChangeLog
hostapd/Makefile
hostapd/config_file.c
hostapd/ctrl_iface.c
hostapd/defconfig
hostapd/hostapd.conf
hostapd/hostapd.eap_user_sqlite [new file with mode: 0644]
hostapd/hostapd_cli.c
src/ap/ap_config.c
src/ap/ap_config.h
src/ap/authsrv.c
src/ap/ctrl_iface_ap.c
src/ap/drv_callbacks.c
src/ap/eap_user_db.c [new file with mode: 0644]
src/ap/hostapd.c
src/ap/hostapd.h
src/ap/ieee802_11.c
src/ap/ieee802_11_auth.c
src/ap/ieee802_11_auth.h
src/ap/ieee802_11_vht.c
src/ap/ieee802_1x.c
src/ap/pmksa_cache_auth.c
src/ap/sta_info.c
src/ap/sta_info.h
src/ap/tkip_countermeasures.c
src/ap/tkip_countermeasures.h
src/ap/wpa_auth.c
src/ap/wpa_auth.h
src/ap/wpa_auth_glue.c
src/ap/wpa_auth_ie.c
src/ap/wps_hostapd.c
src/ap/wps_hostapd.h
src/common/defs.h
src/common/ieee802_11_defs.h
src/common/wpa_common.c
src/common/wpa_common.h
src/crypto/md5-internal.c
src/drivers/driver.h
src/drivers/driver_atheros.c
src/drivers/driver_bsd.c
src/drivers/driver_ndis.c
src/drivers/driver_nl80211.c
src/drivers/driver_privsep.c
src/drivers/driver_test.c
src/drivers/driver_wext.c
src/drivers/netlink.c
src/drivers/nl80211_copy.h
src/eap_peer/eap.c
src/eap_peer/eap_tls_common.c
src/eap_server/eap_server_aka.c
src/eap_server/eap_server_sim.c
src/eap_server/eap_server_tls_common.c
src/eapol_supp/eapol_supp_sm.c
src/p2p/p2p.c
src/p2p/p2p.h
src/p2p/p2p_build.c
src/p2p/p2p_go_neg.c
src/p2p/p2p_i.h
src/p2p/p2p_pd.c
src/radius/radius.c
src/radius/radius.h
src/rsn_supp/pmksa_cache.c
src/rsn_supp/pmksa_cache.h
src/rsn_supp/wpa.c
src/rsn_supp/wpa.h
src/rsn_supp/wpa_i.h
src/rsn_supp/wpa_ie.c
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
src/wps/wps_attr_process.c
src/wps/wps_common.c
src/wps/wps_enrollee.c
src/wps/wps_i.h
src/wps/wps_nfc.c [deleted file]
src/wps/wps_nfc_pn531.c [deleted file]
src/wps/wps_registrar.c
src/wps/wps_ufd.c [deleted file]
wpa_supplicant/Android.mk
wpa_supplicant/ChangeLog
wpa_supplicant/Makefile
wpa_supplicant/README-WPS
wpa_supplicant/ap.c
wpa_supplicant/ap.h
wpa_supplicant/autoscan.c
wpa_supplicant/bgscan_learn.c
wpa_supplicant/blacklist.c
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/config_winreg.c
wpa_supplicant/ctrl_iface.c
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_wps.c
wpa_supplicant/dbus/dbus_old_handlers.c
wpa_supplicant/driver_i.h
wpa_supplicant/events.c
wpa_supplicant/examples/wps-nfc.py [new file with mode: 0755]
wpa_supplicant/gas_query.c
wpa_supplicant/hs20_supplicant.c
wpa_supplicant/interworking.c
wpa_supplicant/interworking.h
wpa_supplicant/notify.c
wpa_supplicant/p2p_supplicant.c
wpa_supplicant/p2p_supplicant.h
wpa_supplicant/preauth_test.c
wpa_supplicant/scan.c
wpa_supplicant/sme.c
wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in [new file with mode: 0644]
wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in [new file with mode: 0644]
wpa_supplicant/systemd/wpa_supplicant.service.arg.in [new file with mode: 0644]
wpa_supplicant/systemd/wpa_supplicant.service.in [new file with mode: 0644]
wpa_supplicant/utils/log2pcap.py [new file with mode: 0755]
wpa_supplicant/wpa_cli.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 cea6aa1..4ef1b2e 100644 (file)
@@ -87,6 +87,7 @@ OBJS += src/ap/utils.c
 OBJS += src/ap/authsrv.c
 OBJS += src/ap/ieee802_1x.c
 OBJS += src/ap/ap_config.c
+OBJS += src/ap/eap_user_db.c
 OBJS += src/ap/ieee802_11_auth.c
 OBJS += src/ap/sta_info.c
 OBJS += src/ap/wpa_auth.c
@@ -215,6 +216,10 @@ NEED_AES_OMAC1=y
 NEED_AES_UNWRAP=y
 endif
 
+ifdef CONFIG_SAE
+L_CFLAGS += -DCONFIG_SAE
+endif
+
 ifdef CONFIG_IEEE80211V
 L_CFLAGS += -DCONFIG_IEEE80211V
 OBJS += src/ap/wnm_ap.c
@@ -402,25 +407,10 @@ NEED_AES_CBC=y
 NEED_MODEXP=y
 CONFIG_EAP=y
 
-ifdef CONFIG_WPS_UFD
-L_CFLAGS += -DCONFIG_WPS_UFD
-OBJS += src/wps/wps_ufd.c
-NEED_WPS_OOB=y
-endif
-
 ifdef CONFIG_WPS_NFC
 L_CFLAGS += -DCONFIG_WPS_NFC
 OBJS += src/wps/ndef.c
-OBJS += src/wps/wps_nfc.c
 NEED_WPS_OOB=y
-ifdef CONFIG_WPS_NFC_PN531
-PN531_PATH ?= /usr/local/src/nfc
-L_CFLAGS += -DCONFIG_WPS_NFC_PN531
-L_CFLAGS += -I${PN531_PATH}/inc
-OBJS += src/wps/wps_nfc_pn531.c
-LIBS += ${PN531_PATH}/lib/wpsnfc.dll
-LIBS += ${PN531_PATH}/lib/libnfc_mapping_pn53x.dll
-endif
 endif
 
 ifdef NEED_WPS_OOB
@@ -536,10 +526,6 @@ ifeq ($(CONFIG_TLS), gnutls)
 ifdef TLS_FUNCS
 OBJS += src/crypto/tls_gnutls.c
 LIBS += -lgnutls -lgpg-error
-ifdef CONFIG_GNUTLS_EXTRA
-L_CFLAGS += -DCONFIG_GNUTLS_EXTRA
-LIBS += -lgnutls-extra
-endif
 endif
 OBJS += src/crypto/crypto_gnutls.c
 HOBJS += src/crypto/crypto_gnutls.c
index 9fc05f7..e739325 100644 (file)
@@ -1,5 +1,95 @@
 ChangeLog for hostapd
 
+????-??-?? - v2.0
+       * added AP-STA-DISCONNECTED ctrl_iface event
+       * improved debug logging (human readable event names, interface name
+         included in more entries)
+       * added number of small changes to make it easier for static analyzers
+         to understand the implementation
+       * added a workaround for Windows 7 Michael MIC failure reporting and
+         use of the Secure bit in EAPOL-Key msg 3/4
+       * fixed number of small bugs (see git logs for more details)
+       * changed OpenSSL to read full certificate chain from server_cert file
+       * nl80211: number of updates to use new cfg80211/nl80211 functionality
+         - replace monitor interface with nl80211 commands
+         - additional information for driver-based AP SME
+       * EAP-pwd:
+         - fix KDF for group 21 and zero-padding
+         - added support for fragmentation
+         - increased maximum number of hunting-and-pecking iterations
+       * avoid excessive Probe Response retries for broadcast Probe Request
+         frames (only with drivers using hostapd SME/MLME)
+       * added preliminary support for using TLS v1.2 (CONFIG_TLSV12=y)
+       * fixed WPS operation stopping on dual concurrent AP
+       * added wps_rf_bands configuration parameter for overriding RF Bands
+         value for WPS
+       * added support for getting per-device PSK from RADIUS Tunnel-Password
+       * added support for libnl 3.2 and newer
+       * increased initial group key handshake retransmit timeout to 500 ms
+       * added a workaround for 4-way handshake to update SNonce even after
+         having sent EAPOL-Key 3/4 to avoid issues with some supplicant
+         implementations that can change SNonce for each EAP-Key 2/4
+       * added a workaround for EAPOL-Key 4/4 using incorrect type value in
+         WPA2 mode (some deployed stations use WPA type in that message)
+       * added a WPS workaround for mixed mode AP Settings with Windows 7
+       * changed WPS AP PIN disabling mechanism to disable the PIN after 10
+         consecutive failures in addition to using the exponential lockout
+         period
+       * added support for WFA Hotspot 2.0
+         - GAS/ANQP advertisement of network information
+         - disable_dgaf parameter to disable downstream group-addressed
+           forwarding
+       * simplified licensing terms by selecting the BSD license as the only
+         alternative
+       * EAP-SIM: fixed re-authentication not to update pseudonym
+       * EAP-SIM: use Notification round before EAP-Failure
+       * EAP-AKA: added support for AT_COUNTER_TOO_SMALL
+       * EAP-AKA: skip AKA/Identity exchange if EAP identity is recognized
+       * EAP-AKA': fixed identity for MK derivation
+       * EAP-AKA': updated to RFC 5448 (username prefixes changed); note: this
+         breaks interoperability with older versions
+       * EAP-SIM/AKA: allow pseudonym to be used after unknown reauth id
+       * changed ANonce to be a random number instead of Counter-based
+       * added support for canceling WPS operations with hostapd_cli wps_cancel
+       * fixed EAP/WPS to PSK transition on reassociation in cases where
+         deauthentication is missed
+       * hlr_auc_gw enhancements:
+         - a new command line parameter -u can be used to enable updating of
+           SQN in Milenage file
+         - use 5 bit IND for SQN updates
+         - SQLite database can now be used to store Milenage information
+       * EAP-SIM/AKA DB: added optional use of SQLite database for pseudonyms
+         and reauth data
+       * added support for Chargeable-User-Identity (RFC 4372)
+       * added radius_auth_req_attr and radius_acct_req_attr configuration
+         parameters to allow adding/overriding of RADIUS attributes in
+         Access-Request and Accounting-Request packets
+       * added support for RADIUS dynamic authorization server (RFC 5176)
+       * added initial support for WNM operations
+         - BSS max idle period
+         - WNM-Sleep Mode
+       * added new WPS NFC ctrl_iface mechanism
+         - removed obsoleted WPS_OOB command (including support for deprecated
+           UFD config_method)
+       * added FT support for drivers that implement MLME internally
+       * added SA Query support for drivers that implement MLME internally
+       * removed default ACM=1 from AC_VO and AC_VI
+       * changed VENDOR-TEST EAP method to use proper private enterprise number
+         (this will not interoperate with older versions)
+       * added hostapd.conf parameter vendor_elements to allow arbitrary vendor
+         specific elements to be added to the Beacon and Probe Response frames
+       * added support for configuring GCMP cipher for IEEE 802.11ad
+       * added support for 256-bit AES with internal TLS implementation
+       * changed EAPOL transmission to use AC_VO if WMM is active
+       * fixed EAP-TLS/PEAP/TTLS/FAST server to validate TLS Message Length
+         correctly; invalid messages could have caused the hostapd process to
+         terminate before this fix [CVE-2012-4445]
+       * limit number of active wildcard PINs for WPS Registrar to one to avoid
+         confusing behavior with multiple wildcard PINs
+       * added a workaround for WPS PBC session overlap detection to avoid
+         interop issues with deployed station implementations that do not
+         remove active PBC indication from Probe Request frames properly
+
 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
index f5dfce0..4cc3805 100644 (file)
@@ -43,6 +43,7 @@ OBJS += ../src/ap/utils.o
 OBJS += ../src/ap/authsrv.o
 OBJS += ../src/ap/ieee802_1x.o
 OBJS += ../src/ap/ap_config.o
+OBJS += ../src/ap/eap_user_db.o
 OBJS += ../src/ap/ieee802_11_auth.o
 OBJS += ../src/ap/sta_info.o
 OBJS += ../src/ap/wpa_auth.o
@@ -171,6 +172,10 @@ NEED_AES_OMAC1=y
 NEED_AES_UNWRAP=y
 endif
 
+ifdef CONFIG_SAE
+CFLAGS += -DCONFIG_SAE
+endif
+
 ifdef CONFIG_IEEE80211V
 CFLAGS += -DCONFIG_IEEE80211V
 OBJS += ../src/ap/wnm_ap.o
@@ -357,25 +362,10 @@ NEED_AES_CBC=y
 NEED_MODEXP=y
 CONFIG_EAP=y
 
-ifdef CONFIG_WPS_UFD
-CFLAGS += -DCONFIG_WPS_UFD
-OBJS += ../src/wps/wps_ufd.o
-NEED_WPS_OOB=y
-endif
-
 ifdef CONFIG_WPS_NFC
 CFLAGS += -DCONFIG_WPS_NFC
 OBJS += ../src/wps/ndef.o
-OBJS += ../src/wps/wps_nfc.o
 NEED_WPS_OOB=y
-ifdef CONFIG_WPS_NFC_PN531
-PN531_PATH ?= /usr/local/src/nfc
-CFLAGS += -DCONFIG_WPS_NFC_PN531
-CFLAGS += -I${PN531_PATH}/inc
-OBJS += ../src/wps/wps_nfc_pn531.o
-LIBS += ${PN531_PATH}/lib/wpsnfc.dll
-LIBS += ${PN531_PATH}/lib/libnfc_mapping_pn53x.dll
-endif
 endif
 
 ifdef NEED_WPS_OOB
index 0a24ec3..8af8157 100644 (file)
@@ -200,6 +200,12 @@ static int hostapd_config_read_eap_user(const char *fname,
        if (!fname)
                return 0;
 
+       if (os_strncmp(fname, "sqlite:", 7) == 0) {
+               os_free(conf->eap_user_sqlite);
+               conf->eap_user_sqlite = os_strdup(fname + 7);
+               return 0;
+       }
+
        f = fopen(fname, "r");
        if (!f) {
                wpa_printf(MSG_ERROR, "EAP user file '%s' not found.", fname);
@@ -624,6 +630,12 @@ static int hostapd_config_parse_key_mgmt(int line, const char *value)
                else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
                        val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
 #endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+               else if (os_strcmp(start, "SAE") == 0)
+                       val |= WPA_KEY_MGMT_SAE;
+               else if (os_strcmp(start, "FT-SAE") == 0)
+                       val |= WPA_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
                else {
                        wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
                                   line, start);
@@ -2512,6 +2524,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                } else if (os_strcmp(buf, "vht_oper_centr_freq_seg0_idx") == 0)
                {
                        conf->vht_oper_centr_freq_seg0_idx = atoi(pos);
+               } else if (os_strcmp(buf, "vht_oper_centr_freq_seg1_idx") == 0)
+               {
+                       conf->vht_oper_centr_freq_seg1_idx = atoi(pos);
 #endif /* CONFIG_IEEE80211AC */
                } else if (os_strcmp(buf, "max_listen_interval") == 0) {
                        bss->max_listen_interval = atoi(pos);
index 1b8bede..ccc018e 100644 (file)
@@ -250,30 +250,6 @@ static int hostapd_ctrl_iface_wps_check_pin(
 }
 
 
-#ifdef CONFIG_WPS_OOB
-static int hostapd_ctrl_iface_wps_oob(struct hostapd_data *hapd, char *txt)
-{
-       char *path, *method, *name;
-
-       path = os_strchr(txt, ' ');
-       if (path == NULL)
-               return -1;
-       *path++ = '\0';
-
-       method = os_strchr(path, ' ');
-       if (method == NULL)
-               return -1;
-       *method++ = '\0';
-
-       name = os_strchr(method, ' ');
-       if (name != NULL)
-               *name++ = '\0';
-
-       return hostapd_wps_start_oob(hapd, txt, path, method, name);
-}
-#endif /* CONFIG_WPS_OOB */
-
-
 #ifdef CONFIG_WPS_NFC
 static int hostapd_ctrl_iface_wps_nfc_tag_read(struct hostapd_data *hapd,
                                               char *pos)
@@ -912,11 +888,6 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
        } 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))
-                       reply_len = -1;
-#endif /* CONFIG_WPS_OOB */
        } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
                reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11,
                                                          reply, reply_size);
index 204aa76..b5ddca3 100644 (file)
@@ -265,5 +265,5 @@ CONFIG_IPV6=y
 # Hotspot 2.0
 #CONFIG_HS20=y
 
-# Enable SQLite database support in hlr_auc_gw
+# Enable SQLite database support in hlr_auc_gw, EAP-SIM DB, and eap_user_file
 #CONFIG_SQLITE=y
index edbd772..c839ad0 100644 (file)
@@ -572,6 +572,12 @@ wmm_ac_vo_acm=0
 # which is channel 42 in 5G band
 #
 #vht_oper_centr_freq_seg0_idx=42
+#
+# center freq = 5 GHz + (5 * index)
+# So index 159 gives center freq 5.795 GHz
+# which is channel 159 in 5G band
+#
+#vht_oper_centr_freq_seg1_idx=159
 
 ##### IEEE 802.1X-2004 related configuration ##################################
 
@@ -629,6 +635,8 @@ eapol_key_index_workaround=0
 eap_server=0
 
 # Path for EAP server user database
+# If SQLite support is included, this can be set to "sqlite:/path/to/sqlite.db"
+# to use SQLite database instead of a text file.
 #eap_user_file=/etc/hostapd.eap_user
 
 # CA certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS
diff --git a/hostapd/hostapd.eap_user_sqlite b/hostapd/hostapd.eap_user_sqlite
new file mode 100644 (file)
index 0000000..f688327
--- /dev/null
@@ -0,0 +1,17 @@
+CREATE TABLE users(
+       identity TEXT PRIMARY KEY,
+       methods TEXT,
+       password TEXT,
+       phase2 INTEGER
+);
+
+CREATE TABLE wildcards(
+       identity TEXT PRIMARY KEY,
+       methods TEXT
+);
+
+INSERT INTO users(identity,methods,password,phase2) VALUES ('user','TTLS-MSCHAPV2','password',1);
+INSERT INTO users(identity,methods,password,phase2) VALUES ('DOMAIN\mschapv2 user','TTLS-MSCHAPV2','password',1);
+
+INSERT INTO wildcards(identity,methods) VALUES ('','TTLS,TLS');
+INSERT INTO wildcards(identity,methods) VALUES ('0','AKA');
index 27bea2a..de1af3b 100644 (file)
@@ -72,9 +72,6 @@ static const char *commands_help =
 "   wps_check_pin <PIN>  verify PIN checksum\n"
 "   wps_pbc              indicate button pushed to initiate PBC\n"
 "   wps_cancel           cancel the pending WPS operation\n"
-#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"
@@ -410,40 +407,6 @@ static int hostapd_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
 }
 
 
-#ifdef CONFIG_WPS_OOB
-static int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc,
-                                  char *argv[])
-{
-       char cmd[256];
-       int res;
-
-       if (argc != 3 && argc != 4) {
-               printf("Invalid WPS_OOB command: need three or four "
-                      "arguments:\n"
-                      "- DEV_TYPE: use 'ufd' or 'nfc'\n"
-                      "- PATH: path of OOB device like '/mnt'\n"
-                      "- METHOD: OOB method 'pin-e' or 'pin-r', "
-                      "'cred'\n"
-                      "- DEV_NAME: (only for NFC) device name like "
-                      "'pn531'\n");
-               return -1;
-       }
-
-       if (argc == 3)
-               res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s",
-                                 argv[0], argv[1], argv[2]);
-       else
-               res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s",
-                                 argv[0], argv[1], argv[2], argv[3]);
-       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-               printf("Too long WPS_OOB command.\n");
-               return -1;
-       }
-       return wpa_ctrl_command(ctrl, cmd);
-}
-#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[])
@@ -809,9 +772,6 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
        { "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 },
index 31e1c19..3c699f7 100644 (file)
@@ -408,6 +408,7 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
                user = user->next;
                hostapd_config_free_eap_user(prev_user);
        }
+       os_free(conf->eap_user_sqlite);
 
        os_free(conf->dump_log_name);
        os_free(conf->eap_req_id_text);
@@ -619,57 +620,3 @@ const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
 
        return NULL;
 }
-
-
-const struct hostapd_eap_user *
-hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
-                    size_t identity_len, int phase2)
-{
-       struct hostapd_eap_user *user = conf->eap_user;
-
-#ifdef CONFIG_WPS
-       if (conf->wps_state && identity_len == WSC_ID_ENROLLEE_LEN &&
-           os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) {
-               static struct hostapd_eap_user wsc_enrollee;
-               os_memset(&wsc_enrollee, 0, sizeof(wsc_enrollee));
-               wsc_enrollee.methods[0].method = eap_server_get_type(
-                       "WSC", &wsc_enrollee.methods[0].vendor);
-               return &wsc_enrollee;
-       }
-
-       if (conf->wps_state && identity_len == WSC_ID_REGISTRAR_LEN &&
-           os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) {
-               static struct hostapd_eap_user wsc_registrar;
-               os_memset(&wsc_registrar, 0, sizeof(wsc_registrar));
-               wsc_registrar.methods[0].method = eap_server_get_type(
-                       "WSC", &wsc_registrar.methods[0].vendor);
-               wsc_registrar.password = (u8 *) conf->ap_pin;
-               wsc_registrar.password_len = conf->ap_pin ?
-                       os_strlen(conf->ap_pin) : 0;
-               return &wsc_registrar;
-       }
-#endif /* CONFIG_WPS */
-
-       while (user) {
-               if (!phase2 && user->identity == NULL) {
-                       /* Wildcard match */
-                       break;
-               }
-
-               if (user->phase2 == !!phase2 && user->wildcard_prefix &&
-                   identity_len >= user->identity_len &&
-                   os_memcmp(user->identity, identity, user->identity_len) ==
-                   0) {
-                       /* Wildcard prefix match */
-                       break;
-               }
-
-               if (user->phase2 == !!phase2 &&
-                   user->identity_len == identity_len &&
-                   os_memcmp(user->identity, identity, identity_len) == 0)
-                       break;
-               user = user->next;
-       }
-
-       return user;
-}
index f5e4a6a..71313c0 100644 (file)
@@ -96,6 +96,11 @@ struct hostapd_vlan {
 };
 
 #define PMK_LEN 32
+struct hostapd_sta_wpa_psk_short {
+       struct hostapd_sta_wpa_psk_short *next;
+       u8 psk[PMK_LEN];
+};
+
 struct hostapd_wpa_psk {
        struct hostapd_wpa_psk *next;
        int group;
@@ -192,6 +197,7 @@ struct hostapd_bss_config {
        int eap_server; /* Use internal EAP server instead of external
                         * RADIUS server */
        struct hostapd_eap_user *eap_user;
+       char *eap_user_sqlite;
        char *eap_sim_db;
        struct hostapd_ip_addr own_ip_addr;
        char *nas_identifier;
@@ -505,6 +511,7 @@ struct hostapd_config {
        int require_vht;
        u8 vht_oper_chwidth;
        u8 vht_oper_centr_freq_seg0_idx;
+       u8 vht_oper_centr_freq_seg1_idx;
 };
 
 
@@ -523,9 +530,6 @@ const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
 int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf);
 const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan,
                                        int vlan_id);
-const struct hostapd_eap_user *
-hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
-                    size_t identity_len, int phase2);
 struct hostapd_radius_attr *
 hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type);
 
index 5c03f45..d66d97e 100644 (file)
@@ -92,7 +92,7 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
        os_memset(&srv, 0, sizeof(srv));
        srv.client_file = conf->radius_server_clients;
        srv.auth_port = conf->radius_server_auth_port;
-       srv.conf_ctx = conf;
+       srv.conf_ctx = hapd;
        srv.eap_sim_db_priv = hapd->eap_sim_db_priv;
        srv.ssl_ctx = hapd->ssl_ctx;
        srv.msg_ctx = hapd->msg_ctx;
index ab9c83e..c55d3fe 100644 (file)
 #include "ap_drv_ops.h"
 
 
+static int hostapd_get_sta_conn_time(struct sta_info *sta,
+                                    char *buf, size_t buflen)
+{
+       struct os_time now, age;
+       int len = 0, ret;
+
+       if (!sta->connected_time.sec)
+               return 0;
+
+       os_get_time(&now);
+       os_time_sub(&now, &sta->connected_time, &age);
+
+       ret = os_snprintf(buf + len, buflen - len, "connected_time=%u\n",
+                         (unsigned int) age.sec);
+       if (ret < 0 || (size_t) ret >= buflen - len)
+               return len;
+       len += ret;
+
+       return len;
+}
+
+
 static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
                                      struct sta_info *sta,
                                      char *buf, size_t buflen)
@@ -58,6 +80,10 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
        if (res >= 0)
                len += res;
 
+       res = hostapd_get_sta_conn_time(sta, buf + len, buflen - len);
+       if (res >= 0)
+               len += res;
+
        return len;
 }
 
index 23fa241..8613975 100644 (file)
@@ -109,6 +109,15 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
        }
 #endif /* CONFIG_P2P */
 
+#ifdef CONFIG_HS20
+       wpabuf_free(sta->hs20_ie);
+       if (elems.hs20 && elems.hs20_len > 4) {
+               sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
+                                                elems.hs20_len - 4);
+       } else
+               sta->hs20_ie = NULL;
+#endif /* CONFIG_HS20 */
+
        if (hapd->conf->wpa) {
                if (ie == NULL || ielen == 0) {
 #ifdef CONFIG_WPS
@@ -672,12 +681,15 @@ static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
                                   const u8 *data, size_t data_len)
 {
        struct hostapd_iface *iface = hapd->iface;
+       struct sta_info *sta;
        size_t j;
 
        for (j = 0; j < iface->num_bss; j++) {
-               if (ap_get_sta(iface->bss[j], src)) {
-                       hapd = iface->bss[j];
-                       break;
+               if ((sta = ap_get_sta(iface->bss[j], src))) {
+                       if (sta->flags & WLAN_STA_ASSOC) {
+                               hapd = iface->bss[j];
+                               break;
+                       }
                }
        }
 
diff --git a/src/ap/eap_user_db.c b/src/ap/eap_user_db.c
new file mode 100644 (file)
index 0000000..79d50e5
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * hostapd / EAP user database
+ * 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"
+#ifdef CONFIG_SQLITE
+#include <sqlite3.h>
+#endif /* CONFIG_SQLITE */
+
+#include "common.h"
+#include "eap_common/eap_wsc_common.h"
+#include "eap_server/eap_methods.h"
+#include "eap_server/eap.h"
+#include "ap_config.h"
+#include "hostapd.h"
+
+#ifdef CONFIG_SQLITE
+
+static void set_user_methods(struct hostapd_eap_user *user, const char *methods)
+{
+       char *buf, *start;
+       int num_methods;
+
+       buf = os_strdup(methods);
+       if (buf == NULL)
+               return;
+
+       os_memset(&user->methods, 0, sizeof(user->methods));
+       num_methods = 0;
+       start = buf;
+       while (*start) {
+               char *pos3 = os_strchr(start, ',');
+               if (pos3)
+                       *pos3++ = '\0';
+               user->methods[num_methods].method =
+                       eap_server_get_type(start,
+                                           &user->methods[num_methods].vendor);
+               if (user->methods[num_methods].vendor == EAP_VENDOR_IETF &&
+                   user->methods[num_methods].method == EAP_TYPE_NONE) {
+                       if (os_strcmp(start, "TTLS-PAP") == 0) {
+                               user->ttls_auth |= EAP_TTLS_AUTH_PAP;
+                               goto skip_eap;
+                       }
+                       if (os_strcmp(start, "TTLS-CHAP") == 0) {
+                               user->ttls_auth |= EAP_TTLS_AUTH_CHAP;
+                               goto skip_eap;
+                       }
+                       if (os_strcmp(start, "TTLS-MSCHAP") == 0) {
+                               user->ttls_auth |= EAP_TTLS_AUTH_MSCHAP;
+                               goto skip_eap;
+                       }
+                       if (os_strcmp(start, "TTLS-MSCHAPV2") == 0) {
+                               user->ttls_auth |= EAP_TTLS_AUTH_MSCHAPV2;
+                               goto skip_eap;
+                       }
+                       wpa_printf(MSG_INFO, "DB: Unsupported EAP type '%s'",
+                                  start);
+                       os_free(buf);
+                       return;
+               }
+
+               num_methods++;
+               if (num_methods >= EAP_MAX_METHODS)
+                       break;
+       skip_eap:
+               if (pos3 == NULL)
+                       break;
+               start = pos3;
+       }
+
+       os_free(buf);
+}
+
+
+static int get_user_cb(void *ctx, int argc, char *argv[], char *col[])
+{
+       struct hostapd_eap_user *user = ctx;
+       int i;
+
+       for (i = 0; i < argc; i++) {
+               if (os_strcmp(col[i], "password") == 0 && argv[i]) {
+                       os_free(user->password);
+                       user->password_len = os_strlen(argv[i]);
+                       user->password = (u8 *) os_strdup(argv[i]);
+                       user->next = (void *) 1;
+               } else if (os_strcmp(col[i], "methods") == 0 && argv[i]) {
+                       set_user_methods(user, argv[i]);
+               }
+       }
+
+       return 0;
+}
+
+
+static int get_wildcard_cb(void *ctx, int argc, char *argv[], char *col[])
+{
+       struct hostapd_eap_user *user = ctx;
+       int i, id = -1, methods = -1;
+       size_t len;
+
+       for (i = 0; i < argc; i++) {
+               if (os_strcmp(col[i], "identity") == 0 && argv[i])
+                       id = i;
+               else if (os_strcmp(col[i], "methods") == 0 && argv[i])
+                       methods = i;
+       }
+
+       if (id < 0 || methods < 0)
+               return 0;
+
+       len = os_strlen(argv[id]);
+       if (len <= user->identity_len &&
+           os_memcmp(argv[id], user->identity, len) == 0 &&
+           (user->password == NULL || len > user->password_len)) {
+               os_free(user->password);
+               user->password_len = os_strlen(argv[id]);
+               user->password = (u8 *) os_strdup(argv[id]);
+               user->next = (void *) 1;
+               set_user_methods(user, argv[methods]);
+       }
+
+       return 0;
+}
+
+
+static const struct hostapd_eap_user *
+eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
+                   size_t identity_len, int phase2)
+{
+       sqlite3 *db;
+       struct hostapd_eap_user *user = NULL;
+       char id_str[256], cmd[300];
+       size_t i;
+
+       if (identity_len >= sizeof(id_str))
+               return NULL;
+       os_memcpy(id_str, identity, identity_len);
+       id_str[identity_len] = '\0';
+       for (i = 0; i < identity_len; i++) {
+               if (id_str[i] >= 'a' && id_str[i] <= 'z')
+                       continue;
+               if (id_str[i] >= 'A' && id_str[i] <= 'Z')
+                       continue;
+               if (id_str[i] >= '0' && id_str[i] <= '9')
+                       continue;
+               if (id_str[i] == '-' || id_str[i] == '_' || id_str[i] == '.' ||
+                   id_str[i] == ',' || id_str[i] == '@' || id_str[i] == '\\' ||
+                   id_str[i] == '!' || id_str[i] == '#' || id_str[i] == '%' ||
+                   id_str[i] == '=' || id_str[i] == ' ')
+                       continue;
+               wpa_printf(MSG_INFO, "DB: Unsupported character in identity");
+               return NULL;
+       }
+
+       os_free(hapd->tmp_eap_user.identity);
+       os_free(hapd->tmp_eap_user.password);
+       os_memset(&hapd->tmp_eap_user, 0, sizeof(hapd->tmp_eap_user));
+       hapd->tmp_eap_user.phase2 = phase2;
+       hapd->tmp_eap_user.identity = os_zalloc(identity_len + 1);
+       if (hapd->tmp_eap_user.identity == NULL)
+               return NULL;
+       os_memcpy(hapd->tmp_eap_user.identity, identity, identity_len);
+
+       if (sqlite3_open(hapd->conf->eap_user_sqlite, &db)) {
+               wpa_printf(MSG_INFO, "DB: Failed to open database %s: %s",
+                          hapd->conf->eap_user_sqlite, sqlite3_errmsg(db));
+               sqlite3_close(db);
+               return NULL;
+       }
+
+       os_snprintf(cmd, sizeof(cmd),
+                   "SELECT password,methods FROM users WHERE "
+                   "identity='%s' AND phase2=%d;", id_str, phase2);
+       wpa_printf(MSG_DEBUG, "DB: %s", cmd);
+       if (sqlite3_exec(db, cmd, get_user_cb, &hapd->tmp_eap_user, NULL) !=
+           SQLITE_OK) {
+               wpa_printf(MSG_DEBUG, "DB: Failed to complete SQL operation");
+       } else if (hapd->tmp_eap_user.next)
+               user = &hapd->tmp_eap_user;
+
+       if (user == NULL && !phase2) {
+               os_snprintf(cmd, sizeof(cmd),
+                           "SELECT identity,methods FROM wildcards;");
+               wpa_printf(MSG_DEBUG, "DB: %s", cmd);
+               if (sqlite3_exec(db, cmd, get_wildcard_cb, &hapd->tmp_eap_user,
+                                NULL) != SQLITE_OK) {
+                       wpa_printf(MSG_DEBUG, "DB: Failed to complete SQL "
+                                  "operation");
+               } else if (hapd->tmp_eap_user.next) {
+                       user = &hapd->tmp_eap_user;
+                       os_free(user->identity);
+                       user->identity = user->password;
+                       user->identity_len = user->password_len;
+                       user->password = NULL;
+                       user->password_len = 0;
+               }
+       }
+
+       sqlite3_close(db);
+
+       return user;
+}
+
+#endif /* CONFIG_SQLITE */
+
+
+const struct hostapd_eap_user *
+hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
+                    size_t identity_len, int phase2)
+{
+       const struct hostapd_bss_config *conf = hapd->conf;
+       struct hostapd_eap_user *user = conf->eap_user;
+
+#ifdef CONFIG_WPS
+       if (conf->wps_state && identity_len == WSC_ID_ENROLLEE_LEN &&
+           os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) {
+               static struct hostapd_eap_user wsc_enrollee;
+               os_memset(&wsc_enrollee, 0, sizeof(wsc_enrollee));
+               wsc_enrollee.methods[0].method = eap_server_get_type(
+                       "WSC", &wsc_enrollee.methods[0].vendor);
+               return &wsc_enrollee;
+       }
+
+       if (conf->wps_state && identity_len == WSC_ID_REGISTRAR_LEN &&
+           os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) {
+               static struct hostapd_eap_user wsc_registrar;
+               os_memset(&wsc_registrar, 0, sizeof(wsc_registrar));
+               wsc_registrar.methods[0].method = eap_server_get_type(
+                       "WSC", &wsc_registrar.methods[0].vendor);
+               wsc_registrar.password = (u8 *) conf->ap_pin;
+               wsc_registrar.password_len = conf->ap_pin ?
+                       os_strlen(conf->ap_pin) : 0;
+               return &wsc_registrar;
+       }
+#endif /* CONFIG_WPS */
+
+       while (user) {
+               if (!phase2 && user->identity == NULL) {
+                       /* Wildcard match */
+                       break;
+               }
+
+               if (user->phase2 == !!phase2 && user->wildcard_prefix &&
+                   identity_len >= user->identity_len &&
+                   os_memcmp(user->identity, identity, user->identity_len) ==
+                   0) {
+                       /* Wildcard prefix match */
+                       break;
+               }
+
+               if (user->phase2 == !!phase2 &&
+                   user->identity_len == identity_len &&
+                   os_memcmp(user->identity, identity, identity_len) == 0)
+                       break;
+               user = user->next;
+       }
+
+#ifdef CONFIG_SQLITE
+       if (user == NULL && conf->eap_user_sqlite) {
+               return eap_user_sqlite_get(hapd, identity, identity_len,
+                                          phase2);
+       }
+#endif /* CONFIG_SQLITE */
+
+       return user;
+}
index 3429258..cef9daf 100644 (file)
@@ -273,6 +273,11 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
 #ifdef CONFIG_INTERWORKING
        gas_serv_deinit(hapd);
 #endif /* CONFIG_INTERWORKING */
+
+#ifdef CONFIG_SQLITE
+       os_free(hapd->tmp_eap_user.identity);
+       os_free(hapd->tmp_eap_user.password);
+#endif /* CONFIG_SQLITE */
 }
 
 
@@ -1113,12 +1118,13 @@ int hostapd_reload_iface(struct hostapd_iface *hapd_iface)
 int hostapd_disable_iface(struct hostapd_iface *hapd_iface)
 {
        size_t j;
-       struct hostapd_bss_config *bss = hapd_iface->bss[0]->conf;
+       struct hostapd_bss_config *bss;
        const struct wpa_driver_ops *driver;
        void *drv_priv;
 
        if (hapd_iface == NULL)
                return -1;
+       bss = hapd_iface->bss[0]->conf;
        driver = hapd_iface->bss[0]->driver;
        drv_priv = hapd_iface->bss[0]->drv_priv;
 
@@ -1373,8 +1379,10 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
        /* Start accounting here, if IEEE 802.1X and WPA are not used.
         * IEEE 802.1X/WPA code will start accounting after the station has
         * been authorized. */
-       if (!hapd->conf->ieee802_1x && !hapd->conf->wpa)
+       if (!hapd->conf->ieee802_1x && !hapd->conf->wpa) {
+               os_get_time(&sta->connected_time);
                accounting_sta_start(hapd, sta);
+       }
 
        /* Start IEEE 802.1X authentication process for new stations */
        ieee802_1x_new_station(hapd, sta);
index 71f476c..f1e7d9f 100644 (file)
@@ -10,6 +10,7 @@
 #define HOSTAPD_H
 
 #include "common/defs.h"
+#include "ap_config.h"
 
 struct wpa_driver_ops;
 struct wpa_ctrl_dst;
@@ -187,6 +188,10 @@ struct hostapd_data {
 #ifdef CONFIG_INTERWORKING
        size_t gas_frag_limit;
 #endif /* CONFIG_INTERWORKING */
+
+#ifdef CONFIG_SQLITE
+       struct hostapd_eap_user tmp_eap_user;
+#endif /* CONFIG_SQLITE */
 };
 
 
@@ -297,4 +302,8 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
 void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
                             int offset);
 
+const struct hostapd_eap_user *
+hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
+                    size_t identity_len, int phase2);
+
 #endif /* HOSTAPD_H */
index ce20e5f..a13a135 100644 (file)
@@ -49,6 +49,8 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
        num = hapd->iface->num_rates;
        if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
                num++;
+       if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
+               num++;
        if (num > 8) {
                /* rest of the rates are encoded in Extended supported
                 * rates element */
@@ -66,9 +68,15 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
                pos++;
        }
 
-       if (hapd->iconf->ieee80211n && hapd->iconf->require_ht &&
-           hapd->iface->num_rates < 8)
+       if (hapd->iconf->ieee80211n && hapd->iconf->require_ht && count < 8) {
+               count++;
                *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
+       }
+
+       if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht && count < 8) {
+               count++;
+               *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
+       }
 
        return pos;
 }
@@ -85,6 +93,8 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
        num = hapd->iface->num_rates;
        if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
                num++;
+       if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
+               num++;
        if (num <= 8)
                return eid;
        num -= 8;
@@ -103,9 +113,17 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
                pos++;
        }
 
-       if (hapd->iconf->ieee80211n && hapd->iconf->require_ht &&
-           hapd->iface->num_rates >= 8)
-               *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
+       if (hapd->iconf->ieee80211n && hapd->iconf->require_ht) {
+               count++;
+               if (count > 8)
+                       *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
+       }
+
+       if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht) {
+               count++;
+               if (count > 8)
+                       *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
+       }
 
        return pos;
 }
@@ -296,6 +314,142 @@ static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
 #endif /* CONFIG_IEEE80211R */
 
 
+#ifdef CONFIG_SAE
+
+static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
+                                            struct sta_info *sta)
+{
+       struct wpabuf *buf;
+
+       buf = wpabuf_alloc(2);
+       if (buf == NULL)
+               return NULL;
+
+       wpabuf_put_le16(buf, 19); /* Finite Cyclic Group */
+       /* TODO: Anti-Clogging Token (if requested) */
+       /* TODO: Scalar */
+       /* TODO: Element */
+
+       return buf;
+}
+
+
+static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd,
+                                             struct sta_info *sta)
+{
+       struct wpabuf *buf;
+
+       buf = wpabuf_alloc(2);
+       if (buf == NULL)
+               return NULL;
+
+       wpabuf_put_le16(buf, sta->sae_send_confirm);
+       sta->sae_send_confirm++;
+       /* TODO: Confirm */
+
+       return buf;
+}
+
+
+static u16 handle_sae_commit(struct hostapd_data *hapd, struct sta_info *sta,
+                            const u8 *data, size_t len)
+{
+       wpa_hexdump(MSG_DEBUG, "SAE commit fields", data, len);
+
+       /* Check Finite Cyclic Group */
+       if (len < 2)
+               return WLAN_STATUS_UNSPECIFIED_FAILURE;
+       if (WPA_GET_LE16(data) != 19) {
+               wpa_printf(MSG_DEBUG, "SAE: Unsupported Finite Cyclic Group %u",
+                          WPA_GET_LE16(data));
+               return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+       }
+
+       return WLAN_STATUS_SUCCESS;
+}
+
+
+static u16 handle_sae_confirm(struct hostapd_data *hapd, struct sta_info *sta,
+                             const u8 *data, size_t len)
+{
+       u16 rc;
+
+       wpa_hexdump(MSG_DEBUG, "SAE confirm fields", data, len);
+
+       if (len < 2)
+               return WLAN_STATUS_UNSPECIFIED_FAILURE;
+       rc = WPA_GET_LE16(data);
+       wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", rc);
+
+       return WLAN_STATUS_SUCCESS;
+}
+
+
+static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
+                           const struct ieee80211_mgmt *mgmt, size_t len,
+                           u8 auth_transaction)
+{
+       u16 resp = WLAN_STATUS_SUCCESS;
+       struct wpabuf *data;
+
+       if (auth_transaction == 1) {
+               hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+                              HOSTAPD_LEVEL_DEBUG,
+                              "start SAE authentication (RX commit)");
+               resp = handle_sae_commit(hapd, sta, mgmt->u.auth.variable,
+                                        ((u8 *) mgmt) + len -
+                                        mgmt->u.auth.variable);
+               if (resp == WLAN_STATUS_SUCCESS)
+                       sta->sae_state = SAE_COMMIT;
+       } else if (auth_transaction == 2) {
+               if (sta->sae_state != SAE_COMMIT) {
+                       hostapd_logger(hapd, sta->addr,
+                                      HOSTAPD_MODULE_IEEE80211,
+                                      HOSTAPD_LEVEL_DEBUG,
+                                      "SAE confirm before commit");
+                       resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
+               }
+               hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+                              HOSTAPD_LEVEL_DEBUG,
+                              "SAE authentication (RX confirm)");
+               resp = handle_sae_confirm(hapd, sta, mgmt->u.auth.variable,
+                                         ((u8 *) mgmt) + len -
+                                         mgmt->u.auth.variable);
+               if (resp == WLAN_STATUS_SUCCESS) {
+                       sta->flags |= WLAN_STA_AUTH;
+                       wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
+                       sta->auth_alg = WLAN_AUTH_SAE;
+                       mlme_authenticate_indication(hapd, sta);
+               }
+       } else {
+               hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+                              HOSTAPD_LEVEL_DEBUG,
+                              "unexpected SAE authentication transaction %u",
+                              auth_transaction);
+               resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
+       }
+
+       sta->auth_alg = WLAN_AUTH_SAE;
+
+       if (resp == WLAN_STATUS_SUCCESS) {
+               if (auth_transaction == 1)
+                       data = auth_build_sae_commit(hapd, sta);
+               else
+                       data = auth_build_sae_confirm(hapd, sta);
+               if (data == NULL)
+                       resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+       } else
+               data = NULL;
+
+       send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
+                       auth_transaction, resp,
+                       data ? wpabuf_head(data) : (u8 *) "",
+                       data ? wpabuf_len(data) : 0);
+       wpabuf_free(data);
+}
+#endif /* CONFIG_SAE */
+
+
 static void handle_auth(struct hostapd_data *hapd,
                        const struct ieee80211_mgmt *mgmt, size_t len)
 {
@@ -307,8 +461,7 @@ static void handle_auth(struct hostapd_data *hapd,
        const u8 *challenge = NULL;
        u32 session_timeout, acct_interim_interval;
        int vlan_id = 0;
-       u8 psk[PMK_LEN];
-       int has_psk = 0;
+       struct hostapd_sta_wpa_psk_short *psk = NULL;
        u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
        size_t resp_ies_len = 0;
        char *identity = NULL;
@@ -348,6 +501,10 @@ static void handle_auth(struct hostapd_data *hapd,
              (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
               auth_alg == WLAN_AUTH_FT) ||
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+             (hapd->conf->wpa && wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
+              auth_alg == WLAN_AUTH_SAE) ||
+#endif /* CONFIG_SAE */
              ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
               auth_alg == WLAN_AUTH_SHARED_KEY))) {
                printf("Unsupported authentication algorithm (%d)\n",
@@ -356,7 +513,7 @@ static void handle_auth(struct hostapd_data *hapd,
                goto fail;
        }
 
-       if (!(auth_transaction == 1 ||
+       if (!(auth_transaction == 1 || auth_alg == WLAN_AUTH_SAE ||
              (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) {
                printf("Unknown authentication transaction number (%d)\n",
                       auth_transaction);
@@ -374,7 +531,7 @@ static void handle_auth(struct hostapd_data *hapd,
        res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len,
                                      &session_timeout,
                                      &acct_interim_interval, &vlan_id,
-                                     psk, &has_psk, &identity, &radius_cui);
+                                     &psk, &identity, &radius_cui);
 
        if (res == HOSTAPD_ACL_REJECT) {
                printf("Station " MACSTR " not allowed to authenticate.\n",
@@ -413,13 +570,11 @@ static void handle_auth(struct hostapd_data *hapd,
                               HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
        }
 
-       if (has_psk && hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
-               os_free(sta->psk);
-               sta->psk = os_malloc(PMK_LEN);
-               if (sta->psk)
-                       os_memcpy(sta->psk, psk, PMK_LEN);
+       hostapd_free_psk_list(sta->psk);
+       if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
+               sta->psk = psk;
+               psk = NULL;
        } else {
-               os_free(sta->psk);
                sta->psk = NULL;
        }
 
@@ -486,11 +641,17 @@ static void handle_auth(struct hostapd_data *hapd,
                /* handle_auth_ft_finish() callback will complete auth. */
                return;
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+       case WLAN_AUTH_SAE:
+               handle_auth_sae(hapd, sta, mgmt, len, auth_transaction);
+               return;
+#endif /* CONFIG_SAE */
        }
 
  fail:
        os_free(identity);
        os_free(radius_cui);
+       hostapd_free_psk_list(psk);
 
        send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
                        auth_transaction + 1, resp, resp_ies, resp_ies_len);
@@ -779,6 +940,16 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
                }
 #endif /* CONFIG_IEEE80211R */
 
+#ifdef CONFIG_SAE
+               if (wpa_auth_uses_sae(sta->wpa_sm) &&
+                   sta->auth_alg != WLAN_AUTH_SAE) {
+                       wpa_printf(MSG_DEBUG, "SAE: " MACSTR " tried to use "
+                                  "SAE AKM after non-SAE auth_alg %u",
+                                  MAC2STR(sta->addr), sta->auth_alg);
+                       return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
+               }
+#endif /* CONFIG_SAE */
+
 #ifdef CONFIG_IEEE80211N
                if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) &&
                    wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
@@ -807,6 +978,15 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
        p2p_group_notif_assoc(hapd->p2p_group, sta->addr, ies, ies_len);
 #endif /* CONFIG_P2P */
 
+#ifdef CONFIG_HS20
+       wpabuf_free(sta->hs20_ie);
+       if (elems.hs20 && elems.hs20_len > 4) {
+               sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
+                                                elems.hs20_len - 4);
+       } else
+               sta->hs20_ie = NULL;
+#endif /* CONFIG_HS20 */
+
        return WLAN_STATUS_SUCCESS;
 }
 
index 63ae345..c311e55 100644 (file)
@@ -36,8 +36,7 @@ struct hostapd_cached_radius_acl {
        u32 session_timeout;
        u32 acct_interim_interval;
        int vlan_id;
-       int has_psk;
-       u8 psk[PMK_LEN];
+       struct hostapd_sta_wpa_psk_short *psk;
        char *identity;
        char *radius_cui;
 };
@@ -58,6 +57,7 @@ static void hostapd_acl_cache_free_entry(struct hostapd_cached_radius_acl *e)
 {
        os_free(e->identity);
        os_free(e->radius_cui);
+       hostapd_free_psk_list(e->psk);
        os_free(e);
 }
 
@@ -74,11 +74,34 @@ static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
 }
 
 
+static void copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
+                         struct hostapd_sta_wpa_psk_short *src)
+{
+       struct hostapd_sta_wpa_psk_short **copy_to;
+       struct hostapd_sta_wpa_psk_short *copy_from;
+
+       /* Copy PSK linked list */
+       copy_to = psk;
+       copy_from = src;
+       while (copy_from && copy_to) {
+               *copy_to = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short));
+               if (*copy_to == NULL)
+                       break;
+               os_memcpy(*copy_to, copy_from,
+                         sizeof(struct hostapd_sta_wpa_psk_short));
+               copy_from = copy_from->next;
+               copy_to = &((*copy_to)->next);
+       }
+       if (copy_to)
+               *copy_to = NULL;
+}
+
+
 static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
                                 u32 *session_timeout,
                                 u32 *acct_interim_interval, int *vlan_id,
-                                u8 *psk, int *has_psk, char **identity,
-                                char **radius_cui)
+                                struct hostapd_sta_wpa_psk_short **psk,
+                                char **identity, char **radius_cui)
 {
        struct hostapd_cached_radius_acl *entry;
        struct os_time now;
@@ -99,10 +122,7 @@ static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
                                entry->acct_interim_interval;
                if (vlan_id)
                        *vlan_id = entry->vlan_id;
-               if (psk)
-                       os_memcpy(psk, entry->psk, PMK_LEN);
-               if (has_psk)
-                       *has_psk = entry->has_psk;
+               copy_psk_list(psk, entry->psk);
                if (identity) {
                        if (entry->identity)
                                *identity = os_strdup(entry->identity);
@@ -200,8 +220,7 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
  * @session_timeout: Buffer for returning session timeout (from RADIUS)
  * @acct_interim_interval: Buffer for returning account interval (from RADIUS)
  * @vlan_id: Buffer for returning VLAN ID
- * @psk: Buffer for returning WPA PSK
- * @has_psk: Buffer for indicating whether psk was filled
+ * @psk: Linked list buffer for returning WPA PSK
  * @identity: Buffer for returning identity (from RADIUS)
  * @radius_cui: Buffer for returning CUI (from RADIUS)
  * Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
@@ -212,8 +231,8 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
 int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
                            const u8 *msg, size_t len, u32 *session_timeout,
                            u32 *acct_interim_interval, int *vlan_id,
-                           u8 *psk, int *has_psk, char **identity,
-                           char **radius_cui)
+                           struct hostapd_sta_wpa_psk_short **psk,
+                           char **identity, char **radius_cui)
 {
        if (session_timeout)
                *session_timeout = 0;
@@ -221,10 +240,8 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
                *acct_interim_interval = 0;
        if (vlan_id)
                *vlan_id = 0;
-       if (has_psk)
-               *has_psk = 0;
        if (psk)
-               os_memset(psk, 0, PMK_LEN);
+               *psk = NULL;
        if (identity)
                *identity = NULL;
        if (radius_cui)
@@ -253,7 +270,7 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
                /* Check whether ACL cache has an entry for this station */
                int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
                                                acct_interim_interval,
-                                               vlan_id, psk, has_psk,
+                                               vlan_id, psk,
                                                identity, radius_cui);
                if (res == HOSTAPD_ACL_ACCEPT ||
                    res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
@@ -396,6 +413,54 @@ static void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx)
 }
 
 
+static void decode_tunnel_passwords(struct hostapd_data *hapd,
+                                   const u8 *shared_secret,
+                                   size_t shared_secret_len,
+                                   struct radius_msg *msg,
+                                   struct radius_msg *req,
+                                   struct hostapd_cached_radius_acl *cache)
+{
+       int passphraselen;
+       char *passphrase, *strpassphrase;
+       size_t i;
+       struct hostapd_sta_wpa_psk_short *psk;
+
+       /*
+        * Decode all tunnel passwords as PSK and save them into a linked list.
+        */
+       for (i = 0; ; i++) {
+               passphrase = radius_msg_get_tunnel_password(
+                       msg, &passphraselen, shared_secret, shared_secret_len,
+                       req, i);
+               /*
+                * Passphrase is NULL iff there is no i-th Tunnel-Password
+                * attribute in msg.
+                */
+               if (passphrase == NULL)
+                       break;
+               /*
+                * passphrase does not contain the NULL termination.
+                * Add it here as pbkdf2_sha1() requires it.
+                */
+               strpassphrase = os_zalloc(passphraselen + 1);
+               psk = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short));
+               if (strpassphrase && psk) {
+                       os_memcpy(strpassphrase, passphrase, passphraselen);
+                       pbkdf2_sha1(strpassphrase,
+                                   hapd->conf->ssid.ssid,
+                                   hapd->conf->ssid.ssid_len, 4096,
+                                   psk->psk, PMK_LEN);
+                       psk->next = cache->psk;
+                       cache->psk = psk;
+                       psk = NULL;
+               }
+               os_free(strpassphrase);
+               os_free(psk);
+               os_free(passphrase);
+       }
+}
+
+
 /**
  * hostapd_acl_recv_radius - Process incoming RADIUS Authentication messages
  * @msg: RADIUS response message
@@ -454,8 +519,6 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
        cache->timestamp = t.sec;
        os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
        if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
-               int passphraselen;
-               char *passphrase;
                u8 *buf;
                size_t len;
 
@@ -478,27 +541,9 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
 
                cache->vlan_id = radius_msg_get_vlanid(msg);
 
-               passphrase = radius_msg_get_tunnel_password(
-                       msg, &passphraselen,
-                       hapd->conf->radius->auth_server->shared_secret,
-                       hapd->conf->radius->auth_server->shared_secret_len,
-                       req);
-               cache->has_psk = passphrase != NULL;
-               if (passphrase != NULL) {
-                       /* passphrase does not contain the NULL termination.
-                        * Add it here as pbkdf2_sha1 requires it. */
-                       char *strpassphrase = os_zalloc(passphraselen + 1);
-                       if (strpassphrase) {
-                               os_memcpy(strpassphrase, passphrase,
-                                         passphraselen);
-                               pbkdf2_sha1(strpassphrase,
-                                           hapd->conf->ssid.ssid,
-                                           hapd->conf->ssid.ssid_len, 4096,
-                                           cache->psk, PMK_LEN);
-                               os_free(strpassphrase);
-                       }
-                       os_free(passphrase);
-               }
+               decode_tunnel_passwords(hapd, shared_secret, shared_secret_len,
+                                       msg, req, cache);
+
                if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
                                            &buf, &len, NULL) == 0) {
                        cache->identity = os_zalloc(len + 1);
@@ -514,7 +559,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
                }
 
                if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
-                   !cache->has_psk)
+                   !cache->psk)
                        cache->accepted = HOSTAPD_ACL_REJECT;
        } else
                cache->accepted = HOSTAPD_ACL_REJECT;
@@ -586,3 +631,13 @@ void hostapd_acl_deinit(struct hostapd_data *hapd)
                hostapd_acl_query_free(prev);
        }
 }
+
+
+void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk)
+{
+       while (psk) {
+               struct hostapd_sta_wpa_psk_short *prev = psk;
+               psk = psk->next;
+               os_free(prev);
+       }
+}
index 0e8d1cb..2bc1065 100644 (file)
@@ -19,9 +19,10 @@ enum {
 int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
                            const u8 *msg, size_t len, u32 *session_timeout,
                            u32 *acct_interim_interval, int *vlan_id,
-                           u8 *psk, int *has_psk, char **identity,
-                           char **radius_cui);
+                           struct hostapd_sta_wpa_psk_short **psk,
+                           char **identity, char **radius_cui);
 int hostapd_acl_init(struct hostapd_data *hapd);
 void hostapd_acl_deinit(struct hostapd_data *hapd);
+void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk);
 
 #endif /* IEEE802_11_AUTH_H */
index 7599ef8..b21c2b7 100644 (file)
@@ -68,6 +68,8 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
         */
        oper->vht_op_info_chan_center_freq_seg0_idx =
                hapd->iconf->vht_oper_centr_freq_seg0_idx;
+       oper->vht_op_info_chan_center_freq_seg1_idx =
+               hapd->iconf->vht_oper_centr_freq_seg1_idx;
 
        oper->vht_op_info_chwidth = hapd->iconf->vht_oper_chwidth;
 
index c4d3da8..e1b11ba 100644 (file)
@@ -99,8 +99,10 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
                       "driver (errno=%d).\n", MAC2STR(sta->addr), errno);
        }
 
-       if (authorized)
+       if (authorized) {
+               os_get_time(&sta->connected_time);
                accounting_sta_start(hapd, sta);
+       }
 }
 
 
@@ -1684,8 +1686,7 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
        const struct hostapd_eap_user *eap_user;
        int i;
 
-       eap_user = hostapd_get_eap_user(hapd->conf, identity,
-                                       identity_len, phase2);
+       eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2);
        if (eap_user == NULL)
                return -1;
 
index ba2c033..3a9cc7b 100644 (file)
@@ -95,11 +95,9 @@ static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
 
        os_get_time(&now);
        while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
-               struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
-               pmksa->pmksa = entry->next;
                wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
-                          MACSTR, MAC2STR(entry->spa));
-               pmksa_cache_free_entry(pmksa, entry);
+                          MACSTR, MAC2STR(pmksa->pmksa->spa));
+               pmksa_cache_free_entry(pmksa, pmksa->pmksa);
        }
 
        pmksa_cache_set_expiration(pmksa);
index d61177f..6bc43d2 100644 (file)
@@ -20,6 +20,7 @@
 #include "accounting.h"
 #include "ieee802_1x.h"
 #include "ieee802_11.h"
+#include "ieee802_11_auth.h"
 #include "wpa_auth.h"
 #include "preauth_auth.h"
 #include "ap_config.h"
@@ -232,9 +233,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
 
        wpabuf_free(sta->wps_ie);
        wpabuf_free(sta->p2p_ie);
+       wpabuf_free(sta->hs20_ie);
 
        os_free(sta->ht_capabilities);
-       os_free(sta->psk);
+       hostapd_free_psk_list(sta->psk);
        os_free(sta->identity);
        os_free(sta->radius_cui);
 
index b3c57b4..d5e92fa 100644 (file)
@@ -95,7 +95,8 @@ struct sta_info {
        struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */
 
        int vlan_id;
-       u8 *psk; /* PSK from RADIUS authentication server */
+        /* PSKs from RADIUS authentication server */
+       struct hostapd_sta_wpa_psk_short *psk;
 
        char *identity; /* User-Name from RADIUS */
        char *radius_cui; /* Chargeable-User-Identity from RADIUS */
@@ -121,6 +122,14 @@ struct sta_info {
 
        struct wpabuf *wps_ie; /* WPS IE from (Re)Association Request */
        struct wpabuf *p2p_ie; /* P2P IE from (Re)Association Request */
+       struct wpabuf *hs20_ie; /* HS 2.0 IE from (Re)Association Request */
+
+       struct os_time connected_time;
+
+#ifdef CONFIG_SAE
+       enum { SAE_INIT, SAE_COMMIT, SAE_CONFIRM } sae_state;
+       u16 sae_send_confirm;
+#endif /* CONFIG_SAE */
 };
 
 
index dd5aa68..4a2ea06 100644 (file)
@@ -66,9 +66,10 @@ void ieee80211_tkip_countermeasures_deinit(struct hostapd_data *hapd)
 }
 
 
-void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
+int michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
 {
        struct os_time now;
+       int ret = 0;
 
        if (addr && local) {
                struct sta_info *sta = ap_get_sta(hapd, addr);
@@ -84,7 +85,7 @@ void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
                                   "MLME-MICHAELMICFAILURE.indication "
                                   "for not associated STA (" MACSTR
                                   ") ignored", MAC2STR(addr));
-                       return;
+                       return ret;
                }
        }
 
@@ -93,8 +94,12 @@ void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
                hapd->michael_mic_failures = 1;
        } else {
                hapd->michael_mic_failures++;
-               if (hapd->michael_mic_failures > 1)
+               if (hapd->michael_mic_failures > 1) {
                        ieee80211_tkip_countermeasures_start(hapd);
+                       ret = 1;
+               }
        }
        hapd->michael_mic_failure = now.sec;
+
+       return ret;
 }
index f7a6624..d3eaed3 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.
@@ -9,7 +9,7 @@
 #ifndef TKIP_COUNTERMEASURES_H
 #define TKIP_COUNTERMEASURES_H
 
-void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local);
+int michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local);
 void ieee80211_tkip_countermeasures_deinit(struct hostapd_data *hapd);
 
 #endif /* TKIP_COUNTERMEASURES_H */
index 49d8175..0816b25 100644 (file)
@@ -54,11 +54,12 @@ static const int dot11RSNAConfigPMKReauthThreshold = 70;
 static const int dot11RSNAConfigSATimeout = 60;
 
 
-static inline void wpa_auth_mic_failure_report(
+static inline int wpa_auth_mic_failure_report(
        struct wpa_authenticator *wpa_auth, const u8 *addr)
 {
        if (wpa_auth->cb.mic_failure_report)
-               wpa_auth->cb.mic_failure_report(wpa_auth->cb.ctx, addr);
+               return wpa_auth->cb.mic_failure_report(wpa_auth->cb.ctx, addr);
+       return 0;
 }
 
 
@@ -700,8 +701,8 @@ static int ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth,
 #endif /* CONFIG_IEEE80211R */
 
 
-static void wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
-                                    struct wpa_state_machine *sm, int group)
+static int wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
+                                   struct wpa_state_machine *sm, int group)
 {
        /* Supplicant reported a Michael MIC error */
        wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
@@ -718,7 +719,8 @@ static void wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
                                "ignore Michael MIC failure report since "
                                "pairwise cipher is not TKIP");
        } else {
-               wpa_auth_mic_failure_report(wpa_auth, sm->addr);
+               if (wpa_auth_mic_failure_report(wpa_auth, sm->addr) > 0)
+                       return 1; /* STA entry was removed */
                sm->dot11RSNAStatsTKIPRemoteMICFailures++;
                wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++;
        }
@@ -728,6 +730,7 @@ static void wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
         * Authenticator may do it, let's change the keys now anyway.
         */
        wpa_request_new_ptk(sm);
+       return 0;
 }
 
 
@@ -1081,9 +1084,10 @@ continue_processing:
 #endif /* CONFIG_PEERKEY */
                        return;
                } else if (key_info & WPA_KEY_INFO_ERROR) {
-                       wpa_receive_error_report(
-                               wpa_auth, sm,
-                               !(key_info & WPA_KEY_INFO_KEY_TYPE));
+                       if (wpa_receive_error_report(
+                                   wpa_auth, sm,
+                                   !(key_info & WPA_KEY_INFO_KEY_TYPE)) > 0)
+                               return; /* STA entry was removed */
                } else if (key_info & WPA_KEY_INFO_KEY_TYPE) {
                        wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
                                        "received EAPOL-Key Request for new "
@@ -3056,3 +3060,11 @@ void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
                                       wpa_send_eapol_timeout, wpa_auth, sm);
        }
 }
+
+
+int wpa_auth_uses_sae(struct wpa_state_machine *sm)
+{
+       if (sm == NULL)
+               return 0;
+       return wpa_key_mgmt_sae(sm->wpa_key_mgmt);
+}
index 91ba499..6ab170d 100644 (file)
@@ -177,7 +177,7 @@ struct wpa_auth_callbacks {
        void (*logger)(void *ctx, const u8 *addr, logger_level level,
                       const char *txt);
        void (*disconnect)(void *ctx, const u8 *addr, u16 reason);
-       void (*mic_failure_report)(void *ctx, const u8 *addr);
+       int (*mic_failure_report)(void *ctx, const u8 *addr);
        void (*set_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var,
                          int value);
        int (*get_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var);
@@ -291,4 +291,6 @@ int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos);
 #endif /* CONFIG_IEEE80211W */
 #endif /* CONFIG_IEEE80211V */
 
+int wpa_auth_uses_sae(struct wpa_state_machine *sm);
+
 #endif /* WPA_AUTH_H */
index bdc89e4..76c61ea 100644 (file)
@@ -112,10 +112,10 @@ static void hostapd_wpa_auth_disconnect(void *ctx, const u8 *addr,
 }
 
 
-static void hostapd_wpa_auth_mic_failure_report(void *ctx, const u8 *addr)
+static int hostapd_wpa_auth_mic_failure_report(void *ctx, const u8 *addr)
 {
        struct hostapd_data *hapd = ctx;
-       michael_mic_failure(hapd, addr, 0);
+       return michael_mic_failure(hapd, addr, 0);
 }
 
 
@@ -188,10 +188,18 @@ static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
        /*
         * This is about to iterate over all psks, prev_psk gives the last
         * returned psk which should not be returned again.
-        * logic list (all hostapd_get_psk; sta->psk)
+        * logic list (all hostapd_get_psk; all sta->psk)
         */
-       if (sta && sta->psk && !psk && sta->psk != prev_psk)
-               psk = sta->psk;
+       if (sta && sta->psk && !psk) {
+               struct hostapd_sta_wpa_psk_short *pos;
+               psk = sta->psk->psk;
+               for (pos = sta->psk; pos; pos = pos->next) {
+                       if (pos->psk == prev_psk) {
+                               psk = pos->next ? pos->next->psk : NULL;
+                               break;
+                       }
+               }
+       }
        return psk;
 }
 
index 1786230..4fd0135 100644 (file)
@@ -188,6 +188,18 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
                num_suites++;
        }
 #endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+       if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) {
+               RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
+               pos += RSN_SELECTOR_LEN;
+               num_suites++;
+       }
+       if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) {
+               RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
+               pos += RSN_SELECTOR_LEN;
+               num_suites++;
+       }
+#endif /* CONFIG_SAE */
 
 #ifdef CONFIG_RSN_TESTING
        if (rsn_testing) {
@@ -407,6 +419,12 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
                else if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
                        selector = RSN_AUTH_KEY_MGMT_PSK_SHA256;
 #endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+               else if (data.key_mgmt & WPA_KEY_MGMT_SAE)
+                       selector = RSN_AUTH_KEY_MGMT_SAE;
+               else if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE)
+                       selector = RSN_AUTH_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
                else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X)
                        selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
                else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
@@ -479,6 +497,12 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
        else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
                sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
 #endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+       else if (key_mgmt & WPA_KEY_MGMT_SAE)
+               sm->wpa_key_mgmt = WPA_KEY_MGMT_SAE;
+       else if (key_mgmt & WPA_KEY_MGMT_FT_SAE)
+               sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
        else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X)
                sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
        else
index 5e44c72..85633ec 100644 (file)
@@ -11,8 +11,6 @@
 #include "utils/common.h"
 #include "utils/eloop.h"
 #include "utils/uuid.h"
-#include "crypto/dh_groups.h"
-#include "crypto/dh_group5.h"
 #include "common/wpa_ctrl.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
@@ -1036,8 +1034,6 @@ void hostapd_deinit_wps(struct hostapd_data *hapd)
        wps_device_data_free(&hapd->wps->dev);
        wpabuf_free(hapd->wps->dh_pubkey);
        wpabuf_free(hapd->wps->dh_privkey);
-       wpabuf_free(hapd->wps->oob_conf.pubkey_hash);
-       wpabuf_free(hapd->wps->oob_conf.dev_password);
        wps_free_pending_msgs(hapd->wps->upnp_msgs);
        hostapd_wps_nfc_clear(hapd->wps);
        os_free(hapd->wps);
@@ -1155,60 +1151,6 @@ int hostapd_wps_cancel(struct hostapd_data *hapd)
 }
 
 
-#ifdef CONFIG_WPS_OOB
-int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type,
-                         char *path, char *method, char *name)
-{
-       struct wps_context *wps = hapd->wps;
-       struct oob_device_data *oob_dev;
-
-       oob_dev = wps_get_oob_device(device_type);
-       if (oob_dev == NULL)
-               return -1;
-       oob_dev->device_path = path;
-       oob_dev->device_name = name;
-       wps->oob_conf.oob_method = wps_get_oob_method(method);
-
-       if (wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_R) {
-               /*
-                * Use pre-configured DH keys in order to be able to write the
-                * key hash into the OOB file.
-                */
-               wpabuf_free(wps->dh_pubkey);
-               wpabuf_free(wps->dh_privkey);
-               wps->dh_privkey = NULL;
-               wps->dh_pubkey = dh_init(dh_groups_get(WPS_DH_GROUP),
-                                        &wps->dh_privkey);
-               wps->dh_pubkey = wpabuf_zeropad(wps->dh_pubkey, 192);
-               if (wps->dh_pubkey == NULL) {
-                       wpa_printf(MSG_ERROR, "WPS: Failed to initialize "
-                                  "Diffie-Hellman handshake");
-                       return -1;
-               }
-       }
-
-       if (wps_process_oob(wps, oob_dev, 1) < 0)
-               goto error;
-
-       if ((wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E ||
-            wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_R) &&
-           hostapd_wps_add_pin(hapd, NULL, "any",
-                               wpabuf_head(wps->oob_conf.dev_password), 0) <
-           0)
-               goto error;
-
-       return 0;
-
-error:
-       wpabuf_free(wps->dh_pubkey);
-       wps->dh_pubkey = NULL;
-       wpabuf_free(wps->dh_privkey);
-       wps->dh_privkey = NULL;
-       return -1;
-}
-#endif /* CONFIG_WPS_OOB */
-
-
 static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da,
                                    const u8 *bssid,
                                    const u8 *ie, size_t ie_len,
index f968e15..4e5026b 100644 (file)
@@ -21,8 +21,6 @@ int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr,
 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,
                            char *buf, size_t buflen);
 void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd);
index db29b5d..85e9932 100644 (file)
@@ -27,6 +27,7 @@ typedef enum { FALSE = 0, TRUE = 1 } Boolean;
 #define WPA_CIPHER_AES_128_CMAC BIT(5)
 #endif /* CONFIG_IEEE80211W */
 #define WPA_CIPHER_GCMP BIT(6)
+#define WPA_CIPHER_SMS4 BIT(7)
 
 #define WPA_KEY_MGMT_IEEE8021X BIT(0)
 #define WPA_KEY_MGMT_PSK BIT(1)
@@ -38,11 +39,17 @@ typedef enum { FALSE = 0, TRUE = 1 } Boolean;
 #define WPA_KEY_MGMT_IEEE8021X_SHA256 BIT(7)
 #define WPA_KEY_MGMT_PSK_SHA256 BIT(8)
 #define WPA_KEY_MGMT_WPS BIT(9)
+#define WPA_KEY_MGMT_SAE BIT(10)
+#define WPA_KEY_MGMT_FT_SAE BIT(11)
+#define WPA_KEY_MGMT_WAPI_PSK BIT(12)
+#define WPA_KEY_MGMT_WAPI_CERT BIT(13)
+#define WPA_KEY_MGMT_CCKM BIT(14)
 
 static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
 {
        return !!(akm & (WPA_KEY_MGMT_IEEE8021X |
                         WPA_KEY_MGMT_FT_IEEE8021X |
+                        WPA_KEY_MGMT_CCKM |
                         WPA_KEY_MGMT_IEEE8021X_SHA256));
 }
 
@@ -50,13 +57,21 @@ static inline int wpa_key_mgmt_wpa_psk(int akm)
 {
        return !!(akm & (WPA_KEY_MGMT_PSK |
                         WPA_KEY_MGMT_FT_PSK |
-                        WPA_KEY_MGMT_PSK_SHA256));
+                        WPA_KEY_MGMT_PSK_SHA256 |
+                        WPA_KEY_MGMT_SAE));
 }
 
 static inline int wpa_key_mgmt_ft(int akm)
 {
        return !!(akm & (WPA_KEY_MGMT_FT_PSK |
-                        WPA_KEY_MGMT_FT_IEEE8021X));
+                        WPA_KEY_MGMT_FT_IEEE8021X |
+                        WPA_KEY_MGMT_FT_SAE));
+}
+
+static inline int wpa_key_mgmt_sae(int akm)
+{
+       return !!(akm & (WPA_KEY_MGMT_SAE |
+                        WPA_KEY_MGMT_FT_SAE));
 }
 
 static inline int wpa_key_mgmt_sha256(int akm)
@@ -76,14 +91,21 @@ static inline int wpa_key_mgmt_wpa_any(int akm)
        return wpa_key_mgmt_wpa(akm) || (akm & WPA_KEY_MGMT_WPA_NONE);
 }
 
+static inline int wpa_key_mgmt_cckm(int akm)
+{
+       return akm == WPA_KEY_MGMT_CCKM;
+}
+
 
 #define WPA_PROTO_WPA BIT(0)
 #define WPA_PROTO_RSN BIT(1)
+#define WPA_PROTO_WAPI BIT(2)
 
 #define WPA_AUTH_ALG_OPEN BIT(0)
 #define WPA_AUTH_ALG_SHARED BIT(1)
 #define WPA_AUTH_ALG_LEAP BIT(2)
 #define WPA_AUTH_ALG_FT BIT(3)
+#define WPA_AUTH_ALG_SAE BIT(4)
 
 
 enum wpa_alg {
@@ -93,7 +115,9 @@ enum wpa_alg {
        WPA_ALG_CCMP,
        WPA_ALG_IGTK,
        WPA_ALG_PMK,
-       WPA_ALG_GCMP
+       WPA_ALG_GCMP,
+       WPA_ALG_SMS4,
+       WPA_ALG_KRK
 };
 
 /**
@@ -105,7 +129,8 @@ enum wpa_cipher {
        CIPHER_TKIP,
        CIPHER_CCMP,
        CIPHER_WEP104,
-       CIPHER_GCMP
+       CIPHER_GCMP,
+       CIPHER_SMS4
 };
 
 /**
@@ -121,7 +146,12 @@ enum wpa_key_mgmt {
        KEY_MGMT_FT_PSK,
        KEY_MGMT_802_1X_SHA256,
        KEY_MGMT_PSK_SHA256,
-       KEY_MGMT_WPS
+       KEY_MGMT_WPS,
+       KEY_MGMT_SAE,
+       KEY_MGMT_FT_SAE,
+       KEY_MGMT_WAPI_PSK,
+       KEY_MGMT_WAPI_CERT,
+       KEY_MGMT_CCKM
 };
 
 /**
@@ -256,8 +286,9 @@ enum wpa_states {
 enum mfp_options {
        NO_MGMT_FRAME_PROTECTION = 0,
        MGMT_FRAME_PROTECTION_OPTIONAL = 1,
-       MGMT_FRAME_PROTECTION_REQUIRED = 2
+       MGMT_FRAME_PROTECTION_REQUIRED = 2,
 };
+#define MGMT_FRAME_PROTECTION_DEFAULT 3
 
 /**
  * enum hostapd_hw_mode - Hardware mode
index 2ab7fbf..07c8580 100644 (file)
@@ -76,6 +76,7 @@
 #define WLAN_AUTH_OPEN                 0
 #define WLAN_AUTH_SHARED_KEY           1
 #define WLAN_AUTH_FT                   2
+#define WLAN_AUTH_SAE                  3
 #define WLAN_AUTH_LEAP                 128
 
 #define WLAN_AUTH_CHALLENGE_LEN 128
 #define WLAN_STATUS_REQ_REFUSED_SSPN 67
 #define WLAN_STATUS_REQ_REFUSED_UNAUTH_ACCESS 68
 #define WLAN_STATUS_INVALID_RSNIE 72
+#define WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ 76
+#define WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED 77
 #define WLAN_STATUS_TRANSMISSION_FAILURE 79
 
 /* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */
 #define WLAN_EID_RIC_DATA 57
 #define WLAN_EID_HT_OPERATION 61
 #define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
+#define WLAN_EID_WAPI 68
 #define WLAN_EID_TIME_ADVERTISEMENT 69
 #define WLAN_EID_20_40_BSS_COEXISTENCE 72
 #define WLAN_EID_20_40_BSS_INTOLERANT 73
 #define WLAN_EID_ADV_PROTO 108
 #define WLAN_EID_ROAMING_CONSORTIUM 111
 #define WLAN_EID_EXT_CAPAB 127
+#define WLAN_EID_CCKM 156
 #define WLAN_EID_VHT_CAP 191
 #define WLAN_EID_VHT_OPERATION 192
 #define WLAN_EID_VHT_EXTENDED_BSS_LOAD 193
@@ -666,6 +671,7 @@ struct ieee80211_vht_operation {
 #define HT_INFO_STBC_PARAM_PCO_ACTIVE                  ((u16) BIT(10))
 #define HT_INFO_STBC_PARAM_PCO_PHASE                   ((u16) BIT(11))
 
+#define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
 #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
 
 /* VHT Defines */
@@ -966,9 +972,17 @@ enum wifi_display_subelem {
 #define WLAN_CIPHER_SUITE_NO_GROUP_ADDR        0x000FAC07
 #define WLAN_CIPHER_SUITE_GCMP         0x000FAC08
 
+#define WLAN_CIPHER_SUITE_SMS4         0x00147201
+
+#define WLAN_CIPHER_SUITE_CKIP         0x00409600
+#define WLAN_CIPHER_SUITE_CKIP_CMIC    0x00409601
+#define WLAN_CIPHER_SUITE_CMIC         0x00409602
+#define WLAN_CIPHER_SUITE_KRK          0x004096FF /* for nl80211 use only */
+
 /* AKM suite selectors */
 #define WLAN_AKM_SUITE_8021X           0x000FAC01
 #define WLAN_AKM_SUITE_PSK             0x000FAC02
+#define WLAN_AKM_SUITE_CCKM            0x00409600
 
 
 /* IEEE 802.11v - WNM Action field values */
index 36c308a..8d7a11c 100644 (file)
@@ -376,6 +376,12 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s)
        if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256)
                return WPA_KEY_MGMT_PSK_SHA256;
 #endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+       if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE)
+               return WPA_KEY_MGMT_SAE;
+       if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_SAE)
+               return WPA_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
        return 0;
 }
 #endif /* CONFIG_NO_WPA2 */
index 603166b..20c79d8 100644 (file)
@@ -32,6 +32,7 @@
 #define WPA_AUTH_KEY_MGMT_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0)
 #define WPA_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
 #define WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 2)
+#define WPA_AUTH_KEY_MGMT_CCKM RSN_SELECTOR(0x00, 0x40, 0x96, 0)
 #define WPA_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0)
 #define WPA_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
 #define WPA_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x50, 0xf2, 2)
@@ -51,6 +52,9 @@
 #define RSN_AUTH_KEY_MGMT_802_1X_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
 #define RSN_AUTH_KEY_MGMT_PSK_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
 #define RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
+#define RSN_AUTH_KEY_MGMT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
+#define RSN_AUTH_KEY_MGMT_FT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
+#define RSN_AUTH_KEY_MGMT_CCKM RSN_SELECTOR(0x00, 0x40, 0x96, 0x00)
 
 #define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0)
 #define RSN_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
index 790a6f3..f0a2a5d 100644 (file)
@@ -176,8 +176,8 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
     byteReverse(ctx->in, 14);
 
     /* Append length in bits and transform */
-    ((u32 *) ctx->in)[14] = ctx->bits[0];
-    ((u32 *) ctx->in)[15] = ctx->bits[1];
+    ((u32 *) aliasing_hide_typecast(ctx->in, u32))[14] = ctx->bits[0];
+    ((u32 *) aliasing_hide_typecast(ctx->in, u32))[15] = ctx->bits[1];
 
     MD5Transform(ctx->buf, (u32 *) ctx->in);
     byteReverse((unsigned char *) ctx->buf, 4);
index e9f926f..f7bdc2c 100644 (file)
@@ -41,7 +41,7 @@ struct hostapd_channel_data {
        /**
         * freq - Frequency in MHz
         */
-       short freq;
+       int freq;
 
        /**
         * flag - Channel flags (HOSTAPD_CHAN_*)
@@ -314,6 +314,9 @@ struct wpa_driver_auth_params {
         */
        int p2p;
 
+       const u8 *sae_data;
+       size_t sae_data_len;
+
 };
 
 enum wps_mode {
@@ -758,6 +761,7 @@ struct wpa_driver_capa {
 #define WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE      0x00000010
 #define WPA_DRIVER_CAPA_KEY_MGMT_FT            0x00000020
 #define WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK                0x00000040
+#define WPA_DRIVER_CAPA_KEY_MGMT_WAPI_PSK      0x00000080
        unsigned int key_mgmt;
 
 #define WPA_DRIVER_CAPA_ENC_WEP40      0x00000001
@@ -834,6 +838,10 @@ struct wpa_driver_capa {
 #define WPA_DRIVER_FLAGS_INACTIVITY_TIMER              0x00800000
 /* Driver expects user space implementation of MLME in AP mode */
 #define WPA_DRIVER_FLAGS_AP_MLME                       0x01000000
+/* Driver supports SAE with user space SME */
+#define WPA_DRIVER_FLAGS_SAE                           0x02000000
+/* Driver makes use of OBSS scan mechanism in wpa_supplicant */
+#define WPA_DRIVER_FLAGS_OBSS_SCAN                     0x04000000
        unsigned int flags;
 
        int max_scan_ssids;
@@ -1195,17 +1203,6 @@ struct wpa_driver_ops {
        int (*deauthenticate)(void *priv, const u8 *addr, int reason_code);
 
        /**
-        * disassociate - Request driver to disassociate
-        * @priv: private driver interface data
-        * @addr: peer address (BSSID of the AP)
-        * @reason_code: 16-bit reason code to be sent in the disassociation
-        *      frame
-        *
-        * Returns: 0 on success, -1 on failure
-        */
-       int (*disassociate)(void *priv, const u8 *addr, int reason_code);
-
-       /**
         * associate - Request driver to associate
         * @priv: private driver interface data
         * @params: association parameters
index 5f2e675..a0a5210 100644 (file)
@@ -976,8 +976,6 @@ static int atheros_receive_pkt(struct atheros_driver_data *drv)
        if (drv->sock_raw == NULL)
                return -1;
 #endif /* CONFIG_WPS || CONFIG_IEEE80211R */
-       if (l2_packet_get_own_addr(drv->sock_xmit, drv->own_addr))
-               return -1;
        return ret;
 }
 
@@ -1656,6 +1654,7 @@ atheros_init(struct hostapd_data *hapd, struct wpa_init_params *params)
                goto bad;
        if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr))
                goto bad;
+       os_memcpy(drv->own_addr, params->own_addr, ETH_ALEN);
        if (params->bridge[0]) {
                wpa_printf(MSG_DEBUG, "Configure bridge %s for EAPOL traffic.",
                           params->bridge[0]);
index a2b34c1..9d869b1 100644 (file)
@@ -973,13 +973,6 @@ wpa_driver_bsd_deauthenticate(void *priv, const u8 *addr, int reason_code)
 }
 
 static int
-wpa_driver_bsd_disassociate(void *priv, const u8 *addr, int reason_code)
-{
-       return bsd_send_mlme_param(priv, IEEE80211_MLME_DISASSOC, reason_code,
-                                  addr);
-}
-
-static int
 wpa_driver_bsd_set_auth_alg(void *priv, int auth_alg)
 {
        int authmode;
@@ -1564,7 +1557,6 @@ const struct wpa_driver_ops wpa_driver_bsd_ops = {
        .scan2                  = wpa_driver_bsd_scan,
        .get_scan_results2      = wpa_driver_bsd_get_scan_results2,
        .deauthenticate         = wpa_driver_bsd_deauthenticate,
-       .disassociate           = wpa_driver_bsd_disassociate,
        .associate              = wpa_driver_bsd_associate,
        .get_capa               = wpa_driver_bsd_get_capa,
 #endif /* HOSTAPD */
index b9e096c..7af3317 100644 (file)
@@ -725,14 +725,6 @@ static int wpa_driver_ndis_deauthenticate(void *priv, const u8 *addr,
 }
 
 
-static int wpa_driver_ndis_disassociate(void *priv, const u8 *addr,
-                                       int reason_code)
-{
-       struct wpa_driver_ndis_data *drv = priv;
-       return wpa_driver_ndis_disconnect(drv);
-}
-
-
 static void wpa_driver_ndis_scan_timeout(void *eloop_ctx, void *timeout_ctx)
 {
        wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
@@ -3223,7 +3215,6 @@ void driver_ndis_init_ops(void)
        wpa_driver_ndis_ops.init = wpa_driver_ndis_init;
        wpa_driver_ndis_ops.deinit = wpa_driver_ndis_deinit;
        wpa_driver_ndis_ops.deauthenticate = wpa_driver_ndis_deauthenticate;
-       wpa_driver_ndis_ops.disassociate = wpa_driver_ndis_disassociate;
        wpa_driver_ndis_ops.associate = wpa_driver_ndis_associate;
        wpa_driver_ndis_ops.add_pmkid = wpa_driver_ndis_add_pmkid;
        wpa_driver_ndis_ops.remove_pmkid = wpa_driver_ndis_remove_pmkid;
index 4574938..a0644b4 100644 (file)
@@ -244,6 +244,7 @@ struct wpa_driver_nl80211_data {
        unsigned int scan_for_auth:1;
        unsigned int retry_auth:1;
        unsigned int use_monitor:1;
+       unsigned int ignore_next_local_disconnect:1;
 
        u64 remain_on_chan_cookie;
        u64 send_action_cookie;
@@ -1038,6 +1039,7 @@ static void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
        const struct ieee80211_mgmt *mgmt;
        union wpa_event_data event;
 
+       wpa_printf(MSG_DEBUG, "nl80211: Authenticate event");
        mgmt = (const struct ieee80211_mgmt *) frame;
        if (len < 24 + sizeof(mgmt->u.auth)) {
                wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
@@ -1049,6 +1051,8 @@ static void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
        os_memset(&event, 0, sizeof(event));
        os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
        event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg);
+       event.auth.auth_transaction =
+               le_to_host16(mgmt->u.auth.auth_transaction);
        event.auth.status_code = le_to_host16(mgmt->u.auth.status_code);
        if (len > 24 + sizeof(mgmt->u.auth)) {
                event.auth.ies = mgmt->u.auth.variable;
@@ -1097,6 +1101,7 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
        union wpa_event_data event;
        u16 status;
 
+       wpa_printf(MSG_DEBUG, "nl80211: Associate event");
        mgmt = (const struct ieee80211_mgmt *) frame;
        if (len < 24 + sizeof(mgmt->u.assoc_resp)) {
                wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
@@ -1153,6 +1158,11 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
                return;
        }
 
+       if (cmd == NL80211_CMD_CONNECT)
+               wpa_printf(MSG_DEBUG, "nl80211: Connect event");
+       else if (cmd == NL80211_CMD_ROAM)
+               wpa_printf(MSG_DEBUG, "nl80211: Roam event");
+
        os_memset(&event, 0, sizeof(event));
        if (cmd == NL80211_CMD_CONNECT &&
            nla_get_u16(status) != WLAN_STATUS_SUCCESS) {
@@ -1191,6 +1201,7 @@ static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
                                  struct nlattr *by_ap)
 {
        union wpa_event_data data;
+       unsigned int locally_generated = by_ap == NULL;
 
        if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
                /*
@@ -1202,6 +1213,19 @@ static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
                return;
        }
 
+       if (drv->ignore_next_local_disconnect) {
+               drv->ignore_next_local_disconnect = 0;
+               if (locally_generated) {
+                       wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
+                                  "event triggered during reassociation");
+                       return;
+               }
+               wpa_printf(MSG_WARNING, "nl80211: Was expecting local "
+                          "disconnect but got another disconnect "
+                          "event first");
+       }
+
+       wpa_printf(MSG_DEBUG, "nl80211: Disconnect event");
        drv->associated = 0;
        os_memset(&data, 0, sizeof(data));
        if (reason)
@@ -1279,6 +1303,7 @@ static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv,
        u16 fc, stype;
        int ssi_signal = 0;
 
+       wpa_printf(MSG_DEBUG, "nl80211: Frame event");
        mgmt = (const struct ieee80211_mgmt *) frame;
        if (len < 24) {
                wpa_printf(MSG_DEBUG, "nl80211: Too short action frame");
@@ -1321,6 +1346,7 @@ static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv,
        const struct ieee80211_hdr *hdr;
        u16 fc;
 
+       wpa_printf(MSG_DEBUG, "nl80211: Frame TX status event");
        if (!is_ap_interface(drv->nlmode)) {
                u64 cookie_val;
 
@@ -1360,6 +1386,11 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
        const u8 *bssid = NULL;
        u16 reason_code = 0;
 
+       if (type == EVENT_DEAUTH)
+               wpa_printf(MSG_DEBUG, "nl80211: Deauthenticate event");
+       else
+               wpa_printf(MSG_DEBUG, "nl80211: Disassociate event");
+
        mgmt = (const struct ieee80211_mgmt *) frame;
        if (len >= 24) {
                bssid = mgmt->bssid;
@@ -1420,6 +1451,11 @@ static void mlme_event_unprot_disconnect(struct wpa_driver_nl80211_data *drv,
        union wpa_event_data event;
        u16 reason_code = 0;
 
+       if (type == EVENT_UNPROT_DEAUTH)
+               wpa_printf(MSG_DEBUG, "nl80211: Unprot Deauthenticate event");
+       else
+               wpa_printf(MSG_DEBUG, "nl80211: Unprot Disassociate event");
+
        if (len < 24)
                return;
 
@@ -2046,6 +2082,8 @@ static void nl80211_pmksa_candidate_event(struct wpa_driver_nl80211_data *drv,
        };
        union wpa_event_data data;
 
+       wpa_printf(MSG_DEBUG, "nl80211: PMKSA candidate event");
+
        if (!tb[NL80211_ATTR_PMKSA_CANDIDATE])
                return;
        if (nla_parse_nested(cand, MAX_NL80211_PMKSA_CANDIDATE,
@@ -2071,6 +2109,8 @@ static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv,
 {
        union wpa_event_data data;
 
+       wpa_printf(MSG_DEBUG, "nl80211: Probe client event");
+
        if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK])
                return;
 
@@ -2082,6 +2122,43 @@ static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv,
 }
 
 
+static void nl80211_tdls_oper_event(struct wpa_driver_nl80211_data *drv,
+                                   struct nlattr **tb)
+{
+       union wpa_event_data data;
+
+       wpa_printf(MSG_DEBUG, "nl80211: TDLS operation event");
+
+       if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_TDLS_OPERATION])
+               return;
+
+       os_memset(&data, 0, sizeof(data));
+       os_memcpy(data.tdls.peer, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+       switch (nla_get_u8(tb[NL80211_ATTR_TDLS_OPERATION])) {
+       case NL80211_TDLS_SETUP:
+               wpa_printf(MSG_DEBUG, "nl80211: TDLS setup request for peer "
+                          MACSTR, MAC2STR(data.tdls.peer));
+               data.tdls.oper = TDLS_REQUEST_SETUP;
+               break;
+       case NL80211_TDLS_TEARDOWN:
+               wpa_printf(MSG_DEBUG, "nl80211: TDLS teardown request for peer "
+                          MACSTR, MAC2STR(data.tdls.peer));
+               data.tdls.oper = TDLS_REQUEST_TEARDOWN;
+               break;
+       default:
+               wpa_printf(MSG_DEBUG, "nl80211: Unsupported TDLS operatione "
+                          "event");
+               return;
+       }
+       if (tb[NL80211_ATTR_REASON_CODE]) {
+               data.tdls.reason_code =
+                       nla_get_u16(tb[NL80211_ATTR_REASON_CODE]);
+       }
+
+       wpa_supplicant_event(drv->ctx, EVENT_TDLS, &data);
+}
+
+
 static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb,
                                   int wds)
 {
@@ -2214,6 +2291,9 @@ static void do_process_drv_event(struct wpa_driver_nl80211_data *drv,
        case NL80211_CMD_PROBE_CLIENT:
                nl80211_client_probe_event(drv, tb);
                break;
+       case NL80211_CMD_TDLS_OPER:
+               nl80211_tdls_oper_event(drv, tb);
+               break;
        default:
                wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
                           "(cmd=%d)", cmd);
@@ -2587,6 +2667,12 @@ broken_combination:
 
                if (flags & NL80211_FEATURE_INACTIVITY_TIMER)
                        capa->flags |= WPA_DRIVER_FLAGS_INACTIVITY_TIMER;
+
+               if (flags & NL80211_FEATURE_SAE)
+                       capa->flags |= WPA_DRIVER_FLAGS_SAE;
+
+               if (flags & NL80211_FEATURE_NEED_OBSS_SCAN)
+                       capa->flags |= WPA_DRIVER_FLAGS_OBSS_SCAN;
        }
 
        if (tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]) {
@@ -4227,6 +4313,14 @@ static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
                        NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
                                    WLAN_CIPHER_SUITE_AES_CMAC);
                        break;
+               case WPA_ALG_SMS4:
+                       NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+                                   WLAN_CIPHER_SUITE_SMS4);
+                       break;
+               case WPA_ALG_KRK:
+                       NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+                                   WLAN_CIPHER_SUITE_KRK);
+                       break;
                default:
                        wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
                                   "algorithm %d", __func__, alg);
@@ -4464,7 +4558,8 @@ static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
        NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason_code);
-       NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+       if (addr)
+               NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
        if (local_state_change)
                NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE);
 
@@ -4485,12 +4580,13 @@ nla_put_failure:
 
 
 static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
-                                        const u8 *addr, int reason_code)
+                                        int reason_code)
 {
-       wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
-                  __func__, MAC2STR(addr), reason_code);
+       wpa_printf(MSG_DEBUG, "%s(reason_code=%d)", __func__, reason_code);
        drv->associated = 0;
-       return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DISCONNECT,
+       drv->ignore_next_local_disconnect = 0;
+       /* Disconnect command doesn't need BSSID - it uses cached value */
+       return wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT,
                                       reason_code, 0);
 }
 
@@ -4501,7 +4597,7 @@ static int wpa_driver_nl80211_deauthenticate(void *priv, const u8 *addr,
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
        if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
-               return wpa_driver_nl80211_disconnect(drv, addr, reason_code);
+               return wpa_driver_nl80211_disconnect(drv, reason_code);
        wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
                   __func__, MAC2STR(addr), reason_code);
        drv->associated = 0;
@@ -4512,20 +4608,6 @@ static int wpa_driver_nl80211_deauthenticate(void *priv, const u8 *addr,
 }
 
 
-static int wpa_driver_nl80211_disassociate(void *priv, const u8 *addr,
-                                          int reason_code)
-{
-       struct i802_bss *bss = priv;
-       struct wpa_driver_nl80211_data *drv = bss->drv;
-       if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
-               return wpa_driver_nl80211_disconnect(drv, addr, reason_code);
-       wpa_printf(MSG_DEBUG, "%s", __func__);
-       drv->associated = 0;
-       return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DISASSOCIATE,
-                                      reason_code, 0);
-}
-
-
 static void nl80211_copy_auth_params(struct wpa_driver_nl80211_data *drv,
                                     struct wpa_driver_auth_params *params)
 {
@@ -4642,6 +4724,12 @@ retry:
        wpa_hexdump(MSG_DEBUG, "  * IEs", params->ie, params->ie_len);
        if (params->ie)
                NLA_PUT(msg, NL80211_ATTR_IE, params->ie_len, params->ie);
+       if (params->sae_data) {
+               wpa_hexdump(MSG_DEBUG, "  * SAE data", params->sae_data,
+                           params->sae_data_len);
+               NLA_PUT(msg, NL80211_ATTR_SAE_DATA, params->sae_data_len,
+                       params->sae_data);
+       }
        if (params->auth_alg & WPA_AUTH_ALG_OPEN)
                type = NL80211_AUTHTYPE_OPEN_SYSTEM;
        else if (params->auth_alg & WPA_AUTH_ALG_SHARED)
@@ -4650,6 +4738,8 @@ retry:
                type = NL80211_AUTHTYPE_NETWORK_EAP;
        else if (params->auth_alg & WPA_AUTH_ALG_FT)
                type = NL80211_AUTHTYPE_FT;
+       else if (params->auth_alg & WPA_AUTH_ALG_SAE)
+               type = NL80211_AUTHTYPE_SAE;
        else
                goto nla_put_failure;
        wpa_printf(MSG_DEBUG, "  * Auth Type %d", type);
@@ -5267,7 +5357,7 @@ static int wpa_driver_nl80211_send_mntr(struct wpa_driver_nl80211_data *drv,
 
        if (noack)
                txflags |= IEEE80211_RADIOTAP_F_TX_NOACK;
-       *(le16 *) &rtap_hdr[12] = host_to_le16(txflags);
+       WPA_PUT_LE16(&rtap_hdr[12], txflags);
 
        res = sendmsg(drv->monitor_sock, &msg, 0);
        if (res < 0) {
@@ -6648,56 +6738,7 @@ nla_put_failure:
 }
 
 
-static unsigned int nl80211_get_assoc_bssid(struct wpa_driver_nl80211_data *drv,
-                                           u8 *bssid)
-{
-       struct nl_msg *msg;
-       int ret;
-       struct nl80211_bss_info_arg arg;
-
-       os_memset(&arg, 0, sizeof(arg));
-       msg = nlmsg_alloc();
-       if (!msg)
-               goto nla_put_failure;
-
-       nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
-       arg.drv = drv;
-       ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
-       msg = NULL;
-       if (ret == 0) {
-               if (is_zero_ether_addr(arg.assoc_bssid))
-                       return -ENOTCONN;
-               os_memcpy(bssid, arg.assoc_bssid, ETH_ALEN);
-               return 0;
-       }
-       wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
-                  "(%s)", ret, strerror(-ret));
-nla_put_failure:
-       nlmsg_free(msg);
-       return drv->assoc_freq;
-}
-
-
-static int nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
-                             const u8 *bssid)
-{
-       u8 addr[ETH_ALEN];
-
-       if (bssid == NULL) {
-               int res = nl80211_get_assoc_bssid(drv, addr);
-               if (res)
-                       return res;
-               bssid = addr;
-       }
-
-       return wpa_driver_nl80211_disconnect(drv, bssid,
-                                            WLAN_REASON_PREV_AUTH_NOT_VALID);
-}
-
-
-static int wpa_driver_nl80211_connect(
+static int wpa_driver_nl80211_try_connect(
        struct wpa_driver_nl80211_data *drv,
        struct wpa_driver_associate_params *params)
 {
@@ -6788,6 +6829,9 @@ skip_auth_type:
                int cipher;
 
                switch (params->pairwise_suite) {
+               case CIPHER_SMS4:
+                       cipher = WLAN_CIPHER_SUITE_SMS4;
+                       break;
                case CIPHER_WEP40:
                        cipher = WLAN_CIPHER_SUITE_WEP40;
                        break;
@@ -6812,6 +6856,9 @@ skip_auth_type:
                int cipher;
 
                switch (params->group_suite) {
+               case CIPHER_SMS4:
+                       cipher = WLAN_CIPHER_SUITE_SMS4;
+                       break;
                case CIPHER_WEP40:
                        cipher = WLAN_CIPHER_SUITE_WEP40;
                        break;
@@ -6833,10 +6880,14 @@ skip_auth_type:
        }
 
        if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
-           params->key_mgmt_suite == KEY_MGMT_PSK) {
+           params->key_mgmt_suite == KEY_MGMT_PSK ||
+           params->key_mgmt_suite == KEY_MGMT_CCKM) {
                int mgmt = WLAN_AKM_SUITE_PSK;
 
                switch (params->key_mgmt_suite) {
+               case KEY_MGMT_CCKM:
+                       mgmt = WLAN_AKM_SUITE_CCKM;
+                       break;
                case KEY_MGMT_802_1X:
                        mgmt = WLAN_AKM_SUITE_8021X;
                        break;
@@ -6867,14 +6918,6 @@ skip_auth_type:
        if (ret) {
                wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
                           "(%s)", ret, strerror(-ret));
-               /*
-                * cfg80211 does not currently accept new connection if we are
-                * already connected. As a workaround, force disconnection and
-                * try again once the driver indicates it completed
-                * disconnection.
-                */
-               if (ret == -EALREADY)
-                       nl80211_disconnect(drv, params->bssid);
                goto nla_put_failure;
        }
        ret = 0;
@@ -6887,6 +6930,31 @@ nla_put_failure:
 }
 
 
+static int wpa_driver_nl80211_connect(
+       struct wpa_driver_nl80211_data *drv,
+       struct wpa_driver_associate_params *params)
+{
+       int ret = wpa_driver_nl80211_try_connect(drv, params);
+       if (ret == -EALREADY) {
+               /*
+                * cfg80211 does not currently accept new connections if
+                * we are already connected. As a workaround, force
+                * disconnection and try again.
+                */
+               wpa_printf(MSG_DEBUG, "nl80211: Explicitly "
+                          "disconnecting before reassociation "
+                          "attempt");
+               if (wpa_driver_nl80211_disconnect(
+                           drv, WLAN_REASON_PREV_AUTH_NOT_VALID))
+                       return -1;
+               /* Ignore the next local disconnect message. */
+               drv->ignore_next_local_disconnect = 1;
+               ret = wpa_driver_nl80211_try_connect(drv, params);
+       }
+       return ret;
+}
+
+
 static int wpa_driver_nl80211_associate(
        void *priv, struct wpa_driver_associate_params *params)
 {
@@ -9186,7 +9254,6 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .stop_sched_scan = wpa_driver_nl80211_stop_sched_scan,
        .get_scan_results2 = wpa_driver_nl80211_get_scan_results,
        .deauthenticate = wpa_driver_nl80211_deauthenticate,
-       .disassociate = wpa_driver_nl80211_disassociate,
        .authenticate = wpa_driver_nl80211_authenticate,
        .associate = wpa_driver_nl80211_associate,
        .global_init = nl80211_global_init,
index 9481cbf..ed88e71 100644 (file)
@@ -304,17 +304,6 @@ static int wpa_driver_privsep_deauthenticate(void *priv, const u8 *addr,
 }
 
 
-static int wpa_driver_privsep_disassociate(void *priv, const u8 *addr,
-                                       int reason_code)
-{
-       //struct wpa_driver_privsep_data *drv = priv;
-       wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d",
-                  __func__, MAC2STR(addr), reason_code);
-       wpa_printf(MSG_DEBUG, "%s - TODO", __func__);
-       return 0;
-}
-
-
 static void wpa_driver_privsep_event_assoc(void *ctx,
                                           enum wpa_event_type event,
                                           u8 *buf, size_t len)
@@ -736,7 +725,6 @@ struct wpa_driver_ops wpa_driver_privsep_ops = {
        .set_param = wpa_driver_privsep_set_param,
        .scan2 = wpa_driver_privsep_scan,
        .deauthenticate = wpa_driver_privsep_deauthenticate,
-       .disassociate = wpa_driver_privsep_disassociate,
        .associate = wpa_driver_privsep_associate,
        .get_capa = wpa_driver_privsep_get_capa,
        .get_mac_addr = wpa_driver_privsep_get_mac_addr,
index e7bf195..89aee7d 100644 (file)
@@ -1714,20 +1714,6 @@ static int wpa_driver_test_deauthenticate(void *priv, const u8 *addr,
 }
 
 
-static int wpa_driver_test_disassociate(void *priv, const u8 *addr,
-                                       int reason_code)
-{
-       struct test_driver_bss *dbss = priv;
-       struct wpa_driver_test_data *drv = dbss->drv;
-       wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d",
-                  __func__, MAC2STR(addr), reason_code);
-       os_memset(dbss->bssid, 0, ETH_ALEN);
-       drv->associated = 0;
-       wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
-       return wpa_driver_test_send_disassoc(drv);
-}
-
-
 static const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie)
 {
        const u8 *end, *pos;
@@ -2870,7 +2856,7 @@ static int wpa_driver_test_p2p_connect(void *priv, const u8 *peer_addr,
                return -1;
        return p2p_connect(drv->p2p, peer_addr, wps_method, go_intent,
                           own_interface_addr, force_freq, persistent_group,
-                          NULL, 0, 0);
+                          NULL, 0, 0, 0);
 }
 
 
@@ -3299,7 +3285,6 @@ const struct wpa_driver_ops wpa_driver_test_ops = {
        .deinit = wpa_driver_test_deinit,
        .set_param = wpa_driver_test_set_param,
        .deauthenticate = wpa_driver_test_deauthenticate,
-       .disassociate = wpa_driver_test_disassociate,
        .associate = wpa_driver_test_associate,
        .get_capa = wpa_driver_test_get_capa,
        .get_mac_addr = wpa_driver_test_get_mac_addr,
index bd37ca1..9733e01 100644 (file)
@@ -1938,18 +1938,6 @@ static int wpa_driver_wext_deauthenticate(void *priv, const u8 *addr,
 }
 
 
-static int wpa_driver_wext_disassociate(void *priv, const u8 *addr,
-                                       int reason_code)
-{
-       struct wpa_driver_wext_data *drv = priv;
-       int ret;
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-       ret = wpa_driver_wext_mlme(drv, addr, IW_MLME_DISASSOC, reason_code);
-       wpa_driver_wext_disconnect(drv);
-       return ret;
-}
-
-
 static int wpa_driver_wext_set_gen_ie(void *priv, const u8 *ie,
                                      size_t ie_len)
 {
@@ -2485,7 +2473,6 @@ const struct wpa_driver_ops wpa_driver_wext_ops = {
        .scan2 = wpa_driver_wext_scan,
        .get_scan_results2 = wpa_driver_wext_get_scan_results,
        .deauthenticate = wpa_driver_wext_deauthenticate,
-       .disassociate = wpa_driver_wext_disassociate,
        .associate = wpa_driver_wext_associate,
        .init = wpa_driver_wext_init,
        .deinit = wpa_driver_wext_deinit,
index dd662f3..6c60550 100644 (file)
@@ -97,8 +97,6 @@ struct netlink_data * netlink_init(struct netlink_config *cfg)
        if (netlink == NULL)
                return NULL;
 
-       netlink->cfg = cfg;
-
        netlink->sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
        if (netlink->sock < 0) {
                wpa_printf(MSG_ERROR, "netlink: Failed to open netlink "
@@ -121,6 +119,8 @@ struct netlink_data * netlink_init(struct netlink_config *cfg)
        eloop_register_read_sock(netlink->sock, netlink_receive, netlink,
                                 NULL);
 
+       netlink->cfg = cfg;
+
        return netlink;
 }
 
index 2f38788..1a9a819 100644 (file)
  *     of PMKSA caching dandidates.
  *
  * @NL80211_CMD_TDLS_OPER: Perform a high-level TDLS command (e.g. link setup).
+ *     In addition, this can be used as an event to request userspace to take
+ *     actions on TDLS links (set up a new link or tear down an existing one).
+ *     In such events, %NL80211_ATTR_TDLS_OPERATION indicates the requested
+ *     operation, %NL80211_ATTR_MAC contains the peer MAC address, and
+ *     %NL80211_ATTR_REASON_CODE the reason code to be used (only with
+ *     %NL80211_TDLS_TEARDOWN).
  * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame.
  *
  * @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP
  *     %NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ with
  *     %NL80211_ATTR_WIPHY_CHANNEL_TYPE.
  *
+ * @NL80211_CMD_START_P2P_DEVICE: Start the given P2P Device, identified by
+ *     its %NL80211_ATTR_WDEV identifier. It must have been created with
+ *     %NL80211_CMD_NEW_INTERFACE previously. After it has been started, the
+ *     P2P Device can be used for P2P operations, e.g. remain-on-channel and
+ *     public action frame TX.
+ * @NL80211_CMD_STOP_P2P_DEVICE: Stop the given P2P Device, identified by
+ *     its %NL80211_ATTR_WDEV identifier.
+ *
+ * @NL80211_CMD_CONN_FAILED: connection request to an AP failed; used to
+ *     notify userspace that AP has rejected the connection request from a
+ *     station, due to particular reason. %NL80211_ATTR_CONN_FAILED_REASON
+ *     is used for this.
+ *
+ * @NL80211_CMD_SET_MCAST_RATE: Change the rate used to send multicast frames
+ *     for IBSS or MESH vif.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -708,6 +730,13 @@ enum nl80211_commands {
 
        NL80211_CMD_CH_SWITCH_NOTIFY,
 
+       NL80211_CMD_START_P2P_DEVICE,
+       NL80211_CMD_STOP_P2P_DEVICE,
+
+       NL80211_CMD_CONN_FAILED,
+
+       NL80211_CMD_SET_MCAST_RATE,
+
        /* add new commands above here */
 
        /* used to define NL80211_CMD_MAX below */
@@ -1251,6 +1280,18 @@ enum nl80211_commands {
  *     was used to provide the hint. For the different types of
  *     allowed user regulatory hints see nl80211_user_reg_hint_type.
  *
+ * @NL80211_ATTR_CONN_FAILED_REASON: The reason for which AP has rejected
+ *     the connection request from a station. nl80211_connect_failed_reason
+ *     enum has different reasons of connection failure.
+ *
+ * @NL80211_ATTR_SAE_DATA: SAE elements in Authentication frames. This starts
+ *     with the Authentication transaction sequence number field.
+ *
+ * @NL80211_ATTR_VHT_CAPABILITY: VHT Capability information element (from
+ *     association request when used with NL80211_CMD_NEW_STATION)
+ *
+ * @NL80211_ATTR_SCAN_FLAGS: scan request control flags (u32)
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1506,6 +1547,14 @@ enum nl80211_attrs {
 
        NL80211_ATTR_USER_REG_HINT_TYPE,
 
+       NL80211_ATTR_CONN_FAILED_REASON,
+
+       NL80211_ATTR_SAE_DATA,
+
+       NL80211_ATTR_VHT_CAPABILITY,
+
+       NL80211_ATTR_SCAN_FLAGS,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -1549,6 +1598,7 @@ enum nl80211_attrs {
 #define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY    16
 #define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY    24
 #define NL80211_HT_CAPABILITY_LEN              26
+#define NL80211_VHT_CAPABILITY_LEN             12
 
 #define NL80211_MAX_NR_CIPHER_SUITES           5
 #define NL80211_MAX_NR_AKM_SUITES              2
@@ -1575,6 +1625,10 @@ enum nl80211_attrs {
  * @NL80211_IFTYPE_MESH_POINT: mesh point
  * @NL80211_IFTYPE_P2P_CLIENT: P2P client
  * @NL80211_IFTYPE_P2P_GO: P2P group owner
+ * @NL80211_IFTYPE_P2P_DEVICE: P2P device interface type, this is not a netdev
+ *     and therefore can't be created in the normal ways, use the
+ *     %NL80211_CMD_START_P2P_DEVICE and %NL80211_CMD_STOP_P2P_DEVICE
+ *     commands to create and destroy one
  * @NL80211_IFTYPE_MAX: highest interface type number currently defined
  * @NUM_NL80211_IFTYPES: number of defined interface types
  *
@@ -1593,6 +1647,7 @@ enum nl80211_iftype {
        NL80211_IFTYPE_MESH_POINT,
        NL80211_IFTYPE_P2P_CLIENT,
        NL80211_IFTYPE_P2P_GO,
+       NL80211_IFTYPE_P2P_DEVICE,
 
        /* keep last */
        NUM_NL80211_IFTYPES,
@@ -2460,6 +2515,7 @@ enum nl80211_bss_status {
  * @NL80211_AUTHTYPE_SHARED_KEY: Shared Key authentication (WEP only)
  * @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r)
  * @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP)
+ * @NL80211_AUTHTYPE_SAE: Simultaneous authentication of equals
  * @__NL80211_AUTHTYPE_NUM: internal
  * @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm
  * @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by
@@ -2471,6 +2527,7 @@ enum nl80211_auth_type {
        NL80211_AUTHTYPE_SHARED_KEY,
        NL80211_AUTHTYPE_FT,
        NL80211_AUTHTYPE_NETWORK_EAP,
+       NL80211_AUTHTYPE_SAE,
 
        /* keep last */
        __NL80211_AUTHTYPE_NUM,
@@ -2994,12 +3051,34 @@ enum nl80211_ap_sme_features {
  * @NL80211_FEATURE_CELL_BASE_REG_HINTS: This driver has been tested
  *     to work properly to suppport receiving regulatory hints from
  *     cellular base stations.
+ * @NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL: If this is set, an active
+ *     P2P Device (%NL80211_IFTYPE_P2P_DEVICE) requires its own channel
+ *     in the interface combinations, even when it's only used for scan
+ *     and remain-on-channel. This could be due to, for example, the
+ *     remain-on-channel implementation requiring a channel context.
+ * @NL80211_FEATURE_SAE: This driver supports simultaneous authentication of
+ *     equals (SAE) with user space SME (NL80211_CMD_AUTHENTICATE) in station
+ *     mode
+ * @NL80211_FEATURE_LOW_PRIORITY_SCAN: This driver supports low priority scan
+ * @NL80211_FEATURE_SCAN_FLUSH: Scan flush is supported
+ * @NL80211_FEATURE_AP_SCAN: Support scanning using an AP vif
+ * @NL80211_FEATURE_VIF_TXPOWER: The driver supports per-vif TX power setting
+ * @NL80211_FEATURE_NEED_OBSS_SCAN: The driver expects userspace to perform
+ *     OBSS scans and generate 20/40 BSS coex reports. This flag is used only
+ *     for drivers implementing the CONNECT API, for AUTH/ASSOC it is implied.
  */
 enum nl80211_feature_flags {
-       NL80211_FEATURE_SK_TX_STATUS    = 1 << 0,
-       NL80211_FEATURE_HT_IBSS         = 1 << 1,
-       NL80211_FEATURE_INACTIVITY_TIMER = 1 << 2,
-       NL80211_FEATURE_CELL_BASE_REG_HINTS = 1 << 3,
+       NL80211_FEATURE_SK_TX_STATUS                    = 1 << 0,
+       NL80211_FEATURE_HT_IBSS                         = 1 << 1,
+       NL80211_FEATURE_INACTIVITY_TIMER                = 1 << 2,
+       NL80211_FEATURE_CELL_BASE_REG_HINTS             = 1 << 3,
+       NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL        = 1 << 4,
+       NL80211_FEATURE_SAE                             = 1 << 5,
+       NL80211_FEATURE_LOW_PRIORITY_SCAN               = 1 << 6,
+       NL80211_FEATURE_SCAN_FLUSH                      = 1 << 7,
+       NL80211_FEATURE_AP_SCAN                         = 1 << 8,
+       NL80211_FEATURE_VIF_TXPOWER                     = 1 << 9,
+       NL80211_FEATURE_NEED_OBSS_SCAN                  = 1 << 10,
 };
 
 /**
@@ -3023,4 +3102,36 @@ enum nl80211_probe_resp_offload_support_attr {
        NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U =     1<<3,
 };
 
+/**
+ * enum nl80211_connect_failed_reason - connection request failed reasons
+ * @NL80211_CONN_FAIL_MAX_CLIENTS: Maximum number of clients that can be
+ *     handled by the AP is reached.
+ * @NL80211_CONN_FAIL_BLOCKED_CLIENT: Client's MAC is in the AP's blocklist.
+ */
+enum nl80211_connect_failed_reason {
+       NL80211_CONN_FAIL_MAX_CLIENTS,
+       NL80211_CONN_FAIL_BLOCKED_CLIENT,
+};
+
+/**
+ * enum nl80211_scan_flags -  scan request control flags
+ *
+ * Scan request control flags are used to control the handling
+ * of NL80211_CMD_TRIGGER_SCAN and NL80211_CMD_START_SCHED_SCAN
+ * requests.
+ *
+ * @NL80211_SCAN_FLAG_LOW_PRIORITY: scan request has low priority
+ * @NL80211_SCAN_FLAG_FLUSH: flush cache before scanning
+ * @NL80211_SCAN_FLAG_AP: force a scan even if the interface is configured
+ *     as AP and the beaconing has already been configured. This attribute is
+ *     dangerous because will destroy stations performance as a lot of frames
+ *     will be lost while scanning off-channel, therefore it must be used only
+ *     when really needed
+ */
+enum nl80211_scan_flags {
+       NL80211_SCAN_FLAG_LOW_PRIORITY                  = 1<<0,
+       NL80211_SCAN_FLAG_FLUSH                         = 1<<1,
+       NL80211_SCAN_FLAG_AP                            = 1<<2,
+};
+
 #endif /* __LINUX_NL80211_H */
index 2ed74b8..a4c9b25 100644 (file)
@@ -348,6 +348,7 @@ SM_STATE(EAP, METHOD)
 {
        struct wpabuf *eapReqData;
        struct eap_method_ret ret;
+       int min_len = 1;
 
        SM_ENTRY(EAP, METHOD);
        if (sm->m == NULL) {
@@ -356,7 +357,9 @@ SM_STATE(EAP, METHOD)
        }
 
        eapReqData = eapol_get_eapReqData(sm);
-       if (!eap_hdr_len_valid(eapReqData, 1))
+       if (sm->m->vendor == EAP_VENDOR_IETF && sm->m->method == EAP_TYPE_LEAP)
+               min_len = 0; /* LEAP uses EAP-Success without payload */
+       if (!eap_hdr_len_valid(eapReqData, min_len))
                return;
 
        /*
index 7eefe8c..aedd85a 100644 (file)
@@ -829,6 +829,14 @@ const u8 * eap_peer_tls_process_init(struct eap_sm *sm,
                }
                pos += 4;
                left -= 4;
+
+               if (left > tls_msg_len) {
+                       wpa_printf(MSG_INFO, "SSL: TLS Message Length (%d "
+                                  "bytes) smaller than this fragment (%d "
+                                  "bytes)", (int) tls_msg_len, (int) left);
+                       ret->ignore = TRUE;
+                       return NULL;
+               }
        }
 
        ret->ignore = FALSE;
index a965cac..177b58d 100644 (file)
@@ -365,6 +365,7 @@ static struct wpabuf * eap_aka_build_identity(struct eap_sm *sm,
                eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0);
        } else if (data->identity_round > 3) {
                /* Cannot use more than three rounds of Identity messages */
+               eap_sim_msg_free(msg);
                return NULL;
        } else if (sm->identity && sm->identity_len > 0 &&
                   (sm->identity[0] == EAP_AKA_REAUTH_ID_PREFIX ||
index f83c3cb..b531241 100644 (file)
@@ -117,6 +117,7 @@ static struct wpabuf * eap_sim_build_start(struct eap_sm *sm,
                eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0);
        } else if (data->start_round > 3) {
                /* Cannot use more than three rounds of Start messages */
+               eap_sim_msg_free(msg);
                return NULL;
        } else if (data->start_round == 0) {
                /*
index 31be2ec..9efb5b2 100644 (file)
@@ -228,6 +228,14 @@ static int eap_server_tls_process_fragment(struct eap_ssl_data *data,
                        return -1;
                }
 
+               if (len > message_length) {
+                       wpa_printf(MSG_INFO, "SSL: Too much data (%d bytes) in "
+                                  "first fragment of frame (TLS Message "
+                                  "Length %d bytes)",
+                                  (int) len, (int) message_length);
+                       return -1;
+               }
+
                data->tls_in = wpabuf_alloc(message_length);
                if (data->tls_in == NULL) {
                        wpa_printf(MSG_DEBUG, "SSL: No memory for message");
@@ -289,6 +297,13 @@ static int eap_server_tls_reassemble(struct eap_ssl_data *data, u8 flags,
                           tls_msg_len);
                *pos += 4;
                *left -= 4;
+
+               if (*left > tls_msg_len) {
+                       wpa_printf(MSG_INFO, "SSL: TLS Message Length (%d "
+                                  "bytes) smaller than this fragment (%d "
+                                  "bytes)", (int) tls_msg_len, (int) *left);
+                       return -1;
+               }
        }
 
        wpa_printf(MSG_DEBUG, "SSL: Received packet: Flags 0x%x "
index 851cf49..f90fb62 100644 (file)
@@ -1469,10 +1469,7 @@ void eapol_sm_notify_cached(struct eapol_sm *sm)
        if (sm == NULL)
                return;
        wpa_printf(MSG_DEBUG, "EAPOL: PMKSA caching was used - skip EAPOL");
-       sm->SUPP_PAE_state = SUPP_PAE_AUTHENTICATED;
-       sm->suppPortStatus = Authorized;
-       eapol_sm_set_port_authorized(sm);
-       sm->portValid = TRUE;
+       sm->eapSuccess = TRUE;
        eap_notify_success(sm->eap);
        eapol_sm_step(sm);
 }
index a3eaa8c..b122f7c 100644 (file)
@@ -256,7 +256,7 @@ void p2p_go_neg_failed(struct p2p_data *p2p, struct p2p_device *peer,
 }
 
 
-static void p2p_listen_in_find(struct p2p_data *p2p)
+static void p2p_listen_in_find(struct p2p_data *p2p, int dev_disc)
 {
        unsigned int r, tu;
        int freq;
@@ -277,6 +277,19 @@ static void p2p_listen_in_find(struct p2p_data *p2p)
        os_get_random((u8 *) &r, sizeof(r));
        tu = (r % ((p2p->max_disc_int - p2p->min_disc_int) + 1) +
              p2p->min_disc_int) * 100;
+       if (p2p->max_disc_tu >= 0 && tu > (unsigned int) p2p->max_disc_tu)
+               tu = p2p->max_disc_tu;
+       if (!dev_disc && tu < 100)
+               tu = 100; /* Need to wait in non-device discovery use cases */
+       if (p2p->cfg->max_listen && 1024 * tu / 1000 > p2p->cfg->max_listen)
+               tu = p2p->cfg->max_listen * 1000 / 1024;
+
+       if (tu == 0) {
+               wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Skip listen state "
+                       "since duration was 0 TU");
+               p2p_set_timeout(p2p, 0, 0);
+               return;
+       }
 
        p2p->pending_listen_freq = freq;
        p2p->pending_listen_sec = 0;
@@ -1153,15 +1166,17 @@ void p2p_stop_find(struct p2p_data *p2p)
 }
 
 
-static int p2p_prepare_channel(struct p2p_data *p2p, unsigned int force_freq)
+static int p2p_prepare_channel(struct p2p_data *p2p, unsigned int force_freq,
+                              unsigned int pref_freq)
 {
-       if (force_freq) {
+       if (force_freq || pref_freq) {
                u8 op_reg_class, op_channel;
-               if (p2p_freq_to_channel(p2p->cfg->country, force_freq,
+               unsigned int freq = force_freq ? force_freq : pref_freq;
+               if (p2p_freq_to_channel(p2p->cfg->country, freq,
                                        &op_reg_class, &op_channel) < 0) {
                        wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
                                "P2P: Unsupported frequency %u MHz",
-                               force_freq);
+                               freq);
                        return -1;
                }
                if (!p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
@@ -1169,37 +1184,21 @@ static int p2p_prepare_channel(struct p2p_data *p2p, unsigned int force_freq)
                        wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
                                "P2P: Frequency %u MHz (oper_class %u "
                                "channel %u) not allowed for P2P",
-                               force_freq, op_reg_class, op_channel);
+                               freq, op_reg_class, op_channel);
                        return -1;
                }
                p2p->op_reg_class = op_reg_class;
                p2p->op_channel = op_channel;
-#ifndef ANDROID_P2P
-               p2p->channels.reg_classes = 1;
-               p2p->channels.reg_class[0].channels = 1;
-               p2p->channels.reg_class[0].reg_class = p2p->op_reg_class;
-               p2p->channels.reg_class[0].channel[0] = p2p->op_channel;
-#else
-               if(p2p->cfg->p2p_concurrency == P2P_MULTI_CHANNEL_CONCURRENT) {
-                       /* We we are requesting for a preferred channel. But since
-                        * are multichannel concurrent, we have to poplulate the
-                        * p2p_channels with list of channels that we support.
-                        */
-#ifdef ANDROID_P2P
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "Full channel list");
-#endif
-                       os_memcpy(&p2p->channels, &p2p->cfg->channels,
-                               sizeof(struct p2p_channels));
-               } else {
-#ifdef ANDROID_P2P
-                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "Single channel list %d", p2p->op_channel);
-#endif
+               if (force_freq) {
                        p2p->channels.reg_classes = 1;
                        p2p->channels.reg_class[0].channels = 1;
-                       p2p->channels.reg_class[0].reg_class = p2p->op_reg_class;
+                       p2p->channels.reg_class[0].reg_class =
+                               p2p->op_reg_class;
                        p2p->channels.reg_class[0].channel[0] = p2p->op_channel;
+               } else {
+                       os_memcpy(&p2p->channels, &p2p->cfg->channels,
+                                 sizeof(struct p2p_channels));
                }
-#endif
        } else {
                u8 op_reg_class, op_channel;
 
@@ -1279,18 +1278,18 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
                int go_intent, const u8 *own_interface_addr,
                unsigned int force_freq, int persistent_group,
                const u8 *force_ssid, size_t force_ssid_len,
-               int pd_before_go_neg)
+               int pd_before_go_neg, unsigned int pref_freq)
 {
        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 pd_before_go_neg=%d force_freq %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, pd_before_go_neg, force_freq);
+               wps_method, persistent_group, pd_before_go_neg);
 
-       if (p2p_prepare_channel(p2p, force_freq) < 0)
+       if (p2p_prepare_channel(p2p, force_freq, pref_freq) < 0)
                return -1;
 
        dev = p2p_get_device(p2p, peer_addr);
@@ -1390,7 +1389,8 @@ 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,
-                 const u8 *force_ssid, size_t force_ssid_len)
+                 const u8 *force_ssid, size_t force_ssid_len,
+                 unsigned int pref_freq)
 {
        struct p2p_device *dev;
 
@@ -1401,7 +1401,7 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr,
                MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr),
                wps_method, persistent_group);
 
-       if (p2p_prepare_channel(p2p, force_freq) < 0)
+       if (p2p_prepare_channel(p2p, force_freq, pref_freq) < 0)
                return -1;
 
        dev = p2p_get_device(p2p, peer_addr);
@@ -2416,6 +2416,7 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg)
        p2p->min_disc_int = 1;
 #endif
        p2p->max_disc_int = 3;
+       p2p->max_disc_tu = -1;
 
        os_get_random(&p2p->next_tie_breaker, 1);
        p2p->next_tie_breaker &= 0x01;
@@ -2712,7 +2713,7 @@ void p2p_continue_find(struct p2p_data *p2p)
                }
        }
 
-       p2p_listen_in_find(p2p);
+       p2p_listen_in_find(p2p, 1);
 }
 
 
@@ -2758,8 +2759,7 @@ static void p2p_retry_pd(struct p2p_data *p2p)
 
        /*
         * Retry the prov disc req attempt only for the peer that the user had
-        * requested for and provided a join has not been initiated on it
-        * in the meantime.
+        * requested.
         */
 
        dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
@@ -2768,15 +2768,14 @@ static void p2p_retry_pd(struct p2p_data *p2p)
                        continue;
                if (!dev->req_config_methods)
                        continue;
-               if (dev->flags & P2P_DEV_PD_FOR_JOIN)
-                       continue;
 
                wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send "
                        "pending Provision Discovery Request to "
                        MACSTR " (config methods 0x%x)",
                        MAC2STR(dev->info.p2p_device_addr),
                        dev->req_config_methods);
-               p2p_send_prov_disc_req(p2p, dev, 0, 0);
+               p2p_send_prov_disc_req(p2p, dev,
+                                      dev->flags & P2P_DEV_PD_FOR_JOIN, 0);
                return;
        }
 }
@@ -3198,7 +3197,7 @@ static void p2p_timeout_connect(struct p2p_data *p2p)
                return;
        }
        p2p_set_state(p2p, P2P_CONNECT_LISTEN);
-       p2p_listen_in_find(p2p);
+       p2p_listen_in_find(p2p, 0);
 }
 
 
@@ -3262,7 +3261,7 @@ static void p2p_timeout_wait_peer_idle(struct p2p_data *p2p)
                "P2P: Go to Listen state while waiting for the peer to become "
                "ready for GO Negotiation");
        p2p_set_state(p2p, P2P_WAIT_PEER_CONNECT);
-       p2p_listen_in_find(p2p);
+       p2p_listen_in_find(p2p, 0);
 }
 
 
@@ -3307,9 +3306,23 @@ static void p2p_timeout_prov_disc_req(struct p2p_data *p2p)
                p2p->pd_retries--;
                p2p_retry_pd(p2p);
        } else {
+               struct p2p_device *dev;
+               int for_join = 0;
+
+               dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
+                       if (os_memcmp(p2p->pending_pd_devaddr,
+                                     dev->info.p2p_device_addr, ETH_ALEN) != 0)
+                               continue;
+                       if (dev->req_config_methods &&
+                           (dev->flags & P2P_DEV_PD_FOR_JOIN))
+                               for_join = 1;
+               }
+
                if (p2p->cfg->prov_disc_fail)
                        p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx,
                                                 p2p->pending_pd_devaddr,
+                                                for_join ?
+                                                P2P_PROV_DISC_TIMEOUT_JOIN :
                                                 P2P_PROV_DISC_TIMEOUT);
                p2p_reset_pending_pd(p2p);
        }
@@ -3330,7 +3343,7 @@ static void p2p_timeout_invite(struct p2p_data *p2p)
                p2p_set_timeout(p2p, 0, 100000);
                return;
        }
-       p2p_listen_in_find(p2p);
+       p2p_listen_in_find(p2p, 0);
 }
 
 
@@ -4384,3 +4397,20 @@ int p2p_set_wfd_coupled_sink_info(struct p2p_data *p2p,
 }
 
 #endif /* CONFIG_WIFI_DISPLAY */
+
+
+int p2p_set_disc_int(struct p2p_data *p2p, int min_disc_int, int max_disc_int,
+                    int max_disc_tu)
+{
+       if (min_disc_int > max_disc_int || min_disc_int < 0 || max_disc_int < 0)
+               return -1;
+
+       p2p->min_disc_int = min_disc_int;
+       p2p->max_disc_int = max_disc_int;
+       p2p->max_disc_tu = max_disc_tu;
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Set discoverable interval: "
+               "min=%d max=%d max_tu=%d", min_disc_int, max_disc_int,
+               max_disc_tu);
+
+       return 0;
+}
index b80f898..045e6f7 100644 (file)
@@ -92,6 +92,16 @@ struct p2p_go_neg_results {
        size_t ssid_len;
 
        /**
+        * psk - WPA pre-shared key (256 bits) (GO only)
+        */
+       u8 psk[32];
+
+       /**
+        * psk_set - Whether PSK field is configured (GO only)
+        */
+       int psk_set;
+
+       /**
         * passphrase - WPA2-Personal passphrase for the group (GO only)
         */
        char passphrase[64];
@@ -227,6 +237,7 @@ enum p2p_prov_disc_status {
        P2P_PROV_DISC_SUCCESS,
        P2P_PROV_DISC_TIMEOUT,
        P2P_PROV_DISC_REJECTED,
+       P2P_PROV_DISC_TIMEOUT_JOIN,
 };
 
 struct p2p_channel {
@@ -359,6 +370,11 @@ struct p2p_config {
         */
        size_t ssid_postfix_len;
 
+       /**
+        * max_listen - Maximum listen duration in ms
+        */
+       unsigned int max_listen;
+
 #ifdef ANDROID_P2P
        enum p2p_concurrency_type {
                P2P_NON_CONCURRENT,
@@ -902,6 +918,8 @@ int p2p_listen(struct p2p_data *p2p, unsigned int timeout);
  * @pd_before_go_neg: Whether to send Provision Discovery prior to GO
  *     Negotiation as an interoperability workaround when initiating group
  *     formation
+ * @pref_freq: Preferred operating frequency in MHz or 0 (this is only used if
+ *     force_freq == 0)
  * Returns: 0 on success, -1 on failure
  */
 int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
@@ -909,7 +927,7 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
                int go_intent, const u8 *own_interface_addr,
                unsigned int force_freq, int persistent_group,
                const u8 *force_ssid, size_t force_ssid_len,
-               int pd_before_go_neg);
+               int pd_before_go_neg, unsigned int pref_freq);
 
 /**
  * p2p_authorize - Authorize P2P group formation (GO negotiation)
@@ -925,6 +943,8 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
  * @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
+ * @pref_freq: Preferred operating frequency in MHz or 0 (this is only used if
+ *     force_freq == 0)
  * Returns: 0 on success, -1 on failure
  *
  * This is like p2p_connect(), but the actual group negotiation is not
@@ -934,7 +954,8 @@ 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,
-                 const u8 *force_ssid, size_t force_ssid_len);
+                 const u8 *force_ssid, size_t force_ssid_len,
+                 unsigned int pref_freq);
 
 /**
  * p2p_reject - Reject peer device (explicitly block connection attempts)
@@ -951,6 +972,7 @@ int p2p_reject(struct p2p_data *p2p, const u8 *peer_addr);
  * @config_methods: WPS Config Methods value (only one bit set)
  * @join: Whether this is used by a client joining an active group
  * @force_freq: Forced TX frequency for the frame (mainly for the join case)
+ * @user_initiated_pd: Flag to indicate if initiated by user or not
  * Returns: 0 on success, -1 on failure
  *
  * This function can be used to request a discovered P2P peer to display a PIN
@@ -962,7 +984,8 @@ int p2p_reject(struct p2p_data *p2p, const u8 *peer_addr);
  * indicated with the p2p_config::prov_disc_resp() callback.
  */
 int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
-                     u16 config_methods, int join, int force_freq);
+                     u16 config_methods, int join, int force_freq,
+                     int user_initiated_pd);
 
 /**
  * p2p_sd_request - Schedule a service discovery query
@@ -1767,4 +1790,25 @@ int p2p_set_wfd_coupled_sink_info(struct p2p_data *p2p,
                                  const struct wpabuf *elem);
 struct wpabuf * wifi_display_encaps(struct wpabuf *subelems);
 
+/**
+ * p2p_set_disc_int - Set min/max discoverable interval for p2p_find
+ * @p2p: P2P module context from p2p_init()
+ * @min_disc_int: minDiscoverableInterval (in units of 100 TU); default 1
+ * @max_disc_int: maxDiscoverableInterval (in units of 100 TU); default 3
+ * @max_disc_tu: Maximum number of TUs (1.024 ms) for discoverable interval; or
+ *     -1 not to limit
+ * Returns: 0 on success, or -1 on failure
+ *
+ * This function can be used to configure minDiscoverableInterval and
+ * maxDiscoverableInterval parameters for the Listen state during device
+ * discovery (p2p_find). A random number of 100 TU units is picked for each
+ * Listen state iteration from [min_disc_int,max_disc_int] range.
+ *
+ * max_disc_tu can be used to futher limit the discoverable duration. However,
+ * it should be noted that use of this parameter is not recommended since it
+ * would not be compliant with the P2P specification.
+ */
+int p2p_set_disc_int(struct p2p_data *p2p, int min_disc_int, int max_disc_int,
+                    int max_disc_tu);
+
 #endif /* P2P_H */
index be069a5..5838d35 100644 (file)
@@ -136,6 +136,7 @@ void p2p_buf_add_channel_list(struct wpabuf *buf, const char *country,
                    len + 2, (u8 *) wpabuf_put(buf, 0) - len - 2);
 }
 
+
 void p2p_buf_add_status(struct wpabuf *buf, u8 status)
 {
        /* Status */
index b21d97c..fe4b560 100644 (file)
@@ -211,7 +211,7 @@ int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev)
                else
                        return -1;
                return p2p_prov_disc_req(p2p, dev->info.p2p_device_addr,
-                                        config_method, 0, 0);
+                                        config_method, 0, 0, 1);
        }
 
        freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
@@ -302,7 +302,6 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
                                              p2p->op_channel);
        }
        p2p_buf_add_intended_addr(buf, p2p->intended_addr);
-
        if (status || peer == NULL) {
                p2p_buf_add_channel_list(buf, p2p->cfg->country,
                                         &p2p->channels);
@@ -315,7 +314,6 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
                                       &res);
                p2p_buf_add_channel_list(buf, p2p->cfg->country, &res);
        }
-
        p2p_buf_add_device_info(buf, p2p, peer);
        if (peer && peer->go_state == LOCAL_GO) {
                p2p_buf_add_group_id(buf, p2p->cfg->dev_addr, p2p->ssid,
index 673c4c1..d2868fb 100644 (file)
@@ -226,6 +226,11 @@ struct p2p_data {
        int max_disc_int;
 
        /**
+        * max_disc_tu - Maximum number of TUs for discoverable interval
+        */
+       int max_disc_tu;
+
+       /**
         * devices - List of known P2P Device peers
         */
        struct dl_list devices;
index 42447e5..e40f2b7 100644 (file)
@@ -19,7 +19,7 @@
  * Number of retries to attempt for provision discovery requests
  * in case the peer is not listening.
  */
-#define MAX_PROV_DISC_REQ_RETRIES 10
+#define MAX_PROV_DISC_REQ_RETRIES 120
 
 
 static void p2p_build_wps_ie_config_methods(struct wpabuf *buf,
@@ -408,7 +408,8 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
 
 
 int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
-                     u16 config_methods, int join, int force_freq)
+                     u16 config_methods, int join, int force_freq,
+                     int user_initiated_pd)
 {
        struct p2p_device *dev;
 
@@ -446,11 +447,7 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
                return 0;
        }
 
-       /*
-        * We use the join param as a cue to differentiate between user
-        * initiated PD request and one issued during finds (internal).
-        */
-       p2p->user_initiated_pd = !join;
+       p2p->user_initiated_pd = user_initiated_pd;
 
        if (p2p->user_initiated_pd)
                p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES;
index d5edfd8..d1feec9 100644 (file)
@@ -1406,11 +1406,12 @@ int radius_msg_get_vlanid(struct radius_msg *msg)
  * @secret: RADIUS shared secret
  * @secret_len: Length of secret
  * @sent_msg: Sent RADIUS message
- * Returns: pointer to password (free with os_free) or %NULL
+ * @n: Number of password attribute to return (starting with 0)
+ * Returns: Pointer to n-th password (free with os_free) or %NULL
  */
 char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
                                      const u8 *secret, size_t secret_len,
-                                     struct radius_msg *sent_msg)
+                                     struct radius_msg *sent_msg, size_t n)
 {
        u8 *buf = NULL;
        size_t buflen;
@@ -1420,7 +1421,7 @@ char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
        size_t len[3];
        u8 hash[16];
        u8 *pos;
-       size_t i;
+       size_t i, j = 0;
        struct radius_attr_hdr *attr;
        const u8 *data;
        size_t dlen;
@@ -1428,7 +1429,7 @@ char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
        size_t fdlen = -1;
        char *ret = NULL;
 
-       /* find attribute with lowest tag and check it */
+       /* find n-th valid Tunnel-Password attribute */
        for (i = 0; i < msg->attr_used; i++) {
                attr = radius_get_attr_hdr(msg, i);
                if (attr == NULL ||
@@ -1441,11 +1442,13 @@ char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
                dlen = attr->length - sizeof(*attr);
                if (dlen <= 3 || dlen % 16 != 3)
                        continue;
-               if (fdata != NULL && fdata[0] <= data[0])
+               j++;
+               if (j <= n)
                        continue;
 
                fdata = data;
                fdlen = dlen;
+               break;
        }
        if (fdata == NULL)
                goto out;
index 727640b..2031054 100644 (file)
@@ -242,7 +242,7 @@ int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len);
 int radius_msg_get_vlanid(struct radius_msg *msg);
 char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
                                      const u8 *secret, size_t secret_len,
-                                     struct radius_msg *sent_msg);
+                                     struct radius_msg *sent_msg, size_t n);
 
 static inline int radius_msg_add_attr_int32(struct radius_msg *msg, u8 type,
                                            u32 value)
index 9783e7c..df67583 100644 (file)
@@ -25,7 +25,7 @@ struct rsn_pmksa_cache {
        struct wpa_sm *sm; /* TODO: get rid of this reference(?) */
 
        void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx,
-                       int replace);
+                       enum pmksa_free_reason reason);
        void *ctx;
 };
 
@@ -41,11 +41,11 @@ static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
 
 static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
                                   struct rsn_pmksa_cache_entry *entry,
-                                  int replace)
+                                  enum pmksa_free_reason reason)
 {
        wpa_sm_remove_pmkid(pmksa->sm, entry->aa, entry->pmkid);
        pmksa->pmksa_count--;
-       pmksa->free_cb(entry, pmksa->ctx, replace);
+       pmksa->free_cb(entry, pmksa->ctx, reason);
        _pmksa_cache_free_entry(entry);
 }
 
@@ -61,7 +61,7 @@ static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
                pmksa->pmksa = entry->next;
                wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
                           MACSTR, MAC2STR(entry->aa));
-               pmksa_cache_free_entry(pmksa, entry, 0);
+               pmksa_cache_free_entry(pmksa, entry, PMKSA_EXPIRE);
        }
 
        pmksa_cache_set_expiration(pmksa);
@@ -164,22 +164,9 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
                                pmksa->pmksa = pos->next;
                        else
                                prev->next = pos->next;
-                       if (pos == pmksa->sm->cur_pmksa) {
-                               /* We are about to replace the current PMKSA
-                                * cache entry. This happens when the PMKSA
-                                * caching attempt fails, so we don't want to
-                                * force pmksa_cache_free_entry() to disconnect
-                                * at this point. Let's just make sure the old
-                                * PMKSA cache entry will not be used in the
-                                * future.
-                                */
-                               wpa_printf(MSG_DEBUG, "RSN: replacing current "
-                                          "PMKSA entry");
-                               pmksa->sm->cur_pmksa = NULL;
-                       }
                        wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
                                   "the current AP");
-                       pmksa_cache_free_entry(pmksa, pos, 1);
+                       pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE);
 
                        /*
                         * If OKC is used, there may be other PMKSA cache
@@ -214,7 +201,7 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
                                   "PMKSA cache entry (for " MACSTR ") to "
                                   "make room for new one",
                                   MAC2STR(pos->aa));
-                       pmksa_cache_free_entry(pmksa, pos, 0);
+                       pmksa_cache_free_entry(pmksa, pos, PMKSA_FREE);
                }
        }
 
@@ -265,7 +252,7 @@ void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx)
                                pmksa->pmksa = entry->next;
                        tmp = entry;
                        entry = entry->next;
-                       pmksa_cache_free_entry(pmksa, tmp, 0);
+                       pmksa_cache_free_entry(pmksa, tmp, PMKSA_FREE);
                        removed++;
                } else {
                        prev = entry;
@@ -507,7 +494,7 @@ int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
  */
 struct rsn_pmksa_cache *
 pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
-                                void *ctx, int replace),
+                                void *ctx, enum pmksa_free_reason reason),
                 void *ctx, struct wpa_sm *sm)
 {
        struct rsn_pmksa_cache *pmksa;
index 9245aab..f318c52 100644 (file)
@@ -38,11 +38,17 @@ struct rsn_pmksa_cache_entry {
 
 struct rsn_pmksa_cache;
 
+enum pmksa_free_reason {
+       PMKSA_FREE,
+       PMKSA_REPLACE,
+       PMKSA_EXPIRE,
+};
+
 #if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
 
 struct rsn_pmksa_cache *
 pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
-                                void *ctx, int replace),
+                                void *ctx, enum pmksa_free_reason reason),
                 void *ctx, struct wpa_sm *sm);
 void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa);
 struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
@@ -66,7 +72,7 @@ void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx);
 
 static inline struct rsn_pmksa_cache *
 pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
-                                void *ctx, int replace),
+                                void *ctx, int reason),
                 void *ctx, struct wpa_sm *sm)
 {
        return (void *) -1;
index 5cf32df..3c45f3a 100644 (file)
@@ -783,7 +783,7 @@ static void wpa_report_ie_mismatch(struct wpa_sm *sm,
                            rsn_ie, rsn_ie_len);
        }
 
-       wpa_sm_disassociate(sm, WLAN_REASON_IE_IN_4WAY_DIFFERS);
+       wpa_sm_deauthenticate(sm, WLAN_REASON_IE_IN_4WAY_DIFFERS);
 }
 
 
@@ -1836,6 +1836,10 @@ static u32 wpa_key_mgmt_suite(struct wpa_sm *sm)
        case WPA_KEY_MGMT_PSK_SHA256:
                return RSN_AUTH_KEY_MGMT_PSK_SHA256;
 #endif /* CONFIG_IEEE80211W */
+       case WPA_KEY_MGMT_CCKM:
+               return (sm->proto == WPA_PROTO_RSN ?
+                       RSN_AUTH_KEY_MGMT_CCKM:
+                       WPA_AUTH_KEY_MGMT_CCKM);
        case WPA_KEY_MGMT_WPA_NONE:
                return WPA_AUTH_KEY_MGMT_NONE;
        default:
@@ -1931,25 +1935,40 @@ int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
 
 
 static void wpa_sm_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
-                                void *ctx, int replace)
+                                void *ctx, enum pmksa_free_reason reason)
 {
        struct wpa_sm *sm = ctx;
+       int deauth = 0;
+
+       wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA cache entry free_cb: "
+               MACSTR " reason=%d", MAC2STR(entry->aa), reason);
+
+       if (sm->cur_pmksa == entry) {
+               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+                       "RSN: %s current PMKSA entry",
+                       reason == PMKSA_REPLACE ? "replaced" : "removed");
+               pmksa_cache_clear_current(sm);
+
+               /*
+                * If an entry is simply being replaced, there's no need to
+                * deauthenticate because it will be immediately re-added.
+                * This happens when EAP authentication is completed again
+                * (reauth or failed PMKSA caching attempt).
+                */
+               if (reason != PMKSA_REPLACE)
+                       deauth = 1;
+       }
 
-       if (sm->cur_pmksa == entry ||
+       if (reason == PMKSA_EXPIRE &&
            (sm->pmk_len == entry->pmk_len &&
             os_memcmp(sm->pmk, entry->pmk, sm->pmk_len) == 0)) {
                wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
-                       "RSN: removed current PMKSA entry");
-               sm->cur_pmksa = NULL;
-
-               if (replace) {
-                       /* A new entry is being added, so no need to
-                        * deauthenticate in this case. This happens when EAP
-                        * authentication is completed again (reauth or failed
-                        * PMKSA caching attempt). */
-                       return;
-               }
+                       "RSN: deauthenticating due to expired PMK");
+               pmksa_cache_clear_current(sm);
+               deauth = 1;
+       }
 
+       if (deauth) {
                os_memset(sm->pmk, 0, sizeof(sm->pmk));
                wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
        }
@@ -2080,6 +2099,7 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
 void wpa_sm_notify_disassoc(struct wpa_sm *sm)
 {
        rsn_preauth_deinit(sm);
+       pmksa_cache_clear_current(sm);
        if (wpa_sm_get_state(sm) == WPA_4WAY_HANDSHAKE)
                sm->dot11RSNA4WayHandshakeFailures++;
 #ifdef CONFIG_TDLS
@@ -2372,6 +2392,22 @@ int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
        if (ret < 0 || ret >= end - pos)
                return pos - buf;
        pos += ret;
+
+       if (sm->mfp != NO_MGMT_FRAME_PROTECTION && sm->ap_rsn_ie) {
+               struct wpa_ie_data rsn;
+               if (wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &rsn)
+                   >= 0 &&
+                   rsn.capabilities & (WPA_CAPABILITY_MFPR |
+                                       WPA_CAPABILITY_MFPC)) {
+                       ret = os_snprintf(pos, end - pos, "pmf=%d\n",
+                                         (rsn.capabilities &
+                                          WPA_CAPABILITY_MFPR) ? 2 : 1);
+                       if (ret < 0 || ret >= end - pos)
+                               return pos - buf;
+                       pos += ret;
+               }
+       }
+
        return pos - buf;
 }
 
index 1077b5a..8afdf39 100644 (file)
@@ -24,7 +24,6 @@ struct wpa_sm_ctx {
        void (*set_state)(void *ctx, enum wpa_states state);
        enum wpa_states (*get_state)(void *ctx);
        void (*deauthenticate)(void * ctx, int reason_code); 
-       void (*disassociate)(void *ctx, int reason_code);
        int (*set_key)(void *ctx, enum wpa_alg alg,
                       const u8 *addr, int key_idx, int set_tx,
                       const u8 *seq, size_t seq_len,
index c30d09e..9f9e641 100644 (file)
@@ -143,12 +143,6 @@ static inline void wpa_sm_deauthenticate(struct wpa_sm *sm, int reason_code)
        sm->ctx->deauthenticate(sm->ctx->ctx, reason_code);
 }
 
-static inline void wpa_sm_disassociate(struct wpa_sm *sm, int reason_code)
-{
-       WPA_ASSERT(sm->ctx->disassociate);
-       sm->ctx->disassociate(sm->ctx->ctx, reason_code);
-}
-
 static inline int wpa_sm_set_key(struct wpa_sm *sm, enum wpa_alg alg,
                                 const u8 *addr, int key_idx, int set_tx,
                                 const u8 *seq, size_t seq_len,
index 6a8f9f1..3d75365 100644 (file)
@@ -83,6 +83,8 @@ static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
                RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
        } else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
                RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE);
+       } else if (key_mgmt == WPA_KEY_MGMT_CCKM) {
+               RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_CCKM);
        } else {
                wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
                           key_mgmt);
@@ -152,6 +154,8 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
                RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
        } else if (key_mgmt == WPA_KEY_MGMT_PSK) {
                RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
+       } else if (key_mgmt == WPA_KEY_MGMT_CCKM) {
+               RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_CCKM);
 #ifdef CONFIG_IEEE80211R
        } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
                RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
@@ -164,6 +168,12 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
        } else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) {
                RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
 #endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+       } else if (key_mgmt == WPA_KEY_MGMT_SAE) {
+               RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
+       } else if (key_mgmt == WPA_KEY_MGMT_FT_SAE) {
+               RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
+#endif /* CONFIG_SAE */
        } else {
                wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
                           key_mgmt);
index 7630ecb..a48a2d7 100644 (file)
 #include "includes.h"
 #include "common.h"
 #include "wps/wps.h"
-#include "wps/wps_i.h"
 
 #define FLAG_MESSAGE_BEGIN (1 << 7)
 #define FLAG_MESSAGE_END (1 << 6)
 #define FLAG_CHUNK (1 << 5)
 #define FLAG_SHORT_RECORD (1 << 4)
 #define FLAG_ID_LENGTH_PRESENT (1 << 3)
+#define FLAG_TNF_NFC_FORUM (0x01)
 #define FLAG_TNF_RFC2046 (0x02)
 
 struct ndef_record {
@@ -168,3 +168,78 @@ struct wpabuf * ndef_build_wifi(const struct wpabuf *buf)
                                 FLAG_TNF_RFC2046, wifi_handover_type,
                                 os_strlen(wifi_handover_type), NULL, 0, buf);
 }
+
+
+struct wpabuf * ndef_build_wifi_hr(void)
+{
+       struct wpabuf *rn, *cr, *ac_payload, *ac, *hr_payload, *hr;
+       struct wpabuf *carrier, *hc;
+
+       rn = wpabuf_alloc(2);
+       if (rn == NULL)
+               return NULL;
+       wpabuf_put_be16(rn, os_random() & 0xffff);
+
+       cr = ndef_build_record(FLAG_MESSAGE_BEGIN | FLAG_TNF_NFC_FORUM, "cr", 2,
+                              NULL, 0, rn);
+       wpabuf_free(rn);
+
+       if (cr == NULL)
+               return NULL;
+
+       ac_payload = wpabuf_alloc(4);
+       if (ac_payload == NULL) {
+               wpabuf_free(cr);
+               return NULL;
+       }
+       wpabuf_put_u8(ac_payload, 0x01); /* Carrier Flags: CRS=1 "active" */
+       wpabuf_put_u8(ac_payload, 0x01); /* Carrier Data Reference Length */
+       wpabuf_put_u8(ac_payload, '0'); /* Carrier Data Reference: "0" */
+       wpabuf_put_u8(ac_payload, 0); /* Aux Data Reference Count */
+
+       ac = ndef_build_record(FLAG_MESSAGE_END | FLAG_TNF_NFC_FORUM, "ac", 2,
+                              NULL, 0, ac_payload);
+       wpabuf_free(ac_payload);
+       if (ac == NULL) {
+               wpabuf_free(cr);
+               return NULL;
+       }
+
+       hr_payload = wpabuf_alloc(1 + wpabuf_len(cr) + wpabuf_len(ac));
+       if (hr_payload == NULL) {
+               wpabuf_free(cr);
+               wpabuf_free(ac);
+               return NULL;
+       }
+
+       wpabuf_put_u8(hr_payload, 0x12); /* Connection Handover Version 1.2 */
+       wpabuf_put_buf(hr_payload, cr);
+       wpabuf_put_buf(hr_payload, ac);
+       wpabuf_free(cr);
+       wpabuf_free(ac);
+
+       hr = ndef_build_record(FLAG_MESSAGE_BEGIN | FLAG_TNF_NFC_FORUM, "Hr", 2,
+                              NULL, 0, hr_payload);
+       wpabuf_free(hr_payload);
+       if (hr == NULL)
+               return NULL;
+
+       carrier = wpabuf_alloc(2 + os_strlen(wifi_handover_type));
+       if (carrier == NULL) {
+               wpabuf_free(hr);
+               return NULL;
+       }
+       wpabuf_put_u8(carrier, 0x02); /* Carrier Type Format */
+       wpabuf_put_u8(carrier, os_strlen(wifi_handover_type));
+       wpabuf_put_str(carrier, wifi_handover_type);
+
+       hc = ndef_build_record(FLAG_MESSAGE_END | FLAG_TNF_NFC_FORUM, "Hc", 2,
+                              "0", 1, carrier);
+       wpabuf_free(carrier);
+       if (hc == NULL) {
+               wpabuf_free(hr);
+               return NULL;
+       }
+
+       return wpabuf_concat(hr, hc);
+}
index 4c2322d..2575705 100644 (file)
@@ -45,8 +45,7 @@ struct wps_data * wps_init(const struct wps_config *cfg)
                os_memcpy(data->uuid_e, cfg->wps->uuid, WPS_UUID_LEN);
        }
        if (cfg->pin) {
-               data->dev_pw_id = data->wps->oob_dev_pw_id == 0 ?
-                       cfg->dev_pw_id : data->wps->oob_dev_pw_id;
+               data->dev_pw_id = cfg->dev_pw_id;
                data->dev_password = os_malloc(cfg->pin_len);
                if (data->dev_password == NULL) {
                        os_free(data);
@@ -110,6 +109,7 @@ struct wps_data * wps_init(const struct wps_config *cfg)
                data->new_ap_settings =
                        os_malloc(sizeof(*data->new_ap_settings));
                if (data->new_ap_settings == NULL) {
+                       os_free(data->dev_password);
                        os_free(data);
                        return NULL;
                }
index c45b68c..c6b7099 100644 (file)
@@ -42,6 +42,7 @@ struct wps_parse_attr;
  * @cred_attr: Unparsed Credential attribute data (used only in cred_cb());
  *     this may be %NULL, if not used
  * @cred_attr_len: Length of cred_attr in octets
+ * @ap_channel: AP channel
  */
 struct wps_credential {
        u8 ssid[32];
@@ -54,6 +55,7 @@ struct wps_credential {
        u8 mac_addr[ETH_ALEN];
        const u8 *cred_attr;
        size_t cred_attr_len;
+       u16 ap_channel;
 };
 
 #define WPS_DEV_TYPE_LEN 8
@@ -101,17 +103,6 @@ struct wps_device_data {
        int p2p;
 };
 
-struct oob_conf_data {
-       enum {
-               OOB_METHOD_UNKNOWN = 0,
-               OOB_METHOD_DEV_PWD_E,
-               OOB_METHOD_DEV_PWD_R,
-               OOB_METHOD_CRED,
-       } oob_method;
-       struct wpabuf *dev_password;
-       struct wpabuf *pubkey_hash;
-};
-
 /**
  * struct wps_config - WPS configuration for a single registration protocol run
  */
@@ -617,16 +608,6 @@ struct wps_context {
        struct wps_device_data dev;
 
        /**
-        * oob_conf - OOB Config data
-        */
-       struct oob_conf_data oob_conf;
-
-       /**
-        * oob_dev_pw_id - OOB Device password id
-        */
-       u16 oob_dev_pw_id;
-
-       /**
         * dh_ctx - Context data for Diffie-Hellman operation
         */
        void *dh_ctx;
@@ -764,23 +745,6 @@ struct wps_context {
        struct wpabuf *ap_nfc_dev_pw;
 };
 
-struct oob_device_data {
-       char *device_name;
-       char *device_path;
-       void * (*init_func)(struct wps_context *, struct oob_device_data *,
-                           int);
-       struct wpabuf * (*read_func)(void *);
-       int (*write_func)(void *, struct wpabuf *);
-       void (*deinit_func)(void *);
-};
-
-struct oob_nfc_device_data {
-       int (*init_func)(char *);
-       void * (*read_func)(size_t *);
-       int (*write_func)(void *, size_t);
-       void (*deinit_func)(void);
-};
-
 struct wps_registrar *
 wps_registrar_init(struct wps_context *wps,
                   const struct wps_registrar_config *cfg);
@@ -819,11 +783,6 @@ 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);
-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);
@@ -858,6 +817,7 @@ struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,
 /* ndef.c */
 struct wpabuf * ndef_parse_wifi(const struct wpabuf *buf);
 struct wpabuf * ndef_build_wifi(const struct wpabuf *buf);
+struct wpabuf * ndef_build_wifi_hr(void);
 
 #ifdef CONFIG_WPS_STRICT
 int wps_validate_beacon(const struct wpabuf *wps_ie);
index 9be30b9..29aee8e 100644 (file)
@@ -368,38 +368,6 @@ int wps_build_oob_dev_pw(struct wpabuf *msg, u16 dev_pw_id,
 
        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");
-
-       if (os_get_random((u8 *) &wps->oob_dev_pw_id, sizeof(u16)) < 0) {
-               wpa_printf(MSG_ERROR, "WPS: device password id "
-                          "generation error");
-               return -1;
-       }
-       wps->oob_dev_pw_id |= 0x0010;
-
-       if (random_get_bytes(dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN) <
-           0) {
-               wpa_printf(MSG_ERROR, "WPS: OOB device password "
-                          "generation error");
-               return -1;
-       }
-
-       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 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 5aa9b00..3999b1b 100644 (file)
@@ -542,6 +542,14 @@ static int wps_set_attr(struct wps_parse_attr *attr, u16 type,
                if (wps_parse_vendor_ext(attr, pos, len) < 0)
                        return -1;
                break;
+       case ATTR_AP_CHANNEL:
+               if (len != 2) {
+                       wpa_printf(MSG_DEBUG, "WPS: Invalid AP Channel "
+                                  "length %u", len);
+                       return -1;
+               }
+               attr->ap_channel = pos;
+               break;
        default:
                wpa_printf(MSG_DEBUG, "WPS: Unsupported attribute type 0x%x "
                           "len=%u", type, len);
index 332e966..88e51a4 100644 (file)
@@ -56,6 +56,7 @@ struct wps_parse_attr {
        const u8 *settings_delay_time; /* 1 octet */
        const u8 *network_key_shareable; /* 1 octet (Bool) */
        const u8 *request_to_enroll; /* 1 octet (Bool) */
+       const u8 *ap_channel; /* 2 octets */
 
        /* variable length fields */
        const u8 *manufacturer;
index d4c6e88..b81f106 100644 (file)
@@ -258,6 +258,19 @@ static int wps_process_cred_802_1x_enabled(struct wps_credential *cred,
 }
 
 
+static int wps_process_cred_ap_channel(struct wps_credential *cred,
+                                      const u8 *ap_channel)
+{
+       if (ap_channel == NULL)
+               return 0; /* optional attribute */
+
+       cred->ap_channel = WPA_GET_BE16(ap_channel);
+       wpa_printf(MSG_DEBUG, "WPS: AP Channel: %u", cred->ap_channel);
+
+       return 0;
+}
+
+
 static int wps_workaround_cred_key(struct wps_credential *cred)
 {
        if (cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK) &&
@@ -303,7 +316,8 @@ int wps_process_cred(struct wps_parse_attr *attr,
            wps_process_cred_eap_identity(cred, attr->eap_identity,
                                          attr->eap_identity_len) ||
            wps_process_cred_key_prov_auto(cred, attr->key_prov_auto) ||
-           wps_process_cred_802_1x_enabled(cred, attr->dot1x_enabled))
+           wps_process_cred_802_1x_enabled(cred, attr->dot1x_enabled) ||
+           wps_process_cred_ap_channel(cred, attr->ap_channel))
                return -1;
 
        return wps_workaround_cred_key(cred);
index 5a8817f..68d9f0a 100644 (file)
@@ -375,84 +375,6 @@ struct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id,
 }
 
 
-static struct wpabuf * wps_get_oob_dev_pwd(struct wps_context *wps)
-{
-       struct wpabuf *data;
-
-       data = wpabuf_alloc(200);
-       if (data == NULL) {
-               wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
-                          "device password attribute");
-               return NULL;
-       }
-
-       wpabuf_free(wps->oob_conf.dev_password);
-       wps->oob_conf.dev_password =
-               wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN * 2 + 1);
-       if (wps->oob_conf.dev_password == NULL) {
-               wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
-                          "device password");
-               wpabuf_free(data);
-               return NULL;
-       }
-
-       if (wps_build_version(data) ||
-           wps_build_oob_dev_password(data, wps) ||
-           wps_build_wfa_ext(data, 0, NULL, 0)) {
-               wpa_printf(MSG_ERROR, "WPS: Build OOB device password "
-                          "attribute error");
-               wpabuf_free(data);
-               return NULL;
-       }
-
-       return data;
-}
-
-
-static int wps_parse_oob_dev_pwd(struct wps_context *wps,
-                                struct wpabuf *data)
-{
-       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) {
-               wpa_printf(MSG_ERROR, "WPS: OOB device password not found");
-               return -1;
-       }
-
-       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) {
-               wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
-                          "public key hash");
-               return -1;
-       }
-       pos += WPS_OOB_PUBKEY_HASH_LEN;
-
-       wps->oob_dev_pw_id = WPA_GET_BE16(pos);
-       pos += sizeof(wps->oob_dev_pw_id);
-
-       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,
-                                             pw_len * 2 + 1),
-                                  pw_len * 2 + 1, pos, pw_len);
-
-       return 0;
-}
-
-
 int wps_oob_use_cred(struct wps_context *wps, struct wps_parse_attr *attr)
 {
        struct wpabuf msg;
@@ -477,107 +399,6 @@ int wps_oob_use_cred(struct wps_context *wps, struct wps_parse_attr *attr)
 }
 
 
-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)
-{
-       struct wpabuf *data;
-       int ret, write_f, oob_method = wps->oob_conf.oob_method;
-       void *oob_priv;
-
-       write_f = oob_method == OOB_METHOD_DEV_PWD_E ? !registrar : registrar;
-
-       oob_priv = oob_dev->init_func(wps, oob_dev, registrar);
-       if (oob_priv == NULL) {
-               wpa_printf(MSG_ERROR, "WPS: Failed to initialize OOB device");
-               return -1;
-       }
-
-       if (write_f) {
-               if (oob_method == OOB_METHOD_CRED)
-                       data = wps_get_oob_cred(wps);
-               else
-                       data = wps_get_oob_dev_pwd(wps);
-
-               ret = 0;
-               if (data == NULL || oob_dev->write_func(oob_priv, data) < 0)
-                       ret = -1;
-       } else {
-               data = oob_dev->read_func(oob_priv);
-               if (data == NULL)
-                       ret = -1;
-               else {
-                       if (oob_method == OOB_METHOD_CRED)
-                               ret = wps_parse_oob_cred(wps, data);
-                       else
-                               ret = wps_parse_oob_dev_pwd(wps, data);
-               }
-       }
-       wpabuf_free(data);
-       oob_dev->deinit_func(oob_priv);
-
-       if (ret < 0) {
-               wpa_printf(MSG_ERROR, "WPS: Failed to process OOB data");
-               return -1;
-       }
-
-       return 0;
-}
-
-
-struct oob_device_data * wps_get_oob_device(char *device_type)
-{
-#ifdef CONFIG_WPS_UFD
-       if (os_strstr(device_type, "ufd") != NULL)
-               return &oob_ufd_device_data;
-#endif /* CONFIG_WPS_UFD */
-#ifdef CONFIG_WPS_NFC
-       if (os_strstr(device_type, "nfc") != NULL)
-               return &oob_nfc_device_data;
-#endif /* CONFIG_WPS_NFC */
-
-       return NULL;
-}
-
-
-#ifdef CONFIG_WPS_NFC
-struct oob_nfc_device_data * wps_get_oob_nfc_device(char *device_name)
-{
-       if (device_name == NULL)
-               return NULL;
-#ifdef CONFIG_WPS_NFC_PN531
-       if (os_strstr(device_name, "pn531") != NULL)
-               return &oob_nfc_pn531_device_data;
-#endif /* CONFIG_WPS_NFC_PN531 */
-
-       return NULL;
-}
-#endif /* CONFIG_WPS_NFC */
-
-
-int wps_get_oob_method(char *method)
-{
-       if (os_strstr(method, "pin-e") != NULL)
-               return OOB_METHOD_DEV_PWD_E;
-       if (os_strstr(method, "pin-r") != NULL)
-               return OOB_METHOD_DEV_PWD_R;
-       if (os_strstr(method, "cred") != NULL)
-               return OOB_METHOD_CRED;
-       return OOB_METHOD_UNKNOWN;
-}
-
 #endif /* CONFIG_WPS_OOB */
 
 
@@ -657,15 +478,10 @@ u16 wps_config_methods_str2bin(const char *str)
 #ifdef CONFIG_WPS2
                methods |= WPS_CONFIG_VIRT_DISPLAY;
 #endif /* CONFIG_WPS2 */
-#ifdef CONFIG_WPS_UFD
-               methods |= WPS_CONFIG_USBA;
-#endif /* CONFIG_WPS_UFD */
 #ifdef CONFIG_WPS_NFC
                methods |= WPS_CONFIG_NFC_INTERFACE;
 #endif /* CONFIG_WPS_NFC */
        } else {
-               if (os_strstr(str, "usba"))
-                       methods |= WPS_CONFIG_USBA;
                if (os_strstr(str, "ethernet"))
                        methods |= WPS_CONFIG_ETHERNET;
                if (os_strstr(str, "label"))
index 389aa84..837b941 100644 (file)
@@ -523,23 +523,6 @@ static int wps_process_pubkey(struct wps_data *wps, const u8 *pk,
                return -1;
        }
 
-#ifdef CONFIG_WPS_OOB
-       if (wps->dev_pw_id != DEV_PW_DEFAULT &&
-           wps->wps->oob_conf.pubkey_hash) {
-               const u8 *addr[1];
-               u8 hash[WPS_HASH_LEN];
-
-               addr[0] = pk;
-               sha256_vector(1, addr, &pk_len, hash);
-               if (os_memcmp(hash,
-                             wpabuf_head(wps->wps->oob_conf.pubkey_hash),
-                             WPS_OOB_PUBKEY_HASH_LEN) != 0) {
-                       wpa_printf(MSG_ERROR, "WPS: Public Key hash error");
-                       return -1;
-               }
-       }
-#endif /* CONFIG_WPS_OOB */
-
        wpabuf_free(wps->dh_pubkey_r);
        wps->dh_pubkey_r = wpabuf_alloc_copy(pk, pk_len);
        if (wps->dh_pubkey_r == NULL)
@@ -665,6 +648,7 @@ static int wps_process_cred_e(struct wps_data *wps, const u8 *cred,
 {
        struct wps_parse_attr attr;
        struct wpabuf msg;
+       int ret = 0;
 
        wpa_printf(MSG_DEBUG, "WPS: Received Credential");
        os_memset(&wps->cred, 0, sizeof(wps->cred));
@@ -714,12 +698,12 @@ static int wps_process_cred_e(struct wps_data *wps, const u8 *cred,
        if (wps->wps->cred_cb) {
                wps->cred.cred_attr = cred - 4;
                wps->cred.cred_attr_len = cred_len + 4;
-               wps->wps->cred_cb(wps->wps->cb_ctx, &wps->cred);
+               ret = wps->wps->cred_cb(wps->wps->cb_ctx, &wps->cred);
                wps->cred.cred_attr = NULL;
                wps->cred.cred_attr_len = 0;
        }
 
-       return 0;
+       return ret;
 }
 
 
index 86ad248..8110894 100644 (file)
@@ -137,10 +137,6 @@ void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part);
 void wps_pbc_overlap_event(struct wps_context *wps);
 void wps_pbc_timeout_event(struct wps_context *wps);
 
-extern struct oob_device_data oob_ufd_device_data;
-extern struct oob_device_data oob_nfc_device_data;
-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);
 
@@ -169,7 +165,6 @@ 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);
 
 /* wps_attr_process.c */
diff --git a/src/wps/wps_nfc.c b/src/wps/wps_nfc.c
deleted file mode 100644 (file)
index 6804350..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * NFC routines for Wi-Fi Protected Setup
- * Copyright (c) 2009-2012, Masashi Honma <masashi.honma@gmail.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-#include "common.h"
-
-#include "wps/wps.h"
-#include "wps_i.h"
-
-
-struct wps_nfc_data {
-       struct oob_nfc_device_data *oob_nfc_dev;
-};
-
-
-static void * init_nfc(struct wps_context *wps,
-                      struct oob_device_data *oob_dev, int registrar)
-{
-       struct oob_nfc_device_data *oob_nfc_dev;
-       struct wps_nfc_data *data;
-
-       oob_nfc_dev = wps_get_oob_nfc_device(oob_dev->device_name);
-       if (oob_nfc_dev == NULL) {
-               wpa_printf(MSG_ERROR, "WPS (NFC): Unknown NFC device (%s)",
-                          oob_dev->device_name);
-               return NULL;
-       }
-
-       if (oob_nfc_dev->init_func(oob_dev->device_path) < 0)
-               return NULL;
-
-       data = os_zalloc(sizeof(*data));
-       if (data == NULL) {
-               wpa_printf(MSG_ERROR, "WPS (NFC): Failed to allocate "
-                          "nfc data area");
-               return NULL;
-       }
-       data->oob_nfc_dev = oob_nfc_dev;
-       return data;
-}
-
-
-static struct wpabuf * read_nfc(void *priv)
-{
-       struct wps_nfc_data *data = priv;
-       struct wpabuf *wifi, *buf;
-       char *raw_data;
-       size_t len;
-
-       raw_data = data->oob_nfc_dev->read_func(&len);
-       if (raw_data == NULL)
-               return NULL;
-
-       wifi = wpabuf_alloc_copy(raw_data, len);
-       os_free(raw_data);
-       if (wifi == NULL) {
-               wpa_printf(MSG_ERROR, "WPS (NFC): Failed to allocate "
-                          "nfc read area");
-               return NULL;
-       }
-
-       buf = ndef_parse_wifi(wifi);
-       wpabuf_free(wifi);
-       if (buf == NULL)
-               wpa_printf(MSG_ERROR, "WPS (NFC): Failed to unwrap");
-       return buf;
-}
-
-
-static int write_nfc(void *priv, struct wpabuf *buf)
-{
-       struct wps_nfc_data *data = priv;
-       struct wpabuf *wifi;
-       int ret;
-
-       wifi = ndef_build_wifi(buf);
-       if (wifi == NULL) {
-               wpa_printf(MSG_ERROR, "WPS (NFC): Failed to wrap");
-               return -1;
-       }
-
-       ret = data->oob_nfc_dev->write_func(wpabuf_mhead(wifi),
-                                           wpabuf_len(wifi));
-       wpabuf_free(wifi);
-       return ret;
-}
-
-
-static void deinit_nfc(void *priv)
-{
-       struct wps_nfc_data *data = priv;
-
-       data->oob_nfc_dev->deinit_func();
-
-       os_free(data);
-}
-
-
-struct oob_device_data oob_nfc_device_data = {
-       .device_name    = NULL,
-       .device_path    = NULL,
-       .init_func      = init_nfc,
-       .read_func      = read_nfc,
-       .write_func     = write_nfc,
-       .deinit_func    = deinit_nfc,
-};
diff --git a/src/wps/wps_nfc_pn531.c b/src/wps/wps_nfc_pn531.c
deleted file mode 100644 (file)
index c2bf457..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * NFC PN531 routines for Wi-Fi Protected Setup
- * Copyright (c) 2009-2012, Masashi Honma <masashi.honma@gmail.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-#include "common.h"
-
-#include "wps/wps.h"
-#include "wps_i.h"
-
-#include "WpsNfcType.h"
-#include "WpsNfc.h"
-
-
-static int init_nfc_pn531(char *path)
-{
-       u32 ret;
-
-       ret = WpsNfcInit();
-       if (ret != WPS_NFCLIB_ERR_SUCCESS) {
-               wpa_printf(MSG_ERROR, "WPS (PN531): Failed to initialize "
-                          "NFC Library: 0x%08x", ret);
-               return -1;
-       }
-
-       ret = WpsNfcOpenDevice((int8 *) path);
-       if (ret != WPS_NFCLIB_ERR_SUCCESS) {
-               wpa_printf(MSG_ERROR, "WPS (PN531): Failed to open "
-                          "NFC Device(%s): 0x%08x", path, ret);
-               goto fail;
-       }
-
-       ret = WpsNfcTokenDiscovery();
-       if (ret != WPS_NFCLIB_ERR_SUCCESS) {
-               wpa_printf(MSG_ERROR, "WPS (PN531): Failed to discover "
-                          "token: 0x%08x", ret);
-               WpsNfcCloseDevice();
-               goto fail;
-       }
-
-       return 0;
-
-fail:
-       WpsNfcDeinit();
-       return -1;
-}
-
-
-static void * read_nfc_pn531(size_t *size)
-{
-       uint32 len;
-       u32 ret;
-       int8 *data;
-
-       ret = WpsNfcRawReadToken(&data, &len);
-       if (ret != WPS_NFCLIB_ERR_SUCCESS) {
-               wpa_printf(MSG_ERROR, "WPS (PN531): Failed to read: 0x%08x",
-                          ret);
-               return NULL;
-       }
-
-       *size = len;
-       return data;
-}
-
-
-static int write_nfc_pn531(void *data, size_t len)
-{
-       u32 ret;
-
-       ret = WpsNfcRawWriteToken(data, len);
-       if (ret != WPS_NFCLIB_ERR_SUCCESS) {
-               wpa_printf(MSG_ERROR, "WPS (PN531): Failed to write: 0x%08x",
-                          ret);
-               return -1;
-       }
-
-       return 0;
-}
-
-
-static void deinit_nfc_pn531(void)
-{
-       u32 ret;
-
-       ret = WpsNfcCloseDevice();
-       if (ret != WPS_NFCLIB_ERR_SUCCESS)
-               wpa_printf(MSG_ERROR, "WPS (PN531): Failed to close "
-                          "NFC Device: 0x%08x", ret);
-
-       ret = WpsNfcDeinit();
-       if (ret != WPS_NFCLIB_ERR_SUCCESS)
-               wpa_printf(MSG_ERROR, "WPS (PN531): Failed to deinitialize "
-                          "NFC Library: 0x%08x", ret);
-}
-
-
-struct oob_nfc_device_data oob_nfc_pn531_device_data = {
-       .init_func      = init_nfc_pn531,
-       .read_func      = read_nfc_pn531,
-       .write_func     = write_nfc_pn531,
-       .deinit_func    = deinit_nfc_pn531,
-};
index 53684d6..b24836e 100644 (file)
@@ -180,6 +180,9 @@ struct wps_registrar {
        u8 authorized_macs_union[WPS_MAX_AUTHORIZED_MACS][ETH_ALEN];
 
        u8 p2p_dev_addr[ETH_ALEN];
+
+       u8 pbc_ignore_uuid[WPS_UUID_LEN];
+       struct os_time pbc_ignore_start;
 };
 
 
@@ -187,6 +190,8 @@ static int wps_set_ie(struct wps_registrar *reg);
 static void wps_registrar_pbc_timeout(void *eloop_ctx, void *timeout_ctx);
 static void wps_registrar_set_selected_timeout(void *eloop_ctx,
                                               void *timeout_ctx);
+static void wps_registrar_remove_pin(struct wps_registrar *reg,
+                                    struct wps_uuid_pin *pin);
 
 
 static void wps_registrar_add_authorized_mac(struct wps_registrar *reg,
@@ -696,6 +701,21 @@ void wps_registrar_deinit(struct wps_registrar *reg)
 }
 
 
+static void wps_registrar_invalidate_unused(struct wps_registrar *reg)
+{
+       struct wps_uuid_pin *pin;
+
+       dl_list_for_each(pin, &reg->pins, struct wps_uuid_pin, list) {
+               if (pin->wildcard_uuid == 1 && !(pin->flags & PIN_LOCKED)) {
+                       wpa_printf(MSG_DEBUG, "WPS: Invalidate previously "
+                                  "configured wildcard PIN");
+                       wps_registrar_remove_pin(reg, pin);
+                       break;
+               }
+       }
+}
+
+
 /**
  * wps_registrar_add_pin - Configure a new PIN for Registrar
  * @reg: Registrar data from wps_registrar_init()
@@ -735,6 +755,9 @@ int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *addr,
                p->expiration.sec += timeout;
        }
 
+       if (p->wildcard_uuid)
+               wps_registrar_invalidate_unused(reg);
+
        dl_list_add(&reg->pins, &p->list);
 
        wpa_printf(MSG_DEBUG, "WPS: A new PIN configured (timeout=%d)",
@@ -1015,6 +1038,8 @@ void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e,
                wps_registrar_remove_pbc_session(registrar,
                                                 uuid_e, NULL);
                wps_registrar_pbc_completed(registrar);
+               os_get_time(&registrar->pbc_ignore_start);
+               os_memcpy(registrar->pbc_ignore_uuid, uuid_e, WPS_UUID_LEN);
        } else {
                wps_registrar_pin_completed(registrar);
        }
@@ -1061,6 +1086,7 @@ void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,
                                int p2p_wildcard)
 {
        struct wps_parse_attr attr;
+       int skip_add = 0;
 
        wpa_hexdump_buf(MSG_MSGDUMP,
                        "WPS: Probe Request with WPS data received",
@@ -1112,7 +1138,24 @@ void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,
        wpa_hexdump(MSG_DEBUG, "WPS: UUID-E from Probe Request", attr.uuid_e,
                    WPS_UUID_LEN);
 
-       wps_registrar_add_pbc_session(reg, addr, attr.uuid_e);
+#ifdef WPS_WORKAROUNDS
+       if (reg->pbc_ignore_start.sec &&
+           os_memcmp(attr.uuid_e, reg->pbc_ignore_uuid, WPS_UUID_LEN) == 0) {
+               struct os_time now, dur;
+               os_get_time(&now);
+               os_time_sub(&now, &reg->pbc_ignore_start, &dur);
+               if (dur.sec >= 0 && dur.sec < 5) {
+                       wpa_printf(MSG_DEBUG, "WPS: Ignore PBC activation "
+                                  "based on Probe Request from the Enrollee "
+                                  "that just completed PBC provisioning");
+                       skip_add = 1;
+               } else
+                       reg->pbc_ignore_start.sec = 0;
+       }
+#endif /* WPS_WORKAROUNDS */
+
+       if (!skip_add)
+               wps_registrar_add_pbc_session(reg, addr, attr.uuid_e);
        if (wps_registrar_pbc_overlap(reg, addr, attr.uuid_e)) {
                wpa_printf(MSG_DEBUG, "WPS: PBC session overlap detected");
                reg->force_pbc_overlap = 1;
@@ -2218,22 +2261,6 @@ static int wps_process_pubkey(struct wps_data *wps, const u8 *pk,
                return -1;
        }
 
-#ifdef CONFIG_WPS_OOB
-       if (wps->wps->oob_conf.pubkey_hash != NULL) {
-               const u8 *addr[1];
-               u8 hash[WPS_HASH_LEN];
-
-               addr[0] = pk;
-               sha256_vector(1, addr, &pk_len, hash);
-               if (os_memcmp(hash,
-                             wpabuf_head(wps->wps->oob_conf.pubkey_hash),
-                             WPS_OOB_PUBKEY_HASH_LEN) != 0) {
-                       wpa_printf(MSG_ERROR, "WPS: Public Key hash error");
-                       return -1;
-               }
-       }
-#endif /* CONFIG_WPS_OOB */
-
        wpabuf_free(wps->dh_pubkey_e);
        wps->dh_pubkey_e = wpabuf_alloc_copy(pk, pk_len);
        if (wps->dh_pubkey_e == NULL)
@@ -2529,16 +2556,6 @@ static enum wps_process_res wps_process_m1(struct wps_data *wps,
        }
 #endif /* CONFIG_WPS_NFC */
 
-#ifdef CONFIG_WPS_OOB
-       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);
-               wps->state = SEND_M2D;
-               return WPS_CONTINUE;
-       }
-#endif /* CONFIG_WPS_OOB */
-
        if (wps->dev_pw_id == DEV_PW_PUSHBUTTON) {
                if ((wps->wps->registrar->force_pbc_overlap ||
                     wps_registrar_pbc_overlap(wps->wps->registrar,
@@ -3168,6 +3185,9 @@ static enum wps_process_res wps_process_wsc_done(struct wps_data *wps,
                                                 wps->uuid_e,
                                                 wps->p2p_dev_addr);
                wps_registrar_pbc_completed(wps->wps->registrar);
+               os_get_time(&wps->wps->registrar->pbc_ignore_start);
+               os_memcpy(wps->wps->registrar->pbc_ignore_uuid, wps->uuid_e,
+                         WPS_UUID_LEN);
        } else {
                wps_registrar_pin_completed(wps->wps->registrar);
        }
diff --git a/src/wps/wps_ufd.c b/src/wps/wps_ufd.c
deleted file mode 100644 (file)
index f83bdf4..0000000
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * UFD routines for Wi-Fi Protected Setup
- * Copyright (c) 2009-2012, Masashi Honma <masashi.honma@gmail.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-#include "common.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <dirent.h>
-
-#include "wps/wps.h"
-#include "wps/wps_i.h"
-
-#ifdef CONFIG_NATIVE_WINDOWS
-#define UFD_DIR1 "%s\\SMRTNTKY"
-#define UFD_DIR2 UFD_DIR1 "\\WFAWSC"
-#define UFD_FILE UFD_DIR2 "\\%s"
-#else /* CONFIG_NATIVE_WINDOWS */
-#define UFD_DIR1 "%s/SMRTNTKY"
-#define UFD_DIR2 UFD_DIR1 "/WFAWSC"
-#define UFD_FILE UFD_DIR2 "/%s"
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-
-struct wps_ufd_data {
-       int ufd_fd;
-};
-
-
-static int dev_pwd_e_file_filter(const struct dirent *entry)
-{
-       unsigned int prefix;
-       char ext[5];
-
-       if (sscanf(entry->d_name, "%8x.%4s", &prefix, ext) != 2)
-               return 0;
-       if (prefix == 0)
-               return 0;
-       if (os_strcasecmp(ext, "WFA") != 0)
-               return 0;
-
-       return 1;
-}
-
-
-static int wps_get_dev_pwd_e_file_name(char *path, char *file_name)
-{
-       struct dirent **namelist;
-       int i, file_num;
-
-       file_num = scandir(path, &namelist, &dev_pwd_e_file_filter,
-                          alphasort);
-       if (file_num < 0) {
-               wpa_printf(MSG_ERROR, "WPS: OOB file not found: %d (%s)",
-                          errno, strerror(errno));
-               return -1;
-       }
-       if (file_num == 0) {
-               wpa_printf(MSG_ERROR, "WPS: OOB file not found");
-               os_free(namelist);
-               return -1;
-       }
-       os_strlcpy(file_name, namelist[0]->d_name, 13);
-       for (i = 0; i < file_num; i++)
-               os_free(namelist[i]);
-       os_free(namelist);
-       return 0;
-}
-
-
-static int get_file_name(struct wps_context *wps, int registrar,
-                        const char *path, char *file_name)
-{
-       switch (wps->oob_conf.oob_method) {
-       case OOB_METHOD_CRED:
-               os_snprintf(file_name, 13, "00000000.WSC");
-               break;
-       case OOB_METHOD_DEV_PWD_E:
-               if (registrar) {
-                       char temp[128];
-                       os_snprintf(temp, sizeof(temp), UFD_DIR2, path);
-                       if (wps_get_dev_pwd_e_file_name(temp, file_name) < 0)
-                               return -1;
-               } else {
-                       u8 *mac_addr = wps->dev.mac_addr;
-
-                       os_snprintf(file_name, 13, "%02X%02X%02X%02X.WFA",
-                                   mac_addr[2], mac_addr[3], mac_addr[4],
-                                   mac_addr[5]);
-               }
-               break;
-       case OOB_METHOD_DEV_PWD_R:
-               os_snprintf(file_name, 13, "00000000.WFA");
-               break;
-       default:
-               wpa_printf(MSG_ERROR, "WPS: Invalid USBA OOB method");
-               return -1;
-       }
-       return 0;
-}
-
-
-static int ufd_mkdir(const char *path)
-{
-       if (mkdir(path, S_IRWXU) < 0 && errno != EEXIST) {
-               wpa_printf(MSG_ERROR, "WPS (UFD): Failed to create directory "
-                          "'%s': %d (%s)", path, errno, strerror(errno));
-               return -1;
-       }
-       return 0;
-}
-
-
-static void * init_ufd(struct wps_context *wps,
-                      struct oob_device_data *oob_dev, int registrar)
-{
-       int write_f;
-       char temp[128];
-       char *path = oob_dev->device_path;
-       char filename[13];
-       struct wps_ufd_data *data;
-       int ufd_fd;
-
-       if (path == NULL)
-               return NULL;
-
-       write_f = wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E ?
-               !registrar : registrar;
-
-       if (get_file_name(wps, registrar, path, filename) < 0) {
-               wpa_printf(MSG_ERROR, "WPS (UFD): Failed to get file name");
-               return NULL;
-       }
-
-       if (write_f) {
-               os_snprintf(temp, sizeof(temp), UFD_DIR1, path);
-               if (ufd_mkdir(temp))
-                       return NULL;
-               os_snprintf(temp, sizeof(temp), UFD_DIR2, path);
-               if (ufd_mkdir(temp))
-                       return NULL;
-       }
-
-       os_snprintf(temp, sizeof(temp), UFD_FILE, path, filename);
-       if (write_f)
-               ufd_fd = open(temp, O_WRONLY | O_CREAT | O_TRUNC,
-                             S_IRUSR | S_IWUSR);
-       else
-               ufd_fd = open(temp, O_RDONLY);
-       if (ufd_fd < 0) {
-               wpa_printf(MSG_ERROR, "WPS (UFD): Failed to open %s: %s",
-                          temp, strerror(errno));
-               return NULL;
-       }
-
-       data = os_zalloc(sizeof(*data));
-       if (data == NULL) {
-               close(ufd_fd);
-               return NULL;
-       }
-       data->ufd_fd = ufd_fd;
-       return data;
-}
-
-
-static struct wpabuf * read_ufd(void *priv)
-{
-       struct wps_ufd_data *data = priv;
-       struct wpabuf *buf;
-       struct stat s;
-       size_t file_size;
-
-       if (fstat(data->ufd_fd, &s) < 0) {
-               wpa_printf(MSG_ERROR, "WPS (UFD): Failed to get file size");
-               return NULL;
-       }
-
-       file_size = s.st_size;
-       buf = wpabuf_alloc(file_size);
-       if (buf == NULL) {
-               wpa_printf(MSG_ERROR, "WPS (UFD): Failed to alloc read "
-                          "buffer");
-               return NULL;
-       }
-
-       if (read(data->ufd_fd, wpabuf_mhead(buf), file_size) !=
-           (int) file_size) {
-               wpabuf_free(buf);
-               wpa_printf(MSG_ERROR, "WPS (UFD): Failed to read");
-               return NULL;
-       }
-       wpabuf_put(buf, file_size);
-       return buf;
-}
-
-
-static int write_ufd(void *priv, struct wpabuf *buf)
-{
-       struct wps_ufd_data *data = priv;
-
-       if (write(data->ufd_fd, wpabuf_mhead(buf), wpabuf_len(buf)) !=
-           (int) wpabuf_len(buf)) {
-               wpa_printf(MSG_ERROR, "WPS (UFD): Failed to write");
-               return -1;
-       }
-       return 0;
-}
-
-
-static void deinit_ufd(void *priv)
-{
-       struct wps_ufd_data *data = priv;
-       close(data->ufd_fd);
-       os_free(data);
-}
-
-
-struct oob_device_data oob_ufd_device_data = {
-       .device_name    = NULL,
-       .device_path    = NULL,
-       .init_func      = init_ufd,
-       .read_func      = read_ufd,
-       .write_func     = write_ufd,
-       .deinit_func    = deinit_ufd,
-};
index 33e4579..da86a49 100644 (file)
@@ -31,6 +31,7 @@ endif
 
 ifeq ($(BOARD_WLAN_DEVICE), bcmdhd)
 L_CFLAGS += -DANDROID_P2P
+L_CFLAGS += -DP2P_CONCURRENT_SEARCH_DELAY=0
 endif
 
 ifeq ($(BOARD_WLAN_DEVICE), qcwcn)
@@ -193,6 +194,10 @@ NEED_SHA256=y
 NEED_AES_OMAC1=y
 endif
 
+ifdef CONFIG_SAE
+L_CFLAGS += -DCONFIG_SAE
+endif
+
 ifdef CONFIG_IEEE80211V
 L_CFLAGS += -DCONFIG_IEEE80211V
 OBJS += wnm_sta.c
@@ -333,6 +338,17 @@ TLS_FUNCS=y
 CONFIG_IEEE8021X_EAPOL=y
 endif
 
+ifdef CONFIG_EAP_UNAUTH_TLS
+# EAP-UNAUTH-TLS
+L_CFLAGS += -DEAP_UNAUTH_TLS
+ifndef CONFIG_EAP_UNAUTH_TLS
+OBJS += src/eap_peer/eap_tls.c
+OBJS_h += src/eap_server/eap_server_tls.c
+TLS_FUNCS=y
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
 ifdef CONFIG_EAP_PEAP
 # EAP-PEAP
 ifeq ($(CONFIG_EAP_PEAP), dyn)
@@ -599,25 +615,10 @@ NEED_80211_COMMON=y
 NEED_AES_CBC=y
 NEED_MODEXP=y
 
-ifdef CONFIG_WPS_UFD
-L_CFLAGS += -DCONFIG_WPS_UFD
-OBJS += src/wps/wps_ufd.c
-NEED_WPS_OOB=y
-endif
-
 ifdef CONFIG_WPS_NFC
 L_CFLAGS += -DCONFIG_WPS_NFC
 OBJS += src/wps/ndef.c
-OBJS += src/wps/wps_nfc.c
 NEED_WPS_OOB=y
-ifdef CONFIG_WPS_NFC_PN531
-PN531_PATH ?= /usr/local/src/nfc
-L_CFLAGS += -DCONFIG_WPS_NFC_PN531
-L_CFLAGS += -I${PN531_PATH}/inc
-OBJS += src/wps/wps_nfc_pn531.c
-LIBS += ${PN531_PATH}/lib/wpsnfc.dll
-LIBS += ${PN531_PATH}/lib/libnfc_mapping_pn53x.dll
-endif
 endif
 
 ifdef NEED_WPS_OOB
@@ -743,6 +744,7 @@ OBJS += src/ap/ieee802_11_shared.c
 OBJS += src/ap/drv_callbacks.c
 OBJS += src/ap/ap_drv_ops.c
 OBJS += src/ap/beacon.c
+OBJS += src/ap/eap_user_db.c
 ifdef CONFIG_IEEE80211N
 OBJS += src/ap/ieee802_11_ht.c
 endif
@@ -910,6 +912,10 @@ OBJS += src/crypto/fips_prf_openssl.c
 endif
 LIBS += -lcrypto
 LIBS_p += -lcrypto
+ifdef CONFIG_TLS_ADD_DL
+LIBS += -ldl
+LIBS_p += -ldl
+endif
 endif
 
 ifeq ($(CONFIG_TLS), gnutls)
index 650b8a0..6a5ab17 100644 (file)
@@ -1,5 +1,229 @@
 ChangeLog for wpa_supplicant
 
+????-??-?? - v2.0
+       * removed Qt3-based wpa_gui (obsoleted by wpa_qui-qt4)
+       * removed unmaintained driver wrappers broadcom, iphone, osx, ralink,
+         hostap, madwifi (hostap and madwifi remain available for hostapd;
+         their wpa_supplicant functionality is obsoleted by wext)
+       * improved debug logging (human readable event names, interface name
+         included in more entries)
+       * changed AP mode behavior to enable WPS only for open and
+         WPA/WPA2-Personal configuration
+       * improved P2P concurrency operations
+         - better coordination of concurrent scan and P2P search operations
+         - avoid concurrent remain-on-channel operation requests by canceling
+           previous operations prior to starting a new one
+         - reject operations that would require multi-channel concurrency if
+           the driver does not support it
+         - add parameter to select whether STA or P2P connection is preferred
+           if the driver cannot support both at the same time
+         - allow driver to indicate channel changes
+         - added optional delay=<search delay in milliseconds> parameter for
+           p2p_find to avoid taking all radio resources
+         - use 500 ms p2p_find search delay by default during concurrent
+           operations
+         - allow all channels in GO Negotiation if the driver supports
+           multi-channel concurrency
+       * added number of small changes to make it easier for static analyzers
+         to understand the implementation
+       * fixed number of small bugs (see git logs for more details)
+       * nl80211: number of updates to use new cfg80211/nl80211 functionality
+         - replace monitor interface with nl80211 commands for AP mode
+         - additional information for driver-based AP SME
+         - STA entry authorization in RSN IBSS
+       * EAP-pwd:
+         - fixed KDF for group 21 and zero-padding
+         - added support for fragmentation
+         - increased maximum number of hunting-and-pecking iterations
+       * avoid excessive Probe Response retries for broadcast Probe Request
+         frames (only with drivers using wpa_supplicant AP mode SME/MLME)
+       * added "GET country" ctrl_iface command
+       * do not save an invalid network block in wpa_supplicant.conf to avoid
+         problems reading the file on next start
+       * send STA connected/disconnected ctrl_iface events to both the P2P
+         group and parent interfaces
+       * added preliminary support for using TLS v1.2 (CONFIG_TLSV12=y)
+       * added "SET pno <1/0>" ctrl_iface command to start/stop preferred
+         network offload with sched_scan driver command
+       * merged in number of changes from Android repository for P2P, nl80211,
+         and build parameters
+       * changed P2P GO mode configuration to use driver capabilities to
+         automatically enable HT operations when supported
+       * added "wpa_cli status wps" command to fetch WPA2-Personal passhrase
+         for WPS use cases in AP mode
+       * EAP-AKA: keep pseudonym identity across EAP exchanges to match EAP-SIM
+         behavior
+       * improved reassociation behavior in cases where association is rejected
+         or when an AP disconnects us to handle common load balancing
+         mechanisms
+         - try to avoid extra scans when the needed information is available
+       * added optional "join" argument for p2p_prov_disc ctrl_iface command
+       * added group ifname to P2P-PROV-DISC-* events
+       * added P2P Device Address to AP-STA-DISCONNECTED event and use
+         p2p_dev_addr parameter name with AP-STA-CONNECTED
+       * added workarounds for WPS PBC overlap detection for some P2P use cases
+         where deployed stations work incorrectly
+       * optimize WPS connection speed by disconnecting prior to WPS scan and
+         by using single channel scans when AP channel is known
+       * PCSC and SIM/USIM improvements:
+         - accept 0x67 (Wrong length) as a response to READ RECORD to fix
+           issues with some USIM cards
+         - try to read MNC length from SIM/USIM
+         - build realm according to 3GPP TS 23.003 with identity from the SIM
+         - allow T1 protocol to be enabled
+       * added more WPS and P2P information available through D-Bus
+       * improve P2P negotiation robustness
+         - extra waits to get ACK frames through
+         - longer timeouts for cases where deployed devices have been
+           identified have issues meeting the specification requirements
+         - more retries for some P2P frames
+         - handle race conditions in GO Negotiation start by both devices
+         - ignore unexpected GO Negotiation Response frame
+       * added support for libnl 3.2 and newer
+       * added P2P persistent group info to P2P_PEER data
+       * maintain a list of P2P Clients for persistent group on GO
+       * AP: increased initial group key handshake retransmit timeout to 500 ms
+       * added optional dev_id parameter for p2p_find
+       * added P2P-FIND-STOPPED ctrl_iface event
+       * fixed issues in WPA/RSN element validation when roaming with ap_scan=1
+         and driver-based BSS selection
+       * do not expire P2P peer entries while connected with the peer in a
+         group
+       * fixed WSC element inclusion in cases where P2P is disabled
+       * AP: added a WPS workaround for mixed mode AP Settings with Windows 7
+       * EAP-SIM: fixed AT_COUNTER_TOO_SMALL use
+       * EAP-SIM/AKA: append realm to pseudonym identity
+       * EAP-SIM/AKA: store pseudonym identity in network configuration to
+         allow it to persist over multiple EAP sessions and wpa_supplicant
+         restarts
+       * EAP-AKA': updated to RFC 5448 (username prefixes changed); note: this
+         breaks interoperability with older versions
+       * added support for WFA Hotspot 2.0
+         - GAS/ANQP to fetch network information
+         - credential configuration and automatic network selections based on
+           credential match with ANQP information
+       * limited PMKSA cache entries to be used only with the network context
+         that was used to create them
+       * adjusted bgscan_simple fast-scan backoff to avoid too frequent
+         background scans
+       * removed ctrl_iface event on P2P PD Response in join-group case
+       * added option to fetch BSS table entry based on P2P Device Address
+         ("BSS p2p_dev_addr=<P2P Device Address>")
+       * added BSS entry age to ctrl_iface BSS command output
+       * added optional MASK=0xH option for ctrl_iface BSS command to select
+         which fields are included in the response
+       * added optional RANGE=ALL|N1-N2 option for ctrl_iface BSS command to
+         fetch information about several BSSes in one call
+       * simplified licensing terms by selecting the BSD license as the only
+         alternative
+       * added "P2P_SET disallow_freq <freq list>" ctrl_iface command to
+         disable channels from P2P use
+       * added p2p_pref_chan configuration parameter to allow preferred P2P
+         channels to be specified
+       * added support for advertising immediate availability of a WPS
+         credential for P2P use cases
+       * optimized scan operations for P2P use cases (use single channel scan
+         for a specific SSID when possible)
+       * EAP-TTLS: fixed peer challenge generation for MSCHAPv2
+       * SME: do not use reassociation after explicit disconnection request
+         (local or a notification from an AP)
+       * added support for sending debug info to Linux tracing (-T on command
+         line)
+       * added support for using Deauthentication reason code 3 as an
+         indication of P2P group termination
+       * added wps_vendor_ext_m1 configuration parameter to allow vendor
+         specific attributes to be added to WPS M1
+       * started using separate TLS library context for tunneled TLS
+         (EAP-PEAP/TLS, EAP-TTLS/TLS, EAP-FAST/TLS) to support different CA
+         certificate configuration between Phase 1 and Phase 2
+       * added optional "auto" parameter for p2p_connect to request automatic
+         GO Negotiation vs. join-a-group selection
+       * added disabled_scan_offload parameter to disable automatic scan
+         offloading (sched_scan)
+       * added optional persistent=<network id> parameter for p2p_connect to
+         allow forcing of a specific SSID/passphrase for GO Negotiation
+       * added support for OBSS scan requests and 20/40 BSS coexistence reports
+       * reject PD Request for unknown group
+       * removed scripts and notes related to Windows binary releases (which
+         have not been used starting from 1.x)
+       * added initial support for WNM operations
+         - Keep-alive based on BSS max idle period
+         - WNM-Sleep Mode
+       * added autoscan module to control scanning behavior while not connected
+         - autoscan_periodic and autoscan_exponential modules
+       * added new WPS NFC ctrl_iface mechanism
+         - added initial support NFC connection handover
+         - removed obsoleted WPS_OOB command (including support for deprecated
+           UFD config_method)
+       * added optional framework for external password storage ("ext:<name>")
+       * wpa_cli: added optional support for controlling wpa_supplicant
+         remotely over UDP (CONFIG_CTRL_IFACE=udp-remote) for testing purposes
+       * wpa_cli: extended tab completion to more commands
+       * changed SSID output to use printf-escaped strings instead of masking
+         of non-ASCII characters
+         - SSID can now be configured in the same format: ssid=P"abc\x00test"
+       * removed default ACM=1 from AC_VO and AC_VI
+       * added optional "ht40" argument for P2P ctrl_iface commands to allow
+         40 MHz channels to be requested on the 5 GHz band
+       * added optional parameters for p2p_invite command to specify channel
+         when reinvoking a persistent group as the GO
+       * improved FIPS mode builds with OpenSSL
+         - "make fips" with CONFIG_FIPS=y to build wpa_supplicant with the
+           OpenSSL FIPS object module
+         - replace low level OpenSSL AES API calls to use EVP
+         - use OpenSSL keying material exporter when possible
+         - do not export TLS keys in FIPS mode
+         - remove MD5 from CONFIG_FIPS=y builds
+         - use OpenSSL function for PKBDF2 passphrase-to-PSK
+         - use OpenSSL HMAC implementation
+         - mix RAND_bytes() output into random_get_bytes() to force OpenSSL
+           DRBG to be used in FIPS mode
+         - use OpenSSL CMAC implementation
+       * added mechanism to disable TLS Session Ticket extension
+         - a workaround for servers that do not support TLS extensions that
+           was enabled by default in recent OpenSSL versions
+         - tls_disable_session_ticket=1
+         - automatically disable TLS Session Ticket extension by default when
+           using EAP-TLS/PEAP/TTLS (i.e., only use it with EAP-FAST)
+       * changed VENDOR-TEST EAP method to use proper private enterprise number
+         (this will not interoperate with older versions)
+       * disable network block temporarily on authentication failures
+       * improved WPS AP selection during WPS PIN iteration
+       * added support for configuring GCMP cipher for IEEE 802.11ad
+       * added support for Wi-Fi Display extensions
+         - WFD_SUBELEMENT_SET ctrl_iface command to configure WFD subelements
+         - SET wifi_display <0/1> to disable/enable WFD support
+         - WFD service discovery
+         - an external program is needed to manage the audio/video streaming
+           and codecs
+       * optimized scan result use for network selection
+         - use the internal BSS table instead of raw scan results
+         - allow unnecessary scans to be skipped if fresh information is
+           available (e.g., after GAS/ANQP round for Interworking)
+       * added support for 256-bit AES with internal TLS implementation
+       * allow peer to propose channel in P2P invitation process for a
+         persistent group
+       * added disallow_aps parameter to allow BSSIDs/SSIDs to be disallowed
+         from network selection
+       * re-enable the networks disabled during WPS operations
+       * allow P2P functionality to be disabled per interface (p2p_disabled=1)
+       * added secondary device types into P2P_PEER output
+       * added an option to disable use of a separate P2P group interface
+         (p2p_no_group_iface=1)
+       * fixed P2P Bonjour SD to match entries with both compressed and not
+         compressed domain name format and support multiple Bonjour PTR matches
+         for the same key
+       * use deauthentication instead of disassociation for all disconnection
+         operations; this removes the now unused disassociate() wpa_driver_ops
+         callback
+       * optimized PSK generation on P2P GO by caching results to avoid
+         multiple PBKDF2 operations
+       * added okc=1 global configuration parameter to allow OKC to be enabled
+         by default for all network blocks
+       * added a workaround for WPS PBC session overlap detection to avoid
+         interop issues with deployed station implementations that do not
+         remove active PBC indication from Probe Request frames properly
+
 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.
index 227fb4f..c6c76ec 100644 (file)
@@ -172,6 +172,10 @@ NEED_SHA256=y
 NEED_AES_OMAC1=y
 endif
 
+ifdef CONFIG_SAE
+CFLAGS += -DCONFIG_SAE
+endif
+
 ifdef CONFIG_IEEE80211V
 CFLAGS += -DCONFIG_IEEE80211V
 OBJS += wnm_sta.o
@@ -588,25 +592,10 @@ NEED_80211_COMMON=y
 NEED_AES_CBC=y
 NEED_MODEXP=y
 
-ifdef CONFIG_WPS_UFD
-CFLAGS += -DCONFIG_WPS_UFD
-OBJS += ../src/wps/wps_ufd.o
-NEED_WPS_OOB=y
-endif
-
 ifdef CONFIG_WPS_NFC
 CFLAGS += -DCONFIG_WPS_NFC
 OBJS += ../src/wps/ndef.o
-OBJS += ../src/wps/wps_nfc.o
 NEED_WPS_OOB=y
-ifdef CONFIG_WPS_NFC_PN531
-PN531_PATH ?= /usr/local/src/nfc
-CFLAGS += -DCONFIG_WPS_NFC_PN531
-CFLAGS += -I${PN531_PATH}/inc
-OBJS += ../src/wps/wps_nfc_pn531.o
-LIBS += ${PN531_PATH}/lib/wpsnfc.dll
-LIBS += ${PN531_PATH}/lib/libnfc_mapping_pn53x.dll
-endif
 endif
 
 ifdef NEED_WPS_OOB
@@ -732,6 +721,7 @@ OBJS += ../src/ap/ieee802_11_shared.o
 OBJS += ../src/ap/drv_callbacks.o
 OBJS += ../src/ap/ap_drv_ops.o
 OBJS += ../src/ap/beacon.o
+OBJS += ../src/ap/eap_user_db.o
 ifdef CONFIG_IEEE80211N
 OBJS += ../src/ap/ieee802_11_ht.o
 endif
index 692d5f5..1ea9843 100644 (file)
@@ -130,6 +130,12 @@ wpa_cli wps_pin any 12345670
 This starts the WPS negotiation in the same way as above with the
 generated PIN.
 
+When the wps_pin command is issued for an AP (including P2P GO) mode
+interface, an optional timeout parameter can be used to specify
+expiration timeout for the PIN in seconds. For example:
+
+wpa_cli wps_pin any 12345670 300
+
 
 If a random PIN is needed for a user interface, "wpa_cli wps_pin get"
 can be used to generate a new PIN without starting WPS negotiation.
@@ -345,3 +351,27 @@ an AP) using a special value "nfc-pw" in place of the PIN parameter. If
 the ER functionality has been started (wps_er_start), the NFC password
 token is used to enable enrollment of a new station (that was the source
 of the NFC password token).
+
+"nfc_get_handover_req <NDEF> <WPS>" command can be used to build the
+contents of a Handover Request Message for connection handover. The
+first argument selects the format of the output data and the second
+argument selects which type of connection handover is requested (WPS =
+Wi-Fi handover as specified in WSC 2.0).
+
+"nfc_get_handover_sel <NDEF> <WPS>" command can be used to build the
+contents of a Handover Select Message for connection handover when this
+does not depend on the contents of the Handover Request Message. The
+first argument selects the format of the output data and the second
+argument selects which type of connection handover is requested (WPS =
+Wi-Fi handover as specified in WSC 2.0).
+
+"nfc_rx_handover_req <hexdump of payload>" is used to indicate receipt
+of NFC connection handover request. The payload may include multiple
+carriers the the applicable ones are matched based on the media
+type. The reply data is contents for the Handover Select Message
+(hexdump).
+
+"nfc_rx_handover_sel <hexdump of payload>" is used to indicate receipt
+of NFC connection handover select. The payload may include multiple
+carriers the the applicable ones are matched based on the media
+type.
index 3798f5a..e261ef9 100644 (file)
@@ -174,15 +174,15 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
                bss->wpa = ssid->proto;
        bss->wpa_key_mgmt = ssid->key_mgmt;
        bss->wpa_pairwise = ssid->pairwise_cipher;
-       if (ssid->passphrase) {
-               bss->ssid.wpa_passphrase = os_strdup(ssid->passphrase);
-       } else if (ssid->psk_set) {
+       if (ssid->psk_set) {
                os_free(bss->ssid.wpa_psk);
                bss->ssid.wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
                if (bss->ssid.wpa_psk == NULL)
                        return -1;
                os_memcpy(bss->ssid.wpa_psk->psk, ssid->psk, PMK_LEN);
                bss->ssid.wpa_psk->group = 1;
+       } else if (ssid->passphrase) {
+               bss->ssid.wpa_passphrase = os_strdup(ssid->passphrase);
        } else if (ssid->wep_key_len[0] || ssid->wep_key_len[1] ||
                   ssid->wep_key_len[2] || ssid->wep_key_len[3]) {
                struct hostapd_wep_keys *wep = &bss->ssid.wep;
@@ -724,7 +724,8 @@ int wpa_supplicant_ap_wps_cancel(struct wpa_supplicant *wpa_s)
 
 
 int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
-                             const char *pin, char *buf, size_t buflen)
+                             const char *pin, char *buf, size_t buflen,
+                             int timeout)
 {
        int ret, ret_len = 0;
 
@@ -739,7 +740,7 @@ int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
                ret_len = os_snprintf(buf, buflen, "%s", pin);
 
        ret = hostapd_wps_add_pin(wpa_s->ap_iface->bss[0], bssid, "any", pin,
-                                 0);
+                                 timeout);
        if (ret)
                return -1;
        return ret_len;
index bc953d9..536064f 100644 (file)
@@ -18,7 +18,8 @@ void wpa_supplicant_ap_rx_eapol(struct wpa_supplicant *wpa_s,
 int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
                              const u8 *p2p_dev_addr);
 int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
-                             const char *pin, char *buf, size_t buflen);
+                             const char *pin, char *buf, size_t buflen,
+                             int timeout);
 int wpa_supplicant_ap_wps_cancel(struct wpa_supplicant *wpa_s);
 void wpas_wps_ap_pin_disable(struct wpa_supplicant *wpa_s);
 const char * wpas_wps_ap_pin_random(struct wpa_supplicant *wpa_s, int timeout);
index d0c040a..a2cf7a5 100644 (file)
@@ -36,7 +36,7 @@ static const struct autoscan_ops * autoscan_modules[] = {
 
 static void request_scan(struct wpa_supplicant *wpa_s)
 {
-       wpa_s->scan_req = 2;
+       wpa_s->scan_req = MANUAL_SCAN_REQ;
 
        if (wpa_supplicant_req_sched_scan(wpa_s))
                wpa_supplicant_req_scan(wpa_s, wpa_s->scan_interval, 0);
index adf82d8..07d31e4 100644 (file)
@@ -242,8 +242,11 @@ static int * bgscan_learn_get_probe_freq(struct bgscan_learn_data *data,
 
        idx = data->probe_idx + 1;
        while (idx != data->probe_idx) {
-               if (data->supp_freqs[idx] == 0)
+               if (data->supp_freqs[idx] == 0) {
+                       if (data->probe_idx == 0)
+                               break;
                        idx = 0;
+               }
                if (!in_array(freqs, data->supp_freqs[idx])) {
                        wpa_printf(MSG_DEBUG, "bgscan learn: Probe new freq "
                                   "%u", data->supp_freqs[idx]);
index 2e01e7f..e53dc38 100644 (file)
@@ -123,14 +123,19 @@ int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid)
 void wpa_blacklist_clear(struct wpa_supplicant *wpa_s)
 {
        struct wpa_blacklist *e, *prev;
+       int max_count = 0;
 
        e = wpa_s->blacklist;
        wpa_s->blacklist = NULL;
        while (e) {
+               if (e->count > max_count)
+                       max_count = e->count;
                prev = e;
                e = e->next;
                wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR " from "
                           "blacklist (clear)", MAC2STR(prev->bssid));
                os_free(prev);
        }
+
+       wpa_s->extra_blacklist_count += max_count;
 }
index 6223beb..0babbd5 100644 (file)
@@ -62,6 +62,60 @@ struct wpa_bss_anqp * wpa_bss_anqp_alloc(void)
 }
 
 
+static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp)
+{
+       struct wpa_bss_anqp *n;
+
+       n = os_zalloc(sizeof(*n));
+       if (n == NULL)
+               return NULL;
+
+#define ANQP_DUP(f) if (anqp->f) n->f = wpabuf_dup(anqp->f)
+#ifdef CONFIG_INTERWORKING
+       ANQP_DUP(venue_name);
+       ANQP_DUP(network_auth_type);
+       ANQP_DUP(roaming_consortium);
+       ANQP_DUP(ip_addr_type_availability);
+       ANQP_DUP(nai_realm);
+       ANQP_DUP(anqp_3gpp);
+       ANQP_DUP(domain_name);
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+       ANQP_DUP(hs20_operator_friendly_name);
+       ANQP_DUP(hs20_wan_metrics);
+       ANQP_DUP(hs20_connection_capability);
+       ANQP_DUP(hs20_operating_class);
+#endif /* CONFIG_HS20 */
+#undef ANQP_DUP
+
+       return n;
+}
+
+
+int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss)
+{
+       struct wpa_bss_anqp *anqp;
+
+       if (bss->anqp && bss->anqp->users > 1) {
+               /* allocated, but shared - clone an unshared copy */
+               anqp = wpa_bss_anqp_clone(bss->anqp);
+               if (anqp == NULL)
+                       return -1;
+               anqp->users = 1;
+               bss->anqp->users--;
+               bss->anqp = anqp;
+               return 0;
+       }
+
+       if (bss->anqp)
+               return 0; /* already allocated and not shared */
+
+       /* not allocated - allocate a new storage area */
+       bss->anqp = wpa_bss_anqp_alloc();
+       return bss->anqp ? 0 : -1;
+}
+
+
 static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
 {
        if (anqp == NULL)
index 4a386b6..eb01f2d 100644 (file)
@@ -113,5 +113,6 @@ struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
 int wpa_bss_get_max_rate(const struct wpa_bss *bss);
 int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates);
 struct wpa_bss_anqp * wpa_bss_anqp_alloc(void);
+int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss);
 
 #endif /* BSS_H */
index be21029..e157845 100644 (file)
@@ -504,6 +504,12 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data,
                else if (os_strcmp(start, "WPS") == 0)
                        val |= WPA_KEY_MGMT_WPS;
 #endif /* CONFIG_WPS */
+#ifdef CONFIG_SAE
+               else if (os_strcmp(start, "SAE") == 0)
+                       val |= WPA_KEY_MGMT_SAE;
+               else if (os_strcmp(start, "FT-SAE") == 0)
+                       val |= WPA_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
                else {
                        wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
                                   line, start);
@@ -2035,6 +2041,10 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
        ssid->ampdu_factor = DEFAULT_AMPDU_FACTOR;
        ssid->ampdu_density = DEFAULT_AMPDU_DENSITY;
 #endif /* CONFIG_HT_OVERRIDES */
+       ssid->proactive_key_caching = -1;
+#ifdef CONFIG_IEEE80211W
+       ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT;
+#endif /* CONFIG_IEEE80211W */
 }
 
 
@@ -3000,6 +3010,9 @@ static const struct global_parse_data global_fields[] = {
        { INT_RANGE(p2p_intra_bss, 0, 1), CFG_CHANGED_P2P_INTRA_BSS },
        { INT(p2p_group_idle), 0 },
        { FUNC(p2p_pref_chan), CFG_CHANGED_P2P_PREF_CHAN },
+       { INT(p2p_go_ht40), 0 },
+       { INT(p2p_disabled), 0 },
+       { INT(p2p_no_group_iface), 0 },
 #endif /* CONFIG_P2P */
        { FUNC(country), CFG_CHANGED_COUNTRY },
        { INT(bss_max_count), 0 },
@@ -3024,6 +3037,8 @@ static const struct global_parse_data global_fields[] = {
        { STR(ext_password_backend), CFG_CHANGED_EXT_PW_BACKEND },
        { INT(p2p_go_max_inactivity), 0 },
        { INT_RANGE(auto_interworking, 0, 1), 0 },
+       { INT(okc), 0 },
+       { INT(pmf), 0 },
 };
 
 #undef FUNC
index b889ab8..c0aea0b 100644 (file)
@@ -747,6 +747,50 @@ struct wpa_config {
         *     matching network block
         */
        int auto_interworking;
+
+       /**
+        * p2p_go_ht40 - Default mode for HT40 enable when operating as GO.
+        *
+        * This will take effect for p2p_group_add, p2p_connect, and p2p_invite.
+        * Note that regulatory constraints and driver capabilities are
+        * consulted anyway, so setting it to 1 can't do real harm.
+        * By default: 0 (disabled)
+        */
+       int p2p_go_ht40;
+
+       /**
+        * p2p_disabled - Whether P2P operations are disabled for this interface
+        */
+       int p2p_disabled;
+
+       /**
+        * p2p_no_group_iface - Whether group interfaces can be used
+        *
+        * By default, wpa_supplicant will create a separate interface for P2P
+        * group operations if the driver supports this. This functionality can
+        * be disabled by setting this parameter to 1. In that case, the same
+        * interface that was used for the P2P management operations is used
+        * also for the group operation.
+        */
+       int p2p_no_group_iface;
+
+       /**
+        * okc - Whether to enable opportunistic key caching by default
+        *
+        * By default, OKC is disabled unless enabled by the per-network
+        * proactive_key_caching=1 parameter. okc=1 can be used to change this
+        * default behavior.
+        */
+       int okc;
+
+       /**
+        * pmf - Whether to enable/require PMF by default
+        *
+        * By default, PMF is disabled unless enabled by the per-network
+        * ieee80211w=1 or ieee80211w=2 parameter. pmf=1/2 can be used to change
+        * this default behavior.
+        */
+       enum mfp_options pmf;
 };
 
 
index 531957a..d66eac5 100644 (file)
@@ -676,11 +676,12 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
        INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE);
 #endif /* IEEE8021X_EAPOL */
        INT(mode);
-       INT(proactive_key_caching);
+       write_int(f, "proactive_key_caching", ssid->proactive_key_caching, -1);
        INT(disabled);
        INT(peerkey);
 #ifdef CONFIG_IEEE80211W
-       INT(ieee80211w);
+       write_int(f, "ieee80211w", ssid->ieee80211w,
+                 MGMT_FRAME_PROTECTION_DEFAULT);
 #endif /* CONFIG_IEEE80211W */
        STR(id_str);
 #ifdef CONFIG_P2P
@@ -868,6 +869,13 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
                }
                fprintf(f, "\n");
        }
+       if (config->p2p_go_ht40)
+               fprintf(f, "p2p_go_ht40=%u\n", config->p2p_go_ht40);
+       if (config->p2p_disabled)
+               fprintf(f, "p2p_disabled=%u\n", config->p2p_disabled);
+       if (config->p2p_no_group_iface)
+               fprintf(f, "p2p_no_group_iface=%u\n",
+                       config->p2p_no_group_iface);
 #endif /* CONFIG_P2P */
        if (config->country[0] && config->country[1]) {
                fprintf(f, "country=%c%c\n",
@@ -919,6 +927,10 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
        if (config->auto_interworking)
                fprintf(f, "auto_interworking=%d\n",
                        config->auto_interworking);
+       if (config->okc)
+               fprintf(f, "okc=%d\n", config->okc);
+       if (config->pmf)
+               fprintf(f, "pmf=%d\n", config->pmf);
 }
 
 #endif /* CONFIG_NO_CONFIG_WRITE */
index ff97379..c1184f8 100644 (file)
@@ -228,13 +228,18 @@ struct wpa_ssid {
         *
         * This field can be used to enable proactive key caching which is also
         * known as opportunistic PMKSA caching for WPA2. This is disabled (0)
-        * by default. Enable by setting this to 1.
+        * by default unless default value is changed with the global okc=1
+        * parameter. Enable by setting this to 1.
         *
         * Proactive key caching is used to make supplicant assume that the APs
         * are using the same PMK and generate PMKSA cache entries without
         * doing RSN pre-authentication. This requires support from the AP side
         * and is normally used with wireless switches that co-locate the
         * authenticator.
+        *
+        * Internally, special value -1 is used to indicate that the parameter
+        * was not specified in the configuration (i.e., default behavior is
+        * followed).
         */
        int proactive_key_caching;
 
@@ -323,6 +328,14 @@ struct wpa_ssid {
        int disabled;
 
        /**
+        * disabled_for_connect - Whether this network was temporarily disabled
+        *
+        * This flag is used to reenable all the temporarily disabled networks
+        * after either the success or failure of a WPS connection.
+        */
+       int disabled_for_connect;
+
+       /**
         * peerkey -  Whether PeerKey handshake for direct links is allowed
         *
         * This is only used when both RSN/WPA2 and IEEE 802.11e (QoS) are
@@ -348,6 +361,12 @@ struct wpa_ssid {
         *
         * This value is used to configure policy for management frame
         * protection (IEEE 802.11w). 0 = disabled, 1 = optional, 2 = required.
+        * This is disabled by default unless the default value has been changed
+        * with the global pmf=1/2 parameter.
+        *
+        * Internally, special value 3 is used to indicate that the parameter
+        * was not specified in the configuration (i.e., default behavior is
+        * followed).
         */
        enum mfp_options ieee80211w;
 #endif /* CONFIG_IEEE80211W */
@@ -536,6 +555,15 @@ struct wpa_ssid {
         * disabled_until - Network block disabled until this time if non-zero
         */
        struct os_time disabled_until;
+
+       /**
+        * parent_cred - Pointer to parent wpa_cred entry
+        *
+        * This pointer can be used to delete temporary networks when a wpa_cred
+        * that was used to create them is removed. This pointer should not be
+        * dereferences since it may not be updated in all cases.
+        */
+       void *parent_cred;
 };
 
 #endif /* CONFIG_SSID_H */
index 6d9876c..2750b63 100644 (file)
@@ -202,6 +202,7 @@ static int wpa_config_read_global_os_version(struct wpa_config *config,
 static int wpa_config_read_global(struct wpa_config *config, HKEY hk)
 {
        int errors = 0;
+       int val;
 
        wpa_config_read_reg_dword(hk, TEXT("ap_scan"), &config->ap_scan);
        wpa_config_read_reg_dword(hk, TEXT("fast_reauth"),
@@ -271,6 +272,10 @@ static int wpa_config_read_global(struct wpa_config *config, HKEY hk)
        wpa_config_read_reg_dword(hk, TEXT("disassoc_low_ack"),
                                  (int *) &config->disassoc_low_ack);
 
+       wpa_config_read_reg_dword(hk, TEXT("okc"), &config->okc);
+       wpa_config_read_reg_dword(hk, TEXT("pmf"), &val);
+       config->pmf = val;
+
        return errors ? -1 : 0;
 }
 
@@ -609,6 +614,9 @@ static int wpa_config_write_global(struct wpa_config *config, HKEY hk)
        wpa_config_write_reg_dword(hk, TEXT("disassoc_low_ack"),
                                   config->disassoc_low_ack, 0);
 
+       wpa_config_write_reg_dword(hk, TEXT("okc"), config->okc, 0);
+       wpa_config_write_reg_dword(hk, TEXT("pmf"), config->pmf, 0);
+
        return 0;
 }
 
@@ -904,11 +912,13 @@ static int wpa_config_write_network(HKEY hk, struct wpa_ssid *ssid, int id)
        INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE);
 #endif /* IEEE8021X_EAPOL */
        INT(mode);
-       INT(proactive_key_caching);
+       write_int(netw, "proactive_key_caching", ssid->proactive_key_caching,
+                 -1);
        INT(disabled);
        INT(peerkey);
 #ifdef CONFIG_IEEE80211W
-       INT(ieee80211w);
+       write_int(netw, "ieee80211w", ssid->ieee80211w,
+                 MGMT_FRAME_PROTECTION_DEFAULT);
 #endif /* CONFIG_IEEE80211W */
        STR(id_str);
 
index bcf27be..564c91e 100644 (file)
@@ -37,7 +37,6 @@
 #include "ctrl_iface.h"
 #include "interworking.h"
 #include "blacklist.h"
-#include "wpas_glue.h"
 #include "autoscan.h"
 
 extern struct wpa_driver_ops *wpa_drivers[];
@@ -158,6 +157,128 @@ static int set_bssid_filter(struct wpa_supplicant *wpa_s, char *val)
 }
 
 
+static int set_disallow_aps(struct wpa_supplicant *wpa_s, char *val)
+{
+       char *pos;
+       u8 addr[ETH_ALEN], *bssid = NULL, *n;
+       struct wpa_ssid_value *ssid = NULL, *ns;
+       size_t count = 0, ssid_count = 0;
+       struct wpa_ssid *c;
+
+       /*
+        * disallow_list ::= <ssid_spec> | <bssid_spec> | <disallow_list> | \93\94
+        * SSID_SPEC ::= ssid <SSID_HEX>
+        * BSSID_SPEC ::= bssid <BSSID_HEX>
+        */
+
+       pos = val;
+       while (pos) {
+               if (*pos == '\0')
+                       break;
+               if (os_strncmp(pos, "bssid ", 6) == 0) {
+                       int res;
+                       pos += 6;
+                       res = hwaddr_aton2(pos, addr);
+                       if (res < 0) {
+                               os_free(ssid);
+                               os_free(bssid);
+                               wpa_printf(MSG_DEBUG, "Invalid disallow_aps "
+                                          "BSSID value '%s'", pos);
+                               return -1;
+                       }
+                       pos += res;
+                       n = os_realloc_array(bssid, count + 1, ETH_ALEN);
+                       if (n == NULL) {
+                               os_free(ssid);
+                               os_free(bssid);
+                               return -1;
+                       }
+                       bssid = n;
+                       os_memcpy(bssid + count * ETH_ALEN, addr, ETH_ALEN);
+                       count++;
+               } else if (os_strncmp(pos, "ssid ", 5) == 0) {
+                       char *end;
+                       pos += 5;
+
+                       end = pos;
+                       while (*end) {
+                               if (*end == '\0' || *end == ' ')
+                                       break;
+                               end++;
+                       }
+
+                       ns = os_realloc_array(ssid, ssid_count + 1,
+                                             sizeof(struct wpa_ssid_value));
+                       if (ns == NULL) {
+                               os_free(ssid);
+                               os_free(bssid);
+                               return -1;
+                       }
+                       ssid = ns;
+
+                       if ((end - pos) & 0x01 || end - pos > 2 * 32 ||
+                           hexstr2bin(pos, ssid[ssid_count].ssid,
+                                      (end - pos) / 2) < 0) {
+                               os_free(ssid);
+                               os_free(bssid);
+                               wpa_printf(MSG_DEBUG, "Invalid disallow_aps "
+                                          "SSID value '%s'", pos);
+                               return -1;
+                       }
+                       ssid[ssid_count].ssid_len = (end - pos) / 2;
+                       wpa_hexdump_ascii(MSG_DEBUG, "disallow_aps SSID",
+                                         ssid[ssid_count].ssid,
+                                         ssid[ssid_count].ssid_len);
+                       ssid_count++;
+                       pos = end;
+               } else {
+                       wpa_printf(MSG_DEBUG, "Unexpected disallow_aps value "
+                                  "'%s'", pos);
+                       os_free(ssid);
+                       os_free(bssid);
+                       return -1;
+               }
+
+               pos = os_strchr(pos, ' ');
+               if (pos)
+                       pos++;
+       }
+
+       wpa_hexdump(MSG_DEBUG, "disallow_aps_bssid", bssid, count * ETH_ALEN);
+       os_free(wpa_s->disallow_aps_bssid);
+       wpa_s->disallow_aps_bssid = bssid;
+       wpa_s->disallow_aps_bssid_count = count;
+
+       wpa_printf(MSG_DEBUG, "disallow_aps_ssid_count %d", (int) ssid_count);
+       os_free(wpa_s->disallow_aps_ssid);
+       wpa_s->disallow_aps_ssid = ssid;
+       wpa_s->disallow_aps_ssid_count = ssid_count;
+
+       if (!wpa_s->current_ssid || wpa_s->wpa_state < WPA_AUTHENTICATING)
+               return 0;
+
+       c = wpa_s->current_ssid;
+       if (c->mode != WPAS_MODE_INFRA && c->mode != WPAS_MODE_IBSS)
+               return 0;
+
+       if (!disallowed_bssid(wpa_s, wpa_s->bssid) &&
+           !disallowed_ssid(wpa_s, c->ssid, c->ssid_len))
+               return 0;
+
+       wpa_printf(MSG_DEBUG, "Disconnect and try to find another network "
+                  "because current AP was marked disallowed");
+
+#ifdef CONFIG_SME
+       wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+       wpa_s->reassociate = 1;
+       wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+       wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+       return 0;
+}
+
+
 static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
                                         char *cmd)
 {
@@ -291,6 +412,8 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_WIFI_DISPLAY */
        } else if (os_strcasecmp(cmd, "bssid_filter") == 0) {
                ret = set_bssid_filter(wpa_s, value);
+       } else if (os_strcasecmp(cmd, "disallow_aps") == 0) {
+               ret = set_disallow_aps(wpa_s, value);
        } else {
                value[-1] = '=';
                ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
@@ -540,9 +663,21 @@ static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
        }
 
 #ifdef CONFIG_AP
-       if (wpa_s->ap_iface)
+       if (wpa_s->ap_iface) {
+               int timeout = 0;
+               char *pos;
+
+               if (pin) {
+                       pos = os_strchr(pin, ' ');
+                       if (pos) {
+                               *pos++ = '\0';
+                               timeout = atoi(pos);
+                       }
+               }
+
                return wpa_supplicant_ap_wps_pin(wpa_s, _bssid, pin,
-                                                buf, buflen);
+                                                buf, buflen, timeout);
+       }
 #endif /* CONFIG_AP */
 
        if (pin) {
@@ -614,31 +749,6 @@ static int wpa_supplicant_ctrl_iface_wps_check_pin(
 }
 
 
-#ifdef CONFIG_WPS_OOB
-static int wpa_supplicant_ctrl_iface_wps_oob(struct wpa_supplicant *wpa_s,
-                                            char *cmd)
-{
-       char *path, *method, *name;
-
-       path = os_strchr(cmd, ' ');
-       if (path == NULL)
-               return -1;
-       *path++ = '\0';
-
-       method = os_strchr(path, ' ');
-       if (method == NULL)
-               return -1;
-       *method++ = '\0';
-
-       name = os_strchr(method, ' ');
-       if (name != NULL)
-               *name++ = '\0';
-
-       return wpas_wps_start_oob(wpa_s, cmd, path, method, name);
-}
-#endif /* CONFIG_WPS_OOB */
-
-
 #ifdef CONFIG_WPS_NFC
 
 static int wpa_supplicant_ctrl_iface_wps_nfc(struct wpa_supplicant *wpa_s,
@@ -710,6 +820,149 @@ static int wpa_supplicant_ctrl_iface_wps_nfc_tag_read(
        return ret;
 }
 
+
+static int wpas_ctrl_nfc_get_handover_req_wps(struct wpa_supplicant *wpa_s,
+                                             char *reply, size_t max_len)
+{
+       struct wpabuf *buf;
+       int res;
+
+       buf = wpas_wps_nfc_handover_req(wpa_s);
+       if (buf == NULL)
+               return -1;
+
+       res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+                                        wpabuf_len(buf));
+       reply[res++] = '\n';
+       reply[res] = '\0';
+
+       wpabuf_free(buf);
+
+       return res;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_req(struct wpa_supplicant *wpa_s,
+                                         char *cmd, char *reply,
+                                         size_t max_len)
+{
+       char *pos;
+
+       pos = os_strchr(cmd, ' ');
+       if (pos == NULL)
+               return -1;
+       *pos++ = '\0';
+
+       if (os_strcmp(cmd, "NDEF") != 0)
+               return -1;
+
+       if (os_strcmp(pos, "WPS") == 0) {
+               return wpas_ctrl_nfc_get_handover_req_wps(wpa_s, reply,
+                                                         max_len);
+       }
+
+       return -1;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_sel_wps(struct wpa_supplicant *wpa_s,
+                                             char *reply, size_t max_len)
+{
+       struct wpabuf *buf;
+       int res;
+
+       buf = wpas_wps_nfc_handover_sel(wpa_s);
+       if (buf == NULL)
+               return -1;
+
+       res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+                                        wpabuf_len(buf));
+       reply[res++] = '\n';
+       reply[res] = '\0';
+
+       wpabuf_free(buf);
+
+       return res;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_sel(struct wpa_supplicant *wpa_s,
+                                         char *cmd, char *reply,
+                                         size_t max_len)
+{
+       char *pos;
+
+       pos = os_strchr(cmd, ' ');
+       if (pos == NULL)
+               return -1;
+       *pos++ = '\0';
+
+       if (os_strcmp(cmd, "NDEF") != 0)
+               return -1;
+
+       if (os_strcmp(pos, "WPS") == 0) {
+               return wpas_ctrl_nfc_get_handover_sel_wps(wpa_s, reply,
+                                                         max_len);
+       }
+
+       return -1;
+}
+
+
+static int wpas_ctrl_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
+                                        char *cmd, char *reply,
+                                        size_t max_len)
+{
+       size_t len;
+       struct wpabuf *buf;
+       int ret;
+
+       len = os_strlen(cmd);
+       if (len & 0x01)
+               return -1;
+       len /= 2;
+
+       buf = wpabuf_alloc(len);
+       if (buf == NULL)
+               return -1;
+       if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
+               wpabuf_free(buf);
+               return -1;
+       }
+
+       ret = wpas_wps_nfc_rx_handover_req(wpa_s, buf);
+       wpabuf_free(buf);
+
+       return ret;
+}
+
+
+static int wpas_ctrl_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
+                                        char *cmd)
+{
+       size_t len;
+       struct wpabuf *buf;
+       int ret;
+
+       len = os_strlen(cmd);
+       if (len & 0x01)
+               return -1;
+       len /= 2;
+
+       buf = wpabuf_alloc(len);
+       if (buf == NULL)
+               return -1;
+       if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
+               wpabuf_free(buf);
+               return -1;
+       }
+
+       ret = wpas_wps_nfc_rx_handover_sel(wpa_s, buf);
+       wpabuf_free(buf);
+
+       return ret;
+}
+
 #endif /* CONFIG_WPS_NFC */
 
 
@@ -1146,6 +1399,45 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
                        return pos - buf;
                pos += ret;
        }
+
+       if (wpa_s->current_ssid) {
+               struct wpa_cred *cred;
+               char *type;
+
+               for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+                       if (wpa_s->current_ssid->parent_cred != cred)
+                               continue;
+                       if (!cred->domain)
+                               continue;
+
+                       ret = os_snprintf(pos, end - pos, "home_sp=%s\n",
+                                         cred->domain);
+                       if (ret < 0 || ret >= end - pos)
+                               return pos - buf;
+                       pos += ret;
+
+                       if (wpa_s->current_bss == NULL ||
+                           wpa_s->current_bss->anqp == NULL)
+                               res = -1;
+                       else
+                               res = interworking_home_sp_cred(
+                                       wpa_s, cred,
+                                       wpa_s->current_bss->anqp->domain_name);
+                       if (res > 0)
+                               type = "home";
+                       else if (res == 0)
+                               type = "roaming";
+                       else
+                               type = "unknown";
+
+                       ret = os_snprintf(pos, end - pos, "sp_type=%s\n", type);
+                       if (ret < 0 || ret >= end - pos)
+                               return pos - buf;
+                       pos += ret;
+
+                       break;
+               }
+       }
 #endif /* CONFIG_HS20 */
 
        if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
@@ -1869,8 +2161,8 @@ static int wpa_supplicant_ctrl_iface_remove_network(
 #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,
-                                                   WLAN_REASON_DEAUTH_LEAVING);
+                       wpa_supplicant_deauthenticate(
+                               wpa_s, WLAN_REASON_DEAUTH_LEAVING);
                }
                return 0;
        }
@@ -1902,7 +2194,8 @@ static int wpa_supplicant_ctrl_iface_remove_network(
                wpa_sm_set_config(wpa_s->wpa, NULL);
                eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
 
-               wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+               wpa_supplicant_deauthenticate(wpa_s,
+                                             WLAN_REASON_DEAUTH_LEAVING);
        }
 
        if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
@@ -1952,7 +2245,9 @@ static int wpa_supplicant_ctrl_iface_set_network(
                return -1;
        }
 
-       wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
+       if (os_strcmp(name, "bssid") != 0 &&
+           os_strcmp(name, "priority") != 0)
+               wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
 
        if (wpa_s->current_ssid == ssid || wpa_s->current_ssid == NULL) {
                /*
@@ -2069,20 +2364,62 @@ static int wpa_supplicant_ctrl_iface_add_cred(struct wpa_supplicant *wpa_s,
 }
 
 
+static int wpas_ctrl_remove_cred(struct wpa_supplicant *wpa_s,
+                                struct wpa_cred *cred)
+{
+       struct wpa_ssid *ssid;
+       char str[20];
+
+       if (cred == NULL || wpa_config_remove_cred(wpa_s->conf, cred->id) < 0) {
+               wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred");
+               return -1;
+       }
+
+       /* Remove any network entry created based on the removed credential */
+       ssid = wpa_s->conf->ssid;
+       while (ssid) {
+               if (ssid->parent_cred == cred) {
+                       wpa_printf(MSG_DEBUG, "Remove network id %d since it "
+                                  "used the removed credential", ssid->id);
+                       os_snprintf(str, sizeof(str), "%d", ssid->id);
+                       ssid = ssid->next;
+                       wpa_supplicant_ctrl_iface_remove_network(wpa_s, str);
+               } else
+                       ssid = ssid->next;
+       }
+
+       return 0;
+}
+
+
 static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s,
                                                 char *cmd)
 {
        int id;
-       struct wpa_cred *cred;
+       struct wpa_cred *cred, *prev;
 
-       /* cmd: "<cred id>" or "all" */
+       /* cmd: "<cred id>", "all", or "sp_fqdn=<FQDN>" */
        if (os_strcmp(cmd, "all") == 0) {
                wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED all");
                cred = wpa_s->conf->cred;
                while (cred) {
-                       id = cred->id;
+                       prev = cred;
+                       cred = cred->next;
+                       wpas_ctrl_remove_cred(wpa_s, prev);
+               }
+               return 0;
+       }
+
+       if (os_strncmp(cmd, "sp_fqdn=", 8) == 0) {
+               wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED SP FQDN '%s'",
+                          cmd + 8);
+               cred = wpa_s->conf->cred;
+               while (cred) {
+                       prev = cred;
                        cred = cred->next;
-                       wpa_config_remove_cred(wpa_s->conf, id);
+                       if (prev->domain &&
+                           os_strcmp(prev->domain, cmd + 8) == 0)
+                               wpas_ctrl_remove_cred(wpa_s, prev);
                }
                return 0;
        }
@@ -2091,14 +2428,7 @@ static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s,
        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;
+       return wpas_ctrl_remove_cred(wpa_s, cred);
 }
 
 
@@ -3144,7 +3474,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
        auth = os_strstr(pos, " auth") != NULL;
        automatic = os_strstr(pos, " auto") != NULL;
        pd = os_strstr(pos, " provdisc") != NULL;
-       ht40 = os_strstr(pos, " ht40") != NULL;
+       ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
 
        pos2 = os_strstr(pos, " go_intent=");
        if (pos2) {
@@ -3575,7 +3905,7 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
                        return -1;
        }
 
-       ht40 = os_strstr(cmd, " ht40") != NULL;
+       ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
 
        return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40);
 }
@@ -3651,7 +3981,7 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
        if (pos)
                freq = atoi(pos + 5);
 
-       ht40 = os_strstr(cmd, "ht40") != NULL;
+       ht40 = (os_strstr(cmd, "ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
 
        if (os_strncmp(cmd, "persistent=", 11) == 0)
                return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq,
@@ -3679,6 +4009,7 @@ static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
        char *pos, *end;
        char devtype[WPS_DEV_TYPE_BUFSIZE];
        struct wpa_ssid *ssid;
+       size_t i;
 
        if (!wpa_s->global->p2p)
                return -1;
@@ -3732,6 +4063,18 @@ static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
                return pos - buf;
        pos += res;
 
+       for (i = 0; i < info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN; i++)
+       {
+               const u8 *t;
+               t = &info->wps_sec_dev_type_list[i * WPS_DEV_TYPE_LEN];
+               res = os_snprintf(pos, end - pos, "sec_dev_type=%s\n",
+                                 wps_dev_type_bin2str(t, devtype,
+                                                      sizeof(devtype)));
+               if (res < 0 || res >= end - pos)
+                       return pos - buf;
+               pos += res;
+       }
+
        ssid = wpas_p2p_get_persistent(wpa_s, info->p2p_device_addr, NULL, 0);
        if (ssid) {
                res = os_snprintf(pos, end - pos, "persistent=%d\n", ssid->id);
@@ -3960,6 +4303,30 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
        if (os_strcmp(cmd, "disallow_freq") == 0)
                return p2p_ctrl_disallow_freq(wpa_s, param);
 
+       if (os_strcmp(cmd, "disc_int") == 0) {
+               int min_disc_int, max_disc_int, max_disc_tu;
+               char *pos;
+
+               pos = param;
+
+               min_disc_int = atoi(pos);
+               pos = os_strchr(pos, ' ');
+               if (pos == NULL)
+                       return -1;
+               *pos++ = '\0';
+
+               max_disc_int = atoi(pos);
+               pos = os_strchr(pos, ' ');
+               if (pos == NULL)
+                       return -1;
+               *pos++ = '\0';
+
+               max_disc_tu = atoi(pos);
+
+               return p2p_set_disc_int(wpa_s->global->p2p, min_disc_int,
+                                       max_disc_int, max_disc_tu);
+       }
+
        wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
                   cmd);
 
@@ -4392,7 +4759,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        int reply_len;
 
        if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
-           os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
+           os_strncmp(buf, "SET_NETWORK ", 12) == 0 ||
+           os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 ||
+           os_strncmp(buf, "NFC_RX_HANDOVER_SEL", 19) == 0) {
                wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
                                      (const u8 *) buf, os_strlen(buf));
        } else {
@@ -4452,25 +4821,15 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strcmp(buf, "LOGOFF") == 0) {
                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 {
-                       wpa_s->disconnected = 0;
-                       wpa_s->reassociate = 1;
-                       wpa_supplicant_req_scan(wpa_s, 0, 0);
-               }
+               else
+                       wpas_request_connection(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) {
-                       wpa_s->disconnected = 0;
-                       wpa_s->reassociate = 1;
-                       wpa_supplicant_req_scan(wpa_s, 0, 0);
-               }
+               else if (wpa_s->disconnected)
+                       wpas_request_connection(wpa_s);
 #ifdef IEEE8021X_EAPOL
        } else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
                if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
@@ -4511,11 +4870,6 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
                if (wpas_wps_cancel(wpa_s))
                        reply_len = -1;
-#ifdef CONFIG_WPS_OOB
-       } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
-               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))
@@ -4530,6 +4884,18 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                if (wpa_supplicant_ctrl_iface_wps_nfc_tag_read(wpa_s,
                                                               buf + 17))
                        reply_len = -1;
+       } else if (os_strncmp(buf, "NFC_GET_HANDOVER_REQ ", 21) == 0) {
+               reply_len = wpas_ctrl_nfc_get_handover_req(
+                       wpa_s, buf + 21, reply, reply_size);
+       } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
+               reply_len = wpas_ctrl_nfc_get_handover_sel(
+                       wpa_s, buf + 21, reply, reply_size);
+       } else if (os_strncmp(buf, "NFC_RX_HANDOVER_REQ ", 20) == 0) {
+               reply_len = wpas_ctrl_nfc_rx_handover_req(
+                       wpa_s, buf + 20, reply, reply_size);
+       } else if (os_strncmp(buf, "NFC_RX_HANDOVER_SEL ", 20) == 0) {
+               if (wpas_ctrl_nfc_rx_handover_sel(wpa_s, buf + 20))
+                       reply_len = -1;
 #endif /* CONFIG_WPS_NFC */
        } else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
                if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
@@ -4762,14 +5128,14 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                            ((wpa_s->wpa_state <= WPA_SCANNING) ||
                             (wpa_s->wpa_state == WPA_COMPLETED))) {
                                wpa_s->normal_scans = 0;
-                               wpa_s->scan_req = 2;
+                               wpa_s->scan_req = MANUAL_SCAN_REQ;
                                wpa_supplicant_req_scan(wpa_s, 0, 0);
                        } else if (wpa_s->sched_scanning) {
                                wpa_printf(MSG_DEBUG, "Stop ongoing "
                                           "sched_scan to allow requested "
                                           "full scan to proceed");
                                wpa_supplicant_cancel_sched_scan(wpa_s);
-                               wpa_s->scan_req = 2;
+                               wpa_s->scan_req = MANUAL_SCAN_REQ;
                                wpa_supplicant_req_scan(wpa_s, 0, 0);
                        } else {
                                wpa_printf(MSG_DEBUG, "Ongoing scan action - "
@@ -4903,6 +5269,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                                                      reply_size);
 #endif
        } else if (os_strcmp(buf, "REAUTHENTICATE") == 0) {
+               pmksa_cache_clear_current(wpa_s->wpa);
                eapol_sm_request_reauth(wpa_s->eapol);
        } else {
                os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
index 4eeb93a..8bc6618 100644 (file)
@@ -1950,6 +1950,10 @@ static const struct wpa_dbus_property_desc wpas_dbus_global_properties[] = {
          wpas_dbus_getter_eap_methods,
          NULL
        },
+       { "Capabilities", WPAS_DBUS_NEW_INTERFACE, "as",
+         wpas_dbus_getter_global_capabilities,
+         NULL
+       },
        { NULL, NULL, NULL, NULL, NULL }
 };
 
@@ -2232,6 +2236,10 @@ static const struct wpa_dbus_property_desc wpas_dbus_bss_properties[] = {
          wpas_dbus_getter_bss_rsn,
          NULL
        },
+       { "WPS", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
+         wpas_dbus_getter_bss_wps,
+         NULL
+       },
        { "IEs", WPAS_DBUS_NEW_IFACE_BSS, "ay",
          wpas_dbus_getter_bss_ies,
          NULL
index 44cde42..363a7e5 100644 (file)
@@ -39,6 +39,7 @@ enum wpas_dbus_bss_prop {
        WPAS_DBUS_BSS_PROP_RATES,
        WPAS_DBUS_BSS_PROP_WPA,
        WPAS_DBUS_BSS_PROP_RSN,
+       WPAS_DBUS_BSS_PROP_WPS,
        WPAS_DBUS_BSS_PROP_IES,
 };
 
index 5668e1a..5e06932 100644 (file)
@@ -21,7 +21,6 @@
 #include "../notify.h"
 #include "../bss.h"
 #include "../scan.h"
-#include "../ctrl_iface.h"
 #include "../autoscan.h"
 #include "dbus_new_helpers.h"
 #include "dbus_new.h"
@@ -124,7 +123,7 @@ DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
 static const char *dont_quote[] = {
        "key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
        "opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
-       "bssid", NULL
+       "bssid", "scan_freq", "freq_list", NULL
 };
 
 static dbus_bool_t should_quote_opt(const char *key)
@@ -924,6 +923,44 @@ dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter,
 }
 
 
+/**
+ * wpas_dbus_getter_global_capabilities - Request supported global capabilities
+ * @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 "Capabilities" property. Handles requests by dbus clients to
+ * return a list of strings with supported capabilities like AP, RSN IBSS,
+ * and P2P that are determined at compile time.
+ */
+dbus_bool_t wpas_dbus_getter_global_capabilities(DBusMessageIter *iter,
+                                                DBusError *error,
+                                                void *user_data)
+{
+       const char *capabilities[5] = { NULL, NULL, NULL, NULL, NULL };
+       size_t num_items = 0;
+
+#ifdef CONFIG_AP
+       capabilities[num_items++] = "ap";
+#endif /* CONFIG_AP */
+#ifdef CONFIG_IBSS_RSN
+       capabilities[num_items++] = "ibss-rsn";
+#endif /* CONFIG_IBSS_RSN */
+#ifdef CONFIG_P2P
+       capabilities[num_items++] = "p2p";
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_INTERWORKING
+       capabilities[num_items++] = "interworking";
+#endif /* CONFIG_INTERWORKING */
+
+       return wpas_dbus_simple_array_property_getter(iter,
+                                                     DBUS_TYPE_STRING,
+                                                     capabilities,
+                                                     num_items, error);
+}
+
+
 static int wpas_dbus_get_scan_type(DBusMessage *message, DBusMessageIter *var,
                                   char **type, DBusMessage **reply)
 {
@@ -1275,7 +1312,7 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
                } else if (params.freqs && params.freqs[0]) {
                        wpa_supplicant_trigger_scan(wpa_s, &params);
                } else {
-                       wpa_s->scan_req = 2;
+                       wpa_s->scan_req = MANUAL_SCAN_REQ;
                        wpa_supplicant_req_scan(wpa_s, 0, 0);
                }
        } else if (!os_strcmp(type, "active")) {
@@ -1417,12 +1454,7 @@ DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message,
                                            struct wpa_supplicant *wpa_s)
 {
        if (wpa_s->current_ssid != NULL) {
-               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);
-
+               wpas_request_connection(wpa_s);
                return NULL;
        }
 
@@ -1454,13 +1486,15 @@ DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
        /* Extract the network ID and ensure the network */
        /* is actually a child of this interface */
        iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
-       if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+       if (iface == NULL || net_id == NULL ||
+           os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
                reply = wpas_dbus_error_invalid_args(message, op);
                goto out;
        }
 
+       errno = 0;
        id = strtoul(net_id, NULL, 10);
-       if (errno == EINVAL) {
+       if (errno != 0) {
                reply = wpas_dbus_error_invalid_args(message, op);
                goto out;
        }
@@ -1509,7 +1543,8 @@ static void remove_network(void *arg, struct wpa_ssid *ssid)
        }
 
        if (ssid == wpa_s->current_ssid)
-               wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+               wpa_supplicant_deauthenticate(wpa_s,
+                                             WLAN_REASON_DEAUTH_LEAVING);
 }
 
 
@@ -1553,13 +1588,15 @@ DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
        /* Extract the network ID and ensure the network */
        /* is actually a child of this interface */
        iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
-       if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+       if (iface == NULL || net_id == NULL ||
+           os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
                reply = wpas_dbus_error_invalid_args(message, op);
                goto out;
        }
 
+       errno = 0;
        id = strtoul(net_id, NULL, 10);
-       if (errno == EINVAL) {
+       if (errno != 0) {
                reply = wpas_dbus_error_invalid_args(message, op);
                goto out;
        }
@@ -1608,13 +1645,15 @@ DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message,
        /* Extract the network ID and ensure the network */
        /* is actually a child of this interface */
        iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
-       if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+       if (iface == NULL || net_id == NULL ||
+           os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
                reply = wpas_dbus_error_invalid_args(message, op);
                goto out;
        }
 
+       errno = 0;
        id = strtoul(net_id, NULL, 10);
-       if (errno == EINVAL) {
+       if (errno != 0) {
                reply = wpas_dbus_error_invalid_args(message, net_id);
                goto out;
        }
@@ -3366,6 +3405,63 @@ dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
 
 
 /**
+ * wpas_dbus_getter_bss_wps - Return the WPS options of a BSS
+ * @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 "WPS" property.
+ */
+dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error,
+                                    void *user_data)
+{
+       struct bss_handler_args *args = user_data;
+       struct wpa_bss *res;
+#ifdef CONFIG_WPS
+       struct wpabuf *wps_ie;
+#endif /* CONFIG_WPS */
+       DBusMessageIter iter_dict, variant_iter;
+       const char *type = "";
+
+       res = get_bss_helper(args, error, __func__);
+       if (!res)
+               return FALSE;
+
+       if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+                                             "a{sv}", &variant_iter))
+               goto nomem;
+
+       if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
+               goto nomem;
+
+#ifdef CONFIG_WPS
+       wps_ie = wpa_bss_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE);
+       if (wps_ie) {
+               if (wps_is_selected_pbc_registrar(wps_ie))
+                       type = "pbc";
+               else if (wps_is_selected_pin_registrar(wps_ie))
+                       type = "pin";
+       }
+#endif /* CONFIG_WPS */
+
+       if (!wpa_dbus_dict_append_string(&iter_dict, "Type", type))
+               goto nomem;
+
+       if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
+               goto nomem;
+       if (!dbus_message_iter_close_container(iter, &variant_iter))
+               goto nomem;
+
+       return TRUE;
+
+nomem:
+       dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+       return FALSE;
+}
+
+
+/**
  * wpas_dbus_getter_bss_ies - Return all IEs of a BSS
  * @iter: Pointer to incoming dbus message iter
  * @error: Location to store error on failure
index 178a76b..aa56550 100644 (file)
@@ -80,6 +80,10 @@ dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter,
 dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter,
                                         DBusError *error, void *user_data);
 
+dbus_bool_t wpas_dbus_getter_global_capabilities(DBusMessageIter *iter,
+                                                DBusError *error,
+                                                void *user_data);
+
 DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
                                     struct wpa_supplicant *wpa_s);
 
@@ -238,6 +242,9 @@ dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error,
 dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
                                     void *user_data);
 
+dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error,
+                                    void *user_data);
+
 dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error,
                                     void *user_data);
 
index 8489ce7..4ad5e7e 100644 (file)
@@ -273,7 +273,7 @@ DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message,
                        ret = wpa_supplicant_ap_wps_pin(wpa_s,
                                                        params.bssid,
                                                        params.pin,
-                                                       npin, sizeof(npin));
+                                                       npin, sizeof(npin), 0);
                else
 #endif /* CONFIG_AP */
                {
index e217a72..68e5515 100644 (file)
@@ -331,7 +331,7 @@ DBusMessage * wpas_dbus_global_set_debugparams(DBusMessage *message,
 DBusMessage * wpas_dbus_iface_scan(DBusMessage *message,
                                   struct wpa_supplicant *wpa_s)
 {
-       wpa_s->scan_req = 2;
+       wpa_s->scan_req = MANUAL_SCAN_REQ;
        wpa_supplicant_req_scan(wpa_s, 0, 0);
        return wpas_dbus_new_success_reply(message);
 }
index bc148ca..6bab19c 100644 (file)
@@ -139,16 +139,6 @@ static inline int wpa_drv_deauthenticate(struct wpa_supplicant *wpa_s,
        return -1;
 }
 
-static inline int wpa_drv_disassociate(struct wpa_supplicant *wpa_s,
-                                      const u8 *addr, int reason_code)
-{
-       if (wpa_s->driver->disassociate) {
-               return wpa_s->driver->disassociate(wpa_s->drv_priv, addr,
-                                                  reason_code);
-       }
-       return -1;
-}
-
 static inline int wpa_drv_add_pmkid(struct wpa_supplicant *wpa_s,
                                    const u8 *bssid, const u8 *pmkid)
 {
index 4b1d992..23b91d2 100644 (file)
@@ -84,6 +84,12 @@ static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
                return -1;
        }
 
+       if (disallowed_bssid(wpa_s, wpa_s->bssid) ||
+           disallowed_ssid(wpa_s, ssid->ssid, ssid->ssid_len)) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "Selected BSS is disallowed");
+               return -1;
+       }
+
        res = wpas_temp_disabled(wpa_s, ssid);
        if (res > 0) {
                wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is temporarily "
@@ -423,7 +429,9 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
 
 #ifdef CONFIG_IEEE80211W
                if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
-                   ssid->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) {
+                   (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+                    wpa_s->conf->pmf : ssid->ieee80211w) ==
+                   MGMT_FRAME_PROTECTION_REQUIRED) {
                        wpa_dbg(wpa_s, MSG_DEBUG, "   skip RSN IE - no mgmt "
                                "frame protection");
                        break;
@@ -675,6 +683,16 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
                return NULL;
        }
 
+       if (disallowed_bssid(wpa_s, bss->bssid)) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "   skip - BSSID disallowed");
+               return NULL;
+       }
+
+       if (disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "   skip - SSID disallowed");
+               return NULL;
+       }
+
        wpa = wpa_ie_len > 0 || rsn_ie_len > 0;
 
        for (ssid = group; ssid; ssid = ssid->pnext) {
@@ -862,6 +880,8 @@ static void wpa_supplicant_req_new_scan(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_P2P */
                return;
        }
+
+       wpa_s->scan_for_connection = 1;
        wpa_supplicant_req_scan(wpa_s, timeout_sec, timeout_usec);
 }
 
@@ -1012,6 +1032,12 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
                return 1;
        }
 
+       if (current_bss->level < 0 && current_bss->level > selected->level) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - Current BSS has better "
+                       "signal level");
+               return 0;
+       }
+
        min_diff = 2;
        if (current_bss->level < 0) {
                if (current_bss->level < -85)
@@ -1632,7 +1658,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
 
        if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
                wpa_dbg(wpa_s, MSG_ERROR, "Failed to get BSSID");
-               wpa_supplicant_disassociate(
+               wpa_supplicant_deauthenticate(
                        wpa_s, WLAN_REASON_DEAUTH_LEAVING);
                return;
        }
@@ -1650,7 +1676,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
                        wpa_clear_keys(wpa_s, bssid);
                }
                if (wpa_supplicant_select_config(wpa_s) < 0) {
-                       wpa_supplicant_disassociate(
+                       wpa_supplicant_deauthenticate(
                                wpa_s, WLAN_REASON_DEAUTH_LEAVING);
                        return;
                }
@@ -1838,6 +1864,28 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
 }
 
 
+static int could_be_psk_mismatch(struct wpa_supplicant *wpa_s, u16 reason_code,
+                                int locally_generated)
+{
+       if (wpa_s->wpa_state != WPA_4WAY_HANDSHAKE ||
+           !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt))
+               return 0; /* Not in 4-way handshake with PSK */
+
+       /*
+        * It looks like connection was lost while trying to go through PSK
+        * 4-way handshake. Filter out known disconnection cases that are caused
+        * by something else than PSK mismatch to avoid confusing reports.
+        */
+
+       if (locally_generated) {
+               if (reason_code == WLAN_REASON_IE_IN_4WAY_DIFFERS)
+                       return 0;
+       }
+
+       return 1;
+}
+
+
 static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
                                                 u16 reason_code,
                                                 int locally_generated)
@@ -1863,8 +1911,7 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
                return;
        }
 
-       if (wpa_s->wpa_state == WPA_4WAY_HANDSHAKE &&
-           wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
+       if (could_be_psk_mismatch(wpa_s, reason_code, locally_generated)) {
                wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - "
                        "pre-shared key may be incorrect");
                wpas_auth_failed(wpa_s);
@@ -2530,9 +2577,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                data->assoc_reject.status_code);
                if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
                        sme_event_assoc_reject(wpa_s, data);
-#ifdef ANDROID_P2P
-#ifdef CONFIG_P2P
                else {
+#ifdef ANDROID_P2P
                        if(!wpa_s->current_ssid) {
                                wpa_printf(MSG_ERROR, "current_ssid == NULL");
                                break;
@@ -2571,9 +2617,14 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                                wpa_supplicant_disable_network(wpa_s, wpa_s->current_ssid);
                                wpas_p2p_group_remove(wpa_s, wpa_s->ifname);
                        }
-               }
-#endif
+#else
+                       const u8 *bssid = data->assoc_reject.bssid;
+                       if (bssid == NULL || is_zero_ether_addr(bssid))
+                               bssid = wpa_s->pending_bssid;
+                       wpas_connection_failed(wpa_s, bssid);
+                       wpa_supplicant_mark_disassoc(wpa_s);
 #endif /* ANDROID_P2P */
+               }
                break;
        case EVENT_AUTH_TIMED_OUT:
                if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
diff --git a/wpa_supplicant/examples/wps-nfc.py b/wpa_supplicant/examples/wps-nfc.py
new file mode 100755 (executable)
index 0000000..0cfc1f6
--- /dev/null
@@ -0,0 +1,162 @@
+#!/usr/bin/python
+#
+# Example nfcpy to wpa_supplicant wrapper for WPS NFC operations
+# 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.
+
+import os
+import sys
+import time
+
+import nfc
+import nfc.ndef
+import nfc.llcp
+import nfc.handover
+
+import wpactrl
+
+wpas_ctrl = '/var/run/wpa_supplicant'
+
+def wpas_connect():
+    ifaces = []
+    if os.path.isdir(wpas_ctrl):
+        try:
+            ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
+        except OSError, error:
+            print "Could not find wpa_supplicant: ", error
+            return None
+
+    if len(ifaces) < 1:
+        print "No wpa_supplicant control interface found"
+        return None
+
+    for ctrl in ifaces:
+        try:
+            wpas = wpactrl.WPACtrl(ctrl)
+            return wpas
+        except wpactrl.error, error:
+            print "Error: ", error
+            pass
+    return None
+
+
+def wpas_tag_read(message):
+    wpas = wpas_connect()
+    if (wpas == None):
+        return
+    print wpas.request("WPS_NFC_TAG_READ " + message.encode("hex"))
+
+
+def wpas_get_handover_req():
+    wpas = wpas_connect()
+    if (wpas == None):
+        return None
+    return wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS").rstrip().decode("hex")
+
+
+def wpas_put_handover_sel(message):
+    wpas = wpas_connect()
+    if (wpas == None):
+        return
+    print wpas.request("NFC_RX_HANDOVER_SEL " + str(message).encode("hex"))
+
+
+def wps_handover_init(peer):
+    print "Trying to initiate WPS handover"
+
+    data = wpas_get_handover_req()
+    if (data == None):
+        print "Could not get handover request message from wpa_supplicant"
+        return
+    print "Handover request from wpa_supplicant: " + data.encode("hex")
+    message = nfc.ndef.Message(data)
+    print "Parsed handover request: " + message.pretty()
+
+    nfc.llcp.activate(peer);
+    time.sleep(0.5)
+
+    client = nfc.handover.HandoverClient()
+    try:
+        print "Trying handover";
+        client.connect()
+        print "Connected for handover"
+    except nfc.llcp.ConnectRefused:
+        print "Handover connection refused"
+        nfc.llcp.shutdown()
+        client.close()
+        return
+
+    print "Sending handover request"
+
+    if not client.send(message):
+        print "Failed to send handover request"
+
+    print "Receiving handover response"
+    message = client._recv()
+    print "Handover select received"
+    print message.pretty()
+    wpas_put_handover_sel(message)
+
+    print "Remove peer"
+    nfc.llcp.shutdown()
+    client.close()
+    print "Done with handover"
+
+
+def wps_tag_read(tag):
+    if len(tag.ndef.message):
+        message = nfc.ndef.Message(tag.ndef.message)
+        print "message type " + message.type
+
+        for record in message:
+            print "record type " + record.type
+            if record.type == "application/vnd.wfa.wsc":
+                print "WPS tag - send to wpa_supplicant"
+                wpas_tag_read(tag.ndef.message)
+                break
+    else:
+        print "Empty tag"
+
+    print "Remove tag"
+    while tag.is_present:
+        time.sleep(0.1)
+
+
+def main():
+    clf = nfc.ContactlessFrontend()
+
+    try:
+        while True:
+            print "Waiting for a tag or peer to be touched"
+
+            while True:
+                general_bytes = nfc.llcp.startup({})
+                tag = clf.poll(general_bytes)
+                if tag == None:
+                    continue
+
+                if isinstance(tag, nfc.DEP):
+                    wps_handover_init(tag)
+                    break
+
+                if tag.ndef:
+                    wps_tag_read(tag)
+                    break
+
+                if tag:
+                    print "Not an NDEF tag - remove tag"
+                    while tag.is_present:
+                        time.sleep(0.1)
+                    break
+
+    except KeyboardInterrupt:
+        raise SystemExit
+    finally:
+        clf.close()
+
+    raise SystemExit
+
+if __name__ == '__main__':
+    main()
index efa9be8..0d4ca8e 100644 (file)
@@ -453,6 +453,7 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
        if (gas_query_tx(gas, query, req) < 0) {
                wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
                           MACSTR, MAC2STR(query->addr));
+               dl_list_del(&query->list);
                os_free(query);
                return -1;
        }
index 0eb6119..1404241 100644 (file)
@@ -79,8 +79,10 @@ int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
 
        freq = wpa_s->assoc_freq;
        bss = wpa_bss_get_bssid(wpa_s, dst);
-       if (bss)
+       if (bss) {
+               wpa_bss_anqp_unshare_alloc(bss);
                freq = bss->freq;
+       }
        if (freq <= 0)
                return -1;
 
@@ -141,9 +143,16 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
                }
                break;
        case HS20_STYPE_WAN_METRICS:
+               wpa_hexdump(MSG_DEBUG, "WAN Metrics", pos, slen);
+               if (slen < 13) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short WAN "
+                               "Metrics value from " MACSTR, MAC2STR(sa));
+                       break;
+               }
                wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
-                       " WAN Metrics", MAC2STR(sa));
-               wpa_hexdump_ascii(MSG_DEBUG, "WAN Metrics", pos, slen);
+                       " WAN Metrics %02x:%u:%u:%u:%u:%u", MAC2STR(sa),
+                       pos[0], WPA_GET_LE32(pos + 1), WPA_GET_LE32(pos + 5),
+                       pos[9], pos[10], WPA_GET_LE16(pos + 11));
                if (anqp) {
                        wpabuf_free(anqp->hs20_wan_metrics);
                        anqp->hs20_wan_metrics = wpabuf_alloc_copy(pos, slen);
index 22f709f..cfe56ea 100644 (file)
@@ -717,9 +717,12 @@ static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix)
 #endif /* INTERWORKING_3GPP */
 
 
-static int interworking_set_hs20_params(struct wpa_ssid *ssid)
+static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s,
+                                       struct wpa_ssid *ssid)
 {
-       if (wpa_config_set(ssid, "key_mgmt", "WPA-EAP", 0) < 0)
+       if (wpa_config_set(ssid, "key_mgmt",
+                          wpa_s->conf->pmf != NO_MGMT_FRAME_PROTECTION ?
+                          "WPA-EAP WPA-EAP-SHA256" : "WPA-EAP", 0) < 0)
                return -1;
        if (wpa_config_set(ssid, "proto", "RSN", 0) < 0)
                return -1;
@@ -786,6 +789,7 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
        ssid = wpa_config_add_network(wpa_s->conf);
        if (ssid == NULL)
                return -1;
+       ssid->parent_cred = cred;
 
        wpas_notify_network_added(wpa_s, ssid);
        wpa_config_set_network_defaults(ssid);
@@ -797,7 +801,7 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
        os_memcpy(ssid->ssid, ie + 2, ie[1]);
        ssid->ssid_len = ie[1];
 
-       if (interworking_set_hs20_params(ssid) < 0)
+       if (interworking_set_hs20_params(wpa_s, ssid) < 0)
                goto fail;
 
        eap_type = EAP_TYPE_SIM;
@@ -1046,6 +1050,17 @@ static int interworking_set_eap_params(struct wpa_ssid *ssid,
            wpa_config_set_quoted(ssid, "client_cert", cred->client_cert) < 0)
                return -1;
 
+#ifdef ANDROID
+       if (cred->private_key &&
+           os_strncmp(cred->private_key, "keystore://", 11) == 0) {
+               /* Use OpenSSL engine configuration for Android keystore */
+               if (wpa_config_set_quoted(ssid, "engine_id", "keystore") < 0 ||
+                   wpa_config_set_quoted(ssid, "key_id",
+                                         cred->private_key + 11) < 0 ||
+                   wpa_config_set(ssid, "engine", "1", 0) < 0)
+                       return -1;
+       } else
+#endif /* ANDROID */
        if (cred->private_key && cred->private_key[0] &&
            wpa_config_set_quoted(ssid, "private_key", cred->private_key) < 0)
                return -1;
@@ -1084,6 +1099,7 @@ static int interworking_connect_roaming_consortium(
        ssid = wpa_config_add_network(wpa_s->conf);
        if (ssid == NULL)
                return -1;
+       ssid->parent_cred = cred;
        wpas_notify_network_added(wpa_s, ssid);
        wpa_config_set_network_defaults(ssid);
        ssid->priority = cred->priority;
@@ -1094,7 +1110,7 @@ static int interworking_connect_roaming_consortium(
        os_memcpy(ssid->ssid, ssid_ie + 2, ssid_ie[1]);
        ssid->ssid_len = ssid_ie[1];
 
-       if (interworking_set_hs20_params(ssid) < 0)
+       if (interworking_set_hs20_params(wpa_s, ssid) < 0)
                goto fail;
 
        if (cred->eap_method == NULL) {
@@ -1198,6 +1214,7 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
                nai_realm_free(realm, count);
                return -1;
        }
+       ssid->parent_cred = cred;
        wpas_notify_network_added(wpa_s, ssid);
        wpa_config_set_network_defaults(ssid);
        ssid->priority = cred->priority;
@@ -1208,7 +1225,7 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
        os_memcpy(ssid->ssid, ie + 2, ie[1]);
        ssid->ssid_len = ie[1];
 
-       if (interworking_set_hs20_params(ssid) < 0)
+       if (interworking_set_hs20_params(wpa_s, ssid) < 0)
                goto fail;
 
        if (wpa_config_set(ssid, "eap", eap_get_name(EAP_VENDOR_IETF,
@@ -1424,50 +1441,60 @@ static int domain_name_list_contains(struct wpabuf *domain_names,
 }
 
 
-static int interworking_home_sp(struct wpa_supplicant *wpa_s,
-                               struct wpabuf *domain_names)
+int interworking_home_sp_cred(struct wpa_supplicant *wpa_s,
+                             struct wpa_cred *cred,
+                             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
-               char *imsi = NULL;
-               int mnc_len = 0;
-               if (cred->imsi)
-                       imsi = cred->imsi;
+       char *imsi = NULL;
+       int mnc_len = 0;
+       if (cred->imsi)
+               imsi = cred->imsi;
 #ifdef CONFIG_PCSC
-               else 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;
-               }
+       else 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;
+       }
 #endif /* CONFIG_PCSC */
-               if (imsi && build_root_nai(nai, sizeof(nai), imsi, mnc_len, 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;
-               }
+       if (imsi && build_root_nai(nai, sizeof(nai), imsi, mnc_len, 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;
+       if (cred->domain == NULL)
+               return 0;
 
-               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;
+       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_home_sp(struct wpa_supplicant *wpa_s,
+                               struct wpabuf *domain_names)
+{
+       struct wpa_cred *cred;
+
+       if (domain_names == NULL || wpa_s->conf->cred == NULL)
+               return -1;
+
+       for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+               int res = interworking_home_sp_cred(wpa_s, cred, domain_names);
+               if (res)
+                       return res;
        }
 
        return 0;
@@ -1714,8 +1741,10 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
 
        freq = wpa_s->assoc_freq;
        bss = wpa_bss_get_bssid(wpa_s, dst);
-       if (bss)
+       if (bss) {
+               wpa_bss_anqp_unshare_alloc(bss);
                freq = bss->freq;
+       }
        if (freq <= 0)
                return -1;
 
@@ -1935,7 +1964,7 @@ int interworking_select(struct wpa_supplicant *wpa_s, int auto_select)
        wpa_printf(MSG_DEBUG, "Interworking: Start scan for network "
                   "selection");
        wpa_s->scan_res_handler = interworking_scan_res_handler;
-       wpa_s->scan_req = 2;
+       wpa_s->scan_req = MANUAL_SCAN_REQ;
        wpa_supplicant_req_scan(wpa_s, 0, 0);
 
        return 0;
index cb8438e..4a4af82 100644 (file)
@@ -25,5 +25,8 @@ void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s);
 int interworking_select(struct wpa_supplicant *wpa_s, int auto_select);
 int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss);
 void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s);
+int interworking_home_sp_cred(struct wpa_supplicant *wpa_s,
+                             struct wpa_cred *cred,
+                             struct wpabuf *domain_names);
 
 #endif /* INTERWORKING_H */
index 770907c..4479c09 100644 (file)
@@ -327,6 +327,9 @@ void wpas_notify_bss_rsnie_changed(struct wpa_supplicant *wpa_s,
 void wpas_notify_bss_wps_changed(struct wpa_supplicant *wpa_s,
                                 unsigned int id)
 {
+#ifdef CONFIG_WPS
+       wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_WPS, id);
+#endif /* CONFIG_WPS */
 }
 
 
index e6b0128..c2d702e 100644 (file)
@@ -89,14 +89,13 @@ 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,
                         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);
+static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s);
 
 
 static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
@@ -746,19 +745,13 @@ static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s,
        if (result != OFFCHANNEL_SEND_ACTION_SUCCESS &&
            wpa_s->pending_pd_before_join &&
            (os_memcmp(dst, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
-            os_memcmp(dst, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0)) {
+            os_memcmp(dst, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0) &&
+           wpa_s->p2p_fallback_to_go_neg) {
                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)");
-               wpas_p2p_join_start(wpa_s);
+               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;
        }
 }
 
@@ -861,7 +854,7 @@ static void p2p_go_configured(void *ctx, void *data)
                                          params->peer_device_addr);
        else if (wpa_s->p2p_pin[0])
                wpa_supplicant_ap_wps_pin(wpa_s, params->peer_interface_addr,
-                                         wpa_s->p2p_pin, NULL, 0);
+                                         wpa_s->p2p_pin, NULL, 0, 0);
        os_free(wpa_s->go_params);
        wpa_s->go_params = NULL;
 }
@@ -912,7 +905,11 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
                wpa_config_remove_network(wpa_s->conf, ssid->id);
                return;
        }
-       wpa_config_update_psk(ssid);
+       ssid->psk_set = params->psk_set;
+       if (ssid->psk_set)
+               os_memcpy(ssid->psk, params->psk, sizeof(ssid->psk));
+       else
+               wpa_config_update_psk(ssid);
        ssid->ap_max_inactivity = wpa_s->parent->conf->p2p_go_max_inactivity;
 
        wpa_s->ap_configured_cb = p2p_go_configured;
@@ -1268,6 +1265,135 @@ static int wpas_send_probe_resp(void *ctx, const struct wpabuf *buf)
 }
 
 
+/*
+ * DNS Header section is used only to calculate compression pointers, so the
+ * contents of this data does not matter, but the length needs to be reserved
+ * in the virtual packet.
+ */
+#define DNS_HEADER_LEN 12
+
+/*
+ * 27-octet in-memory packet from P2P specification containing two implied
+ * queries for _tcp.lcoal. PTR IN and _udp.local. PTR IN
+ */
+#define P2P_SD_IN_MEMORY_LEN 27
+
+static int p2p_sd_dns_uncompress_label(char **upos, char *uend, u8 *start,
+                                      u8 **spos, const u8 *end)
+{
+       while (*spos < end) {
+               u8 val = ((*spos)[0] & 0xc0) >> 6;
+               int len;
+
+               if (val == 1 || val == 2) {
+                       /* These are reserved values in RFC 1035 */
+                       wpa_printf(MSG_DEBUG, "P2P: Invalid domain name "
+                                  "sequence starting with 0x%x", val);
+                       return -1;
+               }
+
+               if (val == 3) {
+                       u16 offset;
+                       u8 *spos_tmp;
+
+                       /* Offset */
+                       if (*spos + 2 > end) {
+                               wpa_printf(MSG_DEBUG, "P2P: No room for full "
+                                          "DNS offset field");
+                               return -1;
+                       }
+
+                       offset = (((*spos)[0] & 0x3f) << 8) | (*spos)[1];
+                       if (offset >= *spos - start) {
+                               wpa_printf(MSG_DEBUG, "P2P: Invalid DNS "
+                                          "pointer offset %u", offset);
+                               return -1;
+                       }
+
+                       (*spos) += 2;
+                       spos_tmp = start + offset;
+                       return p2p_sd_dns_uncompress_label(upos, uend, start,
+                                                          &spos_tmp,
+                                                          *spos - 2);
+               }
+
+               /* Label */
+               len = (*spos)[0] & 0x3f;
+               if (len == 0)
+                       return 0;
+
+               (*spos)++;
+               if (*spos + len > end) {
+                       wpa_printf(MSG_DEBUG, "P2P: Invalid domain name "
+                                  "sequence - no room for label with length "
+                                  "%u", len);
+                       return -1;
+               }
+
+               if (*upos + len + 2 > uend)
+                       return -2;
+
+               os_memcpy(*upos, *spos, len);
+               *spos += len;
+               *upos += len;
+               (*upos)[0] = '.';
+               (*upos)++;
+               (*upos)[0] = '\0';
+       }
+
+       return 0;
+}
+
+
+/* Uncompress domain names per RFC 1035 using the P2P SD in-memory packet.
+ * Returns -1 on parsing error (invalid input sequence), -2 if output buffer is
+ * not large enough */
+static int p2p_sd_dns_uncompress(char *buf, size_t buf_len, const u8 *msg,
+                                size_t msg_len, size_t offset)
+{
+       /* 27-octet in-memory packet from P2P specification */
+       const char *prefix = "\x04_tcp\x05local\x00\x00\x0C\x00\x01"
+               "\x04_udp\xC0\x11\x00\x0C\x00\x01";
+       u8 *tmp, *end, *spos;
+       char *upos, *uend;
+       int ret = 0;
+
+       if (buf_len < 2)
+               return -1;
+       if (offset > msg_len)
+               return -1;
+
+       tmp = os_malloc(DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN + msg_len);
+       if (tmp == NULL)
+               return -1;
+       spos = tmp + DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN;
+       end = spos + msg_len;
+       spos += offset;
+
+       os_memset(tmp, 0, DNS_HEADER_LEN);
+       os_memcpy(tmp + DNS_HEADER_LEN, prefix, P2P_SD_IN_MEMORY_LEN);
+       os_memcpy(tmp + DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN, msg, msg_len);
+
+       upos = buf;
+       uend = buf + buf_len;
+
+       ret = p2p_sd_dns_uncompress_label(&upos, uend, tmp, &spos, end);
+       if (ret) {
+               os_free(tmp);
+               return ret;
+       }
+
+       if (upos == buf) {
+               upos[0] = '.';
+               upos[1] = '\0';
+       } else if (upos[-1] == '.')
+               upos[-1] = '\0';
+
+       os_free(tmp);
+       return 0;
+}
+
+
 static struct p2p_srv_bonjour *
 wpas_p2p_service_get_bonjour(struct wpa_supplicant *wpa_s,
                             const struct wpabuf *query)
@@ -1358,13 +1484,40 @@ static void wpas_sd_all_bonjour(struct wpa_supplicant *wpa_s,
 }
 
 
+static int match_bonjour_query(struct p2p_srv_bonjour *bsrv, const u8 *query,
+                              size_t query_len)
+{
+       char str_rx[256], str_srv[256];
+
+       if (query_len < 3 || wpabuf_len(bsrv->query) < 3)
+               return 0; /* Too short to include DNS Type and Version */
+       if (os_memcmp(query + query_len - 3,
+                     wpabuf_head_u8(bsrv->query) + wpabuf_len(bsrv->query) - 3,
+                     3) != 0)
+               return 0; /* Mismatch in DNS Type or Version */
+       if (query_len == wpabuf_len(bsrv->query) &&
+           os_memcmp(query, wpabuf_head(bsrv->query), query_len - 3) == 0)
+               return 1; /* Binary match */
+
+       if (p2p_sd_dns_uncompress(str_rx, sizeof(str_rx), query, query_len - 3,
+                                 0))
+               return 0; /* Failed to uncompress query */
+       if (p2p_sd_dns_uncompress(str_srv, sizeof(str_srv),
+                                 wpabuf_head(bsrv->query),
+                                 wpabuf_len(bsrv->query) - 3, 0))
+               return 0; /* Failed to uncompress service */
+
+       return os_strcmp(str_rx, str_srv) == 0;
+}
+
+
 static void wpas_sd_req_bonjour(struct wpa_supplicant *wpa_s,
                                struct wpabuf *resp, u8 srv_trans_id,
                                const u8 *query, size_t query_len)
 {
        struct p2p_srv_bonjour *bsrv;
-       struct wpabuf buf;
        u8 *len_pos;
+       int matches = 0;
 
        wpa_hexdump_ascii(MSG_DEBUG, "P2P: SD Request for Bonjour",
                          query, query_len);
@@ -1380,39 +1533,52 @@ static void wpas_sd_req_bonjour(struct wpa_supplicant *wpa_s,
                return;
        }
 
-       if (wpabuf_tailroom(resp) < 5)
-               return;
-       /* Length (to be filled) */
-       len_pos = wpabuf_put(resp, 2);
-       wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
-       wpabuf_put_u8(resp, srv_trans_id);
+       dl_list_for_each(bsrv, &wpa_s->global->p2p_srv_bonjour,
+                        struct p2p_srv_bonjour, list) {
+               if (!match_bonjour_query(bsrv, query, query_len))
+                       continue;
+
+               if (wpabuf_tailroom(resp) <
+                   5 + query_len + wpabuf_len(bsrv->resp))
+                       return;
+
+               matches++;
 
-       wpabuf_set(&buf, query, query_len);
-       bsrv = wpas_p2p_service_get_bonjour(wpa_s, &buf);
-       if (bsrv == NULL) {
+               /* Length (to be filled) */
+               len_pos = wpabuf_put(resp, 2);
+               wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
+               wpabuf_put_u8(resp, srv_trans_id);
+
+               /* Status Code */
+               wpabuf_put_u8(resp, P2P_SD_SUCCESS);
+               wpa_hexdump_ascii(MSG_DEBUG, "P2P: Matching Bonjour service",
+                                 wpabuf_head(bsrv->resp),
+                                 wpabuf_len(bsrv->resp));
+
+               /* Response Data */
+               wpabuf_put_data(resp, query, query_len); /* Key */
+               wpabuf_put_buf(resp, bsrv->resp); /* Value */
+
+               WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
+       }
+
+       if (matches == 0) {
                wpa_printf(MSG_DEBUG, "P2P: Requested Bonjour service not "
                           "available");
+               if (wpabuf_tailroom(resp) < 5)
+                       return;
+
+               /* Length (to be filled) */
+               len_pos = wpabuf_put(resp, 2);
+               wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
+               wpabuf_put_u8(resp, srv_trans_id);
 
                /* Status Code */
                wpabuf_put_u8(resp, P2P_SD_REQUESTED_INFO_NOT_AVAILABLE);
                /* Response Data: empty */
                WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos -
                             2);
-               return;
-       }
-
-       /* Status Code */
-       wpabuf_put_u8(resp, P2P_SD_SUCCESS);
-       wpa_hexdump_ascii(MSG_DEBUG, "P2P: Matching Bonjour service",
-                         wpabuf_head(bsrv->resp), wpabuf_len(bsrv->resp));
-
-       if (wpabuf_tailroom(resp) >=
-           wpabuf_len(bsrv->query) + wpabuf_len(bsrv->resp)) {
-               /* Response Data */
-               wpabuf_put_buf(resp, bsrv->query); /* Key */
-               wpabuf_put_buf(resp, bsrv->resp); /* Value */
        }
-       WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
 }
 
 
@@ -1973,14 +2139,6 @@ int wpas_p2p_service_add_bonjour(struct wpa_supplicant *wpa_s,
 {
        struct p2p_srv_bonjour *bsrv;
 
-       bsrv = wpas_p2p_service_get_bonjour(wpa_s, query);
-       if (bsrv) {
-               wpabuf_free(query);
-               wpabuf_free(bsrv->resp);
-               bsrv->resp = resp;
-               return 0;
-       }
-
        bsrv = os_zalloc(sizeof(*bsrv));
        if (bsrv == NULL)
                return -1;
@@ -2185,18 +2343,15 @@ static void wpas_prov_disc_fail(void *ctx, const u8 *peer,
                return;
        }
 
-#ifdef ANDROID_P2P
-       /* If provision discovery failed it is safe to cancel the timer here and
-        * also do not start the join */
-       if (wpa_s->pending_pd_before_join &&
-           (os_memcmp(peer, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
-            os_memcmp(peer, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0)) {
+       if (status == P2P_PROV_DISC_TIMEOUT_JOIN) {
                wpa_s->pending_pd_before_join = 0;
-               wpa_printf(MSG_DEBUG, "P2P: Do not Start pending "
-                          "join-existing-group operation");
-               eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s, NULL);
+               wpa_printf(MSG_DEBUG, "P2P: Starting pending "
+                          "join-existing-group operation (no ACK for PD "
+                          "Req attempts)");
+               wpas_p2p_join_start(wpa_s);
+               return;
        }
-#endif /* ANDROID_P2P */
+
        wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
                " p2p_dev_addr=" MACSTR " status=%d",
                MAC2STR(peer), status);
@@ -2327,6 +2482,7 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
                        wpas_p2p_group_add_persistent(
                                wpa_s, s, go, go ? op_freq : 0, 0);
                } else if (bssid) {
+                       wpa_s->user_initiated_pd = 0;
                        wpas_p2p_join(wpa_s, bssid, go_dev_addr,
                                      wpa_s->p2p_wps_method, 0);
                }
@@ -2839,6 +2995,8 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
 
        p2p.p2p_intra_bss = wpa_s->conf->p2p_intra_bss;
 
+       p2p.max_listen = wpa_s->max_remain_on_chan;
+
 #ifdef ANDROID_P2P
        if(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) {
                p2p.p2p_concurrency = P2P_MULTI_CHANNEL_CONCURRENT;
@@ -2888,7 +3046,6 @@ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s)
        wpa_s->go_params = NULL;
        eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
        eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
-       eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s, NULL);
        wpa_s->p2p_long_listen = 0;
        eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
        eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
@@ -2949,6 +3106,8 @@ void wpas_p2p_deinit_global(struct wpa_global *global)
 
 static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s)
 {
+       if (wpa_s->conf->p2p_no_group_iface)
+               return 0; /* separate interface disabled per configuration */
        if (wpa_s->drv_flags &
            (WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE |
             WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P))
@@ -2969,7 +3128,7 @@ static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s,
                                 enum p2p_wps_method wps_method,
                                 int go_intent, const u8 *own_interface_addr,
                                 unsigned int force_freq, int persistent_group,
-                                struct wpa_ssid *ssid)
+                                struct wpa_ssid *ssid, unsigned int pref_freq)
 {
        if (persistent_group && wpa_s->conf->persistent_reconnect)
                persistent_group = 2;
@@ -2991,7 +3150,7 @@ static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s,
                           go_intent, own_interface_addr, force_freq,
                           persistent_group, ssid ? ssid->ssid : NULL,
                           ssid ? ssid->ssid_len : 0,
-                          wpa_s->p2p_pd_before_go_neg);
+                          wpa_s->p2p_pd_before_go_neg, pref_freq);
 }
 
 
@@ -3000,7 +3159,7 @@ static int wpas_p2p_auth_go_neg(struct wpa_supplicant *wpa_s,
                                enum p2p_wps_method wps_method,
                                int go_intent, const u8 *own_interface_addr,
                                unsigned int force_freq, int persistent_group,
-                               struct wpa_ssid *ssid)
+                               struct wpa_ssid *ssid, unsigned int pref_freq)
 {
        if (persistent_group && wpa_s->conf->persistent_reconnect)
                persistent_group = 2;
@@ -3011,7 +3170,7 @@ 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, ssid ? ssid->ssid : NULL,
-                            ssid ? ssid->ssid_len : 0);
+                            ssid ? ssid->ssid_len : 0, pref_freq);
 }
 
 
@@ -3038,21 +3197,6 @@ static void wpas_p2p_check_join_scan_limit(struct wpa_supplicant *wpa_s)
 }
 
 
-static void wpas_p2p_pd_before_join_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-       struct wpa_supplicant *wpa_s = eloop_ctx;
-       if (!wpa_s->pending_pd_before_join)
-               return;
-       /*
-        * Provision Discovery Response may have been lost - try to connect
-        * anyway since we do not need any information from this PD.
-        */
-       wpa_printf(MSG_DEBUG, "P2P: PD timeout for join-existing-group - "
-                  "try to connect anyway");
-       wpas_p2p_join_start(wpa_s);
-}
-
-
 static int wpas_check_freq_conflict(struct wpa_supplicant *wpa_s, int freq)
 {
        struct wpa_supplicant *iface;
@@ -3170,7 +3314,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
                if (p2p_prov_disc_req(wpa_s->global->p2p,
                                      wpa_s->pending_join_dev_addr,
                                      wpa_s->pending_pd_config_methods, join,
-                                     0) < 0) {
+                                     0, wpa_s->user_initiated_pd) < 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",
@@ -3280,25 +3424,13 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
 
                if (p2p_prov_disc_req(wpa_s->global->p2p,
                                      wpa_s->pending_join_dev_addr, method, 1,
-                                     freq) < 0) {
+                                     freq, wpa_s->user_initiated_pd) < 0) {
                        wpa_printf(MSG_DEBUG, "P2P: Failed to send Provision "
                                   "Discovery Request before joining an "
                                   "existing group");
                        wpa_s->pending_pd_before_join = 0;
                        goto start;
                }
-
-               /*
-                * Actual join operation will be started from the Action frame
-                * TX status callback (if no ACK is received) or when the
-                * Provision Discovery Response is received. Use a short
-                * timeout as a backup mechanism should the Provision Discovery
-                * Response be lost for any reason.
-                */
-               eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s,
-                                    NULL);
-               eloop_register_timeout(2, 0, wpas_p2p_pd_before_join_timeout,
-                                      wpa_s, NULL);
                return;
        }
 
@@ -3425,7 +3557,6 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
        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);
        if (group == NULL)
                return -1;
@@ -3499,7 +3630,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                     int go_intent, int freq, int persistent_id, int pd,
                     int ht40)
 {
-       int force_freq = 0, oper_freq = 0;
+       int force_freq = 0, pref_freq = 0, oper_freq = 0;
        u8 bssid[ETH_ALEN];
        int ret = 0;
        enum wpa_driver_if_type iftype;
@@ -3565,6 +3696,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                                   wpa_s->p2p_auto_started.sec,
                                   wpa_s->p2p_auto_started.usec);
                }
+               wpa_s->user_initiated_pd = 1;
                if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method,
                                  auto_join) < 0)
                        return -1;
@@ -3612,6 +3744,13 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                           "(%u MHz) not available for P2P - try to use "
                           "another channel", oper_freq);
                force_freq = 0;
+       } else if (oper_freq > 0 &&
+                  (wpa_s->drv_flags &
+                   WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+               wpa_printf(MSG_DEBUG, "P2P: Trying to prefer the channel we "
+                          "are already using (%u MHz) on another interface",
+                          oper_freq);
+               pref_freq = oper_freq;
        } else if (oper_freq > 0) {
                wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
                           "channel we are already using (%u MHz) on another "
@@ -3639,15 +3778,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, ssid) <
-                   0)
+                                        force_freq, persistent_group, ssid,
+                                        pref_freq) < 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, ssid) < 0) {
+                                 persistent_group, ssid, pref_freq) < 0) {
                if (wpa_s->create_p2p_iface)
                        wpas_p2p_remove_pending_group_interface(wpa_s);
                return -1;
@@ -3899,7 +4038,7 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
 
        /* Make sure we are not running find during connection establishment */
        wpa_printf(MSG_DEBUG, "P2P: Stop any on-going P2P FIND");
-       wpas_p2p_stop_find(wpa_s);
+       wpas_p2p_stop_find_oper(wpa_s);
 
        if (freq == 2) {
                wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 2.4 GHz "
@@ -4030,7 +4169,7 @@ 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);
+       wpas_p2p_stop_find_oper(wpa_s);
 
        wpa_s->p2p_fallback_to_go_neg = 0;
 
@@ -4044,6 +4183,9 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
                return -1;
 
        params.role_go = 1;
+       params.psk_set = ssid->psk_set;
+       if (params.psk_set)
+               os_memcpy(params.psk, ssid->psk, sizeof(params.psk));
        if (ssid->passphrase == NULL ||
            os_strlen(ssid->passphrase) >= sizeof(params.passphrase)) {
                wpa_printf(MSG_DEBUG, "P2P: Invalid passphrase in persistent "
@@ -4253,7 +4395,7 @@ int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 
        return p2p_prov_disc_req(wpa_s->global->p2p, peer_addr,
                                 config_methods, use == WPAS_P2P_PD_FOR_JOIN,
-                                0);
+                                0, 1);
 }
 
 
@@ -4299,7 +4441,7 @@ int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
 }
 
 
-void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s)
+static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s)
 {
        wpas_p2p_clear_pending_action_tx(wpa_s);
        wpa_s->p2p_long_listen = 0;
@@ -4309,12 +4451,20 @@ void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s)
 
        if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
                wpa_drv_p2p_stop_find(wpa_s);
-               return;
+               return 1;
        }
 
        if (wpa_s->global->p2p)
                p2p_stop_find(wpa_s->global->p2p);
 
+       return 0;
+}
+
+
+void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s)
+{
+       if (wpas_p2p_stop_find_oper(wpa_s) > 0)
+               return;
        wpas_p2p_remove_pending_group_interface(wpa_s);
 }
 
@@ -4743,8 +4893,15 @@ int wpas_p2p_ext_listen(struct wpa_supplicant *wpa_s, unsigned int period,
 
 static int wpas_p2p_is_client(struct wpa_supplicant *wpa_s)
 {
-       return wpa_s->current_ssid != NULL &&
-               wpa_s->current_ssid->p2p_group &&
+       if (wpa_s->current_ssid == NULL) {
+               /*
+                * current_ssid can be cleared when P2P client interface gets
+                * disconnected, so assume this interface was used as P2P
+                * client.
+                */
+               return 1;
+       }
+       return wpa_s->current_ssid->p2p_group &&
                wpa_s->current_ssid->mode == WPAS_MODE_INFRA;
 }
 
@@ -5366,7 +5523,6 @@ 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;
@@ -5438,7 +5594,8 @@ unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s)
 }
 
 #ifdef ANDROID_P2P
-int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq)
+int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq,
+       struct wpa_ssid *ssid)
 {
        struct wpa_supplicant *iface = NULL;
        struct p2p_data *p2p = wpa_s->global->p2p;
@@ -5464,17 +5621,32 @@ int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq)
                        /* If GO cannot be moved or if the conflicting interface is a
                         * P2P Client, remove the interface depending up on the connection
                         * priority */
-                       if (!wpas_is_p2p_prioritized(wpa_s)) {
+                       if(!wpas_is_p2p_prioritized(iface)) {
                                /* STA connection has priority over existing
                                 * P2P connection. So remove the interface */
-                               wpa_printf(MSG_DEBUG, "P2P: Removing P2P connection due to Single channel "
+                               wpa_printf(MSG_DEBUG, "P2P: Removing P2P connection due to Single channel"
                                                "concurrent mode frequency conflict");
                                wpas_p2p_group_delete(iface, P2P_GROUP_REMOVAL_FREQ_CONFLICT);
+                               /* If connection in progress is p2p connection, do not proceed for the connection */
+                               if (wpa_s == iface)
+                                       return -1;
+                               else
+                                       /* If connection in progress is STA connection, proceed for the connection */
+                                       return 0;
                        } else {
-                               /* Existing connection has the priority. Disable the newly
-                                * selected network and let the application know about it.
-                                */
-                               return -1;
+                               /* P2p connection has priority, disable the STA network*/
+                               wpa_supplicant_disable_network(wpa_s->global->ifaces, ssid);
+                               wpa_msg(wpa_s->global->ifaces, MSG_INFO, WPA_EVENT_FREQ_CONFLICT
+                                       " id=%d", ssid->id);
+                               os_memset(wpa_s->global->ifaces->pending_bssid, 0, ETH_ALEN);
+                               if (wpa_s == iface) {
+                                       /* p2p connection is in progress, continue connecting...*/
+                                       return 0;
+                               }
+                               else {
+                                       /* STA connection is in progress, do not allow to continue */
+                                       return -1;
+                               }
                        }
                }
        }
index 6e4cc1d..a27c1b6 100644 (file)
@@ -28,7 +28,7 @@ void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
                                          unsigned int freq);
 #ifdef ANDROID_P2P
 int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s,
-                                          int freq);
+                                          int freq, struct wpa_ssid *ssid);
 #endif
 int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname);
 int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
index 62b7538..3503e65 100644 (file)
@@ -38,12 +38,6 @@ struct preauth_test_data {
 };
 
 
-static void _wpa_supplicant_disassociate(void *wpa_s, int reason_code)
-{
-       wpa_supplicant_disassociate(wpa_s, reason_code);
-}
-
-
 static void _wpa_supplicant_deauthenticate(void *wpa_s, int reason_code)
 {
        wpa_supplicant_deauthenticate(wpa_s, reason_code);
@@ -238,7 +232,6 @@ static void wpa_init_conf(struct wpa_supplicant *wpa_s, const char *ifname)
        ctx->set_state = _wpa_supplicant_set_state;
        ctx->get_state = _wpa_supplicant_get_state;
        ctx->deauthenticate = _wpa_supplicant_deauthenticate;
-       ctx->disassociate = _wpa_supplicant_disassociate;
        ctx->set_key = wpa_supplicant_set_key;
        ctx->get_network_ctx = wpa_supplicant_get_network_ctx;
        ctx->get_bssid = wpa_supplicant_get_bssid;
index 0f6433b..048e6d0 100644 (file)
@@ -66,7 +66,8 @@ static int wpas_wps_in_use(struct wpa_supplicant *wpa_s,
        }
 
 #ifdef CONFIG_P2P
-       if (!wpa_s->global->p2p_disabled && wpa_s->global->p2p) {
+       if (!wpa_s->global->p2p_disabled && wpa_s->global->p2p &&
+           !wpa_s->conf->p2p_disabled) {
                wpa_s->wps->dev.p2p = 1;
                if (!wps) {
                        wps = 1;
@@ -439,11 +440,78 @@ static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
 }
 
 
+#ifdef CONFIG_P2P
+
+/*
+ * Check whether there are any enabled networks or credentials that could be
+ * used for a non-P2P connection.
+ */
+static int non_p2p_network_enabled(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_ssid *ssid;
+
+       for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+               if (wpas_network_disabled(wpa_s, ssid))
+                       continue;
+               if (!ssid->p2p_group)
+                       return 1;
+       }
+
+       if (wpa_s->conf->cred && wpa_s->conf->interworking &&
+           wpa_s->conf->auto_interworking)
+               return 1;
+
+       return 0;
+}
+
+
+/*
+ * Find the operating frequency of any other virtual interface that is using
+ * the same radio concurrently.
+ */
+static int shared_vif_oper_freq(struct wpa_supplicant *wpa_s)
+{
+       const char *rn, *rn2;
+       struct wpa_supplicant *ifs;
+       u8 bssid[ETH_ALEN];
+
+       if (!wpa_s->driver->get_radio_name)
+               return -1;
+
+       rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
+       if (rn == NULL || rn[0] == '\0')
+               return -1;
+
+       for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
+               if (ifs == wpa_s || !ifs->driver->get_radio_name)
+                       continue;
+
+               rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
+               if (!rn2 || os_strcmp(rn, rn2) != 0)
+                       continue;
+
+               if (ifs->current_ssid == NULL || ifs->assoc_freq == 0)
+                       continue;
+
+               if (ifs->current_ssid->mode == WPAS_MODE_AP ||
+                   ifs->current_ssid->mode == WPAS_MODE_P2P_GO)
+                       return ifs->current_ssid->frequency;
+               if (wpa_drv_get_bssid(ifs, bssid) == 0)
+                       return ifs->assoc_freq;
+       }
+
+       return 0;
+}
+
+#endif /* CONFIG_P2P */
+
+
 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;
+       enum scan_req_type scan_req = NORMAL_SCAN_REQ;
+       int ret;
        struct wpabuf *extra_ie = NULL;
        struct wpa_driver_scan_params params;
        struct wpa_driver_scan_params *scan_params;
@@ -455,7 +523,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
                return;
        }
 
-       if (wpa_s->disconnected && !wpa_s->scan_req) {
+       if (wpa_s->disconnected && wpa_s->scan_req == NORMAL_SCAN_REQ) {
                wpa_dbg(wpa_s, MSG_DEBUG, "Disconnected - do not scan");
                wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
                return;
@@ -468,7 +536,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
        }
 #endif
        if (!wpa_supplicant_enabled_networks(wpa_s) &&
-           !wpa_s->scan_req) {
+           wpa_s->scan_req == NORMAL_SCAN_REQ) {
                wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan");
                wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
 #ifdef CONFIG_P2P
@@ -516,7 +584,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
        }
 
        scan_req = wpa_s->scan_req;
-       wpa_s->scan_req = 0;
+       wpa_s->scan_req = NORMAL_SCAN_REQ;
 
        os_memset(&params, 0, sizeof(params));
 
@@ -533,7 +601,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
                goto scan;
        }
 
-       if (scan_req != 2 && wpa_s->connect_without_scan) {
+       if (scan_req != MANUAL_SCAN_REQ && wpa_s->connect_without_scan) {
                for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
                        if (ssid == wpa_s->connect_without_scan)
                                break;
@@ -571,7 +639,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
                }
        }
 
-       if (scan_req != 2 && wpa_s->conf->ap_scan == 2) {
+       if (scan_req != MANUAL_SCAN_REQ && wpa_s->conf->ap_scan == 2) {
                wpa_s->connect_without_scan = NULL;
                wpa_s->prev_scan_wildcard = 0;
                wpa_supplicant_assoc_try(wpa_s, ssid);
@@ -698,6 +766,35 @@ ssid_list_set:
        scan_params = &params;
 
 scan:
+#ifdef CONFIG_P2P
+       /*
+        * If the driver does not support multi-channel concurrency and a
+        * virtual interface that shares the same radio with the wpa_s interface
+        * is operating there may not be need to scan other channels apart from
+        * the current operating channel on the other virtual interface. Filter
+        * out other channels in case we are trying to find a connection for a
+        * station interface when we are not configured to prefer station
+        * connection and a concurrent operation is already in process.
+        */
+       if (wpa_s->scan_for_connection && scan_req == NORMAL_SCAN_REQ &&
+           !scan_params->freqs && !params.freqs &&
+           wpas_is_p2p_prioritized(wpa_s) &&
+           !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) &&
+           wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE &&
+           non_p2p_network_enabled(wpa_s)) {
+               int freq = shared_vif_oper_freq(wpa_s);
+               if (freq > 0) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only the current "
+                               "operating channel (%d MHz) since driver does "
+                               "not support multi-channel concurrency", freq);
+                       params.freqs = os_zalloc(sizeof(int) * 2);
+                       if (params.freqs)
+                               params.freqs[0] = freq;
+                       scan_params->freqs = params.freqs;
+               }
+       }
+#endif /* CONFIG_P2P */
+
        ret = wpa_supplicant_trigger_scan(wpa_s, scan_params);
 
        wpabuf_free(extra_ie);
@@ -706,15 +803,13 @@ scan:
 
        if (ret) {
                wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan");
-#ifdef ANDROID_P2P
-               /* Restore back the wpa_s->scan_req if we failed the scan because of any reason */
-               wpa_msg(wpa_s, MSG_DEBUG, "Restoring back the wpa_s->scan_req "
-                       "to the original value %d", scan_req);
-               wpa_s->scan_req = scan_req;
-#endif
                if (prev_state != wpa_s->wpa_state)
                        wpa_supplicant_set_state(wpa_s, prev_state);
+               /* Restore scan_req since we will try to scan again */
+               wpa_s->scan_req = scan_req;
                wpa_supplicant_req_scan(wpa_s, 1, 0);
+       } else {
+               wpa_s->scan_for_connection = 0;
        }
 }
 
index b09e5f1..e273cb3 100644 (file)
@@ -39,8 +39,50 @@ static void sme_stop_sa_query(struct wpa_supplicant *wpa_s);
 #endif /* CONFIG_IEEE80211W */
 
 
-void sme_authenticate(struct wpa_supplicant *wpa_s,
-                     struct wpa_bss *bss, struct wpa_ssid *ssid)
+#ifdef CONFIG_SAE
+
+static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s)
+{
+       struct wpabuf *buf;
+
+       buf = wpabuf_alloc(4 + 2);
+       if (buf == NULL)
+               return NULL;
+
+       wpabuf_put_le16(buf, 1); /* Transaction seq# */
+       wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+       wpabuf_put_le16(buf, 19); /* Finite Cyclic Group */
+       /* TODO: Anti-Clogging Token (if requested) */
+       /* TODO: Scalar */
+       /* TODO: Element */
+
+       return buf;
+}
+
+
+static struct wpabuf * sme_auth_build_sae_confirm(struct wpa_supplicant *wpa_s)
+{
+       struct wpabuf *buf;
+
+       buf = wpabuf_alloc(4 + 2);
+       if (buf == NULL)
+               return NULL;
+
+       wpabuf_put_le16(buf, 2); /* Transaction seq# */
+       wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+       wpabuf_put_le16(buf, wpa_s->sme.sae_send_confirm);
+       wpa_s->sme.sae_send_confirm++;
+       /* TODO: Confirm */
+
+       return buf;
+}
+
+#endif /* CONFIG_SAE */
+
+
+static void sme_send_authentication(struct wpa_supplicant *wpa_s,
+                                   struct wpa_bss *bss, struct wpa_ssid *ssid,
+                                   int start)
 {
        struct wpa_driver_auth_params params;
        struct wpa_ssid *old_ssid;
@@ -51,6 +93,7 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
        const u8 *md = NULL;
 #endif /* CONFIG_IEEE80211R */
        int i, bssid_changed;
+       struct wpabuf *resp = NULL;
 
        if (bss == NULL) {
                wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for "
@@ -95,6 +138,21 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
                wpa_dbg(wpa_s, MSG_DEBUG, "Overriding auth_alg selection: "
                        "0x%x", params.auth_alg);
        }
+#ifdef CONFIG_SAE
+       if (wpa_key_mgmt_sae(ssid->key_mgmt)) {
+               const u8 *rsn;
+               struct wpa_ie_data ied;
+
+               rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+               if (rsn &&
+                   wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0) {
+                       if (wpa_key_mgmt_sae(ied.key_mgmt)) {
+                               wpa_dbg(wpa_s, MSG_DEBUG, "Using SAE auth_alg");
+                               params.auth_alg = WPA_AUTH_ALG_SAE;
+                       }
+               }
+       }
+#endif /* CONFIG_SAE */
 
        for (i = 0; i < NUM_WEP_KEYS; i++) {
                if (ssid->wep_key_len[i])
@@ -113,7 +171,9 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
             wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
            wpa_key_mgmt_wpa(ssid->key_mgmt)) {
                int try_opportunistic;
-               try_opportunistic = ssid->proactive_key_caching &&
+               try_opportunistic = (ssid->proactive_key_caching < 0 ?
+                                    wpa_s->conf->okc :
+                                    ssid->proactive_key_caching) &&
                        (ssid->proto & WPA_PROTO_RSN);
                if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
                                            wpa_s->current_ssid,
@@ -203,8 +263,9 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_IEEE80211R */
 
 #ifdef CONFIG_IEEE80211W
-       wpa_s->sme.mfp = ssid->ieee80211w;
-       if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+       wpa_s->sme.mfp = ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+               wpa_s->conf->pmf : ssid->ieee80211w;
+       if (wpa_s->sme.mfp != NO_MGMT_FRAME_PROTECTION) {
                const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
                struct wpa_ie_data _ie;
                if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &_ie) == 0 &&
@@ -265,6 +326,20 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
        }
 #endif /* CONFIG_INTERWORKING */
 
+#ifdef CONFIG_SAE
+       if (params.auth_alg == WPA_AUTH_ALG_SAE) {
+               if (start)
+                       resp = sme_auth_build_sae_commit(wpa_s);
+               else
+                       resp = sme_auth_build_sae_confirm(wpa_s);
+               if (resp == NULL)
+                       return;
+               params.sae_data = wpabuf_head(resp);
+               params.sae_data_len = wpabuf_len(resp);
+               wpa_s->sme.sae_state = start ? SME_SAE_COMMIT : SME_SAE_CONFIRM;
+       }
+#endif /* CONFIG_SAE */
+
        wpa_supplicant_cancel_sched_scan(wpa_s);
        wpa_supplicant_cancel_scan(wpa_s);
 
@@ -287,6 +362,7 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
                        "driver failed");
                wpas_connection_failed(wpa_s, bss->bssid);
                wpa_supplicant_mark_disassoc(wpa_s);
+               wpabuf_free(resp);
                return;
        }
 
@@ -297,7 +373,89 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
         * Association will be started based on the authentication event from
         * the driver.
         */
+
+       wpabuf_free(resp);
+}
+
+
+void sme_authenticate(struct wpa_supplicant *wpa_s,
+                     struct wpa_bss *bss, struct wpa_ssid *ssid)
+{
+       wpa_s->sme.sae_state = SME_SAE_INIT;
+       wpa_s->sme.sae_send_confirm = 0;
+       sme_send_authentication(wpa_s, bss, ssid, 1);
+}
+
+
+#ifdef CONFIG_SAE
+
+static int sme_sae_process_commit(struct wpa_supplicant *wpa_s, const u8 *data,
+                                 size_t len)
+{
+       /* Check Finite Cyclic Group */
+       if (len < 2)
+               return -1;
+       if (WPA_GET_LE16(data) != 19) {
+               wpa_printf(MSG_DEBUG, "SAE: Unsupported Finite Cyclic Group %u",
+                          WPA_GET_LE16(data));
+               return -1;
+       }
+
+       /* TODO */
+
+       return 0;
+}
+
+
+static int sme_sae_process_confirm(struct wpa_supplicant *wpa_s, const u8 *data,
+                                  size_t len)
+{
+       u16 rc;
+
+       if (len < 2)
+               return -1;
+       rc = WPA_GET_LE16(data);
+       wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", rc);
+
+       /* TODO */
+       return 0;
+}
+
+
+static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
+                       u16 status_code, const u8 *data, size_t len)
+{
+       wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE authentication transaction %u "
+               "status code %u", auth_transaction, status_code);
+       wpa_hexdump(MSG_DEBUG, "SME: SAE fields", data, len);
+
+       if (status_code != WLAN_STATUS_SUCCESS)
+               return -1;
+
+       if (auth_transaction == 1) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE commit");
+               if (wpa_s->current_bss == NULL ||
+                   wpa_s->current_ssid == NULL)
+                       return -1;
+               if (wpa_s->sme.sae_state != SME_SAE_COMMIT)
+                       return -1;
+               if (sme_sae_process_commit(wpa_s, data, len) < 0)
+                       return -1;
+               sme_send_authentication(wpa_s, wpa_s->current_bss,
+                                       wpa_s->current_ssid, 0);
+               return 0;
+       } else if (auth_transaction == 2) {
+               wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE confirm");
+               if (wpa_s->sme.sae_state != SME_SAE_CONFIRM)
+                       return -1;
+               if (sme_sae_process_confirm(wpa_s, data, len) < 0)
+                       return -1;
+               return 1;
+       }
+
+       return -1;
 }
+#endif /* CONFIG_SAE */
 
 
 void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
@@ -324,14 +482,30 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
        }
 
        wpa_dbg(wpa_s, MSG_DEBUG, "SME: Authentication response: peer=" MACSTR
-               " auth_type=%d status_code=%d",
+               " auth_type=%d auth_transaction=%d status_code=%d",
                MAC2STR(data->auth.peer), data->auth.auth_type,
-               data->auth.status_code);
+               data->auth.auth_transaction, data->auth.status_code);
        wpa_hexdump(MSG_MSGDUMP, "SME: Authentication response IEs",
                    data->auth.ies, data->auth.ies_len);
 
        eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
 
+#ifdef CONFIG_SAE
+       if (data->auth.auth_type == WLAN_AUTH_SAE) {
+               int res;
+               res = sme_sae_auth(wpa_s, data->auth.auth_transaction,
+                                  data->auth.status_code, data->auth.ies,
+                                  data->auth.ies_len);
+               if (res < 0) {
+                       wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+                       wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+
+               }
+               if (res != 1)
+                       return;
+       }
+#endif /* CONFIG_SAE */
+
        if (data->auth.status_code != WLAN_STATUS_SUCCESS) {
                wpa_dbg(wpa_s, MSG_DEBUG, "SME: Authentication failed (status "
                        "code %d)", data->auth.status_code);
@@ -860,9 +1034,14 @@ void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable)
        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 */
+       /*
+        * Schedule OBSS scan if driver is using station SME in wpa_supplicant
+        * or it expects OBSS scan to be performed by wpa_supplicant.
+        */
+       if (!((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) ||
+             (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OBSS_SCAN)) ||
+           ssid == NULL || ssid->mode != IEEE80211_MODE_INFRA)
+               return;
 
        if (!wpa_s->hw.modes)
                return;
@@ -1012,7 +1191,9 @@ void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, const u8 *sa,
        if (wpa_s->wpa_state != WPA_COMPLETED)
                return;
        ssid = wpa_s->current_ssid;
-       if (ssid == NULL || ssid->ieee80211w == 0)
+       if (ssid == NULL ||
+           (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+            wpa_s->conf->pmf : ssid->ieee80211w) == NO_MGMT_FRAME_PROTECTION)
                return;
        if (os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0)
                return;
diff --git a/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in b/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in
new file mode 100644 (file)
index 0000000..76aba12
--- /dev/null
@@ -0,0 +1,13 @@
+[Unit]
+Description=WPA supplicant daemon (interface- and nl80211 driver-specific version)
+Requires=sys-subsystem-net-devices-%i.device
+After=sys-subsystem-net-devices-%i.device
+
+# NetworkManager users will probably want the dbus version instead.
+
+[Service]
+Type=simple
+ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-nl80211-%I.conf -Dnl80211 -i%I
+
+[Install]
+Alias=multi-user.target.wants/wpa_supplicant-nl80211@wlan0.service
diff --git a/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in b/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in
new file mode 100644 (file)
index 0000000..ff384ae
--- /dev/null
@@ -0,0 +1,13 @@
+[Unit]
+Description=WPA supplicant daemon (interface- and wired driver-specific version)
+Requires=sys-subsystem-net-devices-%i.device
+After=sys-subsystem-net-devices-%i.device
+
+# NetworkManager users will probably want the dbus version instead.
+
+[Service]
+Type=simple
+ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-wired-%I.conf -Dwired -i%I
+
+[Install]
+Alias=multi-user.target.wants/wpa_supplicant-wired@wlan0.service
diff --git a/wpa_supplicant/systemd/wpa_supplicant.service.arg.in b/wpa_supplicant/systemd/wpa_supplicant.service.arg.in
new file mode 100644 (file)
index 0000000..c215567
--- /dev/null
@@ -0,0 +1,13 @@
+[Unit]
+Description=WPA supplicant daemon (interface-specific version)
+Requires=sys-subsystem-net-devices-%i.device
+After=sys-subsystem-net-devices-%i.device
+
+# NetworkManager users will probably want the dbus version instead.
+
+[Service]
+Type=simple
+ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-%I.conf -i%I
+
+[Install]
+Alias=multi-user.target.wants/wpa_supplicant@wlan0.service
diff --git a/wpa_supplicant/systemd/wpa_supplicant.service.in b/wpa_supplicant/systemd/wpa_supplicant.service.in
new file mode 100644 (file)
index 0000000..4351ad8
--- /dev/null
@@ -0,0 +1,11 @@
+[Unit]
+Description=WPA supplicant
+
+[Service]
+Type=dbus
+BusName=fi.epitest.hostap.WPASupplicant
+ExecStart=@BINDIR@/wpa_supplicant -u
+
+[Install]
+WantedBy=multi-user.target
+Alias=dbus-fi.epitest.hostap.WPASupplicant.service
diff --git a/wpa_supplicant/utils/log2pcap.py b/wpa_supplicant/utils/log2pcap.py
new file mode 100755 (executable)
index 0000000..65e2fa1
--- /dev/null
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2012, Intel Corporation
+#
+# Author: Johannes Berg <johannes@sipsolutions.net>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import sys, struct, re
+
+def write_pcap_header(pcap_file):
+    pcap_file.write(
+        struct.pack('<IHHIIII',
+                    0xa1b2c3d4, 2, 4, 0, 0, 65535,
+                    105 # raw 802.11 format
+                    ))
+
+def pcap_addpacket(pcap_file, ts, data):
+    # ts in seconds, float
+    pcap_file.write(struct.pack('<IIII',
+        int(ts), int(1000000 * ts) % 1000000,
+        len(data), len(data)))
+    pcap_file.write(data)
+
+if __name__ == "__main__":
+    try:
+        input = sys.argv[1]
+        pcap = sys.argv[2]
+    except IndexError:
+        print "Usage: %s <log file> <pcap file>" % sys.argv[0]
+        sys.exit(2)
+
+    input_file = open(input, 'r')
+    pcap_file = open(pcap, 'w')
+    frame_re = re.compile(r'(([0-9]+.[0-9]{6}):\s*)?nl80211: MLME event frame - hexdump\(len=[0-9]*\):((\s*[0-9a-fA-F]{2})*)')
+
+    write_pcap_header(pcap_file)
+
+    for line in input_file:
+        m = frame_re.match(line)
+        if m is None:
+            continue
+        if m.group(2):
+            ts = float(m.group(2))
+        else:
+            ts = 0
+        hexdata = m.group(3)
+        hexdata = hexdata.split()
+        data = ''.join([chr(int(x, 16)) for x in hexdata])
+        pcap_addpacket(pcap_file, ts, data)
+
+    input_file.close()
+    pcap_file.close()
index 3986b9b..4e7c81c 100644 (file)
@@ -762,26 +762,6 @@ static int wpa_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
 }
 
 
-#ifdef CONFIG_WPS_OOB
-static int wpa_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-       if (argc != 3 && argc != 4) {
-               printf("Invalid WPS_OOB command: need three or four "
-                      "arguments:\n"
-                      "- DEV_TYPE: use 'ufd' or 'nfc'\n"
-                      "- PATH: path of OOB device like '/mnt'\n"
-                      "- METHOD: OOB method 'pin-e' or 'pin-r', "
-                      "'cred'\n"
-                      "- DEV_NAME: (only for NFC) device name like "
-                      "'pn531'\n");
-               return -1;
-       }
-
-       return wpa_cli_cmd(ctrl, "WPS_OOB", 3, argc, argv);
-}
-#endif /* CONFIG_WPS_OOB */
-
-
 #ifdef CONFIG_WPS_NFC
 
 static int wpa_cli_cmd_wps_nfc(struct wpa_ctrl *ctrl, int argc, char *argv[])
@@ -822,6 +802,72 @@ static int wpa_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
        return ret;
 }
 
+
+static int wpa_cli_cmd_nfc_get_handover_req(struct wpa_ctrl *ctrl, int argc,
+                                           char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_REQ", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl, int argc,
+                                           char *argv[])
+{
+       return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_SEL", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_nfc_rx_handover_req(struct wpa_ctrl *ctrl, int argc,
+                                          char *argv[])
+{
+       int ret;
+       char *buf;
+       size_t buflen;
+
+       if (argc != 1) {
+               printf("Invalid 'nfc_rx_handover_req' command - one argument "
+                      "is required.\n");
+               return -1;
+       }
+
+       buflen = 21 + os_strlen(argv[0]);
+       buf = os_malloc(buflen);
+       if (buf == NULL)
+               return -1;
+       os_snprintf(buf, buflen, "NFC_RX_HANDOVER_REQ %s", argv[0]);
+
+       ret = wpa_ctrl_command(ctrl, buf);
+       os_free(buf);
+
+       return ret;
+}
+
+
+static int wpa_cli_cmd_nfc_rx_handover_sel(struct wpa_ctrl *ctrl, int argc,
+                                          char *argv[])
+{
+       int ret;
+       char *buf;
+       size_t buflen;
+
+       if (argc != 1) {
+               printf("Invalid 'nfc_rx_handover_sel' command - one argument "
+                      "is required.\n");
+               return -1;
+       }
+
+       buflen = 21 + os_strlen(argv[0]);
+       buf = os_malloc(buflen);
+       if (buf == NULL)
+               return -1;
+       os_snprintf(buf, buflen, "NFC_RX_HANDOVER_SEL %s", argv[0]);
+
+       ret = wpa_ctrl_command(ctrl, buf);
+       os_free(buf);
+
+       return ret;
+}
+
 #endif /* CONFIG_WPS_NFC */
 
 
@@ -1330,7 +1376,7 @@ static int wpa_cli_cmd_set_network(struct wpa_ctrl *ctrl, int argc,
                return 0;
        }
 
-       if (argc != 3) {
+       if (argc < 3) {
                printf("Invalid SET_NETWORK command: needs three arguments\n"
                       "(network id, variable name, and value)\n");
                return -1;
@@ -2469,11 +2515,6 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
          "<PIN> = verify PIN checksum" },
        { "wps_cancel", wpa_cli_cmd_wps_cancel, NULL, cli_cmd_flag_none,
          "Cancels the pending WPS operation" },
-#ifdef CONFIG_WPS_OOB
-       { "wps_oob", wpa_cli_cmd_wps_oob, NULL,
-         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, wpa_cli_complete_bss,
          cli_cmd_flag_none,
@@ -2484,6 +2525,18 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
        { "wps_nfc_tag_read", wpa_cli_cmd_wps_nfc_tag_read, NULL,
          cli_cmd_flag_sensitive,
          "<hexdump of payload> = report read NFC tag with WPS data" },
+       { "nfc_get_handover_req", wpa_cli_cmd_nfc_get_handover_req, NULL,
+         cli_cmd_flag_none,
+         "<NDEF> <WPS> = create NFC handover request" },
+       { "nfc_get_handover_sel", wpa_cli_cmd_nfc_get_handover_sel, NULL,
+         cli_cmd_flag_none,
+         "<NDEF> <WPS> = create NFC handover select" },
+       { "nfc_rx_handover_req", wpa_cli_cmd_nfc_rx_handover_req, NULL,
+         cli_cmd_flag_none,
+         "<hexdump of payload> = report received NFC handover request" },
+       { "nfc_rx_handover_sel", wpa_cli_cmd_nfc_rx_handover_sel, NULL,
+         cli_cmd_flag_none,
+         "<hexdump of payload> = report received NFC handover select" },
 #endif /* CONFIG_WPS_NFC */
        { "wps_reg", wpa_cli_cmd_wps_reg, wpa_cli_complete_bss,
          cli_cmd_flag_sensitive,
index d8f3c44..3dcd7d6 100644 (file)
@@ -190,7 +190,7 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
                MAC2STR(bssid));
        wpa_blacklist_add(wpa_s, bssid);
        wpa_sm_notify_disassoc(wpa_s->wpa);
-       wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+       wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
        wpa_s->reassociate = 1;
 
        /*
@@ -470,6 +470,11 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
        os_free(wpa_s->bssid_filter);
        wpa_s->bssid_filter = NULL;
 
+       os_free(wpa_s->disallow_aps_bssid);
+       wpa_s->disallow_aps_bssid = NULL;
+       os_free(wpa_s->disallow_aps_ssid);
+       wpa_s->disallow_aps_ssid = NULL;
+
        wnm_bss_keep_alive_deinit(wpa_s);
 
        ext_password_deinit(wpa_s->ext_pw);
@@ -666,6 +671,7 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
                        ssid && ssid->id_str ? ssid->id_str : "");
 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
                wpas_clear_temp_disabled(wpa_s, ssid, 1);
+               wpa_s->extra_blacklist_count = 0;
                wpa_s->new_connection = 0;
                wpa_s->reassociated_connection = 1;
                wpa_drv_set_operstate(wpa_s, 1);
@@ -931,7 +937,9 @@ static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
 
 #ifdef CONFIG_IEEE80211W
        if (!(ie->capabilities & WPA_CAPABILITY_MFPC) &&
-           ssid->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) {
+           (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+            wpa_s->conf->pmf : ssid->ieee80211w) ==
+           MGMT_FRAME_PROTECTION_REQUIRED) {
                wpa_msg(wpa_s, MSG_INFO, "WPA: Driver associated with an AP "
                        "that does not support management frame protection - "
                        "reject");
@@ -1074,6 +1082,10 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
        }
 
        sel = ie.key_mgmt & ssid->key_mgmt;
+#ifdef CONFIG_SAE
+       if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE))
+               sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE);
+#endif /* CONFIG_SAE */
        if (0) {
 #ifdef CONFIG_IEEE80211R
        } else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
@@ -1083,6 +1095,14 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
                wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+       } else if (sel & WPA_KEY_MGMT_SAE) {
+               wpa_s->key_mgmt = WPA_KEY_MGMT_SAE;
+               wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT SAE");
+       } else if (sel & WPA_KEY_MGMT_FT_SAE) {
+               wpa_s->key_mgmt = WPA_KEY_MGMT_FT_SAE;
+               wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT FT/SAE");
+#endif /* CONFIG_SAE */
 #ifdef CONFIG_IEEE80211W
        } else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA256) {
                wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
@@ -1115,7 +1135,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
 
 #ifdef CONFIG_IEEE80211W
        sel = ie.mgmt_group_cipher;
-       if (ssid->ieee80211w == NO_MGMT_FRAME_PROTECTION ||
+       if ((ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+            wpa_s->conf->pmf : ssid->ieee80211w) == NO_MGMT_FRAME_PROTECTION ||
            !(ie.capabilities & WPA_CAPABILITY_MFPC))
                sel = 0;
        if (sel & WPA_CIPHER_AES_128_CMAC) {
@@ -1128,7 +1149,9 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
        }
        wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
                         wpa_s->mgmt_group_cipher);
-       wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP, ssid->ieee80211w);
+       wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
+                        (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+                         wpa_s->conf->pmf : ssid->ieee80211w));
 #endif /* CONFIG_IEEE80211W */
 
        if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
@@ -1309,7 +1332,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                   (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
                /* Use ap_scan==1 style network selection to find the network
                 */
-               wpa_s->scan_req = 2;
+               wpa_s->scan_req = MANUAL_SCAN_REQ;
                wpa_s->reassociate = 1;
                wpa_supplicant_req_scan(wpa_s, 0, 0);
                return;
@@ -1347,7 +1370,9 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                    wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
            wpa_key_mgmt_wpa(ssid->key_mgmt)) {
                int try_opportunistic;
-               try_opportunistic = ssid->proactive_key_caching &&
+               try_opportunistic = (ssid->proactive_key_caching < 0 ?
+                                    wpa_s->conf->okc :
+                                    ssid->proactive_key_caching) &&
                        (ssid->proto & WPA_PROTO_RSN);
                if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
                                            wpa_s->current_ssid,
@@ -1552,8 +1577,10 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        params.drop_unencrypted = use_crypt;
 
 #ifdef CONFIG_IEEE80211W
-       params.mgmt_frame_protection = ssid->ieee80211w;
-       if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION && bss) {
+       params.mgmt_frame_protection =
+               ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+               wpa_s->conf->pmf : ssid->ieee80211w;
+       if (params.mgmt_frame_protection != NO_MGMT_FRAME_PROTECTION && bss) {
                const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
                struct wpa_ie_data ie;
                if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie) == 0 &&
@@ -1590,16 +1617,8 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                ((freq = wpa_drv_shared_freq(wpa_s)) > 0) && (freq != params.freq)) {
                wpa_printf(MSG_DEBUG, "Shared interface with conflicting frequency found (%d != %d)"
                                                                                                                                , freq, params.freq);
-               if (wpas_p2p_handle_frequency_conflicts(wpa_s, params.freq) < 0) {
-                       /* Handling conflicts failed. Disable the current connect req and
-                        * notify the userspace to take appropriate action */
-                       wpa_printf(MSG_DEBUG, "proiritize is not set. Notifying user space to handle the case");
-                       wpa_supplicant_disable_network(wpa_s, ssid);
-                       wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_FREQ_CONFLICT
-                               " id=%d", ssid->id);
-                       os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
+               if (wpas_p2p_handle_frequency_conflicts(wpa_s, params.freq, ssid) < 0) 
                        return;
-               }
        }
 #endif
        ret = wpa_drv_associate(wpa_s, &params);
@@ -1694,33 +1713,6 @@ static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s,
 
 
 /**
- * wpa_supplicant_disassociate - Disassociate the current connection
- * @wpa_s: Pointer to wpa_supplicant data
- * @reason_code: IEEE 802.11 reason code for the disassociate frame
- *
- * This function is used to request %wpa_supplicant to disassociate with the
- * current AP.
- */
-void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
-                                int reason_code)
-{
-       u8 *addr = NULL;
-       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);
-}
-
-
-/**
  * wpa_supplicant_deauthenticate - Deauthenticate the current connection
  * @wpa_s: Pointer to wpa_supplicant data
  * @reason_code: IEEE 802.11 reason code for the deauthenticate frame
@@ -1733,14 +1725,38 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
 {
        u8 *addr = NULL;
        union wpa_event_data event;
+       int zero_addr = 0;
+
+       wpa_dbg(wpa_s, MSG_DEBUG, "Request to deauthenticate - bssid=" MACSTR
+               " pending_bssid=" MACSTR " reason=%d state=%s",
+               MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
+               reason_code, wpa_supplicant_state_txt(wpa_s->wpa_state));
 
-       if (!is_zero_ether_addr(wpa_s->bssid)) {
-               wpa_drv_deauthenticate(wpa_s, wpa_s->bssid, reason_code);
+       if (!is_zero_ether_addr(wpa_s->bssid))
                addr = wpa_s->bssid;
+       else if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
+                (wpa_s->wpa_state == WPA_AUTHENTICATING ||
+                 wpa_s->wpa_state == WPA_ASSOCIATING))
+               addr = wpa_s->pending_bssid;
+       else if (wpa_s->wpa_state == WPA_ASSOCIATING) {
+               /*
+                * When using driver-based BSS selection, we may not know the
+                * BSSID with which we are currently trying to associate. We
+                * need to notify the driver of this disconnection even in such
+                * a case, so use the all zeros address here.
+                */
+               addr = wpa_s->bssid;
+               zero_addr = 1;
+       }
+
+       if (addr) {
+               wpa_drv_deauthenticate(wpa_s, addr, reason_code);
                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);
+               if (zero_addr)
+                       addr = NULL;
        }
 
        wpa_supplicant_clear_connection(wpa_s, addr);
@@ -1831,11 +1847,11 @@ void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
                                        wpa_s, other_ssid);
                }
                if (wpa_s->current_ssid)
-                       wpa_supplicant_disassociate(
+                       wpa_supplicant_deauthenticate(
                                wpa_s, WLAN_REASON_DEAUTH_LEAVING);
        } else if (ssid->disabled != 2) {
                if (ssid == wpa_s->current_ssid)
-                       wpa_supplicant_disassociate(
+                       wpa_supplicant_deauthenticate(
                                wpa_s, WLAN_REASON_DEAUTH_LEAVING);
 
                was_disabled = ssid->disabled;
@@ -1861,7 +1877,7 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
        int disconnected = 0;
 
        if (ssid && ssid != wpa_s->current_ssid && wpa_s->current_ssid) {
-               wpa_supplicant_disassociate(
+               wpa_supplicant_deauthenticate(
                        wpa_s, WLAN_REASON_DEAUTH_LEAVING);
                disconnected = 1;
        }
@@ -2419,7 +2435,7 @@ static struct wpa_supplicant * wpa_supplicant_alloc(void)
        wpa_s = os_zalloc(sizeof(*wpa_s));
        if (wpa_s == NULL)
                return NULL;
-       wpa_s->scan_req = 1;
+       wpa_s->scan_req = INITIAL_SCAN_REQ;
        wpa_s->scan_interval = 5;
        wpa_s->new_connection = 1;
        wpa_s->parent = wpa_s;
@@ -3452,6 +3468,12 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
                }
        }
 
+       /*
+        * Add previous failure count in case the temporary blacklist was
+        * cleared due to no other BSSes being available.
+        */
+       count += wpa_s->extra_blacklist_count;
+
        switch (count) {
        case 1:
                timeout = 100;
@@ -3462,10 +3484,17 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
        case 3:
                timeout = 1000;
                break;
-       default:
+       case 4:
                timeout = 5000;
+               break;
+       default:
+               timeout = 10000;
+               break;
        }
 
+       wpa_dbg(wpa_s, MSG_DEBUG, "Blacklist count %d --> request scan in %d "
+               "ms", count, timeout);
+
        /*
         * TODO: if more than one possible AP is available in scan results,
         * could try the other ones before requesting a new scan.
@@ -3672,3 +3701,58 @@ void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s,
        if (clear_failures)
                ssid->auth_failures = 0;
 }
+
+
+int disallowed_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+       size_t i;
+
+       if (wpa_s->disallow_aps_bssid == NULL)
+               return 0;
+
+       for (i = 0; i < wpa_s->disallow_aps_bssid_count; i++) {
+               if (os_memcmp(wpa_s->disallow_aps_bssid + i * ETH_ALEN,
+                             bssid, ETH_ALEN) == 0)
+                       return 1;
+       }
+
+       return 0;
+}
+
+
+int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid,
+                   size_t ssid_len)
+{
+       size_t i;
+
+       if (wpa_s->disallow_aps_ssid == NULL || ssid == NULL)
+               return 0;
+
+       for (i = 0; i < wpa_s->disallow_aps_ssid_count; i++) {
+               struct wpa_ssid_value *s = &wpa_s->disallow_aps_ssid[i];
+               if (ssid_len == s->ssid_len &&
+                   os_memcmp(ssid, s->ssid, ssid_len) == 0)
+                       return 1;
+       }
+
+       return 0;
+}
+
+
+/**
+ * wpas_request_connection - Request a new connection
+ * @wpa_s: Pointer to the network interface
+ *
+ * This function is used to request a new connection to be found. It will mark
+ * the interface to allow reassociation and request a new scan to find a
+ * suitable network to connect to.
+ */
+void wpas_request_connection(struct wpa_supplicant *wpa_s)
+{
+       wpa_s->normal_scans = 0;
+       wpa_supplicant_reinit_autoscan(wpa_s);
+       wpa_s->extra_blacklist_count = 0;
+       wpa_s->disconnected = 0;
+       wpa_s->reassociate = 1;
+       wpa_supplicant_req_scan(wpa_s, 0, 0);
+}
index 0b0ea88..5f0dec6 100644 (file)
@@ -265,6 +265,21 @@ fast_reauth=1
 # inactive stations.
 #p2p_go_max_inactivity=300
 
+# Opportunistic Key Caching (also known as Proactive Key Caching) default
+# This parameter can be used to set the default behavior for the
+# proactive_key_caching parameter. By default, OKC is disabled unless enabled
+# with the global okc=1 parameter or with the per-network
+# proactive_key_caching=1 parameter. With okc=1, OKC is enabled by default, but
+# can be disabled with per-network proactive_key_caching=0 parameter.
+#okc=0
+
+# Protected Management Frames default
+# This parameter can be used to set the default behavior for the ieee80211w
+# parameter. By default, PMF is disabled unless enabled with the global pmf=1/2
+# parameter or with the per-network ieee80211w=1/2 parameter. With pmf=1/2, PMF
+# is enabled/required by default, but can be disabled with the per-network
+# ieee80211w parameter.
+#pmf=0
 
 # Interworking (IEEE 802.11u)
 
@@ -490,7 +505,7 @@ fast_reauth=1
 # If not set, this defaults to: WPA-PSK WPA-EAP
 #
 # ieee80211w: whether management frame protection is enabled
-# 0 = disabled (default)
+# 0 = disabled (default unless changed with the global pmf parameter)
 # 1 = optional
 # 2 = required
 # The most common configuration options for this based on the PMF (protected
@@ -548,7 +563,7 @@ fast_reauth=1
 #
 # proactive_key_caching:
 # Enable/disable opportunistic PMKSA caching for WPA2.
-# 0 = disabled (default)
+# 0 = disabled (default unless changed with the global okc parameter)
 # 1 = enabled
 #
 # wep_key0..3: Static WEP key (ASCII in double quotation, e.g. "abcde" or
index 55f3d88..a92d0c1 100644 (file)
@@ -267,6 +267,11 @@ struct wps_ap_info {
        struct os_time last_attempt;
 };
 
+struct wpa_ssid_value {
+       u8 ssid[32];
+       size_t ssid_len;
+};
+
 /**
  * struct wpa_supplicant - Internal data for wpa_supplicant interface
  *
@@ -323,6 +328,11 @@ struct wpa_supplicant {
        u8 *bssid_filter;
        size_t bssid_filter_count;
 
+       u8 *disallow_aps_bssid;
+       size_t disallow_aps_bssid_count;
+       struct wpa_ssid_value *disallow_aps_ssid;
+       size_t disallow_aps_ssid_count;
+
        /* previous scan was wildcard when interleaving between
         * wildcard scans and specific SSID scan when max_ssids=1 */
        int prev_scan_wildcard;
@@ -387,12 +397,54 @@ struct wpa_supplicant {
 
        struct wpa_blacklist *blacklist;
 
-       int scan_req; /* manual scan request; this forces a scan even if there
-                      * are no enabled networks in the configuration */
+       /**
+        * extra_blacklist_count - Sum of blacklist counts after last connection
+        *
+        * This variable is used to maintain a count of temporary blacklisting
+        * failures (maximum number for any BSS) over blacklist clear
+        * operations. This is needed for figuring out whether there has been
+        * failures prior to the last blacklist clear operation which happens
+        * whenever no other not-blacklisted BSS candidates are available. This
+        * gets cleared whenever a connection has been established successfully.
+        */
+       int extra_blacklist_count;
+
+       /**
+        * scan_req - Type of the scan request
+        */
+       enum scan_req_type {
+               /**
+                * NORMAL_SCAN_REQ - Normal scan request
+                *
+                * This is used for scans initiated by wpa_supplicant to find an
+                * AP for a connection.
+                */
+               NORMAL_SCAN_REQ,
+
+               /**
+                * INITIAL_SCAN_REQ - Initial scan request
+                *
+                * This is used for the first scan on an interface to force at
+                * least one scan to be run even if the configuration does not
+                * include any enabled networks.
+                */
+               INITIAL_SCAN_REQ,
+
+               /**
+                * MANUAL_SCAN_REQ - Manual scan request
+                *
+                * This is used for scans where the user request a scan or
+                * a specific wpa_supplicant operation (e.g., WPS) requires scan
+                * to be run.
+                */
+               MANUAL_SCAN_REQ
+       } scan_req;
        int scan_runs; /* number of scan runs since WPS was started */
        int *next_scan_freqs;
        int scan_interval; /* time in sec between scans to find suitable AP */
        int normal_scans; /* normal scans run before sched_scan */
+       int scan_for_connection; /* whether the scan request was triggered for
+                                 * finding a connection */
 
        unsigned int drv_flags;
        unsigned int drv_enc;
@@ -457,6 +509,12 @@ struct wpa_supplicant {
                u8 sched_obss_scan;
                u16 obss_scan_int;
                u16 bss_max_idle_period;
+               enum {
+                       SME_SAE_INIT,
+                       SME_SAE_COMMIT,
+                       SME_SAE_CONFIRM
+               } sae_state;
+               u16 sae_send_confirm;
        } sme;
 #endif /* CONFIG_SME */
 
@@ -549,6 +607,7 @@ struct wpa_supplicant {
        unsigned int p2p_fallback_to_go_neg:1;
        unsigned int p2p_pd_before_go_neg:1;
        unsigned int p2p_go_ht40:1;
+       unsigned int user_initiated_pd:1;
        int p2p_persistent_go_freq;
        int p2p_persistent_id;
        int p2p_go_intent;
@@ -573,6 +632,7 @@ struct wpa_supplicant {
        int after_wps;
        int known_wps_freq;
        unsigned int wps_freq;
+       u16 wps_ap_channel;
        int wps_fragment_size;
        int auto_reconnect_disabled;
 
@@ -643,8 +703,6 @@ const char * wpa_supplicant_get_eap_mode(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
                                   int reason_code);
-void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
-                                int reason_code);
 
 void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
                                   struct wpa_ssid *ssid);
@@ -693,7 +751,10 @@ int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s);
 void wpas_auth_failed(struct wpa_supplicant *wpa_s);
 void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s,
                              struct wpa_ssid *ssid, int clear_failures);
-void wpa_supplicant_proc_40mhz_intolerant(struct wpa_supplicant *wpa_s);
+int disallowed_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid,
+                   size_t ssid_len);
+void wpas_request_connection(struct wpa_supplicant *wpa_s);
 
 /**
  * wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
index 6aa5205..1ba4c92 100644 (file)
@@ -406,14 +406,6 @@ static enum wpa_states _wpa_supplicant_get_state(void *wpa_s)
 }
 
 
-static void _wpa_supplicant_disassociate(void *wpa_s, int reason_code)
-{
-       wpa_supplicant_disassociate(wpa_s, reason_code);
-       /* Schedule a scan to make sure we continue looking for networks */
-       wpa_supplicant_req_scan(wpa_s, 5, 0);
-}
-
-
 static void _wpa_supplicant_deauthenticate(void *wpa_s, int reason_code)
 {
        wpa_supplicant_deauthenticate(wpa_s, reason_code);
@@ -839,7 +831,6 @@ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
        ctx->set_state = _wpa_supplicant_set_state;
        ctx->get_state = _wpa_supplicant_get_state;
        ctx->deauthenticate = _wpa_supplicant_deauthenticate;
-       ctx->disassociate = _wpa_supplicant_disassociate;
        ctx->set_key = wpa_supplicant_set_key;
        ctx->get_network_ctx = wpa_supplicant_get_network_ctx;
        ctx->get_bssid = wpa_supplicant_get_bssid;
@@ -889,7 +880,8 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
                conf.peerkey_enabled = ssid->peerkey;
                conf.allowed_pairwise_cipher = ssid->pairwise_cipher;
 #ifdef IEEE8021X_EAPOL
-               conf.proactive_key_caching = ssid->proactive_key_caching;
+               conf.proactive_key_caching = ssid->proactive_key_caching < 0 ?
+                       wpa_s->conf->okc : ssid->proactive_key_caching;
                conf.eap_workaround = ssid->eap_workaround;
                conf.eap_conf_ctx = &ssid->eap;
 #endif /* IEEE8021X_EAPOL */
index 915ca57..0239c55 100644 (file)
@@ -256,6 +256,15 @@ static int wpa_supplicant_wps_cred(void *ctx,
                return 0;
        }
 
+       if (auth_type == WPS_AUTH_WPAPSK || auth_type == WPS_AUTH_WPA2PSK) {
+               if (cred->key_len < 8 || cred->key_len > 2 * PMK_LEN) {
+                       wpa_printf(MSG_ERROR, "WPS: Reject PSK credential with "
+                                  "invalid Network Key length %lu",
+                                  (unsigned long) cred->key_len);
+                       return -1;
+               }
+       }
+
        if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
                wpa_printf(MSG_DEBUG, "WPS: Replace WPS network block based "
                           "on the received credential");
@@ -403,6 +412,9 @@ static int wpa_supplicant_wps_cred(void *ctx,
 
        wpas_wps_security_workaround(wpa_s, ssid, cred);
 
+       if (cred->ap_channel)
+               wpa_s->wps_ap_channel = cred->ap_channel;
+
 #ifndef CONFIG_NO_CONFIG_WRITE
        if (wpa_s->conf->update_config &&
            wpa_config_write(wpa_s->confname, wpa_s->conf)) {
@@ -487,11 +499,46 @@ static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s,
 }
 
 
+static void wpas_wps_reenable_networks_cb(void *eloop_ctx, void *timeout_ctx);
+
+static void wpas_wps_reenable_networks(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_ssid *ssid;
+
+       eloop_cancel_timeout(wpas_wps_reenable_networks_cb, wpa_s, NULL);
+
+       for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+               if (ssid->disabled_for_connect && ssid->disabled) {
+                       ssid->disabled_for_connect = 0;
+                       ssid->disabled = 0;
+                       wpas_notify_network_enabled_changed(wpa_s, ssid);
+               }
+       }
+}
+
+
+static void wpas_wps_reenable_networks_cb(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+       /* Enable the networks disabled during wpas_wps_reassoc */
+       wpas_wps_reenable_networks(wpa_s);
+}
+
+
 static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s)
 {
        wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_SUCCESS);
        wpa_s->wps_success = 1;
        wpas_notify_wps_event_success(wpa_s);
+
+       /*
+        * Enable the networks disabled during wpas_wps_reassoc after 10
+        * seconds. The 10 seconds timer is to allow the data connection to be
+        * formed before allowing other networks to be selected.
+        */
+       eloop_register_timeout(10, 0, wpas_wps_reenable_networks_cb, wpa_s,
+                              NULL);
+
 #ifdef CONFIG_P2P
        wpas_p2p_wps_success(wpa_s, wpa_s->bssid, 0);
 #endif /* CONFIG_P2P */
@@ -690,6 +737,9 @@ static void wpas_clear_wps(struct wpa_supplicant *wpa_s)
 
        prev_current = wpa_s->current_ssid;
 
+       /* Enable the networks disabled during wpas_wps_reassoc */
+       wpas_wps_reenable_networks(wpa_s);
+
        eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
 
        /* Remove any existing WPS network from configuration */
@@ -819,6 +869,7 @@ static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
        ssid = wpa_s->conf->ssid;
        while (ssid) {
                int was_disabled = ssid->disabled;
+               ssid->disabled_for_connect = 0;
                /*
                 * In case the network object corresponds to a persistent group
                 * then do not send out network disabled signal. In addition,
@@ -827,9 +878,12 @@ static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
                 */
                if (was_disabled != 2) {
                        ssid->disabled = ssid != selected;
-                       if (was_disabled != ssid->disabled)
+                       if (was_disabled != ssid->disabled) {
+                               if (ssid->disabled)
+                                       ssid->disabled_for_connect = 1;
                                wpas_notify_network_enabled_changed(wpa_s,
                                                                    ssid);
+                       }
                }
                ssid = ssid->next;
        }
@@ -940,62 +994,13 @@ int wpas_wps_cancel(struct wpa_supplicant *wpa_s)
                wpa_supplicant_deauthenticate(wpa_s,
                                              WLAN_REASON_DEAUTH_LEAVING);
                wpas_clear_wps(wpa_s);
-       } else
+       } else {
+               wpas_wps_reenable_networks(wpa_s);
                wpas_wps_clear_ap_info(wpa_s);
-
-       return 0;
-}
-
-
-#ifdef CONFIG_WPS_OOB
-int wpas_wps_start_oob(struct wpa_supplicant *wpa_s, char *device_type,
-                      char *path, char *method, char *name)
-{
-       struct wps_context *wps = wpa_s->wps;
-       struct oob_device_data *oob_dev;
-
-       oob_dev = wps_get_oob_device(device_type);
-       if (oob_dev == NULL)
-               return -1;
-       oob_dev->device_path = path;
-       oob_dev->device_name = name;
-       wps->oob_conf.oob_method = wps_get_oob_method(method);
-
-       if (wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E) {
-               /*
-                * Use pre-configured DH keys in order to be able to write the
-                * key hash into the OOB file.
-                */
-               wpabuf_free(wps->dh_pubkey);
-               wpabuf_free(wps->dh_privkey);
-               wps->dh_privkey = NULL;
-               wps->dh_pubkey = NULL;
-               dh5_free(wps->dh_ctx);
-               wps->dh_ctx = dh5_init(&wps->dh_privkey, &wps->dh_pubkey);
-               wps->dh_pubkey = wpabuf_zeropad(wps->dh_pubkey, 192);
-               if (wps->dh_ctx == NULL || wps->dh_pubkey == NULL) {
-                       wpa_printf(MSG_ERROR, "WPS: Failed to initialize "
-                                  "Diffie-Hellman handshake");
-                       return -1;
-               }
        }
 
-       if (wps->oob_conf.oob_method == OOB_METHOD_CRED)
-               wpas_clear_wps(wpa_s);
-
-       if (wps_process_oob(wps, oob_dev, 0) < 0)
-               return -1;
-
-       if ((wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E ||
-            wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_R) &&
-           wpas_wps_start_pin(wpa_s, NULL,
-                              wpabuf_head(wps->oob_conf.dev_password), 0,
-                              DEV_PW_DEFAULT) < 0)
-                       return -1;
-
        return 0;
 }
-#endif /* CONFIG_WPS_OOB */
 
 
 int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
@@ -1247,6 +1252,7 @@ int wpas_wps_init(struct wpa_supplicant *wpa_s)
 void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
 {
        eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
+       eloop_cancel_timeout(wpas_wps_reenable_networks_cb, wpa_s, NULL);
        wpas_wps_clear_ap_info(wpa_s);
 
        if (wpa_s->wps == NULL)
@@ -1260,8 +1266,6 @@ void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
        wps_registrar_deinit(wpa_s->wps->registrar);
        wpabuf_free(wpa_s->wps->dh_pubkey);
        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);
@@ -1851,6 +1855,8 @@ int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid)
 static int wpas_wps_use_cred(struct wpa_supplicant *wpa_s,
                             struct wps_parse_attr *attr)
 {
+       wpa_s->wps_ap_channel = 0;
+
        if (wps_oob_use_cred(wpa_s->wps, attr) < 0)
                return -1;
 
@@ -1861,6 +1867,24 @@ static int wpas_wps_use_cred(struct wpa_supplicant *wpa_s,
                   "based on the received credential added");
        wpa_s->normal_scans = 0;
        wpa_supplicant_reinit_autoscan(wpa_s);
+       if (wpa_s->wps_ap_channel) {
+               u16 chan = wpa_s->wps_ap_channel;
+               int freq = 0;
+
+               if (chan >= 1 && chan <= 13)
+                       freq = 2407 + 5 * chan;
+               else if (chan == 14)
+                       freq = 2484;
+               else if (chan >= 30)
+                       freq = 5000 + 5 * chan;
+
+               if (freq) {
+                       wpa_printf(MSG_DEBUG, "WPS: Credential indicated "
+                                  "AP channel %u -> %u MHz", chan, freq);
+                       wpa_s->after_wps = 5;
+                       wpa_s->wps_freq = freq;
+               }
+       }
        wpa_s->disconnected = 0;
        wpa_s->reassociate = 1;
        wpa_supplicant_req_scan(wpa_s, 0, 0);
@@ -1930,6 +1954,45 @@ int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,
        return ret;
 }
 
+
+struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s)
+{
+       return ndef_build_wifi_hr();
+}
+
+
+struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s)
+{
+       return NULL;
+}
+
+
+int wpas_wps_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
+                                const struct wpabuf *data)
+{
+       /* TODO */
+       return -1;
+}
+
+
+int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
+                                const struct wpabuf *data)
+{
+       struct wpabuf *wps;
+       int ret;
+
+       wps = ndef_parse_wifi(data);
+       if (wps == NULL)
+               return -1;
+       wpa_printf(MSG_DEBUG, "WPS: Received application/vnd.wfa.wsc "
+                  "payload from NFC connection handover");
+       wpa_hexdump_buf_key(MSG_DEBUG, "WPS: NFC payload", wps);
+       ret = wpas_wps_nfc_tag_process(wpa_s, wps);
+       wpabuf_free(wps);
+
+       return ret;
+}
+
 #endif /* CONFIG_WPS_NFC */
 
 
index d5eb3b6..dd0dc60 100644 (file)
@@ -9,7 +9,6 @@
 #ifndef WPS_SUPPLICANT_H
 #define WPS_SUPPLICANT_H
 
-struct wpa_scan_res;
 struct wpa_scan_results;
 
 #ifdef CONFIG_WPS
@@ -35,8 +34,6 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
 int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
                       const char *pin, int p2p_group, u16 dev_pw_id);
 int wpas_wps_cancel(struct wpa_supplicant *wpa_s);
-int wpas_wps_start_oob(struct wpa_supplicant *wpa_s, char *device_type,
-                      char *path, char *method, char *name);
 int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
                       const char *pin, struct wps_new_ap_settings *settings);
 int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
@@ -69,6 +66,12 @@ 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);
+struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s);
+struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s);
+int wpas_wps_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
+                                const struct wpabuf *data);
+int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
+                                const struct wpabuf *data);
 void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
                             struct wpa_scan_results *scan_res);
 void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid);
@@ -96,14 +99,14 @@ static inline u8 wpas_wps_get_req_type(struct wpa_ssid *ssid)
 
 static inline int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
                                          struct wpa_ssid *ssid,
-                                         struct wpa_scan_res *bss)
+                                         struct wpa_bss *bss)
 {
        return -1;
 }
 
 static inline int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
                                            struct wpa_ssid *ssid,
-                                           struct wpa_scan_res *bss)
+                                           struct wpa_bss *bss)
 {
        return 0;
 }