diff options
Diffstat (limited to 'net/mac80211/util.c')
-rw-r--r-- | net/mac80211/util.c | 134 |
1 files changed, 114 insertions, 20 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 5ffe9e831b66..1fdb80ff9241 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -881,30 +881,66 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
881 | enum ieee80211_band band) | 881 | enum ieee80211_band band) |
882 | { | 882 | { |
883 | struct ieee80211_supported_band *sband; | 883 | struct ieee80211_supported_band *sband; |
884 | u8 *pos, *supp_rates_len, *esupp_rates_len = NULL; | 884 | u8 *pos; |
885 | int i; | 885 | size_t offset = 0, noffset; |
886 | int supp_rates_len, i; | ||
886 | 887 | ||
887 | sband = local->hw.wiphy->bands[band]; | 888 | sband = local->hw.wiphy->bands[band]; |
888 | 889 | ||
889 | pos = buffer; | 890 | pos = buffer; |
890 | 891 | ||
892 | supp_rates_len = min_t(int, sband->n_bitrates, 8); | ||
893 | |||
891 | *pos++ = WLAN_EID_SUPP_RATES; | 894 | *pos++ = WLAN_EID_SUPP_RATES; |
892 | supp_rates_len = pos; | 895 | *pos++ = supp_rates_len; |
893 | *pos++ = 0; | ||
894 | |||
895 | for (i = 0; i < sband->n_bitrates; i++) { | ||
896 | struct ieee80211_rate *rate = &sband->bitrates[i]; | ||
897 | |||
898 | if (esupp_rates_len) { | ||
899 | *esupp_rates_len += 1; | ||
900 | } else if (*supp_rates_len == 8) { | ||
901 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | ||
902 | esupp_rates_len = pos; | ||
903 | *pos++ = 1; | ||
904 | } else | ||
905 | *supp_rates_len += 1; | ||
906 | 896 | ||
907 | *pos++ = rate->bitrate / 5; | 897 | for (i = 0; i < supp_rates_len; i++) { |
898 | int rate = sband->bitrates[i].bitrate; | ||
899 | *pos++ = (u8) (rate / 5); | ||
900 | } | ||
901 | |||
902 | /* insert "request information" if in custom IEs */ | ||
903 | if (ie && ie_len) { | ||
904 | static const u8 before_extrates[] = { | ||
905 | WLAN_EID_SSID, | ||
906 | WLAN_EID_SUPP_RATES, | ||
907 | WLAN_EID_REQUEST, | ||
908 | }; | ||
909 | noffset = ieee80211_ie_split(ie, ie_len, | ||
910 | before_extrates, | ||
911 | ARRAY_SIZE(before_extrates), | ||
912 | offset); | ||
913 | memcpy(pos, ie + offset, noffset - offset); | ||
914 | pos += noffset - offset; | ||
915 | offset = noffset; | ||
916 | } | ||
917 | |||
918 | if (sband->n_bitrates > i) { | ||
919 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | ||
920 | *pos++ = sband->n_bitrates - i; | ||
921 | |||
922 | for (; i < sband->n_bitrates; i++) { | ||
923 | int rate = sband->bitrates[i].bitrate; | ||
924 | *pos++ = (u8) (rate / 5); | ||
925 | } | ||
926 | } | ||
927 | |||
928 | /* insert custom IEs that go before HT */ | ||
929 | if (ie && ie_len) { | ||
930 | static const u8 before_ht[] = { | ||
931 | WLAN_EID_SSID, | ||
932 | WLAN_EID_SUPP_RATES, | ||
933 | WLAN_EID_REQUEST, | ||
934 | WLAN_EID_EXT_SUPP_RATES, | ||
935 | WLAN_EID_DS_PARAMS, | ||
936 | WLAN_EID_SUPPORTED_REGULATORY_CLASSES, | ||
937 | }; | ||
938 | noffset = ieee80211_ie_split(ie, ie_len, | ||
939 | before_ht, ARRAY_SIZE(before_ht), | ||
940 | offset); | ||
941 | memcpy(pos, ie + offset, noffset - offset); | ||
942 | pos += noffset - offset; | ||
943 | offset = noffset; | ||
908 | } | 944 | } |
909 | 945 | ||
910 | if (sband->ht_cap.ht_supported) { | 946 | if (sband->ht_cap.ht_supported) { |
@@ -936,9 +972,11 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
936 | * that calculates local->scan_ies_len. | 972 | * that calculates local->scan_ies_len. |
937 | */ | 973 | */ |
938 | 974 | ||
939 | if (ie) { | 975 | /* add any remaining custom IEs */ |
940 | memcpy(pos, ie, ie_len); | 976 | if (ie && ie_len) { |
941 | pos += ie_len; | 977 | noffset = ie_len; |
978 | memcpy(pos, ie + offset, noffset - offset); | ||
979 | pos += noffset - offset; | ||
942 | } | 980 | } |
943 | 981 | ||
944 | return pos - buffer; | 982 | return pos - buffer; |
@@ -1252,3 +1290,59 @@ void ieee80211_recalc_smps(struct ieee80211_local *local, | |||
1252 | /* changed flag is auto-detected for this */ | 1290 | /* changed flag is auto-detected for this */ |
1253 | ieee80211_hw_config(local, 0); | 1291 | ieee80211_hw_config(local, 0); |
1254 | } | 1292 | } |
1293 | |||
1294 | static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) | ||
1295 | { | ||
1296 | int i; | ||
1297 | |||
1298 | for (i = 0; i < n_ids; i++) | ||
1299 | if (ids[i] == id) | ||
1300 | return true; | ||
1301 | return false; | ||
1302 | } | ||
1303 | |||
1304 | /** | ||
1305 | * ieee80211_ie_split - split an IE buffer according to ordering | ||
1306 | * | ||
1307 | * @ies: the IE buffer | ||
1308 | * @ielen: the length of the IE buffer | ||
1309 | * @ids: an array with element IDs that are allowed before | ||
1310 | * the split | ||
1311 | * @n_ids: the size of the element ID array | ||
1312 | * @offset: offset where to start splitting in the buffer | ||
1313 | * | ||
1314 | * This function splits an IE buffer by updating the @offset | ||
1315 | * variable to point to the location where the buffer should be | ||
1316 | * split. | ||
1317 | * | ||
1318 | * It assumes that the given IE buffer is well-formed, this | ||
1319 | * has to be guaranteed by the caller! | ||
1320 | * | ||
1321 | * It also assumes that the IEs in the buffer are ordered | ||
1322 | * correctly, if not the result of using this function will not | ||
1323 | * be ordered correctly either, i.e. it does no reordering. | ||
1324 | * | ||
1325 | * The function returns the offset where the next part of the | ||
1326 | * buffer starts, which may be @ielen if the entire (remainder) | ||
1327 | * of the buffer should be used. | ||
1328 | */ | ||
1329 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, | ||
1330 | const u8 *ids, int n_ids, size_t offset) | ||
1331 | { | ||
1332 | size_t pos = offset; | ||
1333 | |||
1334 | while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos])) | ||
1335 | pos += 2 + ies[pos + 1]; | ||
1336 | |||
1337 | return pos; | ||
1338 | } | ||
1339 | |||
1340 | size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset) | ||
1341 | { | ||
1342 | size_t pos = offset; | ||
1343 | |||
1344 | while (pos < ielen && ies[pos] != WLAN_EID_VENDOR_SPECIFIC) | ||
1345 | pos += 2 + ies[pos + 1]; | ||
1346 | |||
1347 | return pos; | ||
1348 | } | ||