1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-23 11:18:54 +00:00

Fix a panic I introduced in r234487, the bridge softc pointer is set to null

early in the detach so rearrange things not to explode.

Reported by:	David Roffiaen, Gustau Perez Querol
Tested by:	David Roffiaen
MFC after:	3 days
This commit is contained in:
Andrew Thompson 2012-06-11 20:12:13 +00:00
parent fd45a47ba6
commit 08e348234c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=236916

View File

@ -334,6 +334,7 @@ static int bridge_ip6_checkbasic(struct mbuf **mp);
static int bridge_fragment(struct ifnet *, struct mbuf *, static int bridge_fragment(struct ifnet *, struct mbuf *,
struct ether_header *, int, struct llc *); struct ether_header *, int, struct llc *);
static void bridge_linkstate(struct ifnet *ifp); static void bridge_linkstate(struct ifnet *ifp);
static void bridge_linkcheck(struct bridge_softc *sc);
extern void (*bridge_linkstate_p)(struct ifnet *ifp); extern void (*bridge_linkstate_p)(struct ifnet *ifp);
@ -964,6 +965,7 @@ bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif,
EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp); EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp);
} }
bridge_linkcheck(sc);
bridge_mutecaps(sc); /* recalcuate now this interface is removed */ bridge_mutecaps(sc); /* recalcuate now this interface is removed */
bridge_rtdelete(sc, ifs, IFBF_FLUSHALL); bridge_rtdelete(sc, ifs, IFBF_FLUSHALL);
KASSERT(bif->bif_addrcnt == 0, KASSERT(bif->bif_addrcnt == 0,
@ -993,7 +995,6 @@ bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif,
bridge_set_ifcap(sc, bif, bif->bif_savedcaps); bridge_set_ifcap(sc, bif, bif->bif_savedcaps);
} }
bstp_destroy(&bif->bif_stp); /* prepare to free */ bstp_destroy(&bif->bif_stp); /* prepare to free */
bridge_linkstate(ifs);
BRIDGE_LOCK(sc); BRIDGE_LOCK(sc);
free(bif, M_DEVBUF); free(bif, M_DEVBUF);
} }
@ -1092,18 +1093,17 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
/* Set interface capabilities to the intersection set of all members */ /* Set interface capabilities to the intersection set of all members */
bridge_mutecaps(sc); bridge_mutecaps(sc);
bridge_linkcheck(sc);
BRIDGE_UNLOCK(sc);
/* Update the linkstate for the bridge */
bridge_linkstate(ifs);
/* Place the interface into promiscuous mode */ /* Place the interface into promiscuous mode */
switch (ifs->if_type) { switch (ifs->if_type) {
case IFT_ETHER: case IFT_ETHER:
case IFT_L2VLAN: case IFT_L2VLAN:
BRIDGE_UNLOCK(sc);
error = ifpromisc(ifs, 1); error = ifpromisc(ifs, 1);
BRIDGE_LOCK(sc);
break; break;
} }
BRIDGE_LOCK(sc);
if (error) if (error)
bridge_delete_member(sc, bif, 0); bridge_delete_member(sc, bif, 0);
out: out:
@ -3486,8 +3486,7 @@ static void
bridge_linkstate(struct ifnet *ifp) bridge_linkstate(struct ifnet *ifp)
{ {
struct bridge_softc *sc = ifp->if_bridge; struct bridge_softc *sc = ifp->if_bridge;
struct bridge_iflist *bif, *bif2; struct bridge_iflist *bif;
int new_link, hasls;
BRIDGE_LOCK(sc); BRIDGE_LOCK(sc);
bif = bridge_lookup_member_if(sc, ifp); bif = bridge_lookup_member_if(sc, ifp);
@ -3495,13 +3494,26 @@ bridge_linkstate(struct ifnet *ifp)
BRIDGE_UNLOCK(sc); BRIDGE_UNLOCK(sc);
return; return;
} }
bridge_linkcheck(sc);
BRIDGE_UNLOCK(sc);
bstp_linkstate(&bif->bif_stp);
}
static void
bridge_linkcheck(struct bridge_softc *sc)
{
struct bridge_iflist *bif;
int new_link, hasls;
BRIDGE_LOCK_ASSERT(sc);
new_link = LINK_STATE_DOWN; new_link = LINK_STATE_DOWN;
hasls = 0; hasls = 0;
/* Our link is considered up if at least one of our ports is active */ /* Our link is considered up if at least one of our ports is active */
LIST_FOREACH(bif2, &sc->sc_iflist, bif_next) { LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
if (bif2->bif_ifp->if_capabilities & IFCAP_LINKSTATE) if (bif->bif_ifp->if_capabilities & IFCAP_LINKSTATE)
hasls++; hasls++;
if (bif2->bif_ifp->if_link_state == LINK_STATE_UP) { if (bif->bif_ifp->if_link_state == LINK_STATE_UP) {
new_link = LINK_STATE_UP; new_link = LINK_STATE_UP;
break; break;
} }
@ -3511,8 +3523,4 @@ bridge_linkstate(struct ifnet *ifp)
new_link = LINK_STATE_UP; new_link = LINK_STATE_UP;
} }
if_link_state_change(sc->sc_ifp, new_link); if_link_state_change(sc->sc_ifp, new_link);
BRIDGE_UNLOCK(sc);
bstp_linkstate(&bif->bif_stp);
} }