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;
.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,
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];
hw->wiphy->addresses = data->addresses;
data->channels = channels;
+ data->idx = idx;
if (data->channels > 1) {
hw->wiphy->max_scan_ssids = 255;
list_add_tail(&data->list, &hwsim_radios);
spin_unlock_bh(&hwsim_radio_lock);
- return 0;
+ return idx;
failed_hw:
device_unregister(data->dev);
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[] = {
{
.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,
{
int i, err;
- if (radios < 1 || radios > 100)
+ if (radios < 0 || radios > 100)
return -EINVAL;
if (channels < 1)
}
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;
}
* 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 {
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)
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
*/
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)