HS 2.0R2: Add support for Policy/RequiredProtoPortTuple

The new credential parameter req_conn_capab can be used to specify
restrictions on roaming networks providing connectivity for a set of
protocols/ports.

Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
Jouni Malinen 2013-08-08 20:31:41 +03:00 committed by Jouni Malinen
parent a45b2dc5dc
commit 33fb8c526c
5 changed files with 202 additions and 3 deletions

View file

@ -244,6 +244,21 @@ Credentials can be pre-configured for automatic network selection:
# BSS Load or if the limit would prevent any connection, this constraint
# will be ignored.
#
# req_conn_capab: Required connection capability
# (PPS/<X+>/Policy/RequiredProtoPortTuple)
# This value is used to configure set of required protocol/port pairs that
# a roaming network shall support (include explicitly in Connection
# Capability ANQP element). This constraint is ignored if the AP does not
# advertise Connection Capability or if this constraint would prevent any
# network connection. This policy is not used in home networks.
# Format: <protocol>[:<comma-separated list of ports]
# Multiple entries can be used to list multiple requirements.
# For example, number of common TCP protocols:
# req_conn_capab=6,22,80,443
# For example, IPSec/IKE:
# req_conn_capab=17:500
# req_conn_capab=50
#
# for example:
#
#cred={

View file

@ -1931,6 +1931,10 @@ void wpa_config_free_cred(struct wpa_cred *cred)
os_free(cred->excluded_ssid);
os_free(cred->roaming_partner);
os_free(cred->provisioning_sp);
for (i = 0; i < cred->num_req_conn_capab; i++)
os_free(cred->req_conn_capab_port[i]);
os_free(cred->req_conn_capab_port);
os_free(cred->req_conn_capab_proto);
os_free(cred);
}
@ -2402,6 +2406,69 @@ void wpa_config_update_psk(struct wpa_ssid *ssid)
}
static int wpa_config_set_cred_req_conn_capab(struct wpa_cred *cred,
const char *value)
{
u8 *proto;
int **port;
int *ports, *nports;
const char *pos;
unsigned int num_ports;
proto = os_realloc_array(cred->req_conn_capab_proto,
cred->num_req_conn_capab + 1, sizeof(u8));
if (proto == NULL)
return -1;
cred->req_conn_capab_proto = proto;
port = os_realloc_array(cred->req_conn_capab_port,
cred->num_req_conn_capab + 1, sizeof(int *));
if (port == NULL)
return -1;
cred->req_conn_capab_port = port;
proto[cred->num_req_conn_capab] = atoi(value);
pos = os_strchr(value, ':');
if (pos == NULL) {
port[cred->num_req_conn_capab] = NULL;
cred->num_req_conn_capab++;
return 0;
}
pos++;
ports = NULL;
num_ports = 0;
while (*pos) {
nports = os_realloc_array(ports, num_ports + 1, sizeof(int));
if (nports == NULL) {
os_free(ports);
return -1;
}
ports = nports;
ports[num_ports++] = atoi(pos);
pos = os_strchr(pos, ',');
if (pos == NULL)
break;
pos++;
}
nports = os_realloc_array(ports, num_ports + 1, sizeof(int));
if (nports == NULL) {
os_free(ports);
return -1;
}
ports = nports;
ports[num_ports] = -1;
port[cred->num_req_conn_capab] = ports;
cred->num_req_conn_capab++;
return 0;
}
int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
const char *value, int line)
{
@ -2478,6 +2545,9 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
return 0;
}
if (os_strcmp(var, "req_conn_capab") == 0)
return wpa_config_set_cred_req_conn_capab(cred, value);
val = wpa_config_parse_string(value, &len);
if (val == NULL) {
wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string "

View file

@ -265,6 +265,10 @@ struct wpa_cred {
* constraint will be ignored.
*/
unsigned int max_bss_load;
unsigned int num_req_conn_capab;
u8 *req_conn_capab_proto;
int **req_conn_capab_port;
};

View file

@ -167,6 +167,7 @@ static int cred_with_domain(struct wpa_supplicant *wpa_s)
#ifdef CONFIG_HS20
static int cred_with_min_backhaul(struct wpa_supplicant *wpa_s)
{
struct wpa_cred *cred;
@ -180,6 +181,19 @@ static int cred_with_min_backhaul(struct wpa_supplicant *wpa_s)
}
return 0;
}
static int cred_with_conn_capab(struct wpa_supplicant *wpa_s)
{
struct wpa_cred *cred;
for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
if (cred->num_req_conn_capab)
return 1;
}
return 0;
}
#endif /* CONFIG_HS20 */
@ -253,7 +267,7 @@ static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s,
HS20_STYPE_OPERATOR_FRIENDLY_NAME);
if (all || cred_with_min_backhaul(wpa_s))
wpabuf_put_u8(extra, HS20_STYPE_WAN_METRICS);
if (all)
if (all || cred_with_conn_capab(wpa_s))
wpabuf_put_u8(extra, HS20_STYPE_CONNECTION_CAPABILITY);
if (all)
wpabuf_put_u8(extra, HS20_STYPE_OPERATING_CLASS);
@ -1153,6 +1167,76 @@ static int cred_over_max_bss_load(struct wpa_supplicant *wpa_s,
}
static int has_proto_match(const u8 *pos, const u8 *end, u8 proto)
{
while (pos + 4 <= end) {
if (pos[0] == proto && pos[3] == 1 /* Open */)
return 1;
pos += 4;
}
return 0;
}
static int has_proto_port_match(const u8 *pos, const u8 *end, u8 proto,
u16 port)
{
while (pos + 4 <= end) {
if (pos[0] == proto && WPA_GET_LE16(&pos[1]) == port &&
pos[3] == 1 /* Open */)
return 1;
pos += 4;
}
return 0;
}
static int cred_conn_capab_missing(struct wpa_supplicant *wpa_s,
struct wpa_cred *cred, struct wpa_bss *bss)
{
int res;
const u8 *capab, *end;
unsigned int i, j;
int *ports;
if (!cred->num_req_conn_capab)
return 0; /* No connection capability constraint specified */
if (bss->anqp == NULL || bss->anqp->hs20_connection_capability == NULL)
return 0; /* No Connection Capability known - ignore constraint
*/
res = interworking_home_sp_cred(wpa_s, cred, bss->anqp ?
bss->anqp->domain_name : NULL);
if (res > 0)
return 0; /* No constraint in home network */
capab = wpabuf_head(bss->anqp->hs20_connection_capability);
end = capab + wpabuf_len(bss->anqp->hs20_connection_capability);
for (i = 0; i < cred->num_req_conn_capab; i++) {
ports = cred->req_conn_capab_port[i];
if (!ports) {
if (!has_proto_match(capab, end,
cred->req_conn_capab_proto[i]))
return 1;
} else {
for (j = 0; ports[j] > -1; j++) {
if (!has_proto_port_match(
capab, end,
cred->req_conn_capab_proto[i],
ports[j]))
return 1;
}
}
}
return 0;
}
static struct wpa_cred * interworking_credentials_available_roaming_consortium(
struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw)
{
@ -1188,6 +1272,8 @@ static struct wpa_cred * interworking_credentials_available_roaming_consortium(
continue;
if (!ignore_bw && cred_over_max_bss_load(wpa_s, cred, bss))
continue;
if (!ignore_bw && cred_conn_capab_missing(wpa_s, cred, bss))
continue;
if (selected == NULL ||
selected->priority < cred->priority)
@ -1683,6 +1769,9 @@ static struct wpa_cred * interworking_credentials_available_3gpp(
if (!ignore_bw &&
cred_over_max_bss_load(wpa_s, cred, bss))
continue;
if (!ignore_bw &&
cred_conn_capab_missing(wpa_s, cred, bss))
continue;
if (selected == NULL ||
selected->priority < cred->priority)
selected = cred;
@ -1733,6 +1822,9 @@ static struct wpa_cred * interworking_credentials_available_realm(
if (!ignore_bw &&
cred_over_max_bss_load(wpa_s, cred, bss))
continue;
if (!ignore_bw &&
cred_conn_capab_missing(wpa_s, cred, bss))
continue;
if (selected == NULL ||
selected->priority < cred->priority)
selected = cred;
@ -2024,12 +2116,15 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s)
type = "roaming";
else
type = "unknown";
wpa_msg(wpa_s, MSG_INFO, INTERWORKING_AP MACSTR " type=%s%s%s",
wpa_msg(wpa_s, MSG_INFO, INTERWORKING_AP MACSTR
" type=%s%s%s%s",
MAC2STR(bss->bssid), type,
cred_below_min_backhaul(wpa_s, cred, bss) ?
" below_min_backhaul=1" : "",
cred_over_max_bss_load(wpa_s, cred, bss) ?
" over_max_bss_load=1" : "");
" over_max_bss_load=1" : "",
cred_conn_capab_missing(wpa_s, cred, bss) ?
" conn_capab_missing=1" : "");
if (wpa_s->auto_select ||
(wpa_s->conf->auto_interworking &&
wpa_s->auto_network_select)) {

View file

@ -463,6 +463,21 @@ fast_reauth=1
# BSS Load or if the limit would prevent any connection, this constraint
# will be ignored.
#
# req_conn_capab: Required connection capability
# (PPS/<X+>/Policy/RequiredProtoPortTuple)
# This value is used to configure set of required protocol/port pairs that
# a roaming network shall support (include explicitly in Connection
# Capability ANQP element). This constraint is ignored if the AP does not
# advertise Connection Capability or if this constraint would prevent any
# network connection. This policy is not used in home networks.
# Format: <protocol>[:<comma-separated list of ports]
# Multiple entries can be used to list multiple requirements.
# For example, number of common TCP protocols:
# req_conn_capab=6,22,80,443
# For example, IPSec/IKE:
# req_conn_capab=17:500
# req_conn_capab=50
#
# for example:
#
#cred={