diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20 index feb904900..5669c55c3 100644 --- a/wpa_supplicant/README-HS20 +++ b/wpa_supplicant/README-HS20 @@ -190,6 +190,11 @@ Credentials can be pre-configured for automatic network selection: # phase2: Pre-configure Phase 2 (inner authentication) parameters # This optional field is used with like the 'eap' parameter. # +# excluded_ssid: Excluded SSID +# This optional field can be used to excluded specific SSID(s) from +# matching with the network. Multiple entries can be used to specify more +# than one SSID. +# # for example: # #cred={ diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index e157845f7..58e56ce9d 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -1835,6 +1835,7 @@ void wpa_config_free_cred(struct wpa_cred *cred) os_free(cred->eap_method); os_free(cred->phase1); os_free(cred->phase2); + os_free(cred->excluded_ssid); os_free(cred); } @@ -2411,6 +2412,34 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, return 0; } + if (os_strcmp(var, "excluded_ssid") == 0) { + struct excluded_ssid *e; + + if (len > MAX_SSID_LEN) { + wpa_printf(MSG_ERROR, "Line %d: invalid " + "excluded_ssid length %d", line, (int) len); + os_free(val); + return -1; + } + + e = os_realloc_array(cred->excluded_ssid, + cred->num_excluded_ssid + 1, + sizeof(struct excluded_ssid)); + if (e == NULL) { + os_free(val); + return -1; + } + cred->excluded_ssid = e; + + e = &cred->excluded_ssid[cred->num_excluded_ssid++]; + os_memcpy(e->ssid, val, len); + e->ssid_len = len; + + os_free(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 c0aea0b33..1bca44420 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -196,6 +196,12 @@ struct wpa_cred { * Pre-configured EAP parameters or %NULL. */ char *phase2; + + struct excluded_ssid { + u8 ssid[MAX_SSID_LEN]; + size_t ssid_len; + } *excluded_ssid; + size_t num_excluded_ssid; }; diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index 3ba0abe2c..b6fb3e607 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -742,6 +742,16 @@ static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred) fprintf(f, "\tphase1=\"%s\"\n", cred->phase1); if (cred->phase2) fprintf(f, "\tphase2=\"%s\"\n", cred->phase2); + if (cred->excluded_ssid) { + size_t i, j; + for (i = 0; i < cred->num_excluded_ssid; i++) { + struct excluded_ssid *e = &cred->excluded_ssid[i]; + fprintf(f, "\texcluded_ssid="); + for (j = 0; j < e->ssid_len; j++) + fprintf(f, "%02x", e->ssid[j]); + fprintf(f, "\n"); + } + } } diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c index 875abce20..057255694 100644 --- a/wpa_supplicant/interworking.c +++ b/wpa_supplicant/interworking.c @@ -948,6 +948,24 @@ static int roaming_consortium_match(const u8 *ie, const struct wpabuf *anqp, } +static int cred_excluded_ssid(struct wpa_cred *cred, struct wpa_bss *bss) +{ + size_t i; + + if (!cred->excluded_ssid) + return 0; + + for (i = 0; i < cred->num_excluded_ssid; i++) { + struct excluded_ssid *e = &cred->excluded_ssid[i]; + if (bss->ssid_len == e->ssid_len && + os_memcmp(bss->ssid, e->ssid, e->ssid_len) == 0) + return 1; + } + + return 0; +} + + static struct wpa_cred * interworking_credentials_available_roaming_consortium( struct wpa_supplicant *wpa_s, struct wpa_bss *bss) { @@ -975,6 +993,9 @@ static struct wpa_cred * interworking_credentials_available_roaming_consortium( cred->roaming_consortium_len)) continue; + if (cred_excluded_ssid(cred, bss)) + continue; + if (selected == NULL || selected->priority < cred->priority) selected = cred; @@ -1343,6 +1364,8 @@ static struct wpa_cred * interworking_credentials_available_3gpp( ret = plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len); wpa_printf(MSG_DEBUG, "PLMN match %sfound", ret ? "" : "not "); if (ret) { + if (cred_excluded_ssid(cred, bss)) + continue; if (selected == NULL || selected->priority < cred->priority) selected = cred; @@ -1383,6 +1406,8 @@ static struct wpa_cred * interworking_credentials_available_realm( if (!nai_realm_match(&realm[i], cred->realm)) continue; if (nai_realm_find_eap(cred, &realm[i])) { + if (cred_excluded_ssid(cred, bss)) + continue; if (selected == NULL || selected->priority < cred->priority) selected = cred; diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index 5f0dec66e..ebefe6071 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -389,6 +389,11 @@ fast_reauth=1 # phase2: Pre-configure Phase 2 (inner authentication) parameters # This optional field is used with like the 'eap' parameter. # +# excluded_ssid: Excluded SSID +# This optional field can be used to excluded specific SSID(s) from +# matching with the network. Multiple entries can be used to specify more +# than one SSID. +# # for example: # #cred={