iwd.lists.linux.dev archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/5] netconfig: Move loading settings to new method, refactor
@ 2021-08-27  3:02 Andrew Zaborowski
  2021-08-27  3:02 ` [PATCH 2/5] netconfig: FILS IP assigment API Andrew Zaborowski
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Andrew Zaborowski @ 2021-08-27  3:02 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 13946 bytes --]

Split loading settings out of network_configure into a new method,
network_load_settings.  Make sure both consistently handle errors by
printing messages and informing the caller.
---
 src/netconfig.c | 236 ++++++++++++++++++++++++++++++------------------
 src/netconfig.h |   5 +-
 src/p2p.c       |  12 ++-
 src/station.c   |  20 ++--
 4 files changed, 175 insertions(+), 98 deletions(-)

diff --git a/src/netconfig.c b/src/netconfig.c
index 005316cd..10c9b90c 100644
--- a/src/netconfig.c
+++ b/src/netconfig.c
@@ -47,6 +47,7 @@
 #include "src/common.h"
 #include "src/network.h"
 #include "src/resolve.h"
+#include "src/util.h"
 #include "src/netconfig.h"
 
 struct netconfig {
@@ -270,49 +271,47 @@ static int netconfig_set_domains(struct netconfig *netconfig)
 }
 
 static struct l_rtnl_address *netconfig_get_static4_address(
-						struct netconfig *netconfig)
+				const struct l_settings *active_settings)
 {
 	struct l_rtnl_address *ifaddr = NULL;
-	char *ip;
-	char *netmask;
+	L_AUTO_FREE_VAR(char *, ip) = NULL;
+	L_AUTO_FREE_VAR(char *, netmask) = NULL;
 	struct in_addr in_addr;
-	char *broadcast;
+	L_AUTO_FREE_VAR(char *, broadcast) = NULL;
 	uint32_t prefix_len;
 
-	ip = l_settings_get_string(netconfig->active_settings, "IPv4",
-								"Address");
+	ip = l_settings_get_string(active_settings, "IPv4", "Address");
 	if (!ip)
 		return NULL;
 
-	netmask = l_settings_get_string(netconfig->active_settings,
-						"IPv4", "Netmask");
+	netmask = l_settings_get_string(active_settings, "IPv4", "Netmask");
+	if (netmask) {
+		if (inet_pton(AF_INET, netmask, &in_addr) != 1) {
+			l_error("netconfig: Can't parse IPv4 Netmask");
+			return NULL;
+		}
 
-	if (netmask && inet_pton(AF_INET, netmask, &in_addr) > 0)
 		prefix_len = __builtin_popcountl(in_addr.s_addr);
-	else
-		prefix_len = 24;
 
-	l_free(netmask);
+		if (ntohl(in_addr.s_addr) !=
+				util_netmask_from_prefix(prefix_len)) {
+			l_error("netconfig: Invalid IPv4 Netmask");
+			return NULL;
+		}
+	} else
+		prefix_len = 24;
 
 	ifaddr = l_rtnl_address_new(ip, prefix_len);
-	l_free(ip);
-
 	if (!ifaddr) {
-		l_error("Unable to parse IPv4.Address, ignoring...");
+		l_error("netconfig: Unable to parse IPv4.Address");
 		return NULL;
 	}
 
-	broadcast = l_settings_get_string(netconfig->active_settings,
-						"IPv4", "Broadcast");
-	if (broadcast) {
-		bool r = l_rtnl_address_set_broadcast(ifaddr, broadcast);
-		l_free(broadcast);
-
-		if (!r) {
-			l_error("Unable to parse IPv4.Broadcast, ignoring...");
-			l_rtnl_address_free(ifaddr);
-			return NULL;
-		}
+	broadcast = l_settings_get_string(active_settings, "IPv4", "Broadcast");
+	if (broadcast && !l_rtnl_address_set_broadcast(ifaddr, broadcast)) {
+		l_error("netconfig: Unable to parse IPv4.Broadcast");
+		l_rtnl_address_free(ifaddr);
+		return NULL;
 	}
 
 	l_rtnl_address_set_noprefixroute(ifaddr, true);
@@ -347,15 +346,14 @@ static char *netconfig_ipv4_get_gateway(struct netconfig *netconfig)
 }
 
 static struct l_rtnl_address *netconfig_get_static6_address(
-						struct netconfig *netconfig)
+				const struct l_settings *active_settings)
 {
 	L_AUTO_FREE_VAR(char *, ip);
 	char *p;
 	struct l_rtnl_address *ret;
 	uint32_t prefix_len = 128;
 
-	ip = l_settings_get_string(netconfig->active_settings, "IPv6",
-								"Address");
+	ip = l_settings_get_string(active_settings, "IPv6", "Address");
 	if (!ip)
 		return NULL;
 
@@ -898,14 +896,17 @@ static void netconfig_ipv4_acd_event(enum l_acd_event event, void *user_data)
 	}
 }
 
-static void netconfig_ipv4_select_and_install(struct netconfig *netconfig)
+static bool netconfig_ipv4_select_and_install(struct netconfig *netconfig)
 {
-	char ip[INET6_ADDRSTRLEN];
+	if (netconfig->rtm_protocol == RTPROT_STATIC) {
+		char ip[INET6_ADDRSTRLEN];
+
+		if (L_WARN_ON(!netconfig->v4_address ||
+					!l_rtnl_address_get_address(
+							netconfig->v4_address,
+							ip)))
+			return false;
 
-	netconfig->v4_address = netconfig_get_static4_address(netconfig);
-	if (netconfig->v4_address &&
-			l_rtnl_address_get_address(netconfig->v4_address, ip)) {
-		netconfig->rtm_protocol = RTPROT_STATIC;
 		netconfig->acd = l_acd_new(netconfig->ifindex);
 		l_acd_set_event_handler(netconfig->acd,
 					netconfig_ipv4_acd_event, netconfig,
@@ -926,47 +927,43 @@ static void netconfig_ipv4_select_and_install(struct netconfig *netconfig)
 					netconfig, NULL)));
 		}
 
-		return;
+		return true;
 	}
 
-	netconfig->rtm_protocol = RTPROT_DHCP;
-
 	if (l_dhcp_client_start(netconfig->dhcp_client))
-		return;
+		return true;
 
 	l_error("netconfig: Failed to start DHCPv4 client for interface %u",
 							netconfig->ifindex);
+	return false;
 }
 
-static void netconfig_ipv6_select_and_install(struct netconfig *netconfig)
+static bool netconfig_ipv6_select_and_install(struct netconfig *netconfig)
 {
 	struct netdev *netdev = netdev_find(netconfig->ifindex);
-	struct l_rtnl_address *address;
-	bool enabled;
 
-	if (!l_settings_get_bool(netconfig->active_settings, "IPv6",
-					"Enabled", &enabled))
-		enabled = ipv6_enabled;
-
-	if (!enabled) {
+	if (netconfig->rtm_v6_protocol == RTPROT_UNSPEC) {
 		l_debug("IPV6 configuration disabled");
-		return;
+		return true;
 	}
 
 	sysfs_write_ipv6_setting(netdev_get_name(netdev), "disable_ipv6", "0");
 
-	address = netconfig_get_static6_address(netconfig);
-	if (address) {
-		netconfig->rtm_v6_protocol = RTPROT_STATIC;
+	if (netconfig->rtm_v6_protocol == RTPROT_STATIC) {
+		struct l_rtnl_address *address =
+			netconfig_get_static6_address(
+						netconfig->active_settings);
+
 		L_WARN_ON(!(netconfig->addr6_add_cmd_id =
 			l_rtnl_ifaddr_add(rtnl, netconfig->ifindex, address,
 					netconfig_ipv6_ifaddr_add_cmd_cb,
 					netconfig, NULL)));
 		l_rtnl_address_free(address);
-		return;
+		return true;
 	}
 
-	netconfig->rtm_v6_protocol = RTPROT_DHCP;
+	/* DHCP */
+	return true;
 }
 
 static int validate_dns_list(int family, char **dns_list)
@@ -998,77 +995,144 @@ static int validate_dns_list(int family, char **dns_list)
 	return n_valid;
 }
 
-bool netconfig_configure(struct netconfig *netconfig,
+bool netconfig_load_settings(struct netconfig *netconfig,
 				const struct l_settings *active_settings,
-				const uint8_t *mac_address,
-				netconfig_notify_func_t notify, void *user_data)
+				const uint8_t *mac_address)
 {
 	char *mdns;
-	char hostname[HOST_NAME_MAX + 1];
 	bool send_hostname;
+	bool v6_enabled;
+	char hostname[HOST_NAME_MAX + 1];
+	char **dns4_overrides = NULL;
+	char **dns6_overrides = NULL;
+	struct l_rtnl_address *v4_address = NULL;
+	struct l_rtnl_address *v6_address = NULL;
 
-	netconfig->dns4_overrides = l_settings_get_string_list(active_settings,
+	dns4_overrides = l_settings_get_string_list(active_settings,
 							"IPv4", "DNS", ' ');
+	if (dns4_overrides) {
+		int r = validate_dns_list(AF_INET, dns4_overrides);
 
-	if (netconfig->dns4_overrides) {
-		int r = validate_dns_list(AF_INET, netconfig->dns4_overrides);
+		if (unlikely(r <= 0)) {
+			l_strfreev(dns4_overrides);
+			dns4_overrides = NULL;
 
-		if (r <= 0) {
-			l_strfreev(netconfig->dns4_overrides);
-			netconfig->dns4_overrides = NULL;
+			if (r < 0)
+				goto err_dns4;
 		}
 
 		if (r == 0)
 			l_error("netconfig: Empty IPv4.DNS entry, skipping...");
 	}
 
-	netconfig->dns6_overrides = l_settings_get_string_list(active_settings,
+	dns6_overrides = l_settings_get_string_list(active_settings,
 							"IPv6", "DNS", ' ');
 
-	if (netconfig->dns6_overrides) {
-		int r = validate_dns_list(AF_INET6, netconfig->dns6_overrides);
+	if (dns6_overrides) {
+		int r = validate_dns_list(AF_INET6, dns6_overrides);
+
+		if (unlikely(r <= 0)) {
+			l_strfreev(dns6_overrides);
+			dns6_overrides = NULL;
 
-		if (r <= 0) {
-			l_strfreev(netconfig->dns6_overrides);
-			netconfig->dns6_overrides = NULL;
+			if (r < 0)
+				goto err_dns6;
 		}
 
 		if (r == 0)
 			l_error("netconfig: Empty IPv6.DNS entry, skipping...");
 	}
 
-	netconfig->active_settings = active_settings;
-	netconfig->notify = notify;
-	netconfig->user_data = user_data;
-
-	l_dhcp_client_set_address(netconfig->dhcp_client, ARPHRD_ETHER,
-							mac_address, ETH_ALEN);
-	l_dhcp6_client_set_address(netconfig->dhcp6_client, ARPHRD_ETHER,
-							mac_address, ETH_ALEN);
-
 	if (!l_settings_get_bool(active_settings,
 					"IPv4", "SendHostname", &send_hostname))
 		send_hostname = false;
 
 	if (send_hostname) {
-		if (gethostname(hostname, sizeof(hostname)) == 0) {
-			l_dhcp_client_set_hostname(
-				netconfig->dhcp_client, hostname);
-		} else {
+		if (gethostname(hostname, sizeof(hostname)) != 0) {
 			l_warn("netconfig: Unable to get hostname. "
 					"Error %d: %s", errno, strerror(errno));
+			send_hostname = false;
 		}
 	}
 
-	netconfig_ipv4_select_and_install(netconfig);
+	mdns = l_settings_get_string(active_settings,
+					"Network", "MulticastDNS");
 
-	netconfig_ipv6_select_and_install(netconfig);
+	if (l_settings_has_key(active_settings, "IPv4", "Address")) {
+		v4_address = netconfig_get_static4_address(active_settings);
+
+		if (unlikely(!v4_address)) {
+			l_error("netconfig: Can't parse IPv4 address");
+			goto err_v4_addr;
+		}
+	}
+
+	if (!l_settings_get_bool(active_settings, "IPv6",
+					"Enabled", &v6_enabled))
+		v6_enabled = ipv6_enabled;
+
+	if (l_settings_has_key(active_settings, "IPv6", "Address")) {
+		v6_address = netconfig_get_static6_address(active_settings);
+		l_rtnl_address_free(v6_address);
+
+		if (unlikely(!v6_address)) {
+			l_error("netconfig: Can't parse IPv6 address");
+			goto err_v6_addr;
+		}
+	}
+
+	/* No more validation steps for now, commit new values */
+
+	if (v4_address) {
+		netconfig->v4_address = v4_address;
+		netconfig->rtm_protocol = RTPROT_STATIC;
+	} else
+		netconfig->rtm_protocol = RTPROT_DHCP;
+
+	if (!v6_enabled)
+		netconfig->rtm_v6_protocol = RTPROT_UNSPEC;
+	else if (v6_address)
+		netconfig->rtm_v6_protocol = RTPROT_STATIC;
+	else
+		netconfig->rtm_v6_protocol = RTPROT_DHCP;
+
+	if (send_hostname)
+		l_dhcp_client_set_hostname(netconfig->dhcp_client, hostname);
 
-	mdns = l_settings_get_string(active_settings,
-						"Network", "MulticastDNS");
 	resolve_set_mdns(netconfig->resolve, mdns);
 	l_free(mdns);
 
+	l_dhcp_client_set_address(netconfig->dhcp_client, ARPHRD_ETHER,
+							mac_address, ETH_ALEN);
+	l_dhcp6_client_set_address(netconfig->dhcp6_client, ARPHRD_ETHER,
+							mac_address, ETH_ALEN);
+
+	netconfig->active_settings = active_settings;
+	return true;
+
+err_v6_addr:
+	l_rtnl_address_free(v4_address);
+err_v4_addr:
+	l_free(mdns);
+	l_strfreev(dns6_overrides);
+err_dns6:
+	l_strfreev(dns4_overrides);
+err_dns4:
+	return false;
+}
+
+bool netconfig_configure(struct netconfig *netconfig,
+				netconfig_notify_func_t notify, void *user_data)
+{
+	netconfig->notify = notify;
+	netconfig->user_data = user_data;
+
+	if (unlikely(!netconfig_ipv4_select_and_install(netconfig)))
+		return false;
+
+	if (unlikely(!netconfig_ipv6_select_and_install(netconfig)))
+		return false;
+
 	return true;
 }
 
diff --git a/src/netconfig.h b/src/netconfig.h
index 2c68cb1c..73e4df8b 100644
--- a/src/netconfig.h
+++ b/src/netconfig.h
@@ -29,9 +29,10 @@ enum netconfig_event {
 typedef void (*netconfig_notify_func_t)(enum netconfig_event event,
 							void *user_data);
 
-bool netconfig_configure(struct netconfig *netconfig,
+bool netconfig_load_settings(struct netconfig *netconfig,
 				const struct l_settings *active_settings,
-				const uint8_t *mac_address,
+				const uint8_t *mac_address);
+bool netconfig_configure(struct netconfig *netconfig,
 				netconfig_notify_func_t notify,
 				void *user_data);
 bool netconfig_reconfigure(struct netconfig *netconfig);
diff --git a/src/p2p.c b/src/p2p.c
index 8170bbe0..3328271b 100644
--- a/src/p2p.c
+++ b/src/p2p.c
@@ -1328,8 +1328,16 @@ static void p2p_start_client_netconfig(struct p2p_device *dev)
 	}
 
 	settings = dev->conn_netconfig_settings ?: p2p_dhcp_settings;
-	netconfig_configure(dev->conn_netconfig, settings, dev->conn_addr,
-				p2p_netconfig_event_handler, dev);
+
+	if (!netconfig_load_settings(dev->conn_netconfig, settings,
+					dev->conn_addr) ||
+			!netconfig_configure(dev->conn_netconfig,
+						p2p_netconfig_event_handler,
+						dev)) {
+		p2p_connect_failed(dev);
+		return;
+	}
+
 	dev->conn_dhcp_timeout = l_timeout_create(p2p_dhcp_timeout_val,
 						p2p_dhcp_timeout, dev,
 						p2p_dhcp_timeout_destroy);
diff --git a/src/station.c b/src/station.c
index d61e775a..f6237ade 100644
--- a/src/station.c
+++ b/src/station.c
@@ -2443,14 +2443,12 @@ static void station_connect_ok(struct station *station)
 
 	network_connected(station->connected_network);
 
-	if (station->netconfig)
-		netconfig_configure(station->netconfig,
-					network_get_settings(
-						station->connected_network),
-					netdev_get_address(station->netdev),
-					station_netconfig_event_handler,
-					station);
-	else
+	if (station->netconfig) {
+		if (L_WARN_ON(!netconfig_configure(station->netconfig,
+						station_netconfig_event_handler,
+						station)))
+			return;
+	} else
 		station_enter_state(station, STATION_STATE_CONNECTED);
 }
 
@@ -2592,6 +2590,12 @@ int __station_connect_network(struct station *station, struct network *network,
 	struct handshake_state *hs;
 	int r;
 
+	if (station->netconfig && !netconfig_load_settings(
+					station->netconfig,
+					network_get_settings(network),
+					netdev_get_address(station->netdev)))
+		return -EINVAL;
+
 	hs = station_handshake_setup(station, network, bss);
 	if (!hs)
 		return -ENOTSUP;
-- 
2.30.2

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/5] netconfig: FILS IP assigment API
  2021-08-27  3:02 [PATCH 1/5] netconfig: Move loading settings to new method, refactor Andrew Zaborowski
@ 2021-08-27  3:02 ` Andrew Zaborowski
  2021-08-27  3:02 ` [PATCH 3/5] station, netdev: Enable FILS IP Address Assignment Andrew Zaborowski
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Andrew Zaborowski @ 2021-08-27  3:02 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 10169 bytes --]

Add two methods that will allow station to implement FILS IP Address
Assigment, one method to decide whether to send the request during
association, and fill in the values to be used in the request IE, and
another to handle the response IE values received from the server and
apply them.  The netconfig->rtm_protocol value used when the address is
assigned this way remains RTPROT_DHCP because from the user's point of
view this is automatic IP assigment by the server, a replacement for
DHCP.
---
 src/netconfig.c | 167 ++++++++++++++++++++++++++++++++++++++++++++----
 src/netconfig.h |   6 ++
 2 files changed, 159 insertions(+), 14 deletions(-)

diff --git a/src/netconfig.c b/src/netconfig.c
index 10c9b90c..6e1e1aa7 100644
--- a/src/netconfig.c
+++ b/src/netconfig.c
@@ -48,6 +48,7 @@
 #include "src/network.h"
 #include "src/resolve.h"
 #include "src/util.h"
+#include "src/ie.h"
 #include "src/netconfig.h"
 
 struct netconfig {
@@ -59,6 +60,7 @@ struct netconfig {
 	struct l_rtnl_address *v4_address;
 	char **dns4_overrides;
 	char **dns6_overrides;
+	struct ie_fils_ip_addr_response_info *fils_override;
 
 	const struct l_settings *active_settings;
 
@@ -164,6 +166,36 @@ static struct netconfig *netconfig_find(uint32_t ifindex)
 			dest[index++] = *p;			\
 	} while (0)						\
 
+static inline char *netconfig_ipv4_to_string(uint32_t addr)
+{
+	struct in_addr in_addr = { .s_addr = addr };
+	char *addr_str = l_malloc(INET_ADDRSTRLEN);
+
+	if (L_WARN_ON(unlikely(!inet_ntop(AF_INET, &in_addr, addr_str,
+						INET_ADDRSTRLEN)))) {
+		l_free(addr_str);
+		return NULL;
+	}
+
+	return addr_str;
+}
+
+static inline char *netconfig_ipv6_to_string(const uint8_t *addr)
+{
+	struct in6_addr in6_addr;
+	char *addr_str = l_malloc(INET6_ADDRSTRLEN);
+
+	memcpy(in6_addr.__in6_u.__u6_addr8, addr, 16);
+
+	if (L_WARN_ON(unlikely(!inet_ntop(AF_INET6, &in6_addr, addr_str,
+						INET6_ADDRSTRLEN)))) {
+		l_free(addr_str);
+		return NULL;
+	}
+
+	return addr_str;
+}
+
 static int netconfig_set_dns(struct netconfig *netconfig)
 {
 	char **dns6_list = NULL;
@@ -173,19 +205,30 @@ static int netconfig_set_dns(struct netconfig *netconfig)
 
 	if (!netconfig->dns4_overrides &&
 			netconfig->rtm_protocol == RTPROT_DHCP) {
-		const struct l_dhcp_lease *lease =
-			l_dhcp_client_get_lease(netconfig->dhcp_client);
-
-		if (lease)
+		const struct l_dhcp_lease *lease;
+
+		if (netconfig->fils_override &&
+				netconfig->fils_override->ipv4_dns) {
+			dns4_list = l_new(char *, 2);
+			dns4_list[0] = netconfig_ipv4_to_string(
+					netconfig->fils_override->ipv4_dns);
+		} else if ((lease = l_dhcp_client_get_lease(
+						netconfig->dhcp_client)))
 			dns4_list = l_dhcp_lease_get_dns(lease);
 	}
 
 	if (!netconfig->dns6_overrides &&
 			netconfig->rtm_v6_protocol == RTPROT_DHCP) {
-		const struct l_dhcp6_lease *lease =
-			l_dhcp6_client_get_lease(netconfig->dhcp6_client);
-
-		if (lease)
+		const struct l_dhcp6_lease *lease;
+
+		if (netconfig->fils_override &&
+				!l_memeqzero(netconfig->fils_override->ipv6_dns,
+						16)) {
+			dns6_list = l_new(char *, 2);
+			dns6_list[0] = netconfig_ipv6_to_string(
+					netconfig->fils_override->ipv6_dns);
+		} else if ((lease = l_dhcp6_client_get_lease(
+						netconfig->dhcp6_client)))
 			dns6_list = l_dhcp6_lease_get_dns(lease);
 	}
 
@@ -335,6 +378,11 @@ static char *netconfig_ipv4_get_gateway(struct netconfig *netconfig)
 		return gateway;
 
 	case RTPROT_DHCP:
+		if (netconfig->fils_override &&
+				netconfig->fils_override->ipv4_gateway)
+			return netconfig_ipv4_to_string(
+					netconfig->fils_override->ipv4_gateway);
+
 		lease = l_dhcp_client_get_lease(netconfig->dhcp_client);
 		if (!lease)
 			return NULL;
@@ -390,7 +438,13 @@ static struct l_rtnl_route *netconfig_get_static6_gateway(
 
 	gateway = l_settings_get_string(netconfig->active_settings,
 						"IPv6", "Gateway");
-	if (!gateway)
+	if (!gateway && netconfig->rtm_v6_protocol == RTPROT_DHCP &&
+			netconfig->fils_override &&
+			!l_memeqzero(netconfig->fils_override->ipv6_gateway,
+					16))
+		gateway = netconfig_ipv6_to_string(
+					netconfig->fils_override->ipv6_gateway);
+	else if (!gateway)
 		return NULL;
 
 	ret = l_rtnl_route_new_gateway(gateway);
@@ -520,7 +574,9 @@ static void netconfig_ifaddr_ipv6_added(struct netconfig *netconfig,
 	l_debug("ifindex %u: ifaddr %s/%u", netconfig->ifindex,
 			ip, ifa->ifa_prefixlen);
 
-	if (netconfig->rtm_v6_protocol != RTPROT_DHCP)
+	if (netconfig->rtm_v6_protocol != RTPROT_DHCP ||
+			(netconfig->fils_override &&
+			 !l_memeqzero(netconfig->fils_override->ipv6_addr, 16)))
 		return;
 
 	inet_pton(AF_INET6, ip, &in6);
@@ -898,7 +954,35 @@ static void netconfig_ipv4_acd_event(enum l_acd_event event, void *user_data)
 
 static bool netconfig_ipv4_select_and_install(struct netconfig *netconfig)
 {
-	if (netconfig->rtm_protocol == RTPROT_STATIC) {
+	bool set_address = (netconfig->rtm_protocol == RTPROT_STATIC);
+
+	if (netconfig->rtm_protocol == RTPROT_DHCP &&
+			netconfig->fils_override &&
+			netconfig->fils_override->ipv4_addr) {
+		L_AUTO_FREE_VAR(char *, addr_str) = netconfig_ipv4_to_string(
+					netconfig->fils_override->ipv4_addr);
+		uint8_t prefix_len = netconfig->fils_override->ipv4_prefix_len;
+
+		if (unlikely(!addr_str))
+			return false;
+
+		if (L_WARN_ON(unlikely(!(netconfig->v4_address =
+						l_rtnl_address_new(addr_str,
+								prefix_len)))))
+			return false;
+
+		l_rtnl_address_set_noprefixroute(netconfig->v4_address, true);
+		set_address = true;
+
+		/*
+		 * TODO: If netconfig->fils_override->ipv4_lifetime is set,
+		 * start a timeout to renew the address using FILS IP Address
+		 * Assignment or perhaps just start the DHCP client at that
+		 * time.
+		 */
+	}
+
+	if (set_address) {
 		char ip[INET6_ADDRSTRLEN];
 
 		if (L_WARN_ON(!netconfig->v4_address ||
@@ -941,6 +1025,7 @@ static bool netconfig_ipv4_select_and_install(struct netconfig *netconfig)
 static bool netconfig_ipv6_select_and_install(struct netconfig *netconfig)
 {
 	struct netdev *netdev = netdev_find(netconfig->ifindex);
+	struct l_rtnl_address *address = NULL;
 
 	if (netconfig->rtm_v6_protocol == RTPROT_UNSPEC) {
 		l_debug("IPV6 configuration disabled");
@@ -949,11 +1034,34 @@ static bool netconfig_ipv6_select_and_install(struct netconfig *netconfig)
 
 	sysfs_write_ipv6_setting(netdev_get_name(netdev), "disable_ipv6", "0");
 
-	if (netconfig->rtm_v6_protocol == RTPROT_STATIC) {
-		struct l_rtnl_address *address =
-			netconfig_get_static6_address(
+	if (netconfig->rtm_v6_protocol == RTPROT_STATIC)
+		address = netconfig_get_static6_address(
 						netconfig->active_settings);
+	else if (netconfig->rtm_v6_protocol == RTPROT_DHCP &&
+			netconfig->fils_override &&
+			!l_memeqzero(netconfig->fils_override->ipv6_addr, 16)) {
+		uint8_t prefix_len = netconfig->fils_override->ipv6_prefix_len;
+		L_AUTO_FREE_VAR(char *, addr_str) = netconfig_ipv6_to_string(
+					netconfig->fils_override->ipv6_addr);
+
+		if (unlikely(!addr_str))
+			return false;
+
+		if (L_WARN_ON(unlikely(!(address = l_rtnl_address_new(addr_str,
+								prefix_len)))))
+			return false;
 
+		l_rtnl_address_set_noprefixroute(address, true);
+
+		/*
+		 * TODO: If netconfig->fils_override->ipv6_lifetime is set,
+		 * start a timeout to renew the address using FILS IP Address
+		 * Assignment or perhaps just start the DHCP client at that
+		 * time.
+		 */
+	}
+
+	if (address) {
 		L_WARN_ON(!(netconfig->addr6_add_cmd_id =
 			l_rtnl_ifaddr_add(rtnl, netconfig->ifindex, address,
 					netconfig_ipv6_ifaddr_add_cmd_cb,
@@ -1184,6 +1292,8 @@ bool netconfig_reset(struct netconfig *netconfig)
 						"disable_ipv6", "1");
 	}
 
+	l_free(l_steal_ptr(netconfig->fils_override));
+
 	return true;
 }
 
@@ -1201,6 +1311,35 @@ char *netconfig_get_dhcp_server_ipv4(struct netconfig *netconfig)
 	return l_dhcp_lease_get_server_id(lease);
 }
 
+bool netconfig_get_fils_ip_req(struct netconfig *netconfig,
+				struct ie_fils_ip_addr_request_info *info)
+{
+	/*
+	 * Fill in the fields used for building the FILS IP Address Assigment
+	 * IE during connection if we're configured to do automatic network
+	 * configuration (usually DHCP).  If we're configured with static
+	 * values return false to mean the IE should not be sent.
+	 */
+	if (netconfig->rtm_protocol != RTPROT_DHCP &&
+			netconfig->rtm_v6_protocol != RTPROT_DHCP)
+		return false;
+
+	memset(info, 0, sizeof(*info));
+	info->ipv4 = (netconfig->rtm_protocol == RTPROT_DHCP);
+	info->ipv6 = (netconfig->rtm_v6_protocol == RTPROT_DHCP);
+	info->dns = (info->ipv4 && !netconfig->dns4_overrides) ||
+		(info->ipv6 && !netconfig->dns6_overrides);
+
+	return true;
+}
+
+void netconfig_handle_fils_ip_resp(struct netconfig *netconfig,
+			const struct ie_fils_ip_addr_response_info *info)
+{
+	l_free(netconfig->fils_override);
+	netconfig->fils_override = l_memdup(info, sizeof(*info));
+}
+
 struct netconfig *netconfig_new(uint32_t ifindex)
 {
 	struct netdev *netdev = netdev_find(ifindex);
diff --git a/src/netconfig.h b/src/netconfig.h
index 73e4df8b..fa46c7c8 100644
--- a/src/netconfig.h
+++ b/src/netconfig.h
@@ -21,6 +21,8 @@
  */
 
 struct netconfig;
+struct ie_fils_ip_addr_request_info;
+struct ie_fils_ip_addr_response_info;
 
 enum netconfig_event {
 	NETCONFIG_EVENT_CONNECTED,
@@ -38,6 +40,10 @@ bool netconfig_configure(struct netconfig *netconfig,
 bool netconfig_reconfigure(struct netconfig *netconfig);
 bool netconfig_reset(struct netconfig *netconfig);
 char *netconfig_get_dhcp_server_ipv4(struct netconfig *netconfig);
+bool netconfig_get_fils_ip_req(struct netconfig *netconfig,
+				struct ie_fils_ip_addr_request_info *info);
+void netconfig_handle_fils_ip_resp(struct netconfig *netconfig,
+			const struct ie_fils_ip_addr_response_info *info);
 
 struct netconfig *netconfig_new(uint32_t ifindex);
 void netconfig_destroy(struct netconfig *netconfig);
-- 
2.30.2

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 3/5] station, netdev: Enable FILS IP Address Assignment
  2021-08-27  3:02 [PATCH 1/5] netconfig: Move loading settings to new method, refactor Andrew Zaborowski
  2021-08-27  3:02 ` [PATCH 2/5] netconfig: FILS IP assigment API Andrew Zaborowski
@ 2021-08-27  3:02 ` Andrew Zaborowski
  2021-08-27  3:02 ` [PATCH 4/5] ie: Extract same-subnet check code to util.h Andrew Zaborowski
  2021-08-27  3:02 ` [PATCH 5/5] netconfig: Apply MACs received in FILS IP Assigment Andrew Zaborowski
  3 siblings, 0 replies; 5+ messages in thread
From: Andrew Zaborowski @ 2021-08-27  3:02 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 4591 bytes --]

Send and receive the FILS IP Address Assignment IEs during association.
As implemented this would work independently of FILS although the only
AP software handling this mechanism without FILS is likely IWD itself.

No support is added for handling the IP assignment information sent from
the server after the initial Association Request/Response frames, i.e.
the information is only used if it is received directly in the
Association Response without the "response pending" bit, otherwise the
DHCP client will be started.
---
 src/handshake.c |  2 ++
 src/handshake.h |  2 ++
 src/netdev.c    | 15 +++++++++++++++
 src/station.c   | 40 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 59 insertions(+)

diff --git a/src/handshake.c b/src/handshake.c
index f36df572..146434c2 100644
--- a/src/handshake.c
+++ b/src/handshake.c
@@ -106,6 +106,8 @@ void handshake_state_free(struct handshake_state *s)
 	l_free(s->supplicant_rsnxe);
 	l_free(s->mde);
 	l_free(s->fte);
+	l_free(s->fils_ip_req_ie);
+	l_free(s->fils_ip_resp_ie);
 
 	if (s->erp_cache)
 		erp_cache_put(s->erp_cache);
diff --git a/src/handshake.h b/src/handshake.h
index 31dce117..f3f6680b 100644
--- a/src/handshake.h
+++ b/src/handshake.h
@@ -140,6 +140,8 @@ struct handshake_state {
 	uint32_t client_ip_addr;
 	uint32_t subnet_mask;
 	uint32_t go_ip_addr;
+	uint8_t *fils_ip_req_ie;
+	uint8_t *fils_ip_resp_ie;
 	void *user_data;
 
 	void (*free)(struct handshake_state *s);
diff --git a/src/netdev.c b/src/netdev.c
index 54856f6a..a5d1b8ed 100644
--- a/src/netdev.c
+++ b/src/netdev.c
@@ -292,6 +292,9 @@ static unsigned int netdev_populate_common_ies(struct netdev *netdev,
 
 	c_iov = iov_ie_append(iov, n_iov, c_iov, hs->vendor_ies);
 
+	if (hs->fils_ip_req_ie)
+		c_iov = iov_ie_append(iov, n_iov, c_iov, hs->fils_ip_req_ie);
+
 	return c_iov;
 }
 
@@ -2186,6 +2189,18 @@ process_resp_ies:
 				qos_set = data;
 				qos_len = ie_tlv_iter_get_length(&iter);
 				break;
+			case IE_TYPE_FILS_IP_ADDRESS:
+				if (netdev->handshake->fils_ip_resp_ie) {
+					l_debug("Duplicate response FILS IP "
+						"Address Assignment IE");
+					l_free(netdev->handshake->
+						fils_ip_resp_ie);
+				}
+
+				netdev->handshake->fils_ip_resp_ie = l_memdup(
+					data - 3,
+					ie_tlv_iter_get_length(&iter) + 3);
+				break;
 			}
 		}
 
diff --git a/src/station.c b/src/station.c
index f6237ade..9f00bfb3 100644
--- a/src/station.c
+++ b/src/station.c
@@ -924,6 +924,7 @@ static struct handshake_state *station_handshake_setup(struct station *station,
 	struct handshake_state *hs;
 	const struct iovec *vendor_ies;
 	size_t iov_elems = 0;
+	struct ie_fils_ip_addr_request_info fils_ip_req;
 
 	hs = netdev_handshake_state_new(station->netdev);
 
@@ -940,6 +941,16 @@ static struct handshake_state *station_handshake_setup(struct station *station,
 	vendor_ies = network_info_get_extra_ies(info, bss, &iov_elems);
 	handshake_state_set_vendor_ies(hs, vendor_ies, iov_elems);
 
+	/*
+	 * It can't hurt to try the FILS IP Address Assigment independent of
+	 * which auth-proto is actually used.
+	 */
+	if (station->netconfig && netconfig_get_fils_ip_req(station->netconfig,
+								&fils_ip_req)) {
+		hs->fils_ip_req_ie = l_malloc(32);
+		ie_build_fils_ip_addr_request(&fils_ip_req, hs->fils_ip_req_ie);
+	}
+
 	return hs;
 
 not_supported:
@@ -2444,6 +2455,35 @@ static void station_connect_ok(struct station *station)
 	network_connected(station->connected_network);
 
 	if (station->netconfig) {
+		if (hs->fils_ip_req_ie && hs->fils_ip_resp_ie) {
+			struct ie_fils_ip_addr_response_info info;
+			struct ie_tlv_iter iter;
+			int r;
+
+			ie_tlv_iter_init(&iter, hs->fils_ip_resp_ie,
+						hs->fils_ip_resp_ie[1] + 2);
+			ie_tlv_iter_next(&iter);
+			r = ie_parse_fils_ip_addr_response(&iter, &info);
+
+			if (r != 0)
+				l_debug("Error parsing the FILS IP Address "
+					"Assignment response: %s (%i)",
+					strerror(-r), -r);
+			else if (info.response_pending &&
+					info.response_timeout)
+				l_debug("FILS IP Address Assignment response "
+					"is pending (unsupported)");
+			else if (info.response_pending)
+				l_debug("FILS IP Address Assignment failed");
+			else {
+				l_debug("FILS IP Address Assignment response "
+					"OK");
+				netconfig_handle_fils_ip_resp(
+							station->netconfig,
+							&info);
+			}
+		}
+
 		if (L_WARN_ON(!netconfig_configure(station->netconfig,
 						station_netconfig_event_handler,
 						station)))
-- 
2.30.2

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 4/5] ie: Extract same-subnet check code to util.h
  2021-08-27  3:02 [PATCH 1/5] netconfig: Move loading settings to new method, refactor Andrew Zaborowski
  2021-08-27  3:02 ` [PATCH 2/5] netconfig: FILS IP assigment API Andrew Zaborowski
  2021-08-27  3:02 ` [PATCH 3/5] station, netdev: Enable FILS IP Address Assignment Andrew Zaborowski
@ 2021-08-27  3:02 ` Andrew Zaborowski
  2021-08-27  3:02 ` [PATCH 5/5] netconfig: Apply MACs received in FILS IP Assigment Andrew Zaborowski
  3 siblings, 0 replies; 5+ messages in thread
From: Andrew Zaborowski @ 2021-08-27  3:02 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 2425 bytes --]

---
 src/ie.c   | 22 +++++++++-------------
 src/util.h | 14 ++++++++++++++
 2 files changed, 23 insertions(+), 13 deletions(-)

diff --git a/src/ie.c b/src/ie.c
index 6f487912..0aa86af6 100644
--- a/src/ie.c
+++ b/src/ie.c
@@ -2309,8 +2309,10 @@ int ie_parse_fils_ip_addr_response(struct ie_tlv_iter *iter,
 		memcpy(info.ipv4_gateway_mac, ptr + 4, 6);
 
 		/* Check gateway is on the same subnet */
-		if (info.ipv4_addr && (ntohl(info.ipv4_addr ^ info.ipv4_gateway) &
-				util_netmask_from_prefix(info.ipv4_prefix_len)))
+		if (info.ipv4_addr &&
+				!util_ip_subnet_match(info.ipv4_prefix_len,
+							&info.ipv4_addr,
+							&info.ipv4_gateway))
 			return -EINVAL;
 	}
 
@@ -2330,17 +2332,11 @@ int ie_parse_fils_ip_addr_response(struct ie_tlv_iter *iter,
 		memcpy(info.ipv6_gateway_mac, ptr + 16, 6);
 
 		/* Check gateway is on the same subnet */
-		if (!l_memeqzero(info.ipv6_addr, 12)) {
-			int n = info.ipv6_prefix_len / 8;
-			uint8_t mask = (1 << (info.ipv6_prefix_len & 7)) - 1;
-
-			if (n && memcmp(info.ipv6_addr, info.ipv6_gateway, n))
-				return -EINVAL;
-
-			if (mask && ((info.ipv6_addr[n] ^
-						info.ipv6_gateway[n]) & mask))
-				return -EINVAL;
-		}
+		if (!l_memeqzero(info.ipv6_addr, 16) &&
+				!util_ip_subnet_match(info.ipv6_prefix_len,
+							info.ipv6_addr,
+							info.ipv6_gateway))
+			return -EINVAL;
 	}
 
 	if (*resp_ctrl & IE_FILS_IP_ADDR_RESP_CTRL_IPV4_LIFETIME_INCLUDED)
diff --git a/src/util.h b/src/util.h
index 1604a372..ae640698 100644
--- a/src/util.h
+++ b/src/util.h
@@ -82,9 +82,23 @@ static inline uint32_t util_secure_fill_with_msb(uint32_t val)
 bool util_ip_prefix_tohl(const char *ip, uint8_t *prefix, uint32_t *start_out,
 				uint32_t *end_out, uint32_t *mask_out);
 
+/* Host byte-order IPv4 netmask */
 static inline uint32_t util_netmask_from_prefix(uint8_t prefix_len)
 {
 	return ~((1ull << (32 - prefix_len)) - 1);
 }
 
+/* Expects network byte-order (big-endian) addresses */
+static inline bool util_ip_subnet_match(uint8_t prefix_len,
+					const void *addr1, const void *addr2)
+{
+	const uint8_t *u8_1 = addr1;
+	const uint8_t *u8_2 = addr2;
+	uint8_t pref_bytes = prefix_len / 8;
+
+	return (!pref_bytes || !memcmp(u8_1, u8_2, pref_bytes)) &&
+		!((u8_1[pref_bytes] ^ u8_2[pref_bytes]) &
+		  ~((1u << (8 - (prefix_len % 8))) - 1));
+}
+
 #endif /* __UTIL_H */
-- 
2.30.2

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 5/5] netconfig: Apply MACs received in FILS IP Assigment
  2021-08-27  3:02 [PATCH 1/5] netconfig: Move loading settings to new method, refactor Andrew Zaborowski
                   ` (2 preceding siblings ...)
  2021-08-27  3:02 ` [PATCH 4/5] ie: Extract same-subnet check code to util.h Andrew Zaborowski
@ 2021-08-27  3:02 ` Andrew Zaborowski
  3 siblings, 0 replies; 5+ messages in thread
From: Andrew Zaborowski @ 2021-08-27  3:02 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 8481 bytes --]

Use the MAC addresses for the gateways and DNS servers received in the
FILS IP Assigment IE together with the gateway IP and DNS server IP.
Commit the IP to MAC mappings directly to the ARP/NDP tables so that the
network stack can skip sending the corresponding queries over the air.
---
 src/netconfig.c | 123 +++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 102 insertions(+), 21 deletions(-)

diff --git a/src/netconfig.c b/src/netconfig.c
index 6e1e1aa7..69aded52 100644
--- a/src/netconfig.c
+++ b/src/netconfig.c
@@ -196,22 +196,40 @@ static inline char *netconfig_ipv6_to_string(const uint8_t *addr)
 	return addr_str;
 }
 
+static void netconfig_set_neighbor_entry_cb(int error,
+						uint16_t type, const void *data,
+						uint32_t len, void *user_data)
+{
+	if (error)
+		l_error("l_rtnl_neighbor_set_hwaddr failed: %s (%i)",
+			strerror(-error), error);
+}
+
 static int netconfig_set_dns(struct netconfig *netconfig)
 {
 	char **dns6_list = NULL;
 	char **dns4_list = NULL;
 	unsigned int n_entries = 0;
 	char **dns_list;
+	const uint8_t *fils_dns4_mac = NULL;
+	const uint8_t *fils_dns6_mac = NULL;
+	const struct ie_fils_ip_addr_response_info *fils =
+		netconfig->fils_override;
 
 	if (!netconfig->dns4_overrides &&
 			netconfig->rtm_protocol == RTPROT_DHCP) {
 		const struct l_dhcp_lease *lease;
 
-		if (netconfig->fils_override &&
-				netconfig->fils_override->ipv4_dns) {
+		if (fils && fils->ipv4_dns) {
 			dns4_list = l_new(char *, 2);
-			dns4_list[0] = netconfig_ipv4_to_string(
-					netconfig->fils_override->ipv4_dns);
+			dns4_list[0] = netconfig_ipv4_to_string(fils->ipv4_dns);
+
+			if (!l_memeqzero(fils->ipv4_dns_mac, 6) &&
+					util_ip_subnet_match(
+							fils->ipv4_prefix_len,
+							&fils->ipv4_addr,
+							&fils->ipv4_dns))
+				fils_dns4_mac = fils->ipv4_dns_mac;
 		} else if ((lease = l_dhcp_client_get_lease(
 						netconfig->dhcp_client)))
 			dns4_list = l_dhcp_lease_get_dns(lease);
@@ -221,12 +239,21 @@ static int netconfig_set_dns(struct netconfig *netconfig)
 			netconfig->rtm_v6_protocol == RTPROT_DHCP) {
 		const struct l_dhcp6_lease *lease;
 
-		if (netconfig->fils_override &&
-				!l_memeqzero(netconfig->fils_override->ipv6_dns,
+		if (fils && !l_memeqzero(fils->ipv6_dns,
 						16)) {
 			dns6_list = l_new(char *, 2);
-			dns6_list[0] = netconfig_ipv6_to_string(
-					netconfig->fils_override->ipv6_dns);
+			dns6_list[0] = netconfig_ipv6_to_string(fils->ipv6_dns);
+
+			/*
+			 * TODO: perhaps check that the IP is on the local
+			 * subnet.
+			 */
+			if (!l_memeqzero(fils->ipv6_dns_mac, 6) &&
+					util_ip_subnet_match(
+							fils->ipv6_prefix_len,
+							fils->ipv6_addr,
+							fils->ipv6_dns))
+				fils_dns6_mac = fils->ipv6_dns_mac;
 		} else if ((lease = l_dhcp6_client_get_lease(
 						netconfig->dhcp6_client)))
 			dns6_list = l_dhcp6_lease_get_dns(lease);
@@ -242,15 +269,28 @@ static int netconfig_set_dns(struct netconfig *netconfig)
 
 	APPEND_STRDUPV(dns_list, n_entries, netconfig->dns4_overrides);
 	APPENDV(dns_list, n_entries, dns4_list);
-	/* Contents now belong to ret, so not l_strfreev */
-	l_free(dns4_list);
 	APPEND_STRDUPV(dns_list, n_entries, netconfig->dns6_overrides);
 	APPENDV(dns_list, n_entries, dns6_list);
-	/* Contents now belong to ret, so not l_strfreev */
-	l_free(dns6_list);
-
 	resolve_set_dns(netconfig->resolve, dns_list);
+
+	if (fils_dns4_mac && !l_rtnl_neighbor_set_hwaddr(rtnl,
+					netconfig->ifindex, AF_INET,
+					&fils->ipv4_dns, fils_dns4_mac, 6,
+					netconfig_set_neighbor_entry_cb, NULL,
+					NULL))
+		l_debug("l_rtnl_neighbor_set_hwaddr failed");
+
+	if (fils_dns6_mac && !l_rtnl_neighbor_set_hwaddr(rtnl,
+					netconfig->ifindex, AF_INET6,
+					fils->ipv6_dns, fils_dns6_mac, 6,
+					netconfig_set_neighbor_entry_cb, NULL,
+					NULL))
+		l_debug("l_rtnl_neighbor_set_hwaddr failed");
+
 	l_strv_free(dns_list);
+	/* Contents belonged to dns_list, so not l_strfreev */
+	l_free(dns4_list);
+	l_free(dns6_list);
 	return 0;
 }
 
@@ -361,7 +401,8 @@ static struct l_rtnl_address *netconfig_get_static4_address(
 	return ifaddr;
 }
 
-static char *netconfig_ipv4_get_gateway(struct netconfig *netconfig)
+static char *netconfig_ipv4_get_gateway(struct netconfig *netconfig,
+					const uint8_t **out_mac)
 {
 	const struct l_dhcp_lease *lease;
 	char *gateway;
@@ -379,10 +420,18 @@ static char *netconfig_ipv4_get_gateway(struct netconfig *netconfig)
 
 	case RTPROT_DHCP:
 		if (netconfig->fils_override &&
-				netconfig->fils_override->ipv4_gateway)
-			return netconfig_ipv4_to_string(
+				netconfig->fils_override->ipv4_gateway) {
+			gateway = netconfig_ipv4_to_string(
 					netconfig->fils_override->ipv4_gateway);
 
+			if (gateway && !l_memeqzero(netconfig->fils_override->
+							ipv4_gateway_mac, 6))
+				*out_mac = netconfig->fils_override->
+					ipv4_gateway_mac;
+
+			return gateway;
+		}
+
 		lease = l_dhcp_client_get_lease(netconfig->dhcp_client);
 		if (!lease)
 			return NULL;
@@ -431,7 +480,8 @@ no_prefix_len:
 }
 
 static struct l_rtnl_route *netconfig_get_static6_gateway(
-						struct netconfig *netconfig)
+						struct netconfig *netconfig,
+						const uint8_t **out_mac)
 {
 	L_AUTO_FREE_VAR(char *, gateway);
 	struct l_rtnl_route *ret;
@@ -441,10 +491,13 @@ static struct l_rtnl_route *netconfig_get_static6_gateway(
 	if (!gateway && netconfig->rtm_v6_protocol == RTPROT_DHCP &&
 			netconfig->fils_override &&
 			!l_memeqzero(netconfig->fils_override->ipv6_gateway,
-					16))
+					16)) {
 		gateway = netconfig_ipv6_to_string(
 					netconfig->fils_override->ipv6_gateway);
-	else if (!gateway)
+
+		if (!l_memeqzero(netconfig->fils_override->ipv6_gateway_mac, 6))
+			*out_mac = netconfig->fils_override->ipv6_gateway_mac;
+	} else if (!gateway)
 		return NULL;
 
 	ret = l_rtnl_route_new_gateway(gateway);
@@ -678,6 +731,7 @@ static void netconfig_route_add_cmd_cb(int error, uint16_t type,
 static bool netconfig_ipv4_routes_install(struct netconfig *netconfig)
 {
 	L_AUTO_FREE_VAR(char *, gateway) = NULL;
+	const uint8_t *gateway_mac = NULL;
 	struct in_addr in_addr;
 	char ip[INET_ADDRSTRLEN];
 	char network[INET_ADDRSTRLEN];
@@ -704,7 +758,7 @@ static bool netconfig_ipv4_routes_install(struct netconfig *netconfig)
 		return false;
 	}
 
-	gateway = netconfig_ipv4_get_gateway(netconfig);
+	gateway = netconfig_ipv4_get_gateway(netconfig, &gateway_mac);
 	if (!gateway) {
 		l_debug("No gateway obtained from %s.",
 				netconfig->rtm_protocol == RTPROT_STATIC ?
@@ -732,6 +786,24 @@ static bool netconfig_ipv4_routes_install(struct netconfig *netconfig)
 		return false;
 	}
 
+	if (gateway_mac) {
+		/*
+		 * Attempt to use the gateway MAC address 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.
+		 */
+		if (!l_rtnl_neighbor_set_hwaddr(rtnl, netconfig->ifindex,
+					AF_INET,
+					&netconfig->fils_override->ipv4_gateway,
+					gateway_mac, 6,
+					netconfig_set_neighbor_entry_cb, NULL,
+					NULL))
+			l_debug("l_rtnl_neighbor_set_hwaddr failed");
+	}
+
 	return true;
 }
 
@@ -764,6 +836,7 @@ static void netconfig_ipv6_ifaddr_add_cmd_cb(int error, uint16_t type,
 {
 	struct netconfig *netconfig = user_data;
 	struct l_rtnl_route *gateway;
+	const uint8_t *gateway_mac = NULL;
 
 	netconfig->addr6_add_cmd_id = 0;
 
@@ -773,13 +846,21 @@ static void netconfig_ipv6_ifaddr_add_cmd_cb(int error, uint16_t type,
 		return;
 	}
 
-	gateway = netconfig_get_static6_gateway(netconfig);
+	gateway = netconfig_get_static6_gateway(netconfig, &gateway_mac);
 	if (gateway) {
 		L_WARN_ON(!l_rtnl_route_add(rtnl, netconfig->ifindex,
 						gateway,
 						netconfig_route_generic_cb,
 						netconfig, NULL));
 		l_rtnl_route_free(gateway);
+
+		if (gateway_mac && !l_rtnl_neighbor_set_hwaddr(rtnl,
+					netconfig->ifindex, AF_INET6,
+					netconfig->fils_override->ipv6_gateway,
+					gateway_mac, 6,
+					netconfig_set_neighbor_entry_cb, NULL,
+					NULL))
+			l_debug("l_rtnl_neighbor_set_hwaddr failed");
 	}
 
 	netconfig_set_dns(netconfig);
-- 
2.30.2

^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2021-08-27  3:02 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-27  3:02 [PATCH 1/5] netconfig: Move loading settings to new method, refactor Andrew Zaborowski
2021-08-27  3:02 ` [PATCH 2/5] netconfig: FILS IP assigment API Andrew Zaborowski
2021-08-27  3:02 ` [PATCH 3/5] station, netdev: Enable FILS IP Address Assignment Andrew Zaborowski
2021-08-27  3:02 ` [PATCH 4/5] ie: Extract same-subnet check code to util.h Andrew Zaborowski
2021-08-27  3:02 ` [PATCH 5/5] netconfig: Apply MACs received in FILS IP Assigment Andrew Zaborowski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).