Interworking: Fetch only the needed ANQP information
authorJouni Malinen <j@w1.fi>
Sun, 2 Sep 2012 18:05:54 +0000 (21:05 +0300)
committerJouni Malinen <j@w1.fi>
Sun, 2 Sep 2012 18:05:54 +0000 (21:05 +0300)
Use configured credentials to figure out which ANQP information needs to
be fetched and only fetch those when using Interworking network
selection. The fetch_anqp command is still fetching all ANQP
information.

Signed-hostap: Jouni Malinen <j@w1.fi>

wpa_supplicant/interworking.c
wpa_supplicant/wpa_supplicant_i.h

index 987c79b..20c7731 100644 (file)
@@ -108,27 +108,101 @@ static void interworking_anqp_resp_cb(void *ctx, const u8 *dst,
 }
 
 
+static int cred_with_roaming_consortium(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_cred *cred;
+
+       for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+               if (cred->roaming_consortium_len)
+                       return 1;
+       }
+       return 0;
+}
+
+
+static int cred_with_3gpp(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_cred *cred;
+
+       for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+               if (cred->pcsc || cred->imsi)
+                       return 1;
+       }
+       return 0;
+}
+
+
+static int cred_with_nai_realm(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_cred *cred;
+
+       for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+               if (cred->pcsc || cred->imsi)
+                       continue;
+               if (!cred->eap_method)
+                       return 1;
+               if (cred->realm && cred->roaming_consortium_len == 0)
+                       return 1;
+       }
+       return 0;
+}
+
+
+static int cred_with_domain(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_cred *cred;
+
+       for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+               if (cred->domain || cred->pcsc || cred->imsi)
+                       return 1;
+       }
+       return 0;
+}
+
+
+static int additional_roaming_consortiums(struct wpa_bss *bss)
+{
+       const u8 *ie;
+       ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
+       if (ie == NULL || ie[1] == 0)
+               return 0;
+       return ie[2]; /* Number of ANQP OIs */
+}
+
+
 static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s,
                                      struct wpa_bss *bss)
 {
        struct wpabuf *buf;
        int ret = 0;
        int res;
-       u16 info_ids[] = {
-               ANQP_CAPABILITY_LIST,
-               ANQP_VENUE_NAME,
-               ANQP_NETWORK_AUTH_TYPE,
-               ANQP_ROAMING_CONSORTIUM,
-               ANQP_IP_ADDR_TYPE_AVAILABILITY,
-               ANQP_NAI_REALM,
-               ANQP_3GPP_CELLULAR_NETWORK,
-               ANQP_DOMAIN_NAME
-       };
+       u16 info_ids[8];
+       size_t num_info_ids = 0;
        struct wpabuf *extra = NULL;
+       int all = wpa_s->fetch_all_anqp;
 
        wpa_printf(MSG_DEBUG, "Interworking: ANQP Query Request to " MACSTR,
                   MAC2STR(bss->bssid));
 
+       info_ids[num_info_ids++] = ANQP_CAPABILITY_LIST;
+       if (all) {
+               info_ids[num_info_ids++] = ANQP_VENUE_NAME;
+               info_ids[num_info_ids++] = ANQP_NETWORK_AUTH_TYPE;
+       }
+       if (all || (cred_with_roaming_consortium(wpa_s) &&
+                   additional_roaming_consortiums(bss)))
+               info_ids[num_info_ids++] = ANQP_ROAMING_CONSORTIUM;
+       if (all)
+               info_ids[num_info_ids++] = ANQP_IP_ADDR_TYPE_AVAILABILITY;
+       if (all || cred_with_nai_realm(wpa_s))
+               info_ids[num_info_ids++] = ANQP_NAI_REALM;
+       if (all || cred_with_3gpp(wpa_s))
+               info_ids[num_info_ids++] = ANQP_3GPP_CELLULAR_NETWORK;
+       if (all || cred_with_domain(wpa_s))
+               info_ids[num_info_ids++] = ANQP_DOMAIN_NAME;
+       wpa_hexdump(MSG_DEBUG, "Interworking: ANQP Query info",
+                   (u8 *) info_ids, num_info_ids * 2);
+
 #ifdef CONFIG_HS20
        if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
                u8 *len_pos;
@@ -143,16 +217,18 @@ static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s,
                wpabuf_put_u8(extra, HS20_STYPE_QUERY_LIST);
                wpabuf_put_u8(extra, 0); /* Reserved */
                wpabuf_put_u8(extra, HS20_STYPE_CAPABILITY_LIST);
-               wpabuf_put_u8(extra, HS20_STYPE_OPERATOR_FRIENDLY_NAME);
-               wpabuf_put_u8(extra, HS20_STYPE_WAN_METRICS);
-               wpabuf_put_u8(extra, HS20_STYPE_CONNECTION_CAPABILITY);
-               wpabuf_put_u8(extra, HS20_STYPE_OPERATING_CLASS);
+               if (all) {
+                       wpabuf_put_u8(extra,
+                                     HS20_STYPE_OPERATOR_FRIENDLY_NAME);
+                       wpabuf_put_u8(extra, HS20_STYPE_WAN_METRICS);
+                       wpabuf_put_u8(extra, HS20_STYPE_CONNECTION_CAPABILITY);
+                       wpabuf_put_u8(extra, HS20_STYPE_OPERATING_CLASS);
+               }
                gas_anqp_set_element_len(extra, len_pos);
        }
 #endif /* CONFIG_HS20 */
 
-       buf = anqp_build_req(info_ids, sizeof(info_ids) / sizeof(info_ids[0]),
-                            extra);
+       buf = anqp_build_req(info_ids, num_info_ids, extra);
        wpabuf_free(extra);
        if (buf == NULL)
                return -1;
@@ -1532,6 +1608,7 @@ int interworking_fetch_anqp(struct wpa_supplicant *wpa_s)
                return 0;
 
        wpa_s->network_select = 0;
+       wpa_s->fetch_all_anqp = 1;
 
        interworking_start_fetch_anqp(wpa_s);
 
@@ -1774,6 +1851,7 @@ int interworking_select(struct wpa_supplicant *wpa_s, int auto_select)
        wpa_s->network_select = 1;
        wpa_s->auto_network_select = 0;
        wpa_s->auto_select = !!auto_select;
+       wpa_s->fetch_all_anqp = 0;
        wpa_printf(MSG_DEBUG, "Interworking: Start scan for network "
                   "selection");
        wpa_s->scan_res_handler = interworking_scan_res_handler;
index 4c520ba..0bc2880 100644 (file)
@@ -588,6 +588,7 @@ struct wpa_supplicant {
        unsigned int network_select:1;
        unsigned int auto_select:1;
        unsigned int auto_network_select:1;
+       unsigned int fetch_all_anqp:1;
 #endif /* CONFIG_INTERWORKING */
        unsigned int drv_capa_known;