diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 18cf4b3bc..e209d8ae0 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -158,6 +158,128 @@ static int set_bssid_filter(struct wpa_supplicant *wpa_s, char *val) } +static int set_disallow_aps(struct wpa_supplicant *wpa_s, char *val) +{ + char *pos; + u8 addr[ETH_ALEN], *bssid = NULL, *n; + struct wpa_ssid_value *ssid = NULL, *ns; + size_t count = 0, ssid_count = 0; + struct wpa_ssid *c; + + /* + * disallow_list ::= | | | “” + * SSID_SPEC ::= ssid + * BSSID_SPEC ::= bssid + */ + + pos = val; + while (pos) { + if (*pos == '\0') + break; + if (os_strncmp(pos, "bssid ", 6) == 0) { + int res; + pos += 6; + res = hwaddr_aton2(pos, addr); + if (res < 0) { + os_free(ssid); + os_free(bssid); + wpa_printf(MSG_DEBUG, "Invalid disallow_aps " + "BSSID value '%s'", pos); + return -1; + } + pos += res; + n = os_realloc_array(bssid, count + 1, ETH_ALEN); + if (n == NULL) { + os_free(ssid); + os_free(bssid); + return -1; + } + bssid = n; + os_memcpy(bssid + count * ETH_ALEN, addr, ETH_ALEN); + count++; + } else if (os_strncmp(pos, "ssid ", 5) == 0) { + char *end; + pos += 5; + + end = pos; + while (*end) { + if (*end == '\0' || *end == ' ') + break; + end++; + } + + ns = os_realloc_array(ssid, ssid_count + 1, + sizeof(struct wpa_ssid_value)); + if (ns == NULL) { + os_free(ssid); + os_free(bssid); + return -1; + } + ssid = ns; + + if ((end - pos) & 0x01 || end - pos > 2 * 32 || + hexstr2bin(pos, ssid[ssid_count].ssid, + (end - pos) / 2) < 0) { + os_free(ssid); + os_free(bssid); + wpa_printf(MSG_DEBUG, "Invalid disallow_aps " + "SSID value '%s'", pos); + return -1; + } + ssid[ssid_count].ssid_len = (end - pos) / 2; + wpa_hexdump_ascii(MSG_DEBUG, "disallow_aps SSID", + ssid[ssid_count].ssid, + ssid[ssid_count].ssid_len); + ssid_count++; + pos = end; + } else { + wpa_printf(MSG_DEBUG, "Unexpected disallow_aps value " + "'%s'", pos); + os_free(ssid); + os_free(bssid); + return -1; + } + + pos = os_strchr(pos, ' '); + if (pos) + pos++; + } + + wpa_hexdump(MSG_DEBUG, "disallow_aps_bssid", bssid, count * ETH_ALEN); + os_free(wpa_s->disallow_aps_bssid); + wpa_s->disallow_aps_bssid = bssid; + wpa_s->disallow_aps_bssid_count = count; + + wpa_printf(MSG_DEBUG, "disallow_aps_ssid_count %d", (int) ssid_count); + os_free(wpa_s->disallow_aps_ssid); + wpa_s->disallow_aps_ssid = ssid; + wpa_s->disallow_aps_ssid_count = ssid_count; + + if (!wpa_s->current_ssid || wpa_s->wpa_state < WPA_AUTHENTICATING) + return 0; + + c = wpa_s->current_ssid; + if (c->mode != WPAS_MODE_INFRA && c->mode != WPAS_MODE_IBSS) + return 0; + + if (!disallowed_bssid(wpa_s, wpa_s->bssid) && + !disallowed_ssid(wpa_s, c->ssid, c->ssid_len)) + return 0; + + wpa_printf(MSG_DEBUG, "Disconnect and try to find another network " + "because current AP was marked disallowed"); + +#ifdef CONFIG_SME + wpa_s->sme.prev_bssid_set = 0; +#endif /* CONFIG_SME */ + wpa_s->reassociate = 1; + wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); + wpa_supplicant_req_scan(wpa_s, 0, 0); + + return 0; +} + + static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, char *cmd) { @@ -291,6 +413,8 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, #endif /* CONFIG_WIFI_DISPLAY */ } else if (os_strcasecmp(cmd, "bssid_filter") == 0) { ret = set_bssid_filter(wpa_s, value); + } else if (os_strcasecmp(cmd, "disallow_aps") == 0) { + ret = set_disallow_aps(wpa_s, value); } else { value[-1] = '='; ret = wpa_config_process_global(wpa_s->conf, cmd, -1); diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index d696ad1f8..5399f76d1 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -84,6 +84,12 @@ static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s) return -1; } + if (disallowed_bssid(wpa_s, wpa_s->bssid) || + disallowed_ssid(wpa_s, ssid->ssid, ssid->ssid_len)) { + wpa_dbg(wpa_s, MSG_DEBUG, "Selected BSS is disallowed"); + return -1; + } + res = wpas_temp_disabled(wpa_s, ssid); if (res > 0) { wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is temporarily " @@ -672,6 +678,16 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, return NULL; } + if (disallowed_bssid(wpa_s, bss->bssid)) { + wpa_dbg(wpa_s, MSG_DEBUG, " skip - BSSID disallowed"); + return NULL; + } + + if (disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) { + wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID disallowed"); + return NULL; + } + wpa = wpa_ie_len > 0 || rsn_ie_len > 0; for (ssid = group; ssid; ssid = ssid->pnext) { diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index a036f3ec6..fe2894935 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -470,6 +470,11 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) os_free(wpa_s->bssid_filter); wpa_s->bssid_filter = NULL; + os_free(wpa_s->disallow_aps_bssid); + wpa_s->disallow_aps_bssid = NULL; + os_free(wpa_s->disallow_aps_ssid); + wpa_s->disallow_aps_ssid = NULL; + wnm_bss_keep_alive_deinit(wpa_s); ext_password_deinit(wpa_s->ext_pw); @@ -3643,3 +3648,39 @@ void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s, if (clear_failures) ssid->auth_failures = 0; } + + +int disallowed_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid) +{ + size_t i; + + if (wpa_s->disallow_aps_bssid == NULL) + return 0; + + for (i = 0; i < wpa_s->disallow_aps_bssid_count; i++) { + if (os_memcmp(wpa_s->disallow_aps_bssid + i * ETH_ALEN, + bssid, ETH_ALEN) == 0) + return 1; + } + + return 0; +} + + +int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid, + size_t ssid_len) +{ + size_t i; + + if (wpa_s->disallow_aps_ssid == NULL || ssid == NULL) + return 0; + + for (i = 0; i < wpa_s->disallow_aps_ssid_count; i++) { + struct wpa_ssid_value *s = &wpa_s->disallow_aps_ssid[i]; + if (ssid_len == s->ssid_len && + os_memcmp(ssid, s->ssid, ssid_len) == 0) + return 1; + } + + return 0; +} diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 55f3d8810..d23022b13 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -267,6 +267,11 @@ struct wps_ap_info { struct os_time last_attempt; }; +struct wpa_ssid_value { + u8 ssid[32]; + size_t ssid_len; +}; + /** * struct wpa_supplicant - Internal data for wpa_supplicant interface * @@ -323,6 +328,11 @@ struct wpa_supplicant { u8 *bssid_filter; size_t bssid_filter_count; + u8 *disallow_aps_bssid; + size_t disallow_aps_bssid_count; + struct wpa_ssid_value *disallow_aps_ssid; + size_t disallow_aps_ssid_count; + /* previous scan was wildcard when interleaving between * wildcard scans and specific SSID scan when max_ssids=1 */ int prev_scan_wildcard; @@ -693,6 +703,9 @@ int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s); void wpas_auth_failed(struct wpa_supplicant *wpa_s); void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int clear_failures); +int disallowed_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid); +int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid, + size_t ssid_len); void wpa_supplicant_proc_40mhz_intolerant(struct wpa_supplicant *wpa_s); /**