Changeset View
Changeset View
Standalone View
Standalone View
sys/net80211/ieee80211_proto.c
Show First 20 Lines • Show All 341 Lines • ▼ Show 20 Lines | ieee80211_proto_vattach(struct ieee80211vap *vap) | ||||
TASK_INIT(&vap->iv_wme_task, 0, vap_update_wme, vap); | TASK_INIT(&vap->iv_wme_task, 0, vap_update_wme, vap); | ||||
/* | /* | ||||
* Install default tx rate handling: no fixed rate, lowest | * Install default tx rate handling: no fixed rate, lowest | ||||
* supported rate for mgmt and multicast frames. Default | * supported rate for mgmt and multicast frames. Default | ||||
* max retry count. These settings can be changed by the | * max retry count. These settings can be changed by the | ||||
* driver and/or user applications. | * driver and/or user applications. | ||||
*/ | */ | ||||
for (i = IEEE80211_MODE_11A; i < IEEE80211_MODE_MAX; i++) { | 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 | * Setting the management rate to MCS 0 assumes that the | ||||
* BSS Basic rate set is empty and the BSS Basic MCS set | * BSS Basic rate set is empty and the BSS Basic MCS set | ||||
* is not. | * is not. | ||||
* | * | ||||
* Since we're not checking this, default to the lowest | * Since we're not checking this, default to the lowest | ||||
* defined rate for this mode. | * defined rate for this mode. | ||||
* | * | ||||
* At least one 11n AP (DLINK DIR-825) is reported to drop | * At least one 11n AP (DLINK DIR-825) is reported to drop | ||||
* some MCS management traffic (eg BA response frames.) | * some MCS management traffic (eg BA response frames.) | ||||
* | * | ||||
* See also: 9.6.0 of the 802.11n-2009 specification. | * See also: 9.6.0 of the 802.11n-2009 specification. | ||||
*/ | */ | ||||
#ifdef NOTYET | #ifdef NOTYET | ||||
if (i == IEEE80211_MODE_11NA || i == IEEE80211_MODE_11NG) { | if (i == IEEE80211_MODE_11NA || i == IEEE80211_MODE_11NG) { | ||||
vap->iv_txparms[i].mgmtrate = 0 | IEEE80211_RATE_MCS; | const struct ieee80211_htrateset *hrs; | ||||
vap->iv_txparms[i].mcastrate = 0 | IEEE80211_RATE_MCS; | |||||
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 { | } else { | ||||
vap->iv_txparms[i].mgmtrate = rs->rates[0].rs_index; | |||||
vap->iv_txparms[i].mcastrate = rs->rates[0].rs_index; | |||||
} | |||||
#endif | |||||
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 = | vap->iv_txparms[i].mgmtrate = | ||||
rs->rs_rates[0] & IEEE80211_RATE_VAL; | IEEE80211_RATE_NONEXISTENT; | ||||
vap->iv_txparms[i].mcastrate = | vap->iv_txparms[i].mcastrate = | ||||
rs->rs_rates[0] & IEEE80211_RATE_VAL; | IEEE80211_RATE_NONEXISTENT; | ||||
} | } | ||||
#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; | |||||
vap->iv_txparms[i].maxretry = IEEE80211_TXMAX_DEFAULT; | vap->iv_txparms[i].maxretry = IEEE80211_TXMAX_DEFAULT; | ||||
} | } | ||||
vap->iv_roaming = IEEE80211_ROAMING_AUTO; | vap->iv_roaming = IEEE80211_ROAMING_AUTO; | ||||
vap->iv_update_beacon = null_update_beacon; | vap->iv_update_beacon = null_update_beacon; | ||||
vap->iv_deliver_data = ieee80211_deliver_data; | vap->iv_deliver_data = ieee80211_deliver_data; | ||||
/* attach support for operating mode */ | /* attach support for operating mode */ | ||||
▲ Show 20 Lines • Show All 222 Lines • ▼ Show 20 Lines | for (i = 0; i < len; i++) { | ||||
printf(" "); | printf(" "); | ||||
printf("%02x", buf[i]); | printf("%02x", buf[i]); | ||||
} | } | ||||
printf("\n"); | printf("\n"); | ||||
} | } | ||||
} | } | ||||
static __inline int | static __inline int | ||||
findrix(const struct ieee80211_rateset *rs, int r) | findrix(const struct ieee80211_rateset *rs, uint16_t rate_index) | ||||
{ | { | ||||
int i; | int i; | ||||
for (i = 0; i < rs->rs_nrates; 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 i; | ||||
return -1; | 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 | int | ||||
ieee80211_fix_rate(struct ieee80211_node *ni, | ieee80211_fix_rate(struct ieee80211_node *ni, | ||||
struct ieee80211_rateset *nrs, int flags) | struct ieee80211_rateset *nrs, int flags) | ||||
{ | { | ||||
struct ieee80211vap *vap = ni->ni_vap; | struct ieee80211vap *vap = ni->ni_vap; | ||||
struct ieee80211com *ic = ni->ni_ic; | struct ieee80211com *ic = ni->ni_ic; | ||||
int i, j, rix, error; | |||||
int okrate, badrate, fixedrate, ucastrate; | |||||
const struct ieee80211_rateset *srs; | 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; | error = 0; | ||||
okrate = badrate = 0; | okrate = lastrate = IEEE80211_RATE_NONEXISTENT; | ||||
ucastrate = vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)].ucastrate; | 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 | * Workaround awkwardness with fixed rate. We are called | ||||
* to check both the legacy rate set and the HT rate set | * to check both the legacy rate set and the HT rate set | ||||
* but we must apply any legacy fixed rate check only to the | * but we must apply any legacy fixed rate check only to the | ||||
* legacy rate set and vice versa. We cannot tell what type | * legacy rate set and vice versa. We cannot tell what type | ||||
* of rate set we've been given (legacy or HT) but we can | * 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 | * So to deal with this the caller communicates whether to | ||||
* check MCS or legacy rate using the flags and we use the | * check MCS or legacy rate using the flags and we use the | ||||
* type of any fixed rate to avoid applying an MCS to a | * type of any fixed rate to avoid applying an MCS to a | ||||
* legacy rate and vice versa. | * legacy rate and vice versa. | ||||
*/ | */ | ||||
if (ucastrate & 0x80) { | rate = ieee80211_get_rate(ucastrate); | ||||
if (flags & IEEE80211_F_DOFRATE) | switch (rate->type) { | ||||
flags &= ~IEEE80211_F_DOFRATE; | case IEEE80211_T_VHT: | ||||
} else if ((ucastrate & 0x80) == 0) { | if (rateset_type != IEEE80211_F_RATE_VHT) | ||||
if (flags & IEEE80211_F_DOFMCS) | flags &= ~IEEE80211_F_DOFIXED; | ||||
flags &= ~IEEE80211_F_DOFMCS; | |||||
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 */ | } else | ||||
ucastrate &= IEEE80211_RATE_VAL; | flags &= ~IEEE80211_F_DOFIXED; | ||||
} | |||||
fixedrate = IEEE80211_FIXED_RATE_NONE; | |||||
/* | /* | ||||
* 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 | * we must use the appropriate basic rate set or chaos will | ||||
* ensue; for now callers that want MCS must supply | * ensue. | ||||
* 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. | |||||
*/ | */ | ||||
if (flags & IEEE80211_F_DOBRS) | switch (rateset_type) { | ||||
case IEEE80211_F_RATE_VHT: | |||||
srs = (const struct ieee80211_rateset *) | srs = (const struct ieee80211_rateset *) | ||||
ieee80211_get_suphtrates(ic, ni->ni_chan); | ieee80211_get_supvhtrates(ic); | ||||
else | 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); | 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; ) { | for (i = 0; i < nrs->rs_nrates; ) { | ||||
if (flags & IEEE80211_F_DOSORT) { | if (flags & IEEE80211_F_DOSORT) | ||||
sortrate(nrs, i); | |||||
lastrate = nrs->rates[i].rs_index; | |||||
/* | /* | ||||
* 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; | |||||
/* | |||||
* Check for fixed rate. | * Check for fixed rate. | ||||
*/ | */ | ||||
if (r == ucastrate) | if (lastrate == ucastrate) | ||||
fixedrate = r; | fixed_rate_found = 1; | ||||
/* | /* | ||||
* Check against supported rates. | * Check against supported rates. | ||||
*/ | */ | ||||
rix = findrix(srs, r); | rix = findrix(srs, lastrate); | ||||
if (flags & IEEE80211_F_DONEGO) { | if (flags & IEEE80211_F_DONEGO) { | ||||
if (rix < 0) { | if (rix < 0) { | ||||
/* | /* | ||||
* A rate in the node's rate set is not | * A rate in the node's rate set is not | ||||
* supported. If this is a basic rate and we | * supported. If this is a basic rate and we | ||||
* are operating as a STA then this is an error. | * are operating as a STA then this is an error. | ||||
* Otherwise we just discard/ignore the rate. | * Otherwise we just discard/ignore the rate. | ||||
*/ | */ | ||||
if ((flags & IEEE80211_F_JOIN) && | if ((flags & IEEE80211_F_JOIN) && | ||||
(nrs->rs_rates[i] & IEEE80211_RATE_BASIC)) | nrs->rates[i].rs_basic) | ||||
error++; | error++; | ||||
} else if ((flags & IEEE80211_F_JOIN) == 0) { | } else if ((flags & IEEE80211_F_JOIN) == 0) { | ||||
/* | /* Reset basic rate bit. */ | ||||
* Overwrite with the supported rate | nrs->rates[i].rs_basic = | ||||
* value so any basic rate bit is set. | srs->rates[rix].rs_basic; | ||||
*/ | |||||
nrs->rs_rates[i] = srs->rs_rates[rix]; | |||||
} | } | ||||
} | } | ||||
if ((flags & IEEE80211_F_DODEL) && rix < 0) { | if ((flags & IEEE80211_F_DODEL) && rix < 0) { | ||||
/* | /* | ||||
* Delete unacceptable rates. | * Delete unacceptable rates. | ||||
*/ | */ | ||||
nrs->rs_nrates--; | nrs->rs_nrates--; | ||||
for (j = i; j < nrs->rs_nrates; j++) | for (j = i; j < nrs->rs_nrates; j++) | ||||
nrs->rs_rates[j] = nrs->rs_rates[j + 1]; | nrs->rates[j] = nrs->rates[j + 1]; | ||||
nrs->rs_rates[j] = 0; | memset(&nrs->rates[j], 0, sizeof(nrs->rates[j])); | ||||
continue; | continue; | ||||
} | } | ||||
if (rix >= 0) | if (rix >= 0) | ||||
okrate = nrs->rs_rates[i]; | okrate = nrs->rates[i].rs_index; | ||||
i++; | i++; | ||||
} | } | ||||
if (okrate == 0 || error != 0 || | |||||
((flags & (IEEE80211_F_DOFRATE|IEEE80211_F_DOFMCS)) && | if (okrate == IEEE80211_RATE_NONEXISTENT || error != 0 || | ||||
fixedrate != ucastrate)) { | ((flags & IEEE80211_F_DOFIXED) && !fixed_rate_found)) { | ||||
IEEE80211_NOTE(vap, IEEE80211_MSG_XRATE | IEEE80211_MSG_11N, ni, | IEEE80211_NOTE(vap, IEEE80211_MSG_XRATE | IEEE80211_MSG_11N, ni, | ||||
"%s: flags 0x%x okrate %d error %d fixedrate 0x%x " | "%s: flags 0x%x okrate %d error %d ucastrate %x " | ||||
"ucastrate %x\n", __func__, fixedrate, ucastrate, flags); | "(found %d)\n", __func__, flags, okrate, error, | ||||
return badrate | IEEE80211_RATE_BASIC; | ucastrate, fixed_rate_found); | ||||
return (lastrate | IEEE80211_F_RATESET_ERROR); | |||||
} else | } else | ||||
return IEEE80211_RV(okrate); | return (okrate); | ||||
} | } | ||||
/* | /* | ||||
* Reset 11g-related state. | * Reset 11g-related state. | ||||
*/ | */ | ||||
void | void | ||||
ieee80211_reset_erp(struct ieee80211com *ic) | ieee80211_reset_erp(struct ieee80211com *ic) | ||||
{ | { | ||||
Show All 36 Lines | else | ||||
ic->ic_flags &= ~IEEE80211_F_SHSLOT; | ic->ic_flags &= ~IEEE80211_F_SHSLOT; | ||||
/* notify driver */ | /* notify driver */ | ||||
if (ic->ic_updateslot != NULL) | if (ic->ic_updateslot != NULL) | ||||
ic->ic_updateslot(ic); | ic->ic_updateslot(ic); | ||||
} | } | ||||
/* | /* | ||||
* Check if the specified rate set supports ERP. | * Check if the specified rate set supports ERP. | ||||
* NB: the rate set is assumed to be sorted. | |||||
*/ | */ | ||||
int | int | ||||
ieee80211_iserp_rateset(const struct ieee80211_rateset *rs) | ieee80211_iserp_rateset(const struct ieee80211_rateset *rs) | ||||
{ | { | ||||
static const int rates[] = { 2, 4, 11, 22, 12, 24, 48 }; | static const int rates[] = { 2, 4, 11, 22, 12, 24, 48 }; | ||||
int i, j; | int i; | ||||
if (rs->rs_nrates < nitems(rates)) | if (rs->rs_nrates < nitems(rates)) | ||||
return 0; | return (0); | ||||
for (i = 0; i < nitems(rates); i++) { | for (i = 0; i < nitems(rates); i++) | ||||
for (j = 0; j < rs->rs_nrates; j++) { | if (isclr(rs->rs_bitmap, rates[i])) | ||||
int r = rs->rs_rates[j] & IEEE80211_RATE_VAL; | return (0); | ||||
if (rates[i] == r) | |||||
goto next; | return (1); | ||||
if (r > rates[i]) | |||||
return 0; | |||||
} | } | ||||
return 0; | |||||
next: | |||||
; | |||||
} | |||||
return 1; | |||||
} | |||||
/* | /* | ||||
* Mark the basic rates for the rate table based on the | * Mark the basic rates for the rate table based on the | ||||
* operating mode. For real 11g we mark all the 11b rates | * operating mode. For real 11g we mark all the 11b rates | ||||
* and 6, 12, and 24 OFDM. For 11b compatibility we mark only | * and 6, 12, and 24 OFDM. For 11b compatibility we mark only | ||||
* 11b rates. There's also a pseudo 11a-mode used to mark only | * 11b rates. There's also a pseudo 11a-mode used to mark only | ||||
* the basic OFDM rates. | * the basic OFDM rates. | ||||
*/ | */ | ||||
static void | static void | ||||
setbasicrates(struct ieee80211_rateset *rs, | setbasicrates(struct ieee80211_rateset *rs, | ||||
enum ieee80211_phymode mode, int add) | enum ieee80211_phymode mode, int add) | ||||
{ | { | ||||
static const struct ieee80211_rateset basic[IEEE80211_MODE_MAX] = { | const struct ieee80211_rate_t *rate; | ||||
[IEEE80211_MODE_11A] = { 3, { 12, 24, 48 } }, | const struct ieee80211_rateset *basic; | ||||
[IEEE80211_MODE_11B] = { 2, { 2, 4 } }, | int i; | ||||
/* 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; | |||||
basic = ieee80211_get_basic_rateset(mode); | |||||
for (i = 0; i < rs->rs_nrates; i++) { | for (i = 0; i < rs->rs_nrates; i++) { | ||||
if (!add) | rate = ieee80211_get_rate(rs->rates[i].rs_index); | ||||
rs->rs_rates[i] &= IEEE80211_RATE_VAL; | |||||
for (j = 0; j < basic[mode].rs_nrates; j++) | if (isset(basic->rs_bitmap, rate->value)) | ||||
if (basic[mode].rs_rates[j] == rs->rs_rates[i]) { | rs->rates[i].rs_basic = 1; | ||||
rs->rs_rates[i] |= IEEE80211_RATE_BASIC; | else if (!add) | ||||
break; | rs->rates[i].rs_basic = 0; | ||||
} | |||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Set the basic rates in a rate set. | * Set the basic rates in a rate set. | ||||
*/ | */ | ||||
void | void | ||||
ieee80211_setbasicrates(struct ieee80211_rateset *rs, | ieee80211_setbasicrates(struct ieee80211_rateset *rs, | ||||
▲ Show 20 Lines • Show All 1,419 Lines • Show Last 20 Lines |