1f79cbc77SKalle Valo // SPDX-License-Identifier: GPL-2.0-only 2f79cbc77SKalle Valo /* 3f79cbc77SKalle Valo * mac80211_hwsim - software simulator of 802.11 radio(s) for mac80211 4f79cbc77SKalle Valo * Copyright (c) 2008, Jouni Malinen <j@w1.fi> 5f79cbc77SKalle Valo * Copyright (c) 2011, Javier Lopez <jlopex@gmail.com> 6f79cbc77SKalle Valo * Copyright (c) 2016 - 2017 Intel Deutschland GmbH 7f79cbc77SKalle Valo * Copyright (C) 2018 - 2022 Intel Corporation 8f79cbc77SKalle Valo */ 9f79cbc77SKalle Valo 10f79cbc77SKalle Valo /* 11f79cbc77SKalle Valo * TODO: 12f79cbc77SKalle Valo * - Add TSF sync and fix IBSS beacon transmission by adding 13f79cbc77SKalle Valo * competition for "air time" at TBTT 14f79cbc77SKalle Valo * - RX filtering based on filter configuration (data->rx_filter) 15f79cbc77SKalle Valo */ 16f79cbc77SKalle Valo 17f79cbc77SKalle Valo #include <linux/list.h> 18f79cbc77SKalle Valo #include <linux/slab.h> 19f79cbc77SKalle Valo #include <linux/spinlock.h> 20f79cbc77SKalle Valo #include <net/dst.h> 21f79cbc77SKalle Valo #include <net/xfrm.h> 22f79cbc77SKalle Valo #include <net/mac80211.h> 23f79cbc77SKalle Valo #include <net/ieee80211_radiotap.h> 24f79cbc77SKalle Valo #include <linux/if_arp.h> 25f79cbc77SKalle Valo #include <linux/rtnetlink.h> 26f79cbc77SKalle Valo #include <linux/etherdevice.h> 27f79cbc77SKalle Valo #include <linux/platform_device.h> 28f79cbc77SKalle Valo #include <linux/debugfs.h> 29f79cbc77SKalle Valo #include <linux/module.h> 30f79cbc77SKalle Valo #include <linux/ktime.h> 31f79cbc77SKalle Valo #include <net/genetlink.h> 32f79cbc77SKalle Valo #include <net/net_namespace.h> 33f79cbc77SKalle Valo #include <net/netns/generic.h> 34f79cbc77SKalle Valo #include <linux/rhashtable.h> 35f79cbc77SKalle Valo #include <linux/nospec.h> 36f79cbc77SKalle Valo #include <linux/virtio.h> 37f79cbc77SKalle Valo #include <linux/virtio_ids.h> 38f79cbc77SKalle Valo #include <linux/virtio_config.h> 39f79cbc77SKalle Valo #include "mac80211_hwsim.h" 40f79cbc77SKalle Valo 41f79cbc77SKalle Valo #define WARN_QUEUE 100 42f79cbc77SKalle Valo #define MAX_QUEUE 200 43f79cbc77SKalle Valo 44f79cbc77SKalle Valo MODULE_AUTHOR("Jouni Malinen"); 45f79cbc77SKalle Valo MODULE_DESCRIPTION("Software simulator of 802.11 radio(s) for mac80211"); 46f79cbc77SKalle Valo MODULE_LICENSE("GPL"); 47f79cbc77SKalle Valo 48f79cbc77SKalle Valo static int radios = 2; 49f79cbc77SKalle Valo module_param(radios, int, 0444); 50f79cbc77SKalle Valo MODULE_PARM_DESC(radios, "Number of simulated radios"); 51f79cbc77SKalle Valo 52f79cbc77SKalle Valo static int channels = 1; 53f79cbc77SKalle Valo module_param(channels, int, 0444); 54f79cbc77SKalle Valo MODULE_PARM_DESC(channels, "Number of concurrent channels"); 55f79cbc77SKalle Valo 56f79cbc77SKalle Valo static bool paged_rx = false; 57f79cbc77SKalle Valo module_param(paged_rx, bool, 0644); 58f79cbc77SKalle Valo MODULE_PARM_DESC(paged_rx, "Use paged SKBs for RX instead of linear ones"); 59f79cbc77SKalle Valo 60f79cbc77SKalle Valo static bool rctbl = false; 61f79cbc77SKalle Valo module_param(rctbl, bool, 0444); 62f79cbc77SKalle Valo MODULE_PARM_DESC(rctbl, "Handle rate control table"); 63f79cbc77SKalle Valo 64f79cbc77SKalle Valo static bool support_p2p_device = true; 65f79cbc77SKalle Valo module_param(support_p2p_device, bool, 0444); 66f79cbc77SKalle Valo MODULE_PARM_DESC(support_p2p_device, "Support P2P-Device interface type"); 67f79cbc77SKalle Valo 68f79cbc77SKalle Valo static bool mlo; 69f79cbc77SKalle Valo module_param(mlo, bool, 0444); 70f79cbc77SKalle Valo MODULE_PARM_DESC(mlo, "Support MLO"); 71f79cbc77SKalle Valo 72f79cbc77SKalle Valo /** 73f79cbc77SKalle Valo * enum hwsim_regtest - the type of regulatory tests we offer 74f79cbc77SKalle Valo * 75f79cbc77SKalle Valo * These are the different values you can use for the regtest 76f79cbc77SKalle Valo * module parameter. This is useful to help test world roaming 77f79cbc77SKalle Valo * and the driver regulatory_hint() call and combinations of these. 78f79cbc77SKalle Valo * If you want to do specific alpha2 regulatory domain tests simply 79f79cbc77SKalle Valo * use the userspace regulatory request as that will be respected as 80f79cbc77SKalle Valo * well without the need of this module parameter. This is designed 81f79cbc77SKalle Valo * only for testing the driver regulatory request, world roaming 82f79cbc77SKalle Valo * and all possible combinations. 83f79cbc77SKalle Valo * 84f79cbc77SKalle Valo * @HWSIM_REGTEST_DISABLED: No regulatory tests are performed, 85f79cbc77SKalle Valo * this is the default value. 86f79cbc77SKalle Valo * @HWSIM_REGTEST_DRIVER_REG_FOLLOW: Used for testing the driver regulatory 87f79cbc77SKalle Valo * hint, only one driver regulatory hint will be sent as such the 88f79cbc77SKalle Valo * secondary radios are expected to follow. 89f79cbc77SKalle Valo * @HWSIM_REGTEST_DRIVER_REG_ALL: Used for testing the driver regulatory 90f79cbc77SKalle Valo * request with all radios reporting the same regulatory domain. 91f79cbc77SKalle Valo * @HWSIM_REGTEST_DIFF_COUNTRY: Used for testing the drivers calling 92f79cbc77SKalle Valo * different regulatory domains requests. Expected behaviour is for 93f79cbc77SKalle Valo * an intersection to occur but each device will still use their 94f79cbc77SKalle Valo * respective regulatory requested domains. Subsequent radios will 95f79cbc77SKalle Valo * use the resulting intersection. 96f79cbc77SKalle Valo * @HWSIM_REGTEST_WORLD_ROAM: Used for testing the world roaming. We accomplish 97f79cbc77SKalle Valo * this by using a custom beacon-capable regulatory domain for the first 98f79cbc77SKalle Valo * radio. All other device world roam. 99f79cbc77SKalle Valo * @HWSIM_REGTEST_CUSTOM_WORLD: Used for testing the custom world regulatory 100f79cbc77SKalle Valo * domain requests. All radios will adhere to this custom world regulatory 101f79cbc77SKalle Valo * domain. 102f79cbc77SKalle Valo * @HWSIM_REGTEST_CUSTOM_WORLD_2: Used for testing 2 custom world regulatory 103f79cbc77SKalle Valo * domain requests. The first radio will adhere to the first custom world 104f79cbc77SKalle Valo * regulatory domain, the second one to the second custom world regulatory 105f79cbc77SKalle Valo * domain. All other devices will world roam. 106f79cbc77SKalle Valo * @HWSIM_REGTEST_STRICT_FOLLOW: Used for testing strict regulatory domain 107f79cbc77SKalle Valo * settings, only the first radio will send a regulatory domain request 108f79cbc77SKalle Valo * and use strict settings. The rest of the radios are expected to follow. 109f79cbc77SKalle Valo * @HWSIM_REGTEST_STRICT_ALL: Used for testing strict regulatory domain 110f79cbc77SKalle Valo * settings. All radios will adhere to this. 111f79cbc77SKalle Valo * @HWSIM_REGTEST_STRICT_AND_DRIVER_REG: Used for testing strict regulatory 112f79cbc77SKalle Valo * domain settings, combined with secondary driver regulatory domain 113f79cbc77SKalle Valo * settings. The first radio will get a strict regulatory domain setting 114f79cbc77SKalle Valo * using the first driver regulatory request and the second radio will use 115f79cbc77SKalle Valo * non-strict settings using the second driver regulatory request. All 116f79cbc77SKalle Valo * other devices should follow the intersection created between the 117f79cbc77SKalle Valo * first two. 118f79cbc77SKalle Valo * @HWSIM_REGTEST_ALL: Used for testing every possible mix. You will need 119f79cbc77SKalle Valo * at least 6 radios for a complete test. We will test in this order: 120f79cbc77SKalle Valo * 1 - driver custom world regulatory domain 121f79cbc77SKalle Valo * 2 - second custom world regulatory domain 122f79cbc77SKalle Valo * 3 - first driver regulatory domain request 123f79cbc77SKalle Valo * 4 - second driver regulatory domain request 124f79cbc77SKalle Valo * 5 - strict regulatory domain settings using the third driver regulatory 125f79cbc77SKalle Valo * domain request 126f79cbc77SKalle Valo * 6 and on - should follow the intersection of the 3rd, 4rth and 5th radio 127f79cbc77SKalle Valo * regulatory requests. 128f79cbc77SKalle Valo */ 129f79cbc77SKalle Valo enum hwsim_regtest { 130f79cbc77SKalle Valo HWSIM_REGTEST_DISABLED = 0, 131f79cbc77SKalle Valo HWSIM_REGTEST_DRIVER_REG_FOLLOW = 1, 132f79cbc77SKalle Valo HWSIM_REGTEST_DRIVER_REG_ALL = 2, 133f79cbc77SKalle Valo HWSIM_REGTEST_DIFF_COUNTRY = 3, 134f79cbc77SKalle Valo HWSIM_REGTEST_WORLD_ROAM = 4, 135f79cbc77SKalle Valo HWSIM_REGTEST_CUSTOM_WORLD = 5, 136f79cbc77SKalle Valo HWSIM_REGTEST_CUSTOM_WORLD_2 = 6, 137f79cbc77SKalle Valo HWSIM_REGTEST_STRICT_FOLLOW = 7, 138f79cbc77SKalle Valo HWSIM_REGTEST_STRICT_ALL = 8, 139f79cbc77SKalle Valo HWSIM_REGTEST_STRICT_AND_DRIVER_REG = 9, 140f79cbc77SKalle Valo HWSIM_REGTEST_ALL = 10, 141f79cbc77SKalle Valo }; 142f79cbc77SKalle Valo 143f79cbc77SKalle Valo /* Set to one of the HWSIM_REGTEST_* values above */ 144f79cbc77SKalle Valo static int regtest = HWSIM_REGTEST_DISABLED; 145f79cbc77SKalle Valo module_param(regtest, int, 0444); 146f79cbc77SKalle Valo MODULE_PARM_DESC(regtest, "The type of regulatory test we want to run"); 147f79cbc77SKalle Valo 148f79cbc77SKalle Valo static const char *hwsim_alpha2s[] = { 149f79cbc77SKalle Valo "FI", 150f79cbc77SKalle Valo "AL", 151f79cbc77SKalle Valo "US", 152f79cbc77SKalle Valo "DE", 153f79cbc77SKalle Valo "JP", 154f79cbc77SKalle Valo "AL", 155f79cbc77SKalle Valo }; 156f79cbc77SKalle Valo 157f79cbc77SKalle Valo static const struct ieee80211_regdomain hwsim_world_regdom_custom_01 = { 158f79cbc77SKalle Valo .n_reg_rules = 5, 159f79cbc77SKalle Valo .alpha2 = "99", 160f79cbc77SKalle Valo .reg_rules = { 161f79cbc77SKalle Valo REG_RULE(2412-10, 2462+10, 40, 0, 20, 0), 162f79cbc77SKalle Valo REG_RULE(2484-10, 2484+10, 40, 0, 20, 0), 163f79cbc77SKalle Valo REG_RULE(5150-10, 5240+10, 40, 0, 30, 0), 164f79cbc77SKalle Valo REG_RULE(5745-10, 5825+10, 40, 0, 30, 0), 165f79cbc77SKalle Valo REG_RULE(5855-10, 5925+10, 40, 0, 33, 0), 166f79cbc77SKalle Valo } 167f79cbc77SKalle Valo }; 168f79cbc77SKalle Valo 169f79cbc77SKalle Valo static const struct ieee80211_regdomain hwsim_world_regdom_custom_02 = { 170f79cbc77SKalle Valo .n_reg_rules = 3, 171f79cbc77SKalle Valo .alpha2 = "99", 172f79cbc77SKalle Valo .reg_rules = { 173f79cbc77SKalle Valo REG_RULE(2412-10, 2462+10, 40, 0, 20, 0), 174f79cbc77SKalle Valo REG_RULE(5725-10, 5850+10, 40, 0, 30, 175f79cbc77SKalle Valo NL80211_RRF_NO_IR), 176f79cbc77SKalle Valo REG_RULE(5855-10, 5925+10, 40, 0, 33, 0), 177f79cbc77SKalle Valo } 178f79cbc77SKalle Valo }; 179f79cbc77SKalle Valo 180f79cbc77SKalle Valo static const struct ieee80211_regdomain hwsim_world_regdom_custom_03 = { 181f79cbc77SKalle Valo .n_reg_rules = 6, 182f79cbc77SKalle Valo .alpha2 = "99", 183f79cbc77SKalle Valo .reg_rules = { 184f79cbc77SKalle Valo REG_RULE(2412 - 10, 2462 + 10, 40, 0, 20, 0), 185f79cbc77SKalle Valo REG_RULE(2484 - 10, 2484 + 10, 40, 0, 20, 0), 186f79cbc77SKalle Valo REG_RULE(5150 - 10, 5240 + 10, 40, 0, 30, 0), 187f79cbc77SKalle Valo REG_RULE(5745 - 10, 5825 + 10, 40, 0, 30, 0), 188f79cbc77SKalle Valo REG_RULE(5855 - 10, 5925 + 10, 40, 0, 33, 0), 189f79cbc77SKalle Valo REG_RULE(5955 - 10, 7125 + 10, 320, 0, 33, 0), 190f79cbc77SKalle Valo } 191f79cbc77SKalle Valo }; 192f79cbc77SKalle Valo 193f79cbc77SKalle Valo static const struct ieee80211_regdomain *hwsim_world_regdom_custom[] = { 194f79cbc77SKalle Valo &hwsim_world_regdom_custom_01, 195f79cbc77SKalle Valo &hwsim_world_regdom_custom_02, 196f79cbc77SKalle Valo &hwsim_world_regdom_custom_03, 197f79cbc77SKalle Valo }; 198f79cbc77SKalle Valo 199f79cbc77SKalle Valo struct hwsim_vif_priv { 200f79cbc77SKalle Valo u32 magic; 201f79cbc77SKalle Valo u8 bssid[ETH_ALEN]; 202f79cbc77SKalle Valo bool assoc; 203f79cbc77SKalle Valo bool bcn_en; 204f79cbc77SKalle Valo u16 aid; 205f79cbc77SKalle Valo }; 206f79cbc77SKalle Valo 207f79cbc77SKalle Valo #define HWSIM_VIF_MAGIC 0x69537748 208f79cbc77SKalle Valo 209f79cbc77SKalle Valo static inline void hwsim_check_magic(struct ieee80211_vif *vif) 210f79cbc77SKalle Valo { 211f79cbc77SKalle Valo struct hwsim_vif_priv *vp = (void *)vif->drv_priv; 212f79cbc77SKalle Valo WARN(vp->magic != HWSIM_VIF_MAGIC, 213f79cbc77SKalle Valo "Invalid VIF (%p) magic %#x, %pM, %d/%d\n", 214f79cbc77SKalle Valo vif, vp->magic, vif->addr, vif->type, vif->p2p); 215f79cbc77SKalle Valo } 216f79cbc77SKalle Valo 217f79cbc77SKalle Valo static inline void hwsim_set_magic(struct ieee80211_vif *vif) 218f79cbc77SKalle Valo { 219f79cbc77SKalle Valo struct hwsim_vif_priv *vp = (void *)vif->drv_priv; 220f79cbc77SKalle Valo vp->magic = HWSIM_VIF_MAGIC; 221f79cbc77SKalle Valo } 222f79cbc77SKalle Valo 223f79cbc77SKalle Valo static inline void hwsim_clear_magic(struct ieee80211_vif *vif) 224f79cbc77SKalle Valo { 225f79cbc77SKalle Valo struct hwsim_vif_priv *vp = (void *)vif->drv_priv; 226f79cbc77SKalle Valo vp->magic = 0; 227f79cbc77SKalle Valo } 228f79cbc77SKalle Valo 229f79cbc77SKalle Valo struct hwsim_sta_priv { 230f79cbc77SKalle Valo u32 magic; 231f79cbc77SKalle Valo unsigned int last_link; 232f79cbc77SKalle Valo u16 active_links_rx; 233f79cbc77SKalle Valo }; 234f79cbc77SKalle Valo 235f79cbc77SKalle Valo #define HWSIM_STA_MAGIC 0x6d537749 236f79cbc77SKalle Valo 237f79cbc77SKalle Valo static inline void hwsim_check_sta_magic(struct ieee80211_sta *sta) 238f79cbc77SKalle Valo { 239f79cbc77SKalle Valo struct hwsim_sta_priv *sp = (void *)sta->drv_priv; 240f79cbc77SKalle Valo WARN_ON(sp->magic != HWSIM_STA_MAGIC); 241f79cbc77SKalle Valo } 242f79cbc77SKalle Valo 243f79cbc77SKalle Valo static inline void hwsim_set_sta_magic(struct ieee80211_sta *sta) 244f79cbc77SKalle Valo { 245f79cbc77SKalle Valo struct hwsim_sta_priv *sp = (void *)sta->drv_priv; 246f79cbc77SKalle Valo sp->magic = HWSIM_STA_MAGIC; 247f79cbc77SKalle Valo } 248f79cbc77SKalle Valo 249f79cbc77SKalle Valo static inline void hwsim_clear_sta_magic(struct ieee80211_sta *sta) 250f79cbc77SKalle Valo { 251f79cbc77SKalle Valo struct hwsim_sta_priv *sp = (void *)sta->drv_priv; 252f79cbc77SKalle Valo sp->magic = 0; 253f79cbc77SKalle Valo } 254f79cbc77SKalle Valo 255f79cbc77SKalle Valo struct hwsim_chanctx_priv { 256f79cbc77SKalle Valo u32 magic; 257f79cbc77SKalle Valo }; 258f79cbc77SKalle Valo 259f79cbc77SKalle Valo #define HWSIM_CHANCTX_MAGIC 0x6d53774a 260f79cbc77SKalle Valo 261f79cbc77SKalle Valo static inline void hwsim_check_chanctx_magic(struct ieee80211_chanctx_conf *c) 262f79cbc77SKalle Valo { 263f79cbc77SKalle Valo struct hwsim_chanctx_priv *cp = (void *)c->drv_priv; 264f79cbc77SKalle Valo WARN_ON(cp->magic != HWSIM_CHANCTX_MAGIC); 265f79cbc77SKalle Valo } 266f79cbc77SKalle Valo 267f79cbc77SKalle Valo static inline void hwsim_set_chanctx_magic(struct ieee80211_chanctx_conf *c) 268f79cbc77SKalle Valo { 269f79cbc77SKalle Valo struct hwsim_chanctx_priv *cp = (void *)c->drv_priv; 270f79cbc77SKalle Valo cp->magic = HWSIM_CHANCTX_MAGIC; 271f79cbc77SKalle Valo } 272f79cbc77SKalle Valo 273f79cbc77SKalle Valo static inline void hwsim_clear_chanctx_magic(struct ieee80211_chanctx_conf *c) 274f79cbc77SKalle Valo { 275f79cbc77SKalle Valo struct hwsim_chanctx_priv *cp = (void *)c->drv_priv; 276f79cbc77SKalle Valo cp->magic = 0; 277f79cbc77SKalle Valo } 278f79cbc77SKalle Valo 279f79cbc77SKalle Valo static unsigned int hwsim_net_id; 280f79cbc77SKalle Valo 281f79cbc77SKalle Valo static DEFINE_IDA(hwsim_netgroup_ida); 282f79cbc77SKalle Valo 283f79cbc77SKalle Valo struct hwsim_net { 284f79cbc77SKalle Valo int netgroup; 285f79cbc77SKalle Valo u32 wmediumd; 286f79cbc77SKalle Valo }; 287f79cbc77SKalle Valo 288f79cbc77SKalle Valo static inline int hwsim_net_get_netgroup(struct net *net) 289f79cbc77SKalle Valo { 290f79cbc77SKalle Valo struct hwsim_net *hwsim_net = net_generic(net, hwsim_net_id); 291f79cbc77SKalle Valo 292f79cbc77SKalle Valo return hwsim_net->netgroup; 293f79cbc77SKalle Valo } 294f79cbc77SKalle Valo 295f79cbc77SKalle Valo static inline int hwsim_net_set_netgroup(struct net *net) 296f79cbc77SKalle Valo { 297f79cbc77SKalle Valo struct hwsim_net *hwsim_net = net_generic(net, hwsim_net_id); 298f79cbc77SKalle Valo 299f79cbc77SKalle Valo hwsim_net->netgroup = ida_alloc(&hwsim_netgroup_ida, GFP_KERNEL); 300f79cbc77SKalle Valo return hwsim_net->netgroup >= 0 ? 0 : -ENOMEM; 301f79cbc77SKalle Valo } 302f79cbc77SKalle Valo 303f79cbc77SKalle Valo static inline u32 hwsim_net_get_wmediumd(struct net *net) 304f79cbc77SKalle Valo { 305f79cbc77SKalle Valo struct hwsim_net *hwsim_net = net_generic(net, hwsim_net_id); 306f79cbc77SKalle Valo 307f79cbc77SKalle Valo return hwsim_net->wmediumd; 308f79cbc77SKalle Valo } 309f79cbc77SKalle Valo 310f79cbc77SKalle Valo static inline void hwsim_net_set_wmediumd(struct net *net, u32 portid) 311f79cbc77SKalle Valo { 312f79cbc77SKalle Valo struct hwsim_net *hwsim_net = net_generic(net, hwsim_net_id); 313f79cbc77SKalle Valo 314f79cbc77SKalle Valo hwsim_net->wmediumd = portid; 315f79cbc77SKalle Valo } 316f79cbc77SKalle Valo 317f79cbc77SKalle Valo static struct class *hwsim_class; 318f79cbc77SKalle Valo 319f79cbc77SKalle Valo static struct net_device *hwsim_mon; /* global monitor netdev */ 320f79cbc77SKalle Valo 321f79cbc77SKalle Valo #define CHAN2G(_freq) { \ 322f79cbc77SKalle Valo .band = NL80211_BAND_2GHZ, \ 323f79cbc77SKalle Valo .center_freq = (_freq), \ 324f79cbc77SKalle Valo .hw_value = (_freq), \ 325f79cbc77SKalle Valo } 326f79cbc77SKalle Valo 327f79cbc77SKalle Valo #define CHAN5G(_freq) { \ 328f79cbc77SKalle Valo .band = NL80211_BAND_5GHZ, \ 329f79cbc77SKalle Valo .center_freq = (_freq), \ 330f79cbc77SKalle Valo .hw_value = (_freq), \ 331f79cbc77SKalle Valo } 332f79cbc77SKalle Valo 333f79cbc77SKalle Valo #define CHAN6G(_freq) { \ 334f79cbc77SKalle Valo .band = NL80211_BAND_6GHZ, \ 335f79cbc77SKalle Valo .center_freq = (_freq), \ 336f79cbc77SKalle Valo .hw_value = (_freq), \ 337f79cbc77SKalle Valo } 338f79cbc77SKalle Valo 339f79cbc77SKalle Valo static const struct ieee80211_channel hwsim_channels_2ghz[] = { 340f79cbc77SKalle Valo CHAN2G(2412), /* Channel 1 */ 341f79cbc77SKalle Valo CHAN2G(2417), /* Channel 2 */ 342f79cbc77SKalle Valo CHAN2G(2422), /* Channel 3 */ 343f79cbc77SKalle Valo CHAN2G(2427), /* Channel 4 */ 344f79cbc77SKalle Valo CHAN2G(2432), /* Channel 5 */ 345f79cbc77SKalle Valo CHAN2G(2437), /* Channel 6 */ 346f79cbc77SKalle Valo CHAN2G(2442), /* Channel 7 */ 347f79cbc77SKalle Valo CHAN2G(2447), /* Channel 8 */ 348f79cbc77SKalle Valo CHAN2G(2452), /* Channel 9 */ 349f79cbc77SKalle Valo CHAN2G(2457), /* Channel 10 */ 350f79cbc77SKalle Valo CHAN2G(2462), /* Channel 11 */ 351f79cbc77SKalle Valo CHAN2G(2467), /* Channel 12 */ 352f79cbc77SKalle Valo CHAN2G(2472), /* Channel 13 */ 353f79cbc77SKalle Valo CHAN2G(2484), /* Channel 14 */ 354f79cbc77SKalle Valo }; 355f79cbc77SKalle Valo 356f79cbc77SKalle Valo static const struct ieee80211_channel hwsim_channels_5ghz[] = { 357f79cbc77SKalle Valo CHAN5G(5180), /* Channel 36 */ 358f79cbc77SKalle Valo CHAN5G(5200), /* Channel 40 */ 359f79cbc77SKalle Valo CHAN5G(5220), /* Channel 44 */ 360f79cbc77SKalle Valo CHAN5G(5240), /* Channel 48 */ 361f79cbc77SKalle Valo 362f79cbc77SKalle Valo CHAN5G(5260), /* Channel 52 */ 363f79cbc77SKalle Valo CHAN5G(5280), /* Channel 56 */ 364f79cbc77SKalle Valo CHAN5G(5300), /* Channel 60 */ 365f79cbc77SKalle Valo CHAN5G(5320), /* Channel 64 */ 366f79cbc77SKalle Valo 367f79cbc77SKalle Valo CHAN5G(5500), /* Channel 100 */ 368f79cbc77SKalle Valo CHAN5G(5520), /* Channel 104 */ 369f79cbc77SKalle Valo CHAN5G(5540), /* Channel 108 */ 370f79cbc77SKalle Valo CHAN5G(5560), /* Channel 112 */ 371f79cbc77SKalle Valo CHAN5G(5580), /* Channel 116 */ 372f79cbc77SKalle Valo CHAN5G(5600), /* Channel 120 */ 373f79cbc77SKalle Valo CHAN5G(5620), /* Channel 124 */ 374f79cbc77SKalle Valo CHAN5G(5640), /* Channel 128 */ 375f79cbc77SKalle Valo CHAN5G(5660), /* Channel 132 */ 376f79cbc77SKalle Valo CHAN5G(5680), /* Channel 136 */ 377f79cbc77SKalle Valo CHAN5G(5700), /* Channel 140 */ 378f79cbc77SKalle Valo 379f79cbc77SKalle Valo CHAN5G(5745), /* Channel 149 */ 380f79cbc77SKalle Valo CHAN5G(5765), /* Channel 153 */ 381f79cbc77SKalle Valo CHAN5G(5785), /* Channel 157 */ 382f79cbc77SKalle Valo CHAN5G(5805), /* Channel 161 */ 383f79cbc77SKalle Valo CHAN5G(5825), /* Channel 165 */ 384f79cbc77SKalle Valo CHAN5G(5845), /* Channel 169 */ 385f79cbc77SKalle Valo 386f79cbc77SKalle Valo CHAN5G(5855), /* Channel 171 */ 387f79cbc77SKalle Valo CHAN5G(5860), /* Channel 172 */ 388f79cbc77SKalle Valo CHAN5G(5865), /* Channel 173 */ 389f79cbc77SKalle Valo CHAN5G(5870), /* Channel 174 */ 390f79cbc77SKalle Valo 391f79cbc77SKalle Valo CHAN5G(5875), /* Channel 175 */ 392f79cbc77SKalle Valo CHAN5G(5880), /* Channel 176 */ 393f79cbc77SKalle Valo CHAN5G(5885), /* Channel 177 */ 394f79cbc77SKalle Valo CHAN5G(5890), /* Channel 178 */ 395f79cbc77SKalle Valo CHAN5G(5895), /* Channel 179 */ 396f79cbc77SKalle Valo CHAN5G(5900), /* Channel 180 */ 397f79cbc77SKalle Valo CHAN5G(5905), /* Channel 181 */ 398f79cbc77SKalle Valo 399f79cbc77SKalle Valo CHAN5G(5910), /* Channel 182 */ 400f79cbc77SKalle Valo CHAN5G(5915), /* Channel 183 */ 401f79cbc77SKalle Valo CHAN5G(5920), /* Channel 184 */ 402f79cbc77SKalle Valo CHAN5G(5925), /* Channel 185 */ 403f79cbc77SKalle Valo }; 404f79cbc77SKalle Valo 405f79cbc77SKalle Valo static const struct ieee80211_channel hwsim_channels_6ghz[] = { 406f79cbc77SKalle Valo CHAN6G(5955), /* Channel 1 */ 407f79cbc77SKalle Valo CHAN6G(5975), /* Channel 5 */ 408f79cbc77SKalle Valo CHAN6G(5995), /* Channel 9 */ 409f79cbc77SKalle Valo CHAN6G(6015), /* Channel 13 */ 410f79cbc77SKalle Valo CHAN6G(6035), /* Channel 17 */ 411f79cbc77SKalle Valo CHAN6G(6055), /* Channel 21 */ 412f79cbc77SKalle Valo CHAN6G(6075), /* Channel 25 */ 413f79cbc77SKalle Valo CHAN6G(6095), /* Channel 29 */ 414f79cbc77SKalle Valo CHAN6G(6115), /* Channel 33 */ 415f79cbc77SKalle Valo CHAN6G(6135), /* Channel 37 */ 416f79cbc77SKalle Valo CHAN6G(6155), /* Channel 41 */ 417f79cbc77SKalle Valo CHAN6G(6175), /* Channel 45 */ 418f79cbc77SKalle Valo CHAN6G(6195), /* Channel 49 */ 419f79cbc77SKalle Valo CHAN6G(6215), /* Channel 53 */ 420f79cbc77SKalle Valo CHAN6G(6235), /* Channel 57 */ 421f79cbc77SKalle Valo CHAN6G(6255), /* Channel 61 */ 422f79cbc77SKalle Valo CHAN6G(6275), /* Channel 65 */ 423f79cbc77SKalle Valo CHAN6G(6295), /* Channel 69 */ 424f79cbc77SKalle Valo CHAN6G(6315), /* Channel 73 */ 425f79cbc77SKalle Valo CHAN6G(6335), /* Channel 77 */ 426f79cbc77SKalle Valo CHAN6G(6355), /* Channel 81 */ 427f79cbc77SKalle Valo CHAN6G(6375), /* Channel 85 */ 428f79cbc77SKalle Valo CHAN6G(6395), /* Channel 89 */ 429f79cbc77SKalle Valo CHAN6G(6415), /* Channel 93 */ 430f79cbc77SKalle Valo CHAN6G(6435), /* Channel 97 */ 431f79cbc77SKalle Valo CHAN6G(6455), /* Channel 181 */ 432f79cbc77SKalle Valo CHAN6G(6475), /* Channel 105 */ 433f79cbc77SKalle Valo CHAN6G(6495), /* Channel 109 */ 434f79cbc77SKalle Valo CHAN6G(6515), /* Channel 113 */ 435f79cbc77SKalle Valo CHAN6G(6535), /* Channel 117 */ 436f79cbc77SKalle Valo CHAN6G(6555), /* Channel 121 */ 437f79cbc77SKalle Valo CHAN6G(6575), /* Channel 125 */ 438f79cbc77SKalle Valo CHAN6G(6595), /* Channel 129 */ 439f79cbc77SKalle Valo CHAN6G(6615), /* Channel 133 */ 440f79cbc77SKalle Valo CHAN6G(6635), /* Channel 137 */ 441f79cbc77SKalle Valo CHAN6G(6655), /* Channel 141 */ 442f79cbc77SKalle Valo CHAN6G(6675), /* Channel 145 */ 443f79cbc77SKalle Valo CHAN6G(6695), /* Channel 149 */ 444f79cbc77SKalle Valo CHAN6G(6715), /* Channel 153 */ 445f79cbc77SKalle Valo CHAN6G(6735), /* Channel 157 */ 446f79cbc77SKalle Valo CHAN6G(6755), /* Channel 161 */ 447f79cbc77SKalle Valo CHAN6G(6775), /* Channel 165 */ 448f79cbc77SKalle Valo CHAN6G(6795), /* Channel 169 */ 449f79cbc77SKalle Valo CHAN6G(6815), /* Channel 173 */ 450f79cbc77SKalle Valo CHAN6G(6835), /* Channel 177 */ 451f79cbc77SKalle Valo CHAN6G(6855), /* Channel 181 */ 452f79cbc77SKalle Valo CHAN6G(6875), /* Channel 185 */ 453f79cbc77SKalle Valo CHAN6G(6895), /* Channel 189 */ 454f79cbc77SKalle Valo CHAN6G(6915), /* Channel 193 */ 455f79cbc77SKalle Valo CHAN6G(6935), /* Channel 197 */ 456f79cbc77SKalle Valo CHAN6G(6955), /* Channel 201 */ 457f79cbc77SKalle Valo CHAN6G(6975), /* Channel 205 */ 458f79cbc77SKalle Valo CHAN6G(6995), /* Channel 209 */ 459f79cbc77SKalle Valo CHAN6G(7015), /* Channel 213 */ 460f79cbc77SKalle Valo CHAN6G(7035), /* Channel 217 */ 461f79cbc77SKalle Valo CHAN6G(7055), /* Channel 221 */ 462f79cbc77SKalle Valo CHAN6G(7075), /* Channel 225 */ 463f79cbc77SKalle Valo CHAN6G(7095), /* Channel 229 */ 464f79cbc77SKalle Valo CHAN6G(7115), /* Channel 233 */ 465f79cbc77SKalle Valo }; 466f79cbc77SKalle Valo 467f79cbc77SKalle Valo #define NUM_S1G_CHANS_US 51 468f79cbc77SKalle Valo static struct ieee80211_channel hwsim_channels_s1g[NUM_S1G_CHANS_US]; 469f79cbc77SKalle Valo 470f79cbc77SKalle Valo static const struct ieee80211_sta_s1g_cap hwsim_s1g_cap = { 471f79cbc77SKalle Valo .s1g = true, 472f79cbc77SKalle Valo .cap = { S1G_CAP0_SGI_1MHZ | S1G_CAP0_SGI_2MHZ, 473f79cbc77SKalle Valo 0, 474f79cbc77SKalle Valo 0, 475f79cbc77SKalle Valo S1G_CAP3_MAX_MPDU_LEN, 476f79cbc77SKalle Valo 0, 477f79cbc77SKalle Valo S1G_CAP5_AMPDU, 478f79cbc77SKalle Valo 0, 479f79cbc77SKalle Valo S1G_CAP7_DUP_1MHZ, 480f79cbc77SKalle Valo S1G_CAP8_TWT_RESPOND | S1G_CAP8_TWT_REQUEST, 481f79cbc77SKalle Valo 0}, 482f79cbc77SKalle Valo .nss_mcs = { 0xfc | 1, /* MCS 7 for 1 SS */ 483f79cbc77SKalle Valo /* RX Highest Supported Long GI Data Rate 0:7 */ 484f79cbc77SKalle Valo 0, 485f79cbc77SKalle Valo /* RX Highest Supported Long GI Data Rate 0:7 */ 486f79cbc77SKalle Valo /* TX S1G MCS Map 0:6 */ 487f79cbc77SKalle Valo 0xfa, 488f79cbc77SKalle Valo /* TX S1G MCS Map :7 */ 489f79cbc77SKalle Valo /* TX Highest Supported Long GI Data Rate 0:6 */ 490f79cbc77SKalle Valo 0x80, 491f79cbc77SKalle Valo /* TX Highest Supported Long GI Data Rate 7:8 */ 492f79cbc77SKalle Valo /* Rx Single spatial stream and S1G-MCS Map for 1MHz */ 493f79cbc77SKalle Valo /* Tx Single spatial stream and S1G-MCS Map for 1MHz */ 494f79cbc77SKalle Valo 0 }, 495f79cbc77SKalle Valo }; 496f79cbc77SKalle Valo 497f79cbc77SKalle Valo static void hwsim_init_s1g_channels(struct ieee80211_channel *chans) 498f79cbc77SKalle Valo { 499f79cbc77SKalle Valo int ch, freq; 500f79cbc77SKalle Valo 501f79cbc77SKalle Valo for (ch = 0; ch < NUM_S1G_CHANS_US; ch++) { 502f79cbc77SKalle Valo freq = 902000 + (ch + 1) * 500; 503f79cbc77SKalle Valo chans[ch].band = NL80211_BAND_S1GHZ; 504f79cbc77SKalle Valo chans[ch].center_freq = KHZ_TO_MHZ(freq); 505f79cbc77SKalle Valo chans[ch].freq_offset = freq % 1000; 506f79cbc77SKalle Valo chans[ch].hw_value = ch + 1; 507f79cbc77SKalle Valo } 508f79cbc77SKalle Valo } 509f79cbc77SKalle Valo 510f79cbc77SKalle Valo static const struct ieee80211_rate hwsim_rates[] = { 511f79cbc77SKalle Valo { .bitrate = 10 }, 512f79cbc77SKalle Valo { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, 513f79cbc77SKalle Valo { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, 514f79cbc77SKalle Valo { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, 515f79cbc77SKalle Valo { .bitrate = 60 }, 516f79cbc77SKalle Valo { .bitrate = 90 }, 517f79cbc77SKalle Valo { .bitrate = 120 }, 518f79cbc77SKalle Valo { .bitrate = 180 }, 519f79cbc77SKalle Valo { .bitrate = 240 }, 520f79cbc77SKalle Valo { .bitrate = 360 }, 521f79cbc77SKalle Valo { .bitrate = 480 }, 522f79cbc77SKalle Valo { .bitrate = 540 } 523f79cbc77SKalle Valo }; 524f79cbc77SKalle Valo 525f79cbc77SKalle Valo #define DEFAULT_RX_RSSI -50 526f79cbc77SKalle Valo 527f79cbc77SKalle Valo static const u32 hwsim_ciphers[] = { 528f79cbc77SKalle Valo WLAN_CIPHER_SUITE_WEP40, 529f79cbc77SKalle Valo WLAN_CIPHER_SUITE_WEP104, 530f79cbc77SKalle Valo WLAN_CIPHER_SUITE_TKIP, 531f79cbc77SKalle Valo WLAN_CIPHER_SUITE_CCMP, 532f79cbc77SKalle Valo WLAN_CIPHER_SUITE_CCMP_256, 533f79cbc77SKalle Valo WLAN_CIPHER_SUITE_GCMP, 534f79cbc77SKalle Valo WLAN_CIPHER_SUITE_GCMP_256, 535f79cbc77SKalle Valo WLAN_CIPHER_SUITE_AES_CMAC, 536f79cbc77SKalle Valo WLAN_CIPHER_SUITE_BIP_CMAC_256, 537f79cbc77SKalle Valo WLAN_CIPHER_SUITE_BIP_GMAC_128, 538f79cbc77SKalle Valo WLAN_CIPHER_SUITE_BIP_GMAC_256, 539f79cbc77SKalle Valo }; 540f79cbc77SKalle Valo 541f79cbc77SKalle Valo #define OUI_QCA 0x001374 542f79cbc77SKalle Valo #define QCA_NL80211_SUBCMD_TEST 1 543f79cbc77SKalle Valo enum qca_nl80211_vendor_subcmds { 544f79cbc77SKalle Valo QCA_WLAN_VENDOR_ATTR_TEST = 8, 545f79cbc77SKalle Valo QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_TEST 546f79cbc77SKalle Valo }; 547f79cbc77SKalle Valo 548f79cbc77SKalle Valo static const struct nla_policy 549f79cbc77SKalle Valo hwsim_vendor_test_policy[QCA_WLAN_VENDOR_ATTR_MAX + 1] = { 550f79cbc77SKalle Valo [QCA_WLAN_VENDOR_ATTR_MAX] = { .type = NLA_U32 }, 551f79cbc77SKalle Valo }; 552f79cbc77SKalle Valo 553f79cbc77SKalle Valo static int mac80211_hwsim_vendor_cmd_test(struct wiphy *wiphy, 554f79cbc77SKalle Valo struct wireless_dev *wdev, 555f79cbc77SKalle Valo const void *data, int data_len) 556f79cbc77SKalle Valo { 557f79cbc77SKalle Valo struct sk_buff *skb; 558f79cbc77SKalle Valo struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX + 1]; 559f79cbc77SKalle Valo int err; 560f79cbc77SKalle Valo u32 val; 561f79cbc77SKalle Valo 562f79cbc77SKalle Valo err = nla_parse_deprecated(tb, QCA_WLAN_VENDOR_ATTR_MAX, data, 563f79cbc77SKalle Valo data_len, hwsim_vendor_test_policy, NULL); 564f79cbc77SKalle Valo if (err) 565f79cbc77SKalle Valo return err; 566f79cbc77SKalle Valo if (!tb[QCA_WLAN_VENDOR_ATTR_TEST]) 567f79cbc77SKalle Valo return -EINVAL; 568f79cbc77SKalle Valo val = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_TEST]); 569f79cbc77SKalle Valo wiphy_dbg(wiphy, "%s: test=%u\n", __func__, val); 570f79cbc77SKalle Valo 571f79cbc77SKalle Valo /* Send a vendor event as a test. Note that this would not normally be 572f79cbc77SKalle Valo * done within a command handler, but rather, based on some other 573f79cbc77SKalle Valo * trigger. For simplicity, this command is used to trigger the event 574f79cbc77SKalle Valo * here. 575f79cbc77SKalle Valo * 576f79cbc77SKalle Valo * event_idx = 0 (index in mac80211_hwsim_vendor_commands) 577f79cbc77SKalle Valo */ 578f79cbc77SKalle Valo skb = cfg80211_vendor_event_alloc(wiphy, wdev, 100, 0, GFP_KERNEL); 579f79cbc77SKalle Valo if (skb) { 580f79cbc77SKalle Valo /* skb_put() or nla_put() will fill up data within 581f79cbc77SKalle Valo * NL80211_ATTR_VENDOR_DATA. 582f79cbc77SKalle Valo */ 583f79cbc77SKalle Valo 584f79cbc77SKalle Valo /* Add vendor data */ 585f79cbc77SKalle Valo nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_TEST, val + 1); 586f79cbc77SKalle Valo 587f79cbc77SKalle Valo /* Send the event - this will call nla_nest_end() */ 588f79cbc77SKalle Valo cfg80211_vendor_event(skb, GFP_KERNEL); 589f79cbc77SKalle Valo } 590f79cbc77SKalle Valo 591f79cbc77SKalle Valo /* Send a response to the command */ 592f79cbc77SKalle Valo skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, 10); 593f79cbc77SKalle Valo if (!skb) 594f79cbc77SKalle Valo return -ENOMEM; 595f79cbc77SKalle Valo 596f79cbc77SKalle Valo /* skb_put() or nla_put() will fill up data within 597f79cbc77SKalle Valo * NL80211_ATTR_VENDOR_DATA 598f79cbc77SKalle Valo */ 599f79cbc77SKalle Valo nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_TEST, val + 2); 600f79cbc77SKalle Valo 601f79cbc77SKalle Valo return cfg80211_vendor_cmd_reply(skb); 602f79cbc77SKalle Valo } 603f79cbc77SKalle Valo 604f79cbc77SKalle Valo static struct wiphy_vendor_command mac80211_hwsim_vendor_commands[] = { 605f79cbc77SKalle Valo { 606f79cbc77SKalle Valo .info = { .vendor_id = OUI_QCA, 607f79cbc77SKalle Valo .subcmd = QCA_NL80211_SUBCMD_TEST }, 608f79cbc77SKalle Valo .flags = WIPHY_VENDOR_CMD_NEED_NETDEV, 609f79cbc77SKalle Valo .doit = mac80211_hwsim_vendor_cmd_test, 610f79cbc77SKalle Valo .policy = hwsim_vendor_test_policy, 611f79cbc77SKalle Valo .maxattr = QCA_WLAN_VENDOR_ATTR_MAX, 612f79cbc77SKalle Valo } 613f79cbc77SKalle Valo }; 614f79cbc77SKalle Valo 615f79cbc77SKalle Valo /* Advertise support vendor specific events */ 616f79cbc77SKalle Valo static const struct nl80211_vendor_cmd_info mac80211_hwsim_vendor_events[] = { 617f79cbc77SKalle Valo { .vendor_id = OUI_QCA, .subcmd = 1 }, 618f79cbc77SKalle Valo }; 619f79cbc77SKalle Valo 620f79cbc77SKalle Valo static DEFINE_SPINLOCK(hwsim_radio_lock); 621f79cbc77SKalle Valo static LIST_HEAD(hwsim_radios); 622f79cbc77SKalle Valo static struct rhashtable hwsim_radios_rht; 623f79cbc77SKalle Valo static int hwsim_radio_idx; 624f79cbc77SKalle Valo static int hwsim_radios_generation = 1; 625f79cbc77SKalle Valo 626f79cbc77SKalle Valo static struct platform_driver mac80211_hwsim_driver = { 627f79cbc77SKalle Valo .driver = { 628f79cbc77SKalle Valo .name = "mac80211_hwsim", 629f79cbc77SKalle Valo }, 630f79cbc77SKalle Valo }; 631f79cbc77SKalle Valo 632f79cbc77SKalle Valo struct mac80211_hwsim_link_data { 633f79cbc77SKalle Valo u32 link_id; 634f79cbc77SKalle Valo u64 beacon_int /* beacon interval in us */; 635f79cbc77SKalle Valo struct hrtimer beacon_timer; 636f79cbc77SKalle Valo }; 637f79cbc77SKalle Valo 638f79cbc77SKalle Valo struct mac80211_hwsim_data { 639f79cbc77SKalle Valo struct list_head list; 640f79cbc77SKalle Valo struct rhash_head rht; 641f79cbc77SKalle Valo struct ieee80211_hw *hw; 642f79cbc77SKalle Valo struct device *dev; 643f79cbc77SKalle Valo struct ieee80211_supported_band bands[NUM_NL80211_BANDS]; 644f79cbc77SKalle Valo struct ieee80211_channel channels_2ghz[ARRAY_SIZE(hwsim_channels_2ghz)]; 645f79cbc77SKalle Valo struct ieee80211_channel channels_5ghz[ARRAY_SIZE(hwsim_channels_5ghz)]; 646f79cbc77SKalle Valo struct ieee80211_channel channels_6ghz[ARRAY_SIZE(hwsim_channels_6ghz)]; 647f79cbc77SKalle Valo struct ieee80211_channel channels_s1g[ARRAY_SIZE(hwsim_channels_s1g)]; 648f79cbc77SKalle Valo struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)]; 649f79cbc77SKalle Valo struct ieee80211_iface_combination if_combination; 650f79cbc77SKalle Valo struct ieee80211_iface_limit if_limits[3]; 651f79cbc77SKalle Valo int n_if_limits; 652f79cbc77SKalle Valo 653f79cbc77SKalle Valo u32 ciphers[ARRAY_SIZE(hwsim_ciphers)]; 654f79cbc77SKalle Valo 655f79cbc77SKalle Valo struct mac_address addresses[2]; 656f79cbc77SKalle Valo int channels, idx; 657f79cbc77SKalle Valo bool use_chanctx; 658f79cbc77SKalle Valo bool destroy_on_close; 659f79cbc77SKalle Valo u32 portid; 660f79cbc77SKalle Valo char alpha2[2]; 661f79cbc77SKalle Valo const struct ieee80211_regdomain *regd; 662f79cbc77SKalle Valo 663f79cbc77SKalle Valo struct ieee80211_channel *tmp_chan; 664f79cbc77SKalle Valo struct ieee80211_channel *roc_chan; 665f79cbc77SKalle Valo u32 roc_duration; 666f79cbc77SKalle Valo struct delayed_work roc_start; 667f79cbc77SKalle Valo struct delayed_work roc_done; 668f79cbc77SKalle Valo struct delayed_work hw_scan; 669f79cbc77SKalle Valo struct cfg80211_scan_request *hw_scan_request; 670f79cbc77SKalle Valo struct ieee80211_vif *hw_scan_vif; 671f79cbc77SKalle Valo int scan_chan_idx; 672f79cbc77SKalle Valo u8 scan_addr[ETH_ALEN]; 673f79cbc77SKalle Valo struct { 674f79cbc77SKalle Valo struct ieee80211_channel *channel; 675f79cbc77SKalle Valo unsigned long next_start, start, end; 676f79cbc77SKalle Valo } survey_data[ARRAY_SIZE(hwsim_channels_2ghz) + 677f79cbc77SKalle Valo ARRAY_SIZE(hwsim_channels_5ghz) + 678f79cbc77SKalle Valo ARRAY_SIZE(hwsim_channels_6ghz)]; 679f79cbc77SKalle Valo 680f79cbc77SKalle Valo struct ieee80211_channel *channel; 681f79cbc77SKalle Valo enum nl80211_chan_width bw; 682f79cbc77SKalle Valo unsigned int rx_filter; 683f79cbc77SKalle Valo bool started, idle, scanning; 684f79cbc77SKalle Valo struct mutex mutex; 685f79cbc77SKalle Valo enum ps_mode { 686f79cbc77SKalle Valo PS_DISABLED, PS_ENABLED, PS_AUTO_POLL, PS_MANUAL_POLL 687f79cbc77SKalle Valo } ps; 688f79cbc77SKalle Valo bool ps_poll_pending; 689f79cbc77SKalle Valo struct dentry *debugfs; 690f79cbc77SKalle Valo 691f79cbc77SKalle Valo atomic_t pending_cookie; 692f79cbc77SKalle Valo struct sk_buff_head pending; /* packets pending */ 693f79cbc77SKalle Valo /* 694f79cbc77SKalle Valo * Only radios in the same group can communicate together (the 695f79cbc77SKalle Valo * channel has to match too). Each bit represents a group. A 696f79cbc77SKalle Valo * radio can be in more than one group. 697f79cbc77SKalle Valo */ 698f79cbc77SKalle Valo u64 group; 699f79cbc77SKalle Valo 700f79cbc77SKalle Valo /* group shared by radios created in the same netns */ 701f79cbc77SKalle Valo int netgroup; 702f79cbc77SKalle Valo /* wmediumd portid responsible for netgroup of this radio */ 703f79cbc77SKalle Valo u32 wmediumd; 704f79cbc77SKalle Valo 705f79cbc77SKalle Valo /* difference between this hw's clock and the real clock, in usecs */ 706f79cbc77SKalle Valo s64 tsf_offset; 707f79cbc77SKalle Valo s64 bcn_delta; 708f79cbc77SKalle Valo /* absolute beacon transmission time. Used to cover up "tx" delay. */ 709f79cbc77SKalle Valo u64 abs_bcn_ts; 710f79cbc77SKalle Valo 711f79cbc77SKalle Valo /* Stats */ 712f79cbc77SKalle Valo u64 tx_pkts; 713f79cbc77SKalle Valo u64 rx_pkts; 714f79cbc77SKalle Valo u64 tx_bytes; 715f79cbc77SKalle Valo u64 rx_bytes; 716f79cbc77SKalle Valo u64 tx_dropped; 717f79cbc77SKalle Valo u64 tx_failed; 718f79cbc77SKalle Valo 719f79cbc77SKalle Valo /* RSSI in rx status of the receiver */ 720f79cbc77SKalle Valo int rx_rssi; 721f79cbc77SKalle Valo 722f79cbc77SKalle Valo struct mac80211_hwsim_link_data link_data[IEEE80211_MLD_MAX_NUM_LINKS]; 723f79cbc77SKalle Valo }; 724f79cbc77SKalle Valo 725f79cbc77SKalle Valo static const struct rhashtable_params hwsim_rht_params = { 726f79cbc77SKalle Valo .nelem_hint = 2, 727f79cbc77SKalle Valo .automatic_shrinking = true, 728f79cbc77SKalle Valo .key_len = ETH_ALEN, 729f79cbc77SKalle Valo .key_offset = offsetof(struct mac80211_hwsim_data, addresses[1]), 730f79cbc77SKalle Valo .head_offset = offsetof(struct mac80211_hwsim_data, rht), 731f79cbc77SKalle Valo }; 732f79cbc77SKalle Valo 733f79cbc77SKalle Valo struct hwsim_radiotap_hdr { 734f79cbc77SKalle Valo struct ieee80211_radiotap_header hdr; 735f79cbc77SKalle Valo __le64 rt_tsft; 736f79cbc77SKalle Valo u8 rt_flags; 737f79cbc77SKalle Valo u8 rt_rate; 738f79cbc77SKalle Valo __le16 rt_channel; 739f79cbc77SKalle Valo __le16 rt_chbitmask; 740f79cbc77SKalle Valo } __packed; 741f79cbc77SKalle Valo 742f79cbc77SKalle Valo struct hwsim_radiotap_ack_hdr { 743f79cbc77SKalle Valo struct ieee80211_radiotap_header hdr; 744f79cbc77SKalle Valo u8 rt_flags; 745f79cbc77SKalle Valo u8 pad; 746f79cbc77SKalle Valo __le16 rt_channel; 747f79cbc77SKalle Valo __le16 rt_chbitmask; 748f79cbc77SKalle Valo } __packed; 749f79cbc77SKalle Valo 750f79cbc77SKalle Valo /* MAC80211_HWSIM netlink family */ 751f79cbc77SKalle Valo static struct genl_family hwsim_genl_family; 752f79cbc77SKalle Valo 753f79cbc77SKalle Valo enum hwsim_multicast_groups { 754f79cbc77SKalle Valo HWSIM_MCGRP_CONFIG, 755f79cbc77SKalle Valo }; 756f79cbc77SKalle Valo 757f79cbc77SKalle Valo static const struct genl_multicast_group hwsim_mcgrps[] = { 758f79cbc77SKalle Valo [HWSIM_MCGRP_CONFIG] = { .name = "config", }, 759f79cbc77SKalle Valo }; 760f79cbc77SKalle Valo 761f79cbc77SKalle Valo /* MAC80211_HWSIM netlink policy */ 762f79cbc77SKalle Valo 763f79cbc77SKalle Valo static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = { 764f79cbc77SKalle Valo [HWSIM_ATTR_ADDR_RECEIVER] = NLA_POLICY_ETH_ADDR_COMPAT, 765f79cbc77SKalle Valo [HWSIM_ATTR_ADDR_TRANSMITTER] = NLA_POLICY_ETH_ADDR_COMPAT, 766f79cbc77SKalle Valo [HWSIM_ATTR_FRAME] = { .type = NLA_BINARY, 767f79cbc77SKalle Valo .len = IEEE80211_MAX_DATA_LEN }, 768f79cbc77SKalle Valo [HWSIM_ATTR_FLAGS] = { .type = NLA_U32 }, 769f79cbc77SKalle Valo [HWSIM_ATTR_RX_RATE] = { .type = NLA_U32 }, 770f79cbc77SKalle Valo [HWSIM_ATTR_SIGNAL] = { .type = NLA_U32 }, 771f79cbc77SKalle Valo [HWSIM_ATTR_TX_INFO] = { .type = NLA_BINARY, 772f79cbc77SKalle Valo .len = IEEE80211_TX_MAX_RATES * 773f79cbc77SKalle Valo sizeof(struct hwsim_tx_rate)}, 774f79cbc77SKalle Valo [HWSIM_ATTR_COOKIE] = { .type = NLA_U64 }, 775f79cbc77SKalle Valo [HWSIM_ATTR_CHANNELS] = { .type = NLA_U32 }, 776f79cbc77SKalle Valo [HWSIM_ATTR_RADIO_ID] = { .type = NLA_U32 }, 777f79cbc77SKalle Valo [HWSIM_ATTR_REG_HINT_ALPHA2] = { .type = NLA_STRING, .len = 2 }, 778f79cbc77SKalle Valo [HWSIM_ATTR_REG_CUSTOM_REG] = { .type = NLA_U32 }, 779f79cbc77SKalle Valo [HWSIM_ATTR_REG_STRICT_REG] = { .type = NLA_FLAG }, 780f79cbc77SKalle Valo [HWSIM_ATTR_SUPPORT_P2P_DEVICE] = { .type = NLA_FLAG }, 781f79cbc77SKalle Valo [HWSIM_ATTR_USE_CHANCTX] = { .type = NLA_FLAG }, 782f79cbc77SKalle Valo [HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE] = { .type = NLA_FLAG }, 783f79cbc77SKalle Valo [HWSIM_ATTR_RADIO_NAME] = { .type = NLA_STRING }, 784f79cbc77SKalle Valo [HWSIM_ATTR_NO_VIF] = { .type = NLA_FLAG }, 785f79cbc77SKalle Valo [HWSIM_ATTR_FREQ] = { .type = NLA_U32 }, 786f79cbc77SKalle Valo [HWSIM_ATTR_TX_INFO_FLAGS] = { .type = NLA_BINARY }, 787f79cbc77SKalle Valo [HWSIM_ATTR_PERM_ADDR] = NLA_POLICY_ETH_ADDR_COMPAT, 788f79cbc77SKalle Valo [HWSIM_ATTR_IFTYPE_SUPPORT] = { .type = NLA_U32 }, 789f79cbc77SKalle Valo [HWSIM_ATTR_CIPHER_SUPPORT] = { .type = NLA_BINARY }, 790f79cbc77SKalle Valo [HWSIM_ATTR_MLO_SUPPORT] = { .type = NLA_FLAG }, 791f79cbc77SKalle Valo }; 792f79cbc77SKalle Valo 793f79cbc77SKalle Valo #if IS_REACHABLE(CONFIG_VIRTIO) 794f79cbc77SKalle Valo 795f79cbc77SKalle Valo /* MAC80211_HWSIM virtio queues */ 796f79cbc77SKalle Valo static struct virtqueue *hwsim_vqs[HWSIM_NUM_VQS]; 797f79cbc77SKalle Valo static bool hwsim_virtio_enabled; 798f79cbc77SKalle Valo static DEFINE_SPINLOCK(hwsim_virtio_lock); 799f79cbc77SKalle Valo 800f79cbc77SKalle Valo static void hwsim_virtio_rx_work(struct work_struct *work); 801f79cbc77SKalle Valo static DECLARE_WORK(hwsim_virtio_rx, hwsim_virtio_rx_work); 802f79cbc77SKalle Valo 803f79cbc77SKalle Valo static int hwsim_tx_virtio(struct mac80211_hwsim_data *data, 804f79cbc77SKalle Valo struct sk_buff *skb) 805f79cbc77SKalle Valo { 806f79cbc77SKalle Valo struct scatterlist sg[1]; 807f79cbc77SKalle Valo unsigned long flags; 808f79cbc77SKalle Valo int err; 809f79cbc77SKalle Valo 810f79cbc77SKalle Valo spin_lock_irqsave(&hwsim_virtio_lock, flags); 811f79cbc77SKalle Valo if (!hwsim_virtio_enabled) { 812f79cbc77SKalle Valo err = -ENODEV; 813f79cbc77SKalle Valo goto out_free; 814f79cbc77SKalle Valo } 815f79cbc77SKalle Valo 816f79cbc77SKalle Valo sg_init_one(sg, skb->head, skb_end_offset(skb)); 817f79cbc77SKalle Valo err = virtqueue_add_outbuf(hwsim_vqs[HWSIM_VQ_TX], sg, 1, skb, 818f79cbc77SKalle Valo GFP_ATOMIC); 819f79cbc77SKalle Valo if (err) 820f79cbc77SKalle Valo goto out_free; 821f79cbc77SKalle Valo virtqueue_kick(hwsim_vqs[HWSIM_VQ_TX]); 822f79cbc77SKalle Valo spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 823f79cbc77SKalle Valo return 0; 824f79cbc77SKalle Valo 825f79cbc77SKalle Valo out_free: 826f79cbc77SKalle Valo spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 827f79cbc77SKalle Valo nlmsg_free(skb); 828f79cbc77SKalle Valo return err; 829f79cbc77SKalle Valo } 830f79cbc77SKalle Valo #else 831f79cbc77SKalle Valo /* cause a linker error if this ends up being needed */ 832f79cbc77SKalle Valo extern int hwsim_tx_virtio(struct mac80211_hwsim_data *data, 833f79cbc77SKalle Valo struct sk_buff *skb); 834f79cbc77SKalle Valo #define hwsim_virtio_enabled false 835f79cbc77SKalle Valo #endif 836f79cbc77SKalle Valo 837f79cbc77SKalle Valo static int hwsim_get_chanwidth(enum nl80211_chan_width bw) 838f79cbc77SKalle Valo { 839f79cbc77SKalle Valo switch (bw) { 840f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_20_NOHT: 841f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_20: 842f79cbc77SKalle Valo return 20; 843f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_40: 844f79cbc77SKalle Valo return 40; 845f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_80: 846f79cbc77SKalle Valo return 80; 847f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_80P80: 848f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_160: 849f79cbc77SKalle Valo return 160; 850f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_320: 851f79cbc77SKalle Valo return 320; 852f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_5: 853f79cbc77SKalle Valo return 5; 854f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_10: 855f79cbc77SKalle Valo return 10; 856f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_1: 857f79cbc77SKalle Valo return 1; 858f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_2: 859f79cbc77SKalle Valo return 2; 860f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_4: 861f79cbc77SKalle Valo return 4; 862f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_8: 863f79cbc77SKalle Valo return 8; 864f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_16: 865f79cbc77SKalle Valo return 16; 866f79cbc77SKalle Valo } 867f79cbc77SKalle Valo 868f79cbc77SKalle Valo return INT_MAX; 869f79cbc77SKalle Valo } 870f79cbc77SKalle Valo 871f79cbc77SKalle Valo static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, 872f79cbc77SKalle Valo struct sk_buff *skb, 873f79cbc77SKalle Valo struct ieee80211_channel *chan); 874f79cbc77SKalle Valo 875f79cbc77SKalle Valo /* sysfs attributes */ 876f79cbc77SKalle Valo static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) 877f79cbc77SKalle Valo { 878f79cbc77SKalle Valo struct mac80211_hwsim_data *data = dat; 879f79cbc77SKalle Valo struct hwsim_vif_priv *vp = (void *)vif->drv_priv; 880f79cbc77SKalle Valo struct sk_buff *skb; 881f79cbc77SKalle Valo struct ieee80211_pspoll *pspoll; 882f79cbc77SKalle Valo 883f79cbc77SKalle Valo if (!vp->assoc) 884f79cbc77SKalle Valo return; 885f79cbc77SKalle Valo 886f79cbc77SKalle Valo wiphy_dbg(data->hw->wiphy, 887f79cbc77SKalle Valo "%s: send PS-Poll to %pM for aid %d\n", 888f79cbc77SKalle Valo __func__, vp->bssid, vp->aid); 889f79cbc77SKalle Valo 890f79cbc77SKalle Valo skb = dev_alloc_skb(sizeof(*pspoll)); 891f79cbc77SKalle Valo if (!skb) 892f79cbc77SKalle Valo return; 893f79cbc77SKalle Valo pspoll = skb_put(skb, sizeof(*pspoll)); 894f79cbc77SKalle Valo pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | 895f79cbc77SKalle Valo IEEE80211_STYPE_PSPOLL | 896f79cbc77SKalle Valo IEEE80211_FCTL_PM); 897f79cbc77SKalle Valo pspoll->aid = cpu_to_le16(0xc000 | vp->aid); 898f79cbc77SKalle Valo memcpy(pspoll->bssid, vp->bssid, ETH_ALEN); 899f79cbc77SKalle Valo memcpy(pspoll->ta, mac, ETH_ALEN); 900f79cbc77SKalle Valo 901f79cbc77SKalle Valo rcu_read_lock(); 902f79cbc77SKalle Valo mac80211_hwsim_tx_frame(data->hw, skb, 903f79cbc77SKalle Valo rcu_dereference(vif->bss_conf.chanctx_conf)->def.chan); 904f79cbc77SKalle Valo rcu_read_unlock(); 905f79cbc77SKalle Valo } 906f79cbc77SKalle Valo 907f79cbc77SKalle Valo static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, 908f79cbc77SKalle Valo struct ieee80211_vif *vif, int ps) 909f79cbc77SKalle Valo { 910f79cbc77SKalle Valo struct hwsim_vif_priv *vp = (void *)vif->drv_priv; 911f79cbc77SKalle Valo struct sk_buff *skb; 912f79cbc77SKalle Valo struct ieee80211_hdr *hdr; 913f79cbc77SKalle Valo struct ieee80211_tx_info *cb; 914f79cbc77SKalle Valo 915f79cbc77SKalle Valo if (!vp->assoc) 916f79cbc77SKalle Valo return; 917f79cbc77SKalle Valo 918f79cbc77SKalle Valo wiphy_dbg(data->hw->wiphy, 919f79cbc77SKalle Valo "%s: send data::nullfunc to %pM ps=%d\n", 920f79cbc77SKalle Valo __func__, vp->bssid, ps); 921f79cbc77SKalle Valo 922f79cbc77SKalle Valo skb = dev_alloc_skb(sizeof(*hdr)); 923f79cbc77SKalle Valo if (!skb) 924f79cbc77SKalle Valo return; 925f79cbc77SKalle Valo hdr = skb_put(skb, sizeof(*hdr) - ETH_ALEN); 926f79cbc77SKalle Valo hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | 927f79cbc77SKalle Valo IEEE80211_STYPE_NULLFUNC | 928f79cbc77SKalle Valo IEEE80211_FCTL_TODS | 929f79cbc77SKalle Valo (ps ? IEEE80211_FCTL_PM : 0)); 930f79cbc77SKalle Valo hdr->duration_id = cpu_to_le16(0); 931f79cbc77SKalle Valo memcpy(hdr->addr1, vp->bssid, ETH_ALEN); 932f79cbc77SKalle Valo memcpy(hdr->addr2, mac, ETH_ALEN); 933f79cbc77SKalle Valo memcpy(hdr->addr3, vp->bssid, ETH_ALEN); 934f79cbc77SKalle Valo 935f79cbc77SKalle Valo cb = IEEE80211_SKB_CB(skb); 936f79cbc77SKalle Valo cb->control.rates[0].count = 1; 937f79cbc77SKalle Valo cb->control.rates[1].idx = -1; 938f79cbc77SKalle Valo 939f79cbc77SKalle Valo rcu_read_lock(); 940f79cbc77SKalle Valo mac80211_hwsim_tx_frame(data->hw, skb, 941f79cbc77SKalle Valo rcu_dereference(vif->bss_conf.chanctx_conf)->def.chan); 942f79cbc77SKalle Valo rcu_read_unlock(); 943f79cbc77SKalle Valo } 944f79cbc77SKalle Valo 945f79cbc77SKalle Valo 946f79cbc77SKalle Valo static void hwsim_send_nullfunc_ps(void *dat, u8 *mac, 947f79cbc77SKalle Valo struct ieee80211_vif *vif) 948f79cbc77SKalle Valo { 949f79cbc77SKalle Valo struct mac80211_hwsim_data *data = dat; 950f79cbc77SKalle Valo hwsim_send_nullfunc(data, mac, vif, 1); 951f79cbc77SKalle Valo } 952f79cbc77SKalle Valo 953f79cbc77SKalle Valo static void hwsim_send_nullfunc_no_ps(void *dat, u8 *mac, 954f79cbc77SKalle Valo struct ieee80211_vif *vif) 955f79cbc77SKalle Valo { 956f79cbc77SKalle Valo struct mac80211_hwsim_data *data = dat; 957f79cbc77SKalle Valo hwsim_send_nullfunc(data, mac, vif, 0); 958f79cbc77SKalle Valo } 959f79cbc77SKalle Valo 960f79cbc77SKalle Valo static int hwsim_fops_ps_read(void *dat, u64 *val) 961f79cbc77SKalle Valo { 962f79cbc77SKalle Valo struct mac80211_hwsim_data *data = dat; 963f79cbc77SKalle Valo *val = data->ps; 964f79cbc77SKalle Valo return 0; 965f79cbc77SKalle Valo } 966f79cbc77SKalle Valo 967f79cbc77SKalle Valo static int hwsim_fops_ps_write(void *dat, u64 val) 968f79cbc77SKalle Valo { 969f79cbc77SKalle Valo struct mac80211_hwsim_data *data = dat; 970f79cbc77SKalle Valo enum ps_mode old_ps; 971f79cbc77SKalle Valo 972f79cbc77SKalle Valo if (val != PS_DISABLED && val != PS_ENABLED && val != PS_AUTO_POLL && 973f79cbc77SKalle Valo val != PS_MANUAL_POLL) 974f79cbc77SKalle Valo return -EINVAL; 975f79cbc77SKalle Valo 976f79cbc77SKalle Valo if (val == PS_MANUAL_POLL) { 977f79cbc77SKalle Valo if (data->ps != PS_ENABLED) 978f79cbc77SKalle Valo return -EINVAL; 979f79cbc77SKalle Valo local_bh_disable(); 980f79cbc77SKalle Valo ieee80211_iterate_active_interfaces_atomic( 981f79cbc77SKalle Valo data->hw, IEEE80211_IFACE_ITER_NORMAL, 982f79cbc77SKalle Valo hwsim_send_ps_poll, data); 983f79cbc77SKalle Valo local_bh_enable(); 984f79cbc77SKalle Valo return 0; 985f79cbc77SKalle Valo } 986f79cbc77SKalle Valo old_ps = data->ps; 987f79cbc77SKalle Valo data->ps = val; 988f79cbc77SKalle Valo 989f79cbc77SKalle Valo local_bh_disable(); 990f79cbc77SKalle Valo if (old_ps == PS_DISABLED && val != PS_DISABLED) { 991f79cbc77SKalle Valo ieee80211_iterate_active_interfaces_atomic( 992f79cbc77SKalle Valo data->hw, IEEE80211_IFACE_ITER_NORMAL, 993f79cbc77SKalle Valo hwsim_send_nullfunc_ps, data); 994f79cbc77SKalle Valo } else if (old_ps != PS_DISABLED && val == PS_DISABLED) { 995f79cbc77SKalle Valo ieee80211_iterate_active_interfaces_atomic( 996f79cbc77SKalle Valo data->hw, IEEE80211_IFACE_ITER_NORMAL, 997f79cbc77SKalle Valo hwsim_send_nullfunc_no_ps, data); 998f79cbc77SKalle Valo } 999f79cbc77SKalle Valo local_bh_enable(); 1000f79cbc77SKalle Valo 1001f79cbc77SKalle Valo return 0; 1002f79cbc77SKalle Valo } 1003f79cbc77SKalle Valo 1004f79cbc77SKalle Valo DEFINE_DEBUGFS_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write, 1005f79cbc77SKalle Valo "%llu\n"); 1006f79cbc77SKalle Valo 1007f79cbc77SKalle Valo static int hwsim_write_simulate_radar(void *dat, u64 val) 1008f79cbc77SKalle Valo { 1009f79cbc77SKalle Valo struct mac80211_hwsim_data *data = dat; 1010f79cbc77SKalle Valo 1011f79cbc77SKalle Valo ieee80211_radar_detected(data->hw); 1012f79cbc77SKalle Valo 1013f79cbc77SKalle Valo return 0; 1014f79cbc77SKalle Valo } 1015f79cbc77SKalle Valo 1016f79cbc77SKalle Valo DEFINE_DEBUGFS_ATTRIBUTE(hwsim_simulate_radar, NULL, 1017f79cbc77SKalle Valo hwsim_write_simulate_radar, "%llu\n"); 1018f79cbc77SKalle Valo 1019f79cbc77SKalle Valo static int hwsim_fops_group_read(void *dat, u64 *val) 1020f79cbc77SKalle Valo { 1021f79cbc77SKalle Valo struct mac80211_hwsim_data *data = dat; 1022f79cbc77SKalle Valo *val = data->group; 1023f79cbc77SKalle Valo return 0; 1024f79cbc77SKalle Valo } 1025f79cbc77SKalle Valo 1026f79cbc77SKalle Valo static int hwsim_fops_group_write(void *dat, u64 val) 1027f79cbc77SKalle Valo { 1028f79cbc77SKalle Valo struct mac80211_hwsim_data *data = dat; 1029f79cbc77SKalle Valo data->group = val; 1030f79cbc77SKalle Valo return 0; 1031f79cbc77SKalle Valo } 1032f79cbc77SKalle Valo 1033f79cbc77SKalle Valo DEFINE_DEBUGFS_ATTRIBUTE(hwsim_fops_group, 1034f79cbc77SKalle Valo hwsim_fops_group_read, hwsim_fops_group_write, 1035f79cbc77SKalle Valo "%llx\n"); 1036f79cbc77SKalle Valo 1037f79cbc77SKalle Valo static int hwsim_fops_rx_rssi_read(void *dat, u64 *val) 1038f79cbc77SKalle Valo { 1039f79cbc77SKalle Valo struct mac80211_hwsim_data *data = dat; 1040f79cbc77SKalle Valo *val = data->rx_rssi; 1041f79cbc77SKalle Valo return 0; 1042f79cbc77SKalle Valo } 1043f79cbc77SKalle Valo 1044f79cbc77SKalle Valo static int hwsim_fops_rx_rssi_write(void *dat, u64 val) 1045f79cbc77SKalle Valo { 1046f79cbc77SKalle Valo struct mac80211_hwsim_data *data = dat; 1047f79cbc77SKalle Valo int rssi = (int)val; 1048f79cbc77SKalle Valo 1049f79cbc77SKalle Valo if (rssi >= 0 || rssi < -100) 1050f79cbc77SKalle Valo return -EINVAL; 1051f79cbc77SKalle Valo 1052f79cbc77SKalle Valo data->rx_rssi = rssi; 1053f79cbc77SKalle Valo return 0; 1054f79cbc77SKalle Valo } 1055f79cbc77SKalle Valo 1056f79cbc77SKalle Valo DEFINE_DEBUGFS_ATTRIBUTE(hwsim_fops_rx_rssi, 1057f79cbc77SKalle Valo hwsim_fops_rx_rssi_read, hwsim_fops_rx_rssi_write, 1058f79cbc77SKalle Valo "%lld\n"); 1059f79cbc77SKalle Valo 1060f79cbc77SKalle Valo static netdev_tx_t hwsim_mon_xmit(struct sk_buff *skb, 1061f79cbc77SKalle Valo struct net_device *dev) 1062f79cbc77SKalle Valo { 1063f79cbc77SKalle Valo /* TODO: allow packet injection */ 1064f79cbc77SKalle Valo dev_kfree_skb(skb); 1065f79cbc77SKalle Valo return NETDEV_TX_OK; 1066f79cbc77SKalle Valo } 1067f79cbc77SKalle Valo 1068f79cbc77SKalle Valo static inline u64 mac80211_hwsim_get_tsf_raw(void) 1069f79cbc77SKalle Valo { 1070f79cbc77SKalle Valo return ktime_to_us(ktime_get_real()); 1071f79cbc77SKalle Valo } 1072f79cbc77SKalle Valo 1073f79cbc77SKalle Valo static __le64 __mac80211_hwsim_get_tsf(struct mac80211_hwsim_data *data) 1074f79cbc77SKalle Valo { 1075f79cbc77SKalle Valo u64 now = mac80211_hwsim_get_tsf_raw(); 1076f79cbc77SKalle Valo return cpu_to_le64(now + data->tsf_offset); 1077f79cbc77SKalle Valo } 1078f79cbc77SKalle Valo 1079f79cbc77SKalle Valo static u64 mac80211_hwsim_get_tsf(struct ieee80211_hw *hw, 1080f79cbc77SKalle Valo struct ieee80211_vif *vif) 1081f79cbc77SKalle Valo { 1082f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 1083f79cbc77SKalle Valo return le64_to_cpu(__mac80211_hwsim_get_tsf(data)); 1084f79cbc77SKalle Valo } 1085f79cbc77SKalle Valo 1086f79cbc77SKalle Valo static void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw, 1087f79cbc77SKalle Valo struct ieee80211_vif *vif, u64 tsf) 1088f79cbc77SKalle Valo { 1089f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 1090f79cbc77SKalle Valo u64 now = mac80211_hwsim_get_tsf(hw, vif); 1091f79cbc77SKalle Valo /* MLD not supported here */ 1092f79cbc77SKalle Valo u32 bcn_int = data->link_data[0].beacon_int; 1093f79cbc77SKalle Valo u64 delta = abs(tsf - now); 1094f79cbc77SKalle Valo 1095f79cbc77SKalle Valo /* adjust after beaconing with new timestamp at old TBTT */ 1096f79cbc77SKalle Valo if (tsf > now) { 1097f79cbc77SKalle Valo data->tsf_offset += delta; 1098f79cbc77SKalle Valo data->bcn_delta = do_div(delta, bcn_int); 1099f79cbc77SKalle Valo } else { 1100f79cbc77SKalle Valo data->tsf_offset -= delta; 1101f79cbc77SKalle Valo data->bcn_delta = -(s64)do_div(delta, bcn_int); 1102f79cbc77SKalle Valo } 1103f79cbc77SKalle Valo } 1104f79cbc77SKalle Valo 1105f79cbc77SKalle Valo static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, 1106f79cbc77SKalle Valo struct sk_buff *tx_skb, 1107f79cbc77SKalle Valo struct ieee80211_channel *chan) 1108f79cbc77SKalle Valo { 1109f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 1110f79cbc77SKalle Valo struct sk_buff *skb; 1111f79cbc77SKalle Valo struct hwsim_radiotap_hdr *hdr; 1112f79cbc77SKalle Valo u16 flags, bitrate; 1113f79cbc77SKalle Valo struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_skb); 1114f79cbc77SKalle Valo struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info); 1115f79cbc77SKalle Valo 1116f79cbc77SKalle Valo if (!txrate) 1117f79cbc77SKalle Valo bitrate = 0; 1118f79cbc77SKalle Valo else 1119f79cbc77SKalle Valo bitrate = txrate->bitrate; 1120f79cbc77SKalle Valo 1121f79cbc77SKalle Valo if (!netif_running(hwsim_mon)) 1122f79cbc77SKalle Valo return; 1123f79cbc77SKalle Valo 1124f79cbc77SKalle Valo skb = skb_copy_expand(tx_skb, sizeof(*hdr), 0, GFP_ATOMIC); 1125f79cbc77SKalle Valo if (skb == NULL) 1126f79cbc77SKalle Valo return; 1127f79cbc77SKalle Valo 1128f79cbc77SKalle Valo hdr = skb_push(skb, sizeof(*hdr)); 1129f79cbc77SKalle Valo hdr->hdr.it_version = PKTHDR_RADIOTAP_VERSION; 1130f79cbc77SKalle Valo hdr->hdr.it_pad = 0; 1131f79cbc77SKalle Valo hdr->hdr.it_len = cpu_to_le16(sizeof(*hdr)); 1132f79cbc77SKalle Valo hdr->hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | 1133f79cbc77SKalle Valo (1 << IEEE80211_RADIOTAP_RATE) | 1134f79cbc77SKalle Valo (1 << IEEE80211_RADIOTAP_TSFT) | 1135f79cbc77SKalle Valo (1 << IEEE80211_RADIOTAP_CHANNEL)); 1136f79cbc77SKalle Valo hdr->rt_tsft = __mac80211_hwsim_get_tsf(data); 1137f79cbc77SKalle Valo hdr->rt_flags = 0; 1138f79cbc77SKalle Valo hdr->rt_rate = bitrate / 5; 1139f79cbc77SKalle Valo hdr->rt_channel = cpu_to_le16(chan->center_freq); 1140f79cbc77SKalle Valo flags = IEEE80211_CHAN_2GHZ; 1141f79cbc77SKalle Valo if (txrate && txrate->flags & IEEE80211_RATE_ERP_G) 1142f79cbc77SKalle Valo flags |= IEEE80211_CHAN_OFDM; 1143f79cbc77SKalle Valo else 1144f79cbc77SKalle Valo flags |= IEEE80211_CHAN_CCK; 1145f79cbc77SKalle Valo hdr->rt_chbitmask = cpu_to_le16(flags); 1146f79cbc77SKalle Valo 1147f79cbc77SKalle Valo skb->dev = hwsim_mon; 1148f79cbc77SKalle Valo skb_reset_mac_header(skb); 1149f79cbc77SKalle Valo skb->ip_summed = CHECKSUM_UNNECESSARY; 1150f79cbc77SKalle Valo skb->pkt_type = PACKET_OTHERHOST; 1151f79cbc77SKalle Valo skb->protocol = htons(ETH_P_802_2); 1152f79cbc77SKalle Valo memset(skb->cb, 0, sizeof(skb->cb)); 1153f79cbc77SKalle Valo netif_rx(skb); 1154f79cbc77SKalle Valo } 1155f79cbc77SKalle Valo 1156f79cbc77SKalle Valo 1157f79cbc77SKalle Valo static void mac80211_hwsim_monitor_ack(struct ieee80211_channel *chan, 1158f79cbc77SKalle Valo const u8 *addr) 1159f79cbc77SKalle Valo { 1160f79cbc77SKalle Valo struct sk_buff *skb; 1161f79cbc77SKalle Valo struct hwsim_radiotap_ack_hdr *hdr; 1162f79cbc77SKalle Valo u16 flags; 1163f79cbc77SKalle Valo struct ieee80211_hdr *hdr11; 1164f79cbc77SKalle Valo 1165f79cbc77SKalle Valo if (!netif_running(hwsim_mon)) 1166f79cbc77SKalle Valo return; 1167f79cbc77SKalle Valo 1168f79cbc77SKalle Valo skb = dev_alloc_skb(100); 1169f79cbc77SKalle Valo if (skb == NULL) 1170f79cbc77SKalle Valo return; 1171f79cbc77SKalle Valo 1172f79cbc77SKalle Valo hdr = skb_put(skb, sizeof(*hdr)); 1173f79cbc77SKalle Valo hdr->hdr.it_version = PKTHDR_RADIOTAP_VERSION; 1174f79cbc77SKalle Valo hdr->hdr.it_pad = 0; 1175f79cbc77SKalle Valo hdr->hdr.it_len = cpu_to_le16(sizeof(*hdr)); 1176f79cbc77SKalle Valo hdr->hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | 1177f79cbc77SKalle Valo (1 << IEEE80211_RADIOTAP_CHANNEL)); 1178f79cbc77SKalle Valo hdr->rt_flags = 0; 1179f79cbc77SKalle Valo hdr->pad = 0; 1180f79cbc77SKalle Valo hdr->rt_channel = cpu_to_le16(chan->center_freq); 1181f79cbc77SKalle Valo flags = IEEE80211_CHAN_2GHZ; 1182f79cbc77SKalle Valo hdr->rt_chbitmask = cpu_to_le16(flags); 1183f79cbc77SKalle Valo 1184f79cbc77SKalle Valo hdr11 = skb_put(skb, 10); 1185f79cbc77SKalle Valo hdr11->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | 1186f79cbc77SKalle Valo IEEE80211_STYPE_ACK); 1187f79cbc77SKalle Valo hdr11->duration_id = cpu_to_le16(0); 1188f79cbc77SKalle Valo memcpy(hdr11->addr1, addr, ETH_ALEN); 1189f79cbc77SKalle Valo 1190f79cbc77SKalle Valo skb->dev = hwsim_mon; 1191f79cbc77SKalle Valo skb_reset_mac_header(skb); 1192f79cbc77SKalle Valo skb->ip_summed = CHECKSUM_UNNECESSARY; 1193f79cbc77SKalle Valo skb->pkt_type = PACKET_OTHERHOST; 1194f79cbc77SKalle Valo skb->protocol = htons(ETH_P_802_2); 1195f79cbc77SKalle Valo memset(skb->cb, 0, sizeof(skb->cb)); 1196f79cbc77SKalle Valo netif_rx(skb); 1197f79cbc77SKalle Valo } 1198f79cbc77SKalle Valo 1199f79cbc77SKalle Valo struct mac80211_hwsim_addr_match_data { 1200f79cbc77SKalle Valo u8 addr[ETH_ALEN]; 1201f79cbc77SKalle Valo bool ret; 1202f79cbc77SKalle Valo }; 1203f79cbc77SKalle Valo 1204f79cbc77SKalle Valo static void mac80211_hwsim_addr_iter(void *data, u8 *mac, 1205f79cbc77SKalle Valo struct ieee80211_vif *vif) 1206f79cbc77SKalle Valo { 1207f79cbc77SKalle Valo int i; 1208f79cbc77SKalle Valo struct mac80211_hwsim_addr_match_data *md = data; 1209f79cbc77SKalle Valo 1210f79cbc77SKalle Valo if (memcmp(mac, md->addr, ETH_ALEN) == 0) { 1211f79cbc77SKalle Valo md->ret = true; 1212f79cbc77SKalle Valo return; 1213f79cbc77SKalle Valo } 1214f79cbc77SKalle Valo 1215f79cbc77SKalle Valo /* Match the link address */ 1216f79cbc77SKalle Valo for (i = 0; i < ARRAY_SIZE(vif->link_conf); i++) { 1217f79cbc77SKalle Valo struct ieee80211_bss_conf *conf; 1218f79cbc77SKalle Valo 1219f79cbc77SKalle Valo conf = rcu_dereference(vif->link_conf[i]); 1220f79cbc77SKalle Valo if (!conf) 1221f79cbc77SKalle Valo continue; 1222f79cbc77SKalle Valo 1223f79cbc77SKalle Valo if (memcmp(conf->addr, md->addr, ETH_ALEN) == 0) { 1224f79cbc77SKalle Valo md->ret = true; 1225f79cbc77SKalle Valo return; 1226f79cbc77SKalle Valo } 1227f79cbc77SKalle Valo } 1228f79cbc77SKalle Valo } 1229f79cbc77SKalle Valo 1230f79cbc77SKalle Valo static bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data, 1231f79cbc77SKalle Valo const u8 *addr) 1232f79cbc77SKalle Valo { 1233f79cbc77SKalle Valo struct mac80211_hwsim_addr_match_data md = { 1234f79cbc77SKalle Valo .ret = false, 1235f79cbc77SKalle Valo }; 1236f79cbc77SKalle Valo 1237f79cbc77SKalle Valo if (data->scanning && memcmp(addr, data->scan_addr, ETH_ALEN) == 0) 1238f79cbc77SKalle Valo return true; 1239f79cbc77SKalle Valo 1240f79cbc77SKalle Valo memcpy(md.addr, addr, ETH_ALEN); 1241f79cbc77SKalle Valo 1242f79cbc77SKalle Valo ieee80211_iterate_active_interfaces_atomic(data->hw, 1243f79cbc77SKalle Valo IEEE80211_IFACE_ITER_NORMAL, 1244f79cbc77SKalle Valo mac80211_hwsim_addr_iter, 1245f79cbc77SKalle Valo &md); 1246f79cbc77SKalle Valo 1247f79cbc77SKalle Valo return md.ret; 1248f79cbc77SKalle Valo } 1249f79cbc77SKalle Valo 1250f79cbc77SKalle Valo static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data, 1251f79cbc77SKalle Valo struct sk_buff *skb) 1252f79cbc77SKalle Valo { 1253f79cbc77SKalle Valo switch (data->ps) { 1254f79cbc77SKalle Valo case PS_DISABLED: 1255f79cbc77SKalle Valo return true; 1256f79cbc77SKalle Valo case PS_ENABLED: 1257f79cbc77SKalle Valo return false; 1258f79cbc77SKalle Valo case PS_AUTO_POLL: 1259f79cbc77SKalle Valo /* TODO: accept (some) Beacons by default and other frames only 1260f79cbc77SKalle Valo * if pending PS-Poll has been sent */ 1261f79cbc77SKalle Valo return true; 1262f79cbc77SKalle Valo case PS_MANUAL_POLL: 1263f79cbc77SKalle Valo /* Allow unicast frames to own address if there is a pending 1264f79cbc77SKalle Valo * PS-Poll */ 1265f79cbc77SKalle Valo if (data->ps_poll_pending && 1266f79cbc77SKalle Valo mac80211_hwsim_addr_match(data, skb->data + 4)) { 1267f79cbc77SKalle Valo data->ps_poll_pending = false; 1268f79cbc77SKalle Valo return true; 1269f79cbc77SKalle Valo } 1270f79cbc77SKalle Valo return false; 1271f79cbc77SKalle Valo } 1272f79cbc77SKalle Valo 1273f79cbc77SKalle Valo return true; 1274f79cbc77SKalle Valo } 1275f79cbc77SKalle Valo 1276f79cbc77SKalle Valo static int hwsim_unicast_netgroup(struct mac80211_hwsim_data *data, 1277f79cbc77SKalle Valo struct sk_buff *skb, int portid) 1278f79cbc77SKalle Valo { 1279f79cbc77SKalle Valo struct net *net; 1280f79cbc77SKalle Valo bool found = false; 1281f79cbc77SKalle Valo int res = -ENOENT; 1282f79cbc77SKalle Valo 1283f79cbc77SKalle Valo rcu_read_lock(); 1284f79cbc77SKalle Valo for_each_net_rcu(net) { 1285f79cbc77SKalle Valo if (data->netgroup == hwsim_net_get_netgroup(net)) { 1286f79cbc77SKalle Valo res = genlmsg_unicast(net, skb, portid); 1287f79cbc77SKalle Valo found = true; 1288f79cbc77SKalle Valo break; 1289f79cbc77SKalle Valo } 1290f79cbc77SKalle Valo } 1291f79cbc77SKalle Valo rcu_read_unlock(); 1292f79cbc77SKalle Valo 1293f79cbc77SKalle Valo if (!found) 1294f79cbc77SKalle Valo nlmsg_free(skb); 1295f79cbc77SKalle Valo 1296f79cbc77SKalle Valo return res; 1297f79cbc77SKalle Valo } 1298f79cbc77SKalle Valo 1299f79cbc77SKalle Valo static void mac80211_hwsim_config_mac_nl(struct ieee80211_hw *hw, 1300f79cbc77SKalle Valo const u8 *addr, bool add) 1301f79cbc77SKalle Valo { 1302f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 1303f79cbc77SKalle Valo u32 _portid = READ_ONCE(data->wmediumd); 1304f79cbc77SKalle Valo struct sk_buff *skb; 1305f79cbc77SKalle Valo void *msg_head; 1306f79cbc77SKalle Valo 1307f79cbc77SKalle Valo WARN_ON(!is_valid_ether_addr(addr)); 1308f79cbc77SKalle Valo 1309f79cbc77SKalle Valo if (!_portid && !hwsim_virtio_enabled) 1310f79cbc77SKalle Valo return; 1311f79cbc77SKalle Valo 1312f79cbc77SKalle Valo skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_ATOMIC); 1313f79cbc77SKalle Valo if (!skb) 1314f79cbc77SKalle Valo return; 1315f79cbc77SKalle Valo 1316f79cbc77SKalle Valo msg_head = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, 1317f79cbc77SKalle Valo add ? HWSIM_CMD_ADD_MAC_ADDR : 1318f79cbc77SKalle Valo HWSIM_CMD_DEL_MAC_ADDR); 1319f79cbc77SKalle Valo if (!msg_head) { 1320f79cbc77SKalle Valo pr_debug("mac80211_hwsim: problem with msg_head\n"); 1321f79cbc77SKalle Valo goto nla_put_failure; 1322f79cbc77SKalle Valo } 1323f79cbc77SKalle Valo 1324f79cbc77SKalle Valo if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER, 1325f79cbc77SKalle Valo ETH_ALEN, data->addresses[1].addr)) 1326f79cbc77SKalle Valo goto nla_put_failure; 1327f79cbc77SKalle Valo 1328f79cbc77SKalle Valo if (nla_put(skb, HWSIM_ATTR_ADDR_RECEIVER, ETH_ALEN, addr)) 1329f79cbc77SKalle Valo goto nla_put_failure; 1330f79cbc77SKalle Valo 1331f79cbc77SKalle Valo genlmsg_end(skb, msg_head); 1332f79cbc77SKalle Valo 1333f79cbc77SKalle Valo if (hwsim_virtio_enabled) 1334f79cbc77SKalle Valo hwsim_tx_virtio(data, skb); 1335f79cbc77SKalle Valo else 1336f79cbc77SKalle Valo hwsim_unicast_netgroup(data, skb, _portid); 1337f79cbc77SKalle Valo return; 1338f79cbc77SKalle Valo nla_put_failure: 1339f79cbc77SKalle Valo nlmsg_free(skb); 1340f79cbc77SKalle Valo } 1341f79cbc77SKalle Valo 1342f79cbc77SKalle Valo static inline u16 trans_tx_rate_flags_ieee2hwsim(struct ieee80211_tx_rate *rate) 1343f79cbc77SKalle Valo { 1344f79cbc77SKalle Valo u16 result = 0; 1345f79cbc77SKalle Valo 1346f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_USE_RTS_CTS) 1347f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_USE_RTS_CTS; 1348f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT) 1349f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_USE_CTS_PROTECT; 1350f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) 1351f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_USE_SHORT_PREAMBLE; 1352f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_MCS) 1353f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_MCS; 1354f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD) 1355f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_GREEN_FIELD; 1356f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) 1357f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_40_MHZ_WIDTH; 1358f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_DUP_DATA) 1359f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_DUP_DATA; 1360f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_SHORT_GI) 1361f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_SHORT_GI; 1362f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_VHT_MCS) 1363f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_VHT_MCS; 1364f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH) 1365f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_80_MHZ_WIDTH; 1366f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH) 1367f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_160_MHZ_WIDTH; 1368f79cbc77SKalle Valo 1369f79cbc77SKalle Valo return result; 1370f79cbc77SKalle Valo } 1371f79cbc77SKalle Valo 1372f79cbc77SKalle Valo static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, 1373f79cbc77SKalle Valo struct sk_buff *my_skb, 1374f79cbc77SKalle Valo int dst_portid, 1375f79cbc77SKalle Valo struct ieee80211_channel *channel) 1376f79cbc77SKalle Valo { 1377f79cbc77SKalle Valo struct sk_buff *skb; 1378f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 1379f79cbc77SKalle Valo struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) my_skb->data; 1380f79cbc77SKalle Valo struct ieee80211_tx_info *info = IEEE80211_SKB_CB(my_skb); 1381f79cbc77SKalle Valo void *msg_head; 1382f79cbc77SKalle Valo unsigned int hwsim_flags = 0; 1383f79cbc77SKalle Valo int i; 1384f79cbc77SKalle Valo struct hwsim_tx_rate tx_attempts[IEEE80211_TX_MAX_RATES]; 1385f79cbc77SKalle Valo struct hwsim_tx_rate_flag tx_attempts_flags[IEEE80211_TX_MAX_RATES]; 1386f79cbc77SKalle Valo uintptr_t cookie; 1387f79cbc77SKalle Valo 1388f79cbc77SKalle Valo if (data->ps != PS_DISABLED) 1389f79cbc77SKalle Valo hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); 1390f79cbc77SKalle Valo /* If the queue contains MAX_QUEUE skb's drop some */ 1391f79cbc77SKalle Valo if (skb_queue_len(&data->pending) >= MAX_QUEUE) { 1392f79cbc77SKalle Valo /* Dropping until WARN_QUEUE level */ 1393f79cbc77SKalle Valo while (skb_queue_len(&data->pending) >= WARN_QUEUE) { 1394f79cbc77SKalle Valo ieee80211_free_txskb(hw, skb_dequeue(&data->pending)); 1395f79cbc77SKalle Valo data->tx_dropped++; 1396f79cbc77SKalle Valo } 1397f79cbc77SKalle Valo } 1398f79cbc77SKalle Valo 1399f79cbc77SKalle Valo skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_ATOMIC); 1400f79cbc77SKalle Valo if (skb == NULL) 1401f79cbc77SKalle Valo goto nla_put_failure; 1402f79cbc77SKalle Valo 1403f79cbc77SKalle Valo msg_head = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, 1404f79cbc77SKalle Valo HWSIM_CMD_FRAME); 1405f79cbc77SKalle Valo if (msg_head == NULL) { 1406f79cbc77SKalle Valo pr_debug("mac80211_hwsim: problem with msg_head\n"); 1407f79cbc77SKalle Valo goto nla_put_failure; 1408f79cbc77SKalle Valo } 1409f79cbc77SKalle Valo 1410f79cbc77SKalle Valo if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER, 1411f79cbc77SKalle Valo ETH_ALEN, data->addresses[1].addr)) 1412f79cbc77SKalle Valo goto nla_put_failure; 1413f79cbc77SKalle Valo 1414f79cbc77SKalle Valo /* We get the skb->data */ 1415f79cbc77SKalle Valo if (nla_put(skb, HWSIM_ATTR_FRAME, my_skb->len, my_skb->data)) 1416f79cbc77SKalle Valo goto nla_put_failure; 1417f79cbc77SKalle Valo 1418f79cbc77SKalle Valo /* We get the flags for this transmission, and we translate them to 1419f79cbc77SKalle Valo wmediumd flags */ 1420f79cbc77SKalle Valo 1421f79cbc77SKalle Valo if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) 1422f79cbc77SKalle Valo hwsim_flags |= HWSIM_TX_CTL_REQ_TX_STATUS; 1423f79cbc77SKalle Valo 1424f79cbc77SKalle Valo if (info->flags & IEEE80211_TX_CTL_NO_ACK) 1425f79cbc77SKalle Valo hwsim_flags |= HWSIM_TX_CTL_NO_ACK; 1426f79cbc77SKalle Valo 1427f79cbc77SKalle Valo if (nla_put_u32(skb, HWSIM_ATTR_FLAGS, hwsim_flags)) 1428f79cbc77SKalle Valo goto nla_put_failure; 1429f79cbc77SKalle Valo 1430f79cbc77SKalle Valo if (nla_put_u32(skb, HWSIM_ATTR_FREQ, channel->center_freq)) 1431f79cbc77SKalle Valo goto nla_put_failure; 1432f79cbc77SKalle Valo 1433f79cbc77SKalle Valo /* We get the tx control (rate and retries) info*/ 1434f79cbc77SKalle Valo 1435f79cbc77SKalle Valo for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { 1436f79cbc77SKalle Valo tx_attempts[i].idx = info->status.rates[i].idx; 1437f79cbc77SKalle Valo tx_attempts_flags[i].idx = info->status.rates[i].idx; 1438f79cbc77SKalle Valo tx_attempts[i].count = info->status.rates[i].count; 1439f79cbc77SKalle Valo tx_attempts_flags[i].flags = 1440f79cbc77SKalle Valo trans_tx_rate_flags_ieee2hwsim( 1441f79cbc77SKalle Valo &info->status.rates[i]); 1442f79cbc77SKalle Valo } 1443f79cbc77SKalle Valo 1444f79cbc77SKalle Valo if (nla_put(skb, HWSIM_ATTR_TX_INFO, 1445f79cbc77SKalle Valo sizeof(struct hwsim_tx_rate)*IEEE80211_TX_MAX_RATES, 1446f79cbc77SKalle Valo tx_attempts)) 1447f79cbc77SKalle Valo goto nla_put_failure; 1448f79cbc77SKalle Valo 1449f79cbc77SKalle Valo if (nla_put(skb, HWSIM_ATTR_TX_INFO_FLAGS, 1450f79cbc77SKalle Valo sizeof(struct hwsim_tx_rate_flag) * IEEE80211_TX_MAX_RATES, 1451f79cbc77SKalle Valo tx_attempts_flags)) 1452f79cbc77SKalle Valo goto nla_put_failure; 1453f79cbc77SKalle Valo 1454f79cbc77SKalle Valo /* We create a cookie to identify this skb */ 1455f79cbc77SKalle Valo cookie = atomic_inc_return(&data->pending_cookie); 1456f79cbc77SKalle Valo info->rate_driver_data[0] = (void *)cookie; 1457f79cbc77SKalle Valo if (nla_put_u64_64bit(skb, HWSIM_ATTR_COOKIE, cookie, HWSIM_ATTR_PAD)) 1458f79cbc77SKalle Valo goto nla_put_failure; 1459f79cbc77SKalle Valo 1460f79cbc77SKalle Valo genlmsg_end(skb, msg_head); 1461f79cbc77SKalle Valo 1462f79cbc77SKalle Valo if (hwsim_virtio_enabled) { 1463f79cbc77SKalle Valo if (hwsim_tx_virtio(data, skb)) 1464f79cbc77SKalle Valo goto err_free_txskb; 1465f79cbc77SKalle Valo } else { 1466f79cbc77SKalle Valo if (hwsim_unicast_netgroup(data, skb, dst_portid)) 1467f79cbc77SKalle Valo goto err_free_txskb; 1468f79cbc77SKalle Valo } 1469f79cbc77SKalle Valo 1470f79cbc77SKalle Valo /* Enqueue the packet */ 1471f79cbc77SKalle Valo skb_queue_tail(&data->pending, my_skb); 1472f79cbc77SKalle Valo data->tx_pkts++; 1473f79cbc77SKalle Valo data->tx_bytes += my_skb->len; 1474f79cbc77SKalle Valo return; 1475f79cbc77SKalle Valo 1476f79cbc77SKalle Valo nla_put_failure: 1477f79cbc77SKalle Valo nlmsg_free(skb); 1478f79cbc77SKalle Valo err_free_txskb: 1479f79cbc77SKalle Valo pr_debug("mac80211_hwsim: error occurred in %s\n", __func__); 1480f79cbc77SKalle Valo ieee80211_free_txskb(hw, my_skb); 1481f79cbc77SKalle Valo data->tx_failed++; 1482f79cbc77SKalle Valo } 1483f79cbc77SKalle Valo 1484f79cbc77SKalle Valo static bool hwsim_chans_compat(struct ieee80211_channel *c1, 1485f79cbc77SKalle Valo struct ieee80211_channel *c2) 1486f79cbc77SKalle Valo { 1487f79cbc77SKalle Valo if (!c1 || !c2) 1488f79cbc77SKalle Valo return false; 1489f79cbc77SKalle Valo 1490f79cbc77SKalle Valo return c1->center_freq == c2->center_freq; 1491f79cbc77SKalle Valo } 1492f79cbc77SKalle Valo 1493f79cbc77SKalle Valo struct tx_iter_data { 1494f79cbc77SKalle Valo struct ieee80211_channel *channel; 1495f79cbc77SKalle Valo bool receive; 1496f79cbc77SKalle Valo }; 1497f79cbc77SKalle Valo 1498f79cbc77SKalle Valo static void mac80211_hwsim_tx_iter(void *_data, u8 *addr, 1499f79cbc77SKalle Valo struct ieee80211_vif *vif) 1500f79cbc77SKalle Valo { 1501f79cbc77SKalle Valo struct tx_iter_data *data = _data; 1502f79cbc77SKalle Valo int i; 1503f79cbc77SKalle Valo 1504f79cbc77SKalle Valo for (i = 0; i < ARRAY_SIZE(vif->link_conf); i++) { 1505f79cbc77SKalle Valo struct ieee80211_bss_conf *conf; 1506f79cbc77SKalle Valo struct ieee80211_chanctx_conf *chanctx; 1507f79cbc77SKalle Valo 1508f79cbc77SKalle Valo conf = rcu_dereference(vif->link_conf[i]); 1509f79cbc77SKalle Valo if (!conf) 1510f79cbc77SKalle Valo continue; 1511f79cbc77SKalle Valo 1512f79cbc77SKalle Valo chanctx = rcu_dereference(conf->chanctx_conf); 1513f79cbc77SKalle Valo if (!chanctx) 1514f79cbc77SKalle Valo continue; 1515f79cbc77SKalle Valo 1516f79cbc77SKalle Valo if (!hwsim_chans_compat(data->channel, chanctx->def.chan)) 1517f79cbc77SKalle Valo continue; 1518f79cbc77SKalle Valo 1519f79cbc77SKalle Valo data->receive = true; 1520f79cbc77SKalle Valo return; 1521f79cbc77SKalle Valo } 1522f79cbc77SKalle Valo } 1523f79cbc77SKalle Valo 1524f79cbc77SKalle Valo static void mac80211_hwsim_add_vendor_rtap(struct sk_buff *skb) 1525f79cbc77SKalle Valo { 1526f79cbc77SKalle Valo /* 1527f79cbc77SKalle Valo * To enable this code, #define the HWSIM_RADIOTAP_OUI, 1528f79cbc77SKalle Valo * e.g. like this: 1529f79cbc77SKalle Valo * #define HWSIM_RADIOTAP_OUI "\x02\x00\x00" 1530f79cbc77SKalle Valo * (but you should use a valid OUI, not that) 1531f79cbc77SKalle Valo * 1532f79cbc77SKalle Valo * If anyone wants to 'donate' a radiotap OUI/subns code 1533f79cbc77SKalle Valo * please send a patch removing this #ifdef and changing 1534f79cbc77SKalle Valo * the values accordingly. 1535f79cbc77SKalle Valo */ 1536f79cbc77SKalle Valo #ifdef HWSIM_RADIOTAP_OUI 1537f79cbc77SKalle Valo struct ieee80211_radiotap_vendor_tlv *rtap; 1538f79cbc77SKalle Valo static const char vendor_data[8] = "ABCDEFGH"; 1539f79cbc77SKalle Valo 1540f79cbc77SKalle Valo // Make sure no padding is needed 1541f79cbc77SKalle Valo BUILD_BUG_ON(sizeof(vendor_data) % 4); 1542f79cbc77SKalle Valo /* this is last radiotap info before the mac header, so 1543f79cbc77SKalle Valo * skb_reset_mac_header for mac8022 to know the end of 1544f79cbc77SKalle Valo * the radiotap TLV/beginning of the 802.11 header 1545f79cbc77SKalle Valo */ 1546f79cbc77SKalle Valo skb_reset_mac_header(skb); 1547f79cbc77SKalle Valo 1548f79cbc77SKalle Valo /* 1549f79cbc77SKalle Valo * Note that this code requires the headroom in the SKB 1550f79cbc77SKalle Valo * that was allocated earlier. 1551f79cbc77SKalle Valo */ 1552f79cbc77SKalle Valo rtap = skb_push(skb, sizeof(*rtap) + sizeof(vendor_data)); 1553f79cbc77SKalle Valo 1554f79cbc77SKalle Valo rtap->len = cpu_to_le16(sizeof(*rtap) - 1555f79cbc77SKalle Valo sizeof(struct ieee80211_radiotap_tlv) + 1556f79cbc77SKalle Valo sizeof(vendor_data)); 1557f79cbc77SKalle Valo rtap->type = cpu_to_le16(IEEE80211_RADIOTAP_VENDOR_NAMESPACE); 1558f79cbc77SKalle Valo 1559f79cbc77SKalle Valo rtap->content.oui[0] = HWSIM_RADIOTAP_OUI[0]; 1560f79cbc77SKalle Valo rtap->content.oui[1] = HWSIM_RADIOTAP_OUI[1]; 1561f79cbc77SKalle Valo rtap->content.oui[2] = HWSIM_RADIOTAP_OUI[2]; 1562f79cbc77SKalle Valo rtap->content.oui_subtype = 127; 1563f79cbc77SKalle Valo /* clear reserved field */ 1564f79cbc77SKalle Valo rtap->content.reserved = 0; 1565f79cbc77SKalle Valo rtap->content.vendor_type = 0; 1566f79cbc77SKalle Valo memcpy(rtap->content.data, vendor_data, sizeof(vendor_data)); 1567f79cbc77SKalle Valo 1568f79cbc77SKalle Valo IEEE80211_SKB_RXCB(skb)->flag |= RX_FLAG_RADIOTAP_TLV_AT_END; 1569f79cbc77SKalle Valo #endif 1570f79cbc77SKalle Valo } 1571f79cbc77SKalle Valo 1572f79cbc77SKalle Valo static void mac80211_hwsim_rx(struct mac80211_hwsim_data *data, 1573f79cbc77SKalle Valo struct ieee80211_rx_status *rx_status, 1574f79cbc77SKalle Valo struct sk_buff *skb) 1575f79cbc77SKalle Valo { 1576f79cbc77SKalle Valo struct ieee80211_hdr *hdr = (void *)skb->data; 1577f79cbc77SKalle Valo 1578f79cbc77SKalle Valo if (!ieee80211_has_morefrags(hdr->frame_control) && 1579f79cbc77SKalle Valo !is_multicast_ether_addr(hdr->addr1) && 1580f79cbc77SKalle Valo (ieee80211_is_mgmt(hdr->frame_control) || 1581f79cbc77SKalle Valo ieee80211_is_data(hdr->frame_control))) { 1582f79cbc77SKalle Valo struct ieee80211_sta *sta; 1583f79cbc77SKalle Valo unsigned int link_id; 1584f79cbc77SKalle Valo 1585f79cbc77SKalle Valo rcu_read_lock(); 1586f79cbc77SKalle Valo sta = ieee80211_find_sta_by_link_addrs(data->hw, hdr->addr2, 1587f79cbc77SKalle Valo hdr->addr1, &link_id); 1588f79cbc77SKalle Valo if (sta) { 1589f79cbc77SKalle Valo struct hwsim_sta_priv *sp = (void *)sta->drv_priv; 1590f79cbc77SKalle Valo 1591f79cbc77SKalle Valo if (ieee80211_has_pm(hdr->frame_control)) 1592f79cbc77SKalle Valo sp->active_links_rx &= ~BIT(link_id); 1593f79cbc77SKalle Valo else 1594f79cbc77SKalle Valo sp->active_links_rx |= BIT(link_id); 1595f79cbc77SKalle Valo } 1596f79cbc77SKalle Valo rcu_read_unlock(); 1597f79cbc77SKalle Valo } 1598f79cbc77SKalle Valo 1599f79cbc77SKalle Valo memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status)); 1600f79cbc77SKalle Valo 1601f79cbc77SKalle Valo mac80211_hwsim_add_vendor_rtap(skb); 1602f79cbc77SKalle Valo 1603f79cbc77SKalle Valo data->rx_pkts++; 1604f79cbc77SKalle Valo data->rx_bytes += skb->len; 1605f79cbc77SKalle Valo ieee80211_rx_irqsafe(data->hw, skb); 1606f79cbc77SKalle Valo } 1607f79cbc77SKalle Valo 1608f79cbc77SKalle Valo static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, 1609f79cbc77SKalle Valo struct sk_buff *skb, 1610f79cbc77SKalle Valo struct ieee80211_channel *chan) 1611f79cbc77SKalle Valo { 1612f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv, *data2; 1613f79cbc77SKalle Valo bool ack = false; 1614f79cbc77SKalle Valo struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 1615f79cbc77SKalle Valo struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 1616f79cbc77SKalle Valo struct ieee80211_rx_status rx_status; 1617f79cbc77SKalle Valo u64 now; 1618f79cbc77SKalle Valo 1619f79cbc77SKalle Valo memset(&rx_status, 0, sizeof(rx_status)); 1620f79cbc77SKalle Valo rx_status.flag |= RX_FLAG_MACTIME_START; 1621f79cbc77SKalle Valo rx_status.freq = chan->center_freq; 1622f79cbc77SKalle Valo rx_status.freq_offset = chan->freq_offset ? 1 : 0; 1623f79cbc77SKalle Valo rx_status.band = chan->band; 1624f79cbc77SKalle Valo if (info->control.rates[0].flags & IEEE80211_TX_RC_VHT_MCS) { 1625f79cbc77SKalle Valo rx_status.rate_idx = 1626f79cbc77SKalle Valo ieee80211_rate_get_vht_mcs(&info->control.rates[0]); 1627f79cbc77SKalle Valo rx_status.nss = 1628f79cbc77SKalle Valo ieee80211_rate_get_vht_nss(&info->control.rates[0]); 1629f79cbc77SKalle Valo rx_status.encoding = RX_ENC_VHT; 1630f79cbc77SKalle Valo } else { 1631f79cbc77SKalle Valo rx_status.rate_idx = info->control.rates[0].idx; 1632f79cbc77SKalle Valo if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS) 1633f79cbc77SKalle Valo rx_status.encoding = RX_ENC_HT; 1634f79cbc77SKalle Valo } 1635f79cbc77SKalle Valo if (info->control.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) 1636f79cbc77SKalle Valo rx_status.bw = RATE_INFO_BW_40; 1637f79cbc77SKalle Valo else if (info->control.rates[0].flags & IEEE80211_TX_RC_80_MHZ_WIDTH) 1638f79cbc77SKalle Valo rx_status.bw = RATE_INFO_BW_80; 1639f79cbc77SKalle Valo else if (info->control.rates[0].flags & IEEE80211_TX_RC_160_MHZ_WIDTH) 1640f79cbc77SKalle Valo rx_status.bw = RATE_INFO_BW_160; 1641f79cbc77SKalle Valo else 1642f79cbc77SKalle Valo rx_status.bw = RATE_INFO_BW_20; 1643f79cbc77SKalle Valo if (info->control.rates[0].flags & IEEE80211_TX_RC_SHORT_GI) 1644f79cbc77SKalle Valo rx_status.enc_flags |= RX_ENC_FLAG_SHORT_GI; 1645f79cbc77SKalle Valo /* TODO: simulate optional packet loss */ 1646f79cbc77SKalle Valo rx_status.signal = data->rx_rssi; 1647f79cbc77SKalle Valo if (info->control.vif) 1648f79cbc77SKalle Valo rx_status.signal += info->control.vif->bss_conf.txpower; 1649f79cbc77SKalle Valo 1650f79cbc77SKalle Valo if (data->ps != PS_DISABLED) 1651f79cbc77SKalle Valo hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); 1652f79cbc77SKalle Valo 1653f79cbc77SKalle Valo /* release the skb's source info */ 1654f79cbc77SKalle Valo skb_orphan(skb); 1655f79cbc77SKalle Valo skb_dst_drop(skb); 1656f79cbc77SKalle Valo skb->mark = 0; 1657f79cbc77SKalle Valo skb_ext_reset(skb); 1658f79cbc77SKalle Valo nf_reset_ct(skb); 1659f79cbc77SKalle Valo 1660f79cbc77SKalle Valo /* 1661f79cbc77SKalle Valo * Get absolute mactime here so all HWs RX at the "same time", and 1662f79cbc77SKalle Valo * absolute TX time for beacon mactime so the timestamp matches. 1663f79cbc77SKalle Valo * Giving beacons a different mactime than non-beacons looks messy, but 1664f79cbc77SKalle Valo * it helps the Toffset be exact and a ~10us mactime discrepancy 1665f79cbc77SKalle Valo * probably doesn't really matter. 1666f79cbc77SKalle Valo */ 1667f79cbc77SKalle Valo if (ieee80211_is_beacon(hdr->frame_control) || 1668f79cbc77SKalle Valo ieee80211_is_probe_resp(hdr->frame_control)) { 1669f79cbc77SKalle Valo rx_status.boottime_ns = ktime_get_boottime_ns(); 1670f79cbc77SKalle Valo now = data->abs_bcn_ts; 1671f79cbc77SKalle Valo } else { 1672f79cbc77SKalle Valo now = mac80211_hwsim_get_tsf_raw(); 1673f79cbc77SKalle Valo } 1674f79cbc77SKalle Valo 1675f79cbc77SKalle Valo /* Copy skb to all enabled radios that are on the current frequency */ 1676f79cbc77SKalle Valo spin_lock(&hwsim_radio_lock); 1677f79cbc77SKalle Valo list_for_each_entry(data2, &hwsim_radios, list) { 1678f79cbc77SKalle Valo struct sk_buff *nskb; 1679f79cbc77SKalle Valo struct tx_iter_data tx_iter_data = { 1680f79cbc77SKalle Valo .receive = false, 1681f79cbc77SKalle Valo .channel = chan, 1682f79cbc77SKalle Valo }; 1683f79cbc77SKalle Valo 1684f79cbc77SKalle Valo if (data == data2) 1685f79cbc77SKalle Valo continue; 1686f79cbc77SKalle Valo 1687f79cbc77SKalle Valo if (!data2->started || (data2->idle && !data2->tmp_chan) || 1688f79cbc77SKalle Valo !hwsim_ps_rx_ok(data2, skb)) 1689f79cbc77SKalle Valo continue; 1690f79cbc77SKalle Valo 1691f79cbc77SKalle Valo if (!(data->group & data2->group)) 1692f79cbc77SKalle Valo continue; 1693f79cbc77SKalle Valo 1694f79cbc77SKalle Valo if (data->netgroup != data2->netgroup) 1695f79cbc77SKalle Valo continue; 1696f79cbc77SKalle Valo 1697f79cbc77SKalle Valo if (!hwsim_chans_compat(chan, data2->tmp_chan) && 1698f79cbc77SKalle Valo !hwsim_chans_compat(chan, data2->channel)) { 1699f79cbc77SKalle Valo ieee80211_iterate_active_interfaces_atomic( 1700f79cbc77SKalle Valo data2->hw, IEEE80211_IFACE_ITER_NORMAL, 1701f79cbc77SKalle Valo mac80211_hwsim_tx_iter, &tx_iter_data); 1702f79cbc77SKalle Valo if (!tx_iter_data.receive) 1703f79cbc77SKalle Valo continue; 1704f79cbc77SKalle Valo } 1705f79cbc77SKalle Valo 1706f79cbc77SKalle Valo /* 1707f79cbc77SKalle Valo * reserve some space for our vendor and the normal 1708f79cbc77SKalle Valo * radiotap header, since we're copying anyway 1709f79cbc77SKalle Valo */ 1710f79cbc77SKalle Valo if (skb->len < PAGE_SIZE && paged_rx) { 1711f79cbc77SKalle Valo struct page *page = alloc_page(GFP_ATOMIC); 1712f79cbc77SKalle Valo 1713f79cbc77SKalle Valo if (!page) 1714f79cbc77SKalle Valo continue; 1715f79cbc77SKalle Valo 1716f79cbc77SKalle Valo nskb = dev_alloc_skb(128); 1717f79cbc77SKalle Valo if (!nskb) { 1718f79cbc77SKalle Valo __free_page(page); 1719f79cbc77SKalle Valo continue; 1720f79cbc77SKalle Valo } 1721f79cbc77SKalle Valo 1722f79cbc77SKalle Valo memcpy(page_address(page), skb->data, skb->len); 1723f79cbc77SKalle Valo skb_add_rx_frag(nskb, 0, page, 0, skb->len, skb->len); 1724f79cbc77SKalle Valo } else { 1725f79cbc77SKalle Valo nskb = skb_copy(skb, GFP_ATOMIC); 1726f79cbc77SKalle Valo if (!nskb) 1727f79cbc77SKalle Valo continue; 1728f79cbc77SKalle Valo } 1729f79cbc77SKalle Valo 1730f79cbc77SKalle Valo if (mac80211_hwsim_addr_match(data2, hdr->addr1)) 1731f79cbc77SKalle Valo ack = true; 1732f79cbc77SKalle Valo 1733f79cbc77SKalle Valo rx_status.mactime = now + data2->tsf_offset; 1734f79cbc77SKalle Valo 1735f79cbc77SKalle Valo mac80211_hwsim_rx(data2, &rx_status, nskb); 1736f79cbc77SKalle Valo } 1737f79cbc77SKalle Valo spin_unlock(&hwsim_radio_lock); 1738f79cbc77SKalle Valo 1739f79cbc77SKalle Valo return ack; 1740f79cbc77SKalle Valo } 1741f79cbc77SKalle Valo 1742f79cbc77SKalle Valo static struct ieee80211_bss_conf * 1743f79cbc77SKalle Valo mac80211_hwsim_select_tx_link(struct mac80211_hwsim_data *data, 1744f79cbc77SKalle Valo struct ieee80211_vif *vif, 1745f79cbc77SKalle Valo struct ieee80211_sta *sta, 1746f79cbc77SKalle Valo struct ieee80211_hdr *hdr, 1747f79cbc77SKalle Valo struct ieee80211_link_sta **link_sta) 1748f79cbc77SKalle Valo { 1749f79cbc77SKalle Valo struct hwsim_sta_priv *sp = (void *)sta->drv_priv; 1750f79cbc77SKalle Valo int i; 1751f79cbc77SKalle Valo 1752f79cbc77SKalle Valo if (!vif->valid_links) 1753f79cbc77SKalle Valo return &vif->bss_conf; 1754f79cbc77SKalle Valo 1755f79cbc77SKalle Valo WARN_ON(is_multicast_ether_addr(hdr->addr1)); 1756f79cbc77SKalle Valo 1757f79cbc77SKalle Valo if (WARN_ON_ONCE(!sta->valid_links)) 1758f79cbc77SKalle Valo return &vif->bss_conf; 1759f79cbc77SKalle Valo 1760f79cbc77SKalle Valo for (i = 0; i < ARRAY_SIZE(vif->link_conf); i++) { 1761f79cbc77SKalle Valo struct ieee80211_bss_conf *bss_conf; 1762f79cbc77SKalle Valo unsigned int link_id; 1763f79cbc77SKalle Valo 1764f79cbc77SKalle Valo /* round-robin the available link IDs */ 1765f79cbc77SKalle Valo link_id = (sp->last_link + i + 1) % ARRAY_SIZE(vif->link_conf); 1766f79cbc77SKalle Valo 1767f79cbc77SKalle Valo if (!(vif->active_links & BIT(link_id))) 1768f79cbc77SKalle Valo continue; 1769f79cbc77SKalle Valo 1770f79cbc77SKalle Valo if (!(sp->active_links_rx & BIT(link_id))) 1771f79cbc77SKalle Valo continue; 1772f79cbc77SKalle Valo 1773f79cbc77SKalle Valo *link_sta = rcu_dereference(sta->link[link_id]); 1774f79cbc77SKalle Valo if (!*link_sta) 1775f79cbc77SKalle Valo continue; 1776f79cbc77SKalle Valo 1777f79cbc77SKalle Valo bss_conf = rcu_dereference(vif->link_conf[link_id]); 1778f79cbc77SKalle Valo if (WARN_ON_ONCE(!bss_conf)) 1779f79cbc77SKalle Valo continue; 1780f79cbc77SKalle Valo 1781f79cbc77SKalle Valo /* can happen while switching links */ 1782f79cbc77SKalle Valo if (!rcu_access_pointer(bss_conf->chanctx_conf)) 1783f79cbc77SKalle Valo continue; 1784f79cbc77SKalle Valo 1785f79cbc77SKalle Valo sp->last_link = link_id; 1786f79cbc77SKalle Valo return bss_conf; 1787f79cbc77SKalle Valo } 1788f79cbc77SKalle Valo 1789f79cbc77SKalle Valo return NULL; 1790f79cbc77SKalle Valo } 1791f79cbc77SKalle Valo 1792f79cbc77SKalle Valo static void mac80211_hwsim_tx(struct ieee80211_hw *hw, 1793f79cbc77SKalle Valo struct ieee80211_tx_control *control, 1794f79cbc77SKalle Valo struct sk_buff *skb) 1795f79cbc77SKalle Valo { 1796f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 1797f79cbc77SKalle Valo struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb); 1798f79cbc77SKalle Valo struct ieee80211_hdr *hdr = (void *)skb->data; 1799f79cbc77SKalle Valo struct ieee80211_chanctx_conf *chanctx_conf; 1800f79cbc77SKalle Valo struct ieee80211_channel *channel; 1801f79cbc77SKalle Valo bool ack; 1802f79cbc77SKalle Valo enum nl80211_chan_width confbw = NL80211_CHAN_WIDTH_20_NOHT; 1803f79cbc77SKalle Valo u32 _portid, i; 1804f79cbc77SKalle Valo 1805f79cbc77SKalle Valo if (WARN_ON(skb->len < 10)) { 1806f79cbc77SKalle Valo /* Should not happen; just a sanity check for addr1 use */ 1807f79cbc77SKalle Valo ieee80211_free_txskb(hw, skb); 1808f79cbc77SKalle Valo return; 1809f79cbc77SKalle Valo } 1810f79cbc77SKalle Valo 1811f79cbc77SKalle Valo if (!data->use_chanctx) { 1812f79cbc77SKalle Valo channel = data->channel; 1813f79cbc77SKalle Valo confbw = data->bw; 1814f79cbc77SKalle Valo } else if (txi->hw_queue == 4) { 1815f79cbc77SKalle Valo channel = data->tmp_chan; 1816f79cbc77SKalle Valo } else { 1817f79cbc77SKalle Valo u8 link = u32_get_bits(IEEE80211_SKB_CB(skb)->control.flags, 1818f79cbc77SKalle Valo IEEE80211_TX_CTRL_MLO_LINK); 1819f79cbc77SKalle Valo struct ieee80211_vif *vif = txi->control.vif; 1820f79cbc77SKalle Valo struct ieee80211_link_sta *link_sta = NULL; 1821f79cbc77SKalle Valo struct ieee80211_sta *sta = control->sta; 1822f79cbc77SKalle Valo struct ieee80211_bss_conf *bss_conf; 1823f79cbc77SKalle Valo 1824f79cbc77SKalle Valo if (link != IEEE80211_LINK_UNSPECIFIED) { 1825f79cbc77SKalle Valo bss_conf = rcu_dereference(txi->control.vif->link_conf[link]); 1826f79cbc77SKalle Valo if (sta) 1827f79cbc77SKalle Valo link_sta = rcu_dereference(sta->link[link]); 1828f79cbc77SKalle Valo } else { 1829f79cbc77SKalle Valo bss_conf = mac80211_hwsim_select_tx_link(data, vif, sta, 1830f79cbc77SKalle Valo hdr, &link_sta); 1831f79cbc77SKalle Valo } 1832f79cbc77SKalle Valo 1833f79cbc77SKalle Valo if (WARN_ON(!bss_conf)) { 1834f79cbc77SKalle Valo ieee80211_free_txskb(hw, skb); 1835f79cbc77SKalle Valo return; 1836f79cbc77SKalle Valo } 1837f79cbc77SKalle Valo 1838f79cbc77SKalle Valo if (sta && sta->mlo) { 1839f79cbc77SKalle Valo if (WARN_ON(!link_sta)) { 1840f79cbc77SKalle Valo ieee80211_free_txskb(hw, skb); 1841f79cbc77SKalle Valo return; 1842f79cbc77SKalle Valo } 1843f79cbc77SKalle Valo /* address translation to link addresses on TX */ 1844f79cbc77SKalle Valo ether_addr_copy(hdr->addr1, link_sta->addr); 1845f79cbc77SKalle Valo ether_addr_copy(hdr->addr2, bss_conf->addr); 1846f79cbc77SKalle Valo /* translate A3 only if it's the BSSID */ 1847f79cbc77SKalle Valo if (!ieee80211_has_tods(hdr->frame_control) && 1848f79cbc77SKalle Valo !ieee80211_has_fromds(hdr->frame_control)) { 1849f79cbc77SKalle Valo if (ether_addr_equal(hdr->addr3, sta->addr)) 1850f79cbc77SKalle Valo ether_addr_copy(hdr->addr3, link_sta->addr); 1851f79cbc77SKalle Valo else if (ether_addr_equal(hdr->addr3, vif->addr)) 1852f79cbc77SKalle Valo ether_addr_copy(hdr->addr3, bss_conf->addr); 1853f79cbc77SKalle Valo } 1854f79cbc77SKalle Valo /* no need to look at A4, if present it's SA */ 1855f79cbc77SKalle Valo } 1856f79cbc77SKalle Valo 1857f79cbc77SKalle Valo chanctx_conf = rcu_dereference(bss_conf->chanctx_conf); 1858f79cbc77SKalle Valo if (chanctx_conf) { 1859f79cbc77SKalle Valo channel = chanctx_conf->def.chan; 1860f79cbc77SKalle Valo confbw = chanctx_conf->def.width; 1861f79cbc77SKalle Valo } else { 1862f79cbc77SKalle Valo channel = NULL; 1863f79cbc77SKalle Valo } 1864f79cbc77SKalle Valo } 1865f79cbc77SKalle Valo 1866f79cbc77SKalle Valo if (WARN(!channel, "TX w/o channel - queue = %d\n", txi->hw_queue)) { 1867f79cbc77SKalle Valo ieee80211_free_txskb(hw, skb); 1868f79cbc77SKalle Valo return; 1869f79cbc77SKalle Valo } 1870f79cbc77SKalle Valo 1871f79cbc77SKalle Valo if (data->idle && !data->tmp_chan) { 1872f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "Trying to TX when idle - reject\n"); 1873f79cbc77SKalle Valo ieee80211_free_txskb(hw, skb); 1874f79cbc77SKalle Valo return; 1875f79cbc77SKalle Valo } 1876f79cbc77SKalle Valo 1877f79cbc77SKalle Valo if (txi->control.vif) 1878f79cbc77SKalle Valo hwsim_check_magic(txi->control.vif); 1879f79cbc77SKalle Valo if (control->sta) 1880f79cbc77SKalle Valo hwsim_check_sta_magic(control->sta); 1881f79cbc77SKalle Valo 1882f79cbc77SKalle Valo if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE)) 1883f79cbc77SKalle Valo ieee80211_get_tx_rates(txi->control.vif, control->sta, skb, 1884f79cbc77SKalle Valo txi->control.rates, 1885f79cbc77SKalle Valo ARRAY_SIZE(txi->control.rates)); 1886f79cbc77SKalle Valo 1887f79cbc77SKalle Valo for (i = 0; i < ARRAY_SIZE(txi->control.rates); i++) { 1888f79cbc77SKalle Valo u16 rflags = txi->control.rates[i].flags; 1889f79cbc77SKalle Valo /* initialize to data->bw for 5/10 MHz handling */ 1890f79cbc77SKalle Valo enum nl80211_chan_width bw = data->bw; 1891f79cbc77SKalle Valo 1892f79cbc77SKalle Valo if (txi->control.rates[i].idx == -1) 1893f79cbc77SKalle Valo break; 1894f79cbc77SKalle Valo 1895f79cbc77SKalle Valo if (rflags & IEEE80211_TX_RC_40_MHZ_WIDTH) 1896f79cbc77SKalle Valo bw = NL80211_CHAN_WIDTH_40; 1897f79cbc77SKalle Valo else if (rflags & IEEE80211_TX_RC_80_MHZ_WIDTH) 1898f79cbc77SKalle Valo bw = NL80211_CHAN_WIDTH_80; 1899f79cbc77SKalle Valo else if (rflags & IEEE80211_TX_RC_160_MHZ_WIDTH) 1900f79cbc77SKalle Valo bw = NL80211_CHAN_WIDTH_160; 1901f79cbc77SKalle Valo 1902f79cbc77SKalle Valo if (WARN_ON(hwsim_get_chanwidth(bw) > hwsim_get_chanwidth(confbw))) 1903f79cbc77SKalle Valo return; 1904f79cbc77SKalle Valo } 1905f79cbc77SKalle Valo 1906f79cbc77SKalle Valo if (skb->len >= 24 + 8 && 1907f79cbc77SKalle Valo ieee80211_is_probe_resp(hdr->frame_control)) { 1908f79cbc77SKalle Valo /* fake header transmission time */ 1909f79cbc77SKalle Valo struct ieee80211_mgmt *mgmt; 1910f79cbc77SKalle Valo struct ieee80211_rate *txrate; 1911f79cbc77SKalle Valo /* TODO: get MCS */ 1912f79cbc77SKalle Valo int bitrate = 100; 1913f79cbc77SKalle Valo u64 ts; 1914f79cbc77SKalle Valo 1915f79cbc77SKalle Valo mgmt = (struct ieee80211_mgmt *)skb->data; 1916f79cbc77SKalle Valo txrate = ieee80211_get_tx_rate(hw, txi); 1917f79cbc77SKalle Valo if (txrate) 1918f79cbc77SKalle Valo bitrate = txrate->bitrate; 1919f79cbc77SKalle Valo ts = mac80211_hwsim_get_tsf_raw(); 1920f79cbc77SKalle Valo mgmt->u.probe_resp.timestamp = 1921f79cbc77SKalle Valo cpu_to_le64(ts + data->tsf_offset + 1922f79cbc77SKalle Valo 24 * 8 * 10 / bitrate); 1923f79cbc77SKalle Valo } 1924f79cbc77SKalle Valo 1925f79cbc77SKalle Valo mac80211_hwsim_monitor_rx(hw, skb, channel); 1926f79cbc77SKalle Valo 1927f79cbc77SKalle Valo /* wmediumd mode check */ 1928f79cbc77SKalle Valo _portid = READ_ONCE(data->wmediumd); 1929f79cbc77SKalle Valo 1930f79cbc77SKalle Valo if (_portid || hwsim_virtio_enabled) 1931f79cbc77SKalle Valo return mac80211_hwsim_tx_frame_nl(hw, skb, _portid, channel); 1932f79cbc77SKalle Valo 1933f79cbc77SKalle Valo /* NO wmediumd detected, perfect medium simulation */ 1934f79cbc77SKalle Valo data->tx_pkts++; 1935f79cbc77SKalle Valo data->tx_bytes += skb->len; 1936f79cbc77SKalle Valo ack = mac80211_hwsim_tx_frame_no_nl(hw, skb, channel); 1937f79cbc77SKalle Valo 1938f79cbc77SKalle Valo if (ack && skb->len >= 16) 1939f79cbc77SKalle Valo mac80211_hwsim_monitor_ack(channel, hdr->addr2); 1940f79cbc77SKalle Valo 1941f79cbc77SKalle Valo ieee80211_tx_info_clear_status(txi); 1942f79cbc77SKalle Valo 1943f79cbc77SKalle Valo /* frame was transmitted at most favorable rate at first attempt */ 1944f79cbc77SKalle Valo txi->control.rates[0].count = 1; 1945f79cbc77SKalle Valo txi->control.rates[1].idx = -1; 1946f79cbc77SKalle Valo 1947f79cbc77SKalle Valo if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) && ack) 1948f79cbc77SKalle Valo txi->flags |= IEEE80211_TX_STAT_ACK; 1949f79cbc77SKalle Valo ieee80211_tx_status_irqsafe(hw, skb); 1950f79cbc77SKalle Valo } 1951f79cbc77SKalle Valo 1952f79cbc77SKalle Valo 1953f79cbc77SKalle Valo static int mac80211_hwsim_start(struct ieee80211_hw *hw) 1954f79cbc77SKalle Valo { 1955f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 1956f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "%s\n", __func__); 1957f79cbc77SKalle Valo data->started = true; 1958f79cbc77SKalle Valo return 0; 1959f79cbc77SKalle Valo } 1960f79cbc77SKalle Valo 1961f79cbc77SKalle Valo 1962f79cbc77SKalle Valo static void mac80211_hwsim_stop(struct ieee80211_hw *hw) 1963f79cbc77SKalle Valo { 1964f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 1965f79cbc77SKalle Valo int i; 1966f79cbc77SKalle Valo 1967f79cbc77SKalle Valo data->started = false; 1968f79cbc77SKalle Valo 1969f79cbc77SKalle Valo for (i = 0; i < ARRAY_SIZE(data->link_data); i++) 1970f79cbc77SKalle Valo hrtimer_cancel(&data->link_data[i].beacon_timer); 1971f79cbc77SKalle Valo 1972f79cbc77SKalle Valo while (!skb_queue_empty(&data->pending)) 1973f79cbc77SKalle Valo ieee80211_free_txskb(hw, skb_dequeue(&data->pending)); 1974f79cbc77SKalle Valo 1975f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "%s\n", __func__); 1976f79cbc77SKalle Valo } 1977f79cbc77SKalle Valo 1978f79cbc77SKalle Valo 1979f79cbc77SKalle Valo static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw, 1980f79cbc77SKalle Valo struct ieee80211_vif *vif) 1981f79cbc77SKalle Valo { 1982f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "%s (type=%d mac_addr=%pM)\n", 1983f79cbc77SKalle Valo __func__, ieee80211_vif_type_p2p(vif), 1984f79cbc77SKalle Valo vif->addr); 1985f79cbc77SKalle Valo hwsim_set_magic(vif); 1986f79cbc77SKalle Valo 1987f79cbc77SKalle Valo if (vif->type != NL80211_IFTYPE_MONITOR) 1988f79cbc77SKalle Valo mac80211_hwsim_config_mac_nl(hw, vif->addr, true); 1989f79cbc77SKalle Valo 1990f79cbc77SKalle Valo vif->cab_queue = 0; 1991f79cbc77SKalle Valo vif->hw_queue[IEEE80211_AC_VO] = 0; 1992f79cbc77SKalle Valo vif->hw_queue[IEEE80211_AC_VI] = 1; 1993f79cbc77SKalle Valo vif->hw_queue[IEEE80211_AC_BE] = 2; 1994f79cbc77SKalle Valo vif->hw_queue[IEEE80211_AC_BK] = 3; 1995f79cbc77SKalle Valo 1996f79cbc77SKalle Valo return 0; 1997f79cbc77SKalle Valo } 1998f79cbc77SKalle Valo 1999f79cbc77SKalle Valo 2000f79cbc77SKalle Valo static int mac80211_hwsim_change_interface(struct ieee80211_hw *hw, 2001f79cbc77SKalle Valo struct ieee80211_vif *vif, 2002f79cbc77SKalle Valo enum nl80211_iftype newtype, 2003f79cbc77SKalle Valo bool newp2p) 2004f79cbc77SKalle Valo { 2005f79cbc77SKalle Valo newtype = ieee80211_iftype_p2p(newtype, newp2p); 2006f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, 2007f79cbc77SKalle Valo "%s (old type=%d, new type=%d, mac_addr=%pM)\n", 2008f79cbc77SKalle Valo __func__, ieee80211_vif_type_p2p(vif), 2009f79cbc77SKalle Valo newtype, vif->addr); 2010f79cbc77SKalle Valo hwsim_check_magic(vif); 2011f79cbc77SKalle Valo 2012f79cbc77SKalle Valo /* 2013f79cbc77SKalle Valo * interface may change from non-AP to AP in 2014f79cbc77SKalle Valo * which case this needs to be set up again 2015f79cbc77SKalle Valo */ 2016f79cbc77SKalle Valo vif->cab_queue = 0; 2017f79cbc77SKalle Valo 2018f79cbc77SKalle Valo return 0; 2019f79cbc77SKalle Valo } 2020f79cbc77SKalle Valo 2021f79cbc77SKalle Valo static void mac80211_hwsim_remove_interface( 2022f79cbc77SKalle Valo struct ieee80211_hw *hw, struct ieee80211_vif *vif) 2023f79cbc77SKalle Valo { 2024f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "%s (type=%d mac_addr=%pM)\n", 2025f79cbc77SKalle Valo __func__, ieee80211_vif_type_p2p(vif), 2026f79cbc77SKalle Valo vif->addr); 2027f79cbc77SKalle Valo hwsim_check_magic(vif); 2028f79cbc77SKalle Valo hwsim_clear_magic(vif); 2029f79cbc77SKalle Valo if (vif->type != NL80211_IFTYPE_MONITOR) 2030f79cbc77SKalle Valo mac80211_hwsim_config_mac_nl(hw, vif->addr, false); 2031f79cbc77SKalle Valo } 2032f79cbc77SKalle Valo 2033f79cbc77SKalle Valo static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, 2034f79cbc77SKalle Valo struct sk_buff *skb, 2035f79cbc77SKalle Valo struct ieee80211_channel *chan) 2036f79cbc77SKalle Valo { 2037f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 2038f79cbc77SKalle Valo u32 _portid = READ_ONCE(data->wmediumd); 2039f79cbc77SKalle Valo 2040f79cbc77SKalle Valo if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE)) { 2041f79cbc77SKalle Valo struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb); 2042f79cbc77SKalle Valo ieee80211_get_tx_rates(txi->control.vif, NULL, skb, 2043f79cbc77SKalle Valo txi->control.rates, 2044f79cbc77SKalle Valo ARRAY_SIZE(txi->control.rates)); 2045f79cbc77SKalle Valo } 2046f79cbc77SKalle Valo 2047f79cbc77SKalle Valo mac80211_hwsim_monitor_rx(hw, skb, chan); 2048f79cbc77SKalle Valo 2049f79cbc77SKalle Valo if (_portid || hwsim_virtio_enabled) 2050f79cbc77SKalle Valo return mac80211_hwsim_tx_frame_nl(hw, skb, _portid, chan); 2051f79cbc77SKalle Valo 2052f79cbc77SKalle Valo data->tx_pkts++; 2053f79cbc77SKalle Valo data->tx_bytes += skb->len; 2054f79cbc77SKalle Valo mac80211_hwsim_tx_frame_no_nl(hw, skb, chan); 2055f79cbc77SKalle Valo dev_kfree_skb(skb); 2056f79cbc77SKalle Valo } 2057f79cbc77SKalle Valo 2058*b3a912e3SAloka Dixit static void __mac80211_hwsim_beacon_tx(struct ieee80211_bss_conf *link_conf, 2059*b3a912e3SAloka Dixit struct mac80211_hwsim_data *data, 2060*b3a912e3SAloka Dixit struct ieee80211_hw *hw, 2061*b3a912e3SAloka Dixit struct ieee80211_vif *vif, 2062*b3a912e3SAloka Dixit struct sk_buff *skb) 2063f79cbc77SKalle Valo { 2064f79cbc77SKalle Valo struct ieee80211_tx_info *info; 2065f79cbc77SKalle Valo struct ieee80211_rate *txrate; 2066f79cbc77SKalle Valo struct ieee80211_mgmt *mgmt; 2067f79cbc77SKalle Valo /* TODO: get MCS */ 2068f79cbc77SKalle Valo int bitrate = 100; 2069f79cbc77SKalle Valo 2070f79cbc77SKalle Valo info = IEEE80211_SKB_CB(skb); 2071f79cbc77SKalle Valo if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE)) 2072f79cbc77SKalle Valo ieee80211_get_tx_rates(vif, NULL, skb, 2073f79cbc77SKalle Valo info->control.rates, 2074f79cbc77SKalle Valo ARRAY_SIZE(info->control.rates)); 2075f79cbc77SKalle Valo 2076f79cbc77SKalle Valo txrate = ieee80211_get_tx_rate(hw, info); 2077f79cbc77SKalle Valo if (txrate) 2078f79cbc77SKalle Valo bitrate = txrate->bitrate; 2079f79cbc77SKalle Valo 2080f79cbc77SKalle Valo mgmt = (struct ieee80211_mgmt *) skb->data; 2081f79cbc77SKalle Valo /* fake header transmission time */ 2082f79cbc77SKalle Valo data->abs_bcn_ts = mac80211_hwsim_get_tsf_raw(); 2083f79cbc77SKalle Valo if (ieee80211_is_s1g_beacon(mgmt->frame_control)) { 2084f79cbc77SKalle Valo struct ieee80211_ext *ext = (void *) mgmt; 2085f79cbc77SKalle Valo 2086f79cbc77SKalle Valo ext->u.s1g_beacon.timestamp = cpu_to_le32(data->abs_bcn_ts + 2087f79cbc77SKalle Valo data->tsf_offset + 2088f79cbc77SKalle Valo 10 * 8 * 10 / 2089f79cbc77SKalle Valo bitrate); 2090f79cbc77SKalle Valo } else { 2091f79cbc77SKalle Valo mgmt->u.beacon.timestamp = cpu_to_le64(data->abs_bcn_ts + 2092f79cbc77SKalle Valo data->tsf_offset + 2093f79cbc77SKalle Valo 24 * 8 * 10 / 2094f79cbc77SKalle Valo bitrate); 2095f79cbc77SKalle Valo } 2096f79cbc77SKalle Valo 2097f79cbc77SKalle Valo mac80211_hwsim_tx_frame(hw, skb, 2098f79cbc77SKalle Valo rcu_dereference(link_conf->chanctx_conf)->def.chan); 2099*b3a912e3SAloka Dixit } 2100*b3a912e3SAloka Dixit 2101*b3a912e3SAloka Dixit static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, 2102*b3a912e3SAloka Dixit struct ieee80211_vif *vif) 2103*b3a912e3SAloka Dixit { 2104*b3a912e3SAloka Dixit struct mac80211_hwsim_link_data *link_data = arg; 2105*b3a912e3SAloka Dixit u32 link_id = link_data->link_id; 2106*b3a912e3SAloka Dixit struct ieee80211_bss_conf *link_conf; 2107*b3a912e3SAloka Dixit struct mac80211_hwsim_data *data = 2108*b3a912e3SAloka Dixit container_of(link_data, struct mac80211_hwsim_data, 2109*b3a912e3SAloka Dixit link_data[link_id]); 2110*b3a912e3SAloka Dixit struct ieee80211_hw *hw = data->hw; 2111*b3a912e3SAloka Dixit struct sk_buff *skb; 2112*b3a912e3SAloka Dixit 2113*b3a912e3SAloka Dixit hwsim_check_magic(vif); 2114*b3a912e3SAloka Dixit 2115*b3a912e3SAloka Dixit link_conf = rcu_dereference(vif->link_conf[link_id]); 2116*b3a912e3SAloka Dixit if (!link_conf) 2117*b3a912e3SAloka Dixit return; 2118*b3a912e3SAloka Dixit 2119*b3a912e3SAloka Dixit if (vif->type != NL80211_IFTYPE_AP && 2120*b3a912e3SAloka Dixit vif->type != NL80211_IFTYPE_MESH_POINT && 2121*b3a912e3SAloka Dixit vif->type != NL80211_IFTYPE_ADHOC && 2122*b3a912e3SAloka Dixit vif->type != NL80211_IFTYPE_OCB) 2123*b3a912e3SAloka Dixit return; 2124*b3a912e3SAloka Dixit 2125*b3a912e3SAloka Dixit skb = ieee80211_beacon_get(hw, vif, link_id); 2126*b3a912e3SAloka Dixit if (!skb) 2127*b3a912e3SAloka Dixit return; 2128*b3a912e3SAloka Dixit 2129*b3a912e3SAloka Dixit __mac80211_hwsim_beacon_tx(link_conf, data, hw, vif, skb); 2130f79cbc77SKalle Valo 2131f79cbc77SKalle Valo while ((skb = ieee80211_get_buffered_bc(hw, vif)) != NULL) { 2132f79cbc77SKalle Valo mac80211_hwsim_tx_frame(hw, skb, 2133f79cbc77SKalle Valo rcu_dereference(link_conf->chanctx_conf)->def.chan); 2134f79cbc77SKalle Valo } 2135f79cbc77SKalle Valo 2136f79cbc77SKalle Valo if (link_conf->csa_active && ieee80211_beacon_cntdwn_is_complete(vif)) 2137f79cbc77SKalle Valo ieee80211_csa_finish(vif); 2138f79cbc77SKalle Valo } 2139f79cbc77SKalle Valo 2140f79cbc77SKalle Valo static enum hrtimer_restart 2141f79cbc77SKalle Valo mac80211_hwsim_beacon(struct hrtimer *timer) 2142f79cbc77SKalle Valo { 2143f79cbc77SKalle Valo struct mac80211_hwsim_link_data *link_data = 2144f79cbc77SKalle Valo container_of(timer, struct mac80211_hwsim_link_data, beacon_timer); 2145f79cbc77SKalle Valo struct mac80211_hwsim_data *data = 2146f79cbc77SKalle Valo container_of(link_data, struct mac80211_hwsim_data, 2147f79cbc77SKalle Valo link_data[link_data->link_id]); 2148f79cbc77SKalle Valo struct ieee80211_hw *hw = data->hw; 2149f79cbc77SKalle Valo u64 bcn_int = link_data->beacon_int; 2150f79cbc77SKalle Valo 2151f79cbc77SKalle Valo if (!data->started) 2152f79cbc77SKalle Valo return HRTIMER_NORESTART; 2153f79cbc77SKalle Valo 2154f79cbc77SKalle Valo ieee80211_iterate_active_interfaces_atomic( 2155f79cbc77SKalle Valo hw, IEEE80211_IFACE_ITER_NORMAL, 2156f79cbc77SKalle Valo mac80211_hwsim_beacon_tx, link_data); 2157f79cbc77SKalle Valo 2158f79cbc77SKalle Valo /* beacon at new TBTT + beacon interval */ 2159f79cbc77SKalle Valo if (data->bcn_delta) { 2160f79cbc77SKalle Valo bcn_int -= data->bcn_delta; 2161f79cbc77SKalle Valo data->bcn_delta = 0; 2162f79cbc77SKalle Valo } 2163f79cbc77SKalle Valo hrtimer_forward_now(&link_data->beacon_timer, 2164f79cbc77SKalle Valo ns_to_ktime(bcn_int * NSEC_PER_USEC)); 2165f79cbc77SKalle Valo return HRTIMER_RESTART; 2166f79cbc77SKalle Valo } 2167f79cbc77SKalle Valo 2168f79cbc77SKalle Valo static const char * const hwsim_chanwidths[] = { 2169f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_5] = "ht5", 2170f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_10] = "ht10", 2171f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_20_NOHT] = "noht", 2172f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_20] = "ht20", 2173f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_40] = "ht40", 2174f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_80] = "vht80", 2175f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_80P80] = "vht80p80", 2176f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_160] = "vht160", 2177f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_1] = "1MHz", 2178f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_2] = "2MHz", 2179f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_4] = "4MHz", 2180f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_8] = "8MHz", 2181f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_16] = "16MHz", 2182f79cbc77SKalle Valo }; 2183f79cbc77SKalle Valo 2184f79cbc77SKalle Valo static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) 2185f79cbc77SKalle Valo { 2186f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 2187f79cbc77SKalle Valo struct ieee80211_conf *conf = &hw->conf; 2188f79cbc77SKalle Valo static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = { 2189f79cbc77SKalle Valo [IEEE80211_SMPS_AUTOMATIC] = "auto", 2190f79cbc77SKalle Valo [IEEE80211_SMPS_OFF] = "off", 2191f79cbc77SKalle Valo [IEEE80211_SMPS_STATIC] = "static", 2192f79cbc77SKalle Valo [IEEE80211_SMPS_DYNAMIC] = "dynamic", 2193f79cbc77SKalle Valo }; 2194f79cbc77SKalle Valo int idx; 2195f79cbc77SKalle Valo 2196f79cbc77SKalle Valo if (conf->chandef.chan) 2197f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, 2198f79cbc77SKalle Valo "%s (freq=%d(%d - %d)/%s idle=%d ps=%d smps=%s)\n", 2199f79cbc77SKalle Valo __func__, 2200f79cbc77SKalle Valo conf->chandef.chan->center_freq, 2201f79cbc77SKalle Valo conf->chandef.center_freq1, 2202f79cbc77SKalle Valo conf->chandef.center_freq2, 2203f79cbc77SKalle Valo hwsim_chanwidths[conf->chandef.width], 2204f79cbc77SKalle Valo !!(conf->flags & IEEE80211_CONF_IDLE), 2205f79cbc77SKalle Valo !!(conf->flags & IEEE80211_CONF_PS), 2206f79cbc77SKalle Valo smps_modes[conf->smps_mode]); 2207f79cbc77SKalle Valo else 2208f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, 2209f79cbc77SKalle Valo "%s (freq=0 idle=%d ps=%d smps=%s)\n", 2210f79cbc77SKalle Valo __func__, 2211f79cbc77SKalle Valo !!(conf->flags & IEEE80211_CONF_IDLE), 2212f79cbc77SKalle Valo !!(conf->flags & IEEE80211_CONF_PS), 2213f79cbc77SKalle Valo smps_modes[conf->smps_mode]); 2214f79cbc77SKalle Valo 2215f79cbc77SKalle Valo data->idle = !!(conf->flags & IEEE80211_CONF_IDLE); 2216f79cbc77SKalle Valo 2217f79cbc77SKalle Valo WARN_ON(conf->chandef.chan && data->use_chanctx); 2218f79cbc77SKalle Valo 2219f79cbc77SKalle Valo mutex_lock(&data->mutex); 2220f79cbc77SKalle Valo if (data->scanning && conf->chandef.chan) { 2221f79cbc77SKalle Valo for (idx = 0; idx < ARRAY_SIZE(data->survey_data); idx++) { 2222f79cbc77SKalle Valo if (data->survey_data[idx].channel == data->channel) { 2223f79cbc77SKalle Valo data->survey_data[idx].start = 2224f79cbc77SKalle Valo data->survey_data[idx].next_start; 2225f79cbc77SKalle Valo data->survey_data[idx].end = jiffies; 2226f79cbc77SKalle Valo break; 2227f79cbc77SKalle Valo } 2228f79cbc77SKalle Valo } 2229f79cbc77SKalle Valo 2230f79cbc77SKalle Valo data->channel = conf->chandef.chan; 2231f79cbc77SKalle Valo data->bw = conf->chandef.width; 2232f79cbc77SKalle Valo 2233f79cbc77SKalle Valo for (idx = 0; idx < ARRAY_SIZE(data->survey_data); idx++) { 2234f79cbc77SKalle Valo if (data->survey_data[idx].channel && 2235f79cbc77SKalle Valo data->survey_data[idx].channel != data->channel) 2236f79cbc77SKalle Valo continue; 2237f79cbc77SKalle Valo data->survey_data[idx].channel = data->channel; 2238f79cbc77SKalle Valo data->survey_data[idx].next_start = jiffies; 2239f79cbc77SKalle Valo break; 2240f79cbc77SKalle Valo } 2241f79cbc77SKalle Valo } else { 2242f79cbc77SKalle Valo data->channel = conf->chandef.chan; 2243f79cbc77SKalle Valo data->bw = conf->chandef.width; 2244f79cbc77SKalle Valo } 2245f79cbc77SKalle Valo mutex_unlock(&data->mutex); 2246f79cbc77SKalle Valo 2247f79cbc77SKalle Valo for (idx = 0; idx < ARRAY_SIZE(data->link_data); idx++) { 2248f79cbc77SKalle Valo struct mac80211_hwsim_link_data *link_data = 2249f79cbc77SKalle Valo &data->link_data[idx]; 2250f79cbc77SKalle Valo 2251f79cbc77SKalle Valo if (!data->started || !link_data->beacon_int) { 2252f79cbc77SKalle Valo hrtimer_cancel(&link_data->beacon_timer); 2253f79cbc77SKalle Valo } else if (!hrtimer_is_queued(&link_data->beacon_timer)) { 2254f79cbc77SKalle Valo u64 tsf = mac80211_hwsim_get_tsf(hw, NULL); 2255f79cbc77SKalle Valo u32 bcn_int = link_data->beacon_int; 2256f79cbc77SKalle Valo u64 until_tbtt = bcn_int - do_div(tsf, bcn_int); 2257f79cbc77SKalle Valo 2258f79cbc77SKalle Valo hrtimer_start(&link_data->beacon_timer, 2259f79cbc77SKalle Valo ns_to_ktime(until_tbtt * NSEC_PER_USEC), 2260f79cbc77SKalle Valo HRTIMER_MODE_REL_SOFT); 2261f79cbc77SKalle Valo } 2262f79cbc77SKalle Valo } 2263f79cbc77SKalle Valo 2264f79cbc77SKalle Valo return 0; 2265f79cbc77SKalle Valo } 2266f79cbc77SKalle Valo 2267f79cbc77SKalle Valo 2268f79cbc77SKalle Valo static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw, 2269f79cbc77SKalle Valo unsigned int changed_flags, 2270f79cbc77SKalle Valo unsigned int *total_flags,u64 multicast) 2271f79cbc77SKalle Valo { 2272f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 2273f79cbc77SKalle Valo 2274f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "%s\n", __func__); 2275f79cbc77SKalle Valo 2276f79cbc77SKalle Valo data->rx_filter = 0; 2277f79cbc77SKalle Valo if (*total_flags & FIF_ALLMULTI) 2278f79cbc77SKalle Valo data->rx_filter |= FIF_ALLMULTI; 2279f79cbc77SKalle Valo if (*total_flags & FIF_MCAST_ACTION) 2280f79cbc77SKalle Valo data->rx_filter |= FIF_MCAST_ACTION; 2281f79cbc77SKalle Valo 2282f79cbc77SKalle Valo *total_flags = data->rx_filter; 2283f79cbc77SKalle Valo } 2284f79cbc77SKalle Valo 2285f79cbc77SKalle Valo static void mac80211_hwsim_bcn_en_iter(void *data, u8 *mac, 2286f79cbc77SKalle Valo struct ieee80211_vif *vif) 2287f79cbc77SKalle Valo { 2288f79cbc77SKalle Valo unsigned int *count = data; 2289f79cbc77SKalle Valo struct hwsim_vif_priv *vp = (void *)vif->drv_priv; 2290f79cbc77SKalle Valo 2291f79cbc77SKalle Valo if (vp->bcn_en) 2292f79cbc77SKalle Valo (*count)++; 2293f79cbc77SKalle Valo } 2294f79cbc77SKalle Valo 2295f79cbc77SKalle Valo static void mac80211_hwsim_vif_info_changed(struct ieee80211_hw *hw, 2296f79cbc77SKalle Valo struct ieee80211_vif *vif, 2297f79cbc77SKalle Valo u64 changed) 2298f79cbc77SKalle Valo { 2299f79cbc77SKalle Valo struct hwsim_vif_priv *vp = (void *)vif->drv_priv; 2300f79cbc77SKalle Valo 2301f79cbc77SKalle Valo hwsim_check_magic(vif); 2302f79cbc77SKalle Valo 2303f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "%s(changed=0x%llx vif->addr=%pM)\n", 2304f79cbc77SKalle Valo __func__, changed, vif->addr); 2305f79cbc77SKalle Valo 2306f79cbc77SKalle Valo if (changed & BSS_CHANGED_ASSOC) { 2307f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, " ASSOC: assoc=%d aid=%d\n", 2308f79cbc77SKalle Valo vif->cfg.assoc, vif->cfg.aid); 2309f79cbc77SKalle Valo vp->assoc = vif->cfg.assoc; 2310f79cbc77SKalle Valo vp->aid = vif->cfg.aid; 2311f79cbc77SKalle Valo } 2312f79cbc77SKalle Valo } 2313f79cbc77SKalle Valo 2314f79cbc77SKalle Valo static void mac80211_hwsim_link_info_changed(struct ieee80211_hw *hw, 2315f79cbc77SKalle Valo struct ieee80211_vif *vif, 2316f79cbc77SKalle Valo struct ieee80211_bss_conf *info, 2317f79cbc77SKalle Valo u64 changed) 2318f79cbc77SKalle Valo { 2319f79cbc77SKalle Valo struct hwsim_vif_priv *vp = (void *)vif->drv_priv; 2320f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 2321f79cbc77SKalle Valo unsigned int link_id = info->link_id; 2322f79cbc77SKalle Valo struct mac80211_hwsim_link_data *link_data = &data->link_data[link_id]; 2323f79cbc77SKalle Valo 2324f79cbc77SKalle Valo hwsim_check_magic(vif); 2325f79cbc77SKalle Valo 2326f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "%s(changed=0x%llx vif->addr=%pM, link id %u)\n", 2327f79cbc77SKalle Valo __func__, (unsigned long long)changed, vif->addr, link_id); 2328f79cbc77SKalle Valo 2329f79cbc77SKalle Valo if (changed & BSS_CHANGED_BSSID) { 2330f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "%s: BSSID changed: %pM\n", 2331f79cbc77SKalle Valo __func__, info->bssid); 2332f79cbc77SKalle Valo memcpy(vp->bssid, info->bssid, ETH_ALEN); 2333f79cbc77SKalle Valo } 2334f79cbc77SKalle Valo 2335f79cbc77SKalle Valo if (changed & BSS_CHANGED_BEACON_ENABLED) { 2336f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, " BCN EN: %d (BI=%u)\n", 2337f79cbc77SKalle Valo info->enable_beacon, info->beacon_int); 2338f79cbc77SKalle Valo vp->bcn_en = info->enable_beacon; 2339f79cbc77SKalle Valo if (data->started && 2340f79cbc77SKalle Valo !hrtimer_is_queued(&link_data->beacon_timer) && 2341f79cbc77SKalle Valo info->enable_beacon) { 2342f79cbc77SKalle Valo u64 tsf, until_tbtt; 2343f79cbc77SKalle Valo u32 bcn_int; 2344f79cbc77SKalle Valo link_data->beacon_int = info->beacon_int * 1024; 2345f79cbc77SKalle Valo tsf = mac80211_hwsim_get_tsf(hw, vif); 2346f79cbc77SKalle Valo bcn_int = link_data->beacon_int; 2347f79cbc77SKalle Valo until_tbtt = bcn_int - do_div(tsf, bcn_int); 2348f79cbc77SKalle Valo 2349f79cbc77SKalle Valo hrtimer_start(&link_data->beacon_timer, 2350f79cbc77SKalle Valo ns_to_ktime(until_tbtt * NSEC_PER_USEC), 2351f79cbc77SKalle Valo HRTIMER_MODE_REL_SOFT); 2352f79cbc77SKalle Valo } else if (!info->enable_beacon) { 2353f79cbc77SKalle Valo unsigned int count = 0; 2354f79cbc77SKalle Valo ieee80211_iterate_active_interfaces_atomic( 2355f79cbc77SKalle Valo data->hw, IEEE80211_IFACE_ITER_NORMAL, 2356f79cbc77SKalle Valo mac80211_hwsim_bcn_en_iter, &count); 2357f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, " beaconing vifs remaining: %u", 2358f79cbc77SKalle Valo count); 2359f79cbc77SKalle Valo if (count == 0) { 2360f79cbc77SKalle Valo hrtimer_cancel(&link_data->beacon_timer); 2361f79cbc77SKalle Valo link_data->beacon_int = 0; 2362f79cbc77SKalle Valo } 2363f79cbc77SKalle Valo } 2364f79cbc77SKalle Valo } 2365f79cbc77SKalle Valo 2366f79cbc77SKalle Valo if (changed & BSS_CHANGED_ERP_CTS_PROT) { 2367f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, " ERP_CTS_PROT: %d\n", 2368f79cbc77SKalle Valo info->use_cts_prot); 2369f79cbc77SKalle Valo } 2370f79cbc77SKalle Valo 2371f79cbc77SKalle Valo if (changed & BSS_CHANGED_ERP_PREAMBLE) { 2372f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, " ERP_PREAMBLE: %d\n", 2373f79cbc77SKalle Valo info->use_short_preamble); 2374f79cbc77SKalle Valo } 2375f79cbc77SKalle Valo 2376f79cbc77SKalle Valo if (changed & BSS_CHANGED_ERP_SLOT) { 2377f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, " ERP_SLOT: %d\n", info->use_short_slot); 2378f79cbc77SKalle Valo } 2379f79cbc77SKalle Valo 2380f79cbc77SKalle Valo if (changed & BSS_CHANGED_HT) { 2381f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, " HT: op_mode=0x%x\n", 2382f79cbc77SKalle Valo info->ht_operation_mode); 2383f79cbc77SKalle Valo } 2384f79cbc77SKalle Valo 2385f79cbc77SKalle Valo if (changed & BSS_CHANGED_BASIC_RATES) { 2386f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, " BASIC_RATES: 0x%llx\n", 2387f79cbc77SKalle Valo (unsigned long long) info->basic_rates); 2388f79cbc77SKalle Valo } 2389f79cbc77SKalle Valo 2390f79cbc77SKalle Valo if (changed & BSS_CHANGED_TXPOWER) 2391f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, " TX Power: %d dBm\n", info->txpower); 2392f79cbc77SKalle Valo } 2393f79cbc77SKalle Valo 2394f79cbc77SKalle Valo static void 2395f79cbc77SKalle Valo mac80211_hwsim_sta_rc_update(struct ieee80211_hw *hw, 2396f79cbc77SKalle Valo struct ieee80211_vif *vif, 2397f79cbc77SKalle Valo struct ieee80211_sta *sta, 2398f79cbc77SKalle Valo u32 changed) 2399f79cbc77SKalle Valo { 2400f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 2401f79cbc77SKalle Valo u32 bw = U32_MAX; 2402f79cbc77SKalle Valo int link_id; 2403f79cbc77SKalle Valo 2404f79cbc77SKalle Valo rcu_read_lock(); 2405f79cbc77SKalle Valo for (link_id = 0; 2406f79cbc77SKalle Valo link_id < ARRAY_SIZE(vif->link_conf); 2407f79cbc77SKalle Valo link_id++) { 2408f79cbc77SKalle Valo enum nl80211_chan_width confbw = NL80211_CHAN_WIDTH_20_NOHT; 2409f79cbc77SKalle Valo struct ieee80211_bss_conf *vif_conf; 2410f79cbc77SKalle Valo struct ieee80211_link_sta *link_sta; 2411f79cbc77SKalle Valo 2412f79cbc77SKalle Valo link_sta = rcu_dereference(sta->link[link_id]); 2413f79cbc77SKalle Valo 2414f79cbc77SKalle Valo if (!link_sta) 2415f79cbc77SKalle Valo continue; 2416f79cbc77SKalle Valo 2417f79cbc77SKalle Valo switch (link_sta->bandwidth) { 2418f79cbc77SKalle Valo #define C(_bw) case IEEE80211_STA_RX_BW_##_bw: bw = _bw; break 2419f79cbc77SKalle Valo C(20); 2420f79cbc77SKalle Valo C(40); 2421f79cbc77SKalle Valo C(80); 2422f79cbc77SKalle Valo C(160); 2423f79cbc77SKalle Valo C(320); 2424f79cbc77SKalle Valo #undef C 2425f79cbc77SKalle Valo } 2426f79cbc77SKalle Valo 2427f79cbc77SKalle Valo if (!data->use_chanctx) { 2428f79cbc77SKalle Valo confbw = data->bw; 2429f79cbc77SKalle Valo } else { 2430f79cbc77SKalle Valo struct ieee80211_chanctx_conf *chanctx_conf; 2431f79cbc77SKalle Valo 2432f79cbc77SKalle Valo vif_conf = rcu_dereference(vif->link_conf[link_id]); 2433f79cbc77SKalle Valo if (WARN_ON(!vif_conf)) 2434f79cbc77SKalle Valo continue; 2435f79cbc77SKalle Valo 2436f79cbc77SKalle Valo chanctx_conf = rcu_dereference(vif_conf->chanctx_conf); 2437f79cbc77SKalle Valo 2438f79cbc77SKalle Valo if (!WARN_ON(!chanctx_conf)) 2439f79cbc77SKalle Valo confbw = chanctx_conf->def.width; 2440f79cbc77SKalle Valo } 2441f79cbc77SKalle Valo 2442f79cbc77SKalle Valo WARN(bw > hwsim_get_chanwidth(confbw), 2443f79cbc77SKalle Valo "intf %pM [link=%d]: bad STA %pM bandwidth %d MHz (%d) > channel config %d MHz (%d)\n", 2444f79cbc77SKalle Valo vif->addr, link_id, sta->addr, bw, sta->deflink.bandwidth, 2445f79cbc77SKalle Valo hwsim_get_chanwidth(data->bw), data->bw); 2446f79cbc77SKalle Valo 2447f79cbc77SKalle Valo 2448f79cbc77SKalle Valo } 2449f79cbc77SKalle Valo rcu_read_unlock(); 2450f79cbc77SKalle Valo 2451f79cbc77SKalle Valo 2452f79cbc77SKalle Valo } 2453f79cbc77SKalle Valo 2454f79cbc77SKalle Valo static int mac80211_hwsim_sta_add(struct ieee80211_hw *hw, 2455f79cbc77SKalle Valo struct ieee80211_vif *vif, 2456f79cbc77SKalle Valo struct ieee80211_sta *sta) 2457f79cbc77SKalle Valo { 2458f79cbc77SKalle Valo struct hwsim_sta_priv *sp = (void *)sta->drv_priv; 2459f79cbc77SKalle Valo 2460f79cbc77SKalle Valo hwsim_check_magic(vif); 2461f79cbc77SKalle Valo hwsim_set_sta_magic(sta); 2462f79cbc77SKalle Valo mac80211_hwsim_sta_rc_update(hw, vif, sta, 0); 2463f79cbc77SKalle Valo 2464f79cbc77SKalle Valo if (sta->valid_links) { 2465f79cbc77SKalle Valo WARN(hweight16(sta->valid_links) > 1, 2466f79cbc77SKalle Valo "expect to add STA with single link, have 0x%x\n", 2467f79cbc77SKalle Valo sta->valid_links); 2468f79cbc77SKalle Valo sp->active_links_rx = sta->valid_links; 2469f79cbc77SKalle Valo } 2470f79cbc77SKalle Valo 2471f79cbc77SKalle Valo return 0; 2472f79cbc77SKalle Valo } 2473f79cbc77SKalle Valo 2474f79cbc77SKalle Valo static int mac80211_hwsim_sta_remove(struct ieee80211_hw *hw, 2475f79cbc77SKalle Valo struct ieee80211_vif *vif, 2476f79cbc77SKalle Valo struct ieee80211_sta *sta) 2477f79cbc77SKalle Valo { 2478f79cbc77SKalle Valo hwsim_check_magic(vif); 2479f79cbc77SKalle Valo hwsim_clear_sta_magic(sta); 2480f79cbc77SKalle Valo 2481f79cbc77SKalle Valo return 0; 2482f79cbc77SKalle Valo } 2483f79cbc77SKalle Valo 2484f79cbc77SKalle Valo static int mac80211_hwsim_sta_state(struct ieee80211_hw *hw, 2485f79cbc77SKalle Valo struct ieee80211_vif *vif, 2486f79cbc77SKalle Valo struct ieee80211_sta *sta, 2487f79cbc77SKalle Valo enum ieee80211_sta_state old_state, 2488f79cbc77SKalle Valo enum ieee80211_sta_state new_state) 2489f79cbc77SKalle Valo { 2490f79cbc77SKalle Valo if (new_state == IEEE80211_STA_NOTEXIST) 2491f79cbc77SKalle Valo return mac80211_hwsim_sta_remove(hw, vif, sta); 2492f79cbc77SKalle Valo 2493f79cbc77SKalle Valo if (old_state == IEEE80211_STA_NOTEXIST) 2494f79cbc77SKalle Valo return mac80211_hwsim_sta_add(hw, vif, sta); 2495f79cbc77SKalle Valo 2496f79cbc77SKalle Valo /* 2497f79cbc77SKalle Valo * when client is authorized (AP station marked as such), 2498f79cbc77SKalle Valo * enable all links 2499f79cbc77SKalle Valo */ 2500f79cbc77SKalle Valo if (vif->type == NL80211_IFTYPE_STATION && 2501f79cbc77SKalle Valo new_state == IEEE80211_STA_AUTHORIZED && !sta->tdls) 2502f79cbc77SKalle Valo ieee80211_set_active_links_async(vif, vif->valid_links); 2503f79cbc77SKalle Valo 2504f79cbc77SKalle Valo return 0; 2505f79cbc77SKalle Valo } 2506f79cbc77SKalle Valo 2507f79cbc77SKalle Valo static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw, 2508f79cbc77SKalle Valo struct ieee80211_vif *vif, 2509f79cbc77SKalle Valo enum sta_notify_cmd cmd, 2510f79cbc77SKalle Valo struct ieee80211_sta *sta) 2511f79cbc77SKalle Valo { 2512f79cbc77SKalle Valo hwsim_check_magic(vif); 2513f79cbc77SKalle Valo 2514f79cbc77SKalle Valo switch (cmd) { 2515f79cbc77SKalle Valo case STA_NOTIFY_SLEEP: 2516f79cbc77SKalle Valo case STA_NOTIFY_AWAKE: 2517f79cbc77SKalle Valo /* TODO: make good use of these flags */ 2518f79cbc77SKalle Valo break; 2519f79cbc77SKalle Valo default: 2520f79cbc77SKalle Valo WARN(1, "Invalid sta notify: %d\n", cmd); 2521f79cbc77SKalle Valo break; 2522f79cbc77SKalle Valo } 2523f79cbc77SKalle Valo } 2524f79cbc77SKalle Valo 2525f79cbc77SKalle Valo static int mac80211_hwsim_set_tim(struct ieee80211_hw *hw, 2526f79cbc77SKalle Valo struct ieee80211_sta *sta, 2527f79cbc77SKalle Valo bool set) 2528f79cbc77SKalle Valo { 2529f79cbc77SKalle Valo hwsim_check_sta_magic(sta); 2530f79cbc77SKalle Valo return 0; 2531f79cbc77SKalle Valo } 2532f79cbc77SKalle Valo 2533f79cbc77SKalle Valo static int mac80211_hwsim_conf_tx(struct ieee80211_hw *hw, 2534f79cbc77SKalle Valo struct ieee80211_vif *vif, 2535f79cbc77SKalle Valo unsigned int link_id, u16 queue, 2536f79cbc77SKalle Valo const struct ieee80211_tx_queue_params *params) 2537f79cbc77SKalle Valo { 2538f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, 2539f79cbc77SKalle Valo "%s (queue=%d txop=%d cw_min=%d cw_max=%d aifs=%d)\n", 2540f79cbc77SKalle Valo __func__, queue, 2541f79cbc77SKalle Valo params->txop, params->cw_min, 2542f79cbc77SKalle Valo params->cw_max, params->aifs); 2543f79cbc77SKalle Valo return 0; 2544f79cbc77SKalle Valo } 2545f79cbc77SKalle Valo 2546f79cbc77SKalle Valo static int mac80211_hwsim_get_survey(struct ieee80211_hw *hw, int idx, 2547f79cbc77SKalle Valo struct survey_info *survey) 2548f79cbc77SKalle Valo { 2549f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = hw->priv; 2550f79cbc77SKalle Valo 2551f79cbc77SKalle Valo if (idx < 0 || idx >= ARRAY_SIZE(hwsim->survey_data)) 2552f79cbc77SKalle Valo return -ENOENT; 2553f79cbc77SKalle Valo 2554f79cbc77SKalle Valo mutex_lock(&hwsim->mutex); 2555f79cbc77SKalle Valo survey->channel = hwsim->survey_data[idx].channel; 2556f79cbc77SKalle Valo if (!survey->channel) { 2557f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2558f79cbc77SKalle Valo return -ENOENT; 2559f79cbc77SKalle Valo } 2560f79cbc77SKalle Valo 2561f79cbc77SKalle Valo /* 2562f79cbc77SKalle Valo * Magically conjured dummy values --- this is only ok for simulated hardware. 2563f79cbc77SKalle Valo * 2564f79cbc77SKalle Valo * A real driver which cannot determine real values noise MUST NOT 2565f79cbc77SKalle Valo * report any, especially not a magically conjured ones :-) 2566f79cbc77SKalle Valo */ 2567f79cbc77SKalle Valo survey->filled = SURVEY_INFO_NOISE_DBM | 2568f79cbc77SKalle Valo SURVEY_INFO_TIME | 2569f79cbc77SKalle Valo SURVEY_INFO_TIME_BUSY; 2570f79cbc77SKalle Valo survey->noise = -92; 2571f79cbc77SKalle Valo survey->time = 2572f79cbc77SKalle Valo jiffies_to_msecs(hwsim->survey_data[idx].end - 2573f79cbc77SKalle Valo hwsim->survey_data[idx].start); 2574f79cbc77SKalle Valo /* report 12.5% of channel time is used */ 2575f79cbc77SKalle Valo survey->time_busy = survey->time/8; 2576f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2577f79cbc77SKalle Valo 2578f79cbc77SKalle Valo return 0; 2579f79cbc77SKalle Valo } 2580f79cbc77SKalle Valo 2581f79cbc77SKalle Valo #ifdef CONFIG_NL80211_TESTMODE 2582f79cbc77SKalle Valo /* 2583f79cbc77SKalle Valo * This section contains example code for using netlink 2584f79cbc77SKalle Valo * attributes with the testmode command in nl80211. 2585f79cbc77SKalle Valo */ 2586f79cbc77SKalle Valo 2587f79cbc77SKalle Valo /* These enums need to be kept in sync with userspace */ 2588f79cbc77SKalle Valo enum hwsim_testmode_attr { 2589f79cbc77SKalle Valo __HWSIM_TM_ATTR_INVALID = 0, 2590f79cbc77SKalle Valo HWSIM_TM_ATTR_CMD = 1, 2591f79cbc77SKalle Valo HWSIM_TM_ATTR_PS = 2, 2592f79cbc77SKalle Valo 2593f79cbc77SKalle Valo /* keep last */ 2594f79cbc77SKalle Valo __HWSIM_TM_ATTR_AFTER_LAST, 2595f79cbc77SKalle Valo HWSIM_TM_ATTR_MAX = __HWSIM_TM_ATTR_AFTER_LAST - 1 2596f79cbc77SKalle Valo }; 2597f79cbc77SKalle Valo 2598f79cbc77SKalle Valo enum hwsim_testmode_cmd { 2599f79cbc77SKalle Valo HWSIM_TM_CMD_SET_PS = 0, 2600f79cbc77SKalle Valo HWSIM_TM_CMD_GET_PS = 1, 2601f79cbc77SKalle Valo HWSIM_TM_CMD_STOP_QUEUES = 2, 2602f79cbc77SKalle Valo HWSIM_TM_CMD_WAKE_QUEUES = 3, 2603f79cbc77SKalle Valo }; 2604f79cbc77SKalle Valo 2605f79cbc77SKalle Valo static const struct nla_policy hwsim_testmode_policy[HWSIM_TM_ATTR_MAX + 1] = { 2606f79cbc77SKalle Valo [HWSIM_TM_ATTR_CMD] = { .type = NLA_U32 }, 2607f79cbc77SKalle Valo [HWSIM_TM_ATTR_PS] = { .type = NLA_U32 }, 2608f79cbc77SKalle Valo }; 2609f79cbc77SKalle Valo 2610f79cbc77SKalle Valo static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw, 2611f79cbc77SKalle Valo struct ieee80211_vif *vif, 2612f79cbc77SKalle Valo void *data, int len) 2613f79cbc77SKalle Valo { 2614f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = hw->priv; 2615f79cbc77SKalle Valo struct nlattr *tb[HWSIM_TM_ATTR_MAX + 1]; 2616f79cbc77SKalle Valo struct sk_buff *skb; 2617f79cbc77SKalle Valo int err, ps; 2618f79cbc77SKalle Valo 2619f79cbc77SKalle Valo err = nla_parse_deprecated(tb, HWSIM_TM_ATTR_MAX, data, len, 2620f79cbc77SKalle Valo hwsim_testmode_policy, NULL); 2621f79cbc77SKalle Valo if (err) 2622f79cbc77SKalle Valo return err; 2623f79cbc77SKalle Valo 2624f79cbc77SKalle Valo if (!tb[HWSIM_TM_ATTR_CMD]) 2625f79cbc77SKalle Valo return -EINVAL; 2626f79cbc77SKalle Valo 2627f79cbc77SKalle Valo switch (nla_get_u32(tb[HWSIM_TM_ATTR_CMD])) { 2628f79cbc77SKalle Valo case HWSIM_TM_CMD_SET_PS: 2629f79cbc77SKalle Valo if (!tb[HWSIM_TM_ATTR_PS]) 2630f79cbc77SKalle Valo return -EINVAL; 2631f79cbc77SKalle Valo ps = nla_get_u32(tb[HWSIM_TM_ATTR_PS]); 2632f79cbc77SKalle Valo return hwsim_fops_ps_write(hwsim, ps); 2633f79cbc77SKalle Valo case HWSIM_TM_CMD_GET_PS: 2634f79cbc77SKalle Valo skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 2635f79cbc77SKalle Valo nla_total_size(sizeof(u32))); 2636f79cbc77SKalle Valo if (!skb) 2637f79cbc77SKalle Valo return -ENOMEM; 2638f79cbc77SKalle Valo if (nla_put_u32(skb, HWSIM_TM_ATTR_PS, hwsim->ps)) 2639f79cbc77SKalle Valo goto nla_put_failure; 2640f79cbc77SKalle Valo return cfg80211_testmode_reply(skb); 2641f79cbc77SKalle Valo case HWSIM_TM_CMD_STOP_QUEUES: 2642f79cbc77SKalle Valo ieee80211_stop_queues(hw); 2643f79cbc77SKalle Valo return 0; 2644f79cbc77SKalle Valo case HWSIM_TM_CMD_WAKE_QUEUES: 2645f79cbc77SKalle Valo ieee80211_wake_queues(hw); 2646f79cbc77SKalle Valo return 0; 2647f79cbc77SKalle Valo default: 2648f79cbc77SKalle Valo return -EOPNOTSUPP; 2649f79cbc77SKalle Valo } 2650f79cbc77SKalle Valo 2651f79cbc77SKalle Valo nla_put_failure: 2652f79cbc77SKalle Valo kfree_skb(skb); 2653f79cbc77SKalle Valo return -ENOBUFS; 2654f79cbc77SKalle Valo } 2655f79cbc77SKalle Valo #endif 2656f79cbc77SKalle Valo 2657f79cbc77SKalle Valo static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw, 2658f79cbc77SKalle Valo struct ieee80211_vif *vif, 2659f79cbc77SKalle Valo struct ieee80211_ampdu_params *params) 2660f79cbc77SKalle Valo { 2661f79cbc77SKalle Valo struct ieee80211_sta *sta = params->sta; 2662f79cbc77SKalle Valo enum ieee80211_ampdu_mlme_action action = params->action; 2663f79cbc77SKalle Valo u16 tid = params->tid; 2664f79cbc77SKalle Valo 2665f79cbc77SKalle Valo switch (action) { 2666f79cbc77SKalle Valo case IEEE80211_AMPDU_TX_START: 2667f79cbc77SKalle Valo return IEEE80211_AMPDU_TX_START_IMMEDIATE; 2668f79cbc77SKalle Valo case IEEE80211_AMPDU_TX_STOP_CONT: 2669f79cbc77SKalle Valo case IEEE80211_AMPDU_TX_STOP_FLUSH: 2670f79cbc77SKalle Valo case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: 2671f79cbc77SKalle Valo ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); 2672f79cbc77SKalle Valo break; 2673f79cbc77SKalle Valo case IEEE80211_AMPDU_TX_OPERATIONAL: 2674f79cbc77SKalle Valo break; 2675f79cbc77SKalle Valo case IEEE80211_AMPDU_RX_START: 2676f79cbc77SKalle Valo case IEEE80211_AMPDU_RX_STOP: 2677f79cbc77SKalle Valo break; 2678f79cbc77SKalle Valo default: 2679f79cbc77SKalle Valo return -EOPNOTSUPP; 2680f79cbc77SKalle Valo } 2681f79cbc77SKalle Valo 2682f79cbc77SKalle Valo return 0; 2683f79cbc77SKalle Valo } 2684f79cbc77SKalle Valo 2685f79cbc77SKalle Valo static void mac80211_hwsim_flush(struct ieee80211_hw *hw, 2686f79cbc77SKalle Valo struct ieee80211_vif *vif, 2687f79cbc77SKalle Valo u32 queues, bool drop) 2688f79cbc77SKalle Valo { 2689f79cbc77SKalle Valo /* Not implemented, queues only on kernel side */ 2690f79cbc77SKalle Valo } 2691f79cbc77SKalle Valo 2692f79cbc77SKalle Valo static void hw_scan_work(struct work_struct *work) 2693f79cbc77SKalle Valo { 2694f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = 2695f79cbc77SKalle Valo container_of(work, struct mac80211_hwsim_data, hw_scan.work); 2696f79cbc77SKalle Valo struct cfg80211_scan_request *req = hwsim->hw_scan_request; 2697f79cbc77SKalle Valo int dwell, i; 2698f79cbc77SKalle Valo 2699f79cbc77SKalle Valo mutex_lock(&hwsim->mutex); 2700f79cbc77SKalle Valo if (hwsim->scan_chan_idx >= req->n_channels) { 2701f79cbc77SKalle Valo struct cfg80211_scan_info info = { 2702f79cbc77SKalle Valo .aborted = false, 2703f79cbc77SKalle Valo }; 2704f79cbc77SKalle Valo 2705f79cbc77SKalle Valo wiphy_dbg(hwsim->hw->wiphy, "hw scan complete\n"); 2706f79cbc77SKalle Valo ieee80211_scan_completed(hwsim->hw, &info); 2707f79cbc77SKalle Valo hwsim->hw_scan_request = NULL; 2708f79cbc77SKalle Valo hwsim->hw_scan_vif = NULL; 2709f79cbc77SKalle Valo hwsim->tmp_chan = NULL; 2710f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2711f79cbc77SKalle Valo mac80211_hwsim_config_mac_nl(hwsim->hw, hwsim->scan_addr, 2712f79cbc77SKalle Valo false); 2713f79cbc77SKalle Valo return; 2714f79cbc77SKalle Valo } 2715f79cbc77SKalle Valo 2716f79cbc77SKalle Valo wiphy_dbg(hwsim->hw->wiphy, "hw scan %d MHz\n", 2717f79cbc77SKalle Valo req->channels[hwsim->scan_chan_idx]->center_freq); 2718f79cbc77SKalle Valo 2719f79cbc77SKalle Valo hwsim->tmp_chan = req->channels[hwsim->scan_chan_idx]; 2720f79cbc77SKalle Valo if (hwsim->tmp_chan->flags & (IEEE80211_CHAN_NO_IR | 2721f79cbc77SKalle Valo IEEE80211_CHAN_RADAR) || 2722f79cbc77SKalle Valo !req->n_ssids) { 2723f79cbc77SKalle Valo dwell = 120; 2724f79cbc77SKalle Valo } else { 2725f79cbc77SKalle Valo dwell = 30; 2726f79cbc77SKalle Valo /* send probes */ 2727f79cbc77SKalle Valo for (i = 0; i < req->n_ssids; i++) { 2728f79cbc77SKalle Valo struct sk_buff *probe; 2729f79cbc77SKalle Valo struct ieee80211_mgmt *mgmt; 2730f79cbc77SKalle Valo 2731f79cbc77SKalle Valo probe = ieee80211_probereq_get(hwsim->hw, 2732f79cbc77SKalle Valo hwsim->scan_addr, 2733f79cbc77SKalle Valo req->ssids[i].ssid, 2734f79cbc77SKalle Valo req->ssids[i].ssid_len, 2735f79cbc77SKalle Valo req->ie_len); 2736f79cbc77SKalle Valo if (!probe) 2737f79cbc77SKalle Valo continue; 2738f79cbc77SKalle Valo 2739f79cbc77SKalle Valo mgmt = (struct ieee80211_mgmt *) probe->data; 2740f79cbc77SKalle Valo memcpy(mgmt->da, req->bssid, ETH_ALEN); 2741f79cbc77SKalle Valo memcpy(mgmt->bssid, req->bssid, ETH_ALEN); 2742f79cbc77SKalle Valo 2743f79cbc77SKalle Valo if (req->ie_len) 2744f79cbc77SKalle Valo skb_put_data(probe, req->ie, req->ie_len); 2745f79cbc77SKalle Valo 2746f79cbc77SKalle Valo rcu_read_lock(); 2747f79cbc77SKalle Valo if (!ieee80211_tx_prepare_skb(hwsim->hw, 2748f79cbc77SKalle Valo hwsim->hw_scan_vif, 2749f79cbc77SKalle Valo probe, 2750f79cbc77SKalle Valo hwsim->tmp_chan->band, 2751f79cbc77SKalle Valo NULL)) { 2752f79cbc77SKalle Valo rcu_read_unlock(); 2753f79cbc77SKalle Valo kfree_skb(probe); 2754f79cbc77SKalle Valo continue; 2755f79cbc77SKalle Valo } 2756f79cbc77SKalle Valo 2757f79cbc77SKalle Valo local_bh_disable(); 2758f79cbc77SKalle Valo mac80211_hwsim_tx_frame(hwsim->hw, probe, 2759f79cbc77SKalle Valo hwsim->tmp_chan); 2760f79cbc77SKalle Valo rcu_read_unlock(); 2761f79cbc77SKalle Valo local_bh_enable(); 2762f79cbc77SKalle Valo } 2763f79cbc77SKalle Valo } 2764f79cbc77SKalle Valo ieee80211_queue_delayed_work(hwsim->hw, &hwsim->hw_scan, 2765f79cbc77SKalle Valo msecs_to_jiffies(dwell)); 2766f79cbc77SKalle Valo hwsim->survey_data[hwsim->scan_chan_idx].channel = hwsim->tmp_chan; 2767f79cbc77SKalle Valo hwsim->survey_data[hwsim->scan_chan_idx].start = jiffies; 2768f79cbc77SKalle Valo hwsim->survey_data[hwsim->scan_chan_idx].end = 2769f79cbc77SKalle Valo jiffies + msecs_to_jiffies(dwell); 2770f79cbc77SKalle Valo hwsim->scan_chan_idx++; 2771f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2772f79cbc77SKalle Valo } 2773f79cbc77SKalle Valo 2774f79cbc77SKalle Valo static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw, 2775f79cbc77SKalle Valo struct ieee80211_vif *vif, 2776f79cbc77SKalle Valo struct ieee80211_scan_request *hw_req) 2777f79cbc77SKalle Valo { 2778f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = hw->priv; 2779f79cbc77SKalle Valo struct cfg80211_scan_request *req = &hw_req->req; 2780f79cbc77SKalle Valo 2781f79cbc77SKalle Valo mutex_lock(&hwsim->mutex); 2782f79cbc77SKalle Valo if (WARN_ON(hwsim->tmp_chan || hwsim->hw_scan_request)) { 2783f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2784f79cbc77SKalle Valo return -EBUSY; 2785f79cbc77SKalle Valo } 2786f79cbc77SKalle Valo hwsim->hw_scan_request = req; 2787f79cbc77SKalle Valo hwsim->hw_scan_vif = vif; 2788f79cbc77SKalle Valo hwsim->scan_chan_idx = 0; 2789f79cbc77SKalle Valo if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) 2790f79cbc77SKalle Valo get_random_mask_addr(hwsim->scan_addr, 2791f79cbc77SKalle Valo hw_req->req.mac_addr, 2792f79cbc77SKalle Valo hw_req->req.mac_addr_mask); 2793f79cbc77SKalle Valo else 2794f79cbc77SKalle Valo memcpy(hwsim->scan_addr, vif->addr, ETH_ALEN); 2795f79cbc77SKalle Valo memset(hwsim->survey_data, 0, sizeof(hwsim->survey_data)); 2796f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2797f79cbc77SKalle Valo 2798f79cbc77SKalle Valo mac80211_hwsim_config_mac_nl(hw, hwsim->scan_addr, true); 2799f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "hwsim hw_scan request\n"); 2800f79cbc77SKalle Valo 2801f79cbc77SKalle Valo ieee80211_queue_delayed_work(hwsim->hw, &hwsim->hw_scan, 0); 2802f79cbc77SKalle Valo 2803f79cbc77SKalle Valo return 0; 2804f79cbc77SKalle Valo } 2805f79cbc77SKalle Valo 2806f79cbc77SKalle Valo static void mac80211_hwsim_cancel_hw_scan(struct ieee80211_hw *hw, 2807f79cbc77SKalle Valo struct ieee80211_vif *vif) 2808f79cbc77SKalle Valo { 2809f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = hw->priv; 2810f79cbc77SKalle Valo struct cfg80211_scan_info info = { 2811f79cbc77SKalle Valo .aborted = true, 2812f79cbc77SKalle Valo }; 2813f79cbc77SKalle Valo 2814f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "hwsim cancel_hw_scan\n"); 2815f79cbc77SKalle Valo 2816f79cbc77SKalle Valo cancel_delayed_work_sync(&hwsim->hw_scan); 2817f79cbc77SKalle Valo 2818f79cbc77SKalle Valo mutex_lock(&hwsim->mutex); 2819f79cbc77SKalle Valo ieee80211_scan_completed(hwsim->hw, &info); 2820f79cbc77SKalle Valo hwsim->tmp_chan = NULL; 2821f79cbc77SKalle Valo hwsim->hw_scan_request = NULL; 2822f79cbc77SKalle Valo hwsim->hw_scan_vif = NULL; 2823f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2824f79cbc77SKalle Valo } 2825f79cbc77SKalle Valo 2826f79cbc77SKalle Valo static void mac80211_hwsim_sw_scan(struct ieee80211_hw *hw, 2827f79cbc77SKalle Valo struct ieee80211_vif *vif, 2828f79cbc77SKalle Valo const u8 *mac_addr) 2829f79cbc77SKalle Valo { 2830f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = hw->priv; 2831f79cbc77SKalle Valo 2832f79cbc77SKalle Valo mutex_lock(&hwsim->mutex); 2833f79cbc77SKalle Valo 2834f79cbc77SKalle Valo if (hwsim->scanning) { 2835f79cbc77SKalle Valo pr_debug("two hwsim sw_scans detected!\n"); 2836f79cbc77SKalle Valo goto out; 2837f79cbc77SKalle Valo } 2838f79cbc77SKalle Valo 2839f79cbc77SKalle Valo pr_debug("hwsim sw_scan request, prepping stuff\n"); 2840f79cbc77SKalle Valo 2841f79cbc77SKalle Valo memcpy(hwsim->scan_addr, mac_addr, ETH_ALEN); 2842f79cbc77SKalle Valo mac80211_hwsim_config_mac_nl(hw, hwsim->scan_addr, true); 2843f79cbc77SKalle Valo hwsim->scanning = true; 2844f79cbc77SKalle Valo memset(hwsim->survey_data, 0, sizeof(hwsim->survey_data)); 2845f79cbc77SKalle Valo 2846f79cbc77SKalle Valo out: 2847f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2848f79cbc77SKalle Valo } 2849f79cbc77SKalle Valo 2850f79cbc77SKalle Valo static void mac80211_hwsim_sw_scan_complete(struct ieee80211_hw *hw, 2851f79cbc77SKalle Valo struct ieee80211_vif *vif) 2852f79cbc77SKalle Valo { 2853f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = hw->priv; 2854f79cbc77SKalle Valo 2855f79cbc77SKalle Valo mutex_lock(&hwsim->mutex); 2856f79cbc77SKalle Valo 2857f79cbc77SKalle Valo pr_debug("hwsim sw_scan_complete\n"); 2858f79cbc77SKalle Valo hwsim->scanning = false; 2859f79cbc77SKalle Valo mac80211_hwsim_config_mac_nl(hw, hwsim->scan_addr, false); 2860f79cbc77SKalle Valo eth_zero_addr(hwsim->scan_addr); 2861f79cbc77SKalle Valo 2862f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2863f79cbc77SKalle Valo } 2864f79cbc77SKalle Valo 2865f79cbc77SKalle Valo static void hw_roc_start(struct work_struct *work) 2866f79cbc77SKalle Valo { 2867f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = 2868f79cbc77SKalle Valo container_of(work, struct mac80211_hwsim_data, roc_start.work); 2869f79cbc77SKalle Valo 2870f79cbc77SKalle Valo mutex_lock(&hwsim->mutex); 2871f79cbc77SKalle Valo 2872f79cbc77SKalle Valo wiphy_dbg(hwsim->hw->wiphy, "hwsim ROC begins\n"); 2873f79cbc77SKalle Valo hwsim->tmp_chan = hwsim->roc_chan; 2874f79cbc77SKalle Valo ieee80211_ready_on_channel(hwsim->hw); 2875f79cbc77SKalle Valo 2876f79cbc77SKalle Valo ieee80211_queue_delayed_work(hwsim->hw, &hwsim->roc_done, 2877f79cbc77SKalle Valo msecs_to_jiffies(hwsim->roc_duration)); 2878f79cbc77SKalle Valo 2879f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2880f79cbc77SKalle Valo } 2881f79cbc77SKalle Valo 2882f79cbc77SKalle Valo static void hw_roc_done(struct work_struct *work) 2883f79cbc77SKalle Valo { 2884f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = 2885f79cbc77SKalle Valo container_of(work, struct mac80211_hwsim_data, roc_done.work); 2886f79cbc77SKalle Valo 2887f79cbc77SKalle Valo mutex_lock(&hwsim->mutex); 2888f79cbc77SKalle Valo ieee80211_remain_on_channel_expired(hwsim->hw); 2889f79cbc77SKalle Valo hwsim->tmp_chan = NULL; 2890f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2891f79cbc77SKalle Valo 2892f79cbc77SKalle Valo wiphy_dbg(hwsim->hw->wiphy, "hwsim ROC expired\n"); 2893f79cbc77SKalle Valo } 2894f79cbc77SKalle Valo 2895f79cbc77SKalle Valo static int mac80211_hwsim_roc(struct ieee80211_hw *hw, 2896f79cbc77SKalle Valo struct ieee80211_vif *vif, 2897f79cbc77SKalle Valo struct ieee80211_channel *chan, 2898f79cbc77SKalle Valo int duration, 2899f79cbc77SKalle Valo enum ieee80211_roc_type type) 2900f79cbc77SKalle Valo { 2901f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = hw->priv; 2902f79cbc77SKalle Valo 2903f79cbc77SKalle Valo mutex_lock(&hwsim->mutex); 2904f79cbc77SKalle Valo if (WARN_ON(hwsim->tmp_chan || hwsim->hw_scan_request)) { 2905f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2906f79cbc77SKalle Valo return -EBUSY; 2907f79cbc77SKalle Valo } 2908f79cbc77SKalle Valo 2909f79cbc77SKalle Valo hwsim->roc_chan = chan; 2910f79cbc77SKalle Valo hwsim->roc_duration = duration; 2911f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2912f79cbc77SKalle Valo 2913f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "hwsim ROC (%d MHz, %d ms)\n", 2914f79cbc77SKalle Valo chan->center_freq, duration); 2915f79cbc77SKalle Valo ieee80211_queue_delayed_work(hw, &hwsim->roc_start, HZ/50); 2916f79cbc77SKalle Valo 2917f79cbc77SKalle Valo return 0; 2918f79cbc77SKalle Valo } 2919f79cbc77SKalle Valo 2920f79cbc77SKalle Valo static int mac80211_hwsim_croc(struct ieee80211_hw *hw, 2921f79cbc77SKalle Valo struct ieee80211_vif *vif) 2922f79cbc77SKalle Valo { 2923f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = hw->priv; 2924f79cbc77SKalle Valo 2925f79cbc77SKalle Valo cancel_delayed_work_sync(&hwsim->roc_start); 2926f79cbc77SKalle Valo cancel_delayed_work_sync(&hwsim->roc_done); 2927f79cbc77SKalle Valo 2928f79cbc77SKalle Valo mutex_lock(&hwsim->mutex); 2929f79cbc77SKalle Valo hwsim->tmp_chan = NULL; 2930f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2931f79cbc77SKalle Valo 2932f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "hwsim ROC canceled\n"); 2933f79cbc77SKalle Valo 2934f79cbc77SKalle Valo return 0; 2935f79cbc77SKalle Valo } 2936f79cbc77SKalle Valo 2937f79cbc77SKalle Valo static int mac80211_hwsim_add_chanctx(struct ieee80211_hw *hw, 2938f79cbc77SKalle Valo struct ieee80211_chanctx_conf *ctx) 2939f79cbc77SKalle Valo { 2940f79cbc77SKalle Valo hwsim_set_chanctx_magic(ctx); 2941f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, 2942f79cbc77SKalle Valo "add channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n", 2943f79cbc77SKalle Valo ctx->def.chan->center_freq, ctx->def.width, 2944f79cbc77SKalle Valo ctx->def.center_freq1, ctx->def.center_freq2); 2945f79cbc77SKalle Valo return 0; 2946f79cbc77SKalle Valo } 2947f79cbc77SKalle Valo 2948f79cbc77SKalle Valo static void mac80211_hwsim_remove_chanctx(struct ieee80211_hw *hw, 2949f79cbc77SKalle Valo struct ieee80211_chanctx_conf *ctx) 2950f79cbc77SKalle Valo { 2951f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, 2952f79cbc77SKalle Valo "remove channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n", 2953f79cbc77SKalle Valo ctx->def.chan->center_freq, ctx->def.width, 2954f79cbc77SKalle Valo ctx->def.center_freq1, ctx->def.center_freq2); 2955f79cbc77SKalle Valo hwsim_check_chanctx_magic(ctx); 2956f79cbc77SKalle Valo hwsim_clear_chanctx_magic(ctx); 2957f79cbc77SKalle Valo } 2958f79cbc77SKalle Valo 2959f79cbc77SKalle Valo static void mac80211_hwsim_change_chanctx(struct ieee80211_hw *hw, 2960f79cbc77SKalle Valo struct ieee80211_chanctx_conf *ctx, 2961f79cbc77SKalle Valo u32 changed) 2962f79cbc77SKalle Valo { 2963f79cbc77SKalle Valo hwsim_check_chanctx_magic(ctx); 2964f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, 2965f79cbc77SKalle Valo "change channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n", 2966f79cbc77SKalle Valo ctx->def.chan->center_freq, ctx->def.width, 2967f79cbc77SKalle Valo ctx->def.center_freq1, ctx->def.center_freq2); 2968f79cbc77SKalle Valo } 2969f79cbc77SKalle Valo 2970f79cbc77SKalle Valo static int mac80211_hwsim_assign_vif_chanctx(struct ieee80211_hw *hw, 2971f79cbc77SKalle Valo struct ieee80211_vif *vif, 2972f79cbc77SKalle Valo struct ieee80211_bss_conf *link_conf, 2973f79cbc77SKalle Valo struct ieee80211_chanctx_conf *ctx) 2974f79cbc77SKalle Valo { 2975f79cbc77SKalle Valo hwsim_check_magic(vif); 2976f79cbc77SKalle Valo hwsim_check_chanctx_magic(ctx); 2977f79cbc77SKalle Valo 2978f79cbc77SKalle Valo /* if we activate a link while already associated wake it up */ 2979f79cbc77SKalle Valo if (vif->type == NL80211_IFTYPE_STATION && vif->cfg.assoc) { 2980f79cbc77SKalle Valo struct sk_buff *skb; 2981f79cbc77SKalle Valo 2982f79cbc77SKalle Valo skb = ieee80211_nullfunc_get(hw, vif, link_conf->link_id, true); 2983f79cbc77SKalle Valo if (skb) { 2984f79cbc77SKalle Valo local_bh_disable(); 2985f79cbc77SKalle Valo mac80211_hwsim_tx_frame(hw, skb, ctx->def.chan); 2986f79cbc77SKalle Valo local_bh_enable(); 2987f79cbc77SKalle Valo } 2988f79cbc77SKalle Valo } 2989f79cbc77SKalle Valo 2990f79cbc77SKalle Valo return 0; 2991f79cbc77SKalle Valo } 2992f79cbc77SKalle Valo 2993f79cbc77SKalle Valo static void mac80211_hwsim_unassign_vif_chanctx(struct ieee80211_hw *hw, 2994f79cbc77SKalle Valo struct ieee80211_vif *vif, 2995f79cbc77SKalle Valo struct ieee80211_bss_conf *link_conf, 2996f79cbc77SKalle Valo struct ieee80211_chanctx_conf *ctx) 2997f79cbc77SKalle Valo { 2998f79cbc77SKalle Valo hwsim_check_magic(vif); 2999f79cbc77SKalle Valo hwsim_check_chanctx_magic(ctx); 3000f79cbc77SKalle Valo 3001f79cbc77SKalle Valo /* if we deactivate a link while associated suspend it first */ 3002f79cbc77SKalle Valo if (vif->type == NL80211_IFTYPE_STATION && vif->cfg.assoc) { 3003f79cbc77SKalle Valo struct sk_buff *skb; 3004f79cbc77SKalle Valo 3005f79cbc77SKalle Valo skb = ieee80211_nullfunc_get(hw, vif, link_conf->link_id, true); 3006f79cbc77SKalle Valo if (skb) { 3007f79cbc77SKalle Valo struct ieee80211_hdr *hdr = (void *)skb->data; 3008f79cbc77SKalle Valo 3009f79cbc77SKalle Valo hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); 3010f79cbc77SKalle Valo 3011f79cbc77SKalle Valo local_bh_disable(); 3012f79cbc77SKalle Valo mac80211_hwsim_tx_frame(hw, skb, ctx->def.chan); 3013f79cbc77SKalle Valo local_bh_enable(); 3014f79cbc77SKalle Valo } 3015f79cbc77SKalle Valo } 3016f79cbc77SKalle Valo } 3017f79cbc77SKalle Valo 3018f79cbc77SKalle Valo static const char mac80211_hwsim_gstrings_stats[][ETH_GSTRING_LEN] = { 3019f79cbc77SKalle Valo "tx_pkts_nic", 3020f79cbc77SKalle Valo "tx_bytes_nic", 3021f79cbc77SKalle Valo "rx_pkts_nic", 3022f79cbc77SKalle Valo "rx_bytes_nic", 3023f79cbc77SKalle Valo "d_tx_dropped", 3024f79cbc77SKalle Valo "d_tx_failed", 3025f79cbc77SKalle Valo "d_ps_mode", 3026f79cbc77SKalle Valo "d_group", 3027f79cbc77SKalle Valo }; 3028f79cbc77SKalle Valo 3029f79cbc77SKalle Valo #define MAC80211_HWSIM_SSTATS_LEN ARRAY_SIZE(mac80211_hwsim_gstrings_stats) 3030f79cbc77SKalle Valo 3031f79cbc77SKalle Valo static void mac80211_hwsim_get_et_strings(struct ieee80211_hw *hw, 3032f79cbc77SKalle Valo struct ieee80211_vif *vif, 3033f79cbc77SKalle Valo u32 sset, u8 *data) 3034f79cbc77SKalle Valo { 3035f79cbc77SKalle Valo if (sset == ETH_SS_STATS) 3036f79cbc77SKalle Valo memcpy(data, *mac80211_hwsim_gstrings_stats, 3037f79cbc77SKalle Valo sizeof(mac80211_hwsim_gstrings_stats)); 3038f79cbc77SKalle Valo } 3039f79cbc77SKalle Valo 3040f79cbc77SKalle Valo static int mac80211_hwsim_get_et_sset_count(struct ieee80211_hw *hw, 3041f79cbc77SKalle Valo struct ieee80211_vif *vif, int sset) 3042f79cbc77SKalle Valo { 3043f79cbc77SKalle Valo if (sset == ETH_SS_STATS) 3044f79cbc77SKalle Valo return MAC80211_HWSIM_SSTATS_LEN; 3045f79cbc77SKalle Valo return 0; 3046f79cbc77SKalle Valo } 3047f79cbc77SKalle Valo 3048f79cbc77SKalle Valo static void mac80211_hwsim_get_et_stats(struct ieee80211_hw *hw, 3049f79cbc77SKalle Valo struct ieee80211_vif *vif, 3050f79cbc77SKalle Valo struct ethtool_stats *stats, u64 *data) 3051f79cbc77SKalle Valo { 3052f79cbc77SKalle Valo struct mac80211_hwsim_data *ar = hw->priv; 3053f79cbc77SKalle Valo int i = 0; 3054f79cbc77SKalle Valo 3055f79cbc77SKalle Valo data[i++] = ar->tx_pkts; 3056f79cbc77SKalle Valo data[i++] = ar->tx_bytes; 3057f79cbc77SKalle Valo data[i++] = ar->rx_pkts; 3058f79cbc77SKalle Valo data[i++] = ar->rx_bytes; 3059f79cbc77SKalle Valo data[i++] = ar->tx_dropped; 3060f79cbc77SKalle Valo data[i++] = ar->tx_failed; 3061f79cbc77SKalle Valo data[i++] = ar->ps; 3062f79cbc77SKalle Valo data[i++] = ar->group; 3063f79cbc77SKalle Valo 3064f79cbc77SKalle Valo WARN_ON(i != MAC80211_HWSIM_SSTATS_LEN); 3065f79cbc77SKalle Valo } 3066f79cbc77SKalle Valo 3067f79cbc77SKalle Valo static int mac80211_hwsim_tx_last_beacon(struct ieee80211_hw *hw) 3068f79cbc77SKalle Valo { 3069f79cbc77SKalle Valo return 1; 3070f79cbc77SKalle Valo } 3071f79cbc77SKalle Valo 3072f79cbc77SKalle Valo static int mac80211_hwsim_set_rts_threshold(struct ieee80211_hw *hw, u32 value) 3073f79cbc77SKalle Valo { 3074f79cbc77SKalle Valo return -EOPNOTSUPP; 3075f79cbc77SKalle Valo } 3076f79cbc77SKalle Valo 3077f79cbc77SKalle Valo static int mac80211_hwsim_change_vif_links(struct ieee80211_hw *hw, 3078f79cbc77SKalle Valo struct ieee80211_vif *vif, 3079f79cbc77SKalle Valo u16 old_links, u16 new_links, 3080f79cbc77SKalle Valo struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]) 3081f79cbc77SKalle Valo { 3082f79cbc77SKalle Valo unsigned long rem = old_links & ~new_links; 3083f79cbc77SKalle Valo unsigned long add = new_links & ~old_links; 3084f79cbc77SKalle Valo int i; 3085f79cbc77SKalle Valo 3086f79cbc77SKalle Valo if (!old_links) 3087f79cbc77SKalle Valo rem |= BIT(0); 3088f79cbc77SKalle Valo if (!new_links) 3089f79cbc77SKalle Valo add |= BIT(0); 3090f79cbc77SKalle Valo 3091f79cbc77SKalle Valo for_each_set_bit(i, &rem, IEEE80211_MLD_MAX_NUM_LINKS) 3092f79cbc77SKalle Valo mac80211_hwsim_config_mac_nl(hw, old[i]->addr, false); 3093f79cbc77SKalle Valo 3094f79cbc77SKalle Valo for_each_set_bit(i, &add, IEEE80211_MLD_MAX_NUM_LINKS) { 3095f79cbc77SKalle Valo struct ieee80211_bss_conf *link_conf; 3096f79cbc77SKalle Valo 3097f79cbc77SKalle Valo link_conf = link_conf_dereference_protected(vif, i); 3098f79cbc77SKalle Valo if (WARN_ON(!link_conf)) 3099f79cbc77SKalle Valo continue; 3100f79cbc77SKalle Valo 3101f79cbc77SKalle Valo mac80211_hwsim_config_mac_nl(hw, link_conf->addr, true); 3102f79cbc77SKalle Valo } 3103f79cbc77SKalle Valo 3104f79cbc77SKalle Valo return 0; 3105f79cbc77SKalle Valo } 3106f79cbc77SKalle Valo 3107f79cbc77SKalle Valo static int mac80211_hwsim_change_sta_links(struct ieee80211_hw *hw, 3108f79cbc77SKalle Valo struct ieee80211_vif *vif, 3109f79cbc77SKalle Valo struct ieee80211_sta *sta, 3110f79cbc77SKalle Valo u16 old_links, u16 new_links) 3111f79cbc77SKalle Valo { 3112f79cbc77SKalle Valo struct hwsim_sta_priv *sp = (void *)sta->drv_priv; 3113f79cbc77SKalle Valo 3114f79cbc77SKalle Valo hwsim_check_sta_magic(sta); 3115f79cbc77SKalle Valo 3116f79cbc77SKalle Valo if (vif->type == NL80211_IFTYPE_STATION) 3117f79cbc77SKalle Valo sp->active_links_rx = new_links; 3118f79cbc77SKalle Valo 3119f79cbc77SKalle Valo return 0; 3120f79cbc77SKalle Valo } 3121f79cbc77SKalle Valo 3122f79cbc77SKalle Valo #define HWSIM_COMMON_OPS \ 3123f79cbc77SKalle Valo .tx = mac80211_hwsim_tx, \ 3124f79cbc77SKalle Valo .wake_tx_queue = ieee80211_handle_wake_tx_queue, \ 3125f79cbc77SKalle Valo .start = mac80211_hwsim_start, \ 3126f79cbc77SKalle Valo .stop = mac80211_hwsim_stop, \ 3127f79cbc77SKalle Valo .add_interface = mac80211_hwsim_add_interface, \ 3128f79cbc77SKalle Valo .change_interface = mac80211_hwsim_change_interface, \ 3129f79cbc77SKalle Valo .remove_interface = mac80211_hwsim_remove_interface, \ 3130f79cbc77SKalle Valo .config = mac80211_hwsim_config, \ 3131f79cbc77SKalle Valo .configure_filter = mac80211_hwsim_configure_filter, \ 3132f79cbc77SKalle Valo .vif_cfg_changed = mac80211_hwsim_vif_info_changed, \ 3133f79cbc77SKalle Valo .link_info_changed = mac80211_hwsim_link_info_changed, \ 3134f79cbc77SKalle Valo .tx_last_beacon = mac80211_hwsim_tx_last_beacon, \ 3135f79cbc77SKalle Valo .sta_notify = mac80211_hwsim_sta_notify, \ 3136f79cbc77SKalle Valo .sta_rc_update = mac80211_hwsim_sta_rc_update, \ 3137f79cbc77SKalle Valo .conf_tx = mac80211_hwsim_conf_tx, \ 3138f79cbc77SKalle Valo .get_survey = mac80211_hwsim_get_survey, \ 3139f79cbc77SKalle Valo CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd) \ 3140f79cbc77SKalle Valo .ampdu_action = mac80211_hwsim_ampdu_action, \ 3141f79cbc77SKalle Valo .flush = mac80211_hwsim_flush, \ 3142f79cbc77SKalle Valo .get_et_sset_count = mac80211_hwsim_get_et_sset_count, \ 3143f79cbc77SKalle Valo .get_et_stats = mac80211_hwsim_get_et_stats, \ 3144f79cbc77SKalle Valo .get_et_strings = mac80211_hwsim_get_et_strings, 3145f79cbc77SKalle Valo 3146f79cbc77SKalle Valo #define HWSIM_NON_MLO_OPS \ 3147f79cbc77SKalle Valo .sta_add = mac80211_hwsim_sta_add, \ 3148f79cbc77SKalle Valo .sta_remove = mac80211_hwsim_sta_remove, \ 3149f79cbc77SKalle Valo .set_tim = mac80211_hwsim_set_tim, \ 3150f79cbc77SKalle Valo .get_tsf = mac80211_hwsim_get_tsf, \ 3151f79cbc77SKalle Valo .set_tsf = mac80211_hwsim_set_tsf, 3152f79cbc77SKalle Valo 3153f79cbc77SKalle Valo static const struct ieee80211_ops mac80211_hwsim_ops = { 3154f79cbc77SKalle Valo HWSIM_COMMON_OPS 3155f79cbc77SKalle Valo HWSIM_NON_MLO_OPS 3156f79cbc77SKalle Valo .sw_scan_start = mac80211_hwsim_sw_scan, 3157f79cbc77SKalle Valo .sw_scan_complete = mac80211_hwsim_sw_scan_complete, 3158f79cbc77SKalle Valo }; 3159f79cbc77SKalle Valo 3160f79cbc77SKalle Valo #define HWSIM_CHANCTX_OPS \ 3161f79cbc77SKalle Valo .hw_scan = mac80211_hwsim_hw_scan, \ 3162f79cbc77SKalle Valo .cancel_hw_scan = mac80211_hwsim_cancel_hw_scan, \ 3163f79cbc77SKalle Valo .remain_on_channel = mac80211_hwsim_roc, \ 3164f79cbc77SKalle Valo .cancel_remain_on_channel = mac80211_hwsim_croc, \ 3165f79cbc77SKalle Valo .add_chanctx = mac80211_hwsim_add_chanctx, \ 3166f79cbc77SKalle Valo .remove_chanctx = mac80211_hwsim_remove_chanctx, \ 3167f79cbc77SKalle Valo .change_chanctx = mac80211_hwsim_change_chanctx, \ 3168f79cbc77SKalle Valo .assign_vif_chanctx = mac80211_hwsim_assign_vif_chanctx,\ 3169f79cbc77SKalle Valo .unassign_vif_chanctx = mac80211_hwsim_unassign_vif_chanctx, 3170f79cbc77SKalle Valo 3171f79cbc77SKalle Valo static const struct ieee80211_ops mac80211_hwsim_mchan_ops = { 3172f79cbc77SKalle Valo HWSIM_COMMON_OPS 3173f79cbc77SKalle Valo HWSIM_NON_MLO_OPS 3174f79cbc77SKalle Valo HWSIM_CHANCTX_OPS 3175f79cbc77SKalle Valo }; 3176f79cbc77SKalle Valo 3177f79cbc77SKalle Valo static const struct ieee80211_ops mac80211_hwsim_mlo_ops = { 3178f79cbc77SKalle Valo HWSIM_COMMON_OPS 3179f79cbc77SKalle Valo HWSIM_CHANCTX_OPS 3180f79cbc77SKalle Valo .set_rts_threshold = mac80211_hwsim_set_rts_threshold, 3181f79cbc77SKalle Valo .change_vif_links = mac80211_hwsim_change_vif_links, 3182f79cbc77SKalle Valo .change_sta_links = mac80211_hwsim_change_sta_links, 3183f79cbc77SKalle Valo .sta_state = mac80211_hwsim_sta_state, 3184f79cbc77SKalle Valo }; 3185f79cbc77SKalle Valo 3186f79cbc77SKalle Valo struct hwsim_new_radio_params { 3187f79cbc77SKalle Valo unsigned int channels; 3188f79cbc77SKalle Valo const char *reg_alpha2; 3189f79cbc77SKalle Valo const struct ieee80211_regdomain *regd; 3190f79cbc77SKalle Valo bool reg_strict; 3191f79cbc77SKalle Valo bool p2p_device; 3192f79cbc77SKalle Valo bool use_chanctx; 3193f79cbc77SKalle Valo bool destroy_on_close; 3194f79cbc77SKalle Valo const char *hwname; 3195f79cbc77SKalle Valo bool no_vif; 3196f79cbc77SKalle Valo const u8 *perm_addr; 3197f79cbc77SKalle Valo u32 iftypes; 3198f79cbc77SKalle Valo u32 *ciphers; 3199f79cbc77SKalle Valo u8 n_ciphers; 3200f79cbc77SKalle Valo bool mlo; 3201f79cbc77SKalle Valo }; 3202f79cbc77SKalle Valo 3203f79cbc77SKalle Valo static void hwsim_mcast_config_msg(struct sk_buff *mcast_skb, 3204f79cbc77SKalle Valo struct genl_info *info) 3205f79cbc77SKalle Valo { 3206f79cbc77SKalle Valo if (info) 3207f79cbc77SKalle Valo genl_notify(&hwsim_genl_family, mcast_skb, info, 3208f79cbc77SKalle Valo HWSIM_MCGRP_CONFIG, GFP_KERNEL); 3209f79cbc77SKalle Valo else 3210f79cbc77SKalle Valo genlmsg_multicast(&hwsim_genl_family, mcast_skb, 0, 3211f79cbc77SKalle Valo HWSIM_MCGRP_CONFIG, GFP_KERNEL); 3212f79cbc77SKalle Valo } 3213f79cbc77SKalle Valo 3214f79cbc77SKalle Valo static int append_radio_msg(struct sk_buff *skb, int id, 3215f79cbc77SKalle Valo struct hwsim_new_radio_params *param) 3216f79cbc77SKalle Valo { 3217f79cbc77SKalle Valo int ret; 3218f79cbc77SKalle Valo 3219f79cbc77SKalle Valo ret = nla_put_u32(skb, HWSIM_ATTR_RADIO_ID, id); 3220f79cbc77SKalle Valo if (ret < 0) 3221f79cbc77SKalle Valo return ret; 3222f79cbc77SKalle Valo 3223f79cbc77SKalle Valo if (param->channels) { 3224f79cbc77SKalle Valo ret = nla_put_u32(skb, HWSIM_ATTR_CHANNELS, param->channels); 3225f79cbc77SKalle Valo if (ret < 0) 3226f79cbc77SKalle Valo return ret; 3227f79cbc77SKalle Valo } 3228f79cbc77SKalle Valo 3229f79cbc77SKalle Valo if (param->reg_alpha2) { 3230f79cbc77SKalle Valo ret = nla_put(skb, HWSIM_ATTR_REG_HINT_ALPHA2, 2, 3231f79cbc77SKalle Valo param->reg_alpha2); 3232f79cbc77SKalle Valo if (ret < 0) 3233f79cbc77SKalle Valo return ret; 3234f79cbc77SKalle Valo } 3235f79cbc77SKalle Valo 3236f79cbc77SKalle Valo if (param->regd) { 3237f79cbc77SKalle Valo int i; 3238f79cbc77SKalle Valo 3239f79cbc77SKalle Valo for (i = 0; i < ARRAY_SIZE(hwsim_world_regdom_custom); i++) { 3240f79cbc77SKalle Valo if (hwsim_world_regdom_custom[i] != param->regd) 3241f79cbc77SKalle Valo continue; 3242f79cbc77SKalle Valo 3243f79cbc77SKalle Valo ret = nla_put_u32(skb, HWSIM_ATTR_REG_CUSTOM_REG, i); 3244f79cbc77SKalle Valo if (ret < 0) 3245f79cbc77SKalle Valo return ret; 3246f79cbc77SKalle Valo break; 3247f79cbc77SKalle Valo } 3248f79cbc77SKalle Valo } 3249f79cbc77SKalle Valo 3250f79cbc77SKalle Valo if (param->reg_strict) { 3251f79cbc77SKalle Valo ret = nla_put_flag(skb, HWSIM_ATTR_REG_STRICT_REG); 3252f79cbc77SKalle Valo if (ret < 0) 3253f79cbc77SKalle Valo return ret; 3254f79cbc77SKalle Valo } 3255f79cbc77SKalle Valo 3256f79cbc77SKalle Valo if (param->p2p_device) { 3257f79cbc77SKalle Valo ret = nla_put_flag(skb, HWSIM_ATTR_SUPPORT_P2P_DEVICE); 3258f79cbc77SKalle Valo if (ret < 0) 3259f79cbc77SKalle Valo return ret; 3260f79cbc77SKalle Valo } 3261f79cbc77SKalle Valo 3262f79cbc77SKalle Valo if (param->use_chanctx) { 3263f79cbc77SKalle Valo ret = nla_put_flag(skb, HWSIM_ATTR_USE_CHANCTX); 3264f79cbc77SKalle Valo if (ret < 0) 3265f79cbc77SKalle Valo return ret; 3266f79cbc77SKalle Valo } 3267f79cbc77SKalle Valo 3268f79cbc77SKalle Valo if (param->hwname) { 3269f79cbc77SKalle Valo ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME, 3270f79cbc77SKalle Valo strlen(param->hwname), param->hwname); 3271f79cbc77SKalle Valo if (ret < 0) 3272f79cbc77SKalle Valo return ret; 3273f79cbc77SKalle Valo } 3274f79cbc77SKalle Valo 3275f79cbc77SKalle Valo return 0; 3276f79cbc77SKalle Valo } 3277f79cbc77SKalle Valo 3278f79cbc77SKalle Valo static void hwsim_mcast_new_radio(int id, struct genl_info *info, 3279f79cbc77SKalle Valo struct hwsim_new_radio_params *param) 3280f79cbc77SKalle Valo { 3281f79cbc77SKalle Valo struct sk_buff *mcast_skb; 3282f79cbc77SKalle Valo void *data; 3283f79cbc77SKalle Valo 3284f79cbc77SKalle Valo mcast_skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 3285f79cbc77SKalle Valo if (!mcast_skb) 3286f79cbc77SKalle Valo return; 3287f79cbc77SKalle Valo 3288f79cbc77SKalle Valo data = genlmsg_put(mcast_skb, 0, 0, &hwsim_genl_family, 0, 3289f79cbc77SKalle Valo HWSIM_CMD_NEW_RADIO); 3290f79cbc77SKalle Valo if (!data) 3291f79cbc77SKalle Valo goto out_err; 3292f79cbc77SKalle Valo 3293f79cbc77SKalle Valo if (append_radio_msg(mcast_skb, id, param) < 0) 3294f79cbc77SKalle Valo goto out_err; 3295f79cbc77SKalle Valo 3296f79cbc77SKalle Valo genlmsg_end(mcast_skb, data); 3297f79cbc77SKalle Valo 3298f79cbc77SKalle Valo hwsim_mcast_config_msg(mcast_skb, info); 3299f79cbc77SKalle Valo return; 3300f79cbc77SKalle Valo 3301f79cbc77SKalle Valo out_err: 3302f79cbc77SKalle Valo nlmsg_free(mcast_skb); 3303f79cbc77SKalle Valo } 3304f79cbc77SKalle Valo 3305f79cbc77SKalle Valo static const struct ieee80211_sband_iftype_data sband_capa_2ghz[] = { 3306f79cbc77SKalle Valo { 3307f79cbc77SKalle Valo .types_mask = BIT(NL80211_IFTYPE_STATION), 3308f79cbc77SKalle Valo .he_cap = { 3309f79cbc77SKalle Valo .has_he = true, 3310f79cbc77SKalle Valo .he_cap_elem = { 3311f79cbc77SKalle Valo .mac_cap_info[0] = 3312f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP0_HTC_HE, 3313f79cbc77SKalle Valo .mac_cap_info[1] = 3314f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | 3315f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 3316f79cbc77SKalle Valo .mac_cap_info[2] = 3317f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_BSR | 3318f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_MU_CASCADING | 3319f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_ACK_EN, 3320f79cbc77SKalle Valo .mac_cap_info[3] = 3321f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 3322f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 3323f79cbc77SKalle Valo .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 3324f79cbc77SKalle Valo .phy_cap_info[1] = 3325f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 3326f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 3327f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 3328f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 3329f79cbc77SKalle Valo .phy_cap_info[2] = 3330f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | 3331f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | 3332f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | 3333f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | 3334f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO, 3335f79cbc77SKalle Valo 3336f79cbc77SKalle Valo /* Leave all the other PHY capability bytes 3337f79cbc77SKalle Valo * unset, as DCM, beam forming, RU and PPE 3338f79cbc77SKalle Valo * threshold information are not supported 3339f79cbc77SKalle Valo */ 3340f79cbc77SKalle Valo }, 3341f79cbc77SKalle Valo .he_mcs_nss_supp = { 3342f79cbc77SKalle Valo .rx_mcs_80 = cpu_to_le16(0xfffa), 3343f79cbc77SKalle Valo .tx_mcs_80 = cpu_to_le16(0xfffa), 3344f79cbc77SKalle Valo .rx_mcs_160 = cpu_to_le16(0xffff), 3345f79cbc77SKalle Valo .tx_mcs_160 = cpu_to_le16(0xffff), 3346f79cbc77SKalle Valo .rx_mcs_80p80 = cpu_to_le16(0xffff), 3347f79cbc77SKalle Valo .tx_mcs_80p80 = cpu_to_le16(0xffff), 3348f79cbc77SKalle Valo }, 3349f79cbc77SKalle Valo }, 3350f79cbc77SKalle Valo .eht_cap = { 3351f79cbc77SKalle Valo .has_eht = true, 3352f79cbc77SKalle Valo .eht_cap_elem = { 3353f79cbc77SKalle Valo .mac_cap_info[0] = 3354f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | 3355f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_OM_CONTROL | 3356f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1, 3357f79cbc77SKalle Valo .phy_cap_info[0] = 3358f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | 3359f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | 3360f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | 3361f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER | 3362f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE, 3363f79cbc77SKalle Valo .phy_cap_info[3] = 3364f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | 3365f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | 3366f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | 3367f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | 3368f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | 3369f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | 3370f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK, 3371f79cbc77SKalle Valo .phy_cap_info[4] = 3372f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | 3373f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PSR_SR_SUPP | 3374f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | 3375f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI | 3376f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK, 3377f79cbc77SKalle Valo .phy_cap_info[5] = 3378f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | 3379f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP | 3380f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP | 3381f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT | 3382f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK | 3383f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK, 3384f79cbc77SKalle Valo .phy_cap_info[6] = 3385f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK | 3386f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK, 3387f79cbc77SKalle Valo .phy_cap_info[7] = 3388f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_20MHZ_STA_RX_NDP_WIDER_BW, 3389f79cbc77SKalle Valo }, 3390f79cbc77SKalle Valo 3391f79cbc77SKalle Valo /* For all MCS and bandwidth, set 8 NSS for both Tx and 3392f79cbc77SKalle Valo * Rx 3393f79cbc77SKalle Valo */ 3394f79cbc77SKalle Valo .eht_mcs_nss_supp = { 3395f79cbc77SKalle Valo /* 3396f79cbc77SKalle Valo * Since B0, B1, B2 and B3 are not set in 3397f79cbc77SKalle Valo * the supported channel width set field in the 3398f79cbc77SKalle Valo * HE PHY capabilities information field the 3399f79cbc77SKalle Valo * device is a 20MHz only device on 2.4GHz band. 3400f79cbc77SKalle Valo */ 3401f79cbc77SKalle Valo .only_20mhz = { 3402f79cbc77SKalle Valo .rx_tx_mcs7_max_nss = 0x88, 3403f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 3404f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 3405f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 3406f79cbc77SKalle Valo }, 3407f79cbc77SKalle Valo }, 3408f79cbc77SKalle Valo /* PPE threshold information is not supported */ 3409f79cbc77SKalle Valo }, 3410f79cbc77SKalle Valo }, 3411f79cbc77SKalle Valo { 3412f79cbc77SKalle Valo .types_mask = BIT(NL80211_IFTYPE_AP), 3413f79cbc77SKalle Valo .he_cap = { 3414f79cbc77SKalle Valo .has_he = true, 3415f79cbc77SKalle Valo .he_cap_elem = { 3416f79cbc77SKalle Valo .mac_cap_info[0] = 3417f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP0_HTC_HE, 3418f79cbc77SKalle Valo .mac_cap_info[1] = 3419f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | 3420f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 3421f79cbc77SKalle Valo .mac_cap_info[2] = 3422f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_BSR | 3423f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_MU_CASCADING | 3424f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_ACK_EN, 3425f79cbc77SKalle Valo .mac_cap_info[3] = 3426f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 3427f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 3428f79cbc77SKalle Valo .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 3429f79cbc77SKalle Valo .phy_cap_info[1] = 3430f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 3431f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 3432f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 3433f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 3434f79cbc77SKalle Valo .phy_cap_info[2] = 3435f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | 3436f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | 3437f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | 3438f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | 3439f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO, 3440f79cbc77SKalle Valo 3441f79cbc77SKalle Valo /* Leave all the other PHY capability bytes 3442f79cbc77SKalle Valo * unset, as DCM, beam forming, RU and PPE 3443f79cbc77SKalle Valo * threshold information are not supported 3444f79cbc77SKalle Valo */ 3445f79cbc77SKalle Valo }, 3446f79cbc77SKalle Valo .he_mcs_nss_supp = { 3447f79cbc77SKalle Valo .rx_mcs_80 = cpu_to_le16(0xfffa), 3448f79cbc77SKalle Valo .tx_mcs_80 = cpu_to_le16(0xfffa), 3449f79cbc77SKalle Valo .rx_mcs_160 = cpu_to_le16(0xffff), 3450f79cbc77SKalle Valo .tx_mcs_160 = cpu_to_le16(0xffff), 3451f79cbc77SKalle Valo .rx_mcs_80p80 = cpu_to_le16(0xffff), 3452f79cbc77SKalle Valo .tx_mcs_80p80 = cpu_to_le16(0xffff), 3453f79cbc77SKalle Valo }, 3454f79cbc77SKalle Valo }, 3455f79cbc77SKalle Valo .eht_cap = { 3456f79cbc77SKalle Valo .has_eht = true, 3457f79cbc77SKalle Valo .eht_cap_elem = { 3458f79cbc77SKalle Valo .mac_cap_info[0] = 3459f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | 3460f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_OM_CONTROL | 3461f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1, 3462f79cbc77SKalle Valo .phy_cap_info[0] = 3463f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | 3464f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | 3465f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | 3466f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER | 3467f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE, 3468f79cbc77SKalle Valo .phy_cap_info[3] = 3469f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | 3470f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | 3471f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | 3472f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | 3473f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | 3474f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | 3475f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK, 3476f79cbc77SKalle Valo .phy_cap_info[4] = 3477f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | 3478f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PSR_SR_SUPP | 3479f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | 3480f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI | 3481f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK, 3482f79cbc77SKalle Valo .phy_cap_info[5] = 3483f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | 3484f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP | 3485f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP | 3486f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT | 3487f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK | 3488f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK, 3489f79cbc77SKalle Valo .phy_cap_info[6] = 3490f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK | 3491f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK, 3492f79cbc77SKalle Valo .phy_cap_info[7] = 3493f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_20MHZ_STA_RX_NDP_WIDER_BW, 3494f79cbc77SKalle Valo }, 3495f79cbc77SKalle Valo 3496f79cbc77SKalle Valo /* For all MCS and bandwidth, set 8 NSS for both Tx and 3497f79cbc77SKalle Valo * Rx 3498f79cbc77SKalle Valo */ 3499f79cbc77SKalle Valo .eht_mcs_nss_supp = { 3500f79cbc77SKalle Valo /* 3501f79cbc77SKalle Valo * Since B0, B1, B2 and B3 are not set in 3502f79cbc77SKalle Valo * the supported channel width set field in the 3503f79cbc77SKalle Valo * HE PHY capabilities information field the 3504f79cbc77SKalle Valo * device is a 20MHz only device on 2.4GHz band. 3505f79cbc77SKalle Valo */ 3506f79cbc77SKalle Valo .only_20mhz = { 3507f79cbc77SKalle Valo .rx_tx_mcs7_max_nss = 0x88, 3508f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 3509f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 3510f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 3511f79cbc77SKalle Valo }, 3512f79cbc77SKalle Valo }, 3513f79cbc77SKalle Valo /* PPE threshold information is not supported */ 3514f79cbc77SKalle Valo }, 3515f79cbc77SKalle Valo }, 3516f79cbc77SKalle Valo #ifdef CONFIG_MAC80211_MESH 3517f79cbc77SKalle Valo { 3518f79cbc77SKalle Valo .types_mask = BIT(NL80211_IFTYPE_MESH_POINT), 3519f79cbc77SKalle Valo .he_cap = { 3520f79cbc77SKalle Valo .has_he = true, 3521f79cbc77SKalle Valo .he_cap_elem = { 3522f79cbc77SKalle Valo .mac_cap_info[0] = 3523f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP0_HTC_HE, 3524f79cbc77SKalle Valo .mac_cap_info[1] = 3525f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 3526f79cbc77SKalle Valo .mac_cap_info[2] = 3527f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_ACK_EN, 3528f79cbc77SKalle Valo .mac_cap_info[3] = 3529f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 3530f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 3531f79cbc77SKalle Valo .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 3532f79cbc77SKalle Valo .phy_cap_info[1] = 3533f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 3534f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 3535f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 3536f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 3537f79cbc77SKalle Valo .phy_cap_info[2] = 0, 3538f79cbc77SKalle Valo 3539f79cbc77SKalle Valo /* Leave all the other PHY capability bytes 3540f79cbc77SKalle Valo * unset, as DCM, beam forming, RU and PPE 3541f79cbc77SKalle Valo * threshold information are not supported 3542f79cbc77SKalle Valo */ 3543f79cbc77SKalle Valo }, 3544f79cbc77SKalle Valo .he_mcs_nss_supp = { 3545f79cbc77SKalle Valo .rx_mcs_80 = cpu_to_le16(0xfffa), 3546f79cbc77SKalle Valo .tx_mcs_80 = cpu_to_le16(0xfffa), 3547f79cbc77SKalle Valo .rx_mcs_160 = cpu_to_le16(0xffff), 3548f79cbc77SKalle Valo .tx_mcs_160 = cpu_to_le16(0xffff), 3549f79cbc77SKalle Valo .rx_mcs_80p80 = cpu_to_le16(0xffff), 3550f79cbc77SKalle Valo .tx_mcs_80p80 = cpu_to_le16(0xffff), 3551f79cbc77SKalle Valo }, 3552f79cbc77SKalle Valo }, 3553f79cbc77SKalle Valo }, 3554f79cbc77SKalle Valo #endif 3555f79cbc77SKalle Valo }; 3556f79cbc77SKalle Valo 3557f79cbc77SKalle Valo static const struct ieee80211_sband_iftype_data sband_capa_5ghz[] = { 3558f79cbc77SKalle Valo { 3559f79cbc77SKalle Valo /* TODO: should we support other types, e.g., P2P? */ 3560f79cbc77SKalle Valo .types_mask = BIT(NL80211_IFTYPE_STATION), 3561f79cbc77SKalle Valo .he_cap = { 3562f79cbc77SKalle Valo .has_he = true, 3563f79cbc77SKalle Valo .he_cap_elem = { 3564f79cbc77SKalle Valo .mac_cap_info[0] = 3565f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP0_HTC_HE, 3566f79cbc77SKalle Valo .mac_cap_info[1] = 3567f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | 3568f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 3569f79cbc77SKalle Valo .mac_cap_info[2] = 3570f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_BSR | 3571f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_MU_CASCADING | 3572f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_ACK_EN, 3573f79cbc77SKalle Valo .mac_cap_info[3] = 3574f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 3575f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 3576f79cbc77SKalle Valo .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 3577f79cbc77SKalle Valo .phy_cap_info[0] = 3578f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | 3579f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | 3580f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G, 3581f79cbc77SKalle Valo .phy_cap_info[1] = 3582f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 3583f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 3584f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 3585f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 3586f79cbc77SKalle Valo .phy_cap_info[2] = 3587f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | 3588f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | 3589f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | 3590f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | 3591f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO, 3592f79cbc77SKalle Valo 3593f79cbc77SKalle Valo /* Leave all the other PHY capability bytes 3594f79cbc77SKalle Valo * unset, as DCM, beam forming, RU and PPE 3595f79cbc77SKalle Valo * threshold information are not supported 3596f79cbc77SKalle Valo */ 3597f79cbc77SKalle Valo }, 3598f79cbc77SKalle Valo .he_mcs_nss_supp = { 3599f79cbc77SKalle Valo .rx_mcs_80 = cpu_to_le16(0xfffa), 3600f79cbc77SKalle Valo .tx_mcs_80 = cpu_to_le16(0xfffa), 3601f79cbc77SKalle Valo .rx_mcs_160 = cpu_to_le16(0xfffa), 3602f79cbc77SKalle Valo .tx_mcs_160 = cpu_to_le16(0xfffa), 3603f79cbc77SKalle Valo .rx_mcs_80p80 = cpu_to_le16(0xfffa), 3604f79cbc77SKalle Valo .tx_mcs_80p80 = cpu_to_le16(0xfffa), 3605f79cbc77SKalle Valo }, 3606f79cbc77SKalle Valo }, 3607f79cbc77SKalle Valo .eht_cap = { 3608f79cbc77SKalle Valo .has_eht = true, 3609f79cbc77SKalle Valo .eht_cap_elem = { 3610f79cbc77SKalle Valo .mac_cap_info[0] = 3611f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | 3612f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_OM_CONTROL | 3613f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1, 3614f79cbc77SKalle Valo .phy_cap_info[0] = 3615f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | 3616f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | 3617f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | 3618f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER | 3619f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE | 3620f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK, 3621f79cbc77SKalle Valo .phy_cap_info[1] = 3622f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK | 3623f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK, 3624f79cbc77SKalle Valo .phy_cap_info[2] = 3625f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_80MHZ_MASK | 3626f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK, 3627f79cbc77SKalle Valo .phy_cap_info[3] = 3628f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | 3629f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | 3630f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | 3631f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | 3632f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | 3633f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | 3634f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK, 3635f79cbc77SKalle Valo .phy_cap_info[4] = 3636f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | 3637f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PSR_SR_SUPP | 3638f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | 3639f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI | 3640f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK, 3641f79cbc77SKalle Valo .phy_cap_info[5] = 3642f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | 3643f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP | 3644f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP | 3645f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT | 3646f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK | 3647f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK, 3648f79cbc77SKalle Valo .phy_cap_info[6] = 3649f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK | 3650f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK, 3651f79cbc77SKalle Valo .phy_cap_info[7] = 3652f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_20MHZ_STA_RX_NDP_WIDER_BW | 3653f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ | 3654f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ | 3655f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ | 3656f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ, 3657f79cbc77SKalle Valo }, 3658f79cbc77SKalle Valo 3659f79cbc77SKalle Valo /* For all MCS and bandwidth, set 8 NSS for both Tx and 3660f79cbc77SKalle Valo * Rx 3661f79cbc77SKalle Valo */ 3662f79cbc77SKalle Valo .eht_mcs_nss_supp = { 3663f79cbc77SKalle Valo /* 3664f79cbc77SKalle Valo * As B1 and B2 are set in the supported 3665f79cbc77SKalle Valo * channel width set field in the HE PHY 3666f79cbc77SKalle Valo * capabilities information field include all 3667f79cbc77SKalle Valo * the following MCS/NSS. 3668f79cbc77SKalle Valo */ 3669f79cbc77SKalle Valo .bw._80 = { 3670f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 3671f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 3672f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 3673f79cbc77SKalle Valo }, 3674f79cbc77SKalle Valo .bw._160 = { 3675f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 3676f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 3677f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 3678f79cbc77SKalle Valo }, 3679f79cbc77SKalle Valo }, 3680f79cbc77SKalle Valo /* PPE threshold information is not supported */ 3681f79cbc77SKalle Valo }, 3682f79cbc77SKalle Valo }, 3683f79cbc77SKalle Valo { 3684f79cbc77SKalle Valo .types_mask = BIT(NL80211_IFTYPE_AP), 3685f79cbc77SKalle Valo .he_cap = { 3686f79cbc77SKalle Valo .has_he = true, 3687f79cbc77SKalle Valo .he_cap_elem = { 3688f79cbc77SKalle Valo .mac_cap_info[0] = 3689f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP0_HTC_HE, 3690f79cbc77SKalle Valo .mac_cap_info[1] = 3691f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | 3692f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 3693f79cbc77SKalle Valo .mac_cap_info[2] = 3694f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_BSR | 3695f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_MU_CASCADING | 3696f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_ACK_EN, 3697f79cbc77SKalle Valo .mac_cap_info[3] = 3698f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 3699f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 3700f79cbc77SKalle Valo .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 3701f79cbc77SKalle Valo .phy_cap_info[0] = 3702f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | 3703f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | 3704f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G, 3705f79cbc77SKalle Valo .phy_cap_info[1] = 3706f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 3707f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 3708f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 3709f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 3710f79cbc77SKalle Valo .phy_cap_info[2] = 3711f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | 3712f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | 3713f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | 3714f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | 3715f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO, 3716f79cbc77SKalle Valo 3717f79cbc77SKalle Valo /* Leave all the other PHY capability bytes 3718f79cbc77SKalle Valo * unset, as DCM, beam forming, RU and PPE 3719f79cbc77SKalle Valo * threshold information are not supported 3720f79cbc77SKalle Valo */ 3721f79cbc77SKalle Valo }, 3722f79cbc77SKalle Valo .he_mcs_nss_supp = { 3723f79cbc77SKalle Valo .rx_mcs_80 = cpu_to_le16(0xfffa), 3724f79cbc77SKalle Valo .tx_mcs_80 = cpu_to_le16(0xfffa), 3725f79cbc77SKalle Valo .rx_mcs_160 = cpu_to_le16(0xfffa), 3726f79cbc77SKalle Valo .tx_mcs_160 = cpu_to_le16(0xfffa), 3727f79cbc77SKalle Valo .rx_mcs_80p80 = cpu_to_le16(0xfffa), 3728f79cbc77SKalle Valo .tx_mcs_80p80 = cpu_to_le16(0xfffa), 3729f79cbc77SKalle Valo }, 3730f79cbc77SKalle Valo }, 3731f79cbc77SKalle Valo .eht_cap = { 3732f79cbc77SKalle Valo .has_eht = true, 3733f79cbc77SKalle Valo .eht_cap_elem = { 3734f79cbc77SKalle Valo .mac_cap_info[0] = 3735f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | 3736f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_OM_CONTROL | 3737f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1, 3738f79cbc77SKalle Valo .phy_cap_info[0] = 3739f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | 3740f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | 3741f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | 3742f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER | 3743f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE | 3744f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK, 3745f79cbc77SKalle Valo .phy_cap_info[1] = 3746f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK | 3747f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK, 3748f79cbc77SKalle Valo .phy_cap_info[2] = 3749f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_80MHZ_MASK | 3750f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK, 3751f79cbc77SKalle Valo .phy_cap_info[3] = 3752f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | 3753f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | 3754f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | 3755f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | 3756f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | 3757f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | 3758f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK, 3759f79cbc77SKalle Valo .phy_cap_info[4] = 3760f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | 3761f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PSR_SR_SUPP | 3762f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | 3763f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI | 3764f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK, 3765f79cbc77SKalle Valo .phy_cap_info[5] = 3766f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | 3767f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP | 3768f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP | 3769f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT | 3770f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK | 3771f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK, 3772f79cbc77SKalle Valo .phy_cap_info[6] = 3773f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK | 3774f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK, 3775f79cbc77SKalle Valo .phy_cap_info[7] = 3776f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_20MHZ_STA_RX_NDP_WIDER_BW | 3777f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ | 3778f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ | 3779f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ | 3780f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ, 3781f79cbc77SKalle Valo }, 3782f79cbc77SKalle Valo 3783f79cbc77SKalle Valo /* For all MCS and bandwidth, set 8 NSS for both Tx and 3784f79cbc77SKalle Valo * Rx 3785f79cbc77SKalle Valo */ 3786f79cbc77SKalle Valo .eht_mcs_nss_supp = { 3787f79cbc77SKalle Valo /* 3788f79cbc77SKalle Valo * As B1 and B2 are set in the supported 3789f79cbc77SKalle Valo * channel width set field in the HE PHY 3790f79cbc77SKalle Valo * capabilities information field include all 3791f79cbc77SKalle Valo * the following MCS/NSS. 3792f79cbc77SKalle Valo */ 3793f79cbc77SKalle Valo .bw._80 = { 3794f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 3795f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 3796f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 3797f79cbc77SKalle Valo }, 3798f79cbc77SKalle Valo .bw._160 = { 3799f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 3800f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 3801f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 3802f79cbc77SKalle Valo }, 3803f79cbc77SKalle Valo }, 3804f79cbc77SKalle Valo /* PPE threshold information is not supported */ 3805f79cbc77SKalle Valo }, 3806f79cbc77SKalle Valo }, 3807f79cbc77SKalle Valo #ifdef CONFIG_MAC80211_MESH 3808f79cbc77SKalle Valo { 3809f79cbc77SKalle Valo /* TODO: should we support other types, e.g., IBSS?*/ 3810f79cbc77SKalle Valo .types_mask = BIT(NL80211_IFTYPE_MESH_POINT), 3811f79cbc77SKalle Valo .he_cap = { 3812f79cbc77SKalle Valo .has_he = true, 3813f79cbc77SKalle Valo .he_cap_elem = { 3814f79cbc77SKalle Valo .mac_cap_info[0] = 3815f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP0_HTC_HE, 3816f79cbc77SKalle Valo .mac_cap_info[1] = 3817f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 3818f79cbc77SKalle Valo .mac_cap_info[2] = 3819f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_ACK_EN, 3820f79cbc77SKalle Valo .mac_cap_info[3] = 3821f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 3822f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 3823f79cbc77SKalle Valo .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 3824f79cbc77SKalle Valo .phy_cap_info[0] = 3825f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | 3826f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | 3827f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G, 3828f79cbc77SKalle Valo .phy_cap_info[1] = 3829f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 3830f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 3831f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 3832f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 3833f79cbc77SKalle Valo .phy_cap_info[2] = 0, 3834f79cbc77SKalle Valo 3835f79cbc77SKalle Valo /* Leave all the other PHY capability bytes 3836f79cbc77SKalle Valo * unset, as DCM, beam forming, RU and PPE 3837f79cbc77SKalle Valo * threshold information are not supported 3838f79cbc77SKalle Valo */ 3839f79cbc77SKalle Valo }, 3840f79cbc77SKalle Valo .he_mcs_nss_supp = { 3841f79cbc77SKalle Valo .rx_mcs_80 = cpu_to_le16(0xfffa), 3842f79cbc77SKalle Valo .tx_mcs_80 = cpu_to_le16(0xfffa), 3843f79cbc77SKalle Valo .rx_mcs_160 = cpu_to_le16(0xfffa), 3844f79cbc77SKalle Valo .tx_mcs_160 = cpu_to_le16(0xfffa), 3845f79cbc77SKalle Valo .rx_mcs_80p80 = cpu_to_le16(0xfffa), 3846f79cbc77SKalle Valo .tx_mcs_80p80 = cpu_to_le16(0xfffa), 3847f79cbc77SKalle Valo }, 3848f79cbc77SKalle Valo }, 3849f79cbc77SKalle Valo }, 3850f79cbc77SKalle Valo #endif 3851f79cbc77SKalle Valo }; 3852f79cbc77SKalle Valo 3853f79cbc77SKalle Valo static const struct ieee80211_sband_iftype_data sband_capa_6ghz[] = { 3854f79cbc77SKalle Valo { 3855f79cbc77SKalle Valo /* TODO: should we support other types, e.g., P2P? */ 3856f79cbc77SKalle Valo .types_mask = BIT(NL80211_IFTYPE_STATION), 3857f79cbc77SKalle Valo .he_6ghz_capa = { 3858f79cbc77SKalle Valo .capa = cpu_to_le16(IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START | 3859f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP | 3860f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN | 3861f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_SM_PS | 3862f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_RD_RESPONDER | 3863f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS | 3864f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS), 3865f79cbc77SKalle Valo }, 3866f79cbc77SKalle Valo .he_cap = { 3867f79cbc77SKalle Valo .has_he = true, 3868f79cbc77SKalle Valo .he_cap_elem = { 3869f79cbc77SKalle Valo .mac_cap_info[0] = 3870f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP0_HTC_HE, 3871f79cbc77SKalle Valo .mac_cap_info[1] = 3872f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | 3873f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 3874f79cbc77SKalle Valo .mac_cap_info[2] = 3875f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_BSR | 3876f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_MU_CASCADING | 3877f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_ACK_EN, 3878f79cbc77SKalle Valo .mac_cap_info[3] = 3879f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 3880f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 3881f79cbc77SKalle Valo .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 3882f79cbc77SKalle Valo .phy_cap_info[0] = 3883f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | 3884f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | 3885f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G, 3886f79cbc77SKalle Valo .phy_cap_info[1] = 3887f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 3888f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 3889f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 3890f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 3891f79cbc77SKalle Valo .phy_cap_info[2] = 3892f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | 3893f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | 3894f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | 3895f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | 3896f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO, 3897f79cbc77SKalle Valo 3898f79cbc77SKalle Valo /* Leave all the other PHY capability bytes 3899f79cbc77SKalle Valo * unset, as DCM, beam forming, RU and PPE 3900f79cbc77SKalle Valo * threshold information are not supported 3901f79cbc77SKalle Valo */ 3902f79cbc77SKalle Valo }, 3903f79cbc77SKalle Valo .he_mcs_nss_supp = { 3904f79cbc77SKalle Valo .rx_mcs_80 = cpu_to_le16(0xfffa), 3905f79cbc77SKalle Valo .tx_mcs_80 = cpu_to_le16(0xfffa), 3906f79cbc77SKalle Valo .rx_mcs_160 = cpu_to_le16(0xfffa), 3907f79cbc77SKalle Valo .tx_mcs_160 = cpu_to_le16(0xfffa), 3908f79cbc77SKalle Valo .rx_mcs_80p80 = cpu_to_le16(0xfffa), 3909f79cbc77SKalle Valo .tx_mcs_80p80 = cpu_to_le16(0xfffa), 3910f79cbc77SKalle Valo }, 3911f79cbc77SKalle Valo }, 3912f79cbc77SKalle Valo .eht_cap = { 3913f79cbc77SKalle Valo .has_eht = true, 3914f79cbc77SKalle Valo .eht_cap_elem = { 3915f79cbc77SKalle Valo .mac_cap_info[0] = 3916f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | 3917f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_OM_CONTROL | 3918f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1, 3919f79cbc77SKalle Valo .phy_cap_info[0] = 3920f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ | 3921f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | 3922f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | 3923f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | 3924f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER | 3925f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE | 3926f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK, 3927f79cbc77SKalle Valo .phy_cap_info[1] = 3928f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK | 3929f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK | 3930f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK, 3931f79cbc77SKalle Valo .phy_cap_info[2] = 3932f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_80MHZ_MASK | 3933f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK | 3934f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_320MHZ_MASK, 3935f79cbc77SKalle Valo .phy_cap_info[3] = 3936f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | 3937f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | 3938f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | 3939f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | 3940f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | 3941f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | 3942f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK, 3943f79cbc77SKalle Valo .phy_cap_info[4] = 3944f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | 3945f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PSR_SR_SUPP | 3946f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | 3947f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI | 3948f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK, 3949f79cbc77SKalle Valo .phy_cap_info[5] = 3950f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | 3951f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP | 3952f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP | 3953f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT | 3954f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK | 3955f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK, 3956f79cbc77SKalle Valo .phy_cap_info[6] = 3957f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK | 3958f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK | 3959f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_EHT_DUP_6GHZ_SUPP, 3960f79cbc77SKalle Valo .phy_cap_info[7] = 3961f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_20MHZ_STA_RX_NDP_WIDER_BW | 3962f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ | 3963f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ | 3964f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_320MHZ | 3965f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ | 3966f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ | 3967f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_320MHZ, 3968f79cbc77SKalle Valo }, 3969f79cbc77SKalle Valo 3970f79cbc77SKalle Valo /* For all MCS and bandwidth, set 8 NSS for both Tx and 3971f79cbc77SKalle Valo * Rx 3972f79cbc77SKalle Valo */ 3973f79cbc77SKalle Valo .eht_mcs_nss_supp = { 3974f79cbc77SKalle Valo /* 3975f79cbc77SKalle Valo * As B1 and B2 are set in the supported 3976f79cbc77SKalle Valo * channel width set field in the HE PHY 3977f79cbc77SKalle Valo * capabilities information field and 320MHz in 3978f79cbc77SKalle Valo * 6GHz is supported include all the following 3979f79cbc77SKalle Valo * MCS/NSS. 3980f79cbc77SKalle Valo */ 3981f79cbc77SKalle Valo .bw._80 = { 3982f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 3983f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 3984f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 3985f79cbc77SKalle Valo }, 3986f79cbc77SKalle Valo .bw._160 = { 3987f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 3988f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 3989f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 3990f79cbc77SKalle Valo }, 3991f79cbc77SKalle Valo .bw._320 = { 3992f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 3993f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 3994f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 3995f79cbc77SKalle Valo }, 3996f79cbc77SKalle Valo }, 3997f79cbc77SKalle Valo /* PPE threshold information is not supported */ 3998f79cbc77SKalle Valo }, 3999f79cbc77SKalle Valo }, 4000f79cbc77SKalle Valo { 4001f79cbc77SKalle Valo .types_mask = BIT(NL80211_IFTYPE_AP), 4002f79cbc77SKalle Valo .he_6ghz_capa = { 4003f79cbc77SKalle Valo .capa = cpu_to_le16(IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START | 4004f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP | 4005f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN | 4006f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_SM_PS | 4007f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_RD_RESPONDER | 4008f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS | 4009f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS), 4010f79cbc77SKalle Valo }, 4011f79cbc77SKalle Valo .he_cap = { 4012f79cbc77SKalle Valo .has_he = true, 4013f79cbc77SKalle Valo .he_cap_elem = { 4014f79cbc77SKalle Valo .mac_cap_info[0] = 4015f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP0_HTC_HE, 4016f79cbc77SKalle Valo .mac_cap_info[1] = 4017f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | 4018f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 4019f79cbc77SKalle Valo .mac_cap_info[2] = 4020f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_BSR | 4021f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_MU_CASCADING | 4022f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_ACK_EN, 4023f79cbc77SKalle Valo .mac_cap_info[3] = 4024f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 4025f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 4026f79cbc77SKalle Valo .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 4027f79cbc77SKalle Valo .phy_cap_info[0] = 4028f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | 4029f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | 4030f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G, 4031f79cbc77SKalle Valo .phy_cap_info[1] = 4032f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 4033f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 4034f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 4035f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 4036f79cbc77SKalle Valo .phy_cap_info[2] = 4037f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | 4038f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | 4039f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | 4040f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | 4041f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO, 4042f79cbc77SKalle Valo 4043f79cbc77SKalle Valo /* Leave all the other PHY capability bytes 4044f79cbc77SKalle Valo * unset, as DCM, beam forming, RU and PPE 4045f79cbc77SKalle Valo * threshold information are not supported 4046f79cbc77SKalle Valo */ 4047f79cbc77SKalle Valo }, 4048f79cbc77SKalle Valo .he_mcs_nss_supp = { 4049f79cbc77SKalle Valo .rx_mcs_80 = cpu_to_le16(0xfffa), 4050f79cbc77SKalle Valo .tx_mcs_80 = cpu_to_le16(0xfffa), 4051f79cbc77SKalle Valo .rx_mcs_160 = cpu_to_le16(0xfffa), 4052f79cbc77SKalle Valo .tx_mcs_160 = cpu_to_le16(0xfffa), 4053f79cbc77SKalle Valo .rx_mcs_80p80 = cpu_to_le16(0xfffa), 4054f79cbc77SKalle Valo .tx_mcs_80p80 = cpu_to_le16(0xfffa), 4055f79cbc77SKalle Valo }, 4056f79cbc77SKalle Valo }, 4057f79cbc77SKalle Valo .eht_cap = { 4058f79cbc77SKalle Valo .has_eht = true, 4059f79cbc77SKalle Valo .eht_cap_elem = { 4060f79cbc77SKalle Valo .mac_cap_info[0] = 4061f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | 4062f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_OM_CONTROL | 4063f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1, 4064f79cbc77SKalle Valo .phy_cap_info[0] = 4065f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ | 4066f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | 4067f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | 4068f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | 4069f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER | 4070f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE | 4071f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK, 4072f79cbc77SKalle Valo .phy_cap_info[1] = 4073f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK | 4074f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK | 4075f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK, 4076f79cbc77SKalle Valo .phy_cap_info[2] = 4077f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_80MHZ_MASK | 4078f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK | 4079f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_320MHZ_MASK, 4080f79cbc77SKalle Valo .phy_cap_info[3] = 4081f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | 4082f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | 4083f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | 4084f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | 4085f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | 4086f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | 4087f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK, 4088f79cbc77SKalle Valo .phy_cap_info[4] = 4089f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | 4090f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PSR_SR_SUPP | 4091f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | 4092f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI | 4093f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK, 4094f79cbc77SKalle Valo .phy_cap_info[5] = 4095f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | 4096f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP | 4097f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP | 4098f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT | 4099f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK | 4100f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK, 4101f79cbc77SKalle Valo .phy_cap_info[6] = 4102f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK | 4103f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK | 4104f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_EHT_DUP_6GHZ_SUPP, 4105f79cbc77SKalle Valo .phy_cap_info[7] = 4106f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_20MHZ_STA_RX_NDP_WIDER_BW | 4107f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ | 4108f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ | 4109f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_320MHZ | 4110f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ | 4111f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ | 4112f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_320MHZ, 4113f79cbc77SKalle Valo }, 4114f79cbc77SKalle Valo 4115f79cbc77SKalle Valo /* For all MCS and bandwidth, set 8 NSS for both Tx and 4116f79cbc77SKalle Valo * Rx 4117f79cbc77SKalle Valo */ 4118f79cbc77SKalle Valo .eht_mcs_nss_supp = { 4119f79cbc77SKalle Valo /* 4120f79cbc77SKalle Valo * As B1 and B2 are set in the supported 4121f79cbc77SKalle Valo * channel width set field in the HE PHY 4122f79cbc77SKalle Valo * capabilities information field and 320MHz in 4123f79cbc77SKalle Valo * 6GHz is supported include all the following 4124f79cbc77SKalle Valo * MCS/NSS. 4125f79cbc77SKalle Valo */ 4126f79cbc77SKalle Valo .bw._80 = { 4127f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 4128f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 4129f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 4130f79cbc77SKalle Valo }, 4131f79cbc77SKalle Valo .bw._160 = { 4132f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 4133f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 4134f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 4135f79cbc77SKalle Valo }, 4136f79cbc77SKalle Valo .bw._320 = { 4137f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 4138f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 4139f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 4140f79cbc77SKalle Valo }, 4141f79cbc77SKalle Valo }, 4142f79cbc77SKalle Valo /* PPE threshold information is not supported */ 4143f79cbc77SKalle Valo }, 4144f79cbc77SKalle Valo }, 4145f79cbc77SKalle Valo #ifdef CONFIG_MAC80211_MESH 4146f79cbc77SKalle Valo { 4147f79cbc77SKalle Valo /* TODO: should we support other types, e.g., IBSS?*/ 4148f79cbc77SKalle Valo .types_mask = BIT(NL80211_IFTYPE_MESH_POINT), 4149f79cbc77SKalle Valo .he_6ghz_capa = { 4150f79cbc77SKalle Valo .capa = cpu_to_le16(IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START | 4151f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP | 4152f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN | 4153f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_SM_PS | 4154f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_RD_RESPONDER | 4155f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS | 4156f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS), 4157f79cbc77SKalle Valo }, 4158f79cbc77SKalle Valo .he_cap = { 4159f79cbc77SKalle Valo .has_he = true, 4160f79cbc77SKalle Valo .he_cap_elem = { 4161f79cbc77SKalle Valo .mac_cap_info[0] = 4162f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP0_HTC_HE, 4163f79cbc77SKalle Valo .mac_cap_info[1] = 4164f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 4165f79cbc77SKalle Valo .mac_cap_info[2] = 4166f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_ACK_EN, 4167f79cbc77SKalle Valo .mac_cap_info[3] = 4168f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 4169f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 4170f79cbc77SKalle Valo .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 4171f79cbc77SKalle Valo .phy_cap_info[0] = 4172f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | 4173f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | 4174f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G, 4175f79cbc77SKalle Valo .phy_cap_info[1] = 4176f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 4177f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 4178f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 4179f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 4180f79cbc77SKalle Valo .phy_cap_info[2] = 0, 4181f79cbc77SKalle Valo 4182f79cbc77SKalle Valo /* Leave all the other PHY capability bytes 4183f79cbc77SKalle Valo * unset, as DCM, beam forming, RU and PPE 4184f79cbc77SKalle Valo * threshold information are not supported 4185f79cbc77SKalle Valo */ 4186f79cbc77SKalle Valo }, 4187f79cbc77SKalle Valo .he_mcs_nss_supp = { 4188f79cbc77SKalle Valo .rx_mcs_80 = cpu_to_le16(0xfffa), 4189f79cbc77SKalle Valo .tx_mcs_80 = cpu_to_le16(0xfffa), 4190f79cbc77SKalle Valo .rx_mcs_160 = cpu_to_le16(0xfffa), 4191f79cbc77SKalle Valo .tx_mcs_160 = cpu_to_le16(0xfffa), 4192f79cbc77SKalle Valo .rx_mcs_80p80 = cpu_to_le16(0xfffa), 4193f79cbc77SKalle Valo .tx_mcs_80p80 = cpu_to_le16(0xfffa), 4194f79cbc77SKalle Valo }, 4195f79cbc77SKalle Valo }, 4196f79cbc77SKalle Valo }, 4197f79cbc77SKalle Valo #endif 4198f79cbc77SKalle Valo }; 4199f79cbc77SKalle Valo 4200f79cbc77SKalle Valo static void mac80211_hwsim_sband_capab(struct ieee80211_supported_band *sband) 4201f79cbc77SKalle Valo { 4202f79cbc77SKalle Valo u16 n_iftype_data; 4203f79cbc77SKalle Valo 4204f79cbc77SKalle Valo if (sband->band == NL80211_BAND_2GHZ) { 4205f79cbc77SKalle Valo n_iftype_data = ARRAY_SIZE(sband_capa_2ghz); 4206f79cbc77SKalle Valo sband->iftype_data = 4207f79cbc77SKalle Valo (struct ieee80211_sband_iftype_data *)sband_capa_2ghz; 4208f79cbc77SKalle Valo } else if (sband->band == NL80211_BAND_5GHZ) { 4209f79cbc77SKalle Valo n_iftype_data = ARRAY_SIZE(sband_capa_5ghz); 4210f79cbc77SKalle Valo sband->iftype_data = 4211f79cbc77SKalle Valo (struct ieee80211_sband_iftype_data *)sband_capa_5ghz; 4212f79cbc77SKalle Valo } else if (sband->band == NL80211_BAND_6GHZ) { 4213f79cbc77SKalle Valo n_iftype_data = ARRAY_SIZE(sband_capa_6ghz); 4214f79cbc77SKalle Valo sband->iftype_data = 4215f79cbc77SKalle Valo (struct ieee80211_sband_iftype_data *)sband_capa_6ghz; 4216f79cbc77SKalle Valo } else { 4217f79cbc77SKalle Valo return; 4218f79cbc77SKalle Valo } 4219f79cbc77SKalle Valo 4220f79cbc77SKalle Valo sband->n_iftype_data = n_iftype_data; 4221f79cbc77SKalle Valo } 4222f79cbc77SKalle Valo 4223f79cbc77SKalle Valo #ifdef CONFIG_MAC80211_MESH 4224f79cbc77SKalle Valo #define HWSIM_MESH_BIT BIT(NL80211_IFTYPE_MESH_POINT) 4225f79cbc77SKalle Valo #else 4226f79cbc77SKalle Valo #define HWSIM_MESH_BIT 0 4227f79cbc77SKalle Valo #endif 4228f79cbc77SKalle Valo 4229f79cbc77SKalle Valo #define HWSIM_DEFAULT_IF_LIMIT \ 4230f79cbc77SKalle Valo (BIT(NL80211_IFTYPE_STATION) | \ 4231f79cbc77SKalle Valo BIT(NL80211_IFTYPE_P2P_CLIENT) | \ 4232f79cbc77SKalle Valo BIT(NL80211_IFTYPE_AP) | \ 4233f79cbc77SKalle Valo BIT(NL80211_IFTYPE_P2P_GO) | \ 4234f79cbc77SKalle Valo HWSIM_MESH_BIT) 4235f79cbc77SKalle Valo 4236f79cbc77SKalle Valo #define HWSIM_IFTYPE_SUPPORT_MASK \ 4237f79cbc77SKalle Valo (BIT(NL80211_IFTYPE_STATION) | \ 4238f79cbc77SKalle Valo BIT(NL80211_IFTYPE_AP) | \ 4239f79cbc77SKalle Valo BIT(NL80211_IFTYPE_P2P_CLIENT) | \ 4240f79cbc77SKalle Valo BIT(NL80211_IFTYPE_P2P_GO) | \ 4241f79cbc77SKalle Valo BIT(NL80211_IFTYPE_ADHOC) | \ 4242f79cbc77SKalle Valo BIT(NL80211_IFTYPE_MESH_POINT) | \ 4243f79cbc77SKalle Valo BIT(NL80211_IFTYPE_OCB)) 4244f79cbc77SKalle Valo 4245f79cbc77SKalle Valo static int mac80211_hwsim_new_radio(struct genl_info *info, 4246f79cbc77SKalle Valo struct hwsim_new_radio_params *param) 4247f79cbc77SKalle Valo { 4248f79cbc77SKalle Valo int err; 4249f79cbc77SKalle Valo u8 addr[ETH_ALEN]; 4250f79cbc77SKalle Valo struct mac80211_hwsim_data *data; 4251f79cbc77SKalle Valo struct ieee80211_hw *hw; 4252f79cbc77SKalle Valo enum nl80211_band band; 4253f79cbc77SKalle Valo const struct ieee80211_ops *ops = &mac80211_hwsim_ops; 4254f79cbc77SKalle Valo struct net *net; 4255f79cbc77SKalle Valo int idx, i; 4256f79cbc77SKalle Valo int n_limits = 0; 4257f79cbc77SKalle Valo 4258f79cbc77SKalle Valo if (WARN_ON(param->channels > 1 && !param->use_chanctx)) 4259f79cbc77SKalle Valo return -EINVAL; 4260f79cbc77SKalle Valo 4261f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 4262f79cbc77SKalle Valo idx = hwsim_radio_idx++; 4263f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 4264f79cbc77SKalle Valo 4265f79cbc77SKalle Valo if (param->mlo) 4266f79cbc77SKalle Valo ops = &mac80211_hwsim_mlo_ops; 4267f79cbc77SKalle Valo else if (param->use_chanctx) 4268f79cbc77SKalle Valo ops = &mac80211_hwsim_mchan_ops; 4269f79cbc77SKalle Valo hw = ieee80211_alloc_hw_nm(sizeof(*data), ops, param->hwname); 4270f79cbc77SKalle Valo if (!hw) { 4271f79cbc77SKalle Valo pr_debug("mac80211_hwsim: ieee80211_alloc_hw failed\n"); 4272f79cbc77SKalle Valo err = -ENOMEM; 4273f79cbc77SKalle Valo goto failed; 4274f79cbc77SKalle Valo } 4275f79cbc77SKalle Valo 4276f79cbc77SKalle Valo /* ieee80211_alloc_hw_nm may have used a default name */ 4277f79cbc77SKalle Valo param->hwname = wiphy_name(hw->wiphy); 4278f79cbc77SKalle Valo 4279f79cbc77SKalle Valo if (info) 4280f79cbc77SKalle Valo net = genl_info_net(info); 4281f79cbc77SKalle Valo else 4282f79cbc77SKalle Valo net = &init_net; 4283f79cbc77SKalle Valo wiphy_net_set(hw->wiphy, net); 4284f79cbc77SKalle Valo 4285f79cbc77SKalle Valo data = hw->priv; 4286f79cbc77SKalle Valo data->hw = hw; 4287f79cbc77SKalle Valo 4288f79cbc77SKalle Valo data->dev = device_create(hwsim_class, NULL, 0, hw, "hwsim%d", idx); 4289f79cbc77SKalle Valo if (IS_ERR(data->dev)) { 4290f79cbc77SKalle Valo printk(KERN_DEBUG 4291f79cbc77SKalle Valo "mac80211_hwsim: device_create failed (%ld)\n", 4292f79cbc77SKalle Valo PTR_ERR(data->dev)); 4293f79cbc77SKalle Valo err = -ENOMEM; 4294f79cbc77SKalle Valo goto failed_drvdata; 4295f79cbc77SKalle Valo } 4296f79cbc77SKalle Valo data->dev->driver = &mac80211_hwsim_driver.driver; 4297f79cbc77SKalle Valo err = device_bind_driver(data->dev); 4298f79cbc77SKalle Valo if (err != 0) { 4299f79cbc77SKalle Valo pr_debug("mac80211_hwsim: device_bind_driver failed (%d)\n", 4300f79cbc77SKalle Valo err); 4301f79cbc77SKalle Valo goto failed_bind; 4302f79cbc77SKalle Valo } 4303f79cbc77SKalle Valo 4304f79cbc77SKalle Valo skb_queue_head_init(&data->pending); 4305f79cbc77SKalle Valo 4306f79cbc77SKalle Valo SET_IEEE80211_DEV(hw, data->dev); 4307f79cbc77SKalle Valo if (!param->perm_addr) { 4308f79cbc77SKalle Valo eth_zero_addr(addr); 4309f79cbc77SKalle Valo addr[0] = 0x02; 4310f79cbc77SKalle Valo addr[3] = idx >> 8; 4311f79cbc77SKalle Valo addr[4] = idx; 4312f79cbc77SKalle Valo memcpy(data->addresses[0].addr, addr, ETH_ALEN); 4313f79cbc77SKalle Valo /* Why need here second address ? */ 4314f79cbc77SKalle Valo memcpy(data->addresses[1].addr, addr, ETH_ALEN); 4315f79cbc77SKalle Valo data->addresses[1].addr[0] |= 0x40; 4316f79cbc77SKalle Valo hw->wiphy->n_addresses = 2; 4317f79cbc77SKalle Valo hw->wiphy->addresses = data->addresses; 4318f79cbc77SKalle Valo /* possible address clash is checked at hash table insertion */ 4319f79cbc77SKalle Valo } else { 4320f79cbc77SKalle Valo memcpy(data->addresses[0].addr, param->perm_addr, ETH_ALEN); 4321f79cbc77SKalle Valo /* compatibility with automatically generated mac addr */ 4322f79cbc77SKalle Valo memcpy(data->addresses[1].addr, param->perm_addr, ETH_ALEN); 4323f79cbc77SKalle Valo hw->wiphy->n_addresses = 2; 4324f79cbc77SKalle Valo hw->wiphy->addresses = data->addresses; 4325f79cbc77SKalle Valo } 4326f79cbc77SKalle Valo 4327f79cbc77SKalle Valo data->channels = param->channels; 4328f79cbc77SKalle Valo data->use_chanctx = param->use_chanctx; 4329f79cbc77SKalle Valo data->idx = idx; 4330f79cbc77SKalle Valo data->destroy_on_close = param->destroy_on_close; 4331f79cbc77SKalle Valo if (info) 4332f79cbc77SKalle Valo data->portid = info->snd_portid; 4333f79cbc77SKalle Valo 4334f79cbc77SKalle Valo /* setup interface limits, only on interface types we support */ 4335f79cbc77SKalle Valo if (param->iftypes & BIT(NL80211_IFTYPE_ADHOC)) { 4336f79cbc77SKalle Valo data->if_limits[n_limits].max = 1; 4337f79cbc77SKalle Valo data->if_limits[n_limits].types = BIT(NL80211_IFTYPE_ADHOC); 4338f79cbc77SKalle Valo n_limits++; 4339f79cbc77SKalle Valo } 4340f79cbc77SKalle Valo 4341f79cbc77SKalle Valo if (param->iftypes & HWSIM_DEFAULT_IF_LIMIT) { 4342f79cbc77SKalle Valo data->if_limits[n_limits].max = 2048; 4343f79cbc77SKalle Valo /* 4344f79cbc77SKalle Valo * For this case, we may only support a subset of 4345f79cbc77SKalle Valo * HWSIM_DEFAULT_IF_LIMIT, therefore we only want to add the 4346f79cbc77SKalle Valo * bits that both param->iftype & HWSIM_DEFAULT_IF_LIMIT have. 4347f79cbc77SKalle Valo */ 4348f79cbc77SKalle Valo data->if_limits[n_limits].types = 4349f79cbc77SKalle Valo HWSIM_DEFAULT_IF_LIMIT & param->iftypes; 4350f79cbc77SKalle Valo n_limits++; 4351f79cbc77SKalle Valo } 4352f79cbc77SKalle Valo 4353f79cbc77SKalle Valo if (param->iftypes & BIT(NL80211_IFTYPE_P2P_DEVICE)) { 4354f79cbc77SKalle Valo data->if_limits[n_limits].max = 1; 4355f79cbc77SKalle Valo data->if_limits[n_limits].types = 4356f79cbc77SKalle Valo BIT(NL80211_IFTYPE_P2P_DEVICE); 4357f79cbc77SKalle Valo n_limits++; 4358f79cbc77SKalle Valo } 4359f79cbc77SKalle Valo 4360f79cbc77SKalle Valo if (data->use_chanctx) { 4361f79cbc77SKalle Valo hw->wiphy->max_scan_ssids = 255; 4362f79cbc77SKalle Valo hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; 4363f79cbc77SKalle Valo hw->wiphy->max_remain_on_channel_duration = 1000; 4364f79cbc77SKalle Valo data->if_combination.radar_detect_widths = 0; 4365f79cbc77SKalle Valo data->if_combination.num_different_channels = data->channels; 4366f79cbc77SKalle Valo } else { 4367f79cbc77SKalle Valo data->if_combination.num_different_channels = 1; 4368f79cbc77SKalle Valo data->if_combination.radar_detect_widths = 4369f79cbc77SKalle Valo BIT(NL80211_CHAN_WIDTH_5) | 4370f79cbc77SKalle Valo BIT(NL80211_CHAN_WIDTH_10) | 4371f79cbc77SKalle Valo BIT(NL80211_CHAN_WIDTH_20_NOHT) | 4372f79cbc77SKalle Valo BIT(NL80211_CHAN_WIDTH_20) | 4373f79cbc77SKalle Valo BIT(NL80211_CHAN_WIDTH_40) | 4374f79cbc77SKalle Valo BIT(NL80211_CHAN_WIDTH_80) | 4375f79cbc77SKalle Valo BIT(NL80211_CHAN_WIDTH_160); 4376f79cbc77SKalle Valo } 4377f79cbc77SKalle Valo 4378f79cbc77SKalle Valo if (!n_limits) { 4379f79cbc77SKalle Valo err = -EINVAL; 4380f79cbc77SKalle Valo goto failed_hw; 4381f79cbc77SKalle Valo } 4382f79cbc77SKalle Valo 4383f79cbc77SKalle Valo data->if_combination.max_interfaces = 0; 4384f79cbc77SKalle Valo for (i = 0; i < n_limits; i++) 4385f79cbc77SKalle Valo data->if_combination.max_interfaces += 4386f79cbc77SKalle Valo data->if_limits[i].max; 4387f79cbc77SKalle Valo 4388f79cbc77SKalle Valo data->if_combination.n_limits = n_limits; 4389f79cbc77SKalle Valo data->if_combination.limits = data->if_limits; 4390f79cbc77SKalle Valo 4391f79cbc77SKalle Valo /* 4392f79cbc77SKalle Valo * If we actually were asked to support combinations, 4393f79cbc77SKalle Valo * advertise them - if there's only a single thing like 4394f79cbc77SKalle Valo * only IBSS then don't advertise it as combinations. 4395f79cbc77SKalle Valo */ 4396f79cbc77SKalle Valo if (data->if_combination.max_interfaces > 1) { 4397f79cbc77SKalle Valo hw->wiphy->iface_combinations = &data->if_combination; 4398f79cbc77SKalle Valo hw->wiphy->n_iface_combinations = 1; 4399f79cbc77SKalle Valo } 4400f79cbc77SKalle Valo 4401f79cbc77SKalle Valo if (param->ciphers) { 4402f79cbc77SKalle Valo memcpy(data->ciphers, param->ciphers, 4403f79cbc77SKalle Valo param->n_ciphers * sizeof(u32)); 4404f79cbc77SKalle Valo hw->wiphy->cipher_suites = data->ciphers; 4405f79cbc77SKalle Valo hw->wiphy->n_cipher_suites = param->n_ciphers; 4406f79cbc77SKalle Valo } 4407f79cbc77SKalle Valo 4408f79cbc77SKalle Valo data->rx_rssi = DEFAULT_RX_RSSI; 4409f79cbc77SKalle Valo 4410f79cbc77SKalle Valo INIT_DELAYED_WORK(&data->roc_start, hw_roc_start); 4411f79cbc77SKalle Valo INIT_DELAYED_WORK(&data->roc_done, hw_roc_done); 4412f79cbc77SKalle Valo INIT_DELAYED_WORK(&data->hw_scan, hw_scan_work); 4413f79cbc77SKalle Valo 4414f79cbc77SKalle Valo hw->queues = 5; 4415f79cbc77SKalle Valo hw->offchannel_tx_hw_queue = 4; 4416f79cbc77SKalle Valo 4417f79cbc77SKalle Valo ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); 4418f79cbc77SKalle Valo ieee80211_hw_set(hw, CHANCTX_STA_CSA); 4419f79cbc77SKalle Valo ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); 4420f79cbc77SKalle Valo ieee80211_hw_set(hw, QUEUE_CONTROL); 4421f79cbc77SKalle Valo ieee80211_hw_set(hw, WANT_MONITOR_VIF); 4422f79cbc77SKalle Valo ieee80211_hw_set(hw, AMPDU_AGGREGATION); 4423f79cbc77SKalle Valo ieee80211_hw_set(hw, MFP_CAPABLE); 4424f79cbc77SKalle Valo ieee80211_hw_set(hw, SIGNAL_DBM); 4425f79cbc77SKalle Valo ieee80211_hw_set(hw, SUPPORTS_PS); 4426f79cbc77SKalle Valo ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); 4427f79cbc77SKalle Valo ieee80211_hw_set(hw, TDLS_WIDER_BW); 4428f79cbc77SKalle Valo ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); 4429f79cbc77SKalle Valo 4430f79cbc77SKalle Valo if (param->mlo) { 4431f79cbc77SKalle Valo hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_MLO; 4432f79cbc77SKalle Valo ieee80211_hw_set(hw, HAS_RATE_CONTROL); 4433f79cbc77SKalle Valo ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); 4434f79cbc77SKalle Valo ieee80211_hw_set(hw, CONNECTION_MONITOR); 4435f79cbc77SKalle Valo ieee80211_hw_set(hw, AP_LINK_PS); 4436f79cbc77SKalle Valo } else { 4437f79cbc77SKalle Valo ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); 4438f79cbc77SKalle Valo ieee80211_hw_set(hw, PS_NULLFUNC_STACK); 4439f79cbc77SKalle Valo if (rctbl) 4440f79cbc77SKalle Valo ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); 4441f79cbc77SKalle Valo } 4442f79cbc77SKalle Valo 4443f79cbc77SKalle Valo hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; 4444f79cbc77SKalle Valo hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | 4445f79cbc77SKalle Valo WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | 4446f79cbc77SKalle Valo WIPHY_FLAG_AP_UAPSD | 4447f79cbc77SKalle Valo WIPHY_FLAG_SUPPORTS_5_10_MHZ | 4448f79cbc77SKalle Valo WIPHY_FLAG_HAS_CHANNEL_SWITCH; 4449f79cbc77SKalle Valo hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR | 4450f79cbc77SKalle Valo NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | 4451f79cbc77SKalle Valo NL80211_FEATURE_STATIC_SMPS | 4452f79cbc77SKalle Valo NL80211_FEATURE_DYNAMIC_SMPS | 4453f79cbc77SKalle Valo NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; 4454f79cbc77SKalle Valo wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS); 4455f79cbc77SKalle Valo wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_BEACON_PROTECTION); 4456f79cbc77SKalle Valo wiphy_ext_feature_set(hw->wiphy, 4457f79cbc77SKalle Valo NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS); 4458f79cbc77SKalle Valo wiphy_ext_feature_set(hw->wiphy, 4459f79cbc77SKalle Valo NL80211_EXT_FEATURE_BEACON_RATE_LEGACY); 4460f79cbc77SKalle Valo 4461f79cbc77SKalle Valo wiphy_ext_feature_set(hw->wiphy, 4462f79cbc77SKalle Valo NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT); 4463f79cbc77SKalle Valo 4464f79cbc77SKalle Valo hw->wiphy->interface_modes = param->iftypes; 4465f79cbc77SKalle Valo 4466f79cbc77SKalle Valo /* ask mac80211 to reserve space for magic */ 4467f79cbc77SKalle Valo hw->vif_data_size = sizeof(struct hwsim_vif_priv); 4468f79cbc77SKalle Valo hw->sta_data_size = sizeof(struct hwsim_sta_priv); 4469f79cbc77SKalle Valo hw->chanctx_data_size = sizeof(struct hwsim_chanctx_priv); 4470f79cbc77SKalle Valo 4471f79cbc77SKalle Valo memcpy(data->channels_2ghz, hwsim_channels_2ghz, 4472f79cbc77SKalle Valo sizeof(hwsim_channels_2ghz)); 4473f79cbc77SKalle Valo memcpy(data->channels_5ghz, hwsim_channels_5ghz, 4474f79cbc77SKalle Valo sizeof(hwsim_channels_5ghz)); 4475f79cbc77SKalle Valo memcpy(data->channels_6ghz, hwsim_channels_6ghz, 4476f79cbc77SKalle Valo sizeof(hwsim_channels_6ghz)); 4477f79cbc77SKalle Valo memcpy(data->channels_s1g, hwsim_channels_s1g, 4478f79cbc77SKalle Valo sizeof(hwsim_channels_s1g)); 4479f79cbc77SKalle Valo memcpy(data->rates, hwsim_rates, sizeof(hwsim_rates)); 4480f79cbc77SKalle Valo 4481f79cbc77SKalle Valo for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; band++) { 4482f79cbc77SKalle Valo struct ieee80211_supported_band *sband = &data->bands[band]; 4483f79cbc77SKalle Valo 4484f79cbc77SKalle Valo sband->band = band; 4485f79cbc77SKalle Valo 4486f79cbc77SKalle Valo switch (band) { 4487f79cbc77SKalle Valo case NL80211_BAND_2GHZ: 4488f79cbc77SKalle Valo sband->channels = data->channels_2ghz; 4489f79cbc77SKalle Valo sband->n_channels = ARRAY_SIZE(hwsim_channels_2ghz); 4490f79cbc77SKalle Valo sband->bitrates = data->rates; 4491f79cbc77SKalle Valo sband->n_bitrates = ARRAY_SIZE(hwsim_rates); 4492f79cbc77SKalle Valo break; 4493f79cbc77SKalle Valo case NL80211_BAND_5GHZ: 4494f79cbc77SKalle Valo sband->channels = data->channels_5ghz; 4495f79cbc77SKalle Valo sband->n_channels = ARRAY_SIZE(hwsim_channels_5ghz); 4496f79cbc77SKalle Valo sband->bitrates = data->rates + 4; 4497f79cbc77SKalle Valo sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4; 4498f79cbc77SKalle Valo 4499f79cbc77SKalle Valo sband->vht_cap.vht_supported = true; 4500f79cbc77SKalle Valo sband->vht_cap.cap = 4501f79cbc77SKalle Valo IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | 4502f79cbc77SKalle Valo IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ | 4503f79cbc77SKalle Valo IEEE80211_VHT_CAP_RXLDPC | 4504f79cbc77SKalle Valo IEEE80211_VHT_CAP_SHORT_GI_80 | 4505f79cbc77SKalle Valo IEEE80211_VHT_CAP_SHORT_GI_160 | 4506f79cbc77SKalle Valo IEEE80211_VHT_CAP_TXSTBC | 4507f79cbc77SKalle Valo IEEE80211_VHT_CAP_RXSTBC_4 | 4508f79cbc77SKalle Valo IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; 4509f79cbc77SKalle Valo sband->vht_cap.vht_mcs.rx_mcs_map = 4510f79cbc77SKalle Valo cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | 4511f79cbc77SKalle Valo IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 | 4512f79cbc77SKalle Valo IEEE80211_VHT_MCS_SUPPORT_0_9 << 4 | 4513f79cbc77SKalle Valo IEEE80211_VHT_MCS_SUPPORT_0_9 << 6 | 4514f79cbc77SKalle Valo IEEE80211_VHT_MCS_SUPPORT_0_9 << 8 | 4515f79cbc77SKalle Valo IEEE80211_VHT_MCS_SUPPORT_0_9 << 10 | 4516f79cbc77SKalle Valo IEEE80211_VHT_MCS_SUPPORT_0_9 << 12 | 4517f79cbc77SKalle Valo IEEE80211_VHT_MCS_SUPPORT_0_9 << 14); 4518f79cbc77SKalle Valo sband->vht_cap.vht_mcs.tx_mcs_map = 4519f79cbc77SKalle Valo sband->vht_cap.vht_mcs.rx_mcs_map; 4520f79cbc77SKalle Valo break; 4521f79cbc77SKalle Valo case NL80211_BAND_6GHZ: 4522f79cbc77SKalle Valo sband->channels = data->channels_6ghz; 4523f79cbc77SKalle Valo sband->n_channels = ARRAY_SIZE(hwsim_channels_6ghz); 4524f79cbc77SKalle Valo sband->bitrates = data->rates + 4; 4525f79cbc77SKalle Valo sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4; 4526f79cbc77SKalle Valo break; 4527f79cbc77SKalle Valo case NL80211_BAND_S1GHZ: 4528f79cbc77SKalle Valo memcpy(&sband->s1g_cap, &hwsim_s1g_cap, 4529f79cbc77SKalle Valo sizeof(sband->s1g_cap)); 4530f79cbc77SKalle Valo sband->channels = data->channels_s1g; 4531f79cbc77SKalle Valo sband->n_channels = ARRAY_SIZE(hwsim_channels_s1g); 4532f79cbc77SKalle Valo break; 4533f79cbc77SKalle Valo default: 4534f79cbc77SKalle Valo continue; 4535f79cbc77SKalle Valo } 4536f79cbc77SKalle Valo 4537f79cbc77SKalle Valo if (band != NL80211_BAND_6GHZ){ 4538f79cbc77SKalle Valo sband->ht_cap.ht_supported = true; 4539f79cbc77SKalle Valo sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | 4540f79cbc77SKalle Valo IEEE80211_HT_CAP_GRN_FLD | 4541f79cbc77SKalle Valo IEEE80211_HT_CAP_SGI_20 | 4542f79cbc77SKalle Valo IEEE80211_HT_CAP_SGI_40 | 4543f79cbc77SKalle Valo IEEE80211_HT_CAP_DSSSCCK40; 4544f79cbc77SKalle Valo sband->ht_cap.ampdu_factor = 0x3; 4545f79cbc77SKalle Valo sband->ht_cap.ampdu_density = 0x6; 4546f79cbc77SKalle Valo memset(&sband->ht_cap.mcs, 0, 4547f79cbc77SKalle Valo sizeof(sband->ht_cap.mcs)); 4548f79cbc77SKalle Valo sband->ht_cap.mcs.rx_mask[0] = 0xff; 4549f79cbc77SKalle Valo sband->ht_cap.mcs.rx_mask[1] = 0xff; 4550f79cbc77SKalle Valo sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; 4551f79cbc77SKalle Valo } 4552f79cbc77SKalle Valo 4553f79cbc77SKalle Valo mac80211_hwsim_sband_capab(sband); 4554f79cbc77SKalle Valo 4555f79cbc77SKalle Valo hw->wiphy->bands[band] = sband; 4556f79cbc77SKalle Valo } 4557f79cbc77SKalle Valo 4558f79cbc77SKalle Valo /* By default all radios belong to the first group */ 4559f79cbc77SKalle Valo data->group = 1; 4560f79cbc77SKalle Valo mutex_init(&data->mutex); 4561f79cbc77SKalle Valo 4562f79cbc77SKalle Valo data->netgroup = hwsim_net_get_netgroup(net); 4563f79cbc77SKalle Valo data->wmediumd = hwsim_net_get_wmediumd(net); 4564f79cbc77SKalle Valo 4565f79cbc77SKalle Valo /* Enable frame retransmissions for lossy channels */ 4566f79cbc77SKalle Valo hw->max_rates = 4; 4567f79cbc77SKalle Valo hw->max_rate_tries = 11; 4568f79cbc77SKalle Valo 4569f79cbc77SKalle Valo hw->wiphy->vendor_commands = mac80211_hwsim_vendor_commands; 4570f79cbc77SKalle Valo hw->wiphy->n_vendor_commands = 4571f79cbc77SKalle Valo ARRAY_SIZE(mac80211_hwsim_vendor_commands); 4572f79cbc77SKalle Valo hw->wiphy->vendor_events = mac80211_hwsim_vendor_events; 4573f79cbc77SKalle Valo hw->wiphy->n_vendor_events = ARRAY_SIZE(mac80211_hwsim_vendor_events); 4574f79cbc77SKalle Valo 4575f79cbc77SKalle Valo if (param->reg_strict) 4576f79cbc77SKalle Valo hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG; 4577f79cbc77SKalle Valo if (param->regd) { 4578f79cbc77SKalle Valo data->regd = param->regd; 4579f79cbc77SKalle Valo hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; 4580f79cbc77SKalle Valo wiphy_apply_custom_regulatory(hw->wiphy, param->regd); 4581f79cbc77SKalle Valo /* give the regulatory workqueue a chance to run */ 4582f79cbc77SKalle Valo schedule_timeout_interruptible(1); 4583f79cbc77SKalle Valo } 4584f79cbc77SKalle Valo 4585f79cbc77SKalle Valo if (param->no_vif) 4586f79cbc77SKalle Valo ieee80211_hw_set(hw, NO_AUTO_VIF); 4587f79cbc77SKalle Valo 4588f79cbc77SKalle Valo wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); 4589f79cbc77SKalle Valo 4590f79cbc77SKalle Valo for (i = 0; i < ARRAY_SIZE(data->link_data); i++) { 4591f79cbc77SKalle Valo hrtimer_init(&data->link_data[i].beacon_timer, CLOCK_MONOTONIC, 4592f79cbc77SKalle Valo HRTIMER_MODE_ABS_SOFT); 4593f79cbc77SKalle Valo data->link_data[i].beacon_timer.function = 4594f79cbc77SKalle Valo mac80211_hwsim_beacon; 4595f79cbc77SKalle Valo data->link_data[i].link_id = i; 4596f79cbc77SKalle Valo } 4597f79cbc77SKalle Valo 4598f79cbc77SKalle Valo err = ieee80211_register_hw(hw); 4599f79cbc77SKalle Valo if (err < 0) { 4600f79cbc77SKalle Valo pr_debug("mac80211_hwsim: ieee80211_register_hw failed (%d)\n", 4601f79cbc77SKalle Valo err); 4602f79cbc77SKalle Valo goto failed_hw; 4603f79cbc77SKalle Valo } 4604f79cbc77SKalle Valo 4605f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "hwaddr %pM registered\n", hw->wiphy->perm_addr); 4606f79cbc77SKalle Valo 4607f79cbc77SKalle Valo if (param->reg_alpha2) { 4608f79cbc77SKalle Valo data->alpha2[0] = param->reg_alpha2[0]; 4609f79cbc77SKalle Valo data->alpha2[1] = param->reg_alpha2[1]; 4610f79cbc77SKalle Valo regulatory_hint(hw->wiphy, param->reg_alpha2); 4611f79cbc77SKalle Valo } 4612f79cbc77SKalle Valo 4613f79cbc77SKalle Valo data->debugfs = debugfs_create_dir("hwsim", hw->wiphy->debugfsdir); 4614f79cbc77SKalle Valo debugfs_create_file("ps", 0666, data->debugfs, data, &hwsim_fops_ps); 4615f79cbc77SKalle Valo debugfs_create_file("group", 0666, data->debugfs, data, 4616f79cbc77SKalle Valo &hwsim_fops_group); 4617f79cbc77SKalle Valo debugfs_create_file("rx_rssi", 0666, data->debugfs, data, 4618f79cbc77SKalle Valo &hwsim_fops_rx_rssi); 4619f79cbc77SKalle Valo if (!data->use_chanctx) 4620f79cbc77SKalle Valo debugfs_create_file("dfs_simulate_radar", 0222, 4621f79cbc77SKalle Valo data->debugfs, 4622f79cbc77SKalle Valo data, &hwsim_simulate_radar); 4623f79cbc77SKalle Valo 4624f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 4625f79cbc77SKalle Valo err = rhashtable_insert_fast(&hwsim_radios_rht, &data->rht, 4626f79cbc77SKalle Valo hwsim_rht_params); 4627f79cbc77SKalle Valo if (err < 0) { 4628f79cbc77SKalle Valo if (info) { 4629f79cbc77SKalle Valo GENL_SET_ERR_MSG(info, "perm addr already present"); 4630f79cbc77SKalle Valo NL_SET_BAD_ATTR(info->extack, 4631f79cbc77SKalle Valo info->attrs[HWSIM_ATTR_PERM_ADDR]); 4632f79cbc77SKalle Valo } 4633f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 4634f79cbc77SKalle Valo goto failed_final_insert; 4635f79cbc77SKalle Valo } 4636f79cbc77SKalle Valo 4637f79cbc77SKalle Valo list_add_tail(&data->list, &hwsim_radios); 4638f79cbc77SKalle Valo hwsim_radios_generation++; 4639f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 4640f79cbc77SKalle Valo 4641f79cbc77SKalle Valo hwsim_mcast_new_radio(idx, info, param); 4642f79cbc77SKalle Valo 4643f79cbc77SKalle Valo return idx; 4644f79cbc77SKalle Valo 4645f79cbc77SKalle Valo failed_final_insert: 4646f79cbc77SKalle Valo debugfs_remove_recursive(data->debugfs); 4647f79cbc77SKalle Valo ieee80211_unregister_hw(data->hw); 4648f79cbc77SKalle Valo failed_hw: 4649f79cbc77SKalle Valo device_release_driver(data->dev); 4650f79cbc77SKalle Valo failed_bind: 4651f79cbc77SKalle Valo device_unregister(data->dev); 4652f79cbc77SKalle Valo failed_drvdata: 4653f79cbc77SKalle Valo ieee80211_free_hw(hw); 4654f79cbc77SKalle Valo failed: 4655f79cbc77SKalle Valo return err; 4656f79cbc77SKalle Valo } 4657f79cbc77SKalle Valo 4658f79cbc77SKalle Valo static void hwsim_mcast_del_radio(int id, const char *hwname, 4659f79cbc77SKalle Valo struct genl_info *info) 4660f79cbc77SKalle Valo { 4661f79cbc77SKalle Valo struct sk_buff *skb; 4662f79cbc77SKalle Valo void *data; 4663f79cbc77SKalle Valo int ret; 4664f79cbc77SKalle Valo 4665f79cbc77SKalle Valo skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 4666f79cbc77SKalle Valo if (!skb) 4667f79cbc77SKalle Valo return; 4668f79cbc77SKalle Valo 4669f79cbc77SKalle Valo data = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, 4670f79cbc77SKalle Valo HWSIM_CMD_DEL_RADIO); 4671f79cbc77SKalle Valo if (!data) 4672f79cbc77SKalle Valo goto error; 4673f79cbc77SKalle Valo 4674f79cbc77SKalle Valo ret = nla_put_u32(skb, HWSIM_ATTR_RADIO_ID, id); 4675f79cbc77SKalle Valo if (ret < 0) 4676f79cbc77SKalle Valo goto error; 4677f79cbc77SKalle Valo 4678f79cbc77SKalle Valo ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME, strlen(hwname), 4679f79cbc77SKalle Valo hwname); 4680f79cbc77SKalle Valo if (ret < 0) 4681f79cbc77SKalle Valo goto error; 4682f79cbc77SKalle Valo 4683f79cbc77SKalle Valo genlmsg_end(skb, data); 4684f79cbc77SKalle Valo 4685f79cbc77SKalle Valo hwsim_mcast_config_msg(skb, info); 4686f79cbc77SKalle Valo 4687f79cbc77SKalle Valo return; 4688f79cbc77SKalle Valo 4689f79cbc77SKalle Valo error: 4690f79cbc77SKalle Valo nlmsg_free(skb); 4691f79cbc77SKalle Valo } 4692f79cbc77SKalle Valo 4693f79cbc77SKalle Valo static void mac80211_hwsim_del_radio(struct mac80211_hwsim_data *data, 4694f79cbc77SKalle Valo const char *hwname, 4695f79cbc77SKalle Valo struct genl_info *info) 4696f79cbc77SKalle Valo { 4697f79cbc77SKalle Valo hwsim_mcast_del_radio(data->idx, hwname, info); 4698f79cbc77SKalle Valo debugfs_remove_recursive(data->debugfs); 4699f79cbc77SKalle Valo ieee80211_unregister_hw(data->hw); 4700f79cbc77SKalle Valo device_release_driver(data->dev); 4701f79cbc77SKalle Valo device_unregister(data->dev); 4702f79cbc77SKalle Valo ieee80211_free_hw(data->hw); 4703f79cbc77SKalle Valo } 4704f79cbc77SKalle Valo 4705f79cbc77SKalle Valo static int mac80211_hwsim_get_radio(struct sk_buff *skb, 4706f79cbc77SKalle Valo struct mac80211_hwsim_data *data, 4707f79cbc77SKalle Valo u32 portid, u32 seq, 4708f79cbc77SKalle Valo struct netlink_callback *cb, int flags) 4709f79cbc77SKalle Valo { 4710f79cbc77SKalle Valo void *hdr; 4711f79cbc77SKalle Valo struct hwsim_new_radio_params param = { }; 4712f79cbc77SKalle Valo int res = -EMSGSIZE; 4713f79cbc77SKalle Valo 4714f79cbc77SKalle Valo hdr = genlmsg_put(skb, portid, seq, &hwsim_genl_family, flags, 4715f79cbc77SKalle Valo HWSIM_CMD_GET_RADIO); 4716f79cbc77SKalle Valo if (!hdr) 4717f79cbc77SKalle Valo return -EMSGSIZE; 4718f79cbc77SKalle Valo 4719f79cbc77SKalle Valo if (cb) 4720f79cbc77SKalle Valo genl_dump_check_consistent(cb, hdr); 4721f79cbc77SKalle Valo 4722f79cbc77SKalle Valo if (data->alpha2[0] && data->alpha2[1]) 4723f79cbc77SKalle Valo param.reg_alpha2 = data->alpha2; 4724f79cbc77SKalle Valo 4725f79cbc77SKalle Valo param.reg_strict = !!(data->hw->wiphy->regulatory_flags & 4726f79cbc77SKalle Valo REGULATORY_STRICT_REG); 4727f79cbc77SKalle Valo param.p2p_device = !!(data->hw->wiphy->interface_modes & 4728f79cbc77SKalle Valo BIT(NL80211_IFTYPE_P2P_DEVICE)); 4729f79cbc77SKalle Valo param.use_chanctx = data->use_chanctx; 4730f79cbc77SKalle Valo param.regd = data->regd; 4731f79cbc77SKalle Valo param.channels = data->channels; 4732f79cbc77SKalle Valo param.hwname = wiphy_name(data->hw->wiphy); 4733f79cbc77SKalle Valo 4734f79cbc77SKalle Valo res = append_radio_msg(skb, data->idx, ¶m); 4735f79cbc77SKalle Valo if (res < 0) 4736f79cbc77SKalle Valo goto out_err; 4737f79cbc77SKalle Valo 4738f79cbc77SKalle Valo genlmsg_end(skb, hdr); 4739f79cbc77SKalle Valo return 0; 4740f79cbc77SKalle Valo 4741f79cbc77SKalle Valo out_err: 4742f79cbc77SKalle Valo genlmsg_cancel(skb, hdr); 4743f79cbc77SKalle Valo return res; 4744f79cbc77SKalle Valo } 4745f79cbc77SKalle Valo 4746f79cbc77SKalle Valo static void mac80211_hwsim_free(void) 4747f79cbc77SKalle Valo { 4748f79cbc77SKalle Valo struct mac80211_hwsim_data *data; 4749f79cbc77SKalle Valo 4750f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 4751f79cbc77SKalle Valo while ((data = list_first_entry_or_null(&hwsim_radios, 4752f79cbc77SKalle Valo struct mac80211_hwsim_data, 4753f79cbc77SKalle Valo list))) { 4754f79cbc77SKalle Valo list_del(&data->list); 4755f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 4756f79cbc77SKalle Valo mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy), 4757f79cbc77SKalle Valo NULL); 4758f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 4759f79cbc77SKalle Valo } 4760f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 4761f79cbc77SKalle Valo class_destroy(hwsim_class); 4762f79cbc77SKalle Valo } 4763f79cbc77SKalle Valo 4764f79cbc77SKalle Valo static const struct net_device_ops hwsim_netdev_ops = { 4765f79cbc77SKalle Valo .ndo_start_xmit = hwsim_mon_xmit, 4766f79cbc77SKalle Valo .ndo_set_mac_address = eth_mac_addr, 4767f79cbc77SKalle Valo .ndo_validate_addr = eth_validate_addr, 4768f79cbc77SKalle Valo }; 4769f79cbc77SKalle Valo 4770f79cbc77SKalle Valo static void hwsim_mon_setup(struct net_device *dev) 4771f79cbc77SKalle Valo { 4772f79cbc77SKalle Valo u8 addr[ETH_ALEN]; 4773f79cbc77SKalle Valo 4774f79cbc77SKalle Valo dev->netdev_ops = &hwsim_netdev_ops; 4775f79cbc77SKalle Valo dev->needs_free_netdev = true; 4776f79cbc77SKalle Valo ether_setup(dev); 4777f79cbc77SKalle Valo dev->priv_flags |= IFF_NO_QUEUE; 4778f79cbc77SKalle Valo dev->type = ARPHRD_IEEE80211_RADIOTAP; 4779f79cbc77SKalle Valo eth_zero_addr(addr); 4780f79cbc77SKalle Valo addr[0] = 0x12; 4781f79cbc77SKalle Valo eth_hw_addr_set(dev, addr); 4782f79cbc77SKalle Valo } 4783f79cbc77SKalle Valo 4784f79cbc77SKalle Valo static struct mac80211_hwsim_data *get_hwsim_data_ref_from_addr(const u8 *addr) 4785f79cbc77SKalle Valo { 4786f79cbc77SKalle Valo return rhashtable_lookup_fast(&hwsim_radios_rht, 4787f79cbc77SKalle Valo addr, 4788f79cbc77SKalle Valo hwsim_rht_params); 4789f79cbc77SKalle Valo } 4790f79cbc77SKalle Valo 4791f79cbc77SKalle Valo static void hwsim_register_wmediumd(struct net *net, u32 portid) 4792f79cbc77SKalle Valo { 4793f79cbc77SKalle Valo struct mac80211_hwsim_data *data; 4794f79cbc77SKalle Valo 4795f79cbc77SKalle Valo hwsim_net_set_wmediumd(net, portid); 4796f79cbc77SKalle Valo 4797f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 4798f79cbc77SKalle Valo list_for_each_entry(data, &hwsim_radios, list) { 4799f79cbc77SKalle Valo if (data->netgroup == hwsim_net_get_netgroup(net)) 4800f79cbc77SKalle Valo data->wmediumd = portid; 4801f79cbc77SKalle Valo } 4802f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 4803f79cbc77SKalle Valo } 4804f79cbc77SKalle Valo 4805f79cbc77SKalle Valo static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2, 4806f79cbc77SKalle Valo struct genl_info *info) 4807f79cbc77SKalle Valo { 4808f79cbc77SKalle Valo 4809f79cbc77SKalle Valo struct ieee80211_hdr *hdr; 4810f79cbc77SKalle Valo struct mac80211_hwsim_data *data2; 4811f79cbc77SKalle Valo struct ieee80211_tx_info *txi; 4812f79cbc77SKalle Valo struct hwsim_tx_rate *tx_attempts; 4813f79cbc77SKalle Valo u64 ret_skb_cookie; 4814f79cbc77SKalle Valo struct sk_buff *skb, *tmp; 4815f79cbc77SKalle Valo const u8 *src; 4816f79cbc77SKalle Valo unsigned int hwsim_flags; 4817f79cbc77SKalle Valo int i; 4818f79cbc77SKalle Valo unsigned long flags; 4819f79cbc77SKalle Valo bool found = false; 4820f79cbc77SKalle Valo 4821f79cbc77SKalle Valo if (!info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER] || 4822f79cbc77SKalle Valo !info->attrs[HWSIM_ATTR_FLAGS] || 4823f79cbc77SKalle Valo !info->attrs[HWSIM_ATTR_COOKIE] || 4824f79cbc77SKalle Valo !info->attrs[HWSIM_ATTR_SIGNAL] || 4825f79cbc77SKalle Valo !info->attrs[HWSIM_ATTR_TX_INFO]) 4826f79cbc77SKalle Valo goto out; 4827f79cbc77SKalle Valo 4828f79cbc77SKalle Valo src = (void *)nla_data(info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER]); 4829f79cbc77SKalle Valo hwsim_flags = nla_get_u32(info->attrs[HWSIM_ATTR_FLAGS]); 4830f79cbc77SKalle Valo ret_skb_cookie = nla_get_u64(info->attrs[HWSIM_ATTR_COOKIE]); 4831f79cbc77SKalle Valo 4832f79cbc77SKalle Valo data2 = get_hwsim_data_ref_from_addr(src); 4833f79cbc77SKalle Valo if (!data2) 4834f79cbc77SKalle Valo goto out; 4835f79cbc77SKalle Valo 4836f79cbc77SKalle Valo if (!hwsim_virtio_enabled) { 4837f79cbc77SKalle Valo if (hwsim_net_get_netgroup(genl_info_net(info)) != 4838f79cbc77SKalle Valo data2->netgroup) 4839f79cbc77SKalle Valo goto out; 4840f79cbc77SKalle Valo 4841f79cbc77SKalle Valo if (info->snd_portid != data2->wmediumd) 4842f79cbc77SKalle Valo goto out; 4843f79cbc77SKalle Valo } 4844f79cbc77SKalle Valo 4845f79cbc77SKalle Valo /* look for the skb matching the cookie passed back from user */ 4846f79cbc77SKalle Valo spin_lock_irqsave(&data2->pending.lock, flags); 4847f79cbc77SKalle Valo skb_queue_walk_safe(&data2->pending, skb, tmp) { 4848f79cbc77SKalle Valo uintptr_t skb_cookie; 4849f79cbc77SKalle Valo 4850f79cbc77SKalle Valo txi = IEEE80211_SKB_CB(skb); 4851f79cbc77SKalle Valo skb_cookie = (uintptr_t)txi->rate_driver_data[0]; 4852f79cbc77SKalle Valo 4853f79cbc77SKalle Valo if (skb_cookie == ret_skb_cookie) { 4854f79cbc77SKalle Valo __skb_unlink(skb, &data2->pending); 4855f79cbc77SKalle Valo found = true; 4856f79cbc77SKalle Valo break; 4857f79cbc77SKalle Valo } 4858f79cbc77SKalle Valo } 4859f79cbc77SKalle Valo spin_unlock_irqrestore(&data2->pending.lock, flags); 4860f79cbc77SKalle Valo 4861f79cbc77SKalle Valo /* not found */ 4862f79cbc77SKalle Valo if (!found) 4863f79cbc77SKalle Valo goto out; 4864f79cbc77SKalle Valo 4865f79cbc77SKalle Valo /* Tx info received because the frame was broadcasted on user space, 4866f79cbc77SKalle Valo so we get all the necessary info: tx attempts and skb control buff */ 4867f79cbc77SKalle Valo 4868f79cbc77SKalle Valo tx_attempts = (struct hwsim_tx_rate *)nla_data( 4869f79cbc77SKalle Valo info->attrs[HWSIM_ATTR_TX_INFO]); 4870f79cbc77SKalle Valo 4871f79cbc77SKalle Valo /* now send back TX status */ 4872f79cbc77SKalle Valo txi = IEEE80211_SKB_CB(skb); 4873f79cbc77SKalle Valo 4874f79cbc77SKalle Valo ieee80211_tx_info_clear_status(txi); 4875f79cbc77SKalle Valo 4876f79cbc77SKalle Valo for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { 4877f79cbc77SKalle Valo txi->status.rates[i].idx = tx_attempts[i].idx; 4878f79cbc77SKalle Valo txi->status.rates[i].count = tx_attempts[i].count; 4879f79cbc77SKalle Valo } 4880f79cbc77SKalle Valo 4881f79cbc77SKalle Valo txi->status.ack_signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]); 4882f79cbc77SKalle Valo 4883f79cbc77SKalle Valo if (!(hwsim_flags & HWSIM_TX_CTL_NO_ACK) && 4884f79cbc77SKalle Valo (hwsim_flags & HWSIM_TX_STAT_ACK)) { 4885f79cbc77SKalle Valo if (skb->len >= 16) { 4886f79cbc77SKalle Valo hdr = (struct ieee80211_hdr *) skb->data; 4887f79cbc77SKalle Valo mac80211_hwsim_monitor_ack(data2->channel, 4888f79cbc77SKalle Valo hdr->addr2); 4889f79cbc77SKalle Valo } 4890f79cbc77SKalle Valo txi->flags |= IEEE80211_TX_STAT_ACK; 4891f79cbc77SKalle Valo } 4892f79cbc77SKalle Valo 4893f79cbc77SKalle Valo if (hwsim_flags & HWSIM_TX_CTL_NO_ACK) 4894f79cbc77SKalle Valo txi->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; 4895f79cbc77SKalle Valo 4896f79cbc77SKalle Valo ieee80211_tx_status_irqsafe(data2->hw, skb); 4897f79cbc77SKalle Valo return 0; 4898f79cbc77SKalle Valo out: 4899f79cbc77SKalle Valo return -EINVAL; 4900f79cbc77SKalle Valo 4901f79cbc77SKalle Valo } 4902f79cbc77SKalle Valo 4903f79cbc77SKalle Valo static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, 4904f79cbc77SKalle Valo struct genl_info *info) 4905f79cbc77SKalle Valo { 4906f79cbc77SKalle Valo struct mac80211_hwsim_data *data2; 4907f79cbc77SKalle Valo struct ieee80211_rx_status rx_status; 4908f79cbc77SKalle Valo struct ieee80211_hdr *hdr; 4909f79cbc77SKalle Valo const u8 *dst; 4910f79cbc77SKalle Valo int frame_data_len; 4911f79cbc77SKalle Valo void *frame_data; 4912f79cbc77SKalle Valo struct sk_buff *skb = NULL; 4913f79cbc77SKalle Valo struct ieee80211_channel *channel = NULL; 4914f79cbc77SKalle Valo 4915f79cbc77SKalle Valo if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] || 4916f79cbc77SKalle Valo !info->attrs[HWSIM_ATTR_FRAME] || 4917f79cbc77SKalle Valo !info->attrs[HWSIM_ATTR_RX_RATE] || 4918f79cbc77SKalle Valo !info->attrs[HWSIM_ATTR_SIGNAL]) 4919f79cbc77SKalle Valo goto out; 4920f79cbc77SKalle Valo 4921f79cbc77SKalle Valo dst = (void *)nla_data(info->attrs[HWSIM_ATTR_ADDR_RECEIVER]); 4922f79cbc77SKalle Valo frame_data_len = nla_len(info->attrs[HWSIM_ATTR_FRAME]); 4923f79cbc77SKalle Valo frame_data = (void *)nla_data(info->attrs[HWSIM_ATTR_FRAME]); 4924f79cbc77SKalle Valo 4925f79cbc77SKalle Valo /* Allocate new skb here */ 4926f79cbc77SKalle Valo skb = alloc_skb(frame_data_len, GFP_KERNEL); 4927f79cbc77SKalle Valo if (skb == NULL) 4928f79cbc77SKalle Valo goto err; 4929f79cbc77SKalle Valo 4930f79cbc77SKalle Valo if (frame_data_len > IEEE80211_MAX_DATA_LEN) 4931f79cbc77SKalle Valo goto err; 4932f79cbc77SKalle Valo 4933f79cbc77SKalle Valo /* Copy the data */ 4934f79cbc77SKalle Valo skb_put_data(skb, frame_data, frame_data_len); 4935f79cbc77SKalle Valo 4936f79cbc77SKalle Valo data2 = get_hwsim_data_ref_from_addr(dst); 4937f79cbc77SKalle Valo if (!data2) 4938f79cbc77SKalle Valo goto out; 4939f79cbc77SKalle Valo 4940f79cbc77SKalle Valo if (data2->use_chanctx) { 4941f79cbc77SKalle Valo if (data2->tmp_chan) 4942f79cbc77SKalle Valo channel = data2->tmp_chan; 4943f79cbc77SKalle Valo } else { 4944f79cbc77SKalle Valo channel = data2->channel; 4945f79cbc77SKalle Valo } 4946f79cbc77SKalle Valo 4947f79cbc77SKalle Valo if (!hwsim_virtio_enabled) { 4948f79cbc77SKalle Valo if (hwsim_net_get_netgroup(genl_info_net(info)) != 4949f79cbc77SKalle Valo data2->netgroup) 4950f79cbc77SKalle Valo goto out; 4951f79cbc77SKalle Valo 4952f79cbc77SKalle Valo if (info->snd_portid != data2->wmediumd) 4953f79cbc77SKalle Valo goto out; 4954f79cbc77SKalle Valo } 4955f79cbc77SKalle Valo 4956f79cbc77SKalle Valo /* check if radio is configured properly */ 4957f79cbc77SKalle Valo 4958f79cbc77SKalle Valo if ((data2->idle && !data2->tmp_chan) || !data2->started) 4959f79cbc77SKalle Valo goto out; 4960f79cbc77SKalle Valo 4961f79cbc77SKalle Valo /* A frame is received from user space */ 4962f79cbc77SKalle Valo memset(&rx_status, 0, sizeof(rx_status)); 4963f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_FREQ]) { 4964f79cbc77SKalle Valo struct tx_iter_data iter_data = {}; 4965f79cbc77SKalle Valo 4966f79cbc77SKalle Valo /* throw away off-channel packets, but allow both the temporary 4967f79cbc77SKalle Valo * ("hw" scan/remain-on-channel), regular channels and links, 4968f79cbc77SKalle Valo * since the internal datapath also allows this 4969f79cbc77SKalle Valo */ 4970f79cbc77SKalle Valo rx_status.freq = nla_get_u32(info->attrs[HWSIM_ATTR_FREQ]); 4971f79cbc77SKalle Valo 4972f79cbc77SKalle Valo iter_data.channel = ieee80211_get_channel(data2->hw->wiphy, 4973f79cbc77SKalle Valo rx_status.freq); 4974f79cbc77SKalle Valo if (!iter_data.channel) 4975f79cbc77SKalle Valo goto out; 4976f79cbc77SKalle Valo rx_status.band = iter_data.channel->band; 4977f79cbc77SKalle Valo 4978f79cbc77SKalle Valo mutex_lock(&data2->mutex); 4979f79cbc77SKalle Valo if (!hwsim_chans_compat(iter_data.channel, channel)) { 4980f79cbc77SKalle Valo ieee80211_iterate_active_interfaces_atomic( 4981f79cbc77SKalle Valo data2->hw, IEEE80211_IFACE_ITER_NORMAL, 4982f79cbc77SKalle Valo mac80211_hwsim_tx_iter, &iter_data); 4983f79cbc77SKalle Valo if (!iter_data.receive) { 4984f79cbc77SKalle Valo mutex_unlock(&data2->mutex); 4985f79cbc77SKalle Valo goto out; 4986f79cbc77SKalle Valo } 4987f79cbc77SKalle Valo } 4988f79cbc77SKalle Valo mutex_unlock(&data2->mutex); 4989f79cbc77SKalle Valo } else if (!channel) { 4990f79cbc77SKalle Valo goto out; 4991f79cbc77SKalle Valo } else { 4992f79cbc77SKalle Valo rx_status.freq = channel->center_freq; 4993f79cbc77SKalle Valo rx_status.band = channel->band; 4994f79cbc77SKalle Valo } 4995f79cbc77SKalle Valo 4996f79cbc77SKalle Valo rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]); 4997f79cbc77SKalle Valo if (rx_status.rate_idx >= data2->hw->wiphy->bands[rx_status.band]->n_bitrates) 4998f79cbc77SKalle Valo goto out; 4999f79cbc77SKalle Valo rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]); 5000f79cbc77SKalle Valo 5001f79cbc77SKalle Valo hdr = (void *)skb->data; 5002f79cbc77SKalle Valo 5003f79cbc77SKalle Valo if (ieee80211_is_beacon(hdr->frame_control) || 5004f79cbc77SKalle Valo ieee80211_is_probe_resp(hdr->frame_control)) 5005f79cbc77SKalle Valo rx_status.boottime_ns = ktime_get_boottime_ns(); 5006f79cbc77SKalle Valo 5007f79cbc77SKalle Valo mac80211_hwsim_rx(data2, &rx_status, skb); 5008f79cbc77SKalle Valo 5009f79cbc77SKalle Valo return 0; 5010f79cbc77SKalle Valo err: 5011f79cbc77SKalle Valo pr_debug("mac80211_hwsim: error occurred in %s\n", __func__); 5012f79cbc77SKalle Valo out: 5013f79cbc77SKalle Valo dev_kfree_skb(skb); 5014f79cbc77SKalle Valo return -EINVAL; 5015f79cbc77SKalle Valo } 5016f79cbc77SKalle Valo 5017f79cbc77SKalle Valo static int hwsim_register_received_nl(struct sk_buff *skb_2, 5018f79cbc77SKalle Valo struct genl_info *info) 5019f79cbc77SKalle Valo { 5020f79cbc77SKalle Valo struct net *net = genl_info_net(info); 5021f79cbc77SKalle Valo struct mac80211_hwsim_data *data; 5022f79cbc77SKalle Valo int chans = 1; 5023f79cbc77SKalle Valo 5024f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 5025f79cbc77SKalle Valo list_for_each_entry(data, &hwsim_radios, list) 5026f79cbc77SKalle Valo chans = max(chans, data->channels); 5027f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 5028f79cbc77SKalle Valo 5029f79cbc77SKalle Valo /* In the future we should revise the userspace API and allow it 5030f79cbc77SKalle Valo * to set a flag that it does support multi-channel, then we can 5031f79cbc77SKalle Valo * let this pass conditionally on the flag. 5032f79cbc77SKalle Valo * For current userspace, prohibit it since it won't work right. 5033f79cbc77SKalle Valo */ 5034f79cbc77SKalle Valo if (chans > 1) 5035f79cbc77SKalle Valo return -EOPNOTSUPP; 5036f79cbc77SKalle Valo 5037f79cbc77SKalle Valo if (hwsim_net_get_wmediumd(net)) 5038f79cbc77SKalle Valo return -EBUSY; 5039f79cbc77SKalle Valo 5040f79cbc77SKalle Valo hwsim_register_wmediumd(net, info->snd_portid); 5041f79cbc77SKalle Valo 5042f79cbc77SKalle Valo pr_debug("mac80211_hwsim: received a REGISTER, " 5043f79cbc77SKalle Valo "switching to wmediumd mode with pid %d\n", info->snd_portid); 5044f79cbc77SKalle Valo 5045f79cbc77SKalle Valo return 0; 5046f79cbc77SKalle Valo } 5047f79cbc77SKalle Valo 5048f79cbc77SKalle Valo /* ensures ciphers only include ciphers listed in 'hwsim_ciphers' array */ 5049f79cbc77SKalle Valo static bool hwsim_known_ciphers(const u32 *ciphers, int n_ciphers) 5050f79cbc77SKalle Valo { 5051f79cbc77SKalle Valo int i; 5052f79cbc77SKalle Valo 5053f79cbc77SKalle Valo for (i = 0; i < n_ciphers; i++) { 5054f79cbc77SKalle Valo int j; 5055f79cbc77SKalle Valo int found = 0; 5056f79cbc77SKalle Valo 5057f79cbc77SKalle Valo for (j = 0; j < ARRAY_SIZE(hwsim_ciphers); j++) { 5058f79cbc77SKalle Valo if (ciphers[i] == hwsim_ciphers[j]) { 5059f79cbc77SKalle Valo found = 1; 5060f79cbc77SKalle Valo break; 5061f79cbc77SKalle Valo } 5062f79cbc77SKalle Valo } 5063f79cbc77SKalle Valo 5064f79cbc77SKalle Valo if (!found) 5065f79cbc77SKalle Valo return false; 5066f79cbc77SKalle Valo } 5067f79cbc77SKalle Valo 5068f79cbc77SKalle Valo return true; 5069f79cbc77SKalle Valo } 5070f79cbc77SKalle Valo 5071f79cbc77SKalle Valo static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info) 5072f79cbc77SKalle Valo { 5073f79cbc77SKalle Valo struct hwsim_new_radio_params param = { 0 }; 5074f79cbc77SKalle Valo const char *hwname = NULL; 5075f79cbc77SKalle Valo int ret; 5076f79cbc77SKalle Valo 5077f79cbc77SKalle Valo param.reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG]; 5078f79cbc77SKalle Valo param.p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE]; 5079f79cbc77SKalle Valo param.channels = channels; 5080f79cbc77SKalle Valo param.destroy_on_close = 5081f79cbc77SKalle Valo info->attrs[HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE]; 5082f79cbc77SKalle Valo 5083f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_CHANNELS]) 5084f79cbc77SKalle Valo param.channels = nla_get_u32(info->attrs[HWSIM_ATTR_CHANNELS]); 5085f79cbc77SKalle Valo 5086f79cbc77SKalle Valo if (param.channels < 1) { 5087f79cbc77SKalle Valo GENL_SET_ERR_MSG(info, "must have at least one channel"); 5088f79cbc77SKalle Valo return -EINVAL; 5089f79cbc77SKalle Valo } 5090f79cbc77SKalle Valo 5091f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_NO_VIF]) 5092f79cbc77SKalle Valo param.no_vif = true; 5093f79cbc77SKalle Valo 5094f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_USE_CHANCTX]) 5095f79cbc77SKalle Valo param.use_chanctx = true; 5096f79cbc77SKalle Valo else 5097f79cbc77SKalle Valo param.use_chanctx = (param.channels > 1); 5098f79cbc77SKalle Valo 5099f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]) 5100f79cbc77SKalle Valo param.reg_alpha2 = 5101f79cbc77SKalle Valo nla_data(info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]); 5102f79cbc77SKalle Valo 5103f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]) { 5104f79cbc77SKalle Valo u32 idx = nla_get_u32(info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]); 5105f79cbc77SKalle Valo 5106f79cbc77SKalle Valo if (idx >= ARRAY_SIZE(hwsim_world_regdom_custom)) 5107f79cbc77SKalle Valo return -EINVAL; 5108f79cbc77SKalle Valo 5109f79cbc77SKalle Valo idx = array_index_nospec(idx, 5110f79cbc77SKalle Valo ARRAY_SIZE(hwsim_world_regdom_custom)); 5111f79cbc77SKalle Valo param.regd = hwsim_world_regdom_custom[idx]; 5112f79cbc77SKalle Valo } 5113f79cbc77SKalle Valo 5114f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_PERM_ADDR]) { 5115f79cbc77SKalle Valo if (!is_valid_ether_addr( 5116f79cbc77SKalle Valo nla_data(info->attrs[HWSIM_ATTR_PERM_ADDR]))) { 5117f79cbc77SKalle Valo GENL_SET_ERR_MSG(info,"MAC is no valid source addr"); 5118f79cbc77SKalle Valo NL_SET_BAD_ATTR(info->extack, 5119f79cbc77SKalle Valo info->attrs[HWSIM_ATTR_PERM_ADDR]); 5120f79cbc77SKalle Valo return -EINVAL; 5121f79cbc77SKalle Valo } 5122f79cbc77SKalle Valo 5123f79cbc77SKalle Valo param.perm_addr = nla_data(info->attrs[HWSIM_ATTR_PERM_ADDR]); 5124f79cbc77SKalle Valo } 5125f79cbc77SKalle Valo 5126f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_IFTYPE_SUPPORT]) { 5127f79cbc77SKalle Valo param.iftypes = 5128f79cbc77SKalle Valo nla_get_u32(info->attrs[HWSIM_ATTR_IFTYPE_SUPPORT]); 5129f79cbc77SKalle Valo 5130f79cbc77SKalle Valo if (param.iftypes & ~HWSIM_IFTYPE_SUPPORT_MASK) { 5131f79cbc77SKalle Valo NL_SET_ERR_MSG_ATTR(info->extack, 5132f79cbc77SKalle Valo info->attrs[HWSIM_ATTR_IFTYPE_SUPPORT], 5133f79cbc77SKalle Valo "cannot support more iftypes than kernel"); 5134f79cbc77SKalle Valo return -EINVAL; 5135f79cbc77SKalle Valo } 5136f79cbc77SKalle Valo } else { 5137f79cbc77SKalle Valo param.iftypes = HWSIM_IFTYPE_SUPPORT_MASK; 5138f79cbc77SKalle Valo } 5139f79cbc77SKalle Valo 5140f79cbc77SKalle Valo /* ensure both flag and iftype support is honored */ 5141f79cbc77SKalle Valo if (param.p2p_device || 5142f79cbc77SKalle Valo param.iftypes & BIT(NL80211_IFTYPE_P2P_DEVICE)) { 5143f79cbc77SKalle Valo param.iftypes |= BIT(NL80211_IFTYPE_P2P_DEVICE); 5144f79cbc77SKalle Valo param.p2p_device = true; 5145f79cbc77SKalle Valo } 5146f79cbc77SKalle Valo 5147f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_CIPHER_SUPPORT]) { 5148f79cbc77SKalle Valo u32 len = nla_len(info->attrs[HWSIM_ATTR_CIPHER_SUPPORT]); 5149f79cbc77SKalle Valo 5150f79cbc77SKalle Valo param.ciphers = 5151f79cbc77SKalle Valo nla_data(info->attrs[HWSIM_ATTR_CIPHER_SUPPORT]); 5152f79cbc77SKalle Valo 5153f79cbc77SKalle Valo if (len % sizeof(u32)) { 5154f79cbc77SKalle Valo NL_SET_ERR_MSG_ATTR(info->extack, 5155f79cbc77SKalle Valo info->attrs[HWSIM_ATTR_CIPHER_SUPPORT], 5156f79cbc77SKalle Valo "bad cipher list length"); 5157f79cbc77SKalle Valo return -EINVAL; 5158f79cbc77SKalle Valo } 5159f79cbc77SKalle Valo 5160f79cbc77SKalle Valo param.n_ciphers = len / sizeof(u32); 5161f79cbc77SKalle Valo 5162f79cbc77SKalle Valo if (param.n_ciphers > ARRAY_SIZE(hwsim_ciphers)) { 5163f79cbc77SKalle Valo NL_SET_ERR_MSG_ATTR(info->extack, 5164f79cbc77SKalle Valo info->attrs[HWSIM_ATTR_CIPHER_SUPPORT], 5165f79cbc77SKalle Valo "too many ciphers specified"); 5166f79cbc77SKalle Valo return -EINVAL; 5167f79cbc77SKalle Valo } 5168f79cbc77SKalle Valo 5169f79cbc77SKalle Valo if (!hwsim_known_ciphers(param.ciphers, param.n_ciphers)) { 5170f79cbc77SKalle Valo NL_SET_ERR_MSG_ATTR(info->extack, 5171f79cbc77SKalle Valo info->attrs[HWSIM_ATTR_CIPHER_SUPPORT], 5172f79cbc77SKalle Valo "unsupported ciphers specified"); 5173f79cbc77SKalle Valo return -EINVAL; 5174f79cbc77SKalle Valo } 5175f79cbc77SKalle Valo } 5176f79cbc77SKalle Valo 5177f79cbc77SKalle Valo param.mlo = info->attrs[HWSIM_ATTR_MLO_SUPPORT]; 5178f79cbc77SKalle Valo 5179f79cbc77SKalle Valo if (param.mlo) 5180f79cbc77SKalle Valo param.use_chanctx = true; 5181f79cbc77SKalle Valo 5182f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_RADIO_NAME]) { 5183f79cbc77SKalle Valo hwname = kstrndup((char *)nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME]), 5184f79cbc77SKalle Valo nla_len(info->attrs[HWSIM_ATTR_RADIO_NAME]), 5185f79cbc77SKalle Valo GFP_KERNEL); 5186f79cbc77SKalle Valo if (!hwname) 5187f79cbc77SKalle Valo return -ENOMEM; 5188f79cbc77SKalle Valo param.hwname = hwname; 5189f79cbc77SKalle Valo } 5190f79cbc77SKalle Valo 5191f79cbc77SKalle Valo ret = mac80211_hwsim_new_radio(info, ¶m); 5192f79cbc77SKalle Valo kfree(hwname); 5193f79cbc77SKalle Valo return ret; 5194f79cbc77SKalle Valo } 5195f79cbc77SKalle Valo 5196f79cbc77SKalle Valo static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info) 5197f79cbc77SKalle Valo { 5198f79cbc77SKalle Valo struct mac80211_hwsim_data *data; 5199f79cbc77SKalle Valo s64 idx = -1; 5200f79cbc77SKalle Valo const char *hwname = NULL; 5201f79cbc77SKalle Valo 5202f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_RADIO_ID]) { 5203f79cbc77SKalle Valo idx = nla_get_u32(info->attrs[HWSIM_ATTR_RADIO_ID]); 5204f79cbc77SKalle Valo } else if (info->attrs[HWSIM_ATTR_RADIO_NAME]) { 5205f79cbc77SKalle Valo hwname = kstrndup((char *)nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME]), 5206f79cbc77SKalle Valo nla_len(info->attrs[HWSIM_ATTR_RADIO_NAME]), 5207f79cbc77SKalle Valo GFP_KERNEL); 5208f79cbc77SKalle Valo if (!hwname) 5209f79cbc77SKalle Valo return -ENOMEM; 5210f79cbc77SKalle Valo } else 5211f79cbc77SKalle Valo return -EINVAL; 5212f79cbc77SKalle Valo 5213f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 5214f79cbc77SKalle Valo list_for_each_entry(data, &hwsim_radios, list) { 5215f79cbc77SKalle Valo if (idx >= 0) { 5216f79cbc77SKalle Valo if (data->idx != idx) 5217f79cbc77SKalle Valo continue; 5218f79cbc77SKalle Valo } else { 5219f79cbc77SKalle Valo if (!hwname || 5220f79cbc77SKalle Valo strcmp(hwname, wiphy_name(data->hw->wiphy))) 5221f79cbc77SKalle Valo continue; 5222f79cbc77SKalle Valo } 5223f79cbc77SKalle Valo 5224f79cbc77SKalle Valo if (!net_eq(wiphy_net(data->hw->wiphy), genl_info_net(info))) 5225f79cbc77SKalle Valo continue; 5226f79cbc77SKalle Valo 5227f79cbc77SKalle Valo list_del(&data->list); 5228f79cbc77SKalle Valo rhashtable_remove_fast(&hwsim_radios_rht, &data->rht, 5229f79cbc77SKalle Valo hwsim_rht_params); 5230f79cbc77SKalle Valo hwsim_radios_generation++; 5231f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 5232f79cbc77SKalle Valo mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy), 5233f79cbc77SKalle Valo info); 5234f79cbc77SKalle Valo kfree(hwname); 5235f79cbc77SKalle Valo return 0; 5236f79cbc77SKalle Valo } 5237f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 5238f79cbc77SKalle Valo 5239f79cbc77SKalle Valo kfree(hwname); 5240f79cbc77SKalle Valo return -ENODEV; 5241f79cbc77SKalle Valo } 5242f79cbc77SKalle Valo 5243f79cbc77SKalle Valo static int hwsim_get_radio_nl(struct sk_buff *msg, struct genl_info *info) 5244f79cbc77SKalle Valo { 5245f79cbc77SKalle Valo struct mac80211_hwsim_data *data; 5246f79cbc77SKalle Valo struct sk_buff *skb; 5247f79cbc77SKalle Valo int idx, res = -ENODEV; 5248f79cbc77SKalle Valo 5249f79cbc77SKalle Valo if (!info->attrs[HWSIM_ATTR_RADIO_ID]) 5250f79cbc77SKalle Valo return -EINVAL; 5251f79cbc77SKalle Valo idx = nla_get_u32(info->attrs[HWSIM_ATTR_RADIO_ID]); 5252f79cbc77SKalle Valo 5253f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 5254f79cbc77SKalle Valo list_for_each_entry(data, &hwsim_radios, list) { 5255f79cbc77SKalle Valo if (data->idx != idx) 5256f79cbc77SKalle Valo continue; 5257f79cbc77SKalle Valo 5258f79cbc77SKalle Valo if (!net_eq(wiphy_net(data->hw->wiphy), genl_info_net(info))) 5259f79cbc77SKalle Valo continue; 5260f79cbc77SKalle Valo 5261f79cbc77SKalle Valo skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); 5262f79cbc77SKalle Valo if (!skb) { 5263f79cbc77SKalle Valo res = -ENOMEM; 5264f79cbc77SKalle Valo goto out_err; 5265f79cbc77SKalle Valo } 5266f79cbc77SKalle Valo 5267f79cbc77SKalle Valo res = mac80211_hwsim_get_radio(skb, data, info->snd_portid, 5268f79cbc77SKalle Valo info->snd_seq, NULL, 0); 5269f79cbc77SKalle Valo if (res < 0) { 5270f79cbc77SKalle Valo nlmsg_free(skb); 5271f79cbc77SKalle Valo goto out_err; 5272f79cbc77SKalle Valo } 5273f79cbc77SKalle Valo 5274f79cbc77SKalle Valo res = genlmsg_reply(skb, info); 5275f79cbc77SKalle Valo break; 5276f79cbc77SKalle Valo } 5277f79cbc77SKalle Valo 5278f79cbc77SKalle Valo out_err: 5279f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 5280f79cbc77SKalle Valo 5281f79cbc77SKalle Valo return res; 5282f79cbc77SKalle Valo } 5283f79cbc77SKalle Valo 5284f79cbc77SKalle Valo static int hwsim_dump_radio_nl(struct sk_buff *skb, 5285f79cbc77SKalle Valo struct netlink_callback *cb) 5286f79cbc77SKalle Valo { 5287f79cbc77SKalle Valo int last_idx = cb->args[0] - 1; 5288f79cbc77SKalle Valo struct mac80211_hwsim_data *data = NULL; 5289f79cbc77SKalle Valo int res = 0; 5290f79cbc77SKalle Valo void *hdr; 5291f79cbc77SKalle Valo 5292f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 5293f79cbc77SKalle Valo cb->seq = hwsim_radios_generation; 5294f79cbc77SKalle Valo 5295f79cbc77SKalle Valo if (last_idx >= hwsim_radio_idx-1) 5296f79cbc77SKalle Valo goto done; 5297f79cbc77SKalle Valo 5298f79cbc77SKalle Valo list_for_each_entry(data, &hwsim_radios, list) { 5299f79cbc77SKalle Valo if (data->idx <= last_idx) 5300f79cbc77SKalle Valo continue; 5301f79cbc77SKalle Valo 5302f79cbc77SKalle Valo if (!net_eq(wiphy_net(data->hw->wiphy), sock_net(skb->sk))) 5303f79cbc77SKalle Valo continue; 5304f79cbc77SKalle Valo 5305f79cbc77SKalle Valo res = mac80211_hwsim_get_radio(skb, data, 5306f79cbc77SKalle Valo NETLINK_CB(cb->skb).portid, 5307f79cbc77SKalle Valo cb->nlh->nlmsg_seq, cb, 5308f79cbc77SKalle Valo NLM_F_MULTI); 5309f79cbc77SKalle Valo if (res < 0) 5310f79cbc77SKalle Valo break; 5311f79cbc77SKalle Valo 5312f79cbc77SKalle Valo last_idx = data->idx; 5313f79cbc77SKalle Valo } 5314f79cbc77SKalle Valo 5315f79cbc77SKalle Valo cb->args[0] = last_idx + 1; 5316f79cbc77SKalle Valo 5317f79cbc77SKalle Valo /* list changed, but no new element sent, set interrupted flag */ 5318f79cbc77SKalle Valo if (skb->len == 0 && cb->prev_seq && cb->seq != cb->prev_seq) { 5319f79cbc77SKalle Valo hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, 5320f79cbc77SKalle Valo cb->nlh->nlmsg_seq, &hwsim_genl_family, 5321f79cbc77SKalle Valo NLM_F_MULTI, HWSIM_CMD_GET_RADIO); 5322f79cbc77SKalle Valo if (hdr) { 5323f79cbc77SKalle Valo genl_dump_check_consistent(cb, hdr); 5324f79cbc77SKalle Valo genlmsg_end(skb, hdr); 5325f79cbc77SKalle Valo } else { 5326f79cbc77SKalle Valo res = -EMSGSIZE; 5327f79cbc77SKalle Valo } 5328f79cbc77SKalle Valo } 5329f79cbc77SKalle Valo 5330f79cbc77SKalle Valo done: 5331f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 5332f79cbc77SKalle Valo return res ?: skb->len; 5333f79cbc77SKalle Valo } 5334f79cbc77SKalle Valo 5335f79cbc77SKalle Valo /* Generic Netlink operations array */ 5336f79cbc77SKalle Valo static const struct genl_small_ops hwsim_ops[] = { 5337f79cbc77SKalle Valo { 5338f79cbc77SKalle Valo .cmd = HWSIM_CMD_REGISTER, 5339f79cbc77SKalle Valo .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 5340f79cbc77SKalle Valo .doit = hwsim_register_received_nl, 5341f79cbc77SKalle Valo .flags = GENL_UNS_ADMIN_PERM, 5342f79cbc77SKalle Valo }, 5343f79cbc77SKalle Valo { 5344f79cbc77SKalle Valo .cmd = HWSIM_CMD_FRAME, 5345f79cbc77SKalle Valo .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 5346f79cbc77SKalle Valo .doit = hwsim_cloned_frame_received_nl, 5347f79cbc77SKalle Valo }, 5348f79cbc77SKalle Valo { 5349f79cbc77SKalle Valo .cmd = HWSIM_CMD_TX_INFO_FRAME, 5350f79cbc77SKalle Valo .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 5351f79cbc77SKalle Valo .doit = hwsim_tx_info_frame_received_nl, 5352f79cbc77SKalle Valo }, 5353f79cbc77SKalle Valo { 5354f79cbc77SKalle Valo .cmd = HWSIM_CMD_NEW_RADIO, 5355f79cbc77SKalle Valo .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 5356f79cbc77SKalle Valo .doit = hwsim_new_radio_nl, 5357f79cbc77SKalle Valo .flags = GENL_UNS_ADMIN_PERM, 5358f79cbc77SKalle Valo }, 5359f79cbc77SKalle Valo { 5360f79cbc77SKalle Valo .cmd = HWSIM_CMD_DEL_RADIO, 5361f79cbc77SKalle Valo .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 5362f79cbc77SKalle Valo .doit = hwsim_del_radio_nl, 5363f79cbc77SKalle Valo .flags = GENL_UNS_ADMIN_PERM, 5364f79cbc77SKalle Valo }, 5365f79cbc77SKalle Valo { 5366f79cbc77SKalle Valo .cmd = HWSIM_CMD_GET_RADIO, 5367f79cbc77SKalle Valo .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 5368f79cbc77SKalle Valo .doit = hwsim_get_radio_nl, 5369f79cbc77SKalle Valo .dumpit = hwsim_dump_radio_nl, 5370f79cbc77SKalle Valo }, 5371f79cbc77SKalle Valo }; 5372f79cbc77SKalle Valo 5373f79cbc77SKalle Valo static struct genl_family hwsim_genl_family __ro_after_init = { 5374f79cbc77SKalle Valo .name = "MAC80211_HWSIM", 5375f79cbc77SKalle Valo .version = 1, 5376f79cbc77SKalle Valo .maxattr = HWSIM_ATTR_MAX, 5377f79cbc77SKalle Valo .policy = hwsim_genl_policy, 5378f79cbc77SKalle Valo .netnsok = true, 5379f79cbc77SKalle Valo .module = THIS_MODULE, 5380f79cbc77SKalle Valo .small_ops = hwsim_ops, 5381f79cbc77SKalle Valo .n_small_ops = ARRAY_SIZE(hwsim_ops), 5382f79cbc77SKalle Valo .resv_start_op = HWSIM_CMD_DEL_MAC_ADDR + 1, 5383f79cbc77SKalle Valo .mcgrps = hwsim_mcgrps, 5384f79cbc77SKalle Valo .n_mcgrps = ARRAY_SIZE(hwsim_mcgrps), 5385f79cbc77SKalle Valo }; 5386f79cbc77SKalle Valo 5387f79cbc77SKalle Valo static void remove_user_radios(u32 portid) 5388f79cbc77SKalle Valo { 5389f79cbc77SKalle Valo struct mac80211_hwsim_data *entry, *tmp; 5390f79cbc77SKalle Valo LIST_HEAD(list); 5391f79cbc77SKalle Valo 5392f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 5393f79cbc77SKalle Valo list_for_each_entry_safe(entry, tmp, &hwsim_radios, list) { 5394f79cbc77SKalle Valo if (entry->destroy_on_close && entry->portid == portid) { 5395f79cbc77SKalle Valo list_move(&entry->list, &list); 5396f79cbc77SKalle Valo rhashtable_remove_fast(&hwsim_radios_rht, &entry->rht, 5397f79cbc77SKalle Valo hwsim_rht_params); 5398f79cbc77SKalle Valo hwsim_radios_generation++; 5399f79cbc77SKalle Valo } 5400f79cbc77SKalle Valo } 5401f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 5402f79cbc77SKalle Valo 5403f79cbc77SKalle Valo list_for_each_entry_safe(entry, tmp, &list, list) { 5404f79cbc77SKalle Valo list_del(&entry->list); 5405f79cbc77SKalle Valo mac80211_hwsim_del_radio(entry, wiphy_name(entry->hw->wiphy), 5406f79cbc77SKalle Valo NULL); 5407f79cbc77SKalle Valo } 5408f79cbc77SKalle Valo } 5409f79cbc77SKalle Valo 5410f79cbc77SKalle Valo static int mac80211_hwsim_netlink_notify(struct notifier_block *nb, 5411f79cbc77SKalle Valo unsigned long state, 5412f79cbc77SKalle Valo void *_notify) 5413f79cbc77SKalle Valo { 5414f79cbc77SKalle Valo struct netlink_notify *notify = _notify; 5415f79cbc77SKalle Valo 5416f79cbc77SKalle Valo if (state != NETLINK_URELEASE) 5417f79cbc77SKalle Valo return NOTIFY_DONE; 5418f79cbc77SKalle Valo 5419f79cbc77SKalle Valo remove_user_radios(notify->portid); 5420f79cbc77SKalle Valo 5421f79cbc77SKalle Valo if (notify->portid == hwsim_net_get_wmediumd(notify->net)) { 5422f79cbc77SKalle Valo printk(KERN_INFO "mac80211_hwsim: wmediumd released netlink" 5423f79cbc77SKalle Valo " socket, switching to perfect channel medium\n"); 5424f79cbc77SKalle Valo hwsim_register_wmediumd(notify->net, 0); 5425f79cbc77SKalle Valo } 5426f79cbc77SKalle Valo return NOTIFY_DONE; 5427f79cbc77SKalle Valo 5428f79cbc77SKalle Valo } 5429f79cbc77SKalle Valo 5430f79cbc77SKalle Valo static struct notifier_block hwsim_netlink_notifier = { 5431f79cbc77SKalle Valo .notifier_call = mac80211_hwsim_netlink_notify, 5432f79cbc77SKalle Valo }; 5433f79cbc77SKalle Valo 5434f79cbc77SKalle Valo static int __init hwsim_init_netlink(void) 5435f79cbc77SKalle Valo { 5436f79cbc77SKalle Valo int rc; 5437f79cbc77SKalle Valo 5438f79cbc77SKalle Valo printk(KERN_INFO "mac80211_hwsim: initializing netlink\n"); 5439f79cbc77SKalle Valo 5440f79cbc77SKalle Valo rc = genl_register_family(&hwsim_genl_family); 5441f79cbc77SKalle Valo if (rc) 5442f79cbc77SKalle Valo goto failure; 5443f79cbc77SKalle Valo 5444f79cbc77SKalle Valo rc = netlink_register_notifier(&hwsim_netlink_notifier); 5445f79cbc77SKalle Valo if (rc) { 5446f79cbc77SKalle Valo genl_unregister_family(&hwsim_genl_family); 5447f79cbc77SKalle Valo goto failure; 5448f79cbc77SKalle Valo } 5449f79cbc77SKalle Valo 5450f79cbc77SKalle Valo return 0; 5451f79cbc77SKalle Valo 5452f79cbc77SKalle Valo failure: 5453f79cbc77SKalle Valo pr_debug("mac80211_hwsim: error occurred in %s\n", __func__); 5454f79cbc77SKalle Valo return -EINVAL; 5455f79cbc77SKalle Valo } 5456f79cbc77SKalle Valo 5457f79cbc77SKalle Valo static __net_init int hwsim_init_net(struct net *net) 5458f79cbc77SKalle Valo { 5459f79cbc77SKalle Valo return hwsim_net_set_netgroup(net); 5460f79cbc77SKalle Valo } 5461f79cbc77SKalle Valo 5462f79cbc77SKalle Valo static void __net_exit hwsim_exit_net(struct net *net) 5463f79cbc77SKalle Valo { 5464f79cbc77SKalle Valo struct mac80211_hwsim_data *data, *tmp; 5465f79cbc77SKalle Valo LIST_HEAD(list); 5466f79cbc77SKalle Valo 5467f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 5468f79cbc77SKalle Valo list_for_each_entry_safe(data, tmp, &hwsim_radios, list) { 5469f79cbc77SKalle Valo if (!net_eq(wiphy_net(data->hw->wiphy), net)) 5470f79cbc77SKalle Valo continue; 5471f79cbc77SKalle Valo 5472f79cbc77SKalle Valo /* Radios created in init_net are returned to init_net. */ 5473f79cbc77SKalle Valo if (data->netgroup == hwsim_net_get_netgroup(&init_net)) 5474f79cbc77SKalle Valo continue; 5475f79cbc77SKalle Valo 5476f79cbc77SKalle Valo list_move(&data->list, &list); 5477f79cbc77SKalle Valo rhashtable_remove_fast(&hwsim_radios_rht, &data->rht, 5478f79cbc77SKalle Valo hwsim_rht_params); 5479f79cbc77SKalle Valo hwsim_radios_generation++; 5480f79cbc77SKalle Valo } 5481f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 5482f79cbc77SKalle Valo 5483f79cbc77SKalle Valo list_for_each_entry_safe(data, tmp, &list, list) { 5484f79cbc77SKalle Valo list_del(&data->list); 5485f79cbc77SKalle Valo mac80211_hwsim_del_radio(data, 5486f79cbc77SKalle Valo wiphy_name(data->hw->wiphy), 5487f79cbc77SKalle Valo NULL); 5488f79cbc77SKalle Valo } 5489f79cbc77SKalle Valo 5490f79cbc77SKalle Valo ida_free(&hwsim_netgroup_ida, hwsim_net_get_netgroup(net)); 5491f79cbc77SKalle Valo } 5492f79cbc77SKalle Valo 5493f79cbc77SKalle Valo static struct pernet_operations hwsim_net_ops = { 5494f79cbc77SKalle Valo .init = hwsim_init_net, 5495f79cbc77SKalle Valo .exit = hwsim_exit_net, 5496f79cbc77SKalle Valo .id = &hwsim_net_id, 5497f79cbc77SKalle Valo .size = sizeof(struct hwsim_net), 5498f79cbc77SKalle Valo }; 5499f79cbc77SKalle Valo 5500f79cbc77SKalle Valo static void hwsim_exit_netlink(void) 5501f79cbc77SKalle Valo { 5502f79cbc77SKalle Valo /* unregister the notifier */ 5503f79cbc77SKalle Valo netlink_unregister_notifier(&hwsim_netlink_notifier); 5504f79cbc77SKalle Valo /* unregister the family */ 5505f79cbc77SKalle Valo genl_unregister_family(&hwsim_genl_family); 5506f79cbc77SKalle Valo } 5507f79cbc77SKalle Valo 5508f79cbc77SKalle Valo #if IS_REACHABLE(CONFIG_VIRTIO) 5509f79cbc77SKalle Valo static void hwsim_virtio_tx_done(struct virtqueue *vq) 5510f79cbc77SKalle Valo { 5511f79cbc77SKalle Valo unsigned int len; 5512f79cbc77SKalle Valo struct sk_buff *skb; 5513f79cbc77SKalle Valo unsigned long flags; 5514f79cbc77SKalle Valo 5515f79cbc77SKalle Valo spin_lock_irqsave(&hwsim_virtio_lock, flags); 5516f79cbc77SKalle Valo while ((skb = virtqueue_get_buf(vq, &len))) 5517f79cbc77SKalle Valo nlmsg_free(skb); 5518f79cbc77SKalle Valo spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 5519f79cbc77SKalle Valo } 5520f79cbc77SKalle Valo 5521f79cbc77SKalle Valo static int hwsim_virtio_handle_cmd(struct sk_buff *skb) 5522f79cbc77SKalle Valo { 5523f79cbc77SKalle Valo struct nlmsghdr *nlh; 5524f79cbc77SKalle Valo struct genlmsghdr *gnlh; 5525f79cbc77SKalle Valo struct nlattr *tb[HWSIM_ATTR_MAX + 1]; 5526f79cbc77SKalle Valo struct genl_info info = {}; 5527f79cbc77SKalle Valo int err; 5528f79cbc77SKalle Valo 5529f79cbc77SKalle Valo nlh = nlmsg_hdr(skb); 5530f79cbc77SKalle Valo gnlh = nlmsg_data(nlh); 5531f79cbc77SKalle Valo 5532f79cbc77SKalle Valo if (skb->len < nlh->nlmsg_len) 5533f79cbc77SKalle Valo return -EINVAL; 5534f79cbc77SKalle Valo 5535f79cbc77SKalle Valo err = genlmsg_parse(nlh, &hwsim_genl_family, tb, HWSIM_ATTR_MAX, 5536f79cbc77SKalle Valo hwsim_genl_policy, NULL); 5537f79cbc77SKalle Valo if (err) { 5538f79cbc77SKalle Valo pr_err_ratelimited("hwsim: genlmsg_parse returned %d\n", err); 5539f79cbc77SKalle Valo return err; 5540f79cbc77SKalle Valo } 5541f79cbc77SKalle Valo 5542f79cbc77SKalle Valo info.attrs = tb; 5543f79cbc77SKalle Valo 5544f79cbc77SKalle Valo switch (gnlh->cmd) { 5545f79cbc77SKalle Valo case HWSIM_CMD_FRAME: 5546f79cbc77SKalle Valo hwsim_cloned_frame_received_nl(skb, &info); 5547f79cbc77SKalle Valo break; 5548f79cbc77SKalle Valo case HWSIM_CMD_TX_INFO_FRAME: 5549f79cbc77SKalle Valo hwsim_tx_info_frame_received_nl(skb, &info); 5550f79cbc77SKalle Valo break; 5551f79cbc77SKalle Valo default: 5552f79cbc77SKalle Valo pr_err_ratelimited("hwsim: invalid cmd: %d\n", gnlh->cmd); 5553f79cbc77SKalle Valo return -EPROTO; 5554f79cbc77SKalle Valo } 5555f79cbc77SKalle Valo return 0; 5556f79cbc77SKalle Valo } 5557f79cbc77SKalle Valo 5558f79cbc77SKalle Valo static void hwsim_virtio_rx_work(struct work_struct *work) 5559f79cbc77SKalle Valo { 5560f79cbc77SKalle Valo struct virtqueue *vq; 5561f79cbc77SKalle Valo unsigned int len; 5562f79cbc77SKalle Valo struct sk_buff *skb; 5563f79cbc77SKalle Valo struct scatterlist sg[1]; 5564f79cbc77SKalle Valo int err; 5565f79cbc77SKalle Valo unsigned long flags; 5566f79cbc77SKalle Valo 5567f79cbc77SKalle Valo spin_lock_irqsave(&hwsim_virtio_lock, flags); 5568f79cbc77SKalle Valo if (!hwsim_virtio_enabled) 5569f79cbc77SKalle Valo goto out_unlock; 5570f79cbc77SKalle Valo 5571f79cbc77SKalle Valo skb = virtqueue_get_buf(hwsim_vqs[HWSIM_VQ_RX], &len); 5572f79cbc77SKalle Valo if (!skb) 5573f79cbc77SKalle Valo goto out_unlock; 5574f79cbc77SKalle Valo spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 5575f79cbc77SKalle Valo 5576f79cbc77SKalle Valo skb->data = skb->head; 5577f79cbc77SKalle Valo skb_reset_tail_pointer(skb); 5578f79cbc77SKalle Valo skb_put(skb, len); 5579f79cbc77SKalle Valo hwsim_virtio_handle_cmd(skb); 5580f79cbc77SKalle Valo 5581f79cbc77SKalle Valo spin_lock_irqsave(&hwsim_virtio_lock, flags); 5582f79cbc77SKalle Valo if (!hwsim_virtio_enabled) { 5583f79cbc77SKalle Valo nlmsg_free(skb); 5584f79cbc77SKalle Valo goto out_unlock; 5585f79cbc77SKalle Valo } 5586f79cbc77SKalle Valo vq = hwsim_vqs[HWSIM_VQ_RX]; 5587f79cbc77SKalle Valo sg_init_one(sg, skb->head, skb_end_offset(skb)); 5588f79cbc77SKalle Valo err = virtqueue_add_inbuf(vq, sg, 1, skb, GFP_ATOMIC); 5589f79cbc77SKalle Valo if (WARN(err, "virtqueue_add_inbuf returned %d\n", err)) 5590f79cbc77SKalle Valo nlmsg_free(skb); 5591f79cbc77SKalle Valo else 5592f79cbc77SKalle Valo virtqueue_kick(vq); 5593f79cbc77SKalle Valo schedule_work(&hwsim_virtio_rx); 5594f79cbc77SKalle Valo 5595f79cbc77SKalle Valo out_unlock: 5596f79cbc77SKalle Valo spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 5597f79cbc77SKalle Valo } 5598f79cbc77SKalle Valo 5599f79cbc77SKalle Valo static void hwsim_virtio_rx_done(struct virtqueue *vq) 5600f79cbc77SKalle Valo { 5601f79cbc77SKalle Valo schedule_work(&hwsim_virtio_rx); 5602f79cbc77SKalle Valo } 5603f79cbc77SKalle Valo 5604f79cbc77SKalle Valo static int init_vqs(struct virtio_device *vdev) 5605f79cbc77SKalle Valo { 5606f79cbc77SKalle Valo vq_callback_t *callbacks[HWSIM_NUM_VQS] = { 5607f79cbc77SKalle Valo [HWSIM_VQ_TX] = hwsim_virtio_tx_done, 5608f79cbc77SKalle Valo [HWSIM_VQ_RX] = hwsim_virtio_rx_done, 5609f79cbc77SKalle Valo }; 5610f79cbc77SKalle Valo const char *names[HWSIM_NUM_VQS] = { 5611f79cbc77SKalle Valo [HWSIM_VQ_TX] = "tx", 5612f79cbc77SKalle Valo [HWSIM_VQ_RX] = "rx", 5613f79cbc77SKalle Valo }; 5614f79cbc77SKalle Valo 5615f79cbc77SKalle Valo return virtio_find_vqs(vdev, HWSIM_NUM_VQS, 5616f79cbc77SKalle Valo hwsim_vqs, callbacks, names, NULL); 5617f79cbc77SKalle Valo } 5618f79cbc77SKalle Valo 5619f79cbc77SKalle Valo static int fill_vq(struct virtqueue *vq) 5620f79cbc77SKalle Valo { 5621f79cbc77SKalle Valo int i, err; 5622f79cbc77SKalle Valo struct sk_buff *skb; 5623f79cbc77SKalle Valo struct scatterlist sg[1]; 5624f79cbc77SKalle Valo 5625f79cbc77SKalle Valo for (i = 0; i < virtqueue_get_vring_size(vq); i++) { 5626f79cbc77SKalle Valo skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 5627f79cbc77SKalle Valo if (!skb) 5628f79cbc77SKalle Valo return -ENOMEM; 5629f79cbc77SKalle Valo 5630f79cbc77SKalle Valo sg_init_one(sg, skb->head, skb_end_offset(skb)); 5631f79cbc77SKalle Valo err = virtqueue_add_inbuf(vq, sg, 1, skb, GFP_KERNEL); 5632f79cbc77SKalle Valo if (err) { 5633f79cbc77SKalle Valo nlmsg_free(skb); 5634f79cbc77SKalle Valo return err; 5635f79cbc77SKalle Valo } 5636f79cbc77SKalle Valo } 5637f79cbc77SKalle Valo virtqueue_kick(vq); 5638f79cbc77SKalle Valo return 0; 5639f79cbc77SKalle Valo } 5640f79cbc77SKalle Valo 5641f79cbc77SKalle Valo static void remove_vqs(struct virtio_device *vdev) 5642f79cbc77SKalle Valo { 5643f79cbc77SKalle Valo int i; 5644f79cbc77SKalle Valo 5645f79cbc77SKalle Valo virtio_reset_device(vdev); 5646f79cbc77SKalle Valo 5647f79cbc77SKalle Valo for (i = 0; i < ARRAY_SIZE(hwsim_vqs); i++) { 5648f79cbc77SKalle Valo struct virtqueue *vq = hwsim_vqs[i]; 5649f79cbc77SKalle Valo struct sk_buff *skb; 5650f79cbc77SKalle Valo 5651f79cbc77SKalle Valo while ((skb = virtqueue_detach_unused_buf(vq))) 5652f79cbc77SKalle Valo nlmsg_free(skb); 5653f79cbc77SKalle Valo } 5654f79cbc77SKalle Valo 5655f79cbc77SKalle Valo vdev->config->del_vqs(vdev); 5656f79cbc77SKalle Valo } 5657f79cbc77SKalle Valo 5658f79cbc77SKalle Valo static int hwsim_virtio_probe(struct virtio_device *vdev) 5659f79cbc77SKalle Valo { 5660f79cbc77SKalle Valo int err; 5661f79cbc77SKalle Valo unsigned long flags; 5662f79cbc77SKalle Valo 5663f79cbc77SKalle Valo spin_lock_irqsave(&hwsim_virtio_lock, flags); 5664f79cbc77SKalle Valo if (hwsim_virtio_enabled) { 5665f79cbc77SKalle Valo spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 5666f79cbc77SKalle Valo return -EEXIST; 5667f79cbc77SKalle Valo } 5668f79cbc77SKalle Valo spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 5669f79cbc77SKalle Valo 5670f79cbc77SKalle Valo err = init_vqs(vdev); 5671f79cbc77SKalle Valo if (err) 5672f79cbc77SKalle Valo return err; 5673f79cbc77SKalle Valo 5674f79cbc77SKalle Valo virtio_device_ready(vdev); 5675f79cbc77SKalle Valo 5676f79cbc77SKalle Valo err = fill_vq(hwsim_vqs[HWSIM_VQ_RX]); 5677f79cbc77SKalle Valo if (err) 5678f79cbc77SKalle Valo goto out_remove; 5679f79cbc77SKalle Valo 5680f79cbc77SKalle Valo spin_lock_irqsave(&hwsim_virtio_lock, flags); 5681f79cbc77SKalle Valo hwsim_virtio_enabled = true; 5682f79cbc77SKalle Valo spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 5683f79cbc77SKalle Valo 5684f79cbc77SKalle Valo schedule_work(&hwsim_virtio_rx); 5685f79cbc77SKalle Valo return 0; 5686f79cbc77SKalle Valo 5687f79cbc77SKalle Valo out_remove: 5688f79cbc77SKalle Valo remove_vqs(vdev); 5689f79cbc77SKalle Valo return err; 5690f79cbc77SKalle Valo } 5691f79cbc77SKalle Valo 5692f79cbc77SKalle Valo static void hwsim_virtio_remove(struct virtio_device *vdev) 5693f79cbc77SKalle Valo { 5694f79cbc77SKalle Valo hwsim_virtio_enabled = false; 5695f79cbc77SKalle Valo 5696f79cbc77SKalle Valo cancel_work_sync(&hwsim_virtio_rx); 5697f79cbc77SKalle Valo 5698f79cbc77SKalle Valo remove_vqs(vdev); 5699f79cbc77SKalle Valo } 5700f79cbc77SKalle Valo 5701f79cbc77SKalle Valo /* MAC80211_HWSIM virtio device id table */ 5702f79cbc77SKalle Valo static const struct virtio_device_id id_table[] = { 5703f79cbc77SKalle Valo { VIRTIO_ID_MAC80211_HWSIM, VIRTIO_DEV_ANY_ID }, 5704f79cbc77SKalle Valo { 0 } 5705f79cbc77SKalle Valo }; 5706f79cbc77SKalle Valo MODULE_DEVICE_TABLE(virtio, id_table); 5707f79cbc77SKalle Valo 5708f79cbc77SKalle Valo static struct virtio_driver virtio_hwsim = { 5709f79cbc77SKalle Valo .driver.name = KBUILD_MODNAME, 5710f79cbc77SKalle Valo .driver.owner = THIS_MODULE, 5711f79cbc77SKalle Valo .id_table = id_table, 5712f79cbc77SKalle Valo .probe = hwsim_virtio_probe, 5713f79cbc77SKalle Valo .remove = hwsim_virtio_remove, 5714f79cbc77SKalle Valo }; 5715f79cbc77SKalle Valo 5716f79cbc77SKalle Valo static int hwsim_register_virtio_driver(void) 5717f79cbc77SKalle Valo { 5718f79cbc77SKalle Valo return register_virtio_driver(&virtio_hwsim); 5719f79cbc77SKalle Valo } 5720f79cbc77SKalle Valo 5721f79cbc77SKalle Valo static void hwsim_unregister_virtio_driver(void) 5722f79cbc77SKalle Valo { 5723f79cbc77SKalle Valo unregister_virtio_driver(&virtio_hwsim); 5724f79cbc77SKalle Valo } 5725f79cbc77SKalle Valo #else 5726f79cbc77SKalle Valo static inline int hwsim_register_virtio_driver(void) 5727f79cbc77SKalle Valo { 5728f79cbc77SKalle Valo return 0; 5729f79cbc77SKalle Valo } 5730f79cbc77SKalle Valo 5731f79cbc77SKalle Valo static inline void hwsim_unregister_virtio_driver(void) 5732f79cbc77SKalle Valo { 5733f79cbc77SKalle Valo } 5734f79cbc77SKalle Valo #endif 5735f79cbc77SKalle Valo 5736f79cbc77SKalle Valo static int __init init_mac80211_hwsim(void) 5737f79cbc77SKalle Valo { 5738f79cbc77SKalle Valo int i, err; 5739f79cbc77SKalle Valo 5740f79cbc77SKalle Valo if (radios < 0 || radios > 100) 5741f79cbc77SKalle Valo return -EINVAL; 5742f79cbc77SKalle Valo 5743f79cbc77SKalle Valo if (channels < 1) 5744f79cbc77SKalle Valo return -EINVAL; 5745f79cbc77SKalle Valo 5746f79cbc77SKalle Valo err = rhashtable_init(&hwsim_radios_rht, &hwsim_rht_params); 5747f79cbc77SKalle Valo if (err) 5748f79cbc77SKalle Valo return err; 5749f79cbc77SKalle Valo 5750f79cbc77SKalle Valo err = register_pernet_device(&hwsim_net_ops); 5751f79cbc77SKalle Valo if (err) 5752f79cbc77SKalle Valo goto out_free_rht; 5753f79cbc77SKalle Valo 5754f79cbc77SKalle Valo err = platform_driver_register(&mac80211_hwsim_driver); 5755f79cbc77SKalle Valo if (err) 5756f79cbc77SKalle Valo goto out_unregister_pernet; 5757f79cbc77SKalle Valo 5758f79cbc77SKalle Valo err = hwsim_init_netlink(); 5759f79cbc77SKalle Valo if (err) 5760f79cbc77SKalle Valo goto out_unregister_driver; 5761f79cbc77SKalle Valo 5762f79cbc77SKalle Valo err = hwsim_register_virtio_driver(); 5763f79cbc77SKalle Valo if (err) 5764f79cbc77SKalle Valo goto out_exit_netlink; 5765f79cbc77SKalle Valo 5766f79cbc77SKalle Valo hwsim_class = class_create(THIS_MODULE, "mac80211_hwsim"); 5767f79cbc77SKalle Valo if (IS_ERR(hwsim_class)) { 5768f79cbc77SKalle Valo err = PTR_ERR(hwsim_class); 5769f79cbc77SKalle Valo goto out_exit_virtio; 5770f79cbc77SKalle Valo } 5771f79cbc77SKalle Valo 5772f79cbc77SKalle Valo hwsim_init_s1g_channels(hwsim_channels_s1g); 5773f79cbc77SKalle Valo 5774f79cbc77SKalle Valo for (i = 0; i < radios; i++) { 5775f79cbc77SKalle Valo struct hwsim_new_radio_params param = { 0 }; 5776f79cbc77SKalle Valo 5777f79cbc77SKalle Valo param.channels = channels; 5778f79cbc77SKalle Valo 5779f79cbc77SKalle Valo switch (regtest) { 5780f79cbc77SKalle Valo case HWSIM_REGTEST_DIFF_COUNTRY: 5781f79cbc77SKalle Valo if (i < ARRAY_SIZE(hwsim_alpha2s)) 5782f79cbc77SKalle Valo param.reg_alpha2 = hwsim_alpha2s[i]; 5783f79cbc77SKalle Valo break; 5784f79cbc77SKalle Valo case HWSIM_REGTEST_DRIVER_REG_FOLLOW: 5785f79cbc77SKalle Valo if (!i) 5786f79cbc77SKalle Valo param.reg_alpha2 = hwsim_alpha2s[0]; 5787f79cbc77SKalle Valo break; 5788f79cbc77SKalle Valo case HWSIM_REGTEST_STRICT_ALL: 5789f79cbc77SKalle Valo param.reg_strict = true; 5790f79cbc77SKalle Valo fallthrough; 5791f79cbc77SKalle Valo case HWSIM_REGTEST_DRIVER_REG_ALL: 5792f79cbc77SKalle Valo param.reg_alpha2 = hwsim_alpha2s[0]; 5793f79cbc77SKalle Valo break; 5794f79cbc77SKalle Valo case HWSIM_REGTEST_WORLD_ROAM: 5795f79cbc77SKalle Valo if (i == 0) 5796f79cbc77SKalle Valo param.regd = &hwsim_world_regdom_custom_01; 5797f79cbc77SKalle Valo break; 5798f79cbc77SKalle Valo case HWSIM_REGTEST_CUSTOM_WORLD: 5799f79cbc77SKalle Valo param.regd = &hwsim_world_regdom_custom_01; 5800f79cbc77SKalle Valo break; 5801f79cbc77SKalle Valo case HWSIM_REGTEST_CUSTOM_WORLD_2: 5802f79cbc77SKalle Valo if (i == 0) 5803f79cbc77SKalle Valo param.regd = &hwsim_world_regdom_custom_01; 5804f79cbc77SKalle Valo else if (i == 1) 5805f79cbc77SKalle Valo param.regd = &hwsim_world_regdom_custom_02; 5806f79cbc77SKalle Valo break; 5807f79cbc77SKalle Valo case HWSIM_REGTEST_STRICT_FOLLOW: 5808f79cbc77SKalle Valo if (i == 0) { 5809f79cbc77SKalle Valo param.reg_strict = true; 5810f79cbc77SKalle Valo param.reg_alpha2 = hwsim_alpha2s[0]; 5811f79cbc77SKalle Valo } 5812f79cbc77SKalle Valo break; 5813f79cbc77SKalle Valo case HWSIM_REGTEST_STRICT_AND_DRIVER_REG: 5814f79cbc77SKalle Valo if (i == 0) { 5815f79cbc77SKalle Valo param.reg_strict = true; 5816f79cbc77SKalle Valo param.reg_alpha2 = hwsim_alpha2s[0]; 5817f79cbc77SKalle Valo } else if (i == 1) { 5818f79cbc77SKalle Valo param.reg_alpha2 = hwsim_alpha2s[1]; 5819f79cbc77SKalle Valo } 5820f79cbc77SKalle Valo break; 5821f79cbc77SKalle Valo case HWSIM_REGTEST_ALL: 5822f79cbc77SKalle Valo switch (i) { 5823f79cbc77SKalle Valo case 0: 5824f79cbc77SKalle Valo param.regd = &hwsim_world_regdom_custom_01; 5825f79cbc77SKalle Valo break; 5826f79cbc77SKalle Valo case 1: 5827f79cbc77SKalle Valo param.regd = &hwsim_world_regdom_custom_02; 5828f79cbc77SKalle Valo break; 5829f79cbc77SKalle Valo case 2: 5830f79cbc77SKalle Valo param.reg_alpha2 = hwsim_alpha2s[0]; 5831f79cbc77SKalle Valo break; 5832f79cbc77SKalle Valo case 3: 5833f79cbc77SKalle Valo param.reg_alpha2 = hwsim_alpha2s[1]; 5834f79cbc77SKalle Valo break; 5835f79cbc77SKalle Valo case 4: 5836f79cbc77SKalle Valo param.reg_strict = true; 5837f79cbc77SKalle Valo param.reg_alpha2 = hwsim_alpha2s[2]; 5838f79cbc77SKalle Valo break; 5839f79cbc77SKalle Valo } 5840f79cbc77SKalle Valo break; 5841f79cbc77SKalle Valo default: 5842f79cbc77SKalle Valo break; 5843f79cbc77SKalle Valo } 5844f79cbc77SKalle Valo 5845f79cbc77SKalle Valo param.p2p_device = support_p2p_device; 5846f79cbc77SKalle Valo param.mlo = mlo; 5847f79cbc77SKalle Valo param.use_chanctx = channels > 1 || mlo; 5848f79cbc77SKalle Valo param.iftypes = HWSIM_IFTYPE_SUPPORT_MASK; 5849f79cbc77SKalle Valo if (param.p2p_device) 5850f79cbc77SKalle Valo param.iftypes |= BIT(NL80211_IFTYPE_P2P_DEVICE); 5851f79cbc77SKalle Valo 5852f79cbc77SKalle Valo err = mac80211_hwsim_new_radio(NULL, ¶m); 5853f79cbc77SKalle Valo if (err < 0) 5854f79cbc77SKalle Valo goto out_free_radios; 5855f79cbc77SKalle Valo } 5856f79cbc77SKalle Valo 5857f79cbc77SKalle Valo hwsim_mon = alloc_netdev(0, "hwsim%d", NET_NAME_UNKNOWN, 5858f79cbc77SKalle Valo hwsim_mon_setup); 5859f79cbc77SKalle Valo if (hwsim_mon == NULL) { 5860f79cbc77SKalle Valo err = -ENOMEM; 5861f79cbc77SKalle Valo goto out_free_radios; 5862f79cbc77SKalle Valo } 5863f79cbc77SKalle Valo 5864f79cbc77SKalle Valo rtnl_lock(); 5865f79cbc77SKalle Valo err = dev_alloc_name(hwsim_mon, hwsim_mon->name); 5866f79cbc77SKalle Valo if (err < 0) { 5867f79cbc77SKalle Valo rtnl_unlock(); 5868f79cbc77SKalle Valo goto out_free_mon; 5869f79cbc77SKalle Valo } 5870f79cbc77SKalle Valo 5871f79cbc77SKalle Valo err = register_netdevice(hwsim_mon); 5872f79cbc77SKalle Valo if (err < 0) { 5873f79cbc77SKalle Valo rtnl_unlock(); 5874f79cbc77SKalle Valo goto out_free_mon; 5875f79cbc77SKalle Valo } 5876f79cbc77SKalle Valo rtnl_unlock(); 5877f79cbc77SKalle Valo 5878f79cbc77SKalle Valo return 0; 5879f79cbc77SKalle Valo 5880f79cbc77SKalle Valo out_free_mon: 5881f79cbc77SKalle Valo free_netdev(hwsim_mon); 5882f79cbc77SKalle Valo out_free_radios: 5883f79cbc77SKalle Valo mac80211_hwsim_free(); 5884f79cbc77SKalle Valo out_exit_virtio: 5885f79cbc77SKalle Valo hwsim_unregister_virtio_driver(); 5886f79cbc77SKalle Valo out_exit_netlink: 5887f79cbc77SKalle Valo hwsim_exit_netlink(); 5888f79cbc77SKalle Valo out_unregister_driver: 5889f79cbc77SKalle Valo platform_driver_unregister(&mac80211_hwsim_driver); 5890f79cbc77SKalle Valo out_unregister_pernet: 5891f79cbc77SKalle Valo unregister_pernet_device(&hwsim_net_ops); 5892f79cbc77SKalle Valo out_free_rht: 5893f79cbc77SKalle Valo rhashtable_destroy(&hwsim_radios_rht); 5894f79cbc77SKalle Valo return err; 5895f79cbc77SKalle Valo } 5896f79cbc77SKalle Valo module_init(init_mac80211_hwsim); 5897f79cbc77SKalle Valo 5898f79cbc77SKalle Valo static void __exit exit_mac80211_hwsim(void) 5899f79cbc77SKalle Valo { 5900f79cbc77SKalle Valo pr_debug("mac80211_hwsim: unregister radios\n"); 5901f79cbc77SKalle Valo 5902f79cbc77SKalle Valo hwsim_unregister_virtio_driver(); 5903f79cbc77SKalle Valo hwsim_exit_netlink(); 5904f79cbc77SKalle Valo 5905f79cbc77SKalle Valo mac80211_hwsim_free(); 5906f79cbc77SKalle Valo 5907f79cbc77SKalle Valo rhashtable_destroy(&hwsim_radios_rht); 5908f79cbc77SKalle Valo unregister_netdev(hwsim_mon); 5909f79cbc77SKalle Valo platform_driver_unregister(&mac80211_hwsim_driver); 5910f79cbc77SKalle Valo unregister_pernet_device(&hwsim_net_ops); 5911f79cbc77SKalle Valo } 5912f79cbc77SKalle Valo module_exit(exit_mac80211_hwsim); 5913