HS 2.0R2: Add routine for fetching OSU provider information
The new wpa_cli fetch_osu command can be used to fetch information about all OSU providers and write that to a text file with the icons in separate files. cancel_osu_fetch command can be used to stop ongoing OSU provider list fetch. Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
1d2215fc67
commit
b572df8650
9 changed files with 673 additions and 41 deletions
|
@ -1999,6 +1999,7 @@ void wpa_config_free(struct wpa_config *config)
|
|||
os_free(config->ext_password_backend);
|
||||
os_free(config->sae_groups);
|
||||
wpabuf_free(config->ap_vendor_elements);
|
||||
os_free(config->osu_dir);
|
||||
os_free(config);
|
||||
}
|
||||
|
||||
|
@ -3464,6 +3465,7 @@ static const struct global_parse_data global_fields[] = {
|
|||
{ INT(scan_cur_freq), 0 },
|
||||
{ INT(sched_scan_interval), 0 },
|
||||
{ INT(tdls_external_control), 0},
|
||||
{ STR(osu_dir), 0 },
|
||||
};
|
||||
|
||||
#undef FUNC
|
||||
|
|
|
@ -963,6 +963,15 @@ struct wpa_config {
|
|||
u8 ip_addr_mask[4];
|
||||
u8 ip_addr_start[4];
|
||||
u8 ip_addr_end[4];
|
||||
|
||||
/**
|
||||
* osu_dir - OSU provider information directory
|
||||
*
|
||||
* If set, allow FETCH_OSU control interface command to be used to fetch
|
||||
* OSU provider information into all APs and store the results in this
|
||||
* directory.
|
||||
*/
|
||||
char *osu_dir;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -5197,6 +5197,7 @@ static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd)
|
|||
used++;
|
||||
icon = &cmd[used];
|
||||
|
||||
wpa_s->fetch_osu_icon_in_progress = 0;
|
||||
return hs20_anqp_send_req(wpa_s, dst_addr, BIT(HS20_STYPE_ICON_REQUEST),
|
||||
(u8 *) icon, os_strlen(icon));
|
||||
}
|
||||
|
@ -5495,6 +5496,10 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
|
|||
radio_remove_works(wpa_s, NULL, 1);
|
||||
|
||||
wpa_s->next_ssid = NULL;
|
||||
|
||||
#ifdef CONFIG_INTERWORKING
|
||||
hs20_cancel_fetch_osu(wpa_s);
|
||||
#endif /* CONFIG_INTERWORKING */
|
||||
}
|
||||
|
||||
|
||||
|
@ -6129,6 +6134,11 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
|
|||
} else if (os_strncmp(buf, "HS20_ICON_REQUEST ", 18) == 0) {
|
||||
if (hs20_icon_request(wpa_s, buf + 18) < 0)
|
||||
reply_len = -1;
|
||||
} else if (os_strcmp(buf, "FETCH_OSU") == 0) {
|
||||
if (hs20_fetch_osu(wpa_s) < 0)
|
||||
reply_len = -1;
|
||||
} else if (os_strcmp(buf, "CANCEL_FETCH_OSU") == 0) {
|
||||
hs20_cancel_fetch_osu(wpa_s);
|
||||
#endif /* CONFIG_HS20 */
|
||||
} else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
|
||||
{
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "wpa_supplicant_i.h"
|
||||
#include "driver_i.h"
|
||||
#include "config.h"
|
||||
#include "scan.h"
|
||||
#include "bss.h"
|
||||
#include "blacklist.h"
|
||||
#include "gas_query.h"
|
||||
|
@ -25,6 +26,39 @@
|
|||
#include "hs20_supplicant.h"
|
||||
|
||||
|
||||
#define OSU_MAX_ITEMS 10
|
||||
|
||||
struct osu_lang_string {
|
||||
char lang[4];
|
||||
char text[253];
|
||||
};
|
||||
|
||||
struct osu_icon {
|
||||
u16 width;
|
||||
u16 height;
|
||||
char lang[4];
|
||||
char icon_type[256];
|
||||
char filename[256];
|
||||
unsigned int id;
|
||||
unsigned int failed:1;
|
||||
};
|
||||
|
||||
struct osu_provider {
|
||||
u8 bssid[ETH_ALEN];
|
||||
u8 osu_ssid[32];
|
||||
u8 osu_ssid_len;
|
||||
char server_uri[256];
|
||||
u32 osu_methods; /* bit 0 = OMA-DM, bit 1 = SOAP-XML SPP */
|
||||
char osu_nai[256];
|
||||
struct osu_lang_string friendly_name[OSU_MAX_ITEMS];
|
||||
size_t friendly_name_count;
|
||||
struct osu_lang_string serv_desc[OSU_MAX_ITEMS];
|
||||
size_t serv_desc_count;
|
||||
struct osu_icon icon[OSU_MAX_ITEMS];
|
||||
size_t icon_count;
|
||||
};
|
||||
|
||||
|
||||
void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id)
|
||||
{
|
||||
u8 conf;
|
||||
|
@ -165,6 +199,107 @@ int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
|
|||
}
|
||||
|
||||
|
||||
static int hs20_process_icon_binary_file(struct wpa_supplicant *wpa_s,
|
||||
const u8 *sa, const u8 *pos,
|
||||
size_t slen)
|
||||
{
|
||||
char fname[256];
|
||||
int png;
|
||||
FILE *f;
|
||||
u16 data_len;
|
||||
|
||||
wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR " Icon Binary File",
|
||||
MAC2STR(sa));
|
||||
|
||||
if (slen < 4) {
|
||||
wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File "
|
||||
"value from " MACSTR, MAC2STR(sa));
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Download Status Code %u", *pos);
|
||||
if (*pos != 0)
|
||||
return -1;
|
||||
pos++;
|
||||
slen--;
|
||||
|
||||
if ((size_t) 1 + pos[0] > slen) {
|
||||
wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File "
|
||||
"value from " MACSTR, MAC2STR(sa));
|
||||
return -1;
|
||||
}
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "Icon Type", pos + 1, pos[0]);
|
||||
png = os_strncasecmp((char *) pos + 1, "image/png", 9) == 0;
|
||||
slen -= 1 + pos[0];
|
||||
pos += 1 + pos[0];
|
||||
|
||||
if (slen < 2) {
|
||||
wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File "
|
||||
"value from " MACSTR, MAC2STR(sa));
|
||||
return -1;
|
||||
}
|
||||
data_len = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
slen -= 2;
|
||||
|
||||
if (data_len > slen) {
|
||||
wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File "
|
||||
"value from " MACSTR, MAC2STR(sa));
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Icon Binary Data: %u bytes", data_len);
|
||||
if (wpa_s->conf->osu_dir == NULL)
|
||||
return -1;
|
||||
|
||||
wpa_s->osu_icon_id++;
|
||||
if (wpa_s->osu_icon_id == 0)
|
||||
wpa_s->osu_icon_id++;
|
||||
snprintf(fname, sizeof(fname), "%s/osu-icon-%u.%s",
|
||||
wpa_s->conf->osu_dir, wpa_s->osu_icon_id,
|
||||
png ? "png" : "icon");
|
||||
f = fopen(fname, "wb");
|
||||
if (f == NULL)
|
||||
return -1;
|
||||
if (fwrite(pos, slen, 1, f) != 1) {
|
||||
fclose(f);
|
||||
unlink(fname);
|
||||
return -1;
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP-ICON %s", fname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void hs20_continue_icon_fetch(void *eloop_ctx, void *sock_ctx)
|
||||
{
|
||||
struct wpa_supplicant *wpa_s = eloop_ctx;
|
||||
if (wpa_s->fetch_osu_icon_in_progress)
|
||||
hs20_next_osu_icon(wpa_s);
|
||||
}
|
||||
|
||||
|
||||
static void hs20_osu_icon_fetch_result(struct wpa_supplicant *wpa_s, int res)
|
||||
{
|
||||
size_t i, j;
|
||||
for (i = 0; i < wpa_s->osu_prov_count; i++) {
|
||||
struct osu_provider *osu = &wpa_s->osu_prov[i];
|
||||
for (j = 0; j < osu->icon_count; j++) {
|
||||
struct osu_icon *icon = &osu->icon[j];
|
||||
if (icon->id || icon->failed)
|
||||
continue;
|
||||
if (res < 0)
|
||||
icon->failed = 1;
|
||||
else
|
||||
icon->id = wpa_s->osu_icon_id;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
|
||||
const u8 *sa, const u8 *data, size_t slen)
|
||||
{
|
||||
|
@ -172,7 +307,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
|
|||
u8 subtype;
|
||||
struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
|
||||
struct wpa_bss_anqp *anqp = NULL;
|
||||
u16 data_len;
|
||||
int ret;
|
||||
|
||||
if (slen < 2)
|
||||
return;
|
||||
|
@ -248,44 +383,14 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
|
|||
}
|
||||
break;
|
||||
case HS20_STYPE_ICON_BINARY_FILE:
|
||||
wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
|
||||
" Icon Binary File", MAC2STR(sa));
|
||||
|
||||
if (slen < 4) {
|
||||
wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon "
|
||||
"Binary File value from " MACSTR, MAC2STR(sa));
|
||||
break;
|
||||
ret = hs20_process_icon_binary_file(wpa_s, sa, pos, slen);
|
||||
if (wpa_s->fetch_osu_icon_in_progress) {
|
||||
hs20_osu_icon_fetch_result(wpa_s, ret);
|
||||
eloop_cancel_timeout(hs20_continue_icon_fetch,
|
||||
wpa_s, NULL);
|
||||
eloop_register_timeout(0, 0, hs20_continue_icon_fetch,
|
||||
wpa_s, NULL);
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Download Status Code %u", *pos);
|
||||
pos++;
|
||||
slen--;
|
||||
|
||||
if ((size_t) 1 + pos[0] > slen) {
|
||||
wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon "
|
||||
"Binary File value from " MACSTR, MAC2STR(sa));
|
||||
break;
|
||||
}
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "Icon Type", pos + 1, pos[0]);
|
||||
slen -= 1 + pos[0];
|
||||
pos += 1 + pos[0];
|
||||
|
||||
if (slen < 2) {
|
||||
wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon "
|
||||
"Binary File value from " MACSTR, MAC2STR(sa));
|
||||
break;
|
||||
}
|
||||
data_len = WPA_GET_BE16(pos);
|
||||
pos += 2;
|
||||
slen -= 2;
|
||||
|
||||
if (data_len > slen) {
|
||||
wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon "
|
||||
"Binary File value from " MACSTR, MAC2STR(sa));
|
||||
break;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Icon Binary Data: %u bytes", data_len);
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "HS20: Unsupported subtype %u", subtype);
|
||||
|
@ -294,6 +399,444 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
|
|||
}
|
||||
|
||||
|
||||
void hs20_notify_parse_done(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
if (!wpa_s->fetch_osu_icon_in_progress)
|
||||
return;
|
||||
if (eloop_is_timeout_registered(hs20_continue_icon_fetch, wpa_s, NULL))
|
||||
return;
|
||||
/*
|
||||
* We are going through icon fetch, but no icon response was received.
|
||||
* Assume this means the current AP could not provide an answer to avoid
|
||||
* getting stuck in fetch iteration.
|
||||
*/
|
||||
hs20_icon_fetch_failed(wpa_s);
|
||||
}
|
||||
|
||||
|
||||
static void hs20_free_osu_prov_entry(struct osu_provider *prov)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void hs20_free_osu_prov(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < wpa_s->osu_prov_count; i++)
|
||||
hs20_free_osu_prov_entry(&wpa_s->osu_prov[i]);
|
||||
os_free(wpa_s->osu_prov);
|
||||
wpa_s->osu_prov = NULL;
|
||||
wpa_s->osu_prov_count = 0;
|
||||
}
|
||||
|
||||
|
||||
static void hs20_osu_fetch_done(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
char fname[256];
|
||||
FILE *f;
|
||||
size_t i, j;
|
||||
|
||||
wpa_s->fetch_osu_info = 0;
|
||||
wpa_s->fetch_osu_icon_in_progress = 0;
|
||||
|
||||
if (wpa_s->conf->osu_dir == NULL) {
|
||||
hs20_free_osu_prov(wpa_s);
|
||||
wpa_s->fetch_anqp_in_progress = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(fname, sizeof(fname), "%s/osu-providers.txt",
|
||||
wpa_s->conf->osu_dir);
|
||||
f = fopen(fname, "w");
|
||||
if (f == NULL) {
|
||||
hs20_free_osu_prov(wpa_s);
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < wpa_s->osu_prov_count; i++) {
|
||||
struct osu_provider *osu = &wpa_s->osu_prov[i];
|
||||
if (i > 0)
|
||||
fprintf(f, "\n");
|
||||
fprintf(f, "OSU-PROVIDER " MACSTR "\n"
|
||||
"uri=%s\n"
|
||||
"methods=%08x\n",
|
||||
MAC2STR(osu->bssid), osu->server_uri, osu->osu_methods);
|
||||
if (osu->osu_ssid_len) {
|
||||
fprintf(f, "osu_ssid=%s\n",
|
||||
wpa_ssid_txt(osu->osu_ssid,
|
||||
osu->osu_ssid_len));
|
||||
}
|
||||
if (osu->osu_nai[0])
|
||||
fprintf(f, "osu_nai=%s\n", osu->osu_nai);
|
||||
for (j = 0; j < osu->friendly_name_count; j++) {
|
||||
fprintf(f, "friendly_name=%s:%s\n",
|
||||
osu->friendly_name[j].lang,
|
||||
osu->friendly_name[j].text);
|
||||
}
|
||||
for (j = 0; j < osu->serv_desc_count; j++) {
|
||||
fprintf(f, "desc=%s:%s\n",
|
||||
osu->serv_desc[j].lang,
|
||||
osu->serv_desc[j].text);
|
||||
}
|
||||
for (j = 0; j < osu->icon_count; j++) {
|
||||
struct osu_icon *icon = &osu->icon[j];
|
||||
if (icon->failed)
|
||||
continue; /* could not fetch icon */
|
||||
fprintf(f, "icon=%u:%u:%u:%s:%s:%s\n",
|
||||
icon->id, icon->width, icon->height, icon->lang,
|
||||
icon->icon_type, icon->filename);
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
hs20_free_osu_prov(wpa_s);
|
||||
|
||||
wpa_msg(wpa_s, MSG_INFO, "OSU provider fetch completed");
|
||||
wpa_s->fetch_anqp_in_progress = 0;
|
||||
}
|
||||
|
||||
|
||||
void hs20_next_osu_icon(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
size_t i, j;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Ready to fetch next icon");
|
||||
|
||||
for (i = 0; i < wpa_s->osu_prov_count; i++) {
|
||||
struct osu_provider *osu = &wpa_s->osu_prov[i];
|
||||
for (j = 0; j < osu->icon_count; j++) {
|
||||
struct osu_icon *icon = &osu->icon[j];
|
||||
if (icon->id || icon->failed)
|
||||
continue;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Try to fetch icon '%s' "
|
||||
"from " MACSTR, icon->filename,
|
||||
MAC2STR(osu->bssid));
|
||||
if (hs20_anqp_send_req(wpa_s, osu->bssid,
|
||||
BIT(HS20_STYPE_ICON_REQUEST),
|
||||
(u8 *) icon->filename,
|
||||
os_strlen(icon->filename)) < 0) {
|
||||
icon->failed = 1;
|
||||
continue;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: No more icons to fetch");
|
||||
hs20_osu_fetch_done(wpa_s);
|
||||
}
|
||||
|
||||
|
||||
static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
|
||||
const u8 *osu_ssid, u8 osu_ssid_len,
|
||||
const u8 *pos, size_t len)
|
||||
{
|
||||
struct osu_provider *prov;
|
||||
const u8 *end = pos + len;
|
||||
u16 len2;
|
||||
const u8 *pos2;
|
||||
|
||||
wpa_hexdump(MSG_DEBUG, "HS 2.0: Parsing OSU Provider", pos, len);
|
||||
prov = os_realloc_array(wpa_s->osu_prov,
|
||||
wpa_s->osu_prov_count + 1,
|
||||
sizeof(*prov));
|
||||
if (prov == NULL)
|
||||
return;
|
||||
wpa_s->osu_prov = prov;
|
||||
prov = &prov[wpa_s->osu_prov_count];
|
||||
os_memset(prov, 0, sizeof(*prov));
|
||||
|
||||
os_memcpy(prov->bssid, bss->bssid, ETH_ALEN);
|
||||
os_memcpy(prov->osu_ssid, osu_ssid, osu_ssid_len);
|
||||
prov->osu_ssid_len = osu_ssid_len;
|
||||
|
||||
/* OSU Friendly Name Length */
|
||||
if (pos + 2 > end) {
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU "
|
||||
"Friendly Name Length");
|
||||
return;
|
||||
}
|
||||
len2 = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
if (pos + len2 > end) {
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU "
|
||||
"Friendly Name Duples");
|
||||
return;
|
||||
}
|
||||
pos2 = pos;
|
||||
pos += len2;
|
||||
|
||||
/* OSU Friendly Name Duples */
|
||||
while (pos2 + 4 <= pos && prov->friendly_name_count < OSU_MAX_ITEMS) {
|
||||
struct osu_lang_string *f;
|
||||
if (pos2 + 1 + pos2[0] > pos || pos2[0] < 3) {
|
||||
wpa_printf(MSG_DEBUG, "Invalid OSU Friendly Name");
|
||||
break;
|
||||
}
|
||||
f = &prov->friendly_name[prov->friendly_name_count++];
|
||||
os_memcpy(f->lang, pos2 + 1, 3);
|
||||
os_memcpy(f->text, pos2 + 1 + 3, pos2[0] - 3);
|
||||
pos2 += 1 + pos2[0];
|
||||
}
|
||||
|
||||
/* OSU Server URI */
|
||||
if (pos + 1 > end || pos + 1 + pos[0] > end) {
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Server "
|
||||
"URI");
|
||||
return;
|
||||
}
|
||||
os_memcpy(prov->server_uri, pos + 1, pos[0]);
|
||||
pos += 1 + pos[0];
|
||||
|
||||
/* OSU Method list */
|
||||
if (pos + 1 > end || pos + 1 + pos[0] > end) {
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Method "
|
||||
"list");
|
||||
return;
|
||||
}
|
||||
pos2 = pos + 1;
|
||||
pos += 1 + pos[0];
|
||||
while (pos2 < pos) {
|
||||
if (*pos2 < 32)
|
||||
prov->osu_methods |= BIT(*pos2);
|
||||
pos2++;
|
||||
}
|
||||
|
||||
/* Icons Available Length */
|
||||
if (pos + 2 > end) {
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for Icons "
|
||||
"Available Length");
|
||||
return;
|
||||
}
|
||||
len2 = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
if (pos + len2 > end) {
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for Icons "
|
||||
"Available");
|
||||
return;
|
||||
}
|
||||
pos2 = pos;
|
||||
pos += len2;
|
||||
|
||||
/* Icons Available */
|
||||
while (pos2 < pos) {
|
||||
struct osu_icon *icon = &prov->icon[prov->icon_count];
|
||||
if (pos2 + 2 + 2 + 3 + 1 + 1 > pos) {
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Invalid Icon Metadata");
|
||||
break;
|
||||
}
|
||||
|
||||
icon->width = WPA_GET_LE16(pos2);
|
||||
pos2 += 2;
|
||||
icon->height = WPA_GET_LE16(pos2);
|
||||
pos2 += 2;
|
||||
os_memcpy(icon->lang, pos2, 3);
|
||||
pos2 += 3;
|
||||
|
||||
if (pos2 + 1 + pos2[0] > pos) {
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon Type");
|
||||
break;
|
||||
}
|
||||
os_memcpy(icon->icon_type, pos2 + 1, pos2[0]);
|
||||
pos2 += 1 + pos2[0];
|
||||
|
||||
if (pos2 + 1 + pos2[0] > pos) {
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon "
|
||||
"Filename");
|
||||
break;
|
||||
}
|
||||
os_memcpy(icon->filename, pos2 + 1, pos2[0]);
|
||||
pos2 += 1 + pos2[0];
|
||||
|
||||
prov->icon_count++;
|
||||
}
|
||||
|
||||
/* OSU_NAI */
|
||||
if (pos + 1 > end || pos + 1 + pos[0] > end) {
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU_NAI");
|
||||
return;
|
||||
}
|
||||
os_memcpy(prov->osu_nai, pos + 1, pos[0]);
|
||||
pos += 1 + pos[0];
|
||||
|
||||
/* OSU Service Description Length */
|
||||
if (pos + 2 > end) {
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU "
|
||||
"Service Description Length");
|
||||
return;
|
||||
}
|
||||
len2 = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
if (pos + len2 > end) {
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU "
|
||||
"Service Description Duples");
|
||||
return;
|
||||
}
|
||||
pos2 = pos;
|
||||
pos += len2;
|
||||
|
||||
/* OSU Service Description Duples */
|
||||
while (pos2 + 4 <= pos && prov->serv_desc_count < OSU_MAX_ITEMS) {
|
||||
struct osu_lang_string *f;
|
||||
if (pos2 + 1 + pos2[0] > pos || pos2[0] < 3) {
|
||||
wpa_printf(MSG_DEBUG, "Invalid OSU Service "
|
||||
"Description");
|
||||
break;
|
||||
}
|
||||
f = &prov->serv_desc[prov->serv_desc_count++];
|
||||
os_memcpy(f->lang, pos2 + 1, 3);
|
||||
os_memcpy(f->text, pos2 + 1 + 3, pos2[0] - 3);
|
||||
pos2 += 1 + pos2[0];
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Added OSU Provider through " MACSTR,
|
||||
MAC2STR(bss->bssid));
|
||||
wpa_s->osu_prov_count++;
|
||||
}
|
||||
|
||||
|
||||
void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
struct wpa_bss *bss;
|
||||
struct wpabuf *prov_anqp;
|
||||
const u8 *pos, *end;
|
||||
u16 len;
|
||||
const u8 *osu_ssid;
|
||||
u8 osu_ssid_len;
|
||||
u8 num_providers;
|
||||
|
||||
hs20_free_osu_prov(wpa_s);
|
||||
|
||||
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
|
||||
if (bss->anqp == NULL)
|
||||
continue;
|
||||
prov_anqp = bss->anqp->hs20_osu_providers_list;
|
||||
if (prov_anqp == NULL)
|
||||
continue;
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Parsing OSU Providers list from "
|
||||
MACSTR, MAC2STR(bss->bssid));
|
||||
wpa_hexdump_buf(MSG_DEBUG, "HS 2.0: OSU Providers list",
|
||||
prov_anqp);
|
||||
pos = wpabuf_head(prov_anqp);
|
||||
end = pos + wpabuf_len(prov_anqp);
|
||||
|
||||
/* OSU SSID */
|
||||
if (pos + 1 > end)
|
||||
continue;
|
||||
if (pos + 1 + pos[0] > end) {
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for "
|
||||
"OSU SSID");
|
||||
continue;
|
||||
}
|
||||
osu_ssid_len = *pos++;
|
||||
if (osu_ssid_len > 32) {
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Invalid OSU SSID "
|
||||
"Length %u", osu_ssid_len);
|
||||
continue;
|
||||
}
|
||||
osu_ssid = pos;
|
||||
pos += osu_ssid_len;
|
||||
|
||||
if (pos + 1 > end) {
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for "
|
||||
"Number of OSU Providers");
|
||||
continue;
|
||||
}
|
||||
num_providers = *pos++;
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Number of OSU Providers: %u",
|
||||
num_providers);
|
||||
|
||||
/* OSU Providers */
|
||||
while (pos + 2 < end && num_providers > 0) {
|
||||
num_providers--;
|
||||
len = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
if (pos + len > end)
|
||||
break;
|
||||
hs20_osu_add_prov(wpa_s, bss, osu_ssid,
|
||||
osu_ssid_len, pos, len);
|
||||
pos += len;
|
||||
}
|
||||
|
||||
if (pos != end) {
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Ignored %d bytes of "
|
||||
"extra data after OSU Providers",
|
||||
(int) (end - pos));
|
||||
}
|
||||
}
|
||||
|
||||
wpa_s->fetch_osu_icon_in_progress = 1;
|
||||
hs20_next_osu_icon(wpa_s);
|
||||
}
|
||||
|
||||
|
||||
static void hs20_osu_scan_res_handler(struct wpa_supplicant *wpa_s,
|
||||
struct wpa_scan_results *scan_res)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "OSU provisioning fetch scan completed");
|
||||
wpa_s->network_select = 0;
|
||||
wpa_s->fetch_all_anqp = 1;
|
||||
wpa_s->fetch_osu_info = 1;
|
||||
wpa_s->fetch_osu_icon_in_progress = 0;
|
||||
|
||||
interworking_start_fetch_anqp(wpa_s);
|
||||
}
|
||||
|
||||
|
||||
int hs20_fetch_osu(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Cannot start fetch_osu - "
|
||||
"interface disabled");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wpa_s->scanning) {
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Cannot start fetch_osu - "
|
||||
"scanning");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wpa_s->conf->osu_dir == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Cannot start fetch_osu - "
|
||||
"osu_dir not configured");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wpa_s->fetch_anqp_in_progress || wpa_s->network_select) {
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Cannot start fetch_osu - "
|
||||
"fetch in progress (%d, %d)",
|
||||
wpa_s->fetch_anqp_in_progress,
|
||||
wpa_s->network_select);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_msg(wpa_s, MSG_INFO, "Starting OSU provisioning information fetch");
|
||||
wpa_s->scan_req = MANUAL_SCAN_REQ;
|
||||
wpa_s->scan_res_handler = hs20_osu_scan_res_handler;
|
||||
wpa_supplicant_req_scan(wpa_s, 0, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void hs20_cancel_fetch_osu(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "Cancel OSU fetch");
|
||||
interworking_stop_fetch_anqp(wpa_s);
|
||||
wpa_s->network_select = 0;
|
||||
wpa_s->fetch_osu_info = 0;
|
||||
wpa_s->fetch_osu_icon_in_progress = 0;
|
||||
}
|
||||
|
||||
|
||||
void hs20_icon_fetch_failed(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
hs20_osu_icon_fetch_result(wpa_s, -1);
|
||||
eloop_cancel_timeout(hs20_continue_icon_fetch, wpa_s, NULL);
|
||||
eloop_register_timeout(0, 0, hs20_continue_icon_fetch, wpa_s, NULL);
|
||||
}
|
||||
|
||||
|
||||
void hs20_rx_subscription_remediation(struct wpa_supplicant *wpa_s,
|
||||
const char *url, u8 osu_method)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
|
@ -19,10 +19,18 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
|
|||
int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
|
||||
struct wpa_bss *bss);
|
||||
int hs20_get_pps_mo_id(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
|
||||
void hs20_notify_parse_done(struct wpa_supplicant *wpa_s);
|
||||
|
||||
void hs20_rx_subscription_remediation(struct wpa_supplicant *wpa_s,
|
||||
const char *url, u8 osu_method);
|
||||
void hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s, u8 code,
|
||||
u16 reauth_delay, const char *url);
|
||||
|
||||
void hs20_free_osu_prov(struct wpa_supplicant *wpa_s);
|
||||
void hs20_next_osu_icon(struct wpa_supplicant *wpa_s);
|
||||
void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s);
|
||||
int hs20_fetch_osu(struct wpa_supplicant *wpa_s);
|
||||
void hs20_cancel_fetch_osu(struct wpa_supplicant *wpa_s);
|
||||
void hs20_icon_fetch_failed(struct wpa_supplicant *wpa_s);
|
||||
|
||||
#endif /* HS20_SUPPLICANT_H */
|
||||
|
|
|
@ -102,6 +102,9 @@ static void interworking_anqp_resp_cb(void *ctx, const u8 *dst,
|
|||
{
|
||||
struct wpa_supplicant *wpa_s = ctx;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Response callback dst=" MACSTR
|
||||
" dialog_token=%u result=%d status_code=%u",
|
||||
MAC2STR(dst), dialog_token, result, status_code);
|
||||
anqp_resp_cb(wpa_s, dst, dialog_token, result, adv_proto, resp,
|
||||
status_code);
|
||||
interworking_next_anqp_fetch(wpa_s);
|
||||
|
@ -1970,8 +1973,21 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
|
|||
int found = 0;
|
||||
const u8 *ie;
|
||||
|
||||
if (eloop_terminated() || !wpa_s->fetch_anqp_in_progress)
|
||||
wpa_printf(MSG_DEBUG, "Interworking: next_anqp_fetch - "
|
||||
"fetch_anqp_in_progress=%d fetch_osu_icon_in_progress=%d",
|
||||
wpa_s->fetch_anqp_in_progress,
|
||||
wpa_s->fetch_osu_icon_in_progress);
|
||||
|
||||
if (eloop_terminated() || !wpa_s->fetch_anqp_in_progress) {
|
||||
wpa_printf(MSG_DEBUG, "Interworking: Stop next-ANQP-fetch");
|
||||
return;
|
||||
}
|
||||
|
||||
if (wpa_s->fetch_osu_icon_in_progress) {
|
||||
wpa_printf(MSG_DEBUG, "Interworking: Next icon (in progress)");
|
||||
hs20_next_osu_icon(wpa_s);
|
||||
return;
|
||||
}
|
||||
|
||||
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
|
||||
if (!(bss->caps & IEEE80211_CAP_ESS))
|
||||
|
@ -2005,6 +2021,11 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
|
|||
}
|
||||
|
||||
if (found == 0) {
|
||||
if (wpa_s->fetch_osu_info) {
|
||||
wpa_printf(MSG_DEBUG, "Interworking: Next icon");
|
||||
hs20_osu_icon_fetch(wpa_s);
|
||||
return;
|
||||
}
|
||||
wpa_msg(wpa_s, MSG_INFO, "ANQP fetch completed");
|
||||
wpa_s->fetch_anqp_in_progress = 0;
|
||||
if (wpa_s->network_select)
|
||||
|
@ -2032,6 +2053,7 @@ int interworking_fetch_anqp(struct wpa_supplicant *wpa_s)
|
|||
|
||||
wpa_s->network_select = 0;
|
||||
wpa_s->fetch_all_anqp = 1;
|
||||
wpa_s->fetch_osu_info = 0;
|
||||
|
||||
interworking_start_fetch_anqp(wpa_s);
|
||||
|
||||
|
@ -2229,14 +2251,22 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
|
|||
u16 slen;
|
||||
struct wpa_bss *bss = NULL, *tmp;
|
||||
|
||||
if (result != GAS_QUERY_SUCCESS)
|
||||
wpa_printf(MSG_DEBUG, "Interworking: anqp_resp_cb dst=" MACSTR
|
||||
" dialog_token=%u result=%d status_code=%u",
|
||||
MAC2STR(dst), dialog_token, result, status_code);
|
||||
if (result != GAS_QUERY_SUCCESS) {
|
||||
if (wpa_s->fetch_osu_icon_in_progress)
|
||||
hs20_icon_fetch_failed(wpa_s);
|
||||
return;
|
||||
}
|
||||
|
||||
pos = wpabuf_head(adv_proto);
|
||||
if (wpabuf_len(adv_proto) < 4 || pos[0] != WLAN_EID_ADV_PROTO ||
|
||||
pos[1] < 2 || pos[3] != ACCESS_NETWORK_QUERY_PROTOCOL) {
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Unexpected Advertisement "
|
||||
"Protocol in response");
|
||||
if (wpa_s->fetch_osu_icon_in_progress)
|
||||
hs20_icon_fetch_failed(wpa_s);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2276,6 +2306,8 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
|
|||
slen);
|
||||
pos += slen;
|
||||
}
|
||||
|
||||
hs20_notify_parse_done(wpa_s);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2296,6 +2328,7 @@ int interworking_select(struct wpa_supplicant *wpa_s, int auto_select,
|
|||
wpa_s->auto_network_select = 0;
|
||||
wpa_s->auto_select = !!auto_select;
|
||||
wpa_s->fetch_all_anqp = 0;
|
||||
wpa_s->fetch_osu_info = 0;
|
||||
wpa_printf(MSG_DEBUG, "Interworking: Start scan for network "
|
||||
"selection");
|
||||
wpa_s->scan_res_handler = interworking_scan_res_handler;
|
||||
|
|
|
@ -2316,6 +2316,19 @@ static int wpa_cli_cmd_hs20_icon_request(struct wpa_ctrl *ctrl, int argc,
|
|||
return wpa_ctrl_command(ctrl, cmd);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_cli_cmd_fetch_osu(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
return wpa_ctrl_command(ctrl, "FETCH_OSU");
|
||||
}
|
||||
|
||||
|
||||
static int wpa_cli_cmd_cancel_fetch_osu(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return wpa_ctrl_command(ctrl, "CANCEL_FETCH_OSU");
|
||||
}
|
||||
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
|
||||
|
@ -2852,6 +2865,11 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
|
|||
{ "hs20_icon_request", wpa_cli_cmd_hs20_icon_request,
|
||||
wpa_cli_complete_bss, cli_cmd_flag_none,
|
||||
"<addr> <icon name> = get Hotspot 2.0 OSU icon" },
|
||||
{ "fetch_osu", wpa_cli_cmd_fetch_osu, NULL, cli_cmd_flag_none,
|
||||
"= fetch OSU provider information from all APs" },
|
||||
{ "cancel_fetch_osu", wpa_cli_cmd_cancel_fetch_osu, NULL,
|
||||
cli_cmd_flag_none,
|
||||
"= cancel fetch_osu command" },
|
||||
#endif /* CONFIG_HS20 */
|
||||
{ "sta_autoconnect", wpa_cli_cmd_sta_autoconnect, NULL,
|
||||
cli_cmd_flag_none,
|
||||
|
|
|
@ -483,6 +483,10 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
|
|||
|
||||
os_free(wpa_s->last_scan_res);
|
||||
wpa_s->last_scan_res = NULL;
|
||||
|
||||
#ifdef CONFIG_HS20
|
||||
hs20_free_osu_prov(wpa_s);
|
||||
#endif /* CONFIG_HS20 */
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -771,7 +771,12 @@ struct wpa_supplicant {
|
|||
unsigned int auto_select:1;
|
||||
unsigned int auto_network_select:1;
|
||||
unsigned int fetch_all_anqp:1;
|
||||
unsigned int fetch_osu_info:1;
|
||||
unsigned int fetch_osu_icon_in_progress:1;
|
||||
struct wpa_bss *interworking_gas_bss;
|
||||
unsigned int osu_icon_id;
|
||||
struct osu_provider *osu_prov;
|
||||
size_t osu_prov_count;
|
||||
#endif /* CONFIG_INTERWORKING */
|
||||
unsigned int drv_capa_known;
|
||||
|
||||
|
|
Loading…
Reference in a new issue