Subject: Re: rate adaptation for BSD
To: David Young <dyoung@pobox.com>
From: Jason Thorpe <thorpej@wasabisystems.com>
List: tech-net
Date: 09/22/2003 23:01:02
--Apple-Mail-2-90317060
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
charset=US-ASCII;
format=flowed
On Thursday, June 26, 2003, at 08:18 PM, David Young wrote:
> I have added rate adaptation for 802.11b APs and clients to wi.
> The performance of host APs will be especially improved. I have
> attached
> patches in the hope of getting a some review and testing.
FWIW...
Here are the same patches, updated to -current. These compile, but I
have not yet booted the resulting kernel on my Soekris AP. Tomorrow's
task.
-- Jason R. Thorpe <thorpej@wasabisystems.com>
--Apple-Mail-2-90317060
Content-Disposition: attachment;
filename=linkadapt.patch
Content-Transfer-Encoding: 7bit
Content-Type: application/octet-stream;
x-unix-mode=0644;
name="linkadapt.patch"
Index: net/if_ieee80211.h
===================================================================
RCS file: /cvsroot/src/sys/net/if_ieee80211.h,v
retrieving revision 1.36
diff -c -r1.36 if_ieee80211.h
*** net/if_ieee80211.h 2003/07/06 20:54:24 1.36
--- net/if_ieee80211.h 2003/09/23 05:49:23
***************
*** 405,410 ****
--- 405,426 ----
#define IEEE80211_INACT_MAX (300/IEEE80211_INACT_WAIT)
/*
+ * Link adaptation.
+ */
+
+ /* Buckets for frames 0-128 bytes long, 129-1024, 1025-maximum. */
+ #define IEEE80211_LADAPT_BUCKETS 3
+ #define IEEE80211_LADAPT_BUCKET0 128
+
+ #define IEEE80211_LADAPT_RETRY_LIMIT 3
+ #define IEEE80211_LADAPT_THRESH_NEW \
+ (ieee80211_ladapt_thresh_denom - ieee80211_ladapt_thresh_old)
+ #define IEEE80211_LADAPT_DECAY_NEW \
+ (ieee80211_ladapt_decay_denom - ieee80211_ladapt_decay_old)
+ #define IEEE80211_LADAPT_AVGRSSI_NEW \
+ (ieee80211_ladapt_avgrssi_denom - ieee80211_ladapt_avgrssi_old)
+
+ /*
* Structure for IEEE 802.11 drivers.
*/
***************
*** 448,453 ****
--- 464,471 ----
/* hardware */
u_int8_t ni_rssi;
+ /* exponential averave RSSI << 8 */
+ u_int16_t ni_avg_rssi;
u_int32_t ni_rstamp;
/* header */
***************
*** 478,486 ****
--- 496,520 ----
int ni_fails; /* failure count to associate */
int ni_inact; /* inactivity mark count */
int ni_txrate; /* index to ni_rates[] */
+ /* RSSI threshold for each Tx rate */
+ u_int16_t ni_rate_thresh[IEEE80211_LADAPT_BUCKETS]
+ [IEEE80211_RATE_SIZE];
+ u_char ni_rate_used[IEEE80211_LADAPT_BUCKETS]
+ [howmany(IEEE80211_RATE_SIZE,NBBY)];
+ u_char ni_rate_fail[IEEE80211_LADAPT_BUCKETS]
+ [howmany(IEEE80211_RATE_SIZE,NBBY)];
+
void *ni_private; /* driver private */
};
+ /* Properties of a Tx packet, for link adaptation. */
+ struct ieee80211_txinfo {
+ u_int i_len; /* Tx packet length */
+ u_int i_rateidx; /* index into ni->ni_rates */
+ u_int8_t i_dstaddr[IEEE80211_ADDR_LEN]; /* destination STA MAC */
+ u_int8_t i_rssi; /* destination STA avg RSS @ Tx time */
+ };
+
/* ni_chan encoding for FH phy */
#define IEEE80211_FH_CHANMOD 80
#define IEEE80211_FH_CHAN(set,pat) (((set)-1)*IEEE80211_FH_CHANMOD+(pat))
***************
*** 539,544 ****
--- 573,579 ----
int ic_mgt_timer; /* mgmt timeout */
int ic_scan_timer; /* scant wait */
int ic_inact_timer; /* inactivity timer wait */
+ int ic_ladapt_timer;/* link adaptation debug timer*/
int ic_des_esslen;
u_int8_t ic_des_essid[IEEE80211_NWID_LEN];
int ic_des_chan; /* desired channel */
***************
*** 549,554 ****
--- 584,590 ----
u_int32_t ic_iv; /* initial vector for wep */
u_int32_t ic_aid_bitmap[IEEE80211_MAX_AID / 32 + 1];
u_int16_t ic_max_aid;
+ struct callout ic_ladapt_ch; /* decay of RSS thresholds */
struct ifmedia ic_media;
};
#ifdef __NetBSD__
***************
*** 627,632 ****
--- 663,673 ----
void ieee80211_pwrsave(struct ieee80211com *, struct ieee80211_node *,
struct mbuf *);
+
+ int ieee80211_choose_rate(struct ieee80211com *, struct ieee80211_frame *,
+ u_int);
+ void ieee80211_lower_rate(struct ieee80211com *, struct ieee80211_txinfo *);
+ void ieee80211_raise_rate(void *);
int ieee80211_media_change(struct ifnet *);
void ieee80211_media_status(struct ifnet *, struct ifmediareq *);
Index: net/if_ieee80211subr.c
===================================================================
RCS file: /cvsroot/src/sys/net/if_ieee80211subr.c,v
retrieving revision 1.43
diff -c -r1.43 if_ieee80211subr.c
*** net/if_ieee80211subr.c 2003/07/06 20:54:25 1.43
--- net/if_ieee80211subr.c 2003/09/23 05:49:28
***************
*** 82,90 ****
--- 82,113 ----
#ifdef IEEE80211_DEBUG
int ieee80211_debug = 0;
+
+ static struct timeval lastratechoice; /* time of last rate choice msg */
+ static int curchoiceps = 0; /* current rate-choice msgs/sec */
+ static int ieee80211_choicerate = 2; /* rate-choice max msgs/sec */
+
+ static struct timeval lastrateadapt; /* time of last rate adaptation msg */
+ static int curladaptps = 0; /* current rate-adaptation msgs/sec */
+ static int ieee80211_adaptrate = 4; /* rate-adaptation max msgs/sec */
+
+ #define RCHOICE_PRINTF(__ic, X) \
+ if ((__ic->ic_if.if_flags & IFF_DEBUG) && \
+ ppsratecheck(&lastratechoice, &curchoiceps, \
+ ieee80211_choicerate)) \
+ printf X
+
+ #define LADAPT_PRINTF(X) \
+ if (ieee80211_debug > 0 && \
+ ppsratecheck(&lastrateadapt, &curladaptps, \
+ ieee80211_adaptrate)) \
+ printf X
+
#define DPRINTF(X) if (ieee80211_debug) printf X
#define DPRINTF2(X) if (ieee80211_debug>1) printf X
#else
+ #define RCHOICE_PRINTF(__ic, X)
+ #define LADAPT_PRINTF(X)
#define DPRINTF(X)
#define DPRINTF2(X)
#endif
***************
*** 125,130 ****
--- 148,156 ----
static void ieee80211_crc_init(void);
static u_int32_t ieee80211_crc_update(u_int32_t, u_int8_t *, int);
+ static void ieee80211_node_raise_rate(struct ieee80211com *,
+ struct ieee80211_node *);
+
static const char *ieee80211_mgt_subtype_name[] = {
"assoc_req", "assoc_resp", "reassoc_req", "reassoc_resp",
"probe_req", "probe_resp", "reserved#6", "reserved#7",
***************
*** 132,137 ****
--- 158,173 ----
"deauth", "reserved#13", "reserved#14", "reserved#15"
};
+ /* RSS threshold decay. */
+ u_int ieee80211_ladapt_decay_denom = 8;
+ u_int ieee80211_ladapt_decay_old = 4;
+ /* RSS threshold update. */
+ u_int ieee80211_ladapt_thresh_denom = 8;
+ u_int ieee80211_ladapt_thresh_old = 4;
+ /* RSS average update. */
+ u_int ieee80211_ladapt_avgrssi_denom = 8;
+ u_int ieee80211_ladapt_avgrssi_old = 4;
+
void
ieee80211_ifattach(struct ifnet *ifp)
{
***************
*** 177,182 ****
--- 213,221 ----
if (ic->ic_max_aid == 0)
ic->ic_max_aid = IEEE80211_MAX_AID;
+ /* rate threshold decay */
+ callout_init(&ic->ic_ladapt_ch);
+
/* initialize management frame handlers */
ic->ic_recv_mgmt[IEEE80211_FC0_SUBTYPE_PROBE_RESP
>> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_beacon;
***************
*** 271,276 ****
--- 310,316 ----
free(ic->ic_wep_ctx, M_DEVBUF);
ic->ic_wep_ctx = NULL;
}
+ callout_stop(&ic->ic_ladapt_ch);
ieee80211_free_allnodes(ic);
ifmedia_delete_instance(&ic->ic_media, IFM_INST_ANY);
#if NBPFILTER > 0
***************
*** 289,295 ****
struct ether_header *eh;
void (*rh)(struct ieee80211com *, struct mbuf *, int, u_int);
struct mbuf *m1;
! int error, len;
u_int8_t dir, subtype;
u_int8_t *bssid;
u_int16_t rxseq;
--- 329,335 ----
struct ether_header *eh;
void (*rh)(struct ieee80211com *, struct mbuf *, int, u_int);
struct mbuf *m1;
! int error, len, last_avg;
u_int8_t dir, subtype;
u_int8_t *bssid;
u_int16_t rxseq;
***************
*** 350,355 ****
--- 390,403 ----
goto out;
}
ni->ni_rssi = rssi;
+ last_avg = ni->ni_avg_rssi;
+ ni->ni_avg_rssi =
+ (ieee80211_ladapt_avgrssi_old * ni->ni_avg_rssi +
+ IEEE80211_LADAPT_AVGRSSI_NEW * (ni->ni_rssi << 8)) /
+ ieee80211_ladapt_avgrssi_denom;
+ LADAPT_PRINTF(("%s: src %s rssi %d avg %d -> %d\n",
+ ic->ic_if.if_xname, ether_sprintf(wh->i_addr2),
+ ni->ni_rssi, last_avg, ni->ni_avg_rssi));
ni->ni_rstamp = rstamp;
rxseq = ni->ni_rxseq;
ni->ni_rxseq =
***************
*** 2247,2252 ****
--- 2295,2302 ----
IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_BASIC_RATE);
return;
}
+ /* use highest rate (TBD rate selection) */
+ ni->ni_txrate = ni->ni_nrate - 1;
ni->ni_rssi = rssi;
ni->ni_rstamp = rstamp;
ni->ni_intval = bintval;
***************
*** 2502,2508 ****
(*ifp->if_start)(ifp);
}
-
int
ieee80211_new_state(struct ifnet *ifp, enum ieee80211_state nstate, int mgt)
{
--- 2552,2557 ----
***************
*** 2530,2535 ****
--- 2579,2585 ----
ic->ic_state = nstate;
switch (nstate) {
case IEEE80211_S_INIT:
+ callout_stop(&ic->ic_ladapt_ch);
switch (ostate) {
case IEEE80211_S_INIT:
break;
***************
*** 2585,2590 ****
--- 2635,2641 ----
}
break;
case IEEE80211_S_SCAN:
+ ieee80211_raise_rate((void*)ic);
ic->ic_flags &= ~IEEE80211_F_SIBSS;
ni = &ic->ic_bss;
/* initialize bss for probe request */
***************
*** 2687,2692 ****
--- 2738,2744 ----
}
break;
case IEEE80211_S_RUN:
+ ieee80211_raise_rate((void*)ic);
switch (ostate) {
case IEEE80211_S_INIT:
case IEEE80211_S_AUTH:
***************
*** 3706,3709 ****
--- 3758,3953 ----
break;
}
return error;
+ }
+
+ /*
+ * If we transmitted an l-length packet at rate n in this decay period,
+ * then the RSS threshold T[l, n+1] decays, approaching T[l, n].
+ */
+ void
+ ieee80211_raise_rate(void *xic)
+ {
+ struct ieee80211com *ic = (struct ieee80211com *)xic;
+ struct ieee80211_node *ni;
+ int s;
+
+ s = splnet();
+
+ ++ic->ic_ladapt_timer;
+
+ if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
+ TAILQ_FOREACH(ni, &ic->ic_node, ni_list)
+ ieee80211_node_raise_rate(ic, ni);
+ } else {
+ ieee80211_node_raise_rate(ic, &ic->ic_bss);
+ }
+
+ callout_reset(&ic->ic_ladapt_ch, hz, ieee80211_raise_rate, xic);
+
+ splx(s);
+ }
+
+ static void
+ ieee80211_node_raise_rate(struct ieee80211com *ic, struct ieee80211_node *ni)
+ {
+ u_int16_t (*thrs)[IEEE80211_RATE_SIZE];
+ int i, j, rate;
+
+ for (i = 0; i < IEEE80211_LADAPT_BUCKETS; i++) {
+ thrs = &ni->ni_rate_thresh[i];
+ for (j = ni->ni_nrate - 1; --j >= 0; ) {
+ if (isclr(ni->ni_rate_used[i], j) ||
+ isset(ni->ni_rate_fail[i], j) ||
+ (*thrs)[j + 1] <= (*thrs)[j])
+ continue;
+
+ rate = (ni->ni_rates[j + 1] & IEEE80211_RATE_VAL);
+
+ LADAPT_PRINTF(("%s: threshold[%d, %d.%d] decay %d ",
+ ic->ic_if.if_xname,
+ IEEE80211_LADAPT_BUCKET0 << (3 * i),
+ rate / 2, rate * 5 % 10, (*thrs)[j + 1]));
+
+ (*thrs)[j + 1] =
+ (ieee80211_ladapt_decay_old * (*thrs)[j + 1] +
+ IEEE80211_LADAPT_DECAY_NEW * (*thrs)[j]) /
+ ieee80211_ladapt_decay_denom;
+
+ LADAPT_PRINTF(("-> %d\n", (*thrs)[j + 1]));
+ }
+ }
+ memset(ni->ni_rate_used, 0, sizeof(ni->ni_rate_used));
+ memset(ni->ni_rate_fail, 0, sizeof(ni->ni_rate_fail));
+
+ #ifdef IEEE80211_DEBUG
+ if ((ieee80211_debug > 0) && (ic->ic_ladapt_timer % 5 == 0)) {
+ printf("%s: dst %s thresholds\n", ic->ic_if.if_xname,
+ ether_sprintf(ni->ni_macaddr));
+ for (i = 0; i < IEEE80211_LADAPT_BUCKETS; i++) {
+ printf("%d-byte", IEEE80211_LADAPT_BUCKET0 << (3 * i));
+ for (j = 0; j < ni->ni_nrate; j++) {
+ rate = (ni->ni_rates[j] & IEEE80211_RATE_VAL);
+ printf(", T[%d.%d] = %d", rate / 2,
+ rate * 5 % 10, ni->ni_rate_thresh[i][j]);
+ }
+ printf("\n");
+ }
+ }
+ #endif /* IEEE80211_DEBUG */
+ }
+
+ /*
+ * Adapt the data rate to suit the conditions. When a transmitted
+ * packet is dropped after IEEE80211_LADAPT_RETRY_LIMIT retransmissions,
+ * raise the RSS threshold for transmitting packets of similar length at
+ * the same data rate.
+ */
+ void
+ ieee80211_lower_rate(struct ieee80211com *ic, struct ieee80211_txinfo *txi)
+ {
+ struct ieee80211_node *ni;
+ u_int16_t last_thr;
+ u_int i, thridx, top;
+ int s;
+
+ s = splnet();
+
+ if (ic->ic_opmode != IEEE80211_M_HOSTAP) {
+ ni = &ic->ic_bss;
+ } else if ((ni = ieee80211_find_node(ic, txi->i_dstaddr)) == NULL) {
+ DPRINTF(("ieee80211_lower_rate: missing node %s\n",
+ ether_sprintf(txi->i_dstaddr)));
+ splx(s);
+ return;
+ }
+
+ if (txi->i_rateidx >= ni->ni_nrate) {
+ DPRINTF(("ieee80211_lower_rate: "
+ "%s rate #%d > #%d out of bounds\n",
+ ether_sprintf(txi->i_dstaddr), txi->i_rateidx,
+ ni->ni_nrate - 1));
+ splx(s);
+ return;
+ }
+
+ for (i = 0, top = IEEE80211_LADAPT_BUCKET0;
+ i < IEEE80211_LADAPT_BUCKETS; i++, top <<= 3) {
+ thridx = i;
+ if (txi->i_len <= top)
+ break;
+ }
+
+ last_thr = ni->ni_rate_thresh[thridx][txi->i_rateidx];
+ ni->ni_rate_thresh[thridx][txi->i_rateidx] =
+ (ieee80211_ladapt_thresh_old * last_thr +
+ IEEE80211_LADAPT_THRESH_NEW * (txi->i_rssi << 8)) /
+ ieee80211_ladapt_thresh_denom;
+
+ setbit(ni->ni_rate_fail[thridx], txi->i_rateidx);
+
+ LADAPT_PRINTF(("%s: dst %s rssi %d threshold[%d, %d.%d] %d -> %d\n",
+ ic->ic_if.if_xname, ether_sprintf(txi->i_dstaddr),
+ txi->i_rssi, txi->i_len,
+ (ni->ni_rates[txi->i_rateidx] & IEEE80211_RATE_VAL) / 2,
+ (ni->ni_rates[txi->i_rateidx] & IEEE80211_RATE_VAL) * 5 % 10,
+ last_thr, ni->ni_rate_thresh[thridx][txi->i_rateidx]));
+
+ splx(s);
+ }
+
+ /*
+ * Choose a data rate for a packet len bytes long that suits the wireless
+ * conditions.
+ *
+ * TBD Adapt fragmentation threshold.
+ */
+ int
+ ieee80211_choose_rate(struct ieee80211com *ic, struct ieee80211_frame *wh,
+ u_int len)
+ {
+ struct ieee80211_node *ni;
+ u_int16_t (*thrs)[IEEE80211_RATE_SIZE];
+ int flags = 0, i, rateidx = 0, thridx, s, top;
+
+ s = splnet();
+
+ if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
+ flags |= IEEE80211_RATE_BASIC;
+ ni = &ic->ic_bss; /* TBD choose STA w/ lowest rate */
+ } else if (ic->ic_opmode == IEEE80211_M_STA)
+ ni = &ic->ic_bss;
+ else if ((ni = ieee80211_find_node(ic, wh->i_addr1)) == NULL)
+ goto out;
+
+ if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
+ flags |= IEEE80211_RATE_BASIC;
+
+ for (i = 0, top = IEEE80211_LADAPT_BUCKET0;
+ i < IEEE80211_LADAPT_BUCKETS; i++, top <<= 3) {
+ thridx = i;
+ if (len <= top)
+ break;
+ }
+
+ thrs = &ni->ni_rate_thresh[thridx];
+
+ /* Choose the highest rate with all the flags set. */
+ for (i = ni->ni_nrate; --i >= 0; ) {
+ rateidx = i;
+ if ((ni->ni_rates[i] & flags) != flags)
+ continue;
+ if (i == ic->ic_fixed_rate || (*thrs)[i] < ni->ni_avg_rssi)
+ break;
+ }
+
+ setbit(ni->ni_rate_used[thridx], rateidx);
+
+ RCHOICE_PRINTF(ic, ("%s: dst %s threshold[%d, %d.%d] %d < %d\n",
+ ic->ic_if.if_xname, ether_sprintf(wh->i_addr1), len,
+ (ni->ni_rates[rateidx] & IEEE80211_RATE_VAL) / 2,
+ (ni->ni_rates[rateidx] & IEEE80211_RATE_VAL) * 5 % 10,
+ (*thrs)[rateidx], ni->ni_avg_rssi));
+ out:
+ splx(s);
+ return (rateidx);
}
Index: dev/ic/wi.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/wi.c,v
retrieving revision 1.132
diff -c -r1.132 wi.c
*** dev/ic/wi.c 2003/07/06 20:01:17 1.132
--- dev/ic/wi.c 2003/09/23 05:49:31
***************
*** 121,127 ****
static int wi_get_cfg(struct ifnet *, u_long, caddr_t);
static int wi_set_cfg(struct ifnet *, u_long, caddr_t);
! static int wi_write_txrate(struct wi_softc *);
static int wi_write_wep(struct wi_softc *);
static int wi_write_multi(struct wi_softc *);
static int wi_alloc_fid(struct wi_softc *, int, int *);
--- 121,128 ----
static int wi_get_cfg(struct ifnet *, u_long, caddr_t);
static int wi_set_cfg(struct ifnet *, u_long, caddr_t);
! static int wi_cfg_txrate(struct wi_softc *);
! static int wi_write_txrate(struct wi_softc *, int);
static int wi_write_wep(struct wi_softc *);
static int wi_write_multi(struct wi_softc *);
static int wi_alloc_fid(struct wi_softc *, int, int *);
***************
*** 604,610 ****
wi_write_val(sc, WI_RID_ROAMING_MODE, sc->sc_roaming_mode);
if (sc->sc_flags & WI_FLAGS_HAS_MOR)
wi_write_val(sc, WI_RID_MICROWAVE_OVEN, sc->sc_microwave_oven);
! wi_write_txrate(sc);
wi_write_ssid(sc, WI_RID_NODENAME, sc->sc_nodename, sc->sc_nodelen);
if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
--- 605,611 ----
wi_write_val(sc, WI_RID_ROAMING_MODE, sc->sc_roaming_mode);
if (sc->sc_flags & WI_FLAGS_HAS_MOR)
wi_write_val(sc, WI_RID_MICROWAVE_OVEN, sc->sc_microwave_oven);
! wi_cfg_txrate(sc);
wi_write_ssid(sc, WI_RID_NODENAME, sc->sc_nodename, sc->sc_nodelen);
if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
***************
*** 615,620 ****
--- 616,627 ----
wi_write_val(sc, WI_RID_DTIM_PERIOD, 1);
}
+ if (sc->sc_firmware_type == WI_INTERSIL &&
+ (ic->ic_opmode == IEEE80211_M_STA ||
+ ic->ic_opmode == IEEE80211_M_HOSTAP))
+ wi_write_val(sc, WI_RID_ALT_RETRY_COUNT,
+ IEEE80211_LADAPT_RETRY_LIMIT);
+
/*
* Initialize promisc mode.
* Being in the Host-AP mode causes a great
***************
*** 654,660 ****
sc->sc_txd[i].d_len = 0;
}
}
! sc->sc_txcur = sc->sc_txnext = 0;
/* Enable desired port */
wi_cmd(sc, WI_CMD_ENABLE | sc->sc_portnum, 0, 0, 0);
--- 661,668 ----
sc->sc_txd[i].d_len = 0;
}
}
! memset(sc->sc_txinfo, 0, sizeof(sc->sc_txinfo));
! sc->sc_txcur = sc->sc_txnext = sc->sc_txinfonext = 0;
/* Enable desired port */
wi_cmd(sc, WI_CMD_ENABLE | sc->sc_portnum, 0, 0, 0);
***************
*** 842,847 ****
--- 850,891 ----
}
frmhdr.wi_tx_ctl |= htole16(WI_TXCNTL_NOCRYPT);
}
+ if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
+ ic->ic_opmode == IEEE80211_M_STA) {
+ struct ieee80211_txinfo *txi;
+
+ if (ic->ic_opmode == IEEE80211_M_STA) {
+ ni = &ic->ic_bss;
+ ni->ni_txrate = ieee80211_choose_rate(ic, wh,
+ m0->m_pkthdr.len);
+ wi_write_txrate(sc,
+ ni->ni_rates[ni->ni_txrate]);
+ } else {
+ ni = ieee80211_find_node(ic, wh->i_addr1);
+ if (ni == NULL) {
+ m_freem(m0);
+ ifp->if_oerrors++;
+ continue;
+ }
+ ni->ni_txrate = ieee80211_choose_rate(ic, wh,
+ m0->m_pkthdr.len);
+ frmhdr.wi_tx_rate =
+ (ni->ni_rates[ni->ni_txrate] &
+ IEEE80211_RATE_VAL) * 5;
+ }
+
+ frmhdr.wi_tx_idx = sc->sc_txinfonext;
+ sc->sc_txinfonext = (sc->sc_txinfonext + 1) % WI_NTXBUF;
+
+ txi = &sc->sc_txinfo[frmhdr.wi_tx_idx];
+
+ txi->i_rateidx = ni->ni_txrate;
+ txi->i_rssi = ni->ni_rssi;
+ txi->i_len = m0->m_pkthdr.len;
+
+ IEEE80211_ADDR_COPY(txi->i_dstaddr, wh->i_addr1);
+ frmhdr.wi_tx_ctl |= htole16(WI_TXCNTL_ALTRTRY);
+ }
m_copydata(m0, 0, sizeof(struct ieee80211_frame),
(caddr_t)&frmhdr.wi_whdr);
m_adj(m0, sizeof(struct ieee80211_frame));
***************
*** 1294,1335 ****
struct ifnet *ifp = &ic->ic_if;
struct wi_frame frmhdr;
int fid;
fid = CSR_READ_2(sc, WI_TX_CMP_FID);
/* Read in the frame header */
! if (wi_read_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr)) == 0) {
! u_int16_t status = le16toh(frmhdr.wi_status);
! /*
! * Spontaneous station disconnects appear as xmit
! * errors. Don't announce them and/or count them
! * as an output error.
! */
! if ((status & WI_TXSTAT_DISCONNECT) == 0) {
! if (ppsratecheck(&lasttxerror, &curtxeps, wi_txerate)) {
! curtxeps = 0;
! printf("%s: tx failed", sc->sc_dev.dv_xname);
! if (status & WI_TXSTAT_RET_ERR)
! printf(", retry limit exceeded");
! if (status & WI_TXSTAT_AGED_ERR)
! printf(", max transmit lifetime exceeded");
! if (status & WI_TXSTAT_DISCONNECT)
! printf(", port disconnected");
! if (status & WI_TXSTAT_FORM_ERR)
! printf(", invalid format (data len %u src %s)",
! le16toh(frmhdr.wi_dat_len),
! ether_sprintf(frmhdr.wi_ehdr.ether_shost));
! if (status & ~0xf)
! printf(", status=0x%x", status);
! printf("\n");
! }
! ifp->if_oerrors++;
! } else {
! DPRINTF(("port disconnected\n"));
! ifp->if_collisions++; /* XXX */
}
! } else
! DPRINTF(("wi_tx_ex_intr: read fid %x failed\n", fid));
CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX_EXC);
}
--- 1338,1391 ----
struct ifnet *ifp = &ic->ic_if;
struct wi_frame frmhdr;
int fid;
+ u_int16_t status;
fid = CSR_READ_2(sc, WI_TX_CMP_FID);
/* Read in the frame header */
! if (wi_read_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr)) != 0) {
! DPRINTF(("wi_tx_ex_intr: read fid %x failed\n", fid));
! goto out;
! }
! status = le16toh(frmhdr.wi_status);
!
! /*
! * Spontaneous station disconnects appear as xmit
! * errors. Don't announce them and/or count them
! * as an output error.
! */
! if ((status & WI_TXSTAT_DISCONNECT) != 0) {
! DPRINTF(("port disconnected\n"));
! ifp->if_collisions++; /* XXX */
! goto out;
! }
! if (ppsratecheck(&lasttxerror, &curtxeps, wi_txerate)) {
! curtxeps = 0;
! printf("%s: tx failed", sc->sc_dev.dv_xname);
! if (status & WI_TXSTAT_RET_ERR)
! printf(", retry limit exceeded");
! if (status & WI_TXSTAT_AGED_ERR)
! printf(", max transmit lifetime exceeded");
! if (status & WI_TXSTAT_DISCONNECT)
! printf(", port disconnected");
! if (status & WI_TXSTAT_FORM_ERR)
! printf(", invalid format (data len %u src %s)",
! le16toh(frmhdr.wi_dat_len),
! ether_sprintf(frmhdr.wi_ehdr.ether_shost));
! if (status & ~0xf)
! printf(", status=0x%x", status);
! printf("\n");
! }
! ifp->if_oerrors++;
! if ((ic->ic_opmode == IEEE80211_M_HOSTAP ||
! ic->ic_opmode == IEEE80211_M_STA) &&
! (status & WI_TXSTAT_RET_ERR) != 0) {
! if (frmhdr.wi_tx_idx >= WI_NTXBUF) {
! goto out;
}
! ieee80211_lower_rate(ic, &sc->sc_txinfo[frmhdr.wi_tx_idx]);
! }
! out:
CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX_EXC);
}
***************
*** 1824,1830 ****
ic->ic_fixed_rate = i;
}
if (sc->sc_enabled)
! error = wi_write_txrate(sc);
break;
case WI_RID_SCAN_APS:
--- 1880,1886 ----
ic->ic_fixed_rate = i;
}
if (sc->sc_enabled)
! error = wi_cfg_txrate(sc);
break;
case WI_RID_SCAN_APS:
***************
*** 1864,1887 ****
}
static int
! wi_write_txrate(struct wi_softc *sc)
{
struct ieee80211com *ic = &sc->sc_ic;
! int i;
! u_int16_t rate;
if (ic->ic_fixed_rate < 0)
rate = 0; /* auto */
else
! rate = (ic->ic_sup_rates[ic->ic_fixed_rate] &
! IEEE80211_RATE_VAL) / 2;
/* rate: 0, 1, 2, 5, 11 */
switch (sc->sc_firmware_type) {
case WI_LUCENT:
! if (rate == 0)
! rate = 3; /* auto */
break;
default:
/* Choose a bit according to this table.
--- 1920,1969 ----
}
static int
! wi_cfg_txrate(struct wi_softc *sc)
{
struct ieee80211com *ic = &sc->sc_ic;
! int rate;
+ sc->sc_tx_rate = 0; /* force write to RID */
+
if (ic->ic_fixed_rate < 0)
rate = 0; /* auto */
else
! rate = ic->ic_sup_rates[ic->ic_fixed_rate];
!
! return wi_write_txrate(sc, rate);
! }
!
! /*
! * Rate is 0 for hardware auto-select, otherwise rate is
! * 2, 4, 11, or 22 (units of 500Kbps).
! */
! static int
! wi_write_txrate(struct wi_softc *sc, int rate)
! {
! u_int16_t hwrate;
! int i;
!
! rate = (rate & IEEE80211_RATE_VAL) / 2;
/* rate: 0, 1, 2, 5, 11 */
switch (sc->sc_firmware_type) {
case WI_LUCENT:
! switch (rate) {
! case 0:
! hwrate = 3; /* auto */
! break;
! case 5:
! hwrate = 4;
! break;
! case 11:
! hwrate = 5;
! break;
! default:
! hwrate = rate;
! }
break;
default:
/* Choose a bit according to this table.
***************
*** 1898,1909 ****
break;
}
if (i == 0)
! rate = 0xf; /* auto */
else
! rate = i;
break;
}
! return wi_write_val(sc, WI_RID_TX_RATE, rate);
}
static int
--- 1980,1997 ----
break;
}
if (i == 0)
! hwrate = 0xf; /* auto */
else
! hwrate = i;
break;
}
!
! if (sc->sc_tx_rate == hwrate)
! return 0;
!
! sc->sc_tx_rate = hwrate;
!
! return wi_write_val(sc, WI_RID_TX_RATE, sc->sc_tx_rate);
}
static int
***************
*** 2308,2316 ****
--- 2396,2406 ----
ni->ni_esslen = IEEE80211_NWID_LEN; /*XXX*/
memcpy(ni->ni_essid, ssid.wi_ssid, ni->ni_esslen);
}
+ ieee80211_raise_rate((void*)ic);
break;
case IEEE80211_S_SCAN:
+ ieee80211_raise_rate((void*)ic);
case IEEE80211_S_AUTH:
case IEEE80211_S_ASSOC:
break;
Index: dev/ic/wi_ieee.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/wi_ieee.h,v
retrieving revision 1.20
diff -c -r1.20 wi_ieee.h
*** dev/ic/wi_ieee.h 2003/04/08 04:31:25 1.20
--- dev/ic/wi_ieee.h 2003/09/23 05:49:31
***************
*** 236,241 ****
--- 236,242 ----
#define WI_RID_WEP_MAPTABLE 0xFC29
#define WI_RID_CNFAUTHMODE 0xFC2A
#define WI_RID_ROAMING_MODE 0xFC2D
+ #define WI_RID_ALT_RETRY_COUNT 0xFC32 /* retry count if WI_TXCNTL_ALTRTRY */
#define WI_RID_OWN_BEACON_INT 0xFC33 /* beacon xmit time for BSS creation */
#define WI_RID_SET_TIM 0xFC40
#define WI_RID_DBM_ADJUST 0xFC46 /* RSSI - WI_RID_DBM_ADJUST ~ dBm */
Index: dev/ic/wireg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/wireg.h,v
retrieving revision 1.45
diff -c -r1.45 wireg.h
*** dev/ic/wireg.h 2003/05/13 08:35:58 1.45
--- dev/ic/wireg.h 2003/09/23 05:49:32
***************
*** 544,549 ****
--- 544,555 ----
struct ether_header wi_ehdr; /* 0x2e */
} __attribute__((__packed__));
+ /* Software support fields are returned untouched by TxOK, TxExc events. */
+ #define wi_tx_swsup0 wi_rx_silence
+ #define wi_tx_swsup1 wi_rx_signal
+ #define wi_tx_swsup2 wi_rx_rate
+ #define wi_tx_idx wi_rx_flow
+
/* Tx Status Field */
#define WI_TXSTAT_RET_ERR 0x0001
#define WI_TXSTAT_AGED_ERR 0x0002
Index: dev/ic/wivar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/wivar.h,v
retrieving revision 1.36
diff -c -r1.36 wivar.h
*** dev/ic/wivar.h 2003/07/06 20:01:18 1.36
--- dev/ic/wivar.h 2003/09/23 05:49:32
***************
*** 90,95 ****
--- 90,97 ----
} sc_txd[WI_NTXBUF];
int sc_txnext;
int sc_txcur;
+ struct ieee80211_txinfo sc_txinfo[WI_NTXBUF];
+ int sc_txinfonext;
int sc_tx_timer;
int sc_scan_timer;
int sc_syn_timer;
--Apple-Mail-2-90317060--