Interworking: Add advertising of NAI Realm list

Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
Jay Katabathuni 2012-08-25 15:58:30 +03:00 committed by Jouni Malinen
parent a9277e85ca
commit 8047b18691
6 changed files with 251 additions and 0 deletions

View file

@ -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) {

View file

@ -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

View file

@ -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);

View file

@ -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;

View file

@ -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",

View file

@ -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 \