netconfig: Add netconfig-commit API

Add netconfig-commit.c whose main method, netconfig_commit actually sets
the configuration obtained by l_netconfig to the system netdev,
specifically it sets local addresses on the interface, adds routes to the
routing table, sets DNS related data and may add entries to the neighbor
cache.  netconfig-commit.c uses a backend-ops type structure to allow
for switching backends.  In this commit there's only a default backend
that uses l_netconfig_rtnl_apply() and a struct resolve object to write
the configuration.

netconfig_gateway_to_arp is moved from netconfig.c to netconfig-commit.c
(and renamed.)  The struct netconfig definition is moved to netconfig.h
so that both files can access the settings stored in the struct.
This commit is contained in:
Andrew Zaborowski 2022-08-29 19:35:57 +02:00 committed by Denis Kenzior
parent a8b1139dcb
commit b79c7d49cd
4 changed files with 243 additions and 73 deletions

View File

@ -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 \

203
src/netconfig-commit.c Normal file
View File

@ -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 <config.h>
#endif
#include <arpa/inet.h>
#include <netinet/if_ether.h>
#include <linux/icmpv6.h>
#include <ell/ell.h>
#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);
}

View File

@ -27,9 +27,7 @@
#include <errno.h>
#include <arpa/inet.h>
#include <net/if_arp.h>
#include <netinet/if_ether.h>
#include <netinet/in.h>
#include <linux/rtnetlink.h>
#include <limits.h>
#include <string.h>
#include <fcntl.h>
@ -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);
}

View File

@ -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);