Search Linux Wireless

[PATCHv2 06/18] mac80211: choose bitrate table according to bandwidth

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



For situations where a reduced bandwidth (5 MHz, 10 MHz) is used, the
bitrates used internally (for building/interpreting IEs, rate control,
etc) must change accordingly. Therefore add bitrates_half and
bitrates_quarter bitrate table according to the currently selected
mode. Only drivers which support these modes have to fill these
tables.

This patch touches a lot of components, but is usually only selecting
the right bitrate table, returning an error if this is not possible or
falls back to the standard bitrate table.

Signed-off-by: Simon Wunderlich <siwu@xxxxxxxxxxxxxxxxxx>
Signed-off-by: Mathias Kretschmer <mathias.kretschmer@xxxxxxxxxxxxxxxxxxx>
---
 include/net/mac80211.h             |   36 +++++++++++--
 net/mac80211/cfg.c                 |   50 +++++++++++++++---
 net/mac80211/ibss.c                |   28 ++++++++---
 net/mac80211/ieee80211_i.h         |    2 +
 net/mac80211/iface.c               |    5 ++
 net/mac80211/main.c                |    5 +-
 net/mac80211/mesh_plink.c          |   10 +++-
 net/mac80211/mlme.c                |   55 ++++++++++++++------
 net/mac80211/rate.c                |   94 +++++++++++++++++++++++-----------
 net/mac80211/rc80211_minstrel.c    |   47 +++++++++++------
 net/mac80211/rc80211_minstrel_ht.c |   18 +++++--
 net/mac80211/rc80211_pid.h         |    2 +
 net/mac80211/rc80211_pid_algo.c    |   68 +++++++++++++++++++------
 net/mac80211/rx.c                  |   29 +++++++++--
 net/mac80211/status.c              |   15 ++++--
 net/mac80211/tx.c                  |   33 +++++++++---
 net/mac80211/util.c                |   98 +++++++++++++++++++++++++++++-------
 17 files changed, 464 insertions(+), 131 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 04c2d46..3e52e22 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1648,27 +1648,54 @@ static inline struct ieee80211_rate *
 ieee80211_get_tx_rate(const struct ieee80211_hw *hw,
 		      const struct ieee80211_tx_info *c)
 {
+	struct ieee80211_rate *bitrates;
+	int n_bitrates;
+
 	if (WARN_ON_ONCE(c->control.rates[0].idx < 0))
 		return NULL;
-	return &hw->wiphy->bands[c->band]->bitrates[c->control.rates[0].idx];
+
+	if (WARN_ON(ieee80211_get_bitrates(hw->wiphy->bands[c->band],
+					   hw->conf.chandef.width,
+					   &bitrates, &n_bitrates)))
+		return NULL;
+
+	return &bitrates[c->control.rates[0].idx];
 }
 
 static inline struct ieee80211_rate *
 ieee80211_get_rts_cts_rate(const struct ieee80211_hw *hw,
 			   const struct ieee80211_tx_info *c)
 {
+	struct ieee80211_rate *bitrates;
+	int n_bitrates;
+
 	if (c->control.rts_cts_rate_idx < 0)
 		return NULL;
-	return &hw->wiphy->bands[c->band]->bitrates[c->control.rts_cts_rate_idx];
+
+	if (WARN_ON(ieee80211_get_bitrates(hw->wiphy->bands[c->band],
+					   hw->conf.chandef.width,
+					   &bitrates, &n_bitrates)))
+		return NULL;
+
+	return &bitrates[c->control.rts_cts_rate_idx];
 }
 
 static inline struct ieee80211_rate *
 ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
 			     const struct ieee80211_tx_info *c, int idx)
 {
+	struct ieee80211_rate *bitrates;
+	int n_bitrates;
+
 	if (c->control.rates[idx + 1].idx < 0)
 		return NULL;
-	return &hw->wiphy->bands[c->band]->bitrates[c->control.rates[idx + 1].idx];
+
+	if (WARN_ON(ieee80211_get_bitrates(hw->wiphy->bands[c->band],
+					   hw->conf.chandef.width,
+					   &bitrates, &n_bitrates)))
+		return NULL;
+
+	return &bitrates[c->control.rates[idx + 1].idx];
 }
 
 /**
@@ -4235,11 +4262,12 @@ bool rate_control_send_low(struct ieee80211_sta *sta,
 
 static inline s8
 rate_lowest_index(struct ieee80211_supported_band *sband,
+		  int n_bitrates,
 		  struct ieee80211_sta *sta)
 {
 	int i;
 
-	for (i = 0; i < sband->n_bitrates; i++)
+	for (i = 0; i < n_bitrates; i++)
 		if (rate_supported(sta, sband->band, i))
 			return i;
 
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 1a89c80..4657f1b 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -392,9 +392,19 @@ void sta_set_rate_info_tx(struct sta_info *sta,
 		rinfo->nss = ieee80211_rate_get_vht_nss(rate);
 	} else {
 		struct ieee80211_supported_band *sband;
+		struct ieee80211_hw *hw;
+		struct ieee80211_rate *bitrates;
+		int n_bitrates;
+
 		sband = sta->local->hw.wiphy->bands[
 				ieee80211_get_sdata_band(sta->sdata)];
-		rinfo->legacy = sband->bitrates[rate->idx].bitrate;
+		hw = &sta->sdata->local->hw;
+		if (ieee80211_get_bitrates(sband, hw->conf.chandef.width,
+					   &bitrates, &n_bitrates)) {
+			bitrates = sband->bitrates;
+			n_bitrates = sband->n_bitrates;
+		}
+		rinfo->legacy = bitrates[rate->idx].bitrate;
 	}
 	if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
 		rinfo->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
@@ -419,11 +429,21 @@ 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;
+		struct ieee80211_rate *bitrates;
+		struct ieee80211_hw *hw;
+		int n_bitrates;
 
 		sband = sta->local->hw.wiphy->bands[
 				ieee80211_get_sdata_band(sta->sdata)];
+		hw = &sta->sdata->local->hw;
+		if (ieee80211_get_bitrates(sband, hw->conf.chandef.width,
+					   &bitrates, &n_bitrates)) {
+			bitrates = sband->bitrates;
+			n_bitrates = sband->n_bitrates;
+		}
+
 		rinfo->legacy =
-			sband->bitrates[sta->last_rx_rate_idx].bitrate;
+			bitrates[sta->last_rx_rate_idx].bitrate;
 	}
 
 	if (sta->last_rx_rate_flag & RX_FLAG_40MHZ)
@@ -1264,12 +1284,20 @@ static int sta_apply_parameters(struct ieee80211_local *local,
 		sta->listen_interval = params->listen_interval;
 
 	if (params->supported_rates) {
+		struct ieee80211_rate *bitrates;
+		int n_bitrates;
 		rates = 0;
 
+		if (ieee80211_get_bitrates(sband, local->hw.conf.chandef.width,
+					   &bitrates, &n_bitrates)) {
+			bitrates = sband->bitrates;
+			n_bitrates = sband->n_bitrates;
+		}
+
 		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)
+			for (j = 0; j < n_bitrates; j++) {
+				if (bitrates[j].bitrate == rate)
 					rates |= BIT(j);
 			}
 		}
@@ -1935,11 +1963,21 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
 		int i, j;
 		u32 rates = 0;
 		struct ieee80211_supported_band *sband = wiphy->bands[band];
+		struct ieee80211_hw *hw;
+		struct ieee80211_rate *bitrates;
+		int n_bitrates;
+
+		hw = &sdata->local->hw;
+		if (ieee80211_get_bitrates(sband, hw->conf.chandef.width,
+					   &bitrates, &n_bitrates)) {
+			bitrates = sband->bitrates;
+			n_bitrates = sband->n_bitrates;
+		}
 
 		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)
+			for (j = 0; j < n_bitrates; j++) {
+				if (bitrates[j].bitrate == rate)
 					rates |= BIT(j);
 			}
 		}
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 6a96663..3b55a43 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -53,6 +53,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 	struct cfg80211_chan_def chandef;
 	struct beacon_data *presp;
 	int frame_len;
+	struct ieee80211_rate *bitrates;
+	int n_bitrates;
 
 	lockdep_assert_held(&ifibss->mtx);
 
@@ -100,6 +102,11 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 
 	sband = local->hw.wiphy->bands[chan->band];
 
+	if (WARN_ON(ieee80211_get_bitrates(sband, chandef.width,
+					   &bitrates, &n_bitrates)))
+		return;
+
+
 	/* Build IBSS probe response */
 	frame_len = sizeof(struct ieee80211_hdr_3addr) +
 		    12 /* struct ieee80211_mgmt.u.beacon */ +
@@ -134,11 +141,11 @@ 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);
+	rates = min_t(int, 8, n_bitrates);
 	*pos++ = WLAN_EID_SUPP_RATES;
 	*pos++ = rates;
 	for (i = 0; i < rates; i++) {
-		int rate = sband->bitrates[i].bitrate;
+		int rate = bitrates[i].bitrate;
 		u8 basic = 0;
 		if (basic_rates & BIT(i))
 			basic = 0x80;
@@ -157,11 +164,11 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 	*pos++ = 0;
 	*pos++ = 0;
 
-	if (sband->n_bitrates > 8) {
+	if (n_bitrates > 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;
+		for (i = 8; i < n_bitrates; i++) {
+			int rate = bitrates[i].bitrate;
 			u8 basic = 0;
 			if (basic_rates & BIT(i))
 				basic = 0x80;
@@ -240,7 +247,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, n_bitrates, supp_rates);
 
 	ifibss->state = IEEE80211_IBSS_MLME_JOINED;
 	mod_timer(&ifibss->timer,
@@ -263,6 +270,8 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 	int i, j;
 	u16 beacon_int = cbss->beacon_interval;
 	const struct cfg80211_bss_ies *ies;
+	struct ieee80211_rate *bitrates;
+	int n_bitrates;
 	u64 tsf;
 
 	lockdep_assert_held(&sdata->u.ibss.mtx);
@@ -271,6 +280,9 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 		beacon_int = 10;
 
 	sband = sdata->local->hw.wiphy->bands[cbss->channel->band];
+	if (WARN_ON(ieee80211_get_bitrates(sband, sdata->u.ibss.chandef.width,
+					   &bitrates, &n_bitrates)))
+		return;
 
 	basic_rates = 0;
 
@@ -278,8 +290,8 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 		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 + 4) / 5 == rate) {
+		for (j = 0; j < n_bitrates; j++) {
+			if ((bitrates[j].bitrate + 4) / 5 == rate) {
 				if (is_basic)
 					basic_rates |= BIT(j);
 				break;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 0e8f2d0..3258039 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -741,6 +741,8 @@ struct ieee80211_sub_if_data {
 
 	/* bitmap of allowed (non-MCS) rate indexes for rate control */
 	u32 rc_rateidx_mask[IEEE80211_NUM_BANDS];
+	u32 rc_rateidx_mask_half[IEEE80211_NUM_BANDS];
+	u32 rc_rateidx_mask_quarter[IEEE80211_NUM_BANDS];
 
 	bool rc_has_mcs_mask[IEEE80211_NUM_BANDS];
 	u8  rc_rateidx_mcs_mask[IEEE80211_NUM_BANDS][IEEE80211_HT_MCS_MASK_LEN];
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 60f1ce5..28a38a7 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1615,6 +1615,11 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
 		sband = local->hw.wiphy->bands[i];
 		sdata->rc_rateidx_mask[i] =
 			sband ? (1 << sband->n_bitrates) - 1 : 0;
+		sdata->rc_rateidx_mask_half[i] =
+			sband ? (1 << sband->n_bitrates_half) - 1 : 0;
+		sdata->rc_rateidx_mask_quarter[i] =
+			sband ? (1 << sband->n_bitrates_quarter) - 1 : 0;
+
 		if (sband)
 			memcpy(sdata->rc_rateidx_mcs_mask[i],
 			       sband->ht_cap.mcs.rx_mask,
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 8a7bfc4..f6b6b57 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -761,8 +761,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 
 		channels += sband->n_channels;
 
-		if (max_bitrates < sband->n_bitrates)
-			max_bitrates = sband->n_bitrates;
+		max_bitrates = max(max_bitrates, sband->n_bitrates);
+		max_bitrates = max(max_bitrates, sband->n_bitrates_quarter);
+		max_bitrates = max(max_bitrates, sband->n_bitrates_half);
 		supp_ht = supp_ht || sband->ht_cap.ht_supported;
 		supp_vht = supp_vht || sband->vht_cap.vht_supported;
 
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 02c05fa..2f07985 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -92,6 +92,8 @@ static u32 mesh_set_short_slot_time(struct ieee80211_sub_if_data *sdata)
 	struct ieee80211_local *local = sdata->local;
 	enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
 	struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
+	struct ieee80211_rate *bitrates;
+	int n_bitrates;
 	struct sta_info *sta;
 	u32 erp_rates = 0, changed = 0;
 	int i;
@@ -106,8 +108,12 @@ static u32 mesh_set_short_slot_time(struct ieee80211_sub_if_data *sdata)
 		    local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
 		goto out;
 
-	for (i = 0; i < sband->n_bitrates; i++)
-		if (sband->bitrates[i].flags & IEEE80211_RATE_ERP_G)
+	if (ieee80211_get_bitrates(sband, local->hw.conf.chandef.width,
+				   &bitrates, &n_bitrates))
+		goto out;
+
+	for (i = 0; i < n_bitrates; i++)
+		if (bitrates[i].flags & IEEE80211_RATE_ERP_G)
 			erp_rates |= BIT(i);
 
 	if (!erp_rates)
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 03c1b73..837a580 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -513,8 +513,8 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
 /* frame sending functions */
 
 static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len,
-				      struct ieee80211_supported_band *sband,
-				      u32 *rates)
+				      struct ieee80211_rate *bitrates,
+				      int n_bitrates, u32 *rates)
 {
 	int i, j, count;
 	*rates = 0;
@@ -522,8 +522,8 @@ static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len,
 	for (i = 0; i < supp_rates_len; i++) {
 		int rate = supp_rates[i] & 0x7F;
 
-		for (j = 0; j < sband->n_bitrates; j++)
-			if ((sband->bitrates[j].bitrate + 4) / 5 == rate) {
+		for (j = 0; j < n_bitrates; j++)
+			if ((bitrates[j].bitrate + 4) / 5 == rate) {
 				*rates |= BIT(j);
 				count++;
 				break;
@@ -656,6 +656,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
 	struct ieee80211_supported_band *sband;
 	struct ieee80211_chanctx_conf *chanctx_conf;
 	struct ieee80211_channel *chan;
+	struct ieee80211_rate *bitrates;
+	int n_bitrates;
 	u32 rates = 0;
 
 	lockdep_assert_held(&ifmgd->mtx);
@@ -667,8 +669,13 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
 		return;
 	}
 	chan = chanctx_conf->def.chan;
-	rcu_read_unlock();
 	sband = local->hw.wiphy->bands[chan->band];
+	if (WARN_ON(ieee80211_get_bitrates(sband, chanctx_conf->def.width,
+					   &bitrates, &n_bitrates))) {
+		bitrates = sband->bitrates;
+		n_bitrates = sband->n_bitrates;
+	}
+	rcu_read_unlock();
 
 	if (assoc_data->supp_rates_len) {
 		/*
@@ -679,7 +686,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
 		 */
 		rates_len = ieee80211_compatible_rates(assoc_data->supp_rates,
 						       assoc_data->supp_rates_len,
-						       sband, &rates);
+						       bitrates, n_bitrates,
+						       &rates);
 	} else {
 		/*
 		 * In case AP not provide any supported rates information
@@ -687,7 +695,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
 		 * all rates that we support.
 		 */
 		rates = ~0;
-		rates_len = sband->n_bitrates;
+		rates_len = n_bitrates;
 	}
 
 	skb = alloc_skb(local->hw.extra_tx_headroom +
@@ -762,9 +770,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
 	*pos++ = supp_rates_len;
 
 	count = 0;
-	for (i = 0; i < sband->n_bitrates; i++) {
+	for (i = 0; i < n_bitrates; i++) {
 		if (BIT(i) & rates) {
-			int rate = sband->bitrates[i].bitrate;
+			int rate = bitrates[i].bitrate;
 			*pos++ = (u8) ((rate + 4) / 5);
 			if (++count == 8)
 				break;
@@ -776,9 +784,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
 		*pos++ = WLAN_EID_EXT_SUPP_RATES;
 		*pos++ = rates_len - count;
 
-		for (i++; i < sband->n_bitrates; i++) {
+		for (i++; i < n_bitrates; i++) {
 			if (BIT(i) & rates) {
-				int rate = sband->bitrates[i].bitrate;
+				int rate = bitrates[i].bitrate;
 				*pos++ = (u8) ((rate + 4) / 5);
 			}
 		}
@@ -2439,7 +2447,8 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
 	return RX_MGMT_CFG80211_DISASSOC;
 }
 
-static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
+static void ieee80211_get_rates(struct ieee80211_rate *bitrates,
+				int n_bitrates,
 				u8 *supp_rates, unsigned int supp_rates_len,
 				u32 *rates, u32 *basic_rates,
 				bool *have_higher_than_11mbit,
@@ -2466,8 +2475,8 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
 		    (supp_rates[i] & 0x7f) == BSS_MEMBERSHIP_SELECTOR_HT_PHY)
 			continue;
 
-		for (j = 0; j < sband->n_bitrates; j++) {
-			if ((sband->bitrates[j].bitrate + 4) / 5 == rate) {
+		for (j = 0; j < n_bitrates; j++) {
+			if ((bitrates[j].bitrate + 4) / 5 == rate) {
 				*rates |= BIT(j);
 				if (is_basic)
 					*basic_rates |= BIT(j);
@@ -3860,6 +3869,9 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
 		int min_rate = INT_MAX, min_rate_index = -1;
 		struct ieee80211_supported_band *sband;
 		const struct cfg80211_bss_ies *ies;
+		struct ieee80211_chanctx_conf *chanctx_conf;
+		struct ieee80211_rate *bitrates;
+		int n_bitrates;
 
 		sband = local->hw.wiphy->bands[cbss->channel->band];
 
@@ -3868,8 +3880,21 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
 			sta_info_free(local, new_sta);
 			return err;
 		}
+		rcu_read_lock();
+		chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+		if (WARN_ON(!chanctx_conf)) {
+			rcu_read_unlock();
+			return err;
+		}
+		if (WARN_ON(ieee80211_get_bitrates(sband,
+						   chanctx_conf->def.width,
+						   &bitrates, &n_bitrates))) {
+			rcu_read_unlock();
+			return err;
+		}
+		rcu_read_unlock();
 
-		ieee80211_get_rates(sband, bss->supp_rates,
+		ieee80211_get_rates(bitrates, n_bitrates, bss->supp_rates,
 				    bss->supp_rates_len,
 				    &rates, &basic_rates,
 				    &have_higher_than_11mbit,
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index 1ca7ded..99a3fbd 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -211,7 +211,8 @@ static bool rc_no_data_or_no_ack_use_min(struct ieee80211_tx_rate_control *txrc)
 }
 
 static void rc_send_low_broadcast(s8 *idx, u32 basic_rates,
-				  struct ieee80211_supported_band *sband)
+				  struct ieee80211_rate *bitrates,
+				  int n_bitrates)
 {
 	u8 i;
 
@@ -222,7 +223,7 @@ static void rc_send_low_broadcast(s8 *idx, u32 basic_rates,
 	if (basic_rates & (1 << *idx))
 		return; /* selected rate is a basic rate */
 
-	for (i = *idx + 1; i <= sband->n_bitrates; i++) {
+	for (i = *idx + 1; i <= n_bitrates; i++) {
 		if (basic_rates & (1 << i)) {
 			*idx = i;
 			return;
@@ -234,12 +235,14 @@ static void rc_send_low_broadcast(s8 *idx, u32 basic_rates,
 
 static inline s8
 rate_lowest_non_cck_index(struct ieee80211_supported_band *sband,
+			  struct ieee80211_rate *bitrates,
+			  int n_bitrates,
 			  struct ieee80211_sta *sta)
 {
 	int i;
 
-	for (i = 0; i < sband->n_bitrates; i++) {
-		struct ieee80211_rate *srate = &sband->bitrates[i];
+	for (i = 0; i < n_bitrates; i++) {
+		struct ieee80211_rate *srate = &bitrates[i];
 		if ((srate->bitrate == 10) || (srate->bitrate == 20) ||
 		    (srate->bitrate == 55) || (srate->bitrate == 110))
 			continue;
@@ -254,15 +257,19 @@ rate_lowest_non_cck_index(struct ieee80211_supported_band *sband,
 
 static void __rate_control_send_low(struct ieee80211_hw *hw,
 				    struct ieee80211_supported_band *sband,
+				    struct ieee80211_rate *bitrates,
+				    int n_bitrates,
 				    struct ieee80211_sta *sta,
 				    struct ieee80211_tx_info *info)
 {
 	if ((sband->band != IEEE80211_BAND_2GHZ) ||
 	    !(info->flags & IEEE80211_TX_CTL_NO_CCK_RATE))
-		info->control.rates[0].idx = rate_lowest_index(sband, sta);
+		info->control.rates[0].idx =
+			rate_lowest_index(sband, n_bitrates, sta);
 	else
 		info->control.rates[0].idx =
-			rate_lowest_non_cck_index(sband, sta);
+			rate_lowest_non_cck_index(sband, bitrates, n_bitrates,
+						  sta);
 
 	info->control.rates[0].count =
 		(info->flags & IEEE80211_TX_CTL_NO_ACK) ?
@@ -278,10 +285,18 @@ bool rate_control_send_low(struct ieee80211_sta *sta,
 {
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);
 	struct ieee80211_supported_band *sband = txrc->sband;
+	struct ieee80211_rate *bitrates;
+	int n_bitrates;
 	int mcast_rate;
 
+	if (WARN_ON(ieee80211_get_bitrates(sband,
+					   txrc->hw->conf.chandef.width,
+					   &bitrates, &n_bitrates)))
+		return false;
+
 	if (!sta || !priv_sta || rc_no_data_or_no_ack_use_min(txrc)) {
-		__rate_control_send_low(txrc->hw, sband, sta, info);
+		__rate_control_send_low(txrc->hw, sband, bitrates, n_bitrates,
+					sta, info);
 
 		if (!sta && txrc->bss) {
 			mcast_rate = txrc->bss_conf->mcast_rate[sband->band];
@@ -292,7 +307,7 @@ bool rate_control_send_low(struct ieee80211_sta *sta,
 
 			rc_send_low_broadcast(&info->control.rates[0].idx,
 					      txrc->bss_conf->basic_rates,
-					      sband);
+					      bitrates, n_bitrates);
 		}
 		return true;
 	}
@@ -366,7 +381,8 @@ static bool rate_idx_match_mcs_mask(struct ieee80211_tx_rate *rate,
 
 
 static void rate_idx_match_mask(struct ieee80211_tx_rate *rate,
-				struct ieee80211_supported_band *sband,
+				struct ieee80211_rate *bitrates,
+				int n_bitrates,
 				enum nl80211_chan_width chan_width,
 				u32 mask,
 				u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN])
@@ -387,13 +403,13 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate,
 				  IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
 		alt_rate.count = rate->count;
 		if (rate_idx_match_legacy_mask(&alt_rate,
-					       sband->n_bitrates, mask)) {
+					       n_bitrates, mask)) {
 			*rate = alt_rate;
 			return;
 		}
 	} else {
 		/* handle legacy rates */
-		if (rate_idx_match_legacy_mask(rate, sband->n_bitrates, mask))
+		if (rate_idx_match_legacy_mask(rate, n_bitrates, mask))
 			return;
 
 		/* if HT BSS, and we handle a data frame, also try HT rates */
@@ -435,7 +451,8 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate,
 }
 
 static void rate_fixup_ratelist(struct ieee80211_vif *vif,
-				struct ieee80211_supported_band *sband,
+				struct ieee80211_rate *bitrates,
+				int n_bitrates,
 				struct ieee80211_tx_info *info,
 				struct ieee80211_tx_rate *rates,
 				int max_rates)
@@ -456,18 +473,18 @@ static void rate_fixup_ratelist(struct ieee80211_vif *vif,
 		u32 basic_rates = vif->bss_conf.basic_rates;
 		s8 baserate = basic_rates ? ffs(basic_rates - 1) : 0;
 
-		rate = &sband->bitrates[rates[0].idx];
+		rate = &bitrates[rates[0].idx];
 
-		for (i = 0; i < sband->n_bitrates; i++) {
+		for (i = 0; i < 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)
+			if (bitrates[i].bitrate > rate->bitrate)
 				continue;
 			/* maximum */
-			if (sband->bitrates[baserate].bitrate <
-			     sband->bitrates[i].bitrate)
+			if (bitrates[baserate].bitrate <
+			     bitrates[i].bitrate)
 				baserate = i;
 		}
 
@@ -515,12 +532,12 @@ static void rate_fixup_ratelist(struct ieee80211_vif *vif,
 		}
 
 		/* RC is busted */
-		if (WARN_ON_ONCE(rates[i].idx >= sband->n_bitrates)) {
+		if (WARN_ON_ONCE(rates[i].idx >= n_bitrates)) {
 			rates[i].idx = -1;
 			continue;
 		}
 
-		rate = &sband->bitrates[rates[i].idx];
+		rate = &bitrates[rates[i].idx];
 
 		/* set up short preamble */
 		if (info->control.short_preamble &&
@@ -576,7 +593,8 @@ static void rate_control_fill_sta_table(struct ieee80211_sta *sta,
 
 static void rate_control_apply_mask(struct ieee80211_sub_if_data *sdata,
 				    struct ieee80211_sta *sta,
-				    struct ieee80211_supported_band *sband,
+				    struct ieee80211_rate *bitrates,
+				    int n_bitrates,
 				    struct ieee80211_tx_info *info,
 				    struct ieee80211_tx_rate *rates,
 				    int max_rates)
@@ -592,9 +610,20 @@ static void rate_control_apply_mask(struct ieee80211_sub_if_data *sdata,
 	 * default mask (allow all rates) is used to save some processing for
 	 * the common case.
 	 */
-	mask = sdata->rc_rateidx_mask[info->band];
+	chan_width = sdata->vif.bss_conf.chandef.width;
+	switch (chan_width) {
+	case NL80211_CHAN_WIDTH_5:
+		mask = sdata->rc_rateidx_mask_quarter[info->band];
+		break;
+	case NL80211_CHAN_WIDTH_10:
+		mask = sdata->rc_rateidx_mask_half[info->band];
+		break;
+	default:
+		mask = sdata->rc_rateidx_mask[info->band];
+		break;
+	}
 	has_mcs_mask = sdata->rc_has_mcs_mask[info->band];
-	if (mask == (1 << sband->n_bitrates) - 1 && !has_mcs_mask)
+	if (mask == (1 << n_bitrates) - 1 && !has_mcs_mask)
 		return;
 
 	if (has_mcs_mask)
@@ -615,14 +644,13 @@ static void rate_control_apply_mask(struct ieee80211_sub_if_data *sdata,
 	 * included in the configured mask and change the rate indexes
 	 * if needed.
 	 */
-	chan_width = sdata->vif.bss_conf.chandef.width;
 	for (i = 0; i < max_rates; i++) {
 		/* Skip invalid rates */
 		if (rates[i].idx < 0)
 			break;
 
-		rate_idx_match_mask(&rates[i], sband, mask, chan_width,
-				    mcs_mask);
+		rate_idx_match_mask(&rates[i], bitrates, n_bitrates, mask,
+				    chan_width, mcs_mask);
 	}
 }
 
@@ -636,6 +664,8 @@ void ieee80211_get_tx_rates(struct ieee80211_vif *vif,
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_supported_band *sband;
+	struct ieee80211_rate *bitrates;
+	int n_bitrates;
 
 	rate_control_fill_sta_table(sta, info, dest, max_rates);
 
@@ -645,14 +675,22 @@ void ieee80211_get_tx_rates(struct ieee80211_vif *vif,
 	sdata = vif_to_sdata(vif);
 	sband = sdata->local->hw.wiphy->bands[info->band];
 
+	if (WARN_ON(ieee80211_get_bitrates(sband,
+					   sdata->local->hw.conf.chandef.width,
+					   &bitrates, &n_bitrates)))
+		return;
+
 	if (ieee80211_is_data(hdr->frame_control))
-		rate_control_apply_mask(sdata, sta, sband, info, dest, max_rates);
+		rate_control_apply_mask(sdata, sta, bitrates, n_bitrates, info,
+					dest, max_rates);
 
 	if (dest[0].idx < 0)
-		__rate_control_send_low(&sdata->local->hw, sband, sta, info);
+		__rate_control_send_low(&sdata->local->hw, sband, bitrates,
+					n_bitrates, sta, info);
 
 	if (sta)
-		rate_fixup_ratelist(vif, sband, info, dest, max_rates);
+		rate_fixup_ratelist(vif, bitrates, n_bitrates, info, dest,
+				    max_rates);
 }
 EXPORT_SYMBOL(ieee80211_get_tx_rates);
 
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index 6c89c29..00024c8 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -427,10 +427,19 @@ minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband,
 	struct ieee80211_rate *ctl_rate;
 	unsigned int i, n = 0;
 	unsigned int t_slot = 9; /* FIXME: get real slot time */
+	struct ieee80211_rate *bitrates;
+	int n_bitrates;
+
+	if (WARN_ON(ieee80211_get_bitrates(sband,
+					   mp->hw->conf.chandef.width,
+					   &bitrates, &n_bitrates))) {
+		bitrates = sband->bitrates;
+		n_bitrates = sband->n_bitrates;
+	}
 
 	mi->sta = sta;
-	mi->lowest_rix = rate_lowest_index(sband, sta);
-	ctl_rate = &sband->bitrates[mi->lowest_rix];
+	mi->lowest_rix = rate_lowest_index(sband, n_bitrates, sta);
+	ctl_rate = &bitrates[mi->lowest_rix];
 	mi->sp_ack_dur = ieee80211_frame_duration(sband->band, 10,
 				ctl_rate->bitrate,
 				!!(ctl_rate->flags & IEEE80211_RATE_ERP_G), 1,
@@ -439,7 +448,7 @@ minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband,
 	memset(mi->max_tp_rate, 0, sizeof(mi->max_tp_rate));
 	mi->max_prob_rate = 0;
 
-	for (i = 0; i < sband->n_bitrates; i++) {
+	for (i = 0; i < n_bitrates; i++) {
 		struct minstrel_rate *mr = &mi->r[n];
 		unsigned int tx_time = 0, tx_time_cts = 0, tx_time_rtscts = 0;
 		unsigned int tx_time_single;
@@ -451,8 +460,8 @@ minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband,
 		memset(mr, 0, sizeof(*mr));
 
 		mr->rix = i;
-		mr->bitrate = (sband->bitrates[i].bitrate + 4) / 5;
-		calc_rate_durations(sband->band, mr, &sband->bitrates[i], mp);
+		mr->bitrate = (bitrates[i].bitrate + 4) / 5;
+		calc_rate_durations(sband->band, mr, &bitrates[i], mp);
 
 		/* calculate maximum number of retransmissions before
 		 * fallback (based on maximum segment size) */
@@ -481,11 +490,11 @@ minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband,
 		} while ((tx_time < mp->segment_size) &&
 				(++mr->retry_count < mp->max_retry));
 		mr->adjusted_retry_count = mr->retry_count;
-		if (!(sband->bitrates[i].flags & IEEE80211_RATE_ERP_G))
+		if (!(bitrates[i].flags & IEEE80211_RATE_ERP_G))
 			mr->retry_count_cts = mr->retry_count;
 	}
 
-	for (i = n; i < sband->n_bitrates; i++) {
+	for (i = n; i < n_bitrates; i++) {
 		struct minstrel_rate *mr = &mi->r[i];
 		mr->rix = -1;
 	}
@@ -513,8 +522,12 @@ minstrel_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
 
 	for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
 		sband = hw->wiphy->bands[i];
-		if (sband && sband->n_bitrates > max_rates)
-			max_rates = sband->n_bitrates;
+		if (!sband)
+			continue;
+
+		max_rates = max(sband->n_bitrates, max_rates);
+		max_rates = max(sband->n_bitrates_half, max_rates);
+		max_rates = max(sband->n_bitrates_quarter, max_rates);
 	}
 
 	mi->r = kzalloc(sizeof(struct minstrel_rate) * max_rates, gfp);
@@ -548,22 +561,28 @@ minstrel_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta)
 static void
 minstrel_init_cck_rates(struct minstrel_priv *mp)
 {
-	static const int bitrates[4] = { 10, 20, 55, 110 };
+	static const int cck_bitrates[4] = { 10, 20, 55, 110 };
 	struct ieee80211_supported_band *sband;
+	struct ieee80211_rate *bitrates;
+	int n_bitrates;
 	int i, j;
 
 	sband = mp->hw->wiphy->bands[IEEE80211_BAND_2GHZ];
 	if (!sband)
 		return;
 
-	for (i = 0, j = 0; i < sband->n_bitrates; i++) {
-		struct ieee80211_rate *rate = &sband->bitrates[i];
+	if (ieee80211_get_bitrates(sband, mp->hw->conf.chandef.width,
+				   &bitrates, &n_bitrates))
+		return;
+
+	for (i = 0, j = 0; i < n_bitrates; i++) {
+		struct ieee80211_rate *rate = &bitrates[i];
 
 		if (rate->flags & IEEE80211_RATE_ERP_G)
 			continue;
 
-		for (j = 0; j < ARRAY_SIZE(bitrates); j++) {
-			if (rate->bitrate != bitrates[j])
+		for (j = 0; j < ARRAY_SIZE(cck_bitrates); j++) {
+			if (rate->bitrate != cck_bitrates[j])
 				continue;
 
 			mp->cck_rates[j] = i;
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
index f05eeff..21688ac 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -815,19 +815,25 @@ minstrel_ht_update_cck(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
 		       struct ieee80211_supported_band *sband,
 		       struct ieee80211_sta *sta)
 {
-	int i;
+	struct ieee80211_rate *bitrates;
+	int i, n_bitrates;
+
 
 	if (sband->band != IEEE80211_BAND_2GHZ)
 		return;
 
 	mi->cck_supported = 0;
 	mi->cck_supported_short = 0;
+	if (ieee80211_get_bitrates(sband, mp->hw->conf.chandef.width,
+				   &bitrates, &n_bitrates))
+		return;
+
 	for (i = 0; i < 4; i++) {
 		if (!rate_supported(sta, sband->band, mp->cck_rates[i]))
 			continue;
 
 		mi->cck_supported |= BIT(i);
-		if (sband->bitrates[i].flags & IEEE80211_RATE_SHORT_PREAMBLE)
+		if (bitrates[i].flags & IEEE80211_RATE_SHORT_PREAMBLE)
 			mi->cck_supported_short |= BIT(i);
 	}
 
@@ -963,8 +969,12 @@ minstrel_ht_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
 
 	for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
 		sband = hw->wiphy->bands[i];
-		if (sband && sband->n_bitrates > max_rates)
-			max_rates = sband->n_bitrates;
+		if (!sband)
+			continue;
+
+		max_rates = max(sband->n_bitrates, max_rates);
+		max_rates = max(sband->n_bitrates_half, max_rates);
+		max_rates = max(sband->n_bitrates_quarter, max_rates);
 	}
 
 	msp = kzalloc(sizeof(*msp), gfp);
diff --git a/net/mac80211/rc80211_pid.h b/net/mac80211/rc80211_pid.h
index 19111c7..dc48981 100644
--- a/net/mac80211/rc80211_pid.h
+++ b/net/mac80211/rc80211_pid.h
@@ -269,6 +269,8 @@ struct rc_pid_info {
 	/* Index of the last used rate. */
 	int oldrate;
 
+	struct ieee80211_hw *hw;
+
 #ifdef CONFIG_MAC80211_DEBUGFS
 	/* Debugfs entries created for the parameters above. */
 	struct rc_pid_debugfs_entries dentries;
diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c
index 502d3ec..cb9ee86 100644
--- a/net/mac80211/rc80211_pid_algo.c
+++ b/net/mac80211/rc80211_pid_algo.c
@@ -72,13 +72,14 @@
 static void rate_control_pid_adjust_rate(struct ieee80211_supported_band *sband,
 					 struct ieee80211_sta *sta,
 					 struct rc_pid_sta_info *spinfo, int adj,
-					 struct rc_pid_rateinfo *rinfo)
+					 struct rc_pid_rateinfo *rinfo,
+					 struct ieee80211_rate *bitrates,
+					 int n_bitrates)
 {
-	int cur_sorted, new_sorted, probe, tmp, n_bitrates, band;
+	int cur_sorted, new_sorted, probe, tmp, band;
 	int cur = spinfo->txrate_idx;
 
 	band = sband->band;
-	n_bitrates = sband->n_bitrates;
 
 	/* Map passed arguments to sorted values. */
 	cur_sorted = rinfo[cur].rev_index;
@@ -121,7 +122,7 @@ static void rate_control_pid_adjust_rate(struct ieee80211_supported_band *sband,
 #ifdef CONFIG_MAC80211_DEBUGFS
 	rate_control_pid_event_rate_change(&spinfo->events,
 		spinfo->txrate_idx,
-		sband->bitrates[spinfo->txrate_idx].bitrate);
+		bitrates[spinfo->txrate_idx].bitrate);
 #endif
 }
 
@@ -155,6 +156,15 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo,
 	u32 err_der;
 	int adj, i, j, tmp;
 	unsigned long period;
+	struct ieee80211_rate *bitrates;
+	int n_bitrates;
+
+	if (WARN_ON(ieee80211_get_bitrates(sband,
+					   pinfo->hw->conf.chandef.width,
+					   &bitrates, &n_bitrates))) {
+		bitrates = sband->bitrates;
+		n_bitrates = sband->n_bitrates;
+	}
 
 	/* In case nothing happened during the previous control interval, turn
 	 * the sharpening factor on. */
@@ -186,7 +196,7 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo,
 		rinfo[j].diff = rinfo[i].diff + tmp;
 		pinfo->oldrate = spinfo->txrate_idx;
 	}
-	rate_control_pid_normalize(pinfo, sband->n_bitrates);
+	rate_control_pid_normalize(pinfo, n_bitrates);
 
 	/* Compute the proportional, integral and derivative errors. */
 	err_prop = (pinfo->target - pf) << RC_PID_ARITH_SHIFT;
@@ -213,7 +223,8 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo,
 
 	/* Change rate. */
 	if (adj)
-		rate_control_pid_adjust_rate(sband, sta, spinfo, adj, rinfo);
+		rate_control_pid_adjust_rate(sband, sta, spinfo, adj, rinfo,
+					     bitrates, n_bitrates);
 }
 
 static void rate_control_pid_tx_status(void *priv, struct ieee80211_supported_band *sband,
@@ -265,7 +276,16 @@ rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta,
 	struct ieee80211_supported_band *sband = txrc->sband;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct rc_pid_sta_info *spinfo = priv_sta;
-	int rateidx;
+	struct ieee80211_rate *bitrates;
+	int rateidx, n_bitrates;
+
+	if (WARN_ON(ieee80211_get_bitrates(sband,
+					   txrc->hw->conf.chandef.width,
+					   &bitrates, &n_bitrates))) {
+		bitrates = sband->bitrates;
+		n_bitrates = sband->n_bitrates;
+	}
+
 
 	if (txrc->rts)
 		info->control.rates[0].count =
@@ -280,14 +300,14 @@ rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta,
 
 	rateidx = spinfo->txrate_idx;
 
-	if (rateidx >= sband->n_bitrates)
-		rateidx = sband->n_bitrates - 1;
+	if (rateidx >= n_bitrates)
+		rateidx = n_bitrates - 1;
 
 	info->control.rates[0].idx = rateidx;
 
 #ifdef CONFIG_MAC80211_DEBUGFS
 	rate_control_pid_event_tx_rate(&spinfo->events,
-		rateidx, sband->bitrates[rateidx].bitrate);
+		rateidx, bitrates[rateidx].bitrate);
 #endif
 }
 
@@ -298,6 +318,8 @@ rate_control_pid_rate_init(void *priv, struct ieee80211_supported_band *sband,
 	struct rc_pid_sta_info *spinfo = priv_sta;
 	struct rc_pid_info *pinfo = priv;
 	struct rc_pid_rateinfo *rinfo = pinfo->rinfo;
+	struct ieee80211_rate *bitrates;
+	int n_bitrates;
 	int i, j, tmp;
 	bool s;
 
@@ -309,7 +331,15 @@ rate_control_pid_rate_init(void *priv, struct ieee80211_supported_band *sband,
 	/* Sort the rates. This is optimized for the most common case (i.e.
 	 * almost-sorted CCK+OFDM rates). Kind of bubble-sort with reversed
 	 * mapping too. */
-	for (i = 0; i < sband->n_bitrates; i++) {
+
+	if (WARN_ON(ieee80211_get_bitrates(sband,
+					   pinfo->hw->conf.chandef.width,
+					   &bitrates, &n_bitrates))) {
+		bitrates = sband->bitrates;
+		n_bitrates = sband->n_bitrates;
+	}
+
+	for (i = 0; i < n_bitrates; i++) {
 		rinfo[i].index = i;
 		rinfo[i].rev_index = i;
 		if (RC_PID_FAST_START)
@@ -320,8 +350,8 @@ rate_control_pid_rate_init(void *priv, struct ieee80211_supported_band *sband,
 	for (i = 1; i < sband->n_bitrates; i++) {
 		s = false;
 		for (j = 0; j < sband->n_bitrates - i; j++)
-			if (unlikely(sband->bitrates[rinfo[j].index].bitrate >
-				     sband->bitrates[rinfo[j + 1].index].bitrate)) {
+			if (unlikely(bitrates[rinfo[j].index].bitrate >
+				     bitrates[rinfo[j + 1].index].bitrate)) {
 				tmp = rinfo[j].index;
 				rinfo[j].index = rinfo[j + 1].index;
 				rinfo[j + 1].index = tmp;
@@ -333,7 +363,7 @@ rate_control_pid_rate_init(void *priv, struct ieee80211_supported_band *sband,
 			break;
 	}
 
-	spinfo->txrate_idx = rate_lowest_index(sband, sta);
+	spinfo->txrate_idx = rate_lowest_index(sband, n_bitrates, sta);
 }
 
 static void *rate_control_pid_alloc(struct ieee80211_hw *hw,
@@ -351,10 +381,16 @@ static void *rate_control_pid_alloc(struct ieee80211_hw *hw,
 	if (!pinfo)
 		return NULL;
 
+	pinfo->hw = hw;
+
 	for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
 		sband = hw->wiphy->bands[i];
-		if (sband && sband->n_bitrates > max_rates)
-			max_rates = sband->n_bitrates;
+		if (!sband)
+			continue;
+
+		max_rates = max(sband->n_bitrates, max_rates);
+		max_rates = max(sband->n_bitrates_half, max_rates);
+		max_rates = max(sband->n_bitrates_quarter, max_rates);
 	}
 
 	rinfo = kmalloc(sizeof(*rinfo) * max_rates, GFP_ATOMIC);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 06f71c6..b0834a9 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2832,13 +2832,23 @@ static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx,
 		struct ieee80211_rate *rate = NULL;
 		struct ieee80211_supported_band *sband;
 		struct ieee80211_rx_status *status;
+		struct ieee80211_rate *bitrates;
+		int n_bitrates;
+		enum nl80211_chan_width width;
 
 		status = IEEE80211_SKB_RXCB((rx->skb));
 
 		sband = rx->local->hw.wiphy->bands[status->band];
 		if (!(status->flag & RX_FLAG_HT) &&
-		    !(status->flag & RX_FLAG_VHT))
-			rate = &sband->bitrates[status->rate_idx];
+		    !(status->flag & RX_FLAG_VHT)) {
+			width = rx->sdata->local->hw.conf.chandef.width;
+			if (WARN_ON(ieee80211_get_bitrates(sband, width,
+							   &bitrates,
+							   &n_bitrates)))
+				bitrates = sband->bitrates;
+
+			rate = &bitrates[status->rate_idx];
+		}
 
 		ieee80211_rx_cooked_monitor(rx, rate);
 		break;
@@ -3293,9 +3303,20 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
 				      status->rate_idx, status->vht_nss))
 				goto drop;
 		} else {
-			if (WARN_ON(status->rate_idx >= sband->n_bitrates))
+			struct ieee80211_rate *bitrates;
+			int n_bitrates;
+			enum nl80211_chan_width width;
+
+			width = local->hw.conf.chandef.width;
+
+			if (WARN_ON(ieee80211_get_bitrates(sband, width,
+							   &bitrates,
+							   &n_bitrates)))
 				goto drop;
-			rate = &sband->bitrates[status->rate_idx];
+
+			if (WARN_ON(status->rate_idx >= n_bitrates))
+				goto drop;
+			rate = &bitrates[status->rate_idx];
 		}
 	}
 
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index f62e4f6..41805ed 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -253,7 +253,8 @@ static int ieee80211_tx_radiotap_len(struct ieee80211_tx_info *info)
 }
 
 static void ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band
-					     *sband, struct sk_buff *skb,
+					     *sband, struct ieee80211_hw *hw,
+					     struct sk_buff *skb,
 					     int retry_count, int rtap_len)
 {
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -280,10 +281,18 @@ static void ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band
 	/* IEEE80211_RADIOTAP_RATE */
 	if (info->status.rates[0].idx >= 0 &&
 	    !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) {
+		struct ieee80211_rate *bitrates;
+		int n_bitrates;
 		int rate;
 
+		if (ieee80211_get_bitrates(sband, hw->conf.chandef.width,
+					   &bitrates, &n_bitrates)) {
+			bitrates = sband->bitrates;
+			n_bitrates = sband->n_bitrates;
+		}
+
 		rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE);
-		rate = sband->bitrates[info->status.rates[0].idx].bitrate;
+		rate = bitrates[info->status.rates[0].idx].bitrate;
 		*pos = (rate + 4) / 5;
 		/* padding for tx flags */
 		pos += 2;
@@ -627,7 +636,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 		dev_kfree_skb(skb);
 		return;
 	}
-	ieee80211_add_tx_radiotap_header(sband, skb, retry_count, rtap_len);
+	ieee80211_add_tx_radiotap_header(sband, hw, skb, retry_count, rtap_len);
 
 	/* XXX: is this sufficient for BPF? */
 	skb_set_mac_header(skb, 0);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index e1f18a8..e8ef0bd 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -46,6 +46,8 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
 	struct ieee80211_supported_band *sband;
 	struct ieee80211_hdr *hdr;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_rate *bitrates;
+	int n_bitrates;
 
 	/* assume HW handles this */
 	if (tx->rate.flags & IEEE80211_TX_RC_MCS)
@@ -56,7 +58,12 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
 		return 0;
 
 	sband = local->hw.wiphy->bands[info->band];
-	txrate = &sband->bitrates[tx->rate.idx];
+	if (WARN_ON(ieee80211_get_bitrates(sband,
+					   local->hw.conf.chandef.width,
+					   &bitrates, &n_bitrates)))
+		return 0;
+
+	txrate = &bitrates[tx->rate.idx];
 
 	erp = txrate->flags & IEEE80211_RATE_ERP_G;
 
@@ -115,9 +122,9 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
 	 */
 	rate = -1;
 	/* use lowest available if everything fails */
-	mrate = sband->bitrates[0].bitrate;
-	for (i = 0; i < sband->n_bitrates; i++) {
-		struct ieee80211_rate *r = &sband->bitrates[i];
+	mrate = bitrates[0].bitrate;
+	for (i = 0; i < n_bitrates; i++) {
+		struct ieee80211_rate *r = &bitrates[i];
 
 		if (r->bitrate > txrate->bitrate)
 			break;
@@ -624,6 +631,8 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
 	u32 len;
 	struct ieee80211_tx_rate_control txrc;
 	struct ieee80211_sta_rates *ratetbl = NULL;
+	struct ieee80211_rate *bitrates;
+	int n_bitrates;
 	bool assoc = false;
 
 	memset(&txrc, 0, sizeof(txrc));
@@ -633,6 +642,11 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
 	len = min_t(u32, tx->skb->len + FCS_LEN,
 			 tx->local->hw.wiphy->frag_threshold);
 
+	if (WARN_ON(ieee80211_get_bitrates(sband,
+					   tx->local->hw.conf.chandef.width,
+					   &bitrates, &n_bitrates)))
+		return TX_DROP;
+
 	/* set up the tx rate control struct we give the RC algo */
 	txrc.hw = &tx->local->hw;
 	txrc.sband = sband;
@@ -640,7 +654,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
 	txrc.skb = tx->skb;
 	txrc.reported_rate.idx = -1;
 	txrc.rate_idx_mask = tx->sdata->rc_rateidx_mask[info->band];
-	if (txrc.rate_idx_mask == (1 << sband->n_bitrates) - 1)
+	if (txrc.rate_idx_mask == (1 << n_bitrates) - 1)
 		txrc.max_rate_idx = -1;
 	else
 		txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
@@ -2340,6 +2354,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
 	enum ieee80211_band band;
 	struct ieee80211_tx_rate_control txrc;
 	struct ieee80211_chanctx_conf *chanctx_conf;
+	struct ieee80211_rate *bitrates;
+	int n_bitrates;
 
 	rcu_read_lock();
 
@@ -2431,6 +2447,11 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
 
 	band = chanctx_conf->def.chan->band;
 
+	if (WARN_ON(ieee80211_get_bitrates(local->hw.wiphy->bands[band],
+					   chanctx_conf->def.width,
+					   &bitrates, &n_bitrates)))
+		goto out;
+
 	info = IEEE80211_SKB_CB(skb);
 
 	info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
@@ -2444,7 +2465,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
 	txrc.skb = skb;
 	txrc.reported_rate.idx = -1;
 	txrc.rate_idx_mask = sdata->rc_rateidx_mask[band];
-	if (txrc.rate_idx_mask == (1 << txrc.sband->n_bitrates) - 1)
+	if (txrc.rate_idx_mask == (1 << n_bitrates) - 1)
 		txrc.max_rate_idx = -1;
 	else
 		txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 9d04989..617364d 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -141,14 +141,21 @@ int ieee80211_frame_duration(enum ieee80211_band band, size_t len,
 		dur = 16; /* SIFS + signal ext */
 		dur += 16; /* IEEE 802.11-2012 18.3.2.4: T_PREAMBLE = 16 usec */
 		dur += 4; /* IEEE 802.11-2012 18.3.2.4: T_SIGNAL = 4 usec */
-		dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10,
-					4 * rate); /* T_SYM x N_SYM */
 
 		/* IEEE 802.11-2012 18.3.2.4: all values above are:
 		 *  * times 4 for 5 MHz
 		 *  * times 2 for 10 MHz
 		 */
 		dur *= divisor;
+
+		/*
+		 * rates should already consider the channel bandwidth,
+		 * don't apply divisor again.
+		 */
+		dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10,
+					4 * rate); /* T_SYM x N_SYM */
+
+
 	} else {
 		/*
 		 * 802.11b or 802.11g with 802.11b compatibility:
@@ -204,6 +211,8 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
 	struct ieee80211_local *local = hw_to_local(hw);
 	struct ieee80211_rate *rate;
 	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_rate *bitrates;
+	int n_bitrates;
 	bool short_preamble;
 	int erp, divisor = 1;
 	u16 dur;
@@ -213,7 +222,13 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
 
 	short_preamble = false;
 
-	rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx];
+	if (WARN_ON(ieee80211_get_bitrates(sband, hw->conf.chandef.width,
+					   &bitrates, &n_bitrates))) {
+		bitrates = sband->bitrates;
+		n_bitrates = sband->n_bitrates;
+	}
+
+	rate = &bitrates[frame_txctl->control.rts_cts_rate_idx];
 
 	erp = 0;
 	if (vif) {
@@ -248,6 +263,8 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
 	struct ieee80211_sub_if_data *sdata;
 	bool short_preamble;
 	int erp, divisor = 1;
+	struct ieee80211_rate *bitrates;
+	int n_bitrates;
 	u16 dur;
 	struct ieee80211_supported_band *sband;
 
@@ -255,7 +272,13 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
 
 	short_preamble = false;
 
-	rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx];
+	if (WARN_ON(ieee80211_get_bitrates(sband, hw->conf.chandef.width,
+					   &bitrates, &n_bitrates))) {
+		bitrates = sband->bitrates;
+		n_bitrates = sband->n_bitrates;
+	}
+
+	rate = &bitrates[frame_txctl->control.rts_cts_rate_idx];
 	erp = 0;
 	if (vif) {
 		sdata = vif_to_sdata(vif);
@@ -1092,20 +1115,26 @@ u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
 	struct ieee80211_rate *bitrates;
 	u32 mandatory_rates;
 	enum ieee80211_rate_flags mandatory_flag;
-	int i;
+	int i, n_bitrates;
 
 	sband = local->hw.wiphy->bands[band];
 	if (WARN_ON(!sband))
 		return 1;
 
+	if (WARN_ON(ieee80211_get_bitrates(sband,
+					   local->hw.conf.chandef.width,
+					   &bitrates, &n_bitrates))) {
+		bitrates = sband->bitrates;
+		n_bitrates = sband->n_bitrates;
+	}
+
 	if (band == IEEE80211_BAND_2GHZ)
 		mandatory_flag = IEEE80211_RATE_MANDATORY_B;
 	else
 		mandatory_flag = IEEE80211_RATE_MANDATORY_A;
 
-	bitrates = sband->bitrates;
 	mandatory_rates = 0;
-	for (i = 0; i < sband->n_bitrates; i++)
+	for (i = 0; i < n_bitrates; i++)
 		if (bitrates[i].flags & mandatory_flag)
 			mandatory_rates |= BIT(i);
 	return mandatory_rates;
@@ -1198,6 +1227,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
 			     u8 channel)
 {
 	struct ieee80211_supported_band *sband;
+	struct ieee80211_rate *bitrates;
+	int n_bitrates;
 	u8 *pos = buffer, *end = buffer + buffer_len;
 	size_t offset = 0, noffset;
 	int supp_rates_len, i;
@@ -1209,12 +1240,17 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
 	if (WARN_ON_ONCE(!sband))
 		return 0;
 
+	if (WARN_ON(ieee80211_get_bitrates(sband,
+					   local->hw.conf.chandef.width,
+					   &bitrates, &n_bitrates)))
+		return 0;
+
 	num_rates = 0;
-	for (i = 0; i < sband->n_bitrates; i++) {
+	for (i = 0; i < n_bitrates; i++) {
 		if ((BIT(i) & rate_mask) == 0)
 			continue; /* skip rate */
 		rates[num_rates++] = (u8)
-			((sband->bitrates[i].bitrate + 4) / 5);
+			((bitrates[i].bitrate + 4) / 5);
 	}
 
 	supp_rates_len = min_t(int, num_rates, 8);
@@ -1395,8 +1431,11 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
 	if (WARN_ON(!sband))
 		return 1;
 
-	bitrates = sband->bitrates;
-	num_rates = sband->n_bitrates;
+	if (WARN_ON(ieee80211_get_bitrates(sband,
+					   local->hw.conf.chandef.width,
+					   &bitrates, &num_rates)))
+		return 1;
+
 	supp_rates = 0;
 	for (i = 0; i < elems->supp_rates_len +
 		     elems->ext_supp_rates_len; i++) {
@@ -2036,12 +2075,18 @@ int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata,
 {
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_supported_band *sband;
-	int rate;
-	u8 i, rates, *pos;
+	struct ieee80211_rate *bitrates;
+	int rate, rates;
+	u8 i, *pos;
 	u32 basic_rates = sdata->vif.bss_conf.basic_rates;
 
 	sband = local->hw.wiphy->bands[band];
-	rates = sband->n_bitrates;
+
+	if (WARN_ON(ieee80211_get_bitrates(sband,
+					   sdata->local->hw.conf.chandef.width,
+					   &bitrates, &rates)))
+		return -EINVAL;
+
 	if (rates > 8)
 		rates = 8;
 
@@ -2055,7 +2100,7 @@ int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata,
 		u8 basic = 0;
 		if (need_basic && basic_rates & BIT(i))
 			basic = 0x80;
-		rate = sband->bitrates[i].bitrate;
+		rate = bitrates[i].bitrate;
 		*pos++ = basic | (u8) ((rate + 4) / 5);
 	}
 
@@ -2068,11 +2113,17 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
 {
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_supported_band *sband;
-	int rate;
+	struct ieee80211_rate *bitrates;
+	int n_bitrates, rate;
 	u8 i, exrates, *pos;
 	u32 basic_rates = sdata->vif.bss_conf.basic_rates;
 
 	sband = local->hw.wiphy->bands[band];
+	if (WARN_ON(ieee80211_get_bitrates(sband,
+					   sdata->local->hw.conf.chandef.width,
+					   &bitrates, &n_bitrates)))
+		return -EINVAL;
+
 	exrates = sband->n_bitrates;
 	if (exrates > 8)
 		exrates -= 8;
@@ -2086,11 +2137,11 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
 		pos = skb_put(skb, exrates + 2);
 		*pos++ = WLAN_EID_EXT_SUPP_RATES;
 		*pos++ = exrates;
-		for (i = 8; i < sband->n_bitrates; i++) {
+		for (i = 8; i < n_bitrates; i++) {
 			u8 basic = 0;
 			if (need_basic && basic_rates & BIT(i))
 				basic = 0x80;
-			rate = sband->bitrates[i].bitrate;
+			rate = bitrates[i].bitrate;
 			*pos++ = basic | (u8) ((rate + 4) / 5);
 		}
 	}
@@ -2175,9 +2226,18 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
 			ri.flags |= RATE_INFO_FLAGS_SHORT_GI;
 	} else {
 		struct ieee80211_supported_band *sband;
+		struct ieee80211_rate *bitrates;
+		int n_bitrates;
 
 		sband = local->hw.wiphy->bands[status->band];
-		ri.legacy = sband->bitrates[status->rate_idx].bitrate;
+		if (WARN_ON(ieee80211_get_bitrates(sband,
+						   local->hw.conf.chandef.width,
+						   &bitrates, &n_bitrates))) {
+			bitrates = sband->bitrates;
+			n_bitrates = sband->n_bitrates;
+		}
+
+		ri.legacy = bitrates[status->rate_idx].bitrate;
 	}
 
 	rate = cfg80211_calculate_bitrate(&ri);
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux