summaryrefslogtreecommitdiffstats
path: root/sys/dev/pci/if_ipw.c
diff options
context:
space:
mode:
authordamien <damien@openbsd.org>2008-12-21 18:19:58 +0000
committerdamien <damien@openbsd.org>2008-12-21 18:19:58 +0000
commit237f3d12226590abb82c358a1576a4d027d231be (patch)
treeec40881bba403dcd71d58ec40748d67233d505db /sys/dev/pci/if_ipw.c
parentfix example comparison function to work with large ranges of numbers. ok djm otto (diff)
downloadwireguard-openbsd-237f3d12226590abb82c358a1576a4d027d231be.tar.xz
wireguard-openbsd-237f3d12226590abb82c358a1576a4d027d231be.zip
Undo m_defrag().
m_defrag() does not work. It seems to assume that if the length of the mbuf passed as parameter is less than MHLEN, then it is an mbuf header and not a cluster (or something like that.) It thus fails miserably in the bcopy path. I don't have the time to investigate further into this. Thanks to Okan Demirmen for reporting the issue on a ral(4) RT2560. The RT2560 chipset does not support TX scatter and thus m_defrag() was called much more often than in other drivers using m_defrag() where it was less noticeable.
Diffstat (limited to 'sys/dev/pci/if_ipw.c')
-rw-r--r--sys/dev/pci/if_ipw.c21
1 files changed, 18 insertions, 3 deletions
diff --git a/sys/dev/pci/if_ipw.c b/sys/dev/pci/if_ipw.c
index 3df6e44fd83..45c7b33b141 100644
--- a/sys/dev/pci/if_ipw.c
+++ b/sys/dev/pci/if_ipw.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_ipw.c,v 1.81 2008/11/25 21:43:57 damien Exp $ */
+/* $OpenBSD: if_ipw.c,v 1.82 2008/12/21 18:19:58 damien Exp $ */
/*-
* Copyright (c) 2004-2008
@@ -1127,6 +1127,7 @@ ipw_tx_start(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni)
struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211_frame *wh;
struct ieee80211_key *k;
+ struct mbuf *m1;
struct ipw_soft_bd *sbd;
struct ipw_soft_hdr *shdr;
struct ipw_soft_buf *sbuf;
@@ -1191,10 +1192,24 @@ ipw_tx_start(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni)
}
if (error != 0) {
/* too many fragments, linearize */
- if (m_defrag(m, M_DONTWAIT) != 0) {
+ MGETHDR(m1, MT_DATA, M_DONTWAIT);
+ if (m1 == NULL) {
m_freem(m);
- return ENOMEM;
+ return ENOBUFS;
+ }
+ if (m->m_pkthdr.len > MHLEN) {
+ MCLGET(m1, M_DONTWAIT);
+ if (!(m1->m_flags & M_EXT)) {
+ m_freem(m);
+ m_freem(m1);
+ return ENOBUFS;
+ }
}
+ m_copydata(m, 0, m->m_pkthdr.len, mtod(m1, caddr_t));
+ m1->m_pkthdr.len = m1->m_len = m->m_pkthdr.len;
+ m_freem(m);
+ m = m1;
+
error = bus_dmamap_load_mbuf(sc->sc_dmat, sbuf->map, m,
BUS_DMA_NOWAIT);
if (error != 0) {