Subject: Re: ural patch
To: None <port-i386@netbsd.org>
From: KIYOHARA Takashi <kiyohara@kk.iij4u.or.jp>
List: tech-kern
Date: 06/26/2006 00:50:16
----Next_Part(Mon_Jun_26_00:50:16_2006_300)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Hi! all i386 users,


This mail was posted to current-users@ and tech-kern@ by me.

Would you please test this ural patch.
My evbmips machine (OMSAL400) works fine.  ;-)


From: "Perry E. Metzger" <perry@piermont.com>
Date: Sun, 25 Jun 2006 11:16:57 -0400

> 
> KIYOHARA Takashi <kiyohara@kk.iij4u.or.jp> writes:
> > I coordinated ural(4) of FreeBSD-current (v 1.40).  This ural works
> > fine on hostap-mode on evbmips (OMSAL400).  However, ural of -current
> > don't works hostap-mode.
> > I request to commit this patch.  But it didn't test other arch.  ;-<
> 
> You should post the patch to port-i386 as well and see if anyone tries
> it. If no one tells you that the patch does not work, I think it
> should be okay to commit it.
> 
> Perry

--
kiyohara


----Next_Part(Mon_Jun_26_00:50:16_2006_300)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="if_ural.diff"

Index: if_ural.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/if_ural.c,v
retrieving revision 1.11
diff -u -r1.11 if_ural.c
--- if_ural.c	4 Mar 2006 01:22:31 -0000	1.11
+++ if_ural.c	23 Jun 2006 17:53:39 -0000
@@ -1,9 +1,8 @@
 /*	$NetBSD: if_ural.c,v 1.11 2006/03/04 01:22:31 nakayama Exp $ */
-/*	$OpenBSD: if_ral.c,v 1.38 2005/07/07 08:33:22 jsg Exp $  */
-/*	$FreeBSD: /a/cvsroot/freebsd.repo/ncvs/src/sys/dev/usb/if_ural.c,v 1.10 2005/07/10 00:17:05 sam Exp $	*/
+/*	$FreeBSD: /repoman/r/ncvs/src/sys/dev/usb/if_ural.c,v 1.40 2006/06/02 23:14:40 sam Exp $	*/
 
 /*-
- * Copyright (c) 2005
+ * Copyright (c) 2005, 2006
  *	Damien Bergamini <damien.bergamini@free.fr>
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -120,11 +119,12 @@
 Static void		ural_task(void *);
 Static int		ural_newstate(struct ieee80211com *,
 			    enum ieee80211_state, int);
+Static int		ural_rxrate(struct ural_rx_desc *);
 Static void		ural_txeof(usbd_xfer_handle, usbd_private_handle,
 			    usbd_status);
 Static void		ural_rxeof(usbd_xfer_handle, usbd_private_handle,
 			    usbd_status);
-Static int		ural_ack_rate(int);
+Static int		ural_ack_rate(struct ieee80211com *, int);
 Static uint16_t		ural_txtime(int, int, uint32_t);
 Static uint8_t		ural_plcp_signal(int);
 Static void		ural_setup_tx_desc(struct ural_softc *,
@@ -137,7 +137,9 @@
 			    struct ieee80211_node *);
 Static void		ural_start(struct ifnet *);
 Static void		ural_watchdog(struct ifnet *);
+Static int		ural_reset(struct ifnet *);
 Static int		ural_ioctl(struct ifnet *, u_long, caddr_t);
+Static void		ural_set_testmode(struct ural_softc *);
 Static void		ural_eeprom_read(struct ural_softc *, uint16_t, void *,
 			    int);
 Static uint16_t		ural_read(struct ural_softc *, uint16_t);
@@ -153,6 +155,9 @@
 			    struct ieee80211_channel *);
 Static void		ural_disable_rf_tune(struct ural_softc *);
 Static void		ural_enable_tsf_sync(struct ural_softc *);
+Static void		ural_update_slot(struct ifnet *);
+Static void		ural_set_txpreamble(struct ural_softc *);
+Static void		ural_set_basicrates(struct ural_softc *);
 Static void		ural_set_bssid(struct ural_softc *, uint8_t *);
 Static void		ural_set_macaddr(struct ural_softc *, uint8_t *);
 Static void		ural_update_promisc(struct ural_softc *);
@@ -163,6 +168,13 @@
 Static void		ural_set_rxantenna(struct ural_softc *, int);
 Static int		ural_init(struct ifnet *);
 Static void		ural_stop(struct ifnet *, int);
+Static void		ural_amrr_start(struct ural_softc *,
+			    struct ieee80211_node *);
+Static void		ural_amrr_timeout(void *);
+Static void		ural_amrr_update(usbd_xfer_handle, usbd_private_handle,
+			    usbd_status status);
+Static void		ural_ratectl(struct ural_amrr *,
+			    struct ieee80211_node *);
 
 /*
  * Supported rates for 802.11a/b/g modes (in 500Kbps unit).
@@ -296,7 +308,6 @@
 	uint32_t	r2;
 	uint32_t	r4;
 } ural_rf5222[] = {
-	/* channels in the 2.4GHz band */
 	{   1, 0x08808, 0x0044d, 0x00282 },
 	{   2, 0x08808, 0x0044e, 0x00282 },
 	{   3, 0x08808, 0x0044f, 0x00282 },
@@ -312,7 +323,6 @@
 	{  13, 0x08808, 0x00469, 0x00282 },
 	{  14, 0x08808, 0x0046b, 0x00286 },
 
-	/* channels in the 5.2GHz band */
 	{  36, 0x08804, 0x06225, 0x00287 },
 	{  40, 0x08804, 0x06226, 0x00287 },
 	{  44, 0x08804, 0x06227, 0x00287 },
@@ -395,7 +405,7 @@
 	for (i = 0; i < id->bNumEndpoints; i++) {
 		ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
 		if (ed == NULL) {
-			printf("%s: no endpoint descriptor for iface %d\n",
+			printf("%s: no endpoint descriptor for %d\n",
 			    USBDEVNAME(sc->sc_dev), i);
 			USB_ATTACH_ERROR_RETURN;
 		}
@@ -414,6 +424,7 @@
 
 	usb_init_task(&sc->sc_task, ural_task, sc);
 	callout_init(&sc->scan_ch);
+	callout_init(&sc->amrr_ch);
 
 	/* retrieve RT2570 rev. no */
 	sc->asic_rev = ural_read(sc, RAL_MAC_CSR0);
@@ -421,9 +432,18 @@
 	/* retrieve MAC address and various other things from EEPROM */
 	ural_read_eeprom(sc);
 
-	printf("%s: MAC/BBP RT2570 (rev 0x%02x), RF %s, address %s\n",
-	    USBDEVNAME(sc->sc_dev), sc->asic_rev, ural_get_rf(sc->rf_rev),
-	    ether_sprintf(ic->ic_myaddr));
+	printf("%s: MAC/BBP RT2570 (rev 0x%02x), RF %s\n",
+	    USBDEVNAME(sc->sc_dev), sc->asic_rev, ural_get_rf(sc->rf_rev));
+
+	ifp->if_softc = sc;
+	memcpy(ifp->if_xname, USBDEVNAME(sc->sc_dev), IFNAMSIZ);
+	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+	ifp->if_init = ural_init;
+	ifp->if_ioctl = ural_ioctl;
+	ifp->if_start = ural_start;
+	ifp->if_watchdog = ural_watchdog;
+	IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
+	IFQ_SET_READY(&ifp->if_snd);
 
 	ic->ic_ifp = ifp;
 	ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
@@ -431,9 +451,14 @@
 	ic->ic_state = IEEE80211_S_INIT;
 
 	/* set device capabilities */
-	ic->ic_caps = IEEE80211_C_MONITOR | IEEE80211_C_IBSS |
-	    IEEE80211_C_HOSTAP | IEEE80211_C_SHPREAMBLE | IEEE80211_C_SHSLOT |
-	    IEEE80211_C_PMGT | IEEE80211_C_TXPMGT | IEEE80211_C_WPA;
+	ic->ic_caps =
+	    IEEE80211_C_IBSS |		/* IBSS mode supported */
+	    IEEE80211_C_MONITOR |	/* monitor mode supported */
+	    IEEE80211_C_HOSTAP |	/* HostAp mode supported */
+	    IEEE80211_C_TXPMGT |	/* tx power management */
+	    IEEE80211_C_SHPREAMBLE |	/* short preamble supported */
+	    IEEE80211_C_SHSLOT |	/* short slot time supported */
+	    IEEE80211_C_WPA;		/* 802.11i */
 
 	if (sc->rf_rev == RAL_RF_5222) {
 		/* set supported .11a rates */
@@ -470,18 +495,9 @@
 		    IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
 	}
 
-	ifp->if_softc = sc;
-	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
-	ifp->if_init = ural_init;
-	ifp->if_stop = ural_stop;
-	ifp->if_ioctl = ural_ioctl;
-	ifp->if_start = ural_start;
-	ifp->if_watchdog = ural_watchdog;
-	IFQ_SET_READY(&ifp->if_snd);
-	memcpy(ifp->if_xname, USBDEVNAME(sc->sc_dev), IFNAMSIZ);
-
 	if_attach(ifp);
 	ieee80211_ifattach(ic);
+	ic->ic_reset = ural_reset;
 
 	/* override state transition machine */
 	sc->sc_newstate = ic->ic_newstate;
@@ -518,8 +534,15 @@
 
 	s = splusb();
 
+	ural_stop(ifp, 1);
 	usb_rem_task(sc->sc_udev, &sc->sc_task);
 	callout_stop(&sc->scan_ch);
+	callout_stop(&sc->amrr_ch);
+
+	if (sc->amrr_xfer != NULL) {
+		usbd_free_xfer(sc->amrr_xfer);
+		sc->amrr_xfer = NULL;
+	}
 
 	if (sc->sc_rx_pipeh != NULL) {
 		usbd_abort_pipe(sc->sc_rx_pipeh);
@@ -713,6 +736,7 @@
 	struct ural_softc *sc = arg;
 	struct ieee80211com *ic = &sc->sc_ic;
 	enum ieee80211_state ostate;
+	struct ieee80211_node *ni;
 	struct mbuf *m;
 
 	ostate = ic->ic_state;
@@ -744,21 +768,27 @@
 	case IEEE80211_S_RUN:
 		ural_set_chan(sc, ic->ic_curchan);
 
-		if (ic->ic_opmode != IEEE80211_M_MONITOR)
-			ural_set_bssid(sc, ic->ic_bss->ni_bssid);
+		ni = ic->ic_bss;
+
+		if (ic->ic_opmode != IEEE80211_M_MONITOR) {
+			ural_update_slot(ic->ic_ifp);
+			ural_set_txpreamble(sc);
+			ural_set_basicrates(sc);
+			ural_set_bssid(sc, ni->ni_bssid);
+		}
 
 		if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
 		    ic->ic_opmode == IEEE80211_M_IBSS) {
-			m = ieee80211_beacon_alloc(ic, ic->ic_bss, &sc->sc_bo);
+			m = ieee80211_beacon_alloc(ic, ni, &sc->sc_bo);
 			if (m == NULL) {
 				printf("%s: could not allocate beacon\n",
 				    USBDEVNAME(sc->sc_dev));
 				return;
 			}
 
-			if (ural_tx_bcn(sc, m, ic->ic_bss) != 0) {
+			if (ural_tx_bcn(sc, m, ni) != 0) {
 				m_freem(m);
-				printf("%s: could not transmit beacon\n",
+				printf("%s: could not send beacon\n",
 				    USBDEVNAME(sc->sc_dev));
 				return;
 			}
@@ -772,6 +802,12 @@
 
 		if (ic->ic_opmode != IEEE80211_M_MONITOR)
 			ural_enable_tsf_sync(sc);
+
+		/* enable automatic rate adaptation in STA mode */
+		if (ic->ic_opmode == IEEE80211_M_STA &&
+		    ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE)
+			ural_amrr_start(sc, ni);
+
 		break;
 	}
 
@@ -785,6 +821,7 @@
 
 	usb_rem_task(sc->sc_udev, &sc->sc_task);
 	callout_stop(&sc->scan_ch);
+	callout_stop(&sc->amrr_ch);
 
 	/* do it in a process context */
 	sc->sc_state = nstate;
@@ -798,7 +835,41 @@
 
 #define RAL_ACK_SIZE	14	/* 10 + 4(FCS) */
 #define RAL_CTS_SIZE	14	/* 10 + 4(FCS) */
-#define RAL_SIFS	10
+
+#define RAL_SIFS		10	/* us */
+
+#define RAL_RXTX_TURNAROUND	5	/* us */
+
+/*
+ * This function is only used by the Rx radiotap code.
+ */
+Static int
+ural_rxrate(struct ural_rx_desc *desc)
+{
+	if (le32toh(desc->flags) & RAL_RX_OFDM) {
+		/* reverse function of ural_plcp_signal */
+		switch (desc->rate) {
+		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 */
+}
 
 Static void
 ural_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
@@ -849,9 +920,9 @@
 	struct ieee80211com *ic = &sc->sc_ic;
 	struct ifnet *ifp = &sc->sc_if;
 	struct ural_rx_desc *desc;
-	struct ieee80211_frame_min *wh;
+	struct ieee80211_frame *wh;
 	struct ieee80211_node *ni;
-	struct mbuf *m;
+	struct mbuf *mnew, *m;
 	int s, len;
 
 	if (status != USBD_NORMAL_COMPLETION) {
@@ -865,8 +936,9 @@
 
 	usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL);
 
-	if (len < RAL_RX_DESC_SIZE) {
-		printf("%s: xfer too short %d\n", USBDEVNAME(sc->sc_dev), len);
+	if (len < RAL_RX_DESC_SIZE + IEEE80211_MIN_LEN) {
+		DPRINTF(("%s: xfer too short %d\n", USBDEVNAME(sc->sc_dev),
+		    len));
 		ifp->if_ierrors++;
 		goto skip;
 	}
@@ -874,7 +946,8 @@
 	/* rx descriptor is located at the end */
 	desc = (struct ural_rx_desc *)(data->buf + len - RAL_RX_DESC_SIZE);
 
-	if (le32toh(desc->flags) & (RAL_RX_PHY_ERROR | RAL_RX_CRC_ERROR)) {
+	if ((le32toh(desc->flags) & RAL_RX_PHY_ERROR) ||
+	    (le32toh(desc->flags) & RAL_RX_CRC_ERROR)) {
 		/*
 		 * This should not happen since we did not request to receive
 		 * those frames when we filled RAL_TXRX_CSR2.
@@ -884,11 +957,27 @@
 		goto skip;
 	}
 
-	/* finalize mbuf */
+	MGETHDR(mnew, M_DONTWAIT, MT_DATA);
+	if (mnew == NULL) {
+		ifp->if_ierrors++;
+		goto skip;
+	}
+
+	MCLGET(mnew, M_DONTWAIT);
+	if (!(mnew->m_flags & M_EXT)) {
+		ifp->if_ierrors++;
+		m_freem(mnew);
+		goto skip;
+	}
+
 	m = data->m;
+	data->m = mnew;
+	data->buf = mtod(data->m, uint8_t *);
+
+	/* finalize mbuf */
 	m->m_pkthdr.rcvif = ifp;
 	m->m_pkthdr.len = m->m_len = (le32toh(desc->flags) >> 16) & 0xfff;
-	m->m_flags |= M_HASFCS; /* hardware appends FCS */
+	m->m_flags |= M_HASFCS;	/* h/w leaves FCS */
 
 	s = splnet();
 
@@ -897,8 +986,9 @@
 		struct ural_rx_radiotap_header *tap = &sc->sc_rxtap;
 
 		tap->wr_flags = IEEE80211_RADIOTAP_F_FCS;
-		tap->wr_chan_freq = htole16(ic->ic_ibss_chan->ic_freq);
-		tap->wr_chan_flags = htole16(ic->ic_ibss_chan->ic_flags);
+		tap->wr_rate = ural_rxrate(desc);
+		tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
+		tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
 		tap->wr_antenna = sc->rx_ant;
 		tap->wr_antsignal = desc->rssi;
 
@@ -906,8 +996,8 @@
 	}
 #endif
 
-	wh = mtod(m, struct ieee80211_frame_min *);
-	ni = ieee80211_find_rxnode(ic, wh);
+	wh = mtod(m, struct ieee80211_frame *);
+	ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
 
 	/* send the frame to the 802.11 layer */
 	ieee80211_input(ic, m, ni, desc->rssi, 0);
@@ -917,24 +1007,6 @@
 
 	splx(s);
 
-	MGETHDR(data->m, M_DONTWAIT, MT_DATA);
-	if (data->m == NULL) {
-		printf("%s: could not allocate rx mbuf\n",
-		    USBDEVNAME(sc->sc_dev));
-		return;
-	}
-
-	MCLGET(data->m, M_DONTWAIT);
-	if (!(data->m->m_flags & M_EXT)) {
-		printf("%s: could not allocate rx mbuf cluster\n",
-		    USBDEVNAME(sc->sc_dev));
-		m_freem(data->m);
-		data->m = NULL;
-		return;
-	}
-
-	data->buf = mtod(data->m, uint8_t *);
-
 	DPRINTFN(15, ("rx done\n"));
 
 skip:	/* setup a new transfer */
@@ -948,7 +1020,7 @@
  * XXX: this should depend on the destination node basic rate set.
  */
 Static int
-ural_ack_rate(int rate)
+ural_ack_rate(struct ieee80211com *ic, int rate)
 {
 	switch (rate) {
 	/* CCK rates */
@@ -957,7 +1029,7 @@
 	case 4:
 	case 11:
 	case 22:
-		return 4;
+		return (ic->ic_curmode == IEEE80211_MODE_11B) ? 4 : rate;
 
 	/* OFDM rates */
 	case 12:
@@ -986,35 +1058,19 @@
 ural_txtime(int len, int rate, uint32_t flags)
 {
 	uint16_t txtime;
-	int ceil, dbps;
 
 	if (RAL_RATE_IS_OFDM(rate)) {
-		/*
-		 * OFDM TXTIME calculation.
-		 * From IEEE Std 802.11a-1999, pp. 37.
-		 */
-		dbps = rate * 2; /* data bits per OFDM symbol */
-
-		ceil = (16 + 8 * len + 6) / dbps;
-		if ((16 + 8 * len + 6) % dbps != 0)
-			ceil++;
-
-		txtime = 16 + 4 + 4 * ceil + 6;
+		/* IEEE Std 802.11a-1999, pp. 37 */
+		txtime = (8 + 4 * len + 3 + rate - 1) / rate;
+		txtime = 16 + 4 + 4 * txtime + 6;
 	} else {
-		/*
-		 * High Rate TXTIME calculation.
-		 * From IEEE Std 802.11b-1999, pp. 28.
-		 */
-		ceil = (8 * len * 2) / rate;
-		if ((8 * len * 2) % rate != 0)
-			ceil++;
-
+		/* IEEE Std 802.11b-1999, pp. 28 */
+		txtime = (16 * len + rate - 1) / rate;
 		if (rate != 2 && (flags & IEEE80211_F_SHPREAMBLE))
-			txtime =  72 + 24 + ceil;
+			txtime +=  72 + 24;
 		else
-			txtime = 144 + 48 + ceil;
+			txtime += 144 + 48;
 	}
-
 	return txtime;
 }
 
@@ -1055,44 +1111,33 @@
 	desc->flags |= htole32(RAL_TX_NEWSEQ);
 	desc->flags |= htole32(len << 16);
 
-	if (RAL_RATE_IS_OFDM(rate))
-		desc->flags |= htole32(RAL_TX_OFDM);
-
-	desc->wme = htole16(RAL_LOGCWMAX(5) | RAL_LOGCWMIN(3) | RAL_AIFSN(2));
+	desc->wme = htole16(RAL_AIFSN(2) | RAL_LOGCWMIN(3) | RAL_LOGCWMAX(5));
 	desc->wme |= htole16(RAL_IVOFFSET(sizeof (struct ieee80211_frame)));
 
-	/*
-	 * Fill PLCP fields.
-	 */
+	/* setup PLCP fields */
+	desc->plcp_signal  = ural_plcp_signal(rate);
 	desc->plcp_service = 4;
 
-	len += 4; /* account for FCS */
+	len += IEEE80211_CRC_LEN;
 	if (RAL_RATE_IS_OFDM(rate)) {
-		/*
-		 * PLCP length field (LENGTH).
-		 * From IEEE Std 802.11a-1999, pp. 14.
-		 */
+		desc->flags |= htole32(RAL_TX_OFDM);
+
 		plcp_length = len & 0xfff;
-		desc->plcp_length = htole16((plcp_length >> 6) << 8 |
-		    (plcp_length & 0x3f));
+		desc->plcp_length_hi = plcp_length >> 6;
+		desc->plcp_length_lo = plcp_length & 0x3f;
 	} else {
-		/*
-		 * Long PLCP LENGTH field.
-		 * From IEEE Std 802.11b-1999, pp. 16.
-		 */
-		plcp_length = (8 * len * 2) / rate;
-		remainder = (8 * len * 2) % rate;
-		if (remainder != 0) {
-			if (rate == 22 && (rate - remainder) / 16 != 0)
+		plcp_length = (16 * len + rate - 1) / rate;
+		if (rate == 22) {
+			remainder = (16 * len) % 22;
+			if (remainder != 0 && remainder < 7)
 				desc->plcp_service |= RAL_PLCP_LENGEXT;
-			plcp_length++;
 		}
-		desc->plcp_length = htole16(plcp_length);
-	}
+		desc->plcp_length_hi = plcp_length >> 8;
+		desc->plcp_length_lo = plcp_length & 0xff;
 
-	desc->plcp_signal = ural_plcp_signal(rate);
-	if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
-		desc->plcp_signal |= 0x08;
+		if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
+			desc->plcp_signal |= 0x08;
+	}
 
 	desc->iv = 0;
 	desc->eiv = 0;
@@ -1103,15 +1148,14 @@
 Static int
 ural_tx_bcn(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
 {
-	struct ieee80211com *ic = &sc->sc_ic;
 	struct ural_tx_desc *desc;
 	usbd_xfer_handle xfer;
-	usbd_status error;
 	uint8_t cmd = 0;
+	usbd_status error;
 	uint8_t *buf;
 	int xferlen, rate;
 
-	rate = IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ? 12 : 4;
+	rate = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? 12 : 2;
 
 	xfer = usbd_alloc_xfer(sc->sc_udev);
 	if (xfer == NULL)
@@ -1168,7 +1212,8 @@
 	data = &sc->tx_data[0];
 	desc = (struct ural_tx_desc *)data->buf;
 
-	rate = IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ? 12 : 4;
+	rate = IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ? 12 : 2;
+
 	data->m = m0;
 	data->ni = ni;
 
@@ -1181,9 +1226,10 @@
 		*(uint16_t *)wh->i_dur = htole16(dur);
 
 		/* tell hardware to add timestamp for probe responses */
-		if ((wh->i_fc[0] &
-		    (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) ==
-		    (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP))
+		if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
+		    IEEE80211_FC0_TYPE_MGT &&
+		    (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
+		    IEEE80211_FC0_SUBTYPE_PROBE_RESP)
 			flags |= RAL_TX_TIMESTAMP;
 	}
 
@@ -1204,20 +1250,26 @@
 	m_copydata(m0, 0, m0->m_pkthdr.len, data->buf + RAL_TX_DESC_SIZE);
 	ural_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate);
 
-	/* xfer length needs to be a multiple of two! */
+	/* align end on a 2-bytes boundary */
 	xferlen = (RAL_TX_DESC_SIZE + m0->m_pkthdr.len + 1) & ~1;
 
+	/*
+	 * No space left in the last URB to store the extra 2 bytes, force
+	 * sending of another URB.
+	 */
+	if ((xferlen % 64) == 0)
+		xferlen += 2;
+
 	DPRINTFN(10, ("sending mgt frame len=%u rate=%u xfer len=%u\n",
 	    m0->m_pkthdr.len, rate, xferlen));
 
-	usbd_setup_xfer(data->xfer, sc->sc_tx_pipeh, data, data->buf, xferlen,
-	    USBD_FORCE_SHORT_XFER | USBD_NO_COPY, RAL_TX_TIMEOUT, ural_txeof);
+	usbd_setup_xfer(data->xfer, sc->sc_tx_pipeh, data, data->buf,
+	    xferlen, USBD_FORCE_SHORT_XFER | USBD_NO_COPY, RAL_TX_TIMEOUT,
+	    ural_txeof);
 
 	error = usbd_transfer(data->xfer);
-	if (error != USBD_NORMAL_COMPLETION && error != USBD_IN_PROGRESS) {
-		m_freem(m0);
+	if (error != USBD_NORMAL_COMPLETION && error != USBD_IN_PROGRESS)
 		return error;
-	}
 
 	sc->tx_queued++;
 
@@ -1228,7 +1280,6 @@
 ural_tx_data(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
 {
 	struct ieee80211com *ic = &sc->sc_ic;
-	struct ieee80211_rateset *rs;
 	struct ural_tx_desc *desc;
 	struct ural_tx_data *data;
 	struct ieee80211_frame *wh;
@@ -1240,18 +1291,11 @@
 
 	wh = mtod(m0, struct ieee80211_frame *);
 
-	/* XXX this should be reworked! */
-	if (ic->ic_fixed_rate != -1) {
-		if (ic->ic_curmode != IEEE80211_MODE_AUTO)
-			rs = &ic->ic_sup_rates[ic->ic_curmode];
-		else
-			rs = &ic->ic_sup_rates[IEEE80211_MODE_11G];
+	if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE)
+		rate = ic->ic_bss->ni_rates.rs_rates[ic->ic_fixed_rate];
+	else
+		rate = ni->ni_rates.rs_rates[ni->ni_txrate];
 
-		rate = rs->rs_rates[ic->ic_fixed_rate];
-	} else {
-		rs = &ni->ni_rates;
-		rate = rs->rs_rates[ni->ni_txrate];
-	}
 	rate &= IEEE80211_RATE_VAL;
 
 	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
@@ -1265,20 +1309,6 @@
 		wh = mtod(m0, struct ieee80211_frame *);
 	}
 
-#if NBPFILTER > 0
-	if (sc->sc_drvbpf != NULL) {
-		struct ural_tx_radiotap_header *tap = &sc->sc_txtap;
-
-		tap->wt_flags = 0;
-		tap->wt_rate = rate;
-		tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
-		tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags);
-		tap->wt_antenna = sc->tx_ant;
-
-		bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m0);
-	}
-#endif
-
 	data = &sc->tx_data[0];
 	desc = (struct ural_tx_desc *)data->buf;
 
@@ -1289,28 +1319,48 @@
 		flags |= RAL_TX_ACK;
 		flags |= RAL_TX_RETRY(7);
 
-		dur = ural_txtime(RAL_ACK_SIZE, ural_ack_rate(rate),
+		dur = ural_txtime(RAL_ACK_SIZE, ural_ack_rate(ic, rate),
 		    ic->ic_flags) + RAL_SIFS;
 		*(uint16_t *)wh->i_dur = htole16(dur);
 	}
 
+#if NBPFILTER > 0
+	if (sc->sc_drvbpf != NULL) {
+		struct ural_tx_radiotap_header *tap = &sc->sc_txtap;
+
+		tap->wt_flags = 0;
+		tap->wt_rate = rate;
+		tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
+		tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags);
+		tap->wt_antenna = sc->tx_ant;
+
+		bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m0);
+	}
+#endif
+
 	m_copydata(m0, 0, m0->m_pkthdr.len, data->buf + RAL_TX_DESC_SIZE);
 	ural_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate);
 
-	/* xfer length needs to be a multiple of two! */
+	/* align end on a 2-bytes boundary */
 	xferlen = (RAL_TX_DESC_SIZE + m0->m_pkthdr.len + 1) & ~1;
 
+	/*
+	 * No space left in the last URB to store the extra 2 bytes, force
+	 * sending of another URB.
+	 */
+	if ((xferlen % 64) == 0)
+		xferlen += 2;
+
 	DPRINTFN(10, ("sending data frame len=%u rate=%u xfer len=%u\n",
 	    m0->m_pkthdr.len, rate, xferlen));
 
-	usbd_setup_xfer(data->xfer, sc->sc_tx_pipeh, data, data->buf, xferlen,
-	    USBD_FORCE_SHORT_XFER | USBD_NO_COPY, RAL_TX_TIMEOUT, ural_txeof);
+	usbd_setup_xfer(data->xfer, sc->sc_tx_pipeh, data, data->buf,
+	    xferlen, USBD_FORCE_SHORT_XFER | USBD_NO_COPY, RAL_TX_TIMEOUT,
+	    ural_txeof);
 
 	error = usbd_transfer(data->xfer);
-	if (error != USBD_NORMAL_COMPLETION && error != USBD_IN_PROGRESS) {
-		m_freem(m0);
+	if (error != USBD_NORMAL_COMPLETION && error != USBD_IN_PROGRESS)
 		return error;
-	}
 
 	sc->tx_queued++;
 
@@ -1322,9 +1372,9 @@
 {
 	struct ural_softc *sc = ifp->if_softc;
 	struct ieee80211com *ic = &sc->sc_ic;
+	struct mbuf *m0;
 	struct ether_header *eh;
 	struct ieee80211_node *ni;
-	struct mbuf *m0;
 
 	for (;;) {
 		IF_POLL(&ic->ic_mgtq, m0);
@@ -1402,7 +1452,7 @@
 	if (sc->sc_tx_timer > 0) {
 		if (--sc->sc_tx_timer == 0) {
 			printf("%s: device timeout\n", USBDEVNAME(sc->sc_dev));
-			/*ural_init(ifp); XXX needs a process context! */
+			/*ural_init(sc); XXX needs a process context! */
 			ifp->if_oerrors++;
 			return;
 		}
@@ -1412,12 +1462,30 @@
 	ieee80211_watchdog(ic);
 }
 
+/*
+ * This function allows for fast channel switching in monitor mode (used by
+ * net-mgmt/kismet). In IBSS mode, we must explicitly reset the interface to
+ * generate a new beacon frame.
+ */
+Static int
+ural_reset(struct ifnet *ifp)
+{
+	struct ural_softc *sc = ifp->if_softc;
+	struct ieee80211com *ic = &sc->sc_ic;
+
+	if (ic->ic_opmode != IEEE80211_M_MONITOR)
+		return ENETRESET;
+
+	ural_set_chan(sc, ic->ic_curchan);
+
+	return 0;
+}
+
 Static int
 ural_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
 {
 	struct ural_softc *sc = ifp->if_softc;
 	struct ieee80211com *ic = &sc->sc_ic;
-	struct ifreq *ifr;
 	int s, error = 0;
 
 	s = splnet();
@@ -1435,31 +1503,6 @@
 		}
 		break;
 
-	case SIOCADDMULTI:
-	case SIOCDELMULTI:
-		ifr = (struct ifreq *)data;
-		error = (cmd == SIOCADDMULTI) ?
-		    ether_addmulti(ifr, &sc->sc_ec) :
-		    ether_delmulti(ifr, &sc->sc_ec);
-
-		if (error == ENETRESET)
-			error = 0;
-		break;
-
-	case SIOCS80211CHANNEL:
-		/*
-		 * This allows for fast channel switching in monitor mode
-		 * (used by kismet). In IBSS mode, we must explicitly reset
-		 * the interface to generate a new beacon frame.
-		 */
-		error = ieee80211_ioctl(ic, cmd, data);
-		if (error == ENETRESET &&
-		    ic->ic_opmode == IEEE80211_M_MONITOR) {
-			ural_set_chan(sc, ic->ic_ibss_chan);
-			error = 0;
-		}
-		break;
-
 	default:
 		error = ieee80211_ioctl(ic, cmd, data);
 	}
@@ -1477,6 +1520,25 @@
 }
 
 Static void
+ural_set_testmode(struct ural_softc *sc)
+{
+	usb_device_request_t req;
+	usbd_status error;
+
+	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+	req.bRequest = RAL_VENDOR_REQUEST;
+	USETW(req.wValue, 4);
+	USETW(req.wIndex, 1);
+	USETW(req.wLength, 0);
+
+	error = usbd_do_request(sc->sc_udev, &req, NULL);
+	if (error != 0) {
+		printf("%s: could not set test mode: %s\n",
+		    USBDEVNAME(sc->sc_dev), usbd_errstr(error));
+	}
+}
+
+Static void
 ural_eeprom_read(struct ural_softc *sc, uint16_t addr, void *buf, int len)
 {
 	usb_device_request_t req;
@@ -1534,7 +1596,6 @@
 	if (error != 0) {
 		printf("%s: could not read MAC register: %s\n",
 		    USBDEVNAME(sc->sc_dev), usbd_errstr(error));
-		return;
 	}
 }
 
@@ -1644,7 +1705,6 @@
 Static void
 ural_set_chan(struct ural_softc *sc, struct ieee80211_channel *c)
 {
-#define N(a)	(sizeof (a) / sizeof ((a)[0]))
 	struct ieee80211com *ic = &sc->sc_ic;
 	uint8_t power, tmp;
 	u_int i, chan;
@@ -1658,6 +1718,9 @@
 	else
 		power = 31;
 
+	/* adjust txpower using ifconfig settings */
+	power -= (100 - ic->ic_txpowlimit) / 8;
+
 	DPRINTFN(2, ("setting channel to %u, txpower to %u\n", chan, power));
 
 	switch (sc->rf_rev) {
@@ -1712,16 +1775,12 @@
 
 	/* dual-band RF */
 	case RAL_RF_5222:
-		for (i = 0; i < N(ural_rf5222); i++)
-			if (ural_rf5222[i].chan == chan)
-				break;
+		for (i = 0; i < ural_rf5222[i].chan != chan; i++);
 
-		if (i < N(ural_rf5222)) {
-			ural_rf_write(sc, RAL_RF1, ural_rf5222[i].r1);
-			ural_rf_write(sc, RAL_RF2, ural_rf5222[i].r2);
-			ural_rf_write(sc, RAL_RF3, power << 7 | 0x00040);
-			ural_rf_write(sc, RAL_RF4, ural_rf5222[i].r4);
-		}
+		ural_rf_write(sc, RAL_RF1, ural_rf5222[i].r1);
+		ural_rf_write(sc, RAL_RF2, ural_rf5222[i].r2);
+		ural_rf_write(sc, RAL_RF3, power << 7 | 0x00040);
+		ural_rf_write(sc, RAL_RF4, ural_rf5222[i].r4);
 		break;
 	}
 
@@ -1739,10 +1798,9 @@
 		/* clear CRC errors */
 		ural_read(sc, RAL_STA_CSR0);
 
-		DELAY(1000); /* RF needs a 1ms delay here */
+		DELAY(10000);
 		ural_disable_rf_tune(sc);
 	}
-#undef N
 }
 
 /*
@@ -1797,6 +1855,64 @@
 }
 
 Static void
+ural_update_slot(struct ifnet *ifp)
+{
+	struct ural_softc *sc = ifp->if_softc;
+	struct ieee80211com *ic = &sc->sc_ic;
+	uint16_t slottime, sifs, eifs;
+
+	slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20;
+
+	/*
+	 * These settings may sound a bit inconsistent but this is what the
+	 * reference driver does.
+	 */
+	if (ic->ic_curmode == IEEE80211_MODE_11B) {
+		sifs = 16 - RAL_RXTX_TURNAROUND;
+		eifs = 364;
+	} else {
+		sifs = 10 - RAL_RXTX_TURNAROUND;
+		eifs = 64;
+	}
+
+	ural_write(sc, RAL_MAC_CSR10, slottime);
+	ural_write(sc, RAL_MAC_CSR11, sifs);
+	ural_write(sc, RAL_MAC_CSR12, eifs);
+}
+
+Static void
+ural_set_txpreamble(struct ural_softc *sc)
+{
+	uint16_t tmp;
+
+	tmp = ural_read(sc, RAL_TXRX_CSR10);
+
+	tmp &= ~RAL_SHORT_PREAMBLE;
+	if (sc->sc_ic.ic_flags & IEEE80211_F_SHPREAMBLE)
+		tmp |= RAL_SHORT_PREAMBLE;
+
+	ural_write(sc, RAL_TXRX_CSR10, tmp);
+}
+
+Static void
+ural_set_basicrates(struct ural_softc *sc)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+
+	/* update basic rate set */
+	if (ic->ic_curmode == IEEE80211_MODE_11B) {
+		/* 11b basic rates: 1, 2Mbps */
+		ural_write(sc, RAL_TXRX_CSR11, 0x3);
+	} else if (IEEE80211_IS_CHAN_5GHZ(ic->ic_bss->ni_chan)) {
+		/* 11a basic rates: 6, 12, 24Mbps */
+		ural_write(sc, RAL_TXRX_CSR11, 0x150);
+	} else {
+		/* 11g basic rates: 1, 2, 5.5, 11, 6, 12, 24Mbps */
+		ural_write(sc, RAL_TXRX_CSR11, 0x15f);
+	}
+}
+
+Static void
 ural_set_bssid(struct ural_softc *sc, uint8_t *bssid)
 {
 	uint16_t tmp;
@@ -1833,8 +1949,8 @@
 Static void
 ural_update_promisc(struct ural_softc *sc)
 {
-	struct ifnet *ifp = &sc->sc_if;
-	uint16_t tmp;
+	struct ifnet *ifp = sc->sc_ic.ic_ifp;
+	uint32_t tmp;
 
 	tmp = ural_read(sc, RAL_TXRX_CSR2);
 
@@ -1943,7 +2059,7 @@
 
 	ural_bbp_write(sc, RAL_BBP_TX, tx);
 
-	/* update flags in PHY_CSR5 and PHY_CSR6 too */
+	/* update values in PHY_CSR5 and PHY_CSR6 */
 	tmp = ural_read(sc, RAL_PHY_CSR5) & ~0x7;
 	ural_write(sc, RAL_PHY_CSR5, tmp | (tx & 0x7));
 
@@ -1979,10 +2095,13 @@
 	struct ieee80211com *ic = &sc->sc_ic;
 	struct ieee80211_key *wk;
 	struct ural_rx_data *data;
-	uint16_t sta_tmp[11], tmp;
+	uint16_t tmp;
 	usbd_status error;
 	int i, ntries;
 
+	ural_set_testmode(sc);
+	ural_write(sc, 0x308, 0x00f0);	/* XXX magic */
+
 	ural_stop(ifp, 0);
 
 	/* initialize MAC registers to default values */
@@ -2007,22 +2126,21 @@
 	/* we're ready! */
 	ural_write(sc, RAL_MAC_CSR1, RAL_HOST_READY);
 
-	/* set supported basic rates (1, 2, 6, 12, 24) */
-	ural_write(sc, RAL_TXRX_CSR11, 0x153);
+	/* set basic rate set (will be updated later) */
+	ural_write(sc, RAL_TXRX_CSR11, 0x15f);
 
 	error = ural_bbp_init(sc);
 	if (error != 0)
 		goto fail;
 
 	/* set default BSS channel */
-	ic->ic_curchan = ic->ic_ibss_chan;
 	ural_set_chan(sc, ic->ic_curchan);
 
 	/* clear statistic registers (STA_CSR0 to STA_CSR10) */
-	ural_read_multi(sc, RAL_STA_CSR0, sta_tmp, sizeof sta_tmp);
+	ural_read_multi(sc, RAL_STA_CSR0, sc->sta, sizeof sc->sta);
 
-	ural_set_txantenna(sc, 1);
-	ural_set_rxantenna(sc, 1);
+	ural_set_txantenna(sc, sc->tx_ant);
+	ural_set_rxantenna(sc, sc->rx_ant);
 
 	IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl));
 	ural_set_macaddr(sc, ic->ic_myaddr);
@@ -2031,12 +2149,22 @@
 	 * Copy WEP keys into adapter's memory (SEC_CSR0 to SEC_CSR31).
 	 */
 	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
-		wk = &ic->ic_nw_keys[i];
+		wk = &ic->ic_crypto.cs_nw_keys[i];
 		ural_write_multi(sc, wk->wk_keyix * IEEE80211_KEYBUF_SIZE +
 		    RAL_SEC_CSR0, wk->wk_key, IEEE80211_KEYBUF_SIZE);
 	}
 
 	/*
+	 * Allocate xfer for AMRR statistics requests.
+	 */
+	sc->amrr_xfer = usbd_alloc_xfer(sc->sc_udev);
+	if (sc->amrr_xfer == NULL) {
+		printf("%s: could not allocate AMRR xfer\n",
+		    USBDEVNAME(sc->sc_dev));
+		goto fail;
+	}
+
+	/*
 	 * Open Tx and Rx USB bulk pipes.
 	 */
 	error = usbd_open_pipe(sc->sc_iface, sc->sc_tx_no, USBD_EXCLUSIVE_USE,
@@ -2097,10 +2225,11 @@
 	ifp->if_flags &= ~IFF_OACTIVE;
 	ifp->if_flags |= IFF_RUNNING;
 
-	if (ic->ic_opmode == IEEE80211_M_MONITOR)
+	if (ic->ic_opmode != IEEE80211_M_MONITOR) {
+		if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL)
+			ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
+	} else
 		ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
-	else
-		ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
 
 	return 0;
 
@@ -2128,6 +2257,11 @@
 	ural_write(sc, RAL_MAC_CSR1, RAL_RESET_ASIC | RAL_RESET_BBP);
 	ural_write(sc, RAL_MAC_CSR1, 0);
 
+	if (sc->amrr_xfer != NULL) {
+		usbd_free_xfer(sc->amrr_xfer);
+		sc->amrr_xfer = NULL;
+	}
+
 	if (sc->sc_rx_pipeh != NULL) {
 		usbd_abort_pipe(sc->sc_rx_pipeh);
 		usbd_close_pipe(sc->sc_rx_pipeh);
@@ -2161,3 +2295,155 @@
 
 	return 0;
 }
+
+#define URAL_AMRR_MIN_SUCCESS_THRESHOLD	 1
+#define URAL_AMRR_MAX_SUCCESS_THRESHOLD	10
+
+Static void
+ural_amrr_start(struct ural_softc *sc, struct ieee80211_node *ni)
+{
+	struct ural_amrr *amrr = &sc->amrr;
+	int i;
+
+	/* clear statistic registers (STA_CSR0 to STA_CSR10) */
+	ural_read_multi(sc, RAL_STA_CSR0, sc->sta, sizeof sc->sta);
+
+	amrr->success = 0;
+	amrr->recovery = 0;
+	amrr->txcnt = amrr->retrycnt = 0;
+	amrr->success_threshold = URAL_AMRR_MIN_SUCCESS_THRESHOLD;
+
+	/* set rate to some reasonable initial value */
+	for (i = ni->ni_rates.rs_nrates - 1;
+	     i > 0 && (ni->ni_rates.rs_rates[i] & IEEE80211_RATE_VAL) > 72;
+	     i--);
+
+	ni->ni_txrate = i;
+
+	callout_reset(&sc->amrr_ch, hz, ural_amrr_timeout, sc);
+}
+
+Static void
+ural_amrr_timeout(void *arg)
+{
+	struct ural_softc *sc = (struct ural_softc *)arg;
+	usb_device_request_t req;
+	int s;
+
+	s = splusb();
+
+	/*
+	 * Asynchronously read statistic registers (cleared by read).
+	 */
+	req.bmRequestType = UT_READ_VENDOR_DEVICE;
+	req.bRequest = RAL_READ_MULTI_MAC;
+	USETW(req.wValue, 0);
+	USETW(req.wIndex, RAL_STA_CSR0);
+	USETW(req.wLength, sizeof sc->sta);
+
+	usbd_setup_default_xfer(sc->amrr_xfer, sc->sc_udev, sc,
+	    USBD_DEFAULT_TIMEOUT, &req, sc->sta, sizeof sc->sta, 0,
+	    ural_amrr_update);
+	(void)usbd_transfer(sc->amrr_xfer);
+
+	splx(s);
+}
+
+Static void
+ural_amrr_update(usbd_xfer_handle xfer, usbd_private_handle priv,
+    usbd_status status)
+{
+	struct ural_softc *sc = (struct ural_softc *)priv;
+	struct ural_amrr *amrr = &sc->amrr;
+	struct ifnet *ifp = sc->sc_ic.ic_ifp;
+
+	if (status != USBD_NORMAL_COMPLETION) {
+		printf("%s: could not retrieve Tx statistics - "
+		    "cancelling automatic rate control\n",
+		    USBDEVNAME(sc->sc_dev));
+		return;
+	}
+
+	/* count TX retry-fail as Tx errors */
+	ifp->if_oerrors += sc->sta[9];
+
+	amrr->retrycnt =
+	    sc->sta[7] +	/* TX one-retry ok count */
+	    sc->sta[8] +	/* TX more-retry ok count */
+	    sc->sta[9];		/* TX retry-fail count */
+
+	amrr->txcnt =
+	    amrr->retrycnt +
+	    sc->sta[6];		/* TX no-retry ok count */
+
+	ural_ratectl(amrr, sc->sc_ic.ic_bss);
+
+	callout_reset(&sc->amrr_ch, hz, ural_amrr_timeout, sc);
+}
+
+/*-
+ * Naive implementation of the Adaptive Multi Rate Retry algorithm:
+ *     "IEEE 802.11 Rate Adaptation: A Practical Approach"
+ *     Mathieu Lacage, Hossein Manshaei, Thierry Turletti
+ *     INRIA Sophia - Projet Planete
+ *     http://www-sop.inria.fr/rapports/sophia/RR-5208.html
+ *
+ * This algorithm is particularly well suited for ural since it does not
+ * require per-frame retry statistics.  Note however that since h/w does
+ * not provide per-frame stats, we can't do per-node rate adaptation and
+ * thus automatic rate adaptation is only enabled in STA operating mode.
+ */
+#define is_success(amrr)	\
+	((amrr)->retrycnt < (amrr)->txcnt / 10)
+#define is_failure(amrr)	\
+	((amrr)->retrycnt > (amrr)->txcnt / 3)
+#define is_enough(amrr)		\
+	((amrr)->txcnt > 10)
+#define is_min_rate(ni)		\
+	((ni)->ni_txrate == 0)
+#define is_max_rate(ni)		\
+	((ni)->ni_txrate == (ni)->ni_rates.rs_nrates - 1)
+#define increase_rate(ni)	\
+	((ni)->ni_txrate++)
+#define decrease_rate(ni)	\
+	((ni)->ni_txrate--)
+#define reset_cnt(amrr)		\
+	do { (amrr)->txcnt = (amrr)->retrycnt = 0; } while (0)
+Static void
+ural_ratectl(struct ural_amrr *amrr, struct ieee80211_node *ni)
+{
+	int need_change = 0;
+
+	if (is_success(amrr) && is_enough(amrr)) {
+		amrr->success++;
+		if (amrr->success >= amrr->success_threshold &&
+		    !is_max_rate(ni)) {
+			amrr->recovery = 1;
+			amrr->success = 0;
+			increase_rate(ni);
+			need_change = 1;
+		} else {
+			amrr->recovery = 0;
+		}
+	} else if (is_failure(amrr)) {
+		amrr->success = 0;
+		if (!is_min_rate(ni)) {
+			if (amrr->recovery) {
+				amrr->success_threshold *= 2;
+				if (amrr->success_threshold >
+				    URAL_AMRR_MAX_SUCCESS_THRESHOLD)
+					amrr->success_threshold =
+					    URAL_AMRR_MAX_SUCCESS_THRESHOLD;
+			} else {
+				amrr->success_threshold =
+				    URAL_AMRR_MIN_SUCCESS_THRESHOLD;
+			}
+			decrease_rate(ni);
+			need_change = 1;
+		}
+		amrr->recovery = 0;	/* original paper was incorrect */
+	}
+
+	if (is_enough(amrr) || need_change)
+		reset_cnt(amrr);
+}
Index: if_uralreg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/if_uralreg.h,v
retrieving revision 1.2
diff -u -r1.2 if_uralreg.h
--- if_uralreg.h	11 Dec 2005 12:24:01 -0000	1.2
+++ if_uralreg.h	23 Jun 2006 17:53:39 -0000
@@ -24,6 +24,7 @@
 #define RAL_CONFIG_NO	1
 #define RAL_IFACE_INDEX 0
 
+#define RAL_VENDOR_REQUEST	0x01
 #define RAL_WRITE_MAC		0x02
 #define RAL_READ_MAC		0x03
 #define RAL_WRITE_MULTI_MAC	0x06
@@ -43,6 +44,7 @@
 #define RAL_MAC_CSR7	0x040e	/* BSSID2 */
 #define RAL_MAC_CSR8	0x0410	/* Max frame length */
 #define RAL_MAC_CSR9	0x0412	/* Timer control */
+#define RAL_MAC_CSR10	0x0414	/* Slot time */
 #define RAL_MAC_CSR11	0x0416	/* IFS */
 #define RAL_MAC_CSR12	0x0418	/* EIFS */
 #define RAL_MAC_CSR13	0x041a	/* Power mode0 */
@@ -64,6 +66,7 @@
 #define RAL_TXRX_CSR6	0x044c	/* CCK Tx BBP ID1 */
 #define RAL_TXRX_CSR7	0x044e	/* OFDM Tx BBP ID0 */
 #define RAL_TXRX_CSR8	0x0450	/* OFDM Tx BBP ID1 */
+#define RAL_TXRX_CSR10	0x0454	/* Auto responder control */
 #define RAL_TXRX_CSR11	0x0456	/* Auto responder basic rate */
 #define RAL_TXRX_CSR18	0x0464	/* Beacon interval */
 #define RAL_TXRX_CSR19	0x0466	/* Beacon/sync control */
@@ -103,6 +106,8 @@
 #define RAL_DROP_MULTICAST	(1 << 9)
 #define RAL_DROP_BROADCAST	(1 << 10)
 
+#define RAL_SHORT_PREAMBLE	(1 << 2)
+
 #define RAL_HOST_READY	(1 << 2)
 #define RAL_RESET_ASIC	(1 << 0)
 #define RAL_RESET_BBP	(1 << 1)
@@ -168,7 +173,8 @@
 	uint8_t		plcp_service;
 #define RAL_PLCP_LENGEXT	0x80
 
-	uint16_t	plcp_length;
+	uint8_t		plcp_length_lo;
+	uint8_t		plcp_length_hi;
 	uint32_t	iv;
 	uint32_t	eiv;
 } __packed;
@@ -176,6 +182,7 @@
 struct ural_rx_desc {
 	uint32_t	flags;
 #define RAL_RX_CRC_ERROR	(1 << 5)
+#define RAL_RX_OFDM		(1 << 6)
 #define RAL_RX_PHY_ERROR	(1 << 7)
 
 	uint8_t		rate;
Index: if_uralvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/if_uralvar.h,v
retrieving revision 1.4
diff -u -r1.4 if_uralvar.h
--- if_uralvar.h	11 Dec 2005 12:24:01 -0000	1.4
+++ if_uralvar.h	23 Jun 2006 17:53:39 -0000
@@ -24,7 +24,7 @@
 struct ural_rx_radiotap_header {
 	struct ieee80211_radiotap_header wr_ihdr;
 	uint8_t		wr_flags;
-	uint8_t		_pad;
+	uint8_t		wr_rate;
 	uint16_t	wr_chan_freq;
 	uint16_t	wr_chan_flags;
 	uint8_t		wr_antenna;
@@ -69,6 +69,14 @@
 	struct mbuf		*m;
 };
 
+struct ural_amrr {
+	int	txcnt;
+	int	retrycnt;
+	int	success;
+	int	success_threshold;
+	int	recovery;
+};
+
 struct ural_softc {
 	USBBASEDEVICE		sc_dev;
 	struct ethercom		sc_ec;
@@ -86,12 +94,16 @@
 	uint32_t		asic_rev;
 	uint8_t			rf_rev;
 
+	usbd_xfer_handle	amrr_xfer;
+
 	usbd_pipe_handle	sc_rx_pipeh;
 	usbd_pipe_handle	sc_tx_pipeh;
 
 	enum ieee80211_state	sc_state;
 	struct usb_task		sc_task;
 
+	struct ural_amrr	amrr;
+
 	struct ural_rx_data	rx_data[RAL_RX_LIST_COUNT];
 	struct ural_tx_data	tx_data[RAL_TX_LIST_COUNT];
 	int			tx_queued;
@@ -99,9 +111,11 @@
 	struct ieee80211_beacon_offsets sc_bo;
 
 	struct callout		scan_ch;
+	struct callout		amrr_ch;
 
 	int			sc_tx_timer;
 
+	int16_t			sta[11];
 	uint32_t		rf_regs[4];
 	uint8_t			txpow[14];
 

----Next_Part(Mon_Jun_26_00:50:16_2006_300)----