]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
HS 2.0R2 AP: Add OSU Providers list ANQP element
authorJouni Malinen <jouni@qca.qualcomm.com>
Sun, 17 Mar 2013 14:34:09 +0000 (16:34 +0200)
committerJouni Malinen <j@w1.fi>
Tue, 25 Feb 2014 23:24:25 +0000 (01:24 +0200)
hostapd can now be configured to advertise OSU Providers with the
new osu_* confgiuration parameters.

Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>

hostapd/config_file.c
hostapd/hostapd.conf
src/ap/ap_config.c
src/ap/ap_config.h
src/ap/gas_serv.c
src/ap/gas_serv.h

index 6b1105b7c73a47f907e2a7ff263d5353acc2323d..ca95747a5897f3205f2cd6d48fb6d398fb037f61 100644 (file)
@@ -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)                                   \
index c07913a8bfee770763e1690b17cf8ab3ac3a338b..c745fe83be62f7ea966248847b9c1c7d1dc7475c 100644 (file)
@@ -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
index c48f56743196474c2b21adc04aa6c71d0ff62cdc..07fd8c34c5978139831132fca4aa3ca024d26411 100644 (file)
@@ -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);
index 8d0aae5ee58b985539915e4b77198268cca97742..7a40b3e90fbdfe431531eb1ec079b8e379977cf1 100644 (file)
@@ -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 */
 
index 835d0a8b99c4abb622523fc5375f1eb521f8fe38..fd1041eac11392d81b7753a928628b224a74420d 100644 (file)
@@ -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);
index ff32dc93634e3c92c74e76a2a6064ca8545e9885..7e392b36a5448fc6661bfc33f60fecf474cedd81 100644 (file)
@@ -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)