diff options
author | Dan Winship <danw@gnome.org> | 2014-02-19 16:10:14 -0500 |
---|---|---|
committer | Dan Winship <danw@gnome.org> | 2014-03-26 10:39:36 -0400 |
commit | e0832bdb795fadbdc3b18c1321f750626e11e5a0 (patch) | |
tree | a73dc22abc9d516e0280c334faeb2d72bb0fd6a1 | |
parent | 6f61b3b934641ce8e7099728d106453a6a0592f5 (diff) | |
download | NetworkManager-e0832bdb795fadbdc3b18c1321f750626e11e5a0.tar.gz |
libnm-util: add (private API) support for address labels to NMSettingIP4Config
-rw-r--r-- | libnm-util/nm-setting-ip4-config.c | 125 | ||||
-rw-r--r-- | libnm-util/nm-setting-private.h | 6 | ||||
-rw-r--r-- | libnm-util/nm-util-private.c | 2 | ||||
-rw-r--r-- | libnm-util/nm-util-private.h | 7 | ||||
-rw-r--r-- | libnm-util/tests/test-general.c | 150 |
5 files changed, 283 insertions, 7 deletions
diff --git a/libnm-util/nm-setting-ip4-config.c b/libnm-util/nm-setting-ip4-config.c index be819b1cac..d6574ca659 100644 --- a/libnm-util/nm-setting-ip4-config.c +++ b/libnm-util/nm-setting-ip4-config.c @@ -78,6 +78,7 @@ typedef struct { GArray *dns; /* array of guint32; elements in network byte order */ GSList *dns_search; /* list of strings */ GSList *addresses; /* array of NMIP4Address */ + GSList *address_labels; /* list of strings */ GSList *routes; /* array of NMIP4Route */ gboolean ignore_auto_routes; gboolean ignore_auto_dns; @@ -94,6 +95,7 @@ enum { PROP_DNS, PROP_DNS_SEARCH, PROP_ADDRESSES, + PROP_ADDRESS_LABELS, PROP_ROUTES, PROP_IGNORE_AUTO_ROUTES, PROP_IGNORE_AUTO_DNS, @@ -440,6 +442,19 @@ nm_setting_ip4_config_get_address (NMSettingIP4Config *setting, guint32 i) return (NMIP4Address *) g_slist_nth_data (priv->addresses, i); } +const char * +nm_setting_ip4_config_get_address_label (NMSettingIP4Config *setting, guint32 i) +{ + NMSettingIP4ConfigPrivate *priv; + + g_return_val_if_fail (NM_IS_SETTING_IP4_CONFIG (setting), NULL); + + priv = NM_SETTING_IP4_CONFIG_GET_PRIVATE (setting); + g_return_val_if_fail (i <= g_slist_length (priv->address_labels), NULL); + + return (const char *) g_slist_nth_data (priv->address_labels, i); +} + /** * nm_setting_ip4_config_add_address: * @setting: the #NMSettingIP4Config @@ -455,6 +470,14 @@ gboolean nm_setting_ip4_config_add_address (NMSettingIP4Config *setting, NMIP4Address *address) { + return nm_setting_ip4_config_add_address_with_label (setting, address, NULL); +} + +gboolean +nm_setting_ip4_config_add_address_with_label (NMSettingIP4Config *setting, + NMIP4Address *address, + const char *label) +{ NMSettingIP4ConfigPrivate *priv; NMIP4Address *copy; GSList *iter; @@ -472,6 +495,8 @@ nm_setting_ip4_config_add_address (NMSettingIP4Config *setting, g_return_val_if_fail (copy != NULL, FALSE); priv->addresses = g_slist_append (priv->addresses, copy); + priv->address_labels = g_slist_append (priv->address_labels, g_strdup (label)); + g_object_notify (G_OBJECT (setting), NM_SETTING_IP4_CONFIG_ADDRESSES); return TRUE; } @@ -487,16 +512,21 @@ void nm_setting_ip4_config_remove_address (NMSettingIP4Config *setting, guint32 i) { NMSettingIP4ConfigPrivate *priv; - GSList *elt; + GSList *addr, *label; g_return_if_fail (NM_IS_SETTING_IP4_CONFIG (setting)); priv = NM_SETTING_IP4_CONFIG_GET_PRIVATE (setting); - elt = g_slist_nth (priv->addresses, i); - g_return_if_fail (elt != NULL); + addr = g_slist_nth (priv->addresses, i); + label = g_slist_nth (priv->address_labels, i); + g_return_if_fail (addr != NULL && label != NULL); + + nm_ip4_address_unref ((NMIP4Address *) addr->data); + priv->addresses = g_slist_delete_link (priv->addresses, addr); + if (label->data) + g_free (label->data); + priv->address_labels = g_slist_delete_link (priv->address_labels, label); - nm_ip4_address_unref ((NMIP4Address *) elt->data); - priv->addresses = g_slist_delete_link (priv->addresses, elt); g_object_notify (G_OBJECT (setting), NM_SETTING_IP4_CONFIG_ADDRESSES); } @@ -548,6 +578,8 @@ nm_setting_ip4_config_clear_addresses (NMSettingIP4Config *setting) g_slist_free_full (priv->addresses, (GDestroyNotify) nm_ip4_address_unref); priv->addresses = NULL; + g_slist_free_full (priv->address_labels, g_free); + priv->address_labels = NULL; g_object_notify (G_OBJECT (setting), NM_SETTING_IP4_CONFIG_ADDRESSES); } @@ -822,10 +854,34 @@ nm_setting_ip4_config_get_may_fail (NMSettingIP4Config *setting) } 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, GSList *all_settings, GError **error) { NMSettingIP4ConfigPrivate *priv = NM_SETTING_IP4_CONFIG_GET_PRIVATE (setting); - GSList *iter; + GSList *iter, *l_iter; int i; if (!priv->method) { @@ -912,8 +968,11 @@ verify (NMSetting *setting, GSList *all_settings, GError **error) } /* Validate addresses */ - for (iter = priv->addresses, i = 0; iter; iter = g_slist_next (iter), i++) { + for (iter = priv->addresses, l_iter = priv->address_labels, i = 0; + iter && l_iter; + iter = g_slist_next (iter), l_iter = g_slist_next (l_iter), i++) { NMIP4Address *addr = (NMIP4Address *) iter->data; + const char *label = (const char *) l_iter->data; guint32 prefix = nm_ip4_address_get_prefix (addr); if (!nm_ip4_address_get_address (addr)) { @@ -935,6 +994,27 @@ verify (NMSetting *setting, GSList *all_settings, GError **error) g_prefix_error (error, "%s.%s: ", NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_SETTING_IP4_CONFIG_ADDRESSES); return FALSE; } + + if (label && !verify_label (label)) { + g_set_error (error, + NM_SETTING_IP4_CONFIG_ERROR, + NM_SETTING_IP4_CONFIG_ERROR_INVALID_PROPERTY, + _("%d. IPv4 address has invalid label '%s'"), + i+1, label); + g_prefix_error (error, "%s.%s: ", NM_SETTING_IP4_CONFIG_SETTING_NAME, "address-labels"); + return FALSE; + } + } + + if (iter || l_iter) { + g_set_error (error, + NM_SETTING_IP4_CONFIG_ERROR, + NM_SETTING_IP4_CONFIG_ERROR_INVALID_PROPERTY, + _("IPv4 address / label count mismatch (%d vs %d)"), + g_slist_length (priv->addresses), + g_slist_length (priv->address_labels)); + g_prefix_error (error, "%s.%s: ", NM_SETTING_IP4_CONFIG_SETTING_NAME, "address-labels"); + return FALSE; } /* Validate routes */ @@ -990,6 +1070,7 @@ finalize (GObject *object) g_slist_free_full (priv->dns_search, g_free); g_slist_free_full (priv->addresses, (GDestroyNotify) nm_ip4_address_unref); + g_slist_free_full (priv->address_labels, g_free); g_slist_free_full (priv->routes, (GDestroyNotify) nm_ip4_route_unref); G_OBJECT_CLASS (nm_setting_ip4_config_parent_class)->finalize (object); @@ -1001,6 +1082,7 @@ set_property (GObject *object, guint prop_id, { NMSettingIP4Config *setting = NM_SETTING_IP4_CONFIG (object); NMSettingIP4ConfigPrivate *priv = NM_SETTING_IP4_CONFIG_GET_PRIVATE (setting); + GSList *iter; switch (prop_id) { case PROP_METHOD: @@ -1020,6 +1102,24 @@ set_property (GObject *object, guint prop_id, case PROP_ADDRESSES: g_slist_free_full (priv->addresses, (GDestroyNotify) nm_ip4_address_unref); priv->addresses = nm_utils_ip4_addresses_from_gvalue (value); + + if (g_slist_length (priv->addresses) != g_slist_length (priv->address_labels)) { + g_slist_free_full (priv->address_labels, g_free); + priv->address_labels = NULL; + for (iter = priv->addresses; iter; iter = iter->next) + priv->address_labels = g_slist_prepend (priv->address_labels, NULL); + } + break; + case PROP_ADDRESS_LABELS: + g_slist_free_full (priv->address_labels, g_free); + priv->address_labels = g_value_dup_boxed (value); + /* NULLs get converted to "" when this is sent over D-Bus. */ + for (iter = priv->address_labels; iter; iter = iter->next) { + if (!g_strcmp0 (iter->data, "")) { + g_free (iter->data); + iter->data = NULL; + } + } break; case PROP_ROUTES: g_slist_free_full (priv->routes, (GDestroyNotify) nm_ip4_route_unref); @@ -1074,6 +1174,9 @@ get_property (GObject *object, guint prop_id, case PROP_ADDRESSES: nm_utils_ip4_addresses_to_gvalue (priv->addresses, value); break; + case PROP_ADDRESS_LABELS: + g_value_set_boxed (value, priv->address_labels); + break; case PROP_ROUTES: nm_utils_ip4_routes_to_gvalue (priv->routes, value); break; @@ -1239,6 +1342,14 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *setting_class) DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT, G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE)); + g_object_class_install_property + (object_class, PROP_ADDRESS_LABELS, + _nm_param_spec_specialized ("address-labels", + "Address labels", + "Internal use only", + DBUS_TYPE_G_LIST_OF_STRING, + G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE)); + /** * NMSettingIP4Config:routes: * diff --git a/libnm-util/nm-setting-private.h b/libnm-util/nm-setting-private.h index b3a0947123..c3ec9d1993 100644 --- a/libnm-util/nm-setting-private.h +++ b/libnm-util/nm-setting-private.h @@ -21,6 +21,7 @@ #ifndef NM_SETTING_PRIVATE_H #define NM_SETTING_PRIVATE_H +#include "nm-setting.h" #include "nm-glib-compat.h" #define NM_SETTING_SECRET_FLAGS_ALL \ @@ -86,5 +87,10 @@ static void __attribute__((constructor)) register_setting (void) \ NMSetting *nm_setting_find_in_list (GSList *settings_list, const char *setting_name); +/* Private NMSettingIP4Config methods */ +#include "nm-setting-ip4-config.h" +const char *nm_setting_ip4_config_get_address_label (NMSettingIP4Config *setting, guint32 i); +gboolean nm_setting_ip4_config_add_address_with_label (NMSettingIP4Config *setting, NMIP4Address *address, const char *label); + #endif /* NM_SETTING_PRIVATE_H */ diff --git a/libnm-util/nm-util-private.c b/libnm-util/nm-util-private.c index 2b67080f69..545113e619 100644 --- a/libnm-util/nm-util-private.c +++ b/libnm-util/nm-util-private.c @@ -22,6 +22,8 @@ #include "nm-util-private.h" static const NMUtilPrivateData data = { + .nm_setting_ip4_config_get_address_label = nm_setting_ip4_config_get_address_label, + .nm_setting_ip4_config_add_address_with_label = nm_setting_ip4_config_add_address_with_label, }; /** diff --git a/libnm-util/nm-util-private.h b/libnm-util/nm-util-private.h index 819faa9eba..f59fc887ab 100644 --- a/libnm-util/nm-util-private.h +++ b/libnm-util/nm-util-private.h @@ -24,9 +24,16 @@ #include <glib.h> +#include "nm-setting-private.h" + G_BEGIN_DECLS typedef struct NMUtilPrivateData { + const char * (*nm_setting_ip4_config_get_address_label) (NMSettingIP4Config *setting, + guint32 i); + gboolean (*nm_setting_ip4_config_add_address_with_label) (NMSettingIP4Config *setting, + NMIP4Address *address, + const char *label); } NMUtilPrivateData; const NMUtilPrivateData *nm_util_get_private (void); diff --git a/libnm-util/tests/test-general.c b/libnm-util/tests/test-general.c index 90aa05bfbd..0af42150ac 100644 --- a/libnm-util/tests/test-general.c +++ b/libnm-util/tests/test-general.c @@ -42,6 +42,7 @@ #include "nm-setting-vlan.h" #include "nm-setting-bond.h" #include "nm-utils.h" +#include "nm-util-private.h" #include "nm-dbus-glib-types.h" #include "nm-glib-compat.h" @@ -272,6 +273,153 @@ test_setting_vpn_modify_during_foreach (void) g_object_unref (s_vpn); } +static void +test_setting_ip4_config_labels (void) +{ + NMSettingIP4Config *s_ip4; + NMIP4Address *addr; + const char *label; + GPtrArray *addrs; + GSList *labels; + GError *error = NULL; + + s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new (); + g_object_set (G_OBJECT (s_ip4), + NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL, + NULL); + + /* addr 1 */ + addr = nm_ip4_address_new (); + nm_ip4_address_set_address (addr, 0x01010101); + nm_ip4_address_set_prefix (addr, 24); + + nm_setting_ip4_config_add_address (s_ip4, addr); + nm_setting_verify (NM_SETTING (s_ip4), NULL, &error); + g_assert_no_error (error); + + label = NM_UTIL_PRIVATE_CALL (nm_setting_ip4_config_get_address_label (s_ip4, 0)); + g_assert_cmpstr (label, ==, NULL); + + /* addr 2 */ + addr = nm_ip4_address_new (); + nm_ip4_address_set_address (addr, 0x02020202); + nm_ip4_address_set_prefix (addr, 24); + + NM_UTIL_PRIVATE_CALL (nm_setting_ip4_config_add_address_with_label (s_ip4, addr, "eth0:1")); + nm_setting_verify (NM_SETTING (s_ip4), NULL, &error); + g_assert_no_error (error); + + label = NM_UTIL_PRIVATE_CALL (nm_setting_ip4_config_get_address_label (s_ip4, 1)); + g_assert_cmpstr (label, ==, "eth0:1"); + + /* addr 3 */ + addr = nm_ip4_address_new (); + nm_ip4_address_set_address (addr, 0x03030303); + nm_ip4_address_set_prefix (addr, 24); + + NM_UTIL_PRIVATE_CALL (nm_setting_ip4_config_add_address_with_label (s_ip4, addr, NULL)); + nm_setting_verify (NM_SETTING (s_ip4), NULL, &error); + g_assert_no_error (error); + + label = NM_UTIL_PRIVATE_CALL (nm_setting_ip4_config_get_address_label (s_ip4, 2)); + g_assert_cmpstr (label, ==, NULL); + + /* Remove addr 1 and re-verify remaining addresses */ + nm_setting_ip4_config_remove_address (s_ip4, 0); + nm_setting_verify (NM_SETTING (s_ip4), NULL, &error); + g_assert_no_error (error); + + addr = nm_setting_ip4_config_get_address (s_ip4, 0); + g_assert_cmpint (nm_ip4_address_get_address (addr), ==, 0x02020202); + label = NM_UTIL_PRIVATE_CALL (nm_setting_ip4_config_get_address_label (s_ip4, 0)); + g_assert_cmpstr (label, ==, "eth0:1"); + + addr = nm_setting_ip4_config_get_address (s_ip4, 1); + g_assert_cmpint (nm_ip4_address_get_address (addr), ==, 0x03030303); + label = NM_UTIL_PRIVATE_CALL (nm_setting_ip4_config_get_address_label (s_ip4, 1)); + g_assert_cmpstr (label, ==, NULL); + + + /* Test explicit property assignment */ + g_object_get (G_OBJECT (s_ip4), + NM_SETTING_IP4_CONFIG_ADDRESSES, &addrs, + "address-labels", &labels, + NULL); + + nm_setting_ip4_config_clear_addresses (s_ip4); + g_assert_cmpint (nm_setting_ip4_config_get_num_addresses (s_ip4), ==, 0); + + /* Setting addrs but not labels will result in empty labels */ + g_object_set (G_OBJECT (s_ip4), + NM_SETTING_IP4_CONFIG_ADDRESSES, addrs, + NULL); + g_boxed_free (DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT, addrs); + nm_setting_verify (NM_SETTING (s_ip4), NULL, &error); + g_assert_no_error (error); + g_assert_cmpint (nm_setting_ip4_config_get_num_addresses (s_ip4), ==, 2); + + addr = nm_setting_ip4_config_get_address (s_ip4, 0); + g_assert_cmpint (nm_ip4_address_get_address (addr), ==, 0x02020202); + label = NM_UTIL_PRIVATE_CALL (nm_setting_ip4_config_get_address_label (s_ip4, 0)); + g_assert_cmpstr (label, ==, NULL); + + addr = nm_setting_ip4_config_get_address (s_ip4, 1); + g_assert_cmpint (nm_ip4_address_get_address (addr), ==, 0x03030303); + label = NM_UTIL_PRIVATE_CALL (nm_setting_ip4_config_get_address_label (s_ip4, 1)); + g_assert_cmpstr (label, ==, NULL); + + /* Setting labels now will leave addresses untouched */ + g_object_set (G_OBJECT (s_ip4), + "address-labels", labels, + NULL); + g_boxed_free (DBUS_TYPE_G_LIST_OF_STRING, labels); + nm_setting_verify (NM_SETTING (s_ip4), NULL, &error); + g_assert_no_error (error); + g_assert_cmpint (nm_setting_ip4_config_get_num_addresses (s_ip4), ==, 2); + + addr = nm_setting_ip4_config_get_address (s_ip4, 0); + g_assert_cmpint (nm_ip4_address_get_address (addr), ==, 0x02020202); + label = NM_UTIL_PRIVATE_CALL (nm_setting_ip4_config_get_address_label (s_ip4, 0)); + g_assert_cmpstr (label, ==, "eth0:1"); + + addr = nm_setting_ip4_config_get_address (s_ip4, 1); + g_assert_cmpint (nm_ip4_address_get_address (addr), ==, 0x03030303); + label = NM_UTIL_PRIVATE_CALL (nm_setting_ip4_config_get_address_label (s_ip4, 1)); + g_assert_cmpstr (label, ==, NULL); + + /* Setting labels to a value that's too short or too long will result in + * the setting not verifying. + */ + labels = g_slist_append (NULL, "eth0:2"); + g_object_set (G_OBJECT (s_ip4), + "address-labels", labels, + NULL); + + nm_setting_verify (NM_SETTING (s_ip4), NULL, &error); + g_assert_error (error, NM_SETTING_IP4_CONFIG_ERROR, NM_SETTING_IP4_CONFIG_ERROR_INVALID_PROPERTY); + g_assert (g_str_has_prefix (error->message, "ipv4.address-labels:")); + g_clear_error (&error); + + labels = g_slist_append (labels, "eth0:3"); + g_object_set (G_OBJECT (s_ip4), + "address-labels", labels, + NULL); + nm_setting_verify (NM_SETTING (s_ip4), NULL, &error); + g_assert_no_error (error); + + labels = g_slist_append (labels, "eth0:4"); + g_object_set (G_OBJECT (s_ip4), + "address-labels", labels, + NULL); + nm_setting_verify (NM_SETTING (s_ip4), NULL, &error); + g_assert_error (error, NM_SETTING_IP4_CONFIG_ERROR, NM_SETTING_IP4_CONFIG_ERROR_INVALID_PROPERTY); + g_assert (g_str_has_prefix (error->message, "ipv4.address-labels:")); + g_clear_error (&error); + + + g_object_unref (s_ip4); +} + #define OLD_DBUS_TYPE_G_IP6_ADDRESS (dbus_g_type_get_struct ("GValueArray", DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_UINT, G_TYPE_INVALID)) #define OLD_DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS (dbus_g_type_get_collection ("GPtrArray", OLD_DBUS_TYPE_G_IP6_ADDRESS)) @@ -1197,6 +1345,7 @@ test_connection_diff_a_only (void) { NM_SETTING_IP4_CONFIG_DNS, NM_SETTING_DIFF_RESULT_IN_A }, { NM_SETTING_IP4_CONFIG_DNS_SEARCH, NM_SETTING_DIFF_RESULT_IN_A }, { NM_SETTING_IP4_CONFIG_ADDRESSES, NM_SETTING_DIFF_RESULT_IN_A }, + { "address-labels", NM_SETTING_DIFF_RESULT_IN_A }, { NM_SETTING_IP4_CONFIG_ROUTES, NM_SETTING_DIFF_RESULT_IN_A }, { NM_SETTING_IP4_CONFIG_IGNORE_AUTO_ROUTES, NM_SETTING_DIFF_RESULT_IN_A }, { NM_SETTING_IP4_CONFIG_IGNORE_AUTO_DNS, NM_SETTING_DIFF_RESULT_IN_A }, @@ -2232,6 +2381,7 @@ int main (int argc, char **argv) test_setting_vpn_items (); test_setting_vpn_update_secrets (); test_setting_vpn_modify_during_foreach (); + test_setting_ip4_config_labels (); test_setting_ip6_config_old_address_array (); test_setting_gsm_apn_spaces (); test_setting_gsm_apn_bad_chars (); |