Author: bz
Date: Sun Apr 11 16:04:08 2010
New Revision: 206481
URL: http://svn.freebsd.org/changeset/base/206481

Log:
  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

Modified:
  head/sys/net/if_llatbl.c
  head/sys/netinet/if_ether.c
  head/sys/netinet/in.c
  head/sys/netinet6/in6.c
  head/sys/netinet6/nd6.c

Modified: head/sys/net/if_llatbl.c
==============================================================================
--- head/sys/net/if_llatbl.c    Sun Apr 11 15:35:17 2010        (r206480)
+++ head/sys/net/if_llatbl.c    Sun Apr 11 16:04:08 2010        (r206481)
@@ -170,9 +170,12 @@ lltable_free(struct lltable *llt)
 
        for (i=0; i < LLTBL_HASHTBL_SIZE; i++) {
                LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
+                       int canceled;
 
-                       callout_drain(&lle->la_timer);
+                       canceled = callout_drain(&lle->la_timer);
                        LLE_WLOCK(lle);
+                       if (canceled)
+                               LLE_REMREF(lle);
                        llentry_free(lle);
                }
        }

Modified: head/sys/netinet/if_ether.c
==============================================================================
--- head/sys/netinet/if_ether.c Sun Apr 11 15:35:17 2010        (r206480)
+++ head/sys/netinet/if_ether.c Sun Apr 11 16:04:08 2010        (r206481)
@@ -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;

Modified: head/sys/netinet/in.c
==============================================================================
--- head/sys/netinet/in.c       Sun Apr 11 15:35:17 2010        (r206480)
+++ head/sys/netinet/in.c       Sun Apr 11 16:04:08 2010        (r206481)
@@ -1357,8 +1357,12 @@ in_lltable_prefix_free(struct lltable *l
 
                        if (IN_ARE_MASKED_ADDR_EQUAL((struct sockaddr_in 
*)L3_ADDR(lle), 
                                                     pfx, msk)) {
-                               callout_drain(&lle->la_timer);
+                               int canceled;
+
+                               canceled = callout_drain(&lle->la_timer);
                                LLE_WLOCK(lle);
+                               if (canceled)
+                                       LLE_REMREF(lle);
                                llentry_free(lle);
                        }
                }

Modified: head/sys/netinet6/in6.c
==============================================================================
--- head/sys/netinet6/in6.c     Sun Apr 11 15:35:17 2010        (r206480)
+++ head/sys/netinet6/in6.c     Sun Apr 11 16:04:08 2010        (r206481)
@@ -2344,8 +2344,12 @@ in6_lltable_prefix_free(struct lltable *
                                    &((struct sockaddr_in6 
*)L3_ADDR(lle))->sin6_addr, 
                                    &pfx->sin6_addr, 
                                    &msk->sin6_addr)) {
-                               callout_drain(&lle->la_timer);
+                               int canceled;
+
+                               canceled = callout_drain(&lle->la_timer);
                                LLE_WLOCK(lle);
+                               if (canceled)
+                                       LLE_REMREF(lle);
                                llentry_free(lle);
                        }
                }

Modified: head/sys/netinet6/nd6.c
==============================================================================
--- head/sys/netinet6/nd6.c     Sun Apr 11 15:35:17 2010        (r206480)
+++ head/sys/netinet6/nd6.c     Sun Apr 11 16:04:08 2010        (r206481)
@@ -1125,6 +1125,7 @@ nd6_free(struct llentry *ln, int gc)
        ifp = ln->lle_tbl->llt_ifp;
        IF_AFDATA_LOCK(ifp);
        LLE_WLOCK(ln);
+       LLE_REMREF(ln);
        llentry_free(ln);
        IF_AFDATA_UNLOCK(ifp);
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to