DF-3454 / fix.diff
--- a/sys/netproto/802_11/wlan/ieee80211_amrr.c +++ b/sys/netproto/802_11/wlan/ieee80211_amrr.c @@ -254,6 +254,17 @@ rs = &ni->ni_rates; } + /* + * The node's HT status (and therefore the active rateset) can + * change at any time (channel switch, re-association without + * HT IEs, htrates cleared). Never trust a stale index that + * was computed against a different rateset. + */ + if (rs->rs_nrates == 0) + rix = 0; + else if (rix < 0 || rix >= rs->rs_nrates) + rix = rs->rs_nrates - 1; + IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, "AMRR: current rate %d, txcnt=%d, retrycnt=%d", rs->rs_rates[rix] & IEEE80211_RATE_VAL, @@ -332,6 +343,16 @@ rs = &ni->ni_rates; } + /* + * Re-sync a stale index against the currently selected rateset + * before it is used here or handed to drivers (which index + * their own legacy rate tables with it). + */ + if (rs->rs_nrates == 0) + amn->amn_rix = 0; + else if (amn->amn_rix < 0 || amn->amn_rix >= rs->rs_nrates) + amn->amn_rix = rs->rs_nrates - 1; + if (is_enough(amn) && (ticks - amn->amn_ticks) > amrr->amrr_interval) { rix = amrr_update(amrr, amn, ni); if (rix != amn->amn_rix) { @@ -425,17 +446,24 @@ int rate; struct ieee80211_amrr_node *amn = ni->ni_rctls; struct ieee80211_rateset *rs; + int rix; /* XXX TODO: check locking? */ /* XXX TODO: this should be a method */ if (amrr_node_is_11n(ni)) { rs = (struct ieee80211_rateset *) &ni->ni_htrates; - rate = rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL; + rix = amn->amn_rix; + if (rix < 0 || rix >= rs->rs_nrates) + rix = (rs->rs_nrates == 0) ? 0 : rs->rs_nrates - 1; + rate = rs->rs_rates[rix] & IEEE80211_RATE_VAL; sbuf_printf(s, "rate: MCS %d\n", rate); } else { rs = &ni->ni_rates; - rate = rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL; + rix = amn->amn_rix; + if (rix < 0 || rix >= rs->rs_nrates) + rix = (rs->rs_nrates == 0) ? 0 : rs->rs_nrates - 1; + rate = rs->rs_rates[rix] & IEEE80211_RATE_VAL; sbuf_printf(s, "rate: %d Mbit\n", rate / 2); } |