diff options
-rw-r--r-- | include/net/cfg80211.h | 24 | ||||
-rw-r--r-- | include/uapi/linux/nl80211.h | 12 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 58 | ||||
-rw-r--r-- | net/wireless/util.c | 74 |
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 | */ |
670 | enum rate_info_flags { | 674 | enum 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 | */ |
686 | struct rate_info { | 695 | struct 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 | */ |
1743 | enum nl80211_rate_info { | 1748 | enum 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 | |||
2914 | nla_put_failure: | ||
2915 | return false; | ||
2916 | } | 2939 | } |
2917 | 2940 | ||
2918 | static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq, | 2941 | static 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 | ||
947 | static 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 | |||
947 | u32 cfg80211_calculate_bitrate(struct rate_info *rate) | 1016 | u32 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)) |