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.c399
1 files changed, 300 insertions, 99 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 3848140313f5..748387d45bc0 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -18,7 +18,6 @@
18#include <linux/skbuff.h> 18#include <linux/skbuff.h>
19#include <linux/etherdevice.h> 19#include <linux/etherdevice.h>
20#include <linux/if_arp.h> 20#include <linux/if_arp.h>
21#include <linux/wireless.h>
22#include <linux/bitmap.h> 21#include <linux/bitmap.h>
23#include <linux/crc32.h> 22#include <linux/crc32.h>
24#include <net/net_namespace.h> 23#include <net/net_namespace.h>
@@ -271,6 +270,8 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
271 struct ieee80211_local *local = hw_to_local(hw); 270 struct ieee80211_local *local = hw_to_local(hw);
272 struct ieee80211_sub_if_data *sdata; 271 struct ieee80211_sub_if_data *sdata;
273 272
273 trace_wake_queue(local, queue, reason);
274
274 if (WARN_ON(queue >= hw->queues)) 275 if (WARN_ON(queue >= hw->queues))
275 return; 276 return;
276 277
@@ -280,13 +281,13 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
280 /* someone still has this queue stopped */ 281 /* someone still has this queue stopped */
281 return; 282 return;
282 283
283 if (!skb_queue_empty(&local->pending[queue])) 284 if (skb_queue_empty(&local->pending[queue])) {
285 rcu_read_lock();
286 list_for_each_entry_rcu(sdata, &local->interfaces, list)
287 netif_tx_wake_queue(netdev_get_tx_queue(sdata->dev, queue));
288 rcu_read_unlock();
289 } else
284 tasklet_schedule(&local->tx_pending_tasklet); 290 tasklet_schedule(&local->tx_pending_tasklet);
285
286 rcu_read_lock();
287 list_for_each_entry_rcu(sdata, &local->interfaces, list)
288 netif_tx_wake_queue(netdev_get_tx_queue(sdata->dev, queue));
289 rcu_read_unlock();
290} 291}
291 292
292void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, 293void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
@@ -313,6 +314,8 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
313 struct ieee80211_local *local = hw_to_local(hw); 314 struct ieee80211_local *local = hw_to_local(hw);
314 struct ieee80211_sub_if_data *sdata; 315 struct ieee80211_sub_if_data *sdata;
315 316
317 trace_stop_queue(local, queue, reason);
318
316 if (WARN_ON(queue >= hw->queues)) 319 if (WARN_ON(queue >= hw->queues))
317 return; 320 return;
318 321
@@ -480,8 +483,8 @@ void ieee80211_iterate_active_interfaces(
480 case NL80211_IFTYPE_MESH_POINT: 483 case NL80211_IFTYPE_MESH_POINT:
481 break; 484 break;
482 } 485 }
483 if (netif_running(sdata->dev)) 486 if (ieee80211_sdata_running(sdata))
484 iterator(data, sdata->dev->dev_addr, 487 iterator(data, sdata->vif.addr,
485 &sdata->vif); 488 &sdata->vif);
486 } 489 }
487 490
@@ -514,8 +517,8 @@ void ieee80211_iterate_active_interfaces_atomic(
514 case NL80211_IFTYPE_MESH_POINT: 517 case NL80211_IFTYPE_MESH_POINT:
515 break; 518 break;
516 } 519 }
517 if (netif_running(sdata->dev)) 520 if (ieee80211_sdata_running(sdata))
518 iterator(data, sdata->dev->dev_addr, 521 iterator(data, sdata->vif.addr,
519 &sdata->vif); 522 &sdata->vif);
520 } 523 }
521 524
@@ -793,8 +796,19 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
793 break; 796 break;
794 } 797 }
795 798
799 qparam.uapsd = false;
800
796 drv_conf_tx(local, queue, &qparam); 801 drv_conf_tx(local, queue, &qparam);
797 } 802 }
803
804 /* after reinitialize QoS TX queues setting to default,
805 * disable QoS at all */
806
807 if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
808 sdata->vif.bss_conf.qos =
809 sdata->vif.type != NL80211_IFTYPE_STATION;
810 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS);
811 }
798} 812}
799 813
800void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, 814void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
@@ -860,7 +874,7 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
860 sizeof(*mgmt) + 6 + extra_len); 874 sizeof(*mgmt) + 6 + extra_len);
861 if (!skb) { 875 if (!skb) {
862 printk(KERN_DEBUG "%s: failed to allocate buffer for auth " 876 printk(KERN_DEBUG "%s: failed to allocate buffer for auth "
863 "frame\n", sdata->dev->name); 877 "frame\n", sdata->name);
864 return; 878 return;
865 } 879 }
866 skb_reserve(skb, local->hw.extra_tx_headroom); 880 skb_reserve(skb, local->hw.extra_tx_headroom);
@@ -870,7 +884,7 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
870 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | 884 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
871 IEEE80211_STYPE_AUTH); 885 IEEE80211_STYPE_AUTH);
872 memcpy(mgmt->da, bssid, ETH_ALEN); 886 memcpy(mgmt->da, bssid, ETH_ALEN);
873 memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); 887 memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
874 memcpy(mgmt->bssid, bssid, ETH_ALEN); 888 memcpy(mgmt->bssid, bssid, ETH_ALEN);
875 mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg); 889 mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg);
876 mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); 890 mgmt->u.auth.auth_transaction = cpu_to_le16(transaction);
@@ -893,43 +907,87 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
893 enum ieee80211_band band) 907 enum ieee80211_band band)
894{ 908{
895 struct ieee80211_supported_band *sband; 909 struct ieee80211_supported_band *sband;
896 u8 *pos, *supp_rates_len, *esupp_rates_len = NULL; 910 u8 *pos;
897 int i; 911 size_t offset = 0, noffset;
912 int supp_rates_len, i;
898 913
899 sband = local->hw.wiphy->bands[band]; 914 sband = local->hw.wiphy->bands[band];
900 915
901 pos = buffer; 916 pos = buffer;
902 917
918 supp_rates_len = min_t(int, sband->n_bitrates, 8);
919
903 *pos++ = WLAN_EID_SUPP_RATES; 920 *pos++ = WLAN_EID_SUPP_RATES;
904 supp_rates_len = pos; 921 *pos++ = supp_rates_len;
905 *pos++ = 0;
906
907 for (i = 0; i < sband->n_bitrates; i++) {
908 struct ieee80211_rate *rate = &sband->bitrates[i];
909
910 if (esupp_rates_len) {
911 *esupp_rates_len += 1;
912 } else if (*supp_rates_len == 8) {
913 *pos++ = WLAN_EID_EXT_SUPP_RATES;
914 esupp_rates_len = pos;
915 *pos++ = 1;
916 } else
917 *supp_rates_len += 1;
918 922
919 *pos++ = rate->bitrate / 5; 923 for (i = 0; i < supp_rates_len; i++) {
924 int rate = sband->bitrates[i].bitrate;
925 *pos++ = (u8) (rate / 5);
926 }
927
928 /* insert "request information" if in custom IEs */
929 if (ie && ie_len) {
930 static const u8 before_extrates[] = {
931 WLAN_EID_SSID,
932 WLAN_EID_SUPP_RATES,
933 WLAN_EID_REQUEST,
934 };
935 noffset = ieee80211_ie_split(ie, ie_len,
936 before_extrates,
937 ARRAY_SIZE(before_extrates),
938 offset);
939 memcpy(pos, ie + offset, noffset - offset);
940 pos += noffset - offset;
941 offset = noffset;
942 }
943
944 if (sband->n_bitrates > i) {
945 *pos++ = WLAN_EID_EXT_SUPP_RATES;
946 *pos++ = sband->n_bitrates - i;
947
948 for (; i < sband->n_bitrates; i++) {
949 int rate = sband->bitrates[i].bitrate;
950 *pos++ = (u8) (rate / 5);
951 }
952 }
953
954 /* insert custom IEs that go before HT */
955 if (ie && ie_len) {
956 static const u8 before_ht[] = {
957 WLAN_EID_SSID,
958 WLAN_EID_SUPP_RATES,
959 WLAN_EID_REQUEST,
960 WLAN_EID_EXT_SUPP_RATES,
961 WLAN_EID_DS_PARAMS,
962 WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
963 };
964 noffset = ieee80211_ie_split(ie, ie_len,
965 before_ht, ARRAY_SIZE(before_ht),
966 offset);
967 memcpy(pos, ie + offset, noffset - offset);
968 pos += noffset - offset;
969 offset = noffset;
920 } 970 }
921 971
922 if (sband->ht_cap.ht_supported) { 972 if (sband->ht_cap.ht_supported) {
923 __le16 tmp = cpu_to_le16(sband->ht_cap.cap); 973 u16 cap = sband->ht_cap.cap;
974 __le16 tmp;
975
976 if (ieee80211_disable_40mhz_24ghz &&
977 sband->band == IEEE80211_BAND_2GHZ) {
978 cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
979 cap &= ~IEEE80211_HT_CAP_SGI_40;
980 }
924 981
925 *pos++ = WLAN_EID_HT_CAPABILITY; 982 *pos++ = WLAN_EID_HT_CAPABILITY;
926 *pos++ = sizeof(struct ieee80211_ht_cap); 983 *pos++ = sizeof(struct ieee80211_ht_cap);
927 memset(pos, 0, sizeof(struct ieee80211_ht_cap)); 984 memset(pos, 0, sizeof(struct ieee80211_ht_cap));
985 tmp = cpu_to_le16(cap);
928 memcpy(pos, &tmp, sizeof(u16)); 986 memcpy(pos, &tmp, sizeof(u16));
929 pos += sizeof(u16); 987 pos += sizeof(u16);
930 /* TODO: needs a define here for << 2 */
931 *pos++ = sband->ht_cap.ampdu_factor | 988 *pos++ = sband->ht_cap.ampdu_factor |
932 (sband->ht_cap.ampdu_density << 2); 989 (sband->ht_cap.ampdu_density <<
990 IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
933 memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); 991 memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
934 pos += sizeof(sband->ht_cap.mcs); 992 pos += sizeof(sband->ht_cap.mcs);
935 pos += 2 + 4 + 1; /* ext info, BF cap, antsel */ 993 pos += 2 + 4 + 1; /* ext info, BF cap, antsel */
@@ -940,9 +998,11 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
940 * that calculates local->scan_ies_len. 998 * that calculates local->scan_ies_len.
941 */ 999 */
942 1000
943 if (ie) { 1001 /* add any remaining custom IEs */
944 memcpy(pos, ie, ie_len); 1002 if (ie && ie_len) {
945 pos += ie_len; 1003 noffset = ie_len;
1004 memcpy(pos, ie + offset, noffset - offset);
1005 pos += noffset - offset;
946 } 1006 }
947 1007
948 return pos - buffer; 1008 return pos - buffer;
@@ -955,40 +1015,33 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
955 struct ieee80211_local *local = sdata->local; 1015 struct ieee80211_local *local = sdata->local;
956 struct sk_buff *skb; 1016 struct sk_buff *skb;
957 struct ieee80211_mgmt *mgmt; 1017 struct ieee80211_mgmt *mgmt;
958 u8 *pos; 1018 size_t buf_len;
959 1019 u8 *buf;
960 skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + 1020
961 ie_len); 1021 /* FIXME: come up with a proper value */
962 if (!skb) { 1022 buf = kmalloc(200 + ie_len, GFP_KERNEL);
963 printk(KERN_DEBUG "%s: failed to allocate buffer for probe " 1023 if (!buf) {
964 "request\n", sdata->dev->name); 1024 printk(KERN_DEBUG "%s: failed to allocate temporary IE "
1025 "buffer\n", sdata->name);
965 return; 1026 return;
966 } 1027 }
967 skb_reserve(skb, local->hw.extra_tx_headroom);
968 1028
969 mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); 1029 buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len,
970 memset(mgmt, 0, 24); 1030 local->hw.conf.channel->band);
971 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | 1031
972 IEEE80211_STYPE_PROBE_REQ); 1032 skb = ieee80211_probereq_get(&local->hw, &sdata->vif,
973 memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); 1033 ssid, ssid_len,
1034 buf, buf_len);
1035
974 if (dst) { 1036 if (dst) {
1037 mgmt = (struct ieee80211_mgmt *) skb->data;
975 memcpy(mgmt->da, dst, ETH_ALEN); 1038 memcpy(mgmt->da, dst, ETH_ALEN);
976 memcpy(mgmt->bssid, dst, ETH_ALEN); 1039 memcpy(mgmt->bssid, dst, ETH_ALEN);
977 } else {
978 memset(mgmt->da, 0xff, ETH_ALEN);
979 memset(mgmt->bssid, 0xff, ETH_ALEN);
980 } 1040 }
981 pos = skb_put(skb, 2 + ssid_len);
982 *pos++ = WLAN_EID_SSID;
983 *pos++ = ssid_len;
984 memcpy(pos, ssid, ssid_len);
985 pos += ssid_len;
986
987 skb_put(skb, ieee80211_build_preq_ies(local, pos, ie, ie_len,
988 local->hw.conf.channel->band));
989 1041
990 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; 1042 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
991 ieee80211_tx_skb(sdata, skb); 1043 ieee80211_tx_skb(sdata, skb);
1044 kfree(buf);
992} 1045}
993 1046
994u32 ieee80211_sta_get_rates(struct ieee80211_local *local, 1047u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
@@ -1032,18 +1085,16 @@ void ieee80211_stop_device(struct ieee80211_local *local)
1032 ieee80211_led_radio(local, false); 1085 ieee80211_led_radio(local, false);
1033 1086
1034 cancel_work_sync(&local->reconfig_filter); 1087 cancel_work_sync(&local->reconfig_filter);
1035 drv_stop(local);
1036 1088
1037 flush_workqueue(local->workqueue); 1089 flush_workqueue(local->workqueue);
1090 drv_stop(local);
1038} 1091}
1039 1092
1040int ieee80211_reconfig(struct ieee80211_local *local) 1093int ieee80211_reconfig(struct ieee80211_local *local)
1041{ 1094{
1042 struct ieee80211_hw *hw = &local->hw; 1095 struct ieee80211_hw *hw = &local->hw;
1043 struct ieee80211_sub_if_data *sdata; 1096 struct ieee80211_sub_if_data *sdata;
1044 struct ieee80211_if_init_conf conf;
1045 struct sta_info *sta; 1097 struct sta_info *sta;
1046 unsigned long flags;
1047 int res; 1098 int res;
1048 1099
1049 if (local->suspended) 1100 if (local->suspended)
@@ -1059,9 +1110,9 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1059 */ 1110 */
1060 res = drv_start(local); 1111 res = drv_start(local);
1061 if (res) { 1112 if (res) {
1062 WARN(local->suspended, "Harware became unavailable " 1113 WARN(local->suspended, "Hardware became unavailable "
1063 "upon resume. This is could be a software issue" 1114 "upon resume. This could be a software issue "
1064 "prior to suspend or a harware issue\n"); 1115 "prior to suspend or a hardware issue.\n");
1065 return res; 1116 return res;
1066 } 1117 }
1067 1118
@@ -1072,41 +1123,24 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1072 list_for_each_entry(sdata, &local->interfaces, list) { 1123 list_for_each_entry(sdata, &local->interfaces, list) {
1073 if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && 1124 if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
1074 sdata->vif.type != NL80211_IFTYPE_MONITOR && 1125 sdata->vif.type != NL80211_IFTYPE_MONITOR &&
1075 netif_running(sdata->dev)) { 1126 ieee80211_sdata_running(sdata))
1076 conf.vif = &sdata->vif; 1127 res = drv_add_interface(local, &sdata->vif);
1077 conf.type = sdata->vif.type;
1078 conf.mac_addr = sdata->dev->dev_addr;
1079 res = drv_add_interface(local, &conf);
1080 }
1081 } 1128 }
1082 1129
1083 /* add STAs back */ 1130 /* add STAs back */
1084 if (local->ops->sta_notify) { 1131 mutex_lock(&local->sta_mtx);
1085 spin_lock_irqsave(&local->sta_lock, flags); 1132 list_for_each_entry(sta, &local->sta_list, list) {
1086 list_for_each_entry(sta, &local->sta_list, list) { 1133 if (sta->uploaded) {
1087 sdata = sta->sdata; 1134 sdata = sta->sdata;
1088 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 1135 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
1089 sdata = container_of(sdata->bss, 1136 sdata = container_of(sdata->bss,
1090 struct ieee80211_sub_if_data, 1137 struct ieee80211_sub_if_data,
1091 u.ap); 1138 u.ap);
1092 1139
1093 drv_sta_notify(local, &sdata->vif, STA_NOTIFY_ADD, 1140 WARN_ON(drv_sta_add(local, sdata, &sta->sta));
1094 &sta->sta);
1095 } 1141 }
1096 spin_unlock_irqrestore(&local->sta_lock, flags);
1097 } 1142 }
1098 1143 mutex_unlock(&local->sta_mtx);
1099 /* Clear Suspend state so that ADDBA requests can be processed */
1100
1101 rcu_read_lock();
1102
1103 if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
1104 list_for_each_entry_rcu(sta, &local->sta_list, list) {
1105 clear_sta_flags(sta, WLAN_STA_SUSPEND);
1106 }
1107 }
1108
1109 rcu_read_unlock();
1110 1144
1111 /* setup RTS threshold */ 1145 /* setup RTS threshold */
1112 drv_set_rts_threshold(local, hw->wiphy->rts_threshold); 1146 drv_set_rts_threshold(local, hw->wiphy->rts_threshold);
@@ -1118,18 +1152,34 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1118 1152
1119 /* Finally also reconfigure all the BSS information */ 1153 /* Finally also reconfigure all the BSS information */
1120 list_for_each_entry(sdata, &local->interfaces, list) { 1154 list_for_each_entry(sdata, &local->interfaces, list) {
1121 u32 changed = ~0; 1155 u32 changed;
1122 if (!netif_running(sdata->dev)) 1156
1157 if (!ieee80211_sdata_running(sdata))
1123 continue; 1158 continue;
1159
1160 /* common change flags for all interface types */
1161 changed = BSS_CHANGED_ERP_CTS_PROT |
1162 BSS_CHANGED_ERP_PREAMBLE |
1163 BSS_CHANGED_ERP_SLOT |
1164 BSS_CHANGED_HT |
1165 BSS_CHANGED_BASIC_RATES |
1166 BSS_CHANGED_BEACON_INT |
1167 BSS_CHANGED_BSSID |
1168 BSS_CHANGED_CQM |
1169 BSS_CHANGED_QOS;
1170
1124 switch (sdata->vif.type) { 1171 switch (sdata->vif.type) {
1125 case NL80211_IFTYPE_STATION: 1172 case NL80211_IFTYPE_STATION:
1126 /* disable beacon change bits */ 1173 changed |= BSS_CHANGED_ASSOC;
1127 changed &= ~(BSS_CHANGED_BEACON | 1174 ieee80211_bss_info_change_notify(sdata, changed);
1128 BSS_CHANGED_BEACON_ENABLED); 1175 break;
1129 /* fall through */
1130 case NL80211_IFTYPE_ADHOC: 1176 case NL80211_IFTYPE_ADHOC:
1177 changed |= BSS_CHANGED_IBSS;
1178 /* fall through */
1131 case NL80211_IFTYPE_AP: 1179 case NL80211_IFTYPE_AP:
1132 case NL80211_IFTYPE_MESH_POINT: 1180 case NL80211_IFTYPE_MESH_POINT:
1181 changed |= BSS_CHANGED_BEACON |
1182 BSS_CHANGED_BEACON_ENABLED;
1133 ieee80211_bss_info_change_notify(sdata, changed); 1183 ieee80211_bss_info_change_notify(sdata, changed);
1134 break; 1184 break;
1135 case NL80211_IFTYPE_WDS: 1185 case NL80211_IFTYPE_WDS:
@@ -1145,9 +1195,30 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1145 } 1195 }
1146 } 1196 }
1147 1197
1198 /*
1199 * Clear the WLAN_STA_BLOCK_BA flag so new aggregation
1200 * sessions can be established after a resume.
1201 *
1202 * Also tear down aggregation sessions since reconfiguring
1203 * them in a hardware restart scenario is not easily done
1204 * right now, and the hardware will have lost information
1205 * about the sessions, but we and the AP still think they
1206 * are active. This is really a workaround though.
1207 */
1208 if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
1209 mutex_lock(&local->sta_mtx);
1210
1211 list_for_each_entry(sta, &local->sta_list, list) {
1212 ieee80211_sta_tear_down_BA_sessions(sta);
1213 clear_sta_flags(sta, WLAN_STA_BLOCK_BA);
1214 }
1215
1216 mutex_unlock(&local->sta_mtx);
1217 }
1218
1148 /* add back keys */ 1219 /* add back keys */
1149 list_for_each_entry(sdata, &local->interfaces, list) 1220 list_for_each_entry(sdata, &local->interfaces, list)
1150 if (netif_running(sdata->dev)) 1221 if (ieee80211_sdata_running(sdata))
1151 ieee80211_enable_keys(sdata); 1222 ieee80211_enable_keys(sdata);
1152 1223
1153 ieee80211_wake_queues_by_reason(hw, 1224 ieee80211_wake_queues_by_reason(hw,
@@ -1184,13 +1255,143 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1184 1255
1185 add_timer(&local->sta_cleanup); 1256 add_timer(&local->sta_cleanup);
1186 1257
1187 spin_lock_irqsave(&local->sta_lock, flags); 1258 mutex_lock(&local->sta_mtx);
1188 list_for_each_entry(sta, &local->sta_list, list) 1259 list_for_each_entry(sta, &local->sta_list, list)
1189 mesh_plink_restart(sta); 1260 mesh_plink_restart(sta);
1190 spin_unlock_irqrestore(&local->sta_lock, flags); 1261 mutex_unlock(&local->sta_mtx);
1191#else 1262#else
1192 WARN_ON(1); 1263 WARN_ON(1);
1193#endif 1264#endif
1194 return 0; 1265 return 0;
1195} 1266}
1196 1267
1268static int check_mgd_smps(struct ieee80211_if_managed *ifmgd,
1269 enum ieee80211_smps_mode *smps_mode)
1270{
1271 if (ifmgd->associated) {
1272 *smps_mode = ifmgd->ap_smps;
1273
1274 if (*smps_mode == IEEE80211_SMPS_AUTOMATIC) {
1275 if (ifmgd->powersave)
1276 *smps_mode = IEEE80211_SMPS_DYNAMIC;
1277 else
1278 *smps_mode = IEEE80211_SMPS_OFF;
1279 }
1280
1281 return 1;
1282 }
1283
1284 return 0;
1285}
1286
1287/* must hold iflist_mtx */
1288void ieee80211_recalc_smps(struct ieee80211_local *local,
1289 struct ieee80211_sub_if_data *forsdata)
1290{
1291 struct ieee80211_sub_if_data *sdata;
1292 enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF;
1293 int count = 0;
1294
1295 if (forsdata)
1296 WARN_ON(!mutex_is_locked(&forsdata->u.mgd.mtx));
1297
1298 WARN_ON(!mutex_is_locked(&local->iflist_mtx));
1299
1300 /*
1301 * This function could be improved to handle multiple
1302 * interfaces better, but right now it makes any
1303 * non-station interfaces force SM PS to be turned
1304 * off. If there are multiple station interfaces it
1305 * could also use the best possible mode, e.g. if
1306 * one is in static and the other in dynamic then
1307 * dynamic is ok.
1308 */
1309
1310 list_for_each_entry(sdata, &local->interfaces, list) {
1311 if (!netif_running(sdata->dev))
1312 continue;
1313 if (sdata->vif.type != NL80211_IFTYPE_STATION)
1314 goto set;
1315 if (sdata != forsdata) {
1316 /*
1317 * This nested is ok -- we are holding the iflist_mtx
1318 * so can't get here twice or so. But it's required
1319 * since normally we acquire it first and then the
1320 * iflist_mtx.
1321 */
1322 mutex_lock_nested(&sdata->u.mgd.mtx, SINGLE_DEPTH_NESTING);
1323 count += check_mgd_smps(&sdata->u.mgd, &smps_mode);
1324 mutex_unlock(&sdata->u.mgd.mtx);
1325 } else
1326 count += check_mgd_smps(&sdata->u.mgd, &smps_mode);
1327
1328 if (count > 1) {
1329 smps_mode = IEEE80211_SMPS_OFF;
1330 break;
1331 }
1332 }
1333
1334 if (smps_mode == local->smps_mode)
1335 return;
1336
1337 set:
1338 local->smps_mode = smps_mode;
1339 /* changed flag is auto-detected for this */
1340 ieee80211_hw_config(local, 0);
1341}
1342
1343static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id)
1344{
1345 int i;
1346
1347 for (i = 0; i < n_ids; i++)
1348 if (ids[i] == id)
1349 return true;
1350 return false;
1351}
1352
1353/**
1354 * ieee80211_ie_split - split an IE buffer according to ordering
1355 *
1356 * @ies: the IE buffer
1357 * @ielen: the length of the IE buffer
1358 * @ids: an array with element IDs that are allowed before
1359 * the split
1360 * @n_ids: the size of the element ID array
1361 * @offset: offset where to start splitting in the buffer
1362 *
1363 * This function splits an IE buffer by updating the @offset
1364 * variable to point to the location where the buffer should be
1365 * split.
1366 *
1367 * It assumes that the given IE buffer is well-formed, this
1368 * has to be guaranteed by the caller!
1369 *
1370 * It also assumes that the IEs in the buffer are ordered
1371 * correctly, if not the result of using this function will not
1372 * be ordered correctly either, i.e. it does no reordering.
1373 *
1374 * The function returns the offset where the next part of the
1375 * buffer starts, which may be @ielen if the entire (remainder)
1376 * of the buffer should be used.
1377 */
1378size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
1379 const u8 *ids, int n_ids, size_t offset)
1380{
1381 size_t pos = offset;
1382
1383 while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos]))
1384 pos += 2 + ies[pos + 1];
1385
1386 return pos;
1387}
1388
1389size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset)
1390{
1391 size_t pos = offset;
1392
1393 while (pos < ielen && ies[pos] != WLAN_EID_VENDOR_SPECIFIC)
1394 pos += 2 + ies[pos + 1];
1395
1396 return pos;
1397}