Cumulative patch from commit 538922a628d4f5403b9a96b171a59235bcb3d921
538922a dbus: Add boolean AllowRoam option to Scan() method options dictionary
c6f5dec Don't start second scan when changing scan interval
cd3b070 nl80211: Fix DFS radar event parsing
2b72df6 nl80211: Free BSS structure even if netdev does not exists
41cc50d nl80211: Update send_action_cookie on AP-offchannel-TX path
313424d GAS: Add support for multiple pending queries for the same destination
cbc5484 GAS: Do not start new scan operation during an ongoing GAS query
c377514 GAS: Delay GAS query Tx while scanning/connecting
24c694b GAS: Delay GAS query Tx while another query is in progress
7255983 WPS: Clear after_wps from number of new locations
73b54d6 P2P: Fix Operating Channel in Invitation Request for operating group
dc46fd6 P2P: Cancel offchannel TX wait on Invitation Response RX
0c92963 D-Bus: Clean up debug print for P2P invitation result
8d82c21 P2P: Fix PD retry channel on join-a-group case
d285888 P2P: Add GO BSS entry details to debug log on join-a-group
512629a P2P: Accept Invitation Response non-success without Channel List
e241b1b eap_proxy: Fix IMSI fetch for home vs. visited network determination
db13605 EAP-AKA/AKA' peer: Allow external USIM processing to be used
569ccf7 EAP-SIM peer: Allow external SIM processing to be used
84dc137 hlr_auc_gw: Add GSM-AUTH-REQ command
a5d44ac EAP peer: Add framework for external SIM/USIM processing
7e8bc7d eapol_test: Initialize BSS lists
bceb843 Send CTRL-RSP command response before processing EAPOL update
b607796 eapol_test: Fix external EAP request mechanism
94de082 eapol_test: Initialize wpa_s->global to fix ctrl_iface
f07bba3 Android: Add dfs.c into build
0cf0af2 WNM: Set Disassoc Imminent flag in ESS Disassoc Imminent frame
f47c145 Interworking: Add required_roaming_consortium parameter for credentials
a83e574 GAS: Update timeout from TX status handler
e88060e HTTP server: Allow TCP socket to be reused
9bc3386 Add test option for specifying hardcoded BSS Load element
9c7e43a Define BSS Load element id
56f5af4 Interworking: Add support for QoS Mapping functionality for the STA
850e1c2 atheros: Add support for QoS Mapping configuration
c551700 Interworking: Add support for QoS Mapping functionality for the AP
ac1bc54 Interworking: Add domain_suffix_match for credentials
463c8ff Interworking: Add support for multiple home FQDNs
01f809c Add AAA server domain name suffix matching constraint
be7963b OpenSSL: Fix code indentation in OCSP processing
899cc14 hostapd: Add support for DFS with 160 MHz channel width
6de0e0c Mark DFS functions static and rename them
58b73e3 hostapd: DFS with 40/80 MHz channel width support
846de15 DFS: Add more parameters to radar events
04e8003 nl80211: Use struct hostapd_freq_params with start_dfs_cac
72c753d hostapd: Split hostapd_set_freq to helper function
e76da50 hostapd: Add AP DFS support
Change-Id: Ie9ed4662ba6d81e6d8b14bccb29ffa192becf0f2
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 8515b5a..5075976 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -794,6 +794,7 @@
OBJS += src/ap/ap_list.c
OBJS += src/ap/ieee802_11.c
OBJS += src/ap/hw_features.c
+OBJS += src/ap/dfs.c
L_CFLAGS += -DNEED_AP_MLME
endif
ifdef CONFIG_WPS
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 5698619..7c44241 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -772,6 +772,7 @@
OBJS += ../src/ap/ap_list.o
OBJS += ../src/ap/ieee802_11.o
OBJS += ../src/ap/hw_features.o
+OBJS += ../src/ap/dfs.o
CFLAGS += -DNEED_AP_MLME
endif
ifdef CONFIG_WPS
diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20
index 5669c55..61e4a4d 100644
--- a/wpa_supplicant/README-HS20
+++ b/wpa_supplicant/README-HS20
@@ -166,9 +166,25 @@
# milenage: Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN>
# format
#
-# domain: Home service provider FQDN
+# domain_suffix_match: Constraint for server domain name
+# If set, this FQDN is used as a suffix match requirement for the AAA
+# server certificate in SubjectAltName dNSName element(s). If a
+# matching dNSName is found, this constraint is met. If no dNSName
+# values are present, this constraint is matched against SubjetName CN
+# using same suffix match comparison. Suffix match here means that the
+# host/domain name is compared one label at a time starting from the
+# top-level domain and all the labels in @domain_suffix_match shall be
+# included in the certificate. The certificate may include additional
+# sub-level labels in addition to the required labels.
+#
+# For example, domain_suffix_match=example.com would match
+# test.example.com but would not match test-example.com.
+#
+# domain: Home service provider FQDN(s)
# This is used to compare against the Domain Name List to figure out
-# whether the AP is operated by the Home SP.
+# whether the AP is operated by the Home SP. Multiple domain entries can
+# be used to configure alternative FQDNs that will be considered home
+# networks.
#
# roaming_consortium: Roaming Consortium OI
# If roaming_consortium_len is non-zero, this field contains the
@@ -203,6 +219,7 @@
# password="password"
# ca_cert="/etc/wpa_supplicant/ca.pem"
# domain="example.com"
+# domain_suffix_match="example.com"
#}
#
#cred={
@@ -267,6 +284,17 @@
Note: the return value of add_cred is used as the first argument to
the following set_cred commands.
+Add a SIM credential using a external SIM/USIM processing:
+
+> set external_sim 1
+OK
+> add_cred
+1
+> set_cred 1 imsi "23456-0000000000"
+OK
+> set_cred 1 eap SIM
+OK
+
Add a WPA2-Enterprise network:
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 2b17365..ea7ac5a 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1579,6 +1579,7 @@
{ STRe(dh_file) },
{ STRe(subject_match) },
{ STRe(altsubject_match) },
+ { STRe(domain_suffix_match) },
{ STRe(ca_cert2) },
{ STRe(ca_path2) },
{ STRe(client_cert2) },
@@ -1587,6 +1588,7 @@
{ STRe(dh_file2) },
{ STRe(subject_match2) },
{ STRe(altsubject_match2) },
+ { STRe(domain_suffix_match2) },
{ STRe(phase1) },
{ STRe(phase2) },
{ STRe(pcsc) },
@@ -1786,6 +1788,7 @@
os_free(eap->dh_file);
os_free(eap->subject_match);
os_free(eap->altsubject_match);
+ os_free(eap->domain_suffix_match);
os_free(eap->ca_cert2);
os_free(eap->ca_path2);
os_free(eap->client_cert2);
@@ -1794,6 +1797,7 @@
os_free(eap->dh_file2);
os_free(eap->subject_match2);
os_free(eap->altsubject_match2);
+ os_free(eap->domain_suffix_match2);
os_free(eap->phase1);
os_free(eap->phase2);
os_free(eap->pcsc);
@@ -1811,6 +1815,7 @@
os_free(eap->pending_req_otp);
os_free(eap->pac_file);
os_free(eap->new_password);
+ os_free(eap->external_sim_resp);
}
#endif /* IEEE8021X_EAPOL */
@@ -1851,6 +1856,8 @@
void wpa_config_free_cred(struct wpa_cred *cred)
{
+ size_t i;
+
os_free(cred->realm);
os_free(cred->username);
os_free(cred->password);
@@ -1860,7 +1867,10 @@
os_free(cred->private_key_passwd);
os_free(cred->imsi);
os_free(cred->milenage);
+ for (i = 0; i < cred->num_domain; i++)
+ os_free(cred->domain[i]);
os_free(cred->domain);
+ os_free(cred->domain_suffix_match);
os_free(cred->eap_method);
os_free(cred->phase1);
os_free(cred->phase2);
@@ -2432,9 +2442,23 @@
return 0;
}
+ if (os_strcmp(var, "domain_suffix_match") == 0) {
+ os_free(cred->domain_suffix_match);
+ cred->domain_suffix_match = val;
+ return 0;
+ }
+
if (os_strcmp(var, "domain") == 0) {
- os_free(cred->domain);
- cred->domain = val;
+ char **new_domain;
+ new_domain = os_realloc_array(cred->domain,
+ cred->num_domain + 1,
+ sizeof(char *));
+ if (new_domain == NULL) {
+ os_free(val);
+ return -1;
+ }
+ new_domain[cred->num_domain++] = val;
+ cred->domain = new_domain;
return 0;
}
@@ -2464,6 +2488,21 @@
return 0;
}
+ if (os_strcmp(var, "required_roaming_consortium") == 0) {
+ if (len < 3 || len > sizeof(cred->required_roaming_consortium))
+ {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "required_roaming_consortium length %d "
+ "(3..15 expected)", line, (int) len);
+ os_free(val);
+ return -1;
+ }
+ os_memcpy(cred->required_roaming_consortium, val, len);
+ cred->required_roaming_consortium_len = len;
+ os_free(val);
+ return 0;
+ }
+
if (os_strcmp(var, "excluded_ssid") == 0) {
struct excluded_ssid *e;
@@ -3156,6 +3195,7 @@
{ STR(pkcs11_module_path), 0 },
{ STR(pcsc_reader), 0 },
{ STR(pcsc_pin), 0 },
+ { INT(external_sim), 0 },
{ STR(driver_param), 0 },
{ INT(dot11RSNAConfigPMKLifetime), 0 },
{ INT(dot11RSNAConfigPMKReauthThreshold), 0 },
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 1748cf3..2e558fd 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -150,12 +150,37 @@
char *milenage;
/**
- * domain - Home service provider FQDN
+ * domain_suffix_match - Constraint for server domain name
+ *
+ * If set, this FQDN is used as a suffix match requirement for the AAA
+ * server certificate in SubjectAltName dNSName element(s). If a
+ * matching dNSName is found, this constraint is met. If no dNSName
+ * values are present, this constraint is matched against SubjetName CN
+ * using same suffix match comparison. Suffix match here means that the
+ * host/domain name is compared one label at a time starting from the
+ * top-level domain and all the labels in @domain_suffix_match shall be
+ * included in the certificate. The certificate may include additional
+ * sub-level labels in addition to the required labels.
+ *
+ * For example, domain_suffix_match=example.com would match
+ * test.example.com but would not match test-example.com.
+ */
+ char *domain_suffix_match;
+
+ /**
+ * domain - Home service provider FQDN(s)
*
* This is used to compare against the Domain Name List to figure out
- * whether the AP is operated by the Home SP.
+ * whether the AP is operated by the Home SP. Multiple domain entries
+ * can be used to configure alternative FQDNs that will be considered
+ * home networks.
*/
- char *domain;
+ char **domain;
+
+ /**
+ * num_domain - Number of FQDNs in the domain array
+ */
+ size_t num_domain;
/**
* roaming_consortium - Roaming Consortium OI
@@ -175,6 +200,9 @@
*/
size_t roaming_consortium_len;
+ u8 required_roaming_consortium[15];
+ size_t required_roaming_consortium_len;
+
/**
* eap_method - EAP method to use
*
@@ -425,6 +453,11 @@
char *pcsc_pin;
/**
+ * external_sim - Use external processing for SIM/USIM operations
+ */
+ int external_sim;
+
+ /**
* driver_param - Driver interface parameters
*
* This text string is passed to the selected driver interface with the
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 0d2bd8c..b8fff70 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -667,6 +667,7 @@
STR(dh_file);
STR(subject_match);
STR(altsubject_match);
+ STR(domain_suffix_match);
STR(ca_cert2);
STR(ca_path2);
STR(client_cert2);
@@ -675,6 +676,7 @@
STR(dh_file2);
STR(subject_match2);
STR(altsubject_match2);
+ STR(domain_suffix_match2);
STR(phase1);
STR(phase2);
STR(pcsc);
@@ -726,6 +728,8 @@
static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred)
{
+ size_t i;
+
if (cred->priority)
fprintf(f, "\tpriority=%d\n", cred->priority);
if (cred->pcsc)
@@ -751,10 +755,12 @@
fprintf(f, "\timsi=\"%s\"\n", cred->imsi);
if (cred->milenage)
fprintf(f, "\tmilenage=\"%s\"\n", cred->milenage);
- if (cred->domain)
- fprintf(f, "\tdomain=\"%s\"\n", cred->domain);
+ for (i = 0; i < cred->num_domain; i++)
+ fprintf(f, "\tdomain=\"%s\"\n", cred->domain[i]);
+ if (cred->domain_suffix_match)
+ fprintf(f, "\tdomain_suffix_match=\"%s\"",
+ cred->domain_suffix_match);
if (cred->roaming_consortium_len) {
- size_t i;
fprintf(f, "\troaming_consortium=");
for (i = 0; i < cred->roaming_consortium_len; i++)
fprintf(f, "%02x", cred->roaming_consortium[i]);
@@ -771,7 +777,7 @@
if (cred->phase2)
fprintf(f, "\tphase2=\"%s\"\n", cred->phase2);
if (cred->excluded_ssid) {
- size_t i, j;
+ size_t j;
for (i = 0; i < cred->num_excluded_ssid; i++) {
struct excluded_ssid *e = &cred->excluded_ssid[i];
fprintf(f, "\texcluded_ssid=");
@@ -1049,6 +1055,9 @@
if (config->sched_scan_interval)
fprintf(f, "sched_scan_interval=%u\n",
config->sched_scan_interval);
+
+ if (config->external_sim)
+ fprintf(f, "external_sim=%d\n", config->external_sim);
}
#endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
index 1b5e237..00a1004 100644
--- a/wpa_supplicant/config_winreg.c
+++ b/wpa_supplicant/config_winreg.c
@@ -623,6 +623,9 @@
wpa_config_write_reg_dword(hk, TEXT("okc"), config->okc, 0);
wpa_config_write_reg_dword(hk, TEXT("pmf"), config->pmf, 0);
+ wpa_config_write_reg_dword(hk, TEXT("external_sim"),
+ config->external_sim, 0);
+
return 0;
}
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 4aa67f7..15f5268 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -1565,16 +1565,21 @@
char *type;
for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ size_t i;
+
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;
+ for (i = 0; i < cred->num_domain; i++) {
+ ret = os_snprintf(pos, end - pos,
+ "home_sp=%s\n",
+ cred->domain[i]);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
if (wpa_s->current_bss == NULL ||
wpa_s->current_bss->anqp == NULL)
@@ -2467,7 +2472,7 @@
ret = os_snprintf(pos, end - pos, "%d\t%s\t%s\t%s\t%s\n",
cred->id, cred->realm ? cred->realm : "",
cred->username ? cred->username : "",
- cred->domain ? cred->domain : "",
+ cred->domain ? cred->domain[0] : "",
cred->imsi ? cred->imsi : "");
if (ret < 0 || ret >= end - pos)
return pos - buf;
@@ -2552,9 +2557,16 @@
while (cred) {
prev = cred;
cred = cred->next;
- if (prev->domain &&
- os_strcmp(prev->domain, cmd + 8) == 0)
- wpas_ctrl_remove_cred(wpa_s, prev);
+ if (prev->domain) {
+ size_t i;
+ for (i = 0; i < prev->num_domain; i++) {
+ if (os_strcmp(prev->domain[i], cmd + 8)
+ != 0)
+ continue;
+ wpas_ctrl_remove_cred(wpa_s, prev);
+ break;
+ }
+ }
}
return 0;
}
@@ -5194,6 +5206,7 @@
#ifdef CONFIG_WPS
wpas_wps_cancel(wpa_s);
#endif /* CONFIG_WPS */
+ wpa_s->after_wps = 0;
#ifdef CONFIG_TDLS_TESTING
extern unsigned int tdls_testing;
@@ -5229,12 +5242,18 @@
}
+static void wpas_ctrl_eapol_response(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ eapol_sm_notify_ctrl_response(wpa_s->eapol);
+}
+
+
char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
char *buf, size_t *resp_len)
{
char *reply;
const int reply_size = 4096;
- int ctrl_rsp = 0;
int reply_len;
if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
@@ -5573,8 +5592,14 @@
if (wpa_supplicant_ctrl_iface_ctrl_rsp(
wpa_s, buf + os_strlen(WPA_CTRL_RSP)))
reply_len = -1;
- else
- ctrl_rsp = 1;
+ else {
+ /*
+ * Notify response from timeout to allow the control
+ * interface response to be sent first.
+ */
+ eloop_register_timeout(0, 0, wpas_ctrl_eapol_response,
+ wpa_s, NULL);
+ }
} else if (os_strcmp(buf, "RECONFIGURE") == 0) {
if (wpa_supplicant_reload_configuration(wpa_s))
reply_len = -1;
@@ -5615,6 +5640,7 @@
(wpa_s->wpa_state == WPA_COMPLETED))) {
wpa_s->normal_scans = 0;
wpa_s->scan_req = MANUAL_SCAN_REQ;
+ wpa_s->after_wps = 0;
wpa_supplicant_req_scan(wpa_s, 0, 0);
} else if (wpa_s->sched_scanning) {
wpa_printf(MSG_DEBUG, "Stop ongoing "
@@ -5777,9 +5803,6 @@
reply_len = 5;
}
- if (ctrl_rsp)
- eapol_sm_notify_ctrl_response(wpa_s->eapol);
-
*resp_len = reply_len;
return reply;
}
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index ddd2c82..f9521f6 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -1362,7 +1362,7 @@
DBusMessageIter iter, dict_iter;
struct wpas_dbus_priv *iface;
- wpa_printf(MSG_INFO, "%s\n", __func__);
+ wpa_printf(MSG_DEBUG, "%s", __func__);
iface = wpa_s->global->dbus;
/* Do nothing if the control interface is not turned on */
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 478d02f..bb6b7b9 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -1236,6 +1236,23 @@
}
+static int wpas_dbus_get_scan_allow_roam(DBusMessage *message,
+ DBusMessageIter *var,
+ dbus_bool_t *allow,
+ DBusMessage **reply)
+{
+ if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_BOOLEAN) {
+ wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
+ "Type must be a boolean");
+ *reply = wpas_dbus_error_invalid_args(
+ message, "Wrong Type value type. Boolean required");
+ return -1;
+ }
+ dbus_message_iter_get_basic(var, allow);
+ return 0;
+}
+
+
/**
* wpas_dbus_handler_scan - Request a wireless scan on an interface
* @message: Pointer to incoming dbus message
@@ -1254,6 +1271,7 @@
char *key = NULL, *type = NULL;
struct wpa_driver_scan_params params;
size_t i;
+ dbus_bool_t allow_roam = 1;
os_memset(¶ms, 0, sizeof(params));
@@ -1284,6 +1302,12 @@
if (wpas_dbus_get_scan_channels(message, &variant_iter,
¶ms, &reply) < 0)
goto out;
+ } else if (os_strcmp(key, "AllowRoam") == 0) {
+ if (wpas_dbus_get_scan_allow_roam(message,
+ &variant_iter,
+ &allow_roam,
+ &reply) < 0)
+ goto out;
} else {
wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
"Unknown argument %s", key);
@@ -1332,6 +1356,9 @@
goto out;
}
+ if (!allow_roam)
+ wpa_s->scan_res_handler = scan_only_handler;
+
out:
for (i = 0; i < WPAS_MAX_SCAN_SSIDS; i++)
os_free((u8 *) params.ssids[i].ssid);
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 6a96331..628b81b 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -718,4 +718,13 @@
return wpa_s->driver->status(wpa_s->drv_priv, buf, buflen);
}
+static inline int wpa_drv_set_qos_map(struct wpa_supplicant *wpa_s,
+ const u8 *qos_map_set, u8 qos_map_set_len)
+{
+ if (!wpa_s->driver->set_qos_map)
+ return -1;
+ return wpa_s->driver->set_qos_map(wpa_s->drv_priv, qos_map_set,
+ qos_map_set_len);
+}
+
#endif /* DRIVER_I_H */
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index dad2765..9024f23 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - test code
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -27,6 +27,7 @@
#include "common/wpa_ctrl.h"
#include "ctrl_iface.h"
#include "pcsc_funcs.h"
+#include "wpas_glue.h"
extern int wpa_debug_level;
@@ -395,6 +396,54 @@
}
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
+static void eapol_test_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field,
+ const char *default_txt)
+{
+ struct eapol_test_data *e = ctx;
+ struct wpa_supplicant *wpa_s = e->wpa_s;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ const char *field_name, *txt = NULL;
+ char *buf;
+ size_t buflen;
+ int len;
+
+ if (ssid == NULL)
+ return;
+
+ field_name = wpa_supplicant_ctrl_req_to_string(field, default_txt,
+ &txt);
+ if (field_name == NULL) {
+ wpa_printf(MSG_WARNING, "Unhandled EAP param %d needed",
+ field);
+ return;
+ }
+
+ buflen = 100 + os_strlen(txt) + ssid->ssid_len;
+ buf = os_malloc(buflen);
+ if (buf == NULL)
+ return;
+ len = os_snprintf(buf, buflen,
+ WPA_CTRL_REQ "%s-%d:%s needed for SSID ",
+ field_name, ssid->id, txt);
+ if (len < 0 || (size_t) len >= buflen) {
+ os_free(buf);
+ return;
+ }
+ if (ssid->ssid && buflen > len + ssid->ssid_len) {
+ os_memcpy(buf + len, ssid->ssid, ssid->ssid_len);
+ len += ssid->ssid_len;
+ buf[len] = '\0';
+ }
+ buf[buflen - 1] = '\0';
+ wpa_msg(wpa_s, MSG_INFO, "%s", buf);
+ os_free(buf);
+}
+#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+#define eapol_test_eap_param_needed NULL
+#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+
+
static void eapol_test_cert_cb(void *ctx, int depth, const char *subject,
const char *cert_hash,
const struct wpabuf *cert)
@@ -484,6 +533,7 @@
ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path;
ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
+ ctx->eap_param_needed = eapol_test_eap_param_needed;
ctx->cert_cb = eapol_test_cert_cb;
ctx->cert_in_cb = 1;
ctx->set_anon_id = eapol_test_set_anon_id;
@@ -501,6 +551,7 @@
eapol_conf.required_keys = 0;
eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
eapol_conf.workaround = ssid->eap_workaround;
+ eapol_conf.external_sim = wpa_s->conf->external_sim;
eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
@@ -1094,6 +1145,7 @@
int main(int argc, char *argv[])
{
+ struct wpa_global global;
struct wpa_supplicant wpa_s;
int c, ret = 1, wait_for_monitor = 0, save_config = 0;
char *as_addr = "127.0.0.1";
@@ -1230,8 +1282,12 @@
return -1;
}
+ os_memset(&global, 0, sizeof(global));
os_memset(&wpa_s, 0, sizeof(wpa_s));
+ wpa_s.global = &global;
eapol_test.wpa_s = &wpa_s;
+ dl_list_init(&wpa_s.bss);
+ dl_list_init(&wpa_s.bss_id);
wpa_s.conf = wpa_config_read(conf, NULL);
if (wpa_s.conf == NULL) {
printf("Failed to parse configuration file '%s'.\n", conf);
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 7700595..fdf25b5 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -278,7 +278,8 @@
#ifdef PCSC_FUNCS
int aka = 0, sim = 0;
- if (ssid->eap.pcsc == NULL || wpa_s->scard != NULL)
+ if (ssid->eap.pcsc == NULL || wpa_s->scard != NULL ||
+ wpa_s->conf->external_sim)
return 0;
if (ssid->eap.eap_methods == NULL) {
@@ -1506,6 +1507,43 @@
}
+#ifdef CONFIG_INTERWORKING
+
+static int wpas_qos_map_set(struct wpa_supplicant *wpa_s, const u8 *qos_map,
+ size_t len)
+{
+ int res;
+
+ wpa_hexdump(MSG_DEBUG, "Interworking: QoS Map Set", qos_map, len);
+ res = wpa_drv_set_qos_map(wpa_s, qos_map, len);
+ if (res) {
+ wpa_printf(MSG_DEBUG, "Interworking: Failed to configure QoS Map Set to the driver");
+ }
+
+ return res;
+}
+
+
+static void interworking_process_assoc_resp(struct wpa_supplicant *wpa_s,
+ const u8 *ies, size_t ies_len)
+{
+ struct ieee802_11_elems elems;
+
+ if (ies == NULL)
+ return;
+
+ if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed)
+ return;
+
+ if (elems.qos_map_set) {
+ wpas_qos_map_set(wpa_s, elems.qos_map_set,
+ elems.qos_map_set_len);
+ }
+}
+
+#endif /* CONFIG_INTERWORKING */
+
+
static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
@@ -1530,6 +1568,10 @@
wnm_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
data->assoc_info.resp_ies_len);
#endif /* CONFIG_WNM */
+#ifdef CONFIG_INTERWORKING
+ interworking_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len);
+#endif /* CONFIG_INTERWORKING */
}
if (data->assoc_info.beacon_ies)
wpa_hexdump(MSG_DEBUG, "beacon_ies",
@@ -2958,6 +3000,19 @@
break;
}
#endif /* CONFIG_TDLS */
+#ifdef CONFIG_INTERWORKING
+ if (data->rx_action.category == WLAN_ACTION_QOS &&
+ data->rx_action.len >= 1 &&
+ data->rx_action.data[0] == QOS_QOS_MAP_CONFIG) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Interworking: Received QoS Map Configure frame from "
+ MACSTR, MAC2STR(data->rx_action.sa));
+ if (os_memcmp(data->rx_action.sa, wpa_s->bssid, ETH_ALEN)
+ == 0)
+ wpas_qos_map_set(wpa_s, data->rx_action.data + 1,
+ data->rx_action.len - 1);
+ break;
+ }
+#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_P2P
wpas_p2p_rx_action(wpa_s, data->rx_action.da,
data->rx_action.sa,
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index 06a97d3..f9885e3 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -1,7 +1,7 @@
/*
* Generic advertisement service (GAS) query
* Copyright (c) 2009, Atheros Communications
- * Copyright (c) 2011, Qualcomm Atheros
+ * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -21,6 +21,8 @@
/** GAS query timeout in seconds */
#define GAS_QUERY_TIMEOUT_PERIOD 2
+/** Retry period for GAS query requests in milliseconds */
+#define GAS_SERVICE_RETRY_PERIOD_MS 500
/**
@@ -35,6 +37,7 @@
unsigned int offchannel_tx_started:1;
int freq;
u16 status_code;
+ struct wpabuf *req;
struct wpabuf *adv_proto;
struct wpabuf *resp;
void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
@@ -50,11 +53,13 @@
struct gas_query {
struct wpa_supplicant *wpa_s;
struct dl_list pending; /* struct gas_query_pending */
+ struct gas_query_pending *current;
};
static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx);
static void gas_query_timeout(void *eloop_data, void *user_ctx);
+static void gas_service_timeout(void *eloop_data, void *user_ctx);
/**
@@ -81,13 +86,17 @@
struct gas_query_pending *query,
enum gas_query_result result)
{
+ if (gas->current == query)
+ gas->current = NULL;
if (query->offchannel_tx_started)
offchannel_send_action_done(gas->wpa_s);
eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
eloop_cancel_timeout(gas_query_timeout, gas, query);
+ eloop_cancel_timeout(gas_service_timeout, gas, query);
dl_list_del(&query->list);
query->cb(query->ctx, query->addr, query->dialog_token, result,
query->adv_proto, query->resp, query->status_code);
+ wpabuf_free(query->req);
wpabuf_free(query->adv_proto);
wpabuf_free(query->resp);
os_free(query);
@@ -138,6 +147,44 @@
}
+static void gas_query_tx_status(struct wpa_supplicant *wpa_s,
+ unsigned int freq, const u8 *dst,
+ const u8 *src, const u8 *bssid,
+ const u8 *data, size_t data_len,
+ enum offchannel_send_action_result result)
+{
+ struct gas_query_pending *query;
+ struct gas_query *gas = wpa_s->gas;
+
+ if (gas->current == NULL) {
+ wpa_printf(MSG_DEBUG, "GAS: Unexpected TX status: freq=%u dst="
+ MACSTR " result=%d - no query in progress",
+ freq, MAC2STR(dst), result);
+ return;
+ }
+
+ query = gas->current;
+
+ wpa_printf(MSG_DEBUG, "GAS: TX status: freq=%u dst=" MACSTR
+ " result=%d query=%p dialog_token=%u",
+ freq, MAC2STR(dst), result, query, query->dialog_token);
+ if (os_memcmp(dst, query->addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "GAS: TX status for unexpected destination");
+ return;
+ }
+
+ if (result == OFFCHANNEL_SEND_ACTION_SUCCESS) {
+ eloop_cancel_timeout(gas_query_timeout, gas, query);
+ eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0,
+ gas_query_timeout, gas, query);
+ }
+ if (result == OFFCHANNEL_SEND_ACTION_FAILED) {
+ eloop_cancel_timeout(gas_query_timeout, gas, query);
+ eloop_register_timeout(0, 0, gas_query_timeout, gas, query);
+ }
+}
+
+
static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query,
struct wpabuf *req)
{
@@ -148,7 +195,7 @@
res = offchannel_send_action(gas->wpa_s, query->freq, query->addr,
gas->wpa_s->own_addr, query->addr,
wpabuf_head(req), wpabuf_len(req), 1000,
- NULL, 0);
+ gas_query_tx_status, 0);
if (res == 0)
query->offchannel_tx_started = 1;
return res;
@@ -426,12 +473,50 @@
struct gas_query *gas = eloop_data;
struct gas_query_pending *query = user_ctx;
- wpa_printf(MSG_DEBUG, "GAS: No response received for query to " MACSTR,
- MAC2STR(query->addr));
+ wpa_printf(MSG_DEBUG, "GAS: No response received for query to " MACSTR
+ " dialog token %u",
+ MAC2STR(query->addr), query->dialog_token);
gas_query_done(gas, query, GAS_QUERY_TIMEOUT);
}
+static void gas_service_timeout(void *eloop_data, void *user_ctx)
+{
+ struct gas_query *gas = eloop_data;
+ struct wpa_supplicant *wpa_s = gas->wpa_s;
+ struct gas_query_pending *query = user_ctx;
+ int conn;
+
+ conn = wpas_wpa_is_in_progress(wpa_s, 1);
+ if (conn || wpa_s->scanning || gas->current) {
+ wpa_printf(MSG_DEBUG, "GAS: Delaying GAS query Tx while another operation is in progress:%s%s%s",
+ conn ? " connection" : "",
+ wpa_s->scanning ? " scanning" : "",
+ gas->current ? " gas_query" : "");
+ eloop_register_timeout(
+ GAS_SERVICE_RETRY_PERIOD_MS / 1000,
+ (GAS_SERVICE_RETRY_PERIOD_MS % 1000) * 1000,
+ gas_service_timeout, gas, query);
+ return;
+ }
+
+ if (gas_query_tx(gas, query, query->req) < 0) {
+ wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
+ MACSTR, MAC2STR(query->addr));
+ dl_list_del(&query->list);
+ wpabuf_free(query->req);
+ os_free(query);
+ return;
+ }
+ gas->current = query;
+
+ wpa_printf(MSG_DEBUG, "GAS: Starting query timeout for dialog token %u",
+ query->dialog_token);
+ eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0,
+ gas_query_timeout, gas, query);
+}
+
+
static int gas_query_dialog_token_available(struct gas_query *gas,
const u8 *dst, u8 dialog_token)
{
@@ -451,7 +536,8 @@
* @gas: GAS query data from gas_query_init()
* @dst: Destination MAC address for the query
* @freq: Frequency (in MHz) for the channel on which to send the query
- * @req: GAS query payload
+ * @req: GAS query payload (to be freed by gas_query module in case of success
+ * return)
* @cb: Callback function for reporting GAS query result and response
* @ctx: Context pointer to use with the @cb call
* Returns: dialog token (>= 0) on success or -1 on failure
@@ -490,22 +576,15 @@
query->freq = freq;
query->cb = cb;
query->ctx = ctx;
+ query->req = req;
dl_list_add(&gas->pending, &query->list);
*(wpabuf_mhead_u8(req) + 2) = dialog_token;
wpa_printf(MSG_DEBUG, "GAS: Starting request for " MACSTR
" dialog_token %u", MAC2STR(dst), dialog_token);
- 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;
- }
- eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0, gas_query_timeout,
- gas, query);
+ eloop_register_timeout(0, 0, gas_service_timeout, gas, query);
return dialog_token;
}
@@ -526,3 +605,9 @@
gas_query_done(gas, query, GAS_QUERY_CANCELLED);
}
+
+
+int gas_query_in_progress(struct gas_query *gas)
+{
+ return gas->current != NULL;
+}
diff --git a/wpa_supplicant/gas_query.h b/wpa_supplicant/gas_query.h
index 5c3d161..6b6c77c 100644
--- a/wpa_supplicant/gas_query.h
+++ b/wpa_supplicant/gas_query.h
@@ -18,6 +18,7 @@
void gas_query_deinit(struct gas_query *gas);
int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
const u8 *bssid, const u8 *data, size_t len, int freq);
+int gas_query_in_progress(struct gas_query *gas);
/**
* enum gas_query_result - GAS query result
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
index 4048cf7..5f30313 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -125,12 +125,12 @@
res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
if (res < 0) {
wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+ wpabuf_free(buf);
ret = -1;
} else
wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
"%u", res);
- wpabuf_free(buf);
return ret;
}
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 36f75a1..e294917 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -112,6 +112,8 @@
for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
if (cred->roaming_consortium_len)
return 1;
+ if (cred->required_roaming_consortium_len)
+ return 1;
}
return 0;
}
@@ -242,6 +244,7 @@
interworking_anqp_resp_cb, wpa_s);
if (res < 0) {
wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+ wpabuf_free(buf);
ret = -1;
eloop_register_timeout(0, 0, interworking_continue_anqp, wpa_s,
NULL);
@@ -249,7 +252,6 @@
wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
"%u", res);
- wpabuf_free(buf);
return ret;
}
@@ -944,6 +946,27 @@
}
+static int cred_no_required_oi_match(struct wpa_cred *cred, struct wpa_bss *bss)
+{
+ const u8 *ie;
+
+ if (cred->required_roaming_consortium_len == 0)
+ return 0;
+
+ ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
+
+ if (ie == NULL &&
+ (bss->anqp == NULL || bss->anqp->roaming_consortium == NULL))
+ return 1;
+
+ return !roaming_consortium_match(ie,
+ bss->anqp ?
+ bss->anqp->roaming_consortium : NULL,
+ cred->required_roaming_consortium,
+ cred->required_roaming_consortium_len);
+}
+
+
static int cred_excluded_ssid(struct wpa_cred *cred, struct wpa_bss *bss)
{
size_t i;
@@ -991,6 +1014,8 @@
if (cred_excluded_ssid(cred, bss))
continue;
+ if (cred_no_required_oi_match(cred, bss))
+ continue;
if (selected == NULL ||
selected->priority < cred->priority)
@@ -1100,6 +1125,11 @@
wpa_config_set_quoted(ssid, "ca_cert", cred->ca_cert) < 0)
return -1;
+ if (cred->domain_suffix_match && cred->domain_suffix_match[0] &&
+ wpa_config_set_quoted(ssid, "domain_suffix_match",
+ cred->domain_suffix_match) < 0)
+ return -1;
+
return 0;
}
@@ -1377,7 +1407,8 @@
#endif /* CONFIG_EAP_PROXY */
if (cred->imsi == NULL || !cred->imsi[0] ||
- cred->milenage == NULL || !cred->milenage[0])
+ (!wpa_s->conf->external_sim &&
+ (cred->milenage == NULL || !cred->milenage[0])))
continue;
sep = os_strchr(cred->imsi, '-');
@@ -1404,6 +1435,8 @@
if (ret) {
if (cred_excluded_ssid(cred, bss))
continue;
+ if (cred_no_required_oi_match(cred, bss))
+ continue;
if (selected == NULL ||
selected->priority < cred->priority)
selected = cred;
@@ -1446,6 +1479,8 @@
if (nai_realm_find_eap(cred, &realm[i])) {
if (cred_excluded_ssid(cred, bss))
continue;
+ if (cred_no_required_oi_match(cred, bss))
+ continue;
if (selected == NULL ||
selected->priority < cred->priority)
selected = cred;
@@ -1514,6 +1549,7 @@
struct wpa_cred *cred,
struct wpabuf *domain_names)
{
+ size_t i;
#ifdef INTERWORKING_3GPP
char nai[100], *realm;
@@ -1528,6 +1564,12 @@
mnc_len = wpa_s->mnc_len;
}
#endif /* CONFIG_PCSC */
+#ifdef CONFIG_EAP_PROXY
+ else if (cred->pcsc && wpa_s->mnc_len > 0 && wpa_s->imsi[0]) {
+ imsi = wpa_s->imsi;
+ mnc_len = wpa_s->mnc_len;
+ }
+#endif /* CONFIG_EAP_PROXY */
if (domain_names &&
imsi && build_root_nai(nai, sizeof(nai), imsi, mnc_len, 0) == 0) {
realm = os_strchr(nai, '@');
@@ -1544,10 +1586,12 @@
if (domain_names == NULL || 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;
+ for (i = 0; i < cred->num_domain; i++) {
+ wpa_printf(MSG_DEBUG, "Interworking: Search for match with "
+ "home SP FQDN %s", cred->domain[i]);
+ if (domain_name_list_contains(domain_names, cred->domain[i]))
+ return 1;
+ }
return 0;
}
@@ -1833,12 +1877,12 @@
res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
if (res < 0) {
wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+ wpabuf_free(buf);
ret = -1;
} else
wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
"%u", res);
- wpabuf_free(buf);
return ret;
}
@@ -2133,11 +2177,11 @@
res = gas_query_req(wpa_s->gas, dst, freq, buf, gas_resp_cb, wpa_s);
if (res < 0) {
wpa_printf(MSG_DEBUG, "GAS: Failed to send Query Request");
+ wpabuf_free(buf);
ret = -1;
} else
wpa_printf(MSG_DEBUG, "GAS: Query started with dialog token "
"%u", res);
- wpabuf_free(buf);
return ret;
}
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 86bcf87..48cd429 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -3794,7 +3794,8 @@
if (bss) {
freq = bss->freq;
wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
- "from BSS table: %d MHz", freq);
+ "from BSS table: %d MHz (SSID %s)", freq,
+ wpa_ssid_txt(bss->ssid, bss->ssid_len));
}
if (freq > 0) {
u16 method;
@@ -4009,6 +4010,9 @@
res.freq = bss->freq;
res.ssid_len = bss->ssid_len;
os_memcpy(res.ssid, bss->ssid, bss->ssid_len);
+ wpa_printf(MSG_DEBUG, "P2P: Join target GO operating frequency "
+ "from BSS table: %d MHz (SSID %s)", bss->freq,
+ wpa_ssid_txt(bss->ssid, bss->ssid_len));
}
if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
@@ -5261,7 +5265,7 @@
u8 *bssid = NULL;
struct wpa_ssid *ssid;
int persistent;
- int force_freq = 0, pref_freq = 0;
+ int freq = 0, force_freq = 0, pref_freq = 0;
int res;
wpa_s->p2p_persistent_go_freq = 0;
@@ -5293,6 +5297,7 @@
bssid = wpa_s->own_addr;
if (go_dev_addr == NULL)
go_dev_addr = wpa_s->global->p2p_dev_addr;
+ freq = ssid->frequency;
} else {
role = P2P_INVITE_ROLE_CLIENT;
if (wpa_s->wpa_state < WPA_ASSOCIATED) {
@@ -5304,6 +5309,8 @@
if (go_dev_addr == NULL &&
!is_zero_ether_addr(wpa_s->go_dev_addr))
go_dev_addr = wpa_s->go_dev_addr;
+ freq = wpa_s->current_bss ? wpa_s->current_bss->freq :
+ (int) wpa_s->assoc_freq;
}
wpa_s->parent->pending_invite_ssid_id = -1;
@@ -5315,7 +5322,7 @@
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
- res = wpas_p2p_setup_freqs(wpa_s, 0, &force_freq, &pref_freq);
+ res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq);
if (res)
return res;
wpas_p2p_set_own_freq_preference(wpa_s, force_freq);
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 7eec468..dc98361 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -21,6 +21,7 @@
#include "hs20_supplicant.h"
#include "notify.h"
#include "bss.h"
+#include "gas_query.h"
#include "scan.h"
@@ -595,7 +596,7 @@
}
#ifdef CONFIG_P2P
- if (wpas_p2p_in_progress(wpa_s) || wpas_wpa_is_in_progress(wpa_s)) {
+ if (wpas_p2p_in_progress(wpa_s) || wpas_wpa_is_in_progress(wpa_s, 0)) {
if (wpa_s->sta_scan_pending &&
wpas_p2p_in_progress(wpa_s) == 2 &&
wpa_s->global->p2p_cb_on_scan_complete) {
@@ -611,6 +612,14 @@
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_GAS
+ if (gas_query_in_progress(wpa_s->gas)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Delay scan while GAS query is in progress");
+ wpa_supplicant_req_scan(wpa_s, 1, 0);
+ return;
+ }
+#endif /* CONFIG_GAS */
+
if (wpa_s->conf->ap_scan == 2)
max_ssids = 1;
else {
@@ -887,8 +896,10 @@
new_int.usec = remaining.usec;
}
- eloop_register_timeout(new_int.sec, new_int.usec, wpa_supplicant_scan,
- wpa_s, NULL);
+ if (cancelled) {
+ eloop_register_timeout(new_int.sec, new_int.usec,
+ wpa_supplicant_scan, wpa_s, NULL);
+ }
wpa_s->scan_interval = sec;
}
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 6727526..8c900c2 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -625,7 +625,7 @@
"wps_nfc_dev_pw", "ext_password_backend",
"p2p_go_max_inactivity", "auto_interworking", "okc", "pmf",
"sae_groups", "dtim_period", "beacon_int", "ap_vendor_elements",
- "ignore_old_scan_res", "freq_list"
+ "ignore_old_scan_res", "freq_list", "external_sim"
};
int i, num_fields = sizeof(fields) / sizeof(fields[0]);
@@ -1270,6 +1270,38 @@
}
+static int wpa_cli_cmd_sim(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ char cmd[256], *pos, *end;
+ int i, ret;
+
+ if (argc < 2) {
+ printf("Invalid SIM command: needs two arguments "
+ "(network id and SIM operation response)\n");
+ return -1;
+ }
+
+ end = cmd + sizeof(cmd);
+ pos = cmd;
+ ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "SIM-%s:%s",
+ argv[0], argv[1]);
+ if (ret < 0 || ret >= end - pos) {
+ printf("Too long SIM command.\n");
+ return -1;
+ }
+ pos += ret;
+ for (i = 2; i < argc; i++) {
+ ret = os_snprintf(pos, end - pos, " %s", argv[i]);
+ if (ret < 0 || ret >= end - pos) {
+ printf("Too long SIM command.\n");
+ return -1;
+ }
+ pos += ret;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -2488,6 +2520,9 @@
cli_cmd_flag_sensitive,
"<network id> <passphrase> = configure private key passphrase\n"
" for an SSID" },
+ { "sim", wpa_cli_cmd_sim, NULL,
+ cli_cmd_flag_sensitive,
+ "<network id> <pin> = report SIM operation result" },
{ "bssid", wpa_cli_cmd_bssid, NULL,
cli_cmd_flag_none,
"<network id> <BSSID> = set preferred BSSID for an SSID" },
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index f924316..fc3471d 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -303,6 +303,7 @@
!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) &&
wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
wpa_s->key_mgmt != WPA_KEY_MGMT_WPS;
+ eapol_conf.external_sim = wpa_s->conf->external_sim;
eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
#endif /* IEEE8021X_EAPOL */
}
@@ -1225,6 +1226,9 @@
#endif /* CONFIG_INTERWORKING */
break;
case 4: /* Bits 32-39 */
+#ifdef CONFIG_INTERWORKING
+ *pos |= 0x01; /* Bit 32 - QoS Map */
+#endif /* CONFIG_INTERWORKING */
break;
case 5: /* Bits 40-47 */
break;
@@ -3768,6 +3772,10 @@
if (ssid == wpa_s->current_ssid)
wpa_s->reassociate = 1;
break;
+ case WPA_CTRL_REQ_SIM:
+ os_free(eap->external_sim_resp);
+ eap->external_sim_resp = os_strdup(value);
+ break;
default:
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field);
return -1;
@@ -3958,37 +3966,53 @@
}
+static int wpas_conn_in_progress(struct wpa_supplicant *wpa_s)
+{
+ return wpa_s->wpa_state >= WPA_AUTHENTICATING &&
+ wpa_s->wpa_state != WPA_COMPLETED;
+}
+
+
/**
* wpas_wpa_is_in_progress - Check whether a connection is in progress
* @wpa_s: Pointer to wpa_supplicant data
+ * @include_current: Whether to consider specified interface
*
* This function is to check if the wpa state is in beginning of the connection
* during 4-way handshake or group key handshake with WPA on any shared
* interface.
*/
-int wpas_wpa_is_in_progress(struct wpa_supplicant *wpa_s)
+int wpas_wpa_is_in_progress(struct wpa_supplicant *wpa_s, int include_current)
{
const char *rn, *rn2;
struct wpa_supplicant *ifs;
- if (!wpa_s->driver->get_radio_name)
+ if (!wpa_s->driver->get_radio_name) {
+ if (include_current && wpas_conn_in_progress(wpa_s)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Connection is in progress on interface %s - defer",
+ wpa_s->ifname);
+ return 1;
+ }
+
return 0;
+ }
rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
if (rn == NULL || rn[0] == '\0')
return 0;
for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
- if (ifs == wpa_s || !ifs->driver->get_radio_name)
+ if (!include_current && ifs == wpa_s)
+ continue;
+ if (!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->wpa_state >= WPA_AUTHENTICATING &&
- ifs->wpa_state != WPA_COMPLETED) {
+ if (wpas_conn_in_progress(ifs)) {
wpa_dbg(wpa_s, MSG_DEBUG, "Connection is in progress "
- "on interface %s - defer scan", ifs->ifname);
+ "on interface %s - defer", ifs->ifname);
return 1;
}
}
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index d73d371..6414f44 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -399,9 +399,11 @@
# milenage: Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN>
# format
#
-# domain: Home service provider FQDN
+# domain: Home service provider FQDN(s)
# This is used to compare against the Domain Name List to figure out
-# whether the AP is operated by the Home SP.
+# whether the AP is operated by the Home SP. Multiple domain entries can
+# be used to configure alternative FQDNs that will be considered home
+# networks.
#
# roaming_consortium: Roaming Consortium OI
# If roaming_consortium_len is non-zero, this field contains the
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index be493cf..d44f0a2 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -823,7 +823,7 @@
size_t ssid_len);
void wpas_request_connection(struct wpa_supplicant *wpa_s);
int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf);
-int wpas_wpa_is_in_progress(struct wpa_supplicant *wpa_s);
+int wpas_wpa_is_in_progress(struct wpa_supplicant *wpa_s, int include_current);
/**
* wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 61a42bd..ab6cdca 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -611,6 +611,8 @@
return WPA_CTRL_REQ_EAP_OTP;
else if (os_strcmp(field, "PASSPHRASE") == 0)
return WPA_CTRL_REQ_EAP_PASSPHRASE;
+ else if (os_strcmp(field, "SIM") == 0)
+ return WPA_CTRL_REQ_SIM;
return WPA_CTRL_REQ_UNKNOWN;
}
@@ -647,6 +649,9 @@
*txt = "Private key passphrase";
ret = "PASSPHRASE";
break;
+ case WPA_CTRL_REQ_SIM:
+ ret = "SIM";
+ break;
default:
break;
}
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index a2b941c..0d75464 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -882,6 +882,8 @@
int id;
struct wpa_ssid *ssid, *remove_ssid = NULL, *prev_current;
+ wpa_s->after_wps = 0;
+
prev_current = wpa_s->current_ssid;
/* Enable the networks disabled during wpas_wps_reassoc */
@@ -1157,6 +1159,8 @@
wpas_wps_clear_ap_info(wpa_s);
}
+ wpa_s->after_wps = 0;
+
return 0;
}
@@ -2465,6 +2469,9 @@
void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid)
{
struct wps_ap_info *ap;
+
+ wpa_s->after_wps = 0;
+
if (!wpa_s->wps_ap_iter)
return;
ap = wpas_wps_get_ap_info(wpa_s, bssid);