diff options
author | Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> | 2015-08-06 17:47:33 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2015-08-14 11:49:51 -0400 |
commit | b119ad6e726cc805f739f8f6843b9de4df1f895e (patch) | |
tree | 059dd7446c6e86eb3df1619efd7acab6a9e07a96 | |
parent | e910867bd285bb8470c47076d99d0325aaea895c (diff) |
mac80211: add rate mask logic for vht rates
Define rc_rateidx_vht_mcs_mask array and rate_idx_match_vht_mcs_mask()
method in order to apply mcs mask for vht rates
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r-- | net/mac80211/cfg.c | 16 | ||||
-rw-r--r-- | net/mac80211/debugfs_netdev.c | 34 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 5 | ||||
-rw-r--r-- | net/mac80211/iface.c | 14 | ||||
-rw-r--r-- | net/mac80211/rate.c | 102 | ||||
-rw-r--r-- | net/mac80211/vht.c | 26 |
6 files changed, 181 insertions, 16 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 5789d8353505..685ec13ed7c2 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -2504,16 +2504,26 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, | |||
2504 | sdata->rc_rateidx_mask[i] = mask->control[i].legacy; | 2504 | sdata->rc_rateidx_mask[i] = mask->control[i].legacy; |
2505 | memcpy(sdata->rc_rateidx_mcs_mask[i], mask->control[i].ht_mcs, | 2505 | memcpy(sdata->rc_rateidx_mcs_mask[i], mask->control[i].ht_mcs, |
2506 | sizeof(mask->control[i].ht_mcs)); | 2506 | sizeof(mask->control[i].ht_mcs)); |
2507 | memcpy(sdata->rc_rateidx_vht_mcs_mask[i], | ||
2508 | mask->control[i].vht_mcs, | ||
2509 | sizeof(mask->control[i].vht_mcs)); | ||
2507 | 2510 | ||
2508 | sdata->rc_has_mcs_mask[i] = false; | 2511 | sdata->rc_has_mcs_mask[i] = false; |
2512 | sdata->rc_has_vht_mcs_mask[i] = false; | ||
2509 | if (!sband) | 2513 | if (!sband) |
2510 | continue; | 2514 | continue; |
2511 | 2515 | ||
2512 | for (j = 0; j < IEEE80211_HT_MCS_MASK_LEN; j++) | 2516 | for (j = 0; j < IEEE80211_HT_MCS_MASK_LEN; j++) { |
2513 | if (~sdata->rc_rateidx_mcs_mask[i][j]) { | 2517 | if (~sdata->rc_rateidx_mcs_mask[i][j]) |
2514 | sdata->rc_has_mcs_mask[i] = true; | 2518 | sdata->rc_has_mcs_mask[i] = true; |
2519 | |||
2520 | if (~sdata->rc_rateidx_vht_mcs_mask[i][j]) | ||
2521 | sdata->rc_has_vht_mcs_mask[i] = true; | ||
2522 | |||
2523 | if (sdata->rc_has_mcs_mask[i] && | ||
2524 | sdata->rc_has_vht_mcs_mask[i]) | ||
2515 | break; | 2525 | break; |
2516 | } | 2526 | } |
2517 | } | 2527 | } |
2518 | 2528 | ||
2519 | return 0; | 2529 | return 0; |
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index c09c0131bfa2..1021e87c051f 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c | |||
@@ -186,6 +186,38 @@ IEEE80211_IF_FILE(rc_rateidx_mcs_mask_2ghz, | |||
186 | IEEE80211_IF_FILE(rc_rateidx_mcs_mask_5ghz, | 186 | IEEE80211_IF_FILE(rc_rateidx_mcs_mask_5ghz, |
187 | rc_rateidx_mcs_mask[IEEE80211_BAND_5GHZ], HEXARRAY); | 187 | rc_rateidx_mcs_mask[IEEE80211_BAND_5GHZ], HEXARRAY); |
188 | 188 | ||
189 | static ssize_t ieee80211_if_fmt_rc_rateidx_vht_mcs_mask_2ghz( | ||
190 | const struct ieee80211_sub_if_data *sdata, | ||
191 | char *buf, int buflen) | ||
192 | { | ||
193 | int i, len = 0; | ||
194 | const u16 *mask = sdata->rc_rateidx_vht_mcs_mask[IEEE80211_BAND_2GHZ]; | ||
195 | |||
196 | for (i = 0; i < NL80211_VHT_NSS_MAX; i++) | ||
197 | len += scnprintf(buf + len, buflen - len, "%04x ", mask[i]); | ||
198 | len += scnprintf(buf + len, buflen - len, "\n"); | ||
199 | |||
200 | return len; | ||
201 | } | ||
202 | |||
203 | IEEE80211_IF_FILE_R(rc_rateidx_vht_mcs_mask_2ghz); | ||
204 | |||
205 | static ssize_t ieee80211_if_fmt_rc_rateidx_vht_mcs_mask_5ghz( | ||
206 | const struct ieee80211_sub_if_data *sdata, | ||
207 | char *buf, int buflen) | ||
208 | { | ||
209 | int i, len = 0; | ||
210 | const u16 *mask = sdata->rc_rateidx_vht_mcs_mask[IEEE80211_BAND_5GHZ]; | ||
211 | |||
212 | for (i = 0; i < NL80211_VHT_NSS_MAX; i++) | ||
213 | len += scnprintf(buf + len, buflen - len, "%04x ", mask[i]); | ||
214 | len += scnprintf(buf + len, buflen - len, "\n"); | ||
215 | |||
216 | return len; | ||
217 | } | ||
218 | |||
219 | IEEE80211_IF_FILE_R(rc_rateidx_vht_mcs_mask_5ghz); | ||
220 | |||
189 | IEEE80211_IF_FILE(flags, flags, HEX); | 221 | IEEE80211_IF_FILE(flags, flags, HEX); |
190 | IEEE80211_IF_FILE(state, state, LHEX); | 222 | IEEE80211_IF_FILE(state, state, LHEX); |
191 | IEEE80211_IF_FILE(txpower, vif.bss_conf.txpower, DEC); | 223 | IEEE80211_IF_FILE(txpower, vif.bss_conf.txpower, DEC); |
@@ -565,6 +597,8 @@ static void add_common_files(struct ieee80211_sub_if_data *sdata) | |||
565 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); | 597 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); |
566 | DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz); | 598 | DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz); |
567 | DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz); | 599 | DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz); |
600 | DEBUGFS_ADD(rc_rateidx_vht_mcs_mask_2ghz); | ||
601 | DEBUGFS_ADD(rc_rateidx_vht_mcs_mask_5ghz); | ||
568 | DEBUGFS_ADD(hw_queues); | 602 | DEBUGFS_ADD(hw_queues); |
569 | } | 603 | } |
570 | 604 | ||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 36f217e842d8..6e52659f923f 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -901,6 +901,9 @@ struct ieee80211_sub_if_data { | |||
901 | bool rc_has_mcs_mask[IEEE80211_NUM_BANDS]; | 901 | bool rc_has_mcs_mask[IEEE80211_NUM_BANDS]; |
902 | u8 rc_rateidx_mcs_mask[IEEE80211_NUM_BANDS][IEEE80211_HT_MCS_MASK_LEN]; | 902 | u8 rc_rateidx_mcs_mask[IEEE80211_NUM_BANDS][IEEE80211_HT_MCS_MASK_LEN]; |
903 | 903 | ||
904 | bool rc_has_vht_mcs_mask[IEEE80211_NUM_BANDS]; | ||
905 | u16 rc_rateidx_vht_mcs_mask[IEEE80211_NUM_BANDS][NL80211_VHT_NSS_MAX]; | ||
906 | |||
904 | union { | 907 | union { |
905 | struct ieee80211_if_ap ap; | 908 | struct ieee80211_if_ap ap; |
906 | struct ieee80211_if_wds wds; | 909 | struct ieee80211_if_wds wds; |
@@ -1713,6 +1716,8 @@ void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, | |||
1713 | enum ieee80211_band band, bool nss_only); | 1716 | enum ieee80211_band band, bool nss_only); |
1714 | void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata, | 1717 | void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata, |
1715 | struct ieee80211_sta_vht_cap *vht_cap); | 1718 | struct ieee80211_sta_vht_cap *vht_cap); |
1719 | void ieee80211_get_vht_mask_from_cap(__le16 vht_cap, | ||
1720 | u16 vht_mask[NL80211_VHT_NSS_MAX]); | ||
1716 | 1721 | ||
1717 | /* Spectrum management */ | 1722 | /* Spectrum management */ |
1718 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, | 1723 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 0fba7f97a963..6964fc6a8ea2 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -1788,13 +1788,23 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
1788 | sband = local->hw.wiphy->bands[i]; | 1788 | sband = local->hw.wiphy->bands[i]; |
1789 | sdata->rc_rateidx_mask[i] = | 1789 | sdata->rc_rateidx_mask[i] = |
1790 | sband ? (1 << sband->n_bitrates) - 1 : 0; | 1790 | sband ? (1 << sband->n_bitrates) - 1 : 0; |
1791 | if (sband) | 1791 | if (sband) { |
1792 | __le16 cap; | ||
1793 | u16 *vht_rate_mask; | ||
1794 | |||
1792 | memcpy(sdata->rc_rateidx_mcs_mask[i], | 1795 | memcpy(sdata->rc_rateidx_mcs_mask[i], |
1793 | sband->ht_cap.mcs.rx_mask, | 1796 | sband->ht_cap.mcs.rx_mask, |
1794 | sizeof(sdata->rc_rateidx_mcs_mask[i])); | 1797 | sizeof(sdata->rc_rateidx_mcs_mask[i])); |
1795 | else | 1798 | |
1799 | cap = sband->vht_cap.vht_mcs.rx_mcs_map; | ||
1800 | vht_rate_mask = sdata->rc_rateidx_vht_mcs_mask[i]; | ||
1801 | ieee80211_get_vht_mask_from_cap(cap, vht_rate_mask); | ||
1802 | } else { | ||
1796 | memset(sdata->rc_rateidx_mcs_mask[i], 0, | 1803 | memset(sdata->rc_rateidx_mcs_mask[i], 0, |
1797 | sizeof(sdata->rc_rateidx_mcs_mask[i])); | 1804 | sizeof(sdata->rc_rateidx_mcs_mask[i])); |
1805 | memset(sdata->rc_rateidx_vht_mcs_mask[i], 0, | ||
1806 | sizeof(sdata->rc_rateidx_vht_mcs_mask[i])); | ||
1807 | } | ||
1798 | } | 1808 | } |
1799 | 1809 | ||
1800 | ieee80211_set_default_queues(sdata); | 1810 | ieee80211_set_default_queues(sdata); |
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 7e71de98297c..9857693b91ec 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c | |||
@@ -414,16 +414,77 @@ static bool rate_idx_match_mcs_mask(s8 *rate_idx, u8 *mcs_mask) | |||
414 | return false; | 414 | return false; |
415 | } | 415 | } |
416 | 416 | ||
417 | static bool rate_idx_match_vht_mcs_mask(s8 *rate_idx, u16 *vht_mask) | ||
418 | { | ||
419 | int i, j; | ||
420 | int ridx, rbit; | ||
421 | |||
422 | ridx = *rate_idx >> 4; | ||
423 | rbit = *rate_idx & 0xf; | ||
424 | |||
425 | if (ridx < 0 || ridx >= NL80211_VHT_NSS_MAX) | ||
426 | return false; | ||
417 | 427 | ||
428 | /* See whether the selected rate or anything below it is allowed. */ | ||
429 | for (i = ridx; i >= 0; i--) { | ||
430 | for (j = rbit; j >= 0; j--) { | ||
431 | if (vht_mask[i] & BIT(j)) { | ||
432 | *rate_idx = (i << 4) | j; | ||
433 | return true; | ||
434 | } | ||
435 | } | ||
436 | rbit = 15; | ||
437 | } | ||
438 | |||
439 | /* Try to find a higher rate that would be allowed */ | ||
440 | ridx = (*rate_idx + 1) >> 4; | ||
441 | rbit = (*rate_idx + 1) & 0xf; | ||
442 | |||
443 | for (i = ridx; i < NL80211_VHT_NSS_MAX; i++) { | ||
444 | for (j = rbit; j < 16; j++) { | ||
445 | if (vht_mask[i] & BIT(j)) { | ||
446 | *rate_idx = (i << 4) | j; | ||
447 | return true; | ||
448 | } | ||
449 | } | ||
450 | rbit = 0; | ||
451 | } | ||
452 | return false; | ||
453 | } | ||
418 | 454 | ||
419 | static void rate_idx_match_mask(s8 *rate_idx, u16 *rate_flags, | 455 | static void rate_idx_match_mask(s8 *rate_idx, u16 *rate_flags, |
420 | struct ieee80211_supported_band *sband, | 456 | struct ieee80211_supported_band *sband, |
421 | enum nl80211_chan_width chan_width, | 457 | enum nl80211_chan_width chan_width, |
422 | u32 mask, | 458 | u32 mask, |
423 | u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN]) | 459 | u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN], |
460 | u16 vht_mask[NL80211_VHT_NSS_MAX]) | ||
424 | { | 461 | { |
425 | /* handle HT rates */ | 462 | if (*rate_flags & IEEE80211_TX_RC_VHT_MCS) { |
426 | if (*rate_flags & IEEE80211_TX_RC_MCS) { | 463 | /* handle VHT rates */ |
464 | if (rate_idx_match_vht_mcs_mask(rate_idx, vht_mask)) | ||
465 | return; | ||
466 | |||
467 | *rate_idx = 0; | ||
468 | /* keep protection flags */ | ||
469 | *rate_flags &= (IEEE80211_TX_RC_USE_RTS_CTS | | ||
470 | IEEE80211_TX_RC_USE_CTS_PROTECT | | ||
471 | IEEE80211_TX_RC_USE_SHORT_PREAMBLE); | ||
472 | |||
473 | *rate_flags |= IEEE80211_TX_RC_MCS; | ||
474 | if (chan_width == NL80211_CHAN_WIDTH_40) | ||
475 | *rate_flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | ||
476 | |||
477 | if (rate_idx_match_mcs_mask(rate_idx, mcs_mask)) | ||
478 | return; | ||
479 | |||
480 | /* also try the legacy rates. */ | ||
481 | *rate_flags &= ~(IEEE80211_TX_RC_MCS | | ||
482 | IEEE80211_TX_RC_40_MHZ_WIDTH); | ||
483 | if (rate_idx_match_legacy_mask(rate_idx, sband->n_bitrates, | ||
484 | mask)) | ||
485 | return; | ||
486 | } else if (*rate_flags & IEEE80211_TX_RC_MCS) { | ||
487 | /* handle HT rates */ | ||
427 | if (rate_idx_match_mcs_mask(rate_idx, mcs_mask)) | 488 | if (rate_idx_match_mcs_mask(rate_idx, mcs_mask)) |
428 | return; | 489 | return; |
429 | 490 | ||
@@ -436,7 +497,7 @@ static void rate_idx_match_mask(s8 *rate_idx, u16 *rate_flags, | |||
436 | if (rate_idx_match_legacy_mask(rate_idx, sband->n_bitrates, | 497 | if (rate_idx_match_legacy_mask(rate_idx, sband->n_bitrates, |
437 | mask)) | 498 | mask)) |
438 | return; | 499 | return; |
439 | } else if (!(*rate_flags & IEEE80211_TX_RC_VHT_MCS)) { | 500 | } else { |
440 | /* handle legacy rates */ | 501 | /* handle legacy rates */ |
441 | if (rate_idx_match_legacy_mask(rate_idx, sband->n_bitrates, | 502 | if (rate_idx_match_legacy_mask(rate_idx, sband->n_bitrates, |
442 | mask)) | 503 | mask)) |
@@ -620,7 +681,8 @@ static void rate_control_fill_sta_table(struct ieee80211_sta *sta, | |||
620 | static bool rate_control_cap_mask(struct ieee80211_sub_if_data *sdata, | 681 | static bool rate_control_cap_mask(struct ieee80211_sub_if_data *sdata, |
621 | struct ieee80211_supported_band *sband, | 682 | struct ieee80211_supported_band *sband, |
622 | struct ieee80211_sta *sta, u32 *mask, | 683 | struct ieee80211_sta *sta, u32 *mask, |
623 | u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN]) | 684 | u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN], |
685 | u16 vht_mask[NL80211_VHT_NSS_MAX]) | ||
624 | { | 686 | { |
625 | u32 i, flags; | 687 | u32 i, flags; |
626 | 688 | ||
@@ -632,7 +694,8 @@ static bool rate_control_cap_mask(struct ieee80211_sub_if_data *sdata, | |||
632 | } | 694 | } |
633 | 695 | ||
634 | if (*mask == (1 << sband->n_bitrates) - 1 && | 696 | if (*mask == (1 << sband->n_bitrates) - 1 && |
635 | !sdata->rc_has_mcs_mask[sband->band]) | 697 | !sdata->rc_has_mcs_mask[sband->band] && |
698 | !sdata->rc_has_vht_mcs_mask[sband->band]) | ||
636 | return false; | 699 | return false; |
637 | 700 | ||
638 | if (sdata->rc_has_mcs_mask[sband->band]) | 701 | if (sdata->rc_has_mcs_mask[sband->band]) |
@@ -641,11 +704,25 @@ static bool rate_control_cap_mask(struct ieee80211_sub_if_data *sdata, | |||
641 | else | 704 | else |
642 | memset(mcs_mask, 0xff, IEEE80211_HT_MCS_MASK_LEN); | 705 | memset(mcs_mask, 0xff, IEEE80211_HT_MCS_MASK_LEN); |
643 | 706 | ||
707 | if (sdata->rc_has_vht_mcs_mask[sband->band]) | ||
708 | memcpy(vht_mask, sdata->rc_rateidx_vht_mcs_mask[sband->band], | ||
709 | sizeof(u16) * NL80211_VHT_NSS_MAX); | ||
710 | else | ||
711 | memset(vht_mask, 0xff, sizeof(u16) * NL80211_VHT_NSS_MAX); | ||
712 | |||
644 | if (sta) { | 713 | if (sta) { |
714 | __le16 sta_vht_cap; | ||
715 | u16 sta_vht_mask[NL80211_VHT_NSS_MAX]; | ||
716 | |||
645 | /* Filter out rates that the STA does not support */ | 717 | /* Filter out rates that the STA does not support */ |
646 | *mask &= sta->supp_rates[sband->band]; | 718 | *mask &= sta->supp_rates[sband->band]; |
647 | for (i = 0; i < sizeof(mcs_mask); i++) | 719 | for (i = 0; i < sizeof(mcs_mask); i++) |
648 | mcs_mask[i] &= sta->ht_cap.mcs.rx_mask[i]; | 720 | mcs_mask[i] &= sta->ht_cap.mcs.rx_mask[i]; |
721 | |||
722 | sta_vht_cap = sta->vht_cap.vht_mcs.rx_mcs_map; | ||
723 | ieee80211_get_vht_mask_from_cap(sta_vht_cap, sta_vht_mask); | ||
724 | for (i = 0; i < NL80211_VHT_NSS_MAX; i++) | ||
725 | vht_mask[i] &= sta_vht_mask[i]; | ||
649 | } | 726 | } |
650 | 727 | ||
651 | return true; | 728 | return true; |
@@ -659,10 +736,11 @@ rate_control_apply_mask_ratetbl(struct sta_info *sta, | |||
659 | int i; | 736 | int i; |
660 | u32 mask; | 737 | u32 mask; |
661 | u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN]; | 738 | u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN]; |
739 | u16 vht_mask[NL80211_VHT_NSS_MAX]; | ||
662 | enum nl80211_chan_width chan_width; | 740 | enum nl80211_chan_width chan_width; |
663 | 741 | ||
664 | if (!rate_control_cap_mask(sta->sdata, sband, &sta->sta, &mask, | 742 | if (!rate_control_cap_mask(sta->sdata, sband, &sta->sta, &mask, |
665 | mcs_mask)) | 743 | mcs_mask, vht_mask)) |
666 | return; | 744 | return; |
667 | 745 | ||
668 | chan_width = sta->sdata->vif.bss_conf.chandef.width; | 746 | chan_width = sta->sdata->vif.bss_conf.chandef.width; |
@@ -671,7 +749,8 @@ rate_control_apply_mask_ratetbl(struct sta_info *sta, | |||
671 | break; | 749 | break; |
672 | 750 | ||
673 | rate_idx_match_mask(&rates->rate[i].idx, &rates->rate[i].flags, | 751 | rate_idx_match_mask(&rates->rate[i].idx, &rates->rate[i].flags, |
674 | sband, chan_width, mask, mcs_mask); | 752 | sband, chan_width, mask, mcs_mask, |
753 | vht_mask); | ||
675 | } | 754 | } |
676 | } | 755 | } |
677 | 756 | ||
@@ -684,7 +763,7 @@ static void rate_control_apply_mask(struct ieee80211_sub_if_data *sdata, | |||
684 | enum nl80211_chan_width chan_width; | 763 | enum nl80211_chan_width chan_width; |
685 | u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN]; | 764 | u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN]; |
686 | u32 mask; | 765 | u32 mask; |
687 | u16 rate_flags; | 766 | u16 rate_flags, vht_mask[NL80211_VHT_NSS_MAX]; |
688 | int i; | 767 | int i; |
689 | 768 | ||
690 | /* | 769 | /* |
@@ -692,7 +771,8 @@ static void rate_control_apply_mask(struct ieee80211_sub_if_data *sdata, | |||
692 | * default mask (allow all rates) is used to save some processing for | 771 | * default mask (allow all rates) is used to save some processing for |
693 | * the common case. | 772 | * the common case. |
694 | */ | 773 | */ |
695 | if (!rate_control_cap_mask(sdata, sband, sta, &mask, mcs_mask)) | 774 | if (!rate_control_cap_mask(sdata, sband, sta, &mask, mcs_mask, |
775 | vht_mask)) | ||
696 | return; | 776 | return; |
697 | 777 | ||
698 | /* | 778 | /* |
@@ -708,7 +788,7 @@ static void rate_control_apply_mask(struct ieee80211_sub_if_data *sdata, | |||
708 | 788 | ||
709 | rate_flags = rates[i].flags; | 789 | rate_flags = rates[i].flags; |
710 | rate_idx_match_mask(&rates[i].idx, &rate_flags, sband, | 790 | rate_idx_match_mask(&rates[i].idx, &rate_flags, sband, |
711 | chan_width, mask, mcs_mask); | 791 | chan_width, mask, mcs_mask, vht_mask); |
712 | rates[i].flags = rate_flags; | 792 | rates[i].flags = rate_flags; |
713 | } | 793 | } |
714 | } | 794 | } |
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index f05808d0d80f..834ccdbc74be 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c | |||
@@ -426,3 +426,29 @@ void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, | |||
426 | if (changed > 0) | 426 | if (changed > 0) |
427 | rate_control_rate_update(local, sband, sta, changed); | 427 | rate_control_rate_update(local, sband, sta, changed); |
428 | } | 428 | } |
429 | |||
430 | void ieee80211_get_vht_mask_from_cap(__le16 vht_cap, | ||
431 | u16 vht_mask[NL80211_VHT_NSS_MAX]) | ||
432 | { | ||
433 | int i; | ||
434 | u16 mask, cap = le16_to_cpu(vht_cap); | ||
435 | |||
436 | for (i = 0; i < NL80211_VHT_NSS_MAX; i++) { | ||
437 | mask = (cap >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
438 | switch (mask) { | ||
439 | case IEEE80211_VHT_MCS_SUPPORT_0_7: | ||
440 | vht_mask[i] = 0x00FF; | ||
441 | break; | ||
442 | case IEEE80211_VHT_MCS_SUPPORT_0_8: | ||
443 | vht_mask[i] = 0x01FF; | ||
444 | break; | ||
445 | case IEEE80211_VHT_MCS_SUPPORT_0_9: | ||
446 | vht_mask[i] = 0x03FF; | ||
447 | break; | ||
448 | case IEEE80211_VHT_MCS_NOT_SUPPORTED: | ||
449 | default: | ||
450 | vht_mask[i] = 0; | ||
451 | break; | ||
452 | } | ||
453 | } | ||
454 | } | ||