Date: Wed, 24 Nov 2010 05:24:36 +0000 (UTC) From: Gleb Smirnoff <glebius@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r215790 - head/sys/netinet Message-ID: <201011240524.oAO5OaxE056035@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: glebius Date: Wed Nov 24 05:24:36 2010 New Revision: 215790 URL: http://svn.freebsd.org/changeset/base/215790 Log: Redo r166423. It is important not only skip freeing multicast entires when underlying interface is detached, but also purge pointers to them, to avoid double-free in future. Modified: head/sys/netinet/ip_carp.c Modified: head/sys/netinet/ip_carp.c ============================================================================== --- head/sys/netinet/ip_carp.c Wed Nov 24 01:13:55 2010 (r215789) +++ head/sys/netinet/ip_carp.c Wed Nov 24 05:24:36 2010 (r215790) @@ -218,7 +218,7 @@ static void carp_set_state(struct carp_s static int carp_addrcount(struct carp_if *, struct in_ifaddr *, int); enum { CARP_COUNT_MASTER, CARP_COUNT_RUNNING }; -static void carp_multicast_cleanup(struct carp_softc *); +static void carp_multicast_cleanup(struct carp_softc *, int dofree); static int carp_set_addr(struct carp_softc *, struct sockaddr_in *); static int carp_del_addr(struct carp_softc *, struct sockaddr_in *); static void carp_carpdev_state_locked(struct carp_if *); @@ -227,7 +227,7 @@ static void carp_sc_state_locked(struct static void carp_send_na(struct carp_softc *); static int carp_set_addr6(struct carp_softc *, struct sockaddr_in6 *); static int carp_del_addr6(struct carp_softc *, struct sockaddr_in6 *); -static void carp_multicast6_cleanup(struct carp_softc *); +static void carp_multicast6_cleanup(struct carp_softc *, int dofree); #endif static LIST_HEAD(, carp_softc) carpif_list; @@ -466,9 +466,11 @@ carp_clone_destroy(struct ifnet *ifp) /* * This function can be called on CARP interface destroy path, * and in case of the removal of the underlying interface as - * well. We differentiate these two cases. In the latter case - * we do not cleanup our multicast memberships, since they - * are already freed. Also, in the latter case we do not + * well. We differentiate these two cases: in case of destruction + * of the underlying interface, we do not cleanup our multicast + * memberships, since they are already freed. But we purge pointers + * to multicast structures, since they are no longer valid, to + * avoid panic in future calls to carpdetach(). Also, we do not * release the lock on return, because the function will be * called once more, for another CARP instance on the same * interface. @@ -493,10 +495,9 @@ carpdetach(struct carp_softc *sc, int un carp_set_state(sc, INIT); SC2IFP(sc)->if_flags &= ~IFF_UP; carp_setrun(sc, 0); - if (unlock) - carp_multicast_cleanup(sc); + carp_multicast_cleanup(sc, unlock); #ifdef INET6 - carp_multicast6_cleanup(sc); + carp_multicast6_cleanup(sc, unlock); #endif if (sc->sc_carpdev != NULL) { @@ -1444,7 +1445,7 @@ carp_setrun(struct carp_softc *sc, sa_fa } static void -carp_multicast_cleanup(struct carp_softc *sc) +carp_multicast_cleanup(struct carp_softc *sc, int dofree) { struct ip_moptions *imo = &sc->sc_imo; u_int16_t n = imo->imo_num_memberships; @@ -1452,7 +1453,8 @@ carp_multicast_cleanup(struct carp_softc /* Clean up our own multicast memberships */ while (n-- > 0) { if (imo->imo_membership[n] != NULL) { - in_delmulti(imo->imo_membership[n]); + if (dofree) + in_delmulti(imo->imo_membership[n]); imo->imo_membership[n] = NULL; } } @@ -1464,14 +1466,15 @@ carp_multicast_cleanup(struct carp_softc #ifdef INET6 static void -carp_multicast6_cleanup(struct carp_softc *sc) +carp_multicast6_cleanup(struct carp_softc *sc, int dofree) { struct ip6_moptions *im6o = &sc->sc_im6o; u_int16_t n = im6o->im6o_num_memberships; while (n-- > 0) { if (im6o->im6o_membership[n] != NULL) { - in6_mc_leave(im6o->im6o_membership[n], NULL); + if (dofree) + in6_mc_leave(im6o->im6o_membership[n], NULL); im6o->im6o_membership[n] = NULL; } } @@ -1831,7 +1834,7 @@ carp_set_addr6(struct carp_softc *sc, st cleanup: if (!sc->sc_naddrs6) - carp_multicast6_cleanup(sc); + carp_multicast6_cleanup(sc, 1); ifa_free(&ia->ia_ifa); return (error); } @@ -1849,7 +1852,7 @@ carp_del_addr6(struct carp_softc *sc, st SC2IFP(sc)->if_flags &= ~IFF_UP; SC2IFP(sc)->if_drv_flags &= ~IFF_DRV_RUNNING; sc->sc_vhid = -1; - carp_multicast6_cleanup(sc); + carp_multicast6_cleanup(sc, 1); TAILQ_REMOVE(&cif->vhif_vrs, sc, sc_list); if (!--cif->vhif_nvrs) { CARP_LOCK_DESTROY(cif);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201011240524.oAO5OaxE056035>