Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/netinet6/nd6_rtr.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/netinet6/nd6_rtr.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.82 retrieving revision 1.83 diff -u -p -r1.82 -r1.83 --- src/sys/netinet6/nd6_rtr.c 2011/11/19 22:51:29 1.82 +++ src/sys/netinet6/nd6_rtr.c 2012/06/23 03:14:04 1.83 @@ -1,4 +1,4 @@ -/* $NetBSD: nd6_rtr.c,v 1.82 2011/11/19 22:51:29 tls Exp $ */ +/* $NetBSD: nd6_rtr.c,v 1.83 2012/06/23 03:14:04 christos Exp $ */ /* $KAME: nd6_rtr.c,v 1.95 2001/02/07 08:09:47 itojun Exp $ */ /* @@ -31,7 +31,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: nd6_rtr.c,v 1.82 2011/11/19 22:51:29 tls Exp $"); +__KERNEL_RCSID(0, "$NetBSD: nd6_rtr.c,v 1.83 2012/06/23 03:14:04 christos Exp $"); #include #include @@ -79,8 +79,9 @@ static void defrouter_delreq(struct nd_d static void nd6_rtmsg(int, struct rtentry *); static int in6_init_prefix_ltimes(struct nd_prefix *); -static void in6_init_address_ltimes(struct nd_prefix *ndpr, - struct in6_addrlifetime *lt6); +static void in6_init_address_ltimes(struct nd_prefix *, + struct in6_addrlifetime *); +static void purge_detached(struct ifnet *); static int rt6_deleteroute(struct rtentry *, void *); @@ -488,6 +489,7 @@ defrtrlist_del(struct nd_defrouter *dr) struct nd_ifinfo *ndi = ND_IFINFO(dr->ifp); struct nd_defrouter *deldr = NULL; struct nd_prefix *pr; + struct in6_ifextra *ext = dr->ifp->if_afdata[AF_INET6]; /* * Flush all the routing table entries that use the router @@ -521,6 +523,12 @@ defrtrlist_del(struct nd_defrouter *dr) if (deldr) defrouter_select(); + ext->ndefrouters--; + if (ext->ndefrouters < 0) { + log(LOG_WARNING, "defrtrlist_del: negative count on %s\n", + dr->ifp->if_xname); + } + free(dr, M_IP6NDP); } @@ -777,6 +785,13 @@ defrtrlist_update(struct nd_defrouter *n return (dr); } + struct in6_ifextra *ext = new->ifp->if_afdata[AF_INET6]; + if (ip6_maxifdefrouters >= 0 && + ext->ndefrouters >= ip6_maxifdefrouters) { + splx(s); + return (NULL); + } + /* entry does not exist */ if (new->rtlifetime == 0) { splx(s); @@ -818,6 +833,8 @@ insert: defrouter_select(); + ext->ndefrouters++; + splx(s); return (n); @@ -875,6 +892,43 @@ nd6_prefix_lookup(struct nd_prefixctl *k return (search); } +static void +purge_detached(struct ifnet *ifp) +{ + struct nd_prefix *pr, *pr_next; + struct in6_ifaddr *ia; + struct ifaddr *ifa, *ifa_next; + + for (pr = nd_prefix.lh_first; pr; pr = pr_next) { + pr_next = pr->ndpr_next; + + /* + * This function is called when we need to make more room for + * new prefixes rather than keeping old, possibly stale ones. + * Detached prefixes would be a good candidate; if all routers + * that advertised the prefix expired, the prefix is also + * probably stale. + */ + if (pr->ndpr_ifp != ifp || + IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr) || + ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 && + !LIST_EMPTY(&pr->ndpr_advrtrs))) + continue; + + for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa_next) { + ifa_next = ifa->ifa_list.tqe_next; + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + ia = (struct in6_ifaddr *)ifa; + if ((ia->ia6_flags & IN6_IFF_AUTOCONF) == + IN6_IFF_AUTOCONF && ia->ia6_ndpr == pr) { + in6_purgeaddr(ifa); + } + } + if (pr->ndpr_refcnt == 0) + prelist_remove(pr); + } +} int nd6_prelist_add(struct nd_prefixctl *pr, struct nd_defrouter *dr, struct nd_prefix **newp) @@ -882,6 +936,14 @@ nd6_prelist_add(struct nd_prefixctl *pr, struct nd_prefix *new = NULL; int i, s; int error; + struct in6_ifextra *ext = pr->ndpr_ifp->if_afdata[AF_INET6]; + + if (ip6_maxifprefixes >= 0) { + if (ext->nprefixes >= ip6_maxifprefixes / 2) + purge_detached(pr->ndpr_ifp); + if (ext->nprefixes >= ip6_maxifprefixes) + return ENOMEM; + } error = 0; new = malloc(sizeof(*new), M_IP6NDP, M_NOWAIT|M_ZERO); @@ -930,6 +992,8 @@ nd6_prelist_add(struct nd_prefixctl *pr, if (dr) pfxrtr_add(new, dr); + ext->nprefixes++; + return 0; } @@ -938,6 +1002,7 @@ prelist_remove(struct nd_prefix *pr) { struct nd_pfxrouter *pfr, *next; int e, s; + struct in6_ifextra *ext = pr->ndpr_ifp->if_afdata[AF_INET6]; /* make sure to invalidate the prefix until it is really freed. */ pr->ndpr_vltime = 0; @@ -972,6 +1037,12 @@ prelist_remove(struct nd_prefix *pr) free(pfr, M_IP6NDP); } + + ext->nprefixes--; + if (ext->nprefixes < 0) { + log(LOG_WARNING, "prelist_remove: negative count on %s\n", + pr->ndpr_ifp->if_xname); + } splx(s); free(pr, M_IP6NDP);