diff options
author | Renato Botelho <renato@netgate.com> | 2016-10-06 07:48:56 -0300 |
---|---|---|
committer | Renato Botelho <renato@netgate.com> | 2016-10-06 07:48:56 -0300 |
commit | fa098ef31c4cf4ddab63aced6553fef24c185eea (patch) | |
tree | 889bed18c879ec9a159ac7ceca8c175fe3dbffa8 /sys/net | |
parent | 4548300e7a07c11f157a8ca76565517d2483df36 (diff) | |
parent | ad44cbcf96571d28c76d58c4beff77c8f2af28cb (diff) | |
download | FreeBSD-src-fa098ef31c4cf4ddab63aced6553fef24c185eea.zip FreeBSD-src-fa098ef31c4cf4ddab63aced6553fef24c185eea.tar.gz |
Merge remote-tracking branch 'origin/stable/10' into devel
Diffstat (limited to 'sys/net')
-rw-r--r-- | sys/net/if_bridge.c | 86 |
1 files changed, 55 insertions, 31 deletions
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c index 57aadc0..b22e324 100644 --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -332,7 +332,7 @@ static int bridge_ip_checkbasic(struct mbuf **mp); #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); @@ -1870,6 +1870,7 @@ bridge_enqueue(struct bridge_softc *sc, struct ifnet *dst_ifp, struct mbuf *m) 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); sc->sc_ifp->if_oerrors++; @@ -3226,10 +3227,12 @@ bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir) break; /* check if we need to fragment the packet */ + /* bridge_fragment generates a mbuf chain of packets */ + /* that already include eth headers */ if (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); } @@ -3468,56 +3471,77 @@ bad: /* * 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, *nextpkt = NULL, *mprev = NULL, *mcur = NULL; struct ip *ip; int error = -1; if (m->m_len < sizeof(struct ip) && (m = m_pullup(m, sizeof(struct ip))) == NULL) - goto out; + goto dropit; ip = mtod(m, struct ip *); m->m_pkthdr.csum_flags |= CSUM_IP; error = ip_fragment(ip, &m, ifp->if_mtu, ifp->if_hwassist); if (error) - goto out; + goto dropit; - /* walk the chain and re-add the Ethernet header */ - for (m0 = m; m0; m0 = m0->m_nextpkt) { - if (error == 0) { - if (snap) { - M_PREPEND(m0, sizeof(struct llc), M_NOWAIT); - if (m0 == NULL) { - error = ENOBUFS; - continue; - } - bcopy(llc, mtod(m0, caddr_t), - sizeof(struct llc)); - } - M_PREPEND(m0, ETHER_HDR_LEN, M_NOWAIT); - if (m0 == NULL) { + /* + * Walk the chain and re-add the Ethernet header for + * each mbuf packet. + */ + for (mcur = m; mcur; mcur = mcur->m_nextpkt) { + nextpkt = mcur->m_nextpkt; + mcur->m_nextpkt = NULL; + if (snap) { + M_PREPEND(mcur, sizeof(struct llc), M_NOWAIT); + if (mcur == NULL) { error = ENOBUFS; - continue; + if (mprev != NULL) + mprev->m_nextpkt = nextpkt; + goto dropit; } - bcopy(eh, mtod(m0, caddr_t), ETHER_HDR_LEN); - } else - m_freem(m); - } + bcopy(llc, mtod(mcur, caddr_t),sizeof(struct llc)); + } - if (error == 0) - KMOD_IPSTAT_INC(ips_fragmented); + M_PREPEND(mcur, ETHER_HDR_LEN, M_NOWAIT); + if (mcur == NULL) { + error = ENOBUFS; + if (mprev != NULL) + mprev->m_nextpkt = nextpkt; + goto dropit; + } + bcopy(eh, mtod(mcur, caddr_t), ETHER_HDR_LEN); + /* + * The previous two M_PREPEND could have inserted one or two + * mbufs in front so we have to update the previous packet's + * m_nextpkt. + */ + mcur->m_nextpkt = nextpkt; + if (mprev != NULL) + mprev->m_nextpkt = mcur; + else { + /* The first mbuf in the original chain needs to be + * updated. */ + *mp = mcur; + } + mprev = mcur; + } + + KMOD_IPSTAT_INC(ips_fragmented); return (error); -out: - if (m != NULL) - m_freem(m); +dropit: + for (mcur = *mp; mcur; mcur = m) { /* droping the full packet chain */ + m = mcur->m_nextpkt; + m_freem(mcur); + } return (error); } |