diff options
author | Damien Bergamini <damien@cvs.openbsd.org> | 2006-11-14 17:08:25 +0000 |
---|---|---|
committer | Damien Bergamini <damien@cvs.openbsd.org> | 2006-11-14 17:08:25 +0000 |
commit | 60f89064e9775c88b520ef04f3193ffe718b3144 (patch) | |
tree | 13e4c1942173a3871cb845867e7799bf37977878 /sys/dev | |
parent | ff5e222d29981c9e65c8928d8657916f3fb2b770 (diff) |
don't always leave the mbuf on the if_snd queue if vge_encap() fails.
if the mbuf is coalesced in vge_encap(), the mbuf reference is no
longer valid. drop the mbuf in this case.
bug introduced in r1.28
tested by Frank Denis
fixes kernel/5291
"go for it" deraadt@
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/if_vge.c | 33 |
1 files changed, 17 insertions, 16 deletions
diff --git a/sys/dev/pci/if_vge.c b/sys/dev/pci/if_vge.c index 9c4d3fed95c..c978ca1f3a7 100644 --- a/sys/dev/pci/if_vge.c +++ b/sys/dev/pci/if_vge.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_vge.c,v 1.29 2006/10/19 10:55:56 tom Exp $ */ +/* $OpenBSD: if_vge.c,v 1.30 2006/11/14 17:08:24 damien Exp $ */ /* $FreeBSD: if_vge.c,v 1.3 2004/09/11 22:13:25 wpaul Exp $ */ /* * Copyright (c) 2004 @@ -1281,9 +1281,11 @@ vge_intr(void *arg) int vge_encap(struct vge_softc *sc, struct mbuf *m_head, int idx) { + struct ifnet *ifp = &sc->arpcom.ac_if; bus_dmamap_t txmap; struct vge_tx_desc *d = NULL; struct vge_tx_frag *f; + struct mbuf *mnew = NULL; int error, frag; u_int32_t vge_flags; @@ -1326,26 +1328,23 @@ repack: * copy the data into a mbuf cluster and map that. */ if (frag == VGE_TX_FRAGS) { - struct mbuf *m = NULL; - - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) { - m_freem(m_head); + MGETHDR(mnew, M_DONTWAIT, MT_DATA); + if (mnew == NULL) return (ENOBUFS); - } + if (m_head->m_pkthdr.len > MHLEN) { - MCLGET(m, M_DONTWAIT); - if (!(m->m_flags & M_EXT)) { - m_freem(m); - m_freem(m_head); + MCLGET(mnew, M_DONTWAIT); + if (!(mnew->m_flags & M_EXT)) { + m_freem(mnew); return (ENOBUFS); } } m_copydata(m_head, 0, m_head->m_pkthdr.len, - mtod(m, caddr_t)); - m->m_pkthdr.len = m->m_len = m_head->m_pkthdr.len; + mtod(mnew, caddr_t)); + mnew->m_pkthdr.len = mnew->m_len = m_head->m_pkthdr.len; + IFQ_DEQUEUE(&ifp->if_snd, m_head); m_freem(m_head); - m_head = m; + m_head = mnew; goto repack; } @@ -1388,7 +1387,10 @@ repack: #endif idx++; - + if (mnew == NULL) { + /* if mbuf is coalesced, it is already dequeued */ + IFQ_DEQUEUE(&ifp->if_snd, m_head); + } return (0); } @@ -1434,7 +1436,6 @@ vge_start(struct ifnet *ifp) ifp->if_flags |= IFF_OACTIVE; break; } - IFQ_DEQUEUE(&ifp->if_snd, m_head); sc->vge_ldata.vge_tx_list[pidx].vge_frag[0].vge_buflen |= htole16(VGE_TXDESC_Q); |