mac80211-hwsim: Add support for HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE
authorJukka Rissanen <jukka.rissanen@linux.intel.com>
Thu, 9 Oct 2014 12:27:51 +0000 (15:27 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Thu, 9 Oct 2014 14:13:01 +0000 (16:13 +0200)
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 <jukka.rissanen@linux.intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mac80211_hwsim.h

index f1a0794b33f3843fcf73d824b5869810b51bfe66..6ffe07323e6e98d53a5290b8aed753e4f1b8c888 100644 (file)
@@ -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,
@@ -1947,7 +1951,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];
@@ -2007,6 +2012,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 @@ 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;
        }
index c9d0315575bab27035378378d396a46db828bf4c..b96d8670a7030b7d0262a6da680658f6c44e36f7 100644 (file)
@@ -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)