summaryrefslogtreecommitdiffstats
path: root/sys/netinet/if_ether.c
diff options
context:
space:
mode:
authorbz <bz@FreeBSD.org>2010-04-11 16:04:08 +0000
committerbz <bz@FreeBSD.org>2010-04-11 16:04:08 +0000
commitd7a91dc6bf166a266421facb5e7cc8067695b03b (patch)
tree62a56a95d03df4cca3ba14e6c3cae4d3f5a44931 /sys/netinet/if_ether.c
parent63955b94c288cde6ff80eaba0accf6043c55844a (diff)
downloadFreeBSD-src-d7a91dc6bf166a266421facb5e7cc8067695b03b.zip
FreeBSD-src-d7a91dc6bf166a266421facb5e7cc8067695b03b.tar.gz
Plug reference leaks in the link-layer code ("new-arp") that previously
prevented the link-layer entry from being freed. In both in.c and in6.c (though that code path seems to be basically dead) plug a reference leak in case of a pending callout being drained. In if_ether.c consistently add a reference before resetting the callout and in case we canceled a pending one remove the reference for that. In the final case in arptimer, before freeing the expired entry, remove the reference again and explicitly call callout_stop() to clear the active flag. In nd6.c:nd6_free() we are only ever called from the callout function and thus need to remove the reference there as well before calling into llentry_free(). In if_llatbl.c when freeing entire tables make sure that in case we cancel a pending callout to remove the reference as well. Reviewed by: qingli (earlier version) MFC after: 10 days Problem observed, patch tested by: simon on ipv6gw.f.o, Christian Kratzer (ck cksoft.de), Evgenii Davidov (dado korolev-net.ru) PR: kern/144564 Configurations still affected: with options FLOWTABLE
Diffstat (limited to 'sys/netinet/if_ether.c')
-rw-r--r--sys/netinet/if_ether.c18
1 files changed, 15 insertions, 3 deletions
diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c
index 97152a7..25fba9f 100644
--- a/sys/netinet/if_ether.c
+++ b/sys/netinet/if_ether.c
@@ -180,6 +180,8 @@ arptimer(void *arg)
else {
if (!callout_pending(&lle->la_timer) &&
callout_active(&lle->la_timer)) {
+ callout_stop(&lle->la_timer);
+ LLE_REMREF(lle);
(void) llentry_free(lle);
ARPSTAT_INC(timeouts);
}
@@ -382,9 +384,14 @@ retry:
EHOSTUNREACH : EHOSTDOWN;
if (renew) {
+ int canceled;
+
LLE_ADDREF(la);
la->la_expire = time_second + V_arpt_down;
- callout_reset(&la->la_timer, hz * V_arpt_down, arptimer, la);
+ canceled = callout_reset(&la->la_timer, hz * V_arpt_down,
+ arptimer, la);
+ if (canceled)
+ LLE_REMREF(la);
la->la_asked++;
LLE_WUNLOCK(la);
arprequest(ifp, NULL, &SIN(dst)->sin_addr,
@@ -696,9 +703,14 @@ match:
EVENTHANDLER_INVOKE(arp_update_event, la);
if (!(la->la_flags & LLE_STATIC)) {
+ int canceled;
+
+ LLE_ADDREF(la);
la->la_expire = time_second + V_arpt_keep;
- callout_reset(&la->la_timer, hz * V_arpt_keep,
- arptimer, la);
+ canceled = callout_reset(&la->la_timer,
+ hz * V_arpt_keep, arptimer, la);
+ if (canceled)
+ LLE_REMREF(la);
}
la->la_asked = 0;
la->la_preempt = V_arp_maxtries;
OpenPOWER on IntegriCloud