aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve Kondik <shade@chemlab.org>2013-12-13 06:23:24 -0500
committerSteve Kondik <shade@chemlab.org>2013-12-13 06:23:24 -0500
commit14a5afdd5255623482f78402bc46dad276f8143b (patch)
tree68ff819fd7543ef1115c1f154a587bfc0ffe62a9
parent67128b60aaa3785bd88781f451fc2478d5f8076f (diff)
parentb740a47e36e811907a8d191fbef40bfe58c24aa7 (diff)
downloadandroid_external_wpa_supplicant_8-14a5afdd5255623482f78402bc46dad276f8143b.tar.gz
android_external_wpa_supplicant_8-14a5afdd5255623482f78402bc46dad276f8143b.tar.bz2
android_external_wpa_supplicant_8-14a5afdd5255623482f78402bc46dad276f8143b.zip
Merge branch 'kk_2.7_rb1.15' of git://codeaurora.org/platform/external/wpa_supplicant_8 into cm-11.0
Change-Id: I8033a00b2741fcddca9aa27706dea99ebc77ab9c
-rw-r--r--src/ap/ap_drv_ops.h7
-rw-r--r--src/ap/drv_callbacks.c10
-rw-r--r--src/ap/hostapd.c62
-rw-r--r--src/ap/hostapd.h3
-rw-r--r--src/common/wpa_ctrl.h1
-rw-r--r--src/drivers/driver.h23
-rw-r--r--src/drivers/driver_nl80211.c67
-rw-r--r--src/p2p/p2p.c3
-rw-r--r--src/p2p/p2p.h3
-rw-r--r--src/p2p/p2p_go_neg.c6
-rw-r--r--src/p2p/p2p_i.h3
-rw-r--r--src/p2p/p2p_invitation.c10
-rw-r--r--src/p2p/p2p_utils.c29
-rw-r--r--wpa_supplicant/README-HS206
-rw-r--r--wpa_supplicant/config.c16
-rw-r--r--wpa_supplicant/config.h13
-rw-r--r--wpa_supplicant/config_file.c9
-rw-r--r--wpa_supplicant/ctrl_iface.c57
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers_p2p.c2
-rw-r--r--wpa_supplicant/events.c62
-rw-r--r--wpa_supplicant/interworking.c113
-rw-r--r--wpa_supplicant/p2p_supplicant.c61
-rw-r--r--wpa_supplicant/p2p_supplicant.h3
-rw-r--r--wpa_supplicant/wpa_supplicant.c32
-rw-r--r--wpa_supplicant/wpa_supplicant.conf6
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h1
26 files changed, 500 insertions, 108 deletions
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 23277b6b..423cd8d3 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -235,4 +235,11 @@ static inline int hostapd_drv_get_survey(struct hostapd_data *hapd,
return hapd->driver->get_survey(hapd->drv_priv, freq);
}
+static inline int hostapd_get_country(struct hostapd_data *hapd, char *alpha2)
+{
+ if (hapd->driver == NULL || hapd->driver->get_country == NULL)
+ return -1;
+ return hapd->driver->get_country(hapd->drv_priv, alpha2);
+}
+
#endif /* AP_DRV_OPS */
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index d6bc98d0..4b8a1a9d 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -929,6 +929,16 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
case EVENT_SURVEY:
hostapd_event_get_survey(hapd, &data->survey_results);
break;
+#ifdef NEED_AP_MLME
+ case EVENT_CHANNEL_LIST_CHANGED:
+ /* channel list changed (regulatory?), update channel list */
+ /* TODO: check this. hostapd_get_hw_features() initializes
+ * too much stuff. */
+ /* hostapd_get_hw_features(hapd->iface); */
+ hostapd_channel_list_updated(
+ hapd->iface, data->channel_list_changed.initiator);
+ break;
+#endif /* NEED_AP_MLME */
default:
wpa_printf(MSG_DEBUG, "Unknown event %d", event);
break;
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index fd1ca2b3..3852d146 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -37,6 +37,8 @@
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd);
static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd);
+static int setup_interface2(struct hostapd_iface *iface);
+static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx);
extern int wpa_debug_level;
extern struct wpa_driver_ops *wpa_drivers[];
@@ -325,6 +327,8 @@ static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
*/
static void hostapd_cleanup_iface(struct hostapd_iface *iface)
{
+ eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
+
hostapd_cleanup_iface_partial(iface);
hostapd_config_free(iface->conf);
iface->conf = NULL;
@@ -882,11 +886,39 @@ static void hostapd_set_acl(struct hostapd_data *hapd)
}
+static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_iface *iface = eloop_ctx;
+
+ if (!iface->wait_channel_update) {
+ wpa_printf(MSG_INFO, "Channel list update timeout, but interface was not waiting for it");
+ return;
+ }
+
+ /*
+ * It is possible that the existing channel list is acceptable, so try
+ * to proceed.
+ */
+ wpa_printf(MSG_DEBUG, "Channel list update timeout - try to continue anyway");
+ setup_interface2(iface);
+}
+
+
+void hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator)
+{
+ if (!iface->wait_channel_update || initiator != REGDOM_SET_BY_USER)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Channel list updated - continue setup");
+ eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
+ setup_interface2(iface);
+}
+
+
static int setup_interface(struct hostapd_iface *iface)
{
struct hostapd_data *hapd = iface->bss[0];
size_t i;
- char country[4];
/*
* Make sure that all BSSes get configured with a pointer to the same
@@ -901,14 +933,39 @@ static int setup_interface(struct hostapd_iface *iface)
return -1;
if (hapd->iconf->country[0] && hapd->iconf->country[1]) {
+ char country[4], previous_country[4];
+
+ if (hostapd_get_country(hapd, previous_country) < 0)
+ previous_country[0] = '\0';
+
os_memcpy(country, hapd->iconf->country, 3);
country[3] = '\0';
if (hostapd_set_country(hapd, country) < 0) {
wpa_printf(MSG_ERROR, "Failed to set country code");
return -1;
}
+
+ wpa_printf(MSG_DEBUG, "Previous country code %s, new country code %s",
+ previous_country, country);
+
+ if (os_strncmp(previous_country, country, 2) != 0) {
+ wpa_printf(MSG_DEBUG, "Continue interface setup after channel list update");
+ iface->wait_channel_update = 1;
+ eloop_register_timeout(1, 0,
+ channel_list_update_timeout,
+ iface, NULL);
+ return 0;
+ }
}
+ return setup_interface2(iface);
+}
+
+
+static int setup_interface2(struct hostapd_iface *iface)
+{
+ iface->wait_channel_update = 0;
+
if (hostapd_get_hw_features(iface)) {
/* Not all drivers support this yet, so continue without hw
* feature data. */
@@ -1105,6 +1162,9 @@ void hostapd_interface_deinit(struct hostapd_iface *iface)
if (iface == NULL)
return;
+ eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
+ iface->wait_channel_update = 0;
+
hostapd_cleanup_iface_pre(iface);
for (j = 0; j < iface->num_bss; j++) {
struct hostapd_data *hapd = iface->bss[j];
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index dbf1b52f..73ea73e4 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -251,6 +251,8 @@ struct hostapd_iface {
size_t num_bss;
struct hostapd_data **bss;
+ unsigned int wait_channel_update:1;
+
int num_ap; /* number of entries in ap_list */
struct ap_info *ap_list; /* AP info list head */
struct ap_info *ap_hash[STA_HASH_SIZE];
@@ -353,6 +355,7 @@ int hostapd_reload_iface(struct hostapd_iface *hapd_iface);
int hostapd_disable_iface(struct hostapd_iface *hapd_iface);
int hostapd_add_iface(struct hapd_interfaces *ifaces, char *buf);
int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf);
+void hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator);
/* utils.c */
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index fd7f686c..1156043f 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -149,6 +149,7 @@ extern "C" {
#define INTERWORKING_AP "INTERWORKING-AP "
#define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH "
+#define INTERWORKING_ALREADY_CONNECTED "INTERWORKING-ALREADY-CONNECTED "
#define GAS_RESPONSE_INFO "GAS-RESPONSE-INFO "
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index b8c98290..92db1575 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -37,6 +37,13 @@
#define HOSTAPD_CHAN_DFS_AVAILABLE 0x00000300
#define HOSTAPD_CHAN_DFS_MASK 0x00000300
+enum reg_change_initiator {
+ REGDOM_SET_BY_CORE,
+ REGDOM_SET_BY_USER,
+ REGDOM_SET_BY_DRIVER,
+ REGDOM_SET_BY_COUNTRY_IE,
+};
+
/**
* struct hostapd_channel_data - Channel information
*/
@@ -1565,6 +1572,14 @@ struct wpa_driver_ops {
int (*set_country)(void *priv, const char *alpha2);
/**
+ * get_country - Get country
+ * @priv: Private driver interface data
+ * @alpha2: Buffer for returning country code (at least 3 octets)
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*get_country)(void *priv, char *alpha2);
+
+ /**
* global_init - Global driver initialization
* Returns: Pointer to private data (global), %NULL on failure
*
@@ -3973,6 +3988,14 @@ union wpa_event_data {
unsigned int freq_filter;
struct dl_list survey_list; /* struct freq_survey */
} survey_results;
+
+ /**
+ * channel_list_changed - Data for EVENT_CHANNEL_LIST_CHANGED
+ * @initiator: Initiator of the regulatory change
+ */
+ struct channel_list_changed {
+ enum reg_change_initiator initiator;
+ } channel_list_changed;
};
/**
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 79f0292d..a1b49575 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -2608,6 +2608,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
struct nlattr **tb)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
+ union wpa_event_data data;
wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
cmd, nl80211_command_to_string(cmd), bss->ifname);
@@ -2701,8 +2702,33 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
break;
case NL80211_CMD_REG_CHANGE:
wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change");
+ if (tb[NL80211_ATTR_REG_INITIATOR] == NULL)
+ break;
+ os_memset(&data, 0, sizeof(data));
+ switch (nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR])) {
+ case NL80211_REGDOM_SET_BY_CORE:
+ data.channel_list_changed.initiator =
+ REGDOM_SET_BY_CORE;
+ break;
+ case NL80211_REGDOM_SET_BY_USER:
+ data.channel_list_changed.initiator =
+ REGDOM_SET_BY_USER;
+ break;
+ case NL80211_REGDOM_SET_BY_DRIVER:
+ data.channel_list_changed.initiator =
+ REGDOM_SET_BY_DRIVER;
+ break;
+ case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+ data.channel_list_changed.initiator =
+ REGDOM_SET_BY_COUNTRY_IE;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "nl80211: Unknown reg change initiator %d received",
+ nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR]));
+ break;
+ }
wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
- NULL);
+ &data);
break;
case NL80211_CMD_REG_BEACON_HINT:
wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint");
@@ -2910,6 +2936,44 @@ nla_put_failure:
}
+static int nl80211_get_country(struct nl_msg *msg, void *arg)
+{
+ char *alpha2 = arg;
+ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+
+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (!tb_msg[NL80211_ATTR_REG_ALPHA2]) {
+ wpa_printf(MSG_DEBUG, "nl80211: No country information available");
+ return NL_SKIP;
+ }
+ os_strlcpy(alpha2, nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]), 3);
+ return NL_SKIP;
+}
+
+
+static int wpa_driver_nl80211_get_country(void *priv, char *alpha2)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
+ alpha2[0] = '\0';
+ ret = send_and_recv_msgs(drv, msg, nl80211_get_country, alpha2);
+ if (!alpha2[0])
+ ret = -1;
+
+ return ret;
+}
+
+
static int protocol_feature_handler(struct nl_msg *msg, void *arg)
{
u32 *feat = arg;
@@ -10889,6 +10953,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.set_operstate = wpa_driver_nl80211_set_operstate,
.set_supp_port = wpa_driver_nl80211_set_supp_port,
.set_country = wpa_driver_nl80211_set_country,
+ .get_country = wpa_driver_nl80211_get_country,
.set_ap = wpa_driver_nl80211_set_ap,
.set_acl = wpa_driver_nl80211_set_acl,
.if_add = wpa_driver_nl80211_if_add,
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 738436c4..160dfc20 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -3361,7 +3361,8 @@ static void p2p_timeout_invite_listen(struct p2p_data *p2p)
if (p2p->cfg->invitation_result)
p2p->cfg->invitation_result(
p2p->cfg->cb_ctx, -1, NULL, NULL,
- p2p->invite_peer->info.p2p_device_addr);
+ p2p->invite_peer->info.p2p_device_addr,
+ 0);
}
p2p_set_state(p2p, P2P_IDLE);
}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 7f845b23..c6e5c94e 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -742,6 +742,7 @@ struct p2p_config {
* @bssid: P2P Group BSSID or %NULL if not received
* @channels: Available operating channels for the group
* @addr: Peer address
+ * @freq: Frequency (in MHz) indicated during invitation or 0
*
* This callback is used to indicate result of an Invitation procedure
* started with a call to p2p_invite(). The indicated status code is
@@ -751,7 +752,7 @@ struct p2p_config {
*/
void (*invitation_result)(void *ctx, int status, const u8 *bssid,
const struct p2p_channels *channels,
- const u8 *addr);
+ const u8 *addr, int freq);
/**
* go_connected - Check whether we are connected to a GO
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index bd583be8..17fb3293 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -418,13 +418,7 @@ void p2p_reselect_channel(struct p2p_data *p2p,
/* Prefer a 5 GHz channel */
for (i = 0; i < intersection->reg_classes; i++) {
-#ifdef ANDROID_P2P
- struct p2p_reg_class prc;
- struct p2p_reg_class *c = &prc;
- p2p_copy_reg_class(c, &intersection->reg_class[i]);
-#else
struct p2p_reg_class *c = &intersection->reg_class[i];
-#endif
if ((c->reg_class == 115 || c->reg_class == 124) &&
c->channels) {
unsigned int r;
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 81e521ec..d28aae93 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -572,9 +572,6 @@ void p2p_channels_intersect(const struct p2p_channels *a,
struct p2p_channels *res);
int p2p_channels_includes(const struct p2p_channels *channels, u8 reg_class,
u8 channel);
-#ifdef ANDROID_P2P
-size_t p2p_copy_reg_class(struct p2p_reg_class *dc, struct p2p_reg_class *sc);
-#endif
/* p2p_parse.c */
int p2p_parse_p2p_ie(const struct wpabuf *buf, struct p2p_message *msg);
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index 4fafe5ea..b5a3058e 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -428,9 +428,15 @@ void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa,
channels = &intersection;
}
- if (p2p->cfg->invitation_result)
+ if (p2p->cfg->invitation_result) {
+ int freq = p2p_channel_to_freq(p2p->op_reg_class,
+ p2p->op_channel);
+ if (freq < 0)
+ freq = 0;
p2p->cfg->invitation_result(p2p->cfg->cb_ctx, *msg.status,
- msg.group_bssid, channels, sa);
+ msg.group_bssid, channels, sa,
+ freq);
+ }
p2p_parse_free(&msg);
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index a4c48f67..f5155dcf 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -244,39 +244,10 @@ int p2p_channels_includes_freq(const struct p2p_channels *channels,
}
-#ifdef ANDROID_P2P
-static int p2p_block_op_freq(unsigned int freq)
-{
- return (freq >= 5170 && freq < 5745);
-}
-
-
-size_t p2p_copy_reg_class(struct p2p_reg_class *dc, struct p2p_reg_class *sc)
-{
- unsigned int i;
-
- dc->reg_class = sc->reg_class;
- dc->channels = 0;
- for (i=0; i < sc->channels; i++) {
- if (!p2p_block_op_freq(p2p_channel_to_freq(sc->reg_class,
- sc->channel[i]))) {
- dc->channel[dc->channels] = sc->channel[i];
- dc->channels++;
- }
- }
- return dc->channels;
-}
-#endif
-
-
int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq)
{
u8 op_reg_class, op_channel;
-#ifdef ANDROID_P2P
- if (p2p_block_op_freq(freq))
- return 0;
-#endif
if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
return 0;
return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20
index 5669c55c..7a570bdd 100644
--- a/wpa_supplicant/README-HS20
+++ b/wpa_supplicant/README-HS20
@@ -166,9 +166,11 @@ Credentials can be pre-configured for automatic network selection:
# 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/config.c b/wpa_supplicant/config.c
index 69f920da..97d59eb4 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1813,6 +1813,8 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid)
void wpa_config_free_cred(struct wpa_cred *cred)
{
+ size_t i;
+
os_free(cred->realm);
os_free(cred->username);
os_free(cred->password);
@@ -1822,6 +1824,8 @@ void wpa_config_free_cred(struct wpa_cred *cred)
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->eap_method);
os_free(cred->phase1);
@@ -2395,8 +2399,16 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
}
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;
}
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 3fe46e33..bce8d168 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -150,12 +150,19 @@ struct wpa_cred {
char *milenage;
/**
- * 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.
*/
- char *domain;
+ char **domain;
+
+ /**
+ * num_domain - Number of FQDNs in the domain array
+ */
+ size_t num_domain;
/**
* roaming_consortium - Roaming Consortium OI
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index bb0e536e..20935ce7 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -725,6 +725,8 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
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)
@@ -750,10 +752,9 @@ static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred)
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->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]);
@@ -770,7 +771,7 @@ static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred)
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=");
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index e5951e5e..545bef70 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -1579,16 +1579,19 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
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; cred->domain && 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)
@@ -2481,7 +2484,7 @@ static int wpa_supplicant_ctrl_iface_list_creds(struct wpa_supplicant *wpa_s,
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;
@@ -2566,9 +2569,16 @@ static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s,
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;
}
@@ -4244,7 +4254,8 @@ static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
return -1;
}
- return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40, NULL);
+ return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40, NULL,
+ 0);
}
@@ -5171,7 +5182,27 @@ static int wpa_supplicant_driver_cmd(struct wpa_supplicant *wpa_s, char *cmd,
{
int ret;
- ret = wpa_drv_driver_cmd(wpa_s, cmd, buf, buflen);
+ if (os_strncasecmp(cmd, "SETBAND ", 8) == 0) {
+ int val = atoi(cmd + 8);
+ /*
+ * Use driver_cmd for drivers that support it, but ignore the
+ * return value since scan requests from wpa_supplicant will
+ * provide a list of channels to scan for based on the SETBAND
+ * setting.
+ */
+ wpa_printf(MSG_DEBUG, "SETBAND: %d", val);
+ wpa_drv_driver_cmd(wpa_s, cmd, buf, buflen);
+ ret = 0;
+ if (val == 0)
+ wpa_s->setband = WPA_SETBAND_AUTO;
+ else if (val == 1)
+ wpa_s->setband = WPA_SETBAND_5G;
+ else if (val == 2)
+ wpa_s->setband = WPA_SETBAND_2G;
+ else
+ ret = -1;
+ } else
+ ret = wpa_drv_driver_cmd(wpa_s, cmd, buf, buflen);
if (ret == 0) {
if (os_strncasecmp(cmd, "COUNTRY", 7) == 0) {
struct p2p_data *p2p = wpa_s->global->p2p;
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 6ec96dfe..52b36b4a 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -347,7 +347,7 @@ DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message,
goto inv_args;
if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0,
- NULL)) {
+ NULL, 0)) {
reply = wpas_dbus_error_unknown_error(
message,
"Failed to reinvoke a persistent group");
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index fdad6254..e939e36f 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1325,10 +1325,12 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
if (wpas_p2p_scan_no_go_seen(wpa_s) == 1)
return 0;
- if (wpa_s->p2p_in_provisioning) {
+ if (wpa_s->p2p_in_provisioning ||
+ wpa_s->show_group_started) {
/*
* Use shorter wait during P2P Provisioning
- * state to speed up group formation.
+ * state and during P2P join-a-group operation
+ * to speed up group formation.
*/
timeout_sec = 0;
timeout_usec = 250000;
@@ -2469,6 +2471,51 @@ static void wpa_supplicant_event_unprot_disassoc(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_IEEE80211W */
}
+static void wpa_supplicant_update_channel_list(struct wpa_supplicant *wpa_s)
+{
+ const char *rn, *rn2;
+ struct wpa_supplicant *ifs;
+
+ if (wpa_s->drv_priv == NULL)
+ return; /* Ignore event during drv initialization */
+
+ free_hw_features(wpa_s);
+ wpa_s->hw.modes = wpa_drv_get_hw_feature_data(
+ wpa_s, &wpa_s->hw.num_modes, &wpa_s->hw.flags);
+
+#ifdef CONFIG_P2P
+ wpas_p2p_update_channel_list(wpa_s);
+#endif /* CONFIG_P2P */
+
+ /*
+ * Check other interfaces to see if they have the same radio-name. If
+ * so, they get updated with this same hw mode info.
+ */
+ if (!wpa_s->driver->get_radio_name)
+ return;
+
+ rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
+ if (rn == NULL || rn[0] == '\0')
+ return;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "Checking for other virtual interfaces "
+ "sharing same radio (%s) in event_channel_list_change", rn);
+
+ 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) {
+ wpa_printf(MSG_DEBUG, "%s: Updating hw mode",
+ ifs->ifname);
+ free_hw_features(ifs);
+ ifs->hw.modes = wpa_drv_get_hw_feature_data(
+ ifs, &ifs->hw.num_modes, &ifs->hw.flags);
+ }
+ }
+}
+
static void wpas_event_disconnect(struct wpa_supplicant *wpa_s, const u8 *addr,
u16 reason_code, int locally_generated,
@@ -3074,16 +3121,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
break;
case EVENT_CHANNEL_LIST_CHANGED:
- if (wpa_s->drv_priv == NULL)
- break; /* Ignore event during drv initialization */
-
- free_hw_features(wpa_s);
- wpa_s->hw.modes = wpa_drv_get_hw_feature_data(
- wpa_s, &wpa_s->hw.num_modes, &wpa_s->hw.flags);
-
-#ifdef CONFIG_P2P
- wpas_p2p_update_channel_list(wpa_s);
-#endif /* CONFIG_P2P */
+ wpa_supplicant_update_channel_list(wpa_s);
break;
case EVENT_INTERFACE_UNAVAILABLE:
#ifdef CONFIG_P2P
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 4c699378..06b08931 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -1,6 +1,6 @@
/*
* Interworking (IEEE 802.11u)
- * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -19,6 +19,7 @@
#include "eap_peer/eap.h"
#include "eap_peer/eap_methods.h"
#include "eapol_supp/eapol_supp_sm.h"
+#include "rsn_supp/wpa.h"
#include "wpa_supplicant_i.h"
#include "config.h"
#include "config_ssid.h"
@@ -748,6 +749,59 @@ static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix)
#endif /* INTERWORKING_3GPP */
+static int already_connected(struct wpa_supplicant *wpa_s,
+ struct wpa_cred *cred, struct wpa_bss *bss)
+{
+ struct wpa_ssid *ssid;
+
+ if (wpa_s->wpa_state < WPA_ASSOCIATED || wpa_s->current_ssid == NULL)
+ return 0;
+
+ ssid = wpa_s->current_ssid;
+ if (ssid->parent_cred != cred)
+ return 0;
+
+ if (ssid->ssid_len != bss->ssid_len ||
+ os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) != 0)
+ return 0;
+
+ return 1;
+}
+
+
+static void remove_duplicate_network(struct wpa_supplicant *wpa_s,
+ struct wpa_cred *cred,
+ struct wpa_bss *bss)
+{
+ struct wpa_ssid *ssid;
+
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (ssid->parent_cred != cred)
+ continue;
+ if (ssid->ssid_len != bss->ssid_len ||
+ os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) != 0)
+ continue;
+
+ break;
+ }
+
+ if (ssid == NULL)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Interworking: Remove duplicate network entry for the same credential");
+
+ if (ssid == wpa_s->current_ssid) {
+ wpa_sm_set_config(wpa_s->wpa, NULL);
+ eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+ wpa_supplicant_deauthenticate(wpa_s,
+ WLAN_REASON_DEAUTH_LEAVING);
+ }
+
+ wpas_notify_network_removed(wpa_s, ssid);
+ wpa_config_remove_network(wpa_s->conf, ssid->id);
+}
+
+
static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
@@ -783,6 +837,14 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " (3GPP)",
MAC2STR(bss->bssid));
+ if (already_connected(wpa_s, cred, bss)) {
+ wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
+ MAC2STR(bss->bssid));
+ return 0;
+ }
+
+ remove_duplicate_network(wpa_s, cred, bss);
+
ssid = wpa_config_add_network(wpa_s->conf);
if (ssid == NULL)
return -1;
@@ -1114,6 +1176,14 @@ static int interworking_connect_roaming_consortium(
wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " based on "
"roaming consortium match", MAC2STR(bss->bssid));
+ if (already_connected(wpa_s, cred, bss)) {
+ wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
+ MAC2STR(bss->bssid));
+ return 0;
+ }
+
+ remove_duplicate_network(wpa_s, cred, bss);
+
ssid = wpa_config_add_network(wpa_s->conf);
if (ssid == NULL)
return -1;
@@ -1167,6 +1237,12 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
if (wpa_s->conf->cred == NULL || bss == NULL)
return -1;
+ if (disallowed_bssid(wpa_s, bss->bssid) ||
+ disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) {
+ wpa_printf(MSG_DEBUG, "Interworking: Reject connection to disallowed BSS "
+ MACSTR, MAC2STR(bss->bssid));
+ return -1;
+ }
ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
if (ie == NULL || ie[1] == 0) {
wpa_printf(MSG_DEBUG, "Interworking: No SSID known for "
@@ -1249,6 +1325,15 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR,
MAC2STR(bss->bssid));
+ if (already_connected(wpa_s, cred, bss)) {
+ wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
+ MAC2STR(bss->bssid));
+ nai_realm_free(realm, count);
+ return 0;
+ }
+
+ remove_duplicate_network(wpa_s, cred, bss);
+
ssid = wpa_config_add_network(wpa_s->conf);
if (ssid == NULL) {
nai_realm_free(realm, count);
@@ -1483,6 +1568,13 @@ static struct wpa_cred * interworking_credentials_available(
{
struct wpa_cred *cred, *cred2;
+ if (disallowed_bssid(wpa_s, bss->bssid) ||
+ disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) {
+ wpa_printf(MSG_DEBUG, "Interworking: Ignore disallowed BSS "
+ MACSTR, MAC2STR(bss->bssid));
+ return NULL;
+ }
+
cred = interworking_credentials_available_realm(wpa_s, bss);
cred2 = interworking_credentials_available_3gpp(wpa_s, bss);
if (cred && cred2 && cred2->priority >= cred->priority)
@@ -1532,6 +1624,8 @@ int interworking_home_sp_cred(struct wpa_supplicant *wpa_s,
struct wpa_cred *cred,
struct wpabuf *domain_names)
{
+ size_t i;
+ int ret = -1;
#ifdef INTERWORKING_3GPP
char nai[100], *realm;
@@ -1556,16 +1650,20 @@ int interworking_home_sp_cred(struct wpa_supplicant *wpa_s,
if (realm &&
domain_name_list_contains(domain_names, realm))
return 1;
+ if (realm)
+ ret = 0;
}
#endif /* INTERWORKING_3GPP */
if (domain_names == NULL || cred->domain == NULL)
- return 0;
+ return ret;
- 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;
}
@@ -1757,6 +1855,9 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB);
if (ie == NULL || ie[1] < 4 || !(ie[5] & 0x80))
continue; /* AP does not support Interworking */
+ if (disallowed_bssid(wpa_s, bss->bssid) ||
+ disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len))
+ continue; /* Disallowed BSS */
if (!(bss->flags & WPA_BSS_ANQP_FETCH_TRIED)) {
if (bss->anqp == NULL) {
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 6c527b12..88f71bd1 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -73,6 +73,15 @@
#define P2P_MAX_INITIAL_CONN_WAIT_GO 10
#endif /* P2P_MAX_INITIAL_CONN_WAIT_GO */
+#ifndef P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE
+/*
+ * How many seconds to wait for initial 4-way handshake to get completed after
+ * re-invocation of a persistent group on the GO when the client is expected
+ * to connect automatically (no user interaction).
+ */
+#define P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE 15
+#endif /* P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE */
+
#ifndef P2P_CONCURRENT_SEARCH_DELAY
#define P2P_CONCURRENT_SEARCH_DELAY 500
#endif /* P2P_CONCURRENT_SEARCH_DELAY */
@@ -447,6 +456,12 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
wpa_s->p2p_in_provisioning = 0;
}
+ /*
+ * Make sure wait for the first client does not remain active after the
+ * group has been removed.
+ */
+ wpa_s->global->p2p_go_wait_client.sec = 0;
+
if (removal_reason != P2P_GROUP_REMOVAL_SILENT && ssid)
wpas_notify_p2p_group_removed(wpa_s, ssid, gtype);
@@ -1033,6 +1048,21 @@ static void p2p_go_configured(void *ctx, void *data)
wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
wpas_p2p_cross_connect_setup(wpa_s);
wpas_p2p_set_group_idle_timeout(wpa_s);
+
+ if (wpa_s->p2p_first_connection_timeout) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Start group formation timeout of %d seconds until first data connection on GO",
+ wpa_s->p2p_first_connection_timeout);
+ wpa_s->p2p_go_group_formation_completed = 0;
+ wpa_s->global->p2p_group_formation = wpa_s;
+ eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL);
+ eloop_register_timeout(
+ wpa_s->p2p_first_connection_timeout, 0,
+ wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL);
+ }
+
return;
}
@@ -2732,7 +2762,8 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
if (s) {
int go = s->mode == WPAS_MODE_P2P_GO;
wpas_p2p_group_add_persistent(
- wpa_s, s, go, go ? op_freq : 0, 0, NULL);
+ wpa_s, s, go, go ? op_freq : 0, 0, NULL,
+ go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0);
} else if (bssid) {
wpa_s->user_initiated_pd = 0;
wpas_p2p_join(wpa_s, bssid, go_dev_addr,
@@ -2839,10 +2870,11 @@ static void wpas_remove_persistent_client(struct wpa_supplicant *wpa_s,
static void wpas_invitation_result(void *ctx, int status, const u8 *bssid,
const struct p2p_channels *channels,
- const u8 *peer)
+ const u8 *peer, int neg_freq)
{
struct wpa_supplicant *wpa_s = ctx;
struct wpa_ssid *ssid;
+ int freq;
if (bssid) {
wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RESULT
@@ -2904,10 +2936,21 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid,
os_sleep(0, 100000);
#endif
+ freq = wpa_s->p2p_persistent_go_freq;
+ if (neg_freq > 0 && ssid->mode == WPAS_MODE_P2P_GO &&
+ freq_included(channels, neg_freq)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use frequence %d MHz from invitation for GO mode",
+ neg_freq);
+ freq = neg_freq;
+ }
+
wpas_p2p_group_add_persistent(wpa_s, ssid,
ssid->mode == WPAS_MODE_P2P_GO,
- wpa_s->p2p_persistent_go_freq,
- wpa_s->p2p_go_ht40, channels);
+ freq,
+ wpa_s->p2p_go_ht40, channels,
+ ssid->mode == WPAS_MODE_P2P_GO ?
+ P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
+ 0);
}
@@ -4542,6 +4585,7 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
if (!wpas_p2p_create_iface(wpa_s)) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use same interface for group "
"operations");
+ wpa_s->p2p_first_connection_timeout = 0;
return wpa_s;
}
@@ -4561,6 +4605,7 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use separate group interface %s",
group_wpa_s->ifname);
+ group_wpa_s->p2p_first_connection_timeout = 0;
return group_wpa_s;
}
@@ -4652,10 +4697,10 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
if (params->passphrase)
ssid->passphrase = os_strdup(params->passphrase);
- wpa_supplicant_select_network(wpa_s, ssid);
-
wpa_s->show_group_started = 1;
+ wpa_supplicant_select_network(wpa_s, ssid);
+
return 0;
}
@@ -4663,7 +4708,8 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int addr_allocated,
int freq, int ht40,
- const struct p2p_channels *channels)
+ const struct p2p_channels *channels,
+ int connection_timeout)
{
struct p2p_go_neg_results params;
int go = 0;
@@ -4720,6 +4766,7 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
if (wpa_s == NULL)
return -1;
+ wpa_s->p2p_first_connection_timeout = connection_timeout;
wpas_start_wps_go(wpa_s, &params, 0);
return 0;
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 65ccbf98..64c5857c 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -39,7 +39,8 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int addr_allocated,
int freq, int ht40,
- const struct p2p_channels *channels);
+ const struct p2p_channels *channels,
+ int connection_timeout);
struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index d121494b..ed08d289 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1273,8 +1273,6 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
int wep_keys_set = 0;
int assoc_failed = 0;
struct wpa_ssid *old_ssid;
- u8 ext_capab[10];
- int ext_capab_len;
#ifdef CONFIG_HT_OVERRIDES
struct ieee80211_ht_capabilities htcaps;
struct ieee80211_ht_capabilities htcaps_mask;
@@ -1489,15 +1487,27 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_HS20 */
- ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab);
- if (ext_capab_len > 0) {
- u8 *pos = wpa_ie;
- if (wpa_ie_len > 0 && pos[0] == WLAN_EID_RSN)
- pos += 2 + pos[1];
- os_memmove(pos + ext_capab_len, pos,
- wpa_ie_len - (pos - wpa_ie));
- wpa_ie_len += ext_capab_len;
- os_memcpy(pos, ext_capab, ext_capab_len);
+ /*
+ * Workaround: Add Extended Capabilities element only if the AP
+ * included this element in Beacon/Probe Response frames. Some older
+ * APs seem to have interoperability issues if this element is
+ * included, so while the standard may require us to include the
+ * element in all cases, it is justifiable to skip it to avoid
+ * interoperability issues.
+ */
+ if (!bss || wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB)) {
+ u8 ext_capab[10];
+ int ext_capab_len;
+ ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab);
+ if (ext_capab_len > 0) {
+ u8 *pos = wpa_ie;
+ if (wpa_ie_len > 0 && pos[0] == WLAN_EID_RSN)
+ pos += 2 + pos[1];
+ os_memmove(pos + ext_capab_len, pos,
+ wpa_ie_len - (pos - wpa_ie));
+ wpa_ie_len += ext_capab_len;
+ os_memcpy(pos, ext_capab, ext_capab_len);
+ }
}
wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index d73d3715..6414f447 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -399,9 +399,11 @@ fast_reauth=1
# 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 efce95e5..353c68e8 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -650,6 +650,7 @@ struct wpa_supplicant {
unsigned int p2p_go_ht40:1;
unsigned int user_initiated_pd:1;
unsigned int p2p_go_group_formation_completed:1;
+ int p2p_first_connection_timeout;
int p2p_persistent_go_freq;
int p2p_persistent_id;
int p2p_go_intent;