2014-10-09 11:29:48

by Jukka Rissanen

[permalink] [raw]
Subject: [PATCH] mac80211-hwsim: Add support for HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE

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 <[email protected]>
---
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 == wmediumd_portid) {
printk(KERN_INFO "mac80211_hwsim: wmediumd released netlink"
" socket, switching to perfect channel medium\n");
@@ -2676,7 +2722,7 @@ static int __init init_mac80211_hwsim(void)
err = mac80211_hwsim_create_radio(channels, reg_alpha2,
regd, reg_strict,
support_p2p_device,
- channels > 1);
+ channels > 1, false, 0);
if (err < 0)
goto out_free_radios;
}
diff --git a/drivers/net/wireless/mac80211_hwsim.h b/drivers/net/wireless/mac80211_hwsim.h
index c9d0315..b96d867 100644
--- a/drivers/net/wireless/mac80211_hwsim.h
+++ b/drivers/net/wireless/mac80211_hwsim.h
@@ -111,6 +111,8 @@ enum {
* @HWSIM_ATTR_USE_CHANCTX: used with the %HWSIM_CMD_CREATE_RADIO
* command to force use of channel contexts even when only a
* single channel is supported
+ * @HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE: used with the %HWSIM_CMD_CREATE_RADIO
+ * command to force radio removal when process that created the radio dies
* @__HWSIM_ATTR_MAX: enum limit
*/

@@ -132,6 +134,7 @@ enum {
HWSIM_ATTR_REG_STRICT_REG,
HWSIM_ATTR_SUPPORT_P2P_DEVICE,
HWSIM_ATTR_USE_CHANCTX,
+ HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE,
__HWSIM_ATTR_MAX,
};
#define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1)
--
1.8.3.1



2014-10-09 11:34:33

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH] mac80211-hwsim: Add support for HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE

On Thu, 2014-10-09 at 14:29 +0300, Jukka Rissanen wrote:

> +struct urelease_work {
> + struct work_struct w;
> + u32 portid;
> +};

Wouldn't it be simpler to embed the work struct in the hwsim data, and
just queue that up when the device is affected? you should be able to
walk the list in the notifier, I'd think.

> +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);

That cast is currently correct, but still clearly the wrong thing to do.

> + w->portid = portid;
> + schedule_work((struct work_struct *)w);

ditto

johannes