Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 9 May 2007 16:30:18 GMT
From:      Sam Leffler <sam@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 119566 for review
Message-ID:  <200705091630.l49GUIWp001642@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
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) <<<



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