diff options
Diffstat (limited to 'net/mac80211/iface.c')
-rw-r--r-- | net/mac80211/iface.c | 168 |
1 files changed, 120 insertions, 48 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index b9074824862a..91e8e1bacaaa 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -21,6 +21,23 @@ | |||
21 | #include "mesh.h" | 21 | #include "mesh.h" |
22 | #include "led.h" | 22 | #include "led.h" |
23 | 23 | ||
24 | /** | ||
25 | * DOC: Interface list locking | ||
26 | * | ||
27 | * The interface list in each struct ieee80211_local is protected | ||
28 | * three-fold: | ||
29 | * | ||
30 | * (1) modifications may only be done under the RTNL | ||
31 | * (2) modifications and readers are protected against each other by | ||
32 | * the iflist_mtx. | ||
33 | * (3) modifications are done in an RCU manner so atomic readers | ||
34 | * can traverse the list in RCU-safe blocks. | ||
35 | * | ||
36 | * As a consequence, reads (traversals) of the list can be protected | ||
37 | * by either the RTNL, the iflist_mtx or RCU. | ||
38 | */ | ||
39 | |||
40 | |||
24 | static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) | 41 | static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) |
25 | { | 42 | { |
26 | int meshhdrlen; | 43 | int meshhdrlen; |
@@ -219,7 +236,10 @@ static int ieee80211_open(struct net_device *dev) | |||
219 | break; | 236 | break; |
220 | case NL80211_IFTYPE_STATION: | 237 | case NL80211_IFTYPE_STATION: |
221 | case NL80211_IFTYPE_ADHOC: | 238 | case NL80211_IFTYPE_ADHOC: |
222 | sdata->u.sta.flags &= ~IEEE80211_STA_PREV_BSSID_SET; | 239 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
240 | sdata->u.mgd.flags &= ~IEEE80211_STA_PREV_BSSID_SET; | ||
241 | else | ||
242 | sdata->u.ibss.flags &= ~IEEE80211_IBSS_PREV_BSSID_SET; | ||
223 | /* fall through */ | 243 | /* fall through */ |
224 | default: | 244 | default: |
225 | conf.vif = &sdata->vif; | 245 | conf.vif = &sdata->vif; |
@@ -241,8 +261,7 @@ static int ieee80211_open(struct net_device *dev) | |||
241 | ieee80211_bss_info_change_notify(sdata, changed); | 261 | ieee80211_bss_info_change_notify(sdata, changed); |
242 | ieee80211_enable_keys(sdata); | 262 | ieee80211_enable_keys(sdata); |
243 | 263 | ||
244 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | 264 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
245 | !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)) | ||
246 | netif_carrier_off(dev); | 265 | netif_carrier_off(dev); |
247 | else | 266 | else |
248 | netif_carrier_on(dev); | 267 | netif_carrier_on(dev); |
@@ -304,11 +323,10 @@ static int ieee80211_open(struct net_device *dev) | |||
304 | * yet be effective. Trigger execution of ieee80211_sta_work | 323 | * yet be effective. Trigger execution of ieee80211_sta_work |
305 | * to fix this. | 324 | * to fix this. |
306 | */ | 325 | */ |
307 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 326 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
308 | sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 327 | queue_work(local->hw.workqueue, &sdata->u.mgd.work); |
309 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 328 | else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) |
310 | queue_work(local->hw.workqueue, &ifsta->work); | 329 | queue_work(local->hw.workqueue, &sdata->u.ibss.work); |
311 | } | ||
312 | 330 | ||
313 | netif_tx_start_all_queues(dev); | 331 | netif_tx_start_all_queues(dev); |
314 | 332 | ||
@@ -345,13 +363,24 @@ static int ieee80211_stop(struct net_device *dev) | |||
345 | 363 | ||
346 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | 364 | list_for_each_entry_rcu(sta, &local->sta_list, list) { |
347 | if (sta->sdata == sdata) | 365 | if (sta->sdata == sdata) |
348 | ieee80211_sta_tear_down_BA_sessions(sdata, | 366 | ieee80211_sta_tear_down_BA_sessions(sta); |
349 | sta->sta.addr); | ||
350 | } | 367 | } |
351 | 368 | ||
352 | rcu_read_unlock(); | 369 | rcu_read_unlock(); |
353 | 370 | ||
354 | /* | 371 | /* |
372 | * Announce that we are leaving the network, in case we are a | ||
373 | * station interface type. This must be done before removing | ||
374 | * all stations associated with sta_info_flush, otherwise STA | ||
375 | * information will be gone and no announce being done. | ||
376 | */ | ||
377 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | ||
378 | if (sdata->u.mgd.state != IEEE80211_STA_MLME_DISABLED) | ||
379 | ieee80211_sta_deauthenticate(sdata, | ||
380 | WLAN_REASON_DEAUTH_LEAVING); | ||
381 | } | ||
382 | |||
383 | /* | ||
355 | * Remove all stations associated with this interface. | 384 | * Remove all stations associated with this interface. |
356 | * | 385 | * |
357 | * This must be done before calling ops->remove_interface() | 386 | * This must be done before calling ops->remove_interface() |
@@ -383,6 +412,8 @@ static int ieee80211_stop(struct net_device *dev) | |||
383 | atomic_dec(&local->iff_promiscs); | 412 | atomic_dec(&local->iff_promiscs); |
384 | 413 | ||
385 | dev_mc_unsync(local->mdev, dev); | 414 | dev_mc_unsync(local->mdev, dev); |
415 | del_timer_sync(&local->dynamic_ps_timer); | ||
416 | cancel_work_sync(&local->dynamic_ps_enable_work); | ||
386 | 417 | ||
387 | /* APs need special treatment */ | 418 | /* APs need special treatment */ |
388 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | 419 | if (sdata->vif.type == NL80211_IFTYPE_AP) { |
@@ -434,14 +465,9 @@ static int ieee80211_stop(struct net_device *dev) | |||
434 | netif_addr_unlock_bh(local->mdev); | 465 | netif_addr_unlock_bh(local->mdev); |
435 | break; | 466 | break; |
436 | case NL80211_IFTYPE_STATION: | 467 | case NL80211_IFTYPE_STATION: |
437 | case NL80211_IFTYPE_ADHOC: | 468 | memset(sdata->u.mgd.bssid, 0, ETH_ALEN); |
438 | /* Announce that we are leaving the network. */ | 469 | del_timer_sync(&sdata->u.mgd.chswitch_timer); |
439 | if (sdata->u.sta.state != IEEE80211_STA_MLME_DISABLED) | 470 | del_timer_sync(&sdata->u.mgd.timer); |
440 | ieee80211_sta_deauthenticate(sdata, | ||
441 | WLAN_REASON_DEAUTH_LEAVING); | ||
442 | |||
443 | memset(sdata->u.sta.bssid, 0, ETH_ALEN); | ||
444 | del_timer_sync(&sdata->u.sta.timer); | ||
445 | /* | 471 | /* |
446 | * If the timer fired while we waited for it, it will have | 472 | * If the timer fired while we waited for it, it will have |
447 | * requeued the work. Now the work will be running again | 473 | * requeued the work. Now the work will be running again |
@@ -449,7 +475,11 @@ static int ieee80211_stop(struct net_device *dev) | |||
449 | * whether the interface is running, which, at this point, | 475 | * whether the interface is running, which, at this point, |
450 | * it no longer is. | 476 | * it no longer is. |
451 | */ | 477 | */ |
452 | cancel_work_sync(&sdata->u.sta.work); | 478 | cancel_work_sync(&sdata->u.mgd.work); |
479 | cancel_work_sync(&sdata->u.mgd.chswitch_work); | ||
480 | |||
481 | cancel_work_sync(&sdata->u.mgd.beacon_loss_work); | ||
482 | |||
453 | /* | 483 | /* |
454 | * When we get here, the interface is marked down. | 484 | * When we get here, the interface is marked down. |
455 | * Call synchronize_rcu() to wait for the RX path | 485 | * Call synchronize_rcu() to wait for the RX path |
@@ -457,12 +487,22 @@ static int ieee80211_stop(struct net_device *dev) | |||
457 | * frames at this very time on another CPU. | 487 | * frames at this very time on another CPU. |
458 | */ | 488 | */ |
459 | synchronize_rcu(); | 489 | synchronize_rcu(); |
460 | skb_queue_purge(&sdata->u.sta.skb_queue); | 490 | skb_queue_purge(&sdata->u.mgd.skb_queue); |
461 | 491 | ||
462 | sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED; | 492 | sdata->u.mgd.flags &= ~(IEEE80211_STA_PRIVACY_INVOKED | |
463 | kfree(sdata->u.sta.extra_ie); | 493 | IEEE80211_STA_TKIP_WEP_USED); |
464 | sdata->u.sta.extra_ie = NULL; | 494 | kfree(sdata->u.mgd.extra_ie); |
465 | sdata->u.sta.extra_ie_len = 0; | 495 | sdata->u.mgd.extra_ie = NULL; |
496 | sdata->u.mgd.extra_ie_len = 0; | ||
497 | /* fall through */ | ||
498 | case NL80211_IFTYPE_ADHOC: | ||
499 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
500 | memset(sdata->u.ibss.bssid, 0, ETH_ALEN); | ||
501 | del_timer_sync(&sdata->u.ibss.timer); | ||
502 | cancel_work_sync(&sdata->u.ibss.work); | ||
503 | synchronize_rcu(); | ||
504 | skb_queue_purge(&sdata->u.ibss.skb_queue); | ||
505 | } | ||
466 | /* fall through */ | 506 | /* fall through */ |
467 | case NL80211_IFTYPE_MESH_POINT: | 507 | case NL80211_IFTYPE_MESH_POINT: |
468 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 508 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
@@ -501,7 +541,7 @@ static int ieee80211_stop(struct net_device *dev) | |||
501 | * scan event to userspace -- the scan is incomplete. | 541 | * scan event to userspace -- the scan is incomplete. |
502 | */ | 542 | */ |
503 | if (local->sw_scanning) | 543 | if (local->sw_scanning) |
504 | ieee80211_scan_completed(&local->hw); | 544 | ieee80211_scan_completed(&local->hw, true); |
505 | } | 545 | } |
506 | 546 | ||
507 | conf.vif = &sdata->vif; | 547 | conf.vif = &sdata->vif; |
@@ -569,19 +609,6 @@ static void ieee80211_set_multicast_list(struct net_device *dev) | |||
569 | dev_mc_sync(local->mdev, dev); | 609 | dev_mc_sync(local->mdev, dev); |
570 | } | 610 | } |
571 | 611 | ||
572 | static void ieee80211_if_setup(struct net_device *dev) | ||
573 | { | ||
574 | ether_setup(dev); | ||
575 | dev->hard_start_xmit = ieee80211_subif_start_xmit; | ||
576 | dev->wireless_handlers = &ieee80211_iw_handler_def; | ||
577 | dev->set_multicast_list = ieee80211_set_multicast_list; | ||
578 | dev->change_mtu = ieee80211_change_mtu; | ||
579 | dev->open = ieee80211_open; | ||
580 | dev->stop = ieee80211_stop; | ||
581 | dev->destructor = free_netdev; | ||
582 | /* we will validate the address ourselves in ->open */ | ||
583 | dev->validate_addr = NULL; | ||
584 | } | ||
585 | /* | 612 | /* |
586 | * Called when the netdev is removed or, by the code below, before | 613 | * Called when the netdev is removed or, by the code below, before |
587 | * the interface type changes. | 614 | * the interface type changes. |
@@ -621,12 +648,14 @@ static void ieee80211_teardown_sdata(struct net_device *dev) | |||
621 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 648 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
622 | mesh_rmc_free(sdata); | 649 | mesh_rmc_free(sdata); |
623 | break; | 650 | break; |
624 | case NL80211_IFTYPE_STATION: | ||
625 | case NL80211_IFTYPE_ADHOC: | 651 | case NL80211_IFTYPE_ADHOC: |
626 | kfree(sdata->u.sta.extra_ie); | 652 | kfree_skb(sdata->u.ibss.probe_resp); |
627 | kfree(sdata->u.sta.assocreq_ies); | 653 | break; |
628 | kfree(sdata->u.sta.assocresp_ies); | 654 | case NL80211_IFTYPE_STATION: |
629 | kfree_skb(sdata->u.sta.probe_resp); | 655 | kfree(sdata->u.mgd.extra_ie); |
656 | kfree(sdata->u.mgd.assocreq_ies); | ||
657 | kfree(sdata->u.mgd.assocresp_ies); | ||
658 | kfree(sdata->u.mgd.sme_auth_ie); | ||
630 | break; | 659 | break; |
631 | case NL80211_IFTYPE_WDS: | 660 | case NL80211_IFTYPE_WDS: |
632 | case NL80211_IFTYPE_AP_VLAN: | 661 | case NL80211_IFTYPE_AP_VLAN: |
@@ -642,6 +671,34 @@ static void ieee80211_teardown_sdata(struct net_device *dev) | |||
642 | WARN_ON(flushed); | 671 | WARN_ON(flushed); |
643 | } | 672 | } |
644 | 673 | ||
674 | static const struct net_device_ops ieee80211_dataif_ops = { | ||
675 | .ndo_open = ieee80211_open, | ||
676 | .ndo_stop = ieee80211_stop, | ||
677 | .ndo_uninit = ieee80211_teardown_sdata, | ||
678 | .ndo_start_xmit = ieee80211_subif_start_xmit, | ||
679 | .ndo_set_multicast_list = ieee80211_set_multicast_list, | ||
680 | .ndo_change_mtu = ieee80211_change_mtu, | ||
681 | .ndo_set_mac_address = eth_mac_addr, | ||
682 | }; | ||
683 | |||
684 | static const struct net_device_ops ieee80211_monitorif_ops = { | ||
685 | .ndo_open = ieee80211_open, | ||
686 | .ndo_stop = ieee80211_stop, | ||
687 | .ndo_uninit = ieee80211_teardown_sdata, | ||
688 | .ndo_start_xmit = ieee80211_monitor_start_xmit, | ||
689 | .ndo_set_multicast_list = ieee80211_set_multicast_list, | ||
690 | .ndo_change_mtu = ieee80211_change_mtu, | ||
691 | .ndo_set_mac_address = eth_mac_addr, | ||
692 | }; | ||
693 | |||
694 | static void ieee80211_if_setup(struct net_device *dev) | ||
695 | { | ||
696 | ether_setup(dev); | ||
697 | dev->netdev_ops = &ieee80211_dataif_ops; | ||
698 | dev->wireless_handlers = &ieee80211_iw_handler_def; | ||
699 | dev->destructor = free_netdev; | ||
700 | } | ||
701 | |||
645 | /* | 702 | /* |
646 | * Helper function to initialise an interface to a specific type. | 703 | * Helper function to initialise an interface to a specific type. |
647 | */ | 704 | */ |
@@ -653,7 +710,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
653 | 710 | ||
654 | /* and set some type-dependent values */ | 711 | /* and set some type-dependent values */ |
655 | sdata->vif.type = type; | 712 | sdata->vif.type = type; |
656 | sdata->dev->hard_start_xmit = ieee80211_subif_start_xmit; | 713 | sdata->dev->netdev_ops = &ieee80211_dataif_ops; |
657 | sdata->wdev.iftype = type; | 714 | sdata->wdev.iftype = type; |
658 | 715 | ||
659 | /* only monitor differs */ | 716 | /* only monitor differs */ |
@@ -665,16 +722,18 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
665 | INIT_LIST_HEAD(&sdata->u.ap.vlans); | 722 | INIT_LIST_HEAD(&sdata->u.ap.vlans); |
666 | break; | 723 | break; |
667 | case NL80211_IFTYPE_STATION: | 724 | case NL80211_IFTYPE_STATION: |
668 | case NL80211_IFTYPE_ADHOC: | ||
669 | ieee80211_sta_setup_sdata(sdata); | 725 | ieee80211_sta_setup_sdata(sdata); |
670 | break; | 726 | break; |
727 | case NL80211_IFTYPE_ADHOC: | ||
728 | ieee80211_ibss_setup_sdata(sdata); | ||
729 | break; | ||
671 | case NL80211_IFTYPE_MESH_POINT: | 730 | case NL80211_IFTYPE_MESH_POINT: |
672 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 731 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
673 | ieee80211_mesh_init_sdata(sdata); | 732 | ieee80211_mesh_init_sdata(sdata); |
674 | break; | 733 | break; |
675 | case NL80211_IFTYPE_MONITOR: | 734 | case NL80211_IFTYPE_MONITOR: |
676 | sdata->dev->type = ARPHRD_IEEE80211_RADIOTAP; | 735 | sdata->dev->type = ARPHRD_IEEE80211_RADIOTAP; |
677 | sdata->dev->hard_start_xmit = ieee80211_monitor_start_xmit; | 736 | sdata->dev->netdev_ops = &ieee80211_monitorif_ops; |
678 | sdata->u.mntr_flags = MONITOR_FLAG_CONTROL | | 737 | sdata->u.mntr_flags = MONITOR_FLAG_CONTROL | |
679 | MONITOR_FLAG_OTHER_BSS; | 738 | MONITOR_FLAG_OTHER_BSS; |
680 | break; | 739 | break; |
@@ -755,6 +814,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
755 | 814 | ||
756 | memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); | 815 | memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); |
757 | SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); | 816 | SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); |
817 | ndev->features |= NETIF_F_NETNS_LOCAL; | ||
758 | 818 | ||
759 | /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */ | 819 | /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */ |
760 | sdata = netdev_priv(ndev); | 820 | sdata = netdev_priv(ndev); |
@@ -780,15 +840,15 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
780 | if (ret) | 840 | if (ret) |
781 | goto fail; | 841 | goto fail; |
782 | 842 | ||
783 | ndev->uninit = ieee80211_teardown_sdata; | ||
784 | |||
785 | if (ieee80211_vif_is_mesh(&sdata->vif) && | 843 | if (ieee80211_vif_is_mesh(&sdata->vif) && |
786 | params && params->mesh_id_len) | 844 | params && params->mesh_id_len) |
787 | ieee80211_sdata_set_mesh_id(sdata, | 845 | ieee80211_sdata_set_mesh_id(sdata, |
788 | params->mesh_id_len, | 846 | params->mesh_id_len, |
789 | params->mesh_id); | 847 | params->mesh_id); |
790 | 848 | ||
849 | mutex_lock(&local->iflist_mtx); | ||
791 | list_add_tail_rcu(&sdata->list, &local->interfaces); | 850 | list_add_tail_rcu(&sdata->list, &local->interfaces); |
851 | mutex_unlock(&local->iflist_mtx); | ||
792 | 852 | ||
793 | if (new_dev) | 853 | if (new_dev) |
794 | *new_dev = ndev; | 854 | *new_dev = ndev; |
@@ -804,7 +864,10 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata) | |||
804 | { | 864 | { |
805 | ASSERT_RTNL(); | 865 | ASSERT_RTNL(); |
806 | 866 | ||
867 | mutex_lock(&sdata->local->iflist_mtx); | ||
807 | list_del_rcu(&sdata->list); | 868 | list_del_rcu(&sdata->list); |
869 | mutex_unlock(&sdata->local->iflist_mtx); | ||
870 | |||
808 | synchronize_rcu(); | 871 | synchronize_rcu(); |
809 | unregister_netdevice(sdata->dev); | 872 | unregister_netdevice(sdata->dev); |
810 | } | 873 | } |
@@ -820,7 +883,16 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local) | |||
820 | ASSERT_RTNL(); | 883 | ASSERT_RTNL(); |
821 | 884 | ||
822 | list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { | 885 | list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { |
886 | /* | ||
887 | * we cannot hold the iflist_mtx across unregister_netdevice, | ||
888 | * but we only need to hold it for list modifications to lock | ||
889 | * out readers since we're under the RTNL here as all other | ||
890 | * writers. | ||
891 | */ | ||
892 | mutex_lock(&local->iflist_mtx); | ||
823 | list_del(&sdata->list); | 893 | list_del(&sdata->list); |
894 | mutex_unlock(&local->iflist_mtx); | ||
895 | |||
824 | unregister_netdevice(sdata->dev); | 896 | unregister_netdevice(sdata->dev); |
825 | } | 897 | } |
826 | } | 898 | } |