diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20 index 5669c55c3..7a570bdd7 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 :: # 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 c4fc7b670..2b47e8e69 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -1855,6 +1855,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); @@ -1864,6 +1866,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); @@ -2437,8 +2441,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 1748cf3b8..27301b803 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 6512a8270..2c14a2c91 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -728,6 +728,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) @@ -753,10 +755,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]); @@ -773,7 +774,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 0f893f7e6..7b3af28d0 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -1565,16 +1565,21 @@ 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; 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) @@ -2448,7 +2453,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; @@ -2533,9 +2538,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; } diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c index 36f75a166..01acae1c6 100644 --- a/wpa_supplicant/interworking.c +++ b/wpa_supplicant/interworking.c @@ -1514,6 +1514,7 @@ int interworking_home_sp_cred(struct wpa_supplicant *wpa_s, struct wpa_cred *cred, struct wpabuf *domain_names) { + size_t i; #ifdef INTERWORKING_3GPP char nai[100], *realm; @@ -1544,10 +1545,12 @@ int interworking_home_sp_cred(struct wpa_supplicant *wpa_s, 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; } diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index d73d3715a..6414f447d 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 :: # 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