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));