mac80211_hwsim: allow creating/destroying radios on the fly
Add new commands to the hwsim generic netlink family to allow creating and destroying radios on the fly. The number of channels a radio supports can be specified when it's created, if it isn't the module parameter will be used as default. This should be extended in the future to allow other parameters to be specified, e.g. * list of channels * interface combinations, particularly P2P_DEVICE support * regtest * and pretty much all other hardware capabilities Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Родитель
c5ac08548b
Коммит
bc79109896
|
@ -273,7 +273,7 @@ struct mac80211_hwsim_data {
|
|||
struct ieee80211_iface_combination if_combination;
|
||||
|
||||
struct mac_address addresses[2];
|
||||
int channels;
|
||||
int channels, idx;
|
||||
|
||||
struct ieee80211_channel *tmp_chan;
|
||||
struct delayed_work roc_done;
|
||||
|
@ -352,6 +352,8 @@ static struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = {
|
|||
.len = IEEE80211_TX_MAX_RATES *
|
||||
sizeof(struct hwsim_tx_rate)},
|
||||
[HWSIM_ATTR_COOKIE] = { .type = NLA_U64 },
|
||||
[HWSIM_ATTR_CHANNELS] = { .type = NLA_U32 },
|
||||
[HWSIM_ATTR_RADIO_ID] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
|
||||
|
@ -1818,7 +1820,7 @@ static const struct ieee80211_ops mac80211_hwsim_ops = {
|
|||
|
||||
static struct ieee80211_ops mac80211_hwsim_mchan_ops;
|
||||
|
||||
static int __init mac80211_hwsim_create_radio(void)
|
||||
static int mac80211_hwsim_create_radio(int channels)
|
||||
{
|
||||
int err;
|
||||
u8 addr[ETH_ALEN];
|
||||
|
@ -1873,6 +1875,7 @@ static int __init mac80211_hwsim_create_radio(void)
|
|||
hw->wiphy->addresses = data->addresses;
|
||||
|
||||
data->channels = channels;
|
||||
data->idx = idx;
|
||||
|
||||
if (data->channels > 1) {
|
||||
hw->wiphy->max_scan_ssids = 255;
|
||||
|
@ -2023,7 +2026,7 @@ static int __init mac80211_hwsim_create_radio(void)
|
|||
list_add_tail(&data->list, &hwsim_radios);
|
||||
spin_unlock_bh(&hwsim_radio_lock);
|
||||
|
||||
return 0;
|
||||
return idx;
|
||||
|
||||
failed_hw:
|
||||
device_unregister(data->dev);
|
||||
|
@ -2270,6 +2273,39 @@ static int hwsim_register_received_nl(struct sk_buff *skb_2,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int hwsim_create_radio_nl(struct sk_buff *msg, struct genl_info *info)
|
||||
{
|
||||
unsigned int chans = channels;
|
||||
|
||||
if (info->attrs[HWSIM_ATTR_CHANNELS])
|
||||
chans = nla_get_u32(info->attrs[HWSIM_ATTR_CHANNELS]);
|
||||
|
||||
return mac80211_hwsim_create_radio(chans);
|
||||
}
|
||||
|
||||
static int hwsim_destroy_radio_nl(struct sk_buff *msg, struct genl_info *info)
|
||||
{
|
||||
struct mac80211_hwsim_data *data;
|
||||
int idx;
|
||||
|
||||
if (!info->attrs[HWSIM_ATTR_RADIO_ID])
|
||||
return -EINVAL;
|
||||
idx = nla_get_u32(info->attrs[HWSIM_ATTR_RADIO_ID]);
|
||||
|
||||
spin_lock_bh(&hwsim_radio_lock);
|
||||
list_for_each_entry(data, &hwsim_radios, list) {
|
||||
if (data->idx != idx)
|
||||
continue;
|
||||
list_del(&data->list);
|
||||
spin_unlock_bh(&hwsim_radio_lock);
|
||||
mac80211_hwsim_destroy_radio(data);
|
||||
return 0;
|
||||
}
|
||||
spin_unlock_bh(&hwsim_radio_lock);
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Generic Netlink operations array */
|
||||
static const struct genl_ops hwsim_ops[] = {
|
||||
{
|
||||
|
@ -2288,6 +2324,18 @@ static const struct genl_ops hwsim_ops[] = {
|
|||
.policy = hwsim_genl_policy,
|
||||
.doit = hwsim_tx_info_frame_received_nl,
|
||||
},
|
||||
{
|
||||
.cmd = HWSIM_CMD_CREATE_RADIO,
|
||||
.policy = hwsim_genl_policy,
|
||||
.doit = hwsim_create_radio_nl,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
{
|
||||
.cmd = HWSIM_CMD_DESTROY_RADIO,
|
||||
.policy = hwsim_genl_policy,
|
||||
.doit = hwsim_destroy_radio_nl,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
};
|
||||
|
||||
static int mac80211_hwsim_netlink_notify(struct notifier_block *nb,
|
||||
|
@ -2345,7 +2393,7 @@ static int __init init_mac80211_hwsim(void)
|
|||
{
|
||||
int i, err;
|
||||
|
||||
if (radios < 1 || radios > 100)
|
||||
if (radios < 0 || radios > 100)
|
||||
return -EINVAL;
|
||||
|
||||
if (channels < 1)
|
||||
|
@ -2380,8 +2428,8 @@ static int __init init_mac80211_hwsim(void)
|
|||
}
|
||||
|
||||
for (i = 0; i < radios; i++) {
|
||||
err = mac80211_hwsim_create_radio();
|
||||
if (err)
|
||||
err = mac80211_hwsim_create_radio(channels);
|
||||
if (err < 0)
|
||||
goto out_free_radios;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,6 +65,9 @@ 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_MAX: enum limit
|
||||
*/
|
||||
enum {
|
||||
|
@ -72,6 +75,8 @@ enum {
|
|||
HWSIM_CMD_REGISTER,
|
||||
HWSIM_CMD_FRAME,
|
||||
HWSIM_CMD_TX_INFO_FRAME,
|
||||
HWSIM_CMD_CREATE_RADIO,
|
||||
HWSIM_CMD_DESTROY_RADIO,
|
||||
__HWSIM_CMD_MAX,
|
||||
};
|
||||
#define HWSIM_CMD_MAX (_HWSIM_CMD_MAX - 1)
|
||||
|
@ -94,6 +99,10 @@ enum {
|
|||
space
|
||||
* @HWSIM_ATTR_TX_INFO: ieee80211_tx_rate array
|
||||
* @HWSIM_ATTR_COOKIE: sk_buff cookie to identify the frame
|
||||
* @HWSIM_ATTR_CHANNELS: u32 attribute used with the %HWSIM_CMD_CREATE_RADIO
|
||||
* command giving the number of channels supported by the new radio
|
||||
* @HWSIM_ATTR_RADIO_ID: u32 attribute used with %HWSIM_CMD_DESTROY_RADIO
|
||||
* only to destroy a radio
|
||||
* @__HWSIM_ATTR_MAX: enum limit
|
||||
*/
|
||||
|
||||
|
@ -108,6 +117,8 @@ enum {
|
|||
HWSIM_ATTR_SIGNAL,
|
||||
HWSIM_ATTR_TX_INFO,
|
||||
HWSIM_ATTR_COOKIE,
|
||||
HWSIM_ATTR_CHANNELS,
|
||||
HWSIM_ATTR_RADIO_ID,
|
||||
__HWSIM_ATTR_MAX,
|
||||
};
|
||||
#define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1)
|
||||
|
|
Загрузка…
Ссылка в новой задаче