diff options
Diffstat (limited to 'net/mac80211/iface.c')
-rw-r--r-- | net/mac80211/iface.c | 460 |
1 files changed, 294 insertions, 166 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index ebbe264e2b0b..f9163b12c7f1 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include "led.h" | 24 | #include "led.h" |
25 | #include "driver-ops.h" | 25 | #include "driver-ops.h" |
26 | #include "wme.h" | 26 | #include "wme.h" |
27 | #include "rate.h" | ||
27 | 28 | ||
28 | /** | 29 | /** |
29 | * DOC: Interface list locking | 30 | * DOC: Interface list locking |
@@ -94,21 +95,14 @@ static inline int identical_mac_addr_allowed(int type1, int type2) | |||
94 | type2 == NL80211_IFTYPE_AP_VLAN)); | 95 | type2 == NL80211_IFTYPE_AP_VLAN)); |
95 | } | 96 | } |
96 | 97 | ||
97 | static int ieee80211_open(struct net_device *dev) | 98 | static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata, |
99 | enum nl80211_iftype iftype) | ||
98 | { | 100 | { |
99 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
100 | struct ieee80211_sub_if_data *nsdata; | ||
101 | struct ieee80211_local *local = sdata->local; | 101 | struct ieee80211_local *local = sdata->local; |
102 | struct sta_info *sta; | 102 | struct ieee80211_sub_if_data *nsdata; |
103 | u32 changed = 0; | 103 | struct net_device *dev = sdata->dev; |
104 | int res; | ||
105 | u32 hw_reconf_flags = 0; | ||
106 | u8 null_addr[ETH_ALEN] = {0}; | ||
107 | 104 | ||
108 | /* fail early if user set an invalid address */ | 105 | ASSERT_RTNL(); |
109 | if (compare_ether_addr(dev->dev_addr, null_addr) && | ||
110 | !is_valid_ether_addr(dev->dev_addr)) | ||
111 | return -EADDRNOTAVAIL; | ||
112 | 106 | ||
113 | /* we hold the RTNL here so can safely walk the list */ | 107 | /* we hold the RTNL here so can safely walk the list */ |
114 | list_for_each_entry(nsdata, &local->interfaces, list) { | 108 | list_for_each_entry(nsdata, &local->interfaces, list) { |
@@ -125,7 +119,7 @@ static int ieee80211_open(struct net_device *dev) | |||
125 | * belonging to the same hardware. Then, however, we're | 119 | * belonging to the same hardware. Then, however, we're |
126 | * faced with having to adopt two different TSF timers... | 120 | * faced with having to adopt two different TSF timers... |
127 | */ | 121 | */ |
128 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && | 122 | if (iftype == NL80211_IFTYPE_ADHOC && |
129 | nsdata->vif.type == NL80211_IFTYPE_ADHOC) | 123 | nsdata->vif.type == NL80211_IFTYPE_ADHOC) |
130 | return -EBUSY; | 124 | return -EBUSY; |
131 | 125 | ||
@@ -139,19 +133,56 @@ static int ieee80211_open(struct net_device *dev) | |||
139 | /* | 133 | /* |
140 | * check whether it may have the same address | 134 | * check whether it may have the same address |
141 | */ | 135 | */ |
142 | if (!identical_mac_addr_allowed(sdata->vif.type, | 136 | if (!identical_mac_addr_allowed(iftype, |
143 | nsdata->vif.type)) | 137 | nsdata->vif.type)) |
144 | return -ENOTUNIQ; | 138 | return -ENOTUNIQ; |
145 | 139 | ||
146 | /* | 140 | /* |
147 | * can only add VLANs to enabled APs | 141 | * can only add VLANs to enabled APs |
148 | */ | 142 | */ |
149 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN && | 143 | if (iftype == NL80211_IFTYPE_AP_VLAN && |
150 | nsdata->vif.type == NL80211_IFTYPE_AP) | 144 | nsdata->vif.type == NL80211_IFTYPE_AP) |
151 | sdata->bss = &nsdata->u.ap; | 145 | sdata->bss = &nsdata->u.ap; |
152 | } | 146 | } |
153 | } | 147 | } |
154 | 148 | ||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, | ||
153 | const int offset) | ||
154 | { | ||
155 | struct ieee80211_local *local = sdata->local; | ||
156 | u32 flags = sdata->u.mntr_flags; | ||
157 | |||
158 | #define ADJUST(_f, _s) do { \ | ||
159 | if (flags & MONITOR_FLAG_##_f) \ | ||
160 | local->fif_##_s += offset; \ | ||
161 | } while (0) | ||
162 | |||
163 | ADJUST(FCSFAIL, fcsfail); | ||
164 | ADJUST(PLCPFAIL, plcpfail); | ||
165 | ADJUST(CONTROL, control); | ||
166 | ADJUST(CONTROL, pspoll); | ||
167 | ADJUST(OTHER_BSS, other_bss); | ||
168 | |||
169 | #undef ADJUST | ||
170 | } | ||
171 | |||
172 | /* | ||
173 | * NOTE: Be very careful when changing this function, it must NOT return | ||
174 | * an error on interface type changes that have been pre-checked, so most | ||
175 | * checks should be in ieee80211_check_concurrent_iface. | ||
176 | */ | ||
177 | static int ieee80211_do_open(struct net_device *dev, bool coming_up) | ||
178 | { | ||
179 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
180 | struct ieee80211_local *local = sdata->local; | ||
181 | struct sta_info *sta; | ||
182 | u32 changed = 0; | ||
183 | int res; | ||
184 | u32 hw_reconf_flags = 0; | ||
185 | |||
155 | switch (sdata->vif.type) { | 186 | switch (sdata->vif.type) { |
156 | case NL80211_IFTYPE_WDS: | 187 | case NL80211_IFTYPE_WDS: |
157 | if (!is_valid_ether_addr(sdata->u.wds.remote_addr)) | 188 | if (!is_valid_ether_addr(sdata->u.wds.remote_addr)) |
@@ -177,7 +208,9 @@ static int ieee80211_open(struct net_device *dev) | |||
177 | /* no special treatment */ | 208 | /* no special treatment */ |
178 | break; | 209 | break; |
179 | case NL80211_IFTYPE_UNSPECIFIED: | 210 | case NL80211_IFTYPE_UNSPECIFIED: |
180 | case __NL80211_IFTYPE_AFTER_LAST: | 211 | case NUM_NL80211_IFTYPES: |
212 | case NL80211_IFTYPE_P2P_CLIENT: | ||
213 | case NL80211_IFTYPE_P2P_GO: | ||
181 | /* cannot happen */ | 214 | /* cannot happen */ |
182 | WARN_ON(1); | 215 | WARN_ON(1); |
183 | break; | 216 | break; |
@@ -187,39 +220,30 @@ static int ieee80211_open(struct net_device *dev) | |||
187 | res = drv_start(local); | 220 | res = drv_start(local); |
188 | if (res) | 221 | if (res) |
189 | goto err_del_bss; | 222 | goto err_del_bss; |
223 | if (local->ops->napi_poll) | ||
224 | napi_enable(&local->napi); | ||
190 | /* we're brought up, everything changes */ | 225 | /* we're brought up, everything changes */ |
191 | hw_reconf_flags = ~0; | 226 | hw_reconf_flags = ~0; |
192 | ieee80211_led_radio(local, true); | 227 | ieee80211_led_radio(local, true); |
193 | } | 228 | } |
194 | 229 | ||
195 | /* | 230 | /* |
196 | * Check all interfaces and copy the hopefully now-present | 231 | * Copy the hopefully now-present MAC address to |
197 | * MAC address to those that have the special null one. | 232 | * this interface, if it has the special null one. |
198 | */ | 233 | */ |
199 | list_for_each_entry(nsdata, &local->interfaces, list) { | 234 | if (is_zero_ether_addr(dev->dev_addr)) { |
200 | struct net_device *ndev = nsdata->dev; | 235 | memcpy(dev->dev_addr, |
201 | 236 | local->hw.wiphy->perm_addr, | |
202 | /* | 237 | ETH_ALEN); |
203 | * No need to check running since we do not allow | 238 | memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN); |
204 | * it to start up with this invalid address. | 239 | |
205 | */ | 240 | if (!is_valid_ether_addr(dev->dev_addr)) { |
206 | if (compare_ether_addr(null_addr, ndev->dev_addr) == 0) { | 241 | if (!local->open_count) |
207 | memcpy(ndev->dev_addr, | 242 | drv_stop(local); |
208 | local->hw.wiphy->perm_addr, | 243 | return -EADDRNOTAVAIL; |
209 | ETH_ALEN); | ||
210 | memcpy(ndev->perm_addr, ndev->dev_addr, ETH_ALEN); | ||
211 | } | 244 | } |
212 | } | 245 | } |
213 | 246 | ||
214 | /* | ||
215 | * Validate the MAC address for this device. | ||
216 | */ | ||
217 | if (!is_valid_ether_addr(dev->dev_addr)) { | ||
218 | if (!local->open_count) | ||
219 | drv_stop(local); | ||
220 | return -EADDRNOTAVAIL; | ||
221 | } | ||
222 | |||
223 | switch (sdata->vif.type) { | 247 | switch (sdata->vif.type) { |
224 | case NL80211_IFTYPE_AP_VLAN: | 248 | case NL80211_IFTYPE_AP_VLAN: |
225 | /* no need to tell driver */ | 249 | /* no need to tell driver */ |
@@ -237,25 +261,17 @@ static int ieee80211_open(struct net_device *dev) | |||
237 | hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; | 261 | hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; |
238 | } | 262 | } |
239 | 263 | ||
240 | if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL) | 264 | ieee80211_adjust_monitor_flags(sdata, 1); |
241 | local->fif_fcsfail++; | ||
242 | if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL) | ||
243 | local->fif_plcpfail++; | ||
244 | if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) { | ||
245 | local->fif_control++; | ||
246 | local->fif_pspoll++; | ||
247 | } | ||
248 | if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) | ||
249 | local->fif_other_bss++; | ||
250 | |||
251 | ieee80211_configure_filter(local); | 265 | ieee80211_configure_filter(local); |
252 | 266 | ||
253 | netif_carrier_on(dev); | 267 | netif_carrier_on(dev); |
254 | break; | 268 | break; |
255 | default: | 269 | default: |
256 | res = drv_add_interface(local, &sdata->vif); | 270 | if (coming_up) { |
257 | if (res) | 271 | res = drv_add_interface(local, &sdata->vif); |
258 | goto err_stop; | 272 | if (res) |
273 | goto err_stop; | ||
274 | } | ||
259 | 275 | ||
260 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 276 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
261 | local->fif_other_bss++; | 277 | local->fif_other_bss++; |
@@ -264,8 +280,11 @@ static int ieee80211_open(struct net_device *dev) | |||
264 | ieee80211_start_mesh(sdata); | 280 | ieee80211_start_mesh(sdata); |
265 | } else if (sdata->vif.type == NL80211_IFTYPE_AP) { | 281 | } else if (sdata->vif.type == NL80211_IFTYPE_AP) { |
266 | local->fif_pspoll++; | 282 | local->fif_pspoll++; |
283 | local->fif_probe_req++; | ||
267 | 284 | ||
268 | ieee80211_configure_filter(local); | 285 | ieee80211_configure_filter(local); |
286 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
287 | local->fif_probe_req++; | ||
269 | } | 288 | } |
270 | 289 | ||
271 | changed |= ieee80211_reset_erp_info(sdata); | 290 | changed |= ieee80211_reset_erp_info(sdata); |
@@ -277,6 +296,8 @@ static int ieee80211_open(struct net_device *dev) | |||
277 | netif_carrier_on(dev); | 296 | netif_carrier_on(dev); |
278 | } | 297 | } |
279 | 298 | ||
299 | set_bit(SDATA_STATE_RUNNING, &sdata->state); | ||
300 | |||
280 | if (sdata->vif.type == NL80211_IFTYPE_WDS) { | 301 | if (sdata->vif.type == NL80211_IFTYPE_WDS) { |
281 | /* Create STA entry for the WDS peer */ | 302 | /* Create STA entry for the WDS peer */ |
282 | sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr, | 303 | sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr, |
@@ -294,6 +315,8 @@ static int ieee80211_open(struct net_device *dev) | |||
294 | /* STA has been freed */ | 315 | /* STA has been freed */ |
295 | goto err_del_interface; | 316 | goto err_del_interface; |
296 | } | 317 | } |
318 | |||
319 | rate_control_rate_init(sta); | ||
297 | } | 320 | } |
298 | 321 | ||
299 | /* | 322 | /* |
@@ -307,9 +330,13 @@ static int ieee80211_open(struct net_device *dev) | |||
307 | if (sdata->flags & IEEE80211_SDATA_PROMISC) | 330 | if (sdata->flags & IEEE80211_SDATA_PROMISC) |
308 | atomic_inc(&local->iff_promiscs); | 331 | atomic_inc(&local->iff_promiscs); |
309 | 332 | ||
333 | mutex_lock(&local->mtx); | ||
310 | hw_reconf_flags |= __ieee80211_recalc_idle(local); | 334 | hw_reconf_flags |= __ieee80211_recalc_idle(local); |
335 | mutex_unlock(&local->mtx); | ||
336 | |||
337 | if (coming_up) | ||
338 | local->open_count++; | ||
311 | 339 | ||
312 | local->open_count++; | ||
313 | if (hw_reconf_flags) { | 340 | if (hw_reconf_flags) { |
314 | ieee80211_hw_config(local, hw_reconf_flags); | 341 | ieee80211_hw_config(local, hw_reconf_flags); |
315 | /* | 342 | /* |
@@ -334,22 +361,42 @@ static int ieee80211_open(struct net_device *dev) | |||
334 | sdata->bss = NULL; | 361 | sdata->bss = NULL; |
335 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 362 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
336 | list_del(&sdata->u.vlan.list); | 363 | list_del(&sdata->u.vlan.list); |
364 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); | ||
337 | return res; | 365 | return res; |
338 | } | 366 | } |
339 | 367 | ||
340 | static int ieee80211_stop(struct net_device *dev) | 368 | static int ieee80211_open(struct net_device *dev) |
341 | { | 369 | { |
342 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 370 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
371 | int err; | ||
372 | |||
373 | /* fail early if user set an invalid address */ | ||
374 | if (!is_zero_ether_addr(dev->dev_addr) && | ||
375 | !is_valid_ether_addr(dev->dev_addr)) | ||
376 | return -EADDRNOTAVAIL; | ||
377 | |||
378 | err = ieee80211_check_concurrent_iface(sdata, sdata->vif.type); | ||
379 | if (err) | ||
380 | return err; | ||
381 | |||
382 | return ieee80211_do_open(dev, true); | ||
383 | } | ||
384 | |||
385 | static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | ||
386 | bool going_down) | ||
387 | { | ||
343 | struct ieee80211_local *local = sdata->local; | 388 | struct ieee80211_local *local = sdata->local; |
344 | unsigned long flags; | 389 | unsigned long flags; |
345 | struct sk_buff *skb, *tmp; | 390 | struct sk_buff *skb, *tmp; |
346 | u32 hw_reconf_flags = 0; | 391 | u32 hw_reconf_flags = 0; |
347 | int i; | 392 | int i; |
348 | 393 | ||
394 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); | ||
395 | |||
349 | /* | 396 | /* |
350 | * Stop TX on this interface first. | 397 | * Stop TX on this interface first. |
351 | */ | 398 | */ |
352 | netif_tx_stop_all_queues(dev); | 399 | netif_tx_stop_all_queues(sdata->dev); |
353 | 400 | ||
354 | /* | 401 | /* |
355 | * Purge work for this interface. | 402 | * Purge work for this interface. |
@@ -366,12 +413,9 @@ static int ieee80211_stop(struct net_device *dev) | |||
366 | * (because if we remove a STA after ops->remove_interface() | 413 | * (because if we remove a STA after ops->remove_interface() |
367 | * the driver will have removed the vif info already!) | 414 | * the driver will have removed the vif info already!) |
368 | * | 415 | * |
369 | * We could relax this and only unlink the stations from the | 416 | * This is relevant only in AP, WDS and mesh modes, since in |
370 | * hash table and list but keep them on a per-sdata list that | 417 | * all other modes we've already removed all stations when |
371 | * will be inserted back again when the interface is brought | 418 | * disconnecting etc. |
372 | * up again, but I don't currently see a use case for that, | ||
373 | * except with WDS which gets a STA entry created when it is | ||
374 | * brought up. | ||
375 | */ | 419 | */ |
376 | sta_info_flush(local, sdata); | 420 | sta_info_flush(local, sdata); |
377 | 421 | ||
@@ -387,14 +431,19 @@ static int ieee80211_stop(struct net_device *dev) | |||
387 | if (sdata->flags & IEEE80211_SDATA_PROMISC) | 431 | if (sdata->flags & IEEE80211_SDATA_PROMISC) |
388 | atomic_dec(&local->iff_promiscs); | 432 | atomic_dec(&local->iff_promiscs); |
389 | 433 | ||
390 | if (sdata->vif.type == NL80211_IFTYPE_AP) | 434 | if (sdata->vif.type == NL80211_IFTYPE_AP) { |
391 | local->fif_pspoll--; | 435 | local->fif_pspoll--; |
436 | local->fif_probe_req--; | ||
437 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
438 | local->fif_probe_req--; | ||
439 | } | ||
392 | 440 | ||
393 | netif_addr_lock_bh(dev); | 441 | netif_addr_lock_bh(sdata->dev); |
394 | spin_lock_bh(&local->filter_lock); | 442 | spin_lock_bh(&local->filter_lock); |
395 | __hw_addr_unsync(&local->mc_list, &dev->mc, dev->addr_len); | 443 | __hw_addr_unsync(&local->mc_list, &sdata->dev->mc, |
444 | sdata->dev->addr_len); | ||
396 | spin_unlock_bh(&local->filter_lock); | 445 | spin_unlock_bh(&local->filter_lock); |
397 | netif_addr_unlock_bh(dev); | 446 | netif_addr_unlock_bh(sdata->dev); |
398 | 447 | ||
399 | ieee80211_configure_filter(local); | 448 | ieee80211_configure_filter(local); |
400 | 449 | ||
@@ -406,11 +455,21 @@ static int ieee80211_stop(struct net_device *dev) | |||
406 | struct ieee80211_sub_if_data *vlan, *tmpsdata; | 455 | struct ieee80211_sub_if_data *vlan, *tmpsdata; |
407 | struct beacon_data *old_beacon = sdata->u.ap.beacon; | 456 | struct beacon_data *old_beacon = sdata->u.ap.beacon; |
408 | 457 | ||
458 | /* sdata_running will return false, so this will disable */ | ||
459 | ieee80211_bss_info_change_notify(sdata, | ||
460 | BSS_CHANGED_BEACON_ENABLED); | ||
461 | |||
409 | /* remove beacon */ | 462 | /* remove beacon */ |
410 | rcu_assign_pointer(sdata->u.ap.beacon, NULL); | 463 | rcu_assign_pointer(sdata->u.ap.beacon, NULL); |
411 | synchronize_rcu(); | 464 | synchronize_rcu(); |
412 | kfree(old_beacon); | 465 | kfree(old_beacon); |
413 | 466 | ||
467 | /* free all potentially still buffered bcast frames */ | ||
468 | while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) { | ||
469 | local->total_ps_buffered--; | ||
470 | dev_kfree_skb(skb); | ||
471 | } | ||
472 | |||
414 | /* down all dependent devices, that is VLANs */ | 473 | /* down all dependent devices, that is VLANs */ |
415 | list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans, | 474 | list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans, |
416 | u.vlan.list) | 475 | u.vlan.list) |
@@ -418,7 +477,8 @@ static int ieee80211_stop(struct net_device *dev) | |||
418 | WARN_ON(!list_empty(&sdata->u.ap.vlans)); | 477 | WARN_ON(!list_empty(&sdata->u.ap.vlans)); |
419 | } | 478 | } |
420 | 479 | ||
421 | local->open_count--; | 480 | if (going_down) |
481 | local->open_count--; | ||
422 | 482 | ||
423 | switch (sdata->vif.type) { | 483 | switch (sdata->vif.type) { |
424 | case NL80211_IFTYPE_AP_VLAN: | 484 | case NL80211_IFTYPE_AP_VLAN: |
@@ -437,40 +497,9 @@ static int ieee80211_stop(struct net_device *dev) | |||
437 | hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; | 497 | hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; |
438 | } | 498 | } |
439 | 499 | ||
440 | if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL) | 500 | ieee80211_adjust_monitor_flags(sdata, -1); |
441 | local->fif_fcsfail--; | ||
442 | if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL) | ||
443 | local->fif_plcpfail--; | ||
444 | if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) { | ||
445 | local->fif_pspoll--; | ||
446 | local->fif_control--; | ||
447 | } | ||
448 | if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) | ||
449 | local->fif_other_bss--; | ||
450 | |||
451 | ieee80211_configure_filter(local); | 501 | ieee80211_configure_filter(local); |
452 | break; | 502 | break; |
453 | case NL80211_IFTYPE_STATION: | ||
454 | del_timer_sync(&sdata->u.mgd.chswitch_timer); | ||
455 | del_timer_sync(&sdata->u.mgd.timer); | ||
456 | del_timer_sync(&sdata->u.mgd.conn_mon_timer); | ||
457 | del_timer_sync(&sdata->u.mgd.bcn_mon_timer); | ||
458 | /* | ||
459 | * If any of the timers fired while we waited for it, it will | ||
460 | * have queued its work. Now the work will be running again | ||
461 | * but will not rearm the timer again because it checks | ||
462 | * whether the interface is running, which, at this point, | ||
463 | * it no longer is. | ||
464 | */ | ||
465 | cancel_work_sync(&sdata->u.mgd.chswitch_work); | ||
466 | cancel_work_sync(&sdata->u.mgd.monitor_work); | ||
467 | cancel_work_sync(&sdata->u.mgd.beacon_connection_loss_work); | ||
468 | |||
469 | /* fall through */ | ||
470 | case NL80211_IFTYPE_ADHOC: | ||
471 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | ||
472 | del_timer_sync(&sdata->u.ibss.timer); | ||
473 | /* fall through */ | ||
474 | case NL80211_IFTYPE_MESH_POINT: | 503 | case NL80211_IFTYPE_MESH_POINT: |
475 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 504 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
476 | /* other_bss and allmulti are always set on mesh | 505 | /* other_bss and allmulti are always set on mesh |
@@ -498,27 +527,34 @@ static int ieee80211_stop(struct net_device *dev) | |||
498 | ieee80211_scan_cancel(local); | 527 | ieee80211_scan_cancel(local); |
499 | 528 | ||
500 | /* | 529 | /* |
501 | * Disable beaconing for AP and mesh, IBSS can't | 530 | * Disable beaconing here for mesh only, AP and IBSS |
502 | * still be joined to a network at this point. | 531 | * are already taken care of. |
503 | */ | 532 | */ |
504 | if (sdata->vif.type == NL80211_IFTYPE_AP || | 533 | if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT) |
505 | sdata->vif.type == NL80211_IFTYPE_MESH_POINT) { | ||
506 | ieee80211_bss_info_change_notify(sdata, | 534 | ieee80211_bss_info_change_notify(sdata, |
507 | BSS_CHANGED_BEACON_ENABLED); | 535 | BSS_CHANGED_BEACON_ENABLED); |
508 | } | ||
509 | 536 | ||
510 | /* free all remaining keys, there shouldn't be any */ | 537 | /* |
538 | * Free all remaining keys, there shouldn't be any, | ||
539 | * except maybe group keys in AP more or WDS? | ||
540 | */ | ||
511 | ieee80211_free_keys(sdata); | 541 | ieee80211_free_keys(sdata); |
512 | drv_remove_interface(local, &sdata->vif); | 542 | |
543 | if (going_down) | ||
544 | drv_remove_interface(local, &sdata->vif); | ||
513 | } | 545 | } |
514 | 546 | ||
515 | sdata->bss = NULL; | 547 | sdata->bss = NULL; |
516 | 548 | ||
549 | mutex_lock(&local->mtx); | ||
517 | hw_reconf_flags |= __ieee80211_recalc_idle(local); | 550 | hw_reconf_flags |= __ieee80211_recalc_idle(local); |
551 | mutex_unlock(&local->mtx); | ||
518 | 552 | ||
519 | ieee80211_recalc_ps(local, -1); | 553 | ieee80211_recalc_ps(local, -1); |
520 | 554 | ||
521 | if (local->open_count == 0) { | 555 | if (local->open_count == 0) { |
556 | if (local->ops->napi_poll) | ||
557 | napi_disable(&local->napi); | ||
522 | ieee80211_clear_tx_pending(local); | 558 | ieee80211_clear_tx_pending(local); |
523 | ieee80211_stop_device(local); | 559 | ieee80211_stop_device(local); |
524 | 560 | ||
@@ -541,6 +577,13 @@ static int ieee80211_stop(struct net_device *dev) | |||
541 | } | 577 | } |
542 | } | 578 | } |
543 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 579 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
580 | } | ||
581 | |||
582 | static int ieee80211_stop(struct net_device *dev) | ||
583 | { | ||
584 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
585 | |||
586 | ieee80211_do_stop(sdata, true); | ||
544 | 587 | ||
545 | return 0; | 588 | return 0; |
546 | } | 589 | } |
@@ -585,8 +628,6 @@ static void ieee80211_teardown_sdata(struct net_device *dev) | |||
585 | { | 628 | { |
586 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 629 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
587 | struct ieee80211_local *local = sdata->local; | 630 | struct ieee80211_local *local = sdata->local; |
588 | struct beacon_data *beacon; | ||
589 | struct sk_buff *skb; | ||
590 | int flushed; | 631 | int flushed; |
591 | int i; | 632 | int i; |
592 | 633 | ||
@@ -599,37 +640,8 @@ static void ieee80211_teardown_sdata(struct net_device *dev) | |||
599 | __skb_queue_purge(&sdata->fragments[i].skb_list); | 640 | __skb_queue_purge(&sdata->fragments[i].skb_list); |
600 | sdata->fragment_next = 0; | 641 | sdata->fragment_next = 0; |
601 | 642 | ||
602 | switch (sdata->vif.type) { | 643 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
603 | case NL80211_IFTYPE_AP: | 644 | mesh_rmc_free(sdata); |
604 | beacon = sdata->u.ap.beacon; | ||
605 | rcu_assign_pointer(sdata->u.ap.beacon, NULL); | ||
606 | synchronize_rcu(); | ||
607 | kfree(beacon); | ||
608 | |||
609 | while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) { | ||
610 | local->total_ps_buffered--; | ||
611 | dev_kfree_skb(skb); | ||
612 | } | ||
613 | |||
614 | break; | ||
615 | case NL80211_IFTYPE_MESH_POINT: | ||
616 | if (ieee80211_vif_is_mesh(&sdata->vif)) | ||
617 | mesh_rmc_free(sdata); | ||
618 | break; | ||
619 | case NL80211_IFTYPE_ADHOC: | ||
620 | if (WARN_ON(sdata->u.ibss.presp)) | ||
621 | kfree_skb(sdata->u.ibss.presp); | ||
622 | break; | ||
623 | case NL80211_IFTYPE_STATION: | ||
624 | case NL80211_IFTYPE_WDS: | ||
625 | case NL80211_IFTYPE_AP_VLAN: | ||
626 | case NL80211_IFTYPE_MONITOR: | ||
627 | break; | ||
628 | case NL80211_IFTYPE_UNSPECIFIED: | ||
629 | case __NL80211_IFTYPE_AFTER_LAST: | ||
630 | BUG(); | ||
631 | break; | ||
632 | } | ||
633 | 645 | ||
634 | flushed = sta_info_flush(local, sdata); | 646 | flushed = sta_info_flush(local, sdata); |
635 | WARN_ON(flushed); | 647 | WARN_ON(flushed); |
@@ -791,7 +803,8 @@ static void ieee80211_iface_work(struct work_struct *work) | |||
791 | 803 | ||
792 | __ieee80211_stop_rx_ba_session( | 804 | __ieee80211_stop_rx_ba_session( |
793 | sta, tid, WLAN_BACK_RECIPIENT, | 805 | sta, tid, WLAN_BACK_RECIPIENT, |
794 | WLAN_REASON_QSTA_REQUIRE_SETUP); | 806 | WLAN_REASON_QSTA_REQUIRE_SETUP, |
807 | true); | ||
795 | } | 808 | } |
796 | mutex_unlock(&local->sta_mtx); | 809 | mutex_unlock(&local->sta_mtx); |
797 | } else switch (sdata->vif.type) { | 810 | } else switch (sdata->vif.type) { |
@@ -844,9 +857,13 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
844 | 857 | ||
845 | /* and set some type-dependent values */ | 858 | /* and set some type-dependent values */ |
846 | sdata->vif.type = type; | 859 | sdata->vif.type = type; |
860 | sdata->vif.p2p = false; | ||
847 | sdata->dev->netdev_ops = &ieee80211_dataif_ops; | 861 | sdata->dev->netdev_ops = &ieee80211_dataif_ops; |
848 | sdata->wdev.iftype = type; | 862 | sdata->wdev.iftype = type; |
849 | 863 | ||
864 | sdata->control_port_protocol = cpu_to_be16(ETH_P_PAE); | ||
865 | sdata->control_port_no_encrypt = false; | ||
866 | |||
850 | /* only monitor differs */ | 867 | /* only monitor differs */ |
851 | sdata->dev->type = ARPHRD_ETHER; | 868 | sdata->dev->type = ARPHRD_ETHER; |
852 | 869 | ||
@@ -854,10 +871,20 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
854 | INIT_WORK(&sdata->work, ieee80211_iface_work); | 871 | INIT_WORK(&sdata->work, ieee80211_iface_work); |
855 | 872 | ||
856 | switch (type) { | 873 | switch (type) { |
874 | case NL80211_IFTYPE_P2P_GO: | ||
875 | type = NL80211_IFTYPE_AP; | ||
876 | sdata->vif.type = type; | ||
877 | sdata->vif.p2p = true; | ||
878 | /* fall through */ | ||
857 | case NL80211_IFTYPE_AP: | 879 | case NL80211_IFTYPE_AP: |
858 | skb_queue_head_init(&sdata->u.ap.ps_bc_buf); | 880 | skb_queue_head_init(&sdata->u.ap.ps_bc_buf); |
859 | INIT_LIST_HEAD(&sdata->u.ap.vlans); | 881 | INIT_LIST_HEAD(&sdata->u.ap.vlans); |
860 | break; | 882 | break; |
883 | case NL80211_IFTYPE_P2P_CLIENT: | ||
884 | type = NL80211_IFTYPE_STATION; | ||
885 | sdata->vif.type = type; | ||
886 | sdata->vif.p2p = true; | ||
887 | /* fall through */ | ||
861 | case NL80211_IFTYPE_STATION: | 888 | case NL80211_IFTYPE_STATION: |
862 | ieee80211_sta_setup_sdata(sdata); | 889 | ieee80211_sta_setup_sdata(sdata); |
863 | break; | 890 | break; |
@@ -878,7 +905,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
878 | case NL80211_IFTYPE_AP_VLAN: | 905 | case NL80211_IFTYPE_AP_VLAN: |
879 | break; | 906 | break; |
880 | case NL80211_IFTYPE_UNSPECIFIED: | 907 | case NL80211_IFTYPE_UNSPECIFIED: |
881 | case __NL80211_IFTYPE_AFTER_LAST: | 908 | case NUM_NL80211_IFTYPES: |
882 | BUG(); | 909 | BUG(); |
883 | break; | 910 | break; |
884 | } | 911 | } |
@@ -886,12 +913,85 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
886 | ieee80211_debugfs_add_netdev(sdata); | 913 | ieee80211_debugfs_add_netdev(sdata); |
887 | } | 914 | } |
888 | 915 | ||
916 | static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata, | ||
917 | enum nl80211_iftype type) | ||
918 | { | ||
919 | struct ieee80211_local *local = sdata->local; | ||
920 | int ret, err; | ||
921 | enum nl80211_iftype internal_type = type; | ||
922 | bool p2p = false; | ||
923 | |||
924 | ASSERT_RTNL(); | ||
925 | |||
926 | if (!local->ops->change_interface) | ||
927 | return -EBUSY; | ||
928 | |||
929 | switch (sdata->vif.type) { | ||
930 | case NL80211_IFTYPE_AP: | ||
931 | case NL80211_IFTYPE_STATION: | ||
932 | case NL80211_IFTYPE_ADHOC: | ||
933 | /* | ||
934 | * Could maybe also all others here? | ||
935 | * Just not sure how that interacts | ||
936 | * with the RX/config path e.g. for | ||
937 | * mesh. | ||
938 | */ | ||
939 | break; | ||
940 | default: | ||
941 | return -EBUSY; | ||
942 | } | ||
943 | |||
944 | switch (type) { | ||
945 | case NL80211_IFTYPE_AP: | ||
946 | case NL80211_IFTYPE_STATION: | ||
947 | case NL80211_IFTYPE_ADHOC: | ||
948 | /* | ||
949 | * Could probably support everything | ||
950 | * but WDS here (WDS do_open can fail | ||
951 | * under memory pressure, which this | ||
952 | * code isn't prepared to handle). | ||
953 | */ | ||
954 | break; | ||
955 | case NL80211_IFTYPE_P2P_CLIENT: | ||
956 | p2p = true; | ||
957 | internal_type = NL80211_IFTYPE_STATION; | ||
958 | break; | ||
959 | case NL80211_IFTYPE_P2P_GO: | ||
960 | p2p = true; | ||
961 | internal_type = NL80211_IFTYPE_AP; | ||
962 | break; | ||
963 | default: | ||
964 | return -EBUSY; | ||
965 | } | ||
966 | |||
967 | ret = ieee80211_check_concurrent_iface(sdata, internal_type); | ||
968 | if (ret) | ||
969 | return ret; | ||
970 | |||
971 | ieee80211_do_stop(sdata, false); | ||
972 | |||
973 | ieee80211_teardown_sdata(sdata->dev); | ||
974 | |||
975 | ret = drv_change_interface(local, sdata, internal_type, p2p); | ||
976 | if (ret) | ||
977 | type = sdata->vif.type; | ||
978 | |||
979 | ieee80211_setup_sdata(sdata, type); | ||
980 | |||
981 | err = ieee80211_do_open(sdata->dev, false); | ||
982 | WARN(err, "type change: do_open returned %d", err); | ||
983 | |||
984 | return ret; | ||
985 | } | ||
986 | |||
889 | int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, | 987 | int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, |
890 | enum nl80211_iftype type) | 988 | enum nl80211_iftype type) |
891 | { | 989 | { |
990 | int ret; | ||
991 | |||
892 | ASSERT_RTNL(); | 992 | ASSERT_RTNL(); |
893 | 993 | ||
894 | if (type == sdata->vif.type) | 994 | if (type == ieee80211_vif_type_p2p(&sdata->vif)) |
895 | return 0; | 995 | return 0; |
896 | 996 | ||
897 | /* Setting ad-hoc mode on non-IBSS channel is not supported. */ | 997 | /* Setting ad-hoc mode on non-IBSS channel is not supported. */ |
@@ -899,18 +999,15 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, | |||
899 | type == NL80211_IFTYPE_ADHOC) | 999 | type == NL80211_IFTYPE_ADHOC) |
900 | return -EOPNOTSUPP; | 1000 | return -EOPNOTSUPP; |
901 | 1001 | ||
902 | /* | 1002 | if (ieee80211_sdata_running(sdata)) { |
903 | * We could, here, on changes between IBSS/STA/MESH modes, | 1003 | ret = ieee80211_runtime_change_iftype(sdata, type); |
904 | * invoke an MLME function instead that disassociates etc. | 1004 | if (ret) |
905 | * and goes into the requested mode. | 1005 | return ret; |
906 | */ | 1006 | } else { |
907 | 1007 | /* Purge and reset type-dependent state. */ | |
908 | if (ieee80211_sdata_running(sdata)) | 1008 | ieee80211_teardown_sdata(sdata->dev); |
909 | return -EBUSY; | 1009 | ieee80211_setup_sdata(sdata, type); |
910 | 1010 | } | |
911 | /* Purge and reset type-dependent state. */ | ||
912 | ieee80211_teardown_sdata(sdata->dev); | ||
913 | ieee80211_setup_sdata(sdata, type); | ||
914 | 1011 | ||
915 | /* reset some values that shouldn't be kept across type changes */ | 1012 | /* reset some values that shouldn't be kept across type changes */ |
916 | sdata->vif.bss_conf.basic_rates = | 1013 | sdata->vif.bss_conf.basic_rates = |
@@ -1167,8 +1264,7 @@ static u32 ieee80211_idle_off(struct ieee80211_local *local, | |||
1167 | return 0; | 1264 | return 0; |
1168 | 1265 | ||
1169 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 1266 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
1170 | printk(KERN_DEBUG "%s: device no longer idle - %s\n", | 1267 | wiphy_debug(local->hw.wiphy, "device no longer idle - %s\n", reason); |
1171 | wiphy_name(local->hw.wiphy), reason); | ||
1172 | #endif | 1268 | #endif |
1173 | 1269 | ||
1174 | local->hw.conf.flags &= ~IEEE80211_CONF_IDLE; | 1270 | local->hw.conf.flags &= ~IEEE80211_CONF_IDLE; |
@@ -1181,8 +1277,7 @@ static u32 ieee80211_idle_on(struct ieee80211_local *local) | |||
1181 | return 0; | 1277 | return 0; |
1182 | 1278 | ||
1183 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 1279 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
1184 | printk(KERN_DEBUG "%s: device now idle\n", | 1280 | wiphy_debug(local->hw.wiphy, "device now idle\n"); |
1185 | wiphy_name(local->hw.wiphy)); | ||
1186 | #endif | 1281 | #endif |
1187 | 1282 | ||
1188 | drv_flush(local, false); | 1283 | drv_flush(local, false); |
@@ -1195,28 +1290,61 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | |||
1195 | { | 1290 | { |
1196 | struct ieee80211_sub_if_data *sdata; | 1291 | struct ieee80211_sub_if_data *sdata; |
1197 | int count = 0; | 1292 | int count = 0; |
1293 | bool working = false, scanning = false; | ||
1294 | struct ieee80211_work *wk; | ||
1198 | 1295 | ||
1199 | if (!list_empty(&local->work_list)) | 1296 | #ifdef CONFIG_PROVE_LOCKING |
1200 | return ieee80211_idle_off(local, "working"); | 1297 | WARN_ON(debug_locks && !lockdep_rtnl_is_held() && |
1201 | 1298 | !lockdep_is_held(&local->iflist_mtx)); | |
1202 | if (local->scanning) | 1299 | #endif |
1203 | return ieee80211_idle_off(local, "scanning"); | 1300 | lockdep_assert_held(&local->mtx); |
1204 | 1301 | ||
1205 | list_for_each_entry(sdata, &local->interfaces, list) { | 1302 | list_for_each_entry(sdata, &local->interfaces, list) { |
1206 | if (!ieee80211_sdata_running(sdata)) | 1303 | if (!ieee80211_sdata_running(sdata)) { |
1304 | sdata->vif.bss_conf.idle = true; | ||
1207 | continue; | 1305 | continue; |
1306 | } | ||
1307 | |||
1308 | sdata->old_idle = sdata->vif.bss_conf.idle; | ||
1309 | |||
1208 | /* do not count disabled managed interfaces */ | 1310 | /* do not count disabled managed interfaces */ |
1209 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | 1311 | if (sdata->vif.type == NL80211_IFTYPE_STATION && |
1210 | !sdata->u.mgd.associated) | 1312 | !sdata->u.mgd.associated) { |
1313 | sdata->vif.bss_conf.idle = true; | ||
1211 | continue; | 1314 | continue; |
1315 | } | ||
1212 | /* do not count unused IBSS interfaces */ | 1316 | /* do not count unused IBSS interfaces */ |
1213 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && | 1317 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && |
1214 | !sdata->u.ibss.ssid_len) | 1318 | !sdata->u.ibss.ssid_len) { |
1319 | sdata->vif.bss_conf.idle = true; | ||
1215 | continue; | 1320 | continue; |
1321 | } | ||
1216 | /* count everything else */ | 1322 | /* count everything else */ |
1217 | count++; | 1323 | count++; |
1218 | } | 1324 | } |
1219 | 1325 | ||
1326 | list_for_each_entry(wk, &local->work_list, list) { | ||
1327 | working = true; | ||
1328 | wk->sdata->vif.bss_conf.idle = false; | ||
1329 | } | ||
1330 | |||
1331 | if (local->scan_sdata) { | ||
1332 | scanning = true; | ||
1333 | local->scan_sdata->vif.bss_conf.idle = false; | ||
1334 | } | ||
1335 | |||
1336 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
1337 | if (sdata->old_idle == sdata->vif.bss_conf.idle) | ||
1338 | continue; | ||
1339 | if (!ieee80211_sdata_running(sdata)) | ||
1340 | continue; | ||
1341 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); | ||
1342 | } | ||
1343 | |||
1344 | if (working) | ||
1345 | return ieee80211_idle_off(local, "working"); | ||
1346 | if (scanning) | ||
1347 | return ieee80211_idle_off(local, "scanning"); | ||
1220 | if (!count) | 1348 | if (!count) |
1221 | return ieee80211_idle_on(local); | 1349 | return ieee80211_idle_on(local); |
1222 | else | 1350 | else |