summary refs log tree commit diff
path: root/src/core/ndisc
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2022-01-13 22:30:39 +0100
committerMichael Biebl <biebl@debian.org>2022-01-13 22:30:39 +0100
commit88c227d90a6b7b388c5c85d72802a0ca8f05ed5c (patch)
tree71f32df6617802270e8a78574bd8e1637dc532f4 /src/core/ndisc
parente74c568b07b50b97873fb4ee1d776dedefbd54d6 (diff)
New upstream version 1.34.0 upstream/1.34.0
Diffstat (limited to 'src/core/ndisc')
-rw-r--r--src/core/ndisc/nm-lndp-ndisc.c83
-rw-r--r--src/core/ndisc/nm-lndp-ndisc.h7
-rw-r--r--src/core/ndisc/nm-ndisc.c238
-rw-r--r--src/core/ndisc/nm-ndisc.h15
-rw-r--r--src/core/ndisc/tests/test-ndisc-linux.c12
5 files changed, 213 insertions, 142 deletions
diff --git a/src/core/ndisc/nm-lndp-ndisc.c b/src/core/ndisc/nm-lndp-ndisc.c
index f11178f8..552b0e4b 100644
--- a/src/core/ndisc/nm-lndp-ndisc.c
+++ b/src/core/ndisc/nm-lndp-ndisc.c
@@ -85,14 +85,14 @@ send_rs(NMNDisc *ndisc, GError **error)
 static NMIcmpv6RouterPref
 _route_preference_coerce(enum ndp_route_preference pref)
 {
-#define _ASSERT_ENUM(v1, v2)                                       \
-    G_STMT_START                                                   \
-    {                                                              \
-        G_STATIC_ASSERT((NMIcmpv6RouterPref) (v1) == (v2));        \
-        G_STATIC_ASSERT((enum ndp_route_preference) (v2) == (v1)); \
-        G_STATIC_ASSERT((gint64) (v1) == (v2));                    \
-        G_STATIC_ASSERT((gint64) (v2) == (v1));                    \
-    }                                                              \
+#define _ASSERT_ENUM(v1, v2)                                      \
+    G_STMT_START                                                  \
+    {                                                             \
+        G_STATIC_ASSERT((NMIcmpv6RouterPref) (v1) == (v2));       \
+        G_STATIC_ASSERT((enum ndp_route_preference)(v2) == (v1)); \
+        G_STATIC_ASSERT((gint64) (v1) == (v2));                   \
+        G_STATIC_ASSERT((gint64) (v2) == (v1));                   \
+    }                                                             \
     G_STMT_END
 
     switch (pref) {
@@ -599,9 +599,7 @@ start(NMNDisc *ndisc)
 
     fd = ndp_get_eventfd(priv->ndp);
 
-    priv->event_source =
-        nm_g_unix_fd_source_new(fd, G_IO_IN, G_PRIORITY_DEFAULT, event_ready, ndisc, NULL);
-    g_source_attach(priv->event_source, NULL);
+    priv->event_source = nm_g_unix_fd_add_source(fd, G_IO_IN, event_ready, ndisc);
 
     /* Flush any pending messages to avoid using obsolete information */
     event_ready(fd, 0, ndisc);
@@ -666,69 +664,6 @@ stop(NMNDisc *ndisc)
 
 /*****************************************************************************/
 
-static int
-ipv6_sysctl_get(NMPlatform *platform,
-                const char *ifname,
-                const char *property,
-                int         min,
-                int         max,
-                int         defval)
-{
-    return nm_platform_sysctl_ip_conf_get_int_checked(platform,
-                                                      AF_INET6,
-                                                      ifname,
-                                                      property,
-                                                      10,
-                                                      min,
-                                                      max,
-                                                      defval);
-}
-
-void
-nm_lndp_ndisc_get_sysctl(NMPlatform *platform,
-                         const char *ifname,
-                         int *       out_max_addresses,
-                         int *       out_router_solicitations,
-                         int *       out_router_solicitation_interval,
-                         guint32 *   out_default_ra_timeout)
-{
-    int router_solicitation_interval = 0;
-    int router_solicitations         = 0;
-
-    if (out_max_addresses) {
-        *out_max_addresses = ipv6_sysctl_get(platform,
-                                             ifname,
-                                             "max_addresses",
-                                             0,
-                                             G_MAXINT32,
-                                             NM_NDISC_MAX_ADDRESSES_DEFAULT);
-    }
-    if (out_router_solicitations || out_default_ra_timeout) {
-        router_solicitations = ipv6_sysctl_get(platform,
-                                               ifname,
-                                               "router_solicitations",
-                                               1,
-                                               G_MAXINT32,
-                                               NM_NDISC_ROUTER_SOLICITATIONS_DEFAULT);
-        NM_SET_OUT(out_router_solicitations, router_solicitations);
-    }
-    if (out_router_solicitation_interval || out_default_ra_timeout) {
-        router_solicitation_interval = ipv6_sysctl_get(platform,
-                                                       ifname,
-                                                       "router_solicitation_interval",
-                                                       1,
-                                                       G_MAXINT32,
-                                                       NM_NDISC_RFC4861_RTR_SOLICITATION_INTERVAL);
-        NM_SET_OUT(out_router_solicitation_interval, router_solicitation_interval);
-    }
-    if (out_default_ra_timeout) {
-        *out_default_ra_timeout =
-            NM_MAX((((gint64) router_solicitations) * router_solicitation_interval) + 1, 30);
-    }
-}
-
-/*****************************************************************************/
-
 static void
 nm_lndp_ndisc_init(NMLndpNDisc *lndp_ndisc)
 {}
diff --git a/src/core/ndisc/nm-lndp-ndisc.h b/src/core/ndisc/nm-lndp-ndisc.h
index 96fc9737..151f4bf7 100644
--- a/src/core/ndisc/nm-lndp-ndisc.h
+++ b/src/core/ndisc/nm-lndp-ndisc.h
@@ -36,11 +36,4 @@ NMNDisc *nm_lndp_ndisc_new(NMPlatform *                  platform,
                            guint32                       ra_timeout,
                            GError **                     error);
 
-void nm_lndp_ndisc_get_sysctl(NMPlatform *platform,
-                              const char *ifname,
-                              int *       out_max_addresses,
-                              int *       out_router_solicitations,
-                              int *       out_router_solicitation_interval,
-                              guint32 *   out_default_ra_timeout);
-
 #endif /* __NETWORKMANAGER_LNDP_NDISC_H__ */
diff --git a/src/core/ndisc/nm-ndisc.c b/src/core/ndisc/nm-ndisc.c
index cf1b58ec..d7b1a2e1 100644
--- a/src/core/ndisc/nm-ndisc.c
+++ b/src/core/ndisc/nm-ndisc.c
@@ -23,6 +23,9 @@
 #define RFC7559_IRT ((gint32) 4)    /* RFC7559, Initial Retransmission Time, in seconds */
 #define RFC7559_MRT ((gint32) 3600) /* RFC7559, Maximum Retransmission Time, in seconds */
 
+#define NM_NDISC_PRE_EXPIRY_TIME_MSEC         60000
+#define NM_NDISC_PRE_EXPIRY_MIN_LIFETIME_MSEC 120000
+
 #define _SIZE_MAX_GATEWAYS    100u
 #define _SIZE_MAX_ADDRESSES   100u
 #define _SIZE_MAX_ROUTES      1000u
@@ -44,6 +47,7 @@ struct _NMNDiscPrivate {
     gint32 last_ra;
 
     gint32 solicit_retransmit_time_msec;
+    gint64 last_rs_msec;
 
     GSource *solicit_timer_source;
 
@@ -96,6 +100,16 @@ static gboolean timeout_expire_cb(gpointer user_data);
 
 /*****************************************************************************/
 
+NM_UTILS_LOOKUP_STR_DEFINE(nm_ndisc_dhcp_level_to_string,
+                           NMNDiscDHCPLevel,
+                           NM_UTILS_LOOKUP_DEFAULT("INVALID"),
+                           NM_UTILS_LOOKUP_STR_ITEM(NM_NDISC_DHCP_LEVEL_UNKNOWN, "unknown"),
+                           NM_UTILS_LOOKUP_STR_ITEM(NM_NDISC_DHCP_LEVEL_NONE, "none"),
+                           NM_UTILS_LOOKUP_STR_ITEM(NM_NDISC_DHCP_LEVEL_OTHERCONF, "otherconf"),
+                           NM_UTILS_LOOKUP_STR_ITEM(NM_NDISC_DHCP_LEVEL_MANAGED, "managed"), );
+
+/*****************************************************************************/
+
 NML3ConfigData *
 nm_ndisc_data_to_l3cd(NMDedupMultiIndex *       multi_idx,
                       int                       ifindex,
@@ -112,9 +126,7 @@ nm_ndisc_data_to_l3cd(NMDedupMultiIndex *       multi_idx,
     guint                                   i;
     const gint32                            now_sec = nm_utils_get_monotonic_timestamp_sec();
 
-    l3cd = nm_l3_config_data_new(multi_idx, ifindex);
-
-    nm_l3_config_data_set_source(l3cd, NM_IP_CONFIG_SOURCE_NDISC);
+    l3cd = nm_l3_config_data_new(multi_idx, ifindex, NM_IP_CONFIG_SOURCE_NDISC);
 
     nm_l3_config_data_set_ip6_privacy(l3cd, ip6_privacy);
 
@@ -468,12 +480,12 @@ complete_address(NMNDisc *ndisc, NMNDiscAddress *addr)
 
     priv = NM_NDISC_GET_PRIVATE(ndisc);
     if (priv->addr_gen_mode == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY) {
-        if (!nm_utils_ipv6_addr_set_stable_privacy(priv->stable_type,
-                                                   &addr->address,
-                                                   priv->ifname,
-                                                   priv->network_id,
-                                                   addr->dad_counter++,
-                                                   &error)) {
+        if (!nm_utils_ipv6_addr_set_stable_privacy_may_fail(priv->stable_type,
+                                                            &addr->address,
+                                                            priv->ifname,
+                                                            priv->network_id,
+                                                            addr->dad_counter++,
+                                                            &error)) {
             _LOGW("complete-address: failed to generate an stable-privacy address: %s",
                   error->message);
             g_clear_error(&error);
@@ -490,7 +502,7 @@ complete_address(NMNDisc *ndisc, NMNDiscAddress *addr)
 
     if (addr->address.s6_addr32[2] == 0x0 && addr->address.s6_addr32[3] == 0x0) {
         _LOGD("complete-address: adding an EUI-64 address");
-        nm_utils_ipv6_addr_set_interface_identifier(&addr->address, priv->iid);
+        nm_utils_ipv6_addr_set_interface_identifier(&addr->address, &priv->iid);
         return TRUE;
     }
 
@@ -832,6 +844,8 @@ solicit_timer_cb(gpointer user_data)
     else {
         _LOGT("solicit: router solicitation sent");
         nm_clear_g_free(&priv->last_error);
+
+        priv->last_rs_msec = nm_utils_get_monotonic_timestamp_msec();
     }
 
     /* https://tools.ietf.org/html/rfc4861#section-6.3.7 describes how to send solicitations:
@@ -1213,21 +1227,6 @@ config_map_to_string(NMNDiscConfigMap map, char *p)
     *p = '\0';
 }
 
-static const char *
-dhcp_level_to_string(NMNDiscDHCPLevel dhcp_level)
-{
-    switch (dhcp_level) {
-    case NM_NDISC_DHCP_LEVEL_NONE:
-        return "none";
-    case NM_NDISC_DHCP_LEVEL_OTHERCONF:
-        return "otherconf";
-    case NM_NDISC_DHCP_LEVEL_MANAGED:
-        return "managed";
-    default:
-        return "INVALID";
-    }
-}
-
 static void
 _config_changed_log(NMNDisc *ndisc, NMNDiscConfigMap changed)
 {
@@ -1250,7 +1249,7 @@ _config_changed_log(NMNDisc *ndisc, NMNDiscConfigMap changed)
 
     config_map_to_string(changed, changedstr);
     _LOGD("neighbor discovery configuration changed [%s]:", changedstr);
-    _LOGD("  dhcp-level %s", dhcp_level_to_string(priv->rdata.public.dhcp_level));
+    _LOGD("  dhcp-level %s", nm_ndisc_dhcp_level_to_string(priv->rdata.public.dhcp_level));
 
     if (rdata->public.hop_limit)
         _LOGD("  hop limit      : %d", rdata->public.hop_limit);
@@ -1508,33 +1507,6 @@ check_timestamps(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap changed)
                                                                      ndisc);
     }
 
-    /* When we receive an RA, we don't disable solicitations entirely. Instead,
-     * we set the interval the maximum (RFC7559_MRT).
-     *
-     * This contradicts https://tools.ietf.org/html/rfc7559#section-2.1, which says
-     * that we SHOULD stop sending RS if we receive an RA -- but only on a multicast
-     * capable link and if the RA has a valid router lifetime.
-     *
-     * But we really want to recover from a dead router on the network, so we
-     * don't want to cease sending RS entirely.
-     *
-     * But we only re-schedule the timer if the current interval is not already
-     * "RFC7559_MRT * 1000". Otherwise, we already have a slow interval counter
-     * pending. */
-    if (priv->solicit_retransmit_time_msec != RFC7559_MRT * 1000) {
-        gint32 timeout_msec;
-
-        priv->solicit_retransmit_time_msec = RFC7559_MRT * 1000;
-        timeout_msec = solicit_retransmit_time_jitter(priv->solicit_retransmit_time_msec);
-
-        _LOGD("solicit: schedule sending next (slow) solicitation in about %.3f seconds",
-              ((double) timeout_msec) / 1000);
-
-        nm_clear_g_source_inst(&priv->solicit_timer_source);
-        priv->solicit_timer_source =
-            nm_g_timeout_add_source_approx(timeout_msec, 0, solicit_timer_cb, ndisc);
-    }
-
     if (changed != NM_NDISC_CONFIG_NONE)
         nm_ndisc_emit_config_change(ndisc, changed);
 }
@@ -1546,14 +1518,111 @@ timeout_expire_cb(gpointer user_data)
     return G_SOURCE_CONTINUE;
 }
 
+/* Calculate the earliest time where some part of the advertised data is about
+ * to expire.
+ *
+ * Entities are considered about to expire NM_NDISC_PRE_EXPIRY_TIME_MSEC before
+ * their expiration time.
+ *
+ * However, data which has a lifetime (as calculated from the time the last
+ * RS has been sent) shorter than NM_NDISC_PRE_EXPIRY_MIN_LIFETIME_MSEC, is
+ * ignored. This is because when we send out RSs because some data is about
+ * to expire, and the received RAs neither extend the lifetime nor remove
+ * the offending data, the data would be considered about to expire again,
+ * triggering more RS in an endless loop until it expired for good.
+ */
+
+static void
+_calc_pre_expiry_rs_msec_worker(gint64 *earliest_expiry_msec,
+                                gint64  last_rs_msec,
+                                gint64  expiry_msec)
+{
+    if (expiry_msec == NM_NDISC_EXPIRY_INFINITY)
+        return;
+
+    if (expiry_msec < last_rs_msec + NM_NDISC_PRE_EXPIRY_MIN_LIFETIME_MSEC)
+        return;
+
+    *earliest_expiry_msec = NM_MIN(*earliest_expiry_msec, expiry_msec);
+}
+
+static gint64
+calc_pre_expiry_rs_msec(NMNDisc *ndisc)
+{
+    NMNDiscPrivate *     priv        = NM_NDISC_GET_PRIVATE(ndisc);
+    NMNDiscDataInternal *rdata       = &priv->rdata;
+    gint64               expiry_msec = NM_NDISC_EXPIRY_INFINITY;
+    guint                i;
+
+    for (i = 0; i < rdata->gateways->len; i++) {
+        _calc_pre_expiry_rs_msec_worker(
+            &expiry_msec,
+            priv->last_rs_msec,
+            g_array_index(rdata->gateways, NMNDiscGateway, i).expiry_msec);
+    }
+
+    for (i = 0; i < rdata->addresses->len; i++) {
+        _calc_pre_expiry_rs_msec_worker(
+            &expiry_msec,
+            priv->last_rs_msec,
+            g_array_index(rdata->addresses, NMNDiscAddress, 0).expiry_msec);
+    }
+
+    for (i = 0; i < rdata->routes->len; i++) {
+        _calc_pre_expiry_rs_msec_worker(&expiry_msec,
+                                        priv->last_rs_msec,
+                                        g_array_index(rdata->routes, NMNDiscRoute, 0).expiry_msec);
+    }
+
+    for (i = 0; i < rdata->dns_servers->len; i++) {
+        _calc_pre_expiry_rs_msec_worker(
+            &expiry_msec,
+            priv->last_rs_msec,
+            g_array_index(rdata->dns_servers, NMNDiscDNSServer, 0).expiry_msec);
+    }
+
+    for (i = 0; i < rdata->dns_domains->len; i++) {
+        _calc_pre_expiry_rs_msec_worker(
+            &expiry_msec,
+            priv->last_rs_msec,
+            g_array_index(rdata->dns_domains, NMNDiscDNSDomain, 0).expiry_msec);
+    }
+
+    return expiry_msec - solicit_retransmit_time_jitter(NM_NDISC_PRE_EXPIRY_TIME_MSEC);
+}
+
 void
 nm_ndisc_ra_received(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap changed)
 {
     NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE(ndisc);
+    gint64          pre_expiry_msec;
+    gint32          timeout_msec;
 
     nm_clear_g_source_inst(&priv->ra_timeout_source);
     nm_clear_g_free(&priv->last_error);
     check_timestamps(ndisc, now_msec, changed);
+
+    /* When we receive an RA, we don't disable solicitations.
+     *
+     * This contradicts https://tools.ietf.org/html/rfc7559#section-2.1, which
+     * says that we SHOULD stop sending RS if we receive an RA -- but only on
+     * a multicast capable link and if the RA has a valid router lifetime.
+     *
+     * But there are routers out in the wild that won't send unsolicited RAs.
+     * So we begin sending out RS again when entities are about to expire.
+     */
+    pre_expiry_msec = NM_CLAMP(calc_pre_expiry_rs_msec(ndisc),
+                               priv->last_rs_msec + RFC7559_IRT * 1000,
+                               priv->last_rs_msec + RFC7559_MRT * 1000);
+    timeout_msec    = NM_CLAMP(pre_expiry_msec - now_msec, (gint64) 0, (gint64) G_MAXINT32);
+
+    _LOGD("solicit: schedule sending next (slow) solicitation in about %.3f seconds",
+          ((double) timeout_msec) / 1000);
+
+    priv->solicit_retransmit_time_msec = 0;
+    nm_clear_g_source_inst(&priv->solicit_timer_source);
+    priv->solicit_timer_source =
+        nm_g_timeout_add_source_approx(timeout_msec, 0, solicit_timer_cb, ndisc);
 }
 
 void
@@ -1567,6 +1636,69 @@ nm_ndisc_rs_received(NMNDisc *ndisc)
 
 /*****************************************************************************/
 
+static int
+ipv6_sysctl_get(NMPlatform *platform,
+                const char *ifname,
+                const char *property,
+                int         min,
+                int         max,
+                int         defval)
+{
+    return nm_platform_sysctl_ip_conf_get_int_checked(platform,
+                                                      AF_INET6,
+                                                      ifname,
+                                                      property,
+                                                      10,
+                                                      min,
+                                                      max,
+                                                      defval);
+}
+
+void
+nm_ndisc_get_sysctl(NMPlatform *platform,
+                    const char *ifname,
+                    int *       out_max_addresses,
+                    int *       out_router_solicitations,
+                    int *       out_router_solicitation_interval,
+                    guint32 *   out_default_ra_timeout)
+{
+    int router_solicitation_interval = 0;
+    int router_solicitations         = 0;
+
+    if (out_max_addresses) {
+        *out_max_addresses = ipv6_sysctl_get(platform,
+                                             ifname,
+                                             "max_addresses",
+                                             0,
+                                             G_MAXINT32,
+                                             NM_NDISC_MAX_ADDRESSES_DEFAULT);
+    }
+    if (out_router_solicitations || out_default_ra_timeout) {
+        router_solicitations = ipv6_sysctl_get(platform,
+                                               ifname,
+                                               "router_solicitations",
+                                               1,
+                                               G_MAXINT32,
+                                               NM_NDISC_ROUTER_SOLICITATIONS_DEFAULT);
+        NM_SET_OUT(out_router_solicitations, router_solicitations);
+    }
+    if (out_router_solicitation_interval || out_default_ra_timeout) {
+        router_solicitation_interval = ipv6_sysctl_get(platform,
+                                                       ifname,
+                                                       "router_solicitation_interval",
+                                                       1,
+                                                       G_MAXINT32,
+                                                       NM_NDISC_RFC4861_RTR_SOLICITATION_INTERVAL);
+        NM_SET_OUT(out_router_solicitation_interval, router_solicitation_interval);
+    }
+    if (out_default_ra_timeout) {
+        *out_default_ra_timeout =
+            NM_MAX((((gint64) router_solicitations) * router_solicitation_interval) + 1, 30);
+    }
+}
+
+/*****************************************************************************/
+
 static void
 dns_domain_free(gpointer data)
 {
diff --git a/src/core/ndisc/nm-ndisc.h b/src/core/ndisc/nm-ndisc.h
index 15f95d20..5b827528 100644
--- a/src/core/ndisc/nm-ndisc.h
+++ b/src/core/ndisc/nm-ndisc.h
@@ -48,6 +48,8 @@ typedef enum {
     NM_NDISC_DHCP_LEVEL_MANAGED
 } NMNDiscDHCPLevel;
 
+const char *nm_ndisc_dhcp_level_to_string(NMNDiscDHCPLevel level);
+
 #define NM_NDISC_INFINITY_U32 ((uint32_t) -1)
 
 /* It's important that this is G_MAXINT64, so that we can meaningfully do
@@ -239,7 +241,7 @@ static inline gboolean
 nm_ndisc_dad_addr_is_fail_candidate_event(NMPlatformSignalChangeType  change_type,
                                           const NMPlatformIP6Address *addr)
 {
-    return !NM_FLAGS_HAS(addr->n_ifa_flags, IFA_F_TEMPORARY)
+    return !NM_FLAGS_HAS(addr->n_ifa_flags, IFA_F_SECONDARY)
            && ((change_type == NM_PLATFORM_SIGNAL_CHANGED && addr->n_ifa_flags & IFA_F_DADFAILED)
                || (change_type == NM_PLATFORM_SIGNAL_REMOVED
                    && addr->n_ifa_flags & IFA_F_TENTATIVE));
@@ -253,7 +255,7 @@ nm_ndisc_dad_addr_is_fail_candidate(NMPlatform *platform, const NMPObject *obj)
     addr = NMP_OBJECT_CAST_IP6_ADDRESS(
         nm_platform_lookup_obj(platform, NMP_CACHE_ID_TYPE_OBJECT_TYPE, obj));
     if (addr
-        && (NM_FLAGS_HAS(addr->n_ifa_flags, IFA_F_TEMPORARY)
+        && (NM_FLAGS_HAS(addr->n_ifa_flags, IFA_F_SECONDARY)
             || !NM_FLAGS_HAS(addr->n_ifa_flags, IFA_F_DADFAILED))) {
         /* the address still/again exists and is not in DADFAILED state. Skip it. */
         return FALSE;
@@ -264,6 +266,15 @@ nm_ndisc_dad_addr_is_fail_candidate(NMPlatform *platform, const NMPObject *obj)
 
 /*****************************************************************************/
 
+void nm_ndisc_get_sysctl(NMPlatform *platform,
+                         const char *ifname,
+                         int *       out_max_addresses,
+                         int *       out_router_solicitations,
+                         int *       out_router_solicitation_interval,
+                         guint32 *   out_default_ra_timeout);
+
+/*****************************************************************************/
+
 struct _NML3ConfigData;
 
 struct _NML3ConfigData *nm_ndisc_data_to_l3cd(NMDedupMultiIndex *       multi_idx,
diff --git a/src/core/ndisc/tests/test-ndisc-linux.c b/src/core/ndisc/tests/test-ndisc-linux.c
index c84ee142..57021606 100644
--- a/src/core/ndisc/tests/test-ndisc-linux.c
+++ b/src/core/ndisc/tests/test-ndisc-linux.c
@@ -49,12 +49,12 @@ main(int argc, char **argv)
         return EXIT_FAILURE;
     }
 
-    nm_lndp_ndisc_get_sysctl(NM_PLATFORM_GET,
-                             ifname,
-                             &max_addresses,
-                             &router_solicitations,
-                             &router_solicitation_interval,
-                             &ra_timeout);
+    nm_ndisc_get_sysctl(NM_PLATFORM_GET,
+                        ifname,
+                        &max_addresses,
+                        &router_solicitations,
+                        &router_solicitation_interval,
+                        &ra_timeout);
 
     ndisc = nm_lndp_ndisc_new(NM_PLATFORM_GET,
                               ifindex,