Interworking: Support unknown ANQP-elements in BSS table

This allows wpa_supplicant to expose internally unknown ANQP-elements in
the BSS command. For example, "ANQP_GET <BSSID> 265" can be used to
fetch the AP Geospatial Location ANQP-element and if the AP has this
information, the "BSS <BSSID>" command will include the response as
"anqp[265]=<hexdump>".

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
Jouni Malinen 2015-10-07 16:10:38 +03:00 committed by Jouni Malinen
parent aeeb0bca71
commit 8c4a1026b8
4 changed files with 69 additions and 0 deletions

View file

@ -60,6 +60,9 @@ struct wpa_bss_anqp * wpa_bss_anqp_alloc(void)
anqp = os_zalloc(sizeof(*anqp)); anqp = os_zalloc(sizeof(*anqp));
if (anqp == NULL) if (anqp == NULL)
return NULL; return NULL;
#ifdef CONFIG_INTERWORKING
dl_list_init(&anqp->anqp_elems);
#endif /* CONFIG_INTERWORKING */
anqp->users = 1; anqp->users = 1;
return anqp; return anqp;
} }
@ -80,6 +83,7 @@ static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp)
#define ANQP_DUP(f) if (anqp->f) n->f = wpabuf_dup(anqp->f) #define ANQP_DUP(f) if (anqp->f) n->f = wpabuf_dup(anqp->f)
#ifdef CONFIG_INTERWORKING #ifdef CONFIG_INTERWORKING
dl_list_init(&n->anqp_elems);
ANQP_DUP(capability_list); ANQP_DUP(capability_list);
ANQP_DUP(venue_name); ANQP_DUP(venue_name);
ANQP_DUP(network_auth_type); ANQP_DUP(network_auth_type);
@ -141,6 +145,10 @@ int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss)
*/ */
static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp) static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
{ {
#ifdef CONFIG_INTERWORKING
struct wpa_bss_anqp_elem *elem;
#endif /* CONFIG_INTERWORKING */
if (anqp == NULL) if (anqp == NULL)
return; return;
@ -159,6 +167,13 @@ static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
wpabuf_free(anqp->nai_realm); wpabuf_free(anqp->nai_realm);
wpabuf_free(anqp->anqp_3gpp); wpabuf_free(anqp->anqp_3gpp);
wpabuf_free(anqp->domain_name); wpabuf_free(anqp->domain_name);
while ((elem = dl_list_first(&anqp->anqp_elems,
struct wpa_bss_anqp_elem, list))) {
dl_list_del(&elem->list);
wpabuf_free(elem->payload);
os_free(elem);
}
#endif /* CONFIG_INTERWORKING */ #endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_HS20 #ifdef CONFIG_HS20
wpabuf_free(anqp->hs20_capability_list); wpabuf_free(anqp->hs20_capability_list);

View file

@ -19,6 +19,12 @@ struct wpa_scan_res;
#define WPA_BSS_ASSOCIATED BIT(5) #define WPA_BSS_ASSOCIATED BIT(5)
#define WPA_BSS_ANQP_FETCH_TRIED BIT(6) #define WPA_BSS_ANQP_FETCH_TRIED BIT(6)
struct wpa_bss_anqp_elem {
struct dl_list list;
u16 infoid;
struct wpabuf *payload;
};
/** /**
* struct wpa_bss_anqp - ANQP data for a BSS entry (struct wpa_bss) * struct wpa_bss_anqp - ANQP data for a BSS entry (struct wpa_bss)
*/ */
@ -34,6 +40,7 @@ struct wpa_bss_anqp {
struct wpabuf *nai_realm; struct wpabuf *nai_realm;
struct wpabuf *anqp_3gpp; struct wpabuf *anqp_3gpp;
struct wpabuf *domain_name; struct wpabuf *domain_name;
struct dl_list anqp_elems; /* list of struct wpa_bss_anqp_elem */
#endif /* CONFIG_INTERWORKING */ #endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_HS20 #ifdef CONFIG_HS20
struct wpabuf *hs20_capability_list; struct wpabuf *hs20_capability_list;

View file

@ -4231,6 +4231,8 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
#ifdef CONFIG_INTERWORKING #ifdef CONFIG_INTERWORKING
if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) { if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) {
struct wpa_bss_anqp *anqp = bss->anqp; struct wpa_bss_anqp *anqp = bss->anqp;
struct wpa_bss_anqp_elem *elem;
pos = anqp_add_hex(pos, end, "anqp_capability_list", pos = anqp_add_hex(pos, end, "anqp_capability_list",
anqp->capability_list); anqp->capability_list);
pos = anqp_add_hex(pos, end, "anqp_venue_name", pos = anqp_add_hex(pos, end, "anqp_venue_name",
@ -4260,6 +4262,15 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
pos = anqp_add_hex(pos, end, "hs20_osu_providers_list", pos = anqp_add_hex(pos, end, "hs20_osu_providers_list",
anqp->hs20_osu_providers_list); anqp->hs20_osu_providers_list);
#endif /* CONFIG_HS20 */ #endif /* CONFIG_HS20 */
dl_list_for_each(elem, &anqp->anqp_elems,
struct wpa_bss_anqp_elem, list) {
char title[20];
os_snprintf(title, sizeof(title), "anqp[%u]",
elem->infoid);
pos = anqp_add_hex(pos, end, title, elem->payload);
}
} }
#endif /* CONFIG_INTERWORKING */ #endif /* CONFIG_INTERWORKING */

View file

@ -2716,6 +2716,41 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
} }
static void anqp_add_extra(struct wpa_supplicant *wpa_s,
struct wpa_bss_anqp *anqp, u16 info_id,
const u8 *data, size_t slen)
{
struct wpa_bss_anqp_elem *tmp, *elem = NULL;
if (!anqp)
return;
dl_list_for_each(tmp, &anqp->anqp_elems, struct wpa_bss_anqp_elem,
list) {
if (tmp->infoid == info_id) {
elem = tmp;
break;
}
}
if (!elem) {
elem = os_zalloc(sizeof(*elem));
if (!elem)
return;
elem->infoid = info_id;
dl_list_add(&anqp->anqp_elems, &elem->list);
} else {
wpabuf_free(elem->payload);
}
elem->payload = wpabuf_alloc_copy(data, slen);
if (!elem->payload) {
dl_list_del(&elem->list);
os_free(elem);
}
}
static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, const u8 *sa, struct wpa_bss *bss, const u8 *sa,
u16 info_id, u16 info_id,
@ -2849,6 +2884,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
default: default:
wpa_msg(wpa_s, MSG_DEBUG, wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Unsupported ANQP Info ID %u", info_id); "Interworking: Unsupported ANQP Info ID %u", info_id);
anqp_add_extra(wpa_s, anqp, info_id, data, slen);
break; break;
} }
} }