Browse Source

Interworking: Add support for home vs. visited SP determination

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>
Jouni Malinen 13 years ago
parent
commit
00bf219ddb
3 changed files with 62 additions and 5 deletions
  1. 2 0
      wpa_supplicant/config.c
  2. 8 0
      wpa_supplicant/config.h
  3. 52 5
      wpa_supplicant/interworking.c

+ 2 - 0
wpa_supplicant/config.c

@@ -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 }

+ 8 - 0
wpa_supplicant/config.h

@@ -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;
 };
 
 

+ 52 - 5
wpa_supplicant/interworking.c

@@ -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) {