Interworking: Add advertising of NAI Realm list
Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
a9277e85ca
commit
8047b18691
6 changed files with 251 additions and 0 deletions
|
@ -1412,6 +1412,147 @@ fail:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int parse_nai_realm(struct hostapd_bss_config *bss, char *buf, int line)
|
||||||
|
{
|
||||||
|
struct hostapd_nai_realm_data *realm;
|
||||||
|
size_t i, j, len;
|
||||||
|
int *offsets;
|
||||||
|
char *pos, *end, *rpos;
|
||||||
|
|
||||||
|
offsets = os_calloc(bss->nai_realm_count * MAX_NAI_REALMS,
|
||||||
|
sizeof(int));
|
||||||
|
if (offsets == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (i = 0; i < bss->nai_realm_count; i++) {
|
||||||
|
realm = &bss->nai_realm_data[i];
|
||||||
|
for (j = 0; j < MAX_NAI_REALMS; j++) {
|
||||||
|
offsets[i * MAX_NAI_REALMS + j] =
|
||||||
|
realm->realm[j] ?
|
||||||
|
realm->realm[j] - realm->realm_buf : -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
realm = os_realloc_array(bss->nai_realm_data, bss->nai_realm_count + 1,
|
||||||
|
sizeof(struct hostapd_nai_realm_data));
|
||||||
|
if (realm == NULL) {
|
||||||
|
os_free(offsets);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
bss->nai_realm_data = realm;
|
||||||
|
|
||||||
|
/* patch the pointers after realloc */
|
||||||
|
for (i = 0; i < bss->nai_realm_count; i++) {
|
||||||
|
realm = &bss->nai_realm_data[i];
|
||||||
|
for (j = 0; j < MAX_NAI_REALMS; j++) {
|
||||||
|
int offs = offsets[i * MAX_NAI_REALMS + j];
|
||||||
|
if (offs >= 0)
|
||||||
|
realm->realm[j] = realm->realm_buf + offs;
|
||||||
|
else
|
||||||
|
realm->realm[j] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
os_free(offsets);
|
||||||
|
|
||||||
|
realm = &bss->nai_realm_data[bss->nai_realm_count];
|
||||||
|
os_memset(realm, 0, sizeof(*realm));
|
||||||
|
|
||||||
|
pos = buf;
|
||||||
|
realm->encoding = atoi(pos);
|
||||||
|
pos = os_strchr(pos, ',');
|
||||||
|
if (pos == NULL)
|
||||||
|
goto fail;
|
||||||
|
pos++;
|
||||||
|
|
||||||
|
end = os_strchr(pos, ',');
|
||||||
|
if (end) {
|
||||||
|
len = end - pos;
|
||||||
|
*end = '\0';
|
||||||
|
} else {
|
||||||
|
len = os_strlen(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len > MAX_NAI_REALMLEN) {
|
||||||
|
wpa_printf(MSG_ERROR, "Too long a realm string (%d > max %d "
|
||||||
|
"characters)", (int) len, MAX_NAI_REALMLEN);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
os_memcpy(realm->realm_buf, pos, len);
|
||||||
|
|
||||||
|
if (end)
|
||||||
|
pos = end + 1;
|
||||||
|
else
|
||||||
|
pos = NULL;
|
||||||
|
|
||||||
|
while (pos && *pos) {
|
||||||
|
struct hostapd_nai_realm_eap *eap;
|
||||||
|
|
||||||
|
if (realm->eap_method_count >= MAX_NAI_EAP_METHODS) {
|
||||||
|
wpa_printf(MSG_ERROR, "Too many EAP methods");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
eap = &realm->eap_method[realm->eap_method_count];
|
||||||
|
realm->eap_method_count++;
|
||||||
|
|
||||||
|
end = os_strchr(pos, ',');
|
||||||
|
if (end == NULL)
|
||||||
|
end = pos + os_strlen(pos);
|
||||||
|
|
||||||
|
eap->eap_method = atoi(pos);
|
||||||
|
for (;;) {
|
||||||
|
pos = os_strchr(pos, '[');
|
||||||
|
if (pos == NULL || pos > end)
|
||||||
|
break;
|
||||||
|
pos++;
|
||||||
|
if (eap->num_auths >= MAX_NAI_AUTH_TYPES) {
|
||||||
|
wpa_printf(MSG_ERROR, "Too many auth params");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
eap->auth_id[eap->num_auths] = atoi(pos);
|
||||||
|
pos = os_strchr(pos, ':');
|
||||||
|
if (pos == NULL || pos > end)
|
||||||
|
goto fail;
|
||||||
|
pos++;
|
||||||
|
eap->auth_val[eap->num_auths] = atoi(pos);
|
||||||
|
pos = os_strchr(pos, ']');
|
||||||
|
if (pos == NULL || pos > end)
|
||||||
|
goto fail;
|
||||||
|
pos++;
|
||||||
|
eap->num_auths++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*end != ',')
|
||||||
|
break;
|
||||||
|
|
||||||
|
pos = end + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Split realm list into null terminated realms */
|
||||||
|
rpos = realm->realm_buf;
|
||||||
|
i = 0;
|
||||||
|
while (*rpos) {
|
||||||
|
if (i >= MAX_NAI_REALMS) {
|
||||||
|
wpa_printf(MSG_ERROR, "Too many realms");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
realm->realm[i++] = rpos;
|
||||||
|
rpos = os_strchr(rpos, ';');
|
||||||
|
if (rpos == NULL)
|
||||||
|
break;
|
||||||
|
*rpos++ = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
bss->nai_realm_count++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
wpa_printf(MSG_ERROR, "Line %d: invalid nai_realm '%s'", line, buf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_INTERWORKING */
|
#endif /* CONFIG_INTERWORKING */
|
||||||
|
|
||||||
|
|
||||||
|
@ -2679,6 +2820,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||||
} else if (os_strcmp(buf, "anqp_3gpp_cell_net") == 0) {
|
} else if (os_strcmp(buf, "anqp_3gpp_cell_net") == 0) {
|
||||||
if (parse_3gpp_cell_net(bss, pos, line) < 0)
|
if (parse_3gpp_cell_net(bss, pos, line) < 0)
|
||||||
errors++;
|
errors++;
|
||||||
|
} else if (os_strcmp(buf, "nai_realm") == 0) {
|
||||||
|
if (parse_nai_realm(bss, pos, line) < 0)
|
||||||
|
errors++;
|
||||||
} else if (os_strcmp(buf, "gas_frag_limit") == 0) {
|
} else if (os_strcmp(buf, "gas_frag_limit") == 0) {
|
||||||
bss->gas_frag_limit = atoi(pos);
|
bss->gas_frag_limit = atoi(pos);
|
||||||
} else if (os_strcmp(buf, "gas_comeback_delay") == 0) {
|
} else if (os_strcmp(buf, "gas_comeback_delay") == 0) {
|
||||||
|
|
|
@ -1388,6 +1388,31 @@ own_ip_addr=127.0.0.1
|
||||||
# format: <MCC1,MNC1>[;<MCC2,MNC2>][;...]
|
# format: <MCC1,MNC1>[;<MCC2,MNC2>][;...]
|
||||||
#anqp_3gpp_cell_net=244,91;310,026;234,56
|
#anqp_3gpp_cell_net=244,91;310,026;234,56
|
||||||
|
|
||||||
|
# NAI Realm information
|
||||||
|
# One or more realm can be advertised. Each nai_realm line adds a new realm to
|
||||||
|
# the set. These parameters provide information for stations using Interworking
|
||||||
|
# network selection to allow automatic connection to a network based on
|
||||||
|
# credentials.
|
||||||
|
# format: <encoding>,<NAI Realm(s)>[,<EAP Method 1>][,<EAP Method 2>][,...]
|
||||||
|
# encoding:
|
||||||
|
# 0 = Realm formatted in accordance with IETF RFC 4282
|
||||||
|
# 1 = UTF-8 formatted character string that is not formatted in
|
||||||
|
# accordance with IETF RFC 4282
|
||||||
|
# NAI Realm(s): Semi-colon delimited NAI Realm(s)
|
||||||
|
# EAP Method: <EAP Method>[:<[AuthParam1:Val1]>][<[AuthParam2:Val2]>][...]
|
||||||
|
# AuthParam (Table 8-188 in IEEE Std 802.11-2012):
|
||||||
|
# ID 2 = Non-EAP Inner Authentication Type
|
||||||
|
# 1 = PAP, 2 = CHAP, 3 = MSCHAP, 4 = MSCHAPV2
|
||||||
|
# ID 3 = Inner authentication EAP Method Type
|
||||||
|
# ID 5 = Credential Type
|
||||||
|
# 1 = SIM, 2 = USIM, 3 = NFC Secure Element, 4 = Hardware Token,
|
||||||
|
# 5 = Softoken, 6 = Certificate, 7 = username/password, 9 = Anonymous,
|
||||||
|
# 10 = Vendor Specific
|
||||||
|
#nai_realm=0,example.com;example.net
|
||||||
|
# EAP methods EAP-TLS with certificate and EAP-TTLS/MSCHAPv2 with
|
||||||
|
# username/password
|
||||||
|
#nai_realm=0,example.org,13[5:6],21[2:4][5:7]
|
||||||
|
|
||||||
##### Hotspot 2.0 #############################################################
|
##### Hotspot 2.0 #############################################################
|
||||||
|
|
||||||
# Enable Hotspot 2.0 support
|
# Enable Hotspot 2.0 support
|
||||||
|
|
|
@ -498,6 +498,7 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||||
|
|
||||||
os_free(conf->roaming_consortium);
|
os_free(conf->roaming_consortium);
|
||||||
os_free(conf->venue_name);
|
os_free(conf->venue_name);
|
||||||
|
os_free(conf->nai_realm_data);
|
||||||
os_free(conf->network_auth_type);
|
os_free(conf->network_auth_type);
|
||||||
os_free(conf->anqp_3gpp_cell_net);
|
os_free(conf->anqp_3gpp_cell_net);
|
||||||
os_free(conf->domain_name);
|
os_free(conf->domain_name);
|
||||||
|
|
|
@ -151,6 +151,23 @@ struct hostapd_lang_string {
|
||||||
u8 name[252];
|
u8 name[252];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define MAX_NAI_REALMS 10
|
||||||
|
#define MAX_NAI_REALMLEN 255
|
||||||
|
#define MAX_NAI_EAP_METHODS 5
|
||||||
|
#define MAX_NAI_AUTH_TYPES 4
|
||||||
|
struct hostapd_nai_realm_data {
|
||||||
|
u8 encoding;
|
||||||
|
char realm_buf[MAX_NAI_REALMLEN + 1];
|
||||||
|
char *realm[MAX_NAI_REALMS];
|
||||||
|
u8 eap_method_count;
|
||||||
|
struct hostapd_nai_realm_eap {
|
||||||
|
u8 eap_method;
|
||||||
|
u8 num_auths;
|
||||||
|
u8 auth_id[MAX_NAI_AUTH_TYPES];
|
||||||
|
u8 auth_val[MAX_NAI_AUTH_TYPES];
|
||||||
|
} eap_method[MAX_NAI_EAP_METHODS];
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct hostapd_bss_config - Per-BSS configuration
|
* struct hostapd_bss_config - Per-BSS configuration
|
||||||
*/
|
*/
|
||||||
|
@ -404,6 +421,9 @@ struct hostapd_bss_config {
|
||||||
u8 *domain_name;
|
u8 *domain_name;
|
||||||
size_t domain_name_len;
|
size_t domain_name_len;
|
||||||
|
|
||||||
|
unsigned int nai_realm_count;
|
||||||
|
struct hostapd_nai_realm_data *nai_realm_data;
|
||||||
|
|
||||||
u16 gas_comeback_delay;
|
u16 gas_comeback_delay;
|
||||||
int gas_frag_limit;
|
int gas_frag_limit;
|
||||||
|
|
||||||
|
|
|
@ -166,6 +166,8 @@ static void anqp_add_capab_list(struct hostapd_data *hapd,
|
||||||
wpabuf_put_le16(buf, ANQP_ROAMING_CONSORTIUM);
|
wpabuf_put_le16(buf, ANQP_ROAMING_CONSORTIUM);
|
||||||
if (hapd->conf->ipaddr_type_configured)
|
if (hapd->conf->ipaddr_type_configured)
|
||||||
wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
|
wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
|
||||||
|
if (hapd->conf->nai_realm_data)
|
||||||
|
wpabuf_put_le16(buf, ANQP_NAI_REALM);
|
||||||
if (hapd->conf->anqp_3gpp_cell_net)
|
if (hapd->conf->anqp_3gpp_cell_net)
|
||||||
wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
|
wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
|
||||||
if (hapd->conf->domain_name)
|
if (hapd->conf->domain_name)
|
||||||
|
@ -235,6 +237,56 @@ static void anqp_add_ip_addr_type_availability(struct hostapd_data *hapd,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void anqp_add_nai_realm_eap(struct wpabuf *buf,
|
||||||
|
struct hostapd_nai_realm_data *realm)
|
||||||
|
{
|
||||||
|
unsigned int i, j;
|
||||||
|
|
||||||
|
wpabuf_put_u8(buf, realm->eap_method_count);
|
||||||
|
|
||||||
|
for (i = 0; i < realm->eap_method_count; i++) {
|
||||||
|
struct hostapd_nai_realm_eap *eap = &realm->eap_method[i];
|
||||||
|
wpabuf_put_u8(buf, 2 + (3 * eap->num_auths));
|
||||||
|
wpabuf_put_u8(buf, eap->eap_method);
|
||||||
|
wpabuf_put_u8(buf, eap->num_auths);
|
||||||
|
for (j = 0; j < eap->num_auths; j++) {
|
||||||
|
wpabuf_put_u8(buf, eap->auth_id[j]);
|
||||||
|
wpabuf_put_u8(buf, 1);
|
||||||
|
wpabuf_put_u8(buf, eap->auth_val[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf)
|
||||||
|
{
|
||||||
|
if (hapd->conf->nai_realm_data) {
|
||||||
|
u8 *len;
|
||||||
|
unsigned int i, j;
|
||||||
|
len = gas_anqp_add_element(buf, ANQP_NAI_REALM);
|
||||||
|
wpabuf_put_le16(buf, hapd->conf->nai_realm_count);
|
||||||
|
for (i = 0; i < hapd->conf->nai_realm_count; i++) {
|
||||||
|
u8 *realm_data_len, *realm_len;
|
||||||
|
struct hostapd_nai_realm_data *realm;
|
||||||
|
|
||||||
|
realm = &hapd->conf->nai_realm_data[i];
|
||||||
|
realm_data_len = wpabuf_put(buf, 2);
|
||||||
|
wpabuf_put_u8(buf, realm->encoding);
|
||||||
|
realm_len = wpabuf_put(buf, 1);
|
||||||
|
for (j = 0; realm->realm[j]; j++) {
|
||||||
|
if (j > 0)
|
||||||
|
wpabuf_put_u8(buf, ';');
|
||||||
|
wpabuf_put_str(buf, realm->realm[j]);
|
||||||
|
}
|
||||||
|
*realm_len = (u8 *) wpabuf_put(buf, 0) - realm_len - 1;
|
||||||
|
anqp_add_nai_realm_eap(buf, realm);
|
||||||
|
gas_anqp_set_element_len(buf, realm_data_len);
|
||||||
|
}
|
||||||
|
gas_anqp_set_element_len(buf, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void anqp_add_3gpp_cellular_network(struct hostapd_data *hapd,
|
static void anqp_add_3gpp_cellular_network(struct hostapd_data *hapd,
|
||||||
struct wpabuf *buf)
|
struct wpabuf *buf)
|
||||||
{
|
{
|
||||||
|
@ -351,6 +403,8 @@ 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)
|
||||||
|
anqp_add_nai_realm(hapd, buf);
|
||||||
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)
|
||||||
|
@ -436,6 +490,11 @@ static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id,
|
||||||
hapd->conf->ipaddr_type_configured,
|
hapd->conf->ipaddr_type_configured,
|
||||||
0, 0, qi);
|
0, 0, qi);
|
||||||
break;
|
break;
|
||||||
|
case ANQP_NAI_REALM:
|
||||||
|
set_anqp_req(ANQP_REQ_NAI_REALM, "NAI Realm",
|
||||||
|
hapd->conf->nai_realm_data != NULL,
|
||||||
|
0, 0, qi);
|
||||||
|
break;
|
||||||
case ANQP_3GPP_CELLULAR_NETWORK:
|
case ANQP_3GPP_CELLULAR_NETWORK:
|
||||||
set_anqp_req(ANQP_REQ_3GPP_CELLULAR_NETWORK,
|
set_anqp_req(ANQP_REQ_3GPP_CELLULAR_NETWORK,
|
||||||
"3GPP Cellular Network",
|
"3GPP Cellular Network",
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
(1 << (ANQP_ROAMING_CONSORTIUM - ANQP_QUERY_LIST))
|
(1 << (ANQP_ROAMING_CONSORTIUM - ANQP_QUERY_LIST))
|
||||||
#define ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY \
|
#define ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY \
|
||||||
(1 << (ANQP_IP_ADDR_TYPE_AVAILABILITY - ANQP_QUERY_LIST))
|
(1 << (ANQP_IP_ADDR_TYPE_AVAILABILITY - ANQP_QUERY_LIST))
|
||||||
|
#define ANQP_REQ_NAI_REALM \
|
||||||
|
(1 << (ANQP_NAI_REALM - ANQP_QUERY_LIST))
|
||||||
#define ANQP_REQ_3GPP_CELLULAR_NETWORK \
|
#define ANQP_REQ_3GPP_CELLULAR_NETWORK \
|
||||||
(1 << (ANQP_3GPP_CELLULAR_NETWORK - ANQP_QUERY_LIST))
|
(1 << (ANQP_3GPP_CELLULAR_NETWORK - ANQP_QUERY_LIST))
|
||||||
#define ANQP_REQ_DOMAIN_NAME \
|
#define ANQP_REQ_DOMAIN_NAME \
|
||||||
|
|
Loading…
Reference in a new issue