This diff adds support for "legacy" (pre-11n) modes to MiRa,
and makes the following drivers use MiRa in non-11n modes:
iwn(4), iwm(4), athn(4), wpi(4)
This is an extension to the MiRa paper which I made up.
There is no science behind this whatsoever :-)
The way I have implemented it is to put CCK rates and OFDM rates into
different rate sets which MiRa cycles through, just like it probes through
different MIMO modes in 11n. I don't know if this is the best approach.
I have tested on iwn(4) and wpi(4) so far. It would be good to get
the other drivers tested as well. We need tests in all the modes
11a/b/g/n which a driver supports.
Especially athn(4) hostap in 11b, 11g and 11a modes should be tested.
To test 11b, you'd have to set your AP to 11b mode because running
'ifconfig iwn0 mode 11b' currently does not do what it is supposed to
do when used against an 11g AP. But this command works for testing
11g and 11a against any AP.
In general, nothing should change, except the transmit rate shown in
ifconfig can jump around a bit more.
Keep in mind that in some situations, lower rates are better than
higher rates would be, so don't expect it to go all the way up to
the fastest nominal rate. Instead, evaluate the effective throughput
(uploads/downloads/tcpbench) and latency (typing across SSH) while
using wifi. The goal is to strike a good balance between these,
rather than always using the highest theoretically possible rate.
In situations where AMRR is pathetic things could become better.
But this is hard to test unless you're unfortunate enough to be in
a situation where AMRR is a problem.
Index: dev/ic/ar5008.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/ar5008.c,v
retrieving revision 1.46
diff -u -p -r1.46 ar5008.c
--- dev/ic/ar5008.c 28 Nov 2017 04:35:39 -0000 1.46
+++ dev/ic/ar5008.c 17 Feb 2018 23:21:02 -0000
@@ -50,7 +50,6 @@
#include <netinet/if_ether.h>
#include <net80211/ieee80211_var.h>
-#include <net80211/ieee80211_amrr.h>
#include <net80211/ieee80211_mira.h>
#include <net80211/ieee80211_radiotap.h>
@@ -1011,25 +1010,19 @@ ar5008_tx_process(struct athn_softc *sc,
}
/* Update rate control statistics. */
- if (ni->ni_flags & IEEE80211_NODE_HT) {
- an->mn.frames++;
- an->mn.ampdu_size = bf->bf_m->m_pkthdr.len + IEEE80211_CRC_LEN;
- an->mn.agglen = 1; /* XXX We do not yet support Tx agg. */
- if (failcnt > 0)
- an->mn.retries += failcnt;
- if (txfail)
- an->mn.txfail++;
- if (ic->ic_state == IEEE80211_S_RUN) {
+ an->mn.frames++;
+ an->mn.ampdu_size = bf->bf_m->m_pkthdr.len + IEEE80211_CRC_LEN;
+ an->mn.agglen = 1; /* XXX We do not yet support Tx agg. */
+ if (failcnt > 0)
+ an->mn.retries += failcnt;
+ if (txfail)
+ an->mn.txfail++;
+ if (ic->ic_state == IEEE80211_S_RUN) {
#ifndef IEEE80211_STA_ONLY
- if (ic->ic_opmode != IEEE80211_M_HOSTAP ||
- ni->ni_state == IEEE80211_STA_ASSOC)
+ if (ic->ic_opmode != IEEE80211_M_HOSTAP ||
+ ni->ni_state == IEEE80211_STA_ASSOC)
#endif
- ieee80211_mira_choose(&an->mn, ic, ni);
- }
- } else {
- an->amn.amn_txcnt++;
- if (failcnt > 0)
- an->amn.amn_retrycnt++;
+ ieee80211_mira_choose(&an->mn, ic, ni);
}
DPRINTFN(5, ("Tx done qid=%d status1=%d fail count=%d\n",
qid, ds->ds_status1, failcnt));
Index: dev/ic/ar9003.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/ar9003.c,v
retrieving revision 1.46
diff -u -p -r1.46 ar9003.c
--- dev/ic/ar9003.c 19 May 2017 11:42:48 -0000 1.46
+++ dev/ic/ar9003.c 17 Feb 2018 23:25:26 -0000
@@ -1122,9 +1122,11 @@ ar9003_tx_process(struct athn_softc *sc)
failcnt += MS(ds->ds_status8, AR_TXS8_FINAL_IDX) * 2;
/* Update rate control statistics. */
+#if 0 /* TODO needs to be converted to MiRa */
an->amn.amn_txcnt++;
if (failcnt > 0)
an->amn.amn_retrycnt++;
+#endif
DPRINTFN(5, ("Tx done qid=%d status3=%d fail count=%d\n",
qid, ds->ds_status3, failcnt));
Index: dev/ic/athn.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/athn.c,v
retrieving revision 1.98
diff -u -p -r1.98 athn.c
--- dev/ic/athn.c 3 Jul 2017 09:21:09 -0000 1.98
+++ dev/ic/athn.c 17 Feb 2018 23:24:05 -0000
@@ -52,7 +52,6 @@
#include <netinet/if_ether.h>
#include <net80211/ieee80211_var.h>
-#include <net80211/ieee80211_amrr.h>
#include <net80211/ieee80211_mira.h>
#include <net80211/ieee80211_radiotap.h>
@@ -94,7 +93,6 @@ int athn_set_key(struct ieee80211com *,
struct ieee80211_key *);
void athn_delete_key(struct ieee80211com *, struct ieee80211_node *,
struct ieee80211_key *);
-void athn_iter_calib(void *, struct ieee80211_node *);
void athn_calib_to(void *);
int athn_init_calib(struct athn_softc *,
struct ieee80211_channel *, struct ieee80211_channel *);
@@ -269,9 +267,6 @@ athn_attach(struct athn_softc *sc)
timeout_set(&sc->scan_to, athn_next_scan, sc);
timeout_set(&sc->calib_to, athn_calib_to, sc);
- sc->amrr.amrr_min_success_threshold = 1;
- sc->amrr.amrr_max_success_threshold = 15;
-
ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */
ic->ic_state = IEEE80211_S_INIT;
@@ -382,13 +377,11 @@ void
athn_detach(struct athn_softc *sc)
{
struct ifnet *ifp = &sc->sc_ic.ic_if;
- struct ieee80211com *ic = &sc->sc_ic;
int qid;
timeout_del(&sc->scan_to);
timeout_del(&sc->calib_to);
- if (ic->ic_flags & IEEE80211_F_HTON)
- athn_delete_mira_nodes(sc);
+ athn_delete_mira_nodes(sc);
if (!(sc->flags & ATHN_FLAG_USB)) {
for (qid = 0; qid < ATHN_QID_COUNT; qid++)
@@ -1227,22 +1220,11 @@ athn_btcoex_disable(struct athn_softc *s
#endif
void
-athn_iter_calib(void *arg, struct ieee80211_node *ni)
-{
- struct athn_softc *sc = arg;
- struct athn_node *an = (struct athn_node *)ni;
-
- if ((ni->ni_flags & IEEE80211_NODE_HT) == 0)
- ieee80211_amrr_choose(&sc->amrr, ni, &an->amn);
-}
-
-void
athn_calib_to(void *arg)
{
extern int ticks;
struct athn_softc *sc = arg;
struct athn_ops *ops = &sc->ops;
- struct ieee80211com *ic = &sc->sc_ic;
int s;
s = splnet();
@@ -1271,12 +1253,6 @@ athn_calib_to(void *arg)
ops->next_calib(sc);
#endif
- if (ic->ic_fixed_rate == -1) {
- if (ic->ic_opmode == IEEE80211_M_STA)
- athn_iter_calib(sc, ic->ic_bss);
- else
- ieee80211_iterate_nodes(ic, athn_iter_calib, sc);
- }
timeout_add_msec(&sc->calib_to, 500);
splx(s);
}
@@ -2337,7 +2313,7 @@ athn_node_alloc(struct ieee80211com *ic)
struct athn_node *an;
an = malloc(sizeof(struct athn_node), M_DEVBUF, M_NOWAIT | M_ZERO);
- if (an && (ic->ic_flags & IEEE80211_F_HTON))
+ if (an)
ieee80211_mira_node_init(&an->mn);
return (struct ieee80211_node *)an;
}
@@ -2345,19 +2321,17 @@ athn_node_alloc(struct ieee80211com *ic)
void
athn_newassoc(struct ieee80211com *ic, struct ieee80211_node *ni, int isnew)
{
- struct athn_softc *sc = ic->ic_softc;
struct athn_node *an = (void *)ni;
struct ieee80211_rateset *rs = &ni->ni_rates;
uint8_t rate;
int ridx, i, j;
- if ((ni->ni_flags & IEEE80211_NODE_HT) == 0)
- ieee80211_amrr_node_init(&sc->amrr, &an->amn);
- else if (ic->ic_opmode == IEEE80211_M_STA)
+ if (ic->ic_opmode == IEEE80211_M_STA)
ieee80211_mira_node_init(&an->mn);
- /* Start at lowest available bit-rate, AMRR will raise. */
+ /* Start at lowest available bit-rate, Mira will raise. */
ni->ni_txrate = 0;
+ ni->ni_txmcs = 0;
for (i = 0; i < rs->rs_nrates; i++) {
rate = rs->rs_rates[i] & IEEE80211_RATE_VAL;
@@ -2381,9 +2355,6 @@ athn_newassoc(struct ieee80211com *ic, s
DPRINTFN(2, ("%d fallbacks to %d\n", i, an->fallback[i]));
}
- /* In 11n mode, start at lowest available bit-rate, MiRA will raise. */
- ni->ni_txmcs = 0;
-
for (i = 0; i <= ATHN_MCS_MAX; i++) {
/* Map MCS index to HW rate index. */
ridx = ATHN_NUM_LEGACY_RATES + i;
@@ -2416,8 +2387,7 @@ void
athn_node_leave(struct ieee80211com *ic, struct ieee80211_node *ni)
{
struct athn_node *an = (void *)ni;
- if (ic->ic_flags & IEEE80211_F_HTON)
- ieee80211_mira_cancel_timeouts(&an->mn);
+ ieee80211_mira_cancel_timeouts(&an->mn);
}
#endif
@@ -2493,8 +2463,7 @@ athn_newstate(struct ieee80211com *ic, e
timeout_del(&sc->calib_to);
- if ((ic->ic_flags & IEEE80211_F_HTON) &&
- ic->ic_state == IEEE80211_S_RUN && nstate != IEEE80211_S_RUN)
+ if (ic->ic_state == IEEE80211_S_RUN && nstate != IEEE80211_S_RUN)
athn_delete_mira_nodes(sc);
switch (nstate) {
Index: dev/ic/athnvar.h
===================================================================
RCS file: /cvs/src/sys/dev/ic/athnvar.h,v
retrieving revision 1.37
diff -u -p -r1.37 athnvar.h
--- dev/ic/athnvar.h 12 Jan 2017 16:32:28 -0000 1.37
+++ dev/ic/athnvar.h 17 Feb 2018 23:21:17 -0000
@@ -296,7 +296,6 @@ static const uint16_t ar_mcs_ndbps[][2]
#define ATHN_NUM_RATES (ATHN_NUM_LEGACY_RATES + ATHN_NUM_MCS)
struct athn_node {
struct ieee80211_node ni;
- struct ieee80211_amrr_node amn;
struct ieee80211_mira_node mn;
uint8_t ridx[ATHN_NUM_RATES];
uint8_t fallback[ATHN_NUM_RATES];
@@ -441,7 +440,6 @@ struct athn_softc {
struct timeout scan_to;
struct timeout calib_to;
- struct ieee80211_amrr amrr;
u_int flags;
#define ATHN_FLAG_PCIE (1 << 0)
Index: dev/pci/if_iwm.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwm.c,v
retrieving revision 1.224
diff -u -p -r1.224 if_iwm.c
--- dev/pci/if_iwm.c 31 Jan 2018 12:36:13 -0000 1.224
+++ dev/pci/if_iwm.c 17 Feb 2018 23:16:34 -0000
@@ -141,7 +141,6 @@
#include <netinet/if_ether.h>
#include <net80211/ieee80211_var.h>
-#include <net80211/ieee80211_amrr.h>
#include <net80211/ieee80211_mira.h>
#include <net80211/ieee80211_radiotap.h>
@@ -446,7 +445,6 @@ int iwm_disassoc(struct iwm_softc *);
int iwm_run(struct iwm_softc *);
int iwm_run_stop(struct iwm_softc *);
struct ieee80211_node *iwm_node_alloc(struct ieee80211com *);
-void iwm_calib_timeout(void *);
void iwm_setrates(struct iwm_node *);
int iwm_media_change(struct ifnet *);
void iwm_newstate_task(void *);
@@ -3577,6 +3575,8 @@ iwm_rx_tx_cmd_single(struct iwm_softc *s
struct iwm_tx_resp *tx_resp = (void *)pkt->data;
int status = le16toh(tx_resp->status.status) & IWM_TX_STATUS_MSK;
int txfail;
+ int orate = ni->ni_txrate;
+ int omcs = ni->ni_txmcs;
KASSERT(tx_resp->frame_count == 1);
@@ -3584,28 +3584,21 @@ iwm_rx_tx_cmd_single(struct iwm_softc *s
status != IWM_TX_STATUS_DIRECT_DONE);
/* Update rate control statistics. */
- if ((ni->ni_flags & IEEE80211_NODE_HT) == 0) {
- in->in_amn.amn_txcnt++;
- if (tx_resp->failure_frame > 0)
- in->in_amn.amn_retrycnt++;
- } else if (ic->ic_fixed_mcs == -1) {
- int omcs = ni->ni_txmcs;
- in->in_mn.frames += tx_resp->frame_count;
- in->in_mn.ampdu_size = le16toh(tx_resp->byte_cnt);
- in->in_mn.agglen = tx_resp->frame_count;
- if (tx_resp->failure_frame > 0)
- in->in_mn.retries += tx_resp->failure_frame;
- if (txfail)
- in->in_mn.txfail += tx_resp->frame_count;
- if (ic->ic_state == IEEE80211_S_RUN)
- ieee80211_mira_choose(&in->in_mn, ic, &in->in_ni);
- /*
- * If MiRA has chosen a new TX rate we must update
- * the firwmare's LQ rate table from process context.
- */
- if (omcs != ni->ni_txmcs)
- iwm_add_task(sc, systq, &sc->setrates_task);
- }
+ in->in_mn.frames += tx_resp->frame_count;
+ in->in_mn.ampdu_size = le16toh(tx_resp->byte_cnt);
+ in->in_mn.agglen = tx_resp->frame_count;
+ if (tx_resp->failure_frame > 0)
+ in->in_mn.retries += tx_resp->failure_frame;
+ if (txfail)
+ in->in_mn.txfail += tx_resp->frame_count;
+ if (ic->ic_state == IEEE80211_S_RUN)
+ ieee80211_mira_choose(&in->in_mn, ic, &in->in_ni);
+ /*
+ * If MiRA has chosen a new TX rate we must update
+ * the firwmare's LQ rate table from process context.
+ */
+ if (omcs != ni->ni_txmcs || orate != ni->ni_txrate)
+ iwm_add_task(sc, systq, &sc->setrates_task);
if (txfail)
ifp->if_oerrors++;
@@ -5821,7 +5814,6 @@ iwm_run(struct iwm_softc *sc)
return err;
}
- ieee80211_amrr_node_init(&sc->sc_amrr, &in->in_amn);
ieee80211_mira_node_init(&in->in_mn);
/* Start at lowest available bit-rate, AMRR will raise. */
@@ -5884,33 +5876,6 @@ iwm_node_alloc(struct ieee80211com *ic)
}
void
-iwm_calib_timeout(void *arg)
-{
- struct iwm_softc *sc = arg;
- struct ieee80211com *ic = &sc->sc_ic;
- struct iwm_node *in = (void *)ic->ic_bss;
- struct ieee80211_node *ni = &in->in_ni;
- int s, otxrate;
-
- s = splnet();
- if ((ic->ic_fixed_rate == -1 || ic->ic_fixed_mcs == -1) &&
- ((ni->ni_flags & IEEE80211_NODE_HT) == 0) &&
- ic->ic_opmode == IEEE80211_M_STA && ic->ic_bss) {
- otxrate = ni->ni_txrate;
- ieee80211_amrr_choose(&sc->sc_amrr, &in->in_ni, &in->in_amn);
- /*
- * If AMRR has chosen a new TX rate we must update
- * the firwmare's LQ rate table from process context.
- */
- if (otxrate != ni->ni_txrate)
- iwm_add_task(sc, systq, &sc->setrates_task);
- }
- splx(s);
-
- timeout_add_msec(&sc->sc_calib_to, 500);
-}
-
-void
iwm_setrates_task(void *arg)
{
struct iwm_softc *sc = arg;
@@ -7855,9 +7820,6 @@ iwm_attach(struct device *parent, struct
sc->sc_phyctxt[i].id = i;
}
- sc->sc_amrr.amrr_min_success_threshold = 1;
- sc->sc_amrr.amrr_max_success_threshold = 15;
-
/* IBSS channel undefined for now. */
ic->ic_ibss_chan = &ic->ic_channels[1];
@@ -7877,7 +7839,6 @@ iwm_attach(struct device *parent, struct
#if NBPFILTER > 0
iwm_radiotap_attach(sc);
#endif
- timeout_set(&sc->sc_calib_to, iwm_calib_timeout, sc);
timeout_set(&sc->sc_led_blink_to, iwm_led_blink_timeout, sc);
task_set(&sc->init_task, iwm_init_task, sc);
task_set(&sc->newstate_task, iwm_newstate_task, sc);
Index: dev/pci/if_iwmvar.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwmvar.h,v
retrieving revision 1.37
diff -u -p -r1.37 if_iwmvar.h
--- dev/pci/if_iwmvar.h 8 Dec 2017 21:16:01 -0000 1.37
+++ dev/pci/if_iwmvar.h 17 Feb 2018 23:12:50 -0000
@@ -353,7 +353,6 @@ struct iwm_softc {
int (*sc_newstate)(struct ieee80211com *, enum ieee80211_state, int);
int sc_newstate_pending;
- struct ieee80211_amrr sc_amrr;
struct timeout sc_calib_to;
struct timeout sc_led_blink_to;
@@ -510,7 +509,6 @@ struct iwm_node {
uint16_t in_color;
struct iwm_lq_cmd in_lq;
- struct ieee80211_amrr_node in_amn;
struct ieee80211_mira_node in_mn;
};
#define IWM_STATION_ID 0
Index: dev/pci/if_iwn.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwn.c,v
retrieving revision 1.200
diff -u -p -r1.200 if_iwn.c
--- dev/pci/if_iwn.c 1 Feb 2018 11:21:34 -0000 1.200
+++ dev/pci/if_iwn.c 17 Feb 2018 17:49:03 -0000
@@ -54,7 +54,6 @@
#include <netinet/if_ether.h>
#include <net80211/ieee80211_var.h>
-#include <net80211/ieee80211_amrr.h>
#include <net80211/ieee80211_mira.h>
#include <net80211/ieee80211_radiotap.h>
@@ -147,7 +146,6 @@ void iwn_newassoc(struct ieee80211com *
int);
int iwn_media_change(struct ifnet *);
int iwn_newstate(struct ieee80211com *, enum ieee80211_state, int);
-void iwn_iter_func(void *, struct ieee80211_node *);
void iwn_calib_timeout(void *);
int iwn_ccmp_decap(struct iwn_softc *, struct mbuf *,
struct ieee80211_node *);
@@ -536,9 +534,6 @@ iwn_attach(struct device *parent, struct
ic->ic_newstate = iwn_newstate;
ieee80211_media_init(ifp, iwn_media_change, ieee80211_media_status);
- sc->amrr.amrr_min_success_threshold = 1;
- sc->amrr.amrr_max_success_threshold = 15;
-
#if NBPFILTER > 0
iwn_radiotap_attach(sc);
#endif
@@ -1698,15 +1693,11 @@ iwn_node_alloc(struct ieee80211com *ic)
void
iwn_newassoc(struct ieee80211com *ic, struct ieee80211_node *ni, int isnew)
{
- struct iwn_softc *sc = ic->ic_if.if_softc;
struct iwn_node *wn = (void *)ni;
uint8_t rate;
int ridx, i;
- if ((ni->ni_flags & IEEE80211_NODE_HT) == 0)
- ieee80211_amrr_node_init(&sc->amrr, &wn->amn);
-
- /* Start at lowest available bit-rate, AMRR/MiRA will raise. */
+ /* Start at lowest available bit-rate, MiRA will raise. */
ni->ni_txrate = 0;
ni->ni_txmcs = 0;
@@ -1837,29 +1828,12 @@ iwn_newstate(struct ieee80211com *ic, en
}
void
-iwn_iter_func(void *arg, struct ieee80211_node *ni)
-{
- struct iwn_softc *sc = arg;
- struct iwn_node *wn = (void *)ni;
-
- if ((ni->ni_flags & IEEE80211_NODE_HT) == 0)
- ieee80211_amrr_choose(&sc->amrr, ni, &wn->amn);
-}
-
-void
iwn_calib_timeout(void *arg)
{
struct iwn_softc *sc = arg;
- struct ieee80211com *ic = &sc->sc_ic;
int s;
s = splnet();
- if (ic->ic_fixed_rate == -1) {
- if (ic->ic_opmode == IEEE80211_M_STA)
- iwn_iter_func(sc, ic->ic_bss);
- else
- ieee80211_iterate_nodes(ic, iwn_iter_func, sc);
- }
/* Force automatic TX power calibration every 60 secs. */
if (++sc->calib_cnt >= 120) {
uint32_t flags = 0;
@@ -2420,21 +2394,16 @@ iwn_tx_done(struct iwn_softc *sc, struct
KASSERT(nframes == 1); /* We don't support aggregation yet. */
/* Update rate control statistics. */
- if (data->ni->ni_flags & IEEE80211_NODE_HT) {
- wn->mn.frames += nframes;
- wn->mn.ampdu_size = len;
- wn->mn.agglen = nframes;
- if (ackfailcnt > 0)
- wn->mn.retries += ackfailcnt;
- if (txfail)
- wn->mn.txfail += nframes;
- if (ic->ic_state == IEEE80211_S_RUN)
- ieee80211_mira_choose(&wn->mn, ic, data->ni);
- } else {
- wn->amn.amn_txcnt++;
- if (ackfailcnt > 0)
- wn->amn.amn_retrycnt++;
- }
+ wn->mn.frames += nframes;
+ wn->mn.ampdu_size = len;
+ wn->mn.agglen = nframes;
+ if (ackfailcnt > 0)
+ wn->mn.retries += ackfailcnt;
+ if (txfail)
+ wn->mn.txfail += nframes;
+ if (ic->ic_state == IEEE80211_S_RUN)
+ ieee80211_mira_choose(&wn->mn, ic, data->ni);
+
if (txfail) {
DPRINTF(("%s: status=0x%x\n", __func__, status));
ifp->if_oerrors++;
Index: dev/pci/if_iwnvar.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwnvar.h,v
retrieving revision 1.33
diff -u -p -r1.33 if_iwnvar.h
--- dev/pci/if_iwnvar.h 14 Dec 2017 14:21:11 -0000 1.33
+++ dev/pci/if_iwnvar.h 17 Feb 2018 17:48:04 -0000
@@ -98,7 +98,6 @@ struct iwn_rx_ring {
struct iwn_node {
struct ieee80211_node ni; /* must be the first */
- struct ieee80211_amrr_node amn;
struct ieee80211_mira_node mn;
uint16_t disable_tid;
uint8_t id;
@@ -187,7 +186,6 @@ struct iwn_softc {
int (*sc_newstate)(struct ieee80211com *,
enum ieee80211_state, int);
- struct ieee80211_amrr amrr;
uint8_t fixed_ridx;
bus_dma_tag_t sc_dmat;
Index: dev/pci/if_wpi.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_wpi.c,v
retrieving revision 1.142
diff -u -p -r1.142 if_wpi.c
--- dev/pci/if_wpi.c 31 Jan 2018 12:36:13 -0000 1.142
+++ dev/pci/if_wpi.c 17 Feb 2018 23:25:58 -0000
@@ -54,7 +54,7 @@
#include <netinet/if_ether.h>
#include <net80211/ieee80211_var.h>
-#include <net80211/ieee80211_amrr.h>
+#include <net80211/ieee80211_mira.h>
#include <net80211/ieee80211_radiotap.h>
#include <dev/pci/if_wpireg.h>
@@ -98,7 +98,6 @@ void wpi_newassoc(struct ieee80211com *
int);
int wpi_media_change(struct ifnet *);
int wpi_newstate(struct ieee80211com *, enum ieee80211_state, int);
-void wpi_iter_func(void *, struct ieee80211_node *);
void wpi_calib_timeout(void *);
int wpi_ccmp_decap(struct wpi_softc *, struct mbuf *,
struct ieee80211_key *);
@@ -317,9 +316,6 @@ wpi_attach(struct device *parent, struct
ic->ic_newstate = wpi_newstate;
ieee80211_media_init(ifp, wpi_media_change, ieee80211_media_status);
- sc->amrr.amrr_min_success_threshold = 1;
- sc->amrr.amrr_max_success_threshold = 15;
-
#if NBPFILTER > 0
wpi_radiotap_attach(sc);
#endif
@@ -985,13 +981,11 @@ wpi_node_alloc(struct ieee80211com *ic)
void
wpi_newassoc(struct ieee80211com *ic, struct ieee80211_node *ni, int isnew)
{
- struct wpi_softc *sc = ic->ic_if.if_softc;
struct wpi_node *wn = (void *)ni;
uint8_t rate;
int ridx, i;
- ieee80211_amrr_node_init(&sc->amrr, &wn->amn);
- /* Start at lowest available bit-rate, AMRR will raise. */
+ /* Start at lowest available bit-rate, MiRa will raise. */
ni->ni_txrate = 0;
for (i = 0; i < ni->ni_rates.rs_nrates; i++) {
@@ -1043,6 +1037,12 @@ wpi_newstate(struct ieee80211com *ic, en
timeout_del(&sc->calib_to);
+ if (ic->ic_state == IEEE80211_S_RUN &&
+ ic->ic_opmode == IEEE80211_M_STA) {
+ struct wpi_node *wn = (struct wpi_node *)ic->ic_bss;
+ ieee80211_mira_cancel_timeouts(&wn->mn);
+ }
+
switch (nstate) {
case IEEE80211_S_SCAN:
/* Make the link LED blink while we're scanning. */
@@ -1092,29 +1092,12 @@ wpi_newstate(struct ieee80211com *ic, en
}
void
-wpi_iter_func(void *arg, struct ieee80211_node *ni)
-{
- struct wpi_softc *sc = arg;
- struct wpi_node *wn = (struct wpi_node *)ni;
-
- ieee80211_amrr_choose(&sc->amrr, ni, &wn->amn);
-}
-
-void
wpi_calib_timeout(void *arg)
{
struct wpi_softc *sc = arg;
- struct ieee80211com *ic = &sc->sc_ic;
int s;
s = splnet();
- /* Automatic rate control triggered every 500ms. */
- if (ic->ic_fixed_rate == -1) {
- if (ic->ic_opmode == IEEE80211_M_STA)
- wpi_iter_func(sc, ic->ic_bss);
- else
- ieee80211_iterate_nodes(ic, wpi_iter_func, sc);
- }
/* Force automatic TX power calibration every 60 secs. */
if (++sc->calib_cnt >= 120) {
@@ -1359,12 +1342,17 @@ wpi_tx_done(struct wpi_softc *sc, struct
struct wpi_node *wn = (struct wpi_node *)data->ni;
/* Update rate control statistics. */
- wn->amn.amn_txcnt++;
+ wn->mn.frames++;
+ wn->mn.ampdu_size = data->totlen + IEEE80211_CRC_LEN;
+ wn->mn.agglen = 1;
if (stat->retrycnt > 0)
- wn->amn.amn_retrycnt++;
-
- if ((letoh32(stat->status) & 0xff) != 1)
+ wn->mn.retries += stat->retrycnt;
+ if ((letoh32(stat->status) & 0xff) != 1) {
ifp->if_oerrors++;
+ wn->mn.txfail++;
+ }
+ if (ic->ic_state == IEEE80211_S_RUN)
+ ieee80211_mira_choose(&wn->mn, ic, data->ni);
/* Unmap and free mbuf. */
bus_dmamap_sync(sc->sc_dmat, data->map, 0, data->map->dm_mapsize,
@@ -1741,6 +1729,8 @@ wpi_tx(struct wpi_softc *sc, struct mbuf
totlen += IEEE80211_CCMP_HDRLEN;
}
+ data->totlen = totlen;
+
/* Prepare TX firmware command. */
cmd = &ring->cmd[ring->cur];
cmd->code = WPI_CMD_TX_DATA;
@@ -2678,6 +2668,7 @@ wpi_run(struct wpi_softc *sc)
{
struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211_node *ni = ic->ic_bss;
+ struct wpi_node *wn = (struct wpi_node *)ni;
struct wpi_node_info node;
int error;
@@ -2715,7 +2706,7 @@ wpi_run(struct wpi_softc *sc)
}
/* Fake a join to init the TX rate. */
- ((struct wpi_node *)ni)->id = WPI_ID_BSS;
+ wn->id = WPI_ID_BSS;
wpi_newassoc(ic, ni, 1);
/* Add BSS node. */
@@ -2739,6 +2730,8 @@ wpi_run(struct wpi_softc *sc)
/* Link LED always on while associated. */
wpi_set_led(sc, WPI_LED_LINK, 0, 1);
+
+ ieee80211_mira_node_init(&wn->mn);
/* Enable power-saving mode if requested by user. */
if (sc->sc_ic.ic_flags & IEEE80211_F_PMGTON)
Index: dev/pci/if_wpivar.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_wpivar.h,v
retrieving revision 1.27
diff -u -p -r1.27 if_wpivar.h
--- dev/pci/if_wpivar.h 8 Apr 2017 02:57:25 -0000 1.27
+++ dev/pci/if_wpivar.h 17 Feb 2018 22:58:27 -0000
@@ -67,6 +67,7 @@ struct wpi_tx_data {
bus_addr_t cmd_paddr;
struct mbuf *m;
struct ieee80211_node *ni;
+ uint32_t totlen;
};
struct wpi_tx_ring {
@@ -96,7 +97,7 @@ struct wpi_rx_ring {
struct wpi_node {
struct ieee80211_node ni; /* must be the first */
- struct ieee80211_amrr_node amn;
+ struct ieee80211_mira_node mn;
uint8_t id;
uint8_t ridx[IEEE80211_RATE_MAXSIZE];
};
@@ -136,7 +137,6 @@ struct wpi_softc {
int (*sc_newstate)(struct ieee80211com *,
enum ieee80211_state, int);
- struct ieee80211_amrr amrr;
uint8_t fixed_ridx;
bus_dma_tag_t sc_dmat;
Index: net80211/ieee80211_mira.c
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_mira.c,v
retrieving revision 1.11
diff -u -p -r1.11 ieee80211_mira.c
--- net80211/ieee80211_mira.c 23 Apr 2017 21:04:55 -0000 1.11
+++ net80211/ieee80211_mira.c 18 Feb 2018 15:31:22 -0000
@@ -1,7 +1,7 @@
/* $OpenBSD: ieee80211_mira.c,v 1.11 2017/04/23 21:04:55 stsp Exp $
*/
/*
- * Copyright (c) 2016 Stefan Sperling <[email protected]>
+ * Copyright (c) 2018 Stefan Sperling <[email protected]>
* Copyright (c) 2016 Theo Buehler <[email protected]>
* Copyright (c) 2006 Damien Bergamini <[email protected]>
*
@@ -22,6 +22,8 @@
#include <sys/systm.h>
#include <sys/socket.h>
+#include <lib/libkern/libkern.h>
+
#include <net/if.h>
#include <net/if_media.h>
@@ -34,16 +36,21 @@
/* Allow for aggressive down probing when channel quality changes. */
#define MIRA_AGGRESSIVE_DOWNWARDS_PROBING
-const struct ieee80211_mira_rateset * ieee80211_mira_get_rateset(int);
+const struct ieee80211_mira_rateset * ieee80211_mira_get_ht_rateset(int);
+void ieee80211_mira_get_legacy_rate(const struct ieee80211_mira_rateset **,
+ int *, struct ieee80211_node *, int);
void ieee80211_mira_probe_timeout_up(void *);
void ieee80211_mira_probe_timeout_down(void *);
-uint64_t ieee80211_mira_get_txrate(int);
+uint64_t ieee80211_mira_get_txrate(struct ieee80211_node *);
uint16_t ieee80211_mira_legacy_txtime(uint32_t, int, struct ieee80211com *);
uint32_t ieee80211_mira_ht_txtime(uint32_t, int, int);
-int ieee80211_mira_best_basic_rate(struct ieee80211_node *);
-int ieee80211_mira_ack_rate(struct ieee80211_node *);
+int ieee80211_mira_ack_rate_ht(struct ieee80211com *,
+ struct ieee80211_node *);
+int ieee80211_mira_ack_rate_legacy(struct ieee80211_node *);
uint64_t ieee80211_mira_toverhead(struct ieee80211_mira_node *,
struct ieee80211com *, struct ieee80211_node *);
+struct ieee80211_mira_goodput_stats * ieee80211_mira_get_stats(
+ struct ieee80211_mira_node *, struct ieee80211_node *);
void ieee80211_mira_update_stats(struct ieee80211_mira_node *,
struct ieee80211com *, struct ieee80211_node *);
void ieee80211_mira_reset_goodput_stats(struct ieee80211_mira_node *);
@@ -52,22 +59,31 @@ int ieee80211_mira_next_lower_intra_rate
struct ieee80211_node *);
int ieee80211_mira_next_intra_rate(struct ieee80211_mira_node *,
struct ieee80211_node *);
-const struct ieee80211_mira_rateset * ieee80211_mira_next_rateset(
- struct ieee80211_mira_node *, int);
-int ieee80211_mira_best_mcs_in_rateset(struct ieee80211_mira_node *,
+const struct ieee80211_mira_rateset * ieee80211_mira_next_ht_rateset(
+ struct ieee80211_mira_node *, int);
+const struct ieee80211_mira_rateset * ieee80211_mira_next_legacy_rateset(
+ struct ieee80211_mira_node *, struct ieee80211_node *);
+int ieee80211_mira_ensure_valid_rate(uint32_t, int);
+int ieee80211_mira_best_rate_in_rateset(struct ieee80211_mira_node *,
const struct ieee80211_mira_rateset *);
void ieee80211_mira_probe_next_rateset(struct ieee80211_mira_node *,
struct ieee80211_node *, const struct ieee80211_mira_rateset *);
-int ieee80211_mira_next_mcs(struct ieee80211_mira_node *,
+int ieee80211_mira_next_probe_rate(struct ieee80211_mira_node *,
struct ieee80211_node *);
-int ieee80211_mira_prev_mcs(struct ieee80211_mira_node *,
+int ieee80211_mira_prev_probe_rate(struct ieee80211_mira_node *,
struct ieee80211_node *);
int ieee80211_mira_probe_valid(struct ieee80211_mira_node *,
struct ieee80211_node *);
void ieee80211_mira_probe_done(struct ieee80211_mira_node *);
-int ieee80211_mira_intra_mode_ra_finished(
+int ieee80211_mira_intra_mode_ra_finished_ht(struct ieee80211_mira_node *,
+ struct ieee80211_node *);
+int ieee80211_mira_intra_mode_ra_finished_legacy(
struct ieee80211_mira_node *, struct ieee80211_node *);
-void ieee80211_mira_trigger_next_rateset(struct ieee80211_mira_node *mn,
+int ieee80211_mira_intra_mode_ra_finished(struct ieee80211_mira_node *,
+ struct ieee80211_node *);
+void ieee80211_mira_trigger_next_ht_rateset(struct ieee80211_mira_node *mn,
+ struct ieee80211_node *);
+void ieee80211_mira_trigger_next_legacy_rateset(struct ieee80211_mira_node *,
struct ieee80211_node *);
int ieee80211_mira_inter_mode_ra_finished(
struct ieee80211_mira_node *, struct ieee80211_node *);
@@ -75,16 +91,34 @@ int ieee80211_mira_best_rate(struct ieee
struct ieee80211_node *);
void ieee80211_mira_update_probe_interval(struct ieee80211_mira_node *,
struct ieee80211_mira_goodput_stats *);
-void ieee80211_mira_schedule_probe_timers(struct ieee80211_mira_node *,
+void ieee80211_mira_schedule_probe_timers_ht(struct ieee80211_mira_node *,
struct ieee80211_node *);
+void ieee80211_mira_schedule_probe_timers_legacy(
+ struct ieee80211_mira_node *, struct ieee80211_node *);
int ieee80211_mira_check_probe_timers(struct ieee80211_mira_node *,
+ struct ieee80211com *, struct ieee80211_node *);
+void ieee80211_mira_probe_next_ht_rate(struct ieee80211_mira_node *,
struct ieee80211_node *);
-void ieee80211_mira_probe_next_rate(struct ieee80211_mira_node *,
+void ieee80211_mira_probe_next_legacy_rate(struct ieee80211_mira_node *,
struct ieee80211_node *);
int ieee80211_mira_valid_tx_mcs(struct ieee80211com *, int);
-uint32_t ieee80211_mira_valid_rates(struct ieee80211com *,
+uint32_t ieee80211_mira_valid_mcs(struct ieee80211com *,
+ struct ieee80211_node *);
+uint32_t ieee80211_mira_valid_legacy_rates(struct ieee80211com *,
struct ieee80211_node *);
+uint32_t ieee80211_mira_fill_ratemask(const struct ieee80211_mira_rateset *,
+ uint32_t, int);
uint32_t ieee80211_mira_mcs_below(struct ieee80211_mira_node *, int);
+uint32_t ieee80211_mira_legacy_rates_below(struct ieee80211_mira_node *,
+ struct ieee80211_node *, int);
+void ieee80211_mira_probe_next(struct ieee80211_mira_node *,
+ struct ieee80211_node *ni);
+void ieee80211_mira_set_best_rate(struct ieee80211_mira_node *,
+ struct ieee80211_node *, struct ieee80211_mira_goodput_stats *);
+void ieee80211_mira_probe_downwards(struct ieee80211_mira_node *,
+ struct ieee80211_node *, struct ieee80211_mira_goodput_stats *);
+void ieee80211_mira_probe_upwards(struct ieee80211_mira_node *,
+ struct ieee80211_node *, struct ieee80211_mira_goodput_stats *);
/* We use fixed point arithmetic with 64 bit integers. */
#define MIRA_FP_SHIFT 21
@@ -154,28 +188,35 @@ mira_print_driver_stats(struct ieee80211
* Rate tables.
*/
-/* Index into ieee80211_mira_ratesets[] array. */
+/* Index into ieee80211_mira_legacy_ratesets[] array. */
+#define IEEE80211_MIRA_RATESET_CCK 0
+#define IEEE80211_MIRA_RATESET_OFDM 1
+
+/* Index into ieee80211_mira_ht_ratesets[] array. */
#define IEEE80211_MIRA_RATESET_SISO 0
#define IEEE80211_MIRA_RATESET_MIMO2 1
#define IEEE80211_MIRA_RATESET_MIMO3 2
#define IEEE80211_MIRA_RATESET_MIMO4 3
+#define IEEE80211_MIRA_NUM_MCS 32
#define IEEE80211_MIRA_RATESET_MAX 8 /* Maximum number of rates in a rateset.
*/
+
struct ieee80211_mira_rateset {
uint32_t nrates;
uint32_t rates[IEEE80211_MIRA_RATESET_MAX];
- uint32_t mcs_mask;
- int min_mcs;
- int max_mcs;
-} ieee80211_mira_ratesets[] = {
-/* XXX We only support MCS 0-31, for now. */
-#ifdef notyet
- /* Legacy rates on a 2GHz channel. */
- { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 }, 0x0, -1, -1 },
+ uint32_t rate_mask;
+ int min_rate;
+ int max_rate;
+} ieee80211_mira_legacy_ratesets[] = {
+
+ /* Legacy CCK rates. */
+ { 4, { 2, 4, 11, 22 }, 0x0000000f, 0, 3 },
+
+ /* Legacy OFDM rates. */
+ { 8, { 12, 18, 24, 36, 48, 72, 96, 108 }, 0x00000ff0, 4, 11 },
+
+}, ieee80211_mira_ht_ratesets[] = {
- /* Legacy rates on a 5GHz channel. */
- { 8, { 12, 18, 24, 36, 48, 72, 96, 108 }, 0x0, -1, -1 },
-#endif
/* MCS 0-7, 20MHz channel, no SGI */
{ 8, { 13, 26, 39, 52, 78, 104, 117, 130 }, 0x000000ff, 0, 7 },
@@ -189,24 +230,89 @@ struct ieee80211_mira_rateset {
{ 8, { 52, 104, 156, 208, 312, 416, 468, 520 }, 0xff000000, 24, 31 },
};
-/* XXX We only support HT rates, for now. With legacy added, these differ. */
-#define IEEE80211_MIRA_NUM_MCS IEEE80211_MIRA_NUM_RATES
-
const struct ieee80211_mira_rateset *
-ieee80211_mira_get_rateset(int mcs)
+ieee80211_mira_get_ht_rateset(int mcs)
{
const struct ieee80211_mira_rateset *rs;
int i;
- for (i = 0; i < nitems(ieee80211_mira_ratesets); i++) {
- rs = &ieee80211_mira_ratesets[i];
- if (mcs >= rs->min_mcs && mcs <= rs->max_mcs)
+ for (i = 0; i < nitems(ieee80211_mira_ht_ratesets); i++) {
+ rs = &ieee80211_mira_ht_ratesets[i];
+ if (mcs >= rs->min_rate && mcs <= rs->max_rate)
return rs;
}
panic("MCS %d is not part of any rateset", mcs);
}
+const struct ieee80211_mira_rateset *
+ieee80211_mira_get_legacy_rateset(int ridx)
+{
+ const struct ieee80211_mira_rateset *rs_cck, *rs_ofdm;
+ int i;
+
+ rs_cck = &ieee80211_mira_legacy_ratesets[IEEE80211_MIRA_RATESET_CCK];
+ rs_ofdm = &ieee80211_mira_legacy_ratesets[IEEE80211_MIRA_RATESET_OFDM];
+
+ if (rs_cck->rate_mask & (1 << ridx))
+ i = IEEE80211_MIRA_RATESET_CCK;
+ else if (rs_ofdm->rate_mask & (1 << ridx))
+ i = IEEE80211_MIRA_RATESET_OFDM;
+ else
+ panic("no rateset for rate index %d", ridx);
+
+ return &ieee80211_mira_legacy_ratesets[i];
+}
+
+void
+ieee80211_mira_get_legacy_rate(const struct ieee80211_mira_rateset **rs,
+ int *rsidx, struct ieee80211_node *ni, int txrate)
+{
+ const struct ieee80211_mira_rateset *rs_cck, *rs_ofdm;
+ int rval = ni->ni_rates.rs_rates[txrate] & IEEE80211_RATE_VAL;
+ int i;
+
+ rs_cck = &ieee80211_mira_legacy_ratesets[IEEE80211_MIRA_RATESET_CCK];
+ for (i = 0; i < rs_cck->nrates; i++) {
+ if (rs_cck->rates[i] == rval) {
+ *rs = rs_cck;
+ *rsidx = i;
+ return;
+ }
+ }
+
+ rs_ofdm = &ieee80211_mira_legacy_ratesets[IEEE80211_MIRA_RATESET_OFDM];
+ for (i = 0; i < rs_ofdm->nrates; i++) {
+ if (rs_ofdm->rates[i] == rval) {
+ *rs = rs_ofdm;
+ *rsidx = i;
+ return;
+ }
+ }
+
+ panic("rate %d is not part of any rateset", txrate);
+}
+
+int
+ieee80211_mira_ridx2txrate(int ridx, struct ieee80211_node *ni)
+{
+ const struct ieee80211_mira_rateset *rs;
+ uint8_t rval;
+ int i, rsidx;
+
+ rs = ieee80211_mira_get_legacy_rateset(ridx);
+ rsidx = ridx - rs->min_rate;
+ for (i = 0; i < ni->ni_rates.rs_nrates; i++) {
+ rval = ni->ni_rates.rs_rates[i] & IEEE80211_RATE_VAL;
+ if (rval == rs->rates[rsidx])
+ return i;
+ }
+
+ panic("tx rate index %u not found in node rateset", ridx);
+ return 0; /* not reached */
+}
+
+
/*
* Probe timers.
*/
@@ -244,13 +350,20 @@ ieee80211_mira_probe_timeout_down(void *
*/
uint64_t
-ieee80211_mira_get_txrate(int mcs)
+ieee80211_mira_get_txrate(struct ieee80211_node *ni)
{
const struct ieee80211_mira_rateset *rs;
uint64_t txrate;
- rs = ieee80211_mira_get_rateset(mcs);
- txrate = rs->rates[mcs - rs->min_mcs];
+ if (ni->ni_flags & IEEE80211_NODE_HT) {
+ rs = ieee80211_mira_get_ht_rateset(ni->ni_txmcs);
+ txrate = rs->rates[ni->ni_txmcs - rs->min_rate];
+ } else {
+ int rsidx;
+ ieee80211_mira_get_legacy_rate(&rs, &rsidx, ni, ni->ni_txrate);
+ txrate = rs->rates[rsidx];
+ }
+
txrate <<= MIRA_FP_SHIFT; /* convert to fixed-point */
txrate *= 500; /* convert to kbit/s */
txrate /= 1000; /* convert to mbit/s */
@@ -304,8 +417,8 @@ ieee80211_mira_ht_txtime(uint32_t len, i
* XXX Assumes a 20MHz channel, HT-mixed frame format, no STBC.
*/
t_plcp = t_lstf + t_lltf + t_lsig + t_htstf + 4 * t_ltstf + t_htsig;
- rs = ieee80211_mira_get_rateset(mcs);
- n_dbps = rs->rates[mcs - rs->min_mcs] * 2;
+ rs = ieee80211_mira_get_ht_rateset(mcs);
+ n_dbps = rs->rates[mcs - rs->min_rate] * 2;
n_sym = ((8 * len + 16 + 6) / n_dbps); /* "Equation (20-32)" */
t_data = t_sym * n_sym;
@@ -316,47 +429,55 @@ ieee80211_mira_ht_txtime(uint32_t len, i
return txtime;
}
-int
-ieee80211_mira_best_basic_rate(struct ieee80211_node *ni)
-{
- struct ieee80211_rateset *rs = &ni->ni_rates;
- int i, best, rval;
-
- /* Default to 1 Mbit/s on 2GHz and 6 Mbit/s on 5GHz. */
- best = IEEE80211_IS_CHAN_2GHZ(ni->ni_chan) ? 2 : 12;
-
- for (i = 0; i < rs->rs_nrates; i++) {
- if ((rs->rs_rates[i] & IEEE80211_RATE_BASIC) == 0)
- continue;
- rval = (rs->rs_rates[i] & IEEE80211_RATE_VAL);
- if (rval > best)
- best = rval;
- }
-
- return best;
-}
-
/*
* See 802.11-2012, 9.7.6.5 "Rate selection for control response frames".
* XXX Does not support BlockAck.
*/
int
-ieee80211_mira_ack_rate(struct ieee80211_node *ni)
+ieee80211_mira_ack_rate_ht(struct ieee80211com *ic, struct ieee80211_node *ni)
{
+ const struct ieee80211_mira_rateset *rs_ofdm;
+
/*
* Assume the ACK was sent at a mandatory ERP OFDM rate.
* In the worst case, the firmware has retried at non-HT rates,
* so for MCS 0 assume we didn't actually send an OFDM frame
- * and ACKs arrived at a basic rate.
+ * and ACKs arrived at the minimum basic rate.
*/
+ rs_ofdm = &ieee80211_mira_legacy_ratesets[IEEE80211_MIRA_RATESET_OFDM];
if (ni->ni_txmcs == 0)
- return ieee80211_mira_best_basic_rate(ni);
+ return ieee80211_min_basic_rate(ic);
else if (ni->ni_txmcs == 1)
- return 12; /* 6 Mbit/s */
- else if (ni->ni_txmcs >= 2)
- return 24; /* 12 Mbit/s */
+ return rs_ofdm->rates[0]; /* 6 Mbit/s */
+ else if (ni->ni_txmcs <= 3)
+ return rs_ofdm->rates[2]; /* 12 Mbit/s */
else
- return 48; /* 24 Mbit/s */
+ return rs_ofdm->rates[4]; /* 24 Mbit/s */
+}
+
+int
+ieee80211_mira_ack_rate_legacy(struct ieee80211_node *ni)
+{
+ const struct ieee80211_mira_rateset *rs_cck, *rs_ofdm;
+ const struct ieee80211_mira_rateset *rs;
+ int rsidx, ridx;
+
+ rs_cck = &ieee80211_mira_legacy_ratesets[IEEE80211_MIRA_RATESET_CCK];
+ rs_ofdm = &ieee80211_mira_legacy_ratesets[IEEE80211_MIRA_RATESET_OFDM];
+
+ ieee80211_mira_get_legacy_rate(&rs, &rsidx, ni, ni->ni_txrate);
+ ridx = rs->min_rate + rsidx;
+
+ /* For the CCK rate set, assume ACK was sent using the same rate. */
+ if (ridx <= rs_cck->max_rate)
+ return rs_cck->rates[rsidx];
+ /* For the OFDM rate set, assume a mandatory ERP OFDM rate. */
+ else if (ridx == rs_ofdm->min_rate)
+ return rs_ofdm->rates[0]; /* 6 Mbit/s */
+ else if (ridx <= rs_ofdm->min_rate + 3)
+ return rs_ofdm->rates[2]; /* 12 Mbit/s */
+ else
+ return rs_ofdm->rates[4]; /* 24 Mbit/s */
}
uint64_t
@@ -371,10 +492,17 @@ ieee80211_mira_toverhead(struct ieee8021
int rate, rts;
enum ieee80211_htprot htprot;
- overhead = ieee80211_mira_ht_txtime(0, ni->ni_txmcs,
- IEEE80211_IS_CHAN_2GHZ(ni->ni_chan));
+ if (ni->ni_flags & IEEE80211_NODE_HT) {
+ overhead = ieee80211_mira_ht_txtime(0, ni->ni_txmcs,
+ IEEE80211_IS_CHAN_2GHZ(ni->ni_chan));
+ htprot = (ic->ic_bss->ni_htop1 & IEEE80211_HTOP1_PROT_MASK);
+ } else {
+ uint8_t rval = ni->ni_rates.rs_rates[ni->ni_txrate];
+ rval &= IEEE80211_RATE_VAL;
+ ieee80211_mira_legacy_txtime(0, rval, ic);
+ htprot = IEEE80211_HTPROT_NONE;
+ }
- htprot = (ic->ic_bss->ni_htop1 & IEEE80211_HTOP1_PROT_MASK);
if (htprot == IEEE80211_HTPROT_NONMEMBER ||
htprot == IEEE80211_HTPROT_NONHT_MIXED)
rts = 1;
@@ -386,13 +514,17 @@ ieee80211_mira_toverhead(struct ieee8021
if (rts) {
/* Assume RTS/CTS were sent at a basic rate. */
- rate = ieee80211_mira_best_basic_rate(ni);
+ rate = ieee80211_min_basic_rate(ic);
overhead += ieee80211_mira_legacy_txtime(MIRA_RTSLEN, rate, ic);
overhead += ieee80211_mira_legacy_txtime(MIRA_CTSLEN, rate, ic);
}
- /* XXX This does not yet support BlockAck. */
- rate = ieee80211_mira_ack_rate(ni);
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ /* XXX This does not yet support BlockAck. */
+ rate = ieee80211_mira_ack_rate_ht(ic, ni);
+ else
+ rate = ieee80211_mira_ack_rate_legacy(ni);
+
overhead += ieee80211_mira_legacy_txtime(IEEE80211_ACK_LEN, rate, ic);
toverhead = overhead;
@@ -415,6 +547,20 @@ ieee80211_mira_toverhead(struct ieee8021
return toverhead;
}
+struct ieee80211_mira_goodput_stats *
+ieee80211_mira_get_stats(struct ieee80211_mira_node *mn,
+ struct ieee80211_node *ni)
+{
+ const struct ieee80211_mira_rateset *rs;
+ int rsidx;
+
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ return &mn->g[ni->ni_txmcs];
+
+ ieee80211_mira_get_legacy_rate(&rs, &rsidx, ni, ni->ni_txrate);
+ return &mn->g[rs->min_rate + rsidx];
+}
+
void
ieee80211_mira_update_stats(struct ieee80211_mira_node *mn,
struct ieee80211com *ic, struct ieee80211_node *ni)
@@ -425,9 +571,10 @@ ieee80211_mira_update_stats(struct ieee8
uint64_t sfer, delta, toverhead;
uint64_t agglen = mn->agglen;
uint64_t ampdu_size = mn->ampdu_size * 8; /* convert to bits */
- uint64_t rate = ieee80211_mira_get_txrate(ni->ni_txmcs);
- struct ieee80211_mira_goodput_stats *g = &mn->g[ni->ni_txmcs];
-
+ uint64_t rate = ieee80211_mira_get_txrate(ni);
+ struct ieee80211_mira_goodput_stats *g;
+
+ g = ieee80211_mira_get_stats(mn, ni);
g->nprobes += mn->agglen;
g->nprobe_bytes += mn->ampdu_size;
@@ -472,8 +619,11 @@ ieee80211_mira_update_stats(struct ieee8
g->loss = sfer * 100;
#ifdef MIRA_DEBUG
if (g->loss && ieee80211_mira_probe_valid(mn, ni))
- DPRINTFN(2, ("frame error rate at MCS %d: %s%%\n",
- ni->ni_txmcs, mira_fp_sprintf(g->loss)));
+ DPRINTFN(2, ("frame error rate at %s %d: %s%%\n",
+ (ni->ni_flags & IEEE80211_NODE_HT) ? "MCS" : "rate",
+ (ni->ni_flags & IEEE80211_NODE_HT) ?
+ ni->ni_txmcs : ni->ni_txrate,
+ mira_fp_sprintf(g->loss)));
#endif
/*
@@ -545,18 +695,27 @@ ieee80211_mira_next_lower_intra_rate(str
struct ieee80211_node *ni)
{
const struct ieee80211_mira_rateset *rs;
- int i, next;
+ int i, ridx, next;
- rs = ieee80211_mira_get_rateset(ni->ni_txmcs);
- if (ni->ni_txmcs == rs->min_mcs)
- return rs->min_mcs;
+ if (ni->ni_flags & IEEE80211_NODE_HT) {
+ rs = ieee80211_mira_get_ht_rateset(ni->ni_txmcs);
+ if (ni->ni_txmcs == rs->min_rate)
+ return rs->min_rate;
+ ridx = ni->ni_txmcs;
+ } else {
+ int rsidx;
+ ieee80211_mira_get_legacy_rate(&rs, &rsidx, ni, ni->ni_txrate);
+ if (rsidx == rs->min_rate)
+ return rs->min_rate;
+ ridx = rs->min_rate + rsidx;
+ }
- next = ni->ni_txmcs;
+ next = ridx;
for (i = rs->nrates - 1; i >= 0; i--) {
- if ((mn->valid_rates & (1 << (i + rs->min_mcs))) == 0)
+ if ((mn->valid_rates & (1 << (i + rs->min_rate))) == 0)
continue;
- if (i + rs->min_mcs < ni->ni_txmcs) {
- next = i + rs->min_mcs;
+ if (i + rs->min_rate < ridx) {
+ next = i + rs->min_rate;
break;
}
}
@@ -569,18 +728,27 @@ ieee80211_mira_next_intra_rate(struct ie
struct ieee80211_node *ni)
{
const struct ieee80211_mira_rateset *rs;
- int i, next;
+ int i, ridx, next;
- rs = ieee80211_mira_get_rateset(ni->ni_txmcs);
- if (ni->ni_txmcs == rs->max_mcs)
- return rs->max_mcs;
+ if (ni->ni_flags & IEEE80211_NODE_HT) {
+ rs = ieee80211_mira_get_ht_rateset(ni->ni_txmcs);
+ if (ni->ni_txmcs == rs->max_rate)
+ return rs->max_rate;
+ ridx = ni->ni_txmcs;
+ } else {
+ int rsidx;
+ ieee80211_mira_get_legacy_rate(&rs, &rsidx, ni, ni->ni_txrate);
+ if (rsidx == rs->max_rate)
+ return rs->max_rate;
+ ridx = rs->min_rate + rsidx;
+ }
- next = ni->ni_txmcs;
+ next = ridx;
for (i = 0; i < rs->nrates; i++) {
- if ((mn->valid_rates & (1 << (i + rs->min_mcs))) == 0)
+ if ((mn->valid_rates & (1 << (i + rs->min_rate))) == 0)
continue;
- if (i + rs->min_mcs > ni->ni_txmcs) {
- next = i + rs->min_mcs;
+ if (i + rs->min_rate > ridx) {
+ next = i + rs->min_rate;
break;
}
}
@@ -589,59 +757,99 @@ ieee80211_mira_next_intra_rate(struct ie
}
const struct ieee80211_mira_rateset *
-ieee80211_mira_next_rateset(struct ieee80211_mira_node *mn, int mcs)
+ieee80211_mira_next_ht_rateset(struct ieee80211_mira_node *mn, int mcs)
{
const struct ieee80211_mira_rateset *rs, *rsnext;
int next;
- rs = ieee80211_mira_get_rateset(mcs);
+ rs = ieee80211_mira_get_ht_rateset(mcs);
if (mn->probing & IEEE80211_MIRA_PROBING_UP) {
- if (rs->max_mcs == 7) /* MCS 0-7 */
+ if (rs->max_rate == 7) /* MCS 0-7 */
next = IEEE80211_MIRA_RATESET_MIMO2;
- else if (rs->max_mcs == 15) /* MCS 8-15 */
+ else if (rs->max_rate == 15) /* MCS 8-15 */
next = IEEE80211_MIRA_RATESET_MIMO3;
- else if (rs->max_mcs == 23) /* MCS 16-23 */
+ else if (rs->max_rate == 23) /* MCS 16-23 */
next = IEEE80211_MIRA_RATESET_MIMO4;
else /* MCS 24-31 */
return NULL;
} else if (mn->probing & IEEE80211_MIRA_PROBING_DOWN) {
- if (rs->min_mcs == 24) /* MCS 24-31 */
+ if (rs->min_rate == 24) /* MCS 24-31 */
next = IEEE80211_MIRA_RATESET_MIMO3;
- else if (rs->min_mcs == 16) /* MCS 16-23 */
+ else if (rs->min_rate == 16) /* MCS 16-23 */
next = IEEE80211_MIRA_RATESET_MIMO2;
- else if (rs->min_mcs == 8) /* MCS 8-15 */
+ else if (rs->min_rate == 8) /* MCS 8-15 */
next = IEEE80211_MIRA_RATESET_SISO;
else /* MCS 0-7 */
return NULL;
} else
panic("invalid probing mode %d", mn->probing);
- rsnext = &ieee80211_mira_ratesets[next];
- if ((rsnext->mcs_mask & mn->valid_rates) == 0)
+ rsnext = &ieee80211_mira_ht_ratesets[next];
+ if ((rsnext->rate_mask & mn->valid_rates) == 0)
+ return NULL;
+
+ return rsnext;
+}
+
+const struct ieee80211_mira_rateset *
+ieee80211_mira_next_legacy_rateset(struct ieee80211_mira_node *mn,
+ struct ieee80211_node *ni)
+{
+ const struct ieee80211_mira_rateset *rs, *rsnext;
+ int rsidx, next = -1;
+
+ ieee80211_mira_get_legacy_rate(&rs, &rsidx, ni, ni->ni_txrate);
+ if (mn->probing & IEEE80211_MIRA_PROBING_UP) {
+ if (rs->min_rate == 0) /* CCK */
+ next = IEEE80211_MIRA_RATESET_OFDM;
+ } else if (mn->probing & IEEE80211_MIRA_PROBING_DOWN) {
+ if (rs->min_rate == 4) /* OFDM */
+ next = IEEE80211_MIRA_RATESET_CCK;
+ } else
+ panic("invalid probing mode %d", mn->probing);
+
+ if (next == -1)
+ return NULL;
+
+ rsnext = &ieee80211_mira_legacy_ratesets[next];
+ if ((rsnext->rate_mask & mn->valid_rates) == 0)
return NULL;
return rsnext;
}
int
-ieee80211_mira_best_mcs_in_rateset(struct ieee80211_mira_node *mn,
+ieee80211_mira_ensure_valid_rate(uint32_t valid_rates, int ridx)
+{
+ if ((valid_rates & (1 << ridx)) == 0) {
+ ridx = ffs(valid_rates);
+ KASSERT(ridx > 1);
+ ridx--;
+ }
+
+ return ridx;
+}
+
+int
+ieee80211_mira_best_rate_in_rateset(struct ieee80211_mira_node *mn,
const struct ieee80211_mira_rateset *rs)
{
uint64_t gmax = 0;
- int i, best_mcs = rs->min_mcs;
+ int i, best;
+ struct ieee80211_mira_goodput_stats *g;
- for (i = 0; i < rs->nrates; i++) {
- int mcs = rs->min_mcs + i;
- struct ieee80211_mira_goodput_stats *g = &mn->g[mcs];
- if (((1 << mcs) & mn->valid_rates) == 0)
+ best = ieee80211_mira_ensure_valid_rate(mn->valid_rates, rs->min_rate);
+ for (i = best; i < rs->nrates; i++) {
+ if (((1 << (rs->min_rate + i)) & mn->valid_rates) == 0)
continue;
+ g = &mn->g[rs->min_rate + i];
if (g->measured > gmax + IEEE80211_MIRA_RATE_THRESHOLD) {
gmax = g->measured;
- best_mcs = mcs;
+ best = i;
}
}
- return best_mcs;
+ return best;
}
void
@@ -650,25 +858,40 @@ ieee80211_mira_probe_next_rateset(struct
{
const struct ieee80211_mira_rateset *rs;
struct ieee80211_mira_goodput_stats *g;
- int best_mcs, i;
+ int best_rsidx, best_ridx, i;
/* Find most recently measured best MCS from the current rateset. */
- rs = ieee80211_mira_get_rateset(ni->ni_txmcs);
- best_mcs = ieee80211_mira_best_mcs_in_rateset(mn, rs);
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ rs = ieee80211_mira_get_ht_rateset(ni->ni_txmcs);
+ else {
+ int rsidx;
+ ieee80211_mira_get_legacy_rate(&rs, &rsidx, ni, ni->ni_txrate);
+ }
+ best_rsidx = ieee80211_mira_best_rate_in_rateset(mn, rs);
+ best_ridx = rs->min_rate + best_rsidx;
/* Switch to the next rateset. */
- ni->ni_txmcs = rsnext->min_mcs;
- if ((mn->valid_rates & (1 << rsnext->min_mcs)) == 0)
- ni->ni_txmcs = ieee80211_mira_next_intra_rate(mn, ni);
+ if (ni->ni_flags & IEEE80211_NODE_HT) {
+ ni->ni_txmcs = rsnext->min_rate;
+ if ((mn->valid_rates & (1 << rsnext->min_rate)) == 0)
+ ni->ni_txmcs = ieee80211_mira_next_intra_rate(mn, ni);
+ } else {
+ ni->ni_txrate =
+ ieee80211_mira_ridx2txrate(rsnext->min_rate, ni);
+ if ((mn->valid_rates & (1 << rsnext->min_rate)) == 0) {
+ int ridx = ieee80211_mira_next_intra_rate(mn, ni);
+ ni->ni_txrate = ieee80211_mira_ridx2txrate(ridx, ni);
+ }
+ }
/* Select the lowest rate from the next rateset with loss-free
* goodput close to the current best measurement. */
- g = &mn->g[best_mcs];
+ g = &mn->g[best_ridx];
for (i = 0; i < rsnext->nrates; i++) {
- int mcs = rsnext->min_mcs + i;
+ int ridx = rsnext->min_rate + i;
uint64_t txrate = rsnext->rates[i];
- if ((mn->valid_rates & (1 << mcs)) == 0)
+ if ((mn->valid_rates & (1 << ridx)) == 0)
continue;
txrate = txrate * 500; /* convert to kbit/s */
@@ -676,20 +899,35 @@ ieee80211_mira_probe_next_rateset(struct
txrate /= 1000; /* convert to mbit/s */
if (txrate > g->measured + IEEE80211_MIRA_RATE_THRESHOLD) {
- ni->ni_txmcs = mcs;
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ ni->ni_txmcs = ridx;
+ else
+ ni->ni_txrate =
+ ieee80211_mira_ridx2txrate(ridx, ni);
break;
}
}
/* Add rates from the next rateset as candidates. */
- mn->candidate_rates |= (1 << ni->ni_txmcs);
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ mn->candidate_rates |= (1 << ni->ni_txmcs);
+ else {
+ int rsidx;
+ ieee80211_mira_get_legacy_rate(&rs, &rsidx, ni, ni->ni_txrate);
+ mn->candidate_rates |= (1 << (rs->min_rate + rsidx));
+ }
if (mn->probing & IEEE80211_MIRA_PROBING_UP) {
mn->candidate_rates |=
(1 << ieee80211_mira_next_intra_rate(mn, ni));
} else if (mn->probing & IEEE80211_MIRA_PROBING_DOWN) {
#ifdef MIRA_AGGRESSIVE_DOWNWARDS_PROBING
- mn->candidate_rates |= ieee80211_mira_mcs_below(mn,
- ni->ni_txmcs);
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ mn->candidate_rates |=
+ ieee80211_mira_mcs_below(mn, ni->ni_txmcs);
+ else
+ mn->candidate_rates |=
+ ieee80211_mira_legacy_rates_below(mn, ni,
+ ni->ni_txrate);
#else
mn->candidate_rates |=
(1 << ieee80211_mira_next_lower_intra_rate(mn, ni));
@@ -699,7 +937,7 @@ ieee80211_mira_probe_next_rateset(struct
}
int
-ieee80211_mira_next_mcs(struct ieee80211_mira_node *mn,
+ieee80211_mira_next_probe_rate(struct ieee80211_mira_node *mn,
struct ieee80211_node *ni)
{
int next;
@@ -715,7 +953,7 @@ ieee80211_mira_next_mcs(struct ieee80211
}
int
-ieee80211_mira_prev_mcs(struct ieee80211_mira_node *mn,
+ieee80211_mira_prev_probe_rate(struct ieee80211_mira_node *mn,
struct ieee80211_node *ni)
{
int next;
@@ -734,8 +972,9 @@ int
ieee80211_mira_probe_valid(struct ieee80211_mira_node *mn,
struct ieee80211_node *ni)
{
- struct ieee80211_mira_goodput_stats *g = &mn->g[ni->ni_txmcs];
+ struct ieee80211_mira_goodput_stats *g;
+ g = ieee80211_mira_get_stats(mn, ni);
return (g->nprobes >= IEEE80211_MIRA_MIN_PROBE_FRAMES ||
g->nprobe_bytes >= IEEE80211_MIRA_MIN_PROBE_BYTES);
}
@@ -751,31 +990,27 @@ ieee80211_mira_probe_done(struct ieee802
}
int
-ieee80211_mira_intra_mode_ra_finished(struct ieee80211_mira_node *mn,
+ieee80211_mira_intra_mode_ra_finished_ht(struct ieee80211_mira_node *mn,
struct ieee80211_node *ni)
{
const struct ieee80211_mira_rateset *rs;
struct ieee80211_mira_goodput_stats *g = &mn->g[ni->ni_txmcs];
- int next_mcs, best_mcs, probed_rates;
+ int next_mcs, best_ridx, best_mcs, probed_rates;
uint64_t next_rate;
-
- if (!ieee80211_mira_probe_valid(mn, ni))
- return 0;
-
probed_rates = (mn->probed_rates | (1 << ni->ni_txmcs));
/* Check if the min/max MCS in this rateset has been probed. */
- rs = ieee80211_mira_get_rateset(ni->ni_txmcs);
+ rs = ieee80211_mira_get_ht_rateset(ni->ni_txmcs);
if (mn->probing & IEEE80211_MIRA_PROBING_DOWN) {
- if (ni->ni_txmcs == rs->min_mcs ||
- probed_rates & (1 << rs->min_mcs)) {
- ieee80211_mira_trigger_next_rateset(mn, ni);
+ if (ni->ni_txmcs == rs->min_rate ||
+ probed_rates & (1 << rs->min_rate)) {
+ ieee80211_mira_trigger_next_ht_rateset(mn, ni);
return 1;
}
} else if (mn->probing & IEEE80211_MIRA_PROBING_UP) {
- if (ni->ni_txmcs == rs->max_mcs ||
- probed_rates & (1 << rs->max_mcs)) {
- ieee80211_mira_trigger_next_rateset(mn, ni);
+ if (ni->ni_txmcs == rs->max_rate ||
+ probed_rates & (1 << rs->max_rate)) {
+ ieee80211_mira_trigger_next_ht_rateset(mn, ni);
return 1;
}
}
@@ -784,28 +1019,29 @@ ieee80211_mira_intra_mode_ra_finished(st
* Check if the measured goodput is better than the
* loss-free goodput of the candidate rate.
*/
- next_mcs = ieee80211_mira_next_mcs(mn, ni);
+ next_mcs = ieee80211_mira_next_probe_rate(mn, ni);
if (next_mcs == ni->ni_txmcs) {
- ieee80211_mira_trigger_next_rateset(mn, ni);
+ ieee80211_mira_trigger_next_ht_rateset(mn, ni);
return 1;
}
- next_rate = ieee80211_mira_get_txrate(next_mcs);
+ next_rate = ieee80211_mira_get_txrate(ni);
if (g->measured >= next_rate + IEEE80211_MIRA_RATE_THRESHOLD) {
- ieee80211_mira_trigger_next_rateset(mn, ni);
+ ieee80211_mira_trigger_next_ht_rateset(mn, ni);
return 1;
}
- /* Check if we had a better measurement at a previously probed MCS. */
- best_mcs = ieee80211_mira_best_mcs_in_rateset(mn, rs);
+ /* Check if we had a better measurement at a previously probed rate. */
+ best_ridx = ieee80211_mira_best_rate_in_rateset(mn, rs);
+ best_mcs = rs->min_rate + best_ridx;
if ((mn->probed_rates & (1 << best_mcs))) {
if ((mn->probing & IEEE80211_MIRA_PROBING_UP) &&
best_mcs < ni->ni_txmcs) {
- ieee80211_mira_trigger_next_rateset(mn, ni);
+ ieee80211_mira_trigger_next_ht_rateset(mn, ni);
return 1;
}
if ((mn->probing & IEEE80211_MIRA_PROBING_DOWN) &&
best_mcs > ni->ni_txmcs) {
- ieee80211_mira_trigger_next_rateset(mn, ni);
+ ieee80211_mira_trigger_next_ht_rateset(mn, ni);
return 1;
}
}
@@ -819,13 +1055,90 @@ ieee80211_mira_intra_mode_ra_finished(st
return 0;
}
+int
+ieee80211_mira_intra_mode_ra_finished_legacy(struct ieee80211_mira_node *mn,
+ struct ieee80211_node *ni)
+{
+ const struct ieee80211_mira_rateset *rs;
+ struct ieee80211_mira_goodput_stats *g;
+ int rsidx, probed_rates, best_rsidx, best_ridx;
+
+ ieee80211_mira_get_legacy_rate(&rs, &rsidx, ni, ni->ni_txrate);
+ probed_rates = mn->probed_rates | (1 << (rs->min_rate + rsidx));
+ g = &mn->g[rs->min_rate + rsidx];
+
+ /* Check if the min/max rate in this rateset has been probed. */
+ if (mn->probing & IEEE80211_MIRA_PROBING_DOWN) {
+ if (rsidx == 0) {
+ ieee80211_mira_trigger_next_legacy_rateset(mn, ni);
+ return 1;
+ }
+ } else if (mn->probing & IEEE80211_MIRA_PROBING_UP) {
+ if (rsidx == rs->nrates - 1) {
+ ieee80211_mira_trigger_next_legacy_rateset(mn, ni);
+ return 1;
+ }
+ }
+
+ /* Check if we had a better measurement at a previously probed rate. */
+ best_rsidx = ieee80211_mira_best_rate_in_rateset(mn, rs);
+ best_ridx = rs->min_rate + best_rsidx;
+ if ((mn->probed_rates & (1 << best_ridx))) {
+ if ((mn->probing & IEEE80211_MIRA_PROBING_UP) &&
+ best_rsidx < rsidx) {
+ ieee80211_mira_trigger_next_legacy_rateset(mn, ni);
+ return 1;
+ }
+ if ((mn->probing & IEEE80211_MIRA_PROBING_DOWN) &&
+ best_rsidx > rsidx) {
+ ieee80211_mira_trigger_next_legacy_rateset(mn, ni);
+ return 1;
+ }
+ }
+
+ /* Check if all rates in the set of candidate rates have been probed. */
+ if ((mn->candidate_rates & probed_rates) == mn->candidate_rates)
+ return 1;
+
+ return 0;
+}
+
+int
+ieee80211_mira_intra_mode_ra_finished(struct ieee80211_mira_node *mn,
+ struct ieee80211_node *ni)
+{
+
+ if (!ieee80211_mira_probe_valid(mn, ni))
+ return 0;
+
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ return ieee80211_mira_intra_mode_ra_finished_ht(mn, ni);
+
+ return ieee80211_mira_intra_mode_ra_finished_legacy(mn, ni);
+
+}
+
void
-ieee80211_mira_trigger_next_rateset(struct ieee80211_mira_node *mn,
+ieee80211_mira_trigger_next_ht_rateset(struct ieee80211_mira_node *mn,
struct ieee80211_node *ni)
{
const struct ieee80211_mira_rateset *rsnext;
- rsnext = ieee80211_mira_next_rateset(mn, ni->ni_txmcs);
+ rsnext = ieee80211_mira_next_ht_rateset(mn, ni->ni_txmcs);
+ if (rsnext) {
+ ieee80211_mira_probe_next_rateset(mn, ni, rsnext);
+ mn->probing |= IEEE80211_MIRA_PROBING_INTER;
+ } else
+ mn->probing &= ~IEEE80211_MIRA_PROBING_INTER;
+}
+
+void
+ieee80211_mira_trigger_next_legacy_rateset(struct ieee80211_mira_node *mn,
+ struct ieee80211_node *ni)
+{
+ const struct ieee80211_mira_rateset *rsnext;
+
+ rsnext = ieee80211_mira_next_legacy_rateset(mn, ni);
if (rsnext) {
ieee80211_mira_probe_next_rateset(mn, ni, rsnext);
mn->probing |= IEEE80211_MIRA_PROBING_INTER;
@@ -844,10 +1157,10 @@ int
ieee80211_mira_best_rate(struct ieee80211_mira_node *mn,
struct ieee80211_node *ni)
{
- int i, best = 0;
+ int i, best = ieee80211_mira_ensure_valid_rate(mn->valid_rates, 0);
uint64_t gmax = 0;
- for (i = 0; i < nitems(mn->g); i++) {
+ for (i = best; i < nitems(mn->g); i++) {
struct ieee80211_mira_goodput_stats *g = &mn->g[i];
if (((1 << i) & mn->valid_rates) == 0)
continue;
@@ -858,15 +1171,16 @@ ieee80211_mira_best_rate(struct ieee8021
}
#ifdef MIRA_DEBUG
- if (mn->best_mcs != best) {
- DPRINTF(("MCS %d is best; MCS{Mbps|probe interval}:", best));
- for (i = 0; i < IEEE80211_MIRA_NUM_MCS; i++) {
+ if (mn->best_rate != best) {
+ DPRINTF(("%s %d is best; %s{Mbps|probe interval}:",
+ (ni->ni_flags & IEEE80211_NODE_HT) ? "MCS" : "rate", best,
+ (ni->ni_flags & IEEE80211_NODE_HT) ? "MCS" : "rate"));
+ for (i = 0; i < nitems(mn->g); i++) {
struct ieee80211_mira_goodput_stats *g = &mn->g[i];
if ((mn->valid_rates & (1 << i)) == 0)
continue;
DPRINTF((" %d{%s|%dms}", i,
- mira_fp_sprintf(g->measured),
- g->probe_interval));
+ mira_fp_sprintf(g->measured), g->probe_interval));
}
DPRINTF(("\n"));
}
@@ -895,7 +1209,7 @@ ieee80211_mira_update_probe_interval(str
}
void
-ieee80211_mira_schedule_probe_timers(struct ieee80211_mira_node *mn,
+ieee80211_mira_schedule_probe_timers_ht(struct ieee80211_mira_node *mn,
struct ieee80211_node *ni)
{
struct ieee80211_mira_goodput_stats *g;
@@ -925,12 +1239,45 @@ ieee80211_mira_schedule_probe_timers(str
}
}
+void
+ieee80211_mira_schedule_probe_timers_legacy(struct ieee80211_mira_node *mn,
+ struct ieee80211_node *ni)
+{
+ const struct ieee80211_mira_rateset *rs;
+ struct timeout *to;
+ int rsidx, next_ridx;
+
+ ieee80211_mira_get_legacy_rate(&rs, &rsidx, ni, ni->ni_txrate);
+
+ next_ridx = ieee80211_mira_next_intra_rate(mn, ni);
+ to = &mn->probe_to[IEEE80211_MIRA_PROBE_TO_UP];
+ if (next_ridx != (rs->min_rate + rsidx) && !timeout_pending(to) &&
+ !mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_UP]) {
+ struct ieee80211_mira_goodput_stats *g = &mn->g[next_ridx];
+ timeout_add_msec(to, g->probe_interval);
+ DPRINTFN(3, ("start probing up for node %s at rate %d in at "
+ "least %d msec\n", ether_sprintf(ni->ni_macaddr),
+ next_ridx, g->probe_interval));
+ }
+
+ next_ridx = ieee80211_mira_next_lower_intra_rate(mn, ni);
+ to = &mn->probe_to[IEEE80211_MIRA_PROBE_TO_DOWN];
+ if (next_ridx != (rs->min_rate + rsidx) && !timeout_pending(to) &&
+ !mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_DOWN]) {
+ struct ieee80211_mira_goodput_stats *g = &mn->g[next_ridx];
+ timeout_add_msec(to, g->probe_interval);
+ DPRINTFN(3, ("start probing down for node %s at rate %d in at "
+ "least %d msec\n", ether_sprintf(ni->ni_macaddr),
+ next_ridx, g->probe_interval));
+ }
+}
+
int
ieee80211_mira_check_probe_timers(struct ieee80211_mira_node *mn,
- struct ieee80211_node *ni)
+ struct ieee80211com *ic, struct ieee80211_node *ni)
{
int ret = 0, expired_timer = IEEE80211_MIRA_PROBE_TO_INVALID;
- int mcs;
+ int ridx;
if (mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_UP] &&
mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_DOWN]) {
@@ -951,16 +1298,16 @@ ieee80211_mira_check_probe_timers(struct
/* Do time-based upwards probing on next frame. */
DPRINTFN(2, ("probe timer expired: probe upwards\n"));
mn->probing = IEEE80211_MIRA_PROBING_UP;
- mcs = ieee80211_mira_next_intra_rate(mn, ni);
- mn->candidate_rates = (1 << mcs);
+ ridx = ieee80211_mira_next_intra_rate(mn, ni);
+ mn->candidate_rates = (1 << ridx);
ret = 1;
break;
case IEEE80211_MIRA_PROBE_TO_DOWN:
/* Do time-based downwards probing on next frame. */
DPRINTFN(2, ("probe timer expired: probe downwards\n"));
mn->probing = IEEE80211_MIRA_PROBING_DOWN;
- mcs = ieee80211_mira_next_lower_intra_rate(mn, ni);
- mn->candidate_rates = (1 << mcs);
+ ridx = ieee80211_mira_next_lower_intra_rate(mn, ni);
+ mn->candidate_rates = (1 << ridx);
ret = 1;
break;
case IEEE80211_MIRA_PROBE_TO_INVALID:
@@ -973,13 +1320,13 @@ ieee80211_mira_check_probe_timers(struct
}
void
-ieee80211_mira_probe_next_rate(struct ieee80211_mira_node *mn,
+ieee80211_mira_probe_next_ht_rate(struct ieee80211_mira_node *mn,
struct ieee80211_node *ni)
{
struct ieee80211_mira_goodput_stats *gprev, *g;
int prev_mcs;
- prev_mcs = ieee80211_mira_prev_mcs(mn, ni);
+ prev_mcs = ieee80211_mira_prev_probe_rate(mn, ni);
gprev = &mn->g[prev_mcs];
g = &mn->g[ni->ni_txmcs];
/* If the previous rate was worse, increase its probing interval. */
@@ -989,7 +1336,32 @@ ieee80211_mira_probe_next_rate(struct ie
/* Select the next rate to probe. */
mn->probed_rates |= (1 << ni->ni_txmcs);
- ni->ni_txmcs = ieee80211_mira_next_mcs(mn, ni);
+ ni->ni_txmcs = ieee80211_mira_next_probe_rate(mn, ni);
+}
+
+void
+ieee80211_mira_probe_next_legacy_rate(struct ieee80211_mira_node *mn,
+ struct ieee80211_node *ni)
+{
+ const struct ieee80211_mira_rateset *rs;
+ struct ieee80211_mira_goodput_stats *gprev, *g;
+ int prev_ridx, rsidx, next_ridx;
+
+ prev_ridx = ieee80211_mira_prev_probe_rate(mn, ni);
+ gprev = &mn->g[prev_ridx];
+
+ ieee80211_mira_get_legacy_rate(&rs, &rsidx, ni, ni->ni_txmcs);
+ g = &mn->g[rs->min_rate + rsidx];
+
+ /* If the previous rate was worse, increase its probing interval. */
+ if (prev_ridx != rs->min_rate + rsidx &&
+ gprev->measured + IEEE80211_MIRA_RATE_THRESHOLD < g->measured)
+ ieee80211_mira_update_probe_interval(mn, gprev);
+
+ /* Select the next rate to probe. */
+ mn->probed_rates |= (1 << (rs->min_rate + rsidx));
+ next_ridx = ieee80211_mira_next_probe_rate(mn, ni);
+ ni->ni_txrate = ieee80211_mira_ridx2txrate(next_ridx, ni);
}
int
@@ -1008,7 +1380,7 @@ ieee80211_mira_valid_tx_mcs(struct ieee8
}
uint32_t
-ieee80211_mira_valid_rates(struct ieee80211com *ic, struct ieee80211_node *ni)
+ieee80211_mira_valid_mcs(struct ieee80211com *ic, struct ieee80211_node *ni)
{
uint32_t valid_mcs = 0;
int i;
@@ -1026,34 +1398,196 @@ ieee80211_mira_valid_rates(struct ieee80
}
uint32_t
-ieee80211_mira_mcs_below(struct ieee80211_mira_node *mn, int mcs)
+ieee80211_mira_valid_legacy_rates(struct ieee80211com *ic,
+ struct ieee80211_node *ni)
{
- const struct ieee80211_mira_rateset *rs;
- uint32_t mcs_mask;
+ struct ieee80211_rateset *ic_rates;
+ enum ieee80211_phymode phymode;
+ uint32_t valid_rates = 0;
+ int i, j;
+
+ switch (ic->ic_curmode) {
+ case IEEE80211_MODE_11N:
+ if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan))
+ phymode = IEEE80211_MODE_11A;
+ else
+ phymode = IEEE80211_MODE_11G;
+ break;
+ case IEEE80211_MODE_11A:
+ case IEEE80211_MODE_11B:
+ case IEEE80211_MODE_11G:
+ phymode = ic->ic_curmode;
+ break;
+ default:
+ panic("mira not supported in PHY mode %u\n", ic->ic_curmode);
+ break; /* not reached */
+ }
+ ic_rates = &ic->ic_sup_rates[phymode];
+
+ for (i = 0; i < ni->ni_rates.rs_nrates; i++) {
+ const struct ieee80211_mira_rateset *rs;
+ int rsidx, ic_rval;
+ int rval = ni->ni_rates.rs_rates[i] & IEEE80211_RATE_VAL;
+
+ /* The peer will accept this rate. Check if we support it. */
+ for (j = 0; j < ic_rates->rs_nrates; j++) {
+ ic_rval = (ic_rates->rs_rates[j] & IEEE80211_RATE_VAL);
+ if (rval == ic_rval)
+ break;
+ }
+ if (j == ic_rates->rs_nrates)
+ continue;
+
+ ieee80211_mira_get_legacy_rate(&rs, &rsidx, ni, i);
+ valid_rates |= (1 << (rs->min_rate + rsidx));
+ }
+
+ return valid_rates;
+}
+
+uint32_t
+ieee80211_mira_fill_ratemask(const struct ieee80211_mira_rateset *rs,
+ uint32_t valid_rates, int limit)
+{
+ uint32_t rate_mask = (1 << rs->min_rate);
int i;
- rs = ieee80211_mira_get_rateset(mcs);
- mcs_mask = (1 << rs->min_mcs);
- for (i = rs->min_mcs + 1; i < mcs; i++) {
- if ((mn->valid_rates & (1 << i)) == 0)
+ for (i = rs->min_rate + 1; i < limit; i++) {
+ if ((valid_rates & (1 << i)) == 0)
continue;
- mcs_mask |= (1 << i);
+ rate_mask |= (1 << i);
+ }
+
+ return rate_mask;
+}
+
+uint32_t
+ieee80211_mira_mcs_below(struct ieee80211_mira_node *mn, int mcs)
+{
+ const struct ieee80211_mira_rateset *rs;
+
+ rs = ieee80211_mira_get_ht_rateset(mcs);
+ return ieee80211_mira_fill_ratemask(rs, mn->valid_rates, mcs);
+}
+
+uint32_t
+ieee80211_mira_legacy_rates_below(struct ieee80211_mira_node *mn,
+ struct ieee80211_node *ni, int txrate)
+{
+ const struct ieee80211_mira_rateset *rs;
+ int rsidx;
+
+ ieee80211_mira_get_legacy_rate(&rs, &rsidx, ni, txrate);
+ return ieee80211_mira_fill_ratemask(rs, mn->valid_rates,
+ rs->min_rate + rsidx);
+}
+
+void
+ieee80211_mira_probe_next(struct ieee80211_mira_node *mn,
+ struct ieee80211_node *ni)
+{
+ if (ieee80211_mira_probe_valid(mn, ni)) {
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ ieee80211_mira_probe_next_ht_rate(mn, ni);
+ else
+ ieee80211_mira_probe_next_legacy_rate(mn, ni);
+ ieee80211_mira_reset_driver_stats(mn);
}
- return mcs_mask;
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ DPRINTFN(4, ("probing MCS %d\n", ni->ni_txmcs));
+ else
+ DPRINTFN(4, ("probing legacy rate %d\n", ni->ni_txrate));
+}
+
+void
+ieee80211_mira_set_best_rate(struct ieee80211_mira_node *mn,
+ struct ieee80211_node *ni, struct ieee80211_mira_goodput_stats *g)
+{
+ int best = ieee80211_mira_best_rate(mn, ni);
+
+ if (mn->best_rate != best) {
+ mn->best_rate = best;
+ /* Reset probe interval for new best rate. */
+ mn->g[best].probe_interval = IEEE80211_MIRA_PROBE_TIMEOUT_MIN;
+ mn->g[best].nprobes = 0;
+ mn->g[best].nprobe_bytes = 0;
+ }
+
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ ni->ni_txmcs = mn->best_rate;
+ else
+ ni->ni_txrate = ieee80211_mira_ridx2txrate(mn->best_rate, ni);
+}
+
+void
+ieee80211_mira_probe_downwards(struct ieee80211_mira_node *mn,
+ struct ieee80211_node *ni, struct ieee80211_mira_goodput_stats *g)
+{
+ DPRINTFN(2, ("channel becomes bad; probe downwards\n"));
+ DPRINTFN(3, ("measured: %s Mbit/s\n",
+ mira_fp_sprintf(g->measured)));
+ DPRINTFN(3, ("average: %s Mbit/s\n",
+ mira_fp_sprintf(g->average)));
+ DPRINTFN(3, ("stddeviation: %s\n",
+ mira_fp_sprintf(g->stddeviation)));
+
+ mn->probing = IEEE80211_MIRA_PROBING_DOWN;
+ mn->probed_rates = 0;
+
+#ifdef MIRA_AGGRESSIVE_DOWNWARDS_PROBING
+ /* Allow for probing all the way down within this rateset. */
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ mn->candidate_rates =
+ ieee80211_mira_mcs_below(mn, ni->ni_txmcs);
+ else
+ mn->candidate_rates =
+ ieee80211_mira_legacy_rates_below(mn, ni, ni->ni_txrate);
+#else
+ /* Probe the lower candidate rate to see if it's any better. */
+ mn->candidate_rates =
+ (1 << ieee80211_mira_next_lower_intra_rate(mn, ni));
+#endif
+}
+
+void
+ieee80211_mira_probe_upwards(struct ieee80211_mira_node *mn,
+ struct ieee80211_node *ni, struct ieee80211_mira_goodput_stats *g)
+{
+ DPRINTFN(2, ("channel becomes good; probe upwards\n"));
+ DPRINTFN(3, ("measured: %s Mbit/s\n",
+ mira_fp_sprintf(g->measured)));
+ DPRINTFN(3, ("average: %s Mbit/s\n",
+ mira_fp_sprintf(g->average)));
+ DPRINTFN(3, ("stddeviation: %s\n",
+ mira_fp_sprintf(g->stddeviation)));
+
+ mn->probing = IEEE80211_MIRA_PROBING_UP;
+ mn->probed_rates = 0;
+
+ /* Probe the upper candidate rate to see if it's any better. */
+ mn->candidate_rates =
+ (1 << ieee80211_mira_next_intra_rate(mn, ni));
}
void
ieee80211_mira_choose(struct ieee80211_mira_node *mn, struct ieee80211com *ic,
struct ieee80211_node *ni)
{
- struct ieee80211_mira_goodput_stats *g = &mn->g[ni->ni_txmcs];
+ struct ieee80211_mira_goodput_stats *g;
int s;
s = splnet();
- if (mn->valid_rates == 0)
- mn->valid_rates = ieee80211_mira_valid_rates(ic, ni);
+ g = ieee80211_mira_get_stats(mn, ni);
+
+ if (mn->valid_rates == 0) {
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ mn->valid_rates = ieee80211_mira_valid_mcs(ic, ni);
+ else
+ mn->valid_rates =
+ ieee80211_mira_valid_legacy_rates(ic, ni);
+ }
#ifdef MIRA_DEBUG
if (mira_debug >= 5)
@@ -1064,23 +1598,9 @@ ieee80211_mira_choose(struct ieee80211_m
if (mn->probing) {
/* Probe another rate or settle at the best rate. */
if (!ieee80211_mira_intra_mode_ra_finished(mn, ni)) {
- if (ieee80211_mira_probe_valid(mn, ni)) {
- ieee80211_mira_probe_next_rate(mn, ni);
- ieee80211_mira_reset_driver_stats(mn);
- }
- DPRINTFN(4, ("probing MCS %d\n", ni->ni_txmcs));
+ ieee80211_mira_probe_next(mn, ni);
} else if (ieee80211_mira_inter_mode_ra_finished(mn, ni)) {
- int best = ieee80211_mira_best_rate(mn, ni);
- if (mn->best_mcs != best) {
- mn->best_mcs = best;
- ni->ni_txmcs = best;
- /* Reset probe interval for new best rate. */
- mn->g[best].probe_interval =
- IEEE80211_MIRA_PROBE_TIMEOUT_MIN;
- mn->g[best].nprobes = 0;
- mn->g[best].nprobe_bytes = 0;
- } else
- ni->ni_txmcs = mn->best_mcs;
+ ieee80211_mira_set_best_rate(mn, ni, g);
ieee80211_mira_probe_done(mn);
}
@@ -1088,10 +1608,13 @@ ieee80211_mira_choose(struct ieee80211_m
return;
} else {
ieee80211_mira_reset_driver_stats(mn);
- ieee80211_mira_schedule_probe_timers(mn, ni);
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ ieee80211_mira_schedule_probe_timers_ht(mn, ni);
+ else
+ ieee80211_mira_schedule_probe_timers_legacy(mn, ni);
}
- if (ieee80211_mira_check_probe_timers(mn, ni)) {
+ if (ieee80211_mira_check_probe_timers(mn, ic, ni)) {
/* Time-based probing has triggered. */
splx(s);
return;
@@ -1100,38 +1623,10 @@ ieee80211_mira_choose(struct ieee80211_m
/* Check if event-based probing should be triggered. */
if (g->measured <= g->average - 2 * g->stddeviation) {
/* Channel becomes bad. Probe downwards. */
- DPRINTFN(2, ("channel becomes bad; probe downwards\n"));
- DPRINTFN(3, ("measured: %s Mbit/s\n",
- mira_fp_sprintf(g->measured)));
- DPRINTFN(3, ("average: %s Mbit/s\n",
- mira_fp_sprintf(g->average)));
- DPRINTFN(3, ("stddeviation: %s\n",
- mira_fp_sprintf(g->stddeviation)));
- mn->probing = IEEE80211_MIRA_PROBING_DOWN;
- mn->probed_rates = 0;
-#ifdef MIRA_AGGRESSIVE_DOWNWARDS_PROBING
- /* Allow for probing all the way down within this rateset. */
- mn->candidate_rates = ieee80211_mira_mcs_below(mn,
- ni->ni_txmcs);
-#else
- /* Probe the lower candidate rate to see if it's any better. */
- mn->candidate_rates =
- (1 << ieee80211_mira_next_lower_intra_rate(mn, ni));
-#endif
+ ieee80211_mira_probe_downwards(mn, ni, g);
} else if (g->measured >= g->average + 2 * g->stddeviation) {
/* Channel becomes good. */
- DPRINTFN(2, ("channel becomes good; probe upwards\n"));
- DPRINTFN(3, ("measured: %s Mbit/s\n",
- mira_fp_sprintf(g->measured)));
- DPRINTFN(3, ("average: %s Mbit/s\n",
- mira_fp_sprintf(g->average)));
- DPRINTFN(3, ("stddeviation: %s\n",
- mira_fp_sprintf(g->stddeviation)));
- mn->probing = IEEE80211_MIRA_PROBING_UP;
- mn->probed_rates = 0;
- /* Probe the upper candidate rate to see if it's any better. */
- mn->candidate_rates =
- (1 << ieee80211_mira_next_intra_rate(mn, ni));
+ ieee80211_mira_probe_upwards(mn, ni, g);
} else {
/* Remain at current rate. */
mn->probing = IEEE80211_MIRA_NOT_PROBING;
Index: net80211/ieee80211_mira.h
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_mira.h,v
retrieving revision 1.3
diff -u -p -r1.3 ieee80211_mira.h
--- net80211/ieee80211_mira.h 12 Jan 2017 18:06:57 -0000 1.3
+++ net80211/ieee80211_mira.h 18 Feb 2018 11:51:43 -0000
@@ -1,7 +1,7 @@
/* $OpenBSD: ieee80211_mira.h,v 1.3 2017/01/12 18:06:57 stsp Exp $ */
/*
- * Copyright (c) 2016 Stefan Sperling <[email protected]>
+ * Copyright (c) 2018 Stefan Sperling <[email protected]>
* Copyright (c) 2016 Theo Buehler <[email protected]>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -24,14 +24,21 @@
* MiRA - "MIMO Rate Adaptation in 802.11n Wireless Networks"
* Ioannis Pefkianakis, Yun Hu, Starsky H.Y. Wong, Hao Yang, Songwu Lu
* http://www.cs.ucla.edu/wing/publication/papers/Pefkianakis.MOBICOM10.pdf
+ *
+ * As an extension, this implementation also supports 11a/b/g as an
+ * alternative to 11n, where CCK and OFDM rates are probed separately.
*/
-/* The number of data rates MiRA can choose from. */
-#define IEEE80211_MIRA_NUM_RATES 32 /* XXX limited to MCS 0-31 */
+/*
+ * The number of data rates MiRA can keep concurrent goodput statistics for.
+ * We need to cover either 12 legacy rates, 4 CCK (2GHz only) + 8 legacy OFDM,
+ * or HT MCS 0-31 (MCS >= 32 are not supported).
+ */
+#define IEEE80211_MIRA_MAX_RATES 32
/*
- * Goodput statistics struct. Measures the effective data rate of an MCS
- * index and contains data related to time-based probing to a new rate.
+ * Goodput statistics struct. Measures the effective data rate of a
+ * rate and contains data related to time-based probing to a new rate.
* All uint64_t numbers in this struct use fixed-point arithmetic.
*/
struct ieee80211_mira_goodput_stats {
@@ -65,7 +72,7 @@ struct ieee80211_mira_node {
* Private fields for use by the rate control algorithm.
*/
- /* Bitmaps MCS 0-31. */
+ /* Bitmaps for the legacy rateset (11a/b/g) or MCS 0-31 (11n). */
uint32_t valid_rates;
uint32_t candidate_rates;
uint32_t probed_rates;
@@ -84,11 +91,11 @@ struct ieee80211_mira_node {
#define IEEE80211_MIRA_PROBING_UP 0x2
#define IEEE80211_MIRA_PROBING_INTER 0x4 /* combined with UP or DOWN */
- /* The current best MCS found by probing. */
- int best_mcs;
+ /* The current best legacy rate or MCS index found by probing. */
+ int best_rate;
/* Goodput statistics for each MCS. */
- struct ieee80211_mira_goodput_stats g[IEEE80211_MIRA_NUM_RATES];
+ struct ieee80211_mira_goodput_stats g[IEEE80211_MIRA_MAX_RATES];
};
/* Initialize rate control state. */