summaryrefslogtreecommitdiffstats
path: root/sys/net80211
diff options
context:
space:
mode:
authoradrian <adrian@FreeBSD.org>2013-07-04 21:16:49 +0000
committeradrian <adrian@FreeBSD.org>2013-07-04 21:16:49 +0000
commit1724725351eecf54f5bef13e26ebaf0bfe28fd50 (patch)
tree86ccd407ab7baf589b507d268c141171983167c7 /sys/net80211
parent083dd1de651813c2c5b040ffe3cba771aa583df1 (diff)
downloadFreeBSD-src-1724725351eecf54f5bef13e26ebaf0bfe28fd50.zip
FreeBSD-src-1724725351eecf54f5bef13e26ebaf0bfe28fd50.tar.gz
Implement basic 802.11n awareness in the PHY and AMRR rate control code.
* Add 802.11n 2ghz and 5ghz tables, including legacy rates and up to MCS23 rates (3x3.) * Populate the rate code -> rate index lookup table with MCS _and_ normal rates, but _not_ the basic rate flag. Since the basic rate flag is the same as the MCS flag, we can only use one. * Introduce some accessor inlines that do PLCP and rate table lookup/access and enforce that it doesn't set the basic rate bit. They're not designed for MCS rates, so it will panic. * Start converting drivers that use the rate table stuff to use the accessor inlines and strip the basic flag. * Teach AMRR about basic 11n - it's still as crap for MCS as it is being used by iwn, so it's not a step _backwardS_. * Convert iwn over to accept 11n MCS rates rather than 'translate' legacy to MCS rates. It doesn't use a lookup table any longer; instead it's a function which takes the current node (for HT parameters) and the rate code, and returns the hardware PLCP code to use. Tested: * ath - it's a no-op, and it works that way * iwn - both 11n and non-11n
Diffstat (limited to 'sys/net80211')
-rw-r--r--sys/net80211/ieee80211_amrr.c101
-rw-r--r--sys/net80211/ieee80211_phy.c193
-rw-r--r--sys/net80211/ieee80211_phy.h51
3 files changed, 315 insertions, 30 deletions
diff --git a/sys/net80211/ieee80211_amrr.c b/sys/net80211/ieee80211_amrr.c
index 73dd901..874659f 100644
--- a/sys/net80211/ieee80211_amrr.c
+++ b/sys/net80211/ieee80211_amrr.c
@@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
#endif
#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_ht.h>
#include <net80211/ieee80211_amrr.h>
#include <net80211/ieee80211_ratectl.h>
@@ -128,13 +129,25 @@ amrr_deinit(struct ieee80211vap *vap)
free(vap->iv_rs, M_80211_RATECTL);
}
+static int
+amrr_node_is_11n(struct ieee80211_node *ni)
+{
+
+ if (ni->ni_chan == NULL)
+ return (0);
+ if (ni->ni_chan == IEEE80211_CHAN_ANYC)
+ return (0);
+ return (IEEE80211_IS_CHAN_HT(ni->ni_chan));
+}
+
static void
amrr_node_init(struct ieee80211_node *ni)
{
- const struct ieee80211_rateset *rs = &ni->ni_rates;
+ const struct ieee80211_rateset *rs = NULL;
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211_amrr *amrr = vap->iv_rs;
struct ieee80211_amrr_node *amn;
+ uint8_t rate;
if (ni->ni_rctls == NULL) {
ni->ni_rctls = amn = malloc(sizeof(struct ieee80211_amrr_node),
@@ -152,16 +165,50 @@ amrr_node_init(struct ieee80211_node *ni)
amn->amn_txcnt = amn->amn_retrycnt = 0;
amn->amn_success_threshold = amrr->amrr_min_success_threshold;
- /* pick initial rate */
- for (amn->amn_rix = rs->rs_nrates - 1;
- amn->amn_rix > 0 && (rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL) > 72;
- amn->amn_rix--)
- ;
- ni->ni_txrate = rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL;
+ /* 11n or not? Pick the right rateset */
+ if (amrr_node_is_11n(ni)) {
+ /* XXX ew */
+ IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
+ "%s: 11n node", __func__);
+ rs = (struct ieee80211_rateset *) &ni->ni_htrates;
+ } else {
+ IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
+ "%s: non-11n node", __func__);
+ rs = &ni->ni_rates;
+ }
+
+ /* Initial rate - lowest */
+ rate = rs->rs_rates[0];
+
+ /* XXX clear the basic rate flag if it's not 11n */
+ if (! amrr_node_is_11n(ni))
+ rate &= IEEE80211_RATE_VAL;
+
+ /* pick initial rate from the rateset - HT or otherwise */
+ for (amn->amn_rix = rs->rs_nrates - 1; amn->amn_rix > 0;
+ amn->amn_rix--) {
+ /* legacy - anything < 36mbit, stop searching */
+ /* 11n - stop at MCS4 / MCS12 / MCS28 */
+ if (amrr_node_is_11n(ni) &&
+ (rs->rs_rates[amn->amn_rix] & 0x7) < 4)
+ break;
+ else if ((rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL) <= 72)
+ break;
+ rate = rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL;
+ }
+
+ /* if the rate is an 11n rate, ensure the MCS bit is set */
+ if (amrr_node_is_11n(ni))
+ rate |= IEEE80211_RATE_MCS;
+
+ /* Assign initial rate from the rateset */
+ ni->ni_txrate = rate;
amn->amn_ticks = ticks;
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
- "AMRR initial rate %d", ni->ni_txrate);
+ "AMRR: nrates=%d, initial rate %d",
+ rs->rs_nrates,
+ rate);
}
static void
@@ -175,19 +222,34 @@ amrr_update(struct ieee80211_amrr *amrr, struct ieee80211_amrr_node *amn,
struct ieee80211_node *ni)
{
int rix = amn->amn_rix;
+ const struct ieee80211_rateset *rs = NULL;
KASSERT(is_enough(amn), ("txcnt %d", amn->amn_txcnt));
+ /* 11n or not? Pick the right rateset */
+ if (amrr_node_is_11n(ni)) {
+ /* XXX ew */
+ rs = (struct ieee80211_rateset *) &ni->ni_htrates;
+ } else {
+ rs = &ni->ni_rates;
+ }
+
+ IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
+ "AMRR: current rate %d, txcnt=%d, retrycnt=%d",
+ rs->rs_rates[rix] & IEEE80211_RATE_VAL,
+ amn->amn_txcnt,
+ amn->amn_retrycnt);
+
if (is_success(amn)) {
amn->amn_success++;
if (amn->amn_success >= amn->amn_success_threshold &&
- rix + 1 < ni->ni_rates.rs_nrates) {
+ rix + 1 < rs->rs_nrates) {
amn->amn_recovery = 1;
amn->amn_success = 0;
rix++;
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
"AMRR increasing rate %d (txcnt=%d retrycnt=%d)",
- ni->ni_rates.rs_rates[rix] & IEEE80211_RATE_VAL,
+ rs->rs_rates[rix] & IEEE80211_RATE_VAL,
amn->amn_txcnt, amn->amn_retrycnt);
} else {
amn->amn_recovery = 0;
@@ -208,7 +270,7 @@ amrr_update(struct ieee80211_amrr *amrr, struct ieee80211_amrr_node *amn,
rix--;
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
"AMRR decreasing rate %d (txcnt=%d retrycnt=%d)",
- ni->ni_rates.rs_rates[rix] & IEEE80211_RATE_VAL,
+ rs->rs_rates[rix] & IEEE80211_RATE_VAL,
amn->amn_txcnt, amn->amn_retrycnt);
}
amn->amn_recovery = 0;
@@ -231,14 +293,27 @@ amrr_rate(struct ieee80211_node *ni, void *arg __unused, uint32_t iarg __unused)
{
struct ieee80211_amrr_node *amn = ni->ni_rctls;
struct ieee80211_amrr *amrr = amn->amn_amrr;
+ const struct ieee80211_rateset *rs = NULL;
int rix;
+ /* 11n or not? Pick the right rateset */
+ if (amrr_node_is_11n(ni)) {
+ /* XXX ew */
+ rs = (struct ieee80211_rateset *) &ni->ni_htrates;
+ } else {
+ rs = &ni->ni_rates;
+ }
+
if (is_enough(amn) && (ticks - amn->amn_ticks) > amrr->amrr_interval) {
rix = amrr_update(amrr, amn, ni);
if (rix != amn->amn_rix) {
/* update public rate */
- ni->ni_txrate =
- ni->ni_rates.rs_rates[rix] & IEEE80211_RATE_VAL;
+ ni->ni_txrate = rs->rs_rates[rix];
+ /* XXX strip basic rate flag from txrate, if non-11n */
+ if (amrr_node_is_11n(ni))
+ ni->ni_txrate |= IEEE80211_RATE_MCS;
+ else
+ ni->ni_txrate &= IEEE80211_RATE_VAL;
amn->amn_rix = rix;
}
amn->amn_ticks = ticks;
diff --git a/sys/net80211/ieee80211_phy.c b/sys/net80211/ieee80211_phy.c
index d2ad60d..d1924d8 100644
--- a/sys/net80211/ieee80211_phy.c
+++ b/sys/net80211/ieee80211_phy.c
@@ -60,8 +60,11 @@ struct ieee80211_ds_plcp_hdr {
#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) (0x80 | r)
+#define B(r) (IEEE80211_RATE_BASIC | r)
#define Mb(x) (x*1000)
static struct ieee80211_rate_table ieee80211_11b_table = {
@@ -176,6 +179,98 @@ static struct ieee80211_rate_table ieee80211_turboa_table = {
},
};
+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 },
+
+ [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 },
+
+ [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 },
+
+ [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 },
+
+ },
+};
+
+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 },
+
+ [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 },
+
+ [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 },
+
+ [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 },
+
+ },
+};
+
#undef Mb
#undef B
#undef OFDM
@@ -184,6 +279,8 @@ static struct ieee80211_rate_table ieee80211_turboa_table = {
#undef CCK
#undef TURBO
#undef XR
+#undef HT
+#undef N
/*
* Setup a rate table's reverse lookup table and fill in
@@ -210,15 +307,23 @@ ieee80211_setup_ratetable(struct ieee80211_rate_table *rt)
uint8_t cix = rt->info[i].ctlRateIndex;
uint8_t ctl_rate = rt->info[cix].dot11Rate;
- rt->rateCodeToIndex[code] = i;
- if (code & IEEE80211_RATE_BASIC) {
- /*
- * Map w/o basic rate bit too.
- */
- code &= IEEE80211_RATE_VAL;
- rt->rateCodeToIndex[code] = i;
+ /*
+ * 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;
}
+ /* XXX assume the control rate is non-MCS? */
+ ctl_rate &= IEEE80211_RATE_VAL;
+ rt->rateCodeToIndex[code] = i;
+
/*
* XXX for 11g the control rate to use for 5.5 and 11 Mb/s
* depends on whether they are marked as basic rates;
@@ -247,11 +352,10 @@ ieee80211_phy_init(void)
static struct ieee80211_rate_table * const ratetables[] = {
&ieee80211_half_table,
&ieee80211_quarter_table,
- &ieee80211_11a_table,
- &ieee80211_11g_table,
+ &ieee80211_11na_table,
+ &ieee80211_11ng_table,
&ieee80211_turbog_table,
&ieee80211_turboa_table,
- &ieee80211_turboa_table,
&ieee80211_11a_table,
&ieee80211_11g_table,
&ieee80211_11b_table
@@ -276,9 +380,9 @@ ieee80211_get_ratetable(struct ieee80211_channel *c)
else if (IEEE80211_IS_CHAN_QUARTER(c))
rt = &ieee80211_quarter_table;
else if (IEEE80211_IS_CHAN_HTA(c))
- rt = &ieee80211_11a_table; /* XXX */
+ rt = &ieee80211_11na_table;
else if (IEEE80211_IS_CHAN_HTG(c))
- rt = &ieee80211_11g_table; /* XXX */
+ rt = &ieee80211_11ng_table;
else if (IEEE80211_IS_CHAN_108G(c))
rt = &ieee80211_turbog_table;
else if (IEEE80211_IS_CHAN_ST(c))
@@ -463,3 +567,66 @@ ieee80211_compute_duration(const struct ieee80211_rate_table *rt,
}
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)
+
+#define HT_RC_2_MCS(_rc) ((_rc) & 0xf)
+#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1)
+#define IS_HT_RATE(_rc) ( (_rc) & IEEE80211_RATE_MCS)
+
+/*
+ * 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 IS_HT_RATE
+#undef HT_RC_2_STREAMS
+#undef HT_RC_2_MCS
+#undef HT_LTF
+#undef HT_STF
+#undef HT_SIG
+#undef HT_L_SIG
+#undef HT_L_LTF
+#undef HT_L_STF
+#undef OFDM_PLCP_BITS
diff --git a/sys/net80211/ieee80211_phy.h b/sys/net80211/ieee80211_phy.h
index 56b404f7..bf39cdd 100644
--- a/sys/net80211/ieee80211_phy.h
+++ b/sys/net80211/ieee80211_phy.h
@@ -60,6 +60,8 @@
struct ieee80211_channel;
+#define IEEE80211_RATE_TABLE_SIZE 128
+
struct ieee80211_rate_table {
int rateCount; /* NB: for proper padding */
uint8_t rateCodeToIndex[256]; /* back mapping */
@@ -74,7 +76,7 @@ struct ieee80211_rate_table {
* rate; used for dur. calcs */
uint16_t lpAckDuration; /* long preamble ACK dur. */
uint16_t spAckDuration; /* short preamble ACK dur. */
- } info[32];
+ } info[IEEE80211_RATE_TABLE_SIZE];
};
const struct ieee80211_rate_table *ieee80211_get_ratetable(
@@ -83,7 +85,14 @@ const struct ieee80211_rate_table *ieee80211_get_ratetable(
static __inline__ uint8_t
ieee80211_ack_rate(const struct ieee80211_rate_table *rt, uint8_t rate)
{
- uint8_t cix = rt->info[rt->rateCodeToIndex[rate]].ctlRateIndex;
+ /*
+ * 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;
}
@@ -91,7 +100,14 @@ ieee80211_ack_rate(const struct ieee80211_rate_table *rt, uint8_t rate)
static __inline__ uint8_t
ieee80211_ctl_rate(const struct ieee80211_rate_table *rt, uint8_t rate)
{
- uint8_t cix = rt->info[rt->rateCodeToIndex[rate]].ctlRateIndex;
+ /*
+ * 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;
}
@@ -99,7 +115,14 @@ ieee80211_ctl_rate(const struct ieee80211_rate_table *rt, uint8_t rate)
static __inline__ enum ieee80211_phytype
ieee80211_rate2phytype(const struct ieee80211_rate_table *rt, uint8_t rate)
{
- uint8_t rix = rt->rateCodeToIndex[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));
+
+ 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;
}
@@ -107,6 +130,13 @@ ieee80211_rate2phytype(const struct ieee80211_rate_table *rt, uint8_t rate)
static __inline__ int
ieee80211_isratevalid(const struct ieee80211_rate_table *rt, uint8_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;
}
@@ -134,6 +164,14 @@ ieee80211_ack_duration(const struct ieee80211_rate_table *rt,
}
}
+static __inline__ uint8_t
+ieee80211_legacy_rate_lookup(const struct ieee80211_rate_table *rt,
+ uint8_t rate)
+{
+
+ return (rt->rateCodeToIndex[rate & IEEE80211_RATE_VAL]);
+}
+
/*
* Compute the time to transmit a frame of length frameLen bytes
* using the specified 802.11 rate code, phy, and short preamble
@@ -151,5 +189,10 @@ uint8_t ieee80211_plcp2rate(uint8_t, enum ieee80211_phytype);
* Convert 802.11 rate code to PLCP signal.
*/
uint8_t ieee80211_rate2plcp(int, enum ieee80211_phytype);
+
+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_ */
OpenPOWER on IntegriCloud