diff options
Diffstat (limited to 'net/wireless/core.c')
| -rw-r--r-- | net/wireless/core.c | 280 |
1 files changed, 81 insertions, 199 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c index 73405e00c800..67153964aad2 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
| @@ -34,13 +34,12 @@ | |||
| 34 | MODULE_AUTHOR("Johannes Berg"); | 34 | MODULE_AUTHOR("Johannes Berg"); |
| 35 | MODULE_LICENSE("GPL"); | 35 | MODULE_LICENSE("GPL"); |
| 36 | MODULE_DESCRIPTION("wireless configuration support"); | 36 | MODULE_DESCRIPTION("wireless configuration support"); |
| 37 | MODULE_ALIAS_GENL_FAMILY(NL80211_GENL_NAME); | ||
| 37 | 38 | ||
| 38 | /* RCU-protected (and cfg80211_mutex for writers) */ | 39 | /* RCU-protected (and RTNL for writers) */ |
| 39 | LIST_HEAD(cfg80211_rdev_list); | 40 | LIST_HEAD(cfg80211_rdev_list); |
| 40 | int cfg80211_rdev_list_generation; | 41 | int cfg80211_rdev_list_generation; |
| 41 | 42 | ||
| 42 | DEFINE_MUTEX(cfg80211_mutex); | ||
| 43 | |||
| 44 | /* for debugfs */ | 43 | /* for debugfs */ |
| 45 | static struct dentry *ieee80211_debugfs_dir; | 44 | static struct dentry *ieee80211_debugfs_dir; |
| 46 | 45 | ||
| @@ -52,12 +51,11 @@ module_param(cfg80211_disable_40mhz_24ghz, bool, 0644); | |||
| 52 | MODULE_PARM_DESC(cfg80211_disable_40mhz_24ghz, | 51 | MODULE_PARM_DESC(cfg80211_disable_40mhz_24ghz, |
| 53 | "Disable 40MHz support in the 2.4GHz band"); | 52 | "Disable 40MHz support in the 2.4GHz band"); |
| 54 | 53 | ||
| 55 | /* requires cfg80211_mutex to be held! */ | ||
| 56 | struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx) | 54 | struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx) |
| 57 | { | 55 | { |
| 58 | struct cfg80211_registered_device *result = NULL, *rdev; | 56 | struct cfg80211_registered_device *result = NULL, *rdev; |
| 59 | 57 | ||
| 60 | assert_cfg80211_lock(); | 58 | ASSERT_RTNL(); |
| 61 | 59 | ||
| 62 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | 60 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
| 63 | if (rdev->wiphy_idx == wiphy_idx) { | 61 | if (rdev->wiphy_idx == wiphy_idx) { |
| @@ -76,12 +74,11 @@ int get_wiphy_idx(struct wiphy *wiphy) | |||
| 76 | return rdev->wiphy_idx; | 74 | return rdev->wiphy_idx; |
| 77 | } | 75 | } |
| 78 | 76 | ||
| 79 | /* requires cfg80211_rdev_mutex to be held! */ | ||
| 80 | struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx) | 77 | struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx) |
| 81 | { | 78 | { |
| 82 | struct cfg80211_registered_device *rdev; | 79 | struct cfg80211_registered_device *rdev; |
| 83 | 80 | ||
| 84 | assert_cfg80211_lock(); | 81 | ASSERT_RTNL(); |
| 85 | 82 | ||
| 86 | rdev = cfg80211_rdev_by_wiphy_idx(wiphy_idx); | 83 | rdev = cfg80211_rdev_by_wiphy_idx(wiphy_idx); |
| 87 | if (!rdev) | 84 | if (!rdev) |
| @@ -89,35 +86,13 @@ struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx) | |||
| 89 | return &rdev->wiphy; | 86 | return &rdev->wiphy; |
| 90 | } | 87 | } |
| 91 | 88 | ||
| 92 | struct cfg80211_registered_device * | ||
| 93 | cfg80211_get_dev_from_ifindex(struct net *net, int ifindex) | ||
| 94 | { | ||
| 95 | struct cfg80211_registered_device *rdev = ERR_PTR(-ENODEV); | ||
| 96 | struct net_device *dev; | ||
| 97 | |||
| 98 | mutex_lock(&cfg80211_mutex); | ||
| 99 | dev = dev_get_by_index(net, ifindex); | ||
| 100 | if (!dev) | ||
| 101 | goto out; | ||
| 102 | if (dev->ieee80211_ptr) { | ||
| 103 | rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy); | ||
| 104 | mutex_lock(&rdev->mtx); | ||
| 105 | } else | ||
| 106 | rdev = ERR_PTR(-ENODEV); | ||
| 107 | dev_put(dev); | ||
| 108 | out: | ||
| 109 | mutex_unlock(&cfg80211_mutex); | ||
| 110 | return rdev; | ||
| 111 | } | ||
| 112 | |||
| 113 | /* requires cfg80211_mutex to be held */ | ||
| 114 | int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, | 89 | int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, |
| 115 | char *newname) | 90 | char *newname) |
| 116 | { | 91 | { |
| 117 | struct cfg80211_registered_device *rdev2; | 92 | struct cfg80211_registered_device *rdev2; |
| 118 | int wiphy_idx, taken = -1, result, digits; | 93 | int wiphy_idx, taken = -1, result, digits; |
| 119 | 94 | ||
| 120 | assert_cfg80211_lock(); | 95 | ASSERT_RTNL(); |
| 121 | 96 | ||
| 122 | /* prohibit calling the thing phy%d when %d is not its number */ | 97 | /* prohibit calling the thing phy%d when %d is not its number */ |
| 123 | sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken); | 98 | sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken); |
| @@ -215,8 +190,7 @@ static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data) | |||
| 215 | void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, | 190 | void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, |
| 216 | struct wireless_dev *wdev) | 191 | struct wireless_dev *wdev) |
| 217 | { | 192 | { |
| 218 | lockdep_assert_held(&rdev->devlist_mtx); | 193 | ASSERT_RTNL(); |
| 219 | lockdep_assert_held(&rdev->sched_scan_mtx); | ||
| 220 | 194 | ||
| 221 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)) | 195 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)) |
| 222 | return; | 196 | return; |
| @@ -230,18 +204,15 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, | |||
| 230 | rdev->opencount--; | 204 | rdev->opencount--; |
| 231 | 205 | ||
| 232 | if (rdev->scan_req && rdev->scan_req->wdev == wdev) { | 206 | if (rdev->scan_req && rdev->scan_req->wdev == wdev) { |
| 233 | bool busy = work_busy(&rdev->scan_done_wk); | ||
| 234 | |||
| 235 | /* | 207 | /* |
| 236 | * If the work isn't pending or running (in which case it would | 208 | * If the scan request wasn't notified as done, set it |
| 237 | * be waiting for the lock we hold) the driver didn't properly | 209 | * to aborted and leak it after a warning. The driver |
| 238 | * cancel the scan when the interface was removed. In this case | 210 | * should have notified us that it ended at the latest |
| 239 | * warn and leak the scan request object to not crash later. | 211 | * during rdev_stop_p2p_device(). |
| 240 | */ | 212 | */ |
| 241 | WARN_ON(!busy); | 213 | if (WARN_ON(!rdev->scan_req->notified)) |
| 242 | 214 | rdev->scan_req->aborted = true; | |
| 243 | rdev->scan_req->aborted = true; | 215 | ___cfg80211_scan_done(rdev, !rdev->scan_req->notified); |
| 244 | ___cfg80211_scan_done(rdev, !busy); | ||
| 245 | } | 216 | } |
| 246 | } | 217 | } |
| 247 | 218 | ||
| @@ -255,8 +226,6 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked) | |||
| 255 | 226 | ||
| 256 | rtnl_lock(); | 227 | rtnl_lock(); |
| 257 | 228 | ||
| 258 | /* read-only iteration need not hold the devlist_mtx */ | ||
| 259 | |||
| 260 | list_for_each_entry(wdev, &rdev->wdev_list, list) { | 229 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
| 261 | if (wdev->netdev) { | 230 | if (wdev->netdev) { |
| 262 | dev_close(wdev->netdev); | 231 | dev_close(wdev->netdev); |
| @@ -265,12 +234,7 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked) | |||
| 265 | /* otherwise, check iftype */ | 234 | /* otherwise, check iftype */ |
| 266 | switch (wdev->iftype) { | 235 | switch (wdev->iftype) { |
| 267 | case NL80211_IFTYPE_P2P_DEVICE: | 236 | case NL80211_IFTYPE_P2P_DEVICE: |
| 268 | /* but this requires it */ | ||
| 269 | mutex_lock(&rdev->devlist_mtx); | ||
| 270 | mutex_lock(&rdev->sched_scan_mtx); | ||
| 271 | cfg80211_stop_p2p_device(rdev, wdev); | 237 | cfg80211_stop_p2p_device(rdev, wdev); |
| 272 | mutex_unlock(&rdev->sched_scan_mtx); | ||
| 273 | mutex_unlock(&rdev->devlist_mtx); | ||
| 274 | break; | 238 | break; |
| 275 | default: | 239 | default: |
| 276 | break; | 240 | break; |
| @@ -298,10 +262,7 @@ static void cfg80211_event_work(struct work_struct *work) | |||
| 298 | event_work); | 262 | event_work); |
| 299 | 263 | ||
| 300 | rtnl_lock(); | 264 | rtnl_lock(); |
| 301 | cfg80211_lock_rdev(rdev); | ||
| 302 | |||
| 303 | cfg80211_process_rdev_events(rdev); | 265 | cfg80211_process_rdev_events(rdev); |
| 304 | cfg80211_unlock_rdev(rdev); | ||
| 305 | rtnl_unlock(); | 266 | rtnl_unlock(); |
| 306 | } | 267 | } |
| 307 | 268 | ||
| @@ -309,7 +270,7 @@ static void cfg80211_event_work(struct work_struct *work) | |||
| 309 | 270 | ||
| 310 | struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | 271 | struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) |
| 311 | { | 272 | { |
| 312 | static int wiphy_counter; | 273 | static atomic_t wiphy_counter = ATOMIC_INIT(0); |
| 313 | 274 | ||
| 314 | struct cfg80211_registered_device *rdev; | 275 | struct cfg80211_registered_device *rdev; |
| 315 | int alloc_size; | 276 | int alloc_size; |
| @@ -331,26 +292,21 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
| 331 | 292 | ||
| 332 | rdev->ops = ops; | 293 | rdev->ops = ops; |
| 333 | 294 | ||
| 334 | mutex_lock(&cfg80211_mutex); | 295 | rdev->wiphy_idx = atomic_inc_return(&wiphy_counter); |
| 335 | |||
| 336 | rdev->wiphy_idx = wiphy_counter++; | ||
| 337 | 296 | ||
| 338 | if (unlikely(rdev->wiphy_idx < 0)) { | 297 | if (unlikely(rdev->wiphy_idx < 0)) { |
| 339 | wiphy_counter--; | ||
| 340 | mutex_unlock(&cfg80211_mutex); | ||
| 341 | /* ugh, wrapped! */ | 298 | /* ugh, wrapped! */ |
| 299 | atomic_dec(&wiphy_counter); | ||
| 342 | kfree(rdev); | 300 | kfree(rdev); |
| 343 | return NULL; | 301 | return NULL; |
| 344 | } | 302 | } |
| 345 | 303 | ||
| 346 | mutex_unlock(&cfg80211_mutex); | 304 | /* atomic_inc_return makes it start at 1, make it start at 0 */ |
| 305 | rdev->wiphy_idx--; | ||
| 347 | 306 | ||
| 348 | /* give it a proper name */ | 307 | /* give it a proper name */ |
| 349 | dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx); | 308 | dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx); |
| 350 | 309 | ||
| 351 | mutex_init(&rdev->mtx); | ||
| 352 | mutex_init(&rdev->devlist_mtx); | ||
| 353 | mutex_init(&rdev->sched_scan_mtx); | ||
| 354 | INIT_LIST_HEAD(&rdev->wdev_list); | 310 | INIT_LIST_HEAD(&rdev->wdev_list); |
| 355 | INIT_LIST_HEAD(&rdev->beacon_registrations); | 311 | INIT_LIST_HEAD(&rdev->beacon_registrations); |
| 356 | spin_lock_init(&rdev->beacon_registrations_lock); | 312 | spin_lock_init(&rdev->beacon_registrations_lock); |
| @@ -496,11 +452,24 @@ int wiphy_register(struct wiphy *wiphy) | |||
| 496 | u16 ifmodes = wiphy->interface_modes; | 452 | u16 ifmodes = wiphy->interface_modes; |
| 497 | 453 | ||
| 498 | #ifdef CONFIG_PM | 454 | #ifdef CONFIG_PM |
| 499 | if (WARN_ON((wiphy->wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) && | 455 | if (WARN_ON(wiphy->wowlan && |
| 500 | !(wiphy->wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY))) | 456 | (wiphy->wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) && |
| 457 | !(wiphy->wowlan->flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY))) | ||
| 458 | return -EINVAL; | ||
| 459 | if (WARN_ON(wiphy->wowlan && | ||
| 460 | !wiphy->wowlan->flags && !wiphy->wowlan->n_patterns && | ||
| 461 | !wiphy->wowlan->tcp)) | ||
| 501 | return -EINVAL; | 462 | return -EINVAL; |
| 502 | #endif | 463 | #endif |
| 503 | 464 | ||
| 465 | if (WARN_ON(wiphy->coalesce && | ||
| 466 | (!wiphy->coalesce->n_rules || | ||
| 467 | !wiphy->coalesce->n_patterns) && | ||
| 468 | (!wiphy->coalesce->pattern_min_len || | ||
| 469 | wiphy->coalesce->pattern_min_len > | ||
| 470 | wiphy->coalesce->pattern_max_len))) | ||
| 471 | return -EINVAL; | ||
| 472 | |||
| 504 | if (WARN_ON(wiphy->ap_sme_capa && | 473 | if (WARN_ON(wiphy->ap_sme_capa && |
| 505 | !(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME))) | 474 | !(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME))) |
| 506 | return -EINVAL; | 475 | return -EINVAL; |
| @@ -587,25 +556,28 @@ int wiphy_register(struct wiphy *wiphy) | |||
| 587 | } | 556 | } |
| 588 | 557 | ||
| 589 | #ifdef CONFIG_PM | 558 | #ifdef CONFIG_PM |
| 590 | if (rdev->wiphy.wowlan.n_patterns) { | 559 | if (WARN_ON(rdev->wiphy.wowlan && rdev->wiphy.wowlan->n_patterns && |
| 591 | if (WARN_ON(!rdev->wiphy.wowlan.pattern_min_len || | 560 | (!rdev->wiphy.wowlan->pattern_min_len || |
| 592 | rdev->wiphy.wowlan.pattern_min_len > | 561 | rdev->wiphy.wowlan->pattern_min_len > |
| 593 | rdev->wiphy.wowlan.pattern_max_len)) | 562 | rdev->wiphy.wowlan->pattern_max_len))) |
| 594 | return -EINVAL; | 563 | return -EINVAL; |
| 595 | } | ||
| 596 | #endif | 564 | #endif |
| 597 | 565 | ||
| 598 | /* check and set up bitrates */ | 566 | /* check and set up bitrates */ |
| 599 | ieee80211_set_bitrate_flags(wiphy); | 567 | ieee80211_set_bitrate_flags(wiphy); |
| 600 | 568 | ||
| 601 | mutex_lock(&cfg80211_mutex); | ||
| 602 | 569 | ||
| 603 | res = device_add(&rdev->wiphy.dev); | 570 | res = device_add(&rdev->wiphy.dev); |
| 571 | if (res) | ||
| 572 | return res; | ||
| 573 | |||
| 574 | res = rfkill_register(rdev->rfkill); | ||
| 604 | if (res) { | 575 | if (res) { |
| 605 | mutex_unlock(&cfg80211_mutex); | 576 | device_del(&rdev->wiphy.dev); |
| 606 | return res; | 577 | return res; |
| 607 | } | 578 | } |
| 608 | 579 | ||
| 580 | rtnl_lock(); | ||
| 609 | /* set up regulatory info */ | 581 | /* set up regulatory info */ |
| 610 | wiphy_regulatory_register(wiphy); | 582 | wiphy_regulatory_register(wiphy); |
| 611 | 583 | ||
| @@ -631,25 +603,7 @@ int wiphy_register(struct wiphy *wiphy) | |||
| 631 | } | 603 | } |
| 632 | 604 | ||
| 633 | cfg80211_debugfs_rdev_add(rdev); | 605 | cfg80211_debugfs_rdev_add(rdev); |
| 634 | mutex_unlock(&cfg80211_mutex); | ||
| 635 | 606 | ||
| 636 | /* | ||
| 637 | * due to a locking dependency this has to be outside of the | ||
| 638 | * cfg80211_mutex lock | ||
| 639 | */ | ||
| 640 | res = rfkill_register(rdev->rfkill); | ||
| 641 | if (res) { | ||
| 642 | device_del(&rdev->wiphy.dev); | ||
| 643 | |||
| 644 | mutex_lock(&cfg80211_mutex); | ||
| 645 | debugfs_remove_recursive(rdev->wiphy.debugfsdir); | ||
| 646 | list_del_rcu(&rdev->list); | ||
| 647 | wiphy_regulatory_deregister(wiphy); | ||
| 648 | mutex_unlock(&cfg80211_mutex); | ||
| 649 | return res; | ||
| 650 | } | ||
| 651 | |||
| 652 | rtnl_lock(); | ||
| 653 | rdev->wiphy.registered = true; | 607 | rdev->wiphy.registered = true; |
| 654 | rtnl_unlock(); | 608 | rtnl_unlock(); |
| 655 | return 0; | 609 | return 0; |
| @@ -679,25 +633,19 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
| 679 | { | 633 | { |
| 680 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 634 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
| 681 | 635 | ||
| 682 | rtnl_lock(); | ||
| 683 | rdev->wiphy.registered = false; | ||
| 684 | rtnl_unlock(); | ||
| 685 | |||
| 686 | rfkill_unregister(rdev->rfkill); | ||
| 687 | |||
| 688 | /* protect the device list */ | ||
| 689 | mutex_lock(&cfg80211_mutex); | ||
| 690 | |||
| 691 | wait_event(rdev->dev_wait, ({ | 636 | wait_event(rdev->dev_wait, ({ |
| 692 | int __count; | 637 | int __count; |
| 693 | mutex_lock(&rdev->devlist_mtx); | 638 | rtnl_lock(); |
| 694 | __count = rdev->opencount; | 639 | __count = rdev->opencount; |
| 695 | mutex_unlock(&rdev->devlist_mtx); | 640 | rtnl_unlock(); |
| 696 | __count == 0; })); | 641 | __count == 0; })); |
| 697 | 642 | ||
| 698 | mutex_lock(&rdev->devlist_mtx); | 643 | rfkill_unregister(rdev->rfkill); |
| 644 | |||
| 645 | rtnl_lock(); | ||
| 646 | rdev->wiphy.registered = false; | ||
| 647 | |||
| 699 | BUG_ON(!list_empty(&rdev->wdev_list)); | 648 | BUG_ON(!list_empty(&rdev->wdev_list)); |
| 700 | mutex_unlock(&rdev->devlist_mtx); | ||
| 701 | 649 | ||
| 702 | /* | 650 | /* |
| 703 | * First remove the hardware from everywhere, this makes | 651 | * First remove the hardware from everywhere, this makes |
| @@ -708,20 +656,6 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
| 708 | synchronize_rcu(); | 656 | synchronize_rcu(); |
| 709 | 657 | ||
| 710 | /* | 658 | /* |
| 711 | * Try to grab rdev->mtx. If a command is still in progress, | ||
| 712 | * hopefully the driver will refuse it since it's tearing | ||
| 713 | * down the device already. We wait for this command to complete | ||
| 714 | * before unlinking the item from the list. | ||
| 715 | * Note: as codified by the BUG_ON above we cannot get here if | ||
| 716 | * a virtual interface is still present. Hence, we can only get | ||
| 717 | * to lock contention here if userspace issues a command that | ||
| 718 | * identified the hardware by wiphy index. | ||
| 719 | */ | ||
| 720 | cfg80211_lock_rdev(rdev); | ||
| 721 | /* nothing */ | ||
| 722 | cfg80211_unlock_rdev(rdev); | ||
| 723 | |||
| 724 | /* | ||
| 725 | * If this device got a regulatory hint tell core its | 659 | * If this device got a regulatory hint tell core its |
| 726 | * free to listen now to a new shiny device regulatory hint | 660 | * free to listen now to a new shiny device regulatory hint |
| 727 | */ | 661 | */ |
| @@ -730,16 +664,19 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
| 730 | cfg80211_rdev_list_generation++; | 664 | cfg80211_rdev_list_generation++; |
| 731 | device_del(&rdev->wiphy.dev); | 665 | device_del(&rdev->wiphy.dev); |
| 732 | 666 | ||
| 733 | mutex_unlock(&cfg80211_mutex); | 667 | rtnl_unlock(); |
| 734 | 668 | ||
| 735 | flush_work(&rdev->scan_done_wk); | 669 | flush_work(&rdev->scan_done_wk); |
| 736 | cancel_work_sync(&rdev->conn_work); | 670 | cancel_work_sync(&rdev->conn_work); |
| 737 | flush_work(&rdev->event_work); | 671 | flush_work(&rdev->event_work); |
| 738 | cancel_delayed_work_sync(&rdev->dfs_update_channels_wk); | 672 | cancel_delayed_work_sync(&rdev->dfs_update_channels_wk); |
| 739 | 673 | ||
| 740 | if (rdev->wowlan && rdev->ops->set_wakeup) | 674 | #ifdef CONFIG_PM |
| 675 | if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup) | ||
| 741 | rdev_set_wakeup(rdev, false); | 676 | rdev_set_wakeup(rdev, false); |
| 677 | #endif | ||
| 742 | cfg80211_rdev_free_wowlan(rdev); | 678 | cfg80211_rdev_free_wowlan(rdev); |
| 679 | cfg80211_rdev_free_coalesce(rdev); | ||
| 743 | } | 680 | } |
| 744 | EXPORT_SYMBOL(wiphy_unregister); | 681 | EXPORT_SYMBOL(wiphy_unregister); |
| 745 | 682 | ||
| @@ -748,9 +685,6 @@ void cfg80211_dev_free(struct cfg80211_registered_device *rdev) | |||
| 748 | struct cfg80211_internal_bss *scan, *tmp; | 685 | struct cfg80211_internal_bss *scan, *tmp; |
| 749 | struct cfg80211_beacon_registration *reg, *treg; | 686 | struct cfg80211_beacon_registration *reg, *treg; |
| 750 | rfkill_destroy(rdev->rfkill); | 687 | rfkill_destroy(rdev->rfkill); |
| 751 | mutex_destroy(&rdev->mtx); | ||
| 752 | mutex_destroy(&rdev->devlist_mtx); | ||
| 753 | mutex_destroy(&rdev->sched_scan_mtx); | ||
| 754 | list_for_each_entry_safe(reg, treg, &rdev->beacon_registrations, list) { | 688 | list_for_each_entry_safe(reg, treg, &rdev->beacon_registrations, list) { |
| 755 | list_del(®->list); | 689 | list_del(®->list); |
| 756 | kfree(reg); | 690 | kfree(reg); |
| @@ -775,36 +709,6 @@ void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked) | |||
| 775 | } | 709 | } |
| 776 | EXPORT_SYMBOL(wiphy_rfkill_set_hw_state); | 710 | EXPORT_SYMBOL(wiphy_rfkill_set_hw_state); |
| 777 | 711 | ||
| 778 | static void wdev_cleanup_work(struct work_struct *work) | ||
| 779 | { | ||
| 780 | struct wireless_dev *wdev; | ||
| 781 | struct cfg80211_registered_device *rdev; | ||
| 782 | |||
| 783 | wdev = container_of(work, struct wireless_dev, cleanup_work); | ||
| 784 | rdev = wiphy_to_dev(wdev->wiphy); | ||
| 785 | |||
| 786 | mutex_lock(&rdev->sched_scan_mtx); | ||
| 787 | |||
| 788 | if (WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev)) { | ||
| 789 | rdev->scan_req->aborted = true; | ||
| 790 | ___cfg80211_scan_done(rdev, true); | ||
| 791 | } | ||
| 792 | |||
| 793 | if (WARN_ON(rdev->sched_scan_req && | ||
| 794 | rdev->sched_scan_req->dev == wdev->netdev)) { | ||
| 795 | __cfg80211_stop_sched_scan(rdev, false); | ||
| 796 | } | ||
| 797 | |||
| 798 | mutex_unlock(&rdev->sched_scan_mtx); | ||
| 799 | |||
| 800 | mutex_lock(&rdev->devlist_mtx); | ||
| 801 | rdev->opencount--; | ||
| 802 | mutex_unlock(&rdev->devlist_mtx); | ||
| 803 | wake_up(&rdev->dev_wait); | ||
| 804 | |||
| 805 | dev_put(wdev->netdev); | ||
| 806 | } | ||
| 807 | |||
| 808 | void cfg80211_unregister_wdev(struct wireless_dev *wdev) | 712 | void cfg80211_unregister_wdev(struct wireless_dev *wdev) |
| 809 | { | 713 | { |
| 810 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 714 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
| @@ -814,8 +718,6 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev) | |||
| 814 | if (WARN_ON(wdev->netdev)) | 718 | if (WARN_ON(wdev->netdev)) |
| 815 | return; | 719 | return; |
| 816 | 720 | ||
| 817 | mutex_lock(&rdev->devlist_mtx); | ||
| 818 | mutex_lock(&rdev->sched_scan_mtx); | ||
| 819 | list_del_rcu(&wdev->list); | 721 | list_del_rcu(&wdev->list); |
| 820 | rdev->devlist_generation++; | 722 | rdev->devlist_generation++; |
| 821 | 723 | ||
| @@ -827,8 +729,6 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev) | |||
| 827 | WARN_ON_ONCE(1); | 729 | WARN_ON_ONCE(1); |
| 828 | break; | 730 | break; |
| 829 | } | 731 | } |
| 830 | mutex_unlock(&rdev->sched_scan_mtx); | ||
| 831 | mutex_unlock(&rdev->devlist_mtx); | ||
| 832 | } | 732 | } |
| 833 | EXPORT_SYMBOL(cfg80211_unregister_wdev); | 733 | EXPORT_SYMBOL(cfg80211_unregister_wdev); |
| 834 | 734 | ||
| @@ -847,7 +747,7 @@ void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, | |||
| 847 | } | 747 | } |
| 848 | 748 | ||
| 849 | void cfg80211_leave(struct cfg80211_registered_device *rdev, | 749 | void cfg80211_leave(struct cfg80211_registered_device *rdev, |
| 850 | struct wireless_dev *wdev) | 750 | struct wireless_dev *wdev) |
| 851 | { | 751 | { |
| 852 | struct net_device *dev = wdev->netdev; | 752 | struct net_device *dev = wdev->netdev; |
| 853 | 753 | ||
| @@ -857,9 +757,7 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev, | |||
| 857 | break; | 757 | break; |
| 858 | case NL80211_IFTYPE_P2P_CLIENT: | 758 | case NL80211_IFTYPE_P2P_CLIENT: |
| 859 | case NL80211_IFTYPE_STATION: | 759 | case NL80211_IFTYPE_STATION: |
| 860 | mutex_lock(&rdev->sched_scan_mtx); | ||
| 861 | __cfg80211_stop_sched_scan(rdev, false); | 760 | __cfg80211_stop_sched_scan(rdev, false); |
| 862 | mutex_unlock(&rdev->sched_scan_mtx); | ||
| 863 | 761 | ||
| 864 | wdev_lock(wdev); | 762 | wdev_lock(wdev); |
| 865 | #ifdef CONFIG_CFG80211_WEXT | 763 | #ifdef CONFIG_CFG80211_WEXT |
| @@ -868,14 +766,15 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev, | |||
| 868 | wdev->wext.ie_len = 0; | 766 | wdev->wext.ie_len = 0; |
| 869 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; | 767 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; |
| 870 | #endif | 768 | #endif |
| 871 | __cfg80211_disconnect(rdev, dev, | 769 | cfg80211_disconnect(rdev, dev, |
| 872 | WLAN_REASON_DEAUTH_LEAVING, true); | 770 | WLAN_REASON_DEAUTH_LEAVING, true); |
| 873 | wdev_unlock(wdev); | 771 | wdev_unlock(wdev); |
| 874 | break; | 772 | break; |
| 875 | case NL80211_IFTYPE_MESH_POINT: | 773 | case NL80211_IFTYPE_MESH_POINT: |
| 876 | cfg80211_leave_mesh(rdev, dev); | 774 | cfg80211_leave_mesh(rdev, dev); |
| 877 | break; | 775 | break; |
| 878 | case NL80211_IFTYPE_AP: | 776 | case NL80211_IFTYPE_AP: |
| 777 | case NL80211_IFTYPE_P2P_GO: | ||
| 879 | cfg80211_stop_ap(rdev, dev); | 778 | cfg80211_stop_ap(rdev, dev); |
| 880 | break; | 779 | break; |
| 881 | default: | 780 | default: |
| @@ -886,10 +785,9 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev, | |||
| 886 | } | 785 | } |
| 887 | 786 | ||
| 888 | static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | 787 | static int cfg80211_netdev_notifier_call(struct notifier_block *nb, |
| 889 | unsigned long state, | 788 | unsigned long state, void *ptr) |
| 890 | void *ndev) | ||
| 891 | { | 789 | { |
| 892 | struct net_device *dev = ndev; | 790 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); |
| 893 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 791 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| 894 | struct cfg80211_registered_device *rdev; | 792 | struct cfg80211_registered_device *rdev; |
| 895 | int ret; | 793 | int ret; |
| @@ -912,13 +810,11 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
| 912 | * are added with nl80211. | 810 | * are added with nl80211. |
| 913 | */ | 811 | */ |
| 914 | mutex_init(&wdev->mtx); | 812 | mutex_init(&wdev->mtx); |
| 915 | INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work); | ||
| 916 | INIT_LIST_HEAD(&wdev->event_list); | 813 | INIT_LIST_HEAD(&wdev->event_list); |
| 917 | spin_lock_init(&wdev->event_lock); | 814 | spin_lock_init(&wdev->event_lock); |
| 918 | INIT_LIST_HEAD(&wdev->mgmt_registrations); | 815 | INIT_LIST_HEAD(&wdev->mgmt_registrations); |
| 919 | spin_lock_init(&wdev->mgmt_registrations_lock); | 816 | spin_lock_init(&wdev->mgmt_registrations_lock); |
| 920 | 817 | ||
| 921 | mutex_lock(&rdev->devlist_mtx); | ||
| 922 | wdev->identifier = ++rdev->wdev_id; | 818 | wdev->identifier = ++rdev->wdev_id; |
| 923 | list_add_rcu(&wdev->list, &rdev->wdev_list); | 819 | list_add_rcu(&wdev->list, &rdev->wdev_list); |
| 924 | rdev->devlist_generation++; | 820 | rdev->devlist_generation++; |
| @@ -930,8 +826,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
| 930 | pr_err("failed to add phy80211 symlink to netdev!\n"); | 826 | pr_err("failed to add phy80211 symlink to netdev!\n"); |
| 931 | } | 827 | } |
| 932 | wdev->netdev = dev; | 828 | wdev->netdev = dev; |
| 933 | wdev->sme_state = CFG80211_SME_IDLE; | ||
| 934 | mutex_unlock(&rdev->devlist_mtx); | ||
| 935 | #ifdef CONFIG_CFG80211_WEXT | 829 | #ifdef CONFIG_CFG80211_WEXT |
| 936 | wdev->wext.default_key = -1; | 830 | wdev->wext.default_key = -1; |
| 937 | wdev->wext.default_mgmt_key = -1; | 831 | wdev->wext.default_mgmt_key = -1; |
| @@ -957,26 +851,22 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
| 957 | break; | 851 | break; |
| 958 | case NETDEV_DOWN: | 852 | case NETDEV_DOWN: |
| 959 | cfg80211_update_iface_num(rdev, wdev->iftype, -1); | 853 | cfg80211_update_iface_num(rdev, wdev->iftype, -1); |
| 960 | dev_hold(dev); | 854 | if (rdev->scan_req && rdev->scan_req->wdev == wdev) { |
| 961 | queue_work(cfg80211_wq, &wdev->cleanup_work); | 855 | if (WARN_ON(!rdev->scan_req->notified)) |
| 856 | rdev->scan_req->aborted = true; | ||
| 857 | ___cfg80211_scan_done(rdev, true); | ||
| 858 | } | ||
| 859 | |||
| 860 | if (WARN_ON(rdev->sched_scan_req && | ||
| 861 | rdev->sched_scan_req->dev == wdev->netdev)) { | ||
| 862 | __cfg80211_stop_sched_scan(rdev, false); | ||
| 863 | } | ||
| 864 | |||
| 865 | rdev->opencount--; | ||
| 866 | wake_up(&rdev->dev_wait); | ||
| 962 | break; | 867 | break; |
| 963 | case NETDEV_UP: | 868 | case NETDEV_UP: |
| 964 | /* | ||
| 965 | * If we have a really quick DOWN/UP succession we may | ||
| 966 | * have this work still pending ... cancel it and see | ||
| 967 | * if it was pending, in which case we need to account | ||
| 968 | * for some of the work it would have done. | ||
| 969 | */ | ||
| 970 | if (cancel_work_sync(&wdev->cleanup_work)) { | ||
| 971 | mutex_lock(&rdev->devlist_mtx); | ||
| 972 | rdev->opencount--; | ||
| 973 | mutex_unlock(&rdev->devlist_mtx); | ||
| 974 | dev_put(dev); | ||
| 975 | } | ||
| 976 | cfg80211_update_iface_num(rdev, wdev->iftype, 1); | 869 | cfg80211_update_iface_num(rdev, wdev->iftype, 1); |
| 977 | cfg80211_lock_rdev(rdev); | ||
| 978 | mutex_lock(&rdev->devlist_mtx); | ||
| 979 | mutex_lock(&rdev->sched_scan_mtx); | ||
| 980 | wdev_lock(wdev); | 870 | wdev_lock(wdev); |
| 981 | switch (wdev->iftype) { | 871 | switch (wdev->iftype) { |
| 982 | #ifdef CONFIG_CFG80211_WEXT | 872 | #ifdef CONFIG_CFG80211_WEXT |
| @@ -1008,10 +898,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
| 1008 | break; | 898 | break; |
| 1009 | } | 899 | } |
| 1010 | wdev_unlock(wdev); | 900 | wdev_unlock(wdev); |
| 1011 | mutex_unlock(&rdev->sched_scan_mtx); | ||
| 1012 | rdev->opencount++; | 901 | rdev->opencount++; |
| 1013 | mutex_unlock(&rdev->devlist_mtx); | ||
| 1014 | cfg80211_unlock_rdev(rdev); | ||
| 1015 | 902 | ||
| 1016 | /* | 903 | /* |
| 1017 | * Configure power management to the driver here so that its | 904 | * Configure power management to the driver here so that its |
| @@ -1028,12 +915,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
| 1028 | break; | 915 | break; |
| 1029 | case NETDEV_UNREGISTER: | 916 | case NETDEV_UNREGISTER: |
| 1030 | /* | 917 | /* |
| 1031 | * NB: cannot take rdev->mtx here because this may be | ||
| 1032 | * called within code protected by it when interfaces | ||
| 1033 | * are removed with nl80211. | ||
| 1034 | */ | ||
| 1035 | mutex_lock(&rdev->devlist_mtx); | ||
| 1036 | /* | ||
| 1037 | * It is possible to get NETDEV_UNREGISTER | 918 | * It is possible to get NETDEV_UNREGISTER |
| 1038 | * multiple times. To detect that, check | 919 | * multiple times. To detect that, check |
| 1039 | * that the interface is still on the list | 920 | * that the interface is still on the list |
| @@ -1049,7 +930,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
| 1049 | kfree(wdev->wext.keys); | 930 | kfree(wdev->wext.keys); |
| 1050 | #endif | 931 | #endif |
| 1051 | } | 932 | } |
| 1052 | mutex_unlock(&rdev->devlist_mtx); | ||
| 1053 | /* | 933 | /* |
| 1054 | * synchronise (so that we won't find this netdev | 934 | * synchronise (so that we won't find this netdev |
| 1055 | * from other code any more) and then clear the list | 935 | * from other code any more) and then clear the list |
| @@ -1063,15 +943,19 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
| 1063 | * freed. | 943 | * freed. |
| 1064 | */ | 944 | */ |
| 1065 | cfg80211_process_wdev_events(wdev); | 945 | cfg80211_process_wdev_events(wdev); |
| 946 | |||
| 947 | if (WARN_ON(wdev->current_bss)) { | ||
| 948 | cfg80211_unhold_bss(wdev->current_bss); | ||
| 949 | cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); | ||
| 950 | wdev->current_bss = NULL; | ||
| 951 | } | ||
| 1066 | break; | 952 | break; |
| 1067 | case NETDEV_PRE_UP: | 953 | case NETDEV_PRE_UP: |
| 1068 | if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) | 954 | if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) |
| 1069 | return notifier_from_errno(-EOPNOTSUPP); | 955 | return notifier_from_errno(-EOPNOTSUPP); |
| 1070 | if (rfkill_blocked(rdev->rfkill)) | 956 | if (rfkill_blocked(rdev->rfkill)) |
| 1071 | return notifier_from_errno(-ERFKILL); | 957 | return notifier_from_errno(-ERFKILL); |
| 1072 | mutex_lock(&rdev->devlist_mtx); | ||
| 1073 | ret = cfg80211_can_add_interface(rdev, wdev->iftype); | 958 | ret = cfg80211_can_add_interface(rdev, wdev->iftype); |
| 1074 | mutex_unlock(&rdev->devlist_mtx); | ||
| 1075 | if (ret) | 959 | if (ret) |
| 1076 | return notifier_from_errno(ret); | 960 | return notifier_from_errno(ret); |
| 1077 | break; | 961 | break; |
| @@ -1089,12 +973,10 @@ static void __net_exit cfg80211_pernet_exit(struct net *net) | |||
| 1089 | struct cfg80211_registered_device *rdev; | 973 | struct cfg80211_registered_device *rdev; |
| 1090 | 974 | ||
| 1091 | rtnl_lock(); | 975 | rtnl_lock(); |
| 1092 | mutex_lock(&cfg80211_mutex); | ||
| 1093 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | 976 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
| 1094 | if (net_eq(wiphy_net(&rdev->wiphy), net)) | 977 | if (net_eq(wiphy_net(&rdev->wiphy), net)) |
| 1095 | WARN_ON(cfg80211_switch_netns(rdev, &init_net)); | 978 | WARN_ON(cfg80211_switch_netns(rdev, &init_net)); |
| 1096 | } | 979 | } |
| 1097 | mutex_unlock(&cfg80211_mutex); | ||
| 1098 | rtnl_unlock(); | 980 | rtnl_unlock(); |
| 1099 | } | 981 | } |
| 1100 | 982 | ||
