|
@@ -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;
|
|
@@ -436,7 +439,7 @@ struct mac80211_hwsim_data {
|
|
/*
|
|
/*
|
|
* Only radios in the same group can communicate together (the
|
|
* Only radios in the same group can communicate together (the
|
|
* channel has to match too). Each bit represents a group. A
|
|
* channel has to match too). Each bit represents a group. A
|
|
- * radio can be in more then one group.
|
|
|
|
|
|
+ * radio can be in more than one group.
|
|
*/
|
|
*/
|
|
u64 group;
|
|
u64 group;
|
|
|
|
|
|
@@ -447,6 +450,14 @@ struct mac80211_hwsim_data {
|
|
s64 bcn_delta;
|
|
s64 bcn_delta;
|
|
/* absolute beacon transmission time. Used to cover up "tx" delay. */
|
|
/* absolute beacon transmission time. Used to cover up "tx" delay. */
|
|
u64 abs_bcn_ts;
|
|
u64 abs_bcn_ts;
|
|
|
|
+
|
|
|
|
+ /* Stats */
|
|
|
|
+ u64 tx_pkts;
|
|
|
|
+ u64 rx_pkts;
|
|
|
|
+ u64 tx_bytes;
|
|
|
|
+ u64 rx_bytes;
|
|
|
|
+ u64 tx_dropped;
|
|
|
|
+ u64 tx_failed;
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
@@ -476,6 +487,14 @@ static struct genl_family hwsim_genl_family = {
|
|
.maxattr = HWSIM_ATTR_MAX,
|
|
.maxattr = HWSIM_ATTR_MAX,
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+enum hwsim_multicast_groups {
|
|
|
|
+ HWSIM_MCGRP_CONFIG,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static const struct genl_multicast_group hwsim_mcgrps[] = {
|
|
|
|
+ [HWSIM_MCGRP_CONFIG] = { .name = "config", },
|
|
|
|
+};
|
|
|
|
+
|
|
/* MAC80211_HWSIM netlink policy */
|
|
/* MAC80211_HWSIM netlink policy */
|
|
|
|
|
|
static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = {
|
|
static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = {
|
|
@@ -496,6 +515,10 @@ 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 },
|
|
|
|
+ [HWSIM_ATTR_RADIO_NAME] = { .type = NLA_STRING },
|
|
|
|
+ [HWSIM_ATTR_NO_VIF] = { .type = NLA_FLAG },
|
|
|
|
+ [HWSIM_ATTR_FREQ] = { .type = NLA_U32 },
|
|
};
|
|
};
|
|
|
|
|
|
static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
|
|
static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
|
|
@@ -861,8 +884,10 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
|
|
/* If the queue contains MAX_QUEUE skb's drop some */
|
|
/* If the queue contains MAX_QUEUE skb's drop some */
|
|
if (skb_queue_len(&data->pending) >= MAX_QUEUE) {
|
|
if (skb_queue_len(&data->pending) >= MAX_QUEUE) {
|
|
/* Droping until WARN_QUEUE level */
|
|
/* Droping until WARN_QUEUE level */
|
|
- while (skb_queue_len(&data->pending) >= WARN_QUEUE)
|
|
|
|
- skb_dequeue(&data->pending);
|
|
|
|
|
|
+ while (skb_queue_len(&data->pending) >= WARN_QUEUE) {
|
|
|
|
+ ieee80211_free_txskb(hw, skb_dequeue(&data->pending));
|
|
|
|
+ data->tx_dropped++;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_ATOMIC);
|
|
skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_ATOMIC);
|
|
@@ -896,6 +921,9 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
|
|
if (nla_put_u32(skb, HWSIM_ATTR_FLAGS, hwsim_flags))
|
|
if (nla_put_u32(skb, HWSIM_ATTR_FLAGS, hwsim_flags))
|
|
goto nla_put_failure;
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
+ if (nla_put_u32(skb, HWSIM_ATTR_FREQ, data->channel->center_freq))
|
|
|
|
+ goto nla_put_failure;
|
|
|
|
+
|
|
/* We get the tx control (rate and retries) info*/
|
|
/* We get the tx control (rate and retries) info*/
|
|
|
|
|
|
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
|
|
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
|
|
@@ -917,10 +945,14 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
|
|
|
|
|
|
/* Enqueue the packet */
|
|
/* Enqueue the packet */
|
|
skb_queue_tail(&data->pending, my_skb);
|
|
skb_queue_tail(&data->pending, my_skb);
|
|
|
|
+ data->tx_pkts++;
|
|
|
|
+ data->tx_bytes += my_skb->len;
|
|
return;
|
|
return;
|
|
|
|
|
|
nla_put_failure:
|
|
nla_put_failure:
|
|
printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
|
|
printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
|
|
|
|
+ ieee80211_free_txskb(hw, my_skb);
|
|
|
|
+ data->tx_failed++;
|
|
}
|
|
}
|
|
|
|
|
|
static bool hwsim_chans_compat(struct ieee80211_channel *c1,
|
|
static bool hwsim_chans_compat(struct ieee80211_channel *c1,
|
|
@@ -1066,6 +1098,8 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
|
|
rx_status.mactime = now + data2->tsf_offset;
|
|
rx_status.mactime = now + data2->tsf_offset;
|
|
|
|
|
|
memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status));
|
|
memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status));
|
|
|
|
+ data2->rx_pkts++;
|
|
|
|
+ data2->rx_bytes += nskb->len;
|
|
ieee80211_rx_irqsafe(data2->hw, nskb);
|
|
ieee80211_rx_irqsafe(data2->hw, nskb);
|
|
}
|
|
}
|
|
spin_unlock(&hwsim_radio_lock);
|
|
spin_unlock(&hwsim_radio_lock);
|
|
@@ -1133,6 +1167,8 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
|
|
return mac80211_hwsim_tx_frame_nl(hw, skb, _portid);
|
|
return mac80211_hwsim_tx_frame_nl(hw, skb, _portid);
|
|
|
|
|
|
/* NO wmediumd detected, perfect medium simulation */
|
|
/* NO wmediumd detected, perfect medium simulation */
|
|
|
|
+ data->tx_pkts++;
|
|
|
|
+ data->tx_bytes += skb->len;
|
|
ack = mac80211_hwsim_tx_frame_no_nl(hw, skb, channel);
|
|
ack = mac80211_hwsim_tx_frame_no_nl(hw, skb, channel);
|
|
|
|
|
|
if (ack && skb->len >= 16) {
|
|
if (ack && skb->len >= 16) {
|
|
@@ -1916,6 +1952,57 @@ static void mac80211_hwsim_unassign_vif_chanctx(struct ieee80211_hw *hw,
|
|
hwsim_check_chanctx_magic(ctx);
|
|
hwsim_check_chanctx_magic(ctx);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static const char mac80211_hwsim_gstrings_stats[][ETH_GSTRING_LEN] = {
|
|
|
|
+ "tx_pkts_nic",
|
|
|
|
+ "tx_bytes_nic",
|
|
|
|
+ "rx_pkts_nic",
|
|
|
|
+ "rx_bytes_nic",
|
|
|
|
+ "d_tx_dropped",
|
|
|
|
+ "d_tx_failed",
|
|
|
|
+ "d_ps_mode",
|
|
|
|
+ "d_group",
|
|
|
|
+ "d_tx_power",
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+#define MAC80211_HWSIM_SSTATS_LEN ARRAY_SIZE(mac80211_hwsim_gstrings_stats)
|
|
|
|
+
|
|
|
|
+static void mac80211_hwsim_get_et_strings(struct ieee80211_hw *hw,
|
|
|
|
+ struct ieee80211_vif *vif,
|
|
|
|
+ u32 sset, u8 *data)
|
|
|
|
+{
|
|
|
|
+ if (sset == ETH_SS_STATS)
|
|
|
|
+ memcpy(data, *mac80211_hwsim_gstrings_stats,
|
|
|
|
+ sizeof(mac80211_hwsim_gstrings_stats));
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int mac80211_hwsim_get_et_sset_count(struct ieee80211_hw *hw,
|
|
|
|
+ struct ieee80211_vif *vif, int sset)
|
|
|
|
+{
|
|
|
|
+ if (sset == ETH_SS_STATS)
|
|
|
|
+ return MAC80211_HWSIM_SSTATS_LEN;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void mac80211_hwsim_get_et_stats(struct ieee80211_hw *hw,
|
|
|
|
+ struct ieee80211_vif *vif,
|
|
|
|
+ struct ethtool_stats *stats, u64 *data)
|
|
|
|
+{
|
|
|
|
+ struct mac80211_hwsim_data *ar = hw->priv;
|
|
|
|
+ int i = 0;
|
|
|
|
+
|
|
|
|
+ data[i++] = ar->tx_pkts;
|
|
|
|
+ data[i++] = ar->tx_bytes;
|
|
|
|
+ data[i++] = ar->rx_pkts;
|
|
|
|
+ data[i++] = ar->rx_bytes;
|
|
|
|
+ data[i++] = ar->tx_dropped;
|
|
|
|
+ data[i++] = ar->tx_failed;
|
|
|
|
+ data[i++] = ar->ps;
|
|
|
|
+ data[i++] = ar->group;
|
|
|
|
+ data[i++] = ar->power_level;
|
|
|
|
+
|
|
|
|
+ WARN_ON(i != MAC80211_HWSIM_SSTATS_LEN);
|
|
|
|
+}
|
|
|
|
+
|
|
static const struct ieee80211_ops mac80211_hwsim_ops = {
|
|
static const struct ieee80211_ops mac80211_hwsim_ops = {
|
|
.tx = mac80211_hwsim_tx,
|
|
.tx = mac80211_hwsim_tx,
|
|
.start = mac80211_hwsim_start,
|
|
.start = mac80211_hwsim_start,
|
|
@@ -1939,14 +2026,131 @@ static const struct ieee80211_ops mac80211_hwsim_ops = {
|
|
.flush = mac80211_hwsim_flush,
|
|
.flush = mac80211_hwsim_flush,
|
|
.get_tsf = mac80211_hwsim_get_tsf,
|
|
.get_tsf = mac80211_hwsim_get_tsf,
|
|
.set_tsf = mac80211_hwsim_set_tsf,
|
|
.set_tsf = mac80211_hwsim_set_tsf,
|
|
|
|
+ .get_et_sset_count = mac80211_hwsim_get_et_sset_count,
|
|
|
|
+ .get_et_stats = mac80211_hwsim_get_et_stats,
|
|
|
|
+ .get_et_strings = mac80211_hwsim_get_et_strings,
|
|
};
|
|
};
|
|
|
|
|
|
static struct ieee80211_ops mac80211_hwsim_mchan_ops;
|
|
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)
|
|
|
|
|
|
+struct hwsim_new_radio_params {
|
|
|
|
+ unsigned int channels;
|
|
|
|
+ const char *reg_alpha2;
|
|
|
|
+ const struct ieee80211_regdomain *regd;
|
|
|
|
+ bool reg_strict;
|
|
|
|
+ bool p2p_device;
|
|
|
|
+ bool use_chanctx;
|
|
|
|
+ bool destroy_on_close;
|
|
|
|
+ const char *hwname;
|
|
|
|
+ bool no_vif;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static void hwsim_mcast_config_msg(struct sk_buff *mcast_skb,
|
|
|
|
+ struct genl_info *info)
|
|
|
|
+{
|
|
|
|
+ if (info)
|
|
|
|
+ genl_notify(&hwsim_genl_family, mcast_skb,
|
|
|
|
+ genl_info_net(info), info->snd_portid,
|
|
|
|
+ HWSIM_MCGRP_CONFIG, info->nlhdr, GFP_KERNEL);
|
|
|
|
+ else
|
|
|
|
+ genlmsg_multicast(&hwsim_genl_family, mcast_skb, 0,
|
|
|
|
+ HWSIM_MCGRP_CONFIG, GFP_KERNEL);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static struct sk_buff *build_radio_msg(int cmd, int id,
|
|
|
|
+ struct hwsim_new_radio_params *param)
|
|
|
|
+{
|
|
|
|
+ struct sk_buff *skb;
|
|
|
|
+ void *data;
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
+ if (!skb)
|
|
|
|
+ return NULL;
|
|
|
|
+
|
|
|
|
+ data = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, cmd);
|
|
|
|
+ if (!data)
|
|
|
|
+ goto error;
|
|
|
|
+
|
|
|
|
+ ret = nla_put_u32(skb, HWSIM_ATTR_RADIO_ID, id);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ goto error;
|
|
|
|
+
|
|
|
|
+ if (param->channels) {
|
|
|
|
+ ret = nla_put_u32(skb, HWSIM_ATTR_CHANNELS, param->channels);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (param->reg_alpha2) {
|
|
|
|
+ ret = nla_put(skb, HWSIM_ATTR_REG_HINT_ALPHA2, 2,
|
|
|
|
+ param->reg_alpha2);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (param->regd) {
|
|
|
|
+ int i;
|
|
|
|
+
|
|
|
|
+ for (i = 0; hwsim_world_regdom_custom[i] != param->regd &&
|
|
|
|
+ i < ARRAY_SIZE(hwsim_world_regdom_custom); i++)
|
|
|
|
+ ;
|
|
|
|
+
|
|
|
|
+ if (i < ARRAY_SIZE(hwsim_world_regdom_custom)) {
|
|
|
|
+ ret = nla_put_u32(skb, HWSIM_ATTR_REG_CUSTOM_REG, i);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (param->reg_strict) {
|
|
|
|
+ ret = nla_put_flag(skb, HWSIM_ATTR_REG_STRICT_REG);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (param->p2p_device) {
|
|
|
|
+ ret = nla_put_flag(skb, HWSIM_ATTR_SUPPORT_P2P_DEVICE);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (param->use_chanctx) {
|
|
|
|
+ ret = nla_put_flag(skb, HWSIM_ATTR_USE_CHANCTX);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (param->hwname) {
|
|
|
|
+ ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME,
|
|
|
|
+ strlen(param->hwname), param->hwname);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ genlmsg_end(skb, data);
|
|
|
|
+
|
|
|
|
+ return skb;
|
|
|
|
+
|
|
|
|
+error:
|
|
|
|
+ nlmsg_free(skb);
|
|
|
|
+ return NULL;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void hswim_mcast_new_radio(int id, struct genl_info *info,
|
|
|
|
+ struct hwsim_new_radio_params *param)
|
|
|
|
+{
|
|
|
|
+ struct sk_buff *mcast_skb;
|
|
|
|
+
|
|
|
|
+ mcast_skb = build_radio_msg(HWSIM_CMD_NEW_RADIO, id, param);
|
|
|
|
+ if (!mcast_skb)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ hwsim_mcast_config_msg(mcast_skb, info);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int mac80211_hwsim_new_radio(struct genl_info *info,
|
|
|
|
+ struct hwsim_new_radio_params *param)
|
|
{
|
|
{
|
|
int err;
|
|
int err;
|
|
u8 addr[ETH_ALEN];
|
|
u8 addr[ETH_ALEN];
|
|
@@ -1956,16 +2160,16 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
|
|
const struct ieee80211_ops *ops = &mac80211_hwsim_ops;
|
|
const struct ieee80211_ops *ops = &mac80211_hwsim_ops;
|
|
int idx;
|
|
int idx;
|
|
|
|
|
|
- if (WARN_ON(channels > 1 && !use_chanctx))
|
|
|
|
|
|
+ if (WARN_ON(param->channels > 1 && !param->use_chanctx))
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
spin_lock_bh(&hwsim_radio_lock);
|
|
spin_lock_bh(&hwsim_radio_lock);
|
|
idx = hwsim_radio_idx++;
|
|
idx = hwsim_radio_idx++;
|
|
spin_unlock_bh(&hwsim_radio_lock);
|
|
spin_unlock_bh(&hwsim_radio_lock);
|
|
|
|
|
|
- if (use_chanctx)
|
|
|
|
|
|
+ if (param->use_chanctx)
|
|
ops = &mac80211_hwsim_mchan_ops;
|
|
ops = &mac80211_hwsim_mchan_ops;
|
|
- hw = ieee80211_alloc_hw(sizeof(*data), ops);
|
|
|
|
|
|
+ hw = ieee80211_alloc_hw_nm(sizeof(*data), ops, param->hwname);
|
|
if (!hw) {
|
|
if (!hw) {
|
|
printk(KERN_DEBUG "mac80211_hwsim: ieee80211_alloc_hw failed\n");
|
|
printk(KERN_DEBUG "mac80211_hwsim: ieee80211_alloc_hw failed\n");
|
|
err = -ENOMEM;
|
|
err = -ENOMEM;
|
|
@@ -2003,9 +2207,12 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
|
|
hw->wiphy->n_addresses = 2;
|
|
hw->wiphy->n_addresses = 2;
|
|
hw->wiphy->addresses = data->addresses;
|
|
hw->wiphy->addresses = data->addresses;
|
|
|
|
|
|
- data->channels = channels;
|
|
|
|
- data->use_chanctx = use_chanctx;
|
|
|
|
|
|
+ data->channels = param->channels;
|
|
|
|
+ data->use_chanctx = param->use_chanctx;
|
|
data->idx = idx;
|
|
data->idx = idx;
|
|
|
|
+ data->destroy_on_close = param->destroy_on_close;
|
|
|
|
+ if (info)
|
|
|
|
+ data->portid = info->snd_portid;
|
|
|
|
|
|
if (data->use_chanctx) {
|
|
if (data->use_chanctx) {
|
|
hw->wiphy->max_scan_ssids = 255;
|
|
hw->wiphy->max_scan_ssids = 255;
|
|
@@ -2014,12 +2221,12 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
|
|
/* For channels > 1 DFS is not allowed */
|
|
/* For channels > 1 DFS is not allowed */
|
|
hw->wiphy->n_iface_combinations = 1;
|
|
hw->wiphy->n_iface_combinations = 1;
|
|
hw->wiphy->iface_combinations = &data->if_combination;
|
|
hw->wiphy->iface_combinations = &data->if_combination;
|
|
- if (p2p_device)
|
|
|
|
|
|
+ if (param->p2p_device)
|
|
data->if_combination = hwsim_if_comb_p2p_dev[0];
|
|
data->if_combination = hwsim_if_comb_p2p_dev[0];
|
|
else
|
|
else
|
|
data->if_combination = hwsim_if_comb[0];
|
|
data->if_combination = hwsim_if_comb[0];
|
|
data->if_combination.num_different_channels = data->channels;
|
|
data->if_combination.num_different_channels = data->channels;
|
|
- } else if (p2p_device) {
|
|
|
|
|
|
+ } else if (param->p2p_device) {
|
|
hw->wiphy->iface_combinations = hwsim_if_comb_p2p_dev;
|
|
hw->wiphy->iface_combinations = hwsim_if_comb_p2p_dev;
|
|
hw->wiphy->n_iface_combinations =
|
|
hw->wiphy->n_iface_combinations =
|
|
ARRAY_SIZE(hwsim_if_comb_p2p_dev);
|
|
ARRAY_SIZE(hwsim_if_comb_p2p_dev);
|
|
@@ -2040,7 +2247,7 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
|
|
BIT(NL80211_IFTYPE_ADHOC) |
|
|
BIT(NL80211_IFTYPE_ADHOC) |
|
|
BIT(NL80211_IFTYPE_MESH_POINT);
|
|
BIT(NL80211_IFTYPE_MESH_POINT);
|
|
|
|
|
|
- if (p2p_device)
|
|
|
|
|
|
+ if (param->p2p_device)
|
|
hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_DEVICE);
|
|
hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_DEVICE);
|
|
|
|
|
|
hw->flags = IEEE80211_HW_MFP_CAPABLE |
|
|
hw->flags = IEEE80211_HW_MFP_CAPABLE |
|
|
@@ -2095,6 +2302,7 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
|
|
sband->ht_cap.ht_supported = true;
|
|
sband->ht_cap.ht_supported = true;
|
|
sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
|
|
sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
|
|
IEEE80211_HT_CAP_GRN_FLD |
|
|
IEEE80211_HT_CAP_GRN_FLD |
|
|
|
|
+ IEEE80211_HT_CAP_SGI_20 |
|
|
IEEE80211_HT_CAP_SGI_40 |
|
|
IEEE80211_HT_CAP_SGI_40 |
|
|
IEEE80211_HT_CAP_DSSSCCK40;
|
|
IEEE80211_HT_CAP_DSSSCCK40;
|
|
sband->ht_cap.ampdu_factor = 0x3;
|
|
sband->ht_cap.ampdu_factor = 0x3;
|
|
@@ -2142,15 +2350,18 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
|
|
hw->max_rates = 4;
|
|
hw->max_rates = 4;
|
|
hw->max_rate_tries = 11;
|
|
hw->max_rate_tries = 11;
|
|
|
|
|
|
- if (reg_strict)
|
|
|
|
|
|
+ if (param->reg_strict)
|
|
hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
|
|
hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
|
|
- if (regd) {
|
|
|
|
|
|
+ if (param->regd) {
|
|
hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
|
|
hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
|
|
- wiphy_apply_custom_regulatory(hw->wiphy, regd);
|
|
|
|
|
|
+ wiphy_apply_custom_regulatory(hw->wiphy, param->regd);
|
|
/* give the regulatory workqueue a chance to run */
|
|
/* give the regulatory workqueue a chance to run */
|
|
schedule_timeout_interruptible(1);
|
|
schedule_timeout_interruptible(1);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (param->no_vif)
|
|
|
|
+ hw->flags |= IEEE80211_HW_NO_AUTO_VIF;
|
|
|
|
+
|
|
err = ieee80211_register_hw(hw);
|
|
err = ieee80211_register_hw(hw);
|
|
if (err < 0) {
|
|
if (err < 0) {
|
|
printk(KERN_DEBUG "mac80211_hwsim: ieee80211_register_hw failed (%d)\n",
|
|
printk(KERN_DEBUG "mac80211_hwsim: ieee80211_register_hw failed (%d)\n",
|
|
@@ -2160,8 +2371,8 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
|
|
|
|
|
|
wiphy_debug(hw->wiphy, "hwaddr %pM registered\n", hw->wiphy->perm_addr);
|
|
wiphy_debug(hw->wiphy, "hwaddr %pM registered\n", hw->wiphy->perm_addr);
|
|
|
|
|
|
- if (reg_alpha2)
|
|
|
|
- regulatory_hint(hw->wiphy, reg_alpha2);
|
|
|
|
|
|
+ if (param->reg_alpha2)
|
|
|
|
+ regulatory_hint(hw->wiphy, param->reg_alpha2);
|
|
|
|
|
|
data->debugfs = debugfs_create_dir("hwsim", hw->wiphy->debugfsdir);
|
|
data->debugfs = debugfs_create_dir("hwsim", hw->wiphy->debugfsdir);
|
|
debugfs_create_file("ps", 0666, data->debugfs, data, &hwsim_fops_ps);
|
|
debugfs_create_file("ps", 0666, data->debugfs, data, &hwsim_fops_ps);
|
|
@@ -2180,6 +2391,9 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
|
|
list_add_tail(&data->list, &hwsim_radios);
|
|
list_add_tail(&data->list, &hwsim_radios);
|
|
spin_unlock_bh(&hwsim_radio_lock);
|
|
spin_unlock_bh(&hwsim_radio_lock);
|
|
|
|
|
|
|
|
+ if (idx > 0)
|
|
|
|
+ hswim_mcast_new_radio(idx, info, param);
|
|
|
|
+
|
|
return idx;
|
|
return idx;
|
|
|
|
|
|
failed_hw:
|
|
failed_hw:
|
|
@@ -2190,8 +2404,48 @@ failed:
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
-static void mac80211_hwsim_destroy_radio(struct mac80211_hwsim_data *data)
|
|
|
|
|
|
+static void hwsim_mcast_del_radio(int id, const char *hwname,
|
|
|
|
+ struct genl_info *info)
|
|
|
|
+{
|
|
|
|
+ struct sk_buff *skb;
|
|
|
|
+ void *data;
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
+ if (!skb)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ data = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0,
|
|
|
|
+ HWSIM_CMD_DEL_RADIO);
|
|
|
|
+ if (!data)
|
|
|
|
+ goto error;
|
|
|
|
+
|
|
|
|
+ ret = nla_put_u32(skb, HWSIM_ATTR_RADIO_ID, id);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ goto error;
|
|
|
|
+
|
|
|
|
+ if (hwname) {
|
|
|
|
+ ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME, strlen(hwname),
|
|
|
|
+ hwname);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ genlmsg_end(skb, data);
|
|
|
|
+
|
|
|
|
+ hwsim_mcast_config_msg(skb, info);
|
|
|
|
+
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+error:
|
|
|
|
+ nlmsg_free(skb);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void mac80211_hwsim_del_radio(struct mac80211_hwsim_data *data,
|
|
|
|
+ const char *hwname,
|
|
|
|
+ struct genl_info *info)
|
|
{
|
|
{
|
|
|
|
+ hwsim_mcast_del_radio(data->idx, hwname, info);
|
|
debugfs_remove_recursive(data->debugfs);
|
|
debugfs_remove_recursive(data->debugfs);
|
|
ieee80211_unregister_hw(data->hw);
|
|
ieee80211_unregister_hw(data->hw);
|
|
device_release_driver(data->dev);
|
|
device_release_driver(data->dev);
|
|
@@ -2209,7 +2463,7 @@ static void mac80211_hwsim_free(void)
|
|
list))) {
|
|
list))) {
|
|
list_del(&data->list);
|
|
list_del(&data->list);
|
|
spin_unlock_bh(&hwsim_radio_lock);
|
|
spin_unlock_bh(&hwsim_radio_lock);
|
|
- mac80211_hwsim_destroy_radio(data);
|
|
|
|
|
|
+ mac80211_hwsim_del_radio(data, NULL, NULL);
|
|
spin_lock_bh(&hwsim_radio_lock);
|
|
spin_lock_bh(&hwsim_radio_lock);
|
|
}
|
|
}
|
|
spin_unlock_bh(&hwsim_radio_lock);
|
|
spin_unlock_bh(&hwsim_radio_lock);
|
|
@@ -2337,7 +2591,6 @@ out:
|
|
static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
|
|
static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
|
|
struct genl_info *info)
|
|
struct genl_info *info)
|
|
{
|
|
{
|
|
-
|
|
|
|
struct mac80211_hwsim_data *data2;
|
|
struct mac80211_hwsim_data *data2;
|
|
struct ieee80211_rx_status rx_status;
|
|
struct ieee80211_rx_status rx_status;
|
|
const u8 *dst;
|
|
const u8 *dst;
|
|
@@ -2380,18 +2633,22 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
|
|
|
|
|
|
/* A frame is received from user space */
|
|
/* A frame is received from user space */
|
|
memset(&rx_status, 0, sizeof(rx_status));
|
|
memset(&rx_status, 0, sizeof(rx_status));
|
|
|
|
+ /* TODO: Check ATTR_FREQ if it exists, and maybe throw away off-channel
|
|
|
|
+ * packets?
|
|
|
|
+ */
|
|
rx_status.freq = data2->channel->center_freq;
|
|
rx_status.freq = data2->channel->center_freq;
|
|
rx_status.band = data2->channel->band;
|
|
rx_status.band = data2->channel->band;
|
|
rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]);
|
|
rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]);
|
|
rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]);
|
|
rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]);
|
|
|
|
|
|
memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
|
|
memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
|
|
|
|
+ data2->rx_pkts++;
|
|
|
|
+ data2->rx_bytes += skb->len;
|
|
ieee80211_rx_irqsafe(data2->hw, skb);
|
|
ieee80211_rx_irqsafe(data2->hw, skb);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
err:
|
|
err:
|
|
printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
|
|
printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
|
|
- goto out;
|
|
|
|
out:
|
|
out:
|
|
dev_kfree_skb(skb);
|
|
dev_kfree_skb(skb);
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
@@ -2427,54 +2684,72 @@ static int hwsim_register_received_nl(struct sk_buff *skb_2,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static int hwsim_create_radio_nl(struct sk_buff *msg, struct genl_info *info)
|
|
|
|
|
|
+static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info)
|
|
{
|
|
{
|
|
- unsigned int chans = channels;
|
|
|
|
- const char *alpha2 = NULL;
|
|
|
|
- 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 use_chanctx;
|
|
|
|
|
|
+ struct hwsim_new_radio_params param = { 0 };
|
|
|
|
+
|
|
|
|
+ param.reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG];
|
|
|
|
+ param.p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE];
|
|
|
|
+ param.channels = channels;
|
|
|
|
+ param.destroy_on_close =
|
|
|
|
+ info->attrs[HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE];
|
|
|
|
|
|
if (info->attrs[HWSIM_ATTR_CHANNELS])
|
|
if (info->attrs[HWSIM_ATTR_CHANNELS])
|
|
- chans = nla_get_u32(info->attrs[HWSIM_ATTR_CHANNELS]);
|
|
|
|
|
|
+ param.channels = nla_get_u32(info->attrs[HWSIM_ATTR_CHANNELS]);
|
|
|
|
+
|
|
|
|
+ if (info->attrs[HWSIM_ATTR_NO_VIF])
|
|
|
|
+ param.no_vif = true;
|
|
|
|
+
|
|
|
|
+ if (info->attrs[HWSIM_ATTR_RADIO_NAME])
|
|
|
|
+ param.hwname = nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME]);
|
|
|
|
|
|
if (info->attrs[HWSIM_ATTR_USE_CHANCTX])
|
|
if (info->attrs[HWSIM_ATTR_USE_CHANCTX])
|
|
- use_chanctx = true;
|
|
|
|
|
|
+ param.use_chanctx = true;
|
|
else
|
|
else
|
|
- use_chanctx = (chans > 1);
|
|
|
|
|
|
+ param.use_chanctx = (param.channels > 1);
|
|
|
|
|
|
if (info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2])
|
|
if (info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2])
|
|
- alpha2 = nla_data(info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]);
|
|
|
|
|
|
+ param.reg_alpha2 =
|
|
|
|
+ nla_data(info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]);
|
|
|
|
|
|
if (info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]) {
|
|
if (info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]) {
|
|
u32 idx = nla_get_u32(info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]);
|
|
u32 idx = nla_get_u32(info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]);
|
|
|
|
|
|
if (idx >= ARRAY_SIZE(hwsim_world_regdom_custom))
|
|
if (idx >= ARRAY_SIZE(hwsim_world_regdom_custom))
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
- regd = hwsim_world_regdom_custom[idx];
|
|
|
|
|
|
+ param.regd = hwsim_world_regdom_custom[idx];
|
|
}
|
|
}
|
|
|
|
|
|
- return mac80211_hwsim_create_radio(chans, alpha2, regd, reg_strict,
|
|
|
|
- p2p_device, use_chanctx);
|
|
|
|
|
|
+ return mac80211_hwsim_new_radio(info, ¶m);
|
|
}
|
|
}
|
|
|
|
|
|
-static int hwsim_destroy_radio_nl(struct sk_buff *msg, struct genl_info *info)
|
|
|
|
|
|
+static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info)
|
|
{
|
|
{
|
|
struct mac80211_hwsim_data *data;
|
|
struct mac80211_hwsim_data *data;
|
|
- int idx;
|
|
|
|
|
|
+ s64 idx = -1;
|
|
|
|
+ const char *hwname = NULL;
|
|
|
|
|
|
- if (!info->attrs[HWSIM_ATTR_RADIO_ID])
|
|
|
|
|
|
+ if (info->attrs[HWSIM_ATTR_RADIO_ID])
|
|
|
|
+ idx = nla_get_u32(info->attrs[HWSIM_ATTR_RADIO_ID]);
|
|
|
|
+ else if (info->attrs[HWSIM_ATTR_RADIO_NAME])
|
|
|
|
+ hwname = (void *)nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME]);
|
|
|
|
+ else
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
- idx = nla_get_u32(info->attrs[HWSIM_ATTR_RADIO_ID]);
|
|
|
|
|
|
|
|
spin_lock_bh(&hwsim_radio_lock);
|
|
spin_lock_bh(&hwsim_radio_lock);
|
|
list_for_each_entry(data, &hwsim_radios, list) {
|
|
list_for_each_entry(data, &hwsim_radios, list) {
|
|
- if (data->idx != idx)
|
|
|
|
- continue;
|
|
|
|
|
|
+ if (idx >= 0) {
|
|
|
|
+ if (data->idx != idx)
|
|
|
|
+ continue;
|
|
|
|
+ } else {
|
|
|
|
+ if (hwname &&
|
|
|
|
+ strcmp(hwname, wiphy_name(data->hw->wiphy)))
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
list_del(&data->list);
|
|
list_del(&data->list);
|
|
spin_unlock_bh(&hwsim_radio_lock);
|
|
spin_unlock_bh(&hwsim_radio_lock);
|
|
- mac80211_hwsim_destroy_radio(data);
|
|
|
|
|
|
+ mac80211_hwsim_del_radio(data, hwname, info);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
spin_unlock_bh(&hwsim_radio_lock);
|
|
spin_unlock_bh(&hwsim_radio_lock);
|
|
@@ -2501,19 +2776,42 @@ static const struct genl_ops hwsim_ops[] = {
|
|
.doit = hwsim_tx_info_frame_received_nl,
|
|
.doit = hwsim_tx_info_frame_received_nl,
|
|
},
|
|
},
|
|
{
|
|
{
|
|
- .cmd = HWSIM_CMD_CREATE_RADIO,
|
|
|
|
|
|
+ .cmd = HWSIM_CMD_NEW_RADIO,
|
|
.policy = hwsim_genl_policy,
|
|
.policy = hwsim_genl_policy,
|
|
- .doit = hwsim_create_radio_nl,
|
|
|
|
|
|
+ .doit = hwsim_new_radio_nl,
|
|
.flags = GENL_ADMIN_PERM,
|
|
.flags = GENL_ADMIN_PERM,
|
|
},
|
|
},
|
|
{
|
|
{
|
|
- .cmd = HWSIM_CMD_DESTROY_RADIO,
|
|
|
|
|
|
+ .cmd = HWSIM_CMD_DEL_RADIO,
|
|
.policy = hwsim_genl_policy,
|
|
.policy = hwsim_genl_policy,
|
|
- .doit = hwsim_destroy_radio_nl,
|
|
|
|
|
|
+ .doit = hwsim_del_radio_nl,
|
|
.flags = GENL_ADMIN_PERM,
|
|
.flags = GENL_ADMIN_PERM,
|
|
},
|
|
},
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+static void destroy_radio(struct work_struct *work)
|
|
|
|
+{
|
|
|
|
+ struct mac80211_hwsim_data *data =
|
|
|
|
+ container_of(work, struct mac80211_hwsim_data, destroy_work);
|
|
|
|
+
|
|
|
|
+ mac80211_hwsim_del_radio(data, NULL, NULL);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+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 +2821,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");
|
|
@@ -2542,7 +2842,9 @@ static int hwsim_init_netlink(void)
|
|
|
|
|
|
printk(KERN_INFO "mac80211_hwsim: initializing netlink\n");
|
|
printk(KERN_INFO "mac80211_hwsim: initializing netlink\n");
|
|
|
|
|
|
- rc = genl_register_family_with_ops(&hwsim_genl_family, hwsim_ops);
|
|
|
|
|
|
+ rc = genl_register_family_with_ops_groups(&hwsim_genl_family,
|
|
|
|
+ hwsim_ops,
|
|
|
|
+ hwsim_mcgrps);
|
|
if (rc)
|
|
if (rc)
|
|
goto failure;
|
|
goto failure;
|
|
|
|
|
|
@@ -2603,69 +2905,73 @@ static int __init init_mac80211_hwsim(void)
|
|
goto out_unregister_driver;
|
|
goto out_unregister_driver;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ err = hwsim_init_netlink();
|
|
|
|
+ if (err < 0)
|
|
|
|
+ goto out_unregister_driver;
|
|
|
|
+
|
|
for (i = 0; i < radios; i++) {
|
|
for (i = 0; i < radios; i++) {
|
|
- const char *reg_alpha2 = NULL;
|
|
|
|
- const struct ieee80211_regdomain *regd = NULL;
|
|
|
|
- bool reg_strict = false;
|
|
|
|
|
|
+ struct hwsim_new_radio_params param = { 0 };
|
|
|
|
+
|
|
|
|
+ param.channels = channels;
|
|
|
|
|
|
switch (regtest) {
|
|
switch (regtest) {
|
|
case HWSIM_REGTEST_DIFF_COUNTRY:
|
|
case HWSIM_REGTEST_DIFF_COUNTRY:
|
|
if (i < ARRAY_SIZE(hwsim_alpha2s))
|
|
if (i < ARRAY_SIZE(hwsim_alpha2s))
|
|
- reg_alpha2 = hwsim_alpha2s[i];
|
|
|
|
|
|
+ param.reg_alpha2 = hwsim_alpha2s[i];
|
|
break;
|
|
break;
|
|
case HWSIM_REGTEST_DRIVER_REG_FOLLOW:
|
|
case HWSIM_REGTEST_DRIVER_REG_FOLLOW:
|
|
if (!i)
|
|
if (!i)
|
|
- reg_alpha2 = hwsim_alpha2s[0];
|
|
|
|
|
|
+ param.reg_alpha2 = hwsim_alpha2s[0];
|
|
break;
|
|
break;
|
|
case HWSIM_REGTEST_STRICT_ALL:
|
|
case HWSIM_REGTEST_STRICT_ALL:
|
|
- reg_strict = true;
|
|
|
|
|
|
+ param.reg_strict = true;
|
|
case HWSIM_REGTEST_DRIVER_REG_ALL:
|
|
case HWSIM_REGTEST_DRIVER_REG_ALL:
|
|
- reg_alpha2 = hwsim_alpha2s[0];
|
|
|
|
|
|
+ param.reg_alpha2 = hwsim_alpha2s[0];
|
|
break;
|
|
break;
|
|
case HWSIM_REGTEST_WORLD_ROAM:
|
|
case HWSIM_REGTEST_WORLD_ROAM:
|
|
if (i == 0)
|
|
if (i == 0)
|
|
- regd = &hwsim_world_regdom_custom_01;
|
|
|
|
|
|
+ param.regd = &hwsim_world_regdom_custom_01;
|
|
break;
|
|
break;
|
|
case HWSIM_REGTEST_CUSTOM_WORLD:
|
|
case HWSIM_REGTEST_CUSTOM_WORLD:
|
|
- regd = &hwsim_world_regdom_custom_01;
|
|
|
|
|
|
+ param.regd = &hwsim_world_regdom_custom_01;
|
|
break;
|
|
break;
|
|
case HWSIM_REGTEST_CUSTOM_WORLD_2:
|
|
case HWSIM_REGTEST_CUSTOM_WORLD_2:
|
|
if (i == 0)
|
|
if (i == 0)
|
|
- regd = &hwsim_world_regdom_custom_01;
|
|
|
|
|
|
+ param.regd = &hwsim_world_regdom_custom_01;
|
|
else if (i == 1)
|
|
else if (i == 1)
|
|
- regd = &hwsim_world_regdom_custom_02;
|
|
|
|
|
|
+ param.regd = &hwsim_world_regdom_custom_02;
|
|
break;
|
|
break;
|
|
case HWSIM_REGTEST_STRICT_FOLLOW:
|
|
case HWSIM_REGTEST_STRICT_FOLLOW:
|
|
if (i == 0) {
|
|
if (i == 0) {
|
|
- reg_strict = true;
|
|
|
|
- reg_alpha2 = hwsim_alpha2s[0];
|
|
|
|
|
|
+ param.reg_strict = true;
|
|
|
|
+ param.reg_alpha2 = hwsim_alpha2s[0];
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
case HWSIM_REGTEST_STRICT_AND_DRIVER_REG:
|
|
case HWSIM_REGTEST_STRICT_AND_DRIVER_REG:
|
|
if (i == 0) {
|
|
if (i == 0) {
|
|
- reg_strict = true;
|
|
|
|
- reg_alpha2 = hwsim_alpha2s[0];
|
|
|
|
|
|
+ param.reg_strict = true;
|
|
|
|
+ param.reg_alpha2 = hwsim_alpha2s[0];
|
|
} else if (i == 1) {
|
|
} else if (i == 1) {
|
|
- reg_alpha2 = hwsim_alpha2s[1];
|
|
|
|
|
|
+ param.reg_alpha2 = hwsim_alpha2s[1];
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
case HWSIM_REGTEST_ALL:
|
|
case HWSIM_REGTEST_ALL:
|
|
switch (i) {
|
|
switch (i) {
|
|
case 0:
|
|
case 0:
|
|
- regd = &hwsim_world_regdom_custom_01;
|
|
|
|
|
|
+ param.regd = &hwsim_world_regdom_custom_01;
|
|
break;
|
|
break;
|
|
case 1:
|
|
case 1:
|
|
- regd = &hwsim_world_regdom_custom_02;
|
|
|
|
|
|
+ param.regd = &hwsim_world_regdom_custom_02;
|
|
break;
|
|
break;
|
|
case 2:
|
|
case 2:
|
|
- reg_alpha2 = hwsim_alpha2s[0];
|
|
|
|
|
|
+ param.reg_alpha2 = hwsim_alpha2s[0];
|
|
break;
|
|
break;
|
|
case 3:
|
|
case 3:
|
|
- reg_alpha2 = hwsim_alpha2s[1];
|
|
|
|
|
|
+ param.reg_alpha2 = hwsim_alpha2s[1];
|
|
break;
|
|
break;
|
|
case 4:
|
|
case 4:
|
|
- reg_strict = true;
|
|
|
|
- reg_alpha2 = hwsim_alpha2s[2];
|
|
|
|
|
|
+ param.reg_strict = true;
|
|
|
|
+ param.reg_alpha2 = hwsim_alpha2s[2];
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
@@ -2673,10 +2979,10 @@ static int __init init_mac80211_hwsim(void)
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
- err = mac80211_hwsim_create_radio(channels, reg_alpha2,
|
|
|
|
- regd, reg_strict,
|
|
|
|
- support_p2p_device,
|
|
|
|
- channels > 1);
|
|
|
|
|
|
+ param.p2p_device = support_p2p_device;
|
|
|
|
+ param.use_chanctx = channels > 1;
|
|
|
|
+
|
|
|
|
+ err = mac80211_hwsim_new_radio(NULL, ¶m);
|
|
if (err < 0)
|
|
if (err < 0)
|
|
goto out_free_radios;
|
|
goto out_free_radios;
|
|
}
|
|
}
|
|
@@ -2702,10 +3008,6 @@ static int __init init_mac80211_hwsim(void)
|
|
}
|
|
}
|
|
rtnl_unlock();
|
|
rtnl_unlock();
|
|
|
|
|
|
- err = hwsim_init_netlink();
|
|
|
|
- if (err < 0)
|
|
|
|
- goto out_free_mon;
|
|
|
|
-
|
|
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
out_free_mon:
|
|
out_free_mon:
|