summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2014-09-04 15:11:55 -0500
committerDan Williams <dcbw@redhat.com>2014-09-04 15:11:55 -0500
commit4e530adf60d65e76252ad9e32ee1788c028abb27 (patch)
tree825642ccb14f5220afa00c858851834eda480e3c
parent899df02e4c9a0be1b3684e4f60c3fc6dae01d18e (diff)
parent5e4761a3a9cb1cba692d41d79aa389f539752e50 (diff)
downloadNetworkManager-4e530adf60d65e76252ad9e32ee1788c028abb27.tar.gz
merge: handle IPv6 link-local addresses from userspace when possible (bgo #734149)
-rw-r--r--configure.ac19
-rw-r--r--src/devices/nm-device.c146
-rw-r--r--src/platform/nm-linux-platform.c104
-rw-r--r--src/platform/nm-platform.c61
-rw-r--r--src/platform/nm-platform.h8
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);