summary refs log tree commit diff
path: root/src/platform
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2015-01-22 00:29:39 +0100
committerMichael Biebl <biebl@debian.org>2015-01-22 00:29:39 +0100
commit2c032d8f1c6292c1338a615e6ec40252889ba85c (patch)
tree1f77182220b2b0264288ba4a476ab47e5bc48716 /src/platform
parent33491bc4279481db8ae47213e34a6d695a0e8830 (diff)
Imported Upstream version 1.0.0 upstream/1.0.0
Diffstat (limited to 'src/platform')
-rw-r--r--src/platform/Makefile.in6
-rw-r--r--src/platform/nm-fake-platform.c108
-rw-r--r--src/platform/nm-fake-platform.h6
-rw-r--r--src/platform/nm-linux-platform.c623
-rw-r--r--src/platform/nm-linux-platform.h6
-rw-r--r--src/platform/nm-platform.c293
-rw-r--r--src/platform/nm-platform.h201
-rw-r--r--src/platform/tests/Makefile.am9
-rw-r--r--src/platform/tests/Makefile.in16
-rw-r--r--src/platform/tests/dump.c6
-rw-r--r--src/platform/tests/monitor.c2
-rw-r--r--src/platform/tests/platform.c28
-rw-r--r--src/platform/tests/test-address.c8
-rw-r--r--src/platform/tests/test-cleanup.c24
-rw-r--r--src/platform/tests/test-common.c2
-rw-r--r--src/platform/tests/test-link.c13
-rw-r--r--src/platform/tests/test-route.c48
-rw-r--r--src/platform/wifi/wifi-utils-nl80211.c59
-rw-r--r--src/platform/wifi/wifi-utils-nl80211.h8
-rw-r--r--src/platform/wifi/wifi-utils-private.h12
-rw-r--r--src/platform/wifi/wifi-utils-wext.c19
-rw-r--r--src/platform/wifi/wifi-utils-wext.h6
-rw-r--r--src/platform/wifi/wifi-utils.c23
-rw-r--r--src/platform/wifi/wifi-utils.h16
24 files changed, 1017 insertions, 525 deletions
diff --git a/src/platform/Makefile.in b/src/platform/Makefile.in
index 9358879f..d4c8ade7 100644
--- a/src/platform/Makefile.in
+++ b/src/platform/Makefile.in
@@ -189,6 +189,8 @@ AUTOCONF = @AUTOCONF@
 AUTOHEADER = @AUTOHEADER@
 AUTOMAKE = @AUTOMAKE@
 AWK = @AWK@
+BLUEZ5_CFLAGS = @BLUEZ5_CFLAGS@
+BLUEZ5_LIBS = @BLUEZ5_LIBS@
 CC = @CC@
 CCDEPMODE = @CCDEPMODE@
 CFLAGS = @CFLAGS@
@@ -312,6 +314,7 @@ NEWT_CFLAGS = @NEWT_CFLAGS@
 NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
+NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
 NM_MICRO_VERSION = @NM_MICRO_VERSION@
 NM_MINOR_VERSION = @NM_MINOR_VERSION@
@@ -331,6 +334,7 @@ PACKAGE_TARNAME = @PACKAGE_TARNAME@
 PACKAGE_URL = @PACKAGE_URL@
 PACKAGE_VERSION = @PACKAGE_VERSION@
 PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
 PKG_CONFIG = @PKG_CONFIG@
 PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
 PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
@@ -357,7 +361,7 @@ SYSTEMD_INHIBIT_LIBS = @SYSTEMD_INHIBIT_LIBS@
 SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@
 SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
-UDEV_BASE_DIR = @UDEV_BASE_DIR@
+UDEV_DIR = @UDEV_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c
index 46272217..a5eb7d4e 100644
--- a/src/platform/nm-fake-platform.c
+++ b/src/platform/nm-fake-platform.c
@@ -18,11 +18,14 @@
  * Copyright (C) 2012–2013 Red Hat, Inc.
  */
 
+#include "config.h"
+
 #include <errno.h>
 #include <unistd.h>
 #include <netinet/icmp6.h>
 #include <netinet/in.h>
 
+#include "gsystem-local-alloc.h"
 #include "NetworkManagerUtils.h"
 #include "nm-fake-platform.h"
 #include "nm-logging.h"
@@ -162,12 +165,12 @@ link_get_all (NMPlatform *platform)
 }
 
 static gboolean
-_nm_platform_link_get (NMPlatform *platform, int ifindex, NMPlatformLink *link)
+_nm_platform_link_get (NMPlatform *platform, int ifindex, NMPlatformLink *l)
 {
 	NMFakePlatformLink *device = link_get (platform, ifindex);
 
 	if (device)
-		*link = device->link;
+		*l = device->link;
 	return !!device;
 }
 
@@ -543,7 +546,7 @@ link_get_master (NMPlatform *platform, int slave)
 static gboolean
 master_set_option (NMPlatform *platform, int master, const char *option, const char *value)
 {
-	auto_g_free char *path = g_strdup_printf ("master:%d:%s", master, option);
+	gs_free char *path = g_strdup_printf ("master:%d:%s", master, option);
 
 	return sysctl_set (platform, path, value);
 }
@@ -551,7 +554,7 @@ master_set_option (NMPlatform *platform, int master, const char *option, const c
 static char *
 master_get_option (NMPlatform *platform, int master, const char *option)
 {
-	auto_g_free char *path = g_strdup_printf ("master:%d:%s", master, option);
+	gs_free char *path = g_strdup_printf ("master:%d:%s", master, option);
 
 	return sysctl_get (platform, path);
 }
@@ -559,7 +562,7 @@ master_get_option (NMPlatform *platform, int master, const char *option)
 static gboolean
 slave_set_option (NMPlatform *platform, int slave, const char *option, const char *value)
 {
-	auto_g_free char *path = g_strdup_printf ("slave:%d:%s", slave, option);
+	gs_free char *path = g_strdup_printf ("slave:%d:%s", slave, option);
 
 	return sysctl_set (platform, path, value);
 }
@@ -567,7 +570,7 @@ slave_set_option (NMPlatform *platform, int slave, const char *option, const cha
 static char *
 slave_get_option (NMPlatform *platform, int slave, const char *option)
 {
-	auto_g_free char *path = g_strdup_printf ("slave:%d:%s", slave, option);
+	gs_free char *path = g_strdup_printf ("slave:%d:%s", slave, option);
 
 	return sysctl_get (platform, path);
 }
@@ -688,7 +691,7 @@ wifi_get_capabilities (NMPlatform *platform, int ifindex, NMDeviceWifiCapabiliti
 }
 
 static gboolean
-wifi_get_bssid (NMPlatform *platform, int ifindex, struct ether_addr *bssid)
+wifi_get_bssid (NMPlatform *platform, int ifindex, guint8 *bssid)
 {
 	return FALSE;
 }
@@ -754,7 +757,7 @@ mesh_set_channel (NMPlatform *platform, int ifindex, guint32 channel)
 }
 
 static gboolean
-mesh_set_ssid (NMPlatform *platform, int ifindex, const GByteArray *ssid)
+mesh_set_ssid (NMPlatform *platform, int ifindex, const guint8 *ssid, gsize len)
 {
 	return FALSE;
 }
@@ -827,7 +830,7 @@ ip4_address_add (NMPlatform *platform, int ifindex,
 	int i;
 
 	memset (&address, 0, sizeof (address));
-	address.source = NM_PLATFORM_SOURCE_KERNEL;
+	address.source = NM_IP_CONFIG_SOURCE_KERNEL;
 	address.ifindex = ifindex;
 	address.address = addr;
 	address.peer_address = peer_addr;
@@ -869,7 +872,7 @@ ip6_address_add (NMPlatform *platform, int ifindex,
 	int i;
 
 	memset (&address, 0, sizeof (address));
-	address.source = NM_PLATFORM_SOURCE_KERNEL;
+	address.source = NM_IP_CONFIG_SOURCE_KERNEL;
 	address.ifindex = ifindex;
 	address.address = addr;
 	address.peer_address = peer_addr;
@@ -901,7 +904,7 @@ ip6_address_add (NMPlatform *platform, int ifindex,
 }
 
 static gboolean
-ip4_address_delete (NMPlatform *platform, int ifindex, in_addr_t addr, int plen)
+ip4_address_delete (NMPlatform *platform, int ifindex, in_addr_t addr, int plen, in_addr_t peer_address)
 {
 	NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
 	int i;
@@ -909,7 +912,8 @@ ip4_address_delete (NMPlatform *platform, int ifindex, in_addr_t addr, int plen)
 	for (i = 0; i < priv->ip4_addresses->len; i++) {
 		NMPlatformIP4Address *address = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i);
 
-		if (address->ifindex == ifindex && address->plen == plen && address->address == addr) {
+		if (address->ifindex == ifindex && address->plen == plen && address->address == addr &&
+		    (!peer_address || address->peer_address == peer_address)) {
 			NMPlatformIP4Address deleted_address;
 
 			memcpy (&deleted_address, address, sizeof (deleted_address));
@@ -978,31 +982,37 @@ ip6_address_exists (NMPlatform *platform, int ifindex, struct in6_addr addr, int
 	return FALSE;
 }
 
+static gboolean
+ip4_check_reinstall_device_route (NMPlatform *platform, int ifindex, const NMPlatformIP4Address *address, guint32 device_route_metric)
+{
+	return FALSE;
+}
+
 /******************************************************************/
 
 static GArray *
-ip4_route_get_all (NMPlatform *platform, int ifindex, gboolean include_default)
+ip4_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteMode mode)
 {
 	NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
 	GArray *routes;
 	NMPlatformIP4Route *route;
-	int count = 0, i;
+	guint i;
 
-	/* Count routes */
-	for (i = 0; i < priv->ip4_routes->len; i++) {
-		route = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i);
-		if (route && route->ifindex == ifindex)
-			count++;
-	}
+	g_return_val_if_fail (NM_IN_SET (mode, NM_PLATFORM_GET_ROUTE_MODE_ALL, NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT, NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT), NULL);
 
-	routes = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformIP4Route), count);
+	routes = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP4Route));
 
 	/* Fill routes */
 	for (i = 0; i < priv->ip4_routes->len; i++) {
 		route = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i);
-		if (route && route->ifindex == ifindex) {
-			if (route->plen != 0 || include_default)
-				g_array_append_val (routes, *route);
+		if (route && (!ifindex || route->ifindex == ifindex)) {
+			if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) {
+				if (mode != NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT)
+					g_array_append_val (routes, *route);
+			} else {
+				if (mode != NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT)
+					g_array_append_val (routes, *route);
+			}
 		}
 	}
 
@@ -1010,28 +1020,28 @@ ip4_route_get_all (NMPlatform *platform, int ifindex, gboolean include_default)
 }
 
 static GArray *
-ip6_route_get_all (NMPlatform *platform, int ifindex, gboolean include_default)
+ip6_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteMode mode)
 {
 	NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
 	GArray *routes;
 	NMPlatformIP6Route *route;
-	int count = 0, i;
+	guint i;
 
-	/* Count routes */
-	for (i = 0; i < priv->ip6_routes->len; i++) {
-		route = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i);
-		if (route && route->ifindex == ifindex)
-			count++;
-	}
+	g_return_val_if_fail (NM_IN_SET (mode, NM_PLATFORM_GET_ROUTE_MODE_ALL, NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT, NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT), NULL);
 
-	routes = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformIP6Route), count);
+	routes = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP6Route));
 
 	/* Fill routes */
 	for (i = 0; i < priv->ip6_routes->len; i++) {
 		route = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i);
-		if (route && route->ifindex == ifindex) {
-			if (route->plen != 0 || include_default)
-				g_array_append_val (routes, *route);
+		if (route && (!ifindex || route->ifindex == ifindex)) {
+			if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) {
+				if (mode != NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT)
+					g_array_append_val (routes, *route);
+			} else {
+				if (mode != NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT)
+					g_array_append_val (routes, *route);
+			}
 		}
 	}
 
@@ -1039,16 +1049,16 @@ ip6_route_get_all (NMPlatform *platform, int ifindex, gboolean include_default)
 }
 
 static gboolean
-ip4_route_add (NMPlatform *platform, int ifindex, NMPlatformSource source,
+ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
                in_addr_t network, int plen, in_addr_t gateway,
-               int metric, int mss)
+               guint32 pref_src, guint32 metric, guint32 mss)
 {
 	NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
 	NMPlatformIP4Route route;
 	guint i;
 
 	memset (&route, 0, sizeof (route));
-	route.source = NM_PLATFORM_SOURCE_KERNEL;
+	route.source = NM_IP_CONFIG_SOURCE_KERNEL;
 	route.ifindex = ifindex;
 	route.source = source;
 	route.network = network;
@@ -1079,16 +1089,16 @@ ip4_route_add (NMPlatform *platform, int ifindex, NMPlatformSource source,
 }
 
 static gboolean
-ip6_route_add (NMPlatform *platform, int ifindex, NMPlatformSource source,
+ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
                struct in6_addr network, int plen, struct in6_addr gateway,
-               int metric, int mss)
+               guint32 metric, guint32 mss)
 {
 	NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
 	NMPlatformIP6Route route;
 	guint i;
 
 	memset (&route, 0, sizeof (route));
-	route.source = NM_PLATFORM_SOURCE_KERNEL;
+	route.source = NM_IP_CONFIG_SOURCE_KERNEL;
 	route.ifindex = ifindex;
 	route.source = source;
 	route.network = network;
@@ -1119,7 +1129,7 @@ ip6_route_add (NMPlatform *platform, int ifindex, NMPlatformSource source,
 }
 
 static NMPlatformIP4Route *
-ip4_route_get (NMPlatform *platform, int ifindex, in_addr_t network, int plen, int metric)
+ip4_route_get (NMPlatform *platform, int ifindex, in_addr_t network, int plen, guint32 metric)
 {
 	NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
 	int i;
@@ -1138,7 +1148,7 @@ ip4_route_get (NMPlatform *platform, int ifindex, in_addr_t network, int plen, i
 }
 
 static NMPlatformIP6Route *
-ip6_route_get (NMPlatform *platform, int ifindex, struct in6_addr network, int plen, int metric)
+ip6_route_get (NMPlatform *platform, int ifindex, struct in6_addr network, int plen, guint32 metric)
 {
 	NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
 	int i;
@@ -1157,7 +1167,7 @@ ip6_route_get (NMPlatform *platform, int ifindex, struct in6_addr network, int p
 }
 
 static gboolean
-ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, int plen, int metric)
+ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, int plen, guint32 metric)
 {
 	NMPlatformIP4Route *route = ip4_route_get (platform, ifindex, network, plen, metric);
 	NMPlatformIP4Route deleted_route;
@@ -1172,7 +1182,7 @@ ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, int plen
 }
 
 static gboolean
-ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, int plen, int metric)
+ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, int plen, guint32 metric)
 {
 	NMPlatformIP6Route *route = ip6_route_get (platform, ifindex, network, plen, metric);
 	NMPlatformIP6Route deleted_route;
@@ -1187,13 +1197,13 @@ ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, in
 }
 
 static gboolean
-ip4_route_exists (NMPlatform *platform, int ifindex, in_addr_t network, int plen, int metric)
+ip4_route_exists (NMPlatform *platform, int ifindex, in_addr_t network, int plen, guint32 metric)
 {
 	return !!ip4_route_get (platform, ifindex, network, plen, metric);
 }
 
 static gboolean
-ip6_route_exists (NMPlatform *platform, int ifindex, struct in6_addr network, int plen, int metric)
+ip6_route_exists (NMPlatform *platform, int ifindex, struct in6_addr network, int plen, guint32 metric)
 {
 	return !!ip6_route_get (platform, ifindex, network, plen, metric);
 }
@@ -1341,6 +1351,8 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass)
 	platform_class->ip4_address_exists = ip4_address_exists;
 	platform_class->ip6_address_exists = ip6_address_exists;
 
+	platform_class->ip4_check_reinstall_device_route = ip4_check_reinstall_device_route;
+
 	platform_class->ip4_route_get_all = ip4_route_get_all;
 	platform_class->ip6_route_get_all = ip6_route_get_all;
 	platform_class->ip4_route_add = ip4_route_add;
diff --git a/src/platform/nm-fake-platform.h b/src/platform/nm-fake-platform.h
index c9fa42eb..53a2ff1a 100644
--- a/src/platform/nm-fake-platform.h
+++ b/src/platform/nm-fake-platform.h
@@ -18,8 +18,8 @@
  * Copyright (C) 2012 Red Hat, Inc.
  */
 
-#ifndef NM_FAKE_PLATFORM_H
-#define NM_FAKE_PLATFORM_H
+#ifndef __NETWORKMANAGER_FAKE_PLATFORM_H__
+#define __NETWORKMANAGER_FAKE_PLATFORM_H__
 
 #include "nm-platform.h"
 
@@ -46,4 +46,4 @@ GType nm_fake_platform_get_type (void);
 
 void nm_fake_platform_setup (void);
 
-#endif /* NM_FAKE_PLATFORM_H */
+#endif /* __NETWORKMANAGER_FAKE_PLATFORM_H__ */
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index f73ff320..5d1522ce 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -17,7 +17,7 @@
  *
  * Copyright (C) 2012-2013 Red Hat, Inc.
  */
-#include <config.h>
+#include "config.h"
 
 #include <errno.h>
 #include <unistd.h>
@@ -44,6 +44,17 @@
 #include <netlink/route/route.h>
 #include <gudev/gudev.h>
 
+#if HAVE_LIBNL_INET6_ADDR_GEN_MODE
+#include <netlink/route/link/inet6.h>
+#if HAVE_KERNEL_INET6_ADDR_GEN_MODE
+#include <linux/if_link.h>
+#else
+#define IN6_ADDR_GEN_MODE_EUI64 0
+#define IN6_ADDR_GEN_MODE_NONE  1
+#endif
+#endif
+
+#include "gsystem-local-alloc.h"
 #include "NetworkManagerUtils.h"
 #include "nm-linux-platform.h"
 #include "NetworkManagerUtils.h"
@@ -83,6 +94,7 @@ typedef struct {
 	GHashTable *wifi_data;
 
 	int support_kernel_extended_ifa_flags;
+	int support_user_ipv6ll;
 } NMLinuxPlatformPrivate;
 
 #define NM_LINUX_PLATFORM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_LINUX_PLATFORM, NMLinuxPlatformPrivate))
@@ -90,6 +102,8 @@ typedef struct {
 G_DEFINE_TYPE (NMLinuxPlatform, nm_linux_platform, NM_TYPE_PLATFORM)
 
 static const char *to_string_object (NMPlatform *platform, struct nl_object *obj);
+static gboolean _address_match (struct rtnl_addr *addr, int family, int ifindex);
+static gboolean _route_match (struct rtnl_route *rtnlroute, int family, int ifindex, gboolean include_proto_kernel);
 
 void
 nm_linux_platform_setup (void)
@@ -106,7 +120,7 @@ _nl_f_nl_has_capability (int capability)
 }
 
 static struct libnl_vtable *
-_nl_get_vtable ()
+_nl_get_vtable (void)
 {
 	static struct libnl_vtable vtable;
 
@@ -268,7 +282,7 @@ _nm_rtnl_addr_alloc (int ifindex)
 }
 
 static struct rtnl_route *
-_nm_rtnl_route_alloc ()
+_nm_rtnl_route_alloc (void)
 {
 	struct rtnl_route *rtnlroute = rtnl_route_alloc ();
 
@@ -278,7 +292,7 @@ _nm_rtnl_route_alloc ()
 }
 
 static struct rtnl_nexthop *
-_nm_rtnl_route_nh_alloc ()
+_nm_rtnl_route_nh_alloc (void)
 {
 	struct rtnl_nexthop *nexthop;
 
@@ -596,8 +610,8 @@ ethtool_get (const char *name, gpointer edata)
 static int
 ethtool_get_stringset_index (const char *ifname, int stringset_id, const char *string)
 {
-	auto_g_free struct ethtool_sset_info *info = NULL;
-	auto_g_free struct ethtool_gstrings *strings = NULL;
+	gs_free struct ethtool_sset_info *info = NULL;
+	gs_free struct ethtool_gstrings *strings = NULL;
 	guint32 len, i;
 
 	info = g_malloc0 (sizeof (*info) + sizeof (guint32));
@@ -667,6 +681,23 @@ check_support_kernel_extended_ifa_flags (NMPlatform *platform)
 	return priv->support_kernel_extended_ifa_flags > 0;
 }
 
+static gboolean
+check_support_user_ipv6ll (NMPlatform *platform)
+{
+	NMLinuxPlatformPrivate *priv;
+
+	g_return_val_if_fail (NM_IS_LINUX_PLATFORM (platform), FALSE);
+
+	priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
+
+	if (priv->support_user_ipv6ll == 0) {
+		nm_log_warn (LOGD_PLATFORM, "Unable to detect kernel support for IFLA_INET6_ADDR_GEN_MODE. Assume no kernel support.");
+		priv->support_user_ipv6ll = -1;
+	}
+
+	return priv->support_user_ipv6ll > 0;
+}
+
 
 /* Object type specific utilities */
 
@@ -735,7 +766,7 @@ link_type_from_udev (NMPlatform *platform, int ifindex, const char *ifname, int
 
 	prop = g_udev_device_get_property (udev_device, "DEVTYPE");
 	sysfs_path = g_udev_device_get_sysfs_path (udev_device);
-	if (g_strcmp0 (prop, "wlan") == 0 || wifi_utils_is_wifi (ifname, sysfs_path))
+	if (wifi_utils_is_wifi (ifname, sysfs_path, prop))
 		return_type (NM_LINK_TYPE_WIFI, "wifi");
 	else if (g_strcmp0 (prop, "wwan") == 0)
 		return_type (NM_LINK_TYPE_WWAN_ETHERNET, "wwan");
@@ -1176,7 +1207,7 @@ init_ip4_address (NMPlatformIP4Address *address, struct rtnl_addr *rtnladdr)
 
 	memset (address, 0, sizeof (*address));
 
-	address->source = NM_PLATFORM_SOURCE_KERNEL;
+	address->source = NM_IP_CONFIG_SOURCE_KERNEL;
 	address->ifindex = rtnl_addr_get_ifindex (rtnladdr);
 	address->plen = rtnl_addr_get_prefixlen (rtnladdr);
 	_init_ip_address_lifetime ((NMPlatformIPAddress *) address, rtnladdr);
@@ -1208,7 +1239,7 @@ init_ip6_address (NMPlatformIP6Address *address, struct rtnl_addr *rtnladdr)
 
 	memset (address, 0, sizeof (*address));
 
-	address->source = NM_PLATFORM_SOURCE_KERNEL;
+	address->source = NM_IP_CONFIG_SOURCE_KERNEL;
 	address->ifindex = rtnl_addr_get_ifindex (rtnladdr);
 	address->plen = rtnl_addr_get_prefixlen (rtnladdr);
 	_init_ip_address_lifetime ((NMPlatformIPAddress *) address, rtnladdr);
@@ -1230,16 +1261,16 @@ init_ip6_address (NMPlatformIP6Address *address, struct rtnl_addr *rtnladdr)
 }
 
 static guint
-source_to_rtprot (NMPlatformSource source)
+source_to_rtprot (NMIPConfigSource source)
 {
 	switch (source) {
-	case NM_PLATFORM_SOURCE_UNKNOWN:
+	case NM_IP_CONFIG_SOURCE_UNKNOWN:
 		return RTPROT_UNSPEC;
-	case NM_PLATFORM_SOURCE_KERNEL:
+	case NM_IP_CONFIG_SOURCE_KERNEL:
 		return RTPROT_KERNEL;
-	case NM_PLATFORM_SOURCE_DHCP:
+	case NM_IP_CONFIG_SOURCE_DHCP:
 		return RTPROT_DHCP;
-	case NM_PLATFORM_SOURCE_RDISC:
+	case NM_IP_CONFIG_SOURCE_RDISC:
 		return RTPROT_RA;
 
 	default:
@@ -1247,26 +1278,36 @@ source_to_rtprot (NMPlatformSource source)
 	}
 }
 
-static NMPlatformSource
+static NMIPConfigSource
 rtprot_to_source (guint rtprot)
 {
 	switch (rtprot) {
 	case RTPROT_UNSPEC:
-		return NM_PLATFORM_SOURCE_UNKNOWN;
+		return NM_IP_CONFIG_SOURCE_UNKNOWN;
 	case RTPROT_REDIRECT:
 	case RTPROT_KERNEL:
-		return NM_PLATFORM_SOURCE_KERNEL;
+		return NM_IP_CONFIG_SOURCE_KERNEL;
 	case RTPROT_RA:
-		return NM_PLATFORM_SOURCE_RDISC;
+		return NM_IP_CONFIG_SOURCE_RDISC;
 	case RTPROT_DHCP:
-		return NM_PLATFORM_SOURCE_DHCP;
+		return NM_IP_CONFIG_SOURCE_DHCP;
 
 	default:
-		return NM_PLATFORM_SOURCE_USER;
+		return NM_IP_CONFIG_SOURCE_USER;
 	}
 }
 
 static gboolean
+_rtnl_route_is_default (const struct rtnl_route *rtnlroute)
+{
+	struct nl_addr *dst;
+
+	return    rtnlroute
+	       && (dst = rtnl_route_get_dst ((struct rtnl_route *) rtnlroute))
+	       && nl_addr_get_prefixlen (dst) == 0;
+}
+
+static gboolean
 init_ip4_route (NMPlatformIP4Route *route, struct rtnl_route *rtnlroute)
 {
 	struct nl_addr *dst, *gw;
@@ -1527,8 +1568,20 @@ announce_object (NMPlatform *platform, const struct nl_object *object, NMPlatfor
 	switch (object_type) {
 	case OBJECT_TYPE_LINK:
 		{
-			NMPlatformLink device;
 			struct rtnl_link *rtnl_link = (struct rtnl_link *) object;
+			NMPlatformLink device;
+
+#if HAVE_LIBNL_INET6_ADDR_GEN_MODE
+			/* If we ever see a link with valid IPv6 link-local address
+			 * generation modes, the kernel supports it.
+			 */
+			if (priv->support_user_ipv6ll == 0) {
+				uint8_t mode;
+
+				if (rtnl_link_inet6_get_addr_gen_mode (rtnl_link, &mode) == 0)
+					priv->support_user_ipv6ll = 1;
+			}
+#endif
 
 			if (!init_link (platform, &device, rtnl_link))
 				return;
@@ -1576,20 +1629,25 @@ announce_object (NMPlatform *platform, const struct nl_object *object, NMPlatfor
 		{
 			NMPlatformIP4Address address;
 
-			if (!init_ip4_address (&address, (struct rtnl_addr *) object))
-				return;
-
 			/* Address deletion is sometimes accompanied by route deletion. We need to
 			 * check all routes belonging to the same interface.
 			 */
 			switch (change_type) {
 			case NM_PLATFORM_SIGNAL_REMOVED:
-				check_cache_items (platform, priv->route_cache, address.ifindex);
+				check_cache_items (platform,
+				                   priv->route_cache,
+				                   rtnl_addr_get_ifindex ((struct rtnl_addr *) object));
 				break;
 			default:
 				break;
 			}
 
+			if (!_address_match ((struct rtnl_addr *) object, AF_INET, 0)) {
+				nm_log_dbg (LOGD_PLATFORM, "skip announce unmatching IP4 address %s", to_string_ip4_address ((struct rtnl_addr *) object));
+				return;
+			}
+			if (!init_ip4_address (&address, (struct rtnl_addr *) object))
+				return;
 			g_signal_emit_by_name (platform, sig, address.ifindex, &address, change_type, reason);
 		}
 		return;
@@ -1597,6 +1655,10 @@ announce_object (NMPlatform *platform, const struct nl_object *object, NMPlatfor
 		{
 			NMPlatformIP6Address address;
 
+			if (!_address_match ((struct rtnl_addr *) object, AF_INET6, 0)) {
+				nm_log_dbg (LOGD_PLATFORM, "skip announce unmatching IP6 address %s", to_string_ip6_address ((struct rtnl_addr *) object));
+				return;
+			}
 			if (!init_ip6_address (&address, (struct rtnl_addr *) object))
 				return;
 			g_signal_emit_by_name (platform, sig, address.ifindex, &address, change_type, reason);
@@ -1606,6 +1668,10 @@ announce_object (NMPlatform *platform, const struct nl_object *object, NMPlatfor
 		{
 			NMPlatformIP4Route route;
 
+			if (!_route_match ((struct rtnl_route *) object, AF_INET, 0, FALSE)) {
+				nm_log_dbg (LOGD_PLATFORM, "skip announce unmatching IP4 route %s", to_string_ip4_route ((struct rtnl_route *) object));
+				return;
+			}
 			if (init_ip4_route (&route, (struct rtnl_route *) object))
 				g_signal_emit_by_name (platform, sig, route.ifindex, &route, change_type, reason);
 		}
@@ -1614,6 +1680,10 @@ announce_object (NMPlatform *platform, const struct nl_object *object, NMPlatfor
 		{
 			NMPlatformIP6Route route;
 
+			if (!_route_match ((struct rtnl_route *) object, AF_INET6, 0, FALSE)) {
+				nm_log_dbg (LOGD_PLATFORM, "skip announce unmatching IP6 route %s", to_string_ip6_route ((struct rtnl_route *) object));
+				return;
+			}
 			if (init_ip6_route (&route, (struct rtnl_route *) object))
 				g_signal_emit_by_name (platform, sig, route.ifindex, &route, change_type, reason);
 		}
@@ -1721,15 +1791,14 @@ add_object (NMPlatform *platform, struct nl_object *obj)
 
 /* Decreases the reference count if @obj for convenience */
 static gboolean
-delete_object (NMPlatform *platform, struct nl_object *obj, gboolean do_refresh_object)
+delete_object (NMPlatform *platform, struct nl_object *object, gboolean do_refresh_object)
 {
 	NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
-	auto_nl_object struct nl_object *obj_cleanup = obj;
-	struct nl_object *object = obj;
 	int object_type;
 	int nle;
+	gboolean result = FALSE;
 
-	object_type = object_type_from_nl_object (obj);
+	object_type = object_type_from_nl_object (object);
 	g_return_val_if_fail (object_type != OBJECT_TYPE_UNKNOWN, FALSE);
 
 	switch (object_type) {
@@ -1772,14 +1841,18 @@ delete_object (NMPlatform *platform, struct nl_object *obj, gboolean do_refresh_
 		goto DEFAULT;
 	DEFAULT:
 	default:
-		error ("Netlink error deleting %s: %s (%d)", to_string_object (platform, obj), nl_geterror (nle), nle);
-		return FALSE;
+		error ("Netlink error deleting %s: %s (%d)", to_string_object (platform, object), nl_geterror (nle), nle);
+		goto out;
 	}
 
 	if (do_refresh_object)
 		refresh_object (platform, object, TRUE, NM_PLATFORM_REASON_INTERNAL);
 
-	return TRUE;
+	result = TRUE;
+
+out:
+	nl_object_put (object);
+	return result;
 }
 
 static void
@@ -1807,6 +1880,33 @@ _rtnl_addr_timestamps_equal_fuzzy (guint32 ts1, guint32 ts2)
 	return diff <= 2;
 }
 
+static gboolean
+nm_nl_object_diff (ObjectType type, struct nl_object *_a, struct nl_object *_b)
+{
+	if (nl_object_diff (_a, _b)) {
+		/* libnl thinks objects are different*/
+		return TRUE;
+	}
+
+	if (type == OBJECT_TYPE_IP4_ADDRESS || type == OBJECT_TYPE_IP6_ADDRESS) {
+		struct rtnl_addr *a = (struct rtnl_addr *) _a;
+		struct rtnl_addr *b = (struct rtnl_addr *) _b;
+
+		/* libnl nl_object_diff() ignores differences in timestamp. Let's care about
+		 * them (if they are large enough).
+		 *
+		 * Note that these valid and preferred timestamps are absolute, after
+		 * _rtnl_addr_hack_lifetimes_rel_to_abs(). */
+		if (   !_rtnl_addr_timestamps_equal_fuzzy (rtnl_addr_get_preferred_lifetime (a),
+							  rtnl_addr_get_preferred_lifetime (b))
+		    || !_rtnl_addr_timestamps_equal_fuzzy (rtnl_addr_get_valid_lifetime (a),
+							  rtnl_addr_get_valid_lifetime (b)))
+			return TRUE;
+	}
+
+	return FALSE;
+}
+
 /* This function does all the magic to avoid race conditions caused
  * by concurrent usage of synchronous commands and an asynchronous cache. This
  * might be a nice future addition to libnl but it requires to do all operations
@@ -1912,24 +2012,9 @@ event_notification (struct nl_msg *msg, gpointer user_data)
 		 * This also catches notifications for internal addition or change, unless
 		 * another action occured very soon after it.
 		 */
-		if (!nl_object_diff (kernel_object, cached_object)) {
-			if (type == OBJECT_TYPE_IP4_ADDRESS || type == OBJECT_TYPE_IP6_ADDRESS) {
-				struct rtnl_addr *c = (struct rtnl_addr *) cached_object;
-				struct rtnl_addr *k = (struct rtnl_addr *) kernel_object;
-
-				/* libnl nl_object_diff() ignores differences in timestamp. Let's care about
-				 * them (if they are large enough).
-				 *
-				 * Note that these valid and preferred timestamps are absolute, after
-				 * _rtnl_addr_hack_lifetimes_rel_to_abs(). */
-				if (   _rtnl_addr_timestamps_equal_fuzzy (rtnl_addr_get_preferred_lifetime (c),
-				                                          rtnl_addr_get_preferred_lifetime (k))
-				    && _rtnl_addr_timestamps_equal_fuzzy (rtnl_addr_get_valid_lifetime (c),
-				                                          rtnl_addr_get_valid_lifetime (k)))
-					return NL_OK;
-			} else
-				return NL_OK;
-		}
+		if (!nm_nl_object_diff (type, kernel_object, cached_object))
+			return NL_OK;
+
 		/* Handle external change */
 		nl_cache_remove (cached_object);
 		nle = nl_cache_add (cache, kernel_object);
@@ -2133,7 +2218,7 @@ link_get_all (NMPlatform *platform)
 }
 
 static gboolean
-_nm_platform_link_get (NMPlatform *platform, int ifindex, NMPlatformLink *link)
+_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;
@@ -2141,7 +2226,7 @@ _nm_platform_link_get (NMPlatform *platform, int ifindex, NMPlatformLink *link)
 	rtnllink = rtnl_link_get (priv->link_cache, ifindex);
 	if (rtnllink) {
 		if (link_is_announceable (platform, rtnllink)) {
-			if (init_link (platform, link, rtnllink))
+			if (init_link (platform, l, rtnllink))
 				return TRUE;
 		}
 	}
@@ -2166,7 +2251,7 @@ static gboolean
 link_add (NMPlatform *platform, const char *name, NMLinkType type, const void *address, size_t address_len)
 {
 	int r;
-	struct nl_object *link;
+	struct nl_object *l;
 
 	if (type == NM_LINK_TYPE_BOND) {
 		/* When the kernel loads the bond module, either via explicit modprobe
@@ -2184,15 +2269,15 @@ link_add (NMPlatform *platform, const char *name, NMLinkType type, const void *a
 	debug ("link: add link '%s' of type '%s' (%d)",
 	       name, type_to_string (type), (int) type);
 
-	link = build_rtnl_link (0, name, type);
+	l = build_rtnl_link (0, name, type);
 
 	g_assert ( (address != NULL) ^ (address_len == 0) );
 	if (address) {
 		auto_nl_addr struct nl_addr *nladdr = _nm_nl_addr_build (AF_LLC, address, address_len);
 
-		rtnl_link_set_addr ((struct rtnl_link *) link, nladdr);
+		rtnl_link_set_addr ((struct rtnl_link *) l, nladdr);
 	}
-	return add_object (platform, link);
+	return add_object (platform, l);
 }
 
 static struct rtnl_link *
@@ -2384,6 +2469,46 @@ link_set_noarp (NMPlatform *platform, int ifindex)
 }
 
 static gboolean
+link_get_user_ipv6ll_enabled (NMPlatform *platform, int ifindex)
+{
+#if HAVE_LIBNL_INET6_ADDR_GEN_MODE
+	NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
+
+	if (priv->support_user_ipv6ll > 0) {
+		auto_nl_object struct rtnl_link *rtnllink = link_get (platform, ifindex);
+		uint8_t mode = 0;
+
+		if (rtnllink) {
+			if (rtnl_link_inet6_get_addr_gen_mode (rtnllink, &mode) != 0) {
+				/* Default to "disabled" on error */
+				return FALSE;
+			}
+			return mode == IN6_ADDR_GEN_MODE_NONE;
+		}
+	}
+#endif
+	return FALSE;
+}
+
+static gboolean
+link_set_user_ipv6ll_enabled (NMPlatform *platform, int ifindex, gboolean enabled)
+{
+#if HAVE_LIBNL_INET6_ADDR_GEN_MODE
+	if (check_support_user_ipv6ll (platform)) {
+		auto_nl_object struct rtnl_link *change = _nm_rtnl_link_alloc (ifindex, NULL);
+		guint8 mode = enabled ? IN6_ADDR_GEN_MODE_NONE : IN6_ADDR_GEN_MODE_EUI64;
+		char buf[32];
+
+		rtnl_link_inet6_set_addr_gen_mode (change, mode);
+		debug ("link: change %d: set IPv6 address generation mode to %s",
+		       ifindex, rtnl_link_inet6_addrgenmode2str (mode, buf, sizeof (buf)));
+		return link_change (platform, ifindex, change);
+	}
+#endif
+	return FALSE;
+}
+
+static gboolean
 supports_ethtool_carrier_detect (const char *ifname)
 {
 	struct ethtool_cmd edata = { .cmd = ETHTOOL_GLINK };
@@ -2455,7 +2580,7 @@ link_supports_vlans (NMPlatform *platform, int ifindex)
 {
 	auto_nl_object struct rtnl_link *rtnllink = link_get (platform, ifindex);
 	const char *name = nm_platform_link_get_name (ifindex);
-	auto_g_free struct ethtool_gfeatures *features = NULL;
+	gs_free struct ethtool_gfeatures *features = NULL;
 	int idx, block, bit, size;
 
 	/* Only ARPHRD_ETHER links can possibly support VLANs. */
@@ -2494,7 +2619,7 @@ link_set_address (NMPlatform *platform, int ifindex, gconstpointer address, size
 	rtnl_link_set_addr (change, nladdr);
 
 	if (nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM)) {
-		char *mac = nm_utils_hwaddr_ntoa_len (address, length);
+		char *mac = nm_utils_hwaddr_ntoa (address, length);
 
 		debug ("link: change %d: address %s (%lu bytes)", ifindex, mac, (unsigned long) length);
 		g_free (mac);
@@ -2508,13 +2633,23 @@ link_get_address (NMPlatform *platform, int ifindex, size_t *length)
 {
 	auto_nl_object struct rtnl_link *rtnllink = link_get (platform, ifindex);
 	struct nl_addr *nladdr;
-
-	nladdr = rtnllink ? rtnl_link_get_addr (rtnllink) : NULL;
+	size_t l = 0;
+	gconstpointer a = NULL;
+
+	if (rtnllink &&
+	    (nladdr = rtnl_link_get_addr (rtnllink))) {
+		l = nl_addr_get_len (nladdr);
+		if (l > NM_UTILS_HWADDR_LEN_MAX) {
+			if (length)
+				*length = 0;
+			g_return_val_if_reached (NULL);
+		} else if (l > 0)
+			a = nl_addr_get_binary_addr (nladdr);
+	}
 
 	if (length)
-		*length = nladdr ? nl_addr_get_len (nladdr) : 0;
-
-	return nladdr ? nl_addr_get_binary_addr (nladdr) : NULL;
+		*length = l;
+	return a;
 }
 
 static gboolean
@@ -2667,7 +2802,7 @@ link_option_path (int master, const char *category, const char *option)
 static gboolean
 link_set_option (int master, const char *category, const char *option, const char *value)
 {
-	auto_g_free char *path = link_option_path (master, category, option);
+	gs_free char *path = link_option_path (master, category, option);
 
 	return path && nm_platform_sysctl_set (path, value);
 }
@@ -2675,7 +2810,7 @@ link_set_option (int master, const char *category, const char *option, const cha
 static char *
 link_get_option (int master, const char *category, const char *option)
 {
-	auto_g_free char *path = link_option_path (master, category, option);
+	gs_free char *path = link_option_path (master, category, option);
 
 	return path ? nm_platform_sysctl_get (path) : NULL;
 }
@@ -2754,7 +2889,7 @@ infiniband_partition_add (NMPlatform *platform, int parent, int p_key)
 	g_free (path);
 
 	if (success) {
-		auto_g_free char *ifname = g_strdup_printf ("%s.%04x", parent_name, p_key);
+		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);
 
 		success = refresh_object (platform, (struct nl_object *) rtnllink, FALSE, NM_PLATFORM_REASON_INTERNAL);
@@ -2767,7 +2902,7 @@ static gboolean
 veth_get_properties (NMPlatform *platform, int ifindex, NMPlatformVethProperties *props)
 {
 	const char *ifname;
-	auto_g_free struct ethtool_stats *stats = NULL;
+	gs_free struct ethtool_stats *stats = NULL;
 	int peer_ifindex_stat;
 
 	ifname = nm_platform_link_get_name (ifindex);
@@ -2841,7 +2976,7 @@ tun_get_properties (NMPlatform *platform, int ifindex, NMPlatformTunProperties *
 #ifndef IFF_MULTI_QUEUE
 			const int IFF_MULTI_QUEUE = 0x0100;
 #endif
-			props->mode = ((flags & TUN_TYPE_MASK) == TUN_TUN_DEV) ? "tun" : "tap";
+			props->mode = ((flags & (IFF_TUN | IFF_TAP)) == IFF_TUN) ? "tun" : "tap";
 			props->no_pi = !!(flags & IFF_NO_PI);
 			props->vnet_hdr = !!(flags & IFF_VNET_HDR);
 			props->multi_queue = !!(flags & IFF_MULTI_QUEUE);
@@ -2947,6 +3082,13 @@ macvlan_get_properties (NMPlatform *platform, int ifindex, NMPlatformMacvlanProp
 #undef IFLA_VXLAN_MAX
 #define IFLA_VXLAN_MAX IFLA_VXLAN_LOCAL6
 
+/* older kernel header might not contain 'struct ifla_vxlan_port_range'.
+ * Redefine it. */
+struct nm_ifla_vxlan_port_range {
+	guint16 low;
+	guint16 high;
+};
+
 static const struct nla_policy vxlan_info_policy[IFLA_VXLAN_MAX + 1] = {
 	[IFLA_VXLAN_ID]         = { .type = NLA_U32 },
 	[IFLA_VXLAN_GROUP]      = { .type = NLA_U32 },
@@ -2962,7 +3104,7 @@ static const struct nla_policy vxlan_info_policy[IFLA_VXLAN_MAX + 1] = {
 	[IFLA_VXLAN_AGEING]     = { .type = NLA_U32 },
 	[IFLA_VXLAN_LIMIT]      = { .type = NLA_U32 },
 	[IFLA_VXLAN_PORT_RANGE] = { .type = NLA_UNSPEC,
-	                            .minlen  = sizeof (struct ifla_vxlan_port_range) },
+	                            .minlen  = sizeof (struct nm_ifla_vxlan_port_range) },
 	[IFLA_VXLAN_PROXY]      = { .type = NLA_U8 },
 	[IFLA_VXLAN_RSC]        = { .type = NLA_U8 },
 	[IFLA_VXLAN_L2MISS]     = { .type = NLA_U8 },
@@ -2975,7 +3117,7 @@ vxlan_info_data_parser (struct nlattr *info_data, gpointer parser_data)
 {
 	NMPlatformVxlanProperties *props = parser_data;
 	struct nlattr *tb[IFLA_VXLAN_MAX + 1];
-	struct ifla_vxlan_port_range *range;
+	struct nm_ifla_vxlan_port_range *range;
 	int err;
 
 	err = nla_parse_nested (tb, IFLA_VXLAN_MAX, info_data,
@@ -2985,8 +3127,10 @@ vxlan_info_data_parser (struct nlattr *info_data, gpointer parser_data)
 
 	memset (props, 0, sizeof (*props));
 
-	props->parent_ifindex = tb[IFLA_VXLAN_LINK] ? nla_get_u32 (tb[IFLA_VXLAN_LINK]) : 0;
-	props->id = nla_get_u32 (tb[IFLA_VXLAN_ID]);
+	if (tb[IFLA_VXLAN_LINK])
+		props->parent_ifindex = nla_get_u32 (tb[IFLA_VXLAN_LINK]);
+	if (tb[IFLA_VXLAN_ID])
+		props->id = nla_get_u32 (tb[IFLA_VXLAN_ID]);
 	if (tb[IFLA_VXLAN_GROUP])
 		props->group = nla_get_u32 (tb[IFLA_VXLAN_GROUP]);
 	if (tb[IFLA_VXLAN_LOCAL])
@@ -2996,21 +3140,34 @@ vxlan_info_data_parser (struct nlattr *info_data, gpointer parser_data)
 	if (tb[IFLA_VXLAN_LOCAL6])
 		memcpy (&props->local6, nla_data (tb[IFLA_VXLAN_LOCAL6]), sizeof (props->local6));
 
-	props->ageing = nla_get_u32 (tb[IFLA_VXLAN_AGEING]);
-	props->limit = nla_get_u32 (tb[IFLA_VXLAN_LIMIT]);
-	props->tos = nla_get_u8 (tb[IFLA_VXLAN_TOS]);
-	props->ttl = nla_get_u8 (tb[IFLA_VXLAN_TTL]);
-
-	props->dst_port = nla_get_u16 (tb[IFLA_VXLAN_PORT]);
-	range = nla_data (tb[IFLA_VXLAN_PORT_RANGE]);
-	props->src_port_min = range->low;
-	props->src_port_max = range->high;
+	if (tb[IFLA_VXLAN_AGEING])
+		props->ageing = nla_get_u32 (tb[IFLA_VXLAN_AGEING]);
+	if (tb[IFLA_VXLAN_LIMIT])
+		props->limit = nla_get_u32 (tb[IFLA_VXLAN_LIMIT]);
+	if (tb[IFLA_VXLAN_TOS])
+		props->tos = nla_get_u8 (tb[IFLA_VXLAN_TOS]);
+	if (tb[IFLA_VXLAN_TTL])
+		props->ttl = nla_get_u8 (tb[IFLA_VXLAN_TTL]);
+
+	if (tb[IFLA_VXLAN_PORT])
+		props->dst_port = nla_get_u16 (tb[IFLA_VXLAN_PORT]);
+
+	if (tb[IFLA_VXLAN_PORT_RANGE]) {
+		range = nla_data (tb[IFLA_VXLAN_PORT_RANGE]);
+		props->src_port_min = range->low;
+		props->src_port_max = range->high;
+	}
 
-	props->learning = !!nla_get_u8 (tb[IFLA_VXLAN_LEARNING]);
-	props->proxy = !!nla_get_u8 (tb[IFLA_VXLAN_PROXY]);
-	props->rsc = !!nla_get_u8 (tb[IFLA_VXLAN_RSC]);
-	props->l2miss = !!nla_get_u8 (tb[IFLA_VXLAN_L2MISS]);
-	props->l3miss = !!nla_get_u8 (tb[IFLA_VXLAN_L3MISS]);
+	if (tb[IFLA_VXLAN_LEARNING])
+		props->learning = !!nla_get_u8 (tb[IFLA_VXLAN_LEARNING]);
+	if (tb[IFLA_VXLAN_PROXY])
+		props->proxy = !!nla_get_u8 (tb[IFLA_VXLAN_PROXY]);
+	if (tb[IFLA_VXLAN_RSC])
+		props->rsc = !!nla_get_u8 (tb[IFLA_VXLAN_RSC]);
+	if (tb[IFLA_VXLAN_L2MISS])
+		props->l2miss = !!nla_get_u8 (tb[IFLA_VXLAN_L2MISS]);
+	if (tb[IFLA_VXLAN_L3MISS])
+		props->l3miss = !!nla_get_u8 (tb[IFLA_VXLAN_L3MISS]);
 
 	return 0;
 }
@@ -3131,7 +3288,7 @@ wifi_get_capabilities (NMPlatform *platform, int ifindex, NMDeviceWifiCapabiliti
 }
 
 static gboolean
-wifi_get_bssid (NMPlatform *platform, int ifindex, struct ether_addr *bssid)
+wifi_get_bssid (NMPlatform *platform, int ifindex, guint8 *bssid)
 {
 	WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex);
 
@@ -3244,14 +3401,14 @@ mesh_set_channel (NMPlatform *platform, int ifindex, guint32 channel)
 }
 
 static gboolean
-mesh_set_ssid (NMPlatform *platform, int ifindex, const GByteArray *ssid)
+mesh_set_ssid (NMPlatform *platform, int ifindex, const guint8 *ssid, gsize len)
 {
 	WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex);
 
 	if (!wifi_data)
 		return FALSE;
 
-	return wifi_utils_set_mesh_ssid (wifi_data, ssid);
+	return wifi_utils_set_mesh_ssid (wifi_data, ssid, len);
 }
 
 static gboolean
@@ -3287,7 +3444,7 @@ _address_match (struct rtnl_addr *addr, int family, int ifindex)
 	g_return_val_if_fail (addr, FALSE);
 
 	return rtnl_addr_get_family (addr) == family &&
-	       rtnl_addr_get_ifindex (addr) == ifindex;
+	       (ifindex == 0 || rtnl_addr_get_ifindex (addr) == ifindex);
 }
 
 static GArray *
@@ -3455,9 +3612,9 @@ ip6_address_add (NMPlatform *platform,
 }
 
 static gboolean
-ip4_address_delete (NMPlatform *platform, int ifindex, in_addr_t addr, int plen)
+ip4_address_delete (NMPlatform *platform, int ifindex, in_addr_t addr, int plen, in_addr_t peer_address)
 {
-	return delete_object (platform, build_rtnl_addr (AF_INET, ifindex, &addr, NULL, plen, 0, 0, 0, NULL), TRUE);
+	return delete_object (platform, build_rtnl_addr (AF_INET, ifindex, &addr, peer_address ? &peer_address : NULL, plen, 0, 0, 0, NULL), TRUE);
 }
 
 static gboolean
@@ -3487,10 +3644,53 @@ ip6_address_exists (NMPlatform *platform, int ifindex, struct in6_addr addr, int
 	return ip_address_exists (platform, AF_INET6, ifindex, &addr, plen);
 }
 
+static gboolean
+ip4_check_reinstall_device_route (NMPlatform *platform, int ifindex, const NMPlatformIP4Address *address, guint32 device_route_metric)
+{
+	NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
+	NMPlatformIP4Address addr_candidate;
+	NMPlatformIP4Route route_candidate;
+	struct nl_object *object;
+	guint32 device_network;
+
+	for (object = nl_cache_get_first (priv->address_cache); object; object = nl_cache_get_next (object)) {
+		if (_address_match ((struct rtnl_addr *) object, AF_INET, 0)) {
+			if (init_ip4_address (&addr_candidate, (struct rtnl_addr *) object))
+				if (   addr_candidate.plen == address->plen
+				    && addr_candidate.address == address->address) {
+					/* If we already have the same address installed on any interface,
+					 * we back off.
+					 * Perform this check first, as we expect to have significantly less
+					 * addresses to search. */
+					return FALSE;
+				}
+		}
+	}
+
+	device_network = nm_utils_ip4_address_clear_host_address (address->address, address->plen);
+
+	for (object = nl_cache_get_first (priv->route_cache); object; object = nl_cache_get_next (object)) {
+		if (_route_match ((struct rtnl_route *) object, AF_INET, 0, TRUE)) {
+			if (init_ip4_route (&route_candidate, (struct rtnl_route *) object)) {
+				if (   route_candidate.network == device_network
+				    && route_candidate.plen == address->plen
+				    && (   route_candidate.metric == 0
+				        || route_candidate.metric == device_route_metric)) {
+					/* There is already any route with metric 0 or the metric we want to install
+					 * for the same subnet. */
+					return FALSE;
+				}
+			}
+		}
+	}
+
+	return TRUE;
+}
+
 /******************************************************************/
 
 static gboolean
-_route_match (struct rtnl_route *rtnlroute, int family, int ifindex)
+_route_match (struct rtnl_route *rtnlroute, int family, int ifindex, gboolean include_proto_kernel)
 {
 	struct rtnl_nexthop *nexthop;
 
@@ -3498,31 +3698,42 @@ _route_match (struct rtnl_route *rtnlroute, int family, int ifindex)
 
 	if (rtnl_route_get_type (rtnlroute) != RTN_UNICAST ||
 	    rtnl_route_get_table (rtnlroute) != RT_TABLE_MAIN ||
-	    rtnl_route_get_protocol (rtnlroute) == RTPROT_KERNEL ||
+	    (!include_proto_kernel && rtnl_route_get_protocol (rtnlroute) == RTPROT_KERNEL) ||
 	    rtnl_route_get_family (rtnlroute) != family ||
-	    rtnl_route_get_nnexthops (rtnlroute) != 1)
+	    rtnl_route_get_nnexthops (rtnlroute) != 1 ||
+	    rtnl_route_get_flags (rtnlroute) & RTM_F_CLONED)
 		return FALSE;
 
+	if (ifindex == 0)
+		return TRUE;
+
 	nexthop = rtnl_route_nexthop_n (rtnlroute, 0);
 	return rtnl_route_nh_get_ifindex (nexthop) == ifindex;
 }
 
 static GArray *
-ip4_route_get_all (NMPlatform *platform, int ifindex, gboolean include_default)
+ip4_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteMode mode)
 {
 	NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
 	GArray *routes;
 	NMPlatformIP4Route route;
 	struct nl_object *object;
 
+	g_return_val_if_fail (NM_IN_SET (mode, NM_PLATFORM_GET_ROUTE_MODE_ALL, NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT, NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT), NULL);
+
 	routes = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP4Route));
 
 	for (object = nl_cache_get_first (priv->route_cache); object; object = nl_cache_get_next (object)) {
-		if (_route_match ((struct rtnl_route *) object, AF_INET, ifindex)) {
-			if (init_ip4_route (&route, (struct rtnl_route *) object)) {
-				if (route.plen != 0 || include_default)
-					g_array_append_val (routes, route);
+		if (_route_match ((struct rtnl_route *) object, AF_INET, ifindex, FALSE)) {
+			if (_rtnl_route_is_default ((struct rtnl_route *) object)) {
+				if (mode == NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT)
+					continue;
+			} else {
+				if (mode == NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT)
+					continue;
 			}
+			if (init_ip4_route (&route, (struct rtnl_route *) object))
+				g_array_append_val (routes, route);
 		}
 	}
 
@@ -3530,21 +3741,28 @@ ip4_route_get_all (NMPlatform *platform, int ifindex, gboolean include_default)
 }
 
 static GArray *
-ip6_route_get_all (NMPlatform *platform, int ifindex, gboolean include_default)
+ip6_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteMode mode)
 {
 	NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
 	GArray *routes;
 	NMPlatformIP6Route route;
 	struct nl_object *object;
 
+	g_return_val_if_fail (NM_IN_SET (mode, NM_PLATFORM_GET_ROUTE_MODE_ALL, NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT, NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT), NULL);
+
 	routes = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP6Route));
 
 	for (object = nl_cache_get_first (priv->route_cache); object; object = nl_cache_get_next (object)) {
-		if (_route_match ((struct rtnl_route *) object, AF_INET6, ifindex)) {
-			if (init_ip6_route (&route, (struct rtnl_route *) object)) {
-				if (route.plen != 0 || include_default)
-					g_array_append_val (routes, route);
+		if (_route_match ((struct rtnl_route *) object, AF_INET6, ifindex, FALSE)) {
+			if (_rtnl_route_is_default ((struct rtnl_route *) object)) {
+				if (mode == NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT)
+					continue;
+			} else {
+				if (mode == NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT)
+					continue;
 			}
+			if (init_ip6_route (&route, (struct rtnl_route *) object))
+				g_array_append_val (routes, route);
 		}
 	}
 
@@ -3570,9 +3788,10 @@ clear_host_address (int family, const void *network, int plen, void *dst)
 }
 
 static struct nl_object *
-build_rtnl_route (int family, int ifindex, NMPlatformSource source,
+build_rtnl_route (int family, int ifindex, NMIPConfigSource source,
                   gconstpointer network, int plen, gconstpointer gateway,
-                  int metric, int mss)
+                  gconstpointer pref_src,
+                  guint32 metric, guint32 mss)
 {
 	guint32 network_clean[4];
 	struct rtnl_route *rtnlroute;
@@ -3581,6 +3800,7 @@ build_rtnl_route (int family, int ifindex, NMPlatformSource source,
 	/* Workaround a libnl bug by using zero destination address length for default routes */
 	auto_nl_addr struct nl_addr *dst = NULL;
 	auto_nl_addr struct nl_addr *gw = gateway ? _nm_nl_addr_build (family, gateway, addrlen) : NULL;
+	auto_nl_addr struct nl_addr *pref_src_nl = pref_src ? _nm_nl_addr_build (family, pref_src, addrlen) : NULL;
 
 	/* There seem to be problems adding a route with non-zero host identifier.
 	 * Adding IPv6 routes is simply ignored, without error message.
@@ -3602,6 +3822,8 @@ build_rtnl_route (int family, int ifindex, NMPlatformSource source,
 	rtnl_route_nh_set_ifindex (nexthop, ifindex);
 	if (gw && !nl_addr_iszero (gw))
 		rtnl_route_nh_set_gateway (nexthop, gw);
+	if (pref_src_nl)
+		rtnl_route_set_pref_src (rtnlroute, pref_src_nl);
 	rtnl_route_add_nexthop (rtnlroute, nexthop);
 
 	if (mss > 0)
@@ -3611,23 +3833,23 @@ build_rtnl_route (int family, int ifindex, NMPlatformSource source,
 }
 
 static gboolean
-ip4_route_add (NMPlatform *platform, int ifindex, NMPlatformSource source,
+ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
                in_addr_t network, int plen, in_addr_t gateway,
-               int metric, int mss)
+               guint32 pref_src, guint32 metric, guint32 mss)
 {
-	return add_object (platform, build_rtnl_route (AF_INET, ifindex, source, &network, plen, &gateway, metric, mss));
+	return add_object (platform, build_rtnl_route (AF_INET, ifindex, source, &network, plen, &gateway, pref_src ? &pref_src : NULL, metric, mss));
 }
 
 static gboolean
-ip6_route_add (NMPlatform *platform, int ifindex, NMPlatformSource source,
+ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
                struct in6_addr network, int plen, struct in6_addr gateway,
-               int metric, int mss)
+               guint32 metric, guint32 mss)
 {
-	return add_object (platform, build_rtnl_route (AF_INET6, ifindex, source, &network, plen, &gateway, metric, mss));
+	return add_object (platform, build_rtnl_route (AF_INET6, ifindex, source, &network, plen, &gateway, NULL, metric, mss));
 }
 
 static struct rtnl_route *
-route_search_cache (struct nl_cache *cache, int family, int ifindex, const void *network, int plen, int metric)
+route_search_cache (struct nl_cache *cache, int family, int ifindex, const void *network, int plen, guint32 metric)
 {
 	guint32 network_clean[4], dst_clean[4];
 	struct nl_object *object;
@@ -3638,7 +3860,7 @@ route_search_cache (struct nl_cache *cache, int family, int ifindex, const void
 		struct nl_addr *dst;
 		struct rtnl_route *rtnlroute = (struct rtnl_route *) object;
 
-		if (!_route_match (rtnlroute, family, ifindex))
+		if (!_route_match (rtnlroute, family, ifindex, FALSE))
 			continue;
 
 		if (metric && metric != rtnl_route_get_priority (rtnlroute))
@@ -3676,11 +3898,11 @@ refresh_route (NMPlatform *platform, int family, int ifindex, const void *networ
 }
 
 static gboolean
-ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, int plen, int metric)
+ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, int plen, guint32 metric)
 {
 	in_addr_t gateway = 0;
 	struct rtnl_route *cached_object;
-	struct nl_object *route = build_rtnl_route (AF_INET, ifindex, NM_PLATFORM_SOURCE_UNKNOWN, &network, plen, &gateway, metric, 0);
+	struct nl_object *route = build_rtnl_route (AF_INET, ifindex, NM_IP_CONFIG_SOURCE_UNKNOWN, &network, plen, &gateway, NULL, metric, 0);
 	uint8_t scope = RT_SCOPE_NOWHERE;
 	struct nl_cache *cache;
 
@@ -3736,20 +3958,20 @@ ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, int plen
 }
 
 static gboolean
-ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, int plen, int metric)
+ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, int plen, guint32 metric)
 {
 	struct in6_addr gateway = IN6ADDR_ANY_INIT;
 
-	return delete_object (platform, build_rtnl_route (AF_INET6, ifindex, NM_PLATFORM_SOURCE_UNKNOWN ,&network, plen, &gateway, metric, 0), FALSE) &&
+	return delete_object (platform, build_rtnl_route (AF_INET6, ifindex, NM_IP_CONFIG_SOURCE_UNKNOWN ,&network, plen, &gateway, NULL, metric, 0), FALSE) &&
 	    refresh_route (platform, AF_INET6, ifindex, &network, plen, metric);
 }
 
 static gboolean
-ip_route_exists (NMPlatform *platform, int family, int ifindex, gpointer network, int plen, int metric)
+ip_route_exists (NMPlatform *platform, int family, int ifindex, gpointer network, int plen, guint32 metric)
 {
 	auto_nl_object struct nl_object *object = build_rtnl_route (family, ifindex,
-	                                                            NM_PLATFORM_SOURCE_UNKNOWN,
-	                                                            network, plen, NULL, metric, 0);
+	                                                            NM_IP_CONFIG_SOURCE_UNKNOWN,
+	                                                            network, plen, NULL, NULL, metric, 0);
 	struct nl_cache *cache = choose_cache (platform, object);
 	auto_nl_object struct nl_object *cached_object = nl_cache_search (cache, object);
 
@@ -3759,19 +3981,119 @@ ip_route_exists (NMPlatform *platform, int family, int ifindex, gpointer network
 }
 
 static gboolean
-ip4_route_exists (NMPlatform *platform, int ifindex, in_addr_t network, int plen, int metric)
+ip4_route_exists (NMPlatform *platform, int ifindex, in_addr_t network, int plen, guint32 metric)
 {
 	return ip_route_exists (platform, AF_INET, ifindex, &network, plen, metric);
 }
 
 static gboolean
-ip6_route_exists (NMPlatform *platform, int ifindex, struct in6_addr network, int plen, int metric)
+ip6_route_exists (NMPlatform *platform, int ifindex, struct in6_addr network, int plen, guint32 metric)
 {
 	return ip_route_exists (platform, AF_INET6, ifindex, &network, plen, metric);
 }
 
 /******************************************************************/
 
+/* Initialize the link cache while ensuring all links are of AF_UNSPEC,
+ * family (even though the kernel might set AF_BRIDGE for bridges).
+ * See also: _nl_link_family_unset() */
+static void
+init_link_cache (NMPlatform *platform)
+{
+	NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
+	struct nl_object *object = NULL;
+
+	rtnl_link_alloc_cache (priv->nlh, AF_UNSPEC, &priv->link_cache);
+
+	do {
+		for (object = nl_cache_get_first (priv->link_cache); object; object = nl_cache_get_next (object)) {
+			if (rtnl_link_get_family ((struct rtnl_link *)object) != AF_UNSPEC)
+				break;
+		}
+
+		if (object) {
+			/* A non-AF_UNSPEC object encoutnered */
+			struct nl_object *existing;
+
+			nl_object_get (object);
+			nl_cache_remove (object);
+			rtnl_link_set_family ((struct rtnl_link *)object, AF_UNSPEC);
+			existing = nl_cache_search (priv->link_cache, object);
+			if (existing)
+				nl_object_put (existing);
+			else
+				nl_cache_add (priv->link_cache, object);
+			nl_object_put (object);
+		}
+	} while (object);
+}
+
+/* Calls announce_object with appropriate arguments for all objects
+ * which are not coherent between old and new caches and deallocates
+ * the old cache. */
+static void
+cache_announce_changes (NMPlatform *platform, struct nl_cache *new, struct nl_cache *old)
+{
+	struct nl_object *object;
+
+	if (!old)
+		return;
+
+	for (object = nl_cache_get_first (new); object; object = nl_cache_get_next (object)) {
+		struct nl_object *cached_object = nm_nl_cache_search (old, object);
+
+		if (cached_object) {
+			ObjectType type = object_type_from_nl_object (object);
+			if (nm_nl_object_diff (type, object, cached_object))
+				announce_object (platform, object, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_EXTERNAL);
+			nl_object_put (cached_object);
+		} else
+			announce_object (platform, object, NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_REASON_EXTERNAL);
+	}
+	for (object = nl_cache_get_first (old); object; object = nl_cache_get_next (object)) {
+		struct nl_object *cached_object = nm_nl_cache_search (new, object);
+		if (cached_object)
+			nl_object_put (cached_object);
+		else
+			announce_object (platform, object, NM_PLATFORM_SIGNAL_REMOVED, NM_PLATFORM_REASON_EXTERNAL);
+	}
+
+	nl_cache_free (old);
+}
+
+/* Creates and populates the netlink object caches. Called upon platform init and
+ * when we run out of sync (out of buffer space, netlink congestion control). In case
+ * the caches already exist, it finds changed, added and removed objects, announces
+ * them and destroys the old caches. */
+static void
+cache_repopulate_all (NMPlatform *platform)
+{
+	NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
+	struct nl_cache *old_link_cache = priv->link_cache;
+	struct nl_cache *old_address_cache = priv->address_cache;
+	struct nl_cache *old_route_cache = priv->route_cache;
+	struct nl_object *object;
+
+	debug ("platform: %spopulate platform cache", old_link_cache ? "re" : "");
+
+	/* Allocate new netlink caches */
+	init_link_cache (platform);
+	rtnl_addr_alloc_cache (priv->nlh, &priv->address_cache);
+	rtnl_route_alloc_cache (priv->nlh, AF_UNSPEC, 0, &priv->route_cache);
+	g_assert (priv->link_cache && priv->address_cache && priv->route_cache);
+
+	for (object = nl_cache_get_first (priv->address_cache); object; object = nl_cache_get_next (object)) {
+		_rtnl_addr_hack_lifetimes_rel_to_abs ((struct rtnl_addr *) object);
+	}
+
+	/* Make sure all changes we've missed are announced. */
+	cache_announce_changes (platform, priv->link_cache, old_link_cache);
+	cache_announce_changes (platform, priv->address_cache, old_address_cache);
+	cache_announce_changes (platform, priv->route_cache, old_route_cache);
+}
+
+/******************************************************************/
+
 #define EVENT_CONDITIONS      ((GIOCondition) (G_IO_IN | G_IO_PRI))
 #define ERROR_CONDITIONS      ((GIOCondition) (G_IO_ERR | G_IO_NVAL))
 #define DISCONNECT_CONDITIONS ((GIOCondition) (G_IO_HUP))
@@ -3798,7 +4120,8 @@ event_handler (GIOChannel *channel,
                GIOCondition io_condition,
                gpointer user_data)
 {
-	NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (user_data);
+	NMPlatform *platform = NM_PLATFORM (user_data);
+	NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
 	int nle;
 
 	nle = nl_recvmsgs_default (priv->nlh_event);
@@ -3810,6 +4133,17 @@ event_handler (GIOChannel *channel,
 			 * and can happen easily. */
 			debug ("Uncritical failure to retrieve incoming events: %s (%d)", nl_geterror (nle), nle);
 			break;
+		case -NLE_NOMEM:
+			warning ("Too many netlink events. Need to resynchronize platform cache");
+			/* Drain the event queue, we've lost events and are out of sync anyway and we'd
+			 * like to free up some space. We'll read in the status synchronously. */
+			nl_socket_modify_cb (priv->nlh_event, NL_CB_VALID, NL_CB_DEFAULT, NULL, NULL);
+			do {
+				nle = nl_recvmsgs_default (priv->nlh_event);
+			} while (nle != -NLE_AGAIN);
+			nl_socket_modify_cb (priv->nlh_event, NL_CB_VALID, NL_CB_CUSTOM, event_notification, user_data);
+			cache_repopulate_all (platform);
+			break;
 		default:
 			error ("Failed to retrieve incoming events: %s (%d)", nl_geterror (nle), nle);
 			break;
@@ -3841,6 +4175,12 @@ setup_socket (gboolean event, gpointer user_data)
 	nle = nl_socket_set_passcred (sock, 1);
 	g_assert (!nle);
 
+	/* No blocking for event socket, so that we can drain it safely. */
+	if (event) {
+		nle = nl_socket_set_nonblocking (sock);
+		g_assert (!nle);
+	}
+
 	return sock;
 }
 
@@ -3979,7 +4319,9 @@ setup (NMPlatform *platform)
 	int channel_flags;
 	gboolean status;
 	int nle;
+#if HAVE_LIBNL_INET6_ADDR_GEN_MODE
 	struct nl_object *object;
+#endif
 
 	/* Initialize netlink socket for requests */
 	priv->nlh = setup_socket (FALSE, platform);
@@ -4015,14 +4357,25 @@ setup (NMPlatform *platform)
 		(EVENT_CONDITIONS | ERROR_CONDITIONS | DISCONNECT_CONDITIONS),
 		event_handler, platform);
 
-	/* Allocate netlink caches */
-	rtnl_link_alloc_cache (priv->nlh, AF_UNSPEC, &priv->link_cache);
-	rtnl_addr_alloc_cache (priv->nlh, &priv->address_cache);
-	rtnl_route_alloc_cache (priv->nlh, AF_UNSPEC, 0, &priv->route_cache);
-	g_assert (priv->link_cache && priv->address_cache && priv->route_cache);
+	cache_repopulate_all (platform);
 
-	for (object = nl_cache_get_first (priv->address_cache); object; object = nl_cache_get_next (object))
-		_rtnl_addr_hack_lifetimes_rel_to_abs ((struct rtnl_addr *) object);
+#if HAVE_LIBNL_INET6_ADDR_GEN_MODE
+	/* Initial check for user IPv6LL support once the link cache is allocated
+	 * and filled.  If there are no links in the cache yet then we'll check
+	 * when a new link shows up in announce_object().
+	 */
+	object = nl_cache_get_first (priv->link_cache);
+	if (object) {
+		uint8_t mode;
+
+		if (rtnl_link_inet6_get_addr_gen_mode ((struct rtnl_link *) object, &mode) == 0)
+			priv->support_user_ipv6ll = 1;
+		else
+			priv->support_user_ipv6ll = -1;
+	}
+#else
+	priv->support_user_ipv6ll = -1;
+#endif
 
 	/* Set up udev monitoring */
 	priv->udev_client = g_udev_client_new (udev_subsys);
@@ -4111,6 +4464,9 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
 	platform_class->link_is_connected = link_is_connected;
 	platform_class->link_uses_arp = link_uses_arp;
 
+	platform_class->link_get_user_ipv6ll_enabled = link_get_user_ipv6ll_enabled;
+	platform_class->link_set_user_ipv6ll_enabled = link_set_user_ipv6ll_enabled;
+
 	platform_class->link_get_address = link_get_address;
 	platform_class->link_set_address = link_set_address;
 	platform_class->link_get_mtu = link_get_mtu;
@@ -4167,6 +4523,8 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
 	platform_class->ip4_address_exists = ip4_address_exists;
 	platform_class->ip6_address_exists = ip6_address_exists;
 
+	platform_class->ip4_check_reinstall_device_route = ip4_check_reinstall_device_route;
+
 	platform_class->ip4_route_get_all = ip4_route_get_all;
 	platform_class->ip6_route_get_all = ip6_route_get_all;
 	platform_class->ip4_route_add = ip4_route_add;
@@ -4177,4 +4535,5 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
 	platform_class->ip6_route_exists = ip6_route_exists;
 
 	platform_class->check_support_kernel_extended_ifa_flags = check_support_kernel_extended_ifa_flags;
+	platform_class->check_support_user_ipv6ll = check_support_user_ipv6ll;
 }
diff --git a/src/platform/nm-linux-platform.h b/src/platform/nm-linux-platform.h
index 53ea75e6..6f2c1993 100644
--- a/src/platform/nm-linux-platform.h
+++ b/src/platform/nm-linux-platform.h
@@ -18,8 +18,8 @@
  * Copyright (C) 2012 Red Hat, Inc.
  */
 
-#ifndef NM_LINUX_PLATFORM_H
-#define NM_LINUX_PLATFORM_H
+#ifndef __NETWORKMANAGER_LINUX_PLATFORM_H__
+#define __NETWORKMANAGER_LINUX_PLATFORM_H__
 
 #include "nm-platform.h"
 
@@ -46,4 +46,4 @@ GType nm_linux_platform_get_type (void);
 
 void nm_linux_platform_setup (void);
 
-#endif /* NM_LINUX_PLATFORM_H */
+#endif /* __NETWORKMANAGER_LINUX_PLATFORM_H__ */
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index 542b0faa..14fc44c5 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -18,6 +18,8 @@
  * Copyright (C) 2012 Red Hat, Inc.
  */
 
+#include "config.h"
+
 #include <stdlib.h>
 #include <errno.h>
 #include <unistd.h>
@@ -26,6 +28,7 @@
 #include <string.h>
 #include <netlink/route/addr.h>
 
+#include "gsystem-local-alloc.h"
 #include "NetworkManagerUtils.h"
 #include "nm-utils.h"
 #include "nm-platform.h"
@@ -215,6 +218,21 @@ nm_platform_check_support_kernel_extended_ifa_flags ()
 	return klass->check_support_kernel_extended_ifa_flags (platform);
 }
 
+gboolean
+nm_platform_check_support_user_ipv6ll (void)
+{
+	static int supported = -1;
+
+	g_return_val_if_fail (NM_IS_PLATFORM (platform), FALSE);
+
+	if (!klass->check_support_user_ipv6ll)
+		return FALSE;
+
+	if (supported < 0)
+		supported = klass->check_support_user_ipv6ll (platform) ? 1 : 0;
+	return !!supported;
+}
+
 /******************************************************************/
 
 /**
@@ -730,6 +748,52 @@ nm_platform_link_uses_arp (int ifindex)
 }
 
 /**
+ * nm_platform_link_get_user_ip6vll_enabled:
+ * @ifindex: Interface index
+ *
+ * Check whether NM handles IPv6LL address creation for the link.  If the
+ * platform or OS doesn't support changing the IPv6LL address mode, this call
+ * will fail and return %FALSE.
+ *
+ * Returns: %TRUE if NM handles the IPv6LL address for @ifindex
+ */
+gboolean
+nm_platform_link_get_user_ipv6ll_enabled (int ifindex)
+{
+	reset_error ();
+
+	g_return_val_if_fail (ifindex >= 0, FALSE);
+	g_return_val_if_fail (klass->check_support_user_ipv6ll, FALSE);
+
+	if (klass->link_get_user_ipv6ll_enabled)
+		return klass->link_get_user_ipv6ll_enabled (platform, ifindex);
+	return FALSE;
+}
+
+/**
+ * nm_platform_link_set_user_ip6vll_enabled:
+ * @ifindex: Interface index
+ *
+ * Set whether NM handles IPv6LL address creation for the link.  If the
+ * platform or OS doesn't support changing the IPv6LL address mode, this call
+ * will fail and return %FALSE.
+ *
+ * Returns: %TRUE if the operation was successful, %FALSE if it failed.
+ */
+gboolean
+nm_platform_link_set_user_ipv6ll_enabled (int ifindex, gboolean enabled)
+{
+	reset_error ();
+
+	g_return_val_if_fail (ifindex >= 0, FALSE);
+	g_return_val_if_fail (klass->check_support_user_ipv6ll, FALSE);
+
+	if (klass->link_set_user_ipv6ll_enabled)
+		return klass->link_set_user_ipv6ll_enabled (platform, ifindex, enabled);
+	return FALSE;
+}
+
+/**
  * nm_platform_link_set_address:
  * @ifindex: Interface index
  * @address: The new MAC address
@@ -877,7 +941,7 @@ nm_platform_link_set_mtu (int ifindex, guint32 mtu)
 	g_return_val_if_fail (mtu > 0, FALSE);
 	g_return_val_if_fail (klass->link_set_mtu, FALSE);
 
-	debug ("link: setting '%s' (%d) mtu %d", nm_platform_link_get_name (ifindex), ifindex, mtu);
+	debug ("link: setting '%s' (%d) mtu %"G_GUINT32_FORMAT, nm_platform_link_get_name (ifindex), ifindex, mtu);
 	return klass->link_set_mtu (platform, ifindex, mtu);
 }
 
@@ -1051,7 +1115,7 @@ nm_platform_team_add (const char *name)
  * nm_platform_vlan_add:
  * @name: New interface name
  * @vlanid: VLAN identifier
- * @vlanflags: VLAN flags from libnm-util
+ * @vlanflags: VLAN flags from libnm
  *
  * Create a software VLAN device.
  */
@@ -1266,7 +1330,7 @@ nm_platform_wifi_get_capabilities (int ifindex, NMDeviceWifiCapabilities *caps)
 }
 
 gboolean
-nm_platform_wifi_get_bssid (int ifindex, struct ether_addr *bssid)
+nm_platform_wifi_get_bssid (int ifindex, guint8 *bssid)
 {
 	reset_error ();
 
@@ -1377,14 +1441,38 @@ nm_platform_mesh_set_channel (int ifindex, guint32 channel)
 }
 
 gboolean
-nm_platform_mesh_set_ssid (int ifindex, const GByteArray *ssid)
+nm_platform_mesh_set_ssid (int ifindex, const guint8 *ssid, gsize len)
 {
 	reset_error ();
 
 	g_return_val_if_fail (ifindex > 0, FALSE);
 	g_return_val_if_fail (ssid != NULL, FALSE);
 
-	return klass->mesh_set_ssid (platform, ifindex, ssid);
+	return klass->mesh_set_ssid (platform, ifindex, ssid, len);
+}
+
+#define TO_STRING_DEV_BUF_SIZE (5+15+1)
+static const char *
+_to_string_dev (int ifindex, char *buf, size_t size)
+{
+	g_assert (buf && size >= TO_STRING_DEV_BUF_SIZE);
+
+	if (ifindex) {
+		const char *name = ifindex > 0 ? nm_platform_link_get_name (ifindex) : NULL;
+		char *buf2;
+
+		strcpy (buf, " dev ");
+		buf2 = buf + 5;
+		size -= 5;
+
+		if (name)
+			g_strlcpy (buf2, name, size);
+		else
+			g_snprintf (buf2, size, "%d", ifindex);
+	} else
+		buf[0] = 0;
+
+	return buf;
 }
 
 /******************************************************************/
@@ -1482,28 +1570,41 @@ nm_platform_ip6_address_add (int ifindex,
 }
 
 gboolean
-nm_platform_ip4_address_delete (int ifindex, in_addr_t address, int plen)
+nm_platform_ip4_address_delete (int ifindex, in_addr_t address, int plen, in_addr_t peer_address)
 {
+	char str_dev[TO_STRING_DEV_BUF_SIZE];
+	char str_peer[NM_UTILS_INET_ADDRSTRLEN];
+
 	reset_error ();
 
 	g_return_val_if_fail (ifindex > 0, FALSE);
 	g_return_val_if_fail (plen > 0, FALSE);
 	g_return_val_if_fail (klass->ip4_address_delete, FALSE);
 
-	debug ("address: deleting IPv4 address %s/%d", nm_utils_inet4_ntop (address, NULL), plen);
-	return klass->ip4_address_delete (platform, ifindex, address, plen);
+	debug ("address: deleting IPv4 address %s/%d, %s%s%sifindex %d%s",
+	       nm_utils_inet4_ntop (address, NULL), plen,
+	       peer_address ? "peer " : "",
+	       peer_address ? nm_utils_inet4_ntop (peer_address, str_peer) : "",
+	       peer_address ? ", " : "",
+	       ifindex,
+	       _to_string_dev (ifindex, str_dev, sizeof (str_dev)));
+	return klass->ip4_address_delete (platform, ifindex, address, plen, peer_address);
 }
 
 gboolean
 nm_platform_ip6_address_delete (int ifindex, struct in6_addr address, int plen)
 {
+	char str_dev[TO_STRING_DEV_BUF_SIZE];
+
 	reset_error ();
 
 	g_return_val_if_fail (ifindex > 0, FALSE);
 	g_return_val_if_fail (plen > 0, FALSE);
 	g_return_val_if_fail (klass->ip6_address_delete, FALSE);
 
-	debug ("address: deleting IPv6 address %s/%d", nm_utils_inet6_ntop (&address, NULL), plen);
+	debug ("address: deleting IPv6 address %s/%d, ifindex %d%s",
+	       nm_utils_inet6_ntop (&address, NULL), plen, ifindex,
+	       _to_string_dev (ifindex, str_dev, sizeof (str_dev)));
 	return klass->ip6_address_delete (platform, ifindex, address, plen);
 }
 
@@ -1600,11 +1701,16 @@ _rebase_relative_time_on_now (guint32 timestamp, guint32 duration, guint32 now,
 static gboolean
 _address_get_lifetime (const NMPlatformIPAddress *address, guint32 now, guint32 padding, guint32 *out_lifetime, guint32 *out_preferred)
 {
-	gint32 lifetime, preferred;
+	guint32 lifetime, preferred;
 
 	if (address->lifetime == 0) {
 		*out_lifetime = NM_PLATFORM_LIFETIME_PERMANENT;
 		*out_preferred = NM_PLATFORM_LIFETIME_PERMANENT;
+
+		/* We treat lifetime==0 as permanent addresses to allow easy creation of such addresses
+		 * (without requiring to set the lifetime fields to NM_PLATFORM_LIFETIME_PERMANENT).
+		 * In that case we also expect that the other fields (timestamp and preferred) are left unset. */
+		g_return_val_if_fail (address->timestamp == 0 && address->preferred == 0, TRUE);
 	} else {
 		lifetime = _rebase_relative_time_on_now (address->timestamp, address->lifetime, now, padding);
 		if (!lifetime)
@@ -1626,10 +1732,31 @@ _address_get_lifetime (const NMPlatformIPAddress *address, guint32 now, guint32
 	return TRUE;
 }
 
+gboolean
+nm_platform_ip4_check_reinstall_device_route (int ifindex, const NMPlatformIP4Address *address, guint32 device_route_metric)
+{
+	g_return_val_if_fail (address, FALSE);
+
+	if (   ifindex <= 0
+	    || address->plen <= 0
+	    || address->plen >= 32)
+		return FALSE;
+
+	if (device_route_metric == NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE) {
+		/* The automatically added route would be already our desired priority.
+		 * Nothing to do. */
+		return FALSE;
+	}
+
+	return klass->ip4_check_reinstall_device_route (platform, ifindex, address, device_route_metric);
+}
+
 /**
  * nm_platform_ip4_address_sync:
  * @ifindex: Interface index
  * @known_addresses: List of addresses
+ * @device_route_metric: the route metric for adding subnet routes (replaces
+ *   the kernel added routes).
  *
  * A convenience function to synchronize addresses for a specific interface
  * with the least possible disturbance. It simply removes addresses that are
@@ -1638,7 +1765,7 @@ _address_get_lifetime (const NMPlatformIPAddress *address, guint32 now, guint32
  * Returns: %TRUE on success.
  */
 gboolean
-nm_platform_ip4_address_sync (int ifindex, const GArray *known_addresses)
+nm_platform_ip4_address_sync (int ifindex, const GArray *known_addresses, guint32 device_route_metric)
 {
 	GArray *addresses;
 	NMPlatformIP4Address *address;
@@ -1651,7 +1778,7 @@ nm_platform_ip4_address_sync (int ifindex, const GArray *known_addresses)
 		address = &g_array_index (addresses, NMPlatformIP4Address, i);
 
 		if (!array_contains_ip4_address (known_addresses, address))
-			nm_platform_ip4_address_delete (ifindex, address->address, address->plen);
+			nm_platform_ip4_address_delete (ifindex, address->address, address->plen, address->peer_address);
 	}
 	g_array_free (addresses, TRUE);
 
@@ -1662,13 +1789,34 @@ nm_platform_ip4_address_sync (int ifindex, const GArray *known_addresses)
 	for (i = 0; i < known_addresses->len; i++) {
 		const NMPlatformIP4Address *known_address = &g_array_index (known_addresses, NMPlatformIP4Address, i);
 		guint32 lifetime, preferred;
+		guint32 network;
+		gboolean reinstall_device_route = FALSE;
 
 		/* add a padding of 5 seconds to avoid potential races. */
 		if (!_address_get_lifetime ((NMPlatformIPAddress *) known_address, now, 5, &lifetime, &preferred))
 			continue;
 
+		if (nm_platform_ip4_check_reinstall_device_route (ifindex, known_address, device_route_metric))
+			reinstall_device_route = TRUE;
+
 		if (!nm_platform_ip4_address_add (ifindex, known_address->address, known_address->peer_address, known_address->plen, lifetime, preferred, known_address->label))
 			return FALSE;
+
+		if (reinstall_device_route) {
+			/* Kernel automatically adds a device route for us with metric 0. That is not what we want.
+			 * Remove it, and re-add it.
+			 *
+			 * In face of having the same subnets on two different interfaces with the same metric,
+			 * this is a problem. Surprisingly, kernel is able to add two routes for the same subnet/prefix,metric
+			 * to different interfaces. We cannot. Adding one, would replace the other. This is avoided
+			 * by the above nm_platform_ip4_check_reinstall_device_route() check.
+			 */
+			network = nm_utils_ip4_address_clear_host_address (known_address->address, known_address->plen);
+			(void) nm_platform_ip4_route_add (ifindex, NM_IP_CONFIG_SOURCE_KERNEL, network, known_address->plen,
+			                                  0, known_address->address, device_route_metric, 0);
+			(void) nm_platform_ip4_route_delete (ifindex, network, known_address->plen,
+			                                     NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE);
+		}
 	}
 
 	return TRUE;
@@ -1731,49 +1879,49 @@ nm_platform_ip6_address_sync (int ifindex, const GArray *known_addresses)
 gboolean
 nm_platform_address_flush (int ifindex)
 {
-	return nm_platform_ip4_address_sync (ifindex, NULL)
+	return nm_platform_ip4_address_sync (ifindex, NULL, 0)
 			&& nm_platform_ip6_address_sync (ifindex, NULL);
 }
 
 /******************************************************************/
 
 GArray *
-nm_platform_ip4_route_get_all (int ifindex, gboolean include_default)
+nm_platform_ip4_route_get_all (int ifindex, NMPlatformGetRouteMode mode)
 {
 	reset_error ();
 
-	g_return_val_if_fail (ifindex > 0, NULL);
+	g_return_val_if_fail (ifindex >= 0, NULL);
 	g_return_val_if_fail (klass->ip4_route_get_all, NULL);
 
-	return klass->ip4_route_get_all (platform, ifindex, include_default);
+	return klass->ip4_route_get_all (platform, ifindex, mode);
 }
 
 GArray *
-nm_platform_ip6_route_get_all (int ifindex, gboolean include_default)
+nm_platform_ip6_route_get_all (int ifindex, NMPlatformGetRouteMode mode)
 {
 	reset_error ();
 
-	g_return_val_if_fail (ifindex > 0, NULL);
+	g_return_val_if_fail (ifindex >= 0, NULL);
 	g_return_val_if_fail (klass->ip6_route_get_all, NULL);
 
-	return klass->ip6_route_get_all (platform, ifindex, include_default);
+	return klass->ip6_route_get_all (platform, ifindex, mode);
 }
 
 gboolean
-nm_platform_ip4_route_add (int ifindex, NMPlatformSource source,
+nm_platform_ip4_route_add (int ifindex, NMIPConfigSource source,
                            in_addr_t network, int plen,
-                           in_addr_t gateway, int metric, int mss)
+                           in_addr_t gateway, guint32 pref_src,
+                           guint32 metric, guint32 mss)
 {
 	reset_error ();
 
 	g_return_val_if_fail (platform, FALSE);
 	g_return_val_if_fail (0 <= plen && plen <= 32, FALSE);
-	g_return_val_if_fail (metric >= 0, FALSE);
-	g_return_val_if_fail (mss >= 0, FALSE);
 	g_return_val_if_fail (klass->ip4_route_add, FALSE);
 
 	if (nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM)) {
 		NMPlatformIP4Route route = { 0 };
+		char pref_src_buf[NM_UTILS_INET_ADDRSTRLEN];
 
 		route.ifindex = ifindex;
 		route.source = source;
@@ -1783,20 +1931,21 @@ nm_platform_ip4_route_add (int ifindex, NMPlatformSource source,
 		route.metric = metric;
 		route.mss = mss;
 
-		debug ("route: adding or updating IPv4 route: %s", nm_platform_ip4_route_to_string (&route));
+		debug ("route: adding or updating IPv4 route: %s%s%s%s", nm_platform_ip4_route_to_string (&route),
+		       pref_src ? " (src: " : "",
+		       pref_src ? nm_utils_inet4_ntop (pref_src, pref_src_buf) : "",
+		       pref_src ? ")" : "");
 	}
-	return klass->ip4_route_add (platform, ifindex, source, network, plen, gateway, metric, mss);
+	return klass->ip4_route_add (platform, ifindex, source, network, plen, gateway, pref_src, metric, mss);
 }
 
 gboolean
-nm_platform_ip6_route_add (int ifindex, NMPlatformSource source,
+nm_platform_ip6_route_add (int ifindex, NMIPConfigSource source,
                            struct in6_addr network, int plen, struct in6_addr gateway,
-                           int metric, int mss)
+                           guint32 metric, guint32 mss)
 {
 	g_return_val_if_fail (platform, FALSE);
 	g_return_val_if_fail (0 <= plen && plen <= 128, FALSE);
-	g_return_val_if_fail (metric >= 0, FALSE);
-	g_return_val_if_fail (mss >= 0, FALSE);
 	g_return_val_if_fail (klass->ip6_route_add, FALSE);
 
 	if (nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM)) {
@@ -1816,31 +1965,39 @@ nm_platform_ip6_route_add (int ifindex, NMPlatformSource source,
 }
 
 gboolean
-nm_platform_ip4_route_delete (int ifindex, in_addr_t network, int plen, int metric)
+nm_platform_ip4_route_delete (int ifindex, in_addr_t network, int plen, guint32 metric)
 {
+	char str_dev[TO_STRING_DEV_BUF_SIZE];
+
 	reset_error ();
 
 	g_return_val_if_fail (platform, FALSE);
 	g_return_val_if_fail (klass->ip4_route_delete, FALSE);
 
-	debug ("route: deleting IPv4 route %s/%d, metric=%d", nm_utils_inet4_ntop (network, NULL), plen, metric);
+	debug ("route: deleting IPv4 route %s/%d, metric=%"G_GUINT32_FORMAT", ifindex %d%s",
+	       nm_utils_inet4_ntop (network, NULL), plen, metric, ifindex,
+	       _to_string_dev (ifindex, str_dev, sizeof (str_dev)));
 	return klass->ip4_route_delete (platform, ifindex, network, plen, metric);
 }
 
 gboolean
-nm_platform_ip6_route_delete (int ifindex, struct in6_addr network, int plen, int metric)
+nm_platform_ip6_route_delete (int ifindex, struct in6_addr network, int plen, guint32 metric)
 {
+	char str_dev[TO_STRING_DEV_BUF_SIZE];
+
 	reset_error ();
 
 	g_return_val_if_fail (platform, FALSE);
 	g_return_val_if_fail (klass->ip6_route_delete, FALSE);
 
-	debug ("route: deleting IPv6 route %s/%d, metric=%d", nm_utils_inet6_ntop (&network, NULL), plen, metric);
+	debug ("route: deleting IPv6 route %s/%d, metric=%"G_GUINT32_FORMAT", ifindex %d%s",
+	       nm_utils_inet6_ntop (&network, NULL), plen, metric, ifindex,
+	       _to_string_dev (ifindex, str_dev, sizeof (str_dev)));
 	return klass->ip6_route_delete (platform, ifindex, network, plen, metric);
 }
 
 gboolean
-nm_platform_ip4_route_exists (int ifindex, in_addr_t network, int plen, int metric)
+nm_platform_ip4_route_exists (int ifindex, in_addr_t network, int plen, guint32 metric)
 {
 	reset_error ();
 
@@ -1851,7 +2008,7 @@ nm_platform_ip4_route_exists (int ifindex, in_addr_t network, int plen, int metr
 }
 
 gboolean
-nm_platform_ip6_route_exists (int ifindex, struct in6_addr network, int plen, int metric)
+nm_platform_ip6_route_exists (int ifindex, struct in6_addr network, int plen, guint32 metric)
 {
 	reset_error ();
 
@@ -1907,6 +2064,8 @@ array_contains_ip6_route (const GArray *routes, const NMPlatformIP6Route *route)
  * A convenience function to synchronize routes for a specific interface
  * with the least possible disturbance. It simply removes routes that are
  * not listed and adds routes that are.
+ * Default routes are ignored (both in @known_routes and those already
+ * configured on the device).
  *
  * Returns: %TRUE on success.
  */
@@ -1920,12 +2079,12 @@ nm_platform_ip4_route_sync (int ifindex, const GArray *known_routes)
 	int i, i_type;
 
 	/* Delete unknown routes */
-	routes = nm_platform_ip4_route_get_all (ifindex, FALSE);
+	routes = nm_platform_ip4_route_get_all (ifindex, NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT);
 	for (i = 0; i < routes->len; i++) {
 		route = &g_array_index (routes, NMPlatformIP4Route, i);
 
 		if (!array_contains_ip4_route (known_routes, route))
-			nm_platform_ip4_route_delete (ifindex, route->network, route->plen, route->metric);
+			(void) nm_platform_ip4_route_delete (ifindex, route->network, route->plen, route->metric);
 	}
 
 	if (!known_routes) {
@@ -1938,6 +2097,9 @@ nm_platform_ip4_route_sync (int ifindex, const GArray *known_routes)
 		for (i = 0; i < known_routes->len && success; i++) {
 			known_route = &g_array_index (known_routes, NMPlatformIP4Route, i);
 
+			if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (known_route))
+				continue;
+
 			if ((known_route->gateway == 0) ^ (i_type != 0)) {
 				/* Make two runs over the list of routes. On the first, only add
 				 * device routes, on the second the others (gateway routes). */
@@ -1951,9 +2113,10 @@ nm_platform_ip4_route_sync (int ifindex, const GArray *known_routes)
 				                                     known_route->network,
 				                                     known_route->plen,
 				                                     known_route->gateway,
+				                                     0,
 				                                     known_route->metric,
 				                                     known_route->mss);
-				if (!success && known_route->source < NM_PLATFORM_SOURCE_USER) {
+				if (!success && known_route->source < NM_IP_CONFIG_SOURCE_USER) {
 					nm_log_dbg (LOGD_PLATFORM, "ignore error adding IPv4 route to kernel: %s",
 					                           nm_platform_ip4_route_to_string (known_route));
 					success = TRUE;
@@ -1974,6 +2137,8 @@ nm_platform_ip4_route_sync (int ifindex, const GArray *known_routes)
  * A convenience function to synchronize routes for a specific interface
  * with the least possible disturbance. It simply removes routes that are
  * not listed and adds routes that are.
+ * Default routes are ignored (both in @known_routes and those already
+ * configured on the device).
  *
  * Returns: %TRUE on success.
  */
@@ -1987,7 +2152,7 @@ nm_platform_ip6_route_sync (int ifindex, const GArray *known_routes)
 	int i, i_type;
 
 	/* Delete unknown routes */
-	routes = nm_platform_ip6_route_get_all (ifindex, FALSE);
+	routes = nm_platform_ip6_route_get_all (ifindex, NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT);
 	for (i = 0; i < routes->len; i++) {
 		route = &g_array_index (routes, NMPlatformIP6Route, i);
 		route->ifindex = 0;
@@ -2006,6 +2171,9 @@ nm_platform_ip6_route_sync (int ifindex, const GArray *known_routes)
 		for (i = 0; i < known_routes->len && success; i++) {
 			known_route = &g_array_index (known_routes, NMPlatformIP6Route, i);
 
+			if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (known_route))
+				continue;
+
 			if (IN6_IS_ADDR_UNSPECIFIED (&known_route->gateway) ^ (i_type != 0)) {
 				/* Make two runs over the list of routes. On the first, only add
 				 * device routes, on the second the others (gateway routes). */
@@ -2021,7 +2189,7 @@ nm_platform_ip6_route_sync (int ifindex, const GArray *known_routes)
 				                                     known_route->gateway,
 				                                     known_route->metric,
 				                                     known_route->mss);
-				if (!success && known_route->source < NM_PLATFORM_SOURCE_USER) {
+				if (!success && known_route->source < NM_IP_CONFIG_SOURCE_USER) {
 					nm_log_dbg (LOGD_PLATFORM, "ignore error adding IPv6 route to kernel: %s",
 					                           nm_platform_ip6_route_to_string (known_route));
 					success = TRUE;
@@ -2044,26 +2212,26 @@ nm_platform_route_flush (int ifindex)
 /******************************************************************/
 
 static const char *
-source_to_string (NMPlatformSource source)
+source_to_string (NMIPConfigSource source)
 {
 	switch (source) {
-	case NM_PLATFORM_SOURCE_KERNEL:
+	case NM_IP_CONFIG_SOURCE_KERNEL:
 		return "kernel";
-	case NM_PLATFORM_SOURCE_SHARED:
+	case NM_IP_CONFIG_SOURCE_SHARED:
 		return "shared";
-	case NM_PLATFORM_SOURCE_IP4LL:
+	case NM_IP_CONFIG_SOURCE_IP4LL:
 		return "ipv4ll";
-	case NM_PLATFORM_SOURCE_PPP:
+	case NM_IP_CONFIG_SOURCE_PPP:
 		return "ppp";
-	case NM_PLATFORM_SOURCE_WWAN:
+	case NM_IP_CONFIG_SOURCE_WWAN:
 		return "wwan";
-	case NM_PLATFORM_SOURCE_VPN:
+	case NM_IP_CONFIG_SOURCE_VPN:
 		return "vpn";
-	case NM_PLATFORM_SOURCE_DHCP:
+	case NM_IP_CONFIG_SOURCE_DHCP:
 		return "dhcp";
-	case NM_PLATFORM_SOURCE_RDISC:
+	case NM_IP_CONFIG_SOURCE_RDISC:
 		return "rdisc";
-	case NM_PLATFORM_SOURCE_USER:
+	case NM_IP_CONFIG_SOURCE_USER:
 		return "user";
 	default:
 		break;
@@ -2071,27 +2239,6 @@ source_to_string (NMPlatformSource source)
 	return "unknown";
 }
 
-#define TO_STRING_DEV_BUF_SIZE (5+15+1)
-static void
-_to_string_dev (int ifindex, char *buf, size_t size)
-{
-	g_assert (buf && size >= TO_STRING_DEV_BUF_SIZE);
-
-	if (ifindex){
-		const char *name = ifindex > 0 ? nm_platform_link_get_name (ifindex) : NULL;
-
-		strcpy (buf, " dev ");
-		buf += 5;
-		size -= 5;
-
-		if (name)
-			g_strlcpy (buf, name, size);
-		else
-			g_snprintf (buf, size, "%d", ifindex);
-	} else
-		buf[0] = 0;
-}
-
 static const char *
 _lifetime_to_string (guint32 timestamp, guint32 lifetime, gint32 now, char *buf, size_t buf_size)
 {
@@ -2330,7 +2477,7 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route)
 
 	_to_string_dev (route->ifindex, str_dev, sizeof (str_dev));
 
-	g_snprintf (to_string_buffer, sizeof (to_string_buffer), "%s/%d via %s%s metric %u mss %u src %s",
+	g_snprintf (to_string_buffer, sizeof (to_string_buffer), "%s/%d via %s%s metric %"G_GUINT32_FORMAT" mss %"G_GUINT32_FORMAT" src %s",
 	            s_network, route->plen, s_gateway,
 	            str_dev,
 	            route->metric, route->mss,
@@ -2363,7 +2510,7 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route)
 
 	_to_string_dev (route->ifindex, str_dev, sizeof (str_dev));
 
-	g_snprintf (to_string_buffer, sizeof (to_string_buffer), "%s/%d via %s%s metric %u mss %u src %s",
+	g_snprintf (to_string_buffer, sizeof (to_string_buffer), "%s/%d via %s%s metric %"G_GUINT32_FORMAT" mss %"G_GUINT32_FORMAT" src %s",
 	            s_network, route->plen, s_gateway,
 	            str_dev,
 	            route->metric, route->mss,
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index 96b6cfab..848f78e4 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -18,17 +18,17 @@
  * Copyright (C) 2009 - 2010 Red Hat, Inc.
  */
 
-#ifndef NM_PLATFORM_H
-#define NM_PLATFORM_H
+#ifndef __NETWORKMANAGER_PLATFORM_H__
+#define __NETWORKMANAGER_PLATFORM_H__
 
 #include <glib-object.h>
 #include "nm-glib-compat.h"
 #include <netinet/in.h>
-#include <net/ethernet.h>
 #include <linux/if.h>
 #include <linux/if_addr.h>
 
-#include <NetworkManager.h>
+#include <nm-dbus-interface.h>
+#include "nm-types.h"
 
 #define NM_TYPE_PLATFORM            (nm_platform_get_type ())
 #define NM_PLATFORM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_PLATFORM, NMPlatform))
@@ -72,54 +72,11 @@ typedef enum {
 	NM_PLATFORM_REASON_CACHE_CHECK
 } NMPlatformReason;
 
-typedef enum {
-	/* Please don't interpret type numbers outside nm-platform and use functions
-	 * like nm_platform_link_is_software() and nm_platform_supports_slaves().
-	 *
-	 * type & 0x10000 -> Software device type
-	 * type & 0x20000 -> Type supports slaves
-	 */
-
-	/* No type, used as error value */
-	NM_LINK_TYPE_NONE,
-
-	/* Unknown type  */
-	NM_LINK_TYPE_UNKNOWN,
-
-	/* Hardware types */
-	NM_LINK_TYPE_ETHERNET,
-	NM_LINK_TYPE_INFINIBAND,
-	NM_LINK_TYPE_OLPC_MESH,
-	NM_LINK_TYPE_WIFI,
-	NM_LINK_TYPE_WWAN_ETHERNET,   /* WWAN pseudo-ethernet */
-	NM_LINK_TYPE_WIMAX,
-
-	/* Software types */
-	NM_LINK_TYPE_DUMMY = 0x10000,
-	NM_LINK_TYPE_GRE,
-	NM_LINK_TYPE_GRETAP,
-	NM_LINK_TYPE_IFB,
-	NM_LINK_TYPE_LOOPBACK,
-	NM_LINK_TYPE_MACVLAN,
-	NM_LINK_TYPE_MACVTAP,
-	NM_LINK_TYPE_OPENVSWITCH,
-	NM_LINK_TYPE_TAP,
-	NM_LINK_TYPE_TUN,
-	NM_LINK_TYPE_VETH,
-	NM_LINK_TYPE_VLAN,
-	NM_LINK_TYPE_VXLAN,
-
-	/* Software types with slaves */
-	NM_LINK_TYPE_BRIDGE = 0x10000 | 0x20000,
-	NM_LINK_TYPE_BOND,
-	NM_LINK_TYPE_TEAM,
-} NMLinkType;
-
 #define __NMPlatformObject_COMMON \
 	int ifindex; \
 	;
 
-typedef struct {
+struct _NMPlatformLink {
 	__NMPlatformObject_COMMON;
 	char name[IFNAMSIZ];
 	NMLinkType type;
@@ -132,7 +89,7 @@ typedef struct {
 	gboolean connected;
 	gboolean arp;
 	guint mtu;
-} NMPlatformLink;
+};
 
 typedef enum {
 	NM_PLATFORM_SIGNAL_ADDED,
@@ -143,19 +100,10 @@ typedef enum {
 #define NM_PLATFORM_LIFETIME_PERMANENT G_MAXUINT32
 
 typedef enum {
-	/* In priority order; higher number == higher priority */
-	NM_PLATFORM_SOURCE_UNKNOWN,
-	NM_PLATFORM_SOURCE_KERNEL,
-	NM_PLATFORM_SOURCE_SHARED,
-	NM_PLATFORM_SOURCE_IP4LL,
-	NM_PLATFORM_SOURCE_PPP,
-	NM_PLATFORM_SOURCE_WWAN,
-	NM_PLATFORM_SOURCE_VPN,
-	NM_PLATFORM_SOURCE_DHCP,
-	NM_PLATFORM_SOURCE_RDISC,
-	NM_PLATFORM_SOURCE_USER,
-} NMPlatformSource;
-
+	NM_PLATFORM_GET_ROUTE_MODE_ALL,
+	NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT,
+	NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT,
+} NMPlatformGetRouteMode;
 
 typedef struct {
 	__NMPlatformObject_COMMON;
@@ -164,7 +112,7 @@ typedef struct {
 
 #define __NMPlatformIPAddress_COMMON \
 	__NMPlatformObject_COMMON; \
-	NMPlatformSource source; \
+	NMIPConfigSource source; \
 	\
 	/* Timestamp in seconds in the reference system of nm_utils_get_monotonic_timestamp_*().
 	 *
@@ -207,37 +155,55 @@ typedef struct {
  * NMPlatformIP4Address:
  * @timestamp: timestamp as returned by nm_utils_get_monotonic_timestamp_s()
  **/
-typedef struct {
+struct _NMPlatformIP4Address {
 	__NMPlatformIPAddress_COMMON;
 	in_addr_t address;
 	in_addr_t peer_address;  /* PTP peer address */
 	char label[IFNAMSIZ];
-} NMPlatformIP4Address;
+};
 G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPAddress, address_ptr) == G_STRUCT_OFFSET (NMPlatformIP4Address, address));
 
 /**
  * NMPlatformIP6Address:
  * @timestamp: timestamp as returned by nm_utils_get_monotonic_timestamp_s()
  **/
-typedef struct {
+struct _NMPlatformIP6Address {
 	__NMPlatformIPAddress_COMMON;
 	struct in6_addr address;
 	struct in6_addr peer_address;
 	guint flags; /* ifa_flags from <linux/if_addr.h>, field type "unsigned int" is as used in rtnl_addr_get_flags. */
-} NMPlatformIP6Address;
+};
 G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPAddress, address_ptr) == G_STRUCT_OFFSET (NMPlatformIP6Address, address));
 
+typedef union {
+	NMPlatformIPAddress  ax;
+	NMPlatformIP4Address a4;
+	NMPlatformIP6Address a6;
+} NMPlatformIPXAddress;
+
 #undef __NMPlatformIPAddress_COMMON
 
 
-#define NM_PLATFORM_ROUTE_METRIC_DEFAULT 1024
+/* Default value for adding an IPv4 route. This is also what iproute2 does.
+ * Note that contrary to IPv6, you can add routes with metric 0 and it is even
+ * the default.
+ */
+#define NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4 0
+
+/* Default value for adding an IPv6 route. This is also what iproute2 does.
+ * Adding an IPv6 route with metric 0, kernel translates to IP6_RT_PRIO_USER (1024). */
+#define NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6 1024
+
+/* For IPv4, kernel adds a device route (subnet routes) with metric 0 when user
+ * configures addresses. */
+#define NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE 0
 
 #define __NMPlatformIPRoute_COMMON \
 	__NMPlatformObject_COMMON; \
-	NMPlatformSource source; \
+	NMIPConfigSource source; \
 	int plen; \
-	guint metric; \
-	guint mss; \
+	guint32 metric; \
+	guint32 mss; \
 	;
 
 typedef struct {
@@ -248,20 +214,29 @@ typedef struct {
 	};
 } NMPlatformIPRoute;
 
-typedef struct {
+#define NM_PLATFORM_IP_ROUTE_IS_DEFAULT(route) \
+	( ((const NMPlatformIPRoute *) (route))->plen <= 0 )
+
+struct _NMPlatformIP4Route {
 	__NMPlatformIPRoute_COMMON;
 	in_addr_t network;
 	in_addr_t gateway;
-} NMPlatformIP4Route;
+};
 G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPRoute, network_ptr) == G_STRUCT_OFFSET (NMPlatformIP4Route, network));
 
-typedef struct {
+struct _NMPlatformIP6Route {
 	__NMPlatformIPRoute_COMMON;
 	struct in6_addr network;
 	struct in6_addr gateway;
-} NMPlatformIP6Route;
+};
 G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPRoute, network_ptr) == G_STRUCT_OFFSET (NMPlatformIP6Route, network));
 
+typedef union {
+	NMPlatformIPRoute  rx;
+	NMPlatformIP4Route r4;
+	NMPlatformIP6Route r6;
+} NMPlatformIPXRoute;
+
 #undef __NMPlatformIPRoute_COMMON
 
 
@@ -384,6 +359,9 @@ typedef struct {
 	gboolean (*link_is_connected) (NMPlatform *, int ifindex);
 	gboolean (*link_uses_arp) (NMPlatform *, int ifindex);
 
+	gboolean (*link_get_user_ipv6ll_enabled) (NMPlatform *, int ifindex);
+	gboolean (*link_set_user_ipv6ll_enabled) (NMPlatform *, int ifindex, gboolean enabled);
+
 	gconstpointer (*link_get_address) (NMPlatform *, int ifindex, size_t *length);
 	gboolean (*link_set_address) (NMPlatform *, int ifindex, gconstpointer address, size_t length);
 	guint32 (*link_get_mtu) (NMPlatform *, int ifindex);
@@ -417,7 +395,7 @@ typedef struct {
 	gboolean (*gre_get_properties) (NMPlatform *, int ifindex, NMPlatformGreProperties *props);
 
 	gboolean    (*wifi_get_capabilities) (NMPlatform *, int ifindex, NMDeviceWifiCapabilities *caps);
-	gboolean    (*wifi_get_bssid)        (NMPlatform *, int ifindex, struct ether_addr *bssid);
+	gboolean    (*wifi_get_bssid)        (NMPlatform *, int ifindex, guint8 *bssid);
 	GByteArray *(*wifi_get_ssid)         (NMPlatform *, int ifindex);
 	guint32     (*wifi_get_frequency)    (NMPlatform *, int ifindex);
 	int         (*wifi_get_quality)      (NMPlatform *, int ifindex);
@@ -429,7 +407,7 @@ typedef struct {
 
 	guint32     (*mesh_get_channel)      (NMPlatform *, int ifindex);
 	gboolean    (*mesh_set_channel)      (NMPlatform *, int ifindex, guint32 channel);
-	gboolean    (*mesh_set_ssid)         (NMPlatform *, int ifindex, const GByteArray *ssid);
+	gboolean    (*mesh_set_ssid)         (NMPlatform *, int ifindex, const guint8 *ssid, gsize len);
 
 	GArray * (*ip4_address_get_all) (NMPlatform *, int ifindex);
 	GArray * (*ip6_address_get_all) (NMPlatform *, int ifindex);
@@ -440,25 +418,28 @@ typedef struct {
 	gboolean (*ip6_address_add) (NMPlatform *, int ifindex,
 	                             struct in6_addr address, struct in6_addr peer_address, int plen,
 	                             guint32 lifetime, guint32 preferred_lft, guint flags);
-	gboolean (*ip4_address_delete) (NMPlatform *, int ifindex, in_addr_t address, int plen);
+	gboolean (*ip4_address_delete) (NMPlatform *, int ifindex, in_addr_t address, int plen, in_addr_t peer_address);
 	gboolean (*ip6_address_delete) (NMPlatform *, int ifindex, struct in6_addr address, int plen);
 	gboolean (*ip4_address_exists) (NMPlatform *, int ifindex, in_addr_t address, int plen);
 	gboolean (*ip6_address_exists) (NMPlatform *, int ifindex, struct in6_addr address, int plen);
 
-	GArray * (*ip4_route_get_all) (NMPlatform *, int ifindex, gboolean include_default);
-	GArray * (*ip6_route_get_all) (NMPlatform *, int ifindex, gboolean include_default);
-	gboolean (*ip4_route_add) (NMPlatform *, int ifindex, NMPlatformSource source,
+	gboolean (*ip4_check_reinstall_device_route) (NMPlatform *, int ifindex, const NMPlatformIP4Address *address, guint32 device_route_metric);
+
+	GArray * (*ip4_route_get_all) (NMPlatform *, int ifindex, NMPlatformGetRouteMode mode);
+	GArray * (*ip6_route_get_all) (NMPlatform *, int ifindex, NMPlatformGetRouteMode mode);
+	gboolean (*ip4_route_add) (NMPlatform *, int ifindex, NMIPConfigSource source,
 	                           in_addr_t network, int plen, in_addr_t gateway,
-	                           int prio, int mss);
-	gboolean (*ip6_route_add) (NMPlatform *, int ifindex, NMPlatformSource source,
+	                           guint32 pref_src, guint32 metric, guint32 mss);
+	gboolean (*ip6_route_add) (NMPlatform *, int ifindex, NMIPConfigSource source,
 	                           struct in6_addr network, int plen, struct in6_addr gateway,
-	                           int prio, int mss);
-	gboolean (*ip4_route_delete) (NMPlatform *, int ifindex, in_addr_t network, int plen, int metric);
-	gboolean (*ip6_route_delete) (NMPlatform *, int ifindex, struct in6_addr network, int plen, int metric);
-	gboolean (*ip4_route_exists) (NMPlatform *, int ifindex, in_addr_t network, int plen, int metric);
-	gboolean (*ip6_route_exists) (NMPlatform *, int ifindex, struct in6_addr network, int plen, int metric);
+	                           guint32 metric, guint32 mss);
+	gboolean (*ip4_route_delete) (NMPlatform *, int ifindex, in_addr_t network, int plen, guint32 metric);
+	gboolean (*ip6_route_delete) (NMPlatform *, int ifindex, struct in6_addr network, int plen, guint32 metric);
+	gboolean (*ip4_route_exists) (NMPlatform *, int ifindex, in_addr_t network, int plen, guint32 metric);
+	gboolean (*ip6_route_exists) (NMPlatform *, int ifindex, struct in6_addr network, int plen, guint32 metric);
 
 	gboolean (*check_support_kernel_extended_ifa_flags) (NMPlatform *);
+	gboolean (*check_support_user_ipv6ll) (NMPlatform *);
 } NMPlatformClass;
 
 /* NMPlatform signals
@@ -524,6 +505,9 @@ gboolean nm_platform_link_is_up (int ifindex);
 gboolean nm_platform_link_is_connected (int ifindex);
 gboolean nm_platform_link_uses_arp (int ifindex);
 
+gboolean nm_platform_link_get_user_ipv6ll_enabled (int ifindex);
+gboolean nm_platform_link_set_user_ipv6ll_enabled (int ifindex, gboolean enabled);
+
 gconstpointer nm_platform_link_get_address (int ifindex, size_t *length);
 gboolean nm_platform_link_set_address (int ifindex, const void *address, size_t length);
 guint32 nm_platform_link_get_mtu (int ifindex);
@@ -557,7 +541,7 @@ gboolean nm_platform_vxlan_get_properties (int ifindex, NMPlatformVxlanPropertie
 gboolean nm_platform_gre_get_properties (int ifindex, NMPlatformGreProperties *props);
 
 gboolean    nm_platform_wifi_get_capabilities (int ifindex, NMDeviceWifiCapabilities *caps);
-gboolean    nm_platform_wifi_get_bssid        (int ifindex, struct ether_addr *bssid);
+gboolean    nm_platform_wifi_get_bssid        (int ifindex, guint8 *bssid);
 GByteArray *nm_platform_wifi_get_ssid         (int ifindex);
 guint32     nm_platform_wifi_get_frequency    (int ifindex);
 int         nm_platform_wifi_get_quality      (int ifindex);
@@ -569,7 +553,7 @@ void        nm_platform_wifi_indicate_addressing_running (int ifindex, gboolean
 
 guint32     nm_platform_mesh_get_channel      (int ifindex);
 gboolean    nm_platform_mesh_set_channel      (int ifindex, guint32 channel);
-gboolean    nm_platform_mesh_set_ssid         (int ifindex, const GByteArray *ssid);
+gboolean    nm_platform_mesh_set_ssid         (int ifindex, const guint8 *ssid, gsize len);
 
 GArray *nm_platform_ip4_address_get_all (int ifindex);
 GArray *nm_platform_ip6_address_get_all (int ifindex);
@@ -580,27 +564,28 @@ gboolean nm_platform_ip4_address_add (int ifindex,
 gboolean nm_platform_ip6_address_add (int ifindex,
                                       struct in6_addr address, struct in6_addr peer_address, int plen,
                                       guint32 lifetime, guint32 preferred_lft, guint flags);
-gboolean nm_platform_ip4_address_delete (int ifindex, in_addr_t address, int plen);
+gboolean nm_platform_ip4_address_delete (int ifindex, in_addr_t address, int plen, in_addr_t peer_address);
 gboolean nm_platform_ip6_address_delete (int ifindex, struct in6_addr address, int plen);
 gboolean nm_platform_ip4_address_exists (int ifindex, in_addr_t address, int plen);
 gboolean nm_platform_ip6_address_exists (int ifindex, struct in6_addr address, int plen);
-gboolean nm_platform_ip4_address_sync (int ifindex, const GArray *known_addresses);
+gboolean nm_platform_ip4_address_sync (int ifindex, const GArray *known_addresses, guint32 device_route_metric);
 gboolean nm_platform_ip6_address_sync (int ifindex, const GArray *known_addresses);
 gboolean nm_platform_address_flush (int ifindex);
 
-GArray *nm_platform_ip4_route_get_all (int ifindex, gboolean include_default);
-GArray *nm_platform_ip6_route_get_all (int ifindex, gboolean include_default);
-gboolean nm_platform_route_set_metric (int ifindex, int metric);
-gboolean nm_platform_ip4_route_add (int ifindex, NMPlatformSource source,
+gboolean nm_platform_ip4_check_reinstall_device_route (int ifindex, const NMPlatformIP4Address *address, guint32 device_route_metric);
+
+GArray *nm_platform_ip4_route_get_all (int ifindex, NMPlatformGetRouteMode mode);
+GArray *nm_platform_ip6_route_get_all (int ifindex, NMPlatformGetRouteMode mode);
+gboolean nm_platform_ip4_route_add (int ifindex, NMIPConfigSource source,
                                     in_addr_t network, int plen, in_addr_t gateway,
-                                    int metric, int mss);
-gboolean nm_platform_ip6_route_add (int ifindex, NMPlatformSource source,
+                                    guint32 pref_src, guint32 metric, guint32 mss);
+gboolean nm_platform_ip6_route_add (int ifindex, NMIPConfigSource source,
                                     struct in6_addr network, int plen, struct in6_addr gateway,
-                                    int metric, int mss);
-gboolean nm_platform_ip4_route_delete (int ifindex, in_addr_t network, int plen, int metric);
-gboolean nm_platform_ip6_route_delete (int ifindex, struct in6_addr network, int plen, int metric);
-gboolean nm_platform_ip4_route_exists (int ifindex, in_addr_t network, int plen, int metric);
-gboolean nm_platform_ip6_route_exists (int ifindex, struct in6_addr network, int plen, int metric);
+                                    guint32 metric, guint32 mss);
+gboolean nm_platform_ip4_route_delete (int ifindex, in_addr_t network, int plen, guint32 metric);
+gboolean nm_platform_ip6_route_delete (int ifindex, struct in6_addr network, int plen, guint32 metric);
+gboolean nm_platform_ip4_route_exists (int ifindex, in_addr_t network, int plen, guint32 metric);
+gboolean nm_platform_ip6_route_exists (int ifindex, struct in6_addr network, int plen, guint32 metric);
 gboolean nm_platform_ip4_route_sync (int ifindex, const GArray *known_routes);
 gboolean nm_platform_ip6_route_sync (int ifindex, const GArray *known_routes);
 gboolean nm_platform_route_flush (int ifindex);
@@ -619,16 +604,10 @@ int nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6R
 
 gboolean nm_platform_check_support_libnl_extended_ifa_flags (void);
 gboolean nm_platform_check_support_kernel_extended_ifa_flags (void);
+gboolean nm_platform_check_support_user_ipv6ll (void);
 
 void nm_platform_addr_flags2str (int flags, char *buf, size_t size);
 
 int nm_platform_ip_address_cmp_expiry (const NMPlatformIPAddress *a, const NMPlatformIPAddress *b);
 
-#define auto_g_free __attribute__((cleanup(put_g_free)))
-static void __attribute__((unused))
-put_g_free (void *ptr)
-{
-	g_clear_pointer ((gpointer *) ptr, g_free);
-}
-
-#endif /* NM_PLATFORM_H */
+#endif /* __NETWORKMANAGER_PLATFORM_H__ */
diff --git a/src/platform/tests/Makefile.am b/src/platform/tests/Makefile.am
index 9b10ea7b..b06e25e0 100644
--- a/src/platform/tests/Makefile.am
+++ b/src/platform/tests/Makefile.am
@@ -1,14 +1,13 @@
 AM_CPPFLAGS = \
 	-I${top_srcdir} \
 	-I${top_srcdir}/include \
-	-I${top_builddir}/include \
 	-I${top_srcdir}/src \
 	-I${top_builddir}/src \
-	-I${top_srcdir}/src/logging \
-	-I${top_srcdir}/libnm-util \
-	-I${top_builddir}/libnm-util \
+	-I${top_srcdir}/libnm-core \
+	-I${top_builddir}/libnm-core \
 	-I${srcdir}/.. \
 	-DG_LOG_DOMAIN=\""NetworkManager"\" \
+	-DNETWORKMANAGER_COMPILATION \
 	-DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \
 	$(GLIB_CFLAGS) \
 	$(GUDEV_CFLAGS) \
@@ -111,6 +110,6 @@ test_cleanup_linux_CPPFLAGS = \
 test_cleanup_linux_LDADD = $(PLATFORM_LDADD)
 
 #@VALGRIND_RULES@
-TESTS = test-link-fake test-address-fake test-route-fake test-cleanup-fake test-link-linux test-address-linux test-route-linux test-cleanup-linux
+TESTS = test-link-fake test-address-fake test-route-fake test-cleanup-fake test-address-linux test-route-linux test-cleanup-linux
 
 
diff --git a/src/platform/tests/Makefile.in b/src/platform/tests/Makefile.in
index 6b03e315..052636ab 100644
--- a/src/platform/tests/Makefile.in
+++ b/src/platform/tests/Makefile.in
@@ -86,8 +86,8 @@ noinst_PROGRAMS = dump$(EXEEXT) monitor$(EXEEXT) platform$(EXEEXT) \
 	test-cleanup-fake$(EXEEXT) test-cleanup-linux$(EXEEXT)
 TESTS = test-link-fake$(EXEEXT) test-address-fake$(EXEEXT) \
 	test-route-fake$(EXEEXT) test-cleanup-fake$(EXEEXT) \
-	test-link-linux$(EXEEXT) test-address-linux$(EXEEXT) \
-	test-route-linux$(EXEEXT) test-cleanup-linux$(EXEEXT)
+	test-address-linux$(EXEEXT) test-route-linux$(EXEEXT) \
+	test-cleanup-linux$(EXEEXT)
 subdir = src/platform/tests
 DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
 	$(top_srcdir)/build-aux/depcomp
@@ -299,6 +299,8 @@ AUTOCONF = @AUTOCONF@
 AUTOHEADER = @AUTOHEADER@
 AUTOMAKE = @AUTOMAKE@
 AWK = @AWK@
+BLUEZ5_CFLAGS = @BLUEZ5_CFLAGS@
+BLUEZ5_LIBS = @BLUEZ5_LIBS@
 CC = @CC@
 CCDEPMODE = @CCDEPMODE@
 CFLAGS = @CFLAGS@
@@ -422,6 +424,7 @@ NEWT_CFLAGS = @NEWT_CFLAGS@
 NEWT_LIBS = @NEWT_LIBS@
 NM = @NM@
 NMEDIT = @NMEDIT@
+NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@
 NM_MAJOR_VERSION = @NM_MAJOR_VERSION@
 NM_MICRO_VERSION = @NM_MICRO_VERSION@
 NM_MINOR_VERSION = @NM_MINOR_VERSION@
@@ -441,6 +444,7 @@ PACKAGE_TARNAME = @PACKAGE_TARNAME@
 PACKAGE_URL = @PACKAGE_URL@
 PACKAGE_VERSION = @PACKAGE_VERSION@
 PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
 PKG_CONFIG = @PKG_CONFIG@
 PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
 PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
@@ -467,7 +471,7 @@ SYSTEMD_INHIBIT_LIBS = @SYSTEMD_INHIBIT_LIBS@
 SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@
 SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
-UDEV_BASE_DIR = @UDEV_BASE_DIR@
+UDEV_DIR = @UDEV_DIR@
 USE_NLS = @USE_NLS@
 UUID_CFLAGS = @UUID_CFLAGS@
 UUID_LIBS = @UUID_LIBS@
@@ -547,10 +551,10 @@ with_netconfig = @with_netconfig@
 with_resolvconf = @with_resolvconf@
 with_valgrind = @with_valgrind@
 AM_CPPFLAGS = -I${top_srcdir} -I${top_srcdir}/include \
-	-I${top_builddir}/include -I${top_srcdir}/src \
-	-I${top_builddir}/src -I${top_srcdir}/src/logging \
-	-I${top_srcdir}/libnm-util -I${top_builddir}/libnm-util \
+	-I${top_srcdir}/src -I${top_builddir}/src \
+	-I${top_srcdir}/libnm-core -I${top_builddir}/libnm-core \
 	-I${srcdir}/.. -DG_LOG_DOMAIN=\""NetworkManager"\" \
+	-DNETWORKMANAGER_COMPILATION \
 	-DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE $(GLIB_CFLAGS) \
 	$(GUDEV_CFLAGS) $(LIBNL_CFLAGS) $(am__append_1)
 PLATFORM_SOURCES = \
diff --git a/src/platform/tests/dump.c b/src/platform/tests/dump.c
index e97ef138..3bb61da4 100644
--- a/src/platform/tests/dump.c
+++ b/src/platform/tests/dump.c
@@ -1,3 +1,5 @@
+#include "config.h"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <arpa/inet.h>
@@ -83,8 +85,8 @@ dump_interface (NMPlatformLink *link)
 	g_array_unref (ip4_addresses);
 	g_array_unref (ip6_addresses);
 
-	ip4_routes = nm_platform_ip4_route_get_all (link->ifindex, TRUE);
-	ip6_routes = nm_platform_ip6_route_get_all (link->ifindex, TRUE);
+	ip4_routes = nm_platform_ip4_route_get_all (link->ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
+	ip6_routes = nm_platform_ip6_route_get_all (link->ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
 
 	g_assert (ip4_routes);
 	g_assert (ip6_routes);
diff --git a/src/platform/tests/monitor.c b/src/platform/tests/monitor.c
index d56cc2bf..9aff1047 100644
--- a/src/platform/tests/monitor.c
+++ b/src/platform/tests/monitor.c
@@ -1,3 +1,5 @@
+#include "config.h"
+
 #include <stdlib.h>
 #include <syslog.h>
 
diff --git a/src/platform/tests/platform.c b/src/platform/tests/platform.c
index ea8bd0e3..eea6610d 100644
--- a/src/platform/tests/platform.c
+++ b/src/platform/tests/platform.c
@@ -18,12 +18,15 @@
  * Copyright (C) 2013 Red Hat, Inc.
  */
 
+#include "config.h"
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <arpa/inet.h>
 #include <netlink/route/addr.h>
 
+#include "gsystem-local-alloc.h"
 #include "nm-platform.h"
 #include "nm-linux-platform.h"
 #include "nm-fake-platform.h"
@@ -47,7 +50,7 @@ do_sysctl_set (char **argv)
 static gboolean
 do_sysctl_get (char **argv)
 {
-	auto_g_free char *value = nm_platform_sysctl_get (argv[0]);
+	gs_free char *value = nm_platform_sysctl_get (argv[0]);
 
 	printf ("%s\n", value);
 
@@ -281,7 +284,7 @@ do_master_get_option (char **argv)
 {
 	int ifindex = parse_ifindex (*argv++);
 	const char *option = *argv++;
-	auto_g_free char *value = nm_platform_master_get_option (ifindex, option);
+	gs_free char *value = nm_platform_master_get_option (ifindex, option);
 
 	printf ("%s\n", value);
 
@@ -303,7 +306,7 @@ do_slave_get_option (char **argv)
 {
 	int ifindex = parse_ifindex (*argv++);
 	const char *option = *argv++;
-	auto_g_free char *value = nm_platform_slave_get_option (ifindex, option);
+	gs_free char *value = nm_platform_slave_get_option (ifindex, option);
 
 	printf ("%s\n", value);
 
@@ -532,6 +535,9 @@ parse_ip_address (int family, char *str, gpointer address, int *plen)
 {
 	char *endptr;
 
+	if (plen)
+		*plen = 0;
+
 	if (plen) {
 		char *ptr = strchr (str, '/');
 		if (ptr) {
@@ -594,7 +600,7 @@ do_ip6_address_add (char **argv)
 		return FALSE;
 }
 
-#define ADDR_CMD_FULL(v, cmdname, print) \
+#define ADDR_CMD_FULL(v, cmdname, print, ...) \
 	static gboolean \
 	do_##v##_address_##cmdname (char **argv) \
 	{ \
@@ -602,7 +608,7 @@ do_ip6_address_add (char **argv)
 		v##_t address; \
 		int plen; \
 		if (ifindex && parse_##v##_address (*argv++, &address, &plen)) { \
-			gboolean value = nm_platform_##v##_address_##cmdname (ifindex, address, plen); \
+			gboolean value = nm_platform_##v##_address_##cmdname (ifindex, address, plen, ##__VA_ARGS__); \
 			if (print) { \
 				print_boolean (value); \
 				return TRUE; \
@@ -611,7 +617,7 @@ do_ip6_address_add (char **argv)
 		} else \
 			return FALSE; \
 	}
-#define ADDR_CMD(cmdname) ADDR_CMD_FULL (ip4, cmdname, FALSE) ADDR_CMD_FULL (ip6, cmdname, FALSE)
+#define ADDR_CMD(cmdname) ADDR_CMD_FULL (ip4, cmdname, FALSE, 0) ADDR_CMD_FULL (ip6, cmdname, FALSE)
 #define ADDR_CMD_PRINT(cmdname) ADDR_CMD_FULL (ip4, cmdname, TRUE) ADDR_CMD_FULL (ip6, cmdname, TRUE)
 
 ADDR_CMD (delete)
@@ -627,7 +633,7 @@ do_ip4_route_get_all (char **argv)
 	int i;
 
 	if (ifindex) {
-		routes = nm_platform_ip4_route_get_all (ifindex, TRUE);
+		routes = nm_platform_ip4_route_get_all (ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
 		for (i = 0; i < routes->len; i++) {
 			route = &g_array_index (routes, NMPlatformIP4Route, i);
 			inet_ntop (AF_INET, &route->network, networkstr, sizeof (networkstr));
@@ -651,7 +657,7 @@ do_ip6_route_get_all (char **argv)
 	int i;
 
 	if (ifindex) {
-		routes = nm_platform_ip6_route_get_all (ifindex, TRUE);
+		routes = nm_platform_ip6_route_get_all (ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
 		for (i = 0; i < routes->len; i++) {
 			route = &g_array_index (routes, NMPlatformIP6Route, i);
 			inet_ntop (AF_INET6, &route->network, networkstr, sizeof (networkstr));
@@ -677,8 +683,8 @@ do_ip4_route_add (char **argv)
 	metric = strtol (*argv++, NULL, 10);
 	mss = strtol (*argv++, NULL, 10);
 
-	return nm_platform_ip4_route_add (ifindex, NM_PLATFORM_SOURCE_USER,
-	                                  network, plen, gateway,
+	return nm_platform_ip4_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER,
+	                                  network, plen, gateway, 0,
 	                                  metric, mss);
 }
 
@@ -693,7 +699,7 @@ do_ip6_route_add (char **argv)
 	parse_ip6_address (*argv++, &gateway, NULL);
 	metric = strtol (*argv++, NULL, 10);
 	mss = strtol (*argv++, NULL, 10);
-	return nm_platform_ip6_route_add (ifindex, NM_PLATFORM_SOURCE_USER,
+	return nm_platform_ip6_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER,
 	                                  network, plen, gateway,
 	                                  metric, mss);
 }
diff --git a/src/platform/tests/test-address.c b/src/platform/tests/test-address.c
index 3fef5375..3ef13b8e 100644
--- a/src/platform/tests/test-address.c
+++ b/src/platform/tests/test-address.c
@@ -1,3 +1,5 @@
+#include "config.h"
+
 #include "test-common.h"
 
 #define DEVICE_NAME "nm-test-device"
@@ -91,13 +93,13 @@ test_ip4_address (void)
 	g_array_unref (addresses);
 
 	/* Remove address */
-	g_assert (nm_platform_ip4_address_delete (ifindex, addr, IP4_PLEN));
+	g_assert (nm_platform_ip4_address_delete (ifindex, addr, IP4_PLEN, 0));
 	no_error ();
 	g_assert (!nm_platform_ip4_address_exists (ifindex, addr, IP4_PLEN));
 	accept_signal (address_removed);
 
 	/* Remove address again */
-	g_assert (nm_platform_ip4_address_delete (ifindex, addr, IP4_PLEN));
+	g_assert (nm_platform_ip4_address_delete (ifindex, addr, IP4_PLEN, 0));
 	no_error ();
 
 	free_signal (address_added);
@@ -196,7 +198,7 @@ test_ip4_address_external (void)
 	g_assert (nm_platform_ip4_address_exists (ifindex, addr, IP4_PLEN));
 	accept_signal (address_added);
 	/*run_command ("ip address delete %s/%d dev %s", IP4_ADDRESS, IP4_PLEN, DEVICE_NAME);
-	g_assert (nm_platform_ip4_address_delete (ifindex, addr, IP4_PLEN));
+	g_assert (nm_platform_ip4_address_delete (ifindex, addr, IP4_PLEN, 0));
 	no_error ();
 	g_assert (!nm_platform_ip4_address_exists (ifindex, addr, IP4_PLEN));
 	accept_signal (address_removed);*/
diff --git a/src/platform/tests/test-cleanup.c b/src/platform/tests/test-cleanup.c
index e60d82f0..afbb438c 100644
--- a/src/platform/tests/test-cleanup.c
+++ b/src/platform/tests/test-cleanup.c
@@ -1,9 +1,11 @@
+#include "config.h"
+
 #include "test-common.h"
 
 #define DEVICE_NAME "nm-test-device"
 
 static void
-test_cleanup_internal ()
+test_cleanup_internal (void)
 {
 	SignalData *link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, DEVICE_NAME);
 	int ifindex;
@@ -43,17 +45,17 @@ test_cleanup_internal ()
 	/* Add routes and addresses */
 	g_assert (nm_platform_ip4_address_add (ifindex, addr4, 0, plen4, lifetime, preferred, NULL));
 	g_assert (nm_platform_ip6_address_add (ifindex, addr6, in6addr_any, plen6, lifetime, preferred, flags));
-	g_assert (nm_platform_ip4_route_add (ifindex, NM_PLATFORM_SOURCE_USER, gateway4, 32, INADDR_ANY, metric, mss));
-	g_assert (nm_platform_ip4_route_add (ifindex, NM_PLATFORM_SOURCE_USER, network4, plen4, gateway4, metric, mss));
-	g_assert (nm_platform_ip4_route_add (ifindex, NM_PLATFORM_SOURCE_USER, 0, 0, gateway4, metric, mss));
-	g_assert (nm_platform_ip6_route_add (ifindex, NM_PLATFORM_SOURCE_USER, gateway6, 128, in6addr_any, metric, mss));
-	g_assert (nm_platform_ip6_route_add (ifindex, NM_PLATFORM_SOURCE_USER, network6, plen6, gateway6, metric, mss));
-	g_assert (nm_platform_ip6_route_add (ifindex, NM_PLATFORM_SOURCE_USER, in6addr_any, 0, gateway6, metric, mss));
+	g_assert (nm_platform_ip4_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, gateway4, 32, INADDR_ANY, 0, metric, mss));
+	g_assert (nm_platform_ip4_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, network4, plen4, gateway4, 0, metric, mss));
+	g_assert (nm_platform_ip4_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway4, 0, metric, mss));
+	g_assert (nm_platform_ip6_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, gateway6, 128, in6addr_any, metric, mss));
+	g_assert (nm_platform_ip6_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, network6, plen6, gateway6, metric, mss));
+	g_assert (nm_platform_ip6_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway6, metric, mss));
 
 	addresses4 = nm_platform_ip4_address_get_all (ifindex);
 	addresses6 = nm_platform_ip6_address_get_all (ifindex);
-	routes4 = nm_platform_ip4_route_get_all (ifindex, TRUE);
-	routes6 = nm_platform_ip6_route_get_all (ifindex, TRUE);
+	routes4 = nm_platform_ip4_route_get_all (ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
+	routes6 = nm_platform_ip6_route_get_all (ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
 
 	g_assert_cmpint (addresses4->len, ==, 1);
 	g_assert_cmpint (addresses6->len, ==, 1);
@@ -70,8 +72,8 @@ test_cleanup_internal ()
 
 	addresses4 = nm_platform_ip4_address_get_all (ifindex);
 	addresses6 = nm_platform_ip6_address_get_all (ifindex);
-	routes4 = nm_platform_ip4_route_get_all (ifindex, TRUE);
-	routes6 = nm_platform_ip6_route_get_all (ifindex, TRUE);
+	routes4 = nm_platform_ip4_route_get_all (ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
+	routes6 = nm_platform_ip6_route_get_all (ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
 
 	g_assert_cmpint (addresses4->len, ==, 0);
 	g_assert_cmpint (addresses6->len, ==, 0);
diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c
index 59a770c6..ab40f652 100644
--- a/src/platform/tests/test-common.c
+++ b/src/platform/tests/test-common.c
@@ -1,3 +1,5 @@
+#include "config.h"
+
 #include "test-common.h"
 
 #include "nm-test-utils.h"
diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c
index a3f757c2..8bd2ef44 100644
--- a/src/platform/tests/test-link.c
+++ b/src/platform/tests/test-link.c
@@ -1,3 +1,5 @@
+#include "config.h"
+
 #include "test-common.h"
 #include "nm-test-utils.h"
 
@@ -130,6 +132,7 @@ software_add (NMLinkType link_type, const char *name)
 	default:
 		g_error ("Link type %d unhandled.", link_type);
 	}
+	g_assert_not_reached ();
 }
 
 static void
@@ -188,12 +191,12 @@ test_slave (int master, int type, SignalData *master_changed)
 			/* Older team versions (e.g. Fedora 17) have a bug that team master stays
 			 * IFF_LOWER_UP even if its slave is down. Double check it with iproute2 and if
 			 * `ip link` also claims master to be up, accept it. */
-			char *stdout = NULL;
+			char *stdout_str = NULL;
 
-			nmtst_spawn_sync (NULL, &stdout, NULL, 0, "/sbin/ip", "link", "show", "dev", nm_platform_link_get_name (master));
+			nmtst_spawn_sync (NULL, &stdout_str, NULL, 0, "/sbin/ip", "link", "show", "dev", nm_platform_link_get_name (master));
 
-			g_assert (strstr (stdout, "LOWER_UP"));
-			g_free (stdout);
+			g_assert (strstr (stdout_str, "LOWER_UP"));
+			g_free (stdout_str);
 		} else
 			g_assert_not_reached ();
 	}
@@ -379,7 +382,7 @@ test_team (void)
 }
 
 static void
-test_vlan ()
+test_vlan (void)
 {
 	test_software (NM_LINK_TYPE_VLAN, "vlan");
 }
diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c
index d45730ac..2c70b412 100644
--- a/src/platform/tests/test-route.c
+++ b/src/platform/tests/test-route.c
@@ -1,3 +1,5 @@
+#include "config.h"
+
 #include "test-common.h"
 #include "nm-test-utils.h"
 
@@ -48,7 +50,7 @@ ip6_route_callback (NMPlatform *platform, int ifindex, NMPlatformIP6Route *recei
 }
 
 static void
-test_ip4_route ()
+test_ip4_route (void)
 {
 	int ifindex = nm_platform_link_get_ifindex (DEVICE_NAME);
 	SignalData *route_added = add_signal (NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, NM_PLATFORM_SIGNAL_ADDED, ip4_route_callback);
@@ -59,63 +61,64 @@ test_ip4_route ()
 	in_addr_t network;
 	int plen = 24;
 	in_addr_t gateway;
-	int metric = 20;
+	/* Choose a high metric so that we hopefully don't conflict. */
+	int metric = 22986;
 	int mss = 1000;
 
 	inet_pton (AF_INET, "192.0.3.0", &network);
 	inet_pton (AF_INET, "198.51.100.1", &gateway);
 
 	/* Add route to gateway */
-	g_assert (nm_platform_ip4_route_add (ifindex, NM_PLATFORM_SOURCE_USER, gateway, 32, INADDR_ANY, metric, mss));
+	g_assert (nm_platform_ip4_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, gateway, 32, INADDR_ANY, 0, metric, mss));
 	no_error ();
 	accept_signal (route_added);
 
 	/* Add route */
 	g_assert (!nm_platform_ip4_route_exists (ifindex, network, plen, metric));
 	no_error ();
-	g_assert (nm_platform_ip4_route_add (ifindex, NM_PLATFORM_SOURCE_USER, network, plen, gateway, metric, mss));
+	g_assert (nm_platform_ip4_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, 0, metric, mss));
 	no_error ();
 	g_assert (nm_platform_ip4_route_exists (ifindex, network, plen, metric));
 	no_error ();
 	accept_signal (route_added);
 
 	/* Add route again */
-	g_assert (nm_platform_ip4_route_add (ifindex, NM_PLATFORM_SOURCE_USER, network, plen, gateway, metric, mss));
+	g_assert (nm_platform_ip4_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, 0, metric, mss));
 	no_error ();
 	accept_signal (route_changed);
 
 	/* Add default route */
 	g_assert (!nm_platform_ip4_route_exists (ifindex, 0, 0, metric));
 	no_error ();
-	g_assert (nm_platform_ip4_route_add (ifindex, NM_PLATFORM_SOURCE_USER, 0, 0, gateway, metric, mss));
+	g_assert (nm_platform_ip4_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway, 0, metric, mss));
 	no_error ();
 	g_assert (nm_platform_ip4_route_exists (ifindex, 0, 0, metric));
 	no_error ();
 	accept_signal (route_added);
 
 	/* Add default route again */
-	g_assert (nm_platform_ip4_route_add (ifindex, NM_PLATFORM_SOURCE_USER, 0, 0, gateway, metric, mss));
+	g_assert (nm_platform_ip4_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway, 0, metric, mss));
 	no_error ();
 	accept_signal (route_changed);
 
 	/* Test route listing */
-	routes = nm_platform_ip4_route_get_all (ifindex, TRUE);
+	routes = nm_platform_ip4_route_get_all (ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
 	memset (rts, 0, sizeof (rts));
-	rts[0].source = NM_PLATFORM_SOURCE_USER;
+	rts[0].source = NM_IP_CONFIG_SOURCE_USER;
 	rts[0].network = gateway;
 	rts[0].plen = 32;
 	rts[0].ifindex = ifindex;
 	rts[0].gateway = INADDR_ANY;
 	rts[0].metric = metric;
 	rts[0].mss = mss;
-	rts[1].source = NM_PLATFORM_SOURCE_USER;
+	rts[1].source = NM_IP_CONFIG_SOURCE_USER;
 	rts[1].network = network;
 	rts[1].plen = plen;
 	rts[1].ifindex = ifindex;
 	rts[1].gateway = gateway;
 	rts[1].metric = metric;
 	rts[1].mss = mss;
-	rts[2].source = NM_PLATFORM_SOURCE_USER;
+	rts[2].source = NM_IP_CONFIG_SOURCE_USER;
 	rts[2].network = 0;
 	rts[2].plen = 0;
 	rts[2].ifindex = ifindex;
@@ -143,7 +146,7 @@ test_ip4_route ()
 }
 
 static void
-test_ip6_route ()
+test_ip6_route (void)
 {
 	int ifindex = nm_platform_link_get_ifindex (DEVICE_NAME);
 	SignalData *route_added = add_signal (NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, NM_PLATFORM_SIGNAL_ADDED, ip6_route_callback);
@@ -154,63 +157,64 @@ test_ip6_route ()
 	struct in6_addr network;
 	int plen = 64;
 	struct in6_addr gateway;
-	int metric = 20;
+	/* Choose a high metric so that we hopefully don't conflict. */
+	int metric = 22987;
 	int mss = 1000;
 
 	inet_pton (AF_INET6, "2001:db8:a:b:0:0:0:0", &network);
 	inet_pton (AF_INET6, "2001:db8:c:d:1:2:3:4", &gateway);
 
 	/* Add route to gateway */
-	g_assert (nm_platform_ip6_route_add (ifindex, NM_PLATFORM_SOURCE_USER, gateway, 128, in6addr_any, metric, mss));
+	g_assert (nm_platform_ip6_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, gateway, 128, in6addr_any, metric, mss));
 	no_error ();
 	accept_signal (route_added);
 
 	/* Add route */
 	g_assert (!nm_platform_ip6_route_exists (ifindex, network, plen, metric));
 	no_error ();
-	g_assert (nm_platform_ip6_route_add (ifindex, NM_PLATFORM_SOURCE_USER, network, plen, gateway, metric, mss));
+	g_assert (nm_platform_ip6_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, metric, mss));
 	no_error ();
 	g_assert (nm_platform_ip6_route_exists (ifindex, network, plen, metric));
 	no_error ();
 	accept_signal (route_added);
 
 	/* Add route again */
-	g_assert (nm_platform_ip6_route_add (ifindex, NM_PLATFORM_SOURCE_USER, network, plen, gateway, metric, mss));
+	g_assert (nm_platform_ip6_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, metric, mss));
 	no_error ();
 	accept_signal (route_changed);
 
 	/* Add default route */
 	g_assert (!nm_platform_ip6_route_exists (ifindex, in6addr_any, 0, metric));
 	no_error ();
-	g_assert (nm_platform_ip6_route_add (ifindex, NM_PLATFORM_SOURCE_USER, in6addr_any, 0, gateway, metric, mss));
+	g_assert (nm_platform_ip6_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway, metric, mss));
 	no_error ();
 	g_assert (nm_platform_ip6_route_exists (ifindex, in6addr_any, 0, metric));
 	no_error ();
 	accept_signal (route_added);
 
 	/* Add default route again */
-	g_assert (nm_platform_ip6_route_add (ifindex, NM_PLATFORM_SOURCE_USER, in6addr_any, 0, gateway, metric, mss));
+	g_assert (nm_platform_ip6_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway, metric, mss));
 	no_error ();
 	accept_signal (route_changed);
 
 	/* Test route listing */
-	routes = nm_platform_ip6_route_get_all (ifindex, TRUE);
+	routes = nm_platform_ip6_route_get_all (ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
 	memset (rts, 0, sizeof (rts));
-	rts[0].source = NM_PLATFORM_SOURCE_USER;
+	rts[0].source = NM_IP_CONFIG_SOURCE_USER;
 	rts[0].network = gateway;
 	rts[0].plen = 128;
 	rts[0].ifindex = ifindex;
 	rts[0].gateway = in6addr_any;
 	rts[0].metric = metric;
 	rts[0].mss = mss;
-	rts[1].source = NM_PLATFORM_SOURCE_USER;
+	rts[1].source = NM_IP_CONFIG_SOURCE_USER;
 	rts[1].network = network;
 	rts[1].plen = plen;
 	rts[1].ifindex = ifindex;
 	rts[1].gateway = gateway;
 	rts[1].metric = metric;
 	rts[1].mss = mss;
-	rts[2].source = NM_PLATFORM_SOURCE_USER;
+	rts[2].source = NM_IP_CONFIG_SOURCE_USER;
 	rts[2].network = in6addr_any;
 	rts[2].plen = 0;
 	rts[2].ifindex = ifindex;
diff --git a/src/platform/wifi/wifi-utils-nl80211.c b/src/platform/wifi/wifi-utils-nl80211.c
index 25ebd1b3..752da926 100644
--- a/src/platform/wifi/wifi-utils-nl80211.c
+++ b/src/platform/wifi/wifi-utils-nl80211.c
@@ -20,7 +20,8 @@
  * Copyright (C) 2011 Intel Corporation. All rights reserved.
  */
 
-#include <config.h>
+#include "config.h"
+
 #include <errno.h>
 #include <string.h>
 #include <sys/ioctl.h>
@@ -442,7 +443,7 @@ wifi_nl80211_get_ssid (WifiData *data)
 }
 
 static gboolean
-wifi_nl80211_get_bssid (WifiData *data, struct ether_addr *out_bssid)
+wifi_nl80211_get_bssid (WifiData *data, guint8 *out_bssid)
 {
 	WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data;
 	struct nl80211_bss_info bss_info;
@@ -679,11 +680,20 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg)
 	static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
 		[NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
 		[NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
+#ifdef NL80211_FREQUENCY_ATTR_NO_IR
+		[NL80211_FREQUENCY_ATTR_NO_IR] = { .type = NLA_FLAG },
+#else
 		[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG },
 		[NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
+#endif
 		[NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
 		[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
 	};
+#ifdef NL80211_FREQUENCY_ATTR_NO_IR
+	G_STATIC_ASSERT (NL80211_FREQUENCY_ATTR_PASSIVE_SCAN == NL80211_FREQUENCY_ATTR_NO_IR && NL80211_FREQUENCY_ATTR_NO_IBSS == NL80211_FREQUENCY_ATTR_NO_IR);
+#else
+	G_STATIC_ASSERT (NL80211_FREQUENCY_ATTR_PASSIVE_SCAN != NL80211_FREQUENCY_ATTR_NO_IBSS);
+#endif
 
 	if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
 	               genlmsg_attrlen (gnlh, 0), NULL) < 0)
@@ -924,48 +934,3 @@ error:
 	return NULL;
 }
 
-gboolean
-wifi_nl80211_is_wifi (const char *iface)
-{
-	struct nl_sock *nl_sock;
-	struct nl_cb *nl_cb = NULL;
-	struct nl_msg *msg = NULL;
-	int id, ifindex;
-	struct nl80211_iface_info iface_info = {
-		.mode = NM_802_11_MODE_UNKNOWN,
-	};
-	gboolean is_wifi = FALSE;
-
-	nl_sock = nl_socket_alloc ();
-	if (nl_sock == NULL)
-		return FALSE;
-
-	if (genl_connect (nl_sock))
-		goto error;
-
-	ifindex = nm_platform_link_get_ifindex (iface);
-	if (ifindex < 0)
-		goto error;
-
-	id = genl_ctrl_resolve (nl_sock, "nl80211");
-	if (id < 0)
-		goto error;
-
-	nl_cb = nl_cb_alloc (NL_CB_DEFAULT);
-	if (nl_cb) {
-		msg = _nl80211_alloc_msg (id, ifindex, -1, NL80211_CMD_GET_INTERFACE, 0);
-		if (_nl80211_send_and_recv (nl_sock,
-			                        nl_cb,
-			                        msg,
-			                        nl80211_iface_info_handler,
-			                        &iface_info) >= 0)
-			is_wifi = (iface_info.mode != NM_802_11_MODE_UNKNOWN);
-	}
-
- error:
-	if (nl_cb)
-		nl_cb_put (nl_cb);
-	nl_socket_free (nl_sock);
-	return is_wifi;
-}
-
diff --git a/src/platform/wifi/wifi-utils-nl80211.h b/src/platform/wifi/wifi-utils-nl80211.h
index 2a7fe874..b3e8c897 100644
--- a/src/platform/wifi/wifi-utils-nl80211.h
+++ b/src/platform/wifi/wifi-utils-nl80211.h
@@ -18,13 +18,11 @@
  * Copyright (C) 2011 Intel Corporation. All rights reserved.
  */
 
-#ifndef WIFI_UTILS_NL80211_H
-#define WIFI_UTILS_NL80211_H
+#ifndef __WIFI_UTILS_NL80211_H__
+#define __WIFI_UTILS_NL80211_H__
 
 #include "wifi-utils.h"
 
 WifiData *wifi_nl80211_init (const char *iface, int ifindex);
 
-gboolean wifi_nl80211_is_wifi (const char *iface);
-
-#endif  /* WIFI_UTILS_NL80211_H */
+#endif  /* __WIFI_UTILS_NL80211_H__ */
diff --git a/src/platform/wifi/wifi-utils-private.h b/src/platform/wifi/wifi-utils-private.h
index e7601752..aaedd5b7 100644
--- a/src/platform/wifi/wifi-utils-private.h
+++ b/src/platform/wifi/wifi-utils-private.h
@@ -18,12 +18,12 @@
  * Copyright (C) 2011 Red Hat, Inc.
  */
 
-#ifndef WIFI_UTILS_PRIVATE_H
-#define WIFI_UTILS_PRIVATE_H
+#ifndef __WIFI_UTILS_PRIVATE_H__
+#define __WIFI_UTILS_PRIVATE_H__
 
 #include <glib.h>
 
-#include "NetworkManager.h"
+#include "nm-dbus-interface.h"
 #include "wifi-utils.h"
 
 struct WifiData {
@@ -47,7 +47,7 @@ struct WifiData {
 	/* Return current bitrate in Kbps */
 	guint32 (*get_rate) (WifiData *data);
 
-	gboolean (*get_bssid) (WifiData *data, struct ether_addr *out_bssid);
+	gboolean (*get_bssid) (WifiData *data, guint8 *out_bssid);
 
 	/* Return a signal strength percentage 0 - 100% for the current BSSID;
 	 * return -1 on errors or if not associated.
@@ -66,7 +66,7 @@ struct WifiData {
 	gboolean (*set_mesh_channel) (WifiData *data, guint32 channel);
 
 	/* ssid == NULL means "auto SSID" */
-	gboolean (*set_mesh_ssid) (WifiData *data, const GByteArray *ssid);
+	gboolean (*set_mesh_ssid) (WifiData *data, const guint8 *ssid, gsize len);
 
 	gboolean (*indicate_addressing_running) (WifiData *data, gboolean running);
 };
@@ -74,4 +74,4 @@ struct WifiData {
 gpointer wifi_data_new (const char *iface, int ifindex, gsize len);
 void wifi_data_free (WifiData *data);
 
-#endif  /* WIFI_UTILS_PRIVATE_H */
+#endif  /* __WIFI_UTILS_PRIVATE_H__ */
diff --git a/src/platform/wifi/wifi-utils-wext.c b/src/platform/wifi/wifi-utils-wext.c
index cc94b69a..e0331de7 100644
--- a/src/platform/wifi/wifi-utils-wext.c
+++ b/src/platform/wifi/wifi-utils-wext.c
@@ -19,7 +19,8 @@
  * Copyright (C) 2006 - 2008 Novell, Inc.
  */
 
-#include <config.h>
+#include "config.h"
+
 #include <errno.h>
 #include <string.h>
 #include <sys/ioctl.h>
@@ -41,7 +42,6 @@
 #include <sys/types.h>
 #include <linux/types.h>
 #include <sys/socket.h>
-#include <linux/if.h>
 #include <linux/wireless.h>
 
 
@@ -230,7 +230,7 @@ wifi_wext_get_ssid (WifiData *data)
 }
 
 static gboolean
-wifi_wext_get_bssid (WifiData *data, struct ether_addr *out_bssid)
+wifi_wext_get_bssid (WifiData *data, guint8 *out_bssid)
 {
 	WifiDataWext *wext = (WifiDataWext *) data;
 	struct iwreq wrq;
@@ -243,7 +243,7 @@ wifi_wext_get_bssid (WifiData *data, struct ether_addr *out_bssid)
 		             wext->parent.iface, strerror (errno));
 		return FALSE;
 	}
-	memcpy (out_bssid->ether_addr_octet, &(wrq.u.ap_addr.sa_data), ETH_ALEN);
+	memcpy (out_bssid, &(wrq.u.ap_addr.sa_data), ETH_ALEN);
 	return TRUE;
 }
 
@@ -421,18 +421,15 @@ wifi_wext_set_mesh_channel (WifiData *data, guint32 channel)
 }
 
 static gboolean
-wifi_wext_set_mesh_ssid (WifiData *data, const GByteArray *ssid)
+wifi_wext_set_mesh_ssid (WifiData *data, const guint8 *ssid, gsize len)
 {
 	WifiDataWext *wext = (WifiDataWext *) data;
 	struct iwreq wrq;
-	guint32 len = 0;
 	char buf[IW_ESSID_MAX_SIZE + 1];
 
 	memset (buf, 0, sizeof (buf));
-	if (ssid) {
-		len = ssid->len;
-		memcpy (buf, ssid->data, MIN (sizeof (buf) - 1, len));
-	}
+	memcpy (buf, ssid, MIN (sizeof (buf) - 1, len));
+
 	wrq.u.essid.pointer = (caddr_t) buf;
 	wrq.u.essid.length = len;
 	wrq.u.essid.flags = (len > 0) ? 1 : 0; /* 1=enable SSID, 0=disable/any */
@@ -445,7 +442,7 @@ wifi_wext_set_mesh_ssid (WifiData *data, const GByteArray *ssid)
 		nm_log_err (LOGD_HW | LOGD_WIFI | LOGD_OLPC,
 		            "(%s): error setting SSID to '%s': %s",
 		            wext->parent.iface,
-		            ssid ? nm_utils_escape_ssid (ssid->data, ssid->len) : "(null)",
+		            ssid ? nm_utils_escape_ssid (ssid, len) : "(null)",
 		            strerror (errno));
 	}
 
diff --git a/src/platform/wifi/wifi-utils-wext.h b/src/platform/wifi/wifi-utils-wext.h
index 96ad74eb..e168fe28 100644
--- a/src/platform/wifi/wifi-utils-wext.h
+++ b/src/platform/wifi/wifi-utils-wext.h
@@ -18,8 +18,8 @@
  * Copyright (C) 2011 Red Hat, Inc.
  */
 
-#ifndef WIFI_UTILS_WEXT_H
-#define WIFI_UTILS_WEXT_H
+#ifndef __WIFI_UTILS_WEXT_H__
+#define __WIFI_UTILS_WEXT_H__
 
 #include "wifi-utils.h"
 
@@ -27,4 +27,4 @@ WifiData *wifi_wext_init (const char *iface, int ifindex, gboolean check_scan);
 
 gboolean wifi_wext_is_wifi (const char *iface);
 
-#endif  /* WIFI_UTILS_WEXT_H */
+#endif  /* __WIFI_UTILS_WEXT_H__ */
diff --git a/src/platform/wifi/wifi-utils.c b/src/platform/wifi/wifi-utils.c
index ff480275..daef881b 100644
--- a/src/platform/wifi/wifi-utils.c
+++ b/src/platform/wifi/wifi-utils.c
@@ -19,7 +19,8 @@
  * Copyright (C) 2006 - 2008 Novell, Inc.
  */
 
-#include <config.h>
+#include "config.h"
+
 #include <sys/stat.h>
 #include <stdio.h>
 #include <string.h>
@@ -120,12 +121,12 @@ wifi_utils_get_ssid (WifiData *data)
 }
 
 gboolean
-wifi_utils_get_bssid (WifiData *data, struct ether_addr *out_bssid)
+wifi_utils_get_bssid (WifiData *data, guint8 *out_bssid)
 {
 	g_return_val_if_fail (data != NULL, FALSE);
 	g_return_val_if_fail (out_bssid != NULL, FALSE);
 
-	memset (out_bssid, 0, sizeof (*out_bssid));
+	memset (out_bssid, 0, ETH_ALEN);
 	return data->get_bssid (data, out_bssid);
 }
 
@@ -161,13 +162,20 @@ wifi_utils_deinit (WifiData *data)
 }
 
 gboolean
-wifi_utils_is_wifi (const char *iface, const char *sysfs_path)
+wifi_utils_is_wifi (const char *iface, const char *sysfs_path, const char *devtype)
 {
 	char phy80211_path[255];
 	struct stat s;
 
 	g_return_val_if_fail (iface != NULL, FALSE);
 
+	if (g_strcmp0 (devtype, "wlan") == 0) {
+		/* All Wi-Fi drivers should set DEVTYPE=wlan.  Since the kernel's
+		 * cfg80211/nl80211 stack does, this check should match any nl80211
+		 * capable driver (including mac82011-based ones). */
+		return TRUE;
+	}
+
 	if (sysfs_path) {
 		/* Check for nl80211 sysfs paths */
 		g_snprintf (phy80211_path, sizeof (phy80211_path), "%s/phy80211", sysfs_path);
@@ -175,9 +183,6 @@ wifi_utils_is_wifi (const char *iface, const char *sysfs_path)
 			return TRUE;
 	}
 
-	if (wifi_nl80211_is_wifi (iface))
-		return TRUE;
-
 #if HAVE_WEXT
 	if (wifi_wext_is_wifi (iface))
 		return TRUE;
@@ -207,11 +212,11 @@ wifi_utils_set_mesh_channel (WifiData *data, guint32 channel)
 }
 
 gboolean
-wifi_utils_set_mesh_ssid (WifiData *data, const GByteArray *ssid)
+wifi_utils_set_mesh_ssid (WifiData *data, const guint8 *ssid, gsize len)
 {
 	g_return_val_if_fail (data != NULL, FALSE);
 	g_return_val_if_fail (data->set_mesh_ssid != NULL, FALSE);
-	return data->set_mesh_ssid (data, ssid);
+	return data->set_mesh_ssid (data, ssid, len);
 }
 
 gboolean
diff --git a/src/platform/wifi/wifi-utils.h b/src/platform/wifi/wifi-utils.h
index 455e075f..f1b57ace 100644
--- a/src/platform/wifi/wifi-utils.h
+++ b/src/platform/wifi/wifi-utils.h
@@ -19,17 +19,17 @@
  * Copyright (C) 2006 - 2008 Novell, Inc.
  */
 
-#ifndef WIFI_UTILS_H
-#define WIFI_UTILS_H
+#ifndef __WIFI_UTILS_H__
+#define __WIFI_UTILS_H__
 
 #include <net/ethernet.h>
 #include <glib.h>
 
-#include "NetworkManager.h"
+#include "nm-dbus-interface.h"
 
 typedef struct WifiData WifiData;
 
-gboolean wifi_utils_is_wifi (const char *iface, const char *sysfs_path);
+gboolean wifi_utils_is_wifi (const char *iface, const char *sysfs_path, const char *devtype);
 
 WifiData *wifi_utils_init (const char *iface, int ifindex, gboolean check_scan);
 
@@ -50,8 +50,8 @@ guint32 wifi_utils_find_freq (WifiData *data, const guint32 *freqs);
 /* Caller must free returned byte array */
 GByteArray *wifi_utils_get_ssid (WifiData *data);
 
-/* Caller must free returned byte array */
-gboolean wifi_utils_get_bssid (WifiData *data, struct ether_addr *out_bssid);
+/* out_bssid must be ETH_ALEN bytes */
+gboolean wifi_utils_get_bssid (WifiData *data, guint8 *out_bssid);
 
 /* Returns current bitrate in Kbps */
 guint32 wifi_utils_get_rate (WifiData *data);
@@ -71,6 +71,6 @@ guint32 wifi_utils_get_mesh_channel (WifiData *data);
 
 gboolean wifi_utils_set_mesh_channel (WifiData *data, guint32 channel);
 
-gboolean wifi_utils_set_mesh_ssid (WifiData *data, const GByteArray *ssid);
+gboolean wifi_utils_set_mesh_ssid (WifiData *data, const guint8 *ssid, gsize len);
 
-#endif  /* WIFI_UTILS_H */
+#endif  /* __WIFI_UTILS_H__ */