/* Get the rate control algorithm. */ staticconststruct rate_control_ops *
ieee80211_rate_control_ops_get(constchar *name)
{ conststruct rate_control_ops *ops; constchar *alg_name;
kernel_param_lock(THIS_MODULE); if (!name)
alg_name = ieee80211_default_rc_algo; else
alg_name = name;
ops = ieee80211_try_rate_control_ops_get(alg_name); if (!ops && name) /* try default if specific alg requested but not found */
ops = ieee80211_try_rate_control_ops_get(ieee80211_default_rc_algo);
/* Note: check for > 0 is intentional to avoid clang warning */ if (!ops && (strlen(CONFIG_MAC80211_RC_DEFAULT) > 0)) /* try built-in one if specific alg requested but not found */
ops = ieee80211_try_rate_control_ops_get(CONFIG_MAC80211_RC_DEFAULT);
sdata_dbg(sdata, "no overlap between basic rates (0x%x) and user mask (0x%x on band %d) - clearing the latter",
basic_rates, user_mask, band);
sdata->rc_rateidx_mask[band] = (1 << sband->n_bitrates) - 1;
}
info->control.rates[0].idx = 0; for (i = 0; i < sband->n_bitrates; i++) { if (!(rate_mask & BIT(i))) continue;
if ((rate_flags & sband->bitrates[i].flags) != rate_flags) continue;
if (!rate_supported(sta, sband->band, i)) continue;
info->control.rates[0].idx = i; break;
}
WARN_ONCE(i == sband->n_bitrates, "no supported rates for sta %pM (0x%x, band %d) in rate_mask 0x%x with flags 0x%x\n",
sta ? sta->addr : NULL,
sta ? sta->deflink.supp_rates[sband->band] : -1,
sband->band,
rate_mask, rate_flags);
if (!pubsta || rc_no_data_or_no_ack_use_min(txrc)) {
__rate_control_send_low(txrc->hw, sband, pubsta, info,
txrc->rate_idx_mask);
if (!pubsta && txrc->bss) {
mcast_rate = txrc->bss_conf->mcast_rate[sband->band]; if (mcast_rate > 0) {
info->control.rates[0].idx = mcast_rate - 1; returntrue;
}
use_basicrate = true;
} elseif (pubsta) {
sta = container_of(pubsta, struct sta_info, sta); if (ieee80211_vif_is_mesh(&sta->sdata->vif))
use_basicrate = true;
}
if (use_basicrate)
rc_send_low_basicrate(&info->control.rates[0],
txrc->bss_conf->basic_rates,
sband);
returntrue;
} returnfalse;
}
staticbool rate_idx_match_legacy_mask(s8 *rate_idx, int n_bitrates, u32 mask)
{ int j;
/* See whether the selected rate or anything below it is allowed. */ for (j = *rate_idx; j >= 0; j--) { if (mask & (1 << j)) { /* Okay, found a suitable rate. Use it. */
*rate_idx = j; returntrue;
}
}
/* Try to find a higher rate that would be allowed */ for (j = *rate_idx + 1; j < n_bitrates; j++) { if (mask & (1 << j)) { /* Okay, found a suitable rate. Use it. */
*rate_idx = j; returntrue;
}
} returnfalse;
}
staticbool rate_idx_match_mcs_mask(s8 *rate_idx, u8 *mcs_mask)
{ int i, j; int ridx, rbit;
/* See whether the selected rate or anything below it is allowed. */ for (i = ridx; i >= 0; i--) { for (j = rbit; j >= 0; j--) if (mcs_mask[i] & BIT(j)) {
*rate_idx = i * 8 + j; returntrue;
}
rbit = 7;
}
/* Try to find a higher rate that would be allowed */
ridx = (*rate_idx + 1) / 8;
rbit = (*rate_idx + 1) % 8;
for (i = ridx; i < IEEE80211_HT_MCS_MASK_LEN; i++) { for (j = rbit; j < 8; j++) if (mcs_mask[i] & BIT(j)) {
*rate_idx = i * 8 + j; returntrue;
}
rbit = 0;
} returnfalse;
}
staticbool rate_idx_match_vht_mcs_mask(s8 *rate_idx, u16 *vht_mask)
{ int i, j; int ridx, rbit;
ridx = *rate_idx >> 4;
rbit = *rate_idx & 0xf;
if (ridx < 0 || ridx >= NL80211_VHT_NSS_MAX) returnfalse;
/* See whether the selected rate or anything below it is allowed. */ for (i = ridx; i >= 0; i--) { for (j = rbit; j >= 0; j--) { if (vht_mask[i] & BIT(j)) {
*rate_idx = (i << 4) | j; returntrue;
}
}
rbit = 15;
}
/* Try to find a higher rate that would be allowed */
ridx = (*rate_idx + 1) >> 4;
rbit = (*rate_idx + 1) & 0xf;
for (i = ridx; i < NL80211_VHT_NSS_MAX; i++) { for (j = rbit; j < 16; j++) { if (vht_mask[i] & BIT(j)) {
*rate_idx = (i << 4) | j; returntrue;
}
}
rbit = 0;
} returnfalse;
}
*rate_flags |= IEEE80211_TX_RC_MCS; if (chan_width == NL80211_CHAN_WIDTH_40)
*rate_flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
if (rate_idx_match_mcs_mask(rate_idx, mcs_mask)) return;
/* also try the legacy rates. */
*rate_flags &= ~(IEEE80211_TX_RC_MCS |
IEEE80211_TX_RC_40_MHZ_WIDTH); if (rate_idx_match_legacy_mask(rate_idx, sband->n_bitrates,
mask)) return;
} elseif (*rate_flags & IEEE80211_TX_RC_MCS) { /* handle HT rates */ if (rate_idx_match_mcs_mask(rate_idx, mcs_mask)) return;
/* also try the legacy rates. */
*rate_idx = 0; /* keep protection flags */
*rate_flags &= (IEEE80211_TX_RC_USE_RTS_CTS |
IEEE80211_TX_RC_USE_CTS_PROTECT |
IEEE80211_TX_RC_USE_SHORT_PREAMBLE); if (rate_idx_match_legacy_mask(rate_idx, sband->n_bitrates,
mask)) return;
} else { /* handle legacy rates */ if (rate_idx_match_legacy_mask(rate_idx, sband->n_bitrates,
mask)) return;
/* if HT BSS, and we handle a data frame, also try HT rates */ switch (chan_width) { case NL80211_CHAN_WIDTH_20_NOHT: case NL80211_CHAN_WIDTH_5: case NL80211_CHAN_WIDTH_10: return; default: break;
}
if (chan_width == NL80211_CHAN_WIDTH_40)
*rate_flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
if (rate_idx_match_mcs_mask(rate_idx, mcs_mask)) return;
}
/* * Uh.. No suitable rate exists. This should not really happen with * sane TX rate mask configurations. However, should someone manage to * configure supported rates and TX rate mask in incompatible way, * allow the frame to be transmitted with whatever the rate control * selected.
*/
}
/* * Set up the RTS/CTS rate as the fastest basic rate * that is not faster than the data rate unless there * is no basic rate slower than the data rate, in which * case we pick the slowest basic rate * * XXX: Should this check all retry rates?
*/ if (!(rates[0].flags &
(IEEE80211_TX_RC_MCS | IEEE80211_TX_RC_VHT_MCS))) {
u32 basic_rates = vif->bss_conf.basic_rates;
s8 baserate = basic_rates ? ffs(basic_rates) - 1 : 0;
rate = &sband->bitrates[rates[0].idx];
for (i = 0; i < sband->n_bitrates; i++) { /* must be a basic rate */ if (!(basic_rates & BIT(i))) continue; /* must not be faster than the data rate */ if (sband->bitrates[i].bitrate > rate->bitrate) continue; /* maximum */ if (sband->bitrates[baserate].bitrate <
sband->bitrates[i].bitrate)
baserate = i;
}
info->control.rts_cts_rate_idx = baserate;
}
for (i = 0; i < max_rates; i++) { /* * make sure there's no valid rate following * an invalid one, just in case drivers don't * take the API seriously to stop at -1.
*/ if (inval) {
rates[i].idx = -1; continue;
} if (rates[i].idx < 0) {
inval = true; continue;
}
/* * For now assume MCS is already set up correctly, this * needs to be fixed.
*/ if (rates[i].flags & IEEE80211_TX_RC_MCS) {
WARN_ON(rates[i].idx > 76);
if (rates[i].flags & IEEE80211_TX_RC_VHT_MCS) {
WARN_ON(ieee80211_rate_get_vht_mcs(&rates[i]) > 9); continue;
}
/* set up RTS protection if desired */ if (info->control.use_rts) {
rates[i].flags |= IEEE80211_TX_RC_USE_RTS_CTS;
info->control.use_cts_prot = false;
}
/* RC is busted */ if (WARN_ON_ONCE(rates[i].idx >= sband->n_bitrates)) {
rates[i].idx = -1; continue;
}
rate = &sband->bitrates[rates[i].idx];
/* set up short preamble */ if (info->control.short_preamble &&
rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
rates[i].flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
/* set up G protection */ if (!(rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) &&
info->control.use_cts_prot &&
rate->flags & IEEE80211_RATE_ERP_G)
rates[i].flags |= IEEE80211_TX_RC_USE_CTS_PROTECT;
}
}
staticvoid rate_control_fill_sta_table(struct ieee80211_sta *sta, struct ieee80211_tx_info *info, struct ieee80211_tx_rate *rates, int max_rates)
{ struct ieee80211_sta_rates *ratetbl = NULL; int i;
if (sta && !info->control.skip_table)
ratetbl = rcu_dereference(sta->rates);
/* Fill remaining rate slots with data from the sta rate table. */
max_rates = min_t(int, max_rates, IEEE80211_TX_RATE_TABLE_SIZE); for (i = 0; i < max_rates; i++) { if (i < ARRAY_SIZE(info->control.rates) &&
info->control.rates[i].idx >= 0 &&
info->control.rates[i].count) { if (rates != info->control.rates)
rates[i] = info->control.rates[i];
} elseif (ratetbl) {
rates[i].idx = ratetbl->rate[i].idx;
rates[i].flags = ratetbl->rate[i].flags; if (info->control.use_rts)
rates[i].count = ratetbl->rate[i].count_rts; elseif (info->control.use_cts_prot)
rates[i].count = ratetbl->rate[i].count_cts; else
rates[i].count = ratetbl->rate[i].count;
} else {
rates[i].idx = -1;
rates[i].count = 0;
}
if (rates[i].idx < 0 || !rates[i].count) break;
}
}
if (sta) {
__le16 sta_vht_cap;
u16 sta_vht_mask[NL80211_VHT_NSS_MAX];
/* Filter out rates that the STA does not support */
*mask &= sta->deflink.supp_rates[sband->band]; for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
mcs_mask[i] &= sta->deflink.ht_cap.mcs.rx_mask[i];
sta_vht_cap = sta->deflink.vht_cap.vht_mcs.rx_mcs_map;
ieee80211_get_vht_mask_from_cap(sta_vht_cap, sta_vht_mask); for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
vht_mask[i] &= sta_vht_mask[i];
}
/* * Try to enforce the rateidx mask the user wanted. skip this if the * default mask (allow all rates) is used to save some processing for * the common case.
*/ if (!rate_control_cap_mask(sdata, sband, sta, &mask, mcs_mask,
vht_mask)) return;
/* * Make sure the rate index selected for each TX rate is * included in the configured mask and change the rate indexes * if needed.
*/
chan_width = sdata->vif.bss_conf.chanreq.oper.width; for (i = 0; i < max_rates; i++) { /* Skip invalid rates */ if (rates[i].idx < 0) break;
sband = ieee80211_get_sband(sta->sdata); if (!sband) return -EINVAL;
rate_control_apply_mask_ratetbl(sta, sband, rates); /* * mac80211 guarantees that this function will not be called * concurrently, so the following RCU access is safe, even without * extra locking. This can not be checked easily, so we just set * the condition to true.
*/
old = rcu_dereference_protected(pubsta->rates, true);
rcu_assign_pointer(pubsta->rates, rates); if (old)
kfree_rcu(old, rcu_head);
if (sta->uploaded)
drv_sta_rate_tbl_update(hw_to_local(hw), sta->sdata, pubsta);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.