diff options
author | rwatson <rwatson@FreeBSD.org> | 2004-11-14 20:20:28 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2004-11-14 20:20:28 +0000 |
commit | 0188f1bf36ef4568e79b40fbe6a65cd179c8330e (patch) | |
tree | 3d80496e2696fffb01a74115b98494f71b1c4417 /sys | |
parent | 36c3b3ee0bf3a94e9f93a2529bc1faebcdf5ed33 (diff) | |
download | FreeBSD-src-0188f1bf36ef4568e79b40fbe6a65cd179c8330e.zip FreeBSD-src-0188f1bf36ef4568e79b40fbe6a65cd179c8330e.tar.gz |
Further refine the if_em vlan fix in if_em.c:1.53:
- Because em_encap() can now fail in a way that leaves us without an
mbuf chain, potentially set *m_headp to NULL if that happens, so that
the caller can do the right thing. This case can occur when we try
to prepend the vlan header mbuf but can't allocate additional memory.
- Modify the caller of em_encap() to detect a NULL m_head and not try
to queue the mbuf if that happens.
- When em_encap() fails, make sure to call bus_dmamap_destroy() to
clean up.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/em/if_em.c | 23 |
1 files changed, 19 insertions, 4 deletions
diff --git a/sys/dev/em/if_em.c b/sys/dev/em/if_em.c index 51a574e..7d889f5 100644 --- a/sys/dev/em/if_em.c +++ b/sys/dev/em/if_em.c @@ -598,8 +598,14 @@ em_start_locked(struct ifnet *ifp) IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); if (m_head == NULL) break; - + + /* + * em_encap() can modify our pointer, and or make it NULL on + * failure. In that event, we can't requeue. + */ if (em_encap(adapter, &m_head)) { + if (m_head == NULL) + break; ifp->if_flags |= IFF_OACTIVE; IFQ_DRV_PREPEND(&ifp->if_snd, m_head); break; @@ -1248,15 +1254,24 @@ em_encap(struct adapter *adapter, struct mbuf **m_headp) struct ether_header eh; m_head = m_pullup(m_head, sizeof(eh)); - if (m_head == NULL) + if (m_head == NULL) { + *m_headp = NULL; + bus_dmamap_destroy(adapter->txtag, q.map); return (ENOBUFS); + } eh = *mtod(m_head, struct ether_header *); M_PREPEND(m_head, sizeof(*evl), M_DONTWAIT); - if (m_head == NULL) + if (m_head == NULL) { + *m_headp = NULL; + bus_dmamap_destroy(adapter->txtag, q.map); return (ENOBUFS); + } m_head = m_pullup(m_head, sizeof(*evl)); - if (m_head == NULL) + if (m_head == NULL) { + *m_headp = NULL; + bus_dmamap_destroy(adapter->txtag, q.map); return (ENOBUFS); + } evl = mtod(m_head, struct ether_vlan_header *); bcopy(&eh, evl, sizeof(*evl)); evl->evl_proto = evl->evl_encap_proto; |