Interworking: Unshare ANQP results on explicit ANQP requests
authorJouni Malinen <jouni@qca.qualcomm.com>
Wed, 3 Oct 2012 11:17:41 +0000 (14:17 +0300)
committerJouni Malinen <j@w1.fi>
Wed, 3 Oct 2012 11:17:41 +0000 (14:17 +0300)
When ANQP_GET or HS20_ANQP_GET is used to request ANQP information,
unshare the ANQP information (i.e., create a per-BSS copy of it) to
make sure the information from the specified BSS is available in case
the APs provide different information within HESSID.

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

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

index 6223beb..0babbd5 100644 (file)
@@ -62,6 +62,60 @@ struct wpa_bss_anqp * wpa_bss_anqp_alloc(void)
 }
 
 
+static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp)
+{
+       struct wpa_bss_anqp *n;
+
+       n = os_zalloc(sizeof(*n));
+       if (n == NULL)
+               return NULL;
+
+#define ANQP_DUP(f) if (anqp->f) n->f = wpabuf_dup(anqp->f)
+#ifdef CONFIG_INTERWORKING
+       ANQP_DUP(venue_name);
+       ANQP_DUP(network_auth_type);
+       ANQP_DUP(roaming_consortium);
+       ANQP_DUP(ip_addr_type_availability);
+       ANQP_DUP(nai_realm);
+       ANQP_DUP(anqp_3gpp);
+       ANQP_DUP(domain_name);
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+       ANQP_DUP(hs20_operator_friendly_name);
+       ANQP_DUP(hs20_wan_metrics);
+       ANQP_DUP(hs20_connection_capability);
+       ANQP_DUP(hs20_operating_class);
+#endif /* CONFIG_HS20 */
+#undef ANQP_DUP
+
+       return n;
+}
+
+
+int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss)
+{
+       struct wpa_bss_anqp *anqp;
+
+       if (bss->anqp && bss->anqp->users > 1) {
+               /* allocated, but shared - clone an unshared copy */
+               anqp = wpa_bss_anqp_clone(bss->anqp);
+               if (anqp == NULL)
+                       return -1;
+               anqp->users = 1;
+               bss->anqp->users--;
+               bss->anqp = anqp;
+               return 0;
+       }
+
+       if (bss->anqp)
+               return 0; /* already allocated and not shared */
+
+       /* not allocated - allocate a new storage area */
+       bss->anqp = wpa_bss_anqp_alloc();
+       return bss->anqp ? 0 : -1;
+}
+
+
 static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
 {
        if (anqp == NULL)
index 4a386b6..eb01f2d 100644 (file)
@@ -113,5 +113,6 @@ struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
 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);
+int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss);
 
 #endif /* BSS_H */
index a2577c9..1404241 100644 (file)
@@ -79,8 +79,10 @@ int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
 
        freq = wpa_s->assoc_freq;
        bss = wpa_bss_get_bssid(wpa_s, dst);
-       if (bss)
+       if (bss) {
+               wpa_bss_anqp_unshare_alloc(bss);
                freq = bss->freq;
+       }
        if (freq <= 0)
                return -1;
 
index 8e870f6..6281c73 100644 (file)
@@ -1725,8 +1725,10 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
 
        freq = wpa_s->assoc_freq;
        bss = wpa_bss_get_bssid(wpa_s, dst);
-       if (bss)
+       if (bss) {
+               wpa_bss_anqp_unshare_alloc(bss);
                freq = bss->freq;
+       }
        if (freq <= 0)
                return -1;