Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[cascardo/linux.git] / net / wireless / core.c
index 73405e0..f277246 100644 (file)
 MODULE_AUTHOR("Johannes Berg");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("wireless configuration support");
+MODULE_ALIAS_GENL_FAMILY(NL80211_GENL_NAME);
 
-/* RCU-protected (and cfg80211_mutex for writers) */
+/* RCU-protected (and RTNL for writers) */
 LIST_HEAD(cfg80211_rdev_list);
 int cfg80211_rdev_list_generation;
 
-DEFINE_MUTEX(cfg80211_mutex);
-
 /* for debugfs */
 static struct dentry *ieee80211_debugfs_dir;
 
@@ -52,12 +51,11 @@ module_param(cfg80211_disable_40mhz_24ghz, bool, 0644);
 MODULE_PARM_DESC(cfg80211_disable_40mhz_24ghz,
                 "Disable 40MHz support in the 2.4GHz band");
 
-/* requires cfg80211_mutex to be held! */
 struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx)
 {
        struct cfg80211_registered_device *result = NULL, *rdev;
 
-       assert_cfg80211_lock();
+       ASSERT_RTNL();
 
        list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
                if (rdev->wiphy_idx == wiphy_idx) {
@@ -76,12 +74,11 @@ int get_wiphy_idx(struct wiphy *wiphy)
        return rdev->wiphy_idx;
 }
 
-/* requires cfg80211_rdev_mutex to be held! */
 struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx)
 {
        struct cfg80211_registered_device *rdev;
 
-       assert_cfg80211_lock();
+       ASSERT_RTNL();
 
        rdev = cfg80211_rdev_by_wiphy_idx(wiphy_idx);
        if (!rdev)
@@ -89,35 +86,13 @@ struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx)
        return &rdev->wiphy;
 }
 
-struct cfg80211_registered_device *
-cfg80211_get_dev_from_ifindex(struct net *net, int ifindex)
-{
-       struct cfg80211_registered_device *rdev = ERR_PTR(-ENODEV);
-       struct net_device *dev;
-
-       mutex_lock(&cfg80211_mutex);
-       dev = dev_get_by_index(net, ifindex);
-       if (!dev)
-               goto out;
-       if (dev->ieee80211_ptr) {
-               rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy);
-               mutex_lock(&rdev->mtx);
-       } else
-               rdev = ERR_PTR(-ENODEV);
-       dev_put(dev);
- out:
-       mutex_unlock(&cfg80211_mutex);
-       return rdev;
-}
-
-/* requires cfg80211_mutex to be held */
 int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
                        char *newname)
 {
        struct cfg80211_registered_device *rdev2;
        int wiphy_idx, taken = -1, result, digits;
 
-       assert_cfg80211_lock();
+       ASSERT_RTNL();
 
        /* prohibit calling the thing phy%d when %d is not its number */
        sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken);
@@ -215,8 +190,7 @@ static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data)
 void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
                              struct wireless_dev *wdev)
 {
-       lockdep_assert_held(&rdev->devlist_mtx);
-       lockdep_assert_held(&rdev->sched_scan_mtx);
+       ASSERT_RTNL();
 
        if (WARN_ON(wdev->iftype != NL80211_IFTYPE_P2P_DEVICE))
                return;
@@ -230,18 +204,15 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
        rdev->opencount--;
 
        if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
-               bool busy = work_busy(&rdev->scan_done_wk);
-
                /*
-                * If the work isn't pending or running (in which case it would
-                * be waiting for the lock we hold) the driver didn't properly
-                * cancel the scan when the interface was removed. In this case
-                * warn and leak the scan request object to not crash later.
+                * If the scan request wasn't notified as done, set it
+                * to aborted and leak it after a warning. The driver
+                * should have notified us that it ended at the latest
+                * during rdev_stop_p2p_device().
                 */
-               WARN_ON(!busy);
-
-               rdev->scan_req->aborted = true;
-               ___cfg80211_scan_done(rdev, !busy);
+               if (WARN_ON(!rdev->scan_req->notified))
+                       rdev->scan_req->aborted = true;
+               ___cfg80211_scan_done(rdev, !rdev->scan_req->notified);
        }
 }
 
@@ -255,8 +226,6 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked)
 
        rtnl_lock();
 
-       /* read-only iteration need not hold the devlist_mtx */
-
        list_for_each_entry(wdev, &rdev->wdev_list, list) {
                if (wdev->netdev) {
                        dev_close(wdev->netdev);
@@ -265,12 +234,7 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked)
                /* otherwise, check iftype */
                switch (wdev->iftype) {
                case NL80211_IFTYPE_P2P_DEVICE:
-                       /* but this requires it */
-                       mutex_lock(&rdev->devlist_mtx);
-                       mutex_lock(&rdev->sched_scan_mtx);
                        cfg80211_stop_p2p_device(rdev, wdev);
-                       mutex_unlock(&rdev->sched_scan_mtx);
-                       mutex_unlock(&rdev->devlist_mtx);
                        break;
                default:
                        break;
@@ -298,10 +262,7 @@ static void cfg80211_event_work(struct work_struct *work)
                            event_work);
 
        rtnl_lock();
-       cfg80211_lock_rdev(rdev);
-
        cfg80211_process_rdev_events(rdev);
-       cfg80211_unlock_rdev(rdev);
        rtnl_unlock();
 }
 
@@ -309,7 +270,7 @@ static void cfg80211_event_work(struct work_struct *work)
 
 struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
 {
-       static int wiphy_counter;
+       static atomic_t wiphy_counter = ATOMIC_INIT(0);
 
        struct cfg80211_registered_device *rdev;
        int alloc_size;
@@ -331,26 +292,21 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
 
        rdev->ops = ops;
 
-       mutex_lock(&cfg80211_mutex);
-
-       rdev->wiphy_idx = wiphy_counter++;
+       rdev->wiphy_idx = atomic_inc_return(&wiphy_counter);
 
        if (unlikely(rdev->wiphy_idx < 0)) {
-               wiphy_counter--;
-               mutex_unlock(&cfg80211_mutex);
                /* ugh, wrapped! */
+               atomic_dec(&wiphy_counter);
                kfree(rdev);
                return NULL;
        }
 
-       mutex_unlock(&cfg80211_mutex);
+       /* atomic_inc_return makes it start at 1, make it start at 0 */
+       rdev->wiphy_idx--;
 
        /* give it a proper name */
        dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx);
 
-       mutex_init(&rdev->mtx);
-       mutex_init(&rdev->devlist_mtx);
-       mutex_init(&rdev->sched_scan_mtx);
        INIT_LIST_HEAD(&rdev->wdev_list);
        INIT_LIST_HEAD(&rdev->beacon_registrations);
        spin_lock_init(&rdev->beacon_registrations_lock);
@@ -496,8 +452,13 @@ int wiphy_register(struct wiphy *wiphy)
        u16 ifmodes = wiphy->interface_modes;
 
 #ifdef CONFIG_PM
-       if (WARN_ON((wiphy->wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
-                   !(wiphy->wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY)))
+       if (WARN_ON(wiphy->wowlan &&
+                   (wiphy->wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
+                   !(wiphy->wowlan->flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY)))
+               return -EINVAL;
+       if (WARN_ON(wiphy->wowlan &&
+                   !wiphy->wowlan->flags && !wiphy->wowlan->n_patterns &&
+                   !wiphy->wowlan->tcp))
                return -EINVAL;
 #endif
 
@@ -587,25 +548,28 @@ int wiphy_register(struct wiphy *wiphy)
        }
 
 #ifdef CONFIG_PM
-       if (rdev->wiphy.wowlan.n_patterns) {
-               if (WARN_ON(!rdev->wiphy.wowlan.pattern_min_len ||
-                           rdev->wiphy.wowlan.pattern_min_len >
-                           rdev->wiphy.wowlan.pattern_max_len))
-                       return -EINVAL;
-       }
+       if (WARN_ON(rdev->wiphy.wowlan && rdev->wiphy.wowlan->n_patterns &&
+                   (!rdev->wiphy.wowlan->pattern_min_len ||
+                    rdev->wiphy.wowlan->pattern_min_len >
+                               rdev->wiphy.wowlan->pattern_max_len)))
+               return -EINVAL;
 #endif
 
        /* check and set up bitrates */
        ieee80211_set_bitrate_flags(wiphy);
 
-       mutex_lock(&cfg80211_mutex);
 
        res = device_add(&rdev->wiphy.dev);
+       if (res)
+               return res;
+
+       res = rfkill_register(rdev->rfkill);
        if (res) {
-               mutex_unlock(&cfg80211_mutex);
+               device_del(&rdev->wiphy.dev);
                return res;
        }
 
+       rtnl_lock();
        /* set up regulatory info */
        wiphy_regulatory_register(wiphy);
 
@@ -631,25 +595,7 @@ int wiphy_register(struct wiphy *wiphy)
        }
 
        cfg80211_debugfs_rdev_add(rdev);
-       mutex_unlock(&cfg80211_mutex);
-
-       /*
-        * due to a locking dependency this has to be outside of the
-        * cfg80211_mutex lock
-        */
-       res = rfkill_register(rdev->rfkill);
-       if (res) {
-               device_del(&rdev->wiphy.dev);
-
-               mutex_lock(&cfg80211_mutex);
-               debugfs_remove_recursive(rdev->wiphy.debugfsdir);
-               list_del_rcu(&rdev->list);
-               wiphy_regulatory_deregister(wiphy);
-               mutex_unlock(&cfg80211_mutex);
-               return res;
-       }
 
-       rtnl_lock();
        rdev->wiphy.registered = true;
        rtnl_unlock();
        return 0;
@@ -679,25 +625,19 @@ void wiphy_unregister(struct wiphy *wiphy)
 {
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 
-       rtnl_lock();
-       rdev->wiphy.registered = false;
-       rtnl_unlock();
-
-       rfkill_unregister(rdev->rfkill);
-
-       /* protect the device list */
-       mutex_lock(&cfg80211_mutex);
-
        wait_event(rdev->dev_wait, ({
                int __count;
-               mutex_lock(&rdev->devlist_mtx);
+               rtnl_lock();
                __count = rdev->opencount;
-               mutex_unlock(&rdev->devlist_mtx);
+               rtnl_unlock();
                __count == 0; }));
 
-       mutex_lock(&rdev->devlist_mtx);
+       rfkill_unregister(rdev->rfkill);
+
+       rtnl_lock();
+       rdev->wiphy.registered = false;
+
        BUG_ON(!list_empty(&rdev->wdev_list));
-       mutex_unlock(&rdev->devlist_mtx);
 
        /*
         * First remove the hardware from everywhere, this makes
@@ -707,20 +647,6 @@ void wiphy_unregister(struct wiphy *wiphy)
        list_del_rcu(&rdev->list);
        synchronize_rcu();
 
-       /*
-        * Try to grab rdev->mtx. If a command is still in progress,
-        * hopefully the driver will refuse it since it's tearing
-        * down the device already. We wait for this command to complete
-        * before unlinking the item from the list.
-        * Note: as codified by the BUG_ON above we cannot get here if
-        * a virtual interface is still present. Hence, we can only get
-        * to lock contention here if userspace issues a command that
-        * identified the hardware by wiphy index.
-        */
-       cfg80211_lock_rdev(rdev);
-       /* nothing */
-       cfg80211_unlock_rdev(rdev);
-
        /*
         * If this device got a regulatory hint tell core its
         * free to listen now to a new shiny device regulatory hint
@@ -730,15 +656,17 @@ void wiphy_unregister(struct wiphy *wiphy)
        cfg80211_rdev_list_generation++;
        device_del(&rdev->wiphy.dev);
 
-       mutex_unlock(&cfg80211_mutex);
+       rtnl_unlock();
 
        flush_work(&rdev->scan_done_wk);
        cancel_work_sync(&rdev->conn_work);
        flush_work(&rdev->event_work);
        cancel_delayed_work_sync(&rdev->dfs_update_channels_wk);
 
-       if (rdev->wowlan && rdev->ops->set_wakeup)
+#ifdef CONFIG_PM
+       if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup)
                rdev_set_wakeup(rdev, false);
+#endif
        cfg80211_rdev_free_wowlan(rdev);
 }
 EXPORT_SYMBOL(wiphy_unregister);
@@ -748,9 +676,6 @@ void cfg80211_dev_free(struct cfg80211_registered_device *rdev)
        struct cfg80211_internal_bss *scan, *tmp;
        struct cfg80211_beacon_registration *reg, *treg;
        rfkill_destroy(rdev->rfkill);
-       mutex_destroy(&rdev->mtx);
-       mutex_destroy(&rdev->devlist_mtx);
-       mutex_destroy(&rdev->sched_scan_mtx);
        list_for_each_entry_safe(reg, treg, &rdev->beacon_registrations, list) {
                list_del(&reg->list);
                kfree(reg);
@@ -775,36 +700,6 @@ void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked)
 }
 EXPORT_SYMBOL(wiphy_rfkill_set_hw_state);
 
-static void wdev_cleanup_work(struct work_struct *work)
-{
-       struct wireless_dev *wdev;
-       struct cfg80211_registered_device *rdev;
-
-       wdev = container_of(work, struct wireless_dev, cleanup_work);
-       rdev = wiphy_to_dev(wdev->wiphy);
-
-       mutex_lock(&rdev->sched_scan_mtx);
-
-       if (WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev)) {
-               rdev->scan_req->aborted = true;
-               ___cfg80211_scan_done(rdev, true);
-       }
-
-       if (WARN_ON(rdev->sched_scan_req &&
-                   rdev->sched_scan_req->dev == wdev->netdev)) {
-               __cfg80211_stop_sched_scan(rdev, false);
-       }
-
-       mutex_unlock(&rdev->sched_scan_mtx);
-
-       mutex_lock(&rdev->devlist_mtx);
-       rdev->opencount--;
-       mutex_unlock(&rdev->devlist_mtx);
-       wake_up(&rdev->dev_wait);
-
-       dev_put(wdev->netdev);
-}
-
 void cfg80211_unregister_wdev(struct wireless_dev *wdev)
 {
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
@@ -814,8 +709,6 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev)
        if (WARN_ON(wdev->netdev))
                return;
 
-       mutex_lock(&rdev->devlist_mtx);
-       mutex_lock(&rdev->sched_scan_mtx);
        list_del_rcu(&wdev->list);
        rdev->devlist_generation++;
 
@@ -827,8 +720,6 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev)
                WARN_ON_ONCE(1);
                break;
        }
-       mutex_unlock(&rdev->sched_scan_mtx);
-       mutex_unlock(&rdev->devlist_mtx);
 }
 EXPORT_SYMBOL(cfg80211_unregister_wdev);
 
@@ -847,7 +738,7 @@ void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
 }
 
 void cfg80211_leave(struct cfg80211_registered_device *rdev,
-                  struct wireless_dev *wdev)
+                   struct wireless_dev *wdev)
 {
        struct net_device *dev = wdev->netdev;
 
@@ -857,9 +748,7 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev,
                break;
        case NL80211_IFTYPE_P2P_CLIENT:
        case NL80211_IFTYPE_STATION:
-               mutex_lock(&rdev->sched_scan_mtx);
                __cfg80211_stop_sched_scan(rdev, false);
-               mutex_unlock(&rdev->sched_scan_mtx);
 
                wdev_lock(wdev);
 #ifdef CONFIG_CFG80211_WEXT
@@ -868,8 +757,8 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev,
                wdev->wext.ie_len = 0;
                wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
 #endif
-               __cfg80211_disconnect(rdev, dev,
-                                     WLAN_REASON_DEAUTH_LEAVING, true);
+               cfg80211_disconnect(rdev, dev,
+                                   WLAN_REASON_DEAUTH_LEAVING, true);
                wdev_unlock(wdev);
                break;
        case NL80211_IFTYPE_MESH_POINT:
@@ -886,10 +775,9 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev,
 }
 
 static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
-                                        unsigned long state,
-                                        void *ndev)
+                                        unsigned long state, void *ptr)
 {
-       struct net_device *dev = ndev;
+       struct net_device *dev = netdev_notifier_info_to_dev(ptr);
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_registered_device *rdev;
        int ret;
@@ -912,13 +800,11 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
                 * are added with nl80211.
                 */
                mutex_init(&wdev->mtx);
-               INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work);
                INIT_LIST_HEAD(&wdev->event_list);
                spin_lock_init(&wdev->event_lock);
                INIT_LIST_HEAD(&wdev->mgmt_registrations);
                spin_lock_init(&wdev->mgmt_registrations_lock);
 
-               mutex_lock(&rdev->devlist_mtx);
                wdev->identifier = ++rdev->wdev_id;
                list_add_rcu(&wdev->list, &rdev->wdev_list);
                rdev->devlist_generation++;
@@ -930,8 +816,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
                        pr_err("failed to add phy80211 symlink to netdev!\n");
                }
                wdev->netdev = dev;
-               wdev->sme_state = CFG80211_SME_IDLE;
-               mutex_unlock(&rdev->devlist_mtx);
 #ifdef CONFIG_CFG80211_WEXT
                wdev->wext.default_key = -1;
                wdev->wext.default_mgmt_key = -1;
@@ -957,26 +841,22 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
                break;
        case NETDEV_DOWN:
                cfg80211_update_iface_num(rdev, wdev->iftype, -1);
-               dev_hold(dev);
-               queue_work(cfg80211_wq, &wdev->cleanup_work);
+               if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
+                       if (WARN_ON(!rdev->scan_req->notified))
+                               rdev->scan_req->aborted = true;
+                       ___cfg80211_scan_done(rdev, true);
+               }
+
+               if (WARN_ON(rdev->sched_scan_req &&
+                           rdev->sched_scan_req->dev == wdev->netdev)) {
+                       __cfg80211_stop_sched_scan(rdev, false);
+               }
+
+               rdev->opencount--;
+               wake_up(&rdev->dev_wait);
                break;
        case NETDEV_UP:
-               /*
-                * If we have a really quick DOWN/UP succession we may
-                * have this work still pending ... cancel it and see
-                * if it was pending, in which case we need to account
-                * for some of the work it would have done.
-                */
-               if (cancel_work_sync(&wdev->cleanup_work)) {
-                       mutex_lock(&rdev->devlist_mtx);
-                       rdev->opencount--;
-                       mutex_unlock(&rdev->devlist_mtx);
-                       dev_put(dev);
-               }
                cfg80211_update_iface_num(rdev, wdev->iftype, 1);
-               cfg80211_lock_rdev(rdev);
-               mutex_lock(&rdev->devlist_mtx);
-               mutex_lock(&rdev->sched_scan_mtx);
                wdev_lock(wdev);
                switch (wdev->iftype) {
 #ifdef CONFIG_CFG80211_WEXT
@@ -1008,10 +888,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
                        break;
                }
                wdev_unlock(wdev);
-               mutex_unlock(&rdev->sched_scan_mtx);
                rdev->opencount++;
-               mutex_unlock(&rdev->devlist_mtx);
-               cfg80211_unlock_rdev(rdev);
 
                /*
                 * Configure power management to the driver here so that its
@@ -1027,12 +904,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
                        }
                break;
        case NETDEV_UNREGISTER:
-               /*
-                * NB: cannot take rdev->mtx here because this may be
-                * called within code protected by it when interfaces
-                * are removed with nl80211.
-                */
-               mutex_lock(&rdev->devlist_mtx);
                /*
                 * It is possible to get NETDEV_UNREGISTER
                 * multiple times. To detect that, check
@@ -1049,7 +920,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
                        kfree(wdev->wext.keys);
 #endif
                }
-               mutex_unlock(&rdev->devlist_mtx);
                /*
                 * synchronise (so that we won't find this netdev
                 * from other code any more) and then clear the list
@@ -1069,9 +939,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
                        return notifier_from_errno(-EOPNOTSUPP);
                if (rfkill_blocked(rdev->rfkill))
                        return notifier_from_errno(-ERFKILL);
-               mutex_lock(&rdev->devlist_mtx);
                ret = cfg80211_can_add_interface(rdev, wdev->iftype);
-               mutex_unlock(&rdev->devlist_mtx);
                if (ret)
                        return notifier_from_errno(ret);
                break;
@@ -1089,12 +957,10 @@ static void __net_exit cfg80211_pernet_exit(struct net *net)
        struct cfg80211_registered_device *rdev;
 
        rtnl_lock();
-       mutex_lock(&cfg80211_mutex);
        list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
                if (net_eq(wiphy_net(&rdev->wiphy), net))
                        WARN_ON(cfg80211_switch_netns(rdev, &init_net));
        }
-       mutex_unlock(&cfg80211_mutex);
        rtnl_unlock();
 }