diff options
Diffstat (limited to 'src/nm-ip4-config.c')
| -rw-r--r-- | src/nm-ip4-config.c | 1912 |
1 files changed, 1356 insertions, 556 deletions
diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 0722981e..e27c0436 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -1,5 +1,5 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager +/* NetworkManager * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,27 +15,22 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2005 - 2008 Red Hat, Inc. + * Copyright (C) 2005 - 2014 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. */ -#include <glib.h> -#include <stdio.h> #include <string.h> -#include "nm-ip4-config.h" -#include "nm-dbus-manager.h" -#include "NetworkManager.h" -#include "NetworkManagerUtils.h" -#include "nm-setting-ip4-config.h" -#include "nm-utils.h" -#include <netlink/route/addr.h> -#include <netlink/utils.h> -#include <netinet/in.h> +#include "nm-ip4-config.h" -#include "nm-ip4-config-glue.h" +#include "libgsystem.h" +#include "nm-platform.h" +#include "nm-utils.h" +#include "nm-dbus-manager.h" #include "nm-dbus-glib-types.h" - +#include "nm-ip4-config-glue.h" +#include "NetworkManagerUtils.h" +#include "nm-utils-private.h" G_DEFINE_TYPE (NMIP4Config, nm_ip4_config, G_TYPE_OBJECT) @@ -44,51 +39,38 @@ G_DEFINE_TYPE (NMIP4Config, nm_ip4_config, G_TYPE_OBJECT) typedef struct { char *path; - GSList *addresses; - guint32 ptp_address; - - guint32 mtu; /* Maximum Transmission Unit of the interface */ - guint32 mss; /* Maximum Segment Size of the route */ - + gboolean never_default; + guint32 gateway; + GArray *addresses; + GArray *routes; GArray *nameservers; GPtrArray *domains; GPtrArray *searches; - - GArray *wins; - + guint32 mss; GArray *nis; - char * nis_domain; - - GSList *routes; - - gboolean never_default; + char *nis_domain; + GArray *wins; + guint32 mtu; } NMIP4ConfigPrivate; +/* internal guint32 are assigned to gobject properties of type uint. Ensure, that uint is large enough */ +G_STATIC_ASSERT (sizeof (uint) >= sizeof (guint32)); +G_STATIC_ASSERT (G_MAXUINT >= 0xFFFFFFFF); enum { PROP_0, + PROP_GATEWAY, PROP_ADDRESSES, + PROP_ROUTES, PROP_NAMESERVERS, PROP_DOMAINS, - PROP_ROUTES, + PROP_SEARCHES, PROP_WINS_SERVERS, LAST_PROP }; - - -static struct nl_addr * -nm_utils_ip4_addr_to_nl_addr (guint32 ip4_addr) -{ - struct nl_addr * nla = NULL; - - if (!(nla = nl_addr_alloc (sizeof (in_addr_t)))) - return NULL; - nl_addr_set_family (nla, AF_INET); - nl_addr_set_binary_addr (nla, &ip4_addr, sizeof (guint32)); - - return nla; -} +static GParamSpec *obj_properties[LAST_PROP] = { NULL, }; +#define _NOTIFY(config, prop) G_STMT_START { g_object_notify_by_pspec (G_OBJECT (config), obj_properties[prop]); } G_STMT_END NMIP4Config * @@ -97,722 +79,1447 @@ nm_ip4_config_new (void) return (NMIP4Config *) g_object_new (NM_TYPE_IP4_CONFIG, NULL); } + void nm_ip4_config_export (NMIP4Config *config) { - NMIP4ConfigPrivate *priv; - NMDBusManager *dbus_mgr; - DBusGConnection *connection; + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); static guint32 counter = 0; - g_return_if_fail (NM_IS_IP4_CONFIG (config)); - - priv = NM_IP4_CONFIG_GET_PRIVATE (config); - g_return_if_fail (priv->path == NULL); - - dbus_mgr = nm_dbus_manager_get (); - connection = nm_dbus_manager_get_connection (dbus_mgr); - priv->path = g_strdup_printf (NM_DBUS_PATH "/IP4Config/%d", counter++); - - dbus_g_connection_register_g_object (connection, priv->path, G_OBJECT (config)); - g_object_unref (dbus_mgr); + if (!priv->path) { + priv->path = g_strdup_printf (NM_DBUS_PATH "/IP4Config/%d", counter++); + nm_dbus_manager_register_object (nm_dbus_manager_get (), priv->path, config); + } } const char * -nm_ip4_config_get_dbus_path (NMIP4Config *config) +nm_ip4_config_get_dbus_path (const NMIP4Config *config) { - g_return_val_if_fail (NM_IS_IP4_CONFIG (config), NULL); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - return NM_IP4_CONFIG_GET_PRIVATE (config)->path; + return priv->path; } -void -nm_ip4_config_take_address (NMIP4Config *config, NMIP4Address *address) +static gboolean +same_prefix (guint32 address1, guint32 address2, int plen) { - NMIP4ConfigPrivate *priv; + guint32 masked1 = ntohl (address1) >> (32 - plen); + guint32 masked2 = ntohl (address2) >> (32 - plen); - g_return_if_fail (NM_IS_IP4_CONFIG (config)); - g_return_if_fail (address != NULL); - - priv = NM_IP4_CONFIG_GET_PRIVATE (config); - priv->addresses = g_slist_append (priv->addresses, address); + return masked1 == masked2; } -void -nm_ip4_config_add_address (NMIP4Config *config, - NMIP4Address *address) +/******************************************************************/ + +/** + * nm_ip4_config_capture_resolv_conf(): + * @nameservers: array of guint32 + * @rc_contents: the contents of a resolv.conf or %NULL to read /etc/resolv.conf + * + * Reads all resolv.conf IPv4 nameservers and adds them to @nameservers. + * + * Returns: %TRUE if nameservers were added, %FALSE if @nameservers is unchanged + */ +gboolean +nm_ip4_config_capture_resolv_conf (GArray *nameservers, + const char *rc_contents) { - NMIP4ConfigPrivate *priv; - GSList *iter; + GPtrArray *read_ns; + guint i, j; + gboolean changed = FALSE; - g_return_if_fail (NM_IS_IP4_CONFIG (config)); - g_return_if_fail (address != NULL); + g_return_val_if_fail (nameservers != NULL, FALSE); - priv = NM_IP4_CONFIG_GET_PRIVATE (config); - for (iter = priv->addresses; iter; iter = g_slist_next (iter)) { - if (nm_ip4_address_compare ((NMIP4Address *) iter->data, address)) - return; - } + read_ns = nm_utils_read_resolv_conf_nameservers (rc_contents); + if (!read_ns) + return FALSE; - priv->addresses = g_slist_append (priv->addresses, nm_ip4_address_dup (address)); -} + for (i = 0; i < read_ns->len; i++) { + const char *s = g_ptr_array_index (read_ns, i); + guint32 ns = 0; -void -nm_ip4_config_replace_address (NMIP4Config *config, - guint i, - NMIP4Address *new_address) -{ - NMIP4ConfigPrivate *priv; - GSList *old; + if (!inet_pton (AF_INET, s, (void *) &ns) || !ns) + continue; - g_return_if_fail (NM_IS_IP4_CONFIG (config)); + /* Ignore duplicates */ + for (j = 0; j < nameservers->len; j++) { + if (g_array_index (nameservers, guint32, j) == ns) + break; + } - priv = NM_IP4_CONFIG_GET_PRIVATE (config); - old = g_slist_nth (priv->addresses, i); - g_return_if_fail (old != NULL); - nm_ip4_address_unref ((NMIP4Address *) old->data); + if (j == nameservers->len) { + g_array_append_val (nameservers, ns); + changed = TRUE; + } + } - old->data = nm_ip4_address_dup (new_address); + g_ptr_array_unref (read_ns); + return changed; } -NMIP4Address *nm_ip4_config_get_address (NMIP4Config *config, guint i) +static gboolean +addresses_are_duplicate (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b, gboolean consider_plen) { - g_return_val_if_fail (NM_IS_IP4_CONFIG (config), NULL); - - return (NMIP4Address *) g_slist_nth_data (NM_IP4_CONFIG_GET_PRIVATE (config)->addresses, i); + return a->address == b->address && (!consider_plen || a->plen == b->plen); } -guint32 nm_ip4_config_get_num_addresses (NMIP4Config *config) +static gboolean +routes_are_duplicate (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b, gboolean consider_gateway_and_metric) { - g_return_val_if_fail (NM_IS_IP4_CONFIG (config), 0); - - return g_slist_length (NM_IP4_CONFIG_GET_PRIVATE (config)->addresses); + return a->network == b->network && a->plen == b->plen && + (!consider_gateway_and_metric || (a->gateway == b->gateway && a->metric == b->metric)); } -guint32 nm_ip4_config_get_ptp_address (NMIP4Config *config) +NMIP4Config * +nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf) { - g_return_val_if_fail (NM_IS_IP4_CONFIG (config), 0); + NMIP4Config *config; + NMIP4ConfigPrivate *priv; + guint i; + guint lowest_metric = G_MAXUINT; + guint32 old_gateway = 0; + gboolean has_gateway = FALSE; - return NM_IP4_CONFIG_GET_PRIVATE (config)->ptp_address; -} + /* Slaves have no IP configuration */ + if (nm_platform_link_get_master (ifindex) > 0) + return NULL; -void nm_ip4_config_set_ptp_address (NMIP4Config *config, guint32 ptp_addr) -{ - g_return_if_fail (NM_IS_IP4_CONFIG (config)); + config = nm_ip4_config_new (); + priv = NM_IP4_CONFIG_GET_PRIVATE (config); + + g_array_unref (priv->addresses); + g_array_unref (priv->routes); + + priv->addresses = nm_platform_ip4_address_get_all (ifindex); + priv->routes = nm_platform_ip4_route_get_all (ifindex, TRUE); + + /* Extract gateway from default route */ + old_gateway = priv->gateway; + for (i = 0; i < priv->routes->len; i++) { + const NMPlatformIP4Route *route = &g_array_index (priv->routes, NMPlatformIP4Route, i); + + if (route->network == 0) { + if (route->metric < lowest_metric) { + priv->gateway = route->gateway; + lowest_metric = route->metric; + } + has_gateway = TRUE; + /* Remove the default route from the list */ + g_array_remove_index (priv->routes, i); + i--; + } + } + + /* If there is a host route to the gateway, ignore that route. It is + * automatically added by NetworkManager when needed. + */ + if (has_gateway) { + for (i = 0; i < priv->routes->len; i++) { + const NMPlatformIP4Route *route = &g_array_index (priv->routes, NMPlatformIP4Route, i); + + if ( (route->plen == 32) + && (route->network == priv->gateway) + && (route->gateway == 0)) { + g_array_remove_index (priv->routes, i); + i--; + } + } + } - NM_IP4_CONFIG_GET_PRIVATE (config)->ptp_address = ptp_addr; + /* If the interface has the default route, and has IPv4 addresses, capture + * nameservers from /etc/resolv.conf. + */ + if (priv->addresses->len && has_gateway && capture_resolv_conf) { + if (nm_ip4_config_capture_resolv_conf (priv->nameservers, NULL)) + _NOTIFY (config, PROP_NAMESERVERS); + } + + /* actually, nobody should be connected to the signal, just to be sure, notify */ + _NOTIFY (config, PROP_ADDRESSES); + _NOTIFY (config, PROP_ROUTES); + if (priv->gateway != old_gateway) + _NOTIFY (config, PROP_GATEWAY); + + return config; } -void nm_ip4_config_add_nameserver (NMIP4Config *config, guint32 nameserver) +gboolean +nm_ip4_config_commit (const NMIP4Config *config, int ifindex) { - NMIP4ConfigPrivate *priv; + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + int mtu = nm_ip4_config_get_mtu (config); int i; - g_return_if_fail (NM_IS_IP4_CONFIG (config)); - g_return_if_fail (nameserver > 0); + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (config != NULL, FALSE); - priv = NM_IP4_CONFIG_GET_PRIVATE (config); - for (i = 0; i < priv->nameservers->len; i++) { - guint32 s = g_array_index (priv->nameservers, guint32, i); + /* Addresses */ + nm_platform_ip4_address_sync (ifindex, priv->addresses); - /* No dupes */ - if (nameserver == s) - return; + /* Routes */ + { + int count = nm_ip4_config_get_num_routes (config); + GArray *routes = g_array_sized_new (FALSE, FALSE, sizeof (NMPlatformIP4Route), count); + NMPlatformIP4Route route; + gboolean success; + + for (i = 0; i < count; i++) { + memcpy (&route, nm_ip4_config_get_route (config, i), sizeof (route)); + + /* Don't add the route if it's more specific than one of the subnets + * the device already has an IP address on. + */ + if ( route.gateway == 0 + && nm_ip4_config_destination_is_direct (config, route.network, route.plen)) + continue; + + /* Don't add the default route if the connection + * is never supposed to be the default connection. + */ + if (nm_ip4_config_get_never_default (config) && route.network == 0) + continue; + + g_array_append_val (routes, route); + } + + success = nm_platform_ip4_route_sync (ifindex, routes); + g_array_unref (routes); + if (!success) + return FALSE; } - g_array_append_val (priv->nameservers, nameserver); + /* MTU */ + if (mtu && mtu != nm_platform_link_get_mtu (ifindex)) + nm_platform_link_set_mtu (ifindex, mtu); + + return TRUE; } -guint32 nm_ip4_config_get_nameserver (NMIP4Config *config, guint i) +void +nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIP4Config *setting, int default_route_metric) { - g_return_val_if_fail (NM_IS_IP4_CONFIG (config), 0); + guint naddresses, nroutes, nnameservers, nsearches; + int i; - return g_array_index (NM_IP4_CONFIG_GET_PRIVATE (config)->nameservers, guint32, i); -} + if (!setting) + return; -guint32 nm_ip4_config_get_num_nameservers (NMIP4Config *config) -{ - g_return_val_if_fail (NM_IS_IP4_CONFIG (config), 0); + g_object_freeze_notify (G_OBJECT (config)); - return NM_IP4_CONFIG_GET_PRIVATE (config)->nameservers->len; -} + naddresses = nm_setting_ip4_config_get_num_addresses (setting); + nroutes = nm_setting_ip4_config_get_num_routes (setting); + nnameservers = nm_setting_ip4_config_get_num_dns (setting); + nsearches = nm_setting_ip4_config_get_num_dns_searches (setting); -void nm_ip4_config_reset_nameservers (NMIP4Config *config) -{ - NMIP4ConfigPrivate *priv; + /* Gateway */ + if (nm_setting_ip4_config_get_never_default (setting)) + nm_ip4_config_set_never_default (config, TRUE); + else if (nm_setting_ip4_config_get_ignore_auto_routes (setting)) + nm_ip4_config_set_never_default (config, FALSE); + for (i = 0; i < naddresses; i++) { + guint32 gateway = nm_ip4_address_get_gateway (nm_setting_ip4_config_get_address (setting, i)); - g_return_if_fail (NM_IS_IP4_CONFIG (config)); + if (gateway) { + nm_ip4_config_set_gateway (config, gateway); + break; + } + } - priv = NM_IP4_CONFIG_GET_PRIVATE (config); - if (priv->nameservers->len) - g_array_remove_range (priv->nameservers, 0, priv->nameservers->len); + /* Addresses */ + for (i = 0; i < naddresses; i++) { + NMIP4Address *s_addr = nm_setting_ip4_config_get_address (setting, i); + const char *label = NM_UTILS_PRIVATE_CALL (nm_setting_ip4_config_get_address_label (setting, i)); + NMPlatformIP4Address address; + + memset (&address, 0, sizeof (address)); + address.address = nm_ip4_address_get_address (s_addr); + address.plen = nm_ip4_address_get_prefix (s_addr); + address.lifetime = NM_PLATFORM_LIFETIME_PERMANENT; + address.preferred = NM_PLATFORM_LIFETIME_PERMANENT; + address.source = NM_PLATFORM_SOURCE_USER; + if (label) + g_strlcpy (address.label, label, sizeof (address.label)); + + nm_ip4_config_add_address (config, &address); + } + + /* Routes */ + if (nm_setting_ip4_config_get_ignore_auto_routes (setting)) + nm_ip4_config_reset_routes (config); + for (i = 0; i < nroutes; i++) { + NMIP4Route *s_route = nm_setting_ip4_config_get_route (setting, i); + NMPlatformIP4Route route; + + memset (&route, 0, sizeof (route)); + route.network = nm_ip4_route_get_dest (s_route); + route.plen = nm_ip4_route_get_prefix (s_route); + route.gateway = nm_ip4_route_get_next_hop (s_route); + route.metric = nm_ip4_route_get_metric (s_route); + if (!route.metric) + route.metric = default_route_metric; + route.source = NM_PLATFORM_SOURCE_USER; + + nm_ip4_config_add_route (config, &route); + } + + /* DNS */ + if (nm_setting_ip4_config_get_ignore_auto_dns (setting)) { + nm_ip4_config_reset_nameservers (config); + nm_ip4_config_reset_domains (config); + nm_ip4_config_reset_searches (config); + } + for (i = 0; i < nnameservers; i++) + nm_ip4_config_add_nameserver (config, nm_setting_ip4_config_get_dns (setting, i)); + for (i = 0; i < nsearches; i++) + nm_ip4_config_add_search (config, nm_setting_ip4_config_get_dns_search (setting, i)); + + g_object_thaw_notify (G_OBJECT (config)); } -void nm_ip4_config_add_wins (NMIP4Config *config, guint32 wins) +NMSetting * +nm_ip4_config_create_setting (const NMIP4Config *config) { - NMIP4ConfigPrivate *priv; + NMSettingIP4Config *s_ip4; + guint32 gateway; + guint naddresses, nroutes, nnameservers, nsearches; + const char *method = NULL; int i; - g_return_if_fail (NM_IS_IP4_CONFIG (config)); - g_return_if_fail (wins > 0); + s_ip4 = NM_SETTING_IP4_CONFIG (nm_setting_ip4_config_new ()); - priv = NM_IP4_CONFIG_GET_PRIVATE (config); - for (i = 0; i < priv->wins->len; i++) { - guint32 s = g_array_index (priv->wins, guint32, i); + if (!config) { + g_object_set (s_ip4, + NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_DISABLED, + NULL); + return NM_SETTING (s_ip4); + } - /* No dupes */ - if (wins == s) - return; + gateway = nm_ip4_config_get_gateway (config); + naddresses = nm_ip4_config_get_num_addresses (config); + nroutes = nm_ip4_config_get_num_routes (config); + nnameservers = nm_ip4_config_get_num_nameservers (config); + nsearches = nm_ip4_config_get_num_searches (config); + + /* Addresses */ + for (i = 0; i < naddresses; i++) { + const NMPlatformIP4Address *address = nm_ip4_config_get_address (config, i); + NMIP4Address *s_addr; + + /* Detect dynamic address */ + if (address->lifetime != NM_PLATFORM_LIFETIME_PERMANENT) { + method = NM_SETTING_IP4_CONFIG_METHOD_AUTO; + continue; + } + + /* Static address found. */ + if (!method) + method = NM_SETTING_IP4_CONFIG_METHOD_MANUAL; + + s_addr = nm_ip4_address_new (); + + nm_ip4_address_set_address (s_addr, address->address); + nm_ip4_address_set_prefix (s_addr, address->plen); + /* For backwards compatibility, attach the gateway to an address if it's + * in the same subnet. + */ + if (same_prefix (address->address, gateway, address->plen)) + nm_ip4_address_set_gateway (s_addr, gateway); + + if (*address->label) + NM_UTILS_PRIVATE_CALL (nm_setting_ip4_config_add_address_with_label (s_ip4, s_addr, address->label)); + else + nm_setting_ip4_config_add_address (s_ip4, s_addr); + nm_ip4_address_unref (s_addr); } - g_array_append_val (priv->wins, wins); -} + /* Use 'disabled' if the method wasn't previously set */ + if (!method) + method = NM_SETTING_IP4_CONFIG_METHOD_DISABLED; + g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_METHOD, method, NULL); -guint32 nm_ip4_config_get_wins (NMIP4Config *config, guint i) -{ - g_return_val_if_fail (NM_IS_IP4_CONFIG (config), 0); + /* Routes */ + for (i = 0; i < nroutes; i++) { + const NMPlatformIP4Route *route = nm_ip4_config_get_route (config, i); + NMIP4Route *s_route; - return g_array_index (NM_IP4_CONFIG_GET_PRIVATE (config)->wins, guint32, i); -} + /* Ignore default route. */ + if (!route->plen) + continue; -guint32 nm_ip4_config_get_num_wins (NMIP4Config *config) -{ - g_return_val_if_fail (NM_IS_IP4_CONFIG (config), 0); + /* Ignore routes provided by external sources */ + if (route->source != NM_PLATFORM_SOURCE_USER) + continue; - return NM_IP4_CONFIG_GET_PRIVATE (config)->wins->len; -} + s_route = nm_ip4_route_new (); + nm_ip4_route_set_dest (s_route, route->network); + nm_ip4_route_set_prefix (s_route, route->plen); + nm_ip4_route_set_next_hop (s_route, route->gateway); + nm_ip4_route_set_metric (s_route, route->metric); -void nm_ip4_config_reset_wins (NMIP4Config *config) -{ - NMIP4ConfigPrivate *priv; + nm_setting_ip4_config_add_route (s_ip4, s_route); + nm_ip4_route_unref (s_route); + } - g_return_if_fail (NM_IS_IP4_CONFIG (config)); + /* DNS */ + for (i = 0; i < nnameservers; i++) { + guint32 nameserver = nm_ip4_config_get_nameserver (config, i); - priv = NM_IP4_CONFIG_GET_PRIVATE (config); - if (priv->wins->len) - g_array_remove_range (priv->wins, 0, priv->wins->len); + nm_setting_ip4_config_add_dns (s_ip4, nameserver); + } + for (i = 0; i < nsearches; i++) { + const char *search = nm_ip4_config_get_search (config, i); + + nm_setting_ip4_config_add_dns_search (s_ip4, search); + } + + return NM_SETTING (s_ip4); } +/******************************************************************/ + void -nm_ip4_config_take_route (NMIP4Config *config, NMIP4Route *route) +nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src) { - NMIP4ConfigPrivate *priv; + guint32 i; - g_return_if_fail (NM_IS_IP4_CONFIG (config)); - g_return_if_fail (route != NULL); + g_return_if_fail (src != NULL); + g_return_if_fail (dst != NULL); - priv = NM_IP4_CONFIG_GET_PRIVATE (config); - priv->routes = g_slist_append (priv->routes, route); + g_object_freeze_notify (G_OBJECT (dst)); + + /* addresses */ + for (i = 0; i < nm_ip4_config_get_num_addresses (src); i++) + nm_ip4_config_add_address (dst, nm_ip4_config_get_address (src, i)); + + /* nameservers */ + for (i = 0; i < nm_ip4_config_get_num_nameservers (src); i++) + nm_ip4_config_add_nameserver (dst, nm_ip4_config_get_nameserver (src, i)); + + /* default gateway */ + if (!nm_ip4_config_get_gateway (dst)) + nm_ip4_config_set_gateway (dst, nm_ip4_config_get_gateway (src)); + + /* routes */ + for (i = 0; i < nm_ip4_config_get_num_routes (src); i++) + nm_ip4_config_add_route (dst, nm_ip4_config_get_route (src, i)); + + /* domains */ + for (i = 0; i < nm_ip4_config_get_num_domains (src); i++) + nm_ip4_config_add_domain (dst, nm_ip4_config_get_domain (src, i)); + + /* dns searches */ + for (i = 0; i < nm_ip4_config_get_num_searches (src); i++) + nm_ip4_config_add_search (dst, nm_ip4_config_get_search (src, i)); + + /* MSS */ + if (!nm_ip4_config_get_mss (dst)) + nm_ip4_config_set_mss (dst, nm_ip4_config_get_mss (src)); + + /* MTU */ + if (!nm_ip4_config_get_mtu (dst)) + nm_ip4_config_set_mtu (dst, nm_ip4_config_get_mtu (src)); + + /* NIS */ + for (i = 0; i < nm_ip4_config_get_num_nis_servers (src); i++) + nm_ip4_config_add_nis_server (dst, nm_ip4_config_get_nis_server (src, i)); + + if (nm_ip4_config_get_nis_domain (src)) + nm_ip4_config_set_nis_domain (dst, nm_ip4_config_get_nis_domain (src)); + + /* WINS */ + for (i = 0; i < nm_ip4_config_get_num_wins (src); i++) + nm_ip4_config_add_wins (dst, nm_ip4_config_get_wins (src, i)); + + g_object_thaw_notify (G_OBJECT (dst)); } +/** + * nm_ip4_config_subtract: + * @dst: config from which to remove everything in @src + * @src: config to remove from @dst + * + * Removes everything in @src from @dst. + */ void -nm_ip4_config_add_route (NMIP4Config *config, NMIP4Route *route) +nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src) { - NMIP4ConfigPrivate *priv; - GSList *iter; + guint32 i, j; - g_return_if_fail (NM_IS_IP4_CONFIG (config)); - g_return_if_fail (route != NULL); + g_return_if_fail (src != NULL); + g_return_if_fail (dst != NULL); - priv = NM_IP4_CONFIG_GET_PRIVATE (config); - for (iter = priv->routes; iter; iter = g_slist_next (iter)) { - if (nm_ip4_route_compare ((NMIP4Route *) iter->data, route)) - return; + g_object_freeze_notify (G_OBJECT (dst)); + + /* addresses */ + for (i = 0; i < nm_ip4_config_get_num_addresses (src); i++) { + const NMPlatformIP4Address *src_addr = nm_ip4_config_get_address (src, i); + + for (j = 0; j < nm_ip4_config_get_num_addresses (dst); j++) { + const NMPlatformIP4Address *dst_addr = nm_ip4_config_get_address (dst, j); + + if (src_addr->address == dst_addr->address && + src_addr->plen == dst_addr->plen) { + nm_ip4_config_del_address (dst, j); + break; + } + } } - priv->routes = g_slist_append (priv->routes, nm_ip4_route_dup (route)); -} + /* nameservers */ + for (i = 0; i < nm_ip4_config_get_num_nameservers (src); i++) { + guint32 src_ns = nm_ip4_config_get_nameserver (src, i); -void -nm_ip4_config_replace_route (NMIP4Config *config, - guint i, - NMIP4Route *new_route) -{ - NMIP4ConfigPrivate *priv; - GSList *old; + for (j = 0; j < nm_ip4_config_get_num_nameservers (dst); j++) { + guint32 dst_ns = nm_ip4_config_get_nameserver (dst, j); - g_return_if_fail (NM_IS_IP4_CONFIG (config)); + if (dst_ns == src_ns) { + nm_ip4_config_del_nameserver (dst, j); + break; + } + } + } - priv = NM_IP4_CONFIG_GET_PRIVATE (config); - old = g_slist_nth (priv->routes, i); - g_return_if_fail (old != NULL); - nm_ip4_route_unref ((NMIP4Route *) old->data); + /* default gateway */ + if (nm_ip4_config_get_gateway (src) == nm_ip4_config_get_gateway (dst)) + nm_ip4_config_set_gateway (dst, 0); - old->data = nm_ip4_route_dup (new_route); -} + /* routes */ + for (i = 0; i < nm_ip4_config_get_num_routes (src); i++) { + const NMPlatformIP4Route *src_route = nm_ip4_config_get_route (src, i); -NMIP4Route * -nm_ip4_config_get_route (NMIP4Config *config, guint i) -{ - g_return_val_if_fail (NM_IS_IP4_CONFIG (config), NULL); + for (j = 0; j < nm_ip4_config_get_num_routes (dst); j++) { + const NMPlatformIP4Route *dst_route = nm_ip4_config_get_route (dst, j); + + if (src_route->network == dst_route->network && src_route->plen == dst_route->plen) { + nm_ip4_config_del_route (dst, j); + break; + } + } + } + + /* domains */ + for (i = 0; i < nm_ip4_config_get_num_domains (src); i++) { + const char *src_domain = nm_ip4_config_get_domain (src, i); + + for (j = 0; j < nm_ip4_config_get_num_domains (dst); j++) { + const char *dst_domain = nm_ip4_config_get_domain (dst, j); + + if (g_strcmp0 (src_domain, dst_domain) == 0) { + nm_ip4_config_del_domain (dst, j); + break; + } + } + } + + /* dns searches */ + for (i = 0; i < nm_ip4_config_get_num_searches (src); i++) { + const char *src_search = nm_ip4_config_get_search (src, i); + + for (j = 0; j < nm_ip4_config_get_num_searches (dst); j++) { + const char *dst_search = nm_ip4_config_get_search (dst, j); + + if (g_strcmp0 (src_search, dst_search) == 0) { + nm_ip4_config_del_search (dst, j); + break; + } + } + } + + /* MSS */ + if (nm_ip4_config_get_mss (src) == nm_ip4_config_get_mss (dst)) + nm_ip4_config_set_mss (dst, 0); + + /* MTU */ + if (nm_ip4_config_get_mtu (src) == nm_ip4_config_get_mtu (dst)) + nm_ip4_config_set_mtu (dst, 0); + + /* NIS */ + for (i = 0; i < nm_ip4_config_get_num_nis_servers (src); i++) { + guint32 src_nis = nm_ip4_config_get_nis_server (src, i); + + for (j = 0; j < nm_ip4_config_get_num_nis_servers (dst); j++) { + guint32 dst_nis = nm_ip4_config_get_nis_server (dst, j); + + if (dst_nis == src_nis) { + nm_ip4_config_del_nis_server (dst, j); + break; + } + } + } + + if (g_strcmp0 (nm_ip4_config_get_nis_domain (src), nm_ip4_config_get_nis_domain (dst)) == 0) + nm_ip4_config_set_nis_domain (dst, NULL); + + /* WINS */ + for (i = 0; i < nm_ip4_config_get_num_wins (src); i++) { + guint32 src_wins = nm_ip4_config_get_wins (src, i); + + for (j = 0; j < nm_ip4_config_get_num_wins (dst); j++) { + guint32 dst_wins = nm_ip4_config_get_wins (dst, j); + + if (dst_wins == src_wins) { + nm_ip4_config_del_wins (dst, j); + break; + } + } + } - return (NMIP4Route *) g_slist_nth_data (NM_IP4_CONFIG_GET_PRIVATE (config)->routes, i); + g_object_thaw_notify (G_OBJECT (dst)); } -guint32 nm_ip4_config_get_num_routes (NMIP4Config *config) + +/** + * nm_ip4_config_replace: + * @dst: config from which to remove everything in @src + * @src: config to remove from @dst + * @relevant_changes: return whether there are changes to the + * destination object that are relevant. This is equal to + * nm_ip4_config_equal() showing any difference. + * + * Replaces everything in @dst with @src so that the two configurations + * contain the same content -- with the exception of the dbus path. + * + * Returns: whether the @dst instance changed in any way (including minor changes, + * that are not signaled by the output parameter @relevant_changes). + */ +gboolean +nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relevant_changes) { - g_return_val_if_fail (NM_IS_IP4_CONFIG (config), 0); +#ifndef G_DISABLE_ASSERT + gboolean config_equal; +#endif + gboolean has_minor_changes = FALSE, has_relevant_changes = FALSE, are_equal; + guint i, num; + NMIP4ConfigPrivate *dst_priv, *src_priv; + const NMPlatformIP4Address *dst_addr, *src_addr; + const NMPlatformIP4Route *dst_route, *src_route; + + g_return_val_if_fail (src != NULL, FALSE); + g_return_val_if_fail (dst != NULL, FALSE); + g_return_val_if_fail (src != dst, FALSE); + +#ifndef G_DISABLE_ASSERT + config_equal = nm_ip4_config_equal (dst, src); +#endif + + dst_priv = NM_IP4_CONFIG_GET_PRIVATE (dst); + src_priv = NM_IP4_CONFIG_GET_PRIVATE (src); + + g_object_freeze_notify (G_OBJECT (dst)); + + /* never_default */ + if (src_priv->never_default != dst_priv->never_default) { + dst_priv->never_default = src_priv->never_default; + has_minor_changes = TRUE; + } + + /* default gateway */ + if (src_priv->gateway != dst_priv->gateway) { + nm_ip4_config_set_gateway (dst, src_priv->gateway); + has_relevant_changes = TRUE; + } + + /* addresses */ + num = nm_ip4_config_get_num_addresses (src); + are_equal = num == nm_ip4_config_get_num_addresses (dst); + if (are_equal) { + for (i = 0; i < num; i++ ) { + if (nm_platform_ip4_address_cmp (src_addr = nm_ip4_config_get_address (src, i), + dst_addr = nm_ip4_config_get_address (dst, i))) { + are_equal = FALSE; + if (!addresses_are_duplicate (src_addr, dst_addr, TRUE)) { + has_relevant_changes = TRUE; + break; + } + } + } + } else + has_relevant_changes = TRUE; + if (!are_equal) { + nm_ip4_config_reset_addresses (dst); + for (i = 0; i < num; i++) + nm_ip4_config_add_address (dst, nm_ip4_config_get_address (src, i)); + has_minor_changes = TRUE; + } + + /* routes */ + num = nm_ip4_config_get_num_routes (src); + are_equal = num == nm_ip4_config_get_num_routes (dst); + if (are_equal) { + for (i = 0; i < num; i++ ) { + if (nm_platform_ip4_route_cmp (src_route = nm_ip4_config_get_route (src, i), + dst_route = nm_ip4_config_get_route (dst, i))) { + are_equal = FALSE; + if (!routes_are_duplicate (src_route, dst_route, TRUE)) { + has_relevant_changes = TRUE; + break; + } + } + } + } else + has_relevant_changes = TRUE; + if (!are_equal) { + nm_ip4_config_reset_routes (dst); + for (i = 0; i < num; i++) + nm_ip4_config_add_route (dst, nm_ip4_config_get_route (src, i)); + has_minor_changes = TRUE; + } + + /* nameservers */ + num = nm_ip4_config_get_num_nameservers (src); + are_equal = num == nm_ip4_config_get_num_nameservers (dst); + if (are_equal) { + for (i = 0; i < num; i++ ) { + if (nm_ip4_config_get_nameserver (src, i) != nm_ip4_config_get_nameserver (dst, i)) { + are_equal = FALSE; + break; + } + } + } + if (!are_equal) { + nm_ip4_config_reset_nameservers (dst); + for (i = 0; i < num; i++) + nm_ip4_config_add_nameserver (dst, nm_ip4_config_get_nameserver (src, i)); + has_relevant_changes = TRUE; + } + + /* domains */ + num = nm_ip4_config_get_num_domains (src); + are_equal = num == nm_ip4_config_get_num_domains (dst); + if (are_equal) { + for (i = 0; i < num; i++ ) { + if (g_strcmp0 (nm_ip4_config_get_domain (src, i), + nm_ip4_config_get_domain (dst, i))) { + are_equal = FALSE; + break; + } + } + } + if (!are_equal) { + nm_ip4_config_reset_domains (dst); + for (i = 0; i < num; i++) + nm_ip4_config_add_domain (dst, nm_ip4_config_get_domain (src, i)); + has_relevant_changes = TRUE; + } + + /* dns searches */ + num = nm_ip4_config_get_num_searches (src); + are_equal = num == nm_ip4_config_get_num_searches (dst); + if (are_equal) { + for (i = 0; i < num; i++ ) { + if (g_strcmp0 (nm_ip4_config_get_search (src, i), + nm_ip4_config_get_search (dst, i))) { + are_equal = FALSE; + break; + } + } + } + if (!are_equal) { + nm_ip4_config_reset_searches (dst); + for (i = 0; i < num; i++) + nm_ip4_config_add_search (dst, nm_ip4_config_get_search (src, i)); + has_relevant_changes = TRUE; + } + + /* mss */ + if (src_priv->mss != dst_priv->mss) { + nm_ip4_config_set_mss (dst, src_priv->mss); + has_minor_changes = TRUE; + } + + /* nis */ + num = nm_ip4_config_get_num_nis_servers (src); + are_equal = num == nm_ip4_config_get_num_nis_servers (dst); + if (are_equal) { + for (i = 0; i < num; i++ ) { + if (nm_ip4_config_get_nis_server (src, i) != nm_ip4_config_get_nis_server (dst, i)) { + are_equal = FALSE; + break; + } + } + } + if (!are_equal) { + nm_ip4_config_reset_nis_servers (dst); + for (i = 0; i < num; i++) + nm_ip4_config_add_nis_server (dst, nm_ip4_config_get_nis_server (src, i)); + has_relevant_changes = TRUE; + } + + /* nis_domain */ + if (g_strcmp0 (src_priv->nis_domain, dst_priv->nis_domain)) { + nm_ip4_config_set_nis_domain (dst, src_priv->nis_domain); + has_relevant_changes = TRUE; + } + + /* wins */ + num = nm_ip4_config_get_num_wins (src); + are_equal = num == nm_ip4_config_get_num_wins (dst); + if (are_equal) { + for (i = 0; i < num; i++ ) { + if (nm_ip4_config_get_wins (src, i) != nm_ip4_config_get_wins (dst, i)) { + are_equal = FALSE; + break; + } + } + } + if (!are_equal) { + nm_ip4_config_reset_wins (dst); + for (i = 0; i < num; i++) + nm_ip4_config_add_wins (dst, nm_ip4_config_get_wins (src, i)); + has_relevant_changes = TRUE; + } + + /* mtu */ + if (src_priv->mtu != dst_priv->mtu) { + nm_ip4_config_set_mtu (dst, src_priv->mtu); + has_minor_changes = TRUE; + } + + /* config_equal does not compare *all* the fields, therefore, we might have has_minor_changes + * regardless of config_equal. But config_equal must correspond to has_relevant_changes. */ + g_assert (config_equal == !has_relevant_changes); - return g_slist_length (NM_IP4_CONFIG_GET_PRIVATE (config)->routes); + g_object_thaw_notify (G_OBJECT (dst)); + + if (relevant_changes) + *relevant_changes = has_relevant_changes; + + return has_relevant_changes || has_minor_changes; } -void nm_ip4_config_reset_routes (NMIP4Config *config) +void +nm_ip4_config_dump (const NMIP4Config *config, const char *detail) { - NMIP4ConfigPrivate *priv; + guint32 i, tmp; + const char *str; - g_return_if_fail (NM_IS_IP4_CONFIG (config)); + g_return_if_fail (config != NULL); - priv = NM_IP4_CONFIG_GET_PRIVATE (config); - g_slist_foreach (priv->routes, (GFunc) g_free, NULL); - priv->routes = NULL; + g_message ("--------- NMIP4Config %p (%s)", config, detail); + + str = nm_ip4_config_get_dbus_path (config); + if (str) + g_message (" path: %s", str); + + /* addresses */ + for (i = 0; i < nm_ip4_config_get_num_addresses (config); i++) + g_message (" a: %s", nm_platform_ip4_address_to_string (nm_ip4_config_get_address (config, i))); + + /* default gateway */ + tmp = nm_ip4_config_get_gateway (config); + g_message (" gw: %s", nm_utils_inet4_ntop (tmp, NULL)); + + /* nameservers */ + for (i = 0; i < nm_ip4_config_get_num_nameservers (config); i++) { + tmp = nm_ip4_config_get_nameserver (config, i); + g_message (" ns: %s", nm_utils_inet4_ntop (tmp, NULL)); + } + + /* routes */ + for (i = 0; i < nm_ip4_config_get_num_routes (config); i++) + g_message (" rt: %s", nm_platform_ip4_route_to_string (nm_ip4_config_get_route (config, i))); + + /* domains */ + for (i = 0; i < nm_ip4_config_get_num_domains (config); i++) + g_message (" domain: %s", nm_ip4_config_get_domain (config, i)); + + /* dns searches */ + for (i = 0; i < nm_ip4_config_get_num_searches (config); i++) + g_message (" search: %s", nm_ip4_config_get_search (config, i)); + + g_message (" mss: %u", nm_ip4_config_get_mss (config)); + g_message (" mtu: %u", nm_ip4_config_get_mtu (config)); + + /* NIS */ + for (i = 0; i < nm_ip4_config_get_num_nis_servers (config); i++) { + tmp = nm_ip4_config_get_nis_server (config, i); + g_message (" nis: %s", nm_utils_inet4_ntop (tmp, NULL)); + } + + g_message (" nisdmn: %s", nm_ip4_config_get_nis_domain (config)); + + /* WINS */ + for (i = 0; i < nm_ip4_config_get_num_wins (config); i++) { + tmp = nm_ip4_config_get_wins (config, i); + g_message (" wins: %s", nm_utils_inet4_ntop (tmp, NULL)); + } + + g_message (" n-dflt: %d", nm_ip4_config_get_never_default (config)); } -void nm_ip4_config_add_domain (NMIP4Config *config, const char *domain) +gboolean +nm_ip4_config_destination_is_direct (const NMIP4Config *config, guint32 network, int plen) { - NMIP4ConfigPrivate *priv; + guint naddresses = nm_ip4_config_get_num_addresses (config); int i; - g_return_if_fail (NM_IS_IP4_CONFIG (config)); - g_return_if_fail (domain != NULL); - g_return_if_fail (strlen (domain) > 0); - - priv = NM_IP4_CONFIG_GET_PRIVATE (config); + for (i = 0; i < naddresses; i++) { + const NMPlatformIP4Address *item = nm_ip4_config_get_address (config, i); - for (i = 0; i < priv->domains->len; i++) { - if (!strcmp (g_ptr_array_index (priv->domains, i), domain)) - return; + if (item->plen <= plen && same_prefix (item->address, network, item->plen)) + return TRUE; } - g_ptr_array_add (priv->domains, g_strdup (domain)); + return FALSE; } -const char *nm_ip4_config_get_domain (NMIP4Config *config, guint i) +/******************************************************************/ + +void +nm_ip4_config_set_never_default (NMIP4Config *config, gboolean never_default) { - g_return_val_if_fail (NM_IS_IP4_CONFIG (config), NULL); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - return (const char *) g_ptr_array_index (NM_IP4_CONFIG_GET_PRIVATE (config)->domains, i); + priv->never_default = !!never_default; } -guint32 nm_ip4_config_get_num_domains (NMIP4Config *config) +gboolean +nm_ip4_config_get_never_default (const NMIP4Config *config) { - g_return_val_if_fail (NM_IS_IP4_CONFIG (config), 0); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - return NM_IP4_CONFIG_GET_PRIVATE (config)->domains->len; + return priv->never_default; } -void nm_ip4_config_reset_domains (NMIP4Config *config) +void +nm_ip4_config_set_gateway (NMIP4Config *config, guint32 gateway) { - NMIP4ConfigPrivate *priv; - int i; + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - g_return_if_fail (NM_IS_IP4_CONFIG (config)); + if (priv->gateway != gateway) { + priv->gateway = gateway; + _NOTIFY (config, PROP_GATEWAY); + } +} - priv = NM_IP4_CONFIG_GET_PRIVATE (config); - for (i = 0; i < priv->domains->len; i++) - g_free (g_ptr_array_index (priv->domains, i)); - g_ptr_array_free (priv->domains, TRUE); - priv->domains = g_ptr_array_sized_new (3); +guint32 +nm_ip4_config_get_gateway (const NMIP4Config *config) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + + return priv->gateway; } -void nm_ip4_config_add_search (NMIP4Config *config, const char *search) +/******************************************************************/ + +void +nm_ip4_config_reset_addresses (NMIP4Config *config) { - NMIP4ConfigPrivate *priv; - int i; + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - g_return_if_fail (config != NULL); - g_return_if_fail (search != NULL); - g_return_if_fail (strlen (search) > 0); + if (priv->addresses->len != 0) { + g_array_set_size (priv->addresses, 0); + _NOTIFY (config, PROP_ADDRESSES); + } +} - priv = NM_IP4_CONFIG_GET_PRIVATE (config); +/** + * nm_ip4_config_add_address: + * @config: the #NMIP4Config + * @new: the new address to add to @config + * + * Adds the new address to @config. If an address with the same basic properties + * (address, prefix) already exists in @config, it is overwritten with the + * lifetime and preferred of @new. The source is also overwritten by the source + * from @new if that source is higher priority. + */ +void +nm_ip4_config_add_address (NMIP4Config *config, const NMPlatformIP4Address *new) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMPlatformIP4Address item_old; + int i; - for (i = 0; i < priv->searches->len; i++) { - if (!strcmp (g_ptr_array_index (priv->searches, i), search)) - return; + g_return_if_fail (new != NULL); + + for (i = 0; i < priv->addresses->len; i++ ) { + NMPlatformIP4Address *item = &g_array_index (priv->addresses, NMPlatformIP4Address, i); + + if (addresses_are_duplicate (item, new, FALSE)) { + if (nm_platform_ip4_address_cmp (item, new) == 0) + return; + + /* remember the old values. */ + item_old = *item; + /* Copy over old item to get new lifetime, timestamp, preferred */ + *item = *new; + + /* But restore highest priority source */ + item->source = MAX (item_old.source, new->source); + + /* for addresses that we read from the kernel, we keep the timestamps as defined + * by the previous source (item_old). The reason is, that the other source configured the lifetimes + * with "what should be" and the kernel values are "what turned out after configuring it". + * + * For other sources, the longer lifetime wins. */ + if ( (new->source == NM_PLATFORM_SOURCE_KERNEL && new->source != item_old.source) + || nm_platform_ip_address_cmp_expiry ((const NMPlatformIPAddress *) &item_old, (const NMPlatformIPAddress *) new) > 0) { + item->timestamp = item_old.timestamp; + item->lifetime = item_old.lifetime; + item->preferred = item_old.preferred; + } + if (nm_platform_ip4_address_cmp (&item_old, item) == 0) + return; + goto NOTIFY; + } } - g_ptr_array_add (priv->searches, g_strdup (search)); + g_array_append_val (priv->addresses, *new); +NOTIFY: + _NOTIFY (config, PROP_ADDRESSES); } -const char *nm_ip4_config_get_search (NMIP4Config *config, guint i) +void +nm_ip4_config_del_address (NMIP4Config *config, guint i) { - g_return_val_if_fail (config != NULL, NULL); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + + g_return_if_fail (i < priv->addresses->len); - return (const char *) g_ptr_array_index (NM_IP4_CONFIG_GET_PRIVATE (config)->searches, i); + g_array_remove_index (priv->addresses, i); + _NOTIFY (config, PROP_ADDRESSES); } -guint32 nm_ip4_config_get_num_searches (NMIP4Config *config) +guint +nm_ip4_config_get_num_addresses (const NMIP4Config *config) { - g_return_val_if_fail (config != NULL, 0); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - return NM_IP4_CONFIG_GET_PRIVATE (config)->searches->len; + return priv->addresses->len; } -void nm_ip4_config_reset_searches (NMIP4Config *config) +const NMPlatformIP4Address * +nm_ip4_config_get_address (const NMIP4Config *config, guint i) { - NMIP4ConfigPrivate *priv; - int i; + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - g_return_if_fail (NM_IS_IP4_CONFIG (config)); + return &g_array_index (priv->addresses, NMPlatformIP4Address, i); +} - priv = NM_IP4_CONFIG_GET_PRIVATE (config); - for (i = 0; i < priv->searches->len; i++) - g_free (g_ptr_array_index (priv->searches, i)); - g_ptr_array_free (priv->searches, TRUE); - priv->searches = g_ptr_array_sized_new (3); +gboolean +nm_ip4_config_address_exists (const NMIP4Config *config, + const NMPlatformIP4Address *needle) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + guint i; + + for (i = 0; i < priv->addresses->len; i++) { + const NMPlatformIP4Address *haystack = &g_array_index (priv->addresses, NMPlatformIP4Address, i); + + if (needle->address == haystack->address && needle->plen == haystack->plen) + return TRUE; + } + return FALSE; } -guint32 nm_ip4_config_get_mtu (NMIP4Config *config) +/******************************************************************/ + +void +nm_ip4_config_reset_routes (NMIP4Config *config) { - g_return_val_if_fail (NM_IS_IP4_CONFIG (config), 0); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - return NM_IP4_CONFIG_GET_PRIVATE (config)->mtu; + if (priv->routes->len != 0) { + g_array_set_size (priv->routes, 0); + _NOTIFY (config, PROP_ROUTES); + } } -void nm_ip4_config_set_mtu (NMIP4Config *config, guint32 mtu) +/** + * nm_ip4_config_add_route: + * @config: the #NMIP4Config + * @new: the new route to add to @config + * + * Adds the new route to @config. If a route with the same basic properties + * (network, prefix) already exists in @config, it is overwritten including the + * gateway and metric of @new. The source is also overwritten by the source + * from @new if that source is higher priority. + */ +void +nm_ip4_config_add_route (NMIP4Config *config, const NMPlatformIP4Route *new) { - g_return_if_fail (NM_IS_IP4_CONFIG (config)); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMPlatformSource old_source; + int i; + + g_return_if_fail (new != NULL); + + for (i = 0; i < priv->routes->len; i++ ) { + NMPlatformIP4Route *item = &g_array_index (priv->routes, NMPlatformIP4Route, i); - NM_IP4_CONFIG_GET_PRIVATE (config)->mtu = mtu; + if (routes_are_duplicate (item, new, FALSE)) { + if (nm_platform_ip4_route_cmp (item, new) == 0) + return; + old_source = item->source; + memcpy (item, new, sizeof (*item)); + /* Restore highest priority source */ + item->source = MAX (old_source, new->source); + goto NOTIFY; + } + } + + g_array_append_val (priv->routes, *new); +NOTIFY: + _NOTIFY (config, PROP_ROUTES); } -guint32 nm_ip4_config_get_mss (NMIP4Config *config) +void +nm_ip4_config_del_route (NMIP4Config *config, guint i) { - g_return_val_if_fail (NM_IS_IP4_CONFIG (config), 0); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + + g_return_if_fail (i < priv->routes->len); - return NM_IP4_CONFIG_GET_PRIVATE (config)->mss; + g_array_remove_index (priv->routes, i); + _NOTIFY (config, PROP_ROUTES); } -void nm_ip4_config_set_mss (NMIP4Config *config, guint32 mss) +guint +nm_ip4_config_get_num_routes (const NMIP4Config *config) { - g_return_if_fail (NM_IS_IP4_CONFIG (config)); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - NM_IP4_CONFIG_GET_PRIVATE (config)->mss = mss; + return priv->routes->len; } -gboolean -nm_ip4_config_get_never_default (NMIP4Config *config) +const NMPlatformIP4Route * +nm_ip4_config_get_route (const NMIP4Config *config, guint i) { - g_return_val_if_fail (NM_IS_IP4_CONFIG (config), FALSE); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - return NM_IP4_CONFIG_GET_PRIVATE (config)->never_default; + return &g_array_index (priv->routes, NMPlatformIP4Route, i); } +/******************************************************************/ + void -nm_ip4_config_set_never_default (NMIP4Config *config, gboolean never_default) +nm_ip4_config_reset_nameservers (NMIP4Config *config) { - g_return_if_fail (NM_IS_IP4_CONFIG (config)); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - NM_IP4_CONFIG_GET_PRIVATE (config)->never_default = never_default; + if (priv->nameservers->len != 0) { + g_array_set_size (priv->nameservers, 0); + _NOTIFY (config, PROP_NAMESERVERS); + } } -void nm_ip4_config_add_nis_server (NMIP4Config *config, guint32 nis) +void +nm_ip4_config_add_nameserver (NMIP4Config *config, guint32 new) { - NMIP4ConfigPrivate *priv; + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); int i; - g_return_if_fail (NM_IS_IP4_CONFIG (config)); - g_return_if_fail (nis > 0); - - priv = NM_IP4_CONFIG_GET_PRIVATE (config); - for (i = 0; i < priv->nis->len; i++) { - guint32 s = g_array_index (priv->nis, guint32, i); + g_return_if_fail (new != 0); - /* No dupes */ - g_return_if_fail (nis != s); - } + for (i = 0; i < priv->nameservers->len; i++) + if (new == g_array_index (priv->nameservers, guint32, i)) + return; - g_array_append_val (priv->nis, nis); + g_array_append_val (priv->nameservers, new); + _NOTIFY (config, PROP_NAMESERVERS); } -guint32 nm_ip4_config_get_nis_server (NMIP4Config *config, guint i) +void +nm_ip4_config_del_nameserver (NMIP4Config *config, guint i) { - g_return_val_if_fail (NM_IS_IP4_CONFIG (config), 0); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + + g_return_if_fail (i < priv->nameservers->len); - return g_array_index (NM_IP4_CONFIG_GET_PRIVATE (config)->nis, guint32, i); + g_array_remove_index (priv->nameservers, i); + _NOTIFY (config, PROP_NAMESERVERS); } -guint32 nm_ip4_config_get_num_nis_servers (NMIP4Config *config) +guint32 +nm_ip4_config_get_num_nameservers (const NMIP4Config *config) { - g_return_val_if_fail (NM_IS_IP4_CONFIG (config), 0); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - return NM_IP4_CONFIG_GET_PRIVATE (config)->nis->len; + return priv->nameservers->len; } -void nm_ip4_config_reset_nis_servers (NMIP4Config *config) +guint32 +nm_ip4_config_get_nameserver (const NMIP4Config *config, guint i) { - NMIP4ConfigPrivate *priv; - - g_return_if_fail (NM_IS_IP4_CONFIG (config)); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - priv = NM_IP4_CONFIG_GET_PRIVATE (config); - if (priv->nis->len) - g_array_remove_range (priv->nis, 0, priv->nis->len); + return g_array_index (priv->nameservers, guint32, i); } +/******************************************************************/ + void -nm_ip4_config_set_nis_domain (NMIP4Config *config, const char *domain) +nm_ip4_config_reset_domains (NMIP4Config *config) { - NMIP4ConfigPrivate *priv; - - g_return_if_fail (NM_IS_IP4_CONFIG (config)); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - priv = NM_IP4_CONFIG_GET_PRIVATE (config); - g_free (priv->nis_domain); - priv->nis_domain = g_strdup (domain); + if (priv->domains->len != 0) { + g_ptr_array_set_size (priv->domains, 0); + _NOTIFY (config, PROP_DOMAINS); + } } -const char * -nm_ip4_config_get_nis_domain (NMIP4Config *config) +void +nm_ip4_config_add_domain (NMIP4Config *config, const char *domain) { - g_return_val_if_fail (NM_IS_IP4_CONFIG (config), 0); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + int i; - return NM_IP4_CONFIG_GET_PRIVATE (config)->nis_domain; -} + g_return_if_fail (domain != NULL); + g_return_if_fail (domain[0] != '\0'); -/* libnl convenience/conversion functions */ + for (i = 0; i < priv->domains->len; i++) + if (!g_strcmp0 (g_ptr_array_index (priv->domains, i), domain)) + return; -static int ip4_addr_to_rtnl_local (guint32 ip4_address, struct rtnl_addr *addr) + g_ptr_array_add (priv->domains, g_strdup (domain)); + _NOTIFY (config, PROP_DOMAINS); +} + +void +nm_ip4_config_del_domain (NMIP4Config *config, guint i) { - struct nl_addr * local = NULL; - int err = 0; + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + + g_return_if_fail (i < priv->domains->len); - g_return_val_if_fail (addr != NULL, -1); + g_ptr_array_remove_index (priv->domains, i); + _NOTIFY (config, PROP_DOMAINS); +} - local = nm_utils_ip4_addr_to_nl_addr (ip4_address); - err = rtnl_addr_set_local (addr, local); - nl_addr_put (local); +guint32 +nm_ip4_config_get_num_domains (const NMIP4Config *config) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - return err; + return priv->domains->len; } -static int ip4_addr_to_rtnl_peer (guint32 ip4_address, struct rtnl_addr *addr) +const char * +nm_ip4_config_get_domain (const NMIP4Config *config, guint i) { - struct nl_addr * peer = NULL; - int err = 0; + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - g_return_val_if_fail (addr != NULL, -1); + return g_ptr_array_index (priv->domains, i); +} - peer = nm_utils_ip4_addr_to_nl_addr (ip4_address); - err = rtnl_addr_set_peer (addr, peer); - nl_addr_put (peer); +/******************************************************************/ - return err; +void +nm_ip4_config_reset_searches (NMIP4Config *config) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + + if (priv->searches->len != 0) { + g_ptr_array_set_size (priv->searches, 0); + _NOTIFY (config, PROP_SEARCHES); + } } -static int ip4_addr_to_rtnl_broadcast (guint32 ip4_broadcast, struct rtnl_addr *addr) +void +nm_ip4_config_add_search (NMIP4Config *config, const char *new) { - struct nl_addr * local = NULL; - int err = 0; + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + int i; - g_return_val_if_fail (addr != NULL, -1); + g_return_if_fail (new != NULL); + g_return_if_fail (new[0] != '\0'); - local = nm_utils_ip4_addr_to_nl_addr (ip4_broadcast); - err = rtnl_addr_set_broadcast (addr, local); - nl_addr_put (local); + for (i = 0; i < priv->searches->len; i++) + if (!g_strcmp0 (g_ptr_array_index (priv->searches, i), new)) + return; - return err; + g_ptr_array_add (priv->searches, g_strdup (new)); + _NOTIFY (config, PROP_SEARCHES); } - -struct rtnl_addr * -nm_ip4_config_to_rtnl_addr (NMIP4Config *config, guint32 i, guint32 flags) +void +nm_ip4_config_del_search (NMIP4Config *config, guint i) { NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - NMIP4Address *config_addr; - struct rtnl_addr *addr; - gboolean success = TRUE; - g_return_val_if_fail (NM_IS_IP4_CONFIG (config), NULL); + g_return_if_fail (i < priv->searches->len); - config_addr = nm_ip4_config_get_address (config, i); - g_return_val_if_fail (config_addr != NULL, NULL); + g_ptr_array_remove_index (priv->searches, i); + _NOTIFY (config, PROP_SEARCHES); +} - if (!(addr = rtnl_addr_alloc())) - return NULL; +guint32 +nm_ip4_config_get_num_searches (const NMIP4Config *config) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - if (flags & NM_RTNL_ADDR_ADDR) - success = (ip4_addr_to_rtnl_local (nm_ip4_address_get_address (config_addr), addr) >= 0); + return priv->searches->len; +} - if (flags & NM_RTNL_ADDR_PTP_ADDR) - success = (ip4_addr_to_rtnl_peer (priv->ptp_address, addr) >= 0); +const char * +nm_ip4_config_get_search (const NMIP4Config *config, guint i) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - if (flags & NM_RTNL_ADDR_PREFIX) - rtnl_addr_set_prefixlen (addr, nm_ip4_address_get_prefix (config_addr)); + return g_ptr_array_index (priv->searches, i); +} - if (flags & NM_RTNL_ADDR_BROADCAST) { - guint32 hostmask, network, bcast, netmask; +/******************************************************************/ - netmask = nm_utils_ip4_prefix_to_netmask (nm_ip4_address_get_prefix (config_addr)); - network = ntohl (nm_ip4_address_get_address (config_addr)) & ntohl (netmask); - hostmask = ~ntohl (netmask); - bcast = htonl (network | hostmask); +void +nm_ip4_config_set_mss (NMIP4Config *config, guint32 mss) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - success = (ip4_addr_to_rtnl_broadcast (bcast, addr) >= 0); - } + priv->mss = mss; +} - if (!success) { - rtnl_addr_put (addr); - addr = NULL; - } +guint32 +nm_ip4_config_get_mss (const NMIP4Config *config) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - return addr; + return priv->mss; } -static gboolean -addr_slist_compare (GSList *a, GSList *b) +/******************************************************************/ + +void +nm_ip4_config_reset_nis_servers (NMIP4Config *config) { - GSList *iter_a, *iter_b; - gboolean found = FALSE; + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - for (iter_a = a; iter_a; iter_a = g_slist_next (iter_a)) { - NMIP4Address *addr_a = (NMIP4Address *) iter_a->data; + g_array_set_size (priv->nis, 0); +} - for (iter_b = b, found = FALSE; iter_b; iter_b = g_slist_next (iter_b)) { - NMIP4Address *addr_b = (NMIP4Address *) iter_b->data; +void +nm_ip4_config_add_nis_server (NMIP4Config *config, guint32 nis) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + int i; - if (nm_ip4_address_compare (addr_a, addr_b)) { - found = TRUE; - break; - } - } + for (i = 0; i < priv->nis->len; i++) + if (nis == g_array_index (priv->nis, guint32, i)) + return; - if (!found) - return FALSE; - } - return TRUE; + g_array_append_val (priv->nis, nis); } -static gboolean -route_slist_compare (GSList *a, GSList *b) +void +nm_ip4_config_del_nis_server (NMIP4Config *config, guint i) { - GSList *iter_a, *iter_b; - gboolean found = FALSE; + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - for (iter_a = a; iter_a; iter_a = g_slist_next (iter_a)) { - NMIP4Route *route_a = (NMIP4Route *) iter_a->data; + g_return_if_fail (i < priv->nis->len); - for (iter_b = b, found = FALSE; iter_b; iter_b = g_slist_next (iter_b)) { - NMIP4Route *route_b = (NMIP4Route *) iter_b->data; + g_array_remove_index (priv->nis, i); +} - if (nm_ip4_route_compare (route_a, route_b)) { - found = TRUE; - break; - } - } +guint32 +nm_ip4_config_get_num_nis_servers (const NMIP4Config *config) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - if (!found) - return FALSE; - } - return TRUE; + return priv->nis->len; } -static gboolean -string_array_compare (GPtrArray *a, GPtrArray *b) +guint32 +nm_ip4_config_get_nis_server (const NMIP4Config *config, guint i) { - int i, j; - gboolean found = FALSE; + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - for (i = 0; i < a->len; i++) { - for (j = 0, found = FALSE; j < b->len; j++) { - const char *item_a = g_ptr_array_index (a, i); - const char *item_b = g_ptr_array_index (b, j); + return g_array_index (priv->nis, guint32, i); +} - if ((!item_a && !item_b) || (item_a && item_b && !strcmp (item_a, item_b))) { - found = TRUE; - break; - } - } +void +nm_ip4_config_set_nis_domain (NMIP4Config *config, const char *domain) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - if (!found) - return FALSE; - } - return TRUE; + g_free (priv->nis_domain); + priv->nis_domain = g_strdup (domain); } -static gboolean -addr_array_compare (GArray *a, GArray *b) +const char * +nm_ip4_config_get_nis_domain (const NMIP4Config *config) { - int i, j; - gboolean found = FALSE; + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - for (i = 0; i < a->len; i++) { - for (j = 0, found = FALSE; j < b->len; j++) { - if (g_array_index (a, guint32, i) == g_array_index (b, guint32, j)) { - found = TRUE; - break; - } - } + return priv->nis_domain; +} - if (!found) - return FALSE; +/******************************************************************/ + +void +nm_ip4_config_reset_wins (NMIP4Config *config) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + + if (priv->wins->len != 0) { + g_array_set_size (priv->wins, 0); + _NOTIFY (config, PROP_WINS_SERVERS); } - return TRUE; } -NMIP4ConfigCompareFlags -nm_ip4_config_diff (NMIP4Config *a, NMIP4Config *b) +void +nm_ip4_config_add_wins (NMIP4Config *config, guint32 wins) { - NMIP4ConfigPrivate *a_priv; - NMIP4ConfigPrivate *b_priv; - NMIP4ConfigCompareFlags flags = NM_IP4_COMPARE_FLAG_NONE; + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + int i; - if ((a && !b) || (b && !a)) - return NM_IP4_COMPARE_FLAG_ALL; - if (!a && !b) - return NM_IP4_COMPARE_FLAG_NONE; + g_return_if_fail (wins != 0); - a_priv = NM_IP4_CONFIG_GET_PRIVATE (a); - b_priv = NM_IP4_CONFIG_GET_PRIVATE (b); + for (i = 0; i < priv->wins->len; i++) + if (wins == g_array_index (priv->wins, guint32, i)) + return; - if ( !addr_slist_compare (a_priv->addresses, b_priv->addresses) - || !addr_slist_compare (b_priv->addresses, a_priv->addresses)) - flags |= NM_IP4_COMPARE_FLAG_ADDRESSES; + g_array_append_val (priv->wins, wins); + _NOTIFY (config, PROP_WINS_SERVERS); +} - if (a_priv->ptp_address != b_priv->ptp_address) - flags |= NM_IP4_COMPARE_FLAG_PTP_ADDRESS; +void +nm_ip4_config_del_wins (NMIP4Config *config, guint i) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - if ( (a_priv->nameservers->len != b_priv->nameservers->len) - || !addr_array_compare (a_priv->nameservers, b_priv->nameservers) - || !addr_array_compare (b_priv->nameservers, a_priv->nameservers)) - flags |= NM_IP4_COMPARE_FLAG_NAMESERVERS; + g_return_if_fail (i < priv->wins->len); - if ( (a_priv->wins->len != b_priv->wins->len) - || !addr_array_compare (a_priv->wins, b_priv->wins) - || !addr_array_compare (b_priv->wins, a_priv->wins)) - flags |= NM_IP4_COMPARE_FLAG_WINS_SERVERS; + g_array_remove_index (priv->wins, i); + _NOTIFY (config, PROP_WINS_SERVERS); +} - if ( (a_priv->nis->len != b_priv->nis->len) - || !addr_array_compare (a_priv->nis, b_priv->nis) - || !addr_array_compare (b_priv->nis, a_priv->nis)) - flags |= NM_IP4_COMPARE_FLAG_NIS_SERVERS; +guint32 +nm_ip4_config_get_num_wins (const NMIP4Config *config) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - if ( (a_priv->nis_domain || b_priv->nis_domain) - && (g_strcmp0 (a_priv->nis_domain, b_priv->nis_domain) != 0)) - flags |= NM_IP4_COMPARE_FLAG_NIS_DOMAIN; + return priv->wins->len; +} - if ( !route_slist_compare (a_priv->routes, b_priv->routes) - || !route_slist_compare (b_priv->routes, a_priv->routes)) - flags |= NM_IP4_COMPARE_FLAG_ROUTES; +guint32 +nm_ip4_config_get_wins (const NMIP4Config *config, guint i) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - if ( (a_priv->domains->len != b_priv->domains->len) - || !string_array_compare (a_priv->domains, b_priv->domains) - || !string_array_compare (b_priv->domains, a_priv->domains)) - flags |= NM_IP4_COMPARE_FLAG_DOMAINS; + return g_array_index (priv->wins, guint32, i); +} - if ( (a_priv->searches->len != b_priv->searches->len) - || !string_array_compare (a_priv->searches, b_priv->searches) - || !string_array_compare (b_priv->searches, a_priv->searches)) - flags |= NM_IP4_COMPARE_FLAG_SEARCHES; +/******************************************************************/ - if (a_priv->mtu != b_priv->mtu) - flags |= NM_IP4_COMPARE_FLAG_MTU; +void +nm_ip4_config_set_mtu (NMIP4Config *config, guint32 mtu) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - if (a_priv->mss != b_priv->mss) - flags |= NM_IP4_COMPARE_FLAG_MSS; + priv->mtu = mtu; +} + +guint32 +nm_ip4_config_get_mtu (const NMIP4Config *config) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - return flags; + return priv->mtu; } +/******************************************************************/ + static inline void hash_u32 (GChecksum *sum, guint32 n) { @@ -820,36 +1527,32 @@ hash_u32 (GChecksum *sum, guint32 n) } void -nm_ip4_config_hash (NMIP4Config *config, GChecksum *sum, gboolean dns_only) +nm_ip4_config_hash (const NMIP4Config *config, GChecksum *sum, gboolean dns_only) { - guint32 i, n; + guint32 i; const char *s; - g_return_if_fail (config != NULL); - g_return_if_fail (sum != NULL); + g_return_if_fail (config); + g_return_if_fail (sum); - if (dns_only == FALSE) { - for (i = 0; i < nm_ip4_config_get_num_addresses (config); i++) { - NMIP4Address *a = nm_ip4_config_get_address (config, i); + if (!dns_only) { + hash_u32 (sum, nm_ip4_config_get_gateway (config)); - hash_u32 (sum, nm_ip4_address_get_address (a)); - hash_u32 (sum, nm_ip4_address_get_prefix (a)); - hash_u32 (sum, nm_ip4_address_get_gateway (a)); + for (i = 0; i < nm_ip4_config_get_num_addresses (config); i++) { + const NMPlatformIP4Address *address = nm_ip4_config_get_address (config, i); + hash_u32 (sum, address->address); + hash_u32 (sum, address->plen); } for (i = 0; i < nm_ip4_config_get_num_routes (config); i++) { - NMIP4Route *r = nm_ip4_config_get_route (config, i); + const NMPlatformIP4Route *route = nm_ip4_config_get_route (config, i); - hash_u32 (sum, nm_ip4_route_get_dest (r)); - hash_u32 (sum, nm_ip4_route_get_prefix (r)); - hash_u32 (sum, nm_ip4_route_get_next_hop (r)); - hash_u32 (sum, nm_ip4_route_get_metric (r)); + hash_u32 (sum, route->network); + hash_u32 (sum, route->plen); + hash_u32 (sum, route->gateway); + hash_u32 (sum, route->metric); } - n = nm_ip4_config_get_ptp_address (config); - if (n) - hash_u32 (sum, n); - for (i = 0; i < nm_ip4_config_get_num_nis_servers (config); i++) hash_u32 (sum, nm_ip4_config_get_nis_server (config, i)); @@ -875,16 +1578,60 @@ nm_ip4_config_hash (NMIP4Config *config, GChecksum *sum, gboolean dns_only) } } +/** + * nm_ip4_config_equal: + * @a: first config to compare + * @b: second config to compare + * + * Compares two #NMIP4Configs for basic equality. This means that all + * attributes must exist in the same order in both configs (addresses, routes, + * domains, DNS servers, etc) but some attributes (address lifetimes, and address + * and route sources) are ignored. + * + * Returns: %TRUE if the configurations are basically equal to each other, + * %FALSE if not + */ +gboolean +nm_ip4_config_equal (const NMIP4Config *a, const NMIP4Config *b) +{ + GChecksum *a_checksum = g_checksum_new (G_CHECKSUM_SHA1); + GChecksum *b_checksum = g_checksum_new (G_CHECKSUM_SHA1); + gsize a_len = g_checksum_type_get_length (G_CHECKSUM_SHA1); + gsize b_len = g_checksum_type_get_length (G_CHECKSUM_SHA1); + guchar a_data[a_len], b_data[b_len]; + gboolean equal; + + if (a) + nm_ip4_config_hash (a, a_checksum, FALSE); + if (b) + nm_ip4_config_hash (b, b_checksum, FALSE); + + g_checksum_get_digest (a_checksum, a_data, &a_len); + g_checksum_get_digest (b_checksum, b_data, &b_len); + + g_assert (a_len == b_len); + equal = !memcmp (a_data, b_data, a_len); + + g_checksum_free (a_checksum); + g_checksum_free (b_checksum); + + return equal; +} + +/******************************************************************/ + static void nm_ip4_config_init (NMIP4Config *config) { NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - priv->nameservers = g_array_new (FALSE, TRUE, sizeof (guint32)); - priv->wins = g_array_new (FALSE, TRUE, sizeof (guint32)); - priv->domains = g_ptr_array_sized_new (3); - priv->searches = g_ptr_array_sized_new (3); + priv->addresses = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP4Address)); + priv->routes = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP4Route)); + priv->nameservers = g_array_new (FALSE, FALSE, sizeof (guint32)); + priv->domains = g_ptr_array_new_with_free_func (g_free); + priv->searches = g_ptr_array_new_with_free_func (g_free); priv->nis = g_array_new (FALSE, TRUE, sizeof (guint32)); + priv->wins = g_array_new (FALSE, TRUE, sizeof (guint32)); } static void @@ -892,14 +1639,14 @@ finalize (GObject *object) { NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (object); - nm_utils_slist_free (priv->addresses, (GDestroyNotify) nm_ip4_address_unref); - nm_utils_slist_free (priv->routes, (GDestroyNotify) nm_ip4_route_unref); - g_array_free (priv->wins, TRUE); - g_array_free (priv->nameservers, TRUE); - g_ptr_array_free (priv->domains, TRUE); - g_ptr_array_free (priv->searches, TRUE); - g_array_free (priv->nis, TRUE); + g_array_unref (priv->addresses); + g_array_unref (priv->routes); + g_array_unref (priv->nameservers); + g_ptr_array_unref (priv->domains); + g_ptr_array_unref (priv->searches); + g_array_unref (priv->nis); g_free (priv->nis_domain); + g_array_unref (priv->wins); G_OBJECT_CLASS (nm_ip4_config_parent_class)->finalize (object); } @@ -908,11 +1655,56 @@ static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { + NMIP4Config *config = NM_IP4_CONFIG (object); NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (object); switch (prop_id) { + case PROP_GATEWAY: + if (priv->gateway) + g_value_set_string (value, nm_utils_inet4_ntop (priv->gateway, NULL)); + else + g_value_set_string (value, NULL); + break; case PROP_ADDRESSES: - nm_utils_ip4_addresses_to_gvalue (priv->addresses, value); + { + GPtrArray *addresses = g_ptr_array_new (); + int naddr = nm_ip4_config_get_num_addresses (config); + int i; + + for (i = 0; i < naddr; i++) { + const NMPlatformIP4Address *address = nm_ip4_config_get_address (config, i); + GArray *array = g_array_sized_new (FALSE, TRUE, sizeof (guint32), 3); + + g_array_append_val (array, address->address); + g_array_append_val (array, address->plen); + g_array_append_val (array, priv->gateway); + + g_ptr_array_add (addresses, array); + } + + g_value_take_boxed (value, addresses); + } + break; + case PROP_ROUTES: + { + GPtrArray *routes = g_ptr_array_new (); + guint nroutes = nm_ip4_config_get_num_routes (config); + int i; + + for (i = 0; i < nroutes; i++) { + const NMPlatformIP4Route *route = nm_ip4_config_get_route (config, i); + GArray *array = g_array_sized_new (FALSE, TRUE, sizeof (guint32), 4); + + g_array_append_val (array, route->network); + g_array_append_val (array, route->plen); + g_array_append_val (array, route->gateway); + g_array_append_val (array, route->metric); + + g_ptr_array_add (routes, array); + } + + g_value_take_boxed (value, routes); + } break; case PROP_NAMESERVERS: g_value_set_boxed (value, priv->nameservers); @@ -920,8 +1712,8 @@ get_property (GObject *object, guint prop_id, case PROP_DOMAINS: g_value_set_boxed (value, priv->domains); break; - case PROP_ROUTES: - nm_utils_ip4_routes_to_gvalue (priv->routes, value); + case PROP_SEARCHES: + g_value_set_boxed (value, priv->searches); break; case PROP_WINS_SERVERS: g_value_set_boxed (value, priv->wins); @@ -939,47 +1731,55 @@ nm_ip4_config_class_init (NMIP4ConfigClass *config_class) g_type_class_add_private (config_class, sizeof (NMIP4ConfigPrivate)); - /* virtual methods */ object_class->get_property = get_property; object_class->finalize = finalize; - /* properties */ - g_object_class_install_property - (object_class, PROP_ADDRESSES, + obj_properties[PROP_GATEWAY] = + g_param_spec_string (NM_IP4_CONFIG_GATEWAY, + "Gateway", + "IP4 gateway", + NULL, + G_PARAM_READABLE); + obj_properties[PROP_ADDRESSES] = g_param_spec_boxed (NM_IP4_CONFIG_ADDRESSES, - "Addresses", - "IP4 addresses", - DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT, - G_PARAM_READABLE)); - g_object_class_install_property - (object_class, PROP_NAMESERVERS, + "Addresses", + "IP4 addresses", + DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT, + G_PARAM_READABLE); + obj_properties[PROP_ROUTES] = + g_param_spec_boxed (NM_IP4_CONFIG_ROUTES, + "Routes", + "Routes", + DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT, + G_PARAM_READABLE); + obj_properties[PROP_NAMESERVERS] = g_param_spec_boxed (NM_IP4_CONFIG_NAMESERVERS, - "Nameservers", - "DNS list", - DBUS_TYPE_G_UINT_ARRAY, - G_PARAM_READABLE)); - g_object_class_install_property - (object_class, PROP_DOMAINS, + "Nameservers", + "DNS list", + DBUS_TYPE_G_UINT_ARRAY, + G_PARAM_READABLE); + obj_properties[PROP_DOMAINS] = g_param_spec_boxed (NM_IP4_CONFIG_DOMAINS, - "Domains", - "Domains", - DBUS_TYPE_G_ARRAY_OF_STRING, - G_PARAM_READABLE)); - g_object_class_install_property - (object_class, PROP_ROUTES, - g_param_spec_boxed (NM_IP4_CONFIG_ROUTES, - "Routes", - "Routes", - DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT, - G_PARAM_READABLE)); - g_object_class_install_property - (object_class, PROP_WINS_SERVERS, + "Domains", + "Domains", + DBUS_TYPE_G_ARRAY_OF_STRING, + G_PARAM_READABLE); + obj_properties[PROP_SEARCHES] = + g_param_spec_boxed (NM_IP4_CONFIG_SEARCHES, + "Searches", + "Searches", + DBUS_TYPE_G_ARRAY_OF_STRING, + G_PARAM_READABLE); + obj_properties[PROP_WINS_SERVERS] = g_param_spec_boxed (NM_IP4_CONFIG_WINS_SERVERS, - "WinsServers", - "WINS server list", - DBUS_TYPE_G_UINT_ARRAY, - G_PARAM_READABLE)); + "WinsServers", + "WINS server list", + DBUS_TYPE_G_UINT_ARRAY, + G_PARAM_READABLE); + + g_object_class_install_properties (object_class, LAST_PROP, obj_properties); - dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (config_class), - &dbus_glib_nm_ip4_config_object_info); + nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), + G_TYPE_FROM_CLASS (config_class), + &dbus_glib_nm_ip4_config_object_info); } |