]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - net/wireless/core.c
Merge tag 'for-4.12/dm-post-merge-changes' of git://git.kernel.org/pub/scm/linux...
[karo-tx-linux.git] / net / wireless / core.c
index e55e05bc48053f5542696a4c2d53170dfd02577c..83ea164f16b3e018546260d8e809ae6b244d85e3 100644 (file)
@@ -305,30 +305,14 @@ static void cfg80211_event_work(struct work_struct *work)
 
 void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev)
 {
-       struct cfg80211_iface_destroy *item;
+       struct wireless_dev *wdev, *tmp;
 
        ASSERT_RTNL();
 
-       spin_lock_irq(&rdev->destroy_list_lock);
-       while ((item = list_first_entry_or_null(&rdev->destroy_list,
-                                               struct cfg80211_iface_destroy,
-                                               list))) {
-               struct wireless_dev *wdev, *tmp;
-               u32 nlportid = item->nlportid;
-
-               list_del(&item->list);
-               kfree(item);
-               spin_unlock_irq(&rdev->destroy_list_lock);
-
-               list_for_each_entry_safe(wdev, tmp,
-                                        &rdev->wiphy.wdev_list, list) {
-                       if (nlportid == wdev->owner_nlportid)
-                               rdev_del_virtual_intf(rdev, wdev);
-               }
-
-               spin_lock_irq(&rdev->destroy_list_lock);
+       list_for_each_entry_safe(wdev, tmp, &rdev->wiphy.wdev_list, list) {
+               if (wdev->nl_owner_dead)
+                       rdev_del_virtual_intf(rdev, wdev);
        }
-       spin_unlock_irq(&rdev->destroy_list_lock);
 }
 
 static void cfg80211_destroy_iface_wk(struct work_struct *work)
@@ -346,13 +330,47 @@ static void cfg80211_destroy_iface_wk(struct work_struct *work)
 static void cfg80211_sched_scan_stop_wk(struct work_struct *work)
 {
        struct cfg80211_registered_device *rdev;
+       struct cfg80211_sched_scan_request *req, *tmp;
 
        rdev = container_of(work, struct cfg80211_registered_device,
                           sched_scan_stop_wk);
 
        rtnl_lock();
+       list_for_each_entry_safe(req, tmp, &rdev->sched_scan_req_list, list) {
+               if (req->nl_owner_dead)
+                       cfg80211_stop_sched_scan_req(rdev, req, false);
+       }
+       rtnl_unlock();
+}
 
-       __cfg80211_stop_sched_scan(rdev, false);
+static void cfg80211_propagate_radar_detect_wk(struct work_struct *work)
+{
+       struct cfg80211_registered_device *rdev;
+
+       rdev = container_of(work, struct cfg80211_registered_device,
+                           propagate_radar_detect_wk);
+
+       rtnl_lock();
+
+       regulatory_propagate_dfs_state(&rdev->wiphy, &rdev->radar_chandef,
+                                      NL80211_DFS_UNAVAILABLE,
+                                      NL80211_RADAR_DETECTED);
+
+       rtnl_unlock();
+}
+
+static void cfg80211_propagate_cac_done_wk(struct work_struct *work)
+{
+       struct cfg80211_registered_device *rdev;
+
+       rdev = container_of(work, struct cfg80211_registered_device,
+                           propagate_cac_done_wk);
+
+       rtnl_lock();
+
+       regulatory_propagate_dfs_state(&rdev->wiphy, &rdev->cac_done_chandef,
+                                      NL80211_DFS_AVAILABLE,
+                                      NL80211_RADAR_CAC_FINISHED);
 
        rtnl_unlock();
 }
@@ -436,8 +454,8 @@ use_default_name:
        spin_lock_init(&rdev->beacon_registrations_lock);
        spin_lock_init(&rdev->bss_lock);
        INIT_LIST_HEAD(&rdev->bss_list);
+       INIT_LIST_HEAD(&rdev->sched_scan_req_list);
        INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);
-       INIT_WORK(&rdev->sched_scan_results_wk, __cfg80211_sched_scan_results);
        INIT_LIST_HEAD(&rdev->mlme_unreg);
        spin_lock_init(&rdev->mlme_unreg_lock);
        INIT_WORK(&rdev->mlme_unreg_wk, cfg80211_mlme_unreg_wk);
@@ -452,10 +470,12 @@ use_default_name:
        rdev->wiphy.dev.platform_data = rdev;
        device_enable_async_suspend(&rdev->wiphy.dev);
 
-       INIT_LIST_HEAD(&rdev->destroy_list);
-       spin_lock_init(&rdev->destroy_list_lock);
        INIT_WORK(&rdev->destroy_work, cfg80211_destroy_iface_wk);
        INIT_WORK(&rdev->sched_scan_stop_wk, cfg80211_sched_scan_stop_wk);
+       INIT_WORK(&rdev->sched_scan_res_wk, cfg80211_sched_scan_results_wk);
+       INIT_WORK(&rdev->propagate_radar_detect_wk,
+                 cfg80211_propagate_radar_detect_wk);
+       INIT_WORK(&rdev->propagate_cac_done_wk, cfg80211_propagate_cac_done_wk);
 
 #ifdef CONFIG_CFG80211_DEFAULT_PS
        rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
@@ -915,6 +935,8 @@ void wiphy_unregister(struct wiphy *wiphy)
        flush_work(&rdev->destroy_work);
        flush_work(&rdev->sched_scan_stop_wk);
        flush_work(&rdev->mlme_unreg_wk);
+       flush_work(&rdev->propagate_radar_detect_wk);
+       flush_work(&rdev->propagate_cac_done_wk);
 
 #ifdef CONFIG_PM
        if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup)
@@ -954,6 +976,12 @@ void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked)
 }
 EXPORT_SYMBOL(wiphy_rfkill_set_hw_state);
 
+void cfg80211_cqm_config_free(struct wireless_dev *wdev)
+{
+       kfree(wdev->cqm_config);
+       wdev->cqm_config = NULL;
+}
+
 void cfg80211_unregister_wdev(struct wireless_dev *wdev)
 {
        struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
@@ -980,6 +1008,8 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev)
                WARN_ON_ONCE(1);
                break;
        }
+
+       cfg80211_cqm_config_free(wdev);
 }
 EXPORT_SYMBOL(cfg80211_unregister_wdev);
 
@@ -1001,7 +1031,7 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev,
                      struct wireless_dev *wdev)
 {
        struct net_device *dev = wdev->netdev;
-       struct cfg80211_sched_scan_request *sched_scan_req;
+       struct cfg80211_sched_scan_request *pos, *tmp;
 
        ASSERT_RTNL();
        ASSERT_WDEV_LOCK(wdev);
@@ -1012,9 +1042,11 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev,
                break;
        case NL80211_IFTYPE_P2P_CLIENT:
        case NL80211_IFTYPE_STATION:
-               sched_scan_req = rtnl_dereference(rdev->sched_scan_req);
-               if (sched_scan_req && dev == sched_scan_req->dev)
-                       __cfg80211_stop_sched_scan(rdev, false);
+               list_for_each_entry_safe(pos, tmp, &rdev->sched_scan_req_list,
+                                        list) {
+                       if (dev == pos->dev)
+                               cfg80211_stop_sched_scan_req(rdev, pos, false);
+               }
 
 #ifdef CONFIG_CFG80211_WEXT
                kfree(wdev->wext.ie);
@@ -1089,7 +1121,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_registered_device *rdev;
-       struct cfg80211_sched_scan_request *sched_scan_req;
+       struct cfg80211_sched_scan_request *pos, *tmp;
 
        if (!wdev)
                return NOTIFY_DONE;
@@ -1114,7 +1146,15 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
                INIT_LIST_HEAD(&wdev->mgmt_registrations);
                spin_lock_init(&wdev->mgmt_registrations_lock);
 
-               wdev->identifier = ++rdev->wdev_id;
+               /*
+                * We get here also when the interface changes network namespaces,
+                * as it's registered into the new one, but we don't want it to
+                * change ID in that case. Checking if the ID is already assigned
+                * works, because 0 isn't considered a valid ID and the memory is
+                * 0-initialized.
+                */
+               if (!wdev->identifier)
+                       wdev->identifier = ++rdev->wdev_id;
                list_add_rcu(&wdev->list, &rdev->wiphy.wdev_list);
                rdev->devlist_generation++;
                /* can only change netns with wiphy */
@@ -1158,10 +1198,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
                        ___cfg80211_scan_done(rdev, false);
                }
 
-               sched_scan_req = rtnl_dereference(rdev->sched_scan_req);
-               if (WARN_ON(sched_scan_req &&
-                           sched_scan_req->dev == wdev->netdev)) {
-                       __cfg80211_stop_sched_scan(rdev, false);
+               list_for_each_entry_safe(pos, tmp,
+                                        &rdev->sched_scan_req_list, list) {
+                       if (WARN_ON(pos && pos->dev == wdev->netdev))
+                               cfg80211_stop_sched_scan_req(rdev, pos, false);
                }
 
                rdev->opencount--;
@@ -1208,12 +1248,12 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
                 */
                if ((wdev->iftype == NL80211_IFTYPE_STATION ||
                     wdev->iftype == NL80211_IFTYPE_P2P_CLIENT) &&
-                   rdev->ops->set_power_mgmt)
-                       if (rdev_set_power_mgmt(rdev, dev, wdev->ps,
-                                               wdev->ps_timeout)) {
-                               /* assume this means it's off */
-                               wdev->ps = false;
-                       }
+                   rdev->ops->set_power_mgmt &&
+                   rdev_set_power_mgmt(rdev, dev, wdev->ps,
+                                       wdev->ps_timeout)) {
+                       /* assume this means it's off */
+                       wdev->ps = false;
+               }
                break;
        case NETDEV_UNREGISTER:
                /*
@@ -1234,6 +1274,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
                        kzfree(wdev->wext.keys);
 #endif
                        flush_work(&wdev->disconnect_wk);
+                       cfg80211_cqm_config_free(wdev);
                }
                /*
                 * synchronise (so that we won't find this netdev