PERFORCE change 80556 for review
Sam Leffler
sam at FreeBSD.org
Tue Jul 19 22:02:24 GMT 2005
http://perforce.freebsd.org/chv.cgi?CH=80556
Change 80556 by sam at 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 */
More information about the p4-projects
mailing list