diff options
author | John W. Linville <linville@tuxdriver.com> | 2010-09-02 13:30:07 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-09-02 13:30:07 -0400 |
commit | 78ab952717b62c0ba6ca7f7a27eaa0486685e45f (patch) | |
tree | a4ab2bfc578f279fc6847031f501d84c75057531 /net/mac80211/iface.c | |
parent | 3e502e63586920f219ed2590f69c1f5a8888cfa4 (diff) | |
parent | 85f72bc839705294b32b6c16b491c0422f0a71b3 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6 into for-davem
Diffstat (limited to 'net/mac80211/iface.c')
-rw-r--r-- | net/mac80211/iface.c | 314 |
1 files changed, 183 insertions, 131 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 86f434f234ae..c1cc200ac81f 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)) |
@@ -195,33 +205,22 @@ static int ieee80211_open(struct net_device *dev) | |||
195 | } | 205 | } |
196 | 206 | ||
197 | /* | 207 | /* |
198 | * Check all interfaces and copy the hopefully now-present | 208 | * Copy the hopefully now-present MAC address to |
199 | * MAC address to those that have the special null one. | 209 | * this interface, if it has the special null one. |
200 | */ | 210 | */ |
201 | list_for_each_entry(nsdata, &local->interfaces, list) { | 211 | if (is_zero_ether_addr(dev->dev_addr)) { |
202 | struct net_device *ndev = nsdata->dev; | 212 | memcpy(dev->dev_addr, |
203 | 213 | local->hw.wiphy->perm_addr, | |
204 | /* | 214 | ETH_ALEN); |
205 | * No need to check running since we do not allow | 215 | memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN); |
206 | * it to start up with this invalid address. | 216 | |
207 | */ | 217 | if (!is_valid_ether_addr(dev->dev_addr)) { |
208 | if (compare_ether_addr(null_addr, ndev->dev_addr) == 0) { | 218 | if (!local->open_count) |
209 | memcpy(ndev->dev_addr, | 219 | drv_stop(local); |
210 | local->hw.wiphy->perm_addr, | 220 | return -EADDRNOTAVAIL; |
211 | ETH_ALEN); | ||
212 | memcpy(ndev->perm_addr, ndev->dev_addr, ETH_ALEN); | ||
213 | } | 221 | } |
214 | } | 222 | } |
215 | 223 | ||
216 | /* | ||
217 | * Validate the MAC address for this device. | ||
218 | */ | ||
219 | if (!is_valid_ether_addr(dev->dev_addr)) { | ||
220 | if (!local->open_count) | ||
221 | drv_stop(local); | ||
222 | return -EADDRNOTAVAIL; | ||
223 | } | ||
224 | |||
225 | switch (sdata->vif.type) { | 224 | switch (sdata->vif.type) { |
226 | case NL80211_IFTYPE_AP_VLAN: | 225 | case NL80211_IFTYPE_AP_VLAN: |
227 | /* no need to tell driver */ | 226 | /* no need to tell driver */ |
@@ -255,9 +254,11 @@ static int ieee80211_open(struct net_device *dev) | |||
255 | netif_carrier_on(dev); | 254 | netif_carrier_on(dev); |
256 | break; | 255 | break; |
257 | default: | 256 | default: |
258 | res = drv_add_interface(local, &sdata->vif); | 257 | if (coming_up) { |
259 | if (res) | 258 | res = drv_add_interface(local, &sdata->vif); |
260 | goto err_stop; | 259 | if (res) |
260 | goto err_stop; | ||
261 | } | ||
261 | 262 | ||
262 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 263 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
263 | local->fif_other_bss++; | 264 | local->fif_other_bss++; |
@@ -313,7 +314,9 @@ static int ieee80211_open(struct net_device *dev) | |||
313 | hw_reconf_flags |= __ieee80211_recalc_idle(local); | 314 | hw_reconf_flags |= __ieee80211_recalc_idle(local); |
314 | mutex_unlock(&local->mtx); | 315 | mutex_unlock(&local->mtx); |
315 | 316 | ||
316 | local->open_count++; | 317 | if (coming_up) |
318 | local->open_count++; | ||
319 | |||
317 | if (hw_reconf_flags) { | 320 | if (hw_reconf_flags) { |
318 | ieee80211_hw_config(local, hw_reconf_flags); | 321 | ieee80211_hw_config(local, hw_reconf_flags); |
319 | /* | 322 | /* |
@@ -328,6 +331,8 @@ static int ieee80211_open(struct net_device *dev) | |||
328 | 331 | ||
329 | netif_tx_start_all_queues(dev); | 332 | netif_tx_start_all_queues(dev); |
330 | 333 | ||
334 | set_bit(SDATA_STATE_RUNNING, &sdata->state); | ||
335 | |||
331 | return 0; | 336 | return 0; |
332 | err_del_interface: | 337 | err_del_interface: |
333 | drv_remove_interface(local, &sdata->vif); | 338 | drv_remove_interface(local, &sdata->vif); |
@@ -341,19 +346,38 @@ static int ieee80211_open(struct net_device *dev) | |||
341 | return res; | 346 | return res; |
342 | } | 347 | } |
343 | 348 | ||
344 | static int ieee80211_stop(struct net_device *dev) | 349 | static int ieee80211_open(struct net_device *dev) |
345 | { | 350 | { |
346 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 351 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
352 | int err; | ||
353 | |||
354 | /* fail early if user set an invalid address */ | ||
355 | if (!is_zero_ether_addr(dev->dev_addr) && | ||
356 | !is_valid_ether_addr(dev->dev_addr)) | ||
357 | return -EADDRNOTAVAIL; | ||
358 | |||
359 | err = ieee80211_check_concurrent_iface(sdata, sdata->vif.type); | ||
360 | if (err) | ||
361 | return err; | ||
362 | |||
363 | return ieee80211_do_open(dev, true); | ||
364 | } | ||
365 | |||
366 | static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | ||
367 | bool going_down) | ||
368 | { | ||
347 | struct ieee80211_local *local = sdata->local; | 369 | struct ieee80211_local *local = sdata->local; |
348 | unsigned long flags; | 370 | unsigned long flags; |
349 | struct sk_buff *skb, *tmp; | 371 | struct sk_buff *skb, *tmp; |
350 | u32 hw_reconf_flags = 0; | 372 | u32 hw_reconf_flags = 0; |
351 | int i; | 373 | int i; |
352 | 374 | ||
375 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); | ||
376 | |||
353 | /* | 377 | /* |
354 | * Stop TX on this interface first. | 378 | * Stop TX on this interface first. |
355 | */ | 379 | */ |
356 | netif_tx_stop_all_queues(dev); | 380 | netif_tx_stop_all_queues(sdata->dev); |
357 | 381 | ||
358 | /* | 382 | /* |
359 | * Purge work for this interface. | 383 | * Purge work for this interface. |
@@ -370,12 +394,9 @@ static int ieee80211_stop(struct net_device *dev) | |||
370 | * (because if we remove a STA after ops->remove_interface() | 394 | * (because if we remove a STA after ops->remove_interface() |
371 | * the driver will have removed the vif info already!) | 395 | * the driver will have removed the vif info already!) |
372 | * | 396 | * |
373 | * We could relax this and only unlink the stations from the | 397 | * This is relevant only in AP, WDS and mesh modes, since in |
374 | * hash table and list but keep them on a per-sdata list that | 398 | * all other modes we've already removed all stations when |
375 | * will be inserted back again when the interface is brought | 399 | * disconnecting etc. |
376 | * up again, but I don't currently see a use case for that, | ||
377 | * except with WDS which gets a STA entry created when it is | ||
378 | * brought up. | ||
379 | */ | 400 | */ |
380 | sta_info_flush(local, sdata); | 401 | sta_info_flush(local, sdata); |
381 | 402 | ||
@@ -394,11 +415,12 @@ static int ieee80211_stop(struct net_device *dev) | |||
394 | if (sdata->vif.type == NL80211_IFTYPE_AP) | 415 | if (sdata->vif.type == NL80211_IFTYPE_AP) |
395 | local->fif_pspoll--; | 416 | local->fif_pspoll--; |
396 | 417 | ||
397 | netif_addr_lock_bh(dev); | 418 | netif_addr_lock_bh(sdata->dev); |
398 | spin_lock_bh(&local->filter_lock); | 419 | spin_lock_bh(&local->filter_lock); |
399 | __hw_addr_unsync(&local->mc_list, &dev->mc, dev->addr_len); | 420 | __hw_addr_unsync(&local->mc_list, &sdata->dev->mc, |
421 | sdata->dev->addr_len); | ||
400 | spin_unlock_bh(&local->filter_lock); | 422 | spin_unlock_bh(&local->filter_lock); |
401 | netif_addr_unlock_bh(dev); | 423 | netif_addr_unlock_bh(sdata->dev); |
402 | 424 | ||
403 | ieee80211_configure_filter(local); | 425 | ieee80211_configure_filter(local); |
404 | 426 | ||
@@ -410,11 +432,21 @@ static int ieee80211_stop(struct net_device *dev) | |||
410 | struct ieee80211_sub_if_data *vlan, *tmpsdata; | 432 | struct ieee80211_sub_if_data *vlan, *tmpsdata; |
411 | struct beacon_data *old_beacon = sdata->u.ap.beacon; | 433 | struct beacon_data *old_beacon = sdata->u.ap.beacon; |
412 | 434 | ||
435 | /* sdata_running will return false, so this will disable */ | ||
436 | ieee80211_bss_info_change_notify(sdata, | ||
437 | BSS_CHANGED_BEACON_ENABLED); | ||
438 | |||
413 | /* remove beacon */ | 439 | /* remove beacon */ |
414 | rcu_assign_pointer(sdata->u.ap.beacon, NULL); | 440 | rcu_assign_pointer(sdata->u.ap.beacon, NULL); |
415 | synchronize_rcu(); | 441 | synchronize_rcu(); |
416 | kfree(old_beacon); | 442 | kfree(old_beacon); |
417 | 443 | ||
444 | /* free all potentially still buffered bcast frames */ | ||
445 | while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) { | ||
446 | local->total_ps_buffered--; | ||
447 | dev_kfree_skb(skb); | ||
448 | } | ||
449 | |||
418 | /* down all dependent devices, that is VLANs */ | 450 | /* down all dependent devices, that is VLANs */ |
419 | list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans, | 451 | list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans, |
420 | u.vlan.list) | 452 | u.vlan.list) |
@@ -422,7 +454,8 @@ static int ieee80211_stop(struct net_device *dev) | |||
422 | WARN_ON(!list_empty(&sdata->u.ap.vlans)); | 454 | WARN_ON(!list_empty(&sdata->u.ap.vlans)); |
423 | } | 455 | } |
424 | 456 | ||
425 | local->open_count--; | 457 | if (going_down) |
458 | local->open_count--; | ||
426 | 459 | ||
427 | switch (sdata->vif.type) { | 460 | switch (sdata->vif.type) { |
428 | case NL80211_IFTYPE_AP_VLAN: | 461 | case NL80211_IFTYPE_AP_VLAN: |
@@ -454,27 +487,6 @@ static int ieee80211_stop(struct net_device *dev) | |||
454 | 487 | ||
455 | ieee80211_configure_filter(local); | 488 | ieee80211_configure_filter(local); |
456 | break; | 489 | break; |
457 | case NL80211_IFTYPE_STATION: | ||
458 | del_timer_sync(&sdata->u.mgd.chswitch_timer); | ||
459 | del_timer_sync(&sdata->u.mgd.timer); | ||
460 | del_timer_sync(&sdata->u.mgd.conn_mon_timer); | ||
461 | del_timer_sync(&sdata->u.mgd.bcn_mon_timer); | ||
462 | /* | ||
463 | * If any of the timers fired while we waited for it, it will | ||
464 | * have queued its work. Now the work will be running again | ||
465 | * but will not rearm the timer again because it checks | ||
466 | * whether the interface is running, which, at this point, | ||
467 | * it no longer is. | ||
468 | */ | ||
469 | cancel_work_sync(&sdata->u.mgd.chswitch_work); | ||
470 | cancel_work_sync(&sdata->u.mgd.monitor_work); | ||
471 | cancel_work_sync(&sdata->u.mgd.beacon_connection_loss_work); | ||
472 | |||
473 | /* fall through */ | ||
474 | case NL80211_IFTYPE_ADHOC: | ||
475 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | ||
476 | del_timer_sync(&sdata->u.ibss.timer); | ||
477 | /* fall through */ | ||
478 | case NL80211_IFTYPE_MESH_POINT: | 490 | case NL80211_IFTYPE_MESH_POINT: |
479 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 491 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
480 | /* other_bss and allmulti are always set on mesh | 492 | /* other_bss and allmulti are always set on mesh |
@@ -502,18 +514,21 @@ static int ieee80211_stop(struct net_device *dev) | |||
502 | ieee80211_scan_cancel(local); | 514 | ieee80211_scan_cancel(local); |
503 | 515 | ||
504 | /* | 516 | /* |
505 | * Disable beaconing for AP and mesh, IBSS can't | 517 | * Disable beaconing here for mesh only, AP and IBSS |
506 | * still be joined to a network at this point. | 518 | * are already taken care of. |
507 | */ | 519 | */ |
508 | if (sdata->vif.type == NL80211_IFTYPE_AP || | 520 | if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT) |
509 | sdata->vif.type == NL80211_IFTYPE_MESH_POINT) { | ||
510 | ieee80211_bss_info_change_notify(sdata, | 521 | ieee80211_bss_info_change_notify(sdata, |
511 | BSS_CHANGED_BEACON_ENABLED); | 522 | BSS_CHANGED_BEACON_ENABLED); |
512 | } | ||
513 | 523 | ||
514 | /* free all remaining keys, there shouldn't be any */ | 524 | /* |
525 | * Free all remaining keys, there shouldn't be any, | ||
526 | * except maybe group keys in AP more or WDS? | ||
527 | */ | ||
515 | ieee80211_free_keys(sdata); | 528 | ieee80211_free_keys(sdata); |
516 | drv_remove_interface(local, &sdata->vif); | 529 | |
530 | if (going_down) | ||
531 | drv_remove_interface(local, &sdata->vif); | ||
517 | } | 532 | } |
518 | 533 | ||
519 | sdata->bss = NULL; | 534 | sdata->bss = NULL; |
@@ -549,6 +564,13 @@ static int ieee80211_stop(struct net_device *dev) | |||
549 | } | 564 | } |
550 | } | 565 | } |
551 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 566 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
567 | } | ||
568 | |||
569 | static int ieee80211_stop(struct net_device *dev) | ||
570 | { | ||
571 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
572 | |||
573 | ieee80211_do_stop(sdata, true); | ||
552 | 574 | ||
553 | return 0; | 575 | return 0; |
554 | } | 576 | } |
@@ -593,8 +615,6 @@ static void ieee80211_teardown_sdata(struct net_device *dev) | |||
593 | { | 615 | { |
594 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 616 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
595 | struct ieee80211_local *local = sdata->local; | 617 | struct ieee80211_local *local = sdata->local; |
596 | struct beacon_data *beacon; | ||
597 | struct sk_buff *skb; | ||
598 | int flushed; | 618 | int flushed; |
599 | int i; | 619 | int i; |
600 | 620 | ||
@@ -607,37 +627,8 @@ static void ieee80211_teardown_sdata(struct net_device *dev) | |||
607 | __skb_queue_purge(&sdata->fragments[i].skb_list); | 627 | __skb_queue_purge(&sdata->fragments[i].skb_list); |
608 | sdata->fragment_next = 0; | 628 | sdata->fragment_next = 0; |
609 | 629 | ||
610 | switch (sdata->vif.type) { | 630 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
611 | case NL80211_IFTYPE_AP: | 631 | mesh_rmc_free(sdata); |
612 | beacon = sdata->u.ap.beacon; | ||
613 | rcu_assign_pointer(sdata->u.ap.beacon, NULL); | ||
614 | synchronize_rcu(); | ||
615 | kfree(beacon); | ||
616 | |||
617 | while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) { | ||
618 | local->total_ps_buffered--; | ||
619 | dev_kfree_skb(skb); | ||
620 | } | ||
621 | |||
622 | break; | ||
623 | case NL80211_IFTYPE_MESH_POINT: | ||
624 | if (ieee80211_vif_is_mesh(&sdata->vif)) | ||
625 | mesh_rmc_free(sdata); | ||
626 | break; | ||
627 | case NL80211_IFTYPE_ADHOC: | ||
628 | if (WARN_ON(sdata->u.ibss.presp)) | ||
629 | kfree_skb(sdata->u.ibss.presp); | ||
630 | break; | ||
631 | case NL80211_IFTYPE_STATION: | ||
632 | case NL80211_IFTYPE_WDS: | ||
633 | case NL80211_IFTYPE_AP_VLAN: | ||
634 | case NL80211_IFTYPE_MONITOR: | ||
635 | break; | ||
636 | case NL80211_IFTYPE_UNSPECIFIED: | ||
637 | case NUM_NL80211_IFTYPES: | ||
638 | BUG(); | ||
639 | break; | ||
640 | } | ||
641 | 632 | ||
642 | flushed = sta_info_flush(local, sdata); | 633 | flushed = sta_info_flush(local, sdata); |
643 | WARN_ON(flushed); | 634 | WARN_ON(flushed); |
@@ -855,6 +846,9 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
855 | sdata->dev->netdev_ops = &ieee80211_dataif_ops; | 846 | sdata->dev->netdev_ops = &ieee80211_dataif_ops; |
856 | sdata->wdev.iftype = type; | 847 | sdata->wdev.iftype = type; |
857 | 848 | ||
849 | sdata->control_port_protocol = cpu_to_be16(ETH_P_PAE); | ||
850 | sdata->control_port_no_encrypt = false; | ||
851 | |||
858 | /* only monitor differs */ | 852 | /* only monitor differs */ |
859 | sdata->dev->type = ARPHRD_ETHER; | 853 | sdata->dev->type = ARPHRD_ETHER; |
860 | 854 | ||
@@ -894,9 +888,72 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
894 | ieee80211_debugfs_add_netdev(sdata); | 888 | ieee80211_debugfs_add_netdev(sdata); |
895 | } | 889 | } |
896 | 890 | ||
891 | static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata, | ||
892 | enum nl80211_iftype type) | ||
893 | { | ||
894 | struct ieee80211_local *local = sdata->local; | ||
895 | int ret, err; | ||
896 | |||
897 | ASSERT_RTNL(); | ||
898 | |||
899 | if (!local->ops->change_interface) | ||
900 | return -EBUSY; | ||
901 | |||
902 | switch (sdata->vif.type) { | ||
903 | case NL80211_IFTYPE_AP: | ||
904 | case NL80211_IFTYPE_STATION: | ||
905 | case NL80211_IFTYPE_ADHOC: | ||
906 | /* | ||
907 | * Could maybe also all others here? | ||
908 | * Just not sure how that interacts | ||
909 | * with the RX/config path e.g. for | ||
910 | * mesh. | ||
911 | */ | ||
912 | break; | ||
913 | default: | ||
914 | return -EBUSY; | ||
915 | } | ||
916 | |||
917 | switch (type) { | ||
918 | case NL80211_IFTYPE_AP: | ||
919 | case NL80211_IFTYPE_STATION: | ||
920 | case NL80211_IFTYPE_ADHOC: | ||
921 | /* | ||
922 | * Could probably support everything | ||
923 | * but WDS here (WDS do_open can fail | ||
924 | * under memory pressure, which this | ||
925 | * code isn't prepared to handle). | ||
926 | */ | ||
927 | break; | ||
928 | default: | ||
929 | return -EBUSY; | ||
930 | } | ||
931 | |||
932 | ret = ieee80211_check_concurrent_iface(sdata, type); | ||
933 | if (ret) | ||
934 | return ret; | ||
935 | |||
936 | ieee80211_do_stop(sdata, false); | ||
937 | |||
938 | ieee80211_teardown_sdata(sdata->dev); | ||
939 | |||
940 | ret = drv_change_interface(local, sdata, type); | ||
941 | if (ret) | ||
942 | type = sdata->vif.type; | ||
943 | |||
944 | ieee80211_setup_sdata(sdata, type); | ||
945 | |||
946 | err = ieee80211_do_open(sdata->dev, false); | ||
947 | WARN(err, "type change: do_open returned %d", err); | ||
948 | |||
949 | return ret; | ||
950 | } | ||
951 | |||
897 | int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, | 952 | int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, |
898 | enum nl80211_iftype type) | 953 | enum nl80211_iftype type) |
899 | { | 954 | { |
955 | int ret; | ||
956 | |||
900 | ASSERT_RTNL(); | 957 | ASSERT_RTNL(); |
901 | 958 | ||
902 | if (type == sdata->vif.type) | 959 | if (type == sdata->vif.type) |
@@ -907,18 +964,15 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, | |||
907 | type == NL80211_IFTYPE_ADHOC) | 964 | type == NL80211_IFTYPE_ADHOC) |
908 | return -EOPNOTSUPP; | 965 | return -EOPNOTSUPP; |
909 | 966 | ||
910 | /* | 967 | if (ieee80211_sdata_running(sdata)) { |
911 | * We could, here, on changes between IBSS/STA/MESH modes, | 968 | ret = ieee80211_runtime_change_iftype(sdata, type); |
912 | * invoke an MLME function instead that disassociates etc. | 969 | if (ret) |
913 | * and goes into the requested mode. | 970 | return ret; |
914 | */ | 971 | } else { |
915 | 972 | /* Purge and reset type-dependent state. */ | |
916 | if (ieee80211_sdata_running(sdata)) | 973 | ieee80211_teardown_sdata(sdata->dev); |
917 | return -EBUSY; | 974 | ieee80211_setup_sdata(sdata, type); |
918 | 975 | } | |
919 | /* Purge and reset type-dependent state. */ | ||
920 | ieee80211_teardown_sdata(sdata->dev); | ||
921 | ieee80211_setup_sdata(sdata, type); | ||
922 | 976 | ||
923 | /* reset some values that shouldn't be kept across type changes */ | 977 | /* reset some values that shouldn't be kept across type changes */ |
924 | sdata->vif.bss_conf.basic_rates = | 978 | sdata->vif.bss_conf.basic_rates = |
@@ -1175,8 +1229,7 @@ static u32 ieee80211_idle_off(struct ieee80211_local *local, | |||
1175 | return 0; | 1229 | return 0; |
1176 | 1230 | ||
1177 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 1231 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
1178 | printk(KERN_DEBUG "%s: device no longer idle - %s\n", | 1232 | wiphy_debug(local->hw.wiphy, "device no longer idle - %s\n", reason); |
1179 | wiphy_name(local->hw.wiphy), reason); | ||
1180 | #endif | 1233 | #endif |
1181 | 1234 | ||
1182 | local->hw.conf.flags &= ~IEEE80211_CONF_IDLE; | 1235 | local->hw.conf.flags &= ~IEEE80211_CONF_IDLE; |
@@ -1189,8 +1242,7 @@ static u32 ieee80211_idle_on(struct ieee80211_local *local) | |||
1189 | return 0; | 1242 | return 0; |
1190 | 1243 | ||
1191 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 1244 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
1192 | printk(KERN_DEBUG "%s: device now idle\n", | 1245 | wiphy_debug(local->hw.wiphy, "device now idle\n"); |
1193 | wiphy_name(local->hw.wiphy)); | ||
1194 | #endif | 1246 | #endif |
1195 | 1247 | ||
1196 | drv_flush(local, false); | 1248 | drv_flush(local, false); |