If timeout_del(9) didn't remove the timeout we need to ensure we're not
leaving a reference to the `sc' in the wild.

We do not want to execute the timeout when the interface isn't running,
so add the proper check and correct the flag set/unset ordering.

ok?

diff --git sys/net/bridgectl.c sys/net/bridgectl.c
index 8fdbee5a50d..68114066f7c 100644
--- sys/net/bridgectl.c
+++ sys/net/bridgectl.c
@@ -328,9 +328,13 @@ void
 bridge_rtage(void *vsc)
 {
        struct bridge_softc *sc = vsc;
+       struct ifnet *ifp = &sc->sc_if;
        struct bridge_rtnode *n, *p;
        int i;
 
+       if (!ISSET(ifp->if_flags, IFF_RUNNING))
+               return;
+
        mtx_enter(&sc->sc_mtx);
        for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
                n = LIST_FIRST(&sc->sc_rts[i]);
diff --git sys/net/if_bridge.c sys/net/if_bridge.c
index 457206b11d4..7930bbc25ad 100644
--- sys/net/if_bridge.c
+++ sys/net/if_bridge.c
@@ -690,14 +690,15 @@ bridge_init(struct bridge_softc *sc)
 {
        struct ifnet *ifp = &sc->sc_if;
 
-       if ((ifp->if_flags & IFF_RUNNING) == IFF_RUNNING)
+       if (ISSET(ifp->if_flags, IFF_RUNNING))
                return;
 
-       ifp->if_flags |= IFF_RUNNING;
        bstp_initialization(sc->sc_stp);
 
        if (sc->sc_brttimeout != 0)
                timeout_add_sec(&sc->sc_brtimeout, sc->sc_brttimeout);
+
+       SET(ifp->if_flags, IFF_RUNNING);
 }
 
 /*
@@ -708,17 +709,15 @@ bridge_stop(struct bridge_softc *sc)
 {
        struct ifnet *ifp = &sc->sc_if;
 
-       /*
-        * If we're not running, there's nothing to do.
-        */
-       if ((ifp->if_flags & IFF_RUNNING) == 0)
+       if (!ISSET(ifp->if_flags, IFF_RUNNING))
                return;
 
-       timeout_del(&sc->sc_brtimeout);
+       CLR(ifp->if_flags, IFF_RUNNING);
 
-       bridge_rtflush(sc, IFBF_FLUSHDYN);
+       if (!timeout_del(&sc->sc_brtimeout))
+               timeout_barrier(&sc->sc_brtimeout);
 
-       ifp->if_flags &= ~IFF_RUNNING;
+       bridge_rtflush(sc, IFBF_FLUSHDYN);
 }
 
 /*

Reply via email to