Interworking: Add support for home vs. visited SP determination
authorJouni Malinen <jouni@qca.qualcomm.com>
Thu, 16 Feb 2012 14:32:00 +0000 (16:32 +0200)
committerJouni Malinen <j@w1.fi>
Thu, 16 Feb 2012 14:32:00 +0000 (16:32 +0200)
Use Domain Name List (ANQP) and the new home_domain configuration
parameter to figure out whether a network is operated by the home
service provider and if so, prefer it over networks that would
require roaming.

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

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

index a7c1784..5910b5d 100644 (file)
@@ -1825,6 +1825,7 @@ void wpa_config_free(struct wpa_config *config)
        os_free(config->home_ca_cert);
        os_free(config->home_imsi);
        os_free(config->home_milenage);
+       os_free(config->home_domain);
        os_free(config);
 }
 
@@ -2594,6 +2595,7 @@ static const struct global_parse_data global_fields[] = {
        { STR(home_ca_cert), 0 },
        { STR(home_imsi), 0 },
        { STR(home_milenage), 0 },
+       { STR(home_domain), 0 },
        { INT_RANGE(interworking, 0, 1), 0 },
        { FUNC(hessid), 0 },
        { INT_RANGE(access_network_type, 0, 15), 0 }
index a62f288..380bfbb 100644 (file)
@@ -478,6 +478,14 @@ struct wpa_config {
         *      <Ki>:<OPc>:<SQN> format
         */
        char *home_milenage;
+
+       /**
+        * home_domain - Home service provider FQDN
+        *
+        * This is used to compare against the Domain Name List to figure out
+        * whether the AP is operated by the Home SP.
+        */
+       char *home_domain;
 };
 
 
index 56dd5b1..572e2ed 100644 (file)
@@ -830,10 +830,41 @@ static int interworking_credentials_available(struct wpa_supplicant *wpa_s,
 }
 
 
+static int interworking_home_sp(struct wpa_supplicant *wpa_s,
+                               struct wpabuf *domain_names)
+{
+       const u8 *pos, *end;
+       size_t len;
+
+       if (wpa_s->conf->home_domain == NULL || domain_names == NULL)
+               return -1;
+
+       len = os_strlen(wpa_s->conf->home_domain);
+       pos = wpabuf_head(domain_names);
+       end = pos + wpabuf_len(domain_names);
+
+       while (pos + 1 < end) {
+               if (pos + 1 + pos[0] > end)
+                       break;
+
+               if (pos[0] == len &&
+                   os_strncasecmp(wpa_s->conf->home_domain,
+                                  (const char *) (pos + 1), len) == 0)
+                       return 1;
+
+               pos += 1 + pos[0];
+       }
+
+       return 0;
+}
+
+
 static void interworking_select_network(struct wpa_supplicant *wpa_s)
 {
-       struct wpa_bss *bss, *selected = NULL;
+       struct wpa_bss *bss, *selected = NULL, *selected_home = NULL;
        unsigned int count = 0;
+       const char *type;
+       int res;
 
        wpa_s->network_select = 0;
 
@@ -841,10 +872,26 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s)
                if (!interworking_credentials_available(wpa_s, bss))
                        continue;
                count++;
-               wpa_msg(wpa_s, MSG_INFO, INTERWORKING_AP MACSTR,
-                       MAC2STR(bss->bssid));
-               if (selected == NULL && wpa_s->auto_select)
-                       selected = bss;
+               res = interworking_home_sp(wpa_s, bss->anqp_domain_name);
+               if (res > 0)
+                       type = "home";
+               else if (res == 0)
+                       type = "roaming";
+               else
+                       type = "unknown";
+               wpa_msg(wpa_s, MSG_INFO, INTERWORKING_AP MACSTR " type=%s",
+                       MAC2STR(bss->bssid), type);
+               if (wpa_s->auto_select) {
+                       if (selected == NULL)
+                               selected = bss;
+                       if (selected_home == NULL && res > 0)
+                               selected_home = bss;
+               }
+       }
+
+       if (selected_home && selected_home != selected) {
+               /* Prefer network operated by the Home SP */
+               selected = selected_home;
        }
 
        if (count == 0) {