From 33a88ca566e87adce9102c3389568dfa0e200c85 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 27 Jun 2018 17:00:55 +0200 Subject: [PATCH] core: give better error reason why device is incompatible with profile Note the special error codes NM_UTILS_ERROR_CONNECTION_AVAILABLE_*. This will be used to determine, whether the profile is fundamentally incompatible with the device, or whether just some other properties mismatch. That information will be importand during a plain `nmcli connection up`, where NetworkManager searches all devices for a device to activate. If no device is found (and multiple errors happened), we want to show the error that is most likely relevant for the user. Also note, how NMDevice's check_connection_compatible() uses the new class field "device_class->connection_type_check_compatible" to simplify checks for compatible profiles. The error reason is still unused. --- libnm-core/nm-connection.c | 34 +++++++++ libnm-core/nm-core-internal.h | 4 ++ src/devices/adsl/nm-device-adsl.c | 18 ++--- src/devices/bluetooth/nm-device-bt.c | 34 ++++----- src/devices/nm-device-6lowpan.c | 20 +----- src/devices/nm-device-bond.c | 19 +---- src/devices/nm-device-bridge.c | 31 +++++--- src/devices/nm-device-dummy.c | 17 +---- src/devices/nm-device-ethernet.c | 39 ++++++---- src/devices/nm-device-generic.c | 13 ++-- src/devices/nm-device-infiniband.c | 19 +++-- src/devices/nm-device-ip-tunnel.c | 54 ++++++++++---- src/devices/nm-device-macsec.c | 17 +---- src/devices/nm-device-macvlan.c | 39 +++++++--- src/devices/nm-device-ppp.c | 20 +----- src/devices/nm-device-tun.c | 44 ++++++++---- src/devices/nm-device-vlan.c | 31 ++++---- src/devices/nm-device-vxlan.c | 88 +++++++++++++++++------ src/devices/nm-device-wpan.c | 12 ++-- src/devices/nm-device.c | 74 +++++++++++++++---- src/devices/nm-device.h | 14 +++- src/devices/ovs/nm-device-ovs-bridge.c | 17 +---- src/devices/ovs/nm-device-ovs-interface.c | 20 +++--- src/devices/ovs/nm-device-ovs-port.c | 22 +----- src/devices/team/nm-device-team.c | 19 +---- src/devices/wifi/nm-device-iwd.c | 48 +++++++------ src/devices/wifi/nm-device-olpc-mesh.c | 24 +------ src/devices/wifi/nm-device-wifi.c | 14 +--- src/devices/wwan/nm-device-modem.c | 23 +++++- src/devices/wwan/nm-modem-broadband.c | 36 +++++----- src/devices/wwan/nm-modem-ofono.c | 41 +++++------ src/devices/wwan/nm-modem.c | 50 ++++++------- src/devices/wwan/nm-modem.h | 7 +- src/nm-manager.c | 12 ++-- src/nm-policy.c | 2 +- src/settings/nm-settings.c | 2 +- 36 files changed, 525 insertions(+), 453 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/src/devices/adsl/nm-device-adsl.c b/src/devices/adsl/nm-device-adsl.c index 2f4343fd52..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; } @@ -678,6 +676,8 @@ nm_device_adsl_class_init (NMDeviceAdslClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_adsl); + device_class->connection_type_check_compatible = NM_SETTING_ADSL_SETTING_NAME; + device_class->get_generic_capabilities = get_generic_capabilities; device_class->check_connection_compatible = check_connection_compatible; diff --git a/src/devices/bluetooth/nm-device-bt.c b/src/devices/bluetooth/nm-device-bt.c index 1e51fe98df..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)) - 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)) - return FALSE; - - s_bt = nm_connection_get_setting_bluetooth (connection); - if (!s_bt) + if (!NM_DEVICE_CLASS (nm_device_bt_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; bt_type = get_connection_bt_type (connection); - if (!(bt_type & priv->capabilities)) + 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); 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; } @@ -1184,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 96cc44bd58..52dda3bf74 100644 --- a/src/devices/nm-device-6lowpan.c +++ b/src/devices/nm-device-6lowpan.c @@ -174,21 +174,6 @@ is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) return NM_DEVICE_CLASS (nm_device_6lowpan_parent_class)->is_available (device, 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, @@ -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) @@ -299,10 +285,10 @@ nm_device_6lowpan_class_init (NMDevice6LowpanClass *klass) 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->create_and_realize = create_and_realize; device_class->get_generic_capabilities = get_generic_capabilities; diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c index 28edd7e386..6e7e6ffcd1 100644 --- a/src/devices/nm-device-bond.c +++ b/src/devices/nm-device-bond.c @@ -55,23 +55,6 @@ get_generic_capabilities (NMDevice *dev) return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_IS_SOFTWARE; } -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, @@ -636,11 +619,11 @@ nm_device_bond_class_init (NMDeviceBondClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_bond); 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->check_connection_compatible = check_connection_compatible; device_class->complete_connection = complete_connection; device_class->update_connection = update_connection; diff --git a/src/devices/nm-device-bridge.c b/src/devices/nm-device-bridge.c index 3cc59c48d2..e79de95cd4 100644 --- a/src/devices/nm-device-bridge.c +++ b/src/devices/nm-device-bridge.c @@ -95,23 +95,29 @@ check_connection_available (NMDevice *device, } 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; } @@ -120,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; diff --git a/src/devices/nm-device-dummy.c b/src/devices/nm-device-dummy.c index f5c464b025..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) { @@ -176,10 +161,10 @@ nm_device_dummy_class_init (NMDeviceDummyClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_dummy); 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 f093ba0a83..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; diff --git a/src/devices/nm-device-generic.c b/src/devices/nm-device-generic.c index cdfa890a56..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; } @@ -230,6 +230,7 @@ nm_device_generic_class_init (NMDeviceGenericClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_generic); 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; diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c index c298466f24..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; + } } } @@ -375,6 +373,7 @@ nm_device_infiniband_class_init (NMDeviceInfinibandClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_infiniband); 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; diff --git a/src/devices/nm-device-ip-tunnel.c b/src/devices/nm-device-ip-tunnel.c index b7d6540490..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; + } } } @@ -1044,6 +1069,7 @@ 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, diff --git a/src/devices/nm-device-macsec.c b/src/devices/nm-device-macsec.c index 2e1f3b0974..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 @@ -849,10 +834,10 @@ nm_device_macsec_class_init (NMDeviceMacsecClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_macsec); 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->check_connection_compatible = check_connection_compatible; 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-macvlan.c b/src/devices/nm-device-macvlan.c index a0e9e06acc..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_parent_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; + } } } @@ -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) @@ -501,6 +519,7 @@ nm_device_macvlan_class_init (NMDeviceMacvlanClass *klass) 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; diff --git a/src/devices/nm-device-ppp.c b/src/devices/nm-device-ppp.c index cc12458189..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) { @@ -282,11 +264,11 @@ nm_device_ppp_class_init (NMDevicePppClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_ppp); 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->check_connection_compatible = check_connection_compatible; 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-tun.c b/src/devices/nm-device-tun.c index 4bc5d0030b..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; @@ -435,6 +452,7 @@ nm_device_tun_class_init (NMDeviceTunClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_tun); 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; diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c index 3e6bfa1bb2..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; + const char *parent; - if (!NM_DEVICE_CLASS (nm_device_vlan_parent_class)->check_connection_compatible (device, connection)) + if (!NM_DEVICE_CLASS (nm_device_vlan_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; - s_vlan = nm_connection_get_setting_vlan (connection); - if (!s_vlan) - 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_parent_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; + } } } @@ -455,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) @@ -607,6 +613,7 @@ nm_device_vlan_class_init (NMDeviceVlanClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_vlan); 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; diff --git a/src/devices/nm-device-vxlan.c b/src/devices/nm-device-vxlan.c index 93c72accae..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; } } @@ -582,6 +625,7 @@ nm_device_vxlan_class_init (NMDeviceVxlanClass *klass) 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; diff --git a/src/devices/nm-device-wpan.c b/src/devices/nm-device-wpan.c index 471197379e..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; @@ -216,6 +217,7 @@ nm_device_wpan_class_init (NMDeviceWpanClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_wpan); 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; diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 786ec8694c..33faa4bf4f 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -5420,21 +5420,43 @@ nm_device_match_parent_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; } @@ -5443,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 @@ -5455,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 @@ -13217,13 +13244,22 @@ _nm_device_check_connection_available (NMDevice *self, 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)) { - if (!nm_device_check_connection_compatible (self, connection)) { - nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, - "profile is not compatible with software device"); + 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; @@ -13271,9 +13307,17 @@ _nm_device_check_connection_available (NMDevice *self, } } - if (!nm_device_check_connection_compatible (self, connection)) { - nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, - "profile is not compatible with device"); + 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; } diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index 85197e9177..41156c1008 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -203,6 +203,11 @@ typedef struct _NMDeviceClass { const char *default_type_description; 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 @@ -534,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); diff --git a/src/devices/ovs/nm-device-ovs-bridge.c b/src/devices/ovs/nm-device-ovs-bridge.c index e55d48d677..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, @@ -153,6 +138,7 @@ 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_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; @@ -160,7 +146,6 @@ nm_device_ovs_bridge_class_init (NMDeviceOvsBridgeClass *klass) 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 e1d4eddb88..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; } @@ -202,6 +197,7 @@ nm_device_ovs_interface_class_init (NMDeviceOvsInterfaceClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_ovs_interface); 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; diff --git a/src/devices/ovs/nm-device-ovs-port.c b/src/devices/ovs/nm-device-ovs-port.c index ee2835da0d..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, @@ -199,13 +179,13 @@ 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_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 456ba225ca..899932fd4b 100644 --- a/src/devices/team/nm-device-team.c +++ b/src/devices/team/nm-device-team.c @@ -84,23 +84,6 @@ get_generic_capabilities (NMDevice *device) return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_IS_SOFTWARE; } -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, @@ -920,12 +903,12 @@ nm_device_team_class_init (NMDeviceTeamClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_team); 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->check_connection_compatible = check_connection_compatible; device_class->complete_connection = complete_connection; device_class->update_connection = update_connection; device_class->master_update_slave_connection = master_update_slave_connection; diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c index a0ccee46e8..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 (); + nm_assert (nm_utils_hwaddr_valid (mac_blacklist[i], ETH_ALEN)); + + 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; } - - if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, perm_hw_addr, -1)) - 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; @@ -1986,6 +1989,7 @@ nm_device_iwd_class_init (NMDeviceIwdClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&nm_interface_info_device_wireless); 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; diff --git a/src/devices/wifi/nm-device-olpc-mesh.c b/src/devices/wifi/nm-device-olpc-mesh.c index 3f42ff6c77..7737f19a71 100644 --- a/src/devices/wifi/nm-device-olpc-mesh.c +++ b/src/devices/wifi/nm-device-olpc-mesh.c @@ -79,28 +79,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) { @@ -524,9 +502,9 @@ nm_device_olpc_mesh_class_init (NMDeviceOlpcMeshClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_olpc_mesh); 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->check_connection_compatible = check_connection_compatible; device_class->get_autoconnect_allowed = get_autoconnect_allowed; device_class->complete_connection = complete_connection; device_class->is_available = is_available; diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index 05325613ae..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); @@ -3339,6 +3330,7 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&nm_interface_info_device_wireless); 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; diff --git a/src/devices/wwan/nm-device-modem.c b/src/devices/wwan/nm-device-modem.c index 57c4853936..4119d5987a 100644 --- a/src/devices/wwan/nm-device-modem.c +++ b/src/devices/wwan/nm-device-modem.c @@ -397,12 +397,29 @@ 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 diff --git a/src/devices/wwan/nm-modem-broadband.c b/src/devices/wwan/nm-modem-broadband.c index 6730f4315c..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_with_modem (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; } diff --git a/src/devices/wwan/nm-modem-ofono.c b/src/devices/wwan/nm-modem-ofono.c index 0e6d4022d1..ea66859038 100644 --- a/src/devices/wwan/nm-modem-ofono.c +++ b/src/devices/wwan/nm-modem-ofono.c @@ -280,46 +280,41 @@ deactivate_cleanup (NMModem *modem, NMDevice *device) static gboolean check_connection_compatible_with_modem (NMModem *modem, - NMConnection *connection) + 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); + id = nm_connection_get_id (connection); + + 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, "/context")) { - _LOGD ("skipping %s/%s: unexpected ID", 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; } - if (!g_strrstr (id, priv->imsi)) { - _LOGD ("skipping %s/%s: ID doesn't contain IMSI", uuid, id); - return FALSE; - } - - _LOGD ("%s/%s compatible with IMSI %s", uuid, id, priv->imsi); return TRUE; } diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c index 99686b34bf..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_with_modem) - return NM_MODEM_GET_CLASS (self)->check_connection_compatible_with_modem (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 62d1a66577..c73745cef3 100644 --- a/src/devices/wwan/nm-modem.h +++ b/src/devices/wwan/nm-modem.h @@ -122,7 +122,8 @@ typedef struct { const char **pass); gboolean (*check_connection_compatible_with_modem) (NMModem *modem, - NMConnection *connection); + 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 eca2153630..95799eb426 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; 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));