]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Interworking: Add support for credential priorities
authorJouni Malinen <jouni@qca.qualcomm.com>
Thu, 16 Feb 2012 14:37:21 +0000 (16:37 +0200)
committerJouni Malinen <j@w1.fi>
Thu, 16 Feb 2012 14:37:21 +0000 (16:37 +0200)
This allows credentials to be set with a specific priority to allow
the automatic network selection behavior to be controlled with user
preferences. The priority values are configured to the network block
and BSS selection will select the network based on priorities from
both pre-configured network blocks and credentials.

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

wpa_supplicant/config.c
wpa_supplicant/config.h
wpa_supplicant/config_file.c
wpa_supplicant/interworking.c

index 1ccce440c4c64cb691f06ebaced5578a18c51536..9a0e1e2a90a3ae5a98832501f2ab4f6e3244ce80 100644 (file)
@@ -2217,6 +2217,11 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
        char *val;
        size_t len;
 
+       if (os_strcmp(var, "priority") == 0) {
+               cred->priority = atoi(value);
+               return 0;
+       }
+
        val = wpa_config_parse_string(value, &len);
        if (val == NULL)
                return -1;
index 35fdc9431548dec010920e39088c268bf2b33801..72906fb7f424116a2a20e3a251ff0f688fcbe349 100644 (file)
@@ -48,6 +48,18 @@ struct wpa_cred {
         */
        int id;
 
+       /**
+        * priority - Priority group
+        *
+        * By default, all networks and credentials get the same priority group
+        * (0). This field can be used to give higher priority for credentials
+        * (and similarly in struct wpa_ssid for network blocks) to change the
+        * Interworking automatic networking selection behavior. The matching
+        * network (based on either an enabled network block or a credential)
+        * with the highest priority value will be selected.
+        */
+       int priority;
+
        /**
         * realm - Home Realm for Interworking
         */
index a7e64bb31e08e0ecb355616e484137dcf70700ee..f8f4ff14d49dfb737f2c6e448e32291013d24773 100644 (file)
@@ -657,6 +657,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)
 {
+       if (cred->priority)
+               fprintf(f, "\tpriority=%d\n", cred->priority);
        if (cred->realm)
                fprintf(f, "\trealm=\"%s\"\n", cred->realm);
        if (cred->username)
index 37bca7f649894d9b8bd012583f4a298e378e646a..46a65a0312af229d0cfbab29acb02d35b5490aca 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Interworking (IEEE 802.11u)
- * Copyright (c) 2011, Qualcomm Atheros
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -601,6 +601,7 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
 
        wpas_notify_network_added(wpa_s, ssid);
        wpa_config_set_network_defaults(ssid);
+       ssid->priority = cred->priority;
        ssid->temporary = 1;
        ssid->ssid = os_zalloc(ie[1] + 1);
        if (ssid->ssid == NULL)
@@ -632,6 +633,7 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
            wpa_config_set_quoted(ssid, "password", cred->password) < 0)
                goto fail;
 
+       wpa_config_update_prio_list(wpa_s->conf);
        wpa_s->disconnected = 0;
        wpa_s->reassociate = 1;
        wpa_supplicant_req_scan(wpa_s, 0, 0);
@@ -708,6 +710,7 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
        }
        wpas_notify_network_added(wpa_s, ssid);
        wpa_config_set_network_defaults(ssid);
+       ssid->priority = cred->priority;
        ssid->temporary = 1;
        ssid->ssid = os_zalloc(ie[1] + 1);
        if (ssid->ssid == NULL)
@@ -799,6 +802,7 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
 
        nai_realm_free(realm, count);
 
+       wpa_config_update_prio_list(wpa_s->conf);
        wpa_s->disconnected = 0;
        wpa_s->reassociate = 1;
        wpa_supplicant_req_scan(wpa_s, 0, 0);
@@ -813,15 +817,15 @@ fail:
 }
 
 
-static int interworking_credentials_available_3gpp(
+static struct wpa_cred * interworking_credentials_available_3gpp(
        struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
 {
-       struct wpa_cred *cred;
+       struct wpa_cred *cred, *selected = NULL;
        int ret;
 
 #ifdef INTERWORKING_3GPP
        if (bss->anqp_3gpp == NULL)
-               return 0;
+               return NULL;
 
        for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
                if (cred->imsi == NULL || !cred->imsi[0] ||
@@ -832,27 +836,29 @@ static int interworking_credentials_available_3gpp(
                           MACSTR, MAC2STR(bss->bssid));
                ret = plmn_id_match(bss->anqp_3gpp, cred->imsi);
                wpa_printf(MSG_DEBUG, "PLMN match %sfound", ret ? "" : "not ");
-               if (ret)
-                       return 1;
+               if (ret) {
+                       if (selected == NULL ||
+                           selected->priority < cred->priority)
+                               selected = cred;
+               }
        }
 #endif /* INTERWORKING_3GPP */
-       return 0;
+       return selected;
 }
 
 
-static int interworking_credentials_available_realm(
+static struct wpa_cred * interworking_credentials_available_realm(
        struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
 {
-       struct wpa_cred *cred;
+       struct wpa_cred *cred, *selected = NULL;
        struct nai_realm *realm;
        u16 count, i;
-       int found = 0;
 
        if (bss->anqp_nai_realm == NULL)
-               return 0;
+               return NULL;
 
        if (wpa_s->conf->cred == NULL)
-               return 0;
+               return NULL;
 
        wpa_printf(MSG_DEBUG, "Interworking: Parsing NAI Realm list from "
                   MACSTR, MAC2STR(bss->bssid));
@@ -860,7 +866,7 @@ static int interworking_credentials_available_realm(
        if (realm == NULL) {
                wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
                           "Realm list from " MACSTR, MAC2STR(bss->bssid));
-               return 0;
+               return NULL;
        }
 
        for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
@@ -871,25 +877,33 @@ static int interworking_credentials_available_realm(
                        if (!nai_realm_match(&realm[i], cred->realm))
                                continue;
                        if (nai_realm_find_eap(cred, &realm[i])) {
-                               found++;
+                               if (selected == NULL ||
+                                   selected->priority < cred->priority)
+                                       selected = cred;
                                break;
                        }
                }
-               if (found)
-                       break;
        }
 
        nai_realm_free(realm, count);
 
-       return found;
+       return selected;
 }
 
 
-static int interworking_credentials_available(struct wpa_supplicant *wpa_s,
-                                             struct wpa_bss *bss)
+static struct wpa_cred * interworking_credentials_available(
+       struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
 {
-       return interworking_credentials_available_realm(wpa_s, bss) ||
-               interworking_credentials_available_3gpp(wpa_s, bss);
+       struct wpa_cred *cred, *cred2;
+
+       cred = interworking_credentials_available_realm(wpa_s, bss);
+       cred2 = interworking_credentials_available_3gpp(wpa_s, bss);
+       if (cred && cred2 && cred2->priority >= cred->priority)
+               cred = cred2;
+       if (!cred)
+               cred = cred2;
+
+       return cred;
 }
 
 
@@ -962,14 +976,17 @@ static int interworking_home_sp(struct wpa_supplicant *wpa_s,
 static void interworking_select_network(struct wpa_supplicant *wpa_s)
 {
        struct wpa_bss *bss, *selected = NULL, *selected_home = NULL;
+       int selected_prio = -999999, selected_home_prio = -999999;
        unsigned int count = 0;
        const char *type;
        int res;
+       struct wpa_cred *cred;
 
        wpa_s->network_select = 0;
 
        dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
-               if (!interworking_credentials_available(wpa_s, bss))
+               cred = interworking_credentials_available(wpa_s, bss);
+               if (!cred)
                        continue;
                count++;
                res = interworking_home_sp(wpa_s, bss->anqp_domain_name);
@@ -982,14 +999,22 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s)
                wpa_msg(wpa_s, MSG_INFO, INTERWORKING_AP MACSTR " type=%s",
                        MAC2STR(bss->bssid), type);
                if (wpa_s->auto_select) {
-                       if (selected == NULL)
+                       if (selected == NULL ||
+                           cred->priority > selected_prio) {
                                selected = bss;
-                       if (selected_home == NULL && res > 0)
+                               selected_prio = cred->priority;
+                       }
+                       if (res > 0 &&
+                           (selected_home == NULL ||
+                            cred->priority > selected_home_prio)) {
                                selected_home = bss;
+                               selected_home_prio = cred->priority;
+                       }
                }
        }
 
-       if (selected_home && selected_home != selected) {
+       if (selected_home && selected_home != selected &&
+           selected_home_prio >= selected_prio) {
                /* Prefer network operated by the Home SP */
                selected = selected_home;
        }