HS 2.0: Add NAI Home Realm query
Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
8047b18691
commit
43f51e2aa0
2 changed files with 155 additions and 10 deletions
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue