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.
This commit is contained in:
rwatson 2004-11-14 20:20:28 +00:00
parent 36c3b3ee0b
commit 0188f1bf36

View File

@ -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;