PERFORCE change 68617 for review

Sam Leffler sam at FreeBSD.org
Sun Jan 9 20:46:07 PST 2005


http://perforce.freebsd.org/chv.cgi?CH=68617

Change 68617 by sam at sam_ebb on 2005/01/10 04:45:17

	working fast frames; still needs work

Affected files ...

.. //depot/projects/wifi/sys/dev/ath/if_ath.c#64 edit
.. //depot/projects/wifi/sys/dev/ath/if_athvar.h#26 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_input.c#37 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_ioctl.h#22 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_output.c#32 edit
.. //depot/projects/wifi/tools/tools/ath/80211stats.c#8 edit

Differences ...

==== //depot/projects/wifi/sys/dev/ath/if_ath.c#64 (text+ko) ====

@@ -2184,10 +2184,10 @@
 	}
 	/*
 	 * Check if the previous beacon has gone out.  If
-	 * not don't don't try to post another, skip this
-	 * period and wait for the next.  Missed beacons
-	 * indicate a problem and should not occur.  If we
-	 * miss too many consecutive beacons reset the device.
+	 * not don't try to post another, skip this period
+	 * and wait for the next.  Missed beacons indicate
+	 * a problem and should not occur.  If we miss too
+	 * many consecutive beacons reset the device.
 	 */
 	if (ath_hal_numtxpending(ah, sc->sc_bhalq) != 0) {
 		sc->sc_bmisscount++;
@@ -2890,19 +2890,7 @@
 		if (status == HAL_EINPROGRESS)
 			break;
 		STAILQ_REMOVE_HEAD(&sc->sc_rxbuf, bf_list);
-		if (ds->ds_rxstat.rs_more) {
-			/*
-			 * Frame spans multiple descriptors; this
-			 * cannot happen yet as we don't support
-			 * jumbograms.  If not in monitor mode,
-			 * discard the frame.
-			 */
-			if (ic->ic_opmode != IEEE80211_M_MONITOR) {
-				sc->sc_stats.ast_rx_toobig++;
-				goto rx_next;
-			}
-			/* fall thru for monitor mode handling... */
-		} else if (ds->ds_rxstat.rs_status != 0) {
+		if (ds->ds_rxstat.rs_status != 0) {
 			if (ds->ds_rxstat.rs_status & HAL_RXERR_CRC)
 				sc->sc_stats.ast_rx_crcerr++;
 			if (ds->ds_rxstat.rs_status & HAL_RXERR_FIFO)
@@ -2911,7 +2899,7 @@
 				sc->sc_stats.ast_rx_phyerr++;
 				phyerr = ds->ds_rxstat.rs_phyerr & 0x1f;
 				sc->sc_stats.ast_rx_phy[phyerr]++;
-				goto rx_next;
+				goto rx_error;	/* NB: don't count in ierrors */
 			}
 			if (ds->ds_rxstat.rs_status & HAL_RXERR_DECRYPT) {
 				/*
@@ -2949,7 +2937,15 @@
 				}
 			}
 			ifp->if_ierrors++;
+rx_error:
 			/*
+			 * Cleanup any pending partial frame.
+			 */
+			if (sc->sc_rxpending != NULL) {
+				m_freem(sc->sc_rxpending);
+				sc->sc_rxpending = NULL;
+			}
+			/*
 			 * Reject error frames, we normally don't want
 			 * to see them in monitor mode (in monitor mode
 			 * allow through packets that have crypto problems).
@@ -2972,9 +2968,42 @@
 		bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
 		bf->bf_m = NULL;
 
-		m->m_pkthdr.rcvif = ifp;
 		len = ds->ds_rxstat.rs_datalen;
-		m->m_pkthdr.len = m->m_len = len;
+		m->m_len = len;
+
+		if (ds->ds_rxstat.rs_more) {
+			/*
+			 * Frame spans multiple descriptors; save
+			 * it for the next completed descriptor, it
+			 * will be used to construct a jumbogram.
+			 */
+			if (sc->sc_rxpending != NULL) {
+				/* NB: max frame size is currently 2 clusters */
+				sc->sc_stats.ast_rx_toobig++;
+				m_freem(sc->sc_rxpending);
+			}
+			m->m_pkthdr.rcvif = ifp;
+			m->m_pkthdr.len = len;
+			sc->sc_rxpending = m;
+			goto rx_next;
+		} else if (sc->sc_rxpending != NULL) {
+			/*
+			 * This is the second part of a jumbogram,
+			 * chain it to the first mbuf, adjust the
+			 * frame length, and clear the rxpending state.
+			 */
+			sc->sc_rxpending->m_next = m;
+			sc->sc_rxpending->m_pkthdr.len += len;
+			m = sc->sc_rxpending;
+			sc->sc_rxpending = NULL;
+		} else {
+			/*
+			 * Normal single-descriptor receive; setup
+			 * the rcvif and packet length.
+			 */
+			m->m_pkthdr.rcvif = ifp;
+			m->m_pkthdr.len = len;
+		}
 
 		sc->sc_stats.ast_ant_rx[ds->ds_rxstat.rs_antenna]++;
 
@@ -3783,8 +3812,6 @@
 					ds->ds_txstat.ts_rssi;
 				ATH_RSSI_LPF(an->an_halstats.ns_avgtxrssi,
 					ds->ds_txstat.ts_rssi);
-				if (bf->bf_m->m_flags & M_FF)
-					sc->sc_stats.ast_ff_txok++;
 				pri = M_WME_GETAC(bf->bf_m);
 				if (pri >= WME_AC_VO)
 					ic->ic_wme.wme_hipri_traffic++;
@@ -4037,6 +4064,10 @@
 		}
 	}
 #endif
+	if (sc->sc_rxpending != NULL) {
+		m_freem(sc->sc_rxpending);
+		sc->sc_rxpending = NULL;
+	}
 	sc->sc_rxlink = NULL;		/* just in case */
 #undef PA2DESC
 }
@@ -4051,6 +4082,7 @@
 	struct ath_buf *bf;
 
 	sc->sc_rxlink = NULL;
+	sc->sc_rxpending = NULL;
 	STAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) {
 		int error = ath_rxbuf_init(sc, bf);
 		if (error != 0) {

==== //depot/projects/wifi/sys/dev/ath/if_athvar.h#26 (text+ko) ====

@@ -258,6 +258,7 @@
 
 	struct ath_descdma	sc_rxdma;	/* RX descriptos */
 	ath_bufhead		sc_rxbuf;	/* receive buffer */
+	struct mbuf		*sc_rxpending;	/* pending receive data */
 	u_int32_t		*sc_rxlink;	/* link ptr in last RX desc */
 	struct task		sc_rxtask;	/* rx int processing */
 	struct task		sc_rxorntask;	/* rxorn int processing */

==== //depot/projects/wifi/sys/net80211/ieee80211_input.c#37 (text+ko) ====

@@ -108,7 +108,11 @@
 
 static struct mbuf *ieee80211_defrag(struct ieee80211com *,
 	struct ieee80211_node *, struct mbuf *);
+static void ieee80211_deliver_data(struct ieee80211com *,
+	struct ieee80211_node *, struct mbuf *);
 static struct mbuf *ieee80211_decap(struct ieee80211com *, struct mbuf *);
+static struct mbuf *ieee80211_decap_fastframe(struct ieee80211com *,
+	struct ieee80211_node *, struct mbuf *);
 static void ieee80211_node_pwrsave(struct ieee80211_node *, int enable);
 static void ieee80211_recv_pspoll(struct ieee80211com *,
 	struct ieee80211_node *, struct mbuf *);
@@ -133,7 +137,7 @@
 	struct ieee80211_frame *wh;
 	struct ieee80211_key *key;
 	struct ether_header *eh;
-	int len, hdrsize, off;
+	int hdrsize, off;
 	u_int8_t dir, type, subtype;
 	u_int8_t *bssid;
 	u_int16_t rxseq;
@@ -289,8 +293,8 @@
 		if (m->m_len < hdrsize &&
 		    (m = m_pullup(m, hdrsize)) == NULL) {
 			IEEE80211_DISCARD(ic, IEEE80211_MSG_ANY,
-			    wh, "data", "too short: len %u, expecting %u",
-			    m->m_pkthdr.len, hdrsize);
+			    wh, "data", "too short: m_pullup(%u) failed",
+			    hdrsize);
 			ic->ic_stats.is_rx_tooshort++;
 			goto out;		/* XXX */
 		}
@@ -492,49 +496,32 @@
 		IEEE80211_NODE_STAT(ni, rx_data);
 		IEEE80211_NODE_STAT_ADD(ni, rx_bytes, m->m_pkthdr.len);
 
-		/* perform as a bridge within the AP */
-		if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
-		    (ic->ic_flags & IEEE80211_F_NOBRIDGE) == 0) {
-			struct mbuf *m1 = NULL;
+#define	FF_LLC_SIZE	(sizeof(struct ether_header) + sizeof(struct llc))
+		if ((ni->ni_flags & IEEE80211_NODE_FF) &&
+		    m->m_pkthdr.len >= 3*FF_LLC_SIZE) {
+			struct llc *llc;
 
-			if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
-				m1 = m_copypacket(m, M_DONTWAIT);
-				if (m1 == NULL)
-					ifp->if_oerrors++;
-				else
-					m1->m_flags |= M_MCAST;
-			} else {
-				/* XXX this dups work done in ieee80211_encap */
-				/* check if destination is associated */
-				struct ieee80211_node *ni1 =
-				    ieee80211_find_node(ic->ic_sta,
-							eh->ether_dhost);
-				if (ni1 != NULL) {
-					/* XXX check if authorized */
-					if (ni1->ni_associd != 0) {
-						m1 = m;
-						m = NULL;
-					}
-					/* XXX statistic? */
-					ieee80211_free_node(ni1);
-				}
+			/*
+			 * Check for fast-frame tunnel encapsulation.
+			 */
+			if (m->m_len < FF_LLC_SIZE &&
+			    (m = m_pullup(m, FF_LLC_SIZE)) == NULL) {
+				IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_ANY,
+				    ni->ni_macaddr, "fast-frame",
+				    "%s", "m_pullup(llc) failed");
+				ic->ic_stats.is_rx_tooshort++;
 			}
-			if (m1 != NULL) {
-				len = m1->m_pkthdr.len;
-				IF_ENQUEUE(&ifp->if_snd, m1);
-				if (m != NULL)
-					ifp->if_omcasts++;
-				ifp->if_obytes += len;
+			llc = (struct llc *)(mtod(m, u_int8_t *) + 
+				sizeof(struct ether_header));
+			if (llc->llc_snap.ether_type == htons(ATH_FF_ETH_TYPE)) {
+				m_adj(m, FF_LLC_SIZE);
+				m = ieee80211_decap_fastframe(ic, ni, m);
+				if (m == NULL)
+					return;
 			}
 		}
-		if (m != NULL) {
-			if (ni->ni_vlan != 0) {
-				/* attach vlan tag */
-				/* XXX goto err? */
-				VLAN_INPUT_TAG(ifp, m, ni->ni_vlan, goto out);
-			}
-			(*ifp->if_input)(ifp, m);
-		}
+#undef FF_LLC_SIZE
+		ieee80211_deliver_data(ic, ni, m);
 		return;
 
 	case IEEE80211_FC0_TYPE_MGT:
@@ -711,6 +698,66 @@
 	return mfrag;
 }
 
+static void
+ieee80211_deliver_data(struct ieee80211com *ic,
+	struct ieee80211_node *ni, struct mbuf *m)
+{
+	struct ether_header *eh = mtod(m, struct ether_header *);
+	struct ifnet *ifp = ic->ic_ifp;
+	int len;
+
+	/* perform as a bridge within the AP */
+	if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
+	    (ic->ic_flags & IEEE80211_F_NOBRIDGE) == 0) {
+		struct mbuf *m1 = NULL;
+
+		if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
+			m1 = m_copypacket(m, M_DONTWAIT);
+			if (m1 == NULL)
+				ifp->if_oerrors++;
+			else
+				m1->m_flags |= M_MCAST;
+		} else {
+			/* XXX this dups work done in ieee80211_encap */
+			/* check if destination is associated */
+			struct ieee80211_node *ni1 =
+			    ieee80211_find_node(ic->ic_sta,
+						eh->ether_dhost);
+			if (ni1 != NULL) {
+				/* XXX check if authorized */
+				if (ni1->ni_associd != 0) {
+					m1 = m;
+					m = NULL;
+				}
+				/* XXX statistic? */
+				ieee80211_free_node(ni1);
+			}
+		}
+		if (m1 != NULL) {
+			len = m1->m_pkthdr.len;
+			IF_ENQUEUE(&ifp->if_snd, m1);
+			if (m != NULL)
+				ifp->if_omcasts++;
+			ifp->if_obytes += len;
+		}
+	}
+	if (m != NULL) {
+		if (ni->ni_vlan != 0) {
+			/* attach vlan tag */
+			/* XXX goto err? */
+			VLAN_INPUT_TAG(ifp, m, ni->ni_vlan, goto out);
+		}
+		(*ifp->if_input)(ifp, m);
+	}
+	return;
+  out:
+	if (m != NULL) {
+		if (ic->ic_rawbpf)
+			bpf_mtap(ic->ic_rawbpf, m);
+		m_freem(m);
+	}
+}
+
 static struct mbuf *
 ieee80211_decap(struct ieee80211com *ic, struct mbuf *m)
 {
@@ -813,6 +860,104 @@
 }
 
 /*
+ * Decap a frame encapsulated in a fast-frame.
+ */
+static struct mbuf *
+ieee80211_decap1(struct mbuf *m, int *framelen)
+{
+#define	FF_LLC_SIZE	(sizeof(struct ether_header) + sizeof(struct llc))
+	struct ether_header *eh;
+	struct llc *llc;
+
+	/*
+	 * The frame has an 802.3 header followed by an 802.2
+	 * LLC header.  The encapsulated frame length is in the
+	 * first header type field; save that and overwrite it 
+	 * with the true type field found in the second.  Then
+	 * copy the 802.3 header up to where it belongs and
+	 * adjust the mbuf contents to remove the void.
+	 */
+	if (m->m_len < FF_LLC_SIZE && (m = m_pullup(m, FF_LLC_SIZE)) == NULL)
+		return NULL;
+	eh = mtod(m, struct ether_header *);	/* 802.3 header is first */
+	llc = (struct llc *)&eh[1];		/* 802.2 header follows */
+	*framelen = ntohs(eh->ether_type)	/* encap'd frame size */
+		  + sizeof(struct ether_header) - sizeof(struct llc);
+	eh->ether_type = llc->llc_un.type_snap.ether_type;
+	ovbcopy(eh, mtod(m, u_int8_t *) + sizeof(struct llc),
+		sizeof(struct ether_header));
+	m_adj(m, sizeof(struct llc));
+	return m;
+#undef FF_LLC_SIZE
+}
+
+/*
+ * Decap the encapsulated frame pair and dispatch the first
+ * for delivery.  The second frame is returned for delivery
+ * via the normal path.
+ */
+static struct mbuf *
+ieee80211_decap_fastframe(struct ieee80211com *ic,
+	struct ieee80211_node *ni, struct mbuf *m)
+{
+#define	MS(x,f)	(((x) & f) >> f##_S)
+	u_int32_t ath;
+	struct mbuf *n;
+	int framelen;
+
+	m_copydata(m, 0, sizeof(u_int32_t), (caddr_t) &ath);
+	if (MS(ath, ATH_FF_PROTO) != ATH_FF_PROTO_L2TUNNEL) {
+		IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_ANY,
+		    ni->ni_macaddr, "fast-frame",
+		    "unsupport tunnel protocol, header 0x%x", ath);
+		ic->ic_stats.is_ff_badhdr++;
+		m_freem(m);
+		return NULL;
+	}
+	/* NB: skip header and alignment padding */
+	m_adj(m, roundup(sizeof(u_int32_t) - 2, 4) + 2);
+
+	ic->ic_stats.is_ff_decap++;
+
+	/*
+	 * Decap the first frame, bust it apart from the
+	 * second and deliver; then decap the second frame
+	 * and return it to the caller for normal delivery.
+	 */
+	m = ieee80211_decap1(m, &framelen);
+	if (m == NULL) {
+		IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_ANY,
+		    ni->ni_macaddr, "fast-frame", "%s", "first decap failed");
+		ic->ic_stats.is_ff_tooshort++;
+		return NULL;
+	}
+	n = m_split(m, framelen, M_NOWAIT);
+	if (n == NULL) {
+		IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_ANY,
+		    ni->ni_macaddr, "fast-frame",
+		    "%s", "unable to split encapsulated frames");
+		ic->ic_stats.is_ff_split++;
+		m_freem(m);			/* NB: must reclaim */
+		return NULL;
+	}
+	ieee80211_deliver_data(ic, ni, m);	/* 1st of pair */
+
+	/*
+	 * Decap second frame.
+	 */
+	m_adj(n, roundup2(framelen, 4) - framelen);	/* padding */
+	n = ieee80211_decap1(n, &framelen);
+	if (n == NULL) {
+		IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_ANY,
+		    ni->ni_macaddr, "fast-frame", "%s", "second decap failed");
+		ic->ic_stats.is_ff_tooshort++;
+	}
+	/* XXX verify framelen against mbuf contents */
+	return n;				/* 2nd delivered by caller */
+#undef MS
+}
+
+/*
  * Install received rate set information in the node's state block.
  */
 static int

==== //depot/projects/wifi/sys/net80211/ieee80211_ioctl.h#22 (text+ko) ====

@@ -173,6 +173,11 @@
 	u_int32_t	is_ps_unassoc;		/* ps-poll for unassoc. sta */
 	u_int32_t	is_ps_badaid;		/* ps-poll w/ incorrect aid */
 	u_int32_t	is_ps_qempty;		/* ps-poll w/ nothing to send */
+	u_int32_t	is_ff_badhdr;		/* fast frame rx'd w/ bad hdr */
+	u_int32_t	is_ff_tooshort;		/* fast frame rx decap error */
+	u_int32_t	is_ff_split;		/* fast frame rx split error */
+	u_int32_t	is_ff_decap;		/* fast frames decap'd */
+	u_int32_t	is_ff_encap;		/* fast frames encap'd for tx */
 };
 
 /*

==== //depot/projects/wifi/sys/net80211/ieee80211_output.c#32 (text+ko) ====

@@ -537,9 +537,8 @@
 			goto bad;
 		}
 		m = ieee80211_encap_fastframe(ic, m, &eh, m2, &eh2);
-		if (m == NULL) {
+		if (m == NULL)
 			goto bad;
-		}
 	} else {
 		/*
 		 * Normal frame.
@@ -768,6 +767,8 @@
 	llc->llc_snap.org_code[2] = ATH_FF_SNAP_ORGCODE_2;
 	llc->llc_snap.ether_type = htons(ATH_FF_ETH_TYPE);
 
+	ic->ic_stats.is_ff_encap++;
+
 	return m1;
 }
 

==== //depot/projects/wifi/tools/tools/ath/80211stats.c#8 (text+ko) ====

@@ -144,6 +144,11 @@
 	STAT(ps_unassoc,	"ps-poll received for unassociated station");
 	STAT(ps_badaid,		"ps-poll received with invalid association id");
 	STAT(ps_qempty,		"ps-poll received with nothing to send");
+	STAT(ff_badhdr,		"fast frame rx'd w/ bad hdr");
+	STAT(ff_tooshort,	"fast frame rx decap error");
+	STAT(ff_split,		"fast frame rx split error");
+	STAT(ff_decap,		"fast frames decap'd");
+	STAT(ff_encap,		"fast frames encap'd for tx");
 #undef STAT
 #undef N
 }


More information about the p4-projects mailing list