diff options
Diffstat (limited to 'sys/net80211/ieee80211_amrr.c')
-rw-r--r-- | sys/net80211/ieee80211_amrr.c | 109 |
1 files changed, 96 insertions, 13 deletions
diff --git a/sys/net80211/ieee80211_amrr.c b/sys/net80211/ieee80211_amrr.c index 73dd901..003b4bc 100644 --- a/sys/net80211/ieee80211_amrr.c +++ b/sys/net80211/ieee80211_amrr.c @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$"); #endif #include <net80211/ieee80211_var.h> +#include <net80211/ieee80211_ht.h> #include <net80211/ieee80211_amrr.h> #include <net80211/ieee80211_ratectl.h> @@ -128,13 +129,25 @@ amrr_deinit(struct ieee80211vap *vap) free(vap->iv_rs, M_80211_RATECTL); } +static int +amrr_node_is_11n(struct ieee80211_node *ni) +{ + + if (ni->ni_chan == NULL) + return (0); + if (ni->ni_chan == IEEE80211_CHAN_ANYC) + return (0); + return (IEEE80211_IS_CHAN_HT(ni->ni_chan)); +} + static void amrr_node_init(struct ieee80211_node *ni) { - const struct ieee80211_rateset *rs = &ni->ni_rates; + const struct ieee80211_rateset *rs = NULL; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_amrr *amrr = vap->iv_rs; struct ieee80211_amrr_node *amn; + uint8_t rate; if (ni->ni_rctls == NULL) { ni->ni_rctls = amn = malloc(sizeof(struct ieee80211_amrr_node), @@ -152,16 +165,50 @@ amrr_node_init(struct ieee80211_node *ni) amn->amn_txcnt = amn->amn_retrycnt = 0; amn->amn_success_threshold = amrr->amrr_min_success_threshold; - /* pick initial rate */ - for (amn->amn_rix = rs->rs_nrates - 1; - amn->amn_rix > 0 && (rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL) > 72; - amn->amn_rix--) - ; - ni->ni_txrate = rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL; + /* 11n or not? Pick the right rateset */ + if (amrr_node_is_11n(ni)) { + /* XXX ew */ + IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, + "%s: 11n node", __func__); + rs = (struct ieee80211_rateset *) &ni->ni_htrates; + } else { + IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, + "%s: non-11n node", __func__); + rs = &ni->ni_rates; + } + + /* Initial rate - lowest */ + rate = rs->rs_rates[0]; + + /* XXX clear the basic rate flag if it's not 11n */ + if (! amrr_node_is_11n(ni)) + rate &= IEEE80211_RATE_VAL; + + /* pick initial rate from the rateset - HT or otherwise */ + for (amn->amn_rix = rs->rs_nrates - 1; amn->amn_rix > 0; + amn->amn_rix--) { + /* legacy - anything < 36mbit, stop searching */ + /* 11n - stop at MCS4 / MCS12 / MCS28 */ + if (amrr_node_is_11n(ni) && + (rs->rs_rates[amn->amn_rix] & 0x7) < 4) + break; + else if ((rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL) <= 72) + break; + rate = rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL; + } + + /* if the rate is an 11n rate, ensure the MCS bit is set */ + if (amrr_node_is_11n(ni)) + rate |= IEEE80211_RATE_MCS; + + /* Assign initial rate from the rateset */ + ni->ni_txrate = rate; amn->amn_ticks = ticks; IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, - "AMRR initial rate %d", ni->ni_txrate); + "AMRR: nrates=%d, initial rate %d", + rs->rs_nrates, + rate); } static void @@ -175,19 +222,42 @@ amrr_update(struct ieee80211_amrr *amrr, struct ieee80211_amrr_node *amn, struct ieee80211_node *ni) { int rix = amn->amn_rix; + const struct ieee80211_rateset *rs = NULL; KASSERT(is_enough(amn), ("txcnt %d", amn->amn_txcnt)); + /* 11n or not? Pick the right rateset */ + if (amrr_node_is_11n(ni)) { + /* XXX ew */ + rs = (struct ieee80211_rateset *) &ni->ni_htrates; + } else { + rs = &ni->ni_rates; + } + + IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, + "AMRR: current rate %d, txcnt=%d, retrycnt=%d", + rs->rs_rates[rix] & IEEE80211_RATE_VAL, + amn->amn_txcnt, + amn->amn_retrycnt); + + /* + * XXX This is totally bogus for 11n, as although high MCS + * rates for each stream may be failing, the next stream + * should be checked. + * + * Eg, if MCS5 is ok but MCS6/7 isn't, and we can go up to + * MCS23, we should skip 6/7 and try 8 onwards. + */ if (is_success(amn)) { amn->amn_success++; if (amn->amn_success >= amn->amn_success_threshold && - rix + 1 < ni->ni_rates.rs_nrates) { + rix + 1 < rs->rs_nrates) { amn->amn_recovery = 1; amn->amn_success = 0; rix++; IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, "AMRR increasing rate %d (txcnt=%d retrycnt=%d)", - ni->ni_rates.rs_rates[rix] & IEEE80211_RATE_VAL, + rs->rs_rates[rix] & IEEE80211_RATE_VAL, amn->amn_txcnt, amn->amn_retrycnt); } else { amn->amn_recovery = 0; @@ -208,7 +278,7 @@ amrr_update(struct ieee80211_amrr *amrr, struct ieee80211_amrr_node *amn, rix--; IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, "AMRR decreasing rate %d (txcnt=%d retrycnt=%d)", - ni->ni_rates.rs_rates[rix] & IEEE80211_RATE_VAL, + rs->rs_rates[rix] & IEEE80211_RATE_VAL, amn->amn_txcnt, amn->amn_retrycnt); } amn->amn_recovery = 0; @@ -231,14 +301,27 @@ amrr_rate(struct ieee80211_node *ni, void *arg __unused, uint32_t iarg __unused) { struct ieee80211_amrr_node *amn = ni->ni_rctls; struct ieee80211_amrr *amrr = amn->amn_amrr; + const struct ieee80211_rateset *rs = NULL; int rix; + /* 11n or not? Pick the right rateset */ + if (amrr_node_is_11n(ni)) { + /* XXX ew */ + rs = (struct ieee80211_rateset *) &ni->ni_htrates; + } else { + rs = &ni->ni_rates; + } + if (is_enough(amn) && (ticks - amn->amn_ticks) > amrr->amrr_interval) { rix = amrr_update(amrr, amn, ni); if (rix != amn->amn_rix) { /* update public rate */ - ni->ni_txrate = - ni->ni_rates.rs_rates[rix] & IEEE80211_RATE_VAL; + ni->ni_txrate = rs->rs_rates[rix]; + /* XXX strip basic rate flag from txrate, if non-11n */ + if (amrr_node_is_11n(ni)) + ni->ni_txrate |= IEEE80211_RATE_MCS; + else + ni->ni_txrate &= IEEE80211_RATE_VAL; amn->amn_rix = rix; } amn->amn_ticks = ticks; |