Skip to content

Commit

Permalink
mac80211: select and adjust bitrates according to channel mode
Browse files Browse the repository at this point in the history
The various components accessing the bitrates table must use consider
the used channel bandwidth to select only available rates or calculate
the bitrate correctly.

There are some rates in reduced bandwidth modes which can't be
represented as multiples of 500kbps, like 2.25 MBit/s in 5 MHz mode. The
standard suggests to round up to the next multiple of 500kbps, just do
that in mac80211 as well.

Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de>
[make rate unsigned in ieee80211_add_tx_radiotap_header(), squash fix]
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
  • Loading branch information
Simon Wunderlich authored and Johannes Berg committed Jul 16, 2013
1 parent a5e7069 commit 2103dec
Show file tree
Hide file tree
Showing 12 changed files with 352 additions and 159 deletions.
45 changes: 18 additions & 27 deletions net/mac80211/cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -395,9 +395,13 @@ void sta_set_rate_info_tx(struct sta_info *sta,
rinfo->nss = ieee80211_rate_get_vht_nss(rate);
} else {
struct ieee80211_supported_band *sband;
int shift = ieee80211_vif_get_shift(&sta->sdata->vif);
u16 brate;

sband = sta->local->hw.wiphy->bands[
ieee80211_get_sdata_band(sta->sdata)];
rinfo->legacy = sband->bitrates[rate->idx].bitrate;
brate = sband->bitrates[rate->idx].bitrate;
rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift);
}
if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
rinfo->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
Expand All @@ -422,11 +426,13 @@ void sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo)
rinfo->mcs = sta->last_rx_rate_idx;
} else {
struct ieee80211_supported_band *sband;
int shift = ieee80211_vif_get_shift(&sta->sdata->vif);
u16 brate;

sband = sta->local->hw.wiphy->bands[
ieee80211_get_sdata_band(sta->sdata)];
rinfo->legacy =
sband->bitrates[sta->last_rx_rate_idx].bitrate;
brate = sband->bitrates[sta->last_rx_rate_idx].bitrate;
rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift);
}

if (sta->last_rx_rate_flag & RX_FLAG_40MHZ)
Expand Down Expand Up @@ -1190,8 +1196,6 @@ static int sta_apply_parameters(struct ieee80211_local *local,
struct station_parameters *params)
{
int ret = 0;
u32 rates;
int i, j;
struct ieee80211_supported_band *sband;
struct ieee80211_sub_if_data *sdata = sta->sdata;
enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
Expand Down Expand Up @@ -1284,16 +1288,10 @@ static int sta_apply_parameters(struct ieee80211_local *local,
sta->listen_interval = params->listen_interval;

if (params->supported_rates) {
rates = 0;

for (i = 0; i < params->supported_rates_len; i++) {
int rate = (params->supported_rates[i] & 0x7f) * 5;
for (j = 0; j < sband->n_bitrates; j++) {
if (sband->bitrates[j].bitrate == rate)
rates |= BIT(j);
}
}
sta->sta.supp_rates[band] = rates;
ieee80211_parse_bitrates(&sdata->vif.bss_conf.chandef,
sband, params->supported_rates,
params->supported_rates_len,
&sta->sta.supp_rates[band]);
}

if (params->ht_capa)
Expand Down Expand Up @@ -1956,18 +1954,11 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
}

if (params->basic_rates) {
int i, j;
u32 rates = 0;
struct ieee80211_supported_band *sband = wiphy->bands[band];

for (i = 0; i < params->basic_rates_len; i++) {
int rate = (params->basic_rates[i] & 0x7f) * 5;
for (j = 0; j < sband->n_bitrates; j++) {
if (sband->bitrates[j].bitrate == rate)
rates |= BIT(j);
}
}
sdata->vif.bss_conf.basic_rates = rates;
ieee80211_parse_bitrates(&sdata->vif.bss_conf.chandef,
wiphy->bands[band],
params->basic_rates,
params->basic_rates_len,
&sdata->vif.bss_conf.basic_rates);
changed |= BSS_CHANGED_BASIC_RATES;
}

Expand Down
81 changes: 62 additions & 19 deletions net/mac80211/ibss.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,17 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
struct ieee80211_local *local = sdata->local;
int rates, i;
int rates_n = 0, i, ri;
struct ieee80211_mgmt *mgmt;
u8 *pos;
struct ieee80211_supported_band *sband;
struct cfg80211_bss *bss;
u32 bss_change;
u32 bss_change, rate_flags, rates = 0, rates_added = 0;
u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
struct cfg80211_chan_def chandef;
struct beacon_data *presp;
int frame_len;
int shift;

sdata_assert_lock(sdata);

Expand Down Expand Up @@ -99,6 +100,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
memcpy(ifibss->bssid, bssid, ETH_ALEN);

sband = local->hw.wiphy->bands[chan->band];
shift = ieee80211_vif_get_shift(&sdata->vif);

/* Build IBSS probe response */
frame_len = sizeof(struct ieee80211_hdr_3addr) +
Expand Down Expand Up @@ -134,15 +136,29 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
memcpy(pos, ifibss->ssid, ifibss->ssid_len);
pos += ifibss->ssid_len;

rates = min_t(int, 8, sband->n_bitrates);
rate_flags = ieee80211_chandef_rate_flags(&chandef);
for (i = 0; i < sband->n_bitrates; i++) {
if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
continue;

rates |= BIT(i);
rates_n++;
}

*pos++ = WLAN_EID_SUPP_RATES;
*pos++ = rates;
for (i = 0; i < rates; i++) {
int rate = sband->bitrates[i].bitrate;
*pos++ = min_t(int, 8, rates_n);
for (ri = 0; ri < sband->n_bitrates; ri++) {
int rate = DIV_ROUND_UP(sband->bitrates[ri].bitrate,
5 * (1 << shift));
u8 basic = 0;
if (basic_rates & BIT(i))
if (!(rates & BIT(ri)))
continue;

if (basic_rates & BIT(ri))
basic = 0x80;
*pos++ = basic | (u8) (rate / 5);
*pos++ = basic | (u8) rate;
if (++rates_added == 8)
break;
}

if (sband->band == IEEE80211_BAND_2GHZ) {
Expand All @@ -157,15 +173,20 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
*pos++ = 0;
*pos++ = 0;

if (sband->n_bitrates > 8) {
/* put the remaining rates in WLAN_EID_EXT_SUPP_RATES */
if (rates_n > 8) {
*pos++ = WLAN_EID_EXT_SUPP_RATES;
*pos++ = sband->n_bitrates - 8;
for (i = 8; i < sband->n_bitrates; i++) {
int rate = sband->bitrates[i].bitrate;
*pos++ = rates_n - 8;
for (; ri < sband->n_bitrates; ri++) {
int rate = DIV_ROUND_UP(sband->bitrates[ri].bitrate,
5 * (1 << shift));
u8 basic = 0;
if (basic_rates & BIT(i))
if (!(rates & BIT(ri)))
continue;

if (basic_rates & BIT(ri))
basic = 0x80;
*pos++ = basic | (u8) (rate / 5);
*pos++ = basic | (u8) rate;
}
}

Expand Down Expand Up @@ -244,7 +265,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
sdata->vif.bss_conf.ibss_creator = creator;
ieee80211_bss_info_change_notify(sdata, bss_change);

ieee80211_sta_def_wmm_params(sdata, sband->n_bitrates, supp_rates);
ieee80211_sta_def_wmm_params(sdata, rates, supp_rates);

ifibss->state = IEEE80211_IBSS_MLME_JOINED;
mod_timer(&ifibss->timer,
Expand All @@ -268,22 +289,33 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
u16 beacon_int = cbss->beacon_interval;
const struct cfg80211_bss_ies *ies;
u64 tsf;
u32 rate_flags;
int shift;

sdata_assert_lock(sdata);

if (beacon_int < 10)
beacon_int = 10;

sband = sdata->local->hw.wiphy->bands[cbss->channel->band];
rate_flags = ieee80211_chandef_rate_flags(&sdata->u.ibss.chandef);
shift = ieee80211_vif_get_shift(&sdata->vif);

basic_rates = 0;

for (i = 0; i < bss->supp_rates_len; i++) {
int rate = (bss->supp_rates[i] & 0x7f) * 5;
int rate = bss->supp_rates[i] & 0x7f;
bool is_basic = !!(bss->supp_rates[i] & 0x80);

for (j = 0; j < sband->n_bitrates; j++) {
if (sband->bitrates[j].bitrate == rate) {
int brate;
if ((rate_flags & sband->bitrates[j].flags)
!= rate_flags)
continue;

brate = DIV_ROUND_UP(sband->bitrates[j].bitrate,
5 * (1 << shift));
if (brate == rate) {
if (is_basic)
basic_rates |= BIT(j);
break;
Expand Down Expand Up @@ -465,7 +497,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
sta = sta_info_get(sdata, mgmt->sa);

if (elems->supp_rates) {
supp_rates = ieee80211_sta_get_rates(local, elems,
supp_rates = ieee80211_sta_get_rates(sdata, elems,
band, NULL);
if (sta) {
u32 prev_rates;
Expand Down Expand Up @@ -589,7 +621,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
"beacon TSF higher than local TSF - IBSS merge with BSSID %pM\n",
mgmt->bssid);
ieee80211_sta_join_ibss(sdata, bss);
supp_rates = ieee80211_sta_get_rates(local, elems, band, NULL);
supp_rates = ieee80211_sta_get_rates(sdata, elems, band, NULL);
ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa,
supp_rates);
rcu_read_unlock();
Expand Down Expand Up @@ -1024,6 +1056,9 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
struct cfg80211_ibss_params *params)
{
u32 changed = 0;
u32 rate_flags;
struct ieee80211_supported_band *sband;
int i;

if (params->bssid) {
memcpy(sdata->u.ibss.bssid, params->bssid, ETH_ALEN);
Expand All @@ -1034,6 +1069,14 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
sdata->u.ibss.privacy = params->privacy;
sdata->u.ibss.control_port = params->control_port;
sdata->u.ibss.basic_rates = params->basic_rates;

/* fix basic_rates if channel does not support these rates */
rate_flags = ieee80211_chandef_rate_flags(&params->chandef);
sband = sdata->local->hw.wiphy->bands[params->chandef.chan->band];
for (i = 0; i < sband->n_bitrates; i++) {
if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
sdata->u.ibss.basic_rates &= ~BIT(i);
}
memcpy(sdata->vif.bss_conf.mcast_rate, params->mcast_rate,
sizeof(params->mcast_rate));

Expand Down
7 changes: 5 additions & 2 deletions net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -1601,7 +1601,7 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
size_t buffer_len, const u8 *ie, size_t ie_len,
enum ieee80211_band band, u32 rate_mask,
u8 channel);
struct cfg80211_chan_def *chandef);
struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
u8 *dst, u32 ratemask,
struct ieee80211_channel *chan,
Expand All @@ -1617,7 +1617,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
const size_t supp_rates_len,
const u8 *supp_rates);
u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
u32 ieee80211_sta_get_rates(struct ieee80211_sub_if_data *sdata,
struct ieee802_11_elems *elems,
enum ieee80211_band band, u32 *basic_rates);
int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
Expand All @@ -1634,6 +1634,9 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
u16 prot_mode);
u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
u32 cap);
int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef,
const struct ieee80211_supported_band *sband,
const u8 *srates, int srates_len, u32 *rates);
int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, bool need_basic,
enum ieee80211_band band);
Expand Down
3 changes: 1 addition & 2 deletions net/mac80211/mesh.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
struct ieee802_11_elems *ie)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct ieee80211_local *local = sdata->local;
u32 basic_rates = 0;
struct cfg80211_chan_def sta_chan_def;

Expand All @@ -85,7 +84,7 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
(ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth)))
return false;

ieee80211_sta_get_rates(local, ie, ieee80211_get_sdata_band(sdata),
ieee80211_sta_get_rates(sdata, ie, ieee80211_get_sdata_band(sdata),
&basic_rates);

if (sdata->vif.bss_conf.basic_rates != basic_rates)
Expand Down
2 changes: 1 addition & 1 deletion net/mac80211/mesh_plink.c
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
u32 rates, basic_rates = 0, changed = 0;

sband = local->hw.wiphy->bands[band];
rates = ieee80211_sta_get_rates(local, elems, band, &basic_rates);
rates = ieee80211_sta_get_rates(sdata, elems, band, &basic_rates);

spin_lock_bh(&sta->lock);
sta->last_rx = jiffies;
Expand Down
Loading

0 comments on commit 2103dec

Please sign in to comment.