summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2014-07-08 18:36:02 +0200
committerThomas Haller <thaller@redhat.com>2014-08-22 15:24:31 +0200
commita9e0796433cd89c7a2280777ac35e659c95b52d8 (patch)
tree5af7975829267bfedf1b8135e262f4424c95ece1
parentf60256e035ff650a86e4a8073d91c512d02bcb4d (diff)
downloadNetworkManager-a9e0796433cd89c7a2280777ac35e659c95b52d8.tar.gz
libnm-core: normalize NMSettingConnection:type property
nm_connection_normalize() can now detect the 'type' property based on existing base settings. It can also create a (default) base setting. Signed-off-by: Thomas Haller <thaller@redhat.com>
-rw-r--r--libnm-core/nm-connection.c36
-rw-r--r--libnm-core/nm-setting-connection.c63
-rw-r--r--libnm-core/nm-setting-private.h1
-rw-r--r--libnm-core/nm-setting.c23
-rw-r--r--libnm-core/tests/test-general.c327
5 files changed, 437 insertions, 13 deletions
diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c
index 709fc20a64..1f112603a1 100644
--- a/libnm-core/nm-connection.c
+++ b/libnm-core/nm-connection.c
@@ -581,6 +581,41 @@ _normalize_virtual_iface_name (NMConnection *self)
}
static gboolean
+_normalize_connection_type (NMConnection *self)
+{
+ NMSettingConnection *s_con = nm_connection_get_setting_connection (self);
+ NMSetting *s_base = NULL;
+ const char *type;
+ GSList *all_settings;
+
+ type = nm_setting_connection_get_connection_type (s_con);
+
+ if (type) {
+ s_base = nm_connection_get_setting_by_name (self, type);
+
+ if (!s_base) {
+ GType base_type = nm_setting_lookup_type (type);
+
+ g_return_val_if_fail (base_type, FALSE);
+ nm_connection_add_setting (self, g_object_new (base_type, NULL));
+ return TRUE;
+ }
+ } else {
+ all_settings = _nm_utils_hash_values_to_slist (NM_CONNECTION_GET_PRIVATE (self)->settings);
+
+ s_base = _nm_setting_find_in_list_base_type (all_settings);
+ g_return_val_if_fail (s_base, FALSE);
+
+ type = nm_setting_get_name (s_base);
+ g_object_set (s_con, NM_SETTING_CONNECTION_TYPE, type, NULL);
+ g_slist_free (all_settings);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
_normalize_connection_slave_type (NMConnection *self)
{
NMSettingConnection *s_con = nm_connection_get_setting_connection (self);
@@ -876,6 +911,7 @@ nm_connection_normalize (NMConnection *connection,
* We only do this, after verifying that the connection contains no un-normalizable
* errors, because in that case we rather fail without touching the settings. */
+ was_modified |= _normalize_connection_type (connection);
was_modified |= _normalize_virtual_iface_name (connection);
was_modified |= _normalize_connection_slave_type (connection);
was_modified |= _normalize_ip_config (connection, parameters);
diff --git a/libnm-core/nm-setting-connection.c b/libnm-core/nm-setting-connection.c
index baf94c7250..28e5adf7de 100644
--- a/libnm-core/nm-setting-connection.c
+++ b/libnm-core/nm-setting-connection.c
@@ -735,6 +735,16 @@ nm_setting_connection_get_gateway_ping_timeout (NMSettingConnection *setting)
return NM_SETTING_CONNECTION_GET_PRIVATE (setting)->gateway_ping_timeout;
}
+static void
+_set_error_missing_base_setting (GError **error, const char *type)
+{
+ g_set_error (error,
+ NM_SETTING_CONNECTION_ERROR,
+ NM_SETTING_CONNECTION_ERROR_TYPE_SETTING_NOT_FOUND,
+ _("requires presence of '%s' setting in the connection"),
+ type);
+ g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_TYPE);
+}
static gboolean
verify (NMSetting *setting, GSList *all_settings, GError **error)
@@ -743,9 +753,11 @@ verify (NMSetting *setting, GSList *all_settings, GError **error)
gboolean is_slave;
const char *slave_setting_type = NULL;
GSList *iter;
+ NMSetting *normerr_base_type = NULL;
const char *normerr_slave_setting_type = NULL;
const char *normerr_missing_slave_type = NULL;
const char *normerr_missing_slave_type_port = NULL;
+ gboolean normerr_base_setting = FALSE;
if (!priv->id) {
g_set_error_literal (error,
@@ -825,12 +837,14 @@ verify (NMSetting *setting, GSList *all_settings, GError **error)
}
if (!priv->type) {
- g_set_error_literal (error,
- NM_SETTING_CONNECTION_ERROR,
- NM_SETTING_CONNECTION_ERROR_MISSING_PROPERTY,
- _("property is missing"));
- g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_TYPE);
- return FALSE;
+ if (!(normerr_base_type = _nm_setting_find_in_list_base_type (all_settings))) {
+ g_set_error_literal (error,
+ NM_SETTING_CONNECTION_ERROR,
+ NM_SETTING_CONNECTION_ERROR_MISSING_PROPERTY,
+ _("property is missing"));
+ g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_TYPE);
+ return FALSE;
+ }
} else {
GType base_type;
@@ -867,13 +881,21 @@ verify (NMSetting *setting, GSList *all_settings, GError **error)
/* Make sure the corresponding 'type' item is present */
if ( all_settings
&& !nm_setting_find_in_list (all_settings, priv->type)) {
- g_set_error (error,
- NM_SETTING_CONNECTION_ERROR,
- NM_SETTING_CONNECTION_ERROR_TYPE_SETTING_NOT_FOUND,
- _("requires presence of '%s' setting in the connection"),
- priv->type);
- g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_TYPE);
- return FALSE;
+ NMSetting *s_base;
+ GSList *all_settings2;
+
+ s_base = g_object_new (base_type, NULL);
+ all_settings2 = g_slist_prepend (all_settings, s_base);
+
+ normerr_base_setting = nm_setting_verify (s_base, all_settings2, NULL);
+
+ (void) g_slist_delete_link (all_settings2, all_settings2);
+ g_object_unref (s_base);
+
+ if (!normerr_base_setting) {
+ _set_error_missing_base_setting (error, priv->type);
+ return FALSE;
+ }
}
}
@@ -925,6 +947,21 @@ verify (NMSetting *setting, GSList *all_settings, GError **error)
/* *** errors above here should be always fatal, below NORMALIZABLE_ERROR *** */
+ if (normerr_base_type) {
+ g_set_error (error,
+ NM_SETTING_CONNECTION_ERROR,
+ NM_SETTING_CONNECTION_ERROR_MISSING_PROPERTY,
+ _("property type should be set to '%s'"),
+ nm_setting_get_name (normerr_base_type));
+ g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_TYPE);
+ return NM_SETTING_VERIFY_NORMALIZABLE_ERROR;
+ }
+
+ if (normerr_base_setting) {
+ _set_error_missing_base_setting (error, priv->type);
+ return NM_SETTING_VERIFY_NORMALIZABLE_ERROR;
+ }
+
if (normerr_slave_setting_type) {
g_set_error (error,
NM_SETTING_CONNECTION_ERROR,
diff --git a/libnm-core/nm-setting-private.h b/libnm-core/nm-setting-private.h
index 316838a32b..4c316864b1 100644
--- a/libnm-core/nm-setting-private.h
+++ b/libnm-core/nm-setting-private.h
@@ -110,6 +110,7 @@ NMSettingVerifyResult _nm_setting_verify (NMSetting *setting,
GSList *all_settings,
GError **error);
+NMSetting *_nm_setting_find_in_list_base_type (GSList *all_settings);
gboolean _nm_setting_slave_type_is_valid (const char *slave_type, const char **out_port_type);
const char * _nm_setting_slave_type_detect_from_settings (GSList *all_settings, NMSetting **out_s_port);
diff --git a/libnm-core/nm-setting.c b/libnm-core/nm-setting.c
index 5fc0b64867..61cbdc3ede 100644
--- a/libnm-core/nm-setting.c
+++ b/libnm-core/nm-setting.c
@@ -311,6 +311,29 @@ _nm_setting_slave_type_is_valid (const char *slave_type, const char **out_port_t
}
+NMSetting *
+_nm_setting_find_in_list_base_type (GSList *all_settings)
+{
+ GSList *iter;
+ NMSetting *setting = NULL;
+
+ for (iter = all_settings; iter; iter = iter->next) {
+ NMSetting *s_iter = NM_SETTING (iter->data);
+
+ if (!_nm_setting_is_base_type (s_iter))
+ continue;
+
+ if (setting) {
+ /* FIXME: currently, if there is more than one matching base type,
+ * we cannot detect the base setting.
+ * See: https://bugzilla.gnome.org/show_bug.cgi?id=696936#c8 */
+ return NULL;
+ }
+ setting = s_iter;
+ }
+ return setting;
+}
+
const char *
_nm_setting_slave_type_detect_from_settings (GSList *all_settings, NMSetting **out_s_port)
{
diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c
index f9a7714b8c..a77930f7aa 100644
--- a/libnm-core/tests/test-general.c
+++ b/libnm-core/tests/test-general.c
@@ -2659,6 +2659,332 @@ test_connection_normalize_virtual_iface_name (void)
}
static void
+_test_connection_normalize_type_normalizable_setting (const char *type,
+ void (*prepare_normalizable_fcn) (NMConnection *con))
+{
+ NMSettingConnection *s_con;
+ NMSetting *s_base;
+ GType base_type;
+ gs_unref_object NMConnection *con = NULL;
+ gs_free char *id = g_strdup_printf ("%s[%s]", G_STRFUNC, type);
+
+ base_type = nm_setting_lookup_type (type);
+ g_assert (base_type != G_TYPE_INVALID);
+ g_assert (_nm_setting_type_is_base_type (base_type));
+
+ con = nmtst_create_minimal_connection (id, NULL, NULL, &s_con);
+
+ nmtst_assert_connection_unnormalizable (con, NM_SETTING_CONNECTION_ERROR, NM_SETTING_CONNECTION_ERROR_MISSING_PROPERTY);
+
+ g_object_set (s_con, NM_SETTING_CONNECTION_TYPE, type, NULL);
+
+ if (prepare_normalizable_fcn)
+ prepare_normalizable_fcn (con);
+
+ g_assert (!nm_connection_get_setting_by_name (con, type));
+ nmtst_assert_connection_verifies_after_normalization (con, NM_SETTING_CONNECTION_ERROR, NM_SETTING_CONNECTION_ERROR_TYPE_SETTING_NOT_FOUND);
+
+ s_base = nm_connection_get_setting_by_name (con, type);
+ g_assert (s_base);
+ g_assert (G_OBJECT_TYPE (s_base) == base_type);
+}
+
+static void
+_test_connection_normalize_type_unnormalizable_setting (const char *type)
+{
+ NMSettingConnection *s_con;
+ GType base_type;
+ gs_unref_object NMConnection *con = NULL;
+ gs_free char *id = g_strdup_printf ("%s[%s]", G_STRFUNC, type);
+
+ base_type = nm_setting_lookup_type (type);
+ g_assert (base_type != G_TYPE_INVALID);
+ g_assert (_nm_setting_type_is_base_type (base_type));
+
+ con = nmtst_create_minimal_connection (id, NULL, NULL, &s_con);
+
+ nmtst_assert_connection_unnormalizable (con, NM_SETTING_CONNECTION_ERROR, NM_SETTING_CONNECTION_ERROR_MISSING_PROPERTY);
+
+ g_object_set (s_con, NM_SETTING_CONNECTION_TYPE, type, NULL);
+
+ nmtst_assert_connection_unnormalizable (con, NM_SETTING_CONNECTION_ERROR, NM_SETTING_CONNECTION_ERROR_TYPE_SETTING_NOT_FOUND);
+}
+
+static void
+_test_connection_normalize_type_normalizable_type (const char *type,
+ NMSetting *(*add_setting_fcn) (NMConnection *con))
+{
+ NMSettingConnection *s_con;
+ NMSetting *s_base;
+ GType base_type;
+ gs_unref_object NMConnection *con = NULL;
+ gs_free char *id = g_strdup_printf ("%s[%s]", G_STRFUNC, type);
+
+ base_type = nm_setting_lookup_type (type);
+ g_assert (base_type != G_TYPE_INVALID);
+ g_assert (_nm_setting_type_is_base_type (base_type));
+
+ con = nmtst_create_minimal_connection (id, NULL, NULL, &s_con);
+
+ nmtst_assert_connection_unnormalizable (con, NM_SETTING_CONNECTION_ERROR, NM_SETTING_CONNECTION_ERROR_MISSING_PROPERTY);
+
+ if (add_setting_fcn)
+ s_base = add_setting_fcn (con);
+ else {
+ s_base = NM_SETTING (g_object_new (base_type, NULL));
+ nm_connection_add_setting (con, s_base);
+ }
+
+ g_assert (!nm_connection_get_connection_type (con));
+ g_assert (nm_connection_get_setting_by_name (con, type) == s_base);
+
+ nmtst_assert_connection_verifies_after_normalization (con, NM_SETTING_CONNECTION_ERROR, NM_SETTING_CONNECTION_ERROR_MISSING_PROPERTY);
+
+ g_assert_cmpstr (nm_connection_get_connection_type (con), ==, type);
+ g_assert (nm_connection_get_setting_by_name (con, type) == s_base);
+}
+
+static NMSetting *
+_add_setting_fcn_adsl (NMConnection *con)
+{
+ NMSetting *setting;
+
+ setting = g_object_new (NM_TYPE_SETTING_ADSL,
+ NM_SETTING_ADSL_USERNAME, "test-user",
+ NM_SETTING_ADSL_PROTOCOL, NM_SETTING_ADSL_PROTOCOL_PPPOA,
+ NM_SETTING_ADSL_ENCAPSULATION, NM_SETTING_ADSL_ENCAPSULATION_VCMUX,
+ NULL);
+
+ nm_connection_add_setting (con, setting);
+ return setting;
+}
+
+static NMSetting *
+_add_setting_fcn_bluetooth (NMConnection *con)
+{
+ NMSetting *setting;
+ GByteArray *bdaddr = nm_utils_hwaddr_atoba ("11:22:33:44:55:66", ETH_ALEN);
+
+ setting = g_object_new (NM_TYPE_SETTING_BLUETOOTH,
+ NM_SETTING_BLUETOOTH_BDADDR, bdaddr,
+ NM_SETTING_BLUETOOTH_TYPE, NM_SETTING_BLUETOOTH_TYPE_PANU,
+ NULL);
+ g_byte_array_free (bdaddr, TRUE);
+
+ nm_connection_add_setting (con, setting);
+ return setting;
+}
+
+static NMSetting *
+_add_setting_fcn_bond (NMConnection *con)
+{
+ NMSetting *setting;
+ NMSettingConnection *s_con;
+
+ setting = g_object_new (NM_TYPE_SETTING_BOND, NULL);
+
+ nm_connection_add_setting (con, setting);
+
+ s_con = nm_connection_get_setting_connection (con);
+
+ g_object_set (s_con,
+ NM_SETTING_CONNECTION_INTERFACE_NAME, "test-bond",
+ NULL);
+
+ return setting;
+}
+
+static NMSetting *
+_add_setting_fcn_bridge (NMConnection *con)
+{
+ NMSetting *setting;
+ NMSettingConnection *s_con;
+
+ setting = g_object_new (NM_TYPE_SETTING_BRIDGE, NULL);
+
+ nm_connection_add_setting (con, setting);
+
+ s_con = nm_connection_get_setting_connection (con);
+
+ g_object_set (s_con,
+ NM_SETTING_CONNECTION_INTERFACE_NAME, "test-bridge",
+ NULL);
+
+ return setting;
+}
+
+static NMSetting *
+_add_setting_fcn_cdma (NMConnection *con)
+{
+ NMSetting *setting;
+
+ setting = g_object_new (NM_TYPE_SETTING_CDMA,
+ NM_SETTING_CDMA_NUMBER, "test-number",
+ NULL);
+
+ nm_connection_add_setting (con, setting);
+ return setting;
+}
+
+static NMSetting *
+_add_setting_fcn_infiniband (NMConnection *con)
+{
+ NMSetting *setting;
+
+ setting = g_object_new (NM_TYPE_SETTING_INFINIBAND,
+ NM_SETTING_INFINIBAND_TRANSPORT_MODE, "connected",
+ NULL);
+
+ nm_connection_add_setting (con, setting);
+ return setting;
+}
+
+static NMSetting *
+_add_setting_fcn_olpc_mesh (NMConnection *con)
+{
+ NMSetting *setting;
+ const char *ssid_data = "ssid-test";
+ GByteArray *ssid = g_byte_array_new ();
+
+ g_byte_array_append (ssid, (const guint8 *) ssid_data, strlen (ssid_data));
+ setting = g_object_new (NM_TYPE_SETTING_OLPC_MESH,
+ NM_SETTING_OLPC_MESH_SSID, ssid,
+ NM_SETTING_OLPC_MESH_CHANNEL, 1,
+ NULL);
+ g_byte_array_free (ssid, TRUE);
+
+ nm_connection_add_setting (con, setting);
+ return setting;
+}
+
+static NMSetting *
+_add_setting_fcn_team (NMConnection *con)
+{
+ NMSetting *setting;
+ NMSettingConnection *s_con;
+
+ setting = g_object_new (NM_TYPE_SETTING_TEAM, NULL);
+
+ nm_connection_add_setting (con, setting);
+
+ s_con = nm_connection_get_setting_connection (con);
+
+ g_object_set (s_con,
+ NM_SETTING_CONNECTION_INTERFACE_NAME, "test-team",
+ NULL);
+
+ return setting;
+}
+
+static NMSetting *
+_add_setting_fcn_vlan (NMConnection *con)
+{
+ NMSetting *setting;
+
+ setting = g_object_new (NM_TYPE_SETTING_VLAN,
+ NM_SETTING_VLAN_PARENT, "test-parent",
+ NULL);
+
+ nm_connection_add_setting (con, setting);
+ return setting;
+}
+
+static NMSetting *
+_add_setting_fcn_vpn (NMConnection *con)
+{
+ NMSetting *setting;
+
+ setting = g_object_new (NM_TYPE_SETTING_VPN,
+ NM_SETTING_VPN_SERVICE_TYPE, "test-vpn-service-type",
+ NULL);
+
+ nm_connection_add_setting (con, setting);
+ return setting;
+}
+
+static NMSetting *
+_add_setting_fcn_wimax (NMConnection *con)
+{
+ NMSetting *setting;
+
+ setting = g_object_new (NM_TYPE_SETTING_WIMAX,
+ NM_SETTING_WIMAX_NETWORK_NAME, "test-network",
+ NULL);
+
+ nm_connection_add_setting (con, setting);
+ return setting;
+}
+
+static NMSetting *
+_add_setting_fcn_wireless (NMConnection *con)
+{
+ NMSetting *setting;
+ const char *ssid_data = "ssid-test";
+ GByteArray *ssid = g_byte_array_new ();
+
+ g_byte_array_append (ssid, (const guint8 *) ssid_data, strlen (ssid_data));
+ setting = g_object_new (NM_TYPE_SETTING_WIRELESS,
+ NM_SETTING_WIRELESS_SSID, ssid,
+ NULL);
+ g_byte_array_free (ssid, TRUE);
+
+ nm_connection_add_setting (con, setting);
+ return setting;
+}
+
+static void
+_prepare_normalizable_fcn_vlan (NMConnection *con)
+{
+ GByteArray *mac_addr = nm_utils_hwaddr_atoba ("11:22:33:44:55:66", ETH_ALEN);
+
+ nm_connection_add_setting (con, g_object_new (NM_TYPE_SETTING_WIRED,
+ NM_SETTING_WIRED_MAC_ADDRESS, mac_addr,
+ NULL));
+ g_byte_array_free (mac_addr, TRUE);
+}
+
+static void
+test_connection_normalize_type (void)
+{
+ guint i;
+ struct {
+ const char *type;
+ gboolean normalizable;
+ NMSetting *(*add_setting_fcn) (NMConnection *con);
+ void (*prepare_normalizable_fcn) (NMConnection *con);
+ } types[] = {
+ { NM_SETTING_GENERIC_SETTING_NAME, TRUE },
+ { NM_SETTING_GSM_SETTING_NAME, TRUE },
+ { NM_SETTING_WIRED_SETTING_NAME, TRUE },
+ { NM_SETTING_VLAN_SETTING_NAME, TRUE, _add_setting_fcn_vlan, _prepare_normalizable_fcn_vlan },
+
+ { NM_SETTING_ADSL_SETTING_NAME, FALSE, _add_setting_fcn_adsl },
+ { NM_SETTING_BLUETOOTH_SETTING_NAME, FALSE, _add_setting_fcn_bluetooth },
+ { NM_SETTING_BOND_SETTING_NAME, FALSE, _add_setting_fcn_bond },
+ { NM_SETTING_BRIDGE_SETTING_NAME, FALSE, _add_setting_fcn_bridge },
+ { NM_SETTING_CDMA_SETTING_NAME, FALSE, _add_setting_fcn_cdma },
+ { NM_SETTING_INFINIBAND_SETTING_NAME, FALSE, _add_setting_fcn_infiniband },
+ { NM_SETTING_OLPC_MESH_SETTING_NAME, FALSE, _add_setting_fcn_olpc_mesh },
+ { NM_SETTING_TEAM_SETTING_NAME, FALSE, _add_setting_fcn_team },
+ { NM_SETTING_VLAN_SETTING_NAME, FALSE, _add_setting_fcn_vlan },
+ { NM_SETTING_VPN_SETTING_NAME, FALSE, _add_setting_fcn_vpn },
+ { NM_SETTING_WIMAX_SETTING_NAME, FALSE, _add_setting_fcn_wimax },
+ { NM_SETTING_WIRELESS_SETTING_NAME, FALSE, _add_setting_fcn_wireless },
+ { 0 },
+ };
+
+ for (i = 0; types[i].type; i++) {
+ const char *type = types[i].type;
+
+ if (types[i].normalizable)
+ _test_connection_normalize_type_normalizable_setting (type, types[i].prepare_normalizable_fcn);
+ else
+ _test_connection_normalize_type_unnormalizable_setting (type);
+ _test_connection_normalize_type_normalizable_type (type, types[i].add_setting_fcn);
+ }
+}
+
+static void
test_connection_normalize_slave_type_1 (void)
{
gs_unref_object NMConnection *con = NULL;
@@ -2755,6 +3081,7 @@ int main (int argc, char **argv)
test_connection_new_from_hash ();
test_connection_verify_sets_interface_name ();
test_connection_normalize_virtual_iface_name ();
+ test_connection_normalize_type ();
test_connection_normalize_slave_type_1 ();
test_connection_normalize_slave_type_2 ();