diff options
Diffstat (limited to 'net/wireless/core.c')
-rw-r--r-- | net/wireless/core.c | 134 |
1 files changed, 57 insertions, 77 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c index a87d43552974..31b40cc4a9c3 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -96,69 +96,6 @@ struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx) | |||
96 | return &rdev->wiphy; | 96 | return &rdev->wiphy; |
97 | } | 97 | } |
98 | 98 | ||
99 | /* requires cfg80211_mutex to be held! */ | ||
100 | struct cfg80211_registered_device * | ||
101 | __cfg80211_rdev_from_info(struct genl_info *info) | ||
102 | { | ||
103 | int ifindex; | ||
104 | struct cfg80211_registered_device *bywiphyidx = NULL, *byifidx = NULL; | ||
105 | struct net_device *dev; | ||
106 | int err = -EINVAL; | ||
107 | |||
108 | assert_cfg80211_lock(); | ||
109 | |||
110 | if (info->attrs[NL80211_ATTR_WIPHY]) { | ||
111 | bywiphyidx = cfg80211_rdev_by_wiphy_idx( | ||
112 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY])); | ||
113 | err = -ENODEV; | ||
114 | } | ||
115 | |||
116 | if (info->attrs[NL80211_ATTR_IFINDEX]) { | ||
117 | ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]); | ||
118 | dev = dev_get_by_index(genl_info_net(info), ifindex); | ||
119 | if (dev) { | ||
120 | if (dev->ieee80211_ptr) | ||
121 | byifidx = | ||
122 | wiphy_to_dev(dev->ieee80211_ptr->wiphy); | ||
123 | dev_put(dev); | ||
124 | } | ||
125 | err = -ENODEV; | ||
126 | } | ||
127 | |||
128 | if (bywiphyidx && byifidx) { | ||
129 | if (bywiphyidx != byifidx) | ||
130 | return ERR_PTR(-EINVAL); | ||
131 | else | ||
132 | return bywiphyidx; /* == byifidx */ | ||
133 | } | ||
134 | if (bywiphyidx) | ||
135 | return bywiphyidx; | ||
136 | |||
137 | if (byifidx) | ||
138 | return byifidx; | ||
139 | |||
140 | return ERR_PTR(err); | ||
141 | } | ||
142 | |||
143 | struct cfg80211_registered_device * | ||
144 | cfg80211_get_dev_from_info(struct genl_info *info) | ||
145 | { | ||
146 | struct cfg80211_registered_device *rdev; | ||
147 | |||
148 | mutex_lock(&cfg80211_mutex); | ||
149 | rdev = __cfg80211_rdev_from_info(info); | ||
150 | |||
151 | /* if it is not an error we grab the lock on | ||
152 | * it to assure it won't be going away while | ||
153 | * we operate on it */ | ||
154 | if (!IS_ERR(rdev)) | ||
155 | mutex_lock(&rdev->mtx); | ||
156 | |||
157 | mutex_unlock(&cfg80211_mutex); | ||
158 | |||
159 | return rdev; | ||
160 | } | ||
161 | |||
162 | struct cfg80211_registered_device * | 99 | struct cfg80211_registered_device * |
163 | cfg80211_get_dev_from_ifindex(struct net *net, int ifindex) | 100 | cfg80211_get_dev_from_ifindex(struct net *net, int ifindex) |
164 | { | 101 | { |
@@ -239,7 +176,9 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, | |||
239 | if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK)) | 176 | if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK)) |
240 | return -EOPNOTSUPP; | 177 | return -EOPNOTSUPP; |
241 | 178 | ||
242 | list_for_each_entry(wdev, &rdev->netdev_list, list) { | 179 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
180 | if (!wdev->netdev) | ||
181 | continue; | ||
243 | wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL; | 182 | wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL; |
244 | err = dev_change_net_namespace(wdev->netdev, net, "wlan%d"); | 183 | err = dev_change_net_namespace(wdev->netdev, net, "wlan%d"); |
245 | if (err) | 184 | if (err) |
@@ -251,8 +190,10 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, | |||
251 | /* failed -- clean up to old netns */ | 190 | /* failed -- clean up to old netns */ |
252 | net = wiphy_net(&rdev->wiphy); | 191 | net = wiphy_net(&rdev->wiphy); |
253 | 192 | ||
254 | list_for_each_entry_continue_reverse(wdev, &rdev->netdev_list, | 193 | list_for_each_entry_continue_reverse(wdev, &rdev->wdev_list, |
255 | list) { | 194 | list) { |
195 | if (!wdev->netdev) | ||
196 | continue; | ||
256 | wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL; | 197 | wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL; |
257 | err = dev_change_net_namespace(wdev->netdev, net, | 198 | err = dev_change_net_namespace(wdev->netdev, net, |
258 | "wlan%d"); | 199 | "wlan%d"); |
@@ -289,8 +230,9 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked) | |||
289 | rtnl_lock(); | 230 | rtnl_lock(); |
290 | mutex_lock(&rdev->devlist_mtx); | 231 | mutex_lock(&rdev->devlist_mtx); |
291 | 232 | ||
292 | list_for_each_entry(wdev, &rdev->netdev_list, list) | 233 | list_for_each_entry(wdev, &rdev->wdev_list, list) |
293 | dev_close(wdev->netdev); | 234 | if (wdev->netdev) |
235 | dev_close(wdev->netdev); | ||
294 | 236 | ||
295 | mutex_unlock(&rdev->devlist_mtx); | 237 | mutex_unlock(&rdev->devlist_mtx); |
296 | rtnl_unlock(); | 238 | rtnl_unlock(); |
@@ -367,7 +309,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
367 | mutex_init(&rdev->mtx); | 309 | mutex_init(&rdev->mtx); |
368 | mutex_init(&rdev->devlist_mtx); | 310 | mutex_init(&rdev->devlist_mtx); |
369 | mutex_init(&rdev->sched_scan_mtx); | 311 | mutex_init(&rdev->sched_scan_mtx); |
370 | INIT_LIST_HEAD(&rdev->netdev_list); | 312 | INIT_LIST_HEAD(&rdev->wdev_list); |
371 | spin_lock_init(&rdev->bss_lock); | 313 | spin_lock_init(&rdev->bss_lock); |
372 | INIT_LIST_HEAD(&rdev->bss_list); | 314 | INIT_LIST_HEAD(&rdev->bss_list); |
373 | INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); | 315 | INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); |
@@ -436,6 +378,14 @@ static int wiphy_verify_combinations(struct wiphy *wiphy) | |||
436 | if (WARN_ON(!c->num_different_channels)) | 378 | if (WARN_ON(!c->num_different_channels)) |
437 | return -EINVAL; | 379 | return -EINVAL; |
438 | 380 | ||
381 | /* | ||
382 | * Put a sane limit on maximum number of different | ||
383 | * channels to simplify channel accounting code. | ||
384 | */ | ||
385 | if (WARN_ON(c->num_different_channels > | ||
386 | CFG80211_MAX_NUM_DIFFERENT_CHANNELS)) | ||
387 | return -EINVAL; | ||
388 | |||
439 | if (WARN_ON(!c->n_limits)) | 389 | if (WARN_ON(!c->n_limits)) |
440 | return -EINVAL; | 390 | return -EINVAL; |
441 | 391 | ||
@@ -484,9 +434,11 @@ int wiphy_register(struct wiphy *wiphy) | |||
484 | int i; | 434 | int i; |
485 | u16 ifmodes = wiphy->interface_modes; | 435 | u16 ifmodes = wiphy->interface_modes; |
486 | 436 | ||
437 | #ifdef CONFIG_PM | ||
487 | if (WARN_ON((wiphy->wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) && | 438 | if (WARN_ON((wiphy->wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) && |
488 | !(wiphy->wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY))) | 439 | !(wiphy->wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY))) |
489 | return -EINVAL; | 440 | return -EINVAL; |
441 | #endif | ||
490 | 442 | ||
491 | if (WARN_ON(wiphy->ap_sme_capa && | 443 | if (WARN_ON(wiphy->ap_sme_capa && |
492 | !(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME))) | 444 | !(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME))) |
@@ -521,8 +473,14 @@ int wiphy_register(struct wiphy *wiphy) | |||
521 | continue; | 473 | continue; |
522 | 474 | ||
523 | sband->band = band; | 475 | sband->band = band; |
524 | 476 | if (WARN_ON(!sband->n_channels)) | |
525 | if (WARN_ON(!sband->n_channels || !sband->n_bitrates)) | 477 | return -EINVAL; |
478 | /* | ||
479 | * on 60gHz band, there are no legacy rates, so | ||
480 | * n_bitrates is 0 | ||
481 | */ | ||
482 | if (WARN_ON(band != IEEE80211_BAND_60GHZ && | ||
483 | !sband->n_bitrates)) | ||
526 | return -EINVAL; | 484 | return -EINVAL; |
527 | 485 | ||
528 | /* | 486 | /* |
@@ -563,12 +521,14 @@ int wiphy_register(struct wiphy *wiphy) | |||
563 | return -EINVAL; | 521 | return -EINVAL; |
564 | } | 522 | } |
565 | 523 | ||
524 | #ifdef CONFIG_PM | ||
566 | if (rdev->wiphy.wowlan.n_patterns) { | 525 | if (rdev->wiphy.wowlan.n_patterns) { |
567 | if (WARN_ON(!rdev->wiphy.wowlan.pattern_min_len || | 526 | if (WARN_ON(!rdev->wiphy.wowlan.pattern_min_len || |
568 | rdev->wiphy.wowlan.pattern_min_len > | 527 | rdev->wiphy.wowlan.pattern_min_len > |
569 | rdev->wiphy.wowlan.pattern_max_len)) | 528 | rdev->wiphy.wowlan.pattern_max_len)) |
570 | return -EINVAL; | 529 | return -EINVAL; |
571 | } | 530 | } |
531 | #endif | ||
572 | 532 | ||
573 | /* check and set up bitrates */ | 533 | /* check and set up bitrates */ |
574 | ieee80211_set_bitrate_flags(wiphy); | 534 | ieee80211_set_bitrate_flags(wiphy); |
@@ -582,7 +542,7 @@ int wiphy_register(struct wiphy *wiphy) | |||
582 | } | 542 | } |
583 | 543 | ||
584 | /* set up regulatory info */ | 544 | /* set up regulatory info */ |
585 | regulatory_update(wiphy, NL80211_REGDOM_SET_BY_CORE); | 545 | wiphy_regulatory_register(wiphy); |
586 | 546 | ||
587 | list_add_rcu(&rdev->list, &cfg80211_rdev_list); | 547 | list_add_rcu(&rdev->list, &cfg80211_rdev_list); |
588 | cfg80211_rdev_list_generation++; | 548 | cfg80211_rdev_list_generation++; |
@@ -667,7 +627,7 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
667 | __count == 0; })); | 627 | __count == 0; })); |
668 | 628 | ||
669 | mutex_lock(&rdev->devlist_mtx); | 629 | mutex_lock(&rdev->devlist_mtx); |
670 | BUG_ON(!list_empty(&rdev->netdev_list)); | 630 | BUG_ON(!list_empty(&rdev->wdev_list)); |
671 | mutex_unlock(&rdev->devlist_mtx); | 631 | mutex_unlock(&rdev->devlist_mtx); |
672 | 632 | ||
673 | /* | 633 | /* |
@@ -692,9 +652,11 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
692 | /* nothing */ | 652 | /* nothing */ |
693 | cfg80211_unlock_rdev(rdev); | 653 | cfg80211_unlock_rdev(rdev); |
694 | 654 | ||
695 | /* If this device got a regulatory hint tell core its | 655 | /* |
696 | * free to listen now to a new shiny device regulatory hint */ | 656 | * If this device got a regulatory hint tell core its |
697 | reg_device_remove(wiphy); | 657 | * free to listen now to a new shiny device regulatory hint |
658 | */ | ||
659 | wiphy_regulatory_deregister(wiphy); | ||
698 | 660 | ||
699 | cfg80211_rdev_list_generation++; | 661 | cfg80211_rdev_list_generation++; |
700 | device_del(&rdev->wiphy.dev); | 662 | device_del(&rdev->wiphy.dev); |
@@ -748,7 +710,7 @@ static void wdev_cleanup_work(struct work_struct *work) | |||
748 | 710 | ||
749 | cfg80211_lock_rdev(rdev); | 711 | cfg80211_lock_rdev(rdev); |
750 | 712 | ||
751 | if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == wdev->netdev)) { | 713 | if (WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev)) { |
752 | rdev->scan_req->aborted = true; | 714 | rdev->scan_req->aborted = true; |
753 | ___cfg80211_scan_done(rdev, true); | 715 | ___cfg80211_scan_done(rdev, true); |
754 | } | 716 | } |
@@ -776,6 +738,16 @@ static struct device_type wiphy_type = { | |||
776 | .name = "wlan", | 738 | .name = "wlan", |
777 | }; | 739 | }; |
778 | 740 | ||
741 | void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, | ||
742 | enum nl80211_iftype iftype, int num) | ||
743 | { | ||
744 | ASSERT_RTNL(); | ||
745 | |||
746 | rdev->num_running_ifaces += num; | ||
747 | if (iftype == NL80211_IFTYPE_MONITOR) | ||
748 | rdev->num_running_monitor_ifaces += num; | ||
749 | } | ||
750 | |||
779 | static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | 751 | static int cfg80211_netdev_notifier_call(struct notifier_block *nb, |
780 | unsigned long state, | 752 | unsigned long state, |
781 | void *ndev) | 753 | void *ndev) |
@@ -810,7 +782,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
810 | spin_lock_init(&wdev->mgmt_registrations_lock); | 782 | spin_lock_init(&wdev->mgmt_registrations_lock); |
811 | 783 | ||
812 | mutex_lock(&rdev->devlist_mtx); | 784 | mutex_lock(&rdev->devlist_mtx); |
813 | list_add_rcu(&wdev->list, &rdev->netdev_list); | 785 | wdev->identifier = ++rdev->wdev_id; |
786 | list_add_rcu(&wdev->list, &rdev->wdev_list); | ||
814 | rdev->devlist_generation++; | 787 | rdev->devlist_generation++; |
815 | /* can only change netns with wiphy */ | 788 | /* can only change netns with wiphy */ |
816 | dev->features |= NETIF_F_NETNS_LOCAL; | 789 | dev->features |= NETIF_F_NETNS_LOCAL; |
@@ -869,12 +842,16 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
869 | case NL80211_IFTYPE_MESH_POINT: | 842 | case NL80211_IFTYPE_MESH_POINT: |
870 | cfg80211_leave_mesh(rdev, dev); | 843 | cfg80211_leave_mesh(rdev, dev); |
871 | break; | 844 | break; |
845 | case NL80211_IFTYPE_AP: | ||
846 | cfg80211_stop_ap(rdev, dev); | ||
847 | break; | ||
872 | default: | 848 | default: |
873 | break; | 849 | break; |
874 | } | 850 | } |
875 | wdev->beacon_interval = 0; | 851 | wdev->beacon_interval = 0; |
876 | break; | 852 | break; |
877 | case NETDEV_DOWN: | 853 | case NETDEV_DOWN: |
854 | cfg80211_update_iface_num(rdev, wdev->iftype, -1); | ||
878 | dev_hold(dev); | 855 | dev_hold(dev); |
879 | queue_work(cfg80211_wq, &wdev->cleanup_work); | 856 | queue_work(cfg80211_wq, &wdev->cleanup_work); |
880 | break; | 857 | break; |
@@ -891,6 +868,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
891 | mutex_unlock(&rdev->devlist_mtx); | 868 | mutex_unlock(&rdev->devlist_mtx); |
892 | dev_put(dev); | 869 | dev_put(dev); |
893 | } | 870 | } |
871 | cfg80211_update_iface_num(rdev, wdev->iftype, 1); | ||
894 | cfg80211_lock_rdev(rdev); | 872 | cfg80211_lock_rdev(rdev); |
895 | mutex_lock(&rdev->devlist_mtx); | 873 | mutex_lock(&rdev->devlist_mtx); |
896 | wdev_lock(wdev); | 874 | wdev_lock(wdev); |
@@ -980,7 +958,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
980 | return notifier_from_errno(-EOPNOTSUPP); | 958 | return notifier_from_errno(-EOPNOTSUPP); |
981 | if (rfkill_blocked(rdev->rfkill)) | 959 | if (rfkill_blocked(rdev->rfkill)) |
982 | return notifier_from_errno(-ERFKILL); | 960 | return notifier_from_errno(-ERFKILL); |
961 | mutex_lock(&rdev->devlist_mtx); | ||
983 | ret = cfg80211_can_add_interface(rdev, wdev->iftype); | 962 | ret = cfg80211_can_add_interface(rdev, wdev->iftype); |
963 | mutex_unlock(&rdev->devlist_mtx); | ||
984 | if (ret) | 964 | if (ret) |
985 | return notifier_from_errno(ret); | 965 | return notifier_from_errno(ret); |
986 | break; | 966 | break; |