core: merge branch 'th/sysctl-ifname-race-bgo775613'

https://bugzilla.gnome.org/show_bug.cgi?id=775613
This commit is contained in:
Thomas Haller 2016-12-13 12:02:24 +01:00
commit 0d7bf7dee3
38 changed files with 1223 additions and 536 deletions

View file

@ -22,7 +22,9 @@
#ifndef __NM_MACROS_INTERNAL_H__
#define __NM_MACROS_INTERNAL_H__
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include "nm-glib.h"
@ -59,6 +61,37 @@ _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)
static inline void
_nm_auto_protect_errno (int *p_saved_errno)
{
errno = *p_saved_errno;
}
#define NM_AUTO_PROTECT_ERRNO(errsv_saved) nm_auto(_nm_auto_protect_errno) _nm_unused const int errsv_saved = (errno)
/*****************************************************************************/
/* http://stackoverflow.com/a/11172679 */

View file

@ -137,7 +137,7 @@ adsl_add (NMAtmManager *self, GUdevDevice *udev_device)
atm_index_path = g_strdup_printf ("/sys/class/atm/%s/atmindex",
NM_ASSERT_VALID_PATH_COMPONENT (ifname));
atm_index = (int) nm_platform_sysctl_get_int_checked (NM_PLATFORM_GET,
atm_index_path,
NMP_SYSCTL_PATHID_ABSOLUTE (atm_index_path),
10, 0, G_MAXINT,
-1);
if (atm_index < 0) {

View file

@ -158,7 +158,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);
@ -344,7 +344,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);
@ -547,7 +547,7 @@ carrier_update_cb (gpointer user_data)
path = g_strdup_printf ("/sys/class/atm/%s/carrier",
NM_ASSERT_VALID_PATH_COMPONENT (nm_device_get_iface (NM_DEVICE (self))));
carrier = (int) nm_platform_sysctl_get_int_checked (NM_PLATFORM_GET, path, 10, 0, 1, -1);
carrier = (int) nm_platform_sysctl_get_int_checked (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (path), 10, 0, 1, -1);
g_free (path);
if (carrier != -1)

View file

@ -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;

View file

@ -208,7 +208,7 @@ _update_s390_subchannels (NMDeviceEthernet *self)
gs_free char *path = NULL, *value = NULL;
path = g_strdup_printf ("%s/%s", parent_path, item);
value = nm_platform_sysctl_get (NM_PLATFORM_GET, path);
value = nm_platform_sysctl_get (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (path));
if ( !strcmp (item, "portname")
&& !g_strcmp0 (value, "no portname required")) {
@ -827,7 +827,7 @@ link_negotiation_set (NMDevice *device)
}
}
if (!nm_platform_ethtool_get_link_settings (NM_PLATFORM_GET, nm_device_get_iface (device),
if (!nm_platform_ethtool_get_link_settings (NM_PLATFORM_GET, nm_device_get_ifindex (device),
&link_autoneg, &link_speed, &link_duplex)) {
_LOGW (LOGD_DEVICE, "set-link: unable to retrieve link negotiation");
return;
@ -852,7 +852,7 @@ link_negotiation_set (NMDevice *device)
}
if (!nm_platform_ethtool_set_link_settings (NM_PLATFORM_GET,
nm_device_get_iface (device),
nm_device_get_ifindex (device),
autoneg,
speed,
duplex)) {
@ -1243,7 +1243,7 @@ wake_on_lan_enable (NMDevice *device)
}
wol = NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE;
found:
return nm_platform_ethtool_set_wake_on_lan (NM_PLATFORM_GET, nm_device_get_iface (device), wol, password);
return nm_platform_ethtool_set_wake_on_lan (NM_PLATFORM_GET, nm_device_get_ifindex (device), wol, password);
}
/*****************************************************************************/
@ -1609,7 +1609,7 @@ get_link_speed (NMDevice *device)
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
guint32 speed;
if (!nm_platform_ethtool_get_link_settings (NM_PLATFORM_GET, nm_device_get_iface (device), NULL, &speed, NULL))
if (!nm_platform_ethtool_get_link_settings (NM_PLATFORM_GET, nm_device_get_ifindex (device), NULL, &speed, NULL))
return;
if (priv->speed == speed)
return;

View file

@ -77,10 +77,11 @@ get_generic_capabilities (NMDevice *device)
static NMActStageReturn
act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
{
nm_auto_close int dirfd = -1;
NMActStageReturn ret;
NMSettingInfiniband *s_infiniband;
char ifname_verified[IFNAMSIZ];
const char *transport_mode;
char *mode_path;
gboolean ok, no_firmware = FALSE;
g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
@ -94,11 +95,8 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
transport_mode = nm_setting_infiniband_get_transport_mode (s_infiniband);
mode_path = g_strdup_printf ("/sys/class/net/%s/mode",
NM_ASSERT_VALID_PATH_COMPONENT (nm_device_get_iface (dev)));
if (!g_file_test (mode_path, G_FILE_TEST_EXISTS)) {
g_free (mode_path);
dirfd = nm_platform_sysctl_open_netdir (NM_PLATFORM_GET, nm_device_get_ifindex (dev), ifname_verified);
if (dirfd < 0) {
if (!strcmp (transport_mode, "datagram"))
return NM_ACT_STAGE_RETURN_SUCCESS;
else {
@ -109,8 +107,7 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
/* With some drivers the interface must be down to set transport mode */
nm_device_take_down (dev, TRUE);
ok = nm_platform_sysctl_set (NM_PLATFORM_GET, mode_path, transport_mode);
g_free (mode_path);
ok = nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname_verified, "mode"), transport_mode);
nm_device_bring_up (dev, TRUE, &no_firmware);
if (!ok) {

View file

@ -80,7 +80,7 @@ reload_tun_properties (NMDeviceTun *self)
ifindex = nm_device_get_ifindex (NM_DEVICE (self));
if (ifindex > 0) {
if (!nm_platform_link_tun_get_properties (NM_PLATFORM_GET, ifindex, &props)) {
if (!nm_platform_link_tun_get_properties (NM_PLATFORM_GET, ifindex, NULL, &props)) {
_LOGD (LOGD_DEVICE, "tun-properties: cannot loading tun properties from platform for ifindex %d", ifindex);
ifindex = 0;
} else if (g_strcmp0 (priv->mode, props.mode) != 0) {
@ -181,7 +181,7 @@ update_connection (NMDevice *device, NMConnection *connection)
nm_connection_add_setting (connection, (NMSetting *) s_tun);
}
if (!nm_platform_link_tun_get_properties (NM_PLATFORM_GET, nm_device_get_ifindex (device), &props)) {
if (!nm_platform_link_tun_get_properties (NM_PLATFORM_GET, nm_device_get_ifindex (device), NULL, &props)) {
_LOGW (LOGD_PLATFORM, "failed to get TUN interface info while updating connection.");
return;
}

View file

@ -629,13 +629,13 @@ init_ip6_config_dns_priority (NMDevice *self, NMIP6Config *config)
gboolean
nm_device_ipv6_sysctl_set (NMDevice *self, const char *property, const char *value)
{
return nm_platform_sysctl_set (NM_PLATFORM_GET, nm_utils_ip6_property_path (nm_device_get_ip_iface (self), property), value);
return nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip6_property_path (nm_device_get_ip_iface (self), property)), value);
}
static guint32
nm_device_ipv6_sysctl_get_int32 (NMDevice *self, const char *property, gint32 fallback)
{
return nm_platform_sysctl_get_int32 (NM_PLATFORM_GET, nm_utils_ip6_property_path (nm_device_get_ip_iface (self), property), fallback);
return nm_platform_sysctl_get_int32 (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip6_property_path (nm_device_get_ip_iface (self), property)), fallback);
}
gboolean
@ -6771,7 +6771,7 @@ save_ip6_properties (NMDevice *self)
g_hash_table_remove_all (priv->ip6_saved_properties);
for (i = 0; i < G_N_ELEMENTS (ip6_properties_to_save); i++) {
value = nm_platform_sysctl_get (NM_PLATFORM_GET, nm_utils_ip6_property_path (ifname, ip6_properties_to_save[i]));
value = nm_platform_sysctl_get (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip6_property_path (ifname, ip6_properties_to_save[i])));
if (value) {
g_hash_table_insert (priv->ip6_saved_properties,
(char *) ip6_properties_to_save[i],
@ -6832,7 +6832,7 @@ set_nm_ipv6ll (NMDevice *self, gboolean enable)
if (enable) {
/* Bounce IPv6 to ensure the kernel stops IPv6LL address generation */
value = nm_platform_sysctl_get (NM_PLATFORM_GET,
nm_utils_ip6_property_path (nm_device_get_ip_iface (self), "disable_ipv6"));
NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip6_property_path (nm_device_get_ip_iface (self), "disable_ipv6")));
if (g_strcmp0 (value, "0") == 0)
nm_device_ipv6_sysctl_set (self, "disable_ipv6", "1");
g_free (value);
@ -6898,7 +6898,7 @@ _ip6_privacy_get (NMDevice *self)
* Instead of reading static config files in /etc, just read the current sysctl value.
* This works as NM only writes to "/proc/sys/net/ipv6/conf/IFNAME/use_tempaddr", but leaves
* the "default" entry untouched. */
ip6_privacy = nm_platform_sysctl_get_int32 (NM_PLATFORM_GET, "/proc/sys/net/ipv6/conf/default/use_tempaddr", NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN);
ip6_privacy = nm_platform_sysctl_get_int32 (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv6/conf/default/use_tempaddr"), NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN);
return _ip6_privacy_clamp (ip6_privacy);
}
@ -7406,14 +7406,14 @@ share_init (void)
char **iter;
int errsv;
if (!nm_platform_sysctl_set (NM_PLATFORM_GET, "/proc/sys/net/ipv4/ip_forward", "1")) {
if (!nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv4/ip_forward"), "1")) {
errsv = errno;
nm_log_err (LOGD_SHARING, "share: error enabling IPv4 forwarding: (%d) %s",
errsv, strerror (errsv));
return FALSE;
}
if (!nm_platform_sysctl_set (NM_PLATFORM_GET, "/proc/sys/net/ipv4/ip_dynaddr", "1")) {
if (!nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv4/ip_dynaddr"), "1")) {
errsv = errno;
nm_log_err (LOGD_SHARING, "share: error enabling dynamic addresses: (%d) %s",
errsv, strerror (errsv));
@ -7754,7 +7754,7 @@ activate_stage5_ip6_config_commit (NMDevice *self)
method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG);
if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_SHARED) == 0) {
if (!nm_platform_sysctl_set (NM_PLATFORM_GET, "/proc/sys/net/ipv6/conf/all/forwarding", "1")) {
if (!nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv6/conf/all/forwarding"), "1")) {
errsv = errno;
_LOGE (LOGD_SHARING, "share: error enabling IPv6 forwarding: (%d) %s", errsv, strerror (errsv));
nm_device_ip_method_failed (self, AF_INET6, NM_DEVICE_STATE_REASON_SHARED_START_FAILED);

View file

@ -350,7 +350,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;
@ -358,7 +358,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);

View file

@ -497,18 +497,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 | O_CLOEXEC);
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

View file

@ -719,7 +719,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,
@ -1594,7 +1594,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);

View file

@ -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;
}

View file

@ -521,7 +521,7 @@ static inline int
ipv6_sysctl_get (NMPlatform *platform, const char *ifname, const char *property, int min, int max, int defval)
{
return (int) nm_platform_sysctl_get_int_checked (platform,
nm_utils_ip6_property_path (ifname, property),
NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip6_property_path (ifname, property)),
10,
min,
max,

View file

@ -2802,6 +2802,246 @@ nm_utils_fd_read_loop_exact (int fd, void *buf, size_t nbytes, bool do_poll)
return 0;
}
_nm_printf (3, 4)
static int
_get_contents_error (GError **error, int errsv, const char *format, ...)
{
if (errsv < 0)
errsv = -errsv;
else if (!errsv)
errsv = errno;
if (error) {
char *msg;
va_list args;
va_start (args, format);
msg = g_strdup_vprintf (format, args);
va_end (args);
g_set_error (error,
G_FILE_ERROR,
g_file_error_from_errno (errsv),
"%s: %s",
msg, g_strerror (errsv));
g_free (msg);
}
return -errsv;
}
/**
* nm_utils_fd_get_contents:
* @fd: open file descriptor to read. The fd will not be closed,
* but don't rely on it's state afterwards.
* @max_length: allocate at most @max_length bytes. If the
* file is larger, reading will fail. Set to zero to use
* a very large default.
*
* WARNING: @max_length is here to avoid a crash for huge/unlimited files.
* For example, stat(/sys/class/net/enp0s25/ifindex) gives a filesize of
* 4K, although the actual real is small. @max_length is the memory
* allocated in the process of reading the file, thus it must be at least
* the size reported by fstat.
* If you set it to 1K, read will fail because fstat() claims the
* file is larger.
*
* @contents: the output buffer with the file read. It is always
* NUL terminated. The buffer is at most @max_length long, including
* the NUL byte. That is, it reads only files up to a length of
* @max_length - 1 bytes.
* @length: optional output argument of the read file size.
*
* A reimplementation of g_file_get_contents() with a few differences:
* - accepts an open fd, instead of a path name. This allows you to
* use openat().
* - limits the maxium filesize to max_length.
*
* Returns: a negative error code on failure.
*/
int
nm_utils_fd_get_contents (int fd,
gsize max_length,
char **contents,
gsize *length,
GError **error)
{
struct stat stat_buf;
gs_free char *str = NULL;
g_return_val_if_fail (fd >= 0, -EINVAL);
g_return_val_if_fail (contents, -EINVAL);
g_return_val_if_fail (!error || !*error, -EINVAL);
if (fstat (fd, &stat_buf) < 0)
return _get_contents_error (error, 0, "failure during fstat");
if (!max_length) {
/* default to a very large size, but not extreme */
max_length = 2 * 1024 * 1024;
}
if ( stat_buf.st_size > 0
&& S_ISREG (stat_buf.st_mode)) {
const gsize n_stat = stat_buf.st_size;
ssize_t n_read;
if (n_stat > max_length - 1)
return _get_contents_error (error, EMSGSIZE, "file too large (%zu+1 bytes with maximum %zu bytes)", n_stat, max_length);
str = g_try_malloc (n_stat + 1);
if (!str)
return _get_contents_error (error, ENOMEM, "failure to allocate buffer of %zu+1 bytes", n_stat);
n_read = nm_utils_fd_read_loop (fd, str, n_stat, TRUE);
if (n_read < 0)
return _get_contents_error (error, n_read, "error reading %zu bytes from file descriptor", n_stat);
str[n_read] = '\0';
if (n_read < n_stat) {
char *tmp;
tmp = g_try_realloc (str, n_read + 1);
if (!tmp)
return _get_contents_error (error, ENOMEM, "failure to reallocate buffer with %zu bytes", n_read + 1);
str = tmp;
}
NM_SET_OUT (length, n_read);
} else {
nm_auto_fclose FILE *f = NULL;
char buf[4096];
gsize n_have, n_alloc;
if (!(f = fdopen (fd, "r")))
return _get_contents_error (error, 0, "failure during fdopen");
n_have = 0;
n_alloc = 0;
while (!feof (f)) {
int errsv;
gsize n_read;
n_read = fread (buf, 1, sizeof (buf), f);
errsv = errno;
if (ferror (f))
return _get_contents_error (error, errsv, "error during fread");
if ( n_have > G_MAXSIZE - 1 - n_read
|| n_have + n_read + 1 > max_length) {
return _get_contents_error (error, EMSGSIZE, "file stream too large (%zu+1 bytes with maximum %zu bytes)",
(n_have > G_MAXSIZE - 1 - n_read) ? G_MAXSIZE : n_have + n_read,
max_length);
}
if (n_have + n_read + 1 >= n_alloc) {
char *tmp;
if (str) {
if (n_alloc >= max_length / 2)
n_alloc = max_length;
else
n_alloc *= 2;
} else
n_alloc = NM_MIN (n_read + 1, sizeof (buf));
tmp = g_try_realloc (str, n_alloc);
if (!tmp)
return _get_contents_error (error, ENOMEM, "failure to allocate buffer of %zu bytes", n_alloc);
str = tmp;
}
memcpy (str + n_have, buf, n_read);
n_have += n_read;
}
if (n_alloc == 0)
str = g_new0 (gchar, 1);
else {
str[n_have] = '\0';
if (n_have + 1 < n_alloc) {
char *tmp;
tmp = g_try_realloc (str, n_have + 1);
if (!tmp)
return _get_contents_error (error, ENOMEM, "failure to truncate buffer to %zu bytes", n_have + 1);
str = tmp;
}
}
NM_SET_OUT (length, n_have);
}
*contents = g_steal_pointer (&str);
return 0;
}
/**
* nm_utils_file_get_contents:
* @dirfd: optional file descriptor to use openat(). If negative, use plain open().
* @filename: the filename to open. Possibly relative to @dirfd.
* @max_length: allocate at most @max_length bytes.
* WARNING: see nm_utils_fd_get_contents() hint about @max_length.
* @contents: the output buffer with the file read. It is always
* NUL terminated. The buffer is at most @max_length long, including
* the NUL byte. That is, it reads only files up to a length of
* @max_length - 1 bytes.
* @length: optional output argument of the read file size.
*
* A reimplementation of g_file_get_contents() with a few differences:
* - accepts an @dirfd to open @filename relative to that path via openat().
* - limits the maxium filesize to max_length.
* - uses O_CLOEXEC on internal file descriptor
*
* Returns: a negative error code on failure.
*/
int
nm_utils_file_get_contents (int dirfd,
const char *filename,
gsize max_length,
char **contents,
gsize *length,
GError **error)
{
nm_auto_close int fd = -1;
int errsv;
g_return_val_if_fail (filename && filename[0], -EINVAL);
if (dirfd >= 0) {
fd = openat (dirfd, filename, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
errsv = errno;
g_set_error (error,
G_FILE_ERROR,
g_file_error_from_errno (errsv),
"Failed to open file \"%s\" with openat: %s",
filename,
g_strerror (errsv));
return -errsv;
}
} else {
fd = open (filename, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
errsv = errno;
g_set_error (error,
G_FILE_ERROR,
g_file_error_from_errno (errsv),
"Failed to open file \"%s\": %s",
filename,
g_strerror (errsv));
return -errsv;
}
}
return nm_utils_fd_get_contents (fd,
max_length,
contents,
length,
error);
}
/*****************************************************************************/
/* taken from systemd's dev_urandom(). */
int
nm_utils_read_urandom (void *p, size_t nbytes)
@ -2810,7 +3050,7 @@ nm_utils_read_urandom (void *p, size_t nbytes)
int r;
again:
fd = open ("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
fd = open ("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOCTTY);
if (fd < 0) {
r = errno;
if (r == EINTR)

View file

@ -313,6 +313,25 @@ 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_fd_get_contents (int fd,
gsize max_length,
char **contents,
gsize *length,
GError **error);
int nm_utils_file_get_contents (int dirfd,
const char *filename,
gsize max_length,
char **contents,
gsize *length,
GError **error);
gboolean nm_utils_file_set_contents (const gchar *filename,
const gchar *contents,
gssize length,
mode_t mode,
GError **error);
int nm_utils_read_urandom (void *p, size_t n);
char *nm_utils_machine_id_read (void);
@ -445,12 +464,6 @@ const char *nm_utils_dnsmasq_status_to_string (int status, char *dest, gsize siz
void nm_utils_get_reverse_dns_domains_ip4 (guint32 ip, guint8 plen, GPtrArray *domains);
void nm_utils_get_reverse_dns_domains_ip6 (const struct in6_addr *ip, guint8 plen, GPtrArray *domains);
gboolean nm_utils_file_set_contents (const gchar *filename,
const gchar *contents,
gssize length,
mode_t mode,
GError **error);
struct stat;
gboolean nm_utils_validate_plugin (const char *path, struct stat *stat, GError **error);

View file

@ -246,7 +246,7 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in
char val[16];
g_snprintf (val, sizeof (val), "%d", rdata->mtu);
nm_platform_sysctl_set (NM_PLATFORM_GET, nm_utils_ip6_property_path (global_opt.ifname, "mtu"), val);
nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip6_property_path (global_opt.ifname, "mtu")), val);
}
nm_ip6_config_merge (existing, ndisc_config, NM_IP_CONFIG_MERGE_DEFAULT);
@ -465,7 +465,7 @@ main (int argc, char *argv[])
}
if (global_opt.dhcp4_address) {
nm_platform_sysctl_set (NM_PLATFORM_GET, nm_utils_ip4_property_path (global_opt.ifname, "promote_secondaries"), "1");
nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip4_property_path (global_opt.ifname, "promote_secondaries")), "1");
dhcp4_client = nm_dhcp_manager_start_ip4 (nm_dhcp_manager_get (),
global_opt.ifname,
@ -512,10 +512,10 @@ main (int argc, char *argv[])
if (iid)
nm_ndisc_set_iid (ndisc, *iid);
nm_platform_sysctl_set (NM_PLATFORM_GET, nm_utils_ip6_property_path (global_opt.ifname, "accept_ra"), "1");
nm_platform_sysctl_set (NM_PLATFORM_GET, nm_utils_ip6_property_path (global_opt.ifname, "accept_ra_defrtr"), "0");
nm_platform_sysctl_set (NM_PLATFORM_GET, nm_utils_ip6_property_path (global_opt.ifname, "accept_ra_pinfo"), "0");
nm_platform_sysctl_set (NM_PLATFORM_GET, nm_utils_ip6_property_path (global_opt.ifname, "accept_ra_rtr_pref"), "0");
nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip6_property_path (global_opt.ifname, "accept_ra")), "1");
nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip6_property_path (global_opt.ifname, "accept_ra_defrtr")), "0");
nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip6_property_path (global_opt.ifname, "accept_ra_pinfo")), "0");
nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip6_property_path (global_opt.ifname, "accept_ra_rtr_pref")), "0");
g_signal_connect (NM_PLATFORM_GET,
NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED,

View file

@ -599,6 +599,7 @@ _nm_log_impl (const char *file,
va_list args;
char *msg;
GTimeVal tv;
int errno_saved;
if ((guint) level >= G_N_ELEMENTS (_nm_logging_enabled_state))
g_return_if_reached ();
@ -606,6 +607,8 @@ _nm_log_impl (const char *file,
if (!(_nm_logging_enabled_state[level] & domain))
return;
errno_saved = errno;
/* Make sure that %m maps to the specified error */
if (error != 0) {
if (error < 0)
@ -719,6 +722,8 @@ _nm_log_impl (const char *file,
}
g_free (msg);
errno = errno_saved;
}
/*****************************************************************************/

View file

@ -5450,7 +5450,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);

View file

@ -118,21 +118,43 @@ _ip4_address_equal_peer_net (in_addr_t peer1, in_addr_t peer2, guint8 plen)
/*****************************************************************************/
#define ASSERT_SYSCTL_ARGS(pathid, dirfd, path) \
G_STMT_START { \
const char *const _pathid = (pathid); \
const int _dirfd = (dirfd); \
const char *const _path = (path); \
\
g_assert (_path && _path[0]); \
g_assert (!strstr (_path, "/../")); \
if (_dirfd < 0) { \
g_assert (!_pathid); \
g_assert (_path[0] == '/'); \
g_assert ( g_str_has_prefix (_path, "/proc/sys/") \
|| g_str_has_prefix (_path, "/sys/")); \
} else { \
g_assert_not_reached (); \
} \
} G_STMT_END
static gboolean
sysctl_set (NMPlatform *platform, const char *path, const char *value)
sysctl_set (NMPlatform *platform, const char *pathid, int dirfd, const char *path, const char *value)
{
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
ASSERT_SYSCTL_ARGS (pathid, dirfd, path);
g_hash_table_insert (priv->options, g_strdup (path), g_strdup (value));
return TRUE;
}
static char *
sysctl_get (NMPlatform *platform, const char *path)
sysctl_get (NMPlatform *platform, const char *pathid, int dirfd, const char *path)
{
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
ASSERT_SYSCTL_ARGS (pathid, dirfd, path);
return g_strdup (g_hash_table_lookup (priv->options, path));
}

View file

@ -239,7 +239,7 @@ static void do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActi
static void cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMPCacheOpsType ops_type, gpointer user_data);
static void cache_prune_candidates_prune (NMPlatform *platform);
static gboolean event_handler_read_netlink (NMPlatform *platform, gboolean wait_for_acks);
static void _assert_netns_current (NMPlatform *platform);
static void ASSERT_NETNS_CURRENT (NMPlatform *platform);
/*****************************************************************************/
@ -573,18 +573,14 @@ _lookup_cached_link (const NMPCache *cache, int ifindex, gboolean *completed_fro
#define DEVTYPE_PREFIX "DEVTYPE="
static char *
_linktype_read_devtype (const char *ifname)
_linktype_read_devtype (int dirfd)
{
char uevent[NM_STRLEN ("/sys/class/net/123456789012345/uevent\0") + 100 /*safety*/];
char *contents = NULL;
char *cont, *end;
nm_sprintf_buf (uevent,
"/sys/class/net/%s/uevent",
NM_ASSERT_VALID_PATH_COMPONENT (ifname));
nm_assert (strlen (uevent) < sizeof (uevent) - 1);
nm_assert (dirfd >= 0);
if (!g_file_get_contents (uevent, &contents, NULL, NULL))
if (nm_utils_file_get_contents (dirfd, "uevent", 1*1024*1024, &contents, NULL, NULL) < 0)
return NULL;
for (cont = contents; cont; cont = end) {
end = strpbrk (cont, "\r\n");
@ -614,7 +610,8 @@ _linktype_get_type (NMPlatform *platform,
{
guint i;
_assert_netns_current (platform);
ASSERT_NETNS_CURRENT (platform);
nm_assert (ifname);
if (completed_from_cache) {
const NMPObject *obj;
@ -635,7 +632,7 @@ _linktype_get_type (NMPlatform *platform,
* of messing stuff up. */
if ( obj
&& !NM_IN_SET (obj->link.type, NM_LINK_TYPE_UNKNOWN, NM_LINK_TYPE_NONE)
&& !g_strcmp0 (ifname, obj->link.name)
&& nm_streq (ifname, obj->link.name)
&& ( !kind
|| !g_strcmp0 (kind, obj->link.kind))) {
nm_assert (obj->link.kind == g_intern_string (obj->link.kind));
@ -656,7 +653,7 @@ _linktype_get_type (NMPlatform *platform,
NMPlatformTunProperties props;
if ( platform
&& nm_platform_link_tun_get_properties_ifname (platform, ifname, &props)) {
&& nm_platform_link_tun_get_properties (platform, ifindex, ifname, &props)) {
if (!g_strcmp0 (props.mode, "tap"))
return NM_LINK_TYPE_TAP;
if (!g_strcmp0 (props.mode, "tun"))
@ -679,50 +676,52 @@ _linktype_get_type (NMPlatform *platform,
else if (arptype == ARPHRD_TUNNEL6)
return NM_LINK_TYPE_IP6TNL;
if (ifname) {
char anycast_mask[NM_STRLEN ("/sys/class/net/123456789012345/anycast_mask\0") + 100 /*safety*/];
gs_free char *driver = NULL;
gs_free char *devtype = NULL;
{
NMPUtilsEthtoolDriverInfo driver_info;
/* Fallback OVS detection for kernel <= 3.16 */
if (nmp_utils_ethtool_get_driver_info (ifname, &driver, NULL, NULL)) {
if (!g_strcmp0 (driver, "openvswitch"))
if (nmp_utils_ethtool_get_driver_info (ifindex, &driver_info)) {
if (nm_streq (driver_info.driver, "openvswitch"))
return NM_LINK_TYPE_OPENVSWITCH;
if (arptype == 256) {
/* Some s390 CTC-type devices report 256 for the encapsulation type
* for some reason, but we need to call them Ethernet.
*/
if (!g_strcmp0 (driver, "ctcm"))
if (nm_streq (driver_info.driver, "ctcm"))
return NM_LINK_TYPE_ETHERNET;
}
}
}
nm_sprintf_buf (anycast_mask,
"/sys/class/net/%s/anycast_mask",
NM_ASSERT_VALID_PATH_COMPONENT (ifname));
nm_assert (strlen (anycast_mask) < sizeof (anycast_mask) - 1);
{
nm_auto_close int dirfd = -1;
gs_free char *devtype = NULL;
char ifname_verified[IFNAMSIZ];
if (g_file_test (anycast_mask, G_FILE_TEST_EXISTS))
return NM_LINK_TYPE_OLPC_MESH;
dirfd = nmp_utils_sysctl_open_netdir (ifindex, ifname, ifname_verified);
if (dirfd >= 0) {
if (faccessat (dirfd, "anycast_mask", F_OK, 0) == 0)
return NM_LINK_TYPE_OLPC_MESH;
devtype = _linktype_read_devtype (ifname);
for (i = 0; devtype && i < G_N_ELEMENTS (linktypes); i++) {
if (g_strcmp0 (devtype, linktypes[i].devtype) == 0) {
if (linktypes[i].nm_type == NM_LINK_TYPE_BNEP) {
/* Both BNEP and 6lowpan use DEVTYPE=bluetooth, so we must
* use arptype to distinguish between them.
*/
if (arptype != ARPHRD_ETHER)
continue;
devtype = _linktype_read_devtype (dirfd);
for (i = 0; devtype && i < G_N_ELEMENTS (linktypes); i++) {
if (g_strcmp0 (devtype, linktypes[i].devtype) == 0) {
if (linktypes[i].nm_type == NM_LINK_TYPE_BNEP) {
/* Both BNEP and 6lowpan use DEVTYPE=bluetooth, so we must
* use arptype to distinguish between them.
*/
if (arptype != ARPHRD_ETHER)
continue;
}
return linktypes[i].nm_type;
}
return linktypes[i].nm_type;
}
}
/* Fallback for drivers that don't call SET_NETDEV_DEVTYPE() */
if (wifi_utils_is_wifi (ifname))
return NM_LINK_TYPE_WIFI;
/* Fallback for drivers that don't call SET_NETDEV_DEVTYPE() */
if (wifi_utils_is_wifi (dirfd, ifname_verified))
return NM_LINK_TYPE_WIFI;
}
if (arptype == ARPHRD_ETHER) {
/* Misc non-upstream WWAN drivers. rmnet is Qualcomm's proprietary
@ -2481,50 +2480,66 @@ nm_linux_platform_setup (void)
NULL);
}
/*****************************************************************************/
static void
_assert_netns_current (NMPlatform *platform)
ASSERT_NETNS_CURRENT (NMPlatform *platform)
{
#if NM_MORE_ASSERTS
nm_assert (NM_IS_LINUX_PLATFORM (platform));
nm_assert (NM_IN_SET (nm_platform_netns_get (platform), NULL, nmp_netns_get_current ()));
#endif
}
/*****************************************************************************/
#define ASSERT_SYSCTL_ARGS(pathid, dirfd, path) \
G_STMT_START { \
const char *const _pathid = (pathid); \
const int _dirfd = (dirfd); \
const char *const _path = (path); \
\
nm_assert (_path && _path[0]); \
g_assert (!strstr (_path, "/../")); \
if (_dirfd < 0) { \
nm_assert (!_pathid); \
nm_assert (_path[0] == '/'); \
nm_assert ( g_str_has_prefix (_path, "/proc/sys/") \
|| g_str_has_prefix (_path, "/sys/")); \
} else { \
nm_assert (_pathid && _pathid[0] && _pathid[0] != '/'); \
nm_assert (_path[0] != '/'); \
} \
} G_STMT_END
static void
_log_dbg_sysctl_set_impl (NMPlatform *platform, const char *path, const char *value)
_log_dbg_sysctl_set_impl (NMPlatform *platform, const char *pathid, int dirfd, const char *path, const char *value)
{
GError *error = NULL;
char *contents, *contents_escaped;
char *value_escaped = g_strescape (value, NULL);
if (!g_file_get_contents (path, &contents, NULL, &error)) {
_LOGD ("sysctl: setting '%s' to '%s' (current value cannot be read: %s)", path, value_escaped, error->message);
if (nm_utils_file_get_contents (dirfd, path, 1*1024*1024, &contents, NULL, &error) < 0) {
_LOGD ("sysctl: setting '%s' to '%s' (current value cannot be read: %s)", pathid, value_escaped, error->message);
g_clear_error (&error);
} else {
g_strstrip (contents);
contents_escaped = g_strescape (contents, NULL);
if (strcmp (contents, value) == 0)
_LOGD ("sysctl: setting '%s' to '%s' (current value is identical)", path, value_escaped);
_LOGD ("sysctl: setting '%s' to '%s' (current value is identical)", pathid, value_escaped);
else
_LOGD ("sysctl: setting '%s' to '%s' (current value is '%s')", path, value_escaped, contents_escaped);
_LOGD ("sysctl: setting '%s' to '%s' (current value is '%s')", pathid, value_escaped, contents_escaped);
g_free (contents);
g_free (contents_escaped);
}
g_free (value_escaped);
}
#define _log_dbg_sysctl_set(platform, path, value) \
#define _log_dbg_sysctl_set(platform, pathid, dirfd, path, value) \
G_STMT_START { \
if (_LOGD_ENABLED ()) { \
_log_dbg_sysctl_set_impl (platform, path, value); \
_log_dbg_sysctl_set_impl (platform, pathid, dirfd, path, value); \
} \
} G_STMT_END
static gboolean
sysctl_set (NMPlatform *platform, const char *path, const char *value)
sysctl_set (NMPlatform *platform, const char *pathid, int dirfd, const char *path, const char *value)
{
nm_auto_pop_netns NMPNetns *netns = NULL;
int fd, tries;
@ -2537,32 +2552,46 @@ sysctl_set (NMPlatform *platform, const char *path, const char *value)
g_return_val_if_fail (path != NULL, FALSE);
g_return_val_if_fail (value != NULL, FALSE);
/* Don't write outside known locations */
g_assert (g_str_has_prefix (path, "/proc/sys/")
|| g_str_has_prefix (path, "/sys/"));
/* Don't write to suspicious locations */
g_assert (!strstr (path, "/../"));
ASSERT_SYSCTL_ARGS (pathid, dirfd, path);
if (!nm_platform_netns_push (platform, &netns)) {
errno = ENETDOWN;
return FALSE;
}
fd = open (path, O_WRONLY | O_TRUNC);
if (fd == -1) {
errsv = errno;
if (errsv == ENOENT) {
_LOGD ("sysctl: failed to open '%s': (%d) %s",
path, errsv, strerror (errsv));
} else {
_LOGE ("sysctl: failed to open '%s': (%d) %s",
path, errsv, strerror (errsv));
if (dirfd < 0) {
if (!nm_platform_netns_push (platform, &netns)) {
errno = ENETDOWN;
return FALSE;
}
pathid = path;
fd = open (path, O_WRONLY | O_TRUNC | O_CLOEXEC);
if (fd == -1) {
errsv = errno;
if (errsv == ENOENT) {
_LOGD ("sysctl: failed to open '%s': (%d) %s",
pathid, errsv, strerror (errsv));
} else {
_LOGE ("sysctl: failed to open '%s': (%d) %s",
pathid, errsv, strerror (errsv));
}
errno = errsv;
return FALSE;
}
} else {
fd = openat (dirfd, path, O_WRONLY | O_TRUNC | O_CLOEXEC);
if (fd == -1) {
errsv = errno;
if (errsv == ENOENT) {
_LOGD ("sysctl: failed to openat '%s': (%d) %s",
pathid, errsv, strerror (errsv));
} else {
_LOGE ("sysctl: failed to openat '%s': (%d) %s",
pathid, errsv, strerror (errsv));
}
errno = errsv;
return FALSE;
}
errno = errsv;
return FALSE;
}
_log_dbg_sysctl_set (platform, path, value);
_log_dbg_sysctl_set (platform, pathid, dirfd, path, value);
/* Most sysfs and sysctl options don't care about a trailing LF, while some
* (like infiniband) do. So always add the LF. Also, neither sysfs nor
@ -2635,7 +2664,7 @@ _nm_logging_clear_platform_logging_cache_impl (void)
}
static void
_log_dbg_sysctl_get_impl (NMPlatform *platform, const char *path, const char *contents)
_log_dbg_sysctl_get_impl (NMPlatform *platform, const char *pathid, const char *contents)
{
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
const char *prev_value = NULL;
@ -2645,24 +2674,24 @@ _log_dbg_sysctl_get_impl (NMPlatform *platform, const char *path, const char *co
sysctl_clear_cache_list = g_slist_prepend (sysctl_clear_cache_list, platform);
priv->sysctl_get_prev_values = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
} else
prev_value = g_hash_table_lookup (priv->sysctl_get_prev_values, path);
prev_value = g_hash_table_lookup (priv->sysctl_get_prev_values, pathid);
if (prev_value) {
if (strcmp (prev_value, contents) != 0) {
char *contents_escaped = g_strescape (contents, NULL);
char *prev_value_escaped = g_strescape (prev_value, NULL);
_LOGD ("sysctl: reading '%s': '%s' (changed from '%s' on last read)", path, contents_escaped, prev_value_escaped);
_LOGD ("sysctl: reading '%s': '%s' (changed from '%s' on last read)", pathid, contents_escaped, prev_value_escaped);
g_free (contents_escaped);
g_free (prev_value_escaped);
g_hash_table_insert (priv->sysctl_get_prev_values, g_strdup (path), g_strdup (contents));
g_hash_table_insert (priv->sysctl_get_prev_values, g_strdup (pathid), g_strdup (contents));
}
} else {
char *contents_escaped = g_strescape (contents, NULL);
_LOGD ("sysctl: reading '%s': '%s'", path, contents_escaped);
_LOGD ("sysctl: reading '%s': '%s'", pathid, contents_escaped);
g_free (contents_escaped);
g_hash_table_insert (priv->sysctl_get_prev_values, g_strdup (path), g_strdup (contents));
g_hash_table_insert (priv->sysctl_get_prev_values, g_strdup (pathid), g_strdup (contents));
}
if ( !priv->sysctl_get_warned
@ -2672,43 +2701,42 @@ _log_dbg_sysctl_get_impl (NMPlatform *platform, const char *path, const char *co
}
}
#define _log_dbg_sysctl_get(platform, path, contents) \
#define _log_dbg_sysctl_get(platform, pathid, contents) \
G_STMT_START { \
if (_LOGD_ENABLED ()) \
_log_dbg_sysctl_get_impl (platform, path, contents); \
_log_dbg_sysctl_get_impl (platform, pathid, contents); \
} G_STMT_END
static char *
sysctl_get (NMPlatform *platform, const char *path)
sysctl_get (NMPlatform *platform, const char *pathid, int dirfd, const char *path)
{
nm_auto_pop_netns NMPNetns *netns = NULL;
GError *error = NULL;
char *contents;
/* Don't write outside known locations */
g_assert (g_str_has_prefix (path, "/proc/sys/")
|| g_str_has_prefix (path, "/sys/"));
/* Don't write to suspicious locations */
g_assert (!strstr (path, "/../"));
ASSERT_SYSCTL_ARGS (pathid, dirfd, path);
if (!nm_platform_netns_push (platform, &netns))
return NULL;
if (dirfd < 0) {
if (!nm_platform_netns_push (platform, &netns))
return NULL;
pathid = path;
}
if (!g_file_get_contents (path, &contents, NULL, &error)) {
if (nm_utils_file_get_contents (dirfd, path, 1*1024*1024, &contents, NULL, &error) < 0) {
/* We assume FAILED means EOPNOTSUP */
if ( g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)
|| g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NODEV)
|| g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_FAILED))
_LOGD ("error reading %s: %s", path, error->message);
_LOGD ("error reading %s: %s", pathid, error->message);
else
_LOGE ("error reading %s: %s", path, error->message);
_LOGE ("error reading %s: %s", pathid, error->message);
g_clear_error (&error);
return NULL;
}
g_strstrip (contents);
_log_dbg_sysctl_get (platform, path, contents);
_log_dbg_sysctl_get (platform, pathid, contents);
return contents;
}
@ -2763,8 +2791,7 @@ do_emit_signal (NMPlatform *platform, const NMPObject *obj, NMPCacheOpsType cach
nm_assert (!obj || cache_op == NMP_CACHE_OPS_REMOVED || obj == nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, obj));
nm_assert (!obj || cache_op != NMP_CACHE_OPS_REMOVED || obj != nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, obj));
/* we raise the signals inside the namespace of the NMPlatform instance. */
_assert_netns_current (platform);
ASSERT_NETNS_CURRENT (platform);
switch (cache_op) {
case NMP_CACHE_OPS_ADDED:
@ -4428,10 +4455,6 @@ static gboolean
link_supports_carrier_detect (NMPlatform *platform, int ifindex)
{
nm_auto_pop_netns NMPNetns *netns = NULL;
const char *name = nm_platform_link_get_name (platform, ifindex);
if (!name)
return FALSE;
if (!nm_platform_netns_push (platform, &netns))
return FALSE;
@ -4440,7 +4463,7 @@ link_supports_carrier_detect (NMPlatform *platform, int ifindex)
* us whether the device actually supports carrier detection in the first
* place. We assume any device that does implements one of these two APIs.
*/
return nmp_utils_ethtool_supports_carrier_detect (name) || nmp_utils_mii_supports_carrier_detect (name);
return nmp_utils_ethtool_supports_carrier_detect (ifindex) || nmp_utils_mii_supports_carrier_detect (ifindex);
}
static gboolean
@ -4458,7 +4481,7 @@ link_supports_vlans (NMPlatform *platform, int ifindex)
if (!nm_platform_netns_push (platform, &netns))
return FALSE;
return nmp_utils_ethtool_supports_vlans (obj->link.name);
return nmp_utils_ethtool_supports_vlans (ifindex);
}
static NMPlatformError
@ -4526,7 +4549,7 @@ link_get_permanent_address (NMPlatform *platform,
if (!nm_platform_netns_push (platform, &netns))
return FALSE;
return nmp_utils_ethtool_get_permanent_address (nm_platform_link_get_name (platform, ifindex), buf, length);
return nmp_utils_ethtool_get_permanent_address (ifindex, buf, length);
}
static gboolean
@ -4555,44 +4578,27 @@ nla_put_failure:
static char *
link_get_physical_port_id (NMPlatform *platform, int ifindex)
{
const char *ifname;
char *path, *id;
nm_auto_close int dirfd = -1;
char ifname_verified[IFNAMSIZ];
ifname = nm_platform_link_get_name (platform, ifindex);
if (!ifname)
dirfd = nm_platform_sysctl_open_netdir (platform, ifindex, ifname_verified);
if (dirfd < 0)
return NULL;
ifname = NM_ASSERT_VALID_PATH_COMPONENT (ifname);
path = g_strdup_printf ("/sys/class/net/%s/phys_port_id", ifname);
id = sysctl_get (platform, path);
g_free (path);
return id;
return sysctl_get (platform, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname_verified, "phys_port_id"));
}
static guint
link_get_dev_id (NMPlatform *platform, int ifindex)
{
const char *ifname;
gs_free char *path = NULL, *id = NULL;
gint64 int_val;
nm_auto_close int dirfd = -1;
char ifname_verified[IFNAMSIZ];
ifname = nm_platform_link_get_name (platform, ifindex);
if (!ifname)
dirfd = nm_platform_sysctl_open_netdir (platform, ifindex, ifname_verified);
if (dirfd < 0)
return 0;
ifname = NM_ASSERT_VALID_PATH_COMPONENT (ifname);
path = g_strdup_printf ("/sys/class/net/%s/dev_id", ifname);
id = sysctl_get (platform, path);
if (!id || !*id)
return 0;
/* Value is reported as hex */
int_val = _nm_utils_ascii_str_to_int64 (id, 16, 0, G_MAXUINT16, 0);
return errno ? 0 : (int) int_val;
return nm_platform_sysctl_get_int_checked (platform,
NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname_verified, "dev_id"),
16, 0, G_MAXUINT16, 0);
}
static int
@ -5161,7 +5167,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;
@ -5250,9 +5256,9 @@ _infiniband_partition_action (NMPlatform *platform,
const NMPlatformLink **out_link)
{
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
const NMPObject *obj_parent;
nm_auto_close int dirfd = -1;
char ifname_parent[IFNAMSIZ];
const NMPObject *obj;
char path[NM_STRLEN ("/sys/class/net/%s/%s") + IFNAMSIZ + 100];
char id[20];
char name[IFNAMSIZ];
gboolean success;
@ -5260,20 +5266,18 @@ _infiniband_partition_action (NMPlatform *platform,
nm_assert (NM_IN_SET (action, INFINIBAND_ACTION_CREATE_CHILD, INFINIBAND_ACTION_DELETE_CHILD));
nm_assert (p_key > 0 && p_key <= 0xffff && p_key != 0x8000);
obj_parent = nmp_cache_lookup_link (priv->cache, parent);
if (!obj_parent || !obj_parent->link.name[0]) {
dirfd = nm_platform_sysctl_open_netdir (platform, parent, ifname_parent);
if (dirfd < 0) {
errno = ENOENT;
return FALSE;
}
nm_sprintf_buf (path,
"/sys/class/net/%s/%s",
NM_ASSERT_VALID_PATH_COMPONENT (obj_parent->link.name),
(action == INFINIBAND_ACTION_CREATE_CHILD
? "create_child"
: "delete_child"));
nm_sprintf_buf (id, "0x%04x", p_key);
success = nm_platform_sysctl_set (platform, path, id);
if (action == INFINIBAND_ACTION_CREATE_CHILD)
success = nm_platform_sysctl_set (platform, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname_parent, "create_child"), id);
else
success = nm_platform_sysctl_set (platform, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname_parent, "delete_child"), id);
if (!success) {
if ( action == INFINIBAND_ACTION_DELETE_CHILD
&& errno == ENODEV)
@ -5281,7 +5285,7 @@ _infiniband_partition_action (NMPlatform *platform,
return FALSE;
}
nm_utils_new_infiniband_name (name, obj_parent->link.name, p_key);
nm_utils_new_infiniband_name (name, ifname_parent, p_key);
do_request_link (platform, 0, name);
if (action == INFINIBAND_ACTION_DELETE_CHILD)
@ -5515,7 +5519,7 @@ link_get_wake_on_lan (NMPlatform *platform, int ifindex)
return FALSE;
if (type == NM_LINK_TYPE_ETHERNET)
return nmp_utils_ethtool_get_wake_on_lan (nm_platform_link_get_name (platform, ifindex));
return nmp_utils_ethtool_get_wake_on_lan (ifindex);
else if (type == NM_LINK_TYPE_WIFI) {
WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex);
@ -5535,14 +5539,17 @@ link_get_driver_info (NMPlatform *platform,
char **out_fw_version)
{
nm_auto_pop_netns NMPNetns *netns = NULL;
NMPUtilsEthtoolDriverInfo driver_info;
if (!nm_platform_netns_push (platform, &netns))
return FALSE;
return nmp_utils_ethtool_get_driver_info (nm_platform_link_get_name (platform, ifindex),
out_driver_name,
out_driver_version,
out_fw_version);
if (!nmp_utils_ethtool_get_driver_info (ifindex, &driver_info))
return FALSE;
NM_SET_OUT (out_driver_name, g_strdup (driver_info.driver));
NM_SET_OUT (out_driver_version, g_strdup (driver_info.version));
NM_SET_OUT (out_fw_version, g_strdup (driver_info.fw_version));
return TRUE;
}
/*****************************************************************************/

View file

@ -31,15 +31,39 @@
#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
******************************************************************/
NM_UTILS_ENUM2STR_DEFINE_STATIC (_ethtool_cmd_to_string, guint32,
NM_UTILS_ENUM2STR (ETHTOOL_GDRVINFO, "ETHTOOL_GDRVINFO"),
NM_UTILS_ENUM2STR (ETHTOOL_GFEATURES, "ETHTOOL_GFEATURES"),
NM_UTILS_ENUM2STR (ETHTOOL_GLINK, "ETHTOOL_GLINK"),
NM_UTILS_ENUM2STR (ETHTOOL_GPERMADDR, "ETHTOOL_GPERMADDR"),
NM_UTILS_ENUM2STR (ETHTOOL_GSET, "ETHTOOL_GSET"),
NM_UTILS_ENUM2STR (ETHTOOL_GSSET_INFO, "ETHTOOL_GSSET_INFO"),
NM_UTILS_ENUM2STR (ETHTOOL_GSTATS, "ETHTOOL_GSTATS"),
NM_UTILS_ENUM2STR (ETHTOOL_GSTRINGS, "ETHTOOL_GSTRINGS"),
NM_UTILS_ENUM2STR (ETHTOOL_GWOL, "ETHTOOL_GWOL"),
NM_UTILS_ENUM2STR (ETHTOOL_SSET, "ETHTOOL_SSET"),
NM_UTILS_ENUM2STR (ETHTOOL_SWOL, "ETHTOOL_SWOL"),
);
static const char *
_ethtool_data_to_string (gconstpointer edata, char *buf, gsize len)
{
return _ethtool_cmd_to_string (*((guint32 *) edata), buf, len);
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
#define ethtool_cmd_speed(pedata) ((pedata)->speed)
@ -47,55 +71,84 @@
G_STMT_START { (pedata)->speed = (guint16) (speed); } G_STMT_END
#endif
static gboolean
ethtool_get (const char *name, gpointer edata)
ethtool_get (int ifindex, gpointer edata)
{
struct ifreq ifr;
int fd;
char ifname[IFNAMSIZ];
char sbuf[50];
if (!name || !*name)
return FALSE;
nm_assert (ifindex > 0);
if (!nmp_utils_device_exists (name))
return FALSE;
/* ethtool ioctl API uses the ifname to refer to an interface. That is racy
* as interfaces can be renamed *sigh*.
*
* Note that we anyway have to verify whether the interface exists, before
* calling ioctl for a non-existing ifname. This is to prevent autoloading
* of kernel modules *sigh*.
* Thus, as we anyway verify the existence of ifname before doing the call,
* go one step further and lookup the ifname everytime anew.
*
* This does not solve the renaming race, but it minimizes the time for
* the race to happen as much as possible. */
/* nmp_utils_device_exists() already errors out if @name is invalid. */
nm_assert (strlen (name) < IFNAMSIZ);
memset (&ifr, 0, sizeof (ifr));
nm_utils_ifname_cpy (ifr.ifr_name, name);
ifr.ifr_data = edata;
fd = socket (PF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
nm_log_err (LOGD_PLATFORM, "ethtool: Could not open socket.");
if (!if_indextoname (ifindex, ifname)) {
nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: request fails resolving ifindex: %s",
ifindex,
_ethtool_data_to_string (edata, sbuf, sizeof (sbuf)),
g_strerror (errno));
return FALSE;
}
if (ioctl (fd, SIOCETHTOOL, &ifr) < 0) {
nm_log_dbg (LOGD_PLATFORM, "ethtool: Request failed: %s", strerror (errno));
close (fd);
return FALSE;
}
{
nm_auto_close int fd = -1;
struct ifreq ifr = {
.ifr_data = edata,
};
close (fd);
return TRUE;
memcpy (ifr.ifr_name, ifname, sizeof (ifname));
fd = socket (PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (fd < 0) {
nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s, %s: failed creating socket for ioctl: %s",
ifindex,
_ethtool_data_to_string (edata, sbuf, sizeof (sbuf)),
ifname,
g_strerror (errno));
return FALSE;
}
if (ioctl (fd, SIOCETHTOOL, &ifr) < 0) {
nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s, %s: failed: %s",
ifindex,
_ethtool_data_to_string (edata, sbuf, sizeof (sbuf)),
ifname,
strerror (errno));
return FALSE;
}
nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s, %s: success",
ifindex,
_ethtool_data_to_string (edata, sbuf, sizeof (sbuf)),
ifname);
return TRUE;
}
}
static int
ethtool_get_stringset_index (const char *ifname, int stringset_id, const char *string)
ethtool_get_stringset_index (int ifindex, int stringset_id, const char *string)
{
gs_free struct ethtool_sset_info *info = NULL;
gs_free struct ethtool_gstrings *strings = NULL;
guint32 len, i;
g_return_val_if_fail (ifindex > 0, -1);
info = g_malloc0 (sizeof (*info) + sizeof (guint32));
info->cmd = ETHTOOL_GSSET_INFO;
info->reserved = 0;
info->sset_mask = 1ULL << stringset_id;
if (!ethtool_get (ifname, info))
if (!ethtool_get (ifindex, info))
return -1;
if (!info->sset_mask)
return -1;
@ -106,7 +159,7 @@ ethtool_get_stringset_index (const char *ifname, int stringset_id, const char *s
strings->cmd = ETHTOOL_GSTRINGS;
strings->string_set = stringset_id;
strings->len = len;
if (!ethtool_get (ifname, strings))
if (!ethtool_get (ifindex, strings))
return -1;
for (i = 0; i < len; i++) {
@ -118,32 +171,30 @@ ethtool_get_stringset_index (const char *ifname, int stringset_id, const char *s
}
gboolean
nmp_utils_ethtool_get_driver_info (const char *ifname,
char **out_driver_name,
char **out_driver_version,
char **out_fw_version)
nmp_utils_ethtool_get_driver_info (int ifindex,
NMPUtilsEthtoolDriverInfo *data)
{
struct ethtool_drvinfo drvinfo = { 0 };
struct ethtool_drvinfo *drvinfo;
G_STATIC_ASSERT (sizeof (*data) == sizeof (*drvinfo));
G_STATIC_ASSERT (offsetof (NMPUtilsEthtoolDriverInfo, driver) == offsetof (struct ethtool_drvinfo, driver));
G_STATIC_ASSERT (offsetof (NMPUtilsEthtoolDriverInfo, version) == offsetof (struct ethtool_drvinfo, version));
G_STATIC_ASSERT (offsetof (NMPUtilsEthtoolDriverInfo, fw_version) == offsetof (struct ethtool_drvinfo, fw_version));
G_STATIC_ASSERT (sizeof (data->driver) == sizeof (drvinfo->driver));
G_STATIC_ASSERT (sizeof (data->version) == sizeof (drvinfo->version));
G_STATIC_ASSERT (sizeof (data->fw_version) == sizeof (drvinfo->fw_version));
if (!ifname)
return FALSE;
g_return_val_if_fail (ifindex > 0, FALSE);
g_return_val_if_fail (data, FALSE);
drvinfo.cmd = ETHTOOL_GDRVINFO;
if (!ethtool_get (ifname, &drvinfo))
return FALSE;
drvinfo = (struct ethtool_drvinfo *) data;
if (out_driver_name)
*out_driver_name = g_strdup (drvinfo.driver);
if (out_driver_version)
*out_driver_version = g_strdup (drvinfo.version);
if (out_fw_version)
*out_fw_version = g_strdup (drvinfo.fw_version);
return TRUE;
memset (drvinfo, 0, sizeof (*drvinfo));
drvinfo->cmd = ETHTOOL_GDRVINFO;
return ethtool_get (ifindex, drvinfo);
}
gboolean
nmp_utils_ethtool_get_permanent_address (const char *ifname,
nmp_utils_ethtool_get_permanent_address (int ifindex,
guint8 *buf,
size_t *length)
{
@ -153,14 +204,13 @@ nmp_utils_ethtool_get_permanent_address (const char *ifname,
} edata;
guint i;
if (!ifname)
return FALSE;
g_return_val_if_fail (ifindex > 0, FALSE);
memset (&edata, 0, sizeof (edata));
edata.e.cmd = ETHTOOL_GPERMADDR;
edata.e.size = NM_UTILS_HWADDR_LEN_MAX;
if (!ethtool_get (ifname, &edata.e))
if (!ethtool_get (ifindex, &edata.e))
return FALSE;
if (edata.e.size > NM_UTILS_HWADDR_LEN_MAX)
@ -187,29 +237,30 @@ not_all_0or1:
}
gboolean
nmp_utils_ethtool_supports_carrier_detect (const char *ifname)
nmp_utils_ethtool_supports_carrier_detect (int ifindex)
{
struct ethtool_cmd edata = { .cmd = ETHTOOL_GLINK };
g_return_val_if_fail (ifindex > 0, FALSE);
/* We ignore the result. If the ETHTOOL_GLINK call succeeded, then we
* assume the device supports carrier-detect, otherwise we assume it
* doesn't.
*/
return ethtool_get (ifname, &edata);
return ethtool_get (ifindex, &edata);
}
gboolean
nmp_utils_ethtool_supports_vlans (const char *ifname)
nmp_utils_ethtool_supports_vlans (int ifindex)
{
gs_free struct ethtool_gfeatures *features = NULL;
int idx, block, bit, size;
if (!ifname)
return FALSE;
g_return_val_if_fail (ifindex > 0, FALSE);
idx = ethtool_get_stringset_index (ifname, ETH_SS_FEATURES, "vlan-challenged");
idx = ethtool_get_stringset_index (ifindex, ETH_SS_FEATURES, "vlan-challenged");
if (idx == -1) {
nm_log_dbg (LOGD_PLATFORM, "ethtool: vlan-challenged ethtool feature does not exist for %s?", ifname);
nm_log_dbg (LOGD_PLATFORM, "ethtool: vlan-challenged ethtool feature does not exist for %d?", ifindex);
return FALSE;
}
@ -221,54 +272,52 @@ nmp_utils_ethtool_supports_vlans (const char *ifname)
features->cmd = ETHTOOL_GFEATURES;
features->size = size;
if (!ethtool_get (ifname, features))
if (!ethtool_get (ifindex, features))
return FALSE;
return !(features->features[block].active & (1 << bit));
}
int
nmp_utils_ethtool_get_peer_ifindex (const char *ifname)
nmp_utils_ethtool_get_peer_ifindex (int ifindex)
{
gs_free struct ethtool_stats *stats = NULL;
int peer_ifindex_stat;
if (!ifname)
return 0;
g_return_val_if_fail (ifindex > 0, 0);
peer_ifindex_stat = ethtool_get_stringset_index (ifname, ETH_SS_STATS, "peer_ifindex");
peer_ifindex_stat = ethtool_get_stringset_index (ifindex, ETH_SS_STATS, "peer_ifindex");
if (peer_ifindex_stat == -1) {
nm_log_dbg (LOGD_PLATFORM, "ethtool: peer_ifindex stat for %s does not exist?", ifname);
nm_log_dbg (LOGD_PLATFORM, "ethtool: peer_ifindex stat for %d does not exist?", ifindex);
return FALSE;
}
stats = g_malloc0 (sizeof (*stats) + (peer_ifindex_stat + 1) * sizeof (guint64));
stats->cmd = ETHTOOL_GSTATS;
stats->n_stats = peer_ifindex_stat + 1;
if (!ethtool_get (ifname, stats))
if (!ethtool_get (ifindex, stats))
return 0;
return stats->data[peer_ifindex_stat];
}
gboolean
nmp_utils_ethtool_get_wake_on_lan (const char *ifname)
nmp_utils_ethtool_get_wake_on_lan (int ifindex)
{
struct ethtool_wolinfo wol;
if (!ifname)
return FALSE;
g_return_val_if_fail (ifindex > 0, FALSE);
memset (&wol, 0, sizeof (wol));
wol.cmd = ETHTOOL_GWOL;
if (!ethtool_get (ifname, &wol))
if (!ethtool_get (ifindex, &wol))
return FALSE;
return wol.wolopts != 0;
}
gboolean
nmp_utils_ethtool_get_link_settings (const char *ifname,
nmp_utils_ethtool_get_link_settings (int ifindex,
gboolean *out_autoneg,
guint32 *out_speed,
NMPlatformLinkDuplexType *out_duplex)
@ -277,7 +326,9 @@ nmp_utils_ethtool_get_link_settings (const char *ifname,
.cmd = ETHTOOL_GSET,
};
if (!ethtool_get (ifname, &edata))
g_return_val_if_fail (ifindex > 0, FALSE);
if (!ethtool_get (ifindex, &edata))
return FALSE;
if (out_autoneg)
@ -311,14 +362,19 @@ nmp_utils_ethtool_get_link_settings (const char *ifname,
}
gboolean
nmp_utils_ethtool_set_link_settings (const char *ifname, gboolean autoneg, guint32 speed, NMPlatformLinkDuplexType duplex)
nmp_utils_ethtool_set_link_settings (int ifindex,
gboolean autoneg,
guint32 speed,
NMPlatformLinkDuplexType duplex)
{
struct ethtool_cmd edata = {
.cmd = ETHTOOL_GSET,
};
g_return_val_if_fail (ifindex > 0, FALSE);
/* retrieve first current settings */
if (!ethtool_get (ifname, &edata))
if (!ethtool_get (ifindex, &edata))
return FALSE;
/* then change the needed ones */
@ -346,16 +402,18 @@ nmp_utils_ethtool_set_link_settings (const char *ifname, gboolean autoneg, guint
}
}
return ethtool_get (ifname, &edata);
return ethtool_get (ifindex, &edata);
}
gboolean
nmp_utils_ethtool_set_wake_on_lan (const char *ifname,
nmp_utils_ethtool_set_wake_on_lan (int ifindex,
NMSettingWiredWakeOnLan wol,
const char *wol_password)
{
struct ethtool_wolinfo wol_info = { };
g_return_val_if_fail (ifindex > 0, FALSE);
if (wol == NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE)
return TRUE;
@ -386,7 +444,7 @@ nmp_utils_ethtool_set_wake_on_lan (const char *ifname,
wol_info.wolopts |= WAKE_MAGICSECURE;
}
return ethtool_get (ifname, &wol_info);
return ethtool_get (ifindex, &wol_info);
}
/******************************************************************
@ -394,51 +452,45 @@ nmp_utils_ethtool_set_wake_on_lan (const char *ifname,
******************************************************************/
gboolean
nmp_utils_mii_supports_carrier_detect (const char *ifname)
nmp_utils_mii_supports_carrier_detect (int ifindex)
{
int fd, errsv;
char ifname[IFNAMSIZ];
nm_auto_close int fd = -1;
struct ifreq ifr;
struct mii_ioctl_data *mii;
gboolean supports_mii = FALSE;
if (!ifname)
g_return_val_if_fail (ifindex > 0, FALSE);
if (!if_indextoname (ifindex, ifname)) {
nm_log_trace (LOGD_PLATFORM, "mii[%d]: carrier-detect no: request fails resolving ifindex: %s", ifindex, g_strerror (errno));
return FALSE;
}
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);
nm_log_trace (LOGD_PLATFORM, "mii[%d,%s]: carrier-detect no: couldn't open control socket: %s", ifindex, ifname, g_strerror (errno));
return FALSE;
}
memset (&ifr, 0, sizeof (struct ifreq));
nm_utils_ifname_cpy (ifr.ifr_name, ifname);
memcpy (ifr.ifr_name, ifname, IFNAMSIZ);
errno = 0;
if (ioctl (fd, SIOCGMIIPHY, &ifr) < 0) {
errsv = errno;
nm_log_dbg (LOGD_PLATFORM, "mii: SIOCGMIIPHY failed: %s (%d) (%s)", strerror (errsv), errsv, ifname);
goto out;
nm_log_trace (LOGD_PLATFORM, "mii[%d,%s]: carrier-detect no: SIOCGMIIPHY failed: %s", ifindex, ifname, strerror (errno));
return FALSE;
}
/* If we can read the BMSR register, we assume that the card supports MII link detection */
mii = (struct mii_ioctl_data *) &ifr.ifr_ifru;
mii->reg_num = MII_BMSR;
if (ioctl (fd, SIOCGMIIREG, &ifr) == 0) {
nm_log_dbg (LOGD_PLATFORM, "mii: SIOCGMIIREG result 0x%X (%s)", mii->val_out, ifname);
supports_mii = TRUE;
} else {
errsv = errno;
nm_log_dbg (LOGD_PLATFORM, "mii: SIOCGMIIREG failed: %s (%d) (%s)", strerror (errsv), errsv, ifname);
if (ioctl (fd, SIOCGMIIREG, &ifr) != 0) {
nm_log_trace (LOGD_PLATFORM, "mii[%d,%s]: carrier-detect no: SIOCGMIIREG failed: %s", ifindex, ifname, strerror (errno));
return FALSE;
}
out:
close (fd);
nm_log_dbg (LOGD_PLATFORM, "mii: MII %s supported (%s)", supports_mii ? "is" : "not", ifname);
return supports_mii;
nm_log_trace (LOGD_PLATFORM, "mii[%d,%s]: carrier-detect yes: SIOCGMIIREG result 0x%X", ifindex, ifname, mii->val_out);
return TRUE;
}
/******************************************************************
@ -486,22 +538,6 @@ out:
* utils
*****************************************************************************/
gboolean
nmp_utils_device_exists (const char *name)
{
#define SYS_CLASS_NET "/sys/class/net/"
char sysdir[NM_STRLEN (SYS_CLASS_NET) + IFNAMSIZ];
if ( !name
|| strlen (name) >= IFNAMSIZ
|| !nm_utils_is_valid_path_component (name))
g_return_val_if_reached (FALSE);
memcpy (sysdir, SYS_CLASS_NET, NM_STRLEN (SYS_CLASS_NET));
nm_utils_ifname_cpy (&sysdir[NM_STRLEN (SYS_CLASS_NET)], name);
return g_file_test (sysdir, G_FILE_TEST_EXISTS);
}
NMIPConfigSource
nmp_utils_ip_config_source_from_rtprot (guint8 rtprot)
{
@ -623,3 +659,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;
}

View file

@ -27,38 +27,55 @@
#include "nm-setting-wired.h"
const char *nmp_utils_ethtool_get_driver (const char *ifname);
gboolean nmp_utils_ethtool_supports_carrier_detect (const char *ifname);
gboolean nmp_utils_ethtool_supports_vlans (const char *ifname);
int nmp_utils_ethtool_get_peer_ifindex (const char *ifname);
gboolean nmp_utils_ethtool_get_wake_on_lan (const char *ifname);
gboolean nmp_utils_ethtool_set_wake_on_lan (const char *ifname, NMSettingWiredWakeOnLan wol,
const char *nmp_utils_ethtool_get_driver (int ifindex);
gboolean nmp_utils_ethtool_supports_carrier_detect (int ifindex);
gboolean nmp_utils_ethtool_supports_vlans (int ifindex);
int nmp_utils_ethtool_get_peer_ifindex (int ifindex);
gboolean nmp_utils_ethtool_get_wake_on_lan (int ifindex);
gboolean nmp_utils_ethtool_set_wake_on_lan (int ifindex, NMSettingWiredWakeOnLan wol,
const char *wol_password);
gboolean nmp_utils_ethtool_get_link_settings (const char *ifname, gboolean *out_autoneg, guint32 *out_speed, NMPlatformLinkDuplexType *out_duplex);
gboolean nmp_utils_ethtool_set_link_settings (const char *ifname, gboolean autoneg, guint32 speed, NMPlatformLinkDuplexType duplex);
gboolean nmp_utils_ethtool_get_link_settings (int ifindex, gboolean *out_autoneg, guint32 *out_speed, NMPlatformLinkDuplexType *out_duplex);
gboolean nmp_utils_ethtool_set_link_settings (int ifindex, gboolean autoneg, guint32 speed, NMPlatformLinkDuplexType duplex);
gboolean nmp_utils_ethtool_get_driver_info (const char *ifname,
char **out_driver_name,
char **out_driver_version,
char **out_fw_version);
typedef struct {
/* We don't want to include <linux/ethtool.h> in header files,
* thus create a ABI compatible version of struct ethtool_drvinfo.*/
guint32 _private_cmd;
char driver[32];
char version[32];
char fw_version[32];
char _private_bus_info[32];
char _private_erom_version[32];
char _private_reserved2[12];
guint32 _private_n_priv_flags;
guint32 _private_n_stats;
guint32 _private_testinfo_len;
guint32 _private_eedump_len;
guint32 _private_regdump_len;
} NMPUtilsEthtoolDriverInfo;
gboolean nmp_utils_ethtool_get_permanent_address (const char *ifname,
gboolean nmp_utils_ethtool_get_driver_info (int ifindex,
NMPUtilsEthtoolDriverInfo *data);
gboolean nmp_utils_ethtool_get_permanent_address (int ifindex,
guint8 *buf,
size_t *length);
gboolean nmp_utils_mii_supports_carrier_detect (const char *ifname);
gboolean nmp_utils_mii_supports_carrier_detect (int ifindex);
const char *nmp_utils_udev_get_driver (GUdevDevice *device);
gboolean nmp_utils_device_exists (const char *name);
NMIPConfigSource nmp_utils_ip_config_source_from_rtprot (guint8 rtprot) _nm_const;
guint8 nmp_utils_ip_config_source_coerce_to_rtprot (NMIPConfigSource source) _nm_const;
NMIPConfigSource nmp_utils_ip_config_source_coerce_from_rtprot (NMIPConfigSource source) _nm_const;
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__ */

View file

@ -265,9 +265,40 @@ nm_platform_process_events (NMPlatform *self)
/*****************************************************************************/
/**
* nm_platform_sysctl_open_netdir:
* @self: platform instance
* @ifindex: the ifindex for which to open /sys/class/net/%s
* @out_ifname: optional output argument of the found ifname.
*
* Wraps nmp_utils_sysctl_open_netdir() by first changing into the right
* network-namespace.
*
* Returns: on success, the open file descriptor to the /sys/class/net/%s
* directory.
*/
int
nm_platform_sysctl_open_netdir (NMPlatform *self, int ifindex, char *out_ifname)
{
const char*ifname_guess;
_CHECK_SELF_NETNS (self, klass, netns, -1);
g_return_val_if_fail (ifindex > 0, -1);
/* we don't have an @ifname_guess argument to make the API nicer.
* But still do a cache-lookup first. Chances are good that we have
* the right ifname cached and save if_indextoname() */
ifname_guess = nm_platform_link_get_name (self, ifindex);
return nmp_utils_sysctl_open_netdir (ifindex, ifname_guess, out_ifname);
}
/**
* nm_platform_sysctl_set:
* @self: platform instance
* @pathid: if @dirfd is present, this must be the full path that is looked up.
* It is required for logging.
* @dirfd: optional file descriptor for parent directory for openat()
* @path: Absolute option path
* @value: Value to write
*
@ -278,14 +309,14 @@ nm_platform_process_events (NMPlatform *self)
* Returns: %TRUE on success.
*/
gboolean
nm_platform_sysctl_set (NMPlatform *self, const char *path, const char *value)
nm_platform_sysctl_set (NMPlatform *self, const char *pathid, int dirfd, const char *path, const char *value)
{
_CHECK_SELF (self, klass, FALSE);
g_return_val_if_fail (path, FALSE);
g_return_val_if_fail (value, FALSE);
return klass->sysctl_set (self, path, value);
return klass->sysctl_set (self, pathid, dirfd, path, value);
}
gboolean
@ -305,7 +336,7 @@ nm_platform_sysctl_set_ip6_hop_limit_safe (NMPlatform *self, const char *iface,
return FALSE;
path = nm_utils_ip6_property_path (iface, "hop_limit");
cur = nm_platform_sysctl_get_int_checked (self, path, 10, 1, G_MAXINT32, -1);
cur = nm_platform_sysctl_get_int_checked (self, NMP_SYSCTL_PATHID_ABSOLUTE (path), 10, 1, G_MAXINT32, -1);
/* only allow increasing the hop-limit to avoid DOS by an attacker
* setting a low hop-limit (CVE-2015-2924, rh#1209902) */
@ -316,7 +347,7 @@ nm_platform_sysctl_set_ip6_hop_limit_safe (NMPlatform *self, const char *iface,
char svalue[20];
sprintf (svalue, "%d", value);
nm_platform_sysctl_set (self, path, svalue);
nm_platform_sysctl_set (self, NMP_SYSCTL_PATHID_ABSOLUTE (path), svalue);
}
return TRUE;
@ -325,23 +356,29 @@ nm_platform_sysctl_set_ip6_hop_limit_safe (NMPlatform *self, const char *iface,
/**
* nm_platform_sysctl_get:
* @self: platform instance
* @dirfd: if non-negative, used to lookup the path via openat().
* @pathid: if @dirfd is present, this must be the full path that is looked up.
* It is required for logging.
* @path: Absolute path to sysctl
*
* Returns: (transfer full): Contents of the virtual sysctl file.
*/
char *
nm_platform_sysctl_get (NMPlatform *self, const char *path)
nm_platform_sysctl_get (NMPlatform *self, const char *pathid, int dirfd, const char *path)
{
_CHECK_SELF (self, klass, NULL);
g_return_val_if_fail (path, NULL);
return klass->sysctl_get (self, path);
return klass->sysctl_get (self, pathid, dirfd, path);
}
/**
* nm_platform_sysctl_get_int32:
* @self: platform instance
* @pathid: if @dirfd is present, this must be the full path that is looked up.
* It is required for logging.
* @dirfd: if non-negative, used to lookup the path via openat().
* @path: Absolute path to sysctl
* @fallback: default value, if the content of path could not be read
* as decimal integer.
@ -351,14 +388,17 @@ nm_platform_sysctl_get (NMPlatform *self, const char *path)
* value, on success %errno will be set to zero.
*/
gint32
nm_platform_sysctl_get_int32 (NMPlatform *self, const char *path, gint32 fallback)
nm_platform_sysctl_get_int32 (NMPlatform *self, const char *pathid, int dirfd, const char *path, gint32 fallback)
{
return nm_platform_sysctl_get_int_checked (self, path, 10, G_MININT32, G_MAXINT32, fallback);
return nm_platform_sysctl_get_int_checked (self, pathid, dirfd, path, 10, G_MININT32, G_MAXINT32, fallback);
}
/**
* nm_platform_sysctl_get_int_checked:
* @self: platform instance
* @pathid: if @dirfd is present, this must be the full path that is looked up.
* It is required for logging.
* @dirfd: if non-negative, used to lookup the path via openat().
* @path: Absolute path to sysctl
* @base: base of numeric conversion
* @min: minimal value that is still valid
@ -373,7 +413,7 @@ nm_platform_sysctl_get_int32 (NMPlatform *self, const char *path, gint32 fallbac
* (inclusive) or @fallback.
*/
gint64
nm_platform_sysctl_get_int_checked (NMPlatform *self, const char *path, guint base, gint64 min, gint64 max, gint64 fallback)
nm_platform_sysctl_get_int_checked (NMPlatform *self, const char *pathid, int dirfd, const char *path, guint base, gint64 min, gint64 max, gint64 fallback)
{
char *value = NULL;
gint32 ret;
@ -383,7 +423,7 @@ nm_platform_sysctl_get_int_checked (NMPlatform *self, const char *path, guint ba
g_return_val_if_fail (path, fallback);
if (path)
value = nm_platform_sysctl_get (self, path);
value = nm_platform_sysctl_get (self, pathid, dirfd, path);
if (!value) {
errno = EINVAL;
@ -1668,34 +1708,44 @@ nm_platform_link_tun_add (NMPlatform *self,
/*****************************************************************************/
static char *
link_option_path (NMPlatform *self, int master, const char *category, const char *option)
static gboolean
link_set_option (NMPlatform *self, int ifindex, const char *category, const char *option, const char *value)
{
const char *name = nm_platform_link_get_name (self, master);
nm_auto_close int dirfd = -1;
char ifname_verified[IFNAMSIZ];
const char *path;
if (!name || !category || !option)
if (!category || !option)
return FALSE;
dirfd = nm_platform_sysctl_open_netdir (self, ifindex, ifname_verified);
if (dirfd < 0)
return FALSE;
path = nm_sprintf_bufa (strlen (category) + strlen (option) + 2,
"%s/%s",
category, option);
return nm_platform_sysctl_set (self, NMP_SYSCTL_PATHID_NETDIR_unsafe (dirfd, ifname_verified, path), value);
}
static char *
link_get_option (NMPlatform *self, int ifindex, const char *category, const char *option)
{
nm_auto_close int dirfd = -1;
char ifname_verified[IFNAMSIZ];
const char *path;
if (!category || !option)
return NULL;
return g_strdup_printf ("/sys/class/net/%s/%s/%s",
NM_ASSERT_VALID_PATH_COMPONENT (name),
NM_ASSERT_VALID_PATH_COMPONENT (category),
NM_ASSERT_VALID_PATH_COMPONENT (option));
}
dirfd = nm_platform_sysctl_open_netdir (self, ifindex, ifname_verified);
if (dirfd < 0)
return NULL;
static gboolean
link_set_option (NMPlatform *self, int master, const char *category, const char *option, const char *value)
{
gs_free char *path = link_option_path (self, master, category, option);
return path && nm_platform_sysctl_set (self, path, value);
}
static char *
link_get_option (NMPlatform *self, int master, const char *category, const char *option)
{
gs_free char *path = link_option_path (self, master, category, option);
return path ? nm_platform_sysctl_get (self, path) : NULL;
path = nm_sprintf_bufa (strlen (category) + strlen (option) + 2,
"%s/%s",
category, option);
return nm_platform_sysctl_get (self, NMP_SYSCTL_PATHID_NETDIR_unsafe (dirfd, ifname_verified, path));
}
static const char *
@ -1973,10 +2023,11 @@ nm_platform_link_infiniband_get_properties (NMPlatform *self,
int *out_p_key,
const char **out_mode)
{
nm_auto_close int dirfd = -1;
char ifname_verified[IFNAMSIZ];
const NMPlatformLnkInfiniband *plnk;
const NMPlatformLink *plink;
const char *iface;
char *path, *contents;
char *contents;
const char *mode;
int p_key = 0;
@ -2000,15 +2051,13 @@ nm_platform_link_infiniband_get_properties (NMPlatform *self,
/* Could not get the link information via netlink. To support older kernels,
* fallback to reading sysfs. */
iface = NM_ASSERT_VALID_PATH_COMPONENT (plink->name);
/* Fall back to reading sysfs */
path = g_strdup_printf ("/sys/class/net/%s/mode", iface);
contents = nm_platform_sysctl_get (self, path);
g_free (path);
if (!contents)
dirfd = nm_platform_sysctl_open_netdir (self, ifindex, ifname_verified);
if (dirfd < 0)
return FALSE;
contents = nm_platform_sysctl_get (self, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname_verified, "mode"));
if (!contents)
return FALSE;
if (strstr (contents, "datagram"))
mode = "datagram";
else if (strstr (contents, "connected"))
@ -2017,13 +2066,7 @@ nm_platform_link_infiniband_get_properties (NMPlatform *self,
mode = NULL;
g_free (contents);
path = g_strdup_printf ("/sys/class/net/%s/pkey", iface);
contents = nm_platform_sysctl_get (self, path);
g_free (path);
if (!contents)
return FALSE;
p_key = (int) _nm_utils_ascii_str_to_int64 (contents, 16, 0, 0xFFFF, -1);
g_free (contents);
p_key = nm_platform_sysctl_get_int_checked (self, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname_verified, "pkey"), 16, 0, 0xFFFF, -1);
if (p_key < 0)
return FALSE;
@ -2216,7 +2259,7 @@ nm_platform_link_veth_get_properties (NMPlatform *self, int ifindex, int *out_pe
if (!nm_platform_netns_push (self, &netns))
return FALSE;
peer_ifindex = nmp_utils_ethtool_get_peer_ifindex (plink->name);
peer_ifindex = nmp_utils_ethtool_get_peer_ifindex (plink->ifindex);
if (peer_ifindex <= 0)
return FALSE;
@ -2226,74 +2269,59 @@ nm_platform_link_veth_get_properties (NMPlatform *self, int ifindex, int *out_pe
}
gboolean
nm_platform_link_tun_get_properties_ifname (NMPlatform *self, const char *ifname, NMPlatformTunProperties *props)
nm_platform_link_tun_get_properties (NMPlatform *self, int ifindex, const char *ifname_guess, NMPlatformTunProperties *props)
{
char path[256];
char *val;
nm_auto_close int dirfd = -1;
const char *ifname;
char ifname_verified[IFNAMSIZ];
gint64 flags;
gboolean success = TRUE;
_CHECK_SELF (self, klass, FALSE);
g_return_val_if_fail (ifindex > 0, FALSE);
g_return_val_if_fail (props, FALSE);
/* ifname_guess is an optional argument to find a guess for the ifname corresponding to
* ifindex. */
if (!ifname_guess) {
/* if NULL, obtain the guess from the platform cache. */
ifname = nm_platform_link_get_name (self, ifindex);
} else if (!ifname_guess[0]) {
/* if empty, don't use a guess. That means to use if_indextoname(). */
ifname = NULL;
} else
ifname = ifname_guess;
memset (props, 0, sizeof (*props));
props->owner = -1;
props->group = -1;
if (!ifname || !nm_utils_iface_valid_name (ifname))
dirfd = nm_platform_sysctl_open_netdir (self, ifindex, ifname_verified);
if (dirfd < 0)
return FALSE;
nm_sprintf_buf (path, "/sys/class/net/%s/owner", ifname);
val = nm_platform_sysctl_get (self, path);
if (val) {
props->owner = _nm_utils_ascii_str_to_int64 (val, 10, -1, G_MAXINT64, -1);
if (errno)
success = FALSE;
g_free (val);
} else
ifname = ifname_verified;
props->owner = nm_platform_sysctl_get_int_checked (self, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname, "owner"), 10, -1, G_MAXINT64, -1);
if (errno)
success = FALSE;
nm_sprintf_buf (path, "/sys/class/net/%s/group", ifname);
val = nm_platform_sysctl_get (self, path);
if (val) {
props->group = _nm_utils_ascii_str_to_int64 (val, 10, -1, G_MAXINT64, -1);
if (errno)
success = FALSE;
g_free (val);
} else
props->group = nm_platform_sysctl_get_int_checked (self, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname, "group"), 10, -1, G_MAXINT64, -1);
if (errno)
success = FALSE;
nm_sprintf_buf (path, "/sys/class/net/%s/tun_flags", ifname);
val = nm_platform_sysctl_get (self, path);
if (val) {
gint64 flags;
flags = _nm_utils_ascii_str_to_int64 (val, 16, 0, G_MAXINT64, 0);
if (!errno) {
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 & NM_IFF_MULTI_QUEUE);
} else
success = FALSE;
g_free (val);
flags = nm_platform_sysctl_get_int_checked (self, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname, "tun_flags"), 16, 0, G_MAXINT64, -1);
if (flags >= 0) {
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 & NM_IFF_MULTI_QUEUE);
} else
success = FALSE;
return success;
}
gboolean
nm_platform_link_tun_get_properties (NMPlatform *self, int ifindex, NMPlatformTunProperties *props)
{
_CHECK_SELF (self, klass, FALSE);
g_return_val_if_fail (ifindex > 0, FALSE);
g_return_val_if_fail (props != NULL, FALSE);
return nm_platform_link_tun_get_properties_ifname (self, nm_platform_link_get_name (self, ifindex), props);
}
gboolean
nm_platform_wifi_get_capabilities (NMPlatform *self, int ifindex, NMDeviceWifiCapabilities *caps)
{
@ -2479,27 +2507,33 @@ _to_string_ifa_flags (guint32 ifa_flags, char *buf, gsize size)
/*****************************************************************************/
gboolean
nm_platform_ethtool_set_wake_on_lan (NMPlatform *self, const char *ifname, NMSettingWiredWakeOnLan wol, const char *wol_password)
nm_platform_ethtool_set_wake_on_lan (NMPlatform *self, int ifindex, NMSettingWiredWakeOnLan wol, const char *wol_password)
{
_CHECK_SELF_NETNS (self, klass, netns, FALSE);
return nmp_utils_ethtool_set_wake_on_lan (ifname, wol, wol_password);
g_return_val_if_fail (ifindex > 0, FALSE);
return nmp_utils_ethtool_set_wake_on_lan (ifindex, wol, wol_password);
}
gboolean
nm_platform_ethtool_set_link_settings (NMPlatform *self, const char *ifname, gboolean autoneg, guint32 speed, NMPlatformLinkDuplexType duplex)
nm_platform_ethtool_set_link_settings (NMPlatform *self, int ifindex, gboolean autoneg, guint32 speed, NMPlatformLinkDuplexType duplex)
{
_CHECK_SELF_NETNS (self, klass, netns, FALSE);
return nmp_utils_ethtool_set_link_settings (ifname, autoneg, speed, duplex);
g_return_val_if_fail (ifindex > 0, FALSE);
return nmp_utils_ethtool_set_link_settings (ifindex, autoneg, speed, duplex);
}
gboolean
nm_platform_ethtool_get_link_settings (NMPlatform *self, const char *ifname, gboolean *out_autoneg, guint32 *out_speed, NMPlatformLinkDuplexType *out_duplex)
nm_platform_ethtool_get_link_settings (NMPlatform *self, int ifindex, gboolean *out_autoneg, guint32 *out_speed, NMPlatformLinkDuplexType *out_duplex)
{
_CHECK_SELF_NETNS (self, klass, netns, FALSE);
return nmp_utils_ethtool_get_link_settings (ifname, out_autoneg, out_speed, out_duplex);
g_return_val_if_fail (ifindex > 0, FALSE);
return nmp_utils_ethtool_get_link_settings (ifindex, out_autoneg, out_speed, out_duplex);
}
/*****************************************************************************/

View file

@ -500,8 +500,8 @@ struct _NMPlatform {
typedef struct {
GObjectClass parent;
gboolean (*sysctl_set) (NMPlatform *, const char *path, const char *value);
char * (*sysctl_get) (NMPlatform *, const char *path);
gboolean (*sysctl_set) (NMPlatform *, const char *pathid, int dirfd, const char *path, const char *value);
char * (*sysctl_get) (NMPlatform *, const char *pathid, int dirfd, const char *path);
const NMPlatformLink *(*link_get) (NMPlatform *platform, int ifindex);
const NMPlatformLink *(*link_get_by_ifname) (NMPlatform *platform, const char *ifname);
@ -717,10 +717,24 @@ const char *nm_link_type_to_string (NMLinkType link_type);
const char *_nm_platform_error_to_string (NMPlatformError error);
#define nm_platform_error_to_string(error) NM_UTILS_LOOKUP_STR (_nm_platform_error_to_string, error)
gboolean nm_platform_sysctl_set (NMPlatform *self, const char *path, const char *value);
char *nm_platform_sysctl_get (NMPlatform *self, const char *path);
gint32 nm_platform_sysctl_get_int32 (NMPlatform *self, const char *path, gint32 fallback);
gint64 nm_platform_sysctl_get_int_checked (NMPlatform *self, const char *path, guint base, gint64 min, gint64 max, gint64 fallback);
#define NMP_SYSCTL_PATHID_ABSOLUTE(path) \
((const char *) NULL), -1, (path)
#define NMP_SYSCTL_PATHID_NETDIR_unsafe(dirfd, ifname, path) \
nm_sprintf_bufa (NM_STRLEN ("net:/sys/class/net//\0") + IFNAMSIZ + strlen (path), \
"net:/sys/class/net/%s/%s", (ifname), (path)), \
(dirfd), (path)
#define NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname, path) \
nm_sprintf_bufa (NM_STRLEN ("net:/sys/class/net//"path"/\0") + IFNAMSIZ, \
"net:/sys/class/net/%s/%s", (ifname), path), \
(dirfd), (""path"")
int nm_platform_sysctl_open_netdir (NMPlatform *self, int ifindex, char *out_ifname);
gboolean nm_platform_sysctl_set (NMPlatform *self, const char *pathid, int dirfd, const char *path, const char *value);
char *nm_platform_sysctl_get (NMPlatform *self, const char *pathid, int dirfd, const char *path);
gint32 nm_platform_sysctl_get_int32 (NMPlatform *self, const char *pathid, int dirfd, const char *path, gint32 fallback);
gint64 nm_platform_sysctl_get_int_checked (NMPlatform *self, const char *pathid, int dirfd, const char *path, guint base, gint64 min, gint64 max, gint64 fallback);
gboolean nm_platform_sysctl_set_ip6_hop_limit_safe (NMPlatform *self, const char *iface, int value);
@ -851,9 +865,7 @@ NMPlatformError nm_platform_link_infiniband_delete (NMPlatform *self,
gboolean nm_platform_link_infiniband_get_properties (NMPlatform *self, int ifindex, int *parent, int *p_key, const char **mode);
gboolean nm_platform_link_veth_get_properties (NMPlatform *self, int ifindex, int *out_peer_ifindex);
gboolean nm_platform_link_tun_get_properties (NMPlatform *self, int ifindex, NMPlatformTunProperties *properties);
gboolean nm_platform_link_tun_get_properties_ifname (NMPlatform *platform, const char *ifname, NMPlatformTunProperties *props);
gboolean nm_platform_link_tun_get_properties (NMPlatform *self, int ifindex, const char *ifname_guess, NMPlatformTunProperties *properties);
gboolean nm_platform_wifi_get_capabilities (NMPlatform *self, int ifindex, NMDeviceWifiCapabilities *caps);
gboolean nm_platform_wifi_get_bssid (NMPlatform *self, int ifindex, guint8 *bssid);
@ -980,8 +992,8 @@ const char *nm_platform_route_scope2str (int scope, char *buf, gsize len);
int nm_platform_ip_address_cmp_expiry (const NMPlatformIPAddress *a, const NMPlatformIPAddress *b);
gboolean nm_platform_ethtool_set_wake_on_lan (NMPlatform *self, const char *ifname, NMSettingWiredWakeOnLan wol, const char *wol_password);
gboolean nm_platform_ethtool_set_link_settings (NMPlatform *self, const char *ifname, gboolean autoneg, guint32 speed, NMPlatformLinkDuplexType duplex);
gboolean nm_platform_ethtool_get_link_settings (NMPlatform *self, const char *ifname, gboolean *out_autoneg, guint32 *out_speed, NMPlatformLinkDuplexType *out_duplex);
gboolean nm_platform_ethtool_set_wake_on_lan (NMPlatform *self, int ifindex, NMSettingWiredWakeOnLan wol, const char *wol_password);
gboolean nm_platform_ethtool_set_link_settings (NMPlatform *self, int ifindex, gboolean autoneg, guint32 speed, NMPlatformLinkDuplexType duplex);
gboolean nm_platform_ethtool_get_link_settings (NMPlatform *self, int ifindex, gboolean *out_autoneg, guint32 *out_speed, NMPlatformLinkDuplexType *out_duplex);
#endif /* __NETWORKMANAGER_PLATFORM_H__ */

View file

@ -284,7 +284,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,
@ -293,7 +293,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,
@ -631,7 +631,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);

View file

@ -53,8 +53,12 @@ int nmp_netns_get_fd_mnt (NMPNetns *self);
static inline void
_nm_auto_pop_netns (NMPNetns **p)
{
if (*p)
if (*p) {
int errsv = errno;
nmp_netns_pop (*p);
errno = errsv;
}
}
#define nm_auto_pop_netns __attribute__((cleanup(_nm_auto_pop_netns)))

View file

@ -125,7 +125,7 @@ _vlan_xgress_qos_mappings_cpy (guint *dst_n_map,
/*****************************************************************************/
static const char *
_link_get_driver (GUdevDevice *udev_device, const char *kind, const char *ifname)
_link_get_driver (GUdevDevice *udev_device, const char *kind, int ifindex)
{
const char *driver = NULL;
@ -140,14 +140,12 @@ _link_get_driver (GUdevDevice *udev_device, const char *kind, const char *ifname
if (kind)
return kind;
if (ifname) {
char *d;
if (ifindex > 0) {
NMPUtilsEthtoolDriverInfo driver_info;
if (nmp_utils_ethtool_get_driver_info (ifname, &d, NULL, NULL)) {
driver = d && d[0] ? g_intern_string (d) : NULL;
g_free (d);
if (driver)
return driver;
if (nmp_utils_ethtool_get_driver_info (ifindex, &driver_info)) {
if (driver_info.driver[0])
return g_intern_string (driver_info.driver);
}
}
@ -169,7 +167,7 @@ _nmp_object_fixup_link_udev_fields (NMPObject *obj, gboolean use_udev)
if (obj->_link.netlink.is_in_netlink) {
driver = _link_get_driver (obj->_link.udev.device,
obj->link.kind,
obj->link.name);
obj->link.ifindex);
if (obj->_link.udev.device)
initialized = TRUE;
else if (!use_udev) {

View file

@ -1407,7 +1407,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,
@ -1415,7 +1415,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,
@ -1549,7 +1549,26 @@ 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);
}
/*****************************************************************************/
void
nmtstp_netns_select_random (NMPlatform **platforms, gsize n_platforms, NMPNetns **netns)
{
int i;
g_assert (platforms);
g_assert (n_platforms && n_platforms <= G_MAXINT32);
g_assert (netns && !*netns);
for (i = 0; i < n_platforms; i++)
g_assert (NM_IS_PLATFORM (platforms[i]));
i = nmtst_get_rand_int () % (n_platforms + 1);
if (i == 0)
return;
g_assert (nm_platform_netns_push (platforms[i - 1], netns));
}
/*****************************************************************************/
@ -1573,21 +1592,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);

View file

@ -53,6 +53,10 @@ int nmtstp_namespace_get_fd_for_process (pid_t pid, const char *ns_name);
/*****************************************************************************/
void nmtstp_netns_select_random (NMPlatform **platforms, gsize n_platforms, NMPNetns **netns);
/*****************************************************************************/
typedef struct {
gulong handler_id;
const char *name;

View file

@ -398,26 +398,28 @@ test_software (NMLinkType link_type, const char *link_typename)
accept_signal (link_changed);
/* Set master option */
switch (link_type) {
case NM_LINK_TYPE_BRIDGE:
if (nmtstp_is_sysfs_writable ()) {
g_assert (nm_platform_sysctl_master_set_option (NM_PLATFORM_GET, ifindex, "forward_delay", "628"));
value = nm_platform_sysctl_master_get_option (NM_PLATFORM_GET, ifindex, "forward_delay");
g_assert_cmpstr (value, ==, "628");
g_free (value);
if (nmtstp_is_root_test ()) {
switch (link_type) {
case NM_LINK_TYPE_BRIDGE:
if (nmtstp_is_sysfs_writable ()) {
g_assert (nm_platform_sysctl_master_set_option (NM_PLATFORM_GET, ifindex, "forward_delay", "628"));
value = nm_platform_sysctl_master_get_option (NM_PLATFORM_GET, ifindex, "forward_delay");
g_assert_cmpstr (value, ==, "628");
g_free (value);
}
break;
case NM_LINK_TYPE_BOND:
if (nmtstp_is_sysfs_writable ()) {
g_assert (nm_platform_sysctl_master_set_option (NM_PLATFORM_GET, ifindex, "mode", "active-backup"));
value = nm_platform_sysctl_master_get_option (NM_PLATFORM_GET, ifindex, "mode");
/* When reading back, the output looks slightly different. */
g_assert (g_str_has_prefix (value, "active-backup"));
g_free (value);
}
break;
default:
break;
}
break;
case NM_LINK_TYPE_BOND:
if (nmtstp_is_sysfs_writable ()) {
g_assert (nm_platform_sysctl_master_set_option (NM_PLATFORM_GET, ifindex, "mode", "active-backup"));
value = nm_platform_sysctl_master_get_option (NM_PLATFORM_GET, ifindex, "mode");
/* When reading back, the output looks slightly different. */
g_assert (g_str_has_prefix (value, "active-backup"));
g_free (value);
}
break;
default:
break;
}
/* Enslave and release */
@ -1941,7 +1943,7 @@ _test_netns_check_skip (void)
G_STMT_START { \
gs_free char *_val = NULL; \
\
_val = nm_platform_sysctl_get (plat, path); \
_val = nm_platform_sysctl_get (plat, NMP_SYSCTL_PATHID_ABSOLUTE (path)); \
g_assert_cmpstr (_val, ==, value); \
} G_STMT_END
@ -1954,6 +1956,7 @@ test_netns_general (gpointer fixture, gconstpointer test_data)
char sbuf[100];
int i, j, k;
gboolean ethtool_support;
NMPUtilsEthtoolDriverInfo driver_info;
if (_test_netns_check_skip ())
return;
@ -2013,7 +2016,7 @@ test_netns_general (gpointer fixture, gconstpointer test_data)
else
path = "/proc/sys/net/ipv6/conf/dummy2b/disable_ipv6";
}
g_assert (nm_platform_sysctl_set (pl, path, nm_sprintf_buf (sbuf, "%d", j)));
g_assert (nm_platform_sysctl_set (pl, NMP_SYSCTL_PATHID_ABSOLUTE (path), nm_sprintf_buf (sbuf, "%d", j)));
_sysctl_assert_eq (pl, path, nm_sprintf_buf (sbuf, "%d", j));
}
@ -2024,9 +2027,8 @@ test_netns_general (gpointer fixture, gconstpointer test_data)
* skip asserts that are known to fail. */
ethtool_support = nmtstp_run_command ("ethtool -i dummy1_ > /dev/null") == 0;
if (ethtool_support) {
g_assert ( nmp_utils_ethtool_get_driver_info ("dummy1_", NULL, NULL, NULL));
g_assert ( nmp_utils_ethtool_get_driver_info ("dummy2a", NULL, NULL, NULL));
g_assert (!nmp_utils_ethtool_get_driver_info ("dummy2b", NULL, NULL, NULL));
g_assert (nmp_utils_ethtool_get_driver_info (nmtstp_link_get_typed (platform_1, 0, "dummy1_", NM_LINK_TYPE_DUMMY)->ifindex, &driver_info));
g_assert (nmp_utils_ethtool_get_driver_info (nmtstp_link_get_typed (platform_1, 0, "dummy2a", NM_LINK_TYPE_DUMMY)->ifindex, &driver_info));
g_assert_cmpint (nmtstp_run_command ("ethtool -i dummy1_ > /dev/null"), ==, 0);
g_assert_cmpint (nmtstp_run_command ("ethtool -i dummy2a > /dev/null"), ==, 0);
g_assert_cmpint (nmtstp_run_command ("ethtool -i dummy2b 2> /dev/null"), !=, 0);
@ -2035,9 +2037,8 @@ test_netns_general (gpointer fixture, gconstpointer test_data)
g_assert (nm_platform_netns_push (platform_2, &netns_tmp));
if (ethtool_support) {
g_assert ( nmp_utils_ethtool_get_driver_info ("dummy1_", NULL, NULL, NULL));
g_assert (!nmp_utils_ethtool_get_driver_info ("dummy2a", NULL, NULL, NULL));
g_assert ( nmp_utils_ethtool_get_driver_info ("dummy2b", NULL, NULL, NULL));
g_assert (nmp_utils_ethtool_get_driver_info (nmtstp_link_get_typed (platform_2, 0, "dummy1_", NM_LINK_TYPE_DUMMY)->ifindex, &driver_info));
g_assert (nmp_utils_ethtool_get_driver_info (nmtstp_link_get_typed (platform_2, 0, "dummy2b", NM_LINK_TYPE_DUMMY)->ifindex, &driver_info));
g_assert_cmpint (nmtstp_run_command ("ethtool -i dummy1_ > /dev/null"), ==, 0);
g_assert_cmpint (nmtstp_run_command ("ethtool -i dummy2a 2> /dev/null"), !=, 0);
g_assert_cmpint (nmtstp_run_command ("ethtool -i dummy2b > /dev/null"), ==, 0);
@ -2056,7 +2057,6 @@ test_netns_set_netns (gpointer fixture, gconstpointer test_data)
gs_unref_object NMPlatform *platform_1 = NULL;
gs_unref_object NMPlatform *platform_2 = NULL;
nm_auto_pop_netns NMPNetns *netns_pop = NULL;
int i;
if (_test_netns_check_skip ())
return;
@ -2065,9 +2065,7 @@ test_netns_set_netns (gpointer fixture, gconstpointer test_data)
platforms[1] = platform_1 = _test_netns_create_platform ();
platforms[2] = platform_2 = _test_netns_create_platform ();
i = nmtst_get_rand_int () % 4;
if (i != 3)
g_assert (nm_platform_netns_push (platforms[i], &netns_pop));
nmtstp_netns_select_random (platforms, G_N_ELEMENTS (platforms), &netns_pop);
#define LINK_MOVE_NAME "link-move"
g_assert (!nm_platform_link_get_by_ifname (platform_1, LINK_MOVE_NAME));
@ -2187,7 +2185,7 @@ test_netns_push (gpointer fixture, gconstpointer test_data)
_ADD_DUMMY (pl[i].platform, pl[i].device_name);
g_assert (nm_platform_sysctl_set (pl[i].platform, pl[i].sysctl_path, pl[i].sysctl_value));
g_assert (nm_platform_sysctl_set (pl[i].platform, NMP_SYSCTL_PATHID_ABSOLUTE (pl[i].sysctl_path), pl[i].sysctl_value));
tmp = _get_current_namespace_id (CLONE_NEWNET);
g_ptr_array_add (device_names, tmp);
@ -2294,9 +2292,7 @@ test_netns_bind_to_path (gpointer fixture, gconstpointer test_data)
platforms[1] = platform_1 = _test_netns_create_platform ();
platforms[2] = platform_2 = _test_netns_create_platform ();
i = nmtst_get_rand_int () % 4;
if (i != 3)
g_assert (nm_platform_netns_push (platforms[i], &netns_pop));
nmtstp_netns_select_random (platforms, G_N_ELEMENTS (platforms), &netns_pop);
g_assert_cmpint (mount ("tmpfs", P_VAR_RUN, "tmpfs", MS_NOATIME | MS_NODEV | MS_NOSUID, "mode=0755,size=32K"), ==, 0);
g_assert_cmpint (mkdir (P_VAR_RUN_NETNS, 755), ==, 0);
@ -2325,6 +2321,173 @@ test_netns_bind_to_path (gpointer fixture, gconstpointer test_data)
/*****************************************************************************/
static void
test_sysctl_rename (void)
{
NMPlatform *const PL = NM_PLATFORM_GET;
const char *const IFNAME[3] = {
"nm-dummy-0",
"nm-dummy-1",
"nm-dummy-2",
};
int ifindex[G_N_ELEMENTS (IFNAME)] = { 0 };
nm_auto_close int dirfd = -1;
int i;
char ifname_buf[IFNAMSIZ];
char *s;
const NMPlatformLink *pllink;
ifindex[0] = nmtstp_link_dummy_add (PL, -1, IFNAME[0])->ifindex;
ifindex[1] = nmtstp_link_dummy_add (PL, -1, IFNAME[1])->ifindex;
s = (nmtst_get_rand_int () % 2) ? NULL : ifname_buf;
if (nmtst_get_rand_int () % 2) {
/* bring the platform cache out of sync */
nmtstp_run_command_check ("ip link set %s name %s", IFNAME[0], IFNAME[2]);
nm_platform_process_events (PL);
nmtstp_run_command_check ("ip link set %s name %s", IFNAME[2], IFNAME[0]);
pllink = nm_platform_link_get_by_ifname (PL, IFNAME[2]);
g_assert (pllink && pllink->ifindex == ifindex[0]);
pllink = nm_platform_link_get_by_ifname (PL, IFNAME[0]);
g_assert (!pllink);
}
/* open dirfd for IFNAME[0] */
i = nmtst_get_rand_int () % (2 + G_N_ELEMENTS (IFNAME));
if (i == 0) {
dirfd = nm_platform_sysctl_open_netdir (PL,
ifindex[0],
s);
} else {
const char *ifname_guess;
/* provide a wrong or no guess. */
ifname_guess = i == 1 ? NULL : IFNAME[i - 2];
dirfd = nmp_utils_sysctl_open_netdir (ifindex[0],
ifname_guess,
s);
}
g_assert (dirfd >= 0);
if (s)
g_assert_cmpstr (s, ==, IFNAME[0]);
/* possibly rename the interfaces. */
switch (nmtst_get_rand_int () % 4) {
case 0:
break;
case 1:
nmtstp_run_command_check ("ip link set %s name %s", IFNAME[0], IFNAME[2]);
break;
case 2:
nmtstp_run_command_check ("ip link set %s name %s", IFNAME[0], IFNAME[2]);
nmtstp_run_command_check ("ip link set %s name %s", IFNAME[1], IFNAME[0]);
break;
}
/* possibly, resync platform cache (should make no difference). */
if (nmtst_get_rand_int () % 2)
nm_platform_process_events (PL);
/* check that we still read the same file. */
switch (nmtst_get_rand_int () % 2) {
case 0: {
gs_free char *c = NULL;
if (nm_utils_file_get_contents (dirfd, "ifindex", 1*1024*1024, &c, NULL, NULL) < 0)
g_assert_not_reached();
g_assert_cmpint (ifindex[0], ==, (int) _nm_utils_ascii_str_to_int64 (c, 10, 0, G_MAXINT, -1));
break;
}
case 1: {
g_assert_cmpint (ifindex[0], ==, (gint32) nm_platform_sysctl_get_int32 (PL, NMP_SYSCTL_PATHID_NETDIR (dirfd, s ?: "<unknown>", "ifindex"), -1));
break;
}
default:
g_assert_not_reached ();
}
nm_platform_process_events (PL);
nmtstp_link_del (PL, -1, ifindex[0], NULL);
nmtstp_link_del (PL, -1, ifindex[1], NULL);
}
/*****************************************************************************/
static void
test_sysctl_netns_switch (void)
{
const char *const IFNAME = "nm-dummy-0";
int ifindex, ifindex_tmp;
nm_auto_close int dirfd = -1;
char ifname_buf[IFNAMSIZ];
char *s;
gs_unref_object NMPlatform *platform_0 = NULL;
gs_unref_object NMPlatform *platform_1 = NULL;
gs_unref_object NMPlatform *platform_2 = NULL;
nm_auto_pop_netns NMPNetns *netns_pop_1 = NULL;
nm_auto_pop_netns NMPNetns *netns_pop_2 = NULL;
nm_auto_pop_netns NMPNetns *netns_pop_3 = NULL;
NMPlatform *PL;
NMPlatform *platforms[3];
if (_test_netns_check_skip ())
return;
platforms[0] = platform_0 = nm_linux_platform_new (TRUE);
platforms[1] = platform_1 = _test_netns_create_platform ();
platforms[2] = platform_2 = _test_netns_create_platform ();
PL = platforms[nmtst_get_rand_int () % 3];
nmtstp_netns_select_random (platforms, G_N_ELEMENTS (platforms), &netns_pop_1);
ifindex = nmtstp_link_dummy_add (PL, FALSE, IFNAME)->ifindex;
nmtstp_netns_select_random (platforms, G_N_ELEMENTS (platforms), &netns_pop_2);
s = (nmtst_get_rand_int () % 2) ? NULL : ifname_buf;
dirfd = nm_platform_sysctl_open_netdir (PL,
ifindex,
s);
g_assert (dirfd >= 0);
if (s)
g_assert_cmpstr (s, ==, IFNAME);
nmtstp_netns_select_random (platforms, G_N_ELEMENTS (platforms), &netns_pop_3);
/* even if we switch to other namespaces, we can still lookup the path correctly,
* either using dirfd or via the platform instance (which switches namespace as needed). */
{
gs_free char *c = NULL;
if (nm_utils_file_get_contents (dirfd, "ifindex", 0, &c, NULL, NULL) < 0)
g_assert_not_reached();
g_assert_cmpint (ifindex, ==, (int) _nm_utils_ascii_str_to_int64 (c, 10, 0, G_MAXINT, -1));
}
g_assert_cmpint (ifindex, ==, (gint32) nm_platform_sysctl_get_int32 (PL, NMP_SYSCTL_PATHID_NETDIR (dirfd, s ?: "<unknown>", "ifindex"), -1));
g_assert_cmpint (ifindex, ==, (gint32) nm_platform_sysctl_get_int32 (PL, NMP_SYSCTL_PATHID_ABSOLUTE (nm_sprintf_bufa (100, "/sys/class/net/%s/ifindex", IFNAME)), -1));
/* accessing the path directly, only succeeds iff the current namespace happens to be the namespace
* in which we created the link. */
{
gs_free char *c = NULL;
if (nm_utils_file_get_contents (-1, nm_sprintf_bufa (100, "/sys/class/net/%s/ifindex", IFNAME), 0, &c, NULL, NULL) < 0)
ifindex_tmp = -1;
else
ifindex_tmp = _nm_utils_ascii_str_to_int64 (c, 10, 0, G_MAXINT, -2);
}
if (nmp_netns_get_current () == nm_platform_netns_get (PL))
g_assert_cmpint (ifindex_tmp, ==, ifindex);
else
g_assert_cmpint (ifindex_tmp, ==, -1);
nmtstp_link_del (PL, FALSE, ifindex, NULL);
}
/*****************************************************************************/
NMTstpSetupFunc const _nmtstp_setup_platform_func = SETUP;
void
@ -2378,5 +2541,8 @@ _nmtstp_setup_tests (void)
g_test_add_vtable ("/general/netns/set-netns", 0, NULL, _test_netns_setup, test_netns_set_netns, _test_netns_teardown);
g_test_add_vtable ("/general/netns/push", 0, NULL, _test_netns_setup, test_netns_push, _test_netns_teardown);
g_test_add_vtable ("/general/netns/bind-to-path", 0, NULL, _test_netns_setup, test_netns_bind_to_path, _test_netns_teardown);
g_test_add_func ("/general/sysctl/rename", test_sysctl_rename);
g_test_add_func ("/general/sysctl/netns-switch", test_sysctl_netns_switch);
}
}

View file

@ -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;
@ -662,10 +662,17 @@ wifi_wext_is_wifi (const char *iface)
struct iwreq iwr;
gboolean is_wifi = FALSE;
if (!nmp_utils_device_exists (iface))
return FALSE;
/* performing an ioctl on a non-existing name may cause the automatic
* loading of kernel modules, which should be avoided.
*
* Usually, we should thus make sure that an inteface with this name
* exists.
*
* Note that wifi_wext_is_wifi() has only one caller which just verified
* that an interface with this name exists.
*/
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)

View file

@ -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,30 +183,19 @@ wifi_utils_deinit (WifiData *data)
}
gboolean
wifi_utils_is_wifi (const char *iface)
wifi_utils_is_wifi (int dirfd, const char *ifname)
{
char phy80211_path[NM_STRLEN ("/sys/class/net/123456789012345/phy80211\0") + 100 /*safety*/];
struct stat s;
g_return_val_if_fail (dirfd >= 0, FALSE);
g_return_val_if_fail (iface != 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);
if ((stat (phy80211_path, &s) == 0 && (s.st_mode & S_IFDIR)))
if (faccessat (dirfd, "phy80211", F_OK, 0) == 0)
return TRUE;
#if HAVE_WEXT
if (wifi_wext_is_wifi (iface))
if (wifi_wext_is_wifi (ifname))
return TRUE;
#endif
return FALSE;
}
/* OLPC Mesh-only functions */
guint32

View file

@ -28,7 +28,7 @@
typedef struct WifiData WifiData;
gboolean wifi_utils_is_wifi (const char *iface);
gboolean wifi_utils_is_wifi (int dirfd, const char *ifname);
WifiData *wifi_utils_init (const char *iface, int ifindex, gboolean check_scan);

View file

@ -148,7 +148,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);
}
@ -165,7 +165,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)

View file

@ -144,7 +144,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;

View file

@ -641,11 +641,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
@ -1017,7 +1017,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;

View file

@ -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);

View file

@ -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();