Index: sys/net/if_bridge.c =================================================================== --- sys/net/if_bridge.c +++ sys/net/if_bridge.c @@ -333,7 +333,7 @@ #ifdef INET6 static int bridge_ip6_checkbasic(struct mbuf **mp); #endif /* INET6 */ -static int bridge_fragment(struct ifnet *, struct mbuf *, +static int bridge_fragment(struct ifnet *, struct mbuf **mp, struct ether_header *, int, struct llc *); static void bridge_linkstate(struct ifnet *ifp); static void bridge_linkcheck(struct bridge_softc *sc); @@ -1917,6 +1917,7 @@ m->m_flags &= ~M_VLANTAG; } + M_ASSERTPKTHDR(m); /* We shouldn't transmit mbuf without pkthdr */ if ((err = dst_ifp->if_transmit(dst_ifp, m))) { m_freem(m0); if_inc_counter(sc->sc_ifp, IFCOUNTER_OERRORS, 1); @@ -3234,10 +3235,12 @@ break; /* check if we need to fragment the packet */ + /* bridge_fragment generates a mbuf chain of packets */ + /* that already include eth headers */ if (V_pfil_member && ifp != NULL && dir == PFIL_OUT) { i = (*mp)->m_pkthdr.len; if (i > ifp->if_mtu) { - error = bridge_fragment(ifp, *mp, &eh2, snap, + error = bridge_fragment(ifp, mp, &eh2, snap, &llc1); return (error); } @@ -3476,13 +3479,13 @@ /* * bridge_fragment: * - * Return a fragmented mbuf chain. + * Fragment mbuf chain in multiple packets and prepend ethernet header. */ static int -bridge_fragment(struct ifnet *ifp, struct mbuf *m, struct ether_header *eh, +bridge_fragment(struct ifnet *ifp, struct mbuf **mp, struct ether_header *eh, int snap, struct llc *llc) { - struct mbuf *m0; + struct mbuf *m = *mp, *m0 = NULL, *mprev = NULL, *mcur = NULL; struct ip *ip; int error = -1; @@ -3496,24 +3499,44 @@ if (error) goto out; - /* walk the chain and re-add the Ethernet header */ - for (m0 = m; m0; m0 = m0->m_nextpkt) { + /* + * walk the chain and re-add the Ethernet header for + * each mbuf packets + */ + + for (mcur = m; mcur; mcur = mcur->m_nextpkt) { if (error == 0) { if (snap) { - M_PREPEND(m0, sizeof(struct llc), M_NOWAIT); - if (m0 == NULL) { + M_PREPEND(mcur, sizeof(struct llc), M_NOWAIT); + + if (mcur == NULL) { error = ENOBUFS; continue; } - bcopy(llc, mtod(m0, caddr_t), + bcopy(llc, mtod(mcur, caddr_t), sizeof(struct llc)); } - M_PREPEND(m0, ETHER_HDR_LEN, M_NOWAIT); - if (m0 == NULL) { + m0 = mcur; + M_PREPEND(mcur, ETHER_HDR_LEN, M_NOWAIT); + if (mcur == NULL) { error = ENOBUFS; continue; } - bcopy(eh, mtod(m0, caddr_t), ETHER_HDR_LEN); + bcopy(eh, mtod(mcur, caddr_t), ETHER_HDR_LEN); + /* if M_PREPEND had create a new mbuf, we need to: + * update previous mbuf packet to use this new one + * moving m_nextpkt from the old mbuf to the new one */ + if ( m0 != mcur ) { + mcur->m_nextpkt = mcur->m_next->m_nextpkt; + mcur->m_next->m_nextpkt = NULL; + if (mprev != NULL) { /* It's not the first packet in the chain*/ + mprev->m_nextpkt = mcur; + } else { /* the first mbuf in the original chain need to be updated */ + *mp = mcur; + } + } + mprev = mcur; + } else m_freem(m); }