mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-29 23:10:18 +01:00
When adding an IPv4 address, kernel will also add a device-route. We don't want that route because it has the wrong metric. Instead, we add our own route (with a different metric) and remove the kernel-added one. This could be avoided if kernel would support an IPv4 address flag IFA_F_NOPREFIXROUTE like it does for IPv6 (see related bug rh#1221311). One important thing is, that we want don't want to manage the device-route on assumed devices. Note that this is correct behavior if "assumed" means "do-not-touch". If "assumed" means "seamlessly-takeover", then this is wrong. Imagine we get a new DHCP address. In this case, we would not manage the device-route on the assumed device. This cannot be fixed without splitting unmanaged/assumed with related bug bgo 746440. This is no regression as we would also not manage device-routes for assumed devices previously. We also don't want to remove the device-route if the user added it externally. Note that here we behave wrongly too, because we don't record externally added kernel routes in update_ip_config(). This still needs fixing. Let IPv4 device-routes also be managed by NMRouteManager. NMRouteManager has a list of all routes and can properly add, remove, and restore the device route as needed. One problem is, that the device-route does not get added immediately with the address. It only appears some time later. This is solved by NMRouteManager watching platform and if a matchin device-route shows up within a short time after configuring addresses, remove it. If the route appears after the short timeout, assume they were added for other reasons (e.g. by the user) and don't remove them. https://bugzilla.gnome.org/show_bug.cgi?id=751264 https://bugzilla.redhat.com/show_bug.cgi?id=1211287
3074 lines
89 KiB
C
3074 lines
89 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
|
/* nm-platform.c - Handle runtime kernel networking configuration
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Copyright (C) 2012 Red Hat, Inc.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <string.h>
|
|
#include <netlink/route/addr.h>
|
|
#include <netlink/route/rtnl.h>
|
|
|
|
#include "gsystem-local-alloc.h"
|
|
#include "NetworkManagerUtils.h"
|
|
#include "nm-utils.h"
|
|
#include "nm-platform.h"
|
|
#include "nm-platform-utils.h"
|
|
#include "NetworkManagerUtils.h"
|
|
#include "nm-logging.h"
|
|
#include "nm-enum-types.h"
|
|
#include "nm-core-internal.h"
|
|
|
|
#define ADDRESS_LIFETIME_PADDING 5
|
|
|
|
G_STATIC_ASSERT (sizeof ( ((NMPlatformLink *) NULL)->addr.data ) == NM_UTILS_HWADDR_LEN_MAX);
|
|
|
|
#define debug(...) nm_log_dbg (LOGD_PLATFORM, __VA_ARGS__)
|
|
|
|
#define NM_PLATFORM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_PLATFORM, NMPlatformPrivate))
|
|
|
|
G_DEFINE_TYPE (NMPlatform, nm_platform, G_TYPE_OBJECT)
|
|
|
|
/* NMPlatform signals */
|
|
enum {
|
|
SIGNAL_LINK_CHANGED,
|
|
SIGNAL_IP4_ADDRESS_CHANGED,
|
|
SIGNAL_IP6_ADDRESS_CHANGED,
|
|
SIGNAL_IP4_ROUTE_CHANGED,
|
|
SIGNAL_IP6_ROUTE_CHANGED,
|
|
LAST_SIGNAL
|
|
};
|
|
|
|
static guint signals[LAST_SIGNAL] = { 0 };
|
|
|
|
enum {
|
|
PROP_0,
|
|
PROP_REGISTER_SINGLETON,
|
|
LAST_PROP,
|
|
};
|
|
|
|
typedef struct {
|
|
gboolean register_singleton;
|
|
} NMPlatformPrivate;
|
|
|
|
/******************************************************************/
|
|
|
|
/* Singleton NMPlatform subclass instance and cached class object */
|
|
NM_DEFINE_SINGLETON_INSTANCE (NMPlatform);
|
|
|
|
NM_DEFINE_SINGLETON_WEAK_REF (NMPlatform);
|
|
|
|
/* Just always initialize a @klass instance. NM_PLATFORM_GET_CLASS()
|
|
* is only a plain read on the self instance, which the compiler
|
|
* like can optimize out.
|
|
*/
|
|
#define _CHECK_SELF_VOID(self, klass) \
|
|
NMPlatformClass *klass; \
|
|
do { \
|
|
g_return_if_fail (NM_IS_PLATFORM (self)); \
|
|
klass = NM_PLATFORM_GET_CLASS (self); \
|
|
(void) klass; \
|
|
} while (0)
|
|
|
|
#define _CHECK_SELF(self, klass, err_val) \
|
|
NMPlatformClass *klass; \
|
|
do { \
|
|
g_return_val_if_fail (NM_IS_PLATFORM (self), err_val); \
|
|
klass = NM_PLATFORM_GET_CLASS (self); \
|
|
(void) klass; \
|
|
} while (0)
|
|
|
|
/**
|
|
* nm_platform_setup:
|
|
* @instance: the #NMPlatform instance
|
|
*
|
|
* Failing to set up #NMPlatform singleton results in a fatal error,
|
|
* as well as trying to initialize it multiple times without freeing
|
|
* it.
|
|
*
|
|
* NetworkManager will typically use only one platform object during
|
|
* its run. Test programs might want to switch platform implementations,
|
|
* though.
|
|
*/
|
|
void
|
|
nm_platform_setup (NMPlatform *instance)
|
|
{
|
|
g_return_if_fail (NM_IS_PLATFORM (instance));
|
|
g_return_if_fail (!singleton_instance);
|
|
|
|
singleton_instance = instance;
|
|
|
|
nm_singleton_instance_weak_ref_register ();
|
|
|
|
nm_log_dbg (LOGD_CORE, "setup NMPlatform singleton (%p, %s)", instance, G_OBJECT_TYPE_NAME (instance));
|
|
}
|
|
|
|
/**
|
|
* nm_platform_get:
|
|
* @self: platform instance
|
|
*
|
|
* Retrieve #NMPlatform singleton. Use this whenever you want to connect to
|
|
* #NMPlatform signals. It is an error to call it before nm_platform_setup().
|
|
*
|
|
* Returns: (transfer none): The #NMPlatform singleton reference.
|
|
*/
|
|
NMPlatform *
|
|
nm_platform_get ()
|
|
{
|
|
g_assert (singleton_instance);
|
|
|
|
return singleton_instance;
|
|
}
|
|
|
|
NMPlatform *
|
|
nm_platform_try_get (void)
|
|
{
|
|
return singleton_instance;
|
|
}
|
|
|
|
/******************************************************************/
|
|
|
|
/**
|
|
* nm_platform_error_to_string:
|
|
* @error_code: the error code to stringify.
|
|
*
|
|
* Returns: A string representation of the error.
|
|
* For negative numbers, this function interprets
|
|
* the code as -errno.
|
|
*/
|
|
const char *
|
|
nm_platform_error_to_string (NMPlatformError error)
|
|
{
|
|
switch (error) {
|
|
case NM_PLATFORM_ERROR_SUCCESS:
|
|
return "success";
|
|
case NM_PLATFORM_ERROR_BUG:
|
|
return "bug";
|
|
case NM_PLATFORM_ERROR_UNSPECIFIED:
|
|
return "unspecified";
|
|
case NM_PLATFORM_ERROR_NOT_FOUND:
|
|
return "not-found";
|
|
case NM_PLATFORM_ERROR_EXISTS:
|
|
return "exists";
|
|
case NM_PLATFORM_ERROR_WRONG_TYPE:
|
|
return "wrong-type";
|
|
case NM_PLATFORM_ERROR_NOT_SLAVE:
|
|
return "not-slave";
|
|
case NM_PLATFORM_ERROR_NO_FIRMWARE:
|
|
return "no-firmware";
|
|
default:
|
|
if (error < 0)
|
|
return g_strerror (- ((int) error));
|
|
return "unknown";
|
|
}
|
|
}
|
|
|
|
/******************************************************************/
|
|
|
|
#define IFA_F_MANAGETEMPADDR_STR "mngtmpaddr"
|
|
#define IFA_F_NOPREFIXROUTE_STR "noprefixroute"
|
|
gboolean
|
|
nm_platform_check_support_libnl_extended_ifa_flags ()
|
|
{
|
|
static int supported = -1;
|
|
|
|
/* support for extended ifa-flags was added together
|
|
* with the IFA_F_MANAGETEMPADDR flag. So, check if libnl
|
|
* is able to parse this flag. */
|
|
if (supported == -1)
|
|
supported = rtnl_addr_str2flags (IFA_F_MANAGETEMPADDR_STR) == IFA_F_MANAGETEMPADDR;
|
|
|
|
return supported;
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_check_support_kernel_extended_ifa_flags (NMPlatform *self)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
if (!klass->check_support_kernel_extended_ifa_flags)
|
|
return FALSE;
|
|
|
|
return klass->check_support_kernel_extended_ifa_flags (self);
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_check_support_user_ipv6ll (NMPlatform *self)
|
|
{
|
|
static int supported = -1;
|
|
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
if (!klass->check_support_user_ipv6ll)
|
|
return FALSE;
|
|
|
|
if (supported < 0)
|
|
supported = klass->check_support_user_ipv6ll (self) ? 1 : 0;
|
|
return !!supported;
|
|
}
|
|
|
|
/**
|
|
* nm_platform_process_events:
|
|
* @self: platform instance
|
|
*
|
|
* Process pending events or handle pending delayed-actions.
|
|
* Effectively, this reads the netlink socket and processes
|
|
* new netlink messages. Possibly it will raise change signals.
|
|
*/
|
|
void
|
|
nm_platform_process_events (NMPlatform *self)
|
|
{
|
|
_CHECK_SELF_VOID (self, klass);
|
|
|
|
if (klass->process_events)
|
|
klass->process_events (self);
|
|
}
|
|
|
|
/******************************************************************/
|
|
|
|
/**
|
|
* nm_platform_sysctl_set:
|
|
* @self: platform instance
|
|
* @path: Absolute option path
|
|
* @value: Value to write
|
|
*
|
|
* This function is intended to be used for writing values to sysctl-style
|
|
* virtual runtime configuration files. This includes not only /proc/sys
|
|
* but also for example /sys/class.
|
|
*
|
|
* Returns: %TRUE on success.
|
|
*/
|
|
gboolean
|
|
nm_platform_sysctl_set (NMPlatform *self, 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);
|
|
g_return_val_if_fail (klass->sysctl_set, FALSE);
|
|
|
|
return klass->sysctl_set (self, path, value);
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_sysctl_set_ip6_hop_limit_safe (NMPlatform *self, const char *iface, int value)
|
|
{
|
|
const char *path;
|
|
gint64 cur;
|
|
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
/* the hop-limit provided via RA is uint8. */
|
|
if (value > 0xFF)
|
|
return FALSE;
|
|
|
|
/* don't allow unreasonable small values */
|
|
if (value < 10)
|
|
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);
|
|
|
|
/* only allow increasing the hop-limit to avoid DOS by an attacker
|
|
* setting a low hop-limit (CVE-2015-2924, rh#1209902) */
|
|
|
|
if (value < cur)
|
|
return FALSE;
|
|
if (value != cur) {
|
|
char svalue[20];
|
|
|
|
sprintf (svalue, "%d", value);
|
|
nm_platform_sysctl_set (self, path, svalue);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* nm_platform_sysctl_get:
|
|
* @self: platform instance
|
|
* @path: Absolute path to sysctl
|
|
*
|
|
* Returns: (transfer full): Contents of the virtual sysctl file.
|
|
*/
|
|
char *
|
|
nm_platform_sysctl_get (NMPlatform *self, const char *path)
|
|
{
|
|
_CHECK_SELF (self, klass, NULL);
|
|
|
|
g_return_val_if_fail (path, NULL);
|
|
g_return_val_if_fail (klass->sysctl_get, NULL);
|
|
|
|
return klass->sysctl_get (self, path);
|
|
}
|
|
|
|
/**
|
|
* nm_platform_sysctl_get_int32:
|
|
* @self: platform instance
|
|
* @path: Absolute path to sysctl
|
|
* @fallback: default value, if the content of path could not be read
|
|
* as decimal integer.
|
|
*
|
|
* Returns: contents of the sysctl file parsed as s32 integer, or
|
|
* @fallback on error. On error, %errno will be set to a non-zero
|
|
* value, on success %errno will be set to zero.
|
|
*/
|
|
gint32
|
|
nm_platform_sysctl_get_int32 (NMPlatform *self, const char *path, gint32 fallback)
|
|
{
|
|
return nm_platform_sysctl_get_int_checked (self, path, 10, G_MININT32, G_MAXINT32, fallback);
|
|
}
|
|
|
|
/**
|
|
* nm_platform_sysctl_get_int_checked:
|
|
* @self: platform instance
|
|
* @path: Absolute path to sysctl
|
|
* @base: base of numeric conversion
|
|
* @min: minimal value that is still valid
|
|
* @max: maximal value that is still valid
|
|
* @fallback: default value, if the content of path could not be read
|
|
* as valid integer.
|
|
*
|
|
* Returns: contents of the sysctl file parsed as s64 integer, or
|
|
* @fallback on error. On error, %errno will be set to a non-zero
|
|
* value. On success, %errno will be set to zero. The returned value
|
|
* will always be in the range between @min and @max
|
|
* (inclusive) or @fallback.
|
|
*/
|
|
gint64
|
|
nm_platform_sysctl_get_int_checked (NMPlatform *self, const char *path, guint base, gint64 min, gint64 max, gint64 fallback)
|
|
{
|
|
char *value = NULL;
|
|
gint32 ret;
|
|
|
|
_CHECK_SELF (self, klass, fallback);
|
|
|
|
g_return_val_if_fail (path, fallback);
|
|
|
|
if (path)
|
|
value = nm_platform_sysctl_get (self, path);
|
|
|
|
if (!value) {
|
|
errno = EINVAL;
|
|
return fallback;
|
|
}
|
|
|
|
ret = _nm_utils_ascii_str_to_int64 (value, base, min, max, fallback);
|
|
g_free (value);
|
|
return ret;
|
|
}
|
|
|
|
/******************************************************************/
|
|
|
|
/**
|
|
* nm_platform_link_get_all:
|
|
* self: platform instance
|
|
*
|
|
* Retrieve a snapshot of configuration for all links at once. The result is
|
|
* owned by the caller and should be freed with g_array_unref().
|
|
*/
|
|
GArray *
|
|
nm_platform_link_get_all (NMPlatform *self)
|
|
{
|
|
GArray *links, *result;
|
|
guint i, j, nresult;
|
|
GHashTable *unseen;
|
|
NMPlatformLink *item;
|
|
|
|
_CHECK_SELF (self, klass, NULL);
|
|
|
|
g_return_val_if_fail (klass->link_get_all, NULL);
|
|
|
|
links = klass->link_get_all (self);
|
|
|
|
if (!links || links->len == 0)
|
|
return links;
|
|
|
|
unseen = g_hash_table_new (g_direct_hash, g_direct_equal);
|
|
for (i = 0; i < links->len; i++) {
|
|
item = &g_array_index (links, NMPlatformLink, i);
|
|
|
|
if (item->ifindex <= 0 || g_hash_table_contains (unseen, GINT_TO_POINTER (item->ifindex))) {
|
|
g_warn_if_reached ();
|
|
item->ifindex = 0;
|
|
continue;
|
|
}
|
|
|
|
g_hash_table_insert (unseen, GINT_TO_POINTER (item->ifindex), NULL);
|
|
}
|
|
|
|
#ifndef G_DISABLE_ASSERT
|
|
/* Ensure that link_get_all returns a consistent and valid result. */
|
|
for (i = 0; i < links->len; i++) {
|
|
item = &g_array_index (links, NMPlatformLink, i);
|
|
|
|
if (!item->ifindex)
|
|
continue;
|
|
if (item->master != 0) {
|
|
g_warn_if_fail (item->master > 0);
|
|
g_warn_if_fail (item->master != item->ifindex);
|
|
g_warn_if_fail (g_hash_table_contains (unseen, GINT_TO_POINTER (item->master)));
|
|
}
|
|
if (item->parent != 0) {
|
|
g_warn_if_fail (item->parent > 0);
|
|
g_warn_if_fail (item->parent != item->ifindex);
|
|
g_warn_if_fail (g_hash_table_contains (unseen, GINT_TO_POINTER (item->parent)));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* Re-order the links list such that children/slaves come after all ancestors */
|
|
nresult = g_hash_table_size (unseen);
|
|
result = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformLink), nresult);
|
|
g_array_set_size (result, nresult);
|
|
|
|
j = 0;
|
|
do {
|
|
gboolean found_something = FALSE;
|
|
guint first_idx = G_MAXUINT;
|
|
|
|
for (i = 0; i < links->len; i++) {
|
|
item = &g_array_index (links, NMPlatformLink, i);
|
|
|
|
if (!item->ifindex)
|
|
continue;
|
|
|
|
if (first_idx == G_MAXUINT)
|
|
first_idx = i;
|
|
|
|
g_assert (g_hash_table_contains (unseen, GINT_TO_POINTER (item->ifindex)));
|
|
|
|
if (item->master > 0 && g_hash_table_contains (unseen, GINT_TO_POINTER (item->master)))
|
|
continue;
|
|
if (item->parent > 0 && g_hash_table_contains (unseen, GINT_TO_POINTER (item->parent)))
|
|
continue;
|
|
|
|
g_hash_table_remove (unseen, GINT_TO_POINTER (item->ifindex));
|
|
g_array_index (result, NMPlatformLink, j++) = *item;
|
|
item->ifindex = 0;
|
|
found_something = TRUE;
|
|
}
|
|
|
|
if (!found_something) {
|
|
/* there is a circle, pop the first (remaining) element from the list */
|
|
g_warn_if_reached ();
|
|
item = &g_array_index (links, NMPlatformLink, first_idx);
|
|
|
|
g_hash_table_remove (unseen, GINT_TO_POINTER (item->ifindex));
|
|
g_array_index (result, NMPlatformLink, j++) = *item;
|
|
item->ifindex = 0;
|
|
}
|
|
} while (j < nresult);
|
|
|
|
g_hash_table_destroy (unseen);
|
|
g_array_free (links, TRUE);
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_get:
|
|
* @self: platform instance
|
|
* @ifindex: ifindex of the link
|
|
*
|
|
* Lookup the internal NMPlatformLink object.
|
|
*
|
|
* Returns: %NULL, if such a link exists or the internal
|
|
* platform link object. Do not modify the returned value.
|
|
* Also, be aware that any subsequent platform call might
|
|
* invalidated/modify the returned instance.
|
|
**/
|
|
const NMPlatformLink *
|
|
nm_platform_link_get (NMPlatform *self, int ifindex)
|
|
{
|
|
_CHECK_SELF (self, klass, NULL);
|
|
|
|
if (ifindex > 0)
|
|
return klass->link_get (self, ifindex);
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_get_by_ifname:
|
|
* @self: platform instance
|
|
* @ifname: the ifname
|
|
*
|
|
* Returns: the first #NMPlatformLink instance with the given name.
|
|
**/
|
|
const NMPlatformLink *
|
|
nm_platform_link_get_by_ifname (NMPlatform *self, const char *ifname)
|
|
{
|
|
_CHECK_SELF (self, klass, NULL);
|
|
|
|
if (ifname && *ifname)
|
|
return klass->link_get_by_ifname (self, ifname);
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_get_by_address:
|
|
* @self: platform instance
|
|
* @address: a pointer to the binary hardware address
|
|
* @length: the size of @address in bytes
|
|
*
|
|
* Returns: the first #NMPlatformLink object with a matching
|
|
* address.
|
|
**/
|
|
const NMPlatformLink *
|
|
nm_platform_link_get_by_address (NMPlatform *self,
|
|
gconstpointer address,
|
|
size_t length)
|
|
{
|
|
_CHECK_SELF (self, klass, NULL);
|
|
|
|
g_return_val_if_fail (length == 0 || address, NULL);
|
|
if (length > 0) {
|
|
if (length > NM_UTILS_HWADDR_LEN_MAX)
|
|
g_return_val_if_reached (NULL);
|
|
return klass->link_get_by_address (self, address, length);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static NMPlatformError
|
|
_link_add_check_existing (NMPlatform *self, const char *name, NMLinkType type, NMPlatformLink *out_link)
|
|
{
|
|
const NMPlatformLink *pllink;
|
|
|
|
pllink = nm_platform_link_get_by_ifname (self, name);
|
|
if (pllink) {
|
|
gboolean wrong_type;
|
|
|
|
wrong_type = type != NM_LINK_TYPE_NONE && pllink->type != type;
|
|
debug ("link: skip adding link due to existing interface '%s' of type %s%s%s",
|
|
name,
|
|
nm_link_type_to_string (pllink->type),
|
|
wrong_type ? ", expected " : "",
|
|
wrong_type ? nm_link_type_to_string (type) : "");
|
|
if (out_link)
|
|
*out_link = *pllink;
|
|
if (wrong_type)
|
|
return NM_PLATFORM_ERROR_WRONG_TYPE;
|
|
return NM_PLATFORM_ERROR_EXISTS;
|
|
}
|
|
return NM_PLATFORM_ERROR_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_add:
|
|
* @self: platform instance
|
|
* @name: Interface name
|
|
* @type: Interface type
|
|
* @address: (allow-none): set the mac address of the link
|
|
* @address_len: the length of the @address
|
|
* @out_link: on success, the link object
|
|
*
|
|
* Add a software interface. If the interface already exists and is of type
|
|
* @type, return NM_PLATFORM_ERROR_EXISTS and returns the link
|
|
* in @out_link. If the interface already exists and is not of type @type,
|
|
* return NM_PLATFORM_ERROR_WRONG_TYPE.
|
|
*
|
|
* Any link-changed ADDED signal will be emitted directly, before this
|
|
* function finishes.
|
|
*
|
|
* Returns: the error reason or NM_PLATFORM_ERROR_SUCCESS.
|
|
*/
|
|
static NMPlatformError
|
|
nm_platform_link_add (NMPlatform *self,
|
|
const char *name,
|
|
NMLinkType type,
|
|
const void *address,
|
|
size_t address_len,
|
|
NMPlatformLink *out_link)
|
|
{
|
|
NMPlatformError plerr;
|
|
|
|
_CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG);
|
|
|
|
g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG);
|
|
g_return_val_if_fail (klass->link_add, NM_PLATFORM_ERROR_BUG);
|
|
g_return_val_if_fail ( (address != NULL) ^ (address_len == 0) , NM_PLATFORM_ERROR_BUG);
|
|
|
|
plerr = _link_add_check_existing (self, name, type, out_link);
|
|
if (plerr != NM_PLATFORM_ERROR_SUCCESS)
|
|
return plerr;
|
|
|
|
debug ("link: adding %s '%s'", nm_link_type_to_string (type), name);
|
|
if (!klass->link_add (self, name, type, address, address_len, out_link))
|
|
return NM_PLATFORM_ERROR_UNSPECIFIED;
|
|
return NM_PLATFORM_ERROR_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* nm_platform_dummy_add:
|
|
* @self: platform instance
|
|
* @name: New interface name
|
|
* @out_link: on success, the link object
|
|
*
|
|
* Create a software ethernet-like interface
|
|
*/
|
|
NMPlatformError
|
|
nm_platform_dummy_add (NMPlatform *self, const char *name, NMPlatformLink *out_link)
|
|
{
|
|
return nm_platform_link_add (self, name, NM_LINK_TYPE_DUMMY, NULL, 0, out_link);
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_delete:
|
|
* @self: platform instance
|
|
* @ifindex: Interface index
|
|
*/
|
|
gboolean
|
|
nm_platform_link_delete (NMPlatform *self, int ifindex)
|
|
{
|
|
const NMPlatformLink *pllink;
|
|
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
pllink = nm_platform_link_get (self, ifindex);
|
|
if (!pllink)
|
|
return FALSE;
|
|
|
|
debug ("link: deleting '%s' (%d)", pllink->name, ifindex);
|
|
return klass->link_delete (self, ifindex);
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_get_index:
|
|
* @self: platform instance
|
|
* @name: Interface name
|
|
*
|
|
* Returns: The interface index corresponding to the given interface name
|
|
* or 0. Inteface name is owned by #NMPlatform, don't free it.
|
|
*/
|
|
int
|
|
nm_platform_link_get_ifindex (NMPlatform *self, const char *name)
|
|
{
|
|
const NMPlatformLink *pllink;
|
|
|
|
pllink = nm_platform_link_get_by_ifname (self, name);
|
|
return pllink ? pllink->ifindex : 0;
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_get_name:
|
|
* @self: platform instance
|
|
* @name: Interface name
|
|
*
|
|
* Returns: The interface name corresponding to the given interface index
|
|
* or %NULL.
|
|
*/
|
|
const char *
|
|
nm_platform_link_get_name (NMPlatform *self, int ifindex)
|
|
{
|
|
const NMPlatformLink *pllink;
|
|
|
|
_CHECK_SELF (self, klass, NULL);
|
|
|
|
pllink = nm_platform_link_get (self, ifindex);
|
|
return pllink ? pllink->name : NULL;
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_get_type:
|
|
* @self: platform instance
|
|
* @ifindex: Interface index.
|
|
*
|
|
* Returns: Link type constant as defined in nm-platform.h. On error,
|
|
* NM_LINK_TYPE_NONE is returned.
|
|
*/
|
|
NMLinkType
|
|
nm_platform_link_get_type (NMPlatform *self, int ifindex)
|
|
{
|
|
const NMPlatformLink *pllink;
|
|
|
|
_CHECK_SELF (self, klass, NM_LINK_TYPE_NONE);
|
|
|
|
pllink = nm_platform_link_get (self, ifindex);
|
|
return pllink ? pllink->type : NM_LINK_TYPE_NONE;
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_get_type_name:
|
|
* @self: platform instance
|
|
* @ifindex: Interface index.
|
|
*
|
|
* Returns: A string describing the type of link. In some cases this
|
|
* may be more specific than nm_platform_link_get_type(), but in
|
|
* other cases it may not. On error, %NULL is returned.
|
|
*/
|
|
const char *
|
|
nm_platform_link_get_type_name (NMPlatform *self, int ifindex)
|
|
{
|
|
_CHECK_SELF (self, klass, NULL);
|
|
|
|
g_return_val_if_fail (klass->link_get_type_name, NULL);
|
|
|
|
return klass->link_get_type_name (self, ifindex);
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_get_unmanaged:
|
|
* @self: platform instance
|
|
* @ifindex: interface index
|
|
* @unmanaged: management status (in case %TRUE is returned)
|
|
*
|
|
* Returns: %TRUE if platform overrides NM default-unmanaged status,
|
|
* %FALSE otherwise (with @unmanaged unmodified).
|
|
*/
|
|
gboolean
|
|
nm_platform_link_get_unmanaged (NMPlatform *self, int ifindex, gboolean *unmanaged)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
if (klass->link_get_unmanaged)
|
|
return klass->link_get_unmanaged (self, ifindex, unmanaged);
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_is_software:
|
|
* @self: platform instance
|
|
* @ifindex: Interface index.
|
|
*
|
|
* Returns: %TRUE if ifindex belongs to a software interface, not backed by
|
|
* a physical device.
|
|
*/
|
|
gboolean
|
|
nm_platform_link_is_software (NMPlatform *self, int ifindex)
|
|
{
|
|
return (nm_platform_link_get_type (self, ifindex) & 0x10000);
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_supports_slaves:
|
|
* @self: platform instance
|
|
* @ifindex: Interface index.
|
|
*
|
|
* Returns: %TRUE if ifindex belongs to an interface capable of enslaving
|
|
* other interfaces.
|
|
*/
|
|
gboolean
|
|
nm_platform_link_supports_slaves (NMPlatform *self, int ifindex)
|
|
{
|
|
return (nm_platform_link_get_type (self, ifindex) & 0x20000);
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_refresh:
|
|
* @self: platform instance
|
|
* @ifindex: Interface index
|
|
*
|
|
* Reload the cache for ifindex synchronously.
|
|
*/
|
|
gboolean
|
|
nm_platform_link_refresh (NMPlatform *self, int ifindex)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex > 0, FALSE);
|
|
|
|
if (klass->link_refresh)
|
|
return klass->link_refresh (self, ifindex);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static guint32
|
|
_link_get_flags (NMPlatform *self, int ifindex)
|
|
{
|
|
const NMPlatformLink *pllink;
|
|
|
|
pllink = nm_platform_link_get (self, ifindex);
|
|
return pllink ? pllink->flags : IFF_NOARP;
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_is_up:
|
|
* @self: platform instance
|
|
* @ifindex: Interface index
|
|
*
|
|
* Check if the interface is up.
|
|
*/
|
|
gboolean
|
|
nm_platform_link_is_up (NMPlatform *self, int ifindex)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
return NM_FLAGS_HAS (_link_get_flags (self, ifindex), IFF_UP);
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_is_connected:
|
|
* @self: platform instance
|
|
* @ifindex: Interface index
|
|
*
|
|
* Check if the interface is connected.
|
|
*/
|
|
gboolean
|
|
nm_platform_link_is_connected (NMPlatform *self, int ifindex)
|
|
{
|
|
const NMPlatformLink *pllink;
|
|
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
pllink = nm_platform_link_get (self, ifindex);
|
|
return pllink ? pllink->connected : FALSE;
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_uses_arp:
|
|
* @self: platform instance
|
|
* @ifindex: Interface index
|
|
*
|
|
* Check if the interface is configured to use ARP.
|
|
*/
|
|
gboolean
|
|
nm_platform_link_uses_arp (NMPlatform *self, int ifindex)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
return !NM_FLAGS_HAS (_link_get_flags (self, ifindex), IFF_NOARP);
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_get_ipv6_token:
|
|
* @self: platform instance
|
|
* @ifindex: Interface index
|
|
* @iid: Tokenized interface identifier
|
|
*
|
|
* Returns IPv6 tokenized interface identifier. If the platform or OS doesn't
|
|
* support IPv6 tokenized interface identifiers, or the token is not set
|
|
* this call will fail and return %FALSE.
|
|
*
|
|
* Returns: %TRUE a tokenized identifier was available
|
|
*/
|
|
gboolean
|
|
nm_platform_link_get_ipv6_token (NMPlatform *self, int ifindex, NMUtilsIPv6IfaceId *iid)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex >= 0, FALSE);
|
|
g_return_val_if_fail (iid, FALSE);
|
|
|
|
#if HAVE_LIBNL_INET6_TOKEN
|
|
{
|
|
const NMPlatformLink *pllink;
|
|
|
|
pllink = nm_platform_link_get (self, ifindex);
|
|
if (pllink && pllink->inet6_token.is_valid) {
|
|
*iid = pllink->inet6_token.iid;
|
|
return TRUE;
|
|
}
|
|
}
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
|
|
const char *
|
|
nm_platform_link_get_udi (NMPlatform *self, int ifindex)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex >= 0, NULL);
|
|
|
|
if (klass->link_get_udi)
|
|
return klass->link_get_udi (self, ifindex);
|
|
return NULL;
|
|
}
|
|
|
|
GObject *
|
|
nm_platform_link_get_udev_device (NMPlatform *self, int ifindex)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex >= 0, NULL);
|
|
|
|
if (klass->link_get_udev_device)
|
|
return klass->link_get_udev_device (self, ifindex);
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_get_user_ip6vll_enabled:
|
|
* @self: platform instance
|
|
* @ifindex: Interface index
|
|
*
|
|
* Check whether NM handles IPv6LL address creation for the link. If the
|
|
* platform or OS doesn't support changing the IPv6LL address mode, this call
|
|
* will fail and return %FALSE.
|
|
*
|
|
* Returns: %TRUE if NM handles the IPv6LL address for @ifindex
|
|
*/
|
|
gboolean
|
|
nm_platform_link_get_user_ipv6ll_enabled (NMPlatform *self, int ifindex)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex >= 0, FALSE);
|
|
|
|
#if HAVE_LIBNL_INET6_ADDR_GEN_MODE
|
|
{
|
|
const NMPlatformLink *pllink;
|
|
|
|
pllink = nm_platform_link_get (self, ifindex);
|
|
if (pllink && pllink->inet6_addr_gen_mode_inv)
|
|
return _nm_platform_uint8_inv (pllink->inet6_addr_gen_mode_inv) == IN6_ADDR_GEN_MODE_NONE;
|
|
}
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/**
|
|
* nm_platform_link_set_user_ip6vll_enabled:
|
|
* @self: platform instance
|
|
* @ifindex: Interface index
|
|
*
|
|
* Set whether NM handles IPv6LL address creation for the link. If the
|
|
* platform or OS doesn't support changing the IPv6LL address mode, this call
|
|
* will fail and return %FALSE.
|
|
*
|
|
* Returns: %TRUE if the operation was successful, %FALSE if it failed.
|
|
*/
|
|
gboolean
|
|
nm_platform_link_set_user_ipv6ll_enabled (NMPlatform *self, int ifindex, gboolean enabled)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex >= 0, FALSE);
|
|
g_return_val_if_fail (klass->check_support_user_ipv6ll, FALSE);
|
|
|
|
if (klass->link_set_user_ipv6ll_enabled)
|
|
return klass->link_set_user_ipv6ll_enabled (self, ifindex, enabled);
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_set_address:
|
|
* @self: platform instance
|
|
* @ifindex: Interface index
|
|
* @address: The new MAC address
|
|
*
|
|
* Set interface MAC address.
|
|
*/
|
|
gboolean
|
|
nm_platform_link_set_address (NMPlatform *self, int ifindex, gconstpointer address, size_t length)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex > 0, FALSE);
|
|
g_return_val_if_fail (address, FALSE);
|
|
g_return_val_if_fail (length > 0, FALSE);
|
|
g_return_val_if_fail (klass->link_set_address, FALSE);
|
|
|
|
debug ("link: setting '%s' (%d) hardware address", nm_platform_link_get_name (self, ifindex), ifindex);
|
|
return klass->link_set_address (self, ifindex, address, length);
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_get_address:
|
|
* @self: platform instance
|
|
* @ifindex: Interface index
|
|
* @length: Pointer to a variable to store address length
|
|
*
|
|
* Returns: the interface hardware address as an array of bytes of
|
|
* length @length.
|
|
*/
|
|
gconstpointer
|
|
nm_platform_link_get_address (NMPlatform *self, int ifindex, size_t *length)
|
|
{
|
|
const NMPlatformLink *pllink;
|
|
gconstpointer a = NULL;
|
|
guint8 l = 0;
|
|
|
|
_CHECK_SELF (self, klass, NULL);
|
|
|
|
if (length)
|
|
*length = 0;
|
|
|
|
g_return_val_if_fail (ifindex > 0, NULL);
|
|
|
|
pllink = nm_platform_link_get (self, ifindex);
|
|
if (pllink && pllink->addr.len > 0) {
|
|
if (pllink->addr.len > NM_UTILS_HWADDR_LEN_MAX) {
|
|
if (length)
|
|
*length = 0;
|
|
g_return_val_if_reached (NULL);
|
|
}
|
|
a = pllink->addr.data;
|
|
l = pllink->addr.len;
|
|
}
|
|
|
|
if (length)
|
|
*length = l;
|
|
return a;
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_get_permanent_address:
|
|
* @self: platform instance
|
|
* @ifindex: Interface index
|
|
* @buf: buffer of at least %NM_UTILS_HWADDR_LEN_MAX bytes, on success
|
|
* the permanent hardware address
|
|
* @length: Pointer to a variable to store address length
|
|
*
|
|
* Returns: %TRUE on success, %FALSE on failure to read the permanent hardware
|
|
* address.
|
|
*/
|
|
gboolean
|
|
nm_platform_link_get_permanent_address (NMPlatform *self, int ifindex, guint8 *buf, size_t *length)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
if (length)
|
|
*length = 0;
|
|
|
|
g_return_val_if_fail (ifindex > 0, FALSE);
|
|
g_return_val_if_fail (buf, FALSE);
|
|
g_return_val_if_fail (length, FALSE);
|
|
|
|
if (klass->link_get_permanent_address)
|
|
return klass->link_get_permanent_address (self, ifindex, buf, length);
|
|
return FALSE;
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_link_supports_carrier_detect (NMPlatform *self, int ifindex)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex >= 0, FALSE);
|
|
g_return_val_if_fail (klass->link_supports_carrier_detect, FALSE);
|
|
|
|
return klass->link_supports_carrier_detect (self, ifindex);
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_link_supports_vlans (NMPlatform *self, int ifindex)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex >= 0, FALSE);
|
|
g_return_val_if_fail (klass->link_supports_vlans, FALSE);
|
|
|
|
return klass->link_supports_vlans (self, ifindex);
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_set_up:
|
|
* @self: platform instance
|
|
* @ifindex: Interface index
|
|
* @out_no_firmware: (allow-none): if the failure reason is due to missing firmware.
|
|
*
|
|
* Bring the interface up.
|
|
*/
|
|
gboolean
|
|
nm_platform_link_set_up (NMPlatform *self, int ifindex, gboolean *out_no_firmware)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex > 0, FALSE);
|
|
g_return_val_if_fail (klass->link_set_up, FALSE);
|
|
|
|
debug ("link: setting up '%s' (%d)", nm_platform_link_get_name (self, ifindex), ifindex);
|
|
return klass->link_set_up (self, ifindex, out_no_firmware);
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_set_down:
|
|
* @self: platform instance
|
|
* @ifindex: Interface index
|
|
*
|
|
* Take the interface down.
|
|
*/
|
|
gboolean
|
|
nm_platform_link_set_down (NMPlatform *self, int ifindex)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex > 0, FALSE);
|
|
g_return_val_if_fail (klass->link_set_down, FALSE);
|
|
|
|
debug ("link: setting down '%s' (%d)", nm_platform_link_get_name (self, ifindex), ifindex);
|
|
return klass->link_set_down (self, ifindex);
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_set_arp:
|
|
* @self: platform instance
|
|
* @ifindex: Interface index
|
|
*
|
|
* Enable ARP on the interface.
|
|
*/
|
|
gboolean
|
|
nm_platform_link_set_arp (NMPlatform *self, int ifindex)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex >= 0, FALSE);
|
|
g_return_val_if_fail (klass->link_set_arp, FALSE);
|
|
|
|
debug ("link: setting arp '%s' (%d)", nm_platform_link_get_name (self, ifindex), ifindex);
|
|
return klass->link_set_arp (self, ifindex);
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_set_noarp:
|
|
* @self: platform instance
|
|
* @ifindex: Interface index
|
|
*
|
|
* Disable ARP on the interface.
|
|
*/
|
|
gboolean
|
|
nm_platform_link_set_noarp (NMPlatform *self, int ifindex)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex >= 0, FALSE);
|
|
g_return_val_if_fail (klass->link_set_noarp, FALSE);
|
|
|
|
debug ("link: setting noarp '%s' (%d)", nm_platform_link_get_name (self, ifindex), ifindex);
|
|
return klass->link_set_noarp (self, ifindex);
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_set_mtu:
|
|
* @self: platform instance
|
|
* @ifindex: Interface index
|
|
* @mtu: The new MTU value
|
|
*
|
|
* Set interface MTU.
|
|
*/
|
|
gboolean
|
|
nm_platform_link_set_mtu (NMPlatform *self, int ifindex, guint32 mtu)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex >= 0, FALSE);
|
|
g_return_val_if_fail (mtu > 0, FALSE);
|
|
g_return_val_if_fail (klass->link_set_mtu, FALSE);
|
|
|
|
debug ("link: setting '%s' (%d) mtu %"G_GUINT32_FORMAT, nm_platform_link_get_name (self, ifindex), ifindex, mtu);
|
|
return klass->link_set_mtu (self, ifindex, mtu);
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_get_mtu:
|
|
* @self: platform instance
|
|
* @ifindex: Interface index
|
|
*
|
|
* Returns: MTU value for the interface or 0 on error.
|
|
*/
|
|
guint32
|
|
nm_platform_link_get_mtu (NMPlatform *self, int ifindex)
|
|
{
|
|
const NMPlatformLink *pllink;
|
|
|
|
_CHECK_SELF (self, klass, 0);
|
|
|
|
pllink = nm_platform_link_get (self, ifindex);
|
|
return pllink ? pllink->mtu : 0;
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_get_physical_port_id:
|
|
* @self: platform instance
|
|
* @ifindex: Interface index
|
|
*
|
|
* The physical port ID, if present, indicates some unique identifier of
|
|
* the parent interface (eg, the physical port of which this link is a child).
|
|
* Two links that report the same physical port ID can be assumed to be
|
|
* children of the same physical port and may share resources that limit
|
|
* their abilities.
|
|
*
|
|
* Returns: physical port ID for the interface, or %NULL on error
|
|
* or if the interface has no physical port ID.
|
|
*/
|
|
char *
|
|
nm_platform_link_get_physical_port_id (NMPlatform *self, int ifindex)
|
|
{
|
|
_CHECK_SELF (self, klass, NULL);
|
|
|
|
g_return_val_if_fail (ifindex >= 0, NULL);
|
|
|
|
if (klass->link_get_physical_port_id)
|
|
return klass->link_get_physical_port_id (self, ifindex);
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_get_dev_id:
|
|
* @self: platform instance
|
|
* @ifindex: Interface index
|
|
*
|
|
* In contrast to the physical device ID (which indicates which parent a
|
|
* child has) the device ID differentiates sibling devices that may share
|
|
* the same MAC address.
|
|
*
|
|
* Returns: device ID for the interface, or 0 on error or if the
|
|
* interface has no device ID.
|
|
*/
|
|
guint
|
|
nm_platform_link_get_dev_id (NMPlatform *self, int ifindex)
|
|
{
|
|
_CHECK_SELF (self, klass, 0);
|
|
|
|
g_return_val_if_fail (ifindex >= 0, 0);
|
|
|
|
if (klass->link_get_dev_id)
|
|
return klass->link_get_dev_id (self, ifindex);
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_get_wake_onlan:
|
|
* @self: platform instance
|
|
* @ifindex: Interface index
|
|
*
|
|
* Returns: the "Wake-on-LAN" status for @ifindex.
|
|
*/
|
|
gboolean
|
|
nm_platform_link_get_wake_on_lan (NMPlatform *self, int ifindex)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex >= 0, FALSE);
|
|
|
|
if (klass->link_get_wake_on_lan)
|
|
return klass->link_get_wake_on_lan (self, ifindex);
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_get_driver_info:
|
|
* @self: platform instance
|
|
* @ifindex: Interface index
|
|
* @out_driver_name: (transfer full): on success, the driver name if available
|
|
* @out_driver_version: (transfer full): on success, the driver version if available
|
|
* @out_fw_version: (transfer full): on success, the firmware version if available
|
|
*
|
|
* Returns: %TRUE on success (though @out_driver_name, @out_driver_version and
|
|
* @out_fw_version can be %NULL if no information was available), %FALSE on
|
|
* failure.
|
|
*/
|
|
gboolean
|
|
nm_platform_link_get_driver_info (NMPlatform *self,
|
|
int ifindex,
|
|
char **out_driver_name,
|
|
char **out_driver_version,
|
|
char **out_fw_version)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex >= 0, FALSE);
|
|
g_return_val_if_fail (klass->link_get_driver_info, FALSE);
|
|
|
|
return klass->link_get_driver_info (self,
|
|
ifindex,
|
|
out_driver_name,
|
|
out_driver_version,
|
|
out_fw_version);
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_enslave:
|
|
* @self: platform instance
|
|
* @master: Interface index of the master
|
|
* @slave: Interface index of the slave
|
|
*
|
|
* Enslave @slave to @master.
|
|
*/
|
|
gboolean
|
|
nm_platform_link_enslave (NMPlatform *self, int master, int slave)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (master > 0, FALSE);
|
|
g_return_val_if_fail (slave> 0, FALSE);
|
|
g_return_val_if_fail (klass->link_enslave, FALSE);
|
|
|
|
debug ("link: enslaving '%s' (%d) to master '%s' (%d)",
|
|
nm_platform_link_get_name (self, slave), slave,
|
|
nm_platform_link_get_name (self, master), master);
|
|
return klass->link_enslave (self, master, slave);
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_release:
|
|
* @self: platform instance
|
|
* @master: Interface index of the master
|
|
* @slave: Interface index of the slave
|
|
*
|
|
* Release @slave from @master.
|
|
*/
|
|
gboolean
|
|
nm_platform_link_release (NMPlatform *self, int master, int slave)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (master > 0, FALSE);
|
|
g_return_val_if_fail (slave > 0, FALSE);
|
|
g_return_val_if_fail (klass->link_release, FALSE);
|
|
|
|
if (nm_platform_link_get_master (self, slave) != master)
|
|
return FALSE;
|
|
|
|
debug ("link: releasing '%s' (%d) from master '%s' (%d)",
|
|
nm_platform_link_get_name (self, slave), slave,
|
|
nm_platform_link_get_name (self, master), master);
|
|
return klass->link_release (self, master, slave);
|
|
}
|
|
|
|
/**
|
|
* nm_platform_link_get_master:
|
|
* @self: platform instance
|
|
* @slave: Interface index of the slave.
|
|
*
|
|
* Returns: Interfase index of the slave's master.
|
|
*/
|
|
int
|
|
nm_platform_link_get_master (NMPlatform *self, int slave)
|
|
{
|
|
const NMPlatformLink *pllink;
|
|
|
|
_CHECK_SELF (self, klass, 0);
|
|
|
|
g_return_val_if_fail (slave >= 0, FALSE);
|
|
|
|
pllink = nm_platform_link_get (self, slave);
|
|
return pllink ? pllink->master : 0;
|
|
}
|
|
|
|
/**
|
|
* nm_platform_bridge_add:
|
|
* @self: platform instance
|
|
* @name: New interface name
|
|
* @address: (allow-none): set the mac address of the new bridge
|
|
* @address_len: the length of the @address
|
|
* @out_link: on success, the link object
|
|
*
|
|
* Create a software bridge.
|
|
*/
|
|
NMPlatformError
|
|
nm_platform_bridge_add (NMPlatform *self,
|
|
const char *name,
|
|
const void *address,
|
|
size_t address_len,
|
|
NMPlatformLink *out_link)
|
|
{
|
|
return nm_platform_link_add (self, name, NM_LINK_TYPE_BRIDGE, address, address_len, out_link);
|
|
}
|
|
|
|
/**
|
|
* nm_platform_bond_add:
|
|
* @self: platform instance
|
|
* @name: New interface name
|
|
* @out_link: on success, the link object
|
|
*
|
|
* Create a software bonding device.
|
|
*/
|
|
NMPlatformError
|
|
nm_platform_bond_add (NMPlatform *self, const char *name, NMPlatformLink *out_link)
|
|
{
|
|
return nm_platform_link_add (self, name, NM_LINK_TYPE_BOND, NULL, 0, out_link);
|
|
}
|
|
|
|
/**
|
|
* nm_platform_team_add:
|
|
* @self: platform instance
|
|
* @name: New interface name
|
|
* @out_link: on success, the link object
|
|
*
|
|
* Create a software teaming device.
|
|
*/
|
|
NMPlatformError
|
|
nm_platform_team_add (NMPlatform *self, const char *name, NMPlatformLink *out_link)
|
|
{
|
|
return nm_platform_link_add (self, name, NM_LINK_TYPE_TEAM, NULL, 0, out_link);
|
|
}
|
|
|
|
/**
|
|
* nm_platform_vlan_add:
|
|
* @self: platform instance
|
|
* @name: New interface name
|
|
* @vlanid: VLAN identifier
|
|
* @vlanflags: VLAN flags from libnm
|
|
* @out_link: on success, the link object
|
|
*
|
|
* Create a software VLAN device.
|
|
*/
|
|
NMPlatformError
|
|
nm_platform_vlan_add (NMPlatform *self,
|
|
const char *name,
|
|
int parent,
|
|
int vlanid,
|
|
guint32 vlanflags,
|
|
NMPlatformLink *out_link)
|
|
{
|
|
NMPlatformError plerr;
|
|
|
|
_CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG);
|
|
|
|
g_return_val_if_fail (parent >= 0, NM_PLATFORM_ERROR_BUG);
|
|
g_return_val_if_fail (vlanid >= 0, NM_PLATFORM_ERROR_BUG);
|
|
g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG);
|
|
g_return_val_if_fail (klass->vlan_add, NM_PLATFORM_ERROR_BUG);
|
|
|
|
plerr = _link_add_check_existing (self, name, NM_LINK_TYPE_VLAN, out_link);
|
|
if (plerr != NM_PLATFORM_ERROR_SUCCESS)
|
|
return plerr;
|
|
|
|
debug ("link: adding vlan '%s' parent %d vlanid %d vlanflags %x",
|
|
name, parent, vlanid, vlanflags);
|
|
if (!klass->vlan_add (self, name, parent, vlanid, vlanflags, out_link))
|
|
return NM_PLATFORM_ERROR_UNSPECIFIED;
|
|
return NM_PLATFORM_ERROR_SUCCESS;
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_master_set_option (NMPlatform *self, int ifindex, const char *option, const char *value)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex > 0, FALSE);
|
|
g_return_val_if_fail (option, FALSE);
|
|
g_return_val_if_fail (value, FALSE);
|
|
g_return_val_if_fail (klass->master_set_option, FALSE);
|
|
|
|
return klass->master_set_option (self, ifindex, option, value);
|
|
}
|
|
|
|
char *
|
|
nm_platform_master_get_option (NMPlatform *self, int ifindex, const char *option)
|
|
{
|
|
_CHECK_SELF (self, klass, NULL);
|
|
|
|
g_return_val_if_fail (ifindex > 0, FALSE);
|
|
g_return_val_if_fail (option, FALSE);
|
|
g_return_val_if_fail (klass->master_set_option, FALSE);
|
|
|
|
return klass->master_get_option (self, ifindex, option);
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_slave_set_option (NMPlatform *self, int ifindex, const char *option, const char *value)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex > 0, FALSE);
|
|
g_return_val_if_fail (option, FALSE);
|
|
g_return_val_if_fail (value, FALSE);
|
|
g_return_val_if_fail (klass->slave_set_option, FALSE);
|
|
|
|
return klass->slave_set_option (self, ifindex, option, value);
|
|
}
|
|
|
|
char *
|
|
nm_platform_slave_get_option (NMPlatform *self, int ifindex, const char *option)
|
|
{
|
|
_CHECK_SELF (self, klass, NULL);
|
|
|
|
g_return_val_if_fail (ifindex > 0, FALSE);
|
|
g_return_val_if_fail (option, FALSE);
|
|
g_return_val_if_fail (klass->slave_set_option, FALSE);
|
|
|
|
return klass->slave_get_option (self, ifindex, option);
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_vlan_get_info (NMPlatform *self, int ifindex, int *parent, int *vlanid)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (klass->vlan_get_info, FALSE);
|
|
|
|
if (parent)
|
|
*parent = 0;
|
|
if (vlanid)
|
|
*vlanid = 0;
|
|
|
|
if (nm_platform_link_get_type (self, ifindex) != NM_LINK_TYPE_VLAN)
|
|
return FALSE;
|
|
|
|
return klass->vlan_get_info (self, ifindex, parent, vlanid);
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_vlan_set_ingress_map (NMPlatform *self, int ifindex, int from, int to)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (klass->vlan_set_ingress_map, FALSE);
|
|
|
|
debug ("link: setting vlan ingress map for %d from %d to %d", ifindex, from, to);
|
|
return klass->vlan_set_ingress_map (self, ifindex, from, to);
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_vlan_set_egress_map (NMPlatform *self, int ifindex, int from, int to)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (klass->vlan_set_egress_map, FALSE);
|
|
|
|
debug ("link: setting vlan egress map for %d from %d to %d", ifindex, from, to);
|
|
return klass->vlan_set_egress_map (self, ifindex, from, to);
|
|
}
|
|
|
|
NMPlatformError
|
|
nm_platform_infiniband_partition_add (NMPlatform *self, int parent, int p_key, NMPlatformLink *out_link)
|
|
{
|
|
gs_free char *parent_name = NULL;
|
|
gs_free char *name = NULL;
|
|
NMPlatformError plerr;
|
|
|
|
_CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG);
|
|
|
|
g_return_val_if_fail (parent >= 0, NM_PLATFORM_ERROR_BUG);
|
|
g_return_val_if_fail (p_key >= 0, NM_PLATFORM_ERROR_BUG);
|
|
g_return_val_if_fail (klass->infiniband_partition_add, NM_PLATFORM_ERROR_BUG);
|
|
|
|
parent_name = g_strdup (nm_platform_link_get_name (self, parent));
|
|
if ( !parent_name
|
|
|| nm_platform_link_get_type (self, parent) != NM_LINK_TYPE_INFINIBAND)
|
|
return NM_PLATFORM_ERROR_WRONG_TYPE;
|
|
|
|
name = g_strdup_printf ("%s.%04x", parent_name, p_key);
|
|
plerr = _link_add_check_existing (self, name, NM_LINK_TYPE_INFINIBAND, out_link);
|
|
if (plerr != NM_PLATFORM_ERROR_SUCCESS)
|
|
return plerr;
|
|
|
|
debug ("link: adding infiniband partition %s for parent '%s' (%d), key %d",
|
|
name, parent_name, parent, p_key);
|
|
if (!klass->infiniband_partition_add (self, parent, p_key, out_link))
|
|
return NM_PLATFORM_ERROR_UNSPECIFIED;
|
|
return NM_PLATFORM_ERROR_SUCCESS;
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_infiniband_get_info (NMPlatform *self,
|
|
int ifindex,
|
|
int *parent,
|
|
int *p_key,
|
|
const char **mode)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex > 0, FALSE);
|
|
g_return_val_if_fail (klass->infiniband_get_info, FALSE);
|
|
|
|
return klass->infiniband_get_info (self, ifindex, parent, p_key, mode);
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_veth_get_properties (NMPlatform *self, int ifindex, NMPlatformVethProperties *props)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex > 0, FALSE);
|
|
g_return_val_if_fail (props != NULL, FALSE);
|
|
|
|
return klass->veth_get_properties (self, ifindex, props);
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_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 klass->tun_get_properties (self, ifindex, props);
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_macvlan_get_properties (NMPlatform *self, int ifindex, NMPlatformMacvlanProperties *props)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex > 0, FALSE);
|
|
g_return_val_if_fail (props != NULL, FALSE);
|
|
|
|
return klass->macvlan_get_properties (self, ifindex, props);
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_vxlan_get_properties (NMPlatform *self, int ifindex, NMPlatformVxlanProperties *props)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex > 0, FALSE);
|
|
g_return_val_if_fail (props != NULL, FALSE);
|
|
|
|
return klass->vxlan_get_properties (self, ifindex, props);
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_gre_get_properties (NMPlatform *self, int ifindex, NMPlatformGreProperties *props)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex > 0, FALSE);
|
|
g_return_val_if_fail (props != NULL, FALSE);
|
|
|
|
return klass->gre_get_properties (self, ifindex, props);
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_wifi_get_capabilities (NMPlatform *self, int ifindex, NMDeviceWifiCapabilities *caps)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex > 0, FALSE);
|
|
|
|
return klass->wifi_get_capabilities (self, ifindex, caps);
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_wifi_get_bssid (NMPlatform *self, int ifindex, guint8 *bssid)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex > 0, FALSE);
|
|
|
|
return klass->wifi_get_bssid (self, ifindex, bssid);
|
|
}
|
|
|
|
guint32
|
|
nm_platform_wifi_get_frequency (NMPlatform *self, int ifindex)
|
|
{
|
|
_CHECK_SELF (self, klass, 0);
|
|
|
|
g_return_val_if_fail (ifindex > 0, 0);
|
|
|
|
return klass->wifi_get_frequency (self, ifindex);
|
|
}
|
|
|
|
int
|
|
nm_platform_wifi_get_quality (NMPlatform *self, int ifindex)
|
|
{
|
|
_CHECK_SELF (self, klass, 0);
|
|
|
|
g_return_val_if_fail (ifindex > 0, 0);
|
|
|
|
return klass->wifi_get_quality (self, ifindex);
|
|
}
|
|
|
|
guint32
|
|
nm_platform_wifi_get_rate (NMPlatform *self, int ifindex)
|
|
{
|
|
_CHECK_SELF (self, klass, 0);
|
|
|
|
g_return_val_if_fail (ifindex > 0, 0);
|
|
|
|
return klass->wifi_get_rate (self, ifindex);
|
|
}
|
|
|
|
NM80211Mode
|
|
nm_platform_wifi_get_mode (NMPlatform *self, int ifindex)
|
|
{
|
|
_CHECK_SELF (self, klass, NM_802_11_MODE_UNKNOWN);
|
|
|
|
g_return_val_if_fail (ifindex > 0, NM_802_11_MODE_UNKNOWN);
|
|
|
|
return klass->wifi_get_mode (self, ifindex);
|
|
}
|
|
|
|
void
|
|
nm_platform_wifi_set_mode (NMPlatform *self, int ifindex, NM80211Mode mode)
|
|
{
|
|
_CHECK_SELF_VOID (self, klass);
|
|
|
|
g_return_if_fail (ifindex > 0);
|
|
|
|
klass->wifi_set_mode (self, ifindex, mode);
|
|
}
|
|
|
|
static void
|
|
wifi_set_powersave (NMPlatform *p, int ifindex, guint32 powersave)
|
|
{
|
|
/* empty */
|
|
}
|
|
|
|
void
|
|
nm_platform_wifi_set_powersave (NMPlatform *self, int ifindex, guint32 powersave)
|
|
{
|
|
_CHECK_SELF_VOID (self, klass);
|
|
|
|
g_return_if_fail (ifindex > 0);
|
|
|
|
klass->wifi_set_powersave (self, ifindex, powersave);
|
|
}
|
|
|
|
guint32
|
|
nm_platform_wifi_find_frequency (NMPlatform *self, int ifindex, const guint32 *freqs)
|
|
{
|
|
_CHECK_SELF (self, klass, 0);
|
|
|
|
g_return_val_if_fail (ifindex > 0, 0);
|
|
g_return_val_if_fail (freqs != NULL, 0);
|
|
|
|
return klass->wifi_find_frequency (self, ifindex, freqs);
|
|
}
|
|
|
|
void
|
|
nm_platform_wifi_indicate_addressing_running (NMPlatform *self, int ifindex, gboolean running)
|
|
{
|
|
_CHECK_SELF_VOID (self, klass);
|
|
|
|
g_return_if_fail (ifindex > 0);
|
|
|
|
klass->wifi_indicate_addressing_running (self, ifindex, running);
|
|
}
|
|
|
|
guint32
|
|
nm_platform_mesh_get_channel (NMPlatform *self, int ifindex)
|
|
{
|
|
_CHECK_SELF (self, klass, 0);
|
|
|
|
g_return_val_if_fail (ifindex > 0, 0);
|
|
|
|
return klass->mesh_get_channel (self, ifindex);
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_mesh_set_channel (NMPlatform *self, int ifindex, guint32 channel)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex > 0, FALSE);
|
|
|
|
return klass->mesh_set_channel (self, ifindex, channel);
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_mesh_set_ssid (NMPlatform *self, int ifindex, const guint8 *ssid, gsize len)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex > 0, FALSE);
|
|
g_return_val_if_fail (ssid != NULL, FALSE);
|
|
|
|
return klass->mesh_set_ssid (self, ifindex, ssid, len);
|
|
}
|
|
|
|
#define TO_STRING_DEV_BUF_SIZE (5+15+1)
|
|
static const char *
|
|
_to_string_dev (NMPlatform *self, int ifindex, char *buf, size_t size)
|
|
{
|
|
g_assert (buf && size >= TO_STRING_DEV_BUF_SIZE);
|
|
|
|
if (ifindex) {
|
|
const char *name = ifindex > 0 && self ? nm_platform_link_get_name (self, ifindex) : NULL;
|
|
char *buf2;
|
|
|
|
strcpy (buf, " dev ");
|
|
buf2 = buf + 5;
|
|
size -= 5;
|
|
|
|
if (name)
|
|
g_strlcpy (buf2, name, size);
|
|
else
|
|
g_snprintf (buf2, size, "%d", ifindex);
|
|
} else
|
|
buf[0] = 0;
|
|
|
|
return buf;
|
|
}
|
|
|
|
/******************************************************************/
|
|
|
|
GArray *
|
|
nm_platform_ip4_address_get_all (NMPlatform *self, int ifindex)
|
|
{
|
|
_CHECK_SELF (self, klass, NULL);
|
|
|
|
g_return_val_if_fail (ifindex > 0, NULL);
|
|
g_return_val_if_fail (klass->ip4_address_get_all, NULL);
|
|
|
|
return klass->ip4_address_get_all (self, ifindex);
|
|
}
|
|
|
|
GArray *
|
|
nm_platform_ip6_address_get_all (NMPlatform *self, int ifindex)
|
|
{
|
|
_CHECK_SELF (self, klass, NULL);
|
|
|
|
g_return_val_if_fail (ifindex > 0, NULL);
|
|
g_return_val_if_fail (klass->ip6_address_get_all, NULL);
|
|
|
|
return klass->ip6_address_get_all (self, ifindex);
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_ip4_address_add (NMPlatform *self,
|
|
int ifindex,
|
|
in_addr_t address,
|
|
in_addr_t peer_address,
|
|
int plen,
|
|
guint32 lifetime,
|
|
guint32 preferred,
|
|
const char *label)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex > 0, FALSE);
|
|
g_return_val_if_fail (plen > 0, FALSE);
|
|
g_return_val_if_fail (lifetime > 0, FALSE);
|
|
g_return_val_if_fail (preferred <= lifetime, FALSE);
|
|
g_return_val_if_fail (klass->ip4_address_add, FALSE);
|
|
g_return_val_if_fail (!label || strlen (label) < sizeof (((NMPlatformIP4Address *) NULL)->label), FALSE);
|
|
|
|
if (nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM)) {
|
|
NMPlatformIP4Address addr = { 0 };
|
|
|
|
addr.ifindex = ifindex;
|
|
addr.address = address;
|
|
addr.peer_address = peer_address;
|
|
addr.plen = plen;
|
|
addr.timestamp = 0; /* set it at zero, which to_string will treat as *now* */
|
|
addr.lifetime = lifetime;
|
|
addr.preferred = preferred;
|
|
if (label)
|
|
g_strlcpy (addr.label, label, sizeof (addr.label));
|
|
|
|
debug ("address: adding or updating IPv4 address: %s", nm_platform_ip4_address_to_string (&addr));
|
|
}
|
|
return klass->ip4_address_add (self, ifindex, address, peer_address, plen, lifetime, preferred, label);
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_ip6_address_add (NMPlatform *self,
|
|
int ifindex,
|
|
struct in6_addr address,
|
|
struct in6_addr peer_address,
|
|
int plen,
|
|
guint32 lifetime,
|
|
guint32 preferred,
|
|
guint flags)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex > 0, FALSE);
|
|
g_return_val_if_fail (plen > 0, FALSE);
|
|
g_return_val_if_fail (lifetime > 0, FALSE);
|
|
g_return_val_if_fail (preferred <= lifetime, FALSE);
|
|
g_return_val_if_fail (klass->ip6_address_add, FALSE);
|
|
|
|
if (nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM)) {
|
|
NMPlatformIP6Address addr = { 0 };
|
|
|
|
addr.ifindex = ifindex;
|
|
addr.address = address;
|
|
addr.peer_address = peer_address;
|
|
addr.plen = plen;
|
|
addr.timestamp = 0; /* set it to zero, which to_string will treat as *now* */
|
|
addr.lifetime = lifetime;
|
|
addr.preferred = preferred;
|
|
addr.flags = flags;
|
|
|
|
debug ("address: adding or updating IPv6 address: %s", nm_platform_ip6_address_to_string (&addr));
|
|
}
|
|
return klass->ip6_address_add (self, ifindex, address, peer_address, plen, lifetime, preferred, flags);
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_ip4_address_delete (NMPlatform *self, int ifindex, in_addr_t address, int plen, in_addr_t peer_address)
|
|
{
|
|
char str_dev[TO_STRING_DEV_BUF_SIZE];
|
|
char str_peer[NM_UTILS_INET_ADDRSTRLEN];
|
|
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex > 0, FALSE);
|
|
g_return_val_if_fail (plen > 0, FALSE);
|
|
g_return_val_if_fail (klass->ip4_address_delete, FALSE);
|
|
|
|
debug ("address: deleting IPv4 address %s/%d, %s%s%sifindex %d%s",
|
|
nm_utils_inet4_ntop (address, NULL), plen,
|
|
peer_address ? "peer " : "",
|
|
peer_address ? nm_utils_inet4_ntop (peer_address, str_peer) : "",
|
|
peer_address ? ", " : "",
|
|
ifindex,
|
|
_to_string_dev (self, ifindex, str_dev, sizeof (str_dev)));
|
|
return klass->ip4_address_delete (self, ifindex, address, plen, peer_address);
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_ip6_address_delete (NMPlatform *self, int ifindex, struct in6_addr address, int plen)
|
|
{
|
|
char str_dev[TO_STRING_DEV_BUF_SIZE];
|
|
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (ifindex > 0, FALSE);
|
|
g_return_val_if_fail (plen > 0, FALSE);
|
|
g_return_val_if_fail (klass->ip6_address_delete, FALSE);
|
|
|
|
debug ("address: deleting IPv6 address %s/%d, ifindex %d%s",
|
|
nm_utils_inet6_ntop (&address, NULL), plen, ifindex,
|
|
_to_string_dev (self, ifindex, str_dev, sizeof (str_dev)));
|
|
return klass->ip6_address_delete (self, ifindex, address, plen);
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_ip4_address_exists (NMPlatform *self, int ifindex, in_addr_t address, int plen)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (plen > 0, FALSE);
|
|
g_return_val_if_fail (klass->ip4_address_exists, FALSE);
|
|
|
|
return klass->ip4_address_exists (self, ifindex, address, plen);
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_ip6_address_exists (NMPlatform *self, int ifindex, struct in6_addr address, int plen)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (plen > 0, FALSE);
|
|
g_return_val_if_fail (klass->ip6_address_exists, FALSE);
|
|
|
|
return klass->ip6_address_exists (self, ifindex, address, plen);
|
|
}
|
|
|
|
static gboolean
|
|
array_contains_ip4_address (const GArray *addresses, const NMPlatformIP4Address *address, gint64 now, guint32 padding)
|
|
{
|
|
guint len = addresses ? addresses->len : 0;
|
|
guint i;
|
|
|
|
for (i = 0; i < len; i++) {
|
|
NMPlatformIP4Address *candidate = &g_array_index (addresses, NMPlatformIP4Address, i);
|
|
|
|
if (candidate->address == address->address && candidate->plen == address->plen) {
|
|
guint32 lifetime, preferred;
|
|
|
|
if (nmp_utils_lifetime_get (candidate->timestamp, candidate->lifetime, candidate->preferred,
|
|
now, padding, &lifetime, &preferred))
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
array_contains_ip6_address (const GArray *addresses, const NMPlatformIP6Address *address, gint64 now, guint32 padding)
|
|
{
|
|
guint len = addresses ? addresses->len : 0;
|
|
guint i;
|
|
|
|
for (i = 0; i < len; i++) {
|
|
NMPlatformIP6Address *candidate = &g_array_index (addresses, NMPlatformIP6Address, i);
|
|
|
|
if (IN6_ARE_ADDR_EQUAL (&candidate->address, &address->address) && candidate->plen == address->plen) {
|
|
guint32 lifetime, preferred;
|
|
|
|
if (nmp_utils_lifetime_get (candidate->timestamp, candidate->lifetime, candidate->preferred,
|
|
now, padding, &lifetime, &preferred))
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* nm_platform_ip4_address_sync:
|
|
* @self: platform instance
|
|
* @ifindex: Interface index
|
|
* @known_addresses: List of addresses
|
|
* @out_added_addresses: (out): (allow-none): if not %NULL, return a #GPtrArray
|
|
* with the addresses added. The pointers point into @known_addresses.
|
|
* It possibly does not contain all addresses from @known_address because
|
|
* some addresses might be expired.
|
|
*
|
|
* A convenience function to synchronize addresses for a specific interface
|
|
* with the least possible disturbance. It simply removes addresses that are
|
|
* not listed and adds addresses that are.
|
|
*
|
|
* Returns: %TRUE on success.
|
|
*/
|
|
gboolean
|
|
nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, const GArray *known_addresses, GPtrArray **out_added_addresses)
|
|
{
|
|
GArray *addresses;
|
|
NMPlatformIP4Address *address;
|
|
guint32 now = nm_utils_get_monotonic_timestamp_s ();
|
|
int i;
|
|
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
/* Delete unknown addresses */
|
|
addresses = nm_platform_ip4_address_get_all (self, ifindex);
|
|
for (i = 0; i < addresses->len; i++) {
|
|
address = &g_array_index (addresses, NMPlatformIP4Address, i);
|
|
|
|
if (!array_contains_ip4_address (known_addresses, address, now, ADDRESS_LIFETIME_PADDING))
|
|
nm_platform_ip4_address_delete (self, ifindex, address->address, address->plen, address->peer_address);
|
|
}
|
|
g_array_free (addresses, TRUE);
|
|
|
|
if (out_added_addresses)
|
|
*out_added_addresses = NULL;
|
|
|
|
if (!known_addresses)
|
|
return TRUE;
|
|
|
|
/* Add missing addresses */
|
|
for (i = 0; i < known_addresses->len; i++) {
|
|
const NMPlatformIP4Address *known_address = &g_array_index (known_addresses, NMPlatformIP4Address, i);
|
|
guint32 lifetime, preferred;
|
|
|
|
if (!nmp_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred,
|
|
now, ADDRESS_LIFETIME_PADDING, &lifetime, &preferred))
|
|
continue;
|
|
|
|
if (!nm_platform_ip4_address_add (self, ifindex, known_address->address, known_address->peer_address, known_address->plen, lifetime, preferred, known_address->label))
|
|
return FALSE;
|
|
|
|
if (out_added_addresses) {
|
|
if (!*out_added_addresses)
|
|
*out_added_addresses = g_ptr_array_new ();
|
|
g_ptr_array_add (*out_added_addresses, (gpointer) known_address);
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* nm_platform_ip6_address_sync:
|
|
* @self: platform instance
|
|
* @ifindex: Interface index
|
|
* @known_addresses: List of addresses
|
|
* @keep_link_local: Don't remove link-local address
|
|
*
|
|
* A convenience function to synchronize addresses for a specific interface
|
|
* with the least possible disturbance. It simply removes addresses that are
|
|
* not listed and adds addresses that are.
|
|
*
|
|
* Returns: %TRUE on success.
|
|
*/
|
|
gboolean
|
|
nm_platform_ip6_address_sync (NMPlatform *self, int ifindex, const GArray *known_addresses, gboolean keep_link_local)
|
|
{
|
|
GArray *addresses;
|
|
NMPlatformIP6Address *address;
|
|
guint32 now = nm_utils_get_monotonic_timestamp_s ();
|
|
int i;
|
|
|
|
/* Delete unknown addresses */
|
|
addresses = nm_platform_ip6_address_get_all (self, ifindex);
|
|
for (i = 0; i < addresses->len; i++) {
|
|
address = &g_array_index (addresses, NMPlatformIP6Address, i);
|
|
|
|
/* Leave link local address management to the kernel */
|
|
if (keep_link_local && IN6_IS_ADDR_LINKLOCAL (&address->address))
|
|
continue;
|
|
|
|
if (!array_contains_ip6_address (known_addresses, address, now, ADDRESS_LIFETIME_PADDING))
|
|
nm_platform_ip6_address_delete (self, ifindex, address->address, address->plen);
|
|
}
|
|
g_array_free (addresses, TRUE);
|
|
|
|
if (!known_addresses)
|
|
return TRUE;
|
|
|
|
/* Add missing addresses */
|
|
for (i = 0; i < known_addresses->len; i++) {
|
|
const NMPlatformIP6Address *known_address = &g_array_index (known_addresses, NMPlatformIP6Address, i);
|
|
guint32 lifetime, preferred;
|
|
|
|
if (!nmp_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred,
|
|
now, ADDRESS_LIFETIME_PADDING, &lifetime, &preferred))
|
|
continue;
|
|
|
|
if (!nm_platform_ip6_address_add (self, ifindex, known_address->address,
|
|
known_address->peer_address, known_address->plen,
|
|
lifetime, preferred, known_address->flags))
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_address_flush (NMPlatform *self, int ifindex)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
return nm_platform_ip4_address_sync (self, ifindex, NULL, NULL)
|
|
&& nm_platform_ip6_address_sync (self, ifindex, NULL, FALSE);
|
|
}
|
|
|
|
/******************************************************************/
|
|
|
|
GArray *
|
|
nm_platform_ip4_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags)
|
|
{
|
|
_CHECK_SELF (self, klass, NULL);
|
|
|
|
g_return_val_if_fail (ifindex >= 0, NULL);
|
|
|
|
return klass->ip4_route_get_all (self, ifindex, flags);
|
|
}
|
|
|
|
GArray *
|
|
nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags)
|
|
{
|
|
_CHECK_SELF (self, klass, NULL);
|
|
|
|
g_return_val_if_fail (ifindex >= 0, NULL);
|
|
|
|
return klass->ip6_route_get_all (self, ifindex, flags);
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_ip4_route_add (NMPlatform *self,
|
|
int ifindex, NMIPConfigSource source,
|
|
in_addr_t network, int plen,
|
|
in_addr_t gateway, guint32 pref_src,
|
|
guint32 metric, guint32 mss)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (0 <= plen && plen <= 32, FALSE);
|
|
g_return_val_if_fail (klass->ip4_route_add, FALSE);
|
|
|
|
if (nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM)) {
|
|
NMPlatformIP4Route route = { 0 };
|
|
|
|
route.ifindex = ifindex;
|
|
route.source = source;
|
|
route.network = network;
|
|
route.plen = plen;
|
|
route.gateway = gateway;
|
|
route.metric = metric;
|
|
route.mss = mss;
|
|
route.pref_src = pref_src;
|
|
|
|
debug ("route: adding or updating IPv4 route: %s", nm_platform_ip4_route_to_string (&route));
|
|
}
|
|
return klass->ip4_route_add (self, ifindex, source, network, plen, gateway, pref_src, metric, mss);
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_ip6_route_add (NMPlatform *self,
|
|
int ifindex, NMIPConfigSource source,
|
|
struct in6_addr network, int plen, struct in6_addr gateway,
|
|
guint32 metric, guint32 mss)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (0 <= plen && plen <= 128, FALSE);
|
|
g_return_val_if_fail (klass->ip6_route_add, FALSE);
|
|
|
|
if (nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM)) {
|
|
NMPlatformIP6Route route = { 0 };
|
|
|
|
route.ifindex = ifindex;
|
|
route.source = source;
|
|
route.network = network;
|
|
route.plen = plen;
|
|
route.gateway = gateway;
|
|
route.metric = metric;
|
|
route.mss = mss;
|
|
|
|
debug ("route: adding or updating IPv6 route: %s", nm_platform_ip6_route_to_string (&route));
|
|
}
|
|
return klass->ip6_route_add (self, ifindex, source, network, plen, gateway, metric, mss);
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_ip4_route_delete (NMPlatform *self, int ifindex, in_addr_t network, int plen, guint32 metric)
|
|
{
|
|
char str_dev[TO_STRING_DEV_BUF_SIZE];
|
|
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (klass->ip4_route_delete, FALSE);
|
|
|
|
debug ("route: deleting IPv4 route %s/%d, metric=%"G_GUINT32_FORMAT", ifindex %d%s",
|
|
nm_utils_inet4_ntop (network, NULL), plen, metric, ifindex,
|
|
_to_string_dev (self, ifindex, str_dev, sizeof (str_dev)));
|
|
return klass->ip4_route_delete (self, ifindex, network, plen, metric);
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_ip6_route_delete (NMPlatform *self, int ifindex, struct in6_addr network, int plen, guint32 metric)
|
|
{
|
|
char str_dev[TO_STRING_DEV_BUF_SIZE];
|
|
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (klass->ip6_route_delete, FALSE);
|
|
|
|
debug ("route: deleting IPv6 route %s/%d, metric=%"G_GUINT32_FORMAT", ifindex %d%s",
|
|
nm_utils_inet6_ntop (&network, NULL), plen, metric, ifindex,
|
|
_to_string_dev (self, ifindex, str_dev, sizeof (str_dev)));
|
|
return klass->ip6_route_delete (self, ifindex, network, plen, metric);
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_ip4_route_exists (NMPlatform *self, int ifindex, in_addr_t network, int plen, guint32 metric)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (klass->ip4_route_exists, FALSE);
|
|
|
|
return klass->ip4_route_exists (self ,ifindex, network, plen, metric);
|
|
}
|
|
|
|
gboolean
|
|
nm_platform_ip6_route_exists (NMPlatform *self, int ifindex, struct in6_addr network, int plen, guint32 metric)
|
|
{
|
|
_CHECK_SELF (self, klass, FALSE);
|
|
|
|
g_return_val_if_fail (klass->ip6_route_exists, FALSE);
|
|
|
|
return klass->ip6_route_exists (self, ifindex, network, plen, metric);
|
|
}
|
|
|
|
/******************************************************************/
|
|
|
|
static const char *
|
|
source_to_string (NMIPConfigSource source)
|
|
{
|
|
switch (source) {
|
|
case NM_IP_CONFIG_SOURCE_RTPROT_KERNEL:
|
|
return "rtprot-kernel";
|
|
case _NM_IP_CONFIG_SOURCE_RTM_F_CLONED:
|
|
return "rtm-f-cloned";
|
|
case NM_IP_CONFIG_SOURCE_KERNEL:
|
|
return "kernel";
|
|
case NM_IP_CONFIG_SOURCE_SHARED:
|
|
return "shared";
|
|
case NM_IP_CONFIG_SOURCE_IP4LL:
|
|
return "ipv4ll";
|
|
case NM_IP_CONFIG_SOURCE_PPP:
|
|
return "ppp";
|
|
case NM_IP_CONFIG_SOURCE_WWAN:
|
|
return "wwan";
|
|
case NM_IP_CONFIG_SOURCE_VPN:
|
|
return "vpn";
|
|
case NM_IP_CONFIG_SOURCE_DHCP:
|
|
return "dhcp";
|
|
case NM_IP_CONFIG_SOURCE_RDISC:
|
|
return "rdisc";
|
|
case NM_IP_CONFIG_SOURCE_USER:
|
|
return "user";
|
|
default:
|
|
break;
|
|
}
|
|
return "unknown";
|
|
}
|
|
|
|
static const char *
|
|
_lifetime_to_string (guint32 timestamp, guint32 lifetime, gint32 now, char *buf, size_t buf_size)
|
|
{
|
|
if (lifetime == NM_PLATFORM_LIFETIME_PERMANENT)
|
|
return "forever";
|
|
|
|
g_snprintf (buf, buf_size, "%usec",
|
|
nmp_utils_lifetime_rebase_relative_time_on_now (timestamp, lifetime, now, 0));
|
|
return buf;
|
|
}
|
|
|
|
|
|
static const char *
|
|
_lifetime_summary_to_string (gint32 now, guint32 timestamp, guint32 preferred, guint32 lifetime, char *buf, size_t buf_size)
|
|
{
|
|
g_snprintf (buf, buf_size, " lifetime %d-%u[%u,%u]",
|
|
(signed) now, (unsigned) timestamp, (unsigned) preferred, (unsigned) lifetime);
|
|
return buf;
|
|
}
|
|
|
|
char _nm_platform_to_string_buffer[256];
|
|
|
|
const char *
|
|
nm_platform_link_to_string (const NMPlatformLink *link)
|
|
{
|
|
char master[20];
|
|
char parent[20];
|
|
char str_vlan[16];
|
|
GString *str_flags;
|
|
char str_addrmode[30];
|
|
gs_free char *str_addr = NULL;
|
|
gs_free char *str_inet6_token = NULL;
|
|
|
|
if (!link)
|
|
return "(unknown link)";
|
|
|
|
str_flags = g_string_new (NULL);
|
|
if (NM_FLAGS_HAS (link->flags, IFF_NOARP))
|
|
g_string_append (str_flags, "NOARP,");
|
|
if (NM_FLAGS_HAS (link->flags, IFF_UP))
|
|
g_string_append (str_flags, "UP");
|
|
else
|
|
g_string_append (str_flags, "DOWN");
|
|
if (link->connected)
|
|
g_string_append (str_flags, ",LOWER_UP");
|
|
|
|
if (link->flags) {
|
|
char str_flags_buf[64];
|
|
|
|
rtnl_link_flags2str (link->flags, str_flags_buf, sizeof (str_flags_buf));
|
|
g_string_append_printf (str_flags, ";%s", str_flags_buf);
|
|
}
|
|
|
|
if (link->master)
|
|
g_snprintf (master, sizeof (master), " master %d", link->master);
|
|
else
|
|
master[0] = 0;
|
|
|
|
if (link->parent)
|
|
g_snprintf (parent, sizeof (master), "@%d", link->parent);
|
|
else
|
|
parent[0] = 0;
|
|
|
|
if (link->vlan_id)
|
|
g_snprintf (str_vlan, sizeof (str_vlan), " vlan %u", (guint) link->vlan_id);
|
|
else
|
|
str_vlan[0] = '\0';
|
|
|
|
if (link->inet6_addr_gen_mode_inv) {
|
|
switch (_nm_platform_uint8_inv (link->inet6_addr_gen_mode_inv)) {
|
|
case 0:
|
|
g_snprintf (str_addrmode, sizeof (str_addrmode), " addrgenmode eui64");
|
|
break;
|
|
case 1:
|
|
g_snprintf (str_addrmode, sizeof (str_addrmode), " addrgenmode none");
|
|
break;
|
|
default:
|
|
g_snprintf (str_addrmode, sizeof (str_addrmode), " addrgenmode %d", _nm_platform_uint8_inv (link->inet6_addr_gen_mode_inv));
|
|
break;
|
|
}
|
|
} else
|
|
str_addrmode[0] = '\0';
|
|
|
|
if (link->addr.len)
|
|
str_addr = nm_utils_hwaddr_ntoa (link->addr.data, MIN (link->addr.len, sizeof (link->addr.data)));
|
|
if (link->inet6_token.is_valid)
|
|
str_inet6_token = nm_utils_hwaddr_ntoa (&link->inet6_token.iid, sizeof (link->inet6_token.iid));
|
|
|
|
g_snprintf (_nm_platform_to_string_buffer, sizeof (_nm_platform_to_string_buffer),
|
|
"%d: " /* ifindex */
|
|
"%s" /* name */
|
|
"%s" /* parent */
|
|
" <%s>" /* flags */
|
|
" mtu %d"
|
|
"%s" /* master */
|
|
"%s" /* vlan */
|
|
" arp %u" /* arptype */
|
|
"%s%s" /* link->type */
|
|
"%s%s" /* kind */
|
|
"%s" /* is-in-udev */
|
|
"%s" /* addr-gen-mode */
|
|
"%s%s" /* addr */
|
|
"%s%s" /* inet6_token */
|
|
"%s%s" /* driver */
|
|
,
|
|
link->ifindex,
|
|
link->name,
|
|
parent,
|
|
str_flags->str,
|
|
link->mtu, master,
|
|
str_vlan,
|
|
link->arptype,
|
|
nm_link_type_to_string (link->type) ? " " : "",
|
|
str_if_set (nm_link_type_to_string (link->type), "???"),
|
|
link->kind ? (g_strcmp0 (nm_link_type_to_string (link->type), link->kind) ? "/" : "*") : "",
|
|
link->kind && g_strcmp0 (nm_link_type_to_string (link->type), link->kind) ? link->kind : "",
|
|
link->initialized ? " init" : " not-init",
|
|
str_addrmode,
|
|
str_addr ? " addr " : "",
|
|
str_addr ? str_addr : "",
|
|
str_inet6_token ? " inet6token " : "",
|
|
str_inet6_token ? str_inet6_token : "",
|
|
link->driver ? " driver " : "",
|
|
link->driver ? link->driver : "");
|
|
g_string_free (str_flags, TRUE);
|
|
return _nm_platform_to_string_buffer;
|
|
}
|
|
|
|
/**
|
|
* nm_platform_ip4_address_to_string:
|
|
* @route: pointer to NMPlatformIP4Address address structure
|
|
*
|
|
* A method for converting an address struct into a string representation.
|
|
*
|
|
* Example output: ""
|
|
*
|
|
* Returns: a string representation of the address. The returned string
|
|
* is an internal buffer, so do not keep or free the returned string.
|
|
* Also, this function is not thread safe.
|
|
*/
|
|
const char *
|
|
nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address)
|
|
{
|
|
char s_address[INET_ADDRSTRLEN];
|
|
char s_peer[INET_ADDRSTRLEN];
|
|
char str_dev[TO_STRING_DEV_BUF_SIZE];
|
|
char str_label[32];
|
|
char str_lft[30], str_pref[30], str_time[50];
|
|
char *str_peer = NULL;
|
|
const char *str_lft_p, *str_pref_p, *str_time_p;
|
|
gint32 now = nm_utils_get_monotonic_timestamp_s ();
|
|
|
|
g_return_val_if_fail (address, "(unknown)");
|
|
|
|
inet_ntop (AF_INET, &address->address, s_address, sizeof (s_address));
|
|
|
|
if (address->peer_address) {
|
|
inet_ntop (AF_INET, &address->peer_address, s_peer, sizeof (s_peer));
|
|
str_peer = g_strconcat (" ptp ", s_peer, NULL);
|
|
}
|
|
|
|
_to_string_dev (NULL, address->ifindex, str_dev, sizeof (str_dev));
|
|
|
|
if (*address->label)
|
|
g_snprintf (str_label, sizeof (str_label), " label %s", address->label);
|
|
else
|
|
str_label[0] = 0;
|
|
|
|
str_lft_p = _lifetime_to_string (address->timestamp,
|
|
address->lifetime ? address->lifetime : NM_PLATFORM_LIFETIME_PERMANENT,
|
|
now, str_lft, sizeof (str_lft)),
|
|
str_pref_p = (address->lifetime == address->preferred)
|
|
? str_lft_p
|
|
: ( _lifetime_to_string (address->timestamp,
|
|
address->lifetime ? MIN (address->preferred, address->lifetime) : NM_PLATFORM_LIFETIME_PERMANENT,
|
|
now, str_pref, sizeof (str_pref)) );
|
|
str_time_p = _lifetime_summary_to_string (now, address->timestamp, address->preferred, address->lifetime, str_time, sizeof (str_time));
|
|
|
|
g_snprintf (_nm_platform_to_string_buffer, sizeof (_nm_platform_to_string_buffer), "%s/%d lft %s pref %s%s%s%s%s src %s",
|
|
s_address, address->plen, str_lft_p, str_pref_p, str_time_p,
|
|
str_peer ? str_peer : "",
|
|
str_dev,
|
|
str_label,
|
|
source_to_string (address->source));
|
|
g_free (str_peer);
|
|
return _nm_platform_to_string_buffer;
|
|
}
|
|
|
|
/**
|
|
* nm_platform_addr_flags2str: wrapper for rtnl_addr_flags2str(),
|
|
* which might not yet support some recent address flags.
|
|
**/
|
|
void
|
|
nm_platform_addr_flags2str (int flags, char *buf, size_t size)
|
|
{
|
|
rtnl_addr_flags2str(flags, buf, size);
|
|
|
|
/* There are two recent flags IFA_F_MANAGETEMPADDR and IFA_F_NOPREFIXROUTE.
|
|
* If libnl does not yet support them, add them by hand.
|
|
* These two flags were introduced together with the extended ifa_flags,
|
|
* so, check for that.
|
|
*/
|
|
if ((flags & IFA_F_MANAGETEMPADDR) && !nm_platform_check_support_libnl_extended_ifa_flags ()) {
|
|
strncat (buf, buf[0] ? "," IFA_F_MANAGETEMPADDR_STR : IFA_F_MANAGETEMPADDR_STR,
|
|
size - strlen (buf) - 1);
|
|
}
|
|
if ((flags & IFA_F_NOPREFIXROUTE) && !nm_platform_check_support_libnl_extended_ifa_flags ()) {
|
|
strncat (buf, buf[0] ? "," IFA_F_NOPREFIXROUTE_STR : IFA_F_NOPREFIXROUTE_STR,
|
|
size - strlen (buf) - 1);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* nm_platform_ip6_address_to_string:
|
|
* @route: pointer to NMPlatformIP6Address address structure
|
|
*
|
|
* A method for converting an address struct into a string representation.
|
|
*
|
|
* Example output: "2001:db8:0:f101::1/64 lft 4294967295 pref 4294967295 time 16922666 on dev em1"
|
|
*
|
|
* Returns: a string representation of the address. The returned string
|
|
* is an internal buffer, so do not keep or free the returned string.
|
|
* Also, this function is not thread safe.
|
|
*/
|
|
const char *
|
|
nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address)
|
|
{
|
|
char s_flags[256];
|
|
char s_address[INET6_ADDRSTRLEN];
|
|
char s_peer[INET6_ADDRSTRLEN];
|
|
char str_lft[30], str_pref[30], str_time[50];
|
|
char str_dev[TO_STRING_DEV_BUF_SIZE];
|
|
char *str_flags;
|
|
char *str_peer = NULL;
|
|
const char *str_lft_p, *str_pref_p, *str_time_p;
|
|
gint32 now = nm_utils_get_monotonic_timestamp_s ();
|
|
|
|
g_return_val_if_fail (address, "(unknown)");
|
|
|
|
inet_ntop (AF_INET6, &address->address, s_address, sizeof (s_address));
|
|
|
|
if (!IN6_IS_ADDR_UNSPECIFIED (&address->peer_address)) {
|
|
inet_ntop (AF_INET6, &address->peer_address, s_peer, sizeof (s_peer));
|
|
str_peer = g_strconcat (" ptp ", s_peer, NULL);
|
|
}
|
|
|
|
_to_string_dev (NULL, address->ifindex, str_dev, sizeof (str_dev));
|
|
|
|
nm_platform_addr_flags2str (address->flags, s_flags, sizeof (s_flags));
|
|
|
|
str_flags = s_flags[0] ? g_strconcat (" flags ", s_flags, NULL) : NULL;
|
|
|
|
str_lft_p = _lifetime_to_string (address->timestamp,
|
|
address->lifetime ? address->lifetime : NM_PLATFORM_LIFETIME_PERMANENT,
|
|
now, str_lft, sizeof (str_lft)),
|
|
str_pref_p = (address->lifetime == address->preferred)
|
|
? str_lft_p
|
|
: ( _lifetime_to_string (address->timestamp,
|
|
address->lifetime ? MIN (address->preferred, address->lifetime) : NM_PLATFORM_LIFETIME_PERMANENT,
|
|
now, str_pref, sizeof (str_pref)) );
|
|
str_time_p = _lifetime_summary_to_string (now, address->timestamp, address->preferred, address->lifetime, str_time, sizeof (str_time));
|
|
|
|
g_snprintf (_nm_platform_to_string_buffer, sizeof (_nm_platform_to_string_buffer), "%s/%d lft %s pref %s%s%s%s%s src %s",
|
|
s_address, address->plen, str_lft_p, str_pref_p, str_time_p,
|
|
str_peer ? str_peer : "",
|
|
str_dev,
|
|
str_flags ? str_flags : "",
|
|
source_to_string (address->source));
|
|
g_free (str_flags);
|
|
g_free (str_peer);
|
|
return _nm_platform_to_string_buffer;
|
|
}
|
|
|
|
/**
|
|
* nm_platform_ip4_route_to_string:
|
|
* @route: pointer to NMPlatformIP4Route route structure
|
|
*
|
|
* A method for converting a route struct into a string representation.
|
|
*
|
|
* Example output: "192.168.1.0/24 via 0.0.0.0 dev em1 metric 0 mss 0"
|
|
*
|
|
* Returns: a string representation of the route. The returned string
|
|
* is an internal buffer, so do not keep or free the returned string.
|
|
* Also, this function is not thread safe.
|
|
*/
|
|
const char *
|
|
nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route)
|
|
{
|
|
char s_network[INET_ADDRSTRLEN], s_gateway[INET_ADDRSTRLEN];
|
|
char s_pref_src[INET_ADDRSTRLEN];
|
|
char str_dev[TO_STRING_DEV_BUF_SIZE];
|
|
char str_scope[30];
|
|
|
|
g_return_val_if_fail (route, "(unknown)");
|
|
|
|
inet_ntop (AF_INET, &route->network, s_network, sizeof(s_network));
|
|
inet_ntop (AF_INET, &route->gateway, s_gateway, sizeof(s_gateway));
|
|
|
|
_to_string_dev (NULL, route->ifindex, str_dev, sizeof (str_dev));
|
|
|
|
g_snprintf (_nm_platform_to_string_buffer, sizeof (_nm_platform_to_string_buffer),
|
|
"%s/%d"
|
|
" via %s"
|
|
"%s"
|
|
" metric %"G_GUINT32_FORMAT
|
|
" mss %"G_GUINT32_FORMAT
|
|
" src %s" /* source */
|
|
"%s%s" /* scope */
|
|
"%s%s" /* pref-src */
|
|
"",
|
|
s_network, route->plen,
|
|
s_gateway,
|
|
str_dev,
|
|
route->metric,
|
|
route->mss,
|
|
source_to_string (route->source),
|
|
route->scope_inv ? " scope " : "",
|
|
route->scope_inv ? (rtnl_scope2str (nm_platform_route_scope_inv (route->scope_inv), str_scope, sizeof (str_scope))) : "",
|
|
route->pref_src ? " pref-src " : "",
|
|
route->pref_src ? inet_ntop (AF_INET, &route->pref_src, s_pref_src, sizeof(s_pref_src)) : "");
|
|
return _nm_platform_to_string_buffer;
|
|
}
|
|
|
|
/**
|
|
* nm_platform_ip6_route_to_string:
|
|
* @route: pointer to NMPlatformIP6Route route structure
|
|
*
|
|
* A method for converting a route struct into a string representation.
|
|
*
|
|
* Example output: "ff02::fb/128 via :: dev em1 metric 0"
|
|
*
|
|
* Returns: a string representation of the route. The returned string
|
|
* is an internal buffer, so do not keep or free the returned string.
|
|
* Also, this function is not thread safe.
|
|
*/
|
|
const char *
|
|
nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route)
|
|
{
|
|
char s_network[INET6_ADDRSTRLEN], s_gateway[INET6_ADDRSTRLEN];
|
|
char str_dev[TO_STRING_DEV_BUF_SIZE];
|
|
|
|
g_return_val_if_fail (route, "(unknown)");
|
|
|
|
inet_ntop (AF_INET6, &route->network, s_network, sizeof(s_network));
|
|
inet_ntop (AF_INET6, &route->gateway, s_gateway, sizeof(s_gateway));
|
|
|
|
_to_string_dev (NULL, route->ifindex, str_dev, sizeof (str_dev));
|
|
|
|
g_snprintf (_nm_platform_to_string_buffer, sizeof (_nm_platform_to_string_buffer),
|
|
"%s/%d"
|
|
" via %s"
|
|
"%s"
|
|
" metric %"G_GUINT32_FORMAT
|
|
" mss %"G_GUINT32_FORMAT
|
|
" src %s" /* source */
|
|
"",
|
|
s_network, route->plen,
|
|
s_gateway,
|
|
str_dev,
|
|
route->metric,
|
|
route->mss,
|
|
source_to_string (route->source));
|
|
return _nm_platform_to_string_buffer;
|
|
}
|
|
|
|
#define _CMP_POINTER(a, b) \
|
|
G_STMT_START { \
|
|
if ((a) == (b)) \
|
|
return 0; \
|
|
if (!(a)) \
|
|
return -1; \
|
|
if (!(b)) \
|
|
return 1; \
|
|
} G_STMT_END
|
|
|
|
#define _CMP_FIELD(a, b, field) \
|
|
G_STMT_START { \
|
|
if (((a)->field) != ((b)->field)) \
|
|
return (((a)->field) < ((b)->field)) ? -1 : 1; \
|
|
} G_STMT_END
|
|
|
|
#define _CMP_FIELD_BOOL(a, b, field) \
|
|
G_STMT_START { \
|
|
if ((!((a)->field)) != (!((b)->field))) \
|
|
return ((!((a)->field)) < (!((b)->field))) ? -1 : 1; \
|
|
} G_STMT_END
|
|
|
|
#define _CMP_FIELD_STR(a, b, field) \
|
|
G_STMT_START { \
|
|
int c = strcmp ((a)->field, (b)->field); \
|
|
if (c != 0) \
|
|
return c < 0 ? -1 : 1; \
|
|
} G_STMT_END
|
|
|
|
#define _CMP_FIELD_STR_INTERNED(a, b, field) \
|
|
G_STMT_START { \
|
|
if (((a)->field) != ((b)->field)) { \
|
|
/* just to be sure, also do a strcmp() if the pointers don't match */ \
|
|
int c = g_strcmp0 ((a)->field, (b)->field); \
|
|
if (c != 0) \
|
|
return c < 0 ? -1 : 1; \
|
|
} \
|
|
} G_STMT_END
|
|
|
|
#define _CMP_FIELD_STR0(a, b, field) \
|
|
G_STMT_START { \
|
|
int c = g_strcmp0 ((a)->field, (b)->field); \
|
|
if (c != 0) \
|
|
return c < 0 ? -1 : 1; \
|
|
} G_STMT_END
|
|
|
|
#define _CMP_FIELD_MEMCMP_LEN(a, b, field, len) \
|
|
G_STMT_START { \
|
|
int c = memcmp (&((a)->field), &((b)->field), \
|
|
MIN (len, sizeof ((a)->field))); \
|
|
if (c != 0) \
|
|
return c < 0 ? -1 : 1; \
|
|
} G_STMT_END
|
|
|
|
#define _CMP_FIELD_MEMCMP(a, b, field) \
|
|
G_STMT_START { \
|
|
int c = memcmp (&((a)->field), &((b)->field), \
|
|
sizeof ((a)->field)); \
|
|
if (c != 0) \
|
|
return c < 0 ? -1 : 1; \
|
|
} G_STMT_END
|
|
|
|
int
|
|
nm_platform_link_cmp (const NMPlatformLink *a, const NMPlatformLink *b)
|
|
{
|
|
_CMP_POINTER (a, b);
|
|
_CMP_FIELD (a, b, ifindex);
|
|
_CMP_FIELD (a, b, type);
|
|
_CMP_FIELD_STR (a, b, name);
|
|
_CMP_FIELD (a, b, master);
|
|
_CMP_FIELD (a, b, parent);
|
|
_CMP_FIELD (a, b, vlan_id);
|
|
_CMP_FIELD (a, b, flags);
|
|
_CMP_FIELD (a, b, connected);
|
|
_CMP_FIELD (a, b, mtu);
|
|
_CMP_FIELD_BOOL (a, b, initialized);
|
|
_CMP_FIELD (a, b, arptype);
|
|
_CMP_FIELD (a, b, addr.len);
|
|
_CMP_FIELD (a, b, inet6_addr_gen_mode_inv);
|
|
_CMP_FIELD (a, b, inet6_token.is_valid);
|
|
_CMP_FIELD_STR_INTERNED (a, b, kind);
|
|
_CMP_FIELD_STR_INTERNED (a, b, driver);
|
|
if (a->addr.len)
|
|
_CMP_FIELD_MEMCMP_LEN (a, b, addr.data, a->addr.len);
|
|
if (a->inet6_token.is_valid)
|
|
_CMP_FIELD_MEMCMP (a, b, inet6_token.iid);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b)
|
|
{
|
|
_CMP_POINTER (a, b);
|
|
_CMP_FIELD (a, b, ifindex);
|
|
_CMP_FIELD (a, b, source);
|
|
_CMP_FIELD (a, b, address);
|
|
_CMP_FIELD (a, b, peer_address);
|
|
_CMP_FIELD (a, b, plen);
|
|
_CMP_FIELD (a, b, timestamp);
|
|
_CMP_FIELD (a, b, lifetime);
|
|
_CMP_FIELD (a, b, preferred);
|
|
_CMP_FIELD_STR (a, b, label);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
nm_platform_ip6_address_cmp (const NMPlatformIP6Address *a, const NMPlatformIP6Address *b)
|
|
{
|
|
_CMP_POINTER (a, b);
|
|
_CMP_FIELD (a, b, ifindex);
|
|
_CMP_FIELD (a, b, source);
|
|
_CMP_FIELD_MEMCMP (a, b, address);
|
|
_CMP_FIELD_MEMCMP (a, b, peer_address);
|
|
_CMP_FIELD (a, b, plen);
|
|
_CMP_FIELD (a, b, timestamp);
|
|
_CMP_FIELD (a, b, lifetime);
|
|
_CMP_FIELD (a, b, preferred);
|
|
_CMP_FIELD (a, b, flags);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b)
|
|
{
|
|
_CMP_POINTER (a, b);
|
|
_CMP_FIELD (a, b, ifindex);
|
|
_CMP_FIELD (a, b, source);
|
|
_CMP_FIELD (a, b, network);
|
|
_CMP_FIELD (a, b, plen);
|
|
_CMP_FIELD (a, b, gateway);
|
|
_CMP_FIELD (a, b, metric);
|
|
_CMP_FIELD (a, b, mss);
|
|
_CMP_FIELD (a, b, scope_inv);
|
|
_CMP_FIELD (a, b, pref_src);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b)
|
|
{
|
|
_CMP_POINTER (a, b);
|
|
_CMP_FIELD (a, b, ifindex);
|
|
_CMP_FIELD (a, b, source);
|
|
_CMP_FIELD_MEMCMP (a, b, network);
|
|
_CMP_FIELD (a, b, plen);
|
|
_CMP_FIELD_MEMCMP (a, b, gateway);
|
|
_CMP_FIELD (a, b, metric);
|
|
_CMP_FIELD (a, b, mss);
|
|
return 0;
|
|
}
|
|
|
|
#undef _CMP_FIELD
|
|
#undef _CMP_FIELD_MEMCMP
|
|
|
|
/**
|
|
* nm_platform_ip_address_cmp_expiry:
|
|
* @a: a NMPlatformIPAddress to compare
|
|
* @b: the other NMPlatformIPAddress to compare
|
|
*
|
|
* Compares two addresses and returns which one has a longer remaining lifetime.
|
|
* If both addresses have the same lifetime, look at the remaining preferred time.
|
|
*
|
|
* For comparison, only the timestamp, lifetime and preferred fields are considered.
|
|
* If they compare equal (== 0), their other fields were not considered.
|
|
*
|
|
* Returns: -1, 0, or 1 according to the comparison
|
|
**/
|
|
int
|
|
nm_platform_ip_address_cmp_expiry (const NMPlatformIPAddress *a, const NMPlatformIPAddress *b)
|
|
{
|
|
gint64 ta = 0, tb = 0;
|
|
|
|
_CMP_POINTER (a, b);
|
|
|
|
if (a->lifetime == NM_PLATFORM_LIFETIME_PERMANENT || a->lifetime == 0)
|
|
ta = G_MAXINT64;
|
|
else if (a->timestamp)
|
|
ta = ((gint64) a->timestamp) + a->lifetime;
|
|
|
|
if (b->lifetime == NM_PLATFORM_LIFETIME_PERMANENT || b->lifetime == 0)
|
|
tb = G_MAXINT64;
|
|
else if (b->timestamp)
|
|
tb = ((gint64) b->timestamp) + b->lifetime;
|
|
|
|
if (ta == tb) {
|
|
/* if the lifetime is equal, compare the preferred time. */
|
|
ta = tb = 0;
|
|
|
|
if (a->preferred == NM_PLATFORM_LIFETIME_PERMANENT || a->lifetime == 0 /* liftime==0 means permanent! */)
|
|
ta = G_MAXINT64;
|
|
else if (a->timestamp)
|
|
ta = ((gint64) a->timestamp) + a->preferred;
|
|
|
|
if (b->preferred == NM_PLATFORM_LIFETIME_PERMANENT|| b->lifetime == 0)
|
|
tb = G_MAXINT64;
|
|
else if (b->timestamp)
|
|
tb = ((gint64) b->timestamp) + b->preferred;
|
|
|
|
if (ta == tb)
|
|
return 0;
|
|
}
|
|
|
|
return ta < tb ? -1 : 1;
|
|
}
|
|
|
|
#undef _CMP_POINTER
|
|
|
|
const char *
|
|
nm_platform_signal_change_type_to_string (NMPlatformSignalChangeType change_type)
|
|
{
|
|
switch (change_type) {
|
|
case NM_PLATFORM_SIGNAL_ADDED:
|
|
return "added";
|
|
case NM_PLATFORM_SIGNAL_CHANGED:
|
|
return "changed";
|
|
case NM_PLATFORM_SIGNAL_REMOVED:
|
|
return "removed";
|
|
default:
|
|
g_return_val_if_reached ("UNKNOWN");
|
|
}
|
|
}
|
|
|
|
static void
|
|
log_link (NMPlatform *p, NMPObjectType obj_type, int ifindex, NMPlatformLink *device, NMPlatformSignalChangeType change_type, gpointer user_data)
|
|
{
|
|
|
|
debug ("signal: link %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_link_to_string (device));
|
|
}
|
|
|
|
static void
|
|
log_ip4_address (NMPlatform *p, NMPObjectType obj_type, int ifindex, NMPlatformIP4Address *address, NMPlatformSignalChangeType change_type, gpointer user_data)
|
|
{
|
|
debug ("signal: address 4 %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_ip4_address_to_string (address));
|
|
}
|
|
|
|
static void
|
|
log_ip6_address (NMPlatform *p, NMPObjectType obj_type, int ifindex, NMPlatformIP6Address *address, NMPlatformSignalChangeType change_type, gpointer user_data)
|
|
{
|
|
debug ("signal: address 6 %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_ip6_address_to_string (address));
|
|
}
|
|
|
|
static void
|
|
log_ip4_route (NMPlatform *p, NMPObjectType obj_type, int ifindex, NMPlatformIP4Route *route, NMPlatformSignalChangeType change_type, gpointer user_data)
|
|
{
|
|
debug ("signal: route 4 %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_ip4_route_to_string (route));
|
|
}
|
|
|
|
static void
|
|
log_ip6_route (NMPlatform *p, NMPObjectType obj_type, int ifindex, NMPlatformIP6Route *route, NMPlatformSignalChangeType change_type, gpointer user_data)
|
|
{
|
|
debug ("signal: route 6 %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_ip6_route_to_string (route));
|
|
}
|
|
|
|
/******************************************************************/
|
|
|
|
static gboolean
|
|
_vtr_v4_route_add (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route)
|
|
{
|
|
return nm_platform_ip4_route_add (self,
|
|
ifindex > 0 ? ifindex : route->rx.ifindex,
|
|
route->rx.source,
|
|
route->r4.network,
|
|
route->rx.plen,
|
|
route->r4.gateway,
|
|
route->r4.pref_src,
|
|
route->rx.metric,
|
|
route->rx.mss);
|
|
}
|
|
|
|
static gboolean
|
|
_vtr_v6_route_add (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route)
|
|
{
|
|
return nm_platform_ip6_route_add (self,
|
|
ifindex > 0 ? ifindex : route->rx.ifindex,
|
|
route->rx.source,
|
|
route->r6.network,
|
|
route->rx.plen,
|
|
route->r6.gateway,
|
|
route->rx.metric,
|
|
route->rx.mss);
|
|
}
|
|
|
|
static gboolean
|
|
_vtr_v4_route_delete (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route)
|
|
{
|
|
return nm_platform_ip4_route_delete (self,
|
|
ifindex > 0 ? ifindex : route->rx.ifindex,
|
|
route->r4.network,
|
|
route->rx.plen,
|
|
route->rx.metric);
|
|
}
|
|
|
|
static gboolean
|
|
_vtr_v6_route_delete (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route)
|
|
{
|
|
return nm_platform_ip6_route_delete (self,
|
|
ifindex > 0 ? ifindex : route->rx.ifindex,
|
|
route->r6.network,
|
|
route->rx.plen,
|
|
route->rx.metric);
|
|
}
|
|
|
|
static guint32
|
|
_vtr_v4_metric_normalize (guint32 metric)
|
|
{
|
|
return metric;
|
|
}
|
|
|
|
static gboolean
|
|
_vtr_v4_route_delete_default (NMPlatform *self, int ifindex, guint32 metric)
|
|
{
|
|
return nm_platform_ip4_route_delete (self, ifindex, 0, 0, metric);
|
|
}
|
|
|
|
static gboolean
|
|
_vtr_v6_route_delete_default (NMPlatform *self, int ifindex, guint32 metric)
|
|
{
|
|
return nm_platform_ip6_route_delete (self, ifindex, in6addr_any, 0, metric);
|
|
}
|
|
|
|
/******************************************************************/
|
|
|
|
const NMPlatformVTableRoute nm_platform_vtable_route_v4 = {
|
|
.is_ip4 = TRUE,
|
|
.addr_family = AF_INET,
|
|
.sizeof_route = sizeof (NMPlatformIP4Route),
|
|
.route_cmp = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b)) nm_platform_ip4_route_cmp,
|
|
.route_to_string = (const char *(*) (const NMPlatformIPXRoute *route)) nm_platform_ip4_route_to_string,
|
|
.route_get_all = nm_platform_ip4_route_get_all,
|
|
.route_add = _vtr_v4_route_add,
|
|
.route_delete = _vtr_v4_route_delete,
|
|
.route_delete_default = _vtr_v4_route_delete_default,
|
|
.metric_normalize = _vtr_v4_metric_normalize,
|
|
};
|
|
|
|
const NMPlatformVTableRoute nm_platform_vtable_route_v6 = {
|
|
.is_ip4 = FALSE,
|
|
.addr_family = AF_INET6,
|
|
.sizeof_route = sizeof (NMPlatformIP6Route),
|
|
.route_cmp = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b)) nm_platform_ip6_route_cmp,
|
|
.route_to_string = (const char *(*) (const NMPlatformIPXRoute *route)) nm_platform_ip6_route_to_string,
|
|
.route_get_all = nm_platform_ip6_route_get_all,
|
|
.route_add = _vtr_v6_route_add,
|
|
.route_delete = _vtr_v6_route_delete,
|
|
.route_delete_default = _vtr_v6_route_delete_default,
|
|
.metric_normalize = nm_utils_ip6_route_metric_normalize,
|
|
};
|
|
|
|
/******************************************************************/
|
|
|
|
static void
|
|
set_property (GObject *object, guint prop_id,
|
|
const GValue *value, GParamSpec *pspec)
|
|
{
|
|
NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE (object);
|
|
|
|
switch (prop_id) {
|
|
case PROP_REGISTER_SINGLETON:
|
|
/* construct-only */
|
|
priv->register_singleton = g_value_get_boolean (value);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
constructed (GObject *object)
|
|
{
|
|
NMPlatform *self = NM_PLATFORM (object);
|
|
NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE (self);
|
|
|
|
G_OBJECT_CLASS (nm_platform_parent_class)->constructed (object);
|
|
|
|
if (priv->register_singleton)
|
|
nm_platform_setup (self);
|
|
}
|
|
|
|
static void
|
|
nm_platform_init (NMPlatform *object)
|
|
{
|
|
}
|
|
|
|
#define SIGNAL(signal_id, method) signals[signal_id] = \
|
|
g_signal_new_class_handler (NM_PLATFORM_ ## signal_id, \
|
|
G_OBJECT_CLASS_TYPE (object_class), \
|
|
G_SIGNAL_RUN_FIRST, \
|
|
G_CALLBACK (method), \
|
|
NULL, NULL, NULL, \
|
|
G_TYPE_NONE, 5, NM_TYPE_POBJECT_TYPE, G_TYPE_INT, G_TYPE_POINTER, NM_TYPE_PLATFORM_SIGNAL_CHANGE_TYPE, NM_TYPE_PLATFORM_REASON);
|
|
|
|
static void
|
|
nm_platform_class_init (NMPlatformClass *platform_class)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (platform_class);
|
|
|
|
g_type_class_add_private (object_class, sizeof (NMPlatformPrivate));
|
|
|
|
object_class->set_property = set_property;
|
|
object_class->constructed = constructed;
|
|
|
|
platform_class->wifi_set_powersave = wifi_set_powersave;
|
|
|
|
g_object_class_install_property
|
|
(object_class, PROP_REGISTER_SINGLETON,
|
|
g_param_spec_boolean (NM_PLATFORM_REGISTER_SINGLETON, "", "",
|
|
FALSE,
|
|
G_PARAM_WRITABLE |
|
|
G_PARAM_CONSTRUCT_ONLY |
|
|
G_PARAM_STATIC_STRINGS));
|
|
|
|
/* Signals */
|
|
SIGNAL (SIGNAL_LINK_CHANGED, log_link)
|
|
SIGNAL (SIGNAL_IP4_ADDRESS_CHANGED, log_ip4_address)
|
|
SIGNAL (SIGNAL_IP6_ADDRESS_CHANGED, log_ip6_address)
|
|
SIGNAL (SIGNAL_IP4_ROUTE_CHANGED, log_ip4_route)
|
|
SIGNAL (SIGNAL_IP6_ROUTE_CHANGED, log_ip6_route)
|
|
}
|