diff options
Diffstat (limited to 'net/mac80211/main.c')
-rw-r--r-- | net/mac80211/main.c | 73 |
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 | } |
977 | EXPORT_SYMBOL(ieee80211_free_hw); | 1016 | EXPORT_SYMBOL(ieee80211_free_hw); |