Interworking: Move BSS ANQP information into separate struct
authorJouni Malinen <jouni@qca.qualcomm.com>
Tue, 4 Sep 2012 13:02:29 +0000 (16:02 +0300)
committerJouni Malinen <j@w1.fi>
Tue, 4 Sep 2012 13:22:35 +0000 (16:22 +0300)
This is an initial step in allowing the ANQP responses to be shared
among multiple BSSes if the BSSes are determined to be operating under
identical configuration.

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

wpa_supplicant/bss.c
wpa_supplicant/bss.h
wpa_supplicant/ctrl_iface.c
wpa_supplicant/hs20_supplicant.c
wpa_supplicant/interworking.c

index 503aaa9..a999868 100644 (file)
 #define WPA_BSS_IES_CHANGED_FLAG       BIT(8)
 
 
+struct wpa_bss_anqp * wpa_bss_anqp_alloc(void)
+{
+       struct wpa_bss_anqp *anqp;
+       anqp = os_zalloc(sizeof(*anqp));
+       if (anqp == NULL)
+               return NULL;
+       anqp->users = 1;
+       return anqp;
+}
+
+
+static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
+{
+       if (anqp == NULL)
+               return;
+
+       anqp->users--;
+       if (anqp->users > 0) {
+               /* Another BSS entry holds a pointer to this ANQP info */
+               return;
+       }
+
+#ifdef CONFIG_INTERWORKING
+       wpabuf_free(anqp->venue_name);
+       wpabuf_free(anqp->network_auth_type);
+       wpabuf_free(anqp->roaming_consortium);
+       wpabuf_free(anqp->ip_addr_type_availability);
+       wpabuf_free(anqp->nai_realm);
+       wpabuf_free(anqp->anqp_3gpp);
+       wpabuf_free(anqp->domain_name);
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+       wpabuf_free(anqp->hs20_operator_friendly_name);
+       wpabuf_free(anqp->hs20_wan_metrics);
+       wpabuf_free(anqp->hs20_connection_capability);
+       wpabuf_free(anqp->hs20_operating_class);
+#endif /* CONFIG_HS20 */
+
+       os_free(anqp);
+}
+
+
 static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
                           const char *reason)
 {
@@ -58,21 +100,7 @@ static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
                " SSID '%s' due to %s", bss->id, MAC2STR(bss->bssid),
                wpa_ssid_txt(bss->ssid, bss->ssid_len), reason);
        wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id);
-#ifdef CONFIG_INTERWORKING
-       wpabuf_free(bss->anqp_venue_name);
-       wpabuf_free(bss->anqp_network_auth_type);
-       wpabuf_free(bss->anqp_roaming_consortium);
-       wpabuf_free(bss->anqp_ip_addr_type_availability);
-       wpabuf_free(bss->anqp_nai_realm);
-       wpabuf_free(bss->anqp_3gpp);
-       wpabuf_free(bss->anqp_domain_name);
-#endif /* CONFIG_INTERWORKING */
-#ifdef CONFIG_HS20
-       wpabuf_free(bss->hs20_operator_friendly_name);
-       wpabuf_free(bss->hs20_wan_metrics);
-       wpabuf_free(bss->hs20_connection_capability);
-       wpabuf_free(bss->hs20_operating_class);
-#endif /* CONFIG_HS20 */
+       wpa_bss_anqp_free(bss->anqp);
        os_free(bss);
 }
 
index ef9e5c3..31ae3da 100644 (file)
@@ -19,6 +19,25 @@ struct wpa_scan_res;
 #define WPA_BSS_ASSOCIATED             BIT(5)
 #define WPA_BSS_ANQP_FETCH_TRIED       BIT(6)
 
+struct wpa_bss_anqp {
+       unsigned int users;
+#ifdef CONFIG_INTERWORKING
+       struct wpabuf *venue_name;
+       struct wpabuf *network_auth_type;
+       struct wpabuf *roaming_consortium;
+       struct wpabuf *ip_addr_type_availability;
+       struct wpabuf *nai_realm;
+       struct wpabuf *anqp_3gpp;
+       struct wpabuf *domain_name;
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+       struct wpabuf *hs20_operator_friendly_name;
+       struct wpabuf *hs20_wan_metrics;
+       struct wpabuf *hs20_connection_capability;
+       struct wpabuf *hs20_operating_class;
+#endif /* CONFIG_HS20 */
+};
+
 /**
  * struct wpa_bss - BSS table
  * @list: List entry for struct wpa_supplicant::bss
@@ -60,21 +79,7 @@ struct wpa_bss {
        int level;
        u64 tsf;
        struct os_time last_update;
-#ifdef CONFIG_INTERWORKING
-       struct wpabuf *anqp_venue_name;
-       struct wpabuf *anqp_network_auth_type;
-       struct wpabuf *anqp_roaming_consortium;
-       struct wpabuf *anqp_ip_addr_type_availability;
-       struct wpabuf *anqp_nai_realm;
-       struct wpabuf *anqp_3gpp;
-       struct wpabuf *anqp_domain_name;
-#endif /* CONFIG_INTERWORKING */
-#ifdef CONFIG_HS20
-       struct wpabuf *hs20_operator_friendly_name;
-       struct wpabuf *hs20_wan_metrics;
-       struct wpabuf *hs20_connection_capability;
-       struct wpabuf *hs20_operating_class;
-#endif /* CONFIG_HS20 */
+       struct wpa_bss_anqp *anqp;
        size_t ie_len;
        size_t beacon_ie_len;
        /* followed by ie_len octets of IEs */
@@ -105,5 +110,6 @@ struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
                                                   u32 vendor_type);
 int wpa_bss_get_max_rate(const struct wpa_bss *bss);
 int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates);
+struct wpa_bss_anqp * wpa_bss_anqp_alloc(void);
 
 #endif /* BSS_H */
index df5ecd3..ba2edff 100644 (file)
@@ -2772,27 +2772,28 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
 #endif /* CONFIG_WIFI_DISPLAY */
 
 #ifdef CONFIG_INTERWORKING
-       if (mask & WPA_BSS_MASK_INTERNETW) {
+       if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) {
+               struct wpa_bss_anqp *anqp = bss->anqp;
                pos = anqp_add_hex(pos, end, "anqp_venue_name",
-                                  bss->anqp_venue_name);
+                                  anqp->venue_name);
                pos = anqp_add_hex(pos, end, "anqp_network_auth_type",
-                                  bss->anqp_network_auth_type);
+                                  anqp->network_auth_type);
                pos = anqp_add_hex(pos, end, "anqp_roaming_consortium",
-                                  bss->anqp_roaming_consortium);
+                                  anqp->roaming_consortium);
                pos = anqp_add_hex(pos, end, "anqp_ip_addr_type_availability",
-                                  bss->anqp_ip_addr_type_availability);
+                                  anqp->ip_addr_type_availability);
                pos = anqp_add_hex(pos, end, "anqp_nai_realm",
-                                  bss->anqp_nai_realm);
-               pos = anqp_add_hex(pos, end, "anqp_3gpp", bss->anqp_3gpp);
+                                  anqp->nai_realm);
+               pos = anqp_add_hex(pos, end, "anqp_3gpp", anqp->anqp_3gpp);
                pos = anqp_add_hex(pos, end, "anqp_domain_name",
-                                  bss->anqp_domain_name);
+                                  anqp->domain_name);
 #ifdef CONFIG_HS20
                pos = anqp_add_hex(pos, end, "hs20_operator_friendly_name",
-                                  bss->hs20_operator_friendly_name);
+                                  anqp->hs20_operator_friendly_name);
                pos = anqp_add_hex(pos, end, "hs20_wan_metrics",
-                                  bss->hs20_wan_metrics);
+                                  anqp->hs20_wan_metrics);
                pos = anqp_add_hex(pos, end, "hs20_connection_capability",
-                                  bss->hs20_connection_capability);
+                                  anqp->hs20_connection_capability);
 #endif /* CONFIG_HS20 */
        }
 #endif /* CONFIG_INTERWORKING */
index 2afa16c..0eb6119 100644 (file)
@@ -110,10 +110,14 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
        const u8 *pos = data;
        u8 subtype;
        struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
+       struct wpa_bss_anqp *anqp = NULL;
 
        if (slen < 2)
                return;
 
+       if (bss)
+               anqp = bss->anqp;
+
        subtype = *pos++;
        slen--;
 
@@ -130,9 +134,9 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
                wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
                        " Operator Friendly Name", MAC2STR(sa));
                wpa_hexdump_ascii(MSG_DEBUG, "oper friendly name", pos, slen);
-               if (bss) {
-                       wpabuf_free(bss->hs20_operator_friendly_name);
-                       bss->hs20_operator_friendly_name =
+               if (anqp) {
+                       wpabuf_free(anqp->hs20_operator_friendly_name);
+                       anqp->hs20_operator_friendly_name =
                                wpabuf_alloc_copy(pos, slen);
                }
                break;
@@ -140,18 +144,18 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
                wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
                        " WAN Metrics", MAC2STR(sa));
                wpa_hexdump_ascii(MSG_DEBUG, "WAN Metrics", pos, slen);
-               if (bss) {
-                       wpabuf_free(bss->hs20_wan_metrics);
-                       bss->hs20_wan_metrics = wpabuf_alloc_copy(pos, slen);
+               if (anqp) {
+                       wpabuf_free(anqp->hs20_wan_metrics);
+                       anqp->hs20_wan_metrics = wpabuf_alloc_copy(pos, slen);
                }
                break;
        case HS20_STYPE_CONNECTION_CAPABILITY:
                wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
                        " Connection Capability", MAC2STR(sa));
                wpa_hexdump_ascii(MSG_DEBUG, "conn capability", pos, slen);
-               if (bss) {
-                       wpabuf_free(bss->hs20_connection_capability);
-                       bss->hs20_connection_capability =
+               if (anqp) {
+                       wpabuf_free(anqp->hs20_connection_capability);
+                       anqp->hs20_connection_capability =
                                wpabuf_alloc_copy(pos, slen);
                }
                break;
@@ -159,9 +163,9 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
                wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
                        " Operating Class", MAC2STR(sa));
                wpa_hexdump_ascii(MSG_DEBUG, "Operating Class", pos, slen);
-               if (bss) {
-                       wpabuf_free(bss->hs20_operating_class);
-                       bss->hs20_operating_class =
+               if (anqp) {
+                       wpabuf_free(anqp->hs20_operating_class);
+                       anqp->hs20_operating_class =
                                wpabuf_alloc_copy(pos, slen);
                }
                break;
index 20c7731..bbcfe4d 100644 (file)
@@ -737,7 +737,7 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
        struct wpa_ssid *ssid;
        const u8 *ie;
 
-       if (bss->anqp_3gpp == NULL)
+       if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
                return -1;
 
        for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
@@ -768,7 +768,7 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
 #ifdef PCSC_FUNCS
        compare:
 #endif /* PCSC_FUNCS */
-               if (plmn_id_match(bss->anqp_3gpp, imsi, mnc_len))
+               if (plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len))
                        break;
        }
        if (cred == NULL)
@@ -923,7 +923,8 @@ static struct wpa_cred * interworking_credentials_available_roaming_consortium(
 
        ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
 
-       if (ie == NULL && bss->anqp_roaming_consortium == NULL)
+       if (ie == NULL &&
+           (bss->anqp == NULL || bss->anqp->roaming_consortium == NULL))
                return NULL;
 
        if (wpa_s->conf->cred == NULL)
@@ -933,7 +934,10 @@ static struct wpa_cred * interworking_credentials_available_roaming_consortium(
                if (cred->roaming_consortium_len == 0)
                        continue;
 
-               if (!roaming_consortium_match(ie, bss->anqp_roaming_consortium,
+               if (!roaming_consortium_match(ie,
+                                             bss->anqp ?
+                                             bss->anqp->roaming_consortium :
+                                             NULL,
                                              cred->roaming_consortium,
                                              cred->roaming_consortium_len))
                        continue;
@@ -1123,7 +1127,8 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
                return interworking_connect_roaming_consortium(wpa_s, cred,
                                                               bss, ie);
 
-       realm = nai_realm_parse(bss->anqp_nai_realm, &count);
+       realm = nai_realm_parse(bss->anqp ? bss->anqp->nai_realm : NULL,
+                               &count);
        if (realm == NULL) {
                wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
                           "Realm list from " MACSTR, MAC2STR(bss->bssid));
@@ -1250,7 +1255,7 @@ static struct wpa_cred * interworking_credentials_available_3gpp(
        int ret;
 
 #ifdef INTERWORKING_3GPP
-       if (bss->anqp_3gpp == NULL)
+       if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
                return NULL;
 
        for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
@@ -1283,7 +1288,7 @@ static struct wpa_cred * interworking_credentials_available_3gpp(
 #endif /* PCSC_FUNCS */
                wpa_printf(MSG_DEBUG, "Interworking: Parsing 3GPP info from "
                           MACSTR, MAC2STR(bss->bssid));
-               ret = plmn_id_match(bss->anqp_3gpp, imsi, mnc_len);
+               ret = plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len);
                wpa_printf(MSG_DEBUG, "PLMN match %sfound", ret ? "" : "not ");
                if (ret) {
                        if (selected == NULL ||
@@ -1303,7 +1308,7 @@ static struct wpa_cred * interworking_credentials_available_realm(
        struct nai_realm *realm;
        u16 count, i;
 
-       if (bss->anqp_nai_realm == NULL)
+       if (bss->anqp == NULL || bss->anqp->nai_realm == NULL)
                return NULL;
 
        if (wpa_s->conf->cred == NULL)
@@ -1311,7 +1316,7 @@ static struct wpa_cred * interworking_credentials_available_realm(
 
        wpa_printf(MSG_DEBUG, "Interworking: Parsing NAI Realm list from "
                   MACSTR, MAC2STR(bss->bssid));
-       realm = nai_realm_parse(bss->anqp_nai_realm, &count);
+       realm = nai_realm_parse(bss->anqp->nai_realm, &count);
        if (realm == NULL) {
                wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
                           "Realm list from " MACSTR, MAC2STR(bss->bssid));
@@ -1492,7 +1497,8 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s)
                        continue;
                }
                count++;
-               res = interworking_home_sp(wpa_s, bss->anqp_domain_name);
+               res = interworking_home_sp(wpa_s, bss->anqp ?
+                                          bss->anqp->domain_name : NULL);
                if (res > 0)
                        type = "home";
                else if (res == 0)
@@ -1572,6 +1578,11 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
                        continue; /* AP does not support Interworking */
 
                if (!(bss->flags & WPA_BSS_ANQP_FETCH_TRIED)) {
+                       if (bss->anqp == NULL) {
+                               bss->anqp = wpa_bss_anqp_alloc();
+                               if (bss->anqp == NULL)
+                                       break;
+                       }
                        found++;
                        bss->flags |= WPA_BSS_ANQP_FETCH_TRIED;
                        wpa_msg(wpa_s, MSG_INFO, "Starting ANQP fetch for "
@@ -1667,10 +1678,14 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
 {
        const u8 *pos = data;
        struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
+       struct wpa_bss_anqp *anqp = NULL;
 #ifdef CONFIG_HS20
        u8 type;
 #endif /* CONFIG_HS20 */
 
+       if (bss)
+               anqp = bss->anqp;
+
        switch (info_id) {
        case ANQP_CAPABILITY_LIST:
                wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
@@ -1680,9 +1695,9 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
                wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
                        " Venue Name", MAC2STR(sa));
                wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Venue Name", pos, slen);
-               if (bss) {
-                       wpabuf_free(bss->anqp_venue_name);
-                       bss->anqp_venue_name = wpabuf_alloc_copy(pos, slen);
+               if (anqp) {
+                       wpabuf_free(anqp->venue_name);
+                       anqp->venue_name = wpabuf_alloc_copy(pos, slen);
                }
                break;
        case ANQP_NETWORK_AUTH_TYPE:
@@ -1691,10 +1706,9 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
                        MAC2STR(sa));
                wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Network Authentication "
                                  "Type", pos, slen);
-               if (bss) {
-                       wpabuf_free(bss->anqp_network_auth_type);
-                       bss->anqp_network_auth_type =
-                               wpabuf_alloc_copy(pos, slen);
+               if (anqp) {
+                       wpabuf_free(anqp->network_auth_type);
+                       anqp->network_auth_type = wpabuf_alloc_copy(pos, slen);
                }
                break;
        case ANQP_ROAMING_CONSORTIUM:
@@ -1702,10 +1716,9 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
                        " Roaming Consortium list", MAC2STR(sa));
                wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Roaming Consortium",
                                  pos, slen);
-               if (bss) {
-                       wpabuf_free(bss->anqp_roaming_consortium);
-                       bss->anqp_roaming_consortium =
-                               wpabuf_alloc_copy(pos, slen);
+               if (anqp) {
+                       wpabuf_free(anqp->roaming_consortium);
+                       anqp->roaming_consortium = wpabuf_alloc_copy(pos, slen);
                }
                break;
        case ANQP_IP_ADDR_TYPE_AVAILABILITY:
@@ -1714,9 +1727,9 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
                        MAC2STR(sa));
                wpa_hexdump(MSG_MSGDUMP, "ANQP: IP Address Availability",
                            pos, slen);
-               if (bss) {
-                       wpabuf_free(bss->anqp_ip_addr_type_availability);
-                       bss->anqp_ip_addr_type_availability =
+               if (anqp) {
+                       wpabuf_free(anqp->ip_addr_type_availability);
+                       anqp->ip_addr_type_availability =
                                wpabuf_alloc_copy(pos, slen);
                }
                break;
@@ -1724,9 +1737,9 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
                wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
                        " NAI Realm list", MAC2STR(sa));
                wpa_hexdump_ascii(MSG_DEBUG, "ANQP: NAI Realm", pos, slen);
-               if (bss) {
-                       wpabuf_free(bss->anqp_nai_realm);
-                       bss->anqp_nai_realm = wpabuf_alloc_copy(pos, slen);
+               if (anqp) {
+                       wpabuf_free(anqp->nai_realm);
+                       anqp->nai_realm = wpabuf_alloc_copy(pos, slen);
                }
                break;
        case ANQP_3GPP_CELLULAR_NETWORK:
@@ -1734,18 +1747,18 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
                        " 3GPP Cellular Network information", MAC2STR(sa));
                wpa_hexdump_ascii(MSG_DEBUG, "ANQP: 3GPP Cellular Network",
                                  pos, slen);
-               if (bss) {
-                       wpabuf_free(bss->anqp_3gpp);
-                       bss->anqp_3gpp = wpabuf_alloc_copy(pos, slen);
+               if (anqp) {
+                       wpabuf_free(anqp->anqp_3gpp);
+                       anqp->anqp_3gpp = wpabuf_alloc_copy(pos, slen);
                }
                break;
        case ANQP_DOMAIN_NAME:
                wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
                        " Domain Name list", MAC2STR(sa));
                wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: Domain Name", pos, slen);
-               if (bss) {
-                       wpabuf_free(bss->anqp_domain_name);
-                       bss->anqp_domain_name = wpabuf_alloc_copy(pos, slen);
+               if (anqp) {
+                       wpabuf_free(anqp->domain_name);
+                       anqp->domain_name = wpabuf_alloc_copy(pos, slen);
                }
                break;
        case ANQP_VENDOR_SPECIFIC: