From owner-p4-projects@FreeBSD.ORG Tue Jul 19 22:02:23 2005 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 13A4416A421; Tue, 19 Jul 2005 22:02:23 +0000 (GMT) X-Original-To: perforce@freebsd.org Delivered-To: perforce@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id BECBA16A41F for ; Tue, 19 Jul 2005 22:02:22 +0000 (GMT) (envelope-from sam@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id 7512F43D45 for ; Tue, 19 Jul 2005 22:02:22 +0000 (GMT) (envelope-from sam@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.1/8.13.1) with ESMTP id j6JM2M1K092964 for ; Tue, 19 Jul 2005 22:02:22 GMT (envelope-from sam@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.1/8.13.1/Submit) id j6JM2Mll092960 for perforce@freebsd.org; Tue, 19 Jul 2005 22:02:22 GMT (envelope-from sam@freebsd.org) Date: Tue, 19 Jul 2005 22:02:22 GMT Message-Id: <200507192202.j6JM2Mll092960@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to sam@freebsd.org using -f From: Sam Leffler To: Perforce Change Reviews Cc: Subject: PERFORCE change 80556 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 19 Jul 2005 22:02:24 -0000 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 */