diff options
author | Thomas Haller <thaller@redhat.com> | 2014-07-08 18:36:02 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2014-08-22 15:24:31 +0200 |
commit | a9e0796433cd89c7a2280777ac35e659c95b52d8 (patch) | |
tree | 5af7975829267bfedf1b8135e262f4424c95ece1 | |
parent | f60256e035ff650a86e4a8073d91c512d02bcb4d (diff) | |
download | NetworkManager-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.c | 36 | ||||
-rw-r--r-- | libnm-core/nm-setting-connection.c | 63 | ||||
-rw-r--r-- | libnm-core/nm-setting-private.h | 1 | ||||
-rw-r--r-- | libnm-core/nm-setting.c | 23 | ||||
-rw-r--r-- | libnm-core/tests/test-general.c | 327 |
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 (); |