aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/main.c')
-rw-r--r--net/mac80211/main.c73
1 files changed, 56 insertions, 17 deletions
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 24b14363d6e7..a109c06e8e4e 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -168,7 +168,6 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed)
168 return 0; 168 return 0;
169 169
170 memset(&conf, 0, sizeof(conf)); 170 memset(&conf, 0, sizeof(conf));
171 conf.changed = changed;
172 171
173 if (sdata->vif.type == NL80211_IFTYPE_STATION || 172 if (sdata->vif.type == NL80211_IFTYPE_STATION ||
174 sdata->vif.type == NL80211_IFTYPE_ADHOC) 173 sdata->vif.type == NL80211_IFTYPE_ADHOC)
@@ -176,16 +175,57 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed)
176 else if (sdata->vif.type == NL80211_IFTYPE_AP) 175 else if (sdata->vif.type == NL80211_IFTYPE_AP)
177 conf.bssid = sdata->dev->dev_addr; 176 conf.bssid = sdata->dev->dev_addr;
178 else if (ieee80211_vif_is_mesh(&sdata->vif)) { 177 else if (ieee80211_vif_is_mesh(&sdata->vif)) {
179 u8 zero[ETH_ALEN] = { 0 }; 178 static const u8 zero[ETH_ALEN] = { 0 };
180 conf.bssid = zero; 179 conf.bssid = zero;
181 } else { 180 } else {
182 WARN_ON(1); 181 WARN_ON(1);
183 return -EINVAL; 182 return -EINVAL;
184 } 183 }
185 184
185 switch (sdata->vif.type) {
186 case NL80211_IFTYPE_AP:
187 case NL80211_IFTYPE_ADHOC:
188 case NL80211_IFTYPE_MESH_POINT:
189 break;
190 default:
191 /* do not warn to simplify caller in scan.c */
192 changed &= ~IEEE80211_IFCC_BEACON_ENABLED;
193 if (WARN_ON(changed & IEEE80211_IFCC_BEACON))
194 return -EINVAL;
195 changed &= ~IEEE80211_IFCC_BEACON;
196 break;
197 }
198
199 if (changed & IEEE80211_IFCC_BEACON_ENABLED) {
200 if (local->sw_scanning) {
201 conf.enable_beacon = false;
202 } else {
203 /*
204 * Beacon should be enabled, but AP mode must
205 * check whether there is a beacon configured.
206 */
207 switch (sdata->vif.type) {
208 case NL80211_IFTYPE_AP:
209 conf.enable_beacon =
210 !!rcu_dereference(sdata->u.ap.beacon);
211 break;
212 case NL80211_IFTYPE_ADHOC:
213 case NL80211_IFTYPE_MESH_POINT:
214 conf.enable_beacon = true;
215 break;
216 default:
217 /* not reached */
218 WARN_ON(1);
219 break;
220 }
221 }
222 }
223
186 if (WARN_ON(!conf.bssid && (changed & IEEE80211_IFCC_BSSID))) 224 if (WARN_ON(!conf.bssid && (changed & IEEE80211_IFCC_BSSID)))
187 return -EINVAL; 225 return -EINVAL;
188 226
227 conf.changed = changed;
228
189 return local->ops->config_interface(local_to_hw(local), 229 return local->ops->config_interface(local_to_hw(local),
190 &sdata->vif, &conf); 230 &sdata->vif, &conf);
191} 231}
@@ -208,26 +248,22 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
208 } 248 }
209 249
210 if (chan != local->hw.conf.channel || 250 if (chan != local->hw.conf.channel ||
211 channel_type != local->hw.conf.ht.channel_type) { 251 channel_type != local->hw.conf.channel_type) {
212 local->hw.conf.channel = chan; 252 local->hw.conf.channel = chan;
213 local->hw.conf.ht.channel_type = channel_type; 253 local->hw.conf.channel_type = channel_type;
214 switch (channel_type) {
215 case NL80211_CHAN_NO_HT:
216 local->hw.conf.ht.enabled = false;
217 break;
218 case NL80211_CHAN_HT20:
219 case NL80211_CHAN_HT40MINUS:
220 case NL80211_CHAN_HT40PLUS:
221 local->hw.conf.ht.enabled = true;
222 break;
223 }
224 changed |= IEEE80211_CONF_CHANGE_CHANNEL; 254 changed |= IEEE80211_CONF_CHANGE_CHANNEL;
225 } 255 }
226 256
227 if (!local->hw.conf.power_level) 257 if (local->sw_scanning)
228 power = chan->max_power; 258 power = chan->max_power;
229 else 259 else
230 power = min(chan->max_power, local->hw.conf.power_level); 260 power = local->power_constr_level ?
261 (chan->max_power - local->power_constr_level) :
262 chan->max_power;
263
264 if (local->user_power_level)
265 power = min(power, local->user_power_level);
266
231 if (local->hw.conf.power_level != power) { 267 if (local->hw.conf.power_level != power) {
232 changed |= IEEE80211_CONF_CHANGE_POWER; 268 changed |= IEEE80211_CONF_CHANGE_POWER;
233 local->hw.conf.power_level = power; 269 local->hw.conf.power_level = power;
@@ -722,6 +758,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
722 local->hw.conf.radio_enabled = true; 758 local->hw.conf.radio_enabled = true;
723 759
724 INIT_LIST_HEAD(&local->interfaces); 760 INIT_LIST_HEAD(&local->interfaces);
761 mutex_init(&local->iflist_mtx);
725 762
726 spin_lock_init(&local->key_lock); 763 spin_lock_init(&local->key_lock);
727 764
@@ -822,7 +859,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
822 mdev->set_multicast_list = ieee80211_master_set_multicast_list; 859 mdev->set_multicast_list = ieee80211_master_set_multicast_list;
823 860
824 local->hw.workqueue = 861 local->hw.workqueue =
825 create_freezeable_workqueue(wiphy_name(local->hw.wiphy)); 862 create_singlethread_workqueue(wiphy_name(local->hw.wiphy));
826 if (!local->hw.workqueue) { 863 if (!local->hw.workqueue) {
827 result = -ENOMEM; 864 result = -ENOMEM;
828 goto fail_workqueue; 865 goto fail_workqueue;
@@ -972,6 +1009,8 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
972{ 1009{
973 struct ieee80211_local *local = hw_to_local(hw); 1010 struct ieee80211_local *local = hw_to_local(hw);
974 1011
1012 mutex_destroy(&local->iflist_mtx);
1013
975 wiphy_free(local->hw.wiphy); 1014 wiphy_free(local->hw.wiphy);
976} 1015}
977EXPORT_SYMBOL(ieee80211_free_hw); 1016EXPORT_SYMBOL(ieee80211_free_hw);