diff options
Diffstat (limited to 'net/wireless/util.c')
-rw-r--r-- | net/wireless/util.c | 197 |
1 files changed, 186 insertions, 11 deletions
diff --git a/net/wireless/util.c b/net/wireless/util.c index 2762e8329986..16d76a807c2f 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -11,6 +11,8 @@ | |||
11 | #include <net/ip.h> | 11 | #include <net/ip.h> |
12 | #include <net/dsfield.h> | 12 | #include <net/dsfield.h> |
13 | #include "core.h" | 13 | #include "core.h" |
14 | #include "rdev-ops.h" | ||
15 | |||
14 | 16 | ||
15 | struct ieee80211_rate * | 17 | struct ieee80211_rate * |
16 | ieee80211_get_response_rate(struct ieee80211_supported_band *sband, | 18 | ieee80211_get_response_rate(struct ieee80211_supported_band *sband, |
@@ -686,10 +688,13 @@ EXPORT_SYMBOL(cfg80211_classify8021d); | |||
686 | 688 | ||
687 | const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie) | 689 | const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie) |
688 | { | 690 | { |
689 | if (bss->information_elements == NULL) | 691 | const struct cfg80211_bss_ies *ies; |
692 | |||
693 | ies = rcu_dereference(bss->ies); | ||
694 | if (!ies) | ||
690 | return NULL; | 695 | return NULL; |
691 | return cfg80211_find_ie(ie, bss->information_elements, | 696 | |
692 | bss->len_information_elements); | 697 | return cfg80211_find_ie(ie, ies->data, ies->len); |
693 | } | 698 | } |
694 | EXPORT_SYMBOL(ieee80211_bss_get_ie); | 699 | EXPORT_SYMBOL(ieee80211_bss_get_ie); |
695 | 700 | ||
@@ -705,19 +710,18 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev) | |||
705 | for (i = 0; i < 6; i++) { | 710 | for (i = 0; i < 6; i++) { |
706 | if (!wdev->connect_keys->params[i].cipher) | 711 | if (!wdev->connect_keys->params[i].cipher) |
707 | continue; | 712 | continue; |
708 | if (rdev->ops->add_key(wdev->wiphy, dev, i, false, NULL, | 713 | if (rdev_add_key(rdev, dev, i, false, NULL, |
709 | &wdev->connect_keys->params[i])) { | 714 | &wdev->connect_keys->params[i])) { |
710 | netdev_err(dev, "failed to set key %d\n", i); | 715 | netdev_err(dev, "failed to set key %d\n", i); |
711 | continue; | 716 | continue; |
712 | } | 717 | } |
713 | if (wdev->connect_keys->def == i) | 718 | if (wdev->connect_keys->def == i) |
714 | if (rdev->ops->set_default_key(wdev->wiphy, dev, | 719 | if (rdev_set_default_key(rdev, dev, i, true, true)) { |
715 | i, true, true)) { | ||
716 | netdev_err(dev, "failed to set defkey %d\n", i); | 720 | netdev_err(dev, "failed to set defkey %d\n", i); |
717 | continue; | 721 | continue; |
718 | } | 722 | } |
719 | if (wdev->connect_keys->defmgmt == i) | 723 | if (wdev->connect_keys->defmgmt == i) |
720 | if (rdev->ops->set_default_mgmt_key(wdev->wiphy, dev, i)) | 724 | if (rdev_set_default_mgmt_key(rdev, dev, i)) |
721 | netdev_err(dev, "failed to set mgtdef %d\n", i); | 725 | netdev_err(dev, "failed to set mgtdef %d\n", i); |
722 | } | 726 | } |
723 | 727 | ||
@@ -850,8 +854,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
850 | cfg80211_process_rdev_events(rdev); | 854 | cfg80211_process_rdev_events(rdev); |
851 | } | 855 | } |
852 | 856 | ||
853 | err = rdev->ops->change_virtual_intf(&rdev->wiphy, dev, | 857 | err = rdev_change_virtual_intf(rdev, dev, ntype, flags, params); |
854 | ntype, flags, params); | ||
855 | 858 | ||
856 | WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype); | 859 | WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype); |
857 | 860 | ||
@@ -944,14 +947,86 @@ static u32 cfg80211_calculate_bitrate_60g(struct rate_info *rate) | |||
944 | return __mcs2bitrate[rate->mcs]; | 947 | return __mcs2bitrate[rate->mcs]; |
945 | } | 948 | } |
946 | 949 | ||
950 | static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate) | ||
951 | { | ||
952 | static const u32 base[4][10] = { | ||
953 | { 6500000, | ||
954 | 13000000, | ||
955 | 19500000, | ||
956 | 26000000, | ||
957 | 39000000, | ||
958 | 52000000, | ||
959 | 58500000, | ||
960 | 65000000, | ||
961 | 78000000, | ||
962 | 0, | ||
963 | }, | ||
964 | { 13500000, | ||
965 | 27000000, | ||
966 | 40500000, | ||
967 | 54000000, | ||
968 | 81000000, | ||
969 | 108000000, | ||
970 | 121500000, | ||
971 | 135000000, | ||
972 | 162000000, | ||
973 | 180000000, | ||
974 | }, | ||
975 | { 29300000, | ||
976 | 58500000, | ||
977 | 87800000, | ||
978 | 117000000, | ||
979 | 175500000, | ||
980 | 234000000, | ||
981 | 263300000, | ||
982 | 292500000, | ||
983 | 351000000, | ||
984 | 390000000, | ||
985 | }, | ||
986 | { 58500000, | ||
987 | 117000000, | ||
988 | 175500000, | ||
989 | 234000000, | ||
990 | 351000000, | ||
991 | 468000000, | ||
992 | 526500000, | ||
993 | 585000000, | ||
994 | 702000000, | ||
995 | 780000000, | ||
996 | }, | ||
997 | }; | ||
998 | u32 bitrate; | ||
999 | int idx; | ||
1000 | |||
1001 | if (WARN_ON_ONCE(rate->mcs > 9)) | ||
1002 | return 0; | ||
1003 | |||
1004 | idx = rate->flags & (RATE_INFO_FLAGS_160_MHZ_WIDTH | | ||
1005 | RATE_INFO_FLAGS_80P80_MHZ_WIDTH) ? 3 : | ||
1006 | rate->flags & RATE_INFO_FLAGS_80_MHZ_WIDTH ? 2 : | ||
1007 | rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH ? 1 : 0; | ||
1008 | |||
1009 | bitrate = base[idx][rate->mcs]; | ||
1010 | bitrate *= rate->nss; | ||
1011 | |||
1012 | if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) | ||
1013 | bitrate = (bitrate / 9) * 10; | ||
1014 | |||
1015 | /* do NOT round down here */ | ||
1016 | return (bitrate + 50000) / 100000; | ||
1017 | } | ||
1018 | |||
947 | u32 cfg80211_calculate_bitrate(struct rate_info *rate) | 1019 | u32 cfg80211_calculate_bitrate(struct rate_info *rate) |
948 | { | 1020 | { |
949 | int modulation, streams, bitrate; | 1021 | int modulation, streams, bitrate; |
950 | 1022 | ||
951 | if (!(rate->flags & RATE_INFO_FLAGS_MCS)) | 1023 | if (!(rate->flags & RATE_INFO_FLAGS_MCS) && |
1024 | !(rate->flags & RATE_INFO_FLAGS_VHT_MCS)) | ||
952 | return rate->legacy; | 1025 | return rate->legacy; |
953 | if (rate->flags & RATE_INFO_FLAGS_60G) | 1026 | if (rate->flags & RATE_INFO_FLAGS_60G) |
954 | return cfg80211_calculate_bitrate_60g(rate); | 1027 | return cfg80211_calculate_bitrate_60g(rate); |
1028 | if (rate->flags & RATE_INFO_FLAGS_VHT_MCS) | ||
1029 | return cfg80211_calculate_bitrate_vht(rate); | ||
955 | 1030 | ||
956 | /* the formula below does only work for MCS values smaller than 32 */ | 1031 | /* the formula below does only work for MCS values smaller than 32 */ |
957 | if (WARN_ON_ONCE(rate->mcs >= 32)) | 1032 | if (WARN_ON_ONCE(rate->mcs >= 32)) |
@@ -980,6 +1055,106 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate) | |||
980 | } | 1055 | } |
981 | EXPORT_SYMBOL(cfg80211_calculate_bitrate); | 1056 | EXPORT_SYMBOL(cfg80211_calculate_bitrate); |
982 | 1057 | ||
1058 | int cfg80211_get_p2p_attr(const u8 *ies, unsigned int len, | ||
1059 | enum ieee80211_p2p_attr_id attr, | ||
1060 | u8 *buf, unsigned int bufsize) | ||
1061 | { | ||
1062 | u8 *out = buf; | ||
1063 | u16 attr_remaining = 0; | ||
1064 | bool desired_attr = false; | ||
1065 | u16 desired_len = 0; | ||
1066 | |||
1067 | while (len > 0) { | ||
1068 | unsigned int iedatalen; | ||
1069 | unsigned int copy; | ||
1070 | const u8 *iedata; | ||
1071 | |||
1072 | if (len < 2) | ||
1073 | return -EILSEQ; | ||
1074 | iedatalen = ies[1]; | ||
1075 | if (iedatalen + 2 > len) | ||
1076 | return -EILSEQ; | ||
1077 | |||
1078 | if (ies[0] != WLAN_EID_VENDOR_SPECIFIC) | ||
1079 | goto cont; | ||
1080 | |||
1081 | if (iedatalen < 4) | ||
1082 | goto cont; | ||
1083 | |||
1084 | iedata = ies + 2; | ||
1085 | |||
1086 | /* check WFA OUI, P2P subtype */ | ||
1087 | if (iedata[0] != 0x50 || iedata[1] != 0x6f || | ||
1088 | iedata[2] != 0x9a || iedata[3] != 0x09) | ||
1089 | goto cont; | ||
1090 | |||
1091 | iedatalen -= 4; | ||
1092 | iedata += 4; | ||
1093 | |||
1094 | /* check attribute continuation into this IE */ | ||
1095 | copy = min_t(unsigned int, attr_remaining, iedatalen); | ||
1096 | if (copy && desired_attr) { | ||
1097 | desired_len += copy; | ||
1098 | if (out) { | ||
1099 | memcpy(out, iedata, min(bufsize, copy)); | ||
1100 | out += min(bufsize, copy); | ||
1101 | bufsize -= min(bufsize, copy); | ||
1102 | } | ||
1103 | |||
1104 | |||
1105 | if (copy == attr_remaining) | ||
1106 | return desired_len; | ||
1107 | } | ||
1108 | |||
1109 | attr_remaining -= copy; | ||
1110 | if (attr_remaining) | ||
1111 | goto cont; | ||
1112 | |||
1113 | iedatalen -= copy; | ||
1114 | iedata += copy; | ||
1115 | |||
1116 | while (iedatalen > 0) { | ||
1117 | u16 attr_len; | ||
1118 | |||
1119 | /* P2P attribute ID & size must fit */ | ||
1120 | if (iedatalen < 3) | ||
1121 | return -EILSEQ; | ||
1122 | desired_attr = iedata[0] == attr; | ||
1123 | attr_len = get_unaligned_le16(iedata + 1); | ||
1124 | iedatalen -= 3; | ||
1125 | iedata += 3; | ||
1126 | |||
1127 | copy = min_t(unsigned int, attr_len, iedatalen); | ||
1128 | |||
1129 | if (desired_attr) { | ||
1130 | desired_len += copy; | ||
1131 | if (out) { | ||
1132 | memcpy(out, iedata, min(bufsize, copy)); | ||
1133 | out += min(bufsize, copy); | ||
1134 | bufsize -= min(bufsize, copy); | ||
1135 | } | ||
1136 | |||
1137 | if (copy == attr_len) | ||
1138 | return desired_len; | ||
1139 | } | ||
1140 | |||
1141 | iedata += copy; | ||
1142 | iedatalen -= copy; | ||
1143 | attr_remaining = attr_len - copy; | ||
1144 | } | ||
1145 | |||
1146 | cont: | ||
1147 | len -= ies[1] + 2; | ||
1148 | ies += ies[1] + 2; | ||
1149 | } | ||
1150 | |||
1151 | if (attr_remaining && desired_attr) | ||
1152 | return -EILSEQ; | ||
1153 | |||
1154 | return -ENOENT; | ||
1155 | } | ||
1156 | EXPORT_SYMBOL(cfg80211_get_p2p_attr); | ||
1157 | |||
983 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | 1158 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, |
984 | u32 beacon_int) | 1159 | u32 beacon_int) |
985 | { | 1160 | { |