diff --git a/introspection/nm-device.xml b/introspection/nm-device.xml index 7aef2f35b1..71b830f108 100644 --- a/introspection/nm-device.xml +++ b/introspection/nm-device.xml @@ -648,6 +648,16 @@ A new connection activation was enqueued. + + + The device's parent changed. + + + + + The device parent's management changed. + + diff --git a/libnm-core/nm-dbus-interface.h b/libnm-core/nm-dbus-interface.h index 9bab80f354..ccc3b3a9e9 100644 --- a/libnm-core/nm-dbus-interface.h +++ b/libnm-core/nm-dbus-interface.h @@ -467,6 +467,8 @@ typedef enum { * @NM_DEVICE_STATE_REASON_MODEM_AVAILABLE: Modem now ready and available * @NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT: SIM PIN was incorrect * @NM_DEVICE_STATE_REASON_NEW_ACTIVATION: New connection activation was enqueued + * @NM_DEVICE_STATE_REASON_PARENT_CHANGED: the device's parent changed + * @NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED: the device parent's management changed * * Device state change reason codes * @@ -534,6 +536,8 @@ typedef enum { NM_DEVICE_STATE_REASON_MODEM_AVAILABLE = 58, NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT = 59, NM_DEVICE_STATE_REASON_NEW_ACTIVATION = 60, + NM_DEVICE_STATE_REASON_PARENT_CHANGED = 61, + NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED = 62, } NMDeviceStateReason; diff --git a/libnm-util/NetworkManager.h b/libnm-util/NetworkManager.h index 5a98b8e496..4fa861e88f 100644 --- a/libnm-util/NetworkManager.h +++ b/libnm-util/NetworkManager.h @@ -472,6 +472,8 @@ typedef enum { * @NM_DEVICE_STATE_REASON_MODEM_AVAILABLE: Modem now ready and available * @NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT: SIM PIN was incorrect * @NM_DEVICE_STATE_REASON_NEW_ACTIVATION: New connection activation was enqueued + * @NM_DEVICE_STATE_REASON_PARENT_CHANGED: the device's parent changed + * @NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED: the device parent's management changed * * Device state change reason codes * @@ -539,6 +541,8 @@ typedef enum { NM_DEVICE_STATE_REASON_MODEM_AVAILABLE = 58, NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT = 59, NM_DEVICE_STATE_REASON_NEW_ACTIVATION = 60, + NM_DEVICE_STATE_REASON_PARENT_CHANGED = 61, + NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED = 62, NM_DEVICE_STATE_REASON_LAST = 0xFFFF } NMDeviceStateReason; diff --git a/src/devices/adsl/nm-atm-manager.c b/src/devices/adsl/nm-atm-manager.c index 6f34c02bbd..0830f85d15 100644 --- a/src/devices/adsl/nm-atm-manager.c +++ b/src/devices/adsl/nm-atm-manager.c @@ -25,6 +25,7 @@ #include #include "nm-atm-manager.h" +#include "nm-setting-adsl.h" #include "nm-device-adsl.h" #include "nm-device-factory.h" #include "nm-logging.h" @@ -203,11 +204,9 @@ handle_uevent (GUdevClient *client, adsl_remove (self, device); } -static NMDeviceType -get_device_type (NMDeviceFactory *factory) -{ - return NM_DEVICE_TYPE_ADSL; -} +NM_DEVICE_FACTORY_DECLARE_TYPES ( + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_ADSL_SETTING_NAME) +) /*********************************************************************/ @@ -224,7 +223,7 @@ nm_atm_manager_init (NMAtmManager *self) static void device_factory_interface_init (NMDeviceFactory *factory_iface) { - factory_iface->get_device_type = get_device_type; + factory_iface->get_supported_types = get_supported_types; factory_iface->start = start; } diff --git a/src/devices/bluetooth/nm-bluez-manager.c b/src/devices/bluetooth/nm-bluez-manager.c index 6b0de9949a..2e1c46b13c 100644 --- a/src/devices/bluetooth/nm-bluez-manager.c +++ b/src/devices/bluetooth/nm-bluez-manager.c @@ -29,6 +29,7 @@ #include "nm-logging.h" #include "nm-bluez-manager.h" #include "nm-device-factory.h" +#include "nm-setting-bluetooth.h" #include "nm-bluez4-manager.h" #include "nm-bluez5-manager.h" #include "nm-bluez-device.h" @@ -36,6 +37,7 @@ #include "nm-connection-provider.h" #include "nm-device-bt.h" #include "nm-core-internal.h" +#include "nm-platform.h" typedef struct { int bluez_version; @@ -367,11 +369,10 @@ start (NMDeviceFactory *factory) check_bluez_and_try_setup (NM_BLUEZ_MANAGER (factory)); } -static NMDeviceType -get_device_type (NMDeviceFactory *factory) -{ - return NM_DEVICE_TYPE_BT; -} +NM_DEVICE_FACTORY_DECLARE_TYPES ( + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_BNEP) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_BLUETOOTH_SETTING_NAME) +) /*********************************************************************/ @@ -404,10 +405,19 @@ nm_bluez_manager_init (NMBluezManager *self) g_assert (priv->provider); } +static NMDevice * +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) +{ + g_warn_if_fail (plink->type == NM_LINK_TYPE_BNEP); + *out_ignore = TRUE; + return NULL; +} + static void device_factory_interface_init (NMDeviceFactory *factory_iface) { - factory_iface->get_device_type = get_device_type; + factory_iface->get_supported_types = get_supported_types; + factory_iface->new_link = new_link; factory_iface->start = start; } diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c index b41bd14eee..17fb12c919 100644 --- a/src/devices/nm-device-bond.c +++ b/src/devices/nm-device-bond.c @@ -553,18 +553,15 @@ nm_device_bond_class_init (NMDeviceBondClass *klass) #define NM_BOND_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_BOND_FACTORY, NMBondFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { - if (plink->type == NM_LINK_TYPE_BOND) { - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BOND, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_DRIVER, "bonding", - NM_DEVICE_TYPE_DESC, "Bond", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BOND, - NM_DEVICE_IS_MASTER, TRUE, - NULL); - } - return NULL; + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BOND, + NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_DRIVER, "bonding", + NM_DEVICE_TYPE_DESC, "Bond", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BOND, + NM_DEVICE_IS_MASTER, TRUE, + NULL); } static NMDevice * @@ -573,19 +570,17 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, NMDevice *parent, GError **error) { - const char *iface; + const char *iface = nm_connection_get_interface_name (connection); - if (!nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME)) - return NULL; + g_assert (iface); - iface = nm_connection_get_interface_name (connection); - g_return_val_if_fail (iface != NULL, NULL); - - if ( !nm_platform_bond_add (NM_PLATFORM_GET, iface) - && nm_platform_get_error (NM_PLATFORM_GET) != NM_PLATFORM_ERROR_EXISTS) { - nm_log_warn (LOGD_DEVICE | LOGD_BOND, "(%s): failed to create bonding master interface for '%s': %s", - iface, nm_connection_get_id (connection), - nm_platform_get_error_msg (NM_PLATFORM_GET)); + if ( !nm_platform_bond_add (NM_PLATFORM_GET, iface, NULL) + && nm_platform_get_error (NM_PLATFORM_GET) != NM_PLATFORM_ERROR_EXISTS) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create bond interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), + nm_platform_get_error_msg (NM_PLATFORM_GET)); return NULL; } @@ -598,7 +593,9 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, NULL); } -DEFINE_DEVICE_FACTORY_INTERNAL(BOND, Bond, bond, +NM_DEVICE_FACTORY_DEFINE_INTERNAL (BOND, Bond, bond, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_BOND) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_BOND_SETTING_NAME), factory_iface->new_link = new_link; factory_iface->create_virtual_device_for_connection = create_virtual_device_for_connection; ) diff --git a/src/devices/nm-device-bridge.c b/src/devices/nm-device-bridge.c index 0d9a76c466..221bed97bb 100644 --- a/src/devices/nm-device-bridge.c +++ b/src/devices/nm-device-bridge.c @@ -477,18 +477,15 @@ nm_device_bridge_class_init (NMDeviceBridgeClass *klass) #define NM_BRIDGE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_BRIDGE_FACTORY, NMBridgeFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { - if (plink->type == NM_LINK_TYPE_BRIDGE) { - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BRIDGE, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_DRIVER, "bridge", - NM_DEVICE_TYPE_DESC, "Bridge", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BRIDGE, - NM_DEVICE_IS_MASTER, TRUE, - NULL); - } - return NULL; + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BRIDGE, + NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_DRIVER, "bridge", + NM_DEVICE_TYPE_DESC, "Bridge", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BRIDGE, + NM_DEVICE_IS_MASTER, TRUE, + NULL); } static NMDevice * @@ -497,21 +494,15 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, NMDevice *parent, GError **error) { - const char *iface; + const char *iface = nm_connection_get_interface_name (connection); NMSettingBridge *s_bridge; const char *mac_address_str; guint8 mac_address[NM_UTILS_HWADDR_LEN_MAX]; - if (!nm_connection_is_type (connection, NM_SETTING_BRIDGE_SETTING_NAME)) - return NULL; - - g_return_val_if_fail (connection != NULL, NULL); - - iface = nm_connection_get_interface_name (connection); - g_return_val_if_fail (iface != NULL, NULL); + g_assert (iface); s_bridge = nm_connection_get_setting_bridge (connection); - g_return_val_if_fail (s_bridge, NULL); + g_assert (s_bridge); mac_address_str = nm_setting_bridge_get_mac_address (s_bridge); if (mac_address_str) { @@ -522,10 +513,13 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, if ( !nm_platform_bridge_add (NM_PLATFORM_GET, iface, mac_address_str ? mac_address : NULL, - mac_address_str ? ETH_ALEN : 0) + mac_address_str ? ETH_ALEN : 0, + NULL) && nm_platform_get_error (NM_PLATFORM_GET) != NM_PLATFORM_ERROR_EXISTS) { - nm_log_warn (LOGD_DEVICE | LOGD_BRIDGE, "(%s): failed to create bridge master interface for '%s': %s", - iface, nm_connection_get_id (connection), + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create bridge interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), nm_platform_get_error_msg (NM_PLATFORM_GET)); return NULL; } @@ -539,7 +533,9 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, NULL); } -DEFINE_DEVICE_FACTORY_INTERNAL(BRIDGE, Bridge, bridge, +NM_DEVICE_FACTORY_DEFINE_INTERNAL (BRIDGE, Bridge, bridge, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_BRIDGE) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_BRIDGE_SETTING_NAME), factory_iface->new_link = new_link; factory_iface->create_virtual_device_for_connection = create_virtual_device_for_connection; ) diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index bce1cef7f0..3337a106d4 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -99,9 +99,6 @@ typedef enum { } DcbWait; typedef struct { - char * perm_hw_addr; /* Permanent MAC address */ - char * initial_hw_addr; /* Initial MAC address (as seen when NM starts) */ - guint32 speed; Supplicant supplicant; @@ -310,66 +307,6 @@ nm_device_ethernet_init (NMDeviceEthernet *self) priv->s390_options = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); } -static void -update_permanent_hw_address (NMDevice *dev) -{ - NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev); - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); - struct ifreq req; - struct ethtool_perm_addr *epaddr = NULL; - int fd, ret, errsv; - const char *mac; - - g_return_if_fail (priv->perm_hw_addr == NULL); - - fd = socket (PF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - _LOGW (LOGD_HW, "couldn't open control socket."); - return; - } - - /* Get permanent MAC address */ - memset (&req, 0, sizeof (struct ifreq)); - strncpy (req.ifr_name, nm_device_get_iface (dev), IFNAMSIZ); - - epaddr = g_malloc0 (sizeof (struct ethtool_perm_addr) + ETH_ALEN); - epaddr->cmd = ETHTOOL_GPERMADDR; - epaddr->size = ETH_ALEN; - req.ifr_data = (void *) epaddr; - - errno = 0; - ret = ioctl (fd, SIOCETHTOOL, &req); - errsv = errno; - if ((ret < 0) || !nm_ethernet_address_is_valid (epaddr->data, ETH_ALEN)) { - _LOGD (LOGD_HW | LOGD_ETHER, "unable to read permanent MAC address (error %d)", errsv); - /* Fall back to current address */ - mac = nm_device_get_hw_address (dev); - if (mac) - nm_utils_hwaddr_aton (mac, epaddr->data, ETH_ALEN); - else - memset (epaddr->data, 0, ETH_ALEN); - } - - priv->perm_hw_addr = nm_utils_hwaddr_ntoa (epaddr->data, ETH_ALEN); - - g_free (epaddr); - close (fd); -} - -static void -update_initial_hw_address (NMDevice *dev) -{ - NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev); - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); - - /* This sets initial MAC address from current MAC address. It should only - * be called from NMDevice constructor() to really get the initial address. - */ - priv->initial_hw_addr = g_strdup (nm_device_get_hw_address (dev)); - - _LOGD (LOGD_DEVICE | LOGD_ETHER, "read initial MAC address %s", priv->initial_hw_addr); -} - static NMDeviceCapabilities get_generic_capabilities (NMDevice *device) { @@ -421,7 +358,6 @@ static gboolean check_connection_compatible (NMDevice *device, NMConnection *connection) { NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device); - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); NMSettingWired *s_wired; if (!NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->check_connection_compatible (device, connection)) @@ -438,7 +374,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) return FALSE; if (s_wired) { - const char *mac; + const char *mac, *perm_hw_addr; gboolean try_mac = TRUE; const char * const *mac_blacklist; int i; @@ -446,21 +382,25 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) if (!match_subchans (self, s_wired, &try_mac)) return FALSE; + perm_hw_addr = nm_device_get_permanent_hw_address (device); mac = nm_setting_wired_get_mac_address (s_wired); - if (try_mac && mac && !nm_utils_hwaddr_matches (mac, -1, priv->perm_hw_addr, -1)) - 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 (); + if (perm_hw_addr) { + if (try_mac && mac && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1)) 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 (); + return FALSE; + } + + if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, perm_hw_addr, -1)) + return FALSE; } - - if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, priv->perm_hw_addr, -1)) - return FALSE; - } + } else if (mac) + return FALSE; } return TRUE; @@ -1391,8 +1331,8 @@ deactivate (NMDevice *device) NM_DEVICE_ETHERNET_GET_PRIVATE (device)->last_pppoe_time = nm_utils_get_monotonic_timestamp_s (); /* Reset MAC address back to initial address */ - if (priv->initial_hw_addr) - nm_device_set_hw_addr (device, priv->initial_hw_addr, "reset", LOGD_ETHER); + if (nm_device_get_initial_hw_address (device)) + nm_device_set_hw_addr (device, nm_device_get_initial_hw_address (device), "reset", LOGD_ETHER); } static gboolean @@ -1402,10 +1342,10 @@ complete_connection (NMDevice *device, const GSList *existing_connections, GError **error) { - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device); NMSettingWired *s_wired; NMSettingPppoe *s_pppoe; const char *setting_mac; + const char *perm_hw_addr; s_pppoe = nm_connection_get_setting_pppoe (connection); @@ -1432,21 +1372,22 @@ complete_connection (NMDevice *device, nm_connection_add_setting (connection, NM_SETTING (s_wired)); } - setting_mac = nm_setting_wired_get_mac_address (s_wired); - if (setting_mac) { - /* Make sure the setting MAC (if any) matches the device's permanent MAC */ - if (!nm_utils_hwaddr_matches (setting_mac, -1, priv->perm_hw_addr, -1)) { - g_set_error_literal (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("connection does not match device")); - g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_MAC_ADDRESS); - return FALSE; - } - } else { - if (!nm_utils_hwaddr_matches (priv->perm_hw_addr, -1, NULL, ETH_ALEN)) { + perm_hw_addr = nm_device_get_permanent_hw_address (device); + if (perm_hw_addr) { + setting_mac = nm_setting_wired_get_mac_address (s_wired); + if (setting_mac) { + /* Make sure the setting MAC (if any) matches the device's permanent MAC */ + if (!nm_utils_hwaddr_matches (setting_mac, -1, perm_hw_addr, -1)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("connection does not match device")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_MAC_ADDRESS); + return FALSE; + } + } else { g_object_set (G_OBJECT (s_wired), - NM_SETTING_WIRED_MAC_ADDRESS, priv->perm_hw_addr, + NM_SETTING_WIRED_MAC_ADDRESS, perm_hw_addr, NULL); } } @@ -1515,6 +1456,7 @@ update_connection (NMDevice *device, NMConnection *connection) { NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device); NMSettingWired *s_wired = nm_connection_get_setting_wired (connection); + const char *perm_hw_addr = nm_device_get_permanent_hw_address (device); const char *mac = nm_device_get_hw_address (device); const char *mac_prop = NM_SETTING_WIRED_MAC_ADDRESS; GHashTableIter iter; @@ -1528,11 +1470,11 @@ update_connection (NMDevice *device, NMConnection *connection) /* If the device reports a permanent address, use that for the MAC address * and the current MAC, if different, is the cloned MAC. */ - if (!nm_utils_hwaddr_matches (priv->perm_hw_addr, -1, NULL, ETH_ALEN)) { - g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, priv->perm_hw_addr, NULL); + if (perm_hw_addr) { + g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, perm_hw_addr, NULL); mac_prop = NULL; - if (mac && !nm_utils_hwaddr_matches (priv->perm_hw_addr, -1, mac, -1)) + if (mac && !nm_utils_hwaddr_matches (perm_hw_addr, -1, mac, -1)) mac_prop = NM_SETTING_WIRED_CLONED_MAC_ADDRESS; } @@ -1649,8 +1591,6 @@ finalize (GObject *object) NMDeviceEthernet *self = NM_DEVICE_ETHERNET (object); NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); - g_free (priv->perm_hw_addr); - g_free (priv->initial_hw_addr); g_clear_object (&priv->supplicant.mgr); g_free (priv->subchan1); g_free (priv->subchan2); @@ -1671,7 +1611,7 @@ get_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_PERM_HW_ADDRESS: - g_value_set_string (value, priv->perm_hw_addr); + g_value_set_string (value, nm_device_get_permanent_hw_address (NM_DEVICE (object))); break; case PROP_SPEED: g_value_set_uint (value, priv->speed); @@ -1711,8 +1651,6 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) object_class->set_property = set_property; parent_class->get_generic_capabilities = get_generic_capabilities; - parent_class->update_permanent_hw_address = update_permanent_hw_address; - parent_class->update_initial_hw_address = update_initial_hw_address; parent_class->check_connection_compatible = check_connection_compatible; parent_class->complete_connection = complete_connection; parent_class->new_default_connection = new_default_connection; @@ -1755,19 +1693,18 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) #define NM_ETHERNET_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_ETHERNET_FACTORY, NMEthernetFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { - if (plink->type == NM_LINK_TYPE_ETHERNET) { - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_ETHERNET, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_TYPE_DESC, "Ethernet", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_ETHERNET, - NULL); - } - return NULL; + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_ETHERNET, + NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_TYPE_DESC, "Ethernet", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_ETHERNET, + NULL); } -DEFINE_DEVICE_FACTORY_INTERNAL(ETHERNET, Ethernet, ethernet, \ - factory_iface->new_link = new_link; \ +NM_DEVICE_FACTORY_DEFINE_INTERNAL (ETHERNET, Ethernet, ethernet, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_ETHERNET) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_PPPOE_SETTING_NAME), + factory_iface->new_link = new_link; ) diff --git a/src/devices/nm-device-factory.c b/src/devices/nm-device-factory.c index abfb8d4a67..de7e9d7312 100644 --- a/src/devices/nm-device-factory.c +++ b/src/devices/nm-device-factory.c @@ -19,8 +19,19 @@ */ #include "config.h" +#include +#include +#include +#include + +#include #include "nm-device-factory.h" +#include "nm-logging.h" +#include "nm-platform.h" + +const NMLinkType _nm_device_factory_no_default_links[] = { NM_LINK_TYPE_NONE }; +const char *_nm_device_factory_no_default_settings[] = { NULL }; enum { DEVICE_ADDED, @@ -29,21 +40,6 @@ enum { }; static guint signals[LAST_SIGNAL] = { 0 }; -static GSList *internal_types = NULL; - -void -_nm_device_factory_internal_register_type (GType factory_type) -{ - g_return_if_fail (g_slist_find (internal_types, GUINT_TO_POINTER (factory_type)) == NULL); - internal_types = g_slist_prepend (internal_types, GUINT_TO_POINTER (factory_type)); -} - -const GSList * -nm_device_factory_get_internal_factory_types (void) -{ - return internal_types; -} - gboolean nm_device_factory_emit_component_added (NMDeviceFactory *factory, GObject *component) { @@ -53,67 +49,24 @@ nm_device_factory_emit_component_added (NMDeviceFactory *factory, GObject *compo return consumed; } -static void -interface_init (gpointer g_iface) +void +nm_device_factory_get_supported_types (NMDeviceFactory *factory, + const NMLinkType **out_link_types, + const char ***out_setting_types) { - GType iface_type = G_TYPE_FROM_INTERFACE (g_iface); - static gboolean initialized = FALSE; + const NMLinkType *link_types_fallback; + const char **setting_types_fallback; - if (G_LIKELY (initialized)) - return; + g_return_if_fail (factory != NULL); - /* Signals */ - signals[DEVICE_ADDED] = g_signal_new (NM_DEVICE_FACTORY_DEVICE_ADDED, - iface_type, - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMDeviceFactory, device_added), - NULL, NULL, NULL, - G_TYPE_NONE, 1, NM_TYPE_DEVICE); + if (!out_link_types) + out_link_types = &link_types_fallback; + if (!out_setting_types) + out_setting_types = &setting_types_fallback; - signals[COMPONENT_ADDED] = g_signal_new (NM_DEVICE_FACTORY_COMPONENT_ADDED, - iface_type, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NMDeviceFactory, component_added), - g_signal_accumulator_true_handled, NULL, NULL, - G_TYPE_BOOLEAN, 1, G_TYPE_OBJECT); - - initialized = TRUE; -} - -GType -nm_device_factory_get_type (void) -{ - static GType device_factory_type = 0; - - if (!device_factory_type) { - const GTypeInfo device_factory_info = { - sizeof (NMDeviceFactory), /* class_size */ - interface_init, /* base_init */ - NULL, /* base_finalize */ - NULL, - NULL, /* class_finalize */ - NULL, /* class_data */ - 0, - 0, /* n_preallocs */ - NULL - }; - - device_factory_type = g_type_register_static (G_TYPE_INTERFACE, - "NMDeviceFactory", - &device_factory_info, - 0); - g_type_interface_add_prerequisite (device_factory_type, G_TYPE_OBJECT); - } - - return device_factory_type; -} - -NMDeviceType -nm_device_factory_get_device_type (NMDeviceFactory *factory) -{ - g_return_val_if_fail (factory != NULL, NM_DEVICE_TYPE_UNKNOWN); - - return NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_device_type (factory); + NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_supported_types (factory, + out_link_types, + out_setting_types); } void @@ -128,14 +81,41 @@ nm_device_factory_start (NMDeviceFactory *factory) NMDevice * nm_device_factory_new_link (NMDeviceFactory *factory, NMPlatformLink *plink, + gboolean *out_ignore, GError **error) { + NMDeviceFactory *interface; + const NMLinkType *link_types = NULL; + const char **setting_types = NULL; + int i; + g_return_val_if_fail (factory != NULL, NULL); g_return_val_if_fail (plink != NULL, NULL); - if (NM_DEVICE_FACTORY_GET_INTERFACE (factory)->new_link) - return NM_DEVICE_FACTORY_GET_INTERFACE (factory)->new_link (factory, plink, error); - return NULL; + /* Ensure the factory can create interfaces for this connection */ + nm_device_factory_get_supported_types (factory, &link_types, &setting_types); + for (i = 0; link_types[i] > NM_LINK_TYPE_UNKNOWN; i++) { + if (plink->type == link_types[i]) + break; + } + + if (link_types[i] == NM_LINK_TYPE_UNKNOWN) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Device factory %s does not support link type %s (%d)", + G_OBJECT_TYPE_NAME (factory), + plink->kind, plink->type); + return NULL; + } + + interface = NM_DEVICE_FACTORY_GET_INTERFACE (factory); + if (!interface->new_link) { + g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, + "Device factory %s cannot manage new devices", + G_OBJECT_TYPE_NAME (factory)); + return NULL; + } + + return interface->new_link (factory, plink, out_ignore, error); } NMDevice * @@ -145,14 +125,422 @@ nm_device_factory_create_virtual_device_for_connection (NMDeviceFactory *factory GError **error) { NMDeviceFactory *interface; + const char **setting_types = NULL; + gboolean found = FALSE; + int i; g_return_val_if_fail (factory, NULL); g_return_val_if_fail (connection, NULL); g_return_val_if_fail (!error || !*error, NULL); + /* Ensure the factory can create interfaces for this connection */ + nm_device_factory_get_supported_types (factory, NULL, &setting_types); + for (i = 0; setting_types && setting_types[i]; i++) { + if (nm_connection_is_type (connection, setting_types[i])) { + found = TRUE; + break; + } + } + + if (!found) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, + "Device factory %s does not support connection type %s", + G_OBJECT_TYPE_NAME (factory), + nm_connection_get_connection_type (connection)); + return NULL; + } + interface = NM_DEVICE_FACTORY_GET_INTERFACE (factory); - if (interface->create_virtual_device_for_connection) - return interface->create_virtual_device_for_connection (factory, connection, parent, error); + if (!interface->create_virtual_device_for_connection) { + g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, + "Device factory %s cannot create virtual devices", + G_OBJECT_TYPE_NAME (factory)); + return NULL; + } + + return interface->create_virtual_device_for_connection (factory, connection, parent, error); +} + +const char * +nm_device_factory_get_connection_parent (NMDeviceFactory *factory, + NMConnection *connection) +{ + g_return_val_if_fail (factory != NULL, NULL); + g_return_val_if_fail (connection != NULL, NULL); + + if (!nm_connection_is_virtual (connection)) + return NULL; + + if (NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_connection_parent) + return NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_connection_parent (factory, connection); return NULL; } +static char * +get_virtual_iface_name (NMDeviceFactory *factory, + NMConnection *connection, + const char *parent_iface) +{ + const char *iface; + + /* For any other virtual connection, NMSettingConnection:interface-name is + * the virtual device name. + */ + iface = nm_connection_get_interface_name (connection); + g_return_val_if_fail (iface != NULL, NULL); + return g_strdup (iface); +} + +char * +nm_device_factory_get_virtual_iface_name (NMDeviceFactory *factory, + NMConnection *connection, + const char *parent_iface) +{ + g_return_val_if_fail (factory != NULL, NULL); + g_return_val_if_fail (connection != NULL, NULL); + + if (!nm_connection_is_virtual (connection)) + return NULL; + + if (NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_virtual_iface_name) + return NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_virtual_iface_name (factory, connection, parent_iface); + return NULL; +} + +/*******************************************************************/ + +static void +default_init (NMDeviceFactory *factory_iface) +{ + factory_iface->get_virtual_iface_name = get_virtual_iface_name; + + /* Signals */ + signals[DEVICE_ADDED] = g_signal_new (NM_DEVICE_FACTORY_DEVICE_ADDED, + NM_TYPE_DEVICE_FACTORY, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMDeviceFactory, device_added), + NULL, NULL, NULL, + G_TYPE_NONE, 1, NM_TYPE_DEVICE); + + signals[COMPONENT_ADDED] = g_signal_new (NM_DEVICE_FACTORY_COMPONENT_ADDED, + NM_TYPE_DEVICE_FACTORY, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NMDeviceFactory, component_added), + g_signal_accumulator_true_handled, NULL, NULL, + G_TYPE_BOOLEAN, 1, G_TYPE_OBJECT); +} + +GType +nm_device_factory_get_type (void) +{ + static volatile gsize g_define_type_id__volatile = 0; + if (g_once_init_enter (&g_define_type_id__volatile)) { + GType g_define_type_id = + g_type_register_static_simple (G_TYPE_INTERFACE, + g_intern_static_string ("NMDeviceFactory"), + sizeof (NMDeviceFactory), + (GClassInitFunc) default_init, + 0, + (GInstanceInitFunc) NULL, + (GTypeFlags) 0); + g_type_interface_add_prerequisite (g_define_type_id, G_TYPE_OBJECT); + g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); + } + return g_define_type_id__volatile; +} + +/*******************************************************************/ + +static GSList *internal_types = NULL; +static GHashTable *factories_by_link = NULL; +static GHashTable *factories_by_setting = NULL; + +void +_nm_device_factory_internal_register_type (GType factory_type) +{ + g_return_if_fail (g_slist_find (internal_types, GUINT_TO_POINTER (factory_type)) == NULL); + internal_types = g_slist_prepend (internal_types, GUINT_TO_POINTER (factory_type)); +} + +static void __attribute__((destructor)) +_cleanup (void) +{ + g_clear_pointer (&internal_types, g_slist_free); + g_clear_pointer (&factories_by_link, g_hash_table_unref); + g_clear_pointer (&factories_by_setting, g_hash_table_unref); +} + +static NMDeviceFactory * +find_factory (const NMLinkType *needle_link_types, + const char **needle_setting_types) +{ + NMDeviceFactory *found; + guint i; + + g_return_val_if_fail (factories_by_link, NULL); + g_return_val_if_fail (factories_by_setting, NULL); + + /* NMLinkType search */ + for (i = 0; needle_link_types && needle_link_types[i] > NM_LINK_TYPE_UNKNOWN; i++) { + found = g_hash_table_lookup (factories_by_link, GUINT_TO_POINTER (needle_link_types[i])); + if (found) + return found; + } + + /* NMSetting name search */ + for (i = 0; needle_setting_types && needle_setting_types[i]; i++) { + found = g_hash_table_lookup (factories_by_setting, needle_setting_types[i]); + if (found) + return found; + } + + return NULL; +} + +NMDeviceFactory * +nm_device_factory_manager_find_factory_for_link_type (NMLinkType link_type) +{ + const NMLinkType ltypes[2] = { link_type, NM_LINK_TYPE_NONE }; + + g_assert (ltypes[0] > NM_LINK_TYPE_UNKNOWN); + return find_factory (ltypes, NULL); +} + +NMDeviceFactory * +nm_device_factory_manager_find_factory_for_connection (NMConnection *connection) +{ + const char *stypes[2] = { nm_connection_get_connection_type (connection), NULL }; + + g_assert (stypes[0]); + return find_factory (NULL, stypes); +} + +void +nm_device_factory_manager_for_each_factory (NMDeviceFactoryManagerFactoryFunc callback, + gpointer user_data) +{ + GHashTableIter iter; + NMDeviceFactory *factory; + GSList *list_iter, *list = NULL; + + g_return_if_fail (factories_by_link); + g_return_if_fail (factories_by_setting); + + g_hash_table_iter_init (&iter, factories_by_link); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &factory)) { + if (!g_slist_find (list, factory)) + list = g_slist_prepend (list, factory); + } + + g_hash_table_iter_init (&iter, factories_by_setting); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &factory)) { + if (!g_slist_find (list, factory)) + list = g_slist_prepend (list, factory); + } + + for (list_iter = list; list_iter; list_iter = list_iter->next) + callback (list_iter->data, user_data); + + g_slist_free (list); +} + +#define PLUGIN_PREFIX "libnm-device-plugin-" +#define PLUGIN_PATH_TAG "NMManager-plugin-path" + +struct read_device_factory_paths_data { + char *path; + struct stat st; +}; + +static gint +read_device_factory_paths_sort_fcn (gconstpointer a, gconstpointer b) +{ + const struct read_device_factory_paths_data *da = a; + const struct read_device_factory_paths_data *db = b; + time_t ta, tb; + + ta = MAX (da->st.st_mtime, da->st.st_ctime); + tb = MAX (db->st.st_mtime, db->st.st_ctime); + + if (ta < tb) + return 1; + if (ta > tb) + return -1; + return 0; +} + +static char** +read_device_factory_paths (void) +{ + GDir *dir; + GError *error = NULL; + const char *item; + GArray *paths; + char **result; + guint i; + + dir = g_dir_open (NMPLUGINDIR, 0, &error); + if (!dir) { + nm_log_warn (LOGD_HW, "device plugin: failed to open directory %s: %s", + NMPLUGINDIR, + (error && error->message) ? error->message : "(unknown)"); + g_clear_error (&error); + return NULL; + } + + paths = g_array_new (FALSE, FALSE, sizeof (struct read_device_factory_paths_data)); + + while ((item = g_dir_read_name (dir))) { + int errsv; + struct read_device_factory_paths_data data; + + if (!g_str_has_prefix (item, PLUGIN_PREFIX)) + continue; + if (g_str_has_suffix (item, ".la")) + continue; + + data.path = g_build_filename (NMPLUGINDIR, item, NULL); + + if (stat (data.path, &data.st) != 0) { + errsv = errno; + nm_log_warn (LOGD_HW, "device plugin: skip invalid file %s (error during stat: %s)", data.path, strerror (errsv)); + goto NEXT; + } + if (!S_ISREG (data.st.st_mode)) + goto NEXT; + if (data.st.st_uid != 0) { + nm_log_warn (LOGD_HW, "device plugin: skip invalid file %s (file must be owned by root)", data.path); + goto NEXT; + } + if (data.st.st_mode & (S_IWGRP | S_IWOTH | S_ISUID)) { + nm_log_warn (LOGD_HW, "device plugin: skip invalid file %s (invalid file permissions)", data.path); + goto NEXT; + } + + g_array_append_val (paths, data); + continue; +NEXT: + g_free (data.path); + } + g_dir_close (dir); + + /* sort filenames by modification time. */ + g_array_sort (paths, read_device_factory_paths_sort_fcn); + + result = g_new (char *, paths->len + 1); + for (i = 0; i < paths->len; i++) + result[i] = g_array_index (paths, struct read_device_factory_paths_data, i).path; + result[i] = NULL; + + g_array_free (paths, TRUE); + return result; +} + +static gboolean +_add_factory (NMDeviceFactory *factory, + gboolean check_duplicates, + const char *path, + NMDeviceFactoryManagerFactoryFunc callback, + gpointer user_data) +{ + NMDeviceFactory *found = NULL; + const NMLinkType *link_types = NULL; + const char **setting_types = NULL; + int i; + + g_return_val_if_fail (factories_by_link, FALSE); + g_return_val_if_fail (factories_by_setting, FALSE); + + nm_device_factory_get_supported_types (factory, &link_types, &setting_types); + if (check_duplicates) { + found = find_factory (link_types, setting_types); + if (found) { + nm_log_warn (LOGD_HW, "Loading device plugin failed: multiple plugins " + "for same type (using '%s' instead of '%s')", + (char *) g_object_get_data (G_OBJECT (found), PLUGIN_PATH_TAG), + path); + return FALSE; + } + } + + g_object_set_data_full (G_OBJECT (factory), PLUGIN_PATH_TAG, g_strdup (path), g_free); + for (i = 0; link_types && link_types[i] > NM_LINK_TYPE_UNKNOWN; i++) + g_hash_table_insert (factories_by_link, GUINT_TO_POINTER (link_types[i]), g_object_ref (factory)); + for (i = 0; setting_types && setting_types[i]; i++) + g_hash_table_insert (factories_by_setting, (char *) setting_types[i], g_object_ref (factory)); + + callback (factory, user_data); + + nm_log_info (LOGD_HW, "Loaded device plugin: %s (%s)", G_OBJECT_TYPE_NAME (factory), path); + return TRUE; +} + +void +nm_device_factory_manager_load_factories (NMDeviceFactoryManagerFactoryFunc callback, + gpointer user_data) +{ + NMDeviceFactory *factory; + const GSList *iter; + GError *error = NULL; + char **path, **paths; + + g_return_if_fail (factories_by_link == NULL); + g_return_if_fail (factories_by_setting == NULL); + + factories_by_link = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref); + factories_by_setting = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); + + /* Register internal factories first */ + for (iter = internal_types; iter; iter = iter->next) { + GType ftype = (GType) GPOINTER_TO_SIZE (iter->data); + + factory = (NMDeviceFactory *) g_object_new (ftype, NULL); + g_assert (factory); + _add_factory (factory, FALSE, "internal", callback, user_data); + } + + paths = read_device_factory_paths (); + if (!paths) + return; + + for (path = paths; *path; path++) { + GModule *plugin; + NMDeviceFactoryCreateFunc create_func; + const char *item; + + item = strrchr (*path, '/'); + g_assert (item); + + plugin = g_module_open (*path, G_MODULE_BIND_LOCAL); + + if (!plugin) { + nm_log_warn (LOGD_HW, "(%s): failed to load plugin: %s", item, g_module_error ()); + continue; + } + + if (!g_module_symbol (plugin, "nm_device_factory_create", (gpointer) &create_func)) { + nm_log_warn (LOGD_HW, "(%s): failed to find device factory creator: %s", item, g_module_error ()); + g_module_close (plugin); + continue; + } + + factory = create_func (&error); + if (!factory) { + nm_log_warn (LOGD_HW, "(%s): failed to initialize device factory: %s", + item, error ? error->message : "unknown"); + g_clear_error (&error); + g_module_close (plugin); + continue; + } + g_clear_error (&error); + + if (_add_factory (factory, TRUE, g_module_name (plugin), callback, user_data)) + g_module_make_resident (plugin); + else + g_module_close (plugin); + + g_object_unref (factory); + } + g_strfreev (paths); +} + diff --git a/src/devices/nm-device-factory.h b/src/devices/nm-device-factory.h index ce672b8bfb..34c056d20f 100644 --- a/src/devices/nm-device-factory.h +++ b/src/devices/nm-device-factory.h @@ -66,14 +66,19 @@ struct _NMDeviceFactory { GTypeInterface g_iface; /** - * get_device_type: + * get_supported_types: * @factory: the #NMDeviceFactory + * @out_link_types: on return, a %NM_LINK_TYPE_NONE terminated + * list of #NMLinkType that the plugin supports + * @out_setting_types: on return, a %NULL terminated list of + * base-type #NMSetting names that the plugin can create devices for * - * This function MUST be implemented. - * - * Returns: the #NMDeviceType that this plugin creates + * Returns the #NMLinkType and #NMSetting names that this plugin + * supports. This function MUST be implemented. */ - NMDeviceType (*get_device_type) (NMDeviceFactory *factory); + void (*get_supported_types) (NMDeviceFactory *factory, + const NMLinkType **out_link_types, + const char ***out_setting_types); /** * start: @@ -87,20 +92,27 @@ struct _NMDeviceFactory { /** * new_link: * @factory: the #NMDeviceFactory - * @link: the new link + * @plink: the new link + * @out_ignore: on return, %TRUE if the link should be ignored * @error: error if the link could be claimed but an error occurred * * The NetworkManager core was notified of a new link which the plugin * may want to claim and create a #NMDevice subclass for. If the link - * represents a device the factory is capable of claiming, but the device - * could not be created, %NULL should be returned and @error should be set. - * %NULL should always be returned and @error should never be set if the - * factory cannot create devices for the type which @link represents. + * represents a device which the factory does not support, or the link + * is supported but the device could not be created, %NULL should be + * returned and @error should be set. + * + * If the plugin cannot create a #NMDevice for the link and wants the + * core to ignore it, set @out_ignore to %TRUE and return no error. + * + * @plink is guaranteed to be one of the types the factory returns in + * get_supported_types(). * * Returns: the #NMDevice if the link was claimed and created, %NULL if not */ NMDevice * (*new_link) (NMDeviceFactory *factory, NMPlatformLink *plink, + gboolean *out_ignore, GError **error); /** @@ -121,6 +133,34 @@ struct _NMDeviceFactory { NMDevice *parent, GError **error); + /** + * get_connection_parent: + * @factory: the #NMDeviceFactory + * @connection: the #NMConnection to return the parent name for, if supported + * + * Given a connection, returns the a parent interface name, parent connection + * UUID, or parent device hardware address for @connection. + * + * Returns: the parent interface name, parent connection UUID, parent + * device hardware address, or %NULL + */ + const char * (*get_connection_parent) (NMDeviceFactory *factory, + NMConnection *connection); + + /** + * get_virtual_iface_name: + * @factory: the #NMDeviceFactory + * @connection: the #NMConnection to return the virtual interface name for + * @parent_iface: parent interface name + * + * Given a connection, returns the interface name that a device activating + * that connection would have. + * + * Returns: the interface name, or %NULL + */ + char * (*get_virtual_iface_name) (NMDeviceFactory *factory, + NMConnection *connection, + const char *parent_iface); /* Signals */ @@ -151,12 +191,22 @@ struct _NMDeviceFactory { GType nm_device_factory_get_type (void); -NMDeviceType nm_device_factory_get_device_type (NMDeviceFactory *factory); +void nm_device_factory_get_supported_types (NMDeviceFactory *factory, + const NMLinkType **out_link_types, + const char ***out_setting_types); + +const char *nm_device_factory_get_connection_parent (NMDeviceFactory *factory, + NMConnection *connection); + +char * nm_device_factory_get_virtual_iface_name (NMDeviceFactory *factory, + NMConnection *connection, + const char *parent_iface); void nm_device_factory_start (NMDeviceFactory *factory); NMDevice * nm_device_factory_new_link (NMDeviceFactory *factory, NMPlatformLink *plink, + gboolean *out_ignore, GError **error); NMDevice * nm_device_factory_create_virtual_device_for_connection (NMDeviceFactory *factory, @@ -168,15 +218,33 @@ NMDevice * nm_device_factory_create_virtual_device_for_connection (NMDeviceFacto gboolean nm_device_factory_emit_component_added (NMDeviceFactory *factory, GObject *component); +#define NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(...) \ + { static const NMLinkType _df_links[] = { __VA_ARGS__, NM_LINK_TYPE_NONE }; *out_link_types = _df_links; } +#define NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(...) \ + { static const char *_df_settings[] = { __VA_ARGS__, NULL }; *out_setting_types = _df_settings; } + +extern const NMLinkType _nm_device_factory_no_default_links[]; +extern const char *_nm_device_factory_no_default_settings[]; + +#define NM_DEVICE_FACTORY_DECLARE_TYPES(...) \ + static void \ + get_supported_types (NMDeviceFactory *factory, \ + const NMLinkType **out_link_types, \ + const char ***out_setting_types) \ + { \ + *out_link_types = _nm_device_factory_no_default_links; \ + *out_setting_types = _nm_device_factory_no_default_settings; \ + \ + { __VA_ARGS__; } \ + } \ + \ + /************************************************************************** * INTERNAL DEVICE FACTORY FUNCTIONS - devices provided by plugins should * not use these functions. **************************************************************************/ -#define DEFINE_DEVICE_FACTORY_INTERNAL(upper, mixed, lower, dfi_code) \ - DEFINE_DEVICE_FACTORY_INTERNAL_WITH_DEVTYPE(upper, mixed, lower, upper, dfi_code) - -#define DEFINE_DEVICE_FACTORY_INTERNAL_WITH_DEVTYPE(upper, mixed, lower, devtype, dfi_code) \ +#define NM_DEVICE_FACTORY_DEFINE_INTERNAL(upper, mixed, lower, st_code, dfi_code) \ typedef GObject NM##mixed##Factory; \ typedef GObjectClass NM##mixed##FactoryClass; \ \ @@ -198,16 +266,12 @@ gboolean nm_device_factory_emit_component_added (NMDeviceFactory *factory, g_type_ensure (NM_TYPE_##upper##_FACTORY); \ } \ \ - static NMDeviceType \ - get_device_type (NMDeviceFactory *factory) \ - { \ - return NM_DEVICE_TYPE_##devtype; \ - } \ + NM_DEVICE_FACTORY_DECLARE_TYPES(st_code) \ \ static void \ device_factory_interface_init (NMDeviceFactory *factory_iface) \ { \ - factory_iface->get_device_type = get_device_type; \ + factory_iface->get_supported_types = get_supported_types; \ dfi_code \ } \ \ @@ -222,6 +286,22 @@ gboolean nm_device_factory_emit_component_added (NMDeviceFactory *factory, } void _nm_device_factory_internal_register_type (GType factory_type); -const GSList *nm_device_factory_get_internal_factory_types (void); + +/************************************************************************** + * PRIVATE FACTORY FUNCTIONS - for factory consumers (eg, NMManager). + **************************************************************************/ + +typedef void (*NMDeviceFactoryManagerFactoryFunc) (NMDeviceFactory *factory, + gpointer user_data); + +void nm_device_factory_manager_load_factories (NMDeviceFactoryManagerFactoryFunc callback, + gpointer user_data); + +NMDeviceFactory * nm_device_factory_manager_find_factory_for_link_type (NMLinkType link_type); + +NMDeviceFactory * nm_device_factory_manager_find_factory_for_connection (NMConnection *connection); + +void nm_device_factory_manager_for_each_factory (NMDeviceFactoryManagerFactoryFunc callback, + gpointer user_data); #endif /* __NETWORKMANAGER_DEVICE_FACTORY_H__ */ diff --git a/src/devices/nm-device-gre.c b/src/devices/nm-device-gre.c index 6313bfd714..b3510d2e25 100644 --- a/src/devices/nm-device-gre.c +++ b/src/devices/nm-device-gre.c @@ -267,19 +267,17 @@ nm_device_gre_class_init (NMDeviceGreClass *klass) #define NM_GRE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_GRE_FACTORY, NMGreFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { - if (plink->type == NM_LINK_TYPE_GRE || plink->type == NM_LINK_TYPE_GRETAP) { - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_GRE, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_TYPE_DESC, "Gre", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC, - NULL); - } - return NULL; + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_GRE, + NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_TYPE_DESC, "Gre", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC, + NULL); } -DEFINE_DEVICE_FACTORY_INTERNAL_WITH_DEVTYPE(GRE, Gre, gre, ETHERNET, \ - factory_iface->new_link = new_link; \ +NM_DEVICE_FACTORY_DEFINE_INTERNAL (GRE, Gre, gre, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_GRE, NM_LINK_TYPE_GRETAP), + factory_iface->new_link = new_link; ) diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c index 0a3b17c708..5e89660e7d 100644 --- a/src/devices/nm-device-infiniband.c +++ b/src/devices/nm-device-infiniband.c @@ -293,16 +293,13 @@ nm_device_infiniband_class_init (NMDeviceInfinibandClass *klass) #define NM_INFINIBAND_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_INFINIBAND_FACTORY, NMInfinibandFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { - if (plink->type == NM_LINK_TYPE_INFINIBAND) { - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_INFINIBAND, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_TYPE_DESC, "InfiniBand", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_INFINIBAND, - NULL); - } - return NULL; + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_INFINIBAND, + NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_TYPE_DESC, "InfiniBand", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_INFINIBAND, + NULL); } static NMDevice * @@ -315,23 +312,27 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, int p_key, parent_ifindex; const char *iface; - if (!nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME)) + if (!NM_IS_DEVICE_INFINIBAND (parent)) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Parent interface %s must be an InfiniBand interface", + nm_device_get_iface (parent)); return NULL; - - g_return_val_if_fail (NM_IS_DEVICE_INFINIBAND (parent), NULL); + } s_infiniband = nm_connection_get_setting_infiniband (connection); iface = nm_setting_infiniband_get_virtual_interface_name (s_infiniband); - g_return_val_if_fail (iface != NULL, NULL); + g_assert (iface); parent_ifindex = nm_device_get_ifindex (parent); p_key = nm_setting_infiniband_get_p_key (s_infiniband); - if ( !nm_platform_infiniband_partition_add (NM_PLATFORM_GET, parent_ifindex, p_key) + if ( !nm_platform_infiniband_partition_add (NM_PLATFORM_GET, parent_ifindex, p_key, NULL) && nm_platform_get_error (NM_PLATFORM_GET) != NM_PLATFORM_ERROR_EXISTS) { - nm_log_warn (LOGD_DEVICE | LOGD_INFINIBAND, "(%s): failed to add InfiniBand P_Key interface for '%s': %s", - iface, nm_connection_get_id (connection), + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create InfiniBand P_Key interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), nm_platform_get_error_msg (NM_PLATFORM_GET)); return NULL; } @@ -344,8 +345,42 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, NULL); } -DEFINE_DEVICE_FACTORY_INTERNAL(INFINIBAND, Infiniband, infiniband, \ - factory_iface->new_link = new_link; \ +static const char * +get_connection_parent (NMDeviceFactory *factory, NMConnection *connection) +{ + NMSettingInfiniband *s_infiniband; + + g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME), NULL); + + s_infiniband = nm_connection_get_setting_infiniband (connection); + g_assert (s_infiniband); + + return nm_setting_infiniband_get_parent (s_infiniband); +} + +static char * +get_virtual_iface_name (NMDeviceFactory *factory, + NMConnection *connection, + const char *parent_iface) +{ + NMSettingInfiniband *s_infiniband; + + g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME), NULL); + + s_infiniband = nm_connection_get_setting_infiniband (connection); + g_assert (s_infiniband); + + g_return_val_if_fail (g_strcmp0 (parent_iface, nm_setting_infiniband_get_parent (s_infiniband)) == 0, NULL); + + return g_strdup (nm_setting_infiniband_get_virtual_interface_name (s_infiniband)); +} + +NM_DEVICE_FACTORY_DEFINE_INTERNAL (INFINIBAND, Infiniband, infiniband, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_INFINIBAND) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_INFINIBAND_SETTING_NAME), + factory_iface->new_link = new_link; factory_iface->create_virtual_device_for_connection = create_virtual_device_for_connection; + factory_iface->get_connection_parent = get_connection_parent; + factory_iface->get_virtual_iface_name = get_virtual_iface_name; ) diff --git a/src/devices/nm-device-macvlan.c b/src/devices/nm-device-macvlan.c index 608e541db0..0bfe3fe9fc 100644 --- a/src/devices/nm-device-macvlan.c +++ b/src/devices/nm-device-macvlan.c @@ -175,19 +175,17 @@ nm_device_macvlan_class_init (NMDeviceMacvlanClass *klass) #define NM_MACVLAN_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MACVLAN_FACTORY, NMMacvlanFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { - if (plink->type == NM_LINK_TYPE_MACVLAN || plink->type == NM_LINK_TYPE_MACVTAP) { - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_MACVLAN, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_TYPE_DESC, "Macvlan", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC, - NULL); - } - return NULL; + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_MACVLAN, + NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_TYPE_DESC, "Macvlan", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC, + NULL); } -DEFINE_DEVICE_FACTORY_INTERNAL_WITH_DEVTYPE(MACVLAN, Macvlan, macvlan, ETHERNET, \ - factory_iface->new_link = new_link; \ +NM_DEVICE_FACTORY_DEFINE_INTERNAL (MACVLAN, Macvlan, macvlan, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_MACVLAN, NM_LINK_TYPE_MACVTAP), + factory_iface->new_link = new_link; ) diff --git a/src/devices/nm-device-tun.c b/src/devices/nm-device-tun.c index 4f4ed69b25..5aaff8b1a0 100644 --- a/src/devices/nm-device-tun.c +++ b/src/devices/nm-device-tun.c @@ -270,7 +270,7 @@ nm_device_tun_class_init (NMDeviceTunClass *klass) #define NM_TUN_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_TUN_FACTORY, NMTunFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { const char *mode = NULL; @@ -278,8 +278,10 @@ new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) mode = "tun"; else if (plink->type == NM_LINK_TYPE_TAP) mode = "tap"; - else - return NULL; + else { + g_warn_if_reached (); + mode = "unknown"; + } return (NMDevice *) g_object_new (NM_TYPE_DEVICE_TUN, NM_DEVICE_PLATFORM_DEVICE, plink, @@ -289,7 +291,8 @@ new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) NULL); } -DEFINE_DEVICE_FACTORY_INTERNAL_WITH_DEVTYPE(TUN, Tun, tun, GENERIC, \ - factory_iface->new_link = new_link; \ +NM_DEVICE_FACTORY_DEFINE_INTERNAL (TUN, Tun, tun, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_TUN, NM_LINK_TYPE_TAP), + factory_iface->new_link = new_link; ) diff --git a/src/devices/nm-device-veth.c b/src/devices/nm-device-veth.c index 7650502c2d..04f03fbbe5 100644 --- a/src/devices/nm-device-veth.c +++ b/src/devices/nm-device-veth.c @@ -177,19 +177,17 @@ nm_device_veth_class_init (NMDeviceVethClass *klass) #define NM_VETH_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VETH_FACTORY, NMVethFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { - if (plink->type == NM_LINK_TYPE_VETH) { - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_VETH, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_TYPE_DESC, "Veth", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_ETHERNET, - NULL); - } - return NULL; + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_VETH, + NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_TYPE_DESC, "Veth", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_ETHERNET, + NULL); } -DEFINE_DEVICE_FACTORY_INTERNAL_WITH_DEVTYPE(VETH, Veth, veth, ETHERNET, \ - factory_iface->new_link = new_link; \ +NM_DEVICE_FACTORY_DEFINE_INTERNAL (VETH, Veth, veth, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_VETH), + factory_iface->new_link = new_link; ) diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c index 34fa585488..fcbe402aba 100644 --- a/src/devices/nm-device-vlan.c +++ b/src/devices/nm-device-vlan.c @@ -40,6 +40,7 @@ #include "nm-device-factory.h" #include "nm-manager.h" #include "nm-core-internal.h" +#include "gsystem-local-alloc.h" #include "nm-device-vlan-glue.h" @@ -51,8 +52,6 @@ G_DEFINE_TYPE (NMDeviceVlan, nm_device_vlan, NM_TYPE_DEVICE) #define NM_DEVICE_VLAN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_VLAN, NMDeviceVlanPrivate)) typedef struct { - char *initial_hw_addr; - gboolean disposed; gboolean invalid; @@ -74,16 +73,6 @@ enum { /******************************************************************/ -static void -update_initial_hw_address (NMDevice *dev) -{ - NMDeviceVlan *self = NM_DEVICE_VLAN (dev); - NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self); - - priv->initial_hw_addr = g_strdup (nm_device_get_hw_address (dev)); - _LOGD (LOGD_DEVICE | LOGD_VLAN, "read initial MAC address %s", priv->initial_hw_addr); -} - static NMDeviceCapabilities get_generic_capabilities (NMDevice *dev) { @@ -107,6 +96,104 @@ bring_up (NMDevice *dev, gboolean *no_firmware) /******************************************************************/ +static gboolean +is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) +{ + if (!NM_DEVICE_VLAN_GET_PRIVATE (device)->parent) + return FALSE; + + return NM_DEVICE_CLASS (nm_device_vlan_parent_class)->is_available (device, flags); +} + +static void +parent_state_changed (NMDevice *parent, + NMDeviceState new_state, + NMDeviceState old_state, + NMDeviceStateReason reason, + gpointer user_data) +{ + NMDeviceVlan *self = NM_DEVICE_VLAN (user_data); + + /* We'll react to our own carrier state notifications. Ignore the parent's. */ + if (reason == NM_DEVICE_STATE_REASON_CARRIER) + return; + + nm_device_set_unmanaged (NM_DEVICE (self), NM_UNMANAGED_PARENT, !nm_device_get_managed (parent), reason); +} + +static void +nm_device_vlan_set_parent (NMDeviceVlan *self, NMDevice *parent, gboolean construct) +{ + NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self); + NMDevice *device = NM_DEVICE (self); + + if (parent == priv->parent) + return; + + if (priv->parent_state_id) { + g_signal_handler_disconnect (priv->parent, priv->parent_state_id); + priv->parent_state_id = 0; + } + g_clear_object (&priv->parent); + + if (parent) { + priv->parent = g_object_ref (parent); + priv->parent_state_id = g_signal_connect (priv->parent, + "state-changed", + G_CALLBACK (parent_state_changed), + device); + + /* Set parent-dependent unmanaged flag */ + if (construct) { + nm_device_set_initial_unmanaged_flag (device, + NM_UNMANAGED_PARENT, + !nm_device_get_managed (parent)); + } else { + nm_device_set_unmanaged (device, + NM_UNMANAGED_PARENT, + !nm_device_get_managed (parent), + NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED); + } + } + + /* Recheck availability now that the parent has changed */ + nm_device_queue_recheck_available (self, + NM_DEVICE_STATE_REASON_PARENT_CHANGED, + NM_DEVICE_STATE_REASON_PARENT_CHANGED); + g_object_notify (G_OBJECT (device), NM_DEVICE_VLAN_PARENT); +} + +static gboolean +component_added (NMDevice *device, GObject *component) +{ + NMDeviceVlan *self = NM_DEVICE_VLAN (device); + NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self); + NMDevice *added_device; + int parent_ifindex = -1; + + if (priv->parent) + return FALSE; + + if (!NM_IS_DEVICE (component)) + return FALSE; + added_device = NM_DEVICE (component); + + if (!nm_platform_vlan_get_info (NM_PLATFORM_GET, nm_device_get_ifindex (device), &parent_ifindex, NULL)) { + _LOGW (LOGD_VLAN, "failed to get VLAN interface info while checking added component."); + return FALSE; + } + + if (nm_device_get_ifindex (added_device) != parent_ifindex) + return FALSE; + + nm_device_vlan_set_parent (self, added_device, FALSE); + + /* Don't claim parent exclusively */ + return FALSE; +} + +/******************************************************************/ + static gboolean match_parent (NMDeviceVlan *self, const char *parent) { @@ -114,6 +201,9 @@ match_parent (NMDeviceVlan *self, const char *parent) g_return_val_if_fail (parent != NULL, FALSE); + if (!priv->parent) + return FALSE; + if (nm_utils_is_uuid (parent)) { NMActRequest *parent_req; NMConnection *parent_connection; @@ -239,32 +329,6 @@ complete_connection (NMDevice *device, return TRUE; } -static void parent_state_changed (NMDevice *parent, NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason, - gpointer user_data); - -static void -nm_device_vlan_set_parent (NMDeviceVlan *device, NMDevice *parent) -{ - NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (device); - - if (priv->parent_state_id) { - g_signal_handler_disconnect (priv->parent, priv->parent_state_id); - priv->parent_state_id = 0; - } - g_clear_object (&priv->parent); - - if (parent) { - priv->parent = g_object_ref (parent); - priv->parent_state_id = g_signal_connect (priv->parent, - "state-changed", - G_CALLBACK (parent_state_changed), - device); - } - g_object_notify (G_OBJECT (device), NM_DEVICE_VLAN_PARENT); -} - static void update_connection (NMDevice *device, NMConnection *connection) { @@ -296,8 +360,7 @@ update_connection (NMDevice *device, NMConnection *connection) parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex); g_assert (parent); - if (priv->parent != parent) - nm_device_vlan_set_parent (NM_DEVICE_VLAN (device), parent); + nm_device_vlan_set_parent (NM_DEVICE_VLAN (device), parent, FALSE); /* Update parent in the connection; default to parent's interface name */ new_parent = nm_device_get_iface (parent); @@ -386,30 +449,9 @@ ip4_config_pre_commit (NMDevice *device, NMIP4Config *config) static void deactivate (NMDevice *device) { - NMDeviceVlan *self = NM_DEVICE_VLAN (device); - NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self); - /* Reset MAC address back to initial address */ - if (priv->initial_hw_addr) - nm_device_set_hw_addr (device, priv->initial_hw_addr, "reset", LOGD_VLAN); -} - -/******************************************************************/ - -static void -parent_state_changed (NMDevice *parent, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason, - gpointer user_data) -{ - NMDeviceVlan *self = NM_DEVICE_VLAN (user_data); - - /* We'll react to our own carrier state notifications. Ignore the parent's. */ - if (reason == NM_DEVICE_STATE_REASON_CARRIER) - return; - - nm_device_set_unmanaged (NM_DEVICE (self), NM_UNMANAGED_PARENT, !nm_device_get_managed (parent), reason); + if (nm_device_get_initial_hw_address (device)) + nm_device_set_hw_addr (device, nm_device_get_initial_hw_address (device), "reset", LOGD_VLAN); } /******************************************************************/ @@ -431,12 +473,6 @@ constructed (GObject *object) if (G_OBJECT_CLASS (nm_device_vlan_parent_class)->constructed) G_OBJECT_CLASS (nm_device_vlan_parent_class)->constructed (object); - if (!priv->parent) { - _LOGE (LOGD_VLAN, "no parent specified."); - priv->invalid = TRUE; - return; - } - itype = nm_platform_link_get_type (NM_PLATFORM_GET, ifindex); if (itype != NM_LINK_TYPE_VLAN) { _LOGE (LOGD_VLAN, "failed to get VLAN interface type."); @@ -450,18 +486,27 @@ constructed (GObject *object) return; } - if ( parent_ifindex < 0 - || parent_ifindex != nm_device_get_ip_ifindex (priv->parent) - || vlan_id < 0) { + if (parent_ifindex < 0 || vlan_id < 0) { _LOGW (LOGD_VLAN, "VLAN parent ifindex (%d) or VLAN ID (%d) invalid.", parent_ifindex, priv->vlan_id); priv->invalid = TRUE; return; } + if (priv->parent && parent_ifindex != nm_device_get_ip_ifindex (priv->parent)) { + _LOGW (LOGD_VLAN, "VLAN parent %s (%d) and parent ifindex %d don't match.", + nm_device_get_iface (priv->parent), + nm_device_get_ifindex (priv->parent), + parent_ifindex); + priv->invalid = TRUE; + return; + } + priv->vlan_id = vlan_id; - _LOGI (LOGD_HW | LOGD_VLAN, "VLAN ID %d with parent %s", - priv->vlan_id, nm_device_get_iface (priv->parent)); + _LOGI (LOGD_HW | LOGD_VLAN, "VLAN ID %d with parent %s (%d)", + priv->vlan_id, + priv->parent ? nm_device_get_iface (priv->parent) : "unknown", + parent_ifindex); } static void @@ -494,7 +539,7 @@ set_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_INT_PARENT_DEVICE: - nm_device_vlan_set_parent (NM_DEVICE_VLAN (object), g_value_get_object (value)); + nm_device_vlan_set_parent (NM_DEVICE_VLAN (object), g_value_get_object (value), TRUE); break; case PROP_VLAN_ID: priv->vlan_id = g_value_get_uint (value); @@ -517,22 +562,11 @@ dispose (GObject *object) } priv->disposed = TRUE; - nm_device_vlan_set_parent (self, NULL); + nm_device_vlan_set_parent (self, NULL, FALSE); G_OBJECT_CLASS (nm_device_vlan_parent_class)->dispose (object); } -static void -finalize (GObject *object) -{ - NMDeviceVlan *self = NM_DEVICE_VLAN (object); - NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self); - - g_free (priv->initial_hw_addr); - - G_OBJECT_CLASS (nm_device_vlan_parent_class)->finalize (object); -} - static void nm_device_vlan_class_init (NMDeviceVlanClass *klass) { @@ -548,14 +582,14 @@ nm_device_vlan_class_init (NMDeviceVlanClass *klass) object_class->get_property = get_property; object_class->set_property = set_property; object_class->dispose = dispose; - object_class->finalize = finalize; - parent_class->update_initial_hw_address = update_initial_hw_address; parent_class->get_generic_capabilities = get_generic_capabilities; parent_class->bring_up = bring_up; parent_class->act_stage1_prepare = act_stage1_prepare; parent_class->ip4_config_pre_commit = ip4_config_pre_commit; parent_class->deactivate = deactivate; + parent_class->is_available = is_available; + parent_class->component_added = component_added; parent_class->check_connection_compatible = check_connection_compatible; parent_class->complete_connection = complete_connection; @@ -594,30 +628,18 @@ nm_device_vlan_class_init (NMDeviceVlanClass *klass) #define NM_VLAN_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VLAN_FACTORY, NMVlanFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { int parent_ifindex = -1; NMDevice *parent, *device; - if (plink->type != NM_LINK_TYPE_VLAN) - return NULL; - - /* Have to find the parent device */ + /* Find the parent device */ if (!nm_platform_vlan_get_info (NM_PLATFORM_GET, plink->ifindex, &parent_ifindex, NULL)) { - nm_log_err (LOGD_HW, "(%s): failed to get VLAN parent ifindex", plink->name); + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "VLAN parent ifindex unknown"); return NULL; } - parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex); - if (!parent) { - /* If udev signaled the VLAN interface before it signaled - * the VLAN's parent at startup we may not know about the - * parent device yet. But we'll find it on the second pass - * from nm_manager_start(). - */ - nm_log_dbg (LOGD_HW, "(%s): VLAN parent interface unknown", plink->name); - return NULL; - } device = (NMDevice *) g_object_new (NM_TYPE_DEVICE_VLAN, NM_DEVICE_PLATFORM_DEVICE, plink, @@ -627,14 +649,12 @@ new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_VLAN, NULL); if (NM_DEVICE_VLAN_GET_PRIVATE (device)->invalid) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "VLAN initialization failed"); g_object_unref (device); device = NULL; } - /* Set initial parent-dependent unmanaged flag */ - if (device) - nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_PARENT, !nm_device_get_managed (parent)); - return device; } @@ -646,15 +666,16 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, { NMDevice *device; NMSettingVlan *s_vlan; - char *iface; + gs_free char *iface = NULL; - if (!nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME)) + if (!NM_IS_DEVICE (parent)) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "VLAN interfaces must have parents"); return NULL; - - g_return_val_if_fail (NM_IS_DEVICE (parent), NULL); + } s_vlan = nm_connection_get_setting_vlan (connection); - g_return_val_if_fail (s_vlan != NULL, NULL); + g_assert (s_vlan); iface = g_strdup (nm_connection_get_interface_name (connection)); if (!iface) { @@ -666,11 +687,14 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, iface, nm_device_get_ifindex (parent), nm_setting_vlan_get_id (s_vlan), - nm_setting_vlan_get_flags (s_vlan)) + nm_setting_vlan_get_flags (s_vlan), + NULL) && nm_platform_get_error (NM_PLATFORM_GET) != NM_PLATFORM_ERROR_EXISTS) { - nm_log_warn (LOGD_DEVICE | LOGD_VLAN, "(%s) failed to add VLAN interface for '%s'", - iface, nm_connection_get_id (connection)); - g_free (iface); + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create VLAN interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), + nm_platform_get_error_msg (NM_PLATFORM_GET)); return NULL; } @@ -681,21 +705,74 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, NM_DEVICE_TYPE_DESC, "VLAN", NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_VLAN, NULL); - g_free (iface); if (NM_DEVICE_VLAN_GET_PRIVATE (device)->invalid) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create VLAN interface '%s' for '%s': initialization failed", + iface, nm_connection_get_id (connection)); g_object_unref (device); device = NULL; } - /* Set initial parent-dependent unmanaged flag */ - if (device) - nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_PARENT, !nm_device_get_managed (parent)); - return device; } -DEFINE_DEVICE_FACTORY_INTERNAL(VLAN, Vlan, vlan, \ - factory_iface->new_link = new_link; \ +static const char * +get_connection_parent (NMDeviceFactory *factory, NMConnection *connection) +{ + NMSettingVlan *s_vlan; + NMSettingWired *s_wired; + const char *parent = NULL; + + g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME), NULL); + + s_vlan = nm_connection_get_setting_vlan (connection); + g_assert (s_vlan); + + parent = nm_setting_vlan_get_parent (s_vlan); + if (parent) + return parent; + + /* Try the hardware address from the VLAN connection's hardware setting */ + s_wired = nm_connection_get_setting_wired (connection); + if (s_wired) + return nm_setting_wired_get_mac_address (s_wired); + + return NULL; +} + +static char * +get_virtual_iface_name (NMDeviceFactory *factory, + NMConnection *connection, + const char *parent_iface) +{ + const char *ifname; + NMSettingVlan *s_vlan; + + g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME), NULL); + + s_vlan = nm_connection_get_setting_vlan (connection); + g_assert (s_vlan); + + if (!parent_iface) + return NULL; + + ifname = nm_connection_get_interface_name (connection); + if (ifname) + return g_strdup (ifname); + + /* If the connection doesn't specify the interface name for the VLAN + * device, we create one for it using the VLAN ID and the parent + * interface's name. + */ + return nm_utils_new_vlan_name (parent_iface, nm_setting_vlan_get_id (s_vlan)); +} + +NM_DEVICE_FACTORY_DEFINE_INTERNAL (VLAN, Vlan, vlan, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_VLAN) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_VLAN_SETTING_NAME), + factory_iface->new_link = new_link; factory_iface->create_virtual_device_for_connection = create_virtual_device_for_connection; + factory_iface->get_connection_parent = get_connection_parent; + factory_iface->get_virtual_iface_name = get_virtual_iface_name; ) diff --git a/src/devices/nm-device-vxlan.c b/src/devices/nm-device-vxlan.c index 25ee804dfa..7811934d2a 100644 --- a/src/devices/nm-device-vxlan.c +++ b/src/devices/nm-device-vxlan.c @@ -353,19 +353,17 @@ nm_device_vxlan_class_init (NMDeviceVxlanClass *klass) #define NM_VXLAN_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VXLAN_FACTORY, NMVxlanFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { - if (plink->type == NM_LINK_TYPE_VXLAN) { - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_VXLAN, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_TYPE_DESC, "Vxlan", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC, - NULL); - } - return NULL; + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_VXLAN, + NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_TYPE_DESC, "Vxlan", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC, + NULL); } -DEFINE_DEVICE_FACTORY_INTERNAL_WITH_DEVTYPE(VXLAN, Vxlan, vxlan, GENERIC, \ - factory_iface->new_link = new_link; \ +NM_DEVICE_FACTORY_DEFINE_INTERNAL (VXLAN, Vxlan, vxlan, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_VXLAN), + factory_iface->new_link = new_link; ) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index f0ef6572e3..9bfd5b3a0b 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -28,8 +28,6 @@ #include #include #include -#include -#include #include #include #include @@ -203,6 +201,8 @@ typedef struct { GHashTable * available_connections; char * hw_addr; guint hw_addr_len; + char * perm_hw_addr; + char * initial_hw_addr; char * physical_port_id; guint dev_id; @@ -5891,14 +5891,20 @@ impl_device_delete (NMDevice *self, DBusGMethodInvocation *context) NULL); } -static void +static gboolean _device_activate (NMDevice *self, NMActRequest *req) { NMDevicePrivate *priv; NMConnection *connection; - g_return_if_fail (NM_IS_DEVICE (self)); - g_return_if_fail (NM_IS_ACT_REQUEST (req)); + g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + g_return_val_if_fail (NM_IS_ACT_REQUEST (req), FALSE); + + /* Ensure the activation request is still valid; the master may have + * already failed in which case activation of this device should not proceed. + */ + if (nm_active_connection_get_state (NM_ACTIVE_CONNECTION (req)) >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATING) + return FALSE; priv = NM_DEVICE_GET_PRIVATE (self); @@ -5924,6 +5930,7 @@ _device_activate (NMDevice *self, NMActRequest *req) priv->act_request = g_object_ref (req); nm_device_activate_schedule_stage1_device_prepare (self); + return TRUE; } static void @@ -6019,7 +6026,8 @@ nm_device_queue_activation (NMDevice *self, NMActRequest *req) if (!priv->act_request && !must_queue) { /* Just activate immediately */ - _device_activate (self, req); + if (!_device_activate (self, req)) + g_assert_not_reached (); return; } @@ -8110,13 +8118,18 @@ _set_state_full (NMDevice *self, if ( priv->queued_act_request && !priv->queued_act_request_is_waiting_for_carrier) { NMActRequest *queued_req; + gboolean success; queued_req = priv->queued_act_request; priv->queued_act_request = NULL; - _device_activate (self, queued_req); + success = _device_activate (self, queued_req); g_object_unref (queued_req); - } else if ( old_state > NM_DEVICE_STATE_DISCONNECTED - && nm_device_get_default_unmanaged (self)) + if (success) + break; + /* fall through */ + } + if ( old_state > NM_DEVICE_STATE_DISCONNECTED + && nm_device_get_default_unmanaged (self)) nm_device_queue_state (self, NM_DEVICE_STATE_UNMANAGED, NM_DEVICE_STATE_REASON_NONE); break; case NM_DEVICE_STATE_ACTIVATED: @@ -8397,6 +8410,22 @@ nm_device_set_hw_addr (NMDevice *self, const char *addr, return success; } +const char * +nm_device_get_permanent_hw_address (NMDevice *self) +{ + g_return_val_if_fail (NM_IS_DEVICE (self), NULL); + + return NM_DEVICE_GET_PRIVATE (self)->perm_hw_addr; +} + +const char * +nm_device_get_initial_hw_address (NMDevice *self) +{ + g_return_val_if_fail (NM_IS_DEVICE (self), NULL); + + return NM_DEVICE_GET_PRIVATE (self)->initial_hw_addr; +} + /** * nm_device_spec_match_list: * @self: an #NMDevice @@ -8491,46 +8520,6 @@ nm_device_init (NMDevice *self) priv->default_route.v6_is_assumed = TRUE; } -/* - * Get driver info from SIOCETHTOOL ioctl() for 'iface' - * Returns driver and firmware versions to 'driver_version and' 'firmware_version' - */ -static gboolean -device_get_driver_info (NMDevice *self, const char *iface, char **driver_version, char **firmware_version) -{ - struct ethtool_drvinfo drvinfo; - struct ifreq req; - int fd; - - fd = socket (PF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - _LOGW (LOGD_HW, "couldn't open control socket."); - return FALSE; - } - - /* Get driver and firmware version info */ - memset (&drvinfo, 0, sizeof (drvinfo)); - memset (&req, 0, sizeof (struct ifreq)); - strncpy (req.ifr_name, iface, IFNAMSIZ); - drvinfo.cmd = ETHTOOL_GDRVINFO; - req.ifr_data = &drvinfo; - - errno = 0; - if (ioctl (fd, SIOCETHTOOL, &req) < 0) { - _LOGD (LOGD_HW, "SIOCETHTOOL ioctl() failed: cmd=ETHTOOL_GDRVINFO, iface=%s, errno=%d", - iface, errno); - close (fd); - return FALSE; - } - if (driver_version) - *driver_version = g_strdup (drvinfo.version); - if (firmware_version) - *firmware_version = g_strdup (drvinfo.fw_version); - - close (fd); - return TRUE; -} - static GObject* constructor (GType type, guint n_construct_params, @@ -8566,10 +8555,13 @@ constructor (GType type, if (NM_DEVICE_GET_CLASS (self)->get_generic_capabilities) priv->capabilities |= NM_DEVICE_GET_CLASS (self)->get_generic_capabilities (self); - if (priv->ifindex <= 0 && !nm_device_has_capability (self, NM_DEVICE_CAP_IS_NON_KERNEL)) - _LOGW (LOGD_HW, "failed to look up interface index"); - - device_get_driver_info (self, priv->iface, &priv->driver_version, &priv->firmware_version); + if (priv->ifindex > 0) { + nm_platform_link_get_driver_info (NM_PLATFORM_GET, + priv->ifindex, + NULL, + &priv->driver_version, + &priv->firmware_version); + } /* Watch for external IP config changes */ platform = nm_platform_get (); @@ -8605,13 +8597,29 @@ constructed (GObject *object) nm_device_update_hw_address (self); - if (NM_DEVICE_GET_CLASS (self)->update_permanent_hw_address) - NM_DEVICE_GET_CLASS (self)->update_permanent_hw_address (self); + if (priv->hw_addr_len) { + priv->initial_hw_addr = g_strdup (priv->hw_addr); + _LOGD (LOGD_DEVICE | LOGD_HW, "read initial MAC address %s", priv->initial_hw_addr); - if (NM_DEVICE_GET_CLASS (self)->update_initial_hw_address) - NM_DEVICE_GET_CLASS (self)->update_initial_hw_address (self); + if (priv->ifindex > 0) { + guint8 buf[NM_UTILS_HWADDR_LEN_MAX]; + size_t len = 0; - /* Have to call update_initial_hw_address() before calling get_ignore_carrier() */ + if (nm_platform_link_get_permanent_address (NM_PLATFORM_GET, priv->ifindex, buf, &len)) { + g_warn_if_fail (len == priv->hw_addr_len); + priv->perm_hw_addr = nm_utils_hwaddr_ntoa (buf, priv->hw_addr_len); + _LOGD (LOGD_DEVICE | LOGD_HW, "read permanent MAC address %s", + priv->perm_hw_addr); + } else { + /* Fall back to current address */ + _LOGD (LOGD_HW | LOGD_ETHER, "unable to read permanent MAC address (error %d)", + nm_platform_get_error (NM_PLATFORM_GET)); + priv->perm_hw_addr = g_strdup (priv->hw_addr); + } + } + } + + /* Note: initial hardware address must be read before calling get_ignore_carrier() */ if (nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) { NMConfig *config = nm_config_get (); @@ -8744,6 +8752,8 @@ finalize (GObject *object) _LOGD (LOGD_DEVICE, "finalize(): %s", G_OBJECT_TYPE_NAME (self)); g_free (priv->hw_addr); + g_free (priv->perm_hw_addr); + g_free (priv->initial_hw_addr); g_slist_free_full (priv->pending_actions, g_free); g_clear_pointer (&priv->physical_port_id, g_free); g_free (priv->udi); diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index f7ba2a5296..218faa4fa1 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -139,9 +139,6 @@ typedef struct { /* Carrier state (IFF_LOWER_UP) */ void (*carrier_changed) (NMDevice *, gboolean carrier); - void (* update_permanent_hw_address) (NMDevice *self); - void (* update_initial_hw_address) (NMDevice *self); - gboolean (* get_ip_iface_identifier) (NMDevice *self, NMUtilsIPv6IfaceId *out_iid); NMDeviceCapabilities (* get_generic_capabilities) (NMDevice *self); @@ -237,6 +234,21 @@ typedef struct { gboolean (* have_any_ready_slaves) (NMDevice *self, const GSList *slaves); + /** + * component_added: + * @self: the #NMDevice + * @component: the component (device, modem, etc) which was added + * + * Notifies @self that a new component was added to the Manager. This + * may include any kind of %GObject subclass, and the device is expected + * to match only specific components they care about, like %NMModem objects + * or %NMDevice objects. + * + * Returns: %TRUE if the component was claimed exclusively and no further + * devices should be notified of the new component. %FALSE to indicate + * that the component was not exclusively claimed and other devices should + * be notified. + */ gboolean (* component_added) (NMDevice *self, GObject *component); gboolean (* owns_iface) (NMDevice *self, const char *iface); @@ -272,7 +284,9 @@ int nm_device_get_priority (NMDevice *dev); guint32 nm_device_get_ip4_route_metric (NMDevice *dev); guint32 nm_device_get_ip6_route_metric (NMDevice *dev); -const char * nm_device_get_hw_address (NMDevice *dev); +const char * nm_device_get_hw_address (NMDevice *dev); +const char * nm_device_get_permanent_hw_address (NMDevice *dev); +const char * nm_device_get_initial_hw_address (NMDevice *dev); NMDhcp4Config * nm_device_get_dhcp4_config (NMDevice *dev); NMDhcp6Config * nm_device_get_dhcp6_config (NMDevice *dev); diff --git a/src/devices/team/nm-device-team.c b/src/devices/team/nm-device-team.c index 6b58014393..1f80d543c4 100644 --- a/src/devices/team/nm-device-team.c +++ b/src/devices/team/nm-device-team.c @@ -676,8 +676,6 @@ release_slave (NMDevice *device, NMDevice * nm_device_team_new (NMPlatformLink *platform_device) { - g_return_val_if_fail (platform_device != NULL, NULL); - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_TEAM, NM_DEVICE_PLATFORM_DEVICE, platform_device, NM_DEVICE_DRIVER, "team", @@ -690,20 +688,16 @@ nm_device_team_new (NMPlatformLink *platform_device) NMDevice * nm_device_team_new_for_connection (NMConnection *connection, GError **error) { - const char *iface; + const char *iface = nm_connection_get_interface_name (connection); - g_return_val_if_fail (connection != NULL, NULL); + g_assert (iface); - iface = nm_connection_get_interface_name (connection); - g_return_val_if_fail (iface != NULL, NULL); - - if ( !nm_platform_team_add (NM_PLATFORM_GET, iface) + if ( !nm_platform_team_add (NM_PLATFORM_GET, iface, NULL) && nm_platform_get_error (NM_PLATFORM_GET) != NM_PLATFORM_ERROR_EXISTS) { - g_set_error (error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_CREATION_FAILED, - "failed to create team master interface '%s' for connection '%s': %s", - iface, nm_connection_get_id (connection), + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create team master interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), nm_platform_get_error_msg (NM_PLATFORM_GET)); return NULL; } diff --git a/src/devices/team/nm-team-factory.c b/src/devices/team/nm-team-factory.c index cb887cac24..d87919b6b7 100644 --- a/src/devices/team/nm-team-factory.c +++ b/src/devices/team/nm-team-factory.c @@ -48,11 +48,9 @@ nm_device_factory_create (GError **error) /************************************************************************/ static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { - if (plink->type == NM_LINK_TYPE_TEAM) - return nm_device_team_new (plink); - return NULL; + return nm_device_team_new (plink); } static NMDevice * @@ -61,16 +59,13 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, NMDevice *parent, GError **error) { - if (nm_connection_is_type (connection, NM_SETTING_TEAM_SETTING_NAME)) - return nm_device_team_new_for_connection (connection, error); - return NULL; + return nm_device_team_new_for_connection (connection, error); } -static NMDeviceType -get_device_type (NMDeviceFactory *factory) -{ - return NM_DEVICE_TYPE_TEAM; -} +NM_DEVICE_FACTORY_DECLARE_TYPES ( + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_TEAM) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_TEAM_SETTING_NAME) +) /************************************************************************/ @@ -84,7 +79,7 @@ device_factory_interface_init (NMDeviceFactory *factory_iface) { factory_iface->new_link = new_link; factory_iface->create_virtual_device_for_connection = create_virtual_device_for_connection; - factory_iface->get_device_type = get_device_type; + factory_iface->get_supported_types = get_supported_types; } static void diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index cc4db66628..500fa3aade 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -26,13 +26,7 @@ #include #include #include -#include -#include -#include #include -#include -#include -#include #include #include "nm-glib-compat.h" @@ -117,9 +111,6 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; struct _NMDeviceWifiPrivate { - char * perm_hw_addr; /* Permanent MAC address */ - char * initial_hw_addr; /* Initial MAC address (as seen when NM starts) */ - gint8 invalid_strength_counter; GHashTable * aps; @@ -533,8 +524,8 @@ deactivate (NMDevice *device) nm_platform_wifi_indicate_addressing_running (NM_PLATFORM_GET, ifindex, FALSE); /* Reset MAC address back to initial address */ - if (priv->initial_hw_addr) - nm_device_set_hw_addr (device, priv->initial_hw_addr, "reset", LOGD_WIFI); + if (nm_device_get_initial_hw_address (device)) + nm_device_set_hw_addr (device, nm_device_get_initial_hw_address (device), "reset", LOGD_WIFI); nm_platform_wifi_set_powersave (NM_PLATFORM_GET, ifindex, 0); @@ -600,6 +591,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) const char * const *mac_blacklist; int i; const char *mode; + const char *perm_hw_addr; if (!NM_DEVICE_CLASS (nm_device_wifi_parent_class)->check_connection_compatible (device, connection)) return FALSE; @@ -614,21 +606,25 @@ check_connection_compatible (NMDevice *device, NMConnection *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 (mac && !nm_utils_hwaddr_matches (mac, -1, priv->perm_hw_addr, -1)) - 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 (); + if (perm_hw_addr) { + if (mac && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1)) return FALSE; + + /* Check for MAC address blacklist */ + mac_blacklist = nm_setting_wireless_get_mac_address_blacklist (s_wireless); + for (i = 0; mac_blacklist[i]; i++) { + if (!nm_utils_hwaddr_valid (mac_blacklist[i], ETH_ALEN)) { + g_warn_if_reached (); + return FALSE; + } + + if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, perm_hw_addr, -1)) + return FALSE; } - - if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, priv->perm_hw_addr, -1)) - return FALSE; - } + } else if (mac) + return FALSE; if (is_adhoc_wpa (connection)) return FALSE; @@ -767,7 +763,6 @@ complete_connection (NMDevice *device, GError **error) { NMDeviceWifi *self = NM_DEVICE_WIFI (device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); NMSettingWireless *s_wifi; NMSettingWirelessSecurity *s_wsec; NMSetting8021x *s_8021x; @@ -778,6 +773,7 @@ complete_connection (NMDevice *device, GByteArray *tmp_ssid = NULL; GBytes *setting_ssid = NULL; gboolean hidden = FALSE; + const char *perm_hw_addr; s_wifi = nm_connection_get_setting_wireless (connection); s_wsec = nm_connection_get_setting_wireless_security (connection); @@ -908,29 +904,31 @@ complete_connection (NMDevice *device, if (hidden) g_object_set (s_wifi, NM_SETTING_WIRELESS_HIDDEN, TRUE, NULL); - setting_mac = nm_setting_wireless_get_mac_address (s_wifi); - if (setting_mac) { - /* Make sure the setting MAC (if any) matches the device's permanent MAC */ - if (!nm_utils_hwaddr_matches (setting_mac, -1, priv->perm_hw_addr, -1)) { - g_set_error_literal (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("connection does not match device")); - g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_MAC_ADDRESS); - return FALSE; - } - } else { - guint8 perm_hw_addr[ETH_ALEN]; + perm_hw_addr = nm_device_get_permanent_hw_address (device); + if (perm_hw_addr) { + setting_mac = nm_setting_wireless_get_mac_address (s_wifi); + if (setting_mac) { + /* Make sure the setting MAC (if any) matches the device's permanent MAC */ + if (!nm_utils_hwaddr_matches (setting_mac, -1, perm_hw_addr, -1)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("connection does not match device")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_MAC_ADDRESS); + return FALSE; + } + } else { + guint8 tmp[ETH_ALEN]; - /* Lock the connection to this device by default if it uses a - * permanent MAC address (ie not a 'locally administered' one) - */ - nm_utils_hwaddr_aton (priv->perm_hw_addr, perm_hw_addr, ETH_ALEN); - if ( !(perm_hw_addr[0] & 0x02) - && !nm_utils_hwaddr_matches (perm_hw_addr, ETH_ALEN, NULL, ETH_ALEN)) { - g_object_set (G_OBJECT (s_wifi), - NM_SETTING_WIRELESS_MAC_ADDRESS, priv->perm_hw_addr, - NULL); + /* Lock the connection to this device by default if it uses a + * permanent MAC address (ie not a 'locally administered' one) + */ + nm_utils_hwaddr_aton (perm_hw_addr, tmp, ETH_ALEN); + if (!(tmp[0] & 0x02)) { + g_object_set (G_OBJECT (s_wifi), + NM_SETTING_WIRELESS_MAC_ADDRESS, perm_hw_addr, + NULL); + } } } @@ -2241,62 +2239,6 @@ error: /****************************************************************************/ -static void -update_permanent_hw_address (NMDevice *device) -{ - NMDeviceWifi *self = NM_DEVICE_WIFI (device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - struct ifreq req; - struct ethtool_perm_addr *epaddr = NULL; - int fd, ret, errsv; - - g_return_if_fail (priv->perm_hw_addr == NULL); - - fd = socket (PF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - _LOGE (LOGD_HW, "could not open control socket."); - return; - } - - /* Get permanent MAC address */ - memset (&req, 0, sizeof (struct ifreq)); - strncpy (req.ifr_name, nm_device_get_iface (device), IFNAMSIZ); - - epaddr = g_malloc0 (sizeof (struct ethtool_perm_addr) + ETH_ALEN); - epaddr->cmd = ETHTOOL_GPERMADDR; - epaddr->size = ETH_ALEN; - req.ifr_data = (void *) epaddr; - - errno = 0; - ret = ioctl (fd, SIOCETHTOOL, &req); - errsv = errno; - if ((ret < 0) || !nm_ethernet_address_is_valid (epaddr->data, ETH_ALEN)) { - _LOGD (LOGD_HW | LOGD_ETHER, "unable to read permanent MAC address (error %d)", - errsv); - /* Fall back to current address */ - nm_utils_hwaddr_aton (nm_device_get_hw_address (device), epaddr->data, ETH_ALEN); - } - - priv->perm_hw_addr = nm_utils_hwaddr_ntoa (epaddr->data, ETH_ALEN); - - g_free (epaddr); - close (fd); -} - -static void -update_initial_hw_address (NMDevice *device) -{ - NMDeviceWifi *self = NM_DEVICE_WIFI (device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - - /* This sets initial MAC address from current MAC address. It should only - * be called from NMDevice constructor() to really get the initial address. - */ - priv->initial_hw_addr = g_strdup (nm_device_get_hw_address (device)); - - _LOGD (LOGD_DEVICE | LOGD_ETHER, "read initial MAC address %s", priv->initial_hw_addr); -} - static NMActStageReturn act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) { @@ -2950,12 +2892,7 @@ dispose (GObject *object) static void finalize (GObject *object) { - NMDeviceWifi *self = NM_DEVICE_WIFI (object); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - - g_free (priv->perm_hw_addr); - g_free (priv->initial_hw_addr); - g_clear_pointer (&priv->aps, g_hash_table_unref); + g_clear_pointer (&NM_DEVICE_WIFI_GET_PRIVATE (object)->aps, g_hash_table_unref); G_OBJECT_CLASS (nm_device_wifi_parent_class)->finalize (object); } @@ -2972,7 +2909,7 @@ get_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_PERM_HW_ADDRESS: - g_value_set_string (value, priv->perm_hw_addr); + g_value_set_string (value, nm_device_get_permanent_hw_address (NM_DEVICE (device))); break; case PROP_MODE: g_value_set_uint (value, priv->mode); @@ -3028,8 +2965,6 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) object_class->finalize = finalize; parent_class->bring_up = bring_up; - parent_class->update_permanent_hw_address = update_permanent_hw_address; - parent_class->update_initial_hw_address = update_initial_hw_address; parent_class->can_auto_connect = can_auto_connect; parent_class->is_available = is_available; parent_class->check_connection_compatible = check_connection_compatible; diff --git a/src/devices/wifi/nm-wifi-factory.c b/src/devices/wifi/nm-wifi-factory.c index 4093c61239..c4b4042e70 100644 --- a/src/devices/wifi/nm-wifi-factory.c +++ b/src/devices/wifi/nm-wifi-factory.c @@ -23,6 +23,8 @@ #include #include "nm-device-factory.h" +#include "nm-setting-wireless.h" +#include "nm-setting-olpc-mesh.h" #include "nm-device-wifi.h" #include "nm-device-olpc-mesh.h" #include "nm-settings-connection.h" @@ -57,26 +59,25 @@ nm_device_factory_create (GError **error) /**************************************************************************/ static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { if (plink->type == NM_LINK_TYPE_WIFI) return nm_device_wifi_new (plink); else if (plink->type == NM_LINK_TYPE_OLPC_MESH) return nm_device_olpc_mesh_new (plink); - return NULL; + g_assert_not_reached (); } -static NMDeviceType -get_device_type (NMDeviceFactory *factory) -{ - return NM_DEVICE_TYPE_WIFI; -} +NM_DEVICE_FACTORY_DECLARE_TYPES ( + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_WIFI, NM_LINK_TYPE_OLPC_MESH) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_OLPC_MESH_SETTING_NAME) +) static void device_factory_interface_init (NMDeviceFactory *factory_iface) { factory_iface->new_link = new_link; - factory_iface->get_device_type = get_device_type; + factory_iface->get_supported_types = get_supported_types; } static void diff --git a/src/devices/wwan/nm-wwan-factory.c b/src/devices/wwan/nm-wwan-factory.c index 2b9c3d4dd0..49b0b0af53 100644 --- a/src/devices/wwan/nm-wwan-factory.c +++ b/src/devices/wwan/nm-wwan-factory.c @@ -25,9 +25,12 @@ #include "nm-device-factory.h" #include "nm-wwan-factory.h" +#include "nm-setting-gsm.h" +#include "nm-setting-cdma.h" #include "nm-modem-manager.h" #include "nm-device-modem.h" #include "nm-logging.h" +#include "nm-platform.h" static GType nm_wwan_factory_get_type (void); @@ -87,10 +90,17 @@ modem_added_cb (NMModemManager *manager, } -static NMDeviceType -get_device_type (NMDeviceFactory *factory) +NM_DEVICE_FACTORY_DECLARE_TYPES ( + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_WWAN_ETHERNET) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_GSM_SETTING_NAME, NM_SETTING_CDMA_SETTING_NAME) +) + +static NMDevice * +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { - return NM_DEVICE_TYPE_MODEM; + g_warn_if_fail (plink->type == NM_LINK_TYPE_WWAN_ETHERNET); + *out_ignore = TRUE; + return NULL; } static void @@ -115,7 +125,8 @@ nm_wwan_factory_init (NMWwanFactory *self) static void device_factory_interface_init (NMDeviceFactory *factory_iface) { - factory_iface->get_device_type = get_device_type; + factory_iface->get_supported_types = get_supported_types; + factory_iface->new_link = new_link; factory_iface->start = start; } diff --git a/src/nm-manager.c b/src/nm-manager.c index 0bb3b0efdd..848ccd26bf 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -26,8 +26,6 @@ #include #include #include -#include -#include #include #include #include @@ -129,8 +127,6 @@ static NMActiveConnection *_new_active_connection (NMManager *self, static void policy_activating_device_changed (GObject *object, GParamSpec *pspec, gpointer user_data); -static NMDevice *find_device_by_ip_iface (NMManager *self, const gchar *iface); - static void rfkill_change (const char *desc, RfKillType rtype, gboolean enabled); static gboolean find_master (NMManager *self, @@ -178,9 +174,6 @@ typedef struct { gboolean prop_filter_added; NMRfkillManager *rfkill_mgr; - /* List of NMDeviceFactoryFunc pointers sorted in priority order */ - GSList *factories; - NMSettings *settings; char *hostname; @@ -520,6 +513,38 @@ nm_manager_get_device_by_ifindex (NMManager *manager, int ifindex) return NULL; } +static NMDevice * +find_device_by_hw_addr (NMManager *manager, const char *hwaddr) +{ + GSList *iter; + const char *device_addr; + + g_return_val_if_fail (hwaddr != NULL, NULL); + + if (nm_utils_hwaddr_valid (hwaddr, -1)) { + for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) { + device_addr = nm_device_get_hw_address (NM_DEVICE (iter->data)); + if (device_addr && nm_utils_hwaddr_matches (hwaddr, -1, device_addr, -1)) + return NM_DEVICE (iter->data); + } + } + return NULL; +} + +static NMDevice * +find_device_by_ip_iface (NMManager *self, const gchar *iface) +{ + GSList *iter; + + g_return_val_if_fail (iface != NULL, NULL); + + for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = g_slist_next (iter)) { + if (g_strcmp0 (nm_device_get_ip_iface (NM_DEVICE (iter->data)), iface) == 0) + return NM_DEVICE (iter->data); + } + return NULL; +} + static gboolean manager_sleeping (NMManager *self) { @@ -843,109 +868,56 @@ nm_manager_get_state (NMManager *manager) return NM_MANAGER_GET_PRIVATE (manager)->state; } -/*******************************************************************/ -/* Settings stuff via NMSettings */ -/*******************************************************************/ +/***************************/ static NMDevice * -get_device_from_hwaddr (NMManager *self, const char *setting_mac) +find_parent_device_for_connection (NMManager *self, NMConnection *connection) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - const char *device_mac; + NMDeviceFactory *factory; + const char *parent_name = NULL; + NMConnection *parent_connection; + NMDevice *parent, *first_compatible = NULL; GSList *iter; - if (!setting_mac) + factory = nm_device_factory_manager_find_factory_for_connection (connection); + if (!factory) return NULL; - for (iter = priv->devices; iter; iter = g_slist_next (iter)) { - NMDevice *device = iter->data; + parent_name = nm_device_factory_get_connection_parent (factory, connection); + if (!parent_name) + return NULL; - device_mac = nm_device_get_hw_address (iter->data); - if (!device_mac) - continue; - if (nm_utils_hwaddr_matches (setting_mac, -1, device_mac, -1)) - return device; - } - return NULL; -} + /* Try as an interface name */ + parent = find_device_by_ip_iface (self, parent_name); + if (parent) + return parent; -static NMDevice * -find_vlan_parent (NMManager *self, - NMConnection *connection) -{ - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMSettingVlan *s_vlan; - NMSettingWired *s_wired; - NMConnection *parent_connection; - const char *parent_iface; - NMDevice *parent = NULL; - const char *setting_mac; - GSList *iter; + /* Maybe a hardware address */ + parent = find_device_by_hw_addr (self, parent_name); + if (parent) + return parent; - /* The 'parent' property could be given by an interface name, a - * connection UUID, or the MAC address of an NMSettingWired. + /* Maybe a connection UUID */ + parent_connection = (NMConnection *) nm_settings_get_connection_by_uuid (priv->settings, parent_name); + if (!parent_connection) + return NULL; + + /* Check if the parent connection is currently activated or is comaptible + * with some known device. */ - s_vlan = nm_connection_get_setting_vlan (connection); - g_return_val_if_fail (s_vlan != NULL, NULL); + for (iter = priv->devices; iter; iter = iter->next) { + NMDevice *candidate = iter->data; - s_wired = nm_connection_get_setting_wired (connection); - setting_mac = s_wired ? nm_setting_wired_get_mac_address (s_wired) : NULL; + if (nm_device_get_connection (candidate) == parent_connection) + return candidate; - parent_iface = nm_setting_vlan_get_parent (s_vlan); - if (parent_iface) { - parent = find_device_by_ip_iface (self, parent_iface); - if (parent) - return parent; - - if (nm_utils_is_uuid (parent_iface)) { - /* Try as a connection UUID */ - parent_connection = (NMConnection *) nm_settings_get_connection_by_uuid (priv->settings, parent_iface); - if (parent_connection) { - /* Check if the parent connection is activated on some device already */ - for (iter = priv->devices; iter; iter = g_slist_next (iter)) { - NMActRequest *req; - NMConnection *candidate; - - req = nm_device_get_act_request (NM_DEVICE (iter->data)); - if (req) { - candidate = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (req)); - if (candidate == parent_connection) - return NM_DEVICE (iter->data); - } - } - - /* Check the hardware address of the parent connection */ - return get_device_from_hwaddr (self, setting_mac); - } - return NULL; - } + if ( !first_compatible + && nm_device_check_connection_compatible (candidate, parent_connection)) + first_compatible = candidate; } - /* Try the hardware address from the VLAN connection's hardware setting */ - return get_device_from_hwaddr (self, setting_mac); -} - -static NMDevice * -find_infiniband_parent (NMManager *self, - NMConnection *connection) -{ - NMSettingInfiniband *s_infiniband; - const char *parent_iface; - NMDevice *parent = NULL; - const char *setting_mac; - - s_infiniband = nm_connection_get_setting_infiniband (connection); - g_return_val_if_fail (s_infiniband != NULL, NULL); - - parent_iface = nm_setting_infiniband_get_parent (s_infiniband); - if (parent_iface) { - parent = find_device_by_ip_iface (self, parent_iface); - if (parent) - return parent; - } - - setting_mac = nm_setting_infiniband_get_mac_address (s_infiniband); - return get_device_from_hwaddr (self, setting_mac); + return first_compatible; } /** @@ -953,86 +925,69 @@ find_infiniband_parent (NMManager *self, * @self: the #NMManager * @connection: the #NMConnection representing a virtual interface * @out_parent: on success, the parent device if any + * @error: an error if determining the virtual interface name failed * * Given @connection, returns the interface name that the connection - * would represent. If the interface name is not given by the connection, - * this may require constructing it based on information in the connection - * and existing network interfaces. + * would represent if it is a virtual connection. %NULL is returned and + * @error is set if the connection is not virtual, or if the name could + * not be determined. * * Returns: the expected interface name (caller takes ownership), or %NULL */ static char * get_virtual_iface_name (NMManager *self, NMConnection *connection, - NMDevice **out_parent) + NMDevice **out_parent, + GError **error) { + NMDeviceFactory *factory; + char *iface = NULL; NMDevice *parent = NULL; - const char *ifname; if (out_parent) *out_parent = NULL; - if (!nm_connection_is_virtual (connection)) + if (!nm_connection_is_virtual (connection)) { + g_set_error (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_FAILED, + "NetworkManager plugin for '%s' unavailable", + nm_connection_get_connection_type (connection)); return NULL; - - ifname = nm_connection_get_interface_name (connection); - - if (nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME)) { - NMSettingVlan *s_vlan; - char *vname; - - s_vlan = nm_connection_get_setting_vlan (connection); - g_return_val_if_fail (s_vlan != NULL, NULL); - - parent = find_vlan_parent (self, connection); - if (!parent) - return NULL; - - if (!nm_device_supports_vlans (parent)) { - nm_log_warn (LOGD_DEVICE, "(%s): No support for VLANs on interface %s of type %s", - ifname ? ifname : nm_connection_get_id (connection), - nm_device_get_ip_iface (parent), - nm_device_get_type_desc (parent)); - return NULL; - } - - /* If the connection doesn't specify the interface name for the VLAN - * device, we create one for it using the VLAN ID and the parent - * interface's name. - */ - if (ifname) - vname = g_strdup (ifname); - else { - vname = nm_utils_new_vlan_name (nm_device_get_ip_iface (parent), - nm_setting_vlan_get_id (s_vlan)); - } - if (out_parent) - *out_parent = parent; - return vname; } - if (nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME)) { - NMSettingInfiniband *s_infiniband; - - parent = find_infiniband_parent (self, connection); - if (!parent) - return NULL; - - s_infiniband = nm_connection_get_setting_infiniband (connection); - if (out_parent) - *out_parent = parent; - return g_strdup (nm_setting_infiniband_get_virtual_interface_name (s_infiniband)); + factory = nm_device_factory_manager_find_factory_for_connection (connection); + if (!factory) { + nm_log_warn (LOGD_DEVICE, "(%s) NetworkManager plugin for '%s' unavailable", + nm_connection_get_id (connection), + nm_connection_get_connection_type (connection)); + g_set_error (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_FAILED, + "NetworkManager plugin for '%s' unavailable", + nm_connection_get_connection_type (connection)); + return NULL; } - /* For any other virtual connection, NMSettingConnection:interface-name is - * the virtual device name. - */ - g_return_val_if_fail (ifname != NULL, NULL); - return g_strdup (ifname); + parent = find_parent_device_for_connection (self, connection); + iface = nm_device_factory_get_virtual_iface_name (factory, + connection, + parent ? nm_device_get_ip_iface (parent) : NULL); + if (!iface) { + nm_log_warn (LOGD_DEVICE, "(%s) failed to determine virtual interface name", + nm_connection_get_id (connection)); + g_set_error_literal (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_UNKNOWN_DEVICE, + "failed to determine virtual interface name"); + return NULL; + } + + if (out_parent) + *out_parent = parent; + return iface; } -/***************************/ - /** * system_create_virtual_device: * @self: the #NMManager @@ -1048,7 +1003,7 @@ static NMDevice * system_create_virtual_device (NMManager *self, NMConnection *connection, GError **error) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - GError *local_err = NULL; + NMDeviceFactory *factory; GSList *iter; char *iface = NULL; NMDevice *device = NULL, *parent = NULL; @@ -1058,16 +1013,9 @@ system_create_virtual_device (NMManager *self, NMConnection *connection, GError g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); - iface = get_virtual_iface_name (self, connection, &parent); - if (!iface) { - nm_log_dbg (LOGD_DEVICE, "(%s) failed to determine virtual interface name", - nm_connection_get_id (connection)); - g_set_error_literal (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "failed to determine virtual interface name"); + iface = get_virtual_iface_name (self, connection, &parent, error); + if (!iface) return NULL; - } /* Make sure we didn't create a device for this connection already */ for (iter = priv->devices; iter; iter = g_slist_next (iter)) { @@ -1085,6 +1033,19 @@ system_create_virtual_device (NMManager *self, NMConnection *connection, GError } } + factory = nm_device_factory_manager_find_factory_for_connection (connection); + if (!factory) { + nm_log_err (LOGD_DEVICE, "(%s:%s) NetworkManager plugin for '%s' unavailable", + nm_connection_get_id (connection), iface, + nm_connection_get_connection_type (connection)); + g_set_error (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_FAILED, + "NetworkManager plugin for '%s' unavailable", + nm_connection_get_connection_type (connection)); + goto out; + } + /* Block notification of link added since we're creating the device * explicitly here, otherwise adding the platform/kernel device would * create it before this function can do the rest of the setup. @@ -1093,24 +1054,10 @@ system_create_virtual_device (NMManager *self, NMConnection *connection, GError nm_owned = !nm_platform_link_exists (NM_PLATFORM_GET, iface); - for (iter = priv->factories; iter; iter = iter->next) { - device = nm_device_factory_create_virtual_device_for_connection (NM_DEVICE_FACTORY (iter->data), - connection, - parent, - &local_err); - if (device || local_err) { - if (device) - g_assert_no_error (local_err); - else { - nm_log_err (LOGD_DEVICE, "(%s) failed to create virtual device: %s", - nm_connection_get_id (connection), - local_err ? local_err->message : "(unknown error)"); - g_propagate_error (error, local_err); - } - break; - } - } - + device = nm_device_factory_create_virtual_device_for_connection (factory, + connection, + parent, + error); if (device) { if (nm_owned) nm_device_set_nm_owned (device); @@ -1121,16 +1068,6 @@ system_create_virtual_device (NMManager *self, NMConnection *connection, GError add_device (self, device, !nm_owned); g_object_unref (device); - } else { - if (error && !*error) - nm_log_err (LOGD_DEVICE, "(%s:%s) NetworkManager plugin for '%s' unavailable", - nm_connection_get_id (connection), iface, - nm_connection_get_connection_type (connection)); - g_set_error (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "NetworkManager plugin for '%s' unavailable", - nm_connection_get_connection_type (connection)); } priv->ignore_link_added_cb--; @@ -1776,6 +1713,18 @@ device_ip_iface_changed (NMDevice *device, } } +static gboolean +notify_component_added (NMManager *self, GObject *component) +{ + GSList *iter; + + for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = iter->next) { + if (nm_device_notify_component_added (NM_DEVICE (iter->data), component)) + return TRUE; + } + return FALSE; +} + /** * add_device: * @self: the #NMManager @@ -1893,27 +1842,14 @@ add_device (NMManager *self, NMDevice *device, gboolean try_assume) g_signal_emit (self, signals[DEVICE_ADDED], 0, device); g_object_notify (G_OBJECT (self), NM_MANAGER_DEVICES); + notify_component_added (self, G_OBJECT (device)); + /* New devices might be master interfaces for virtual interfaces; so we may * need to create new virtual interfaces now. */ system_create_virtual_devices (self); } -static NMDevice * -find_device_by_ip_iface (NMManager *self, const gchar *iface) -{ - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - GSList *iter; - - for (iter = priv->devices; iter; iter = g_slist_next (iter)) { - NMDevice *candidate = iter->data; - - if (g_strcmp0 (nm_device_get_ip_iface (candidate), iface) == 0) - return candidate; - } - return NULL; -} - /*******************************************************************/ static void @@ -1928,135 +1864,14 @@ static gboolean factory_component_added_cb (NMDeviceFactory *factory, GObject *component, gpointer user_data) +{ + return notify_component_added (NM_MANAGER (user_data), component); +} + +static void +_register_device_factory (NMDeviceFactory *factory, gpointer user_data) { NMManager *self = NM_MANAGER (user_data); - GSList *iter; - - for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = iter->next) { - if (nm_device_notify_component_added (NM_DEVICE (iter->data), component)) - return TRUE; - } - return FALSE; -} - -#define PLUGIN_PREFIX "libnm-device-plugin-" -#define PLUGIN_PATH_TAG "NMManager-plugin-path" - -struct read_device_factory_paths_data { - char *path; - struct stat st; -}; - -static gint -read_device_factory_paths_sort_fcn (gconstpointer a, gconstpointer b) -{ - const struct read_device_factory_paths_data *da = a; - const struct read_device_factory_paths_data *db = b; - time_t ta, tb; - - ta = MAX (da->st.st_mtime, da->st.st_ctime); - tb = MAX (db->st.st_mtime, db->st.st_ctime); - - if (ta < tb) - return 1; - if (ta > tb) - return -1; - return 0; -} - -static char** -read_device_factory_paths (void) -{ - GDir *dir; - GError *error = NULL; - const char *item; - GArray *paths; - char **result; - guint i; - - dir = g_dir_open (NMPLUGINDIR, 0, &error); - if (!dir) { - nm_log_warn (LOGD_HW, "device plugin: failed to open directory %s: %s", - NMPLUGINDIR, - (error && error->message) ? error->message : "(unknown)"); - g_clear_error (&error); - return NULL; - } - - paths = g_array_new (FALSE, FALSE, sizeof (struct read_device_factory_paths_data)); - - while ((item = g_dir_read_name (dir))) { - int errsv; - struct read_device_factory_paths_data data; - - if (!g_str_has_prefix (item, PLUGIN_PREFIX)) - continue; - if (g_str_has_suffix (item, ".la")) - continue; - - data.path = g_build_filename (NMPLUGINDIR, item, NULL); - - if (stat (data.path, &data.st) != 0) { - errsv = errno; - nm_log_warn (LOGD_HW, "device plugin: skip invalid file %s (error during stat: %s)", data.path, strerror (errsv)); - goto NEXT; - } - if (!S_ISREG (data.st.st_mode)) - goto NEXT; - if (data.st.st_uid != 0) { - nm_log_warn (LOGD_HW, "device plugin: skip invalid file %s (file must be owned by root)", data.path); - goto NEXT; - } - if (data.st.st_mode & (S_IWGRP | S_IWOTH | S_ISUID)) { - nm_log_warn (LOGD_HW, "device plugin: skip invalid file %s (invalid file permissions)", data.path); - goto NEXT; - } - - g_array_append_val (paths, data); - continue; -NEXT: - g_free (data.path); - } - g_dir_close (dir); - - /* sort filenames by modification time. */ - g_array_sort (paths, read_device_factory_paths_sort_fcn); - - result = g_new (char *, paths->len + 1); - for (i = 0; i < paths->len; i++) - result[i] = g_array_index (paths, struct read_device_factory_paths_data, i).path; - result[i] = NULL; - - g_array_free (paths, TRUE); - return result; -} - -static gboolean -_register_device_factory (NMManager *self, - NMDeviceFactory *factory, - gboolean duplicate_check, - const char *path, - GError **error) -{ - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMDeviceType ftype; - GSList *iter; - - if (duplicate_check) { - /* Make sure we don't double-register factories */ - ftype = nm_device_factory_get_device_type (factory); - for (iter = priv->factories; iter; iter = iter->next) { - if (ftype == nm_device_factory_get_device_type (iter->data)) { - g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, - "multiple plugins for same type (using '%s' instead of '%s')", - (char *) g_object_get_data (G_OBJECT (iter->data), PLUGIN_PATH_TAG), - path); - return FALSE; - } - } - } - - priv->factories = g_slist_append (priv->factories, factory); g_signal_connect (factory, NM_DEVICE_FACTORY_DEVICE_ADDED, @@ -2066,80 +1881,6 @@ _register_device_factory (NMManager *self, NM_DEVICE_FACTORY_COMPONENT_ADDED, G_CALLBACK (factory_component_added_cb), self); - g_object_set_data_full (G_OBJECT (factory), PLUGIN_PATH_TAG, - g_strdup (path), g_free); - return TRUE; -} - -static void -load_device_factories (NMManager *self) -{ - NMDeviceFactory *factory; - const GSList *iter; - GError *error = NULL; - char **path, **paths; - - /* Register internal factories first */ - for (iter = nm_device_factory_get_internal_factory_types (); iter; iter = iter->next) { - GType ftype = (GType) GPOINTER_TO_SIZE (iter->data); - - factory = (NMDeviceFactory *) g_object_new (ftype, NULL); - g_assert (factory); - if (_register_device_factory (self, factory, FALSE, "internal", &error)) { - nm_log_dbg (LOGD_HW, "Loaded device plugin: %s", g_type_name (ftype)); - } else { - nm_log_warn (LOGD_HW, "Loading device plugin failed: %s", error->message); - g_object_unref (factory); - g_clear_error (&error); - } - } - - paths = read_device_factory_paths (); - if (!paths) - return; - - for (path = paths; *path; path++) { - GModule *plugin; - NMDeviceFactoryCreateFunc create_func; - const char *item; - - item = strrchr (*path, '/'); - g_assert (item); - - plugin = g_module_open (*path, G_MODULE_BIND_LOCAL); - - if (!plugin) { - nm_log_warn (LOGD_HW, "(%s): failed to load plugin: %s", item, g_module_error ()); - continue; - } - - if (!g_module_symbol (plugin, "nm_device_factory_create", (gpointer) &create_func)) { - nm_log_warn (LOGD_HW, "(%s): failed to find device factory creator: %s", item, g_module_error ()); - g_module_close (plugin); - continue; - } - - factory = create_func (&error); - if (!factory) { - nm_log_warn (LOGD_HW, "(%s): failed to initialize device factory: %s", - item, error ? error->message : "unknown"); - g_clear_error (&error); - g_module_close (plugin); - continue; - } - g_clear_error (&error); - - if (_register_device_factory (self, factory, TRUE, g_module_name (plugin), &error)) { - nm_log_info (LOGD_HW, "Loaded device plugin: %s", g_module_name (plugin)); - g_module_make_resident (plugin); - } else { - nm_log_warn (LOGD_HW, "Loading device plugin failed: %s", error->message); - g_object_unref (factory); - g_module_close (plugin); - g_clear_error (&error); - } - } - g_strfreev (paths); } /*******************************************************************/ @@ -2151,8 +1892,8 @@ platform_link_added (NMManager *self, NMPlatformReason reason) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + NMDeviceFactory *factory; NMDevice *device = NULL; - GSList *iter; GError *error = NULL; gboolean nm_plugin_missing = FALSE; @@ -2165,40 +1906,25 @@ platform_link_added (NMManager *self, return; /* Try registered device factories */ - for (iter = priv->factories; iter; iter = iter->next) { - NMDeviceFactory *factory = NM_DEVICE_FACTORY (iter->data); + factory = nm_device_factory_manager_find_factory_for_link_type (plink->type); + if (factory) { + gboolean ignore = FALSE; - device = nm_device_factory_new_link (factory, plink, &error); - if (device && NM_IS_DEVICE (device)) { - g_assert_no_error (error); - break; /* success! */ - } - - if (error) { - nm_log_warn (LOGD_HW, "%s: factory failed to create device: (%d) %s", - plink->udi, - error ? error->code : -1, - error ? error->message : "(unknown)"); - g_clear_error (&error); + device = nm_device_factory_new_link (factory, plink, &ignore, &error); + if (!device) { + if (!ignore) { + nm_log_warn (LOGD_HW, "%s: factory failed to create device: %s", + plink->name, error->message); + g_clear_error (&error); + } return; } } - /* Ignore Bluetooth PAN interfaces; they are handled by their NMDeviceBt - * parent and don't get a separate interface. - */ - if (!strncmp (plink->name, "bnep", STRLEN ("bnep"))) - return; - if (device == NULL) { switch (plink->type) { - case NM_LINK_TYPE_WWAN_ETHERNET: - /* WWAN pseudo-ethernet interfaces are handled automatically by - * their NMDeviceModem and don't get a separate NMDevice object. - */ - break; - + case NM_LINK_TYPE_BNEP: case NM_LINK_TYPE_OLPC_MESH: case NM_LINK_TYPE_TEAM: case NM_LINK_TYPE_WIFI: @@ -2460,13 +2186,10 @@ find_master (NMManager *self, NMConnection *candidate = iter->data; char *vname; - if (nm_connection_is_virtual (candidate)) { - vname = get_virtual_iface_name (self, candidate, NULL); - if ( g_strcmp0 (master, vname) == 0 - && is_compatible_with_slave (candidate, connection)) - master_connection = candidate; - g_free (vname); - } + vname = get_virtual_iface_name (self, connection, NULL, NULL); + if (g_strcmp0 (master, vname) == 0 && is_compatible_with_slave (candidate, connection)) + master_connection = candidate; + g_free (vname); } g_slist_free (connections); } @@ -3148,17 +2871,12 @@ validate_activation_request (NMManager *self, } if (is_software) { - /* Look for an existing device with the connection's interface name */ char *iface; - iface = get_virtual_iface_name (self, connection, NULL); - if (!iface) { - g_set_error_literal (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "Failed to determine connection's virtual interface name"); + /* Look for an existing device with the connection's interface name */ + iface = get_virtual_iface_name (self, connection, NULL, error); + if (!iface) goto error; - } device = find_device_by_ip_iface (self, iface); g_free (iface); @@ -4219,11 +3937,16 @@ impl_manager_check_connectivity (NMManager *manager, nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE); } +static void +start_factory (NMDeviceFactory *factory, gpointer user_data) +{ + nm_device_factory_start (factory); +} + void nm_manager_start (NMManager *self) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - GSList *iter; guint i; /* Set initial radio enabled/disabled state */ @@ -4255,8 +3978,7 @@ nm_manager_start (NMManager *self) system_hostname_changed_cb (priv->settings, NULL, self); /* Start device factories */ - for (iter = priv->factories; iter; iter = iter->next) - nm_device_factory_start (iter->data); + nm_device_factory_manager_for_each_factory (start_factory, NULL); nm_platform_query_devices (NM_PLATFORM_GET); @@ -4861,7 +4583,7 @@ nm_manager_new (NMSettings *settings, rfkill_change (priv->radio_states[RFKILL_TYPE_WLAN].desc, RFKILL_TYPE_WLAN, initial_wifi_enabled); rfkill_change (priv->radio_states[RFKILL_TYPE_WWAN].desc, RFKILL_TYPE_WWAN, initial_wwan_enabled); - load_device_factories (singleton); + nm_device_factory_manager_load_factories (_register_device_factory, singleton); return singleton; } @@ -5087,6 +4809,12 @@ set_property (GObject *object, guint prop_id, } } +static void +_deinit_device_factory (NMDeviceFactory *factory, gpointer user_data) +{ + g_signal_handlers_disconnect_matched (factory, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, NM_MANAGER (user_data)); +} + static void dispose (GObject *object) { @@ -5094,7 +4822,6 @@ dispose (GObject *object) NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); DBusGConnection *bus; DBusConnection *dbus_connection; - GSList *iter; g_slist_free_full (priv->auth_chains, (GDestroyNotify) nm_auth_chain_unref); priv->auth_chains = NULL; @@ -5170,14 +4897,8 @@ dispose (GObject *object) g_clear_object (&priv->fw_monitor); } - for (iter = priv->factories; iter; iter = iter->next) { - NMDeviceFactory *factory = iter->data; - - g_signal_handlers_disconnect_matched (factory, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, manager); - g_object_unref (factory); - } - g_clear_pointer (&priv->factories, g_slist_free); - + nm_device_factory_manager_for_each_factory (_deinit_device_factory, manager); + if (priv->timestamp_update_id) { g_source_remove (priv->timestamp_update_id); priv->timestamp_update_id = 0; diff --git a/src/nm-types.h b/src/nm-types.h index f22272d91f..1c0ba9b46a 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -101,6 +101,7 @@ typedef enum { NM_LINK_TYPE_VETH, NM_LINK_TYPE_VLAN, NM_LINK_TYPE_VXLAN, + NM_LINK_TYPE_BNEP, /* Bluetooth Ethernet emulation */ /* Software types with slaves */ NM_LINK_TYPE_BRIDGE = 0x10000 | 0x20000, diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index 0da6590ffb..1ac61d41d4 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -162,13 +162,40 @@ _nm_platform_link_get (NMPlatform *platform, int ifindex, NMPlatformLink *l) { NMFakePlatformLink *device = link_get (platform, ifindex); - if (device) + if (device && l) *l = device->link; return !!device; } static gboolean -link_add (NMPlatform *platform, const char *name, NMLinkType type, const void *address, size_t address_len) +_nm_platform_link_get_by_address (NMPlatform *platform, + gconstpointer address, + size_t length, + NMPlatformLink *l) +{ + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); + guint i; + + for (i = 0; i < priv->links->len; i++) { + NMFakePlatformLink *device = &g_array_index (priv->links, NMFakePlatformLink, i); + + if ( device->address + && g_bytes_get_size (device->address) == length + && memcmp (g_bytes_get_data (device->address, NULL), address, length) == 0) { + *l = device->link; + return TRUE; + } + } + return FALSE; +} + +static gboolean +link_add (NMPlatform *platform, + const char *name, + NMLinkType type, + const void *address, + size_t address_len, + NMPlatformLink *out_link) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); NMFakePlatformLink device; @@ -180,6 +207,8 @@ link_add (NMPlatform *platform, const char *name, NMLinkType type, const void *a if (device.link.ifindex) g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, device.link.ifindex, &device, NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_REASON_INTERNAL); + if (out_link) + *out_link = device.link; return TRUE; } @@ -425,6 +454,12 @@ link_get_address (NMPlatform *platform, int ifindex, size_t *length) return g_bytes_get_data (device->address, length); } +static gboolean +link_get_permanent_address (NMPlatform *platform, int ifindex, guint8 *buf, size_t *length) +{ + return FALSE; +} + static gboolean link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu) { @@ -473,6 +508,26 @@ link_get_wake_on_lan (NMPlatform *platform, int ifindex) return FALSE; } +static gboolean +link_get_driver_info (NMPlatform *platform, + int ifindex, + char **out_driver_name, + char **out_driver_version, + char **out_fw_version) +{ + if (out_driver_name) + *out_driver_name = NULL; + if (out_driver_version) + *out_driver_version = NULL; + if (out_fw_version) + *out_fw_version = NULL; + + /* We call link_get just to cause an error to be set if @ifindex is bad. */ + link_get (platform, ifindex); + + return TRUE; +} + static gboolean link_supports_carrier_detect (NMPlatform *platform, int ifindex) { @@ -584,11 +639,11 @@ slave_get_option (NMPlatform *platform, int slave, const char *option) } static gboolean -vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint32 vlan_flags) +vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint32 vlan_flags, NMPlatformLink *out_link) { NMFakePlatformLink *device; - if (!link_add (platform, name, NM_LINK_TYPE_VLAN, NULL, 0)) + if (!link_add (platform, name, NM_LINK_TYPE_VLAN, NULL, 0, NULL)) return FALSE; device = link_get (platform, link_get_ifindex (platform, name)); @@ -598,6 +653,8 @@ vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint device->vlan_id = vlan_id; device->link.parent = parent; + if (out_link) + *out_link = device->link; return TRUE; } @@ -629,7 +686,7 @@ vlan_set_egress_map (NMPlatform *platform, int ifindex, int from, int to) } static gboolean -infiniband_partition_add (NMPlatform *platform, int parent, int p_key) +infiniband_partition_add (NMPlatform *platform, int parent, int p_key, NMPlatformLink *out_link) { NMFakePlatformLink *parent_device; char *name; @@ -639,7 +696,7 @@ infiniband_partition_add (NMPlatform *platform, int parent, int p_key) g_return_val_if_fail (parent_device != NULL, FALSE); name = g_strdup_printf ("%s.%04x", parent_device->link.name, p_key); - success = link_add (platform, name, NM_LINK_TYPE_INFINIBAND, NULL, 0); + success = link_add (platform, name, NM_LINK_TYPE_INFINIBAND, NULL, 0, out_link); g_free (name); return success; @@ -1313,15 +1370,15 @@ nm_fake_platform_setup (void) nm_platform_setup (platform); /* skip zero element */ - link_add (platform, NULL, NM_LINK_TYPE_NONE, NULL, 0); + link_add (platform, NULL, NM_LINK_TYPE_NONE, NULL, 0, NULL); /* add loopback interface */ - link_add (platform, "lo", NM_LINK_TYPE_LOOPBACK, NULL, 0); + link_add (platform, "lo", NM_LINK_TYPE_LOOPBACK, NULL, 0, NULL); /* add some ethernets */ - link_add (platform, "eth0", NM_LINK_TYPE_ETHERNET, NULL, 0); - link_add (platform, "eth1", NM_LINK_TYPE_ETHERNET, NULL, 0); - link_add (platform, "eth2", NM_LINK_TYPE_ETHERNET, NULL, 0); + link_add (platform, "eth0", NM_LINK_TYPE_ETHERNET, NULL, 0, NULL); + link_add (platform, "eth1", NM_LINK_TYPE_ETHERNET, NULL, 0, NULL); + link_add (platform, "eth2", NM_LINK_TYPE_ETHERNET, NULL, 0, NULL); } static void @@ -1361,6 +1418,7 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass) platform_class->sysctl_get = sysctl_get; platform_class->link_get = _nm_platform_link_get; + platform_class->link_get_by_address = _nm_platform_link_get_by_address; platform_class->link_get_all = link_get_all; platform_class->link_add = link_add; platform_class->link_delete = link_delete; @@ -1380,12 +1438,14 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass) platform_class->link_set_address = link_set_address; platform_class->link_get_address = link_get_address; + platform_class->link_get_permanent_address = link_get_permanent_address; platform_class->link_get_mtu = link_get_mtu; platform_class->link_set_mtu = link_set_mtu; platform_class->link_get_physical_port_id = link_get_physical_port_id; platform_class->link_get_dev_id = link_get_dev_id; platform_class->link_get_wake_on_lan = link_get_wake_on_lan; + platform_class->link_get_driver_info = link_get_driver_info; platform_class->link_supports_carrier_detect = link_supports_carrier_detect; platform_class->link_supports_vlans = link_supports_vlans; diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 0ef684d971..68da68625d 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -372,6 +372,9 @@ ethtool_get (const char *name, gpointer edata) struct ifreq ifr; int fd; + if (!name || !*name) + return FALSE; + memset (&ifr, 0, sizeof (ifr)); strncpy (ifr.ifr_name, name, IFNAMSIZ); ifr.ifr_data = edata; @@ -426,21 +429,54 @@ ethtool_get_stringset_index (const char *ifname, int stringset_id, const char *s return -1; } -static const char * -ethtool_get_driver (const char *ifname) +static gboolean +ethtool_get_driver_info (const char *ifname, + char **out_driver_name, + char **out_driver_version, + char **out_fw_version) { struct ethtool_drvinfo drvinfo = { 0 }; - g_return_val_if_fail (ifname != NULL, NULL); + if (!ifname) + return FALSE; drvinfo.cmd = ETHTOOL_GDRVINFO; if (!ethtool_get (ifname, &drvinfo)) - return NULL; + return FALSE; - if (!*drvinfo.driver) - return NULL; + if (out_driver_name) + *out_driver_name = g_strdup (drvinfo.driver); + if (out_driver_version) + *out_driver_version = g_strdup (drvinfo.version); + if (out_fw_version) + *out_fw_version = g_strdup (drvinfo.fw_version); - return g_intern_string (drvinfo.driver); + return TRUE; +} + +static gboolean +ethtool_get_permanent_address (const char *ifname, + guint8 *buf, + size_t *length) +{ + gs_free struct ethtool_perm_addr *epaddr = NULL; + + if (!ifname) + return FALSE; + + epaddr = g_malloc0 (sizeof (*epaddr) + NM_UTILS_HWADDR_LEN_MAX); + epaddr->cmd = ETHTOOL_GPERMADDR; + epaddr->size = NM_UTILS_HWADDR_LEN_MAX; + + if (!ethtool_get (ifname, epaddr)) + return FALSE; + if (!nm_ethernet_address_is_valid (epaddr->data, epaddr->size)) + return FALSE; + + g_assert (epaddr->size <= NM_UTILS_HWADDR_LEN_MAX); + memcpy (buf, epaddr->data, epaddr->size); + *length = epaddr->size; + return TRUE; } /****************************************************************** @@ -881,6 +917,7 @@ static const LinkDesc linktypes[] = { { NM_LINK_TYPE_VETH, "veth", "veth", NULL }, { NM_LINK_TYPE_VLAN, "vlan", "vlan", "vlan" }, { NM_LINK_TYPE_VXLAN, "vxlan", "vxlan", "vxlan" }, + { NM_LINK_TYPE_BNEP, "bluetooth", NULL, "bluetooth" }, { NM_LINK_TYPE_BRIDGE, "bridge", "bridge", "bridge" }, { NM_LINK_TYPE_BOND, "bond", "bond", "bond" }, @@ -980,10 +1017,9 @@ link_extract_type (NMPlatform *platform, struct rtnl_link *rtnllink) else if (arptype == ARPHRD_INFINIBAND) return NM_LINK_TYPE_INFINIBAND; - ifname = rtnl_link_get_name (rtnllink); if (ifname) { - const char *driver = ethtool_get_driver (ifname); + gs_free char *driver = NULL; gs_free char *sysfs_path = NULL; gs_free char *anycast_mask = NULL; gs_free char *devtype = NULL; @@ -997,8 +1033,10 @@ link_extract_type (NMPlatform *platform, struct rtnl_link *rtnllink) } /* Fallback OVS detection for kernel <= 3.16 */ - if (!g_strcmp0 (driver, "openvswitch")) - return NM_LINK_TYPE_OPENVSWITCH; + if (ethtool_get_driver_info (ifname, &driver, NULL, NULL)) { + if (!g_strcmp0 (driver, "openvswitch")) + return NM_LINK_TYPE_OPENVSWITCH; + } sysfs_path = g_strdup_printf ("/sys/class/net/%s", ifname); anycast_mask = g_strdup_printf ("%s/anycast_mask", sysfs_path); @@ -1007,8 +1045,16 @@ link_extract_type (NMPlatform *platform, struct rtnl_link *rtnllink) devtype = read_devtype (sysfs_path); for (i = 0; devtype && i < G_N_ELEMENTS (linktypes); i++) { - if (g_strcmp0 (devtype, linktypes[i].devtype) == 0) + if (g_strcmp0 (devtype, linktypes[i].devtype) == 0) { + if (linktypes[i].nm_type == NM_LINK_TYPE_BNEP) { + /* Both BNEP and 6lowpan use DEVTYPE=bluetooth, so we must + * use arptype to distinguish between them. + */ + if (arptype != ARPHRD_ETHER) + continue; + } return linktypes[i].nm_type; + } } /* Fallback for drivers that don't call SET_NETDEV_DEVTYPE() */ @@ -1033,6 +1079,7 @@ init_link (NMPlatform *platform, NMPlatformLink *info, struct rtnl_link *rtnllin NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); GUdevDevice *udev_device; const char *name; + char *tmp; g_return_val_if_fail (rtnllink, FALSE); @@ -1062,8 +1109,12 @@ init_link (NMPlatform *platform, NMPlatformLink *info, struct rtnl_link *rtnllin if (!info->driver) info->driver = info->kind; - if (!info->driver) - info->driver = ethtool_get_driver (info->name); + if (!info->driver) { + if (ethtool_get_driver_info (name, &tmp, NULL, NULL)) { + info->driver = g_intern_string (tmp); + g_free (tmp); + } + } if (!info->driver) info->driver = "unknown"; @@ -1768,12 +1819,14 @@ refresh_object (NMPlatform *platform, struct nl_object *object, gboolean removed announce_object (platform, kernel_object, cached_object ? NM_PLATFORM_SIGNAL_CHANGED : NM_PLATFORM_SIGNAL_ADDED, reason); - /* Refresh the master device (even on enslave/release) */ if (type == OBJECT_TYPE_LINK) { int kernel_master = rtnl_link_get_master ((struct rtnl_link *) kernel_object); int cached_master = cached_object ? rtnl_link_get_master ((struct rtnl_link *) cached_object) : 0; + const char *orig_link_type = rtnl_link_get_type ((struct rtnl_link *) object); + const char *kernel_link_type = rtnl_link_get_type ((struct rtnl_link *) kernel_object); struct nl_object *master_object; + /* Refresh the master device (even on enslave/release) */ if (kernel_master) { master_object = build_rtnl_link (kernel_master, NULL, NM_LINK_TYPE_NONE); refresh_object (platform, master_object, FALSE, NM_PLATFORM_REASON_INTERNAL); @@ -1784,6 +1837,12 @@ refresh_object (NMPlatform *platform, struct nl_object *object, gboolean removed refresh_object (platform, master_object, FALSE, NM_PLATFORM_REASON_INTERNAL); nl_object_put (master_object); } + + /* Ensure the existing link type matches the refreshed link type */ + if (orig_link_type && kernel_link_type && strcmp (orig_link_type, kernel_link_type)) { + platform->error = NM_PLATFORM_ERROR_WRONG_TYPE; + return FALSE; + } } } @@ -2296,9 +2355,34 @@ _nm_platform_link_get (NMPlatform *platform, int ifindex, NMPlatformLink *l) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); auto_nl_object struct rtnl_link *rtnllink = NULL; + NMPlatformLink tmp = { 0 }; rtnllink = rtnl_link_get (priv->link_cache, ifindex); - return (rtnllink && init_link (platform, l, rtnllink)); + return (rtnllink && init_link (platform, l ? l : &tmp, rtnllink)); +} + +static gboolean +_nm_platform_link_get_by_address (NMPlatform *platform, + gconstpointer address, + size_t length, + NMPlatformLink *l) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + struct nl_object *object; + + for (object = nl_cache_get_first (priv->link_cache); object; object = nl_cache_get_next (object)) { + struct rtnl_link *rtnl_link = (struct rtnl_link *) object; + struct nl_addr *nladdr; + gconstpointer hwaddr; + + nladdr = rtnl_link_get_addr (rtnl_link); + if (nladdr && (nl_addr_get_len (nladdr) == length)) { + hwaddr = nl_addr_get_binary_addr (nladdr); + if (hwaddr && memcmp (hwaddr, address, length) == 0) + return init_link (platform, l, rtnl_link); + } + } + return FALSE; } static struct nl_object * @@ -2316,7 +2400,27 @@ build_rtnl_link (int ifindex, const char *name, NMLinkType type) } static gboolean -link_add (NMPlatform *platform, const char *name, NMLinkType type, const void *address, size_t address_len) +link_get_by_name (NMPlatform *platform, const char *name, NMPlatformLink *out_link) +{ + int ifindex; + + g_return_val_if_fail (name != NULL, FALSE); + + if (out_link) { + ifindex = nm_platform_link_get_ifindex (platform, name); + g_return_val_if_fail (ifindex > 0, FALSE); + return _nm_platform_link_get (platform, ifindex, out_link); + } + return TRUE; +} + +static gboolean +link_add (NMPlatform *platform, + const char *name, + NMLinkType type, + const void *address, + size_t address_len, + NMPlatformLink *out_link) { struct nl_object *l; @@ -2343,7 +2447,11 @@ link_add (NMPlatform *platform, const char *name, NMLinkType type, const void *a rtnl_link_set_addr ((struct rtnl_link *) l, nladdr); } - return add_object (platform, l); + + if (!add_object (platform, l)) + return FALSE; + + return link_get_by_name (platform, name, out_link); } static struct rtnl_link * @@ -2771,6 +2879,15 @@ link_get_address (NMPlatform *platform, int ifindex, size_t *length) return a; } +static gboolean +link_get_permanent_address (NMPlatform *platform, + int ifindex, + guint8 *buf, + size_t *length) +{ + return ethtool_get_permanent_address (nm_platform_link_get_name (platform, ifindex), buf, length); +} + static gboolean link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu) { @@ -2834,7 +2951,12 @@ link_get_dev_id (NMPlatform *platform, int ifindex) } static int -vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint32 vlan_flags) +vlan_add (NMPlatform *platform, + const char *name, + int parent, + int vlan_id, + guint32 vlan_flags, + NMPlatformLink *out_link) { struct nl_object *object = build_rtnl_link (0, name, NM_LINK_TYPE_VLAN); struct rtnl_link *rtnllink = (struct rtnl_link *) object; @@ -2855,7 +2977,10 @@ vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint debug ("link: add vlan '%s', parent %d, vlan id %d, flags %X (native: %X)", name, parent, vlan_id, (unsigned int) vlan_flags, kernel_flags); - return add_object (platform, object); + if (!add_object (platform, object)) + return FALSE; + + return link_get_by_name (platform, name, out_link); } static gboolean @@ -3016,7 +3141,7 @@ slave_get_option (NMPlatform *platform, int slave, const char *option) } static gboolean -infiniband_partition_add (NMPlatform *platform, int parent, int p_key) +infiniband_partition_add (NMPlatform *platform, int parent, int p_key, NMPlatformLink *out_link) { const char *parent_name; char *path, *id; @@ -3033,9 +3158,12 @@ infiniband_partition_add (NMPlatform *platform, int parent, int p_key) if (success) { gs_free char *ifname = g_strdup_printf ("%s.%04x", parent_name, p_key); - auto_nl_object struct rtnl_link *rtnllink = _nm_rtnl_link_alloc (0, ifname); + auto_nl_object struct rtnl_link *rtnllink; + rtnllink = (struct rtnl_link *) build_rtnl_link (0, ifname, NM_LINK_TYPE_INFINIBAND); success = refresh_object (platform, (struct nl_object *) rtnllink, FALSE, NM_PLATFORM_REASON_INTERNAL); + if (success) + success = link_get_by_name (platform, ifname, out_link); } return success; @@ -3582,6 +3710,19 @@ link_get_wake_on_lan (NMPlatform *platform, int ifindex) return FALSE; } +static gboolean +link_get_driver_info (NMPlatform *platform, + int ifindex, + char **out_driver_name, + char **out_driver_version, + char **out_fw_version) +{ + return ethtool_get_driver_info (nm_platform_link_get_name (platform, ifindex), + out_driver_name, + out_driver_version, + out_fw_version); +} + /******************************************************************/ static gboolean @@ -4653,6 +4794,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->sysctl_get = sysctl_get; platform_class->link_get = _nm_platform_link_get; + platform_class->link_get_by_address = _nm_platform_link_get_by_address; platform_class->link_get_all = link_get_all; platform_class->link_add = link_add; platform_class->link_delete = link_delete; @@ -4679,12 +4821,14 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_get_address = link_get_address; platform_class->link_set_address = link_set_address; + platform_class->link_get_permanent_address = link_get_permanent_address; platform_class->link_get_mtu = link_get_mtu; platform_class->link_set_mtu = link_set_mtu; platform_class->link_get_physical_port_id = link_get_physical_port_id; platform_class->link_get_dev_id = link_get_dev_id; platform_class->link_get_wake_on_lan = link_get_wake_on_lan; + platform_class->link_get_driver_info = link_get_driver_info; platform_class->link_supports_carrier_detect = link_supports_carrier_detect; platform_class->link_supports_vlans = link_supports_vlans; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 844ad32cda..a02423ddeb 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -536,12 +536,40 @@ nm_platform_link_get (NMPlatform *self, int ifindex, NMPlatformLink *link) _CHECK_SELF (self, klass, FALSE); g_return_val_if_fail (ifindex > 0, FALSE); - g_return_val_if_fail (link, FALSE); g_return_val_if_fail (klass->link_get, FALSE); return !!klass->link_get (self, ifindex, link); } +/** + * nm_platform_link_get_by_address: + * @self: platform instance + * @address: a pointer to the binary hardware address + * @length: the size of @address in bytes + * @link: (out): output NMPlatformLink structure. + * + * If a link with given @address exists, fill the given NMPlatformLink + * structure. + * + * Returns: %TRUE, if such a link exists, %FALSE otherwise. + * If the link does not exist, the content of @link is undefined. + **/ +gboolean +nm_platform_link_get_by_address (NMPlatform *self, + gconstpointer address, + size_t length, + NMPlatformLink *link) +{ + _CHECK_SELF (self, klass, FALSE); + + g_return_val_if_fail (address != NULL, FALSE); + g_return_val_if_fail (length > 0, FALSE); + g_return_val_if_fail (link, FALSE); + + g_return_val_if_fail (klass->link_get_by_address, FALSE); + return !!klass->link_get_by_address (self, address, length, link); +} + /** * nm_platform_link_add: * @self: platform instance @@ -549,14 +577,24 @@ nm_platform_link_get (NMPlatform *self, int ifindex, NMPlatformLink *link) * @type: Interface type * @address: (allow-none): set the mac address of the link * @address_len: the length of the @address + * @out_link: on success, the link object * - * Add a software interface. Sets self->error to NM_PLATFORM_ERROR_EXISTS - * if interface is already already exists. Any link-changed ADDED signal will be - * emitted directly, before this function finishes. + * Add a software interface. If the interface already exists and is of type + * @type, sets platform->error to NM_PLATFORM_ERROR_EXISTS and returns the link + * in @out_link. If the interface already exists and is not of type @type, + * sets platform->error to NM_PLATFORM_ERROR_WRONG_TYPE. Any link-changed ADDED + * signal will be emitted directly, before this function finishes. */ static gboolean -nm_platform_link_add (NMPlatform *self, const char *name, NMLinkType type, const void *address, size_t address_len) +nm_platform_link_add (NMPlatform *self, + const char *name, + NMLinkType type, + const void *address, + size_t address_len, + NMPlatformLink *out_link) { + int ifindex; + _CHECK_SELF (self, klass, FALSE); reset_error (self); @@ -564,29 +602,37 @@ nm_platform_link_add (NMPlatform *self, const char *name, NMLinkType type, const g_return_val_if_fail (klass->link_add, FALSE); g_return_val_if_fail ( (address != NULL) ^ (address_len == 0) , FALSE); - if (nm_platform_link_exists (self, name)) { + ifindex = nm_platform_link_get_ifindex (self, name); + if (ifindex > 0) { debug ("link: already exists"); - self->error = NM_PLATFORM_ERROR_EXISTS; + if (nm_platform_link_get_type (self, ifindex) != type) + self->error = NM_PLATFORM_ERROR_WRONG_TYPE; + else { + self->error = NM_PLATFORM_ERROR_EXISTS; + (void) nm_platform_link_get (self, ifindex, out_link); + } return FALSE; } - return klass->link_add (self, name, type, address, address_len); + reset_error(self); + return klass->link_add (self, name, type, address, address_len, out_link); } /** * nm_platform_dummy_add: * @self: platform instance * @name: New interface name + * @out_link: on success, the link object * * Create a software ethernet-like interface */ gboolean -nm_platform_dummy_add (NMPlatform *self, const char *name) +nm_platform_dummy_add (NMPlatform *self, const char *name, NMPlatformLink *out_link) { g_return_val_if_fail (name, FALSE); debug ("link: adding dummy '%s'", name); - return nm_platform_link_add (self, name, NM_LINK_TYPE_DUMMY, NULL, 0); + return nm_platform_link_add (self, name, NM_LINK_TYPE_DUMMY, NULL, 0, out_link); } /** @@ -966,7 +1012,8 @@ nm_platform_link_set_address (NMPlatform *self, int ifindex, gconstpointer addre * @ifindex: Interface index * @length: Pointer to a variable to store address length * - * Saves interface hardware address to @address. + * Returns: the interface hardware address as an array of bytes of + * length @length. */ gconstpointer nm_platform_link_get_address (NMPlatform *self, int ifindex, size_t *length) @@ -983,6 +1030,34 @@ nm_platform_link_get_address (NMPlatform *self, int ifindex, size_t *length) return klass->link_get_address (self, ifindex, length); } +/** + * nm_platform_link_get_permanent_address: + * @self: platform instance + * @ifindex: Interface index + * @buf: buffer of at least %NM_UTILS_HWADDR_LEN_MAX bytes, on success + * the permanent hardware address + * @length: Pointer to a variable to store address length + * + * Returns: %TRUE on success, %FALSE on failure to read the permanent hardware + * address. + */ +gboolean +nm_platform_link_get_permanent_address (NMPlatform *self, int ifindex, guint8 *buf, size_t *length) +{ + _CHECK_SELF (self, klass, FALSE); + reset_error (self); + + if (length) + *length = 0; + + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (klass->link_get_permanent_address, FALSE); + g_return_val_if_fail (buf, FALSE); + g_return_val_if_fail (length, FALSE); + + return klass->link_get_permanent_address (self, ifindex, buf, length); +} + gboolean nm_platform_link_supports_carrier_detect (NMPlatform *self, int ifindex) { @@ -1195,6 +1270,38 @@ nm_platform_link_get_wake_on_lan (NMPlatform *self, int ifindex) return klass->link_get_wake_on_lan (self, ifindex); } +/** + * nm_platform_link_get_driver_info: + * @self: platform instance + * @ifindex: Interface index + * @out_driver_name: (transfer full): on success, the driver name if available + * @out_driver_version: (transfer full): on success, the driver version if available + * @out_fw_version: (transfer full): on success, the firmware version if available + * + * Returns: %TRUE on success (though @out_driver_name, @out_driver_version and + * @out_fw_version can be %NULL if no information was available), %FALSE on + * failure. + */ +gboolean +nm_platform_link_get_driver_info (NMPlatform *self, + int ifindex, + char **out_driver_name, + char **out_driver_version, + char **out_fw_version) +{ + _CHECK_SELF (self, klass, FALSE); + reset_error (self); + + g_return_val_if_fail (ifindex >= 0, FALSE); + g_return_val_if_fail (klass->link_get_driver_info, FALSE); + + return klass->link_get_driver_info (self, + ifindex, + out_driver_name, + out_driver_version, + out_fw_version); +} + /** * nm_platform_link_enslave: * @self: platform instance @@ -1277,42 +1384,49 @@ nm_platform_link_get_master (NMPlatform *self, int slave) * @name: New interface name * @address: (allow-none): set the mac address of the new bridge * @address_len: the length of the @address + * @out_link: on success, the link object * * Create a software bridge. */ gboolean -nm_platform_bridge_add (NMPlatform *self, const char *name, const void *address, size_t address_len) +nm_platform_bridge_add (NMPlatform *self, + const char *name, + const void *address, + size_t address_len, + NMPlatformLink *out_link) { debug ("link: adding bridge '%s'", name); - return nm_platform_link_add (self, name, NM_LINK_TYPE_BRIDGE, address, address_len); + return nm_platform_link_add (self, name, NM_LINK_TYPE_BRIDGE, address, address_len, out_link); } /** * nm_platform_bond_add: * @self: platform instance * @name: New interface name + * @out_link: on success, the link object * * Create a software bonding device. */ gboolean -nm_platform_bond_add (NMPlatform *self, const char *name) +nm_platform_bond_add (NMPlatform *self, const char *name, NMPlatformLink *out_link) { debug ("link: adding bond '%s'", name); - return nm_platform_link_add (self, name, NM_LINK_TYPE_BOND, NULL, 0); + return nm_platform_link_add (self, name, NM_LINK_TYPE_BOND, NULL, 0, out_link); } /** * nm_platform_team_add: * @self: platform instance * @name: New interface name + * @out_link: on success, the link object * * Create a software teaming device. */ gboolean -nm_platform_team_add (NMPlatform *self, const char *name) +nm_platform_team_add (NMPlatform *self, const char *name, NMPlatformLink *out_link) { debug ("link: adding team '%s'", name); - return nm_platform_link_add (self, name, NM_LINK_TYPE_TEAM, NULL, 0); + return nm_platform_link_add (self, name, NM_LINK_TYPE_TEAM, NULL, 0, out_link); } /** @@ -1321,11 +1435,17 @@ nm_platform_team_add (NMPlatform *self, const char *name) * @name: New interface name * @vlanid: VLAN identifier * @vlanflags: VLAN flags from libnm + * @out_link: on success, the link object * * Create a software VLAN device. */ gboolean -nm_platform_vlan_add (NMPlatform *self, const char *name, int parent, int vlanid, guint32 vlanflags) +nm_platform_vlan_add (NMPlatform *self, + const char *name, + int parent, + int vlanid, + guint32 vlanflags, + NMPlatformLink *out_link) { _CHECK_SELF (self, klass, FALSE); reset_error (self); @@ -1343,7 +1463,7 @@ nm_platform_vlan_add (NMPlatform *self, const char *name, int parent, int vlanid debug ("link: adding vlan '%s' parent %d vlanid %d vlanflags %x", name, parent, vlanid, vlanflags); - return klass->vlan_add (self, name, parent, vlanid, vlanflags); + return klass->vlan_add (self, name, parent, vlanid, vlanflags, out_link); } gboolean @@ -1444,7 +1564,7 @@ nm_platform_vlan_set_egress_map (NMPlatform *self, int ifindex, int from, int to } gboolean -nm_platform_infiniband_partition_add (NMPlatform *self, int parent, int p_key) +nm_platform_infiniband_partition_add (NMPlatform *self, int parent, int p_key, NMPlatformLink *out_link) { const char *parent_name; char *name; @@ -1471,7 +1591,7 @@ nm_platform_infiniband_partition_add (NMPlatform *self, int parent, int p_key) } g_free (name); - return klass->infiniband_partition_add (self, parent, p_key); + return klass->infiniband_partition_add (self, parent, p_key, out_link); } gboolean diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 1de8747a59..5341958586 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -374,8 +374,14 @@ typedef struct { char * (*sysctl_get) (NMPlatform *, const char *path); gboolean (*link_get) (NMPlatform *platform, int ifindex, NMPlatformLink *link); + gboolean (*link_get_by_address) (NMPlatform *platform, gconstpointer address, size_t length, NMPlatformLink *link); GArray *(*link_get_all) (NMPlatform *); - gboolean (*link_add) (NMPlatform *, const char *name, NMLinkType type, const void *address, size_t address_len); + gboolean (*link_add) (NMPlatform *, + const char *name, + NMLinkType type, + const void *address, + size_t address_len, + NMPlatformLink *out_link); gboolean (*link_delete) (NMPlatform *, int ifindex); int (*link_get_ifindex) (NMPlatform *, const char *name); const char *(*link_get_name) (NMPlatform *, int ifindex); @@ -399,6 +405,10 @@ typedef struct { gboolean (*link_set_user_ipv6ll_enabled) (NMPlatform *, int ifindex, gboolean enabled); gconstpointer (*link_get_address) (NMPlatform *, int ifindex, size_t *length); + gboolean (*link_get_permanent_address) (NMPlatform *, + int ifindex, + guint8 *buf, + size_t *length); gboolean (*link_set_address) (NMPlatform *, int ifindex, gconstpointer address, size_t length); guint32 (*link_get_mtu) (NMPlatform *, int ifindex); gboolean (*link_set_mtu) (NMPlatform *, int ifindex, guint32 mtu); @@ -406,6 +416,11 @@ typedef struct { char * (*link_get_physical_port_id) (NMPlatform *, int ifindex); guint (*link_get_dev_id) (NMPlatform *, int ifindex); gboolean (*link_get_wake_on_lan) (NMPlatform *, int ifindex); + gboolean (*link_get_driver_info) (NMPlatform *, + int ifindex, + char **out_driver_name, + char **out_driver_version, + char **out_fw_version); gboolean (*link_supports_carrier_detect) (NMPlatform *, int ifindex); gboolean (*link_supports_vlans) (NMPlatform *, int ifindex); @@ -418,12 +433,12 @@ typedef struct { gboolean (*slave_set_option) (NMPlatform *, int ifindex, const char *option, const char *value); char * (*slave_get_option) (NMPlatform *, int ifindex, const char *option); - gboolean (*vlan_add) (NMPlatform *, const char *name, int parent, int vlanid, guint32 vlanflags); + gboolean (*vlan_add) (NMPlatform *, const char *name, int parent, int vlanid, guint32 vlanflags, NMPlatformLink *out_link); gboolean (*vlan_get_info) (NMPlatform *, int ifindex, int *parent, int *vlan_id); gboolean (*vlan_set_ingress_map) (NMPlatform *, int ifindex, int from, int to); gboolean (*vlan_set_egress_map) (NMPlatform *, int ifindex, int from, int to); - gboolean (*infiniband_partition_add) (NMPlatform *, int parent, int p_key); + gboolean (*infiniband_partition_add) (NMPlatform *, int parent, int p_key, NMPlatformLink *out_link); gboolean (*veth_get_properties) (NMPlatform *, int ifindex, NMPlatformVethProperties *properties); gboolean (*tun_get_properties) (NMPlatform *, int ifindex, NMPlatformTunProperties *properties); @@ -526,10 +541,11 @@ gboolean nm_platform_sysctl_set_ip6_hop_limit_safe (NMPlatform *self, const char gboolean nm_platform_link_get (NMPlatform *self, int ifindex, NMPlatformLink *link); GArray *nm_platform_link_get_all (NMPlatform *self); -gboolean nm_platform_dummy_add (NMPlatform *self, const char *name); -gboolean nm_platform_bridge_add (NMPlatform *self, const char *name, const void *address, size_t address_len); -gboolean nm_platform_bond_add (NMPlatform *self, const char *name); -gboolean nm_platform_team_add (NMPlatform *self, const char *name); +gboolean nm_platform_link_get_by_address (NMPlatform *self, gconstpointer address, size_t length, NMPlatformLink *link); +gboolean nm_platform_dummy_add (NMPlatform *self, const char *name, NMPlatformLink *out_link); +gboolean nm_platform_bridge_add (NMPlatform *self, const char *name, const void *address, size_t address_len, NMPlatformLink *out_link); +gboolean nm_platform_bond_add (NMPlatform *self, const char *name, NMPlatformLink *out_link); +gboolean nm_platform_team_add (NMPlatform *self, const char *name, NMPlatformLink *out_link); gboolean nm_platform_link_exists (NMPlatform *self, const char *name); gboolean nm_platform_link_delete (NMPlatform *self, int ifindex); int nm_platform_link_get_ifindex (NMPlatform *self, const char *name); @@ -556,6 +572,7 @@ gboolean nm_platform_link_get_user_ipv6ll_enabled (NMPlatform *self, int ifindex gboolean nm_platform_link_set_user_ipv6ll_enabled (NMPlatform *self, int ifindex, gboolean enabled); gconstpointer nm_platform_link_get_address (NMPlatform *self, int ifindex, size_t *length); +gboolean nm_platform_link_get_permanent_address (NMPlatform *self, int ifindex, guint8 *buf, size_t *length); gboolean nm_platform_link_set_address (NMPlatform *self, int ifindex, const void *address, size_t length); guint32 nm_platform_link_get_mtu (NMPlatform *self, int ifindex); gboolean nm_platform_link_set_mtu (NMPlatform *self, int ifindex, guint32 mtu); @@ -563,6 +580,11 @@ gboolean nm_platform_link_set_mtu (NMPlatform *self, int ifindex, guint32 mtu); char *nm_platform_link_get_physical_port_id (NMPlatform *self, int ifindex); guint nm_platform_link_get_dev_id (NMPlatform *self, int ifindex); gboolean nm_platform_link_get_wake_on_lan (NMPlatform *self, int ifindex); +gboolean nm_platform_link_get_driver_info (NMPlatform *self, + int ifindex, + char **out_driver_name, + char **out_driver_version, + char **out_fw_version); gboolean nm_platform_link_supports_carrier_detect (NMPlatform *self, int ifindex); gboolean nm_platform_link_supports_vlans (NMPlatform *self, int ifindex); @@ -575,12 +597,12 @@ char *nm_platform_master_get_option (NMPlatform *self, int ifindex, const char * gboolean nm_platform_slave_set_option (NMPlatform *self, int ifindex, const char *option, const char *value); char *nm_platform_slave_get_option (NMPlatform *self, int ifindex, const char *option); -gboolean nm_platform_vlan_add (NMPlatform *self, const char *name, int parent, int vlanid, guint32 vlanflags); +gboolean nm_platform_vlan_add (NMPlatform *self, const char *name, int parent, int vlanid, guint32 vlanflags, NMPlatformLink *out_link); gboolean nm_platform_vlan_get_info (NMPlatform *self, int ifindex, int *parent, int *vlanid); gboolean nm_platform_vlan_set_ingress_map (NMPlatform *self, int ifindex, int from, int to); gboolean nm_platform_vlan_set_egress_map (NMPlatform *self, int ifindex, int from, int to); -gboolean nm_platform_infiniband_partition_add (NMPlatform *self, int parent, int p_key); +gboolean nm_platform_infiniband_partition_add (NMPlatform *self, int parent, int p_key, NMPlatformLink *out_link); gboolean nm_platform_veth_get_properties (NMPlatform *self, int ifindex, NMPlatformVethProperties *properties); gboolean nm_platform_tun_get_properties (NMPlatform *self, int ifindex, NMPlatformTunProperties *properties); diff --git a/src/platform/tests/platform.c b/src/platform/tests/platform.c index 07ca8f9108..d46d140abd 100644 --- a/src/platform/tests/platform.c +++ b/src/platform/tests/platform.c @@ -93,25 +93,25 @@ do_link_get_all (char **argv) static gboolean do_dummy_add (char **argv) { - return nm_platform_dummy_add (NM_PLATFORM_GET, argv[0]); + return nm_platform_dummy_add (NM_PLATFORM_GET, argv[0], NULL); } static gboolean do_bridge_add (char **argv) { - return nm_platform_bridge_add (NM_PLATFORM_GET, argv[0], NULL, 0); + return nm_platform_bridge_add (NM_PLATFORM_GET, argv[0], NULL, 0, NULL); } static gboolean do_bond_add (char **argv) { - return nm_platform_bond_add (NM_PLATFORM_GET, argv[0]); + return nm_platform_bond_add (NM_PLATFORM_GET, argv[0], NULL); } static gboolean do_team_add (char **argv) { - return nm_platform_team_add (NM_PLATFORM_GET, argv[0]); + return nm_platform_team_add (NM_PLATFORM_GET, argv[0], NULL); } static gboolean @@ -122,7 +122,7 @@ do_vlan_add (char **argv) int vlanid = strtol (*argv++, NULL, 10); guint32 vlan_flags = strtol (*argv++, NULL, 10); - return nm_platform_vlan_add (NM_PLATFORM_GET, name, parent, vlanid, vlan_flags); + return nm_platform_vlan_add (NM_PLATFORM_GET, name, parent, vlanid, vlan_flags, NULL); } static gboolean diff --git a/src/platform/tests/test-address.c b/src/platform/tests/test-address.c index 0547261551..e7b0a47388 100644 --- a/src/platform/tests/test-address.c +++ b/src/platform/tests/test-address.c @@ -259,7 +259,7 @@ setup_tests (void) nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME)); g_assert (!nm_platform_link_exists (NM_PLATFORM_GET, DEVICE_NAME)); - g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME)); + g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL)); accept_signal (link_added); free_signal (link_added); diff --git a/src/platform/tests/test-cleanup.c b/src/platform/tests/test-cleanup.c index 473489da81..962730463f 100644 --- a/src/platform/tests/test-cleanup.c +++ b/src/platform/tests/test-cleanup.c @@ -35,7 +35,7 @@ test_cleanup_internal (void) inet_pton (AF_INET6, "2001:db8:e:f:1:2:3:4", &gateway6); /* Create and set up device */ - g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME)); + g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL)); accept_signal (link_added); free_signal (link_added); g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME))); diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index d82d0165e6..bbd42946af 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -90,13 +90,13 @@ software_add (NMLinkType link_type, const char *name) { switch (link_type) { case NM_LINK_TYPE_DUMMY: - return nm_platform_dummy_add (NM_PLATFORM_GET, name); + return nm_platform_dummy_add (NM_PLATFORM_GET, name, NULL); case NM_LINK_TYPE_BRIDGE: - return nm_platform_bridge_add (NM_PLATFORM_GET, name, NULL, 0); + return nm_platform_bridge_add (NM_PLATFORM_GET, name, NULL, 0, NULL); case NM_LINK_TYPE_BOND: { gboolean bond0_exists = nm_platform_link_exists (NM_PLATFORM_GET, "bond0"); - gboolean result = nm_platform_bond_add (NM_PLATFORM_GET, name); + gboolean result = nm_platform_bond_add (NM_PLATFORM_GET, name, NULL); NMPlatformError error = nm_platform_get_error (NM_PLATFORM_GET); /* Check that bond0 is *not* automatically created. */ @@ -107,14 +107,14 @@ software_add (NMLinkType link_type, const char *name) return result; } case NM_LINK_TYPE_TEAM: - return nm_platform_team_add (NM_PLATFORM_GET, name); + return nm_platform_team_add (NM_PLATFORM_GET, name, NULL); case NM_LINK_TYPE_VLAN: { SignalData *parent_added; SignalData *parent_changed; /* Don't call link_callback for the bridge interface */ parent_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, PARENT_NAME); - if (nm_platform_bridge_add (NM_PLATFORM_GET, PARENT_NAME, NULL, 0)) + if (nm_platform_bridge_add (NM_PLATFORM_GET, PARENT_NAME, NULL, 0, NULL)) accept_signal (parent_added); free_signal (parent_added); @@ -126,7 +126,7 @@ software_add (NMLinkType link_type, const char *name) accept_signal (parent_changed); free_signal (parent_changed); - return nm_platform_vlan_add (NM_PLATFORM_GET, name, parent_ifindex, VLAN_ID, 0); + return nm_platform_vlan_add (NM_PLATFORM_GET, name, parent_ifindex, VLAN_ID, 0, NULL); } } default: @@ -403,12 +403,12 @@ test_internal (void) error (NM_PLATFORM_ERROR_NOT_FOUND); /* Add device */ - g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME)); + g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL)); no_error (); accept_signal (link_added); /* Try to add again */ - g_assert (!nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME)); + g_assert (!nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL)); error (NM_PLATFORM_ERROR_EXISTS); /* Check device index, name and type */ diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c index c22ce51571..dcc74d9621 100644 --- a/src/platform/tests/test-route.c +++ b/src/platform/tests/test-route.c @@ -324,7 +324,7 @@ setup_tests (void) nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME)); g_assert (!nm_platform_link_exists (NM_PLATFORM_GET, DEVICE_NAME)); - g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME)); + g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL)); accept_signal (link_added); free_signal (link_added); diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index 6100681502..2c0f8e3337 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -1590,6 +1590,9 @@ have_connection_for_device (NMSettings *self, NMDevice *device) NMConnection *connection = NM_CONNECTION (data); const char *ctype, *iface; + if (!nm_device_check_connection_compatible (device, connection)) + continue; + s_con = nm_connection_get_setting_connection (connection); iface = nm_setting_connection_get_interface_name (s_con); diff --git a/src/tests/test-route-manager.c b/src/tests/test-route-manager.c index 17bcb454c1..f7b37a3b4a 100644 --- a/src/tests/test-route-manager.c +++ b/src/tests/test-route-manager.c @@ -639,7 +639,7 @@ fixture_setup (test_fixture *fixture, gconstpointer user_data) "nm-test-device0"); nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, "nm-test-device0")); g_assert (!nm_platform_link_exists (NM_PLATFORM_GET, "nm-test-device0")); - g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, "nm-test-device0")); + g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, "nm-test-device0", NULL)); accept_signal (link_added); free_signal (link_added); fixture->ifindex0 = nm_platform_link_get_ifindex (NM_PLATFORM_GET, "nm-test-device0"); @@ -651,7 +651,7 @@ fixture_setup (test_fixture *fixture, gconstpointer user_data) "nm-test-device1"); nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, "nm-test-device1")); g_assert (!nm_platform_link_exists (NM_PLATFORM_GET, "nm-test-device1")); - g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, "nm-test-device1")); + g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, "nm-test-device1", NULL)); accept_signal (link_added); free_signal (link_added); fixture->ifindex1 = nm_platform_link_get_ifindex (NM_PLATFORM_GET, "nm-test-device1");