]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Interworking: Support unknown ANQP-elements in BSS table
authorJouni Malinen <jouni@qca.qualcomm.com>
Wed, 7 Oct 2015 13:10:38 +0000 (16:10 +0300)
committerJouni Malinen <j@w1.fi>
Wed, 7 Oct 2015 14:07:21 +0000 (17:07 +0300)
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>
wpa_supplicant/bss.c
wpa_supplicant/bss.h
wpa_supplicant/ctrl_iface.c
wpa_supplicant/interworking.c

index 1051ee3a4c550482995c187887e4120184ea1ae2..704ee7e83696763a4c84f029090c2e3ebe2604a0 100644 (file)
@@ -60,6 +60,9 @@ struct wpa_bss_anqp * wpa_bss_anqp_alloc(void)
        anqp = os_zalloc(sizeof(*anqp));
        if (anqp == NULL)
                return NULL;
+#ifdef CONFIG_INTERWORKING
+       dl_list_init(&anqp->anqp_elems);
+#endif /* CONFIG_INTERWORKING */
        anqp->users = 1;
        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)
 #ifdef CONFIG_INTERWORKING
+       dl_list_init(&n->anqp_elems);
        ANQP_DUP(capability_list);
        ANQP_DUP(venue_name);
        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)
 {
+#ifdef CONFIG_INTERWORKING
+       struct wpa_bss_anqp_elem *elem;
+#endif /* CONFIG_INTERWORKING */
+
        if (anqp == NULL)
                return;
 
@@ -159,6 +167,13 @@ static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
        wpabuf_free(anqp->nai_realm);
        wpabuf_free(anqp->anqp_3gpp);
        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 */
 #ifdef CONFIG_HS20
        wpabuf_free(anqp->hs20_capability_list);
index b215380eeb15251582c07d5d57994b90786b30f6..4a782afe86e2a0d640bdc58c3222ecccf624635d 100644 (file)
@@ -19,6 +19,12 @@ struct wpa_scan_res;
 #define WPA_BSS_ASSOCIATED             BIT(5)
 #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)
  */
@@ -34,6 +40,7 @@ struct wpa_bss_anqp {
        struct wpabuf *nai_realm;
        struct wpabuf *anqp_3gpp;
        struct wpabuf *domain_name;
+       struct dl_list anqp_elems; /* list of struct wpa_bss_anqp_elem */
 #endif /* CONFIG_INTERWORKING */
 #ifdef CONFIG_HS20
        struct wpabuf *hs20_capability_list;
index 02d0cc2f65de4d889aa90f6a90037523b59c4d5a..c8868b2e1848aed65394fe30e237ac272fd3f5c2 100644 (file)
@@ -4231,6 +4231,8 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
 #ifdef CONFIG_INTERWORKING
        if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) {
                struct wpa_bss_anqp *anqp = bss->anqp;
+               struct wpa_bss_anqp_elem *elem;
+
                pos = anqp_add_hex(pos, end, "anqp_capability_list",
                                   anqp->capability_list);
                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",
                                   anqp->hs20_osu_providers_list);
 #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 */
 
index fd47c179ea4b17af3dbeef1b2a5257971aa37a97..9a6ab47c8f944acd2bf1f2d1f37d102b50b5c7ea 100644 (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,
                                            struct wpa_bss *bss, const u8 *sa,
                                            u16 info_id,
@@ -2849,6 +2884,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
        default:
                wpa_msg(wpa_s, MSG_DEBUG,
                        "Interworking: Unsupported ANQP Info ID %u", info_id);
+               anqp_add_extra(wpa_s, anqp, info_id, data, slen);
                break;
        }
 }