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:
parent
a45b2dc5dc
commit
33fb8c526c
5 changed files with 202 additions and 3 deletions
|
@ -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={
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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={
|
||||
|
|
Loading…
Reference in a new issue