diff options
author | Dan Williams <dcbw@redhat.com> | 2014-09-04 15:11:55 -0500 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2014-09-04 15:11:55 -0500 |
commit | 4e530adf60d65e76252ad9e32ee1788c028abb27 (patch) | |
tree | 825642ccb14f5220afa00c858851834eda480e3c | |
parent | 899df02e4c9a0be1b3684e4f60c3fc6dae01d18e (diff) | |
parent | 5e4761a3a9cb1cba692d41d79aa389f539752e50 (diff) | |
download | NetworkManager-4e530adf60d65e76252ad9e32ee1788c028abb27.tar.gz |
merge: handle IPv6 link-local addresses from userspace when possible (bgo #734149)
-rw-r--r-- | configure.ac | 19 | ||||
-rw-r--r-- | src/devices/nm-device.c | 146 | ||||
-rw-r--r-- | src/platform/nm-linux-platform.c | 104 | ||||
-rw-r--r-- | src/platform/nm-platform.c | 61 | ||||
-rw-r--r-- | src/platform/nm-platform.h | 8 |
5 files changed, 326 insertions, 12 deletions
diff --git a/configure.ac b/configure.ac index 1bc73f6eb7..23898c3bbb 100644 --- a/configure.ac +++ b/configure.ac @@ -386,6 +386,25 @@ PKG_CHECK_MODULES(LIBNL, libnl-3.0 >= 3.2.8 libnl-route-3.0 libnl-genl-3.0) AC_SUBST(LIBNL_CFLAGS) AC_SUBST(LIBNL_LIBS) +AC_CHECK_LIB([nl-route-3], [rtnl_link_inet6_get_addr_gen_mode], + ac_have_addr_gen_mode="1", + ac_have_addr_gen_mode="0") +AC_DEFINE_UNQUOTED(HAVE_LIBNL_INET6_ADDR_GEN_MODE, + $ac_have_addr_gen_mode, [Define if libnl has rtnl_link_inet6_get_addr_gen_mode()]) + +AC_MSG_CHECKING([Linux kernel IN6_ADDR_GEN_MODE enum]) +AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#ifndef __user + #define __user + #endif + #include <linux/if_link.h>]], + [[int a = IN6_ADDR_GEN_MODE_EUI64; a++;]])], + [ac_have_kernel_gen_mode="1"], + [ac_have_kernel_gen_mode="0"]) +AC_DEFINE_UNQUOTED(HAVE_KERNEL_INET6_ADDR_GEN_MODE, + $ac_have_kernel_gen_mode, [Define if the kernel has IN6_ADDR_GEN_MODE_*]) + # uuid library PKG_CHECK_MODULES(UUID, uuid) AC_SUBST(UUID_CFLAGS) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index ef10d0c239..18b0ad21c7 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -268,6 +268,7 @@ typedef struct { NMIP6Config * vpn6_config; /* routes added by a VPN which uses this device */ NMIP6Config * wwan_ip6_config; NMIP6Config * ext_ip6_config; /* Stuff added outside NM */ + gboolean nm_ipv6ll; /* TRUE if NM handles the device's IPv6LL address */ NMRDisc * rdisc; gulong rdisc_changed_id; @@ -563,6 +564,9 @@ nm_device_set_ip_iface (NMDevice *self, const char *iface) if (priv->ip_iface) { priv->ip_ifindex = nm_platform_link_get_ifindex (priv->ip_iface); if (priv->ip_ifindex > 0) { + if (nm_platform_check_support_user_ipv6ll ()) + nm_platform_link_set_user_ipv6ll_enabled (priv->ip_ifindex, TRUE); + if (!nm_platform_link_is_up (priv->ip_ifindex)) nm_platform_link_set_up (priv->ip_ifindex); } else { @@ -611,6 +615,12 @@ get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *out_iid) return success; } +static gboolean +nm_device_get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *iid) +{ + return NM_DEVICE_GET_CLASS (self)->get_ip_iface_identifier (self, iid); +} + const char * nm_device_get_driver (NMDevice *self) { @@ -1132,7 +1142,12 @@ device_ip_link_changed (NMDevice *self, NMPlatformLink *info) } static void -link_changed_cb (NMPlatform *platform, int ifindex, NMPlatformLink *info, NMPlatformSignalChangeType change_type, NMPlatformReason reason, NMDevice *self) +link_changed_cb (NMPlatform *platform, + int ifindex, + NMPlatformLink *info, + NMPlatformSignalChangeType change_type, + NMPlatformReason reason, + NMDevice *self) { if (change_type != NM_PLATFORM_SIGNAL_CHANGED) return; @@ -3368,6 +3383,52 @@ linklocal6_complete (NMDevice *self) g_return_if_fail (FALSE); } +static void +check_and_add_ipv6ll_addr (NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + int ip_ifindex = nm_device_get_ip_ifindex (self); + NMUtilsIPv6IfaceId iid; + struct in6_addr lladdr; + guint i, n; + + if (priv->nm_ipv6ll == FALSE) + return; + + if (priv->ip6_config) { + n = nm_ip6_config_get_num_addresses (priv->ip6_config); + for (i = 0; i < n; i++) { + const NMPlatformIP6Address *addr; + + addr = nm_ip6_config_get_address (priv->ip6_config, i); + if (IN6_IS_ADDR_LINKLOCAL (&addr->address)) { + /* Already have an LL address, nothing to do */ + return; + } + } + } + + if (!nm_device_get_ip_iface_identifier (self, &iid)) { + _LOGW (LOGD_IP6, "failed to get interface identifier; IPv6 may be broken"); + return; + } + + memset (&lladdr, 0, sizeof (lladdr)); + lladdr.s6_addr16[0] = htons (0xfe80); + nm_utils_ipv6_addr_set_interface_identfier (&lladdr, iid); + _LOGD (LOGD_IP6, "adding IPv6LL address %s", nm_utils_inet6_ntop (&lladdr, NULL)); + if (!nm_platform_ip6_address_add (ip_ifindex, + lladdr, + in6addr_any, + 64, + NM_PLATFORM_LIFETIME_PERMANENT, + NM_PLATFORM_LIFETIME_PERMANENT, + 0)) { + _LOGW (LOGD_IP6, "failed to add IPv6 link-local address %s", + nm_utils_inet6_ntop (&lladdr, NULL)); + } +} + static NMActStageReturn linklocal6_start (NMDevice *self) { @@ -3386,6 +3447,8 @@ linklocal6_start (NMDevice *self) method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG); _LOGD (LOGD_DEVICE, "linklocal6: starting IPv6 with method '%s', but the device has no link-local addresses configured. Wait.", method); + check_and_add_ipv6ll_addr (self); + priv->linklocal6_timeout_id = g_timeout_add_seconds (5, linklocal6_timeout_cb, self); return NM_ACT_STAGE_RETURN_POSTPONE; @@ -3630,8 +3693,8 @@ addrconf6_start_with_link_ready (NMDevice *self) g_assert (priv->rdisc); - if (!NM_DEVICE_GET_CLASS (self)->get_ip_iface_identifier (self, &iid)) { - _LOGW (LOGD_IP6, "failed to get interface identifier"); + if (!nm_device_get_ip_iface_identifier (self, &iid)) { + _LOGW (LOGD_IP6, "failed to get interface identifier; IPv6 cannot continue"); return FALSE; } nm_rdisc_set_iid (priv->rdisc, iid); @@ -3759,8 +3822,39 @@ restore_ip6_properties (NMDevice *self) gpointer key, value; g_hash_table_iter_init (&iter, priv->ip6_saved_properties); - while (g_hash_table_iter_next (&iter, &key, &value)) + while (g_hash_table_iter_next (&iter, &key, &value)) { + /* Don't touch "disable_ipv6" if we're doing userland IPv6LL */ + if (priv->nm_ipv6ll && strcmp (key, "disable_ipv6") == 0) + continue; nm_device_ipv6_sysctl_set (self, key, value); + } +} + +static inline void +set_disable_ipv6 (NMDevice *self, const char *value) +{ + /* We only touch disable_ipv6 when NM is not managing the IPv6LL address */ + if (NM_DEVICE_GET_PRIVATE (self)->nm_ipv6ll == FALSE) + nm_device_ipv6_sysctl_set (self, "disable_ipv6", value); +} + +static inline void +set_nm_ipv6ll (NMDevice *self, gboolean enable) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + int ifindex = nm_device_get_ip_ifindex (self); + + if (!nm_platform_check_support_user_ipv6ll ()) + return; + + priv->nm_ipv6ll = enable; + if (ifindex > 0) { + const char *detail = enable ? "enable" : "disable"; + + _LOGD (LOGD_IP6, "will %s userland IPv6LL", detail); + if (!nm_platform_link_set_user_ipv6ll_enabled (ifindex, enable)) + _LOGW (LOGD_IP6, "failed to %s userspace IPv6LL address handling", detail); + } } static NMSettingIP6ConfigPrivacy @@ -3889,7 +3983,7 @@ act_stage3_ip6_config_start (NMDevice *self, } /* Re-enable IPv6 on the interface */ - nm_device_ipv6_sysctl_set (self, "disable_ipv6", "0"); + set_disable_ipv6 (self, "0"); /* Enable/disable IPv6 Privacy Extensions. * If a global value is configured by sysadmin (e.g. /etc/sysctl.conf), @@ -5908,17 +6002,29 @@ queued_ip_config_change (gpointer user_data) priv->queued_ip_config_id = 0; update_ip_config (self, FALSE); + + /* If no IPv6 link-local address exists but other addresses do then we + * must add the LL address to remain conformant with RFC 3513 chapter 2.1 + * ("Addressing Model"): "All interfaces are required to have at least + * one link-local unicast address". + */ + if (priv->ip6_config && nm_ip6_config_get_num_addresses (priv->ip6_config)) + check_and_add_ipv6ll_addr (self); + return FALSE; } static void -device_ip_changed (NMPlatform *platform, int ifindex, gpointer platform_object, NMPlatformSignalChangeType change_type, NMPlatformReason reason, gpointer user_data) +device_ip_changed (NMPlatform *platform, + int ifindex, + gpointer platform_object, + NMPlatformSignalChangeType change_type, + NMPlatformReason reason, + NMDevice *self) { - NMDevice *self = user_data; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); if (nm_device_get_ip_ifindex (self) == ifindex) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - if (!priv->queued_ip_config_id) priv->queued_ip_config_id = g_idle_add (queued_ip_config_change, self); @@ -6538,7 +6644,7 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason) _cleanup_generic_pre (self, TRUE); /* Turn off kernel IPv6 */ - nm_device_ipv6_sysctl_set (self, "disable_ipv6", "1"); + set_disable_ipv6 (self, "1"); nm_device_ipv6_sysctl_set (self, "accept_ra", "0"); nm_device_ipv6_sysctl_set (self, "use_tempaddr", "0"); @@ -6653,6 +6759,7 @@ _set_state_full (NMDevice *self, if (nm_device_get_act_request (self)) nm_device_cleanup (self, reason); nm_device_take_down (self, TRUE); + set_nm_ipv6ll (self, FALSE); restore_ip6_properties (self); } break; @@ -6660,7 +6767,8 @@ _set_state_full (NMDevice *self, if (old_state == NM_DEVICE_STATE_UNMANAGED) { save_ip6_properties (self); if (reason != NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED) { - nm_device_ipv6_sysctl_set (self, "disable_ipv6", "1"); + set_nm_ipv6ll (self, TRUE); + set_disable_ipv6 (self, "1"); nm_device_ipv6_sysctl_set (self, "accept_ra_defrtr", "0"); nm_device_ipv6_sysctl_set (self, "accept_ra_pinfo", "0"); nm_device_ipv6_sysctl_set (self, "accept_ra_rtr_pref", "0"); @@ -6685,6 +6793,12 @@ _set_state_full (NMDevice *self, nm_device_cleanup (self, reason); break; case NM_DEVICE_STATE_DISCONNECTED: + /* Ensure devices that previously assumed a connection now have + * userspace IPv6LL enabled. + */ + if (reason != NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED) + set_nm_ipv6ll (self, TRUE); + if (old_state > NM_DEVICE_STATE_UNAVAILABLE) nm_device_cleanup (self, reason); break; @@ -7179,6 +7293,13 @@ constructor (GType type, g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, G_CALLBACK (device_ip_changed), self); g_signal_connect (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, G_CALLBACK (link_changed_cb), self); + if (nm_platform_check_support_user_ipv6ll ()) { + int ip_ifindex = nm_device_get_ip_ifindex (self); + + if (ip_ifindex > 0) + priv->nm_ipv6ll = nm_platform_link_get_user_ipv6ll_enabled (ip_ifindex); + } + return object; error: @@ -7257,6 +7378,9 @@ dispose (GObject *object) g_warn_if_fail (priv->slaves == NULL); g_assert (priv->master_ready_id == 0); + /* Let the kernel manage IPv6LL again */ + set_nm_ipv6ll (self, FALSE); + _cleanup_generic_post (self, FALSE); g_clear_pointer (&priv->ip6_saved_properties, g_hash_table_unref); diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index feb86010fd..8bec9b2d36 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -44,6 +44,16 @@ #include <netlink/route/route.h> #include <gudev/gudev.h> +#if HAVE_LIBNL_INET6_ADDR_GEN_MODE +#include <netlink/route/link/inet6.h> +#if HAVE_KERNEL_INET6_ADDR_GEN_MODE +#include <linux/if_link.h> +#else +#define IN6_ADDR_GEN_MODE_EUI64 0 +#define IN6_ADDR_GEN_MODE_NONE 1 +#endif +#endif + #include "NetworkManagerUtils.h" #include "nm-linux-platform.h" #include "NetworkManagerUtils.h" @@ -83,6 +93,7 @@ typedef struct { GHashTable *wifi_data; int support_kernel_extended_ifa_flags; + int support_user_ipv6ll; } NMLinuxPlatformPrivate; #define NM_LINUX_PLATFORM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_LINUX_PLATFORM, NMLinuxPlatformPrivate)) @@ -669,6 +680,23 @@ check_support_kernel_extended_ifa_flags (NMPlatform *platform) return priv->support_kernel_extended_ifa_flags > 0; } +static gboolean +check_support_user_ipv6ll (NMPlatform *platform) +{ + NMLinuxPlatformPrivate *priv; + + g_return_val_if_fail (NM_IS_LINUX_PLATFORM (platform), FALSE); + + priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + + if (priv->support_user_ipv6ll == 0) { + nm_log_warn (LOGD_PLATFORM, "Unable to detect kernel support for IFLA_INET6_ADDR_GEN_MODE. Assume no kernel support."); + priv->support_user_ipv6ll = -1; + } + + return priv->support_user_ipv6ll > 0; +} + /* Object type specific utilities */ @@ -1529,8 +1557,20 @@ announce_object (NMPlatform *platform, const struct nl_object *object, NMPlatfor switch (object_type) { case OBJECT_TYPE_LINK: { - NMPlatformLink device; struct rtnl_link *rtnl_link = (struct rtnl_link *) object; + NMPlatformLink device; + +#if HAVE_LIBNL_INET6_ADDR_GEN_MODE + /* If we ever see a link with valid IPv6 link-local address + * generation modes, the kernel supports it. + */ + if (priv->support_user_ipv6ll == 0) { + uint8_t mode; + + if (rtnl_link_inet6_get_addr_gen_mode (rtnl_link, &mode) == 0) + priv->support_user_ipv6ll = 1; + } +#endif if (!init_link (platform, &device, rtnl_link)) return; @@ -2406,6 +2446,46 @@ link_set_noarp (NMPlatform *platform, int ifindex) } static gboolean +link_get_user_ipv6ll_enabled (NMPlatform *platform, int ifindex) +{ +#if HAVE_LIBNL_INET6_ADDR_GEN_MODE + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + + if (priv->support_user_ipv6ll > 0) { + auto_nl_object struct rtnl_link *rtnllink = link_get (platform, ifindex); + uint8_t mode = 0; + + if (rtnllink) { + if (rtnl_link_inet6_get_addr_gen_mode (rtnllink, &mode) != 0) { + /* Default to "disabled" on error */ + return FALSE; + } + return mode == IN6_ADDR_GEN_MODE_NONE; + } + } +#endif + return FALSE; +} + +static gboolean +link_set_user_ipv6ll_enabled (NMPlatform *platform, int ifindex, gboolean enabled) +{ +#if HAVE_LIBNL_INET6_ADDR_GEN_MODE + if (check_support_user_ipv6ll (platform)) { + auto_nl_object struct rtnl_link *change = _nm_rtnl_link_alloc (ifindex, NULL); + guint8 mode = enabled ? IN6_ADDR_GEN_MODE_NONE : IN6_ADDR_GEN_MODE_EUI64; + char buf[32]; + + rtnl_link_inet6_set_addr_gen_mode (change, mode); + debug ("link: change %d: set IPv6 address generation mode to %s", + ifindex, rtnl_link_inet6_addrgenmode2str (mode, buf, sizeof (buf))); + return link_change (platform, ifindex, change); + } +#endif + return FALSE; +} + +static gboolean supports_ethtool_carrier_detect (const char *ifname) { struct ethtool_cmd edata = { .cmd = ETHTOOL_GLINK }; @@ -4060,6 +4140,24 @@ setup (NMPlatform *platform) for (object = nl_cache_get_first (priv->address_cache); object; object = nl_cache_get_next (object)) _rtnl_addr_hack_lifetimes_rel_to_abs ((struct rtnl_addr *) object); +#if HAVE_LIBNL_INET6_ADDR_GEN_MODE + /* Initial check for user IPv6LL support once the link cache is allocated + * and filled. If there are no links in the cache yet then we'll check + * when a new link shows up in announce_object(). + */ + object = nl_cache_get_first (priv->link_cache); + if (object) { + uint8_t mode; + + if (rtnl_link_inet6_get_addr_gen_mode ((struct rtnl_link *) object, &mode) == 0) + priv->support_user_ipv6ll = 1; + else + priv->support_user_ipv6ll = -1; + } +#else + priv->support_user_ipv6ll = -1; +#endif + /* Set up udev monitoring */ priv->udev_client = g_udev_client_new (udev_subsys); g_signal_connect (priv->udev_client, "uevent", G_CALLBACK (handle_udev_event), platform); @@ -4147,6 +4245,9 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_is_connected = link_is_connected; platform_class->link_uses_arp = link_uses_arp; + platform_class->link_get_user_ipv6ll_enabled = link_get_user_ipv6ll_enabled; + platform_class->link_set_user_ipv6ll_enabled = link_set_user_ipv6ll_enabled; + platform_class->link_get_address = link_get_address; platform_class->link_set_address = link_set_address; platform_class->link_get_mtu = link_get_mtu; @@ -4213,4 +4314,5 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->ip6_route_exists = ip6_route_exists; platform_class->check_support_kernel_extended_ifa_flags = check_support_kernel_extended_ifa_flags; + platform_class->check_support_user_ipv6ll = check_support_user_ipv6ll; } diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index b3ffe70a6e..e26e10e158 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -215,6 +215,21 @@ nm_platform_check_support_kernel_extended_ifa_flags () return klass->check_support_kernel_extended_ifa_flags (platform); } +gboolean +nm_platform_check_support_user_ipv6ll (void) +{ + static int supported = -1; + + g_return_val_if_fail (NM_IS_PLATFORM (platform), FALSE); + + if (!klass->check_support_user_ipv6ll) + return FALSE; + + if (supported < 0) + supported = klass->check_support_user_ipv6ll (platform) ? 1 : 0; + return !!supported; +} + /******************************************************************/ /** @@ -730,6 +745,52 @@ nm_platform_link_uses_arp (int ifindex) } /** + * nm_platform_link_get_user_ip6vll_enabled: + * @ifindex: Interface index + * + * Check whether NM handles IPv6LL address creation for the link. If the + * platform or OS doesn't support changing the IPv6LL address mode, this call + * will fail and return %FALSE. + * + * Returns: %TRUE if NM handles the IPv6LL address for @ifindex + */ +gboolean +nm_platform_link_get_user_ipv6ll_enabled (int ifindex) +{ + reset_error (); + + 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); + return FALSE; +} + +/** + * nm_platform_link_set_user_ip6vll_enabled: + * @ifindex: Interface index + * + * Set whether NM handles IPv6LL address creation for the link. If the + * platform or OS doesn't support changing the IPv6LL address mode, this call + * will fail and return %FALSE. + * + * Returns: %TRUE if the operation was successful, %FALSE if it failed. + */ +gboolean +nm_platform_link_set_user_ipv6ll_enabled (int ifindex, gboolean enabled) +{ + reset_error (); + + 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 FALSE; +} + +/** * nm_platform_link_set_address: * @ifindex: Interface index * @address: The new MAC address diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index e706d2d74c..7bc80637c5 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -388,6 +388,9 @@ typedef struct { gboolean (*link_is_connected) (NMPlatform *, int ifindex); gboolean (*link_uses_arp) (NMPlatform *, int ifindex); + gboolean (*link_get_user_ipv6ll_enabled) (NMPlatform *, int ifindex); + gboolean (*link_set_user_ipv6ll_enabled) (NMPlatform *, int ifindex, gboolean enabled); + gconstpointer (*link_get_address) (NMPlatform *, int ifindex, size_t *length); gboolean (*link_set_address) (NMPlatform *, int ifindex, gconstpointer address, size_t length); guint32 (*link_get_mtu) (NMPlatform *, int ifindex); @@ -463,6 +466,7 @@ typedef struct { gboolean (*ip6_route_exists) (NMPlatform *, int ifindex, struct in6_addr network, int plen, int metric); gboolean (*check_support_kernel_extended_ifa_flags) (NMPlatform *); + gboolean (*check_support_user_ipv6ll) (NMPlatform *); } NMPlatformClass; /* NMPlatform signals @@ -528,6 +532,9 @@ gboolean nm_platform_link_is_up (int ifindex); gboolean nm_platform_link_is_connected (int ifindex); gboolean nm_platform_link_uses_arp (int ifindex); +gboolean nm_platform_link_get_user_ipv6ll_enabled (int ifindex); +gboolean nm_platform_link_set_user_ipv6ll_enabled (int ifindex, gboolean enabled); + gconstpointer nm_platform_link_get_address (int ifindex, size_t *length); gboolean nm_platform_link_set_address (int ifindex, const void *address, size_t length); guint32 nm_platform_link_get_mtu (int ifindex); @@ -623,6 +630,7 @@ int nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6R gboolean nm_platform_check_support_libnl_extended_ifa_flags (void); gboolean nm_platform_check_support_kernel_extended_ifa_flags (void); +gboolean nm_platform_check_support_user_ipv6ll (void); void nm_platform_addr_flags2str (int flags, char *buf, size_t size); |