summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/virtual
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/virtual')
-rw-r--r--drivers/net/wireless/virtual/mac80211_hwsim.c541
-rw-r--r--drivers/net/wireless/virtual/mac80211_hwsim.h20
-rw-r--r--drivers/net/wireless/virtual/virt_wifi.c19
3 files changed, 535 insertions, 45 deletions
diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c
index cf3e976471c6..1fcf5d0d2e13 100644
--- a/drivers/net/wireless/virtual/mac80211_hwsim.c
+++ b/drivers/net/wireless/virtual/mac80211_hwsim.c
@@ -36,6 +36,8 @@
#include <linux/virtio.h>
#include <linux/virtio_ids.h>
#include <linux/virtio_config.h>
+#include <linux/uaccess.h>
+#include <linux/string.h>
#include "mac80211_hwsim.h"
#define WARN_QUEUE 100
@@ -337,7 +339,9 @@ static inline void hwsim_net_set_wmediumd(struct net *net, u32 portid)
hwsim_net->wmediumd = portid;
}
-static struct class *hwsim_class;
+static const struct class hwsim_class = {
+ .name = "mac80211_hwsim"
+};
static struct net_device *hwsim_mon; /* global monitor netdev */
@@ -645,6 +649,7 @@ static LIST_HEAD(hwsim_radios);
static struct rhashtable hwsim_radios_rht;
static int hwsim_radio_idx;
static int hwsim_radios_generation = 1;
+static u8 hwsim_nan_cluster_id[ETH_ALEN];
static struct platform_driver mac80211_hwsim_driver = {
.driver = {
@@ -670,7 +675,7 @@ struct mac80211_hwsim_data {
struct ieee80211_channel channels_s1g[ARRAY_SIZE(hwsim_channels_s1g)];
struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)];
struct ieee80211_iface_combination if_combination;
- struct ieee80211_iface_limit if_limits[3];
+ struct ieee80211_iface_limit if_limits[4];
int n_if_limits;
struct ieee80211_iface_combination if_combination_radio;
@@ -679,7 +684,7 @@ struct mac80211_hwsim_data {
u32 ciphers[ARRAY_SIZE(hwsim_ciphers)];
- struct mac_address addresses[2];
+ struct mac_address addresses[3];
int channels, idx;
bool use_chanctx;
bool destroy_on_close;
@@ -714,6 +719,7 @@ struct mac80211_hwsim_data {
} ps;
bool ps_poll_pending;
struct dentry *debugfs;
+ struct cfg80211_chan_def radar_background_chandef;
atomic_t pending_cookie;
struct sk_buff_head pending; /* packets pending */
@@ -752,6 +758,14 @@ struct mac80211_hwsim_data {
struct wireless_dev *pmsr_request_wdev;
struct mac80211_hwsim_link_data link_data[IEEE80211_MLD_MAX_NUM_LINKS];
+
+ struct ieee80211_vif *nan_device_vif;
+ u8 nan_bands;
+
+ enum nl80211_band nan_curr_dw_band;
+ struct hrtimer nan_timer;
+ bool notify_dw;
+ struct ieee80211_vif *nan_vif;
};
static const struct rhashtable_params hwsim_rht_params = {
@@ -926,6 +940,8 @@ static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = {
[HWSIM_ATTR_PMSR_SUPPORT] = NLA_POLICY_NESTED(hwsim_pmsr_capa_policy),
[HWSIM_ATTR_PMSR_RESULT] = NLA_POLICY_NESTED(hwsim_pmsr_peers_result_policy),
[HWSIM_ATTR_MULTI_RADIO] = { .type = NLA_FLAG },
+ [HWSIM_ATTR_SUPPORT_NAN_DEVICE] = { .type = NLA_FLAG },
+ [HWSIM_ATTR_SUPPORT_BACKGROUND_RADAR] = { .type = NLA_FLAG },
};
#if IS_REACHABLE(CONFIG_VIRTIO)
@@ -1154,6 +1170,100 @@ static int hwsim_write_simulate_radar(void *dat, u64 val)
DEFINE_DEBUGFS_ATTRIBUTE(hwsim_simulate_radar, NULL,
hwsim_write_simulate_radar, "%llu\n");
+static ssize_t hwsim_background_cac_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct mac80211_hwsim_data *data = file->private_data;
+ char buf[8] = {};
+
+ if (count >= sizeof(buf))
+ return -EINVAL;
+
+ if (copy_from_user(buf, user_buf, count))
+ return -EFAULT;
+
+ /* Check if background radar channel is configured */
+ if (!data->radar_background_chandef.chan)
+ return -ENOENT;
+
+ if (sysfs_streq(buf, "radar"))
+ cfg80211_background_radar_event(data->hw->wiphy,
+ &data->radar_background_chandef,
+ GFP_KERNEL);
+ else if (sysfs_streq(buf, "cancel"))
+ cfg80211_background_cac_abort(data->hw->wiphy);
+ else
+ return -EINVAL;
+
+ return count;
+}
+
+static const struct file_operations hwsim_background_cac_ops = {
+ .write = hwsim_background_cac_write,
+ .open = simple_open,
+ .llseek = default_llseek,
+};
+
+struct hwsim_chanctx_iter_arg {
+ struct ieee80211_chanctx_conf *conf;
+ u32 freq_mhz;
+};
+
+static void hwsim_6ghz_chanctx_iter(struct ieee80211_hw *hw,
+ struct ieee80211_chanctx_conf *conf,
+ void *data)
+{
+ struct hwsim_chanctx_iter_arg *arg = data;
+
+ if (conf->def.chan &&
+ conf->def.chan->band == NL80211_BAND_6GHZ &&
+ conf->def.chan->center_freq == arg->freq_mhz)
+ arg->conf = conf;
+}
+
+static ssize_t hwsim_simulate_incumbent_signal_write(struct file *file,
+ const char __user *ubuf,
+ size_t len, loff_t *ppos)
+{
+ struct mac80211_hwsim_data *data = file->private_data;
+ struct hwsim_chanctx_iter_arg arg = {};
+ u32 bitmap;
+ char buf[64];
+
+ if (!len || len > sizeof(buf) - 1)
+ return -EINVAL;
+
+ if (copy_from_user(buf, ubuf, len))
+ return -EFAULT;
+ buf[len] = '\0';
+
+ if (sscanf(buf, "%u %i", &arg.freq_mhz, &bitmap) != 2)
+ return -EINVAL;
+
+ if (!arg.freq_mhz)
+ return -EINVAL;
+
+ ieee80211_iter_chan_contexts_atomic(data->hw,
+ hwsim_6ghz_chanctx_iter,
+ &arg);
+
+ if (!arg.conf)
+ return -EINVAL;
+
+ cfg80211_incumbent_signal_notify(data->hw->wiphy,
+ &arg.conf->def,
+ bitmap,
+ GFP_KERNEL);
+
+ return len;
+}
+
+static const struct file_operations hwsim_simulate_incumbent_signal_fops = {
+ .open = simple_open,
+ .write = hwsim_simulate_incumbent_signal_write,
+};
+
static int hwsim_fops_group_read(void *dat, u64 *val)
{
struct mac80211_hwsim_data *data = dat;
@@ -1229,6 +1339,11 @@ static void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw,
/* MLD not supported here */
u32 bcn_int = data->link_data[0].beacon_int;
u64 delta = abs(tsf - now);
+ struct ieee80211_bss_conf *conf;
+
+ conf = link_conf_dereference_protected(vif, data->link_data[0].link_id);
+ if (conf && !conf->enable_beacon)
+ return;
/* adjust after beaconing with new timestamp at old TBTT */
if (tsf > now) {
@@ -1639,6 +1754,16 @@ static void mac80211_hwsim_tx_iter(void *_data, u8 *addr,
struct tx_iter_data *data = _data;
int i;
+ /* For NAN Device simulation purposes, assume that NAN is always
+ * on channel 6 or channel 149.
+ */
+ if (vif->type == NL80211_IFTYPE_NAN) {
+ data->receive = (data->channel &&
+ (data->channel->center_freq == 2437 ||
+ data->channel->center_freq == 5745));
+ return;
+ }
+
for (i = 0; i < ARRAY_SIZE(vif->link_conf); i++) {
struct ieee80211_bss_conf *conf;
struct ieee80211_chanctx_conf *chanctx;
@@ -1930,6 +2055,25 @@ mac80211_hwsim_select_tx_link(struct mac80211_hwsim_data *data,
return NULL;
}
+static int mac80211_hwsim_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key)
+{
+ switch (key->cipher) {
+ case WLAN_CIPHER_SUITE_CCMP:
+ case WLAN_CIPHER_SUITE_CCMP_256:
+ case WLAN_CIPHER_SUITE_GCMP:
+ case WLAN_CIPHER_SUITE_GCMP_256:
+ break;
+ default:
+ return 1;
+ }
+
+ key->flags |= IEEE80211_KEY_FLAG_RESERVE_TAILROOM;
+ return 0;
+}
+
static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
struct ieee80211_tx_control *control,
struct sk_buff *skb)
@@ -1939,7 +2083,8 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr = (void *)skb->data;
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_channel *channel;
- bool ack;
+ struct ieee80211_vif *vif = txi->control.vif;
+ bool ack, unicast_data;
enum nl80211_chan_width confbw = NL80211_CHAN_WIDTH_20_NOHT;
u32 _portid, i;
@@ -1949,7 +2094,33 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
return;
}
- if (!data->use_chanctx) {
+ unicast_data = is_unicast_ether_addr(hdr->addr1) &&
+ ieee80211_is_data(hdr->frame_control);
+
+ if (unicast_data && ieee80211_encrypt_tx_skb(skb) < 0) {
+ ieee80211_free_txskb(hw, skb);
+ return;
+ }
+ /* re-assign hdr since skb data may have shifted after encryption */
+ hdr = (void *)skb->data;
+
+ if (vif && vif->type == NL80211_IFTYPE_NAN && !data->tmp_chan) {
+ /* For NAN Device simulation purposes, assume that NAN is always
+ * on channel 6 or channel 149, unless a ROC is in progress (for
+ * USD use cases).
+ */
+ if (data->nan_curr_dw_band == NL80211_BAND_2GHZ)
+ channel = ieee80211_get_channel(hw->wiphy, 2437);
+ else if (data->nan_curr_dw_band == NL80211_BAND_5GHZ)
+ channel = ieee80211_get_channel(hw->wiphy, 5745);
+ else
+ channel = NULL;
+
+ if (WARN_ON(!channel)) {
+ ieee80211_free_txskb(hw, skb);
+ return;
+ }
+ } else if (!data->use_chanctx) {
channel = data->channel;
confbw = data->bw;
} else if (txi->hw_queue == 4) {
@@ -1957,13 +2128,18 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
} else {
u8 link = u32_get_bits(IEEE80211_SKB_CB(skb)->control.flags,
IEEE80211_TX_CTRL_MLO_LINK);
- struct ieee80211_vif *vif = txi->control.vif;
struct ieee80211_link_sta *link_sta = NULL;
struct ieee80211_sta *sta = control->sta;
struct ieee80211_bss_conf *bss_conf;
+ /* This can happen in case of monitor injection */
+ if (!vif) {
+ ieee80211_free_txskb(hw, skb);
+ return;
+ }
+
if (link != IEEE80211_LINK_UNSPECIFIED) {
- bss_conf = rcu_dereference(txi->control.vif->link_conf[link]);
+ bss_conf = rcu_dereference(vif->link_conf[link]);
if (sta)
link_sta = rcu_dereference(sta->link[link]);
} else {
@@ -2013,6 +2189,13 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
}
}
+ if (!unicast_data && ieee80211_encrypt_tx_skb(skb) < 0) {
+ ieee80211_free_txskb(hw, skb);
+ return;
+ }
+ /* re-assign hdr since skb data may have shifted after encryption */
+ hdr = (void *)skb->data;
+
if (WARN(!channel, "TX w/o channel - queue = %d\n", txi->hw_queue)) {
ieee80211_free_txskb(hw, skb);
return;
@@ -2024,13 +2207,13 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
return;
}
- if (txi->control.vif)
- hwsim_check_magic(txi->control.vif);
+ if (vif)
+ hwsim_check_magic(vif);
if (control->sta)
hwsim_check_sta_magic(control->sta);
if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE))
- ieee80211_get_tx_rates(txi->control.vif, control->sta, skb,
+ ieee80211_get_tx_rates(vif, control->sta, skb,
txi->control.rates,
ARRAY_SIZE(txi->control.rates));
@@ -2273,7 +2456,7 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
{
struct mac80211_hwsim_link_data *link_data = arg;
u32 link_id = link_data->link_id;
- struct ieee80211_bss_conf *link_conf;
+ struct ieee80211_bss_conf *link_conf, *tx_bss_conf;
struct mac80211_hwsim_data *data =
container_of(link_data, struct mac80211_hwsim_data,
link_data[link_id]);
@@ -2292,10 +2475,11 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
vif->type != NL80211_IFTYPE_OCB)
return;
- if (vif->mbssid_tx_vif && vif->mbssid_tx_vif != vif)
+ tx_bss_conf = rcu_access_pointer(link_conf->tx_bss_conf);
+ if (tx_bss_conf && tx_bss_conf != link_conf)
return;
- if (vif->bss_conf.ema_ap) {
+ if (link_conf->ema_ap) {
struct ieee80211_ema_beacons *ema;
u8 i = 0;
@@ -2375,7 +2559,8 @@ static const char * const hwsim_chanwidths[] = {
[NL80211_CHAN_WIDTH_320] = "eht320",
};
-static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
+static int mac80211_hwsim_config(struct ieee80211_hw *hw, int radio_idx,
+ u32 changed)
{
struct mac80211_hwsim_data *data = hw->priv;
struct ieee80211_conf *conf = &hw->conf;
@@ -2972,7 +3157,6 @@ static void hw_scan_work(struct work_struct *work)
hwsim->tmp_chan->band,
NULL)) {
rcu_read_unlock();
- kfree_skb(probe);
continue;
}
@@ -3332,7 +3516,8 @@ static int mac80211_hwsim_tx_last_beacon(struct ieee80211_hw *hw)
return 1;
}
-static int mac80211_hwsim_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
+static int mac80211_hwsim_set_rts_threshold(struct ieee80211_hw *hw,
+ int radio_idx, u32 value)
{
return -EOPNOTSUPP;
}
@@ -3942,6 +4127,186 @@ out:
return err;
}
+static enum hrtimer_restart
+mac80211_hwsim_nan_dw_start(struct hrtimer *timer)
+{
+ struct mac80211_hwsim_data *data =
+ container_of(timer, struct mac80211_hwsim_data,
+ nan_timer);
+ struct ieee80211_hw *hw = data->hw;
+ u64 orig_tsf = mac80211_hwsim_get_tsf(hw, NULL), tsf = orig_tsf;
+ u32 dw_int = 512 * 1024;
+ u64 until_dw;
+
+ if (!data->nan_device_vif)
+ return HRTIMER_NORESTART;
+
+ if (data->nan_bands & BIT(NL80211_BAND_5GHZ)) {
+ if (data->nan_curr_dw_band == NL80211_BAND_2GHZ) {
+ dw_int = 128 * 1024;
+ data->nan_curr_dw_band = NL80211_BAND_5GHZ;
+ } else if (data->nan_curr_dw_band == NL80211_BAND_5GHZ) {
+ data->nan_curr_dw_band = NL80211_BAND_2GHZ;
+ }
+ }
+
+ until_dw = dw_int - do_div(tsf, dw_int);
+
+ /* The timer might fire just before the actual DW, in which case
+ * update the timeout to the actual next DW
+ */
+ if (until_dw < dw_int / 2)
+ until_dw += dw_int;
+
+ /* The above do_div() call directly modifies the 'tsf' variable, thus,
+ * use a copy so that the print below would show the original TSF.
+ */
+ wiphy_debug(hw->wiphy,
+ "%s: tsf=%llx, curr_dw_band=%u, next_dw=%llu\n",
+ __func__, orig_tsf, data->nan_curr_dw_band,
+ until_dw);
+
+ hrtimer_forward_now(&data->nan_timer,
+ ns_to_ktime(until_dw * NSEC_PER_USEC));
+
+ if (data->notify_dw) {
+ struct ieee80211_channel *ch;
+ struct wireless_dev *wdev =
+ ieee80211_vif_to_wdev(data->nan_device_vif);
+
+ if (data->nan_curr_dw_band == NL80211_BAND_5GHZ)
+ ch = ieee80211_get_channel(hw->wiphy, 5745);
+ else
+ ch = ieee80211_get_channel(hw->wiphy, 2437);
+
+ cfg80211_next_nan_dw_notif(wdev, ch, GFP_ATOMIC);
+ }
+
+ return HRTIMER_RESTART;
+}
+
+static int mac80211_hwsim_start_nan(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct cfg80211_nan_conf *conf)
+{
+ struct mac80211_hwsim_data *data = hw->priv;
+ u64 tsf = mac80211_hwsim_get_tsf(hw, NULL);
+ u32 dw_int = 512 * 1000;
+ u64 until_dw = dw_int - do_div(tsf, dw_int);
+ struct wireless_dev *wdev = ieee80211_vif_to_wdev(vif);
+
+ if (vif->type != NL80211_IFTYPE_NAN)
+ return -EINVAL;
+
+ if (data->nan_device_vif)
+ return -EALREADY;
+
+ /* set this before starting the timer, as preemption might occur */
+ data->nan_device_vif = vif;
+ data->nan_bands = conf->bands;
+ data->nan_curr_dw_band = NL80211_BAND_2GHZ;
+
+ wiphy_debug(hw->wiphy, "nan_started, next_dw=%llu\n",
+ until_dw);
+
+ hrtimer_start(&data->nan_timer,
+ ns_to_ktime(until_dw * NSEC_PER_USEC),
+ HRTIMER_MODE_REL_SOFT);
+
+ if (!is_zero_ether_addr(conf->cluster_id) &&
+ is_zero_ether_addr(hwsim_nan_cluster_id)) {
+ memcpy(hwsim_nan_cluster_id, conf->cluster_id, ETH_ALEN);
+ } else if (is_zero_ether_addr(hwsim_nan_cluster_id)) {
+ hwsim_nan_cluster_id[0] = 0x50;
+ hwsim_nan_cluster_id[1] = 0x6f;
+ hwsim_nan_cluster_id[2] = 0x9a;
+ hwsim_nan_cluster_id[3] = 0x01;
+ hwsim_nan_cluster_id[4] = get_random_u8();
+ hwsim_nan_cluster_id[5] = get_random_u8();
+ }
+
+ data->notify_dw = conf->enable_dw_notification;
+
+ cfg80211_nan_cluster_joined(wdev, hwsim_nan_cluster_id, true,
+ GFP_KERNEL);
+
+ return 0;
+}
+
+static int mac80211_hwsim_stop_nan(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct mac80211_hwsim_data *data = hw->priv;
+ struct mac80211_hwsim_data *data2;
+ bool nan_cluster_running = false;
+
+ if (vif->type != NL80211_IFTYPE_NAN || !data->nan_device_vif ||
+ data->nan_device_vif != vif)
+ return -EINVAL;
+
+ hrtimer_cancel(&data->nan_timer);
+ data->nan_device_vif = NULL;
+
+ spin_lock_bh(&hwsim_radio_lock);
+ list_for_each_entry(data2, &hwsim_radios, list) {
+ if (data2->nan_device_vif) {
+ nan_cluster_running = true;
+ break;
+ }
+ }
+ spin_unlock_bh(&hwsim_radio_lock);
+
+ if (!nan_cluster_running)
+ memset(hwsim_nan_cluster_id, 0, ETH_ALEN);
+
+ return 0;
+}
+
+static int mac80211_hwsim_change_nan_config(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct cfg80211_nan_conf *conf,
+ u32 changes)
+{
+ struct mac80211_hwsim_data *data = hw->priv;
+
+ if (vif->type != NL80211_IFTYPE_NAN)
+ return -EINVAL;
+
+ if (!data->nan_device_vif)
+ return -EINVAL;
+
+ wiphy_debug(hw->wiphy, "nan_config_changed: changes=0x%x\n", changes);
+
+ /* Handle only the changes we care about for simulation purposes */
+ if (changes & CFG80211_NAN_CONF_CHANGED_BANDS) {
+ data->nan_bands = conf->bands;
+ data->nan_curr_dw_band = NL80211_BAND_2GHZ;
+ }
+
+ if (changes & CFG80211_NAN_CONF_CHANGED_CONFIG)
+ data->notify_dw = conf->enable_dw_notification;
+
+ return 0;
+}
+
+static int mac80211_hwsim_set_radar_background(struct ieee80211_hw *hw,
+ struct cfg80211_chan_def *chan)
+{
+ struct mac80211_hwsim_data *data = hw->priv;
+
+ if (!wiphy_ext_feature_isset(hw->wiphy,
+ NL80211_EXT_FEATURE_RADAR_BACKGROUND))
+ return -EOPNOTSUPP;
+
+ if (chan)
+ data->radar_background_chandef = *chan;
+ else
+ memset(&data->radar_background_chandef, 0,
+ sizeof(data->radar_background_chandef));
+
+ return 0;
+}
+
#ifdef CONFIG_MAC80211_DEBUGFS
#define HWSIM_DEBUGFS_OPS \
.link_add_debugfs = mac80211_hwsim_link_add_debugfs,
@@ -3974,6 +4339,11 @@ out:
.get_et_strings = mac80211_hwsim_get_et_strings, \
.start_pmsr = mac80211_hwsim_start_pmsr, \
.abort_pmsr = mac80211_hwsim_abort_pmsr, \
+ .start_nan = mac80211_hwsim_start_nan, \
+ .stop_nan = mac80211_hwsim_stop_nan, \
+ .nan_change_conf = mac80211_hwsim_change_nan_config, \
+ .set_radar_background = mac80211_hwsim_set_radar_background, \
+ .set_key = mac80211_hwsim_set_key, \
HWSIM_DEBUGFS_OPS
#define HWSIM_NON_MLO_OPS \
@@ -4039,6 +4409,8 @@ struct hwsim_new_radio_params {
u8 n_ciphers;
bool mlo;
const struct cfg80211_pmsr_capabilities *pmsr_capa;
+ bool nan_device;
+ bool background_radar;
};
static void hwsim_mcast_config_msg(struct sk_buff *mcast_skb,
@@ -4119,6 +4491,17 @@ static int append_radio_msg(struct sk_buff *skb, int id,
return ret;
}
+ if (param->nan_device) {
+ ret = nla_put_flag(skb, HWSIM_ATTR_SUPPORT_NAN_DEVICE);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (param->background_radar) {
+ ret = nla_put_flag(skb, HWSIM_ATTR_SUPPORT_BACKGROUND_RADAR);
+ if (ret < 0)
+ return ret;
+ }
return 0;
}
@@ -4257,6 +4640,11 @@ static const struct ieee80211_sband_iftype_data sband_capa_2ghz[] = {
},
/* PPE threshold information is not supported */
},
+ .uhr_cap = {
+ .has_uhr = true,
+ .phy.cap = IEEE80211_UHR_PHY_CAP_ELR_RX |
+ IEEE80211_UHR_PHY_CAP_ELR_TX,
+ },
},
{
.types_mask = BIT(NL80211_IFTYPE_AP) |
@@ -4365,6 +4753,11 @@ static const struct ieee80211_sband_iftype_data sband_capa_2ghz[] = {
},
/* PPE threshold information is not supported */
},
+ .uhr_cap = {
+ .has_uhr = true,
+ .phy.cap = IEEE80211_UHR_PHY_CAP_ELR_RX |
+ IEEE80211_UHR_PHY_CAP_ELR_TX,
+ },
},
#ifdef CONFIG_MAC80211_MESH
{
@@ -4534,6 +4927,11 @@ static const struct ieee80211_sband_iftype_data sband_capa_5ghz[] = {
},
/* PPE threshold information is not supported */
},
+ .uhr_cap = {
+ .has_uhr = true,
+ .phy.cap = IEEE80211_UHR_PHY_CAP_ELR_RX |
+ IEEE80211_UHR_PHY_CAP_ELR_TX,
+ },
},
{
.types_mask = BIT(NL80211_IFTYPE_AP) |
@@ -4659,6 +5057,11 @@ static const struct ieee80211_sband_iftype_data sband_capa_5ghz[] = {
},
/* PPE threshold information is not supported */
},
+ .uhr_cap = {
+ .has_uhr = true,
+ .phy.cap = IEEE80211_UHR_PHY_CAP_ELR_RX |
+ IEEE80211_UHR_PHY_CAP_ELR_TX,
+ },
},
#ifdef CONFIG_MAC80211_MESH
{
@@ -4852,6 +5255,11 @@ static const struct ieee80211_sband_iftype_data sband_capa_6ghz[] = {
},
/* PPE threshold information is not supported */
},
+ .uhr_cap = {
+ .has_uhr = true,
+ .phy.cap = IEEE80211_UHR_PHY_CAP_ELR_RX |
+ IEEE80211_UHR_PHY_CAP_ELR_TX,
+ },
},
{
.types_mask = BIT(NL80211_IFTYPE_AP) |
@@ -4998,6 +5406,11 @@ static const struct ieee80211_sband_iftype_data sband_capa_6ghz[] = {
},
/* PPE threshold information is not supported */
},
+ .uhr_cap = {
+ .has_uhr = true,
+ .phy.cap = IEEE80211_UHR_PHY_CAP_ELR_RX |
+ IEEE80211_UHR_PHY_CAP_ELR_TX,
+ },
},
#ifdef CONFIG_MAC80211_MESH
{
@@ -5089,6 +5502,11 @@ static const struct ieee80211_sband_iftype_data sband_capa_6ghz[] = {
},
/* PPE threshold information is not supported */
},
+ .uhr_cap = {
+ .has_uhr = true,
+ .phy.cap = IEEE80211_UHR_PHY_CAP_ELR_RX |
+ IEEE80211_UHR_PHY_CAP_ELR_TX,
+ },
},
#endif
};
@@ -5203,7 +5621,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
data = hw->priv;
data->hw = hw;
- data->dev = device_create(hwsim_class, NULL, 0, hw, "hwsim%d", idx);
+ data->dev = device_create(&hwsim_class, NULL, 0, hw, "hwsim%d", idx);
if (IS_ERR(data->dev)) {
printk(KERN_DEBUG
"mac80211_hwsim: device_create failed (%ld)\n",
@@ -5231,14 +5649,18 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
/* Why need here second address ? */
memcpy(data->addresses[1].addr, addr, ETH_ALEN);
data->addresses[1].addr[0] |= 0x40;
- hw->wiphy->n_addresses = 2;
+ memcpy(data->addresses[2].addr, addr, ETH_ALEN);
+ data->addresses[2].addr[0] |= 0x50;
+
+ hw->wiphy->n_addresses = 3;
hw->wiphy->addresses = data->addresses;
/* possible address clash is checked at hash table insertion */
} else {
memcpy(data->addresses[0].addr, param->perm_addr, ETH_ALEN);
/* compatibility with automatically generated mac addr */
memcpy(data->addresses[1].addr, param->perm_addr, ETH_ALEN);
- hw->wiphy->n_addresses = 2;
+ memcpy(data->addresses[2].addr, param->perm_addr, ETH_ALEN);
+ hw->wiphy->n_addresses = 3;
hw->wiphy->addresses = data->addresses;
}
@@ -5275,6 +5697,30 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
n_limits++;
}
+ if (param->iftypes & BIT(NL80211_IFTYPE_NAN)) {
+ data->if_limits[n_limits].max = 1;
+ data->if_limits[n_limits].types = BIT(NL80211_IFTYPE_NAN);
+ n_limits++;
+
+ hw->wiphy->nan_supported_bands = BIT(NL80211_BAND_2GHZ) |
+ BIT(NL80211_BAND_5GHZ);
+
+ hw->wiphy->nan_capa.flags = WIPHY_NAN_FLAGS_CONFIGURABLE_SYNC |
+ WIPHY_NAN_FLAGS_USERSPACE_DE;
+ hw->wiphy->nan_capa.op_mode = NAN_OP_MODE_PHY_MODE_MASK |
+ NAN_OP_MODE_80P80MHZ |
+ NAN_OP_MODE_160MHZ;
+
+ hw->wiphy->nan_capa.n_antennas = 0x22;
+ hw->wiphy->nan_capa.max_channel_switch_time = 0;
+ hw->wiphy->nan_capa.dev_capabilities =
+ NAN_DEV_CAPA_EXT_KEY_ID_SUPPORTED |
+ NAN_DEV_CAPA_NDPE_SUPPORTED;
+
+ hrtimer_setup(&data->nan_timer, mac80211_hwsim_nan_dw_start,
+ CLOCK_MONOTONIC, HRTIMER_MODE_ABS_SOFT);
+ }
+
data->if_combination.radar_detect_widths =
BIT(NL80211_CHAN_WIDTH_5) |
BIT(NL80211_CHAN_WIDTH_10) |
@@ -5372,11 +5818,13 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
WIPHY_FLAG_AP_UAPSD |
WIPHY_FLAG_SUPPORTS_5_10_MHZ |
WIPHY_FLAG_HAS_CHANNEL_SWITCH;
+ hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR |
NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE |
NL80211_FEATURE_STATIC_SMPS |
NL80211_FEATURE_DYNAMIC_SMPS |
- NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
+ NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR |
+ NL80211_FEATURE_AP_SCAN;
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_BEACON_PROTECTION);
wiphy_ext_feature_set(hw->wiphy,
@@ -5389,6 +5837,14 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT);
wiphy_ext_feature_set(hw->wiphy,
NL80211_EXT_FEATURE_BSS_COLOR);
+ wiphy_ext_feature_set(hw->wiphy,
+ NL80211_EXT_FEATURE_SPP_AMSDU_SUPPORT);
+ wiphy_ext_feature_set(hw->wiphy,
+ NL80211_EXT_FEATURE_CAN_REPLACE_PTK0);
+ wiphy_ext_feature_set(hw->wiphy,
+ NL80211_EXT_FEATURE_EXT_KEY_ID);
+ wiphy_ext_feature_set(hw->wiphy,
+ NL80211_EXT_FEATURE_ASSOC_FRAME_ENCRYPTION);
hw->wiphy->interface_modes = param->iftypes;
@@ -5544,11 +6000,15 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
wiphy_ext_feature_set(hw->wiphy,
NL80211_EXT_FEATURE_DFS_CONCURRENT);
+ if (param->background_radar)
+ wiphy_ext_feature_set(hw->wiphy,
+ NL80211_EXT_FEATURE_RADAR_BACKGROUND);
if (param->no_vif)
ieee80211_hw_set(hw, NO_AUTO_VIF);
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+ wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_PUNCT);
for (i = 0; i < ARRAY_SIZE(data->link_data); i++) {
hrtimer_setup(&data->link_data[i].beacon_timer, mac80211_hwsim_beacon,
@@ -5581,6 +6041,13 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
debugfs_create_file("dfs_simulate_radar", 0222,
data->debugfs,
data, &hwsim_simulate_radar);
+ if (param->background_radar)
+ debugfs_create_file("dfs_background_cac", 0200,
+ data->debugfs,
+ data, &hwsim_background_cac_ops);
+ debugfs_create_file("simulate_incumbent_signal_interference", 0200,
+ data->debugfs,
+ data, &hwsim_simulate_incumbent_signal_fops);
if (param->pmsr_capa) {
data->pmsr_capa = *param->pmsr_capa;
@@ -5692,11 +6159,16 @@ static int mac80211_hwsim_get_radio(struct sk_buff *skb,
REGULATORY_STRICT_REG);
param.p2p_device = !!(data->hw->wiphy->interface_modes &
BIT(NL80211_IFTYPE_P2P_DEVICE));
+ param.nan_device = !!(data->hw->wiphy->interface_modes &
+ BIT(NL80211_IFTYPE_NAN));
param.use_chanctx = data->use_chanctx;
param.regd = data->regd;
param.channels = data->channels;
param.hwname = wiphy_name(data->hw->wiphy);
param.pmsr_capa = &data->pmsr_capa;
+ param.background_radar =
+ wiphy_ext_feature_isset(data->hw->wiphy,
+ NL80211_EXT_FEATURE_RADAR_BACKGROUND);
res = append_radio_msg(skb, data->idx, &param);
if (res < 0)
@@ -5725,7 +6197,7 @@ static void mac80211_hwsim_free(void)
spin_lock_bh(&hwsim_radio_lock);
}
spin_unlock_bh(&hwsim_radio_lock);
- class_destroy(hwsim_class);
+ class_unregister(&hwsim_class);
}
static const struct net_device_ops hwsim_netdev_ops = {
@@ -6110,6 +6582,7 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info)
param.reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG];
param.p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE];
+ param.nan_device = info->attrs[HWSIM_ATTR_SUPPORT_NAN_DEVICE];
param.channels = channels;
param.destroy_on_close =
info->attrs[HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE];
@@ -6133,6 +6606,9 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info)
if (info->attrs[HWSIM_ATTR_MULTI_RADIO])
param.multi_radio = true;
+ if (info->attrs[HWSIM_ATTR_SUPPORT_BACKGROUND_RADAR])
+ param.background_radar = true;
+
if (info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2])
param.reg_alpha2 =
nla_data(info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]);
@@ -6181,6 +6657,13 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info)
param.p2p_device = true;
}
+ /* ensure both flag and iftype support is honored */
+ if (param.nan_device ||
+ param.iftypes & BIT(NL80211_IFTYPE_NAN)) {
+ param.iftypes |= BIT(NL80211_IFTYPE_NAN);
+ param.nan_device = true;
+ }
+
if (info->attrs[HWSIM_ATTR_CIPHER_SUPPORT]) {
u32 len = nla_len(info->attrs[HWSIM_ATTR_CIPHER_SUPPORT]);
@@ -6228,7 +6711,7 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info)
if (info->attrs[HWSIM_ATTR_PMSR_SUPPORT]) {
struct cfg80211_pmsr_capabilities *pmsr_capa;
- pmsr_capa = kmalloc(sizeof(*pmsr_capa), GFP_KERNEL);
+ pmsr_capa = kzalloc_obj(*pmsr_capa);
if (!pmsr_capa) {
ret = -ENOMEM;
goto out_free;
@@ -6444,14 +6927,15 @@ static struct genl_family hwsim_genl_family __ro_after_init = {
.n_mcgrps = ARRAY_SIZE(hwsim_mcgrps),
};
-static void remove_user_radios(u32 portid)
+static void remove_user_radios(u32 portid, int netgroup)
{
struct mac80211_hwsim_data *entry, *tmp;
LIST_HEAD(list);
spin_lock_bh(&hwsim_radio_lock);
list_for_each_entry_safe(entry, tmp, &hwsim_radios, list) {
- if (entry->destroy_on_close && entry->portid == portid) {
+ if (entry->destroy_on_close && entry->portid == portid &&
+ entry->netgroup == netgroup) {
list_move(&entry->list, &list);
rhashtable_remove_fast(&hwsim_radios_rht, &entry->rht,
hwsim_rht_params);
@@ -6476,7 +6960,7 @@ static int mac80211_hwsim_netlink_notify(struct notifier_block *nb,
if (state != NETLINK_URELEASE)
return NOTIFY_DONE;
- remove_user_radios(notify->portid);
+ remove_user_radios(notify->portid, hwsim_net_get_netgroup(notify->net));
if (notify->portid == hwsim_net_get_wmediumd(notify->net)) {
printk(KERN_INFO "mac80211_hwsim: wmediumd released netlink"
@@ -6821,11 +7305,9 @@ static int __init init_mac80211_hwsim(void)
if (err)
goto out_exit_netlink;
- hwsim_class = class_create("mac80211_hwsim");
- if (IS_ERR(hwsim_class)) {
- err = PTR_ERR(hwsim_class);
+ err = class_register(&hwsim_class);
+ if (err)
goto out_exit_virtio;
- }
hwsim_init_s1g_channels(hwsim_channels_s1g);
@@ -6903,6 +7385,7 @@ static int __init init_mac80211_hwsim(void)
param.p2p_device = support_p2p_device;
param.mlo = mlo;
param.multi_radio = multi_radio;
+ param.background_radar = true;
param.use_chanctx = channels > 1 || mlo || multi_radio;
param.iftypes = HWSIM_IFTYPE_SUPPORT_MASK;
if (param.p2p_device)
diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.h b/drivers/net/wireless/virtual/mac80211_hwsim.h
index f32fc3a492b0..a022cd5c0f1c 100644
--- a/drivers/net/wireless/virtual/mac80211_hwsim.h
+++ b/drivers/net/wireless/virtual/mac80211_hwsim.h
@@ -3,7 +3,7 @@
* mac80211_hwsim - software simulator of 802.11 radio(s) for mac80211
* Copyright (c) 2008, Jouni Malinen <j@w1.fi>
* Copyright (c) 2011, Javier Lopez <jlopex@gmail.com>
- * Copyright (C) 2020, 2022-2024 Intel Corporation
+ * Copyright (C) 2020, 2022-2025 Intel Corporation
*/
#ifndef __MAC80211_HWSIM_H
@@ -62,7 +62,7 @@ enum hwsim_tx_control_flags {
* @HWSIM_CMD_TX_INFO_FRAME: Transmission info report from user space to
* kernel, uses:
* %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_FLAGS,
- * %HWSIM_ATTR_TX_INFO, %WSIM_ATTR_TX_INFO_FLAGS,
+ * %HWSIM_ATTR_TX_INFO, %HWSIM_ATTR_TX_INFO_FLAGS,
* %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE
* @HWSIM_CMD_NEW_RADIO: create a new radio with the given parameters,
* returns the radio ID (>= 0) or negative on errors, if successful
@@ -126,24 +126,24 @@ enum hwsim_commands {
* 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
+ * @HWSIM_ATTR_CHANNELS: u32 attribute used with the %HWSIM_CMD_NEW_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_REG_HINT_ALPHA2: alpha2 for regulatoro driver hint
+ * @HWSIM_ATTR_REG_HINT_ALPHA2: alpha2 for regulatory driver hint
* (nla string, length 2)
* @HWSIM_ATTR_REG_CUSTOM_REG: custom regulatory domain index (u32 attribute)
* @HWSIM_ATTR_REG_STRICT_REG: request REGULATORY_STRICT_REG (flag attribute)
* @HWSIM_ATTR_SUPPORT_P2P_DEVICE: support P2P Device virtual interface (flag)
- * @HWSIM_ATTR_USE_CHANCTX: used with the %HWSIM_CMD_CREATE_RADIO
+ * @HWSIM_ATTR_USE_CHANCTX: used with the %HWSIM_CMD_NEW_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
+ * @HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE: used with the %HWSIM_CMD_NEW_RADIO
* command to force radio removal when process that created the radio dies
* @HWSIM_ATTR_RADIO_NAME: Name of radio, e.g. phy666
* @HWSIM_ATTR_NO_VIF: Do not create vif (wlanX) when creating radio.
- * @HWSIM_ATTR_PAD: padding attribute for 64-bit values, ignore
* @HWSIM_ATTR_FREQ: Frequency at which packet is transmitted or received.
+ * @HWSIM_ATTR_PAD: padding attribute for 64-bit values, ignore
* @HWSIM_ATTR_TX_INFO_FLAGS: additional flags for corresponding
* rates of %HWSIM_ATTR_TX_INFO
* @HWSIM_ATTR_PERM_ADDR: permanent mac address of new radio
@@ -151,7 +151,7 @@ enum hwsim_commands {
* @HWSIM_ATTR_CIPHER_SUPPORT: u32 array of supported cipher types
* @HWSIM_ATTR_MLO_SUPPORT: claim MLO support (exact parameters TBD) for
* the new radio
- * @HWSIM_ATTR_PMSR_SUPPORT: nested attribute used with %HWSIM_CMD_CREATE_RADIO
+ * @HWSIM_ATTR_PMSR_SUPPORT: nested attribute used with %HWSIM_CMD_NEW_RADIO
* to provide peer measurement capabilities. (nl80211_peer_measurement_attrs)
* @HWSIM_ATTR_PMSR_REQUEST: nested attribute used with %HWSIM_CMD_START_PMSR
* to provide details about peer measurement request (nl80211_peer_measurement_attrs)
@@ -160,6 +160,8 @@ enum hwsim_commands {
* @HWSIM_ATTR_MULTI_RADIO: Register multiple wiphy radios (flag).
* Adds one radio for each band. Number of supported channels will be set for
* each radio instead of for the wiphy.
+ * @HWSIM_ATTR_SUPPORT_NAN_DEVICE: support NAN Device virtual interface (flag)
+ * @HWSIM_ATTR_SUPPORT_BACKGROUND_RADAR: background radar/CAC support (flag)
* @__HWSIM_ATTR_MAX: enum limit
*/
enum hwsim_attrs {
@@ -193,6 +195,8 @@ enum hwsim_attrs {
HWSIM_ATTR_PMSR_REQUEST,
HWSIM_ATTR_PMSR_RESULT,
HWSIM_ATTR_MULTI_RADIO,
+ HWSIM_ATTR_SUPPORT_NAN_DEVICE,
+ HWSIM_ATTR_SUPPORT_BACKGROUND_RADAR,
__HWSIM_ATTR_MAX,
};
#define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1)
diff --git a/drivers/net/wireless/virtual/virt_wifi.c b/drivers/net/wireless/virtual/virt_wifi.c
index 1fffeff2190c..2335e45db8b8 100644
--- a/drivers/net/wireless/virtual/virt_wifi.c
+++ b/drivers/net/wireless/virtual/virt_wifi.c
@@ -277,7 +277,9 @@ static void virt_wifi_connect_complete(struct work_struct *work)
priv->is_connected = true;
/* Schedules an event that acquires the rtnl lock. */
- cfg80211_connect_result(priv->upperdev, requested_bss, NULL, 0, NULL, 0,
+ cfg80211_connect_result(priv->upperdev,
+ priv->is_connected ? fake_router_bssid : NULL,
+ NULL, 0, NULL, 0,
status, GFP_KERNEL);
netif_carrier_on(priv->upperdev);
}
@@ -318,9 +320,11 @@ static int virt_wifi_disconnect(struct wiphy *wiphy, struct net_device *netdev,
}
/* Called with the rtnl lock held. */
-static int virt_wifi_get_station(struct wiphy *wiphy, struct net_device *dev,
- const u8 *mac, struct station_info *sinfo)
+static int virt_wifi_get_station(struct wiphy *wiphy,
+ struct wireless_dev *wdev, const u8 *mac,
+ struct station_info *sinfo)
{
+ struct net_device *dev = wdev->netdev;
struct virt_wifi_netdev_priv *priv = netdev_priv(dev);
wiphy_debug(wiphy, "get_station\n");
@@ -343,10 +347,10 @@ static int virt_wifi_get_station(struct wiphy *wiphy, struct net_device *dev,
}
/* Called with the rtnl lock held. */
-static int virt_wifi_dump_station(struct wiphy *wiphy, struct net_device *dev,
+static int virt_wifi_dump_station(struct wiphy *wiphy, struct wireless_dev *wdev,
int idx, u8 *mac, struct station_info *sinfo)
{
- struct virt_wifi_netdev_priv *priv = netdev_priv(dev);
+ struct virt_wifi_netdev_priv *priv = netdev_priv(wdev->netdev);
wiphy_debug(wiphy, "dump_station\n");
@@ -354,7 +358,7 @@ static int virt_wifi_dump_station(struct wiphy *wiphy, struct net_device *dev,
return -ENOENT;
ether_addr_copy(mac, fake_router_bssid);
- return virt_wifi_get_station(wiphy, dev, fake_router_bssid, sinfo);
+ return virt_wifi_get_station(wiphy, wdev, fake_router_bssid, sinfo);
}
static const struct cfg80211_ops virt_wifi_cfg80211_ops = {
@@ -555,8 +559,7 @@ static int virt_wifi_newlink(struct net_device *dev,
eth_hw_addr_inherit(dev, priv->lowerdev);
netif_stacked_transfer_operstate(priv->lowerdev, dev);
- SET_NETDEV_DEV(dev, &priv->lowerdev->dev);
- dev->ieee80211_ptr = kzalloc(sizeof(*dev->ieee80211_ptr), GFP_KERNEL);
+ dev->ieee80211_ptr = kzalloc_obj(*dev->ieee80211_ptr);
if (!dev->ieee80211_ptr) {
err = -ENOMEM;