aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/util.c')
-rw-r--r--net/mac80211/util.c163
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
1301static 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 */
1336size_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
1347size_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}