From 7515adb2b1ac4dbca98cd78d834c9e9ef7d9e4a6 Mon Sep 17 00:00:00 2001 From: Jay Katabathuni Date: Mon, 30 Jul 2012 22:07:35 +0300 Subject: [PATCH] Interworking: Add advertising of 3GPP Cellular Network info The anqp_3gpp_cell_net parameter can be used to configure hostapd to advertise 3GPP Cellular Network ANQP information. Signed-hostap: Jouni Malinen --- hostapd/config_file.c | 79 +++++++++++++++++++++++++++++++++++++++++++ hostapd/hostapd.conf | 4 +++ src/ap/ap_config.c | 1 + src/ap/ap_config.h | 4 +++ src/ap/gas_serv.c | 23 +++++++++++++ src/ap/gas_serv.h | 2 ++ 6 files changed, 113 insertions(+) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index c2804b905..fceb33f25 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -1329,6 +1329,82 @@ fail: line, pos); return -1; } + + +static int parse_3gpp_cell_net(struct hostapd_bss_config *bss, char *buf, + int line) +{ + size_t count; + char *pos; + u8 *info = NULL, *ipos; + + /* format: [;][;...] */ + + count = 1; + for (pos = buf; *pos; pos++) { + if ((*pos < '0' && *pos > '9') && *pos != ';' && *pos != ',') + goto fail; + if (*pos == ';') + count++; + } + if (1 + count * 3 > 0x7f) + goto fail; + + info = os_zalloc(2 + 3 + count * 3); + if (info == NULL) + return -1; + + ipos = info; + *ipos++ = 0; /* GUD - Version 1 */ + *ipos++ = 3 + count * 3; /* User Data Header Length (UDHL) */ + *ipos++ = 0; /* PLMN List IEI */ + /* ext(b8) | Length of PLMN List value contents(b7..1) */ + *ipos++ = 1 + count * 3; + *ipos++ = count; /* Number of PLMNs */ + + pos = buf; + while (pos && *pos) { + char *mcc, *mnc; + size_t mnc_len; + + mcc = pos; + mnc = os_strchr(pos, ','); + if (mnc == NULL) + goto fail; + *mnc++ = '\0'; + pos = os_strchr(mnc, ';'); + if (pos) + *pos++ = '\0'; + + mnc_len = os_strlen(mnc); + if (os_strlen(mcc) != 3 || (mnc_len != 2 && mnc_len != 3)) + goto fail; + + /* BC coded MCC,MNC */ + /* MCC digit 2 | MCC digit 1 */ + *ipos++ = ((mcc[1] - '0') << 4) | (mcc[0] - '0'); + /* MNC digit 3 | MCC digit 3 */ + *ipos++ = (((mnc_len == 2) ? 0xf0 : ((mnc[2] - '0') << 4))) | + (mcc[2] - '0'); + /* MNC digit 2 | MNC digit 1 */ + *ipos++ = ((mnc[1] - '0') << 4) | (mnc[0] - '0'); + } + + os_free(bss->anqp_3gpp_cell_net); + bss->anqp_3gpp_cell_net = info; + bss->anqp_3gpp_cell_net_len = 2 + 3 + 3 * count; + wpa_hexdump(MSG_MSGDUMP, "3GPP Cellular Network information", + bss->anqp_3gpp_cell_net, bss->anqp_3gpp_cell_net_len); + + return 0; + +fail: + wpa_printf(MSG_ERROR, "Line %d: Invalid anqp_3gpp_cell_net: %s", + line, buf); + os_free(info); + return -1; +} + #endif /* CONFIG_INTERWORKING */ @@ -2479,6 +2555,9 @@ static int hostapd_config_fill(struct hostapd_config *conf, os_free(bss->domain_name); bss->domain_name = domain_list; bss->domain_name_len = domain_list_len; + } else if (os_strcmp(buf, "anqp_3gpp_cell_net") == 0) { + if (parse_3gpp_cell_net(bss, pos, line) < 0) + errors++; } else if (os_strcmp(buf, "gas_frag_limit") == 0) { bss->gas_frag_limit = atoi(pos); } else if (os_strcmp(buf, "gas_comeback_delay") == 0) { diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index 1740b49fa..f02c3cd8a 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -1384,6 +1384,10 @@ own_ip_addr=127.0.0.1 # format: [,] #domain_name=example.com,another.example.com,yet-another.example.com +# 3GPP Cellular Network information +# format: [;][;...] +#anqp_3gpp_cell_net=244,91;310,026;234,56 + ##### Hotspot 2.0 ############################################################# # Enable Hotspot 2.0 support diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index 4fa111400..c804ec586 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -499,6 +499,7 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf) os_free(conf->roaming_consortium); os_free(conf->venue_name); os_free(conf->network_auth_type); + os_free(conf->anqp_3gpp_cell_net); os_free(conf->domain_name); #ifdef CONFIG_RADIUS_TEST diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 6a8174dd9..80f65c54d 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -396,6 +396,10 @@ struct hostapd_bss_config { u8 ipaddr_type_availability; u8 ipaddr_type_configured; + /* IEEE 802.11u - 3GPP Cellular Network */ + u8 *anqp_3gpp_cell_net; + size_t anqp_3gpp_cell_net_len; + /* IEEE 802.11u - Domain Name */ u8 *domain_name; size_t domain_name_len; diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c index 249cf46f3..dfbed39ac 100644 --- a/src/ap/gas_serv.c +++ b/src/ap/gas_serv.c @@ -158,6 +158,8 @@ static void anqp_add_capab_list(struct hostapd_data *hapd, wpabuf_put_le16(buf, ANQP_ROAMING_CONSORTIUM); if (hapd->conf->ipaddr_type_configured) wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY); + if (hapd->conf->anqp_3gpp_cell_net) + wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK); if (hapd->conf->domain_name) wpabuf_put_le16(buf, ANQP_DOMAIN_NAME); anqp_add_hs_capab_list(hapd, buf); @@ -225,6 +227,19 @@ static void anqp_add_ip_addr_type_availability(struct hostapd_data *hapd, } +static void anqp_add_3gpp_cellular_network(struct hostapd_data *hapd, + struct wpabuf *buf) +{ + if (hapd->conf->anqp_3gpp_cell_net) { + wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK); + wpabuf_put_le16(buf, + hapd->conf->anqp_3gpp_cell_net_len); + wpabuf_put_data(buf, hapd->conf->anqp_3gpp_cell_net, + hapd->conf->anqp_3gpp_cell_net_len); + } +} + + static void anqp_add_domain_name(struct hostapd_data *hapd, struct wpabuf *buf) { if (hapd->conf->domain_name) { @@ -257,6 +272,8 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd, anqp_add_roaming_consortium(hapd, buf); if (request & ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY) anqp_add_ip_addr_type_availability(hapd, buf); + if (request & ANQP_REQ_3GPP_CELLULAR_NETWORK) + anqp_add_3gpp_cellular_network(hapd, buf); if (request & ANQP_REQ_DOMAIN_NAME) anqp_add_domain_name(hapd, buf); @@ -332,6 +349,12 @@ static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id, hapd->conf->ipaddr_type_configured, 0, 0, qi); break; + case ANQP_3GPP_CELLULAR_NETWORK: + set_anqp_req(ANQP_REQ_3GPP_CELLULAR_NETWORK, + "3GPP Cellular Network", + hapd->conf->anqp_3gpp_cell_net != NULL, + 0, 0, qi); + break; case ANQP_DOMAIN_NAME: set_anqp_req(ANQP_REQ_DOMAIN_NAME, "Domain Name", hapd->conf->domain_name != NULL, diff --git a/src/ap/gas_serv.h b/src/ap/gas_serv.h index ef71c2d75..dc4bf05bd 100644 --- a/src/ap/gas_serv.h +++ b/src/ap/gas_serv.h @@ -19,6 +19,8 @@ (1 << (ANQP_ROAMING_CONSORTIUM - ANQP_QUERY_LIST)) #define ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY \ (1 << (ANQP_IP_ADDR_TYPE_AVAILABILITY - ANQP_QUERY_LIST)) +#define ANQP_REQ_3GPP_CELLULAR_NETWORK \ + (1 << (ANQP_3GPP_CELLULAR_NETWORK - ANQP_QUERY_LIST)) #define ANQP_REQ_DOMAIN_NAME \ (1 << (ANQP_DOMAIN_NAME - ANQP_QUERY_LIST)) #define ANQP_REQ_HS_CAPABILITY_LIST \