Module Name: src Committed By: ozaki-r Date: Mon Dec 22 09:42:45 UTC 2014
Modified Files: src/sys/net: if_bridge.c Log Message: Call ether_input/m_freem without holding a lock or referencing unnecessary objects When NET_MPSAFE on, a bridge tries to pass up a packet to Layer 3 (or call m_freem) with holding a lock or referencing unnecessary objects. That causes random lock ups. The change fixes the issue. To generate a diff of this commit: cvs rdiff -u -r1.91 -r1.92 src/sys/net/if_bridge.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/net/if_bridge.c diff -u src/sys/net/if_bridge.c:1.91 src/sys/net/if_bridge.c:1.92 --- src/sys/net/if_bridge.c:1.91 Fri Aug 15 15:32:24 2014 +++ src/sys/net/if_bridge.c Mon Dec 22 09:42:45 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: if_bridge.c,v 1.91 2014/08/15 15:32:24 ozaki-r Exp $ */ +/* $NetBSD: if_bridge.c,v 1.92 2014/12/22 09:42:45 ozaki-r Exp $ */ /* * Copyright 2001 Wasabi Systems, Inc. @@ -80,7 +80,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_bridge.c,v 1.91 2014/08/15 15:32:24 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_bridge.c,v 1.92 2014/12/22 09:42:45 ozaki-r Exp $"); #ifdef _KERNEL_OPT #include "opt_bridge_ipf.h" @@ -1804,6 +1804,7 @@ bridge_input(struct ifnet *ifp, struct m if (!(m->m_flags & (M_BCAST|M_MCAST)) && !bstp_state_before_learning(bif)) { struct bridge_iflist *_bif; + struct ifnet *_ifp = NULL; BRIDGE_LOCK(sc); LIST_FOREACH(_bif, &sc->sc_iflist, bif_next) { @@ -1812,21 +1813,22 @@ bridge_input(struct ifnet *ifp, struct m if (_bif->bif_flags & IFBIF_LEARNING) (void) bridge_rtupdate(sc, eh->ether_shost, ifp, 0, IFBAF_DYNAMIC); - m->m_pkthdr.rcvif = _bif->bif_ifp; - ether_input(_bif->bif_ifp, m); + _ifp = m->m_pkthdr.rcvif = _bif->bif_ifp; break; } /* We just received a packet that we sent out. */ - if (bridge_ourether(_bif, eh, 1)) { - m_freem(m); + if (bridge_ourether(_bif, eh, 1)) break; - } } BRIDGE_UNLOCK(sc); if (_bif != NULL) { bridge_release_member(sc, bif); + if (_ifp != NULL) + ether_input(_ifp, m); + else + m_freem(m); return; } } @@ -1844,8 +1846,8 @@ bridge_input(struct ifnet *ifp, struct m * we've done historically. This also prevents some obnoxious behaviour. */ if (bstp_state_before_learning(bif)) { - ether_input(ifp, m); bridge_release_member(sc, bif); + ether_input(ifp, m); return; } @@ -1908,13 +1910,12 @@ bridge_broadcast(struct bridge_softc *sc bridge_enqueue(sc, dst_if, mc, 1); } + BRIDGE_UNLOCK(sc); if (bmcast) ether_input(src_if, m); else if (!used) m_freem(m); - - BRIDGE_UNLOCK(sc); } /*