diff options
Diffstat (limited to 'net/mac80211/util.c')
-rw-r--r-- | net/mac80211/util.c | 163 |
1 files changed, 132 insertions, 31 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index b01972579c7c..7e38858a9280 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -468,7 +468,7 @@ void ieee80211_iterate_active_interfaces( | |||
468 | case NL80211_IFTYPE_MESH_POINT: | 468 | case NL80211_IFTYPE_MESH_POINT: |
469 | break; | 469 | break; |
470 | } | 470 | } |
471 | if (netif_running(sdata->dev)) | 471 | if (ieee80211_sdata_running(sdata)) |
472 | iterator(data, sdata->vif.addr, | 472 | iterator(data, sdata->vif.addr, |
473 | &sdata->vif); | 473 | &sdata->vif); |
474 | } | 474 | } |
@@ -502,7 +502,7 @@ void ieee80211_iterate_active_interfaces_atomic( | |||
502 | case NL80211_IFTYPE_MESH_POINT: | 502 | case NL80211_IFTYPE_MESH_POINT: |
503 | break; | 503 | break; |
504 | } | 504 | } |
505 | if (netif_running(sdata->dev)) | 505 | if (ieee80211_sdata_running(sdata)) |
506 | iterator(data, sdata->vif.addr, | 506 | iterator(data, sdata->vif.addr, |
507 | &sdata->vif); | 507 | &sdata->vif); |
508 | } | 508 | } |
@@ -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; | 896 | |
894 | 897 | for (i = 0; i < supp_rates_len; i++) { | |
895 | for (i = 0; i < sband->n_bitrates; i++) { | 898 | int rate = sband->bitrates[i].bitrate; |
896 | struct ieee80211_rate *rate = &sband->bitrates[i]; | 899 | *pos++ = (u8) (rate / 5); |
897 | 900 | } | |
898 | if (esupp_rates_len) { | 901 | |
899 | *esupp_rates_len += 1; | 902 | /* insert "request information" if in custom IEs */ |
900 | } else if (*supp_rates_len == 8) { | 903 | if (ie && ie_len) { |
901 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | 904 | static const u8 before_extrates[] = { |
902 | esupp_rates_len = pos; | 905 | WLAN_EID_SSID, |
903 | *pos++ = 1; | 906 | WLAN_EID_SUPP_RATES, |
904 | } else | 907 | WLAN_EID_REQUEST, |
905 | *supp_rates_len += 1; | 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 | } | ||
906 | 917 | ||
907 | *pos++ = rate->bitrate / 5; | 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; |
@@ -1037,7 +1075,6 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1037 | { | 1075 | { |
1038 | struct ieee80211_hw *hw = &local->hw; | 1076 | struct ieee80211_hw *hw = &local->hw; |
1039 | struct ieee80211_sub_if_data *sdata; | 1077 | struct ieee80211_sub_if_data *sdata; |
1040 | struct ieee80211_if_init_conf conf; | ||
1041 | struct sta_info *sta; | 1078 | struct sta_info *sta; |
1042 | unsigned long flags; | 1079 | unsigned long flags; |
1043 | int res; | 1080 | int res; |
@@ -1047,7 +1084,19 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1047 | 1084 | ||
1048 | /* restart hardware */ | 1085 | /* restart hardware */ |
1049 | if (local->open_count) { | 1086 | if (local->open_count) { |
1087 | /* | ||
1088 | * Upon resume hardware can sometimes be goofy due to | ||
1089 | * various platform / driver / bus issues, so restarting | ||
1090 | * the device may at times not work immediately. Propagate | ||
1091 | * the error. | ||
1092 | */ | ||
1050 | res = drv_start(local); | 1093 | res = drv_start(local); |
1094 | if (res) { | ||
1095 | WARN(local->suspended, "Harware became unavailable " | ||
1096 | "upon resume. This is could be a software issue" | ||
1097 | "prior to suspend or a harware issue\n"); | ||
1098 | return res; | ||
1099 | } | ||
1051 | 1100 | ||
1052 | ieee80211_led_radio(local, true); | 1101 | ieee80211_led_radio(local, true); |
1053 | } | 1102 | } |
@@ -1056,12 +1105,8 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1056 | list_for_each_entry(sdata, &local->interfaces, list) { | 1105 | list_for_each_entry(sdata, &local->interfaces, list) { |
1057 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && | 1106 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && |
1058 | sdata->vif.type != NL80211_IFTYPE_MONITOR && | 1107 | sdata->vif.type != NL80211_IFTYPE_MONITOR && |
1059 | netif_running(sdata->dev)) { | 1108 | ieee80211_sdata_running(sdata)) |
1060 | conf.vif = &sdata->vif; | 1109 | res = drv_add_interface(local, &sdata->vif); |
1061 | conf.type = sdata->vif.type; | ||
1062 | conf.mac_addr = sdata->vif.addr; | ||
1063 | res = drv_add_interface(local, &conf); | ||
1064 | } | ||
1065 | } | 1110 | } |
1066 | 1111 | ||
1067 | /* add STAs back */ | 1112 | /* add STAs back */ |
@@ -1103,7 +1148,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1103 | /* Finally also reconfigure all the BSS information */ | 1148 | /* Finally also reconfigure all the BSS information */ |
1104 | list_for_each_entry(sdata, &local->interfaces, list) { | 1149 | list_for_each_entry(sdata, &local->interfaces, list) { |
1105 | u32 changed = ~0; | 1150 | u32 changed = ~0; |
1106 | if (!netif_running(sdata->dev)) | 1151 | if (!ieee80211_sdata_running(sdata)) |
1107 | continue; | 1152 | continue; |
1108 | switch (sdata->vif.type) { | 1153 | switch (sdata->vif.type) { |
1109 | case NL80211_IFTYPE_STATION: | 1154 | case NL80211_IFTYPE_STATION: |
@@ -1131,7 +1176,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1131 | 1176 | ||
1132 | /* add back keys */ | 1177 | /* add back keys */ |
1133 | list_for_each_entry(sdata, &local->interfaces, list) | 1178 | list_for_each_entry(sdata, &local->interfaces, list) |
1134 | if (netif_running(sdata->dev)) | 1179 | if (ieee80211_sdata_running(sdata)) |
1135 | ieee80211_enable_keys(sdata); | 1180 | ieee80211_enable_keys(sdata); |
1136 | 1181 | ||
1137 | ieee80211_wake_queues_by_reason(hw, | 1182 | ieee80211_wake_queues_by_reason(hw, |
@@ -1252,3 +1297,59 @@ void ieee80211_recalc_smps(struct ieee80211_local *local, | |||
1252 | /* changed flag is auto-detected for this */ | 1297 | /* changed flag is auto-detected for this */ |
1253 | ieee80211_hw_config(local, 0); | 1298 | ieee80211_hw_config(local, 0); |
1254 | } | 1299 | } |
1300 | |||
1301 | static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) | ||
1302 | { | ||
1303 | int i; | ||
1304 | |||
1305 | for (i = 0; i < n_ids; i++) | ||
1306 | if (ids[i] == id) | ||
1307 | return true; | ||
1308 | return false; | ||
1309 | } | ||
1310 | |||
1311 | /** | ||
1312 | * ieee80211_ie_split - split an IE buffer according to ordering | ||
1313 | * | ||
1314 | * @ies: the IE buffer | ||
1315 | * @ielen: the length of the IE buffer | ||
1316 | * @ids: an array with element IDs that are allowed before | ||
1317 | * the split | ||
1318 | * @n_ids: the size of the element ID array | ||
1319 | * @offset: offset where to start splitting in the buffer | ||
1320 | * | ||
1321 | * This function splits an IE buffer by updating the @offset | ||
1322 | * variable to point to the location where the buffer should be | ||
1323 | * split. | ||
1324 | * | ||
1325 | * It assumes that the given IE buffer is well-formed, this | ||
1326 | * has to be guaranteed by the caller! | ||
1327 | * | ||
1328 | * It also assumes that the IEs in the buffer are ordered | ||
1329 | * correctly, if not the result of using this function will not | ||
1330 | * be ordered correctly either, i.e. it does no reordering. | ||
1331 | * | ||
1332 | * The function returns the offset where the next part of the | ||
1333 | * buffer starts, which may be @ielen if the entire (remainder) | ||
1334 | * of the buffer should be used. | ||
1335 | */ | ||
1336 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, | ||
1337 | const u8 *ids, int n_ids, size_t offset) | ||
1338 | { | ||
1339 | size_t pos = offset; | ||
1340 | |||
1341 | while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos])) | ||
1342 | pos += 2 + ies[pos + 1]; | ||
1343 | |||
1344 | return pos; | ||
1345 | } | ||
1346 | |||
1347 | size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset) | ||
1348 | { | ||
1349 | size_t pos = offset; | ||
1350 | |||
1351 | while (pos < ielen && ies[pos] != WLAN_EID_VENDOR_SPECIFIC) | ||
1352 | pos += 2 + ies[pos + 1]; | ||
1353 | |||
1354 | return pos; | ||
1355 | } | ||