Commit 2103dec1 authored by Simon Wunderlich's avatar Simon Wunderlich Committed by Johannes Berg

mac80211: select and adjust bitrates according to channel mode

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: default avatarSimon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: default avatarMathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de>
[make rate unsigned in ieee80211_add_tx_radiotap_header(), squash fix]
Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
parent a5e70697
...@@ -395,9 +395,13 @@ void sta_set_rate_info_tx(struct sta_info *sta, ...@@ -395,9 +395,13 @@ void sta_set_rate_info_tx(struct sta_info *sta,
rinfo->nss = ieee80211_rate_get_vht_nss(rate); rinfo->nss = ieee80211_rate_get_vht_nss(rate);
} else { } else {
struct ieee80211_supported_band *sband; struct ieee80211_supported_band *sband;
int shift = ieee80211_vif_get_shift(&sta->sdata->vif);
u16 brate;
sband = sta->local->hw.wiphy->bands[ sband = sta->local->hw.wiphy->bands[
ieee80211_get_sdata_band(sta->sdata)]; 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) if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
rinfo->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; rinfo->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
...@@ -422,11 +426,13 @@ void sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo) ...@@ -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; rinfo->mcs = sta->last_rx_rate_idx;
} else { } else {
struct ieee80211_supported_band *sband; struct ieee80211_supported_band *sband;
int shift = ieee80211_vif_get_shift(&sta->sdata->vif);
u16 brate;
sband = sta->local->hw.wiphy->bands[ sband = sta->local->hw.wiphy->bands[
ieee80211_get_sdata_band(sta->sdata)]; ieee80211_get_sdata_band(sta->sdata)];
rinfo->legacy = brate = sband->bitrates[sta->last_rx_rate_idx].bitrate;
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) if (sta->last_rx_rate_flag & RX_FLAG_40MHZ)
...@@ -1190,8 +1196,6 @@ static int sta_apply_parameters(struct ieee80211_local *local, ...@@ -1190,8 +1196,6 @@ static int sta_apply_parameters(struct ieee80211_local *local,
struct station_parameters *params) struct station_parameters *params)
{ {
int ret = 0; int ret = 0;
u32 rates;
int i, j;
struct ieee80211_supported_band *sband; struct ieee80211_supported_band *sband;
struct ieee80211_sub_if_data *sdata = sta->sdata; struct ieee80211_sub_if_data *sdata = sta->sdata;
enum ieee80211_band band = ieee80211_get_sdata_band(sdata); enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
...@@ -1284,16 +1288,10 @@ static int sta_apply_parameters(struct ieee80211_local *local, ...@@ -1284,16 +1288,10 @@ static int sta_apply_parameters(struct ieee80211_local *local,
sta->listen_interval = params->listen_interval; sta->listen_interval = params->listen_interval;
if (params->supported_rates) { if (params->supported_rates) {
rates = 0; ieee80211_parse_bitrates(&sdata->vif.bss_conf.chandef,
sband, params->supported_rates,
for (i = 0; i < params->supported_rates_len; i++) { params->supported_rates_len,
int rate = (params->supported_rates[i] & 0x7f) * 5; &sta->sta.supp_rates[band]);
for (j = 0; j < sband->n_bitrates; j++) {
if (sband->bitrates[j].bitrate == rate)
rates |= BIT(j);
}
}
sta->sta.supp_rates[band] = rates;
} }
if (params->ht_capa) if (params->ht_capa)
...@@ -1956,18 +1954,11 @@ static int ieee80211_change_bss(struct wiphy *wiphy, ...@@ -1956,18 +1954,11 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
} }
if (params->basic_rates) { if (params->basic_rates) {
int i, j; ieee80211_parse_bitrates(&sdata->vif.bss_conf.chandef,
u32 rates = 0; wiphy->bands[band],
struct ieee80211_supported_band *sband = wiphy->bands[band]; params->basic_rates,
params->basic_rates_len,
for (i = 0; i < params->basic_rates_len; i++) { &sdata->vif.bss_conf.basic_rates);
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;
changed |= BSS_CHANGED_BASIC_RATES; changed |= BSS_CHANGED_BASIC_RATES;
} }
......
...@@ -43,16 +43,17 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, ...@@ -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_if_ibss *ifibss = &sdata->u.ibss;
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
int rates, i; int rates_n = 0, i, ri;
struct ieee80211_mgmt *mgmt; struct ieee80211_mgmt *mgmt;
u8 *pos; u8 *pos;
struct ieee80211_supported_band *sband; struct ieee80211_supported_band *sband;
struct cfg80211_bss *bss; struct cfg80211_bss *bss;
u32 bss_change; u32 bss_change, rate_flags, rates = 0, rates_added = 0;
u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
struct cfg80211_chan_def chandef; struct cfg80211_chan_def chandef;
struct beacon_data *presp; struct beacon_data *presp;
int frame_len; int frame_len;
int shift;
sdata_assert_lock(sdata); sdata_assert_lock(sdata);
...@@ -99,6 +100,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, ...@@ -99,6 +100,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
memcpy(ifibss->bssid, bssid, ETH_ALEN); memcpy(ifibss->bssid, bssid, ETH_ALEN);
sband = local->hw.wiphy->bands[chan->band]; sband = local->hw.wiphy->bands[chan->band];
shift = ieee80211_vif_get_shift(&sdata->vif);
/* Build IBSS probe response */ /* Build IBSS probe response */
frame_len = sizeof(struct ieee80211_hdr_3addr) + frame_len = sizeof(struct ieee80211_hdr_3addr) +
...@@ -134,15 +136,29 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, ...@@ -134,15 +136,29 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
memcpy(pos, ifibss->ssid, ifibss->ssid_len); memcpy(pos, ifibss->ssid, ifibss->ssid_len);
pos += 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++ = WLAN_EID_SUPP_RATES;
*pos++ = rates; *pos++ = min_t(int, 8, rates_n);
for (i = 0; i < rates; i++) { for (ri = 0; ri < sband->n_bitrates; ri++) {
int rate = sband->bitrates[i].bitrate; int rate = DIV_ROUND_UP(sband->bitrates[ri].bitrate,
5 * (1 << shift));
u8 basic = 0; u8 basic = 0;
if (basic_rates & BIT(i)) if (!(rates & BIT(ri)))
continue;
if (basic_rates & BIT(ri))
basic = 0x80; basic = 0x80;
*pos++ = basic | (u8) (rate / 5); *pos++ = basic | (u8) rate;
if (++rates_added == 8)
break;
} }
if (sband->band == IEEE80211_BAND_2GHZ) { if (sband->band == IEEE80211_BAND_2GHZ) {
...@@ -157,15 +173,20 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, ...@@ -157,15 +173,20 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
*pos++ = 0; *pos++ = 0;
*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++ = WLAN_EID_EXT_SUPP_RATES;
*pos++ = sband->n_bitrates - 8; *pos++ = rates_n - 8;
for (i = 8; i < sband->n_bitrates; i++) { for (; ri < sband->n_bitrates; ri++) {
int rate = sband->bitrates[i].bitrate; int rate = DIV_ROUND_UP(sband->bitrates[ri].bitrate,
5 * (1 << shift));
u8 basic = 0; u8 basic = 0;
if (basic_rates & BIT(i)) if (!(rates & BIT(ri)))
continue;
if (basic_rates & BIT(ri))
basic = 0x80; basic = 0x80;
*pos++ = basic | (u8) (rate / 5); *pos++ = basic | (u8) rate;
} }
} }
...@@ -244,7 +265,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, ...@@ -244,7 +265,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
sdata->vif.bss_conf.ibss_creator = creator; sdata->vif.bss_conf.ibss_creator = creator;
ieee80211_bss_info_change_notify(sdata, bss_change); 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; ifibss->state = IEEE80211_IBSS_MLME_JOINED;
mod_timer(&ifibss->timer, mod_timer(&ifibss->timer,
...@@ -268,6 +289,8 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, ...@@ -268,6 +289,8 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
u16 beacon_int = cbss->beacon_interval; u16 beacon_int = cbss->beacon_interval;
const struct cfg80211_bss_ies *ies; const struct cfg80211_bss_ies *ies;
u64 tsf; u64 tsf;
u32 rate_flags;
int shift;
sdata_assert_lock(sdata); sdata_assert_lock(sdata);
...@@ -275,15 +298,24 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, ...@@ -275,15 +298,24 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
beacon_int = 10; beacon_int = 10;
sband = sdata->local->hw.wiphy->bands[cbss->channel->band]; 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; basic_rates = 0;
for (i = 0; i < bss->supp_rates_len; i++) { 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); bool is_basic = !!(bss->supp_rates[i] & 0x80);
for (j = 0; j < sband->n_bitrates; j++) { 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) if (is_basic)
basic_rates |= BIT(j); basic_rates |= BIT(j);
break; break;
...@@ -465,7 +497,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, ...@@ -465,7 +497,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
sta = sta_info_get(sdata, mgmt->sa); sta = sta_info_get(sdata, mgmt->sa);
if (elems->supp_rates) { if (elems->supp_rates) {
supp_rates = ieee80211_sta_get_rates(local, elems, supp_rates = ieee80211_sta_get_rates(sdata, elems,
band, NULL); band, NULL);
if (sta) { if (sta) {
u32 prev_rates; u32 prev_rates;
...@@ -589,7 +621,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, ...@@ -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", "beacon TSF higher than local TSF - IBSS merge with BSSID %pM\n",
mgmt->bssid); mgmt->bssid);
ieee80211_sta_join_ibss(sdata, bss); 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, ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa,
supp_rates); supp_rates);
rcu_read_unlock(); rcu_read_unlock();
...@@ -1024,6 +1056,9 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, ...@@ -1024,6 +1056,9 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
struct cfg80211_ibss_params *params) struct cfg80211_ibss_params *params)
{ {
u32 changed = 0; u32 changed = 0;
u32 rate_flags;
struct ieee80211_supported_band *sband;
int i;
if (params->bssid) { if (params->bssid) {
memcpy(sdata->u.ibss.bssid, params->bssid, ETH_ALEN); memcpy(sdata->u.ibss.bssid, params->bssid, ETH_ALEN);
...@@ -1034,6 +1069,14 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, ...@@ -1034,6 +1069,14 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
sdata->u.ibss.privacy = params->privacy; sdata->u.ibss.privacy = params->privacy;
sdata->u.ibss.control_port = params->control_port; sdata->u.ibss.control_port = params->control_port;
sdata->u.ibss.basic_rates = params->basic_rates; 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, memcpy(sdata->vif.bss_conf.mcast_rate, params->mcast_rate,
sizeof(params->mcast_rate)); sizeof(params->mcast_rate));
......
...@@ -1601,7 +1601,7 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, ...@@ -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, int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
size_t buffer_len, const u8 *ie, size_t ie_len, size_t buffer_len, const u8 *ie, size_t ie_len,
enum ieee80211_band band, u32 rate_mask, 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, struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
u8 *dst, u32 ratemask, u8 *dst, u32 ratemask,
struct ieee80211_channel *chan, struct ieee80211_channel *chan,
...@@ -1617,7 +1617,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, ...@@ -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, void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
const size_t supp_rates_len, const size_t supp_rates_len,
const u8 *supp_rates); 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, struct ieee802_11_elems *elems,
enum ieee80211_band band, u32 *basic_rates); enum ieee80211_band band, u32 *basic_rates);
int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
...@@ -1634,6 +1634,9 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, ...@@ -1634,6 +1634,9 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
u16 prot_mode); u16 prot_mode);
u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
u32 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, int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, bool need_basic, struct sk_buff *skb, bool need_basic,
enum ieee80211_band band); enum ieee80211_band band);
......
...@@ -62,7 +62,6 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, ...@@ -62,7 +62,6 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
struct ieee802_11_elems *ie) struct ieee802_11_elems *ie)
{ {
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct ieee80211_local *local = sdata->local;
u32 basic_rates = 0; u32 basic_rates = 0;
struct cfg80211_chan_def sta_chan_def; struct cfg80211_chan_def sta_chan_def;
...@@ -85,7 +84,7 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, ...@@ -85,7 +84,7 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
(ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth))) (ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth)))
return false; 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); &basic_rates);
if (sdata->vif.bss_conf.basic_rates != basic_rates) if (sdata->vif.bss_conf.basic_rates != basic_rates)
......
...@@ -379,7 +379,7 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata, ...@@ -379,7 +379,7 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
u32 rates, basic_rates = 0, changed = 0; u32 rates, basic_rates = 0, changed = 0;
sband = local->hw.wiphy->bands[band]; 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); spin_lock_bh(&sta->lock);
sta->last_rx = jiffies; sta->last_rx = jiffies;
......
...@@ -478,27 +478,6 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata, ...@@ -478,27 +478,6 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
/* frame sending functions */ /* frame sending functions */
static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len,
struct ieee80211_supported_band *sband,
u32 *rates)
{
int i, j, count;
*rates = 0;
count = 0;
for (i = 0; i < supp_rates_len; i++) {
int rate = (supp_rates[i] & 0x7F) * 5;
for (j = 0; j < sband->n_bitrates; j++)
if (sband->bitrates[j].bitrate == rate) {
*rates |= BIT(j);
count++;
break;
}
}
return count;
}
static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata, static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, u8 ap_ht_param, struct sk_buff *skb, u8 ap_ht_param,
struct ieee80211_supported_band *sband, struct ieee80211_supported_band *sband,
...@@ -617,12 +596,12 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) ...@@ -617,12 +596,12 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
struct ieee80211_mgmt *mgmt; struct ieee80211_mgmt *mgmt;
u8 *pos, qos_info; u8 *pos, qos_info;
size_t offset = 0, noffset; size_t offset = 0, noffset;
int i, count, rates_len, supp_rates_len; int i, count, rates_len, supp_rates_len, shift;
u16 capab; u16 capab;
struct ieee80211_supported_band *sband; struct ieee80211_supported_band *sband;
struct ieee80211_chanctx_conf *chanctx_conf; struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_channel *chan; struct ieee80211_channel *chan;
u32 rates = 0; u32 rate_flags, rates = 0;
sdata_assert_lock(sdata); sdata_assert_lock(sdata);
...@@ -633,8 +612,10 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) ...@@ -633,8 +612,10 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
return; return;
} }
chan = chanctx_conf->def.chan; chan = chanctx_conf->def.chan;
rate_flags = ieee80211_chandef_rate_flags(&chanctx_conf->def);
rcu_read_unlock(); rcu_read_unlock();
sband = local->hw.wiphy->bands[chan->band]; sband = local->hw.wiphy->bands[chan->band];
shift = ieee80211_vif_get_shift(&sdata->vif);
if (assoc_data->supp_rates_len) { if (assoc_data->supp_rates_len) {
/* /*
...@@ -643,17 +624,24 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) ...@@ -643,17 +624,24 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
* in the association request (e.g. D-Link DAP 1353 in * in the association request (e.g. D-Link DAP 1353 in
* b-only mode)... * b-only mode)...
*/ */
rates_len = ieee80211_compatible_rates(assoc_data->supp_rates, rates_len = ieee80211_parse_bitrates(&chanctx_conf->def, sband,
assoc_data->supp_rates_len, assoc_data->supp_rates,
sband, &rates); assoc_data->supp_rates_len,
&rates);
} else { } else {
/* /*
* In case AP not provide any supported rates information * In case AP not provide any supported rates information
* before association, we send information element(s) with * before association, we send information element(s) with
* all rates that we support. * all rates that we support.
*/ */
rates = ~0; rates_len = 0;
rates_len = sband->n_bitrates; for (i = 0; i < sband->n_bitrates; i++) {
if ((rate_flags & sband->bitrates[i].flags)
!= rate_flags)
continue;
rates |= BIT(i);
rates_len++;
}
} }
skb = alloc_skb(local->hw.extra_tx_headroom + skb = alloc_skb(local->hw.extra_tx_headroom +
...@@ -730,8 +718,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) ...@@ -730,8 +718,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
count = 0; count = 0;
for (i = 0; i < sband->n_bitrates; i++) { for (i = 0; i < sband->n_bitrates; i++) {
if (BIT(i) & rates) { if (BIT(i) & rates) {
int rate = sband->bitrates[i].bitrate; int rate = DIV_ROUND_UP(sband->bitrates[i].bitrate,
*pos++ = (u8) (rate / 5); 5 * (1 << shift));
*pos++ = (u8) rate;
if (++count == 8) if (++count == 8)
break; break;
} }
...@@ -744,8 +733,10 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) ...@@ -744,8 +733,10 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
for (i++; i < sband->n_bitrates; i++) { for (i++; i < sband->n_bitrates; i++) {
if (BIT(i) & rates) { if (BIT(i) & rates) {
int rate = sband->bitrates[i].bitrate; int rate;
*pos++ = (u8) (rate / 5); rate = DIV_ROUND_UP(sband->bitrates[i].bitrate,
5 * (1 << shift));
*pos++ = (u8) rate;
} }
} }
} }
...@@ -2432,15 +2423,16 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband, ...@@ -2432,15 +2423,16 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
u8 *supp_rates, unsigned int supp_rates_len, u8 *supp_rates, unsigned int supp_rates_len,
u32 *rates, u32 *basic_rates, u32 *rates, u32 *basic_rates,
bool *have_higher_than_11mbit, bool *have_higher_than_11mbit,
int *min_rate, int *min_rate_index) int *min_rate, int *min_rate_index,
int shift, u32 rate_flags)
{ {
int i, j; int i, j;
for (i = 0; i < supp_rates_len; i++) { for (i = 0; i < supp_rates_len; i++) {
int rate = (supp_rates[i] & 0x7f) * 5; int rate = supp_rates[i] & 0x7f;
bool is_basic = !!(supp_rates[i] & 0x80); bool is_basic = !!(supp_rates[i] & 0x80);
if (rate > 110) if ((rate * 5 * (1 << shift)) > 110)
*have_higher_than_11mbit = true; *have_higher_than_11mbit = true;
/* /*
...@@ -2456,12 +2448,20 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband, ...@@ -2456,12 +2448,20 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
continue; continue;
for (j = 0; j < sband->n_bitrates; j++) { for (j = 0; j < sband->n_bitrates; j++) {
if (sband->bitrates[j].bitrate == rate) { struct ieee80211_rate *br;
int brate;
br = &sband->bitrates[j];
if ((rate_flags & br->flags) != rate_flags)
continue;
brate = DIV_ROUND_UP(br->bitrate, (1 << shift) * 5);
if (brate == rate) {
*rates |= BIT(j); *rates |= BIT(j);
if (is_basic) if (is_basic)
*basic_rates |= BIT