diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20 index 33fbc21f9..ec576b921 100644 --- a/wpa_supplicant/README-HS20 +++ b/wpa_supplicant/README-HS20 @@ -223,6 +223,10 @@ Credentials can be pre-configured for automatic network selection: # update_identifier: PPS MO ID # (Hotspot 2.0 PerProviderSubscription/UpdateIdentifier) # +# provisioning_sp: FQDN of the SP that provisioned the credential +# This optional field can be used to keep track of the SP that provisioned +# the credential to find the PPS MO (./Wi-Fi/). +# # for example: # #cred={ diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 6933df96d..b540b00cf 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -1930,6 +1930,7 @@ void wpa_config_free_cred(struct wpa_cred *cred) os_free(cred->phase2); os_free(cred->excluded_ssid); os_free(cred->roaming_partner); + os_free(cred->provisioning_sp); os_free(cred); } @@ -2660,6 +2661,12 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, return 0; } + if (os_strcmp(var, "provisioning_sp") == 0) { + os_free(cred->provisioning_sp); + cred->provisioning_sp = val; + return 0; + } + if (line) { wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.", line, var); diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index 9e06e70a1..6c9b75380 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -246,6 +246,11 @@ struct wpa_cred { size_t num_roaming_partner; int update_identifier; + + /** + * provisioning_sp - FQDN of the SP that provisioned the credential + */ + char *provisioning_sp; }; diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index 7ad3f9331..d8bd3c959 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -806,6 +806,9 @@ static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred) } if (cred->update_identifier) fprintf(f, "\tupdate_identifier=%d\n", cred->update_identifier); + + if (cred->provisioning_sp) + fprintf(f, "\tprovisioning_sp=%s\n", cred->provisioning_sp); } diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 29a097315..9f5d4f403 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -1720,15 +1720,38 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s, if (wpa_s->current_ssid->parent_cred != cred) continue; - for (i = 0; cred->domain && i < cred->num_domain; i++) { + if (cred->provisioning_sp) { ret = os_snprintf(pos, end - pos, - "home_sp=%s\n", - cred->domain[i]); + "provisioning_sp=%s\n", + cred->provisioning_sp); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } + if (!cred->domain) + goto no_domain; + + i = 0; + if (wpa_s->current_bss && wpa_s->current_bss->anqp) { + struct wpabuf *names = + wpa_s->current_bss->anqp->domain_name; + for (i = 0; names && i < cred->num_domain; i++) + { + if (domain_name_list_contains( + names, cred->domain[i], 1)) + break; + } + if (i == cred->num_domain) + i = 0; /* show first entry by default */ + } + ret = os_snprintf(pos, end - pos, "home_sp=%s\n", + cred->domain[i]); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + + no_domain: if (wpa_s->current_bss == NULL || wpa_s->current_bss->anqp == NULL) res = -1; @@ -2695,7 +2718,8 @@ static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s, int id; struct wpa_cred *cred, *prev; - /* cmd: "", "all", or "sp_fqdn=" */ + /* cmd: "", "all", "sp_fqdn=", or + * "provisioning_sp= */ if (os_strcmp(cmd, "all") == 0) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED all"); cred = wpa_s->conf->cred; @@ -2728,6 +2752,20 @@ static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s, return 0; } + if (os_strncmp(cmd, "provisioning_sp=", 16) == 0) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED provisioning SP FQDN '%s'", + cmd + 16); + cred = wpa_s->conf->cred; + while (cred) { + prev = cred; + cred = cred->next; + if (prev->provisioning_sp && + os_strcmp(prev->provisioning_sp, cmd + 16) == 0) + wpas_ctrl_remove_cred(wpa_s, prev); + } + return 0; + } + id = atoi(cmd); wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED id=%d", id); diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c index 0107ff153..3bc6fae04 100644 --- a/wpa_supplicant/interworking.c +++ b/wpa_supplicant/interworking.c @@ -1634,8 +1634,8 @@ static struct wpa_cred * interworking_credentials_available( } -static int domain_name_list_contains(struct wpabuf *domain_names, - const char *domain, int exact_match) +int domain_name_list_contains(struct wpabuf *domain_names, + const char *domain, int exact_match) { const u8 *pos, *end; size_t len; diff --git a/wpa_supplicant/interworking.h b/wpa_supplicant/interworking.h index c8e70938c..bb0ceb813 100644 --- a/wpa_supplicant/interworking.h +++ b/wpa_supplicant/interworking.h @@ -29,5 +29,7 @@ void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s); int interworking_home_sp_cred(struct wpa_supplicant *wpa_s, struct wpa_cred *cred, struct wpabuf *domain_names); +int domain_name_list_contains(struct wpabuf *domain_names, + const char *domain, int exact_match); #endif /* INTERWORKING_H */ diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index 99d86fe64..3c90362ff 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -442,6 +442,10 @@ fast_reauth=1 # update_identifier: PPS MO ID # (Hotspot 2.0 PerProviderSubscription/UpdateIdentifier) # +# provisioning_sp: FQDN of the SP that provisioned the credential +# This optional field can be used to keep track of the SP that provisioned +# the credential to find the PPS MO (./Wi-Fi/). +# # for example: # #cred={