From 485e3a92285c8c6da95427d4a2b633e3c24a8a5e Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 3 Oct 2012 14:17:41 +0300 Subject: [PATCH] Interworking: Unshare ANQP results on explicit ANQP requests 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 --- wpa_supplicant/bss.c | 54 ++++++++++++++++++++++++++++++++ wpa_supplicant/bss.h | 1 + wpa_supplicant/hs20_supplicant.c | 4 ++- wpa_supplicant/interworking.c | 4 ++- 4 files changed, 61 insertions(+), 2 deletions(-) diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c index 6223bebe9..0babbd5ef 100644 --- a/wpa_supplicant/bss.c +++ b/wpa_supplicant/bss.c @@ -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) diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h index 4a386b63b..eb01f2dae 100644 --- a/wpa_supplicant/bss.h +++ b/wpa_supplicant/bss.h @@ -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 */ diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c index a2577c938..14042419b 100644 --- a/wpa_supplicant/hs20_supplicant.c +++ b/wpa_supplicant/hs20_supplicant.c @@ -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; diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c index 8e870f6ee..6281c73f7 100644 --- a/wpa_supplicant/interworking.c +++ b/wpa_supplicant/interworking.c @@ -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;