diff options
Diffstat (limited to 'net/mac80211/iface.c')
-rw-r--r-- | net/mac80211/iface.c | 401 |
1 files changed, 259 insertions, 142 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index ebbe264e2b0..66785739dad 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -94,21 +94,14 @@ static inline int identical_mac_addr_allowed(int type1, int type2) | |||
94 | type2 == NL80211_IFTYPE_AP_VLAN)); | 94 | type2 == NL80211_IFTYPE_AP_VLAN)); |
95 | } | 95 | } |
96 | 96 | ||
97 | static int ieee80211_open(struct net_device *dev) | 97 | static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata, |
98 | enum nl80211_iftype iftype) | ||
98 | { | 99 | { |
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; | 100 | struct ieee80211_local *local = sdata->local; |
102 | struct sta_info *sta; | 101 | struct ieee80211_sub_if_data *nsdata; |
103 | u32 changed = 0; | 102 | struct net_device *dev = sdata->dev; |
104 | int res; | ||
105 | u32 hw_reconf_flags = 0; | ||
106 | u8 null_addr[ETH_ALEN] = {0}; | ||
107 | 103 | ||
108 | /* fail early if user set an invalid address */ | 104 | ASSERT_RTNL(); |
109 | if (compare_ether_addr(dev->dev_addr, null_addr) && | ||
110 | !is_valid_ether_addr(dev->dev_addr)) | ||
111 | return -EADDRNOTAVAIL; | ||
112 | 105 | ||
113 | /* we hold the RTNL here so can safely walk the list */ | 106 | /* we hold the RTNL here so can safely walk the list */ |
114 | list_for_each_entry(nsdata, &local->interfaces, list) { | 107 | list_for_each_entry(nsdata, &local->interfaces, list) { |
@@ -125,7 +118,7 @@ static int ieee80211_open(struct net_device *dev) | |||
125 | * belonging to the same hardware. Then, however, we're | 118 | * belonging to the same hardware. Then, however, we're |
126 | * faced with having to adopt two different TSF timers... | 119 | * faced with having to adopt two different TSF timers... |
127 | */ | 120 | */ |
128 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && | 121 | if (iftype == NL80211_IFTYPE_ADHOC && |
129 | nsdata->vif.type == NL80211_IFTYPE_ADHOC) | 122 | nsdata->vif.type == NL80211_IFTYPE_ADHOC) |
130 | return -EBUSY; | 123 | return -EBUSY; |
131 | 124 | ||
@@ -139,19 +132,36 @@ static int ieee80211_open(struct net_device *dev) | |||
139 | /* | 132 | /* |
140 | * check whether it may have the same address | 133 | * check whether it may have the same address |
141 | */ | 134 | */ |
142 | if (!identical_mac_addr_allowed(sdata->vif.type, | 135 | if (!identical_mac_addr_allowed(iftype, |
143 | nsdata->vif.type)) | 136 | nsdata->vif.type)) |
144 | return -ENOTUNIQ; | 137 | return -ENOTUNIQ; |
145 | 138 | ||
146 | /* | 139 | /* |
147 | * can only add VLANs to enabled APs | 140 | * can only add VLANs to enabled APs |
148 | */ | 141 | */ |
149 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN && | 142 | if (iftype == NL80211_IFTYPE_AP_VLAN && |
150 | nsdata->vif.type == NL80211_IFTYPE_AP) | 143 | nsdata->vif.type == NL80211_IFTYPE_AP) |
151 | sdata->bss = &nsdata->u.ap; | 144 | sdata->bss = &nsdata->u.ap; |
152 | } | 145 | } |
153 | } | 146 | } |
154 | 147 | ||
148 | return 0; | ||
149 | } | ||
150 | |||
151 | /* | ||
152 | * NOTE: Be very careful when changing this function, it must NOT return | ||
153 | * an error on interface type changes that have been pre-checked, so most | ||
154 | * checks should be in ieee80211_check_concurrent_iface. | ||
155 | */ | ||
156 | static int ieee80211_do_open(struct net_device *dev, bool coming_up) | ||
157 | { | ||
158 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
159 | struct ieee80211_local *local = sdata->local; | ||
160 | struct sta_info *sta; | ||
161 | u32 changed = 0; | ||
162 | int res; | ||
163 | u32 hw_reconf_flags = 0; | ||
164 | |||
155 | switch (sdata->vif.type) { | 165 | switch (sdata->vif.type) { |
156 | case NL80211_IFTYPE_WDS: | 166 | case NL80211_IFTYPE_WDS: |
157 | if (!is_valid_ether_addr(sdata->u.wds.remote_addr)) | 167 | if (!is_valid_ether_addr(sdata->u.wds.remote_addr)) |
@@ -177,7 +187,9 @@ static int ieee80211_open(struct net_device *dev) | |||
177 | /* no special treatment */ | 187 | /* no special treatment */ |
178 | break; | 188 | break; |
179 | case NL80211_IFTYPE_UNSPECIFIED: | 189 | case NL80211_IFTYPE_UNSPECIFIED: |
180 | case __NL80211_IFTYPE_AFTER_LAST: | 190 | case NUM_NL80211_IFTYPES: |
191 | case NL80211_IFTYPE_P2P_CLIENT: | ||
192 | case NL80211_IFTYPE_P2P_GO: | ||
181 | /* cannot happen */ | 193 | /* cannot happen */ |
182 | WARN_ON(1); | 194 | WARN_ON(1); |
183 | break; | 195 | break; |
@@ -187,39 +199,30 @@ static int ieee80211_open(struct net_device *dev) | |||
187 | res = drv_start(local); | 199 | res = drv_start(local); |
188 | if (res) | 200 | if (res) |
189 | goto err_del_bss; | 201 | goto err_del_bss; |
202 | if (local->ops->napi_poll) | ||
203 | napi_enable(&local->napi); | ||
190 | /* we're brought up, everything changes */ | 204 | /* we're brought up, everything changes */ |
191 | hw_reconf_flags = ~0; | 205 | hw_reconf_flags = ~0; |
192 | ieee80211_led_radio(local, true); | 206 | ieee80211_led_radio(local, true); |
193 | } | 207 | } |
194 | 208 | ||
195 | /* | 209 | /* |
196 | * Check all interfaces and copy the hopefully now-present | 210 | * Copy the hopefully now-present MAC address to |
197 | * MAC address to those that have the special null one. | 211 | * this interface, if it has the special null one. |
198 | */ | 212 | */ |
199 | list_for_each_entry(nsdata, &local->interfaces, list) { | 213 | if (is_zero_ether_addr(dev->dev_addr)) { |
200 | struct net_device *ndev = nsdata->dev; | 214 | memcpy(dev->dev_addr, |
201 | 215 | local->hw.wiphy->perm_addr, | |
202 | /* | 216 | ETH_ALEN); |
203 | * No need to check running since we do not allow | 217 | memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN); |
204 | * it to start up with this invalid address. | 218 | |
205 | */ | 219 | if (!is_valid_ether_addr(dev->dev_addr)) { |
206 | if (compare_ether_addr(null_addr, ndev->dev_addr) == 0) { | 220 | if (!local->open_count) |
207 | memcpy(ndev->dev_addr, | 221 | drv_stop(local); |
208 | local->hw.wiphy->perm_addr, | 222 | return -EADDRNOTAVAIL; |
209 | ETH_ALEN); | ||
210 | memcpy(ndev->perm_addr, ndev->dev_addr, ETH_ALEN); | ||
211 | } | 223 | } |
212 | } | 224 | } |
213 | 225 | ||
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) { | 226 | switch (sdata->vif.type) { |
224 | case NL80211_IFTYPE_AP_VLAN: | 227 | case NL80211_IFTYPE_AP_VLAN: |
225 | /* no need to tell driver */ | 228 | /* no need to tell driver */ |
@@ -253,9 +256,11 @@ static int ieee80211_open(struct net_device *dev) | |||
253 | netif_carrier_on(dev); | 256 | netif_carrier_on(dev); |
254 | break; | 257 | break; |
255 | default: | 258 | default: |
256 | res = drv_add_interface(local, &sdata->vif); | 259 | if (coming_up) { |
257 | if (res) | 260 | res = drv_add_interface(local, &sdata->vif); |
258 | goto err_stop; | 261 | if (res) |
262 | goto err_stop; | ||
263 | } | ||
259 | 264 | ||
260 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 265 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
261 | local->fif_other_bss++; | 266 | local->fif_other_bss++; |
@@ -277,6 +282,8 @@ static int ieee80211_open(struct net_device *dev) | |||
277 | netif_carrier_on(dev); | 282 | netif_carrier_on(dev); |
278 | } | 283 | } |
279 | 284 | ||
285 | set_bit(SDATA_STATE_RUNNING, &sdata->state); | ||
286 | |||
280 | if (sdata->vif.type == NL80211_IFTYPE_WDS) { | 287 | if (sdata->vif.type == NL80211_IFTYPE_WDS) { |
281 | /* Create STA entry for the WDS peer */ | 288 | /* Create STA entry for the WDS peer */ |
282 | sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr, | 289 | sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr, |
@@ -307,9 +314,13 @@ static int ieee80211_open(struct net_device *dev) | |||
307 | if (sdata->flags & IEEE80211_SDATA_PROMISC) | 314 | if (sdata->flags & IEEE80211_SDATA_PROMISC) |
308 | atomic_inc(&local->iff_promiscs); | 315 | atomic_inc(&local->iff_promiscs); |
309 | 316 | ||
317 | mutex_lock(&local->mtx); | ||
310 | hw_reconf_flags |= __ieee80211_recalc_idle(local); | 318 | hw_reconf_flags |= __ieee80211_recalc_idle(local); |
319 | mutex_unlock(&local->mtx); | ||
320 | |||
321 | if (coming_up) | ||
322 | local->open_count++; | ||
311 | 323 | ||
312 | local->open_count++; | ||
313 | if (hw_reconf_flags) { | 324 | if (hw_reconf_flags) { |
314 | ieee80211_hw_config(local, hw_reconf_flags); | 325 | ieee80211_hw_config(local, hw_reconf_flags); |
315 | /* | 326 | /* |
@@ -334,22 +345,42 @@ static int ieee80211_open(struct net_device *dev) | |||
334 | sdata->bss = NULL; | 345 | sdata->bss = NULL; |
335 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 346 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
336 | list_del(&sdata->u.vlan.list); | 347 | list_del(&sdata->u.vlan.list); |
348 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); | ||
337 | return res; | 349 | return res; |
338 | } | 350 | } |
339 | 351 | ||
340 | static int ieee80211_stop(struct net_device *dev) | 352 | static int ieee80211_open(struct net_device *dev) |
341 | { | 353 | { |
342 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 354 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
355 | int err; | ||
356 | |||
357 | /* fail early if user set an invalid address */ | ||
358 | if (!is_zero_ether_addr(dev->dev_addr) && | ||
359 | !is_valid_ether_addr(dev->dev_addr)) | ||
360 | return -EADDRNOTAVAIL; | ||
361 | |||
362 | err = ieee80211_check_concurrent_iface(sdata, sdata->vif.type); | ||
363 | if (err) | ||
364 | return err; | ||
365 | |||
366 | return ieee80211_do_open(dev, true); | ||
367 | } | ||
368 | |||
369 | static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | ||
370 | bool going_down) | ||
371 | { | ||
343 | struct ieee80211_local *local = sdata->local; | 372 | struct ieee80211_local *local = sdata->local; |
344 | unsigned long flags; | 373 | unsigned long flags; |
345 | struct sk_buff *skb, *tmp; | 374 | struct sk_buff *skb, *tmp; |
346 | u32 hw_reconf_flags = 0; | 375 | u32 hw_reconf_flags = 0; |
347 | int i; | 376 | int i; |
348 | 377 | ||
378 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); | ||
379 | |||
349 | /* | 380 | /* |
350 | * Stop TX on this interface first. | 381 | * Stop TX on this interface first. |
351 | */ | 382 | */ |
352 | netif_tx_stop_all_queues(dev); | 383 | netif_tx_stop_all_queues(sdata->dev); |
353 | 384 | ||
354 | /* | 385 | /* |
355 | * Purge work for this interface. | 386 | * Purge work for this interface. |
@@ -366,12 +397,9 @@ static int ieee80211_stop(struct net_device *dev) | |||
366 | * (because if we remove a STA after ops->remove_interface() | 397 | * (because if we remove a STA after ops->remove_interface() |
367 | * the driver will have removed the vif info already!) | 398 | * the driver will have removed the vif info already!) |
368 | * | 399 | * |
369 | * We could relax this and only unlink the stations from the | 400 | * 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 | 401 | * all other modes we've already removed all stations when |
371 | * will be inserted back again when the interface is brought | 402 | * 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 | */ | 403 | */ |
376 | sta_info_flush(local, sdata); | 404 | sta_info_flush(local, sdata); |
377 | 405 | ||
@@ -390,11 +418,12 @@ static int ieee80211_stop(struct net_device *dev) | |||
390 | if (sdata->vif.type == NL80211_IFTYPE_AP) | 418 | if (sdata->vif.type == NL80211_IFTYPE_AP) |
391 | local->fif_pspoll--; | 419 | local->fif_pspoll--; |
392 | 420 | ||
393 | netif_addr_lock_bh(dev); | 421 | netif_addr_lock_bh(sdata->dev); |
394 | spin_lock_bh(&local->filter_lock); | 422 | spin_lock_bh(&local->filter_lock); |
395 | __hw_addr_unsync(&local->mc_list, &dev->mc, dev->addr_len); | 423 | __hw_addr_unsync(&local->mc_list, &sdata->dev->mc, |
424 | sdata->dev->addr_len); | ||
396 | spin_unlock_bh(&local->filter_lock); | 425 | spin_unlock_bh(&local->filter_lock); |
397 | netif_addr_unlock_bh(dev); | 426 | netif_addr_unlock_bh(sdata->dev); |
398 | 427 | ||
399 | ieee80211_configure_filter(local); | 428 | ieee80211_configure_filter(local); |
400 | 429 | ||
@@ -406,11 +435,21 @@ static int ieee80211_stop(struct net_device *dev) | |||
406 | struct ieee80211_sub_if_data *vlan, *tmpsdata; | 435 | struct ieee80211_sub_if_data *vlan, *tmpsdata; |
407 | struct beacon_data *old_beacon = sdata->u.ap.beacon; | 436 | struct beacon_data *old_beacon = sdata->u.ap.beacon; |
408 | 437 | ||
438 | /* sdata_running will return false, so this will disable */ | ||
439 | ieee80211_bss_info_change_notify(sdata, | ||
440 | BSS_CHANGED_BEACON_ENABLED); | ||
441 | |||
409 | /* remove beacon */ | 442 | /* remove beacon */ |
410 | rcu_assign_pointer(sdata->u.ap.beacon, NULL); | 443 | rcu_assign_pointer(sdata->u.ap.beacon, NULL); |
411 | synchronize_rcu(); | 444 | synchronize_rcu(); |
412 | kfree(old_beacon); | 445 | kfree(old_beacon); |
413 | 446 | ||
447 | /* free all potentially still buffered bcast frames */ | ||
448 | while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) { | ||
449 | local->total_ps_buffered--; | ||
450 | dev_kfree_skb(skb); | ||
451 | } | ||
452 | |||
414 | /* down all dependent devices, that is VLANs */ | 453 | /* down all dependent devices, that is VLANs */ |
415 | list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans, | 454 | list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans, |
416 | u.vlan.list) | 455 | u.vlan.list) |
@@ -418,7 +457,8 @@ static int ieee80211_stop(struct net_device *dev) | |||
418 | WARN_ON(!list_empty(&sdata->u.ap.vlans)); | 457 | WARN_ON(!list_empty(&sdata->u.ap.vlans)); |
419 | } | 458 | } |
420 | 459 | ||
421 | local->open_count--; | 460 | if (going_down) |
461 | local->open_count--; | ||
422 | 462 | ||
423 | switch (sdata->vif.type) { | 463 | switch (sdata->vif.type) { |
424 | case NL80211_IFTYPE_AP_VLAN: | 464 | case NL80211_IFTYPE_AP_VLAN: |
@@ -450,27 +490,6 @@ static int ieee80211_stop(struct net_device *dev) | |||
450 | 490 | ||
451 | ieee80211_configure_filter(local); | 491 | ieee80211_configure_filter(local); |
452 | break; | 492 | 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: | 493 | case NL80211_IFTYPE_MESH_POINT: |
475 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 494 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
476 | /* other_bss and allmulti are always set on mesh | 495 | /* other_bss and allmulti are always set on mesh |
@@ -498,27 +517,34 @@ static int ieee80211_stop(struct net_device *dev) | |||
498 | ieee80211_scan_cancel(local); | 517 | ieee80211_scan_cancel(local); |
499 | 518 | ||
500 | /* | 519 | /* |
501 | * Disable beaconing for AP and mesh, IBSS can't | 520 | * Disable beaconing here for mesh only, AP and IBSS |
502 | * still be joined to a network at this point. | 521 | * are already taken care of. |
503 | */ | 522 | */ |
504 | if (sdata->vif.type == NL80211_IFTYPE_AP || | 523 | if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT) |
505 | sdata->vif.type == NL80211_IFTYPE_MESH_POINT) { | ||
506 | ieee80211_bss_info_change_notify(sdata, | 524 | ieee80211_bss_info_change_notify(sdata, |
507 | BSS_CHANGED_BEACON_ENABLED); | 525 | BSS_CHANGED_BEACON_ENABLED); |
508 | } | ||
509 | 526 | ||
510 | /* free all remaining keys, there shouldn't be any */ | 527 | /* |
528 | * Free all remaining keys, there shouldn't be any, | ||
529 | * except maybe group keys in AP more or WDS? | ||
530 | */ | ||
511 | ieee80211_free_keys(sdata); | 531 | ieee80211_free_keys(sdata); |
512 | drv_remove_interface(local, &sdata->vif); | 532 | |
533 | if (going_down) | ||
534 | drv_remove_interface(local, &sdata->vif); | ||
513 | } | 535 | } |
514 | 536 | ||
515 | sdata->bss = NULL; | 537 | sdata->bss = NULL; |
516 | 538 | ||
539 | mutex_lock(&local->mtx); | ||
517 | hw_reconf_flags |= __ieee80211_recalc_idle(local); | 540 | hw_reconf_flags |= __ieee80211_recalc_idle(local); |
541 | mutex_unlock(&local->mtx); | ||
518 | 542 | ||
519 | ieee80211_recalc_ps(local, -1); | 543 | ieee80211_recalc_ps(local, -1); |
520 | 544 | ||
521 | if (local->open_count == 0) { | 545 | if (local->open_count == 0) { |
546 | if (local->ops->napi_poll) | ||
547 | napi_disable(&local->napi); | ||
522 | ieee80211_clear_tx_pending(local); | 548 | ieee80211_clear_tx_pending(local); |
523 | ieee80211_stop_device(local); | 549 | ieee80211_stop_device(local); |
524 | 550 | ||
@@ -541,6 +567,13 @@ static int ieee80211_stop(struct net_device *dev) | |||
541 | } | 567 | } |
542 | } | 568 | } |
543 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 569 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
570 | } | ||
571 | |||
572 | static int ieee80211_stop(struct net_device *dev) | ||
573 | { | ||
574 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
575 | |||
576 | ieee80211_do_stop(sdata, true); | ||
544 | 577 | ||
545 | return 0; | 578 | return 0; |
546 | } | 579 | } |
@@ -585,8 +618,6 @@ static void ieee80211_teardown_sdata(struct net_device *dev) | |||
585 | { | 618 | { |
586 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 619 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
587 | struct ieee80211_local *local = sdata->local; | 620 | struct ieee80211_local *local = sdata->local; |
588 | struct beacon_data *beacon; | ||
589 | struct sk_buff *skb; | ||
590 | int flushed; | 621 | int flushed; |
591 | int i; | 622 | int i; |
592 | 623 | ||
@@ -599,37 +630,8 @@ static void ieee80211_teardown_sdata(struct net_device *dev) | |||
599 | __skb_queue_purge(&sdata->fragments[i].skb_list); | 630 | __skb_queue_purge(&sdata->fragments[i].skb_list); |
600 | sdata->fragment_next = 0; | 631 | sdata->fragment_next = 0; |
601 | 632 | ||
602 | switch (sdata->vif.type) { | 633 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
603 | case NL80211_IFTYPE_AP: | 634 | 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 | 635 | ||
634 | flushed = sta_info_flush(local, sdata); | 636 | flushed = sta_info_flush(local, sdata); |
635 | WARN_ON(flushed); | 637 | WARN_ON(flushed); |
@@ -844,9 +846,13 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
844 | 846 | ||
845 | /* and set some type-dependent values */ | 847 | /* and set some type-dependent values */ |
846 | sdata->vif.type = type; | 848 | sdata->vif.type = type; |
849 | sdata->vif.p2p = false; | ||
847 | sdata->dev->netdev_ops = &ieee80211_dataif_ops; | 850 | sdata->dev->netdev_ops = &ieee80211_dataif_ops; |
848 | sdata->wdev.iftype = type; | 851 | sdata->wdev.iftype = type; |
849 | 852 | ||
853 | sdata->control_port_protocol = cpu_to_be16(ETH_P_PAE); | ||
854 | sdata->control_port_no_encrypt = false; | ||
855 | |||
850 | /* only monitor differs */ | 856 | /* only monitor differs */ |
851 | sdata->dev->type = ARPHRD_ETHER; | 857 | sdata->dev->type = ARPHRD_ETHER; |
852 | 858 | ||
@@ -854,10 +860,20 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
854 | INIT_WORK(&sdata->work, ieee80211_iface_work); | 860 | INIT_WORK(&sdata->work, ieee80211_iface_work); |
855 | 861 | ||
856 | switch (type) { | 862 | switch (type) { |
863 | case NL80211_IFTYPE_P2P_GO: | ||
864 | type = NL80211_IFTYPE_AP; | ||
865 | sdata->vif.type = type; | ||
866 | sdata->vif.p2p = true; | ||
867 | /* fall through */ | ||
857 | case NL80211_IFTYPE_AP: | 868 | case NL80211_IFTYPE_AP: |
858 | skb_queue_head_init(&sdata->u.ap.ps_bc_buf); | 869 | skb_queue_head_init(&sdata->u.ap.ps_bc_buf); |
859 | INIT_LIST_HEAD(&sdata->u.ap.vlans); | 870 | INIT_LIST_HEAD(&sdata->u.ap.vlans); |
860 | break; | 871 | break; |
872 | case NL80211_IFTYPE_P2P_CLIENT: | ||
873 | type = NL80211_IFTYPE_STATION; | ||
874 | sdata->vif.type = type; | ||
875 | sdata->vif.p2p = true; | ||
876 | /* fall through */ | ||
861 | case NL80211_IFTYPE_STATION: | 877 | case NL80211_IFTYPE_STATION: |
862 | ieee80211_sta_setup_sdata(sdata); | 878 | ieee80211_sta_setup_sdata(sdata); |
863 | break; | 879 | break; |
@@ -878,7 +894,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
878 | case NL80211_IFTYPE_AP_VLAN: | 894 | case NL80211_IFTYPE_AP_VLAN: |
879 | break; | 895 | break; |
880 | case NL80211_IFTYPE_UNSPECIFIED: | 896 | case NL80211_IFTYPE_UNSPECIFIED: |
881 | case __NL80211_IFTYPE_AFTER_LAST: | 897 | case NUM_NL80211_IFTYPES: |
882 | BUG(); | 898 | BUG(); |
883 | break; | 899 | break; |
884 | } | 900 | } |
@@ -886,12 +902,85 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
886 | ieee80211_debugfs_add_netdev(sdata); | 902 | ieee80211_debugfs_add_netdev(sdata); |
887 | } | 903 | } |
888 | 904 | ||
905 | static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata, | ||
906 | enum nl80211_iftype type) | ||
907 | { | ||
908 | struct ieee80211_local *local = sdata->local; | ||
909 | int ret, err; | ||
910 | enum nl80211_iftype internal_type = type; | ||
911 | bool p2p = false; | ||
912 | |||
913 | ASSERT_RTNL(); | ||
914 | |||
915 | if (!local->ops->change_interface) | ||
916 | return -EBUSY; | ||
917 | |||
918 | switch (sdata->vif.type) { | ||
919 | case NL80211_IFTYPE_AP: | ||
920 | case NL80211_IFTYPE_STATION: | ||
921 | case NL80211_IFTYPE_ADHOC: | ||
922 | /* | ||
923 | * Could maybe also all others here? | ||
924 | * Just not sure how that interacts | ||
925 | * with the RX/config path e.g. for | ||
926 | * mesh. | ||
927 | */ | ||
928 | break; | ||
929 | default: | ||
930 | return -EBUSY; | ||
931 | } | ||
932 | |||
933 | switch (type) { | ||
934 | case NL80211_IFTYPE_AP: | ||
935 | case NL80211_IFTYPE_STATION: | ||
936 | case NL80211_IFTYPE_ADHOC: | ||
937 | /* | ||
938 | * Could probably support everything | ||
939 | * but WDS here (WDS do_open can fail | ||
940 | * under memory pressure, which this | ||
941 | * code isn't prepared to handle). | ||
942 | */ | ||
943 | break; | ||
944 | case NL80211_IFTYPE_P2P_CLIENT: | ||
945 | p2p = true; | ||
946 | internal_type = NL80211_IFTYPE_STATION; | ||
947 | break; | ||
948 | case NL80211_IFTYPE_P2P_GO: | ||
949 | p2p = true; | ||
950 | internal_type = NL80211_IFTYPE_AP; | ||
951 | break; | ||
952 | default: | ||
953 | return -EBUSY; | ||
954 | } | ||
955 | |||
956 | ret = ieee80211_check_concurrent_iface(sdata, internal_type); | ||
957 | if (ret) | ||
958 | return ret; | ||
959 | |||
960 | ieee80211_do_stop(sdata, false); | ||
961 | |||
962 | ieee80211_teardown_sdata(sdata->dev); | ||
963 | |||
964 | ret = drv_change_interface(local, sdata, internal_type, p2p); | ||
965 | if (ret) | ||
966 | type = sdata->vif.type; | ||
967 | |||
968 | ieee80211_setup_sdata(sdata, type); | ||
969 | |||
970 | err = ieee80211_do_open(sdata->dev, false); | ||
971 | WARN(err, "type change: do_open returned %d", err); | ||
972 | |||
973 | return ret; | ||
974 | } | ||
975 | |||
889 | int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, | 976 | int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, |
890 | enum nl80211_iftype type) | 977 | enum nl80211_iftype type) |
891 | { | 978 | { |
979 | int ret; | ||
980 | |||
892 | ASSERT_RTNL(); | 981 | ASSERT_RTNL(); |
893 | 982 | ||
894 | if (type == sdata->vif.type) | 983 | if (type == ieee80211_vif_type_p2p(&sdata->vif)) |
895 | return 0; | 984 | return 0; |
896 | 985 | ||
897 | /* Setting ad-hoc mode on non-IBSS channel is not supported. */ | 986 | /* Setting ad-hoc mode on non-IBSS channel is not supported. */ |
@@ -899,18 +988,15 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, | |||
899 | type == NL80211_IFTYPE_ADHOC) | 988 | type == NL80211_IFTYPE_ADHOC) |
900 | return -EOPNOTSUPP; | 989 | return -EOPNOTSUPP; |
901 | 990 | ||
902 | /* | 991 | if (ieee80211_sdata_running(sdata)) { |
903 | * We could, here, on changes between IBSS/STA/MESH modes, | 992 | ret = ieee80211_runtime_change_iftype(sdata, type); |
904 | * invoke an MLME function instead that disassociates etc. | 993 | if (ret) |
905 | * and goes into the requested mode. | 994 | return ret; |
906 | */ | 995 | } else { |
907 | 996 | /* Purge and reset type-dependent state. */ | |
908 | if (ieee80211_sdata_running(sdata)) | 997 | ieee80211_teardown_sdata(sdata->dev); |
909 | return -EBUSY; | 998 | ieee80211_setup_sdata(sdata, type); |
910 | 999 | } | |
911 | /* Purge and reset type-dependent state. */ | ||
912 | ieee80211_teardown_sdata(sdata->dev); | ||
913 | ieee80211_setup_sdata(sdata, type); | ||
914 | 1000 | ||
915 | /* reset some values that shouldn't be kept across type changes */ | 1001 | /* reset some values that shouldn't be kept across type changes */ |
916 | sdata->vif.bss_conf.basic_rates = | 1002 | sdata->vif.bss_conf.basic_rates = |
@@ -1167,8 +1253,7 @@ static u32 ieee80211_idle_off(struct ieee80211_local *local, | |||
1167 | return 0; | 1253 | return 0; |
1168 | 1254 | ||
1169 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 1255 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
1170 | printk(KERN_DEBUG "%s: device no longer idle - %s\n", | 1256 | wiphy_debug(local->hw.wiphy, "device no longer idle - %s\n", reason); |
1171 | wiphy_name(local->hw.wiphy), reason); | ||
1172 | #endif | 1257 | #endif |
1173 | 1258 | ||
1174 | local->hw.conf.flags &= ~IEEE80211_CONF_IDLE; | 1259 | local->hw.conf.flags &= ~IEEE80211_CONF_IDLE; |
@@ -1181,8 +1266,7 @@ static u32 ieee80211_idle_on(struct ieee80211_local *local) | |||
1181 | return 0; | 1266 | return 0; |
1182 | 1267 | ||
1183 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 1268 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
1184 | printk(KERN_DEBUG "%s: device now idle\n", | 1269 | wiphy_debug(local->hw.wiphy, "device now idle\n"); |
1185 | wiphy_name(local->hw.wiphy)); | ||
1186 | #endif | 1270 | #endif |
1187 | 1271 | ||
1188 | drv_flush(local, false); | 1272 | drv_flush(local, false); |
@@ -1195,28 +1279,61 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | |||
1195 | { | 1279 | { |
1196 | struct ieee80211_sub_if_data *sdata; | 1280 | struct ieee80211_sub_if_data *sdata; |
1197 | int count = 0; | 1281 | int count = 0; |
1282 | bool working = false, scanning = false; | ||
1283 | struct ieee80211_work *wk; | ||
1198 | 1284 | ||
1199 | if (!list_empty(&local->work_list)) | 1285 | #ifdef CONFIG_PROVE_LOCKING |
1200 | return ieee80211_idle_off(local, "working"); | 1286 | WARN_ON(debug_locks && !lockdep_rtnl_is_held() && |
1201 | 1287 | !lockdep_is_held(&local->iflist_mtx)); | |
1202 | if (local->scanning) | 1288 | #endif |
1203 | return ieee80211_idle_off(local, "scanning"); | 1289 | lockdep_assert_held(&local->mtx); |
1204 | 1290 | ||
1205 | list_for_each_entry(sdata, &local->interfaces, list) { | 1291 | list_for_each_entry(sdata, &local->interfaces, list) { |
1206 | if (!ieee80211_sdata_running(sdata)) | 1292 | if (!ieee80211_sdata_running(sdata)) { |
1293 | sdata->vif.bss_conf.idle = true; | ||
1207 | continue; | 1294 | continue; |
1295 | } | ||
1296 | |||
1297 | sdata->old_idle = sdata->vif.bss_conf.idle; | ||
1298 | |||
1208 | /* do not count disabled managed interfaces */ | 1299 | /* do not count disabled managed interfaces */ |
1209 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | 1300 | if (sdata->vif.type == NL80211_IFTYPE_STATION && |
1210 | !sdata->u.mgd.associated) | 1301 | !sdata->u.mgd.associated) { |
1302 | sdata->vif.bss_conf.idle = true; | ||
1211 | continue; | 1303 | continue; |
1304 | } | ||
1212 | /* do not count unused IBSS interfaces */ | 1305 | /* do not count unused IBSS interfaces */ |
1213 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && | 1306 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && |
1214 | !sdata->u.ibss.ssid_len) | 1307 | !sdata->u.ibss.ssid_len) { |
1308 | sdata->vif.bss_conf.idle = true; | ||
1215 | continue; | 1309 | continue; |
1310 | } | ||
1216 | /* count everything else */ | 1311 | /* count everything else */ |
1217 | count++; | 1312 | count++; |
1218 | } | 1313 | } |
1219 | 1314 | ||
1315 | list_for_each_entry(wk, &local->work_list, list) { | ||
1316 | working = true; | ||
1317 | wk->sdata->vif.bss_conf.idle = false; | ||
1318 | } | ||
1319 | |||
1320 | if (local->scan_sdata) { | ||
1321 | scanning = true; | ||
1322 | local->scan_sdata->vif.bss_conf.idle = false; | ||
1323 | } | ||
1324 | |||
1325 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
1326 | if (sdata->old_idle == sdata->vif.bss_conf.idle) | ||
1327 | continue; | ||
1328 | if (!ieee80211_sdata_running(sdata)) | ||
1329 | continue; | ||
1330 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); | ||
1331 | } | ||
1332 | |||
1333 | if (working) | ||
1334 | return ieee80211_idle_off(local, "working"); | ||
1335 | if (scanning) | ||
1336 | return ieee80211_idle_off(local, "scanning"); | ||
1220 | if (!count) | 1337 | if (!count) |
1221 | return ieee80211_idle_on(local); | 1338 | return ieee80211_idle_on(local); |
1222 | else | 1339 | else |