aboutsummaryrefslogtreecommitdiff
path: root/sys/netinet
diff options
context:
space:
mode:
authorBjoern A. Zeeb <bz@FreeBSD.org>2010-08-14 13:47:34 +0000
committerBjoern A. Zeeb <bz@FreeBSD.org>2010-08-14 13:47:34 +0000
commit07c100e6d63cb50223c5698c9715c85740869601 (patch)
tree7acd978a83ffb63e2c4f52a0a61df373e0c5c8da /sys/netinet
parentf214ec81b9686b8786f5065c93e4eed73357f835 (diff)
Notes
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/in_rmx.c20
1 files changed, 20 insertions, 0 deletions
diff --git a/sys/netinet/in_rmx.c b/sys/netinet/in_rmx.c
index 33c3f280e8c8..6481e15e4bf6 100644
--- a/sys/netinet/in_rmx.c
+++ b/sys/netinet/in_rmx.c
@@ -402,15 +402,35 @@ in_ifadownkill(struct radix_node *rn, void *xap)
if (rt->rt_ifa == ap->ifa &&
(ap->del || !(rt->rt_flags & RTF_STATIC))) {
/*
+ * Aquire a reference so that it can later be freed
+ * as the refcount would be 0 here in case of at least
+ * ap->del.
+ */
+ RT_ADDREF(rt);
+ /*
* We need to disable the automatic prune that happens
* in this case in rtrequest() because it will blow
* away the pointers that rn_walktree() needs in order
* continue our descent. We will end up deleting all
* the routes that rtrequest() would have in any case,
* so that behavior is not needed there.
+ * Disconnect it from the tree and permit protocols
+ * to cleanup.
*/
rt->rt_flags &= ~RTF_CLONING;
rtexpunge(rt);
+ /*
+ * At this point it is an rttrash node, and in case
+ * the above is the only reference we must free it.
+ * If we do not noone will have a pointer and the
+ * rtentry will be leaked forever.
+ * In case someone else holds a reference, we are
+ * fine as we only decrement the refcount. In that
+ * case if the other entity calls RT_REMREF, we
+ * will still be leaking but at least we tried.
+ */
+ RTFREE_LOCKED(rt);
+ return (0);
}
RT_UNLOCK(rt);
return 0;