diff options
Diffstat (limited to 'src/platform/nm-platform.c')
| -rw-r--r-- | src/platform/nm-platform.c | 2093 |
1 files changed, 1136 insertions, 957 deletions
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index ba7708d6..b6d87ff9 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -27,16 +27,59 @@ #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 _LOG_DOMAIN LOGD_PLATFORM +#define _LOG_PREFIX_NAME "platform" + +#define _LOG(level, domain, self, ...) \ + G_STMT_START { \ + const NMLogLevel __level = (level); \ + const NMLogDomain __domain = (domain); \ + \ + if (nm_logging_enabled (__level, __domain)) { \ + char __prefix[32]; \ + const char *__p_prefix = _LOG_PREFIX_NAME; \ + const void *const __self = (self); \ + \ + if (__self && __self != nm_platform_try_get ()) { \ + g_snprintf (__prefix, sizeof (__prefix), "%s[%p]", _LOG_PREFIX_NAME, __self); \ + __p_prefix = __prefix; \ + } \ + _nm_log (__level, __domain, 0, \ + "%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ + __p_prefix _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ + } \ + } G_STMT_END +#define _LOG_LEVEL_ENABLED(level, domain) \ + ( nm_logging_enabled ((level), (domain)) ) + +#ifdef NM_MORE_LOGGING +#define _LOGT_ENABLED() _LOG_LEVEL_ENABLED (LOGL_TRACE, _LOG_DOMAIN) +#define _LOGT(...) _LOG (LOGL_TRACE, _LOG_DOMAIN, self, __VA_ARGS__) +#else +#define _LOGT_ENABLED() FALSE +#define _LOGT(...) G_STMT_START { if (FALSE) { _LOG (LOGL_TRACE, _LOG_DOMAIN, self, __VA_ARGS__); } } G_STMT_END +#endif -#define debug(...) nm_log_dbg (LOGD_PLATFORM, __VA_ARGS__) +#define _LOGD(...) _LOG (LOGL_DEBUG, _LOG_DOMAIN, self, __VA_ARGS__) +#define _LOGI(...) _LOG (LOGL_INFO , _LOG_DOMAIN, self, __VA_ARGS__) +#define _LOGW(...) _LOG (LOGL_WARN , _LOG_DOMAIN, self, __VA_ARGS__) +#define _LOGE(...) _LOG (LOGL_ERR , _LOG_DOMAIN, self, __VA_ARGS__) #define NM_PLATFORM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_PLATFORM, NMPlatformPrivate)) @@ -54,19 +97,46 @@ enum { 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 */ -static NMPlatform *platform = NULL; -static NMPlatformClass *klass = NULL; +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: - * @type: The #GType for a subclass of #NMPlatform - * - * Do not use this function directly, it is intended to be called by - * NMPlatform subclasses. For the linux platform initialization use - * nm_linux_platform_setup() instead. + * @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 @@ -74,122 +144,82 @@ static NMPlatformClass *klass = NULL; * * NetworkManager will typically use only one platform object during * its run. Test programs might want to switch platform implementations, - * though. This is done with a combination of nm_platform_free() and - * nm_*_platform_setup(). + * though. */ void -nm_platform_setup (GType type) +nm_platform_setup (NMPlatform *instance) { - gboolean status; + g_return_if_fail (NM_IS_PLATFORM (instance)); + g_return_if_fail (!singleton_instance); - g_assert (platform == NULL); + singleton_instance = instance; - platform = g_object_new (type, NULL); - g_assert (NM_IS_PLATFORM (platform)); + nm_singleton_instance_weak_ref_register (); - klass = NM_PLATFORM_GET_CLASS (platform); - g_assert (klass->setup); - - status = klass->setup (platform); - g_assert (status); -} - -/** - * nm_platform_free: - * - * Free #NMPlatform singleton created by nm_*_platform_setup(). - */ -void -nm_platform_free (void) -{ - g_assert (platform); - - g_object_unref (platform); - platform = NULL; + 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() - * or after nm_platform_free(). + * #NMPlatform signals. It is an error to call it before nm_platform_setup(). * * Returns: (transfer none): The #NMPlatform singleton reference. */ NMPlatform * -nm_platform_get (void) +nm_platform_get () { - g_assert (platform); + g_assert (singleton_instance); - return platform; + return singleton_instance; } -/******************************************************************/ - -/** - * nm_platform_set_error: - * @error: The error code - * - * Convenience function to falsify platform->error. It can be used for example - * by functions that want to save the error, execute some operations and - * restore it. - */ -void nm_platform_set_error (NMPlatformError error) +NMPlatform * +nm_platform_try_get (void) { - platform->error = error; + return singleton_instance; } -/** - * nm_platform_get_error: - * - * Convenience function to quickly retrieve the error code of the last - * operation. - * - * Returns: Integer error code. - */ -NMPlatformError -nm_platform_get_error (void) -{ - g_assert (platform); - - return platform->error; -} +/******************************************************************/ /** - * nm_platform_get_error_message: + * nm_platform_error_to_string: + * @error_code: the error code to stringify. * - * Returns: Static human-readable string for the error. Don't free. + * Returns: A string representation of the error. + * For negative numbers, this function interprets + * the code as -errno. */ const char * -nm_platform_get_error_msg (void) -{ - g_assert (platform); - - switch (platform->error) { - case NM_PLATFORM_ERROR_NONE: - return "unknown error"; +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 "object not found"; + return "not-found"; case NM_PLATFORM_ERROR_EXISTS: - return "object already exists"; + return "exists"; case NM_PLATFORM_ERROR_WRONG_TYPE: - return "object is wrong type"; + return "wrong-type"; case NM_PLATFORM_ERROR_NOT_SLAVE: - return "link not a slave"; + return "not-slave"; case NM_PLATFORM_ERROR_NO_FIRMWARE: - return "firmware not found"; + return "no-firmware"; default: - return "invalid error number"; + if (error < 0) + return g_strerror (- ((int) error)); + return "unknown"; } } -static void -reset_error (void) -{ - g_assert (platform); - platform->error = NM_PLATFORM_ERROR_NONE; -} +/******************************************************************/ #define IFA_F_MANAGETEMPADDR_STR "mngtmpaddr" #define IFA_F_NOPREFIXROUTE_STR "noprefixroute" @@ -208,35 +238,53 @@ nm_platform_check_support_libnl_extended_ifa_flags () } gboolean -nm_platform_check_support_kernel_extended_ifa_flags () +nm_platform_check_support_kernel_extended_ifa_flags (NMPlatform *self) { - g_return_val_if_fail (NM_IS_PLATFORM (platform), FALSE); + _CHECK_SELF (self, klass, FALSE); if (!klass->check_support_kernel_extended_ifa_flags) return FALSE; - return klass->check_support_kernel_extended_ifa_flags (platform); + return klass->check_support_kernel_extended_ifa_flags (self); } gboolean -nm_platform_check_support_user_ipv6ll (void) +nm_platform_check_support_user_ipv6ll (NMPlatform *self) { static int supported = -1; - g_return_val_if_fail (NM_IS_PLATFORM (platform), FALSE); + _CHECK_SELF (self, klass, FALSE); if (!klass->check_support_user_ipv6ll) return FALSE; if (supported < 0) - supported = klass->check_support_user_ipv6ll (platform) ? 1 : 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 * @@ -247,23 +295,25 @@ nm_platform_check_support_user_ipv6ll (void) * Returns: %TRUE on success. */ gboolean -nm_platform_sysctl_set (const char *path, const char *value) +nm_platform_sysctl_set (NMPlatform *self, const char *path, const char *value) { - reset_error (); + _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 (platform, path, value); + return klass->sysctl_set (self, path, value); } gboolean -nm_platform_sysctl_set_ip6_hop_limit_safe (const char *iface, int value) +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; @@ -273,7 +323,7 @@ nm_platform_sysctl_set_ip6_hop_limit_safe (const char *iface, int value) return FALSE; path = nm_utils_ip6_property_path (iface, "hop_limit"); - cur = nm_platform_sysctl_get_int_checked (path, 10, 1, G_MAXINT32, -1); + 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) */ @@ -284,7 +334,7 @@ nm_platform_sysctl_set_ip6_hop_limit_safe (const char *iface, int value) char svalue[20]; sprintf (svalue, "%d", value); - nm_platform_sysctl_set (path, svalue); + nm_platform_sysctl_set (self, path, svalue); } return TRUE; @@ -292,23 +342,25 @@ nm_platform_sysctl_set_ip6_hop_limit_safe (const char *iface, int value) /** * 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 (const char *path) +nm_platform_sysctl_get (NMPlatform *self, const char *path) { - reset_error (); + _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 (platform, path); + 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. @@ -318,13 +370,14 @@ nm_platform_sysctl_get (const char *path) * value, on success %errno will be set to zero. */ gint32 -nm_platform_sysctl_get_int32 (const char *path, gint32 fallback) +nm_platform_sysctl_get_int32 (NMPlatform *self, const char *path, gint32 fallback) { - return nm_platform_sysctl_get_int_checked (path, 10, G_MININT32, G_MAXINT32, 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 @@ -339,22 +392,24 @@ nm_platform_sysctl_get_int32 (const char *path, gint32 fallback) * (inclusive) or @fallback. */ gint64 -nm_platform_sysctl_get_int_checked (const char *path, guint base, gint64 min, gint64 max, gint64 fallback) +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 (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); + ret = _nm_utils_ascii_str_to_int64 (value, base, min, max, fallback); g_free (value); return ret; } @@ -362,47 +417,25 @@ nm_platform_sysctl_get_int_checked (const char *path, guint base, gint64 min, gi /******************************************************************/ /** - * nm_platform_query_devices: - * - * Emit #NMPlatform:link-changed ADDED signals for all currently-known links. - * Should only be called at startup. - */ -void -nm_platform_query_devices (void) -{ - GArray *links_array; - NMPlatformLink *links; - int i; - - links_array = nm_platform_link_get_all (); - links = (NMPlatformLink *) links_array->data; - for (i = 0; i < links_array->len; i++) { - g_signal_emit (platform, signals[SIGNAL_LINK_CHANGED], 0, - links[i].ifindex, &links[i], NM_PLATFORM_SIGNAL_ADDED, - NM_PLATFORM_REASON_INTERNAL); - } - g_array_unref (links_array); -} - -/** * 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 (void) +nm_platform_link_get_all (NMPlatform *self) { GArray *links, *result; guint i, j, nresult; GHashTable *unseen; NMPlatformLink *item; - reset_error (); + _CHECK_SELF (self, klass, NULL); g_return_val_if_fail (klass->link_get_all, NULL); - links = klass->link_get_all (platform); + links = klass->link_get_all (self); if (!links || links->len == 0) return links; @@ -411,11 +444,9 @@ nm_platform_link_get_all (void) 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; - } + _LOGT ("link-get: %3d: %s", i, nm_platform_link_to_string (item)); + + nm_assert (item->ifindex > 0 && !g_hash_table_contains (unseen, GINT_TO_POINTER (item->ifindex))); g_hash_table_insert (unseen, GINT_TO_POINTER (item->ifindex), NULL); } @@ -466,6 +497,8 @@ nm_platform_link_get_all (void) if (item->parent > 0 && g_hash_table_contains (unseen, GINT_TO_POINTER (item->parent))) continue; + _LOGT ("link-get: add %3d -> %3d: %s", i, j, nm_platform_link_to_string (item)); + g_hash_table_remove (unseen, GINT_TO_POINTER (item->ifindex)); g_array_index (result, NMPlatformLink, j++) = *item; item->ifindex = 0; @@ -473,10 +506,12 @@ nm_platform_link_get_all (void) } if (!found_something) { - /* there is a circle, pop the first (remaining) element from the list */ - g_warn_if_reached (); + /* There is a loop, pop the first (remaining) element from the list. + * This can happen for veth pairs where each peer is parent of the other end. */ item = &g_array_index (links, NMPlatformLink, first_idx); + _LOGT ("link-get: add (loop) %3d -> %3d: %s", first_idx, j, nm_platform_link_to_string (item)); + g_hash_table_remove (unseen, GINT_TO_POINTER (item->ifindex)); g_array_index (result, NMPlatformLink, j++) = *item; item->ifindex = 0; @@ -491,182 +526,229 @@ nm_platform_link_get_all (void) /** * nm_platform_link_get: + * @self: platform instance * @ifindex: ifindex of the link - * @link: (out): output NMPlatformLink structure. * - * If a link with given @ifindex exists, fill the given NMPlatformLink - * structure. + * Lookup the internal NMPlatformLink object. * - * Returns: %TRUE, if such a link exists, %FALSE otherwise. - * If the link does not exist, the content of @link is undefined. + * 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. **/ -gboolean -nm_platform_link_get (int ifindex, NMPlatformLink *link) +const NMPlatformLink * +nm_platform_link_get (NMPlatform *self, int ifindex) { - g_return_val_if_fail (ifindex > 0, FALSE); - g_return_val_if_fail (link, FALSE); + _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); - g_return_val_if_fail (klass->link_get, FALSE); - return !!klass->link_get (platform, ifindex, link); + 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; + _LOGD ("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. Sets platform->error to NM_PLATFORM_ERROR_EXISTS - * if interface is already already exists. Any link-changed ADDED signal will be - * emitted directly, before this function finishes. + * 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 gboolean -nm_platform_link_add (const char *name, NMLinkType type, const void *address, size_t address_len) +static NMPlatformError +nm_platform_link_add (NMPlatform *self, + const char *name, + NMLinkType type, + const void *address, + size_t address_len, + NMPlatformLink *out_link) { - reset_error (); + NMPlatformError plerr; - g_return_val_if_fail (name, FALSE); - g_return_val_if_fail (klass->link_add, FALSE); - g_return_val_if_fail ( (address != NULL) ^ (address_len == 0) , FALSE); + _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); - if (nm_platform_link_exists (name)) { - debug ("link: already exists"); - platform->error = NM_PLATFORM_ERROR_EXISTS; - return FALSE; - } + 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; - return klass->link_add (platform, name, type, address, address_len); + _LOGD ("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 */ -gboolean -nm_platform_dummy_add (const char *name) -{ - g_return_val_if_fail (name, FALSE); - - debug ("link: adding dummy '%s'", name); - return nm_platform_link_add (name, NM_LINK_TYPE_DUMMY, NULL, 0); -} - -/** - * nm_platform_link_exists: - * @name: Interface name - * - * Returns: %TRUE if an interface of this name exists, %FALSE otherwise. - */ -gboolean -nm_platform_link_exists (const char *name) +NMPlatformError +nm_platform_dummy_add (NMPlatform *self, const char *name, NMPlatformLink *out_link) { - int ifindex = nm_platform_link_get_ifindex (name); - - reset_error(); - return ifindex > 0; + 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 - * - * Delete a software interface. Sets platform->error to - * NM_PLATFORM_ERROR_NOT_FOUND if ifindex not available. */ gboolean -nm_platform_link_delete (int ifindex) +nm_platform_link_delete (NMPlatform *self, int ifindex) { - const char *name; + const NMPlatformLink *pllink; - reset_error (); + _CHECK_SELF (self, klass, FALSE); - g_return_val_if_fail (klass->link_delete, FALSE); - - name = nm_platform_link_get_name (ifindex); - - if (!name) + pllink = nm_platform_link_get (self, ifindex); + if (!pllink) return FALSE; - debug ("link: deleting '%s' (%d)", name, ifindex); - return klass->link_delete (platform, ifindex); + _LOGD ("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 (const char *name) +nm_platform_link_get_ifindex (NMPlatform *self, const char *name) { - int ifindex; - - reset_error (); + const NMPlatformLink *pllink; - g_return_val_if_fail (name, 0); - g_return_val_if_fail (klass->link_get_ifindex, 0); - - ifindex = klass->link_get_ifindex (platform, name); - - if (!ifindex) { - debug ("link not found: %s", name); - platform->error = NM_PLATFORM_ERROR_NOT_FOUND; - } - - return ifindex; + 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 (int ifindex) +nm_platform_link_get_name (NMPlatform *self, int ifindex) { - const char *name; - - reset_error (); - - g_return_val_if_fail (klass->link_get_name, NULL); + const NMPlatformLink *pllink; - name = klass->link_get_name (platform, ifindex); - - if (!name) { - debug ("link not found: %d", ifindex); - platform->error = NM_PLATFORM_ERROR_NOT_FOUND; - return FALSE; - } + _CHECK_SELF (self, klass, NULL); - return name; + 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 (int ifindex) +nm_platform_link_get_type (NMPlatform *self, int ifindex) { - reset_error (); + const NMPlatformLink *pllink; - g_return_val_if_fail (klass->link_get_type, NM_LINK_TYPE_NONE); + _CHECK_SELF (self, klass, NM_LINK_TYPE_NONE); - return klass->link_get_type (platform, ifindex); + 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 @@ -674,113 +756,200 @@ nm_platform_link_get_type (int ifindex) * other cases it may not. On error, %NULL is returned. */ const char * -nm_platform_link_get_type_name (int ifindex) +nm_platform_link_get_type_name (NMPlatform *self, int ifindex) { - reset_error (); + _CHECK_SELF (self, klass, NULL); g_return_val_if_fail (klass->link_get_type_name, NULL); - return klass->link_get_type_name (platform, ifindex); + 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 (int ifindex) +nm_platform_link_is_software (NMPlatform *self, int ifindex) { - return (nm_platform_link_get_type (ifindex) & 0x10000); + 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 (int ifindex) +nm_platform_link_supports_slaves (NMPlatform *self, int ifindex) { - return (nm_platform_link_get_type (ifindex) & 0x20000); + 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 (int ifindex) +nm_platform_link_refresh (NMPlatform *self, int ifindex) { - reset_error (); + _CHECK_SELF (self, klass, FALSE); g_return_val_if_fail (ifindex > 0, FALSE); if (klass->link_refresh) - return klass->link_refresh (platform, ifindex); + 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 (int ifindex) +nm_platform_link_is_up (NMPlatform *self, int ifindex) { - reset_error (); - - g_return_val_if_fail (ifindex >= 0, FALSE); - g_return_val_if_fail (klass->link_is_up, FALSE); + _CHECK_SELF (self, klass, FALSE); - return klass->link_is_up (platform, ifindex); + 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 (int ifindex) +nm_platform_link_is_connected (NMPlatform *self, int ifindex) { - reset_error (); + const NMPlatformLink *pllink; - g_return_val_if_fail (ifindex >= 0, FALSE); - g_return_val_if_fail (klass->link_is_connected, FALSE); + _CHECK_SELF (self, klass, FALSE); - return klass->link_is_connected (platform, ifindex); + 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 (int ifindex) +nm_platform_link_uses_arp (NMPlatform *self, int ifindex) { - reset_error (); + _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 (klass->link_uses_arp, FALSE); + g_return_val_if_fail (iid, FALSE); + +#if HAVE_LIBNL_INET6_TOKEN + { + const NMPlatformLink *pllink; - return klass->link_uses_arp (platform, ifindex); + 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 @@ -790,20 +959,28 @@ nm_platform_link_uses_arp (int ifindex) * Returns: %TRUE if NM handles the IPv6LL address for @ifindex */ gboolean -nm_platform_link_get_user_ipv6ll_enabled (int ifindex) +nm_platform_link_get_user_ipv6ll_enabled (NMPlatform *self, int ifindex) { - reset_error (); + _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_get_user_ipv6ll_enabled) - return klass->link_get_user_ipv6ll_enabled (platform, ifindex); +#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 @@ -813,189 +990,248 @@ nm_platform_link_get_user_ipv6ll_enabled (int ifindex) * Returns: %TRUE if the operation was successful, %FALSE if it failed. */ gboolean -nm_platform_link_set_user_ipv6ll_enabled (int ifindex, gboolean enabled) +nm_platform_link_set_user_ipv6ll_enabled (NMPlatform *self, int ifindex, gboolean enabled) { - reset_error (); + _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 (platform, ifindex, 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 (int ifindex, gconstpointer address, size_t length) +nm_platform_link_set_address (NMPlatform *self, int ifindex, gconstpointer address, size_t length) { - reset_error (); + _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 (ifindex), ifindex); - return klass->link_set_address (platform, ifindex, address, length); + _LOGD ("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 * - * Saves interface hardware address to @address. + * Returns: the interface hardware address as an array of bytes of + * length @length. */ gconstpointer -nm_platform_link_get_address (int ifindex, size_t *length) +nm_platform_link_get_address (NMPlatform *self, int ifindex, size_t *length) { - reset_error (); + 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); - g_return_val_if_fail (klass->link_get_address, NULL); - return klass->link_get_address (platform, ifindex, length); + 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 (int ifindex) +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 (platform, ifindex); + return klass->link_supports_carrier_detect (self, ifindex); } gboolean -nm_platform_link_supports_vlans (int ifindex) +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 (platform, ifindex); + 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 (int ifindex) +nm_platform_link_set_up (NMPlatform *self, int ifindex, gboolean *out_no_firmware) { - reset_error (); + _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 (ifindex), ifindex); - return klass->link_set_up (platform, ifindex); + _LOGD ("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 (int ifindex) +nm_platform_link_set_down (NMPlatform *self, int ifindex) { - reset_error (); + _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 (ifindex), ifindex); - return klass->link_set_down (platform, ifindex); + _LOGD ("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 (int ifindex) +nm_platform_link_set_arp (NMPlatform *self, int ifindex) { - reset_error (); + _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 (ifindex), ifindex); - return klass->link_set_arp (platform, ifindex); + _LOGD ("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 (int ifindex) +nm_platform_link_set_noarp (NMPlatform *self, int ifindex) { - reset_error (); + _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 (ifindex), ifindex); - return klass->link_set_noarp (platform, ifindex); + _LOGD ("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 (int ifindex, guint32 mtu) +nm_platform_link_set_mtu (NMPlatform *self, int ifindex, guint32 mtu) { - reset_error (); + _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 (ifindex), ifindex, mtu); - return klass->link_set_mtu (platform, ifindex, mtu); + _LOGD ("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 (int ifindex) +nm_platform_link_get_mtu (NMPlatform *self, int ifindex) { - reset_error (); + const NMPlatformLink *pllink; - g_return_val_if_fail (ifindex >= 0, 0); - g_return_val_if_fail (klass->link_get_mtu, 0); + _CHECK_SELF (self, klass, 0); - return klass->link_get_mtu (platform, ifindex); + 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 @@ -1008,18 +1244,20 @@ nm_platform_link_get_mtu (int ifindex) * or if the interface has no physical port ID. */ char * -nm_platform_link_get_physical_port_id (int ifindex) +nm_platform_link_get_physical_port_id (NMPlatform *self, int ifindex) { - reset_error (); + _CHECK_SELF (self, klass, NULL); g_return_val_if_fail (ifindex >= 0, NULL); - g_return_val_if_fail (klass->link_get_physical_port_id, NULL); - return klass->link_get_physical_port_id (platform, ifindex); + 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 @@ -1030,233 +1268,277 @@ nm_platform_link_get_physical_port_id (int ifindex) * interface has no device ID. */ guint -nm_platform_link_get_dev_id (int ifindex) +nm_platform_link_get_dev_id (NMPlatform *self, int ifindex) { - reset_error (); + _CHECK_SELF (self, klass, 0); g_return_val_if_fail (ifindex >= 0, 0); - g_return_val_if_fail (klass->link_get_dev_id, 0); - return klass->link_get_dev_id (platform, ifindex); + 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 (int ifindex) +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) { - reset_error (); + _CHECK_SELF (self, klass, FALSE); g_return_val_if_fail (ifindex >= 0, FALSE); - g_return_val_if_fail (klass->link_get_wake_on_lan, FALSE); + g_return_val_if_fail (klass->link_get_driver_info, FALSE); - return klass->link_get_wake_on_lan (platform, ifindex); + 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 (int master, int slave) +nm_platform_link_enslave (NMPlatform *self, int master, int slave) { - reset_error (); + _CHECK_SELF (self, klass, FALSE); - g_assert (platform); 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 (slave), slave, - nm_platform_link_get_name (master), master); - return klass->link_enslave (platform, master, slave); + _LOGD ("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 (int master, int slave) +nm_platform_link_release (NMPlatform *self, int master, int slave) { - reset_error (); + _CHECK_SELF (self, klass, FALSE); - g_assert (platform); 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 (slave) != master) { - platform->error = NM_PLATFORM_ERROR_NOT_SLAVE; + 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 (slave), slave, - nm_platform_link_get_name (master), master); - return klass->link_release (platform, master, slave); + _LOGD ("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 (int slave) +nm_platform_link_get_master (NMPlatform *self, int slave) { - reset_error (); + const NMPlatformLink *pllink; + + _CHECK_SELF (self, klass, 0); - g_assert (platform); g_return_val_if_fail (slave >= 0, FALSE); - g_return_val_if_fail (klass->link_get_master, FALSE); - if (!nm_platform_link_get_name (slave)) { - platform->error = NM_PLATFORM_ERROR_NOT_FOUND; - return 0; - } - return klass->link_get_master (platform, slave); + 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. */ -gboolean -nm_platform_bridge_add (const char *name, const void *address, size_t address_len) +NMPlatformError +nm_platform_bridge_add (NMPlatform *self, + const char *name, + const void *address, + size_t address_len, + NMPlatformLink *out_link) { - debug ("link: adding bridge '%s'", name); - return nm_platform_link_add (name, NM_LINK_TYPE_BRIDGE, address, address_len); + 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. */ -gboolean -nm_platform_bond_add (const char *name) +NMPlatformError +nm_platform_bond_add (NMPlatform *self, const char *name, NMPlatformLink *out_link) { - debug ("link: adding bond '%s'", name); - return nm_platform_link_add (name, NM_LINK_TYPE_BOND, NULL, 0); + 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. */ -gboolean -nm_platform_team_add (const char *name) +NMPlatformError +nm_platform_team_add (NMPlatform *self, const char *name, NMPlatformLink *out_link) { - debug ("link: adding team '%s'", name); - return nm_platform_link_add (name, NM_LINK_TYPE_TEAM, NULL, 0); + 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. */ -gboolean -nm_platform_vlan_add (const char *name, int parent, int vlanid, guint32 vlanflags) +NMPlatformError +nm_platform_vlan_add (NMPlatform *self, + const char *name, + int parent, + int vlanid, + guint32 vlanflags, + NMPlatformLink *out_link) { - reset_error (); + NMPlatformError plerr; - g_assert (platform); - g_return_val_if_fail (parent >= 0, FALSE); - g_return_val_if_fail (vlanid >= 0, FALSE); - g_return_val_if_fail (name, FALSE); - g_return_val_if_fail (klass->vlan_add, FALSE); + _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); - if (nm_platform_link_exists (name)) { - debug ("link already exists: %s", name); - platform->error = NM_PLATFORM_ERROR_EXISTS; - return FALSE; - } + 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); - return klass->vlan_add (platform, name, parent, vlanid, vlanflags); + _LOGD ("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 (int ifindex, const char *option, const char *value) +nm_platform_master_set_option (NMPlatform *self, int ifindex, const char *option, const char *value) { - reset_error (); + _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 (platform, ifindex, option, value); + return klass->master_set_option (self, ifindex, option, value); } char * -nm_platform_master_get_option (int ifindex, const char *option) +nm_platform_master_get_option (NMPlatform *self, int ifindex, const char *option) { - reset_error (); + _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 (platform, ifindex, option); + return klass->master_get_option (self, ifindex, option); } gboolean -nm_platform_slave_set_option (int ifindex, const char *option, const char *value) +nm_platform_slave_set_option (NMPlatform *self, int ifindex, const char *option, const char *value) { - reset_error (); + _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 (platform, ifindex, option, value); + return klass->slave_set_option (self, ifindex, option, value); } char * -nm_platform_slave_get_option (int ifindex, const char *option) +nm_platform_slave_get_option (NMPlatform *self, int ifindex, const char *option) { - reset_error (); + _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 (platform, ifindex, option); + return klass->slave_get_option (self, ifindex, option); } gboolean -nm_platform_vlan_get_info (int ifindex, int *parent, int *vlanid) +nm_platform_vlan_get_info (NMPlatform *self, int ifindex, int *parent, int *vlanid) { - reset_error (); + _CHECK_SELF (self, klass, FALSE); - g_assert (platform); g_return_val_if_fail (klass->vlan_get_info, FALSE); if (parent) @@ -1264,261 +1546,274 @@ nm_platform_vlan_get_info (int ifindex, int *parent, int *vlanid) if (vlanid) *vlanid = 0; - if (nm_platform_link_get_type (ifindex) != NM_LINK_TYPE_VLAN) + if (nm_platform_link_get_type (self, ifindex) != NM_LINK_TYPE_VLAN) return FALSE; - return klass->vlan_get_info (platform, ifindex, parent, vlanid); + return klass->vlan_get_info (self, ifindex, parent, vlanid); } gboolean -nm_platform_vlan_set_ingress_map (int ifindex, int from, int to) +nm_platform_vlan_set_ingress_map (NMPlatform *self, int ifindex, int from, int to) { - reset_error (); + _CHECK_SELF (self, klass, FALSE); - g_assert (platform); 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 (platform, ifindex, from, to); + _LOGD ("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 (int ifindex, int from, int to) +nm_platform_vlan_set_egress_map (NMPlatform *self, int ifindex, int from, int to) { - reset_error (); + _CHECK_SELF (self, klass, FALSE); - g_assert (platform); 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 (platform, ifindex, from, to); + _LOGD ("link: setting vlan egress map for %d from %d to %d", ifindex, from, to); + return klass->vlan_set_egress_map (self, ifindex, from, to); } -gboolean -nm_platform_infiniband_partition_add (int parent, int p_key) +NMPlatformError +nm_platform_infiniband_partition_add (NMPlatform *self, int parent, int p_key, NMPlatformLink *out_link) { - const char *parent_name; - char *name; + gs_free char *parent_name = NULL; + gs_free char *name = NULL; + NMPlatformError plerr; - reset_error (); + _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); - g_return_val_if_fail (parent >= 0, FALSE); - g_return_val_if_fail (p_key >= 0, FALSE); - g_return_val_if_fail (klass->infiniband_partition_add, FALSE); + 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); - if (nm_platform_link_get_type (parent) != NM_LINK_TYPE_INFINIBAND) { - platform->error = NM_PLATFORM_ERROR_WRONG_TYPE; - return FALSE; - } + 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; - parent_name = nm_platform_link_get_name (parent); name = g_strdup_printf ("%s.%04x", parent_name, p_key); - if (nm_platform_link_exists (name)) { - debug ("infiniband: already exists"); - platform->error = NM_PLATFORM_ERROR_EXISTS; - g_free (name); - return FALSE; - } - g_free (name); + plerr = _link_add_check_existing (self, name, NM_LINK_TYPE_INFINIBAND, out_link); + if (plerr != NM_PLATFORM_ERROR_SUCCESS) + return plerr; - return klass->infiniband_partition_add (platform, parent, p_key); + _LOGD ("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_veth_get_properties (int ifindex, NMPlatformVethProperties *props) +nm_platform_infiniband_get_info (NMPlatform *self, + int ifindex, + int *parent, + int *p_key, + const char **mode) { - reset_error (); + _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 (platform, ifindex, props); + return klass->veth_get_properties (self, ifindex, props); } gboolean -nm_platform_tun_get_properties (int ifindex, NMPlatformTunProperties *props) +nm_platform_tun_get_properties (NMPlatform *self, int ifindex, NMPlatformTunProperties *props) { - reset_error (); + _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 (platform, ifindex, props); + return klass->tun_get_properties (self, ifindex, props); } gboolean -nm_platform_macvlan_get_properties (int ifindex, NMPlatformMacvlanProperties *props) +nm_platform_macvlan_get_properties (NMPlatform *self, int ifindex, NMPlatformMacvlanProperties *props) { - reset_error (); + _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 (platform, ifindex, props); + return klass->macvlan_get_properties (self, ifindex, props); } gboolean -nm_platform_vxlan_get_properties (int ifindex, NMPlatformVxlanProperties *props) +nm_platform_vxlan_get_properties (NMPlatform *self, int ifindex, NMPlatformVxlanProperties *props) { - reset_error (); + _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 (platform, ifindex, props); + return klass->vxlan_get_properties (self, ifindex, props); } gboolean -nm_platform_gre_get_properties (int ifindex, NMPlatformGreProperties *props) +nm_platform_gre_get_properties (NMPlatform *self, int ifindex, NMPlatformGreProperties *props) { - reset_error (); + _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 (platform, ifindex, props); + return klass->gre_get_properties (self, ifindex, props); } gboolean -nm_platform_wifi_get_capabilities (int ifindex, NMDeviceWifiCapabilities *caps) +nm_platform_wifi_get_capabilities (NMPlatform *self, int ifindex, NMDeviceWifiCapabilities *caps) { - reset_error (); + _CHECK_SELF (self, klass, FALSE); g_return_val_if_fail (ifindex > 0, FALSE); - return klass->wifi_get_capabilities (platform, ifindex, caps); + return klass->wifi_get_capabilities (self, ifindex, caps); } gboolean -nm_platform_wifi_get_bssid (int ifindex, guint8 *bssid) +nm_platform_wifi_get_bssid (NMPlatform *self, int ifindex, guint8 *bssid) { - reset_error (); + _CHECK_SELF (self, klass, FALSE); g_return_val_if_fail (ifindex > 0, FALSE); - return klass->wifi_get_bssid (platform, ifindex, bssid); + return klass->wifi_get_bssid (self, ifindex, bssid); } GByteArray * -nm_platform_wifi_get_ssid (int ifindex) +nm_platform_wifi_get_ssid (NMPlatform *self, int ifindex) { - reset_error (); + _CHECK_SELF (self, klass, NULL); g_return_val_if_fail (ifindex > 0, NULL); - return klass->wifi_get_ssid (platform, ifindex); + return klass->wifi_get_ssid (self, ifindex); } guint32 -nm_platform_wifi_get_frequency (int ifindex) +nm_platform_wifi_get_frequency (NMPlatform *self, int ifindex) { - reset_error (); + _CHECK_SELF (self, klass, 0); g_return_val_if_fail (ifindex > 0, 0); - return klass->wifi_get_frequency (platform, ifindex); + return klass->wifi_get_frequency (self, ifindex); } int -nm_platform_wifi_get_quality (int ifindex) +nm_platform_wifi_get_quality (NMPlatform *self, int ifindex) { - reset_error (); + _CHECK_SELF (self, klass, 0); g_return_val_if_fail (ifindex > 0, 0); - return klass->wifi_get_quality (platform, ifindex); + return klass->wifi_get_quality (self, ifindex); } guint32 -nm_platform_wifi_get_rate (int ifindex) +nm_platform_wifi_get_rate (NMPlatform *self, int ifindex) { - reset_error (); + _CHECK_SELF (self, klass, 0); g_return_val_if_fail (ifindex > 0, 0); - return klass->wifi_get_rate (platform, ifindex); + return klass->wifi_get_rate (self, ifindex); } NM80211Mode -nm_platform_wifi_get_mode (int ifindex) +nm_platform_wifi_get_mode (NMPlatform *self, int ifindex) { - reset_error (); + _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 (platform, ifindex); + return klass->wifi_get_mode (self, ifindex); } void -nm_platform_wifi_set_mode (int ifindex, NM80211Mode mode) +nm_platform_wifi_set_mode (NMPlatform *self, int ifindex, NM80211Mode mode) { - reset_error (); + _CHECK_SELF_VOID (self, klass); g_return_if_fail (ifindex > 0); - klass->wifi_set_mode (platform, ifindex, mode); + klass->wifi_set_mode (self, ifindex, mode); } guint32 -nm_platform_wifi_find_frequency (int ifindex, const guint32 *freqs) +nm_platform_wifi_find_frequency (NMPlatform *self, int ifindex, const guint32 *freqs) { - reset_error (); + _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 (platform, ifindex, freqs); + return klass->wifi_find_frequency (self, ifindex, freqs); } void -nm_platform_wifi_indicate_addressing_running (int ifindex, gboolean running) +nm_platform_wifi_indicate_addressing_running (NMPlatform *self, int ifindex, gboolean running) { - reset_error (); + _CHECK_SELF_VOID (self, klass); g_return_if_fail (ifindex > 0); - klass->wifi_indicate_addressing_running (platform, ifindex, running); + klass->wifi_indicate_addressing_running (self, ifindex, running); } guint32 -nm_platform_mesh_get_channel (int ifindex) +nm_platform_mesh_get_channel (NMPlatform *self, int ifindex) { - reset_error (); + _CHECK_SELF (self, klass, 0); g_return_val_if_fail (ifindex > 0, 0); - return klass->mesh_get_channel (platform, ifindex); + return klass->mesh_get_channel (self, ifindex); } gboolean -nm_platform_mesh_set_channel (int ifindex, guint32 channel) +nm_platform_mesh_set_channel (NMPlatform *self, int ifindex, guint32 channel) { - reset_error (); + _CHECK_SELF (self, klass, FALSE); g_return_val_if_fail (ifindex > 0, FALSE); - return klass->mesh_set_channel (platform, ifindex, channel); + return klass->mesh_set_channel (self, ifindex, channel); } gboolean -nm_platform_mesh_set_ssid (int ifindex, const guint8 *ssid, gsize len) +nm_platform_mesh_set_ssid (NMPlatform *self, int ifindex, const guint8 *ssid, gsize len) { - reset_error (); + _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 (platform, ifindex, ssid, len); + return klass->mesh_set_ssid (self, ifindex, ssid, len); } #define TO_STRING_DEV_BUF_SIZE (5+15+1) static const char * -_to_string_dev (int ifindex, char *buf, size_t size) +_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 ? nm_platform_link_get_name (ifindex) : NULL; + const char *name = ifindex > 0 && self ? nm_platform_link_get_name (self, ifindex) : NULL; char *buf2; strcpy (buf, " dev "); @@ -1538,29 +1833,30 @@ _to_string_dev (int ifindex, char *buf, size_t size) /******************************************************************/ GArray * -nm_platform_ip4_address_get_all (int ifindex) +nm_platform_ip4_address_get_all (NMPlatform *self, int ifindex) { - reset_error (); + _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 (platform, ifindex); + return klass->ip4_address_get_all (self, ifindex); } GArray * -nm_platform_ip6_address_get_all (int ifindex) +nm_platform_ip6_address_get_all (NMPlatform *self, int ifindex) { - reset_error (); + _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 (platform, ifindex); + return klass->ip6_address_get_all (self, ifindex); } gboolean -nm_platform_ip4_address_add (int ifindex, +nm_platform_ip4_address_add (NMPlatform *self, + int ifindex, in_addr_t address, in_addr_t peer_address, int plen, @@ -1568,7 +1864,7 @@ nm_platform_ip4_address_add (int ifindex, guint32 preferred, const char *label) { - reset_error (); + _CHECK_SELF (self, klass, FALSE); g_return_val_if_fail (ifindex > 0, FALSE); g_return_val_if_fail (plen > 0, FALSE); @@ -1590,13 +1886,14 @@ nm_platform_ip4_address_add (int ifindex, 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)); + _LOGD ("address: adding or updating IPv4 address: %s", nm_platform_ip4_address_to_string (&addr)); } - return klass->ip4_address_add (platform, ifindex, address, peer_address, plen, lifetime, preferred, label); + return klass->ip4_address_add (self, ifindex, address, peer_address, plen, lifetime, preferred, label); } gboolean -nm_platform_ip6_address_add (int ifindex, +nm_platform_ip6_address_add (NMPlatform *self, + int ifindex, struct in6_addr address, struct in6_addr peer_address, int plen, @@ -1604,7 +1901,7 @@ nm_platform_ip6_address_add (int ifindex, guint32 preferred, guint flags) { - reset_error (); + _CHECK_SELF (self, klass, FALSE); g_return_val_if_fail (ifindex > 0, FALSE); g_return_val_if_fail (plen > 0, FALSE); @@ -1624,74 +1921,72 @@ nm_platform_ip6_address_add (int ifindex, addr.preferred = preferred; addr.flags = flags; - debug ("address: adding or updating IPv6 address: %s", nm_platform_ip6_address_to_string (&addr)); + _LOGD ("address: adding or updating IPv6 address: %s", nm_platform_ip6_address_to_string (&addr)); } - return klass->ip6_address_add (platform, ifindex, address, peer_address, plen, lifetime, preferred, flags); + return klass->ip6_address_add (self, ifindex, address, peer_address, plen, lifetime, preferred, flags); } gboolean -nm_platform_ip4_address_delete (int ifindex, in_addr_t address, int plen, in_addr_t peer_address) +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]; - reset_error (); + _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", + _LOGD ("address: deleting IPv4 address %s/%d, %s%s%sifindex %d%s", nm_utils_inet4_ntop (address, NULL), plen, peer_address ? "peer " : "", peer_address ? nm_utils_inet4_ntop (peer_address, str_peer) : "", peer_address ? ", " : "", ifindex, - _to_string_dev (ifindex, str_dev, sizeof (str_dev))); - return klass->ip4_address_delete (platform, ifindex, address, plen, peer_address); + _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 (int ifindex, struct in6_addr address, int plen) +nm_platform_ip6_address_delete (NMPlatform *self, int ifindex, struct in6_addr address, int plen) { char str_dev[TO_STRING_DEV_BUF_SIZE]; - reset_error (); + _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", + _LOGD ("address: deleting IPv6 address %s/%d, ifindex %d%s", nm_utils_inet6_ntop (&address, NULL), plen, ifindex, - _to_string_dev (ifindex, str_dev, sizeof (str_dev))); - return klass->ip6_address_delete (platform, ifindex, address, plen); + _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 (int ifindex, in_addr_t address, int plen) +const NMPlatformIP4Address * +nm_platform_ip4_address_get (NMPlatform *self, int ifindex, in_addr_t address, int plen) { - reset_error (); + _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 (platform, ifindex, address, plen); + return klass->ip4_address_get (self, ifindex, address, plen); } -gboolean -nm_platform_ip6_address_exists (int ifindex, struct in6_addr address, int plen) +const NMPlatformIP6Address * +nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr address, int plen) { - reset_error (); + _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 (platform, ifindex, address, plen); + return klass->ip6_address_get (self, ifindex, address, plen); } static gboolean -array_contains_ip4_address (const GArray *addresses, const NMPlatformIP4Address *address) +array_contains_ip4_address (const GArray *addresses, const NMPlatformIP4Address *address, gint64 now, guint32 padding) { guint len = addresses ? addresses->len : 0; guint i; @@ -1699,15 +1994,20 @@ array_contains_ip4_address (const GArray *addresses, const NMPlatformIP4Address for (i = 0; i < len; i++) { NMPlatformIP4Address *candidate = &g_array_index (addresses, NMPlatformIP4Address, i); - if (candidate->address == address->address && candidate->plen == address->plen) - return TRUE; + 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) +array_contains_ip6_address (const GArray *addresses, const NMPlatformIP6Address *address, gint64 now, guint32 padding) { guint len = addresses ? addresses->len : 0; guint i; @@ -1715,108 +2015,27 @@ array_contains_ip6_address (const GArray *addresses, const NMPlatformIP6Address 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) - return TRUE; - } - - return FALSE; -} - -/** - * Takes a pair @timestamp and @duration, and returns the remaining duration based - * on the new timestamp @now. - */ -static guint32 -_rebase_relative_time_on_now (guint32 timestamp, guint32 duration, guint32 now, guint32 padding) -{ - gint64 t; - - if (duration == NM_PLATFORM_LIFETIME_PERMANENT) - return NM_PLATFORM_LIFETIME_PERMANENT; - - if (timestamp == 0) { - /* if the @timestamp is zero, assume it was just left unset and that the relative - * @duration starts counting from @now. This is convenient to construct an address - * and print it in nm_platform_ip4_address_to_string(). - * - * In general it does not make sense to set the @duration without anchoring at - * @timestamp because you don't know the absolute expiration time when looking - * at the address at a later moment. */ - timestamp = now; - } + if (IN6_ARE_ADDR_EQUAL (&candidate->address, &address->address) && candidate->plen == address->plen) { + guint32 lifetime, preferred; - /* For timestamp > now, just accept it and calculate the expected(?) result. */ - t = (gint64) timestamp + (gint64) duration - (gint64) now; - - /* Optional padding to avoid potential races. */ - t += (gint64) padding; - - if (t <= 0) - return 0; - if (t >= NM_PLATFORM_LIFETIME_PERMANENT) - return NM_PLATFORM_LIFETIME_PERMANENT - 1; - return t; -} - -static gboolean -_address_get_lifetime (const NMPlatformIPAddress *address, guint32 now, guint32 padding, guint32 *out_lifetime, guint32 *out_preferred) -{ - guint32 lifetime, preferred; - - if (address->lifetime == 0) { - *out_lifetime = NM_PLATFORM_LIFETIME_PERMANENT; - *out_preferred = NM_PLATFORM_LIFETIME_PERMANENT; - - /* We treat lifetime==0 as permanent addresses to allow easy creation of such addresses - * (without requiring to set the lifetime fields to NM_PLATFORM_LIFETIME_PERMANENT). - * In that case we also expect that the other fields (timestamp and preferred) are left unset. */ - g_return_val_if_fail (address->timestamp == 0 && address->preferred == 0, TRUE); - } else { - lifetime = _rebase_relative_time_on_now (address->timestamp, address->lifetime, now, padding); - if (!lifetime) - return FALSE; - preferred = _rebase_relative_time_on_now (address->timestamp, address->preferred, now, padding); - - *out_lifetime = lifetime; - *out_preferred = MIN (preferred, lifetime); - - /* Assert that non-permanent addresses have a (positive) @timestamp. _rebase_relative_time_on_now() - * treats addresses with timestamp 0 as *now*. Addresses passed to _address_get_lifetime() always - * should have a valid @timestamp, otherwise on every re-sync, their lifetime will be extended anew. - */ - g_return_val_if_fail ( address->timestamp != 0 - || ( address->lifetime == NM_PLATFORM_LIFETIME_PERMANENT - && address->preferred == NM_PLATFORM_LIFETIME_PERMANENT), TRUE); - g_return_val_if_fail (preferred <= lifetime, TRUE); - } - return TRUE; -} - -gboolean -nm_platform_ip4_check_reinstall_device_route (int ifindex, const NMPlatformIP4Address *address, guint32 device_route_metric) -{ - g_return_val_if_fail (address, FALSE); - - if ( ifindex <= 0 - || address->plen <= 0 - || address->plen >= 32) - return FALSE; - - if (device_route_metric == NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE) { - /* The automatically added route would be already our desired priority. - * Nothing to do. */ - return FALSE; + if (nmp_utils_lifetime_get (candidate->timestamp, candidate->lifetime, candidate->preferred, + now, padding, &lifetime, &preferred)) + return TRUE; + } } - return klass->ip4_check_reinstall_device_route (platform, ifindex, address, device_route_metric); + return FALSE; } /** * nm_platform_ip4_address_sync: + * @self: platform instance * @ifindex: Interface index * @known_addresses: List of addresses - * @device_route_metric: the route metric for adding subnet routes (replaces - * the kernel added routes). + * @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 @@ -1825,23 +2044,28 @@ nm_platform_ip4_check_reinstall_device_route (int ifindex, const NMPlatformIP4Ad * Returns: %TRUE on success. */ gboolean -nm_platform_ip4_address_sync (int ifindex, const GArray *known_addresses, guint32 device_route_metric) +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 (ifindex); + 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)) - nm_platform_ip4_address_delete (ifindex, address->address, address->plen, address->peer_address); + 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; @@ -1849,33 +2073,18 @@ nm_platform_ip4_address_sync (int ifindex, const GArray *known_addresses, guint3 for (i = 0; i < known_addresses->len; i++) { const NMPlatformIP4Address *known_address = &g_array_index (known_addresses, NMPlatformIP4Address, i); guint32 lifetime, preferred; - guint32 network; - gboolean reinstall_device_route = FALSE; - /* add a padding of 5 seconds to avoid potential races. */ - if (!_address_get_lifetime ((NMPlatformIPAddress *) known_address, now, 5, &lifetime, &preferred)) + 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_check_reinstall_device_route (ifindex, known_address, device_route_metric)) - reinstall_device_route = TRUE; - - if (!nm_platform_ip4_address_add (ifindex, known_address->address, known_address->peer_address, known_address->plen, lifetime, preferred, known_address->label)) + 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 (reinstall_device_route) { - /* Kernel automatically adds a device route for us with metric 0. That is not what we want. - * Remove it, and re-add it. - * - * In face of having the same subnets on two different interfaces with the same metric, - * this is a problem. Surprisingly, kernel is able to add two routes for the same subnet/prefix,metric - * to different interfaces. We cannot. Adding one, would replace the other. This is avoided - * by the above nm_platform_ip4_check_reinstall_device_route() check. - */ - network = nm_utils_ip4_address_clear_host_address (known_address->address, known_address->plen); - (void) nm_platform_ip4_route_add (ifindex, NM_IP_CONFIG_SOURCE_KERNEL, network, known_address->plen, - 0, known_address->address, device_route_metric, 0); - (void) nm_platform_ip4_route_delete (ifindex, network, known_address->plen, - NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE); + 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); } } @@ -1884,6 +2093,7 @@ nm_platform_ip4_address_sync (int ifindex, const GArray *known_addresses, guint3 /** * 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 @@ -1895,7 +2105,7 @@ nm_platform_ip4_address_sync (int ifindex, const GArray *known_addresses, guint3 * Returns: %TRUE on success. */ gboolean -nm_platform_ip6_address_sync (int ifindex, const GArray *known_addresses, gboolean keep_link_local) +nm_platform_ip6_address_sync (NMPlatform *self, int ifindex, const GArray *known_addresses, gboolean keep_link_local) { GArray *addresses; NMPlatformIP6Address *address; @@ -1903,7 +2113,7 @@ nm_platform_ip6_address_sync (int ifindex, const GArray *known_addresses, gboole int i; /* Delete unknown addresses */ - addresses = nm_platform_ip6_address_get_all (ifindex); + addresses = nm_platform_ip6_address_get_all (self, ifindex); for (i = 0; i < addresses->len; i++) { address = &g_array_index (addresses, NMPlatformIP6Address, i); @@ -1911,8 +2121,8 @@ nm_platform_ip6_address_sync (int ifindex, const GArray *known_addresses, gboole if (keep_link_local && IN6_IS_ADDR_LINKLOCAL (&address->address)) continue; - if (!array_contains_ip6_address (known_addresses, address)) - nm_platform_ip6_address_delete (ifindex, address->address, address->plen); + 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); @@ -1924,11 +2134,11 @@ nm_platform_ip6_address_sync (int ifindex, const GArray *known_addresses, gboole const NMPlatformIP6Address *known_address = &g_array_index (known_addresses, NMPlatformIP6Address, i); guint32 lifetime, preferred; - /* add a padding of 5 seconds to avoid potential races. */ - if (!_address_get_lifetime ((NMPlatformIPAddress *) known_address, now, 5, &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 (ifindex, known_address->address, + 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; @@ -1938,51 +2148,50 @@ nm_platform_ip6_address_sync (int ifindex, const GArray *known_addresses, gboole } gboolean -nm_platform_address_flush (int ifindex) +nm_platform_address_flush (NMPlatform *self, int ifindex) { - return nm_platform_ip4_address_sync (ifindex, NULL, 0) - && nm_platform_ip6_address_sync (ifindex, NULL, FALSE); + _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 (int ifindex, NMPlatformGetRouteMode mode) +nm_platform_ip4_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags) { - reset_error (); + _CHECK_SELF (self, klass, NULL); g_return_val_if_fail (ifindex >= 0, NULL); - g_return_val_if_fail (klass->ip4_route_get_all, NULL); - return klass->ip4_route_get_all (platform, ifindex, mode); + return klass->ip4_route_get_all (self, ifindex, flags); } GArray * -nm_platform_ip6_route_get_all (int ifindex, NMPlatformGetRouteMode mode) +nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags) { - reset_error (); + _CHECK_SELF (self, klass, NULL); g_return_val_if_fail (ifindex >= 0, NULL); - g_return_val_if_fail (klass->ip6_route_get_all, NULL); - return klass->ip6_route_get_all (platform, ifindex, mode); + return klass->ip6_route_get_all (self, ifindex, flags); } gboolean -nm_platform_ip4_route_add (int ifindex, NMIPConfigSource source, +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) { - reset_error (); + _CHECK_SELF (self, klass, FALSE); - g_return_val_if_fail (platform, 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 }; - char pref_src_buf[NM_UTILS_INET_ADDRSTRLEN]; route.ifindex = ifindex; route.source = source; @@ -1991,21 +2200,21 @@ nm_platform_ip4_route_add (int ifindex, NMIPConfigSource source, route.gateway = gateway; route.metric = metric; route.mss = mss; + route.pref_src = pref_src; - debug ("route: adding or updating IPv4 route: %s%s%s%s", nm_platform_ip4_route_to_string (&route), - pref_src ? " (src: " : "", - pref_src ? nm_utils_inet4_ntop (pref_src, pref_src_buf) : "", - pref_src ? ")" : ""); + _LOGD ("route: adding or updating IPv4 route: %s", nm_platform_ip4_route_to_string (&route)); } - return klass->ip4_route_add (platform, ifindex, source, network, plen, gateway, pref_src, metric, mss); + return klass->ip4_route_add (self, ifindex, source, network, plen, gateway, pref_src, metric, mss); } gboolean -nm_platform_ip6_route_add (int ifindex, NMIPConfigSource source, +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) { - g_return_val_if_fail (platform, FALSE); + _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); @@ -2020,256 +2229,55 @@ nm_platform_ip6_route_add (int ifindex, NMIPConfigSource source, route.metric = metric; route.mss = mss; - debug ("route: adding or updating IPv6 route: %s", nm_platform_ip6_route_to_string (&route)); + _LOGD ("route: adding or updating IPv6 route: %s", nm_platform_ip6_route_to_string (&route)); } - return klass->ip6_route_add (platform, ifindex, source, network, plen, gateway, metric, mss); + return klass->ip6_route_add (self, ifindex, source, network, plen, gateway, metric, mss); } gboolean -nm_platform_ip4_route_delete (int ifindex, in_addr_t network, int plen, guint32 metric) +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]; - reset_error (); + _CHECK_SELF (self, klass, FALSE); - g_return_val_if_fail (platform, FALSE); g_return_val_if_fail (klass->ip4_route_delete, FALSE); - debug ("route: deleting IPv4 route %s/%d, metric=%"G_GUINT32_FORMAT", ifindex %d%s", + _LOGD ("route: deleting IPv4 route %s/%d, metric=%"G_GUINT32_FORMAT", ifindex %d%s", nm_utils_inet4_ntop (network, NULL), plen, metric, ifindex, - _to_string_dev (ifindex, str_dev, sizeof (str_dev))); - return klass->ip4_route_delete (platform, ifindex, network, plen, metric); + _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 (int ifindex, struct in6_addr network, int plen, guint32 metric) +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]; - reset_error (); + _CHECK_SELF (self, klass, FALSE); - g_return_val_if_fail (platform, FALSE); g_return_val_if_fail (klass->ip6_route_delete, FALSE); - debug ("route: deleting IPv6 route %s/%d, metric=%"G_GUINT32_FORMAT", ifindex %d%s", + _LOGD ("route: deleting IPv6 route %s/%d, metric=%"G_GUINT32_FORMAT", ifindex %d%s", nm_utils_inet6_ntop (&network, NULL), plen, metric, ifindex, - _to_string_dev (ifindex, str_dev, sizeof (str_dev))); - return klass->ip6_route_delete (platform, ifindex, network, plen, metric); -} - -gboolean -nm_platform_ip4_route_exists (int ifindex, in_addr_t network, int plen, guint32 metric) -{ - reset_error (); - - g_return_val_if_fail (platform, FALSE); - g_return_val_if_fail (klass->ip4_route_exists, FALSE); - - return klass->ip4_route_exists (platform,ifindex, network, plen, metric); -} - -gboolean -nm_platform_ip6_route_exists (int ifindex, struct in6_addr network, int plen, guint32 metric) -{ - reset_error (); - - g_return_val_if_fail (platform, FALSE); - g_return_val_if_fail (klass->ip6_route_exists, FALSE); - - return klass->ip6_route_exists (platform, ifindex, network, plen, metric); -} - -static gboolean -array_contains_ip4_route (const GArray *routes, const NMPlatformIP4Route *route) -{ - guint len = routes ? routes->len : 0; - guint i; - - for (i = 0; i < len; i++) { - NMPlatformIP4Route *c = &g_array_index (routes, NMPlatformIP4Route, i); - - if (route->network == c->network && - route->plen == c->plen && - route->gateway == c->gateway && - route->metric == c->metric) - return TRUE; - } - - return FALSE; + _to_string_dev (self, ifindex, str_dev, sizeof (str_dev))); + return klass->ip6_route_delete (self, ifindex, network, plen, metric); } -static gboolean -array_contains_ip6_route (const GArray *routes, const NMPlatformIP6Route *route) +const NMPlatformIP4Route * +nm_platform_ip4_route_get (NMPlatform *self, int ifindex, in_addr_t network, int plen, guint32 metric) { - guint len = routes ? routes->len : 0; - guint i; + _CHECK_SELF (self, klass, FALSE); - for (i = 0; i < len; i++) { - NMPlatformIP6Route *c = &g_array_index (routes, NMPlatformIP6Route, i); - - if (IN6_ARE_ADDR_EQUAL (&route->network, &c->network) && - route->plen == c->plen && - IN6_ARE_ADDR_EQUAL (&route->gateway, &c->gateway) && - route->metric == c->metric) - return TRUE; - } - - return FALSE; + return klass->ip4_route_get (self ,ifindex, network, plen, metric); } -/** - * nm_platform_ip4_route_sync: - * @ifindex: Interface index - * @known_routes: List of routes - * - * A convenience function to synchronize routes for a specific interface - * with the least possible disturbance. It simply removes routes that are - * not listed and adds routes that are. - * Default routes are ignored (both in @known_routes and those already - * configured on the device). - * - * Returns: %TRUE on success. - */ -gboolean -nm_platform_ip4_route_sync (int ifindex, const GArray *known_routes) +const NMPlatformIP6Route * +nm_platform_ip6_route_get (NMPlatform *self, int ifindex, struct in6_addr network, int plen, guint32 metric) { - GArray *routes; - NMPlatformIP4Route *route; - const NMPlatformIP4Route *known_route; - gboolean success; - int i, i_type; - - /* Delete unknown routes */ - routes = nm_platform_ip4_route_get_all (ifindex, NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT); - for (i = 0; i < routes->len; i++) { - route = &g_array_index (routes, NMPlatformIP4Route, i); - - if (!array_contains_ip4_route (known_routes, route)) - (void) nm_platform_ip4_route_delete (ifindex, route->network, route->plen, route->metric); - } - - if (!known_routes) { - g_array_free (routes, TRUE); - return TRUE; - } - - /* Add missing routes */ - for (i_type = 0, success = TRUE; i_type < 2 && success; i_type++) { - for (i = 0; i < known_routes->len && success; i++) { - known_route = &g_array_index (known_routes, NMPlatformIP4Route, i); - - if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (known_route)) - continue; + _CHECK_SELF (self, klass, FALSE); - if ( (i_type == 0 && known_route->gateway != 0) - || (i_type == 1 && known_route->gateway == 0)) { - /* Make two runs over the list of routes. On the first, only add - * device routes, on the second the others (gateway routes). */ - continue; - } - - /* Ignore routes that already exist */ - if (!array_contains_ip4_route (routes, known_route)) { - success = nm_platform_ip4_route_add (ifindex, - known_route->source, - known_route->network, - known_route->plen, - known_route->gateway, - 0, - known_route->metric, - known_route->mss); - if (!success && known_route->source < NM_IP_CONFIG_SOURCE_USER) { - nm_log_dbg (LOGD_PLATFORM, "ignore error adding IPv4 route to kernel: %s", - nm_platform_ip4_route_to_string (known_route)); - success = TRUE; - } - } - } - } - - g_array_free (routes, TRUE); - return success; -} - -/** - * nm_platform_ip6_route_sync: - * @ifindex: Interface index - * @known_routes: List of routes - * - * A convenience function to synchronize routes for a specific interface - * with the least possible disturbance. It simply removes routes that are - * not listed and adds routes that are. - * Default routes are ignored (both in @known_routes and those already - * configured on the device). - * - * Returns: %TRUE on success. - */ -gboolean -nm_platform_ip6_route_sync (int ifindex, const GArray *known_routes) -{ - GArray *routes; - NMPlatformIP6Route *route; - const NMPlatformIP6Route *known_route; - gboolean success; - int i, i_type; - - /* Delete unknown routes */ - routes = nm_platform_ip6_route_get_all (ifindex, NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT); - for (i = 0; i < routes->len; i++) { - route = &g_array_index (routes, NMPlatformIP6Route, i); - route->ifindex = 0; - - if (!array_contains_ip6_route (known_routes, route)) - nm_platform_ip6_route_delete (ifindex, route->network, route->plen, route->metric); - } - - if (!known_routes) { - g_array_free (routes, TRUE); - return TRUE; - } - - /* Add missing routes */ - for (i_type = 0, success = TRUE; i_type < 2 && success; i_type++) { - for (i = 0; i < known_routes->len && success; i++) { - known_route = &g_array_index (known_routes, NMPlatformIP6Route, i); - - if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (known_route)) - continue; - - if ( (i_type == 0 && !IN6_IS_ADDR_UNSPECIFIED (&known_route->gateway)) - || (i_type == 1 && IN6_IS_ADDR_UNSPECIFIED (&known_route->gateway))) { - /* Make two runs over the list of routes. On the first, only add - * device routes, on the second the others (gateway routes). */ - continue; - } - - /* Ignore routes that already exist */ - if (!array_contains_ip6_route (routes, known_route)) { - success = nm_platform_ip6_route_add (ifindex, - known_route->source, - known_route->network, - known_route->plen, - known_route->gateway, - known_route->metric, - known_route->mss); - if (!success && known_route->source < NM_IP_CONFIG_SOURCE_USER) { - nm_log_dbg (LOGD_PLATFORM, "ignore error adding IPv6 route to kernel: %s", - nm_platform_ip6_route_to_string (known_route)); - success = TRUE; - } - } - } - } - - g_array_free (routes, TRUE); - return success; -} - -gboolean -nm_platform_route_flush (int ifindex) -{ - return nm_platform_ip4_route_sync (ifindex, NULL) - && nm_platform_ip6_route_sync (ifindex, NULL); + return klass->ip6_route_get (self, ifindex, network, plen, metric); } /******************************************************************/ @@ -2278,6 +2286,10 @@ 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: @@ -2309,7 +2321,7 @@ _lifetime_to_string (guint32 timestamp, guint32 lifetime, gint32 now, char *buf, return "forever"; g_snprintf (buf, buf_size, "%usec", - _rebase_relative_time_on_now (timestamp, lifetime, now, 0)); + nmp_utils_lifetime_rebase_relative_time_on_now (timestamp, lifetime, now, 0)); return buf; } @@ -2322,28 +2334,38 @@ _lifetime_summary_to_string (gint32 now, guint32 timestamp, guint32 preferred, g return buf; } -static char to_string_buffer[256]; +char _nm_platform_to_string_buffer[256]; const char * nm_platform_link_to_string (const NMPlatformLink *link) { char master[20]; char parent[20]; - char *driver, *udi, *type; - GString *str; + 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 = g_string_new (NULL); - if (!link->arp) - g_string_append (str, "NOARP,"); - if (link->up) - g_string_append (str, "UP"); + 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, "DOWN"); + g_string_append (str_flags, "DOWN"); if (link->connected) - g_string_append (str, ",LOWER_UP"); + 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); @@ -2355,19 +2377,69 @@ nm_platform_link_to_string (const NMPlatformLink *link) else parent[0] = 0; - driver = link->driver ? g_strdup_printf (" driver '%s'", link->driver) : NULL; - udi = link->udi ? g_strdup_printf (" udi '%s'", link->udi) : NULL; - type = link->type_name ? NULL : g_strdup_printf ("(%d)", link->type); - - g_snprintf (to_string_buffer, sizeof (to_string_buffer), "%d: %s%s <%s> mtu %d%s %s%s%s", - link->ifindex, link->name, parent, str->str, - link->mtu, master, link->type_name ? link->type_name : type, - driver ? driver : "", udi ? udi : ""); - g_string_free (str, TRUE); - g_free (driver); - g_free (udi); - g_free (type); - return to_string_buffer; + 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; } /** @@ -2403,7 +2475,7 @@ nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address) str_peer = g_strconcat (" ptp ", s_peer, NULL); } - _to_string_dev (address->ifindex, str_dev, sizeof (str_dev)); + _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); @@ -2420,14 +2492,14 @@ nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address) 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 (to_string_buffer, sizeof (to_string_buffer), "%s/%d lft %s pref %s%s%s%s%s src %s", + 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 to_string_buffer; + return _nm_platform_to_string_buffer; } /** @@ -2488,7 +2560,7 @@ nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address) str_peer = g_strconcat (" ptp ", s_peer, NULL); } - _to_string_dev (address->ifindex, str_dev, sizeof (str_dev)); + _to_string_dev (NULL, address->ifindex, str_dev, sizeof (str_dev)); nm_platform_addr_flags2str (address->flags, s_flags, sizeof (s_flags)); @@ -2504,7 +2576,7 @@ nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address) 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 (to_string_buffer, sizeof (to_string_buffer), "%s/%d lft %s pref %s%s%s%s%s src %s", + 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, @@ -2512,7 +2584,7 @@ nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address) source_to_string (address->source)); g_free (str_flags); g_free (str_peer); - return to_string_buffer; + return _nm_platform_to_string_buffer; } /** @@ -2531,21 +2603,38 @@ 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 (route->ifindex, str_dev, sizeof (str_dev)); - - g_snprintf (to_string_buffer, sizeof (to_string_buffer), "%s/%d via %s%s metric %"G_GUINT32_FORMAT" mss %"G_GUINT32_FORMAT" src %s", - s_network, route->plen, s_gateway, + _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)); - return to_string_buffer; + 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; } /** @@ -2571,14 +2660,23 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route) 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 (route->ifindex, str_dev, sizeof (str_dev)); - - g_snprintf (to_string_buffer, sizeof (to_string_buffer), "%s/%d via %s%s metric %"G_GUINT32_FORMAT" mss %"G_GUINT32_FORMAT" src %s", - s_network, route->plen, s_gateway, + _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, + route->metric, + route->mss, source_to_string (route->source)); - return to_string_buffer; + return _nm_platform_to_string_buffer; } #define _CMP_POINTER(a, b) \ @@ -2597,6 +2695,12 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route) 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); \ @@ -2604,6 +2708,16 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route) 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); \ @@ -2611,6 +2725,14 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route) 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), \ @@ -2623,17 +2745,26 @@ 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, up); + _CMP_FIELD (a, b, vlan_id); + _CMP_FIELD (a, b, flags); _CMP_FIELD (a, b, connected); - _CMP_FIELD (a, b, arp); _CMP_FIELD (a, b, mtu); - _CMP_FIELD_STR0 (a, b, type_name); - _CMP_FIELD_STR0 (a, b, udi); - _CMP_FIELD_STR0 (a, b, driver); + _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; } @@ -2680,6 +2811,8 @@ nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route _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; } @@ -2753,8 +2886,8 @@ nm_platform_ip_address_cmp_expiry (const NMPlatformIPAddress *a, const NMPlatfor #undef _CMP_POINTER -static const char * -_change_type_to_string (NMPlatformSignalChangeType change_type) +const char * +nm_platform_signal_change_type_to_string (NMPlatformSignalChangeType change_type) { switch (change_type) { case NM_PLATFORM_SIGNAL_ADDED: @@ -2769,76 +2902,80 @@ _change_type_to_string (NMPlatformSignalChangeType change_type) } static void -log_link (NMPlatform *p, int ifindex, NMPlatformLink *device, NMPlatformSignalChangeType change_type, gpointer user_data) +log_link (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatformLink *device, NMPlatformSignalChangeType change_type, gpointer user_data) { - debug ("signal: link %7s: %s", _change_type_to_string (change_type), nm_platform_link_to_string (device)); + _LOGD ("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, int ifindex, NMPlatformIP4Address *address, NMPlatformSignalChangeType change_type, gpointer user_data) +log_ip4_address (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatformIP4Address *address, NMPlatformSignalChangeType change_type, gpointer user_data) { - debug ("signal: address 4 %7s: %s", _change_type_to_string (change_type), nm_platform_ip4_address_to_string (address)); + _LOGD ("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, int ifindex, NMPlatformIP6Address *address, NMPlatformSignalChangeType change_type, gpointer user_data) +log_ip6_address (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatformIP6Address *address, NMPlatformSignalChangeType change_type, gpointer user_data) { - debug ("signal: address 6 %7s: %s", _change_type_to_string (change_type), nm_platform_ip6_address_to_string (address)); + _LOGD ("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, int ifindex, NMPlatformIP4Route *route, NMPlatformSignalChangeType change_type, gpointer user_data) +log_ip4_route (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatformIP4Route *route, NMPlatformSignalChangeType change_type, gpointer user_data) { - debug ("signal: route 4 %7s: %s", _change_type_to_string (change_type), nm_platform_ip4_route_to_string (route)); + _LOGD ("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, int ifindex, NMPlatformIP6Route *route, NMPlatformSignalChangeType change_type, gpointer user_data) +log_ip6_route (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatformIP6Route *route, NMPlatformSignalChangeType change_type, gpointer user_data) { - debug ("signal: route 6 %7s: %s", _change_type_to_string (change_type), nm_platform_ip6_route_to_string (route)); + _LOGD ("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 (int ifindex, const NMPlatformIPXRoute *route, guint32 v4_pref_src) +_vtr_v4_route_add (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, gint64 metric) { - return nm_platform_ip4_route_add (ifindex > 0 ? ifindex : route->rx.ifindex, + 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, - v4_pref_src, - route->rx.metric, + route->r4.pref_src, + metric >= 0 ? (guint32) metric : route->rx.metric, route->rx.mss); } static gboolean -_vtr_v6_route_add (int ifindex, const NMPlatformIPXRoute *route, guint32 v4_pref_src) +_vtr_v6_route_add (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, gint64 metric) { - return nm_platform_ip6_route_add (ifindex > 0 ? ifindex : route->rx.ifindex, + 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, + metric >= 0 ? (guint32) metric : route->rx.metric, route->rx.mss); } static gboolean -_vtr_v4_route_delete (int ifindex, const NMPlatformIPXRoute *route) +_vtr_v4_route_delete (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route) { - return nm_platform_ip4_route_delete (ifindex > 0 ? ifindex : route->rx.ifindex, + 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 (int ifindex, const NMPlatformIPXRoute *route) +_vtr_v6_route_delete (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route) { - return nm_platform_ip6_route_delete (ifindex > 0 ? ifindex : route->rx.ifindex, + return nm_platform_ip6_route_delete (self, + ifindex > 0 ? ifindex : route->rx.ifindex, route->r6.network, route->rx.plen, route->rx.metric); @@ -2851,15 +2988,15 @@ _vtr_v4_metric_normalize (guint32 metric) } static gboolean -_vtr_v4_route_delete_default (int ifindex, guint32 metric) +_vtr_v4_route_delete_default (NMPlatform *self, int ifindex, guint32 metric) { - return nm_platform_ip4_route_delete (ifindex, 0, 0, metric); + return nm_platform_ip4_route_delete (self, ifindex, 0, 0, metric); } static gboolean -_vtr_v6_route_delete_default (int ifindex, guint32 metric) +_vtr_v6_route_delete_default (NMPlatform *self, int ifindex, guint32 metric) { - return nm_platform_ip6_route_delete (ifindex, in6addr_any, 0, metric); + return nm_platform_ip6_route_delete (self, ifindex, in6addr_any, 0, metric); } /******************************************************************/ @@ -2893,6 +3030,35 @@ const NMPlatformVTableRoute nm_platform_vtable_route_v6 = { /******************************************************************/ 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) { } @@ -2903,13 +3069,26 @@ nm_platform_init (NMPlatform *object) G_SIGNAL_RUN_FIRST, \ G_CALLBACK (method), \ NULL, NULL, NULL, \ - G_TYPE_NONE, 4, G_TYPE_INT, G_TYPE_POINTER, NM_TYPE_PLATFORM_SIGNAL_CHANGE_TYPE, NM_TYPE_PLATFORM_REASON); + 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; + + 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) |