HS 2.0R2 AP: Add OSU Providers list ANQP element
hostapd can now be configured to advertise OSU Providers with the new osu_* confgiuration parameters. Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
f7bd7a01a8
commit
ae6d15c722
6 changed files with 327 additions and 1 deletions
|
@ -1630,6 +1630,142 @@ static int hs20_parse_icon(struct hostapd_bss_config *bss, char *pos)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hs20_parse_osu_ssid(struct hostapd_bss_config *bss,
|
||||
char *pos, int line)
|
||||
{
|
||||
size_t slen;
|
||||
char *str;
|
||||
|
||||
str = wpa_config_parse_string(pos, &slen);
|
||||
if (str == NULL || slen < 1 || slen > HOSTAPD_MAX_SSID_LEN) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: Invalid SSID '%s'", line, pos);
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memcpy(bss->osu_ssid, str, slen);
|
||||
bss->osu_ssid_len = slen;
|
||||
os_free(str);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hs20_parse_osu_server_uri(struct hostapd_bss_config *bss,
|
||||
char *pos, int line)
|
||||
{
|
||||
struct hs20_osu_provider *p;
|
||||
|
||||
p = os_realloc_array(bss->hs20_osu_providers,
|
||||
bss->hs20_osu_providers_count + 1, sizeof(*p));
|
||||
if (p == NULL)
|
||||
return -1;
|
||||
|
||||
bss->hs20_osu_providers = p;
|
||||
bss->last_osu = &bss->hs20_osu_providers[bss->hs20_osu_providers_count];
|
||||
bss->hs20_osu_providers_count++;
|
||||
os_memset(bss->last_osu, 0, sizeof(*p));
|
||||
bss->last_osu->server_uri = os_strdup(pos);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hs20_parse_osu_friendly_name(struct hostapd_bss_config *bss,
|
||||
char *pos, int line)
|
||||
{
|
||||
if (bss->last_osu == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: Unexpected OSU field", line);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (parse_lang_string(&bss->last_osu->friendly_name,
|
||||
&bss->last_osu->friendly_name_count, pos)) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: Invalid osu_friendly_name '%s'",
|
||||
line, pos);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hs20_parse_osu_nai(struct hostapd_bss_config *bss,
|
||||
char *pos, int line)
|
||||
{
|
||||
if (bss->last_osu == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: Unexpected OSU field", line);
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_free(bss->last_osu->osu_nai);
|
||||
bss->last_osu->osu_nai = os_strdup(pos);
|
||||
if (bss->last_osu->osu_nai == NULL)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hs20_parse_osu_method_list(struct hostapd_bss_config *bss, char *pos,
|
||||
int line)
|
||||
{
|
||||
if (bss->last_osu == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: Unexpected OSU field", line);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hostapd_parse_intlist(&bss->last_osu->method_list, pos)) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: Invalid osu_method_list", line);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hs20_parse_osu_icon(struct hostapd_bss_config *bss, char *pos,
|
||||
int line)
|
||||
{
|
||||
char **n;
|
||||
struct hs20_osu_provider *p = bss->last_osu;
|
||||
|
||||
if (p == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: Unexpected OSU field", line);
|
||||
return -1;
|
||||
}
|
||||
|
||||
n = os_realloc_array(p->icons, p->icons_count + 1, sizeof(char *));
|
||||
if (n == NULL)
|
||||
return -1;
|
||||
p->icons = n;
|
||||
p->icons[p->icons_count] = os_strdup(pos);
|
||||
if (p->icons[p->icons_count] == NULL)
|
||||
return -1;
|
||||
p->icons_count++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hs20_parse_osu_service_desc(struct hostapd_bss_config *bss,
|
||||
char *pos, int line)
|
||||
{
|
||||
if (bss->last_osu == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: Unexpected OSU field", line);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (parse_lang_string(&bss->last_osu->service_desc,
|
||||
&bss->last_osu->service_desc_count, pos)) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: Invalid osu_service_desc '%s'",
|
||||
line, pos);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
|
||||
|
@ -2918,6 +3054,27 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
|||
errors++;
|
||||
return errors;
|
||||
}
|
||||
} else if (os_strcmp(buf, "osu_ssid") == 0) {
|
||||
if (hs20_parse_osu_ssid(bss, pos, line) < 0)
|
||||
errors++;
|
||||
} else if (os_strcmp(buf, "osu_server_uri") == 0) {
|
||||
if (hs20_parse_osu_server_uri(bss, pos, line) < 0)
|
||||
errors++;
|
||||
} else if (os_strcmp(buf, "osu_friendly_name") == 0) {
|
||||
if (hs20_parse_osu_friendly_name(bss, pos, line) < 0)
|
||||
errors++;
|
||||
} else if (os_strcmp(buf, "osu_nai") == 0) {
|
||||
if (hs20_parse_osu_nai(bss, pos, line) < 0)
|
||||
errors++;
|
||||
} else if (os_strcmp(buf, "osu_method_list") == 0) {
|
||||
if (hs20_parse_osu_method_list(bss, pos, line) < 0)
|
||||
errors++;
|
||||
} else if (os_strcmp(buf, "osu_icon") == 0) {
|
||||
if (hs20_parse_osu_icon(bss, pos, line) < 0)
|
||||
errors++;
|
||||
} else if (os_strcmp(buf, "osu_service_desc") == 0) {
|
||||
if (hs20_parse_osu_service_desc(bss, pos, line) < 0)
|
||||
errors++;
|
||||
#endif /* CONFIG_HS20 */
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
#define PARSE_TEST_PROBABILITY(_val) \
|
||||
|
|
|
@ -1645,6 +1645,27 @@ own_ip_addr=127.0.0.1
|
|||
#hs20_icon=32:32:eng:image/png:icon32:/tmp/icon32.png
|
||||
#hs20_icon=64:64:eng:image/png:icon64:/tmp/icon64.png
|
||||
|
||||
# OSU SSID (see ssid2 for format description)
|
||||
# This is the SSID used for all OSU connections to all the listed OSU Providers.
|
||||
#osu_ssid="example"
|
||||
|
||||
# OSU Providers
|
||||
# One or more sets of following parameter. Each OSU provider is started by the
|
||||
# mandatory osu_server_uri item. The other parameters add information for the
|
||||
# last added OSU provider.
|
||||
#
|
||||
#osu_server_uri=https://example.com/osu/
|
||||
#osu_friendly_name=eng:Example operator
|
||||
#osu_friendly_name=fin:Esimerkkipalveluntarjoaja
|
||||
#osu_nai=anonymous@example.com
|
||||
#osu_method_list=1 0
|
||||
#osu_icon=icon32
|
||||
#osu_icon=icon64
|
||||
#osu_service_desc=eng:Example services
|
||||
#osu_service_desc=fin:Esimerkkipalveluja
|
||||
#
|
||||
#osu_server_uri=...
|
||||
|
||||
##### TESTING OPTIONS #########################################################
|
||||
#
|
||||
# The options in this section are only available when the build configuration
|
||||
|
|
|
@ -529,6 +529,23 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
|||
os_free(conf->hs20_connection_capability);
|
||||
os_free(conf->hs20_operating_class);
|
||||
os_free(conf->hs20_icons);
|
||||
if (conf->hs20_osu_providers) {
|
||||
size_t i;
|
||||
for (i = 0; i < conf->hs20_osu_providers_count; i++) {
|
||||
struct hs20_osu_provider *p;
|
||||
size_t j;
|
||||
p = &conf->hs20_osu_providers[i];
|
||||
os_free(p->friendly_name);
|
||||
os_free(p->server_uri);
|
||||
os_free(p->method_list);
|
||||
for (j = 0; j < p->icons_count; j++)
|
||||
os_free(p->icons[j]);
|
||||
os_free(p->icons);
|
||||
os_free(p->osu_nai);
|
||||
os_free(p->service_desc);
|
||||
}
|
||||
os_free(conf->hs20_osu_providers);
|
||||
}
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
wpabuf_free(conf->vendor_elements);
|
||||
|
|
|
@ -474,6 +474,20 @@ struct hostapd_bss_config {
|
|||
char file[256];
|
||||
} *hs20_icons;
|
||||
size_t hs20_icons_count;
|
||||
u8 osu_ssid[HOSTAPD_MAX_SSID_LEN];
|
||||
size_t osu_ssid_len;
|
||||
struct hs20_osu_provider {
|
||||
unsigned int friendly_name_count;
|
||||
struct hostapd_lang_string *friendly_name;
|
||||
char *server_uri;
|
||||
int *method_list;
|
||||
char **icons;
|
||||
size_t icons_count;
|
||||
char *osu_nai;
|
||||
unsigned int service_desc_count;
|
||||
struct hostapd_lang_string *service_desc;
|
||||
} *hs20_osu_providers, *last_osu;
|
||||
size_t hs20_osu_providers_count;
|
||||
unsigned int hs20_deauth_req_timeout;
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
|
|
|
@ -159,6 +159,8 @@ static void anqp_add_hs_capab_list(struct hostapd_data *hapd,
|
|||
wpabuf_put_u8(buf, HS20_STYPE_NAI_HOME_REALM_QUERY);
|
||||
if (hapd->conf->hs20_operating_class)
|
||||
wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS);
|
||||
if (hapd->conf->hs20_osu_providers_count)
|
||||
wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_LIST);
|
||||
if (hapd->conf->hs20_icons_count)
|
||||
wpabuf_put_u8(buf, HS20_STYPE_ICON_REQUEST);
|
||||
gas_anqp_set_element_len(buf, len);
|
||||
|
@ -517,6 +519,113 @@ static void anqp_add_operating_class(struct hostapd_data *hapd,
|
|||
}
|
||||
|
||||
|
||||
static void anqp_add_osu_provider(struct wpabuf *buf,
|
||||
struct hostapd_bss_config *bss,
|
||||
struct hs20_osu_provider *p)
|
||||
{
|
||||
u8 *len, *len2, *count;
|
||||
unsigned int i;
|
||||
|
||||
len = wpabuf_put(buf, 2); /* OSU Provider Length to be filled */
|
||||
|
||||
/* OSU Friendly Name Duples */
|
||||
len2 = wpabuf_put(buf, 2);
|
||||
for (i = 0; i < p->friendly_name_count; i++) {
|
||||
struct hostapd_lang_string *s = &p->friendly_name[i];
|
||||
wpabuf_put_u8(buf, 3 + s->name_len);
|
||||
wpabuf_put_data(buf, s->lang, 3);
|
||||
wpabuf_put_data(buf, s->name, s->name_len);
|
||||
}
|
||||
WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2);
|
||||
|
||||
/* OSU Server URI */
|
||||
if (p->server_uri) {
|
||||
wpabuf_put_u8(buf, os_strlen(p->server_uri));
|
||||
wpabuf_put_str(buf, p->server_uri);
|
||||
} else
|
||||
wpabuf_put_u8(buf, 0);
|
||||
|
||||
/* OSU Method List */
|
||||
count = wpabuf_put(buf, 1);
|
||||
for (i = 0; p->method_list[i] >= 0; i++)
|
||||
wpabuf_put_u8(buf, p->method_list[i]);
|
||||
*count = i;
|
||||
|
||||
/* Icons Available */
|
||||
len2 = wpabuf_put(buf, 2);
|
||||
for (i = 0; i < p->icons_count; i++) {
|
||||
size_t j;
|
||||
struct hs20_icon *icon = NULL;
|
||||
|
||||
for (j = 0; j < bss->hs20_icons_count && !icon; j++) {
|
||||
if (os_strcmp(p->icons[i], bss->hs20_icons[j].name) ==
|
||||
0)
|
||||
icon = &bss->hs20_icons[j];
|
||||
}
|
||||
if (!icon)
|
||||
continue; /* icon info not found */
|
||||
|
||||
wpabuf_put_le16(buf, icon->width);
|
||||
wpabuf_put_le16(buf, icon->height);
|
||||
wpabuf_put_data(buf, icon->language, 3);
|
||||
wpabuf_put_u8(buf, os_strlen(icon->type));
|
||||
wpabuf_put_str(buf, icon->type);
|
||||
wpabuf_put_u8(buf, os_strlen(icon->name));
|
||||
wpabuf_put_str(buf, icon->name);
|
||||
}
|
||||
WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2);
|
||||
|
||||
/* OSU_NAI */
|
||||
if (p->osu_nai) {
|
||||
wpabuf_put_u8(buf, os_strlen(p->osu_nai));
|
||||
wpabuf_put_str(buf, p->osu_nai);
|
||||
} else
|
||||
wpabuf_put_u8(buf, 0);
|
||||
|
||||
/* OSU Service Description Duples */
|
||||
len2 = wpabuf_put(buf, 2);
|
||||
for (i = 0; i < p->service_desc_count; i++) {
|
||||
struct hostapd_lang_string *s = &p->service_desc[i];
|
||||
wpabuf_put_u8(buf, 3 + s->name_len);
|
||||
wpabuf_put_data(buf, s->lang, 3);
|
||||
wpabuf_put_data(buf, s->name, s->name_len);
|
||||
}
|
||||
WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2);
|
||||
|
||||
WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
|
||||
}
|
||||
|
||||
|
||||
static void anqp_add_osu_providers_list(struct hostapd_data *hapd,
|
||||
struct wpabuf *buf)
|
||||
{
|
||||
if (hapd->conf->hs20_osu_providers_count) {
|
||||
size_t i;
|
||||
u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
|
||||
wpabuf_put_be24(buf, OUI_WFA);
|
||||
wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
|
||||
wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_LIST);
|
||||
wpabuf_put_u8(buf, 0); /* Reserved */
|
||||
|
||||
/* OSU SSID */
|
||||
wpabuf_put_u8(buf, hapd->conf->osu_ssid_len);
|
||||
wpabuf_put_data(buf, hapd->conf->osu_ssid,
|
||||
hapd->conf->osu_ssid_len);
|
||||
|
||||
/* Number of OSU Providers */
|
||||
wpabuf_put_u8(buf, hapd->conf->hs20_osu_providers_count);
|
||||
|
||||
for (i = 0; i < hapd->conf->hs20_osu_providers_count; i++) {
|
||||
anqp_add_osu_provider(
|
||||
buf, hapd->conf,
|
||||
&hapd->conf->hs20_osu_providers[i]);
|
||||
}
|
||||
|
||||
gas_anqp_set_element_len(buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void anqp_add_icon_binary_file(struct hostapd_data *hapd,
|
||||
struct wpabuf *buf,
|
||||
const u8 *name, size_t name_len)
|
||||
|
@ -625,6 +734,8 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
|
|||
anqp_add_connection_capability(hapd, buf);
|
||||
if (request & ANQP_REQ_OPERATING_CLASS)
|
||||
anqp_add_operating_class(hapd, buf);
|
||||
if (request & ANQP_REQ_OSU_PROVIDERS_LIST)
|
||||
anqp_add_osu_providers_list(hapd, buf);
|
||||
if (request & ANQP_REQ_ICON_REQUEST)
|
||||
anqp_add_icon_binary_file(hapd, buf, icon_name, icon_name_len);
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
@ -770,6 +881,10 @@ static void rx_anqp_hs_query_list(struct hostapd_data *hapd, u8 subtype,
|
|||
hapd->conf->hs20_operating_class != NULL,
|
||||
0, 0, qi);
|
||||
break;
|
||||
case HS20_STYPE_OSU_PROVIDERS_LIST:
|
||||
set_anqp_req(ANQP_REQ_OSU_PROVIDERS_LIST, "OSU Providers list",
|
||||
hapd->conf->hs20_osu_providers_count, 0, 0, qi);
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 subtype %u",
|
||||
subtype);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Generic advertisement service (GAS) server
|
||||
* 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.
|
||||
|
@ -37,6 +37,8 @@
|
|||
(0x10000 << HS20_STYPE_NAI_HOME_REALM_QUERY)
|
||||
#define ANQP_REQ_OPERATING_CLASS \
|
||||
(0x10000 << HS20_STYPE_OPERATING_CLASS)
|
||||
#define ANQP_REQ_OSU_PROVIDERS_LIST \
|
||||
(0x10000 << HS20_STYPE_OSU_PROVIDERS_LIST)
|
||||
#define ANQP_REQ_ICON_REQUEST \
|
||||
(0x10000 << HS20_STYPE_ICON_REQUEST)
|
||||
|
||||
|
|
Loading…
Reference in a new issue