diff options
| author | Steve Kondik <shade@chemlab.org> | 2013-12-13 06:23:24 -0500 |
|---|---|---|
| committer | Steve Kondik <shade@chemlab.org> | 2013-12-13 06:23:24 -0500 |
| commit | 14a5afdd5255623482f78402bc46dad276f8143b (patch) | |
| tree | 68ff819fd7543ef1115c1f154a587bfc0ffe62a9 | |
| parent | 67128b60aaa3785bd88781f451fc2478d5f8076f (diff) | |
| parent | b740a47e36e811907a8d191fbef40bfe58c24aa7 (diff) | |
| download | android_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.h | 7 | ||||
| -rw-r--r-- | src/ap/drv_callbacks.c | 10 | ||||
| -rw-r--r-- | src/ap/hostapd.c | 62 | ||||
| -rw-r--r-- | src/ap/hostapd.h | 3 | ||||
| -rw-r--r-- | src/common/wpa_ctrl.h | 1 | ||||
| -rw-r--r-- | src/drivers/driver.h | 23 | ||||
| -rw-r--r-- | src/drivers/driver_nl80211.c | 67 | ||||
| -rw-r--r-- | src/p2p/p2p.c | 3 | ||||
| -rw-r--r-- | src/p2p/p2p.h | 3 | ||||
| -rw-r--r-- | src/p2p/p2p_go_neg.c | 6 | ||||
| -rw-r--r-- | src/p2p/p2p_i.h | 3 | ||||
| -rw-r--r-- | src/p2p/p2p_invitation.c | 10 | ||||
| -rw-r--r-- | src/p2p/p2p_utils.c | 29 | ||||
| -rw-r--r-- | wpa_supplicant/README-HS20 | 6 | ||||
| -rw-r--r-- | wpa_supplicant/config.c | 16 | ||||
| -rw-r--r-- | wpa_supplicant/config.h | 13 | ||||
| -rw-r--r-- | wpa_supplicant/config_file.c | 9 | ||||
| -rw-r--r-- | wpa_supplicant/ctrl_iface.c | 57 | ||||
| -rw-r--r-- | wpa_supplicant/dbus/dbus_new_handlers_p2p.c | 2 | ||||
| -rw-r--r-- | wpa_supplicant/events.c | 62 | ||||
| -rw-r--r-- | wpa_supplicant/interworking.c | 113 | ||||
| -rw-r--r-- | wpa_supplicant/p2p_supplicant.c | 61 | ||||
| -rw-r--r-- | wpa_supplicant/p2p_supplicant.h | 3 | ||||
| -rw-r--r-- | wpa_supplicant/wpa_supplicant.c | 32 | ||||
| -rw-r--r-- | wpa_supplicant/wpa_supplicant.conf | 6 | ||||
| -rw-r--r-- | wpa_supplicant/wpa_supplicant_i.h | 1 |
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, ¶ms, 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; |
