diff options
| author | Jukka Rissanen <jukka.rissanen@linux.intel.com> | 2014-12-15 13:25:39 +0200 |
|---|---|---|
| committer | Mister Oyster <oysterized@gmail.com> | 2017-04-13 12:32:24 +0200 |
| commit | 50a83a05586f62b3c48ea83126cc44df135c813a (patch) | |
| tree | 5aaee5605d1228d1a885ec4d0120d983feb38cbe /net | |
| parent | fa5735fd9060d1c90bd96fa9633d7ee5d5dbe651 (diff) | |
BACKPORT: nl80211: Stop scheduled scan if netlink client disappears
(cherry pick from commit 93a1e86ce10e4898f9ca9cd09d659a8a7780ee5e)
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>
Bug: 25561044
Change-Id: Ibe4a555b29b64b6df1b9ed4cdcd0f05a69416d14
Diffstat (limited to 'net')
| -rw-r--r-- | net/wireless/core.c | 16 | ||||
| -rw-r--r-- | net/wireless/core.h | 2 | ||||
| -rw-r--r-- | net/wireless/nl80211.c | 16 |
3 files changed, 34 insertions, 0 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c index 0603f5982..0fc9d7531 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -344,6 +344,20 @@ static void cfg80211_destroy_iface_wk(struct work_struct *work) rtnl_unlock(); } +static void cfg80211_sched_scan_stop_wk(struct work_struct *work) +{ + struct cfg80211_registered_device *rdev; + + rdev = container_of(work, struct cfg80211_registered_device, + sched_scan_stop_wk); + + rtnl_lock(); + + __cfg80211_stop_sched_scan(rdev, false); + + rtnl_unlock(); +} + /* exported functions */ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) @@ -410,6 +424,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) 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); #ifdef CONFIG_CFG80211_DEFAULT_PS rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; @@ -780,6 +795,7 @@ void wiphy_unregister(struct wiphy *wiphy) flush_work(&rdev->event_work); cancel_delayed_work_sync(&rdev->dfs_update_channels_wk); flush_work(&rdev->destroy_work); + flush_work(&rdev->sched_scan_stop_wk); if (rdev->wowlan && rdev->ops->set_wakeup) rdev_set_wakeup(rdev, false); diff --git a/net/wireless/core.h b/net/wireless/core.h index 9363ac0a4..20db2b1ec 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -94,6 +94,8 @@ struct cfg80211_registered_device { struct list_head destroy_list; struct work_struct destroy_work; + struct work_struct sched_scan_stop_wk; + /* must be last because of the way we do wiphy_priv(), * and it should at least be aligned to NETDEV_ALIGN */ struct wiphy wiphy __aligned(NETDEV_ALIGN); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 7cd5224d5..713d9439b 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -5600,6 +5600,9 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, err = rdev_sched_scan_start(rdev, dev, request); if (!err) { + if (info->attrs[NL80211_ATTR_IFACE_SOCKET_OWNER]) + request->owner_nlportid = info->snd_portid; + rdev->sched_scan_req = request; nl80211_send_sched_scan(rdev, dev, NL80211_CMD_START_SCHED_SCAN); @@ -10907,6 +10910,13 @@ static int nl80211_netlink_notify(struct notifier_block * nb, list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { bool schedule_destroy_work = false; + bool schedule_scan_stop = false; + struct cfg80211_sched_scan_request *sched_scan_req = + rcu_dereference(rdev->sched_scan_req); + + if (sched_scan_req && notify->portid && + sched_scan_req->owner_nlportid == notify->portid) + schedule_scan_stop = true; list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) { cfg80211_mlme_unregister_socket(wdev, notify->portid); @@ -10937,6 +10947,12 @@ static int nl80211_netlink_notify(struct notifier_block * nb, spin_unlock(&rdev->destroy_list_lock); schedule_work(&rdev->destroy_work); } + } else if (schedule_scan_stop) { + sched_scan_req->owner_nlportid = 0; + + if (rdev->ops->sched_scan_stop && + rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) + schedule_work(&rdev->sched_scan_stop_wk); } } |
