summaryrefslogtreecommitdiff
path: root/libnm-core
diff options
context:
space:
mode:
authorDan Winship <danw@gnome.org>2014-10-20 21:30:56 -0400
committerDan Winship <danw@gnome.org>2014-11-07 07:49:40 -0500
commitf17699f4e3dacb9358a8503c8b15efe3cb852b48 (patch)
treefc26094c54154b91497b4b5eac72eeca093fedf0 /libnm-core
parent329791ad55ee66e2d12c3cedcc2daf8c0865f7a6 (diff)
downloadNetworkManager-f17699f4e3dacb9358a8503c8b15efe3cb852b48.tar.gz
libnm-core: add NMSettingIPConfig:gateway, drop NMIPAddress:gateway
The gateway is a global property of the IPv4/IPv6 configuration, not an attribute of any particular address. So represent it as such in the API; remove the gateway from NMIPAddress, and add it to NMSettingIPConfig. Behind the scenes, the gateway is still serialized along with the first address in NMSettingIPConfig:addresses, and is deserialized from that if the settings dictionary doesn't contain a 'gateway' key. Adjust nmcli's interactive mode to prompt for IP addresses and gateway separately. (Patch partly from Jirka Klimeš.)
Diffstat (limited to 'libnm-core')
-rw-r--r--libnm-core/nm-setting-ip-config.c130
-rw-r--r--libnm-core/nm-setting-ip-config.h8
-rw-r--r--libnm-core/nm-setting-ip4-config.c23
-rw-r--r--libnm-core/nm-setting-ip6-config.c57
-rw-r--r--libnm-core/nm-utils.c83
-rw-r--r--libnm-core/nm-utils.h12
-rw-r--r--libnm-core/tests/test-general.c152
7 files changed, 345 insertions, 120 deletions
diff --git a/libnm-core/nm-setting-ip-config.c b/libnm-core/nm-setting-ip-config.c
index ebe38712b2..0ed612cd06 100644
--- a/libnm-core/nm-setting-ip-config.c
+++ b/libnm-core/nm-setting-ip-config.c
@@ -102,7 +102,7 @@ G_DEFINE_BOXED_TYPE (NMIPAddress, nm_ip_address, nm_ip_address_dup, nm_ip_addres
struct NMIPAddress {
guint refcount;
- char *address, *gateway;
+ char *address;
int prefix, family;
GHashTable *attributes;
@@ -113,7 +113,6 @@ struct NMIPAddress {
* @family: the IP address family (%AF_INET or %AF_INET6)
* @addr: the IP address
* @prefix: the address prefix length
- * @gateway: (allow-none): the gateway
* @error: location to store error, or %NULL
*
* Creates a new #NMIPAddress object.
@@ -122,7 +121,7 @@ struct NMIPAddress {
**/
NMIPAddress *
nm_ip_address_new (int family,
- const char *addr, guint prefix, const char *gateway,
+ const char *addr, guint prefix,
GError **error)
{
NMIPAddress *address;
@@ -134,8 +133,6 @@ nm_ip_address_new (int family,
return NULL;
if (!valid_prefix (family, prefix, error))
return NULL;
- if (gateway && !valid_ip (family, gateway, error))
- return NULL;
address = g_slice_new0 (NMIPAddress);
address->refcount = 1;
@@ -143,7 +140,6 @@ nm_ip_address_new (int family,
address->family = family;
address->address = canonicalize_ip (family, addr, FALSE);
address->prefix = prefix;
- address->gateway = canonicalize_ip (family, gateway, TRUE);
return address;
}
@@ -153,17 +149,16 @@ nm_ip_address_new (int family,
* @family: the IP address family (%AF_INET or %AF_INET6)
* @addr: the IP address
* @prefix: the address prefix length
- * @gateway: (allow-none): the gateway
* @error: location to store error, or %NULL
*
- * Creates a new #NMIPAddress object. @addr and @gateway (if non-%NULL) must
- * point to buffers of the correct size for @family.
+ * 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, gconstpointer gateway,
+ gconstpointer addr, guint prefix,
GError **error)
{
NMIPAddress *address;
@@ -181,8 +176,6 @@ nm_ip_address_new_binary (int family,
address->family = family;
address->address = g_strdup (inet_ntop (family, addr, string, sizeof (string)));
address->prefix = prefix;
- if (gateway)
- address->gateway = g_strdup (inet_ntop (family, gateway, string, sizeof (string)));
return address;
}
@@ -218,7 +211,6 @@ nm_ip_address_unref (NMIPAddress *address)
address->refcount--;
if (address->refcount == 0) {
g_free (address->address);
- g_free (address->gateway);
if (address->attributes)
g_hash_table_unref (address->attributes);
g_slice_free (NMIPAddress, address);
@@ -230,8 +222,8 @@ nm_ip_address_unref (NMIPAddress *address)
* @address: the #NMIPAddress
* @other: the #NMIPAddress to compare @address to.
*
- * Determines if two #NMIPAddress objects contain the same address, prefix, and
- * gateway (attributes are not compared).
+ * 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.
**/
@@ -246,8 +238,7 @@ nm_ip_address_equal (NMIPAddress *address, NMIPAddress *other)
if ( address->family != other->family
|| address->prefix != other->prefix
- || strcmp (address->address, other->address) != 0
- || g_strcmp0 (address->gateway, other->gateway) != 0)
+ || strcmp (address->address, other->address) != 0)
return FALSE;
return TRUE;
}
@@ -269,7 +260,7 @@ nm_ip_address_dup (NMIPAddress *address)
g_return_val_if_fail (address->refcount > 0, NULL);
copy = nm_ip_address_new (address->family,
- address->address, address->prefix, address->gateway,
+ address->address, address->prefix,
NULL);
if (address->attributes) {
GHashTableIter iter;
@@ -418,46 +409,6 @@ nm_ip_address_set_prefix (NMIPAddress *address,
}
/**
- * nm_ip_address_get_gateway:
- * @address: the #NMIPAddress
- *
- * Gets the gateway property of this address object; this will be %NULL if the
- * address has no associated gateway.
- *
- * Returns: the gateway
- **/
-const char *
-nm_ip_address_get_gateway (NMIPAddress *address)
-{
- g_return_val_if_fail (address != NULL, NULL);
- g_return_val_if_fail (address->refcount > 0, NULL);
-
- return address->gateway;
-}
-
-/**
- * nm_ip_address_set_gateway:
- * @address: the #NMIPAddress
- * @gateway: (allow-none): the gateway, as a string
- *
- * Sets the gateway property of this address object.
- *
- * @gateway (if non-%NULL) 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_gateway (NMIPAddress *address,
- const char *gateway)
-{
- g_return_if_fail (address != NULL);
- g_return_if_fail (!gateway || nm_utils_ipaddr_valid (address->family, gateway));
-
- g_free (address->gateway);
- address->gateway = canonicalize_ip (address->family, gateway, TRUE);
-}
-
-/**
* nm_ip_address_get_attribute_names:
* @address: the #NMIPAddress
*
@@ -1081,6 +1032,7 @@ typedef struct {
GPtrArray *dns_search; /* array of domain name strings */
GPtrArray *addresses; /* array of NMIPAddress */
GPtrArray *routes; /* array of NMIPRoute */
+ char *gateway;
gboolean ignore_auto_routes;
gboolean ignore_auto_dns;
char *dhcp_hostname;
@@ -1095,6 +1047,7 @@ enum {
PROP_DNS,
PROP_DNS_SEARCH,
PROP_ADDRESSES,
+ PROP_GATEWAY,
PROP_ROUTES,
PROP_IGNORE_AUTO_ROUTES,
PROP_IGNORE_AUTO_DNS,
@@ -1544,6 +1497,21 @@ nm_setting_ip_config_clear_addresses (NMSettingIPConfig *setting)
}
/**
+ * 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
*
@@ -1882,6 +1850,27 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
}
}
+ /* 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];
@@ -1919,6 +1908,7 @@ finalize (GObject *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);
@@ -1935,6 +1925,7 @@ set_property (GObject *object, guint prop_id,
{
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:
@@ -1955,6 +1946,12 @@ set_property (GObject *object, guint prop_id,
(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),
@@ -2008,6 +2005,9 @@ get_property (GObject *object, guint prop_id,
(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,
@@ -2119,6 +2119,20 @@ nm_setting_ip_config_class_init (NMSettingIPConfigClass *setting_class)
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.
diff --git a/libnm-core/nm-setting-ip-config.h b/libnm-core/nm-setting-ip-config.h
index 0f2d16367c..37437761c4 100644
--- a/libnm-core/nm-setting-ip-config.h
+++ b/libnm-core/nm-setting-ip-config.h
@@ -38,12 +38,10 @@ GType nm_ip_address_get_type (void);
NMIPAddress *nm_ip_address_new (int family,
const char *addr,
guint prefix,
- const char *gateway,
GError **error);
NMIPAddress *nm_ip_address_new_binary (int family,
gconstpointer addr,
guint prefix,
- gconstpointer gateway,
GError **error);
void nm_ip_address_ref (NMIPAddress *address);
@@ -63,9 +61,6 @@ void nm_ip_address_set_address_binary (NMIPAddress *address,
guint nm_ip_address_get_prefix (NMIPAddress *address);
void nm_ip_address_set_prefix (NMIPAddress *address,
guint prefix);
-const char *nm_ip_address_get_gateway (NMIPAddress *address);
-void nm_ip_address_set_gateway (NMIPAddress *address,
- const char *gateway);
char **nm_ip_address_get_attribute_names (NMIPAddress *address);
GVariant *nm_ip_address_get_attribute (NMIPAddress *address,
@@ -139,6 +134,7 @@ void nm_ip_route_set_attribute (NMIPRoute *route,
#define NM_SETTING_IP_CONFIG_DNS "dns"
#define NM_SETTING_IP_CONFIG_DNS_SEARCH "dns-search"
#define NM_SETTING_IP_CONFIG_ADDRESSES "addresses"
+#define NM_SETTING_IP_CONFIG_GATEWAY "gateway"
#define NM_SETTING_IP_CONFIG_ROUTES "routes"
#define NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES "ignore-auto-routes"
#define NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS "ignore-auto-dns"
@@ -195,6 +191,8 @@ gboolean nm_setting_ip_config_remove_address_by_value (NMSettingIPConfig
NMIPAddress *address);
void nm_setting_ip_config_clear_addresses (NMSettingIPConfig *setting);
+const char *nm_setting_ip_config_get_gateway (NMSettingIPConfig *setting);
+
guint nm_setting_ip_config_get_num_routes (NMSettingIPConfig *setting);
NMIPRoute *nm_setting_ip_config_get_route (NMSettingIPConfig *setting,
int i);
diff --git a/libnm-core/nm-setting-ip4-config.c b/libnm-core/nm-setting-ip4-config.c
index 068ba0451a..66f2ea997e 100644
--- a/libnm-core/nm-setting-ip4-config.c
+++ b/libnm-core/nm-setting-ip4-config.c
@@ -102,10 +102,12 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
{
NMSettingIP4ConfigPrivate *priv = NM_SETTING_IP4_CONFIG_GET_PRIVATE (setting);
NMSettingIPConfig *s_ip = NM_SETTING_IP_CONFIG (setting);
+ NMSettingVerifyResult ret;
const char *method;
- if (!NM_SETTING_CLASS (nm_setting_ip4_config_parent_class)->verify (setting, connection, error))
- return FALSE;
+ ret = NM_SETTING_CLASS (nm_setting_ip4_config_parent_class)->verify (setting, connection, error);
+ if (ret != NM_SETTING_VERIFY_SUCCESS)
+ return ret;
method = nm_setting_ip_config_get_method (s_ip);
/* Base class already checked that it exists */
@@ -245,10 +247,12 @@ ip4_addresses_get (NMSetting *setting,
const char *property)
{
GPtrArray *addrs;
+ const char *gateway;
GVariant *ret;
g_object_get (setting, property, &addrs, NULL);
- ret = nm_utils_ip4_addresses_to_variant (addrs);
+ gateway = nm_setting_ip_config_get_gateway (NM_SETTING_IP_CONFIG (setting));
+ ret = nm_utils_ip4_addresses_to_variant (addrs, gateway);
g_ptr_array_unref (addrs);
return ret;
@@ -262,18 +266,27 @@ ip4_addresses_set (NMSetting *setting,
{
GPtrArray *addrs;
GVariant *s_ip4;
- char **labels;
+ char **labels, *gateway = NULL;
int i;
- addrs = nm_utils_ip4_addresses_from_variant (value);
+ addrs = nm_utils_ip4_addresses_from_variant (value, &gateway);
s_ip4 = g_variant_lookup_value (connection_dict, NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_VARIANT_TYPE_SETTING);
+
if (g_variant_lookup (s_ip4, "address-labels", "^as", &labels)) {
for (i = 0; i < addrs->len && labels[i]; i++)
if (*labels[i])
nm_ip_address_set_attribute (addrs->pdata[i], "label", g_variant_new_string (labels[i]));
g_strfreev (labels);
}
+
+ if (gateway && !g_variant_lookup (s_ip4, "gateway", "s", NULL)) {
+ g_object_set (setting,
+ NM_SETTING_IP_CONFIG_GATEWAY, gateway,
+ NULL);
+ }
+ g_free (gateway);
+
g_variant_unref (s_ip4);
g_object_set (setting, property, addrs, NULL);
diff --git a/libnm-core/nm-setting-ip6-config.c b/libnm-core/nm-setting-ip6-config.c
index dc05e541c3..9e3001157e 100644
--- a/libnm-core/nm-setting-ip6-config.c
+++ b/libnm-core/nm-setting-ip6-config.c
@@ -100,10 +100,12 @@ static gboolean
verify (NMSetting *setting, NMConnection *connection, GError **error)
{
NMSettingIPConfig *s_ip = NM_SETTING_IP_CONFIG (setting);
+ NMSettingVerifyResult ret;
const char *method;
- if (!NM_SETTING_CLASS (nm_setting_ip6_config_parent_class)->verify (setting, connection, error))
- return FALSE;
+ ret = NM_SETTING_CLASS (nm_setting_ip6_config_parent_class)->verify (setting, connection, error);
+ if (ret != NM_SETTING_VERIFY_SUCCESS)
+ return ret;
method = nm_setting_ip_config_get_method (s_ip);
/* Base class already checked that it exists */
@@ -187,16 +189,46 @@ ip6_dns_from_dbus (GVariant *dbus_value,
}
static GVariant *
-ip6_addresses_to_dbus (const GValue *prop_value)
+ip6_addresses_get (NMSetting *setting,
+ const char *property)
{
- return nm_utils_ip6_addresses_to_variant (g_value_get_boxed (prop_value));
+ GPtrArray *addrs;
+ const char *gateway;
+ GVariant *ret;
+
+ g_object_get (setting, property, &addrs, NULL);
+ gateway = nm_setting_ip_config_get_gateway (NM_SETTING_IP_CONFIG (setting));
+ ret = nm_utils_ip6_addresses_to_variant (addrs, gateway);
+ g_ptr_array_unref (addrs);
+
+ return ret;
}
static void
-ip6_addresses_from_dbus (GVariant *dbus_value,
- GValue *prop_value)
+ip6_addresses_set (NMSetting *setting,
+ GVariant *connection_dict,
+ const char *property,
+ GVariant *value)
{
- g_value_take_boxed (prop_value, nm_utils_ip6_addresses_from_variant (dbus_value));
+ GPtrArray *addrs;
+ GVariant *s_ip6;
+ char *gateway = NULL;
+
+ addrs = nm_utils_ip6_addresses_from_variant (value, &gateway);
+
+ s_ip6 = g_variant_lookup_value (connection_dict, NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_VARIANT_TYPE_SETTING);
+
+ if (gateway && !g_variant_lookup (s_ip6, "gateway", "s", NULL)) {
+ g_object_set (setting,
+ NM_SETTING_IP_CONFIG_GATEWAY, gateway,
+ NULL);
+ }
+ g_free (gateway);
+
+ g_variant_unref (s_ip6);
+
+ g_object_set (setting, property, addrs, NULL);
+ g_ptr_array_unref (addrs);
}
static GVariant *
@@ -285,11 +317,12 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *ip6_class)
ip6_dns_to_dbus,
ip6_dns_from_dbus);
- _nm_setting_class_transform_property (setting_class,
- NM_SETTING_IP_CONFIG_ADDRESSES,
- G_VARIANT_TYPE ("a(ayuay)"),
- ip6_addresses_to_dbus,
- ip6_addresses_from_dbus);
+ _nm_setting_class_override_property (setting_class,
+ NM_SETTING_IP_CONFIG_ADDRESSES,
+ G_VARIANT_TYPE ("a(ayuay)"),
+ ip6_addresses_get,
+ ip6_addresses_set,
+ NULL);
_nm_setting_class_transform_property (setting_class,
NM_SETTING_IP_CONFIG_ROUTES,
diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c
index 110142fbfc..62698eefc8 100644
--- a/libnm-core/nm-utils.c
+++ b/libnm-core/nm-utils.c
@@ -1136,16 +1136,18 @@ nm_utils_ip4_dns_from_variant (GVariant *value)
/**
* nm_utils_ip4_addresses_to_variant:
* @addresses: (element-type NMIPAddress): an array of #NMIPAddress objects
+ * @gateway: (allow-none): the gateway IP address
*
* Utility function to convert a #GPtrArray of #NMIPAddress objects representing
* IPv4 addresses into a #GVariant of type 'aau' representing an array of
* NetworkManager IPv4 addresses (which are tuples of address, prefix, and
- * gateway, although only the first "gateway" field is preserved)
+ * gateway). The "gateway" field of the first address will get the value of
+ * @gateway (if non-%NULL). In all of the other addresses, that field will be 0.
*
* Returns: (transfer none): a new floating #GVariant representing @addresses.
**/
GVariant *
-nm_utils_ip4_addresses_to_variant (GPtrArray *addresses)
+nm_utils_ip4_addresses_to_variant (GPtrArray *addresses, const char *gateway)
{
GVariantBuilder builder;
int i;
@@ -1162,8 +1164,8 @@ nm_utils_ip4_addresses_to_variant (GPtrArray *addresses)
nm_ip_address_get_address_binary (addr, &array[0]);
array[1] = nm_ip_address_get_prefix (addr);
- if (i == 0 && nm_ip_address_get_gateway (addr))
- inet_pton (AF_INET, nm_ip_address_get_gateway (addr), &array[2]);
+ if (i == 0 && gateway)
+ inet_pton (AF_INET, gateway, &array[2]);
else
array[2] = 0;
@@ -1179,17 +1181,19 @@ nm_utils_ip4_addresses_to_variant (GPtrArray *addresses)
/**
* nm_utils_ip4_addresses_from_variant:
* @value: a #GVariant of type 'aau'
+ * @out_gateway: (out) (allow-none) (transfer full): on return, will contain the IP gateway
*
* Utility function to convert a #GVariant of type 'aau' representing a list of
* NetworkManager IPv4 addresses (which are tuples of address, prefix, and
- * gateway, although only the first "gateway" field is preserved) into a
- * #GPtrArray of #NMIPAddress objects.
+ * gateway) into a #GPtrArray of #NMIPAddress objects. The "gateway" field of
+ * the first address (if set) will be returned in @out_gateway; the "gateway" fields
+ * of the other addresses are ignored.
*
* Returns: (transfer full) (element-type NMIPAddress): a newly allocated
* #GPtrArray of #NMIPAddress objects
**/
GPtrArray *
-nm_utils_ip4_addresses_from_variant (GVariant *value)
+nm_utils_ip4_addresses_from_variant (GVariant *value, char **out_gateway)
{
GPtrArray *addresses;
GVariantIter iter;
@@ -1197,6 +1201,9 @@ nm_utils_ip4_addresses_from_variant (GVariant *value)
g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("aau")), NULL);
+ if (out_gateway)
+ *out_gateway = NULL;
+
g_variant_iter_init (&iter, value);
addresses = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_address_unref);
@@ -1213,16 +1220,19 @@ nm_utils_ip4_addresses_from_variant (GVariant *value)
continue;
}
- addr = nm_ip_address_new_binary (AF_INET,
- &addr_array[0], addr_array[1],
- addresses->len == 0 ? &addr_array[2] : NULL,
- &error);
+ addr = nm_ip_address_new_binary (AF_INET, &addr_array[0], addr_array[1], &error);
+ if (addresses->len == 0 && out_gateway) {
+ if (addr_array[2])
+ *out_gateway = g_strdup (nm_utils_inet4_ntop (addr_array[2], NULL));
+ }
+
if (addr)
g_ptr_array_add (addresses, addr);
else {
g_warning ("Ignoring invalid IP4 address: %s", error->message);
g_clear_error (&error);
}
+
g_variant_unref (addr_var);
}
@@ -1469,16 +1479,19 @@ nm_utils_ip6_dns_from_variant (GVariant *value)
/**
* nm_utils_ip6_addresses_to_variant:
* @addresses: (element-type NMIPAddress): an array of #NMIPAddress objects
+ * @gateway: (allow-none): the gateway IP address
*
* Utility function to convert a #GPtrArray of #NMIPAddress objects representing
* IPv6 addresses into a #GVariant of type 'a(ayuay)' representing an array of
* NetworkManager IPv6 addresses (which are tuples of address, prefix, and
- * gateway, although only the first "gateway" field is preserved).
+ * gateway). The "gateway" field of the first address will get the value of
+ * @gateway (if non-%NULL). In all of the other addresses, that field will be
+ * all 0s.
*
* Returns: (transfer none): a new floating #GVariant representing @addresses.
**/
GVariant *
-nm_utils_ip6_addresses_to_variant (GPtrArray *addresses)
+nm_utils_ip6_addresses_to_variant (GPtrArray *addresses, const char *gateway)
{
GVariantBuilder builder;
int i;
@@ -1489,24 +1502,24 @@ nm_utils_ip6_addresses_to_variant (GPtrArray *addresses)
for (i = 0; i < addresses->len; i++) {
NMIPAddress *addr = addresses->pdata[i];
struct in6_addr ip_bytes, gateway_bytes;
- GVariant *ip, *gateway;
+ GVariant *ip_var, *gateway_var;
guint32 prefix;
if (nm_ip_address_get_family (addr) != AF_INET6)
continue;
nm_ip_address_get_address_binary (addr, &ip_bytes);
- ip = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, &ip_bytes, 16, 1);
+ ip_var = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, &ip_bytes, 16, 1);
prefix = nm_ip_address_get_prefix (addr);
-
- if (i == 0 && nm_ip_address_get_gateway (addr))
- inet_pton (AF_INET6, nm_ip_address_get_gateway (addr), &gateway_bytes);
+
+ if (i == 0 && gateway)
+ inet_pton (AF_INET6, gateway, &gateway_bytes);
else
memset (&gateway_bytes, 0, sizeof (gateway_bytes));
- gateway = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, &gateway_bytes, 16, 1);
+ gateway_var = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, &gateway_bytes, 16, 1);
- g_variant_builder_add (&builder, "(@ayu@ay)", ip, prefix, gateway);
+ g_variant_builder_add (&builder, "(@ayu@ay)", ip_var, prefix, gateway_var);
}
}
@@ -1516,17 +1529,19 @@ nm_utils_ip6_addresses_to_variant (GPtrArray *addresses)
/**
* nm_utils_ip6_addresses_from_variant:
* @value: a #GVariant of type 'a(ayuay)'
+ * @out_gateway: (out) (allow-none) (transfer full): on return, will contain the IP gateway
*
* Utility function to convert a #GVariant of type 'a(ayuay)' representing a
* list of NetworkManager IPv6 addresses (which are tuples of address, prefix,
- * and gateway, although only the first "gateway" field is preserved) into a
- * #GPtrArray of #NMIPAddress objects.
+ * and gateway) into a #GPtrArray of #NMIPAddress objects. The "gateway" field
+ * of the first address (if set) will be returned in @out_gateway; the "gateway"
+ * fields of the other addresses are ignored.
*
* Returns: (transfer full) (element-type NMIPAddress): a newly allocated
* #GPtrArray of #NMIPAddress objects
**/
GPtrArray *
-nm_utils_ip6_addresses_from_variant (GVariant *value)
+nm_utils_ip6_addresses_from_variant (GVariant *value, char **out_gateway)
{
GVariantIter iter;
GVariant *addr_var, *gateway_var;
@@ -1535,6 +1550,9 @@ nm_utils_ip6_addresses_from_variant (GVariant *value)
g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("a(ayuay)")), NULL);
+ if (out_gateway)
+ *out_gateway = NULL;
+
g_variant_iter_init (&iter, value);
addresses = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_address_unref);
@@ -1556,16 +1574,19 @@ nm_utils_ip6_addresses_from_variant (GVariant *value)
__func__, (int) addr_len);
goto next;
}
- gateway_bytes = g_variant_get_fixed_array (gateway_var, &gateway_len, 1);
- if (gateway_len != 16) {
- g_warning ("%s: ignoring invalid IP6 address of length %d",
- __func__, (int) gateway_len);
- goto next;
+
+ if (addresses->len == 0 && out_gateway) {
+ gateway_bytes = g_variant_get_fixed_array (gateway_var, &gateway_len, 1);
+ if (gateway_len != 16) {
+ g_warning ("%s: ignoring invalid IP6 address of length %d",
+ __func__, (int) gateway_len);
+ goto next;
+ }
+ if (!IN6_IS_ADDR_UNSPECIFIED (gateway_bytes))
+ *out_gateway = g_strdup (nm_utils_inet6_ntop (gateway_bytes, NULL));
}
- addr = nm_ip_address_new_binary (AF_INET6, addr_bytes, prefix,
- addresses->len == 0 ? gateway_bytes : NULL,
- &error);
+ addr = nm_ip_address_new_binary (AF_INET6, addr_bytes, prefix, &error);
if (addr)
g_ptr_array_add (addresses, addr);
else {
diff --git a/libnm-core/nm-utils.h b/libnm-core/nm-utils.h
index ccf15f7b84..628fa0f5a6 100644
--- a/libnm-core/nm-utils.h
+++ b/libnm-core/nm-utils.h
@@ -97,8 +97,10 @@ gboolean nm_utils_wpa_psk_valid (const char *psk);
GVariant *nm_utils_ip4_dns_to_variant (char **dns);
char **nm_utils_ip4_dns_from_variant (GVariant *value);
-GVariant *nm_utils_ip4_addresses_to_variant (GPtrArray *addresses);
-GPtrArray *nm_utils_ip4_addresses_from_variant (GVariant *value);
+GVariant *nm_utils_ip4_addresses_to_variant (GPtrArray *addresses,
+ const char *gateway);
+GPtrArray *nm_utils_ip4_addresses_from_variant (GVariant *value,
+ char **out_gateway);
GVariant *nm_utils_ip4_routes_to_variant (GPtrArray *routes);
GPtrArray *nm_utils_ip4_routes_from_variant (GVariant *value);
@@ -108,8 +110,10 @@ guint32 nm_utils_ip4_get_default_prefix (guint32 ip);
GVariant *nm_utils_ip6_dns_to_variant (char **dns);
char **nm_utils_ip6_dns_from_variant (GVariant *value);
-GVariant *nm_utils_ip6_addresses_to_variant (GPtrArray *addresses);
-GPtrArray *nm_utils_ip6_addresses_from_variant (GVariant *value);
+GVariant *nm_utils_ip6_addresses_to_variant (GPtrArray *addresses,
+ const char *gateway);
+GPtrArray *nm_utils_ip6_addresses_from_variant (GVariant *value,
+ char **out_gateway);
GVariant *nm_utils_ip6_routes_to_variant (GPtrArray *routes);
GPtrArray *nm_utils_ip6_routes_from_variant (GVariant *value);
diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c
index 041c4263f4..d66a9c9f6e 100644
--- a/libnm-core/tests/test-general.c
+++ b/libnm-core/tests/test-general.c
@@ -338,7 +338,7 @@ test_setting_ip4_config_labels (void)
NULL);
/* addr 1 */
- addr = nm_ip_address_new (AF_INET, "1.1.1.1", 24, NULL, &error);
+ addr = nm_ip_address_new (AF_INET, "1.1.1.1", 24, &error);
g_assert_no_error (error);
nm_setting_ip_config_add_address (s_ip4, addr);
@@ -351,7 +351,7 @@ test_setting_ip4_config_labels (void)
g_assert (label == NULL);
/* addr 2 */
- addr = nm_ip_address_new (AF_INET, "2.2.2.2", 24, NULL, &error);
+ addr = nm_ip_address_new (AF_INET, "2.2.2.2", 24, &error);
g_assert_no_error (error);
nm_ip_address_set_attribute (addr, "label", g_variant_new_string ("eth0:1"));
@@ -366,7 +366,7 @@ test_setting_ip4_config_labels (void)
g_assert_cmpstr (g_variant_get_string (label, NULL), ==, "eth0:1");
/* addr 3 */
- addr = nm_ip_address_new (AF_INET, "3.3.3.3", 24, NULL, &error);
+ addr = nm_ip_address_new (AF_INET, "3.3.3.3", 24, &error);
g_assert_no_error (error);
nm_ip_address_set_attribute (addr, "label", NULL);
@@ -1634,6 +1634,7 @@ test_connection_diff_a_only (void)
{ NM_SETTING_IP_CONFIG_DNS, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_IP_CONFIG_DNS_SEARCH, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_DIFF_RESULT_IN_A },
+ { NM_SETTING_IP_CONFIG_GATEWAY, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_IP_CONFIG_ROUTES, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, NM_SETTING_DIFF_RESULT_IN_A },
@@ -2480,7 +2481,7 @@ test_setting_ip4_changed_signal (void)
ASSERT_CHANGED (nm_setting_ip_config_add_dns_search (s_ip4, "foobar.com"));
ASSERT_CHANGED (nm_setting_ip_config_clear_dns_searches (s_ip4));
- addr = nm_ip_address_new (AF_INET, "22.33.0.0", 24, NULL, &error);
+ addr = nm_ip_address_new (AF_INET, "22.33.0.0", 24, &error);
g_assert_no_error (error);
ASSERT_CHANGED (nm_setting_ip_config_add_address (s_ip4, addr));
ASSERT_CHANGED (nm_setting_ip_config_remove_address (s_ip4, 0));
@@ -2549,7 +2550,7 @@ test_setting_ip6_changed_signal (void)
nm_setting_ip_config_add_dns_search (s_ip6, "foobar.com");
ASSERT_CHANGED (nm_setting_ip_config_clear_dns_searches (s_ip6));
- addr = nm_ip_address_new (AF_INET6, "1:2:3::4:5:6", 64, NULL, &error);
+ addr = nm_ip_address_new (AF_INET6, "1:2:3::4:5:6", 64, &error);
g_assert_no_error (error);
ASSERT_CHANGED (nm_setting_ip_config_add_address (s_ip6, addr));
@@ -3336,6 +3337,145 @@ test_connection_normalize_infiniband_mtu (void)
g_assert_cmpint (65520, ==, nm_setting_infiniband_get_mtu (s_infini));
}
+static void
+test_setting_ip4_gateway (void)
+{
+ NMConnection *conn;
+ NMSettingIPConfig *s_ip4;
+ NMIPAddress *addr;
+ GVariant *conn_dict, *ip4_dict, *value;
+ GVariantIter iter;
+ GVariant *addr_var;
+ GError *error = NULL;
+
+ /* When serializing, ipv4.gateway is copied to the first entry of ipv4.addresses */
+ conn = nmtst_create_minimal_connection ("test_setting_ip4_gateway", NULL,
+ NM_SETTING_WIRED_SETTING_NAME, NULL);
+ s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new ();
+ g_object_set (s_ip4,
+ NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
+ NM_SETTING_IP_CONFIG_GATEWAY, "192.168.1.1",
+ NULL);
+ nm_connection_add_setting (conn, NM_SETTING (s_ip4));
+
+ addr = nm_ip_address_new (AF_INET, "192.168.1.10", 24, &error);
+ g_assert_no_error (error);
+ nm_setting_ip_config_add_address (s_ip4, addr);
+ nm_ip_address_unref (addr);
+
+ conn_dict = nm_connection_to_dbus (conn, NM_CONNECTION_SERIALIZE_ALL);
+ g_object_unref (conn);
+
+ ip4_dict = g_variant_lookup_value (conn_dict, NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_VARIANT_TYPE_SETTING);
+ g_assert (ip4_dict != NULL);
+
+ value = g_variant_lookup_value (ip4_dict, NM_SETTING_IP_CONFIG_GATEWAY, G_VARIANT_TYPE_STRING);
+ g_assert (value != NULL);
+ g_assert_cmpstr (g_variant_get_string (value, NULL), ==, "192.168.1.1");
+ g_variant_unref (value);
+
+ value = g_variant_lookup_value (ip4_dict, NM_SETTING_IP_CONFIG_ADDRESSES, G_VARIANT_TYPE ("aau"));
+ g_assert (value != NULL);
+
+ g_variant_iter_init (&iter, value);
+ while (g_variant_iter_next (&iter, "@au", &addr_var)) {
+ const guint32 *addr_array;
+ gsize length;
+
+ addr_array = g_variant_get_fixed_array (addr_var, &length, sizeof (guint32));
+ g_assert_cmpint (length, ==, 3);
+ g_assert_cmpstr (nm_utils_inet4_ntop (addr_array[2], NULL), ==, "192.168.1.1");
+ g_variant_unref (addr_var);
+ }
+ g_variant_unref (value);
+
+ g_variant_unref (ip4_dict);
+
+ /* When deserializing, the first gateway in ipv4.addresses is copied to ipv4.gateway */
+ NMTST_VARIANT_EDITOR (conn_dict,
+ NMTST_VARIANT_DROP_PROPERTY (NM_SETTING_IP4_CONFIG_SETTING_NAME,
+ NM_SETTING_IP_CONFIG_GATEWAY);
+ );
+
+ conn = nm_simple_connection_new_from_dbus (conn_dict, &error);
+ g_variant_unref (conn_dict);
+ g_assert_no_error (error);
+
+ s_ip4 = (NMSettingIPConfig *) nm_connection_get_setting_ip4_config (conn);
+ g_assert_cmpstr (nm_setting_ip_config_get_gateway (s_ip4), ==, "192.168.1.1");
+
+ g_object_unref (conn);
+}
+
+static void
+test_setting_ip6_gateway (void)
+{
+ NMConnection *conn;
+ NMSettingIPConfig *s_ip6;
+ NMIPAddress *addr;
+ GVariant *conn_dict, *ip6_dict, *value;
+ GVariantIter iter;
+ GVariant *gateway_var;
+ GError *error = NULL;
+
+ /* When serializing, ipv6.gateway is copied to the first entry of ipv6.addresses */
+ conn = nmtst_create_minimal_connection ("test_setting_ip6_gateway", NULL,
+ NM_SETTING_WIRED_SETTING_NAME, NULL);
+ s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new ();
+ g_object_set (s_ip6,
+ NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_MANUAL,
+ NM_SETTING_IP_CONFIG_GATEWAY, "abcd::1",
+ NULL);
+ nm_connection_add_setting (conn, NM_SETTING (s_ip6));
+
+ addr = nm_ip_address_new (AF_INET6, "abcd::10", 64, &error);
+ g_assert_no_error (error);
+ nm_setting_ip_config_add_address (s_ip6, addr);
+ nm_ip_address_unref (addr);
+
+ conn_dict = nm_connection_to_dbus (conn, NM_CONNECTION_SERIALIZE_ALL);
+ g_object_unref (conn);
+
+ ip6_dict = g_variant_lookup_value (conn_dict, NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_VARIANT_TYPE_SETTING);
+ g_assert (ip6_dict != NULL);
+
+ value = g_variant_lookup_value (ip6_dict, NM_SETTING_IP_CONFIG_GATEWAY, G_VARIANT_TYPE_STRING);
+ g_assert (value != NULL);
+ g_assert_cmpstr (g_variant_get_string (value, NULL), ==, "abcd::1");
+
+ value = g_variant_lookup_value (ip6_dict, NM_SETTING_IP_CONFIG_ADDRESSES, G_VARIANT_TYPE ("a(ayuay)"));
+ g_assert (value != NULL);
+
+ g_variant_iter_init (&iter, value);
+ while (g_variant_iter_next (&iter, "(@ayu@ay)", NULL, NULL, &gateway_var)) {
+ const guint8 *gateway_bytes;
+ gsize length;
+
+ gateway_bytes = g_variant_get_fixed_array (gateway_var, &length, 1);
+ g_assert_cmpint (length, ==, 16);
+ g_assert_cmpstr (nm_utils_inet6_ntop ((struct in6_addr *) gateway_bytes, NULL), ==, "abcd::1");
+ g_variant_unref (gateway_var);
+ }
+ g_variant_unref (value);
+
+ g_variant_unref (ip6_dict);
+
+ /* When deserializing, the first gateway in ipv4.addresses is copied to ipv4.gateway */
+ NMTST_VARIANT_EDITOR (conn_dict,
+ NMTST_VARIANT_DROP_PROPERTY (NM_SETTING_IP6_CONFIG_SETTING_NAME,
+ NM_SETTING_IP_CONFIG_GATEWAY);
+ );
+
+ conn = nm_simple_connection_new_from_dbus (conn_dict, &error);
+ g_variant_unref (conn_dict);
+ g_assert_no_error (error);
+
+ s_ip6 = (NMSettingIPConfig *) nm_connection_get_setting_ip6_config (conn);
+ g_assert_cmpstr (nm_setting_ip_config_get_gateway (s_ip6), ==, "abcd::1");
+
+ g_object_unref (conn);
+}
+
NMTST_DEFINE ();
int main (int argc, char **argv)
@@ -3424,6 +3564,8 @@ int main (int argc, char **argv)
g_test_add_func ("/core/general/test_setting_wireless_changed_signal", test_setting_wireless_changed_signal);
g_test_add_func ("/core/general/test_setting_wireless_security_changed_signal", test_setting_wireless_security_changed_signal);
g_test_add_func ("/core/general/test_setting_802_1x_changed_signal", test_setting_802_1x_changed_signal);
+ g_test_add_func ("/core/general/test_setting_ip4_gateway", test_setting_ip4_gateway);
+ g_test_add_func ("/core/general/test_setting_ip6_gateway", test_setting_ip6_gateway);
return g_test_run ();
}