commit 5074898591ae99f79b0cc4872c3c7cf018abee82
Author: Pavel Šimerda <psimerda@redhat.com>
Date:   Mon Jan 21 15:12:24 2013 +0100

    core: use nm-platform for link management

diff --git a/src/devices/nm-device-adsl.c b/src/devices/nm-device-adsl.c
index 53396b4..92f9e33 100644
--- a/src/devices/nm-device-adsl.c
+++ b/src/devices/nm-device-adsl.c
@@ -39,8 +39,8 @@
 #include "NetworkManagerUtils.h"
 #include "nm-logging.h"
 #include "nm-enum-types.h"
+#include "nm-platform.h"
 #include "nm-system.h"
-#include "nm-netlink-monitor.h"
 #include "nm-dbus-manager.h"
 #include "nm-platform.h"
 
@@ -167,10 +167,7 @@ set_nas_iface (NMDeviceAdsl *self, int idx, const char *name)
 	g_return_if_fail (name != NULL);
 
 	g_warn_if_fail (priv->nas_ifindex <= 0);
-	if (idx > 0)
-		priv->nas_ifindex = idx;
-	else
-		priv->nas_ifindex = nm_netlink_iface_to_index (name);
+	priv->nas_ifindex = idx > 0 ? idx : nm_platform_link_get_ifindex (name);
 	g_warn_if_fail (priv->nas_ifindex > 0);
 
 	g_warn_if_fail (priv->nas_ifname == NULL);
@@ -382,7 +379,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_reason)
 		nm_log_dbg (LOGD_ADSL, "(%s): ATM setup successful", nm_device_get_iface (device));
 
 		/* otherwise we're good for stage3 */
-		nm_system_iface_set_up (priv->nas_ifindex, TRUE, NULL);
+		nm_platform_link_set_up (priv->nas_ifindex);
 		ret = NM_ACT_STAGE_RETURN_SUCCESS;
 
 	} else if (g_strcmp0 (protocol, NM_SETTING_ADSL_PROTOCOL_PPPOA) == 0) {
diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c
index a15cc61..96459e2 100644
--- a/src/devices/nm-device-bond.c
+++ b/src/devices/nm-device-bond.c
@@ -30,7 +30,7 @@
 #include "nm-utils.h"
 #include "NetworkManagerUtils.h"
 #include "nm-device-private.h"
-#include "nm-netlink-monitor.h"
+#include "nm-platform.h"
 #include "nm-dbus-glib-types.h"
 #include "nm-dbus-manager.h"
 #include "nm-enum-types.h"
@@ -165,7 +165,7 @@ complete_connection (NMDevice *device,
 	while (i < 500 && !nm_setting_bond_get_interface_name (s_bond)) {
 		name = g_strdup_printf ("bond%u", i);
 		/* check interface names */
-		if (nm_netlink_iface_to_index (name) < 0) {
+		if (!nm_platform_link_exists (name)) {
 			/* check existing bond connections */
 			for (iter = existing_connections, found = FALSE; iter; iter = g_slist_next (iter)) {
 				NMConnection *candidate = iter->data;
@@ -236,10 +236,8 @@ enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection)
 
 	nm_device_hw_take_down (slave, TRUE);
 
-	success = nm_system_bond_enslave (nm_device_get_ip_ifindex (device),
-	                                  iface,
-	                                  nm_device_get_ip_ifindex (slave),
-	                                  slave_iface);
+	success = nm_platform_link_enslave (nm_device_get_ip_ifindex (device),
+	                                    nm_device_get_ip_ifindex (slave));
 
 	nm_device_hw_bring_up (slave, TRUE, &no_firmware);
 
@@ -256,10 +254,9 @@ release_slave (NMDevice *device, NMDevice *slave)
 {
 	gboolean success, no_firmware = FALSE;
 
-	success = nm_system_bond_release (nm_device_get_ip_ifindex (device),
-	                                  nm_device_get_ip_iface (device),
-	                                  nm_device_get_ip_ifindex (slave),
-	                                  nm_device_get_ip_iface (slave));
+	success = nm_platform_link_release (nm_device_get_ip_ifindex (device),
+	                                    nm_device_get_ip_ifindex (slave));
+
 	nm_log_info (LOGD_BOND, "(%s): released bond slave %s (success %d)",
 	             nm_device_get_ip_iface (device),
 	             nm_device_get_ip_iface (slave),
diff --git a/src/devices/nm-device-bridge.c b/src/devices/nm-device-bridge.c
index d85c0dd..e3ef1f9 100644
--- a/src/devices/nm-device-bridge.c
+++ b/src/devices/nm-device-bridge.c
@@ -30,10 +30,10 @@
 #include "nm-utils.h"
 #include "NetworkManagerUtils.h"
 #include "nm-device-private.h"
-#include "nm-netlink-monitor.h"
 #include "nm-dbus-glib-types.h"
 #include "nm-dbus-manager.h"
 #include "nm-enum-types.h"
+#include "nm-platform.h"
 #include "nm-system.h"
 
 #include "nm-device-bridge-glue.h"
@@ -144,7 +144,7 @@ complete_connection (NMDevice *device,
 	while (i < 500 && !nm_setting_bridge_get_interface_name (s_bridge)) {
 		name = g_strdup_printf ("br%u", i);
 		/* check interface names */
-		if (nm_netlink_iface_to_index (name) < 0) {
+		if (!nm_platform_link_exists (name)) {
 			/* check existing bridge connections */
 			for (iter = existing_connections, found = FALSE; iter; iter = g_slist_next (iter)) {
 				NMConnection *candidate = iter->data;
@@ -272,10 +272,9 @@ enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection)
 	const char *iface = nm_device_get_ip_iface (device);
 	const char *slave_iface = nm_device_get_ip_iface (slave);
 
-	success = nm_system_bridge_attach (nm_device_get_ip_ifindex (device),
-	                                   iface,
-	                                   nm_device_get_ip_ifindex (slave),
-	                                   slave_iface);
+	success = nm_platform_link_enslave (nm_device_get_ip_ifindex (device),
+	                                    nm_device_get_ip_ifindex (slave));
+
 	if (!success)
 		return FALSE;
 
@@ -299,10 +298,9 @@ release_slave (NMDevice *device, NMDevice *slave)
 {
 	gboolean success;
 
-	success = nm_system_bridge_detach (nm_device_get_ip_ifindex (device),
-	                                   nm_device_get_ip_iface (device),
-	                                   nm_device_get_ip_ifindex (slave),
-	                                   nm_device_get_ip_iface (slave));
+	success = nm_platform_link_release (nm_device_get_ip_ifindex (device),
+	                                    nm_device_get_ip_ifindex (slave));
+
 	nm_log_info (LOGD_BRIDGE, "(%s): detached bridge port %s (success %d)",
 	             nm_device_get_ip_iface (device),
 	             nm_device_get_ip_iface (slave),
diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c
index 0e556d3..d88a4a3 100644
--- a/src/devices/nm-device-ethernet.c
+++ b/src/devices/nm-device-ethernet.c
@@ -54,7 +54,6 @@
 #include "nm-logging.h"
 #include "nm-utils.h"
 #include "nm-enum-types.h"
-#include "nm-netlink-monitor.h"
 #include "nm-dbus-manager.h"
 #include "nm-platform.h"
 
@@ -231,7 +230,7 @@ constructor (GType type,
 	GObject *object;
 	NMDeviceEthernetPrivate *priv;
 	NMDevice *self;
-	int itype;
+	int ifindex;
 
 	object = G_OBJECT_CLASS (nm_device_ethernet_parent_class)->constructor (type,
 	                                                                        n_construct_params,
@@ -239,11 +238,9 @@ constructor (GType type,
 	if (object) {
 		self = NM_DEVICE (object);
 		priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
+		ifindex = nm_device_get_ifindex (self);
 
-		// FIXME: Convert this into a no-export property so type can be specified
-		//        when the device is created.
-		itype = nm_system_get_iface_type (nm_device_get_ifindex (self), nm_device_get_iface (self));
-		g_assert (itype == NM_IFACE_TYPE_UNSPEC);
+		g_assert (nm_platform_link_get_type (ifindex) == NM_LINK_TYPE_ETHERNET);
 
 		nm_log_dbg (LOGD_HW | LOGD_ETHER, "(%s): kernel ifindex %d",
 			        nm_device_get_iface (NM_DEVICE (self)),
@@ -365,7 +362,7 @@ _set_hw_addr (NMDeviceEthernet *self, const guint8 *addr, const char *detail)
 	/* Can't change MAC address while device is up */
 	nm_device_hw_take_down (dev, FALSE);
 
-	success = nm_system_iface_set_mac (nm_device_get_ip_ifindex (dev), (struct ether_addr *) addr);
+	success = nm_platform_link_set_address (nm_device_get_ip_ifindex (dev), addr, ETH_ALEN);
 	if (success) {
 		/* MAC address succesfully changed; update the current MAC to match */
 		nm_device_update_hw_address (dev);
diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c
index 3745369..be64dee 100644
--- a/src/devices/nm-device-vlan.c
+++ b/src/devices/nm-device-vlan.c
@@ -35,7 +35,7 @@
 #include "nm-enum-types.h"
 #include "nm-system.h"
 #include "nm-dbus-manager.h"
-#include "nm-netlink-monitor.h"
+#include "nm-platform.h"
 
 #include "nm-device-vlan-glue.h"
 
@@ -85,7 +85,7 @@ get_generic_capabilities (NMDevice *dev)
 static gboolean
 hw_bring_up (NMDevice *dev, gboolean *no_firmware)
 {
-	gboolean success = FALSE, carrier;
+	gboolean success = FALSE;
 	guint i = 20;
 
 	while (i-- > 0 && !success) {
@@ -93,33 +93,6 @@ hw_bring_up (NMDevice *dev, gboolean *no_firmware)
 		g_usleep (50);
 	}
 
-	if (success) {
-		/* Block a bit to make sure the carrier comes on; it's delayed a bit
-		 * after setting the interface up.
-		 */
-		i = 20;
-		while (i-- > 0) {
-			GError *error = NULL;
-			guint32 ifflags = 0;
-
-			if (!nm_netlink_monitor_get_flags_sync (nm_netlink_monitor_get (),
-			                                        nm_device_get_ifindex (dev),
-			                                        &ifflags, &error)) {
-				nm_log_warn (LOGD_DEVICE | LOGD_VLAN,
-				             "(%s): couldn't get carrier state: %s",
-				             nm_device_get_iface (dev),
-				             error->message);
-				g_clear_error (&error);
-				break;
-			}
-
-			carrier = !!(ifflags & IFF_LOWER_UP);
-			nm_device_set_carrier (dev, carrier);
-			if (carrier)
-				break;
-			g_usleep (100);
-		}
-	}
 	return success;
 }
 
@@ -352,14 +325,14 @@ nm_device_vlan_new (const char *udi, const char *iface, NMDevice *parent)
 		int parent_ifindex = -1, itype;
 		int vlan_id;
 
-		itype = nm_system_get_iface_type (ifindex, iface);
-		if (itype != NM_IFACE_TYPE_VLAN) {
+		itype = nm_platform_link_get_type (ifindex);
+		if (itype != NM_LINK_TYPE_VLAN) {
 			nm_log_err (LOGD_VLAN, "(%s): failed to get VLAN interface type.", iface);
 			g_object_unref (device);
 			return NULL;
 		}
 
-		if (!nm_system_get_iface_vlan_info (ifindex, &parent_ifindex, &vlan_id)) {
+		if (!nm_platform_vlan_get_info (ifindex, &parent_ifindex, &vlan_id)) {
 			nm_log_warn (LOGD_VLAN, "(%s): failed to get VLAN interface info.", iface);
 			g_object_unref (device);
 			return NULL;
diff --git a/src/devices/nm-device-wifi.c b/src/devices/nm-device-wifi.c
index 33ef53d..b83d0a4 100644
--- a/src/devices/nm-device-wifi.c
+++ b/src/devices/nm-device-wifi.c
@@ -33,7 +33,6 @@
 #include <linux/ethtool.h>
 #include <sys/ioctl.h>
 #include <netinet/ether.h>
-#include <net/if.h>
 #include <errno.h>
 
 #include "nm-glib-compat.h"
@@ -54,6 +53,7 @@
 #include "nm-setting-8021x.h"
 #include "nm-setting-ip4-config.h"
 #include "nm-setting-ip6-config.h"
+#include "nm-platform.h"
 #include "nm-system.h"
 #include "nm-manager-auth.h"
 #include "nm-settings-connection.h"
@@ -847,7 +847,7 @@ _set_hw_addr (NMDeviceWifi *self, const guint8 *addr, const char *detail)
 	/* Can't change MAC address while device is up */
 	nm_device_hw_take_down (dev, FALSE);
 
-	success = nm_system_iface_set_mac (nm_device_get_ip_ifindex (dev), (struct ether_addr *) addr);
+	success = nm_platform_link_set_address (nm_device_get_ip_ifindex (dev), addr, ETH_ALEN);
 	if (success) {
 		/* MAC address succesfully changed; update the current MAC to match */
 		nm_device_update_hw_address (dev);
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 112154c..4509fe3 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -42,12 +42,12 @@
 #include "nm-device-private.h"
 #include "nm-device-ethernet.h"
 #include "NetworkManagerUtils.h"
+#include "nm-platform.h"
 #include "nm-system.h"
 #include "nm-dhcp-manager.h"
 #include "nm-dbus-manager.h"
 #include "nm-utils.h"
 #include "nm-logging.h"
-#include "nm-netlink-monitor.h"
 #include "nm-netlink-utils.h"
 #include "nm-setting-ip4-config.h"
 #include "nm-setting-ip6-config.h"
@@ -213,6 +213,7 @@ typedef struct {
 	guint           carrier_defer_id;
 	gboolean        carrier;
 	gboolean        ignore_carrier;
+	guint           link_changed_id;
 
 	/* Generic DHCP stuff */
 	NMDHCPManager * dhcp_manager;
@@ -320,8 +321,7 @@ static void cp_connection_updated (NMConnectionProvider *cp, NMConnection *conne
 
 static const char *state_to_string (NMDeviceState state);
 
-static void link_connected_cb (NMNetlinkMonitor *monitor, int ifindex, NMDevice *device);
-static void link_disconnected_cb (NMNetlinkMonitor *monitor, int ifindex, NMDevice *device);
+static void link_changed_cb (NMPlatform *platform, int ifindex, NMPlatformLink *info, NMDevice *device);
 static void check_carrier (NMDevice *device);
 
 static void nm_device_queued_ip_config_change_clear (NMDevice *self);
@@ -558,19 +558,10 @@ constructed (GObject *object)
 		             priv->ignore_carrier ? " (but ignored)" : "");
 
 		if (!device_has_capability (dev, NM_DEVICE_CAP_NONSTANDARD_CARRIER)) {
-			NMNetlinkMonitor *netlink_monitor = nm_netlink_monitor_get ();
-
-			priv->link_connected_id = g_signal_connect (netlink_monitor, "carrier-on",
-			                                            G_CALLBACK (link_connected_cb), dev);
-			priv->link_disconnected_id = g_signal_connect (netlink_monitor, "carrier-off",
-			                                               G_CALLBACK (link_disconnected_cb), dev);
+			NMPlatform *platform = nm_platform_get ();
 
-			/* Request link state again just in case an error occurred getting the
-			 * initial link state.
-			 *
-			 * TODO: Check if this is necessary at all.
-			 */
-			nm_netlink_monitor_request_status (netlink_monitor);
+			priv->link_changed_id = g_signal_connect (platform, "link-changed",
+			                                          G_CALLBACK (link_changed_cb), dev);
 		}
 	} else {
 		/* Fake online link when carrier detection is not available. */
@@ -597,7 +588,7 @@ hw_is_up (NMDevice *device)
 {
 	int ifindex = nm_device_get_ip_ifindex (device);
 
-	return ifindex > 0 ? nm_system_iface_is_up (ifindex) : TRUE;
+	return ifindex ? nm_platform_link_is_up (ifindex) : TRUE;
 }
 
 void
@@ -686,7 +677,7 @@ nm_device_set_ip_iface (NMDevice *self, const char *iface)
 
 	priv->ip_iface = g_strdup (iface);
 	if (priv->ip_iface) {
-		priv->ip_ifindex = nm_netlink_iface_to_index (priv->ip_iface);
+		priv->ip_ifindex = nm_platform_link_get_ifindex (priv->ip_iface);
 		if (priv->ip_ifindex <= 0) {
 			/* Device IP interface must always be a kernel network interface */
 			nm_log_warn (LOGD_HW, "(%s): failed to look up interface index", iface);
@@ -1101,43 +1092,19 @@ nm_device_set_carrier (NMDevice *device, gboolean carrier)
 }
 
 static void
-link_connected_cb (NMNetlinkMonitor *monitor, int ifindex, NMDevice *device)
-{
-	if (ifindex == nm_device_get_ifindex (device))
-		nm_device_set_carrier (device, TRUE);
-}
-
-static void
-link_disconnected_cb (NMNetlinkMonitor *monitor, int ifindex, NMDevice *device)
+link_changed_cb (NMPlatform *platform, int ifindex, NMPlatformLink *info, NMDevice *device)
 {
 	if (ifindex == nm_device_get_ifindex (device))
-		nm_device_set_carrier (device, FALSE);
+		nm_device_set_carrier (device, info->connected);
 }
 
 static void
 check_carrier (NMDevice *device)
 {
-	GError *error = NULL;
-	guint32 ifflags = 0;
-
-	if (device_has_capability (device, NM_DEVICE_CAP_NONSTANDARD_CARRIER)) {
-		/* Don't try to get an updated state, just keep the old one. */
-		return;
-	}
-
-	if (!nm_netlink_monitor_get_flags_sync (nm_netlink_monitor_get (),
-	                                        nm_device_get_ip_ifindex (device),
-	                                        &ifflags,
-	                                        &error)) {
-		nm_log_warn (LOGD_DEVICE,
-		             "(%s): couldn't get carrier state: (%d) %s",
-		             nm_device_get_ip_iface (device),
-		             error ? error->code : -1,
-		             (error && error->message) ? error->message : "unknown");
-		g_clear_error (&error);
-	}
+	int ifindex = nm_device_get_ip_ifindex (device);
 
-	nm_device_set_carrier (device, !!(ifflags & IFF_LOWER_UP));
+	if (!device_has_capability (device, NM_DEVICE_CAP_NONSTANDARD_CARRIER))
+		nm_device_set_carrier (device, nm_platform_link_is_connected (ifindex));
 }
 
 static void
@@ -3289,8 +3256,8 @@ nm_device_activate_stage3_ip_config_start (gpointer user_data)
 
 	/* Make sure the interface is up before trying to do anything with it */
 	ifindex = nm_device_get_ip_ifindex (self);
-	if ((ifindex > 0) && (nm_system_iface_is_up (ifindex) == FALSE))
-		nm_system_iface_set_up (ifindex, TRUE, NULL);
+	if (ifindex && !nm_platform_link_is_up (ifindex))
+		nm_platform_link_set_up (ifindex);
 
 	priv->ip4_state = priv->ip6_state = IP_WAIT;
 
@@ -3707,8 +3674,8 @@ nm_device_activate_ip4_config_commit (gpointer user_data)
 
 	/* Make sure the interface is up again just because */
 	ifindex = nm_device_get_ip_ifindex (self);
-	if ((ifindex > 0) && (nm_system_iface_is_up (ifindex) == FALSE))
-		nm_system_iface_set_up (ifindex, TRUE, NULL);
+	if (ifindex && !nm_platform_link_is_up (ifindex))
+		nm_platform_link_set_up (ifindex);
 
 	/* Allow setting MTU etc */
 	if (NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit)
@@ -3824,8 +3791,8 @@ nm_device_activate_ip6_config_commit (gpointer user_data)
 
 	/* Make sure the interface is up again just because */
 	ifindex = nm_device_get_ip_ifindex (self);
-	if ((ifindex > 0) && (nm_system_iface_is_up (ifindex) == FALSE))
-		nm_system_iface_set_up (ifindex, TRUE, NULL);
+	if (ifindex && !nm_platform_link_is_up (ifindex))
+		nm_platform_link_set_up (ifindex);
 
 	/* Allow setting MTU etc */
 	if (NM_DEVICE_GET_CLASS (self)->ip6_config_pre_commit)
@@ -4508,7 +4475,8 @@ hw_bring_up (NMDevice *device, gboolean *no_firmware)
 	if (!ifindex)
 		return TRUE;
 
-	result = nm_system_iface_set_up (ifindex, TRUE, no_firmware);
+	result = nm_platform_link_set_up (ifindex);
+	*no_firmware = nm_platform_get_error () == NM_PLATFORM_ERROR_NO_FIRMWARE;
 
 	/* Store carrier immediately. */
 	if (result && device_has_capability (device, NM_DEVICE_CAP_CARRIER_DETECT))
@@ -4542,8 +4510,8 @@ hw_take_down (NMDevice *device)
 {
 	int ifindex = nm_device_get_ip_ifindex (device);
 
-	if (ifindex > 0)
-		nm_system_iface_set_up (ifindex, FALSE, NULL);
+	if (ifindex)
+		nm_platform_link_set_down (ifindex);
 }
 
 static gboolean
@@ -4659,10 +4627,8 @@ dispose (GObject *object)
 	}
 	g_free (priv->ip6_privacy_tempaddr_path);
 
-	if (priv->link_connected_id)
-		g_signal_handler_disconnect (nm_netlink_monitor_get (), priv->link_connected_id);
-	if (priv->link_disconnected_id)
-		g_signal_handler_disconnect (nm_netlink_monitor_get (), priv->link_disconnected_id);
+	if (priv->link_changed_id)
+		g_signal_handler_disconnect (nm_platform_get (), priv->link_changed_id);
 	if (priv->carrier_defer_id) {
 		g_source_remove (priv->carrier_defer_id);
 		priv->carrier_defer_id = 0;
@@ -4739,10 +4705,6 @@ set_property (GObject *object, guint prop_id,
  
 	switch (prop_id) {
 	case PROP_UDI:
-		/* Only virtual interfaces can set UDI post-construction */
-		if (priv->initialized)
-			g_return_if_fail (nm_system_get_iface_type (priv->ifindex, NULL) != NM_IFACE_TYPE_UNSPEC);
-
 		g_free (priv->udi);
 		priv->udi = g_strdup (g_value_get_string (value));
 		break;
@@ -4756,7 +4718,7 @@ set_property (GObject *object, guint prop_id,
 		 * the IP interface.
 		 */
 		if (priv->iface && !strchr (priv->iface, ':')) {
-			priv->ifindex = nm_netlink_iface_to_index (priv->iface);
+			priv->ifindex = nm_platform_link_get_ifindex (priv->iface);
 			if (priv->ifindex <= 0)
 				nm_log_warn (LOGD_HW, "(%s): failed to look up interface index", priv->iface);
 		}
@@ -6223,43 +6185,24 @@ nm_device_update_hw_address (NMDevice *dev)
 	priv->hw_addr_len = nm_device_get_hw_address_length (dev);
 
 	if (priv->hw_addr_len) {
-		struct rtnl_link *rtnl;
-		struct nl_addr *addr;
-		int idx;
+		int ifindex = nm_device_get_ip_ifindex (dev);
 		gsize addrlen;
 		const guint8 *binaddr;
 
-		idx = nm_device_get_ip_ifindex (dev);
-		g_return_val_if_fail (idx > 0, FALSE);
+		g_return_val_if_fail (ifindex > 0, FALSE);
 
-		rtnl = nm_netlink_index_to_rtnl_link (idx);
-		if (!rtnl) {
-			nm_log_err (LOGD_HW | LOGD_DEVICE,
-			            "(%s): failed to read hardware address (error %d)",
-			            nm_device_get_iface (dev), errno);
-			return FALSE;
-		}
+		binaddr = nm_platform_link_get_address (ifindex, &addrlen);
 
-		addr = rtnl_link_get_addr (rtnl);
-		if (!addr) {
-			nm_log_err (LOGD_HW | LOGD_DEVICE,
-			            "(%s): no hardware address?",
-			            nm_device_get_iface (dev));
-			rtnl_link_put (rtnl);
-			return FALSE;
-		}
-
-		addrlen = nl_addr_get_len (addr);
 		if (addrlen != priv->hw_addr_len) {
 			nm_log_err (LOGD_HW | LOGD_DEVICE,
 			            "(%s): hardware address is wrong length (got %zd, expected %d)",
 			            nm_device_get_iface (dev), addrlen, priv->hw_addr_len);
 		} else {
-			binaddr = nl_addr_get_binary_addr (addr);
-			changed = memcmp (priv->hw_addr, binaddr, addrlen) ? TRUE : FALSE;
-			memcpy (priv->hw_addr, binaddr, addrlen);
+			changed = !!memcmp (priv->hw_addr, binaddr, addrlen);
 			if (changed) {
 				char *addrstr = nm_utils_hwaddr_ntoa (binaddr, nm_utils_hwaddr_type (addrlen));
+
+				memcpy (priv->hw_addr, binaddr, addrlen);
 				nm_log_dbg (LOGD_HW | LOGD_DEVICE,
 				            "(%s): hardware address is %s",
 				            nm_device_get_iface (dev), addrstr);
@@ -6267,8 +6210,6 @@ nm_device_update_hw_address (NMDevice *dev)
 				g_object_notify (G_OBJECT (dev), NM_DEVICE_HW_ADDRESS);
 			}
 		}
-
-		rtnl_link_put (rtnl);
 	} else {
 		int i;
 
diff --git a/src/ip6-manager/nm-ip6-manager.c b/src/ip6-manager/nm-ip6-manager.c
index dcb28d6..77a491f 100644
--- a/src/ip6-manager/nm-ip6-manager.c
+++ b/src/ip6-manager/nm-ip6-manager.c
@@ -34,6 +34,7 @@
 #include "NetworkManagerUtils.h"
 #include "nm-logging.h"
 #include "nm-utils.h"
+#include "nm-platform.h"
 
 /* Pre-DHCP addrconf timeout, in seconds */
 #define NM_IP6_TIMEOUT 20
@@ -183,7 +184,7 @@ nm_ip6_device_new (NMIP6Manager *manager,
 
 	device = g_slice_new0 (NMIP6Device);
 	device->ifindex = ifindex;
-	device->iface = nm_netlink_index_to_iface (ifindex);
+	device->iface = g_strdup (nm_platform_link_get_name (ifindex));
 	if (!device->iface) {
 		nm_log_err (LOGD_IP6, "(%d): could not find interface name from index.",
 		            ifindex);
diff --git a/src/main.c b/src/main.c
index 5de7662..2e71072 100644
--- a/src/main.c
+++ b/src/main.c
@@ -590,7 +590,7 @@ main (int argc, char *argv[])
 	 * physical interfaces.
 	 */
 	nm_log_dbg (LOGD_CORE, "setting up local loopback");
-	nm_system_iface_set_up (nm_netlink_iface_to_index ("lo"), TRUE, NULL);
+	nm_platform_link_set_up (nm_platform_link_get_ifindex ("lo"));
 
 	success = TRUE;
 
diff --git a/src/modem-manager/nm-modem.c b/src/modem-manager/nm-modem.c
index 7ec5176..c7d3126 100644
--- a/src/modem-manager/nm-modem.c
+++ b/src/modem-manager/nm-modem.c
@@ -21,6 +21,7 @@
 
 #include <string.h>
 #include "nm-modem.h"
+#include "nm-platform.h"
 #include "nm-system.h"
 #include "nm-dbus-manager.h"
 #include "nm-setting-connection.h"
@@ -323,7 +324,7 @@ nm_modem_ip4_pre_commit (NMModem *modem,
 
 		g_assert (addr);
 		if (nm_ip4_address_get_prefix (addr) == 32)
-			nm_system_iface_set_arp (nm_device_get_ip_ifindex (device), FALSE);
+			nm_platform_link_set_noarp (nm_device_get_ip_ifindex (device));
 	}
 }
 
@@ -534,7 +535,7 @@ deactivate (NMModem *self, NMDevice *device)
 		if (ifindex > 0) {
 			nm_system_iface_flush_routes (ifindex, AF_UNSPEC);
 			nm_system_iface_flush_addresses (ifindex, AF_UNSPEC);
-			nm_system_iface_set_up (ifindex, FALSE, NULL);
+			nm_platform_link_set_down (ifindex);
 		}
 		break;
 	default:
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 656807f..d35aca7 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -57,6 +57,7 @@
 #include "nm-setting-wireless.h"
 #include "nm-setting-vpn.h"
 #include "nm-dbus-glib-types.h"
+#include "nm-platform.h"
 #include "nm-udev-manager.h"
 #include "nm-hostname-provider.h"
 #include "nm-bluez-manager.h"
@@ -1238,7 +1239,7 @@ system_create_virtual_device (NMManager *self, NMConnection *connection)
 	}
 
 	if (nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME)) {
-		if (!nm_system_add_bonding_master (iface)) {
+		if (!nm_platform_bond_add (iface)) {
 			nm_log_warn (LOGD_DEVICE, "(%s): failed to add bonding master interface for '%s'",
 			             iface, nm_connection_get_id (connection));
 			goto out;
@@ -1248,16 +1249,17 @@ system_create_virtual_device (NMManager *self, NMConnection *connection)
 		device = nm_device_bond_new (udi, iface);
 		g_free (udi);
 	} else if (nm_connection_is_type (connection, NM_SETTING_BRIDGE_SETTING_NAME)) {
-		gboolean exists = FALSE;
+		gboolean result;
 
-		if (!nm_system_create_bridge (iface, &exists)) {
+		result = nm_platform_bridge_add (iface);
+		if (!result && nm_platform_get_error () != NM_PLATFORM_ERROR_EXISTS) {
 			nm_log_warn (LOGD_DEVICE, "(%s): failed to add bridging interface for '%s'",
 			             iface, nm_connection_get_id (connection));
 			goto out;
 		}
 
 		/* FIXME: remove when we handle bridges non-destructively */
-		if (exists && !bridge_created_by_nm (self, iface)) {
+		if (!result && !bridge_created_by_nm (self, iface)) {
 			nm_log_warn (LOGD_DEVICE, "(%s): cannot use existing bridge for '%s'",
 			             iface, nm_connection_get_id (connection));
 			goto out;
@@ -1267,13 +1269,28 @@ system_create_virtual_device (NMManager *self, NMConnection *connection)
 		device = nm_device_bridge_new (udi, iface);
 		g_free (udi);
 	} else if (nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME)) {
-		g_return_val_if_fail (parent != NULL, FALSE);
-
-		if (!nm_system_add_vlan_iface (connection, iface, nm_device_get_ip_ifindex (parent))) {
+		NMSettingVlan *s_vlan = nm_connection_get_setting_vlan (connection);
+		int ifindex = nm_device_get_ip_ifindex (parent);
+		int num, i;
+		guint32 from, to;
+
+		if (!nm_platform_vlan_add (iface, ifindex,
+				nm_setting_vlan_get_id (s_vlan),
+				nm_setting_vlan_get_flags (s_vlan))) {
 			nm_log_warn (LOGD_DEVICE, "(%s): failed to add VLAN interface for '%s'",
 			             iface, nm_connection_get_id (connection));
 			goto out;
 		}
+		num = nm_setting_vlan_get_num_priorities (s_vlan, NM_VLAN_INGRESS_MAP);
+		for (i = 0; i < num; i++) {
+			if (nm_setting_vlan_get_priority (s_vlan, NM_VLAN_INGRESS_MAP, i, &from, &to))
+				nm_platform_vlan_set_ingress_map (ifindex, from, to);
+		}
+		num = nm_setting_vlan_get_num_priorities (s_vlan, NM_VLAN_EGRESS_MAP);
+		for (i = 0; i < num; i++) {
+			if (nm_setting_vlan_get_priority (s_vlan, NM_VLAN_EGRESS_MAP, i, &from, &to))
+				nm_platform_vlan_set_egress_map (ifindex, from, to);
+		}
 		udi = get_virtual_iface_placeholder_udi ();
 		device = nm_device_vlan_new (udi, iface, parent);
 		g_free (udi);
@@ -2151,19 +2168,19 @@ is_infiniband (GUdevDevice *device)
 static gboolean
 is_bond (int ifindex)
 {
-	return (nm_system_get_iface_type (ifindex, NULL) == NM_IFACE_TYPE_BOND);
+	return (nm_platform_link_get_type (ifindex) == NM_LINK_TYPE_BOND);
 }
 
 static gboolean
 is_bridge (int ifindex)
 {
-	return (nm_system_get_iface_type (ifindex, NULL) == NM_IFACE_TYPE_BRIDGE);
+	return (nm_platform_link_get_type (ifindex) == NM_LINK_TYPE_BRIDGE);
 }
 
 static gboolean
 is_vlan (int ifindex)
 {
-	return (nm_system_get_iface_type (ifindex, NULL) == NM_IFACE_TYPE_VLAN);
+	return (nm_platform_link_get_type (ifindex) == NM_LINK_TYPE_VLAN);
 }
 
 static gboolean
@@ -2196,8 +2213,7 @@ udev_device_added_cb (NMUdevManager *udev_mgr,
 		device = find_device_by_ifindex (self, ifindex);
 		if (device) {
 			/* If it's a virtual device we may need to update its UDI */
-			if (nm_system_get_iface_type (ifindex, iface) != NM_IFACE_TYPE_UNSPEC)
-				g_object_set (G_OBJECT (device), NM_DEVICE_UDI, sysfs_path, NULL);
+			g_object_set (G_OBJECT (device), NM_DEVICE_UDI, sysfs_path, NULL);
 			return;
 		}
 	} else {
@@ -2253,7 +2269,7 @@ udev_device_added_cb (NMUdevManager *udev_mgr,
 			NMDevice *parent;
 
 			/* Have to find the parent device */
-			if (nm_system_get_iface_vlan_info (ifindex, &parent_ifindex, NULL)) {
+			if (nm_platform_vlan_get_info (ifindex, &parent_ifindex, NULL)) {
 				parent = find_device_by_ifindex (self, parent_ifindex);
 				if (parent)
 					device = nm_device_vlan_new (sysfs_path, iface, parent);
diff --git a/src/nm-udev-manager.c b/src/nm-udev-manager.c
index 41cbbe6..5759394 100644
--- a/src/nm-udev-manager.c
+++ b/src/nm-udev-manager.c
@@ -28,6 +28,7 @@
 
 #include "nm-udev-manager.h"
 #include "nm-logging.h"
+#include "nm-platform.h"
 #include "nm-system.h"
 
 typedef struct {
@@ -397,14 +398,14 @@ dev_get_attrs (GUdevDevice *udev_device,
 		ifindex = g_udev_device_get_sysfs_attr_as_int (udev_device, "ifindex");
 
 	if (!driver) {
-		switch (nm_system_get_iface_type (ifindex, ifname)) {
-		case NM_IFACE_TYPE_BOND:
+		switch (nm_platform_link_get_type (ifindex)) {
+		case NM_LINK_TYPE_BOND:
 			driver = "bonding";
 			break;
-		case NM_IFACE_TYPE_BRIDGE:
+		case NM_LINK_TYPE_BRIDGE:
 			driver = "bridge";
 			break;
-		case NM_IFACE_TYPE_VLAN:
+		case NM_LINK_TYPE_VLAN:
 			driver = "8021q";
 			break;
 		default:
diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c
index a494c21..bfa3853 100644
--- a/src/vpn-manager/nm-vpn-connection.c
+++ b/src/vpn-manager/nm-vpn-connection.c
@@ -34,6 +34,7 @@
 #include "nm-setting-vpn.h"
 #include "nm-setting-ip4-config.h"
 #include "nm-dbus-manager.h"
+#include "nm-platform.h"
 #include "nm-system.h"
 #include "nm-logging.h"
 #include "nm-utils.h"
@@ -41,7 +42,6 @@
 #include "nm-properties-changed-signal.h"
 #include "nm-dbus-glib-types.h"
 #include "NetworkManagerUtils.h"
-#include "nm-netlink-monitor.h"
 #include "nm-netlink-utils.h"
 #include "nm-glib-compat.h"
 #include "settings/nm-settings-connection.h"
@@ -165,7 +165,7 @@ vpn_cleanup (NMVPNConnection *connection)
 	NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
 
 	if (priv->ip_ifindex) {
-		nm_system_iface_set_up (priv->ip_ifindex, FALSE, NULL);
+		nm_platform_link_set_down (priv->ip_ifindex);
 		nm_system_iface_flush_routes (priv->ip_ifindex, AF_UNSPEC);
 		nm_system_iface_flush_addresses (priv->ip_ifindex, AF_UNSPEC);
 	}
@@ -598,7 +598,7 @@ nm_vpn_connection_apply_config (NMVPNConnection *connection)
 {
 	NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
 
-	nm_system_iface_set_up (priv->ip_ifindex, TRUE, NULL);
+	nm_platform_link_set_up (priv->ip_ifindex);
 
 	if (priv->ip4_config) {
 		if (!nm_system_apply_ip4_config (priv->ip_ifindex, priv->ip4_config,
@@ -690,8 +690,8 @@ process_generic_config (NMVPNConnection *connection,
 	}
 
 	/* Grab the interface index for address/routing operations */
-	priv->ip_ifindex = nm_netlink_iface_to_index (priv->ip_iface);
-	if (priv->ip_ifindex <= 0) {
+	priv->ip_ifindex = nm_platform_link_get_ifindex (priv->ip_iface);
+	if (priv->ip_ifindex < 0) {
 		nm_log_err (LOGD_VPN, "(%s): failed to look up VPN interface index", priv->ip_iface);
 		nm_vpn_connection_config_maybe_complete (connection, FALSE);
 		return FALSE;
