diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /net/wireless/core.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'net/wireless/core.c')
-rw-r--r-- | net/wireless/core.c | 114 |
1 files changed, 84 insertions, 30 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c index a595f712b5bf..6ac70c101523 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -1,13 +1,14 @@ | |||
1 | /* | 1 | /* |
2 | * This is the linux wireless configuration interface. | 2 | * This is the linux wireless configuration interface. |
3 | * | 3 | * |
4 | * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net> | 4 | * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/if.h> | 7 | #include <linux/if.h> |
8 | #include <linux/module.h> | 8 | #include <linux/module.h> |
9 | #include <linux/err.h> | 9 | #include <linux/err.h> |
10 | #include <linux/list.h> | 10 | #include <linux/list.h> |
11 | #include <linux/slab.h> | ||
11 | #include <linux/nl80211.h> | 12 | #include <linux/nl80211.h> |
12 | #include <linux/debugfs.h> | 13 | #include <linux/debugfs.h> |
13 | #include <linux/notifier.h> | 14 | #include <linux/notifier.h> |
@@ -22,6 +23,7 @@ | |||
22 | #include "sysfs.h" | 23 | #include "sysfs.h" |
23 | #include "debugfs.h" | 24 | #include "debugfs.h" |
24 | #include "wext-compat.h" | 25 | #include "wext-compat.h" |
26 | #include "ethtool.h" | ||
25 | 27 | ||
26 | /* name for sysfs, %d is appended */ | 28 | /* name for sysfs, %d is appended */ |
27 | #define PHY_NAME "phy" | 29 | #define PHY_NAME "phy" |
@@ -30,20 +32,18 @@ MODULE_AUTHOR("Johannes Berg"); | |||
30 | MODULE_LICENSE("GPL"); | 32 | MODULE_LICENSE("GPL"); |
31 | MODULE_DESCRIPTION("wireless configuration support"); | 33 | MODULE_DESCRIPTION("wireless configuration support"); |
32 | 34 | ||
33 | /* RCU might be appropriate here since we usually | 35 | /* RCU-protected (and cfg80211_mutex for writers) */ |
34 | * only read the list, and that can happen quite | ||
35 | * often because we need to do it for each command */ | ||
36 | LIST_HEAD(cfg80211_rdev_list); | 36 | LIST_HEAD(cfg80211_rdev_list); |
37 | int cfg80211_rdev_list_generation; | 37 | int cfg80211_rdev_list_generation; |
38 | 38 | ||
39 | /* | ||
40 | * This is used to protect the cfg80211_rdev_list | ||
41 | */ | ||
42 | DEFINE_MUTEX(cfg80211_mutex); | 39 | DEFINE_MUTEX(cfg80211_mutex); |
43 | 40 | ||
44 | /* for debugfs */ | 41 | /* for debugfs */ |
45 | static struct dentry *ieee80211_debugfs_dir; | 42 | static struct dentry *ieee80211_debugfs_dir; |
46 | 43 | ||
44 | /* for the cleanup, scan and event works */ | ||
45 | struct workqueue_struct *cfg80211_wq; | ||
46 | |||
47 | /* requires cfg80211_mutex to be held! */ | 47 | /* requires cfg80211_mutex to be held! */ |
48 | struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx) | 48 | struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx) |
49 | { | 49 | { |
@@ -230,7 +230,7 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, | |||
230 | struct wireless_dev *wdev; | 230 | struct wireless_dev *wdev; |
231 | int err = 0; | 231 | int err = 0; |
232 | 232 | ||
233 | if (!rdev->wiphy.netnsok) | 233 | if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK)) |
234 | return -EOPNOTSUPP; | 234 | return -EOPNOTSUPP; |
235 | 235 | ||
236 | list_for_each_entry(wdev, &rdev->netdev_list, list) { | 236 | list_for_each_entry(wdev, &rdev->netdev_list, list) { |
@@ -359,11 +359,17 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
359 | INIT_LIST_HEAD(&rdev->bss_list); | 359 | INIT_LIST_HEAD(&rdev->bss_list); |
360 | INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); | 360 | INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); |
361 | 361 | ||
362 | #ifdef CONFIG_CFG80211_WEXT | ||
363 | rdev->wiphy.wext = &cfg80211_wext_handler; | ||
364 | #endif | ||
365 | |||
362 | device_initialize(&rdev->wiphy.dev); | 366 | device_initialize(&rdev->wiphy.dev); |
363 | rdev->wiphy.dev.class = &ieee80211_class; | 367 | rdev->wiphy.dev.class = &ieee80211_class; |
364 | rdev->wiphy.dev.platform_data = rdev; | 368 | rdev->wiphy.dev.platform_data = rdev; |
365 | 369 | ||
366 | rdev->wiphy.ps_default = CONFIG_CFG80211_DEFAULT_PS_VALUE; | 370 | #ifdef CONFIG_CFG80211_DEFAULT_PS |
371 | rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; | ||
372 | #endif | ||
367 | 373 | ||
368 | wiphy_net_set(&rdev->wiphy, &init_net); | 374 | wiphy_net_set(&rdev->wiphy, &init_net); |
369 | 375 | ||
@@ -392,6 +398,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
392 | rdev->wiphy.retry_long = 4; | 398 | rdev->wiphy.retry_long = 4; |
393 | rdev->wiphy.frag_threshold = (u32) -1; | 399 | rdev->wiphy.frag_threshold = (u32) -1; |
394 | rdev->wiphy.rts_threshold = (u32) -1; | 400 | rdev->wiphy.rts_threshold = (u32) -1; |
401 | rdev->wiphy.coverage_class = 0; | ||
395 | 402 | ||
396 | return &rdev->wiphy; | 403 | return &rdev->wiphy; |
397 | } | 404 | } |
@@ -407,6 +414,18 @@ int wiphy_register(struct wiphy *wiphy) | |||
407 | int i; | 414 | int i; |
408 | u16 ifmodes = wiphy->interface_modes; | 415 | u16 ifmodes = wiphy->interface_modes; |
409 | 416 | ||
417 | if (WARN_ON(wiphy->addresses && !wiphy->n_addresses)) | ||
418 | return -EINVAL; | ||
419 | |||
420 | if (WARN_ON(wiphy->addresses && | ||
421 | !is_zero_ether_addr(wiphy->perm_addr) && | ||
422 | memcmp(wiphy->perm_addr, wiphy->addresses[0].addr, | ||
423 | ETH_ALEN))) | ||
424 | return -EINVAL; | ||
425 | |||
426 | if (wiphy->addresses) | ||
427 | memcpy(wiphy->perm_addr, wiphy->addresses[0].addr, ETH_ALEN); | ||
428 | |||
410 | /* sanity check ifmodes */ | 429 | /* sanity check ifmodes */ |
411 | WARN_ON(!ifmodes); | 430 | WARN_ON(!ifmodes); |
412 | ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1; | 431 | ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1; |
@@ -466,7 +485,7 @@ int wiphy_register(struct wiphy *wiphy) | |||
466 | /* set up regulatory info */ | 485 | /* set up regulatory info */ |
467 | wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); | 486 | wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); |
468 | 487 | ||
469 | list_add(&rdev->list, &cfg80211_rdev_list); | 488 | list_add_rcu(&rdev->list, &cfg80211_rdev_list); |
470 | cfg80211_rdev_list_generation++; | 489 | cfg80211_rdev_list_generation++; |
471 | 490 | ||
472 | mutex_unlock(&cfg80211_mutex); | 491 | mutex_unlock(&cfg80211_mutex); |
@@ -478,7 +497,7 @@ int wiphy_register(struct wiphy *wiphy) | |||
478 | if (IS_ERR(rdev->wiphy.debugfsdir)) | 497 | if (IS_ERR(rdev->wiphy.debugfsdir)) |
479 | rdev->wiphy.debugfsdir = NULL; | 498 | rdev->wiphy.debugfsdir = NULL; |
480 | 499 | ||
481 | if (wiphy->custom_regulatory) { | 500 | if (wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) { |
482 | struct regulatory_request request; | 501 | struct regulatory_request request; |
483 | 502 | ||
484 | request.wiphy_idx = get_wiphy_idx(wiphy); | 503 | request.wiphy_idx = get_wiphy_idx(wiphy); |
@@ -542,8 +561,9 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
542 | * First remove the hardware from everywhere, this makes | 561 | * First remove the hardware from everywhere, this makes |
543 | * it impossible to find from userspace. | 562 | * it impossible to find from userspace. |
544 | */ | 563 | */ |
545 | cfg80211_debugfs_rdev_del(rdev); | 564 | debugfs_remove_recursive(rdev->wiphy.debugfsdir); |
546 | list_del(&rdev->list); | 565 | list_del_rcu(&rdev->list); |
566 | synchronize_rcu(); | ||
547 | 567 | ||
548 | /* | 568 | /* |
549 | * Try to grab rdev->mtx. If a command is still in progress, | 569 | * Try to grab rdev->mtx. If a command is still in progress, |
@@ -565,7 +585,6 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
565 | 585 | ||
566 | cfg80211_rdev_list_generation++; | 586 | cfg80211_rdev_list_generation++; |
567 | device_del(&rdev->wiphy.dev); | 587 | device_del(&rdev->wiphy.dev); |
568 | debugfs_remove(rdev->wiphy.debugfsdir); | ||
569 | 588 | ||
570 | mutex_unlock(&cfg80211_mutex); | 589 | mutex_unlock(&cfg80211_mutex); |
571 | 590 | ||
@@ -626,6 +645,10 @@ static void wdev_cleanup_work(struct work_struct *work) | |||
626 | dev_put(wdev->netdev); | 645 | dev_put(wdev->netdev); |
627 | } | 646 | } |
628 | 647 | ||
648 | static struct device_type wiphy_type = { | ||
649 | .name = "wlan", | ||
650 | }; | ||
651 | |||
629 | static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | 652 | static int cfg80211_netdev_notifier_call(struct notifier_block * nb, |
630 | unsigned long state, | 653 | unsigned long state, |
631 | void *ndev) | 654 | void *ndev) |
@@ -642,6 +665,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
642 | WARN_ON(wdev->iftype == NL80211_IFTYPE_UNSPECIFIED); | 665 | WARN_ON(wdev->iftype == NL80211_IFTYPE_UNSPECIFIED); |
643 | 666 | ||
644 | switch (state) { | 667 | switch (state) { |
668 | case NETDEV_POST_INIT: | ||
669 | SET_NETDEV_DEVTYPE(dev, &wiphy_type); | ||
670 | break; | ||
645 | case NETDEV_REGISTER: | 671 | case NETDEV_REGISTER: |
646 | /* | 672 | /* |
647 | * NB: cannot take rdev->mtx here because this may be | 673 | * NB: cannot take rdev->mtx here because this may be |
@@ -652,8 +678,11 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
652 | INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work); | 678 | INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work); |
653 | INIT_LIST_HEAD(&wdev->event_list); | 679 | INIT_LIST_HEAD(&wdev->event_list); |
654 | spin_lock_init(&wdev->event_lock); | 680 | spin_lock_init(&wdev->event_lock); |
681 | INIT_LIST_HEAD(&wdev->action_registrations); | ||
682 | spin_lock_init(&wdev->action_registrations_lock); | ||
683 | |||
655 | mutex_lock(&rdev->devlist_mtx); | 684 | mutex_lock(&rdev->devlist_mtx); |
656 | list_add(&wdev->list, &rdev->netdev_list); | 685 | list_add_rcu(&wdev->list, &rdev->netdev_list); |
657 | rdev->devlist_generation++; | 686 | rdev->devlist_generation++; |
658 | /* can only change netns with wiphy */ | 687 | /* can only change netns with wiphy */ |
659 | dev->features |= NETIF_F_NETNS_LOCAL; | 688 | dev->features |= NETIF_F_NETNS_LOCAL; |
@@ -666,22 +695,31 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
666 | wdev->netdev = dev; | 695 | wdev->netdev = dev; |
667 | wdev->sme_state = CFG80211_SME_IDLE; | 696 | wdev->sme_state = CFG80211_SME_IDLE; |
668 | mutex_unlock(&rdev->devlist_mtx); | 697 | mutex_unlock(&rdev->devlist_mtx); |
669 | #ifdef CONFIG_WIRELESS_EXT | 698 | #ifdef CONFIG_CFG80211_WEXT |
670 | if (!dev->wireless_handlers) | ||
671 | dev->wireless_handlers = &cfg80211_wext_handler; | ||
672 | wdev->wext.default_key = -1; | 699 | wdev->wext.default_key = -1; |
673 | wdev->wext.default_mgmt_key = -1; | 700 | wdev->wext.default_mgmt_key = -1; |
674 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; | 701 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; |
675 | wdev->wext.ps = wdev->wiphy->ps_default; | 702 | #endif |
676 | wdev->wext.ps_timeout = 100; | 703 | |
704 | if (wdev->wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT) | ||
705 | wdev->ps = true; | ||
706 | else | ||
707 | wdev->ps = false; | ||
708 | wdev->ps_timeout = 100; | ||
677 | if (rdev->ops->set_power_mgmt) | 709 | if (rdev->ops->set_power_mgmt) |
678 | if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, | 710 | if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, |
679 | wdev->wext.ps, | 711 | wdev->ps, |
680 | wdev->wext.ps_timeout)) { | 712 | wdev->ps_timeout)) { |
681 | /* assume this means it's off */ | 713 | /* assume this means it's off */ |
682 | wdev->wext.ps = false; | 714 | wdev->ps = false; |
683 | } | 715 | } |
684 | #endif | 716 | |
717 | if (!dev->ethtool_ops) | ||
718 | dev->ethtool_ops = &cfg80211_ethtool_ops; | ||
719 | |||
720 | if ((wdev->iftype == NL80211_IFTYPE_STATION || | ||
721 | wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr) | ||
722 | dev->priv_flags |= IFF_DONT_BRIDGE; | ||
685 | break; | 723 | break; |
686 | case NETDEV_GOING_DOWN: | 724 | case NETDEV_GOING_DOWN: |
687 | switch (wdev->iftype) { | 725 | switch (wdev->iftype) { |
@@ -690,7 +728,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
690 | break; | 728 | break; |
691 | case NL80211_IFTYPE_STATION: | 729 | case NL80211_IFTYPE_STATION: |
692 | wdev_lock(wdev); | 730 | wdev_lock(wdev); |
693 | #ifdef CONFIG_WIRELESS_EXT | 731 | #ifdef CONFIG_CFG80211_WEXT |
694 | kfree(wdev->wext.ie); | 732 | kfree(wdev->wext.ie); |
695 | wdev->wext.ie = NULL; | 733 | wdev->wext.ie = NULL; |
696 | wdev->wext.ie_len = 0; | 734 | wdev->wext.ie_len = 0; |
@@ -707,7 +745,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
707 | break; | 745 | break; |
708 | case NETDEV_DOWN: | 746 | case NETDEV_DOWN: |
709 | dev_hold(dev); | 747 | dev_hold(dev); |
710 | schedule_work(&wdev->cleanup_work); | 748 | queue_work(cfg80211_wq, &wdev->cleanup_work); |
711 | break; | 749 | break; |
712 | case NETDEV_UP: | 750 | case NETDEV_UP: |
713 | /* | 751 | /* |
@@ -722,9 +760,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
722 | mutex_unlock(&rdev->devlist_mtx); | 760 | mutex_unlock(&rdev->devlist_mtx); |
723 | dev_put(dev); | 761 | dev_put(dev); |
724 | } | 762 | } |
725 | #ifdef CONFIG_WIRELESS_EXT | ||
726 | cfg80211_lock_rdev(rdev); | 763 | cfg80211_lock_rdev(rdev); |
727 | mutex_lock(&rdev->devlist_mtx); | 764 | mutex_lock(&rdev->devlist_mtx); |
765 | #ifdef CONFIG_CFG80211_WEXT | ||
728 | wdev_lock(wdev); | 766 | wdev_lock(wdev); |
729 | switch (wdev->iftype) { | 767 | switch (wdev->iftype) { |
730 | case NL80211_IFTYPE_ADHOC: | 768 | case NL80211_IFTYPE_ADHOC: |
@@ -737,10 +775,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
737 | break; | 775 | break; |
738 | } | 776 | } |
739 | wdev_unlock(wdev); | 777 | wdev_unlock(wdev); |
778 | #endif | ||
740 | rdev->opencount++; | 779 | rdev->opencount++; |
741 | mutex_unlock(&rdev->devlist_mtx); | 780 | mutex_unlock(&rdev->devlist_mtx); |
742 | cfg80211_unlock_rdev(rdev); | 781 | cfg80211_unlock_rdev(rdev); |
743 | #endif | ||
744 | break; | 782 | break; |
745 | case NETDEV_UNREGISTER: | 783 | case NETDEV_UNREGISTER: |
746 | /* | 784 | /* |
@@ -758,13 +796,22 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
758 | */ | 796 | */ |
759 | if (!list_empty(&wdev->list)) { | 797 | if (!list_empty(&wdev->list)) { |
760 | sysfs_remove_link(&dev->dev.kobj, "phy80211"); | 798 | sysfs_remove_link(&dev->dev.kobj, "phy80211"); |
761 | list_del_init(&wdev->list); | 799 | list_del_rcu(&wdev->list); |
762 | rdev->devlist_generation++; | 800 | rdev->devlist_generation++; |
763 | #ifdef CONFIG_WIRELESS_EXT | 801 | cfg80211_mlme_purge_actions(wdev); |
802 | #ifdef CONFIG_CFG80211_WEXT | ||
764 | kfree(wdev->wext.keys); | 803 | kfree(wdev->wext.keys); |
765 | #endif | 804 | #endif |
766 | } | 805 | } |
767 | mutex_unlock(&rdev->devlist_mtx); | 806 | mutex_unlock(&rdev->devlist_mtx); |
807 | /* | ||
808 | * synchronise (so that we won't find this netdev | ||
809 | * from other code any more) and then clear the list | ||
810 | * head so that the above code can safely check for | ||
811 | * !list_empty() to avoid double-cleanup. | ||
812 | */ | ||
813 | synchronize_rcu(); | ||
814 | INIT_LIST_HEAD(&wdev->list); | ||
768 | break; | 815 | break; |
769 | case NETDEV_PRE_UP: | 816 | case NETDEV_PRE_UP: |
770 | if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) | 817 | if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) |
@@ -825,8 +872,14 @@ static int __init cfg80211_init(void) | |||
825 | if (err) | 872 | if (err) |
826 | goto out_fail_reg; | 873 | goto out_fail_reg; |
827 | 874 | ||
875 | cfg80211_wq = create_singlethread_workqueue("cfg80211"); | ||
876 | if (!cfg80211_wq) | ||
877 | goto out_fail_wq; | ||
878 | |||
828 | return 0; | 879 | return 0; |
829 | 880 | ||
881 | out_fail_wq: | ||
882 | regulatory_exit(); | ||
830 | out_fail_reg: | 883 | out_fail_reg: |
831 | debugfs_remove(ieee80211_debugfs_dir); | 884 | debugfs_remove(ieee80211_debugfs_dir); |
832 | out_fail_nl80211: | 885 | out_fail_nl80211: |
@@ -848,5 +901,6 @@ static void cfg80211_exit(void) | |||
848 | wiphy_sysfs_exit(); | 901 | wiphy_sysfs_exit(); |
849 | regulatory_exit(); | 902 | regulatory_exit(); |
850 | unregister_pernet_device(&cfg80211_pernet_ops); | 903 | unregister_pernet_device(&cfg80211_pernet_ops); |
904 | destroy_workqueue(cfg80211_wq); | ||
851 | } | 905 | } |
852 | module_exit(cfg80211_exit); | 906 | module_exit(cfg80211_exit); |