HS 2.0: Extend ANQP_GET to accept Hotspot 2.0 subtypes

This allows a single ANQP query to be used to fetch both IEEE 802.11
defined ANQP elements and Hotspot 2.0 vendor specific elements.

ANQP_GET <addr> <info id>[,<info id>]...
[,hs20:<subtype>][...,hs20:<subtype>]

For example:
ANQP_GET 00:11:22:33:44:55:66 258,268,hs20:3,hs20:4

Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
This commit is contained in:
Dmitry Shmidt 2014-03-24 17:36:13 -07:00 committed by Jouni Malinen
parent 163f801ef2
commit cf28c66bcb
5 changed files with 48 additions and 12 deletions

View file

@ -4945,15 +4945,27 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
#define MAX_ANQP_INFO_ID 100 #define MAX_ANQP_INFO_ID 100
u16 id[MAX_ANQP_INFO_ID]; u16 id[MAX_ANQP_INFO_ID];
size_t num_id = 0; size_t num_id = 0;
u32 subtypes = 0;
used = hwaddr_aton2(dst, dst_addr); used = hwaddr_aton2(dst, dst_addr);
if (used < 0) if (used < 0)
return -1; return -1;
pos = dst + used; pos = dst + used;
while (num_id < MAX_ANQP_INFO_ID) { while (num_id < MAX_ANQP_INFO_ID) {
if (os_strncmp(pos, "hs20:", 5) == 0) {
#ifdef CONFIG_HS20
int num = atoi(pos + 5);
if (num <= 0 || num > 31)
return -1;
subtypes |= BIT(num);
#else /* CONFIG_HS20 */
return -1;
#endif /* CONFIG_HS20 */
} else {
id[num_id] = atoi(pos); id[num_id] = atoi(pos);
if (id[num_id]) if (id[num_id])
num_id++; num_id++;
}
pos = os_strchr(pos + 1, ','); pos = os_strchr(pos + 1, ',');
if (pos == NULL) if (pos == NULL)
break; break;
@ -4963,7 +4975,7 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
if (num_id == 0) if (num_id == 0)
return -1; return -1;
return anqp_send_req(wpa_s, dst_addr, id, num_id); return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes);
} }

View file

@ -121,15 +121,13 @@ int hs20_get_pps_mo_id(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
} }
struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload, void hs20_put_anqp_req(u32 stypes, const u8 *payload, size_t payload_len,
size_t payload_len) struct wpabuf *buf)
{ {
struct wpabuf *buf;
u8 *len_pos; u8 *len_pos;
buf = gas_anqp_build_initial_req(0, 100 + payload_len);
if (buf == NULL) if (buf == NULL)
return NULL; return;
len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
wpabuf_put_be24(buf, OUI_WFA); wpabuf_put_be24(buf, OUI_WFA);
@ -156,6 +154,19 @@ struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
gas_anqp_set_element_len(buf, len_pos); gas_anqp_set_element_len(buf, len_pos);
gas_anqp_set_len(buf); gas_anqp_set_len(buf);
}
struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
size_t payload_len)
{
struct wpabuf *buf;
buf = gas_anqp_build_initial_req(0, 100 + payload_len);
if (buf == NULL)
return NULL;
hs20_put_anqp_req(stypes, payload, payload_len, buf);
return buf; return buf;
} }

View file

@ -14,6 +14,8 @@ int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
const u8 *payload, size_t payload_len); const u8 *payload, size_t payload_len);
struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload, struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
size_t payload_len); size_t payload_len);
void hs20_put_anqp_req(u32 stypes, const u8 *payload, size_t payload_len,
struct wpabuf *buf);
void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
const u8 *sa, const u8 *data, size_t slen); const u8 *sa, const u8 *data, size_t slen);
int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,

View file

@ -2531,9 +2531,10 @@ void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s)
int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
u16 info_ids[], size_t num_ids) u16 info_ids[], size_t num_ids, u32 subtypes)
{ {
struct wpabuf *buf; struct wpabuf *buf;
struct wpabuf *hs20_buf = NULL;
int ret = 0; int ret = 0;
int freq; int freq;
struct wpa_bss *bss; struct wpa_bss *bss;
@ -2551,7 +2552,17 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
wpa_printf(MSG_DEBUG, "ANQP: Query Request to " MACSTR " for %u id(s)", wpa_printf(MSG_DEBUG, "ANQP: Query Request to " MACSTR " for %u id(s)",
MAC2STR(dst), (unsigned int) num_ids); MAC2STR(dst), (unsigned int) num_ids);
buf = anqp_build_req(info_ids, num_ids, NULL); #ifdef CONFIG_HS20
if (subtypes != 0) {
hs20_buf = wpabuf_alloc(100);
if (hs20_buf == NULL)
return -1;
hs20_put_anqp_req(subtypes, NULL, 0, hs20_buf);
}
#endif /* CONFIG_HS20 */
buf = anqp_build_req(info_ids, num_ids, hs20_buf);
wpabuf_free(hs20_buf);
if (buf == NULL) if (buf == NULL)
return -1; return -1;

View file

@ -12,7 +12,7 @@
enum gas_query_result; enum gas_query_result;
int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
u16 info_ids[], size_t num_ids); u16 info_ids[], size_t num_ids, u32 subtypes);
void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token, void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
enum gas_query_result result, enum gas_query_result result,
const struct wpabuf *adv_proto, const struct wpabuf *adv_proto,