|
@@ -412,6 +412,9 @@ struct mac80211_hwsim_data {
|
|
struct mac_address addresses[2];
|
|
struct mac_address addresses[2];
|
|
int channels, idx;
|
|
int channels, idx;
|
|
bool use_chanctx;
|
|
bool use_chanctx;
|
|
|
|
+ bool destroy_on_close;
|
|
|
|
+ struct work_struct destroy_work;
|
|
|
|
+ u32 portid;
|
|
|
|
|
|
struct ieee80211_channel *tmp_chan;
|
|
struct ieee80211_channel *tmp_chan;
|
|
struct delayed_work roc_done;
|
|
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_CUSTOM_REG] = { .type = NLA_U32 },
|
|
[HWSIM_ATTR_REG_STRICT_REG] = { .type = NLA_FLAG },
|
|
[HWSIM_ATTR_REG_STRICT_REG] = { .type = NLA_FLAG },
|
|
[HWSIM_ATTR_SUPPORT_P2P_DEVICE] = { .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,
|
|
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,
|
|
static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
|
|
const struct ieee80211_regdomain *regd,
|
|
const struct ieee80211_regdomain *regd,
|
|
bool reg_strict, bool p2p_device,
|
|
bool reg_strict, bool p2p_device,
|
|
- bool use_chanctx)
|
|
|
|
|
|
+ bool use_chanctx, bool destroy_on_close,
|
|
|
|
+ u32 portid)
|
|
{
|
|
{
|
|
int err;
|
|
int err;
|
|
u8 addr[ETH_ALEN];
|
|
u8 addr[ETH_ALEN];
|
|
@@ -2007,6 +2012,8 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
|
|
data->channels = channels;
|
|
data->channels = channels;
|
|
data->use_chanctx = use_chanctx;
|
|
data->use_chanctx = use_chanctx;
|
|
data->idx = idx;
|
|
data->idx = idx;
|
|
|
|
+ data->destroy_on_close = destroy_on_close;
|
|
|
|
+ data->portid = portid;
|
|
|
|
|
|
if (data->use_chanctx) {
|
|
if (data->use_chanctx) {
|
|
hw->wiphy->max_scan_ssids = 255;
|
|
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;
|
|
const struct ieee80211_regdomain *regd = NULL;
|
|
bool reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG];
|
|
bool reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG];
|
|
bool p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE];
|
|
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;
|
|
bool use_chanctx;
|
|
|
|
|
|
if (info->attrs[HWSIM_ATTR_CHANNELS])
|
|
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,
|
|
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)
|
|
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,
|
|
static int mac80211_hwsim_netlink_notify(struct notifier_block *nb,
|
|
unsigned long state,
|
|
unsigned long state,
|
|
void *_notify)
|
|
void *_notify)
|
|
@@ -2523,6 +2555,8 @@ static int mac80211_hwsim_netlink_notify(struct notifier_block *nb,
|
|
if (state != NETLINK_URELEASE)
|
|
if (state != NETLINK_URELEASE)
|
|
return NOTIFY_DONE;
|
|
return NOTIFY_DONE;
|
|
|
|
|
|
|
|
+ remove_user_radios(notify->portid);
|
|
|
|
+
|
|
if (notify->portid == wmediumd_portid) {
|
|
if (notify->portid == wmediumd_portid) {
|
|
printk(KERN_INFO "mac80211_hwsim: wmediumd released netlink"
|
|
printk(KERN_INFO "mac80211_hwsim: wmediumd released netlink"
|
|
" socket, switching to perfect channel medium\n");
|
|
" 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,
|
|
err = mac80211_hwsim_create_radio(channels, reg_alpha2,
|
|
regd, reg_strict,
|
|
regd, reg_strict,
|
|
support_p2p_device,
|
|
support_p2p_device,
|
|
- channels > 1);
|
|
|
|
|
|
+ channels > 1, false, 0);
|
|
if (err < 0)
|
|
if (err < 0)
|
|
goto out_free_radios;
|
|
goto out_free_radios;
|
|
}
|
|
}
|