From owner-p4-projects@FreeBSD.ORG Wed May 9 16:30:20 2007 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 C9A1716A405; Wed, 9 May 2007 16:30:19 +0000 (UTC) X-Original-To: perforce@freebsd.org Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 568A516A400 for ; Wed, 9 May 2007 16:30:19 +0000 (UTC) (envelope-from sam@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [69.147.83.41]) by mx1.freebsd.org (Postfix) with ESMTP id 44E7813C447 for ; Wed, 9 May 2007 16:30:19 +0000 (UTC) (envelope-from sam@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.8/8.13.8) with ESMTP id l49GUJbl001646 for ; Wed, 9 May 2007 16:30:19 GMT (envelope-from sam@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.8/8.13.8/Submit) id l49GUIWp001642 for perforce@freebsd.org; Wed, 9 May 2007 16:30:18 GMT (envelope-from sam@freebsd.org) Date: Wed, 9 May 2007 16:30:18 GMT Message-Id: <200705091630.l49GUIWp001642@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 119566 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: Wed, 09 May 2007 16:30:20 -0000 http://perforce.freebsd.org/chv.cgi?CH=119566 Change 119566 by sam@sam_ebb on 2007/05/09 16:30:02 Minimal 802.11n support; mostly tested in ap mode, sta mode is known to be incomplete; a-msdu is untested; a-mpdu is known to work but BAR handling needs fixups. This grows per-sta state significantly; we may want to make support conditional. This work is derived from code provided by Atheros. Sponsored by: Marvelle Reviewed by: sephe Affected files ... .. //depot/projects/wifi/sys/net80211/_ieee80211.h#19 edit .. //depot/projects/wifi/sys/net80211/ieee80211.c#51 edit .. //depot/projects/wifi/sys/net80211/ieee80211.h#20 edit .. //depot/projects/wifi/sys/net80211/ieee80211_freebsd.h#26 edit .. //depot/projects/wifi/sys/net80211/ieee80211_ht.c#1 add .. //depot/projects/wifi/sys/net80211/ieee80211_ht.h#1 add .. //depot/projects/wifi/sys/net80211/ieee80211_input.c#102 edit .. //depot/projects/wifi/sys/net80211/ieee80211_ioctl.c#77 edit .. //depot/projects/wifi/sys/net80211/ieee80211_ioctl.h#38 edit .. //depot/projects/wifi/sys/net80211/ieee80211_node.c#92 edit .. //depot/projects/wifi/sys/net80211/ieee80211_node.h#44 edit .. //depot/projects/wifi/sys/net80211/ieee80211_output.c#73 edit .. //depot/projects/wifi/sys/net80211/ieee80211_proto.c#55 edit .. //depot/projects/wifi/sys/net80211/ieee80211_proto.h#35 edit .. //depot/projects/wifi/sys/net80211/ieee80211_radiotap.h#10 edit .. //depot/projects/wifi/sys/net80211/ieee80211_regdomain.c#3 edit .. //depot/projects/wifi/sys/net80211/ieee80211_regdomain.h#2 edit .. //depot/projects/wifi/sys/net80211/ieee80211_scan.c#12 edit .. //depot/projects/wifi/sys/net80211/ieee80211_scan.h#7 edit .. //depot/projects/wifi/sys/net80211/ieee80211_scan_ap.c#6 edit .. //depot/projects/wifi/sys/net80211/ieee80211_scan_sta.c#18 edit .. //depot/projects/wifi/sys/net80211/ieee80211_var.h#56 edit Differences ... ==== //depot/projects/wifi/sys/net80211/_ieee80211.h#19 (text+ko) ==== @@ -29,7 +29,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/sys/net80211/_ieee80211.h,v 1.8 2007/03/07 04:35:07 sam Exp $ + * $FreeBSD: src/sys/net80211/_ieee80211.h,v 1.7 2007/02/02 02:45:33 sam Exp $ */ #ifndef _NET80211__IEEE80211_H_ #define _NET80211__IEEE80211_H_ @@ -39,6 +39,7 @@ IEEE80211_T_FH, /* frequency hopping */ IEEE80211_T_OFDM, /* frequency division multiplexing */ IEEE80211_T_TURBO, /* high rate OFDM, aka turbo mode */ + IEEE80211_T_HT, /* high throughput, full GI */ }; #define IEEE80211_T_CCK IEEE80211_T_DS /* more common nomenclature */ @@ -52,8 +53,10 @@ IEEE80211_MODE_TURBO_A = 5, /* 5GHz, OFDM, 2x clock */ IEEE80211_MODE_TURBO_G = 6, /* 2GHz, OFDM, 2x clock */ IEEE80211_MODE_STURBO_A = 7, /* 5GHz, OFDM, 2x clock, static */ + IEEE80211_MODE_11NA = 8, /* 5GHz, w/ HT */ + IEEE80211_MODE_11NG = 9, /* 2GHz, w/ HT */ }; -#define IEEE80211_MODE_MAX (IEEE80211_MODE_STURBO_A+1) +#define IEEE80211_MODE_MAX (IEEE80211_MODE_11NG+1) enum ieee80211_opmode { IEEE80211_M_STA = 1, /* infrastructure station */ @@ -66,7 +69,7 @@ #define IEEE80211_OPMODE_MAX (IEEE80211_M_MONITOR+1) /* - * 802.11g protection mode. + * 802.11g/802.11n protection mode. */ enum ieee80211_protmode { IEEE80211_PROT_NONE = 0, /* no protection */ @@ -135,7 +138,13 @@ #define IEEE80211_CHAN_STURBO 0x02000 /* 11a static turbo channel only */ #define IEEE80211_CHAN_HALF 0x04000 /* Half rate channel */ #define IEEE80211_CHAN_QUARTER 0x08000 /* Quarter rate channel */ +#define IEEE80211_CHAN_HT20 0x10000 /* HT 20 channel */ +#define IEEE80211_CHAN_HT40U 0x20000 /* HT 40 channel w/ ext above */ +#define IEEE80211_CHAN_HT40D 0x40000 /* HT 40 channel w/ ext below */ +#define IEEE80211_CHAN_HT40 (IEEE80211_CHAN_HT40U | IEEE80211_CHAN_HT40D) +#define IEEE80211_CHAN_HT (IEEE80211_CHAN_HT20 | IEEE80211_CHAN_HT40) + /* * Useful combinations of channel characteristics. */ @@ -158,7 +167,8 @@ #define IEEE80211_CHAN_ALL \ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_GFSK | \ - IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_DYN) + IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_DYN | \ + IEEE80211_CHAN_HT) #define IEEE80211_CHAN_ALLTURBO \ (IEEE80211_CHAN_ALL | IEEE80211_CHAN_TURBO | IEEE80211_CHAN_STURBO) @@ -208,6 +218,22 @@ (((_c)->ic_flags & (IEEE80211_CHAN_QUARTER | IEEE80211_CHAN_HALF)) == 0) #define IEEE80211_IS_CHAN_GSM(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_GSM) != 0) +#define IEEE80211_IS_CHAN_HT(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HT) != 0) +#define IEEE80211_IS_CHAN_HT20(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HT20) != 0) +#define IEEE80211_IS_CHAN_HT40(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HT40) != 0) +#define IEEE80211_IS_CHAN_HT40U(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HT40U) != 0) +#define IEEE80211_IS_CHAN_HT40D(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HT40D) != 0) +#define IEEE80211_IS_CHAN_HTA(_c) \ + (IEEE80211_IS_CHAN_5GHZ(_c) && \ + ((_c)->ic_flags & IEEE80211_CHAN_HT) != 0) +#define IEEE80211_IS_CHAN_HTG(_c) \ + (IEEE80211_IS_CHAN_2GHZ(_c) && \ + ((_c)->ic_flags & IEEE80211_CHAN_HT) != 0) /* ni_chan encoding for FH phy */ #define IEEE80211_FH_CHANMOD 80 @@ -226,6 +252,26 @@ u_int8_t rs_rates[IEEE80211_RATE_MAXSIZE]; }; +/* + * 802.11n variant of ieee80211_rateset. Instead + * legacy rates the entries are MCS rates. We define + * the structure such that it can be used interchangeably + * with an ieee80211_rateset (modulo structure size). + */ +#define IEEE80211_HTRATE_MAXSIZE 127 + +struct ieee80211_htrateset { + u_int8_t rs_nrates; + u_int8_t rs_rates[IEEE80211_HTRATE_MAXSIZE]; +}; + +/* + * Roaming state visible to user space. There are two + * thresholds that control whether roaming is considered; + * when either is exceeded the 802.11 layer will check + * the scan cache for another AP. If the cache is stale + * then a scan may be triggered. + */ struct ieee80211_roam { int8_t rssi11a; /* rssi thresh for 11a bss */ int8_t rssi11b; /* for 11g sta in 11b bss */ ==== //depot/projects/wifi/sys/net80211/ieee80211.c#51 (text+ko) ==== @@ -60,6 +60,8 @@ "turboA", /* IEEE80211_MODE_TURBO_A */ "turboG", /* IEEE80211_MODE_TURBO_G */ "sturboA", /* IEEE80211_MODE_STURBO_A */ + "11na", /* IEEE80211_MODE_11NA */ + "11ng", /* IEEE80211_MODE_11NG */ }; /* @@ -181,6 +183,10 @@ setbit(ic->ic_modecaps, IEEE80211_MODE_TURBO_G); if (IEEE80211_IS_CHAN_ST(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_STURBO_A); + if (IEEE80211_IS_CHAN_HTA(c)) + setbit(ic->ic_modecaps, IEEE80211_MODE_11NA); + if (IEEE80211_IS_CHAN_HTG(c)) + setbit(ic->ic_modecaps, IEEE80211_MODE_11NG); } /* initialize candidate channels to all available */ memcpy(ic->ic_chan_active, ic->ic_chan_avail, @@ -216,6 +222,19 @@ bpfattach2(ifp, DLT_IEEE802_11, sizeof(struct ieee80211_frame_addr4), &ic->ic_rawbpf); + /* override the 802.3 setting */ + ifp->if_hdrlen = ic->ic_headroom + + sizeof(struct ieee80211_qosframe_addr4) + + IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + + IEEE80211_WEP_EXTIVLEN; + /* XXX no way to recalculate on ifdetach */ + if (ALIGN(ifp->if_hdrlen) > max_linkhdr) { + /* XXX sanity check... */ + max_linkhdr = ALIGN(ifp->if_hdrlen); + max_hdr = max_linkhdr + max_protohdr; + max_datalen = MHLEN - max_hdr; + } + /* * Fill in 802.11 available channel set, mark all * available channels as active, and pick a default @@ -232,6 +251,7 @@ #endif if (ic->ic_caps & IEEE80211_C_BURST) ic->ic_flags |= IEEE80211_F_BURST; + ic->ic_flags |= IEEE80211_F_DOTH; /* XXX out of caps, just ena */ ic->ic_bintval = IEEE80211_BINTVAL_DEFAULT; ic->ic_bmissthreshold = IEEE80211_HWBMISS_DEFAULT; @@ -246,6 +266,7 @@ ieee80211_node_attach(ic); ieee80211_power_attach(ic); ieee80211_proto_attach(ic); + ieee80211_ht_attach(ic); ieee80211_scan_attach(ic); ieee80211_add_vap(ic); @@ -272,6 +293,7 @@ ieee80211_sysctl_detach(ic); ieee80211_scan_detach(ic); + ieee80211_ht_detach(ic); /* NB: must be called before ieee80211_node_detach */ ieee80211_proto_detach(ic); ieee80211_crypto_detach(ic); @@ -439,6 +461,8 @@ TURBO(IFM_IEEE80211_11A), /* IEEE80211_MODE_TURBO_A */ TURBO(IFM_IEEE80211_11G), /* IEEE80211_MODE_TURBO_G */ TURBO(IFM_IEEE80211_11A), /* IEEE80211_MODE_STURBO_A */ + IFM_IEEE80211_11NA, /* IEEE80211_MODE_11NA */ + IFM_IEEE80211_11NG, /* IEEE80211_MODE_11NG */ }; u_int mopt; @@ -501,7 +525,7 @@ * Add media for legacy operating modes. */ memset(&allrates, 0, sizeof(allrates)); - for (mode = IEEE80211_MODE_AUTO; mode < IEEE80211_MODE_MAX; mode++) { + for (mode = IEEE80211_MODE_AUTO; mode < IEEE80211_MODE_11NA; mode++) { if (isclr(ic->ic_modecaps, mode)) continue; addmedia(ic, mode, IFM_AUTO); @@ -539,6 +563,27 @@ /* NB: remove media options from mword */ addmedia(ic, IEEE80211_MODE_AUTO, IFM_SUBTYPE(mword)); } + /* + * Add HT/11n media. Note that we do not have enough + * bits in the media subtype to express the MCS so we + * use a "placeholder" media subtype and any fixed MCS + * must be specified with a different mechanism. + */ + for (; mode < IEEE80211_MODE_MAX; mode++) { + if (isclr(ic->ic_modecaps, mode)) + continue; + addmedia(ic, mode, IFM_AUTO); + addmedia(ic, mode, IFM_IEEE80211_MCS); + } + if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA) || + isset(ic->ic_modecaps, IEEE80211_MODE_11NG)) { + addmedia(ic, IEEE80211_MODE_AUTO, IFM_IEEE80211_MCS); + /* XXX could walk htrates */ + /* XXX known array size */ + if (ieee80211_htrates[15] > maxrate) + maxrate = ieee80211_htrates[15]; + } + /* NB: strip explicit mode; we're actually in autoselect */ ifmedia_set(&ic->ic_media, media_status(ic->ic_opmode, ic->ic_curchan) &~ IFM_MMASK); @@ -554,6 +599,12 @@ return &ieee80211_rateset_half; if (IEEE80211_IS_CHAN_QUARTER(c)) return &ieee80211_rateset_quarter; + if (IEEE80211_IS_CHAN_HTA(c)) + return &ic->ic_sup_rates[IEEE80211_MODE_11A]; + if (IEEE80211_IS_CHAN_HTG(c)) { + /* XXX does this work for basic rates? */ + return &ic->ic_sup_rates[IEEE80211_MODE_11G]; + } return &ic->ic_sup_rates[ieee80211_chan2mode(c)]; } @@ -564,7 +615,7 @@ int i, mode, rate, mword; const struct ieee80211_rateset *rs; - for (mode = IEEE80211_MODE_11A; mode < IEEE80211_MODE_MAX; mode++) { + for (mode = IEEE80211_MODE_AUTO; mode < IEEE80211_MODE_11NA; mode++) { if (isclr(ic->ic_modecaps, mode)) continue; if_printf(ifp, "%s rates: ", ieee80211_phymode_name[mode]); @@ -579,6 +630,7 @@ } printf("\n"); } + ieee80211_ht_announce(ic); } void @@ -597,6 +649,8 @@ type = 'T'; else if (IEEE80211_IS_CHAN_108G(c)) type = 'G'; + else if (IEEE80211_IS_CHAN_HT(c)) + type = 'n'; else if (IEEE80211_IS_CHAN_A(c)) type = 'a'; else if (IEEE80211_IS_CHAN_ANYG(c)) @@ -605,15 +659,19 @@ type = 'b'; else type = 'f'; - if (IEEE80211_IS_CHAN_HALF(c)) + if (IEEE80211_IS_CHAN_HT40(c) || IEEE80211_IS_CHAN_TURBO(c)) + cw = 40; + else if (IEEE80211_IS_CHAN_HALF(c)) cw = 10; else if (IEEE80211_IS_CHAN_QUARTER(c)) cw = 5; else cw = 20; - printf("%4d %4d%c %2d %6d %4d.%d %4d.%d\n" + printf("%4d %4d%c %2d%c %6d %4d.%d %4d.%d\n" , c->ic_ieee, c->ic_freq, type , cw + , IEEE80211_IS_CHAN_HT40U(c) ? '+' : + IEEE80211_IS_CHAN_HT40D(c) ? '-' : ' ' , c->ic_maxregpower , c->ic_minpower / 2, c->ic_minpower & 1 ? 5 : 0 , c->ic_maxpower / 2, c->ic_maxpower & 1 ? 5 : 0 @@ -727,6 +785,12 @@ case IFM_IEEE80211_FH: newphymode = IEEE80211_MODE_FH; break; + case IFM_IEEE80211_11NA: + newphymode = IEEE80211_MODE_11NA; + break; + case IFM_IEEE80211_11NG: + newphymode = IEEE80211_MODE_11NG; + break; case IFM_AUTO: newphymode = IEEE80211_MODE_AUTO; break; @@ -748,6 +812,7 @@ else return EINVAL; } + /* XXX HT40 +/- */ /* * Next, the fixed/variable rate. */ @@ -855,21 +920,28 @@ /* should not come here */ break; } - if (IEEE80211_IS_CHAN_A(chan)) { + if (IEEE80211_IS_CHAN_HTA(chan)) { + status |= IFM_IEEE80211_11NA; + } else if (IEEE80211_IS_CHAN_HTG(chan)) { + status |= IFM_IEEE80211_11NG; + } else if (IEEE80211_IS_CHAN_A(chan)) { status |= IFM_IEEE80211_11A; - if (IEEE80211_IS_CHAN_TURBO(chan)) - status |= IFM_IEEE80211_TURBO; } else if (IEEE80211_IS_CHAN_B(chan)) { status |= IFM_IEEE80211_11B; } else if (IEEE80211_IS_CHAN_ANYG(chan)) { status |= IFM_IEEE80211_11G; - if (IEEE80211_IS_CHAN_TURBO(chan)) - status |= IFM_IEEE80211_TURBO; } else if (IEEE80211_IS_CHAN_FHSS(chan)) { status |= IFM_IEEE80211_FH; } /* XXX else complain? */ + if (IEEE80211_IS_CHAN_TURBO(chan)) + status |= IFM_IEEE80211_TURBO; + if (IEEE80211_IS_CHAN_HT40U(chan)) + status |= IFM_IEEE80211_HT40PLUS; + if (IEEE80211_IS_CHAN_HT40D(chan)) + status |= IFM_IEEE80211_HT40MINUS; + return status; } @@ -909,6 +981,7 @@ } else if (ic->ic_opmode == IEEE80211_M_STA) { /* * In station mode report the current transmit rate. + * XXX HT rate */ rs = &ic->ic_bss->ni_rates; imr->ifm_active |= ieee80211_rate2media(ic, @@ -949,7 +1022,11 @@ ieee80211_chan2mode(const struct ieee80211_channel *chan) { - if (IEEE80211_IS_CHAN_108G(chan)) + if (IEEE80211_IS_CHAN_HTA(chan)) + return IEEE80211_MODE_11NA; + else if (IEEE80211_IS_CHAN_HTG(chan)) + return IEEE80211_MODE_11NG; + else if (IEEE80211_IS_CHAN_108G(chan)) return IEEE80211_MODE_TURBO_G; else if (IEEE80211_IS_CHAN_ST(chan)) return IEEE80211_MODE_STURBO_A; @@ -988,7 +1065,8 @@ /* * Convert IEEE80211 rate value to ifmedia subtype. - * Rate is a legacy rate in units of 0.5Mbps. + * Rate is either a legacy rate in units of 0.5Mbps + * or an MCS index. */ int ieee80211_rate2media(struct ieee80211com *ic, int rate, enum ieee80211_phymode mode) @@ -1027,10 +1105,47 @@ { 54 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM27 }, /* NB: OFDM72 doesn't realy exist so we don't handle it */ }; + static const struct ratemedia htrates[] = { + { 0, IFM_IEEE80211_MCS }, + { 1, IFM_IEEE80211_MCS }, + { 2, IFM_IEEE80211_MCS }, + { 3, IFM_IEEE80211_MCS }, + { 4, IFM_IEEE80211_MCS }, + { 5, IFM_IEEE80211_MCS }, + { 6, IFM_IEEE80211_MCS }, + { 7, IFM_IEEE80211_MCS }, + { 8, IFM_IEEE80211_MCS }, + { 9, IFM_IEEE80211_MCS }, + { 10, IFM_IEEE80211_MCS }, + { 11, IFM_IEEE80211_MCS }, + { 12, IFM_IEEE80211_MCS }, + { 13, IFM_IEEE80211_MCS }, + { 14, IFM_IEEE80211_MCS }, + { 15, IFM_IEEE80211_MCS }, + }; + int m; + /* + * Check 11n rates first for match as an MCS. + */ + if (mode == IEEE80211_MODE_11NA) { + if ((rate & IEEE80211_RATE_BASIC) == 0) { + m = findmedia(htrates, N(htrates), rate); + if (m != IFM_AUTO) + return m | IFM_IEEE80211_11NA; + } + } else if (mode == IEEE80211_MODE_11NG) { + /* NB: 12 is ambiguous, it will be treated as an MCS */ + if ((rate & IEEE80211_RATE_BASIC) == 0) { + m = findmedia(htrates, N(htrates), rate); + if (m != IFM_AUTO) + return m | IFM_IEEE80211_11NG; + } + } rate &= IEEE80211_RATE_VAL; switch (mode) { case IEEE80211_MODE_11A: + case IEEE80211_MODE_11NA: case IEEE80211_MODE_TURBO_A: case IEEE80211_MODE_STURBO_A: return findmedia(rates, N(rates), rate | IFM_IEEE80211_11A); @@ -1046,6 +1161,7 @@ /* NB: hack, 11g matches both 11b+11a rates */ /* fall thru... */ case IEEE80211_MODE_11G: + case IEEE80211_MODE_11NG: case IEEE80211_MODE_TURBO_G: return findmedia(rates, N(rates), rate | IFM_IEEE80211_11G); } @@ -1082,6 +1198,7 @@ 6, /* IFM_IEEE80211_OFDM3 */ 9, /* IFM_IEEE80211_OFDM4 */ 54, /* IFM_IEEE80211_OFDM27 */ + -1, /* IFM_IEEE80211_MCS */ }; return IFM_SUBTYPE(mword) < N(ieeerates) ? ieeerates[IFM_SUBTYPE(mword)] : 0; ==== //depot/projects/wifi/sys/net80211/ieee80211.h#20 (text+ko) ==== ==== //depot/projects/wifi/sys/net80211/ieee80211_freebsd.h#26 (text+ko) ==== @@ -191,6 +191,8 @@ #define M_MORE_DATA M_PROTO5 /* more data frames to follow */ #define M_FF 0x20000 /* fast frame */ #define M_TXCB 0x40000 /* do tx complete callback */ +/* rx path usage */ +#define M_AMPDU M_PROTO5 /* A-MPDU processing done */ /* * Encode WME access control bits in the PROTO flags. * This is safe since it's passed directly in to the ==== //depot/projects/wifi/sys/net80211/ieee80211_input.c#102 (text+ko) ==== @@ -108,10 +108,28 @@ struct ieee80211_key *key; struct ether_header *eh; int hdrspace, need_tap; - u_int8_t dir, type, subtype; + u_int8_t dir, type, subtype, qos; u_int8_t *bssid; u_int16_t rxseq; + if (m->m_flags & M_AMPDU) { + /* + * Fastpath for A-MPDU reorder q resubmission. Frames + * w/ M_AMPDU marked have already passed through here + * but were received out of order and been held on the + * reorder queue. When resubmitted they are marked + * with the M_AMPDU flag and we can bypass most of the + * normal processing. + */ + wh = mtod(m, struct ieee80211_frame *); + type = IEEE80211_FC0_TYPE_DATA; + dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK; + subtype = IEEE80211_FC0_SUBTYPE_QOS; + hdrspace = ieee80211_hdrspace(ic, wh); /* XXX optimize? */ + need_tap = 0; + goto resubmit_ampdu; + } + KASSERT(ni != NULL, ("null node")); ni->ni_inact = ni->ni_inact_reload; @@ -234,7 +252,8 @@ } else tid = IEEE80211_NONQOS_TID; rxseq = le16toh(*(u_int16_t *)wh->i_seq); - if ((wh->i_fc[1] & IEEE80211_FC1_RETRY) && + if ((ni->ni_flags & IEEE80211_NODE_HT) == 0 && + (wh->i_fc[1] & IEEE80211_FC1_RETRY) && SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) { /* duplicate, discard */ IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_INPUT, @@ -328,6 +347,7 @@ /* * Check for power save state change. + * XXX out-of-order A-MPDU frames? */ if (((wh->i_fc[1] & IEEE80211_FC1_PWR_MGT) ^ (ni->ni_flags & IEEE80211_NODE_PWR_MGT))) @@ -340,6 +360,23 @@ } /* + * Handle A-MPDU re-ordering. The station must be + * associated and negotiated HT. The frame must be + * a QoS frame (not QoS null data) and not previously + * processed for A-MPDU re-ordering. If the frame is + * to be processed directly then ieee80211_ampdu_reorder + * will return 0; otherwise it has consumed the mbuf + * and we should do nothing more with it. + */ + if ((ni->ni_flags & IEEE80211_NODE_HT) && + subtype == IEEE80211_FC0_SUBTYPE_QOS && + ieee80211_ampdu_reorder(ni, m) != 0) { + m = NULL; + goto out; + } + resubmit_ampdu: + + /* * Handle privacy requirements. Note that we * must not be preempted from here until after * we (potentially) call ieee80211_crypto_demic; @@ -371,6 +408,16 @@ } /* + * Save QoS bits for use below--before we strip the header. + */ + if (subtype == IEEE80211_FC0_SUBTYPE_QOS) { + qos = (dir == IEEE80211_FC1_DIR_DSTODS) ? + ((struct ieee80211_qosframe_addr4 *)wh)->i_qos[0] : + ((struct ieee80211_qosframe *)wh)->i_qos[0]; + } else + qos = 0; + + /* * Next up, any fragmentation. */ if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { @@ -448,8 +495,13 @@ goto out; } } + /* XXX require HT? */ + if (qos & IEEE80211_QOS_AMSDU) { + m = ieee80211_decap_amsdu(ni, m); + if (m == NULL) + return IEEE80211_FC0_TYPE_DATA; + } else if ((ni->ni_ath_flags & IEEE80211_NODE_FF) && #define FF_LLC_SIZE (sizeof(struct ether_header) + sizeof(struct llc)) - if ((ni->ni_ath_flags & IEEE80211_NODE_FF) && m->m_pkthdr.len >= 3*FF_LLC_SIZE) { struct llc *llc; @@ -547,6 +599,9 @@ case IEEE80211_FC0_SUBTYPE_PS_POLL: ieee80211_recv_pspoll(ic, ni, m); break; + case IEEE80211_FC0_SUBTYPE_BAR: + ieee80211_recv_bar(ni, m); + break; } } goto out; @@ -828,7 +883,7 @@ } /* - * Decap a frame encapsulated in a fast-frame. + * Decap a frame encapsulated in a fast-frame/A-MSDU. */ struct mbuf * ieee80211_decap1(struct mbuf *m, int *framelen) @@ -1438,6 +1493,18 @@ return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI); } +static __inline int +ishtcapoui(const u_int8_t *frm) +{ + return frm[1] > 3 && LE_READ_4(frm+2) == ((BCM_OUI_HTCAP<<24)|BCM_OUI); +} + +static __inline int +ishtinfooui(const u_int8_t *frm) +{ + return frm[1] > 3 && LE_READ_4(frm+2) == ((BCM_OUI_HTINFO<<24)|BCM_OUI); +} + /* * Convert a WPA cipher selector OUI to an internal * cipher algorithm. Where appropriate we also @@ -1986,7 +2053,7 @@ #define ISREASSOC(_st) ((_st) == IEEE80211_FC0_SUBTYPE_REASSOC_RESP) struct ieee80211_frame *wh; u_int8_t *frm, *efrm; - u_int8_t *ssid, *rates, *xrates, *wpa, *rsn, *wme, *ath; + u_int8_t *ssid, *rates, *xrates, *wpa, *rsn, *wme, *ath, *htcap; int reassoc, resp, allocbs; u_int8_t rate; @@ -2025,6 +2092,8 @@ * [tlv] extended supported rates * [tlv] WME * [tlv] WPA or RSN + * [tlv] HT capabilities + * [tlv] HT information * [tlv] Atheros capabilities */ IEEE80211_VERIFY_LENGTH(efrm - frm, 12, return); @@ -2082,9 +2151,15 @@ } scan.erp = frm[2]; break; + case IEEE80211_ELEMID_HTCAP: + scan.htcap = frm; + break; case IEEE80211_ELEMID_RSN: scan.rsn = frm; break; + case IEEE80211_ELEMID_HTINFO: + scan.htinfo = frm; + break; case IEEE80211_ELEMID_VENDOR: if (iswpaoui(frm)) scan.wpa = frm; @@ -2092,6 +2167,19 @@ scan.wme = frm; else if (isatherosoui(frm)) scan.ath = frm; + else if (ic->ic_flags_ext & IEEE80211_FEXT_HTCOMPAT) { + /* + * Accept pre-draft HT ie's if the + * standard ones have not been seen. + */ + if (ishtcapoui(frm)) { + if (scan.htcap == NULL) + scan.htcap = frm; + } else if (ishtinfooui(frm)) { + if (scan.htinfo == NULL) + scan.htcap = frm; + } + } break; default: IEEE80211_DISCARD_IE(ic, IEEE80211_MSG_ELEMID, @@ -2147,6 +2235,25 @@ ic->ic_stats.is_rx_badbintval++; return; } + /* + * Process HT ie's. This is complicated by our + * accepting both the standard ie's and the pre-draft + * vendor OUI ie's that some vendors still use/require. + */ + if (scan.htcap != NULL) { + IEEE80211_VERIFY_LENGTH(scan.htcap[1], + scan.htcap[0] == IEEE80211_ELEMID_VENDOR ? + 4 + sizeof(struct ieee80211_ie_htcap)-2 : + sizeof(struct ieee80211_ie_htcap)-2, + scan.htcap = NULL); + } + if (scan.htinfo != NULL) { + IEEE80211_VERIFY_LENGTH(scan.htinfo[1], + scan.htinfo[0] == IEEE80211_ELEMID_VENDOR ? + 4 + sizeof(struct ieee80211_ie_htinfo)-2 : + sizeof(struct ieee80211_ie_htinfo)-2, + scan.htinfo = NULL); + } /* * Count frame now that we know it's to be processed. @@ -2208,6 +2315,10 @@ ieee80211_wme_updateparams(ic); if (scan.ath != NULL) ieee80211_parse_athparams(ni, scan.ath, wh); + if (scan.htcap != NULL) + ieee80211_parse_htcap(ni, scan.htcap); + if (scan.htinfo != NULL) + ieee80211_parse_htinfo(ni, scan.htinfo); if (scan.tim != NULL) { struct ieee80211_tim_ie *tim = (struct ieee80211_tim_ie *) scan.tim; @@ -2497,6 +2608,7 @@ * [tlv] supported rates * [tlv] extended supported rates * [tlv] WPA or RSN + * [tlv] HT capabilities * [tlv] Atheros capabilities */ IEEE80211_VERIFY_LENGTH(efrm - frm, (reassoc ? 10 : 4), return); @@ -2512,7 +2624,7 @@ lintval = le16toh(*(u_int16_t *)frm); frm += 2; if (reassoc) frm += 6; /* ignore current AP info */ - ssid = rates = xrates = wpa = rsn = wme = ath = NULL; + ssid = rates = xrates = wpa = rsn = wme = ath = htcap = NULL; while (efrm - frm > 1) { IEEE80211_VERIFY_LENGTH(efrm - frm, frm[1] + 2, return); switch (*frm) { @@ -2529,6 +2641,9 @@ case IEEE80211_ELEMID_RSN: rsn = frm; break; + case IEEE80211_ELEMID_HTCAP: + htcap = frm; + break; case IEEE80211_ELEMID_VENDOR: if (iswpaoui(frm)) wpa = frm; @@ -2536,6 +2651,10 @@ wme = frm; else if (isatherosoui(frm)) ath = frm; + else if (ic->ic_flags_ext & IEEE80211_FEXT_HTCOMPAT) { + if (ishtcapoui(frm) && htcap == NULL) + htcap = frm; + } break; } frm += frm[1] + 2; @@ -2546,6 +2665,13 @@ IEEE80211_RATE_MAXSIZE - rates[1]); IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN); IEEE80211_VERIFY_SSID(ic->ic_bss, ssid); + if (htcap != NULL) { + IEEE80211_VERIFY_LENGTH(htcap[1], + htcap[0] == IEEE80211_ELEMID_VENDOR ? + 4 + sizeof(struct ieee80211_ie_htcap)-2 : + sizeof(struct ieee80211_ie_htcap)-2, + return); /* XXX just NULL out? */ + } if (ni == ic->ic_bss) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, @@ -2654,6 +2780,21 @@ ratesetmismatch(ni, wh, reassoc, resp, "11g", rate); return; } + /* XXX enforce PUREN */ + /* 802.11n-specific rateset handling */ + if (IEEE80211_IS_CHAN_HT(ic->ic_curchan) && htcap != NULL) { + rate = ieee80211_setup_htrates(ni, htcap, + IEEE80211_F_DOFRATE | IEEE80211_F_DONEGO | + IEEE80211_F_DOBRS); + if (rate & IEEE80211_RATE_BASIC) { + /* XXX 11n-specific stat */ + ratesetmismatch(ni, wh, reassoc, resp, + "HT", rate); + return; + } + ieee80211_ht_node_init(ni, htcap); + } else if (ni->ni_flags & IEEE80211_NODE_HT) + ieee80211_ht_node_cleanup(ni); ni->ni_rssi = rssi; ni->ni_noise = noise; ni->ni_rstamp = rstamp; @@ -2748,6 +2889,7 @@ * [tlv] supported rates * [tlv] extended supported rates * [tlv] WME + * [tlv] HT capabilities */ IEEE80211_VERIFY_LENGTH(efrm - frm, 6, return); ni = ic->ic_bss; @@ -2768,7 +2910,7 @@ associd = le16toh(*(u_int16_t *)frm); frm += 2; - rates = xrates = wme = NULL; + rates = xrates = wme = htcap = NULL; while (efrm - frm > 1) { IEEE80211_VERIFY_LENGTH(efrm - frm, frm[1] + 2, return); switch (*frm) { @@ -2778,6 +2920,9 @@ case IEEE80211_ELEMID_XRATES: xrates = frm; break; + case IEEE80211_ELEMID_HTCAP: + htcap = frm; + break; case IEEE80211_ELEMID_VENDOR: if (iswmeoui(frm)) wme = frm; @@ -2939,6 +3084,65 @@ } break; } + + case IEEE80211_FC0_SUBTYPE_ACTION: { + const struct ieee80211_action *ia; + + if (ic->ic_state != IEEE80211_S_RUN && + ic->ic_state != IEEE80211_S_ASSOC && + ic->ic_state != IEEE80211_S_AUTH) { + ic->ic_stats.is_rx_mgtdiscard++; + return; + } + /* + * action frame format: + * [1] category + * [1] action + * [tlv] parameters + */ + IEEE80211_VERIFY_LENGTH(efrm - frm, + sizeof(struct ieee80211_action), return); + ia = (const struct ieee80211_action *) frm; + + ic->ic_stats.is_rx_action++; + IEEE80211_NODE_STAT(ni, rx_action); + + /* verify frame payloads but defer processing */ + /* XXX maybe push this to method */ + switch (ia->ia_category) { + case IEEE80211_ACTION_CAT_BA: + switch (ia->ia_action) { + case IEEE80211_ACTION_BA_ADDBA_REQUEST: + IEEE80211_VERIFY_LENGTH(efrm - frm, + sizeof(struct ieee80211_action_ba_addbarequest), + return); + break; + case IEEE80211_ACTION_BA_ADDBA_RESPONSE: + IEEE80211_VERIFY_LENGTH(efrm - frm, + sizeof(struct ieee80211_action_ba_addbaresponse), + return); + break; + case IEEE80211_ACTION_BA_DELBA: + IEEE80211_VERIFY_LENGTH(efrm - frm, + sizeof(struct ieee80211_action_ba_delba), + return); + break; + } + break; + case IEEE80211_ACTION_CAT_HT: + switch (ia->ia_action) { + case IEEE80211_ACTION_HT_TXCHWIDTH: + IEEE80211_VERIFY_LENGTH(efrm - frm, + sizeof(struct ieee80211_action_ht_txchwidth), + return); + break; + } + break; + } + ic->ic_recv_action(ni, frm, efrm); + break; + } + default: IEEE80211_DISCARD(ic, IEEE80211_MSG_ANY, wh, "mgt", "subtype 0x%x not handled", subtype); ==== //depot/projects/wifi/sys/net80211/ieee80211_ioctl.c#77 (text+ko) ==== @@ -461,6 +461,7 @@ cp = copyie(cp, se->se_rsn_ie); cp = copyie(cp, se->se_wme_ie); cp = copyie(cp, se->se_ath_ie); + cp = copyie(cp, se->se_htcap_ie); } req->space -= len; @@ -1066,6 +1067,45 @@ case IEEE80211_IOC_CURCHAN: error = ieee80211_ioctl_getcurchan(ic, ireq); break; + case IEEE80211_IOC_SHORTGI: + ireq->i_val = 0; + if (ic->ic_flags_ext & IEEE80211_FEXT_SHORTGI20) + ireq->i_val |= IEEE80211_HTCAP_SHORTGI20; + if (ic->ic_flags_ext & IEEE80211_FEXT_SHORTGI40) + ireq->i_val |= IEEE80211_HTCAP_SHORTGI40; + break; + case IEEE80211_IOC_AMPDU: + ireq->i_val = 0; + if (ic->ic_flags_ext & IEEE80211_FEXT_AMPDU_TX) + ireq->i_val |= 1; + if (ic->ic_flags_ext & IEEE80211_FEXT_AMPDU_RX) + ireq->i_val |= 2; + break; + case IEEE80211_IOC_AMPDU_LIMIT: + ireq->i_val = ic->ic_ampdu_limit; /* XXX truncation? */ + break; + case IEEE80211_IOC_AMPDU_DENSITY: + ireq->i_val = ic->ic_ampdu_density; + break; + case IEEE80211_IOC_AMSDU: + ireq->i_val = 0; + if (ic->ic_flags_ext & IEEE80211_FEXT_AMSDU_TX) + ireq->i_val |= 1; + if (ic->ic_flags_ext & IEEE80211_FEXT_AMSDU_RX) + ireq->i_val |= 2; + break; + case IEEE80211_IOC_AMSDU_LIMIT: + ireq->i_val = ic->ic_amsdu_limit; /* XXX truncation? */ + break; + case IEEE80211_IOC_PUREN: + ireq->i_val = (ic->ic_flags_ext & IEEE80211_FEXT_PUREN) != 0; + break; + case IEEE80211_IOC_DOTH: + ireq->i_val = (ic->ic_flags & IEEE80211_F_DOTH) != 0; + break; + case IEEE80211_IOC_HTCOMPAT: + ireq->i_val = (ic->ic_flags_ext & IEEE80211_FEXT_HTCOMPAT) != 0; + break; default: error = EINVAL; break; @@ -1606,6 +1646,9 @@ IEEE80211_CHAN_108A, /* IEEE80211_MODE_TURBO_A */ IEEE80211_CHAN_108G, /* IEEE80211_MODE_TURBO_G */ IEEE80211_CHAN_STURBO, /* IEEE80211_MODE_STURBO_A */ + /* NB: handled specially below */ + IEEE80211_CHAN_A, /* IEEE80211_MODE_11NA */ + IEEE80211_CHAN_G, /* IEEE80211_MODE_11NG */ }; u_int modeflags; int i; @@ -1627,11 +1670,17 @@ * XXX special-case 11b/g channels so we * always select the g channel if both * are present. + * XXX prefer HT to non-HT? */ if (!IEEE80211_IS_CHAN_B(c) || !find11gchannel(ic, i, c->ic_freq)) return c; } else { + /* must check HT specially */ + if ((mode == IEEE80211_MODE_11NA || + mode == IEEE80211_MODE_11NG) && + !IEEE80211_IS_CHAN_HT(c)) + continue; if ((c->ic_flags & modeflags) == modeflags) return c; } @@ -1653,11 +1702,15 @@ case IEEE80211_MODE_11B: return (IEEE80211_IS_CHAN_B(c)); case IEEE80211_MODE_11G: - return (IEEE80211_IS_CHAN_ANYG(c)); + return (IEEE80211_IS_CHAN_ANYG(c) && !IEEE80211_IS_CHAN_HT(c)); case IEEE80211_MODE_11A: - return (IEEE80211_IS_CHAN_A(c)); + return (IEEE80211_IS_CHAN_A(c) && !IEEE80211_IS_CHAN_HT(c)); case IEEE80211_MODE_STURBO_A: return (IEEE80211_IS_CHAN_STURBO(c)); + case IEEE80211_MODE_11NA: + return (IEEE80211_IS_CHAN_HTA(c)); + case IEEE80211_MODE_11NG: + return (IEEE80211_IS_CHAN_HTG(c)); } return 1; >>> TRUNCATED FOR MAIL (1000 lines) <<<