aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
authorJukka Rissanen <jukka.rissanen@linux.intel.com>2014-12-15 06:25:39 -0500
committerJohannes Berg <johannes.berg@intel.com>2014-12-18 08:38:44 -0500
commit93a1e86ce10e4898f9ca9cd09d659a8a7780ee5e (patch)
tree42155b15af02c90d9c824ffbc2d3ad8b6d4a9b34 /net/wireless
parent31a60ed1e95ab8afbadb65599bef12b195080a0c (diff)
nl80211: Stop scheduled scan if netlink client disappears
An attribute NL80211_ATTR_SOCKET_OWNER can be set by the scan initiator. If present, the attribute will cause the scan to be stopped if the client dies. Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/core.c16
-rw-r--r--net/wireless/core.h2
-rw-r--r--net/wireless/nl80211.c16
3 files changed, 34 insertions, 0 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 0743449405ca..456e4c38c279 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -321,6 +321,20 @@ static void cfg80211_destroy_iface_wk(struct work_struct *work)
321 rtnl_unlock(); 321 rtnl_unlock();
322} 322}
323 323
324static void cfg80211_sched_scan_stop_wk(struct work_struct *work)
325{
326 struct cfg80211_registered_device *rdev;
327
328 rdev = container_of(work, struct cfg80211_registered_device,
329 sched_scan_stop_wk);
330
331 rtnl_lock();
332
333 __cfg80211_stop_sched_scan(rdev, false);
334
335 rtnl_unlock();
336}
337
324/* exported functions */ 338/* exported functions */
325 339
326struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv, 340struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
@@ -407,6 +421,7 @@ use_default_name:
407 INIT_LIST_HEAD(&rdev->destroy_list); 421 INIT_LIST_HEAD(&rdev->destroy_list);
408 spin_lock_init(&rdev->destroy_list_lock); 422 spin_lock_init(&rdev->destroy_list_lock);
409 INIT_WORK(&rdev->destroy_work, cfg80211_destroy_iface_wk); 423 INIT_WORK(&rdev->destroy_work, cfg80211_destroy_iface_wk);
424 INIT_WORK(&rdev->sched_scan_stop_wk, cfg80211_sched_scan_stop_wk);
410 425
411#ifdef CONFIG_CFG80211_DEFAULT_PS 426#ifdef CONFIG_CFG80211_DEFAULT_PS
412 rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; 427 rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
@@ -787,6 +802,7 @@ void wiphy_unregister(struct wiphy *wiphy)
787 flush_work(&rdev->event_work); 802 flush_work(&rdev->event_work);
788 cancel_delayed_work_sync(&rdev->dfs_update_channels_wk); 803 cancel_delayed_work_sync(&rdev->dfs_update_channels_wk);
789 flush_work(&rdev->destroy_work); 804 flush_work(&rdev->destroy_work);
805 flush_work(&rdev->sched_scan_stop_wk);
790 806
791#ifdef CONFIG_PM 807#ifdef CONFIG_PM
792 if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup) 808 if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup)
diff --git a/net/wireless/core.h b/net/wireless/core.h
index e82030c32311..801cd49c5a0c 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -91,6 +91,8 @@ struct cfg80211_registered_device {
91 struct list_head destroy_list; 91 struct list_head destroy_list;
92 struct work_struct destroy_work; 92 struct work_struct destroy_work;
93 93
94 struct work_struct sched_scan_stop_wk;
95
94 /* must be last because of the way we do wiphy_priv(), 96 /* must be last because of the way we do wiphy_priv(),
95 * and it should at least be aligned to NETDEV_ALIGN */ 97 * and it should at least be aligned to NETDEV_ALIGN */
96 struct wiphy wiphy __aligned(NETDEV_ALIGN); 98 struct wiphy wiphy __aligned(NETDEV_ALIGN);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index bacdf22fa472..702920134b34 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -6214,6 +6214,9 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
6214 sched_scan_req->dev = dev; 6214 sched_scan_req->dev = dev;
6215 sched_scan_req->wiphy = &rdev->wiphy; 6215 sched_scan_req->wiphy = &rdev->wiphy;
6216 6216
6217 if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
6218 sched_scan_req->owner_nlportid = info->snd_portid;
6219
6217 rcu_assign_pointer(rdev->sched_scan_req, sched_scan_req); 6220 rcu_assign_pointer(rdev->sched_scan_req, sched_scan_req);
6218 6221
6219 nl80211_send_sched_scan(rdev, dev, 6222 nl80211_send_sched_scan(rdev, dev,
@@ -12618,6 +12621,13 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
12618 12621
12619 list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { 12622 list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
12620 bool schedule_destroy_work = false; 12623 bool schedule_destroy_work = false;
12624 bool schedule_scan_stop = false;
12625 struct cfg80211_sched_scan_request *sched_scan_req =
12626 rcu_dereference(rdev->sched_scan_req);
12627
12628 if (sched_scan_req && notify->portid &&
12629 sched_scan_req->owner_nlportid == notify->portid)
12630 schedule_scan_stop = true;
12621 12631
12622 list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) { 12632 list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) {
12623 cfg80211_mlme_unregister_socket(wdev, notify->portid); 12633 cfg80211_mlme_unregister_socket(wdev, notify->portid);
@@ -12648,6 +12658,12 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
12648 spin_unlock(&rdev->destroy_list_lock); 12658 spin_unlock(&rdev->destroy_list_lock);
12649 schedule_work(&rdev->destroy_work); 12659 schedule_work(&rdev->destroy_work);
12650 } 12660 }
12661 } else if (schedule_scan_stop) {
12662 sched_scan_req->owner_nlportid = 0;
12663
12664 if (rdev->ops->sched_scan_stop &&
12665 rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
12666 schedule_work(&rdev->sched_scan_stop_wk);
12651 } 12667 }
12652 } 12668 }
12653 12669