PERFORCE change 42879 for review

Sam Leffler sam at FreeBSD.org
Thu Nov 20 21:32:07 PST 2003


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

Change 42879 by sam at sam_ebb on 2003/11/20 21:32:03

	o expand fragment reassembly support handle 3 concurrent
	  frames per the spec
	o make caller verify reassembly is needed before calling
	  the reassembler since the caller has enough state sitting
	  around to make this worthwhile
	o fix cleanup code to not double-free the frag queues for
	  the bss node

Affected files ...

.. //depot/projects/netperf/sys/net80211/ieee80211_input.c#16 edit
.. //depot/projects/netperf/sys/net80211/ieee80211_node.c#18 edit
.. //depot/projects/netperf/sys/net80211/ieee80211_node.h#13 edit

Differences ...

==== //depot/projects/netperf/sys/net80211/ieee80211_input.c#16 (text+ko) ====

@@ -301,9 +301,18 @@
 		if (ic->ic_rawbpf)
 			bpf_mtap(ic->ic_rawbpf, m);
 #endif
-		m = ieee80211_reass(ic, ni, m);
-		if (m == NULL)
-			goto out;
+		if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
+			/*
+			 * Check for and reassemble fragmented frames.
+			 */
+			if ((wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG) ||
+			    (le16toh(*(u_int16_t *)wh->i_seq) &
+				IEEE80211_SEQ_FRAG_MASK) != 0) {
+				m = ieee80211_reass(ic, ni, m);
+				if (m == NULL)
+					goto out;
+			}
+		}
 		m = ieee80211_decap(ifp, m);
 		if (m == NULL) {
 			ic->ic_stats.is_rx_decap++;
@@ -413,6 +422,19 @@
 		if (ic->ic_rawbpf)
 			bpf_mtap(ic->ic_rawbpf, m);
 #endif
+		if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
+			/*
+			 * Check for and reassemble fragmented frames.
+			 * XXX are management frames fragmented?
+			 */
+			if ((wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG) ||
+			    (le16toh(*(u_int16_t *)wh->i_seq) &
+				IEEE80211_SEQ_FRAG_MASK) != 0) {
+				m = ieee80211_reass(ic, ni, m);
+				if (m == NULL)
+					goto out;
+			}
+		}
 		m = ieee80211_reass(ic, ni, m);
 		if (m == NULL)
 			goto out;
@@ -452,43 +474,81 @@
 }
 
 /*
- * Reassemble fragments as necessary.
+ * Reassemble fragments.  The caller is required to check
+ * reassembly is needed before calling.
  */
 static struct mbuf *
 ieee80211_reass(struct ieee80211com *ic, struct ieee80211_node *ni, struct mbuf *m)
 {
-	struct ieee80211_frame *wh, *lwh;
+#define	N(a)	(sizeof(a)/sizeof(a[0]))
+	struct ieee80211_frame *wh;
+	struct ieee80211_frame *lwh = NULL;	/* XXX silence compiler */
 	u_int16_t rxseq, lseq;
 	u_int8_t fragno, more;
+	int i, slot;
 
 	wh = mtod(m, struct ieee80211_frame *);
-	if (IEEE80211_IS_MULTICAST(wh->i_addr1))
-		return m;			/* no mcast frames */
-
+	KASSERT(!IEEE80211_IS_MULTICAST(wh->i_addr1),
+		("multicast frame sent for reassembly"));
 	more = wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG;
 	rxseq = le16toh(*(u_int16_t *)wh->i_seq);
 	fragno = rxseq & IEEE80211_SEQ_FRAG_MASK;
-	if (!more && fragno == 0)
-		return m;			/* not fragmented */
+	KASSERT(more || fragno != 0,
+		("unexpected frame sent for reassembly, more %u fragno %u",
+			more, fragno));
+	/*
+	 * Locate previously received data.
+	 */
+	slot = -1;
+	for (i = N(ni->ni_rxfrag)-1; i >= 0; i--) {
+		if (ni->ni_rxfrag[i] != NULL) {
+			/*
+			 * Slot is in use.  If the data is from the same
+			 * sender then use the slot.  We check the sequence
+			 * number below to decide if the existing data
+			 * should be used or discarded.
+			 */
+			lwh = mtod(ni->ni_rxfrag[i], struct ieee80211_frame *);
+			if (!IEEE80211_ADDR_EQ(wh->i_addr1, lwh->i_addr1) ||
+			    !IEEE80211_ADDR_EQ(wh->i_addr2, lwh->i_addr2))
+				continue;
+			slot = i;
+			break;
+		}
+		slot = i;			/* record unused slot */
+	}
+	if (slot < 0) {
+		/*
+		 * No free slot found, discard the oldest one.
+		 */
+		/* XXX track age to identify oldest one */
+		/* XXX stat */
+		slot = 0;
+		m_freem(ni->ni_rxfrag[slot]);
+		ni->ni_rxfrag[slot] = NULL;
+	}
 
 	/*
 	 * Validate that fragment is in order and
 	 * related to the previous ones.
 	 */
-	if (ni->ni_rxfrag != NULL) {
-		lwh = mtod(ni->ni_rxfrag, struct ieee80211_frame *);
+	KASSERT(0 <= slot && slot < N(ni->ni_rxfrag),
+		("fragment reassembly slot %d out of bounds", slot));
+	if (ni->ni_rxfrag[slot] != NULL) {
+		KASSERT(lwh == mtod(ni->ni_rxfrag[slot],
+			struct ieee80211_frame *),
+			("fragment header pointer not setup"));
 		lseq = le16toh(*(u_int16_t *)lwh->i_seq);
 		/* NB: this checks seq#'s and frag number together */
-		if (rxseq != lseq+1 ||
-		    !IEEE80211_ADDR_EQ(wh->i_addr1, lwh->i_addr1) ||
-		    !IEEE80211_ADDR_EQ(wh->i_addr2, lwh->i_addr2)) {
+		if (rxseq != lseq+1) {
 			/* Unrelated fragment, clear existing data */
 			/* XXX stat */
-			m_freem(ni->ni_rxfrag);
-			ni->ni_rxfrag = NULL;
+			m_freem(ni->ni_rxfrag[slot]);
+			ni->ni_rxfrag[slot] = NULL;
 		}
 	} else {
 		if (fragno != 0) {		/* out of order fragment */
+			/* XXX maybe move this up so we don't reclaim a slot */
 			/* XXX stat */
 			m_freem(m);
 			return NULL;
@@ -497,25 +557,28 @@
 	/*
 	 * Add new fragment to existing data, if any.
 	 */
- 	if (ni->ni_rxfrag != NULL) {
+ 	if (ni->ni_rxfrag[slot] != NULL) {
 		/*
 		 * We know this is the next sequential fragment
 		 * because of the check done above; append the data.
 		 */
-		lwh = mtod(ni->ni_rxfrag, struct ieee80211_frame *);
-		m_cat(ni->ni_rxfrag, m);
+		KASSERT(lwh == mtod(ni->ni_rxfrag[slot],
+			struct ieee80211_frame *),
+			("fragment header pointer not setup"));
+		m_cat(ni->ni_rxfrag[slot], m);
 		/* record last sequence and fragno */
-		*(u_int16_t *) lwh->i_seq = rxseq;
+		*(u_int16_t *)lwh->i_seq = rxseq;
 		if (!more) {			/* reassembly complete */
-			m = ni->ni_rxfrag;
-			ni->ni_rxfrag = NULL;
+			m = ni->ni_rxfrag[slot];
+			ni->ni_rxfrag[slot] = NULL;
 		} else				/* frame incomplete */
 			m = NULL;
 	} else {
-		ni->ni_rxfrag = m;
+		ni->ni_rxfrag[slot] = m;
 		m = NULL;
 	}
 	return m;
+#undef N
 }
 
 struct mbuf *

==== //depot/projects/netperf/sys/net80211/ieee80211_node.c#18 (text+ko) ====

@@ -111,11 +111,8 @@
 {
 	struct ieee80211com *ic = (void *)ifp;
 
-	if (ic->ic_bss != NULL) {
-		if (ic->ic_bss->ni_rxfrag != NULL)
-			m_freem(ic->ic_bss->ni_rxfrag);
+	if (ic->ic_bss != NULL)
 		(*ic->ic_node_free)(ic, ic->ic_bss);
-	}
 	ieee80211_free_allnodes(ic);
 	IEEE80211_NODE_LOCK_DESTROY(ic);
 }
@@ -530,6 +527,9 @@
 static void
 _ieee80211_free_node(struct ieee80211com *ic, struct ieee80211_node *ni)
 {
+#define	N(a)	(sizeof(a)/sizeof(a[0]))
+	int i;
+
 	KASSERT(ni != ic->ic_bss, ("freeing bss node"));
 
 	IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap);
@@ -542,9 +542,11 @@
 	}
 	if (TAILQ_EMPTY(&ic->ic_node))
 		ic->ic_inact_timer = 0;
-	if (ni->ni_rxfrag != NULL)
-		m_freem(ni->ni_rxfrag);
+	for (i = 0; i < N(ni->ni_rxfrag); i++)
+		if (ni->ni_rxfrag[i] != NULL)
+			m_freem(ni->ni_rxfrag[i]);
 	(*ic->ic_node_free)(ic, ni);
+#undef N
 }
 
 void

==== //depot/projects/netperf/sys/net80211/ieee80211_node.h#13 (text+ko) ====

@@ -108,7 +108,7 @@
 	int			ni_inact;	/* inactivity mark count */
 	int			ni_txrate;	/* index to ni_rates[] */
 	u_int32_t		*ni_challenge;	/* shared-key challenge */
-	struct mbuf		*ni_rxfrag;	/* rx frag reassembly */
+	struct mbuf		*ni_rxfrag[3];	/* rx frag reassembly */
 };
 
 static __inline struct ieee80211_node *


More information about the p4-projects mailing list