summary refs log tree commit diff
path: root/src/platform
diff options
context:
space:
mode:
Diffstat (limited to 'src/platform')
-rw-r--r--src/platform/nm-linux-platform.c63
-rw-r--r--src/platform/nm-platform-utils.c87
-rw-r--r--src/platform/nm-platform-utils.h4
-rw-r--r--src/platform/nm-platform.c3
-rw-r--r--src/platform/nmp-netns.c6
-rw-r--r--src/platform/nmp-object.c1
-rw-r--r--src/platform/nmp-object.h1
-rw-r--r--src/platform/tests/test-common.c12
-rw-r--r--src/platform/wifi/wifi-utils-nl80211.c16
-rw-r--r--src/platform/wifi/wifi-utils-wext.c36
-rw-r--r--src/platform/wifi/wifi-utils.c32
-rw-r--r--src/platform/wifi/wifi-utils.h2
12 files changed, 198 insertions, 65 deletions
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index 070a83ea..f9f4b088 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -36,12 +36,7 @@
 #include <linux/if_tun.h>
 #include <linux/if_tunnel.h>
 #include <netlink/netlink.h>
-#include <netlink/object.h>
-#include <netlink/cache.h>
-#include <netlink/route/link.h>
-#include <netlink/route/link/vlan.h>
-#include <netlink/route/addr.h>
-#include <netlink/route/route.h>
+#include <netlink/msg.h>
 #include <gudev/gudev.h>
 
 #include "nm-utils.h"
@@ -54,6 +49,7 @@
 #include "nm-platform-utils.h"
 #include "wifi/wifi-utils.h"
 #include "wifi/wifi-utils-wext.h"
+#include "nm-utils/unaligned.h"
 
 #define offset_plus_sizeof(t,m) (offsetof (t,m) + sizeof (((t *) NULL)->m))
 
@@ -61,6 +57,7 @@
 
 /* nm-internal error codes for libnl. Make sure they don't overlap. */
 #define _NLE_NM_NOBUFS 500
+#define _NLE_MSG_TRUNC 501
 
 /*********************************************************************************************/
 
@@ -724,7 +721,7 @@ _linktype_get_type (NMPlatform *platform,
 		}
 
 		/* Fallback for drivers that don't call SET_NETDEV_DEVTYPE() */
-		if (wifi_utils_is_wifi (ifname))
+		if (wifi_utils_is_wifi (ifindex, ifname))
 			return NM_LINK_TYPE_WIFI;
 
 		if (arptype == ARPHRD_ETHER) {
@@ -1477,12 +1474,18 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
 	}
 
 	if (tb[IFLA_STATS64]) {
-		struct rtnl_link_stats64 *stats = nla_data (tb[IFLA_STATS64]);
+		/* tb[IFLA_STATS64] is only guaranteed to be 32bit-aligned,
+		 * so in general we can't access the rtnl_link_stats64 struct
+		 * members directly on 64bit architectures. */
+		char *stats = nla_data (tb[IFLA_STATS64]);
 
-		obj->link.rx_packets = stats->rx_packets;
-		obj->link.rx_bytes = stats->rx_bytes;
-		obj->link.tx_packets = stats->tx_packets;
-		obj->link.tx_bytes = stats->tx_bytes;
+#define READ_STAT64(member) \
+	unaligned_read_ne64 (stats + offsetof (struct rtnl_link_stats64, member))
+
+		obj->link.rx_packets = READ_STAT64 (rx_packets);
+		obj->link.rx_bytes   = READ_STAT64 (rx_bytes);
+		obj->link.tx_packets = READ_STAT64 (tx_packets);
+		obj->link.tx_bytes   = READ_STAT64 (tx_bytes);
 	}
 
 	obj->link.n_ifi_flags = ifi->ifi_flags;
@@ -5144,7 +5147,7 @@ tun_add (NMPlatform *platform, const char *name, gboolean tap,
 	_LOGD ("link: add %s '%s' owner %" G_GINT64_FORMAT " group %" G_GINT64_FORMAT,
 	       tap ? "tap" : "tun", name, owner, group);
 
-	fd = open ("/dev/net/tun", O_RDWR);
+	fd = open ("/dev/net/tun", O_RDWR | O_CLOEXEC);
 	if (fd < 0)
 		return FALSE;
 
@@ -5967,6 +5970,23 @@ continue_reading:
 			n = -NLE_AGAIN;
 		}
 		break;
+	case -NLE_MSG_TRUNC: {
+		int buf_size;
+
+		/* the message receive buffer was too small. We lost one message, which
+		 * is unfortunate. Try to double the buffer size for the next time. */
+		buf_size = nl_socket_get_msg_buf_size (sk);
+		if (buf_size < 512*1024) {
+			buf_size *= 2;
+			_LOGT ("netlink: recvmsg: increase message buffer size for recvmsg() to %d bytes", buf_size);
+			if (nl_socket_set_msg_buf_size (sk, buf_size) < 0)
+				nm_assert_not_reached ();
+			if (!handle_events)
+				goto continue_reading;
+		}
+		n = -_NLE_MSG_TRUNC;
+		break;
+	}
 	case -NLE_NOMEM:
 		if (errno == ENOBUFS) {
 			/* we are very much interested in a overrun of the receive buffer.
@@ -6155,8 +6175,17 @@ event_handler_read_netlink (NMPlatform *platform, gboolean wait_for_acks)
 				case -NLE_DUMP_INTR:
 					_LOGD ("netlink: read: uncritical failure to retrieve incoming events: %s (%d)", nl_geterror (nle), nle);
 					break;
+				case -_NLE_MSG_TRUNC:
 				case -_NLE_NM_NOBUFS:
-					_LOGI ("netlink: read: too many netlink events. Need to resynchronize platform cache");
+					_LOGI ("netlink: read: %s. Need to resynchronize platform cache",
+					       ({
+					            const char *_reason = "unknown";
+					            switch (nle) {
+					            case -_NLE_MSG_TRUNC: _reason = "message truncated";       break;
+					            case -_NLE_NM_NOBUFS: _reason = "too many netlink events"; break;
+					            }
+					            _reason;
+					       }));
 					event_handler_recvmsgs (platform, FALSE);
 					delayed_action_wait_for_nl_response_complete_all (platform, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC);
 					delayed_action_schedule (platform,
@@ -6413,6 +6442,12 @@ constructed (GObject *_object)
 	nle = nl_socket_set_buffer_size (priv->nlh, 8*1024*1024, 0);
 	g_assert (!nle);
 
+	/* explicitly set the msg buffer size and disable MSG_PEEK.
+	 * If we later encounter NLE_MSG_TRUNC, we will adjust the buffer size. */
+	nl_socket_disable_msg_peek (priv->nlh);
+	nle = nl_socket_set_msg_buf_size (priv->nlh, 32 * 1024);
+	g_assert (!nle);
+
 	nle = nl_socket_add_memberships (priv->nlh,
 	                                 RTNLGRP_LINK,
 	                                 RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR,
diff --git a/src/platform/nm-platform-utils.c b/src/platform/nm-platform-utils.c
index 068801ee..b939e783 100644
--- a/src/platform/nm-platform-utils.c
+++ b/src/platform/nm-platform-utils.c
@@ -31,12 +31,15 @@
 #include <linux/mii.h>
 #include <linux/version.h>
 #include <linux/rtnetlink.h>
+#include <fcntl.h>
 
 #include "nm-utils.h"
 #include "nm-setting-wired.h"
 
 #include "nm-core-utils.h"
 
+extern char *if_indextoname (unsigned int __ifindex, char *__ifname);
+
 /******************************************************************
  * ethtool
  ******************************************************************/
@@ -60,7 +63,7 @@ ethtool_get (const char *name, gpointer edata)
 	nm_utils_ifname_cpy (ifr.ifr_name, name);
 	ifr.ifr_data = edata;
 
-	fd = socket (PF_INET, SOCK_DGRAM, 0);
+	fd = socket (PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
 	if (fd < 0) {
 		nm_log_err (LOGD_PLATFORM, "ethtool: Could not open socket.");
 		return FALSE;
@@ -342,7 +345,7 @@ nmp_utils_mii_supports_carrier_detect (const char *ifname)
 	if (!nmp_utils_device_exists (ifname))
 		return FALSE;
 
-	fd = socket (PF_INET, SOCK_DGRAM, 0);
+	fd = socket (PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
 	if (fd < 0) {
 		nm_log_err (LOGD_PLATFORM, "mii: couldn't open control socket (%s)", ifname);
 		return FALSE;
@@ -558,3 +561,83 @@ nmp_utils_ip_config_source_to_string (NMIPConfigSource source, char *buf, gsize
 	return buf;
 }
 
+/**
+ * nmp_utils_sysctl_open_netdir:
+ * @ifindex: the ifindex for which to open "/sys/class/net/%s"
+ * @ifname_guess: (allow-none): optional argument, if present used as initial
+ *   guess as the current name for @ifindex. If guessed right,
+ *   it saves an addtional if_indextoname() call.
+ * @out_ifname: (allow-none): if present, must be at least IFNAMSIZ
+ *   characters. On success, this will contain the actual ifname
+ *   found while opening the directory.
+ *
+ * Returns: a negative value on failure, on success returns the open fd
+ *   to the "/sys/class/net/%s" directory for @ifindex.
+ */
+int
+nmp_utils_sysctl_open_netdir (int ifindex,
+                              const char *ifname_guess,
+                              char *out_ifname)
+{
+	#define SYS_CLASS_NET "/sys/class/net/"
+	const char *ifname = ifname_guess;
+	char ifname_buf_last_try[IFNAMSIZ];
+	char ifname_buf[IFNAMSIZ];
+	guint try_count = 0;
+	char sysdir[NM_STRLEN (SYS_CLASS_NET) + IFNAMSIZ] = SYS_CLASS_NET;
+	char fd_buf[256];
+	ssize_t nn;
+
+	g_return_val_if_fail (ifindex >= 0, -1);
+
+	ifname_buf_last_try[0] = '\0';
+
+	for (try_count = 0; try_count < 10; try_count++, ifname = NULL) {
+		nm_auto_close int fd_dir = -1;
+		nm_auto_close int fd_ifindex = -1;
+		int fd;
+
+		if (!ifname) {
+			ifname = if_indextoname (ifindex, ifname_buf);
+			if (!ifname)
+				return -1;
+		}
+
+		nm_assert (nm_utils_iface_valid_name (ifname));
+
+		if (g_strlcpy (&sysdir[NM_STRLEN (SYS_CLASS_NET)], ifname, IFNAMSIZ) >= IFNAMSIZ)
+			g_return_val_if_reached (-1);
+
+		/* we only retry, if the name changed since previous attempt.
+		 * Hence, it is extremely unlikely that this loop runes until the
+		 * end of the @try_count. */
+		if (nm_streq (ifname, ifname_buf_last_try))
+			return -1;
+		strcpy (ifname_buf_last_try, ifname);
+
+		fd_dir = open (sysdir, O_DIRECTORY | O_CLOEXEC);
+		if (fd_dir < 0)
+			continue;
+
+		fd_ifindex = openat (fd_dir, "ifindex", O_CLOEXEC);
+		if (fd_ifindex < 0)
+			continue;
+
+		nn = nm_utils_fd_read_loop (fd_ifindex, fd_buf, sizeof (fd_buf) - 2, FALSE);
+		if (nn <= 0)
+			continue;
+		fd_buf[nn] = '\0';
+
+		if (ifindex != _nm_utils_ascii_str_to_int64 (fd_buf, 10, 1, G_MAXINT, -1))
+			continue;
+
+		if (out_ifname)
+			strcpy (out_ifname, ifname);
+
+		fd = fd_dir;
+		fd_dir = -1;
+		return fd;
+	}
+
+	return -1;
+}
diff --git a/src/platform/nm-platform-utils.h b/src/platform/nm-platform-utils.h
index 456c0865..92a06fdf 100644
--- a/src/platform/nm-platform-utils.h
+++ b/src/platform/nm-platform-utils.h
@@ -60,4 +60,8 @@ NMIPConfigSource nmp_utils_ip_config_source_coerce_from_rtprot (NMIPConfigSource
 NMIPConfigSource nmp_utils_ip_config_source_round_trip_rtprot  (NMIPConfigSource source) _nm_const;
 const char *     nmp_utils_ip_config_source_to_string (NMIPConfigSource source, char *buf, gsize len);
 
+int nmp_utils_sysctl_open_netdir (int ifindex,
+                                  const char *ifname_guess,
+                                  char *out_ifname);
+
 #endif /* __NM_PLATFORM_UTILS_H__ */
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index 9dace699..9274a31d 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -28,11 +28,10 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <string.h>
-#include <netlink/route/addr.h>
-#include <netlink/route/rtnl.h>
 #include <linux/ip.h>
 #include <linux/if_tun.h>
 #include <linux/if_tunnel.h>
+#include <linux/rtnetlink.h>
 
 #include "nm-utils.h"
 #include "nm-core-internal.h"
diff --git a/src/platform/nmp-netns.c b/src/platform/nmp-netns.c
index 26295855..07e134c1 100644
--- a/src/platform/nmp-netns.c
+++ b/src/platform/nmp-netns.c
@@ -277,7 +277,7 @@ _netns_new (GError **error)
 	int fd_net, fd_mnt;
 	int errsv;
 
-	fd_net = open (PROC_SELF_NS_NET, O_RDONLY);
+	fd_net = open (PROC_SELF_NS_NET, O_RDONLY | O_CLOEXEC);
 	if (fd_net == -1) {
 		errsv = errno;
 		g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
@@ -286,7 +286,7 @@ _netns_new (GError **error)
 		return NULL;
 	}
 
-	fd_mnt = open (PROC_SELF_NS_MNT, O_RDONLY);
+	fd_mnt = open (PROC_SELF_NS_MNT, O_RDONLY | O_CLOEXEC);
 	if (fd_mnt == -1) {
 		errsv = errno;
 		g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
@@ -623,7 +623,7 @@ nmp_netns_bind_to_path (NMPNetns *self, const char *filename, int *out_fd)
 	}
 
 	if (out_fd) {
-		if ((fd = open (filename, O_RDONLY)) == -1) {
+		if ((fd = open (filename, O_RDONLY | O_CLOEXEC)) == -1) {
 			errsv = errno;
 			_LOGE (self, "bind: failed to open %s: %s", filename, g_strerror (errsv));
 			umount2 (filename, MNT_DETACH);
diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c
index 30a52c25..993c23d6 100644
--- a/src/platform/nmp-object.c
+++ b/src/platform/nmp-object.c
@@ -23,6 +23,7 @@
 #include "nmp-object.h"
 
 #include <unistd.h>
+#include <linux/rtnetlink.h>
 
 #include "nm-utils.h"
 
diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h
index d295f7a0..b6d6709c 100644
--- a/src/platform/nmp-object.h
+++ b/src/platform/nmp-object.h
@@ -21,7 +21,6 @@
 #ifndef __NMP_OBJECT_H__
 #define __NMP_OBJECT_H__
 
-#include <netlink/netlink.h>
 #include <gudev/gudev.h>
 
 #include "nm-platform.h"
diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c
index b1947a6d..d636ebeb 100644
--- a/src/platform/tests/test-common.c
+++ b/src/platform/tests/test-common.c
@@ -1398,7 +1398,7 @@ nmtstp_namespace_create (int unshare_flags, GError **error)
 	int pipefd_p2c[2];
 	ssize_t r;
 
-	e = pipe (pipefd_c2p);
+	e = pipe2 (pipefd_c2p, O_CLOEXEC);
 	if (e != 0) {
 		errsv = errno;
 		g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
@@ -1406,7 +1406,7 @@ nmtstp_namespace_create (int unshare_flags, GError **error)
 		return FALSE;
 	}
 
-	e = pipe (pipefd_p2c);
+	e = pipe2 (pipefd_p2c, O_CLOEXEC);
 	if (e != 0) {
 		errsv = errno;
 		g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
@@ -1540,7 +1540,7 @@ nmtstp_namespace_get_fd_for_process (pid_t pid, const char *ns_name)
 
 	nm_sprintf_buf (p, "/proc/%lu/ns/%s", (long unsigned) pid, ns_name);
 
-	return open(p, O_RDONLY);
+	return open(p, O_RDONLY | O_CLOEXEC);
 }
 
 /*****************************************************************************/
@@ -1564,21 +1564,21 @@ unshare_user (void)
 
 	/* Since Linux 3.19 we have to disable setgroups() in order to map users.
 	 * Just proceed if the file is not there. */
-	f = fopen ("/proc/self/setgroups", "w");
+	f = fopen ("/proc/self/setgroups", "we");
 	if (f) {
 		fprintf (f, "deny");
 		fclose (f);
 	}
 
 	/* Map current UID to root in NS to be created. */
-	f = fopen ("/proc/self/uid_map", "w");
+	f = fopen ("/proc/self/uid_map", "we");
 	if (!f)
 		return FALSE;
 	fprintf (f, "0 %d 1", uid);
 	fclose (f);
 
 	/* Map current GID to root in NS to be created. */
-	f = fopen ("/proc/self/gid_map", "w");
+	f = fopen ("/proc/self/gid_map", "we");
 	if (!f)
 		return FALSE;
 	fprintf (f, "0 %d 1", gid);
diff --git a/src/platform/wifi/wifi-utils-nl80211.c b/src/platform/wifi/wifi-utils-nl80211.c
index 79f217a8..2e222eb8 100644
--- a/src/platform/wifi/wifi-utils-nl80211.c
+++ b/src/platform/wifi/wifi-utils-nl80211.c
@@ -1003,7 +1003,7 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg)
 			case WLAN_CIPHER_SUITE_SMS4:
 				break;
 			default:
-				nm_log_dbg (LOGD_HW | LOGD_WIFI, "Don't know the meaning of NL80211_ATTR_CIPHER_SUITE %#8.8x.", ciphers[i]);
+				nm_log_dbg (LOGD_PLATFORM | LOGD_WIFI, "Don't know the meaning of NL80211_ATTR_CIPHER_SUITE %#8.8x.", ciphers[i]);
 				break;
 			}
 		}
@@ -1071,42 +1071,42 @@ wifi_nl80211_init (const char *iface, int ifindex)
 
 	if (nl80211_send_and_recv (nl80211, msg, nl80211_wiphy_info_handler,
 	                           &device_info) < 0) {
-		nm_log_dbg (LOGD_HW | LOGD_WIFI,
+		nm_log_dbg (LOGD_PLATFORM | LOGD_WIFI,
 		            "(%s): NL80211_CMD_GET_WIPHY request failed",
 		            nl80211->parent.iface);
 		goto error;
 	}
 
 	if (!device_info.success) {
-		nm_log_dbg (LOGD_HW | LOGD_WIFI,
+		nm_log_dbg (LOGD_PLATFORM | LOGD_WIFI,
 		            "(%s): NL80211_CMD_GET_WIPHY request indicated failure",
 		            nl80211->parent.iface);
 		goto error;
 	}
 
 	if (!device_info.supported) {
-		nm_log_dbg (LOGD_HW | LOGD_WIFI,
+		nm_log_dbg (LOGD_PLATFORM | LOGD_WIFI,
 		            "(%s): driver does not fully support nl80211, falling back to WEXT",
 		            nl80211->parent.iface);
 		goto error;
 	}
 
 	if (!device_info.can_scan_ssid) {
-		nm_log_err (LOGD_HW | LOGD_WIFI,
+		nm_log_err (LOGD_PLATFORM | LOGD_WIFI,
 		            "(%s): driver does not support SSID scans",
 		            nl80211->parent.iface);
 		goto error;
 	}
 
 	if (device_info.num_freqs == 0 || device_info.freqs == NULL) {
-		nm_log_err (LOGD_HW | LOGD_WIFI,
+		nm_log_err (LOGD_PLATFORM | LOGD_WIFI,
 		            "(%s): driver reports no supported frequencies",
 		            nl80211->parent.iface);
 		goto error;
 	}
 
 	if (device_info.caps == 0) {
-		nm_log_err (LOGD_HW | LOGD_WIFI,
+		nm_log_err (LOGD_PLATFORM | LOGD_WIFI,
 		            "(%s): driver doesn't report support of any encryption",
 		            nl80211->parent.iface);
 		goto error;
@@ -1120,7 +1120,7 @@ wifi_nl80211_init (const char *iface, int ifindex)
 	if (device_info.can_wowlan)
 		nl80211->parent.get_wowlan = wifi_nl80211_get_wowlan;
 
-	nm_log_info (LOGD_HW | LOGD_WIFI,
+	nm_log_info (LOGD_PLATFORM | LOGD_WIFI,
 	             "(%s): using nl80211 for WiFi device control",
 	             nl80211->parent.iface);
 
diff --git a/src/platform/wifi/wifi-utils-wext.c b/src/platform/wifi/wifi-utils-wext.c
index af285b45..d4ed86eb 100644
--- a/src/platform/wifi/wifi-utils-wext.c
+++ b/src/platform/wifi/wifi-utils-wext.c
@@ -105,7 +105,7 @@ wifi_wext_get_mode (WifiData *data)
 
 	if (ioctl (wext->fd, SIOCGIWMODE, &wrq) < 0) {
 		if (errno != ENODEV) {
-			nm_log_warn (LOGD_HW | LOGD_WIFI,
+			nm_log_warn (LOGD_PLATFORM | LOGD_WIFI,
 			             "(%s): error %d getting card mode",
 			             wext->parent.iface, errno);
 		}
@@ -154,7 +154,7 @@ wifi_wext_set_mode (WifiData *data, const NM80211Mode mode)
 	nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface);
 	if (ioctl (wext->fd, SIOCSIWMODE, &wrq) < 0) {
 		if (errno != ENODEV) {
-			nm_log_err (LOGD_HW | LOGD_WIFI, "(%s): error setting mode %d",
+			nm_log_err (LOGD_PLATFORM | LOGD_WIFI, "(%s): error setting mode %d",
 			            wext->parent.iface, mode);
 		}
 		return FALSE;
@@ -178,7 +178,7 @@ wifi_wext_set_powersave (WifiData *data, guint32 powersave)
 	nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface);
 	if (ioctl (wext->fd, SIOCSIWPOWER, &wrq) < 0) {
 		if (errno != ENODEV) {
-			nm_log_err (LOGD_HW | LOGD_WIFI, "(%s): error setting powersave %" G_GUINT32_FORMAT,
+			nm_log_err (LOGD_PLATFORM | LOGD_WIFI, "(%s): error setting powersave %" G_GUINT32_FORMAT,
 			            wext->parent.iface, powersave);
 		}
 		return FALSE;
@@ -196,7 +196,7 @@ wifi_wext_get_freq (WifiData *data)
 	memset (&wrq, 0, sizeof (struct iwreq));
 	nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface);
 	if (ioctl (wext->fd, SIOCGIWFREQ, &wrq) < 0) {
-		nm_log_warn (LOGD_HW | LOGD_WIFI,
+		nm_log_warn (LOGD_PLATFORM | LOGD_WIFI,
 		             "(%s): error getting frequency: %s",
 		             wext->parent.iface, strerror (errno));
 		return 0;
@@ -230,7 +230,7 @@ wifi_wext_get_bssid (WifiData *data, guint8 *out_bssid)
 	memset (&wrq, 0, sizeof (wrq));
 	nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface);
 	if (ioctl (wext->fd, SIOCGIWAP, &wrq) < 0) {
-		nm_log_warn (LOGD_HW | LOGD_WIFI,
+		nm_log_warn (LOGD_PLATFORM | LOGD_WIFI,
 		             "(%s): error getting associated BSSID: %s",
 		             wext->parent.iface, strerror (errno));
 		return FALSE;
@@ -360,7 +360,7 @@ wifi_wext_get_qual (WifiData *data)
 	nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface);
 
 	if (ioctl (wext->fd, SIOCGIWSTATS, &wrq) < 0) {
-		nm_log_warn (LOGD_HW | LOGD_WIFI,
+		nm_log_warn (LOGD_PLATFORM | LOGD_WIFI,
 		             "(%s): error getting signal strength: %s",
 		             wext->parent.iface, strerror (errno));
 		return -1;
@@ -403,7 +403,7 @@ wifi_wext_set_mesh_channel (WifiData *data, guint32 channel)
 	}
 
 	if (ioctl (wext->fd, SIOCSIWFREQ, &wrq) < 0) {
-		nm_log_err (LOGD_HW | LOGD_WIFI | LOGD_OLPC,
+		nm_log_err (LOGD_PLATFORM | LOGD_WIFI | LOGD_OLPC,
 		            "(%s): error setting channel to %d: %s",
 		            wext->parent.iface, channel, strerror (errno));
 		return FALSE;
@@ -431,7 +431,7 @@ wifi_wext_set_mesh_ssid (WifiData *data, const guint8 *ssid, gsize len)
 		return TRUE;
 
 	if (errno != ENODEV) {
-		nm_log_err (LOGD_HW | LOGD_WIFI | LOGD_OLPC,
+		nm_log_err (LOGD_PLATFORM | LOGD_WIFI | LOGD_OLPC,
 		            "(%s): error setting SSID to '%s': %s",
 		            wext->parent.iface,
 		            ssid ? nm_utils_escape_ssid (ssid, len) : "(null)",
@@ -482,7 +482,7 @@ wext_get_range (WifiDataWext *wext,
 			success = TRUE;
 			break;
 		} else if (errno != EAGAIN) {
-			nm_log_err (LOGD_HW | LOGD_WIFI,
+			nm_log_err (LOGD_PLATFORM | LOGD_WIFI,
 			            "(%s): couldn't get driver range information (%d).",
 			            wext->parent.iface, errno);
 			break;
@@ -492,7 +492,7 @@ wext_get_range (WifiDataWext *wext,
 	}
 
 	if (i <= 0) {
-		nm_log_warn (LOGD_HW | LOGD_WIFI,
+		nm_log_warn (LOGD_PLATFORM | LOGD_WIFI,
 		             "(%s): driver took too long to respond to IWRANGE query.",
 		             wext->parent.iface);
 	}
@@ -577,19 +577,19 @@ wifi_wext_init (const char *iface, int ifindex, gboolean check_scan)
 	wext->parent.set_mesh_channel = wifi_wext_set_mesh_channel;
 	wext->parent.set_mesh_ssid = wifi_wext_set_mesh_ssid;
 
-	wext->fd = socket (PF_INET, SOCK_DGRAM, 0);
+	wext->fd = socket (PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
 	if (wext->fd < 0)
 		goto error;
 
 	memset (&range, 0, sizeof (struct iw_range));
 	if (wext_get_range (wext, &range, &response_len) == FALSE) {
-		nm_log_info (LOGD_HW | LOGD_WIFI, "(%s): driver WEXT range request failed",
+		nm_log_info (LOGD_PLATFORM | LOGD_WIFI, "(%s): driver WEXT range request failed",
 		             wext->parent.iface);
 		goto error;
 	}
 
 	if ((response_len < 300) || (range.we_version_compiled < 21)) {
-		nm_log_info (LOGD_HW | LOGD_WIFI,
+		nm_log_info (LOGD_PLATFORM | LOGD_WIFI,
 		             "(%s): driver WEXT version too old (got %d, expected >= 21)",
 		             wext->parent.iface,
 		             range.we_version_compiled);
@@ -613,7 +613,7 @@ wifi_wext_init (const char *iface, int ifindex, gboolean check_scan)
 
 	/* Check for scanning capability; cards that can't scan are not supported */
 	if (check_scan && (wext_can_scan (wext) == FALSE)) {
-		nm_log_info (LOGD_HW | LOGD_WIFI,
+		nm_log_info (LOGD_PLATFORM | LOGD_WIFI,
 		             "(%s): drivers that cannot scan are unsupported",
 		             wext->parent.iface);
 		goto error;
@@ -625,12 +625,12 @@ wifi_wext_init (const char *iface, int ifindex, gboolean check_scan)
 	 */
 	scan_capa_range = (struct iw_range_with_scan_capa *) &range;
 	if (scan_capa_range->scan_capa & NM_IW_SCAN_CAPA_ESSID) {
-		nm_log_info (LOGD_HW | LOGD_WIFI,
+		nm_log_info (LOGD_PLATFORM | LOGD_WIFI,
 		             "(%s): driver supports SSID scans (scan_capa 0x%02X).",
 		             wext->parent.iface,
 		             scan_capa_range->scan_capa);
 	} else {
-		nm_log_info (LOGD_HW | LOGD_WIFI,
+		nm_log_info (LOGD_PLATFORM | LOGD_WIFI,
 		             "(%s): driver does not support SSID scans (scan_capa 0x%02X).",
 		             wext->parent.iface,
 		             scan_capa_range->scan_capa);
@@ -644,7 +644,7 @@ wifi_wext_init (const char *iface, int ifindex, gboolean check_scan)
 	if (has_5ghz)
 		wext->parent.caps |= NM_WIFI_DEVICE_CAP_FREQ_5GHZ;
 
-	nm_log_info (LOGD_HW | LOGD_WIFI,
+	nm_log_info (LOGD_PLATFORM | LOGD_WIFI,
 	             "(%s): using WEXT for WiFi device control",
 	             wext->parent.iface);
 
@@ -665,7 +665,7 @@ wifi_wext_is_wifi (const char *iface)
 	if (!nmp_utils_device_exists (iface))
 		return FALSE;
 
-	fd = socket (PF_INET, SOCK_DGRAM, 0);
+	fd = socket (PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
 	if (fd >= 0) {
 		nm_utils_ifname_cpy (iwr.ifr_ifrn.ifrn_name, iface);
 		if (ioctl (fd, SIOCGIWNAME, &iwr) == 0)
diff --git a/src/platform/wifi/wifi-utils.c b/src/platform/wifi/wifi-utils.c
index b7fe86bb..2ce6eb77 100644
--- a/src/platform/wifi/wifi-utils.c
+++ b/src/platform/wifi/wifi-utils.c
@@ -26,6 +26,7 @@
 #include <sys/stat.h>
 #include <stdio.h>
 #include <string.h>
+#include <fcntl.h>
 
 #include "wifi-utils-private.h"
 #include "wifi-utils-nl80211.h"
@@ -34,6 +35,8 @@
 #endif
 #include "nm-core-utils.h"
 
+#include "platform/nm-platform-utils.h"
+
 gpointer
 wifi_data_new (const char *iface, int ifindex, gsize len)
 {
@@ -180,23 +183,32 @@ wifi_utils_deinit (WifiData *data)
 }
 
 gboolean
-wifi_utils_is_wifi (const char *iface)
+wifi_utils_is_wifi (int ifindex, const char *ifname)
 {
-	char phy80211_path[NM_STRLEN ("/sys/class/net/123456789012345/phy80211\0") + 100 /*safety*/];
-	struct stat s;
+	int fd_sysnet;
+	int fd_phy80211;
+	char ifname_verified[IFNAMSIZ];
+
+	g_return_val_if_fail (ifindex > 0, FALSE);
 
-	g_return_val_if_fail (iface != NULL, FALSE);
+	fd_sysnet = nmp_utils_sysctl_open_netdir (ifindex, ifname, ifname_verified);
+	if (fd_sysnet < 0)
+		return FALSE;
 
-	nm_sprintf_buf (phy80211_path,
-	                "/sys/class/net/%s/phy80211",
-	                NM_ASSERT_VALID_PATH_COMPONENT (iface));
-	nm_assert (strlen (phy80211_path) < sizeof (phy80211_path) - 1);
+	/* there might have been a race and ifname might be wrong. Below for checking
+	 * wext, use the possibly improved name that we just verified. */
+	ifname = ifname_verified;
 
-	if ((stat (phy80211_path, &s) == 0 && (s.st_mode & S_IFDIR)))
+	fd_phy80211 = openat (fd_sysnet, "phy80211", O_CLOEXEC);
+	close (fd_sysnet);
+
+	if (fd_phy80211 >= 0) {
+		close (fd_phy80211);
 		return TRUE;
+	}
 
 #if HAVE_WEXT
-	if (wifi_wext_is_wifi (iface))
+	if (wifi_wext_is_wifi (ifname))
 		return TRUE;
 #endif
 
diff --git a/src/platform/wifi/wifi-utils.h b/src/platform/wifi/wifi-utils.h
index 8e2b93f1..3dca2ac1 100644
--- a/src/platform/wifi/wifi-utils.h
+++ b/src/platform/wifi/wifi-utils.h
@@ -28,7 +28,7 @@
 
 typedef struct WifiData WifiData;
 
-gboolean wifi_utils_is_wifi (const char *iface);
+gboolean wifi_utils_is_wifi (int ifindex, const char *ifname);
 
 WifiData *wifi_utils_init (const char *iface, int ifindex, gboolean check_scan);