diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /net/wireless/core.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'net/wireless/core.c')
-rw-r--r-- | net/wireless/core.c | 231 |
1 files changed, 163 insertions, 68 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c index d6d046b9f6f2..880dbe2e6f94 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -4,6 +4,8 @@ | |||
4 | * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> | 4 | * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
8 | |||
7 | #include <linux/if.h> | 9 | #include <linux/if.h> |
8 | #include <linux/module.h> | 10 | #include <linux/module.h> |
9 | #include <linux/err.h> | 11 | #include <linux/err.h> |
@@ -44,6 +46,11 @@ static struct dentry *ieee80211_debugfs_dir; | |||
44 | /* for the cleanup, scan and event works */ | 46 | /* for the cleanup, scan and event works */ |
45 | struct workqueue_struct *cfg80211_wq; | 47 | struct workqueue_struct *cfg80211_wq; |
46 | 48 | ||
49 | static bool cfg80211_disable_40mhz_24ghz; | ||
50 | module_param(cfg80211_disable_40mhz_24ghz, bool, 0644); | ||
51 | MODULE_PARM_DESC(cfg80211_disable_40mhz_24ghz, | ||
52 | "Disable 40MHz support in the 2.4GHz band"); | ||
53 | |||
47 | /* requires cfg80211_mutex to be held! */ | 54 | /* requires cfg80211_mutex to be held! */ |
48 | struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx) | 55 | struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx) |
49 | { | 56 | { |
@@ -216,8 +223,7 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, | |||
216 | rdev->wiphy.debugfsdir, | 223 | rdev->wiphy.debugfsdir, |
217 | rdev->wiphy.debugfsdir->d_parent, | 224 | rdev->wiphy.debugfsdir->d_parent, |
218 | newname)) | 225 | newname)) |
219 | printk(KERN_ERR "cfg80211: failed to rename debugfs dir to %s!\n", | 226 | pr_err("failed to rename debugfs dir to %s!\n", newname); |
220 | newname); | ||
221 | 227 | ||
222 | nl80211_notify_dev_rename(rdev); | 228 | nl80211_notify_dev_rename(rdev); |
223 | 229 | ||
@@ -253,11 +259,16 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, | |||
253 | WARN_ON(err); | 259 | WARN_ON(err); |
254 | wdev->netdev->features |= NETIF_F_NETNS_LOCAL; | 260 | wdev->netdev->features |= NETIF_F_NETNS_LOCAL; |
255 | } | 261 | } |
262 | |||
263 | return err; | ||
256 | } | 264 | } |
257 | 265 | ||
258 | wiphy_net_set(&rdev->wiphy, net); | 266 | wiphy_net_set(&rdev->wiphy, net); |
259 | 267 | ||
260 | return err; | 268 | err = device_rename(&rdev->wiphy.dev, dev_name(&rdev->wiphy.dev)); |
269 | WARN_ON(err); | ||
270 | |||
271 | return 0; | ||
261 | } | 272 | } |
262 | 273 | ||
263 | static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data) | 274 | static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data) |
@@ -326,6 +337,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
326 | WARN_ON(ops->add_virtual_intf && !ops->del_virtual_intf); | 337 | WARN_ON(ops->add_virtual_intf && !ops->del_virtual_intf); |
327 | WARN_ON(ops->add_station && !ops->del_station); | 338 | WARN_ON(ops->add_station && !ops->del_station); |
328 | WARN_ON(ops->add_mpath && !ops->del_mpath); | 339 | WARN_ON(ops->add_mpath && !ops->del_mpath); |
340 | WARN_ON(ops->join_mesh && !ops->leave_mesh); | ||
329 | 341 | ||
330 | alloc_size = sizeof(*rdev) + sizeof_priv; | 342 | alloc_size = sizeof(*rdev) + sizeof_priv; |
331 | 343 | ||
@@ -354,11 +366,12 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
354 | 366 | ||
355 | mutex_init(&rdev->mtx); | 367 | mutex_init(&rdev->mtx); |
356 | mutex_init(&rdev->devlist_mtx); | 368 | mutex_init(&rdev->devlist_mtx); |
369 | mutex_init(&rdev->sched_scan_mtx); | ||
357 | INIT_LIST_HEAD(&rdev->netdev_list); | 370 | INIT_LIST_HEAD(&rdev->netdev_list); |
358 | spin_lock_init(&rdev->bss_lock); | 371 | spin_lock_init(&rdev->bss_lock); |
359 | INIT_LIST_HEAD(&rdev->bss_list); | 372 | INIT_LIST_HEAD(&rdev->bss_list); |
360 | INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); | 373 | INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); |
361 | 374 | INIT_WORK(&rdev->sched_scan_results_wk, __cfg80211_sched_scan_results); | |
362 | #ifdef CONFIG_CFG80211_WEXT | 375 | #ifdef CONFIG_CFG80211_WEXT |
363 | rdev->wiphy.wext = &cfg80211_wext_handler; | 376 | rdev->wiphy.wext = &cfg80211_wext_handler; |
364 | #endif | 377 | #endif |
@@ -404,6 +417,67 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
404 | } | 417 | } |
405 | EXPORT_SYMBOL(wiphy_new); | 418 | EXPORT_SYMBOL(wiphy_new); |
406 | 419 | ||
420 | static int wiphy_verify_combinations(struct wiphy *wiphy) | ||
421 | { | ||
422 | const struct ieee80211_iface_combination *c; | ||
423 | int i, j; | ||
424 | |||
425 | /* If we have combinations enforce them */ | ||
426 | if (wiphy->n_iface_combinations) | ||
427 | wiphy->flags |= WIPHY_FLAG_ENFORCE_COMBINATIONS; | ||
428 | |||
429 | for (i = 0; i < wiphy->n_iface_combinations; i++) { | ||
430 | u32 cnt = 0; | ||
431 | u16 all_iftypes = 0; | ||
432 | |||
433 | c = &wiphy->iface_combinations[i]; | ||
434 | |||
435 | /* Combinations with just one interface aren't real */ | ||
436 | if (WARN_ON(c->max_interfaces < 2)) | ||
437 | return -EINVAL; | ||
438 | |||
439 | /* Need at least one channel */ | ||
440 | if (WARN_ON(!c->num_different_channels)) | ||
441 | return -EINVAL; | ||
442 | |||
443 | if (WARN_ON(!c->n_limits)) | ||
444 | return -EINVAL; | ||
445 | |||
446 | for (j = 0; j < c->n_limits; j++) { | ||
447 | u16 types = c->limits[j].types; | ||
448 | |||
449 | /* | ||
450 | * interface types shouldn't overlap, this is | ||
451 | * used in cfg80211_can_change_interface() | ||
452 | */ | ||
453 | if (WARN_ON(types & all_iftypes)) | ||
454 | return -EINVAL; | ||
455 | all_iftypes |= types; | ||
456 | |||
457 | if (WARN_ON(!c->limits[j].max)) | ||
458 | return -EINVAL; | ||
459 | |||
460 | /* Shouldn't list software iftypes in combinations! */ | ||
461 | if (WARN_ON(wiphy->software_iftypes & types)) | ||
462 | return -EINVAL; | ||
463 | |||
464 | cnt += c->limits[j].max; | ||
465 | /* | ||
466 | * Don't advertise an unsupported type | ||
467 | * in a combination. | ||
468 | */ | ||
469 | if (WARN_ON((wiphy->interface_modes & types) != types)) | ||
470 | return -EINVAL; | ||
471 | } | ||
472 | |||
473 | /* You can't even choose that many! */ | ||
474 | if (WARN_ON(cnt < c->max_interfaces)) | ||
475 | return -EINVAL; | ||
476 | } | ||
477 | |||
478 | return 0; | ||
479 | } | ||
480 | |||
407 | int wiphy_register(struct wiphy *wiphy) | 481 | int wiphy_register(struct wiphy *wiphy) |
408 | { | 482 | { |
409 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 483 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
@@ -428,10 +502,14 @@ int wiphy_register(struct wiphy *wiphy) | |||
428 | 502 | ||
429 | /* sanity check ifmodes */ | 503 | /* sanity check ifmodes */ |
430 | WARN_ON(!ifmodes); | 504 | WARN_ON(!ifmodes); |
431 | ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1; | 505 | ifmodes &= ((1 << NUM_NL80211_IFTYPES) - 1) & ~1; |
432 | if (WARN_ON(ifmodes != wiphy->interface_modes)) | 506 | if (WARN_ON(ifmodes != wiphy->interface_modes)) |
433 | wiphy->interface_modes = ifmodes; | 507 | wiphy->interface_modes = ifmodes; |
434 | 508 | ||
509 | res = wiphy_verify_combinations(wiphy); | ||
510 | if (res) | ||
511 | return res; | ||
512 | |||
435 | /* sanity check supported bands/channels */ | 513 | /* sanity check supported bands/channels */ |
436 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 514 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
437 | sband = wiphy->bands[band]; | 515 | sband = wiphy->bands[band]; |
@@ -444,6 +522,18 @@ int wiphy_register(struct wiphy *wiphy) | |||
444 | return -EINVAL; | 522 | return -EINVAL; |
445 | 523 | ||
446 | /* | 524 | /* |
525 | * Since cfg80211_disable_40mhz_24ghz is global, we can | ||
526 | * modify the sband's ht data even if the driver uses a | ||
527 | * global structure for that. | ||
528 | */ | ||
529 | if (cfg80211_disable_40mhz_24ghz && | ||
530 | band == IEEE80211_BAND_2GHZ && | ||
531 | sband->ht_cap.ht_supported) { | ||
532 | sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
533 | sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
534 | } | ||
535 | |||
536 | /* | ||
447 | * Since we use a u32 for rate bitmaps in | 537 | * Since we use a u32 for rate bitmaps in |
448 | * ieee80211_get_response_rate, we cannot | 538 | * ieee80211_get_response_rate, we cannot |
449 | * have more than 32 legacy rates. | 539 | * have more than 32 legacy rates. |
@@ -469,6 +559,13 @@ int wiphy_register(struct wiphy *wiphy) | |||
469 | return -EINVAL; | 559 | return -EINVAL; |
470 | } | 560 | } |
471 | 561 | ||
562 | if (rdev->wiphy.wowlan.n_patterns) { | ||
563 | if (WARN_ON(!rdev->wiphy.wowlan.pattern_min_len || | ||
564 | rdev->wiphy.wowlan.pattern_min_len > | ||
565 | rdev->wiphy.wowlan.pattern_max_len)) | ||
566 | return -EINVAL; | ||
567 | } | ||
568 | |||
472 | /* check and set up bitrates */ | 569 | /* check and set up bitrates */ |
473 | ieee80211_set_bitrate_flags(wiphy); | 570 | ieee80211_set_bitrate_flags(wiphy); |
474 | 571 | ||
@@ -605,8 +702,10 @@ void cfg80211_dev_free(struct cfg80211_registered_device *rdev) | |||
605 | rfkill_destroy(rdev->rfkill); | 702 | rfkill_destroy(rdev->rfkill); |
606 | mutex_destroy(&rdev->mtx); | 703 | mutex_destroy(&rdev->mtx); |
607 | mutex_destroy(&rdev->devlist_mtx); | 704 | mutex_destroy(&rdev->devlist_mtx); |
705 | mutex_destroy(&rdev->sched_scan_mtx); | ||
608 | list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list) | 706 | list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list) |
609 | cfg80211_put_bss(&scan->pub); | 707 | cfg80211_put_bss(&scan->pub); |
708 | cfg80211_rdev_free_wowlan(rdev); | ||
610 | kfree(rdev); | 709 | kfree(rdev); |
611 | } | 710 | } |
612 | 711 | ||
@@ -642,6 +741,15 @@ static void wdev_cleanup_work(struct work_struct *work) | |||
642 | 741 | ||
643 | cfg80211_unlock_rdev(rdev); | 742 | cfg80211_unlock_rdev(rdev); |
644 | 743 | ||
744 | mutex_lock(&rdev->sched_scan_mtx); | ||
745 | |||
746 | if (WARN_ON(rdev->sched_scan_req && | ||
747 | rdev->sched_scan_req->dev == wdev->netdev)) { | ||
748 | __cfg80211_stop_sched_scan(rdev, false); | ||
749 | } | ||
750 | |||
751 | mutex_unlock(&rdev->sched_scan_mtx); | ||
752 | |||
645 | mutex_lock(&rdev->devlist_mtx); | 753 | mutex_lock(&rdev->devlist_mtx); |
646 | rdev->opencount--; | 754 | rdev->opencount--; |
647 | mutex_unlock(&rdev->devlist_mtx); | 755 | mutex_unlock(&rdev->devlist_mtx); |
@@ -661,6 +769,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
661 | struct net_device *dev = ndev; | 769 | struct net_device *dev = ndev; |
662 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 770 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
663 | struct cfg80211_registered_device *rdev; | 771 | struct cfg80211_registered_device *rdev; |
772 | int ret; | ||
664 | 773 | ||
665 | if (!wdev) | 774 | if (!wdev) |
666 | return NOTIFY_DONE; | 775 | return NOTIFY_DONE; |
@@ -683,8 +792,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
683 | INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work); | 792 | INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work); |
684 | INIT_LIST_HEAD(&wdev->event_list); | 793 | INIT_LIST_HEAD(&wdev->event_list); |
685 | spin_lock_init(&wdev->event_lock); | 794 | spin_lock_init(&wdev->event_lock); |
686 | INIT_LIST_HEAD(&wdev->action_registrations); | 795 | INIT_LIST_HEAD(&wdev->mgmt_registrations); |
687 | spin_lock_init(&wdev->action_registrations_lock); | 796 | spin_lock_init(&wdev->mgmt_registrations_lock); |
688 | 797 | ||
689 | mutex_lock(&rdev->devlist_mtx); | 798 | mutex_lock(&rdev->devlist_mtx); |
690 | list_add_rcu(&wdev->list, &rdev->netdev_list); | 799 | list_add_rcu(&wdev->list, &rdev->netdev_list); |
@@ -694,8 +803,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
694 | 803 | ||
695 | if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj, | 804 | if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj, |
696 | "phy80211")) { | 805 | "phy80211")) { |
697 | printk(KERN_ERR "wireless: failed to add phy80211 " | 806 | pr_err("failed to add phy80211 symlink to netdev!\n"); |
698 | "symlink to netdev!\n"); | ||
699 | } | 807 | } |
700 | wdev->netdev = dev; | 808 | wdev->netdev = dev; |
701 | wdev->sme_state = CFG80211_SME_IDLE; | 809 | wdev->sme_state = CFG80211_SME_IDLE; |
@@ -712,18 +820,12 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
712 | wdev->ps = false; | 820 | wdev->ps = false; |
713 | /* allow mac80211 to determine the timeout */ | 821 | /* allow mac80211 to determine the timeout */ |
714 | wdev->ps_timeout = -1; | 822 | wdev->ps_timeout = -1; |
715 | if (rdev->ops->set_power_mgmt) | ||
716 | if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, | ||
717 | wdev->ps, | ||
718 | wdev->ps_timeout)) { | ||
719 | /* assume this means it's off */ | ||
720 | wdev->ps = false; | ||
721 | } | ||
722 | 823 | ||
723 | if (!dev->ethtool_ops) | 824 | if (!dev->ethtool_ops) |
724 | dev->ethtool_ops = &cfg80211_ethtool_ops; | 825 | dev->ethtool_ops = &cfg80211_ethtool_ops; |
725 | 826 | ||
726 | if ((wdev->iftype == NL80211_IFTYPE_STATION || | 827 | if ((wdev->iftype == NL80211_IFTYPE_STATION || |
828 | wdev->iftype == NL80211_IFTYPE_P2P_CLIENT || | ||
727 | wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr) | 829 | wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr) |
728 | dev->priv_flags |= IFF_DONT_BRIDGE; | 830 | dev->priv_flags |= IFF_DONT_BRIDGE; |
729 | break; | 831 | break; |
@@ -732,7 +834,12 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
732 | case NL80211_IFTYPE_ADHOC: | 834 | case NL80211_IFTYPE_ADHOC: |
733 | cfg80211_leave_ibss(rdev, dev, true); | 835 | cfg80211_leave_ibss(rdev, dev, true); |
734 | break; | 836 | break; |
837 | case NL80211_IFTYPE_P2P_CLIENT: | ||
735 | case NL80211_IFTYPE_STATION: | 838 | case NL80211_IFTYPE_STATION: |
839 | mutex_lock(&rdev->sched_scan_mtx); | ||
840 | __cfg80211_stop_sched_scan(rdev, false); | ||
841 | mutex_unlock(&rdev->sched_scan_mtx); | ||
842 | |||
736 | wdev_lock(wdev); | 843 | wdev_lock(wdev); |
737 | #ifdef CONFIG_CFG80211_WEXT | 844 | #ifdef CONFIG_CFG80211_WEXT |
738 | kfree(wdev->wext.ie); | 845 | kfree(wdev->wext.ie); |
@@ -745,9 +852,13 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
745 | cfg80211_mlme_down(rdev, dev); | 852 | cfg80211_mlme_down(rdev, dev); |
746 | wdev_unlock(wdev); | 853 | wdev_unlock(wdev); |
747 | break; | 854 | break; |
855 | case NL80211_IFTYPE_MESH_POINT: | ||
856 | cfg80211_leave_mesh(rdev, dev); | ||
857 | break; | ||
748 | default: | 858 | default: |
749 | break; | 859 | break; |
750 | } | 860 | } |
861 | wdev->beacon_interval = 0; | ||
751 | break; | 862 | break; |
752 | case NETDEV_DOWN: | 863 | case NETDEV_DOWN: |
753 | dev_hold(dev); | 864 | dev_hold(dev); |
@@ -768,23 +879,53 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
768 | } | 879 | } |
769 | cfg80211_lock_rdev(rdev); | 880 | cfg80211_lock_rdev(rdev); |
770 | mutex_lock(&rdev->devlist_mtx); | 881 | mutex_lock(&rdev->devlist_mtx); |
771 | #ifdef CONFIG_CFG80211_WEXT | ||
772 | wdev_lock(wdev); | 882 | wdev_lock(wdev); |
773 | switch (wdev->iftype) { | 883 | switch (wdev->iftype) { |
884 | #ifdef CONFIG_CFG80211_WEXT | ||
774 | case NL80211_IFTYPE_ADHOC: | 885 | case NL80211_IFTYPE_ADHOC: |
775 | cfg80211_ibss_wext_join(rdev, wdev); | 886 | cfg80211_ibss_wext_join(rdev, wdev); |
776 | break; | 887 | break; |
777 | case NL80211_IFTYPE_STATION: | 888 | case NL80211_IFTYPE_STATION: |
778 | cfg80211_mgd_wext_connect(rdev, wdev); | 889 | cfg80211_mgd_wext_connect(rdev, wdev); |
779 | break; | 890 | break; |
891 | #endif | ||
892 | #ifdef CONFIG_MAC80211_MESH | ||
893 | case NL80211_IFTYPE_MESH_POINT: | ||
894 | { | ||
895 | /* backward compat code... */ | ||
896 | struct mesh_setup setup; | ||
897 | memcpy(&setup, &default_mesh_setup, | ||
898 | sizeof(setup)); | ||
899 | /* back compat only needed for mesh_id */ | ||
900 | setup.mesh_id = wdev->ssid; | ||
901 | setup.mesh_id_len = wdev->mesh_id_up_len; | ||
902 | if (wdev->mesh_id_up_len) | ||
903 | __cfg80211_join_mesh(rdev, dev, | ||
904 | &setup, | ||
905 | &default_mesh_config); | ||
906 | break; | ||
907 | } | ||
908 | #endif | ||
780 | default: | 909 | default: |
781 | break; | 910 | break; |
782 | } | 911 | } |
783 | wdev_unlock(wdev); | 912 | wdev_unlock(wdev); |
784 | #endif | ||
785 | rdev->opencount++; | 913 | rdev->opencount++; |
786 | mutex_unlock(&rdev->devlist_mtx); | 914 | mutex_unlock(&rdev->devlist_mtx); |
787 | cfg80211_unlock_rdev(rdev); | 915 | cfg80211_unlock_rdev(rdev); |
916 | |||
917 | /* | ||
918 | * Configure power management to the driver here so that its | ||
919 | * correctly set also after interface type changes etc. | ||
920 | */ | ||
921 | if (wdev->iftype == NL80211_IFTYPE_STATION && | ||
922 | rdev->ops->set_power_mgmt) | ||
923 | if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, | ||
924 | wdev->ps, | ||
925 | wdev->ps_timeout)) { | ||
926 | /* assume this means it's off */ | ||
927 | wdev->ps = false; | ||
928 | } | ||
788 | break; | 929 | break; |
789 | case NETDEV_UNREGISTER: | 930 | case NETDEV_UNREGISTER: |
790 | /* | 931 | /* |
@@ -804,7 +945,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
804 | sysfs_remove_link(&dev->dev.kobj, "phy80211"); | 945 | sysfs_remove_link(&dev->dev.kobj, "phy80211"); |
805 | list_del_rcu(&wdev->list); | 946 | list_del_rcu(&wdev->list); |
806 | rdev->devlist_generation++; | 947 | rdev->devlist_generation++; |
807 | cfg80211_mlme_purge_actions(wdev); | 948 | cfg80211_mlme_purge_registrations(wdev); |
808 | #ifdef CONFIG_CFG80211_WEXT | 949 | #ifdef CONFIG_CFG80211_WEXT |
809 | kfree(wdev->wext.keys); | 950 | kfree(wdev->wext.keys); |
810 | #endif | 951 | #endif |
@@ -824,6 +965,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
824 | return notifier_from_errno(-EOPNOTSUPP); | 965 | return notifier_from_errno(-EOPNOTSUPP); |
825 | if (rfkill_blocked(rdev->rfkill)) | 966 | if (rfkill_blocked(rdev->rfkill)) |
826 | return notifier_from_errno(-ERFKILL); | 967 | return notifier_from_errno(-ERFKILL); |
968 | ret = cfg80211_can_add_interface(rdev, wdev->iftype); | ||
969 | if (ret) | ||
970 | return notifier_from_errno(ret); | ||
827 | break; | 971 | break; |
828 | } | 972 | } |
829 | 973 | ||
@@ -910,52 +1054,3 @@ static void __exit cfg80211_exit(void) | |||
910 | destroy_workqueue(cfg80211_wq); | 1054 | destroy_workqueue(cfg80211_wq); |
911 | } | 1055 | } |
912 | module_exit(cfg80211_exit); | 1056 | module_exit(cfg80211_exit); |
913 | |||
914 | static int ___wiphy_printk(const char *level, const struct wiphy *wiphy, | ||
915 | struct va_format *vaf) | ||
916 | { | ||
917 | if (!wiphy) | ||
918 | return printk("%s(NULL wiphy *): %pV", level, vaf); | ||
919 | |||
920 | return printk("%s%s: %pV", level, wiphy_name(wiphy), vaf); | ||
921 | } | ||
922 | |||
923 | int __wiphy_printk(const char *level, const struct wiphy *wiphy, | ||
924 | const char *fmt, ...) | ||
925 | { | ||
926 | struct va_format vaf; | ||
927 | va_list args; | ||
928 | int r; | ||
929 | |||
930 | va_start(args, fmt); | ||
931 | |||
932 | vaf.fmt = fmt; | ||
933 | vaf.va = &args; | ||
934 | |||
935 | r = ___wiphy_printk(level, wiphy, &vaf); | ||
936 | va_end(args); | ||
937 | |||
938 | return r; | ||
939 | } | ||
940 | EXPORT_SYMBOL(__wiphy_printk); | ||
941 | |||
942 | #define define_wiphy_printk_level(func, kern_level) \ | ||
943 | int func(const struct wiphy *wiphy, const char *fmt, ...) \ | ||
944 | { \ | ||
945 | struct va_format vaf; \ | ||
946 | va_list args; \ | ||
947 | int r; \ | ||
948 | \ | ||
949 | va_start(args, fmt); \ | ||
950 | \ | ||
951 | vaf.fmt = fmt; \ | ||
952 | vaf.va = &args; \ | ||
953 | \ | ||
954 | r = ___wiphy_printk(kern_level, wiphy, &vaf); \ | ||
955 | va_end(args); \ | ||
956 | \ | ||
957 | return r; \ | ||
958 | } \ | ||
959 | EXPORT_SYMBOL(func); | ||
960 | |||
961 | define_wiphy_printk_level(wiphy_debug, KERN_DEBUG); | ||