Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 17 Mar 2008 21:44:09 GMT
From:      Sam Leffler <sam@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 137955 for review
Message-ID:  <200803172144.m2HLi9RM008424@repoman.freebsd.org>

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

Change 137955 by sam@sam_ebb on 2008/03/17 21:44:03

	o track rssadapt changes
	o add protection
	o use common phy support

Affected files ...

.. //depot/projects/vap/sys/dev/ral/rt2661.c#17 edit
.. //depot/projects/vap/sys/dev/ral/rt2661var.h#9 edit

Differences ...

==== //depot/projects/vap/sys/dev/ral/rt2661.c#17 (text) ====

@@ -53,6 +53,7 @@
 #include <net/if_types.h>
 
 #include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_phy.h>
 #include <net80211/ieee80211_radiotap.h>
 #include <net80211/ieee80211_regdomain.h>
 #include <net80211/ieee80211_rssadapt.h>
@@ -113,18 +114,12 @@
 static void		rt2661_mcu_beacon_expire(struct rt2661_softc *);
 static void		rt2661_mcu_wakeup(struct rt2661_softc *);
 static void		rt2661_mcu_cmd_intr(struct rt2661_softc *);
-static int		rt2661_ack_rate(struct ieee80211com *, int);
 static void		rt2661_scan_start(struct ieee80211com *);
 static void		rt2661_scan_end(struct ieee80211com *);
 static void		rt2661_set_channel(struct ieee80211com *);
-static uint16_t		rt2661_txtime(int, int, uint32_t);
-static uint8_t		rt2661_rxrate(struct rt2661_rx_desc *);
-static uint8_t		rt2661_plcp_signal(int);
 static void		rt2661_setup_tx_desc(struct rt2661_softc *,
 			    struct rt2661_tx_desc *, uint32_t, uint16_t, int,
 			    int, const bus_dma_segment_t *, int, int);
-static struct mbuf *	rt2661_get_rts(struct rt2661_softc *,
-			    struct ieee80211_frame *, uint16_t);
 static int		rt2661_tx_data(struct rt2661_softc *, struct mbuf *,
 			    struct ieee80211_node *, int);
 static int		rt2661_tx_mgt(struct rt2661_softc *, struct mbuf *,
@@ -319,6 +314,8 @@
 	ic->ic_vap_create = rt2661_vap_create;
 	ic->ic_vap_delete = rt2661_vap_delete;
 
+	sc->sc_rates = ieee80211_get_ratetable(ic->ic_curchan);
+
 	bpfattach(ifp, DLT_IEEE802_11_RADIO,
 	    sizeof (struct ieee80211_frame) + sizeof (sc->sc_txtap));
 
@@ -430,8 +427,7 @@
 	vap->iv_update_beacon = rt2661_beacon_update;
 #endif
 
-	callout_init(&rvp->rssadapt_ch, CALLOUT_MPSAFE);
-	ieee80211_rssadapt_init(&rvp->rssadapt, vap);
+	ieee80211_rssadapt_init(&rvp->rssadapt, vap, 100 /*ms*/);
 
 	/* complete setup */
 	ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status);
@@ -445,7 +441,7 @@
 {
 	struct rt2661_vap *rvp = RT2661_VAP(vap);
 
-	callout_stop(&rvp->rssadapt_ch);
+	ieee80211_rssadapt_cleanup(&rvp->rssadapt);
 	ieee80211_vap_detach(vap);
 	free(rvp, M_80211_VAP);
 }
@@ -785,38 +781,7 @@
 	return (rn != NULL) ? &rn->ni : NULL;
 }
 
-/*
- * This function is called for each node present in the node station table.
- */
 static void
-rt2661_iter_func(void *arg, struct ieee80211_node *ni)
-{
-	struct ieee80211vap *vap = arg;
-
-	if (ni->ni_vap == vap)
-		ieee80211_rssadapt_updatestats(&RT2661_NODE(ni)->rssadapt);
-}
-
-/*
- * This function is called periodically (every 100ms) in RUN state to update
- * the rate adaptation statistics.
- */
-static void
-rt2661_update_rssadapt(void *arg)
-{
-	struct ieee80211vap *vap = arg;
-	struct rt2661_vap *rvp = RT2661_VAP(vap);
-
-	if (vap->iv_opmode != IEEE80211_M_STA) {
-		struct ieee80211com *ic = vap->iv_ic;
-		ieee80211_iterate_nodes(&ic->ic_sta, rt2661_iter_func, arg);
-	} else
-		rt2661_iter_func(arg, vap->iv_bss);
-
-	callout_reset(&rvp->rssadapt_ch, hz / 10, rt2661_update_rssadapt, vap);
-}
-
-static void
 rt2661_newassoc(struct ieee80211_node *ni, int isnew)
 {
 	struct ieee80211vap *vap = ni->ni_vap;
@@ -836,8 +801,6 @@
 	if (nstate == IEEE80211_S_INIT && vap->iv_state == IEEE80211_S_RUN) {
 		uint32_t tmp;
 
-		callout_stop(&rvp->rssadapt_ch);
-
 		/* abort TSF synchronization */
 		tmp = RAL_READ(sc, RT2661_TXRX_CSR9);
 		RAL_WRITE(sc, RT2661_TXRX_CSR9, tmp & ~0x00ffffff);
@@ -847,7 +810,6 @@
 
 	if (error == 0 && nstate == IEEE80211_S_RUN) {
 		struct ieee80211_node *ni = vap->iv_bss;
-		const struct ieee80211_txparam *tp;
 
 		if (vap->iv_opmode != IEEE80211_M_MONITOR) {
 			rt2661_enable_mrr(sc);
@@ -867,11 +829,6 @@
 				/* fake a join to init the tx rate */
 				rt2661_newassoc(ni, 1);
 			}
-			tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)];
-			if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE)
-				callout_reset(&rvp->rssadapt_ch, hz / 10,
-				    rt2661_update_rssadapt, vap);
-
 			rt2661_enable_tsf_sync(sc);
 		}
 	}
@@ -970,7 +927,7 @@
 		if (ni == NULL)
 			continue;
 
-		rn = (struct rt2661_node *)ni;
+		rn = RT2661_NODE(ni);
 
 		switch (RT2661_TX_RESULT(val)) {
 		case RT2661_TX_SUCCESS:
@@ -980,8 +937,9 @@
 			    "%d retries\n", retrycnt);
 			if (retrycnt == 0 &&
 			    data->rix != IEEE80211_FIXED_RATE_NONE) {
-				ieee80211_rssadapt_tx_complete(&rn->rssadapt, 1,
-				    m->m_pkthdr.len, data->rix, data->rssi);
+				ieee80211_rssadapt_tx_complete(&rn->rssadapt,
+				    IEEE80211_RSSADAPT_SUCCESS,
+				    m->m_pkthdr.len, data->rssi);
 			}
 			ifp->if_opackets++;
 			break;
@@ -990,8 +948,9 @@
 			DPRINTFN(sc, 9, "%s\n",
 			    "sending data frame failed (too much retries)");
 			if (data->rix != IEEE80211_FIXED_RATE_NONE) {
-				ieee80211_rssadapt_tx_complete(&rn->rssadapt, 0,
-				    m->m_pkthdr.len, data->rix, data->rssi);
+				ieee80211_rssadapt_tx_complete(&rn->rssadapt,
+				    IEEE80211_RSSADAPT_FAILURE,
+				    m->m_pkthdr.len, data->rssi);
 			}
 			ifp->if_oerrors++;
 			break;
@@ -1157,7 +1116,8 @@
 			tap->wr_tsf =
 			    htole64(((uint64_t)tsf_hi << 32) | tsf_lo);
 			tap->wr_flags = 0;
-			tap->wr_rate = rt2661_rxrate(desc);
+			tap->wr_rate = ieee80211_plcp2rate(desc->rate,
+			    le32toh(desc->flags) & RT2661_RX_OFDM);
 			tap->wr_antsignal = rssi < 0 ? 0 : rssi;
 
 			bpf_mtap2(ifp->if_bpf, tap, sc->sc_rxtap_len, m);
@@ -1284,131 +1244,6 @@
 	RAL_UNLOCK(sc);
 }
 
-/* quickly determine if a given rate is CCK or OFDM */
-#define RAL_RATE_IS_OFDM(rate) ((rate) >= 12 && (rate) != 22)
-
-#define RAL_ACK_SIZE	14	/* 10 + 4(FCS) */
-#define RAL_CTS_SIZE	14	/* 10 + 4(FCS) */
-
-#define RAL_SIFS	10	/* us */
-
-/*
- * This function is only used by the Rx radiotap code. It returns the rate at
- * which a given frame was received.
- */
-static uint8_t
-rt2661_rxrate(struct rt2661_rx_desc *desc)
-{
-	if (le32toh(desc->flags) & RT2661_RX_OFDM) {
-		/* reverse function of rt2661_plcp_signal */
-		switch (desc->rate & 0xf) {
-		case 0xb:	return 12;
-		case 0xf:	return 18;
-		case 0xa:	return 24;
-		case 0xe:	return 36;
-		case 0x9:	return 48;
-		case 0xd:	return 72;
-		case 0x8:	return 96;
-		case 0xc:	return 108;
-		}
-	} else {
-		if (desc->rate == 10)
-			return 2;
-		if (desc->rate == 20)
-			return 4;
-		if (desc->rate == 55)
-			return 11;
-		if (desc->rate == 110)
-			return 22;
-	}
-	return 2;	/* should not get there */
-}
-
-/*
- * Return the expected ack rate for a frame transmitted at rate `rate'.
- * XXX: this should depend on the destination node basic rate set.
- */
-static int
-rt2661_ack_rate(struct ieee80211com *ic, int rate)
-{
-	switch (rate) {
-	/* CCK rates */
-	case 2:
-		return 2;
-	case 4:
-	case 11:
-	case 22:
-		return (ic->ic_curmode == IEEE80211_MODE_11B) ? 4 : rate;
-
-	/* OFDM rates */
-	case 12:
-	case 18:
-		return 12;
-	case 24:
-	case 36:
-		return 24;
-	case 48:
-	case 72:
-	case 96:
-	case 108:
-		return 48;
-	}
-
-	/* default to 1Mbps */
-	return 2;
-}
-
-/*
- * Compute the duration (in us) needed to transmit `len' bytes at rate `rate'.
- * The function automatically determines the operating mode depending on the
- * given rate. `flags' indicates whether short preamble is in use or not.
- */
-static uint16_t
-rt2661_txtime(int len, int rate, uint32_t flags)
-{
-	uint16_t txtime;
-
-	if (RAL_RATE_IS_OFDM(rate)) {
-		/* IEEE Std 802.11a-1999, pp. 37 */
-		txtime = (8 + 4 * len + 3 + rate - 1) / rate;
-		txtime = 16 + 4 + 4 * txtime + 6;
-	} else {
-		/* IEEE Std 802.11b-1999, pp. 28 */
-		txtime = (16 * len + rate - 1) / rate;
-		if (rate != 2 && (flags & IEEE80211_F_SHPREAMBLE))
-			txtime +=  72 + 24;
-		else
-			txtime += 144 + 48;
-	}
-
-	return txtime;
-}
-
-static uint8_t
-rt2661_plcp_signal(int rate)
-{
-	switch (rate) {
-	/* CCK rates (returned values are device-dependent) */
-	case 2:		return 0x0;
-	case 4:		return 0x1;
-	case 11:	return 0x2;
-	case 22:	return 0x3;
-
-	/* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */
-	case 12:	return 0xb;
-	case 18:	return 0xf;
-	case 24:	return 0xa;
-	case 36:	return 0xe;
-	case 48:	return 0x9;
-	case 72:	return 0xd;
-	case 96:	return 0x8;
-	case 108:	return 0xc;
-
-	/* unsupported rates (should not get there) */
-	default:	return 0xff;
-	}
-}
-
 static void
 rt2661_setup_tx_desc(struct rt2661_softc *sc, struct rt2661_tx_desc *desc,
     uint32_t flags, uint16_t xflags, int len, int rate,
@@ -1439,11 +1274,11 @@
 	desc->qid = ac;
 
 	/* setup PLCP fields */
-	desc->plcp_signal  = rt2661_plcp_signal(rate);
+	desc->plcp_signal  = ieee80211_rate2plcp(rate);
 	desc->plcp_service = 4;
 
 	len += IEEE80211_CRC_LEN;
-	if (RAL_RATE_IS_OFDM(rate)) {
+	if (ieee80211_rate2phytype(sc->sc_rates, rate) == IEEE80211_T_OFDM) {
 		desc->flags |= htole32(RT2661_TX_OFDM);
 
 		plcp_length = len & 0xfff;
@@ -1529,8 +1364,8 @@
 	if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
 		flags |= RT2661_TX_NEED_ACK;
 
-		dur = rt2661_txtime(RAL_ACK_SIZE, rate, ic->ic_flags) +
-		    RAL_SIFS;
+		dur = ieee80211_ack_duration(sc->sc_rates,
+		    rate, ic->ic_flags & IEEE80211_F_SHPREAMBLE);
 		*(uint16_t *)wh->i_dur = htole16(dur);
 
 		/* tell hardware to add timestamp in probe responses */
@@ -1558,35 +1393,74 @@
 	return 0;
 }
 
-/*
- * Build a RTS control frame.
- */
-static struct mbuf *
-rt2661_get_rts(struct rt2661_softc *sc, struct ieee80211_frame *wh,
-    uint16_t dur)
+static int
+rt2661_sendprot(struct rt2661_softc *sc, int ac,
+    const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate)
 {
-	struct ieee80211_frame_rts *rts;
-	struct mbuf *m;
+	struct ieee80211com *ic = ni->ni_ic;
+	struct rt2661_tx_ring *txq = &sc->txq[ac];
+	const struct ieee80211_frame *wh;
+	struct rt2661_tx_desc *desc;
+	struct rt2661_tx_data *data;
+	struct mbuf *mprot;
+	int protrate, ackrate, pktlen, flags, isshort, error;
+	uint16_t dur;
+	bus_dma_segment_t segs[RT2661_MAX_SCATTER];
+	int nsegs;
+
+	KASSERT(prot == IEEE80211_PROT_RTSCTS || prot == IEEE80211_PROT_CTSONLY,
+	    ("protection %d", prot));
+
+	wh = mtod(m, const struct ieee80211_frame *);
+	pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN;
+
+	protrate = ieee80211_ctl_rate(sc->sc_rates, rate);
+	ackrate = ieee80211_ack_rate(sc->sc_rates, rate);
+
+	isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0;
+	dur = ieee80211_compute_duration(sc->sc_rates, pktlen, rate, isshort);
+	    + ieee80211_ack_duration(sc->sc_rates, rate, isshort);
+	flags = RT2661_TX_MORE_FRAG;
+	if (prot == IEEE80211_PROT_RTSCTS) {
+		/* NB: CTS is the same size as an ACK */
+		dur += ieee80211_ack_duration(sc->sc_rates, rate, isshort);
+		flags |= RT2661_TX_NEED_ACK;
+		mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur);
+	} else {
+		mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur);
+	}
+	if (mprot == NULL) {
+		/* XXX stat + msg */
+		return ENOBUFS;
+	}
+
+	data = &txq->data[txq->cur];
+	desc = &txq->desc[txq->cur];
 
-	MGETHDR(m, M_DONTWAIT, MT_DATA);
-	if (m == NULL) {
-		sc->sc_ic.ic_stats.is_tx_nobuf++;
-		device_printf(sc->sc_dev, "could not allocate RTS frame\n");
-		return NULL;
+	error = bus_dmamap_load_mbuf_sg(txq->data_dmat, data->map, mprot, segs,
+	    &nsegs, 0);
+	if (error != 0) {
+		device_printf(sc->sc_dev,
+		    "could not map mbuf (error %d)\n", error);
+		m_freem(mprot);
+		return error;
 	}
 
-	rts = mtod(m, struct ieee80211_frame_rts *);
+	data->m = mprot;
+	data->ni = ieee80211_ref_node(ni);
+	/* ctl frames are not taken into account for rssadapt */
+	data->rix = IEEE80211_FIXED_RATE_NONE;
+
+	rt2661_setup_tx_desc(sc, desc, flags, 0, mprot->m_pkthdr.len,
+	    protrate, segs, 1, ac);
 
-	rts->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_CTL |
-	    IEEE80211_FC0_SUBTYPE_RTS;
-	rts->i_fc[1] = IEEE80211_FC1_DIR_NODS;
-	*(uint16_t *)rts->i_dur = htole16(dur);
-	IEEE80211_ADDR_COPY(rts->i_ra, wh->i_addr1);
-	IEEE80211_ADDR_COPY(rts->i_ta, wh->i_addr2);
+	bus_dmamap_sync(txq->data_dmat, data->map, BUS_DMASYNC_PREWRITE);
+	bus_dmamap_sync(txq->desc_dmat, txq->desc_map, BUS_DMASYNC_PREWRITE);
 
-	m->m_pkthdr.len = m->m_len = sizeof (struct ieee80211_frame_rts);
+	txq->queued++;
+	txq->cur = (txq->cur + 1) % RT2661_TX_RING_COUNT;
 
-	return m;
+	return 0;
 }
 
 static int
@@ -1599,7 +1473,6 @@
 	struct ifnet *ifp = sc->sc_ifp;
 	struct rt2661_tx_desc *desc;
 	struct rt2661_tx_data *data;
-	struct rt2661_node *rn;
 	struct ieee80211_frame *wh;
 	const struct ieee80211_txparam *tp;
 	struct ieee80211_key *k;
@@ -1607,7 +1480,7 @@
 	struct mbuf *mnew;
 	bus_dma_segment_t segs[RT2661_MAX_SCATTER];
 	uint16_t dur;
-	uint32_t flags = 0;
+	uint32_t flags;
 	int error, nsegs, rate, noack = 0;
 
 	wh = mtod(m0, struct ieee80211_frame *);
@@ -1620,13 +1493,9 @@
 	} else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) {
 		rate = tp->ucastrate;
 	} else {
-		struct ieee80211_rateset *rs;
-
-		rs = &ni->ni_rates;
-		rn = (struct rt2661_node *)ni;
-		ni->ni_txrate = ieee80211_rssadapt_choose(&rn->rssadapt, rs,
+		(void) ieee80211_rssadapt_choose(ni, &RT2661_NODE(ni)->rssadapt,
 		    m0->m_pkthdr.len);
-		rate = rs->rs_rates[ni->ni_txrate];
+		rate = ni->ni_txrate;
 	}
 	rate &= IEEE80211_RATE_VAL;
 
@@ -1646,66 +1515,22 @@
 		wh = mtod(m0, struct ieee80211_frame *);
 	}
 
-	/*
-	 * IEEE Std 802.11-1999, pp 82: "A STA shall use an RTS/CTS exchange
-	 * for directed frames only when the length of the MPDU is greater
-	 * than the length threshold indicated by [...]" ic_rtsthreshold.
-	 */
-	if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
-	    m0->m_pkthdr.len > vap->iv_rtsthreshold) {
-		struct mbuf *m;
-		uint16_t dur;
-		int rtsrate, ackrate;
-
-		rtsrate = IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ? 12 : 2;
-		ackrate = rt2661_ack_rate(ic, rate);
-
-		dur = rt2661_txtime(m0->m_pkthdr.len + 4, rate, ic->ic_flags) +
-		      rt2661_txtime(RAL_CTS_SIZE, rtsrate, ic->ic_flags) +
-		      /* XXX: noack (QoS)? */
-		      rt2661_txtime(RAL_ACK_SIZE, ackrate, ic->ic_flags) +
-		      3 * RAL_SIFS;
-
-		m = rt2661_get_rts(sc, wh, dur);
-
-		desc = &txq->desc[txq->cur];
-		data = &txq->data[txq->cur];
-
-		error = bus_dmamap_load_mbuf_sg(txq->data_dmat, data->map, m,
-		    segs, &nsegs, 0);
-		if (error != 0) {
-			device_printf(sc->sc_dev,
-			    "could not map mbuf (error %d)\n", error);
-			m_freem(m);
-			m_freem(m0);
-			return error;
+	flags = 0;
+	if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
+		int prot = IEEE80211_PROT_NONE;
+		if (m0->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold)
+			prot = IEEE80211_PROT_RTSCTS;
+		else if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
+		    ieee80211_rate2phytype(sc->sc_rates, rate) == IEEE80211_T_OFDM)
+			prot = ic->ic_protmode;
+		if (prot != IEEE80211_PROT_NONE) {
+			error = rt2661_sendprot(sc, ac, m0, ni, prot, rate);
+			if (error) {
+				m_freem(m0);
+				return error;
+			}
+			flags |= RT2661_TX_LONG_RETRY | RT2661_TX_IFS;
 		}
-
-		/* avoid multiple free() of the same node for each fragment */
-		ieee80211_ref_node(ni);
-
-		data->m = m;
-		data->ni = ni;
-
-		/* RTS frames are not taken into account for rssadapt */
-		data->rix = IEEE80211_FIXED_RATE_NONE;
-
-		rt2661_setup_tx_desc(sc, desc, RT2661_TX_NEED_ACK |
-		    RT2661_TX_MORE_FRAG, 0, m->m_pkthdr.len, rtsrate, segs,
-		    nsegs, ac);
-
-		bus_dmamap_sync(txq->data_dmat, data->map,
-		    BUS_DMASYNC_PREWRITE);
-
-		txq->queued++;
-		txq->cur = (txq->cur + 1) % RT2661_TX_RING_COUNT;
-
-		/*
-		 * IEEE Std 802.11-1999: when an RTS/CTS exchange is used, the
-		 * asynchronous data frame shall be transmitted after the CTS
-		 * frame and a SIFS period.
-		 */
-		flags |= RT2661_TX_LONG_RETRY | RT2661_TX_IFS;
 	}
 
 	data = &txq->data[txq->cur];
@@ -1767,8 +1592,8 @@
 	if (!noack && !IEEE80211_IS_MULTICAST(wh->i_addr1)) {
 		flags |= RT2661_TX_NEED_ACK;
 
-		dur = rt2661_txtime(RAL_ACK_SIZE, rt2661_ack_rate(ic, rate),
-		    ic->ic_flags) + RAL_SIFS;
+		dur = ieee80211_ack_duration(sc->sc_rates,
+		    rate, ic->ic_flags & IEEE80211_F_SHPREAMBLE);
 		*(uint16_t *)wh->i_dur = htole16(dur);
 	}
 
@@ -2170,6 +1995,8 @@
 	chan = ieee80211_chan2ieee(ic, c);
 	KASSERT(chan != 0 && chan != IEEE80211_CHAN_ANY, ("chan 0x%x", chan));
 
+	sc->sc_rates = ieee80211_get_ratetable(c);
+
 	/* select the appropriate RF settings based on what EEPROM says */
 	rfprog = (sc->rfprog == 0) ? rt2661_rf5225_1 : rt2661_rf5225_2;
 

==== //depot/projects/vap/sys/dev/ral/rt2661var.h#9 (text) ====

@@ -95,7 +95,6 @@
 struct rt2661_vap {
 	struct ieee80211vap	ral_vap;
 	struct ieee80211_rssadapt rssadapt;
-	struct callout		rssadapt_ch;
 
 	int			(*ral_newstate)(struct ieee80211vap *,
 				    enum ieee80211_state, int);
@@ -116,6 +115,8 @@
 	int				sc_tx_timer;
 	int                             sc_invalid;
 	int				sc_debug;
+
+	const struct ieee80211_rate_table *sc_rates;
 /*
  * The same in both up to here
  * ------------------------------------------------



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