]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Add disallow_aps parameter to disallow BSSIDs/SSIDs
authorJouni Malinen <jouni@qca.qualcomm.com>
Thu, 27 Sep 2012 14:36:59 +0000 (17:36 +0300)
committerJouni Malinen <j@w1.fi>
Thu, 27 Sep 2012 14:36:59 +0000 (17:36 +0300)
External programs can use this new parameter to prevent wpa_supplicant
from connecting to a list of BSSIDs and/or SSIDs. The disallowed BSSes
will still be visible in scan results and it is possible to run ANQP
operations with them, but BSS selection for connection will skip any
BSS that matches an entry in the disallowed list.

The new parameter can be set with the control interface SET command
using following syntax:

SET disallow_aps <disallow_list>
disallow_list ::= <ssid_spec> | <bssid_spec> | <disallow_list> | “”
SSID_SPEC ::= ssid <SSID_HEX>
BSSID_SPEC ::= bssid <BSSID_HEX>

For example:
wpa_cli set disallow_list "ssid 74657374 bssid 001122334455 ssid 68656c6c6f"
wpa_cli set disallow_list
(the empty value removes all entries)

Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>

wpa_supplicant/ctrl_iface.c
wpa_supplicant/events.c
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant_i.h

index 18cf4b3bc35e556d290f8500ba269213c7cb285b..e209d8ae0879cfca708b925aa7c0f60e87076e7d 100644 (file)
@@ -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> | <bssid_spec> | <disallow_list> | “”
+        * SSID_SPEC ::= ssid <SSID_HEX>
+        * BSSID_SPEC ::= bssid <BSSID_HEX>
+        */
+
+       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);
index d696ad1f8b0605b1fadd5062a232fbc73dfff2bf..5399f76d183ef8e137ce26ca1425e93b16914aca 100644 (file)
@@ -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) {
index a036f3ec64f03e8e9894c245fabaf6f9385dc3c5..fe2894935df15e58ecd65786f670af92a73700b8 100644 (file)
@@ -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;
+}
index 55f3d8810502d51b6ed1bfc3ed5c68bc0615b9aa..d23022b13a25daf08cef9c8f510ca0d5854955c8 100644 (file)
@@ -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);
 
 /**