summary refs log tree commit diff
path: root/src/devices/nm-device-ethernet.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/nm-device-ethernet.c')
-rw-r--r--src/devices/nm-device-ethernet.c256
1 files changed, 87 insertions, 169 deletions
diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c
index ac408d3d..af2cb8f2 100644
--- a/src/devices/nm-device-ethernet.c
+++ b/src/devices/nm-device-ethernet.c
@@ -26,10 +26,6 @@
 #include <netinet/in.h>
 #include <string.h>
 #include <stdlib.h>
-#include <linux/sockios.h>
-#include <linux/ethtool.h>
-#include <linux/version.h>
-#include <sys/ioctl.h>
 #include <unistd.h>
 #include <errno.h>
 
@@ -48,6 +44,7 @@
 #include "nm-enum-types.h"
 #include "nm-dbus-manager.h"
 #include "nm-platform.h"
+#include "nm-platform-utils.h"
 #include "nm-dcb.h"
 #include "nm-settings-connection.h"
 #include "nm-config.h"
@@ -55,6 +52,7 @@
 #include "nm-connection-provider.h"
 #include "nm-device-factory.h"
 #include "nm-core-internal.h"
+#include "NetworkManagerUtils.h"
 
 #include "nm-device-ethernet-glue.h"
 
@@ -99,9 +97,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;
@@ -156,26 +151,21 @@ static void
 _update_s390_subchannels (NMDeviceEthernet *self)
 {
 	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
-	GUdevClient *client;
 	GUdevDevice *dev;
 	GUdevDevice *parent = NULL;
 	const char *parent_path, *item, *driver;
-	const char *subsystems[] = { "net", NULL };
+	int ifindex;
 	GDir *dir;
 	GError *error = NULL;
 
-	client = g_udev_client_new (subsystems);
-	if (!client) {
-		_LOGW (LOGD_DEVICE | LOGD_HW, "failed to initialize GUdev client");
-		return;
-	}
-
-	dev = g_udev_client_query_by_subsystem_and_name (client, "net",
-	                                                 nm_device_get_iface (NM_DEVICE (self)));
+	ifindex = nm_device_get_ifindex (NM_DEVICE (self));
+	dev = (GUdevDevice *) nm_platform_link_get_udev_device (NM_PLATFORM_GET, ifindex);
 	if (!dev) {
-		_LOGW (LOGD_DEVICE | LOGD_HW, "failed to find device with udev");
+		_LOGW (LOGD_DEVICE | LOGD_HW, "failed to find device %d '%s' with udev",
+		       ifindex, str_if_set (nm_device_get_iface (NM_DEVICE (self)), "(null)"));
 		goto out;
 	}
+	g_object_ref (dev);
 
 	/* Try for the "ccwgroup" parent */
 	parent = g_udev_device_get_parent_with_subsystem (dev, "ccwgroup", NULL);
@@ -210,7 +200,7 @@ _update_s390_subchannels (NMDeviceEthernet *self)
 		           || !strcmp (item, "portno")) {
 			char *path, *value;
 			path = g_strdup_printf ("%s/%s", parent_path, item);
-			value = nm_platform_sysctl_get (path);
+			value = nm_platform_sysctl_get (NM_PLATFORM_GET, path);
 			if (value && *value)
 				g_hash_table_insert (priv->s390_options, g_strdup (item), g_strdup (value));
 			else
@@ -247,7 +237,6 @@ out:
 		g_object_unref (parent);
 	if (dev)
 		g_object_unref (dev);
-	g_object_unref (client);
 }
 
 static GObject*
@@ -263,7 +252,7 @@ constructor (GType type,
 	if (object) {
 #ifndef G_DISABLE_ASSERT
 		int ifindex = nm_device_get_ifindex (NM_DEVICE (object));
-		NMLinkType link_type = nm_platform_link_get_type (ifindex);
+		NMLinkType link_type = nm_platform_link_get_type (NM_PLATFORM_GET, ifindex);
 
 		g_assert (   link_type == NM_LINK_TYPE_ETHERNET
 		          || link_type == NM_LINK_TYPE_VETH
@@ -310,72 +299,12 @@ 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 guint32
+static NMDeviceCapabilities
 get_generic_capabilities (NMDevice *device)
 {
 	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device);
 
-	if (nm_platform_link_supports_carrier_detect (nm_device_get_ifindex (device)))
+	if (nm_platform_link_supports_carrier_detect (NM_PLATFORM_GET, nm_device_get_ifindex (device)))
 	    return NM_DEVICE_CAP_CARRIER_DETECT;
 	else {
 		_LOGI (LOGD_HW, "driver '%s' does not support carrier detection.",
@@ -421,7 +350,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 +366,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 +374,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;
-			}
 
-			if (nm_utils_hwaddr_matches (mac_blacklist[i], -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 ();
+					return FALSE;
+				}
+
+				if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, perm_hw_addr, -1))
+					return FALSE;
+			}
+		} else if (mac)
+			return FALSE;
 	}
 
 	return TRUE;
@@ -1160,7 +1092,7 @@ dcb_state (NMDevice *device, gboolean timeout)
 	g_return_if_fail (nm_device_get_state (device) == NM_DEVICE_STATE_CONFIG);
 
 
-	carrier = nm_platform_link_is_connected (nm_device_get_ifindex (device));
+	carrier = nm_platform_link_is_connected (NM_PLATFORM_GET, nm_device_get_ifindex (device));
 	_LOGD (LOGD_DCB, "dcb_state() wait %d carrier %d timeout %d", priv->dcb_wait, carrier, timeout);
 
 	switch (priv->dcb_wait) {
@@ -1278,7 +1210,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason)
 	s_dcb = (NMSettingDcb *) device_get_setting (device, NM_TYPE_SETTING_DCB);
 	if (s_dcb) {
 		/* lldpad really really wants the carrier to be up */
-		if (nm_platform_link_is_connected (nm_device_get_ifindex (device))) {
+		if (nm_platform_link_is_connected (NM_PLATFORM_GET, nm_device_get_ifindex (device))) {
 			if (!dcb_enable (device)) {
 				*reason = NM_DEVICE_STATE_REASON_DCB_FCOE_FAILED;
 				return NM_ACT_STAGE_RETURN_FAILURE;
@@ -1391,8 +1323,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 +1334,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 +1364,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);
 		}
 	}
@@ -1463,7 +1396,7 @@ new_default_connection (NMDevice *self)
 	const char *hw_address;
 	char *defname, *uuid;
 
-	if (!nm_config_get_ethernet_can_auto_default (nm_config_get (), self))
+	if (nm_config_get_no_auto_default_for_device (nm_config_get (), self))
 		return NULL;
 
 	hw_address = nm_device_get_hw_address (self);
@@ -1495,15 +1428,19 @@ new_default_connection (NMDevice *self)
 	return connection;
 }
 
-static gboolean
+static NMMatchSpecMatchType
 spec_match_list (NMDevice *device, const GSList *specs)
 {
+	NMMatchSpecMatchType matched = NM_MATCH_SPEC_NO_MATCH, m;
 	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device);
 
-	if (priv->subchannels && nm_match_spec_s390_subchannels (specs, priv->subchannels))
-		return TRUE;
-
-	return NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->spec_match_list (device, specs);
+	if (priv->subchannels)
+		matched = nm_match_spec_s390_subchannels (specs, priv->subchannels);
+	if (matched != NM_MATCH_SPEC_NEG_MATCH) {
+		m = NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->spec_match_list (device, specs);
+		matched = MAX (matched, m);
+	}
+	return matched;
 }
 
 static void
@@ -1511,6 +1448,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;
@@ -1524,11 +1462,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;
 	}
 
@@ -1562,37 +1500,10 @@ get_link_speed (NMDevice *device)
 {
 	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device);
 	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
-	struct ifreq ifr;
-	struct ethtool_cmd edata = {
-		.cmd = ETHTOOL_GSET,
-	};
 	guint32 speed;
-	int fd;
 
-	fd = socket (PF_INET, SOCK_DGRAM, 0);
-	if (fd < 0) {
-		_LOGW (LOGD_HW | LOGD_ETHER, "couldn't open ethtool control socket.");
+	if (!nmp_utils_ethtool_get_link_speed (nm_device_get_iface (device), &speed))
 		return;
-	}
-
-	memset (&ifr, 0, sizeof (struct ifreq));
-	strncpy (ifr.ifr_name, nm_device_get_iface (device), IFNAMSIZ);
-	ifr.ifr_data = (char *) &edata;
-
-	if (ioctl (fd, SIOCETHTOOL, &ifr) < 0) {
-		close (fd);
-		return;
-	}
-	close (fd);
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
-	speed = edata.speed;
-#else
-	speed = ethtool_cmd_speed (&edata);
-#endif
-	if (speed == G_MAXUINT16 || speed == G_MAXUINT32)
-		speed = 0;
-
 	if (priv->speed == speed)
 		return;
 
@@ -1612,6 +1523,17 @@ carrier_changed (NMDevice *device, gboolean carrier)
 }
 
 static void
+link_changed (NMDevice *device, NMPlatformLink *info)
+{
+	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device);
+	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
+
+	NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->link_changed (device, info);
+	if (!priv->subchan1 && info->initialized)
+		_update_s390_subchannels (self);
+}
+
+static void
 dispose (GObject *object)
 {
 	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (object);
@@ -1634,8 +1556,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);
@@ -1656,7 +1576,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);
@@ -1696,8 +1616,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;
@@ -1710,6 +1628,7 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass)
 	parent_class->spec_match_list = spec_match_list;
 	parent_class->update_connection = update_connection;
 	parent_class->carrier_changed = carrier_changed;
+	parent_class->link_changed = link_changed;
 
 	parent_class->state_changed = device_state_changed;
 
@@ -1739,19 +1658,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;
 	)