[PATCH v9 2/2] nl80211: Stop scheduled scan if netlink client disappears

2014-12-15 Thread Jukka Rissanen
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 
---
 include/net/cfg80211.h   |  1 +
 include/uapi/linux/nl80211.h |  3 +++
 net/wireless/core.c  | 16 
 net/wireless/core.h  |  2 ++
 net/wireless/nl80211.c   | 16 
 5 files changed, 38 insertions(+)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 8ea8b94..4ba9790 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1538,6 +1538,7 @@ struct cfg80211_sched_scan_request {
struct net_device *dev;
unsigned long scan_start;
struct rcu_head rcu_head;
+   u32 owner_nlportid;
 
/* keep last */
struct ieee80211_channel *channels[0];
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index d775245..a0e3b32 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1655,6 +1655,9 @@ enum nl80211_commands {
  * @NL80211_ATTR_SOCKET_OWNER: Flag attribute, if set during interface
  * creation then the new interface will be owned by the netlink socket
  * that created it and will be destroyed when the socket is closed.
+ * If set during scheduled scan start then the new scan req will be
+ * owned by the netlink socket that created it and the scheduled scan will
+ * be stopped when the socket is closed.
  *
  * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
  * the TDLS link initiator.
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 9b43438..b612b71 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -320,6 +320,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_nm(const struct cfg80211_ops *ops, int sizeof_priv,
@@ -406,6 +420,7 @@ use_default_name:
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;
@@ -764,6 +779,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);
 
 #ifdef CONFIG_PM
if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup)
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 6cded4d..4e3630b 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -84,6 +84,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 be2654b..18d0d6f 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -6092,6 +6092,9 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
sched_scan_req->dev = dev;
sched_scan_req->wiphy = &rdev->wiphy;
 
+   if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
+   sched_scan_req->owner_nlportid = info->snd_portid;
+
rcu_assign_pointer(rdev->sched_scan_req, sched_scan_req);
 
nl80211_send_sched_scan(rdev, dev,
@@ -12474,6 +12477,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);
@@ -12504,6 +12514,12 @@ static int nl80211_netlink_notify(struct 

[PATCH v9 1/2] nl80211: Convert sched_scan_req pointer to RCU pointer

2014-12-15 Thread Jukka Rissanen
Because of possible races when accessing sched_scan_req pointer in
rdev, the sched_scan_req is converted to RCU pointer.

Signed-off-by: Jukka Rissanen 
---
 include/net/cfg80211.h |  1 +
 net/wireless/core.c| 10 +++---
 net/wireless/core.h|  2 +-
 net/wireless/nl80211.c | 19 +++
 net/wireless/scan.c| 13 -
 5 files changed, 28 insertions(+), 17 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index bb748c4..8ea8b94 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1537,6 +1537,7 @@ struct cfg80211_sched_scan_request {
struct wiphy *wiphy;
struct net_device *dev;
unsigned long scan_start;
+   struct rcu_head rcu_head;
 
/* keep last */
struct ieee80211_channel *channels[0];
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 4c2e501..9b43438 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -844,6 +844,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;
 
ASSERT_RTNL();
ASSERT_WDEV_LOCK(wdev);
@@ -854,7 +855,8 @@ void __cfg80211_leave(struct cfg80211_registered_device 
*rdev,
break;
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_STATION:
-   if (rdev->sched_scan_req && dev == rdev->sched_scan_req->dev)
+   sched_scan_req = rtnl_dereference(rdev->sched_scan_req);
+   if (sched_scan_req && dev == sched_scan_req->dev)
__cfg80211_stop_sched_scan(rdev, false);
 
 #ifdef CONFIG_CFG80211_WEXT
@@ -929,6 +931,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;
 
if (!wdev)
return NOTIFY_DONE;
@@ -993,8 +996,9 @@ static int cfg80211_netdev_notifier_call(struct 
notifier_block *nb,
___cfg80211_scan_done(rdev, false);
}
 
-   if (WARN_ON(rdev->sched_scan_req &&
-   rdev->sched_scan_req->dev == wdev->netdev)) {
+   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);
}
 
diff --git a/net/wireless/core.h b/net/wireless/core.h
index faa5b16..6cded4d 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -63,7 +63,7 @@ struct cfg80211_registered_device {
u32 bss_generation;
struct cfg80211_scan_request *scan_req; /* protected by RTNL */
struct sk_buff *scan_msg;
-   struct cfg80211_sched_scan_request *sched_scan_req;
+   struct cfg80211_sched_scan_request __rcu *sched_scan_req;
unsigned long suspend_at;
struct work_struct scan_done_wk;
struct work_struct sched_scan_results_wk;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index b5e3c48..be2654b 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -6068,6 +6068,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
struct wireless_dev *wdev = dev->ieee80211_ptr;
+   struct cfg80211_sched_scan_request *sched_scan_req;
int err;
 
if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
@@ -6077,27 +6078,29 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
if (rdev->sched_scan_req)
return -EINPROGRESS;
 
-   rdev->sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev,
-   info->attrs);
-   err = PTR_ERR_OR_ZERO(rdev->sched_scan_req);
+   sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev,
+ info->attrs);
+
+   err = PTR_ERR_OR_ZERO(sched_scan_req);
if (err)
goto out_err;
 
-   err = rdev_sched_scan_start(rdev, dev, rdev->sched_scan_req);
+   err = rdev_sched_scan_start(rdev, dev, sched_scan_req);
if (err)
goto out_free;
 
-   rdev->sched_scan_req->dev = dev;
-   rdev->sched_scan_req->wiphy = &rdev->wiphy;
+   sched_scan_req->dev = dev;
+   sched_scan_req->wiphy = &rdev->wiphy;
+
+   rcu_assign_pointer(rdev->sched_scan_req, sched_scan_req);

[PATCH v9 0/2] Stop scheduled scan if netlink client disappears

2014-12-15 Thread Jukka Rissanen
Hi,

v9:
- switched the patch order, now RCU fixes are done before the scheduled
  scan tweaks
- fix the RCU code according to comments from v8

v8:
- reworked the RCU code and placed it in patch 2

v7:
- convert the cfg80211_sched_scan_request to __rcu pointer in order
  to avoid races when accessing it
- reverting the patch v6, the port id is back in request struct

v6:
- moved owner netlink port id from cfg80211_sched_scan_request to
  rdev in order to avoid possible races

v5:
- discarded the locking changes in v4
- instead of trying to schedule sched_scan_stop worker from
  struct cfg80211_sched_scan_request, move the worker to wiphy
  as that makes it easier to manage the sched_scan_stop worker.
  There are also one scheduled scan / wiphy so it is also logical
  to do it like this.

v4:
- rtnl locking issues fixed in patch 2

v3:
- backward compatibility define tweaked in patch 1
- added missing signed-off-by:

v2:
- split the patch
- In patch 1, use a generic NL80211_ATTR_SOCKET_OWNER attribute and
  convert the old code that uses NL80211_ATTR_IFACE_SOCKET_OWNER to
  use the new value. A define is provided for backward compatibility.
- Any pending schedule scan stop worker is cancelled when interface is
  taken down in patch 2


Jukka Rissanen (2):
  nl80211: Convert sched_scan_req pointer to RCU pointer
  nl80211: Stop scheduled scan if netlink client disappears

 include/net/cfg80211.h   |  2 ++
 include/uapi/linux/nl80211.h |  3 +++
 net/wireless/core.c  | 26 +++---
 net/wireless/core.h  |  4 +++-
 net/wireless/nl80211.c   | 35 +++
 net/wireless/scan.c  | 13 -
 6 files changed, 66 insertions(+), 17 deletions(-)

-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v8 2/2] nl80211: Convert sched_scan_req pointer to RCU pointer

2014-11-27 Thread Jukka Rissanen
Because of possible races when accessing sched_scan_req pointer in
rdev, the sched_scan_req is converted to RCU pointer.

Signed-off-by: Jukka Rissanen 
---
 include/net/cfg80211.h |  1 +
 net/wireless/core.c| 10 +++---
 net/wireless/core.h|  2 +-
 net/wireless/nl80211.c | 27 ---
 net/wireless/scan.c| 20 +++-
 5 files changed, 40 insertions(+), 20 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 5806c75..0e540fc 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1538,6 +1538,7 @@ struct cfg80211_sched_scan_request {
struct net_device *dev;
unsigned long scan_start;
u32 owner_nlportid;
+   struct rcu_head rcu_head;
 
/* keep last */
struct ieee80211_channel *channels[0];
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 8236e2d..b612b71 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -860,6 +860,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;
 
ASSERT_RTNL();
ASSERT_WDEV_LOCK(wdev);
@@ -870,7 +871,8 @@ void __cfg80211_leave(struct cfg80211_registered_device 
*rdev,
break;
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_STATION:
-   if (rdev->sched_scan_req && dev == rdev->sched_scan_req->dev)
+   sched_scan_req = rtnl_dereference(rdev->sched_scan_req);
+   if (sched_scan_req && dev == sched_scan_req->dev)
__cfg80211_stop_sched_scan(rdev, false);
 
 #ifdef CONFIG_CFG80211_WEXT
@@ -945,6 +947,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;
 
if (!wdev)
return NOTIFY_DONE;
@@ -1009,8 +1012,9 @@ static int cfg80211_netdev_notifier_call(struct 
notifier_block *nb,
___cfg80211_scan_done(rdev, false);
}
 
-   if (WARN_ON(rdev->sched_scan_req &&
-   rdev->sched_scan_req->dev == wdev->netdev)) {
+   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);
}
 
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 5327375..4e3630b 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -63,7 +63,7 @@ struct cfg80211_registered_device {
u32 bss_generation;
struct cfg80211_scan_request *scan_req; /* protected by RTNL */
struct sk_buff *scan_msg;
-   struct cfg80211_sched_scan_request *sched_scan_req;
+   struct cfg80211_sched_scan_request __rcu *sched_scan_req;
unsigned long suspend_at;
struct work_struct scan_done_wk;
struct work_struct sched_scan_results_wk;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index a5cc4d6..6cdb2ff 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -6068,6 +6068,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
struct wireless_dev *wdev = dev->ieee80211_ptr;
+   struct cfg80211_sched_scan_request *sched_scan_req;
int err;
 
if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
@@ -6077,30 +6078,34 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
if (rdev->sched_scan_req)
return -EINPROGRESS;
 
-   rdev->sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev,
-   info->attrs);
-   err = PTR_ERR_OR_ZERO(rdev->sched_scan_req);
+   sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev,
+ info->attrs);
+
+   err = PTR_ERR_OR_ZERO(sched_scan_req);
if (err)
goto out_err;
 
-   err = rdev_sched_scan_start(rdev, dev, rdev->sched_scan_req);
+   rcu_assign_pointer(rdev->sched_scan_req, sched_scan_req);
+
+   err = rdev_sched_scan_start(rdev, dev, sched_scan_req);
if (err)
goto out_free;
 
-   rdev->sched_scan_req->dev = dev;
-   rdev->sched_scan_req->wiphy = &rdev->wiphy;
-
if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
-   rdev->sc

[PATCH v8 1/2] nl80211: Stop scheduled scan if netlink client disappears

2014-11-27 Thread Jukka Rissanen
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 
---
 include/net/cfg80211.h   |  1 +
 include/uapi/linux/nl80211.h |  3 +++
 net/wireless/core.c  | 16 
 net/wireless/core.h  |  2 ++
 net/wireless/nl80211.c   | 16 
 5 files changed, 38 insertions(+)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index bb748c4..5806c75 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1537,6 +1537,7 @@ struct cfg80211_sched_scan_request {
struct wiphy *wiphy;
struct net_device *dev;
unsigned long scan_start;
+   u32 owner_nlportid;
 
/* keep last */
struct ieee80211_channel *channels[0];
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index d775245..a0e3b32 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1655,6 +1655,9 @@ enum nl80211_commands {
  * @NL80211_ATTR_SOCKET_OWNER: Flag attribute, if set during interface
  * creation then the new interface will be owned by the netlink socket
  * that created it and will be destroyed when the socket is closed.
+ * If set during scheduled scan start then the new scan req will be
+ * owned by the netlink socket that created it and the scheduled scan will
+ * be stopped when the socket is closed.
  *
  * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
  * the TDLS link initiator.
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 4c2e501..8236e2d 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -320,6 +320,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_nm(const struct cfg80211_ops *ops, int sizeof_priv,
@@ -406,6 +420,7 @@ use_default_name:
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;
@@ -764,6 +779,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);
 
 #ifdef CONFIG_PM
if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup)
diff --git a/net/wireless/core.h b/net/wireless/core.h
index faa5b16..5327375 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -84,6 +84,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 b5e3c48..a5cc4d6 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -6090,6 +6090,9 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
rdev->sched_scan_req->dev = dev;
rdev->sched_scan_req->wiphy = &rdev->wiphy;
 
+   if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
+   rdev->sched_scan_req->owner_nlportid = info->snd_portid;
+
nl80211_send_sched_scan(rdev, dev,
NL80211_CMD_START_SCHED_SCAN);
return 0;
@@ -12471,6 +12474,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 =
+   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);
@@ -12501,6 +12511,12 @@ static int nl80211_netlink_not

[PATCH v8 0/2] Stop scheduled scan if netlink client disappears

2014-11-27 Thread Jukka Rissanen
Hi,

v8:
- reworked the RCU code and placed it in patch 2

v7:
- convert the cfg80211_sched_scan_request to __rcu pointer in order
  to avoid races when accessing it
- reverting the patch v6, the port id is back in request struct

v6:
- moved owner netlink port id from cfg80211_sched_scan_request to
  rdev in order to avoid possible races

v5:
- discarded the locking changes in v4
- instead of trying to schedule sched_scan_stop worker from
  struct cfg80211_sched_scan_request, move the worker to wiphy
  as that makes it easier to manage the sched_scan_stop worker.
  There are also one scheduled scan / wiphy so it is also logical
  to do it like this.

v4:
- rtnl locking issues fixed in patch 2

v3:
- backward compatibility define tweaked in patch 1
- added missing signed-off-by:

v2:
- split the patch
- In patch 1, use a generic NL80211_ATTR_SOCKET_OWNER attribute and
  convert the old code that uses NL80211_ATTR_IFACE_SOCKET_OWNER to
  use the new value. A define is provided for backward compatibility.
- Any pending schedule scan stop worker is cancelled when interface is
  taken down in patch 2



Jukka Rissanen (2):
  nl80211: Stop scheduled scan if netlink client disappears
  nl80211: Convert sched_scan_req pointer to RCU pointer

 include/net/cfg80211.h   |  2 ++
 include/uapi/linux/nl80211.h |  3 +++
 net/wireless/core.c  | 26 +++---
 net/wireless/core.h  |  4 +++-
 net/wireless/nl80211.c   | 37 +
 net/wireless/scan.c  | 20 +++-
 6 files changed, 75 insertions(+), 17 deletions(-)

-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v7] nl80211: Stop scheduled scan if netlink client disappears

2014-11-26 Thread Jukka Rissanen
On ke, 2014-11-26 at 10:32 +0100, Johannes Berg wrote:
> On Wed, 2014-11-26 at 11:07 +0200, Jukka Rissanen wrote:
> > 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 
> > ---
> > Hi,
> > 
> > v7:
> > - convert the cfg80211_sched_scan_request to __rcu pointer in order
> >   to avoid races when accessing it
> 
> You totally need to revisit how to use RCU.

Yes, probably. This is very new stuff to me :)

> 
> Just some examples:
>  * don't synchronize_rcu() after assignment - what did you do that for?

Following the examples described in Documentation/RCU/whatisRCU.txt

>  * don't use rcu_read_lock() when you already have the write lock (rtnl)
>  * don't use rcu_access_pointer(), use
> - local variables
> - rcu_dereference_protected() (or rather rtnl_dereference())
> - rcu_dereference()
>  * actually fix it to assign the values before rcu_assign_pointer() so
> they're
>all published together ...
> 
> Also, please make that a separate patch so it isn't mixed with the
> functional changes.
> 
> johannes
> 

Jukka


--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7] nl80211: Stop scheduled scan if netlink client disappears

2014-11-26 Thread Jukka Rissanen
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 
---
Hi,

v7:
- convert the cfg80211_sched_scan_request to __rcu pointer in order
  to avoid races when accessing it
- reverting the patch v6, the port id is back in request struct

v6:
- moved owner netlink port id from cfg80211_sched_scan_request to
  rdev in order to avoid possible races

v5:
- discarded the locking changes in v4
- instead of trying to schedule sched_scan_stop worker from
  struct cfg80211_sched_scan_request, move the worker to wiphy
  as that makes it easier to manage the sched_scan_stop worker.
  There are also one scheduled scan / wiphy so it is also logical
  to do it like this.

v4:
- rtnl locking issues fixed in patch 2

v3:
- backward compatibility define tweaked in patch 1
- added missing signed-off-by:

v2:
- split the patch
- In patch 1, use a generic NL80211_ATTR_SOCKET_OWNER attribute and
  convert the old code that uses NL80211_ATTR_IFACE_SOCKET_OWNER to
  use the new value. A define is provided for backward compatibility.
- Any pending schedule scan stop worker is cancelled when interface is
  taken down in patch 2

Cheers,
Jukka


 include/net/cfg80211.h   |  2 ++
 include/uapi/linux/nl80211.h |  3 +++
 net/wireless/core.c  | 28 +---
 net/wireless/core.h  |  4 +++-
 net/wireless/nl80211.c   | 40 +---
 net/wireless/scan.c  | 27 +--
 6 files changed, 87 insertions(+), 17 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index bb748c4..0e540fc 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1537,6 +1537,8 @@ struct cfg80211_sched_scan_request {
struct wiphy *wiphy;
struct net_device *dev;
unsigned long scan_start;
+   u32 owner_nlportid;
+   struct rcu_head rcu_head;
 
/* keep last */
struct ieee80211_channel *channels[0];
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index d775245..a0e3b32 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1655,6 +1655,9 @@ enum nl80211_commands {
  * @NL80211_ATTR_SOCKET_OWNER: Flag attribute, if set during interface
  * creation then the new interface will be owned by the netlink socket
  * that created it and will be destroyed when the socket is closed.
+ * If set during scheduled scan start then the new scan req will be
+ * owned by the netlink socket that created it and the scheduled scan will
+ * be stopped when the socket is closed.
  *
  * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
  * the TDLS link initiator.
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 4c2e501..368e276 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -320,6 +320,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_nm(const struct cfg80211_ops *ops, int sizeof_priv,
@@ -406,6 +420,7 @@ use_default_name:
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;
@@ -764,6 +779,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);
 
 #ifdef CONFIG_PM
if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup)
@@ -854,8 +870,11 @@ void __cfg80211_leave(struct cfg80211_registered_device 
*rdev,
break;
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_STATION:
-   if (rdev->sched_scan_req && dev == rdev->sched_scan_req->dev)
+   rcu_read_lock();
+   if (rcu_access_pointer(rdev->sched_scan_req) &&
+   dev == rtnl_dereference(rdev->sched_scan_req)->dev)
__cfg80211_stop_sched_scan(rdev, false);
+   rcu_read_unlock();
 
 #ifdef CONFIG_CFG80211_WEXT
kfree(wdev->wext.ie);
@@ -993,10 +1012,13 @@ static int cf

Re: [PATCH v6] nl80211: Stop scheduled scan if netlink client disappears

2014-11-21 Thread Jukka Rissanen
Hi Johannes,

On to, 2014-11-20 at 16:14 +0100, Johannes Berg wrote:
> On Thu, 2014-11-20 at 13:32 +0200, Jukka Rissanen wrote:
> 
> > - moved owner netlink port id from cfg80211_sched_scan_request to
> >   rdev in order to avoid possible races
> 
> How does that really help though? You're not really locking it anyway.
> 
> I think you should consider keeping it inside the sched_scan_request,
> but maybe make that an __rcu pointer.
> 
> Your patch also still has the problem I pointed out to you before - you
> can get the following sequence of events:
> 
> start_sched_scan (owner=true)
> close socket - schedule worker
> start_sched_scan (from another socket, owner doesn't matter)

If I am reading the code correctly from
nl80211.c:nl80211_start_sched_scan() this socket will get -EINPROGRESS.
Only after the worker has finished and called
__cfg80211_stop_sched_scan() will the other socket able to start a new
scheduled scan. Or I might have just missed some important detail
here :)

> run worker - cancels the new sched_scan
> 
> You need to make sure the worker is flushed in start_sched_scan or so,
> which might require RTNL work there or something.
> 
> johannes
> 


Cheers,
Jukka


--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v6] nl80211: Stop scheduled scan if netlink client disappears

2014-11-20 Thread Jukka Rissanen
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 
---
Hi,

v6:
- moved owner netlink port id from cfg80211_sched_scan_request to
  rdev in order to avoid possible races

v5:
- discarded the locking changes in v4
- instead of trying to schedule sched_scan_stop worker from
  struct cfg80211_sched_scan_request, move the worker to wiphy
  as that makes it easier to manage the sched_scan_stop worker.
  There are also one scheduled scan / wiphy so it is also logical
  to do it like this.

v4:
- rtnl locking issues fixed in patch 2

v3:
- backward compatibility define tweaked in patch 1
- added missing signed-off-by:

v2:
- split the patch
- In patch 1, use a generic NL80211_ATTR_SOCKET_OWNER attribute and
  convert the old code that uses NL80211_ATTR_IFACE_SOCKET_OWNER to
  use the new value. A define is provided for backward compatibility.
- Any pending schedule scan stop worker is cancelled when interface is
  taken down in patch 2

Cheers,
Jukka


 include/uapi/linux/nl80211.h |  3 +++
 net/wireless/core.c  | 17 +
 net/wireless/core.h  |  2 ++
 net/wireless/nl80211.c   | 14 ++
 4 files changed, 36 insertions(+)

diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 185f9c7..5038240 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1640,6 +1640,9 @@ enum nl80211_commands {
  * @NL80211_ATTR_SOCKET_OWNER: Flag attribute, if set during interface
  * creation then the new interface will be owned by the netlink socket
  * that created it and will be destroyed when the socket is closed.
+ * If set during scheduled scan start then the new scan req will be
+ * owned by the netlink socket that created it and the scheduled scan will
+ * be stopped when the socket is closed.
  *
  * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
  * the TDLS link initiator.
diff --git a/net/wireless/core.c b/net/wireless/core.c
index a4d2792..6fffcb3 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -320,6 +320,21 @@ 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();
+
+   if (rdev->sched_scan_req)
+   __cfg80211_stop_sched_scan(rdev, false);
+
+   rtnl_unlock();
+}
+
 /* exported functions */
 
 struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
@@ -406,6 +421,7 @@ use_default_name:
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;
@@ -760,6 +776,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);
 
 #ifdef CONFIG_PM
if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup)
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 61ee664..c27615e 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -67,6 +67,8 @@ struct cfg80211_registered_device {
unsigned long suspend_at;
struct work_struct scan_done_wk;
struct work_struct sched_scan_results_wk;
+   struct work_struct sched_scan_stop_wk;
+   u32 sched_scan_owner_nlportid;
 
struct genl_info *cur_cmd_info;
 
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index df447c0..9ed6a34 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5955,6 +5955,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_SOCKET_OWNER])
+   rdev->sched_scan_owner_nlportid = info->snd_portid;
+
rdev->sched_scan_req = request;
nl80211_send_sched_scan(rdev, dev,
NL80211_CMD_START_SCHED_SCAN);
@@ -12127,6 +12130,11 @@ 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;
+
+   if (rdev->sched_s

[PATCH v2] mac80211-hwsim: hwname is always known so use the value from wiphy

2014-11-14 Thread Jukka Rissanen
We can always know the hwname of the radio so use the value
from wiphy.

Signed-off-by: Jukka Rissanen 
---
Hi,

this v2 adds the missing signed-off-by

Cheers,
Jukka

 drivers/net/wireless/mac80211_hwsim.c | 18 +-
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c 
b/drivers/net/wireless/mac80211_hwsim.c
index 58f11bb..d1bb775 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -2474,12 +2474,10 @@ static void hwsim_mcast_del_radio(int id, const char 
*hwname,
if (ret < 0)
goto error;
 
-   if (hwname) {
-   ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME, strlen(hwname),
- hwname);
-   if (ret < 0)
-   goto error;
-   }
+   ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME, strlen(hwname),
+ hwname);
+   if (ret < 0)
+   goto error;
 
genlmsg_end(skb, data);
 
@@ -2513,7 +2511,8 @@ static void mac80211_hwsim_free(void)
list))) {
list_del(&data->list);
spin_unlock_bh(&hwsim_radio_lock);
-   mac80211_hwsim_del_radio(data, NULL, NULL);
+   mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy),
+NULL);
spin_lock_bh(&hwsim_radio_lock);
}
spin_unlock_bh(&hwsim_radio_lock);
@@ -2799,7 +2798,8 @@ static int hwsim_del_radio_nl(struct sk_buff *msg, struct 
genl_info *info)
 
list_del(&data->list);
spin_unlock_bh(&hwsim_radio_lock);
-   mac80211_hwsim_del_radio(data, hwname, info);
+   mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy),
+info);
return 0;
}
spin_unlock_bh(&hwsim_radio_lock);
@@ -2844,7 +2844,7 @@ static void destroy_radio(struct work_struct *work)
struct mac80211_hwsim_data *data =
container_of(work, struct mac80211_hwsim_data, destroy_work);
 
-   mac80211_hwsim_del_radio(data, NULL, NULL);
+   mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy), NULL);
 }
 
 static void remove_user_radios(u32 portid)
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] mac80211-hwsim: hwname is always known in wiphy

2014-11-14 Thread Jukka Rissanen
We can always know the hwname of the radio so use the value
from wiphy.
---
 drivers/net/wireless/mac80211_hwsim.c | 18 +-
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c 
b/drivers/net/wireless/mac80211_hwsim.c
index 58f11bb..d1bb775 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -2474,12 +2474,10 @@ static void hwsim_mcast_del_radio(int id, const char 
*hwname,
if (ret < 0)
goto error;
 
-   if (hwname) {
-   ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME, strlen(hwname),
- hwname);
-   if (ret < 0)
-   goto error;
-   }
+   ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME, strlen(hwname),
+ hwname);
+   if (ret < 0)
+   goto error;
 
genlmsg_end(skb, data);
 
@@ -2513,7 +2511,8 @@ static void mac80211_hwsim_free(void)
list))) {
list_del(&data->list);
spin_unlock_bh(&hwsim_radio_lock);
-   mac80211_hwsim_del_radio(data, NULL, NULL);
+   mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy),
+NULL);
spin_lock_bh(&hwsim_radio_lock);
}
spin_unlock_bh(&hwsim_radio_lock);
@@ -2799,7 +2798,8 @@ static int hwsim_del_radio_nl(struct sk_buff *msg, struct 
genl_info *info)
 
list_del(&data->list);
spin_unlock_bh(&hwsim_radio_lock);
-   mac80211_hwsim_del_radio(data, hwname, info);
+   mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy),
+info);
return 0;
}
spin_unlock_bh(&hwsim_radio_lock);
@@ -2844,7 +2844,7 @@ static void destroy_radio(struct work_struct *work)
struct mac80211_hwsim_data *data =
container_of(work, struct mac80211_hwsim_data, destroy_work);
 
-   mac80211_hwsim_del_radio(data, NULL, NULL);
+   mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy), NULL);
 }
 
 static void remove_user_radios(u32 portid)
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v5 2/2] nl80211: Stop scheduled scan if netlink client disappears

2014-11-13 Thread Jukka Rissanen
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 
---
 include/net/cfg80211.h   |  1 +
 include/uapi/linux/nl80211.h |  3 +++
 net/wireless/core.c  | 17 +
 net/wireless/core.h  |  2 ++
 net/wireless/nl80211.c   | 15 +++
 5 files changed, 38 insertions(+)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 220d5f5..6fa764a 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1512,6 +1512,7 @@ struct cfg80211_sched_scan_request {
struct wiphy *wiphy;
struct net_device *dev;
unsigned long scan_start;
+   u32 owner_nlportid;
 
/* keep last */
struct ieee80211_channel *channels[0];
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 185f9c7..5038240 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1640,6 +1640,9 @@ enum nl80211_commands {
  * @NL80211_ATTR_SOCKET_OWNER: Flag attribute, if set during interface
  * creation then the new interface will be owned by the netlink socket
  * that created it and will be destroyed when the socket is closed.
+ * If set during scheduled scan start then the new scan req will be
+ * owned by the netlink socket that created it and the scheduled scan will
+ * be stopped when the socket is closed.
  *
  * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
  * the TDLS link initiator.
diff --git a/net/wireless/core.c b/net/wireless/core.c
index a4d2792..6fffcb3 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -320,6 +320,21 @@ 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();
+
+   if (rdev->sched_scan_req)
+   __cfg80211_stop_sched_scan(rdev, false);
+
+   rtnl_unlock();
+}
+
 /* exported functions */
 
 struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
@@ -406,6 +421,7 @@ use_default_name:
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;
@@ -760,6 +776,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);
 
 #ifdef CONFIG_PM
if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup)
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 61ee664..1bdffac 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -84,6 +84,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 df447c0..8ab3610 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5955,6 +5955,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_SOCKET_OWNER])
+   request->owner_nlportid = info->snd_portid;
+
rdev->sched_scan_req = request;
nl80211_send_sched_scan(rdev, dev,
NL80211_CMD_START_SCHED_SCAN);
@@ -12127,6 +12130,12 @@ 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 *req = rdev->sched_scan_req;
+
+   if (req && req->owner_nlportid == notify->portid &&
+   notify->portid)
+   schedule_scan_stop = true;
 
list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) {
cfg80211_mlme_unregister_socket(wdev, notify->portid);
@@ -12157,6 +12166,12 @

[PATCH v5 1/2] nl80211: Replace interface socket owner attribute with more generic one

2014-11-13 Thread Jukka Rissanen
Replace NL80211_ATTR_IFACE_SOCKET_OWNER attribute with more generic
NL80211_ATTR_SOCKET_OWNER that can be used with other commands
that interface creation.

Signed-off-by: Jukka Rissanen 
---
 include/uapi/linux/nl80211.h | 7 ---
 net/wireless/nl80211.c   | 4 ++--
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 442369f..185f9c7 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1637,9 +1637,9 @@ enum nl80211_commands {
  * @NL80211_ATTR_TDLS_PEER_CAPABILITY: flags for TDLS peer capabilities, u32.
  * As specified in the &enum nl80211_tdls_peer_capability.
  *
- * @NL80211_ATTR_IFACE_SOCKET_OWNER: flag attribute, if set during interface
+ * @NL80211_ATTR_SOCKET_OWNER: Flag attribute, if set during interface
  * creation then the new interface will be owned by the netlink socket
- * that created it and will be destroyed when the socket is closed
+ * that created it and will be destroyed when the socket is closed.
  *
  * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
  * the TDLS link initiator.
@@ -2004,7 +2004,7 @@ enum nl80211_attrs {
 
NL80211_ATTR_TDLS_PEER_CAPABILITY,
 
-   NL80211_ATTR_IFACE_SOCKET_OWNER,
+   NL80211_ATTR_SOCKET_OWNER,
 
NL80211_ATTR_CSA_C_OFFSETS_TX,
NL80211_ATTR_MAX_CSA_COUNTERS,
@@ -2030,6 +2030,7 @@ enum nl80211_attrs {
 /* source-level API compatibility */
 #define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION
 #defineNL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG
+#define NL80211_ATTR_IFACE_SOCKET_OWNER NL80211_ATTR_SOCKET_OWNER
 
 /*
  * Allow user space programs to use #ifdef on new attributes by defining them
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index d0a8361..df447c0 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -388,7 +388,7 @@ static const struct nla_policy 
nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_MAC_HINT] = { .len = ETH_ALEN },
[NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 },
[NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 },
-   [NL80211_ATTR_IFACE_SOCKET_OWNER] = { .type = NLA_FLAG },
+   [NL80211_ATTR_SOCKET_OWNER] = { .type = NLA_FLAG },
[NL80211_ATTR_CSA_C_OFFSETS_TX] = { .type = NLA_BINARY },
[NL80211_ATTR_USE_RRM] = { .type = NLA_FLAG },
[NL80211_ATTR_TSID] = { .type = NLA_U8 },
@@ -2646,7 +2646,7 @@ static int nl80211_new_interface(struct sk_buff *skb, 
struct genl_info *info)
return PTR_ERR(wdev);
}
 
-   if (info->attrs[NL80211_ATTR_IFACE_SOCKET_OWNER])
+   if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
wdev->owner_nlportid = info->snd_portid;
 
switch (type) {
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v5 0/2] Stop scheduled scan if netlink client disappears

2014-11-13 Thread Jukka Rissanen
Hi,

v5:
- discarded the locking changes in v4
- instead of trying to schedule sched_scan_stop worker from
  struct cfg80211_sched_scan_request, move the worker to wiphy
  as that makes it easier to manage the sched_scan_stop worker.
  There are also one scheduled scan / wiphy so it is also logical
  to do it like this.

v4:
- rtnl locking issues fixed in patch 2

v3:
- backward compatibility define tweaked in patch 1
- added missing signed-off-by:

v2:
- split the patch
- In patch 1, use a generic NL80211_ATTR_SOCKET_OWNER attribute and
  convert the old code that uses NL80211_ATTR_IFACE_SOCKET_OWNER to
  use the new value. A define is provided for backward compatibility.
- Any pending schedule scan stop worker is cancelled when interface is
  taken down in patch 2

Cheers,
Jukka


Jukka Rissanen (2):
  nl80211: Replace interface socket owner attribute with more generic
one
  nl80211: Stop scheduled scan if netlink client disappears

 include/net/cfg80211.h   |  1 +
 include/uapi/linux/nl80211.h | 10 +++---
 net/wireless/core.c  | 17 +
 net/wireless/core.h  |  2 ++
 net/wireless/nl80211.c   | 19 +--
 5 files changed, 44 insertions(+), 5 deletions(-)

-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v4 0/2] Stop scheduled scan if netlink client disappears

2014-11-13 Thread Jukka Rissanen
Hi,

v4:
- rtnl locking issues fixed in patch 2

v3:
- backward compatibility define tweaked in patch 1
- added missing signed-off-by:

v2:
- split the patch
- In patch 1, use a generic NL80211_ATTR_SOCKET_OWNER attribute and
  convert the old code that uses NL80211_ATTR_IFACE_SOCKET_OWNER to
  use the new value. A define is provided for backward compatibility.
- Any pending schedule scan stop worker is cancelled when interface is
  taken down in patch 2

Cheers,
Jukka


Jukka Rissanen (2):
  nl80211: Replace interface socket owner attribute with more generic
one
  nl80211: Stop scheduled scan if netlink client disappears

 include/net/cfg80211.h   |  2 ++
 include/uapi/linux/nl80211.h | 10 +++---
 net/wireless/core.c  |  5 -
 net/wireless/nl80211.c   | 39 +--
 4 files changed, 50 insertions(+), 6 deletions(-)

-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v4 2/2] nl80211: Stop scheduled scan if netlink client disappears

2014-11-13 Thread Jukka Rissanen
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 
---
 include/net/cfg80211.h   |  2 ++
 include/uapi/linux/nl80211.h |  3 +++
 net/wireless/core.c  |  5 -
 net/wireless/nl80211.c   | 35 +++
 4 files changed, 44 insertions(+), 1 deletion(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 220d5f5..84378bf 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1512,6 +1512,8 @@ struct cfg80211_sched_scan_request {
struct wiphy *wiphy;
struct net_device *dev;
unsigned long scan_start;
+   u32 owner_nlportid;
+   struct work_struct sched_scan_stop_wk;
 
/* keep last */
struct ieee80211_channel *channels[0];
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 185f9c7..5038240 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1640,6 +1640,9 @@ enum nl80211_commands {
  * @NL80211_ATTR_SOCKET_OWNER: Flag attribute, if set during interface
  * creation then the new interface will be owned by the netlink socket
  * that created it and will be destroyed when the socket is closed.
+ * If set during scheduled scan start then the new scan req will be
+ * owned by the netlink socket that created it and the scheduled scan will
+ * be stopped when the socket is closed.
  *
  * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
  * the TDLS link initiator.
diff --git a/net/wireless/core.c b/net/wireless/core.c
index a4d2792..9d33df6 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -850,8 +850,10 @@ void __cfg80211_leave(struct cfg80211_registered_device 
*rdev,
break;
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_STATION:
-   if (rdev->sched_scan_req && dev == rdev->sched_scan_req->dev)
+   if (rdev->sched_scan_req && dev == rdev->sched_scan_req->dev) {
+   flush_work(&rdev->sched_scan_req->sched_scan_stop_wk);
__cfg80211_stop_sched_scan(rdev, false);
+   }
 
 #ifdef CONFIG_CFG80211_WEXT
kfree(wdev->wext.ie);
@@ -991,6 +993,7 @@ static int cfg80211_netdev_notifier_call(struct 
notifier_block *nb,
 
if (WARN_ON(rdev->sched_scan_req &&
rdev->sched_scan_req->dev == wdev->netdev)) {
+   flush_work(&rdev->sched_scan_req->sched_scan_stop_wk);
__cfg80211_stop_sched_scan(rdev, false);
}
 
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index df447c0..87a4b71 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5681,6 +5681,22 @@ static int nl80211_trigger_scan(struct sk_buff *skb, 
struct genl_info *info)
return err;
 }
 
+static void nl80211_sched_scan_stop_wk(struct work_struct *work)
+{
+   struct cfg80211_sched_scan_request *req;
+   struct cfg80211_registered_device *rdev;
+
+   req = container_of(work, struct cfg80211_sched_scan_request,
+  sched_scan_stop_wk);
+
+   rdev = wiphy_to_rdev(req->wiphy);
+
+   if (rtnl_trylock()) {
+   __cfg80211_stop_sched_scan(rdev, false);
+   rtnl_unlock();
+   }
+}
+
 static int nl80211_start_sched_scan(struct sk_buff *skb,
struct genl_info *info)
 {
@@ -5955,6 +5971,13 @@ 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_SOCKET_OWNER]) {
+   INIT_WORK(&request->sched_scan_stop_wk,
+ nl80211_sched_scan_stop_wk);
+
+   request->owner_nlportid = info->snd_portid;
+   }
+
rdev->sched_scan_req = request;
nl80211_send_sched_scan(rdev, dev,
NL80211_CMD_START_SCHED_SCAN);
@@ -12127,6 +12150,12 @@ 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 *req = rdev->sched_scan_req;
+
+   if (req && req->owner_nlportid == notify->portid &&
+   notify->portid)
+   schedule_scan_stop = true;
 
list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) {
cfg80211_mlme_unregister_socket(wdev, notify->porti

[PATCH v4 1/2] nl80211: Replace interface socket owner attribute with more generic one

2014-11-13 Thread Jukka Rissanen
Replace NL80211_ATTR_IFACE_SOCKET_OWNER attribute with more generic
NL80211_ATTR_SOCKET_OWNER that can be used with other commands
that interface creation.

Signed-off-by: Jukka Rissanen 
---
 include/uapi/linux/nl80211.h | 7 ---
 net/wireless/nl80211.c   | 4 ++--
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 442369f..185f9c7 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1637,9 +1637,9 @@ enum nl80211_commands {
  * @NL80211_ATTR_TDLS_PEER_CAPABILITY: flags for TDLS peer capabilities, u32.
  * As specified in the &enum nl80211_tdls_peer_capability.
  *
- * @NL80211_ATTR_IFACE_SOCKET_OWNER: flag attribute, if set during interface
+ * @NL80211_ATTR_SOCKET_OWNER: Flag attribute, if set during interface
  * creation then the new interface will be owned by the netlink socket
- * that created it and will be destroyed when the socket is closed
+ * that created it and will be destroyed when the socket is closed.
  *
  * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
  * the TDLS link initiator.
@@ -2004,7 +2004,7 @@ enum nl80211_attrs {
 
NL80211_ATTR_TDLS_PEER_CAPABILITY,
 
-   NL80211_ATTR_IFACE_SOCKET_OWNER,
+   NL80211_ATTR_SOCKET_OWNER,
 
NL80211_ATTR_CSA_C_OFFSETS_TX,
NL80211_ATTR_MAX_CSA_COUNTERS,
@@ -2030,6 +2030,7 @@ enum nl80211_attrs {
 /* source-level API compatibility */
 #define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION
 #defineNL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG
+#define NL80211_ATTR_IFACE_SOCKET_OWNER NL80211_ATTR_SOCKET_OWNER
 
 /*
  * Allow user space programs to use #ifdef on new attributes by defining them
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index d0a8361..df447c0 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -388,7 +388,7 @@ static const struct nla_policy 
nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_MAC_HINT] = { .len = ETH_ALEN },
[NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 },
[NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 },
-   [NL80211_ATTR_IFACE_SOCKET_OWNER] = { .type = NLA_FLAG },
+   [NL80211_ATTR_SOCKET_OWNER] = { .type = NLA_FLAG },
[NL80211_ATTR_CSA_C_OFFSETS_TX] = { .type = NLA_BINARY },
[NL80211_ATTR_USE_RRM] = { .type = NLA_FLAG },
[NL80211_ATTR_TSID] = { .type = NLA_U8 },
@@ -2646,7 +2646,7 @@ static int nl80211_new_interface(struct sk_buff *skb, 
struct genl_info *info)
return PTR_ERR(wdev);
}
 
-   if (info->attrs[NL80211_ATTR_IFACE_SOCKET_OWNER])
+   if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
wdev->owner_nlportid = info->snd_portid;
 
switch (type) {
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 1/2] nl80211: Replace interface socket owner attribute with more generic one

2014-11-12 Thread Jukka Rissanen
Replace NL80211_ATTR_IFACE_SOCKET_OWNER attribute with more generic
NL80211_ATTR_SOCKET_OWNER that can be used with other commands
that interface creation.

Signed-off-by: Jukka Rissanen 
---
 include/uapi/linux/nl80211.h | 7 ---
 net/wireless/nl80211.c   | 4 ++--
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 442369f..185f9c7 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1637,9 +1637,9 @@ enum nl80211_commands {
  * @NL80211_ATTR_TDLS_PEER_CAPABILITY: flags for TDLS peer capabilities, u32.
  * As specified in the &enum nl80211_tdls_peer_capability.
  *
- * @NL80211_ATTR_IFACE_SOCKET_OWNER: flag attribute, if set during interface
+ * @NL80211_ATTR_SOCKET_OWNER: Flag attribute, if set during interface
  * creation then the new interface will be owned by the netlink socket
- * that created it and will be destroyed when the socket is closed
+ * that created it and will be destroyed when the socket is closed.
  *
  * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
  * the TDLS link initiator.
@@ -2004,7 +2004,7 @@ enum nl80211_attrs {
 
NL80211_ATTR_TDLS_PEER_CAPABILITY,
 
-   NL80211_ATTR_IFACE_SOCKET_OWNER,
+   NL80211_ATTR_SOCKET_OWNER,
 
NL80211_ATTR_CSA_C_OFFSETS_TX,
NL80211_ATTR_MAX_CSA_COUNTERS,
@@ -2030,6 +2030,7 @@ enum nl80211_attrs {
 /* source-level API compatibility */
 #define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION
 #defineNL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG
+#define NL80211_ATTR_IFACE_SOCKET_OWNER NL80211_ATTR_SOCKET_OWNER
 
 /*
  * Allow user space programs to use #ifdef on new attributes by defining them
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index d0a8361..df447c0 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -388,7 +388,7 @@ static const struct nla_policy 
nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_MAC_HINT] = { .len = ETH_ALEN },
[NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 },
[NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 },
-   [NL80211_ATTR_IFACE_SOCKET_OWNER] = { .type = NLA_FLAG },
+   [NL80211_ATTR_SOCKET_OWNER] = { .type = NLA_FLAG },
[NL80211_ATTR_CSA_C_OFFSETS_TX] = { .type = NLA_BINARY },
[NL80211_ATTR_USE_RRM] = { .type = NLA_FLAG },
[NL80211_ATTR_TSID] = { .type = NLA_U8 },
@@ -2646,7 +2646,7 @@ static int nl80211_new_interface(struct sk_buff *skb, 
struct genl_info *info)
return PTR_ERR(wdev);
}
 
-   if (info->attrs[NL80211_ATTR_IFACE_SOCKET_OWNER])
+   if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
wdev->owner_nlportid = info->snd_portid;
 
switch (type) {
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 2/2] nl80211: Stop scheduled scan if netlink client disappears

2014-11-12 Thread Jukka Rissanen
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 
---
 include/net/cfg80211.h   |  2 ++
 include/uapi/linux/nl80211.h |  3 +++
 net/wireless/core.c  | 10 +-
 net/wireless/nl80211.c   | 34 ++
 4 files changed, 48 insertions(+), 1 deletion(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 220d5f5..84378bf 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1512,6 +1512,8 @@ struct cfg80211_sched_scan_request {
struct wiphy *wiphy;
struct net_device *dev;
unsigned long scan_start;
+   u32 owner_nlportid;
+   struct work_struct sched_scan_stop_wk;
 
/* keep last */
struct ieee80211_channel *channels[0];
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 185f9c7..5038240 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1640,6 +1640,9 @@ enum nl80211_commands {
  * @NL80211_ATTR_SOCKET_OWNER: Flag attribute, if set during interface
  * creation then the new interface will be owned by the netlink socket
  * that created it and will be destroyed when the socket is closed.
+ * If set during scheduled scan start then the new scan req will be
+ * owned by the netlink socket that created it and the scheduled scan will
+ * be stopped when the socket is closed.
  *
  * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
  * the TDLS link initiator.
diff --git a/net/wireless/core.c b/net/wireless/core.c
index a4d2792..88898d9 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -840,6 +840,8 @@ 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 =
+   rdev->sched_scan_req;
 
ASSERT_RTNL();
ASSERT_WDEV_LOCK(wdev);
@@ -850,8 +852,10 @@ void __cfg80211_leave(struct cfg80211_registered_device 
*rdev,
break;
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_STATION:
-   if (rdev->sched_scan_req && dev == rdev->sched_scan_req->dev)
+   if (sched_scan_req && dev == sched_scan_req->dev) {
+   cancel_work_sync(&sched_scan_req->sched_scan_stop_wk);
__cfg80211_stop_sched_scan(rdev, false);
+   }
 
 #ifdef CONFIG_CFG80211_WEXT
kfree(wdev->wext.ie);
@@ -991,6 +995,10 @@ static int cfg80211_netdev_notifier_call(struct 
notifier_block *nb,
 
if (WARN_ON(rdev->sched_scan_req &&
rdev->sched_scan_req->dev == wdev->netdev)) {
+   struct cfg80211_sched_scan_request *sched_scan_req =
+   rdev->sched_scan_req;
+
+   cancel_work_sync(&sched_scan_req->sched_scan_stop_wk);
__cfg80211_stop_sched_scan(rdev, false);
}
 
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index df447c0..8fc500d 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5681,6 +5681,21 @@ static int nl80211_trigger_scan(struct sk_buff *skb, 
struct genl_info *info)
return err;
 }
 
+static void nl80211_sched_scan_stop_wk(struct work_struct *work)
+{
+   struct cfg80211_sched_scan_request *req;
+   struct cfg80211_registered_device *rdev;
+
+   req = container_of(work, struct cfg80211_sched_scan_request,
+  sched_scan_stop_wk);
+
+   rdev = wiphy_to_rdev(req->wiphy);
+
+   rtnl_lock();
+   __cfg80211_stop_sched_scan(rdev, false);
+   rtnl_unlock();
+}
+
 static int nl80211_start_sched_scan(struct sk_buff *skb,
struct genl_info *info)
 {
@@ -5955,6 +5970,13 @@ 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_SOCKET_OWNER]) {
+   INIT_WORK(&request->sched_scan_stop_wk,
+ nl80211_sched_scan_stop_wk);
+
+   request->owner_nlportid = info->snd_portid;
+   }
+
rdev->sched_scan_req = request;
nl80211_send_sched_scan(rdev, dev,
NL80211_CMD_START_SCHED_SCAN);
@@ -12127,6 +12149,12 @@ 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;
+   

[PATCH v3 0/2] Stop scheduled scan if netlink client disappears

2014-11-12 Thread Jukka Rissanen
Hi,

v3:
- backward compatibility define tweaked in patch 1
- added missing signed-off-by:

v2:
- split the patch
- In patch 1, use a generic NL80211_ATTR_SOCKET_OWNER attribute and
  convert the old code that uses NL80211_ATTR_IFACE_SOCKET_OWNER to
  use the new value. A define is provided for backward compatibility.
- Any pending schedule scan stop worker is cancelled when interface is
  taken down in patch 2

Cheers,
Jukka


Jukka Rissanen (2):
  nl80211: Replace interface socket owner attribute with more generic
one
  nl80211: Stop scheduled scan if netlink client disappears

 include/net/cfg80211.h   |  2 ++
 include/uapi/linux/nl80211.h | 10 +++---
 net/wireless/core.c  | 10 +-
 net/wireless/nl80211.c   | 38 --
 4 files changed, 54 insertions(+), 6 deletions(-)

-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 2/2] nl80211: Stop scheduled scan if netlink client disappears

2014-11-12 Thread Jukka Rissanen
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.
---
 include/net/cfg80211.h   |  2 ++
 include/uapi/linux/nl80211.h |  3 +++
 net/wireless/core.c  | 10 +-
 net/wireless/nl80211.c   | 34 ++
 4 files changed, 48 insertions(+), 1 deletion(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 220d5f5..84378bf 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1512,6 +1512,8 @@ struct cfg80211_sched_scan_request {
struct wiphy *wiphy;
struct net_device *dev;
unsigned long scan_start;
+   u32 owner_nlportid;
+   struct work_struct sched_scan_stop_wk;
 
/* keep last */
struct ieee80211_channel *channels[0];
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index c410284..310dc9b 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1640,6 +1640,9 @@ enum nl80211_commands {
  * @NL80211_ATTR_SOCKET_OWNER: Flag attribute, if set during interface
  * creation then the new interface will be owned by the netlink socket
  * that created it and will be destroyed when the socket is closed.
+ * If set during scheduled scan start then the new scan req will be
+ * owned by the netlink socket that created it and the scheduled scan will
+ * be stopped when the socket is closed.
  *
  * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
  * the TDLS link initiator.
diff --git a/net/wireless/core.c b/net/wireless/core.c
index a4d2792..88898d9 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -840,6 +840,8 @@ 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 =
+   rdev->sched_scan_req;
 
ASSERT_RTNL();
ASSERT_WDEV_LOCK(wdev);
@@ -850,8 +852,10 @@ void __cfg80211_leave(struct cfg80211_registered_device 
*rdev,
break;
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_STATION:
-   if (rdev->sched_scan_req && dev == rdev->sched_scan_req->dev)
+   if (sched_scan_req && dev == sched_scan_req->dev) {
+   cancel_work_sync(&sched_scan_req->sched_scan_stop_wk);
__cfg80211_stop_sched_scan(rdev, false);
+   }
 
 #ifdef CONFIG_CFG80211_WEXT
kfree(wdev->wext.ie);
@@ -991,6 +995,10 @@ static int cfg80211_netdev_notifier_call(struct 
notifier_block *nb,
 
if (WARN_ON(rdev->sched_scan_req &&
rdev->sched_scan_req->dev == wdev->netdev)) {
+   struct cfg80211_sched_scan_request *sched_scan_req =
+   rdev->sched_scan_req;
+
+   cancel_work_sync(&sched_scan_req->sched_scan_stop_wk);
__cfg80211_stop_sched_scan(rdev, false);
}
 
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index df447c0..8fc500d 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5681,6 +5681,21 @@ static int nl80211_trigger_scan(struct sk_buff *skb, 
struct genl_info *info)
return err;
 }
 
+static void nl80211_sched_scan_stop_wk(struct work_struct *work)
+{
+   struct cfg80211_sched_scan_request *req;
+   struct cfg80211_registered_device *rdev;
+
+   req = container_of(work, struct cfg80211_sched_scan_request,
+  sched_scan_stop_wk);
+
+   rdev = wiphy_to_rdev(req->wiphy);
+
+   rtnl_lock();
+   __cfg80211_stop_sched_scan(rdev, false);
+   rtnl_unlock();
+}
+
 static int nl80211_start_sched_scan(struct sk_buff *skb,
struct genl_info *info)
 {
@@ -5955,6 +5970,13 @@ 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_SOCKET_OWNER]) {
+   INIT_WORK(&request->sched_scan_stop_wk,
+ nl80211_sched_scan_stop_wk);
+
+   request->owner_nlportid = info->snd_portid;
+   }
+
rdev->sched_scan_req = request;
nl80211_send_sched_scan(rdev, dev,
NL80211_CMD_START_SCHED_SCAN);
@@ -12127,6 +12149,12 @@ 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 *req = rdev->sched_scan_req;
+
+   if (req && req->owner_nlportid == notify->portid 

[PATCH v2 0/2] Stop scheduled scan if netlink client disappears

2014-11-12 Thread Jukka Rissanen
Hi,

v2:

- split the patch
- In patch 1, use a generic NL80211_ATTR_SOCKET_OWNER attribute and
  convert the old code that uses NL80211_ATTR_IFACE_SOCKET_OWNER to
  use the new value. A define is provided for backward compatibility.
- Any pending schedule scan stop worker is cancelled when interface is
  taken down in patch 2

Cheers,
Jukka


Jukka Rissanen (2):
  nl80211: Replace interface socket owner attribute with more generic
one
  nl80211: Stop scheduled scan if netlink client disappears

 include/net/cfg80211.h   |  2 ++
 include/uapi/linux/nl80211.h | 11 ---
 net/wireless/core.c  | 10 +-
 net/wireless/nl80211.c   | 38 --
 4 files changed, 55 insertions(+), 6 deletions(-)

-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 1/2] nl80211: Replace interface socket owner attribute with more generic one

2014-11-12 Thread Jukka Rissanen
Replace NL80211_ATTR_IFACE_SOCKET_OWNER attribute with more generic
NL80211_ATTR_SOCKET_OWNER that can be used with other commands
that interface creation.
---
 include/uapi/linux/nl80211.h | 8 +---
 net/wireless/nl80211.c   | 4 ++--
 2 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 442369f..c410284 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1637,9 +1637,9 @@ enum nl80211_commands {
  * @NL80211_ATTR_TDLS_PEER_CAPABILITY: flags for TDLS peer capabilities, u32.
  * As specified in the &enum nl80211_tdls_peer_capability.
  *
- * @NL80211_ATTR_IFACE_SOCKET_OWNER: flag attribute, if set during interface
+ * @NL80211_ATTR_SOCKET_OWNER: Flag attribute, if set during interface
  * creation then the new interface will be owned by the netlink socket
- * that created it and will be destroyed when the socket is closed
+ * that created it and will be destroyed when the socket is closed.
  *
  * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
  * the TDLS link initiator.
@@ -2004,7 +2004,7 @@ enum nl80211_attrs {
 
NL80211_ATTR_TDLS_PEER_CAPABILITY,
 
-   NL80211_ATTR_IFACE_SOCKET_OWNER,
+   NL80211_ATTR_SOCKET_OWNER,
 
NL80211_ATTR_CSA_C_OFFSETS_TX,
NL80211_ATTR_MAX_CSA_COUNTERS,
@@ -2056,6 +2056,8 @@ enum nl80211_attrs {
 #define NL80211_ATTR_KEY NL80211_ATTR_KEY
 #define NL80211_ATTR_KEYS NL80211_ATTR_KEYS
 #define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS
+#define NL80211_ATTR_IFACE_SOCKET_OWNER NL80211_ATTR_SOCKET_OWNER
+#define NL80211_ATTR_SOCKET_OWNER NL80211_ATTR_SOCKET_OWNER
 
 #define NL80211_MAX_SUPP_RATES 32
 #define NL80211_MAX_SUPP_HT_RATES  77
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index d0a8361..df447c0 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -388,7 +388,7 @@ static const struct nla_policy 
nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_MAC_HINT] = { .len = ETH_ALEN },
[NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 },
[NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 },
-   [NL80211_ATTR_IFACE_SOCKET_OWNER] = { .type = NLA_FLAG },
+   [NL80211_ATTR_SOCKET_OWNER] = { .type = NLA_FLAG },
[NL80211_ATTR_CSA_C_OFFSETS_TX] = { .type = NLA_BINARY },
[NL80211_ATTR_USE_RRM] = { .type = NLA_FLAG },
[NL80211_ATTR_TSID] = { .type = NLA_U8 },
@@ -2646,7 +2646,7 @@ static int nl80211_new_interface(struct sk_buff *skb, 
struct genl_info *info)
return PTR_ERR(wdev);
}
 
-   if (info->attrs[NL80211_ATTR_IFACE_SOCKET_OWNER])
+   if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
wdev->owner_nlportid = info->snd_portid;
 
switch (type) {
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] nl80211: Stop scheduled scan if netlink client disappears

2014-11-11 Thread Jukka Rissanen
A new attribute NL80211_ATTR_SCAN_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 
---
 include/net/cfg80211.h   |  2 ++
 include/uapi/linux/nl80211.h |  8 
 net/wireless/nl80211.c   | 35 +++
 3 files changed, 45 insertions(+)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 220d5f5..84378bf 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1512,6 +1512,8 @@ struct cfg80211_sched_scan_request {
struct wiphy *wiphy;
struct net_device *dev;
unsigned long scan_start;
+   u32 owner_nlportid;
+   struct work_struct sched_scan_stop_wk;
 
/* keep last */
struct ieee80211_channel *channels[0];
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 442369f..2731a04 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1669,6 +1669,11 @@ enum nl80211_commands {
  * @NL80211_ATTR_SMPS_MODE: SMPS mode to use (ap mode). see
  * &enum nl80211_smps_mode.
  *
+ * @NL80211_ATTR_SCAN_SOCKET_OWNER: flag attribute, if set during scheduled
+ * scan start then the new scan req will be owned by the netlink socket
+ * that created it and the pending scan will be stopped when the socket
+ * is closed.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -2021,6 +2026,8 @@ enum nl80211_attrs {
 
NL80211_ATTR_SMPS_MODE,
 
+   NL80211_ATTR_SCAN_SOCKET_OWNER,
+
/* add attributes here, update the policy in nl80211.c */
 
__NL80211_ATTR_AFTER_LAST,
@@ -2056,6 +2063,7 @@ enum nl80211_attrs {
 #define NL80211_ATTR_KEY NL80211_ATTR_KEY
 #define NL80211_ATTR_KEYS NL80211_ATTR_KEYS
 #define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS
+#define NL80211_ATTR_SCAN_SOCKET_OWNER NL80211_ATTR_SCAN_SOCKET_OWNER
 
 #define NL80211_MAX_SUPP_RATES 32
 #define NL80211_MAX_SUPP_HT_RATES  77
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index d0a8361..653f649 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -395,6 +395,7 @@ static const struct nla_policy 
nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_USER_PRIO] = { .type = NLA_U8 },
[NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 },
[NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 },
+   [NL80211_ATTR_SCAN_SOCKET_OWNER] = { .type = NLA_FLAG },
 };
 
 /* policy for the key attributes */
@@ -5681,6 +5682,21 @@ static int nl80211_trigger_scan(struct sk_buff *skb, 
struct genl_info *info)
return err;
 }
 
+static void nl80211_sched_scan_stop_wk(struct work_struct *work)
+{
+   struct cfg80211_sched_scan_request *req;
+   struct cfg80211_registered_device *rdev;
+
+   req = container_of(work, struct cfg80211_sched_scan_request,
+  sched_scan_stop_wk);
+
+   rdev = wiphy_to_rdev(req->wiphy);
+
+   rtnl_lock();
+   __cfg80211_stop_sched_scan(rdev, false);
+   rtnl_unlock();
+}
+
 static int nl80211_start_sched_scan(struct sk_buff *skb,
struct genl_info *info)
 {
@@ -5955,6 +5971,13 @@ 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_SCAN_SOCKET_OWNER]) {
+   INIT_WORK(&request->sched_scan_stop_wk,
+ nl80211_sched_scan_stop_wk);
+
+   request->owner_nlportid = info->snd_portid;
+   }
+
rdev->sched_scan_req = request;
nl80211_send_sched_scan(rdev, dev,
NL80211_CMD_START_SCHED_SCAN);
@@ -12127,6 +12150,12 @@ 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 *req = rdev->sched_scan_req;
+
+   if (req && req->owner_nlportid == notify->portid &&
+   notify->portid)
+   schedule_scan_stop = true;
 
list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) {
cfg80211_mlme_unregister_socket(wdev, notify->portid);
@@ -12157,6 +12186,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) {
+  

[PATCH v3 0/2] Add mcast event when hwsim radios are created and removed

2014-10-31 Thread Jukka Rissanen
Hi,

v3:
- rebased on top of the latest changes in upstream

v2:
- removed old patch 1 as that is already applied
- added suitable prefixes to new function names
- refactored the patch 1 so that multicast message building is
  separated into a more generic function
- instead of passing radio parameters (6 pcs) into different functions
  separately, a struct is used instead

v1:
patch 1 renames HWSIM_CMD_CREATE_RADIO to HWSIM_CMD_NEW_RADIO and
HWSIM_CMD_DESTROY_RADIO to HWSIM_CMD_DEL_RADIO. They are more
fitting on how other pieces of the wireless system work. A define
to old name is provided for backward compatibility.

Patches 2 and 3 use the newly named enums and provide a way to inform
the listeners on the multicast group "config" when new radio is created
and existing radio is deleted.


Jukka Rissanen (2):
  mac80211-hwsim: Provide multicast event for HWSIM_CMD_NEW_RADIO
  mac80211-hwsim: Provide multicast event for HWSIM_CMD_DEL_RADIO

 drivers/net/wireless/mac80211_hwsim.c | 329 +-
 1 file changed, 245 insertions(+), 84 deletions(-)

-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 2/2] mac80211-hwsim: Provide multicast event for HWSIM_CMD_DEL_RADIO

2014-10-31 Thread Jukka Rissanen
When deleting old radio via HWSIM_CMD_DEL_RADIO then listeners on the
multicast group "config" are informed.

Signed-off-by: Jukka Rissanen 
---
 drivers/net/wireless/mac80211_hwsim.c | 54 ++-
 1 file changed, 47 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c 
b/drivers/net/wireless/mac80211_hwsim.c
index 476c89c..209db62 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -2404,8 +2404,48 @@ failed:
return err;
 }
 
-static void mac80211_hwsim_destroy_radio(struct mac80211_hwsim_data *data)
+static void hwsim_mcast_del_radio(int id, const char *hwname,
+ struct genl_info *info)
 {
+   struct sk_buff *skb;
+   void *data;
+   int ret;
+
+   skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
+   if (!skb)
+   return;
+
+   data = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0,
+  HWSIM_CMD_DEL_RADIO);
+   if (!data)
+   goto error;
+
+   ret = nla_put_u32(skb, HWSIM_ATTR_RADIO_ID, id);
+   if (ret < 0)
+   goto error;
+
+   if (hwname) {
+   ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME, strlen(hwname),
+ hwname);
+   if (ret < 0)
+   goto error;
+   }
+
+   genlmsg_end(skb, data);
+
+   hwsim_mcast_config_msg(skb, info);
+
+   return;
+
+error:
+   nlmsg_free(skb);
+}
+
+static void mac80211_hwsim_del_radio(struct mac80211_hwsim_data *data,
+const char *hwname,
+struct genl_info *info)
+{
+   hwsim_mcast_del_radio(data->idx, hwname, info);
debugfs_remove_recursive(data->debugfs);
ieee80211_unregister_hw(data->hw);
device_release_driver(data->dev);
@@ -2423,7 +2463,7 @@ static void mac80211_hwsim_free(void)
list))) {
list_del(&data->list);
spin_unlock_bh(&hwsim_radio_lock);
-   mac80211_hwsim_destroy_radio(data);
+   mac80211_hwsim_del_radio(data, NULL, NULL);
spin_lock_bh(&hwsim_radio_lock);
}
spin_unlock_bh(&hwsim_radio_lock);
@@ -2683,7 +2723,7 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct 
genl_info *info)
return mac80211_hwsim_new_radio(info, ¶m);
 }
 
-static int hwsim_destroy_radio_nl(struct sk_buff *msg, struct genl_info *info)
+static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info)
 {
struct mac80211_hwsim_data *data;
s64 idx = -1;
@@ -2709,7 +2749,7 @@ static int hwsim_destroy_radio_nl(struct sk_buff *msg, 
struct genl_info *info)
 
list_del(&data->list);
spin_unlock_bh(&hwsim_radio_lock);
-   mac80211_hwsim_destroy_radio(data);
+   mac80211_hwsim_del_radio(data, hwname, info);
return 0;
}
spin_unlock_bh(&hwsim_radio_lock);
@@ -2742,9 +2782,9 @@ static const struct genl_ops hwsim_ops[] = {
.flags = GENL_ADMIN_PERM,
},
{
-   .cmd = HWSIM_CMD_DESTROY_RADIO,
+   .cmd = HWSIM_CMD_DEL_RADIO,
.policy = hwsim_genl_policy,
-   .doit = hwsim_destroy_radio_nl,
+   .doit = hwsim_del_radio_nl,
.flags = GENL_ADMIN_PERM,
},
 };
@@ -2754,7 +2794,7 @@ static void destroy_radio(struct work_struct *work)
struct mac80211_hwsim_data *data =
container_of(work, struct mac80211_hwsim_data, destroy_work);
 
-   mac80211_hwsim_destroy_radio(data);
+   mac80211_hwsim_del_radio(data, NULL, NULL);
 }
 
 static void remove_user_radios(u32 portid)
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 1/2] mac80211-hwsim: Provide multicast event for HWSIM_CMD_NEW_RADIO

2014-10-31 Thread Jukka Rissanen
When adding new radio via HWSIM_CMD_NEW_RADIO then listeners on the
multicast group "config" are informed.

Signed-off-by: Jukka Rissanen 
---
 drivers/net/wireless/mac80211_hwsim.c | 275 --
 1 file changed, 198 insertions(+), 77 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c 
b/drivers/net/wireless/mac80211_hwsim.c
index 5dbaee3..476c89c 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -487,6 +487,14 @@ static struct genl_family hwsim_genl_family = {
.maxattr = HWSIM_ATTR_MAX,
 };
 
+enum hwsim_multicast_groups {
+   HWSIM_MCGRP_CONFIG,
+};
+
+static const struct genl_multicast_group hwsim_mcgrps[] = {
+   [HWSIM_MCGRP_CONFIG] = { .name = "config", },
+};
+
 /* MAC80211_HWSIM netlink policy */
 
 static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = {
@@ -2025,12 +2033,124 @@ static const struct ieee80211_ops mac80211_hwsim_ops = 
{
 
 static struct ieee80211_ops mac80211_hwsim_mchan_ops;
 
-static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
-  const struct ieee80211_regdomain *regd,
-  bool reg_strict, bool p2p_device,
-  bool use_chanctx, bool destroy_on_close,
-  u32 portid, const char *hwname,
-  bool no_vif)
+struct hwsim_new_radio_params {
+   unsigned int channels;
+   const char *reg_alpha2;
+   const struct ieee80211_regdomain *regd;
+   bool reg_strict;
+   bool p2p_device;
+   bool use_chanctx;
+   bool destroy_on_close;
+   const char *hwname;
+   bool no_vif;
+};
+
+static void hwsim_mcast_config_msg(struct sk_buff *mcast_skb,
+  struct genl_info *info)
+{
+   if (info)
+   genl_notify(&hwsim_genl_family, mcast_skb,
+   genl_info_net(info), info->snd_portid,
+   HWSIM_MCGRP_CONFIG, info->nlhdr, GFP_KERNEL);
+   else
+   genlmsg_multicast(&hwsim_genl_family, mcast_skb, 0,
+ HWSIM_MCGRP_CONFIG, GFP_KERNEL);
+}
+
+static struct sk_buff *build_radio_msg(int cmd, int id,
+  struct hwsim_new_radio_params *param)
+{
+   struct sk_buff *skb;
+   void *data;
+   int ret;
+
+   skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
+   if (!skb)
+   return NULL;
+
+   data = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, cmd);
+   if (!data)
+   goto error;
+
+   ret = nla_put_u32(skb, HWSIM_ATTR_RADIO_ID, id);
+   if (ret < 0)
+   goto error;
+
+   if (param->channels) {
+   ret = nla_put_u32(skb, HWSIM_ATTR_CHANNELS, param->channels);
+   if (ret < 0)
+   goto error;
+   }
+
+   if (param->reg_alpha2) {
+   ret = nla_put(skb, HWSIM_ATTR_REG_HINT_ALPHA2, 2,
+ param->reg_alpha2);
+   if (ret < 0)
+   goto error;
+   }
+
+   if (param->regd) {
+   int i;
+
+   for (i = 0; hwsim_world_regdom_custom[i] != param->regd &&
+i < ARRAY_SIZE(hwsim_world_regdom_custom); i++)
+   ;
+
+   if (i < ARRAY_SIZE(hwsim_world_regdom_custom)) {
+   ret = nla_put_u32(skb, HWSIM_ATTR_REG_CUSTOM_REG, i);
+   if (ret < 0)
+   goto error;
+   }
+   }
+
+   if (param->reg_strict) {
+   ret = nla_put_flag(skb, HWSIM_ATTR_REG_STRICT_REG);
+   if (ret < 0)
+   goto error;
+   }
+
+   if (param->p2p_device) {
+   ret = nla_put_flag(skb, HWSIM_ATTR_SUPPORT_P2P_DEVICE);
+   if (ret < 0)
+   goto error;
+   }
+
+   if (param->use_chanctx) {
+   ret = nla_put_flag(skb, HWSIM_ATTR_USE_CHANCTX);
+   if (ret < 0)
+   goto error;
+   }
+
+   if (param->hwname) {
+   ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME,
+ strlen(param->hwname), param->hwname);
+   if (ret < 0)
+   goto error;
+   }
+
+   genlmsg_end(skb, data);
+
+   return skb;
+
+error:
+   nlmsg_free(skb);
+   return NULL;
+}
+
+static void hswim_mcast_new_radio(int id, struct genl_info *info,
+ struct hwsim_new_radio_params *param)
+{
+   struct sk_buff *mcast_skb;
+
+   mcast_skb = build_radio_msg(HWSIM_CMD_NEW_RADIO, id, param);
+   if (!mcast_skb)
+   return;
+
+

Re: [PATCH] mac80211-hwsim: add frequency attribute to netlink pkts

2014-10-31 Thread Jukka Rissanen
Hi Johannes,

On pe, 2014-10-31 at 09:04 +0100, Johannes Berg wrote:
> On Fri, 2014-10-31 at 10:02 +0200, Jukka Rissanen wrote:
> 
> > while rebasing my hwsim patches on top of Ben's patches, I noticed that
> > the freq attribute is not mentioned in hwsim_genl_policy struct. The
> > same applies also to radio name and vif attributes. Just wondered should
> > they be mentioned in the policy struct like the other attributes?
> 
> Hmm, yes, they should be there. It's only important for the name, I
> guess, but better have them all. I can fix it or would you like to send
> a patch?

Please fix it so it gets applied faster :)


Cheers,
Jukka


--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] mac80211-hwsim: add frequency attribute to netlink pkts

2014-10-31 Thread Jukka Rissanen
Hi Ben & Johannes,

while rebasing my hwsim patches on top of Ben's patches, I noticed that
the freq attribute is not mentioned in hwsim_genl_policy struct. The
same applies also to radio name and vif attributes. Just wondered should
they be mentioned in the policy struct like the other attributes?


On ma, 2014-10-27 at 15:04 -0700, gree...@candelatech.com wrote:
> From: Ben Greear 
> 
> Add frequency attribute when sending to user-space over
> netlink socket.  The frequency is currently ignored when
> receiving from user-space.
> 
> Signed-off-by: Ben Greear 
> ---
>  drivers/net/wireless/mac80211_hwsim.c | 7 +++
>  drivers/net/wireless/mac80211_hwsim.h | 4 +++-
>  2 files changed, 10 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/wireless/mac80211_hwsim.c 
> b/drivers/net/wireless/mac80211_hwsim.c
> index 270f8cd..b40435c 100644
> --- a/drivers/net/wireless/mac80211_hwsim.c
> +++ b/drivers/net/wireless/mac80211_hwsim.c
> @@ -906,6 +906,9 @@ static void mac80211_hwsim_tx_frame_nl(struct 
> ieee80211_hw *hw,
>   if (nla_put_u32(skb, HWSIM_ATTR_FLAGS, hwsim_flags))
>   goto nla_put_failure;
>  
> + if (nla_put_u32(skb, HWSIM_ATTR_FREQ, data->channel->center_freq))
> + goto nla_put_failure;
> +
>   /* We get the tx control (rate and retries) info*/
>  
>   for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
> @@ -2421,6 +2424,7 @@ static int hwsim_cloned_frame_received_nl(struct 
> sk_buff *skb_2,
>   int frame_data_len;
>   void *frame_data;
>   struct sk_buff *skb = NULL;
> + u32 freq;
>  
>   if (info->snd_portid != wmediumd_portid) {
>   printk(KERN_DEBUG "mac80211-hwsim: port-id mismatch: %d %d\n",
> @@ -2468,6 +2472,9 @@ static int hwsim_cloned_frame_received_nl(struct 
> sk_buff *skb_2,
>  
>   /* A frame is received from user space */
>   memset(&rx_status, 0, sizeof(rx_status));
> + /* TODO: Check ATTR_FREQ if it exists, and maybe throw away off-channel
> +  * packets?
> +  */
>   rx_status.freq = data2->channel->center_freq;
>   rx_status.band = data2->channel->band;
>   rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]);
> diff --git a/drivers/net/wireless/mac80211_hwsim.h 
> b/drivers/net/wireless/mac80211_hwsim.h
> index e614a20..85da35a 100644
> --- a/drivers/net/wireless/mac80211_hwsim.h
> +++ b/drivers/net/wireless/mac80211_hwsim.h
> @@ -60,7 +60,7 @@ enum hwsim_tx_control_flags {
>   * space, uses:
>   *   %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_ADDR_RECEIVER,
>   *   %HWSIM_ATTR_FRAME, %HWSIM_ATTR_FLAGS, %HWSIM_ATTR_RX_RATE,
> - *   %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE
> + *   %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE, %HWSIM_ATTR_FREQ (optional)
>   * @HWSIM_CMD_TX_INFO_FRAME: Transmission info report from user space to
>   * kernel, uses:
>   *   %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_FLAGS,
> @@ -113,6 +113,7 @@ enum {
>   *   single channel is supported
>   * @HWSIM_ATTR_RADIO_NAME: Name of radio, e.g. phy666
>   * @HWSIM_ATTR_NO_VIF:  Do not create vif (wlanX) when creating radio.
> + * @HWSIM_ATTR_FREQ: Frequency at which packet is transmitted or received.
>   * @__HWSIM_ATTR_MAX: enum limit
>   */
>  
> @@ -137,6 +138,7 @@ enum {
>   HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE,
>   HWSIM_ATTR_RADIO_NAME,
>   HWSIM_ATTR_NO_VIF,
> + HWSIM_ATTR_FREQ,
>   __HWSIM_ATTR_MAX,
>  };
>  #define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1)


Cheers,
Jukka



--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 0/2] Add mcast event when hwsim radios are created and removed

2014-10-30 Thread Jukka Rissanen
Hi,

v2:
- removed old patch 1 as that is already applied
- added suitable prefixes to new function names
- refactored the patch 1 so that multicast message building is
  separated into a more generic function
- instead of passing radio parameters (6 pcs) into different functions
  separately, a struct is used instead

v1:
patch 1 renames HWSIM_CMD_CREATE_RADIO to HWSIM_CMD_NEW_RADIO and
HWSIM_CMD_DESTROY_RADIO to HWSIM_CMD_DEL_RADIO. They are more
fitting on how other pieces of the wireless system work. A define
to old name is provided for backward compatibility.

Patches 2 and 3 use the newly named enums and provide a way to inform
the listeners on the multicast group "config" when new radio is created
and existing radio is deleted.


Jukka Rissanen (2):
  mac80211-hwsim: Provide multicast event for HWSIM_CMD_NEW_RADIO
  mac80211-hwsim: Provide multicast event for HWSIM_CMD_DEL_RADIO

 drivers/net/wireless/mac80211_hwsim.c | 285 ++
 1 file changed, 216 insertions(+), 69 deletions(-)

-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 2/2] mac80211-hwsim: Provide multicast event for HWSIM_CMD_DEL_RADIO

2014-10-30 Thread Jukka Rissanen
When deleting old radio via HWSIM_CMD_DEL_RADIO then listeners on the
multicast group "config" are informed.

Signed-off-by: Jukka Rissanen 
---
 drivers/net/wireless/mac80211_hwsim.c | 43 ++-
 1 file changed, 37 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c 
b/drivers/net/wireless/mac80211_hwsim.c
index ff187fe..909777c 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -2305,8 +2305,39 @@ failed:
return err;
 }
 
-static void mac80211_hwsim_destroy_radio(struct mac80211_hwsim_data *data)
+static void hwsim_mcast_del_radio(int id, struct genl_info *info)
 {
+   struct sk_buff *mcast_skb;
+   void *data;
+   int ret;
+
+   mcast_skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
+   if (!mcast_skb)
+   return;
+
+   data = genlmsg_put(mcast_skb, 0, 0, &hwsim_genl_family, 0,
+  HWSIM_CMD_DEL_RADIO);
+   if (!data)
+   goto error;
+
+   ret = nla_put_u32(mcast_skb, HWSIM_ATTR_RADIO_ID, id);
+   if (ret < 0)
+   goto error;
+
+   genlmsg_end(mcast_skb, data);
+
+   hwsim_mcast_config_msg(mcast_skb, info);
+
+   return;
+
+error:
+   nlmsg_free(mcast_skb);
+}
+
+static void mac80211_hwsim_del_radio(struct mac80211_hwsim_data *data,
+struct genl_info *info)
+{
+   hwsim_mcast_del_radio(data->idx, info);
debugfs_remove_recursive(data->debugfs);
ieee80211_unregister_hw(data->hw);
device_release_driver(data->dev);
@@ -2324,7 +2355,7 @@ static void mac80211_hwsim_free(void)
list))) {
list_del(&data->list);
spin_unlock_bh(&hwsim_radio_lock);
-   mac80211_hwsim_destroy_radio(data);
+   mac80211_hwsim_del_radio(data, NULL);
spin_lock_bh(&hwsim_radio_lock);
}
spin_unlock_bh(&hwsim_radio_lock);
@@ -2573,7 +2604,7 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct 
genl_info *info)
return mac80211_hwsim_new_radio(info, ¶m);
 }
 
-static int hwsim_destroy_radio_nl(struct sk_buff *msg, struct genl_info *info)
+static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info)
 {
struct mac80211_hwsim_data *data;
int idx;
@@ -2588,7 +2619,7 @@ static int hwsim_destroy_radio_nl(struct sk_buff *msg, 
struct genl_info *info)
continue;
list_del(&data->list);
spin_unlock_bh(&hwsim_radio_lock);
-   mac80211_hwsim_destroy_radio(data);
+   mac80211_hwsim_del_radio(data, info);
return 0;
}
spin_unlock_bh(&hwsim_radio_lock);
@@ -2621,9 +2652,9 @@ static const struct genl_ops hwsim_ops[] = {
.flags = GENL_ADMIN_PERM,
},
{
-   .cmd = HWSIM_CMD_DESTROY_RADIO,
+   .cmd = HWSIM_CMD_DEL_RADIO,
.policy = hwsim_genl_policy,
-   .doit = hwsim_destroy_radio_nl,
+   .doit = hwsim_del_radio_nl,
.flags = GENL_ADMIN_PERM,
},
 };
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 1/2] mac80211-hwsim: Provide multicast event for HWSIM_CMD_NEW_RADIO

2014-10-30 Thread Jukka Rissanen
When adding new radio via HWSIM_CMD_NEW_RADIO then listeners on the
multicast group "config" are informed.

Signed-off-by: Jukka Rissanen 
---
 drivers/net/wireless/mac80211_hwsim.c | 242 +-
 1 file changed, 179 insertions(+), 63 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c 
b/drivers/net/wireless/mac80211_hwsim.c
index babbdc1..ff187fe 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -476,6 +476,14 @@ static struct genl_family hwsim_genl_family = {
.maxattr = HWSIM_ATTR_MAX,
 };
 
+enum hwsim_multicast_groups {
+   HWSIM_MCGRP_CONFIG,
+};
+
+static const struct genl_multicast_group hwsim_mcgrps[] = {
+   [HWSIM_MCGRP_CONFIG] = { .name = "config", },
+};
+
 /* MAC80211_HWSIM netlink policy */
 
 static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = {
@@ -1943,10 +1951,114 @@ static const struct ieee80211_ops mac80211_hwsim_ops = 
{
 
 static struct ieee80211_ops mac80211_hwsim_mchan_ops;
 
-static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
-  const struct ieee80211_regdomain *regd,
-  bool reg_strict, bool p2p_device,
-  bool use_chanctx)
+struct hwsim_new_radio_params {
+   unsigned int channels;
+   const char *reg_alpha2;
+   const struct ieee80211_regdomain *regd;
+   bool reg_strict;
+   bool p2p_device;
+   bool use_chanctx;
+};
+
+static void hwsim_mcast_config_msg(struct sk_buff *mcast_skb,
+  struct genl_info *info)
+{
+   if (info)
+   genl_notify(&hwsim_genl_family, mcast_skb,
+   genl_info_net(info), info->snd_portid,
+   HWSIM_MCGRP_CONFIG, info->nlhdr, GFP_KERNEL);
+   else
+   genlmsg_multicast(&hwsim_genl_family, mcast_skb, 0,
+ HWSIM_MCGRP_CONFIG, GFP_KERNEL);
+}
+
+static struct sk_buff *build_radio_msg(int cmd, int id,
+  struct hwsim_new_radio_params *param)
+{
+   struct sk_buff *skb;
+   void *data;
+   int ret;
+
+   skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
+   if (!skb)
+   return NULL;
+
+   data = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, cmd);
+   if (!data)
+   goto error;
+
+   ret = nla_put_u32(skb, HWSIM_ATTR_RADIO_ID, id);
+   if (ret < 0)
+   goto error;
+
+   if (param->channels) {
+   ret = nla_put_u32(skb, HWSIM_ATTR_CHANNELS, param->channels);
+   if (ret < 0)
+   goto error;
+   }
+
+   if (param->reg_alpha2) {
+   ret = nla_put(skb, HWSIM_ATTR_REG_HINT_ALPHA2, 2,
+ param->reg_alpha2);
+   if (ret < 0)
+   goto error;
+   }
+
+   if (param->regd) {
+   int i;
+
+   for (i = 0; hwsim_world_regdom_custom[i] != param->regd &&
+i < ARRAY_SIZE(hwsim_world_regdom_custom); i++)
+   ;
+
+   if (i < ARRAY_SIZE(hwsim_world_regdom_custom)) {
+   ret = nla_put_u32(skb, HWSIM_ATTR_REG_CUSTOM_REG, i);
+   if (ret < 0)
+   goto error;
+   }
+   }
+
+   if (param->reg_strict) {
+   ret = nla_put_flag(skb, HWSIM_ATTR_REG_STRICT_REG);
+   if (ret < 0)
+   goto error;
+   }
+
+   if (param->p2p_device) {
+   ret = nla_put_flag(skb, HWSIM_ATTR_SUPPORT_P2P_DEVICE);
+   if (ret < 0)
+   goto error;
+   }
+
+   if (param->use_chanctx) {
+   ret = nla_put_flag(skb, HWSIM_ATTR_USE_CHANCTX);
+   if (ret < 0)
+   goto error;
+   }
+
+   genlmsg_end(skb, data);
+
+   return skb;
+
+error:
+   nlmsg_free(skb);
+   return NULL;
+}
+
+static void hswim_mcast_new_radio(int id, struct genl_info *info,
+ struct hwsim_new_radio_params *param)
+{
+   struct sk_buff *mcast_skb;
+
+   mcast_skb = build_radio_msg(HWSIM_CMD_NEW_RADIO, id, param);
+   if (!mcast_skb)
+   return;
+
+   hwsim_mcast_config_msg(mcast_skb, info);
+}
+
+static int mac80211_hwsim_new_radio(struct genl_info *info,
+   struct hwsim_new_radio_params *param)
 {
int err;
u8 addr[ETH_ALEN];
@@ -1956,14 +2068,14 @@ static int mac80211_hwsim_create_radio(int channels, 
const char *reg_alpha2,
const struct ieee80211_ops *ops = &mac80211_hwsim_ops;
int idx;
 
-   if (WARN_ON(channels > 1 &&

Re: [PATCH 2/3] mac80211-hwsim: Provide multicast event for HWSIM_CMD_NEW_RADIO

2014-10-30 Thread Jukka Rissanen
Hi Johannes,

On ke, 2014-10-29 at 16:53 +0100, Johannes Berg wrote:
> On Wed, 2014-10-29 at 16:50 +0100, Johannes Berg wrote:
> > On Mon, 2014-10-27 at 12:44 +0200, Jukka Rissanen wrote:
> > 
> > > +static void mcast_msg(struct sk_buff *mcast_skb, struct genl_info *info)
> > > +{
> > > + if (info)
> > > + genl_notify(&hwsim_genl_family, mcast_skb,
> > > + genl_info_net(info), info->snd_portid,
> > > + HWSIM_MCGRP_CONFIG, info->nlhdr, GFP_KERNEL);
> > > + else
> > > + genlmsg_multicast(&hwsim_genl_family, mcast_skb, 0,
> > > +   HWSIM_MCGRP_CONFIG, GFP_KERNEL);
> > > +}
> > 
> > Also - given the parameters and what this does, that's a bad name for
> > the function. Never mind that it doesn't have any sort of identifier
> > (say hwsim_ prefix), it doesn't even do what it says it does.
> 
> Or maybe it does? I'm unsure what genl_notify() does...

Yes, genl_notify() will eventually call nlmsg_notify() which will
multicast the message because we have set the group id in the call.

http://lxr.free-electrons.com/source/net/netlink/af_netlink.c#L2856


Cheers,
Jukka


--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 0/3] Add mcast event when hwsim radios are created and removed

2014-10-27 Thread Jukka Rissanen
On ma, 2014-10-27 at 12:31 +0100, Johannes Berg wrote:
> On Mon, 2014-10-27 at 13:29 +0200, Jukka Rissanen wrote:
> 
> > Yes, but from generic nl80211 event you cannot know if event is from
> > hwsim radio or not. With this patch, the listener can know that the
> > radio new/del event is specifically related to hwsim radio.
> 
> That's not particularly hard to figure out, for example by looking at
> sysfs.
> 
> Is this really so time-constrained/important/... that you can't do that?

It does not seem very practical to dig this information from sysfs as
the same information can be easily get via netlink as this patch shows.


Cheers,
Jukka


--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 0/3] Add mcast event when hwsim radios are created and removed

2014-10-27 Thread Jukka Rissanen
Hi Johannes,

On ma, 2014-10-27 at 12:20 +0100, Johannes Berg wrote:
> On Mon, 2014-10-27 at 12:44 +0200, Jukka Rissanen wrote:
> > Hi,
> > 
> > patch 1 renames HWSIM_CMD_CREATE_RADIO to HWSIM_CMD_NEW_RADIO and
> > HWSIM_CMD_DESTROY_RADIO to HWSIM_CMD_DEL_RADIO. They are more
> > fitting on how other pieces of the wireless system work. A define
> > to old name is provided for backward compatibility.
> 
> That seems reasonable, if a little gratuitous.
> 
> > Patches 2 and 3 use the newly named enums and provide a way to inform
> > the listeners on the multicast group "config" when new radio is created
> > and existing radio is deleted.
> 
> Why bother? There are nl80211 events for this already, no?

Yes, but from generic nl80211 event you cannot know if event is from
hwsim radio or not. With this patch, the listener can know that the
radio new/del event is specifically related to hwsim radio.


Cheers,
Jukka


--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 2/3] mac80211-hwsim: Provide multicast event for HWSIM_CMD_NEW_RADIO

2014-10-27 Thread Jukka Rissanen
When adding new radio via HWSIM_CMD_NEW_RADIO then listeners on the
multicast group "config" are informed.

Signed-off-by: Jukka Rissanen 
---
 drivers/net/wireless/mac80211_hwsim.c | 141 +-
 1 file changed, 123 insertions(+), 18 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c 
b/drivers/net/wireless/mac80211_hwsim.c
index babbdc1..74bc1db 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -476,6 +476,14 @@ static struct genl_family hwsim_genl_family = {
.maxattr = HWSIM_ATTR_MAX,
 };
 
+enum hwsim_multicast_groups {
+   HWSIM_MCGRP_CONFIG,
+};
+
+static const struct genl_multicast_group hwsim_mcgrps[] = {
+   [HWSIM_MCGRP_CONFIG] = { .name = "config", },
+};
+
 /* MAC80211_HWSIM netlink policy */
 
 static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = {
@@ -1943,10 +1951,101 @@ static const struct ieee80211_ops mac80211_hwsim_ops = 
{
 
 static struct ieee80211_ops mac80211_hwsim_mchan_ops;
 
-static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
-  const struct ieee80211_regdomain *regd,
-  bool reg_strict, bool p2p_device,
-  bool use_chanctx)
+static void mcast_msg(struct sk_buff *mcast_skb, struct genl_info *info)
+{
+   if (info)
+   genl_notify(&hwsim_genl_family, mcast_skb,
+   genl_info_net(info), info->snd_portid,
+   HWSIM_MCGRP_CONFIG, info->nlhdr, GFP_KERNEL);
+   else
+   genlmsg_multicast(&hwsim_genl_family, mcast_skb, 0,
+ HWSIM_MCGRP_CONFIG, GFP_KERNEL);
+}
+
+static void mcast_new_radio(int id, struct genl_info *info,
+   int channels, const char *reg_alpha2,
+   const struct ieee80211_regdomain *regd,
+   bool reg_strict, bool p2p_device,
+   bool use_chanctx)
+{
+   struct sk_buff *mcast_skb;
+   void *data;
+   int ret;
+
+   mcast_skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
+   if (!mcast_skb)
+   return;
+
+   data = genlmsg_put(mcast_skb, 0, 0, &hwsim_genl_family, 0,
+  HWSIM_CMD_NEW_RADIO);
+   if (!data)
+   goto error;
+
+   ret = nla_put_u32(mcast_skb, HWSIM_ATTR_RADIO_ID, id);
+   if (ret < 0)
+   goto error;
+
+   if (channels) {
+   ret = nla_put_u32(mcast_skb, HWSIM_ATTR_CHANNELS, channels);
+   if (ret < 0)
+   goto error;
+   }
+
+   if (reg_alpha2) {
+   ret = nla_put(mcast_skb, HWSIM_ATTR_REG_HINT_ALPHA2, 2,
+ reg_alpha2);
+   if (ret < 0)
+   goto error;
+   }
+
+   if (regd) {
+   int i;
+
+   for (i = 0; hwsim_world_regdom_custom[i] != regd &&
+i < ARRAY_SIZE(hwsim_world_regdom_custom); i++)
+   ;
+
+   if (i < ARRAY_SIZE(hwsim_world_regdom_custom)) {
+   ret = nla_put_u32(mcast_skb, HWSIM_ATTR_REG_CUSTOM_REG,
+ i);
+   if (ret < 0)
+   goto error;
+   }
+   }
+
+   if (reg_strict) {
+   ret = nla_put_flag(mcast_skb, HWSIM_ATTR_REG_STRICT_REG);
+   if (ret < 0)
+   goto error;
+   }
+
+   if (p2p_device) {
+   ret = nla_put_flag(mcast_skb, HWSIM_ATTR_SUPPORT_P2P_DEVICE);
+   if (ret < 0)
+   goto error;
+   }
+
+   if (use_chanctx) {
+   ret = nla_put_flag(mcast_skb, HWSIM_ATTR_USE_CHANCTX);
+   if (ret < 0)
+   goto error;
+   }
+
+   genlmsg_end(mcast_skb, data);
+
+   mcast_msg(mcast_skb, info);
+
+   return;
+
+error:
+   nlmsg_free(mcast_skb);
+}
+
+static int mac80211_hwsim_new_radio(struct genl_info *info,
+   int channels, const char *reg_alpha2,
+   const struct ieee80211_regdomain *regd,
+   bool reg_strict, bool p2p_device,
+   bool use_chanctx)
 {
int err;
u8 addr[ETH_ALEN];
@@ -2180,6 +2279,10 @@ static int mac80211_hwsim_create_radio(int channels, 
const char *reg_alpha2,
list_add_tail(&data->list, &hwsim_radios);
spin_unlock_bh(&hwsim_radio_lock);
 
+   if (idx > 0)
+   mcast_new_radio(idx, info, channels, reg_alpha2,
+   regd, reg_strict, p2p_device, use_chanctx);
+
return idx;
 
 fa

[PATCH 1/3] mac80211-hwsim: Rename CREATE and DESTROY radio to NEW and DEL radio

2014-10-27 Thread Jukka Rissanen
Using the name HWSIM_CMD_NEW_RADIO and HWSIM_CMD_DEL_RADIO is more
fitting on how other pieces of the wireless system work.

Signed-off-by: Jukka Rissanen 
---
 drivers/net/wireless/mac80211_hwsim.h | 14 +-
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.h 
b/drivers/net/wireless/mac80211_hwsim.h
index c9d0315..1f4f790 100644
--- a/drivers/net/wireless/mac80211_hwsim.h
+++ b/drivers/net/wireless/mac80211_hwsim.h
@@ -65,9 +65,10 @@ enum hwsim_tx_control_flags {
  * kernel, uses:
  * %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_FLAGS,
  * %HWSIM_ATTR_TX_INFO, %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE
- * @HWSIM_CMD_CREATE_RADIO: create a new radio with the given parameters,
- * returns the radio ID (>= 0) or negative on errors
- * @HWSIM_CMD_DESTROY_RADIO: destroy a radio
+ * @HWSIM_CMD_NEW_RADIO: create a new radio with the given parameters,
+ * returns the radio ID (>= 0) or negative on errors, if successful
+ * then multicast the result
+ * @HWSIM_CMD_DEL_RADIO: destroy a radio, reply is multicasted
  * @__HWSIM_CMD_MAX: enum limit
  */
 enum {
@@ -75,12 +76,15 @@ enum {
HWSIM_CMD_REGISTER,
HWSIM_CMD_FRAME,
HWSIM_CMD_TX_INFO_FRAME,
-   HWSIM_CMD_CREATE_RADIO,
-   HWSIM_CMD_DESTROY_RADIO,
+   HWSIM_CMD_NEW_RADIO,
+   HWSIM_CMD_DEL_RADIO,
__HWSIM_CMD_MAX,
 };
 #define HWSIM_CMD_MAX (_HWSIM_CMD_MAX - 1)
 
+#define HWSIM_CMD_CREATE_RADIO   HWSIM_CMD_NEW_RADIO
+#define HWSIM_CMD_DESTROY_RADIO  HWSIM_CMD_DEL_RADIO
+
 /**
  * enum hwsim_attrs - hwsim netlink attributes
  *
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 3/3] mac80211-hwsim: Provide multicast event for HWSIM_CMD_DEL_RADIO

2014-10-27 Thread Jukka Rissanen
When deleting old radio via HWSIM_CMD_DEL_RADIO then listeners on the
multicast group "config" are informed.

Signed-off-by: Jukka Rissanen 
---
 drivers/net/wireless/mac80211_hwsim.c | 43 ++-
 1 file changed, 37 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c 
b/drivers/net/wireless/mac80211_hwsim.c
index 74bc1db..b50a739 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -2293,8 +2293,39 @@ failed:
return err;
 }
 
-static void mac80211_hwsim_destroy_radio(struct mac80211_hwsim_data *data)
+static void mcast_del_radio(int id, struct genl_info *info)
 {
+   struct sk_buff *mcast_skb;
+   void *data;
+   int ret;
+
+   mcast_skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
+   if (!mcast_skb)
+   return;
+
+   data = genlmsg_put(mcast_skb, 0, 0, &hwsim_genl_family, 0,
+  HWSIM_CMD_DEL_RADIO);
+   if (!data)
+   goto error;
+
+   ret = nla_put_u32(mcast_skb, HWSIM_ATTR_RADIO_ID, id);
+   if (ret < 0)
+   goto error;
+
+   genlmsg_end(mcast_skb, data);
+
+   mcast_msg(mcast_skb, info);
+
+   return;
+
+error:
+   nlmsg_free(mcast_skb);
+}
+
+static void mac80211_hwsim_del_radio(struct mac80211_hwsim_data *data,
+struct genl_info *info)
+{
+   mcast_del_radio(data->idx, info);
debugfs_remove_recursive(data->debugfs);
ieee80211_unregister_hw(data->hw);
device_release_driver(data->dev);
@@ -2312,7 +2343,7 @@ static void mac80211_hwsim_free(void)
list))) {
list_del(&data->list);
spin_unlock_bh(&hwsim_radio_lock);
-   mac80211_hwsim_destroy_radio(data);
+   mac80211_hwsim_del_radio(data, NULL);
spin_lock_bh(&hwsim_radio_lock);
}
spin_unlock_bh(&hwsim_radio_lock);
@@ -2562,7 +2593,7 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct 
genl_info *info)
p2p_device, use_chanctx);
 }
 
-static int hwsim_destroy_radio_nl(struct sk_buff *msg, struct genl_info *info)
+static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info)
 {
struct mac80211_hwsim_data *data;
int idx;
@@ -2577,7 +2608,7 @@ static int hwsim_destroy_radio_nl(struct sk_buff *msg, 
struct genl_info *info)
continue;
list_del(&data->list);
spin_unlock_bh(&hwsim_radio_lock);
-   mac80211_hwsim_destroy_radio(data);
+   mac80211_hwsim_del_radio(data, info);
return 0;
}
spin_unlock_bh(&hwsim_radio_lock);
@@ -2610,9 +2641,9 @@ static const struct genl_ops hwsim_ops[] = {
.flags = GENL_ADMIN_PERM,
},
{
-   .cmd = HWSIM_CMD_DESTROY_RADIO,
+   .cmd = HWSIM_CMD_DEL_RADIO,
.policy = hwsim_genl_policy,
-   .doit = hwsim_destroy_radio_nl,
+   .doit = hwsim_del_radio_nl,
.flags = GENL_ADMIN_PERM,
},
 };
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 0/3] Add mcast event when hwsim radios are created and removed

2014-10-27 Thread Jukka Rissanen
Hi,

patch 1 renames HWSIM_CMD_CREATE_RADIO to HWSIM_CMD_NEW_RADIO and
HWSIM_CMD_DESTROY_RADIO to HWSIM_CMD_DEL_RADIO. They are more
fitting on how other pieces of the wireless system work. A define
to old name is provided for backward compatibility.

Patches 2 and 3 use the newly named enums and provide a way to inform
the listeners on the multicast group "config" when new radio is created
and existing radio is deleted.


Cheers,
Jukka


Jukka Rissanen (3):
  mac80211-hwsim: Rename CREATE and DESTROY radio to NEW and DEL radio
  mac80211-hwsim: Provide multicast event for HWSIM_CMD_NEW_RADIO
  mac80211-hwsim: Provide multicast event for HWSIM_CMD_DEL_RADIO

 drivers/net/wireless/mac80211_hwsim.c | 184 +-
 drivers/net/wireless/mac80211_hwsim.h |  14 ++-
 2 files changed, 169 insertions(+), 29 deletions(-)

-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2] mac80211-hwsim: Add support for HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE

2014-10-09 Thread Jukka Rissanen
Add support for new attribute HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE
which can be set by the user space component. The attribute
will cause the kernel to destroy all those radios that were
created by a process if that process dies. The old behaviour
i.e., radios are persistent is still the default.

Signed-off-by: Jukka Rissanen 
---
Hi,

v2:
- embed the work_struct into mac80211_hwsim_data which makes
  the code simpler

Cheers,
Jukka

 drivers/net/wireless/mac80211_hwsim.c | 40 ---
 drivers/net/wireless/mac80211_hwsim.h |  3 +++
 2 files changed, 40 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c 
b/drivers/net/wireless/mac80211_hwsim.c
index babbdc1..e95ae0a 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -412,6 +412,9 @@ struct mac80211_hwsim_data {
struct mac_address addresses[2];
int channels, idx;
bool use_chanctx;
+   bool destroy_on_close;
+   struct work_struct destroy_work;
+   u32 portid;
 
struct ieee80211_channel *tmp_chan;
struct delayed_work roc_done;
@@ -496,6 +499,7 @@ static const struct nla_policy 
hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = {
[HWSIM_ATTR_REG_CUSTOM_REG] = { .type = NLA_U32 },
[HWSIM_ATTR_REG_STRICT_REG] = { .type = NLA_FLAG },
[HWSIM_ATTR_SUPPORT_P2P_DEVICE] = { .type = NLA_FLAG },
+   [HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE] = { .type = NLA_FLAG },
 };
 
 static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
@@ -1946,7 +1950,8 @@ static struct ieee80211_ops mac80211_hwsim_mchan_ops;
 static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
   const struct ieee80211_regdomain *regd,
   bool reg_strict, bool p2p_device,
-  bool use_chanctx)
+  bool use_chanctx, bool destroy_on_close,
+  u32 portid)
 {
int err;
u8 addr[ETH_ALEN];
@@ -2006,6 +2011,8 @@ static int mac80211_hwsim_create_radio(int channels, 
const char *reg_alpha2,
data->channels = channels;
data->use_chanctx = use_chanctx;
data->idx = idx;
+   data->destroy_on_close = destroy_on_close;
+   data->portid = portid;
 
if (data->use_chanctx) {
hw->wiphy->max_scan_ssids = 255;
@@ -2434,6 +2441,7 @@ static int hwsim_create_radio_nl(struct sk_buff *msg, 
struct genl_info *info)
const struct ieee80211_regdomain *regd = NULL;
bool reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG];
bool p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE];
+   bool destroy_on_close = info->attrs[HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE];
bool use_chanctx;
 
if (info->attrs[HWSIM_ATTR_CHANNELS])
@@ -2456,7 +2464,8 @@ static int hwsim_create_radio_nl(struct sk_buff *msg, 
struct genl_info *info)
}
 
return mac80211_hwsim_create_radio(chans, alpha2, regd, reg_strict,
-  p2p_device, use_chanctx);
+  p2p_device, use_chanctx,
+  destroy_on_close, info->snd_portid);
 }
 
 static int hwsim_destroy_radio_nl(struct sk_buff *msg, struct genl_info *info)
@@ -2514,6 +2523,29 @@ static const struct genl_ops hwsim_ops[] = {
},
 };
 
+static void destroy_radio(struct work_struct *work)
+{
+   struct mac80211_hwsim_data *data =
+   container_of(work, struct mac80211_hwsim_data, destroy_work);
+
+   mac80211_hwsim_destroy_radio(data);
+}
+
+static void remove_user_radios(u32 portid)
+{
+   struct mac80211_hwsim_data *entry, *tmp;
+
+   spin_lock_bh(&hwsim_radio_lock);
+   list_for_each_entry_safe(entry, tmp, &hwsim_radios, list) {
+   if (entry->destroy_on_close && entry->portid == portid) {
+   list_del(&entry->list);
+   INIT_WORK(&entry->destroy_work, destroy_radio);
+   schedule_work(&entry->destroy_work);
+   }
+   }
+   spin_unlock_bh(&hwsim_radio_lock);
+}
+
 static int mac80211_hwsim_netlink_notify(struct notifier_block *nb,
 unsigned long state,
 void *_notify)
@@ -2523,6 +2555,8 @@ static int mac80211_hwsim_netlink_notify(struct 
notifier_block *nb,
if (state != NETLINK_URELEASE)
return NOTIFY_DONE;
 
+   remove_user_radios(notify->portid);
+
if (notify->portid == wmediumd_portid) {
printk(KERN_INFO "mac80211_hwsim: wmediumd released netlink"
   " socket, switching to perfect channel medium\n");
@@ -2676,7 +2710,7 @@ st

[PATCH] mac80211-hwsim: Add support for HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE

2014-10-09 Thread Jukka Rissanen
Add support for new attribute HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE
which can be set by the user space component. The attribute
will cause the kernel to destroy all those radios that were
created by a process if that process dies. The old behaviour
i.e., radios are persistent is still the default.

Signed-off-by: Jukka Rissanen 
---
 drivers/net/wireless/mac80211_hwsim.c | 52 +--
 drivers/net/wireless/mac80211_hwsim.h |  3 ++
 2 files changed, 52 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c 
b/drivers/net/wireless/mac80211_hwsim.c
index babbdc1..2d27c12 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -412,6 +412,8 @@ struct mac80211_hwsim_data {
struct mac_address addresses[2];
int channels, idx;
bool use_chanctx;
+   bool destroy_on_close;
+   u32 portid;
 
struct ieee80211_channel *tmp_chan;
struct delayed_work roc_done;
@@ -496,6 +498,7 @@ static const struct nla_policy 
hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = {
[HWSIM_ATTR_REG_CUSTOM_REG] = { .type = NLA_U32 },
[HWSIM_ATTR_REG_STRICT_REG] = { .type = NLA_FLAG },
[HWSIM_ATTR_SUPPORT_P2P_DEVICE] = { .type = NLA_FLAG },
+   [HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE] = { .type = NLA_FLAG },
 };
 
 static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
@@ -1946,7 +1949,8 @@ static struct ieee80211_ops mac80211_hwsim_mchan_ops;
 static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
   const struct ieee80211_regdomain *regd,
   bool reg_strict, bool p2p_device,
-  bool use_chanctx)
+  bool use_chanctx, bool destroy_on_close,
+  u32 portid)
 {
int err;
u8 addr[ETH_ALEN];
@@ -2006,6 +2010,8 @@ static int mac80211_hwsim_create_radio(int channels, 
const char *reg_alpha2,
data->channels = channels;
data->use_chanctx = use_chanctx;
data->idx = idx;
+   data->destroy_on_close = destroy_on_close;
+   data->portid = portid;
 
if (data->use_chanctx) {
hw->wiphy->max_scan_ssids = 255;
@@ -2434,6 +2440,7 @@ static int hwsim_create_radio_nl(struct sk_buff *msg, 
struct genl_info *info)
const struct ieee80211_regdomain *regd = NULL;
bool reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG];
bool p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE];
+   bool destroy_on_close = info->attrs[HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE];
bool use_chanctx;
 
if (info->attrs[HWSIM_ATTR_CHANNELS])
@@ -2456,7 +2463,8 @@ static int hwsim_create_radio_nl(struct sk_buff *msg, 
struct genl_info *info)
}
 
return mac80211_hwsim_create_radio(chans, alpha2, regd, reg_strict,
-  p2p_device, use_chanctx);
+  p2p_device, use_chanctx,
+  destroy_on_close, info->snd_portid);
 }
 
 static int hwsim_destroy_radio_nl(struct sk_buff *msg, struct genl_info *info)
@@ -2514,6 +2522,42 @@ static const struct genl_ops hwsim_ops[] = {
},
 };
 
+struct urelease_work {
+   struct work_struct w;
+   u32 portid;
+};
+
+static void urelease_event_work(struct work_struct *work)
+{
+   struct urelease_work *w = container_of(work, struct urelease_work, w);
+   struct mac80211_hwsim_data *entry, *tmp;
+
+   spin_lock_bh(&hwsim_radio_lock);
+   list_for_each_entry_safe(entry, tmp, &hwsim_radios, list) {
+   if (entry->destroy_on_close && w->portid == entry->portid) {
+   list_del(&entry->list);
+   spin_unlock_bh(&hwsim_radio_lock);
+   mac80211_hwsim_destroy_radio(entry);
+   spin_lock_bh(&hwsim_radio_lock);
+   }
+   }
+   spin_unlock_bh(&hwsim_radio_lock);
+
+   kfree(w);
+}
+
+static void remove_user_radios(u32 portid)
+{
+   struct urelease_work *w;
+
+   w = kmalloc(sizeof(*w), GFP_ATOMIC);
+   if (w) {
+   INIT_WORK((struct work_struct *)w, urelease_event_work);
+   w->portid = portid;
+   schedule_work((struct work_struct *)w);
+   }
+}
+
 static int mac80211_hwsim_netlink_notify(struct notifier_block *nb,
 unsigned long state,
 void *_notify)
@@ -2523,6 +2567,8 @@ static int mac80211_hwsim_netlink_notify(struct 
notifier_block *nb,
if (state != NETLINK_URELEASE)
return NOTIFY_DONE;
 
+   remove_user_radios(notify->portid);
+
if (notify->portid == wm