aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/cfg80211.h24
-rw-r--r--include/uapi/linux/nl80211.h12
-rw-r--r--net/wireless/nl80211.c58
-rw-r--r--net/wireless/util.c74
4 files changed, 144 insertions, 24 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 977da58fb7e..e78db2cf3d1 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -662,16 +662,24 @@ enum station_info_flags {
662 * Used by the driver to indicate the specific rate transmission 662 * Used by the driver to indicate the specific rate transmission
663 * type for 802.11n transmissions. 663 * type for 802.11n transmissions.
664 * 664 *
665 * @RATE_INFO_FLAGS_MCS: @tx_bitrate_mcs filled 665 * @RATE_INFO_FLAGS_MCS: mcs field filled with HT MCS
666 * @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 Mhz width transmission 666 * @RATE_INFO_FLAGS_VHT_MCS: mcs field filled with VHT MCS
667 * @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 MHz width transmission
668 * @RATE_INFO_FLAGS_80_MHZ_WIDTH: 80 MHz width transmission
669 * @RATE_INFO_FLAGS_80P80_MHZ_WIDTH: 80+80 MHz width transmission
670 * @RATE_INFO_FLAGS_160_MHZ_WIDTH: 160 MHz width transmission
667 * @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval 671 * @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval
668 * @RATE_INFO_FLAGS_60G: 60gHz MCS 672 * @RATE_INFO_FLAGS_60G: 60GHz MCS
669 */ 673 */
670enum rate_info_flags { 674enum rate_info_flags {
671 RATE_INFO_FLAGS_MCS = 1<<0, 675 RATE_INFO_FLAGS_MCS = BIT(0),
672 RATE_INFO_FLAGS_40_MHZ_WIDTH = 1<<1, 676 RATE_INFO_FLAGS_VHT_MCS = BIT(1),
673 RATE_INFO_FLAGS_SHORT_GI = 1<<2, 677 RATE_INFO_FLAGS_40_MHZ_WIDTH = BIT(2),
674 RATE_INFO_FLAGS_60G = 1<<3, 678 RATE_INFO_FLAGS_80_MHZ_WIDTH = BIT(3),
679 RATE_INFO_FLAGS_80P80_MHZ_WIDTH = BIT(4),
680 RATE_INFO_FLAGS_160_MHZ_WIDTH = BIT(5),
681 RATE_INFO_FLAGS_SHORT_GI = BIT(6),
682 RATE_INFO_FLAGS_60G = BIT(7),
675}; 683};
676 684
677/** 685/**
@@ -682,11 +690,13 @@ enum rate_info_flags {
682 * @flags: bitflag of flags from &enum rate_info_flags 690 * @flags: bitflag of flags from &enum rate_info_flags
683 * @mcs: mcs index if struct describes a 802.11n bitrate 691 * @mcs: mcs index if struct describes a 802.11n bitrate
684 * @legacy: bitrate in 100kbit/s for 802.11abg 692 * @legacy: bitrate in 100kbit/s for 802.11abg
693 * @nss: number of streams (VHT only)
685 */ 694 */
686struct rate_info { 695struct rate_info {
687 u8 flags; 696 u8 flags;
688 u8 mcs; 697 u8 mcs;
689 u16 legacy; 698 u16 legacy;
699 u8 nss;
690}; 700};
691 701
692/** 702/**
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 84f9c7d84c6..33a417481ad 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1734,10 +1734,15 @@ struct nl80211_sta_flag_update {
1734 * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved 1734 * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved
1735 * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s) 1735 * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s)
1736 * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8) 1736 * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8)
1737 * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate 1737 * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 MHz dualchannel bitrate
1738 * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval 1738 * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval
1739 * @NL80211_RATE_INFO_BITRATE32: total bitrate (u32, 100kbit/s) 1739 * @NL80211_RATE_INFO_BITRATE32: total bitrate (u32, 100kbit/s)
1740 * @NL80211_RATE_INFO_MAX: highest rate_info number currently defined 1740 * @NL80211_RATE_INFO_MAX: highest rate_info number currently defined
1741 * @NL80211_RATE_INFO_VHT_MCS: MCS index for VHT (u8)
1742 * @NL80211_RATE_INFO_VHT_NSS: number of streams in VHT (u8)
1743 * @NL80211_RATE_INFO_80_MHZ_WIDTH: 80 MHz VHT rate
1744 * @NL80211_RATE_INFO_80P80_MHZ_WIDTH: 80+80 MHz VHT rate
1745 * @NL80211_RATE_INFO_160_MHZ_WIDTH: 160 MHz VHT rate
1741 * @__NL80211_RATE_INFO_AFTER_LAST: internal use 1746 * @__NL80211_RATE_INFO_AFTER_LAST: internal use
1742 */ 1747 */
1743enum nl80211_rate_info { 1748enum nl80211_rate_info {
@@ -1747,6 +1752,11 @@ enum nl80211_rate_info {
1747 NL80211_RATE_INFO_40_MHZ_WIDTH, 1752 NL80211_RATE_INFO_40_MHZ_WIDTH,
1748 NL80211_RATE_INFO_SHORT_GI, 1753 NL80211_RATE_INFO_SHORT_GI,
1749 NL80211_RATE_INFO_BITRATE32, 1754 NL80211_RATE_INFO_BITRATE32,
1755 NL80211_RATE_INFO_VHT_MCS,
1756 NL80211_RATE_INFO_VHT_NSS,
1757 NL80211_RATE_INFO_80_MHZ_WIDTH,
1758 NL80211_RATE_INFO_80P80_MHZ_WIDTH,
1759 NL80211_RATE_INFO_160_MHZ_WIDTH,
1750 1760
1751 /* keep last */ 1761 /* keep last */
1752 __NL80211_RATE_INFO_AFTER_LAST, 1762 __NL80211_RATE_INFO_AFTER_LAST,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 15158a3d64a..d038fa45ecd 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2890,29 +2890,52 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
2890 2890
2891 rate = nla_nest_start(msg, attr); 2891 rate = nla_nest_start(msg, attr);
2892 if (!rate) 2892 if (!rate)
2893 goto nla_put_failure; 2893 return false;
2894 2894
2895 /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */ 2895 /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */
2896 bitrate = cfg80211_calculate_bitrate(info); 2896 bitrate = cfg80211_calculate_bitrate(info);
2897 /* report 16-bit bitrate only if we can */ 2897 /* report 16-bit bitrate only if we can */
2898 bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0; 2898 bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0;
2899 if ((bitrate > 0 && 2899 if (bitrate > 0 &&
2900 nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate)) || 2900 nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate))
2901 (bitrate_compat > 0 && 2901 return false;
2902 nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat)) || 2902 if (bitrate_compat > 0 &&
2903 ((info->flags & RATE_INFO_FLAGS_MCS) && 2903 nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat))
2904 nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs)) || 2904 return false;
2905 ((info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) && 2905
2906 nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH)) || 2906 if (info->flags & RATE_INFO_FLAGS_MCS) {
2907 ((info->flags & RATE_INFO_FLAGS_SHORT_GI) && 2907 if (nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs))
2908 nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))) 2908 return false;
2909 goto nla_put_failure; 2909 if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH &&
2910 nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH))
2911 return false;
2912 if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
2913 nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
2914 return false;
2915 } else if (info->flags & RATE_INFO_FLAGS_VHT_MCS) {
2916 if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_MCS, info->mcs))
2917 return false;
2918 if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_NSS, info->nss))
2919 return false;
2920 if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH &&
2921 nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH))
2922 return false;
2923 if (info->flags & RATE_INFO_FLAGS_80_MHZ_WIDTH &&
2924 nla_put_flag(msg, NL80211_RATE_INFO_80_MHZ_WIDTH))
2925 return false;
2926 if (info->flags & RATE_INFO_FLAGS_80P80_MHZ_WIDTH &&
2927 nla_put_flag(msg, NL80211_RATE_INFO_80P80_MHZ_WIDTH))
2928 return false;
2929 if (info->flags & RATE_INFO_FLAGS_160_MHZ_WIDTH &&
2930 nla_put_flag(msg, NL80211_RATE_INFO_160_MHZ_WIDTH))
2931 return false;
2932 if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
2933 nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
2934 return false;
2935 }
2910 2936
2911 nla_nest_end(msg, rate); 2937 nla_nest_end(msg, rate);
2912 return true; 2938 return true;
2913
2914nla_put_failure:
2915 return false;
2916} 2939}
2917 2940
2918static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq, 2941static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq,
@@ -5475,6 +5498,11 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
5475 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef)) 5498 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef))
5476 return -EINVAL; 5499 return -EINVAL;
5477 5500
5501 if (ibss.chandef.width > NL80211_CHAN_WIDTH_40)
5502 return -EINVAL;
5503 if (ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
5504 !(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
5505
5478 ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; 5506 ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
5479 ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; 5507 ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
5480 5508
diff --git a/net/wireless/util.c b/net/wireless/util.c
index db61fe8a6b6..3cce6e48621 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -944,14 +944,86 @@ static u32 cfg80211_calculate_bitrate_60g(struct rate_info *rate)
944 return __mcs2bitrate[rate->mcs]; 944 return __mcs2bitrate[rate->mcs];
945} 945}
946 946
947static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate)
948{
949 static const u32 base[4][10] = {
950 { 6500000,
951 13000000,
952 19500000,
953 26000000,
954 39000000,
955 52000000,
956 58500000,
957 65000000,
958 78000000,
959 0,
960 },
961 { 13500000,
962 27000000,
963 40500000,
964 54000000,
965 81000000,
966 108000000,
967 121500000,
968 135000000,
969 162000000,
970 180000000,
971 },
972 { 29300000,
973 58500000,
974 87800000,
975 117000000,
976 175500000,
977 234000000,
978 263300000,
979 292500000,
980 351000000,
981 390000000,
982 },
983 { 58500000,
984 117000000,
985 175500000,
986 234000000,
987 351000000,
988 468000000,
989 526500000,
990 585000000,
991 702000000,
992 780000000,
993 },
994 };
995 u32 bitrate;
996 int idx;
997
998 if (WARN_ON_ONCE(rate->mcs > 9))
999 return 0;
1000
1001 idx = rate->flags & (RATE_INFO_FLAGS_160_MHZ_WIDTH |
1002 RATE_INFO_FLAGS_80P80_MHZ_WIDTH) ? 3 :
1003 rate->flags & RATE_INFO_FLAGS_80_MHZ_WIDTH ? 2 :
1004 rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH ? 1 : 0;
1005
1006 bitrate = base[idx][rate->mcs];
1007 bitrate *= rate->nss;
1008
1009 if (rate->flags & RATE_INFO_FLAGS_SHORT_GI)
1010 bitrate = (bitrate / 9) * 10;
1011
1012 /* do NOT round down here */
1013 return (bitrate + 50000) / 100000;
1014}
1015
947u32 cfg80211_calculate_bitrate(struct rate_info *rate) 1016u32 cfg80211_calculate_bitrate(struct rate_info *rate)
948{ 1017{
949 int modulation, streams, bitrate; 1018 int modulation, streams, bitrate;
950 1019
951 if (!(rate->flags & RATE_INFO_FLAGS_MCS)) 1020 if (!(rate->flags & RATE_INFO_FLAGS_MCS) &&
1021 !(rate->flags & RATE_INFO_FLAGS_VHT_MCS))
952 return rate->legacy; 1022 return rate->legacy;
953 if (rate->flags & RATE_INFO_FLAGS_60G) 1023 if (rate->flags & RATE_INFO_FLAGS_60G)
954 return cfg80211_calculate_bitrate_60g(rate); 1024 return cfg80211_calculate_bitrate_60g(rate);
1025 if (rate->flags & RATE_INFO_FLAGS_VHT_MCS)
1026 return cfg80211_calculate_bitrate_vht(rate);
955 1027
956 /* the formula below does only work for MCS values smaller than 32 */ 1028 /* the formula below does only work for MCS values smaller than 32 */
957 if (WARN_ON_ONCE(rate->mcs >= 32)) 1029 if (WARN_ON_ONCE(rate->mcs >= 32))