HS 2.0: Add NAI Home Realm query

Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
Jay Katabathuni 2012-08-25 16:28:29 +03:00 committed by Jouni Malinen
parent 8047b18691
commit 43f51e2aa0
2 changed files with 155 additions and 10 deletions

View file

@ -145,6 +145,8 @@ static void anqp_add_hs_capab_list(struct hostapd_data *hapd,
wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS); wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS);
if (hapd->conf->hs20_connection_capability) if (hapd->conf->hs20_connection_capability)
wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY); wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY);
if (hapd->conf->nai_realm_data)
wpabuf_put_u8(buf, HS20_STYPE_NAI_HOME_REALM_QUERY);
if (hapd->conf->hs20_operating_class) if (hapd->conf->hs20_operating_class)
wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS); wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS);
gas_anqp_set_element_len(buf, len); gas_anqp_set_element_len(buf, len);
@ -258,9 +260,122 @@ static void anqp_add_nai_realm_eap(struct wpabuf *buf,
} }
static void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf) static void anqp_add_nai_realm_data(struct wpabuf *buf,
struct hostapd_nai_realm_data *realm,
unsigned int realm_idx)
{ {
if (hapd->conf->nai_realm_data) { u8 *realm_data_len;
wpa_printf(MSG_DEBUG, "realm=%s, len=%d", realm->realm[realm_idx],
(int) os_strlen(realm->realm[realm_idx]));
realm_data_len = wpabuf_put(buf, 2);
wpabuf_put_u8(buf, realm->encoding);
wpabuf_put_u8(buf, os_strlen(realm->realm[realm_idx]));
wpabuf_put_str(buf, realm->realm[realm_idx]);
anqp_add_nai_realm_eap(buf, realm);
gas_anqp_set_element_len(buf, realm_data_len);
}
static int hs20_add_nai_home_realm_matches(struct hostapd_data *hapd,
struct wpabuf *buf,
const u8 *home_realm,
size_t home_realm_len)
{
unsigned int i, j, k;
u8 num_realms, num_matching = 0, encoding, realm_len, *realm_list_len;
struct hostapd_nai_realm_data *realm;
const u8 *pos, *realm_name, *end;
struct {
unsigned int realm_data_idx;
unsigned int realm_idx;
} matches[10];
pos = home_realm;
end = pos + home_realm_len;
if (pos + 1 > end) {
wpa_hexdump(MSG_DEBUG, "Too short NAI Home Realm Query",
home_realm, home_realm_len);
return -1;
}
num_realms = *pos++;
for (i = 0; i < num_realms && num_matching < 10; i++) {
if (pos + 2 > end) {
wpa_hexdump(MSG_DEBUG,
"Truncated NAI Home Realm Query",
home_realm, home_realm_len);
return -1;
}
encoding = *pos++;
realm_len = *pos++;
if (pos + realm_len > end) {
wpa_hexdump(MSG_DEBUG,
"Truncated NAI Home Realm Query",
home_realm, home_realm_len);
return -1;
}
realm_name = pos;
for (j = 0; j < hapd->conf->nai_realm_count &&
num_matching < 10; j++) {
const u8 *rpos, *rend;
realm = &hapd->conf->nai_realm_data[j];
if (encoding != realm->encoding)
continue;
rpos = realm_name;
while (rpos < realm_name + realm_len &&
num_matching < 10) {
for (rend = rpos;
rend < realm_name + realm_len; rend++) {
if (*rend == ';')
break;
}
for (k = 0; k < MAX_NAI_REALMS &&
realm->realm[k] &&
num_matching < 10; k++) {
if ((int) os_strlen(realm->realm[k]) !=
rend - rpos ||
os_strncmp((char *) rpos,
realm->realm[k],
rend - rpos) != 0)
continue;
matches[num_matching].realm_data_idx =
j;
matches[num_matching].realm_idx = k;
num_matching++;
}
rpos = rend + 1;
}
}
pos += realm_len;
}
realm_list_len = gas_anqp_add_element(buf, ANQP_NAI_REALM);
wpabuf_put_le16(buf, num_matching);
/*
* There are two ways to format. 1. each realm in a NAI Realm Data unit
* 2. all realms that share the same EAP methods in a NAI Realm Data
* unit. The first format is likely to be bigger in size than the
* second, but may be easier to parse and process by the receiver.
*/
for (i = 0; i < num_matching; i++) {
wpa_printf(MSG_DEBUG, "realm_idx %d, realm_data_idx %d",
matches[i].realm_data_idx, matches[i].realm_idx);
realm = &hapd->conf->nai_realm_data[matches[i].realm_data_idx];
anqp_add_nai_realm_data(buf, realm, matches[i].realm_idx);
}
gas_anqp_set_element_len(buf, realm_list_len);
return 0;
}
static void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf,
const u8 *home_realm, size_t home_realm_len,
int nai_realm, int nai_home_realm)
{
if (nai_realm && hapd->conf->nai_realm_data) {
u8 *len; u8 *len;
unsigned int i, j; unsigned int i, j;
len = gas_anqp_add_element(buf, ANQP_NAI_REALM); len = gas_anqp_add_element(buf, ANQP_NAI_REALM);
@ -283,6 +398,9 @@ static void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf)
gas_anqp_set_element_len(buf, realm_data_len); gas_anqp_set_element_len(buf, realm_data_len);
} }
gas_anqp_set_element_len(buf, len); gas_anqp_set_element_len(buf, len);
} else if (nai_home_realm && hapd->conf->nai_realm_data) {
hs20_add_nai_home_realm_matches(hapd, buf, home_realm,
home_realm_len);
} }
} }
@ -385,7 +503,8 @@ static void anqp_add_operating_class(struct hostapd_data *hapd,
static struct wpabuf * static struct wpabuf *
gas_serv_build_gas_resp_payload(struct hostapd_data *hapd, gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
unsigned int request, unsigned int request,
struct gas_dialog_info *di) struct gas_dialog_info *di,
const u8 *home_realm, size_t home_realm_len)
{ {
struct wpabuf *buf; struct wpabuf *buf;
@ -403,8 +522,10 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
anqp_add_roaming_consortium(hapd, buf); anqp_add_roaming_consortium(hapd, buf);
if (request & ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY) if (request & ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY)
anqp_add_ip_addr_type_availability(hapd, buf); anqp_add_ip_addr_type_availability(hapd, buf);
if (request & ANQP_REQ_NAI_REALM) if (request & (ANQP_REQ_NAI_REALM | ANQP_REQ_NAI_HOME_REALM))
anqp_add_nai_realm(hapd, buf); anqp_add_nai_realm(hapd, buf, home_realm, home_realm_len,
request & ANQP_REQ_NAI_REALM,
request & ANQP_REQ_NAI_HOME_REALM);
if (request & ANQP_REQ_3GPP_CELLULAR_NETWORK) if (request & ANQP_REQ_3GPP_CELLULAR_NETWORK)
anqp_add_3gpp_cellular_network(hapd, buf); anqp_add_3gpp_cellular_network(hapd, buf);
if (request & ANQP_REQ_DOMAIN_NAME) if (request & ANQP_REQ_DOMAIN_NAME)
@ -439,8 +560,8 @@ static void gas_serv_clear_cached_ies(void *eloop_data, void *user_ctx)
struct anqp_query_info { struct anqp_query_info {
unsigned int request; unsigned int request;
unsigned int remote_request; unsigned int remote_request;
const void *param; const u8 *home_realm_query;
u32 param_arg; size_t home_realm_query_len;
u16 remote_delay; u16 remote_delay;
}; };
@ -566,6 +687,23 @@ static void rx_anqp_hs_query_list(struct hostapd_data *hapd, u8 subtype,
} }
static void rx_anqp_hs_nai_home_realm(struct hostapd_data *hapd,
const u8 *pos, const u8 *end,
struct anqp_query_info *qi)
{
qi->request |= ANQP_REQ_NAI_HOME_REALM;
qi->home_realm_query = pos;
qi->home_realm_query_len = end - pos;
if (hapd->conf->nai_realm_data != NULL) {
wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query "
"(local)");
} else {
wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query not "
"available");
}
}
static void rx_anqp_vendor_specific(struct hostapd_data *hapd, static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
const u8 *pos, const u8 *end, const u8 *pos, const u8 *end,
struct anqp_query_info *qi) struct anqp_query_info *qi)
@ -607,6 +745,9 @@ static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
pos++; pos++;
} }
break; break;
case HS20_STYPE_NAI_HOME_REALM_QUERY:
rx_anqp_hs_nai_home_realm(hapd, pos, end, qi);
break;
default: default:
wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 query subtype " wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 query subtype "
"%u", subtype); "%u", subtype);
@ -621,7 +762,9 @@ static void gas_serv_req_local_processing(struct hostapd_data *hapd,
{ {
struct wpabuf *buf, *tx_buf; struct wpabuf *buf, *tx_buf;
buf = gas_serv_build_gas_resp_payload(hapd, qi->request, NULL); buf = gas_serv_build_gas_resp_payload(hapd, qi->request, NULL,
qi->home_realm_query,
qi->home_realm_query_len);
wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Locally generated ANQP responses", wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Locally generated ANQP responses",
buf); buf);
if (!buf) if (!buf)
@ -782,7 +925,7 @@ void gas_serv_tx_gas_response(struct hostapd_data *hapd, const u8 *dst,
if (dialog->sd_resp == NULL) { if (dialog->sd_resp == NULL) {
buf = gas_serv_build_gas_resp_payload(hapd, buf = gas_serv_build_gas_resp_payload(hapd,
dialog->all_requested, dialog->all_requested,
dialog); dialog, NULL, 0);
wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses", wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses",
buf); buf);
if (!buf) if (!buf)
@ -911,7 +1054,7 @@ static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
buf = gas_serv_build_gas_resp_payload(hapd, buf = gas_serv_build_gas_resp_payload(hapd,
dialog->all_requested, dialog->all_requested,
dialog); dialog, NULL, 0);
wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses", wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses",
buf); buf);
if (!buf) if (!buf)

View file

@ -33,6 +33,8 @@
(0x10000 << HS20_STYPE_WAN_METRICS) (0x10000 << HS20_STYPE_WAN_METRICS)
#define ANQP_REQ_CONNECTION_CAPABILITY \ #define ANQP_REQ_CONNECTION_CAPABILITY \
(0x10000 << HS20_STYPE_CONNECTION_CAPABILITY) (0x10000 << HS20_STYPE_CONNECTION_CAPABILITY)
#define ANQP_REQ_NAI_HOME_REALM \
(0x10000 << HS20_STYPE_NAI_HOME_REALM_QUERY)
#define ANQP_REQ_OPERATING_CLASS \ #define ANQP_REQ_OPERATING_CLASS \
(0x10000 << HS20_STYPE_OPERATING_CLASS) (0x10000 << HS20_STYPE_OPERATING_CLASS)