diff --git a/Makefile.am b/Makefile.am index 31b7e24b..bc26d052 100644 --- a/Makefile.am +++ b/Makefile.am @@ -237,7 +237,8 @@ src_iwd_SOURCES = src/main.c linux/nl80211.h src/iwd.h src/missing.h \ src/anqp.h src/anqp.c \ src/anqputil.h src/anqputil.c \ src/netconfig.h src/netconfig.c\ - src/resolve.h src/resolve.c\ + src/netconfig-commit.c \ + src/resolve.h src/resolve.c \ src/hotspot.c \ src/p2p.h src/p2p.c \ src/p2putil.h src/p2putil.c \ diff --git a/src/netconfig-commit.c b/src/netconfig-commit.c new file mode 100644 index 00000000..48ebe847 --- /dev/null +++ b/src/netconfig-commit.c @@ -0,0 +1,203 @@ +/* + * + * Wireless daemon for Linux + * + * Copyright (C) 2022 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include + +#include "ell/useful.h" +#include "src/iwd.h" +#include "src/common.h" +#include "src/util.h" +#include "src/netdev.h" +#include "src/ie.h" +#include "src/resolve.h" +#include "src/netconfig.h" + +struct netconfig_commit_ops { + bool (*init_data)(struct netconfig *netconfig); + void (*free_data)(struct netconfig *netconfig, const char *reasonstr); + void (*commit)(struct netconfig *netconfig, uint8_t family, + enum l_netconfig_event event); +}; + +static struct l_netlink *rtnl; + +static void netconfig_rtnl_commit(struct netconfig *netconfig, uint8_t family, + enum l_netconfig_event event); + +/* Default backend */ +static struct netconfig_commit_ops netconfig_rtnl_ops = { + .commit = netconfig_rtnl_commit, +}; + +/* Same backend for all netconfig objects */ +static const struct netconfig_commit_ops *commit_ops = &netconfig_rtnl_ops; + +static struct l_queue *netconfig_list; + +void netconfig_commit_init(struct netconfig *netconfig) +{ + if (!rtnl) + rtnl = l_rtnl_get(); + + if (!netconfig_list) + netconfig_list = l_queue_new(); + + l_queue_push_tail(netconfig_list, netconfig); + + L_WARN_ON(netconfig->commit_data); + + if (commit_ops->init_data) + commit_ops->init_data(netconfig); +} + +void netconfig_commit_free(struct netconfig *netconfig, const char *reasonstr) +{ + if (commit_ops->free_data) + commit_ops->free_data(netconfig, reasonstr); + + L_WARN_ON(!l_queue_remove(netconfig_list, netconfig)); + + if (l_queue_isempty(netconfig_list)) + l_queue_destroy(l_steal_ptr(netconfig_list), NULL); +} + +void netconfig_commit(struct netconfig *netconfig, uint8_t family, + enum l_netconfig_event event) +{ + commit_ops->commit(netconfig, family, event); + + if (event == L_NETCONFIG_EVENT_CONFIGURE) { + /* + * Done here instead of in ops->commit because the MACs are + * not considered part of the network configuration + * (particularly Network Manager's "level 3 config" or l3cfg) + * so we can handle this ourselves independent of the backend. + */ + if (family == AF_INET && + !netconfig->static_config[INDEX_FOR_AF(family)]) + netconfig_dhcp_gateway_to_arp(netconfig); + } +} + +/* + * Called by all backends when netconfig_commit finishes, synchronously or + * asynchronously. + */ +static void netconfig_commit_done(struct netconfig *netconfig, uint8_t family, + enum l_netconfig_event event, + bool success) +{ +} + +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); +} + +void netconfig_dhcp_gateway_to_arp(struct netconfig *netconfig) +{ + struct l_dhcp_client *dhcp = l_netconfig_get_dhcp_client(netconfig->nc); + const struct l_dhcp_lease *lease; + _auto_(l_free) char *server_id = NULL; + _auto_(l_free) char *gw = NULL; + const uint8_t *server_mac; + struct in_addr in_gw; + uint32_t ifindex = netdev_get_ifindex(netconfig->netdev); + + /* Can only do this for DHCP in certain network setups */ + if (netconfig->static_config[INDEX_FOR_AF(AF_INET)] || + netconfig->fils_override) + return; + + lease = l_dhcp_client_get_lease(dhcp); + if (!lease) + return; + + server_id = l_dhcp_lease_get_server_id(lease); + gw = l_dhcp_lease_get_gateway(lease); + server_mac = l_dhcp_lease_get_server_mac(lease); + + if (!gw || strcmp(server_id, gw) || !server_mac) + return; + + l_debug("Gateway MAC is known, setting into ARP cache"); + in_gw.s_addr = l_dhcp_lease_get_gateway_u32(lease); + + if (!l_rtnl_neighbor_set_hwaddr(rtnl, ifindex, AF_INET, + &in_gw, server_mac, ETH_ALEN, + netconfig_set_neighbor_entry_cb, NULL, + NULL)) + l_debug("l_rtnl_neighbor_set_hwaddr failed"); +} + +static void netconfig_dns_list_update(struct netconfig *netconfig) +{ + _auto_(l_strv_free) char **dns_list = + l_netconfig_get_dns_list(netconfig->nc); + + if (netconfig->resolve && dns_list) + resolve_set_dns(netconfig->resolve, dns_list); +} + +static void netconfig_domains_update(struct netconfig *netconfig) +{ + _auto_(l_strv_free) char **domains = + l_netconfig_get_domain_names(netconfig->nc); + + if (netconfig->resolve && domains) + resolve_set_domains(netconfig->resolve, domains); +} + +static void netconfig_rtnl_commit(struct netconfig *netconfig, uint8_t family, + enum l_netconfig_event event) +{ + l_netconfig_apply_rtnl(netconfig->nc); + + /* TODO: cache values and skip updates if unchanged */ + netconfig_dns_list_update(netconfig); + netconfig_domains_update(netconfig); + + if (event == L_NETCONFIG_EVENT_CONFIGURE && family == AF_INET) + /* + * netconfig->mdns is currently only loaded in + * netconfig_load_settings() so we can set it once on + * the CONFIGURE event. + */ + resolve_set_mdns(netconfig->resolve, netconfig->mdns); + + if (event == L_NETCONFIG_EVENT_UNCONFIGURE && family == AF_INET) + resolve_revert(netconfig->resolve); + + netconfig_commit_done(netconfig, family, event, true); +} diff --git a/src/netconfig.c b/src/netconfig.c index 74eaca16..5b7a21ee 100644 --- a/src/netconfig.c +++ b/src/netconfig.c @@ -27,9 +27,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -52,30 +50,6 @@ #include "src/netconfig.h" #include "src/sysfs.h" -struct netconfig { - struct l_netconfig *nc; - struct netdev *netdev; - - char *mdns; - struct ie_fils_ip_addr_response_info *fils_override; - bool enabled[2]; - bool static_config[2]; - bool gateway_overridden[2]; - bool dns_overridden[2]; - - const struct l_settings *active_settings; - - netconfig_notify_func_t notify; - void *user_data; - - struct resolve *resolve; -}; - -/* 0 for AF_INET, 1 for AF_INET6 */ -#define INDEX_FOR_AF(af) ((af) != AF_INET) - -static struct l_netlink *rtnl; - /* * Routing priority offset, configurable in main.conf. The route with lower * priority offset is preferred. @@ -116,7 +90,7 @@ static void netconfig_free(void *data) l_free(netconfig); } -static bool netconfig_use_fils_addr(struct netconfig *netconfig, int af) +bool netconfig_use_fils_addr(struct netconfig *netconfig, int af) { if (!netconfig->enabled[INDEX_FOR_AF(af)]) return false; @@ -133,15 +107,6 @@ static bool netconfig_use_fils_addr(struct netconfig *netconfig, int af) return !l_memeqzero(netconfig->fils_override->ipv6_addr, 16); } -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 struct l_rtnl_address *netconfig_get_static4_address( const struct l_settings *active_settings) { @@ -240,41 +205,6 @@ no_prefix_len: return l_steal_ptr(ret); } -static void netconfig_gateway_to_arp(struct netconfig *netconfig) -{ - struct l_dhcp_client *dhcp = l_netconfig_get_dhcp_client(netconfig->nc); - const struct l_dhcp_lease *lease; - _auto_(l_free) char *server_id = NULL; - _auto_(l_free) char *gw = NULL; - const uint8_t *server_mac; - struct in_addr in_gw; - - /* Can only do this for DHCP in certain network setups */ - if (netconfig->static_config[INDEX_FOR_AF(AF_INET)] || - netconfig->fils_override) - return; - - lease = l_dhcp_client_get_lease(dhcp); - if (!lease) - return; - - server_id = l_dhcp_lease_get_server_id(lease); - gw = l_dhcp_lease_get_gateway(lease); - server_mac = l_dhcp_lease_get_server_mac(lease); - - if (!gw || strcmp(server_id, gw) || !server_mac) - return; - - l_debug("Gateway MAC is known, setting into ARP cache"); - in_gw.s_addr = l_dhcp_lease_get_gateway_u32(lease); - - if (!l_rtnl_neighbor_set_hwaddr(rtnl, netconfig->ifindex, AF_INET, - &in_gw, server_mac, ETH_ALEN, - netconfig_set_neighbor_entry_cb, NULL, - NULL)) - l_debug("l_rtnl_neighbor_set_hwaddr failed"); -} - static bool netconfig_load_dns(struct netconfig *netconfig, const struct l_settings *active_settings, const char *group_name, uint8_t family) @@ -501,7 +431,7 @@ bool netconfig_reconfigure(struct netconfig *netconfig, bool set_arp_gw) * to alleviate this */ if (set_arp_gw) - netconfig_gateway_to_arp(netconfig); + netconfig_dhcp_gateway_to_arp(netconfig); if (!netconfig->static_config[INDEX_FOR_AF(AF_INET)]) { /* TODO l_dhcp_client sending a DHCP inform request */ @@ -584,6 +514,8 @@ struct netconfig *netconfig_new(uint32_t ifindex) netconfig->netdev = netdev; netconfig->resolve = resolve_new(ifindex); + netconfig_commit_init(netconfig); + debug_level = getenv("IWD_DHCP_DEBUG"); if (debug_level != NULL) { if (!strcmp("debug", debug_level)) @@ -618,6 +550,7 @@ void netconfig_destroy(struct netconfig *netconfig) l_debug(""); netconfig_reset(netconfig); + netconfig_commit_free(netconfig, "aborted"); resolve_free(netconfig->resolve); netconfig_free(netconfig); } diff --git a/src/netconfig.h b/src/netconfig.h index c9ac6f8f..9f4f3b77 100644 --- a/src/netconfig.h +++ b/src/netconfig.h @@ -20,6 +20,7 @@ * */ +struct netdev; struct netconfig; struct ie_fils_ip_addr_request_info; struct ie_fils_ip_addr_response_info; @@ -31,6 +32,30 @@ enum netconfig_event { typedef void (*netconfig_notify_func_t)(enum netconfig_event event, void *user_data); +struct netconfig { + struct l_netconfig *nc; + struct netdev *netdev; + + char *mdns; + struct ie_fils_ip_addr_response_info *fils_override; + bool enabled[2]; + bool static_config[2]; + bool gateway_overridden[2]; + bool dns_overridden[2]; + + const struct l_settings *active_settings; + + netconfig_notify_func_t notify; + void *user_data; + + struct resolve *resolve; + + void *commit_data; +}; + +/* 0 for AF_INET, 1 for AF_INET6 */ +#define INDEX_FOR_AF(af) ((af) != AF_INET) + bool netconfig_load_settings(struct netconfig *netconfig, const struct l_settings *active_settings); bool netconfig_configure(struct netconfig *netconfig, @@ -43,8 +68,16 @@ 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); +bool netconfig_use_fils_addr(struct netconfig *netconfig, int af); struct netconfig *netconfig_new(uint32_t ifindex); void netconfig_destroy(struct netconfig *netconfig); bool netconfig_enabled(void); + +void netconfig_commit_init(struct netconfig *netconfig); +void netconfig_commit_free(struct netconfig *netconfig, const char *reasonstr); +void netconfig_commit(struct netconfig *netconfig, uint8_t family, + enum l_netconfig_event event); + +void netconfig_dhcp_gateway_to_arp(struct netconfig *netconfig);