Subject: Re: 2.0.2 an ftp
To: David Young <dyoung@pobox.com>
From: John Nemeth <jnemeth@victoria.tc.ca>
List: current-users
Date: 05/12/2005 00:40:11
On Oct 1,  7:23pm, David Young wrote:
} On Wed, May 11, 2005 at 05:19:06PM -0700, John Nemeth wrote:
} >      I have a Cisco 350 Wireless Adapter that I'm trying to use with
} > 2.0.2 on my laptop.  Whenever I try to fetch a file via FTP the
} > following message is logged and ftp receives nothing:
} > 
} > an0: discarding oversize frame (len=1516)
} 
} This ought to be fixed in -current, can you try?  A pull-up to the 2.x
} branch may be in order.

     Thanks.  I grabbed anreg.h and anvar.h from -current.  Then I
patched an.c with just the required changes in order to eliminate any
other differences between 2.0.2 and -current.  Patch is included
below.  All files are in src/sys/dev/ic.  This seems to have done the
job.  My test case was 'download-vulnerability-list'.  Unfortunately,
it failed.  It appears that the signoff message from ftp.netbsd.org is
being truncated.  I tried another test by doing a 'make fetch' in
pkgsrc/devel/gmake.  This seemed to have worked, so the failing test
may not be related.  If it matters I'm using a 2.0.2 i386 box for NAT.

Index: an.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/an.c,v
retrieving revision 1.32
retrieving revision 1.33
diff -u -r1.32 -r1.33
--- an.c	24 Aug 2004 00:53:29 -0000	1.32
+++ an.c	15 Jan 2005 11:01:46 -0000	1.33
@@ -1228,7 +1351,8 @@
 	struct an_rxframe frmhdr;
 	struct mbuf *m;
 	u_int16_t status;
-	int fid, off, len;
+	int fid, gaplen, len, off;
+	uint8_t *gap;
 
 	fid = CSR_READ_2(sc, AN_RX_FID);
 
@@ -1264,7 +1388,8 @@
 		return;
 	}
 
-	len = le16toh(frmhdr.an_rx_payload_len);
+	/* the payload length field includes a 16-bit "mystery field" */
+	len = le16toh(frmhdr.an_rx_payload_len) - sizeof(uint16_t);
 	off = ALIGN(sizeof(struct ieee80211_frame));
 
 	if (off + len > MCLBYTES) {
@@ -1284,7 +1409,7 @@
 		DPRINTF(("an_rx_intr: MGET failed\n"));
 		return;
 	}
-	if (off + len > MHLEN) {
+	if (off + len + AN_GAPLEN_MAX > MHLEN) {
 		MCLGET(m, M_DONTWAIT);
 		if ((m->m_flags & M_EXT) == 0) {
 			CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
@@ -1297,29 +1422,45 @@
 	m->m_data += off - sizeof(struct ieee80211_frame);
 
 	if (ic->ic_opmode != IEEE80211_M_MONITOR) {
+		gaplen = le16toh(frmhdr.an_gaplen);
+		if (gaplen > AN_GAPLEN_MAX) {
+			CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
+			m_freem(m);
+			ifp->if_ierrors++;
+			DPRINTF(("%s: gap too long\n", __func__));
+			return;
+		}
 		/*
-		 * The gap and the payload length should be skipped.
-		 * Make dummy read to avoid seek.
+		 * We don't need the 16-bit mystery field (payload length?),
+		 * so read it into the region reserved for the 802.11 header.
+		 *
+		 * When Cisco Aironet 350 cards w/ firmware version 5 or
+		 * greater operate with certain Cisco 350 APs,
+		 * the "gap" is filled with the SNAP header.  Read
+		 * it in after the 802.11 header.
 		 */
-		an_read_bap(sc, fid, -1, m->m_data,
-		    le16toh(frmhdr.an_gaplen) + sizeof(u_int16_t));
+		gap = m->m_data + sizeof(struct ieee80211_frame) -
+		    sizeof(uint16_t);
+		an_read_bap(sc, fid, -1, gap, gaplen + sizeof(u_int16_t));
 #ifdef AN_DEBUG
 		if ((ifp->if_flags & (IFF_DEBUG|IFF_LINK2)) ==
 		    (IFF_DEBUG|IFF_LINK2)) {
 			int i;
 			printf(" gap&len");
-			for (i = 0;
-			    i < le16toh(frmhdr.an_gaplen) + sizeof(u_int16_t);
-			    i++)
-				printf(" %02x", mtod(m, u_int8_t *)[i]);
+			for (i = 0; i < gaplen + sizeof(u_int16_t); i++)
+				printf(" %02x", gap[i]);
 			printf("\n");
 		}
 #endif
-	}
+	} else
+		gaplen = 0;
+
+	an_read_bap(sc, fid, -1,
+	    m->m_data + sizeof(struct ieee80211_frame) + gaplen, len);
+	m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame) + gaplen +
+	    len;
+
 	memcpy(m->m_data, &frmhdr.an_whdr, sizeof(struct ieee80211_frame));
-	an_read_bap(sc, fid, -1, m->m_data + sizeof(struct ieee80211_frame),
-	    len);
-	m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame) + len;
 	m->m_pkthdr.rcvif = ifp;
 	CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
 
}-- End of excerpt from David Young