Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 19 Jul 2005 22:02:22 GMT
From:      Sam Leffler <sam@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 80556 for review
Message-ID:  <200507192202.j6JM2Mll092960@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=80556

Change 80556 by sam@sam_ebb on 2005/07/19 22:02:01

	o add tx fragmentation
	o move rts+txfrag default settings from ieee80211.h
	  to ieee80211_var.h since they are implementation-dependent
	  and not defined by the protocol (well maybe)
	o correct max rts 
	o fix some bounds checking of ioctl parameters to allow the
	  min/max settings
	o allow rts/frag thresholds to be reset with "-"; e.g.
	  ifconfig ath0 fragthreshold -

Affected files ...

.. //depot/projects/wifi/sbin/ifconfig/ifieee80211.c#43 edit
.. //depot/projects/wifi/sys/dev/ath/if_ath.c#89 edit
.. //depot/projects/wifi/sys/net80211/ieee80211.h#10 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_ioctl.c#43 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_ioctl.h#27 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_output.c#45 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_proto.c#30 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_var.h#30 edit

Differences ...

==== //depot/projects/wifi/sbin/ifconfig/ifieee80211.c#43 (text+ko) ====

@@ -344,7 +344,8 @@
 static void
 set80211rtsthreshold(const char *val, int d, int s, const struct afswtch *rafp)
 {
-	set80211(s, IEEE80211_IOC_RTSTHRESHOLD, atoi(val), 0, NULL);
+	set80211(s, IEEE80211_IOC_RTSTHRESHOLD,
+		isundefarg(val) ? IEEE80211_RTS_MAX : atoi(val), 0, NULL);
 }
 
 static void
@@ -702,6 +703,13 @@
 	set80211(s, IEEE80211_IOC_MCAST_RATE, 2*atoi(val), 0, NULL);
 }
 
+static
+DECL_CMD_FUNC(set80211fragthreshold, val, d)
+{
+	set80211(s, IEEE80211_IOC_FRAGTHRESHOLD,
+		isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL);
+}
+
 static int
 getmaxrate(uint8_t rates[15], uint8_t nrates)
 {
@@ -1093,7 +1101,7 @@
 #define	IEEE80211_C_BITS \
 "\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \
 "\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE\21MONITOR\22TKIPMIC\30WPA1" \
-"\31WPA2\32BURST\33WME\34WDS\36BGSCAN"
+"\31WPA2\32BURST\33WME\34WDS\36BGSCAN\37TXFRAG"
 
 static void
 list_capabilities(int s)
@@ -1587,6 +1595,12 @@
 			LINE_CHECK("%crtsthreshold %d", spacer, ireq.i_val);
 	}
 
+	ireq.i_type = IEEE80211_IOC_FRAGTHRESHOLD;
+	if (ioctl(s, SIOCG80211, &ireq) != -1) {
+		if (ireq.i_val != IEEE80211_FRAG_MAX || verbose)
+			LINE_CHECK("%cfragthreshold %d", spacer, ireq.i_val);
+	}
+
 	ireq.i_type = IEEE80211_IOC_MCAST_RATE;
 	if (ioctl(s, SIOCG80211, &ireq) != -1) {
 		if (ireq.i_val != 2*1 || verbose)
@@ -1967,6 +1981,7 @@
 	DEF_CMD_ARG("roam:rate11b",	set80211roamrate11b),
 	DEF_CMD_ARG("roam:rate11g",	set80211roamrate11g),
 	DEF_CMD_ARG("mcastrate",	set80211mcastrate),
+	DEF_CMD_ARG("fragthreshold",	set80211fragthreshold),
 };
 static struct afswtch af_ieee80211 = {
 	.af_name	= "af_ieee80211",

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

@@ -503,6 +503,7 @@
 		| IEEE80211_C_SHSLOT		/* short slot time supported */
 		| IEEE80211_C_WPA		/* capable of WPA1+WPA2 */
 		| IEEE80211_C_BGSCAN		/* capable of bg scanning */
+		| IEEE80211_C_TXFRAG		/* handle tx frags */
 		;
 	/*
 	 * Query the hal to figure out h/w crypto support.
@@ -1376,7 +1377,55 @@
 	return m;
 }
 
+/*
+ * Cleanup driver resources when we run out of buffers
+ * while processing fragments; return the tx buffers
+ * allocated and drop node references.
+ */
 static void
+ath_txfrag_cleanup(struct ath_softc *sc,
+	ath_bufhead *frags, struct ieee80211_node *ni)
+{
+	struct ath_buf *bf, *next;
+
+	ATH_TXBUF_LOCK_ASSERT(sc);
+
+	STAILQ_FOREACH_SAFE(bf, frags, bf_list, next) {
+		STAILQ_REMOVE_HEAD(frags, bf_list);
+		STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
+		ieee80211_node_decref(ni);
+	}
+}
+
+/*
+ * Setup xmit of a fragmented frame.  Allocate a buffer
+ * for each frag and bump the node reference count to
+ * reflect the held reference to be setup by ath_tx_start.
+ */
+static int
+ath_txfrag_setup(struct ath_softc *sc, ath_bufhead *frags,
+	struct mbuf *m0, struct ieee80211_node *ni)
+{
+	struct mbuf *m;
+	struct ath_buf *bf;
+
+	ATH_TXBUF_LOCK(sc);
+	for (m = m0->m_nextpkt; m != NULL; m = m->m_nextpkt) {
+		bf = STAILQ_FIRST(&sc->sc_txbuf);
+		if (bf == NULL) {	/* out of buffers, cleanup */
+			ath_txfrag_cleanup(sc, frags, ni);
+			break;
+		}
+		STAILQ_REMOVE_HEAD(&sc->sc_txbuf, bf_list);
+		ieee80211_node_incref(ni);
+		STAILQ_INSERT_TAIL(frags, bf, bf_list);
+	}
+	ATH_TXBUF_UNLOCK(sc);
+
+	return !STAILQ_EMPTY(frags);
+}
+
+static void
 ath_start(struct ifnet *ifp)
 {
 	struct ath_softc *sc = ifp->if_softc;
@@ -1384,10 +1433,11 @@
 	struct ieee80211com *ic = &sc->sc_ic;
 	struct ieee80211_node *ni;
 	struct ath_buf *bf;
-	struct mbuf *m;
+	struct mbuf *m, *next;
 	struct ieee80211_frame *wh;
 	struct ether_header *eh;
 	struct ath_txq *txq;
+	ath_bufhead frags;
 	int pri;
 
 	if ((ifp->if_flags & IFF_RUNNING) == 0 || sc->sc_invalid)
@@ -1434,6 +1484,7 @@
 				ATH_TXBUF_UNLOCK(sc);
 				break;
 			}
+			STAILQ_INIT(&frags);
 			/* 
 			 * Find the node for the destination so we can do
 			 * things like power save and fast frames aggregation.
@@ -1504,6 +1555,19 @@
 				sc->sc_stats.ast_tx_encap++;
 				goto bad;
 			}
+			/*
+			 * Check for fragmentation.  If this has frame
+			 * has been broken up verify we have enough
+			 * buffers to send all the fragments so all
+			 * go out or none...
+			 */
+			if ((m->m_flags & M_FRAG) && 
+			    !ath_txfrag_setup(sc, &frags, m, ni)) {
+				DPRINTF(sc, ATH_DEBUG_ANY,
+				    "%s: out of txfrag buffers\n", __func__);
+				ic->ic_stats.is_tx_nobuf++;	/* XXX */
+				goto bad;
+			}
 		} else {
 			/*
 			 * Hack!  The referenced node pointer is in the
@@ -1534,17 +1598,27 @@
 			sc->sc_stats.ast_tx_mgmt++;
 		}
 
+	nextfrag:
+		next = m->m_nextpkt;
 		if (ath_tx_start(sc, ni, bf, m)) {
 	bad:
 			ifp->if_oerrors++;
 	reclaim:
 			ATH_TXBUF_LOCK(sc);
 			STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
+			ath_txfrag_cleanup(sc, &frags, ni);
 			ATH_TXBUF_UNLOCK(sc);
 			if (ni != NULL)
 				ieee80211_free_node(ni);
 			continue;
 		}
+		if (next != NULL) {
+			m = next;
+			bf = STAILQ_FIRST(&frags);
+			KASSERT(bf != NULL, ("no buf for txfrag"));
+			STAILQ_REMOVE_HEAD(&frags, bf_list);
+			goto nextfrag;
+		}
 
 		sc->sc_tx_timer = 5;
 		ifp->if_timer = 1;
@@ -3563,6 +3637,18 @@
 	return 0;		/* NB: lowest rate */
 }
 
+static void
+ath_freetx(struct mbuf *m)
+{
+	struct mbuf *next;
+
+	do {
+		next = m->m_nextpkt;
+		m->m_nextpkt = NULL;
+		m_freem(m);
+	} while ((m = next) != NULL);
+}
+
 static int
 ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf,
     struct mbuf *m0)
@@ -3578,7 +3664,7 @@
 	struct ath_hal *ah = sc->sc_ah;
 	struct ifnet *ifp = sc->sc_ifp;
 	const struct chanAccParams *cap = &ic->ic_wme.wme_chanParams;
-	int i, error, iswep, ismcast, keyix, hdrlen, pktlen, try0;
+	int i, error, iswep, ismcast, isfrag, keyix, hdrlen, pktlen, try0;
 	u_int8_t rix, txrate, ctsrate;
 	u_int8_t cix = 0xff;		/* NB: silence compiler */
 	struct ath_desc *ds, *ds0;
@@ -3595,6 +3681,7 @@
 	wh = mtod(m0, struct ieee80211_frame *);
 	iswep = wh->i_fc[1] & IEEE80211_FC1_WEP;
 	ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
+	isfrag = m0->m_flags & M_FRAG;
 	hdrlen = ieee80211_anyhdrsize(wh);
 	/*
 	 * Packet length must not include any
@@ -3619,21 +3706,22 @@
 			 * 802.11 layer counts failures and provides
 			 * debugging/diagnostics.
 			 */
-			m_freem(m0);
+			ath_freetx(m0);
 			return EIO;
 		}
 		/*
 		 * Adjust the packet + header lengths for the crypto
 		 * additions and calculate the h/w key index.  When
 		 * a s/w mic is done the frame will have had any mic
-		 * added to it prior to entry so skb->len above will
+		 * added to it prior to entry so m0->m_pkthdr.len will
 		 * account for it. Otherwise we need to add it to the
 		 * packet length.
 		 */
 		cip = k->wk_cipher;
 		hdrlen += cip->ic_header;
 		pktlen += cip->ic_header + cip->ic_trailer;
-		if ((k->wk_flags & IEEE80211_KEY_SWMIC) == 0)
+		/* NB: frags always have any TKIP MIC done in s/w */
+		if ((k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && !isfrag)
 			pktlen += cip->ic_miclen;
 		keyix = k->wk_keyix;
 
@@ -3663,7 +3751,7 @@
 		bf->bf_nseg = ATH_TXDESC+1;
 	} else if (error != 0) {
 		sc->sc_stats.ast_tx_busdma++;
-		m_freem(m0);
+		ath_freetx(m0);
 		return error;
 	}
 	/*
@@ -3675,7 +3763,7 @@
 		sc->sc_stats.ast_tx_linear++;
 		m = ath_defrag(m0, M_DONTWAIT, ATH_TXDESC);
 		if (m == NULL) {
-			m_freem(m0);
+			ath_freetx(m0);
 			sc->sc_stats.ast_tx_nombuf++;
 			return ENOMEM;
 		}
@@ -3685,14 +3773,14 @@
 					     BUS_DMA_NOWAIT);
 		if (error != 0) {
 			sc->sc_stats.ast_tx_busdma++;
-			m_freem(m0);
+			ath_freetx(m0);
 			return error;
 		}
 		KASSERT(bf->bf_nseg <= ATH_TXDESC,
 		    ("too many segments after defrag; nseg %u", bf->bf_nseg));
 	} else if (bf->bf_nseg == 0) {		/* null packet, discard */
 		sc->sc_stats.ast_tx_nodata++;
-		m_freem(m0);
+		ath_freetx(m0);
 		return EIO;
 	}
 	DPRINTF(sc, ATH_DEBUG_XMIT, "%s: m %p len %u\n", __func__, m0, pktlen);
@@ -3805,7 +3893,7 @@
 		if_printf(ifp, "bogus frame type 0x%x (%s)\n",
 			wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK, __func__);
 		/* XXX statistic */
-		m_freem(m0);
+		ath_freetx(m0);
 		return EIO;
 	}
 	txq = sc->sc_ac2q[pri];
@@ -3846,7 +3934,17 @@
 			flags |= HAL_TXDESC_RTSENA;
 		else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
 			flags |= HAL_TXDESC_CTSENA;
-		cix = rt->info[sc->sc_protrix].controlRate;
+		if (isfrag) {
+			/*
+			 * For frags it would be desirable to use the
+			 * highest CCK rate for RTS/CTS.  But stations
+			 * farther away may detect it at a lower CCK rate
+			 * so use the configured protection rate instead
+			 * (for now).
+			 */
+			cix = rt->info[sc->sc_protrix].controlRate;
+		} else
+			cix = rt->info[sc->sc_protrix].controlRate;
 		sc->sc_stats.ast_tx_protect++;
 	}
 
@@ -3857,13 +3955,30 @@
 	if ((flags & HAL_TXDESC_NOACK) == 0 &&
 	    (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL) {
 		u_int16_t dur;
-		/*
-		 * XXX not right with fragmentation.
-		 */
 		if (shortPreamble)
 			dur = rt->info[rix].spAckDuration;
 		else
 			dur = rt->info[rix].lpAckDuration;
+		if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG) {
+			dur += dur;		/* additional SIFS+ACK */
+			KASSERT(m0->m_nextpkt != NULL, ("no fragment"));
+			/*
+			 * Include the size of next fragment so NAV is
+			 * updated properly.  The last fragment uses only
+			 * the ACK duration
+			 */
+			dur += ath_hal_computetxtime(ah, rt,
+					m0->m_nextpkt->m_pkthdr.len,
+					rix, shortPreamble);
+		}
+		if (isfrag) {
+			/*
+			 * Force hardware to use computed duration for next
+			 * fragment by disabling multi-rate retry which updates
+			 * duration based on the multi-rate duration table.
+			 */
+			try0 = ATH_TXMAXTRY;
+		}
 		*(u_int16_t *)wh->i_dur = htole16(dur);
 	}
 
@@ -3922,6 +4037,8 @@
 		sc->sc_tx_th.wt_flags = sc->sc_hwmap[txrate].txflags;
 		if (iswep)
 			sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP;
+		if (isfrag)
+			sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_FRAG;
 		sc->sc_tx_th.wt_rate = sc->sc_hwmap[txrate].ieeerate;
 		sc->sc_tx_th.wt_txpower = ni->ni_txpower;
 		sc->sc_tx_th.wt_antenna = sc->sc_txantenna;

==== //depot/projects/wifi/sys/net80211/ieee80211.h#10 (text+ko) ====

@@ -635,11 +635,19 @@
 
 /* 
  * RTS frame length parameters.  The default is specified in
- * the 802.11 spec.  The max may be wrong for jumbo frames.
+ * the 802.11 spec as 5212; we treat it as implementation-dependent
+ * so it's defined in ieee80211_var.h.  The max may be wrong
+ * for jumbo frames.
  */
-#define	IEEE80211_RTS_DEFAULT		512
 #define	IEEE80211_RTS_MIN		1
-#define	IEEE80211_RTS_MAX		IEEE80211_MAX_LEN
+#define	IEEE80211_RTS_MAX		2346
+
+/* 
+ * TX fragmentation parameters.  As above for RTS, we treat
+ * default as implementation-dependent so define it elsewhere.
+ */
+#define	IEEE80211_FRAG_MIN		256
+#define	IEEE80211_FRAG_MAX		2346
 
 /*
  * Atheros fast-frame encapsulation format.

==== //depot/projects/wifi/sys/net80211/ieee80211_ioctl.c#43 (text+ko) ====

@@ -846,6 +846,9 @@
 	case IEEE80211_IOC_MCAST_RATE:
 		ireq->i_val = ic->ic_mcast_rate;
 		break;
+	case IEEE80211_IOC_FRAGTHRESHOLD:
+		ireq->i_val = ic->ic_fragthreshold;
+		break;
 	default:
 		error = EINVAL;
 		break;
@@ -1608,8 +1611,8 @@
 		error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
 		break;
 	case IEEE80211_IOC_RTSTHRESHOLD:
-		if (!(IEEE80211_RTS_MIN < ireq->i_val &&
-		      ireq->i_val < IEEE80211_RTS_MAX))
+		if (!(IEEE80211_RTS_MIN <= ireq->i_val &&
+		      ireq->i_val <= IEEE80211_RTS_MAX))
 			return EINVAL;
 		ic->ic_rtsthreshold = ireq->i_val;
 		error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
@@ -1626,8 +1629,8 @@
 	case IEEE80211_IOC_TXPOWER:
 		if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
 			return EINVAL;
-		if (!(IEEE80211_TXPOWER_MIN < ireq->i_val &&
-		      ireq->i_val < IEEE80211_TXPOWER_MAX))
+		if (!(IEEE80211_TXPOWER_MIN <= ireq->i_val &&
+		      ireq->i_val <= IEEE80211_TXPOWER_MAX))
 			return EINVAL;
 		ic->ic_txpowlimit = ireq->i_val;
 		error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
@@ -1911,6 +1914,16 @@
 	case IEEE80211_IOC_MCAST_RATE:
 		ic->ic_mcast_rate = ireq->i_val & IEEE80211_RATE_VAL;
 		break;
+	case IEEE80211_IOC_FRAGTHRESHOLD:
+		if ((ic->ic_caps & IEEE80211_C_TXFRAG) == 0 &&
+		    ireq->i_val != IEEE80211_FRAG_MAX)
+			return EINVAL;
+		if (!(IEEE80211_FRAG_MIN <= ireq->i_val &&
+		      ireq->i_val <= IEEE80211_FRAG_MAX))
+			return EINVAL;
+		ic->ic_fragthreshold = ireq->i_val;
+		error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
+		break;
 	default:
 		error = EINVAL;
 		break;

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

@@ -149,6 +149,8 @@
 	u_int32_t	is_tx_badcipher;	/* tx failed 'cuz key type */
 	u_int32_t	is_tx_nodefkey;		/* tx failed 'cuz no defkey */
 	u_int32_t	is_tx_noheadroom;	/* tx failed 'cuz no space */
+	u_int32_t	is_tx_fragframes;	/* tx frames fragmented */
+	u_int32_t	is_tx_frags;		/* tx fragments created */
 	u_int32_t	is_scan_active;		/* active scans started */
 	u_int32_t	is_scan_passive;	/* passive scans started */
 	u_int32_t	is_node_timeout;	/* nodes timed out inactivity */
@@ -446,6 +448,7 @@
 #define	IEEE80211_IOC_ROAM_RATE_11B	70	/* tx rate threshold in 11b */
 #define	IEEE80211_IOC_ROAM_RATE_11G	71	/* tx rate threshold in 11g */
 #define	IEEE80211_IOC_MCAST_RATE	72	/* tx rate for mcast frames */
+#define	IEEE80211_IOC_FRAGTHRESHOLD	73	/* tx fragmentation threshold */
 
 /*
  * Scan result data returned for IEEE80211_IOC_SCAN_RESULTS.

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

@@ -62,6 +62,8 @@
 static struct mbuf *ieee80211_encap_fastframe(struct ieee80211com *ic,
 	struct mbuf *m1, const struct ether_header *eh1,
 	struct mbuf *m2, const struct ether_header *eh2);
+static int ieee80211_fragment(struct ieee80211com *, struct mbuf *,
+	u_int hdrsize, u_int ciphdrsize, u_int mtu);
 
 #ifdef IEEE80211_DEBUG
 /*
@@ -484,7 +486,7 @@
 	struct ieee80211_frame *wh;
 	struct ieee80211_key *key;
 	struct llc *llc;
-	int hdrsize, datalen, addqos;
+	int hdrsize, datalen, addqos, txfrag;
 
 	/*
 	 * Copy existing Ethernet header to a safe place.  The
@@ -666,6 +668,10 @@
 		    htole16(ni->ni_txseqs[0] << IEEE80211_SEQ_SEQ_SHIFT);
 		ni->ni_txseqs[0]++;
 	}
+	/* check if xmit fragmentation is required */
+	txfrag = (m->m_pkthdr.len > ic->ic_fragthreshold &&
+	    !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
+	    (m->m_flags & M_FF) == 0);		/* NB: don't fragment ff's */
 	if (key != NULL) {
 		/*
 		 * IEEE 802.1X: send EAPOL frames always in the clear.
@@ -676,8 +682,7 @@
 		     (ic->ic_opmode == IEEE80211_M_STA ?
 		      !KEY_UNDEFINED(*key) : !KEY_UNDEFINED(ni->ni_ucastkey)))) {
 			wh->i_fc[1] |= IEEE80211_FC1_WEP;
-			/* XXX do fragmentation */
-			if (!ieee80211_crypto_enmic(ic, key, m, 0)) {
+			if (!ieee80211_crypto_enmic(ic, key, m, txfrag)) {
 				IEEE80211_DPRINTF(ic, IEEE80211_MSG_OUTPUT,
 				    "[%s] enmic failed, discard frame\n",
 				    ether_sprintf(eh.ether_dhost));
@@ -686,6 +691,9 @@
 			}
 		}
 	}
+	if (txfrag && !ieee80211_fragment(ic, m, hdrsize,
+	    key != NULL ? key->wk_cipher->ic_header : 0, ic->ic_fragthreshold))
+		goto bad;
 
 	IEEE80211_NODE_STAT(ni, tx_data);
 	IEEE80211_NODE_STAT_ADD(ni, tx_bytes, datalen);
@@ -827,6 +835,98 @@
 }
 
 /*
+ * Fragment the frame according to the specified mtu.
+ * The size of the 802.11 header (w/o padding) is provided
+ * so we don't need to recalculate it.  We create a new
+ * mbuf for each fragment and chain it through m_nextpkt;
+ * we might be able to optimize this by reusing the original
+ * packet's mbufs but that is significantly more complicated.
+ */
+static int
+ieee80211_fragment(struct ieee80211com *ic, struct mbuf *m0,
+	u_int hdrsize, u_int ciphdrsize, u_int mtu)
+{
+	struct ieee80211_frame *wh, *whf;
+	struct mbuf *m, *prev, *next;
+	u_int totalhdrsize, fragno, fragsize, off, remainder, payload;
+
+	KASSERT(m0->m_nextpkt == NULL, ("mbuf already chained?"));
+	KASSERT(m0->m_pkthdr.len > mtu,
+		("pktlen %u mtu %u", m0->m_pkthdr.len, mtu));
+
+	wh = mtod(m0, struct ieee80211_frame *);
+	/* NB: mark the first frag; it will be propagated below */
+	wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG;
+	totalhdrsize = hdrsize + ciphdrsize;
+	fragno = 1;
+	off = mtu - ciphdrsize;
+	remainder = m0->m_pkthdr.len - off;
+	prev = m0;
+	do {
+		fragsize = totalhdrsize + remainder;
+		if (fragsize > mtu)
+			fragsize = mtu;
+		KASSERT(fragsize < MCLBYTES,
+			("fragment size %u too big!", fragsize));
+		if (fragsize > MHLEN)
+			m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+		else
+			m = m_gethdr(M_DONTWAIT, MT_DATA);
+		if (m == NULL)
+			goto bad;
+		/* leave room to prepend any cipher header */
+		m_align(m, fragsize - ciphdrsize);
+
+		/*
+		 * Form the header in the fragment.  Note that since
+		 * we mark the first fragment with the MORE_FRAG bit
+		 * it automatically is propagated to each fragment; we
+		 * need only clear it on the last fragment (done below).
+		 */
+		whf = mtod(m, struct ieee80211_frame *);
+		memcpy(whf, wh, hdrsize);
+		*(u_int16_t *)&whf->i_seq[0] |= htole16(
+			(fragno & IEEE80211_SEQ_FRAG_MASK) <<
+				IEEE80211_SEQ_FRAG_SHIFT);
+		fragno++;
+
+		payload = fragsize - totalhdrsize;
+		/* NB: destination is known to be contiguous */
+		m_copydata(m0, off, payload, mtod(m, u_int8_t *) + hdrsize);
+		m->m_len = hdrsize + payload;
+		m->m_pkthdr.len = hdrsize + payload;
+		m->m_flags |= M_FRAG;
+
+		/* chain up the fragment */
+		prev->m_nextpkt = m;
+		prev = m;
+
+		/* deduct fragment just formed */
+		remainder -= payload;
+		off += payload;
+	} while (remainder != 0);
+	whf->i_fc[1] &= ~IEEE80211_FC1_MORE_FRAG;
+
+	/* strip first mbuf now that everything has been copied */
+	m_adj(m0, -(m0->m_pkthdr.len - (mtu - ciphdrsize)));
+	m0->m_flags |= M_FIRSTFRAG | M_FRAG;
+
+	ic->ic_stats.is_tx_fragframes++;
+	ic->ic_stats.is_tx_frags += fragno-1;
+
+	return 1;
+bad:
+	/* reclaim fragments but leave original frame for caller to free */
+	for (m = m0->m_nextpkt; m != NULL; m = next) {
+		next = m->m_nextpkt;
+		m->m_nextpkt = NULL;		/* XXX paranoid */
+		m_freem(m);
+	}
+	m0->m_nextpkt = NULL;
+	return 0;
+}
+
+/*
  * Add a supported rates element id to a frame.
  */
 static u_int8_t *

==== //depot/projects/wifi/sys/net80211/ieee80211_proto.c#30 (text+ko) ====

@@ -94,12 +94,8 @@
 	/* XXX room for crypto  */
 	ifp->if_hdrlen = sizeof(struct ieee80211_qosframe_addr4);
 
-#ifdef notdef
 	ic->ic_rtsthreshold = IEEE80211_RTS_DEFAULT;
-#else
-	ic->ic_rtsthreshold = IEEE80211_RTS_MAX;
-#endif
-	ic->ic_fragthreshold = 2346;		/* XXX not used yet */
+	ic->ic_fragthreshold = IEEE80211_FRAG_DEFAULT;
 	ic->ic_fixed_rate = IEEE80211_FIXED_RATE_NONE;
 	ic->ic_mcast_rate = IEEE80211_MCAST_RATE_DEFAULT;
 	ic->ic_protmode = IEEE80211_PROT_CTSONLY;

==== //depot/projects/wifi/sys/net80211/ieee80211_var.h#30 (text+ko) ====

@@ -83,6 +83,9 @@
 #define	IEEE80211_FIXED_RATE_NONE	-1
 #define	IEEE80211_MCAST_RATE_DEFAULT	(2*1)	/* default mcast rate (1M) */
 
+#define	IEEE80211_RTS_DEFAULT		IEEE80211_RTS_MAX
+#define	IEEE80211_FRAG_DEFAULT		IEEE80211_FRAG_MAX
+
 #define	IEEE80211_MS_TO_TU(x)	(((x) * 1000) / 1024)
 #define	IEEE80211_TU_TO_MS(x)	(((x) * 1024) / 1000)
 
@@ -306,7 +309,9 @@
 #define	IEEE80211_C_BURST	0x02000000	/* CAPABILITY: frame bursting */
 #define	IEEE80211_C_WME		0x04000000	/* CAPABILITY: WME avail */
 #define	IEEE80211_C_WDS		0x08000000	/* CAPABILITY: 4-addr support */
+/* 0x10000000 reserved */
 #define	IEEE80211_C_BGSCAN	0x20000000	/* CAPABILITY: bg scanning */
+#define	IEEE80211_C_TXFRAG	0x40000000	/* CAPABILITY: tx fragments */
 /* XXX protection/barker? */
 
 #define	IEEE80211_C_CRYPTO	0x0000002f	/* CAPABILITY: crypto alg's */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200507192202.j6JM2Mll092960>