diff options
Diffstat (limited to 'net/mac80211/util.c')
-rw-r--r-- | net/mac80211/util.c | 104 |
1 files changed, 93 insertions, 11 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 78a6e924c7e1..b01972579c7c 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -469,7 +469,7 @@ void ieee80211_iterate_active_interfaces( | |||
469 | break; | 469 | break; |
470 | } | 470 | } |
471 | if (netif_running(sdata->dev)) | 471 | if (netif_running(sdata->dev)) |
472 | iterator(data, sdata->dev->dev_addr, | 472 | iterator(data, sdata->vif.addr, |
473 | &sdata->vif); | 473 | &sdata->vif); |
474 | } | 474 | } |
475 | 475 | ||
@@ -503,7 +503,7 @@ void ieee80211_iterate_active_interfaces_atomic( | |||
503 | break; | 503 | break; |
504 | } | 504 | } |
505 | if (netif_running(sdata->dev)) | 505 | if (netif_running(sdata->dev)) |
506 | iterator(data, sdata->dev->dev_addr, | 506 | iterator(data, sdata->vif.addr, |
507 | &sdata->vif); | 507 | &sdata->vif); |
508 | } | 508 | } |
509 | 509 | ||
@@ -848,7 +848,7 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | |||
848 | sizeof(*mgmt) + 6 + extra_len); | 848 | sizeof(*mgmt) + 6 + extra_len); |
849 | if (!skb) { | 849 | if (!skb) { |
850 | printk(KERN_DEBUG "%s: failed to allocate buffer for auth " | 850 | printk(KERN_DEBUG "%s: failed to allocate buffer for auth " |
851 | "frame\n", sdata->dev->name); | 851 | "frame\n", sdata->name); |
852 | return; | 852 | return; |
853 | } | 853 | } |
854 | skb_reserve(skb, local->hw.extra_tx_headroom); | 854 | skb_reserve(skb, local->hw.extra_tx_headroom); |
@@ -858,7 +858,7 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | |||
858 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 858 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
859 | IEEE80211_STYPE_AUTH); | 859 | IEEE80211_STYPE_AUTH); |
860 | memcpy(mgmt->da, bssid, ETH_ALEN); | 860 | memcpy(mgmt->da, bssid, ETH_ALEN); |
861 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 861 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); |
862 | memcpy(mgmt->bssid, bssid, ETH_ALEN); | 862 | memcpy(mgmt->bssid, bssid, ETH_ALEN); |
863 | mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg); | 863 | mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg); |
864 | mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); | 864 | mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); |
@@ -908,16 +908,24 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
908 | } | 908 | } |
909 | 909 | ||
910 | if (sband->ht_cap.ht_supported) { | 910 | if (sband->ht_cap.ht_supported) { |
911 | __le16 tmp = cpu_to_le16(sband->ht_cap.cap); | 911 | u16 cap = sband->ht_cap.cap; |
912 | __le16 tmp; | ||
913 | |||
914 | if (ieee80211_disable_40mhz_24ghz && | ||
915 | sband->band == IEEE80211_BAND_2GHZ) { | ||
916 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
917 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
918 | } | ||
912 | 919 | ||
913 | *pos++ = WLAN_EID_HT_CAPABILITY; | 920 | *pos++ = WLAN_EID_HT_CAPABILITY; |
914 | *pos++ = sizeof(struct ieee80211_ht_cap); | 921 | *pos++ = sizeof(struct ieee80211_ht_cap); |
915 | memset(pos, 0, sizeof(struct ieee80211_ht_cap)); | 922 | memset(pos, 0, sizeof(struct ieee80211_ht_cap)); |
923 | tmp = cpu_to_le16(cap); | ||
916 | memcpy(pos, &tmp, sizeof(u16)); | 924 | memcpy(pos, &tmp, sizeof(u16)); |
917 | pos += sizeof(u16); | 925 | pos += sizeof(u16); |
918 | /* TODO: needs a define here for << 2 */ | ||
919 | *pos++ = sband->ht_cap.ampdu_factor | | 926 | *pos++ = sband->ht_cap.ampdu_factor | |
920 | (sband->ht_cap.ampdu_density << 2); | 927 | (sband->ht_cap.ampdu_density << |
928 | IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); | ||
921 | memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); | 929 | memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); |
922 | pos += sizeof(sband->ht_cap.mcs); | 930 | pos += sizeof(sband->ht_cap.mcs); |
923 | pos += 2 + 4 + 1; /* ext info, BF cap, antsel */ | 931 | pos += 2 + 4 + 1; /* ext info, BF cap, antsel */ |
@@ -949,7 +957,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | |||
949 | ie_len); | 957 | ie_len); |
950 | if (!skb) { | 958 | if (!skb) { |
951 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | 959 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " |
952 | "request\n", sdata->dev->name); | 960 | "request\n", sdata->name); |
953 | return; | 961 | return; |
954 | } | 962 | } |
955 | skb_reserve(skb, local->hw.extra_tx_headroom); | 963 | skb_reserve(skb, local->hw.extra_tx_headroom); |
@@ -958,7 +966,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | |||
958 | memset(mgmt, 0, 24); | 966 | memset(mgmt, 0, 24); |
959 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 967 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
960 | IEEE80211_STYPE_PROBE_REQ); | 968 | IEEE80211_STYPE_PROBE_REQ); |
961 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 969 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); |
962 | if (dst) { | 970 | if (dst) { |
963 | memcpy(mgmt->da, dst, ETH_ALEN); | 971 | memcpy(mgmt->da, dst, ETH_ALEN); |
964 | memcpy(mgmt->bssid, dst, ETH_ALEN); | 972 | memcpy(mgmt->bssid, dst, ETH_ALEN); |
@@ -1051,7 +1059,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1051 | netif_running(sdata->dev)) { | 1059 | netif_running(sdata->dev)) { |
1052 | conf.vif = &sdata->vif; | 1060 | conf.vif = &sdata->vif; |
1053 | conf.type = sdata->vif.type; | 1061 | conf.type = sdata->vif.type; |
1054 | conf.mac_addr = sdata->dev->dev_addr; | 1062 | conf.mac_addr = sdata->vif.addr; |
1055 | res = drv_add_interface(local, &conf); | 1063 | res = drv_add_interface(local, &conf); |
1056 | } | 1064 | } |
1057 | } | 1065 | } |
@@ -1066,7 +1074,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1066 | struct ieee80211_sub_if_data, | 1074 | struct ieee80211_sub_if_data, |
1067 | u.ap); | 1075 | u.ap); |
1068 | 1076 | ||
1069 | drv_sta_notify(local, &sdata->vif, STA_NOTIFY_ADD, | 1077 | drv_sta_notify(local, sdata, STA_NOTIFY_ADD, |
1070 | &sta->sta); | 1078 | &sta->sta); |
1071 | } | 1079 | } |
1072 | spin_unlock_irqrestore(&local->sta_lock, flags); | 1080 | spin_unlock_irqrestore(&local->sta_lock, flags); |
@@ -1170,3 +1178,77 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1170 | return 0; | 1178 | return 0; |
1171 | } | 1179 | } |
1172 | 1180 | ||
1181 | static int check_mgd_smps(struct ieee80211_if_managed *ifmgd, | ||
1182 | enum ieee80211_smps_mode *smps_mode) | ||
1183 | { | ||
1184 | if (ifmgd->associated) { | ||
1185 | *smps_mode = ifmgd->ap_smps; | ||
1186 | |||
1187 | if (*smps_mode == IEEE80211_SMPS_AUTOMATIC) { | ||
1188 | if (ifmgd->powersave) | ||
1189 | *smps_mode = IEEE80211_SMPS_DYNAMIC; | ||
1190 | else | ||
1191 | *smps_mode = IEEE80211_SMPS_OFF; | ||
1192 | } | ||
1193 | |||
1194 | return 1; | ||
1195 | } | ||
1196 | |||
1197 | return 0; | ||
1198 | } | ||
1199 | |||
1200 | /* must hold iflist_mtx */ | ||
1201 | void ieee80211_recalc_smps(struct ieee80211_local *local, | ||
1202 | struct ieee80211_sub_if_data *forsdata) | ||
1203 | { | ||
1204 | struct ieee80211_sub_if_data *sdata; | ||
1205 | enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF; | ||
1206 | int count = 0; | ||
1207 | |||
1208 | if (forsdata) | ||
1209 | WARN_ON(!mutex_is_locked(&forsdata->u.mgd.mtx)); | ||
1210 | |||
1211 | WARN_ON(!mutex_is_locked(&local->iflist_mtx)); | ||
1212 | |||
1213 | /* | ||
1214 | * This function could be improved to handle multiple | ||
1215 | * interfaces better, but right now it makes any | ||
1216 | * non-station interfaces force SM PS to be turned | ||
1217 | * off. If there are multiple station interfaces it | ||
1218 | * could also use the best possible mode, e.g. if | ||
1219 | * one is in static and the other in dynamic then | ||
1220 | * dynamic is ok. | ||
1221 | */ | ||
1222 | |||
1223 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
1224 | if (!netif_running(sdata->dev)) | ||
1225 | continue; | ||
1226 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
1227 | goto set; | ||
1228 | if (sdata != forsdata) { | ||
1229 | /* | ||
1230 | * This nested is ok -- we are holding the iflist_mtx | ||
1231 | * so can't get here twice or so. But it's required | ||
1232 | * since normally we acquire it first and then the | ||
1233 | * iflist_mtx. | ||
1234 | */ | ||
1235 | mutex_lock_nested(&sdata->u.mgd.mtx, SINGLE_DEPTH_NESTING); | ||
1236 | count += check_mgd_smps(&sdata->u.mgd, &smps_mode); | ||
1237 | mutex_unlock(&sdata->u.mgd.mtx); | ||
1238 | } else | ||
1239 | count += check_mgd_smps(&sdata->u.mgd, &smps_mode); | ||
1240 | |||
1241 | if (count > 1) { | ||
1242 | smps_mode = IEEE80211_SMPS_OFF; | ||
1243 | break; | ||
1244 | } | ||
1245 | } | ||
1246 | |||
1247 | if (smps_mode == local->smps_mode) | ||
1248 | return; | ||
1249 | |||
1250 | set: | ||
1251 | local->smps_mode = smps_mode; | ||
1252 | /* changed flag is auto-detected for this */ | ||
1253 | ieee80211_hw_config(local, 0); | ||
1254 | } | ||