diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 35103e54fa..90ffff4b32 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -477,6 +477,21 @@ restore_ip6_properties (NMDevice *self) } } +static gint32 +sysctl_get_ipv6_max_addresses (const char *dev) +{ + gint32 max_addresses = 16; + char *path; + + g_return_val_if_fail (dev && *dev, max_addresses); + + path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/max_addresses", dev); + max_addresses = nm_platform_sysctl_get_int32 (path, max_addresses); + g_free (path); + + return max_addresses; +} + /* * Get driver info from SIOCETHTOOL ioctl() for 'iface' * Returns driver and firmware versions to 'driver_version and' 'firmware_version' @@ -3320,6 +3335,11 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *device /* Rebuild address list from router discovery cache. */ nm_ip6_config_reset_addresses (priv->ac_ip6_config); + /* rdisc->addresses contains at most max_addresses entries. + * This is different from what the kernel does, which + * also counts static and temporary addresses when checking + * max_addresses. + **/ for (i = 0; i < rdisc->addresses->len; i++) { NMRDiscAddress *discovered_address = &g_array_index (rdisc->addresses, NMRDiscAddress, i); NMPlatformIP6Address address; @@ -3428,7 +3448,8 @@ addrconf6_start (NMDevice *self) priv->ac_ip6_config = NULL; } - priv->rdisc = nm_lndp_rdisc_new (nm_device_get_ip_ifindex (self), ip_iface); + priv->rdisc = nm_lndp_rdisc_new (nm_device_get_ip_ifindex (self), ip_iface, + sysctl_get_ipv6_max_addresses (ip_iface)); if (!priv->rdisc) { nm_log_err (LOGD_IP6, "(%s): failed to start router discovery.", ip_iface); return FALSE; diff --git a/src/rdisc/nm-fake-rdisc.c b/src/rdisc/nm-fake-rdisc.c index f39c5a208c..38faa5078a 100644 --- a/src/rdisc/nm-fake-rdisc.c +++ b/src/rdisc/nm-fake-rdisc.c @@ -36,7 +36,7 @@ G_DEFINE_TYPE (NMFakeRDisc, nm_fake_rdisc, NM_TYPE_RDISC) /******************************************************************/ NMRDisc * -nm_fake_rdisc_new (int ifindex, const char *ifname) +nm_fake_rdisc_new (int ifindex, const char *ifname, gint32 max_addresses) { NMRDisc *rdisc = g_object_new (NM_TYPE_FAKE_RDISC, NULL); @@ -44,6 +44,7 @@ nm_fake_rdisc_new (int ifindex, const char *ifname) rdisc->ifindex = ifindex; rdisc->ifname = g_strdup (ifname); + rdisc->max_addresses = max_addresses; return rdisc; } diff --git a/src/rdisc/nm-fake-rdisc.h b/src/rdisc/nm-fake-rdisc.h index 248283b22b..cff9ee4494 100644 --- a/src/rdisc/nm-fake-rdisc.h +++ b/src/rdisc/nm-fake-rdisc.h @@ -44,6 +44,6 @@ typedef struct { GType nm_fake_rdisc_get_type (void); -NMRDisc *nm_fake_rdisc_new (int ifindex, const char *ifname); +NMRDisc *nm_fake_rdisc_new (int ifindex, const char *ifname, gint32 max_addressses); #endif /* NM_FAKE_RDISC_H */ diff --git a/src/rdisc/nm-lndp-rdisc.c b/src/rdisc/nm-lndp-rdisc.c index 04b52067fc..e7124f1b7a 100644 --- a/src/rdisc/nm-lndp-rdisc.c +++ b/src/rdisc/nm-lndp-rdisc.c @@ -48,7 +48,7 @@ G_DEFINE_TYPE (NMLNDPRDisc, nm_lndp_rdisc, NM_TYPE_RDISC) /******************************************************************/ NMRDisc * -nm_lndp_rdisc_new (int ifindex, const char *ifname) +nm_lndp_rdisc_new (int ifindex, const char *ifname, gint32 max_addresses) { NMRDisc *rdisc; NMLNDPRDiscPrivate *priv; @@ -59,6 +59,7 @@ nm_lndp_rdisc_new (int ifindex, const char *ifname) rdisc->ifindex = ifindex; rdisc->ifname = g_strdup (ifname); + rdisc->max_addresses = max_addresses; priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc); error = ndp_open (&priv->ndp); @@ -113,6 +114,13 @@ add_address (NMRDisc *rdisc, const NMRDiscAddress *new) } } + /* we create at most max_addresses autoconf addresses. This is different from + * what the kernel does, because it considers *all* addresses (including + * static and other temporary addresses). + **/ + if (rdisc->max_addresses && rdisc->addresses->len >= rdisc->max_addresses) + return FALSE; + g_array_insert_val (rdisc->addresses, i, *new); return TRUE; } diff --git a/src/rdisc/nm-lndp-rdisc.h b/src/rdisc/nm-lndp-rdisc.h index eb6a1df6d9..30d53db409 100644 --- a/src/rdisc/nm-lndp-rdisc.h +++ b/src/rdisc/nm-lndp-rdisc.h @@ -44,6 +44,6 @@ typedef struct { GType nm_lndp_rdisc_get_type (void); -NMRDisc *nm_lndp_rdisc_new (int ifindex, const char *ifname); +NMRDisc *nm_lndp_rdisc_new (int ifindex, const char *ifname, gint32 max_addresses); #endif /* NM_LNDP_RDISC_H */ diff --git a/src/rdisc/nm-rdisc.h b/src/rdisc/nm-rdisc.h index 75262d862b..4690a5f5e7 100644 --- a/src/rdisc/nm-rdisc.h +++ b/src/rdisc/nm-rdisc.h @@ -106,6 +106,7 @@ typedef struct { int ifindex; char *ifname; GBytes *lladdr; + gint32 max_addresses; NMRDiscDHCPLevel dhcp_level; GArray *gateways; diff --git a/src/rdisc/tests/rdisc.c b/src/rdisc/tests/rdisc.c index fc6e86be08..6a0591af54 100644 --- a/src/rdisc/tests/rdisc.c +++ b/src/rdisc/tests/rdisc.c @@ -12,7 +12,7 @@ main (int argc, char **argv) { GMainLoop *loop; NMRDisc *rdisc; - NMRDisc *(*new) (int ifindex, const char *ifname) = nm_lndp_rdisc_new; + NMRDisc *(*new) (int ifindex, const char *ifname, gint32 max_addresses) = nm_lndp_rdisc_new; int ifindex = 1; char ifname[IF_NAMESIZE]; char mac[6] = { 0x02, 0xaa, 0xbb, 0xcc, 0xdd, 0xee }; @@ -34,7 +34,7 @@ main (int argc, char **argv) } } - rdisc = new (ifindex, ifname); + rdisc = new (ifindex, ifname, 0); if (!rdisc) return EXIT_FAILURE;