diff options
Diffstat (limited to 'net/mac80211/util.c')
-rw-r--r-- | net/mac80211/util.c | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index d54dbe8e09ba..086ef6257b4b 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -1170,3 +1170,77 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1170 | return 0; | 1170 | return 0; |
1171 | } | 1171 | } |
1172 | 1172 | ||
1173 | static int check_mgd_smps(struct ieee80211_if_managed *ifmgd, | ||
1174 | enum ieee80211_smps_mode *smps_mode) | ||
1175 | { | ||
1176 | if (ifmgd->associated) { | ||
1177 | *smps_mode = ifmgd->ap_smps; | ||
1178 | |||
1179 | if (*smps_mode == IEEE80211_SMPS_AUTOMATIC) { | ||
1180 | if (ifmgd->powersave) | ||
1181 | *smps_mode = IEEE80211_SMPS_DYNAMIC; | ||
1182 | else | ||
1183 | *smps_mode = IEEE80211_SMPS_OFF; | ||
1184 | } | ||
1185 | |||
1186 | return 1; | ||
1187 | } | ||
1188 | |||
1189 | return 0; | ||
1190 | } | ||
1191 | |||
1192 | /* must hold iflist_mtx */ | ||
1193 | void ieee80211_recalc_smps(struct ieee80211_local *local, | ||
1194 | struct ieee80211_sub_if_data *forsdata) | ||
1195 | { | ||
1196 | struct ieee80211_sub_if_data *sdata; | ||
1197 | enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF; | ||
1198 | int count = 0; | ||
1199 | |||
1200 | if (forsdata) | ||
1201 | WARN_ON(!mutex_is_locked(&forsdata->u.mgd.mtx)); | ||
1202 | |||
1203 | WARN_ON(!mutex_is_locked(&local->iflist_mtx)); | ||
1204 | |||
1205 | /* | ||
1206 | * This function could be improved to handle multiple | ||
1207 | * interfaces better, but right now it makes any | ||
1208 | * non-station interfaces force SM PS to be turned | ||
1209 | * off. If there are multiple station interfaces it | ||
1210 | * could also use the best possible mode, e.g. if | ||
1211 | * one is in static and the other in dynamic then | ||
1212 | * dynamic is ok. | ||
1213 | */ | ||
1214 | |||
1215 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
1216 | if (!netif_running(sdata->dev)) | ||
1217 | continue; | ||
1218 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
1219 | goto set; | ||
1220 | if (sdata != forsdata) { | ||
1221 | /* | ||
1222 | * This nested is ok -- we are holding the iflist_mtx | ||
1223 | * so can't get here twice or so. But it's required | ||
1224 | * since normally we acquire it first and then the | ||
1225 | * iflist_mtx. | ||
1226 | */ | ||
1227 | mutex_lock_nested(&sdata->u.mgd.mtx, SINGLE_DEPTH_NESTING); | ||
1228 | count += check_mgd_smps(&sdata->u.mgd, &smps_mode); | ||
1229 | mutex_unlock(&sdata->u.mgd.mtx); | ||
1230 | } else | ||
1231 | count += check_mgd_smps(&sdata->u.mgd, &smps_mode); | ||
1232 | |||
1233 | if (count > 1) { | ||
1234 | smps_mode = IEEE80211_SMPS_OFF; | ||
1235 | break; | ||
1236 | } | ||
1237 | } | ||
1238 | |||
1239 | if (smps_mode == local->smps_mode) | ||
1240 | return; | ||
1241 | |||
1242 | set: | ||
1243 | local->smps_mode = smps_mode; | ||
1244 | /* changed flag is auto-detected for this */ | ||
1245 | ieee80211_hw_config(local, 0); | ||
1246 | } | ||