NetworkManager/src/core/nm-ip-config.c
Thomas Haller 615221a99c format: reformat source tree with clang-format 13.0
We use clang-format for automatic formatting of our source files.
Since clang-format is actively maintained software, the actual
formatting depends on the used version of clang-format. That is
unfortunate and painful, but really unavoidable unless clang-format
would be strictly bug-compatible.

So the version that we must use is from the current Fedora release, which
is also tested by our gitlab-ci. Previously, we were using Fedora 34 with
clang-tools-extra-12.0.1-1.fc34.x86_64.

As Fedora 35 comes along, we need to update our formatting as Fedora 35
comes with version "13.0.0~rc1-1.fc35".
An alternative would be to freeze on version 12, but that has different
problems (like, it's cumbersome to rebuild clang 12 on Fedora 35 and it
would be cumbersome for our developers which are on Fedora 35 to use a
clang that they cannot easily install).

The (differently painful) solution is to reformat from time to time, as we
switch to a new Fedora (and thus clang) version.
Usually we would expect that such a reformatting brings minor changes.
But this time, the changes are huge. That is mentioned in the release
notes [1] as

  Makes PointerAligment: Right working with AlignConsecutiveDeclarations. (Fixes https://llvm.org/PR27353)

[1] https://releases.llvm.org/13.0.0/tools/clang/docs/ReleaseNotes.html#clang-format
2021-11-29 09:31:09 +00:00

904 lines
38 KiB
C

/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2005 - 2017 Red Hat, Inc.
* Copyright (C) 2006 - 2008 Novell, Inc.
*/
#include "src/core/nm-default-daemon.h"
#include "nm-ip-config.h"
#include <linux/rtnetlink.h>
#include "nm-l3cfg.h"
#include "NetworkManagerUtils.h"
/*****************************************************************************/
GType nm_ip4_config_get_type(void);
GType nm_ip6_config_get_type(void);
/*****************************************************************************/
#define NM_IP_CONFIG_ADDRESS_DATA "address-data"
#define NM_IP_CONFIG_DNS_OPTIONS "dns-options"
#define NM_IP_CONFIG_DNS_PRIORITY "dns-priority"
#define NM_IP_CONFIG_DOMAINS "domains"
#define NM_IP_CONFIG_GATEWAY "gateway"
#define NM_IP_CONFIG_ROUTE_DATA "route-data"
#define NM_IP_CONFIG_SEARCHES "searches"
/*****************************************************************************/
typedef struct _NMIPConfigPrivate NMIPConfigPrivate;
NM_GOBJECT_PROPERTIES_DEFINE_FULL(_ip,
NMIPConfig,
PROP_IP_L3CFG,
PROP_IP_ADDRESS_DATA,
PROP_IP_GATEWAY,
PROP_IP_ROUTE_DATA,
PROP_IP_DOMAINS,
PROP_IP_SEARCHES,
PROP_IP_DNS_PRIORITY,
PROP_IP_DNS_OPTIONS, );
G_DEFINE_ABSTRACT_TYPE(NMIPConfig, nm_ip_config, NM_TYPE_DBUS_OBJECT)
#define NM_IP_CONFIG_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMIPConfig, NM_IS_IP_CONFIG)
/*****************************************************************************/
static void _handle_platform_change(NMIPConfig *self, guint32 obj_type_flags, gboolean is_init);
static void _handle_l3cd_changed(NMIPConfig *self, const NML3ConfigData *l3cd);
/*****************************************************************************/
static void
_value_set_variant_as(GValue *value, const char *const *strv, guint len)
{
if (len > 0) {
nm_assert(strv && strv[0]);
g_value_set_variant(value, g_variant_new_strv((const char *const *) strv, len));
} else
g_value_set_variant(value, nm_g_variant_singleton_as());
}
/*****************************************************************************/
static void
_l3cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMIPConfig *self)
{
switch (notify_data->notify_type) {
case NM_L3_CONFIG_NOTIFY_TYPE_L3CD_CHANGED:
if (notify_data->l3cd_changed.commited)
_handle_l3cd_changed(self, notify_data->l3cd_changed.l3cd_new);
break;
case NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE:
_handle_platform_change(self, notify_data->platform_change_on_idle.obj_type_flags, FALSE);
break;
default:
break;
}
}
/*****************************************************************************/
static void
get_property_ip(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
NMIPConfig *self = NM_IP_CONFIG(object);
NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE(self);
const int addr_family = nm_ip_config_get_addr_family(self);
char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN];
const char *const *strv;
guint len;
int v_i;
switch (prop_id) {
case PROP_IP_ADDRESS_DATA:
g_value_set_variant(value, priv->v_address_data);
break;
case PROP_IP_GATEWAY:
if (priv->v_gateway.best_default_route) {
const NMIPAddr *gateway;
gateway = nm_platform_ip_route_get_gateway(
addr_family,
NMP_OBJECT_CAST_IP_ROUTE(priv->v_gateway.best_default_route));
g_value_set_variant(
value,
g_variant_new_string(nm_utils_inet_ntop(addr_family, gateway, sbuf_addr)));
} else
g_value_set_variant(value, nm_g_variant_singleton_s_empty());
break;
case PROP_IP_ROUTE_DATA:
g_value_set_variant(value, priv->v_route_data);
break;
case PROP_IP_DOMAINS:
strv = nm_l3_config_data_get_domains(priv->l3cd, addr_family, &len);
_value_set_variant_as(value, strv, len);
break;
case PROP_IP_SEARCHES:
strv = nm_l3_config_data_get_searches(priv->l3cd, addr_family, &len);
_value_set_variant_as(value, strv, len);
break;
case PROP_IP_DNS_PRIORITY:
v_i = nm_l3_config_data_get_dns_priority_or_default(priv->l3cd, addr_family);
g_value_set_variant(value,
(v_i == 0) ? nm_g_variant_singleton_i_0() : g_variant_new_int32(v_i));
break;
case PROP_IP_DNS_OPTIONS:
strv = nm_l3_config_data_get_dns_options(priv->l3cd, addr_family, &len);
_value_set_variant_as(value, strv, len);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}
static void
set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
NMIPConfig *self = NM_IP_CONFIG(object);
NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE(self);
gpointer ptr;
switch (prop_id) {
case PROP_IP_L3CFG:
/* construct-only */
ptr = g_value_get_pointer(value);
nm_assert(NM_IS_L3CFG(ptr));
priv->l3cfg = g_object_ref(ptr);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}
/*****************************************************************************/
static void
nm_ip_config_init(NMIPConfig *self)
{}
NMIPConfig *
nm_ip_config_new(int addr_family, NML3Cfg *l3cfg)
{
nm_assert_addr_family(addr_family);
nm_assert(NM_L3CFG(l3cfg));
return g_object_new(NM_IS_IPv4(addr_family) ? nm_ip4_config_get_type()
: nm_ip6_config_get_type(),
NM_IP_CONFIG_L3CFG,
l3cfg,
NULL);
}
static void
constructed(GObject *object)
{
NMIPConfig *self = NM_IP_CONFIG(object);
NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE(self);
priv->l3cfg_notify_id =
g_signal_connect(priv->l3cfg, NM_L3CFG_SIGNAL_NOTIFY, G_CALLBACK(_l3cfg_notify_cb), self);
priv->l3cd = nm_l3_config_data_ref(nm_l3cfg_get_combined_l3cd(priv->l3cfg, TRUE));
_handle_platform_change(self, ~((guint32) 0u), TRUE);
G_OBJECT_CLASS(nm_ip_config_parent_class)->constructed(object);
}
void
nm_ip_config_take_and_unexport_on_idle(NMIPConfig *self_take)
{
if (self_take)
nm_dbus_object_unexport_on_idle(g_steal_pointer(&self_take));
}
static void
finalize(GObject *object)
{
NMIPConfig *self = NM_IP_CONFIG(object);
NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE(self);
nm_clear_g_signal_handler(priv->l3cfg, &priv->l3cfg_notify_id);
g_object_unref(priv->l3cfg);
nm_g_variant_unref(priv->v_address_data);
nm_g_variant_unref(priv->v_addresses);
nm_g_variant_unref(priv->v_route_data);
nm_g_variant_unref(priv->v_routes);
nmp_object_unref(priv->v_gateway.best_default_route);
nm_l3_config_data_unref(priv->l3cd);
G_OBJECT_CLASS(nm_ip_config_parent_class)->finalize(object);
}
static void
nm_ip_config_class_init(NMIPConfigClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass);
object_class->get_property = get_property_ip;
object_class->set_property = set_property;
object_class->constructed = constructed;
object_class->finalize = finalize;
dbus_object_class->export_on_construction = TRUE;
obj_properties_ip[PROP_IP_L3CFG] =
g_param_spec_pointer(NM_IP_CONFIG_L3CFG,
"",
"",
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
obj_properties_ip[PROP_IP_ADDRESS_DATA] =
g_param_spec_variant(NM_IP_CONFIG_ADDRESS_DATA,
"",
"",
G_VARIANT_TYPE("aa{sv}"),
NULL,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
obj_properties_ip[PROP_IP_GATEWAY] =
g_param_spec_variant(NM_IP_CONFIG_GATEWAY,
"",
"",
G_VARIANT_TYPE("s"),
NULL,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
obj_properties_ip[PROP_IP_ROUTE_DATA] =
g_param_spec_variant(NM_IP_CONFIG_ROUTE_DATA,
"",
"",
G_VARIANT_TYPE("aa{sv}"),
NULL,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
obj_properties_ip[PROP_IP_DOMAINS] =
g_param_spec_variant(NM_IP_CONFIG_DOMAINS,
"",
"",
G_VARIANT_TYPE("as"),
NULL,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
obj_properties_ip[PROP_IP_SEARCHES] =
g_param_spec_variant(NM_IP_CONFIG_SEARCHES,
"",
"",
G_VARIANT_TYPE("as"),
NULL,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
obj_properties_ip[PROP_IP_DNS_PRIORITY] =
g_param_spec_variant(NM_IP_CONFIG_DNS_PRIORITY,
"",
"",
G_VARIANT_TYPE("i"),
NULL,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
obj_properties_ip[PROP_IP_DNS_OPTIONS] =
g_param_spec_variant(NM_IP_CONFIG_DNS_OPTIONS,
"",
"",
G_VARIANT_TYPE("as"),
NULL,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST_ip, obj_properties_ip);
}
/*****************************************************************************/
/* public */
#define NM_IP4_CONFIG_NAMESERVER_DATA "nameserver-data"
#define NM_IP4_CONFIG_WINS_SERVER_DATA "wins-server-data"
/* deprecated */
#define NM_IP4_CONFIG_ADDRESSES "addresses"
#define NM_IP4_CONFIG_NAMESERVERS "nameservers"
#define NM_IP4_CONFIG_ROUTES "routes"
#define NM_IP4_CONFIG_WINS_SERVERS "wins-servers"
typedef struct _NMIP4Config NMIP4Config;
typedef struct _NMIP4ConfigClass NMIP4ConfigClass;
NM_GOBJECT_PROPERTIES_DEFINE_FULL(_ip4,
NMIP4Config,
PROP_IP4_ADDRESSES,
PROP_IP4_NAMESERVERS,
PROP_IP4_NAMESERVER_DATA,
PROP_IP4_ROUTES,
PROP_IP4_WINS_SERVERS,
PROP_IP4_WINS_SERVER_DATA, );
struct _NMIP4Config {
NMIPConfig parent;
};
struct _NMIP4ConfigClass {
NMIPConfigClass parent;
};
G_DEFINE_TYPE(NMIP4Config, nm_ip4_config, NM_TYPE_IP_CONFIG)
static void
get_property_ip4(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
NMIPConfig *self = NM_IP_CONFIG(object);
NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE(self);
char addr_str[NM_UTILS_INET_ADDRSTRLEN];
GVariantBuilder builder;
const in_addr_t *addrs;
guint len;
guint i;
switch (prop_id) {
case PROP_IP4_ADDRESSES:
g_value_set_variant(value, priv->v_addresses);
break;
case PROP_IP4_ROUTES:
g_value_set_variant(value, priv->v_routes);
break;
case PROP_IP4_NAMESERVERS:
addrs = nm_l3_config_data_get_nameservers(priv->l3cd, AF_INET, &len);
g_value_set_variant(value,
(len == 0) ? nm_g_variant_singleton_au()
: nm_g_variant_new_au(addrs, len));
break;
case PROP_IP4_NAMESERVER_DATA:
addrs = nm_l3_config_data_get_nameservers(priv->l3cd, AF_INET, &len);
if (len == 0)
g_value_set_variant(value, nm_g_variant_singleton_aaLsvI());
else {
g_variant_builder_init(&builder, G_VARIANT_TYPE("aa{sv}"));
for (i = 0; i < len; i++) {
GVariantBuilder nested_builder;
_nm_utils_inet4_ntop(addrs[i], addr_str);
g_variant_builder_init(&nested_builder, G_VARIANT_TYPE("a{sv}"));
g_variant_builder_add(&nested_builder,
"{sv}",
"address",
g_variant_new_string(addr_str));
g_variant_builder_add(&builder, "a{sv}", &nested_builder);
}
g_value_take_variant(value, g_variant_builder_end(&builder));
}
break;
case PROP_IP4_WINS_SERVERS:
addrs = nm_l3_config_data_get_wins(priv->l3cd, &len);
g_value_set_variant(value,
(len == 0) ? nm_g_variant_singleton_au()
: nm_g_variant_new_au(addrs, len));
break;
case PROP_IP4_WINS_SERVER_DATA:
addrs = nm_l3_config_data_get_wins(priv->l3cd, &len);
if (len == 0)
g_value_set_variant(value, nm_g_variant_singleton_as());
else {
g_variant_builder_init(&builder, G_VARIANT_TYPE("as"));
for (i = 0; i < len; i++)
g_variant_builder_add(&builder, "s", _nm_utils_inet4_ntop(addrs[i], addr_str));
g_value_take_variant(value, g_variant_builder_end(&builder));
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}
static const NMDBusInterfaceInfoExtended interface_info_ip4_config = {
.parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT(
NM_DBUS_INTERFACE_IP4_CONFIG,
.properties = NM_DEFINE_GDBUS_PROPERTY_INFOS(
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Addresses",
"aau",
NM_IP4_CONFIG_ADDRESSES),
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("AddressData",
"aa{sv}",
NM_IP_CONFIG_ADDRESS_DATA),
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Gateway", "s", NM_IP_CONFIG_GATEWAY),
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Routes", "aau", NM_IP4_CONFIG_ROUTES),
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("RouteData",
"aa{sv}",
NM_IP_CONFIG_ROUTE_DATA),
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("NameserverData",
"aa{sv}",
NM_IP4_CONFIG_NAMESERVER_DATA),
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Nameservers",
"au",
NM_IP4_CONFIG_NAMESERVERS),
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Domains", "as", NM_IP_CONFIG_DOMAINS),
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Searches", "as", NM_IP_CONFIG_SEARCHES),
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("DnsOptions",
"as",
NM_IP_CONFIG_DNS_OPTIONS),
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("DnsPriority",
"i",
NM_IP_CONFIG_DNS_PRIORITY),
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("WinsServerData",
"as",
NM_IP4_CONFIG_WINS_SERVER_DATA),
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("WinsServers",
"au",
NM_IP4_CONFIG_WINS_SERVERS), ), ),
};
static void
nm_ip4_config_init(NMIP4Config *self)
{}
static void
nm_ip4_config_class_init(NMIP4ConfigClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass);
NMIPConfigClass *ip_config_class = NM_IP_CONFIG_CLASS(klass);
ip_config_class->addr_family = AF_INET;
dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED(NM_DBUS_PATH "/IP4Config");
dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_ip4_config);
object_class->get_property = get_property_ip4;
obj_properties_ip4[PROP_IP4_ADDRESSES] =
g_param_spec_variant(NM_IP4_CONFIG_ADDRESSES,
"",
"",
G_VARIANT_TYPE("aau"),
NULL,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
obj_properties_ip4[PROP_IP4_ROUTES] =
g_param_spec_variant(NM_IP4_CONFIG_ROUTES,
"",
"",
G_VARIANT_TYPE("aau"),
NULL,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
obj_properties_ip4[PROP_IP4_NAMESERVER_DATA] =
g_param_spec_variant(NM_IP4_CONFIG_NAMESERVER_DATA,
"",
"",
G_VARIANT_TYPE("aa{sv}"),
NULL,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
obj_properties_ip4[PROP_IP4_NAMESERVERS] =
g_param_spec_variant(NM_IP4_CONFIG_NAMESERVERS,
"",
"",
G_VARIANT_TYPE("au"),
NULL,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
obj_properties_ip4[PROP_IP4_WINS_SERVER_DATA] =
g_param_spec_variant(NM_IP4_CONFIG_WINS_SERVER_DATA,
"",
"",
G_VARIANT_TYPE("as"),
NULL,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
obj_properties_ip4[PROP_IP4_WINS_SERVERS] =
g_param_spec_variant(NM_IP4_CONFIG_WINS_SERVERS,
"",
"",
G_VARIANT_TYPE("au"),
NULL,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST_ip4, obj_properties_ip4);
}
void
nm_ip_config_dns_hash(const NML3ConfigData *l3cd, GChecksum *sum, int addr_family)
{
guint i;
int val;
const char *const *nameservers;
const in_addr_t *wins;
const char *const *domains;
const char *const *searches;
const char *const *options;
guint num_nameservers;
guint num_wins;
guint num_domains;
guint num_searches;
guint num_options;
g_return_if_fail(l3cd);
g_return_if_fail(sum);
nameservers = nm_l3_config_data_get_nameservers(l3cd, addr_family, &num_nameservers);
for (i = 0; i < num_nameservers; i++) {
g_checksum_update(sum,
nm_ip_addr_from_packed_array(addr_family, nameservers, i),
nm_utils_addr_family_to_size(addr_family));
}
if (addr_family == AF_INET) {
wins = nm_l3_config_data_get_wins(l3cd, &num_wins);
for (i = 0; i < num_wins; i++)
g_checksum_update(sum, (guint8 *) &wins[i], 4);
}
domains = nm_l3_config_data_get_domains(l3cd, addr_family, &num_domains);
for (i = 0; i < num_domains; i++) {
g_checksum_update(sum, (const guint8 *) domains[i], strlen(domains[i]));
}
searches = nm_l3_config_data_get_searches(l3cd, addr_family, &num_searches);
for (i = 0; i < num_searches; i++) {
g_checksum_update(sum, (const guint8 *) searches[i], strlen(searches[i]));
}
options = nm_l3_config_data_get_dns_options(l3cd, addr_family, &num_options);
for (i = 0; i < num_options; i++) {
g_checksum_update(sum, (const guint8 *) options[i], strlen(options[i]));
}
val = nm_l3_config_data_get_mdns(l3cd);
if (val != NM_SETTING_CONNECTION_MDNS_DEFAULT)
g_checksum_update(sum, (const guint8 *) &val, sizeof(val));
val = nm_l3_config_data_get_llmnr(l3cd);
if (val != NM_SETTING_CONNECTION_LLMNR_DEFAULT)
g_checksum_update(sum, (const guint8 *) &val, sizeof(val));
val = nm_l3_config_data_get_dns_over_tls(l3cd);
if (val != NM_SETTING_CONNECTION_DNS_OVER_TLS_DEFAULT)
g_checksum_update(sum, (const guint8 *) &val, sizeof(val));
/* FIXME(ip-config-checksum): the DNS priority should be considered relevant
* and added into the checksum as well, but this can't be done right now
* because in the DNS manager we rely on the fact that an empty
* configuration (i.e. just created) has a zero checksum. This is needed to
* avoid rewriting resolv.conf when there is no change.
*
* The DNS priority initial value depends on the connection type (VPN or
* not), so it's a bit difficult to add it to checksum maintaining the
* assumption of checksum(empty)=0
*/
}
/*****************************************************************************/
/* public */
#define NM_IP6_CONFIG_NAMESERVERS "nameservers"
/* deprecated */
#define NM_IP6_CONFIG_ADDRESSES "addresses"
#define NM_IP6_CONFIG_ROUTES "routes"
typedef struct _NMIP6Config NMIP6Config;
typedef struct _NMIP6ConfigClass NMIP6ConfigClass;
NM_GOBJECT_PROPERTIES_DEFINE_FULL(_ip6,
NMIP6Config,
PROP_IP6_NAMESERVERS,
PROP_IP6_ADDRESSES,
PROP_IP6_ROUTES, );
struct _NMIP6Config {
NMIPConfig parent;
};
struct _NMIP6ConfigClass {
NMIPConfigClass parent;
};
G_DEFINE_TYPE(NMIP6Config, nm_ip6_config, NM_TYPE_IP_CONFIG)
static const NMDBusInterfaceInfoExtended interface_info_ip6_config = {
.parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT(
NM_DBUS_INTERFACE_IP6_CONFIG,
.properties = NM_DEFINE_GDBUS_PROPERTY_INFOS(
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Addresses",
"a(ayuay)",
NM_IP6_CONFIG_ADDRESSES),
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("AddressData",
"aa{sv}",
NM_IP_CONFIG_ADDRESS_DATA),
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Gateway", "s", NM_IP_CONFIG_GATEWAY),
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Routes",
"a(ayuayu)",
NM_IP6_CONFIG_ROUTES),
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("RouteData",
"aa{sv}",
NM_IP_CONFIG_ROUTE_DATA),
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Nameservers",
"aay",
NM_IP6_CONFIG_NAMESERVERS),
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Domains", "as", NM_IP_CONFIG_DOMAINS),
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Searches", "as", NM_IP_CONFIG_SEARCHES),
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("DnsOptions",
"as",
NM_IP_CONFIG_DNS_OPTIONS),
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("DnsPriority",
"i",
NM_IP_CONFIG_DNS_PRIORITY), ), ),
};
static void
get_property_ip6(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
NMIPConfig *self = NM_IP_CONFIG(object);
NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE(self);
GVariantBuilder builder;
guint len;
guint i;
const struct in6_addr *addrs;
switch (prop_id) {
case PROP_IP6_ADDRESSES:
g_value_set_variant(value, priv->v_addresses);
break;
case PROP_IP6_ROUTES:
g_value_set_variant(value, priv->v_routes);
break;
case PROP_IP6_NAMESERVERS:
addrs = nm_l3_config_data_get_nameservers(priv->l3cd, AF_INET6, &len);
if (len == 0)
g_value_set_variant(value, nm_g_variant_singleton_aay());
else {
g_variant_builder_init(&builder, G_VARIANT_TYPE("aay"));
for (i = 0; i < len; i++)
g_variant_builder_add(&builder, "@ay", nm_g_variant_new_ay_in6addr(&addrs[i]));
g_value_take_variant(value, g_variant_builder_end(&builder));
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}
static void
nm_ip6_config_init(NMIP6Config *self)
{}
static void
nm_ip6_config_class_init(NMIP6ConfigClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass);
NMIPConfigClass *ip_config_class = NM_IP_CONFIG_CLASS(klass);
ip_config_class->addr_family = AF_INET6;
dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED(NM_DBUS_PATH "/IP6Config");
dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_ip6_config);
object_class->get_property = get_property_ip6;
obj_properties_ip6[PROP_IP6_ADDRESSES] =
g_param_spec_variant(NM_IP6_CONFIG_ADDRESSES,
"",
"",
G_VARIANT_TYPE("a(ayuay)"),
NULL,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
obj_properties_ip6[PROP_IP6_ROUTES] =
g_param_spec_variant(NM_IP6_CONFIG_ROUTES,
"",
"",
G_VARIANT_TYPE("a(ayuayu)"),
NULL,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
obj_properties_ip6[PROP_IP6_NAMESERVERS] =
g_param_spec_variant(NM_IP6_CONFIG_NAMESERVERS,
"",
"",
G_VARIANT_TYPE("aay"),
NULL,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST_ip6, obj_properties_ip6);
}
/*****************************************************************************/
#define _notify_all(self, changed_params, n_changed_params) \
G_STMT_START \
{ \
NMIPConfig *const _self = (self); \
const guint _n_changed_params = (n_changed_params); \
GParamSpec *const *const _changed_params = (changed_params); \
guint _i; \
\
if (_n_changed_params > 0) { \
nm_assert(_n_changed_params <= G_N_ELEMENTS(changed_params)); \
if (_n_changed_params > 1) \
g_object_freeze_notify(G_OBJECT(_self)); \
for (_i = 0; _i < _n_changed_params; _i++) \
g_object_notify_by_pspec(G_OBJECT(_self), _changed_params[_i]); \
if (_n_changed_params > 1) \
g_object_thaw_notify(G_OBJECT(_self)); \
} \
} \
G_STMT_END
static void
_handle_l3cd_changed(NMIPConfig *self, const NML3ConfigData *l3cd)
{
const int addr_family = nm_ip_config_get_addr_family(self);
const int IS_IPv4 = NM_IS_IPv4(addr_family);
NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE(self);
nm_auto_unref_l3cd const NML3ConfigData *l3cd_old = NULL;
GParamSpec *changed_params[8];
guint n_changed_params = 0;
const char *const *strv;
const char *const *strv_old;
gconstpointer addrs;
gconstpointer addrs_old;
guint len;
guint len_old;
int v_i;
int v_i_old;
l3cd_old = g_steal_pointer(&priv->l3cd);
priv->l3cd = nm_l3_config_data_ref(l3cd);
addrs_old = nm_l3_config_data_get_nameservers(l3cd_old, addr_family, &len_old);
addrs = nm_l3_config_data_get_nameservers(priv->l3cd, addr_family, &len);
if (!nm_memeq_n(addrs_old, len_old, addrs, len, nm_utils_addr_family_to_size(addr_family))) {
if (IS_IPv4) {
changed_params[n_changed_params++] = obj_properties_ip4[PROP_IP4_NAMESERVER_DATA];
changed_params[n_changed_params++] = obj_properties_ip4[PROP_IP4_NAMESERVERS];
} else
changed_params[n_changed_params++] = obj_properties_ip6[PROP_IP6_NAMESERVERS];
}
strv_old = nm_l3_config_data_get_domains(l3cd_old, addr_family, &len_old);
strv = nm_l3_config_data_get_domains(priv->l3cd, addr_family, &len);
if (!nm_strv_equal_n(strv, len, strv_old, len_old))
changed_params[n_changed_params++] = obj_properties_ip[PROP_IP_DOMAINS];
strv_old = nm_l3_config_data_get_searches(l3cd_old, addr_family, &len_old);
strv = nm_l3_config_data_get_searches(priv->l3cd, addr_family, &len);
if (!nm_strv_equal_n(strv, len, strv_old, len_old))
changed_params[n_changed_params++] = obj_properties_ip[PROP_IP_SEARCHES];
v_i_old = nm_l3_config_data_get_dns_priority_or_default(l3cd_old, addr_family);
v_i = nm_l3_config_data_get_dns_priority_or_default(priv->l3cd, addr_family);
if (v_i != v_i_old)
changed_params[n_changed_params++] = obj_properties_ip[PROP_IP_DNS_PRIORITY];
strv_old = nm_l3_config_data_get_dns_options(l3cd_old, addr_family, &len);
strv = nm_l3_config_data_get_dns_options(priv->l3cd, addr_family, &len);
if (!nm_strv_equal_n(strv, len, strv_old, len_old))
changed_params[n_changed_params++] = obj_properties_ip[PROP_IP_DNS_OPTIONS];
if (IS_IPv4) {
addrs_old = nm_l3_config_data_get_wins(l3cd_old, &len_old);
addrs = nm_l3_config_data_get_wins(priv->l3cd, &len);
if (!nm_memeq_n(addrs_old, len_old, addrs, len, sizeof(in_addr_t))) {
changed_params[n_changed_params++] = obj_properties_ip4[PROP_IP4_WINS_SERVER_DATA];
changed_params[n_changed_params++] = obj_properties_ip4[PROP_IP4_WINS_SERVERS];
}
}
_notify_all(self, changed_params, n_changed_params);
}
static void
_handle_platform_change(NMIPConfig *self, guint32 obj_type_flags, gboolean is_init)
{
const int addr_family = nm_ip_config_get_addr_family(self);
const int IS_IPv4 = NM_IS_IPv4(addr_family);
NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE(self);
GParamSpec *changed_params[5];
guint n_changed_params = 0;
const NMDedupMultiHeadEntry *head_entry_routes = NULL;
gboolean best_default_route_changed = FALSE;
if (NM_FLAGS_ANY(obj_type_flags,
(nmp_object_type_to_flags(NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4))
| nmp_object_type_to_flags(NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4))))) {
const NMPObject *best_default_route = NULL;
head_entry_routes = nm_platform_lookup_object(nm_l3cfg_get_platform(priv->l3cfg),
NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4),
nm_l3cfg_get_ifindex(priv->l3cfg));
if (head_entry_routes) {
NMDedupMultiIter iter;
const NMPObject *obj;
nm_dedup_multi_iter_init(&iter, head_entry_routes);
while (nm_platform_dedup_multi_iter_next_obj(&iter,
&obj,
NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4))) {
const NMPlatformIPXRoute *r = NMP_OBJECT_CAST_IPX_ROUTE(obj);
/* Determine the gateway. That is the next hop of a route
* - 0.0.0.0/0 or ::/0
* - type=unicast
* - table=main
*/
if (r->rx.plen != 0
|| r->rx.type_coerced != nm_platform_route_type_coerce(RTN_UNICAST)
|| r->rx.table_coerced != nm_platform_route_table_coerce(RT_TABLE_MAIN)
|| !nm_ip_addr_is_null(addr_family, r->rx.network_ptr))
continue;
if (!best_default_route
|| NMP_OBJECT_CAST_IP_ROUTE(best_default_route)->metric > r->rx.metric)
best_default_route = obj;
}
}
if (priv->v_gateway.best_default_route != best_default_route) {
if (!nm_ip_addr_equal(
addr_family,
nm_platform_ip_route_get_gateway(
addr_family,
NMP_OBJECT_CAST_IP_ROUTE(priv->v_gateway.best_default_route)),
nm_platform_ip_route_get_gateway(addr_family,
NMP_OBJECT_CAST_IP_ROUTE(best_default_route))))
best_default_route_changed = TRUE;
nmp_object_ref_set(&priv->v_gateway.best_default_route, best_default_route);
}
}
if (best_default_route_changed
|| NM_FLAGS_ANY(obj_type_flags,
nmp_object_type_to_flags(NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4)))) {
gs_unref_variant GVariant *x_address_data = NULL;
gs_unref_variant GVariant *x_addresses = NULL;
nm_utils_ip_addresses_to_dbus(addr_family,
nm_platform_lookup_object(nm_l3cfg_get_platform(priv->l3cfg),
NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4),
nm_l3cfg_get_ifindex(priv->l3cfg)),
priv->v_gateway.best_default_route,
&x_address_data,
&x_addresses);
if (!nm_g_variant_equal(priv->v_address_data, x_address_data)) {
changed_params[n_changed_params++] = obj_properties_ip[PROP_IP_ADDRESS_DATA];
g_variant_ref_sink(x_address_data);
NM_SWAP(&priv->v_address_data, &x_address_data);
}
if (!nm_g_variant_equal(priv->v_addresses, x_addresses)) {
changed_params[n_changed_params++] = IS_IPv4 ? obj_properties_ip4[PROP_IP4_ADDRESSES]
: obj_properties_ip6[PROP_IP6_ADDRESSES];
g_variant_ref_sink(x_addresses);
NM_SWAP(&priv->v_addresses, &x_addresses);
}
}
if (best_default_route_changed)
changed_params[n_changed_params++] = obj_properties_ip[PROP_IP_GATEWAY];
if (NM_FLAGS_ANY(obj_type_flags, nmp_object_type_to_flags(NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4)))) {
gs_unref_variant GVariant *x_route_data = NULL;
gs_unref_variant GVariant *x_routes = NULL;
nm_utils_ip_routes_to_dbus(addr_family, head_entry_routes, &x_route_data, &x_routes);
if (!nm_g_variant_equal(priv->v_route_data, x_route_data)) {
changed_params[n_changed_params++] = obj_properties_ip[PROP_IP_ROUTE_DATA];
g_variant_ref_sink(x_route_data);
NM_SWAP(&priv->v_route_data, &x_route_data);
}
if (!nm_g_variant_equal(priv->v_routes, x_routes)) {
changed_params[n_changed_params++] =
IS_IPv4 ? obj_properties_ip4[PROP_IP4_ROUTES] : obj_properties_ip6[PROP_IP6_ROUTES];
g_variant_ref_sink(x_routes);
NM_SWAP(&priv->v_routes, &x_routes);
}
}
if (!is_init)
_notify_all(self, changed_params, n_changed_params);
}