summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAron Xu <happyaron@ubuntu.com>2017-01-18 10:05:21 (GMT)
committerAron Xu <happyaron@ubuntu.com>2017-01-18 10:05:21 (GMT)
commit3727a844980a677bc66c4549eb38c1a545c3130d (patch)
tree9b8c3695241967ec1b89241b66d8e0dd5d01cedb
parentb744b33359ac8f61dc37b3ae05e468559f45e63d (diff)
Backport patches from master branch for LP: #1647283xenial-1647283
-rw-r--r--debian/patches/all-use-O_CLOEXEC-for-file-descriptors.patch392
-rw-r--r--debian/patches/core-add-utils-for-file-handling.patch163
-rw-r--r--debian/patches/device-wwan-use-nm_auto_close-instead-of-gs_fd_close.patch40
-rw-r--r--debian/patches/platform-add-a-new-function-nmp_utils_open_sysctl.patch103
-rw-r--r--debian/patches/platform-refactor-nmp_utils_sysctl_open_netdir.patch206
-rw-r--r--debian/patches/platform-refactor-wifi_utils_is_wifi-not-to-pass-sys.patch93
-rw-r--r--debian/patches/platform-wifi-use-nmp_utils_open_sysctl-to-check-if-.patch110
-rw-r--r--debian/patches/series10
-rw-r--r--debian/patches/shared-add-nm_auto_close-and-nm_auto_fclose.patch62
9 files changed, 1179 insertions, 0 deletions
diff --git a/debian/patches/all-use-O_CLOEXEC-for-file-descriptors.patch b/debian/patches/all-use-O_CLOEXEC-for-file-descriptors.patch
new file mode 100644
index 0000000..35c121c
--- /dev/null
+++ b/debian/patches/all-use-O_CLOEXEC-for-file-descriptors.patch
@@ -0,0 +1,392 @@
+From: Thomas Haller <thaller@redhat.com>
+Date: Sat, 10 Dec 2016 15:28:15 +0100
+Subject: all: use O_CLOEXEC for file descriptors
+
+(cherry picked from commit 4bdee37771ae741f4f9548b52c1db53ddf080fe8)
+---
+ src/devices/adsl/nm-device-adsl.c | 4 ++--
+ src/devices/bluetooth/nm-bluez5-dun.c | 4 ++--
+ src/devices/tests/test-lldp.c | 4 ++--
+ src/devices/wwan/nm-modem.c | 2 +-
+ src/dns-manager/nm-dns-manager.c | 4 ++--
+ src/main-utils.c | 2 +-
+ src/nm-manager.c | 2 +-
+ src/platform/nm-linux-platform.c | 2 +-
+ src/platform/nm-platform-utils.c | 4 ++--
+ src/platform/nmp-netns.c | 6 +++---
+ src/platform/tests/test-common.c | 12 ++++++------
+ src/platform/wifi/wifi-utils-wext.c | 4 ++--
+ src/ppp-manager/nm-ppp-manager.c | 4 ++--
+ src/settings/nm-inotify-helper.c | 2 +-
+ src/settings/plugins/ifcfg-rh/shvar.c | 6 +++---
+ src/settings/plugins/ifupdown/interface_parser.c | 2 +-
+ src/tests/test-general-with-expect.c | 3 ++-
+ 17 files changed, 34 insertions(+), 33 deletions(-)
+
+diff --git a/src/devices/adsl/nm-device-adsl.c b/src/devices/adsl/nm-device-adsl.c
+index 2ab67c9..77c6e11 100644
+--- a/src/devices/adsl/nm-device-adsl.c
++++ b/src/devices/adsl/nm-device-adsl.c
+@@ -154,7 +154,7 @@ br2684_assign_vcc (NMDeviceAdsl *self, NMSettingAdsl *s_adsl)
+ g_return_val_if_fail (priv->brfd == -1, FALSE);
+ g_return_val_if_fail (priv->nas_ifname != NULL, FALSE);
+
+- priv->brfd = socket (PF_ATMPVC, SOCK_DGRAM, ATM_AAL5);
++ priv->brfd = socket (PF_ATMPVC, SOCK_DGRAM | SOCK_CLOEXEC, ATM_AAL5);
+ if (priv->brfd < 0) {
+ errsv = errno;
+ _LOGE (LOGD_ADSL, "failed to open ATM control socket (%d)", errsv);
+@@ -338,7 +338,7 @@ br2684_create_iface (NMDeviceAdsl *self,
+ nm_clear_g_source (&priv->nas_update_id);
+ }
+
+- fd = socket (PF_ATMPVC, SOCK_DGRAM, ATM_AAL5);
++ fd = socket (PF_ATMPVC, SOCK_DGRAM | SOCK_CLOEXEC, ATM_AAL5);
+ if (fd < 0) {
+ errsv = errno;
+ _LOGE (LOGD_ADSL, "failed to open ATM control socket (%d)", errsv);
+diff --git a/src/devices/bluetooth/nm-bluez5-dun.c b/src/devices/bluetooth/nm-bluez5-dun.c
+index 4c93feb..aba3a0d 100644
+--- a/src/devices/bluetooth/nm-bluez5-dun.c
++++ b/src/devices/bluetooth/nm-bluez5-dun.c
+@@ -64,7 +64,7 @@ dun_connect (NMBluez5DunContext *context)
+ .channel = context->rfcomm_channel
+ };
+
+- context->rfcomm_fd = socket (AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
++ context->rfcomm_fd = socket (AF_BLUETOOTH, SOCK_STREAM | SOCK_CLOEXEC, BTPROTO_RFCOMM);
+ if (context->rfcomm_fd < 0) {
+ int errsv = errno;
+ error = g_error_new (NM_BT_ERROR, NM_BT_ERROR_DUN_CONNECT_FAILED,
+@@ -112,7 +112,7 @@ dun_connect (NMBluez5DunContext *context)
+ context->rfcomm_id = devid;
+
+ snprintf (tty, ttylen, "/dev/rfcomm%d", devid);
+- while ((context->rfcomm_tty_fd = open (tty, O_RDONLY | O_NOCTTY)) < 0 && try--) {
++ while ((context->rfcomm_tty_fd = open (tty, O_RDONLY | O_NOCTTY | O_CLOEXEC)) < 0 && try--) {
+ if (try) {
+ g_usleep (100 * 1000);
+ continue;
+diff --git a/src/devices/tests/test-lldp.c b/src/devices/tests/test-lldp.c
+index bff85e6..5af76ad 100644
+--- a/src/devices/tests/test-lldp.c
++++ b/src/devices/tests/test-lldp.c
+@@ -352,7 +352,7 @@ _test_recv_fixture_setup (TestRecvFixture *fixture, gconstpointer user_data)
+ struct ifreq ifr = { };
+ int fd, s;
+
+- fd = open ("/dev/net/tun", O_RDWR);
++ fd = open ("/dev/net/tun", O_RDWR | O_CLOEXEC);
+ g_assert (fd >= 0);
+
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+@@ -360,7 +360,7 @@ _test_recv_fixture_setup (TestRecvFixture *fixture, gconstpointer user_data)
+ g_assert (ioctl (fd, TUNSETIFF, &ifr) >= 0);
+
+ /* Bring the interface up */
+- s = socket (AF_INET, SOCK_DGRAM, 0);
++ s = socket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ g_assert (s >= 0);
+ ifr.ifr_flags |= IFF_UP;
+ g_assert (ioctl (s, SIOCSIFFLAGS, &ifr) >= 0);
+diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c
+index 2d7ee69..347dc12 100644
+--- a/src/devices/wwan/nm-modem.c
++++ b/src/devices/wwan/nm-modem.c
+@@ -499,7 +499,7 @@ port_speed_is_zero (const char *port)
+ struct termios options;
+ nm_auto_close int fd = -1;
+
+- fd = open (port, O_RDWR | O_NONBLOCK | O_NOCTTY);
++ fd = open (port, O_RDWR | O_NONBLOCK | O_NOCTTY | O_CLOEXEC);
+ if (fd < 0)
+ return FALSE;
+
+diff --git a/src/dns-manager/nm-dns-manager.c b/src/dns-manager/nm-dns-manager.c
+index 135a7a9..2d0e515 100644
+--- a/src/dns-manager/nm-dns-manager.c
++++ b/src/dns-manager/nm-dns-manager.c
+@@ -722,7 +722,7 @@ update_resolv_conf (NMDnsManager *self,
+ }
+ }
+
+- if ((f = fopen (MY_RESOLV_CONF_TMP, "w")) == NULL) {
++ if ((f = fopen (MY_RESOLV_CONF_TMP, "we")) == NULL) {
+ errsv = errno;
+ g_set_error (error,
+ NM_MANAGER_ERROR,
+@@ -1591,7 +1591,7 @@ _check_resconf_immutable (NMDnsManagerResolvConfManager rc_manager)
+ }
+ }
+
+- fd = open (_PATH_RESCONF, O_RDONLY);
++ fd = open (_PATH_RESCONF, O_RDONLY | O_CLOEXEC);
+ if (fd != -1) {
+ if (ioctl (fd, FS_IOC_GETFLAGS, &flags) != -1)
+ immutable = NM_FLAGS_HAS (flags, FS_IMMUTABLE_FL);
+diff --git a/src/main-utils.c b/src/main-utils.c
+index 8624280..02fbe19 100644
+--- a/src/main-utils.c
++++ b/src/main-utils.c
+@@ -95,7 +95,7 @@ nm_main_utils_write_pidfile (const char *pidfile)
+ int fd;
+ gboolean success = FALSE;
+
+- if ((fd = open (pidfile, O_CREAT|O_WRONLY|O_TRUNC, 00644)) < 0) {
++ if ((fd = open (pidfile, O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, 00644)) < 0) {
+ fprintf (stderr, _("Opening %s failed: %s\n"), pidfile, strerror (errno));
+ return FALSE;
+ }
+diff --git a/src/nm-manager.c b/src/nm-manager.c
+index 6a09966..3c650f7 100644
+--- a/src/nm-manager.c
++++ b/src/nm-manager.c
+@@ -5323,7 +5323,7 @@ rfkill_change (NMManager *self, const char *desc, RfKillType rtype, gboolean ena
+ g_return_if_fail (rtype == RFKILL_TYPE_WLAN || rtype == RFKILL_TYPE_WWAN);
+
+ errno = 0;
+- fd = open ("/dev/rfkill", O_RDWR);
++ fd = open ("/dev/rfkill", O_RDWR | O_CLOEXEC);
+ if (fd < 0) {
+ if (errno == EACCES)
+ _LOGW (LOGD_RFKILL, "(%s): failed to open killswitch device", desc);
+diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
+index 94fad20..d3bd9e3 100644
+--- a/src/platform/nm-linux-platform.c
++++ b/src/platform/nm-linux-platform.c
+@@ -5013,7 +5013,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;
+
+diff --git a/src/platform/nm-platform-utils.c b/src/platform/nm-platform-utils.c
+index d274a55..1aaea53 100644
+--- a/src/platform/nm-platform-utils.c
++++ b/src/platform/nm-platform-utils.c
+@@ -63,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;
+@@ -341,7 +341,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;
+diff --git a/src/platform/nmp-netns.c b/src/platform/nmp-netns.c
+index 2629585..07e134c 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/tests/test-common.c b/src/platform/tests/test-common.c
+index b1947a6..d636ebe 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-wext.c b/src/platform/wifi/wifi-utils-wext.c
+index af285b4..11e510f 100644
+--- a/src/platform/wifi/wifi-utils-wext.c
++++ b/src/platform/wifi/wifi-utils-wext.c
+@@ -577,7 +577,7 @@ 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;
+
+@@ -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/ppp-manager/nm-ppp-manager.c b/src/ppp-manager/nm-ppp-manager.c
+index fe81eb2..a524b22 100644
+--- a/src/ppp-manager/nm-ppp-manager.c
++++ b/src/ppp-manager/nm-ppp-manager.c
+@@ -197,7 +197,7 @@ monitor_cb (gpointer user_data)
+ if (errno != ENODEV)
+ _LOGW ("could not read ppp stats: %s", strerror (errno));
+ } else {
+- g_signal_emit (manager, signals[STATS], 0,
++ g_signal_emit (manager, signals[STATS], 0,
+ stats.p.ppp_ibytes,
+ stats.p.ppp_obytes);
+ }
+@@ -214,7 +214,7 @@ monitor_stats (NMPPPManager *manager)
+ if (priv->monitor_fd >= 0)
+ return;
+
+- priv->monitor_fd = socket (AF_INET, SOCK_DGRAM, 0);
++ priv->monitor_fd = socket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ if (priv->monitor_fd >= 0) {
+ g_warn_if_fail (priv->monitor_id == 0);
+ if (priv->monitor_id)
+diff --git a/src/settings/nm-inotify-helper.c b/src/settings/nm-inotify-helper.c
+index ce15246..4611264 100644
+--- a/src/settings/nm-inotify-helper.c
++++ b/src/settings/nm-inotify-helper.c
+@@ -128,7 +128,7 @@ init_inotify (NMInotifyHelper *self)
+ GIOChannel *channel;
+ guint source_id;
+
+- priv->ifd = inotify_init ();
++ priv->ifd = inotify_init1 (IN_CLOEXEC);
+ if (priv->ifd == -1) {
+ int errsv = errno;
+
+diff --git a/src/settings/plugins/ifcfg-rh/shvar.c b/src/settings/plugins/ifcfg-rh/shvar.c
+index 4e75634..ff19102 100644
+--- a/src/settings/plugins/ifcfg-rh/shvar.c
++++ b/src/settings/plugins/ifcfg-rh/shvar.c
+@@ -55,11 +55,11 @@ svOpenFileInternal (const char *name, gboolean create, GError **error)
+
+ s->fd = -1;
+ if (create)
+- s->fd = open (name, O_RDWR); /* NOT O_CREAT */
++ s->fd = open (name, O_RDWR | O_CLOEXEC); /* NOT O_CREAT */
+
+ if (!create || s->fd == -1) {
+ /* try read-only */
+- s->fd = open (name, O_RDONLY); /* NOT O_CREAT */
++ s->fd = open (name, O_RDONLY | O_CLOEXEC); /* NOT O_CREAT */
+ if (s->fd == -1)
+ errsv = errno;
+ else
+@@ -467,7 +467,7 @@ svWriteFile (shvarFile *s, int mode, GError **error)
+
+ if (s->modified) {
+ if (s->fd == -1)
+- s->fd = open (s->fileName, O_WRONLY | O_CREAT, mode);
++ s->fd = open (s->fileName, O_WRONLY | O_CREAT | O_CLOEXEC, mode);
+ if (s->fd == -1) {
+ int errsv = errno;
+
+diff --git a/src/settings/plugins/ifupdown/interface_parser.c b/src/settings/plugins/ifupdown/interface_parser.c
+index 7ad902d..cb60dbc 100644
+--- a/src/settings/plugins/ifupdown/interface_parser.c
++++ b/src/settings/plugins/ifupdown/interface_parser.c
+@@ -117,7 +117,7 @@ _recursive_ifparser (const char *eni_file, int quiet)
+ nm_log_warn (LOGD_SETTINGS, "interfaces file %s doesn't exist\n", eni_file);
+ return;
+ }
+- inp = fopen (eni_file, "r");
++ inp = fopen (eni_file, "re");
+ if (inp == NULL) {
+ if (!quiet)
+ nm_log_warn (LOGD_SETTINGS, "Can't open %s\n", eni_file);
+diff --git a/src/tests/test-general-with-expect.c b/src/tests/test-general-with-expect.c
+index 64b47bd..4c88689 100644
+--- a/src/tests/test-general-with-expect.c
++++ b/src/tests/test-general-with-expect.c
+@@ -26,6 +26,7 @@
+ #include <netinet/ether.h>
+ #include <sys/types.h>
+ #include <sys/wait.h>
++#include <fcntl.h>
+
+ #include "NetworkManagerUtils.h"
+ #include "nm-multi-index.h"
+@@ -173,7 +174,7 @@ test_nm_utils_kill_child_create_and_join_pgroup (void)
+ int pipefd[2];
+ pid_t pgid;
+
+- err = pipe (pipefd);
++ err = pipe2 (pipefd, O_CLOEXEC);
+ g_assert (err == 0);
+
+ pgid = fork();
diff --git a/debian/patches/core-add-utils-for-file-handling.patch b/debian/patches/core-add-utils-for-file-handling.patch
new file mode 100644
index 0000000..1f8ae91
--- /dev/null
+++ b/debian/patches/core-add-utils-for-file-handling.patch
@@ -0,0 +1,163 @@
+From: Thomas Haller <thaller@redhat.com>
+Date: Fri, 3 Jun 2016 13:56:18 +0200
+Subject: core: add utils for file handling
+
+Copied and adjusted from systemd code.
+---
+ src/nm-core-utils.c | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ src/nm-core-utils.h | 6 +++
+ 2 files changed, 124 insertions(+)
+
+diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c
+index 28e4f99..38ecd0b 100644
+--- a/src/nm-core-utils.c
++++ b/src/nm-core-utils.c
+@@ -26,6 +26,7 @@
+ #include <errno.h>
+ #include <fcntl.h>
+ #include <string.h>
++#include <poll.h>
+ #include <unistd.h>
+ #include <stdlib.h>
+ #include <resolv.h>
+@@ -2663,6 +2664,123 @@ nm_utils_machine_id_read (void)
+
+ /*****************************************************************************/
+
++/* taken from systemd's fd_wait_for_event(). Note that the timeout
++ * is here in nano-seconds, not micro-seconds. */
++int
++nm_utils_fd_wait_for_event (int fd, int event, gint64 timeout_ns)
++{
++ struct pollfd pollfd = {
++ .fd = fd,
++ .events = event,
++ };
++ struct timespec ts, *pts;
++ int r;
++
++ if (timeout_ns < 0)
++ pts = NULL;
++ else {
++ ts.tv_sec = (time_t) (timeout_ns / NM_UTILS_NS_PER_SECOND);
++ ts.tv_nsec = (long int) (timeout_ns % NM_UTILS_NS_PER_SECOND);
++ pts = &ts;
++ }
++
++ r = ppoll (&pollfd, 1, pts, NULL);
++ if (r < 0)
++ return -errno;
++ if (r == 0)
++ return 0;
++ return pollfd.revents;
++}
++
++/* taken from systemd's loop_read() */
++ssize_t
++nm_utils_fd_read_loop (int fd, void *buf, size_t nbytes, bool do_poll)
++{
++ uint8_t *p = buf;
++ ssize_t n = 0;
++
++ g_return_val_if_fail (fd >= 0, -EINVAL);
++ g_return_val_if_fail (buf, -EINVAL);
++
++ /* If called with nbytes == 0, let's call read() at least
++ * once, to validate the operation */
++
++ if (nbytes > (size_t) SSIZE_MAX)
++ return -EINVAL;
++
++ do {
++ ssize_t k;
++
++ k = read (fd, p, nbytes);
++ if (k < 0) {
++ if (errno == EINTR)
++ continue;
++
++ if (errno == EAGAIN && do_poll) {
++
++ /* We knowingly ignore any return value here,
++ * and expect that any error/EOF is reported
++ * via read() */
++
++ (void) nm_utils_fd_wait_for_event (fd, POLLIN, -1);
++ continue;
++ }
++
++ return n > 0 ? n : -errno;
++ }
++
++ if (k == 0)
++ return n;
++
++ g_assert ((size_t) k <= nbytes);
++
++ p += k;
++ nbytes -= k;
++ n += k;
++ } while (nbytes > 0);
++
++ return n;
++}
++
++/* taken from systemd's loop_read_exact() */
++int
++nm_utils_fd_read_loop_exact (int fd, void *buf, size_t nbytes, bool do_poll)
++{
++ ssize_t n;
++
++ n = nm_utils_fd_read_loop (fd, buf, nbytes, do_poll);
++ if (n < 0)
++ return (int) n;
++ if ((size_t) n != nbytes)
++ return -EIO;
++
++ return 0;
++}
++
++/* taken from systemd's dev_urandom(). */
++int
++nm_utils_read_urandom (void *p, size_t nbytes)
++{
++ int fd = -1;
++ int r;
++
++again:
++ fd = open ("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
++ if (fd < 0) {
++ r = errno;
++ if (r == EINTR)
++ goto again;
++ return r == ENOENT ? -ENOSYS : -r;
++ }
++
++ r = nm_utils_fd_read_loop_exact (fd, p, nbytes, TRUE);
++ close (fd);
++
++ return r;
++}
++
++/*****************************************************************************/
++
+ guint8 *
+ nm_utils_secret_key_read (gsize *out_key_len, GError **error)
+ {
+diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h
+index a1213d2..312b611 100644
+--- a/src/nm-core-utils.h
++++ b/src/nm-core-utils.h
+@@ -308,6 +308,12 @@ const char *nm_utils_ip4_property_path (const char *ifname, const char *property
+
+ gboolean nm_utils_is_specific_hostname (const char *name);
+
++int nm_utils_fd_wait_for_event (int fd, int event, gint64 timeout_ns);
++ssize_t nm_utils_fd_read_loop (int fd, void *buf, size_t nbytes, bool do_poll);
++int nm_utils_fd_read_loop_exact (int fd, void *buf, size_t nbytes, bool do_poll);
++
++int nm_utils_read_urandom (void *p, size_t n);
++
+ char *nm_utils_machine_id_read (void);
+ gboolean nm_utils_machine_id_parse (const char *id_str, /*uuid_t*/ guchar *out_uuid);
+
diff --git a/debian/patches/device-wwan-use-nm_auto_close-instead-of-gs_fd_close.patch b/debian/patches/device-wwan-use-nm_auto_close-instead-of-gs_fd_close.patch
new file mode 100644
index 0000000..6c7e957
--- /dev/null
+++ b/debian/patches/device-wwan-use-nm_auto_close-instead-of-gs_fd_close.patch
@@ -0,0 +1,40 @@
+From: Thomas Haller <thaller@redhat.com>
+Date: Fri, 9 Dec 2016 09:27:02 +0100
+Subject: device/wwan: use nm_auto_close instead of gs_fd_close
+
+(cherry picked from commit ed299cc8605a8291a61b3a514f8dc20390b18c77)
+---
+ src/devices/wwan/nm-modem.c | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c
+index 9d562be..2d7ee69 100644
+--- a/src/devices/wwan/nm-modem.c
++++ b/src/devices/wwan/nm-modem.c
+@@ -496,18 +496,18 @@ ppp_stats (NMPPPManager *ppp_manager,
+ static gboolean
+ port_speed_is_zero (const char *port)
+ {
+- struct termios options;
+- gs_fd_close int fd = -1;
++ struct termios options;
++ nm_auto_close int fd = -1;
+
+- fd = open (port, O_RDWR | O_NONBLOCK | O_NOCTTY);
+- if (fd < 0)
++ fd = open (port, O_RDWR | O_NONBLOCK | O_NOCTTY);
++ if (fd < 0)
+ return FALSE;
+
+- memset (&options, 0, sizeof (struct termios));
+- if (tcgetattr (fd, &options) != 0)
+- return FALSE;
++ memset (&options, 0, sizeof (struct termios));
++ if (tcgetattr (fd, &options) != 0)
++ return FALSE;
+
+- return cfgetospeed (&options) == B0;
++ return cfgetospeed (&options) == B0;
+ }
+
+ static NMActStageReturn
diff --git a/debian/patches/platform-add-a-new-function-nmp_utils_open_sysctl.patch b/debian/patches/platform-add-a-new-function-nmp_utils_open_sysctl.patch
new file mode 100644
index 0000000..603c4ed
--- /dev/null
+++ b/debian/patches/platform-add-a-new-function-nmp_utils_open_sysctl.patch
@@ -0,0 +1,103 @@
+From: Kai-Heng Feng <kai.heng.feng@canonical.com>
+Date: Wed, 7 Dec 2016 18:15:13 +0800
+Subject: platform: add a new function nmp_utils_open_sysctl()
+
+A race condition may happen when NetworkManager opens sysfs and udev
+renames interface name at the same time. Thomas Haller provides a new
+function [1] which can avoid the race condition when opening sysfs.
+
+This patch is a direct copy from [1].
+
+[1] https://mail.gnome.org/archives/networkmanager-list/2016-December/msg00004.html
+
+Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
+(cherry picked from commit 713c74f6e4a88f874cf3e9908b3fb153f2ea5b83)
+---
+ src/platform/nm-platform-utils.c | 51 ++++++++++++++++++++++++++++++++++++++++
+ src/platform/nm-platform-utils.h | 2 ++
+ 2 files changed, 53 insertions(+)
+
+diff --git a/src/platform/nm-platform-utils.c b/src/platform/nm-platform-utils.c
+index b4542ad..85b3ded 100644
+--- a/src/platform/nm-platform-utils.c
++++ b/src/platform/nm-platform-utils.c
+@@ -31,6 +31,7 @@
+ #include <linux/mii.h>
+ #include <linux/version.h>
+ #include <linux/rtnetlink.h>
++#include <fcntl.h>
+
+ #include "nm-utils.h"
+ #include "nm-setting-wired.h"
+@@ -41,6 +42,8 @@
+ * ethtool
+ ******************************************************************/
+
++extern char *if_indextoname (unsigned int __ifindex, char *__ifname);
++
+ static gboolean
+ ethtool_get (const char *name, gpointer edata)
+ {
+@@ -472,3 +475,51 @@ nmp_utils_ip_config_source_from_rtprot (guint rtprot)
+ }
+ }
+
++int
++nmp_utils_open_sysctl(int ifindex, const char *ifname)
++{
++ #define SYS_CLASS_NET "/sys/class/net/"
++ char ifname_buf[IFNAMSIZ];
++ guint try_count = 0;
++ char sysdir[NM_STRLEN (SYS_CLASS_NET) + IFNAMSIZ + 1] = SYS_CLASS_NET;
++ char fd_buf[256];
++ int fd;
++ int fd_ifindex;
++ ssize_t nn;
++
++ while (++try_count < 4) {
++ if (!ifname) {
++ ifname = if_indextoname (ifindex, ifname_buf);
++ if (!ifname)
++ return -1;
++ }
++
++ nm_utils_ifname_cpy (&sysdir[NM_STRLEN (SYS_CLASS_NET)], ifname);
++ fd = open (sysdir, O_DIRECTORY);
++ if (fd < 0)
++ goto next;
++ fd_ifindex = openat (fd, "ifindex", 0);
++ if (fd_ifindex < 0) {
++ close (fd);
++ goto next;
++ }
++ /* read ifindex file, and compare it to @ifindex. If match, return fd. */
++ nn = nm_utils_fd_read_loop (fd_ifindex, fd_buf, sizeof (fd_buf) - 1, FALSE);
++ if (nn < 0) {
++ close (fd);
++ close (fd_ifindex);
++ goto next;
++ }
++ fd_buf[sizeof (fd_buf) - 1] = '\0';
++
++ if (ifindex != _nm_utils_ascii_str_to_int64 (fd_buf, 10, 1, G_MAXINT, -1)) {
++ close (fd);
++ close (fd_ifindex);
++ goto next;
++ }
++ return fd;
++next:
++ ifname = NULL;
++ }
++ return -1;
++}
+diff --git a/src/platform/nm-platform-utils.h b/src/platform/nm-platform-utils.h
+index f259474..6b5869e 100644
+--- a/src/platform/nm-platform-utils.h
++++ b/src/platform/nm-platform-utils.h
+@@ -57,4 +57,6 @@ gboolean nmp_utils_device_exists (const char *name);
+ guint nmp_utils_ip_config_source_to_rtprot (NMIPConfigSource source);
+ NMIPConfigSource nmp_utils_ip_config_source_from_rtprot (guint rtprot);
+
++int nmp_utils_open_sysctl(int ifindex, const char *ifname);
++
+ #endif /* __NM_PLATFORM_UTILS_H__ */
diff --git a/debian/patches/platform-refactor-nmp_utils_sysctl_open_netdir.patch b/debian/patches/platform-refactor-nmp_utils_sysctl_open_netdir.patch
new file mode 100644
index 0000000..12ac72a
--- /dev/null
+++ b/debian/patches/platform-refactor-nmp_utils_sysctl_open_netdir.patch
@@ -0,0 +1,206 @@
+From: Thomas Haller <thaller@redhat.com>
+Date: Thu, 8 Dec 2016 13:55:17 +0100
+Subject: platform: refactor nmp_utils_sysctl_open_netdir()
+
+- use nm_auto_close cleanup attribute
+- optionally, return the found ifname
+- don't stat "phy80211". If such an entity can be opened,
+ just assume it's a directory.
+
+(cherry picked from commit 76876e896c242fd82d048743ffcf2c0481442dc5)
+---
+ src/platform/nm-platform-utils.c | 94 +++++++++++++++++++++++++++-------------
+ src/platform/nm-platform-utils.h | 4 +-
+ src/platform/wifi/wifi-utils.c | 23 +++++-----
+ 3 files changed, 76 insertions(+), 45 deletions(-)
+
+diff --git a/src/platform/nm-platform-utils.c b/src/platform/nm-platform-utils.c
+index 85b3ded..d274a55 100644
+--- a/src/platform/nm-platform-utils.c
++++ b/src/platform/nm-platform-utils.c
+@@ -38,12 +38,12 @@
+
+ #include "nm-core-utils.h"
+
++extern char *if_indextoname (unsigned int __ifindex, char *__ifname);
++
+ /******************************************************************
+ * ethtool
+ ******************************************************************/
+
+-extern char *if_indextoname (unsigned int __ifindex, char *__ifname);
+-
+ static gboolean
+ ethtool_get (const char *name, gpointer edata)
+ {
+@@ -475,51 +475,83 @@ nmp_utils_ip_config_source_from_rtprot (guint rtprot)
+ }
+ }
+
++/**
++ * 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_open_sysctl(int ifindex, const char *ifname)
++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 + 1] = SYS_CLASS_NET;
++ char sysdir[NM_STRLEN (SYS_CLASS_NET) + IFNAMSIZ] = SYS_CLASS_NET;
+ char fd_buf[256];
+- int fd;
+- int fd_ifindex;
+ ssize_t nn;
+
+- while (++try_count < 4) {
++ 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_utils_ifname_cpy (&sysdir[NM_STRLEN (SYS_CLASS_NET)], ifname);
+- fd = open (sysdir, O_DIRECTORY);
+- if (fd < 0)
+- goto next;
+- fd_ifindex = openat (fd, "ifindex", 0);
+- if (fd_ifindex < 0) {
+- close (fd);
+- goto next;
+- }
+- /* read ifindex file, and compare it to @ifindex. If match, return fd. */
+- nn = nm_utils_fd_read_loop (fd_ifindex, fd_buf, sizeof (fd_buf) - 1, FALSE);
+- if (nn < 0) {
+- close (fd);
+- close (fd_ifindex);
+- goto next;
+- }
+- fd_buf[sizeof (fd_buf) - 1] = '\0';
++ nm_assert (nm_utils_iface_valid_name (ifname));
+
+- if (ifindex != _nm_utils_ascii_str_to_int64 (fd_buf, 10, 1, G_MAXINT, -1)) {
+- close (fd);
+- close (fd_ifindex);
+- goto next;
+- }
++ 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;
+-next:
+- ifname = NULL;
+ }
++
+ return -1;
+ }
+diff --git a/src/platform/nm-platform-utils.h b/src/platform/nm-platform-utils.h
+index 6b5869e..9bd82df 100644
+--- a/src/platform/nm-platform-utils.h
++++ b/src/platform/nm-platform-utils.h
+@@ -57,6 +57,8 @@ gboolean nmp_utils_device_exists (const char *name);
+ guint nmp_utils_ip_config_source_to_rtprot (NMIPConfigSource source);
+ NMIPConfigSource nmp_utils_ip_config_source_from_rtprot (guint rtprot);
+
+-int nmp_utils_open_sysctl(int ifindex, const char *ifname);
++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/wifi/wifi-utils.c b/src/platform/wifi/wifi-utils.c
+index 96c2be4..2ce6eb7 100644
+--- a/src/platform/wifi/wifi-utils.c
++++ b/src/platform/wifi/wifi-utils.c
+@@ -187,29 +187,26 @@ wifi_utils_is_wifi (int ifindex, const char *ifname)
+ {
+ int fd_sysnet;
+ int fd_phy80211;
+- struct stat s;
++ char ifname_verified[IFNAMSIZ];
+
+- g_return_val_if_fail (ifname != NULL, FALSE);
++ g_return_val_if_fail (ifindex > 0, FALSE);
+
+- fd_sysnet = nmp_utils_open_sysctl (ifindex, ifname);
++ fd_sysnet = nmp_utils_sysctl_open_netdir (ifindex, ifname, ifname_verified);
+ if (fd_sysnet < 0)
+ return FALSE;
+
+- fd_phy80211 = openat (fd_sysnet, "phy80211", 0);
+- if (fd_phy80211 < 0) {
+- close (fd_sysnet);
+- return FALSE;
+- }
++ /* 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;
++
++ fd_phy80211 = openat (fd_sysnet, "phy80211", O_CLOEXEC);
++ close (fd_sysnet);
+
+- if ((fstat (fd_phy80211, &s) == 0 && (s.st_mode & S_IFDIR))) {
+- close (fd_sysnet);
++ if (fd_phy80211 >= 0) {
+ close (fd_phy80211);
+ return TRUE;
+ }
+
+- close (fd_sysnet);
+- close (fd_phy80211);
+-
+ #if HAVE_WEXT
+ if (wifi_wext_is_wifi (ifname))
+ return TRUE;
diff --git a/debian/patches/platform-refactor-wifi_utils_is_wifi-not-to-pass-sys.patch b/debian/patches/platform-refactor-wifi_utils_is_wifi-not-to-pass-sys.patch
new file mode 100644
index 0000000..eafb543
--- /dev/null
+++ b/debian/patches/platform-refactor-wifi_utils_is_wifi-not-to-pass-sys.patch
@@ -0,0 +1,93 @@
+From: Thomas Haller <thaller@redhat.com>
+Date: Thu, 21 Apr 2016 14:25:38 +0200
+Subject: platform: refactor wifi_utils_is_wifi() not to pass sysfs_path
+
+wifi_utils_is_wifi() only has one caller, so it's very clear
+what the passed in @sysfs_path contains. Instead of accepting
+a redundant argument, compute the sysfs path internally based
+on @iface alone.
+---
+ src/platform/nm-linux-platform.c | 2 +-
+ src/platform/wifi/wifi-utils.c | 21 ++++++++++++---------
+ src/platform/wifi/wifi-utils.h | 2 +-
+ 3 files changed, 14 insertions(+), 11 deletions(-)
+
+diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
+index f6f7be8..25feb71 100644
+--- a/src/platform/nm-linux-platform.c
++++ b/src/platform/nm-linux-platform.c
+@@ -729,7 +729,7 @@ _linktype_get_type (NMPlatform *platform,
+ }
+
+ /* Fallback for drivers that don't call SET_NETDEV_DEVTYPE() */
+- if (wifi_utils_is_wifi (ifname, sysfs_path))
++ if (wifi_utils_is_wifi (ifname))
+ return NM_LINK_TYPE_WIFI;
+
+ if (arptype == ARPHRD_ETHER) {
+diff --git a/src/platform/wifi/wifi-utils.c b/src/platform/wifi/wifi-utils.c
+index 4f04041..b7fe86b 100644
+--- a/src/platform/wifi/wifi-utils.c
++++ b/src/platform/wifi/wifi-utils.c
+@@ -21,16 +21,18 @@
+
+ #include "nm-default.h"
+
++#include "wifi-utils.h"
++
+ #include <sys/stat.h>
+ #include <stdio.h>
+ #include <string.h>
+
+-#include "wifi-utils.h"
+ #include "wifi-utils-private.h"
+ #include "wifi-utils-nl80211.h"
+ #if HAVE_WEXT
+ #include "wifi-utils-wext.h"
+ #endif
++#include "nm-core-utils.h"
+
+ gpointer
+ wifi_data_new (const char *iface, int ifindex, gsize len)
+@@ -178,19 +180,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)
+ {
+- char phy80211_path[255];
++ char phy80211_path[NM_STRLEN ("/sys/class/net/123456789012345/phy80211\0") + 100 /*safety*/];
+ struct stat s;
+
+ g_return_val_if_fail (iface != NULL, FALSE);
+
+- if (sysfs_path) {
+- /* Check for nl80211 sysfs paths */
+- g_snprintf (phy80211_path, sizeof (phy80211_path), "%s/phy80211", sysfs_path);
+- if ((stat (phy80211_path, &s) == 0 && (s.st_mode & S_IFDIR)))
+- return TRUE;
+- }
++ 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);
++
++ if ((stat (phy80211_path, &s) == 0 && (s.st_mode & S_IFDIR)))
++ return TRUE;
+
+ #if HAVE_WEXT
+ if (wifi_wext_is_wifi (iface))
+diff --git a/src/platform/wifi/wifi-utils.h b/src/platform/wifi/wifi-utils.h
+index 9555bbe..3a4f996 100644
+--- a/src/platform/wifi/wifi-utils.h
++++ b/src/platform/wifi/wifi-utils.h
+@@ -29,7 +29,7 @@
+
+ typedef struct WifiData WifiData;
+
+-gboolean wifi_utils_is_wifi (const char *iface, const char *sysfs_path);
++gboolean wifi_utils_is_wifi (const char *iface);
+
+ WifiData *wifi_utils_init (const char *iface, int ifindex, gboolean check_scan);
+
diff --git a/debian/patches/platform-wifi-use-nmp_utils_open_sysctl-to-check-if-.patch b/debian/patches/platform-wifi-use-nmp_utils_open_sysctl-to-check-if-.patch
new file mode 100644
index 0000000..135cc77
--- /dev/null
+++ b/debian/patches/platform-wifi-use-nmp_utils_open_sysctl-to-check-if-.patch
@@ -0,0 +1,110 @@
+From: Kai-Heng Feng <kai.heng.feng@canonical.com>
+Date: Wed, 7 Dec 2016 18:40:09 +0800
+Subject: platform: wifi: use nmp_utils_open_sysctl() to check if device is
+ wifi
+
+Since function nmp_utils_open_sysctl() can avoid race condition, use it
+in wifi_utils_is_wifi() to open sysfs and correctly check if it's a wifi
+device.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=775613
+Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
+(cherry picked from commit b95556eb781a18ee1c96470f40b9e1e162b0ee60)
+---
+ src/platform/nm-linux-platform.c | 2 +-
+ src/platform/wifi/wifi-utils.c | 33 ++++++++++++++++++++++++---------
+ src/platform/wifi/wifi-utils.h | 2 +-
+ 3 files changed, 26 insertions(+), 11 deletions(-)
+
+diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
+index 25feb71..94fad20 100644
+--- a/src/platform/nm-linux-platform.c
++++ b/src/platform/nm-linux-platform.c
+@@ -729,7 +729,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) {
+diff --git a/src/platform/wifi/wifi-utils.c b/src/platform/wifi/wifi-utils.c
+index b7fe86b..96c2be4 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,35 @@ 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*/];
++ int fd_sysnet;
++ int fd_phy80211;
+ struct stat s;
+
+- g_return_val_if_fail (iface != NULL, FALSE);
++ g_return_val_if_fail (ifname != NULL, 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);
++ fd_sysnet = nmp_utils_open_sysctl (ifindex, ifname);
++ if (fd_sysnet < 0)
++ return FALSE;
+
+- if ((stat (phy80211_path, &s) == 0 && (s.st_mode & S_IFDIR)))
++ fd_phy80211 = openat (fd_sysnet, "phy80211", 0);
++ if (fd_phy80211 < 0) {
++ close (fd_sysnet);
++ return FALSE;
++ }
++
++ if ((fstat (fd_phy80211, &s) == 0 && (s.st_mode & S_IFDIR))) {
++ close (fd_sysnet);
++ close (fd_phy80211);
+ return TRUE;
++ }
++
++ close (fd_sysnet);
++ close (fd_phy80211);
+
+ #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 3a4f996..f84c12a 100644
+--- a/src/platform/wifi/wifi-utils.h
++++ b/src/platform/wifi/wifi-utils.h
+@@ -29,7 +29,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);
+
diff --git a/debian/patches/series b/debian/patches/series
index 8732e76..bb8b707 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -45,3 +45,13 @@ disable_general_with_expect_test.patch
libnm-Check-self-still-NMManager-or-not.patch
dns-manager-don-t-merge-split-DNS-search-domains.patch
#manager-fix-state-transition-on-resuming-from-sleep.patch
+
+# for LP: #1647283
+shared-add-nm_auto_close-and-nm_auto_fclose.patch
+device-wwan-use-nm_auto_close-instead-of-gs_fd_close.patch
+core-add-utils-for-file-handling.patch
+platform-add-a-new-function-nmp_utils_open_sysctl.patch
+platform-refactor-wifi_utils_is_wifi-not-to-pass-sys.patch
+platform-wifi-use-nmp_utils_open_sysctl-to-check-if-.patch
+platform-refactor-nmp_utils_sysctl_open_netdir.patch
+all-use-O_CLOEXEC-for-file-descriptors.patch
diff --git a/debian/patches/shared-add-nm_auto_close-and-nm_auto_fclose.patch b/debian/patches/shared-add-nm_auto_close-and-nm_auto_fclose.patch
new file mode 100644
index 0000000..3cb1cfa
--- /dev/null
+++ b/debian/patches/shared-add-nm_auto_close-and-nm_auto_fclose.patch
@@ -0,0 +1,62 @@
+From: Thomas Haller <thaller@redhat.com>
+Date: Fri, 9 Dec 2016 09:22:29 +0100
+Subject: shared: add nm_auto_close and nm_auto_fclose
+
+We already have gs_fd_close, which however doesn't preserve
+errno and only checks for fd != -1. Add our own define.
+
+Downside is, we have to include stdio.h and errno.h,
+which effectively ends up to be included *everywhere*.
+
+(cherry picked from commit 312cea870dfbc363da44074bd6f56ccd283c5420)
+---
+ shared/nm-macros-internal.h | 28 +++++++++++++++++++++++++++-
+ 1 file changed, 27 insertions(+), 1 deletion(-)
+
+diff --git a/shared/nm-macros-internal.h b/shared/nm-macros-internal.h
+index fe27b76..a361a55 100644
+--- a/shared/nm-macros-internal.h
++++ b/shared/nm-macros-internal.h
+@@ -22,7 +22,9 @@
+ #ifndef __NM_MACROS_INTERNAL_H__
+ #define __NM_MACROS_INTERNAL_H__
+
++#include <stdio.h>
+ #include <stdlib.h>
++#include <errno.h>
+
+ /********************************************************/
+
+@@ -54,7 +56,31 @@ _nm_auto_free_gstring_impl (GString **str)
+ }
+ #define nm_auto_free_gstring nm_auto(_nm_auto_free_gstring_impl)
+
+-/********************************************************/
++static inline void
++_nm_auto_close_impl (int *pfd)
++{
++ if (*pfd >= 0) {
++ int errsv = errno;
++
++ (void) close (*pfd);
++ errno = errsv;
++ }
++}
++#define nm_auto_close nm_auto(_nm_auto_close_impl)
++
++static inline void
++_nm_auto_fclose_impl (FILE **pfd)
++{
++ if (*pfd) {
++ int errsv = errno;
++
++ (void) fclose (*pfd);
++ errno = errsv;
++ }
++}
++#define nm_auto_fclose nm_auto(_nm_auto_fclose_impl)
++
++/*****************************************************************************/
+
+ /* http://stackoverflow.com/a/11172679 */
+ #define _NM_UTILS_MACRO_FIRST(...) __NM_UTILS_MACRO_FIRST_HELPER(__VA_ARGS__, throwaway)