diff options
Diffstat (limited to 'libnm-core/nm-setting-ip-config.c')
-rw-r--r-- | libnm-core/nm-setting-ip-config.c | 2321 |
1 files changed, 2321 insertions, 0 deletions
diff --git a/libnm-core/nm-setting-ip-config.c b/libnm-core/nm-setting-ip-config.c new file mode 100644 index 0000000000..8db1d603c0 --- /dev/null +++ b/libnm-core/nm-setting-ip-config.c @@ -0,0 +1,2321 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright 2007 - 2014 Red Hat, Inc. + * Copyright 2007 - 2008 Novell, Inc. + */ + +#include <string.h> +#include <arpa/inet.h> +#include <glib/gi18n.h> + +#include "nm-setting-ip-config.h" +#include "nm-setting-ip4-config.h" +#include "nm-setting-ip6-config.h" +#include "nm-utils.h" +#include "nm-glib-compat.h" +#include "nm-setting-private.h" +#include "nm-utils-private.h" + +/** + * SECTION:nm-setting-ip-config + * @short_description: Abstract base class for IPv4 and IPv6 + * addressing, routing, and name service properties + * @include: nm-setting-ip-config.h + * @see_also: #NMSettingIP4Config, #NMSettingIP6Config + * + * #NMSettingIPConfig is the abstract base class of + * #NMSettingIP4Config and #NMSettingIP6Config, providing properties + * related to IP addressing, routing, and Domain Name Service. + **/ + +static char * +canonicalize_ip (int family, const char *ip, gboolean null_any) +{ + guint8 addr_bytes[sizeof (struct in6_addr)]; + char addr_str[NM_UTILS_INET_ADDRSTRLEN]; + int ret; + + if (!ip) { + g_return_val_if_fail (null_any == TRUE, NULL); + return NULL; + } + + ret = inet_pton (family, ip, addr_bytes); + g_return_val_if_fail (ret == 1, NULL); + + if (null_any) { + int addrlen = (family == AF_INET ? sizeof (struct in_addr) : sizeof (struct in6_addr)); + + if (!memcmp (addr_bytes, &in6addr_any, addrlen)) + return NULL; + } + + return g_strdup (inet_ntop (family, addr_bytes, addr_str, sizeof (addr_str))); +} + +static gboolean +valid_ip (int family, const char *ip, GError **error) +{ + if (!nm_utils_ipaddr_valid (family, ip)) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, + family == AF_INET ? _("Invalid IPv4 address '%s'") : _("Invalid IPv6 address '%s"), + ip); + return FALSE; + } else + return TRUE; +} + +static gboolean +valid_prefix (int family, guint prefix, GError **error) +{ + if ( (family == AF_INET && prefix > 32) + || (family == AF_INET6 && prefix > 128) + || prefix == 0) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, + family == AF_INET ? _("Invalid IPv4 address prefix '%u'") : _("Invalid IPv6 address prefix '%u"), + prefix); + return FALSE; + } + + return TRUE; +} + +static gboolean +valid_metric (gint64 metric, GError **error) +{ + if (metric < -1 || metric > G_MAXUINT32) { + if (error) { + char buf[64]; + + /* We can't concatenate G_GINT64_FORMAT into a translatable string */ + g_snprintf (buf, sizeof (buf), "%" G_GINT64_FORMAT, metric); + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, + _("Invalid routing metric '%s'"), buf); + } + return FALSE; + } + + return TRUE; +} + + +G_DEFINE_BOXED_TYPE (NMIPAddress, nm_ip_address, nm_ip_address_dup, nm_ip_address_unref) + +struct NMIPAddress { + guint refcount; + + char *address; + int prefix, family; + + GHashTable *attributes; +}; + +/** + * nm_ip_address_new: + * @family: the IP address family (%AF_INET or %AF_INET6) + * @addr: the IP address + * @prefix: the address prefix length + * @error: location to store error, or %NULL + * + * Creates a new #NMIPAddress object. + * + * Returns: (transfer full): the new #NMIPAddress object, or %NULL on error + **/ +NMIPAddress * +nm_ip_address_new (int family, + const char *addr, guint prefix, + GError **error) +{ + NMIPAddress *address; + + g_return_val_if_fail (family == AF_INET || family == AF_INET6, NULL); + g_return_val_if_fail (addr != NULL, NULL); + + if (!valid_ip (family, addr, error)) + return NULL; + if (!valid_prefix (family, prefix, error)) + return NULL; + + address = g_slice_new0 (NMIPAddress); + address->refcount = 1; + + address->family = family; + address->address = canonicalize_ip (family, addr, FALSE); + address->prefix = prefix; + + return address; +} + +/** + * nm_ip_address_new_binary: + * @family: the IP address family (%AF_INET or %AF_INET6) + * @addr: the IP address + * @prefix: the address prefix length + * @error: location to store error, or %NULL + * + * Creates a new #NMIPAddress object. @addr must point to a buffer of the + * correct size for @family. + * + * Returns: (transfer full): the new #NMIPAddress object, or %NULL on error + **/ +NMIPAddress * +nm_ip_address_new_binary (int family, + gconstpointer addr, guint prefix, + GError **error) +{ + NMIPAddress *address; + char string[NM_UTILS_INET_ADDRSTRLEN]; + + g_return_val_if_fail (family == AF_INET || family == AF_INET6, NULL); + g_return_val_if_fail (addr != NULL, NULL); + + if (!valid_prefix (family, prefix, error)) + return NULL; + + address = g_slice_new0 (NMIPAddress); + address->refcount = 1; + + address->family = family; + address->address = g_strdup (inet_ntop (family, addr, string, sizeof (string))); + address->prefix = prefix; + + return address; +} + +/** + * nm_ip_address_ref: + * @address: the #NMIPAddress + * + * Increases the reference count of the object. + **/ +void +nm_ip_address_ref (NMIPAddress *address) +{ + g_return_if_fail (address != NULL); + g_return_if_fail (address->refcount > 0); + + address->refcount++; +} + +/** + * nm_ip_address_unref: + * @address: the #NMIPAddress + * + * Decreases the reference count of the object. If the reference count + * reaches zero, the object will be destroyed. + **/ +void +nm_ip_address_unref (NMIPAddress *address) +{ + g_return_if_fail (address != NULL); + g_return_if_fail (address->refcount > 0); + + address->refcount--; + if (address->refcount == 0) { + g_free (address->address); + if (address->attributes) + g_hash_table_unref (address->attributes); + g_slice_free (NMIPAddress, address); + } +} + +/** + * nm_ip_address_equal: + * @address: the #NMIPAddress + * @other: the #NMIPAddress to compare @address to. + * + * Determines if two #NMIPAddress objects contain the same address and prefix + * (attributes are not compared). + * + * Returns: %TRUE if the objects contain the same values, %FALSE if they do not. + **/ +gboolean +nm_ip_address_equal (NMIPAddress *address, NMIPAddress *other) +{ + g_return_val_if_fail (address != NULL, FALSE); + g_return_val_if_fail (address->refcount > 0, FALSE); + + g_return_val_if_fail (other != NULL, FALSE); + g_return_val_if_fail (other->refcount > 0, FALSE); + + if ( address->family != other->family + || address->prefix != other->prefix + || strcmp (address->address, other->address) != 0) + return FALSE; + return TRUE; +} + +/** + * nm_ip_address_dup: + * @address: the #NMIPAddress + * + * Creates a copy of @address + * + * Returns: (transfer full): a copy of @address + **/ +NMIPAddress * +nm_ip_address_dup (NMIPAddress *address) +{ + NMIPAddress *copy; + + g_return_val_if_fail (address != NULL, NULL); + g_return_val_if_fail (address->refcount > 0, NULL); + + copy = nm_ip_address_new (address->family, + address->address, address->prefix, + NULL); + if (address->attributes) { + GHashTableIter iter; + const char *key; + GVariant *value; + + g_hash_table_iter_init (&iter, address->attributes); + while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value)) + nm_ip_address_set_attribute (copy, key, value); + } + + return copy; +} + +/** + * nm_ip_address_get_family: + * @address: the #NMIPAddress + * + * Gets the IP address family (eg, AF_INET) property of this address + * object. + * + * Returns: the IP address family + **/ +int +nm_ip_address_get_family (NMIPAddress *address) +{ + g_return_val_if_fail (address != NULL, 0); + g_return_val_if_fail (address->refcount > 0, 0); + + return address->family; +} + +/** + * nm_ip_address_get_address: + * @address: the #NMIPAddress + * + * Gets the IP address property of this address object. + * + * Returns: the IP address + **/ +const char * +nm_ip_address_get_address (NMIPAddress *address) +{ + g_return_val_if_fail (address != NULL, NULL); + g_return_val_if_fail (address->refcount > 0, NULL); + + return address->address; +} + +/** + * nm_ip_address_set_address: + * @address: the #NMIPAddress + * @addr: the IP address, as a string + * + * Sets the IP address property of this address object. + * + * @addr must be a valid address of @address's family. If you aren't sure you + * have a valid address, use nm_utils_ipaddr_valid() to check it. + **/ +void +nm_ip_address_set_address (NMIPAddress *address, + const char *addr) +{ + g_return_if_fail (address != NULL); + g_return_if_fail (addr != NULL); + g_return_if_fail (nm_utils_ipaddr_valid (address->family, addr)); + + g_free (address->address); + address->address = canonicalize_ip (address->family, addr, FALSE); +} + +/** + * nm_ip_address_get_address_binary: (skip) + * @address: the #NMIPAddress + * @addr: a buffer in which to store the address in binary format. + * + * Gets the IP address property of this address object. + * + * @addr must point to a buffer that is the correct size for @address's family. + **/ +void +nm_ip_address_get_address_binary (NMIPAddress *address, + gpointer addr) +{ + g_return_if_fail (address != NULL); + g_return_if_fail (addr != NULL); + + inet_pton (address->family, address->address, addr); +} + +/** + * nm_ip_address_set_address_binary: (skip) + * @address: the #NMIPAddress + * @addr: the address, in binary format + * + * Sets the IP address property of this address object. + * + * @addr must point to a buffer that is the correct size for @address's family. + **/ +void +nm_ip_address_set_address_binary (NMIPAddress *address, + gconstpointer addr) +{ + char string[NM_UTILS_INET_ADDRSTRLEN]; + + g_return_if_fail (address != NULL); + g_return_if_fail (addr != NULL); + + g_free (address->address); + address->address = g_strdup (inet_ntop (address->family, addr, string, sizeof (string))); +} + +/** + * nm_ip_address_get_prefix: + * @address: the #NMIPAddress + * + * Gets the IP address prefix (ie "24" or "30" etc) property of this address + * object. + * + * Returns: the IP address prefix + **/ +guint +nm_ip_address_get_prefix (NMIPAddress *address) +{ + g_return_val_if_fail (address != NULL, 0); + g_return_val_if_fail (address->refcount > 0, 0); + + return address->prefix; +} + +/** + * nm_ip_address_set_prefix: + * @address: the #NMIPAddress + * @prefix: the IP address prefix + * + * Sets the IP address prefix property of this address object. + **/ +void +nm_ip_address_set_prefix (NMIPAddress *address, + guint prefix) +{ + g_return_if_fail (address != NULL); + g_return_if_fail (valid_prefix (address->family, prefix, NULL)); + + address->prefix = prefix; +} + +/** + * nm_ip_address_get_attribute_names: + * @address: the #NMIPAddress + * + * Gets an array of attribute names defined on @address. + * + * Returns: (transfer full): a %NULL-terminated array of attribute names, + **/ +char ** +nm_ip_address_get_attribute_names (NMIPAddress *address) +{ + GHashTableIter iter; + const char *key; + GPtrArray *names; + + g_return_val_if_fail (address != NULL, NULL); + + names = g_ptr_array_new (); + + if (address->attributes) { + g_hash_table_iter_init (&iter, address->attributes); + while (g_hash_table_iter_next (&iter, (gpointer *) &key, NULL)) + g_ptr_array_add (names, g_strdup (key)); + } + g_ptr_array_add (names, NULL); + + return (char **) g_ptr_array_free (names, FALSE); +} + +/** + * nm_ip_address_get_attribute: + * @address: the #NMIPAddress + * @name: the name of an address attribute + * + * Gets the value of the attribute with name @name on @address + * + * Returns: (transfer none): the value of the attribute with name @name on + * @address, or %NULL if @address has no such attribute. + **/ +GVariant * +nm_ip_address_get_attribute (NMIPAddress *address, const char *name) +{ + g_return_val_if_fail (address != NULL, NULL); + g_return_val_if_fail (name != NULL && *name != '\0', NULL); + + if (address->attributes) + return g_hash_table_lookup (address->attributes, name); + else + return NULL; +} + +/** + * nm_ip_address_set_attribute: + * @address: the #NMIPAddress + * @name: the name of an address attribute + * @value: (transfer none) (allow-none): the value + * + * Sets or clears the named attribute on @address to the given value. + **/ +void +nm_ip_address_set_attribute (NMIPAddress *address, const char *name, GVariant *value) +{ + g_return_if_fail (address != NULL); + g_return_if_fail (name != NULL && *name != '\0'); + g_return_if_fail (strcmp (name, "address") != 0 && strcmp (name, "prefix") != 0); + + if (!address->attributes) { + address->attributes = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, (GDestroyNotify) g_variant_unref); + } + + if (value) + g_hash_table_insert (address->attributes, g_strdup (name), g_variant_ref_sink (value)); + else + g_hash_table_remove (address->attributes, name); +} + + +G_DEFINE_BOXED_TYPE (NMIPRoute, nm_ip_route, nm_ip_route_dup, nm_ip_route_unref) + +struct NMIPRoute { + guint refcount; + + int family; + char *dest; + guint prefix; + char *next_hop; + gint64 metric; + + GHashTable *attributes; +}; + +/** + * nm_ip_route_new: + * @family: the IP address family (%AF_INET or %AF_INET6) + * @dest: the IP address of the route's destination + * @prefix: the address prefix length + * @next_hop: (allow-none): the IP address of the next hop (or %NULL) + * @metric: the route metric (or -1 for "default") + * @error: location to store error, or %NULL + * + * Creates a new #NMIPRoute object. + * + * Returns: (transfer full): the new #NMIPRoute object, or %NULL on error + **/ +NMIPRoute * +nm_ip_route_new (int family, + const char *dest, + guint prefix, + const char *next_hop, + gint64 metric, + GError **error) +{ + NMIPRoute *route; + + g_return_val_if_fail (family == AF_INET || family == AF_INET6, NULL); + + if (!valid_ip (family, dest, error)) + return NULL; + if (!valid_prefix (family, prefix, error)) + return NULL; + if (next_hop && !valid_ip (family, next_hop, error)) + return NULL; + if (!valid_metric (metric, error)) + return NULL; + + route = g_slice_new0 (NMIPRoute); + route->refcount = 1; + + route->family = family; + route->dest = canonicalize_ip (family, dest, FALSE); + route->prefix = prefix; + route->next_hop = canonicalize_ip (family, next_hop, TRUE); + route->metric = metric; + + return route; +} + +/** + * nm_ip_route_new_binary: + * @family: the IP address family (%AF_INET or %AF_INET6) + * @dest: the IP address of the route's destination + * @prefix: the address prefix length + * @next_hop: (allow-none): the IP address of the next hop (or %NULL) + * @metric: the route metric (or -1 for "default") + * @error: location to store error, or %NULL + * + * Creates a new #NMIPRoute object. @dest and @next_hop (if non-%NULL) must + * point to buffers of the correct size for @family. + * + * Returns: (transfer full): the new #NMIPRoute object, or %NULL on error + **/ +NMIPRoute * +nm_ip_route_new_binary (int family, + gconstpointer dest, + guint prefix, + gconstpointer next_hop, + gint64 metric, + GError **error) +{ + NMIPRoute *route; + char string[NM_UTILS_INET_ADDRSTRLEN]; + + g_return_val_if_fail (family == AF_INET || family == AF_INET6, NULL); + + if (!valid_prefix (family, prefix, error)) + return NULL; + if (!valid_metric (metric, error)) + return NULL; + + route = g_slice_new0 (NMIPRoute); + route->refcount = 1; + + route->family = family; + route->dest = g_strdup (inet_ntop (family, dest, string, sizeof (string))); + route->prefix = prefix; + if (next_hop) + route->next_hop = g_strdup (inet_ntop (family, next_hop, string, sizeof (string))); + route->metric = metric; + + return route; +} + +/** + * nm_ip_route_ref: + * @route: the #NMIPRoute + * + * Increases the reference count of the object. + **/ +void +nm_ip_route_ref (NMIPRoute *route) +{ + g_return_if_fail (route != NULL); + g_return_if_fail (route->refcount > 0); + + route->refcount++; +} + +/** + * nm_ip_route_unref: + * @route: the #NMIPRoute + * + * Decreases the reference count of the object. If the reference count + * reaches zero, the object will be destroyed. + **/ +void +nm_ip_route_unref (NMIPRoute *route) +{ + g_return_if_fail (route != NULL); + g_return_if_fail (route->refcount > 0); + + route->refcount--; + if (route->refcount == 0) { + g_free (route->dest); + g_free (route->next_hop); + if (route->attributes) + g_hash_table_unref (route->attributes); + g_slice_free (NMIPRoute, route); + } +} + +/** + * nm_ip_route_equal: + * @route: the #NMIPRoute + * @other: the #NMIPRoute to compare @route to. + * + * Determines if two #NMIPRoute objects contain the same destination, prefix, + * next hop, and metric. (Attributes are not compared.) + * + * Returns: %TRUE if the objects contain the same values, %FALSE if they do not. + **/ +gboolean +nm_ip_route_equal (NMIPRoute *route, NMIPRoute *other) +{ + g_return_val_if_fail (route != NULL, FALSE); + g_return_val_if_fail (route->refcount > 0, FALSE); + + g_return_val_if_fail (other != NULL, FALSE); + g_return_val_if_fail (other->refcount > 0, FALSE); + + if ( route->prefix != other->prefix + || route->metric != other->metric + || strcmp (route->dest, other->dest) != 0 + || g_strcmp0 (route->next_hop, other->next_hop) != 0) + return FALSE; + return TRUE; +} + +/** + * nm_ip_route_dup: + * @route: the #NMIPRoute + * + * Creates a copy of @route + * + * Returns: (transfer full): a copy of @route + **/ +NMIPRoute * +nm_ip_route_dup (NMIPRoute *route) +{ + NMIPRoute *copy; + + g_return_val_if_fail (route != NULL, NULL); + g_return_val_if_fail (route->refcount > 0, NULL); + + copy = nm_ip_route_new (route->family, + route->dest, route->prefix, + route->next_hop, route->metric, + NULL); + if (route->attributes) { + GHashTableIter iter; + const char *key; + GVariant *value; + + g_hash_table_iter_init (&iter, route->attributes); + while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value)) + nm_ip_route_set_attribute (copy, key, value); + } + + return copy; +} + +/** + * nm_ip_route_get_family: + * @route: the #NMIPRoute + * + * Gets the IP address family (eg, AF_INET) property of this route + * object. + * + * Returns: the IP address family + **/ +int +nm_ip_route_get_family (NMIPRoute *route) +{ + g_return_val_if_fail (route != NULL, 0); + g_return_val_if_fail (route->refcount > 0, 0); + + return route->family; +} + +/** + * nm_ip_route_get_dest: + * @route: the #NMIPRoute + * + * Gets the IP destination address property of this route object. + * + * Returns: the IP address of the route's destination + **/ +const char * +nm_ip_route_get_dest (NMIPRoute *route) +{ + g_return_val_if_fail (route != NULL, NULL); + g_return_val_if_fail (route->refcount > 0, NULL); + + return route->dest; +} + +/** + * nm_ip_route_set_dest: + * @route: the #NMIPRoute + * @dest: the route's destination, as a string + * + * Sets the destination property of this route object. + * + * @dest must be a valid address of @route's family. If you aren't sure you + * have a valid address, use nm_utils_ipaddr_valid() to check it. + **/ +void +nm_ip_route_set_dest (NMIPRoute *route, + const char *dest) +{ + g_return_if_fail (route != NULL); + g_return_if_fail (dest != NULL); + g_return_if_fail (nm_utils_ipaddr_valid (route->family, dest)); + + g_free (route->dest); + route->dest = canonicalize_ip (route->family, dest, FALSE); +} + +/** + * nm_ip_route_get_dest_binary: (skip) + * @route: the #NMIPRoute + * @dest: a buffer in which to store the destination in binary format. + * + * Gets the destination property of this route object. + * + * @dest must point to a buffer that is the correct size for @route's family. + **/ +void +nm_ip_route_get_dest_binary (NMIPRoute *route, + gpointer dest) +{ + g_return_if_fail (route != NULL); + g_return_if_fail (dest != NULL); + + inet_pton (route->family, route->dest, dest); +} + +/** + * nm_ip_route_set_dest_binary: (skip) + * @route: the #NMIPRoute + * @dest: the route's destination, in binary format + * + * Sets the destination property of this route object. + * + * @dest must point to a buffer that is the correct size for @route's family. + **/ +void +nm_ip_route_set_dest_binary (NMIPRoute *route, + gconstpointer dest) +{ + char string[NM_UTILS_INET_ADDRSTRLEN]; + + g_return_if_fail (route != NULL); + g_return_if_fail (dest != NULL); + + g_free (route->dest); + route->dest = g_strdup (inet_ntop (route->family, dest, string, sizeof (string))); +} + +/** + * nm_ip_route_get_prefix: + * @route: the #NMIPRoute + * + * Gets the IP prefix (ie "24" or "30" etc) of this route. + * + * Returns: the IP prefix + **/ +guint +nm_ip_route_get_prefix (NMIPRoute *route) +{ + g_return_val_if_fail (route != NULL, 0); + g_return_val_if_fail (route->refcount > 0, 0); + + return route->prefix; +} + +/** + * nm_ip_route_set_prefix: + * @route: the #NMIPRoute + * @prefix: the route prefix + * + * Sets the prefix property of this route object. + **/ +void +nm_ip_route_set_prefix (NMIPRoute *route, + guint prefix) +{ + g_return_if_fail (route != NULL); + g_return_if_fail (valid_prefix (route->family, prefix, NULL)); + + route->prefix = prefix; +} + +/** + * nm_ip_route_get_next_hop: + * @route: the #NMIPRoute + * + * Gets the IP address of the next hop of this route; this will be %NULL if the + * route has no next hop. + * + * Returns: the IP address of the next hop, or %NULL if this is a device route. + **/ +const char * +nm_ip_route_get_next_hop (NMIPRoute *route) +{ + g_return_val_if_fail (route != NULL, NULL); + g_return_val_if_fail (route->refcount > 0, NULL); + + return route->next_hop; +} + +/** + * nm_ip_route_set_next_hop: + * @route: the #NMIPRoute + * @next_hop: (allow-none): the route's next hop, as a string + * + * Sets the next-hop property of this route object. + * + * @next_hop (if non-%NULL) must be a valid address of @route's family. If you + * aren't sure you have a valid address, use nm_utils_ipaddr_valid() to check + * it. + **/ +void +nm_ip_route_set_next_hop (NMIPRoute *route, + const char *next_hop) +{ + g_return_if_fail (route != NULL); + g_return_if_fail (!next_hop || nm_utils_ipaddr_valid (route->family, next_hop)); + + g_free (route->next_hop); + route->next_hop = canonicalize_ip (route->family, next_hop, TRUE); +} + +/** + * nm_ip_route_get_next_hop_binary: (skip) + * @route: the #NMIPRoute + * @next_hop: a buffer in which to store the next hop in binary format. + * + * Gets the next hop property of this route object. + * + * @next_hop must point to a buffer that is the correct size for @route's family. + * + * Returns: %TRUE if @route has a next hop, %FALSE if not (in which case + * @next_hop will be zeroed out) + **/ +gboolean +nm_ip_route_get_next_hop_binary (NMIPRoute *route, + gpointer next_hop) +{ + g_return_val_if_fail (route != NULL, FALSE); + g_return_val_if_fail (next_hop != NULL, FALSE); + + if (route->next_hop) { + inet_pton (route->family, route->next_hop, next_hop); + return TRUE; + } else { + memset (next_hop, 0, + route->family == AF_INET ? sizeof (struct in_addr) : sizeof (struct in6_addr)); + return FALSE; + } +} + +/** + * nm_ip_route_set_next_hop_binary: (skip) + * @route: the #NMIPRoute + * @next_hop: the route's next hop, in binary format + * + * Sets the destination property of this route object. + * + * @next_hop (if non-%NULL) must point to a buffer that is the correct size for + * @route's family. + **/ +void +nm_ip_route_set_next_hop_binary (NMIPRoute *route, + gconstpointer next_hop) +{ + char string[NM_UTILS_INET_ADDRSTRLEN]; + + g_return_if_fail (route != NULL); + + g_free (route->next_hop); + if (next_hop) + route->next_hop = g_strdup (inet_ntop (route->family, next_hop, string, sizeof (string))); + else + route->next_hop = NULL; +} + +/** + * nm_ip_route_get_metric: + * @route: the #NMIPRoute + * + * Gets the route metric property of this route object; lower values + * indicate "better" or more preferred routes; -1 indicates "default" + * (meaning NetworkManager will set it appropriately). + * + * Returns: the route metric + **/ +gint64 +nm_ip_route_get_metric (NMIPRoute *route) +{ + g_return_val_if_fail (route != NULL, 0); + g_return_val_if_fail (route->refcount > 0, 0); + + return route->metric; +} + +/** + * nm_ip_route_set_metric: + * @route: the #NMIPRoute + * @metric: the route metric (or -1 for "default") + * + * Sets the metric property of this route object. + **/ +void +nm_ip_route_set_metric (NMIPRoute *route, + gint64 metric) +{ + g_return_if_fail (route != NULL); + g_return_if_fail (valid_metric (metric, NULL)); + + route->metric = metric; +} + +/** + * nm_ip_route_get_attribute_names: + * @route: the #NMIPRoute + * + * Gets an array of attribute names defined on @route. + * + * Returns: (transfer full): a %NULL-terminated array of attribute names + **/ +char ** +nm_ip_route_get_attribute_names (NMIPRoute *route) +{ + GHashTableIter iter; + const char *key; + GPtrArray *names; + + g_return_val_if_fail (route != NULL, NULL); + + names = g_ptr_array_new (); + + if (route->attributes) { + g_hash_table_iter_init (&iter, route->attributes); + while (g_hash_table_iter_next (&iter, (gpointer *) &key, NULL)) + g_ptr_array_add (names, g_strdup (key)); + } + g_ptr_array_add (names, NULL); + + return (char **) g_ptr_array_free (names, FALSE); +} + +/** + * nm_ip_route_get_attribute: + * @route: the #NMIPRoute + * @name: the name of an route attribute + * + * Gets the value of the attribute with name @name on @route + * + * Returns: (transfer none): the value of the attribute with name @name on + * @route, or %NULL if @route has no such attribute. + **/ +GVariant * +nm_ip_route_get_attribute (NMIPRoute *route, const char *name) +{ + g_return_val_if_fail (route != NULL, NULL); + g_return_val_if_fail (name != NULL && *name != '\0', NULL); + + if (route->attributes) + return g_hash_table_lookup (route->attributes, name); + else + return NULL; +} + +/** + * nm_ip_route_set_attribute: + * @route: the #NMIPRoute + * @name: the name of a route attribute + * @value: (transfer none) (allow-none): the value + * + * Sets the named attribute on @route to the given value. + **/ +void +nm_ip_route_set_attribute (NMIPRoute *route, const char *name, GVariant *value) +{ + g_return_if_fail (route != NULL); + g_return_if_fail (name != NULL && *name != '\0'); + g_return_if_fail ( strcmp (name, "dest") != 0 && strcmp (name, "prefix") != 0 + && strcmp (name, "next-hop") != 0 && strcmp (name, "metric") != 0); + + if (!route->attributes) { + route->attributes = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, (GDestroyNotify) g_variant_unref); + } + + if (value) + g_hash_table_insert (route->attributes, g_strdup (name), g_variant_ref_sink (value)); + else + g_hash_table_remove (route->attributes, name); +} + + +G_DEFINE_ABSTRACT_TYPE (NMSettingIPConfig, nm_setting_ip_config, NM_TYPE_SETTING) + +#define NM_SETTING_IP_CONFIG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_IP_CONFIG, NMSettingIPConfigPrivate)) + +typedef struct { + char *method; + GPtrArray *dns; /* array of IP address strings */ + GPtrArray *dns_search; /* array of domain name strings */ + GPtrArray *addresses; /* array of NMIPAddress */ + GPtrArray *routes; /* array of NMIPRoute */ + gint64 route_metric; + char *gateway; + gboolean ignore_auto_routes; + gboolean ignore_auto_dns; + char *dhcp_hostname; + gboolean dhcp_send_hostname; + gboolean never_default; + gboolean may_fail; +} NMSettingIPConfigPrivate; + +enum { + PROP_0, + PROP_METHOD, + PROP_DNS, + PROP_DNS_SEARCH, + PROP_ADDRESSES, + PROP_GATEWAY, + PROP_ROUTES, + PROP_ROUTE_METRIC, + PROP_IGNORE_AUTO_ROUTES, + PROP_IGNORE_AUTO_DNS, + PROP_DHCP_HOSTNAME, + PROP_DHCP_SEND_HOSTNAME, + PROP_NEVER_DEFAULT, + PROP_MAY_FAIL, + + LAST_PROP +}; + +#define NM_SETTING_IP_CONFIG_GET_FAMILY(setting) (NM_IS_SETTING_IP4_CONFIG (setting) ? AF_INET : AF_INET6) + +/** + * nm_setting_ip_config_get_method: + * @setting: the #NMSettingIPConfig + * + * Returns: the #NMSettingIPConfig:method property of the setting; see + * #NMSettingIP4Config and #NMSettingIP6Config for details of the + * methods available with each type. + **/ +const char * +nm_setting_ip_config_get_method (NMSettingIPConfig *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), NULL); + + return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->method; +} + +/** + * nm_setting_ip_config_get_num_dns: + * @setting: the #NMSettingIPConfig + * + * Returns: the number of configured DNS servers + **/ +guint +nm_setting_ip_config_get_num_dns (NMSettingIPConfig *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), 0); + + return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->dns->len; +} + +/** + * nm_setting_ip_config_get_dns: + * @setting: the #NMSettingIPConfig + * @i: index number of the DNS server to return + * + * Returns: the IP address of the DNS server at index @i + **/ +const char * +nm_setting_ip_config_get_dns (NMSettingIPConfig *setting, int i) +{ + NMSettingIPConfigPrivate *priv; + + g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), NULL); + + priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); + g_return_val_if_fail (i < priv->dns->len, NULL); + + return priv->dns->pdata[i]; +} + +/** + * nm_setting_ip_config_add_dns: + * @setting: the #NMSettingIPConfig + * @dns: the IP address of the DNS server to add + * + * Adds a new DNS server to the setting. + * + * Returns: %TRUE if the DNS server was added; %FALSE if the server was already + * known + **/ +gboolean +nm_setting_ip_config_add_dns (NMSettingIPConfig *setting, const char *dns) +{ + NMSettingIPConfigPrivate *priv; + char *dns_canonical; + int i; + + g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), FALSE); + g_return_val_if_fail (dns != NULL, FALSE); + g_return_val_if_fail (nm_utils_ipaddr_valid (NM_SETTING_IP_CONFIG_GET_FAMILY (setting), dns), FALSE); + + priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); + + dns_canonical = canonicalize_ip (NM_SETTING_IP_CONFIG_GET_FAMILY (setting), dns, FALSE); + for (i = 0; i < priv->dns->len; i++) { + if (!strcmp (dns_canonical, priv->dns->pdata[i])) { + g_free (dns_canonical); + return FALSE; + } + } + + g_ptr_array_add (priv->dns, dns_canonical); + g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS); + return TRUE; +} + +/** + * nm_setting_ip_config_remove_dns: + * @setting: the #NMSettingIPConfig + * @i: index number of the DNS server to remove + * + * Removes the DNS server at index @i. + **/ +void +nm_setting_ip_config_remove_dns (NMSettingIPConfig *setting, int i) +{ + NMSettingIPConfigPrivate *priv; + + g_return_if_fail (NM_IS_SETTING_IP_CONFIG (setting)); + + priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); + g_return_if_fail (i < priv->dns->len); + + g_ptr_array_remove_index (priv->dns, i); + g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS); +} + +/** + * nm_setting_ip_config_remove_dns_by_value: + * @setting: the #NMSettingIPConfig + * @dns: the DNS server to remove + * + * Removes the DNS server @dns. + * + * Returns: %TRUE if the DNS server was found and removed; %FALSE if it was not. + **/ +gboolean +nm_setting_ip_config_remove_dns_by_value (NMSettingIPConfig *setting, const char *dns) +{ + NMSettingIPConfigPrivate *priv; + char *dns_canonical; + int i; + + g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), FALSE); + g_return_val_if_fail (dns != NULL, FALSE); + g_return_val_if_fail (nm_utils_ipaddr_valid (NM_SETTING_IP_CONFIG_GET_FAMILY (setting), dns), FALSE); + + priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); + + dns_canonical = canonicalize_ip (NM_SETTING_IP_CONFIG_GET_FAMILY (setting), dns, FALSE); + for (i = 0; i < priv->dns->len; i++) { + if (!strcmp (dns_canonical, priv->dns->pdata[i])) { + g_ptr_array_remove_index (priv->dns, i); + g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS); + g_free (dns_canonical); + return TRUE; + } + } + g_free (dns_canonical); + return FALSE; +} + +/** + * nm_setting_ip_config_clear_dns: + * @setting: the #NMSettingIPConfig + * + * Removes all configured DNS servers. + **/ +void +nm_setting_ip_config_clear_dns (NMSettingIPConfig *setting) +{ + NMSettingIPConfigPrivate *priv; + + g_return_if_fail (NM_IS_SETTING_IP_CONFIG (setting)); + + priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); + g_ptr_array_set_size (priv->dns, 0); + g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS); +} + +/** + * nm_setting_ip_config_get_num_dns_searches: + * @setting: the #NMSettingIPConfig + * + * Returns: the number of configured DNS search domains + **/ +guint +nm_setting_ip_config_get_num_dns_searches (NMSettingIPConfig *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), 0); + + return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->dns_search->len; +} + +/** + * nm_setting_ip_config_get_dns_search: + * @setting: the #NMSettingIPConfig + * @i: index number of the DNS search domain to return + * + * Returns: the DNS search domain at index @i + **/ +const char * +nm_setting_ip_config_get_dns_search (NMSettingIPConfig *setting, int i) +{ + NMSettingIPConfigPrivate *priv; + + g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), NULL); + + priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); + g_return_val_if_fail (i < priv->dns_search->len, NULL); + + return priv->dns_search->pdata[i]; +} + +/** + * nm_setting_ip_config_add_dns_search: + * @setting: the #NMSettingIPConfig + * @dns_search: the search domain to add + * + * Adds a new DNS search domain to the setting. + * + * Returns: %TRUE if the DNS search domain was added; %FALSE if the search + * domain was already known + **/ +gboolean +nm_setting_ip_config_add_dns_search (NMSettingIPConfig *setting, + const char *dns_search) +{ + NMSettingIPConfigPrivate *priv; + int i; + + g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), FALSE); + g_return_val_if_fail (dns_search != NULL, FALSE); + g_return_val_if_fail (dns_search[0] != '\0', FALSE); + + priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); + for (i = 0; i < priv->dns_search->len; i++) { + if (!strcmp (dns_search, priv->dns_search->pdata[i])) + return FALSE; + } + + g_ptr_array_add (priv->dns_search, g_strdup (dns_search)); + g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS_SEARCH); + return TRUE; +} + +/** + * nm_setting_ip_config_remove_dns_search: + * @setting: the #NMSettingIPConfig + * @i: index number of the DNS search domain + * + * Removes the DNS search domain at index @i. + **/ +void +nm_setting_ip_config_remove_dns_search (NMSettingIPConfig *setting, int i) +{ + NMSettingIPConfigPrivate *priv; + + g_return_if_fail (NM_IS_SETTING_IP_CONFIG (setting)); + + priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); + g_return_if_fail (i < priv->dns_search->len); + + g_ptr_array_remove_index (priv->dns_search, i); + g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS_SEARCH); +} + +/** + * nm_setting_ip_config_remove_dns_search_by_value: + * @setting: the #NMSettingIPConfig + * @dns_search: the search domain to remove + * + * Removes the DNS search domain @dns_search. + * + * Returns: %TRUE if the DNS search domain was found and removed; %FALSE if it was not. + * + * Since 0.9.10 + **/ +gboolean +nm_setting_ip_config_remove_dns_search_by_value (NMSettingIPConfig *setting, + const char *dns_search) +{ + NMSettingIPConfigPrivate *priv; + int i; + + g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), FALSE); + g_return_val_if_fail (dns_search != NULL, FALSE); + g_return_val_if_fail (dns_search[0] != '\0', FALSE); + + priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); + for (i = 0; i < priv->dns_search->len; i++) { + if (!strcmp (dns_search, priv->dns_search->pdata[i])) { + g_ptr_array_remove_index (priv->dns_search, i); + g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS_SEARCH); + return TRUE; + } + } + return FALSE; +} + +/** + * nm_setting_ip_config_clear_dns_searches: + * @setting: the #NMSettingIPConfig + * + * Removes all configured DNS search domains. + **/ +void +nm_setting_ip_config_clear_dns_searches (NMSettingIPConfig *setting) +{ + NMSettingIPConfigPrivate *priv; + + g_return_if_fail (NM_IS_SETTING_IP_CONFIG (setting)); + + priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); + g_ptr_array_set_size (priv->dns_search, 0); + g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS_SEARCH); +} + +/** + * nm_setting_ip_config_get_num_addresses: + * @setting: the #NMSettingIPConfig + * + * Returns: the number of configured addresses + **/ +guint +nm_setting_ip_config_get_num_addresses (NMSettingIPConfig *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), 0); + + return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->addresses->len; +} + +/** + * nm_setting_ip_config_get_address: + * @setting: the #NMSettingIPConfig + * @i: index number of the address to return + * + * Returns: the address at index @i + **/ +NMIPAddress * +nm_setting_ip_config_get_address (NMSettingIPConfig *setting, int i) +{ + NMSettingIPConfigPrivate *priv; + + g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), NULL); + + priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); + g_return_val_if_fail (i < priv->addresses->len, NULL); + + return priv->addresses->pdata[i]; +} + +/** + * nm_setting_ip_config_add_address: + * @setting: the #NMSettingIPConfig + * @address: the new address to add + * + * Adds a new IP address and associated information to the setting. The + * given address is duplicated internally and is not changed by this function. + * + * Returns: %TRUE if the address was added; %FALSE if the address was already + * known. + **/ +gboolean +nm_setting_ip_config_add_address (NMSettingIPConfig *setting, + NMIPAddress *address) +{ + NMSettingIPConfigPrivate *priv; + int i; + + g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), FALSE); + g_return_val_if_fail (address != NULL, FALSE); + g_return_val_if_fail (address->family == NM_SETTING_IP_CONFIG_GET_FAMILY (setting), FALSE); + + priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); + for (i = 0; i < priv->addresses->len; i++) { + if (nm_ip_address_equal (priv->addresses->pdata[i], address)) + return FALSE; + } + + g_ptr_array_add (priv->addresses, nm_ip_address_dup (address)); + + g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_ADDRESSES); + return TRUE; +} + +/** + * nm_setting_ip_config_remove_address: + * @setting: the #NMSettingIPConfig + * @i: index number of the address to remove + * + * Removes the address at index @i. + **/ +void +nm_setting_ip_config_remove_address (NMSettingIPConfig *setting, int i) +{ + NMSettingIPConfigPrivate *priv; + + g_return_if_fail (NM_IS_SETTING_IP_CONFIG (setting)); + + priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); + g_return_if_fail (i < priv->addresses->len); + + g_ptr_array_remove_index (priv->addresses, i); + + g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_ADDRESSES); +} + +/** + * nm_setting_ip_config_remove_address_by_value: + * @setting: the #NMSettingIPConfig + * @address: the IP address to remove + * + * Removes the address @address. + * + * Returns: %TRUE if the address was found and removed; %FALSE if it was not. + **/ +gboolean +nm_setting_ip_config_remove_address_by_value (NMSettingIPConfig *setting, + NMIPAddress *address) +{ + NMSettingIPConfigPrivate *priv; + int i; + + g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), FALSE); + g_return_val_if_fail (address != NULL, FALSE); + + priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); + for (i = 0; i < priv->addresses->len; i++) { + if (nm_ip_address_equal (priv->addresses->pdata[i], address)) { + g_ptr_array_remove_index (priv->addresses, i); + g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_ADDRESSES); + return TRUE; + } + } + return FALSE; +} + +/** + * nm_setting_ip_config_clear_addresses: + * @setting: the #NMSettingIPConfig + * + * Removes all configured addresses. + **/ +void +nm_setting_ip_config_clear_addresses (NMSettingIPConfig *setting) +{ + NMSettingIPConfigPrivate *priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); + + g_return_if_fail (NM_IS_SETTING_IP_CONFIG (setting)); + + g_ptr_array_set_size (priv->addresses, 0); + g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_ADDRESSES); +} + +/** + * nm_setting_ip_config_get_gateway: + * @setting: the #NMSettingIPConfig + * + * Returns: the IP address of the gateway associated with this configuration, or + * %NULL. + **/ +const char * +nm_setting_ip_config_get_gateway (NMSettingIPConfig *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), NULL); + + return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->gateway; +} + +/** + * nm_setting_ip_config_get_num_routes: + * @setting: the #NMSettingIPConfig + * + * Returns: the number of configured routes + **/ +guint +nm_setting_ip_config_get_num_routes (NMSettingIPConfig *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), 0); + + return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->routes->len; +} + +/** + * nm_setting_ip_config_get_route: + * @setting: the #NMSettingIPConfig + * @i: index number of the route to return + * + * Returns: the route at index @i + **/ +NMIPRoute * +nm_setting_ip_config_get_route (NMSettingIPConfig *setting, int i) +{ + NMSettingIPConfigPrivate *priv; + + g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), NULL); + + priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); + g_return_val_if_fail (i < priv->routes->len, NULL); + + return priv->routes->pdata[i]; +} + +/** + * nm_setting_ip_config_add_route: + * @setting: the #NMSettingIPConfig + * @route: the route to add + * + * Adds a new route and associated information to the setting. The + * given route is duplicated internally and is not changed by this function. + * + * Returns: %TRUE if the route was added; %FALSE if the route was already known. + **/ +gboolean +nm_setting_ip_config_add_route (NMSettingIPConfig *setting, + NMIPRoute *route) +{ + NMSettingIPConfigPrivate *priv; + int i; + + g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), FALSE); + g_return_val_if_fail (route != NULL, FALSE); + g_return_val_if_fail (route->family == NM_SETTING_IP_CONFIG_GET_FAMILY (setting), FALSE); + + priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); + for (i = 0; i < priv->routes->len; i++) { + if (nm_ip_route_equal (priv->routes->pdata[i], route)) + return FALSE; + } + + g_ptr_array_add (priv->routes, nm_ip_route_dup (route)); + g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_ROUTES); + return TRUE; +} + +/** + * nm_setting_ip_config_remove_route: + * @setting: the #NMSettingIPConfig + * @i: index number of the route + * + * Removes the route at index @i. + **/ +void +nm_setting_ip_config_remove_route (NMSettingIPConfig *setting, int i) +{ + NMSettingIPConfigPrivate *priv; + + g_return_if_fail (NM_IS_SETTING_IP_CONFIG (setting)); + + priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); + g_return_if_fail (i < priv->routes->len); + + g_ptr_array_remove_index (priv->routes, i); + g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_ROUTES); +} + +/** + * nm_setting_ip_config_remove_route_by_value: + * @setting: the #NMSettingIPConfig + * @route: the route to remove + * + * Removes the route @route. + * + * Returns: %TRUE if the route was found and removed; %FALSE if it was not. + **/ +gboolean +nm_setting_ip_config_remove_route_by_value (NMSettingIPConfig *setting, + NMIPRoute *route) +{ + NMSettingIPConfigPrivate *priv; + int i; + + g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), FALSE); + g_return_val_if_fail (route != NULL, FALSE); + + priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); + for (i = 0; i < priv->routes->len; i++) { + if (nm_ip_route_equal (priv->routes->pdata[i], route)) { + g_ptr_array_remove_index (priv->routes, i); + g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_ROUTES); + return TRUE; + } + } + return FALSE; +} + +/** + * nm_setting_ip_config_clear_routes: + * @setting: the #NMSettingIPConfig + * + * Removes all configured routes. + **/ +void +nm_setting_ip_config_clear_routes (NMSettingIPConfig *setting) +{ + NMSettingIPConfigPrivate *priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); + + g_return_if_fail (NM_IS_SETTING_IP_CONFIG (setting)); + + g_ptr_array_set_size (priv->routes, 0); + g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_ROUTES); +} + +/** + * nm_setting_ip_config_get_route_metric: + * @setting: the #NMSettingIPConfig + * + * Returns the value contained in the #NMSettingIPConfig:route-metric + * property. + * + * Returns: the route metric that is used for routes that don't explicitly + * specify a metric. See #NMSettingIPConfig:route-metric for more details. + **/ +gint64 +nm_setting_ip_config_get_route_metric (NMSettingIPConfig *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), -1); + + return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->route_metric; +} + + +/** + * nm_setting_ip_config_get_ignore_auto_routes: + * @setting: the #NMSettingIPConfig + * + * Returns the value contained in the #NMSettingIPConfig:ignore-auto-routes + * property. + * + * Returns: %TRUE if automatically configured (ie via DHCP) routes should be + * ignored. + **/ +gboolean +nm_setting_ip_config_get_ignore_auto_routes (NMSettingIPConfig *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), FALSE); + + return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->ignore_auto_routes; +} + +/** + * nm_setting_ip_config_get_ignore_auto_dns: + * @setting: the #NMSettingIPConfig + * + * Returns the value contained in the #NMSettingIPConfig:ignore-auto-dns + * property. + * + * Returns: %TRUE if automatically configured (ie via DHCP) DNS information + * should be ignored. + **/ +gboolean +nm_setting_ip_config_get_ignore_auto_dns (NMSettingIPConfig *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), FALSE); + + return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->ignore_auto_dns; +} + +/** + * nm_setting_ip_config_get_dhcp_hostname: + * @setting: the #NMSettingIPConfig + * + * Returns the value contained in the #NMSettingIPConfig:dhcp-hostname + * property. + * + * Returns: the configured hostname to send to the DHCP server + **/ +const char * +nm_setting_ip_config_get_dhcp_hostname (NMSettingIPConfig *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), NULL); + + return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->dhcp_hostname; +} + +/** + * nm_setting_ip_config_get_dhcp_send_hostname: + * @setting: the #NMSettingIPConfig + * + * Returns the value contained in the #NMSettingIPConfig:dhcp-send-hostname + * property. + * + * Returns: %TRUE if NetworkManager should send the machine hostname to the + * DHCP server when requesting addresses to allow the server to automatically + * update DNS information for this machine. + **/ +gboolean +nm_setting_ip_config_get_dhcp_send_hostname (NMSettingIPConfig *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), FALSE); + + return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->dhcp_send_hostname; +} + +/** + * nm_setting_ip_config_get_never_default: + * @setting: the #NMSettingIPConfig + * + * Returns the value contained in the #NMSettingIPConfig:never-default + * property. + * + * Returns: %TRUE if this connection should never be the default + * connection + **/ +gboolean +nm_setting_ip_config_get_never_default (NMSettingIPConfig *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), FALSE); + + return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->never_default; +} + +/** + * nm_setting_ip_config_get_may_fail: + * @setting: the #NMSettingIPConfig + * + * Returns the value contained in the #NMSettingIPConfig:may-fail + * property. + * + * Returns: %TRUE if this connection doesn't require this type of IP + * addressing to complete for the connection to succeed. + **/ +gboolean +nm_setting_ip_config_get_may_fail (NMSettingIPConfig *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), FALSE); + + return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->may_fail; +} + +static gboolean +verify_label (const char *label) +{ + const char *p; + char *iface; + + p = strchr (label, ':'); + if (!p) + return FALSE; + iface = g_strndup (label, p - label); + if (!nm_utils_iface_valid_name (iface)) { + g_free (iface); + return FALSE; + } + g_free (iface); + + for (p++; *p; p++) { + if (!g_ascii_isalnum (*p) && *p != '_') + return FALSE; + } + + return TRUE; +} + +static gboolean +verify (NMSetting *setting, NMConnection *connection, GError **error) +{ + NMSettingIPConfigPrivate *priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); + int i; + + if (!priv->method) { + g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_PROPERTY, + _("property is missing")); + g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_IP_CONFIG_METHOD); + return FALSE; + } + + if (priv->dhcp_hostname && !*priv->dhcp_hostname) { + g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("property is empty")); + g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_IP_CONFIG_DHCP_HOSTNAME); + return FALSE; + } + + /* Validate DNS */ + for (i = 0; i < priv->dns->len; i++) { + const char *dns = priv->dns->pdata[i]; + + if (!nm_utils_ipaddr_valid (NM_SETTING_IP_CONFIG_GET_FAMILY (setting), dns)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("%d. DNS server address is invalid"), + i+1); + g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_IP_CONFIG_DNS); + return FALSE; + } + } + + /* Validate addresses */ + for (i = 0; i < priv->addresses->len; i++) { + NMIPAddress *addr = (NMIPAddress *) priv->addresses->pdata[i]; + GVariant *label; + + if (nm_ip_address_get_family (addr) != NM_SETTING_IP_CONFIG_GET_FAMILY (setting)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("%d. IP address is invalid"), + i+1); + g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_IP_CONFIG_ADDRESSES); + return FALSE; + } + + label = nm_ip_address_get_attribute (addr, "label"); + if (label) { + if (!g_variant_is_of_type (label, G_VARIANT_TYPE_STRING)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("%d. IP address has 'label' property with invalid type"), + i+1); + g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_IP_CONFIG_ADDRESSES); + return FALSE; + } + if (!verify_label (g_variant_get_string (label, NULL))) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("%d. IP address has invalid label '%s'"), + i+1, g_variant_get_string (label, NULL)); + g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_IP_CONFIG_ADDRESSES); + return FALSE; + } + } + } + + /* Validate gateway */ + if (priv->gateway) { + if (!priv->addresses->len) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("gateway cannot be set if there are no addresses configured")); + g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_IP_CONFIG_GATEWAY); + return FALSE; + } + + if (!nm_utils_ipaddr_valid (NM_SETTING_IP_CONFIG_GET_FAMILY (setting), priv->gateway)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("gateway is invalid")); + g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_IP_CONFIG_GATEWAY); + return FALSE; + } + } + + /* Validate routes */ + for (i = 0; i < priv->routes->len; i++) { + NMIPRoute *route = (NMIPRoute *) priv->routes->pdata[i]; + + if (nm_ip_route_get_family (route) != NM_SETTING_IP_CONFIG_GET_FAMILY (setting)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("%d. route is invalid"), + i+1); + g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_IP_CONFIG_ROUTES); + return FALSE; + } + } + + return TRUE; +} + + +static void +nm_setting_ip_config_init (NMSettingIPConfig *setting) +{ + NMSettingIPConfigPrivate *priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); + + priv->dns = g_ptr_array_new_with_free_func (g_free); + priv->dns_search = g_ptr_array_new_with_free_func (g_free); + priv->addresses = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_address_unref); + priv->routes = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_route_unref); +} + +static void +finalize (GObject *object) +{ + NMSettingIPConfig *self = NM_SETTING_IP_CONFIG (object); + NMSettingIPConfigPrivate *priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (self); + + g_free (priv->method); + g_free (priv->gateway); + g_free (priv->dhcp_hostname); + + g_ptr_array_unref (priv->dns); + g_ptr_array_unref (priv->dns_search); + g_ptr_array_unref (priv->addresses); + g_ptr_array_unref (priv->routes); + + G_OBJECT_CLASS (nm_setting_ip_config_parent_class)->finalize (object); +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMSettingIPConfig *setting = NM_SETTING_IP_CONFIG (object); + NMSettingIPConfigPrivate *priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); + const char *gateway; + + switch (prop_id) { + case PROP_METHOD: + g_free (priv->method); + priv->method = g_value_dup_string (value); + break; + case PROP_DNS: + g_ptr_array_unref (priv->dns); + priv->dns = _nm_utils_strv_to_ptrarray (g_value_get_boxed (value)); + break; + case PROP_DNS_SEARCH: + g_ptr_array_unref (priv->dns_search); + priv->dns_search = _nm_utils_strv_to_ptrarray (g_value_get_boxed (value)); + break; + case PROP_ADDRESSES: + g_ptr_array_unref (priv->addresses); + priv->addresses = _nm_utils_copy_array (g_value_get_boxed (value), + (NMUtilsCopyFunc) nm_ip_address_dup, + (GDestroyNotify) nm_ip_address_unref); + break; + case PROP_GATEWAY: + gateway = g_value_get_string (value); + g_return_if_fail (!gateway || nm_utils_ipaddr_valid (NM_SETTING_IP_CONFIG_GET_FAMILY (setting), gateway)); + g_free (priv->gateway); + priv->gateway = canonicalize_ip (NM_SETTING_IP_CONFIG_GET_FAMILY (setting), gateway, TRUE); + break; + case PROP_ROUTES: + g_ptr_array_unref (priv->routes); + priv->routes = _nm_utils_copy_array (g_value_get_boxed (value), + (NMUtilsCopyFunc) nm_ip_route_dup, + (GDestroyNotify) nm_ip_route_unref); + break; + case PROP_ROUTE_METRIC: + priv->route_metric = g_value_get_int64 (value); + break; + case PROP_IGNORE_AUTO_ROUTES: + priv->ignore_auto_routes = g_value_get_boolean (value); + break; + case PROP_IGNORE_AUTO_DNS: + priv->ignore_auto_dns = g_value_get_boolean (value); + break; + case PROP_DHCP_HOSTNAME: + g_free (priv->dhcp_hostname); + priv->dhcp_hostname = g_value_dup_string (value); + break; + case PROP_DHCP_SEND_HOSTNAME: + priv->dhcp_send_hostname = g_value_get_boolean (value); + break; + case PROP_NEVER_DEFAULT: + priv->never_default = g_value_get_boolean (value); + break; + case PROP_MAY_FAIL: + priv->may_fail = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMSettingIPConfig *setting = NM_SETTING_IP_CONFIG (object); + NMSettingIPConfigPrivate *priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting); + + switch (prop_id) { + case PROP_METHOD: + g_value_set_string (value, nm_setting_ip_config_get_method (setting)); + break; + case PROP_DNS: + g_value_take_boxed (value, _nm_utils_ptrarray_to_strv (priv->dns)); + break; + case PROP_DNS_SEARCH: + g_value_take_boxed (value, _nm_utils_ptrarray_to_strv (priv->dns_search)); + break; + case PROP_ADDRESSES: + g_value_take_boxed (value, _nm_utils_copy_array (priv->addresses, + (NMUtilsCopyFunc) nm_ip_address_dup, + (GDestroyNotify) nm_ip_address_unref)); + break; + case PROP_GATEWAY: + g_value_set_string (value, nm_setting_ip_config_get_gateway (setting)); + break; + case PROP_ROUTES: + g_value_take_boxed (value, _nm_utils_copy_array (priv->routes, + (NMUtilsCopyFunc) nm_ip_route_dup, + (GDestroyNotify) nm_ip_route_unref)); + break; + case PROP_ROUTE_METRIC: + g_value_set_int64 (value, priv->route_metric); + break; + case PROP_IGNORE_AUTO_ROUTES: + g_value_set_boolean (value, nm_setting_ip_config_get_ignore_auto_routes (setting)); + break; + case PROP_IGNORE_AUTO_DNS: + g_value_set_boolean (value, nm_setting_ip_config_get_ignore_auto_dns (setting)); + break; + case PROP_DHCP_HOSTNAME: + g_value_set_string (value, nm_setting_ip_config_get_dhcp_hostname (setting)); + break; + case PROP_DHCP_SEND_HOSTNAME: + g_value_set_boolean (value, nm_setting_ip_config_get_dhcp_send_hostname (setting)); + break; + case PROP_NEVER_DEFAULT: + g_value_set_boolean (value, priv->never_default); + break; + case PROP_MAY_FAIL: + g_value_set_boolean (value, priv->may_fail); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nm_setting_ip_config_class_init (NMSettingIPConfigClass *setting_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (setting_class); + NMSettingClass *parent_class = NM_SETTING_CLASS (setting_class); + + g_type_class_add_private (setting_class, sizeof (NMSettingIPConfigPrivate)); + + /* virtual methods */ + object_class->set_property = set_property; + object_class->get_property = get_property; + object_class->finalize = finalize; + parent_class->verify = verify; + + /* Properties */ + + /** + * NMSettingIPConfig:method: + * + * IP configuration method. + * + * #NMSettingIP4Config and #NMSettingIP6Config both support "auto", + * "manual", and "link-local". See the subclass-specific documentation for + * other values. + * + * In general, for the "auto" method, properties such as + * #NMSettingIPConfig:dns and #NMSettingIPConfig:routes specify information + * that is added on to the information returned from automatic + * configuration. The #NMSettingIPConfig:ignore-auto-routes and + * #NMSettingIPConfig:ignore-auto-dns properties modify this behavior. + * + * For methods that imply no upstream network, such as "shared" or + * "link-local", these properties must be empty. + **/ + g_object_class_install_property + (object_class, PROP_METHOD, + g_param_spec_string (NM_SETTING_IP_CONFIG_METHOD, "", "", + NULL, + G_PARAM_READWRITE | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingIPConfig:dns: + * + * Array of IP addresses of DNS servers. + **/ + g_object_class_install_property + (object_class, PROP_DNS, + g_param_spec_boxed (NM_SETTING_IP_CONFIG_DNS, "", "", + G_TYPE_STRV, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingIPConfig:dns-search: + * + * Array of DNS search domains. + **/ + g_object_class_install_property + (object_class, PROP_DNS_SEARCH, + g_param_spec_boxed (NM_SETTING_IP_CONFIG_DNS_SEARCH, "", "", + G_TYPE_STRV, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingIPConfig:addresses: + * + * Array of IP addresses. + * + * Element-Type: NMIPAddress + **/ + g_object_class_install_property + (object_class, PROP_ADDRESSES, + g_param_spec_boxed (NM_SETTING_IP_CONFIG_ADDRESSES, "", "", + G_TYPE_PTR_ARRAY, + G_PARAM_READWRITE | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingIPConfig:gateway: + * + * The gateway associated with this configuration. This is only meaningful + * if #NMSettingIPConfig:addresses is also set. + **/ + g_object_class_install_property + (object_class, PROP_GATEWAY, + g_param_spec_string (NM_SETTING_IP_CONFIG_GATEWAY, "", "", + NULL, + G_PARAM_READWRITE | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingIPConfig:routes: + * + * Array of IP routes. + * + * Element-Type: NMIPRoute + **/ + g_object_class_install_property + (object_class, PROP_ROUTES, + g_param_spec_boxed (NM_SETTING_IP_CONFIG_ROUTES, "", "", + G_TYPE_PTR_ARRAY, + G_PARAM_READWRITE | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingIPConfig:route-metric: + * + * The default metric for routes that don't explicitly specify a metric. + * The default value -1 means that the metric is choosen automatically + * based on the device type. + * The metric applies to dynamic routes, manual (static) routes that + * don't have an explicit metric setting, address prefix routes, and + * the default route. + * Note that for IPv6, the kernel accepts zero (0) but coerces it to + * 1024 (user default). Hence, setting this property to zero effectively + * mean setting it to 1024. + * For IPv4, zero is a regular value for the metric. + **/ + g_object_class_install_property + (object_class, PROP_ROUTE_METRIC, + g_param_spec_int64 (NM_SETTING_IP_CONFIG_ROUTE_METRIC, "", "", + -1, G_MAXUINT32, -1, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingIPConfig:ignore-auto-routes: + * + * When #NMSettingIPConfig:method is set to "auto" and this property to + * %TRUE, automatically configured routes are ignored and only routes + * specified in the #NMSettingIPConfig:routes property, if any, are used. + **/ + g_object_class_install_property + (object_class, PROP_IGNORE_AUTO_ROUTES, + g_param_spec_boolean (NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingIPConfig:ignore-auto-dns: + * + * When #NMSettingIPConfig:method is set to "auto" and this property to + * %TRUE, automatically configured nameservers and search domains are + * ignored and only nameservers and search domains specified in the + * #NMSettingIPConfig:dns and #NMSettingIPConfig:dns-search properties, if + * any, are used. + **/ + g_object_class_install_property + (object_class, PROP_IGNORE_AUTO_DNS, + g_param_spec_boolean (NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingIPConfig:dhcp-hostname: + * + * If the #NMSettingIPConfig:dhcp-send-hostname property is %TRUE, then the + * specified name will be sent to the DHCP server when acquiring a lease. + **/ + g_object_class_install_property + (object_class, PROP_DHCP_HOSTNAME, + g_param_spec_string (NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, "", "", + NULL, + G_PARAM_READWRITE | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingIPConfig:dhcp-send-hostname: + * + * If %TRUE, a hostname is sent to the DHCP server when acquiring a lease. + * Some DHCP servers use this hostname to update DNS databases, essentially + * providing a static hostname for the computer. If the + * #NMSettingIPConfig:dhcp-hostname property is %NULL and this property is + * %TRUE, the current persistent hostname of the computer is sent. + **/ + g_object_class_install_property + (object_class, PROP_DHCP_SEND_HOSTNAME, + g_param_spec_boolean (NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME, "", "", + TRUE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingIPConfig:never-default: + * + * If %TRUE, this connection will never be the default connection for this + * IP type, meaning it will never be assigned the default route by + * NetworkManager. + **/ + g_object_class_install_property + (object_class, PROP_NEVER_DEFAULT, + g_param_spec_boolean (NM_SETTING_IP_CONFIG_NEVER_DEFAULT, "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingIPConfig:may-fail: + * + * If %TRUE, allow overall network configuration to proceed even if the + * configuration specified by this property times out. Note that at least + * one IP configuration must succeed or overall network configuration will + * still fail. For example, in IPv6-only networks, setting this property to + * %TRUE on the #NMSettingIP4Config allows the overall network configuration + * to succeed if IPv4 configuration fails but IPv6 configuration completes + * successfully. + **/ + g_object_class_install_property + (object_class, PROP_MAY_FAIL, + g_param_spec_boolean (NM_SETTING_IP_CONFIG_MAY_FAIL, "", "", + TRUE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS)); +} |