netconfig: Re-add FILS handling

Load the settings from FILS IE data into our l_netconfig instance when
appropriate.
This commit is contained in:
Andrew Zaborowski 2022-08-29 19:35:59 +02:00 committed by Denis Kenzior
parent fbdd4471a1
commit 11bae53408
3 changed files with 166 additions and 1 deletions

View File

@ -103,6 +103,10 @@ void netconfig_commit(struct netconfig *netconfig, uint8_t family,
if (family == AF_INET &&
!netconfig->static_config[INDEX_FOR_AF(family)])
netconfig_dhcp_gateway_to_arp(netconfig);
if (!netconfig->connected[INDEX_FOR_AF(family)] &&
netconfig_use_fils_addr(netconfig, family))
netconfig_commit_fils_macs(netconfig, family);
}
}
@ -187,6 +191,53 @@ void netconfig_dhcp_gateway_to_arp(struct netconfig *netconfig)
l_debug("l_rtnl_neighbor_set_hwaddr failed");
}
void netconfig_commit_fils_macs(struct netconfig *netconfig, uint8_t family)
{
const struct ie_fils_ip_addr_response_info *fils =
netconfig->fils_override;
const void *addr;
const void *hwaddr;
size_t addr_len = (family == AF_INET ? 4 : 16);
uint32_t ifindex = netdev_get_ifindex(netconfig->netdev);
if (!fils)
return;
/*
* Attempt to use the gateway/DNS MAC addressed received from the AP
* by writing the mapping directly into the netdev's ARP table so as
* to save one data frame roundtrip before first IP connections are
* established. This is very low-priority but print error messages
* just because they may indicate bigger problems.
*/
addr = (family == AF_INET ? (void *) &fils->ipv4_gateway :
(void *) &fils->ipv6_gateway);
hwaddr = (family == AF_INET ?
&fils->ipv4_gateway_mac : &fils->ipv6_gateway_mac);
if (!l_memeqzero(addr, addr_len) && !l_memeqzero(hwaddr, ETH_ALEN) &&
unlikely(!l_rtnl_neighbor_set_hwaddr(rtnl, ifindex,
family, addr, hwaddr, ETH_ALEN,
netconfig_set_neighbor_entry_cb,
NULL, NULL)))
l_debug("l_rtnl_neighbor_set_hwaddr(%s, gateway) failed",
family == AF_INET ? "AF_INET" : "AF_INET6");
addr = (family == AF_INET ? (void *) &fils->ipv4_dns :
(void *) &fils->ipv6_dns);
hwaddr = (family == AF_INET ?
&fils->ipv4_dns_mac : &fils->ipv6_dns_mac);
if (!l_memeqzero(addr, addr_len) && !l_memeqzero(hwaddr, ETH_ALEN) &&
unlikely(!l_rtnl_neighbor_set_hwaddr(rtnl, ifindex,
family, addr, hwaddr, ETH_ALEN,
netconfig_set_neighbor_entry_cb,
NULL, NULL)))
l_debug("l_rtnl_neighbor_set_hwaddr(%s, DNS) failed",
family == AF_INET ? "AF_INET" : "AF_INET6");
}
static void netconfig_dns_list_update(struct netconfig *netconfig)
{
_auto_(l_strv_free) char **dns_list =

View File

@ -90,6 +90,26 @@ static void netconfig_free(void *data)
l_free(netconfig);
}
static bool netconfig_addr_to_str(uint8_t af, const void *v4_addr,
const void *v6_addr, char *out_str,
bool *out_is_zero)
{
const void *addr = (af == AF_INET ? v4_addr : v6_addr);
uint8_t bytes = (af == AF_INET ? 4 : 16);
if (l_memeqzero(addr, bytes)) {
*out_is_zero = true;
return true;
}
*out_is_zero = false;
if (L_WARN_ON(!inet_ntop(af, addr, out_str, INET6_ADDRSTRLEN)))
return false;
return true;
}
bool netconfig_use_fils_addr(struct netconfig *netconfig, int af)
{
if (!netconfig->enabled[INDEX_FOR_AF(af)])
@ -408,12 +428,96 @@ mdns:
return false;
}
static bool netconfig_load_fils_settings(struct netconfig *netconfig,
uint8_t af)
{
struct ie_fils_ip_addr_response_info *fils = netconfig->fils_override;
char addr_str[INET6_ADDRSTRLEN];
char gw_addr_str[INET6_ADDRSTRLEN];
char dns_addr_str[INET6_ADDRSTRLEN];
_auto_(l_rtnl_address_free) struct l_rtnl_address *rtnl_addr = NULL;
bool is_zero = false;
uint8_t prefix_len;
if (!netconfig_addr_to_str(af, &fils->ipv4_addr, &fils->ipv6_addr,
addr_str, &is_zero) || is_zero)
return is_zero;
prefix_len = (af == AF_INET ? fils->ipv4_prefix_len :
fils->ipv6_prefix_len);
if (L_WARN_ON(!(rtnl_addr = l_rtnl_address_new(addr_str, prefix_len))))
return false;
if (L_WARN_ON(!l_netconfig_set_static_addr(netconfig->nc, af,
rtnl_addr)))
return false;
if (af == AF_INET &&
L_WARN_ON(!l_netconfig_set_acd_enabled(netconfig->nc,
false)))
return false;
/*
* Done with local address, move on to gateway and DNS.
*
* Since load_settings is called early, generally before the actual
* connection setup starts, and load_fils_settings is called after
* 802.11 Authentication & Association, we need to check if either
* the gateway or DNS settings were overridden in load_settings so
* as not to overwrite the user-provided values. Values received
* with FILS are expected to have the same weight as those from
* DHCP/SLAAC.
*
* TODO: If netconfig->fils_override->ipv{4,6}_lifetime is set,
* start a timeout to renew the address using FILS IP Address
* Assignment or perhaps just start the DHCP client after that
* time.
*
* TODO: validate gateway and/or DNS on local subnet, link-local,
* etc.?
*/
if (!netconfig_addr_to_str(af, &fils->ipv4_gateway, &fils->ipv6_gateway,
gw_addr_str, &is_zero))
return false;
if (!netconfig->gateway_overridden[INDEX_FOR_AF(af)] && !is_zero &&
L_WARN_ON(!l_netconfig_set_gateway_override(
netconfig->nc,
af,
gw_addr_str)))
return false;
if (!netconfig_addr_to_str(af, &fils->ipv4_dns, &fils->ipv6_dns,
dns_addr_str, &is_zero))
return is_zero;
if (!netconfig->dns_overridden[INDEX_FOR_AF(af)] && !is_zero) {
char *dns_list[2] = { dns_addr_str, NULL };
if (L_WARN_ON(!l_netconfig_set_dns_override(netconfig->nc,
af, dns_list)))
return false;
}
return true;
}
bool netconfig_configure(struct netconfig *netconfig,
netconfig_notify_func_t notify, void *user_data)
{
netconfig->notify = notify;
netconfig->user_data = user_data;
if (netconfig_use_fils_addr(netconfig, AF_INET) &&
!netconfig_load_fils_settings(netconfig, AF_INET))
return false;
if (netconfig_use_fils_addr(netconfig, AF_INET6) &&
!netconfig_load_fils_settings(netconfig, AF_INET6))
return false;
if (unlikely(!l_netconfig_start(netconfig->nc)))
return false;
@ -429,9 +533,18 @@ bool netconfig_reconfigure(struct netconfig *netconfig, bool set_arp_gw)
* lost or delayed. Try to force the gateway into the ARP cache
* to alleviate this
*/
if (set_arp_gw)
if (set_arp_gw) {
netconfig_dhcp_gateway_to_arp(netconfig);
if (netconfig->connected[INDEX_FOR_AF(AF_INET)] &&
netconfig_use_fils_addr(netconfig, AF_INET))
netconfig_commit_fils_macs(netconfig, AF_INET);
if (netconfig->connected[INDEX_FOR_AF(AF_INET6)] &&
netconfig_use_fils_addr(netconfig, AF_INET6))
netconfig_commit_fils_macs(netconfig, AF_INET6);
}
if (!netconfig->static_config[INDEX_FOR_AF(AF_INET)]) {
/* TODO l_dhcp_client sending a DHCP inform request */
}

View File

@ -83,3 +83,4 @@ void netconfig_commit(struct netconfig *netconfig, uint8_t family,
enum l_netconfig_event event);
void netconfig_dhcp_gateway_to_arp(struct netconfig *netconfig);
void netconfig_commit_fils_macs(struct netconfig *netconfig, uint8_t family);