diff options
author | Thomas Haller <thaller@redhat.com> | 2018-07-24 09:44:18 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2018-07-24 09:44:18 +0200 |
commit | a6f51fffa1b8fbc38f93f86735b18c8539faba1d (patch) | |
tree | 27c6e37d2762fb1613a8d461bb89e4f93f431101 | |
parent | 159ff23268b13aedcaffd1a27c279d8476cf6503 (diff) | |
parent | 3000ade72af4373f3a53e2b6d02d54fc3ce33513 (diff) | |
download | NetworkManager-a6f51fffa1b8fbc38f93f86735b18c8539faba1d.tar.gz |
device: merge branch 'th/not-available-reason'
https://github.com/NetworkManager/NetworkManager/pull/163
41 files changed, 1144 insertions, 771 deletions
diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c index 2f8cb4e905..29fdd9790a 100644 --- a/libnm-core/nm-connection.c +++ b/libnm-core/nm-connection.c @@ -225,6 +225,40 @@ nm_connection_get_setting_by_name (NMConnection *connection, const char *name) return type ? _connection_get_setting (connection, type) : NULL; } +/*****************************************************************************/ + +gpointer /* (NMSetting *) */ +_nm_connection_check_main_setting (NMConnection *connection, + const char *setting_name, + GError **error) +{ + NMSetting *setting; + + nm_assert (NM_IS_CONNECTION (connection)); + nm_assert (setting_name); + + if (!nm_connection_is_type (connection, setting_name)) { + nm_utils_error_set (error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, + "connection type is not \"%s\"", + setting_name); + return NULL; + } + + setting = nm_connection_get_setting_by_name (connection, setting_name); + if (!setting) { + nm_utils_error_set (error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, + "connection misses \"%s\" settings", + setting_name); + return NULL; + } + + return setting; +} + +/*****************************************************************************/ + static gboolean validate_permissions_type (GVariant *variant, GError **error) { diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index 3808a9e61b..4945118ffd 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -140,6 +140,10 @@ gboolean _nm_connection_replace_settings (NMConnection *connection, NMSettingParseFlags parse_flags, GError **error); +gpointer _nm_connection_check_main_setting (NMConnection *connection, + const char *setting_name, + GError **error); + /** * NMSettingVerifyResult: * @NM_SETTING_VERIFY_SUCCESS: the setting verifies successfully diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index ffa4da0213..093ebf55a8 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -7006,6 +7006,57 @@ test_get_start_time_for_pid (void) /*****************************************************************************/ +static void +test_nm_va_args_macros (void) +{ +#define GET_NARG_1(...) \ + NM_NARG (__VA_ARGS__) + + g_assert_cmpint ( 0, ==, GET_NARG_1 ()); + g_assert_cmpint ( 1, ==, GET_NARG_1 (x)); + g_assert_cmpint ( 2, ==, GET_NARG_1 ( , )); + g_assert_cmpint ( 2, ==, GET_NARG_1 ( , x)); + g_assert_cmpint ( 2, ==, GET_NARG_1 (x, )); + g_assert_cmpint ( 2, ==, GET_NARG_1 (x, x)); + g_assert_cmpint ( 3, ==, GET_NARG_1 ( , , )); + g_assert_cmpint ( 3, ==, GET_NARG_1 ( , , x)); + g_assert_cmpint ( 3, ==, GET_NARG_1 ( , x, )); + g_assert_cmpint ( 3, ==, GET_NARG_1 ( , x, x)); + g_assert_cmpint ( 3, ==, GET_NARG_1 (x, , )); + g_assert_cmpint ( 3, ==, GET_NARG_1 (x, , x)); + g_assert_cmpint ( 3, ==, GET_NARG_1 (x, x, )); + g_assert_cmpint ( 3, ==, GET_NARG_1 (x, x, x)); + g_assert_cmpint ( 4, ==, GET_NARG_1 ( , , , )); + g_assert_cmpint ( 4, ==, GET_NARG_1 ( , , , x)); + g_assert_cmpint ( 4, ==, GET_NARG_1 ( , , x, )); + g_assert_cmpint ( 4, ==, GET_NARG_1 ( , , x, x)); + g_assert_cmpint ( 4, ==, GET_NARG_1 ( , x, , )); + g_assert_cmpint ( 4, ==, GET_NARG_1 ( , x, , x)); + g_assert_cmpint ( 4, ==, GET_NARG_1 ( , x, x, )); + g_assert_cmpint ( 4, ==, GET_NARG_1 ( , x, x, x)); + g_assert_cmpint ( 4, ==, GET_NARG_1 (x, , , )); + g_assert_cmpint ( 4, ==, GET_NARG_1 (x, , , x)); + g_assert_cmpint ( 4, ==, GET_NARG_1 (x, , x, )); + g_assert_cmpint ( 4, ==, GET_NARG_1 (x, , x, x)); + g_assert_cmpint ( 4, ==, GET_NARG_1 (x, x, , )); + g_assert_cmpint ( 4, ==, GET_NARG_1 (x, x, , x)); + g_assert_cmpint ( 4, ==, GET_NARG_1 (x, x, x, )); + g_assert_cmpint ( 4, ==, GET_NARG_1 (x, x, x, x)); + + g_assert_cmpint ( 5, ==, GET_NARG_1 (x, x, x, x, x)); + g_assert_cmpint ( 6, ==, GET_NARG_1 (x, x, x, x, x, x)); + g_assert_cmpint ( 7, ==, GET_NARG_1 (x, x, x, x, x, x, x)); + g_assert_cmpint ( 8, ==, GET_NARG_1 (x, x, x, x, x, x, x, x)); + g_assert_cmpint ( 9, ==, GET_NARG_1 (x, x, x, x, x, x, x, x, x)); + g_assert_cmpint (10, ==, GET_NARG_1 (x, x, x, x, x, x, x, x, x, x)); + + G_STATIC_ASSERT_EXPR (0 == GET_NARG_1 ()); + G_STATIC_ASSERT_EXPR (1 == GET_NARG_1 (x)); + G_STATIC_ASSERT_EXPR (2 == GET_NARG_1 (x, x)); +} + +/*****************************************************************************/ + NMTST_DEFINE (); int main (int argc, char **argv) @@ -7161,6 +7212,8 @@ int main (int argc, char **argv) g_test_add_func ("/core/general/get_start_time_for_pid", test_get_start_time_for_pid); + g_test_add_func ("/core/general/test_nm_va_args_macros", test_nm_va_args_macros); + return g_test_run (); } diff --git a/shared/nm-utils/nm-macros-internal.h b/shared/nm-utils/nm-macros-internal.h index 6d5e25b28c..2ff95a288e 100644 --- a/shared/nm-utils/nm-macros-internal.h +++ b/shared/nm-utils/nm-macros-internal.h @@ -342,13 +342,16 @@ _nm_auto_freev (gpointer ptr) /*****************************************************************************/ -/* http://stackoverflow.com/a/2124385/354393 */ +/* http://stackoverflow.com/a/2124385/354393 + * https://stackoverflow.com/questions/11317474/macro-to-count-number-of-arguments + */ #define NM_NARG(...) \ - _NM_NARG(__VA_ARGS__,_NM_NARG_RSEQ_N()) + _NM_NARG(, ##__VA_ARGS__, _NM_NARG_RSEQ_N()) #define _NM_NARG(...) \ _NM_NARG_ARG_N(__VA_ARGS__) #define _NM_NARG_ARG_N( \ + _0, \ _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \ _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \ _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \ diff --git a/shared/nm-utils/nm-shared-utils.h b/shared/nm-utils/nm-shared-utils.h index 0bac6e4a53..e9885c6e35 100644 --- a/shared/nm-utils/nm-shared-utils.h +++ b/shared/nm-utils/nm-shared-utils.h @@ -386,12 +386,40 @@ _nm_g_slice_free_fcn_define (16) * error reason. Depending on the usage, this might indicate a bug because * usually the target object should stay alive as long as there are pending * operations. + * + * @NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE: used for a very particular + * purpose during nm_device_check_connection_compatible() to indicate that + * the profile does not match the device already because their type differs. + * That is, there is a fundamental reason of trying to check a profile that + * cannot possibly match on this device. + * @NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE: used for a very particular + * purpose during nm_device_check_connection_available(), to indicate that the + * device is not available because it is unmanaged. + * @NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY: the profile is currently not + * available/compatible with the device, but this may be only temporary. + * * @NM_UTILS_ERROR_INVALID_ARGUMENT: invalid argument. */ typedef enum { NM_UTILS_ERROR_UNKNOWN = 0, /*< nick=Unknown >*/ NM_UTILS_ERROR_CANCELLED_DISPOSING, /*< nick=CancelledDisposing >*/ NM_UTILS_ERROR_INVALID_ARGUMENT, /*< nick=InvalidArgument >*/ + + /* the following codes have a special meaning and are exactly used for + * nm_device_check_connection_compatible() and nm_device_check_connection_available(). + * + * Actually, their meaning is not very important (so, don't think too + * hard about the name of these error codes). What is important, is their + * relative order (i.e. the integer value of the codes). When manager + * searches for a suitable device, it will check all devices whether + * a profile can be activated. If they all fail, it will pick the error + * message from the device that returned the *highest* error code, + * in the hope that this message makes the most sense for the caller. + * */ + NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + } NMUtilsError; #define NM_UTILS_ERROR (nm_utils_error_quark ()) @@ -403,6 +431,15 @@ void nm_utils_error_set_cancelled (GError **error, gboolean nm_utils_error_is_cancelled (GError *error, gboolean consider_is_disposing); +static inline void +nm_utils_error_set_literal (GError **error, int error_code, const char *literal) +{ + g_set_error_literal (error, NM_UTILS_ERROR, error_code, literal); +} + +#define nm_utils_error_set(error, error_code, ...) \ + g_set_error ((error), NM_UTILS_ERROR, error_code, __VA_ARGS__) + /*****************************************************************************/ gboolean nm_g_object_set_property (GObject *object, diff --git a/src/devices/adsl/nm-device-adsl.c b/src/devices/adsl/nm-device-adsl.c index 1450a8369d..c9984f5135 100644 --- a/src/devices/adsl/nm-device-adsl.c +++ b/src/devices/adsl/nm-device-adsl.c @@ -87,25 +87,23 @@ get_generic_capabilities (NMDevice *dev) } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { NMSettingAdsl *s_adsl; const char *protocol; - if (!NM_DEVICE_CLASS (nm_device_adsl_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - if (!nm_connection_is_type (connection, NM_SETTING_ADSL_SETTING_NAME)) + if (!NM_DEVICE_CLASS (nm_device_adsl_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; s_adsl = nm_connection_get_setting_adsl (connection); - if (!s_adsl) - return FALSE; - /* FIXME: we don't yet support IPoATM */ protocol = nm_setting_adsl_get_protocol (s_adsl); - if (g_strcmp0 (protocol, NM_SETTING_ADSL_PROTOCOL_IPOATM) == 0) + if (nm_streq0 (protocol, NM_SETTING_ADSL_PROTOCOL_IPOATM)) { + /* FIXME: we don't yet support IPoATM */ + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "IPoATM protocol is not yet supported"); return FALSE; + } return TRUE; } @@ -669,7 +667,7 @@ nm_device_adsl_class_init (NMDeviceAdslClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); object_class->constructed = constructed; object_class->dispose = dispose; @@ -678,14 +676,16 @@ nm_device_adsl_class_init (NMDeviceAdslClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_adsl); - parent_class->get_generic_capabilities = get_generic_capabilities; + device_class->connection_type_check_compatible = NM_SETTING_ADSL_SETTING_NAME; + + device_class->get_generic_capabilities = get_generic_capabilities; - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->complete_connection = complete_connection; + device_class->check_connection_compatible = check_connection_compatible; + device_class->complete_connection = complete_connection; - parent_class->act_stage2_config = act_stage2_config; - parent_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; - parent_class->deactivate = deactivate; + device_class->act_stage2_config = act_stage2_config; + device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; + device_class->deactivate = deactivate; obj_properties[PROP_ATM_INDEX] = g_param_spec_int (NM_DEVICE_ADSL_ATM_INDEX, "", "", diff --git a/src/devices/bluetooth/nm-device-bt.c b/src/devices/bluetooth/nm-device-bt.c index 92ad0b31cc..a11c798698 100644 --- a/src/devices/bluetooth/nm-device-bt.c +++ b/src/devices/bluetooth/nm-device-bt.c @@ -157,36 +157,36 @@ can_auto_connect (NMDevice *device, } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE ((NMDeviceBt *) device); - NMSettingConnection *s_con; NMSettingBluetooth *s_bt; const char *bdaddr; guint32 bt_type; - if (!NM_DEVICE_CLASS (nm_device_bt_parent_class)->check_connection_compatible (device, connection)) + if (!NM_DEVICE_CLASS (nm_device_bt_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; - s_con = nm_connection_get_setting_connection (connection); - g_assert (s_con); - - if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_BLUETOOTH_SETTING_NAME)) + bt_type = get_connection_bt_type (connection); + if (!NM_FLAGS_ALL (priv->capabilities, bt_type)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device does not support bluetooth type of profile"); return FALSE; + } s_bt = nm_connection_get_setting_bluetooth (connection); - if (!s_bt) - return FALSE; - - bt_type = get_connection_bt_type (connection); - if (!(bt_type & priv->capabilities)) - return FALSE; bdaddr = nm_setting_bluetooth_get_bdaddr (s_bt); - if (!bdaddr) + if (!bdaddr) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "profile lacks bdaddr setting"); return FALSE; - if (!nm_utils_hwaddr_matches (priv->bdaddr, -1, bdaddr, -1)) + } + if (!nm_utils_hwaddr_matches (priv->bdaddr, -1, bdaddr, -1)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "devices bdaddr setting mismatches"); return FALSE; + } return TRUE; } @@ -195,18 +195,25 @@ static gboolean check_connection_available (NMDevice *device, NMConnection *connection, NMDeviceCheckConAvailableFlags flags, - const char *specific_object) + const char *specific_object, + GError **error) { NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE ((NMDeviceBt *) device); guint32 bt_type; bt_type = get_connection_bt_type (connection); - if (!(bt_type & priv->capabilities)) + if (!(bt_type & priv->capabilities)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device does not support bluetooth type"); return FALSE; + } /* DUN connections aren't available without ModemManager */ - if (bt_type == NM_BT_CAPABILITY_DUN && priv->mm_running == FALSE) + if (bt_type == NM_BT_CAPABILITY_DUN && priv->mm_running == FALSE) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "ModemManager missing for DUN profile"); return FALSE; + } return TRUE; } @@ -1177,6 +1184,8 @@ nm_device_bt_class_init (NMDeviceBtClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_bluetooth); + device_class->connection_type_check_compatible = NM_SETTING_BLUETOOTH_SETTING_NAME; + device_class->get_generic_capabilities = get_generic_capabilities; device_class->can_auto_connect = can_auto_connect; device_class->deactivate = deactivate; diff --git a/src/devices/nm-device-6lowpan.c b/src/devices/nm-device-6lowpan.c index 9119ab00c3..52dda3bf74 100644 --- a/src/devices/nm-device-6lowpan.c +++ b/src/devices/nm-device-6lowpan.c @@ -175,21 +175,6 @@ is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) -{ - NMSetting6Lowpan *s_6lowpan; - - if (!NM_DEVICE_CLASS (nm_device_6lowpan_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - s_6lowpan = nm_connection_get_setting_6lowpan (connection); - if (!s_6lowpan) - return FALSE; - - return TRUE; -} - -static gboolean complete_connection (NMDevice *device, NMConnection *connection, const char *specific_object, @@ -218,7 +203,7 @@ complete_connection (NMDevice *device, * settings, then there's not enough information to complete the setting. */ if ( !nm_setting_6lowpan_get_parent (s_6lowpan) - && !nm_device_match_hwaddr (device, connection, TRUE)) { + && !nm_device_match_parent_hwaddr (device, connection, TRUE)) { g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, "The '6lowpan' setting had no interface name, parent, or hardware address."); return FALSE; @@ -249,7 +234,8 @@ update_connection (NMDevice *device, NMConnection *connection) /* Don't change a parent specified by UUID if it's still valid */ parent_connection = (NMConnection *) nm_settings_get_connection_by_uuid (nm_device_get_settings (device), setting_parent); - if (parent_connection && nm_device_check_connection_compatible (parent_device, parent_connection)) + if ( parent_connection + && nm_device_check_connection_compatible (parent_device, parent_connection, NULL)) new_parent = NULL; } if (new_parent) @@ -296,14 +282,14 @@ nm_device_6lowpan_class_init (NMDevice6LowpanClass *klass) NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_6LOWPAN) - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_6lowpan); + device_class->connection_type_supported = NM_SETTING_6LOWPAN_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_6LOWPAN_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_6LOWPAN); + device_class->act_stage1_prepare = act_stage1_prepare; - device_class->check_connection_compatible = check_connection_compatible; device_class->complete_connection = complete_connection; - device_class->connection_type = NM_SETTING_6LOWPAN_SETTING_NAME; device_class->create_and_realize = create_and_realize; device_class->get_generic_capabilities = get_generic_capabilities; device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c index ff7ecdbe23..6e7e6ffcd1 100644 --- a/src/devices/nm-device-bond.c +++ b/src/devices/nm-device-bond.c @@ -56,23 +56,6 @@ get_generic_capabilities (NMDevice *dev) } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) -{ - NMSettingBond *s_bond; - - if (!NM_DEVICE_CLASS (nm_device_bond_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - s_bond = nm_connection_get_setting_bond (connection); - if (!s_bond || !nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME)) - return FALSE; - - /* FIXME: match bond properties like mode, etc? */ - - return TRUE; -} - -static gboolean complete_connection (NMDevice *device, NMConnection *connection, const char *specific_object, @@ -631,27 +614,28 @@ static void nm_device_bond_class_init (NMDeviceBondClass *klass) { NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_BOND_SETTING_NAME, NM_LINK_TYPE_BOND) + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_bond); - parent_class->is_master = TRUE; - parent_class->get_generic_capabilities = get_generic_capabilities; - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->complete_connection = complete_connection; - - parent_class->update_connection = update_connection; - parent_class->master_update_slave_connection = master_update_slave_connection; - - parent_class->create_and_realize = create_and_realize; - parent_class->act_stage1_prepare = act_stage1_prepare; - parent_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; - parent_class->enslave_slave = enslave_slave; - parent_class->release_slave = release_slave; - parent_class->can_reapply_change = can_reapply_change; - parent_class->reapply_connection = reapply_connection; + device_class->connection_type_supported = NM_SETTING_BOND_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_BOND_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_BOND); + + device_class->is_master = TRUE; + device_class->get_generic_capabilities = get_generic_capabilities; + device_class->complete_connection = complete_connection; + + device_class->update_connection = update_connection; + device_class->master_update_slave_connection = master_update_slave_connection; + + device_class->create_and_realize = create_and_realize; + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; + device_class->enslave_slave = enslave_slave; + device_class->release_slave = release_slave; + device_class->can_reapply_change = can_reapply_change; + device_class->reapply_connection = reapply_connection; } /*****************************************************************************/ diff --git a/src/devices/nm-device-bridge.c b/src/devices/nm-device-bridge.c index c81a025338..e79de95cd4 100644 --- a/src/devices/nm-device-bridge.c +++ b/src/devices/nm-device-bridge.c @@ -61,41 +61,63 @@ static gboolean check_connection_available (NMDevice *device, NMConnection *connection, NMDeviceCheckConAvailableFlags flags, - const char *specific_object) + const char *specific_object, + GError **error) { NMSettingBluetooth *s_bt; - if (!NM_DEVICE_CLASS (nm_device_bridge_parent_class)->check_connection_available (device, connection, flags, specific_object)) + if (!NM_DEVICE_CLASS (nm_device_bridge_parent_class)->check_connection_available (device, connection, flags, specific_object, error)) return FALSE; s_bt = _nm_connection_get_setting_bluetooth_for_nap (connection); if (s_bt) { - return nm_bt_vtable_network_server - && nm_bt_vtable_network_server->is_available (nm_bt_vtable_network_server, - nm_setting_bluetooth_get_bdaddr (s_bt)); + const char *bdaddr; + + if (!nm_bt_vtable_network_server) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "bluetooth plugin not available to activate NAP profile"); + return FALSE; + } + + bdaddr = nm_setting_bluetooth_get_bdaddr (s_bt); + if (!nm_bt_vtable_network_server->is_available (nm_bt_vtable_network_server, bdaddr)) { + if (bdaddr) + nm_utils_error_set (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "not suitable NAP device \"%s\" available", bdaddr); + else + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "not suitable NAP device available"); + return FALSE; + } } return TRUE; } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { NMSettingBridge *s_bridge; const char *mac_address; - if (!NM_DEVICE_CLASS (nm_device_bridge_parent_class)->check_connection_compatible (device, connection)) + if (!NM_DEVICE_CLASS (nm_device_bridge_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; - s_bridge = nm_connection_get_setting_bridge (connection); - if (!s_bridge) - return FALSE; + if ( nm_connection_is_type (connection, NM_SETTING_BLUETOOTH_SETTING_NAME) + && _nm_connection_get_setting_bluetooth_for_nap (connection)) { + s_bridge = nm_connection_get_setting_bridge (connection); + if (!s_bridge) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "missing bridge setting for bluetooth NAP profile"); + return FALSE; + } - if (!nm_connection_is_type (connection, NM_SETTING_BRIDGE_SETTING_NAME)) { - if ( nm_connection_is_type (connection, NM_SETTING_BLUETOOTH_SETTING_NAME) - && _nm_connection_get_setting_bluetooth_for_nap (connection)) { - /* a bluetooth NAP connection is handled by the bridge */ - } else + /* a bluetooth NAP connection is handled by the bridge. + * + * Proceed... */ + } else { + s_bridge = _nm_connection_check_main_setting (connection, NM_SETTING_BRIDGE_SETTING_NAME, error); + if (!s_bridge) return FALSE; } @@ -104,8 +126,11 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) const char *hw_addr; hw_addr = nm_device_get_hw_address (device); - if (!hw_addr || !nm_utils_hwaddr_matches (hw_addr, -1, mac_address, -1)) + if (!hw_addr || !nm_utils_hwaddr_matches (hw_addr, -1, mac_address, -1)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "mac address mismatches"); return FALSE; + } } return TRUE; @@ -505,28 +530,29 @@ static void nm_device_bridge_class_init (NMDeviceBridgeClass *klass) { NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_BRIDGE_SETTING_NAME, NM_LINK_TYPE_BRIDGE) + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_bridge); - parent_class->is_master = TRUE; - parent_class->get_generic_capabilities = get_generic_capabilities; - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->check_connection_available = check_connection_available; - parent_class->complete_connection = complete_connection; - - parent_class->update_connection = update_connection; - parent_class->master_update_slave_connection = master_update_slave_connection; - - parent_class->create_and_realize = create_and_realize; - parent_class->act_stage1_prepare = act_stage1_prepare; - parent_class->act_stage2_config = act_stage2_config; - parent_class->deactivate = deactivate; - parent_class->enslave_slave = enslave_slave; - parent_class->release_slave = release_slave; - parent_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; + device_class->connection_type_supported = NM_SETTING_BRIDGE_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_BRIDGE); + + device_class->is_master = TRUE; + device_class->get_generic_capabilities = get_generic_capabilities; + device_class->check_connection_compatible = check_connection_compatible; + device_class->check_connection_available = check_connection_available; + device_class->complete_connection = complete_connection; + + device_class->update_connection = update_connection; + device_class->master_update_slave_connection = master_update_slave_connection; + + device_class->create_and_realize = create_and_realize; + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->act_stage2_config = act_stage2_config; + device_class->deactivate = deactivate; + device_class->enslave_slave = enslave_slave; + device_class->release_slave = release_slave; + device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; } /*****************************************************************************/ diff --git a/src/devices/nm-device-dummy.c b/src/devices/nm-device-dummy.c index 9be4d29f20..a905938369 100644 --- a/src/devices/nm-device-dummy.c +++ b/src/devices/nm-device-dummy.c @@ -117,21 +117,6 @@ create_and_realize (NMDevice *device, return TRUE; } -static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) -{ - NMSettingDummy *s_dummy; - - if (!NM_DEVICE_CLASS (nm_device_dummy_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - s_dummy = nm_connection_get_setting_dummy (connection); - if (!s_dummy) - return FALSE; - - return TRUE; -} - static NMActStageReturn act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) { @@ -173,13 +158,13 @@ nm_device_dummy_class_init (NMDeviceDummyClass *klass) NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_DUMMY) - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_dummy); - device_class->connection_type = NM_SETTING_DUMMY_SETTING_NAME; + device_class->connection_type_supported = NM_SETTING_DUMMY_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_DUMMY_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_DUMMY); + device_class->complete_connection = complete_connection; - device_class->check_connection_compatible = check_connection_compatible; device_class->create_and_realize = create_and_realize; device_class->get_generic_capabilities = get_generic_capabilities; device_class->update_connection = update_connection; diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index a9a9f968e6..0d9038983c 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -343,23 +343,21 @@ match_subchans (NMDeviceEthernet *self, NMSettingWired *s_wired, gboolean *try_m } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device); NMSettingWired *s_wired; - if (!NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->check_connection_compatible (device, connection)) + if (!NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; - s_wired = nm_connection_get_setting_wired (connection); - if (nm_connection_is_type (connection, NM_SETTING_PPPOE_SETTING_NAME)) { - /* NOP */ - } else if (nm_connection_is_type (connection, NM_SETTING_WIRED_SETTING_NAME)) { + s_wired = nm_connection_get_setting_wired (connection); + } else { + s_wired = _nm_connection_check_main_setting (connection, NM_SETTING_WIRED_SETTING_NAME, error); if (!s_wired) return FALSE; - } else - return FALSE; + } if (s_wired) { const char *mac, *perm_hw_addr; @@ -367,28 +365,43 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) const char * const *mac_blacklist; int i; - if (!match_subchans (self, s_wired, &try_mac)) + if (!match_subchans (self, s_wired, &try_mac)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "s390 subchannels don't match"); return FALSE; + } perm_hw_addr = nm_device_get_permanent_hw_address (device); mac = nm_setting_wired_get_mac_address (s_wired); if (perm_hw_addr) { - if (try_mac && mac && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1)) + if ( try_mac + && mac + && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "permanent MAC address doesn't match"); return FALSE; + } /* Check for MAC address blacklist */ mac_blacklist = nm_setting_wired_get_mac_address_blacklist (s_wired); for (i = 0; mac_blacklist[i]; i++) { if (!nm_utils_hwaddr_valid (mac_blacklist[i], ETH_ALEN)) { - g_warn_if_reached (); + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "invalid MAC in blacklist"); return FALSE; } - if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, perm_hw_addr, -1)) + if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, perm_hw_addr, -1)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "permanent MAC address of device blacklisted"); return FALSE; + } } - } else if (mac) + } else if (mac) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device has no permanent MAC address to match"); return FALSE; + } } return TRUE; @@ -1750,12 +1763,10 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); g_type_class_add_private (object_class, sizeof (NMDeviceEthernetPrivate)); - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_WIRED_SETTING_NAME, NM_LINK_TYPE_ETHERNET) - object_class->dispose = dispose; object_class->finalize = finalize; object_class->get_property = get_property; @@ -1763,25 +1774,28 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_wired); - parent_class->get_generic_capabilities = get_generic_capabilities; - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->complete_connection = complete_connection; - parent_class->new_default_connection = new_default_connection; - - parent_class->act_stage1_prepare = act_stage1_prepare; - parent_class->act_stage2_config = act_stage2_config; - parent_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; - parent_class->get_configured_mtu = get_configured_mtu; - parent_class->deactivate = deactivate; - parent_class->get_s390_subchannels = get_s390_subchannels; - parent_class->update_connection = update_connection; - parent_class->carrier_changed_notify = carrier_changed_notify; - parent_class->link_changed = link_changed; - parent_class->is_available = is_available; - parent_class->can_reapply_change = can_reapply_change; - parent_class->reapply_connection = reapply_connection; - - parent_class->state_changed = device_state_changed; + device_class->connection_type_supported = NM_SETTING_WIRED_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_ETHERNET); + + device_class->get_generic_capabilities = get_generic_capabilities; + device_class->check_connection_compatible = check_connection_compatible; + device_class->complete_connection = complete_connection; + device_class->new_default_connection = new_default_connection; + + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->act_stage2_config = act_stage2_config; + device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; + device_class->get_configured_mtu = get_configured_mtu; + device_class->deactivate = deactivate; + device_class->get_s390_subchannels = get_s390_subchannels; + device_class->update_connection = update_connection; + device_class->carrier_changed_notify = carrier_changed_notify; + device_class->link_changed = link_changed; + device_class->is_available = is_available; + device_class->can_reapply_change = can_reapply_change; + device_class->reapply_connection = reapply_connection; + + device_class->state_changed = device_state_changed; obj_properties[PROP_SPEED] = g_param_spec_uint (NM_DEVICE_ETHERNET_SPEED, "", "", diff --git a/src/devices/nm-device-generic.c b/src/devices/nm-device-generic.c index 27eaf8d6ce..d00aa93bb5 100644 --- a/src/devices/nm-device-generic.c +++ b/src/devices/nm-device-generic.c @@ -86,19 +86,19 @@ realize_start_notify (NMDevice *device, const NMPlatformLink *plink) } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { NMSettingConnection *s_con; - if (!NM_DEVICE_CLASS (nm_device_generic_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - if (!nm_connection_is_type (connection, NM_SETTING_GENERIC_SETTING_NAME)) + if (!NM_DEVICE_CLASS (nm_device_generic_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; s_con = nm_connection_get_setting_connection (connection); - if (!nm_setting_connection_get_interface_name (s_con)) + if (!nm_setting_connection_get_interface_name (s_con)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "generic profiles need an interface name"); return FALSE; + } return TRUE; } @@ -220,9 +220,7 @@ nm_device_generic_class_init (NMDeviceGenericClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_GENERIC_SETTING_NAME, NM_LINK_TYPE_ANY) + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); object_class->constructor = constructor; object_class->dispose = dispose; @@ -231,11 +229,15 @@ nm_device_generic_class_init (NMDeviceGenericClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_generic); - parent_class->realize_start_notify = realize_start_notify; - parent_class->get_generic_capabilities = get_generic_capabilities; - parent_class->get_type_description = get_type_description; - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->update_connection = update_connection; + device_class->connection_type_supported = NM_SETTING_GENERIC_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_GENERIC_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_ANY); + + device_class->realize_start_notify = realize_start_notify; + device_class->get_generic_capabilities = get_generic_capabilities; + device_class->get_type_description = get_type_description; + device_class->check_connection_compatible = check_connection_compatible; + device_class->update_connection = update_connection; obj_properties[PROP_TYPE_DESCRIPTION] = g_param_spec_string (NM_DEVICE_GENERIC_TYPE_DESCRIPTION, "", "", diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c index 122ae25953..41fac157dd 100644 --- a/src/devices/nm-device-infiniband.c +++ b/src/devices/nm-device-infiniband.c @@ -123,30 +123,28 @@ get_configured_mtu (NMDevice *device, NMDeviceMtuSource *out_source) } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { NMSettingInfiniband *s_infiniband; - if (!NM_DEVICE_CLASS (nm_device_infiniband_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - if (!nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME)) - return FALSE; - - s_infiniband = nm_connection_get_setting_infiniband (connection); - if (!s_infiniband) + if (!NM_DEVICE_CLASS (nm_device_infiniband_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; if (nm_device_is_real (device)) { const char *mac; const char *hw_addr; + s_infiniband = nm_connection_get_setting_infiniband (connection); + mac = nm_setting_infiniband_get_mac_address (s_infiniband); if (mac) { hw_addr = nm_device_get_permanent_hw_address (device); if ( !hw_addr - || !nm_utils_hwaddr_matches (mac, -1, hw_addr, -1)) + || !nm_utils_hwaddr_matches (mac, -1, hw_addr, -1)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "MAC address mismatches"); return FALSE; + } } } @@ -367,24 +365,26 @@ nm_device_infiniband_class_init (NMDeviceInfinibandClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_INFINIBAND_SETTING_NAME, NM_LINK_TYPE_INFINIBAND) + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); object_class->get_property = get_property; object_class->set_property = set_property; dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_infiniband); - parent_class->create_and_realize = create_and_realize; - parent_class->unrealize = unrealize; - parent_class->get_generic_capabilities = get_generic_capabilities; - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->complete_connection = complete_connection; - parent_class->update_connection = update_connection; + device_class->connection_type_supported = NM_SETTING_INFINIBAND_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_INFINIBAND_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_INFINIBAND); + + device_class->create_and_realize = create_and_realize; + device_class->unrealize = unrealize; + device_class->get_generic_capabilities = get_generic_capabilities; + device_class->check_connection_compatible = check_connection_compatible; + device_class->complete_connection = complete_connection; + device_class->update_connection = update_connection; - parent_class->act_stage1_prepare = act_stage1_prepare; - parent_class->get_configured_mtu = get_configured_mtu; + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->get_configured_mtu = get_configured_mtu; obj_properties[PROP_IS_PARTITION] = g_param_spec_boolean (NM_DEVICE_INFINIBAND_IS_PARTITION, "", "", diff --git a/src/devices/nm-device-ip-tunnel.c b/src/devices/nm-device-ip-tunnel.c index 35c9b0b6f6..642bb25447 100644 --- a/src/devices/nm-device-ip-tunnel.c +++ b/src/devices/nm-device-ip-tunnel.c @@ -458,7 +458,7 @@ update_connection (NMDevice *device, NMConnection *connection) /* Don't change a parent specified by UUID if it's still valid */ parent_connection = (NMConnection *) nm_settings_get_connection_by_uuid (nm_device_get_settings (device), setting_parent); - if (parent_connection && nm_device_check_connection_compatible (parent, parent_connection)) + if (parent_connection && nm_device_check_connection_compatible (parent, parent_connection, NULL)) new_parent = NULL; } if (new_parent) @@ -524,54 +524,79 @@ update_connection (NMDevice *device, NMConnection *connection) } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { NMDeviceIPTunnel *self = NM_DEVICE_IP_TUNNEL (device); NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (self); NMSettingIPTunnel *s_ip_tunnel; const char *parent; - if (!NM_DEVICE_CLASS (nm_device_ip_tunnel_parent_class)->check_connection_compatible (device, connection)) + if (!NM_DEVICE_CLASS (nm_device_ip_tunnel_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; s_ip_tunnel = nm_connection_get_setting_ip_tunnel (connection); - if (!s_ip_tunnel) - return FALSE; - if (nm_setting_ip_tunnel_get_mode (s_ip_tunnel) != priv->mode) + if (nm_setting_ip_tunnel_get_mode (s_ip_tunnel) != priv->mode) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "incompatible IP tunnel mode"); return FALSE; + } if (nm_device_is_real (device)) { /* Check parent interface; could be an interface name or a UUID */ parent = nm_setting_ip_tunnel_get_parent (s_ip_tunnel); - if (parent && !nm_device_match_parent (device, parent)) + if (parent && !nm_device_match_parent (device, parent)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "IP tunnel parent mismatches"); return FALSE; + } if (!address_equal_pp (priv->addr_family, nm_setting_ip_tunnel_get_local (s_ip_tunnel), - priv->local)) + priv->local)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "local IP tunnel address mismatches"); return FALSE; + } if (!address_equal_pp (priv->addr_family, nm_setting_ip_tunnel_get_remote (s_ip_tunnel), - priv->remote)) + priv->remote)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "remote IP tunnel address mismatches"); return FALSE; + } - if (nm_setting_ip_tunnel_get_ttl (s_ip_tunnel) != priv->ttl) + if (nm_setting_ip_tunnel_get_ttl (s_ip_tunnel) != priv->ttl) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "TTL of IP tunnel mismatches"); return FALSE; + } - if (nm_setting_ip_tunnel_get_tos (s_ip_tunnel) != priv->tos) + if (nm_setting_ip_tunnel_get_tos (s_ip_tunnel) != priv->tos) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "TOS of IP tunnel mismatches"); return FALSE; + } if (priv->addr_family == AF_INET) { - if (nm_setting_ip_tunnel_get_path_mtu_discovery (s_ip_tunnel) != priv->path_mtu_discovery) + if (nm_setting_ip_tunnel_get_path_mtu_discovery (s_ip_tunnel) != priv->path_mtu_discovery) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "MTU discovery setting of IP tunnel mismatches"); return FALSE; + } } else { - if (nm_setting_ip_tunnel_get_encapsulation_limit (s_ip_tunnel) != priv->encap_limit) + if (nm_setting_ip_tunnel_get_encapsulation_limit (s_ip_tunnel) != priv->encap_limit) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "encapsulation limit of IP tunnel mismatches"); return FALSE; + } - if (nm_setting_ip_tunnel_get_flow_label (s_ip_tunnel) != priv->flow_label) + if (nm_setting_ip_tunnel_get_flow_label (s_ip_tunnel) != priv->flow_label) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "flow-label of IP tunnel mismatches"); return FALSE; + } } } @@ -1043,6 +1068,16 @@ nm_device_ip_tunnel_class_init (NMDeviceIPTunnelClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_ip_tunnel); + device_class->connection_type_supported = NM_SETTING_IP_TUNNEL_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_IP_TUNNEL_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_GRE, + NM_LINK_TYPE_GRETAP, + NM_LINK_TYPE_IP6TNL, + NM_LINK_TYPE_IP6GRE, + NM_LINK_TYPE_IP6GRETAP, + NM_LINK_TYPE_IPIP, + NM_LINK_TYPE_SIT); + device_class->act_stage1_prepare = act_stage1_prepare; device_class->link_changed = link_changed; device_class->can_reapply_change = can_reapply_change; @@ -1054,16 +1089,6 @@ nm_device_ip_tunnel_class_init (NMDeviceIPTunnelClass *klass) device_class->get_configured_mtu = get_configured_mtu; device_class->unrealize_notify = unrealize_notify; - NM_DEVICE_CLASS_DECLARE_TYPES (klass, - NM_SETTING_IP_TUNNEL_SETTING_NAME, - NM_LINK_TYPE_GRE, - NM_LINK_TYPE_GRETAP, - NM_LINK_TYPE_IP6TNL, - NM_LINK_TYPE_IP6GRE, - NM_LINK_TYPE_IP6GRETAP, - NM_LINK_TYPE_IPIP, - NM_LINK_TYPE_SIT); - obj_properties[PROP_MODE] = g_param_spec_uint (NM_DEVICE_IP_TUNNEL_MODE, "", "", 0, G_MAXUINT, 0, diff --git a/src/devices/nm-device-macsec.c b/src/devices/nm-device-macsec.c index 166bfb57a4..8ea4c8b562 100644 --- a/src/devices/nm-device-macsec.c +++ b/src/devices/nm-device-macsec.c @@ -627,21 +627,6 @@ deactivate (NMDevice *device) supplicant_interface_release (self); } -static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) -{ - NMSettingMacsec *s_macsec; - - if (!NM_DEVICE_CLASS (nm_device_macsec_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - s_macsec = nm_connection_get_setting_macsec (connection); - if (!s_macsec) - return FALSE; - - return TRUE; -} - /******************************************************************/ static NMDeviceCapabilities @@ -841,27 +826,26 @@ nm_device_macsec_class_init (NMDeviceMacsecClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_MACSEC) + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); object_class->get_property = get_property; object_class->dispose = dispose; dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_macsec); - parent_class->act_stage2_config = act_stage2_config; - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->create_and_realize = create_and_realize; - parent_class->deactivate = deactivate; - parent_class->get_generic_capabilities = get_generic_capabilities; - parent_class->link_changed = link_changed; - parent_class->is_available = is_available; - parent_class->parent_changed_notify = parent_changed_notify; - parent_class->state_changed = device_state_changed; - parent_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; - - parent_class->connection_type = NM_SETTING_MACSEC_SETTING_NAME; + device_class->connection_type_supported = NM_SETTING_MACSEC_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_MACSEC_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_MACSEC); + + device_class->act_stage2_config = act_stage2_config; + device_class->create_and_realize = create_and_realize; + device_class->deactivate = deactivate; + device_class->get_generic_capabilities = get_generic_capabilities; + device_class->link_changed = link_changed; + device_class->is_available = is_available; + device_class->parent_changed_notify = parent_changed_notify; + device_class->state_changed = device_state_changed; + device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; obj_properties[PROP_SCI] = g_param_spec_uint64 (NM_DEVICE_MACSEC_SCI, "", "", diff --git a/src/devices/nm-device-macvlan.c b/src/devices/nm-device-macvlan.c index dc4fb3e835..fa9a7b0d69 100644 --- a/src/devices/nm-device-macvlan.c +++ b/src/devices/nm-device-macvlan.c @@ -290,40 +290,58 @@ is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) /*****************************************************************************/ static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE ((NMDeviceMacvlan *) device); NMSettingMacvlan *s_macvlan; const char *parent = NULL; - if (!NM_DEVICE_CLASS (nm_device_macvlan_parent_class)->check_connection_compatible (device, connection)) + if (!NM_DEVICE_CLASS (nm_device_macvlan_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; s_macvlan = nm_connection_get_setting_macvlan (connection); - if (!s_macvlan) - return FALSE; - if (nm_setting_macvlan_get_tap (s_macvlan) != priv->props.tap) + if (nm_setting_macvlan_get_tap (s_macvlan) != priv->props.tap) { + if (priv->props.tap) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "macvtap device does not match macvlan profile"); + } else { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "macvlan device does not match macvtap profile"); + } return FALSE; + } /* Before the device is realized some properties will not be set */ if (nm_device_is_real (device)) { - if (setting_mode_to_platform (nm_setting_macvlan_get_mode (s_macvlan)) != priv->props.mode) + if (setting_mode_to_platform (nm_setting_macvlan_get_mode (s_macvlan)) != priv->props.mode) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "macvlan mode setting differs"); return FALSE; + } - if (nm_setting_macvlan_get_promiscuous (s_macvlan) == priv->props.no_promisc) + if (nm_setting_macvlan_get_promiscuous (s_macvlan) == priv->props.no_promisc) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "macvlan promiscuous setting differs"); return FALSE; + } /* Check parent interface; could be an interface name or a UUID */ parent = nm_setting_macvlan_get_parent (s_macvlan); if (parent) { - if (!nm_device_match_parent (device, parent)) + if (!nm_device_match_parent (device, parent)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "macvlan parent setting differs"); return FALSE; + } } else { /* Parent could be a MAC address in an NMSettingWired */ - if (!nm_device_match_hwaddr (device, connection, TRUE)) + if (!nm_device_match_parent_hwaddr (device, connection, TRUE)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "macvlan parent mac setting differs"); return FALSE; + } } } @@ -359,7 +377,7 @@ complete_connection (NMDevice *device, * settings, then there's not enough information to complete the setting. */ if ( !nm_setting_macvlan_get_parent (s_macvlan) - && !nm_device_match_hwaddr (device, connection, TRUE)) { + && !nm_device_match_parent_hwaddr (device, connection, TRUE)) { g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, "The 'macvlan' setting had no interface name, parent, or hardware address."); return FALSE; @@ -402,7 +420,7 @@ update_connection (NMDevice *device, NMConnection *connection) /* Don't change a parent specified by UUID if it's still valid */ parent_connection = (NMConnection *) nm_settings_get_connection_by_uuid (nm_device_get_settings (device), setting_parent); - if (parent_connection && nm_device_check_connection_compatible (parent_device, parent_connection)) + if (parent_connection && nm_device_check_connection_compatible (parent_device, parent_connection, NULL)) new_parent = NULL; } if (new_parent) @@ -495,17 +513,18 @@ nm_device_macvlan_class_init (NMDeviceMacvlanClass *klass) NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_MACVLAN, NM_LINK_TYPE_MACVTAP) - object_class->get_property = get_property; object_class->set_property = set_property; dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_macvlan); + device_class->connection_type_supported = NM_SETTING_MACVLAN_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_MACVLAN_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_MACVLAN, NM_LINK_TYPE_MACVTAP); + device_class->act_stage1_prepare = act_stage1_prepare; device_class->check_connection_compatible = check_connection_compatible; device_class->complete_connection = complete_connection; - device_class->connection_type = NM_SETTING_MACVLAN_SETTING_NAME; device_class->create_and_realize = create_and_realize; device_class->get_generic_capabilities = get_generic_capabilities; device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; diff --git a/src/devices/nm-device-ppp.c b/src/devices/nm-device-ppp.c index a6abb228a6..74b4d710ca 100644 --- a/src/devices/nm-device-ppp.c +++ b/src/devices/nm-device-ppp.c @@ -49,24 +49,6 @@ G_DEFINE_TYPE (NMDevicePpp, nm_device_ppp, NM_TYPE_DEVICE) #define NM_DEVICE_PPP_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDevicePpp, NM_IS_DEVICE_PPP) -static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) -{ - NMSettingPppoe *s_pppoe; - - if (!NM_DEVICE_CLASS (nm_device_ppp_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - if (!nm_streq0 (nm_connection_get_connection_type (connection), - NM_SETTING_PPPOE_SETTING_NAME)) - return FALSE; - - s_pppoe = nm_connection_get_setting_pppoe (connection); - nm_assert (s_pppoe); - - return !!nm_setting_pppoe_get_parent (s_pppoe); -} - static NMDeviceCapabilities get_generic_capabilities (NMDevice *device) { @@ -275,20 +257,21 @@ nm_device_ppp_class_init (NMDevicePppClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_PPPOE_SETTING_NAME, NM_LINK_TYPE_PPP) + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); object_class->dispose = dispose; dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_ppp); - parent_class->act_stage2_config = act_stage2_config; - parent_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->create_and_realize = create_and_realize; - parent_class->deactivate = deactivate; - parent_class->get_generic_capabilities = get_generic_capabilities; + device_class->connection_type_supported = NM_SETTING_PPPOE_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_PPPOE_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_PPP); + + device_class->act_stage2_config = act_stage2_config; + device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; + device_class->create_and_realize = create_and_realize; + device_class->deactivate = deactivate; + device_class->get_generic_capabilities = get_generic_capabilities; } /*****************************************************************************/ diff --git a/src/devices/nm-device-private.h b/src/devices/nm-device-private.h index ba28e9e429..66c715de90 100644 --- a/src/devices/nm-device-private.h +++ b/src/devices/nm-device-private.h @@ -130,12 +130,21 @@ void nm_device_commit_mtu (NMDevice *self); /*****************************************************************************/ -#define NM_DEVICE_CLASS_DECLARE_TYPES(klass, conn_type, ...) \ - NM_DEVICE_CLASS (klass)->connection_type = conn_type; \ - { \ - static const NMLinkType link_types[] = { __VA_ARGS__, NM_LINK_TYPE_NONE }; \ - NM_DEVICE_CLASS (klass)->link_types = link_types; \ - } +#define NM_DEVICE_DEFINE_LINK_TYPES(...) \ + ((NM_NARG (__VA_ARGS__) == 0) \ + ? NULL \ + : ({ \ + static const struct { \ + const NMLinkType types[NM_NARG (__VA_ARGS__)]; \ + const NMLinkType sentinel; \ + } _link_types = { \ + .types = { __VA_ARGS__ }, \ + .sentinel = NM_LINK_TYPE_NONE, \ + }; \ + \ + _link_types.types; \ + })\ + ) gboolean _nm_device_hash_check_invalid_keys (GHashTable *hash, const char *setting_name, GError **error, const char **whitelist); @@ -143,8 +152,8 @@ gboolean _nm_device_hash_check_invalid_keys (GHashTable *hash, const char *setti _nm_device_hash_check_invalid_keys (hash, setting_name, error, ((const char *[]) { __VA_ARGS__, NULL })) gboolean nm_device_match_parent (NMDevice *device, const char *parent); -gboolean nm_device_match_hwaddr (NMDevice *device, - NMConnection *connection, - gboolean fail_if_no_hwaddr); +gboolean nm_device_match_parent_hwaddr (NMDevice *device, + NMConnection *connection, + gboolean fail_if_no_hwaddr); #endif /* NM_DEVICE_PRIVATE_H */ diff --git a/src/devices/nm-device-tun.c b/src/devices/nm-device-tun.c index 3846676c1f..0f76b23a4b 100644 --- a/src/devices/nm-device-tun.c +++ b/src/devices/nm-device-tun.c @@ -289,18 +289,14 @@ _same_og (const char *str, gboolean og_valid, guint32 og_num) } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { NMDeviceTun *self = NM_DEVICE_TUN (device); NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); NMSettingTunMode mode; NMSettingTun *s_tun; - if (!NM_DEVICE_CLASS (nm_device_tun_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - s_tun = nm_connection_get_setting_tun (connection); - if (!s_tun) + if (!NM_DEVICE_CLASS (nm_device_tun_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; if (nm_device_is_real (device)) { @@ -308,22 +304,43 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) case IFF_TUN: mode = NM_SETTING_TUN_MODE_TUN; break; case IFF_TAP: mode = NM_SETTING_TUN_MODE_TAP; break; default: - /* Huh? */ + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "invalid tun type on device"); return FALSE; } - if (mode != nm_setting_tun_get_mode (s_tun)) + s_tun = nm_connection_get_setting_tun (connection); + + if (mode != nm_setting_tun_get_mode (s_tun)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "tun mode setting mismatches"); return FALSE; - if (!_same_og (nm_setting_tun_get_owner (s_tun), priv->props.owner_valid, priv->props.owner)) + } + if (!_same_og (nm_setting_tun_get_owner (s_tun), priv->props.owner_valid, priv->props.owner)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "tun owner setting mismatches"); return FALSE; - if (!_same_og (nm_setting_tun_get_group (s_tun), priv->props.group_valid, priv->props.group)) + } + if (!_same_og (nm_setting_tun_get_group (s_tun), priv->props.group_valid, priv->props.group)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "tun group setting mismatches"); return FALSE; - if (nm_setting_tun_get_pi (s_tun) != priv->props.pi) + } + if (nm_setting_tun_get_pi (s_tun) != priv->props.pi) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "tun pi setting mismatches"); return FALSE; - if (nm_setting_tun_get_vnet_hdr (s_tun) != priv->props.vnet_hdr) + } + if (nm_setting_tun_get_vnet_hdr (s_tun) != priv->props.vnet_hdr) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "tun vnet-hdr setting mismatches"); return FALSE; - if (nm_setting_tun_get_multi_queue (s_tun) != priv->props.multi_queue) + } + if (nm_setting_tun_get_multi_queue (s_tun) != priv->props.multi_queue) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "tun multi-queue setting mismatches"); return FALSE; + } } return TRUE; @@ -430,13 +447,14 @@ nm_device_tun_class_init (NMDeviceTunClass *klass) NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_TUN) - object_class->get_property = get_property; dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_tun); - device_class->connection_type = NM_SETTING_TUN_SETTING_NAME; + device_class->connection_type_supported = NM_SETTING_TUN_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_TUN_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_TUN); + device_class->link_changed = link_changed; device_class->complete_connection = complete_connection; device_class->check_connection_compatible = check_connection_compatible; diff --git a/src/devices/nm-device-veth.c b/src/devices/nm-device-veth.c index 186173eb88..6f90758cd5 100644 --- a/src/devices/nm-device-veth.c +++ b/src/devices/nm-device-veth.c @@ -153,12 +153,13 @@ nm_device_veth_class_init (NMDeviceVethClass *klass) NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_VETH) - object_class->get_property = get_property; dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_veth); + device_class->connection_type_supported = NULL; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_VETH); + device_class->can_unmanaged_external_down = can_unmanaged_external_down; device_class->link_changed = link_changed; device_class->parent_changed_notify = parent_changed_notify; diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c index b0e746a822..d6376489f4 100644 --- a/src/devices/nm-device-vlan.c +++ b/src/devices/nm-device-vlan.c @@ -331,33 +331,39 @@ is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) /*****************************************************************************/ static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE ((NMDeviceVlan *) device); NMSettingVlan *s_vlan; - const char *parent = NULL; - - if (!NM_DEVICE_CLASS (nm_device_vlan_parent_class)->check_connection_compatible (device, connection)) - return FALSE; + const char *parent; - s_vlan = nm_connection_get_setting_vlan (connection); - if (!s_vlan) + if (!NM_DEVICE_CLASS (nm_device_vlan_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; - /* Before the device is realized some properties will not be set */ if (nm_device_is_real (device)) { - if (nm_setting_vlan_get_id (s_vlan) != priv->vlan_id) + s_vlan = nm_connection_get_setting_vlan (connection); + + if (nm_setting_vlan_get_id (s_vlan) != priv->vlan_id) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vlan id setting mismatches"); return FALSE; + } /* Check parent interface; could be an interface name or a UUID */ parent = nm_setting_vlan_get_parent (s_vlan); if (parent) { - if (!nm_device_match_parent (device, parent)) + if (!nm_device_match_parent (device, parent)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vlan parent setting differs"); return FALSE; + } } else { /* Parent could be a MAC address in an NMSettingWired */ - if (!nm_device_match_hwaddr (device, connection, TRUE)) + if (!nm_device_match_parent_hwaddr (device, connection, TRUE)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vlan parent mac setting differs"); return FALSE; + } } } @@ -368,12 +374,13 @@ static gboolean check_connection_available (NMDevice *device, NMConnection *connection, NMDeviceCheckConAvailableFlags flags, - const char *specific_object) + const char *specific_object, + GError **error) { if (!nm_device_is_real (device)) return TRUE; - return NM_DEVICE_CLASS (nm_device_vlan_parent_class)->check_connection_available (device, connection, flags, specific_object); + return NM_DEVICE_CLASS (nm_device_vlan_parent_class)->check_connection_available (device, connection, flags, specific_object, error); } static gboolean @@ -405,7 +412,7 @@ complete_connection (NMDevice *device, * settings, then there's not enough information to complete the setting. */ if ( !nm_setting_vlan_get_parent (s_vlan) - && !nm_device_match_hwaddr (device, connection, TRUE)) { + && !nm_device_match_parent_hwaddr (device, connection, TRUE)) { g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, "The 'vlan' setting had no interface name, parent, or hardware address."); return FALSE; @@ -454,7 +461,7 @@ update_connection (NMDevice *device, NMConnection *connection) /* Don't change a parent specified by UUID if it's still valid */ parent_connection = (NMConnection *) nm_settings_get_connection_by_uuid (nm_device_get_settings (device), setting_parent); - if (parent_connection && nm_device_check_connection_compatible (parent_device, parent_connection)) + if (parent_connection && nm_device_check_connection_compatible (parent_device, parent_connection, NULL)) new_parent = NULL; } if (new_parent) @@ -599,27 +606,29 @@ nm_device_vlan_class_init (NMDeviceVlanClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_VLAN_SETTING_NAME, NM_LINK_TYPE_VLAN) + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); object_class->get_property = get_property; dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_vlan); - parent_class->create_and_realize = create_and_realize; - parent_class->link_changed = link_changed; - parent_class->unrealize_notify = unrealize_notify; - parent_class->get_generic_capabilities = get_generic_capabilities; - parent_class->act_stage1_prepare = act_stage1_prepare; - parent_class->get_configured_mtu = get_configured_mtu; - parent_class->is_available = is_available; - parent_class->parent_changed_notify = parent_changed_notify; - - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->check_connection_available = check_connection_available; - parent_class->complete_connection = complete_connection; - parent_class->update_connection = update_connection; + device_class->connection_type_supported = NM_SETTING_VLAN_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_VLAN_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_VLAN); + + device_class->create_and_realize = create_and_realize; + device_class->link_changed = link_changed; + device_class->unrealize_notify = unrealize_notify; + device_class->get_generic_capabilities = get_generic_capabilities; + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->get_configured_mtu = get_configured_mtu; + device_class->is_available = is_available; + device_class->parent_changed_notify = parent_changed_notify; + + device_class->check_connection_compatible = check_connection_compatible; + device_class->check_connection_available = check_connection_available; + device_class->complete_connection = complete_connection; + device_class->update_connection = update_connection; obj_properties[PROP_VLAN_ID] = g_param_spec_uint (NM_DEVICE_VLAN_ID, "", "", diff --git a/src/devices/nm-device-vxlan.c b/src/devices/nm-device-vxlan.c index e125222374..f6f15729b2 100644 --- a/src/devices/nm-device-vxlan.c +++ b/src/devices/nm-device-vxlan.c @@ -246,65 +246,108 @@ address_matches (const char *str, in_addr_t addr4, struct in6_addr *addr6) } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { NMDeviceVxlanPrivate *priv = NM_DEVICE_VXLAN_GET_PRIVATE ((NMDeviceVxlan *) device); NMSettingVxlan *s_vxlan; const char *parent; - if (!NM_DEVICE_CLASS (nm_device_vxlan_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - s_vxlan = nm_connection_get_setting_vxlan (connection); - if (!s_vxlan) + if (!NM_DEVICE_CLASS (nm_device_vxlan_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; if (nm_device_is_real (device)) { + s_vxlan = nm_connection_get_setting_vxlan (connection); + parent = nm_setting_vxlan_get_parent (s_vxlan); - if (parent && !nm_device_match_parent (device, parent)) + if (parent && !nm_device_match_parent (device, parent)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vxlan parent mismatches"); return FALSE; + } - if (priv->props.id != nm_setting_vxlan_get_id (s_vxlan)) + if (priv->props.id != nm_setting_vxlan_get_id (s_vxlan)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vxlan id mismatches"); return FALSE; + } - if (!address_matches (nm_setting_vxlan_get_local (s_vxlan), priv->props.local, &priv->props.local6)) + if (!address_matches (nm_setting_vxlan_get_local (s_vxlan), priv->props.local, &priv->props.local6)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vxlan local address mismatches"); return FALSE; + } - if (!address_matches (nm_setting_vxlan_get_remote (s_vxlan), priv->props.group, &priv->props.group6)) + if (!address_matches (nm_setting_vxlan_get_remote (s_vxlan), priv->props.group, &priv->props.group6)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vxlan remote address mismatches"); return FALSE; + } - if (priv->props.src_port_min != nm_setting_vxlan_get_source_port_min (s_vxlan)) + if (priv->props.src_port_min != nm_setting_vxlan_get_source_port_min (s_vxlan)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vxlan source port min mismatches"); return FALSE; + } - if (priv->props.src_port_max != nm_setting_vxlan_get_source_port_max (s_vxlan)) + if (priv->props.src_port_max != nm_setting_vxlan_get_source_port_max (s_vxlan)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vxlan source port max mismatches"); return FALSE; + } - if (priv->props.dst_port != nm_setting_vxlan_get_destination_port (s_vxlan)) + if (priv->props.dst_port != nm_setting_vxlan_get_destination_port (s_vxlan)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vxlan destination port mismatches"); return FALSE; + } - if (priv->props.tos != nm_setting_vxlan_get_tos (s_vxlan)) + if (priv->props.tos != nm_setting_vxlan_get_tos (s_vxlan)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vxlan TOS mismatches"); return FALSE; + } - if (priv->props.ttl != nm_setting_vxlan_get_ttl (s_vxlan)) + if (priv->props.ttl != nm_setting_vxlan_get_ttl (s_vxlan)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vxlan TTL mismatches"); return FALSE; + } - if (priv->props.learning != nm_setting_vxlan_get_learning (s_vxlan)) + if (priv->props.learning != nm_setting_vxlan_get_learning (s_vxlan)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vxlan learning mismatches"); return FALSE; + } - if (priv->props.ageing != nm_setting_vxlan_get_ageing (s_vxlan)) + if (priv->props.ageing != nm_setting_vxlan_get_ageing (s_vxlan)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vxlan ageing mismatches"); return FALSE; + } - if (priv->props.proxy != nm_setting_vxlan_get_proxy (s_vxlan)) + if (priv->props.proxy != nm_setting_vxlan_get_proxy (s_vxlan)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vxlan proxy mismatches"); return FALSE; + } - if (priv->props.rsc != nm_setting_vxlan_get_rsc (s_vxlan)) + if (priv->props.rsc != nm_setting_vxlan_get_rsc (s_vxlan)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vxlan rsc mismatches"); return FALSE; + } - if (priv->props.l2miss != nm_setting_vxlan_get_l2_miss (s_vxlan)) + if (priv->props.l2miss != nm_setting_vxlan_get_l2_miss (s_vxlan)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vxlan l2miss mismatches"); return FALSE; + } - if (priv->props.l3miss != nm_setting_vxlan_get_l3_miss (s_vxlan)) + if (priv->props.l3miss != nm_setting_vxlan_get_l3_miss (s_vxlan)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vxlan l3miss mismatches"); return FALSE; + } } return TRUE; @@ -367,7 +410,7 @@ update_connection (NMDevice *device, NMConnection *connection) /* Don't change a parent specified by UUID if it's still valid */ parent_connection = (NMConnection *) nm_settings_get_connection_by_uuid (nm_device_get_settings (device), setting_parent); - if (parent_connection && nm_device_check_connection_compatible (parent_device, parent_connection)) + if (parent_connection && nm_device_check_connection_compatible (parent_device, parent_connection, NULL)) new_parent = NULL; } } @@ -577,15 +620,16 @@ nm_device_vxlan_class_init (NMDeviceVxlanClass *klass) NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_VXLAN) - object_class->get_property = get_property; dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_vxlan); + device_class->connection_type_supported = NM_SETTING_VXLAN_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_VXLAN_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_VXLAN); + device_class->link_changed = link_changed; device_class->unrealize_notify = unrealize_notify; - device_class->connection_type = NM_SETTING_VXLAN_SETTING_NAME; device_class->create_and_realize = create_and_realize; device_class->check_connection_compatible = check_connection_compatible; device_class->complete_connection = complete_connection; diff --git a/src/devices/nm-device-wpan.c b/src/devices/nm-device-wpan.c index 978dfa00ac..dd2ebac149 100644 --- a/src/devices/nm-device-wpan.c +++ b/src/devices/nm-device-wpan.c @@ -91,23 +91,24 @@ update_connection (NMDevice *device, NMConnection *connection) } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { NMSettingWpan *s_wpan; const char *mac, *hw_addr; - if (!NM_DEVICE_CLASS (nm_device_wpan_parent_class)->check_connection_compatible (device, connection)) + if (!NM_DEVICE_CLASS (nm_device_wpan_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; s_wpan = nm_connection_get_setting_wpan (connection); - if (!s_wpan) - return FALSE; mac = nm_setting_wpan_get_mac_address (s_wpan); if (mac) { hw_addr = nm_device_get_hw_address (device); - if (!nm_utils_hwaddr_matches (mac, -1, hw_addr, -1)) + if (!nm_utils_hwaddr_matches (mac, -1, hw_addr, -1)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "MAC address mismatches"); return FALSE; + } } return TRUE; @@ -213,11 +214,12 @@ nm_device_wpan_class_init (NMDeviceWpanClass *klass) NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_WPAN) - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_wpan); - device_class->connection_type = NM_SETTING_WPAN_SETTING_NAME; + device_class->connection_type_supported = NM_SETTING_WPAN_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_WPAN_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_WPAN); + device_class->complete_connection = complete_connection; device_class->check_connection_compatible = check_connection_compatible; device_class->update_connection = update_connection; diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 7ca2360b27..33faa4bf4f 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -5115,7 +5115,7 @@ nm_device_can_auto_connect (NMDevice *self, * over and over again. The caller is supposed to do that. */ nm_assert (nm_device_autoconnect_allowed (self)); - if (!nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_NONE, NULL)) + if (!nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_NONE, NULL, NULL)) return FALSE; if (!NM_DEVICE_GET_CLASS (self)->can_auto_connect (self, connection, specific_object)) @@ -5239,8 +5239,10 @@ nm_device_generate_connection (NMDevice *self, NM_SETTING_CONNECTION_INTERFACE_NAME, ifname, NM_SETTING_CONNECTION_TIMESTAMP, (guint64) time (NULL), NULL); - if (klass->connection_type) - g_object_set (s_con, NM_SETTING_CONNECTION_TYPE, klass->connection_type, NULL); + + if (klass->connection_type_supported) + g_object_set (s_con, NM_SETTING_CONNECTION_TYPE, klass->connection_type_supported, NULL); + nm_connection_add_setting (connection, s_con); /* If the device is a slave, update various slave settings */ @@ -5392,9 +5394,9 @@ nm_device_match_parent (NMDevice *self, const char *parent) } gboolean -nm_device_match_hwaddr (NMDevice *device, - NMConnection *connection, - gboolean fail_if_no_hwaddr) +nm_device_match_parent_hwaddr (NMDevice *device, + NMConnection *connection, + gboolean fail_if_no_hwaddr) { NMSettingWired *s_wired; NMDevice *parent_device; @@ -5418,21 +5420,43 @@ nm_device_match_hwaddr (NMDevice *device, } static gboolean -check_connection_compatible (NMDevice *self, NMConnection *connection) +check_connection_compatible (NMDevice *self, NMConnection *connection, GError **error) { const char *device_iface = nm_device_get_iface (self); - gs_free char *conn_iface = nm_manager_get_connection_iface (nm_manager_get (), - connection, - NULL, NULL); + gs_free_error GError *local = NULL; + gs_free char *conn_iface = NULL; + NMDeviceClass *klass; + + klass = NM_DEVICE_GET_CLASS (self); + if (klass->connection_type_check_compatible) { + if (!_nm_connection_check_main_setting (connection, + klass->connection_type_check_compatible, + error)) + return FALSE; + } + + conn_iface = nm_manager_get_connection_iface (nm_manager_get (), + connection, + NULL, + &local); /* We always need a interface name for virtual devices, but for * physical ones a connection without interface name is fine for * any device. */ - if (!conn_iface) - return !nm_connection_is_virtual (connection); + if (!conn_iface) { + if (nm_connection_is_virtual (connection)) { + nm_utils_error_set (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "cannot get interface name due to %s", local->message); + return FALSE; + } + return TRUE; + } - if (strcmp (conn_iface, device_iface) != 0) + if (!nm_streq0 (conn_iface, device_iface)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "mismatching interface name"); return FALSE; + } return TRUE; } @@ -5441,6 +5465,11 @@ check_connection_compatible (NMDevice *self, NMConnection *connection) * nm_device_check_connection_compatible: * @self: an #NMDevice * @connection: an #NMConnection + * @error: optional reason why it is incompatible. Note that the + * error code is set to %NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, + * if the profile is fundamentally incompatible with the device + * (most commonly, because the device-type does not support the + * connection-type). * * Checks if @connection could potentially be activated on @self. * This means only that @self has the proper capabilities, and that @@ -5453,12 +5482,12 @@ check_connection_compatible (NMDevice *self, NMConnection *connection) * @self. */ gboolean -nm_device_check_connection_compatible (NMDevice *self, NMConnection *connection) +nm_device_check_connection_compatible (NMDevice *self, NMConnection *connection, GError **error) { g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); - return NM_DEVICE_GET_CLASS (self)->check_connection_compatible (self, connection); + return NM_DEVICE_GET_CLASS (self)->check_connection_compatible (self, connection, error); } gboolean @@ -5474,7 +5503,7 @@ nm_device_check_slave_connection_compatible (NMDevice *self, NMConnection *slave return FALSE; /* All masters should have connection type set */ - connection_type = NM_DEVICE_GET_CLASS (self)->connection_type; + connection_type = NM_DEVICE_GET_CLASS (self)->connection_type_supported; g_return_val_if_fail (connection_type, FALSE); s_con = nm_connection_get_setting_connection (slave); @@ -11337,7 +11366,7 @@ _carrier_wait_check_act_request_must_queue (NMDevice *self, NMActRequest *req) if (!connection_requires_carrier (connection)) return FALSE; - if (!nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_ALL, NULL)) { + if (!nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_ALL, NULL, NULL)) { /* We passed all @flags we have, and no @specific_object. * This equals maximal availability, if a connection is not available * in this case, it is not waiting for carrier. @@ -11348,7 +11377,9 @@ _carrier_wait_check_act_request_must_queue (NMDevice *self, NMActRequest *req) return FALSE; } - if (nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_ALL & ~_NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER, NULL)) { + if (nm_device_check_connection_available (self, connection, + NM_DEVICE_CHECK_CON_AVAILABLE_ALL & ~_NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER, + NULL, NULL)) { /* The connection was available with flags ALL, and it is still available * if we pretend not to wait for carrier. That means that the * connection is available now, and does not wait for carrier. @@ -13209,38 +13240,88 @@ static gboolean _nm_device_check_connection_available (NMDevice *self, NMConnection *connection, NMDeviceCheckConAvailableFlags flags, - const char *specific_object) + const char *specific_object, + GError **error) { NMDeviceState state; + GError *local = NULL; /* an unrealized software device is always available, hardware devices never. */ if (!nm_device_is_real (self)) { - if (nm_device_is_software (self)) - return nm_device_check_connection_compatible (self, connection); + if (nm_device_is_software (self)) { + if (!nm_device_check_connection_compatible (self, connection, + error ? &local : NULL)) { + if (error) { + nm_utils_error_set (error, + local->domain == NM_UTILS_ERROR + ? local->code + : NM_UTILS_ERROR_UNKNOWN, + "profile is not compatible with software device (%s)", + local->message); + g_error_free (local); + } + return FALSE; + } + return TRUE; + } + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE, + "hardware device is not realized"); return FALSE; } state = nm_device_get_state (self); - if (state < NM_DEVICE_STATE_UNMANAGED) - return FALSE; - if ( state < NM_DEVICE_STATE_UNAVAILABLE - && ( ( !NM_FLAGS_ANY (flags, NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST) - && !nm_device_get_managed (self, FALSE)) - || ( NM_FLAGS_ANY (flags, NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST) - && !nm_device_get_managed (self, TRUE)))) + if (state < NM_DEVICE_STATE_UNMANAGED) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE, + "device is in unknown state"); return FALSE; + } + if (state < NM_DEVICE_STATE_UNAVAILABLE) { + if (NM_FLAGS_ANY (flags, NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST)) { + if (!nm_device_get_managed (self, TRUE)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE, + "device is unmanaged"); + return FALSE; + } + } else { + if (!nm_device_get_managed (self, FALSE)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE, + "device is unmanaged for interal request"); + return FALSE; + } + } + } if ( state < NM_DEVICE_STATE_DISCONNECTED - && !nm_device_is_software (self) - && ( ( !NM_FLAGS_ANY (flags, NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST) - && !nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) - || ( NM_FLAGS_ANY (flags, NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST) - && !nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_FOR_USER_REQUEST)))) - return FALSE; + && !nm_device_is_software (self)) { + if (NM_FLAGS_ANY (flags, NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST)) { + if (!nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_FOR_USER_REQUEST)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device is not available"); + return FALSE; + } + } else { + if (!nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device is not available for internal request"); + return FALSE; + } + } + } - if (!nm_device_check_connection_compatible (self, connection)) + if (!nm_device_check_connection_compatible (self, connection, + error ? &local : NULL)) { + if (error) { + nm_utils_error_set (error, + local->domain == NM_UTILS_ERROR + ? local->code + : NM_UTILS_ERROR_UNKNOWN, + "profile is not compatible with device (%s)", + local->message); + g_error_free (local); + } return FALSE; + } - return NM_DEVICE_GET_CLASS (self)->check_connection_available (self, connection, flags, specific_object); + return NM_DEVICE_GET_CLASS (self)->check_connection_available (self, connection, flags, specific_object, error); } /** @@ -13253,6 +13334,7 @@ _nm_device_check_connection_available (NMDevice *self, * @specific_object: a device type dependent argument to further * filter the result. Passing a non %NULL specific object can only reduce * the availability of a connection. + * @error: optionally give reason why not available. * * Check if @connection is available to be activated on @self. * @@ -13262,11 +13344,12 @@ gboolean nm_device_check_connection_available (NMDevice *self, NMConnection *connection, NMDeviceCheckConAvailableFlags flags, - const char *specific_object) + const char *specific_object, + GError **error) { gboolean available; - available = _nm_device_check_connection_available (self, connection, flags, specific_object); + available = _nm_device_check_connection_available (self, connection, flags, specific_object, error); #if NM_MORE_ASSERTS >= 2 { @@ -13276,7 +13359,7 @@ nm_device_check_connection_available (NMDevice *self, gboolean available_all[NM_DEVICE_CHECK_CON_AVAILABLE_ALL + 1] = { FALSE }; for (i = 0; i <= NM_DEVICE_CHECK_CON_AVAILABLE_ALL; i++) - available_all[i] = _nm_device_check_connection_available (self, connection, i, specific_object); + available_all[i] = _nm_device_check_connection_available (self, connection, i, specific_object, NULL); for (i = 0; i <= NM_DEVICE_CHECK_CON_AVAILABLE_ALL; i++) { for (j = 1; j <= NM_DEVICE_CHECK_CON_AVAILABLE_ALL; j <<= 1) { @@ -13318,7 +13401,8 @@ static gboolean check_connection_available (NMDevice *self, NMConnection *connection, NMDeviceCheckConAvailableFlags flags, - const char *specific_object) + const char *specific_object, + GError **error) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); @@ -13344,6 +13428,8 @@ check_connection_available (NMDevice *self, if (nm_device_is_master (self)) return TRUE; + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device has no carrier"); return FALSE; } @@ -13376,6 +13462,7 @@ nm_device_recheck_available_connections (NMDevice *self) if (nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_NONE, + NULL, NULL)) { if (available_connections_add (self, connection)) changed = TRUE; @@ -13430,7 +13517,8 @@ nm_device_get_best_connection (NMDevice *self, && !nm_device_check_connection_available (self, NM_CONNECTION (candidate), _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, - specific_object)) + specific_object, + NULL)) continue; nm_settings_connection_get_timestamp (candidate, &candidate_timestamp); @@ -13460,6 +13548,7 @@ cp_connection_added_or_updated (NMDevice *self, NMConnection *connection) if (nm_device_check_connection_available (self, connection, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, + NULL, NULL)) changed = available_connections_add (self, connection); else diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index d145f8fc20..41156c1008 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -202,7 +202,12 @@ typedef struct _NMDeviceClass { struct _NMDeviceClass *default_type_description_klass; const char *default_type_description; - const char *connection_type; + const char *connection_type_supported; + + /* most device types, can only handle profiles of a particular type. This + * is the connection.type setting, as checked by nm_device_check_connection_compatible() */ + const char *connection_type_check_compatible; + const NMLinkType *link_types; /* Whether the device type is a master-type. This depends purely on the @@ -301,7 +306,9 @@ typedef struct _NMDeviceClass { * only the devices type and characteristics. Does not use any live * network information like WiFi scan lists etc. */ - gboolean (* check_connection_compatible) (NMDevice *self, NMConnection *connection); + gboolean (* check_connection_compatible) (NMDevice *self, + NMConnection *connection, + GError **error); /* Checks whether the connection is likely available to be activated, * including any live network information like scan lists. The connection @@ -317,7 +324,8 @@ typedef struct _NMDeviceClass { gboolean (* check_connection_available) (NMDevice *self, NMConnection *connection, NMDeviceCheckConAvailableFlags flags, - const char *specific_object); + const char *specific_object, + GError **error); gboolean (* complete_connection) (NMDevice *self, NMConnection *connection, @@ -533,7 +541,10 @@ gboolean nm_device_complete_connection (NMDevice *device, NMConnection *const*existing_connections, GError **error); -gboolean nm_device_check_connection_compatible (NMDevice *device, NMConnection *connection); +gboolean nm_device_check_connection_compatible (NMDevice *device, + NMConnection *connection, + GError **error); + gboolean nm_device_check_slave_connection_compatible (NMDevice *device, NMConnection *connection); gboolean nm_device_unmanage_on_quit (NMDevice *self); @@ -742,7 +753,8 @@ NMSettingsConnection *nm_device_get_best_connection (NMDevice *device, gboolean nm_device_check_connection_available (NMDevice *device, NMConnection *connection, NMDeviceCheckConAvailableFlags flags, - const char *specific_object); + const char *specific_object, + GError **error); gboolean nm_device_notify_component_added (NMDevice *device, GObject *component); diff --git a/src/devices/ovs/nm-device-ovs-bridge.c b/src/devices/ovs/nm-device-ovs-bridge.c index 2e4d1cbdf8..eff355a3ef 100644 --- a/src/devices/ovs/nm-device-ovs-bridge.c +++ b/src/devices/ovs/nm-device-ovs-bridge.c @@ -76,21 +76,6 @@ get_generic_capabilities (NMDevice *device) return NM_DEVICE_CAP_IS_SOFTWARE; } -static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) -{ - const char *connection_type; - - if (!NM_DEVICE_CLASS (nm_device_ovs_bridge_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - connection_type = nm_connection_get_connection_type (connection); - if (!nm_streq0 (connection_type, NM_SETTING_OVS_BRIDGE_SETTING_NAME)) - return FALSE; - - return TRUE; -} - static NMActStageReturn act_stage3_ip4_config_start (NMDevice *device, NMIP4Config **out_config, @@ -152,13 +137,15 @@ nm_device_ovs_bridge_class_init (NMDeviceOvsBridgeClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_ovs_bridge); - device_class->connection_type = NM_SETTING_OVS_BRIDGE_SETTING_NAME; + device_class->connection_type_supported = NM_SETTING_OVS_BRIDGE_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_OVS_BRIDGE_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (); + device_class->is_master = TRUE; device_class->get_type_description = get_type_description; device_class->create_and_realize = create_and_realize; device_class->unrealize = unrealize; device_class->get_generic_capabilities = get_generic_capabilities; - device_class->check_connection_compatible = check_connection_compatible; device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; device_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; device_class->enslave_slave = enslave_slave; diff --git a/src/devices/ovs/nm-device-ovs-interface.c b/src/devices/ovs/nm-device-ovs-interface.c index c59af7a6b1..2b48fae683 100644 --- a/src/devices/ovs/nm-device-ovs-interface.c +++ b/src/devices/ovs/nm-device-ovs-interface.c @@ -85,25 +85,20 @@ is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { - NMSettingConnection *s_con; NMSettingOvsInterface *s_ovs_iface; - if (!NM_DEVICE_CLASS (nm_device_ovs_interface_parent_class)->check_connection_compatible (device, connection)) + if (!NM_DEVICE_CLASS (nm_device_ovs_interface_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; s_ovs_iface = nm_connection_get_setting_ovs_interface (connection); - if (!s_ovs_iface) - return FALSE; - if (!NM_IN_STRSET (nm_setting_ovs_interface_get_interface_type (s_ovs_iface), - "internal", "patch")) { - return FALSE; - } - s_con = nm_connection_get_setting_connection (connection); - if (g_strcmp0 (nm_setting_connection_get_connection_type (s_con), - NM_SETTING_OVS_INTERFACE_SETTING_NAME) != 0) { + if (!NM_IN_STRSET (nm_setting_ovs_interface_get_interface_type (s_ovs_iface), + "internal", + "patch")) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "unsupported OVS interface type in profile"); return FALSE; } @@ -199,11 +194,12 @@ nm_device_ovs_interface_class_init (NMDeviceOvsInterfaceClass *klass) NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_OPENVSWITCH); - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_ovs_interface); - device_class->connection_type = NM_SETTING_OVS_INTERFACE_SETTING_NAME; + device_class->connection_type_supported = NM_SETTING_OVS_INTERFACE_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_OVS_INTERFACE_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_OPENVSWITCH); + device_class->get_type_description = get_type_description; device_class->create_and_realize = create_and_realize; device_class->get_generic_capabilities = get_generic_capabilities; diff --git a/src/devices/ovs/nm-device-ovs-port.c b/src/devices/ovs/nm-device-ovs-port.c index a9a2b24a2b..1f9afbab5b 100644 --- a/src/devices/ovs/nm-device-ovs-port.c +++ b/src/devices/ovs/nm-device-ovs-port.c @@ -70,26 +70,6 @@ get_generic_capabilities (NMDevice *device) return NM_DEVICE_CAP_IS_SOFTWARE; } -static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) -{ - NMSettingConnection *s_con; - const char *connection_type; - - if (!NM_DEVICE_CLASS (nm_device_ovs_port_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - s_con = nm_connection_get_setting_connection (connection); - connection_type = nm_setting_connection_get_connection_type (s_con); - if (!connection_type) - return FALSE; - - if (strcmp (connection_type, NM_SETTING_OVS_PORT_SETTING_NAME) == 0) - return TRUE; - - return FALSE; -} - static NMActStageReturn act_stage3_ip4_config_start (NMDevice *device, NMIP4Config **out_config, @@ -198,12 +178,14 @@ nm_device_ovs_port_class_init (NMDeviceOvsPortClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_ovs_port); - device_class->connection_type = NM_SETTING_OVS_PORT_SETTING_NAME; + device_class->connection_type_supported = NM_SETTING_OVS_PORT_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_OVS_PORT_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (); + device_class->is_master = TRUE; device_class->get_type_description = get_type_description; device_class->create_and_realize = create_and_realize; device_class->get_generic_capabilities = get_generic_capabilities; - device_class->check_connection_compatible = check_connection_compatible; device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; device_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; device_class->enslave_slave = enslave_slave; diff --git a/src/devices/team/nm-device-team.c b/src/devices/team/nm-device-team.c index ef7c63b8a8..899932fd4b 100644 --- a/src/devices/team/nm-device-team.c +++ b/src/devices/team/nm-device-team.c @@ -85,23 +85,6 @@ get_generic_capabilities (NMDevice *device) } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) -{ - NMSettingTeam *s_team; - - if (!NM_DEVICE_CLASS (nm_device_team_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - s_team = nm_connection_get_setting_team (connection); - if (!s_team || !nm_connection_is_type (connection, NM_SETTING_TEAM_SETTING_NAME)) - return FALSE; - - /* FIXME: match team properties like mode, etc? */ - - return TRUE; -} - -static gboolean complete_connection (NMDevice *device, NMConnection *connection, const char *specific_object, @@ -911,9 +894,7 @@ nm_device_team_class_init (NMDeviceTeamClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_TEAM_SETTING_NAME, NM_LINK_TYPE_TEAM) + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); object_class->constructed = constructed; object_class->dispose = dispose; @@ -921,19 +902,22 @@ nm_device_team_class_init (NMDeviceTeamClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_team); - parent_class->is_master = TRUE; - parent_class->create_and_realize = create_and_realize; - parent_class->get_generic_capabilities = get_generic_capabilities; - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->complete_connection = complete_connection; - parent_class->update_connection = update_connection; - parent_class->master_update_slave_connection = master_update_slave_connection; - - parent_class->act_stage1_prepare = act_stage1_prepare; - parent_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; - parent_class->deactivate = deactivate; - parent_class->enslave_slave = enslave_slave; - parent_class->release_slave = release_slave; + device_class->connection_type_supported = NM_SETTING_TEAM_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_TEAM_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_TEAM); + + device_class->is_master = TRUE; + device_class->create_and_realize = create_and_realize; + device_class->get_generic_capabilities = get_generic_capabilities; + device_class->complete_connection = complete_connection; + device_class->update_connection = update_connection; + device_class->master_update_slave_connection = master_update_slave_connection; + + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; + device_class->deactivate = deactivate; + device_class->enslave_slave = enslave_slave; + device_class->release_slave = release_slave; obj_properties[PROP_CONFIG] = g_param_spec_string (NM_DEVICE_TEAM_CONFIG, "", "", diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c index cdb688d9ae..aaf8e81bb5 100644 --- a/src/devices/wifi/nm-device-iwd.c +++ b/src/devices/wifi/nm-device-iwd.c @@ -492,59 +492,62 @@ is_connection_known_network (NMConnection *connection) } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { - NMSettingConnection *s_con; NMSettingWireless *s_wireless; const char *mac; const char * const *mac_blacklist; int i; - const char *mode; const char *perm_hw_addr; - if (!NM_DEVICE_CLASS (nm_device_iwd_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - s_con = nm_connection_get_setting_connection (connection); - g_assert (s_con); - - if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_WIRELESS_SETTING_NAME)) + if (!NM_DEVICE_CLASS (nm_device_iwd_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; s_wireless = nm_connection_get_setting_wireless (connection); - if (!s_wireless) - return FALSE; perm_hw_addr = nm_device_get_permanent_hw_address (device); mac = nm_setting_wireless_get_mac_address (s_wireless); if (perm_hw_addr) { - if (mac && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1)) + if (mac && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "mac address mispatches"); return FALSE; + } /* Check for MAC address blacklist */ mac_blacklist = nm_setting_wireless_get_mac_address_blacklist (s_wireless); for (i = 0; mac_blacklist[i]; i++) { - if (!nm_utils_hwaddr_valid (mac_blacklist[i], ETH_ALEN)) { - g_warn_if_reached (); - return FALSE; - } + nm_assert (nm_utils_hwaddr_valid (mac_blacklist[i], ETH_ALEN)); - if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, perm_hw_addr, -1)) + if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, perm_hw_addr, -1)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "mac address blacklisted"); return FALSE; + } } - } else if (mac) + } else if (mac) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device has no valid mac address as required by profile"); return FALSE; + } - mode = nm_setting_wireless_get_mode (s_wireless); - if (mode && g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_INFRA) != 0) + if (!NM_IN_STRSET (nm_setting_wireless_get_mode (s_wireless), + NULL, + NM_SETTING_WIRELESS_MODE_INFRA)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "IWD only support infrastructure type profiles"); return FALSE; + } /* 8021x networks can only be used if they've been provisioned on the IWD side and * thus are Known Networks. */ if (get_connection_iwd_security (connection) == NM_IWD_NETWORK_SECURITY_8021X) { - if (!is_connection_known_network (connection)) + if (!is_connection_known_network (connection)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "802.1x profile is not a known network"); return FALSE; + } } return TRUE; @@ -554,7 +557,8 @@ static gboolean check_connection_available (NMDevice *device, NMConnection *connection, NMDeviceCheckConAvailableFlags flags, - const char *specific_object) + const char *specific_object, + GError **error) { NMDeviceIwd *self = NM_DEVICE_IWD (device); NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); @@ -566,19 +570,28 @@ check_connection_available (NMDevice *device, /* Only Infrastrusture mode at this time */ mode = nm_setting_wireless_get_mode (s_wifi); - if (mode && g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_INFRA) != 0) + if (!NM_IN_SET (mode, NULL, NM_SETTING_WIRELESS_MODE_INFRA)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "iwd only supports infrastructure mode connections"); return FALSE; + } /* Hidden SSIDs not supported yet */ - if (nm_setting_wireless_get_hidden (s_wifi)) + if (nm_setting_wireless_get_hidden (s_wifi)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "hidden networks not supported by iwd"); return FALSE; + } /* 8021x networks can only be used if they've been provisioned on the IWD side and * thus are Known Networks. */ if (get_connection_iwd_security (connection) == NM_IWD_NETWORK_SECURITY_8021X) { - if (!is_connection_known_network (connection)) + if (!is_connection_known_network (connection)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "network is not known to iwd"); return FALSE; + } } /* a connection that is available for a certain @specific_object, MUST @@ -588,14 +601,29 @@ check_connection_available (NMDevice *device, NMWifiAP *ap; ap = nm_wifi_ap_lookup_for_device (NM_DEVICE (self), specific_object); - return ap ? nm_wifi_ap_check_compatible (ap, connection) : FALSE; + if (!ap) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "requested access point not found"); + return FALSE; + } + if (!nm_wifi_ap_check_compatible (ap, connection)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "requested access point is not compatible with profile"); + return FALSE; + } + return TRUE; } if (NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP)) return TRUE; - /* Check at least one AP is compatible with this connection */ - return !!nm_wifi_aps_find_first_compatible (&priv->aps_lst_head, connection); + if (!nm_wifi_aps_find_first_compatible (&priv->aps_lst_head, connection)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "no compatible access point found"); + return FALSE; + } + + return TRUE; } static gboolean @@ -1952,9 +1980,7 @@ nm_device_iwd_class_init (NMDeviceIwdClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_WIRELESS_SETTING_NAME, NM_LINK_TYPE_WIFI) + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); object_class->get_property = get_property; object_class->set_property = set_property; @@ -1962,25 +1988,29 @@ nm_device_iwd_class_init (NMDeviceIwdClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&nm_interface_info_device_wireless); - parent_class->can_auto_connect = can_auto_connect; - parent_class->is_available = is_available; - parent_class->get_autoconnect_allowed = get_autoconnect_allowed; - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->check_connection_available = check_connection_available; - parent_class->complete_connection = complete_connection; - parent_class->get_enabled = get_enabled; - parent_class->set_enabled = set_enabled; - parent_class->get_type_description = get_type_description; - - parent_class->act_stage1_prepare = act_stage1_prepare; - parent_class->act_stage2_config = act_stage2_config; - parent_class->get_configured_mtu = get_configured_mtu; - parent_class->deactivate = deactivate; - parent_class->deactivate_async = deactivate_async; - parent_class->deactivate_async_finish = deactivate_async_finish; - parent_class->can_reapply_change = can_reapply_change; - - parent_class->state_changed = device_state_changed; + device_class->connection_type_supported = NM_SETTING_WIRELESS_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_WIRELESS_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_WIFI); + + device_class->can_auto_connect = can_auto_connect; + device_class->is_available = is_available; + device_class->get_autoconnect_allowed = get_autoconnect_allowed; + device_class->check_connection_compatible = check_connection_compatible; + device_class->check_connection_available = check_connection_available; + device_class->complete_connection = complete_connection; + device_class->get_enabled = get_enabled; + device_class->set_enabled = set_enabled; + device_class->get_type_description = get_type_description; + + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->act_stage2_config = act_stage2_config; + device_class->get_configured_mtu = get_configured_mtu; + device_class->deactivate = deactivate; + device_class->deactivate_async = deactivate_async; + device_class->deactivate_async_finish = deactivate_async_finish; + device_class->can_reapply_change = can_reapply_change; + + device_class->state_changed = device_state_changed; klass->scanning_prohibited = scanning_prohibited; diff --git a/src/devices/wifi/nm-device-olpc-mesh.c b/src/devices/wifi/nm-device-olpc-mesh.c index fd7bf3f76f..7737f19a71 100644 --- a/src/devices/wifi/nm-device-olpc-mesh.c +++ b/src/devices/wifi/nm-device-olpc-mesh.c @@ -80,28 +80,6 @@ G_DEFINE_TYPE (NMDeviceOlpcMesh, nm_device_olpc_mesh, NM_TYPE_DEVICE) /*****************************************************************************/ static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) -{ - NMSettingConnection *s_con; - NMSettingOlpcMesh *s_mesh; - - if (!NM_DEVICE_CLASS (nm_device_olpc_mesh_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - s_con = nm_connection_get_setting_connection (connection); - g_assert (s_con); - - if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_OLPC_MESH_SETTING_NAME)) - return FALSE; - - s_mesh = nm_connection_get_setting_olpc_mesh (connection); - if (!s_mesh) - return FALSE; - - return TRUE; -} - -static gboolean get_autoconnect_allowed (NMDevice *device) { return FALSE; @@ -515,9 +493,7 @@ nm_device_olpc_mesh_class_init (NMDeviceOlpcMeshClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_OLPC_MESH_SETTING_NAME, NM_LINK_TYPE_OLPC_MESH) + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); object_class->constructed = constructed; object_class->get_property = get_property; @@ -525,14 +501,17 @@ nm_device_olpc_mesh_class_init (NMDeviceOlpcMeshClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_olpc_mesh); - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->get_autoconnect_allowed = get_autoconnect_allowed; - parent_class->complete_connection = complete_connection; - parent_class->is_available = is_available; - parent_class->act_stage1_prepare = act_stage1_prepare; - parent_class->act_stage2_config = act_stage2_config; - parent_class->state_changed = state_changed; - parent_class->get_dhcp_timeout = get_dhcp_timeout; + device_class->connection_type_supported = NM_SETTING_OLPC_MESH_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_OLPC_MESH_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_OLPC_MESH); + + device_class->get_autoconnect_allowed = get_autoconnect_allowed; + device_class->complete_connection = complete_connection; + device_class->is_available = is_available; + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->act_stage2_config = act_stage2_config; + device_class->state_changed = state_changed; + device_class->get_dhcp_timeout = get_dhcp_timeout; obj_properties[PROP_COMPANION] = g_param_spec_string (NM_DEVICE_OLPC_MESH_COMPANION, "", "", diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index 83f8afb6de..d43559a3a0 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -604,11 +604,10 @@ is_adhoc_wpa (NMConnection *connection) } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { NMDeviceWifi *self = NM_DEVICE_WIFI (device); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - NMSettingConnection *s_con; NMSettingWireless *s_wireless; const char *mac; const char * const *mac_blacklist; @@ -616,18 +615,10 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) const char *mode; const char *perm_hw_addr; - if (!NM_DEVICE_CLASS (nm_device_wifi_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - s_con = nm_connection_get_setting_connection (connection); - g_assert (s_con); - - if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_WIRELESS_SETTING_NAME)) + if (!NM_DEVICE_CLASS (nm_device_wifi_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; s_wireless = nm_connection_get_setting_wireless (connection); - if (!s_wireless) - return FALSE; perm_hw_addr = nm_device_get_permanent_hw_address (device); mac = nm_setting_wireless_get_mac_address (s_wireless); @@ -678,7 +669,8 @@ static gboolean check_connection_available (NMDevice *device, NMConnection *connection, NMDeviceCheckConAvailableFlags flags, - const char *specific_object) + const char *specific_object, + GError **error) { NMDeviceWifi *self = NM_DEVICE_WIFI (device); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); @@ -695,7 +687,17 @@ check_connection_available (NMDevice *device, NMWifiAP *ap; ap = nm_wifi_ap_lookup_for_device (NM_DEVICE (self), specific_object); - return ap ? nm_wifi_ap_check_compatible (ap, connection) : FALSE; + if (!ap) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "requested access point not found"); + return FALSE; + } + if (!nm_wifi_ap_check_compatible (ap, connection)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "requested access point is not compatible with profile"); + return FALSE; + } + return TRUE; } /* Ad-Hoc and AP connections are always available because they may be @@ -714,11 +716,17 @@ check_connection_available (NMDevice *device, * activating but the network isn't available let the device recheck * availability. */ - if (nm_setting_wireless_get_hidden (s_wifi) || NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP)) + if ( nm_setting_wireless_get_hidden (s_wifi) + || NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP)) return TRUE; - /* check at least one AP is compatible with this connection */ - return !!nm_wifi_aps_find_first_compatible (&priv->aps_lst_head, connection); + if (!nm_wifi_aps_find_first_compatible (&priv->aps_lst_head, connection)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "no compatible access point found"); + return FALSE; + } + + return TRUE; } static gboolean @@ -3311,9 +3319,7 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_WIRELESS_SETTING_NAME, NM_LINK_TYPE_WIFI) + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); object_class->constructed = constructed; object_class->get_property = get_property; @@ -3323,29 +3329,33 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&nm_interface_info_device_wireless); - parent_class->can_auto_connect = can_auto_connect; - parent_class->get_autoconnect_allowed = get_autoconnect_allowed; - parent_class->is_available = is_available; - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->check_connection_available = check_connection_available; - parent_class->complete_connection = complete_connection; - parent_class->get_enabled = get_enabled; - parent_class->set_enabled = set_enabled; - - parent_class->act_stage1_prepare = act_stage1_prepare; - parent_class->act_stage2_config = act_stage2_config; - parent_class->get_configured_mtu = get_configured_mtu; - parent_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; - parent_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; - parent_class->act_stage4_ip4_config_timeout = act_stage4_ip4_config_timeout; - parent_class->act_stage4_ip6_config_timeout = act_stage4_ip6_config_timeout; - parent_class->deactivate = deactivate; - parent_class->deactivate_reset_hw_addr = deactivate_reset_hw_addr; - parent_class->unmanaged_on_quit = unmanaged_on_quit; - parent_class->can_reapply_change = can_reapply_change; - parent_class->reapply_connection = reapply_connection; - - parent_class->state_changed = device_state_changed; + device_class->connection_type_supported = NM_SETTING_WIRELESS_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_WIRELESS_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_WIFI); + + device_class->can_auto_connect = can_auto_connect; + device_class->get_autoconnect_allowed = get_autoconnect_allowed; + device_class->is_available = is_available; + device_class->check_connection_compatible = check_connection_compatible; + device_class->check_connection_available = check_connection_available; + device_class->complete_connection = complete_connection; + device_class->get_enabled = get_enabled; + device_class->set_enabled = set_enabled; + + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->act_stage2_config = act_stage2_config; + device_class->get_configured_mtu = get_configured_mtu; + device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; + device_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; + device_class->act_stage4_ip4_config_timeout = act_stage4_ip4_config_timeout; + device_class->act_stage4_ip6_config_timeout = act_stage4_ip6_config_timeout; + device_class->deactivate = deactivate; + device_class->deactivate_reset_hw_addr = deactivate_reset_hw_addr; + device_class->unmanaged_on_quit = unmanaged_on_quit; + device_class->can_reapply_change = can_reapply_change; + device_class->reapply_connection = reapply_connection; + + device_class->state_changed = device_state_changed; klass->scanning_prohibited = scanning_prohibited; diff --git a/src/devices/wwan/nm-device-modem.c b/src/devices/wwan/nm-device-modem.c index 352b1c3e8b..4119d5987a 100644 --- a/src/devices/wwan/nm-device-modem.c +++ b/src/devices/wwan/nm-device-modem.c @@ -397,34 +397,67 @@ get_type_description (NMDevice *device) } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { - if (!NM_DEVICE_CLASS (nm_device_modem_parent_class)->check_connection_compatible (device, connection)) + GError *local = NULL; + + if (!NM_DEVICE_CLASS (nm_device_modem_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; - return nm_modem_check_connection_compatible (NM_DEVICE_MODEM_GET_PRIVATE ((NMDeviceModem *) device)->modem, connection); + if (!nm_modem_check_connection_compatible (NM_DEVICE_MODEM_GET_PRIVATE ((NMDeviceModem *) device)->modem, + connection, + error ? &local : NULL)) { + if (error) { + g_set_error (error, + NM_UTILS_ERROR, + g_error_matches (local, NM_UTILS_ERROR, NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE) + ? NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE + : NM_UTILS_ERROR_UNKNOWN, + "modem is incompatible with connection: %s", + local->message); + g_error_free (local); + } + return FALSE; + } + return TRUE; } static gboolean check_connection_available (NMDevice *device, NMConnection *connection, NMDeviceCheckConAvailableFlags flags, - const char *specific_object) + const char *specific_object, + GError **error) { NMDeviceModem *self = NM_DEVICE_MODEM (device); NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (self); NMModemState state; - if (!priv->rf_enabled || !priv->modem) + if (!priv->rf_enabled) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "RFKILL for modem enabled"); return FALSE; + } + + if (!priv->modem) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "modem not available"); + return FALSE; + } state = nm_modem_get_state (priv->modem); - if (state <= NM_MODEM_STATE_INITIALIZING) + if (state <= NM_MODEM_STATE_INITIALIZING) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "modem not initalized"); return FALSE; + } if (state == NM_MODEM_STATE_LOCKED) { - if (!nm_connection_get_setting_gsm (connection)) + if (!nm_connection_get_setting_gsm (connection)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "modem is locked without pin available"); return FALSE; + } } return TRUE; diff --git a/src/devices/wwan/nm-modem-broadband.c b/src/devices/wwan/nm-modem-broadband.c index 678c92bf7e..253574d589 100644 --- a/src/devices/wwan/nm-modem-broadband.c +++ b/src/devices/wwan/nm-modem-broadband.c @@ -617,44 +617,40 @@ act_stage1_prepare (NMModem *_self, /*****************************************************************************/ static gboolean -check_connection_compatible (NMModem *_self, NMConnection *connection) +check_connection_compatible_with_modem (NMModem *_self, NMConnection *connection, GError **error) { NMModemBroadband *self = NM_MODEM_BROADBAND (_self); MMModemCapability modem_caps; - NMSettingConnection *s_con; modem_caps = mm_modem_get_current_capabilities (self->_priv.modem_iface); - s_con = nm_connection_get_setting_connection (connection); - g_assert (s_con); if (MODEM_CAPS_3GPP (modem_caps)) { - NMSettingGsm *s_gsm; - - if (!g_str_equal (nm_setting_connection_get_connection_type (s_con), - NM_SETTING_GSM_SETTING_NAME)) - return FALSE; - - s_gsm = nm_connection_get_setting_gsm (connection); - if (!s_gsm) + if (!_nm_connection_check_main_setting (connection, NM_SETTING_GSM_SETTING_NAME, error)) return FALSE; return TRUE; } if (MODEM_CAPS_3GPP2 (modem_caps)) { - NMSettingCdma *s_cdma; - - if (!g_str_equal (nm_setting_connection_get_connection_type (s_con), - NM_SETTING_CDMA_SETTING_NAME)) - return FALSE; - - s_cdma = nm_connection_get_setting_cdma (connection); - if (!s_cdma) + if (!_nm_connection_check_main_setting (connection, NM_SETTING_CDMA_SETTING_NAME, error)) return FALSE; return TRUE; } + if ( !_nm_connection_check_main_setting (connection, NM_SETTING_GSM_SETTING_NAME, NULL) + && !_nm_connection_check_main_setting (connection, NM_SETTING_CDMA_SETTING_NAME, NULL)) { + nm_utils_error_set (error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, + "connection type %s is not supported by modem", + nm_connection_get_connection_type (connection)); + return FALSE; + } + + nm_utils_error_set (error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "modem lacks capabilities for %s profile", + nm_connection_get_connection_type (connection)); return FALSE; } @@ -1476,7 +1472,7 @@ nm_modem_broadband_class_init (NMModemBroadbandClass *klass) modem_class->deactivate_cleanup = deactivate_cleanup; modem_class->set_mm_enabled = set_mm_enabled; modem_class->get_user_pass = get_user_pass; - modem_class->check_connection_compatible = check_connection_compatible; + modem_class->check_connection_compatible_with_modem = check_connection_compatible_with_modem; modem_class->complete_connection = complete_connection; modem_class->act_stage1_prepare = act_stage1_prepare; modem_class->owns_port = owns_port; diff --git a/src/devices/wwan/nm-modem-ofono.c b/src/devices/wwan/nm-modem-ofono.c index 1ced1335e8..ea66859038 100644 --- a/src/devices/wwan/nm-modem-ofono.c +++ b/src/devices/wwan/nm-modem-ofono.c @@ -279,47 +279,42 @@ deactivate_cleanup (NMModem *modem, NMDevice *device) } static gboolean -check_connection_compatible (NMModem *modem, - NMConnection *connection) +check_connection_compatible_with_modem (NMModem *modem, + NMConnection *connection, + GError **error) { NMModemOfono *self = NM_MODEM_OFONO (modem); NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE (self); - NMSettingConnection *s_con; - NMSettingGsm *s_gsm; - const char *uuid; const char *id; - s_con = nm_connection_get_setting_connection (connection); - g_assert (s_con); - - uuid = nm_connection_get_uuid (connection); - id = nm_connection_get_id (connection); - - s_gsm = nm_connection_get_setting_gsm (connection); - if (!s_gsm) + if (!_nm_connection_check_main_setting (connection, NM_SETTING_GSM_SETTING_NAME, NULL)) { + nm_utils_error_set (error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, + "connection type %s is not supported by ofono modem", + nm_connection_get_connection_type (connection)); return FALSE; + } if (!priv->imsi) { - _LOGW ("skipping %s/%s: no IMSI", uuid, id); + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "modem has no IMSI"); return FALSE; } - if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_GSM_SETTING_NAME)) { - _LOGD ("skipping %s/%s: not GSM", uuid, id); - return FALSE; - } + id = nm_connection_get_id (connection); - if (!g_strrstr (id, "/context")) { - _LOGD ("skipping %s/%s: unexpected ID", uuid, id); + if (!strstr (id, "/context")) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "the connection ID has no context"); return FALSE; } - if (!g_strrstr (id, priv->imsi)) { - _LOGD ("skipping %s/%s: ID doesn't contain IMSI", uuid, id); + if (!strstr (id, priv->imsi)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "the connection ID does not contain the IMSI"); return FALSE; } - _LOGD ("%s/%s compatible with IMSI %s", uuid, id, priv->imsi); return TRUE; } @@ -1326,7 +1321,7 @@ nm_modem_ofono_class_init (NMModemOfonoClass *klass) modem_class->disconnect = disconnect; modem_class->disconnect_finish = disconnect_finish; modem_class->deactivate_cleanup = deactivate_cleanup; - modem_class->check_connection_compatible = check_connection_compatible; + modem_class->check_connection_compatible_with_modem = check_connection_compatible_with_modem; modem_class->act_stage1_prepare = act_stage1_prepare; modem_class->static_stage3_ip4_config_start = static_stage3_ip4_config_start; diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c index 62e95cc795..59b081e980 100644 --- a/src/devices/wwan/nm-modem.c +++ b/src/devices/wwan/nm-modem.c @@ -1027,35 +1027,29 @@ nm_modem_act_stage2_config (NMModem *self, /*****************************************************************************/ gboolean -nm_modem_check_connection_compatible (NMModem *self, NMConnection *connection) +nm_modem_check_connection_compatible (NMModem *self, NMConnection *connection, GError **error) { NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); - NMSettingConnection *s_con; - s_con = nm_connection_get_setting_connection (connection); - g_assert (s_con); - - if (g_str_equal (nm_setting_connection_get_connection_type (s_con), - NM_SETTING_GSM_SETTING_NAME)) { + if (nm_streq0 (nm_connection_get_connection_type (connection), + NM_SETTING_GSM_SETTING_NAME)) { NMSettingGsm *s_gsm; const char *str; - s_gsm = nm_connection_get_setting_gsm (connection); + s_gsm = _nm_connection_check_main_setting (connection, NM_SETTING_GSM_SETTING_NAME, error); if (!s_gsm) return FALSE; str = nm_setting_gsm_get_device_id (s_gsm); if (str) { if (!priv->device_id) { - _LOGD ("%s/%s has device-id, device does not", - nm_connection_get_uuid (connection), - nm_connection_get_id (connection)); + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "GSM profile has device-id, device does not"); return FALSE; } - if (strcmp (str, priv->device_id)) { - _LOGD ("%s/%s device-id mismatch", - nm_connection_get_uuid (connection), - nm_connection_get_id (connection)); + if (!nm_streq (str, priv->device_id)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device has differing device-id than GSM profile"); return FALSE; } } @@ -1065,30 +1059,26 @@ nm_modem_check_connection_compatible (NMModem *self, NMConnection *connection) * are only compared if present on the device. */ - str = nm_setting_gsm_get_sim_id (s_gsm); - if (str && priv->sim_id) { - if (strcmp (str, priv->sim_id)) { - _LOGD ("%s/%s sim-id mismatch", - nm_connection_get_uuid (connection), - nm_connection_get_id (connection)); + if ( priv->sim_id + && (str = nm_setting_gsm_get_sim_id (s_gsm))) { + if (!nm_streq (str, priv->sim_id)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device has differing sim-id than GSM profile"); return FALSE; } } - str = nm_setting_gsm_get_sim_operator_id (s_gsm); - if (str && priv->sim_operator_id) { - if (strcmp (str, priv->sim_operator_id)) { - _LOGD ("%s/%s sim-operator-id mismatch", - nm_connection_get_uuid (connection), - nm_connection_get_id (connection)); + if ( priv->sim_operator_id + && (str = nm_setting_gsm_get_sim_operator_id (s_gsm))) { + if (!nm_streq (str, priv->sim_operator_id)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device has differing sim-operator-id than GSM profile"); return FALSE; } } } - if (NM_MODEM_GET_CLASS (self)->check_connection_compatible) - return NM_MODEM_GET_CLASS (self)->check_connection_compatible (self, connection); - return FALSE; + return NM_MODEM_GET_CLASS (self)->check_connection_compatible_with_modem (self, connection, error); } /*****************************************************************************/ diff --git a/src/devices/wwan/nm-modem.h b/src/devices/wwan/nm-modem.h index 1f05d07dae..c73745cef3 100644 --- a/src/devices/wwan/nm-modem.h +++ b/src/devices/wwan/nm-modem.h @@ -121,8 +121,9 @@ typedef struct { const char **user, const char **pass); - gboolean (*check_connection_compatible) (NMModem *modem, - NMConnection *connection); + gboolean (*check_connection_compatible_with_modem) (NMModem *modem, + NMConnection *connection, + GError **error); gboolean (*complete_connection) (NMModem *modem, NMConnection *connection, @@ -185,7 +186,9 @@ void nm_modem_get_capabilities (NMModem *self, NMDeviceModemCapabilities *modem_caps, NMDeviceModemCapabilities *current_caps); -gboolean nm_modem_check_connection_compatible (NMModem *self, NMConnection *connection); +gboolean nm_modem_check_connection_compatible (NMModem *self, + NMConnection *connection, + GError **error); gboolean nm_modem_complete_connection (NMModem *self, NMConnection *connection, diff --git a/src/nm-manager.c b/src/nm-manager.c index 37d789a0ad..630180963a 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -1290,7 +1290,7 @@ find_device_by_iface (NMManager *self, if (strcmp (nm_device_get_iface (candidate), iface)) continue; - if (connection && !nm_device_check_connection_compatible (candidate, connection)) + if (connection && !nm_device_check_connection_compatible (candidate, connection, NULL)) continue; if (slave) { if (!nm_device_is_master (candidate)) @@ -1707,7 +1707,7 @@ find_parent_device_for_connection (NMManager *self, NMConnection *connection, NM return candidate; if ( !first_compatible - && nm_device_check_connection_compatible (candidate, NM_CONNECTION (parent_connection))) + && nm_device_check_connection_compatible (candidate, NM_CONNECTION (parent_connection), NULL)) first_compatible = candidate; } @@ -1877,7 +1877,7 @@ system_create_virtual_device (NMManager *self, NMConnection *connection) /* See if there's a device that is already compatible with this connection */ c_list_for_each_entry (dev_candidate, &priv->devices_lst_head, devices_lst) { - if (nm_device_check_connection_compatible (dev_candidate, connection)) { + if (nm_device_check_connection_compatible (dev_candidate, connection, NULL)) { if (nm_device_is_real (dev_candidate)) { _LOG3D (LOGD_DEVICE, connection, "already created virtual interface name %s", iface); @@ -1933,7 +1933,7 @@ system_create_virtual_device (NMManager *self, NMConnection *connection) NMConnection *candidate = NM_CONNECTION (connections[i]); NMSettingConnection *s_con; - if (!nm_device_check_connection_compatible (device, candidate)) + if (!nm_device_check_connection_compatible (device, candidate, NULL)) continue; s_con = nm_connection_get_setting_connection (candidate); @@ -2460,7 +2460,7 @@ get_existing_connection (NMManager *self, && !active_connection_find (self, connection_checked, NULL, NM_ACTIVE_CONNECTION_STATE_ACTIVATED, NULL) - && nm_device_check_connection_compatible (device, NM_CONNECTION (connection_checked))) { + && nm_device_check_connection_compatible (device, NM_CONNECTION (connection_checked), NULL)) { if (connection) { NMConnection *const connections[] = { @@ -2498,7 +2498,7 @@ get_existing_connection (NMManager *self, NMConnection *con = NM_CONNECTION (connections[i]); if ( con != NM_CONNECTION (connection_checked) - && nm_device_check_connection_compatible (device, con)) + && nm_device_check_connection_compatible (device, con, NULL)) connections[j++] = connections[i]; } connections[j] = NULL; @@ -3236,7 +3236,8 @@ static NMDevice * nm_manager_get_best_device_for_connection (NMManager *self, NMConnection *connection, gboolean for_user_request, - GHashTable *unavailable_devices) + GHashTable *unavailable_devices, + GError **error) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMActiveConnectionState ac_state; @@ -3245,6 +3246,7 @@ nm_manager_get_best_device_for_connection (NMManager *self, NMDevice *device; NMDeviceCheckConAvailableFlags flags; gs_unref_ptrarray GPtrArray *all_ac_arr = NULL; + gs_free_error GError *local_best = NULL; flags = for_user_request ? NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST : NM_DEVICE_CHECK_CON_AVAILABLE_NONE; @@ -3254,7 +3256,7 @@ nm_manager_get_best_device_for_connection (NMManager *self, ac_device = nm_active_connection_get_device (ac); if ( ac_device && ( (unavailable_devices && g_hash_table_contains (unavailable_devices, ac_device)) - || !nm_device_check_connection_available (ac_device, connection, flags, NULL))) + || !nm_device_check_connection_available (ac_device, connection, flags, NULL, NULL))) ac_device = NULL; if (all_ac_arr) { @@ -3271,7 +3273,7 @@ nm_manager_get_best_device_for_connection (NMManager *self, if ( !ac_device2 || (unavailable_devices && g_hash_table_contains (unavailable_devices, ac_device2)) - || !nm_device_check_connection_available (ac_device2, connection, flags, NULL)) + || !nm_device_check_connection_available (ac_device2, connection, flags, NULL, NULL)) continue; ac_state2 = nm_active_connection_get_state (ac2); @@ -3319,15 +3321,53 @@ found_better: /* Pick the first device that's compatible with the connection. */ c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) { + GError *local = NULL; - if (unavailable_devices && g_hash_table_contains (unavailable_devices, device)) + if ( unavailable_devices + && g_hash_table_contains (unavailable_devices, device)) continue; - if (nm_device_check_connection_available (device, connection, flags, NULL)) + if (nm_device_check_connection_available (device, + connection, + flags, + NULL, + error ? &local : NULL)) return device; + + if (error) { + gboolean reset_error; + + if (!local_best) + reset_error = TRUE; + else if (local_best->domain != NM_UTILS_ERROR) + reset_error = (local->domain == NM_UTILS_ERROR); + else { + reset_error = ( local->domain == NM_UTILS_ERROR + && local_best->code < local->code); + } + + if (reset_error) { + g_clear_error (&local_best); + g_set_error (&local_best, + local->domain, + local->code, + "device %s not available because %s", + nm_device_get_iface (device), + local->message); + } + g_error_free (local); + } } - /* No luck. :( */ + if (error) { + if (local_best) + g_propagate_error (error, g_steal_pointer (&local_best)); + else { + nm_utils_error_set_literal (error, + NM_UTILS_ERROR_UNKNOWN, + "no suitable device found"); + } + } return NULL; } @@ -3650,7 +3690,11 @@ ensure_master_active_connection (NMManager *self, if (!is_compatible_with_slave (NM_CONNECTION (candidate), connection)) continue; - if (nm_device_check_connection_available (master_device, NM_CONNECTION (candidate), NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, NULL)) { + if (nm_device_check_connection_available (master_device, + NM_CONNECTION (candidate), + NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, + NULL, + NULL)) { master_ac = nm_manager_activate_connection (self, candidate, NULL, @@ -3686,7 +3730,11 @@ ensure_master_active_connection (NMManager *self, continue; } - if (!nm_device_check_connection_available (candidate, NM_CONNECTION (master_connection), NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, NULL)) + if (!nm_device_check_connection_available (candidate, + NM_CONNECTION (master_connection), + NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, + NULL, + NULL)) continue; if (!nm_device_is_software (candidate)) { @@ -3774,7 +3822,8 @@ find_slaves (NMManager *manager, slave_device = nm_manager_get_best_device_for_connection (manager, candidate, FALSE, - devices); + devices, + NULL); if (!slaves) { /* what we allocate is quite likely much too large. Don't bother, it is only @@ -4038,6 +4087,7 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * NMConnection *existing_connection = NULL; NMActiveConnection *master_ac = NULL; NMAuthSubject *subject; + GError *local = NULL; g_return_val_if_fail (NM_IS_MANAGER (self), FALSE); g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (active), FALSE); @@ -4071,10 +4121,13 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * } /* Final connection must be available on device */ - if (!nm_device_check_connection_available (device, applied, NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, NULL)) { + if (!nm_device_check_connection_available (device, applied, NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, NULL, &local)) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION, - "Connection '%s' is not available on the device %s at this time.", - nm_settings_connection_get_id (connection), nm_device_get_iface (device)); + "Connection '%s' is not available on device %s because %s", + nm_settings_connection_get_id (connection), + nm_device_get_iface (device), + local->message); + g_error_free (local); return FALSE; } @@ -4581,17 +4634,20 @@ validate_activation_request (NMManager *self, return NULL; } } else if (!is_vpn) { - device = nm_manager_get_best_device_for_connection (self, connection, TRUE, NULL); + gs_free_error GError *local = NULL; + + device = nm_manager_get_best_device_for_connection (self, connection, TRUE, NULL, &local); if (!device) { gs_free char *iface = NULL; /* VPN and software-device connections don't need a device yet, * but non-virtual connections do ... */ if (!nm_connection_is_virtual (connection)) { - g_set_error_literal (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "No suitable device found for this connection."); + g_set_error (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_UNKNOWN_DEVICE, + "No suitable device found for this connection (%s).", + local->message); return NULL; } diff --git a/src/nm-policy.c b/src/nm-policy.c index 07f0092a7b..4e9af023af 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -1444,7 +1444,7 @@ reset_autoconnect_all (NMPolicy *self, NMSettingsConnection *connection = connections[i]; if ( device - && !nm_device_check_connection_compatible (device, NM_CONNECTION (connection))) + && !nm_device_check_connection_compatible (device, NM_CONNECTION (connection), NULL)) continue; if (only_no_secrets) { diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index 5bb629dca2..a4d47f5346 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -1622,7 +1622,7 @@ have_connection_for_device (NMSettings *self, NMDevice *device) c_list_for_each_entry (connection, &priv->connections_lst_head, _connections_lst) { const char *ctype, *iface; - if (!nm_device_check_connection_compatible (device, NM_CONNECTION (connection))) + if (!nm_device_check_connection_compatible (device, NM_CONNECTION (connection), NULL)) continue; s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection)); |