Index: sys/dev/an/if_an.c =================================================================== --- sys/dev/an/if_an.c +++ sys/dev/an/if_an.c @@ -652,9 +652,11 @@ int an_attach(struct an_softc *sc, int flags) { + const struct ieee80211_rate_t *rate; struct ifnet *ifp; int error = EIO; int i, nrate, mword; + uint16_t rate_idx; u_int8_t r; ifp = sc->an_ifp = if_alloc(IFT_ETHER); @@ -773,7 +775,16 @@ ADD(IFM_AUTO, IFM_IEEE80211_ADHOC); for (i = 0; i < nrate; i++) { r = sc->an_caps.an_rates[i]; - mword = ieee80211_rate2media(NULL, r, IEEE80211_MODE_AUTO); + + rate_idx = ieee80211_convert_from_legacy_rate(r, + IEEE80211_MODE_11B); + if (rate_idx == IEEE80211_RATE_NONEXISTENT) { + /* XXX recheck other rate types? */ + continue; + } + + rate = ieee80211_get_rate(rate_idx); + mword = ieee80211_rate2media(NULL, rate, IEEE80211_MODE_AUTO); if (mword == 0) continue; printf("%s%d%sMbps", (i != 0 ? " " : ""), @@ -3252,8 +3263,10 @@ static void an_media_status(struct ifnet *ifp, struct ifmediareq *imr) { + const struct ieee80211_rate_t *rate; struct an_ltv_status status; struct an_softc *sc = ifp->if_softc; + uint16_t rate_idx; imr->ifm_active = IFM_IEEE80211; @@ -3272,8 +3285,14 @@ if (sc->an_config.an_opmode == AN_OPMODE_IBSS_ADHOC) imr->ifm_active |= IFM_IEEE80211_ADHOC; - imr->ifm_active |= ieee80211_rate2media(NULL, - status.an_current_tx_rate, IEEE80211_MODE_AUTO); + + rate_idx = ieee80211_convert_from_legacy_rate( + status.an_current_tx_rate, IEEE80211_MODE_11B); + if (rate_idx != IEEE80211_RATE_NONEXISTENT) { + rate = ieee80211_get_rate(rate_idx); + imr->ifm_active |= ieee80211_rate2media(NULL, + rate, IEEE80211_MODE_AUTO); + } imr->ifm_status = IFM_AVALID; if (status.an_opmode & AN_STATUS_OPMODE_ASSOCIATED) imr->ifm_status |= IFM_ACTIVE; Index: sys/dev/ath/ath_rate/amrr/amrr.c =================================================================== --- sys/dev/ath/ath_rate/amrr/amrr.c +++ sys/dev/ath/ath_rate/amrr/amrr.c @@ -304,25 +304,27 @@ static void ath_rate_ctl_start(struct ath_softc *sc, struct ieee80211_node *ni) { -#define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL) - const struct ieee80211_txparam *tp = ni->ni_txparms; +#define RV(_ix) (ieee80211_get_rate(rs->rates[(_ix)].rs_index)->value) + const struct ieee80211_txparam_vht *tp = ni->ni_txparms; + const struct ieee80211_rateset *rs = ni->ni_rates; int srate; - KASSERT(ni->ni_rates.rs_nrates > 0, ("no rates")); - if (tp == NULL || tp->ucastrate == IEEE80211_FIXED_RATE_NONE) { + KASSERT(rs->rs_nrates > 0, ("no rates")); + + srate = rs->rs_nrates - 1; + if (tp == NULL || tp->ucastrate == IEEE80211_RATE_NONEXISTENT) { /* * No fixed rate is requested. For 11b start with * the highest negotiated rate; otherwise, for 11g * and 11a, we start "in the middle" at 24Mb or 36Mb. */ - srate = ni->ni_rates.rs_nrates - 1; if (sc->sc_curmode != IEEE80211_MODE_11B) { /* * Scan the negotiated rate set to find the * closest rate. */ /* NB: the rate set is assumed sorted */ - for (; srate >= 0 && RATE(srate) > 72; srate--) + for (; srate >= 0 && RV(srate) > 72; srate--) ; } } else { @@ -334,9 +336,9 @@ * rate set is checked when the station associates. */ /* NB: the rate set is assumed sorted */ - srate = ni->ni_rates.rs_nrates - 1; - for (; srate >= 0 && RATE(srate) != tp->ucastrate; srate--) - ; + for (; srate >= 0; srate--) + if (rs->rates[srate].rs_index == tp->ucastrate) + break; } /* * The selected rate may not be available due to races @@ -345,7 +347,7 @@ * can fail. This is not fatal. */ ath_rate_update(sc, ni, srate < 0 ? 0 : srate); -#undef RATE +#undef RV } /* Index: sys/dev/ath/ath_rate/onoe/onoe.c =================================================================== --- sys/dev/ath/ath_rate/onoe/onoe.c +++ sys/dev/ath/ath_rate/onoe/onoe.c @@ -192,6 +192,8 @@ static void ath_rate_update(struct ath_softc *sc, struct ieee80211_node *ni, int rate) { +#define RV(_ix) (ieee80211_get_rate(rs->rates[(_ix)].rs_index)->value) + const struct ieee80211_rateset *rs = ni->ni_rates; struct ath_node *an = ATH_NODE(ni); struct onoe_node *on = ATH_NODE_ONOE(an); struct ieee80211vap *vap = ni->ni_vap; @@ -202,8 +204,7 @@ IEEE80211_NOTE(vap, IEEE80211_MSG_RATECTL, ni, "%s: set xmit rate to %dM", __func__, - ni->ni_rates.rs_nrates > 0 ? - (ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL) / 2 : 0); + rs->rs_nrates > 0 ? RV(rate) / 2 : 0); /* * Before associating a node has no rate set setup @@ -212,11 +213,11 @@ * but management frames and those always go at the * lowest hardware rate. */ - if (ni->ni_rates.rs_nrates == 0) + if (rs->rs_nrates == 0) goto done; on->on_rix = rate; - ni->ni_txrate = ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL; - on->on_tx_rix0 = sc->sc_rixmap[ni->ni_txrate]; + ni->ni_txrate = rs->rs_rates[rate].rs_index; + on->on_tx_rix0 = sc->sc_rixmap[RV(rate)]; on->on_tx_rate0 = rt->info[on->on_tx_rix0].rateCode; on->on_tx_rate0sp = on->on_tx_rate0 | @@ -231,8 +232,7 @@ */ on->on_tx_try0 = 1 + 3; /* 4 tries at rate 0 */ if (--rate >= 0) { - rix = sc->sc_rixmap[ - ni->ni_rates.rs_rates[rate]&IEEE80211_RATE_VAL]; + rix = sc->sc_rixmap[RV(rate)]; on->on_tx_rate1 = rt->info[rix].rateCode; on->on_tx_rate1sp = on->on_tx_rate1 | rt->info[rix].shortPreamble; @@ -240,8 +240,7 @@ on->on_tx_rate1 = on->on_tx_rate1sp = 0; } if (--rate >= 0) { - rix = sc->sc_rixmap[ - ni->ni_rates.rs_rates[rate]&IEEE80211_RATE_VAL]; + rix = sc->sc_rixmap[RV(rate)]; on->on_tx_rate2 = rt->info[rix].rateCode; on->on_tx_rate2sp = on->on_tx_rate2 | rt->info[rix].shortPreamble; @@ -269,6 +268,7 @@ if (vap->iv_opmode == IEEE80211_M_STA) on->on_interval /= 2; on->on_interval = (on->on_interval * hz) / 1000; +#undef RV } /* @@ -277,25 +277,27 @@ static void ath_rate_ctl_start(struct ath_softc *sc, struct ieee80211_node *ni) { -#define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL) +#define RV(_ix) (ieee80211_get_rate(rs->rates[(_ix)].rs_index)->value) const struct ieee80211_txparam *tp = ni->ni_txparms; + const struct ieee80211_rateset *rs = ni->ni_rates; int srate; - KASSERT(ni->ni_rates.rs_nrates > 0, ("no rates")); - if (tp == NULL || tp->ucastrate == IEEE80211_FIXED_RATE_NONE) { + KASSERT(rs->rs_nrates > 0, ("no rates")); + + srate = rs->rs_nrates - 1; + if (tp == NULL || tp->ucastrate == IEEE80211_RATE_NONEXISTENT) { /* * No fixed rate is requested. For 11b start with * the highest negotiated rate; otherwise, for 11g * and 11a, we start "in the middle" at 24Mb or 36Mb. */ - srate = ni->ni_rates.rs_nrates - 1; if (sc->sc_curmode != IEEE80211_MODE_11B) { /* * Scan the negotiated rate set to find the * closest rate. */ /* NB: the rate set is assumed sorted */ - for (; srate >= 0 && RATE(srate) > 72; srate--) + for (; srate >= 0 && RV(srate) > 72; srate--) ; } } else { @@ -307,9 +309,9 @@ * rate set is checked when the station associates. */ /* NB: the rate set is assumed sorted */ - srate = ni->ni_rates.rs_nrates - 1; - for (; srate >= 0 && RATE(srate) != tp->ucastrate; srate--) - ; + for (; srate >= 0; srate--) + if (rs->rates[srate].rs_index == tp->ucastrate) + break; } /* * The selected rate may not be available due to races @@ -318,7 +320,7 @@ * can fail. This is not fatal. */ ath_rate_update(sc, ni, srate < 0 ? 0 : srate); -#undef RATE +#undef RV } /* @@ -383,8 +385,9 @@ if (nrate != on->on_rix) { IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, "%s: %dM -> %dM (%d ok, %d err, %d retr)", __func__, - ni->ni_txrate / 2, - (rs->rs_rates[nrate] & IEEE80211_RATE_VAL) / 2, + ieee80211_get_rateKbps_by_idx(ni->ni_txrate) / 1000, + ieee80211_get_rateKbps_by_idx(rs->rates[nrate].rs_index) / + 1000, on->on_tx_ok, on->on_tx_err, on->on_tx_retr); ath_rate_update(sc, ni, nrate); } else if (enough) Index: sys/dev/ath/ath_rate/sample/sample.c =================================================================== --- sys/dev/ath/ath_rate/sample/sample.c +++ sys/dev/ath/ath_rate/sample/sample.c @@ -158,6 +158,27 @@ return rt->info[rix].phy == IEEE80211_T_HT ? "MCS" : "Mb "; } +static uint16_t +get11rate_idx(const HAL_RATE_TABLE *rt, int rix) +{ + uint16_t rate_idx; + uint8_t rate; + + KASSERT(rix >= 0, ("rix < 0!")); + + if (rt->info[rix].phy == IEEE80211_T_HT) + rate = rt->info[rix].dot11Rate; + else + rate = IEEE80211_RV(rt->info[rix].dot11Rate); + rate_idx = ieee80211_lookup_rate_index(rt->info[rix].phy, rate); + + KASSERT(rate_idx != IEEE80211_RATE_NONEXISTENT, + ("rate index not found for phy %u / rate %u", + rt->info[rix].phy, rate)); + + return rate_idx; +} + /* * Return the rix with the lowest average_tx_time, * or -1 if all the average_tx_times are 0. @@ -344,37 +365,35 @@ static int ath_rate_get_static_rix(struct ath_softc *sc, const struct ieee80211_node *ni) { -#define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL) -#define DOT11RATE(_ix) (rt->info[(_ix)].dot11Rate & IEEE80211_RATE_VAL) -#define MCS(_ix) (ni->ni_htrates.rs_rates[_ix] | IEEE80211_RATE_MCS) - const struct ieee80211_txparam *tp = ni->ni_txparms; - int srate; + const struct ieee80211_txparam_vht *tp = ni->ni_txparms; + const struct ieee80211_rate_t *rate; + uint8_t value; - /* Check MCS rates */ - for (srate = ni->ni_htrates.rs_nrates - 1; srate >= 0; srate--) { - if (MCS(srate) == tp->ucastrate) - return sc->sc_rixmap[tp->ucastrate]; - } + /* NB: already checked against IEEE80211_RATE_NONEXISTENT */ + rate = ieee80211_get_rate(tp->ucastrate); + value = rate->value; - /* Check legacy rates */ - for (srate = ni->ni_rates.rs_nrates - 1; srate >= 0; srate--) { - if (RATE(srate) == tp->ucastrate) - return sc->sc_rixmap[tp->ucastrate]; + if (rate->type == IEEE80211_T_HT) { + /* Check MCS rates */ + if (isset(ni->ni_htrates.rs_bitmap, value)) + return sc->sc_rixmap[value | IEEE80211_RATE_MCS]; + } else { + /* Check legacy rates */ + if (isset(ni->ni_rates.rs_bitmap, value)) + return sc->sc_rixmap[value]; } + return -1; -#undef RATE -#undef DOT11RATE -#undef MCS } static void ath_rate_update_static_rix(struct ath_softc *sc, struct ieee80211_node *ni) { struct ath_node *an = ATH_NODE(ni); - const struct ieee80211_txparam *tp = ni->ni_txparms; + const struct ieee80211_txparam_vht *tp = ni->ni_txparms; struct sample_node *sn = ATH_NODE_SAMPLE(an); - if (tp != NULL && tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { + if (tp != NULL && tp->ucastrate != IEEE80211_RATE_NONEXISTENT) { /* * A fixed rate is to be used; ucastrate is the IEEE code * for this rate (sans basic bit). Check this against the @@ -627,7 +646,7 @@ /* * Set the visible txrate for this node. */ - an->an_node.ni_txrate = (rt->info[best_rix].phy == IEEE80211_T_HT) ? MCS(best_rix) : DOT11RATE(best_rix); + an->an_node.ni_txrate = get11rate_idx(rt, best_rix); } rix = sn->current_rix[size_bin]; sn->packets_since_switch[size_bin]++; @@ -1040,12 +1059,14 @@ static void ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni) { -#define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL) +#define RATE_IDX(_ix) (ni->ni_rates.rates[(_ix)].rs_index) #define DOT11RATE(_ix) (rt->info[(_ix)].dot11Rate & IEEE80211_RATE_VAL) -#define MCS(_ix) (ni->ni_htrates.rs_rates[_ix] | IEEE80211_RATE_MCS) +#define HTRATE_IDX(_ix) (ni->ni_htrates.rates[(_ix)].rs_index) +#define MCS(_ix) ((_ix) | IEEE80211_RATE_MCS) struct ath_node *an = ATH_NODE(ni); struct sample_node *sn = ATH_NODE_SAMPLE(an); const HAL_RATE_TABLE *rt = sc->sc_currates; + const struct ieee80211_rate_t *rate; int x, y, rix; KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); @@ -1071,7 +1092,8 @@ /* MCS rates */ if (ni->ni_flags & IEEE80211_NODE_HT) { for (x = 0; x < ni->ni_htrates.rs_nrates; x++) { - rix = sc->sc_rixmap[MCS(x)]; + rate = ieee80211_get_rate(HTRATE_IDX(x)); + rix = sc->sc_rixmap[MCS(rate->value)]; if (rix == 0xff) continue; /* skip rates marked broken by hal */ @@ -1085,14 +1107,15 @@ /* Legacy rates */ for (x = 0; x < ni->ni_rates.rs_nrates; x++) { - rix = sc->sc_rixmap[RATE(x)]; + rate = ieee80211_get_rate(RATE_IDX(x)); + rix = sc->sc_rixmap[rate->value]; if (rix == 0xff) continue; /* skip rates marked broken by hal */ if (!rt->info[rix].valid) continue; KASSERT(rix < SAMPLE_MAXRATES, - ("rate %u has rix %d", RATE(x), rix)); + ("rate %u has rix %d", RATE_IDX(x), rix)); sn->ratemask |= (uint64_t) 1<static_rix != -1) - ni->ni_txrate = DOT11RATE(sn->static_rix); + ni->ni_txrate = get11rate_idx(rt, sn->static_rix); else - ni->ni_txrate = RATE(0); -#undef RATE + ni->ni_txrate = RATE_IDX(0); +#undef MCS +#undef HTRATE_IDX #undef DOT11RATE +#undef RATE_IDX } /* Index: sys/dev/ath/if_ath.c =================================================================== --- sys/dev/ath/if_ath.c +++ sys/dev/ath/if_ath.c @@ -4172,6 +4172,21 @@ return (rix == 0xff ? 0 : rix); } +/* + * The same as above, but takes rate index on input instead. + */ +int +ath_tx_findrix_byidx(const struct ath_softc *sc, uint16_t rate_idx) +{ + const struct ieee80211_rate_t *rate; + + rate = ieee80211_get_rate_safe(rate_idx); + if (!rate) + return (0); + + return (ath_tx_findrix(sc, rate->value)); +} + static void ath_tx_update_stats(struct ath_softc *sc, struct ath_tx_status *ts, struct ath_buf *bf) @@ -6182,10 +6197,10 @@ struct ath_node *an = ATH_NODE(ni); struct ieee80211vap *vap = ni->ni_vap; struct ath_softc *sc = vap->iv_ic->ic_softc; - const struct ieee80211_txparam *tp = ni->ni_txparms; + const struct ieee80211_txparam_vht *tp = ni->ni_txparms; - an->an_mcastrix = ath_tx_findrix(sc, tp->mcastrate); - an->an_mgmtrix = ath_tx_findrix(sc, tp->mgmtrate); + an->an_mcastrix = ath_tx_findrix_byidx(sc, tp->mcastrate); + an->an_mgmtrix = ath_tx_findrix_byidx(sc, tp->mgmtrate); DPRINTF(sc, ATH_DEBUG_NODE, "%s: %6D: reassoc; isnew=%d, is_powersave=%d\n", __func__, Index: sys/dev/ath/if_ath_misc.h =================================================================== --- sys/dev/ath/if_ath_misc.h +++ sys/dev/ath/if_ath_misc.h @@ -46,6 +46,7 @@ extern int ath_txbuf_mgmt; extern int ath_tx_findrix(const struct ath_softc *sc, uint8_t rate); +extern int ath_tx_findrix_byidx(const struct ath_softc *sc, uint16_t rate_idx); extern struct ath_buf * ath_getbuf(struct ath_softc *sc, ath_buf_type_t btype); Index: sys/dev/ath/if_ath_tdma.c =================================================================== --- sys/dev/ath/if_ath_tdma.c +++ sys/dev/ath/if_ath_tdma.c @@ -253,7 +253,7 @@ { struct ath_hal *ah = sc->sc_ah; struct ieee80211com *ic = &sc->sc_ic; - const struct ieee80211_txparam *tp; + const struct ieee80211_txparam_vht *tp; const struct ieee80211_tdma_state *tdma = NULL; int rix; @@ -275,10 +275,10 @@ * preamble and plcp in its calculation). */ tdma = vap->iv_tdma; - if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) - rix = ath_tx_findrix(sc, tp->ucastrate); + if (tp->ucastrate != IEEE80211_RATE_NONEXISTENT) + rix = ath_tx_findrix_byidx(sc, tp->ucastrate); else - rix = ath_tx_findrix(sc, tp->mcastrate); + rix = ath_tx_findrix_byidx(sc, tp->mcastrate); /* * If the chip supports enforcing TxOP on transmission, Index: sys/dev/ath/if_ath_tx.c =================================================================== --- sys/dev/ath/if_ath_tx.c +++ sys/dev/ath/if_ath_tx.c @@ -1289,7 +1289,7 @@ * use it. */ if (bf->bf_state.bfs_ctsrate0 != 0) - cix = ath_tx_findrix(sc, bf->bf_state.bfs_ctsrate0); + cix = ath_tx_findrix_byidx(sc, bf->bf_state.bfs_ctsrate0); else /* Control rate from above */ cix = rt->info[rix].controlRate; @@ -2241,7 +2241,7 @@ KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); /* Fetch first rate information */ - rix = ath_tx_findrix(sc, params->ibp_rate0); + rix = ath_tx_findrix_byidx(sc, params->ibp_rate0); try0 = params->ibp_try0; /* @@ -2345,15 +2345,15 @@ if (ismrr) { int rix; - rix = ath_tx_findrix(sc, params->ibp_rate1); + rix = ath_tx_findrix_byidx(sc, params->ibp_rate1); bf->bf_state.bfs_rc[1].rix = rix; bf->bf_state.bfs_rc[1].tries = params->ibp_try1; - rix = ath_tx_findrix(sc, params->ibp_rate2); + rix = ath_tx_findrix_byidx(sc, params->ibp_rate2); bf->bf_state.bfs_rc[2].rix = rix; bf->bf_state.bfs_rc[2].tries = params->ibp_try2; - rix = ath_tx_findrix(sc, params->ibp_rate3); + rix = ath_tx_findrix_byidx(sc, params->ibp_rate3); bf->bf_state.bfs_rc[3].rix = rix; bf->bf_state.bfs_rc[3].tries = params->ibp_try3; } Index: sys/dev/bwi/bwimac.c =================================================================== --- sys/dev/bwi/bwimac.c +++ sys/dev/bwi/bwimac.c @@ -94,7 +94,6 @@ static void bwi_mac_set_retry_lim(struct bwi_mac *, const struct bwi_retry_lim *); static void bwi_mac_set_ackrates(struct bwi_mac *, - const struct ieee80211_rate_table *rt, const struct ieee80211_rateset *); static int bwi_mac_gpio_init(struct bwi_mac *); @@ -1338,7 +1337,7 @@ struct bwi_softc *sc = mac->mac_sc; struct bwi_phy *phy = &mac->mac_phy; struct ieee80211com *ic = &sc->sc_ic; - const struct ieee80211_rate_table *rt; + enum ieee80211_phymode mode; struct bwi_retry_lim lim; uint16_t cw_min; @@ -1363,17 +1362,11 @@ * on the char rateset of the IBSS/BSS to join. * XXX this is all wrong; should be done on channel change */ - if (phy->phy_mode == IEEE80211_MODE_11B) { - rt = ieee80211_get_ratetable( - ieee80211_find_channel(ic, 2412, IEEE80211_CHAN_B)); - bwi_mac_set_ackrates(mac, rt, - &ic->ic_sup_rates[IEEE80211_MODE_11B]); - } else { - rt = ieee80211_get_ratetable( - ieee80211_find_channel(ic, 2412, IEEE80211_CHAN_G)); - bwi_mac_set_ackrates(mac, rt, - &ic->ic_sup_rates[IEEE80211_MODE_11G]); - } + if (phy->phy_mode == IEEE80211_MODE_11B) + mode = IEEE80211_MODE_11B; + else + mode = IEEE80211_MODE_11G; + bwi_mac_set_ackrates(mac, ic->ic_sup_rates[mode]); /* * Set CW min @@ -1408,18 +1401,19 @@ } static void -bwi_mac_set_ackrates(struct bwi_mac *mac, const struct ieee80211_rate_table *rt, - const struct ieee80211_rateset *rs) +bwi_mac_set_ackrates(struct bwi_mac *mac, const struct ieee80211_rateset *rs) { int i; /* XXX not standard conforming */ for (i = 0; i < rs->rs_nrates; ++i) { + const struct ieee80211_rate_t *rate; enum ieee80211_phytype modtype; uint16_t ofs; - modtype = ieee80211_rate2phytype(rt, - rs->rs_rates[i] & IEEE80211_RATE_VAL); + rate = ieee80211_get_rate(rs->rates[i].rs_index); + modtype = rate->type; + switch (modtype) { case IEEE80211_T_DS: ofs = 0x4c0; @@ -1430,9 +1424,7 @@ default: panic("unsupported modtype %u\n", modtype); } - ofs += 2*(ieee80211_rate2plcp( - rs->rs_rates[i] & IEEE80211_RATE_VAL, - modtype) & 0xf); + ofs += 2 * (ieee80211_rate2plcp(rate->value, modtype) & 0xf); MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, ofs + 0x20, MOBJ_READ_2(mac, BWI_COMM_MOBJ, ofs)); Index: sys/dev/bwi/if_bwi.c =================================================================== --- sys/dev/bwi/if_bwi.c +++ sys/dev/bwi/if_bwi.c @@ -518,8 +518,6 @@ ic->ic_transmit = bwi_transmit; ic->ic_parent = bwi_parent; - sc->sc_rates = ieee80211_get_ratetable(ic->ic_curchan); - ieee80211_radiotap_attach(ic, &sc->sc_tx_th.wt_ihdr, sizeof(sc->sc_tx_th), BWI_TX_RADIOTAP_PRESENT, @@ -1730,8 +1728,6 @@ mac = (struct bwi_mac *)sc->sc_cur_regwin; bwi_rf_set_chan(mac, ieee80211_chan2ieee(ic, c), 0); - sc->sc_rates = ieee80211_get_ratetable(c); - /* * Setup radio tap channel freq and flags */ @@ -2904,27 +2900,26 @@ } static __inline void -bwi_plcp_header(const struct ieee80211_rate_table *rt, - void *plcp, int pkt_len, uint8_t rate) +bwi_plcp_header(void *plcp, int pkt_len, const struct ieee80211_rate_t *rate) { - enum ieee80211_phytype modtype; /* * Assume caller has zeroed 'plcp' */ - modtype = ieee80211_rate2phytype(rt, rate); - if (modtype == IEEE80211_T_OFDM) - bwi_ofdm_plcp_header(plcp, pkt_len, rate); - else if (modtype == IEEE80211_T_DS) - bwi_ds_plcp_header(plcp, pkt_len, rate); + if (rate->type == IEEE80211_T_OFDM) + bwi_ofdm_plcp_header(plcp, pkt_len, rate->value); + else if (rate->type == IEEE80211_T_DS) + bwi_ds_plcp_header(plcp, pkt_len, rate->value); else - panic("unsupport modulation type %u\n", modtype); + panic("unsupport modulation type %u\n", rate->type); } static int bwi_encap(struct bwi_softc *sc, int idx, struct mbuf *m, struct ieee80211_node *ni) { + const struct ieee80211_rate_t *rate, *rate_fb; + const struct ieee80211_txparam_vht *tp = ni->ni_txparms; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = &sc->sc_ic; struct bwi_ring_data *rd = &sc->sc_tx_rdata[BWI_TX_DATA_RING]; @@ -2933,10 +2928,8 @@ struct bwi_mac *mac; struct bwi_txbuf_hdr *hdr; struct ieee80211_frame *wh; - const struct ieee80211_txparam *tp = ni->ni_txparms; - uint8_t rate, rate_fb; uint32_t mac_ctrl; - uint16_t phy_ctrl; + uint16_t phy_ctrl, rate_idx, rate_fb_idx; bus_addr_t paddr; int type, ismcast, pkt_len, error, rix; #if 0 @@ -2959,26 +2952,28 @@ * Find TX rate */ if (type != IEEE80211_FC0_TYPE_DATA || (m->m_flags & M_EAPOL)) { - rate = rate_fb = tp->mgmtrate; + rate_idx = rate_fb_idx = tp->mgmtrate; } else if (ismcast) { - rate = rate_fb = tp->mcastrate; - } else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { - rate = rate_fb = tp->ucastrate; + rate_idx = rate_fb_idx = tp->mcastrate; + } else if (tp->ucastrate != IEEE80211_RATE_NONEXISTENT) { + rate_idx = rate_fb_idx = tp->ucastrate; } else { rix = ieee80211_ratectl_rate(ni, NULL, pkt_len); - rate = ni->ni_txrate; + rate_idx = ni->ni_txrate; - if (rix > 0) { - rate_fb = ni->ni_rates.rs_rates[rix-1] & - IEEE80211_RATE_VAL; - } else { - rate_fb = rate; - } + if (rix > 0) + rate_fb_idx = ni->ni_rates.rates[rix-1].rs_index; + else + rate_fb_idx = rate_idx; } - tb->tb_rate[0] = rate; - tb->tb_rate[1] = rate_fb; - sc->sc_tx_rate = rate; + rate = ieee80211_get_rate(rate_idx); + rate_fb = ieee80211_get_rate(rate_fb_idx); + + tb->tb_rate[0] = rate->value; + tb->tb_rate[1] = rate_fb->value; + sc->sc_tx_rate = rate->value; + /* * TX radio tap */ @@ -2986,12 +2981,12 @@ sc->sc_tx_th.wt_flags = 0; if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP; - if (ieee80211_rate2phytype(sc->sc_rates, rate) == IEEE80211_T_DS && - (ic->ic_flags & IEEE80211_F_SHPREAMBLE) && - rate != (1 * 2)) { + if (rate->type == IEEE80211_T_CCK && + rate->props.cck.short_preamble && + (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) { sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; } - sc->sc_tx_th.wt_rate = rate; + sc->sc_tx_th.wt_rate = rate->value; ieee80211_radiotap_tx(vap, m); } @@ -3015,8 +3010,8 @@ if (!ismcast) { uint16_t dur; - dur = ieee80211_ack_duration(sc->sc_rates, rate, - ic->ic_flags & ~IEEE80211_F_SHPREAMBLE); + dur = ieee80211_ack_duration(ic->ic_rt->ctl_rates, + rate_idx, ic->ic_flags & ~IEEE80211_F_SHPREAMBLE); hdr->txh_fb_duration = htole16(dur); } @@ -3024,20 +3019,21 @@ hdr->txh_id = __SHIFTIN(BWI_TX_DATA_RING, BWI_TXH_ID_RING_MASK) | __SHIFTIN(idx, BWI_TXH_ID_IDX_MASK); - bwi_plcp_header(sc->sc_rates, hdr->txh_plcp, pkt_len, rate); - bwi_plcp_header(sc->sc_rates, hdr->txh_fb_plcp, pkt_len, rate_fb); + bwi_plcp_header(hdr->txh_plcp, pkt_len, rate); + bwi_plcp_header(hdr->txh_fb_plcp, pkt_len, rate_fb); phy_ctrl = __SHIFTIN(mac->mac_rf.rf_ant_mode, BWI_TXH_PHY_C_ANTMODE_MASK); - if (ieee80211_rate2phytype(sc->sc_rates, rate) == IEEE80211_T_OFDM) + if (rate->type == IEEE80211_T_OFDM) phy_ctrl |= BWI_TXH_PHY_C_OFDM; - else if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && rate != (2 * 1)) + else if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && + rate->props.cck.short_preamble) phy_ctrl |= BWI_TXH_PHY_C_SHPREAMBLE; mac_ctrl = BWI_TXH_MAC_C_HWSEQ | BWI_TXH_MAC_C_FIRST_FRAG; if (!ismcast) mac_ctrl |= BWI_TXH_MAC_C_ACK; - if (ieee80211_rate2phytype(sc->sc_rates, rate_fb) == IEEE80211_T_OFDM) + if (rate_fb->type == IEEE80211_T_OFDM) mac_ctrl |= BWI_TXH_MAC_C_FB_OFDM; hdr->txh_mac_ctrl = htole32(mac_ctrl); @@ -3116,6 +3112,7 @@ bwi_encap_raw(struct bwi_softc *sc, int idx, struct mbuf *m, struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) { + const struct ieee80211_rate_t *rate, *rate_fb; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; struct bwi_ring_data *rd = &sc->sc_tx_rdata[BWI_TX_DATA_RING]; @@ -3124,7 +3121,6 @@ struct bwi_mac *mac; struct bwi_txbuf_hdr *hdr; struct ieee80211_frame *wh; - uint8_t rate, rate_fb; uint32_t mac_ctrl; uint16_t phy_ctrl; bus_addr_t paddr; @@ -3143,25 +3139,21 @@ /* * Find TX rate */ - rate = params->ibp_rate0; - if (!ieee80211_isratevalid(ic->ic_rt, rate)) { + rate = ieee80211_get_rate_safe(params->ibp_rate0); + if (!rate || !ieee80211_isratevalid(ic->ic_rt, rate)) { /* XXX fall back to mcast/mgmt rate? */ m_freem(m); return EINVAL; } - if (params->ibp_try1 != 0) { - rate_fb = params->ibp_rate1; - if (!ieee80211_isratevalid(ic->ic_rt, rate_fb)) { - /* XXX fall back to rate0? */ - m_freem(m); - return EINVAL; - } - } else + + rate_fb = ieee80211_get_rate_safe(params->ibp_rate1); + if (!rate_fb || !ieee80211_isratevalid(ic->ic_rt, rate_fb)) rate_fb = rate; - tb->tb_rate[0] = rate; - tb->tb_rate[1] = rate_fb; - sc->sc_tx_rate = rate; + tb->tb_rate[0] = rate->value; + tb->tb_rate[1] = rate_fb->value; + sc->sc_tx_rate = rate->value; + /* * TX radio tap */ @@ -3172,7 +3164,7 @@ sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP; if (params->ibp_flags & IEEE80211_BPF_SHORTPRE) sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; - sc->sc_tx_th.wt_rate = rate; + sc->sc_tx_th.wt_rate = rate->value; ieee80211_radiotap_tx(vap, m); } @@ -3197,7 +3189,8 @@ if (!ismcast && (params->ibp_flags & IEEE80211_BPF_NOACK) == 0) { uint16_t dur; - dur = ieee80211_ack_duration(sc->sc_rates, rate_fb, 0); + dur = ieee80211_ack_duration(ic->ic_rt->ctl_rates, + ieee80211_get_rate_index(rate_fb), 0); hdr->txh_fb_duration = htole16(dur); mac_ctrl |= BWI_TXH_MAC_C_ACK; @@ -3206,12 +3199,12 @@ hdr->txh_id = __SHIFTIN(BWI_TX_DATA_RING, BWI_TXH_ID_RING_MASK) | __SHIFTIN(idx, BWI_TXH_ID_IDX_MASK); - bwi_plcp_header(sc->sc_rates, hdr->txh_plcp, pkt_len, rate); - bwi_plcp_header(sc->sc_rates, hdr->txh_fb_plcp, pkt_len, rate_fb); + bwi_plcp_header(hdr->txh_plcp, pkt_len, rate); + bwi_plcp_header(hdr->txh_fb_plcp, pkt_len, rate_fb); phy_ctrl = __SHIFTIN(mac->mac_rf.rf_ant_mode, BWI_TXH_PHY_C_ANTMODE_MASK); - if (ieee80211_rate2phytype(sc->sc_rates, rate) == IEEE80211_T_OFDM) { + if (rate->type == IEEE80211_T_OFDM) { phy_ctrl |= BWI_TXH_PHY_C_OFDM; mac_ctrl |= BWI_TXH_MAC_C_FB_OFDM; } else if (params->ibp_flags & IEEE80211_BPF_SHORTPRE) Index: sys/dev/bwi/if_bwivar.h =================================================================== --- sys/dev/bwi/if_bwivar.h +++ sys/dev/bwi/if_bwivar.h @@ -609,7 +609,6 @@ struct bwi_txstats_data *sc_txstats; int sc_tx_timer; - const struct ieee80211_rate_table *sc_rates; struct bwi_tx_radiotap_hdr sc_tx_th; struct bwi_rx_radiotap_hdr sc_rx_th; Index: sys/dev/bwn/if_bwn.c =================================================================== --- sys/dev/bwn/if_bwn.c +++ sys/dev/bwn/if_bwn.c @@ -6286,40 +6286,32 @@ } static int -bwn_ieeerate2hwrate(struct bwn_softc *sc, int rate) +bwn_ieeerateidx2hwrate(struct bwn_softc *sc, uint16_t rate_idx) { +#define BWN_CHECK_RATE(mod, rv) \ + case IEEE80211_RATE_INDEX_##mod##rv: \ + return (BWN_##mod##_RATE_##rv##MB) - switch (rate) { + switch (rate_idx) { /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */ - case 12: - return (BWN_OFDM_RATE_6MB); - case 18: - return (BWN_OFDM_RATE_9MB); - case 24: - return (BWN_OFDM_RATE_12MB); - case 36: - return (BWN_OFDM_RATE_18MB); - case 48: - return (BWN_OFDM_RATE_24MB); - case 72: - return (BWN_OFDM_RATE_36MB); - case 96: - return (BWN_OFDM_RATE_48MB); - case 108: - return (BWN_OFDM_RATE_54MB); + BWN_CHECK_RATE(OFDM, 6); + BWN_CHECK_RATE(OFDM, 9); + BWN_CHECK_RATE(OFDM, 12); + BWN_CHECK_RATE(OFDM, 18); + BWN_CHECK_RATE(OFDM, 24); + BWN_CHECK_RATE(OFDM, 36); + BWN_CHECK_RATE(OFDM, 48); + BWN_CHECK_RATE(OFDM, 54); /* CCK rates (NB: not IEEE std, device-specific) */ - case 2: - return (BWN_CCK_RATE_1MB); - case 4: - return (BWN_CCK_RATE_2MB); - case 11: - return (BWN_CCK_RATE_5MB); - case 22: - return (BWN_CCK_RATE_11MB); + BWN_CHECK_RATE(CCK, 1); + BWN_CHECK_RATE(CCK, 2); + BWN_CHECK_RATE(CCK, 5); + BWN_CHECK_RATE(CCK, 11); } - device_printf(sc->sc_dev, "unsupported rate %d\n", rate); + device_printf(sc->sc_dev, "unsupported rate %u\n", rate_idx); return (BWN_CCK_RATE_1MB); +#undef BWN_CHECK_RATE } static uint16_t @@ -6397,11 +6389,13 @@ bwn_set_txhdr(struct bwn_mac *mac, struct ieee80211_node *ni, struct mbuf *m, struct bwn_txhdr *txhdr, uint16_t cookie) { + const struct ieee80211_channel *chan; + const struct ieee80211_rate_t *rate_t_ptr; const struct bwn_phy *phy = &mac->mac_phy; struct bwn_softc *sc = mac->mac_sc; struct ieee80211_frame *wh; struct ieee80211_frame *protwh; - const struct ieee80211_txparam *tp = ni->ni_txparms; + const struct ieee80211_txparam_vht *tp = ni->ni_txparms; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = &sc->sc_ic; struct mbuf *mprot; @@ -6410,6 +6404,7 @@ uint32_t macctl = 0; int rts_rate, rts_rate_fb, ismcast, isshort, rix, type; uint16_t phyctl = 0; + uint16_t rate_idx, rate_fb_idx; uint8_t rate, rate_fb; int fill_phy_ctl1 = 0; @@ -6419,6 +6414,8 @@ type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0; + chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ? + ni->ni_chan : ic->ic_curchan; if ((phy->type == BWN_PHYTYPE_N) || (phy->type == BWN_PHYTYPE_LP) || (phy->type == BWN_PHYTYPE_HT)) @@ -6428,41 +6425,39 @@ * Find TX rate */ if (type != IEEE80211_FC0_TYPE_DATA || (m->m_flags & M_EAPOL)) - rate = rate_fb = tp->mgmtrate; + rate_idx = rate_fb_idx = tp->mgmtrate; else if (ismcast) - rate = rate_fb = tp->mcastrate; - else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) - rate = rate_fb = tp->ucastrate; + rate_idx = rate_fb_idx = tp->mcastrate; + else if (tp->ucastrate != IEEE80211_RATE_NONEXISTENT) + rate_idx = rate_fb_idx = tp->ucastrate; else { rix = ieee80211_ratectl_rate(ni, NULL, 0); - rate = ni->ni_txrate; + rate_idx = ni->ni_txrate; if (rix > 0) - rate_fb = ni->ni_rates.rs_rates[rix - 1] & - IEEE80211_RATE_VAL; + rate_fb_idx = ni->ni_rates.rates[rix - 1].rs_index; else - rate_fb = rate; + rate_fb_idx = rate_idx; } - sc->sc_tx_rate = rate; + rate_t_ptr = ieee80211_get_rate(rate_idx); - /* Note: this maps the select ieee80211 rate to hardware rate */ - rate = bwn_ieeerate2hwrate(sc, rate); - rate_fb = bwn_ieeerate2hwrate(sc, rate_fb); + sc->sc_tx_rate = rate_t_ptr->value; + rate = bwn_ieeerateidx2hwrate(sc, rate_idx); + rate_fb = bwn_ieeerateidx2hwrate(sc, rate_fb_idx); txhdr->phyrate = (BWN_ISOFDMRATE(rate)) ? bwn_plcp_getofdm(rate) : bwn_plcp_getcck(rate); bcopy(wh->i_fc, txhdr->macfc, sizeof(txhdr->macfc)); bcopy(wh->i_addr1, txhdr->addr1, IEEE80211_ADDR_LEN); - /* XXX rate/rate_fb is the hardware rate */ if ((rate_fb == rate) || (*(u_int16_t *)wh->i_dur & htole16(0x8000)) || (*(u_int16_t *)wh->i_dur == htole16(0))) txhdr->dur_fb = *(u_int16_t *)wh->i_dur; else - txhdr->dur_fb = ieee80211_compute_duration(ic->ic_rt, - m->m_pkthdr.len, rate, isshort); + txhdr->dur_fb = ieee80211_compute_duration(rate_idx, + m->m_pkthdr.len, chan->ic_flags, isshort); /* XXX TX encryption */ @@ -6489,9 +6484,9 @@ txhdr->chan = phy->chan; phyctl |= (BWN_ISOFDMRATE(rate)) ? BWN_TX_PHY_ENC_OFDM : BWN_TX_PHY_ENC_CCK; - /* XXX preamble? obey net80211 */ - if (isshort && (rate == BWN_CCK_RATE_2MB || rate == BWN_CCK_RATE_5MB || - rate == BWN_CCK_RATE_11MB)) + + if (isshort && rate_t_ptr->type == IEEE80211_T_CCK && + rate_t_ptr->props.cck.short_preamble) phyctl |= BWN_TX_PHY_SHORTPRMBL; if (! phy->gmode) @@ -6536,8 +6531,7 @@ rts_rate = BWN_OFDM_RATE_6MB; rts_rate_fb = bwn_get_fbrate(rts_rate); - /* XXX 'rate' here is hardware rate now, not the net80211 rate */ - mprot = ieee80211_alloc_prot(ni, m, rate, ic->ic_protmode); + mprot = ieee80211_alloc_prot(ni, m, rate_idx, ic->ic_protmode); if (mprot == NULL) { if_inc_counter(vap->iv_ifp, IFCOUNTER_OERRORS, 1); device_printf(sc->sc_dev, @@ -6648,11 +6642,11 @@ sc->sc_tx_th.wt_flags = 0; if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP; - if (isshort && - (rate == BWN_CCK_RATE_2MB || rate == BWN_CCK_RATE_5MB || - rate == BWN_CCK_RATE_11MB)) + if (isshort && rate_t_ptr->type == IEEE80211_T_CCK && + rate_t_ptr->props.cck.short_preamble) sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; - sc->sc_tx_th.wt_rate = rate; + sc->sc_tx_th.wt_rate = + ieee80211_convert_to_legacy_rate(rate_idx); ieee80211_radiotap_tx(vap, m); } Index: sys/dev/if_ndis/if_ndis.c =================================================================== --- sys/dev/if_ndis/if_ndis.c +++ sys/dev/if_ndis/if_ndis.c @@ -723,11 +723,154 @@ return (error); } +static void +ndis_init_ratesets(struct ndis_softc *sc) +{ +#define SETRATE(rs, mode, rv) \ + do { \ + uint16_t idx; \ + \ + idx = ieee80211_convert_from_legacy_rate(rv, mode); \ + if (idx != IEEE80211_RATE_NONEXISTENT) { \ + setbit(rs->rs_bitmap, (rv)); \ + rs->rates[rs->rs_nrates].rs_index = (idx); \ + rs->rs_nrates++; \ + } \ + } while (0) + + struct ieee80211com *ic = &sc->ndis_ic; + struct ieee80211_rateset *rs_11a, *rs_11b, *rs_11g; + ndis_80211_rates_ex rates; + const struct { + enum ieee80211_phymode mode; + struct ieee80211_rateset *rs; + uint16_t rates[4]; + int nrates; + } rates_to_rateset[3] = { + { + .mode = IEEE80211_MODE_11A, + .rs = &sc->ndis_supp_rates[0], + .rates = { + IEEE80211_RATE_INDEX_OFDM24, + IEEE80211_RATE_INDEX_OFDM36, + IEEE80211_RATE_INDEX_OFDM48, + IEEE80211_RATE_INDEX_OFDM54 + }, + .nrates = 4 + }, + { + .mode = IEEE80211_MODE_11B, + .rs = &sc->ndis_supp_rates[1], + .rates = { + IEEE80211_RATE_INDEX_CCK1, + IEEE80211_RATE_INDEX_CCK2, + IEEE80211_RATE_INDEX_CCK5, + IEEE80211_RATE_INDEX_CCK11 + }, + .nrates = 4 + }, + { + .mode = IEEE80211_MODE_11G, + .rs = &sc->ndis_supp_rates[2], + .rates = { + IEEE80211_RATE_INDEX_OFDM24, + IEEE80211_RATE_INDEX_OFDM36, + IEEE80211_RATE_INDEX_OFDM48, + IEEE80211_RATE_INDEX_OFDM54 + }, + .nrates = 4 + }, + }; + int i, j, len, r; + + rs_11a = &sc->ndis_supp_rates[0]; + rs_11b = &sc->ndis_supp_rates[1]; + rs_11g = &sc->ndis_supp_rates[2]; + + len = sizeof(rates); + bzero((char *)&rates, len); + r = ndis_get_info(sc, OID_802_11_SUPPORTED_RATES, (void *)rates, &len); + if (r != 0) + device_printf(sc->ndis_dev, "get rates failed: 0x%x\n", r); + /* + * Since the supported rates only up to 8 can be supported, + * if this is not 802.11b we're just going to be faking it + * all up to heck. + */ + + if (isset(ic->ic_modecaps, IEEE80211_MODE_11A)) + rs_11a->rs_nrates = 0; + if (isset(ic->ic_modecaps, IEEE80211_MODE_11B)) + rs_11b->rs_nrates = 0; + if (isset(ic->ic_modecaps, IEEE80211_MODE_11G)) + rs_11g->rs_nrates = 0; + + for (i = 0; i < len; i++) { + switch (rates[i] & IEEE80211_RATE_VAL) { + case 2: + case 4: + case 11: + case 10: + case 22: + if (isclr(ic->ic_modecaps, IEEE80211_MODE_11B)) { + /* Lazy-init 802.11b. */ + setbit(ic->ic_modecaps, IEEE80211_MODE_11B); + rs_11b->rs_nrates = 0; + } + SETRATE(rs_11b, IEEE80211_MODE_11B, rates[i]); + break; + default: + if (isset(ic->ic_modecaps, IEEE80211_MODE_11A)) + SETRATE(rs_11a, IEEE80211_MODE_11A, rates[i]); + if (isset(ic->ic_modecaps, IEEE80211_MODE_11G)) + SETRATE(rs_11g, IEEE80211_MODE_11G, rates[i]); + break; + } + } + + /* + * If the hardware supports 802.11g, it most + * likely supports 802.11b and all of the + * 802.11b and 802.11g speeds, so maybe we can + * just cheat here. Just how in the heck do + * we detect turbo modes, though? + */ + for (i = 0; i < nitems(rates_to_rateset); i++) { + struct ieee80211_rateset *rs; + const uint16_t *supp_rates; + int is_basic; + + if (isclr(ic->ic_modecaps, rates_to_rateset[i].mode)) + continue; + + rs = rates_to_rateset[i].rs; + supp_rates = rates_to_rateset[i].rates; + is_basic = (rates_to_rateset[i].mode == IEEE80211_MODE_11B); + + for (j = 0; j < rates_to_rateset[i].nrates; j++) { + uint8_t rv; + + rv = ieee80211_convert_to_legacy_rate(supp_rates[j]); + if (isset(rs->rs_bitmap, rv)) + continue; + + setbit(rs->rs_bitmap, rv); + rs->rates[rs->rs_nrates].rs_index = supp_rates[j]; + rs->rates[rs->rs_nrates].rs_basic = is_basic; + rs->rs_nrates++; + } + } + + ic->ic_sup_rates[IEEE80211_MODE_11A] = rs_11a; + ic->ic_sup_rates[IEEE80211_MODE_11B] = rs_11b; + ic->ic_sup_rates[IEEE80211_MODE_11G] = rs_11g; +#undef SETRATE +} + static int ndis_80211attach(struct ndis_softc *sc) { struct ieee80211com *ic = &sc->ndis_ic; - ndis_80211_rates_ex rates; struct ndis_80211_nettype_list *ntl; uint32_t arg; int mode, i, r, len, nonettypes = 1; @@ -771,101 +914,10 @@ setbit(ic->ic_modecaps, IEEE80211_MODE_11B); setbit(bands, IEEE80211_MODE_11B); } - len = sizeof(rates); - bzero((char *)&rates, len); - r = ndis_get_info(sc, OID_802_11_SUPPORTED_RATES, (void *)rates, &len); - if (r != 0) - device_printf(sc->ndis_dev, "get rates failed: 0x%x\n", r); - /* - * Since the supported rates only up to 8 can be supported, - * if this is not 802.11b we're just going to be faking it - * all up to heck. - */ -#define TESTSETRATE(x, y) \ - do { \ - int i; \ - for (i = 0; i < ic->ic_sup_rates[x].rs_nrates; i++) { \ - if (ic->ic_sup_rates[x].rs_rates[i] == (y)) \ - break; \ - } \ - if (i == ic->ic_sup_rates[x].rs_nrates) { \ - ic->ic_sup_rates[x].rs_rates[i] = (y); \ - ic->ic_sup_rates[x].rs_nrates++; \ - } \ - } while (0) - -#define SETRATE(x, y) \ - ic->ic_sup_rates[x].rs_rates[ic->ic_sup_rates[x].rs_nrates] = (y) -#define INCRATE(x) \ - ic->ic_sup_rates[x].rs_nrates++ - ic->ic_curmode = IEEE80211_MODE_AUTO; - if (isset(ic->ic_modecaps, IEEE80211_MODE_11A)) - ic->ic_sup_rates[IEEE80211_MODE_11A].rs_nrates = 0; - if (isset(ic->ic_modecaps, IEEE80211_MODE_11B)) - ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates = 0; - if (isset(ic->ic_modecaps, IEEE80211_MODE_11G)) - ic->ic_sup_rates[IEEE80211_MODE_11G].rs_nrates = 0; - for (i = 0; i < len; i++) { - switch (rates[i] & IEEE80211_RATE_VAL) { - case 2: - case 4: - case 11: - case 10: - case 22: - if (isclr(ic->ic_modecaps, IEEE80211_MODE_11B)) { - /* Lazy-init 802.11b. */ - setbit(ic->ic_modecaps, IEEE80211_MODE_11B); - ic->ic_sup_rates[IEEE80211_MODE_11B]. - rs_nrates = 0; - } - SETRATE(IEEE80211_MODE_11B, rates[i]); - INCRATE(IEEE80211_MODE_11B); - break; - default: - if (isset(ic->ic_modecaps, IEEE80211_MODE_11A)) { - SETRATE(IEEE80211_MODE_11A, rates[i]); - INCRATE(IEEE80211_MODE_11A); - } - if (isset(ic->ic_modecaps, IEEE80211_MODE_11G)) { - SETRATE(IEEE80211_MODE_11G, rates[i]); - INCRATE(IEEE80211_MODE_11G); - } - break; - } - } + ndis_init_ratesets(sc); - /* - * If the hardware supports 802.11g, it most - * likely supports 802.11b and all of the - * 802.11b and 802.11g speeds, so maybe we can - * just cheat here. Just how in the heck do - * we detect turbo modes, though? - */ - if (isset(ic->ic_modecaps, IEEE80211_MODE_11B)) { - TESTSETRATE(IEEE80211_MODE_11B, IEEE80211_RATE_BASIC|2); - TESTSETRATE(IEEE80211_MODE_11B, IEEE80211_RATE_BASIC|4); - TESTSETRATE(IEEE80211_MODE_11B, IEEE80211_RATE_BASIC|11); - TESTSETRATE(IEEE80211_MODE_11B, IEEE80211_RATE_BASIC|22); - } - if (isset(ic->ic_modecaps, IEEE80211_MODE_11G)) { - TESTSETRATE(IEEE80211_MODE_11G, 48); - TESTSETRATE(IEEE80211_MODE_11G, 72); - TESTSETRATE(IEEE80211_MODE_11G, 96); - TESTSETRATE(IEEE80211_MODE_11G, 108); - } - if (isset(ic->ic_modecaps, IEEE80211_MODE_11A)) { - TESTSETRATE(IEEE80211_MODE_11A, 48); - TESTSETRATE(IEEE80211_MODE_11A, 72); - TESTSETRATE(IEEE80211_MODE_11A, 96); - TESTSETRATE(IEEE80211_MODE_11A, 108); - } - -#undef SETRATE -#undef INCRATE -#undef TESTSETRATE - ieee80211_init_channels(ic, NULL, bands); /* @@ -2355,16 +2407,30 @@ ndis_media_status(struct ifnet *ifp, struct ifmediareq *imr) { struct ieee80211vap *vap = ifp->if_softc; - struct ndis_softc *sc = vap->iv_ic->ic_softc; + struct ieee80211com *ic = vap->iv_ic; + struct ndis_softc *sc = ic->ic_softc; + enum ieee80211_phymode mode; uint32_t txrate; + uint16_t rate_idx; int len; if (!NDIS_INITIALIZED(sc)) return; len = sizeof(txrate); - if (ndis_get_info(sc, OID_GEN_LINK_SPEED, &txrate, &len) == 0) - vap->iv_bss->ni_txrate = txrate / 5000; + if (ndis_get_info(sc, OID_GEN_LINK_SPEED, &txrate, &len) == 0) { + mode = ieee80211_chan2mode(ic->ic_curchan); + txrate /= 5000; + + rate_idx = ieee80211_convert_from_legacy_rate(txrate, mode); + if (rate_idx != IEEE80211_RATE_NONEXISTENT) + vap->iv_bss->ni_txrate = rate_idx; + else { + device_printf(sc->ndis_dev, + "rate %u for mode %u was not found\n", + txrate, mode); + } + } ieee80211_media_status(ifp, imr); } Index: sys/dev/if_ndis/if_ndisvar.h =================================================================== --- sys/dev/if_ndis/if_ndisvar.h +++ sys/dev/if_ndis/if_ndisvar.h @@ -166,6 +166,7 @@ }; struct { /* Wireless */ struct ieee80211com ndis_ic; + struct ieee80211_rateset ndis_supp_rates[3]; struct callout ndis_scan_callout; int (*ndis_newstate)(struct ieee80211com *, enum ieee80211_state, int); Index: sys/dev/iwi/if_iwi.c =================================================================== --- sys/dev/iwi/if_iwi.c +++ sys/dev/iwi/if_iwi.c @@ -920,6 +920,29 @@ } /* + * Convert h/w rate code to global rate index. + */ +static uint16_t +iwi_cvtrate_idx(uint32_t iwirate) +{ + switch (iwirate) { + case IWI_RATE_DS1: return IEEE80211_RATE_INDEX_CCK1; + case IWI_RATE_DS2: return IEEE80211_RATE_INDEX_CCK2; + case IWI_RATE_DS5: return IEEE80211_RATE_INDEX_CCK5; + case IWI_RATE_DS11: return IEEE80211_RATE_INDEX_CCK11; + case IWI_RATE_OFDM6: return IEEE80211_RATE_INDEX_OFDM6; + case IWI_RATE_OFDM9: return IEEE80211_RATE_INDEX_OFDM9; + case IWI_RATE_OFDM12: return IEEE80211_RATE_INDEX_OFDM12; + case IWI_RATE_OFDM18: return IEEE80211_RATE_INDEX_OFDM18; + case IWI_RATE_OFDM24: return IEEE80211_RATE_INDEX_OFDM24; + case IWI_RATE_OFDM36: return IEEE80211_RATE_INDEX_OFDM36; + case IWI_RATE_OFDM48: return IEEE80211_RATE_INDEX_OFDM48; + case IWI_RATE_OFDM54: return IEEE80211_RATE_INDEX_OFDM54; + default: return IEEE80211_RATE_NONEXISTENT; + } +} + +/* * The firmware automatically adapts the transmit speed. We report its current * value here. */ @@ -930,11 +953,12 @@ struct ieee80211com *ic = vap->iv_ic; struct iwi_softc *sc = ic->ic_softc; struct ieee80211_node *ni; + uint32_t reg; /* read current transmission rate from adapter */ + reg = CSR_READ_4(sc, IWI_CSR_CURRENT_TX_RATE); ni = ieee80211_ref_node(vap->iv_bss); - ni->ni_txrate = - iwi_cvtrate(CSR_READ_4(sc, IWI_CSR_CURRENT_TX_RATE)); + ni->ni_txrate = iwi_cvtrate_idx(reg); ieee80211_free_node(ni); ieee80211_media_status(ifp, imr); } @@ -2553,7 +2577,9 @@ iwi_set_rateset(struct iwi_softc *sc, const struct ieee80211_rateset *net_rs, int mode, int type) { + const struct ieee80211_rate_t *rate; struct iwi_rateset rs; + int i; memset(&rs, 0, sizeof(rs)); rs.mode = mode; @@ -2564,7 +2590,10 @@ rs.nrates)); rs.nrates = nitems(rs.rates); } - memcpy(rs.rates, net_rs->rs_rates, rs.nrates); + for (i = 0; i < rs.nrates; i++) { + rate = ieee80211_get_rate(net_rs->rates[i].rs_index); + rs.rates[i] = rate->value; + } DPRINTF(("Setting .11%c%s %s rates (%u)\n", mode == IWI_MODE_11A ? 'a' : 'b', mode == IWI_MODE_11G ? "g" : "", @@ -2627,12 +2656,12 @@ return error; } - error = iwi_set_rateset(sc, &ic->ic_sup_rates[IEEE80211_MODE_11G], + error = iwi_set_rateset(sc, ic->ic_sup_rates[IEEE80211_MODE_11G], IWI_MODE_11G, IWI_RATESET_TYPE_SUPPORTED); if (error != 0) return error; - error = iwi_set_rateset(sc, &ic->ic_sup_rates[IEEE80211_MODE_11A], + error = iwi_set_rateset(sc, ic->ic_sup_rates[IEEE80211_MODE_11A], IWI_MODE_11A, IWI_RATESET_TYPE_SUPPORTED); if (error != 0) return error; Index: sys/dev/iwm/if_iwm.c =================================================================== --- sys/dev/iwm/if_iwm.c +++ sys/dev/iwm/if_iwm.c @@ -203,22 +203,22 @@ * XXX For now, there's simply a fixed set of rate table entries * that are populated. */ -const struct iwm_rate { - uint8_t rate; +static const struct iwm_rate { + uint8_t rate_idx; uint8_t plcp; } iwm_rates[] = { - { 2, IWM_RATE_1M_PLCP }, - { 4, IWM_RATE_2M_PLCP }, - { 11, IWM_RATE_5M_PLCP }, - { 22, IWM_RATE_11M_PLCP }, - { 12, IWM_RATE_6M_PLCP }, - { 18, IWM_RATE_9M_PLCP }, - { 24, IWM_RATE_12M_PLCP }, - { 36, IWM_RATE_18M_PLCP }, - { 48, IWM_RATE_24M_PLCP }, - { 72, IWM_RATE_36M_PLCP }, - { 96, IWM_RATE_48M_PLCP }, - { 108, IWM_RATE_54M_PLCP }, + { IEEE80211_RATE_INDEX_CCK1, IWM_RATE_1M_PLCP }, + { IEEE80211_RATE_INDEX_CCK2, IWM_RATE_2M_PLCP }, + { IEEE80211_RATE_INDEX_CCK5, IWM_RATE_5M_PLCP }, + { IEEE80211_RATE_INDEX_CCK11, IWM_RATE_11M_PLCP }, + { IEEE80211_RATE_INDEX_OFDM6, IWM_RATE_6M_PLCP }, + { IEEE80211_RATE_INDEX_OFDM9, IWM_RATE_9M_PLCP }, + { IEEE80211_RATE_INDEX_OFDM12, IWM_RATE_12M_PLCP }, + { IEEE80211_RATE_INDEX_OFDM18, IWM_RATE_18M_PLCP }, + { IEEE80211_RATE_INDEX_OFDM24, IWM_RATE_24M_PLCP }, + { IEEE80211_RATE_INDEX_OFDM36, IWM_RATE_36M_PLCP }, + { IEEE80211_RATE_INDEX_OFDM48, IWM_RATE_48M_PLCP }, + { IEEE80211_RATE_INDEX_OFDM54, IWM_RATE_54M_PLCP }, }; #define IWM_RIDX_CCK 0 #define IWM_RIDX_OFDM 4 @@ -3491,21 +3491,21 @@ */ static int iwm_tx_rateidx_lookup(struct iwm_softc *sc, struct iwm_node *in, - uint8_t rate) + uint16_t rate_idx) { int i; - uint8_t r; + uint16_t r; for (i = 0; i < nitems(in->in_ridx); i++) { - r = iwm_rates[in->in_ridx[i]].rate; - if (rate == r) + r = iwm_rates[in->in_ridx[i]].rate_idx; + if (rate_idx == r) return (i); } IWM_DPRINTF(sc, IWM_DEBUG_XMIT | IWM_DEBUG_TXRATE, - "%s: couldn't find an entry for rate=%d\n", + "%s: couldn't find an entry for rate idx=%u\n", __func__, - rate); + rate_idx); /* XXX Return the first */ /* XXX TODO: have it return the /lowest/ */ @@ -3513,19 +3513,19 @@ } static int -iwm_tx_rateidx_global_lookup(struct iwm_softc *sc, uint8_t rate) +iwm_tx_rateidx_global_lookup(struct iwm_softc *sc, uint16_t rate_idx) { int i; for (i = 0; i < nitems(iwm_rates); i++) { - if (iwm_rates[i].rate == rate) + if (iwm_rates[i].rate_idx == rate_idx) return (i); } /* XXX error? */ IWM_DPRINTF(sc, IWM_DEBUG_XMIT | IWM_DEBUG_TXRATE, - "%s: couldn't find an entry for rate=%d\n", + "%s: couldn't find an entry for rate idx=%u\n", __func__, - rate); + rate_idx); return (0); } @@ -3536,9 +3536,10 @@ iwm_tx_fill_cmd(struct iwm_softc *sc, struct iwm_node *in, struct mbuf *m, struct iwm_tx_cmd *tx) { + const struct ieee80211_rate_t *rate; struct ieee80211_node *ni = &in->in_ni; struct ieee80211_frame *wh; - const struct ieee80211_txparam *tp = ni->ni_txparms; + const struct ieee80211_txparam_vht *tp = ni->ni_txparms; const struct iwm_rate *rinfo; int type; int ridx, rate_flags; @@ -3559,7 +3560,7 @@ ridx = iwm_tx_rateidx_global_lookup(sc, tp->mcastrate); IWM_DPRINTF(sc, IWM_DEBUG_TXRATE, "%s: MCAST (%d)\n", __func__, tp->mcastrate); - } else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { + } else if (tp->ucastrate != IEEE80211_RATE_NONEXISTENT) { ridx = iwm_tx_rateidx_global_lookup(sc, tp->ucastrate); IWM_DPRINTF(sc, IWM_DEBUG_TXRATE, "%s: FIXED_RATE (%d)\n", __func__, tp->ucastrate); @@ -3579,18 +3580,19 @@ IWM_DPRINTF(sc, IWM_DEBUG_XMIT | IWM_DEBUG_TXRATE, "%s: start with i=%d, txrate %d\n", - __func__, i, iwm_rates[ridx].rate); + __func__, i, iwm_rates[ridx].rate_idx); } + rate = ieee80211_get_rate(iwm_ridx2rate(ridx)); IWM_DPRINTF(sc, IWM_DEBUG_XMIT | IWM_DEBUG_TXRATE, - "%s: frame type=%d txrate %d\n", - __func__, type, iwm_rates[ridx].rate); + "%s: frame type=%d txrate %u/%u\n", + __func__, type, rate->type, rate->value); rinfo = &iwm_rates[ridx]; - IWM_DPRINTF(sc, IWM_DEBUG_TXRATE, "%s: ridx=%d; rate=%d, CCK=%d\n", + IWM_DPRINTF(sc, IWM_DEBUG_TXRATE, "%s: ridx=%d; rate=%u/%u, CCK=%d\n", __func__, ridx, - rinfo->rate, + rate->type, rate->value, !! (IWM_RIDX_IS_CCK(ridx)) ); @@ -3661,11 +3663,14 @@ if (ieee80211_radiotap_active_vap(vap)) { struct iwm_tx_radiotap_header *tap = &sc->sc_txtap; + uint8_t rate; + rate = ieee80211_convert_to_legacy_rate(rinfo->rate_idx); + tap->wt_flags = 0; tap->wt_chan_freq = htole16(ni->ni_chan->ic_freq); tap->wt_chan_flags = htole16(ni->ni_chan->ic_flags); - tap->wt_rate = rinfo->rate; + tap->wt_rate = rate; if (k != NULL) tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; ieee80211_radiotap_tx(vap, m); @@ -4165,18 +4170,9 @@ } uint8_t -iwm_ridx2rate(struct ieee80211_rateset *rs, int ridx) +iwm_ridx2rate(int ridx) { - int i; - uint8_t rval; - - for (i = 0; i < rs->rs_nrates; i++) { - rval = (rs->rs_rates[i] & IEEE80211_RATE_VAL); - if (rval == iwm_rates[ridx].rate) - return rs->rs_rates[i]; - } - - return 0; + return (iwm_rates[ridx].rate_idx); } static void @@ -4217,22 +4213,27 @@ * IEEE80211_RATE_MAXSIZE entries! */ for (i = 0; i < min(nrates, IEEE80211_RATE_MAXSIZE); i++) { - int rate = ni->ni_rates.rs_rates[(nrates - 1) - i] & IEEE80211_RATE_VAL; + const struct ieee80211_rate_t *rate; + uint16_t rate_idx; + rate_idx = ni->ni_rates.rates[(nrates - 1) - i].rs_index; + rate = ieee80211_get_rate(rate_idx); + /* Map 802.11 rate to HW rate index. */ for (ridx = 0; ridx <= IWM_RIDX_MAX; ridx++) - if (iwm_rates[ridx].rate == rate) + if (iwm_rates[ridx].rate_idx == rate_idx) break; if (ridx > IWM_RIDX_MAX) { device_printf(sc->sc_dev, - "%s: WARNING: device rate for %d not found!\n", - __func__, rate); + "%s: WARNING: device rate for %u/%u not found!\n", + __func__, rate->type, rate->value); } else { IWM_DPRINTF(sc, IWM_DEBUG_TXRATE, - "%s: rate: i: %d, rate=%d, ridx=%d\n", + "%s: rate: i: %d, rate=%u/%u, ridx=%d\n", __func__, i, - rate, + rate->type, + rate->value, ridx); in->in_ridx[i] = ridx; } @@ -4287,8 +4288,8 @@ if (IWM_RIDX_IS_CCK(ridx)) tab |= IWM_RATE_MCS_CCK_MSK; IWM_DPRINTF(sc, IWM_DEBUG_TXRATE, - "station rate i=%d, rate=%d, hw=%x\n", - i, iwm_rates[ridx].rate, tab); + "station rate i=%d, rate idx=%d, hw=%x\n", + i, iwm_rates[ridx].rate_idx, tab); lq->rs_table[i] = htole32(tab); } /* then fill the rest with the lowest possible rate */ Index: sys/dev/iwm/if_iwm_mac_ctxt.c =================================================================== --- sys/dev/iwm/if_iwm_mac_ctxt.c +++ sys/dev/iwm/if_iwm_mac_ctxt.c @@ -168,6 +168,20 @@ IWM_MVM_TX_FIFO_VO, }; +static int +iwm_is_basic_ridx(const struct ieee80211_rateset *rs, int ridx) +{ + uint16_t rate_idx; + int i; + + rate_idx = iwm_ridx2rate(ridx); + for (i = 0; i < rs->rs_nrates; i++) + if (rs->rates[i].rs_index == rate_idx) + return (rs->rates[i].rs_basic); + + return (0); +} + static void iwm_mvm_ack_rates(struct iwm_softc *sc, int is2ghz, int *cck_rates, int *ofdm_rates, struct iwm_node *in) @@ -181,7 +195,7 @@ if (is2ghz) { for (i = IWM_FIRST_CCK_RATE; i <= IWM_LAST_CCK_RATE; i++) { - if ((iwm_ridx2rate(rs, i) & IEEE80211_RATE_BASIC) == 0) + if (!iwm_is_basic_ridx(rs, i)) continue; cck |= (1 << i); if (lowest_present_cck > i) @@ -189,7 +203,7 @@ } } for (i = IWM_FIRST_OFDM_RATE; i <= IWM_LAST_NON_HT_RATE; i++) { - if ((iwm_ridx2rate(rs, i) & IEEE80211_RATE_BASIC) == 0) + if (!iwm_is_basic_ridx(rs, i)) continue; ofdm |= (1 << (i - IWM_FIRST_OFDM_RATE)); if (lowest_present_ofdm > i) Index: sys/dev/iwm/if_iwm_scan.c =================================================================== --- sys/dev/iwm/if_iwm_scan.c +++ sys/dev/iwm/if_iwm_scan.c @@ -380,10 +380,10 @@ static int iwm_mvm_fill_probe_req(struct iwm_softc *sc, struct iwm_scan_probe_req *preq) { + const struct ieee80211_rateset *rs; struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); struct ieee80211_frame *wh = (struct ieee80211_frame *)preq->buf; - struct ieee80211_rateset *rs; size_t remain = sizeof(preq->buf); uint8_t *frm, *pos; @@ -415,7 +415,7 @@ remain -= frm - (uint8_t *)wh; /* Fill in 2GHz IEs and tell firmware where they are. */ - rs = &ic->ic_sup_rates[IEEE80211_MODE_11G]; + rs = ic->ic_sup_rates[IEEE80211_MODE_11G]; if (rs->rs_nrates > IEEE80211_RATE_SIZE) { if (remain < 4 + rs->rs_nrates) return ENOBUFS; @@ -441,7 +441,7 @@ if (sc->nvm_data->sku_cap_band_52GHz_enable) { /* Fill in 5GHz IEs. */ - rs = &ic->ic_sup_rates[IEEE80211_MODE_11A]; + rs = ic->ic_sup_rates[IEEE80211_MODE_11A]; if (rs->rs_nrates > IEEE80211_RATE_SIZE) { if (remain < 4 + rs->rs_nrates) return ENOBUFS; Index: sys/dev/iwm/if_iwm_util.h =================================================================== --- sys/dev/iwm/if_iwm_util.h +++ sys/dev/iwm/if_iwm_util.h @@ -125,7 +125,7 @@ extern boolean_t iwm_mvm_rx_diversity_allowed(struct iwm_softc *sc); -extern uint8_t iwm_ridx2rate(struct ieee80211_rateset *rs, int ridx); +extern uint8_t iwm_ridx2rate(int ridx); extern int iwm_enable_txq(struct iwm_softc *sc, int sta_id, int qid, int fifo); extern int iwm_mvm_flush_tx_path(struct iwm_softc *sc, uint32_t tfd_msk, uint32_t flags); Index: sys/dev/iwn/if_iwn.c =================================================================== --- sys/dev/iwn/if_iwn.c +++ sys/dev/iwn/if_iwn.c @@ -2756,23 +2756,21 @@ */ static uint32_t iwn_rate_to_plcp(struct iwn_softc *sc, struct ieee80211_node *ni, - uint8_t rate) + const struct ieee80211_rate_t *rate) { - struct ieee80211com *ic = ni->ni_ic; - uint32_t plcp = 0; - int ridx; + uint32_t plcp; /* * If it's an MCS rate, let's set the plcp correctly * and set the relevant flags based on the node config. */ - if (rate & IEEE80211_RATE_MCS) { + if (rate->type == IEEE80211_T_HT) { /* * Set the initial PLCP value to be between 0->31 for * MCS 0 -> MCS 31, then set the "I'm an MCS rate!" * flag. */ - plcp = IEEE80211_RV(rate) | IWN_RFLAG_MCS; + plcp = rate->value | IWN_RFLAG_MCS; /* * XXX the following should only occur if both @@ -2796,9 +2794,9 @@ * Ensure the selected rate matches the link quality * table entries being used. */ - if (rate > 0x8f) + if (rate->props.ht.streams > 2) plcp |= IWN_RFLAG_ANT(sc->txchainmask); - else if (rate > 0x87) + else if (rate->props.ht.streams > 1) plcp |= IWN_RFLAG_ANT(iwn_get_2stream_tx_antmask(sc)); else plcp |= IWN_RFLAG_ANT(iwn_get_1stream_tx_antmask(sc)); @@ -2807,18 +2805,10 @@ * Set the initial PLCP - fine for both * OFDM and CCK rates. */ - plcp = rate2plcp(rate); + plcp = rate2plcp(rate->value); /* Set CCK flag if it's CCK */ - - /* XXX It would be nice to have a method - * to map the ridx -> phy table entry - * so we could just query that, rather than - * this hack to check against IWN_RIDX_OFDM6. - */ - ridx = ieee80211_legacy_rate_lookup(ic->ic_rt, - rate & IEEE80211_RATE_VAL); - if (ridx < IWN_RIDX_OFDM6 && + if (rate->type == IEEE80211_T_CCK && IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) plcp |= IWN_RFLAG_CCK; @@ -2827,9 +2817,9 @@ plcp |= IWN_RFLAG_ANT(iwn_get_1stream_tx_antmask(sc)); } - DPRINTF(sc, IWN_DEBUG_TXRATE, "%s: rate=0x%02x, plcp=0x%08x\n", + DPRINTF(sc, IWN_DEBUG_TXRATE, "%s: rate %u/%u, plcp=0x%08x\n", __func__, - rate, + rate->type, rate->value, plcp); return (htole32(plcp)); @@ -4253,7 +4243,7 @@ */ static int iwn_check_rate_needs_protection(struct iwn_softc *sc, - struct ieee80211vap *vap, uint8_t rate) + struct ieee80211vap *vap, const struct ieee80211_rate_t *rate) { struct ieee80211com *ic = vap->iv_ic; @@ -4275,7 +4265,7 @@ * If it's an 11n rate - no protection. * We'll do it via a specific 11n check. */ - if (rate & IEEE80211_RATE_MCS) { + if (rate->type == IEEE80211_T_HT) { return (0); } @@ -4283,7 +4273,7 @@ * Do a rate table lookup. If the PHY is CCK, * don't do protection. */ - if (ieee80211_rate2phytype(ic->ic_rt, rate) == IEEE80211_T_CCK) + if (rate->type == IEEE80211_T_CCK) return (0); /* @@ -4298,44 +4288,30 @@ */ static int iwn_tx_rate_to_linkq_offset(struct iwn_softc *sc, struct ieee80211_node *ni, - uint8_t rate) + uint16_t rate_idx) { - struct ieee80211_rateset *rs; - int is_11n; - int nr; - int i; - uint8_t cmp_rate; + const struct ieee80211_rateset *rs; + int i, nr; + uint16_t cmp_rate_idx; /* - * Figure out if we're using 11n or not here. - */ - if (IEEE80211_IS_CHAN_HT(ni->ni_chan) && ni->ni_htrates.rs_nrates > 0) - is_11n = 1; - else - is_11n = 0; - - /* * Use the correct rate table. */ - if (is_11n) { + if (IEEE80211_IS_CHAN_HT(ni->ni_chan) && ni->ni_htrates.rs_nrates > 0) rs = (struct ieee80211_rateset *) &ni->ni_htrates; - nr = ni->ni_htrates.rs_nrates; - } else { + else rs = &ni->ni_rates; - nr = rs->rs_nrates; - } /* * Find the relevant link quality entry in the table. */ - for (i = 0; i < nr && i < IWN_MAX_TX_RETRIES - 1 ; i++) { + nr = rs->rs_nrates; + for (i = 0; i < nr && i < IWN_MAX_TX_RETRIES - 1; i++) { /* * The link quality table index starts at 0 == highest * rate, so we walk the rate table backwards. */ - cmp_rate = rs->rs_rates[(nr - 1) - i]; - if (rate & IEEE80211_RATE_MCS) - cmp_rate |= IEEE80211_RATE_MCS; + cmp_rate_idx = rs->rates[(nr - 1) - i].rs_index; #if 0 DPRINTF(sc, IWN_DEBUG_XMIT, "%s: idx %d: nr=%d, rate=0x%02x, rateentry=0x%02x\n", @@ -4343,10 +4319,10 @@ i, nr, rate, - cmp_rate); + cmp_rate_idx); #endif - if (cmp_rate == rate) + if (cmp_rate_idx == rate_idx) return (i); } @@ -4357,7 +4333,8 @@ static int iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni) { - const struct ieee80211_txparam *tp = ni->ni_txparms; + const struct ieee80211_rate_t *rate; + const struct ieee80211_txparam_vht *tp = ni->ni_txparms; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; struct iwn_node *wn = (void *)ni; @@ -4367,9 +4344,9 @@ struct ieee80211_frame *wh; struct ieee80211_key *k = NULL; uint32_t flags; - uint16_t seqno, qos; + uint16_t seqno, qos, rate_idx; uint8_t tid, type; - int ac, totlen, rate; + int ac, totlen; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); @@ -4391,17 +4368,19 @@ if (type == IEEE80211_FC0_TYPE_MGT || type == IEEE80211_FC0_TYPE_CTL || (m->m_flags & M_EAPOL) != 0) - rate = tp->mgmtrate; + rate_idx = tp->mgmtrate; else if (IEEE80211_IS_MULTICAST(wh->i_addr1)) - rate = tp->mcastrate; - else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) - rate = tp->ucastrate; + rate_idx = tp->mcastrate; + else if (tp->ucastrate != IEEE80211_RATE_NONEXISTENT) + rate_idx = tp->ucastrate; else { /* XXX pass pktlen */ (void) ieee80211_ratectl_rate(ni, NULL, 0); - rate = ni->ni_txrate; + rate_idx = ni->ni_txrate; } + rate = ieee80211_get_rate(rate_idx); + /* * XXX TODO: Group addressed frames aren't aggregated and must * go to the normal non-aggregation queue, and have a NONQOS TID @@ -4446,7 +4425,7 @@ struct iwn_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = 0; - tap->wt_rate = rate; + tap->wt_rate = ieee80211_convert_to_legacy_rate(rate_idx); if (k != NULL) tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; @@ -4478,8 +4457,8 @@ flags |= IWN_TX_NEED_CTS; else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) flags |= IWN_TX_NEED_RTS; - } else if ((rate & IEEE80211_RATE_MCS) && - (ic->ic_htprotmode == IEEE80211_PROT_RTSCTS)) { + } else if (rate->type == IEEE80211_T_HT && + ic->ic_htprotmode == IEEE80211_PROT_RTSCTS) { flags |= IWN_TX_NEED_RTS; } @@ -4538,7 +4517,7 @@ /* Group or management frame. */ tx->linkq = 0; } else { - tx->linkq = iwn_tx_rate_to_linkq_offset(sc, ni, rate); + tx->linkq = iwn_tx_rate_to_linkq_offset(sc, ni, rate_idx); flags |= IWN_TX_LINKQ; /* enable MRR */ } @@ -4557,13 +4536,14 @@ iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) { + const struct ieee80211_rate_t *rate; struct ieee80211vap *vap = ni->ni_vap; struct iwn_tx_cmd *cmd; struct iwn_cmd_data *tx; struct ieee80211_frame *wh; struct iwn_tx_ring *ring; uint32_t flags; - int ac, rate; + int ac; uint8_t type; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); @@ -4576,7 +4556,7 @@ ac = params->ibp_pri & 3; /* Choose a TX rate. */ - rate = params->ibp_rate0; + rate = ieee80211_get_rate(params->ibp_rate0); flags = 0; if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) @@ -4602,7 +4582,8 @@ struct iwn_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = 0; - tap->wt_rate = rate; + tap->wt_rate = + ieee80211_convert_to_legacy_rate(params->ibp_rate0); ieee80211_radiotap_tx(vap, m); } @@ -5138,11 +5119,11 @@ static int iwn_set_link_quality(struct iwn_softc *sc, struct ieee80211_node *ni) { + const struct ieee80211_rate_t *rate; struct iwn_node *wn = (void *)ni; struct ieee80211_rateset *rs; struct iwn_cmd_link_quality linkq; - int i, rate, txrate; - int is_11n; + int i, txrate; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); @@ -5167,22 +5148,16 @@ * 11n _and_ we have some 11n rates, or don't * try. */ - if (IEEE80211_IS_CHAN_HT(ni->ni_chan) && ni->ni_htrates.rs_nrates > 0) { + if (IEEE80211_IS_CHAN_HT(ni->ni_chan) && ni->ni_htrates.rs_nrates > 0) rs = (struct ieee80211_rateset *) &ni->ni_htrates; - is_11n = 1; - } else { + else rs = &ni->ni_rates; - is_11n = 0; - } /* Start at highest available bit-rate. */ /* * XXX this is all very dirty! */ - if (is_11n) - txrate = ni->ni_htrates.rs_nrates - 1; - else - txrate = rs->rs_nrates - 1; + txrate = rs->rs_nrates - 1; for (i = 0; i < IWN_MAX_TX_RETRIES; i++) { uint32_t plcp; @@ -5193,20 +5168,16 @@ if (i == 14 || i == 15) txrate = 0; - if (is_11n) - rate = IEEE80211_RATE_MCS | rs->rs_rates[txrate]; - else - rate = IEEE80211_RV(rs->rs_rates[txrate]); - /* Do rate -> PLCP config mapping */ + rate = ieee80211_get_rate(rs->rates[txrate].rs_index); plcp = iwn_rate_to_plcp(sc, ni, rate); linkq.retry[i] = plcp; DPRINTF(sc, IWN_DEBUG_XMIT, - "%s: i=%d, txrate=%d, rate=0x%02x, plcp=0x%08x\n", + "%s: i=%d, txrate=%d, rate=%u/%u, plcp=0x%08x\n", __func__, i, txrate, - rate, + rate->type, rate->value, le32toh(plcp)); /* @@ -5220,8 +5191,8 @@ * the next entry.) That way if the next entry is a non-MIMO * entry, we're already pointing at it. */ - if ((le32toh(plcp) & IWN_RFLAG_MCS) && - IEEE80211_RV(le32toh(plcp)) > 7) + if (rate->type == IEEE80211_T_HT && + rate->props.ht.streams > 1) linkq.mimo = i + 1; /* Next retry at immediate lower bit-rate. */ @@ -6808,6 +6779,7 @@ iwn_scan(struct iwn_softc *sc, struct ieee80211vap *vap, struct ieee80211_scan_state *ss, struct ieee80211_channel *c) { + const struct ieee80211_rateset *rs; struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni = vap->iv_bss; struct iwn_scan_hdr *hdr; @@ -6815,7 +6787,6 @@ struct iwn_scan_essid *essid; struct iwn_scan_chan *chan; struct ieee80211_frame *wh; - struct ieee80211_rateset *rs; uint8_t *buf, *frm; uint16_t rxchain; uint8_t txant; @@ -6893,7 +6864,7 @@ if (IEEE80211_IS_CHAN_5GHZ(c)) { /* Send probe requests at 6Mbps. */ tx->rate = htole32(0xd); - rs = &ic->ic_sup_rates[IEEE80211_MODE_11A]; + rs = ic->ic_sup_rates[IEEE80211_MODE_11A]; } else { hdr->flags = htole32(IWN_RXON_24GHZ | IWN_RXON_AUTO); if (sc->hw_type == IWN_HW_REV_TYPE_4965 && @@ -6903,7 +6874,7 @@ /* Send probe requests at 1Mbps. */ tx->rate = htole32(10 | IWN_RFLAG_CCK); } - rs = &ic->ic_sup_rates[IEEE80211_MODE_11G]; + rs = ic->ic_sup_rates[IEEE80211_MODE_11G]; } /* Use the first valid TX antenna. */ txant = IWN_LSB(sc->txchainmask); Index: sys/dev/malo/if_malo.c =================================================================== --- sys/dev/malo/if_malo.c +++ sys/dev/malo/if_malo.c @@ -904,17 +904,31 @@ static __inline void malo_updatetxrate(struct ieee80211_node *ni, int rix) { - static const int ieeerates[] = - { 2, 4, 11, 22, 44, 12, 18, 24, 36, 48, 96, 108 }; + static const uint16_t ieeerates[] = { + IEEE80211_RATE_INDEX_CCK1, IEEE80211_RATE_INDEX_CCK2, + IEEE80211_RATE_INDEX_CCK5, IEEE80211_RATE_INDEX_CCK11, + IEEE80211_RATE_INDEX_PBCC22, IEEE80211_RATE_INDEX_OFDM6, + IEEE80211_RATE_INDEX_OFDM9, IEEE80211_RATE_INDEX_OFDM12, + IEEE80211_RATE_INDEX_OFDM18, IEEE80211_RATE_INDEX_OFDM24, + IEEE80211_RATE_INDEX_OFDM48, IEEE80211_RATE_INDEX_OFDM54 + }; + if (rix < nitems(ieeerates)) ni->ni_txrate = ieeerates[rix]; } -static int +static uint16_t malo_fix2rate(int fix_rate) { - static const int rates[] = - { 2, 4, 11, 22, 12, 18, 24, 36, 48, 96, 108 }; + static const uint16_t rates[] = { + IEEE80211_RATE_INDEX_CCK1, IEEE80211_RATE_INDEX_CCK2, + IEEE80211_RATE_INDEX_CCK5, IEEE80211_RATE_INDEX_CCK11, + IEEE80211_RATE_INDEX_OFDM6, IEEE80211_RATE_INDEX_OFDM9, + IEEE80211_RATE_INDEX_OFDM12, IEEE80211_RATE_INDEX_OFDM18, + IEEE80211_RATE_INDEX_OFDM24, IEEE80211_RATE_INDEX_OFDM48, + IEEE80211_RATE_INDEX_OFDM54 + }; + return (fix_rate < nitems(rates) ? rates[fix_rate] : 0); } @@ -1751,8 +1765,9 @@ if (nstate == IEEE80211_S_RUN && vap->iv_state != IEEE80211_S_RUN) { struct ieee80211_node *ni = vap->iv_bss; enum ieee80211_phymode mode = ieee80211_chan2mode(ni->ni_chan); - const struct ieee80211_txparam *tp = &vap->iv_txparms[mode]; + const struct ieee80211_txparam_vht *tp; + tp = &vap->iv_txparms[mode]; DPRINTF(sc, MALO_DEBUG_STATE, "%s: %s(RUN): iv_flags 0x%08x bintvl %d bssid %s " "capinfo 0x%04x chan %d associd 0x%x mode %d rate %d\n", @@ -1766,7 +1781,7 @@ MHP_SHORT_PREAMBLE : MHP_LONG_PREAMBLE); malo_hal_setassocid(sc->malo_mh, ni->ni_bssid, ni->ni_associd); malo_hal_set_rate(mh, mode, - tp->ucastrate == IEEE80211_FIXED_RATE_NONE ? + tp->ucastrate == IEEE80211_RATE_NONEXISTENT ? 0 : malo_fix2rate(tp->ucastrate)); } return 0; Index: sys/dev/mwl/if_mwl.c =================================================================== --- sys/dev/mwl/if_mwl.c +++ sys/dev/mwl/if_mwl.c @@ -145,7 +145,7 @@ static int mwl_wme_update(struct ieee80211com *); static void mwl_tx_cleanupq(struct mwl_softc *, struct mwl_txq *); static void mwl_tx_cleanup(struct mwl_softc *); -static uint16_t mwl_calcformat(uint8_t rate, const struct ieee80211_node *); +static uint16_t mwl_calcformat(uint16_t, const struct ieee80211_node *); static int mwl_tx_start(struct mwl_softc *, struct ieee80211_node *, struct mwl_txbuf *, struct mbuf *); static void mwl_tx_proc(void *, int); @@ -1003,11 +1003,14 @@ struct ieee80211com *ic = &sc->sc_ic; const struct ieee80211_rateset *rs; MWL_HAL_TXRATE rates; + uint8_t rv; memset(&rates, 0, sizeof(rates)); rs = ieee80211_get_suprates(ic, ic->ic_curchan); + rv = ieee80211_convert_to_legacy_rate(rs->rates[0].rs_index); + /* rate used to send management frames */ - rates.MgtRate = rs->rs_rates[0] & IEEE80211_RATE_VAL; + rates.MgtRate = rv; /* rate used to send multicast frames */ rates.McastRate = rates.MgtRate; @@ -1023,7 +1026,7 @@ { struct mwl_vap *mvp = MWL_VAP(vap); struct ieee80211_node *ni = vap->iv_bss; - const struct ieee80211_txparam *tp = ni->ni_txparms; + const struct ieee80211_txparam_vht *tp = ni->ni_txparms; MWL_HAL_TXRATE rates; KASSERT(vap->iv_state == IEEE80211_S_RUN, ("state %d", vap->iv_state)); @@ -1034,15 +1037,15 @@ */ memset(&rates, 0, sizeof(rates)); /* rate used to send management frames */ - rates.MgtRate = tp->mgmtrate; + rates.MgtRate = ieee80211_convert_to_legacy_rate(tp->mgmtrate); /* rate used to send multicast frames */ - rates.McastRate = tp->mcastrate; + rates.McastRate = ieee80211_convert_to_legacy_rate(tp->mcastrate); /* while here calculate EAPOL fixed rate cookie */ - mvp->mv_eapolformat = htole16(mwl_calcformat(rates.MgtRate, ni)); + mvp->mv_eapolformat = htole16(mwl_calcformat(tp->mgmtrate, ni)); return mwl_hal_settxrate(mvp->mv_hvap, - tp->ucastrate != IEEE80211_FIXED_RATE_NONE ? + tp->ucastrate != IEEE80211_RATE_NONEXISTENT ? RATE_FIXED : RATE_AUTO, &rates); } @@ -1055,7 +1058,7 @@ struct mwl_vap *mvp = MWL_VAP(vap); struct ieee80211_node *ni = vap->iv_bss; enum ieee80211_phymode mode; - uint8_t rate; + uint16_t rate_idx; KASSERT(vap->iv_state == IEEE80211_S_RUN, ("state %d", vap->iv_state)); @@ -1066,14 +1069,14 @@ */ if (mode == IEEE80211_MODE_11NA && (vap->iv_flags_ht & IEEE80211_FHT_PUREN) == 0) - rate = vap->iv_txparms[IEEE80211_MODE_11A].mgmtrate; + rate_idx = vap->iv_txparms[IEEE80211_MODE_11A].mgmtrate; else if (mode == IEEE80211_MODE_11NG && (vap->iv_flags_ht & IEEE80211_FHT_PUREN) == 0) - rate = vap->iv_txparms[IEEE80211_MODE_11G].mgmtrate; + rate_idx = vap->iv_txparms[IEEE80211_MODE_11G].mgmtrate; else - rate = vap->iv_txparms[mode].mgmtrate; + rate_idx = vap->iv_txparms[mode].mgmtrate; - mvp->mv_eapolformat = htole16(mwl_calcformat(rate, ni)); + mvp->mv_eapolformat = htole16(mwl_calcformat(rate_idx, ni)); } /* @@ -3043,17 +3046,18 @@ * of a tx descriptor. */ static uint16_t -mwl_calcformat(uint8_t rate, const struct ieee80211_node *ni) +mwl_calcformat(uint16_t rate_idx, const struct ieee80211_node *ni) { + const struct ieee80211_rate_t *rate; uint16_t fmt; + rate = ieee80211_get_rate(rate_idx); fmt = SM(3, EAGLE_TXD_ANTENNA) | (IEEE80211_IS_CHAN_HT40D(ni->ni_chan) ? EAGLE_TXD_EXTCHAN_LO : EAGLE_TXD_EXTCHAN_HI); - if (rate & IEEE80211_RATE_MCS) { /* HT MCS */ + if (rate->type == IEEE80211_T_HT) { fmt |= EAGLE_TXD_FORMAT_HT - /* NB: 0x80 implicitly stripped from ucastrate */ - | SM(rate, EAGLE_TXD_RATE); + | SM(rate->value, EAGLE_TXD_RATE); /* XXX short/long GI may be wrong; re-check */ if (IEEE80211_IS_CHAN_HT40(ni->ni_chan)) { fmt |= EAGLE_TXD_CHW_40 @@ -3066,7 +3070,7 @@ } } else { /* legacy rate */ fmt |= EAGLE_TXD_FORMAT_LEGACY - | SM(mwl_cvtlegacyrate(rate), EAGLE_TXD_RATE) + | SM(mwl_cvtlegacyrate(rate->value), EAGLE_TXD_RATE) | EAGLE_TXD_CHW_20 /* XXX iv_flags & IEEE80211_F_SHPREAMBLE? */ | (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE ? @@ -3254,18 +3258,19 @@ break; case IEEE80211_FC0_TYPE_DATA: if (!ismcast) { - const struct ieee80211_txparam *tp = ni->ni_txparms; + const struct ieee80211_txparam_vht *tp; /* * EAPOL frames get forced to a fixed rate and w/o * aggregation; otherwise check for any fixed rate * for the client (may depend on association state). */ + tp = ni->ni_txparms; if (m0->m_flags & M_EAPOL) { const struct mwl_vap *mvp = MWL_VAP_CONST(vap); ds->Format = mvp->mv_eapolformat; ds->pad = htole16( EAGLE_TXD_FIXED_RATE | EAGLE_TXD_DONT_AGGR); - } else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { + } else if (tp->ucastrate != IEEE80211_RATE_NONEXISTENT) { /* XXX pre-calculate per node */ ds->Format = htole16( mwl_calcformat(tp->ucastrate, ni)); @@ -3319,11 +3324,19 @@ return 0; } -static __inline int +static __inline uint16_t mwl_cvtlegacyrix(int rix) { - static const int ieeerates[] = - { 2, 4, 11, 22, 44, 12, 18, 24, 36, 48, 72, 96, 108 }; + static const uint16_t ieeerates[] = { + IEEE80211_RATE_INDEX_CCK1, IEEE80211_RATE_INDEX_CCK2, + IEEE80211_RATE_INDEX_CCK5, IEEE80211_RATE_INDEX_CCK11, + IEEE80211_RATE_INDEX_PBCC22, IEEE80211_RATE_INDEX_OFDM6, + IEEE80211_RATE_INDEX_OFDM9, IEEE80211_RATE_INDEX_OFDM12, + IEEE80211_RATE_INDEX_OFDM18, IEEE80211_RATE_INDEX_OFDM24, + IEEE80211_RATE_INDEX_OFDM36, IEEE80211_RATE_INDEX_OFDM48, + IEEE80211_RATE_INDEX_OFDM54 + }; + return (rix < nitems(ieeerates) ? ieeerates[rix] : 0); } @@ -3340,10 +3353,12 @@ struct mwl_txdesc *ds; struct ieee80211_node *ni; struct mwl_node *an; - int nreaped; + int nreaped, max_mcs; uint32_t status; + uint8_t rv; DPRINTF(sc, MWL_DEBUG_TX_PROC, "%s: tx queue %u\n", __func__, txq->qnum); + max_mcs = IEEE80211_HT_MCS_CHAIN * ic->ic_txstream; for (nreaped = 0;; nreaped++) { MWL_TXQ_LOCK(txq); bf = STAILQ_FIRST(&txq->active); @@ -3380,13 +3395,16 @@ sc->sc_stats.mst_tx_mretries++; if (txq->qnum >= MWL_WME_AC_VO) ic->ic_wme.wme_hipri_traffic++; - ni->ni_txrate = MS(Format, EAGLE_TXD_RATE); - if ((Format & EAGLE_TXD_FORMAT_HT) == 0) { - ni->ni_txrate = mwl_cvtlegacyrix( - ni->ni_txrate); - } else - ni->ni_txrate |= IEEE80211_RATE_MCS; - sc->sc_stats.mst_tx_rate = ni->ni_txrate; + rv = MS(Format, EAGLE_TXD_RATE); + if ((Format & EAGLE_TXD_FORMAT_HT) == 0) + ni->ni_txrate = mwl_cvtlegacyrix(rv); + else if (rv < max_mcs) { + ni->ni_txrate = + IEEE80211_RATE_INDEX_HT(rv); + } + sc->sc_stats.mst_tx_rate = + ieee80211_convert_to_legacy_rate( + ni->ni_txrate); } else { if (status & EAGLE_TXD_STATUS_FAILED_LINK_ERROR) sc->sc_stats.mst_tx_linkerror++; @@ -3970,12 +3988,15 @@ static uint32_t get_rate_bitmap(const struct ieee80211_rateset *rs) { + const struct ieee80211_rate_t *rate; uint32_t rates; int i; rates = 0; for (i = 0; i < rs->rs_nrates; i++) - switch (rs->rs_rates[i] & IEEE80211_RATE_VAL) { + rate = ieee80211_get_rate(rs->rates[i].rs_index); + + switch (rate->value) { case 2: rates |= 0x001; break; case 4: rates |= 0x002; break; case 11: rates |= 0x004; break; @@ -3999,15 +4020,8 @@ static uint32_t get_htrate_bitmap(const struct ieee80211_htrateset *rs) { - uint32_t rates; - int i; - rates = 0; - for (i = 0; i < rs->rs_nrates; i++) { - if (rs->rs_rates[i] < 16) - rates |= 1<rs_rates[i]; - } - return rates; + return (rs->rs_bitmap[0] | (rs->rs_bitmap[1] << 8)); } /* Index: sys/dev/otus/if_otus.c =================================================================== --- sys/dev/otus/if_otus.c +++ sys/dev/otus/if_otus.c @@ -2086,68 +2086,51 @@ * Map net80211 rate to hw rate for otus MAC/PHY. */ static uint8_t -otus_rate_to_hw_rate(struct otus_softc *sc, uint8_t rate) +otus_rate_to_hw_rate(struct otus_softc *sc, + const struct ieee80211_rate_t *rate) { int is_2ghz; - is_2ghz = !! (IEEE80211_IS_CHAN_2GHZ(sc->sc_ic.ic_curchan)); - - switch (rate) { - /* CCK */ - case 2: - return (0x0); - case 4: - return (0x1); - case 11: - return (0x2); - case 22: - return (0x3); - /* OFDM */ - case 12: - return (0xb); - case 18: - return (0xf); - case 24: - return (0xa); - case 36: - return (0xe); - case 48: - return (0x9); - case 72: - return (0xd); - case 96: - return (0x8); - case 108: - return (0xc); + switch (rate->type) { + case IEEE80211_T_HT: + /* TODO */ + break; + case IEEE80211_T_OFDM: + switch (rate->value) { + case 12: return (0xb); + case 18: return (0xf); + case 24: return (0xa); + case 36: return (0xe); + case 48: return (0x9); + case 72: return (0xd); + case 96: return (0x8); + case 108: return (0xc); + default: + break; + } + case IEEE80211_T_CCK: + switch (rate->value) { + case 2: return (0x0); + case 4: return (0x1); + case 11: return (0x2); + case 22: return (0x3); + default: + break; + } default: - device_printf(sc->sc_dev, "%s: unknown rate '%d'\n", - __func__, (int) rate); - case 0: - if (is_2ghz) - return (0x0); /* 1MB CCK */ - else - return (0xb); /* 6MB OFDM */ - - /* XXX TODO: HT */ + break; } -} -static int -otus_hw_rate_is_ofdm(struct otus_softc *sc, uint8_t hw_rate) -{ + device_printf(sc->sc_dev, "%s: unknown rate '%u/%u'\n", + __func__, rate->type, rate->value); - switch (hw_rate) { - case 0x0: - case 0x1: - case 0x2: - case 0x3: - return (0); - default: - return (1); - } + is_2ghz = !! (IEEE80211_IS_CHAN_2GHZ(sc->sc_ic.ic_curchan)); + if (is_2ghz) + return (0x0); /* 1MB CCK */ + else + return (0xb); /* 6MB OFDM */ } - static void otus_tx_update_ratectl(struct otus_softc *sc, struct ieee80211_node *ni) { @@ -2182,15 +2165,16 @@ otus_tx(struct otus_softc *sc, struct ieee80211_node *ni, struct mbuf *m, struct otus_data *data, const struct ieee80211_bpf_params *params) { - const struct ieee80211_txparam *tp = ni->ni_txparms; + const struct ieee80211_txparam_vht *tp = ni->ni_txparms; + const struct ieee80211_rate_t *rate; struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_frame *wh; struct ieee80211_key *k; struct ar_tx_head *head; uint32_t phyctl; - uint16_t macctl, qos; - uint8_t qid, rate; + uint16_t macctl, qos, rate_idx; + uint8_t qid, hw_rate; int hasqos, xferlen, type, ismcast; wh = mtod(m, struct ieee80211_frame *); @@ -2234,18 +2218,21 @@ /* Pickup a rate index. */ if (params != NULL) - rate = otus_rate_to_hw_rate(sc, params->ibp_rate0); + rate_idx = params->ibp_rate0; else if (!!(m->m_flags & M_EAPOL) || type != IEEE80211_FC0_TYPE_DATA) - rate = otus_rate_to_hw_rate(sc, tp->mgmtrate); + rate_idx = tp->mgmtrate; else if (ismcast) - rate = otus_rate_to_hw_rate(sc, tp->mcastrate); - else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) - rate = otus_rate_to_hw_rate(sc, tp->ucastrate); + rate_idx = tp->mcastrate; + else if (tp->ucastrate != IEEE80211_RATE_NONEXISTENT) + rate_idx = tp->ucastrate; else { (void) ieee80211_ratectl_rate(ni, NULL, 0); - rate = otus_rate_to_hw_rate(sc, ni->ni_txrate); + rate_idx = ni->ni_txrate; } + rate = ieee80211_get_rate(rate_idx); + hw_rate = otus_rate_to_hw_rate(sc, rate); + phyctl = 0; macctl = AR_TX_MAC_BACKOFF | AR_TX_MAC_HW_DUR | AR_TX_MAC_QID(qid); @@ -2268,8 +2255,8 @@ } } - phyctl |= AR_TX_PHY_MCS(rate); - if (otus_hw_rate_is_ofdm(sc, rate)) { + phyctl |= AR_TX_PHY_MCS(hw_rate); + if (rate->type == IEEE80211_T_OFDM) { phyctl |= AR_TX_PHY_MT_OFDM; /* Always use all tx antennas for now, just to be safe */ phyctl |= AR_TX_PHY_ANTMSK(sc->txmask); @@ -2299,9 +2286,9 @@ data->m = m; OTUS_DPRINTF(sc, OTUS_DEBUG_XMIT, - "%s: tx: m=%p; data=%p; len=%d mac=0x%04x phy=0x%08x rate=0x%02x, ni_txrate=%d\n", - __func__, m, data, le16toh(head->len), macctl, phyctl, - (int) rate, (int) ni->ni_txrate); + "%s: tx: m=%p; data=%p; len=%d mac=0x%04x phy=0x%08x " + "rate=%u/0x%02x\n", __func__, m, data, le16toh(head->len), + macctl, phyctl, rate->type, rate->value); /* Submit transfer */ STAILQ_INSERT_TAIL(&sc->sc_tx_pending[OTUS_BULK_TX], data, next); Index: sys/dev/ral/rt2560.c =================================================================== --- sys/dev/ral/rt2560.c +++ sys/dev/ral/rt2560.c @@ -121,8 +121,8 @@ struct ieee80211_channel[]); static void rt2560_set_channel(struct ieee80211com *); static void rt2560_setup_tx_desc(struct rt2560_softc *, - struct rt2560_tx_desc *, uint32_t, int, int, int, - bus_addr_t); + struct rt2560_tx_desc *, uint32_t, int, + const struct ieee80211_rate_t *, int, bus_addr_t); static int rt2560_tx_bcn(struct rt2560_softc *, struct mbuf *, struct ieee80211_node *); static int rt2560_tx_mgt(struct rt2560_softc *, struct mbuf *, @@ -942,7 +942,7 @@ txs->long_retries = 0; DPRINTFN(sc, 10, "%s\n", "data frame sent successfully"); - if (data->rix != IEEE80211_FIXED_RATE_NONE) + if (data->submit_to_ratectl) ieee80211_ratectl_tx_complete(ni, txs); status = 0; break; @@ -953,7 +953,7 @@ DPRINTFN(sc, 9, "data frame sent after %u retries\n", txs->long_retries); - if (data->rix != IEEE80211_FIXED_RATE_NONE) + if (data->submit_to_ratectl) ieee80211_ratectl_tx_complete(ni, txs); status = 0; break; @@ -964,7 +964,7 @@ DPRINTFN(sc, 9, "data frame failed after %d retries\n", txs->long_retries); - if (data->rix != IEEE80211_FIXED_RATE_NONE) + if (data->submit_to_ratectl) ieee80211_ratectl_tx_complete(ni, txs); status = 1; break; @@ -1401,7 +1401,8 @@ static void rt2560_setup_tx_desc(struct rt2560_softc *sc, struct rt2560_tx_desc *desc, - uint32_t flags, int len, int rate, int encrypt, bus_addr_t physaddr) + uint32_t flags, int len, const struct ieee80211_rate_t *rate, int encrypt, + bus_addr_t physaddr) { struct ieee80211com *ic = &sc->sc_ic; uint16_t plcp_length; @@ -1417,19 +1418,19 @@ RT2560_LOGCWMAX(8)); /* setup PLCP fields */ - desc->plcp_signal = rt2560_plcp_signal(rate); + desc->plcp_signal = rt2560_plcp_signal(rate->value); desc->plcp_service = 4; len += IEEE80211_CRC_LEN; - if (ieee80211_rate2phytype(ic->ic_rt, rate) == IEEE80211_T_OFDM) { + if (rate->type == IEEE80211_T_OFDM) { desc->flags |= htole32(RT2560_TX_OFDM); plcp_length = len & 0xfff; desc->plcp_length_hi = plcp_length >> 6; desc->plcp_length_lo = plcp_length & 0x3f; } else { - plcp_length = howmany(16 * len, rate); - if (rate == 22) { + plcp_length = howmany(16 * len, rate->value); + if (rate->value == 22) { remainder = (16 * len) % 22; if (remainder != 0 && remainder < 7) desc->plcp_service |= RT2560_PLCP_LENGEXT; @@ -1437,7 +1438,8 @@ desc->plcp_length_hi = plcp_length >> 8; desc->plcp_length_lo = plcp_length & 0xff; - if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) + if (rate->props.cck.short_preamble && + (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) desc->plcp_signal |= 0x08; } @@ -1451,17 +1453,18 @@ rt2560_tx_bcn(struct rt2560_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) { + const struct ieee80211_rate_t *rate; struct ieee80211vap *vap = ni->ni_vap; struct rt2560_tx_desc *desc; struct rt2560_tx_data *data; bus_dma_segment_t segs[RT2560_MAX_SCATTER]; - int nsegs, rate, error; + int nsegs, error; desc = &sc->bcnq.desc[sc->bcnq.cur]; data = &sc->bcnq.data[sc->bcnq.cur]; /* XXX maybe a separate beacon rate? */ - rate = vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)].mgmtrate; + rate = ieee80211_get_rate(ni->ni_txparms->mgmtrate); error = bus_dmamap_load_mbuf_sg(sc->bcnq.data_dmat, data->map, m0, segs, &nsegs, BUS_DMA_NOWAIT); @@ -1476,7 +1479,7 @@ struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = 0; - tap->wt_rate = rate; + tap->wt_rate = rate->value; tap->wt_antenna = sc->tx_ant; ieee80211_radiotap_tx(vap, m0); @@ -1488,8 +1491,8 @@ rt2560_setup_tx_desc(sc, desc, RT2560_TX_IFS_NEWBACKOFF | RT2560_TX_TIMESTAMP, m0->m_pkthdr.len, rate, 0, segs->ds_addr); - DPRINTFN(sc, 10, "sending beacon frame len=%u idx=%u rate=%u\n", - m0->m_pkthdr.len, sc->bcnq.cur, rate); + DPRINTFN(sc, 10, "sending beacon frame len=%u idx=%u rate=%u/%u\n", + m0->m_pkthdr.len, sc->bcnq.cur, rate->type, rate->value); bus_dmamap_sync(sc->bcnq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); bus_dmamap_sync(sc->bcnq.desc_dmat, sc->bcnq.desc_map, @@ -1504,6 +1507,7 @@ rt2560_tx_mgt(struct rt2560_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) { + const struct ieee80211_rate_t *rate; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; struct rt2560_tx_desc *desc; @@ -1513,12 +1517,12 @@ bus_dma_segment_t segs[RT2560_MAX_SCATTER]; uint16_t dur; uint32_t flags = 0; - int nsegs, rate, error; + int nsegs, error; desc = &sc->prioq.desc[sc->prioq.cur]; data = &sc->prioq.data[sc->prioq.cur]; - rate = ni->ni_txparms->mgmtrate; + rate = ieee80211_get_rate(ni->ni_txparms->mgmtrate); wh = mtod(m0, struct ieee80211_frame *); @@ -1543,7 +1547,7 @@ struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = 0; - tap->wt_rate = rate; + tap->wt_rate = rate->value; tap->wt_antenna = sc->tx_ant; ieee80211_radiotap_tx(vap, m0); @@ -1552,15 +1556,16 @@ data->m = m0; data->ni = ni; /* management frames are not taken into account for amrr */ - data->rix = IEEE80211_FIXED_RATE_NONE; + data->submit_to_ratectl = 0; wh = mtod(m0, struct ieee80211_frame *); if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { flags |= RT2560_TX_ACK; - dur = ieee80211_ack_duration(ic->ic_rt, - rate, ic->ic_flags & IEEE80211_F_SHPREAMBLE); + dur = ieee80211_ack_duration(ic->ic_rt->ctl_rates, + ni->ni_txparms->mgmtrate, + ic->ic_flags & IEEE80211_F_SHPREAMBLE); *(uint16_t *)wh->i_dur = htole16(dur); /* tell hardware to add timestamp for probe responses */ @@ -1578,8 +1583,8 @@ bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, BUS_DMASYNC_PREWRITE); - DPRINTFN(sc, 10, "sending mgt frame len=%u idx=%u rate=%u\n", - m0->m_pkthdr.len, sc->prioq.cur, rate); + DPRINTFN(sc, 10, "sending mgt frame len=%u idx=%u rate=%u/%u\n", + m0->m_pkthdr.len, sc->prioq.cur, rate->type, rate->value); /* kick prio */ sc->prioq.queued++; @@ -1590,18 +1595,19 @@ } static int -rt2560_sendprot(struct rt2560_softc *sc, - const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate) +rt2560_sendprot(struct rt2560_softc *sc, const struct mbuf *m, + struct ieee80211_node *ni, int prot, uint16_t rate_idx) { + const struct ieee80211_rate_t *protrate; struct ieee80211com *ic = ni->ni_ic; struct rt2560_tx_desc *desc; struct rt2560_tx_data *data; struct mbuf *mprot; - int protrate, flags, error; + int flags, error; bus_dma_segment_t segs[RT2560_MAX_SCATTER]; int nsegs; - mprot = ieee80211_alloc_prot(ni, m, rate, prot); + mprot = ieee80211_alloc_prot(ni, m, rate_idx, prot); if (mprot == NULL) { if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1); device_printf(sc->sc_dev, @@ -1624,9 +1630,9 @@ data->m = mprot; data->ni = ieee80211_ref_node(ni); /* ctl frames are not taken into account for amrr */ - data->rix = IEEE80211_FIXED_RATE_NONE; + data->submit_to_ratectl = 0; - protrate = ieee80211_ctl_rate(ic->ic_rt, rate); + protrate = ieee80211_ctl_rate(ic->ic_rt->ctl_rates, rate_idx); flags = RT2560_TX_MORE_FRAG; if (prot == IEEE80211_PROT_RTSCTS) flags |= RT2560_TX_ACK; @@ -1647,18 +1653,19 @@ rt2560_tx_raw(struct rt2560_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) { + const struct ieee80211_rate_t *rate; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; struct rt2560_tx_desc *desc; struct rt2560_tx_data *data; bus_dma_segment_t segs[RT2560_MAX_SCATTER]; uint32_t flags; - int nsegs, rate, error; + int nsegs, error; desc = &sc->prioq.desc[sc->prioq.cur]; data = &sc->prioq.data[sc->prioq.cur]; - rate = params->ibp_rate0; + rate = ieee80211_get_rate(params->ibp_rate0); if (!ieee80211_isratevalid(ic->ic_rt, rate)) { /* XXX fall back to mcast/mgmt rate? */ m_freem(m0); @@ -1672,7 +1679,7 @@ error = rt2560_sendprot(sc, m0, ni, params->ibp_flags & IEEE80211_BPF_RTS ? IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY, - rate); + params->ibp_rate0); if (error) { m_freem(m0); return error; @@ -1693,7 +1700,7 @@ struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = 0; - tap->wt_rate = rate; + tap->wt_rate = rate->value; tap->wt_antenna = sc->tx_ant; ieee80211_radiotap_tx(ni->ni_vap, m0); @@ -1711,8 +1718,8 @@ bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, BUS_DMASYNC_PREWRITE); - DPRINTFN(sc, 10, "sending raw frame len=%u idx=%u rate=%u\n", - m0->m_pkthdr.len, sc->prioq.cur, rate); + DPRINTFN(sc, 10, "sending raw frame len=%u idx=%u rate=%u/%u\n", + m0->m_pkthdr.len, sc->prioq.cur, rate->type, rate->value); /* kick prio */ sc->prioq.queued++; @@ -1726,31 +1733,33 @@ rt2560_tx_data(struct rt2560_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) { + const struct ieee80211_rate_t *rate; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; struct rt2560_tx_desc *desc; struct rt2560_tx_data *data; struct ieee80211_frame *wh; - const struct ieee80211_txparam *tp = ni->ni_txparms; + const struct ieee80211_txparam_vht *tp = ni->ni_txparms; struct ieee80211_key *k; struct mbuf *mnew; bus_dma_segment_t segs[RT2560_MAX_SCATTER]; - uint16_t dur; + uint16_t dur, rate_idx; uint32_t flags; - int nsegs, rate, error; + int nsegs, error; wh = mtod(m0, struct ieee80211_frame *); if (m0->m_flags & M_EAPOL) { - rate = tp->mgmtrate; + rate_idx = tp->mgmtrate; } else if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { - rate = tp->mcastrate; - } else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { - rate = tp->ucastrate; + rate_idx = tp->mcastrate; + } else if (tp->ucastrate != IEEE80211_RATE_NONEXISTENT) { + rate_idx = tp->ucastrate; } else { (void) ieee80211_ratectl_rate(ni, NULL, 0); - rate = ni->ni_txrate; + rate_idx = ni->ni_txrate; } + rate = ieee80211_get_rate(rate_idx); if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { k = ieee80211_crypto_encap(ni, m0); @@ -1769,10 +1778,10 @@ if (m0->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) prot = IEEE80211_PROT_RTSCTS; else if ((ic->ic_flags & IEEE80211_F_USEPROT) && - ieee80211_rate2phytype(ic->ic_rt, rate) == IEEE80211_T_OFDM) + rate->type == IEEE80211_T_OFDM) prot = ic->ic_protmode; if (prot != IEEE80211_PROT_NONE) { - error = rt2560_sendprot(sc, m0, ni, prot, rate); + error = rt2560_sendprot(sc, m0, ni, prot, rate_idx); if (error) { m_freem(m0); return error; @@ -1819,7 +1828,7 @@ struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = 0; - tap->wt_rate = rate; + tap->wt_rate = rate->value; tap->wt_antenna = sc->tx_ant; ieee80211_radiotap_tx(vap, m0); @@ -1829,18 +1838,18 @@ data->ni = ni; /* remember link conditions for rate adaptation algorithm */ - if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) { - data->rix = ni->ni_txrate; + if (tp->ucastrate == IEEE80211_RATE_NONEXISTENT) { + data->submit_to_ratectl = 1; /* XXX probably need last rssi value and not avg */ data->rssi = ic->ic_node_getrssi(ni); } else - data->rix = IEEE80211_FIXED_RATE_NONE; + data->submit_to_ratectl = 0; if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { flags |= RT2560_TX_ACK; - dur = ieee80211_ack_duration(ic->ic_rt, - rate, ic->ic_flags & IEEE80211_F_SHPREAMBLE); + dur = ieee80211_ack_duration(ic->ic_rt->ctl_rates, + rate_idx, ic->ic_flags & IEEE80211_F_SHPREAMBLE); *(uint16_t *)wh->i_dur = htole16(dur); } @@ -1851,8 +1860,8 @@ bus_dmamap_sync(sc->txq.desc_dmat, sc->txq.desc_map, BUS_DMASYNC_PREWRITE); - DPRINTFN(sc, 10, "sending data frame len=%u idx=%u rate=%u\n", - m0->m_pkthdr.len, sc->txq.cur_encrypt, rate); + DPRINTFN(sc, 10, "sending data frame len=%u idx=%u rate=%u/%u\n", + m0->m_pkthdr.len, sc->txq.cur_encrypt, rate->type, rate->value); /* kick encrypt */ sc->txq.queued++; @@ -2307,17 +2316,14 @@ { struct ieee80211com *ic = &sc->sc_ic; uint32_t mask = 0; - uint8_t rate; int i; for (i = 0; i < rs->rs_nrates; i++) { - rate = rs->rs_rates[i]; - - if (!(rate & IEEE80211_RATE_BASIC)) + if (!rs->rates[i].rs_basic) continue; - mask |= 1 << ieee80211_legacy_rate_lookup(ic->ic_rt, - IEEE80211_RV(rate)); + mask |= 1 << ieee80211_legacy_rate_lookup(ic->ic_rt->ctl_rates, + rs->rates[i].rs_index); } RAL_WRITE(sc, RT2560_ARSP_PLCP_1, mask); Index: sys/dev/ral/rt2560var.h =================================================================== --- sys/dev/ral/rt2560var.h +++ sys/dev/ral/rt2560var.h @@ -57,8 +57,8 @@ bus_dmamap_t map; struct mbuf *m; struct ieee80211_node *ni; - uint8_t rix; int8_t rssi; + int submit_to_ratectl:1; }; struct rt2560_tx_ring { Index: sys/dev/ral/rt2661.c =================================================================== --- sys/dev/ral/rt2661.c +++ sys/dev/ral/rt2661.c @@ -118,7 +118,8 @@ static void rt2661_set_channel(struct ieee80211com *); static void rt2661_setup_tx_desc(struct rt2661_softc *, struct rt2661_tx_desc *, uint32_t, uint16_t, int, - int, const bus_dma_segment_t *, int, int); + const struct ieee80211_rate_t *, + const bus_dma_segment_t *, int, int); static int rt2661_tx_data(struct rt2661_softc *, struct mbuf *, struct ieee80211_node *, int); static int rt2661_tx_mgt(struct rt2661_softc *, struct mbuf *, @@ -888,7 +889,7 @@ DPRINTFN(sc, 10, "data frame sent successfully after " "%d retries\n", txs->long_retries); - if (data->rix != IEEE80211_FIXED_RATE_NONE) + if (data->submit_to_ratectl) ieee80211_ratectl_tx_complete(ni, txs); error = 0; break; @@ -899,7 +900,7 @@ DPRINTFN(sc, 9, "%s\n", "sending data frame failed (too much retries)"); - if (data->rix != IEEE80211_FIXED_RATE_NONE) + if (data->submit_to_ratectl) ieee80211_ratectl_tx_complete(ni, txs); error = 1; break; @@ -1209,8 +1210,9 @@ static void rt2661_setup_tx_desc(struct rt2661_softc *sc, struct rt2661_tx_desc *desc, - uint32_t flags, uint16_t xflags, int len, int rate, - const bus_dma_segment_t *segs, int nsegs, int ac) + uint32_t flags, uint16_t xflags, int len, + const struct ieee80211_rate_t *rate, const bus_dma_segment_t *segs, + int nsegs, int ac) { struct ieee80211com *ic = &sc->sc_ic; uint16_t plcp_length; @@ -1237,19 +1239,19 @@ desc->qid = ac; /* setup PLCP fields */ - desc->plcp_signal = rt2661_plcp_signal(rate); + desc->plcp_signal = rt2661_plcp_signal(rate->value); desc->plcp_service = 4; len += IEEE80211_CRC_LEN; - if (ieee80211_rate2phytype(ic->ic_rt, rate) == IEEE80211_T_OFDM) { + if (rate->type == IEEE80211_T_OFDM) { desc->flags |= htole32(RT2661_TX_OFDM); plcp_length = len & 0xfff; desc->plcp_length_hi = plcp_length >> 6; desc->plcp_length_lo = plcp_length & 0x3f; } else { - plcp_length = howmany(16 * len, rate); - if (rate == 22) { + plcp_length = howmany(16 * len, rate->value); + if (rate->value == 22) { remainder = (16 * len) % 22; if (remainder != 0 && remainder < 7) desc->plcp_service |= RT2661_PLCP_LENGEXT; @@ -1257,7 +1259,8 @@ desc->plcp_length_hi = plcp_length >> 8; desc->plcp_length_lo = plcp_length & 0xff; - if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) + if (rate->props.cck.short_preamble && + (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) desc->plcp_signal |= 0x08; } @@ -1272,6 +1275,7 @@ rt2661_tx_mgt(struct rt2661_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) { + const struct ieee80211_rate_t *rate; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; struct rt2661_tx_desc *desc; @@ -1281,12 +1285,12 @@ bus_dma_segment_t segs[RT2661_MAX_SCATTER]; uint16_t dur; uint32_t flags = 0; /* XXX HWSEQ */ - int nsegs, rate, error; + int nsegs, error; desc = &sc->mgtq.desc[sc->mgtq.cur]; data = &sc->mgtq.data[sc->mgtq.cur]; - rate = ni->ni_txparms->mgmtrate; + rate = ieee80211_get_rate(ni->ni_txparms->mgmtrate); wh = mtod(m0, struct ieee80211_frame *); @@ -1311,7 +1315,7 @@ struct rt2661_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = 0; - tap->wt_rate = rate; + tap->wt_rate = rate->value; ieee80211_radiotap_tx(vap, m0); } @@ -1319,15 +1323,16 @@ data->m = m0; data->ni = ni; /* management frames are not taken into account for amrr */ - data->rix = IEEE80211_FIXED_RATE_NONE; + data->submit_to_ratectl = 0; wh = mtod(m0, struct ieee80211_frame *); if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { flags |= RT2661_TX_NEED_ACK; - dur = ieee80211_ack_duration(ic->ic_rt, - rate, ic->ic_flags & IEEE80211_F_SHPREAMBLE); + dur = ieee80211_ack_duration(ic->ic_rt->ctl_rates, + ni->ni_txparms->mgmtrate, + ic->ic_flags & IEEE80211_F_SHPREAMBLE); *(uint16_t *)wh->i_dur = htole16(dur); /* tell hardware to add timestamp in probe responses */ @@ -1344,8 +1349,8 @@ bus_dmamap_sync(sc->mgtq.desc_dmat, sc->mgtq.desc_map, BUS_DMASYNC_PREWRITE); - DPRINTFN(sc, 10, "sending mgt frame len=%u idx=%u rate=%u\n", - m0->m_pkthdr.len, sc->mgtq.cur, rate); + DPRINTFN(sc, 10, "sending mgt frame len=%u idx=%u rate=%u/%u\n", + m0->m_pkthdr.len, sc->mgtq.cur, rate->type, rate->value); /* kick mgt */ sc->mgtq.queued++; @@ -1357,18 +1362,20 @@ static int rt2661_sendprot(struct rt2661_softc *sc, int ac, - const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate) + const struct mbuf *m, struct ieee80211_node *ni, int prot, + uint16_t rate_idx) { + const struct ieee80211_rate_t *protrate; struct ieee80211com *ic = ni->ni_ic; struct rt2661_tx_ring *txq = &sc->txq[ac]; struct rt2661_tx_desc *desc; struct rt2661_tx_data *data; struct mbuf *mprot; - int protrate, flags, error; + int flags, error; bus_dma_segment_t segs[RT2661_MAX_SCATTER]; int nsegs; - mprot = ieee80211_alloc_prot(ni, m, rate, prot); + mprot = ieee80211_alloc_prot(ni, m, rate_idx, prot); if (mprot == NULL) { if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1); device_printf(sc->sc_dev, @@ -1391,9 +1398,9 @@ data->m = mprot; data->ni = ieee80211_ref_node(ni); /* ctl frames are not taken into account for amrr */ - data->rix = IEEE80211_FIXED_RATE_NONE; + data->submit_to_ratectl = 0; - protrate = ieee80211_ctl_rate(ic->ic_rt, rate); + protrate = ieee80211_ctl_rate(ic->ic_rt->ctl_rates, rate_idx); flags = RT2661_TX_MORE_FRAG; if (prot == IEEE80211_PROT_RTSCTS) flags |= RT2661_TX_NEED_ACK; @@ -1414,33 +1421,34 @@ rt2661_tx_data(struct rt2661_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, int ac) { + const struct ieee80211_rate_t *rate; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = &sc->sc_ic; struct rt2661_tx_ring *txq = &sc->txq[ac]; struct rt2661_tx_desc *desc; struct rt2661_tx_data *data; struct ieee80211_frame *wh; - const struct ieee80211_txparam *tp = ni->ni_txparms; + const struct ieee80211_txparam_vht *tp = ni->ni_txparms; struct ieee80211_key *k; struct mbuf *mnew; bus_dma_segment_t segs[RT2661_MAX_SCATTER]; - uint16_t dur; + uint16_t dur, rate_idx; uint32_t flags; - int error, nsegs, rate, noack = 0; + int error, nsegs, noack = 0; wh = mtod(m0, struct ieee80211_frame *); if (m0->m_flags & M_EAPOL) { - rate = tp->mgmtrate; + rate_idx = tp->mgmtrate; } else if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { - rate = tp->mcastrate; - } else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { - rate = tp->ucastrate; + rate_idx = tp->mcastrate; + } else if (tp->ucastrate != IEEE80211_RATE_NONEXISTENT) { + rate_idx = tp->ucastrate; } else { (void) ieee80211_ratectl_rate(ni, NULL, 0); - rate = ni->ni_txrate; + rate_idx = ni->ni_txrate; } - rate &= IEEE80211_RATE_VAL; + rate = ieee80211_get_rate(rate_idx); if (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) noack = !! ieee80211_wme_vap_ac_is_noack(vap, ac); @@ -1459,13 +1467,15 @@ flags = 0; if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { int prot = IEEE80211_PROT_NONE; - if (m0->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) + if (m0->m_pkthdr.len + IEEE80211_CRC_LEN > + vap->iv_rtsthreshold) prot = IEEE80211_PROT_RTSCTS; else if ((ic->ic_flags & IEEE80211_F_USEPROT) && - ieee80211_rate2phytype(ic->ic_rt, rate) == IEEE80211_T_OFDM) + rate->type == IEEE80211_T_OFDM) prot = ic->ic_protmode; if (prot != IEEE80211_PROT_NONE) { - error = rt2661_sendprot(sc, ac, m0, ni, prot, rate); + error = rt2661_sendprot(sc, ac, m0, ni, prot, + rate_idx); if (error) { m_freem(m0); return error; @@ -1512,7 +1522,7 @@ struct rt2661_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = 0; - tap->wt_rate = rate; + tap->wt_rate = rate->value; ieee80211_radiotap_tx(vap, m0); } @@ -1521,18 +1531,18 @@ data->ni = ni; /* remember link conditions for rate adaptation algorithm */ - if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) { - data->rix = ni->ni_txrate; + if (tp->ucastrate == IEEE80211_RATE_NONEXISTENT) { + data->submit_to_ratectl = 1; /* XXX probably need last rssi value and not avg */ data->rssi = ic->ic_node_getrssi(ni); } else - data->rix = IEEE80211_FIXED_RATE_NONE; + data->submit_to_ratectl = 0; if (!noack && !IEEE80211_IS_MULTICAST(wh->i_addr1)) { flags |= RT2661_TX_NEED_ACK; - dur = ieee80211_ack_duration(ic->ic_rt, - rate, ic->ic_flags & IEEE80211_F_SHPREAMBLE); + dur = ieee80211_ack_duration(ic->ic_rt->ctl_rates, + rate_idx, ic->ic_flags & IEEE80211_F_SHPREAMBLE); *(uint16_t *)wh->i_dur = htole16(dur); } @@ -1542,8 +1552,8 @@ bus_dmamap_sync(txq->data_dmat, data->map, BUS_DMASYNC_PREWRITE); bus_dmamap_sync(txq->desc_dmat, txq->desc_map, BUS_DMASYNC_PREWRITE); - DPRINTFN(sc, 10, "sending data frame len=%u idx=%u rate=%u\n", - m0->m_pkthdr.len, txq->cur, rate); + DPRINTFN(sc, 10, "sending data frame len=%u idx=%u rate=%u/%u\n", + m0->m_pkthdr.len, txq->cur, rate->type, rate->value); /* kick Tx */ txq->queued++; @@ -1841,17 +1851,14 @@ { struct ieee80211com *ic = &sc->sc_ic; uint32_t mask = 0; - uint8_t rate; int i; for (i = 0; i < rs->rs_nrates; i++) { - rate = rs->rs_rates[i]; - - if (!(rate & IEEE80211_RATE_BASIC)) + if (!rs->rates[i].rs_basic) continue; - mask |= 1 << ieee80211_legacy_rate_lookup(ic->ic_rt, - IEEE80211_RV(rate)); + mask |= 1 << ieee80211_legacy_rate_lookup(ic->ic_rt->ctl_rates, + rs->rates[i].rs_index); } RAL_WRITE(sc, RT2661_TXRX_CSR5, mask); @@ -2608,10 +2615,10 @@ static int rt2661_prepare_beacon(struct rt2661_softc *sc, struct ieee80211vap *vap) { + const struct ieee80211_rate_t *rate; struct ieee80211com *ic = vap->iv_ic; struct rt2661_tx_desc desc; struct mbuf *m0; - int rate; if ((m0 = ieee80211_beacon_alloc(vap->iv_bss))== NULL) { device_printf(sc->sc_dev, "could not allocate beacon frame\n"); @@ -2619,7 +2626,10 @@ } /* send beacons at the lowest available rate */ - rate = IEEE80211_IS_CHAN_5GHZ(ic->ic_bsschan) ? 12 : 2; + if (IEEE80211_IS_CHAN_5GHZ(ic->ic_bsschan)) + rate = ieee80211_get_rate(IEEE80211_RATE_INDEX_OFDM6); + else + rate = ieee80211_get_rate(IEEE80211_RATE_INDEX_CCK1); rt2661_setup_tx_desc(sc, &desc, RT2661_TX_TIMESTAMP, RT2661_TX_HWSEQ, m0->m_pkthdr.len, rate, NULL, 0, RT2661_QID_MGT); Index: sys/dev/ral/rt2661var.h =================================================================== --- sys/dev/ral/rt2661var.h +++ sys/dev/ral/rt2661var.h @@ -53,8 +53,8 @@ bus_dmamap_t map; struct mbuf *m; struct ieee80211_node *ni; - uint8_t rix; int8_t rssi; + int submit_to_ratectl:1; }; struct rt2661_tx_ring { Index: sys/dev/ral/rt2860.c =================================================================== --- sys/dev/ral/rt2860.c +++ sys/dev/ral/rt2860.c @@ -1452,6 +1452,7 @@ static int rt2860_tx(struct rt2860_softc *sc, struct mbuf *m, struct ieee80211_node *ni) { + const struct ieee80211_rate_t *rate; struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = ni->ni_vap; struct rt2860_tx_ring *ring; @@ -1459,15 +1460,15 @@ struct rt2860_txd *txd; struct rt2860_txwi *txwi; struct ieee80211_frame *wh; - const struct ieee80211_txparam *tp = ni->ni_txparms; + const struct ieee80211_txparam_vht *tp = ni->ni_txparms; struct ieee80211_key *k; struct mbuf *m1; bus_dma_segment_t segs[RT2860_MAX_SCATTER]; bus_dma_segment_t *seg; u_int hdrlen; - uint16_t qos, dur; + uint16_t qos, dur, rate_idx; uint8_t type, qsel, mcs, pid, tid, qid; - int i, nsegs, ntxds, pad, rate, ridx, error; + int i, nsegs, ntxds, pad, ridx, error; /* the data pool contains at least one element, pick the first */ data = SLIST_FIRST(&sc->data_pool); @@ -1489,16 +1490,16 @@ type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; if (m->m_flags & M_EAPOL) { - rate = tp->mgmtrate; + rate_idx = tp->mgmtrate; } else if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { - rate = tp->mcastrate; - } else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { - rate = tp->ucastrate; + rate_idx = tp->mcastrate; + } else if (tp->ucastrate != IEEE80211_RATE_NONEXISTENT) { + rate_idx = tp->ucastrate; } else { (void) ieee80211_ratectl_rate(ni, NULL, 0); - rate = ni->ni_txrate; + rate_idx = ni->ni_txrate; } - rate &= IEEE80211_RATE_VAL; + rate = ieee80211_get_rate(rate_idx); qid = M_WME_GETAC(m); if (IEEE80211_QOS_HAS_SEQ(wh)) { @@ -1509,7 +1510,7 @@ tid = 0; } ring = &sc->txq[qid]; - ridx = ieee80211_legacy_rate_lookup(ic->ic_rt, rate); + ridx = ieee80211_legacy_rate_lookup(ic->ic_rt->ctl_rates, rate_idx); /* get MCS code from rate index */ mcs = rt2860_rates[ridx].mcs; @@ -1524,9 +1525,9 @@ else txwi->wcid = 0xff; txwi->len = htole16(m->m_pkthdr.len); - if (rt2860_rates[ridx].phy == IEEE80211_T_DS) { + if (rate->type == IEEE80211_T_DS) { txwi->phy = htole16(RT2860_PHY_CCK); - if (ridx != RT2860_RIDX_CCK1 && + if (rate->props.cck.short_preamble && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) mcs |= RT2860_PHY_SHPRE; } else @@ -1547,7 +1548,7 @@ if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && (m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold || ((ic->ic_flags & IEEE80211_F_USEPROT) && - rt2860_rates[ridx].phy == IEEE80211_T_OFDM))) + rate->type == IEEE80211_T_OFDM))) txwi->txop = RT2860_TX_TXOP_HT; else txwi->txop = RT2860_TX_TXOP_BACKOFF; @@ -1574,7 +1575,7 @@ struct rt2860_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = 0; - tap->wt_rate = rate; + tap->wt_rate = ieee80211_convert_to_legacy_rate(rate_idx); if (mcs & RT2860_PHY_SHPRE) tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; @@ -1728,6 +1729,7 @@ rt2860_tx_raw(struct rt2860_softc *sc, struct mbuf *m, struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) { + const struct ieee80211_rate_t *rate; struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = ni->ni_vap; struct rt2860_tx_ring *ring; @@ -1741,7 +1743,7 @@ u_int hdrlen; uint16_t dur; uint8_t type, qsel, mcs, pid, tid, qid; - int i, nsegs, ntxds, pad, rate, ridx, error; + int i, nsegs, ntxds, pad, ridx, error; /* the data pool contains at least one element, pick the first */ data = SLIST_FIRST(&sc->data_pool); @@ -1751,9 +1753,9 @@ type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; /* Choose a TX rate index. */ - rate = params->ibp_rate0; - ridx = ieee80211_legacy_rate_lookup(ic->ic_rt, - rate & IEEE80211_RATE_VAL); + rate = ieee80211_get_rate(params->ibp_rate0); + ridx = ieee80211_legacy_rate_lookup(ic->ic_rt->ctl_rates, + params->ibp_rate0); if (ridx == (uint8_t)-1) { /* XXX fall back to mcast/mgmt rate? */ m_freem(m); @@ -1774,9 +1776,9 @@ txwi->xflags = params->ibp_pri & 3 ? 0 : RT2860_TX_NSEQ; txwi->wcid = 0xff; txwi->len = htole16(m->m_pkthdr.len); - if (rt2860_rates[ridx].phy == IEEE80211_T_DS) { + if (rate->type == IEEE80211_T_DS) { txwi->phy = htole16(RT2860_PHY_CCK); - if (ridx != RT2860_RIDX_CCK1 && + if (rate->props.cck.short_preamble && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) mcs |= RT2860_PHY_SHPRE; } else @@ -1819,7 +1821,8 @@ struct rt2860_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = 0; - tap->wt_rate = rate; + tap->wt_rate = + ieee80211_convert_to_legacy_rate(params->ibp_rate0); if (mcs & RT2860_PHY_SHPRE) tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; @@ -2259,17 +2262,14 @@ { struct ieee80211com *ic = &sc->sc_ic; uint32_t mask = 0; - uint8_t rate; int i; for (i = 0; i < rs->rs_nrates; i++) { - rate = rs->rs_rates[i]; - - if (!(rate & IEEE80211_RATE_BASIC)) + if (!rs->rates[i].rs_basic) continue; - mask |= 1 << ieee80211_legacy_rate_lookup(ic->ic_rt, - IEEE80211_RV(rate)); + mask |= 1 << ieee80211_legacy_rate_lookup(ic->ic_rt->ctl_rates, + rs->rates[i].rs_index); } RAL_WRITE(sc, RT2860_LEGACY_BASIC_RATE, mask); Index: sys/dev/rtwn/if_rtwn_ridx.h =================================================================== --- sys/dev/rtwn/if_rtwn_ridx.h +++ sys/dev/rtwn/if_rtwn_ridx.h @@ -26,7 +26,7 @@ /* HW rate indices. */ #define RTWN_RIDX_CCK1 0 #define RTWN_RIDX_CCK2 1 -#define RTWN_RIDX_CCK55 2 +#define RTWN_RIDX_CCK5 2 #define RTWN_RIDX_CCK11 3 #define RTWN_RIDX_OFDM6 4 #define RTWN_RIDX_OFDM9 5 @@ -40,7 +40,10 @@ #define RTWN_RIDX_HT_MCS_SHIFT 12 #define RTWN_RIDX_HT_MCS(i) (RTWN_RIDX_HT_MCS_SHIFT + (i)) -#define RTWN_RIDX_COUNT 28 +#define RTWN_RIDX_VHT_MCS_SHIFT 44 +#define RTWN_RIDX_VHT_MCS(i) (RTWN_RIDX_VHT_MCS_SHIFT + (i)) + +#define RTWN_RIDX_COUNT 28 /* NB: obsolete (will be removed) */ #define RTWN_RIDX_UNKNOWN (uint8_t)-1 #define RTWN_RATE_IS_CCK(rate) ((rate) <= RTWN_RIDX_CCK11) @@ -51,45 +54,137 @@ static const uint8_t ridx2rate[] = { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 }; -static __inline uint8_t -rate2ridx(uint8_t rate) +static __inline uint16_t +ridx2rate_idx(device_t dev, uint8_t ridx) { - if (rate & IEEE80211_RATE_MCS) { - return ((rate & 0xf) + RTWN_RIDX_HT_MCS_SHIFT); +#define RTWN_MAX_CHAINS 2 +#define RTWN_MIN_RIDX_HT RTWN_RIDX_HT_MCS(0) +#define RTWN_MAX_RIDX_HT \ + RTWN_RIDX_HT_MCS(IEEE80211_HT_MCS_CHAIN * RTWN_MAX_CHAINS - 1) +#define RTWN_MIN_RIDX_VHT RTWN_RIDX_VHT_MCS(0) +#define RTWN_MAX_RIDX_VHT \ + RTWN_RIDX_VHT_MCS(IEEE80211_VHT_MCS_CHAIN * RTWN_MAX_CHAINS - 1) +#define RTWN_CHECK_RATE(rate) \ + case RTWN_RIDX_##rate: \ + return (IEEE80211_RATE_INDEX_##rate); + + if (RTWN_MIN_RIDX_VHT <= ridx && ridx <= RTWN_MAX_RIDX_VHT) { + int mcs, chains; + + ridx -= RTWN_RIDX_VHT_MCS_SHIFT; + mcs = ridx / RTWN_RIDX_VHT_MCS_SHIFT; + chains = ridx % RTWN_RIDX_VHT_MCS_SHIFT; + + return (IEEE80211_RATE_INDEX_VHT(mcs, chains)); } - switch (rate) { - /* 11g */ - case 12: return 4; - case 18: return 5; - case 24: return 6; - case 36: return 7; - case 48: return 8; - case 72: return 9; - case 96: return 10; - case 108: return 11; - /* 11b */ - case 2: return 0; - case 4: return 1; - case 11: return 2; - case 22: return 3; - default: return RTWN_RIDX_UNKNOWN; + + if (RTWN_MIN_RIDX_HT <= ridx && ridx <= RTWN_MAX_RIDX_HT) { + ridx -= RTWN_RIDX_HT_MCS_SHIFT; + return (IEEE80211_RATE_INDEX_HT(ridx)); } + + switch (ridx) { + RTWN_CHECK_RATE(CCK1); + RTWN_CHECK_RATE(CCK2); + RTWN_CHECK_RATE(CCK5); + RTWN_CHECK_RATE(CCK11); + RTWN_CHECK_RATE(OFDM6); + RTWN_CHECK_RATE(OFDM9); + RTWN_CHECK_RATE(OFDM12); + RTWN_CHECK_RATE(OFDM18); + RTWN_CHECK_RATE(OFDM24); + RTWN_CHECK_RATE(OFDM36); + RTWN_CHECK_RATE(OFDM48); + RTWN_CHECK_RATE(OFDM54); + default: + break; + } + + device_printf(dev, "unknown rate index %u\n", ridx); + + return (IEEE80211_RATE_NONEXISTENT); + +#undef RTWN_CHECK_RATE +#undef RTWN_MAX_RIDX_VHT +#undef RTWN_MIN_RIDX_VHT +#undef RTWN_MAX_RIDX_HT +#undef RTWN_MIN_RIDX_HT +#undef RTWN_MAX_CHAINS } -/* XXX move to net80211 */ -static __inline__ uint8_t -rtwn_ctl_mcsrate(const struct ieee80211_rate_table *rt, uint8_t ridx) +static __inline uint8_t +rate2ridx(const struct ieee80211_rate_t *rate) { - uint8_t cix, rate; + switch (rate->type) { + case IEEE80211_T_VHT: + return RTWN_RIDX_VHT_MCS(rate->value); + case IEEE80211_T_HT: + return RTWN_RIDX_HT_MCS(rate->value); + case IEEE80211_T_OFDM: + switch (rate->value) { + case 12: return 4; + case 18: return 5; + case 24: return 6; + case 36: return 7; + case 48: return 8; + case 72: return 9; + case 96: return 10; + case 108: return 11; + default: return RTWN_RIDX_UNKNOWN; + } + case IEEE80211_T_CCK: + switch (rate->value) { + case 2: return 0; + case 4: return 1; + case 11: return 2; + case 22: return 3; + default: return RTWN_RIDX_UNKNOWN; + } + default: + return (RTWN_RIDX_UNKNOWN); + } +} - /* Check if we are using MCS rate. */ - KASSERT(ridx >= RTWN_RIDX_HT_MCS(0) && ridx != RTWN_RIDX_UNKNOWN, - ("bad mcs rate index %d", ridx)); +static __inline uint8_t +rate_idx2ridx(uint16_t rate_idx) +{ +#define RTWN_MAX_CHAINS 2 +#define MIN_HT_RATE_IDX IEEE80211_RATE_INDEX_HT(0) +#define MAX_HT_RATE_IDX \ + IEEE80211_RATE_INDEX_HT(IEEE80211_HT_MCS_CHAIN * RTWN_MAX_CHAINS - 1) +#define MIN_VHT_RATE_IDX IEEE80211_RATE_INDEX_VHT(0, 1) +#define MAX_VHT_RATE_IDX \ + IEEE80211_RATE_INDEX_VHT(IEEE80211_VHT_MCS_CHAIN - 1, RTWN_MAX_CHAINS) - rate = (ridx - RTWN_RIDX_HT_MCS(0)) | IEEE80211_RATE_MCS; - cix = rt->info[rt->rateCodeToIndex[rate]].ctlRateIndex; - KASSERT(cix != (uint8_t)-1, ("rate %d (%d) has no info", rate, ridx)); - return rt->info[cix].dot11Rate; + if (MIN_VHT_RATE_IDX <= rate_idx && rate_idx <= MAX_VHT_RATE_IDX) + return (rate_idx - MIN_VHT_RATE_IDX + RTWN_RIDX_VHT_MCS_SHIFT); + + if (MIN_HT_RATE_IDX <= rate_idx && rate_idx <= MAX_HT_RATE_IDX) + return (rate_idx - MIN_HT_RATE_IDX + RTWN_RIDX_HT_MCS_SHIFT); + + switch (rate_idx) { + case IEEE80211_RATE_INDEX_OFDM6: return RTWN_RIDX_OFDM6; + case IEEE80211_RATE_INDEX_OFDM9: return RTWN_RIDX_OFDM9; + case IEEE80211_RATE_INDEX_OFDM12: return RTWN_RIDX_OFDM12; + case IEEE80211_RATE_INDEX_OFDM18: return RTWN_RIDX_OFDM18; + case IEEE80211_RATE_INDEX_OFDM24: return RTWN_RIDX_OFDM24; + case IEEE80211_RATE_INDEX_OFDM36: return RTWN_RIDX_OFDM36; + case IEEE80211_RATE_INDEX_OFDM48: return RTWN_RIDX_OFDM48; + case IEEE80211_RATE_INDEX_OFDM54: return RTWN_RIDX_OFDM54; + case IEEE80211_RATE_INDEX_CCK1: return RTWN_RIDX_CCK1; + case IEEE80211_RATE_INDEX_CCK2: return RTWN_RIDX_CCK2; + case IEEE80211_RATE_INDEX_CCK5: return RTWN_RIDX_CCK5; + case IEEE80211_RATE_INDEX_CCK11: return RTWN_RIDX_CCK11; + default: break; + } + + return (RTWN_RIDX_UNKNOWN); + +#undef MAX_VHT_RATE_IDX +#undef MIN_VHT_RATE_IDX +#undef MAX_HT_RATE_IDX +#undef MIN_HT_RATE_IDX +#undef RTWN_MAX_CHAINS } #endif /* IF_RTWN_RIDX_H */ Index: sys/dev/rtwn/if_rtwn_rx.c =================================================================== --- sys/dev/rtwn/if_rtwn_rx.c +++ sys/dev/rtwn/if_rtwn_rx.c @@ -71,11 +71,10 @@ /* This is for 11bg */ for (i = 0; i < rs->rs_nrates; i++) { /* Convert 802.11 rate to HW rate index. */ - ridx = rate2ridx(IEEE80211_RV(rs->rs_rates[i])); + ridx = rate_idx2ridx(rs->rates[i].rs_index); if (ridx == RTWN_RIDX_UNKNOWN) /* Unknown rate, skip. */ continue; - if (((rs->rs_rates[i] & IEEE80211_RATE_BASIC) != 0) || - !basic_rates) { + if (rs->rates[i].rs_basic || !basic_rates) { rates |= 1 << ridx; if (ridx > maxrate) maxrate = ridx; @@ -83,12 +82,15 @@ } /* If we're doing 11n, enable 11n rates */ - if (rs_ht != NULL && !basic_rates) { + if (rs_ht != NULL) { for (i = 0; i < rs_ht->rs_nrates; i++) { - if ((rs_ht->rs_rates[i] & 0x7f) > 0xf) + if (!rs_ht->rates[i].rs_basic && basic_rates) continue; - /* 11n rates start at index 12 */ - ridx = RTWN_RIDX_HT_MCS((rs_ht->rs_rates[i]) & 0xf); + + ridx = rate_idx2ridx(rs_ht->rates[i].rs_index); + if (ridx == RTWN_RIDX_UNKNOWN) + continue; + rates |= (1 << ridx); /* Guard against the rate table being oddly ordered */ @@ -96,6 +98,8 @@ maxrate = ridx; } } + + /* XXX VHT? */ RTWN_DPRINTF(sc, RTWN_DEBUG_RA, "%s: rates 0x%08X, maxrate %d\n", __func__, rates, maxrate); Index: sys/dev/rtwn/if_rtwn_tx.c =================================================================== --- sys/dev/rtwn/if_rtwn_tx.c +++ sys/dev/rtwn/if_rtwn_tx.c @@ -112,14 +112,15 @@ rtwn_tx_data(struct rtwn_softc *sc, struct ieee80211_node *ni, struct mbuf *m) { - const struct ieee80211_txparam *tp = ni->ni_txparms; + const struct ieee80211_txparam_vht *tp = ni->ni_txparms; struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_key *k = NULL; struct ieee80211_frame *wh; struct rtwn_tx_desc_common *txd; struct rtwn_tx_buf buf; - uint8_t rate, ridx, type; + uint16_t rate_idx; + uint8_t type; u_int cipher; int ismcast; @@ -133,28 +134,28 @@ if (type == IEEE80211_FC0_TYPE_MGT || type == IEEE80211_FC0_TYPE_CTL || (m->m_flags & M_EAPOL) != 0) - rate = tp->mgmtrate; + rate_idx = tp->mgmtrate; else if (ismcast) - rate = tp->mcastrate; - else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) - rate = tp->ucastrate; + rate_idx = tp->mcastrate; + else if (tp->ucastrate != IEEE80211_RATE_NONEXISTENT) + rate_idx = tp->ucastrate; else { if (sc->sc_ratectl == RTWN_RATECTL_NET80211) { /* XXX pass pktlen */ (void) ieee80211_ratectl_rate(ni, NULL, 0); - rate = ni->ni_txrate; + rate_idx = ni->ni_txrate; } else { + if (ni->ni_flags & IEEE80211_NODE_VHT) + rate_idx = IEEE80211_RATE_INDEX_VHT(4, 1); if (ni->ni_flags & IEEE80211_NODE_HT) - rate = IEEE80211_RATE_MCS | 0x4; /* MCS4 */ + rate_idx = IEEE80211_RATE_INDEX_HT(4); else if (ic->ic_curmode != IEEE80211_MODE_11B) - rate = ridx2rate[RTWN_RIDX_OFDM36]; + rate_idx = IEEE80211_RATE_INDEX_OFDM36; else - rate = ridx2rate[RTWN_RIDX_CCK55]; + rate_idx = IEEE80211_RATE_INDEX_CCK5; } } - ridx = rate2ridx(rate); - cipher = IEEE80211_CIPHER_NONE; if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { k = ieee80211_crypto_encap(ni, m); @@ -175,7 +176,7 @@ memset(txd, 0, sc->txdesc_len); txd->txdw1 = htole32(SM(RTWN_TXDW1_CIPHER, rtwn_get_cipher(cipher))); - rtwn_fill_tx_desc(sc, ni, m, txd, ridx, tp->maxretry); + rtwn_fill_tx_desc(sc, ni, m, txd, rate_idx, tp->maxretry); if (ieee80211_radiotap_active_vap(vap)) { struct rtwn_tx_radiotap_header *tap = &sc->sc_txtap; Index: sys/dev/rtwn/if_rtwnvar.h =================================================================== --- sys/dev/rtwn/if_rtwnvar.h +++ sys/dev/rtwn/if_rtwnvar.h @@ -319,7 +319,7 @@ void (*sc_detach_private)(struct rtwn_softc *); void (*sc_fill_tx_desc)(struct rtwn_softc *, struct ieee80211_node *, struct mbuf *, - void *, uint8_t, int); + void *, uint16_t, int); void (*sc_fill_tx_desc_raw)(struct rtwn_softc *, struct ieee80211_node *, struct mbuf *, void *, const struct ieee80211_bpf_params *); @@ -522,9 +522,9 @@ #define rtwn_detach_private(_sc) \ (((_sc)->sc_detach_private)((_sc))) #define rtwn_fill_tx_desc(_sc, _ni, _m, \ - _buf, _ridx, _maxretry) \ + _buf, _rate_idx, _maxretry) \ (((_sc)->sc_fill_tx_desc)((_sc), (_ni), \ - (_m), (_buf), (_ridx), (_maxretry))) + (_m), (_buf), (_rate_idx), (_maxretry))) #define rtwn_fill_tx_desc_raw(_sc, _ni, _m, \ _buf, _params) \ (((_sc)->sc_fill_tx_desc_raw)((_sc), (_ni), \ Index: sys/dev/rtwn/rtl8188e/r88e_rx.c =================================================================== --- sys/dev/rtwn/rtl8188e/r88e_rx.c +++ sys/dev/rtwn/rtl8188e/r88e_rx.c @@ -106,12 +106,7 @@ txs.flags = IEEE80211_RATECTL_STATUS_LONG_RETRY | IEEE80211_RATECTL_STATUS_FINAL_RATE; txs.long_retries = ntries; - if (rpt->final_rate > RTWN_RIDX_OFDM54) { /* MCS */ - txs.final_rate = - rpt->final_rate - RTWN_RIDX_HT_MCS_SHIFT; - txs.final_rate |= IEEE80211_RATE_MCS; - } else - txs.final_rate = ridx2rate[rpt->final_rate]; + txs.final_rate = ridx2rate_idx(sc->sc_dev, rpt->final_rate); if (rpt->rptb1 & R88E_RPTB1_PKT_OK) txs.status = IEEE80211_RATECTL_TX_SUCCESS; else if (rpt->rptb2 & R88E_RPTB2_RETRY_OVER) Index: sys/dev/rtwn/rtl8192c/r92c.h =================================================================== --- sys/dev/rtwn/rtl8192c/r92c.h +++ sys/dev/rtwn/rtl8192c/r92c.h @@ -113,7 +113,7 @@ void r92c_tx_setup_hwseq(void *); void r92c_tx_setup_macid(void *, int); void r92c_fill_tx_desc(struct rtwn_softc *, struct ieee80211_node *, - struct mbuf *, void *, uint8_t, int); + struct mbuf *, void *, uint16_t, int); void r92c_fill_tx_desc_raw(struct rtwn_softc *, struct ieee80211_node *, struct mbuf *, void *, const struct ieee80211_bpf_params *); void r92c_fill_tx_desc_null(struct rtwn_softc *, void *, int, int, int); Index: sys/dev/rtwn/rtl8192c/r92c_chan.c =================================================================== --- sys/dev/rtwn/rtl8192c/r92c_chan.c +++ sys/dev/rtwn/rtl8192c/r92c_chan.c @@ -168,14 +168,14 @@ rtwn_bb_write(sc, R92C_TXAGC_A_CCK1_MCS32, reg); reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11); reg = RW(reg, R92C_TXAGC_A_CCK2, power[RTWN_RIDX_CCK2]); - reg = RW(reg, R92C_TXAGC_A_CCK55, power[RTWN_RIDX_CCK55]); + reg = RW(reg, R92C_TXAGC_A_CCK55, power[RTWN_RIDX_CCK5]); reg = RW(reg, R92C_TXAGC_A_CCK11, power[RTWN_RIDX_CCK11]); rtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg); } else { reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK1_55_MCS32); reg = RW(reg, R92C_TXAGC_B_CCK1, power[RTWN_RIDX_CCK1]); reg = RW(reg, R92C_TXAGC_B_CCK2, power[RTWN_RIDX_CCK2]); - reg = RW(reg, R92C_TXAGC_B_CCK55, power[RTWN_RIDX_CCK55]); + reg = RW(reg, R92C_TXAGC_B_CCK55, power[RTWN_RIDX_CCK5]); rtwn_bb_write(sc, R92C_TXAGC_B_CCK1_55_MCS32, reg); reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11); reg = RW(reg, R92C_TXAGC_B_CCK11, power[RTWN_RIDX_CCK11]); Index: sys/dev/rtwn/rtl8192c/r92c_tx.c =================================================================== --- sys/dev/rtwn/rtl8192c/r92c_tx.c +++ sys/dev/rtwn/rtl8192c/r92c_tx.c @@ -81,10 +81,11 @@ static void r92c_tx_protection(struct rtwn_softc *sc, struct r92c_tx_desc *txd, - enum ieee80211_protmode mode, uint8_t ridx) + enum ieee80211_protmode mode, uint16_t rate_idx) { + const struct ieee80211_rate_t *rate; struct ieee80211com *ic = &sc->sc_ic; - uint8_t rate; + uint8_t ridx; switch (mode) { case IEEE80211_PROT_CTSONLY: @@ -99,17 +100,15 @@ if (mode == IEEE80211_PROT_CTSONLY || mode == IEEE80211_PROT_RTSCTS) { - if (ridx >= RTWN_RIDX_HT_MCS(0)) - rate = rtwn_ctl_mcsrate(ic->ic_rt, ridx); - else - rate = ieee80211_ctl_rate(ic->ic_rt, ridx2rate[ridx]); + rate = ieee80211_ctl_rate(ic->ic_rt->ctl_rates, rate_idx); ridx = rate2ridx(rate); txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE, ridx)); /* RTS rate fallback limit (max). */ txd->txdw5 |= htole32(SM(R92C_TXDW5_RTSRATE_FB_LMT, 0xf)); - if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 && + if (rate->type == IEEE80211_T_CCK && + rate->props.cck.short_preamble && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) txd->txdw4 |= htole32(R92C_TXDW4_RTS_SHORT); } @@ -215,8 +214,9 @@ void r92c_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni, - struct mbuf *m, void *buf, uint8_t ridx, int maxretry) + struct mbuf *m, void *buf, uint16_t rate_idx, int maxretry) { + const struct ieee80211_rate_t *rate; #ifndef RTWN_WITHOUT_UCODE struct r92c_softc *rs = sc->sc_priv; #endif @@ -226,7 +226,7 @@ struct ieee80211_frame *wh; struct r92c_tx_desc *txd; enum ieee80211_protmode prot; - uint8_t type, tid, qos, qsel; + uint8_t ridx, type, tid, qos, qsel; int hasqos, ismcast, macid; wh = mtod(m, struct ieee80211_frame *); @@ -234,6 +234,14 @@ hasqos = IEEE80211_QOS_HAS_SEQ(wh); ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); + rate = ieee80211_get_rate(rate_idx); + ridx = rate2ridx(rate); + + KASSERT(rate->type == IEEE80211_T_CCK || + rate->type == IEEE80211_T_OFDM || + rate->type == IEEE80211_T_HT, ("unsupported rate type %u", + rate->type)); + /* Select TX ring for this frame. */ if (hasqos) { qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0]; @@ -280,12 +288,13 @@ #endif } - if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 && + if (rate->type == IEEE80211_T_CCK && + rate->props.cck.short_preamble && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) txd->txdw4 |= htole32(R92C_TXDW4_DATA_SHPRE); prot = IEEE80211_PROT_NONE; - if (ridx >= RTWN_RIDX_HT_MCS(0)) { + if (rate->type == IEEE80211_T_HT) { r92c_tx_set_ht40(sc, txd, ni); r92c_tx_set_sgi(sc, txd, ni); prot = ic->ic_htprotmode; @@ -301,7 +310,7 @@ /* NB: checks for ht40 / short bits (set above). */ if (prot != IEEE80211_PROT_NONE) - r92c_tx_protection(sc, txd, prot, ridx); + r92c_tx_protection(sc, txd, prot, rate_idx); } else /* IEEE80211_FC0_TYPE_MGT */ qsel = R92C_TXDW1_QSEL_MGNT; } else { @@ -355,7 +364,7 @@ wh = mtod(m, struct ieee80211_frame *); ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); - ridx = rate2ridx(params->ibp_rate0); + ridx = rate_idx2ridx(params->ibp_rate0); /* Fill Tx descriptor. */ txd = (struct r92c_tx_desc *)buf; @@ -368,10 +377,14 @@ txd->txdw5 |= htole32(SM(R92C_TXDW5_RTY_LMT, params->ibp_try0)); } - if (params->ibp_flags & IEEE80211_BPF_RTS) - r92c_tx_protection(sc, txd, IEEE80211_PROT_RTSCTS, ridx); - if (params->ibp_flags & IEEE80211_BPF_CTS) - r92c_tx_protection(sc, txd, IEEE80211_PROT_CTSONLY, ridx); + if (params->ibp_flags & IEEE80211_BPF_RTS) { + r92c_tx_protection(sc, txd, IEEE80211_PROT_RTSCTS, + params->ibp_rate0); + } + if (params->ibp_flags & IEEE80211_BPF_CTS) { + r92c_tx_protection(sc, txd, IEEE80211_PROT_CTSONLY, + params->ibp_rate0); + } rtwn_r92c_tx_setup_macid(sc, txd, RTWN_MACID_BC); txd->txdw1 |= htole32(SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT)); Index: sys/dev/rtwn/rtl8812a/r12a.h =================================================================== --- sys/dev/rtwn/rtl8812a/r12a.h +++ sys/dev/rtwn/rtl8812a/r12a.h @@ -133,7 +133,7 @@ /* r12a_tx.c */ void r12a_fill_tx_desc(struct rtwn_softc *, struct ieee80211_node *, - struct mbuf *, void *, uint8_t, int); + struct mbuf *, void *, uint16_t, int); void r12a_fill_tx_desc_raw(struct rtwn_softc *, struct ieee80211_node *, struct mbuf *, void *, const struct ieee80211_bpf_params *); void r12a_fill_tx_desc_null(struct rtwn_softc *, void *, int, int, int); Index: sys/dev/rtwn/rtl8812a/r12a_chan.c =================================================================== --- sys/dev/rtwn/rtl8812a/r12a_chan.c +++ sys/dev/rtwn/rtl8812a/r12a_chan.c @@ -72,7 +72,7 @@ rtwn_bb_write(sc, R12A_TXAGC_CCK11_1(chain), SM(R12A_TXAGC_CCK1, power[RTWN_RIDX_CCK1]) | SM(R12A_TXAGC_CCK2, power[RTWN_RIDX_CCK2]) | - SM(R12A_TXAGC_CCK55, power[RTWN_RIDX_CCK55]) | + SM(R12A_TXAGC_CCK55, power[RTWN_RIDX_CCK5]) | SM(R12A_TXAGC_CCK11, power[RTWN_RIDX_CCK11])); } Index: sys/dev/rtwn/rtl8812a/r12a_rx.c =================================================================== --- sys/dev/rtwn/rtl8812a/r12a_rx.c +++ sys/dev/rtwn/rtl8812a/r12a_rx.c @@ -113,12 +113,7 @@ txs.flags = IEEE80211_RATECTL_STATUS_LONG_RETRY | IEEE80211_RATECTL_STATUS_FINAL_RATE; txs.long_retries = ntries; - if (rpt->final_rate > RTWN_RIDX_OFDM54) { /* MCS */ - txs.final_rate = - rpt->final_rate - RTWN_RIDX_HT_MCS_SHIFT; - txs.final_rate |= IEEE80211_RATE_MCS; - } else - txs.final_rate = ridx2rate[rpt->final_rate]; + txs.final_rate = ridx2rate_idx(sc->sc_dev, rpt->final_rate); if (rpt->txrptb0 & R12A_TXRPTB0_RETRY_OVER) txs.status = IEEE80211_RATECTL_TX_FAIL_LONG; else if (rpt->txrptb0 & R12A_TXRPTB0_LIFE_EXPIRE) Index: sys/dev/rtwn/rtl8812a/r12a_tx.c =================================================================== --- sys/dev/rtwn/rtl8812a/r12a_tx.c +++ sys/dev/rtwn/rtl8812a/r12a_tx.c @@ -89,10 +89,11 @@ static void r12a_tx_protection(struct rtwn_softc *sc, struct r12a_tx_desc *txd, - enum ieee80211_protmode mode, uint8_t ridx) + enum ieee80211_protmode mode, uint16_t rate_idx) { + const struct ieee80211_rate_t *rate; struct ieee80211com *ic = &sc->sc_ic; - uint8_t rate; + uint8_t ridx; switch (mode) { case IEEE80211_PROT_CTSONLY: @@ -107,17 +108,15 @@ if (mode == IEEE80211_PROT_CTSONLY || mode == IEEE80211_PROT_RTSCTS) { - if (ridx >= RTWN_RIDX_HT_MCS(0)) - rate = rtwn_ctl_mcsrate(ic->ic_rt, ridx); - else - rate = ieee80211_ctl_rate(ic->ic_rt, ridx2rate[ridx]); + rate = ieee80211_ctl_rate(ic->ic_rt->ctl_rates, rate_idx); ridx = rate2ridx(rate); txd->txdw4 |= htole32(SM(R12A_TXDW4_RTSRATE, ridx)); /* RTS rate fallback limit (max). */ txd->txdw4 |= htole32(SM(R12A_TXDW4_RTSRATE_FB_LMT, 0xf)); - if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 && + if (rate->type == IEEE80211_T_CCK && + rate->props.cck.short_preamble && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) txd->txdw5 |= htole32(R12A_TXDW5_RTS_SHORT); } @@ -227,15 +226,16 @@ void r12a_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni, - struct mbuf *m, void *buf, uint8_t ridx, int maxretry) + struct mbuf *m, void *buf, uint16_t rate_idx, int maxretry) { + const struct ieee80211_rate_t *rate; struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = ni->ni_vap; struct rtwn_vap *uvp = RTWN_VAP(vap); struct ieee80211_frame *wh; struct r12a_tx_desc *txd; enum ieee80211_protmode prot; - uint8_t type, tid, qos, qsel; + uint8_t type, tid, qos, qsel, ridx; int hasqos, ismcast, macid; wh = mtod(m, struct ieee80211_frame *); @@ -243,6 +243,9 @@ hasqos = IEEE80211_QOS_HAS_SEQ(wh); ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); + rate = ieee80211_get_rate(rate_idx); + ridx = rate2ridx(rate); + /* Select TX ring for this frame. */ if (hasqos) { qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0]; @@ -287,12 +290,13 @@ sc->sc_tx_n_active++; } - if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 && + if (rate->type == IEEE80211_T_CCK && + rate->props.cck.short_preamble && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) txd->txdw5 |= htole32(R12A_TXDW5_DATA_SHORT); prot = IEEE80211_PROT_NONE; - if (ridx >= RTWN_RIDX_HT_MCS(0)) { + if (rate->type == IEEE80211_T_HT) { r12a_tx_set_ht40(sc, txd, ni); r12a_tx_set_sgi(sc, txd, ni); r12a_tx_set_ldpc(sc, txd, ni); @@ -308,7 +312,7 @@ prot = IEEE80211_PROT_RTSCTS; if (prot != IEEE80211_PROT_NONE) - r12a_tx_protection(sc, txd, prot, ridx); + r12a_tx_protection(sc, txd, prot, rate_idx); } else /* IEEE80211_FC0_TYPE_MGT */ qsel = R12A_TXDW1_QSEL_MGNT; } else { @@ -362,7 +366,7 @@ wh = mtod(m, struct ieee80211_frame *); ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); - ridx = rate2ridx(params->ibp_rate0); + ridx = rate_idx2ridx(params->ibp_rate0); /* Fill Tx descriptor. */ txd = (struct r12a_tx_desc *)buf; @@ -375,10 +379,14 @@ txd->txdw4 |= htole32(SM(R12A_TXDW4_RETRY_LMT, params->ibp_try0)); } - if (params->ibp_flags & IEEE80211_BPF_RTS) - r12a_tx_protection(sc, txd, IEEE80211_PROT_RTSCTS, ridx); - if (params->ibp_flags & IEEE80211_BPF_CTS) - r12a_tx_protection(sc, txd, IEEE80211_PROT_CTSONLY, ridx); + if (params->ibp_flags & IEEE80211_BPF_RTS) { + r12a_tx_protection(sc, txd, IEEE80211_PROT_RTSCTS, + params->ibp_rate0); + } + if (params->ibp_flags & IEEE80211_BPF_CTS) { + r12a_tx_protection(sc, txd, IEEE80211_PROT_CTSONLY, + params->ibp_rate0); + } txd->txdw1 |= htole32(SM(R12A_TXDW1_MACID, RTWN_MACID_BC)); txd->txdw1 |= htole32(SM(R12A_TXDW1_QSEL, R12A_TXDW1_QSEL_MGNT)); Index: sys/dev/usb/wlan/if_rsu.c =================================================================== --- sys/dev/usb/wlan/if_rsu.c +++ sys/dev/usb/wlan/if_rsu.c @@ -1511,7 +1511,7 @@ ni = ieee80211_ref_node(vap->iv_bss); rs = &ni->ni_rates; /* Indicate highest supported rate. */ - ni->ni_txrate = rs->rs_rates[rs->rs_nrates - 1]; + ni->ni_txrate = rs->rates[rs->rs_nrates - 1].rs_index; (void) rsu_set_fw_power_state(sc, RSU_PWR_SLEEP); ieee80211_free_node(ni); startcal = 1; @@ -1926,6 +1926,8 @@ static int rsu_join_bss(struct rsu_softc *sc, struct ieee80211_node *ni) { + const struct ieee80211_rate_t *rate; + const struct ieee80211_rateset *rs; struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = ni->ni_vap; struct ndis_wlan_bssid_ex *bss; @@ -1934,7 +1936,7 @@ uint8_t buf[sizeof(*bss) + 128] __aligned(4); uint8_t *frm; uint8_t opmode; - int error; + int i, error; RSU_ASSERT_LOCKED(sc); @@ -1977,8 +1979,11 @@ bss->config.dsconfig = htole32(ieee80211_chan2ieee(ic, ni->ni_chan)); bss->inframode = htole32(NDIS802_11INFRASTRUCTURE); /* XXX verify how this is supposed to look! */ - memcpy(bss->supprates, ni->ni_rates.rs_rates, - ni->ni_rates.rs_nrates); + rs = &ni->ni_rates; + for (i = 0; i < rs->rs_nrates; i++) { + rate = ieee80211_get_rate(rs->rates[i].rs_index); + bss->supprates[i] = rate->value; + } /* Write the fixed fields of the beacon frame. */ fixed = (struct ndis_802_11_fixed_ies *)&bss[1]; memcpy(&fixed->tstamp, ni->ni_tstamp.data, 8); Index: sys/dev/usb/wlan/if_rum.c =================================================================== --- sys/dev/usb/wlan/if_rum.c +++ sys/dev/usb/wlan/if_rum.c @@ -180,7 +180,8 @@ static uint8_t rum_crypto_mode(struct rum_softc *, u_int, int); static void rum_setup_tx_desc(struct rum_softc *, struct rum_tx_desc *, struct ieee80211_key *, - uint32_t, uint8_t, uint8_t, int, int, int); + uint32_t, uint8_t, uint8_t, int, int, + const struct ieee80211_rate_t *); static uint32_t rum_tx_crypto_flags(struct rum_softc *, struct ieee80211_node *, const struct ieee80211_key *); @@ -968,7 +969,7 @@ struct rum_vap *rvp = RUM_VAP(vap); struct ieee80211com *ic = vap->iv_ic; struct rum_softc *sc = ic->ic_softc; - const struct ieee80211_txparam *tp; + const struct ieee80211_txparam_vht *tp; enum ieee80211_state ostate; struct ieee80211_node *ni; usb_error_t uerror; @@ -1037,7 +1038,7 @@ /* enable automatic rate adaptation */ tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; - if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) + if (tp->ucastrate == IEEE80211_RATE_NONEXISTENT) rum_ratectl_start(sc, ni); run_fail: ieee80211_free_node(ni); @@ -1360,7 +1361,7 @@ static void rum_setup_tx_desc(struct rum_softc *sc, struct rum_tx_desc *desc, struct ieee80211_key *k, uint32_t flags, uint8_t xflags, uint8_t qid, - int hdrlen, int len, int rate) + int hdrlen, int len, const struct ieee80211_rate_t *rate) { struct ieee80211com *ic = &sc->sc_ic; struct wmeParams *wmep = &sc->wme_params[qid]; @@ -1380,21 +1381,19 @@ } /* setup PLCP fields */ - desc->plcp_signal = rum_plcp_signal(rate); + desc->plcp_signal = rum_plcp_signal(rate->value); desc->plcp_service = 4; len += IEEE80211_CRC_LEN; - if (ieee80211_rate2phytype(ic->ic_rt, rate) == IEEE80211_T_OFDM) { + if (rate->type == IEEE80211_T_OFDM) { flags |= RT2573_TX_OFDM; plcp_length = len & 0xfff; desc->plcp_length_hi = plcp_length >> 6; desc->plcp_length_lo = plcp_length & 0x3f; } else { - if (rate == 0) - rate = 2; /* avoid division by zero */ - plcp_length = howmany(16 * len, rate); - if (rate == 22) { + plcp_length = howmany(16 * len, rate->value); + if (rate->value == 22) { remainder = (16 * len) % 22; if (remainder != 0 && remainder < 7) desc->plcp_service |= RT2573_PLCP_LENGEXT; @@ -1402,7 +1401,8 @@ desc->plcp_length_hi = plcp_length >> 8; desc->plcp_length_lo = plcp_length & 0xff; - if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) + if (rate->props.cck.short_preamble && + (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) desc->plcp_signal |= 0x08; } @@ -1417,17 +1417,18 @@ } static int -rum_sendprot(struct rum_softc *sc, - const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate) +rum_sendprot(struct rum_softc *sc, const struct mbuf *m, + struct ieee80211_node *ni, int prot, uint16_t rate_idx) { + const struct ieee80211_rate_t *protrate; struct ieee80211com *ic = ni->ni_ic; struct rum_tx_data *data; struct mbuf *mprot; - int protrate, flags; + int flags; RUM_LOCK_ASSERT(sc); - mprot = ieee80211_alloc_prot(ni, m, rate, prot); + mprot = ieee80211_alloc_prot(ni, m, rate_idx, prot); if (mprot == NULL) { if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1); device_printf(sc->sc_dev, @@ -1435,7 +1436,7 @@ return (ENOBUFS); } - protrate = ieee80211_ctl_rate(ic->ic_rt, rate); + protrate = ieee80211_ctl_rate(ic->ic_rt->ctl_rates, rate_idx); flags = 0; if (prot == IEEE80211_PROT_RTSCTS) flags |= RT2573_TX_NEED_ACK; @@ -1446,7 +1447,7 @@ data->m = mprot; data->ni = ieee80211_ref_node(ni); - data->rate = protrate; + data->rate = protrate->value; rum_setup_tx_desc(sc, &data->desc, NULL, flags, 0, 0, 0, mprot->m_pkthdr.len, protrate); @@ -1493,7 +1494,8 @@ static int rum_tx_mgt(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) { - const struct ieee80211_txparam *tp = ni->ni_txparms; + const struct ieee80211_rate_t *rate; + const struct ieee80211_txparam_vht *tp = ni->ni_txparms; struct ieee80211com *ic = &sc->sc_ic; struct rum_tx_data *data; struct ieee80211_frame *wh; @@ -1513,6 +1515,7 @@ type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; hdrlen = ieee80211_anyhdrsize(wh); ac = M_WME_GETAC(m0); + rate = ieee80211_get_rate(tp->mgmtrate); if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { k = ieee80211_crypto_get_txkey(ni, m0); @@ -1529,8 +1532,8 @@ if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { flags |= RT2573_TX_NEED_ACK; - dur = ieee80211_ack_duration(ic->ic_rt, tp->mgmtrate, - ic->ic_flags & IEEE80211_F_SHPREAMBLE); + dur = ieee80211_ack_duration(ic->ic_rt->ctl_rates, + tp->mgmtrate, ic->ic_flags & IEEE80211_F_SHPREAMBLE); USETW(wh->i_dur, dur); /* tell hardware to add timestamp for probe responses */ @@ -1548,13 +1551,14 @@ data->m = m0; data->ni = ni; - data->rate = tp->mgmtrate; + data->rate = rate->value; rum_setup_tx_desc(sc, &data->desc, k, flags, xflags, ac, hdrlen, - m0->m_pkthdr.len, tp->mgmtrate); + m0->m_pkthdr.len, rate); - DPRINTFN(10, "sending mgt frame len=%d rate=%d\n", - m0->m_pkthdr.len + (int)RT2573_TX_DESC_SIZE, tp->mgmtrate); + DPRINTFN(10, "sending mgt frame len=%d rate=%u/%u\n", + m0->m_pkthdr.len + (int)RT2573_TX_DESC_SIZE, rate->type, + rate->value); STAILQ_INSERT_TAIL(&sc->tx_q, data, next); usbd_transfer_start(sc->sc_xfer[RUM_BULK_WR]); @@ -1566,12 +1570,13 @@ rum_tx_raw(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) { + const struct ieee80211_rate_t *rate; struct ieee80211com *ic = ni->ni_ic; struct ieee80211_frame *wh; struct rum_tx_data *data; uint32_t flags; uint8_t ac, type, xflags = 0; - int rate, error; + int error; RUM_LOCK_ASSERT(sc); @@ -1580,8 +1585,8 @@ ac = params->ibp_pri & 3; - rate = params->ibp_rate0; - if (!ieee80211_isratevalid(ic->ic_rt, rate)) + rate = ieee80211_get_rate_safe(params->ibp_rate0); + if (!rate || !ieee80211_isratevalid(ic->ic_rt, rate)) return (EINVAL); flags = 0; @@ -1591,7 +1596,7 @@ error = rum_sendprot(sc, m0, ni, params->ibp_flags & IEEE80211_BPF_RTS ? IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY, - rate); + params->ibp_rate0); if (error || sc->tx_nfree == 0) return (ENOBUFS); @@ -1607,14 +1612,14 @@ data->m = m0; data->ni = ni; - data->rate = rate; + data->rate = rate->value; /* XXX need to setup descriptor ourself */ rum_setup_tx_desc(sc, &data->desc, NULL, flags, xflags, ac, 0, m0->m_pkthdr.len, rate); - DPRINTFN(10, "sending raw frame len=%u rate=%u\n", - m0->m_pkthdr.len, rate); + DPRINTFN(10, "sending raw frame len=%u rate=%u/%u\n", + m0->m_pkthdr.len, rate->type, rate->value); STAILQ_INSERT_TAIL(&sc->tx_q, data, next); usbd_transfer_start(sc->sc_xfer[RUM_BULK_WR]); @@ -1625,16 +1630,17 @@ static int rum_tx_data(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) { + const struct ieee80211_rate_t *rate; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = &sc->sc_ic; struct rum_tx_data *data; struct ieee80211_frame *wh; - const struct ieee80211_txparam *tp = ni->ni_txparms; + const struct ieee80211_txparam_vht *tp = ni->ni_txparms; struct ieee80211_key *k = NULL; uint32_t flags = 0; - uint16_t dur; + uint16_t dur, rate_idx; uint8_t ac, type, qos, xflags = 0; - int error, hdrlen, rate; + int error, hdrlen; RUM_LOCK_ASSERT(sc); @@ -1649,16 +1655,18 @@ ac = M_WME_GETAC(m0); if (m0->m_flags & M_EAPOL) - rate = tp->mgmtrate; + rate_idx = tp->mgmtrate; else if (IEEE80211_IS_MULTICAST(wh->i_addr1)) - rate = tp->mcastrate; - else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) - rate = tp->ucastrate; + rate_idx = tp->mcastrate; + else if (tp->ucastrate != IEEE80211_RATE_NONEXISTENT) + rate_idx = tp->ucastrate; else { (void) ieee80211_ratectl_rate(ni, NULL, 0); - rate = ni->ni_txrate; + rate_idx = ni->ni_txrate; } + rate = ieee80211_get_rate(rate_idx); + if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { k = ieee80211_crypto_get_txkey(ni, m0); if (k == NULL) { @@ -1683,10 +1691,10 @@ if (m0->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) prot = IEEE80211_PROT_RTSCTS; else if ((ic->ic_flags & IEEE80211_F_USEPROT) && - ieee80211_rate2phytype(ic->ic_rt, rate) == IEEE80211_T_OFDM) + rate->type == IEEE80211_T_OFDM) prot = ic->ic_protmode; if (prot != IEEE80211_PROT_NONE) { - error = rum_sendprot(sc, m0, ni, prot, rate); + error = rum_sendprot(sc, m0, ni, prot, rate_idx); if (error || sc->tx_nfree == 0) { m_freem(m0); return ENOBUFS; @@ -1704,7 +1712,7 @@ data->m = m0; data->ni = ni; - data->rate = rate; + data->rate = rate->value; if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { /* Unicast frame, check if an ACK is expected. */ @@ -1712,7 +1720,7 @@ IEEE80211_QOS_ACKPOLICY_NOACK) flags |= RT2573_TX_NEED_ACK; - dur = ieee80211_ack_duration(ic->ic_rt, rate, + dur = ieee80211_ack_duration(ic->ic_rt->ctl_rates, rate_idx, ic->ic_flags & IEEE80211_F_SHPREAMBLE); USETW(wh->i_dur, dur); } @@ -1720,8 +1728,9 @@ rum_setup_tx_desc(sc, &data->desc, k, flags, xflags, ac, hdrlen, m0->m_pkthdr.len, rate); - DPRINTFN(10, "sending frame len=%d rate=%d\n", - m0->m_pkthdr.len + (int)RT2573_TX_DESC_SIZE, rate); + DPRINTFN(10, "sending frame len=%d rate=%u/%u\n", + m0->m_pkthdr.len + (int)RT2573_TX_DESC_SIZE, rate->type, + rate->value); STAILQ_INSERT_TAIL(&sc->tx_q, data, next); usbd_transfer_start(sc->sc_xfer[RUM_BULK_WR]); @@ -2177,7 +2186,7 @@ rum_set_maxretry(struct rum_softc *sc, struct ieee80211vap *vap) { struct ieee80211_node *ni = vap->iv_bss; - const struct ieee80211_txparam *tp = ni->ni_txparms; + const struct ieee80211_txparam_vht *tp = ni->ni_txparms; struct rum_vap *rvp = RUM_VAP(vap); rvp->maxretry = MIN(tp->maxretry, 0xf); @@ -2766,7 +2775,7 @@ struct ieee80211com *ic = vap->iv_ic; struct rum_vap *rvp = RUM_VAP(vap); struct mbuf *m = rvp->bcn_mbuf; - const struct ieee80211_txparam *tp; + const struct ieee80211_txparam_vht *tp; struct rum_tx_desc desc; RUM_LOCK_ASSERT(sc); @@ -2778,7 +2787,8 @@ tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_bsschan)]; rum_setup_tx_desc(sc, &desc, NULL, RT2573_TX_TIMESTAMP, - RT2573_TX_HWSEQ, 0, 0, m->m_pkthdr.len, tp->mgmtrate); + RT2573_TX_HWSEQ, 0, 0, m->m_pkthdr.len, + ieee80211_get_rate(tp->mgmtrate)); /* copy the Tx descriptor into NIC memory */ if (rum_write_multi(sc, RT2573_HW_BCN_BASE(0), (uint8_t *)&desc, Index: sys/dev/usb/wlan/if_run.c =================================================================== --- sys/dev/usb/wlan/if_run.c +++ sys/dev/usb/wlan/if_run.c @@ -433,7 +433,7 @@ static int run_tx_mgt(struct run_softc *, struct mbuf *, struct ieee80211_node *); static int run_sendprot(struct run_softc *, const struct mbuf *, - struct ieee80211_node *, int, int); + struct ieee80211_node *, int, uint16_t); static int run_tx_param(struct run_softc *, struct mbuf *, struct ieee80211_node *, const struct ieee80211_bpf_params *); @@ -501,22 +501,19 @@ uint8_t rate; uint8_t mcs; enum ieee80211_phytype phy; - uint8_t ctl_ridx; - uint16_t sp_ack_dur; - uint16_t lp_ack_dur; } rt2860_rates[] = { - { 2, 0, IEEE80211_T_DS, 0, 314, 314 }, - { 4, 1, IEEE80211_T_DS, 1, 258, 162 }, - { 11, 2, IEEE80211_T_DS, 2, 223, 127 }, - { 22, 3, IEEE80211_T_DS, 3, 213, 117 }, - { 12, 0, IEEE80211_T_OFDM, 4, 60, 60 }, - { 18, 1, IEEE80211_T_OFDM, 4, 52, 52 }, - { 24, 2, IEEE80211_T_OFDM, 6, 48, 48 }, - { 36, 3, IEEE80211_T_OFDM, 6, 44, 44 }, - { 48, 4, IEEE80211_T_OFDM, 8, 44, 44 }, - { 72, 5, IEEE80211_T_OFDM, 8, 40, 40 }, - { 96, 6, IEEE80211_T_OFDM, 8, 40, 40 }, - { 108, 7, IEEE80211_T_OFDM, 8, 40, 40 } + { 2, 0, IEEE80211_T_DS }, + { 4, 1, IEEE80211_T_DS }, + { 11, 2, IEEE80211_T_DS }, + { 22, 3, IEEE80211_T_DS }, + { 12, 0, IEEE80211_T_OFDM }, + { 18, 1, IEEE80211_T_OFDM }, + { 24, 2, IEEE80211_T_OFDM }, + { 36, 3, IEEE80211_T_OFDM }, + { 48, 4, IEEE80211_T_OFDM }, + { 72, 5, IEEE80211_T_OFDM }, + { 96, 6, IEEE80211_T_OFDM }, + { 108, 7, IEEE80211_T_OFDM } }; static const struct { @@ -2034,14 +2031,52 @@ return malloc(sizeof (struct run_node), M_DEVBUF, M_NOWAIT | M_ZERO); } +static uint8_t +rate2ridx(struct run_softc *sc, const struct ieee80211_rate_t *rate) +{ + + switch (rate->type) { + case IEEE80211_T_HT: + /* TODO? */ + break; + case IEEE80211_T_OFDM: + switch (rate->value) { + case 12: return 4; + case 18: return 5; + case 24: return 6; + case 36: return 7; + case 48: return 8; + case 72: return 9; + case 96: return 10; + case 108: return 11; + default: + break; + } + case IEEE80211_T_CCK: + switch (rate->value) { + case 2: return 0; + case 4: return 1; + case 11: return 2; + case 22: return 3; + default: + break; + } + } + + device_printf(sc->sc_dev, "unknown rate %u/%u\n", + rate->type, rate->value); + + return (0); +} + static int run_media_change(struct ifnet *ifp) { + const struct ieee80211_rate_t *rate; struct ieee80211vap *vap = ifp->if_softc; struct ieee80211com *ic = vap->iv_ic; - const struct ieee80211_txparam *tp; + const struct ieee80211_txparam_vht *tp; struct run_softc *sc = ic->ic_softc; - uint8_t rate, ridx; int error; RUN_LOCK(sc); @@ -2053,20 +2088,16 @@ } tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; - if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { + if (tp->ucastrate != IEEE80211_RATE_NONEXISTENT) { struct ieee80211_node *ni; struct run_node *rn; - rate = ic->ic_sup_rates[ic->ic_curmode]. - rs_rates[tp->ucastrate] & IEEE80211_RATE_VAL; - for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) - if (rt2860_rates[ridx].rate == rate) - break; + rate = ieee80211_get_rate(tp->ucastrate); ni = ieee80211_ref_node(vap->iv_bss); rn = RUN_NODE(ni); - rn->fix_ridx = ridx; - RUN_DPRINTF(sc, RUN_DEBUG_RATE, "rate=%d, fix_ridx=%d\n", - rate, rn->fix_ridx); + rn->fix_ridx = rate2ridx(sc, rate); + RUN_DPRINTF(sc, RUN_DEBUG_RATE, "rate=%u/%u, fix_ridx=%d\n", + rate->type, rate->value, rn->fix_ridx); ieee80211_free_node(ni); } @@ -2085,7 +2116,7 @@ static int run_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { - const struct ieee80211_txparam *tp; + const struct ieee80211_txparam_vht *tp; struct ieee80211com *ic = vap->iv_ic; struct run_softc *sc = ic->ic_softc; struct run_vap *rvp = RUN_VAP(vap); @@ -2190,7 +2221,7 @@ /* enable automatic rate adaptation */ tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; - if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) + if (tp->ucastrate == IEEE80211_RATE_NONEXISTENT) ratectl |= bid; } else run_enable_tsf(sc); @@ -2686,15 +2717,15 @@ static void run_newassoc(struct ieee80211_node *ni, int isnew) { + const struct ieee80211_rate_t *rate; struct run_node *rn = RUN_NODE(ni); struct ieee80211_rateset *rs = &ni->ni_rates; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = vap->iv_ic; struct run_softc *sc = ic->ic_softc; - uint8_t rate; - uint8_t ridx; + enum ieee80211_phymode mode; uint8_t wcid; - int i, j; + int i; wcid = (vap->iv_opmode == IEEE80211_M_STA) ? 1 : RUN_AID2WCID(ni->ni_associd); @@ -2725,37 +2756,29 @@ isnew, ni->ni_associd, ether_sprintf(ni->ni_macaddr)); for (i = 0; i < rs->rs_nrates; i++) { - rate = rs->rs_rates[i] & IEEE80211_RATE_VAL; + rate = ieee80211_get_rate(rs->rates[i].rs_index); + /* convert 802.11 rate to hardware rate index */ - for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) - if (rt2860_rates[ridx].rate == rate) - break; - rn->ridx[i] = ridx; - /* determine rate of control response frames */ - for (j = i; j >= 0; j--) { - if ((rs->rs_rates[j] & IEEE80211_RATE_BASIC) && - rt2860_rates[rn->ridx[i]].phy == - rt2860_rates[rn->ridx[j]].phy) - break; - } - if (j >= 0) { - rn->ctl_ridx[i] = rn->ridx[j]; - } else { - /* no basic rate found, use mandatory one */ - rn->ctl_ridx[i] = rt2860_rates[ridx].ctl_ridx; - } + rn->ridx[i] = rate2ridx(sc, rate); + RUN_DPRINTF(sc, RUN_DEBUG_STATE | RUN_DEBUG_RATE, - "rate=0x%02x ridx=%d ctl_ridx=%d\n", - rs->rs_rates[i], rn->ridx[i], rn->ctl_ridx[i]); + "rate=%u/0x%02x ridx=%d\n", + rate->type, rate->value, rn->ridx[i]); } - rate = vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)].mgmtrate; - for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) - if (rt2860_rates[ridx].rate == rate) - break; - rn->mgt_ridx = ridx; + + mode = ieee80211_chan2mode(ic->ic_curchan); + rate = ieee80211_get_rate(vap->iv_txparms[mode].mgmtrate); + rn->mgt_ridx = rate2ridx(sc, rate); RUN_DPRINTF(sc, RUN_DEBUG_STATE | RUN_DEBUG_RATE, - "rate=%d, mgmt_ridx=%d\n", rate, rn->mgt_ridx); + "rate=%u/%u, mgmt_ridx=%d\n", rate->type, rate->value, + rn->mgt_ridx); + rate = ieee80211_get_rate(vap->iv_txparms[mode].mcastrate); + rn->mcast_ridx = rate2ridx(sc, rate); + RUN_DPRINTF(sc, RUN_DEBUG_STATE | RUN_DEBUG_RATE, + "rate=%u/%u, mcast_ridx=%d\n", rate->type, rate->value, + rn->mcast_ridx); + RUN_LOCK(sc); if(sc->ratectl_run != RUN_RATECTL_OFF) usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc); @@ -3315,27 +3338,29 @@ struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_frame *wh; - const struct ieee80211_txparam *tp = ni->ni_txparms; + const struct ieee80211_txparam_vht *tp = ni->ni_txparms; struct run_node *rn = RUN_NODE(ni); struct run_tx_data *data; struct rt2870_txd *txd; struct rt2860_txwi *txwi; + uint16_t rate_idx; uint16_t qos; uint16_t dur; uint16_t qid; uint8_t type; uint8_t tid; uint8_t ridx; - uint8_t ctl_ridx; uint8_t qflags; uint8_t xflags = 0; int hasqos; + int ismcast; RUN_LOCK_ASSERT(sc, MA_OWNED); wh = mtod(m, struct ieee80211_frame *); type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); /* * There are 7 bulk endpoints: 1 for RX @@ -3365,27 +3390,27 @@ qos, qid, tid, qflags); /* pickup a rate index */ - if (IEEE80211_IS_MULTICAST(wh->i_addr1) || - type != IEEE80211_FC0_TYPE_DATA || m->m_flags & M_EAPOL) { - ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ? - RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1; - ctl_ridx = rt2860_rates[ridx].ctl_ridx; + if (type != IEEE80211_FC0_TYPE_DATA || + (m->m_flags & M_EAPOL) != 0) { + rate_idx = tp->mgmtrate; + ridx = rn->mgt_ridx; + } else if (ismcast) { + rate_idx = tp->mcastrate; + ridx = rn->mcast_ridx; + } else if (tp->ucastrate != IEEE80211_RATE_NONEXISTENT) { + rate_idx = tp->ucastrate; + ridx = rn->fix_ridx; } else { - if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) - ridx = rn->fix_ridx; - else - ridx = rn->amrr_ridx; - ctl_ridx = rt2860_rates[ridx].ctl_ridx; + rate_idx = ni->ni_txrate; + ridx = rn->amrr_ridx; } - if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && + if (!ismcast && (!hasqos || (qos & IEEE80211_QOS_ACKPOLICY) != IEEE80211_QOS_ACKPOLICY_NOACK)) { xflags |= RT2860_TX_ACK; - if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) - dur = rt2860_rates[ctl_ridx].sp_ack_dur; - else - dur = rt2860_rates[ctl_ridx].lp_ack_dur; + dur = ieee80211_ack_duration(ic->ic_rt->ctl_rates, + rate_idx, ic->ic_flags & IEEE80211_F_SHPREAMBLE); USETW(wh->i_dur, dur); } @@ -3403,7 +3428,7 @@ txd->flags = qflags; txwi = (struct rt2860_txwi *)(txd + 1); txwi->xflags = xflags; - if (IEEE80211_IS_MULTICAST(wh->i_addr1)) + if (ismcast) txwi->wcid = 0; else txwi->wcid = (vap->iv_opmode == IEEE80211_M_STA) ? @@ -3477,6 +3502,7 @@ static int run_tx_mgt(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) { + const struct ieee80211_txparam_vht *tp = ni->ni_txparms; struct ieee80211com *ic = &sc->sc_ic; struct run_node *rn = RUN_NODE(ni); struct run_tx_data *data; @@ -3500,8 +3526,8 @@ else if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { xflags |= RT2860_TX_ACK; - dur = ieee80211_ack_duration(ic->ic_rt, rt2860_rates[ridx].rate, - ic->ic_flags & IEEE80211_F_SHPREAMBLE); + dur = ieee80211_ack_duration(ic->ic_rt->ctl_rates, + tp->mgmtrate, ic->ic_flags & IEEE80211_F_SHPREAMBLE); USETW(wh->i_dur, dur); } @@ -3538,18 +3564,16 @@ } static int -run_sendprot(struct run_softc *sc, - const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate) +run_sendprot(struct run_softc *sc, const struct mbuf *m, + struct ieee80211_node *ni, int prot, uint16_t rate_idx) { + const struct ieee80211_rate_t *protrate; struct ieee80211com *ic = ni->ni_ic; struct run_tx_data *data; struct rt2870_txd *txd; struct rt2860_txwi *txwi; struct mbuf *mprot; - int ridx; - int protrate; - uint8_t wflags = 0; - uint8_t xflags = 0; + uint8_t wflags, xflags; RUN_LOCK_ASSERT(sc, MA_OWNED); @@ -3558,14 +3582,14 @@ /* let caller free mbuf */ return (ENOBUFS); - mprot = ieee80211_alloc_prot(ni, m, rate, prot); + mprot = ieee80211_alloc_prot(ni, m, rate_idx, prot); if (mprot == NULL) { if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1); RUN_DPRINTF(sc, RUN_DEBUG_XMIT, "could not allocate mbuf\n"); return (ENOBUFS); } - protrate = ieee80211_ctl_rate(ic->ic_rt, rate); + protrate = ieee80211_ctl_rate(ic->ic_rt->ctl_rates, rate_idx); wflags = RT2860_TX_FRAG; xflags = 0; if (prot == IEEE80211_PROT_RTSCTS) @@ -3585,18 +3609,14 @@ data->m = mprot; data->ni = ieee80211_ref_node(ni); + data->ridx = rate2ridx(sc, protrate); - for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) - if (rt2860_rates[ridx].rate == protrate) - break; - data->ridx = ridx; - run_set_tx_desc(sc, data); - RUN_DPRINTF(sc, RUN_DEBUG_XMIT, "sending prot len=%u rate=%u\n", - m->m_pkthdr.len, rate); + RUN_DPRINTF(sc, RUN_DEBUG_XMIT, "sending prot len=%u rate=%u/%u\n", + m->m_pkthdr.len, protrate->type, protrate->value); - STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); + STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); usbd_transfer_start(sc->sc_xfer[0]); @@ -3607,12 +3627,11 @@ run_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) { + const struct ieee80211_rate_t *rate; struct ieee80211com *ic = ni->ni_ic; struct run_tx_data *data; struct rt2870_txd *txd; struct rt2860_txwi *txwi; - uint8_t ridx; - uint8_t rate; uint8_t opflags = 0; uint8_t xflags = 0; int error; @@ -3621,8 +3640,8 @@ KASSERT(params != NULL, ("no raw xmit params")); - rate = params->ibp_rate0; - if (!ieee80211_isratevalid(ic->ic_rt, rate)) { + rate = ieee80211_get_rate_safe(params->ibp_rate0); + if (!rate || !ieee80211_isratevalid(ic->ic_rt, rate)) { /* let caller free mbuf */ return (EINVAL); } @@ -3633,7 +3652,7 @@ error = run_sendprot(sc, m, ni, params->ibp_flags & IEEE80211_BPF_RTS ? IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY, - rate); + params->ibp_rate0); if (error) { /* let caller free mbuf */ return error; @@ -3647,9 +3666,9 @@ "sending raw frame, but tx ring is full\n"); return (EIO); } - data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh); - STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); - sc->sc_epq[0].tx_nfree--; + data = STAILQ_FIRST(&sc->sc_epq[0].tx_fh); + STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); + sc->sc_epq[0].tx_nfree--; txd = (struct rt2870_txd *)&data->desc; txd->flags = RT2860_TX_QSEL_EDCA; @@ -3659,23 +3678,21 @@ txwi->txop = opflags; txwi->flags = 0; /* clear leftover garbage bits */ - data->m = m; - data->ni = ni; - for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) - if (rt2860_rates[ridx].rate == rate) - break; - data->ridx = ridx; + data->m = m; + data->ni = ni; + data->ridx = rate2ridx(sc, rate); - run_set_tx_desc(sc, data); + run_set_tx_desc(sc, data); - RUN_DPRINTF(sc, RUN_DEBUG_XMIT, "sending raw frame len=%u rate=%u\n", - m->m_pkthdr.len, rate); + RUN_DPRINTF(sc, RUN_DEBUG_XMIT, + "sending raw frame len=%u rate=%u/%u\n", + m->m_pkthdr.len, rate->type, rate->value); - STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); + STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); usbd_transfer_start(sc->sc_xfer[0]); - return (0); + return (0); } static int Index: sys/dev/usb/wlan/if_runvar.h =================================================================== --- sys/dev/usb/wlan/if_runvar.h +++ sys/dev/usb/wlan/if_runvar.h @@ -98,8 +98,8 @@ struct run_node { struct ieee80211_node ni; uint8_t ridx[IEEE80211_RATE_MAXSIZE]; - uint8_t ctl_ridx[IEEE80211_RATE_MAXSIZE]; uint8_t amrr_ridx; + uint8_t mcast_ridx; uint8_t mgt_ridx; uint8_t fix_ridx; }; Index: sys/dev/usb/wlan/if_uath.c =================================================================== --- sys/dev/usb/wlan/if_uath.c +++ sys/dev/usb/wlan/if_uath.c @@ -1888,11 +1888,14 @@ static int uath_create_connection(struct uath_softc *sc, uint32_t connid) { + const struct ieee80211_rate_t *rate; const struct ieee80211_rateset *rs; struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); struct ieee80211_node *ni; struct uath_cmd_create_connection create; + struct uath_cmd_rateset *uath_rs; + int i; ni = ieee80211_ref_node(vap->iv_bss); memset(&create, 0, sizeof(create)); @@ -1902,10 +1905,14 @@ create.size = htobe32(sizeof(struct uath_cmd_rateset)); rs = &ni->ni_rates; - create.connattr.rateset.length = rs->rs_nrates; - bcopy(rs->rs_rates, &create.connattr.rateset.set[0], - rs->rs_nrates); + uath_rs = &create.connattr.rateset; + uath_rs->length = MIN(rs->rs_nrates, nitems(uath_rs->set)); + for (i = 0; i < uath_rs->length; i++) { + rate = ieee80211_get_rate(rs->rates[i].rs_index); + uath_rs->set[i] = rate->value; + } + /* XXX turbo */ if (IEEE80211_IS_CHAN_A(ni->ni_chan)) create.connattr.wlanmode = htobe32(WLAN_MODE_11a); @@ -1922,14 +1929,18 @@ static int uath_set_rates(struct uath_softc *sc, const struct ieee80211_rateset *rs) { + const struct ieee80211_rate_t *rate; struct uath_cmd_rates rates; + int i; memset(&rates, 0, sizeof(rates)); rates.connid = htobe32(UATH_ID_BSS); /* XXX */ rates.size = htobe32(sizeof(struct uath_cmd_rateset)); - /* XXX bounds check rs->rs_nrates */ - rates.rateset.length = rs->rs_nrates; - bcopy(rs->rs_rates, &rates.rateset.set[0], rs->rs_nrates); + rates.rateset.length = MIN(rs->rs_nrates, nitems(rates.rateset.set)); + for (i = 0; i < rates.rateset.length; i++) { + rate = ieee80211_get_rate(rs->rates[i].rs_index); + rates.rateset.set[i] = rate->value; + } DPRINTF(sc, UATH_DEBUG_RATES, "setting supported rates nrates=%d\n", rs->rs_nrates); @@ -1990,6 +2001,7 @@ static int uath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { + const struct ieee80211_rateset *rs; enum ieee80211_state ostate = vap->iv_state; int error; struct ieee80211_node *ni; @@ -2006,6 +2018,7 @@ callout_stop(&sc->stat_ch); callout_stop(&sc->watchdog_ch); ni = ieee80211_ref_node(vap->iv_bss); + rs = &ni->ni_rates; switch (nstate) { case IEEE80211_S_INIT: @@ -2040,7 +2053,7 @@ break; case IEEE80211_S_ASSOC: - if (uath_set_rates(sc, &ni->ni_rates) != 0) { + if (uath_set_rates(sc, rs) != 0) { device_printf(sc->sc_dev, "could not set negotiated rate set\n"); break; @@ -2058,7 +2071,7 @@ * Tx rate is controlled by firmware, report the maximum * negotiated rate in ifconfig output. */ - ni->ni_txrate = ni->ni_rates.rs_rates[ni->ni_rates.rs_nrates-1]; + ni->ni_txrate = rs->rates[rs->rs_nrates - 1].rs_index; if (uath_write_associd(sc) != 0) { device_printf(sc->sc_dev, Index: sys/dev/usb/wlan/if_upgt.c =================================================================== --- sys/dev/usb/wlan/if_upgt.c +++ sys/dev/usb/wlan/if_upgt.c @@ -148,7 +148,7 @@ static uint8_t upgt_rx_rate(struct upgt_softc *, const int); static void upgt_set_multi(void *); static void upgt_stop(struct upgt_softc *); -static void upgt_setup_rates(struct ieee80211vap *, struct ieee80211com *); +static void upgt_setup_rates(struct ieee80211vap *); static int upgt_set_macfilter(struct upgt_softc *, uint8_t); static int upgt_newstate(struct ieee80211vap *, enum ieee80211_state, int); static void upgt_set_chan(struct upgt_softc *, struct ieee80211_channel *); @@ -679,11 +679,37 @@ return (0); } +static __inline uint8_t +rate_idx2value(uint16_t rate_idx) +{ + + switch (rate_idx) { + case IEEE80211_RATE_INDEX_CCK1: return (0x10); + case IEEE80211_RATE_INDEX_CCK2: return (0x11); + case IEEE80211_RATE_INDEX_CCK5: return (0x12); + case IEEE80211_RATE_INDEX_CCK11: return (0x13); + case IEEE80211_RATE_INDEX_OFDM6: return (0x01); + case IEEE80211_RATE_INDEX_OFDM9: return (0x04); + case IEEE80211_RATE_INDEX_OFDM12: return (0x06); + case IEEE80211_RATE_INDEX_OFDM18: return (0x07); + case IEEE80211_RATE_INDEX_OFDM24: return (0x08); + case IEEE80211_RATE_INDEX_OFDM36: return (0x09); + case IEEE80211_RATE_INDEX_OFDM48: return (0x0a); + case IEEE80211_RATE_INDEX_OFDM54: return (0x0b); + default: + break; + } + + return (0x10); +} + static void -upgt_setup_rates(struct ieee80211vap *vap, struct ieee80211com *ic) +upgt_setup_rates(struct ieee80211vap *vap) { - struct upgt_softc *sc = ic->ic_softc; - const struct ieee80211_txparam *tp; + struct upgt_softc *sc = vap->iv_ic->ic_softc; + struct ieee80211com *ic = &sc->sc_ic; + const struct ieee80211_txparam_vht *tp; + uint8_t fixed_rate; /* * 0x01 = OFMD6 0x10 = DS1 @@ -699,14 +725,11 @@ { 0x13, 0x13, 0x12, 0x11, 0x11, 0x10, 0x10, 0x10 }; const uint8_t rateset_auto_11g[] = { 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x04, 0x01 }; - const uint8_t rateset_fix_11bg[] = - { 0x10, 0x11, 0x12, 0x13, 0x01, 0x04, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b }; tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; /* XXX */ - if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) { + if (tp->ucastrate == IEEE80211_RATE_NONEXISTENT) { /* * Automatic rate control is done by the device. * We just pass the rateset from which the device @@ -720,8 +743,10 @@ memcpy(sc->sc_cur_rateset, rateset_auto_11g, sizeof(sc->sc_cur_rateset)); } else { + fixed_rate = rate_idx2value(tp->ucastrate); + /* set a fixed rate */ - memset(sc->sc_cur_rateset, rateset_fix_11bg[tp->ucastrate], + memset(sc->sc_cur_rateset, fixed_rate, sizeof(sc->sc_cur_rateset)); } } @@ -972,7 +997,7 @@ vap->iv_newstate = upgt_newstate; /* setup device rates */ - upgt_setup_rates(vap, ic); + upgt_setup_rates(vap); /* complete setup */ ieee80211_vap_attach(vap, ieee80211_media_change, Index: sys/dev/usb/wlan/if_ural.c =================================================================== --- sys/dev/usb/wlan/if_ural.c +++ sys/dev/usb/wlan/if_ural.c @@ -144,7 +144,8 @@ static int ural_newstate(struct ieee80211vap *, enum ieee80211_state, int); static void ural_setup_tx_desc(struct ural_softc *, - struct ural_tx_desc *, uint32_t, int, int); + struct ural_tx_desc *, uint32_t, int, + const struct ieee80211_rate_t *); static int ural_tx_bcn(struct ural_softc *, struct mbuf *, struct ieee80211_node *); static int ural_tx_mgt(struct ural_softc *, struct mbuf *, @@ -681,7 +682,7 @@ struct ural_vap *uvp = URAL_VAP(vap); struct ieee80211com *ic = vap->iv_ic; struct ural_softc *sc = ic->ic_softc; - const struct ieee80211_txparam *tp; + const struct ieee80211_txparam_vht *tp; struct ieee80211_node *ni; struct mbuf *m; @@ -745,7 +746,7 @@ /* enable automatic rate adaptation */ /* XXX should use ic_bsschan but not valid until after newstate call below */ tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; - if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) + if (tp->ucastrate == IEEE80211_RATE_NONEXISTENT) ural_ratectl_start(sc, ni); ieee80211_free_node(ni); break; @@ -983,7 +984,7 @@ static void ural_setup_tx_desc(struct ural_softc *sc, struct ural_tx_desc *desc, - uint32_t flags, int len, int rate) + uint32_t flags, int len, const struct ieee80211_rate_t *rate) { struct ieee80211com *ic = &sc->sc_ic; uint16_t plcp_length; @@ -997,21 +998,22 @@ desc->wme |= htole16(RAL_IVOFFSET(sizeof (struct ieee80211_frame))); /* setup PLCP fields */ - desc->plcp_signal = ural_plcp_signal(rate); + desc->plcp_signal = ural_plcp_signal(rate->value); desc->plcp_service = 4; len += IEEE80211_CRC_LEN; - if (ieee80211_rate2phytype(ic->ic_rt, rate) == IEEE80211_T_OFDM) { + if (rate->type == IEEE80211_T_OFDM) { desc->flags |= htole32(RAL_TX_OFDM); plcp_length = len & 0xfff; desc->plcp_length_hi = plcp_length >> 6; desc->plcp_length_lo = plcp_length & 0x3f; } else { - if (rate == 0) - rate = 2; /* avoid division by zero */ - plcp_length = howmany(16 * len, rate); - if (rate == 22) { + KASSERT(rate->type == IEEE80211_T_CCK, + ("unknown rate type %u\n", rate->type)); + + plcp_length = howmany(16 * len, rate->value); + if (rate->value == 22) { remainder = (16 * len) % 22; if (remainder != 0 && remainder < 7) desc->plcp_service |= RAL_PLCP_LENGEXT; @@ -1019,7 +1021,8 @@ desc->plcp_length_hi = plcp_length >> 8; desc->plcp_length_lo = plcp_length & 0xff; - if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) + if (rate->props.cck.short_preamble && + (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) desc->plcp_signal |= 0x08; } @@ -1032,9 +1035,10 @@ static int ural_tx_bcn(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) { + const struct ieee80211_rate_t *rate; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; - const struct ieee80211_txparam *tp; + const struct ieee80211_txparam_vht *tp; struct ural_tx_data *data; if (sc->tx_nfree == 0) { @@ -1050,18 +1054,19 @@ data = STAILQ_FIRST(&sc->tx_free); STAILQ_REMOVE_HEAD(&sc->tx_free, next); sc->tx_nfree--; + tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_bsschan)]; + rate = ieee80211_get_rate(tp->mgmtrate); data->m = m0; data->ni = ni; - data->rate = tp->mgmtrate; + data->rate = rate->value; ural_setup_tx_desc(sc, &data->desc, - RAL_TX_IFS_NEWBACKOFF | RAL_TX_TIMESTAMP, m0->m_pkthdr.len, - tp->mgmtrate); + RAL_TX_IFS_NEWBACKOFF | RAL_TX_TIMESTAMP, m0->m_pkthdr.len, rate); - DPRINTFN(10, "sending beacon frame len=%u rate=%u\n", - m0->m_pkthdr.len, tp->mgmtrate); + DPRINTFN(10, "sending beacon frame len=%u rate=%u/%u\n", + m0->m_pkthdr.len, rate->type, rate->value); STAILQ_INSERT_TAIL(&sc->tx_q, data, next); usbd_transfer_start(sc->sc_xfer[URAL_BULK_WR]); @@ -1072,7 +1077,8 @@ static int ural_tx_mgt(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) { - const struct ieee80211_txparam *tp = ni->ni_txparms; + const struct ieee80211_txparam_vht *tp = ni->ni_txparms; + const struct ieee80211_rate_t *rate; struct ieee80211com *ic = ni->ni_ic; struct ural_tx_data *data; struct ieee80211_frame *wh; @@ -1096,16 +1102,18 @@ wh = mtod(m0, struct ieee80211_frame *); } + rate = ieee80211_get_rate(tp->mgmtrate); + data->m = m0; data->ni = ni; - data->rate = tp->mgmtrate; + data->rate = rate->value; flags = 0; if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { flags |= RAL_TX_ACK; - dur = ieee80211_ack_duration(ic->ic_rt, tp->mgmtrate, - ic->ic_flags & IEEE80211_F_SHPREAMBLE); + dur = ieee80211_ack_duration(ic->ic_rt->ctl_rates, + tp->mgmtrate, ic->ic_flags & IEEE80211_F_SHPREAMBLE); USETW(wh->i_dur, dur); /* tell hardware to add timestamp for probe responses */ @@ -1116,10 +1124,10 @@ flags |= RAL_TX_TIMESTAMP; } - ural_setup_tx_desc(sc, &data->desc, flags, m0->m_pkthdr.len, tp->mgmtrate); + ural_setup_tx_desc(sc, &data->desc, flags, m0->m_pkthdr.len, rate); - DPRINTFN(10, "sending mgt frame len=%u rate=%u\n", - m0->m_pkthdr.len, tp->mgmtrate); + DPRINTFN(10, "sending mgt frame len=%u rate=%u/%u\n", + m0->m_pkthdr.len, rate->type, rate->value); STAILQ_INSERT_TAIL(&sc->tx_q, data, next); usbd_transfer_start(sc->sc_xfer[URAL_BULK_WR]); @@ -1128,15 +1136,16 @@ } static int -ural_sendprot(struct ural_softc *sc, - const struct mbuf *m, struct ieee80211_node *ni, int prot, int rate) +ural_sendprot(struct ural_softc *sc, const struct mbuf *m, + struct ieee80211_node *ni, int prot, uint16_t rate_idx) { + const struct ieee80211_rate_t *protrate; struct ieee80211com *ic = ni->ni_ic; struct ural_tx_data *data; struct mbuf *mprot; - int protrate, flags; + int flags; - mprot = ieee80211_alloc_prot(ni, m, rate, prot); + mprot = ieee80211_alloc_prot(ni, m, rate_idx, prot); if (mprot == NULL) { if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1); device_printf(sc->sc_dev, @@ -1144,7 +1153,7 @@ return ENOBUFS; } - protrate = ieee80211_ctl_rate(ic->ic_rt, rate); + protrate = ieee80211_ctl_rate(ic->ic_rt->ctl_rates, rate_idx); flags = RAL_TX_RETRY(7); if (prot == IEEE80211_PROT_RTSCTS) flags |= RAL_TX_ACK; @@ -1155,7 +1164,7 @@ data->m = mprot; data->ni = ieee80211_ref_node(ni); - data->rate = protrate; + data->rate = protrate->value; ural_setup_tx_desc(sc, &data->desc, flags, mprot->m_pkthdr.len, protrate); STAILQ_INSERT_TAIL(&sc->tx_q, data, next); @@ -1168,17 +1177,17 @@ ural_tx_raw(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) { + const struct ieee80211_rate_t *rate; struct ieee80211com *ic = ni->ni_ic; struct ural_tx_data *data; uint32_t flags; int error; - int rate; RAL_LOCK_ASSERT(sc, MA_OWNED); KASSERT(params != NULL, ("no raw xmit params")); - rate = params->ibp_rate0; - if (!ieee80211_isratevalid(ic->ic_rt, rate)) { + rate = ieee80211_get_rate_safe(params->ibp_rate0); + if (!rate || !ieee80211_isratevalid(ic->ic_rt, rate)) { m_freem(m0); return EINVAL; } @@ -1189,7 +1198,7 @@ error = ural_sendprot(sc, m0, ni, params->ibp_flags & IEEE80211_BPF_RTS ? IEEE80211_PROT_RTSCTS : IEEE80211_PROT_CTSONLY, - rate); + params->ibp_rate0); if (error || sc->tx_nfree == 0) { m_freem(m0); return ENOBUFS; @@ -1203,13 +1212,13 @@ data->m = m0; data->ni = ni; - data->rate = rate; + data->rate = rate->value; /* XXX need to setup descriptor ourself */ ural_setup_tx_desc(sc, &data->desc, flags, m0->m_pkthdr.len, rate); - DPRINTFN(10, "sending raw frame len=%u rate=%u\n", - m0->m_pkthdr.len, rate); + DPRINTFN(10, "sending raw frame len=%u rate=%u/%u\n", + m0->m_pkthdr.len, rate->type, rate->value); STAILQ_INSERT_TAIL(&sc->tx_q, data, next); usbd_transfer_start(sc->sc_xfer[URAL_BULK_WR]); @@ -1220,31 +1229,35 @@ static int ural_tx_data(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) { + const struct ieee80211_rate_t *rate; + const struct ieee80211_txparam_vht *tp = ni->ni_txparms; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; struct ural_tx_data *data; struct ieee80211_frame *wh; - const struct ieee80211_txparam *tp = ni->ni_txparms; struct ieee80211_key *k; uint32_t flags = 0; - uint16_t dur; - int error, rate; + uint16_t dur, rate_idx; + int ismcast, error; RAL_LOCK_ASSERT(sc, MA_OWNED); wh = mtod(m0, struct ieee80211_frame *); + ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); if (m0->m_flags & M_EAPOL) - rate = tp->mgmtrate; - else if (IEEE80211_IS_MULTICAST(wh->i_addr1)) - rate = tp->mcastrate; - else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) - rate = tp->ucastrate; + rate_idx = tp->mgmtrate; + else if (ismcast) + rate_idx = tp->mcastrate; + else if (tp->ucastrate != IEEE80211_RATE_NONEXISTENT) + rate_idx = tp->ucastrate; else { (void) ieee80211_ratectl_rate(ni, NULL, 0); - rate = ni->ni_txrate; + rate_idx = ni->ni_txrate; } + rate = ieee80211_get_rate(rate_idx); + if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { k = ieee80211_crypto_encap(ni, m0); if (k == NULL) { @@ -1255,15 +1268,15 @@ wh = mtod(m0, struct ieee80211_frame *); } - if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { + if (!ismcast) { int prot = IEEE80211_PROT_NONE; if (m0->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) prot = IEEE80211_PROT_RTSCTS; else if ((ic->ic_flags & IEEE80211_F_USEPROT) && - ieee80211_rate2phytype(ic->ic_rt, rate) == IEEE80211_T_OFDM) + rate->type == IEEE80211_T_OFDM) prot = ic->ic_protmode; if (prot != IEEE80211_PROT_NONE) { - error = ural_sendprot(sc, m0, ni, prot, rate); + error = ural_sendprot(sc, m0, ni, prot, rate_idx); if (error || sc->tx_nfree == 0) { m_freem(m0); return ENOBUFS; @@ -1278,21 +1291,21 @@ data->m = m0; data->ni = ni; - data->rate = rate; + data->rate = rate->value; - if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { + if (!ismcast) { flags |= RAL_TX_ACK; flags |= RAL_TX_RETRY(7); - dur = ieee80211_ack_duration(ic->ic_rt, rate, - ic->ic_flags & IEEE80211_F_SHPREAMBLE); + dur = ieee80211_ack_duration(ic->ic_rt->ctl_rates, + rate_idx, ic->ic_flags & IEEE80211_F_SHPREAMBLE); USETW(wh->i_dur, dur); } ural_setup_tx_desc(sc, &data->desc, flags, m0->m_pkthdr.len, rate); - DPRINTFN(10, "sending data frame len=%u rate=%u\n", - m0->m_pkthdr.len, rate); + DPRINTFN(10, "sending data frame len=%u rate=%u/%u\n", + m0->m_pkthdr.len, rate->type, rate->value); STAILQ_INSERT_TAIL(&sc->tx_q, data, next); usbd_transfer_start(sc->sc_xfer[URAL_BULK_WR]); Index: sys/dev/usb/wlan/if_urtw.c =================================================================== --- sys/dev/usb/wlan/if_urtw.c +++ sys/dev/usb/wlan/if_urtw.c @@ -482,12 +482,6 @@ 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00 }; -static struct urtw_pair urtw_ratetable[] = { - { 2, 0 }, { 4, 1 }, { 11, 2 }, { 12, 4 }, { 18, 5 }, - { 22, 3 }, { 24, 6 }, { 36, 7 }, { 48, 8 }, { 72, 9 }, - { 96, 10 }, { 108, 11 } -}; - #if 0 static const uint8_t urtw_8187b_reg_table[][3] = { { 0xf0, 0x32, 0 }, { 0xf1, 0x32, 0 }, { 0xf2, 0x00, 0 }, @@ -687,8 +681,7 @@ static void urtw_ledtask(void *, int); static void urtw_watchdog(void *); static void urtw_set_multi(void *); -static int urtw_isbmode(uint16_t); -static uint16_t urtw_rtl2rate(uint32_t); +static uint16_t urtw_rtl2rate_idx(uint8_t); static usb_error_t urtw_set_rate(struct urtw_softc *); static usb_error_t urtw_update_msr(struct urtw_softc *); static usb_error_t urtw_read8_c(struct urtw_softc *, int, uint8_t *); @@ -769,8 +762,8 @@ static void urtw_abort_xfers(struct urtw_softc *); static struct urtw_data * urtw_getbuf(struct urtw_softc *sc); -static int urtw_compute_txtime(uint16_t, uint16_t, uint8_t, - uint8_t); +static int urtw_compute_txtime(uint16_t, + const struct ieee80211_rate_t *, uint8_t); static void urtw_updateslot(struct ieee80211com *); static void urtw_updateslottask(void *, int); static void urtw_sysctl_node(struct urtw_softc *); @@ -1649,9 +1642,10 @@ urtw_tx_start(struct urtw_softc *sc, struct ieee80211_node *ni, struct mbuf *m0, struct urtw_data *data, int prior) { + const struct ieee80211_rate_t *rate, *ctl_rate; struct ieee80211_frame *wh = mtod(m0, struct ieee80211_frame *); struct ieee80211_key *k; - const struct ieee80211_txparam *tp = ni->ni_txparms; + const struct ieee80211_txparam_vht *tp = ni->ni_txparms; struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = ni->ni_vap; struct usb_xfer *rtl8187b_pipes[URTW_8187B_TXPIPE_MAX] = { @@ -1661,9 +1655,9 @@ sc->sc_xfer[URTW_8187B_BULK_TX_VO] }; struct usb_xfer *xfer; - int dur = 0, rtsdur = 0, rtsenable = 0, ctsenable = 0, rate, type, + int dur = 0, rtsdur = 0, rtsenable = 0, ctsenable = 0, type, pkttime = 0, txdur = 0, isshort = 0, xferlen, ismcast; - uint16_t acktime, rtstime, ctstime; + uint16_t acktime, rtstime, ctstime, rate_idx; uint32_t flags; usb_error_t error; @@ -1703,44 +1697,47 @@ if (type == IEEE80211_FC0_TYPE_MGT || type == IEEE80211_FC0_TYPE_CTL || (m0->m_flags & M_EAPOL) != 0) { - rate = tp->mgmtrate; + rate_idx = tp->mgmtrate; } else { /* for data frames */ if (ismcast) - rate = tp->mcastrate; - else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) - rate = tp->ucastrate; + rate_idx = tp->mcastrate; + else if (tp->ucastrate != IEEE80211_RATE_NONEXISTENT) + rate_idx = tp->ucastrate; else - rate = urtw_rtl2rate(sc->sc_currate); + rate_idx = urtw_rtl2rate_idx(sc->sc_currate); } + ctl_rate = ieee80211_get_rate(IEEE80211_RATE_INDEX_CCK1); + rate = ieee80211_get_rate(rate_idx); sc->sc_stats.txrates[sc->sc_currate]++; if (ismcast) txdur = pkttime = urtw_compute_txtime(m0->m_pkthdr.len + - IEEE80211_CRC_LEN, rate, 0, 0); + IEEE80211_CRC_LEN, rate, 0); else { - acktime = urtw_compute_txtime(14, 2,0, 0); + acktime = urtw_compute_txtime(14, ctl_rate, 0); if ((m0->m_pkthdr.len + 4) > vap->iv_rtsthreshold) { rtsenable = 1; ctsenable = 0; - rtstime = urtw_compute_txtime(URTW_ACKCTS_LEN, 2, 0, 0); - ctstime = urtw_compute_txtime(14, 2, 0, 0); + rtstime = urtw_compute_txtime(URTW_ACKCTS_LEN, + ctl_rate, 0); + ctstime = urtw_compute_txtime(14, ctl_rate, 0); pkttime = urtw_compute_txtime(m0->m_pkthdr.len + - IEEE80211_CRC_LEN, rate, 0, isshort); + IEEE80211_CRC_LEN, rate, isshort); rtsdur = ctstime + pkttime + acktime + 3 * URTW_ASIFS_TIME; txdur = rtstime + rtsdur; } else { rtsenable = ctsenable = rtsdur = 0; pkttime = urtw_compute_txtime(m0->m_pkthdr.len + - IEEE80211_CRC_LEN, rate, 0, isshort); + IEEE80211_CRC_LEN, rate, isshort); txdur = pkttime + URTW_ASIFS_TIME + acktime; } if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG) dur = urtw_compute_txtime(m0->m_pkthdr.len + - IEEE80211_CRC_LEN, rate, 0, isshort) + + IEEE80211_CRC_LEN, rate, isshort) + 3 * URTW_ASIFS_TIME + 2 * acktime; else @@ -1759,7 +1756,7 @@ if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) && (sc->sc_preamble_mode == URTW_PREAMBLE_MODE_SHORT) && - (sc->sc_currate != 0)) + rate->type == IEEE80211_T_CCK && rate->props.cck.short_preamble) flags |= URTW_TX_FLAG_SPLCP; if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG) flags |= URTW_TX_FLAG_MOREFRAG; @@ -1905,6 +1902,7 @@ urtw_set_multi(void *arg) { /* XXX don't know how to set a device. Lack of docs. */ + /* XXX probably the same as in rtwn(4) - need to test */ } static usb_error_t @@ -1934,16 +1932,21 @@ } static uint16_t -urtw_rtl2rate(uint32_t rate) +urtw_rtl2rate_idx(uint8_t ridx) { - unsigned int i; + static const uint16_t ridx2rate_idx[] = { + IEEE80211_RATE_INDEX_CCK1, IEEE80211_RATE_INDEX_CCK2, + IEEE80211_RATE_INDEX_CCK5, IEEE80211_RATE_INDEX_CCK11, + IEEE80211_RATE_INDEX_OFDM6, IEEE80211_RATE_INDEX_OFDM9, + IEEE80211_RATE_INDEX_OFDM12, IEEE80211_RATE_INDEX_OFDM18, + IEEE80211_RATE_INDEX_OFDM24, IEEE80211_RATE_INDEX_OFDM36, + IEEE80211_RATE_INDEX_OFDM48, IEEE80211_RATE_INDEX_OFDM54 + }; - for (i = 0; i < nitems(urtw_ratetable); i++) { - if (rate == urtw_ratetable[i].val) - return urtw_ratetable[i].reg; - } + if (ridx < nitems(ridx2rate_idx)) + return (ridx2rate_idx[ridx]); - return (0); + return (IEEE80211_RATE_INDEX_CCK1); } static usb_error_t @@ -3993,7 +3996,8 @@ wh = mtod(m, struct ieee80211_frame *); if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) - sc->sc_currate = (rate > 0) ? rate : sc->sc_currate; + if (rate > 0) + sc->sc_currate = rate; *rssi_p = rssi; *nf_p = noise; /* XXX correct? */ @@ -4226,14 +4230,6 @@ return (bf); } -static int -urtw_isbmode(uint16_t rate) -{ - - return ((rate <= 22 && rate != 12 && rate != 18) || - rate == 44) ? (1) : (0); -} - static uint16_t urtw_rate2dbps(uint16_t rate) { @@ -4254,29 +4250,34 @@ return (24); } +#define CCK_PREAMBLE_BITS 144 +#define CCK_PLCP_BITS 48 + static int -urtw_compute_txtime(uint16_t framelen, uint16_t rate, - uint8_t ismgt, uint8_t isshort) +urtw_compute_txtime(uint16_t framelen, const struct ieee80211_rate_t *rate, + uint8_t isshort) { - uint16_t ceiling, frametime, n_dbps; + uint16_t ceiling, frametime, n_dbps; - if (urtw_isbmode(rate)) { - if (ismgt || !isshort || rate == 2) - frametime = (uint16_t)(144 + 48 + - (framelen * 8 / (rate / 2))); - else - frametime = (uint16_t)(72 + 24 + - (framelen * 8 / (rate / 2))); - if ((framelen * 8 % (rate / 2)) != 0) + if (rate->type == IEEE80211_T_CCK) { + frametime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS; + if (isshort && rate->props.cck.short_preamble) + frametime >>= 1; + + frametime += framelen * 8 / (rate->value / 2); + if ((framelen * 8 % (rate->value / 2)) != 0) frametime++; } else { - n_dbps = urtw_rate2dbps(rate); + n_dbps = urtw_rate2dbps(rate->value); ceiling = (16 + 8 * framelen + 6) / n_dbps + (((16 + 8 * framelen + 6) % n_dbps) ? 1 : 0); frametime = (uint16_t)(16 + 4 + 4 * ceiling + 6); } return (frametime); } + +#undef CCK_PREAMBLE_BITS +#undef CCK_PLCP_BITS /* * Callback from the 802.11 layer to update the Index: sys/dev/usb/wlan/if_zyd.c =================================================================== --- sys/dev/usb/wlan/if_zyd.c +++ sys/dev/usb/wlan/if_zyd.c @@ -2436,18 +2436,19 @@ static int zyd_tx_start(struct zyd_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) { + const struct ieee80211_rate_t *rate; + const struct ieee80211_txparam_vht *tp = ni->ni_txparms; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; struct zyd_tx_desc *desc; struct zyd_tx_data *data; struct ieee80211_frame *wh; - const struct ieee80211_txparam *tp = ni->ni_txparms; struct ieee80211_key *k; - int rate, totlen, type, ismcast; + int totlen, type, ismcast; static const uint8_t ratediv[] = ZYD_TX_RATEDIV; - uint8_t phy; - uint16_t pktlen; uint32_t bits; + uint16_t pktlen, rate_idx; + uint8_t phy; wh = mtod(m0, struct ieee80211_frame *); data = STAILQ_FIRST(&sc->tx_free); @@ -2460,19 +2461,21 @@ if (type == IEEE80211_FC0_TYPE_MGT || type == IEEE80211_FC0_TYPE_CTL || (m0->m_flags & M_EAPOL) != 0) { - rate = tp->mgmtrate; + rate_idx = tp->mgmtrate; } else { /* for data frames */ if (ismcast) - rate = tp->mcastrate; + rate_idx = tp->mcastrate; else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) - rate = tp->ucastrate; + rate_idx = tp->ucastrate; else { (void) ieee80211_ratectl_rate(ni, NULL, 0); - rate = ni->ni_txrate; + rate_idx = ni->ni_txrate; } } + rate = ieee80211_get_rate(rate_idx); + if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { k = ieee80211_crypto_encap(ni, m0); if (k == NULL) { @@ -2484,17 +2487,18 @@ data->ni = ni; data->m = m0; - data->rate = rate; + data->rate = rate->value; /* fill Tx descriptor */ desc = &data->desc; - phy = zyd_plcp_signal(sc, rate); + phy = zyd_plcp_signal(sc, rate->value); desc->phy = phy; - if (ZYD_RATE_IS_OFDM(rate)) { + if (rate->type == IEEE80211_T_OFDM) { desc->phy |= ZYD_TX_PHY_OFDM; if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) desc->phy |= ZYD_TX_PHY_5GHZ; - } else if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) + } else if (rate->props.cck.short_preamble && + (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) desc->phy |= ZYD_TX_PHY_SHPREAMBLE; totlen = m0->m_pkthdr.len + IEEE80211_CRC_LEN; @@ -2505,7 +2509,7 @@ /* multicast frames are not sent at OFDM rates in 802.11b/g */ if (totlen > vap->iv_rtsthreshold) { desc->flags |= ZYD_TX_FLAG_RTS; - } else if (ZYD_RATE_IS_OFDM(rate) && + } else if (rate->type == IEEE80211_T_OFDM && (ic->ic_flags & IEEE80211_F_USEPROT)) { if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) desc->flags |= ZYD_TX_FLAG_CTS_TO_SELF; @@ -2525,11 +2529,11 @@ pktlen += totlen; desc->pktlen = htole16(pktlen); - bits = (rate == 11) ? (totlen * 16) + 10 : - ((rate == 22) ? (totlen * 8) + 10 : (totlen * 8)); + bits = (rate->value == 11) ? (totlen * 16) + 10 : + ((rate->value == 22) ? (totlen * 8) + 10 : (totlen * 8)); desc->plcp_length = htole16(bits / ratediv[phy]); desc->plcp_service = 0; - if (rate == 22 && (bits % 11) > 0 && (bits % 11) <= 3) + if (rate->value == 22 && (bits % 11) > 0 && (bits % 11) <= 3) desc->plcp_service |= ZYD_PLCP_LENGEXT; desc->nextlen = 0; @@ -2537,15 +2541,15 @@ struct zyd_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = 0; - tap->wt_rate = rate; + tap->wt_rate = rate->value; ieee80211_radiotap_tx(vap, m0); } DPRINTF(sc, ZYD_DEBUG_XMIT, - "%s: sending data frame len=%zu rate=%u\n", + "%s: sending data frame len=%zu rate=%u/%u\n", device_get_nameunit(sc->sc_dev), (size_t)m0->m_pkthdr.len, - rate); + rate->type, rate->value); STAILQ_INSERT_TAIL(&sc->tx_q, data, next); usbd_transfer_start(sc->sc_xfer[ZYD_BULK_WR]); Index: sys/dev/usb/wlan/if_zydreg.h =================================================================== --- sys/dev/usb/wlan/if_zydreg.h +++ sys/dev/usb/wlan/if_zydreg.h @@ -1153,9 +1153,6 @@ #define ZYD_CMD_FLAG_READ (1 << 0) #define ZYD_CMD_FLAG_SENT (1 << 1) -/* quickly determine if a given rate is CCK or OFDM */ -#define ZYD_RATE_IS_OFDM(rate) ((rate) >= 12 && (rate) != 22) - struct zyd_phy_pair { uint16_t reg; uint8_t val; Index: sys/dev/wi/if_wi.c =================================================================== --- sys/dev/wi/if_wi.c +++ sys/dev/wi/if_wi.c @@ -138,6 +138,8 @@ static void wi_info_intr(struct wi_softc *); +static uint16_t lucent_idx2hw_rate(uint16_t); +static uint16_t intersil_idx2hw_rate(uint16_t); static int wi_write_txrate(struct wi_softc *, struct ieee80211vap *); static int wi_write_wep(struct wi_softc *, struct ieee80211vap *); static int wi_write_multi(struct wi_softc *); @@ -236,12 +238,13 @@ int wi_attach(device_t dev) { + struct ieee80211_rate_t rate; struct wi_softc *sc = device_get_softc(dev); struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_rateset *rs; int i, nrates, buflen; - u_int16_t val; + u_int16_t val, rate_idx; u_int8_t ratebuf[2 + IEEE80211_RATE_SIZE]; - struct ieee80211_rateset *rs; struct sysctl_ctx_list *sctx; struct sysctl_oid *soid; static const u_int8_t empty_macaddr[IEEE80211_ADDR_LEN] = { @@ -403,15 +406,28 @@ /* Find supported rates. */ buflen = sizeof(ratebuf); - rs = &ic->ic_sup_rates[IEEE80211_MODE_11B]; if (wi_read_rid(sc, WI_RID_DATA_RATES, ratebuf, &buflen) == 0) { + rs = &sc->sc_supp_rates; + rate.type = IEEE80211_T_CCK; + nrates = le16toh(*(u_int16_t *)ratebuf); - if (nrates > IEEE80211_RATE_MAXSIZE) - nrates = IEEE80211_RATE_MAXSIZE; + if (nrates > nitems(rs->rates)) + nrates = nitems(rs->rates); rs->rs_nrates = 0; - for (i = 0; i < nrates; i++) - if (ratebuf[2+i]) - rs->rs_rates[rs->rs_nrates++] = ratebuf[2+i]; + for (i = 0; i < nrates; i++) { + if (ratebuf[2 + i] == 0 || + ratebuf[2 + i] >= IEEE80211_RATE_VALUE_MAX) + continue; + + rate.value = ratebuf[2 + i]; + rate_idx = ieee80211_get_rate_index_no_check(&rate); + if (rate_idx == IEEE80211_RATE_NONEXISTENT) + continue; + + rs->rates[rs->rs_nrates++].rs_index = rate_idx; + } + + ic->ic_sup_rates[IEEE80211_MODE_11B] = rs; } else { /* XXX fallback on error? */ } @@ -931,7 +947,9 @@ static void wi_start(struct wi_softc *sc) { + const struct ieee80211_rate_t *rate; struct ieee80211_node *ni; + struct ieee80211vap *vap; struct ieee80211_frame *wh; struct mbuf *m0; struct ieee80211_key *k; @@ -949,6 +967,7 @@ while (sc->sc_txd[cur].d_len == 0 && (m0 = mbufq_dequeue(&sc->sc_snd)) != NULL) { ni = (struct ieee80211_node *) m0->m_pkthdr.rcvif; + vap = ni->ni_vap; /* reconstruct 802.3 header */ wh = mtod(m0, struct ieee80211_frame *); @@ -986,9 +1005,10 @@ frmhdr.wi_tx_ctl |= htole16(WI_TXCNTL_NOCRYPT); } - if (ieee80211_radiotap_active_vap(ni->ni_vap)) { - sc->sc_tx_th.wt_rate = ni->ni_txrate; - ieee80211_radiotap_tx(ni->ni_vap, m0); + if (ieee80211_radiotap_active_vap(vap)) { + rate = ieee80211_get_rate(ni->ni_txrate); + sc->sc_tx_th.wt_rate = rate->value; + ieee80211_radiotap_tx(vap, m0); } m_copydata(m0, 0, sizeof(struct ieee80211_frame), @@ -1034,6 +1054,7 @@ wi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m0, const struct ieee80211_bpf_params *params) { + const struct ieee80211_rate_t *rate; struct ieee80211com *ic = ni->ni_ic; struct ieee80211vap *vap = ni->ni_vap; struct wi_softc *sc = ic->ic_softc; @@ -1075,7 +1096,8 @@ frmhdr.wi_tx_ctl |= htole16(WI_TXCNTL_NOCRYPT); } if (ieee80211_radiotap_active_vap(vap)) { - sc->sc_tx_th.wt_rate = ni->ni_txrate; + rate = ieee80211_get_rate(ni->ni_txrate); + sc->sc_tx_th.wt_rate = rate->value; ieee80211_radiotap_tx(vap, m0); } m_copydata(m0, 0, sizeof(struct ieee80211_frame), @@ -1189,29 +1211,37 @@ static void wi_media_status(struct ifnet *ifp, struct ifmediareq *imr) { + struct ieee80211_rate_t rate; struct ieee80211vap *vap = ifp->if_softc; struct ieee80211com *ic = vap->iv_ic; struct wi_softc *sc = ic->ic_softc; - u_int16_t val; - int rate, len; + u_int16_t val, rate_idx; + int len; len = sizeof(val); if (sc->sc_enabled && wi_read_rid(sc, WI_RID_CUR_TX_RATE, &val, &len) == 0 && len == sizeof(val)) { + rate.type = IEEE80211_T_CCK; + /* convert to 802.11 rate */ val = le16toh(val); - rate = val * 2; + rate.value = val * 2; if (sc->sc_firmware_type == WI_LUCENT) { - if (rate == 10) - rate = 11; /* 5.5Mbps */ + if (rate.value == 10) + rate.value = 11; /* 5.5Mbps */ } else { - if (rate == 4*2) - rate = 11; /* 5.5Mbps */ - else if (rate == 8*2) - rate = 22; /* 11Mbps */ + if (rate.value == 4*2) + rate.value = 11; /* 5.5Mbps */ + else if (rate.value == 8*2) + rate.value = 22; /* 11Mbps */ } - vap->iv_bss->ni_txrate = rate; + + if (rate.value < IEEE80211_RATE_VALUE_MAX) { + rate_idx = ieee80211_get_rate_index_no_check(&rate); + if (rate_idx != IEEE80211_RATE_NONEXISTENT) + vap->iv_bss->ni_txrate = rate_idx; + } } ieee80211_media_status(ifp, imr); } @@ -1656,32 +1686,46 @@ return wi_write_rid(sc, rid, &ssid, sizeof(ssid)); } +static uint16_t +lucent_idx2hw_rate(uint16_t rate_idx) +{ + + switch (rate_idx) { + case IEEE80211_RATE_INDEX_CCK1: return (1); + case IEEE80211_RATE_INDEX_CCK2: return (2); + case IEEE80211_RATE_INDEX_CCK5: return (4); + case IEEE80211_RATE_INDEX_CCK11: return (5); + default: return (3); /* auto */ + } +} + +static uint16_t +intersil_idx2hw_rate(uint16_t rate_idx) +{ + + switch (rate_idx) { + case IEEE80211_RATE_INDEX_CCK1: return (0); + case IEEE80211_RATE_INDEX_CCK2: return (1); + case IEEE80211_RATE_INDEX_CCK5: return (2); + case IEEE80211_RATE_INDEX_CCK11: return (3); + default: return (0xf); /* auto */ + } +} + static int wi_write_txrate(struct wi_softc *sc, struct ieee80211vap *vap) { - static const uint16_t lucent_rates[12] = { - [ 0] = 3, /* auto */ - [ 1] = 1, /* 1Mb/s */ - [ 2] = 2, /* 2Mb/s */ - [ 5] = 4, /* 5.5Mb/s */ - [11] = 5 /* 11Mb/s */ - }; - static const uint16_t intersil_rates[12] = { - [ 0] = 0xf, /* auto */ - [ 1] = 0, /* 1Mb/s */ - [ 2] = 1, /* 2Mb/s */ - [ 5] = 2, /* 5.5Mb/s */ - [11] = 3, /* 11Mb/s */ - }; - const uint16_t *rates = sc->sc_firmware_type == WI_LUCENT ? - lucent_rates : intersil_rates; struct ieee80211com *ic = vap->iv_ic; - const struct ieee80211_txparam *tp; + const struct ieee80211_txparam_vht *tp; + uint16_t val; tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_bsschan)]; - return wi_write_val(sc, WI_RID_TX_RATE, - (tp->ucastrate == IEEE80211_FIXED_RATE_NONE ? - rates[0] : rates[tp->ucastrate / 2])); + if (sc->sc_firmware_type == WI_LUCENT) + val = lucent_idx2hw_rate(tp->ucastrate); + else + val = intersil_idx2hw_rate(tp->ucastrate); + + return (wi_write_val(sc, WI_RID_TX_RATE, val)); } static int Index: sys/dev/wi/if_wivar.h =================================================================== --- sys/dev/wi/if_wivar.h +++ sys/dev/wi/if_wivar.h @@ -142,6 +142,7 @@ u_int16_t sc_txbuf[IEEE80211_MAX_LEN/2]; + struct ieee80211_rateset sc_supp_rates; struct wi_tx_radiotap_header sc_tx_th; struct wi_rx_radiotap_header sc_rx_th; }; Index: sys/dev/wpi/if_wpi.c =================================================================== --- sys/dev/wpi/if_wpi.c +++ sys/dev/wpi/if_wpi.c @@ -1902,9 +1902,6 @@ } } -/* Quickly determine if a given rate is CCK or OFDM. */ -#define WPI_RATE_IS_OFDM(rate) ((rate) >= 12 && (rate) != 22) - static void wpi_rx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc, struct wpi_rx_data *data) @@ -2784,7 +2781,8 @@ static int wpi_tx_data(struct wpi_softc *sc, struct mbuf *m, struct ieee80211_node *ni) { - const struct ieee80211_txparam *tp = ni->ni_txparms; + const struct ieee80211_rate_t *rate; + const struct ieee80211_txparam_vht *tp = ni->ni_txparms; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; struct wpi_node *wn = WPI_NODE(ni); @@ -2793,8 +2791,8 @@ struct wpi_buf tx_data; struct wpi_cmd_data *tx = (struct wpi_cmd_data *)&tx_data.data; uint32_t flags; - uint16_t ac, qos; - uint8_t tid, type, rate; + uint16_t ac, qos, rate_idx; + uint8_t tid, type; int swcrypt, ismcast, totlen; wh = mtod(m, struct ieee80211_frame *); @@ -2816,17 +2814,22 @@ if (type == IEEE80211_FC0_TYPE_MGT || type == IEEE80211_FC0_TYPE_CTL || (m->m_flags & M_EAPOL) != 0) - rate = tp->mgmtrate; + rate_idx = tp->mgmtrate; else if (ismcast) - rate = tp->mcastrate; - else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) - rate = tp->ucastrate; + rate_idx = tp->mcastrate; + else if (tp->ucastrate != IEEE80211_RATE_NONEXISTENT) + rate_idx = tp->ucastrate; else { /* XXX pass pktlen */ (void) ieee80211_ratectl_rate(ni, NULL, 0); - rate = ni->ni_txrate; + rate_idx = ni->ni_txrate; } + rate = ieee80211_get_rate(rate_idx); + KASSERT(rate->type == IEEE80211_T_CCK || + rate->type == IEEE80211_T_OFDM, ("unsupported rate type %u\n", + rate->type)); + /* Encrypt the frame if need be. */ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { /* Retrieve key for TX. */ @@ -2845,7 +2848,7 @@ struct wpi_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = 0; - tap->wt_rate = rate; + tap->wt_rate = rate->value; if (k != NULL) tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG) @@ -2873,7 +2876,7 @@ if (totlen + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) { flags |= WPI_TX_NEED_RTS; } else if ((ic->ic_flags & IEEE80211_F_USEPROT) && - WPI_RATE_IS_OFDM(rate)) { + rate->type == IEEE80211_T_OFDM) { if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) flags |= WPI_TX_NEED_CTS; else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) @@ -2934,7 +2937,7 @@ tx->len = htole16(totlen); tx->flags = htole32(flags); - tx->plcp = rate2plcp(rate); + tx->plcp = rate2plcp(rate->value); tx->tid = tid; tx->lifetime = htole32(WPI_LIFETIME_INFINITE); tx->ofdm_mask = 0xff; @@ -2955,13 +2958,14 @@ wpi_tx_data_raw(struct wpi_softc *sc, struct mbuf *m, struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) { + const struct ieee80211_rate_t *rate; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_key *k = NULL; struct ieee80211_frame *wh; struct wpi_buf tx_data; struct wpi_cmd_data *tx = (struct wpi_cmd_data *)&tx_data.data; uint32_t flags; - uint8_t ac, type, rate; + uint8_t ac, type; int swcrypt, totlen; wh = mtod(m, struct ieee80211_frame *); @@ -2970,8 +2974,8 @@ ac = params->ibp_pri & 3; - /* Choose a TX rate index. */ - rate = params->ibp_rate0; + /* Choose a TX rate. */ + rate = ieee80211_get_rate(params->ibp_rate0); flags = 0; if (!IEEE80211_QOS_HAS_SEQ(wh)) @@ -3003,7 +3007,7 @@ struct wpi_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = 0; - tap->wt_rate = rate; + tap->wt_rate = rate->value; if (params->ibp_flags & IEEE80211_BPF_CRYPTO) tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; @@ -3039,7 +3043,7 @@ tx->len = htole16(totlen); tx->flags = htole32(flags); - tx->plcp = rate2plcp(rate); + tx->plcp = rate2plcp(rate->value); tx->id = WPI_ID_BROADCAST; tx->lifetime = htole32(WPI_LIFETIME_INFINITE); tx->rts_ntries = params->ibp_try1; @@ -4090,6 +4094,7 @@ static int wpi_scan(struct wpi_softc *sc, struct ieee80211_channel *c) { + const struct ieee80211_rateset *rs; struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_scan_state *ss = ic->ic_scan; struct ieee80211vap *vap = ss->ss_vap; @@ -4098,7 +4103,6 @@ struct wpi_scan_essid *essids; struct wpi_scan_chan *chan; struct ieee80211_frame *wh; - struct ieee80211_rateset *rs; uint16_t bintval, buflen, dwell_active, dwell_passive; uint8_t *buf, *frm, i, nssid; int bgscan, error; @@ -4161,12 +4165,12 @@ if (IEEE80211_IS_CHAN_5GHZ(c)) { /* Send probe requests at 6Mbps. */ tx->plcp = wpi_ridx_to_plcp[WPI_RIDX_OFDM6]; - rs = &ic->ic_sup_rates[IEEE80211_MODE_11A]; + rs = ic->ic_sup_rates[IEEE80211_MODE_11A]; } else { hdr->flags = htole32(WPI_RXON_24GHZ | WPI_RXON_AUTO); /* Send probe requests at 1Mbps. */ tx->plcp = wpi_ridx_to_plcp[WPI_RIDX_CCK1]; - rs = &ic->ic_sup_rates[IEEE80211_MODE_11G]; + rs = ic->ic_sup_rates[IEEE80211_MODE_11G]; } essids = (struct wpi_scan_essid *)(tx + 1); Index: sys/net80211/_ieee80211.h =================================================================== --- sys/net80211/_ieee80211.h +++ sys/net80211/_ieee80211.h @@ -41,6 +41,7 @@ */ enum ieee80211_phytype { IEEE80211_T_DS, /* direct sequence spread spectrum */ + IEEE80211_T_PBCC, /* packet binary convolutional code */ IEEE80211_T_FH, /* frequency hopping */ IEEE80211_T_OFDM, /* frequency division multiplexing */ IEEE80211_T_TURBO, /* high rate OFDM, aka turbo mode */ @@ -50,6 +51,7 @@ IEEE80211_T_VHT, /* VHT PHY */ }; #define IEEE80211_T_CCK IEEE80211_T_DS /* more common nomenclature */ +#define IEEE80211_T_MAX (IEEE80211_T_VHT + 1) /* * PHY mode; this is not really a mode as multi-mode devices @@ -376,28 +378,65 @@ #define IEEE80211_AID_DEF 128 #define IEEE80211_AID_MIN 16 +struct ieee80211_rate_t { + uint8_t type; + uint8_t value; + + union { + struct { + uint8_t short_preamble; + } cck; + struct { + uint8_t streams; + uint8_t no_20mhz:1, + no_40mhz:1, + no_80mhz:1, + no_160mhz:1, + unequal:1; + } ht; + } props; +}; + + /* * 802.11 rate set. */ -#define IEEE80211_RATE_SIZE 8 /* 802.11 standard */ -#define IEEE80211_RATE_MAXSIZE 15 /* max rates we'll handle */ +#define IEEE80211_RATE_SIZE 8 /* 802.11 standard */ +#define IEEE80211_RATE_MAXSIZE 15 /* max rates we'll handle */ +#define IEEE80211_RATE_VALUE_MAX 128 +#define IEEE80211_RATE_BITMAP_SIZE howmany(IEEE80211_RATE_VALUE_MAX, NBBY) + +#define IEEE80211_HT_MCS_CHAIN 8 +#define IEEE80211_VHT_MCS_CHAIN 10 + + struct ieee80211_rateset { - uint8_t rs_nrates; - uint8_t rs_rates[IEEE80211_RATE_MAXSIZE]; + uint8_t rs_nrates; + uint8_t rs_bitmap[IEEE80211_RATE_BITMAP_SIZE]; + + struct { + uint16_t rs_index; /* index in the global table */ + uint8_t rs_basic:1; + } rates[IEEE80211_RATE_MAXSIZE]; }; /* - * 802.11n variant of ieee80211_rateset. Instead of + * 802.11n/ac variant of ieee80211_rateset. Instead of * legacy rates the entries are MCS rates. We define * the structure such that it can be used interchangeably * with an ieee80211_rateset (modulo structure size). */ -#define IEEE80211_HTRATE_MAXSIZE 77 +#define IEEE80211_HTRATE_MAXSIZE 80 /* count of VHT rates */ struct ieee80211_htrateset { uint8_t rs_nrates; - uint8_t rs_rates[IEEE80211_HTRATE_MAXSIZE]; + uint8_t rs_bitmap[IEEE80211_RATE_BITMAP_SIZE]; + + struct { + uint16_t rs_index; /* index in the global table */ + uint8_t rs_basic:1; + } rates[IEEE80211_HTRATE_MAXSIZE]; }; #define IEEE80211_RATE_MCS 0x80 @@ -407,23 +446,40 @@ * These can be used to set fixed transmit rate for all operating * modes or on a per-client basis according to the capabilities * of the client (e.g. an 11b client associated to an 11g ap). - * - * MCS are distinguished from legacy rates by or'ing in 0x80. */ -struct ieee80211_txparam { - uint8_t ucastrate; /* ucast data rate (legacy/MCS|0x80) */ - uint8_t mgmtrate; /* mgmt frame rate (legacy/MCS|0x80) */ - uint8_t mcastrate; /* multicast rate (legacy/MCS|0x80) */ +struct ieee80211_txparam_vht { + uint16_t ucastrate; /* ucast data rate index */ + uint16_t mgmtrate; /* mgmt frame rate index */ + uint16_t mcastrate; /* multicast rate index */ uint8_t maxretry; /* max unicast data retry count */ }; /* + * Legacy version (w/ MCS/0x80 bits and without VHT support). + */ +struct ieee80211_txparam { + uint8_t ucastrate; + uint8_t mgmtrate; + uint8_t mcastrate; + uint8_t maxretry; +}; + +/* * Per-mode roaming state visible to user space. There are two * thresholds that control whether roaming is considered; when * either is exceeded the 802.11 layer will check the scan cache * for another AP. If the cache is stale then a scan may be * triggered. */ +struct ieee80211_roamparam_vht { + int8_t rssi; /* rssi thresh (.5 dBm) */ + uint8_t pad; /* reserve */ + uint16_t rate; /* tx rate index thresh */ +}; + +/* + * Legacy version (w/ MCS/0x80 bits and without VHT support). + */ struct ieee80211_roamparam { int8_t rssi; /* rssi thresh (.5 dBm) */ uint8_t rate; /* tx rate thresh (.5 Mb/s or MCS) */ @@ -600,6 +656,7 @@ uint8_t c_nf; /* global NF */ uint8_t c_rssi; /* global RSSI */ uint8_t c_chain; /* number of RX chains involved */ + /* XXX use rate index instead */ uint8_t c_rate; /* legacy; 11n rate code; VHT MCS */ /* 32 bits */ Index: sys/net80211/ieee80211.c =================================================================== --- sys/net80211/ieee80211.c +++ sys/net80211/ieee80211.c @@ -105,25 +105,10 @@ MALLOC_DEFINE(M_80211_VAP, "80211vap", "802.11 vap state"); -/* - * Default supported rates for 802.11 operation (in IEEE .5Mb units). - */ -#define B(r) ((r) | IEEE80211_RATE_BASIC) -static const struct ieee80211_rateset ieee80211_rateset_11a = - { 8, { B(12), 18, B(24), 36, B(48), 72, 96, 108 } }; -static const struct ieee80211_rateset ieee80211_rateset_half = - { 8, { B(6), 9, B(12), 18, B(24), 36, 48, 54 } }; -static const struct ieee80211_rateset ieee80211_rateset_quarter = - { 8, { B(3), 4, B(6), 9, B(12), 18, 24, 27 } }; -static const struct ieee80211_rateset ieee80211_rateset_11b = - { 4, { B(2), B(4), B(11), B(22) } }; -/* NB: OFDM rates are handled specially based on mode */ -static const struct ieee80211_rateset ieee80211_rateset_11g = - { 12, { B(2), B(4), B(11), B(22), 12, 18, 24, 36, 48, 72, 96, 108 } }; -#undef B - static int set_vht_extchan(struct ieee80211_channel *c); +static const struct ieee80211_rateset null_rateset; + /* * Fill in 802.11 available channel set, mark * all available channels as active, and pick @@ -132,10 +117,6 @@ void ieee80211_chan_init(struct ieee80211com *ic) { -#define DEFAULTRATES(m, def) do { \ - if (ic->ic_sup_rates[m].rs_nrates == 0) \ - ic->ic_sup_rates[m] = def; \ -} while (0) struct ieee80211_channel *c; int i; @@ -219,22 +200,21 @@ ic->ic_csa_newchan = NULL; /* arbitrarily pick the first channel */ ic->ic_curchan = &ic->ic_channels[0]; - ic->ic_rt = ieee80211_get_ratetable(ic->ic_curchan); + ic->ic_rt = + ieee80211_get_ratetable(ieee80211_chan2mode(ic->ic_curchan)); /* fillin well-known rate sets if driver has not specified */ - DEFAULTRATES(IEEE80211_MODE_11B, ieee80211_rateset_11b); - DEFAULTRATES(IEEE80211_MODE_11G, ieee80211_rateset_11g); - DEFAULTRATES(IEEE80211_MODE_11A, ieee80211_rateset_11a); - DEFAULTRATES(IEEE80211_MODE_TURBO_A, ieee80211_rateset_11a); - DEFAULTRATES(IEEE80211_MODE_TURBO_G, ieee80211_rateset_11g); - DEFAULTRATES(IEEE80211_MODE_STURBO_A, ieee80211_rateset_11a); - DEFAULTRATES(IEEE80211_MODE_HALF, ieee80211_rateset_half); - DEFAULTRATES(IEEE80211_MODE_QUARTER, ieee80211_rateset_quarter); - DEFAULTRATES(IEEE80211_MODE_11NA, ieee80211_rateset_11a); - DEFAULTRATES(IEEE80211_MODE_11NG, ieee80211_rateset_11g); - DEFAULTRATES(IEEE80211_MODE_VHT_2GHZ, ieee80211_rateset_11g); - DEFAULTRATES(IEEE80211_MODE_VHT_5GHZ, ieee80211_rateset_11a); + /* NB: skip AUTO mode */ + for (i = IEEE80211_MODE_AUTO + 1; i < IEEE80211_MODE_MAX; i++) { + if (ic->ic_sup_rates[i] != NULL) + continue; + if (isset(ic->ic_modecaps, i)) + ic->ic_sup_rates[i] = ieee80211_get_def_rateset(i); + else + ic->ic_sup_rates[i] = &null_rateset; + } + /* * Setup required information to fill the mcsset field, if driver did * not. Assume a 2T2R setup for historic reasons. @@ -249,8 +229,7 @@ /* * Set auto mode to reset active channel state and any desired channel. */ - (void) ieee80211_setmode(ic, IEEE80211_MODE_AUTO); -#undef DEFAULTRATES + ieee80211_setmode(ic, IEEE80211_MODE_AUTO); } static void @@ -1805,29 +1784,37 @@ struct ifmedia *media, int caps, int addsta, ifm_change_cb_t media_change, ifm_stat_cb_t media_stat) { - int i, j, rate, maxrate, mword, r; - enum ieee80211_phymode mode; +#define MAX_RATES 24 const struct ieee80211_rateset *rs; - struct ieee80211_rateset allrates; + const struct ieee80211_rate_t *rate; + enum ieee80211_phymode mode; + uint16_t rate_idx; + uint8_t allrates[MAX_RATES]; /* NB: rateset may be too small */ + uint8_t rate_mask[IEEE80211_RATE_BITMAP_SIZE]; + uint8_t value; + int i, maxrate, mword, rates_count; /* * Fill in media characteristics. */ ifmedia_init(media, 0, media_change, media_stat); maxrate = 0; + rates_count = 0; /* * Add media for legacy operating modes. */ memset(&allrates, 0, sizeof(allrates)); + memset(rate_mask, 0, sizeof(rate_mask)); for (mode = IEEE80211_MODE_AUTO; mode < IEEE80211_MODE_11NA; mode++) { if (isclr(ic->ic_modecaps, mode)) continue; addmedia(media, caps, addsta, mode, IFM_AUTO); if (mode == IEEE80211_MODE_AUTO) continue; - rs = &ic->ic_sup_rates[mode]; + rs = ic->ic_sup_rates[mode]; for (i = 0; i < rs->rs_nrates; i++) { - rate = rs->rs_rates[i]; + rate_idx = rs->rates[i].rs_index; + rate = ieee80211_get_rate(rate_idx); mword = ieee80211_rate2media(ic, rate, mode); if (mword == 0) continue; @@ -1835,23 +1822,21 @@ /* * Add legacy rate to the collection of all rates. */ - r = rate & IEEE80211_RATE_VAL; - for (j = 0; j < allrates.rs_nrates; j++) - if (allrates.rs_rates[j] == r) - break; - if (j == allrates.rs_nrates) { + value = rate->value; + KASSERT(value < IEEE80211_RATE_VALUE_MAX, + ("increase RATE_VALUE_MAX constant")); + if (!isset(rate_mask, value)) { /* unique, add to the set */ - allrates.rs_rates[j] = r; - allrates.rs_nrates++; + setbit(rate_mask, value); + allrates[rates_count++] = rate_idx; } - rate = (rate & IEEE80211_RATE_VAL) / 2; - if (rate > maxrate) - maxrate = rate; + if (value > maxrate) + maxrate = value; } } - for (i = 0; i < allrates.rs_nrates; i++) { - mword = ieee80211_rate2media(ic, allrates.rs_rates[i], - IEEE80211_MODE_AUTO); + for (i = 0; i < rates_count; i++) { + rate = ieee80211_get_rate(allrates[i]); + mword = ieee80211_rate2media(ic, rate, IEEE80211_MODE_AUTO); if (mword == 0) continue; /* NB: remove media options from mword */ @@ -1872,20 +1857,28 @@ } if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA) || isset(ic->ic_modecaps, IEEE80211_MODE_11NG)) { + uint32_t chan_flags; + int sgi; + addmedia(media, caps, addsta, IEEE80211_MODE_AUTO, IFM_IEEE80211_MCS); - i = ic->ic_txstream * 8 - 1; - if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) && - (ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40)) - rate = ieee80211_htrates[i].ht40_rate_400ns; - else if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40)) - rate = ieee80211_htrates[i].ht40_rate_800ns; - else if ((ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20)) - rate = ieee80211_htrates[i].ht20_rate_400ns; - else - rate = ieee80211_htrates[i].ht20_rate_800ns; - if (rate > maxrate) - maxrate = rate; + + rate_idx = IEEE80211_RATE_INDEX_HT( + ic->ic_txstream * IEEE80211_HT_MCS_CHAIN - 1); + + if (ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) { + chan_flags = IEEE80211_CHAN_HT40; + sgi = (ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40) != 0; + } else { + chan_flags = IEEE80211_CHAN_HT20; + sgi = (ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20) != 0; + } + + value = ieee80211_get_rateKbps_by_idx(rate_idx, + chan_flags, sgi); + value /= 500; + if (value > maxrate) + maxrate = value; } /* @@ -1896,49 +1889,75 @@ continue; addmedia(media, caps, addsta, mode, IFM_AUTO); addmedia(media, caps, addsta, mode, IFM_IEEE80211_VHT); + } + if (isset(ic->ic_modecaps, IEEE80211_MODE_VHT_2GHZ) || + isset(ic->ic_modecaps, IEEE80211_MODE_VHT_5GHZ)) { + uint32_t chan_flags; + uint8_t vht_chan_cap; + int sgi; - /* XXX TODO: VHT maxrate */ + addmedia(media, caps, addsta, + IEEE80211_MODE_AUTO, IFM_IEEE80211_VHT); + + /* XXX assume only MCS7 for now */ + rate_idx = IEEE80211_RATE_INDEX_VHT(7, ic->ic_txstream); + + /* XXX create / move to ieee80211_vht_get_max_mcs() */ + /* XXX should check vap caps instead */ + vht_chan_cap = + (ic->ic_vhtcaps & IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_MASK); + vht_chan_cap >>= IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_MASK_S; + + if (vht_chan_cap >= IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_160MHZ) { + chan_flags = IEEE80211_CHAN_VHT160; + + sgi = (ic->ic_vhtcaps & IEEE80211_VHTCAP_SHORT_GI_160); + sgi >>= IEEE80211_VHTCAP_SHORT_GI_160_S; + } else if (vht_chan_cap == + IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_160_80P80MHZ) { + chan_flags = IEEE80211_CHAN_VHT80_80; + + sgi = (ic->ic_vhtcaps & IEEE80211_VHTCAP_SHORT_GI_80); + sgi >>= IEEE80211_VHTCAP_SHORT_GI_80_S; + } else { + chan_flags = IEEE80211_CHAN_VHT80; + + /* XXX unknown (has no capability bits yet). */ + sgi = 0; + } + + value = ieee80211_get_rateKbps_by_idx(rate_idx, + chan_flags, sgi); + value /= 500; + if (value > maxrate) + maxrate = value; } return maxrate; +#undef MAX_RATES } -/* XXX inline or eliminate? */ -const struct ieee80211_rateset * -ieee80211_get_suprates(struct ieee80211com *ic, const struct ieee80211_channel *c) -{ - /* XXX does this work for 11ng basic rates? */ - return &ic->ic_sup_rates[ieee80211_chan2mode(c)]; -} - -/* XXX inline or eliminate? */ -const struct ieee80211_htrateset * -ieee80211_get_suphtrates(struct ieee80211com *ic, - const struct ieee80211_channel *c) -{ - return &ic->ic_sup_htrates; -} - void ieee80211_announce(struct ieee80211com *ic) { - int i, rate, mword; - enum ieee80211_phymode mode; const struct ieee80211_rateset *rs; + const struct ieee80211_rate_t *rate; + enum ieee80211_phymode mode; + uint32_t speed; + int i; /* NB: skip AUTO since it has no rates */ for (mode = IEEE80211_MODE_AUTO+1; mode < IEEE80211_MODE_11NA; mode++) { if (isclr(ic->ic_modecaps, mode)) continue; ic_printf(ic, "%s rates: ", ieee80211_phymode_name[mode]); - rs = &ic->ic_sup_rates[mode]; + rs = ic->ic_sup_rates[mode]; for (i = 0; i < rs->rs_nrates; i++) { - mword = ieee80211_rate2media(ic, rs->rs_rates[i], mode); - if (mword == 0) - continue; - rate = ieee80211_media2rate(mword); + rate = ieee80211_get_rate(rs->rates[i].rs_index); + speed = ieee80211_get_rateKbps(rate, 0, 0); + speed /= 500; printf("%s%d%sMbps", (i != 0 ? " " : ""), - rate / 2, ((rate & 0x1) != 0 ? ".5" : "")); + speed / 2, ((speed & 0x1) != 0 ? ".5" : "")); } printf("\n"); } @@ -2119,6 +2138,7 @@ void ieee80211_media_status(struct ifnet *ifp, struct ifmediareq *imr) { + const struct ieee80211_rate_t *rate; struct ieee80211vap *vap = ifp->if_softc; struct ieee80211com *ic = vap->iv_ic; enum ieee80211_phymode mode; @@ -2139,18 +2159,18 @@ /* * Calculate a current rate if possible. */ - if (vap->iv_txparms[mode].ucastrate != IEEE80211_FIXED_RATE_NONE) { + if (vap->iv_txparms[mode].ucastrate != IEEE80211_RATE_NONEXISTENT) { /* * A fixed rate is set, report that. */ - imr->ifm_active |= ieee80211_rate2media(ic, - vap->iv_txparms[mode].ucastrate, mode); + rate = ieee80211_get_rate(vap->iv_txparms[mode].ucastrate); + imr->ifm_active |= ieee80211_rate2media(ic, rate, mode); } else if (vap->iv_opmode == IEEE80211_M_STA) { /* * In station mode report the current transmit rate. */ - imr->ifm_active |= ieee80211_rate2media(ic, - vap->iv_bss->ni_txrate, mode); + rate = ieee80211_get_rate(vap->iv_bss->ni_txrate); + imr->ifm_active |= ieee80211_rate2media(ic, rate, mode); } else imr->ifm_active |= IFM_AUTO; if (imr->ifm_status & IFM_ACTIVE) @@ -2163,22 +2183,11 @@ * select a new default/current channel if the current one is * inappropriate for this mode. */ -int +void ieee80211_setmode(struct ieee80211com *ic, enum ieee80211_phymode mode) { - /* - * Adjust basic rates in 11b/11g supported rate set. - * Note that if operating on a hal/quarter rate channel - * this is a noop as those rates sets are different - * and used instead. - */ - if (mode == IEEE80211_MODE_11G || mode == IEEE80211_MODE_11B) - ieee80211_setbasicrates(&ic->ic_sup_rates[mode], mode); - ic->ic_curmode = mode; ieee80211_reset_erp(ic); /* reset ERP state */ - - return 0; } /* @@ -2221,196 +2230,154 @@ return IEEE80211_MODE_11B; } -struct ratemedia { - u_int match; /* rate + mode */ - u_int media; /* if_media rate */ +static const u_int rates_fh[] = { + [2] = IFM_IEEE80211_FH1, + [4] = IFM_IEEE80211_FH2 }; -static int -findmedia(const struct ratemedia rates[], int n, u_int match) +static const u_int rates_11b[] = { + [2] = IFM_IEEE80211_DS1, + [4] = IFM_IEEE80211_DS2, + [11] = IFM_IEEE80211_DS5, + [22] = IFM_IEEE80211_DS11, + [44] = IFM_IEEE80211_DS22 +}; + +static const u_int rates_11a[] = { + [6] = IFM_IEEE80211_OFDM3, + [9] = IFM_IEEE80211_OFDM4, + [12] = IFM_IEEE80211_OFDM6, + [18] = IFM_IEEE80211_OFDM9, + [24] = IFM_IEEE80211_OFDM12, + [36] = IFM_IEEE80211_OFDM18, + [48] = IFM_IEEE80211_OFDM24, + [54] = IFM_IEEE80211_OFDM27, + [72] = IFM_IEEE80211_OFDM36, + [96] = IFM_IEEE80211_OFDM48, + [108] = IFM_IEEE80211_OFDM54, + /* NB: OFDM72 doesn't really exist so we don't handle it */ +}; + +/* assumed throughout the file */ +_Static_assert(IFM_AUTO == 0, + "set initial values for ratemedia structures manually"); + +static __inline int +findmedia(const u_int rates[], int n, uint8_t value) { - int i; - for (i = 0; i < n; i++) - if (rates[i].match == match) - return rates[i].media; - return IFM_AUTO; + if (__predict_false(value >= n)) + return (IFM_AUTO); + + return (rates[value]); } /* * Convert IEEE80211 rate value to ifmedia subtype. - * Rate is either a legacy rate in units of 0.5Mbps - * or an MCS index. */ int -ieee80211_rate2media(struct ieee80211com *ic, int rate, enum ieee80211_phymode mode) +ieee80211_rate2media(struct ieee80211com *ic, + const struct ieee80211_rate_t *rate, enum ieee80211_phymode mode) { - static const struct ratemedia rates[] = { - { 2 | IFM_IEEE80211_FH, IFM_IEEE80211_FH1 }, - { 4 | IFM_IEEE80211_FH, IFM_IEEE80211_FH2 }, - { 2 | IFM_IEEE80211_11B, IFM_IEEE80211_DS1 }, - { 4 | IFM_IEEE80211_11B, IFM_IEEE80211_DS2 }, - { 11 | IFM_IEEE80211_11B, IFM_IEEE80211_DS5 }, - { 22 | IFM_IEEE80211_11B, IFM_IEEE80211_DS11 }, - { 44 | IFM_IEEE80211_11B, IFM_IEEE80211_DS22 }, - { 12 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM6 }, - { 18 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM9 }, - { 24 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM12 }, - { 36 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM18 }, - { 48 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM24 }, - { 72 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM36 }, - { 96 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM48 }, - { 108 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM54 }, - { 2 | IFM_IEEE80211_11G, IFM_IEEE80211_DS1 }, - { 4 | IFM_IEEE80211_11G, IFM_IEEE80211_DS2 }, - { 11 | IFM_IEEE80211_11G, IFM_IEEE80211_DS5 }, - { 22 | IFM_IEEE80211_11G, IFM_IEEE80211_DS11 }, - { 12 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM6 }, - { 18 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM9 }, - { 24 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM12 }, - { 36 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM18 }, - { 48 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM24 }, - { 72 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM36 }, - { 96 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM48 }, - { 108 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM54 }, - { 6 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM3 }, - { 9 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM4 }, - { 54 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM27 }, - /* NB: OFDM72 doesn't really exist so we don't handle it */ - }; - static const struct ratemedia htrates[] = { - { 0, IFM_IEEE80211_MCS }, - { 1, IFM_IEEE80211_MCS }, - { 2, IFM_IEEE80211_MCS }, - { 3, IFM_IEEE80211_MCS }, - { 4, IFM_IEEE80211_MCS }, - { 5, IFM_IEEE80211_MCS }, - { 6, IFM_IEEE80211_MCS }, - { 7, IFM_IEEE80211_MCS }, - { 8, IFM_IEEE80211_MCS }, - { 9, IFM_IEEE80211_MCS }, - { 10, IFM_IEEE80211_MCS }, - { 11, IFM_IEEE80211_MCS }, - { 12, IFM_IEEE80211_MCS }, - { 13, IFM_IEEE80211_MCS }, - { 14, IFM_IEEE80211_MCS }, - { 15, IFM_IEEE80211_MCS }, - { 16, IFM_IEEE80211_MCS }, - { 17, IFM_IEEE80211_MCS }, - { 18, IFM_IEEE80211_MCS }, - { 19, IFM_IEEE80211_MCS }, - { 20, IFM_IEEE80211_MCS }, - { 21, IFM_IEEE80211_MCS }, - { 22, IFM_IEEE80211_MCS }, - { 23, IFM_IEEE80211_MCS }, - { 24, IFM_IEEE80211_MCS }, - { 25, IFM_IEEE80211_MCS }, - { 26, IFM_IEEE80211_MCS }, - { 27, IFM_IEEE80211_MCS }, - { 28, IFM_IEEE80211_MCS }, - { 29, IFM_IEEE80211_MCS }, - { 30, IFM_IEEE80211_MCS }, - { 31, IFM_IEEE80211_MCS }, - { 32, IFM_IEEE80211_MCS }, - { 33, IFM_IEEE80211_MCS }, - { 34, IFM_IEEE80211_MCS }, - { 35, IFM_IEEE80211_MCS }, - { 36, IFM_IEEE80211_MCS }, - { 37, IFM_IEEE80211_MCS }, - { 38, IFM_IEEE80211_MCS }, - { 39, IFM_IEEE80211_MCS }, - { 40, IFM_IEEE80211_MCS }, - { 41, IFM_IEEE80211_MCS }, - { 42, IFM_IEEE80211_MCS }, - { 43, IFM_IEEE80211_MCS }, - { 44, IFM_IEEE80211_MCS }, - { 45, IFM_IEEE80211_MCS }, - { 46, IFM_IEEE80211_MCS }, - { 47, IFM_IEEE80211_MCS }, - { 48, IFM_IEEE80211_MCS }, - { 49, IFM_IEEE80211_MCS }, - { 50, IFM_IEEE80211_MCS }, - { 51, IFM_IEEE80211_MCS }, - { 52, IFM_IEEE80211_MCS }, - { 53, IFM_IEEE80211_MCS }, - { 54, IFM_IEEE80211_MCS }, - { 55, IFM_IEEE80211_MCS }, - { 56, IFM_IEEE80211_MCS }, - { 57, IFM_IEEE80211_MCS }, - { 58, IFM_IEEE80211_MCS }, - { 59, IFM_IEEE80211_MCS }, - { 60, IFM_IEEE80211_MCS }, - { 61, IFM_IEEE80211_MCS }, - { 62, IFM_IEEE80211_MCS }, - { 63, IFM_IEEE80211_MCS }, - { 64, IFM_IEEE80211_MCS }, - { 65, IFM_IEEE80211_MCS }, - { 66, IFM_IEEE80211_MCS }, - { 67, IFM_IEEE80211_MCS }, - { 68, IFM_IEEE80211_MCS }, - { 69, IFM_IEEE80211_MCS }, - { 70, IFM_IEEE80211_MCS }, - { 71, IFM_IEEE80211_MCS }, - { 72, IFM_IEEE80211_MCS }, - { 73, IFM_IEEE80211_MCS }, - { 74, IFM_IEEE80211_MCS }, - { 75, IFM_IEEE80211_MCS }, - { 76, IFM_IEEE80211_MCS }, - }; - int m; +#define FINDMEDIA(_rates) \ + findmedia(_rates, nitems(_rates), rate->value) - /* - * Check 11n rates first for match as an MCS. - */ - if (mode == IEEE80211_MODE_11NA) { - if (rate & IEEE80211_RATE_MCS) { - rate &= ~IEEE80211_RATE_MCS; - m = findmedia(htrates, nitems(htrates), rate); - if (m != IFM_AUTO) - return m | IFM_IEEE80211_11NA; + /* NB: process modes that are not handled by get_ratetable() */ + switch (mode) { + case IEEE80211_MODE_FH: + if (rate->type == IEEE80211_T_FH) + return (FINDMEDIA(rates_fh)); + + return (IFM_AUTO); + case IEEE80211_MODE_AUTO: + /* XXX an(4) has no ieee80211com structure */ + if (ic != NULL && ic->ic_phytype == IEEE80211_T_FH) { + if (rate->type == IEEE80211_T_FH) + return (FINDMEDIA(rates_fh)); + + return (IFM_AUTO); } - } else if (mode == IEEE80211_MODE_11NG) { - /* NB: 12 is ambiguous, it will be treated as an MCS */ - if (rate & IEEE80211_RATE_MCS) { - rate &= ~IEEE80211_RATE_MCS; - m = findmedia(htrates, nitems(htrates), rate); - if (m != IFM_AUTO) - return m | IFM_IEEE80211_11NG; + + /* XXX how AUTO should be treated for VHT / HT rates? */ + switch (rate->type) { + case IEEE80211_T_OFDM: + case IEEE80211_T_OFDM_HALF: + case IEEE80211_T_OFDM_QUARTER: + case IEEE80211_T_TURBO: + return (FINDMEDIA(rates_11a)); + case IEEE80211_T_PBCC: + case IEEE80211_T_CCK: + return (FINDMEDIA(rates_11b)); + default: + return (IFM_AUTO); } + default: + { + const struct ieee80211_rate_table *rt; + + rt = ieee80211_get_ratetable(mode); + if (!ieee80211_isratevalid(rt, rate)) + return (IFM_AUTO); + + break; } - rate &= IEEE80211_RATE_VAL; + } + + /* NB: check VHT / HT rates separately */ + switch (rate->type) { + case IEEE80211_T_VHT: + switch (mode) { + case IEEE80211_MODE_VHT_2GHZ: + return (IFM_IEEE80211_VHT | IFM_IEEE80211_VHT2G); + case IEEE80211_MODE_VHT_5GHZ: + return (IFM_IEEE80211_VHT | IFM_IEEE80211_VHT5G); + default: + /* NOTREACHED */ + KASSERT(0, ("unknown mode %u for VHT rate", mode)); + return (IFM_AUTO); + } + case IEEE80211_T_HT: + switch (mode) { + case IEEE80211_MODE_11NA: + return (IFM_IEEE80211_MCS | IFM_IEEE80211_11NA); + case IEEE80211_MODE_11NG: + return (IFM_IEEE80211_MCS | IFM_IEEE80211_11NG); + default: + /* NOTREACHED */ + KASSERT(0, ("unknown mode %u for HT rate", mode)); + return (IFM_AUTO); + } + default: + break; + } + switch (mode) { + case IEEE80211_MODE_11B: + return (FINDMEDIA(rates_11b)); + case IEEE80211_MODE_11G: + case IEEE80211_MODE_11NG: + case IEEE80211_MODE_VHT_2GHZ: + case IEEE80211_MODE_TURBO_G: + if (rate->type == IEEE80211_T_CCK || + rate->type == IEEE80211_T_PBCC) + return (FINDMEDIA(rates_11b)); + + /* FALLTHROUGH */ case IEEE80211_MODE_11A: case IEEE80211_MODE_HALF: /* XXX good 'nuf */ case IEEE80211_MODE_QUARTER: case IEEE80211_MODE_11NA: + case IEEE80211_MODE_VHT_5GHZ: case IEEE80211_MODE_TURBO_A: case IEEE80211_MODE_STURBO_A: - return findmedia(rates, nitems(rates), - rate | IFM_IEEE80211_11A); - case IEEE80211_MODE_11B: - return findmedia(rates, nitems(rates), - rate | IFM_IEEE80211_11B); - case IEEE80211_MODE_FH: - return findmedia(rates, nitems(rates), - rate | IFM_IEEE80211_FH); - case IEEE80211_MODE_AUTO: - /* NB: ic may be NULL for some drivers */ - if (ic != NULL && ic->ic_phytype == IEEE80211_T_FH) - return findmedia(rates, nitems(rates), - rate | IFM_IEEE80211_FH); - /* NB: hack, 11g matches both 11b+11a rates */ - /* fall thru... */ - case IEEE80211_MODE_11G: - case IEEE80211_MODE_11NG: - case IEEE80211_MODE_TURBO_G: - return findmedia(rates, nitems(rates), rate | IFM_IEEE80211_11G); - case IEEE80211_MODE_VHT_2GHZ: - case IEEE80211_MODE_VHT_5GHZ: - /* XXX TODO: need to figure out mapping for VHT rates */ - return IFM_AUTO; + return (FINDMEDIA(rates_11a)); + default: + /* NOTREACHED */ + KASSERT(0, ("unhandled mode %u", mode)); + break; } - return IFM_AUTO; + return (IFM_AUTO); +#undef FINDMEDIA } int Index: sys/net80211/ieee80211_amrr.c =================================================================== --- sys/net80211/ieee80211_amrr.c +++ sys/net80211/ieee80211_amrr.c @@ -139,32 +139,73 @@ } /* - * Return whether 11n rates are possible. - * - * Some 11n devices may return HT information but no HT rates. - * Thus, we shouldn't treat them as an 11n node. + * Return whether 11ac rates are possible. + * + * Some 11ac devices may return VHT information but no VHT rates. + * Thus, we shouldn't treat them as an 11ac node. */ static int +amrr_node_is_11ac(struct ieee80211_node *ni) +{ + if (ni->ni_chan == NULL || ni->ni_chan == IEEE80211_CHAN_ANYC) + return (0); + if (ni->ni_vhtrates.rs_nrates == 0) + return (0); + return (IEEE80211_IS_CHAN_VHT(ni->ni_chan)); +} + +/* + * The same, but for 11n nodes. + */ +static int amrr_node_is_11n(struct ieee80211_node *ni) { - if (ni->ni_chan == NULL) + if (ni->ni_chan == NULL || ni->ni_chan == IEEE80211_CHAN_ANYC) return (0); - if (ni->ni_chan == IEEE80211_CHAN_ANYC) + if (ni->ni_htrates.rs_nrates == 0) return (0); - if (IEEE80211_IS_CHAN_HT(ni->ni_chan) && ni->ni_htrates.rs_nrates == 0) - return (0); return (IEEE80211_IS_CHAN_HT(ni->ni_chan)); } +static const struct ieee80211_rateset * +amrr_get_rateset(struct ieee80211_node *ni) +{ + + /* 11n or not? Pick the right rateset */ + if (amrr_node_is_11ac(ni)) { + return ((struct ieee80211_rateset *) &ni->ni_vhtrates); + } else if (amrr_node_is_11n(ni)) { + /* XXX ew */ + return ((struct ieee80211_rateset *) &ni->ni_htrates); + } else + return (&ni->ni_rates); +} + +static __inline char * +amrr_rate_to_string(struct ieee80211_node *ni, uint16_t rate_index, + char *buf, int buflen) +{ + uint32_t flags = IEEE80211_GET_CHAN_FLAGS(ni->ni_chan); + + /* XXX shortgi? */ + return (ieee80211_rate_to_string(rate_index, flags, 0, buf, buflen)); +} + static void amrr_node_init(struct ieee80211_node *ni) { const struct ieee80211_rateset *rs = NULL; + const struct ieee80211_rate_t *rate; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_amrr *amrr = vap->iv_rs; struct ieee80211_amrr_node *amn; - uint8_t rate; + uint16_t rate_index, max_rate_index; + uint8_t max_rate_value; +#ifdef IEEE80211_DEBUG + char buf[40]; +#endif + int rix; if (ni->ni_rctls == NULL) { ni->ni_rctls = amn = IEEE80211_MALLOC(sizeof(struct ieee80211_amrr_node), @@ -182,54 +223,49 @@ amn->amn_txcnt = amn->amn_retrycnt = 0; amn->amn_success_threshold = amrr->amrr_min_success_threshold; - /* 11n or not? Pick the right rateset */ - if (amrr_node_is_11n(ni)) { - /* XXX ew */ + /* Select max rate value */ + if (amrr_node_is_11ac(ni)) { + /* 11ac - stop at MCS4 */ + max_rate_index = IEEE80211_RATE_INDEX_VHT(3, 0); + } else if (amrr_node_is_11n(ni)) { + /* 11n - stop at MCS4 */ + max_rate_index = IEEE80211_RATE_INDEX_HT(3); IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, "%s: 11n node", __func__); - rs = (struct ieee80211_rateset *) &ni->ni_htrates; } else { + max_rate_index = IEEE80211_RATE_NONEXISTENT; + max_rate_value = 72; /* legacy - anything < 36mbit */ 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]; + rs = amrr_get_rateset(ni); + if (__predict_false(rs->rs_nrates == 0)) { + if_printf(vap->iv_ifp, "%s: no rates available!\n", __func__); + return; + } - /* 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 */ /* Pick something low that's likely to succeed */ - for (amn->amn_rix = rs->rs_nrates - 1; amn->amn_rix > 0; - amn->amn_rix--) { - /* legacy - anything < 36mbit, stop searching */ - /* 11n - stop at MCS4 */ - if (amrr_node_is_11n(ni)) { - if ((rs->rs_rates[amn->amn_rix] & 0x1f) < 4) + for (rix = rs->rs_nrates - 1; rix > 0; rix--) { + rate_index = rs->rates[rix].rs_index; + if (max_rate_index != IEEE80211_RATE_NONEXISTENT) { + if (rate_index <= max_rate_index) break; - } else if ((rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL) <= 72) - break; + } else { + rate = ieee80211_get_rate(rate_index); + if (rate->value <= max_rate_value) + 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; + ni->ni_txrate = rs->rates[rix].rs_index; amn->amn_ticks = ticks; + amn->amn_rix = rix; - /* XXX TODO: we really need a rate-to-string method */ - /* XXX TODO: non-11n rate should be divided by two.. */ IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, - "AMRR: nrates=%d, initial rate %s%d", - rs->rs_nrates, - amrr_node_is_11n(ni) ? "MCS " : "", - rate & IEEE80211_RATE_VAL); + "AMRR: nrates=%d, initial rate: %s", rs->rs_nrates, + amrr_rate_to_string(ni, ni->ni_txrate, buf, sizeof(buf))); } static void @@ -243,25 +279,23 @@ struct ieee80211_node *ni) { int rix = amn->amn_rix; - const struct ieee80211_rateset *rs = NULL; + const struct ieee80211_rateset *rs; +#ifdef IEEE80211_DEBUG + uint16_t rate_index; + char buf[40]; +#endif 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; - } + rs = amrr_get_rateset(ni); - /* XXX TODO: we really need a rate-to-string method */ - /* XXX TODO: non-11n rate should be divided by two.. */ +#ifdef IEEE80211_DEBUG + rate_index = rs->rates[rix].rs_index; 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); + "AMRR: current rate: %s, txcnt=%d, retrycnt=%d", + amrr_rate_to_string(ni, rate_index, buf, sizeof(buf)), + amn->amn_txcnt, amn->amn_retrycnt); +#endif /* * XXX This is totally bogus for 11n, as although high MCS @@ -270,6 +304,8 @@ * * 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. + * + * XXX compare via *get_rateKbps() instead? */ if (is_success(amn)) { amn->amn_success++; @@ -278,12 +314,15 @@ amn->amn_recovery = 1; amn->amn_success = 0; rix++; - /* XXX TODO: we really need a rate-to-string method */ - /* XXX TODO: non-11n rate should be divided by two.. */ + +#ifdef IEEE80211_DEBUG + rate_index = rs->rates[rix].rs_index; IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, - "AMRR increasing rate %d (txcnt=%d retrycnt=%d)", - rs->rs_rates[rix] & IEEE80211_RATE_VAL, + "AMRR: increasing rate: %s (txcnt=%d retrycnt=%d)", + amrr_rate_to_string(ni, rate_index, buf, + sizeof(buf)), amn->amn_txcnt, amn->amn_retrycnt); +#endif } else { amn->amn_recovery = 0; } @@ -301,12 +340,15 @@ amrr->amrr_min_success_threshold; } rix--; - /* XXX TODO: we really need a rate-to-string method */ - /* XXX TODO: non-11n rate should be divided by two.. */ + +#ifdef IEEE80211_DEBUG + rate_index = rs->rates[rix].rs_index; IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, - "AMRR decreasing rate %d (txcnt=%d retrycnt=%d)", - rs->rs_rates[rix] & IEEE80211_RATE_VAL, + "AMRR: decreasing rate: %s (txcnt=%d retrycnt=%d)", + amrr_rate_to_string(ni, rate_index, buf, + sizeof(buf)), amn->amn_txcnt, amn->amn_retrycnt); +#endif } amn->amn_recovery = 0; } @@ -328,27 +370,15 @@ { struct ieee80211_amrr_node *amn = ni->ni_rctls; struct ieee80211_amrr *amrr = amn->amn_amrr; - const struct ieee80211_rateset *rs = NULL; + const struct ieee80211_rateset *rs; 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; - } - + rs = amrr_get_rateset(ni); 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 = 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; + ni->ni_txrate = rs->rates[rix].rs_index; amn->amn_rix = rix; } amn->amn_ticks = ticks; @@ -441,33 +471,28 @@ 0, amrr_sysctl_interval, "I", "amrr operation interval (ms)"); /* XXX bounds check values */ SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, - "amrr_max_sucess_threshold", CTLFLAG_RW, + "amrr_max_success_threshold", CTLFLAG_RW, &amrr->amrr_max_success_threshold, 0, ""); SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, - "amrr_min_sucess_threshold", CTLFLAG_RW, + "amrr_min_success_threshold", CTLFLAG_RW, &amrr->amrr_min_success_threshold, 0, ""); } static void amrr_node_stats(struct ieee80211_node *ni, struct sbuf *s) { - int rate; struct ieee80211_amrr_node *amn = ni->ni_rctls; - struct ieee80211_rateset *rs; + const struct ieee80211_rateset *rs; + uint16_t rate_index; + char buf[40]; /* 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; - sbuf_printf(s, "rate: MCS %d\n", rate); - } else { - rs = &ni->ni_rates; - rate = rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL; - sbuf_printf(s, "rate: %d Mbit\n", rate / 2); - } + rs = amrr_get_rateset(ni); + rate_index = rs->rates[amn->amn_rix].rs_index; + sbuf_printf(s, "rate: %s\n", + amrr_rate_to_string(ni, rate_index, buf, sizeof(buf))); sbuf_printf(s, "ticks: %d\n", amn->amn_ticks); sbuf_printf(s, "txcnt: %u\n", amn->amn_txcnt); sbuf_printf(s, "success: %u\n", amn->amn_success); Index: sys/net80211/ieee80211_ddb.c =================================================================== --- sys/net80211/ieee80211_ddb.c +++ sys/net80211/ieee80211_ddb.c @@ -80,9 +80,9 @@ static void _db_show_appie(const char *tag, const struct ieee80211_appie *); static void _db_show_key(const char *tag, int ix, const struct ieee80211_key *); static void _db_show_roamparams(const char *tag, const void *arg, - const struct ieee80211_roamparam *rp); + const struct ieee80211_roamparam_vht *rp); static void _db_show_txparams(const char *tag, const void *arg, - const struct ieee80211_txparam *tp); + const struct ieee80211_txparam_vht *tp); static void _db_show_ageq(const char *tag, const struct ieee80211_ageq *q); static void _db_show_stats(const struct ieee80211_stats *); #ifdef IEEE80211_SUPPORT_MESH @@ -816,21 +816,22 @@ } static void -printrate(const char *tag, int v) +printrate(const char *tag, uint16_t idx) { - if (v == IEEE80211_FIXED_RATE_NONE) + char buf[40]; + + if (idx >= IEEE80211_RATES_COUNT) { db_printf(" %s ", tag); - else if (v == 11) - db_printf(" %s 5.5", tag); - else if (v & IEEE80211_RATE_MCS) - db_printf(" %s MCS%d", tag, v &~ IEEE80211_RATE_MCS); - else - db_printf(" %s %d", tag, v/2); + return; + } + + db_printf(" %s: %s", tag, + ieee80211_rate_to_string(idx, 0, 0, buf, sizeof(buf))); } static void _db_show_roamparams(const char *tag, const void *arg, - const struct ieee80211_roamparam *rp) + const struct ieee80211_roamparam_vht *rp) { db_printf(tag, arg); @@ -843,7 +844,7 @@ static void _db_show_txparams(const char *tag, const void *arg, - const struct ieee80211_txparam *tp) + const struct ieee80211_txparam_vht *tp) { db_printf(tag, arg); Index: sys/net80211/ieee80211_freebsd.h =================================================================== --- sys/net80211/ieee80211_freebsd.h +++ sys/net80211/ieee80211_freebsd.h @@ -593,6 +593,8 @@ struct ieee80211_bpf_params { uint8_t ibp_vers; /* version */ #define IEEE80211_BPF_VERSION 0 +#define IEEE80211_BPF_VERSION_1 1 /* treat rates as indices */ + uint8_t ibp_len; /* header length in bytes */ uint8_t ibp_flags; #define IEEE80211_BPF_SHORTPRE 0x01 /* tx with short preamble */ @@ -613,6 +615,10 @@ uint8_t ibp_rate2; /* series 3 IEEE tx rate */ uint8_t ibp_try3; /* series 4 try count */ uint8_t ibp_rate3; /* series 4 IEEE tx rate */ + +/* XXX limited by ibp_rate* field width */ +#define IEEE80211_BPF_RATE_INVALID 0xff +#define IEEE80211_BPF_RATE(r) MIN((r), IEEE80211_BPF_RATE_INVALID) }; #ifdef _KERNEL Index: sys/net80211/ieee80211_hostap.c =================================================================== --- sys/net80211/ieee80211_hostap.c +++ sys/net80211/ieee80211_hostap.c @@ -1666,11 +1666,18 @@ static void ratesetmismatch(struct ieee80211_node *ni, const struct ieee80211_frame *wh, - int reassoc, int resp, const char *tag, int rate) + int reassoc, int resp, const char *tag, int rate_index) { +#ifdef IEEE80211_DEBUG + const struct ieee80211_rate_t *rate; + + rate_index &= ~IEEE80211_F_RATESET_ERROR; + rate = ieee80211_get_rate_safe(rate_index); +#endif + IEEE80211_NOTE_MAC(ni->ni_vap, IEEE80211_MSG_ANY, wh->i_addr2, "deny %s request, %s rate set mismatch, rate/MCS %d", - reassoc ? "reassoc" : "assoc", tag, rate & IEEE80211_RATE_VAL); + reassoc ? "reassoc" : "assoc", tag, rate ? rate->value : -1); IEEE80211_SEND_MGMT(ni, resp, IEEE80211_STATUS_BASIC_RATE); ieee80211_node_leave(ni); } @@ -1743,14 +1750,14 @@ hostap_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype, const struct ieee80211_rx_stats *rxs, int rssi, int nf) { + const struct ieee80211_rate_t *rate; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; struct ieee80211_frame *wh; uint8_t *frm, *efrm, *sfrm; uint8_t *ssid, *rates, *xrates, *wpa, *rsn, *wme, *ath, *htcap; uint8_t *vhtcap, *vhtinfo; - int reassoc, resp; - uint8_t rate; + int reassoc, resp, rate_index; wh = mtod(m0, struct ieee80211_frame *); frm = (uint8_t *)&wh[1]; @@ -2139,11 +2146,12 @@ "slot time", capinfo); return; } - rate = ieee80211_setup_rates(ni, rates, xrates, - IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE | + rate_index = ieee80211_setup_rates(ni, rates, xrates, + IEEE80211_F_DOSORT | IEEE80211_F_DOFIXED | IEEE80211_F_DONEGO | IEEE80211_F_DODEL); - if (rate & IEEE80211_RATE_BASIC) { - ratesetmismatch(ni, wh, reassoc, resp, "legacy", rate); + if (rate_index & IEEE80211_F_RATESET_ERROR) { + ratesetmismatch(ni, wh, reassoc, resp, "legacy", + rate_index); vap->iv_stats.is_rx_assoc_norate++; return; } @@ -2151,10 +2159,13 @@ * If constrained to 11g-only stations reject an * 11b-only station. We cheat a bit here by looking * at the max negotiated xmit rate and assuming anyone - * with a best rate <24Mb/s is an 11b station. + * with a CCK as the best rate is an 11b station. */ - if ((vap->iv_flags & IEEE80211_F_PUREG) && rate < 48) { - ratesetmismatch(ni, wh, reassoc, resp, "11g", rate); + rate = ieee80211_get_rate_safe(rate_index); + if ((vap->iv_flags & IEEE80211_F_PUREG) && + (!rate || rate->type == IEEE80211_T_CCK)) { + ratesetmismatch(ni, wh, reassoc, resp, "11g", + rate_index); vap->iv_stats.is_rx_assoc_norate++; return; } @@ -2177,12 +2188,11 @@ /* HT */ if (IEEE80211_IS_CHAN_HT(ni->ni_chan) && htcap != NULL) { - rate = ieee80211_setup_htrates(ni, htcap, - IEEE80211_F_DOFMCS | IEEE80211_F_DONEGO | - IEEE80211_F_DOBRS); - if (rate & IEEE80211_RATE_BASIC) { + rate_index = ieee80211_setup_htrates(ni, htcap, + IEEE80211_F_DOFIXED | IEEE80211_F_DONEGO); + if (rate_index & IEEE80211_F_RATESET_ERROR) { ratesetmismatch(ni, wh, reassoc, resp, - "HT", rate); + "HT", rate_index); vap->iv_stats.is_ht_assoc_norate++; return; } Index: sys/net80211/ieee80211_ht.h =================================================================== --- sys/net80211/ieee80211_ht.h +++ sys/net80211/ieee80211_ht.h @@ -172,13 +172,6 @@ void ieee80211_ht_announce(struct ieee80211com *); -struct ieee80211_mcs_rates { - uint16_t ht20_rate_800ns; - uint16_t ht20_rate_400ns; - uint16_t ht40_rate_800ns; - uint16_t ht40_rate_400ns; -}; -extern const struct ieee80211_mcs_rates ieee80211_htrates[]; void ieee80211_init_suphtrates(struct ieee80211com *); struct ieee80211_node; Index: sys/net80211/ieee80211_ht.c =================================================================== --- sys/net80211/ieee80211_ht.c +++ sys/net80211/ieee80211_ht.c @@ -58,86 +58,6 @@ #define MS(_v, _f) (((_v) & _f) >> _f##_S) #define SM(_v, _f) (((_v) << _f##_S) & _f) -const struct ieee80211_mcs_rates ieee80211_htrates[IEEE80211_HTRATE_MAXSIZE] = { - { 13, 14, 27, 30 }, /* MCS 0 */ - { 26, 29, 54, 60 }, /* MCS 1 */ - { 39, 43, 81, 90 }, /* MCS 2 */ - { 52, 58, 108, 120 }, /* MCS 3 */ - { 78, 87, 162, 180 }, /* MCS 4 */ - { 104, 116, 216, 240 }, /* MCS 5 */ - { 117, 130, 243, 270 }, /* MCS 6 */ - { 130, 144, 270, 300 }, /* MCS 7 */ - { 26, 29, 54, 60 }, /* MCS 8 */ - { 52, 58, 108, 120 }, /* MCS 9 */ - { 78, 87, 162, 180 }, /* MCS 10 */ - { 104, 116, 216, 240 }, /* MCS 11 */ - { 156, 173, 324, 360 }, /* MCS 12 */ - { 208, 231, 432, 480 }, /* MCS 13 */ - { 234, 260, 486, 540 }, /* MCS 14 */ - { 260, 289, 540, 600 }, /* MCS 15 */ - { 39, 43, 81, 90 }, /* MCS 16 */ - { 78, 87, 162, 180 }, /* MCS 17 */ - { 117, 130, 243, 270 }, /* MCS 18 */ - { 156, 173, 324, 360 }, /* MCS 19 */ - { 234, 260, 486, 540 }, /* MCS 20 */ - { 312, 347, 648, 720 }, /* MCS 21 */ - { 351, 390, 729, 810 }, /* MCS 22 */ - { 390, 433, 810, 900 }, /* MCS 23 */ - { 52, 58, 108, 120 }, /* MCS 24 */ - { 104, 116, 216, 240 }, /* MCS 25 */ - { 156, 173, 324, 360 }, /* MCS 26 */ - { 208, 231, 432, 480 }, /* MCS 27 */ - { 312, 347, 648, 720 }, /* MCS 28 */ - { 416, 462, 864, 960 }, /* MCS 29 */ - { 468, 520, 972, 1080 }, /* MCS 30 */ - { 520, 578, 1080, 1200 }, /* MCS 31 */ - { 0, 0, 12, 13 }, /* MCS 32 */ - { 78, 87, 162, 180 }, /* MCS 33 */ - { 104, 116, 216, 240 }, /* MCS 34 */ - { 130, 144, 270, 300 }, /* MCS 35 */ - { 117, 130, 243, 270 }, /* MCS 36 */ - { 156, 173, 324, 360 }, /* MCS 37 */ - { 195, 217, 405, 450 }, /* MCS 38 */ - { 104, 116, 216, 240 }, /* MCS 39 */ - { 130, 144, 270, 300 }, /* MCS 40 */ - { 130, 144, 270, 300 }, /* MCS 41 */ - { 156, 173, 324, 360 }, /* MCS 42 */ - { 182, 202, 378, 420 }, /* MCS 43 */ - { 182, 202, 378, 420 }, /* MCS 44 */ - { 208, 231, 432, 480 }, /* MCS 45 */ - { 156, 173, 324, 360 }, /* MCS 46 */ - { 195, 217, 405, 450 }, /* MCS 47 */ - { 195, 217, 405, 450 }, /* MCS 48 */ - { 234, 260, 486, 540 }, /* MCS 49 */ - { 273, 303, 567, 630 }, /* MCS 50 */ - { 273, 303, 567, 630 }, /* MCS 51 */ - { 312, 347, 648, 720 }, /* MCS 52 */ - { 130, 144, 270, 300 }, /* MCS 53 */ - { 156, 173, 324, 360 }, /* MCS 54 */ - { 182, 202, 378, 420 }, /* MCS 55 */ - { 156, 173, 324, 360 }, /* MCS 56 */ - { 182, 202, 378, 420 }, /* MCS 57 */ - { 208, 231, 432, 480 }, /* MCS 58 */ - { 234, 260, 486, 540 }, /* MCS 59 */ - { 208, 231, 432, 480 }, /* MCS 60 */ - { 234, 260, 486, 540 }, /* MCS 61 */ - { 260, 289, 540, 600 }, /* MCS 62 */ - { 260, 289, 540, 600 }, /* MCS 63 */ - { 286, 318, 594, 660 }, /* MCS 64 */ - { 195, 217, 405, 450 }, /* MCS 65 */ - { 234, 260, 486, 540 }, /* MCS 66 */ - { 273, 303, 567, 630 }, /* MCS 67 */ - { 234, 260, 486, 540 }, /* MCS 68 */ - { 273, 303, 567, 630 }, /* MCS 69 */ - { 312, 347, 648, 720 }, /* MCS 70 */ - { 351, 390, 729, 810 }, /* MCS 71 */ - { 312, 347, 648, 720 }, /* MCS 72 */ - { 351, 390, 729, 810 }, /* MCS 73 */ - { 390, 433, 810, 900 }, /* MCS 74 */ - { 390, 433, 810, 900 }, /* MCS 75 */ - { 429, 477, 891, 990 }, /* MCS 76 */ -}; - static int ieee80211_ampdu_age = -1; /* threshold for ampdu reorder q (ms) */ SYSCTL_PROC(_net_wlan, OID_AUTO, ampdu_age, CTLTYPE_INT | CTLFLAG_RW, &ieee80211_ampdu_age, 0, ieee80211_sysctl_msecs_ticks, "I", @@ -316,53 +236,30 @@ { } -static int -ht_getrate(struct ieee80211com *ic, int index, enum ieee80211_phymode mode, - int ratetype) -{ - int mword, rate; - - mword = ieee80211_rate2media(ic, index | IEEE80211_RATE_MCS, mode); - if (IFM_SUBTYPE(mword) != IFM_IEEE80211_MCS) - return (0); - switch (ratetype) { - case 0: - rate = ieee80211_htrates[index].ht20_rate_800ns; - break; - case 1: - rate = ieee80211_htrates[index].ht20_rate_400ns; - break; - case 2: - rate = ieee80211_htrates[index].ht40_rate_800ns; - break; - default: - rate = ieee80211_htrates[index].ht40_rate_400ns; - break; - } - return (rate); -} - static struct printranges { int minmcs; int maxmcs; int txstream; - int ratetype; int htcapflags; } ranges[] = { - { 0, 7, 1, 0, 0 }, - { 8, 15, 2, 0, 0 }, - { 16, 23, 3, 0, 0 }, - { 24, 31, 4, 0, 0 }, - { 32, 0, 1, 2, IEEE80211_HTC_TXMCS32 }, - { 33, 38, 2, 0, IEEE80211_HTC_TXUNEQUAL }, - { 39, 52, 3, 0, IEEE80211_HTC_TXUNEQUAL }, - { 53, 76, 4, 0, IEEE80211_HTC_TXUNEQUAL }, - { 0, 0, 0, 0, 0 }, + { 0, 7, 1, 0 }, + { 8, 15, 2, 0 }, + { 16, 23, 3, 0 }, + { 24, 31, 4, 0 }, + { 32, 0, 1, IEEE80211_HTC_TXMCS32 }, + { 33, 38, 2, IEEE80211_HTC_TXUNEQUAL }, + { 39, 52, 3, IEEE80211_HTC_TXUNEQUAL }, + { 53, 76, 4, IEEE80211_HTC_TXUNEQUAL }, + { 0, 0, 0, 0 }, }; static void -ht_rateprint(struct ieee80211com *ic, enum ieee80211_phymode mode, int ratetype) +ht_rateprint(struct ieee80211com *ic, uint32_t chan_flags, int shortgi) { +#define RIDX(_mcs) IEEE80211_RATE_INDEX_HT((_mcs)) +#define GET_RATE(_mcs) \ + ieee80211_get_rateKbps_by_idx(RIDX(_mcs), chan_flags, shortgi) / 500 + int minrate, maxrate; struct printranges *range; @@ -372,20 +269,21 @@ if (range->htcapflags && (ic->ic_htcaps & range->htcapflags) == 0) continue; - if (ratetype < range->ratetype) - continue; - minrate = ht_getrate(ic, range->minmcs, mode, ratetype); - maxrate = ht_getrate(ic, range->maxmcs, mode, ratetype); + + minrate = GET_RATE(range->minmcs); if (range->maxmcs) { + maxrate = GET_RATE(range->maxmcs); ic_printf(ic, "MCS %d-%d: %d%sMbps - %d%sMbps\n", range->minmcs, range->maxmcs, minrate/2, ((minrate & 0x1) != 0 ? ".5" : ""), maxrate/2, ((maxrate & 0x1) != 0 ? ".5" : "")); - } else { + } else if (minrate) { ic_printf(ic, "MCS %d: %d%sMbps\n", range->minmcs, minrate/2, ((minrate & 0x1) != 0 ? ".5" : "")); } } +#undef GET_RATE +#undef RIDX } static void @@ -394,19 +292,19 @@ const char *modestr = ieee80211_phymode_name[mode]; ic_printf(ic, "%s MCS 20MHz\n", modestr); - ht_rateprint(ic, mode, 0); + ht_rateprint(ic, IEEE80211_CHAN_HT20, 0); if (ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20) { ic_printf(ic, "%s MCS 20MHz SGI\n", modestr); - ht_rateprint(ic, mode, 1); + ht_rateprint(ic, IEEE80211_CHAN_HT20, 1); } if (ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) { ic_printf(ic, "%s MCS 40MHz:\n", modestr); - ht_rateprint(ic, mode, 2); + ht_rateprint(ic, IEEE80211_CHAN_HT40, 0); } if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) && (ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40)) { ic_printf(ic, "%s MCS 40MHz SGI:\n", modestr); - ht_rateprint(ic, mode, 3); + ht_rateprint(ic, IEEE80211_CHAN_HT40, 1); } } @@ -426,34 +324,34 @@ void ieee80211_init_suphtrates(struct ieee80211com *ic) { -#define ADDRATE(x) do { \ - htrateset->rs_rates[htrateset->rs_nrates] = x; \ - htrateset->rs_nrates++; \ -} while (0) +#define CHECK_CAPS(_ic, _mask) (((_ic)->ic_htcaps & (_mask)) == (_mask)) + const struct ieee80211_rate_t *rate; struct ieee80211_htrateset *htrateset = &ic->ic_sup_htrates; - int i; + int i, has_mcs32, has_unequal; - memset(htrateset, 0, sizeof(struct ieee80211_htrateset)); - for (i = 0; i < ic->ic_txstream * 8; i++) - ADDRATE(i); - if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) && - (ic->ic_htcaps & IEEE80211_HTC_TXMCS32)) - ADDRATE(32); - if (ic->ic_htcaps & IEEE80211_HTC_TXUNEQUAL) { - if (ic->ic_txstream >= 2) { - for (i = 33; i <= 38; i++) - ADDRATE(i); - } - if (ic->ic_txstream >= 3) { - for (i = 39; i <= 52; i++) - ADDRATE(i); - } - if (ic->ic_txstream == 4) { - for (i = 53; i <= 76; i++) - ADDRATE(i); - } + has_mcs32 = + CHECK_CAPS(ic, IEEE80211_HTCAP_CHWIDTH40 | IEEE80211_HTC_TXMCS32); + has_unequal = CHECK_CAPS(ic, IEEE80211_HTC_TXUNEQUAL); + + memset(htrateset, 0, sizeof(*htrateset)); + for (i = IEEE80211_RATE_INDEX_HT(0); i < IEEE80211_RATES_COUNT; i++) { + rate = ieee80211_get_rate(i); + + if (rate->type != IEEE80211_T_HT) + break; + + if (rate->props.ht.streams > ic->ic_txstream || + (rate->value == 32 && !has_mcs32)) + continue; + + if (rate->props.ht.unequal && !has_unequal) + break; + + setbit(htrateset->rs_bitmap, rate->value); + htrateset->rates[htrateset->rs_nrates].rs_index = i; + htrateset->rs_nrates++; } -#undef ADDRATE +#undef CHECK_CAPS } /* @@ -1928,51 +1826,61 @@ int ieee80211_setup_htrates(struct ieee80211_node *ni, const uint8_t *ie, int flags) { +#define CHECK_CAPS(_ic, _mask) (((_ic)->ic_htcaps & (_mask)) == (_mask)) struct ieee80211com *ic = ni->ni_ic; struct ieee80211vap *vap = ni->ni_vap; + const struct ieee80211_rate_t *rate; const struct ieee80211_ie_htcap *htcap; struct ieee80211_htrateset *rs; - int i, maxequalmcs, maxunequalmcs; + int i, has_mcs32, has_unequal; - maxequalmcs = ic->ic_txstream * 8 - 1; - maxunequalmcs = 0; - if (ic->ic_htcaps & IEEE80211_HTC_TXUNEQUAL) { - if (ic->ic_txstream >= 2) - maxunequalmcs = 38; - if (ic->ic_txstream >= 3) - maxunequalmcs = 52; - if (ic->ic_txstream >= 4) - maxunequalmcs = 76; - } + has_mcs32 = + CHECK_CAPS(ic, IEEE80211_HTCAP_CHWIDTH40 | IEEE80211_HTC_TXMCS32); + has_unequal = CHECK_CAPS(ic, IEEE80211_HTC_TXUNEQUAL); rs = &ni->ni_htrates; memset(rs, 0, sizeof(*rs)); - if (ie != NULL) { - if (ie[0] == IEEE80211_ELEMID_VENDOR) - ie += 4; - htcap = (const struct ieee80211_ie_htcap *) ie; - for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++) { - if (isclr(htcap->hc_mcsset, i)) - continue; - if (rs->rs_nrates == IEEE80211_HTRATE_MAXSIZE) { - IEEE80211_NOTE(vap, - IEEE80211_MSG_XRATE | IEEE80211_MSG_11N, ni, - "WARNING, HT rate set too large; only " - "using %u rates", IEEE80211_HTRATE_MAXSIZE); - vap->iv_stats.is_rx_rstoobig++; - break; - } - if (i <= 31 && i > maxequalmcs) - continue; - if (i == 32 && - (ic->ic_htcaps & IEEE80211_HTC_TXMCS32) == 0) - continue; - if (i > 32 && i > maxunequalmcs) - continue; - rs->rs_rates[rs->rs_nrates++] = i; + if (ie == NULL) + goto end; + + if (ie[0] == IEEE80211_ELEMID_VENDOR) + ie += 4; + htcap = (const struct ieee80211_ie_htcap *) ie; + + for (i = IEEE80211_RATE_INDEX_HT(0); i < IEEE80211_RATES_COUNT; i++) { + rate = ieee80211_get_rate(i); + + if (rate->type != IEEE80211_T_HT) + break; + if (isclr(htcap->hc_mcsset, rate->value)) + continue; + if (rs->rs_nrates == IEEE80211_HTRATE_MAXSIZE) { + IEEE80211_NOTE(vap, + IEEE80211_MSG_XRATE | IEEE80211_MSG_11N, ni, + "WARNING, HT rate set too large; only " + "using %u rates", IEEE80211_HTRATE_MAXSIZE); + vap->iv_stats.is_rx_rstoobig++; + break; } - } + + if (rate->props.ht.streams > ic->ic_txstream || + (rate->value == 32 && !has_mcs32)) + continue; + + if (rate->props.ht.unequal && !has_unequal) + break; + + setbit(rs->rs_bitmap, rate->value); + rs->rates[rs->rs_nrates].rs_index = i; + rs->rs_nrates++; + } + +end: + /* Mark that we are using HT rateset */ + flags |= IEEE80211_F_RATE_MCS; + return ieee80211_fix_rate(ni, (struct ieee80211_rateset *) rs, flags); +#undef CHECK_CAPS } /* @@ -1982,9 +1890,10 @@ void ieee80211_setup_basic_htrates(struct ieee80211_node *ni, const uint8_t *ie) { + const struct ieee80211_rate_t *rate; const struct ieee80211_ie_htinfo *htinfo; struct ieee80211_htrateset *rs; - int i, j; + int i; if (ie[0] == IEEE80211_ELEMID_VENDOR) ie += 4; @@ -1996,12 +1905,10 @@ "%s", "WARNING, empty HT rate set"); return; } - for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++) { - if (isclr(htinfo->hi_basicmcsset, i)) - continue; - for (j = 0; j < rs->rs_nrates; j++) - if ((rs->rs_rates[j] & IEEE80211_RATE_VAL) == i) - rs->rs_rates[j] |= IEEE80211_RATE_BASIC; + for (i = 0; i < rs->rs_nrates; i++) { + rate = ieee80211_get_rate(rs->rates[i].rs_index); + if (isset(htinfo->hi_basicmcsset, rate->value)) + rs->rates[i].rs_basic = 1; } } @@ -2805,8 +2712,9 @@ struct ieee80211_bpf_params params; memset(¶ms, 0, sizeof(params)); + params.ibp_vers = IEEE80211_BPF_VERSION_1; params.ibp_pri = WME_AC_VO; - params.ibp_rate0 = ni->ni_txparms->mgmtrate; + params.ibp_rate0 = IEEE80211_BPF_RATE(ni->ni_txparms->mgmtrate); /* NB: we know all frames are unicast */ params.ibp_try0 = ni->ni_txparms->maxretry; params.ibp_power = ni->ni_txpower; @@ -3257,14 +3165,14 @@ static void ieee80211_set_basic_htrates(uint8_t *frm, const struct ieee80211_htrateset *rs) { + const struct ieee80211_rate_t *rate; int i; for (i = 0; i < rs->rs_nrates; i++) { - int r = rs->rs_rates[i] & IEEE80211_RATE_VAL; - if ((rs->rs_rates[i] & IEEE80211_RATE_BASIC) && - r < IEEE80211_HTRATE_MAXSIZE) { + if (rs->rates[i].rs_basic) { /* NB: this assumes a particular implementation */ - setbit(frm, r); + rate = ieee80211_get_rate(rs->rates[i].rs_index); + setbit(frm, rate->value); } } } Index: sys/net80211/ieee80211_hwmp.c =================================================================== --- sys/net80211/ieee80211_hwmp.c +++ sys/net80211/ieee80211_hwmp.c @@ -658,8 +658,9 @@ IEEE80211_NODE_STAT(ni, tx_mgmt); memset(¶ms, 0, sizeof(params)); + params.ibp_vers = IEEE80211_BPF_VERSION_1; params.ibp_pri = WME_AC_VO; - params.ibp_rate0 = ni->ni_txparms->mgmtrate; + params.ibp_rate0 = IEEE80211_BPF_RATE(ni->ni_txparms->mgmtrate); if (IEEE80211_IS_MULTICAST(da)) params.ibp_try0 = 1; else Index: sys/net80211/ieee80211_input.c =================================================================== --- sys/net80211/ieee80211_input.c +++ sys/net80211/ieee80211_input.c @@ -387,6 +387,49 @@ #undef FF_LLC_SIZE } +static void +ieee80211_copy_rates(struct ieee80211_node *ni, + const uint8_t *rates, enum ieee80211_phymode mode) +{ +#define IS_BASIC(_rate) (((_rate) & IEEE80211_RATE_BASIC) != 0) + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211_rateset *rs = &ni->ni_rates; + uint16_t rate_index; + uint8_t i, rate_value; + + if (rs->rs_nrates == nitems(rs->rates)) { + IEEE80211_NOTE(vap, IEEE80211_MSG_XRATE, ni, + "%sno space left in the rate set", ""); + return; + } + + for (i = 0; i < rates[1]; i++) { + rate_value = IEEE80211_RV(rates[i + 2]); + rate_index = ieee80211_convert_from_legacy_rate(rate_value, + mode); + + if (rate_index == IEEE80211_RATE_NONEXISTENT) { + IEEE80211_NOTE(vap, IEEE80211_MSG_XRATE, ni, + "skipping unknown rate %u", rates[i + 2]); + continue; + } + + setbit(rs->rs_bitmap, rate_value); + rs->rates[rs->rs_nrates].rs_index = rate_index; + rs->rates[rs->rs_nrates].rs_basic = IS_BASIC(rates[i + 2]); + + rs->rs_nrates++; + if (rs->rs_nrates == nitems(rs->rates)) { + IEEE80211_NOTE(vap, IEEE80211_MSG_XRATE, ni, + "rate set is too large; only using %u of %u rates", + rs->rs_nrates, rates[1]); + vap->iv_stats.is_rx_rstoobig++; + break; + } + } +#undef IS_BASIC +} + /* * Install received rate set information in the node's state block. */ @@ -394,28 +437,17 @@ ieee80211_setup_rates(struct ieee80211_node *ni, const uint8_t *rates, const uint8_t *xrates, int flags) { - struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_rateset *rs = &ni->ni_rates; + enum ieee80211_phymode mode = ieee80211_chan2mode(ni->ni_chan); memset(rs, 0, sizeof(*rs)); - rs->rs_nrates = rates[1]; - memcpy(rs->rs_rates, rates + 2, rs->rs_nrates); - if (xrates != NULL) { - uint8_t nxrates; - /* - * Tack on 11g extended supported rate element. - */ - nxrates = xrates[1]; - if (rs->rs_nrates + nxrates > IEEE80211_RATE_MAXSIZE) { - nxrates = IEEE80211_RATE_MAXSIZE - rs->rs_nrates; - IEEE80211_NOTE(vap, IEEE80211_MSG_XRATE, ni, - "extended rate set too large; only using " - "%u of %u rates", nxrates, xrates[1]); - vap->iv_stats.is_rx_rstoobig++; - } - memcpy(rs->rs_rates + rs->rs_nrates, xrates+2, nxrates); - rs->rs_nrates += nxrates; - } + ieee80211_copy_rates(ni, rates, mode); + if (xrates != NULL) + ieee80211_copy_rates(ni, xrates, mode); + + /* Mark that we are using legacy rates. */ + flags |= IEEE80211_F_RATE_LEGACY; + return ieee80211_fix_rate(ni, rs, flags); } Index: sys/net80211/ieee80211_ioctl.h =================================================================== --- sys/net80211/ieee80211_ioctl.h +++ sys/net80211/ieee80211_ioctl.h @@ -456,6 +456,9 @@ uint16_t isi_peerid; uint16_t isi_localid; uint8_t isi_peerstate; + /* new fields for rates */ + uint16_t isi_rates_ind[IEEE80211_RATE_MAXSIZE]; + uint16_t isi_txrate_ind; /* XXX frag state? */ /* variable length IE data */ }; @@ -519,6 +522,13 @@ * Station mode roaming parameters. These are maintained * per band/mode and control the roaming algorithm. */ +struct ieee80211_roamparams_req_vht { + struct ieee80211_roamparam_vht params[IEEE80211_MODE_MAX]; +}; + +/* + * Legacy version. + */ struct ieee80211_roamparams_req { struct ieee80211_roamparam params[IEEE80211_MODE_MAX]; }; @@ -529,9 +539,14 @@ * per-client basis according to the capabilities of the client * (e.g. an 11b client associated to an 11g ap) when operating as * an ap. - * - * MCS are distinguished from legacy rates by or'ing in 0x80. */ +struct ieee80211_txparams_vht_req { + struct ieee80211_txparam_vht params[IEEE80211_MODE_MAX]; +}; + +/* + * Legacy version. + */ struct ieee80211_txparams_req { struct ieee80211_txparam params[IEEE80211_MODE_MAX]; }; @@ -710,6 +725,8 @@ #define IEEE80211_IOC_GREENFIELD 112 /* Greenfield (on, off) */ #define IEEE80211_IOC_STBC 113 /* STBC Tx/RX (on, off) */ #define IEEE80211_IOC_LDPC 114 /* LDPC Tx/RX (on, off) */ +#define IEEE80211_IOC_ROAM_VHT 115 /* roaming params (rate_t) */ +#define IEEE80211_IOC_TXPARAMS_VHT 116 /* tx parameters (rate_t) */ /* VHT */ #define IEEE80211_IOC_VHTCONF 130 /* VHT config (off, on; widths) */ Index: sys/net80211/ieee80211_ioctl.c =================================================================== --- sys/net80211/ieee80211_ioctl.c +++ sys/net80211/ieee80211_ioctl.c @@ -376,16 +376,21 @@ static void get_sta_info(void *arg, struct ieee80211_node *ni) { + const struct ieee80211_rate_t *rate; + const struct ieee80211_rateset *rs = &ni->ni_rates; + const struct ieee80211_channel *chan = ni->ni_chan; struct stainforeq *req = arg; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211req_sta_info *si; size_t ielen, len; uint8_t *cp; + uint8_t value; + int i, shortgi; if (vap->iv_opmode == IEEE80211_M_HOSTAP && ni->ni_associd == 0) /* only associated stations */ return; - if (ni->ni_chan == IEEE80211_CHAN_ANYC) /* XXX bogus entry */ + if (chan == IEEE80211_CHAN_ANYC) /* XXX bogus entry */ return; len = sta_space(ni, &ielen); if (len > req->space) @@ -394,8 +399,8 @@ si->isi_len = len; si->isi_ie_off = sizeof(struct ieee80211req_sta_info); si->isi_ie_len = ielen; - si->isi_freq = ni->ni_chan->ic_freq; - si->isi_flags = ni->ni_chan->ic_flags; + si->isi_freq = chan->ic_freq; + si->isi_flags = chan->ic_flags; si->isi_state = ni->ni_flags; si->isi_authmode = ni->ni_authmode; vap->iv_ic->ic_node_getsignal(ni, &si->isi_rssi, &si->isi_noise); @@ -403,27 +408,45 @@ si->isi_capinfo = ni->ni_capinfo; si->isi_erp = ni->ni_erp; IEEE80211_ADDR_COPY(si->isi_macaddr, ni->ni_macaddr); - si->isi_nrates = ni->ni_rates.rs_nrates; - if (si->isi_nrates > 15) - si->isi_nrates = 15; - memcpy(si->isi_rates, ni->ni_rates.rs_rates, si->isi_nrates); - si->isi_txrate = ni->ni_txrate; - if (si->isi_txrate & IEEE80211_RATE_MCS) { - const struct ieee80211_mcs_rates *mcs = - &ieee80211_htrates[ni->ni_txrate &~ IEEE80211_RATE_MCS]; - if (IEEE80211_IS_CHAN_HT40(ni->ni_chan)) { - if (ni->ni_flags & IEEE80211_NODE_SGI40) - si->isi_txmbps = mcs->ht40_rate_800ns; - else - si->isi_txmbps = mcs->ht40_rate_400ns; - } else { - if (ni->ni_flags & IEEE80211_NODE_SGI20) - si->isi_txmbps = mcs->ht20_rate_800ns; - else - si->isi_txmbps = mcs->ht20_rate_400ns; - } - } else - si->isi_txmbps = si->isi_txrate; + si->isi_nrates = MIN(rs->rs_nrates, nitems(si->isi_rates)); + for (i = 0; i < si->isi_nrates; i++) { + rate = ieee80211_get_rate(rs->rates[i].rs_index); + + value = rate->value; + if (rs->rates[i].rs_basic) + value |= IEEE80211_RATE_BASIC; + + /* backward compatibility */ + si->isi_rates[i] = value; + si->isi_rates_ind[i] = rs->rates[i].rs_index; + } + si->isi_txrate = ieee80211_convert_to_legacy_rate(ni->ni_txrate); + si->isi_txrate_ind = ni->ni_txrate; + + shortgi = 0; + rate = ieee80211_get_rate(ni->ni_txrate); + switch (rate->type) { + case IEEE80211_T_VHT: + /* TODO: VHT80 / VHT160 */ + if ((IEEE80211_IS_CHAN_VHT40(chan) && + (ni->ni_flags & IEEE80211_NODE_SGI40) != 0) || + (IEEE80211_IS_CHAN_VHT20(chan) && + (ni->ni_flags & IEEE80211_NODE_SGI20) != 0)) + shortgi = 1; + break; + case IEEE80211_T_HT: + if ((IEEE80211_IS_CHAN_HT40(chan) && + (ni->ni_flags & IEEE80211_NODE_SGI40) != 0) || + (IEEE80211_IS_CHAN_HT20(chan) && + (ni->ni_flags & IEEE80211_NODE_SGI20) != 0)) + shortgi = 1; + break; + default: + break; + } + + si->isi_txmbps = ieee80211_get_rateKbps(rate, chan->ic_flags, shortgi); + si->isi_txmbps /= 500; si->isi_associd = ni->ni_associd; si->isi_txpower = ni->ni_txpower; si->isi_vlan = ni->ni_vlan; @@ -670,22 +693,97 @@ ieee80211_ioctl_getroam(struct ieee80211vap *vap, const struct ieee80211req *ireq) { + struct ieee80211_roamparams_req *req; + struct ieee80211_roamparam_vht *req_in; + struct ieee80211_roamparam *req_out; size_t len = ireq->i_len; + int mode, error; + + req = IEEE80211_MALLOC(sizeof(*req), M_TEMP, + IEEE80211_M_NOWAIT | IEEE80211_M_ZERO); + if (req == NULL) + return (ENOMEM); + + for (mode = 0; mode < nitems(req->params); mode++) { + req_out = &req->params[mode]; + req_in = &vap->iv_roamparms[mode]; + + if (req_in->rate != IEEE80211_RATE_NONEXISTENT) { + req_out->rssi = req_in->rssi; + req_out->rate = + ieee80211_convert_to_legacy_rate(req_in->rate); + } + } + /* NB: accept short requests for backwards compat */ + if (len > sizeof(*req)) + len = sizeof(*req); + + error = copyout(req, ireq->i_data, len); + IEEE80211_FREE(req, M_TEMP); + return (error); +} + +static int +ieee80211_ioctl_getroam_vht(struct ieee80211vap *vap, + const struct ieee80211req *ireq) +{ + size_t len = ireq->i_len; + /* NB: accept short requests for backwards compat */ if (len > sizeof(vap->iv_roamparms)) len = sizeof(vap->iv_roamparms); - return copyout(vap->iv_roamparms, ireq->i_data, len); + return (copyout(vap->iv_roamparms, ireq->i_data, len)); } static int ieee80211_ioctl_gettxparams(struct ieee80211vap *vap, const struct ieee80211req *ireq) { +#define TO_LEGACY(_r, _def_value) \ + ((_r) != IEEE80211_RATE_NONEXISTENT) ? \ + ieee80211_convert_to_legacy_rate((_r)) : (_def_value) + + struct ieee80211_txparams_req *req; + struct ieee80211_txparam_vht *req_in; + struct ieee80211_txparam *req_out; + int mode, error; + + /* NB: no need to zero out memory, all fields are initialized here */ + req = IEEE80211_MALLOC(sizeof(*req), M_TEMP, IEEE80211_M_NOWAIT); + if (req == NULL) + return (ENOMEM); + + for (mode = 0; mode < nitems(req->params); mode++) { + req_out = &req->params[mode]; + req_in = &vap->iv_txparms[mode]; + + req_out->ucastrate = TO_LEGACY(req_in->ucastrate, + IEEE80211_FIXED_RATE_NONE); + req_out->mgmtrate = TO_LEGACY(req_in->mgmtrate, 0); + req_out->mcastrate = TO_LEGACY(req_in->mcastrate, 0); + req_out->maxretry = req_in->maxretry; + } + size_t len = ireq->i_len; /* NB: accept short requests for backwards compat */ + if (len > sizeof(*req)) + len = sizeof(*req); + + error = copyout(req, ireq->i_data, len); + IEEE80211_FREE(req, M_TEMP); + return (error); +#undef TO_LEGACY +} + +static int +ieee80211_ioctl_gettxparams_vht(struct ieee80211vap *vap, + const struct ieee80211req *ireq) +{ + size_t len = ireq->i_len; + /* NB: accept short requests for backwards compat */ if (len > sizeof(vap->iv_txparms)) len = sizeof(vap->iv_txparms); - return copyout(vap->iv_txparms, ireq->i_data, len); + return (copyout(vap->iv_txparms, ireq->i_data, len)); } static int @@ -1063,12 +1161,18 @@ case IEEE80211_IOC_REGDOMAIN: error = ieee80211_ioctl_getregdomain(vap, ireq); break; - case IEEE80211_IOC_ROAM: + case IEEE80211_IOC_ROAM: /* legacy, use ROAM_VHT instead */ error = ieee80211_ioctl_getroam(vap, ireq); break; - case IEEE80211_IOC_TXPARAMS: + case IEEE80211_IOC_ROAM_VHT: + error = ieee80211_ioctl_getroam_vht(vap, ireq); + break; + case IEEE80211_IOC_TXPARAMS: /* legacy, use TXPARAMS_VHT instead */ error = ieee80211_ioctl_gettxparams(vap, ireq); break; + case IEEE80211_IOC_TXPARAMS_VHT: + error = ieee80211_ioctl_gettxparams_vht(vap, ireq); + break; case IEEE80211_IOC_HTCOMPAT: ireq->i_val = (vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT) != 0; break; @@ -1986,6 +2090,7 @@ setcurchan(struct ieee80211vap *vap, struct ieee80211_channel *c) { struct ieee80211com *ic = vap->iv_ic; + enum ieee80211_phymode mode; int error; if (c != IEEE80211_CHAN_ANYC) { @@ -2007,6 +2112,7 @@ vap->iv_des_chan = c; error = 0; + mode = ieee80211_chan2mode(ic->ic_curchan); if (vap->iv_opmode == IEEE80211_M_MONITOR && vap->iv_des_chan != IEEE80211_CHAN_ANYC) { /* @@ -2018,7 +2124,7 @@ vap->iv_bss->ni_chan = ic->ic_curchan; } else { ic->ic_curchan = vap->iv_des_chan; - ic->ic_rt = ieee80211_get_ratetable(ic->ic_curchan); + ic->ic_rt = ieee80211_get_ratetable(mode); } } else { /* @@ -2035,7 +2141,7 @@ * there is immediate feedback; e.g. via ifconfig. */ ic->ic_curchan = vap->iv_des_chan; - ic->ic_rt = ieee80211_get_ratetable(ic->ic_curchan); + ic->ic_rt = ieee80211_get_ratetable(mode); } } return error; @@ -2207,90 +2313,214 @@ ieee80211_ioctl_setroam(struct ieee80211vap *vap, const struct ieee80211req *ireq) { +#define FROM_LEGACY(r, mode) ieee80211_convert_from_legacy_rate((r), (mode)) + struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_roamparams_req_vht *req; + struct ieee80211_roamparams_req *req_in; + struct ieee80211_roamparam_vht *params_vht; + struct ieee80211_roamparam *params; + int m, error; + + if (ireq->i_len != sizeof(*req_in)) + return (EINVAL); + + req_in = IEEE80211_MALLOC(sizeof(*req_in), M_TEMP, IEEE80211_M_NOWAIT); + if (req_in == NULL) + return (ENOMEM); + + req = IEEE80211_MALLOC(sizeof(*req), M_TEMP, IEEE80211_M_NOWAIT); + if (req == NULL) { + IEEE80211_FREE(req_in, M_TEMP); + return (ENOMEM); + } + + error = copyin(ireq->i_data, req_in, sizeof(*req_in)); + if (error != 0) + goto end; + + /* Convert to new format (and validate). */ + for (m = IEEE80211_MODE_AUTO + 1; m < nitems(req_in->params); m++) { + if (isclr(ic->ic_modecaps, m)) + continue; + + params_vht = &req->params[m]; + params = &req_in->params[m]; + + params_vht->rssi = params->rssi; + params_vht->rate = FROM_LEGACY(params->rate, m); + if (params_vht->rate == IEEE80211_RATE_NONEXISTENT) { + error = EINVAL; + goto end; + } + } + + for (m = IEEE80211_MODE_AUTO + 1; m < nitems(req->params); m++) { + if (isclr(ic->ic_modecaps, m)) + continue; + + vap->iv_roamparms[m].rssi = req->params[m].rssi; + vap->iv_roamparms[m].rate = req->params[m].rate; + } + +end: + IEEE80211_FREE(req, M_TEMP); + IEEE80211_FREE(req_in, M_TEMP); + + /* XXX? ENETRESET to push to device? */ + return (error); +#undef FROM_LEGACY +} + +static int +ieee80211_ioctl_setroam_vht(struct ieee80211vap *vap, + const struct ieee80211req *ireq) +{ + const struct ieee80211_rate_table *rt; + const struct ieee80211_rate_t *rate; + struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_roamparams_req_vht *req; + struct ieee80211_roamparam_vht *params; + int m, error; + if (ireq->i_len != sizeof(vap->iv_roamparms)) - return EINVAL; - /* XXX validate params */ + return (EINVAL); + + req = IEEE80211_MALLOC(sizeof(*req), M_TEMP, IEEE80211_M_NOWAIT); + if (req == NULL) + return (ENOMEM); + + error = copyin(ireq->i_data, req, sizeof(*req)); + if (error != 0) + goto end; + + /* Validate parameters. */ + for (m = IEEE80211_MODE_AUTO + 1; m < nitems(req->params); m++) { + if (isclr(ic->ic_modecaps, m)) + continue; + + rt = ieee80211_get_ratetable(m); + params = &req->params[m]; + + rate = ieee80211_get_rate_safe(params->rate); + if (!rate || !ieee80211_isratevalid(rt, rate)) { + error = EINVAL; + goto end; + } + } + + for (m = IEEE80211_MODE_AUTO + 1; m < nitems(req->params); m++) { + if (isclr(ic->ic_modecaps, m)) + continue; + + vap->iv_roamparms[m].rssi = req->params[m].rssi; + vap->iv_roamparms[m].rate = req->params[m].rate; + } + +end: + IEEE80211_FREE(req, M_TEMP); + /* XXX? ENETRESET to push to device? */ - return copyin(ireq->i_data, vap->iv_roamparms, - sizeof(vap->iv_roamparms)); + return (error); } static int -checkrate(const struct ieee80211_rateset *rs, int rate) +rate_to_index(uint8_t rate, uint16_t *rate_index, enum ieee80211_phymode mode) { - int i; + if (rate != IEEE80211_FIXED_RATE_NONE) { + *rate_index = ieee80211_convert_from_legacy_rate(rate, mode); + if (*rate_index == IEEE80211_RATE_NONEXISTENT) + return (-1); + } else + *rate_index = IEEE80211_RATE_NONEXISTENT; - if (rate == IEEE80211_FIXED_RATE_NONE) - return 1; - for (i = 0; i < rs->rs_nrates; i++) - if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == rate) - return 1; - return 0; + return (0); } static int -checkmcs(const struct ieee80211_htrateset *rs, int mcs) +checkrate(const struct ieee80211_rateset *rs, + const struct ieee80211_htrateset *rs_ht, + const struct ieee80211_htrateset *rs_vht, + uint16_t new_rate, uint16_t curr_rate, + enum ieee80211_phymode mode) { - int rate_val = IEEE80211_RV(mcs); - int i; + const struct ieee80211_rate_t *rate; + int is11n, is_vht, rv; - if (mcs == IEEE80211_FIXED_RATE_NONE) - return 1; - if ((mcs & IEEE80211_RATE_MCS) == 0) /* MCS always have 0x80 set */ - return 0; - for (i = 0; i < rs->rs_nrates; i++) - if (IEEE80211_RV(rs->rs_rates[i]) == rate_val) - return 1; - return 0; + is11n = (mode == IEEE80211_MODE_11NA || mode == IEEE80211_MODE_11NG); + is_vht = (mode == IEEE80211_MODE_VHT_2GHZ || + mode == IEEE80211_MODE_VHT_5GHZ); + + if (new_rate != curr_rate) { + if (new_rate == IEEE80211_RATE_NONEXISTENT) + return (1); + + rate = ieee80211_get_rate_safe(new_rate); + if (!rate) + return (-1); + + rv = rate->value; + if (rate->type == IEEE80211_T_VHT) + rv *= rate->props.ht.streams; + + switch (rate->type) { + case IEEE80211_T_VHT: + if (!is_vht || isclr(rs_vht->rs_bitmap, rv)) + return (-1); + + return (1); + case IEEE80211_T_HT: + if (!is11n || isclr(rs_ht->rs_bitmap, rv)) + return (-1); + + return (1); + default: + if (isclr(rs->rs_bitmap, rv)) + return (-1); + + return (1); + } + } + + return (0); } static int -ieee80211_ioctl_settxparams(struct ieee80211vap *vap, - const struct ieee80211req *ireq) +ieee80211_validate_txparams(struct ieee80211vap *vap, + const struct ieee80211_txparams_vht_req *parms, int nmodes) { +#define CHECK_RATE(_rs, _rs_ht, _rs_vht, _new, _old, _mode, _counter) do { \ + int _ret = checkrate((_rs), (_rs_ht), (_rs_vht), (_new), (_old), \ + (_mode)); \ + if (_ret < 0) \ + return (EINVAL); \ + _counter += _ret; \ +} while (0) struct ieee80211com *ic = vap->iv_ic; - struct ieee80211_txparams_req parms; /* XXX stack use? */ - struct ieee80211_txparam *src, *dst; - const struct ieee80211_htrateset *rs_ht; + const struct ieee80211_htrateset *rs_vht = &ic->ic_sup_vhtrates; + const struct ieee80211_htrateset *rs_ht = &ic->ic_sup_htrates; const struct ieee80211_rateset *rs; - int error, mode, changed, is11n, nmodes; + const struct ieee80211_txparam_vht *src; + struct ieee80211_txparam_vht *dst; + enum ieee80211_phymode mode; + int changed; - /* NB: accept short requests for backwards compat */ - if (ireq->i_len > sizeof(parms)) - return EINVAL; - error = copyin(ireq->i_data, &parms, ireq->i_len); - if (error != 0) - return error; - nmodes = ireq->i_len / sizeof(struct ieee80211_txparam); - changed = 0; /* validate parameters and check if anything changed */ + changed = 0; for (mode = IEEE80211_MODE_11A; mode < nmodes; mode++) { if (isclr(ic->ic_modecaps, mode)) continue; - src = &parms.params[mode]; + + src = &parms->params[mode]; dst = &vap->iv_txparms[mode]; - rs = &ic->ic_sup_rates[mode]; /* NB: 11n maps to legacy */ - rs_ht = &ic->ic_sup_htrates; - is11n = (mode == IEEE80211_MODE_11NA || - mode == IEEE80211_MODE_11NG); - if (src->ucastrate != dst->ucastrate) { - if (!checkrate(rs, src->ucastrate) && - (!is11n || !checkmcs(rs_ht, src->ucastrate))) - return EINVAL; - changed++; - } - if (src->mcastrate != dst->mcastrate) { - if (!checkrate(rs, src->mcastrate) && - (!is11n || !checkmcs(rs_ht, src->mcastrate))) - return EINVAL; - changed++; - } - if (src->mgmtrate != dst->mgmtrate) { - if (!checkrate(rs, src->mgmtrate) && - (!is11n || !checkmcs(rs_ht, src->mgmtrate))) - return EINVAL; - changed++; - } + rs = ic->ic_sup_rates[mode]; + + CHECK_RATE(rs, rs_ht, rs_vht, src->ucastrate, dst->ucastrate, + mode, changed); + CHECK_RATE(rs, rs_ht, rs_vht, src->mcastrate, dst->mcastrate, + mode, changed); + CHECK_RATE(rs, rs_ht, rs_vht, src->mgmtrate, dst->mgmtrate, + mode, changed); + if (src->maxretry != dst->maxretry) /* NB: no bounds */ changed++; } @@ -2301,15 +2531,102 @@ */ for (mode = IEEE80211_MODE_11A; mode < nmodes; mode++) { if (isset(ic->ic_modecaps, mode)) - vap->iv_txparms[mode] = parms.params[mode]; + vap->iv_txparms[mode] = parms->params[mode]; } - /* XXX could be more intelligent, - e.g. don't reset if setting not being used */ - return ENETRESET; + /* + * XXX could be more intelligent, + * e.g. don't reset if setting not being used + */ + return (ENETRESET); } - return 0; + return (0); +#undef CHECK_RATE } +static int +ieee80211_ioctl_settxparams(struct ieee80211vap *vap, + const struct ieee80211req *ireq) +{ +#define TO_INDEX(_rate, _index, _mode) do { \ + if (rate_to_index((_rate), (_index), (_mode)) != 0) { \ + error = EINVAL; \ + goto end; \ + } \ +} while (0) + struct ieee80211com *ic = vap->iv_ic; + const struct ieee80211_txparam *src; + struct ieee80211_txparams_vht_req *parms; + struct ieee80211_txparams_req *input; + struct ieee80211_txparam_vht *dst; + enum ieee80211_phymode mode; + int error, nmodes; + + /* NB: accept short requests for backwards compat */ + if (ireq->i_len > sizeof(*input)) + return (EINVAL); + + parms = IEEE80211_MALLOC(sizeof(*parms), M_TEMP, IEEE80211_M_NOWAIT); + if (parms == NULL) + return (ENOMEM); + + input = IEEE80211_MALLOC(sizeof(*input), M_TEMP, IEEE80211_M_NOWAIT); + if (input == NULL) { + IEEE80211_FREE(parms, M_TEMP); + return (ENOMEM); + } + + error = copyin(ireq->i_data, input, ireq->i_len); + if (error != 0) + goto end; + nmodes = ireq->i_len / sizeof(struct ieee80211_txparam); + + /* convert parameters to the new format */ + for (mode = IEEE80211_MODE_11A; mode < nmodes; mode++) { + if (isclr(ic->ic_modecaps, mode)) + continue; + + src = &input->params[mode]; + dst = &parms->params[mode]; + + TO_INDEX(src->ucastrate, &dst->ucastrate, mode); + TO_INDEX(src->mcastrate, &dst->mcastrate, mode); + TO_INDEX(src->mgmtrate, &dst->mgmtrate, mode); + dst->maxretry = src->maxretry; + } + + error = ieee80211_validate_txparams(vap, parms, nmodes); +end: + IEEE80211_FREE(input, M_TEMP); + IEEE80211_FREE(parms, M_TEMP); + return (error); +} + +static int +ieee80211_ioctl_settxparams_vht(struct ieee80211vap *vap, + const struct ieee80211req *ireq) +{ + struct ieee80211_txparams_vht_req *parms; + int error, nmodes; + + /* NB: accept short requests for backwards compat */ + if (ireq->i_len > sizeof(*parms)) + return (EINVAL); + + parms = IEEE80211_MALLOC(sizeof(*parms), M_TEMP, IEEE80211_M_NOWAIT); + if (parms == NULL) + return (ENOMEM); + + error = copyin(ireq->i_data, parms, ireq->i_len); + if (error != 0) + goto end; + + nmodes = ireq->i_len / sizeof(struct ieee80211_txparam_vht); + error = ieee80211_validate_txparams(vap, parms, nmodes); +end: + IEEE80211_FREE(parms, M_TEMP); + return (error); +} + /* * Application Information Element support. */ @@ -3247,11 +3564,17 @@ case IEEE80211_IOC_REGDOMAIN: error = ieee80211_ioctl_setregdomain(vap, ireq); break; - case IEEE80211_IOC_ROAM: + case IEEE80211_IOC_ROAM: /* legacy, use ROAM_VHT instead */ error = ieee80211_ioctl_setroam(vap, ireq); break; - case IEEE80211_IOC_TXPARAMS: + case IEEE80211_IOC_ROAM_VHT: + error = ieee80211_ioctl_setroam_vht(vap, ireq); + break; + case IEEE80211_IOC_TXPARAMS: /* legacy, use TXPARAMS_VHT instead */ error = ieee80211_ioctl_settxparams(vap, ireq); + break; + case IEEE80211_IOC_TXPARAMS_VHT: + error = ieee80211_ioctl_settxparams_vht(vap, ireq); break; case IEEE80211_IOC_HTCOMPAT: if (ireq->i_val) { Index: sys/net80211/ieee80211_mesh.c =================================================================== --- sys/net80211/ieee80211_mesh.c +++ sys/net80211/ieee80211_mesh.c @@ -2683,8 +2683,9 @@ m->m_flags |= M_ENCAP; /* mark encapsulated */ memset(¶ms, 0, sizeof(params)); + params.ibp_vers = IEEE80211_BPF_VERSION_1; params.ibp_pri = WME_AC_VO; - params.ibp_rate0 = ni->ni_txparms->mgmtrate; + params.ibp_rate0 = IEEE80211_BPF_RATE(ni->ni_txparms->mgmtrate); if (IEEE80211_IS_MULTICAST(da)) params.ibp_try0 = 1; else @@ -3297,22 +3298,23 @@ { #define M_BITS 8 #define S_FACTOR (2 * M_BITS) - struct ieee80211com *ic = ni->ni_ic; + const struct ieee80211_rate_t *rate; struct ifnet *ifp = ni->ni_vap->iv_ifp; const static int nbits = 8192 << M_BITS; - uint32_t overhead, rate, errrate; + uint32_t overhead, errrate; uint64_t res; /* Time to transmit a frame */ - rate = ni->ni_txrate; - overhead = ieee80211_compute_duration(ic->ic_rt, - ifp->if_mtu + IEEE80211_MESH_MAXOVERHEAD, rate, 0) << M_BITS; + rate = ieee80211_get_rate(ni->ni_txrate); + overhead = ieee80211_compute_duration(ni->ni_txrate, + ifp->if_mtu + IEEE80211_MESH_MAXOVERHEAD, + IEEE80211_GET_CHAN_FLAGS(ni->ni_chan), 0) << M_BITS; /* Error rate in percentage */ /* XXX assuming small failures are ok */ errrate = (((ifp->if_get_counter(ifp, IFCOUNTER_OERRORS) + ifp->if_get_counter(ifp, IFCOUNTER_IERRORS)) / 100) << M_BITS) / 100; - res = (overhead + (nbits / rate)) * + res = (overhead + (nbits / rate->value)) * ((1 << S_FACTOR) / ((1 << M_BITS) - errrate)); return (uint32_t)(res >> S_FACTOR); Index: sys/net80211/ieee80211_node.h =================================================================== --- sys/net80211/ieee80211_node.h +++ sys/net80211/ieee80211_node.h @@ -159,7 +159,7 @@ #define IEEE80211_NODE_AR 0x0010 /* AR capable */ #define IEEE80211_NODE_BOOST 0x0080 /* Dynamic Turbo boosted */ uint16_t ni_ath_defkeyix;/* Atheros def key index */ - const struct ieee80211_txparam *ni_txparms; + const struct ieee80211_txparam_vht *ni_txparms; uint32_t ni_jointime; /* time of join (secs) */ uint32_t *ni_challenge; /* shared-key challenge */ struct ieee80211_ies ni_ies; /* captured ie's */ @@ -238,6 +238,7 @@ uint8_t ni_vht_chanwidth; /* IEEE80211_VHT_CHANWIDTH_ */ uint8_t ni_vht_pad1; uint32_t ni_vht_spare[8]; + struct ieee80211_htrateset ni_vhtrates; /* negotiated VHT rate set */ /* fast-frames state */ struct mbuf * ni_tx_superg[WME_NUM_TID]; @@ -245,7 +246,7 @@ /* others */ short ni_inact; /* inactivity mark count */ short ni_inact_reload;/* inactivity reload value */ - int ni_txrate; /* legacy rate/MCS */ + uint16_t ni_txrate; /* global rate index */ struct ieee80211_psq ni_psq; /* power save queue */ struct ieee80211_nodestats ni_stats; /* per-node statistics */ Index: sys/net80211/ieee80211_node.c =================================================================== --- sys/net80211/ieee80211_node.c +++ sys/net80211/ieee80211_node.c @@ -289,12 +289,16 @@ ni->ni_chan = chan; mode = ieee80211_chan2mode(chan); + if (IEEE80211_IS_CHAN_VHT(chan)) { + /* Install VHT rate set. */ + ni->ni_vhtrates = *ieee80211_get_supvhtrates(ic); + } if (IEEE80211_IS_CHAN_HT(chan)) { /* * We must install the legacy rate est in ni_rates and the * HT rate set in ni_htrates. */ - ni->ni_htrates = *ieee80211_get_suphtrates(ic, chan); + ni->ni_htrates = *ieee80211_get_suphtrates(ic); /* * Setup bss tx parameters based on operating mode. We * use legacy rates when operating in a mixed HT+non-HT bss @@ -311,7 +315,7 @@ mode = IEEE80211_MODE_11B; } ni->ni_txparms = &vap->iv_txparms[mode]; - ni->ni_rates = *ieee80211_get_suprates(ic, chan); + ni->ni_rates = *ic->ic_sup_rates[mode]; } static __inline void @@ -480,7 +484,7 @@ check_bss(struct ieee80211vap *vap, struct ieee80211_node *ni) { struct ieee80211com *ic = ni->ni_ic; - uint8_t rate; + int ret; if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan))) return 0; @@ -499,9 +503,10 @@ if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) return 0; } - rate = ieee80211_fix_rate(ni, &ni->ni_rates, - IEEE80211_F_JOIN | IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE); - if (rate & IEEE80211_RATE_BASIC) + ret = ieee80211_fix_rate(ni, &ni->ni_rates, + IEEE80211_F_JOIN | IEEE80211_F_DONEGO | + IEEE80211_F_DOFIXED | IEEE80211_F_RATE_LEGACY); + if (ret & IEEE80211_F_RATESET_ERROR) return 0; if (vap->iv_des_nssid != 0 && !match_ssid(ni, vap->iv_des_nssid, vap->iv_des_ssid)) @@ -520,8 +525,7 @@ check_bss_debug(struct ieee80211vap *vap, struct ieee80211_node *ni) { struct ieee80211com *ic = ni->ni_ic; - uint8_t rate; - int fail; + int ret, fail; fail = 0; if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan))) @@ -541,10 +545,13 @@ if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) fail |= 0x04; } - rate = ieee80211_fix_rate(ni, &ni->ni_rates, - IEEE80211_F_JOIN | IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE); - if (rate & IEEE80211_RATE_BASIC) + ret = ieee80211_fix_rate(ni, &ni->ni_rates, + IEEE80211_F_JOIN | IEEE80211_F_DONEGO | + IEEE80211_F_DOFIXED | IEEE80211_F_RATE_LEGACY); + if (ret & IEEE80211_F_RATESET_ERROR) { fail |= 0x08; + ret &= ~IEEE80211_F_RATESET_ERROR; /* for printf */ + } if (vap->iv_des_nssid != 0 && !match_ssid(ni, vap->iv_des_nssid, vap->iv_des_ssid)) fail |= 0x10; @@ -556,8 +563,11 @@ printf(" %s%c", ether_sprintf(ni->ni_bssid), fail & 0x20 ? '!' : ' '); printf(" %3d%c", ieee80211_chan2ieee(ic, ni->ni_chan), fail & 0x01 ? '!' : ' '); - printf(" %2dM%c", (rate & IEEE80211_RATE_VAL) / 2, - fail & 0x08 ? '!' : ' '); + if (ret != IEEE80211_RATE_NONEXISTENT) + printf(" %2dM%c", ieee80211_convert_to_legacy_rate(ret) / 2, + fail & 0x08 ? '!' : ' '); + else + printf(" %c", fail & 0x08 ? '!' : ' '); printf(" %4s%c", (ni->ni_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" : (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" : @@ -767,7 +777,7 @@ if (c != ic->ic_curchan) { ic->ic_curchan = c; ic->ic_curmode = ieee80211_chan2mode(ic->ic_curchan); - ic->ic_rt = ieee80211_get_ratetable(ic->ic_curchan); + ic->ic_rt = ieee80211_get_ratetable(ic->ic_curmode); IEEE80211_UNLOCK(ic); ic->ic_set_channel(ic); ieee80211_radiotap_chan_change(ic); @@ -808,7 +818,7 @@ ic->ic_bsschan = ic->ic_curchan = c; ic->ic_curmode = ieee80211_chan2mode(ic->ic_curchan); - ic->ic_rt = ieee80211_get_ratetable(ic->ic_curchan); + ic->ic_rt = ieee80211_get_ratetable(ic->ic_curmode); } /* @@ -872,7 +882,8 @@ * that the negotiated rate set is acceptable. */ ieee80211_fix_rate(vap->iv_bss, &vap->iv_bss->ni_rates, - IEEE80211_F_DODEL | IEEE80211_F_JOIN); + IEEE80211_F_DODEL | IEEE80211_F_JOIN | + IEEE80211_F_RATE_LEGACY); ieee80211_setcurchan(ic, selbs->ni_chan); /* @@ -1023,7 +1034,7 @@ ieee80211_ht_updateparams_final(ni, ni->ni_ies.htcap_ie, ni->ni_ies.htinfo_ie); ieee80211_setup_htrates(ni, ni->ni_ies.htcap_ie, - IEEE80211_F_JOIN | IEEE80211_F_DOBRS); + IEEE80211_F_JOIN); ieee80211_setup_basic_htrates(ni, ni->ni_ies.htinfo_ie); } @@ -1416,8 +1427,6 @@ IEEE80211_NOTE(vap, IEEE80211_MSG_INACT, ni, "%s: inact_reload %u", __func__, ni->ni_inact_reload); - ieee80211_ratectl_node_init(ni); - return ni; } @@ -1795,7 +1804,7 @@ /* NB: must be after ni_chan is setup */ ieee80211_setup_rates(ni, sp->rates, sp->xrates, - IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE | + IEEE80211_F_DOSORT | IEEE80211_F_DOFIXED | IEEE80211_F_DONEGO | IEEE80211_F_DODEL); /* @@ -1832,9 +1841,8 @@ */ ieee80211_ht_updateparams_final(ni, ni->ni_ies.htcap_ie, ni->ni_ies.htinfo_ie); - ieee80211_setup_htrates(ni, - ni->ni_ies.htcap_ie, - IEEE80211_F_JOIN | IEEE80211_F_DOBRS); + ieee80211_setup_htrates(ni, ni->ni_ies.htcap_ie, + IEEE80211_F_JOIN); ieee80211_setup_basic_htrates(ni, ni->ni_ies.htinfo_ie); Index: sys/net80211/ieee80211_output.c =================================================================== --- sys/net80211/ieee80211_output.c +++ sys/net80211/ieee80211_output.c @@ -614,7 +614,7 @@ const struct sockaddr *dst, struct route *ro) { #define senderr(e) do { error = (e); goto bad;} while (0) - const struct ieee80211_bpf_params *params = NULL; + struct ieee80211_bpf_params params; struct ieee80211_node *ni = NULL; struct ieee80211vap *vap; struct ieee80211_frame *wh; @@ -667,9 +667,9 @@ * NB: we assume sa_data is suitably aligned to cast. */ if (dst->sa_len != 0) - params = (const struct ieee80211_bpf_params *)dst->sa_data; + memcpy(¶ms, dst->sa_data, sizeof(params)); - error = ieee80211_validate_frame(m, params); + error = ieee80211_validate_frame(m, ¶ms); if (error != 0) senderr(error); @@ -698,6 +698,28 @@ ni = ieee80211_ref_node(vap->iv_bss); } + if (dst->sa_len && params.ibp_vers == IEEE80211_BPF_VERSION) { +#define TO_RATE_INDEX(r, mode) \ + IEEE80211_BPF_RATE(ieee80211_convert_from_legacy_rate((r), (mode))) + + const struct ieee80211_channel *chan; + enum ieee80211_phymode mode; + + chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ? + ni->ni_chan : ic->ic_curchan; + mode = ieee80211_chan2mode(chan); + + /* Convert legacy rates to rate indices. */ + params.ibp_rate0 = TO_RATE_INDEX(params.ibp_rate0, mode); + params.ibp_rate1 = TO_RATE_INDEX(params.ibp_rate1, mode); + params.ibp_rate2 = TO_RATE_INDEX(params.ibp_rate2, mode); + params.ibp_rate3 = TO_RATE_INDEX(params.ibp_rate3, mode); + params.ibp_ctsrate = TO_RATE_INDEX(params.ibp_ctsrate, mode); + + params.ibp_vers = IEEE80211_BPF_VERSION_1; +#undef TO_RATE_INDEX + } + /* * Sanitize mbuf for net80211 flags leaked from above. * @@ -726,7 +748,7 @@ IEEE80211_NODE_STAT(ni, tx_ucast); IEEE80211_TX_LOCK(ic); - ret = ieee80211_raw_output(vap, ni, m, params); + ret = ieee80211_raw_output(vap, ni, m, dst->sa_len ? ¶ms : NULL); IEEE80211_TX_UNLOCK(ic); return (ret); bad: @@ -1910,15 +1932,24 @@ uint8_t * ieee80211_add_rates(uint8_t *frm, const struct ieee80211_rateset *rs) { - int nrates; + const struct ieee80211_rate_t *rate; + uint8_t i, nrates, value; *frm++ = IEEE80211_ELEMID_RATES; nrates = rs->rs_nrates; if (nrates > IEEE80211_RATE_SIZE) nrates = IEEE80211_RATE_SIZE; *frm++ = nrates; - memcpy(frm, rs->rs_rates, nrates); - return frm + nrates; + for (i = 0; i < nrates; i++) { + rate = ieee80211_get_rate(rs->rates[i].rs_index); + + value = rate->value; + if (rs->rates[i].rs_basic) + value |= IEEE80211_RATE_BASIC; + + *frm++ = value; + } + return frm; } /* @@ -1927,15 +1958,25 @@ uint8_t * ieee80211_add_xrates(uint8_t *frm, const struct ieee80211_rateset *rs) { + const struct ieee80211_rate_t *rate; + uint8_t i, value; + /* * Add an extended supported rates element if operating in 11g mode. */ if (rs->rs_nrates > IEEE80211_RATE_SIZE) { - int nrates = rs->rs_nrates - IEEE80211_RATE_SIZE; *frm++ = IEEE80211_ELEMID_XRATES; - *frm++ = nrates; - memcpy(frm, rs->rs_rates + IEEE80211_RATE_SIZE, nrates); - frm += nrates; + *frm++ = rs->rs_nrates - IEEE80211_RATE_SIZE; + + for (i = IEEE80211_RATE_SIZE; i < rs->rs_nrates; i++) { + rate = ieee80211_get_rate(rs->rates[i].rs_index); + + value = rate->value; + if (rs->rates[i].rs_basic) + value |= IEEE80211_RATE_BASIC; + + *frm++ = value; + } } return frm; } @@ -2241,7 +2282,7 @@ struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; struct ieee80211_node *bss; - const struct ieee80211_txparam *tp; + const struct ieee80211_txparam_vht *tp; struct ieee80211_bpf_params params; const struct ieee80211_rateset *rs; struct mbuf *m; @@ -2378,9 +2419,10 @@ ssidlen, ssid); memset(¶ms, 0, sizeof(params)); + params.ibp_vers = IEEE80211_BPF_VERSION_1; params.ibp_pri = M_WME_GETAC(m); tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; - params.ibp_rate0 = tp->mgmtrate; + params.ibp_rate0 = IEEE80211_BPF_RATE(tp->mgmtrate); if (IEEE80211_IS_MULTICAST(da)) { params.ibp_flags |= IEEE80211_BPF_NOACK; params.ibp_try0 = 1; @@ -2783,8 +2825,9 @@ } /* NB: force non-ProbeResp frames to the highest queue */ + params.ibp_vers = IEEE80211_BPF_VERSION_1; params.ibp_pri = WME_AC_VO; - params.ibp_rate0 = bss->ni_txparms->mgmtrate; + params.ibp_rate0 = IEEE80211_BPF_RATE(bss->ni_txparms->mgmtrate); /* NB: we know all frames are unicast */ params.ibp_try0 = bss->ni_txparms->maxretry; params.ibp_power = bss->ni_txpower; @@ -3093,12 +3136,13 @@ */ struct mbuf * ieee80211_alloc_prot(struct ieee80211_node *ni, const struct mbuf *m, - uint8_t rate, int prot) + uint16_t rate_idx, int prot) { struct ieee80211com *ic = ni->ni_ic; const struct ieee80211_frame *wh; struct mbuf *mprot; - uint16_t dur; + uint32_t chan_flags; + uint16_t dur, ack_dur; int pktlen, isshort; KASSERT(prot == IEEE80211_PROT_RTSCTS || @@ -3108,12 +3152,18 @@ wh = mtod(m, const struct ieee80211_frame *); pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN; isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0; - dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort) - + ieee80211_ack_duration(ic->ic_rt, rate, isshort); + if (ni->ni_chan != NULL && ni->ni_chan != IEEE80211_CHAN_ANYC) + chan_flags = ni->ni_chan->ic_flags; + else + chan_flags = 0; + ack_dur = ieee80211_ack_duration(ic->ic_rt->ctl_rates, rate_idx, + isshort); + dur = ieee80211_compute_duration(rate_idx, pktlen, chan_flags, isshort) + + ack_dur; if (prot == IEEE80211_PROT_RTSCTS) { /* NB: CTS is the same size as an ACK */ - dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort); + dur += ack_dur; mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur); } else mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur); Index: sys/net80211/ieee80211_phy.h =================================================================== --- sys/net80211/ieee80211_phy.h +++ sys/net80211/ieee80211_phy.h @@ -2,6 +2,7 @@ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2007-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2018 Andriy Voskoboinyk * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -64,86 +65,196 @@ */ #define IEEE80211_DUR_DIFS(sifs, slot) ((sifs) + 2 * (slot)) -struct ieee80211_channel; +#define IEEE80211_CTL_RATE_TABLES 6 +#define IEEE80211_CTL_RATE_VALUES_MAX 256 +#define IEEE80211_CTL_RATE_TABLE_SIZE 256 -#define IEEE80211_RATE_TABLE_SIZE 128 +/* + * Some commonly used rate indices. + * All but NONEXISTENT must be checked in ieee80211_recheck_rate_indices(). + */ +#define IEEE80211_RATE_INDEX_CCK1 2 +#define IEEE80211_RATE_INDEX_CCK2 3 +#define IEEE80211_RATE_INDEX_CCK5 4 +#define IEEE80211_RATE_INDEX_CCK11 5 +#define IEEE80211_RATE_INDEX_PBCC22 6 +#define IEEE80211_RATE_INDEX_OFDM6 8 +#define IEEE80211_RATE_INDEX_OFDM9 9 +#define IEEE80211_RATE_INDEX_OFDM12 10 +#define IEEE80211_RATE_INDEX_OFDM18 11 +#define IEEE80211_RATE_INDEX_OFDM24 12 +#define IEEE80211_RATE_INDEX_OFDM36 13 +#define IEEE80211_RATE_INDEX_OFDM48 14 +#define IEEE80211_RATE_INDEX_OFDM54 15 +#define IEEE80211_RATE_INDEX_HALF6 18 +#define IEEE80211_RATE_INDEX_QUART3 26 +#define IEEE80211_RATE_INDEX_HT(i) (40 + (i)) +#define IEEE80211_RATE_INDEX_VHT(i, c) \ + (117 + (i) + IEEE80211_VHT_MCS_CHAIN * ((c) - 1)) +#define IEEE80211_RATE_NONEXISTENT (uint16_t)-1 -struct ieee80211_rate_table { - int rateCount; /* NB: for proper padding */ - uint8_t rateCodeToIndex[256]; /* back mapping */ +#define IEEE80211_RATES_COUNT 197 +#define IEEE80211_RATES_BYTES howmany(IEEE80211_RATES_COUNT, NBBY) + +extern const struct ieee80211_rate_t *ieee80211_rates; +extern uint16_t + ieee80211_rate_lookup_table[IEEE80211_T_MAX][IEEE80211_RATE_VALUE_MAX]; + +struct ieee80211_ctl_rate_params { + /* list of global rate indexes available here */ + uint8_t localRates[IEEE80211_CTL_RATE_VALUES_MAX]; + /* global index -> local (precedence) index */ + uint16_t rateIndices[IEEE80211_CTL_RATE_VALUES_MAX]; + struct { - uint8_t phy; /* CCK/OFDM/TURBO */ - uint32_t rateKbps; /* transfer rate in kbs */ - uint8_t shortPreamble; /* mask for enabling short - * preamble in CCK rate code */ - uint8_t dot11Rate; /* value for supported rates - * info element of MLME */ - uint8_t ctlRateIndex; /* index of next lower basic - * rate; used for dur. calcs */ - uint16_t lpAckDuration; /* long preamble ACK dur. */ - uint16_t spAckDuration; /* short preamble ACK dur. */ - } info[IEEE80211_RATE_TABLE_SIZE]; + struct ieee80211_rate_t ctlRate; /* next lower basic rate; + * used for dur. calcs */ + uint16_t ackDuration[2]; /* long / short preamble + * ACK dur. */ + } info[IEEE80211_CTL_RATE_TABLE_SIZE]; }; +struct ieee80211_rate_table { + uint8_t types[IEEE80211_T_MAX]; /* included rate types */ + const struct ieee80211_ctl_rate_params *ctl_rates; +}; + +struct ieee80211_channel; + +#define IEEE80211_GET_CHAN_FLAGS(_c) \ + (((_c) != NULL && (_c) != IEEE80211_CHAN_ANYC) ? (_c)->ic_flags : 0) + +uint32_t ieee80211_get_rateKbps(const struct ieee80211_rate_t *, + uint32_t, int); +char * ieee80211_rate_to_string(uint16_t, uint32_t, int, char *, int); + +const struct ieee80211_rateset *ieee80211_get_def_rateset( + const enum ieee80211_phymode); +const struct ieee80211_rateset *ieee80211_get_basic_rateset( + const enum ieee80211_phymode); const struct ieee80211_rate_table *ieee80211_get_ratetable( - struct ieee80211_channel *); + const enum ieee80211_phymode); -static __inline__ uint8_t -ieee80211_ack_rate(const struct ieee80211_rate_table *rt, uint8_t rate) +uint16_t ieee80211_convert_from_legacy_rate(uint8_t, + enum ieee80211_phymode); +uint8_t ieee80211_convert_to_legacy_rate(uint16_t); + + +static __inline__ const struct ieee80211_rate_t * +ieee80211_get_rate(uint16_t index) { - /* - * XXX Assert this is for a legacy rate; not for an MCS rate. - * If the caller wishes to use it for a basic rate, they should - * clear the high bit first. - */ - KASSERT(! (rate & 0x80), ("rate %d is basic/mcs?", rate)); - uint8_t cix = rt->info[rt->rateCodeToIndex[rate & IEEE80211_RATE_VAL]].ctlRateIndex; - KASSERT(cix != (uint8_t)-1, ("rate %d has no info", rate)); - return rt->info[cix].dot11Rate; + KASSERT(index < IEEE80211_RATES_COUNT, + ("out-of-bounds access to the ieee80211_rates[] array (index %u)", + index)); + + return (&ieee80211_rates[index]); } +static __inline__ const struct ieee80211_rate_t * +ieee80211_get_rate_safe(uint16_t index) +{ + + if (index >= IEEE80211_RATES_COUNT) + return (NULL); + + return (ieee80211_get_rate(index)); +} + +static __inline__ int +ieee80211_lookup_rate_index(uint8_t type, uint8_t value) +{ + + KASSERT(type < IEEE80211_T_MAX && value < IEEE80211_RATE_VALUE_MAX, + ("out-of-bounds access: type %u, value %u\n", type, value)); + + return (ieee80211_rate_lookup_table[type][value]); +} + +static __inline__ int +ieee80211_get_rate_index_no_check(const struct ieee80211_rate_t *rate) +{ + + KASSERT(rate->type != IEEE80211_T_VHT, + ("use ieee80211_get_anyrate_index_no_check() instead")); + + return (ieee80211_lookup_rate_index(rate->type, rate->value)); +} + +static __inline__ int +ieee80211_get_rate_index(const struct ieee80211_rate_t *rate) +{ + int index = ieee80211_get_rate_index_no_check(rate); + + KASSERT(index != IEEE80211_RATE_NONEXISTENT, + ("no valid index for rate %u/%u", rate->type, rate->value)); + + return (index); +} + +/* + * The same as above, but with VHT rates handling. + */ +static __inline__ int +ieee80211_get_anyrate_index_no_check(const struct ieee80211_rate_t *rate) +{ + uint8_t idx2; + + if (rate->type == IEEE80211_T_VHT) + idx2 = rate->value * rate->props.ht.streams; + else + idx2 = rate->value; + + return (ieee80211_lookup_rate_index(rate->type, idx2)); +} + +static __inline__ int +ieee80211_get_anyrate_index(const struct ieee80211_rate_t *rate) +{ + int index = ieee80211_get_anyrate_index_no_check(rate); + + KASSERT(index != IEEE80211_RATE_NONEXISTENT, + ("no valid index for rate %u/%u", rate->type, rate->value)); + + return (index); +} + +static __inline__ uint32_t +ieee80211_get_rateKbps_by_idx(uint16_t index, uint32_t chan_flags, int shortgi) +{ + const struct ieee80211_rate_t *rate = ieee80211_get_rate(index); + + return ieee80211_get_rateKbps(rate, chan_flags, shortgi); +} + static __inline__ uint8_t -ieee80211_ctl_rate(const struct ieee80211_rate_table *rt, uint8_t rate) +ieee80211_legacy_rate_lookup(const struct ieee80211_ctl_rate_params *rp, + uint16_t index) { - /* - * XXX Assert this is for a legacy rate; not for an MCS rate. - * If the caller wishes to use it for a basic rate, they should - * clear the high bit first. - */ - KASSERT(! (rate & 0x80), ("rate %d is basic/mcs?", rate)); - uint8_t cix = rt->info[rt->rateCodeToIndex[rate & IEEE80211_RATE_VAL]].ctlRateIndex; - KASSERT(cix != (uint8_t)-1, ("rate %d has no info", rate)); - return rt->info[cix].dot11Rate; + return (rp->rateIndices[index]); } -static __inline__ enum ieee80211_phytype -ieee80211_rate2phytype(const struct ieee80211_rate_table *rt, uint8_t rate) +static __inline__ const struct ieee80211_rate_t * +ieee80211_ack_rate(const struct ieee80211_ctl_rate_params *rp, uint16_t index) { - /* - * XXX Assert this is for a legacy rate; not for an MCS rate. - * If the caller wishes to use it for a basic rate, they should - * clear the high bit first. - */ - KASSERT(! (rate & 0x80), ("rate %d is basic/mcs?", rate)); - uint8_t rix = rt->rateCodeToIndex[rate & IEEE80211_RATE_VAL]; - KASSERT(rix != (uint8_t)-1, ("rate %d has no info", rate)); - return rt->info[rix].phy; + return &rp->info[index].ctlRate; } +static __inline__ const struct ieee80211_rate_t * +ieee80211_ctl_rate(const struct ieee80211_ctl_rate_params *rp, uint16_t index) +{ + + return &rp->info[index].ctlRate; +} + static __inline__ int -ieee80211_isratevalid(const struct ieee80211_rate_table *rt, uint8_t rate) +ieee80211_isratevalid(const struct ieee80211_rate_table *rt, + const struct ieee80211_rate_t *rate) { - /* - * XXX Assert this is for a legacy rate; not for an MCS rate. - * If the caller wishes to use it for a basic rate, they should - * clear the high bit first. - */ - KASSERT(! (rate & 0x80), ("rate %d is basic/mcs?", rate)); - return rt->rateCodeToIndex[rate] != (uint8_t)-1; + return (rt->types[rate->type]); } /* @@ -153,40 +264,30 @@ * sent using rate, phy and short preamble setting. */ static __inline__ uint16_t -ieee80211_ack_duration(const struct ieee80211_rate_table *rt, - uint8_t rate, int isShortPreamble) +ieee80211_ack_duration(const struct ieee80211_ctl_rate_params *rp, + uint16_t index, int isShortPreamble) { - uint8_t rix = rt->rateCodeToIndex[rate]; + uint16_t ack_duration; - KASSERT(rix != (uint8_t)-1, ("rate %d has no info", rate)); - if (isShortPreamble) { - KASSERT(rt->info[rix].spAckDuration != 0, - ("shpreamble ack dur is not computed!\n")); - return rt->info[rix].spAckDuration; - } else { - KASSERT(rt->info[rix].lpAckDuration != 0, - ("lgpreamble ack dur is not computed!\n")); - return rt->info[rix].lpAckDuration; - } -} + KASSERT(index < nitems(rp->info), ("out of range index value %u", + index)); -static __inline__ uint8_t -ieee80211_legacy_rate_lookup(const struct ieee80211_rate_table *rt, - uint8_t rate) -{ + isShortPreamble = (isShortPreamble != 0); + ack_duration = rp->info[index].ackDuration[isShortPreamble]; + KASSERT(ack_duration != 0, ("%spreamble ack dur is not computed!\n", + isShortPreamble ? "sh" : "lg")); - return (rt->rateCodeToIndex[rate & IEEE80211_RATE_VAL]); + return ack_duration; } /* * Compute the time to transmit a frame of length frameLen bytes - * using the specified 802.11 rate code, phy, and short preamble - * setting. + * using the specified 802.11 rate code, phy, channel width, + * guard interval and short preamble setting. * * NB: SIFS is included. */ -uint16_t ieee80211_compute_duration(const struct ieee80211_rate_table *, - uint32_t frameLen, uint16_t rate, int isShortPreamble); +uint16_t ieee80211_compute_duration(uint16_t, uint32_t, uint32_t, int); /* * Convert PLCP signal/rate field to 802.11 rate code (.5Mbits/s) */ @@ -197,16 +298,11 @@ uint8_t ieee80211_rate2plcp(int, enum ieee80211_phytype); /* - * 802.11n rate manipulation. + * 802.11n legacy rate manipulation. */ #define IEEE80211_HT_RC_2_MCS(_rc) ((_rc) & 0x1f) #define IEEE80211_HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1) -#define IEEE80211_IS_HT_RATE(_rc) ( (_rc) & IEEE80211_RATE_MCS) - -uint32_t ieee80211_compute_duration_ht(uint32_t frameLen, - uint16_t rate, int streams, int isht40, - int isShortGI); #endif /* _KERNEL */ #endif /* !_NET80211_IEEE80211_PHY_H_ */ Index: sys/net80211/ieee80211_phy.c =================================================================== --- sys/net80211/ieee80211_phy.c +++ sys/net80211/ieee80211_phy.c @@ -2,6 +2,7 @@ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2007-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2018 Andriy Voskoboinyk * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -49,362 +50,787 @@ #include #include +#include -#ifdef notyet -struct ieee80211_ds_plcp_hdr { - uint8_t i_signal; - uint8_t i_service; - uint16_t i_length; - uint16_t i_crc; -} __packed; -#endif /* notyet */ +const struct ieee80211_rate_t *ieee80211_rates = ieee80211_rates_all; -/* shorthands to compact tables for readability */ -#define OFDM IEEE80211_T_OFDM -#define CCK IEEE80211_T_CCK -#define TURBO IEEE80211_T_TURBO -#define HALF IEEE80211_T_OFDM_HALF -#define QUART IEEE80211_T_OFDM_QUARTER -#define HT IEEE80211_T_HT -/* XXX the 11n and the basic rate flag are unfortunately overlapping. Grr. */ -#define N(r) (IEEE80211_RATE_MCS | r) -#define PBCC (IEEE80211_T_OFDM_QUARTER+1) /* XXX */ -#define B(r) (IEEE80211_RATE_BASIC | r) -#define Mb(x) (x*1000) +_Static_assert(nitems(ieee80211_rates_all) == IEEE80211_RATES_COUNT, + "adjust IEEE80211_RATES_COUNT variable"); +_Static_assert(IEEE80211_RATES_COUNT <= IEEE80211_CTL_RATE_TABLE_SIZE, + "increase IEEE80211_CTL_RATE_TABLE_SIZE constant"); -static struct ieee80211_rate_table ieee80211_11b_table = { - .rateCount = 4, /* XXX no PBCC */ - .info = { -/* short ctrl */ -/* Preamble dot11Rate Rate */ - [0] = { .phy = CCK, 1000, 0x00, B(2), 0 },/* 1 Mb */ - [1] = { .phy = CCK, 2000, 0x04, B(4), 1 },/* 2 Mb */ - [2] = { .phy = CCK, 5500, 0x04, B(11), 1 },/* 5.5 Mb */ - [3] = { .phy = CCK, 11000, 0x04, B(22), 1 },/* 11 Mb */ - [4] = { .phy = PBCC, 22000, 0x04, 44, 3 } /* 22 Mb */ - }, -}; -static struct ieee80211_rate_table ieee80211_11g_table = { - .rateCount = 12, - .info = { -/* short ctrl */ -/* Preamble dot11Rate Rate */ - [0] = { .phy = CCK, 1000, 0x00, B(2), 0 }, - [1] = { .phy = CCK, 2000, 0x04, B(4), 1 }, - [2] = { .phy = CCK, 5500, 0x04, B(11), 2 }, - [3] = { .phy = CCK, 11000, 0x04, B(22), 3 }, - [4] = { .phy = OFDM, 6000, 0x00, 12, 4 }, - [5] = { .phy = OFDM, 9000, 0x00, 18, 4 }, - [6] = { .phy = OFDM, 12000, 0x00, 24, 6 }, - [7] = { .phy = OFDM, 18000, 0x00, 36, 6 }, - [8] = { .phy = OFDM, 24000, 0x00, 48, 8 }, - [9] = { .phy = OFDM, 36000, 0x00, 72, 8 }, - [10] = { .phy = OFDM, 48000, 0x00, 96, 8 }, - [11] = { .phy = OFDM, 54000, 0x00, 108, 8 } - }, -}; +/* const */ +uint16_t + ieee80211_rate_lookup_table[IEEE80211_T_MAX][IEEE80211_RATE_VALUE_MAX]; -static struct ieee80211_rate_table ieee80211_11a_table = { - .rateCount = 8, - .info = { -/* short ctrl */ -/* Preamble dot11Rate Rate */ - [0] = { .phy = OFDM, 6000, 0x00, B(12), 0 }, - [1] = { .phy = OFDM, 9000, 0x00, 18, 0 }, - [2] = { .phy = OFDM, 12000, 0x00, B(24), 2 }, - [3] = { .phy = OFDM, 18000, 0x00, 36, 2 }, - [4] = { .phy = OFDM, 24000, 0x00, B(48), 4 }, - [5] = { .phy = OFDM, 36000, 0x00, 72, 4 }, - [6] = { .phy = OFDM, 48000, 0x00, 96, 4 }, - [7] = { .phy = OFDM, 54000, 0x00, 108, 4 } - }, -}; +_Static_assert(IEEE80211_RATES_COUNT < UINT16_MAX, + "use wider type for index in lookup table"); -static struct ieee80211_rate_table ieee80211_half_table = { - .rateCount = 8, - .info = { -/* short ctrl */ -/* Preamble dot11Rate Rate */ - [0] = { .phy = HALF, 3000, 0x00, B(6), 0 }, - [1] = { .phy = HALF, 4500, 0x00, 9, 0 }, - [2] = { .phy = HALF, 6000, 0x00, B(12), 2 }, - [3] = { .phy = HALF, 9000, 0x00, 18, 2 }, - [4] = { .phy = HALF, 12000, 0x00, B(24), 4 }, - [5] = { .phy = HALF, 18000, 0x00, 36, 4 }, - [6] = { .phy = HALF, 24000, 0x00, 48, 4 }, - [7] = { .phy = HALF, 27000, 0x00, 54, 4 } - }, -}; +/* const */ +static struct ieee80211_ctl_rate_params + ieee80211_ctl_rates[IEEE80211_CTL_RATE_TABLES]; -static struct ieee80211_rate_table ieee80211_quarter_table = { - .rateCount = 8, - .info = { -/* short ctrl */ -/* Preamble dot11Rate Rate */ - [0] = { .phy = QUART, 1500, 0x00, B(3), 0 }, - [1] = { .phy = QUART, 2250, 0x00, 4, 0 }, - [2] = { .phy = QUART, 3000, 0x00, B(9), 2 }, - [3] = { .phy = QUART, 4500, 0x00, 9, 2 }, - [4] = { .phy = QUART, 6000, 0x00, B(12), 4 }, - [5] = { .phy = QUART, 9000, 0x00, 18, 4 }, - [6] = { .phy = QUART, 12000, 0x00, 24, 4 }, - [7] = { .phy = QUART, 13500, 0x00, 27, 4 } - }, +#define IEEE80211_DEF_RATESET_TABLES 6 + +static const uint8_t mode_to_rateset[IEEE80211_MODE_MAX] = { + [IEEE80211_MODE_AUTO] = 5, + [IEEE80211_MODE_11B] = 0, + [IEEE80211_MODE_11G] = 1, + [IEEE80211_MODE_11A] = 2, + [IEEE80211_MODE_FH] = 5, + [IEEE80211_MODE_TURBO_A] = 2, + [IEEE80211_MODE_TURBO_G] = 1, + [IEEE80211_MODE_STURBO_A] = 2, + [IEEE80211_MODE_11NA] = 2, + [IEEE80211_MODE_11NG] = 1, + [IEEE80211_MODE_HALF] = 3, + [IEEE80211_MODE_QUARTER] = 4, + [IEEE80211_MODE_VHT_2GHZ] = 1, + [IEEE80211_MODE_VHT_5GHZ] = 2 }; -static struct ieee80211_rate_table ieee80211_turbog_table = { - .rateCount = 7, - .info = { -/* short ctrl */ -/* Preamble dot11Rate Rate */ - [0] = { .phy = TURBO, 12000, 0x00, B(12), 0 }, - [1] = { .phy = TURBO, 24000, 0x00, B(24), 1 }, - [2] = { .phy = TURBO, 36000, 0x00, 36, 1 }, - [3] = { .phy = TURBO, 48000, 0x00, B(48), 3 }, - [4] = { .phy = TURBO, 72000, 0x00, 72, 3 }, - [5] = { .phy = TURBO, 96000, 0x00, 96, 3 }, - [6] = { .phy = TURBO, 108000, 0x00, 108, 3 } - }, +/* const */ +static struct ieee80211_rateset + ieee80211_def_ratesets[IEEE80211_DEF_RATESET_TABLES]; +/* const */ +static struct ieee80211_rateset + ieee80211_def_ratesets_basic[IEEE80211_DEF_RATESET_TABLES]; + +static const struct ieee80211_rate_table ieee80211_rate_tables[] = { + [IEEE80211_MODE_11B] = { + .types = { [IEEE80211_T_CCK] = 1 }, + .ctl_rates = &ieee80211_ctl_rates[0] + }, + [IEEE80211_MODE_11G] = { + .types = { [IEEE80211_T_CCK] = 1, [IEEE80211_T_OFDM] = 1 }, + .ctl_rates = &ieee80211_ctl_rates[1] + }, + [IEEE80211_MODE_11A] = { + .types = { [IEEE80211_T_OFDM] = 1 }, + .ctl_rates = &ieee80211_ctl_rates[2] + }, + [IEEE80211_MODE_HALF] = { + .types = { [IEEE80211_T_OFDM_HALF] = 1 }, + .ctl_rates = &ieee80211_ctl_rates[3] + }, + [IEEE80211_MODE_QUARTER] = { + .types = { [IEEE80211_T_OFDM_QUARTER] = 1 }, + .ctl_rates = &ieee80211_ctl_rates[4] + }, + [IEEE80211_MODE_TURBO_G] = { + /* XXX include CCK? */ + .types = { [IEEE80211_T_TURBO] = 1 }, + .ctl_rates = &ieee80211_ctl_rates[5] + }, + [IEEE80211_MODE_TURBO_A] = { + .types = { [IEEE80211_T_TURBO] = 1 }, + .ctl_rates = &ieee80211_ctl_rates[5] + }, + /* the same as MODE_TURBO_A */ + [IEEE80211_MODE_STURBO_A] = { + .types = { [IEEE80211_T_TURBO] = 1 }, + .ctl_rates = &ieee80211_ctl_rates[5] + }, + [IEEE80211_MODE_11NG] = { + .types = { [IEEE80211_T_CCK] = 1, [IEEE80211_T_OFDM] = 1, + [IEEE80211_T_HT] = 1 }, + .ctl_rates = &ieee80211_ctl_rates[1] + }, + [IEEE80211_MODE_11NA] = { + .types = { [IEEE80211_T_OFDM] = 1, [IEEE80211_T_HT] = 1 }, + .ctl_rates = &ieee80211_ctl_rates[2] + }, + [IEEE80211_MODE_VHT_2GHZ] = { + .types = { [IEEE80211_T_CCK] = 1, [IEEE80211_T_OFDM] = 1, + [IEEE80211_T_VHT] = 1 }, + .ctl_rates = &ieee80211_ctl_rates[1] + }, + [IEEE80211_MODE_VHT_5GHZ] = { + .types = { [IEEE80211_T_OFDM] = 1, [IEEE80211_T_VHT] = 1 }, + .ctl_rates = &ieee80211_ctl_rates[2] + }, }; -static struct ieee80211_rate_table ieee80211_turboa_table = { - .rateCount = 8, - .info = { -/* short ctrl */ -/* Preamble dot11Rate Rate */ - [0] = { .phy = TURBO, 12000, 0x00, B(12), 0 }, - [1] = { .phy = TURBO, 18000, 0x00, 18, 0 }, - [2] = { .phy = TURBO, 24000, 0x00, B(24), 2 }, - [3] = { .phy = TURBO, 36000, 0x00, 36, 2 }, - [4] = { .phy = TURBO, 48000, 0x00, B(48), 4 }, - [5] = { .phy = TURBO, 72000, 0x00, 72, 4 }, - [6] = { .phy = TURBO, 96000, 0x00, 96, 4 }, - [7] = { .phy = TURBO, 108000, 0x00, 108, 4 } - }, +#define IEEE80211_HT_UNEQUAL_SHIFT 33 + +static const uint16_t ht_unequal_to_mbps[] = { + /* for HT20 channels (500 Kb units) */ + /* 2 streams */ + 78, 104, 130, 117, 156, 195, + /* 3 streams */ + 104, 130, 130, 156, 182, 182, 208, + 156, 195, 195, 234, 273, 273, 312, + /* 4 streams */ + 130, 156, 182, 156, 182, 208, 234, + 208, 234, 260, 260, 286, 195, 234, + 273, 234, 273, 312, 351, 312, 351, + 390, 390, 429 }; -static struct ieee80211_rate_table ieee80211_11ng_table = { - .rateCount = 36, - .info = { -/* short ctrl */ -/* Preamble dot11Rate Rate */ - [0] = { .phy = CCK, 1000, 0x00, B(2), 0 }, - [1] = { .phy = CCK, 2000, 0x04, B(4), 1 }, - [2] = { .phy = CCK, 5500, 0x04, B(11), 2 }, - [3] = { .phy = CCK, 11000, 0x04, B(22), 3 }, - [4] = { .phy = OFDM, 6000, 0x00, 12, 4 }, - [5] = { .phy = OFDM, 9000, 0x00, 18, 4 }, - [6] = { .phy = OFDM, 12000, 0x00, 24, 6 }, - [7] = { .phy = OFDM, 18000, 0x00, 36, 6 }, - [8] = { .phy = OFDM, 24000, 0x00, 48, 8 }, - [9] = { .phy = OFDM, 36000, 0x00, 72, 8 }, - [10] = { .phy = OFDM, 48000, 0x00, 96, 8 }, - [11] = { .phy = OFDM, 54000, 0x00, 108, 8 }, +uint32_t +ieee80211_get_rateKbps(const struct ieee80211_rate_t *rate, + uint32_t chan_flags, int shortgi) +{ +#define CHAN_WIDTH_MASK (IEEE80211_CHAN_HT | IEEE80211_CHAN_VHT) + uint8_t value = rate->value; - [12] = { .phy = HT, 6500, 0x00, N(0), 4 }, - [13] = { .phy = HT, 13000, 0x00, N(1), 6 }, - [14] = { .phy = HT, 19500, 0x00, N(2), 6 }, - [15] = { .phy = HT, 26000, 0x00, N(3), 8 }, - [16] = { .phy = HT, 39000, 0x00, N(4), 8 }, - [17] = { .phy = HT, 52000, 0x00, N(5), 8 }, - [18] = { .phy = HT, 58500, 0x00, N(6), 8 }, - [19] = { .phy = HT, 65000, 0x00, N(7), 8 }, + switch (rate->type) { + case IEEE80211_T_FH: + case IEEE80211_T_CCK: + case IEEE80211_T_PBCC: + case IEEE80211_T_OFDM: + case IEEE80211_T_OFDM_HALF: + return (value * 500); + case IEEE80211_T_OFDM_QUARTER: + if (value == 4) { + /* + * NB: cannot be represented exactly + * through the formula + */ + return (2250); + } else + return (value * 500); + case IEEE80211_T_TURBO: + return (value * 1000); + case IEEE80211_T_HT: + if (value >= 32) { + uint_fast32_t result; - [20] = { .phy = HT, 13000, 0x00, N(8), 4 }, - [21] = { .phy = HT, 26000, 0x00, N(9), 6 }, - [22] = { .phy = HT, 39000, 0x00, N(10), 6 }, - [23] = { .phy = HT, 52000, 0x00, N(11), 8 }, - [24] = { .phy = HT, 78000, 0x00, N(12), 8 }, - [25] = { .phy = HT, 104000, 0x00, N(13), 8 }, - [26] = { .phy = HT, 117000, 0x00, N(14), 8 }, - [27] = { .phy = HT, 130000, 0x00, N(15), 8 }, + if (rate->props.ht.unequal) { + value -= IEEE80211_HT_UNEQUAL_SHIFT; + result = ht_unequal_to_mbps[value] * 500; + } else { + KASSERT(value == 32, ("not MCS32 rate!")); + result = 6000; + } - [28] = { .phy = HT, 19500, 0x00, N(16), 4 }, - [29] = { .phy = HT, 39000, 0x00, N(17), 6 }, - [30] = { .phy = HT, 58500, 0x00, N(18), 6 }, - [31] = { .phy = HT, 78000, 0x00, N(19), 8 }, - [32] = { .phy = HT, 117000, 0x00, N(20), 8 }, - [33] = { .phy = HT, 156000, 0x00, N(21), 8 }, - [34] = { .phy = HT, 175500, 0x00, N(22), 8 }, - [35] = { .phy = HT, 195000, 0x00, N(23), 8 }, + if (rate->props.ht.no_20mhz && + !(chan_flags & IEEE80211_CHAN_HT40)) + return (0); - }, -}; + /* NB: try to keep precision */ + if (shortgi) { + if (chan_flags & IEEE80211_CHAN_HT40) + return (result * 30 / 13); + else + return (result * 10 / 9); + } else { + if (chan_flags & IEEE80211_CHAN_HT40) + return (result * 27 / 13); + else + return (result); + } + } -static struct ieee80211_rate_table ieee80211_11na_table = { - .rateCount = 32, - .info = { -/* short ctrl */ -/* Preamble dot11Rate Rate */ - [0] = { .phy = OFDM, 6000, 0x00, B(12), 0 }, - [1] = { .phy = OFDM, 9000, 0x00, 18, 0 }, - [2] = { .phy = OFDM, 12000, 0x00, B(24), 2 }, - [3] = { .phy = OFDM, 18000, 0x00, 36, 2 }, - [4] = { .phy = OFDM, 24000, 0x00, B(48), 4 }, - [5] = { .phy = OFDM, 36000, 0x00, 72, 4 }, - [6] = { .phy = OFDM, 48000, 0x00, 96, 4 }, - [7] = { .phy = OFDM, 54000, 0x00, 108, 4 }, + value = value % IEEE80211_HT_MCS_CHAIN; + /* FALLTHROUGH */ + case IEEE80211_T_VHT: + { + uint_fast32_t multiplier; - [8] = { .phy = HT, 6500, 0x00, N(0), 0 }, - [9] = { .phy = HT, 13000, 0x00, N(1), 2 }, - [10] = { .phy = HT, 19500, 0x00, N(2), 2 }, - [11] = { .phy = HT, 26000, 0x00, N(3), 4 }, - [12] = { .phy = HT, 39000, 0x00, N(4), 4 }, - [13] = { .phy = HT, 52000, 0x00, N(5), 4 }, - [14] = { .phy = HT, 58500, 0x00, N(6), 4 }, - [15] = { .phy = HT, 65000, 0x00, N(7), 4 }, + multiplier = rate->props.ht.streams; + switch (chan_flags & CHAN_WIDTH_MASK) { + case IEEE80211_CHAN_VHT160: + case IEEE80211_CHAN_VHT80_80: + if (rate->props.ht.no_160mhz) + return (0); - [16] = { .phy = HT, 13000, 0x00, N(8), 0 }, - [17] = { .phy = HT, 26000, 0x00, N(9), 2 }, - [18] = { .phy = HT, 39000, 0x00, N(10), 2 }, - [19] = { .phy = HT, 52000, 0x00, N(11), 4 }, - [20] = { .phy = HT, 78000, 0x00, N(12), 4 }, - [21] = { .phy = HT, 104000, 0x00, N(13), 4 }, - [22] = { .phy = HT, 117000, 0x00, N(14), 4 }, - [23] = { .phy = HT, 130000, 0x00, N(15), 4 }, + multiplier *= 58500; + break; - [24] = { .phy = HT, 19500, 0x00, N(16), 0 }, - [25] = { .phy = HT, 39000, 0x00, N(17), 2 }, - [26] = { .phy = HT, 58500, 0x00, N(18), 2 }, - [27] = { .phy = HT, 78000, 0x00, N(19), 4 }, - [28] = { .phy = HT, 117000, 0x00, N(20), 4 }, - [29] = { .phy = HT, 156000, 0x00, N(21), 4 }, - [30] = { .phy = HT, 175500, 0x00, N(22), 4 }, - [31] = { .phy = HT, 195000, 0x00, N(23), 4 }, + case IEEE80211_CHAN_VHT80: + if (rate->props.ht.no_80mhz) + return (0); - }, -}; + multiplier *= 29250; + break; -#undef Mb -#undef B -#undef OFDM -#undef HALF -#undef QUART -#undef CCK -#undef TURBO -#undef XR -#undef HT -#undef N + case IEEE80211_CHAN_VHT40: + case IEEE80211_CHAN_VHT40U: + case IEEE80211_CHAN_VHT40D: + if (rate->props.ht.no_40mhz) + return (0); + /* FALLTHROUGH */ + case IEEE80211_CHAN_HT40: + case IEEE80211_CHAN_HT40U: + case IEEE80211_CHAN_HT40D: + multiplier *= 13500; + break; + + case IEEE80211_CHAN_VHT20: + case IEEE80211_CHAN_HT20: + default: + multiplier *= 6500; + break; + } + + if (shortgi) + multiplier = multiplier * 10 / 9; + + switch (value) { + case 0: + case 1: + case 2: + case 3: + return ((value + 1) * multiplier); + case 4: + return ((value + 2) * multiplier); + case 5: + case 6: + case 7: + return ((value + 3) * multiplier); + case 8: + KASSERT(rate->type == IEEE80211_T_VHT, + ("wrong type %u for rate %u", rate->type, value)); + return ((value + 4) * multiplier); + case 9: + KASSERT(rate->type == IEEE80211_T_VHT, + ("wrong type %u for rate %u", rate->type, value)); + return ((value + 3) * multiplier * 10 / 9); + default: + break; + } + } + default: + break; + } + + return (0); +#undef CHAN_WIDTH_MASK +} + +char * +ieee80211_rate_to_string(uint16_t rate_index, uint32_t chan_flags, int shortgi, + char *buf, int buflen) +{ + char mbps_str[10]; + const struct ieee80211_rate_t *rate; + int kbps; + + rate = ieee80211_get_rate(rate_index); + kbps = ieee80211_get_rateKbps(rate, chan_flags, shortgi); + + switch (kbps % 1000) { + case 250: + snprintf(mbps_str, sizeof(mbps_str), "%d.25", kbps / 1000); + break; + case 500: + snprintf(mbps_str, sizeof(mbps_str), "%d.5", kbps / 1000); + break; + default: + snprintf(mbps_str, sizeof(mbps_str), "%d", kbps / 1000); + break; + } + + switch (rate->type) { + case IEEE80211_T_FH: + snprintf(buf, buflen, "FH: %u (%s MBps)", + rate->value, mbps_str); + break; + case IEEE80211_T_CCK: + snprintf(buf, buflen, "CCK: %u (%s MBps)", + rate->value, mbps_str); + break; + case IEEE80211_T_PBCC: + snprintf(buf, buflen, "PBCC: %u (%s MBps)", + rate->value, mbps_str); + break; + case IEEE80211_T_OFDM: + snprintf(buf, buflen, "OFDM: %u (%s MBps)", + rate->value, mbps_str); + break; + case IEEE80211_T_OFDM_HALF: + snprintf(buf, buflen, "OFDM/2: %u (%s MBps)", + rate->value, mbps_str); + break; + case IEEE80211_T_OFDM_QUARTER: + snprintf(buf, buflen, "OFDM/4: %u (%s MBps)", + rate->value, mbps_str); + break; + case IEEE80211_T_TURBO: + snprintf(buf, buflen, "TURBO: %u (%s MBps)", + rate->value, mbps_str); + break; + case IEEE80211_T_HT: + snprintf(buf, buflen, "HT: MCS %u / %u stream%s (%s MBps)", + rate->value, rate->props.ht.streams, + rate->props.ht.streams != 1 ? "s" : "", mbps_str); + break; + case IEEE80211_T_VHT: + snprintf(buf, buflen, "VHT: MCS %u / %u stream%s (%s MBps)", + rate->value, rate->props.ht.streams, + rate->props.ht.streams != 1 ? "s" : "", mbps_str); + break; + default: + /* NOTREACHED */ + snprintf(buf, buflen, ": value %u", + rate->value); + break; + } + + return (buf); +} + +static void +ieee80211_recheck_rate_indices(void) +{ +#if defined(IEEE80211_DEBUG) || defined(INVARIANTS) +#define CHECK_RATE_VALUE(_rv, _suffix) \ + case _rv: \ + KASSERT(i == IEEE80211_RATE_INDEX_##_suffix, \ + ("wrong rate index %u for rate %u (idx %u)", \ + IEEE80211_RATE_INDEX_##_suffix, _rv, i)); \ + break; + + const struct ieee80211_rate_t *rate; + uint16_t rindex; + int i; + + for (i = 0; i < IEEE80211_RATES_COUNT; i++) { + rate = &ieee80211_rates[i]; + + switch (rate->type) { + case IEEE80211_T_CCK: + switch (rate->value) { + CHECK_RATE_VALUE(2, CCK1); + CHECK_RATE_VALUE(4, CCK2); + CHECK_RATE_VALUE(11, CCK5); + CHECK_RATE_VALUE(22, CCK11); + default: + break; + } + break; + case IEEE80211_T_PBCC: + switch (rate->value) { + CHECK_RATE_VALUE(44, PBCC22); + default: + break; + } + break; + case IEEE80211_T_OFDM: + switch (rate->value) { + CHECK_RATE_VALUE(12, OFDM6); + CHECK_RATE_VALUE(18, OFDM9); + CHECK_RATE_VALUE(24, OFDM12); + CHECK_RATE_VALUE(36, OFDM18); + CHECK_RATE_VALUE(48, OFDM24); + CHECK_RATE_VALUE(72, OFDM36); + CHECK_RATE_VALUE(96, OFDM48); + CHECK_RATE_VALUE(108, OFDM54); + default: + break; + } + break; + case IEEE80211_T_OFDM_HALF: + switch (rate->value) { + CHECK_RATE_VALUE(12, HALF6); + default: + break; + } + break; + case IEEE80211_T_OFDM_QUARTER: + switch (rate->value) { + CHECK_RATE_VALUE(6, QUART3); + default: + break; + } + break; + case IEEE80211_T_HT: + rindex = IEEE80211_RATE_INDEX_HT(rate->value); + KASSERT(rindex == i, + ("RATE_INDEX_HT macro is broken (%d != %d)", + rindex, i)); + break; + case IEEE80211_T_VHT: + rindex = IEEE80211_RATE_INDEX_VHT(rate->value, + rate->props.ht.streams); + KASSERT(rindex == i, + ("RATE_INDEX_VHT macro is broken (%d != %d)", + rindex, i)); + break; + default: + break; + } + } +#undef CHECK_RATE_VALUE +#endif +} + +static void +ieee80211_init_glbl_mapping_table(void) +{ + const struct ieee80211_rate_t *rate; + int glbl_idx, value; + + memset(ieee80211_rate_lookup_table, 0xff, + sizeof(ieee80211_rate_lookup_table)); + + for (glbl_idx = 0; glbl_idx < IEEE80211_RATES_COUNT; glbl_idx++) { + rate = &ieee80211_rates[glbl_idx]; + if (rate->type != IEEE80211_T_VHT) + value = rate->value; + else + value = rate->value * rate->props.ht.streams; + + KASSERT(rate->type < nitems(ieee80211_rate_lookup_table) && + value < nitems(ieee80211_rate_lookup_table[0]), + ("lookup table is too small")); + + ieee80211_rate_lookup_table[rate->type][value] = glbl_idx; + } +} + /* - * Setup a rate table's reverse lookup table and fill in - * ack durations. The reverse lookup tables are assumed - * to be initialized to zero (or at least the first entry). - * We use this as a key that indicates whether or not - * we've previously setup the reverse lookup table. - * - * XXX not reentrant, but shouldn't matter + * Setup a rate table's present indices table and fill in + * ack durations. Nonexistent entries are initialized to + * 0xff. */ static void -ieee80211_setup_ratetable(struct ieee80211_rate_table *rt) +ieee80211_init_ctl_params(void) { -#define WLAN_CTRL_FRAME_SIZE \ +#define ACK_SZ \ (sizeof(struct ieee80211_frame_ack) + IEEE80211_CRC_LEN) +#define END_OF_THE_TABLE (uint8_t)-1 - int i; + const struct ieee80211_rate_table superset[] = { + /* 11b rates only */ + [0] = { .types = { [IEEE80211_T_CCK] = 1 } }, + /* 11g / 11ng / 11ac+g */ + [1] = { .types = { [IEEE80211_T_CCK] = 1, + [IEEE80211_T_OFDM] = 1, + [IEEE80211_T_HT] = 1, + [IEEE80211_T_VHT] = 1 } }, + /* 11a / 11na / 11ac+a */ + [2] = { .types = { [IEEE80211_T_OFDM] = 1, + [IEEE80211_T_HT] = 1, + [IEEE80211_T_VHT] = 1 } }, + /* half rates */ + [3] = { .types = { [IEEE80211_T_OFDM_HALF] = 1 } }, + /* quarter rates */ + [4] = { .types = { [IEEE80211_T_OFDM_QUARTER] = 1 } }, + /* turbo rates */ + [5] = { .types = { [IEEE80211_T_TURBO] = 1 } } + }; - for (i = 0; i < nitems(rt->rateCodeToIndex); i++) - rt->rateCodeToIndex[i] = (uint8_t) -1; - for (i = 0; i < rt->rateCount; i++) { - uint8_t code = rt->info[i].dot11Rate; - uint8_t cix = rt->info[i].ctlRateIndex; - uint8_t ctl_rate = rt->info[cix].dot11Rate; + /* XXX there must some more elegant way */ + const uint8_t ctl_rates[IEEE80211_CTL_RATE_TABLES][192] = { + [0] = { /* CCK */ + 0, 1, 1, 1, END_OF_THE_TABLE }, + [1] = { /* CCK */ + 0, 1, 2, 3, + /* OFDM */ + 4, 4, 6, 6, 8, 8, 8, 8, + /* HT */ + 4, 6, 6, 8, 8, 8, 8, 8, + 4, 6, 6, 8, 8, 8, 8, 8, + 4, 6, 6, 8, 8, 8, 8, 8, + 4, 6, 6, 8, 8, 8, 8, 8, + /* XXX recheck */ + 4, + 4, 6, 6, 8, 8, 8, + 4, 6, 6, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, + 4, 6, 6, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + /* VHT */ + /* XXX copy-pasted from HT table */ + 4, 6, 6, 8, 8, 8, 8, 8, 8, 8, + 4, 6, 6, 8, 8, 8, 8, 8, 8, 8, + 4, 6, 6, 8, 8, 8, 8, 8, 8, 8, + 4, 6, 6, 8, 8, 8, 8, 8, 8, 8, + 4, 6, 6, 8, 8, 8, 8, 8, 8, 8, + 4, 6, 6, 8, 8, 8, 8, 8, 8, 8, + 4, 6, 6, 8, 8, 8, 8, 8, 8, 8, + 4, 6, 6, 8, 8, 8, 8, 8, 8, 8, END_OF_THE_TABLE }, + [2] = { /* OFDM */ + 0, 0, 2, 2, 4, 4, 4, 4, + /* HT */ + 0, 2, 2, 4, 4, 4, 4, 4, + 0, 2, 2, 4, 4, 4, 4, 4, + 0, 2, 2, 4, 4, 4, 4, 4, + 0, 2, 2, 4, 4, 4, 4, 4, + /* XXX recheck */ + 0, + 0, 2, 2, 4, 4, 4, + 0, 2, 2, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, + 0, 2, 2, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + /* VHT */ + /* XXX copy-pasted from HT table */ + 0, 2, 2, 4, 4, 4, 4, 4, 4, 4, + 0, 2, 2, 4, 4, 4, 4, 4, 4, 4, + 0, 2, 2, 4, 4, 4, 4, 4, 4, 4, + 0, 2, 2, 4, 4, 4, 4, 4, 4, 4, + 0, 2, 2, 4, 4, 4, 4, 4, 4, 4, + 0, 2, 2, 4, 4, 4, 4, 4, 4, 4, + 0, 2, 2, 4, 4, 4, 4, 4, 4, 4, + 0, 2, 2, 4, 4, 4, 4, 4, 4, 4, END_OF_THE_TABLE }, + [3] = { /* OFDM / 2 */ + 0, 0, 2, 2, 4, 4, 4, 4, END_OF_THE_TABLE }, + [4] = { /* OFDM / 4 */ + 0, 0, 2, 2, 4, 4, 4, 4, END_OF_THE_TABLE }, + [5] = { /* TURBO */ + 0, 0, 2, 2, 4, 4, 4, 4, END_OF_THE_TABLE } + }; + int ctl_idx; - /* - * Map without the basic rate bit. - * - * It's up to the caller to ensure that the basic - * rate bit is stripped here. - * - * For HT, use the MCS rate bit. - */ - code &= IEEE80211_RATE_VAL; - if (rt->info[i].phy == IEEE80211_T_HT) { - code |= IEEE80211_RATE_MCS; + for (ctl_idx = 0; ctl_idx < nitems(ieee80211_ctl_rates); ctl_idx++) { + struct ieee80211_ctl_rate_params *params; + uint16_t glbl_idx; + uint8_t local_idx; + + params = &ieee80211_ctl_rates[ctl_idx]; + local_idx = 0; + + /* pre-init the table */ + memset(params, END_OF_THE_TABLE, sizeof(*params)); + + for (glbl_idx = 0; + glbl_idx < IEEE80211_RATES_COUNT; + glbl_idx++) { + const struct ieee80211_rate_t *rate, *ctl_rate; + uint8_t ctl_rate_idx; + + rate = &ieee80211_rates[glbl_idx]; + if (!superset[ctl_idx].types[rate->type]) + continue; + + ctl_rate_idx = ctl_rates[ctl_idx][local_idx]; + KASSERT(ctl_rate_idx != END_OF_THE_TABLE, + ("no control rate available for rate %u/%u (%u) " + "(id %u, local %u)", rate->type, rate->value, + glbl_idx, ctl_idx, local_idx)); + + /* Need to be assigned before ctrl rate lookup */ + params->rateIndices[glbl_idx] = local_idx; + params->localRates[local_idx] = glbl_idx; + + ctl_rate_idx = params->localRates[ctl_rate_idx]; + ctl_rate = &ieee80211_rates[ctl_rate_idx]; + memcpy(¶ms->info[glbl_idx].ctlRate, ctl_rate, + sizeof(*ctl_rate)); + + params->info[glbl_idx].ackDuration[0] = + ieee80211_compute_duration(ctl_rate_idx, + ACK_SZ, 0, 0); + params->info[glbl_idx].ackDuration[1] = + ieee80211_compute_duration(ctl_rate_idx, + ACK_SZ, 0, 1); + + local_idx++; } + } +#undef ACK_SZ +} - /* XXX assume the control rate is non-MCS? */ - ctl_rate &= IEEE80211_RATE_VAL; - rt->rateCodeToIndex[code] = i; +static void +ieee80211_init_rateset(struct ieee80211_rateset *rs, const uint8_t *types) +{ + uint16_t glbl_idx; - /* - * XXX for 11g the control rate to use for 5.5 and 11 Mb/s - * depends on whether they are marked as basic rates; - * the static tables are setup with an 11b-compatible - * 2Mb/s rate which will work but is suboptimal - * - * NB: Control rate is always less than or equal to the - * current rate, so control rate's reverse lookup entry - * has been installed and following call is safe. - */ - rt->info[i].lpAckDuration = ieee80211_compute_duration(rt, - WLAN_CTRL_FRAME_SIZE, ctl_rate, 0); - rt->info[i].spAckDuration = ieee80211_compute_duration(rt, - WLAN_CTRL_FRAME_SIZE, ctl_rate, IEEE80211_F_SHPREAMBLE); + for (glbl_idx = 0; glbl_idx < IEEE80211_RATES_COUNT; glbl_idx++) { + const struct ieee80211_rate_t *rate; + + rate = &ieee80211_rates[glbl_idx]; + if (!types[rate->type]) + continue; + + KASSERT(rs->rs_nrates < nitems(rs->rates), ("index overflow")); + KASSERT(rate->value / NBBY < sizeof(rs->rs_bitmap), + ("bitmap overflow")); + + setbit(rs->rs_bitmap, rate->value); + rs->rates[rs->rs_nrates++].rs_index = glbl_idx; } +} -#undef WLAN_CTRL_FRAME_SIZE +static void +ieee80211_init_rateset_basic(struct ieee80211_rateset *rs, + const enum ieee80211_phymode mode) +{ +#define ADDRATE(_type, _value) do { \ + setbit(rs->rs_bitmap, (_value)); \ + rs->rates[rs->rs_nrates].rs_index = \ + ieee80211_rate_lookup_table[(_type)][(_value)]; \ + rs->rates[rs->rs_nrates].rs_basic = 1; \ + rs->rs_nrates++; \ +} while (0) + + switch (mode) { + case IEEE80211_MODE_11B: + ADDRATE(IEEE80211_T_CCK, 2); + ADDRATE(IEEE80211_T_CCK, 4); + break; + case IEEE80211_MODE_11G: + ADDRATE(IEEE80211_T_CCK, 2); + ADDRATE(IEEE80211_T_CCK, 4); + ADDRATE(IEEE80211_T_CCK, 11); + ADDRATE(IEEE80211_T_CCK, 22); + break; + case IEEE80211_MODE_11A: + ADDRATE(IEEE80211_T_OFDM, 12); + ADDRATE(IEEE80211_T_OFDM, 24); + ADDRATE(IEEE80211_T_OFDM, 48); + break; + case IEEE80211_MODE_HALF: + ADDRATE(IEEE80211_T_OFDM_HALF, 6); + ADDRATE(IEEE80211_T_OFDM_HALF, 12); + ADDRATE(IEEE80211_T_OFDM_HALF, 24); + break; + case IEEE80211_MODE_QUARTER: + ADDRATE(IEEE80211_T_OFDM_QUARTER, 3); + ADDRATE(IEEE80211_T_OFDM_QUARTER, 6); + ADDRATE(IEEE80211_T_OFDM_QUARTER, 12); + break; + default: + /* NOTREACHED */ + break; + } } -/* Setup all rate tables */ +/* + * Init tables for non-HT/VHT rates. + */ static void -ieee80211_phy_init(void) +ieee80211_init_rateset_tables(void) { - static struct ieee80211_rate_table * const ratetables[] = { - &ieee80211_half_table, - &ieee80211_quarter_table, - &ieee80211_11na_table, - &ieee80211_11ng_table, - &ieee80211_turbog_table, - &ieee80211_turboa_table, - &ieee80211_11a_table, - &ieee80211_11g_table, - &ieee80211_11b_table + const enum ieee80211_phymode modes[nitems(ieee80211_def_ratesets)] = { + IEEE80211_MODE_11B, IEEE80211_MODE_11G, IEEE80211_MODE_11A, + IEEE80211_MODE_HALF, IEEE80211_MODE_QUARTER, IEEE80211_MODE_FH }; int i; - for (i = 0; i < nitems(ratetables); ++i) - ieee80211_setup_ratetable(ratetables[i]); + /* XXX keep FH table zeroed for now */ + for (i = 0; i < nitems(modes) - 1; i++) { + struct ieee80211_rateset *rs, *rs_basic; + const uint8_t *types; + rs = &ieee80211_def_ratesets[i]; + rs_basic = &ieee80211_def_ratesets_basic[i]; + types = ieee80211_rate_tables[modes[i]].types; + + ieee80211_init_rateset(rs, types); + ieee80211_init_rateset_basic(rs_basic, modes[i]); + + ieee80211_setbasicrates(rs, modes[i]); + } } + +/* Setup all rate tables */ +static void +ieee80211_phy_init(void) +{ + ieee80211_recheck_rate_indices(); + ieee80211_init_glbl_mapping_table(); + ieee80211_init_ctl_params(); + ieee80211_init_rateset_tables(); +} SYSINIT(wlan_phy, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_phy_init, NULL); +const struct ieee80211_rateset * +ieee80211_get_def_rateset(const enum ieee80211_phymode mode) +{ + int index; + + KASSERT(mode < nitems(mode_to_rateset), + ("unknown mode %d (array size %zu)", mode, + nitems(mode_to_rateset))); + index = mode_to_rateset[mode]; + + return &ieee80211_def_ratesets[index]; +} + +const struct ieee80211_rateset * +ieee80211_get_basic_rateset(const enum ieee80211_phymode mode) +{ + int index; + + KASSERT(mode < nitems(mode_to_rateset), + ("unknown mode %d (array size %zu)", mode, + nitems(mode_to_rateset))); + index = mode_to_rateset[mode]; + + return &ieee80211_def_ratesets_basic[index]; +} + const struct ieee80211_rate_table * -ieee80211_get_ratetable(struct ieee80211_channel *c) +ieee80211_get_ratetable(const enum ieee80211_phymode mode) { - const struct ieee80211_rate_table *rt; - /* XXX HT */ - if (IEEE80211_IS_CHAN_HALF(c)) - rt = &ieee80211_half_table; - else if (IEEE80211_IS_CHAN_QUARTER(c)) - rt = &ieee80211_quarter_table; - else if (IEEE80211_IS_CHAN_HTA(c)) - rt = &ieee80211_11na_table; - else if (IEEE80211_IS_CHAN_HTG(c)) - rt = &ieee80211_11ng_table; - else if (IEEE80211_IS_CHAN_108G(c)) - rt = &ieee80211_turbog_table; - else if (IEEE80211_IS_CHAN_ST(c)) - rt = &ieee80211_turboa_table; - else if (IEEE80211_IS_CHAN_TURBO(c)) - rt = &ieee80211_turboa_table; - else if (IEEE80211_IS_CHAN_A(c)) - rt = &ieee80211_11a_table; - else if (IEEE80211_IS_CHAN_ANYG(c)) - rt = &ieee80211_11g_table; - else if (IEEE80211_IS_CHAN_B(c)) - rt = &ieee80211_11b_table; - else { - /* NB: should not get here */ - panic("%s: no rate table for channel; freq %u flags 0x%x\n", - __func__, c->ic_freq, c->ic_flags); + if (mode >= nitems(ieee80211_rate_tables)) + panic("%s: no rate table for mode %d\n", __func__, mode); + + return &ieee80211_rate_tables[mode]; +} + +uint16_t +ieee80211_convert_from_legacy_rate(uint8_t value, enum ieee80211_phymode mode) +{ + const struct ieee80211_rate_table *rs = &ieee80211_rate_tables[mode]; + uint16_t index; + int type, mcs_bit; + + mcs_bit = value & IEEE80211_RATE_MCS; + value = IEEE80211_RV(value); + + /* NB: value is lower than IEEE80211_RATE_VALUE_MAX */ + if (mcs_bit) { + /* NB: no VHT support here */ + if (!rs->types[IEEE80211_T_HT]) + return (IEEE80211_RATE_NONEXISTENT); + + return (ieee80211_rate_lookup_table[IEEE80211_T_HT][value]); } - return rt; + + for (type = 0; type < nitems(rs->types); type++) { + if (type == IEEE80211_T_HT || type == IEEE80211_T_VHT) + continue; + + if (!rs->types[type]) + continue; + + index = ieee80211_rate_lookup_table[type][value]; + if (index != IEEE80211_RATE_NONEXISTENT) + return (index); + } + + return (IEEE80211_RATE_NONEXISTENT); } +uint8_t +ieee80211_convert_to_legacy_rate(uint16_t rate_index) +{ + const struct ieee80211_rate_t *rate; + + rate = ieee80211_get_rate(rate_index); + + switch (rate->type) { + case IEEE80211_T_FH: + case IEEE80211_T_OFDM: + case IEEE80211_T_CCK: + case IEEE80211_T_PBCC: + case IEEE80211_T_TURBO: + case IEEE80211_T_OFDM_HALF: + case IEEE80211_T_OFDM_QUARTER: + return (rate->value); + case IEEE80211_T_HT: + return (rate->value | IEEE80211_RATE_MCS); + case IEEE80211_T_VHT: + /* nevermind, it does not supported. */ + return (0); + default: + KASSERT(0, ("%s: unknown rate type %d\n", __func__, + rate->type)); + return (0); + } +} + /* * Convert PLCP signal/rate field to 802.11 rate (.5Mbits/s) * @@ -495,32 +921,41 @@ #define TURBO_PLCP_BITS 22 #define TURBO_SYMBOL_TIME 4 +#define HT_L_STF 8 +#define HT_L_LTF 8 +#define HT_L_SIG 4 +#define HT_SIG 8 +#define HT_STF 4 +#define HT_LTF(n) ((n) * 4) + /* * Compute the time to transmit a frame of length frameLen bytes * using the specified rate, phy, and short preamble setting. * SIFS is included. */ uint16_t -ieee80211_compute_duration(const struct ieee80211_rate_table *rt, - uint32_t frameLen, uint16_t rate, int isShortPreamble) +ieee80211_compute_duration(uint16_t rate_idx, uint32_t frameLen, + uint32_t chan_flags, int is_short) { - uint8_t rix = rt->rateCodeToIndex[rate]; + const struct ieee80211_rate_t *rate; uint32_t bitsPerSymbol, numBits, numSymbols, phyTime, txTime; uint32_t kbps; - KASSERT(rix != (uint8_t)-1, ("rate %d has no info", rate)); - kbps = rt->info[rix].rateKbps; - if (kbps == 0) /* XXX bandaid for channel changes */ - return 0; + rate = ieee80211_get_rate(rate_idx); + kbps = ieee80211_get_rateKbps(rate, chan_flags, is_short); + if (kbps == 0) { + panic("%s: wrong rate info (rate %u/%u)\n", __func__, + rate->type, rate->value); + } - switch (rt->info[rix].phy) { + switch (rate->type) { case IEEE80211_T_CCK: phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS; - if (isShortPreamble && rt->info[rix].shortPreamble) + if (is_short && rate->props.cck.short_preamble) phyTime >>= 1; numBits = frameLen << 3; txTime = CCK_SIFS_TIME + phyTime - + ((numBits * 1000)/kbps); + + ((numBits * 1000) / kbps); break; case IEEE80211_T_OFDM: bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000; @@ -534,7 +969,7 @@ break; case IEEE80211_T_OFDM_HALF: bitsPerSymbol = (kbps * OFDM_HALF_SYMBOL_TIME) / 1000; - KASSERT(bitsPerSymbol != 0, ("1/4 rate bps")); + KASSERT(bitsPerSymbol != 0, ("1/2 rate bps")); numBits = OFDM_PLCP_BITS + (frameLen << 3); numSymbols = howmany(numBits, bitsPerSymbol); @@ -544,7 +979,7 @@ break; case IEEE80211_T_OFDM_QUARTER: bitsPerSymbol = (kbps * OFDM_QUARTER_SYMBOL_TIME) / 1000; - KASSERT(bitsPerSymbol != 0, ("1/2 rate bps")); + KASSERT(bitsPerSymbol != 0, ("1/4 rate bps")); numBits = OFDM_PLCP_BITS + (frameLen << 3); numSymbols = howmany(numBits, bitsPerSymbol); @@ -562,65 +997,53 @@ txTime = TURBO_SIFS_TIME + TURBO_PREAMBLE_TIME + (numSymbols * TURBO_SYMBOL_TIME); break; + case IEEE80211_T_HT: + bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000; + KASSERT(bitsPerSymbol != 0, ("ht bps")); + + numBits = OFDM_PLCP_BITS + (frameLen << 3); + numSymbols = howmany(numBits, bitsPerSymbol); + txTime = HT_L_STF + HT_L_LTF + HT_L_SIG + + HT_SIG + HT_STF + + HT_LTF(rate->props.ht.streams) + + (numSymbols * OFDM_SYMBOL_TIME); + break; + case IEEE80211_T_VHT: + /* XXX TODO */ default: panic("%s: unknown phy %u (rate %u)\n", __func__, - rt->info[rix].phy, rate); + rate->type, rate->value); } return txTime; } -static const uint16_t ht20_bps[32] = { - 26, 52, 78, 104, 156, 208, 234, 260, - 52, 104, 156, 208, 312, 416, 468, 520, - 78, 156, 234, 312, 468, 624, 702, 780, - 104, 208, 312, 416, 624, 832, 936, 1040 -}; -static const uint16_t ht40_bps[32] = { - 54, 108, 162, 216, 324, 432, 486, 540, - 108, 216, 324, 432, 648, 864, 972, 1080, - 162, 324, 486, 648, 972, 1296, 1458, 1620, - 216, 432, 648, 864, 1296, 1728, 1944, 2160 -}; - - -#define OFDM_PLCP_BITS 22 -#define HT_L_STF 8 -#define HT_L_LTF 8 -#define HT_L_SIG 4 -#define HT_SIG 8 -#define HT_STF 4 -#define HT_LTF(n) ((n) * 4) - -/* - * Calculate the transmit duration of an 11n frame. - */ -uint32_t -ieee80211_compute_duration_ht(uint32_t frameLen, uint16_t rate, - int streams, int isht40, int isShortGI) -{ - uint32_t bitsPerSymbol, numBits, numSymbols, txTime; - - KASSERT(rate & IEEE80211_RATE_MCS, ("not mcs %d", rate)); - KASSERT((rate &~ IEEE80211_RATE_MCS) < 31, ("bad mcs 0x%x", rate)); - - if (isht40) - bitsPerSymbol = ht40_bps[rate & 0x1f]; - else - bitsPerSymbol = ht20_bps[rate & 0x1f]; - numBits = OFDM_PLCP_BITS + (frameLen << 3); - numSymbols = howmany(numBits, bitsPerSymbol); - if (isShortGI) - txTime = ((numSymbols * 18) + 4) / 5; /* 3.6us */ - else - txTime = numSymbols * 4; /* 4us */ - return txTime + HT_L_STF + HT_L_LTF + - HT_L_SIG + HT_SIG + HT_STF + HT_LTF(streams); -} - #undef HT_LTF #undef HT_STF #undef HT_SIG #undef HT_L_SIG #undef HT_L_LTF #undef HT_L_STF + +#undef TURBO_SYMBOL_TIME +#undef TURBO_PLCP_BITS +#undef TURBO_PREAMBLE_TIME +#undef TURBO_SIFS_TIME + +#undef OFDM_QUARTER_SYMBOL_TIME +#undef OFDM_QUARTER_PLCP_BITS +#undef OFDM_QUARTER_PREAMBLE_TIME +#undef OFDM_QUARTER_SIFS_TIME + +#undef OFDM_HALF_SYMBOL_TIME +#undef OFDM_HALF_PLCP_BITS +#undef OFDM_HALF_PREAMBLE_TIME +#undef OFDM_HALF_SIFS_TIME + +#undef OFDM_SYMBOL_TIME #undef OFDM_PLCP_BITS +#undef OFDM_PREAMBLE_TIME +#undef OFDM_SIFS_TIME + +#undef CCK_PLCP_BITS +#undef CCK_PREAMBLE_BITS +#undef CCK_SIFS_TIME Index: sys/net80211/ieee80211_proto.h =================================================================== --- sys/net80211/ieee80211_proto.h +++ sys/net80211/ieee80211_proto.h @@ -141,7 +141,7 @@ struct mbuf *ieee80211_alloc_cts(struct ieee80211com *, const uint8_t [IEEE80211_ADDR_LEN], uint16_t); struct mbuf *ieee80211_alloc_prot(struct ieee80211_node *, - const struct mbuf *, uint8_t, int); + const struct mbuf *, uint16_t, int); uint8_t *ieee80211_add_rates(uint8_t *, const struct ieee80211_rateset *); uint8_t *ieee80211_add_xrates(uint8_t *, const struct ieee80211_rateset *); @@ -249,12 +249,18 @@ /* flags for ieee80211_fix_rate() */ #define IEEE80211_F_DOSORT 0x00000001 /* sort rate list */ -#define IEEE80211_F_DOFRATE 0x00000002 /* use fixed legacy rate */ +#define IEEE80211_F_DOFIXED 0x00000002 /* use fixed rate */ #define IEEE80211_F_DONEGO 0x00000004 /* calc negotiated rate */ #define IEEE80211_F_DODEL 0x00000008 /* delete ignore rate */ -#define IEEE80211_F_DOBRS 0x00000010 /* check basic rate set */ -#define IEEE80211_F_JOIN 0x00000020 /* sta joining our bss */ -#define IEEE80211_F_DOFMCS 0x00000040 /* use fixed HT rate */ +#define IEEE80211_F_JOIN 0x00000010 /* sta joining our bss */ +#define IEEE80211_F_RATE_MASK 0x00000060 /* rateset type */ +#define IEEE80211_F_RATE_LEGACY 0x00000000 /* use legacy rate */ +#define IEEE80211_F_RATE_MCS 0x00000020 /* use HT rate */ +#define IEEE80211_F_RATE_VHT 0x00000040 /* use VHT rate */ + +/* return value flag */ +#define IEEE80211_F_RATESET_ERROR 0x80000000 + int ieee80211_fix_rate(struct ieee80211_node *, struct ieee80211_rateset *, int); Index: sys/net80211/ieee80211_proto.c =================================================================== --- sys/net80211/ieee80211_proto.c +++ sys/net80211/ieee80211_proto.c @@ -347,9 +347,9 @@ * driver and/or user applications. */ for (i = IEEE80211_MODE_11A; i < IEEE80211_MODE_MAX; i++) { - const struct ieee80211_rateset *rs = &ic->ic_sup_rates[i]; + const struct ieee80211_rateset *rs = ic->ic_sup_rates[i]; - vap->iv_txparms[i].ucastrate = IEEE80211_FIXED_RATE_NONE; + vap->iv_txparms[i].ucastrate = IEEE80211_RATE_NONEXISTENT; /* * Setting the management rate to MCS 0 assumes that the @@ -366,17 +366,26 @@ */ #ifdef NOTYET if (i == IEEE80211_MODE_11NA || i == IEEE80211_MODE_11NG) { - vap->iv_txparms[i].mgmtrate = 0 | IEEE80211_RATE_MCS; - vap->iv_txparms[i].mcastrate = 0 | IEEE80211_RATE_MCS; + const struct ieee80211_htrateset *hrs; + + hrs = &ic->ic_sup_htrates; + + vap->iv_txparms[i].mgmtrate = hrs->rates[0].rs_index; + vap->iv_txparms[i].mcastrate = hrs->rates[0].rs_index; } else { - vap->iv_txparms[i].mgmtrate = - rs->rs_rates[0] & IEEE80211_RATE_VAL; - vap->iv_txparms[i].mcastrate = - rs->rs_rates[0] & IEEE80211_RATE_VAL; + vap->iv_txparms[i].mgmtrate = rs->rates[0].rs_index; + vap->iv_txparms[i].mcastrate = rs->rates[0].rs_index; } #endif - vap->iv_txparms[i].mgmtrate = rs->rs_rates[0] & IEEE80211_RATE_VAL; - vap->iv_txparms[i].mcastrate = rs->rs_rates[0] & IEEE80211_RATE_VAL; + if (rs->rs_nrates > 0) { + vap->iv_txparms[i].mgmtrate = rs->rates[0].rs_index; + vap->iv_txparms[i].mcastrate = rs->rates[0].rs_index; + } else { + vap->iv_txparms[i].mgmtrate = + IEEE80211_RATE_NONEXISTENT; + vap->iv_txparms[i].mcastrate = + IEEE80211_RATE_NONEXISTENT; + } vap->iv_txparms[i].maxretry = IEEE80211_TXMAX_DEFAULT; } vap->iv_roaming = IEEE80211_ROAMING_AUTO; @@ -615,92 +624,129 @@ } static __inline int -findrix(const struct ieee80211_rateset *rs, int r) +findrix(const struct ieee80211_rateset *rs, uint16_t rate_index) { int i; for (i = 0; i < rs->rs_nrates; i++) - if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == r) + if (rs->rates[i].rs_index == rate_index) return i; return -1; } +static __inline void +sortrate(struct ieee80211_rateset *rs, int i) +{ + const struct ieee80211_rate_t *r1, *r2; + uint16_t save_index; + int j, save_basic; + + r1 = ieee80211_get_rate(rs->rates[i].rs_index); + for (j = i + 1; j < rs->rs_nrates; j++) { + r2 = ieee80211_get_rate(rs->rates[j].rs_index); + + if (r1->value > r2->value) { + save_index = rs->rates[i].rs_index; + save_basic = rs->rates[i].rs_basic; + rs->rates[i].rs_index = rs->rates[j].rs_index; + rs->rates[i].rs_basic = rs->rates[j].rs_basic; + rs->rates[j].rs_index = save_index; + rs->rates[j].rs_basic = save_basic; + } + } +} + int ieee80211_fix_rate(struct ieee80211_node *ni, struct ieee80211_rateset *nrs, int flags) { struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; - int i, j, rix, error; - int okrate, badrate, fixedrate, ucastrate; const struct ieee80211_rateset *srs; - uint8_t r; + uint16_t ucastrate, lastrate, okrate; + int fixed_rate_found, rateset_type; + int i, j, rix, error; + fixed_rate_found = 0; error = 0; - okrate = badrate = 0; + okrate = lastrate = IEEE80211_RATE_NONEXISTENT; ucastrate = vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)].ucastrate; - if (ucastrate != IEEE80211_FIXED_RATE_NONE) { + rateset_type = (flags & IEEE80211_F_RATE_MASK); + if (ucastrate != IEEE80211_RATE_NONEXISTENT) { + const struct ieee80211_rate_t *rate; + /* * Workaround awkwardness with fixed rate. We are called * to check both the legacy rate set and the HT rate set * but we must apply any legacy fixed rate check only to the * legacy rate set and vice versa. We cannot tell what type * of rate set we've been given (legacy or HT) but we can - * distinguish the fixed rate type (MCS have 0x80 set). + * distinguish the fixed rate type. * So to deal with this the caller communicates whether to * check MCS or legacy rate using the flags and we use the * type of any fixed rate to avoid applying an MCS to a * legacy rate and vice versa. */ - if (ucastrate & 0x80) { - if (flags & IEEE80211_F_DOFRATE) - flags &= ~IEEE80211_F_DOFRATE; - } else if ((ucastrate & 0x80) == 0) { - if (flags & IEEE80211_F_DOFMCS) - flags &= ~IEEE80211_F_DOFMCS; + rate = ieee80211_get_rate(ucastrate); + switch (rate->type) { + case IEEE80211_T_VHT: + if (rateset_type != IEEE80211_F_RATE_VHT) + flags &= ~IEEE80211_F_DOFIXED; + + break; + case IEEE80211_T_HT: + if (rateset_type != IEEE80211_F_RATE_MCS) + flags &= ~IEEE80211_F_DOFIXED; + + break; + default: + if (rateset_type != IEEE80211_F_RATE_LEGACY) + flags &= ~IEEE80211_F_DOFIXED; + + break; } - /* NB: required to make MCS match below work */ - ucastrate &= IEEE80211_RATE_VAL; - } - fixedrate = IEEE80211_FIXED_RATE_NONE; + } else + flags &= ~IEEE80211_F_DOFIXED; + /* - * XXX we are called to process both MCS and legacy rates; + * We are called to process both MCS and legacy rates; * we must use the appropriate basic rate set or chaos will - * ensue; for now callers that want MCS must supply - * IEEE80211_F_DOBRS; at some point we'll need to split this - * function so there are two variants, one for MCS and one - * for legacy rates. + * ensue. */ - if (flags & IEEE80211_F_DOBRS) + switch (rateset_type) { + case IEEE80211_F_RATE_VHT: srs = (const struct ieee80211_rateset *) - ieee80211_get_suphtrates(ic, ni->ni_chan); - else + ieee80211_get_supvhtrates(ic); + break; + case IEEE80211_F_RATE_MCS: + srs = (const struct ieee80211_rateset *) + ieee80211_get_suphtrates(ic); + break; + case IEEE80211_F_RATE_LEGACY: srs = ieee80211_get_suprates(ic, ni->ni_chan); + break; + default: + /* NOTREACHED */ + KASSERT(0, ("%s: unknown rate set type %x", __func__, + rateset_type)); + return (lastrate | IEEE80211_F_RATESET_ERROR); + } + for (i = 0; i < nrs->rs_nrates; ) { - if (flags & IEEE80211_F_DOSORT) { - /* - * Sort rates. - */ - for (j = i + 1; j < nrs->rs_nrates; j++) { - if (IEEE80211_RV(nrs->rs_rates[i]) > - IEEE80211_RV(nrs->rs_rates[j])) { - r = nrs->rs_rates[i]; - nrs->rs_rates[i] = nrs->rs_rates[j]; - nrs->rs_rates[j] = r; - } - } - } - r = nrs->rs_rates[i] & IEEE80211_RATE_VAL; - badrate = r; + if (flags & IEEE80211_F_DOSORT) + sortrate(nrs, i); + + lastrate = nrs->rates[i].rs_index; + /* * Check for fixed rate. */ - if (r == ucastrate) - fixedrate = r; + if (lastrate == ucastrate) + fixed_rate_found = 1; /* * Check against supported rates. */ - rix = findrix(srs, r); + rix = findrix(srs, lastrate); if (flags & IEEE80211_F_DONEGO) { if (rix < 0) { /* @@ -710,14 +756,12 @@ * Otherwise we just discard/ignore the rate. */ if ((flags & IEEE80211_F_JOIN) && - (nrs->rs_rates[i] & IEEE80211_RATE_BASIC)) + nrs->rates[i].rs_basic) error++; } else if ((flags & IEEE80211_F_JOIN) == 0) { - /* - * Overwrite with the supported rate - * value so any basic rate bit is set. - */ - nrs->rs_rates[i] = srs->rs_rates[rix]; + /* Reset basic rate bit. */ + nrs->rates[i].rs_basic = + srs->rates[rix].rs_basic; } } if ((flags & IEEE80211_F_DODEL) && rix < 0) { @@ -726,23 +770,24 @@ */ nrs->rs_nrates--; for (j = i; j < nrs->rs_nrates; j++) - nrs->rs_rates[j] = nrs->rs_rates[j + 1]; - nrs->rs_rates[j] = 0; + nrs->rates[j] = nrs->rates[j + 1]; + memset(&nrs->rates[j], 0, sizeof(nrs->rates[j])); continue; } if (rix >= 0) - okrate = nrs->rs_rates[i]; + okrate = nrs->rates[i].rs_index; i++; } - if (okrate == 0 || error != 0 || - ((flags & (IEEE80211_F_DOFRATE|IEEE80211_F_DOFMCS)) && - fixedrate != ucastrate)) { + + if (okrate == IEEE80211_RATE_NONEXISTENT || error != 0 || + ((flags & IEEE80211_F_DOFIXED) && !fixed_rate_found)) { IEEE80211_NOTE(vap, IEEE80211_MSG_XRATE | IEEE80211_MSG_11N, ni, - "%s: flags 0x%x okrate %d error %d fixedrate 0x%x " - "ucastrate %x\n", __func__, fixedrate, ucastrate, flags); - return badrate | IEEE80211_RATE_BASIC; + "%s: flags 0x%x okrate %d error %d ucastrate %x " + "(found %d)\n", __func__, flags, okrate, error, + ucastrate, fixed_rate_found); + return (lastrate | IEEE80211_F_RATESET_ERROR); } else - return IEEE80211_RV(okrate); + return (okrate); } /* @@ -795,29 +840,20 @@ /* * Check if the specified rate set supports ERP. - * NB: the rate set is assumed to be sorted. */ int ieee80211_iserp_rateset(const struct ieee80211_rateset *rs) { static const int rates[] = { 2, 4, 11, 22, 12, 24, 48 }; - int i, j; + int i; if (rs->rs_nrates < nitems(rates)) - return 0; - for (i = 0; i < nitems(rates); i++) { - for (j = 0; j < rs->rs_nrates; j++) { - int r = rs->rs_rates[j] & IEEE80211_RATE_VAL; - if (rates[i] == r) - goto next; - if (r > rates[i]) - return 0; - } - return 0; - next: - ; - } - return 1; + return (0); + for (i = 0; i < nitems(rates); i++) + if (isclr(rs->rs_bitmap, rates[i])) + return (0); + + return (1); } /* @@ -831,33 +867,18 @@ setbasicrates(struct ieee80211_rateset *rs, enum ieee80211_phymode mode, int add) { - static const struct ieee80211_rateset basic[IEEE80211_MODE_MAX] = { - [IEEE80211_MODE_11A] = { 3, { 12, 24, 48 } }, - [IEEE80211_MODE_11B] = { 2, { 2, 4 } }, - /* NB: mixed b/g */ - [IEEE80211_MODE_11G] = { 4, { 2, 4, 11, 22 } }, - [IEEE80211_MODE_TURBO_A] = { 3, { 12, 24, 48 } }, - [IEEE80211_MODE_TURBO_G] = { 4, { 2, 4, 11, 22 } }, - [IEEE80211_MODE_STURBO_A] = { 3, { 12, 24, 48 } }, - [IEEE80211_MODE_HALF] = { 3, { 6, 12, 24 } }, - [IEEE80211_MODE_QUARTER] = { 3, { 3, 6, 12 } }, - [IEEE80211_MODE_11NA] = { 3, { 12, 24, 48 } }, - /* NB: mixed b/g */ - [IEEE80211_MODE_11NG] = { 4, { 2, 4, 11, 22 } }, - /* NB: mixed b/g */ - [IEEE80211_MODE_VHT_2GHZ] = { 4, { 2, 4, 11, 22 } }, - [IEEE80211_MODE_VHT_5GHZ] = { 3, { 12, 24, 48 } }, - }; - int i, j; + const struct ieee80211_rate_t *rate; + const struct ieee80211_rateset *basic; + int i; + basic = ieee80211_get_basic_rateset(mode); for (i = 0; i < rs->rs_nrates; i++) { - if (!add) - rs->rs_rates[i] &= IEEE80211_RATE_VAL; - for (j = 0; j < basic[mode].rs_nrates; j++) - if (basic[mode].rs_rates[j] == rs->rs_rates[i]) { - rs->rs_rates[i] |= IEEE80211_RATE_BASIC; - break; - } + rate = ieee80211_get_rate(rs->rates[i].rs_index); + + if (isset(basic->rs_bitmap, rate->value)) + rs->rates[i].rs_basic = 1; + else if (!add) + rs->rates[i].rs_basic = 0; } } Index: sys/net80211/ieee80211_ratectl.h =================================================================== --- sys/net80211/ieee80211_ratectl.h +++ sys/net80211/ieee80211_ratectl.h @@ -59,7 +59,7 @@ enum ieee80211_ratectl_tx_fail_reason status; /* Tx status */ int pktlen; /* frame length */ - int final_rate; /* transmission rate */ + int final_rate; /* transmission rate (index) */ uint_fast8_t short_retries; /* RTS/CTS retries */ uint_fast8_t long_retries; /* ACK retries */ int8_t rssi; /* ACK RSSI */ Index: sys/net80211/ieee80211_ratectl_none.c =================================================================== --- sys/net80211/ieee80211_ratectl_none.c +++ sys/net80211/ieee80211_ratectl_none.c @@ -39,6 +39,7 @@ #include #include +#include #include #include @@ -64,7 +65,14 @@ static void none_node_init(struct ieee80211_node *ni) { - ni->ni_txrate = ni->ni_rates.rs_rates[0] & IEEE80211_RATE_VAL; + struct ieee80211vap *vap = ni->ni_vap; + + if (__predict_false(ni->ni_rates.rs_nrates == 0)) { + if_printf(vap->iv_ifp, "%s: no rates available!\n", __func__); + return; + } + + ni->ni_txrate = ni->ni_rates.rates[0].rs_index; } static void @@ -77,7 +85,7 @@ { int rix = 0; - ni->ni_txrate = ni->ni_rates.rs_rates[rix] & IEEE80211_RATE_VAL; + ni->ni_txrate = ni->ni_rates.rates[rix].rs_index; return rix; } Index: sys/net80211/ieee80211_rates.h =================================================================== --- sys/net80211/ieee80211_rates.h +++ sys/net80211/ieee80211_rates.h @@ -0,0 +1,265 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2007-2008 Sam Leffler, Errno Consulting + * Copyright (c) 2017 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* shorthands to compact table for readability */ +#define FH IEEE80211_T_FH +#define OFDM IEEE80211_T_OFDM +#define CCK IEEE80211_T_CCK +#define PBCC IEEE80211_T_PBCC +#define TURBO IEEE80211_T_TURBO +#define HALF IEEE80211_T_OFDM_HALF +#define QUART IEEE80211_T_OFDM_QUARTER +#define HT IEEE80211_T_HT +#define VHT IEEE80211_T_VHT + +#define streams props.ht.streams +#define no_20mhz props.ht.no_20mhz +#define no_80mhz props.ht.no_80mhz +#define no_160mhz props.ht.no_160mhz +#define unequal props.ht.unequal +#define shpre props.cck.short_preamble + +static const struct ieee80211_rate_t ieee80211_rates_all[] = { + { .type = FH, 2 }, + { .type = FH, 4 }, + { .type = CCK, 2, .shpre = 0 }, + { .type = CCK, 4, .shpre = 1 }, + { .type = CCK, 11, .shpre = 1 }, + { .type = CCK, 22, .shpre = 1 }, + { .type = PBCC, 44 }, + { .type = PBCC, 66 }, + { .type = OFDM, 12 }, + { .type = OFDM, 18 }, + { .type = OFDM, 24 }, + { .type = OFDM, 36 }, + { .type = OFDM, 48 }, + { .type = OFDM, 72 }, + { .type = OFDM, 96 }, + { .type = OFDM, 108 }, + { .type = HALF, 6 }, + { .type = HALF, 9 }, + { .type = HALF, 12 }, + { .type = HALF, 18 }, + { .type = HALF, 24 }, + { .type = HALF, 36 }, + { .type = HALF, 48 }, + { .type = HALF, 54 }, + { .type = QUART, 3 }, + { .type = QUART, 4 }, + { .type = QUART, 6 }, + { .type = QUART, 9 }, + { .type = QUART, 12 }, + { .type = QUART, 18 }, + { .type = QUART, 24 }, + { .type = QUART, 27 }, + { .type = TURBO, 12 }, + { .type = TURBO, 18 }, + { .type = TURBO, 24 }, + { .type = TURBO, 36 }, + { .type = TURBO, 48 }, + { .type = TURBO, 72 }, + { .type = TURBO, 96 }, + { .type = TURBO, 108 }, + { .type = HT, 0, .streams = 1 }, + { .type = HT, 1, .streams = 1 }, + { .type = HT, 2, .streams = 1 }, + { .type = HT, 3, .streams = 1 }, + { .type = HT, 4, .streams = 1 }, + { .type = HT, 5, .streams = 1 }, + { .type = HT, 6, .streams = 1 }, + { .type = HT, 7, .streams = 1 }, + { .type = HT, 8, .streams = 2 }, + { .type = HT, 9, .streams = 2 }, + { .type = HT, 10, .streams = 2 }, + { .type = HT, 11, .streams = 2 }, + { .type = HT, 12, .streams = 2 }, + { .type = HT, 13, .streams = 2 }, + { .type = HT, 14, .streams = 2 }, + { .type = HT, 15, .streams = 2 }, + { .type = HT, 16, .streams = 3 }, + { .type = HT, 17, .streams = 3 }, + { .type = HT, 18, .streams = 3 }, + { .type = HT, 19, .streams = 3 }, + { .type = HT, 20, .streams = 3 }, + { .type = HT, 21, .streams = 3 }, + { .type = HT, 22, .streams = 3 }, + { .type = HT, 23, .streams = 3 }, + { .type = HT, 24, .streams = 4 }, + { .type = HT, 25, .streams = 4 }, + { .type = HT, 26, .streams = 4 }, + { .type = HT, 27, .streams = 4 }, + { .type = HT, 28, .streams = 4 }, + { .type = HT, 29, .streams = 4 }, + { .type = HT, 30, .streams = 4 }, + { .type = HT, 31, .streams = 4 }, + { .type = HT, 32, .streams = 1, .no_20mhz = 1 }, + { .type = HT, 33, .streams = 2, .unequal = 1 }, + { .type = HT, 34, .streams = 2, .unequal = 1 }, + { .type = HT, 35, .streams = 2, .unequal = 1 }, + { .type = HT, 36, .streams = 2, .unequal = 1 }, + { .type = HT, 37, .streams = 2, .unequal = 1 }, + { .type = HT, 38, .streams = 2, .unequal = 1 }, + { .type = HT, 39, .streams = 3, .unequal = 1 }, + { .type = HT, 40, .streams = 3, .unequal = 1 }, + { .type = HT, 41, .streams = 3, .unequal = 1 }, + { .type = HT, 42, .streams = 3, .unequal = 1 }, + { .type = HT, 43, .streams = 3, .unequal = 1 }, + { .type = HT, 44, .streams = 3, .unequal = 1 }, + { .type = HT, 45, .streams = 3, .unequal = 1 }, + { .type = HT, 46, .streams = 3, .unequal = 1 }, + { .type = HT, 47, .streams = 3, .unequal = 1 }, + { .type = HT, 48, .streams = 3, .unequal = 1 }, + { .type = HT, 49, .streams = 3, .unequal = 1 }, + { .type = HT, 50, .streams = 3, .unequal = 1 }, + { .type = HT, 51, .streams = 3, .unequal = 1 }, + { .type = HT, 52, .streams = 3, .unequal = 1 }, + { .type = HT, 53, .streams = 4, .unequal = 1 }, + { .type = HT, 54, .streams = 4, .unequal = 1 }, + { .type = HT, 55, .streams = 4, .unequal = 1 }, + { .type = HT, 56, .streams = 4, .unequal = 1 }, + { .type = HT, 57, .streams = 4, .unequal = 1 }, + { .type = HT, 58, .streams = 4, .unequal = 1 }, + { .type = HT, 59, .streams = 4, .unequal = 1 }, + { .type = HT, 60, .streams = 4, .unequal = 1 }, + { .type = HT, 61, .streams = 4, .unequal = 1 }, + { .type = HT, 62, .streams = 4, .unequal = 1 }, + { .type = HT, 63, .streams = 4, .unequal = 1 }, + { .type = HT, 64, .streams = 4, .unequal = 1 }, + { .type = HT, 65, .streams = 4, .unequal = 1 }, + { .type = HT, 66, .streams = 4, .unequal = 1 }, + { .type = HT, 67, .streams = 4, .unequal = 1 }, + { .type = HT, 68, .streams = 4, .unequal = 1 }, + { .type = HT, 69, .streams = 4, .unequal = 1 }, + { .type = HT, 70, .streams = 4, .unequal = 1 }, + { .type = HT, 71, .streams = 4, .unequal = 1 }, + { .type = HT, 72, .streams = 4, .unequal = 1 }, + { .type = HT, 73, .streams = 4, .unequal = 1 }, + { .type = HT, 74, .streams = 4, .unequal = 1 }, + { .type = HT, 75, .streams = 4, .unequal = 1 }, + { .type = HT, 76, .streams = 4, .unequal = 1 }, + { .type = VHT, 0, .streams = 1 }, + { .type = VHT, 1, .streams = 1 }, + { .type = VHT, 2, .streams = 1 }, + { .type = VHT, 3, .streams = 1 }, + { .type = VHT, 4, .streams = 1 }, + { .type = VHT, 5, .streams = 1 }, + { .type = VHT, 6, .streams = 1 }, + { .type = VHT, 7, .streams = 1 }, + { .type = VHT, 8, .streams = 1 }, + { .type = VHT, 9, .streams = 1, .no_20mhz = 1 }, + { .type = VHT, 0, .streams = 2 }, + { .type = VHT, 1, .streams = 2 }, + { .type = VHT, 2, .streams = 2 }, + { .type = VHT, 3, .streams = 2 }, + { .type = VHT, 4, .streams = 2 }, + { .type = VHT, 5, .streams = 2 }, + { .type = VHT, 6, .streams = 2 }, + { .type = VHT, 7, .streams = 2 }, + { .type = VHT, 8, .streams = 2 }, + { .type = VHT, 9, .streams = 2, .no_20mhz = 1 }, + { .type = VHT, 0, .streams = 3 }, + { .type = VHT, 1, .streams = 3 }, + { .type = VHT, 2, .streams = 3 }, + { .type = VHT, 3, .streams = 3 }, + { .type = VHT, 4, .streams = 3 }, + { .type = VHT, 5, .streams = 3 }, + { .type = VHT, 6, .streams = 3, .no_80mhz = 1 }, + { .type = VHT, 7, .streams = 3 }, + { .type = VHT, 8, .streams = 3 }, + { .type = VHT, 9, .streams = 3, .no_160mhz = 1 }, + { .type = VHT, 0, .streams = 4 }, + { .type = VHT, 1, .streams = 4 }, + { .type = VHT, 2, .streams = 4 }, + { .type = VHT, 3, .streams = 4 }, + { .type = VHT, 4, .streams = 4 }, + { .type = VHT, 5, .streams = 4 }, + { .type = VHT, 6, .streams = 4 }, + { .type = VHT, 7, .streams = 4 }, + { .type = VHT, 8, .streams = 4 }, + { .type = VHT, 9, .streams = 4, .no_20mhz = 1 }, + { .type = VHT, 0, .streams = 5 }, + { .type = VHT, 1, .streams = 5 }, + { .type = VHT, 2, .streams = 5 }, + { .type = VHT, 3, .streams = 5 }, + { .type = VHT, 4, .streams = 5 }, + { .type = VHT, 5, .streams = 5 }, + { .type = VHT, 6, .streams = 5 }, + { .type = VHT, 7, .streams = 5 }, + { .type = VHT, 8, .streams = 5 }, + { .type = VHT, 9, .streams = 5, .no_20mhz = 1 }, + { .type = VHT, 0, .streams = 6 }, + { .type = VHT, 1, .streams = 6 }, + { .type = VHT, 2, .streams = 6 }, + { .type = VHT, 3, .streams = 6 }, + { .type = VHT, 4, .streams = 6 }, + { .type = VHT, 5, .streams = 6 }, + { .type = VHT, 6, .streams = 6 }, + { .type = VHT, 7, .streams = 6 }, + { .type = VHT, 8, .streams = 6 }, + { .type = VHT, 9, .streams = 6, .no_80mhz = 1 }, + { .type = VHT, 0, .streams = 7 }, + { .type = VHT, 1, .streams = 7 }, + { .type = VHT, 2, .streams = 7 }, + { .type = VHT, 3, .streams = 7 }, + { .type = VHT, 4, .streams = 7 }, + { .type = VHT, 5, .streams = 7 }, + { .type = VHT, 6, .streams = 7, .no_80mhz = 1 }, + { .type = VHT, 7, .streams = 7 }, + { .type = VHT, 8, .streams = 7 }, + { .type = VHT, 9, .streams = 7, .no_20mhz = 1 }, + { .type = VHT, 0, .streams = 8 }, + { .type = VHT, 1, .streams = 8 }, + { .type = VHT, 2, .streams = 8 }, + { .type = VHT, 3, .streams = 8 }, + { .type = VHT, 4, .streams = 8 }, + { .type = VHT, 5, .streams = 8 }, + { .type = VHT, 6, .streams = 8 }, + { .type = VHT, 7, .streams = 8 }, + { .type = VHT, 8, .streams = 8 }, + { .type = VHT, 9, .streams = 8, .no_20mhz = 1 } +}; + +#undef shpre +#undef unequal +#undef no_160mhz +#undef no_80mhz +#undef no_20mhz +#undef streams + +#undef VHT +#undef HT +#undef QUART +#undef HALF +#undef TURBO +#undef PBCC +#undef CCK +#undef OFDM +#undef FH Index: sys/net80211/ieee80211_rssadapt.c =================================================================== --- sys/net80211/ieee80211_rssadapt.c +++ sys/net80211/ieee80211_rssadapt.c @@ -172,10 +172,13 @@ static void rssadapt_node_init(struct ieee80211_node *ni) { + const struct ieee80211_rate_t *rate; struct ieee80211_rssadapt_node *ra; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_rssadapt *rsa = vap->iv_rs; const struct ieee80211_rateset *rs = &ni->ni_rates; + uint16_t rate_index; + int rix; if (ni->ni_rctls == NULL) { ni->ni_rctls = ra = @@ -192,16 +195,27 @@ ra->ra_rates = *rs; rssadapt_updatestats(ra); + if (__predict_false(rs->rs_nrates == 0)) { + if_printf(vap->iv_ifp, "%s: no rates available!\n", __func__); + return; + } + /* pick initial rate */ - for (ra->ra_rix = rs->rs_nrates - 1; - ra->ra_rix > 0 && (rs->rs_rates[ra->ra_rix] & IEEE80211_RATE_VAL) > 72; - ra->ra_rix--) - ; - ni->ni_txrate = rs->rs_rates[ra->ra_rix] & IEEE80211_RATE_VAL; + for (rix = rs->rs_nrates - 1; rix > 0; rix--) { + rate_index = rs->rates[rix].rs_index; + rate = ieee80211_get_rate(rate_index); + + if (rate->value <= 72) + break; + } + + ni->ni_txrate = rs->rates[rix].rs_index; ra->ra_ticks = ticks; + ra->ra_rix = rix; + rate = ieee80211_get_rate(ni->ni_txrate); IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, - "RSSADAPT initial rate %d", ni->ni_txrate); + "RSSADAPT initial rate %u/%u", rate->type, rate->value); } static void @@ -229,6 +243,7 @@ static int rssadapt_rate(struct ieee80211_node *ni, void *arg __unused, uint32_t iarg) { + const struct ieee80211_rate_t *rate; struct ieee80211_rssadapt_node *ra = ni->ni_rctls; u_int pktlen = iarg; const struct ieee80211_rateset *rs = &ra->ra_rates; @@ -244,17 +259,18 @@ /* XXX this is average rssi, should be using last value */ rssi = ni->ni_ic->ic_node_getrssi(ni); - for (rix = rs->rs_nrates-1; rix >= 0; rix--) + for (rix = rs->rs_nrates - 1; rix >= 0; rix--) if ((*thrs)[rix] < (rssi << 8)) break; if (rix != ra->ra_rix) { /* update public rate */ - ni->ni_txrate = ni->ni_rates.rs_rates[rix] & IEEE80211_RATE_VAL; + ni->ni_txrate = ni->ni_rates.rates[rix].rs_index; ra->ra_rix = rix; + rate = ieee80211_get_rate(ni->ni_txrate); IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, - "RSSADAPT new rate %d (pktlen %d rssi %d)", - ni->ni_txrate, pktlen, rssi); + "RSSADAPT new rate %u/%u (pktlen %d rssi %d)", + rate->type, rate->value, pktlen, rssi); } return rix; } @@ -268,6 +284,7 @@ static void rssadapt_lower_rate(struct ieee80211_rssadapt_node *ra, int pktlen, int rssi) { + const struct ieee80211_rate_t *rate; uint16_t last_thr; uint16_t (*thrs)[IEEE80211_RATE_SIZE]; u_int rix; @@ -279,15 +296,17 @@ (*thrs)[rix] = interpolate(master_expavgctl.rc_thresh, last_thr, (rssi << 8)); + rate = ieee80211_get_rate(ra->ra_rates.rates[rix + 1].rs_index); IEEE80211_DPRINTF(ra->ra_rs->vap, IEEE80211_MSG_RATECTL, - "RSSADAPT lower threshold for rate %d (last_thr %d new thr %d rssi %d)\n", - ra->ra_rates.rs_rates[rix + 1] & IEEE80211_RATE_VAL, - last_thr, (*thrs)[rix], rssi); + "RSSADAPT lower threshold for rate %u/%u " + "(last_thr %d new thr %d rssi %d)\n", + rate->type, rate->value, last_thr, (*thrs)[rix], rssi); } static void rssadapt_raise_rate(struct ieee80211_rssadapt_node *ra, int pktlen, int rssi) { + const struct ieee80211_rate_t *rate; uint16_t (*thrs)[IEEE80211_RATE_SIZE]; uint16_t newthr, oldthr; int rix; @@ -304,10 +323,12 @@ (*thrs)[rix + 1] = interpolate(master_expavgctl.rc_decay, oldthr, newthr); + rate = + ieee80211_get_rate(ra->ra_rates.rates[rix + 1].rs_index); IEEE80211_DPRINTF(ra->ra_rs->vap, IEEE80211_MSG_RATECTL, - "RSSADAPT raise threshold for rate %d (oldthr %d newthr %d rssi %d)\n", - ra->ra_rates.rs_rates[rix + 1] & IEEE80211_RATE_VAL, - oldthr, newthr, rssi); + "RSSADAPT raise threshold for rate %u/%u " + "(oldthr %d newthr %d rssi %d)\n", + rate->type, rate->value, oldthr, newthr, rssi); ra->ra_last_raise = ticks; } Index: sys/net80211/ieee80211_scan.c =================================================================== --- sys/net80211/ieee80211_scan.c +++ sys/net80211/ieee80211_scan.c @@ -56,22 +56,30 @@ /* * Roaming-related defaults. RSSI thresholds are as returned by the - * driver (.5dBm). Transmit rate thresholds are IEEE rate codes (i.e - * .5M units) or MCS. + * driver (.5dBm). Transmit rate thresholds are coded into global + * ieee80211_rate_t structure indices. */ /* rssi thresholds */ #define ROAM_RSSI_11A_DEFAULT 14 /* 11a bss */ #define ROAM_RSSI_11B_DEFAULT 14 /* 11b bss */ #define ROAM_RSSI_11BONLY_DEFAULT 14 /* 11b-only bss */ /* transmit rate thresholds */ -#define ROAM_RATE_11A_DEFAULT 2*12 /* 11a bss */ -#define ROAM_RATE_11B_DEFAULT 2*5 /* 11b bss */ -#define ROAM_RATE_11BONLY_DEFAULT 2*1 /* 11b-only bss */ -#define ROAM_RATE_HALF_DEFAULT 2*6 /* half-width 11a/g bss */ -#define ROAM_RATE_QUARTER_DEFAULT 2*3 /* quarter-width 11a/g bss */ -#define ROAM_MCS_11N_DEFAULT (1 | IEEE80211_RATE_MCS) /* 11n bss */ -#define ROAM_MCS_11AC_DEFAULT (1 | IEEE80211_RATE_MCS) /* 11ac bss; XXX not used yet */ +#define ROAM_RATE_11A_DEFAULT \ + IEEE80211_RATE_INDEX_OFDM12 /* 11a bss */ +#define ROAM_RATE_11B_DEFAULT \ + IEEE80211_RATE_INDEX_CCK5 /* 11b bss */ +#define ROAM_RATE_11BONLY_DEFAULT \ + IEEE80211_RATE_INDEX_CCK1 /* 11b-only bss */ +#define ROAM_RATE_HALF_DEFAULT \ + IEEE80211_RATE_INDEX_HALF6 /* half-width 11a/g bss */ +#define ROAM_RATE_QUARTER_DEFAULT \ + IEEE80211_RATE_INDEX_QUART3 /* quarter-width 11a/g bss */ +#define ROAM_MCS_11N_DEFAULT \ + IEEE80211_RATE_INDEX_HT(1) /* 11n bss */ +#define ROAM_MCS_11AC_DEFAULT \ + IEEE80211_RATE_INDEX_VHT(1, 1) /* 11ac bss; XXX not used yet */ + void ieee80211_scan_attach(struct ieee80211com *ic) { @@ -98,7 +106,7 @@ ic->ic_scan_methods->sc_detach(ic); } -static const struct ieee80211_roamparam defroam[IEEE80211_MODE_MAX] = { +static const struct ieee80211_roamparam_vht defroam[IEEE80211_MODE_MAX] = { [IEEE80211_MODE_11A] = { .rssi = ROAM_RSSI_11A_DEFAULT, .rate = ROAM_RATE_11A_DEFAULT }, [IEEE80211_MODE_11G] = { .rssi = ROAM_RSSI_11B_DEFAULT, @@ -130,13 +138,21 @@ ieee80211_scan_vattach(struct ieee80211vap *vap) { struct ieee80211com *ic = vap->iv_ic; + int m; vap->iv_bgscanidle = (IEEE80211_BGSCAN_IDLE_DEFAULT*1000)/hz; vap->iv_bgscanintvl = IEEE80211_BGSCAN_INTVAL_DEFAULT*hz; vap->iv_scanvalid = IEEE80211_SCAN_VALID_DEFAULT*hz; vap->iv_roaming = IEEE80211_ROAMING_AUTO; - memcpy(vap->iv_roamparms, defroam, sizeof(defroam)); + for (m = IEEE80211_MODE_AUTO + 1; m < IEEE80211_MODE_MAX; m++) { + if (isclr(ic->ic_modecaps, m)) { + vap->iv_roamparms[m].rate = IEEE80211_RATE_NONEXISTENT; + continue; + } + + memcpy(&vap->iv_roamparms[m], &defroam[m], sizeof(defroam[m])); + } ic->ic_scan_methods->sc_vattach(vap); } Index: sys/net80211/ieee80211_scan_sta.c =================================================================== --- sys/net80211/ieee80211_scan_sta.c +++ sys/net80211/ieee80211_scan_sta.c @@ -789,7 +789,8 @@ { const struct ieee80211_ie_htcap *htcap = (const struct ieee80211_ie_htcap *) se->se_ies.htcap_ie; - int rmax, r, i, txstream; + int rmax, r, i, txstream, sgi; + uint32_t chan_flags; uint16_t caps; uint8_t txparams; @@ -812,15 +813,17 @@ for (i = 31; i >= 0 && isclr(htcap->hc_mcsset, i); i--); if (i >= 0) { caps = le16dec(&htcap->hc_cap); - if ((caps & IEEE80211_HTCAP_CHWIDTH40) && - (caps & IEEE80211_HTCAP_SHORTGI40)) - rmax = ieee80211_htrates[i].ht40_rate_400ns; - else if (caps & IEEE80211_HTCAP_CHWIDTH40) - rmax = ieee80211_htrates[i].ht40_rate_800ns; - else if (caps & IEEE80211_HTCAP_SHORTGI20) - rmax = ieee80211_htrates[i].ht20_rate_400ns; - else - rmax = ieee80211_htrates[i].ht20_rate_800ns; + if (caps & IEEE80211_HTCAP_CHWIDTH40) { + chan_flags = IEEE80211_CHAN_HT40; + sgi = (caps & IEEE80211_HTCAP_SHORTGI40) != 0; + } else { + chan_flags = IEEE80211_CHAN_HT20; + sgi = (caps & IEEE80211_HTCAP_SHORTGI20) != 0; + } + + rmax = ieee80211_get_rateKbps_by_idx( + IEEE80211_RATE_INDEX_HT(i), chan_flags, sgi); + rmax /= 500; } } for (i = 0; i < se->se_rates[1]; i++) { @@ -900,45 +903,55 @@ check_rate(struct ieee80211vap *vap, const struct ieee80211_channel *chan, const struct ieee80211_scan_entry *se) { + const enum ieee80211_phymode mode = ieee80211_chan2mode(chan); const struct ieee80211_rateset *srs; - int i, j, nrs, r, okrate, badrate, fixedrate, ucastrate; + uint16_t ucastrate, rate_index, lastrate, okrate; + uint8_t rv; + int i, nrs, fixed_rate_not_found; const uint8_t *rs; - okrate = badrate = 0; - srs = ieee80211_get_suprates(vap->iv_ic, chan); nrs = se->se_rates[1]; rs = se->se_rates+2; + /* XXX MCS */ - ucastrate = vap->iv_txparms[ieee80211_chan2mode(chan)].ucastrate; - fixedrate = IEEE80211_FIXED_RATE_NONE; + ucastrate = vap->iv_txparms[mode].ucastrate; + fixed_rate_not_found = (ucastrate != IEEE80211_RATE_NONEXISTENT); + okrate = lastrate = IEEE80211_RATE_NONEXISTENT; again: for (i = 0; i < nrs; i++) { - r = IEEE80211_RV(rs[i]); - badrate = r; + rv = IEEE80211_RV(rs[i]); + rate_index = ieee80211_convert_from_legacy_rate(rv, mode); + if (rate_index == IEEE80211_RATE_NONEXISTENT) { + if (rs[i] & IEEE80211_RATE_BASIC) { + okrate = IEEE80211_RATE_NONEXISTENT; + goto back; + } else + continue; + } + + lastrate = rate_index; /* * Check any fixed rate is included. */ - if (r == ucastrate) - fixedrate = r; + if (rate_index == ucastrate) + fixed_rate_not_found = 0; /* * Check against our supported rates. */ - for (j = 0; j < srs->rs_nrates; j++) - if (r == IEEE80211_RV(srs->rs_rates[j])) { - if (r > okrate) /* NB: track max */ - okrate = r; - break; - } - - if (j == srs->rs_nrates && (rs[i] & IEEE80211_RATE_BASIC)) { + if (isclr(srs->rs_bitmap, rv) && + (rs[i] & IEEE80211_RATE_BASIC)) { /* * Don't try joining a BSS, if we don't support * one of its basic rates. */ - okrate = 0; + okrate = IEEE80211_RATE_NONEXISTENT; goto back; } + + if (okrate == IEEE80211_RATE_NONEXISTENT || + okrate < rate_index) /* NB: track max */ + okrate = rate_index; } if (rs == se->se_rates+2) { /* scan xrates too; sort of an algol68-style for loop */ @@ -948,10 +961,10 @@ } back: - if (okrate == 0 || ucastrate != fixedrate) - return badrate | IEEE80211_RATE_BASIC; + if (okrate == IEEE80211_RATE_NONEXISTENT || fixed_rate_not_found) + return (lastrate | IEEE80211_F_RATESET_ERROR); else - return IEEE80211_RV(okrate); + return (okrate); } static __inline int @@ -995,10 +1008,10 @@ const struct ieee80211_scan_state *ss, struct sta_entry *se0, int debug) { + const struct ieee80211_rate_t *rate = NULL; struct ieee80211com *ic = vap->iv_ic; struct ieee80211_scan_entry *se = &se0->base; - uint8_t rate; - int fail; + int fail, rate_index; fail = 0; if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, se->se_chan))) @@ -1093,8 +1106,8 @@ fail |= MATCH_PRIVACY; } se0->se_flags &= ~STA_DEMOTE11B; - rate = check_rate(vap, se->se_chan, se); - if (rate & IEEE80211_RATE_BASIC) { + rate_index = check_rate(vap, se->se_chan, se); + if (rate_index & IEEE80211_F_RATESET_ERROR) { fail |= MATCH_RATE; /* * An 11b-only ap will give a rate mismatch if there is an @@ -1102,27 +1115,33 @@ * in the scan list to 11b and retry the rate check. */ if (IEEE80211_IS_CHAN_ANYG(se->se_chan)) { - rate = check_rate(vap, demote11b(vap, se->se_chan), se); - if ((rate & IEEE80211_RATE_BASIC) == 0) { + rate_index = check_rate(vap, + demote11b(vap, se->se_chan), se); + if ((rate_index & IEEE80211_F_RATESET_ERROR) == 0) { fail &= ~MATCH_RATE; se0->se_flags |= STA_DEMOTE11B; } } - } else if (rate < 2*24) { - /* - * This is an 11b-only ap. Check the desired mode in - * case that needs to be honored (mode 11g filters out - * 11b-only ap's). Otherwise force any 11g channel used - * in scanning to be demoted. - * - * NB: we cheat a bit here by looking at the max rate; - * we could/should check the rates. - */ - if (!(vap->iv_des_mode == IEEE80211_MODE_AUTO || - vap->iv_des_mode == IEEE80211_MODE_11B)) - fail |= MATCH_RATE; - else - se0->se_flags |= STA_DEMOTE11B; + } else { + /* NB: we know that the rate exist. */ + rate = ieee80211_get_rate(rate_index); + + if (rate->type == IEEE80211_T_CCK) { + /* + * This is an 11b-only ap. Check the desired mode in + * case that needs to be honored (mode 11g filters out + * 11b-only ap's). Otherwise force any 11g channel + * used in scanning to be demoted. + * + * NB: we cheat a bit here by looking at the max rate; + * we could/should check the rates. + */ + if (!(vap->iv_des_mode == IEEE80211_MODE_AUTO || + vap->iv_des_mode == IEEE80211_MODE_11B)) + fail |= MATCH_RATE; + else + se0->se_flags |= STA_DEMOTE11B; + } } if (ss->ss_nssid != 0 && !match_ssid(se->se_ssid, ss->ss_nssid, ss->ss_ssid)) @@ -1156,7 +1175,7 @@ printf(" %3d%c", ieee80211_chan2ieee(ic, se->se_chan), fail & MATCH_CHANNEL ? '!' : ' '); printf(" %+4d%c", se->se_rssi, fail & MATCH_RSSI ? '!' : ' '); - printf(" %2dM%c", (rate & IEEE80211_RATE_VAL) / 2, + printf(" %2dM%c", rate ? rate->value / 2 : rate_index, fail & MATCH_RATE ? '!' : ' '); printf(" %4s%c", (se->se_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" : @@ -1313,6 +1332,20 @@ return se; /* NB: unlocked */ } +static __inline int +compare_rates(uint16_t rate_index1, uint16_t rate_index2) +{ + uint8_t value1, value2; + + if (rate_index1 == rate_index2) + return (0); + + value1 = ieee80211_get_rateKbps_by_idx(rate_index1, 0, 0); + value2 = ieee80211_get_rateKbps_by_idx(rate_index2, 0, 0); + + return (value1 < value2); +} + static void sta_roam_check(struct ieee80211_scan_state *ss, struct ieee80211vap *vap) { @@ -1321,7 +1354,7 @@ struct sta_table *st = ss->ss_priv; enum ieee80211_phymode mode; struct sta_entry *se, *selbs; - uint8_t roamRate, curRate, ucastRate; + uint16_t ucastRate, curRate, roamRate; int8_t roamRssi, curRssi; se = sta_lookup(st, ni->ni_macaddr); @@ -1336,9 +1369,8 @@ ucastRate = vap->iv_txparms[mode].ucastrate; /* NB: the most up to date rssi is in the node, not the scan cache */ curRssi = ic->ic_node_getrssi(ni); - if (ucastRate == IEEE80211_FIXED_RATE_NONE) { + if (ucastRate == IEEE80211_RATE_NONEXISTENT) { curRate = ni->ni_txrate; - roamRate &= IEEE80211_RATE_VAL; IEEE80211_DPRINTF(vap, IEEE80211_MSG_ROAM, "%s: currssi %d currate %u roamrssi %d roamrate %u\n", __func__, curRssi, curRate, roamRssi, roamRate); @@ -1351,7 +1383,7 @@ * Check if a new ap should be used and switch. * XXX deauth current ap */ - if (curRate < roamRate || curRssi < roamRssi) { + if (compare_rates(curRate, roamRate) || curRssi < roamRssi) { if (ieee80211_time_after(ticks, ic->ic_lastscan + vap->iv_scanvalid)) { /* * Scan cache contents are too old; force a scan now Index: sys/net80211/ieee80211_scan_sw.c =================================================================== --- sys/net80211/ieee80211_scan_sw.c +++ sys/net80211/ieee80211_scan_sw.c @@ -722,7 +722,7 @@ * Potentially change channel and phy mode. */ ic->ic_curchan = chan; - ic->ic_rt = ieee80211_get_ratetable(chan); + ic->ic_rt = ieee80211_get_ratetable(ieee80211_chan2mode(chan)); IEEE80211_UNLOCK(ic); /* * Perform the channel change and scan unlocked so the driver Index: sys/net80211/ieee80211_sta.c =================================================================== --- sys/net80211/ieee80211_sta.c +++ sys/net80211/ieee80211_sta.c @@ -1355,8 +1355,7 @@ uint8_t *frm, *efrm; uint8_t *rates, *xrates, *wme, *htcap, *htinfo; uint8_t *vhtcap, *vhtopmode; - uint8_t rate; - int ht_state_change = 0, do_ht = 0; + int ht_state_change = 0, do_ht = 0, rate_index; wh = mtod(m0, struct ieee80211_frame *); frm = (uint8_t *)&wh[1]; @@ -1764,11 +1763,11 @@ if (xrates != NULL) IEEE80211_VERIFY_ELEMENT(xrates, IEEE80211_RATE_MAXSIZE - rates[1], return); - rate = ieee80211_setup_rates(ni, rates, xrates, + rate_index = ieee80211_setup_rates(ni, rates, xrates, IEEE80211_F_JOIN | - IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE | + IEEE80211_F_DOSORT | IEEE80211_F_DOFIXED | IEEE80211_F_DONEGO | IEEE80211_F_DODEL); - if (rate & IEEE80211_RATE_BASIC) { + if (rate_index & IEEE80211_F_RATESET_ERROR) { IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_ASSOC, wh->i_addr2, "%sassoc failed (rate set mismatch)", @@ -1820,8 +1819,7 @@ } ieee80211_ht_updateparams_final(ni, htcap, htinfo); - ieee80211_setup_htrates(ni, htcap, - IEEE80211_F_JOIN | IEEE80211_F_DOBRS); + ieee80211_setup_htrates(ni, htcap, IEEE80211_F_JOIN); ieee80211_setup_basic_htrates(ni, htinfo); ieee80211_node_setuptxparms(ni); Index: sys/net80211/ieee80211_superg.c =================================================================== --- sys/net80211/ieee80211_superg.c +++ sys/net80211/ieee80211_superg.c @@ -725,10 +725,11 @@ ff_approx_txtime(struct ieee80211_node *ni, const struct mbuf *m1, const struct mbuf *m2) { - struct ieee80211com *ic = ni->ni_ic; + const struct ieee80211_channel *chan = ni->ni_chan; struct ieee80211vap *vap = ni->ni_vap; uint32_t framelen; uint32_t frame_time; + int has_shortgi; /* * Approximate the frame length to be transmitted. A swag to add @@ -746,19 +747,17 @@ if (m2 != NULL) framelen += m2->m_pkthdr.len; - /* - * For now, we assume non-shortgi, 20MHz, just because I want to - * at least test 802.11n. - */ - if (ni->ni_txrate & IEEE80211_RATE_MCS) - frame_time = ieee80211_compute_duration_ht(framelen, - ni->ni_txrate, - IEEE80211_HT_RC_2_STREAMS(ni->ni_txrate), - 0, /* isht40 */ - 0); /* isshortgi */ - else - frame_time = ieee80211_compute_duration(ic->ic_rt, framelen, - ni->ni_txrate, 0); + has_shortgi = 0; + if (chan != NULL && chan != IEEE80211_CHAN_ANYC && + ((IEEE80211_IS_CHAN_HT40(chan) && + (ni->ni_flags & IEEE80211_NODE_SGI40) != 0)) || + ((IEEE80211_IS_CHAN_HT20(chan) && + (ni->ni_flags & IEEE80211_NODE_SGI20) != 0))) + has_shortgi = 1; + + frame_time = ieee80211_compute_duration(ni->ni_txrate, framelen, + IEEE80211_GET_CHAN_FLAGS(ni->ni_chan), has_shortgi); + return (frame_time); } @@ -982,6 +981,7 @@ { struct ieee80211com *ic = vap->iv_ic; struct ieee80211_channel *chan; + enum ieee80211_phymode mode; chan = ieee80211_find_channel(ic, ic->ic_bsschan->ic_freq, newflags); if (chan == NULL) { /* XXX should not happen */ @@ -991,16 +991,17 @@ return; } + mode = ieee80211_chan2mode(chan); IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG, "%s: %s -> %s (freq %u flags 0x%x)\n", __func__, ieee80211_phymode_name[ieee80211_chan2mode(ic->ic_bsschan)], - ieee80211_phymode_name[ieee80211_chan2mode(chan)], + ieee80211_phymode_name[mode], chan->ic_freq, chan->ic_flags); ic->ic_bsschan = chan; ic->ic_prevchan = ic->ic_curchan; ic->ic_curchan = chan; - ic->ic_rt = ieee80211_get_ratetable(chan); + ic->ic_rt = ieee80211_get_ratetable(mode); ic->ic_set_channel(ic); ieee80211_radiotap_chan_change(ic); /* NB: do not need to reset ERP state 'cuz we're in sta mode */ Index: sys/net80211/ieee80211_var.h =================================================================== --- sys/net80211/ieee80211_var.h +++ sys/net80211/ieee80211_var.h @@ -175,8 +175,10 @@ uint16_t ic_lintval; /* listen interval */ uint16_t ic_holdover; /* PM hold over duration */ uint16_t ic_txpowlimit; /* global tx power limit */ - struct ieee80211_rateset ic_sup_rates[IEEE80211_MODE_MAX]; + + const struct ieee80211_rateset *ic_sup_rates[IEEE80211_MODE_MAX]; struct ieee80211_htrateset ic_sup_htrates; + struct ieee80211_htrateset ic_sup_vhtrates; /* * Channel state: @@ -438,7 +440,7 @@ struct ieee80211_scan_ssid iv_scanreq_ssid[IEEE80211_SCAN_MAX_SSID]; /* sta-mode roaming state */ enum ieee80211_roamingmode iv_roaming; /* roaming mode */ - struct ieee80211_roamparam iv_roamparms[IEEE80211_MODE_MAX]; + struct ieee80211_roamparam_vht iv_roamparms[IEEE80211_MODE_MAX]; uint8_t iv_bmissthreshold; uint8_t iv_bmiss_count; /* current beacon miss count */ @@ -474,7 +476,7 @@ int iv_csa_count; /* count for doing CSA */ struct ieee80211_node *iv_bss; /* information for this node */ - struct ieee80211_txparam iv_txparms[IEEE80211_MODE_MAX]; + struct ieee80211_txparam_vht iv_txparms[IEEE80211_MODE_MAX]; uint16_t iv_rtsthreshold; uint16_t iv_fragthreshold; int iv_inact_timer; /* inactivity timer wait */ @@ -696,10 +698,6 @@ ifm_change_cb_t, ifm_stat_cb_t, const uint8_t macaddr[IEEE80211_ADDR_LEN]); void ieee80211_vap_detach(struct ieee80211vap *); -const struct ieee80211_rateset *ieee80211_get_suprates(struct ieee80211com *ic, - const struct ieee80211_channel *); -const struct ieee80211_htrateset *ieee80211_get_suphtrates( - struct ieee80211com *, const struct ieee80211_channel *); void ieee80211_announce(struct ieee80211com *); void ieee80211_announce_channels(struct ieee80211com *); void ieee80211_drain(struct ieee80211com *); @@ -711,8 +709,8 @@ int ieee80211_media_change(struct ifnet *); void ieee80211_media_status(struct ifnet *, struct ifmediareq *); int ieee80211_ioctl(struct ifnet *, u_long, caddr_t); -int ieee80211_rate2media(struct ieee80211com *, int, - enum ieee80211_phymode); +int ieee80211_rate2media(struct ieee80211com *, + const struct ieee80211_rate_t *, enum ieee80211_phymode); int ieee80211_media2rate(int); int ieee80211_mhz2ieee(u_int, u_int); int ieee80211_chan2ieee(struct ieee80211com *, @@ -735,7 +733,7 @@ int ieee, int flags); struct ieee80211_channel *ieee80211_lookup_channel_rxstatus(struct ieee80211vap *, const struct ieee80211_rx_stats *); -int ieee80211_setmode(struct ieee80211com *, enum ieee80211_phymode); +void ieee80211_setmode(struct ieee80211com *, enum ieee80211_phymode); enum ieee80211_phymode ieee80211_chan2mode(const struct ieee80211_channel *); uint32_t ieee80211_mac_hash(const struct ieee80211com *, const uint8_t addr[IEEE80211_ADDR_LEN]); @@ -762,6 +760,26 @@ void ieee80211_radiotap_tx(struct ieee80211vap *, struct mbuf *); void ieee80211_radiotap_rx(struct ieee80211vap *, struct mbuf *); void ieee80211_radiotap_rx_all(struct ieee80211com *, struct mbuf *); + + +static __inline const struct ieee80211_rateset * +ieee80211_get_suprates(struct ieee80211com *ic, + const struct ieee80211_channel *c) +{ + return ic->ic_sup_rates[ieee80211_chan2mode(c)]; +} + +static __inline const struct ieee80211_htrateset * +ieee80211_get_suphtrates(struct ieee80211com *ic) +{ + return &ic->ic_sup_htrates; +} + +static __inline const struct ieee80211_htrateset * +ieee80211_get_supvhtrates(struct ieee80211com *ic) +{ + return &ic->ic_sup_vhtrates; +} static __inline int ieee80211_radiotap_active(const struct ieee80211com *ic)