diff options
Diffstat (limited to 'drivers/net/wireless/virtual')
| -rw-r--r-- | drivers/net/wireless/virtual/mac80211_hwsim.c | 541 | ||||
| -rw-r--r-- | drivers/net/wireless/virtual/mac80211_hwsim.h | 20 | ||||
| -rw-r--r-- | drivers/net/wireless/virtual/virt_wifi.c | 19 |
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, ¶m); 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; |
