Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

wifi: mac80211_hwsim: Add simulation support for NAN device

Add support for simulating a NAN Device interface:

- Update interface limits to include support for NAN Device.
- Increase the number of supported HW addresses to allow unique
addresses for combination such as: station interface + P2P
Device interface + NAN Device interface.
- Declare support for NAN capabilities, specifically support for
NAN synchronization offload and NAN DE user space support.
- Add the relevant callbacks to support start/stop NAN Device
operation.
- Use a timer to simulate starting a Discovery Window (currently
the timer doesn't do much).
- Update the Tx path to simulate that the channel used for NAN
Device is either channel 6 or channel 149.
- Send DW notification when DW starts.
- Send cluster join notification when new cluster starts, or when an
existing cluster is joined. "Joining" is implemented by reusing the
cluster id of any other existing NAN management interface.

Signed-off-by: Ilan Peer <ilan.peer@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20250908140015.2d02d5be6468.I3badfdb80c29e7713bd37373650ccbf099547a59@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

authored by

Ilan Peer and committed by
Johannes Berg
a37a6f54 1d04fad3

+256 -7
+253 -6
drivers/net/wireless/virtual/mac80211_hwsim.c
··· 645 645 static struct rhashtable hwsim_radios_rht; 646 646 static int hwsim_radio_idx; 647 647 static int hwsim_radios_generation = 1; 648 + static u8 hwsim_nan_cluster_id[ETH_ALEN]; 648 649 649 650 static struct platform_driver mac80211_hwsim_driver = { 650 651 .driver = { ··· 671 670 struct ieee80211_channel channels_s1g[ARRAY_SIZE(hwsim_channels_s1g)]; 672 671 struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)]; 673 672 struct ieee80211_iface_combination if_combination; 674 - struct ieee80211_iface_limit if_limits[3]; 673 + struct ieee80211_iface_limit if_limits[4]; 675 674 int n_if_limits; 676 675 677 676 struct ieee80211_iface_combination if_combination_radio; ··· 680 679 681 680 u32 ciphers[ARRAY_SIZE(hwsim_ciphers)]; 682 681 683 - struct mac_address addresses[2]; 682 + struct mac_address addresses[3]; 684 683 int channels, idx; 685 684 bool use_chanctx; 686 685 bool destroy_on_close; ··· 753 752 struct wireless_dev *pmsr_request_wdev; 754 753 755 754 struct mac80211_hwsim_link_data link_data[IEEE80211_MLD_MAX_NUM_LINKS]; 755 + 756 + struct ieee80211_vif *nan_device_vif; 757 + u8 nan_bands; 758 + 759 + enum nl80211_band nan_curr_dw_band; 760 + struct hrtimer nan_timer; 761 + bool notify_dw; 762 + struct ieee80211_vif *nan_vif; 756 763 }; 757 764 758 765 static const struct rhashtable_params hwsim_rht_params = { ··· 935 926 [HWSIM_ATTR_PMSR_SUPPORT] = NLA_POLICY_NESTED(hwsim_pmsr_capa_policy), 936 927 [HWSIM_ATTR_PMSR_RESULT] = NLA_POLICY_NESTED(hwsim_pmsr_peers_result_policy), 937 928 [HWSIM_ATTR_MULTI_RADIO] = { .type = NLA_FLAG }, 929 + [HWSIM_ATTR_SUPPORT_NAN_DEVICE] = { .type = NLA_FLAG }, 938 930 }; 939 931 940 932 #if IS_REACHABLE(CONFIG_VIRTIO) ··· 1654 1644 struct tx_iter_data *data = _data; 1655 1645 int i; 1656 1646 1647 + /* For NAN Device simulation purposes, assume that NAN is always 1648 + * on channel 6 or channel 149. 1649 + */ 1650 + if (vif->type == NL80211_IFTYPE_NAN) { 1651 + data->receive = (data->channel && 1652 + (data->channel->center_freq == 2437 || 1653 + data->channel->center_freq == 5745)); 1654 + return; 1655 + } 1656 + 1657 1657 for (i = 0; i < ARRAY_SIZE(vif->link_conf); i++) { 1658 1658 struct ieee80211_bss_conf *conf; 1659 1659 struct ieee80211_chanctx_conf *chanctx; ··· 1964 1944 struct ieee80211_hdr *hdr = (void *)skb->data; 1965 1945 struct ieee80211_chanctx_conf *chanctx_conf; 1966 1946 struct ieee80211_channel *channel; 1947 + struct ieee80211_vif *vif = txi->control.vif; 1967 1948 bool ack; 1968 1949 enum nl80211_chan_width confbw = NL80211_CHAN_WIDTH_20_NOHT; 1969 1950 u32 _portid, i; ··· 1975 1954 return; 1976 1955 } 1977 1956 1978 - if (!data->use_chanctx) { 1957 + if (vif && vif->type == NL80211_IFTYPE_NAN && !data->tmp_chan) { 1958 + /* For NAN Device simulation purposes, assume that NAN is always 1959 + * on channel 6 or channel 149, unless a ROC is in progress (for 1960 + * USD use cases). 1961 + */ 1962 + if (data->nan_curr_dw_band == NL80211_BAND_2GHZ) 1963 + channel = ieee80211_get_channel(hw->wiphy, 2437); 1964 + else if (data->nan_curr_dw_band == NL80211_BAND_5GHZ) 1965 + channel = ieee80211_get_channel(hw->wiphy, 5745); 1966 + else 1967 + channel = NULL; 1968 + 1969 + if (WARN_ON(!channel)) { 1970 + ieee80211_free_txskb(hw, skb); 1971 + return; 1972 + } 1973 + } else if (!data->use_chanctx) { 1979 1974 channel = data->channel; 1980 1975 confbw = data->bw; 1981 1976 } else if (txi->hw_queue == 4) { ··· 1999 1962 } else { 2000 1963 u8 link = u32_get_bits(IEEE80211_SKB_CB(skb)->control.flags, 2001 1964 IEEE80211_TX_CTRL_MLO_LINK); 2002 - struct ieee80211_vif *vif = txi->control.vif; 2003 1965 struct ieee80211_link_sta *link_sta = NULL; 2004 1966 struct ieee80211_sta *sta = control->sta; 2005 1967 struct ieee80211_bss_conf *bss_conf; ··· 3986 3950 return err; 3987 3951 } 3988 3952 3953 + static enum hrtimer_restart 3954 + mac80211_hwsim_nan_dw_start(struct hrtimer *timer) 3955 + { 3956 + struct mac80211_hwsim_data *data = 3957 + container_of(timer, struct mac80211_hwsim_data, 3958 + nan_timer); 3959 + struct ieee80211_hw *hw = data->hw; 3960 + u64 orig_tsf = mac80211_hwsim_get_tsf(hw, NULL), tsf = orig_tsf; 3961 + u32 dw_int = 512 * 1024; 3962 + u64 until_dw; 3963 + 3964 + if (!data->nan_device_vif) 3965 + return HRTIMER_NORESTART; 3966 + 3967 + if (data->nan_bands & BIT(NL80211_BAND_5GHZ)) { 3968 + if (data->nan_curr_dw_band == NL80211_BAND_2GHZ) { 3969 + dw_int = 128 * 1024; 3970 + data->nan_curr_dw_band = NL80211_BAND_5GHZ; 3971 + } else if (data->nan_curr_dw_band == NL80211_BAND_5GHZ) { 3972 + data->nan_curr_dw_band = NL80211_BAND_2GHZ; 3973 + } 3974 + } 3975 + 3976 + until_dw = dw_int - do_div(tsf, dw_int); 3977 + 3978 + /* The timer might fire just before the actual DW, in which case 3979 + * update the timeout to the actual next DW 3980 + */ 3981 + if (until_dw < dw_int / 2) 3982 + until_dw += dw_int; 3983 + 3984 + /* The above do_div() call directly modifies the 'tsf' variable, thus, 3985 + * use a copy so that the print below would show the original TSF. 3986 + */ 3987 + wiphy_debug(hw->wiphy, 3988 + "%s: tsf=%llx, curr_dw_band=%u, next_dw=%llu\n", 3989 + __func__, orig_tsf, data->nan_curr_dw_band, 3990 + until_dw); 3991 + 3992 + hrtimer_forward_now(&data->nan_timer, 3993 + ns_to_ktime(until_dw * NSEC_PER_USEC)); 3994 + 3995 + if (data->notify_dw) { 3996 + struct ieee80211_channel *ch; 3997 + struct wireless_dev *wdev = 3998 + ieee80211_vif_to_wdev(data->nan_device_vif); 3999 + 4000 + if (data->nan_curr_dw_band == NL80211_BAND_5GHZ) 4001 + ch = ieee80211_get_channel(hw->wiphy, 5475); 4002 + else 4003 + ch = ieee80211_get_channel(hw->wiphy, 2437); 4004 + 4005 + cfg80211_next_nan_dw_notif(wdev, ch, GFP_ATOMIC); 4006 + } 4007 + 4008 + return HRTIMER_RESTART; 4009 + } 4010 + 4011 + static int mac80211_hwsim_start_nan(struct ieee80211_hw *hw, 4012 + struct ieee80211_vif *vif, 4013 + struct cfg80211_nan_conf *conf) 4014 + { 4015 + struct mac80211_hwsim_data *data = hw->priv; 4016 + u64 tsf = mac80211_hwsim_get_tsf(hw, NULL); 4017 + u32 dw_int = 512 * 1000; 4018 + u64 until_dw = dw_int - do_div(tsf, dw_int); 4019 + struct wireless_dev *wdev = ieee80211_vif_to_wdev(vif); 4020 + 4021 + if (vif->type != NL80211_IFTYPE_NAN) 4022 + return -EINVAL; 4023 + 4024 + if (data->nan_device_vif) 4025 + return -EALREADY; 4026 + 4027 + /* set this before starting the timer, as preemption might occur */ 4028 + data->nan_device_vif = vif; 4029 + data->nan_bands = conf->bands; 4030 + data->nan_curr_dw_band = NL80211_BAND_2GHZ; 4031 + 4032 + wiphy_debug(hw->wiphy, "nan_started, next_dw=%llu\n", 4033 + until_dw); 4034 + 4035 + hrtimer_start(&data->nan_timer, 4036 + ns_to_ktime(until_dw * NSEC_PER_USEC), 4037 + HRTIMER_MODE_REL_SOFT); 4038 + 4039 + if (conf->cluster_id && !is_zero_ether_addr(conf->cluster_id) && 4040 + is_zero_ether_addr(hwsim_nan_cluster_id)) { 4041 + memcpy(hwsim_nan_cluster_id, conf->cluster_id, ETH_ALEN); 4042 + } else if (is_zero_ether_addr(hwsim_nan_cluster_id)) { 4043 + hwsim_nan_cluster_id[0] = 0x50; 4044 + hwsim_nan_cluster_id[1] = 0x6f; 4045 + hwsim_nan_cluster_id[2] = 0x9a; 4046 + hwsim_nan_cluster_id[3] = 0x01; 4047 + hwsim_nan_cluster_id[4] = get_random_u8(); 4048 + hwsim_nan_cluster_id[5] = get_random_u8(); 4049 + } 4050 + 4051 + data->notify_dw = conf->enable_dw_notification; 4052 + 4053 + cfg80211_nan_cluster_joined(wdev, hwsim_nan_cluster_id, true, 4054 + GFP_KERNEL); 4055 + 4056 + return 0; 4057 + } 4058 + 4059 + static int mac80211_hwsim_stop_nan(struct ieee80211_hw *hw, 4060 + struct ieee80211_vif *vif) 4061 + { 4062 + struct mac80211_hwsim_data *data = hw->priv; 4063 + struct mac80211_hwsim_data *data2; 4064 + bool nan_cluster_running = false; 4065 + 4066 + if (vif->type != NL80211_IFTYPE_NAN || !data->nan_device_vif || 4067 + data->nan_device_vif != vif) 4068 + return -EINVAL; 4069 + 4070 + hrtimer_cancel(&data->nan_timer); 4071 + data->nan_device_vif = NULL; 4072 + 4073 + spin_lock(&hwsim_radio_lock); 4074 + list_for_each_entry(data2, &hwsim_radios, list) { 4075 + if (data2->nan_device_vif) { 4076 + nan_cluster_running = true; 4077 + break; 4078 + } 4079 + } 4080 + spin_unlock(&hwsim_radio_lock); 4081 + 4082 + if (!nan_cluster_running) 4083 + memset(hwsim_nan_cluster_id, 0, ETH_ALEN); 4084 + 4085 + return 0; 4086 + } 4087 + 4088 + static int mac80211_hwsim_change_nan_config(struct ieee80211_hw *hw, 4089 + struct ieee80211_vif *vif, 4090 + struct cfg80211_nan_conf *conf, 4091 + u32 changes) 4092 + { 4093 + struct mac80211_hwsim_data *data = hw->priv; 4094 + 4095 + if (vif->type != NL80211_IFTYPE_NAN) 4096 + return -EINVAL; 4097 + 4098 + if (!data->nan_device_vif) 4099 + return -EINVAL; 4100 + 4101 + wiphy_debug(hw->wiphy, "nan_config_changed: changes=0x%x\n", changes); 4102 + 4103 + /* Handle only the changes we care about for simulation purposes */ 4104 + if (changes & CFG80211_NAN_CONF_CHANGED_BANDS) { 4105 + data->nan_bands = conf->bands; 4106 + data->nan_curr_dw_band = NL80211_BAND_2GHZ; 4107 + } 4108 + 4109 + if (changes & CFG80211_NAN_CONF_CHANGED_CONFIG) 4110 + data->notify_dw = conf->enable_dw_notification; 4111 + 4112 + return 0; 4113 + } 4114 + 3989 4115 #ifdef CONFIG_MAC80211_DEBUGFS 3990 4116 #define HWSIM_DEBUGFS_OPS \ 3991 4117 .link_add_debugfs = mac80211_hwsim_link_add_debugfs, ··· 4180 3982 .get_et_strings = mac80211_hwsim_get_et_strings, \ 4181 3983 .start_pmsr = mac80211_hwsim_start_pmsr, \ 4182 3984 .abort_pmsr = mac80211_hwsim_abort_pmsr, \ 3985 + .start_nan = mac80211_hwsim_start_nan, \ 3986 + .stop_nan = mac80211_hwsim_stop_nan, \ 3987 + .nan_change_conf = mac80211_hwsim_change_nan_config, \ 4183 3988 HWSIM_DEBUGFS_OPS 4184 3989 4185 3990 #define HWSIM_NON_MLO_OPS \ ··· 4248 4047 u8 n_ciphers; 4249 4048 bool mlo; 4250 4049 const struct cfg80211_pmsr_capabilities *pmsr_capa; 4050 + bool nan_device; 4251 4051 }; 4252 4052 4253 4053 static void hwsim_mcast_config_msg(struct sk_buff *mcast_skb, ··· 4329 4127 return ret; 4330 4128 } 4331 4129 4130 + if (param->nan_device) { 4131 + ret = nla_put_flag(skb, HWSIM_ATTR_SUPPORT_NAN_DEVICE); 4132 + if (ret < 0) 4133 + return ret; 4134 + } 4332 4135 return 0; 4333 4136 } 4334 4137 ··· 5446 5239 /* Why need here second address ? */ 5447 5240 memcpy(data->addresses[1].addr, addr, ETH_ALEN); 5448 5241 data->addresses[1].addr[0] |= 0x40; 5449 - hw->wiphy->n_addresses = 2; 5242 + memcpy(data->addresses[2].addr, addr, ETH_ALEN); 5243 + data->addresses[2].addr[0] |= 0x50; 5244 + 5245 + hw->wiphy->n_addresses = 3; 5450 5246 hw->wiphy->addresses = data->addresses; 5451 5247 /* possible address clash is checked at hash table insertion */ 5452 5248 } else { 5453 5249 memcpy(data->addresses[0].addr, param->perm_addr, ETH_ALEN); 5454 5250 /* compatibility with automatically generated mac addr */ 5455 5251 memcpy(data->addresses[1].addr, param->perm_addr, ETH_ALEN); 5456 - hw->wiphy->n_addresses = 2; 5252 + memcpy(data->addresses[2].addr, param->perm_addr, ETH_ALEN); 5253 + hw->wiphy->n_addresses = 3; 5457 5254 hw->wiphy->addresses = data->addresses; 5458 5255 } 5459 5256 ··· 5492 5281 data->if_limits[n_limits].types = 5493 5282 BIT(NL80211_IFTYPE_P2P_DEVICE); 5494 5283 n_limits++; 5284 + } 5285 + 5286 + if (param->iftypes & BIT(NL80211_IFTYPE_NAN)) { 5287 + data->if_limits[n_limits].max = 1; 5288 + data->if_limits[n_limits].types = BIT(NL80211_IFTYPE_NAN); 5289 + n_limits++; 5290 + 5291 + hw->wiphy->nan_supported_bands = BIT(NL80211_BAND_2GHZ) | 5292 + BIT(NL80211_BAND_5GHZ); 5293 + 5294 + hw->wiphy->nan_capa.flags = WIPHY_NAN_FLAGS_CONFIGURABLE_SYNC | 5295 + WIPHY_NAN_FLAGS_USERSPACE_DE; 5296 + hw->wiphy->nan_capa.op_mode = NAN_OP_MODE_PHY_MODE_MASK | 5297 + NAN_OP_MODE_80P80MHZ | 5298 + NAN_OP_MODE_160MHZ; 5299 + 5300 + hw->wiphy->nan_capa.n_antennas = 0x22; 5301 + hw->wiphy->nan_capa.max_channel_switch_time = 0; 5302 + hw->wiphy->nan_capa.dev_capabilities = 5303 + NAN_DEV_CAPA_EXT_KEY_ID_SUPPORTED | 5304 + NAN_DEV_CAPA_NDPE_SUPPORTED; 5305 + 5306 + hrtimer_setup(&data->nan_timer, mac80211_hwsim_nan_dw_start, 5307 + CLOCK_MONOTONIC, HRTIMER_MODE_ABS_SOFT); 5495 5308 } 5496 5309 5497 5310 data->if_combination.radar_detect_widths = ··· 5936 5701 REGULATORY_STRICT_REG); 5937 5702 param.p2p_device = !!(data->hw->wiphy->interface_modes & 5938 5703 BIT(NL80211_IFTYPE_P2P_DEVICE)); 5704 + param.nan_device = !!(data->hw->wiphy->interface_modes & 5705 + BIT(NL80211_IFTYPE_NAN)); 5939 5706 param.use_chanctx = data->use_chanctx; 5940 5707 param.regd = data->regd; 5941 5708 param.channels = data->channels; ··· 6356 6119 6357 6120 param.reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG]; 6358 6121 param.p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE]; 6122 + param.nan_device = info->attrs[HWSIM_ATTR_SUPPORT_NAN_DEVICE]; 6359 6123 param.channels = channels; 6360 6124 param.destroy_on_close = 6361 6125 info->attrs[HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE]; ··· 6426 6188 param.iftypes & BIT(NL80211_IFTYPE_P2P_DEVICE)) { 6427 6189 param.iftypes |= BIT(NL80211_IFTYPE_P2P_DEVICE); 6428 6190 param.p2p_device = true; 6191 + } 6192 + 6193 + /* ensure both flag and iftype support is honored */ 6194 + if (param.nan_device || 6195 + param.iftypes & BIT(NL80211_IFTYPE_NAN)) { 6196 + param.iftypes |= BIT(NL80211_IFTYPE_NAN); 6197 + param.nan_device = true; 6429 6198 } 6430 6199 6431 6200 if (info->attrs[HWSIM_ATTR_CIPHER_SUPPORT]) { ··· 7155 6910 } 7156 6911 7157 6912 param.p2p_device = support_p2p_device; 6913 + param.nan_device = true; 7158 6914 param.mlo = mlo; 7159 6915 param.multi_radio = multi_radio; 7160 6916 param.use_chanctx = channels > 1 || mlo || multi_radio; 7161 6917 param.iftypes = HWSIM_IFTYPE_SUPPORT_MASK; 7162 6918 if (param.p2p_device) 7163 6919 param.iftypes |= BIT(NL80211_IFTYPE_P2P_DEVICE); 6920 + param.iftypes |= BIT(NL80211_IFTYPE_NAN); 7164 6921 7165 6922 err = mac80211_hwsim_new_radio(NULL, &param); 7166 6923 if (err < 0)
+3 -1
drivers/net/wireless/virtual/mac80211_hwsim.h
··· 3 3 * mac80211_hwsim - software simulator of 802.11 radio(s) for mac80211 4 4 * Copyright (c) 2008, Jouni Malinen <j@w1.fi> 5 5 * Copyright (c) 2011, Javier Lopez <jlopex@gmail.com> 6 - * Copyright (C) 2020, 2022-2024 Intel Corporation 6 + * Copyright (C) 2020, 2022-2025 Intel Corporation 7 7 */ 8 8 9 9 #ifndef __MAC80211_HWSIM_H ··· 160 160 * @HWSIM_ATTR_MULTI_RADIO: Register multiple wiphy radios (flag). 161 161 * Adds one radio for each band. Number of supported channels will be set for 162 162 * each radio instead of for the wiphy. 163 + * @HWSIM_ATTR_SUPPORT_NAN_DEVICE: support NAN Device virtual interface (flag) 163 164 * @__HWSIM_ATTR_MAX: enum limit 164 165 */ 165 166 enum hwsim_attrs { ··· 194 193 HWSIM_ATTR_PMSR_REQUEST, 195 194 HWSIM_ATTR_PMSR_RESULT, 196 195 HWSIM_ATTR_MULTI_RADIO, 196 + HWSIM_ATTR_SUPPORT_NAN_DEVICE, 197 197 __HWSIM_ATTR_MAX, 198 198 }; 199 199 #define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1)