Changeset View
Changeset View
Standalone View
Standalone View
sys/net80211/ieee80211_ht.c
Show First 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | |||||
#include <net80211/ieee80211_var.h> | #include <net80211/ieee80211_var.h> | ||||
#include <net80211/ieee80211_action.h> | #include <net80211/ieee80211_action.h> | ||||
#include <net80211/ieee80211_input.h> | #include <net80211/ieee80211_input.h> | ||||
/* define here, used throughout file */ | /* define here, used throughout file */ | ||||
#define MS(_v, _f) (((_v) & _f) >> _f##_S) | #define MS(_v, _f) (((_v) & _f) >> _f##_S) | ||||
#define SM(_v, _f) (((_v) << _f##_S) & _f) | #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) */ | static int ieee80211_ampdu_age = -1; /* threshold for ampdu reorder q (ms) */ | ||||
SYSCTL_PROC(_net_wlan, OID_AUTO, ampdu_age, CTLTYPE_INT | CTLFLAG_RW, | SYSCTL_PROC(_net_wlan, OID_AUTO, ampdu_age, CTLTYPE_INT | CTLFLAG_RW, | ||||
&ieee80211_ampdu_age, 0, ieee80211_sysctl_msecs_ticks, "I", | &ieee80211_ampdu_age, 0, ieee80211_sysctl_msecs_ticks, "I", | ||||
"AMPDU max reorder age (ms)"); | "AMPDU max reorder age (ms)"); | ||||
static int ieee80211_recv_bar_ena = 1; | static int ieee80211_recv_bar_ena = 1; | ||||
SYSCTL_INT(_net_wlan, OID_AUTO, recv_bar, CTLFLAG_RW, &ieee80211_recv_bar_ena, | SYSCTL_INT(_net_wlan, OID_AUTO, recv_bar, CTLFLAG_RW, &ieee80211_recv_bar_ena, | ||||
0, "BAR frame processing (ena/dis)"); | 0, "BAR frame processing (ena/dis)"); | ||||
▲ Show 20 Lines • Show All 162 Lines • ▼ Show 20 Lines | if (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY) | ||||
vap->iv_flags_ht &= ~IEEE80211_FHT_HT; | vap->iv_flags_ht &= ~IEEE80211_FHT_HT; | ||||
} | } | ||||
void | void | ||||
ieee80211_ht_vdetach(struct ieee80211vap *vap) | ieee80211_ht_vdetach(struct ieee80211vap *vap) | ||||
{ | { | ||||
} | } | ||||
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 { | static struct printranges { | ||||
int minmcs; | int minmcs; | ||||
int maxmcs; | int maxmcs; | ||||
int txstream; | int txstream; | ||||
int ratetype; | |||||
int htcapflags; | int htcapflags; | ||||
} ranges[] = { | } ranges[] = { | ||||
{ 0, 7, 1, 0, 0 }, | { 0, 7, 1, 0 }, | ||||
{ 8, 15, 2, 0, 0 }, | { 8, 15, 2, 0 }, | ||||
{ 16, 23, 3, 0, 0 }, | { 16, 23, 3, 0 }, | ||||
{ 24, 31, 4, 0, 0 }, | { 24, 31, 4, 0 }, | ||||
{ 32, 0, 1, 2, IEEE80211_HTC_TXMCS32 }, | { 32, 0, 1, IEEE80211_HTC_TXMCS32 }, | ||||
{ 33, 38, 2, 0, IEEE80211_HTC_TXUNEQUAL }, | { 33, 38, 2, IEEE80211_HTC_TXUNEQUAL }, | ||||
{ 39, 52, 3, 0, IEEE80211_HTC_TXUNEQUAL }, | { 39, 52, 3, IEEE80211_HTC_TXUNEQUAL }, | ||||
{ 53, 76, 4, 0, IEEE80211_HTC_TXUNEQUAL }, | { 53, 76, 4, IEEE80211_HTC_TXUNEQUAL }, | ||||
{ 0, 0, 0, 0, 0 }, | { 0, 0, 0, 0 }, | ||||
}; | }; | ||||
static void | 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; | int minrate, maxrate; | ||||
struct printranges *range; | struct printranges *range; | ||||
for (range = ranges; range->txstream != 0; range++) { | for (range = ranges; range->txstream != 0; range++) { | ||||
if (ic->ic_txstream < range->txstream) | if (ic->ic_txstream < range->txstream) | ||||
continue; | continue; | ||||
if (range->htcapflags && | if (range->htcapflags && | ||||
(ic->ic_htcaps & range->htcapflags) == 0) | (ic->ic_htcaps & range->htcapflags) == 0) | ||||
continue; | continue; | ||||
if (ratetype < range->ratetype) | |||||
continue; | minrate = GET_RATE(range->minmcs); | ||||
minrate = ht_getrate(ic, range->minmcs, mode, ratetype); | |||||
maxrate = ht_getrate(ic, range->maxmcs, mode, ratetype); | |||||
if (range->maxmcs) { | if (range->maxmcs) { | ||||
maxrate = GET_RATE(range->maxmcs); | |||||
ic_printf(ic, "MCS %d-%d: %d%sMbps - %d%sMbps\n", | ic_printf(ic, "MCS %d-%d: %d%sMbps - %d%sMbps\n", | ||||
range->minmcs, range->maxmcs, | range->minmcs, range->maxmcs, | ||||
minrate/2, ((minrate & 0x1) != 0 ? ".5" : ""), | minrate/2, ((minrate & 0x1) != 0 ? ".5" : ""), | ||||
maxrate/2, ((maxrate & 0x1) != 0 ? ".5" : "")); | maxrate/2, ((maxrate & 0x1) != 0 ? ".5" : "")); | ||||
} else { | } else if (minrate) { | ||||
ic_printf(ic, "MCS %d: %d%sMbps\n", range->minmcs, | ic_printf(ic, "MCS %d: %d%sMbps\n", range->minmcs, | ||||
minrate/2, ((minrate & 0x1) != 0 ? ".5" : "")); | minrate/2, ((minrate & 0x1) != 0 ? ".5" : "")); | ||||
} | } | ||||
} | } | ||||
#undef GET_RATE | |||||
#undef RIDX | |||||
} | } | ||||
static void | static void | ||||
ht_announce(struct ieee80211com *ic, enum ieee80211_phymode mode) | ht_announce(struct ieee80211com *ic, enum ieee80211_phymode mode) | ||||
{ | { | ||||
const char *modestr = ieee80211_phymode_name[mode]; | const char *modestr = ieee80211_phymode_name[mode]; | ||||
ic_printf(ic, "%s MCS 20MHz\n", modestr); | 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) { | if (ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20) { | ||||
ic_printf(ic, "%s MCS 20MHz SGI\n", modestr); | 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) { | if (ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) { | ||||
ic_printf(ic, "%s MCS 40MHz:\n", modestr); | 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) && | if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) && | ||||
(ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40)) { | (ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40)) { | ||||
ic_printf(ic, "%s MCS 40MHz SGI:\n", modestr); | ic_printf(ic, "%s MCS 40MHz SGI:\n", modestr); | ||||
ht_rateprint(ic, mode, 3); | ht_rateprint(ic, IEEE80211_CHAN_HT40, 1); | ||||
} | } | ||||
} | } | ||||
void | void | ||||
ieee80211_ht_announce(struct ieee80211com *ic) | ieee80211_ht_announce(struct ieee80211com *ic) | ||||
{ | { | ||||
if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA) || | if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA) || | ||||
isset(ic->ic_modecaps, IEEE80211_MODE_11NG)) | isset(ic->ic_modecaps, IEEE80211_MODE_11NG)) | ||||
ic_printf(ic, "%dT%dR\n", ic->ic_txstream, ic->ic_rxstream); | ic_printf(ic, "%dT%dR\n", ic->ic_txstream, ic->ic_rxstream); | ||||
if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA)) | if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA)) | ||||
ht_announce(ic, IEEE80211_MODE_11NA); | ht_announce(ic, IEEE80211_MODE_11NA); | ||||
if (isset(ic->ic_modecaps, IEEE80211_MODE_11NG)) | if (isset(ic->ic_modecaps, IEEE80211_MODE_11NG)) | ||||
ht_announce(ic, IEEE80211_MODE_11NG); | ht_announce(ic, IEEE80211_MODE_11NG); | ||||
} | } | ||||
void | void | ||||
ieee80211_init_suphtrates(struct ieee80211com *ic) | ieee80211_init_suphtrates(struct ieee80211com *ic) | ||||
{ | { | ||||
#define ADDRATE(x) do { \ | #define CHECK_CAPS(_ic, _mask) (((_ic)->ic_htcaps & (_mask)) == (_mask)) | ||||
htrateset->rs_rates[htrateset->rs_nrates] = x; \ | const struct ieee80211_rate_t *rate; | ||||
htrateset->rs_nrates++; \ | |||||
} while (0) | |||||
struct ieee80211_htrateset *htrateset = &ic->ic_sup_htrates; | struct ieee80211_htrateset *htrateset = &ic->ic_sup_htrates; | ||||
int i; | int i, has_mcs32, has_unequal; | ||||
memset(htrateset, 0, sizeof(struct ieee80211_htrateset)); | has_mcs32 = | ||||
for (i = 0; i < ic->ic_txstream * 8; i++) | CHECK_CAPS(ic, IEEE80211_HTCAP_CHWIDTH40 | IEEE80211_HTC_TXMCS32); | ||||
ADDRATE(i); | has_unequal = CHECK_CAPS(ic, IEEE80211_HTC_TXUNEQUAL); | ||||
if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) && | |||||
(ic->ic_htcaps & IEEE80211_HTC_TXMCS32)) | memset(htrateset, 0, sizeof(*htrateset)); | ||||
ADDRATE(32); | for (i = IEEE80211_RATE_INDEX_HT(0); i < IEEE80211_RATES_COUNT; i++) { | ||||
if (ic->ic_htcaps & IEEE80211_HTC_TXUNEQUAL) { | rate = ieee80211_get_rate(i); | ||||
if (ic->ic_txstream >= 2) { | |||||
for (i = 33; i <= 38; i++) | if (rate->type != IEEE80211_T_HT) | ||||
ADDRATE(i); | 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++; | |||||
} | } | ||||
if (ic->ic_txstream >= 3) { | #undef CHECK_CAPS | ||||
for (i = 39; i <= 52; i++) | |||||
ADDRATE(i); | |||||
} | } | ||||
if (ic->ic_txstream == 4) { | |||||
for (i = 53; i <= 76; i++) | |||||
ADDRATE(i); | |||||
} | |||||
} | |||||
#undef ADDRATE | |||||
} | |||||
/* | /* | ||||
* Receive processing. | * Receive processing. | ||||
*/ | */ | ||||
/* | /* | ||||
* Decap the encapsulated A-MSDU frames and dispatch all but | * Decap the encapsulated A-MSDU frames and dispatch all but | ||||
* the last for delivery. The last frame is returned for | * the last for delivery. The last frame is returned for | ||||
▲ Show 20 Lines • Show All 1,457 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/* | /* | ||||
* Install received HT rate set by parsing the HT cap ie. | * Install received HT rate set by parsing the HT cap ie. | ||||
*/ | */ | ||||
int | int | ||||
ieee80211_setup_htrates(struct ieee80211_node *ni, const uint8_t *ie, int flags) | 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 ieee80211com *ic = ni->ni_ic; | ||||
struct ieee80211vap *vap = ni->ni_vap; | struct ieee80211vap *vap = ni->ni_vap; | ||||
const struct ieee80211_rate_t *rate; | |||||
const struct ieee80211_ie_htcap *htcap; | const struct ieee80211_ie_htcap *htcap; | ||||
struct ieee80211_htrateset *rs; | struct ieee80211_htrateset *rs; | ||||
int i, maxequalmcs, maxunequalmcs; | int i, has_mcs32, has_unequal; | ||||
maxequalmcs = ic->ic_txstream * 8 - 1; | has_mcs32 = | ||||
maxunequalmcs = 0; | CHECK_CAPS(ic, IEEE80211_HTCAP_CHWIDTH40 | IEEE80211_HTC_TXMCS32); | ||||
if (ic->ic_htcaps & IEEE80211_HTC_TXUNEQUAL) { | has_unequal = CHECK_CAPS(ic, IEEE80211_HTC_TXUNEQUAL); | ||||
if (ic->ic_txstream >= 2) | |||||
maxunequalmcs = 38; | |||||
if (ic->ic_txstream >= 3) | |||||
maxunequalmcs = 52; | |||||
if (ic->ic_txstream >= 4) | |||||
maxunequalmcs = 76; | |||||
} | |||||
rs = &ni->ni_htrates; | rs = &ni->ni_htrates; | ||||
memset(rs, 0, sizeof(*rs)); | memset(rs, 0, sizeof(*rs)); | ||||
if (ie != NULL) { | if (ie == NULL) | ||||
goto end; | |||||
if (ie[0] == IEEE80211_ELEMID_VENDOR) | if (ie[0] == IEEE80211_ELEMID_VENDOR) | ||||
ie += 4; | ie += 4; | ||||
htcap = (const struct ieee80211_ie_htcap *) ie; | htcap = (const struct ieee80211_ie_htcap *) ie; | ||||
for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++) { | |||||
if (isclr(htcap->hc_mcsset, i)) | 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; | continue; | ||||
if (rs->rs_nrates == IEEE80211_HTRATE_MAXSIZE) { | if (rs->rs_nrates == IEEE80211_HTRATE_MAXSIZE) { | ||||
IEEE80211_NOTE(vap, | IEEE80211_NOTE(vap, | ||||
IEEE80211_MSG_XRATE | IEEE80211_MSG_11N, ni, | IEEE80211_MSG_XRATE | IEEE80211_MSG_11N, ni, | ||||
"WARNING, HT rate set too large; only " | "WARNING, HT rate set too large; only " | ||||
"using %u rates", IEEE80211_HTRATE_MAXSIZE); | "using %u rates", IEEE80211_HTRATE_MAXSIZE); | ||||
vap->iv_stats.is_rx_rstoobig++; | vap->iv_stats.is_rx_rstoobig++; | ||||
break; | break; | ||||
} | } | ||||
if (i <= 31 && i > maxequalmcs) | |||||
if (rate->props.ht.streams > ic->ic_txstream || | |||||
(rate->value == 32 && !has_mcs32)) | |||||
continue; | continue; | ||||
if (i == 32 && | |||||
(ic->ic_htcaps & IEEE80211_HTC_TXMCS32) == 0) | if (rate->props.ht.unequal && !has_unequal) | ||||
continue; | break; | ||||
if (i > 32 && i > maxunequalmcs) | |||||
continue; | setbit(rs->rs_bitmap, rate->value); | ||||
rs->rs_rates[rs->rs_nrates++] = i; | 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); | return ieee80211_fix_rate(ni, (struct ieee80211_rateset *) rs, flags); | ||||
#undef CHECK_CAPS | |||||
} | } | ||||
/* | /* | ||||
* Mark rates in a node's HT rate set as basic according | * Mark rates in a node's HT rate set as basic according | ||||
* to the information in the supplied HT info ie. | * to the information in the supplied HT info ie. | ||||
*/ | */ | ||||
void | void | ||||
ieee80211_setup_basic_htrates(struct ieee80211_node *ni, const uint8_t *ie) | ieee80211_setup_basic_htrates(struct ieee80211_node *ni, const uint8_t *ie) | ||||
{ | { | ||||
const struct ieee80211_rate_t *rate; | |||||
const struct ieee80211_ie_htinfo *htinfo; | const struct ieee80211_ie_htinfo *htinfo; | ||||
struct ieee80211_htrateset *rs; | struct ieee80211_htrateset *rs; | ||||
int i, j; | int i; | ||||
if (ie[0] == IEEE80211_ELEMID_VENDOR) | if (ie[0] == IEEE80211_ELEMID_VENDOR) | ||||
ie += 4; | ie += 4; | ||||
htinfo = (const struct ieee80211_ie_htinfo *) ie; | htinfo = (const struct ieee80211_ie_htinfo *) ie; | ||||
rs = &ni->ni_htrates; | rs = &ni->ni_htrates; | ||||
if (rs->rs_nrates == 0) { | if (rs->rs_nrates == 0) { | ||||
IEEE80211_NOTE(ni->ni_vap, | IEEE80211_NOTE(ni->ni_vap, | ||||
IEEE80211_MSG_XRATE | IEEE80211_MSG_11N, ni, | IEEE80211_MSG_XRATE | IEEE80211_MSG_11N, ni, | ||||
"%s", "WARNING, empty HT rate set"); | "%s", "WARNING, empty HT rate set"); | ||||
return; | return; | ||||
} | } | ||||
for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++) { | for (i = 0; i < rs->rs_nrates; i++) { | ||||
if (isclr(htinfo->hi_basicmcsset, i)) | rate = ieee80211_get_rate(rs->rates[i].rs_index); | ||||
continue; | if (isset(htinfo->hi_basicmcsset, rate->value)) | ||||
for (j = 0; j < rs->rs_nrates; j++) | rs->rates[i].rs_basic = 1; | ||||
if ((rs->rs_rates[j] & IEEE80211_RATE_VAL) == i) | |||||
rs->rs_rates[j] |= IEEE80211_RATE_BASIC; | |||||
} | } | ||||
} | } | ||||
static void | static void | ||||
ampdu_tx_setup(struct ieee80211_tx_ampdu *tap) | ampdu_tx_setup(struct ieee80211_tx_ampdu *tap) | ||||
{ | { | ||||
callout_init(&tap->txa_timer, 1); | callout_init(&tap->txa_timer, 1); | ||||
tap->txa_flags |= IEEE80211_AGGR_SETUP; | tap->txa_flags |= IEEE80211_AGGR_SETUP; | ||||
▲ Show 20 Lines • Show All 787 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static int | static int | ||||
ht_action_output(struct ieee80211_node *ni, struct mbuf *m) | ht_action_output(struct ieee80211_node *ni, struct mbuf *m) | ||||
{ | { | ||||
struct ieee80211_bpf_params params; | struct ieee80211_bpf_params params; | ||||
memset(¶ms, 0, sizeof(params)); | memset(¶ms, 0, sizeof(params)); | ||||
params.ibp_vers = IEEE80211_BPF_VERSION_1; | |||||
params.ibp_pri = WME_AC_VO; | 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 */ | /* NB: we know all frames are unicast */ | ||||
params.ibp_try0 = ni->ni_txparms->maxretry; | params.ibp_try0 = ni->ni_txparms->maxretry; | ||||
params.ibp_power = ni->ni_txpower; | params.ibp_power = ni->ni_txpower; | ||||
return ieee80211_mgmt_output(ni, m, IEEE80211_FC0_SUBTYPE_ACTION, | return ieee80211_mgmt_output(ni, m, IEEE80211_FC0_SUBTYPE_ACTION, | ||||
¶ms); | ¶ms); | ||||
} | } | ||||
#define ADDSHORT(frm, v) do { \ | #define ADDSHORT(frm, v) do { \ | ||||
▲ Show 20 Lines • Show All 434 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Construct the MCS bit mask of basic rates | * Construct the MCS bit mask of basic rates | ||||
* for inclusion in an HT information element. | * for inclusion in an HT information element. | ||||
*/ | */ | ||||
static void | static void | ||||
ieee80211_set_basic_htrates(uint8_t *frm, const struct ieee80211_htrateset *rs) | ieee80211_set_basic_htrates(uint8_t *frm, const struct ieee80211_htrateset *rs) | ||||
{ | { | ||||
const struct ieee80211_rate_t *rate; | |||||
int i; | int i; | ||||
for (i = 0; i < rs->rs_nrates; i++) { | for (i = 0; i < rs->rs_nrates; i++) { | ||||
int r = rs->rs_rates[i] & IEEE80211_RATE_VAL; | if (rs->rates[i].rs_basic) { | ||||
if ((rs->rs_rates[i] & IEEE80211_RATE_BASIC) && | |||||
r < IEEE80211_HTRATE_MAXSIZE) { | |||||
/* NB: this assumes a particular implementation */ | /* NB: this assumes a particular implementation */ | ||||
setbit(frm, r); | rate = ieee80211_get_rate(rs->rates[i].rs_index); | ||||
setbit(frm, rate->value); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Update the HTINFO ie for a beacon frame. | * Update the HTINFO ie for a beacon frame. | ||||
*/ | */ | ||||
void | void | ||||
▲ Show 20 Lines • Show All 106 Lines • Show Last 20 Lines |