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 72292d13386SJaewan Kim /* only used when pmsr capability is supplied */ 72392d13386SJaewan Kim struct cfg80211_pmsr_capabilities pmsr_capa; 7245530c04cSJaewan Kim struct cfg80211_pmsr_request *pmsr_request; 7255530c04cSJaewan Kim struct wireless_dev *pmsr_request_wdev; 72692d13386SJaewan Kim 727f79cbc77SKalle Valo struct mac80211_hwsim_link_data link_data[IEEE80211_MLD_MAX_NUM_LINKS]; 728f79cbc77SKalle Valo }; 729f79cbc77SKalle Valo 730f79cbc77SKalle Valo static const struct rhashtable_params hwsim_rht_params = { 731f79cbc77SKalle Valo .nelem_hint = 2, 732f79cbc77SKalle Valo .automatic_shrinking = true, 733f79cbc77SKalle Valo .key_len = ETH_ALEN, 734f79cbc77SKalle Valo .key_offset = offsetof(struct mac80211_hwsim_data, addresses[1]), 735f79cbc77SKalle Valo .head_offset = offsetof(struct mac80211_hwsim_data, rht), 736f79cbc77SKalle Valo }; 737f79cbc77SKalle Valo 738f79cbc77SKalle Valo struct hwsim_radiotap_hdr { 739f79cbc77SKalle Valo struct ieee80211_radiotap_header hdr; 740f79cbc77SKalle Valo __le64 rt_tsft; 741f79cbc77SKalle Valo u8 rt_flags; 742f79cbc77SKalle Valo u8 rt_rate; 743f79cbc77SKalle Valo __le16 rt_channel; 744f79cbc77SKalle Valo __le16 rt_chbitmask; 745f79cbc77SKalle Valo } __packed; 746f79cbc77SKalle Valo 747f79cbc77SKalle Valo struct hwsim_radiotap_ack_hdr { 748f79cbc77SKalle Valo struct ieee80211_radiotap_header hdr; 749f79cbc77SKalle Valo u8 rt_flags; 750f79cbc77SKalle Valo u8 pad; 751f79cbc77SKalle Valo __le16 rt_channel; 752f79cbc77SKalle Valo __le16 rt_chbitmask; 753f79cbc77SKalle Valo } __packed; 754f79cbc77SKalle Valo 755f79cbc77SKalle Valo /* MAC80211_HWSIM netlink family */ 756f79cbc77SKalle Valo static struct genl_family hwsim_genl_family; 757f79cbc77SKalle Valo 758f79cbc77SKalle Valo enum hwsim_multicast_groups { 759f79cbc77SKalle Valo HWSIM_MCGRP_CONFIG, 760f79cbc77SKalle Valo }; 761f79cbc77SKalle Valo 762f79cbc77SKalle Valo static const struct genl_multicast_group hwsim_mcgrps[] = { 763f79cbc77SKalle Valo [HWSIM_MCGRP_CONFIG] = { .name = "config", }, 764f79cbc77SKalle Valo }; 765f79cbc77SKalle Valo 766f79cbc77SKalle Valo /* MAC80211_HWSIM netlink policy */ 767f79cbc77SKalle Valo 76892d13386SJaewan Kim static const struct nla_policy 76992d13386SJaewan Kim hwsim_ftm_capa_policy[NL80211_PMSR_FTM_CAPA_ATTR_MAX + 1] = { 77092d13386SJaewan Kim [NL80211_PMSR_FTM_CAPA_ATTR_ASAP] = { .type = NLA_FLAG }, 77192d13386SJaewan Kim [NL80211_PMSR_FTM_CAPA_ATTR_NON_ASAP] = { .type = NLA_FLAG }, 77292d13386SJaewan Kim [NL80211_PMSR_FTM_CAPA_ATTR_REQ_LCI] = { .type = NLA_FLAG }, 77392d13386SJaewan Kim [NL80211_PMSR_FTM_CAPA_ATTR_REQ_CIVICLOC] = { .type = NLA_FLAG }, 77492d13386SJaewan Kim [NL80211_PMSR_FTM_CAPA_ATTR_PREAMBLES] = { .type = NLA_U32 }, 77592d13386SJaewan Kim [NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS] = { .type = NLA_U32 }, 77692d13386SJaewan Kim [NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT] = NLA_POLICY_MAX(NLA_U8, 15), 77792d13386SJaewan Kim [NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST] = NLA_POLICY_MAX(NLA_U8, 31), 77892d13386SJaewan Kim [NL80211_PMSR_FTM_CAPA_ATTR_TRIGGER_BASED] = { .type = NLA_FLAG }, 77992d13386SJaewan Kim [NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED] = { .type = NLA_FLAG }, 78092d13386SJaewan Kim }; 78192d13386SJaewan Kim 78292d13386SJaewan Kim static const struct nla_policy 78392d13386SJaewan Kim hwsim_pmsr_capa_type_policy[NL80211_PMSR_TYPE_MAX + 1] = { 78492d13386SJaewan Kim [NL80211_PMSR_TYPE_FTM] = NLA_POLICY_NESTED(hwsim_ftm_capa_policy), 78592d13386SJaewan Kim }; 78692d13386SJaewan Kim 78792d13386SJaewan Kim static const struct nla_policy 78892d13386SJaewan Kim hwsim_pmsr_capa_policy[NL80211_PMSR_ATTR_MAX + 1] = { 78992d13386SJaewan Kim [NL80211_PMSR_ATTR_MAX_PEERS] = { .type = NLA_U32 }, 79092d13386SJaewan Kim [NL80211_PMSR_ATTR_REPORT_AP_TSF] = { .type = NLA_FLAG }, 79192d13386SJaewan Kim [NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR] = { .type = NLA_FLAG }, 79292d13386SJaewan Kim [NL80211_PMSR_ATTR_TYPE_CAPA] = NLA_POLICY_NESTED(hwsim_pmsr_capa_type_policy), 79392d13386SJaewan Kim [NL80211_PMSR_ATTR_PEERS] = { .type = NLA_REJECT }, // only for request. 79492d13386SJaewan Kim }; 79592d13386SJaewan Kim 796f79cbc77SKalle Valo static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = { 797f79cbc77SKalle Valo [HWSIM_ATTR_ADDR_RECEIVER] = NLA_POLICY_ETH_ADDR_COMPAT, 798f79cbc77SKalle Valo [HWSIM_ATTR_ADDR_TRANSMITTER] = NLA_POLICY_ETH_ADDR_COMPAT, 799f79cbc77SKalle Valo [HWSIM_ATTR_FRAME] = { .type = NLA_BINARY, 800f79cbc77SKalle Valo .len = IEEE80211_MAX_DATA_LEN }, 801f79cbc77SKalle Valo [HWSIM_ATTR_FLAGS] = { .type = NLA_U32 }, 802f79cbc77SKalle Valo [HWSIM_ATTR_RX_RATE] = { .type = NLA_U32 }, 803f79cbc77SKalle Valo [HWSIM_ATTR_SIGNAL] = { .type = NLA_U32 }, 804f79cbc77SKalle Valo [HWSIM_ATTR_TX_INFO] = { .type = NLA_BINARY, 805f79cbc77SKalle Valo .len = IEEE80211_TX_MAX_RATES * 806f79cbc77SKalle Valo sizeof(struct hwsim_tx_rate)}, 807f79cbc77SKalle Valo [HWSIM_ATTR_COOKIE] = { .type = NLA_U64 }, 808f79cbc77SKalle Valo [HWSIM_ATTR_CHANNELS] = { .type = NLA_U32 }, 809f79cbc77SKalle Valo [HWSIM_ATTR_RADIO_ID] = { .type = NLA_U32 }, 810f79cbc77SKalle Valo [HWSIM_ATTR_REG_HINT_ALPHA2] = { .type = NLA_STRING, .len = 2 }, 811f79cbc77SKalle Valo [HWSIM_ATTR_REG_CUSTOM_REG] = { .type = NLA_U32 }, 812f79cbc77SKalle Valo [HWSIM_ATTR_REG_STRICT_REG] = { .type = NLA_FLAG }, 813f79cbc77SKalle Valo [HWSIM_ATTR_SUPPORT_P2P_DEVICE] = { .type = NLA_FLAG }, 814f79cbc77SKalle Valo [HWSIM_ATTR_USE_CHANCTX] = { .type = NLA_FLAG }, 815f79cbc77SKalle Valo [HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE] = { .type = NLA_FLAG }, 816f79cbc77SKalle Valo [HWSIM_ATTR_RADIO_NAME] = { .type = NLA_STRING }, 817f79cbc77SKalle Valo [HWSIM_ATTR_NO_VIF] = { .type = NLA_FLAG }, 818f79cbc77SKalle Valo [HWSIM_ATTR_FREQ] = { .type = NLA_U32 }, 819f79cbc77SKalle Valo [HWSIM_ATTR_TX_INFO_FLAGS] = { .type = NLA_BINARY }, 820f79cbc77SKalle Valo [HWSIM_ATTR_PERM_ADDR] = NLA_POLICY_ETH_ADDR_COMPAT, 821f79cbc77SKalle Valo [HWSIM_ATTR_IFTYPE_SUPPORT] = { .type = NLA_U32 }, 822f79cbc77SKalle Valo [HWSIM_ATTR_CIPHER_SUPPORT] = { .type = NLA_BINARY }, 823f79cbc77SKalle Valo [HWSIM_ATTR_MLO_SUPPORT] = { .type = NLA_FLAG }, 82492d13386SJaewan Kim [HWSIM_ATTR_PMSR_SUPPORT] = NLA_POLICY_NESTED(hwsim_pmsr_capa_policy), 825f79cbc77SKalle Valo }; 826f79cbc77SKalle Valo 827f79cbc77SKalle Valo #if IS_REACHABLE(CONFIG_VIRTIO) 828f79cbc77SKalle Valo 829f79cbc77SKalle Valo /* MAC80211_HWSIM virtio queues */ 830f79cbc77SKalle Valo static struct virtqueue *hwsim_vqs[HWSIM_NUM_VQS]; 831f79cbc77SKalle Valo static bool hwsim_virtio_enabled; 832f79cbc77SKalle Valo static DEFINE_SPINLOCK(hwsim_virtio_lock); 833f79cbc77SKalle Valo 834f79cbc77SKalle Valo static void hwsim_virtio_rx_work(struct work_struct *work); 835f79cbc77SKalle Valo static DECLARE_WORK(hwsim_virtio_rx, hwsim_virtio_rx_work); 836f79cbc77SKalle Valo 837f79cbc77SKalle Valo static int hwsim_tx_virtio(struct mac80211_hwsim_data *data, 838f79cbc77SKalle Valo struct sk_buff *skb) 839f79cbc77SKalle Valo { 840f79cbc77SKalle Valo struct scatterlist sg[1]; 841f79cbc77SKalle Valo unsigned long flags; 842f79cbc77SKalle Valo int err; 843f79cbc77SKalle Valo 844f79cbc77SKalle Valo spin_lock_irqsave(&hwsim_virtio_lock, flags); 845f79cbc77SKalle Valo if (!hwsim_virtio_enabled) { 846f79cbc77SKalle Valo err = -ENODEV; 847f79cbc77SKalle Valo goto out_free; 848f79cbc77SKalle Valo } 849f79cbc77SKalle Valo 850f79cbc77SKalle Valo sg_init_one(sg, skb->head, skb_end_offset(skb)); 851f79cbc77SKalle Valo err = virtqueue_add_outbuf(hwsim_vqs[HWSIM_VQ_TX], sg, 1, skb, 852f79cbc77SKalle Valo GFP_ATOMIC); 853f79cbc77SKalle Valo if (err) 854f79cbc77SKalle Valo goto out_free; 855f79cbc77SKalle Valo virtqueue_kick(hwsim_vqs[HWSIM_VQ_TX]); 856f79cbc77SKalle Valo spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 857f79cbc77SKalle Valo return 0; 858f79cbc77SKalle Valo 859f79cbc77SKalle Valo out_free: 860f79cbc77SKalle Valo spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 861f79cbc77SKalle Valo nlmsg_free(skb); 862f79cbc77SKalle Valo return err; 863f79cbc77SKalle Valo } 864f79cbc77SKalle Valo #else 865f79cbc77SKalle Valo /* cause a linker error if this ends up being needed */ 866f79cbc77SKalle Valo extern int hwsim_tx_virtio(struct mac80211_hwsim_data *data, 867f79cbc77SKalle Valo struct sk_buff *skb); 868f79cbc77SKalle Valo #define hwsim_virtio_enabled false 869f79cbc77SKalle Valo #endif 870f79cbc77SKalle Valo 871f79cbc77SKalle Valo static int hwsim_get_chanwidth(enum nl80211_chan_width bw) 872f79cbc77SKalle Valo { 873f79cbc77SKalle Valo switch (bw) { 874f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_20_NOHT: 875f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_20: 876f79cbc77SKalle Valo return 20; 877f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_40: 878f79cbc77SKalle Valo return 40; 879f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_80: 880f79cbc77SKalle Valo return 80; 881f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_80P80: 882f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_160: 883f79cbc77SKalle Valo return 160; 884f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_320: 885f79cbc77SKalle Valo return 320; 886f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_5: 887f79cbc77SKalle Valo return 5; 888f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_10: 889f79cbc77SKalle Valo return 10; 890f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_1: 891f79cbc77SKalle Valo return 1; 892f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_2: 893f79cbc77SKalle Valo return 2; 894f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_4: 895f79cbc77SKalle Valo return 4; 896f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_8: 897f79cbc77SKalle Valo return 8; 898f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_16: 899f79cbc77SKalle Valo return 16; 900f79cbc77SKalle Valo } 901f79cbc77SKalle Valo 902f79cbc77SKalle Valo return INT_MAX; 903f79cbc77SKalle Valo } 904f79cbc77SKalle Valo 905f79cbc77SKalle Valo static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, 906f79cbc77SKalle Valo struct sk_buff *skb, 907f79cbc77SKalle Valo struct ieee80211_channel *chan); 908f79cbc77SKalle Valo 909f79cbc77SKalle Valo /* sysfs attributes */ 910f79cbc77SKalle Valo static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) 911f79cbc77SKalle Valo { 912f79cbc77SKalle Valo struct mac80211_hwsim_data *data = dat; 913f79cbc77SKalle Valo struct hwsim_vif_priv *vp = (void *)vif->drv_priv; 914f79cbc77SKalle Valo struct sk_buff *skb; 915f79cbc77SKalle Valo struct ieee80211_pspoll *pspoll; 916f79cbc77SKalle Valo 917f79cbc77SKalle Valo if (!vp->assoc) 918f79cbc77SKalle Valo return; 919f79cbc77SKalle Valo 920f79cbc77SKalle Valo wiphy_dbg(data->hw->wiphy, 921f79cbc77SKalle Valo "%s: send PS-Poll to %pM for aid %d\n", 922f79cbc77SKalle Valo __func__, vp->bssid, vp->aid); 923f79cbc77SKalle Valo 924f79cbc77SKalle Valo skb = dev_alloc_skb(sizeof(*pspoll)); 925f79cbc77SKalle Valo if (!skb) 926f79cbc77SKalle Valo return; 927f79cbc77SKalle Valo pspoll = skb_put(skb, sizeof(*pspoll)); 928f79cbc77SKalle Valo pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | 929f79cbc77SKalle Valo IEEE80211_STYPE_PSPOLL | 930f79cbc77SKalle Valo IEEE80211_FCTL_PM); 931f79cbc77SKalle Valo pspoll->aid = cpu_to_le16(0xc000 | vp->aid); 932f79cbc77SKalle Valo memcpy(pspoll->bssid, vp->bssid, ETH_ALEN); 933f79cbc77SKalle Valo memcpy(pspoll->ta, mac, ETH_ALEN); 934f79cbc77SKalle Valo 935f79cbc77SKalle Valo rcu_read_lock(); 936f79cbc77SKalle Valo mac80211_hwsim_tx_frame(data->hw, skb, 937f79cbc77SKalle Valo rcu_dereference(vif->bss_conf.chanctx_conf)->def.chan); 938f79cbc77SKalle Valo rcu_read_unlock(); 939f79cbc77SKalle Valo } 940f79cbc77SKalle Valo 941f79cbc77SKalle Valo static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, 942f79cbc77SKalle Valo struct ieee80211_vif *vif, int ps) 943f79cbc77SKalle Valo { 944f79cbc77SKalle Valo struct hwsim_vif_priv *vp = (void *)vif->drv_priv; 945f79cbc77SKalle Valo struct sk_buff *skb; 946f79cbc77SKalle Valo struct ieee80211_hdr *hdr; 947f79cbc77SKalle Valo struct ieee80211_tx_info *cb; 948f79cbc77SKalle Valo 949f79cbc77SKalle Valo if (!vp->assoc) 950f79cbc77SKalle Valo return; 951f79cbc77SKalle Valo 952f79cbc77SKalle Valo wiphy_dbg(data->hw->wiphy, 953f79cbc77SKalle Valo "%s: send data::nullfunc to %pM ps=%d\n", 954f79cbc77SKalle Valo __func__, vp->bssid, ps); 955f79cbc77SKalle Valo 956f79cbc77SKalle Valo skb = dev_alloc_skb(sizeof(*hdr)); 957f79cbc77SKalle Valo if (!skb) 958f79cbc77SKalle Valo return; 959f79cbc77SKalle Valo hdr = skb_put(skb, sizeof(*hdr) - ETH_ALEN); 960f79cbc77SKalle Valo hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | 961f79cbc77SKalle Valo IEEE80211_STYPE_NULLFUNC | 962f79cbc77SKalle Valo IEEE80211_FCTL_TODS | 963f79cbc77SKalle Valo (ps ? IEEE80211_FCTL_PM : 0)); 964f79cbc77SKalle Valo hdr->duration_id = cpu_to_le16(0); 965f79cbc77SKalle Valo memcpy(hdr->addr1, vp->bssid, ETH_ALEN); 966f79cbc77SKalle Valo memcpy(hdr->addr2, mac, ETH_ALEN); 967f79cbc77SKalle Valo memcpy(hdr->addr3, vp->bssid, ETH_ALEN); 968f79cbc77SKalle Valo 969f79cbc77SKalle Valo cb = IEEE80211_SKB_CB(skb); 970f79cbc77SKalle Valo cb->control.rates[0].count = 1; 971f79cbc77SKalle Valo cb->control.rates[1].idx = -1; 972f79cbc77SKalle Valo 973f79cbc77SKalle Valo rcu_read_lock(); 974f79cbc77SKalle Valo mac80211_hwsim_tx_frame(data->hw, skb, 975f79cbc77SKalle Valo rcu_dereference(vif->bss_conf.chanctx_conf)->def.chan); 976f79cbc77SKalle Valo rcu_read_unlock(); 977f79cbc77SKalle Valo } 978f79cbc77SKalle Valo 979f79cbc77SKalle Valo 980f79cbc77SKalle Valo static void hwsim_send_nullfunc_ps(void *dat, u8 *mac, 981f79cbc77SKalle Valo struct ieee80211_vif *vif) 982f79cbc77SKalle Valo { 983f79cbc77SKalle Valo struct mac80211_hwsim_data *data = dat; 984f79cbc77SKalle Valo hwsim_send_nullfunc(data, mac, vif, 1); 985f79cbc77SKalle Valo } 986f79cbc77SKalle Valo 987f79cbc77SKalle Valo static void hwsim_send_nullfunc_no_ps(void *dat, u8 *mac, 988f79cbc77SKalle Valo struct ieee80211_vif *vif) 989f79cbc77SKalle Valo { 990f79cbc77SKalle Valo struct mac80211_hwsim_data *data = dat; 991f79cbc77SKalle Valo hwsim_send_nullfunc(data, mac, vif, 0); 992f79cbc77SKalle Valo } 993f79cbc77SKalle Valo 994f79cbc77SKalle Valo static int hwsim_fops_ps_read(void *dat, u64 *val) 995f79cbc77SKalle Valo { 996f79cbc77SKalle Valo struct mac80211_hwsim_data *data = dat; 997f79cbc77SKalle Valo *val = data->ps; 998f79cbc77SKalle Valo return 0; 999f79cbc77SKalle Valo } 1000f79cbc77SKalle Valo 1001f79cbc77SKalle Valo static int hwsim_fops_ps_write(void *dat, u64 val) 1002f79cbc77SKalle Valo { 1003f79cbc77SKalle Valo struct mac80211_hwsim_data *data = dat; 1004f79cbc77SKalle Valo enum ps_mode old_ps; 1005f79cbc77SKalle Valo 1006f79cbc77SKalle Valo if (val != PS_DISABLED && val != PS_ENABLED && val != PS_AUTO_POLL && 1007f79cbc77SKalle Valo val != PS_MANUAL_POLL) 1008f79cbc77SKalle Valo return -EINVAL; 1009f79cbc77SKalle Valo 1010f79cbc77SKalle Valo if (val == PS_MANUAL_POLL) { 1011f79cbc77SKalle Valo if (data->ps != PS_ENABLED) 1012f79cbc77SKalle Valo return -EINVAL; 1013f79cbc77SKalle Valo local_bh_disable(); 1014f79cbc77SKalle Valo ieee80211_iterate_active_interfaces_atomic( 1015f79cbc77SKalle Valo data->hw, IEEE80211_IFACE_ITER_NORMAL, 1016f79cbc77SKalle Valo hwsim_send_ps_poll, data); 1017f79cbc77SKalle Valo local_bh_enable(); 1018f79cbc77SKalle Valo return 0; 1019f79cbc77SKalle Valo } 1020f79cbc77SKalle Valo old_ps = data->ps; 1021f79cbc77SKalle Valo data->ps = val; 1022f79cbc77SKalle Valo 1023f79cbc77SKalle Valo local_bh_disable(); 1024f79cbc77SKalle Valo if (old_ps == PS_DISABLED && val != PS_DISABLED) { 1025f79cbc77SKalle Valo ieee80211_iterate_active_interfaces_atomic( 1026f79cbc77SKalle Valo data->hw, IEEE80211_IFACE_ITER_NORMAL, 1027f79cbc77SKalle Valo hwsim_send_nullfunc_ps, data); 1028f79cbc77SKalle Valo } else if (old_ps != PS_DISABLED && val == PS_DISABLED) { 1029f79cbc77SKalle Valo ieee80211_iterate_active_interfaces_atomic( 1030f79cbc77SKalle Valo data->hw, IEEE80211_IFACE_ITER_NORMAL, 1031f79cbc77SKalle Valo hwsim_send_nullfunc_no_ps, data); 1032f79cbc77SKalle Valo } 1033f79cbc77SKalle Valo local_bh_enable(); 1034f79cbc77SKalle Valo 1035f79cbc77SKalle Valo return 0; 1036f79cbc77SKalle Valo } 1037f79cbc77SKalle Valo 1038f79cbc77SKalle Valo DEFINE_DEBUGFS_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write, 1039f79cbc77SKalle Valo "%llu\n"); 1040f79cbc77SKalle Valo 1041f79cbc77SKalle Valo static int hwsim_write_simulate_radar(void *dat, u64 val) 1042f79cbc77SKalle Valo { 1043f79cbc77SKalle Valo struct mac80211_hwsim_data *data = dat; 1044f79cbc77SKalle Valo 1045f79cbc77SKalle Valo ieee80211_radar_detected(data->hw); 1046f79cbc77SKalle Valo 1047f79cbc77SKalle Valo return 0; 1048f79cbc77SKalle Valo } 1049f79cbc77SKalle Valo 1050f79cbc77SKalle Valo DEFINE_DEBUGFS_ATTRIBUTE(hwsim_simulate_radar, NULL, 1051f79cbc77SKalle Valo hwsim_write_simulate_radar, "%llu\n"); 1052f79cbc77SKalle Valo 1053f79cbc77SKalle Valo static int hwsim_fops_group_read(void *dat, u64 *val) 1054f79cbc77SKalle Valo { 1055f79cbc77SKalle Valo struct mac80211_hwsim_data *data = dat; 1056f79cbc77SKalle Valo *val = data->group; 1057f79cbc77SKalle Valo return 0; 1058f79cbc77SKalle Valo } 1059f79cbc77SKalle Valo 1060f79cbc77SKalle Valo static int hwsim_fops_group_write(void *dat, u64 val) 1061f79cbc77SKalle Valo { 1062f79cbc77SKalle Valo struct mac80211_hwsim_data *data = dat; 1063f79cbc77SKalle Valo data->group = val; 1064f79cbc77SKalle Valo return 0; 1065f79cbc77SKalle Valo } 1066f79cbc77SKalle Valo 1067f79cbc77SKalle Valo DEFINE_DEBUGFS_ATTRIBUTE(hwsim_fops_group, 1068f79cbc77SKalle Valo hwsim_fops_group_read, hwsim_fops_group_write, 1069f79cbc77SKalle Valo "%llx\n"); 1070f79cbc77SKalle Valo 1071f79cbc77SKalle Valo static int hwsim_fops_rx_rssi_read(void *dat, u64 *val) 1072f79cbc77SKalle Valo { 1073f79cbc77SKalle Valo struct mac80211_hwsim_data *data = dat; 1074f79cbc77SKalle Valo *val = data->rx_rssi; 1075f79cbc77SKalle Valo return 0; 1076f79cbc77SKalle Valo } 1077f79cbc77SKalle Valo 1078f79cbc77SKalle Valo static int hwsim_fops_rx_rssi_write(void *dat, u64 val) 1079f79cbc77SKalle Valo { 1080f79cbc77SKalle Valo struct mac80211_hwsim_data *data = dat; 1081f79cbc77SKalle Valo int rssi = (int)val; 1082f79cbc77SKalle Valo 1083f79cbc77SKalle Valo if (rssi >= 0 || rssi < -100) 1084f79cbc77SKalle Valo return -EINVAL; 1085f79cbc77SKalle Valo 1086f79cbc77SKalle Valo data->rx_rssi = rssi; 1087f79cbc77SKalle Valo return 0; 1088f79cbc77SKalle Valo } 1089f79cbc77SKalle Valo 1090f79cbc77SKalle Valo DEFINE_DEBUGFS_ATTRIBUTE(hwsim_fops_rx_rssi, 1091f79cbc77SKalle Valo hwsim_fops_rx_rssi_read, hwsim_fops_rx_rssi_write, 1092f79cbc77SKalle Valo "%lld\n"); 1093f79cbc77SKalle Valo 1094f79cbc77SKalle Valo static netdev_tx_t hwsim_mon_xmit(struct sk_buff *skb, 1095f79cbc77SKalle Valo struct net_device *dev) 1096f79cbc77SKalle Valo { 1097f79cbc77SKalle Valo /* TODO: allow packet injection */ 1098f79cbc77SKalle Valo dev_kfree_skb(skb); 1099f79cbc77SKalle Valo return NETDEV_TX_OK; 1100f79cbc77SKalle Valo } 1101f79cbc77SKalle Valo 1102f79cbc77SKalle Valo static inline u64 mac80211_hwsim_get_tsf_raw(void) 1103f79cbc77SKalle Valo { 1104f79cbc77SKalle Valo return ktime_to_us(ktime_get_real()); 1105f79cbc77SKalle Valo } 1106f79cbc77SKalle Valo 1107f79cbc77SKalle Valo static __le64 __mac80211_hwsim_get_tsf(struct mac80211_hwsim_data *data) 1108f79cbc77SKalle Valo { 1109f79cbc77SKalle Valo u64 now = mac80211_hwsim_get_tsf_raw(); 1110f79cbc77SKalle Valo return cpu_to_le64(now + data->tsf_offset); 1111f79cbc77SKalle Valo } 1112f79cbc77SKalle Valo 1113f79cbc77SKalle Valo static u64 mac80211_hwsim_get_tsf(struct ieee80211_hw *hw, 1114f79cbc77SKalle Valo struct ieee80211_vif *vif) 1115f79cbc77SKalle Valo { 1116f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 1117f79cbc77SKalle Valo return le64_to_cpu(__mac80211_hwsim_get_tsf(data)); 1118f79cbc77SKalle Valo } 1119f79cbc77SKalle Valo 1120f79cbc77SKalle Valo static void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw, 1121f79cbc77SKalle Valo struct ieee80211_vif *vif, u64 tsf) 1122f79cbc77SKalle Valo { 1123f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 1124f79cbc77SKalle Valo u64 now = mac80211_hwsim_get_tsf(hw, vif); 1125f79cbc77SKalle Valo /* MLD not supported here */ 1126f79cbc77SKalle Valo u32 bcn_int = data->link_data[0].beacon_int; 1127f79cbc77SKalle Valo u64 delta = abs(tsf - now); 1128f79cbc77SKalle Valo 1129f79cbc77SKalle Valo /* adjust after beaconing with new timestamp at old TBTT */ 1130f79cbc77SKalle Valo if (tsf > now) { 1131f79cbc77SKalle Valo data->tsf_offset += delta; 1132f79cbc77SKalle Valo data->bcn_delta = do_div(delta, bcn_int); 1133f79cbc77SKalle Valo } else { 1134f79cbc77SKalle Valo data->tsf_offset -= delta; 1135f79cbc77SKalle Valo data->bcn_delta = -(s64)do_div(delta, bcn_int); 1136f79cbc77SKalle Valo } 1137f79cbc77SKalle Valo } 1138f79cbc77SKalle Valo 1139f79cbc77SKalle Valo static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, 1140f79cbc77SKalle Valo struct sk_buff *tx_skb, 1141f79cbc77SKalle Valo struct ieee80211_channel *chan) 1142f79cbc77SKalle Valo { 1143f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 1144f79cbc77SKalle Valo struct sk_buff *skb; 1145f79cbc77SKalle Valo struct hwsim_radiotap_hdr *hdr; 1146f79cbc77SKalle Valo u16 flags, bitrate; 1147f79cbc77SKalle Valo struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_skb); 1148f79cbc77SKalle Valo struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info); 1149f79cbc77SKalle Valo 1150f79cbc77SKalle Valo if (!txrate) 1151f79cbc77SKalle Valo bitrate = 0; 1152f79cbc77SKalle Valo else 1153f79cbc77SKalle Valo bitrate = txrate->bitrate; 1154f79cbc77SKalle Valo 1155f79cbc77SKalle Valo if (!netif_running(hwsim_mon)) 1156f79cbc77SKalle Valo return; 1157f79cbc77SKalle Valo 1158f79cbc77SKalle Valo skb = skb_copy_expand(tx_skb, sizeof(*hdr), 0, GFP_ATOMIC); 1159f79cbc77SKalle Valo if (skb == NULL) 1160f79cbc77SKalle Valo return; 1161f79cbc77SKalle Valo 1162f79cbc77SKalle Valo hdr = skb_push(skb, sizeof(*hdr)); 1163f79cbc77SKalle Valo hdr->hdr.it_version = PKTHDR_RADIOTAP_VERSION; 1164f79cbc77SKalle Valo hdr->hdr.it_pad = 0; 1165f79cbc77SKalle Valo hdr->hdr.it_len = cpu_to_le16(sizeof(*hdr)); 1166f79cbc77SKalle Valo hdr->hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | 1167f79cbc77SKalle Valo (1 << IEEE80211_RADIOTAP_RATE) | 1168f79cbc77SKalle Valo (1 << IEEE80211_RADIOTAP_TSFT) | 1169f79cbc77SKalle Valo (1 << IEEE80211_RADIOTAP_CHANNEL)); 1170f79cbc77SKalle Valo hdr->rt_tsft = __mac80211_hwsim_get_tsf(data); 1171f79cbc77SKalle Valo hdr->rt_flags = 0; 1172f79cbc77SKalle Valo hdr->rt_rate = bitrate / 5; 1173f79cbc77SKalle Valo hdr->rt_channel = cpu_to_le16(chan->center_freq); 1174f79cbc77SKalle Valo flags = IEEE80211_CHAN_2GHZ; 1175f79cbc77SKalle Valo if (txrate && txrate->flags & IEEE80211_RATE_ERP_G) 1176f79cbc77SKalle Valo flags |= IEEE80211_CHAN_OFDM; 1177f79cbc77SKalle Valo else 1178f79cbc77SKalle Valo flags |= IEEE80211_CHAN_CCK; 1179f79cbc77SKalle Valo hdr->rt_chbitmask = cpu_to_le16(flags); 1180f79cbc77SKalle Valo 1181f79cbc77SKalle Valo skb->dev = hwsim_mon; 1182f79cbc77SKalle Valo skb_reset_mac_header(skb); 1183f79cbc77SKalle Valo skb->ip_summed = CHECKSUM_UNNECESSARY; 1184f79cbc77SKalle Valo skb->pkt_type = PACKET_OTHERHOST; 1185f79cbc77SKalle Valo skb->protocol = htons(ETH_P_802_2); 1186f79cbc77SKalle Valo memset(skb->cb, 0, sizeof(skb->cb)); 1187f79cbc77SKalle Valo netif_rx(skb); 1188f79cbc77SKalle Valo } 1189f79cbc77SKalle Valo 1190f79cbc77SKalle Valo 1191f79cbc77SKalle Valo static void mac80211_hwsim_monitor_ack(struct ieee80211_channel *chan, 1192f79cbc77SKalle Valo const u8 *addr) 1193f79cbc77SKalle Valo { 1194f79cbc77SKalle Valo struct sk_buff *skb; 1195f79cbc77SKalle Valo struct hwsim_radiotap_ack_hdr *hdr; 1196f79cbc77SKalle Valo u16 flags; 1197f79cbc77SKalle Valo struct ieee80211_hdr *hdr11; 1198f79cbc77SKalle Valo 1199f79cbc77SKalle Valo if (!netif_running(hwsim_mon)) 1200f79cbc77SKalle Valo return; 1201f79cbc77SKalle Valo 1202f79cbc77SKalle Valo skb = dev_alloc_skb(100); 1203f79cbc77SKalle Valo if (skb == NULL) 1204f79cbc77SKalle Valo return; 1205f79cbc77SKalle Valo 1206f79cbc77SKalle Valo hdr = skb_put(skb, sizeof(*hdr)); 1207f79cbc77SKalle Valo hdr->hdr.it_version = PKTHDR_RADIOTAP_VERSION; 1208f79cbc77SKalle Valo hdr->hdr.it_pad = 0; 1209f79cbc77SKalle Valo hdr->hdr.it_len = cpu_to_le16(sizeof(*hdr)); 1210f79cbc77SKalle Valo hdr->hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | 1211f79cbc77SKalle Valo (1 << IEEE80211_RADIOTAP_CHANNEL)); 1212f79cbc77SKalle Valo hdr->rt_flags = 0; 1213f79cbc77SKalle Valo hdr->pad = 0; 1214f79cbc77SKalle Valo hdr->rt_channel = cpu_to_le16(chan->center_freq); 1215f79cbc77SKalle Valo flags = IEEE80211_CHAN_2GHZ; 1216f79cbc77SKalle Valo hdr->rt_chbitmask = cpu_to_le16(flags); 1217f79cbc77SKalle Valo 1218f79cbc77SKalle Valo hdr11 = skb_put(skb, 10); 1219f79cbc77SKalle Valo hdr11->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | 1220f79cbc77SKalle Valo IEEE80211_STYPE_ACK); 1221f79cbc77SKalle Valo hdr11->duration_id = cpu_to_le16(0); 1222f79cbc77SKalle Valo memcpy(hdr11->addr1, addr, ETH_ALEN); 1223f79cbc77SKalle Valo 1224f79cbc77SKalle Valo skb->dev = hwsim_mon; 1225f79cbc77SKalle Valo skb_reset_mac_header(skb); 1226f79cbc77SKalle Valo skb->ip_summed = CHECKSUM_UNNECESSARY; 1227f79cbc77SKalle Valo skb->pkt_type = PACKET_OTHERHOST; 1228f79cbc77SKalle Valo skb->protocol = htons(ETH_P_802_2); 1229f79cbc77SKalle Valo memset(skb->cb, 0, sizeof(skb->cb)); 1230f79cbc77SKalle Valo netif_rx(skb); 1231f79cbc77SKalle Valo } 1232f79cbc77SKalle Valo 1233f79cbc77SKalle Valo struct mac80211_hwsim_addr_match_data { 1234f79cbc77SKalle Valo u8 addr[ETH_ALEN]; 1235f79cbc77SKalle Valo bool ret; 1236f79cbc77SKalle Valo }; 1237f79cbc77SKalle Valo 1238f79cbc77SKalle Valo static void mac80211_hwsim_addr_iter(void *data, u8 *mac, 1239f79cbc77SKalle Valo struct ieee80211_vif *vif) 1240f79cbc77SKalle Valo { 1241f79cbc77SKalle Valo int i; 1242f79cbc77SKalle Valo struct mac80211_hwsim_addr_match_data *md = data; 1243f79cbc77SKalle Valo 1244f79cbc77SKalle Valo if (memcmp(mac, md->addr, ETH_ALEN) == 0) { 1245f79cbc77SKalle Valo md->ret = true; 1246f79cbc77SKalle Valo return; 1247f79cbc77SKalle Valo } 1248f79cbc77SKalle Valo 1249f79cbc77SKalle Valo /* Match the link address */ 1250f79cbc77SKalle Valo for (i = 0; i < ARRAY_SIZE(vif->link_conf); i++) { 1251f79cbc77SKalle Valo struct ieee80211_bss_conf *conf; 1252f79cbc77SKalle Valo 1253f79cbc77SKalle Valo conf = rcu_dereference(vif->link_conf[i]); 1254f79cbc77SKalle Valo if (!conf) 1255f79cbc77SKalle Valo continue; 1256f79cbc77SKalle Valo 1257f79cbc77SKalle Valo if (memcmp(conf->addr, md->addr, ETH_ALEN) == 0) { 1258f79cbc77SKalle Valo md->ret = true; 1259f79cbc77SKalle Valo return; 1260f79cbc77SKalle Valo } 1261f79cbc77SKalle Valo } 1262f79cbc77SKalle Valo } 1263f79cbc77SKalle Valo 1264f79cbc77SKalle Valo static bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data, 1265f79cbc77SKalle Valo const u8 *addr) 1266f79cbc77SKalle Valo { 1267f79cbc77SKalle Valo struct mac80211_hwsim_addr_match_data md = { 1268f79cbc77SKalle Valo .ret = false, 1269f79cbc77SKalle Valo }; 1270f79cbc77SKalle Valo 1271f79cbc77SKalle Valo if (data->scanning && memcmp(addr, data->scan_addr, ETH_ALEN) == 0) 1272f79cbc77SKalle Valo return true; 1273f79cbc77SKalle Valo 1274f79cbc77SKalle Valo memcpy(md.addr, addr, ETH_ALEN); 1275f79cbc77SKalle Valo 1276f79cbc77SKalle Valo ieee80211_iterate_active_interfaces_atomic(data->hw, 1277f79cbc77SKalle Valo IEEE80211_IFACE_ITER_NORMAL, 1278f79cbc77SKalle Valo mac80211_hwsim_addr_iter, 1279f79cbc77SKalle Valo &md); 1280f79cbc77SKalle Valo 1281f79cbc77SKalle Valo return md.ret; 1282f79cbc77SKalle Valo } 1283f79cbc77SKalle Valo 1284f79cbc77SKalle Valo static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data, 1285f79cbc77SKalle Valo struct sk_buff *skb) 1286f79cbc77SKalle Valo { 1287f79cbc77SKalle Valo switch (data->ps) { 1288f79cbc77SKalle Valo case PS_DISABLED: 1289f79cbc77SKalle Valo return true; 1290f79cbc77SKalle Valo case PS_ENABLED: 1291f79cbc77SKalle Valo return false; 1292f79cbc77SKalle Valo case PS_AUTO_POLL: 1293f79cbc77SKalle Valo /* TODO: accept (some) Beacons by default and other frames only 1294f79cbc77SKalle Valo * if pending PS-Poll has been sent */ 1295f79cbc77SKalle Valo return true; 1296f79cbc77SKalle Valo case PS_MANUAL_POLL: 1297f79cbc77SKalle Valo /* Allow unicast frames to own address if there is a pending 1298f79cbc77SKalle Valo * PS-Poll */ 1299f79cbc77SKalle Valo if (data->ps_poll_pending && 1300f79cbc77SKalle Valo mac80211_hwsim_addr_match(data, skb->data + 4)) { 1301f79cbc77SKalle Valo data->ps_poll_pending = false; 1302f79cbc77SKalle Valo return true; 1303f79cbc77SKalle Valo } 1304f79cbc77SKalle Valo return false; 1305f79cbc77SKalle Valo } 1306f79cbc77SKalle Valo 1307f79cbc77SKalle Valo return true; 1308f79cbc77SKalle Valo } 1309f79cbc77SKalle Valo 1310f79cbc77SKalle Valo static int hwsim_unicast_netgroup(struct mac80211_hwsim_data *data, 1311f79cbc77SKalle Valo struct sk_buff *skb, int portid) 1312f79cbc77SKalle Valo { 1313f79cbc77SKalle Valo struct net *net; 1314f79cbc77SKalle Valo bool found = false; 1315f79cbc77SKalle Valo int res = -ENOENT; 1316f79cbc77SKalle Valo 1317f79cbc77SKalle Valo rcu_read_lock(); 1318f79cbc77SKalle Valo for_each_net_rcu(net) { 1319f79cbc77SKalle Valo if (data->netgroup == hwsim_net_get_netgroup(net)) { 1320f79cbc77SKalle Valo res = genlmsg_unicast(net, skb, portid); 1321f79cbc77SKalle Valo found = true; 1322f79cbc77SKalle Valo break; 1323f79cbc77SKalle Valo } 1324f79cbc77SKalle Valo } 1325f79cbc77SKalle Valo rcu_read_unlock(); 1326f79cbc77SKalle Valo 1327f79cbc77SKalle Valo if (!found) 1328f79cbc77SKalle Valo nlmsg_free(skb); 1329f79cbc77SKalle Valo 1330f79cbc77SKalle Valo return res; 1331f79cbc77SKalle Valo } 1332f79cbc77SKalle Valo 1333f79cbc77SKalle Valo static void mac80211_hwsim_config_mac_nl(struct ieee80211_hw *hw, 1334f79cbc77SKalle Valo const u8 *addr, bool add) 1335f79cbc77SKalle Valo { 1336f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 1337f79cbc77SKalle Valo u32 _portid = READ_ONCE(data->wmediumd); 1338f79cbc77SKalle Valo struct sk_buff *skb; 1339f79cbc77SKalle Valo void *msg_head; 1340f79cbc77SKalle Valo 1341f79cbc77SKalle Valo WARN_ON(!is_valid_ether_addr(addr)); 1342f79cbc77SKalle Valo 1343f79cbc77SKalle Valo if (!_portid && !hwsim_virtio_enabled) 1344f79cbc77SKalle Valo return; 1345f79cbc77SKalle Valo 1346f79cbc77SKalle Valo skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_ATOMIC); 1347f79cbc77SKalle Valo if (!skb) 1348f79cbc77SKalle Valo return; 1349f79cbc77SKalle Valo 1350f79cbc77SKalle Valo msg_head = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, 1351f79cbc77SKalle Valo add ? HWSIM_CMD_ADD_MAC_ADDR : 1352f79cbc77SKalle Valo HWSIM_CMD_DEL_MAC_ADDR); 1353f79cbc77SKalle Valo if (!msg_head) { 1354f79cbc77SKalle Valo pr_debug("mac80211_hwsim: problem with msg_head\n"); 1355f79cbc77SKalle Valo goto nla_put_failure; 1356f79cbc77SKalle Valo } 1357f79cbc77SKalle Valo 1358f79cbc77SKalle Valo if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER, 1359f79cbc77SKalle Valo ETH_ALEN, data->addresses[1].addr)) 1360f79cbc77SKalle Valo goto nla_put_failure; 1361f79cbc77SKalle Valo 1362f79cbc77SKalle Valo if (nla_put(skb, HWSIM_ATTR_ADDR_RECEIVER, ETH_ALEN, addr)) 1363f79cbc77SKalle Valo goto nla_put_failure; 1364f79cbc77SKalle Valo 1365f79cbc77SKalle Valo genlmsg_end(skb, msg_head); 1366f79cbc77SKalle Valo 1367f79cbc77SKalle Valo if (hwsim_virtio_enabled) 1368f79cbc77SKalle Valo hwsim_tx_virtio(data, skb); 1369f79cbc77SKalle Valo else 1370f79cbc77SKalle Valo hwsim_unicast_netgroup(data, skb, _portid); 1371f79cbc77SKalle Valo return; 1372f79cbc77SKalle Valo nla_put_failure: 1373f79cbc77SKalle Valo nlmsg_free(skb); 1374f79cbc77SKalle Valo } 1375f79cbc77SKalle Valo 1376f79cbc77SKalle Valo static inline u16 trans_tx_rate_flags_ieee2hwsim(struct ieee80211_tx_rate *rate) 1377f79cbc77SKalle Valo { 1378f79cbc77SKalle Valo u16 result = 0; 1379f79cbc77SKalle Valo 1380f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_USE_RTS_CTS) 1381f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_USE_RTS_CTS; 1382f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT) 1383f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_USE_CTS_PROTECT; 1384f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) 1385f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_USE_SHORT_PREAMBLE; 1386f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_MCS) 1387f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_MCS; 1388f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD) 1389f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_GREEN_FIELD; 1390f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) 1391f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_40_MHZ_WIDTH; 1392f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_DUP_DATA) 1393f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_DUP_DATA; 1394f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_SHORT_GI) 1395f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_SHORT_GI; 1396f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_VHT_MCS) 1397f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_VHT_MCS; 1398f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH) 1399f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_80_MHZ_WIDTH; 1400f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH) 1401f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_160_MHZ_WIDTH; 1402f79cbc77SKalle Valo 1403f79cbc77SKalle Valo return result; 1404f79cbc77SKalle Valo } 1405f79cbc77SKalle Valo 1406f79cbc77SKalle Valo static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, 1407f79cbc77SKalle Valo struct sk_buff *my_skb, 1408f79cbc77SKalle Valo int dst_portid, 1409f79cbc77SKalle Valo struct ieee80211_channel *channel) 1410f79cbc77SKalle Valo { 1411f79cbc77SKalle Valo struct sk_buff *skb; 1412f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 1413f79cbc77SKalle Valo struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) my_skb->data; 1414f79cbc77SKalle Valo struct ieee80211_tx_info *info = IEEE80211_SKB_CB(my_skb); 1415f79cbc77SKalle Valo void *msg_head; 1416f79cbc77SKalle Valo unsigned int hwsim_flags = 0; 1417f79cbc77SKalle Valo int i; 1418f79cbc77SKalle Valo struct hwsim_tx_rate tx_attempts[IEEE80211_TX_MAX_RATES]; 1419f79cbc77SKalle Valo struct hwsim_tx_rate_flag tx_attempts_flags[IEEE80211_TX_MAX_RATES]; 1420f79cbc77SKalle Valo uintptr_t cookie; 1421f79cbc77SKalle Valo 1422f79cbc77SKalle Valo if (data->ps != PS_DISABLED) 1423f79cbc77SKalle Valo hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); 1424f79cbc77SKalle Valo /* If the queue contains MAX_QUEUE skb's drop some */ 1425f79cbc77SKalle Valo if (skb_queue_len(&data->pending) >= MAX_QUEUE) { 1426f79cbc77SKalle Valo /* Dropping until WARN_QUEUE level */ 1427f79cbc77SKalle Valo while (skb_queue_len(&data->pending) >= WARN_QUEUE) { 1428f79cbc77SKalle Valo ieee80211_free_txskb(hw, skb_dequeue(&data->pending)); 1429f79cbc77SKalle Valo data->tx_dropped++; 1430f79cbc77SKalle Valo } 1431f79cbc77SKalle Valo } 1432f79cbc77SKalle Valo 1433f79cbc77SKalle Valo skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_ATOMIC); 1434f79cbc77SKalle Valo if (skb == NULL) 1435f79cbc77SKalle Valo goto nla_put_failure; 1436f79cbc77SKalle Valo 1437f79cbc77SKalle Valo msg_head = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, 1438f79cbc77SKalle Valo HWSIM_CMD_FRAME); 1439f79cbc77SKalle Valo if (msg_head == NULL) { 1440f79cbc77SKalle Valo pr_debug("mac80211_hwsim: problem with msg_head\n"); 1441f79cbc77SKalle Valo goto nla_put_failure; 1442f79cbc77SKalle Valo } 1443f79cbc77SKalle Valo 1444f79cbc77SKalle Valo if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER, 1445f79cbc77SKalle Valo ETH_ALEN, data->addresses[1].addr)) 1446f79cbc77SKalle Valo goto nla_put_failure; 1447f79cbc77SKalle Valo 1448f79cbc77SKalle Valo /* We get the skb->data */ 1449f79cbc77SKalle Valo if (nla_put(skb, HWSIM_ATTR_FRAME, my_skb->len, my_skb->data)) 1450f79cbc77SKalle Valo goto nla_put_failure; 1451f79cbc77SKalle Valo 1452f79cbc77SKalle Valo /* We get the flags for this transmission, and we translate them to 1453f79cbc77SKalle Valo wmediumd flags */ 1454f79cbc77SKalle Valo 1455f79cbc77SKalle Valo if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) 1456f79cbc77SKalle Valo hwsim_flags |= HWSIM_TX_CTL_REQ_TX_STATUS; 1457f79cbc77SKalle Valo 1458f79cbc77SKalle Valo if (info->flags & IEEE80211_TX_CTL_NO_ACK) 1459f79cbc77SKalle Valo hwsim_flags |= HWSIM_TX_CTL_NO_ACK; 1460f79cbc77SKalle Valo 1461f79cbc77SKalle Valo if (nla_put_u32(skb, HWSIM_ATTR_FLAGS, hwsim_flags)) 1462f79cbc77SKalle Valo goto nla_put_failure; 1463f79cbc77SKalle Valo 1464f79cbc77SKalle Valo if (nla_put_u32(skb, HWSIM_ATTR_FREQ, channel->center_freq)) 1465f79cbc77SKalle Valo goto nla_put_failure; 1466f79cbc77SKalle Valo 1467f79cbc77SKalle Valo /* We get the tx control (rate and retries) info*/ 1468f79cbc77SKalle Valo 1469f79cbc77SKalle Valo for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { 1470f79cbc77SKalle Valo tx_attempts[i].idx = info->status.rates[i].idx; 1471f79cbc77SKalle Valo tx_attempts_flags[i].idx = info->status.rates[i].idx; 1472f79cbc77SKalle Valo tx_attempts[i].count = info->status.rates[i].count; 1473f79cbc77SKalle Valo tx_attempts_flags[i].flags = 1474f79cbc77SKalle Valo trans_tx_rate_flags_ieee2hwsim( 1475f79cbc77SKalle Valo &info->status.rates[i]); 1476f79cbc77SKalle Valo } 1477f79cbc77SKalle Valo 1478f79cbc77SKalle Valo if (nla_put(skb, HWSIM_ATTR_TX_INFO, 1479f79cbc77SKalle Valo sizeof(struct hwsim_tx_rate)*IEEE80211_TX_MAX_RATES, 1480f79cbc77SKalle Valo tx_attempts)) 1481f79cbc77SKalle Valo goto nla_put_failure; 1482f79cbc77SKalle Valo 1483f79cbc77SKalle Valo if (nla_put(skb, HWSIM_ATTR_TX_INFO_FLAGS, 1484f79cbc77SKalle Valo sizeof(struct hwsim_tx_rate_flag) * IEEE80211_TX_MAX_RATES, 1485f79cbc77SKalle Valo tx_attempts_flags)) 1486f79cbc77SKalle Valo goto nla_put_failure; 1487f79cbc77SKalle Valo 1488f79cbc77SKalle Valo /* We create a cookie to identify this skb */ 1489f79cbc77SKalle Valo cookie = atomic_inc_return(&data->pending_cookie); 1490f79cbc77SKalle Valo info->rate_driver_data[0] = (void *)cookie; 1491f79cbc77SKalle Valo if (nla_put_u64_64bit(skb, HWSIM_ATTR_COOKIE, cookie, HWSIM_ATTR_PAD)) 1492f79cbc77SKalle Valo goto nla_put_failure; 1493f79cbc77SKalle Valo 1494f79cbc77SKalle Valo genlmsg_end(skb, msg_head); 1495f79cbc77SKalle Valo 1496f79cbc77SKalle Valo if (hwsim_virtio_enabled) { 1497f79cbc77SKalle Valo if (hwsim_tx_virtio(data, skb)) 1498f79cbc77SKalle Valo goto err_free_txskb; 1499f79cbc77SKalle Valo } else { 1500f79cbc77SKalle Valo if (hwsim_unicast_netgroup(data, skb, dst_portid)) 1501f79cbc77SKalle Valo goto err_free_txskb; 1502f79cbc77SKalle Valo } 1503f79cbc77SKalle Valo 1504f79cbc77SKalle Valo /* Enqueue the packet */ 1505f79cbc77SKalle Valo skb_queue_tail(&data->pending, my_skb); 1506f79cbc77SKalle Valo data->tx_pkts++; 1507f79cbc77SKalle Valo data->tx_bytes += my_skb->len; 1508f79cbc77SKalle Valo return; 1509f79cbc77SKalle Valo 1510f79cbc77SKalle Valo nla_put_failure: 1511f79cbc77SKalle Valo nlmsg_free(skb); 1512f79cbc77SKalle Valo err_free_txskb: 1513f79cbc77SKalle Valo pr_debug("mac80211_hwsim: error occurred in %s\n", __func__); 1514f79cbc77SKalle Valo ieee80211_free_txskb(hw, my_skb); 1515f79cbc77SKalle Valo data->tx_failed++; 1516f79cbc77SKalle Valo } 1517f79cbc77SKalle Valo 1518f79cbc77SKalle Valo static bool hwsim_chans_compat(struct ieee80211_channel *c1, 1519f79cbc77SKalle Valo struct ieee80211_channel *c2) 1520f79cbc77SKalle Valo { 1521f79cbc77SKalle Valo if (!c1 || !c2) 1522f79cbc77SKalle Valo return false; 1523f79cbc77SKalle Valo 1524f79cbc77SKalle Valo return c1->center_freq == c2->center_freq; 1525f79cbc77SKalle Valo } 1526f79cbc77SKalle Valo 1527f79cbc77SKalle Valo struct tx_iter_data { 1528f79cbc77SKalle Valo struct ieee80211_channel *channel; 1529f79cbc77SKalle Valo bool receive; 1530f79cbc77SKalle Valo }; 1531f79cbc77SKalle Valo 1532f79cbc77SKalle Valo static void mac80211_hwsim_tx_iter(void *_data, u8 *addr, 1533f79cbc77SKalle Valo struct ieee80211_vif *vif) 1534f79cbc77SKalle Valo { 1535f79cbc77SKalle Valo struct tx_iter_data *data = _data; 1536f79cbc77SKalle Valo int i; 1537f79cbc77SKalle Valo 1538f79cbc77SKalle Valo for (i = 0; i < ARRAY_SIZE(vif->link_conf); i++) { 1539f79cbc77SKalle Valo struct ieee80211_bss_conf *conf; 1540f79cbc77SKalle Valo struct ieee80211_chanctx_conf *chanctx; 1541f79cbc77SKalle Valo 1542f79cbc77SKalle Valo conf = rcu_dereference(vif->link_conf[i]); 1543f79cbc77SKalle Valo if (!conf) 1544f79cbc77SKalle Valo continue; 1545f79cbc77SKalle Valo 1546f79cbc77SKalle Valo chanctx = rcu_dereference(conf->chanctx_conf); 1547f79cbc77SKalle Valo if (!chanctx) 1548f79cbc77SKalle Valo continue; 1549f79cbc77SKalle Valo 1550f79cbc77SKalle Valo if (!hwsim_chans_compat(data->channel, chanctx->def.chan)) 1551f79cbc77SKalle Valo continue; 1552f79cbc77SKalle Valo 1553f79cbc77SKalle Valo data->receive = true; 1554f79cbc77SKalle Valo return; 1555f79cbc77SKalle Valo } 1556f79cbc77SKalle Valo } 1557f79cbc77SKalle Valo 1558f79cbc77SKalle Valo static void mac80211_hwsim_add_vendor_rtap(struct sk_buff *skb) 1559f79cbc77SKalle Valo { 1560f79cbc77SKalle Valo /* 1561f79cbc77SKalle Valo * To enable this code, #define the HWSIM_RADIOTAP_OUI, 1562f79cbc77SKalle Valo * e.g. like this: 1563f79cbc77SKalle Valo * #define HWSIM_RADIOTAP_OUI "\x02\x00\x00" 1564f79cbc77SKalle Valo * (but you should use a valid OUI, not that) 1565f79cbc77SKalle Valo * 1566f79cbc77SKalle Valo * If anyone wants to 'donate' a radiotap OUI/subns code 1567f79cbc77SKalle Valo * please send a patch removing this #ifdef and changing 1568f79cbc77SKalle Valo * the values accordingly. 1569f79cbc77SKalle Valo */ 1570f79cbc77SKalle Valo #ifdef HWSIM_RADIOTAP_OUI 1571f79cbc77SKalle Valo struct ieee80211_radiotap_vendor_tlv *rtap; 1572f79cbc77SKalle Valo static const char vendor_data[8] = "ABCDEFGH"; 1573f79cbc77SKalle Valo 1574f79cbc77SKalle Valo // Make sure no padding is needed 1575f79cbc77SKalle Valo BUILD_BUG_ON(sizeof(vendor_data) % 4); 1576f79cbc77SKalle Valo /* this is last radiotap info before the mac header, so 1577f79cbc77SKalle Valo * skb_reset_mac_header for mac8022 to know the end of 1578f79cbc77SKalle Valo * the radiotap TLV/beginning of the 802.11 header 1579f79cbc77SKalle Valo */ 1580f79cbc77SKalle Valo skb_reset_mac_header(skb); 1581f79cbc77SKalle Valo 1582f79cbc77SKalle Valo /* 1583f79cbc77SKalle Valo * Note that this code requires the headroom in the SKB 1584f79cbc77SKalle Valo * that was allocated earlier. 1585f79cbc77SKalle Valo */ 1586f79cbc77SKalle Valo rtap = skb_push(skb, sizeof(*rtap) + sizeof(vendor_data)); 1587f79cbc77SKalle Valo 1588f79cbc77SKalle Valo rtap->len = cpu_to_le16(sizeof(*rtap) - 1589f79cbc77SKalle Valo sizeof(struct ieee80211_radiotap_tlv) + 1590f79cbc77SKalle Valo sizeof(vendor_data)); 1591f79cbc77SKalle Valo rtap->type = cpu_to_le16(IEEE80211_RADIOTAP_VENDOR_NAMESPACE); 1592f79cbc77SKalle Valo 1593f79cbc77SKalle Valo rtap->content.oui[0] = HWSIM_RADIOTAP_OUI[0]; 1594f79cbc77SKalle Valo rtap->content.oui[1] = HWSIM_RADIOTAP_OUI[1]; 1595f79cbc77SKalle Valo rtap->content.oui[2] = HWSIM_RADIOTAP_OUI[2]; 1596f79cbc77SKalle Valo rtap->content.oui_subtype = 127; 1597f79cbc77SKalle Valo /* clear reserved field */ 1598f79cbc77SKalle Valo rtap->content.reserved = 0; 1599f79cbc77SKalle Valo rtap->content.vendor_type = 0; 1600f79cbc77SKalle Valo memcpy(rtap->content.data, vendor_data, sizeof(vendor_data)); 1601f79cbc77SKalle Valo 1602f79cbc77SKalle Valo IEEE80211_SKB_RXCB(skb)->flag |= RX_FLAG_RADIOTAP_TLV_AT_END; 1603f79cbc77SKalle Valo #endif 1604f79cbc77SKalle Valo } 1605f79cbc77SKalle Valo 1606f79cbc77SKalle Valo static void mac80211_hwsim_rx(struct mac80211_hwsim_data *data, 1607f79cbc77SKalle Valo struct ieee80211_rx_status *rx_status, 1608f79cbc77SKalle Valo struct sk_buff *skb) 1609f79cbc77SKalle Valo { 1610f79cbc77SKalle Valo struct ieee80211_hdr *hdr = (void *)skb->data; 1611f79cbc77SKalle Valo 1612f79cbc77SKalle Valo if (!ieee80211_has_morefrags(hdr->frame_control) && 1613f79cbc77SKalle Valo !is_multicast_ether_addr(hdr->addr1) && 1614f79cbc77SKalle Valo (ieee80211_is_mgmt(hdr->frame_control) || 1615f79cbc77SKalle Valo ieee80211_is_data(hdr->frame_control))) { 1616f79cbc77SKalle Valo struct ieee80211_sta *sta; 1617f79cbc77SKalle Valo unsigned int link_id; 1618f79cbc77SKalle Valo 1619f79cbc77SKalle Valo rcu_read_lock(); 1620f79cbc77SKalle Valo sta = ieee80211_find_sta_by_link_addrs(data->hw, hdr->addr2, 1621f79cbc77SKalle Valo hdr->addr1, &link_id); 1622f79cbc77SKalle Valo if (sta) { 1623f79cbc77SKalle Valo struct hwsim_sta_priv *sp = (void *)sta->drv_priv; 1624f79cbc77SKalle Valo 1625f79cbc77SKalle Valo if (ieee80211_has_pm(hdr->frame_control)) 1626f79cbc77SKalle Valo sp->active_links_rx &= ~BIT(link_id); 1627f79cbc77SKalle Valo else 1628f79cbc77SKalle Valo sp->active_links_rx |= BIT(link_id); 1629f79cbc77SKalle Valo } 1630f79cbc77SKalle Valo rcu_read_unlock(); 1631f79cbc77SKalle Valo } 1632f79cbc77SKalle Valo 1633f79cbc77SKalle Valo memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status)); 1634f79cbc77SKalle Valo 1635f79cbc77SKalle Valo mac80211_hwsim_add_vendor_rtap(skb); 1636f79cbc77SKalle Valo 1637f79cbc77SKalle Valo data->rx_pkts++; 1638f79cbc77SKalle Valo data->rx_bytes += skb->len; 1639f79cbc77SKalle Valo ieee80211_rx_irqsafe(data->hw, skb); 1640f79cbc77SKalle Valo } 1641f79cbc77SKalle Valo 1642f79cbc77SKalle Valo static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, 1643f79cbc77SKalle Valo struct sk_buff *skb, 1644f79cbc77SKalle Valo struct ieee80211_channel *chan) 1645f79cbc77SKalle Valo { 1646f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv, *data2; 1647f79cbc77SKalle Valo bool ack = false; 1648f79cbc77SKalle Valo struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 1649f79cbc77SKalle Valo struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 1650f79cbc77SKalle Valo struct ieee80211_rx_status rx_status; 1651f79cbc77SKalle Valo u64 now; 1652f79cbc77SKalle Valo 1653f79cbc77SKalle Valo memset(&rx_status, 0, sizeof(rx_status)); 1654f79cbc77SKalle Valo rx_status.flag |= RX_FLAG_MACTIME_START; 1655f79cbc77SKalle Valo rx_status.freq = chan->center_freq; 1656f79cbc77SKalle Valo rx_status.freq_offset = chan->freq_offset ? 1 : 0; 1657f79cbc77SKalle Valo rx_status.band = chan->band; 1658f79cbc77SKalle Valo if (info->control.rates[0].flags & IEEE80211_TX_RC_VHT_MCS) { 1659f79cbc77SKalle Valo rx_status.rate_idx = 1660f79cbc77SKalle Valo ieee80211_rate_get_vht_mcs(&info->control.rates[0]); 1661f79cbc77SKalle Valo rx_status.nss = 1662f79cbc77SKalle Valo ieee80211_rate_get_vht_nss(&info->control.rates[0]); 1663f79cbc77SKalle Valo rx_status.encoding = RX_ENC_VHT; 1664f79cbc77SKalle Valo } else { 1665f79cbc77SKalle Valo rx_status.rate_idx = info->control.rates[0].idx; 1666f79cbc77SKalle Valo if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS) 1667f79cbc77SKalle Valo rx_status.encoding = RX_ENC_HT; 1668f79cbc77SKalle Valo } 1669f79cbc77SKalle Valo if (info->control.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) 1670f79cbc77SKalle Valo rx_status.bw = RATE_INFO_BW_40; 1671f79cbc77SKalle Valo else if (info->control.rates[0].flags & IEEE80211_TX_RC_80_MHZ_WIDTH) 1672f79cbc77SKalle Valo rx_status.bw = RATE_INFO_BW_80; 1673f79cbc77SKalle Valo else if (info->control.rates[0].flags & IEEE80211_TX_RC_160_MHZ_WIDTH) 1674f79cbc77SKalle Valo rx_status.bw = RATE_INFO_BW_160; 1675f79cbc77SKalle Valo else 1676f79cbc77SKalle Valo rx_status.bw = RATE_INFO_BW_20; 1677f79cbc77SKalle Valo if (info->control.rates[0].flags & IEEE80211_TX_RC_SHORT_GI) 1678f79cbc77SKalle Valo rx_status.enc_flags |= RX_ENC_FLAG_SHORT_GI; 1679f79cbc77SKalle Valo /* TODO: simulate optional packet loss */ 1680f79cbc77SKalle Valo rx_status.signal = data->rx_rssi; 1681f79cbc77SKalle Valo if (info->control.vif) 1682f79cbc77SKalle Valo rx_status.signal += info->control.vif->bss_conf.txpower; 1683f79cbc77SKalle Valo 1684f79cbc77SKalle Valo if (data->ps != PS_DISABLED) 1685f79cbc77SKalle Valo hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); 1686f79cbc77SKalle Valo 1687f79cbc77SKalle Valo /* release the skb's source info */ 1688f79cbc77SKalle Valo skb_orphan(skb); 1689f79cbc77SKalle Valo skb_dst_drop(skb); 1690f79cbc77SKalle Valo skb->mark = 0; 1691f79cbc77SKalle Valo skb_ext_reset(skb); 1692f79cbc77SKalle Valo nf_reset_ct(skb); 1693f79cbc77SKalle Valo 1694f79cbc77SKalle Valo /* 1695f79cbc77SKalle Valo * Get absolute mactime here so all HWs RX at the "same time", and 1696f79cbc77SKalle Valo * absolute TX time for beacon mactime so the timestamp matches. 1697f79cbc77SKalle Valo * Giving beacons a different mactime than non-beacons looks messy, but 1698f79cbc77SKalle Valo * it helps the Toffset be exact and a ~10us mactime discrepancy 1699f79cbc77SKalle Valo * probably doesn't really matter. 1700f79cbc77SKalle Valo */ 1701f79cbc77SKalle Valo if (ieee80211_is_beacon(hdr->frame_control) || 1702f79cbc77SKalle Valo ieee80211_is_probe_resp(hdr->frame_control)) { 1703f79cbc77SKalle Valo rx_status.boottime_ns = ktime_get_boottime_ns(); 1704f79cbc77SKalle Valo now = data->abs_bcn_ts; 1705f79cbc77SKalle Valo } else { 1706f79cbc77SKalle Valo now = mac80211_hwsim_get_tsf_raw(); 1707f79cbc77SKalle Valo } 1708f79cbc77SKalle Valo 1709f79cbc77SKalle Valo /* Copy skb to all enabled radios that are on the current frequency */ 1710f79cbc77SKalle Valo spin_lock(&hwsim_radio_lock); 1711f79cbc77SKalle Valo list_for_each_entry(data2, &hwsim_radios, list) { 1712f79cbc77SKalle Valo struct sk_buff *nskb; 1713f79cbc77SKalle Valo struct tx_iter_data tx_iter_data = { 1714f79cbc77SKalle Valo .receive = false, 1715f79cbc77SKalle Valo .channel = chan, 1716f79cbc77SKalle Valo }; 1717f79cbc77SKalle Valo 1718f79cbc77SKalle Valo if (data == data2) 1719f79cbc77SKalle Valo continue; 1720f79cbc77SKalle Valo 1721f79cbc77SKalle Valo if (!data2->started || (data2->idle && !data2->tmp_chan) || 1722f79cbc77SKalle Valo !hwsim_ps_rx_ok(data2, skb)) 1723f79cbc77SKalle Valo continue; 1724f79cbc77SKalle Valo 1725f79cbc77SKalle Valo if (!(data->group & data2->group)) 1726f79cbc77SKalle Valo continue; 1727f79cbc77SKalle Valo 1728f79cbc77SKalle Valo if (data->netgroup != data2->netgroup) 1729f79cbc77SKalle Valo continue; 1730f79cbc77SKalle Valo 1731f79cbc77SKalle Valo if (!hwsim_chans_compat(chan, data2->tmp_chan) && 1732f79cbc77SKalle Valo !hwsim_chans_compat(chan, data2->channel)) { 1733f79cbc77SKalle Valo ieee80211_iterate_active_interfaces_atomic( 1734f79cbc77SKalle Valo data2->hw, IEEE80211_IFACE_ITER_NORMAL, 1735f79cbc77SKalle Valo mac80211_hwsim_tx_iter, &tx_iter_data); 1736f79cbc77SKalle Valo if (!tx_iter_data.receive) 1737f79cbc77SKalle Valo continue; 1738f79cbc77SKalle Valo } 1739f79cbc77SKalle Valo 1740f79cbc77SKalle Valo /* 1741f79cbc77SKalle Valo * reserve some space for our vendor and the normal 1742f79cbc77SKalle Valo * radiotap header, since we're copying anyway 1743f79cbc77SKalle Valo */ 1744f79cbc77SKalle Valo if (skb->len < PAGE_SIZE && paged_rx) { 1745f79cbc77SKalle Valo struct page *page = alloc_page(GFP_ATOMIC); 1746f79cbc77SKalle Valo 1747f79cbc77SKalle Valo if (!page) 1748f79cbc77SKalle Valo continue; 1749f79cbc77SKalle Valo 1750f79cbc77SKalle Valo nskb = dev_alloc_skb(128); 1751f79cbc77SKalle Valo if (!nskb) { 1752f79cbc77SKalle Valo __free_page(page); 1753f79cbc77SKalle Valo continue; 1754f79cbc77SKalle Valo } 1755f79cbc77SKalle Valo 1756f79cbc77SKalle Valo memcpy(page_address(page), skb->data, skb->len); 1757f79cbc77SKalle Valo skb_add_rx_frag(nskb, 0, page, 0, skb->len, skb->len); 1758f79cbc77SKalle Valo } else { 1759f79cbc77SKalle Valo nskb = skb_copy(skb, GFP_ATOMIC); 1760f79cbc77SKalle Valo if (!nskb) 1761f79cbc77SKalle Valo continue; 1762f79cbc77SKalle Valo } 1763f79cbc77SKalle Valo 1764f79cbc77SKalle Valo if (mac80211_hwsim_addr_match(data2, hdr->addr1)) 1765f79cbc77SKalle Valo ack = true; 1766f79cbc77SKalle Valo 1767f79cbc77SKalle Valo rx_status.mactime = now + data2->tsf_offset; 1768f79cbc77SKalle Valo 1769f79cbc77SKalle Valo mac80211_hwsim_rx(data2, &rx_status, nskb); 1770f79cbc77SKalle Valo } 1771f79cbc77SKalle Valo spin_unlock(&hwsim_radio_lock); 1772f79cbc77SKalle Valo 1773f79cbc77SKalle Valo return ack; 1774f79cbc77SKalle Valo } 1775f79cbc77SKalle Valo 1776f79cbc77SKalle Valo static struct ieee80211_bss_conf * 1777f79cbc77SKalle Valo mac80211_hwsim_select_tx_link(struct mac80211_hwsim_data *data, 1778f79cbc77SKalle Valo struct ieee80211_vif *vif, 1779f79cbc77SKalle Valo struct ieee80211_sta *sta, 1780f79cbc77SKalle Valo struct ieee80211_hdr *hdr, 1781f79cbc77SKalle Valo struct ieee80211_link_sta **link_sta) 1782f79cbc77SKalle Valo { 1783f79cbc77SKalle Valo struct hwsim_sta_priv *sp = (void *)sta->drv_priv; 1784f79cbc77SKalle Valo int i; 1785f79cbc77SKalle Valo 1786f79cbc77SKalle Valo if (!vif->valid_links) 1787f79cbc77SKalle Valo return &vif->bss_conf; 1788f79cbc77SKalle Valo 1789f79cbc77SKalle Valo WARN_ON(is_multicast_ether_addr(hdr->addr1)); 1790f79cbc77SKalle Valo 1791f79cbc77SKalle Valo if (WARN_ON_ONCE(!sta->valid_links)) 1792f79cbc77SKalle Valo return &vif->bss_conf; 1793f79cbc77SKalle Valo 1794f79cbc77SKalle Valo for (i = 0; i < ARRAY_SIZE(vif->link_conf); i++) { 1795f79cbc77SKalle Valo struct ieee80211_bss_conf *bss_conf; 1796f79cbc77SKalle Valo unsigned int link_id; 1797f79cbc77SKalle Valo 1798f79cbc77SKalle Valo /* round-robin the available link IDs */ 1799f79cbc77SKalle Valo link_id = (sp->last_link + i + 1) % ARRAY_SIZE(vif->link_conf); 1800f79cbc77SKalle Valo 1801f79cbc77SKalle Valo if (!(vif->active_links & BIT(link_id))) 1802f79cbc77SKalle Valo continue; 1803f79cbc77SKalle Valo 1804f79cbc77SKalle Valo if (!(sp->active_links_rx & BIT(link_id))) 1805f79cbc77SKalle Valo continue; 1806f79cbc77SKalle Valo 1807f79cbc77SKalle Valo *link_sta = rcu_dereference(sta->link[link_id]); 1808f79cbc77SKalle Valo if (!*link_sta) 1809f79cbc77SKalle Valo continue; 1810f79cbc77SKalle Valo 1811f79cbc77SKalle Valo bss_conf = rcu_dereference(vif->link_conf[link_id]); 1812f79cbc77SKalle Valo if (WARN_ON_ONCE(!bss_conf)) 1813f79cbc77SKalle Valo continue; 1814f79cbc77SKalle Valo 1815f79cbc77SKalle Valo /* can happen while switching links */ 1816f79cbc77SKalle Valo if (!rcu_access_pointer(bss_conf->chanctx_conf)) 1817f79cbc77SKalle Valo continue; 1818f79cbc77SKalle Valo 1819f79cbc77SKalle Valo sp->last_link = link_id; 1820f79cbc77SKalle Valo return bss_conf; 1821f79cbc77SKalle Valo } 1822f79cbc77SKalle Valo 1823f79cbc77SKalle Valo return NULL; 1824f79cbc77SKalle Valo } 1825f79cbc77SKalle Valo 1826f79cbc77SKalle Valo static void mac80211_hwsim_tx(struct ieee80211_hw *hw, 1827f79cbc77SKalle Valo struct ieee80211_tx_control *control, 1828f79cbc77SKalle Valo struct sk_buff *skb) 1829f79cbc77SKalle Valo { 1830f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 1831f79cbc77SKalle Valo struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb); 1832f79cbc77SKalle Valo struct ieee80211_hdr *hdr = (void *)skb->data; 1833f79cbc77SKalle Valo struct ieee80211_chanctx_conf *chanctx_conf; 1834f79cbc77SKalle Valo struct ieee80211_channel *channel; 1835f79cbc77SKalle Valo bool ack; 1836f79cbc77SKalle Valo enum nl80211_chan_width confbw = NL80211_CHAN_WIDTH_20_NOHT; 1837f79cbc77SKalle Valo u32 _portid, i; 1838f79cbc77SKalle Valo 1839f79cbc77SKalle Valo if (WARN_ON(skb->len < 10)) { 1840f79cbc77SKalle Valo /* Should not happen; just a sanity check for addr1 use */ 1841f79cbc77SKalle Valo ieee80211_free_txskb(hw, skb); 1842f79cbc77SKalle Valo return; 1843f79cbc77SKalle Valo } 1844f79cbc77SKalle Valo 1845f79cbc77SKalle Valo if (!data->use_chanctx) { 1846f79cbc77SKalle Valo channel = data->channel; 1847f79cbc77SKalle Valo confbw = data->bw; 1848f79cbc77SKalle Valo } else if (txi->hw_queue == 4) { 1849f79cbc77SKalle Valo channel = data->tmp_chan; 1850f79cbc77SKalle Valo } else { 1851f79cbc77SKalle Valo u8 link = u32_get_bits(IEEE80211_SKB_CB(skb)->control.flags, 1852f79cbc77SKalle Valo IEEE80211_TX_CTRL_MLO_LINK); 1853f79cbc77SKalle Valo struct ieee80211_vif *vif = txi->control.vif; 1854f79cbc77SKalle Valo struct ieee80211_link_sta *link_sta = NULL; 1855f79cbc77SKalle Valo struct ieee80211_sta *sta = control->sta; 1856f79cbc77SKalle Valo struct ieee80211_bss_conf *bss_conf; 1857f79cbc77SKalle Valo 1858f79cbc77SKalle Valo if (link != IEEE80211_LINK_UNSPECIFIED) { 1859f79cbc77SKalle Valo bss_conf = rcu_dereference(txi->control.vif->link_conf[link]); 1860f79cbc77SKalle Valo if (sta) 1861f79cbc77SKalle Valo link_sta = rcu_dereference(sta->link[link]); 1862f79cbc77SKalle Valo } else { 1863f79cbc77SKalle Valo bss_conf = mac80211_hwsim_select_tx_link(data, vif, sta, 1864f79cbc77SKalle Valo hdr, &link_sta); 1865f79cbc77SKalle Valo } 1866f79cbc77SKalle Valo 1867f79cbc77SKalle Valo if (WARN_ON(!bss_conf)) { 1868f79cbc77SKalle Valo ieee80211_free_txskb(hw, skb); 1869f79cbc77SKalle Valo return; 1870f79cbc77SKalle Valo } 1871f79cbc77SKalle Valo 1872f79cbc77SKalle Valo if (sta && sta->mlo) { 1873f79cbc77SKalle Valo if (WARN_ON(!link_sta)) { 1874f79cbc77SKalle Valo ieee80211_free_txskb(hw, skb); 1875f79cbc77SKalle Valo return; 1876f79cbc77SKalle Valo } 1877f79cbc77SKalle Valo /* address translation to link addresses on TX */ 1878f79cbc77SKalle Valo ether_addr_copy(hdr->addr1, link_sta->addr); 1879f79cbc77SKalle Valo ether_addr_copy(hdr->addr2, bss_conf->addr); 1880f79cbc77SKalle Valo /* translate A3 only if it's the BSSID */ 1881f79cbc77SKalle Valo if (!ieee80211_has_tods(hdr->frame_control) && 1882f79cbc77SKalle Valo !ieee80211_has_fromds(hdr->frame_control)) { 1883f79cbc77SKalle Valo if (ether_addr_equal(hdr->addr3, sta->addr)) 1884f79cbc77SKalle Valo ether_addr_copy(hdr->addr3, link_sta->addr); 1885f79cbc77SKalle Valo else if (ether_addr_equal(hdr->addr3, vif->addr)) 1886f79cbc77SKalle Valo ether_addr_copy(hdr->addr3, bss_conf->addr); 1887f79cbc77SKalle Valo } 1888f79cbc77SKalle Valo /* no need to look at A4, if present it's SA */ 1889f79cbc77SKalle Valo } 1890f79cbc77SKalle Valo 1891f79cbc77SKalle Valo chanctx_conf = rcu_dereference(bss_conf->chanctx_conf); 1892f79cbc77SKalle Valo if (chanctx_conf) { 1893f79cbc77SKalle Valo channel = chanctx_conf->def.chan; 1894f79cbc77SKalle Valo confbw = chanctx_conf->def.width; 1895f79cbc77SKalle Valo } else { 1896f79cbc77SKalle Valo channel = NULL; 1897f79cbc77SKalle Valo } 1898f79cbc77SKalle Valo } 1899f79cbc77SKalle Valo 1900f79cbc77SKalle Valo if (WARN(!channel, "TX w/o channel - queue = %d\n", txi->hw_queue)) { 1901f79cbc77SKalle Valo ieee80211_free_txskb(hw, skb); 1902f79cbc77SKalle Valo return; 1903f79cbc77SKalle Valo } 1904f79cbc77SKalle Valo 1905f79cbc77SKalle Valo if (data->idle && !data->tmp_chan) { 1906f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "Trying to TX when idle - reject\n"); 1907f79cbc77SKalle Valo ieee80211_free_txskb(hw, skb); 1908f79cbc77SKalle Valo return; 1909f79cbc77SKalle Valo } 1910f79cbc77SKalle Valo 1911f79cbc77SKalle Valo if (txi->control.vif) 1912f79cbc77SKalle Valo hwsim_check_magic(txi->control.vif); 1913f79cbc77SKalle Valo if (control->sta) 1914f79cbc77SKalle Valo hwsim_check_sta_magic(control->sta); 1915f79cbc77SKalle Valo 1916f79cbc77SKalle Valo if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE)) 1917f79cbc77SKalle Valo ieee80211_get_tx_rates(txi->control.vif, control->sta, skb, 1918f79cbc77SKalle Valo txi->control.rates, 1919f79cbc77SKalle Valo ARRAY_SIZE(txi->control.rates)); 1920f79cbc77SKalle Valo 1921f79cbc77SKalle Valo for (i = 0; i < ARRAY_SIZE(txi->control.rates); i++) { 1922f79cbc77SKalle Valo u16 rflags = txi->control.rates[i].flags; 1923f79cbc77SKalle Valo /* initialize to data->bw for 5/10 MHz handling */ 1924f79cbc77SKalle Valo enum nl80211_chan_width bw = data->bw; 1925f79cbc77SKalle Valo 1926f79cbc77SKalle Valo if (txi->control.rates[i].idx == -1) 1927f79cbc77SKalle Valo break; 1928f79cbc77SKalle Valo 1929f79cbc77SKalle Valo if (rflags & IEEE80211_TX_RC_40_MHZ_WIDTH) 1930f79cbc77SKalle Valo bw = NL80211_CHAN_WIDTH_40; 1931f79cbc77SKalle Valo else if (rflags & IEEE80211_TX_RC_80_MHZ_WIDTH) 1932f79cbc77SKalle Valo bw = NL80211_CHAN_WIDTH_80; 1933f79cbc77SKalle Valo else if (rflags & IEEE80211_TX_RC_160_MHZ_WIDTH) 1934f79cbc77SKalle Valo bw = NL80211_CHAN_WIDTH_160; 1935f79cbc77SKalle Valo 1936f79cbc77SKalle Valo if (WARN_ON(hwsim_get_chanwidth(bw) > hwsim_get_chanwidth(confbw))) 1937f79cbc77SKalle Valo return; 1938f79cbc77SKalle Valo } 1939f79cbc77SKalle Valo 1940f79cbc77SKalle Valo if (skb->len >= 24 + 8 && 1941f79cbc77SKalle Valo ieee80211_is_probe_resp(hdr->frame_control)) { 1942f79cbc77SKalle Valo /* fake header transmission time */ 1943f79cbc77SKalle Valo struct ieee80211_mgmt *mgmt; 1944f79cbc77SKalle Valo struct ieee80211_rate *txrate; 1945f79cbc77SKalle Valo /* TODO: get MCS */ 1946f79cbc77SKalle Valo int bitrate = 100; 1947f79cbc77SKalle Valo u64 ts; 1948f79cbc77SKalle Valo 1949f79cbc77SKalle Valo mgmt = (struct ieee80211_mgmt *)skb->data; 1950f79cbc77SKalle Valo txrate = ieee80211_get_tx_rate(hw, txi); 1951f79cbc77SKalle Valo if (txrate) 1952f79cbc77SKalle Valo bitrate = txrate->bitrate; 1953f79cbc77SKalle Valo ts = mac80211_hwsim_get_tsf_raw(); 1954f79cbc77SKalle Valo mgmt->u.probe_resp.timestamp = 1955f79cbc77SKalle Valo cpu_to_le64(ts + data->tsf_offset + 1956f79cbc77SKalle Valo 24 * 8 * 10 / bitrate); 1957f79cbc77SKalle Valo } 1958f79cbc77SKalle Valo 1959f79cbc77SKalle Valo mac80211_hwsim_monitor_rx(hw, skb, channel); 1960f79cbc77SKalle Valo 1961f79cbc77SKalle Valo /* wmediumd mode check */ 1962f79cbc77SKalle Valo _portid = READ_ONCE(data->wmediumd); 1963f79cbc77SKalle Valo 1964f79cbc77SKalle Valo if (_portid || hwsim_virtio_enabled) 1965f79cbc77SKalle Valo return mac80211_hwsim_tx_frame_nl(hw, skb, _portid, channel); 1966f79cbc77SKalle Valo 1967f79cbc77SKalle Valo /* NO wmediumd detected, perfect medium simulation */ 1968f79cbc77SKalle Valo data->tx_pkts++; 1969f79cbc77SKalle Valo data->tx_bytes += skb->len; 1970f79cbc77SKalle Valo ack = mac80211_hwsim_tx_frame_no_nl(hw, skb, channel); 1971f79cbc77SKalle Valo 1972f79cbc77SKalle Valo if (ack && skb->len >= 16) 1973f79cbc77SKalle Valo mac80211_hwsim_monitor_ack(channel, hdr->addr2); 1974f79cbc77SKalle Valo 1975f79cbc77SKalle Valo ieee80211_tx_info_clear_status(txi); 1976f79cbc77SKalle Valo 1977f79cbc77SKalle Valo /* frame was transmitted at most favorable rate at first attempt */ 1978f79cbc77SKalle Valo txi->control.rates[0].count = 1; 1979f79cbc77SKalle Valo txi->control.rates[1].idx = -1; 1980f79cbc77SKalle Valo 1981f79cbc77SKalle Valo if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) && ack) 1982f79cbc77SKalle Valo txi->flags |= IEEE80211_TX_STAT_ACK; 1983f79cbc77SKalle Valo ieee80211_tx_status_irqsafe(hw, skb); 1984f79cbc77SKalle Valo } 1985f79cbc77SKalle Valo 1986f79cbc77SKalle Valo 1987f79cbc77SKalle Valo static int mac80211_hwsim_start(struct ieee80211_hw *hw) 1988f79cbc77SKalle Valo { 1989f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 1990f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "%s\n", __func__); 1991f79cbc77SKalle Valo data->started = true; 1992f79cbc77SKalle Valo return 0; 1993f79cbc77SKalle Valo } 1994f79cbc77SKalle Valo 1995f79cbc77SKalle Valo 1996f79cbc77SKalle Valo static void mac80211_hwsim_stop(struct ieee80211_hw *hw) 1997f79cbc77SKalle Valo { 1998f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 1999f79cbc77SKalle Valo int i; 2000f79cbc77SKalle Valo 2001f79cbc77SKalle Valo data->started = false; 2002f79cbc77SKalle Valo 2003f79cbc77SKalle Valo for (i = 0; i < ARRAY_SIZE(data->link_data); i++) 2004f79cbc77SKalle Valo hrtimer_cancel(&data->link_data[i].beacon_timer); 2005f79cbc77SKalle Valo 2006f79cbc77SKalle Valo while (!skb_queue_empty(&data->pending)) 2007f79cbc77SKalle Valo ieee80211_free_txskb(hw, skb_dequeue(&data->pending)); 2008f79cbc77SKalle Valo 2009f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "%s\n", __func__); 2010f79cbc77SKalle Valo } 2011f79cbc77SKalle Valo 2012f79cbc77SKalle Valo 2013f79cbc77SKalle Valo static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw, 2014f79cbc77SKalle Valo struct ieee80211_vif *vif) 2015f79cbc77SKalle Valo { 2016f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "%s (type=%d mac_addr=%pM)\n", 2017f79cbc77SKalle Valo __func__, ieee80211_vif_type_p2p(vif), 2018f79cbc77SKalle Valo vif->addr); 2019f79cbc77SKalle Valo hwsim_set_magic(vif); 2020f79cbc77SKalle Valo 2021f79cbc77SKalle Valo if (vif->type != NL80211_IFTYPE_MONITOR) 2022f79cbc77SKalle Valo mac80211_hwsim_config_mac_nl(hw, vif->addr, true); 2023f79cbc77SKalle Valo 2024f79cbc77SKalle Valo vif->cab_queue = 0; 2025f79cbc77SKalle Valo vif->hw_queue[IEEE80211_AC_VO] = 0; 2026f79cbc77SKalle Valo vif->hw_queue[IEEE80211_AC_VI] = 1; 2027f79cbc77SKalle Valo vif->hw_queue[IEEE80211_AC_BE] = 2; 2028f79cbc77SKalle Valo vif->hw_queue[IEEE80211_AC_BK] = 3; 2029f79cbc77SKalle Valo 2030f79cbc77SKalle Valo return 0; 2031f79cbc77SKalle Valo } 2032f79cbc77SKalle Valo 2033f79cbc77SKalle Valo 2034f79cbc77SKalle Valo static int mac80211_hwsim_change_interface(struct ieee80211_hw *hw, 2035f79cbc77SKalle Valo struct ieee80211_vif *vif, 2036f79cbc77SKalle Valo enum nl80211_iftype newtype, 2037f79cbc77SKalle Valo bool newp2p) 2038f79cbc77SKalle Valo { 2039f79cbc77SKalle Valo newtype = ieee80211_iftype_p2p(newtype, newp2p); 2040f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, 2041f79cbc77SKalle Valo "%s (old type=%d, new type=%d, mac_addr=%pM)\n", 2042f79cbc77SKalle Valo __func__, ieee80211_vif_type_p2p(vif), 2043f79cbc77SKalle Valo newtype, vif->addr); 2044f79cbc77SKalle Valo hwsim_check_magic(vif); 2045f79cbc77SKalle Valo 2046f79cbc77SKalle Valo /* 2047f79cbc77SKalle Valo * interface may change from non-AP to AP in 2048f79cbc77SKalle Valo * which case this needs to be set up again 2049f79cbc77SKalle Valo */ 2050f79cbc77SKalle Valo vif->cab_queue = 0; 2051f79cbc77SKalle Valo 2052f79cbc77SKalle Valo return 0; 2053f79cbc77SKalle Valo } 2054f79cbc77SKalle Valo 2055f79cbc77SKalle Valo static void mac80211_hwsim_remove_interface( 2056f79cbc77SKalle Valo struct ieee80211_hw *hw, struct ieee80211_vif *vif) 2057f79cbc77SKalle Valo { 2058f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "%s (type=%d mac_addr=%pM)\n", 2059f79cbc77SKalle Valo __func__, ieee80211_vif_type_p2p(vif), 2060f79cbc77SKalle Valo vif->addr); 2061f79cbc77SKalle Valo hwsim_check_magic(vif); 2062f79cbc77SKalle Valo hwsim_clear_magic(vif); 2063f79cbc77SKalle Valo if (vif->type != NL80211_IFTYPE_MONITOR) 2064f79cbc77SKalle Valo mac80211_hwsim_config_mac_nl(hw, vif->addr, false); 2065f79cbc77SKalle Valo } 2066f79cbc77SKalle Valo 2067f79cbc77SKalle Valo static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, 2068f79cbc77SKalle Valo struct sk_buff *skb, 2069f79cbc77SKalle Valo struct ieee80211_channel *chan) 2070f79cbc77SKalle Valo { 2071f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 2072f79cbc77SKalle Valo u32 _portid = READ_ONCE(data->wmediumd); 2073f79cbc77SKalle Valo 2074f79cbc77SKalle Valo if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE)) { 2075f79cbc77SKalle Valo struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb); 2076f79cbc77SKalle Valo ieee80211_get_tx_rates(txi->control.vif, NULL, skb, 2077f79cbc77SKalle Valo txi->control.rates, 2078f79cbc77SKalle Valo ARRAY_SIZE(txi->control.rates)); 2079f79cbc77SKalle Valo } 2080f79cbc77SKalle Valo 2081f79cbc77SKalle Valo mac80211_hwsim_monitor_rx(hw, skb, chan); 2082f79cbc77SKalle Valo 2083f79cbc77SKalle Valo if (_portid || hwsim_virtio_enabled) 2084f79cbc77SKalle Valo return mac80211_hwsim_tx_frame_nl(hw, skb, _portid, chan); 2085f79cbc77SKalle Valo 2086f79cbc77SKalle Valo data->tx_pkts++; 2087f79cbc77SKalle Valo data->tx_bytes += skb->len; 2088f79cbc77SKalle Valo mac80211_hwsim_tx_frame_no_nl(hw, skb, chan); 2089f79cbc77SKalle Valo dev_kfree_skb(skb); 2090f79cbc77SKalle Valo } 2091f79cbc77SKalle Valo 2092b3a912e3SAloka Dixit static void __mac80211_hwsim_beacon_tx(struct ieee80211_bss_conf *link_conf, 2093b3a912e3SAloka Dixit struct mac80211_hwsim_data *data, 2094b3a912e3SAloka Dixit struct ieee80211_hw *hw, 2095b3a912e3SAloka Dixit struct ieee80211_vif *vif, 2096b3a912e3SAloka Dixit struct sk_buff *skb) 2097f79cbc77SKalle Valo { 2098f79cbc77SKalle Valo struct ieee80211_tx_info *info; 2099f79cbc77SKalle Valo struct ieee80211_rate *txrate; 2100f79cbc77SKalle Valo struct ieee80211_mgmt *mgmt; 2101f79cbc77SKalle Valo /* TODO: get MCS */ 2102f79cbc77SKalle Valo int bitrate = 100; 2103f79cbc77SKalle Valo 2104f79cbc77SKalle Valo info = IEEE80211_SKB_CB(skb); 2105f79cbc77SKalle Valo if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE)) 2106f79cbc77SKalle Valo ieee80211_get_tx_rates(vif, NULL, skb, 2107f79cbc77SKalle Valo info->control.rates, 2108f79cbc77SKalle Valo ARRAY_SIZE(info->control.rates)); 2109f79cbc77SKalle Valo 2110f79cbc77SKalle Valo txrate = ieee80211_get_tx_rate(hw, info); 2111f79cbc77SKalle Valo if (txrate) 2112f79cbc77SKalle Valo bitrate = txrate->bitrate; 2113f79cbc77SKalle Valo 2114f79cbc77SKalle Valo mgmt = (struct ieee80211_mgmt *) skb->data; 2115f79cbc77SKalle Valo /* fake header transmission time */ 2116f79cbc77SKalle Valo data->abs_bcn_ts = mac80211_hwsim_get_tsf_raw(); 2117f79cbc77SKalle Valo if (ieee80211_is_s1g_beacon(mgmt->frame_control)) { 2118f79cbc77SKalle Valo struct ieee80211_ext *ext = (void *) mgmt; 2119f79cbc77SKalle Valo 2120f79cbc77SKalle Valo ext->u.s1g_beacon.timestamp = cpu_to_le32(data->abs_bcn_ts + 2121f79cbc77SKalle Valo data->tsf_offset + 2122f79cbc77SKalle Valo 10 * 8 * 10 / 2123f79cbc77SKalle Valo bitrate); 2124f79cbc77SKalle Valo } else { 2125f79cbc77SKalle Valo mgmt->u.beacon.timestamp = cpu_to_le64(data->abs_bcn_ts + 2126f79cbc77SKalle Valo data->tsf_offset + 2127f79cbc77SKalle Valo 24 * 8 * 10 / 2128f79cbc77SKalle Valo bitrate); 2129f79cbc77SKalle Valo } 2130f79cbc77SKalle Valo 2131f79cbc77SKalle Valo mac80211_hwsim_tx_frame(hw, skb, 2132f79cbc77SKalle Valo rcu_dereference(link_conf->chanctx_conf)->def.chan); 2133b3a912e3SAloka Dixit } 2134b3a912e3SAloka Dixit 2135b3a912e3SAloka Dixit static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, 2136b3a912e3SAloka Dixit struct ieee80211_vif *vif) 2137b3a912e3SAloka Dixit { 2138b3a912e3SAloka Dixit struct mac80211_hwsim_link_data *link_data = arg; 2139b3a912e3SAloka Dixit u32 link_id = link_data->link_id; 2140b3a912e3SAloka Dixit struct ieee80211_bss_conf *link_conf; 2141b3a912e3SAloka Dixit struct mac80211_hwsim_data *data = 2142b3a912e3SAloka Dixit container_of(link_data, struct mac80211_hwsim_data, 2143b3a912e3SAloka Dixit link_data[link_id]); 2144b3a912e3SAloka Dixit struct ieee80211_hw *hw = data->hw; 2145b3a912e3SAloka Dixit struct sk_buff *skb; 2146b3a912e3SAloka Dixit 2147b3a912e3SAloka Dixit hwsim_check_magic(vif); 2148b3a912e3SAloka Dixit 2149b3a912e3SAloka Dixit link_conf = rcu_dereference(vif->link_conf[link_id]); 2150b3a912e3SAloka Dixit if (!link_conf) 2151b3a912e3SAloka Dixit return; 2152b3a912e3SAloka Dixit 2153b3a912e3SAloka Dixit if (vif->type != NL80211_IFTYPE_AP && 2154b3a912e3SAloka Dixit vif->type != NL80211_IFTYPE_MESH_POINT && 2155b3a912e3SAloka Dixit vif->type != NL80211_IFTYPE_ADHOC && 2156b3a912e3SAloka Dixit vif->type != NL80211_IFTYPE_OCB) 2157b3a912e3SAloka Dixit return; 2158b3a912e3SAloka Dixit 2159c4f4d9f7SAloka Dixit if (vif->mbssid_tx_vif && vif->mbssid_tx_vif != vif) 2160c4f4d9f7SAloka Dixit return; 2161c4f4d9f7SAloka Dixit 21620dd45ebcSAloka Dixit if (vif->bss_conf.ema_ap) { 21630dd45ebcSAloka Dixit struct ieee80211_ema_beacons *ema; 21640dd45ebcSAloka Dixit u8 i = 0; 21650dd45ebcSAloka Dixit 21660dd45ebcSAloka Dixit ema = ieee80211_beacon_get_template_ema_list(hw, vif, link_id); 21670dd45ebcSAloka Dixit if (!ema || !ema->cnt) 21680dd45ebcSAloka Dixit return; 21690dd45ebcSAloka Dixit 21700dd45ebcSAloka Dixit for (i = 0; i < ema->cnt; i++) { 21710dd45ebcSAloka Dixit __mac80211_hwsim_beacon_tx(link_conf, data, hw, vif, 21720dd45ebcSAloka Dixit ema->bcn[i].skb); 21730dd45ebcSAloka Dixit ema->bcn[i].skb = NULL; /* Already freed */ 21740dd45ebcSAloka Dixit } 21750dd45ebcSAloka Dixit ieee80211_beacon_free_ema_list(ema); 21760dd45ebcSAloka Dixit } else { 2177b3a912e3SAloka Dixit skb = ieee80211_beacon_get(hw, vif, link_id); 2178b3a912e3SAloka Dixit if (!skb) 2179b3a912e3SAloka Dixit return; 2180b3a912e3SAloka Dixit 2181b3a912e3SAloka Dixit __mac80211_hwsim_beacon_tx(link_conf, data, hw, vif, skb); 21820dd45ebcSAloka Dixit } 2183f79cbc77SKalle Valo 2184f79cbc77SKalle Valo while ((skb = ieee80211_get_buffered_bc(hw, vif)) != NULL) { 2185f79cbc77SKalle Valo mac80211_hwsim_tx_frame(hw, skb, 2186f79cbc77SKalle Valo rcu_dereference(link_conf->chanctx_conf)->def.chan); 2187f79cbc77SKalle Valo } 2188f79cbc77SKalle Valo 2189f79cbc77SKalle Valo if (link_conf->csa_active && ieee80211_beacon_cntdwn_is_complete(vif)) 2190f79cbc77SKalle Valo ieee80211_csa_finish(vif); 2191f79cbc77SKalle Valo } 2192f79cbc77SKalle Valo 2193f79cbc77SKalle Valo static enum hrtimer_restart 2194f79cbc77SKalle Valo mac80211_hwsim_beacon(struct hrtimer *timer) 2195f79cbc77SKalle Valo { 2196f79cbc77SKalle Valo struct mac80211_hwsim_link_data *link_data = 2197f79cbc77SKalle Valo container_of(timer, struct mac80211_hwsim_link_data, beacon_timer); 2198f79cbc77SKalle Valo struct mac80211_hwsim_data *data = 2199f79cbc77SKalle Valo container_of(link_data, struct mac80211_hwsim_data, 2200f79cbc77SKalle Valo link_data[link_data->link_id]); 2201f79cbc77SKalle Valo struct ieee80211_hw *hw = data->hw; 2202f79cbc77SKalle Valo u64 bcn_int = link_data->beacon_int; 2203f79cbc77SKalle Valo 2204f79cbc77SKalle Valo if (!data->started) 2205f79cbc77SKalle Valo return HRTIMER_NORESTART; 2206f79cbc77SKalle Valo 2207f79cbc77SKalle Valo ieee80211_iterate_active_interfaces_atomic( 2208f79cbc77SKalle Valo hw, IEEE80211_IFACE_ITER_NORMAL, 2209f79cbc77SKalle Valo mac80211_hwsim_beacon_tx, link_data); 2210f79cbc77SKalle Valo 2211f79cbc77SKalle Valo /* beacon at new TBTT + beacon interval */ 2212f79cbc77SKalle Valo if (data->bcn_delta) { 2213f79cbc77SKalle Valo bcn_int -= data->bcn_delta; 2214f79cbc77SKalle Valo data->bcn_delta = 0; 2215f79cbc77SKalle Valo } 2216f79cbc77SKalle Valo hrtimer_forward_now(&link_data->beacon_timer, 2217f79cbc77SKalle Valo ns_to_ktime(bcn_int * NSEC_PER_USEC)); 2218f79cbc77SKalle Valo return HRTIMER_RESTART; 2219f79cbc77SKalle Valo } 2220f79cbc77SKalle Valo 2221f79cbc77SKalle Valo static const char * const hwsim_chanwidths[] = { 2222f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_5] = "ht5", 2223f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_10] = "ht10", 2224f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_20_NOHT] = "noht", 2225f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_20] = "ht20", 2226f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_40] = "ht40", 2227f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_80] = "vht80", 2228f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_80P80] = "vht80p80", 2229f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_160] = "vht160", 2230f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_1] = "1MHz", 2231f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_2] = "2MHz", 2232f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_4] = "4MHz", 2233f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_8] = "8MHz", 2234f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_16] = "16MHz", 2235f79cbc77SKalle Valo }; 2236f79cbc77SKalle Valo 2237f79cbc77SKalle Valo static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) 2238f79cbc77SKalle Valo { 2239f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 2240f79cbc77SKalle Valo struct ieee80211_conf *conf = &hw->conf; 2241f79cbc77SKalle Valo static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = { 2242f79cbc77SKalle Valo [IEEE80211_SMPS_AUTOMATIC] = "auto", 2243f79cbc77SKalle Valo [IEEE80211_SMPS_OFF] = "off", 2244f79cbc77SKalle Valo [IEEE80211_SMPS_STATIC] = "static", 2245f79cbc77SKalle Valo [IEEE80211_SMPS_DYNAMIC] = "dynamic", 2246f79cbc77SKalle Valo }; 2247f79cbc77SKalle Valo int idx; 2248f79cbc77SKalle Valo 2249f79cbc77SKalle Valo if (conf->chandef.chan) 2250f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, 2251f79cbc77SKalle Valo "%s (freq=%d(%d - %d)/%s idle=%d ps=%d smps=%s)\n", 2252f79cbc77SKalle Valo __func__, 2253f79cbc77SKalle Valo conf->chandef.chan->center_freq, 2254f79cbc77SKalle Valo conf->chandef.center_freq1, 2255f79cbc77SKalle Valo conf->chandef.center_freq2, 2256f79cbc77SKalle Valo hwsim_chanwidths[conf->chandef.width], 2257f79cbc77SKalle Valo !!(conf->flags & IEEE80211_CONF_IDLE), 2258f79cbc77SKalle Valo !!(conf->flags & IEEE80211_CONF_PS), 2259f79cbc77SKalle Valo smps_modes[conf->smps_mode]); 2260f79cbc77SKalle Valo else 2261f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, 2262f79cbc77SKalle Valo "%s (freq=0 idle=%d ps=%d smps=%s)\n", 2263f79cbc77SKalle Valo __func__, 2264f79cbc77SKalle Valo !!(conf->flags & IEEE80211_CONF_IDLE), 2265f79cbc77SKalle Valo !!(conf->flags & IEEE80211_CONF_PS), 2266f79cbc77SKalle Valo smps_modes[conf->smps_mode]); 2267f79cbc77SKalle Valo 2268f79cbc77SKalle Valo data->idle = !!(conf->flags & IEEE80211_CONF_IDLE); 2269f79cbc77SKalle Valo 2270f79cbc77SKalle Valo WARN_ON(conf->chandef.chan && data->use_chanctx); 2271f79cbc77SKalle Valo 2272f79cbc77SKalle Valo mutex_lock(&data->mutex); 2273f79cbc77SKalle Valo if (data->scanning && conf->chandef.chan) { 2274f79cbc77SKalle Valo for (idx = 0; idx < ARRAY_SIZE(data->survey_data); idx++) { 2275f79cbc77SKalle Valo if (data->survey_data[idx].channel == data->channel) { 2276f79cbc77SKalle Valo data->survey_data[idx].start = 2277f79cbc77SKalle Valo data->survey_data[idx].next_start; 2278f79cbc77SKalle Valo data->survey_data[idx].end = jiffies; 2279f79cbc77SKalle Valo break; 2280f79cbc77SKalle Valo } 2281f79cbc77SKalle Valo } 2282f79cbc77SKalle Valo 2283f79cbc77SKalle Valo data->channel = conf->chandef.chan; 2284f79cbc77SKalle Valo data->bw = conf->chandef.width; 2285f79cbc77SKalle Valo 2286f79cbc77SKalle Valo for (idx = 0; idx < ARRAY_SIZE(data->survey_data); idx++) { 2287f79cbc77SKalle Valo if (data->survey_data[idx].channel && 2288f79cbc77SKalle Valo data->survey_data[idx].channel != data->channel) 2289f79cbc77SKalle Valo continue; 2290f79cbc77SKalle Valo data->survey_data[idx].channel = data->channel; 2291f79cbc77SKalle Valo data->survey_data[idx].next_start = jiffies; 2292f79cbc77SKalle Valo break; 2293f79cbc77SKalle Valo } 2294f79cbc77SKalle Valo } else { 2295f79cbc77SKalle Valo data->channel = conf->chandef.chan; 2296f79cbc77SKalle Valo data->bw = conf->chandef.width; 2297f79cbc77SKalle Valo } 2298f79cbc77SKalle Valo mutex_unlock(&data->mutex); 2299f79cbc77SKalle Valo 2300f79cbc77SKalle Valo for (idx = 0; idx < ARRAY_SIZE(data->link_data); idx++) { 2301f79cbc77SKalle Valo struct mac80211_hwsim_link_data *link_data = 2302f79cbc77SKalle Valo &data->link_data[idx]; 2303f79cbc77SKalle Valo 2304f79cbc77SKalle Valo if (!data->started || !link_data->beacon_int) { 2305f79cbc77SKalle Valo hrtimer_cancel(&link_data->beacon_timer); 2306f79cbc77SKalle Valo } else if (!hrtimer_is_queued(&link_data->beacon_timer)) { 2307f79cbc77SKalle Valo u64 tsf = mac80211_hwsim_get_tsf(hw, NULL); 2308f79cbc77SKalle Valo u32 bcn_int = link_data->beacon_int; 2309f79cbc77SKalle Valo u64 until_tbtt = bcn_int - do_div(tsf, bcn_int); 2310f79cbc77SKalle Valo 2311f79cbc77SKalle Valo hrtimer_start(&link_data->beacon_timer, 2312f79cbc77SKalle Valo ns_to_ktime(until_tbtt * NSEC_PER_USEC), 2313f79cbc77SKalle Valo HRTIMER_MODE_REL_SOFT); 2314f79cbc77SKalle Valo } 2315f79cbc77SKalle Valo } 2316f79cbc77SKalle Valo 2317f79cbc77SKalle Valo return 0; 2318f79cbc77SKalle Valo } 2319f79cbc77SKalle Valo 2320f79cbc77SKalle Valo 2321f79cbc77SKalle Valo static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw, 2322f79cbc77SKalle Valo unsigned int changed_flags, 2323f79cbc77SKalle Valo unsigned int *total_flags,u64 multicast) 2324f79cbc77SKalle Valo { 2325f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 2326f79cbc77SKalle Valo 2327f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "%s\n", __func__); 2328f79cbc77SKalle Valo 2329f79cbc77SKalle Valo data->rx_filter = 0; 2330f79cbc77SKalle Valo if (*total_flags & FIF_ALLMULTI) 2331f79cbc77SKalle Valo data->rx_filter |= FIF_ALLMULTI; 2332f79cbc77SKalle Valo if (*total_flags & FIF_MCAST_ACTION) 2333f79cbc77SKalle Valo data->rx_filter |= FIF_MCAST_ACTION; 2334f79cbc77SKalle Valo 2335f79cbc77SKalle Valo *total_flags = data->rx_filter; 2336f79cbc77SKalle Valo } 2337f79cbc77SKalle Valo 2338f79cbc77SKalle Valo static void mac80211_hwsim_bcn_en_iter(void *data, u8 *mac, 2339f79cbc77SKalle Valo struct ieee80211_vif *vif) 2340f79cbc77SKalle Valo { 2341f79cbc77SKalle Valo unsigned int *count = data; 2342f79cbc77SKalle Valo struct hwsim_vif_priv *vp = (void *)vif->drv_priv; 2343f79cbc77SKalle Valo 2344f79cbc77SKalle Valo if (vp->bcn_en) 2345f79cbc77SKalle Valo (*count)++; 2346f79cbc77SKalle Valo } 2347f79cbc77SKalle Valo 2348f79cbc77SKalle Valo static void mac80211_hwsim_vif_info_changed(struct ieee80211_hw *hw, 2349f79cbc77SKalle Valo struct ieee80211_vif *vif, 2350f79cbc77SKalle Valo u64 changed) 2351f79cbc77SKalle Valo { 2352f79cbc77SKalle Valo struct hwsim_vif_priv *vp = (void *)vif->drv_priv; 2353f79cbc77SKalle Valo 2354f79cbc77SKalle Valo hwsim_check_magic(vif); 2355f79cbc77SKalle Valo 2356f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "%s(changed=0x%llx vif->addr=%pM)\n", 2357f79cbc77SKalle Valo __func__, changed, vif->addr); 2358f79cbc77SKalle Valo 2359f79cbc77SKalle Valo if (changed & BSS_CHANGED_ASSOC) { 2360f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, " ASSOC: assoc=%d aid=%d\n", 2361f79cbc77SKalle Valo vif->cfg.assoc, vif->cfg.aid); 2362f79cbc77SKalle Valo vp->assoc = vif->cfg.assoc; 2363f79cbc77SKalle Valo vp->aid = vif->cfg.aid; 2364f79cbc77SKalle Valo } 2365f79cbc77SKalle Valo } 2366f79cbc77SKalle Valo 2367f79cbc77SKalle Valo static void mac80211_hwsim_link_info_changed(struct ieee80211_hw *hw, 2368f79cbc77SKalle Valo struct ieee80211_vif *vif, 2369f79cbc77SKalle Valo struct ieee80211_bss_conf *info, 2370f79cbc77SKalle Valo u64 changed) 2371f79cbc77SKalle Valo { 2372f79cbc77SKalle Valo struct hwsim_vif_priv *vp = (void *)vif->drv_priv; 2373f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 2374f79cbc77SKalle Valo unsigned int link_id = info->link_id; 2375f79cbc77SKalle Valo struct mac80211_hwsim_link_data *link_data = &data->link_data[link_id]; 2376f79cbc77SKalle Valo 2377f79cbc77SKalle Valo hwsim_check_magic(vif); 2378f79cbc77SKalle Valo 2379f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "%s(changed=0x%llx vif->addr=%pM, link id %u)\n", 2380f79cbc77SKalle Valo __func__, (unsigned long long)changed, vif->addr, link_id); 2381f79cbc77SKalle Valo 2382f79cbc77SKalle Valo if (changed & BSS_CHANGED_BSSID) { 2383f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "%s: BSSID changed: %pM\n", 2384f79cbc77SKalle Valo __func__, info->bssid); 2385f79cbc77SKalle Valo memcpy(vp->bssid, info->bssid, ETH_ALEN); 2386f79cbc77SKalle Valo } 2387f79cbc77SKalle Valo 2388f79cbc77SKalle Valo if (changed & BSS_CHANGED_BEACON_ENABLED) { 2389f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, " BCN EN: %d (BI=%u)\n", 2390f79cbc77SKalle Valo info->enable_beacon, info->beacon_int); 2391f79cbc77SKalle Valo vp->bcn_en = info->enable_beacon; 2392f79cbc77SKalle Valo if (data->started && 2393f79cbc77SKalle Valo !hrtimer_is_queued(&link_data->beacon_timer) && 2394f79cbc77SKalle Valo info->enable_beacon) { 2395f79cbc77SKalle Valo u64 tsf, until_tbtt; 2396f79cbc77SKalle Valo u32 bcn_int; 2397f79cbc77SKalle Valo link_data->beacon_int = info->beacon_int * 1024; 2398f79cbc77SKalle Valo tsf = mac80211_hwsim_get_tsf(hw, vif); 2399f79cbc77SKalle Valo bcn_int = link_data->beacon_int; 2400f79cbc77SKalle Valo until_tbtt = bcn_int - do_div(tsf, bcn_int); 2401f79cbc77SKalle Valo 2402f79cbc77SKalle Valo hrtimer_start(&link_data->beacon_timer, 2403f79cbc77SKalle Valo ns_to_ktime(until_tbtt * NSEC_PER_USEC), 2404f79cbc77SKalle Valo HRTIMER_MODE_REL_SOFT); 2405f79cbc77SKalle Valo } else if (!info->enable_beacon) { 2406f79cbc77SKalle Valo unsigned int count = 0; 2407f79cbc77SKalle Valo ieee80211_iterate_active_interfaces_atomic( 2408f79cbc77SKalle Valo data->hw, IEEE80211_IFACE_ITER_NORMAL, 2409f79cbc77SKalle Valo mac80211_hwsim_bcn_en_iter, &count); 2410f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, " beaconing vifs remaining: %u", 2411f79cbc77SKalle Valo count); 2412f79cbc77SKalle Valo if (count == 0) { 2413f79cbc77SKalle Valo hrtimer_cancel(&link_data->beacon_timer); 2414f79cbc77SKalle Valo link_data->beacon_int = 0; 2415f79cbc77SKalle Valo } 2416f79cbc77SKalle Valo } 2417f79cbc77SKalle Valo } 2418f79cbc77SKalle Valo 2419f79cbc77SKalle Valo if (changed & BSS_CHANGED_ERP_CTS_PROT) { 2420f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, " ERP_CTS_PROT: %d\n", 2421f79cbc77SKalle Valo info->use_cts_prot); 2422f79cbc77SKalle Valo } 2423f79cbc77SKalle Valo 2424f79cbc77SKalle Valo if (changed & BSS_CHANGED_ERP_PREAMBLE) { 2425f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, " ERP_PREAMBLE: %d\n", 2426f79cbc77SKalle Valo info->use_short_preamble); 2427f79cbc77SKalle Valo } 2428f79cbc77SKalle Valo 2429f79cbc77SKalle Valo if (changed & BSS_CHANGED_ERP_SLOT) { 2430f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, " ERP_SLOT: %d\n", info->use_short_slot); 2431f79cbc77SKalle Valo } 2432f79cbc77SKalle Valo 2433f79cbc77SKalle Valo if (changed & BSS_CHANGED_HT) { 2434f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, " HT: op_mode=0x%x\n", 2435f79cbc77SKalle Valo info->ht_operation_mode); 2436f79cbc77SKalle Valo } 2437f79cbc77SKalle Valo 2438f79cbc77SKalle Valo if (changed & BSS_CHANGED_BASIC_RATES) { 2439f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, " BASIC_RATES: 0x%llx\n", 2440f79cbc77SKalle Valo (unsigned long long) info->basic_rates); 2441f79cbc77SKalle Valo } 2442f79cbc77SKalle Valo 2443f79cbc77SKalle Valo if (changed & BSS_CHANGED_TXPOWER) 2444f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, " TX Power: %d dBm\n", info->txpower); 2445f79cbc77SKalle Valo } 2446f79cbc77SKalle Valo 2447f79cbc77SKalle Valo static void 2448f79cbc77SKalle Valo mac80211_hwsim_sta_rc_update(struct ieee80211_hw *hw, 2449f79cbc77SKalle Valo struct ieee80211_vif *vif, 2450f79cbc77SKalle Valo struct ieee80211_sta *sta, 2451f79cbc77SKalle Valo u32 changed) 2452f79cbc77SKalle Valo { 2453f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 2454f79cbc77SKalle Valo u32 bw = U32_MAX; 2455f79cbc77SKalle Valo int link_id; 2456f79cbc77SKalle Valo 2457f79cbc77SKalle Valo rcu_read_lock(); 2458f79cbc77SKalle Valo for (link_id = 0; 2459f79cbc77SKalle Valo link_id < ARRAY_SIZE(vif->link_conf); 2460f79cbc77SKalle Valo link_id++) { 2461f79cbc77SKalle Valo enum nl80211_chan_width confbw = NL80211_CHAN_WIDTH_20_NOHT; 2462f79cbc77SKalle Valo struct ieee80211_bss_conf *vif_conf; 2463f79cbc77SKalle Valo struct ieee80211_link_sta *link_sta; 2464f79cbc77SKalle Valo 2465f79cbc77SKalle Valo link_sta = rcu_dereference(sta->link[link_id]); 2466f79cbc77SKalle Valo 2467f79cbc77SKalle Valo if (!link_sta) 2468f79cbc77SKalle Valo continue; 2469f79cbc77SKalle Valo 2470f79cbc77SKalle Valo switch (link_sta->bandwidth) { 2471f79cbc77SKalle Valo #define C(_bw) case IEEE80211_STA_RX_BW_##_bw: bw = _bw; break 2472f79cbc77SKalle Valo C(20); 2473f79cbc77SKalle Valo C(40); 2474f79cbc77SKalle Valo C(80); 2475f79cbc77SKalle Valo C(160); 2476f79cbc77SKalle Valo C(320); 2477f79cbc77SKalle Valo #undef C 2478f79cbc77SKalle Valo } 2479f79cbc77SKalle Valo 2480f79cbc77SKalle Valo if (!data->use_chanctx) { 2481f79cbc77SKalle Valo confbw = data->bw; 2482f79cbc77SKalle Valo } else { 2483f79cbc77SKalle Valo struct ieee80211_chanctx_conf *chanctx_conf; 2484f79cbc77SKalle Valo 2485f79cbc77SKalle Valo vif_conf = rcu_dereference(vif->link_conf[link_id]); 2486f79cbc77SKalle Valo if (WARN_ON(!vif_conf)) 2487f79cbc77SKalle Valo continue; 2488f79cbc77SKalle Valo 2489f79cbc77SKalle Valo chanctx_conf = rcu_dereference(vif_conf->chanctx_conf); 2490f79cbc77SKalle Valo 2491f79cbc77SKalle Valo if (!WARN_ON(!chanctx_conf)) 2492f79cbc77SKalle Valo confbw = chanctx_conf->def.width; 2493f79cbc77SKalle Valo } 2494f79cbc77SKalle Valo 2495f79cbc77SKalle Valo WARN(bw > hwsim_get_chanwidth(confbw), 2496f79cbc77SKalle Valo "intf %pM [link=%d]: bad STA %pM bandwidth %d MHz (%d) > channel config %d MHz (%d)\n", 2497f79cbc77SKalle Valo vif->addr, link_id, sta->addr, bw, sta->deflink.bandwidth, 2498f79cbc77SKalle Valo hwsim_get_chanwidth(data->bw), data->bw); 2499f79cbc77SKalle Valo 2500f79cbc77SKalle Valo 2501f79cbc77SKalle Valo } 2502f79cbc77SKalle Valo rcu_read_unlock(); 2503f79cbc77SKalle Valo 2504f79cbc77SKalle Valo 2505f79cbc77SKalle Valo } 2506f79cbc77SKalle Valo 2507f79cbc77SKalle Valo static int mac80211_hwsim_sta_add(struct ieee80211_hw *hw, 2508f79cbc77SKalle Valo struct ieee80211_vif *vif, 2509f79cbc77SKalle Valo struct ieee80211_sta *sta) 2510f79cbc77SKalle Valo { 2511f79cbc77SKalle Valo struct hwsim_sta_priv *sp = (void *)sta->drv_priv; 2512f79cbc77SKalle Valo 2513f79cbc77SKalle Valo hwsim_check_magic(vif); 2514f79cbc77SKalle Valo hwsim_set_sta_magic(sta); 2515f79cbc77SKalle Valo mac80211_hwsim_sta_rc_update(hw, vif, sta, 0); 2516f79cbc77SKalle Valo 2517f79cbc77SKalle Valo if (sta->valid_links) { 2518f79cbc77SKalle Valo WARN(hweight16(sta->valid_links) > 1, 2519f79cbc77SKalle Valo "expect to add STA with single link, have 0x%x\n", 2520f79cbc77SKalle Valo sta->valid_links); 2521f79cbc77SKalle Valo sp->active_links_rx = sta->valid_links; 2522f79cbc77SKalle Valo } 2523f79cbc77SKalle Valo 2524f79cbc77SKalle Valo return 0; 2525f79cbc77SKalle Valo } 2526f79cbc77SKalle Valo 2527f79cbc77SKalle Valo static int mac80211_hwsim_sta_remove(struct ieee80211_hw *hw, 2528f79cbc77SKalle Valo struct ieee80211_vif *vif, 2529f79cbc77SKalle Valo struct ieee80211_sta *sta) 2530f79cbc77SKalle Valo { 2531f79cbc77SKalle Valo hwsim_check_magic(vif); 2532f79cbc77SKalle Valo hwsim_clear_sta_magic(sta); 2533f79cbc77SKalle Valo 2534f79cbc77SKalle Valo return 0; 2535f79cbc77SKalle Valo } 2536f79cbc77SKalle Valo 2537f79cbc77SKalle Valo static int mac80211_hwsim_sta_state(struct ieee80211_hw *hw, 2538f79cbc77SKalle Valo struct ieee80211_vif *vif, 2539f79cbc77SKalle Valo struct ieee80211_sta *sta, 2540f79cbc77SKalle Valo enum ieee80211_sta_state old_state, 2541f79cbc77SKalle Valo enum ieee80211_sta_state new_state) 2542f79cbc77SKalle Valo { 2543f79cbc77SKalle Valo if (new_state == IEEE80211_STA_NOTEXIST) 2544f79cbc77SKalle Valo return mac80211_hwsim_sta_remove(hw, vif, sta); 2545f79cbc77SKalle Valo 2546f79cbc77SKalle Valo if (old_state == IEEE80211_STA_NOTEXIST) 2547f79cbc77SKalle Valo return mac80211_hwsim_sta_add(hw, vif, sta); 2548f79cbc77SKalle Valo 2549f79cbc77SKalle Valo /* 2550f79cbc77SKalle Valo * when client is authorized (AP station marked as such), 2551f79cbc77SKalle Valo * enable all links 2552f79cbc77SKalle Valo */ 2553f79cbc77SKalle Valo if (vif->type == NL80211_IFTYPE_STATION && 2554f79cbc77SKalle Valo new_state == IEEE80211_STA_AUTHORIZED && !sta->tdls) 2555f79cbc77SKalle Valo ieee80211_set_active_links_async(vif, vif->valid_links); 2556f79cbc77SKalle Valo 2557f79cbc77SKalle Valo return 0; 2558f79cbc77SKalle Valo } 2559f79cbc77SKalle Valo 2560f79cbc77SKalle Valo static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw, 2561f79cbc77SKalle Valo struct ieee80211_vif *vif, 2562f79cbc77SKalle Valo enum sta_notify_cmd cmd, 2563f79cbc77SKalle Valo struct ieee80211_sta *sta) 2564f79cbc77SKalle Valo { 2565f79cbc77SKalle Valo hwsim_check_magic(vif); 2566f79cbc77SKalle Valo 2567f79cbc77SKalle Valo switch (cmd) { 2568f79cbc77SKalle Valo case STA_NOTIFY_SLEEP: 2569f79cbc77SKalle Valo case STA_NOTIFY_AWAKE: 2570f79cbc77SKalle Valo /* TODO: make good use of these flags */ 2571f79cbc77SKalle Valo break; 2572f79cbc77SKalle Valo default: 2573f79cbc77SKalle Valo WARN(1, "Invalid sta notify: %d\n", cmd); 2574f79cbc77SKalle Valo break; 2575f79cbc77SKalle Valo } 2576f79cbc77SKalle Valo } 2577f79cbc77SKalle Valo 2578f79cbc77SKalle Valo static int mac80211_hwsim_set_tim(struct ieee80211_hw *hw, 2579f79cbc77SKalle Valo struct ieee80211_sta *sta, 2580f79cbc77SKalle Valo bool set) 2581f79cbc77SKalle Valo { 2582f79cbc77SKalle Valo hwsim_check_sta_magic(sta); 2583f79cbc77SKalle Valo return 0; 2584f79cbc77SKalle Valo } 2585f79cbc77SKalle Valo 2586f79cbc77SKalle Valo static int mac80211_hwsim_conf_tx(struct ieee80211_hw *hw, 2587f79cbc77SKalle Valo struct ieee80211_vif *vif, 2588f79cbc77SKalle Valo unsigned int link_id, u16 queue, 2589f79cbc77SKalle Valo const struct ieee80211_tx_queue_params *params) 2590f79cbc77SKalle Valo { 2591f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, 2592f79cbc77SKalle Valo "%s (queue=%d txop=%d cw_min=%d cw_max=%d aifs=%d)\n", 2593f79cbc77SKalle Valo __func__, queue, 2594f79cbc77SKalle Valo params->txop, params->cw_min, 2595f79cbc77SKalle Valo params->cw_max, params->aifs); 2596f79cbc77SKalle Valo return 0; 2597f79cbc77SKalle Valo } 2598f79cbc77SKalle Valo 2599f79cbc77SKalle Valo static int mac80211_hwsim_get_survey(struct ieee80211_hw *hw, int idx, 2600f79cbc77SKalle Valo struct survey_info *survey) 2601f79cbc77SKalle Valo { 2602f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = hw->priv; 2603f79cbc77SKalle Valo 2604f79cbc77SKalle Valo if (idx < 0 || idx >= ARRAY_SIZE(hwsim->survey_data)) 2605f79cbc77SKalle Valo return -ENOENT; 2606f79cbc77SKalle Valo 2607f79cbc77SKalle Valo mutex_lock(&hwsim->mutex); 2608f79cbc77SKalle Valo survey->channel = hwsim->survey_data[idx].channel; 2609f79cbc77SKalle Valo if (!survey->channel) { 2610f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2611f79cbc77SKalle Valo return -ENOENT; 2612f79cbc77SKalle Valo } 2613f79cbc77SKalle Valo 2614f79cbc77SKalle Valo /* 2615f79cbc77SKalle Valo * Magically conjured dummy values --- this is only ok for simulated hardware. 2616f79cbc77SKalle Valo * 2617f79cbc77SKalle Valo * A real driver which cannot determine real values noise MUST NOT 2618f79cbc77SKalle Valo * report any, especially not a magically conjured ones :-) 2619f79cbc77SKalle Valo */ 2620f79cbc77SKalle Valo survey->filled = SURVEY_INFO_NOISE_DBM | 2621f79cbc77SKalle Valo SURVEY_INFO_TIME | 2622f79cbc77SKalle Valo SURVEY_INFO_TIME_BUSY; 2623f79cbc77SKalle Valo survey->noise = -92; 2624f79cbc77SKalle Valo survey->time = 2625f79cbc77SKalle Valo jiffies_to_msecs(hwsim->survey_data[idx].end - 2626f79cbc77SKalle Valo hwsim->survey_data[idx].start); 2627f79cbc77SKalle Valo /* report 12.5% of channel time is used */ 2628f79cbc77SKalle Valo survey->time_busy = survey->time/8; 2629f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2630f79cbc77SKalle Valo 2631f79cbc77SKalle Valo return 0; 2632f79cbc77SKalle Valo } 2633f79cbc77SKalle Valo 2634f79cbc77SKalle Valo #ifdef CONFIG_NL80211_TESTMODE 2635f79cbc77SKalle Valo /* 2636f79cbc77SKalle Valo * This section contains example code for using netlink 2637f79cbc77SKalle Valo * attributes with the testmode command in nl80211. 2638f79cbc77SKalle Valo */ 2639f79cbc77SKalle Valo 2640f79cbc77SKalle Valo /* These enums need to be kept in sync with userspace */ 2641f79cbc77SKalle Valo enum hwsim_testmode_attr { 2642f79cbc77SKalle Valo __HWSIM_TM_ATTR_INVALID = 0, 2643f79cbc77SKalle Valo HWSIM_TM_ATTR_CMD = 1, 2644f79cbc77SKalle Valo HWSIM_TM_ATTR_PS = 2, 2645f79cbc77SKalle Valo 2646f79cbc77SKalle Valo /* keep last */ 2647f79cbc77SKalle Valo __HWSIM_TM_ATTR_AFTER_LAST, 2648f79cbc77SKalle Valo HWSIM_TM_ATTR_MAX = __HWSIM_TM_ATTR_AFTER_LAST - 1 2649f79cbc77SKalle Valo }; 2650f79cbc77SKalle Valo 2651f79cbc77SKalle Valo enum hwsim_testmode_cmd { 2652f79cbc77SKalle Valo HWSIM_TM_CMD_SET_PS = 0, 2653f79cbc77SKalle Valo HWSIM_TM_CMD_GET_PS = 1, 2654f79cbc77SKalle Valo HWSIM_TM_CMD_STOP_QUEUES = 2, 2655f79cbc77SKalle Valo HWSIM_TM_CMD_WAKE_QUEUES = 3, 2656f79cbc77SKalle Valo }; 2657f79cbc77SKalle Valo 2658f79cbc77SKalle Valo static const struct nla_policy hwsim_testmode_policy[HWSIM_TM_ATTR_MAX + 1] = { 2659f79cbc77SKalle Valo [HWSIM_TM_ATTR_CMD] = { .type = NLA_U32 }, 2660f79cbc77SKalle Valo [HWSIM_TM_ATTR_PS] = { .type = NLA_U32 }, 2661f79cbc77SKalle Valo }; 2662f79cbc77SKalle Valo 2663f79cbc77SKalle Valo static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw, 2664f79cbc77SKalle Valo struct ieee80211_vif *vif, 2665f79cbc77SKalle Valo void *data, int len) 2666f79cbc77SKalle Valo { 2667f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = hw->priv; 2668f79cbc77SKalle Valo struct nlattr *tb[HWSIM_TM_ATTR_MAX + 1]; 2669f79cbc77SKalle Valo struct sk_buff *skb; 2670f79cbc77SKalle Valo int err, ps; 2671f79cbc77SKalle Valo 2672f79cbc77SKalle Valo err = nla_parse_deprecated(tb, HWSIM_TM_ATTR_MAX, data, len, 2673f79cbc77SKalle Valo hwsim_testmode_policy, NULL); 2674f79cbc77SKalle Valo if (err) 2675f79cbc77SKalle Valo return err; 2676f79cbc77SKalle Valo 2677f79cbc77SKalle Valo if (!tb[HWSIM_TM_ATTR_CMD]) 2678f79cbc77SKalle Valo return -EINVAL; 2679f79cbc77SKalle Valo 2680f79cbc77SKalle Valo switch (nla_get_u32(tb[HWSIM_TM_ATTR_CMD])) { 2681f79cbc77SKalle Valo case HWSIM_TM_CMD_SET_PS: 2682f79cbc77SKalle Valo if (!tb[HWSIM_TM_ATTR_PS]) 2683f79cbc77SKalle Valo return -EINVAL; 2684f79cbc77SKalle Valo ps = nla_get_u32(tb[HWSIM_TM_ATTR_PS]); 2685f79cbc77SKalle Valo return hwsim_fops_ps_write(hwsim, ps); 2686f79cbc77SKalle Valo case HWSIM_TM_CMD_GET_PS: 2687f79cbc77SKalle Valo skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 2688f79cbc77SKalle Valo nla_total_size(sizeof(u32))); 2689f79cbc77SKalle Valo if (!skb) 2690f79cbc77SKalle Valo return -ENOMEM; 2691f79cbc77SKalle Valo if (nla_put_u32(skb, HWSIM_TM_ATTR_PS, hwsim->ps)) 2692f79cbc77SKalle Valo goto nla_put_failure; 2693f79cbc77SKalle Valo return cfg80211_testmode_reply(skb); 2694f79cbc77SKalle Valo case HWSIM_TM_CMD_STOP_QUEUES: 2695f79cbc77SKalle Valo ieee80211_stop_queues(hw); 2696f79cbc77SKalle Valo return 0; 2697f79cbc77SKalle Valo case HWSIM_TM_CMD_WAKE_QUEUES: 2698f79cbc77SKalle Valo ieee80211_wake_queues(hw); 2699f79cbc77SKalle Valo return 0; 2700f79cbc77SKalle Valo default: 2701f79cbc77SKalle Valo return -EOPNOTSUPP; 2702f79cbc77SKalle Valo } 2703f79cbc77SKalle Valo 2704f79cbc77SKalle Valo nla_put_failure: 2705f79cbc77SKalle Valo kfree_skb(skb); 2706f79cbc77SKalle Valo return -ENOBUFS; 2707f79cbc77SKalle Valo } 2708f79cbc77SKalle Valo #endif 2709f79cbc77SKalle Valo 2710f79cbc77SKalle Valo static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw, 2711f79cbc77SKalle Valo struct ieee80211_vif *vif, 2712f79cbc77SKalle Valo struct ieee80211_ampdu_params *params) 2713f79cbc77SKalle Valo { 2714f79cbc77SKalle Valo struct ieee80211_sta *sta = params->sta; 2715f79cbc77SKalle Valo enum ieee80211_ampdu_mlme_action action = params->action; 2716f79cbc77SKalle Valo u16 tid = params->tid; 2717f79cbc77SKalle Valo 2718f79cbc77SKalle Valo switch (action) { 2719f79cbc77SKalle Valo case IEEE80211_AMPDU_TX_START: 2720f79cbc77SKalle Valo return IEEE80211_AMPDU_TX_START_IMMEDIATE; 2721f79cbc77SKalle Valo case IEEE80211_AMPDU_TX_STOP_CONT: 2722f79cbc77SKalle Valo case IEEE80211_AMPDU_TX_STOP_FLUSH: 2723f79cbc77SKalle Valo case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: 2724f79cbc77SKalle Valo ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); 2725f79cbc77SKalle Valo break; 2726f79cbc77SKalle Valo case IEEE80211_AMPDU_TX_OPERATIONAL: 2727f79cbc77SKalle Valo break; 2728f79cbc77SKalle Valo case IEEE80211_AMPDU_RX_START: 2729f79cbc77SKalle Valo case IEEE80211_AMPDU_RX_STOP: 2730f79cbc77SKalle Valo break; 2731f79cbc77SKalle Valo default: 2732f79cbc77SKalle Valo return -EOPNOTSUPP; 2733f79cbc77SKalle Valo } 2734f79cbc77SKalle Valo 2735f79cbc77SKalle Valo return 0; 2736f79cbc77SKalle Valo } 2737f79cbc77SKalle Valo 2738f79cbc77SKalle Valo static void mac80211_hwsim_flush(struct ieee80211_hw *hw, 2739f79cbc77SKalle Valo struct ieee80211_vif *vif, 2740f79cbc77SKalle Valo u32 queues, bool drop) 2741f79cbc77SKalle Valo { 2742f79cbc77SKalle Valo /* Not implemented, queues only on kernel side */ 2743f79cbc77SKalle Valo } 2744f79cbc77SKalle Valo 2745f79cbc77SKalle Valo static void hw_scan_work(struct work_struct *work) 2746f79cbc77SKalle Valo { 2747f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = 2748f79cbc77SKalle Valo container_of(work, struct mac80211_hwsim_data, hw_scan.work); 2749f79cbc77SKalle Valo struct cfg80211_scan_request *req = hwsim->hw_scan_request; 2750f79cbc77SKalle Valo int dwell, i; 2751f79cbc77SKalle Valo 2752f79cbc77SKalle Valo mutex_lock(&hwsim->mutex); 2753f79cbc77SKalle Valo if (hwsim->scan_chan_idx >= req->n_channels) { 2754f79cbc77SKalle Valo struct cfg80211_scan_info info = { 2755f79cbc77SKalle Valo .aborted = false, 2756f79cbc77SKalle Valo }; 2757f79cbc77SKalle Valo 2758f79cbc77SKalle Valo wiphy_dbg(hwsim->hw->wiphy, "hw scan complete\n"); 2759f79cbc77SKalle Valo ieee80211_scan_completed(hwsim->hw, &info); 2760f79cbc77SKalle Valo hwsim->hw_scan_request = NULL; 2761f79cbc77SKalle Valo hwsim->hw_scan_vif = NULL; 2762f79cbc77SKalle Valo hwsim->tmp_chan = NULL; 2763f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2764f79cbc77SKalle Valo mac80211_hwsim_config_mac_nl(hwsim->hw, hwsim->scan_addr, 2765f79cbc77SKalle Valo false); 2766f79cbc77SKalle Valo return; 2767f79cbc77SKalle Valo } 2768f79cbc77SKalle Valo 2769f79cbc77SKalle Valo wiphy_dbg(hwsim->hw->wiphy, "hw scan %d MHz\n", 2770f79cbc77SKalle Valo req->channels[hwsim->scan_chan_idx]->center_freq); 2771f79cbc77SKalle Valo 2772f79cbc77SKalle Valo hwsim->tmp_chan = req->channels[hwsim->scan_chan_idx]; 2773f79cbc77SKalle Valo if (hwsim->tmp_chan->flags & (IEEE80211_CHAN_NO_IR | 2774f79cbc77SKalle Valo IEEE80211_CHAN_RADAR) || 2775f79cbc77SKalle Valo !req->n_ssids) { 2776f79cbc77SKalle Valo dwell = 120; 2777f79cbc77SKalle Valo } else { 2778f79cbc77SKalle Valo dwell = 30; 2779f79cbc77SKalle Valo /* send probes */ 2780f79cbc77SKalle Valo for (i = 0; i < req->n_ssids; i++) { 2781f79cbc77SKalle Valo struct sk_buff *probe; 2782f79cbc77SKalle Valo struct ieee80211_mgmt *mgmt; 2783f79cbc77SKalle Valo 2784f79cbc77SKalle Valo probe = ieee80211_probereq_get(hwsim->hw, 2785f79cbc77SKalle Valo hwsim->scan_addr, 2786f79cbc77SKalle Valo req->ssids[i].ssid, 2787f79cbc77SKalle Valo req->ssids[i].ssid_len, 2788f79cbc77SKalle Valo req->ie_len); 2789f79cbc77SKalle Valo if (!probe) 2790f79cbc77SKalle Valo continue; 2791f79cbc77SKalle Valo 2792f79cbc77SKalle Valo mgmt = (struct ieee80211_mgmt *) probe->data; 2793f79cbc77SKalle Valo memcpy(mgmt->da, req->bssid, ETH_ALEN); 2794f79cbc77SKalle Valo memcpy(mgmt->bssid, req->bssid, ETH_ALEN); 2795f79cbc77SKalle Valo 2796f79cbc77SKalle Valo if (req->ie_len) 2797f79cbc77SKalle Valo skb_put_data(probe, req->ie, req->ie_len); 2798f79cbc77SKalle Valo 2799f79cbc77SKalle Valo rcu_read_lock(); 2800f79cbc77SKalle Valo if (!ieee80211_tx_prepare_skb(hwsim->hw, 2801f79cbc77SKalle Valo hwsim->hw_scan_vif, 2802f79cbc77SKalle Valo probe, 2803f79cbc77SKalle Valo hwsim->tmp_chan->band, 2804f79cbc77SKalle Valo NULL)) { 2805f79cbc77SKalle Valo rcu_read_unlock(); 2806f79cbc77SKalle Valo kfree_skb(probe); 2807f79cbc77SKalle Valo continue; 2808f79cbc77SKalle Valo } 2809f79cbc77SKalle Valo 2810f79cbc77SKalle Valo local_bh_disable(); 2811f79cbc77SKalle Valo mac80211_hwsim_tx_frame(hwsim->hw, probe, 2812f79cbc77SKalle Valo hwsim->tmp_chan); 2813f79cbc77SKalle Valo rcu_read_unlock(); 2814f79cbc77SKalle Valo local_bh_enable(); 2815f79cbc77SKalle Valo } 2816f79cbc77SKalle Valo } 2817f79cbc77SKalle Valo ieee80211_queue_delayed_work(hwsim->hw, &hwsim->hw_scan, 2818f79cbc77SKalle Valo msecs_to_jiffies(dwell)); 2819f79cbc77SKalle Valo hwsim->survey_data[hwsim->scan_chan_idx].channel = hwsim->tmp_chan; 2820f79cbc77SKalle Valo hwsim->survey_data[hwsim->scan_chan_idx].start = jiffies; 2821f79cbc77SKalle Valo hwsim->survey_data[hwsim->scan_chan_idx].end = 2822f79cbc77SKalle Valo jiffies + msecs_to_jiffies(dwell); 2823f79cbc77SKalle Valo hwsim->scan_chan_idx++; 2824f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2825f79cbc77SKalle Valo } 2826f79cbc77SKalle Valo 2827f79cbc77SKalle Valo static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw, 2828f79cbc77SKalle Valo struct ieee80211_vif *vif, 2829f79cbc77SKalle Valo struct ieee80211_scan_request *hw_req) 2830f79cbc77SKalle Valo { 2831f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = hw->priv; 2832f79cbc77SKalle Valo struct cfg80211_scan_request *req = &hw_req->req; 2833f79cbc77SKalle Valo 2834f79cbc77SKalle Valo mutex_lock(&hwsim->mutex); 2835f79cbc77SKalle Valo if (WARN_ON(hwsim->tmp_chan || hwsim->hw_scan_request)) { 2836f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2837f79cbc77SKalle Valo return -EBUSY; 2838f79cbc77SKalle Valo } 2839f79cbc77SKalle Valo hwsim->hw_scan_request = req; 2840f79cbc77SKalle Valo hwsim->hw_scan_vif = vif; 2841f79cbc77SKalle Valo hwsim->scan_chan_idx = 0; 2842f79cbc77SKalle Valo if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) 2843f79cbc77SKalle Valo get_random_mask_addr(hwsim->scan_addr, 2844f79cbc77SKalle Valo hw_req->req.mac_addr, 2845f79cbc77SKalle Valo hw_req->req.mac_addr_mask); 2846f79cbc77SKalle Valo else 2847f79cbc77SKalle Valo memcpy(hwsim->scan_addr, vif->addr, ETH_ALEN); 2848f79cbc77SKalle Valo memset(hwsim->survey_data, 0, sizeof(hwsim->survey_data)); 2849f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2850f79cbc77SKalle Valo 2851f79cbc77SKalle Valo mac80211_hwsim_config_mac_nl(hw, hwsim->scan_addr, true); 2852f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "hwsim hw_scan request\n"); 2853f79cbc77SKalle Valo 2854f79cbc77SKalle Valo ieee80211_queue_delayed_work(hwsim->hw, &hwsim->hw_scan, 0); 2855f79cbc77SKalle Valo 2856f79cbc77SKalle Valo return 0; 2857f79cbc77SKalle Valo } 2858f79cbc77SKalle Valo 2859f79cbc77SKalle Valo static void mac80211_hwsim_cancel_hw_scan(struct ieee80211_hw *hw, 2860f79cbc77SKalle Valo struct ieee80211_vif *vif) 2861f79cbc77SKalle Valo { 2862f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = hw->priv; 2863f79cbc77SKalle Valo struct cfg80211_scan_info info = { 2864f79cbc77SKalle Valo .aborted = true, 2865f79cbc77SKalle Valo }; 2866f79cbc77SKalle Valo 2867f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "hwsim cancel_hw_scan\n"); 2868f79cbc77SKalle Valo 2869f79cbc77SKalle Valo cancel_delayed_work_sync(&hwsim->hw_scan); 2870f79cbc77SKalle Valo 2871f79cbc77SKalle Valo mutex_lock(&hwsim->mutex); 2872f79cbc77SKalle Valo ieee80211_scan_completed(hwsim->hw, &info); 2873f79cbc77SKalle Valo hwsim->tmp_chan = NULL; 2874f79cbc77SKalle Valo hwsim->hw_scan_request = NULL; 2875f79cbc77SKalle Valo hwsim->hw_scan_vif = NULL; 2876f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2877f79cbc77SKalle Valo } 2878f79cbc77SKalle Valo 2879f79cbc77SKalle Valo static void mac80211_hwsim_sw_scan(struct ieee80211_hw *hw, 2880f79cbc77SKalle Valo struct ieee80211_vif *vif, 2881f79cbc77SKalle Valo const u8 *mac_addr) 2882f79cbc77SKalle Valo { 2883f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = hw->priv; 2884f79cbc77SKalle Valo 2885f79cbc77SKalle Valo mutex_lock(&hwsim->mutex); 2886f79cbc77SKalle Valo 2887f79cbc77SKalle Valo if (hwsim->scanning) { 2888f79cbc77SKalle Valo pr_debug("two hwsim sw_scans detected!\n"); 2889f79cbc77SKalle Valo goto out; 2890f79cbc77SKalle Valo } 2891f79cbc77SKalle Valo 2892f79cbc77SKalle Valo pr_debug("hwsim sw_scan request, prepping stuff\n"); 2893f79cbc77SKalle Valo 2894f79cbc77SKalle Valo memcpy(hwsim->scan_addr, mac_addr, ETH_ALEN); 2895f79cbc77SKalle Valo mac80211_hwsim_config_mac_nl(hw, hwsim->scan_addr, true); 2896f79cbc77SKalle Valo hwsim->scanning = true; 2897f79cbc77SKalle Valo memset(hwsim->survey_data, 0, sizeof(hwsim->survey_data)); 2898f79cbc77SKalle Valo 2899f79cbc77SKalle Valo out: 2900f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2901f79cbc77SKalle Valo } 2902f79cbc77SKalle Valo 2903f79cbc77SKalle Valo static void mac80211_hwsim_sw_scan_complete(struct ieee80211_hw *hw, 2904f79cbc77SKalle Valo struct ieee80211_vif *vif) 2905f79cbc77SKalle Valo { 2906f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = hw->priv; 2907f79cbc77SKalle Valo 2908f79cbc77SKalle Valo mutex_lock(&hwsim->mutex); 2909f79cbc77SKalle Valo 2910f79cbc77SKalle Valo pr_debug("hwsim sw_scan_complete\n"); 2911f79cbc77SKalle Valo hwsim->scanning = false; 2912f79cbc77SKalle Valo mac80211_hwsim_config_mac_nl(hw, hwsim->scan_addr, false); 2913f79cbc77SKalle Valo eth_zero_addr(hwsim->scan_addr); 2914f79cbc77SKalle Valo 2915f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2916f79cbc77SKalle Valo } 2917f79cbc77SKalle Valo 2918f79cbc77SKalle Valo static void hw_roc_start(struct work_struct *work) 2919f79cbc77SKalle Valo { 2920f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = 2921f79cbc77SKalle Valo container_of(work, struct mac80211_hwsim_data, roc_start.work); 2922f79cbc77SKalle Valo 2923f79cbc77SKalle Valo mutex_lock(&hwsim->mutex); 2924f79cbc77SKalle Valo 2925f79cbc77SKalle Valo wiphy_dbg(hwsim->hw->wiphy, "hwsim ROC begins\n"); 2926f79cbc77SKalle Valo hwsim->tmp_chan = hwsim->roc_chan; 2927f79cbc77SKalle Valo ieee80211_ready_on_channel(hwsim->hw); 2928f79cbc77SKalle Valo 2929f79cbc77SKalle Valo ieee80211_queue_delayed_work(hwsim->hw, &hwsim->roc_done, 2930f79cbc77SKalle Valo msecs_to_jiffies(hwsim->roc_duration)); 2931f79cbc77SKalle Valo 2932f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2933f79cbc77SKalle Valo } 2934f79cbc77SKalle Valo 2935f79cbc77SKalle Valo static void hw_roc_done(struct work_struct *work) 2936f79cbc77SKalle Valo { 2937f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = 2938f79cbc77SKalle Valo container_of(work, struct mac80211_hwsim_data, roc_done.work); 2939f79cbc77SKalle Valo 2940f79cbc77SKalle Valo mutex_lock(&hwsim->mutex); 2941f79cbc77SKalle Valo ieee80211_remain_on_channel_expired(hwsim->hw); 2942f79cbc77SKalle Valo hwsim->tmp_chan = NULL; 2943f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2944f79cbc77SKalle Valo 2945f79cbc77SKalle Valo wiphy_dbg(hwsim->hw->wiphy, "hwsim ROC expired\n"); 2946f79cbc77SKalle Valo } 2947f79cbc77SKalle Valo 2948f79cbc77SKalle Valo static int mac80211_hwsim_roc(struct ieee80211_hw *hw, 2949f79cbc77SKalle Valo struct ieee80211_vif *vif, 2950f79cbc77SKalle Valo struct ieee80211_channel *chan, 2951f79cbc77SKalle Valo int duration, 2952f79cbc77SKalle Valo enum ieee80211_roc_type type) 2953f79cbc77SKalle Valo { 2954f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = hw->priv; 2955f79cbc77SKalle Valo 2956f79cbc77SKalle Valo mutex_lock(&hwsim->mutex); 2957f79cbc77SKalle Valo if (WARN_ON(hwsim->tmp_chan || hwsim->hw_scan_request)) { 2958f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2959f79cbc77SKalle Valo return -EBUSY; 2960f79cbc77SKalle Valo } 2961f79cbc77SKalle Valo 2962f79cbc77SKalle Valo hwsim->roc_chan = chan; 2963f79cbc77SKalle Valo hwsim->roc_duration = duration; 2964f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2965f79cbc77SKalle Valo 2966f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "hwsim ROC (%d MHz, %d ms)\n", 2967f79cbc77SKalle Valo chan->center_freq, duration); 2968f79cbc77SKalle Valo ieee80211_queue_delayed_work(hw, &hwsim->roc_start, HZ/50); 2969f79cbc77SKalle Valo 2970f79cbc77SKalle Valo return 0; 2971f79cbc77SKalle Valo } 2972f79cbc77SKalle Valo 2973f79cbc77SKalle Valo static int mac80211_hwsim_croc(struct ieee80211_hw *hw, 2974f79cbc77SKalle Valo struct ieee80211_vif *vif) 2975f79cbc77SKalle Valo { 2976f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = hw->priv; 2977f79cbc77SKalle Valo 2978f79cbc77SKalle Valo cancel_delayed_work_sync(&hwsim->roc_start); 2979f79cbc77SKalle Valo cancel_delayed_work_sync(&hwsim->roc_done); 2980f79cbc77SKalle Valo 2981f79cbc77SKalle Valo mutex_lock(&hwsim->mutex); 2982f79cbc77SKalle Valo hwsim->tmp_chan = NULL; 2983f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2984f79cbc77SKalle Valo 2985f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "hwsim ROC canceled\n"); 2986f79cbc77SKalle Valo 2987f79cbc77SKalle Valo return 0; 2988f79cbc77SKalle Valo } 2989f79cbc77SKalle Valo 2990f79cbc77SKalle Valo static int mac80211_hwsim_add_chanctx(struct ieee80211_hw *hw, 2991f79cbc77SKalle Valo struct ieee80211_chanctx_conf *ctx) 2992f79cbc77SKalle Valo { 2993f79cbc77SKalle Valo hwsim_set_chanctx_magic(ctx); 2994f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, 2995f79cbc77SKalle Valo "add channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n", 2996f79cbc77SKalle Valo ctx->def.chan->center_freq, ctx->def.width, 2997f79cbc77SKalle Valo ctx->def.center_freq1, ctx->def.center_freq2); 2998f79cbc77SKalle Valo return 0; 2999f79cbc77SKalle Valo } 3000f79cbc77SKalle Valo 3001f79cbc77SKalle Valo static void mac80211_hwsim_remove_chanctx(struct ieee80211_hw *hw, 3002f79cbc77SKalle Valo struct ieee80211_chanctx_conf *ctx) 3003f79cbc77SKalle Valo { 3004f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, 3005f79cbc77SKalle Valo "remove channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n", 3006f79cbc77SKalle Valo ctx->def.chan->center_freq, ctx->def.width, 3007f79cbc77SKalle Valo ctx->def.center_freq1, ctx->def.center_freq2); 3008f79cbc77SKalle Valo hwsim_check_chanctx_magic(ctx); 3009f79cbc77SKalle Valo hwsim_clear_chanctx_magic(ctx); 3010f79cbc77SKalle Valo } 3011f79cbc77SKalle Valo 3012f79cbc77SKalle Valo static void mac80211_hwsim_change_chanctx(struct ieee80211_hw *hw, 3013f79cbc77SKalle Valo struct ieee80211_chanctx_conf *ctx, 3014f79cbc77SKalle Valo u32 changed) 3015f79cbc77SKalle Valo { 3016f79cbc77SKalle Valo hwsim_check_chanctx_magic(ctx); 3017f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, 3018f79cbc77SKalle Valo "change channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n", 3019f79cbc77SKalle Valo ctx->def.chan->center_freq, ctx->def.width, 3020f79cbc77SKalle Valo ctx->def.center_freq1, ctx->def.center_freq2); 3021f79cbc77SKalle Valo } 3022f79cbc77SKalle Valo 3023f79cbc77SKalle Valo static int mac80211_hwsim_assign_vif_chanctx(struct ieee80211_hw *hw, 3024f79cbc77SKalle Valo struct ieee80211_vif *vif, 3025f79cbc77SKalle Valo struct ieee80211_bss_conf *link_conf, 3026f79cbc77SKalle Valo struct ieee80211_chanctx_conf *ctx) 3027f79cbc77SKalle Valo { 3028f79cbc77SKalle Valo hwsim_check_magic(vif); 3029f79cbc77SKalle Valo hwsim_check_chanctx_magic(ctx); 3030f79cbc77SKalle Valo 3031f79cbc77SKalle Valo /* if we activate a link while already associated wake it up */ 3032f79cbc77SKalle Valo if (vif->type == NL80211_IFTYPE_STATION && vif->cfg.assoc) { 3033f79cbc77SKalle Valo struct sk_buff *skb; 3034f79cbc77SKalle Valo 3035f79cbc77SKalle Valo skb = ieee80211_nullfunc_get(hw, vif, link_conf->link_id, true); 3036f79cbc77SKalle Valo if (skb) { 3037f79cbc77SKalle Valo local_bh_disable(); 3038f79cbc77SKalle Valo mac80211_hwsim_tx_frame(hw, skb, ctx->def.chan); 3039f79cbc77SKalle Valo local_bh_enable(); 3040f79cbc77SKalle Valo } 3041f79cbc77SKalle Valo } 3042f79cbc77SKalle Valo 3043f79cbc77SKalle Valo return 0; 3044f79cbc77SKalle Valo } 3045f79cbc77SKalle Valo 3046f79cbc77SKalle Valo static void mac80211_hwsim_unassign_vif_chanctx(struct ieee80211_hw *hw, 3047f79cbc77SKalle Valo struct ieee80211_vif *vif, 3048f79cbc77SKalle Valo struct ieee80211_bss_conf *link_conf, 3049f79cbc77SKalle Valo struct ieee80211_chanctx_conf *ctx) 3050f79cbc77SKalle Valo { 3051f79cbc77SKalle Valo hwsim_check_magic(vif); 3052f79cbc77SKalle Valo hwsim_check_chanctx_magic(ctx); 3053f79cbc77SKalle Valo 3054f79cbc77SKalle Valo /* if we deactivate a link while associated suspend it first */ 3055f79cbc77SKalle Valo if (vif->type == NL80211_IFTYPE_STATION && vif->cfg.assoc) { 3056f79cbc77SKalle Valo struct sk_buff *skb; 3057f79cbc77SKalle Valo 3058f79cbc77SKalle Valo skb = ieee80211_nullfunc_get(hw, vif, link_conf->link_id, true); 3059f79cbc77SKalle Valo if (skb) { 3060f79cbc77SKalle Valo struct ieee80211_hdr *hdr = (void *)skb->data; 3061f79cbc77SKalle Valo 3062f79cbc77SKalle Valo hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); 3063f79cbc77SKalle Valo 3064f79cbc77SKalle Valo local_bh_disable(); 3065f79cbc77SKalle Valo mac80211_hwsim_tx_frame(hw, skb, ctx->def.chan); 3066f79cbc77SKalle Valo local_bh_enable(); 3067f79cbc77SKalle Valo } 3068f79cbc77SKalle Valo } 3069f79cbc77SKalle Valo } 3070f79cbc77SKalle Valo 3071f79cbc77SKalle Valo static const char mac80211_hwsim_gstrings_stats[][ETH_GSTRING_LEN] = { 3072f79cbc77SKalle Valo "tx_pkts_nic", 3073f79cbc77SKalle Valo "tx_bytes_nic", 3074f79cbc77SKalle Valo "rx_pkts_nic", 3075f79cbc77SKalle Valo "rx_bytes_nic", 3076f79cbc77SKalle Valo "d_tx_dropped", 3077f79cbc77SKalle Valo "d_tx_failed", 3078f79cbc77SKalle Valo "d_ps_mode", 3079f79cbc77SKalle Valo "d_group", 3080f79cbc77SKalle Valo }; 3081f79cbc77SKalle Valo 3082f79cbc77SKalle Valo #define MAC80211_HWSIM_SSTATS_LEN ARRAY_SIZE(mac80211_hwsim_gstrings_stats) 3083f79cbc77SKalle Valo 3084f79cbc77SKalle Valo static void mac80211_hwsim_get_et_strings(struct ieee80211_hw *hw, 3085f79cbc77SKalle Valo struct ieee80211_vif *vif, 3086f79cbc77SKalle Valo u32 sset, u8 *data) 3087f79cbc77SKalle Valo { 3088f79cbc77SKalle Valo if (sset == ETH_SS_STATS) 3089f79cbc77SKalle Valo memcpy(data, *mac80211_hwsim_gstrings_stats, 3090f79cbc77SKalle Valo sizeof(mac80211_hwsim_gstrings_stats)); 3091f79cbc77SKalle Valo } 3092f79cbc77SKalle Valo 3093f79cbc77SKalle Valo static int mac80211_hwsim_get_et_sset_count(struct ieee80211_hw *hw, 3094f79cbc77SKalle Valo struct ieee80211_vif *vif, int sset) 3095f79cbc77SKalle Valo { 3096f79cbc77SKalle Valo if (sset == ETH_SS_STATS) 3097f79cbc77SKalle Valo return MAC80211_HWSIM_SSTATS_LEN; 3098f79cbc77SKalle Valo return 0; 3099f79cbc77SKalle Valo } 3100f79cbc77SKalle Valo 3101f79cbc77SKalle Valo static void mac80211_hwsim_get_et_stats(struct ieee80211_hw *hw, 3102f79cbc77SKalle Valo struct ieee80211_vif *vif, 3103f79cbc77SKalle Valo struct ethtool_stats *stats, u64 *data) 3104f79cbc77SKalle Valo { 3105f79cbc77SKalle Valo struct mac80211_hwsim_data *ar = hw->priv; 3106f79cbc77SKalle Valo int i = 0; 3107f79cbc77SKalle Valo 3108f79cbc77SKalle Valo data[i++] = ar->tx_pkts; 3109f79cbc77SKalle Valo data[i++] = ar->tx_bytes; 3110f79cbc77SKalle Valo data[i++] = ar->rx_pkts; 3111f79cbc77SKalle Valo data[i++] = ar->rx_bytes; 3112f79cbc77SKalle Valo data[i++] = ar->tx_dropped; 3113f79cbc77SKalle Valo data[i++] = ar->tx_failed; 3114f79cbc77SKalle Valo data[i++] = ar->ps; 3115f79cbc77SKalle Valo data[i++] = ar->group; 3116f79cbc77SKalle Valo 3117f79cbc77SKalle Valo WARN_ON(i != MAC80211_HWSIM_SSTATS_LEN); 3118f79cbc77SKalle Valo } 3119f79cbc77SKalle Valo 3120f79cbc77SKalle Valo static int mac80211_hwsim_tx_last_beacon(struct ieee80211_hw *hw) 3121f79cbc77SKalle Valo { 3122f79cbc77SKalle Valo return 1; 3123f79cbc77SKalle Valo } 3124f79cbc77SKalle Valo 3125f79cbc77SKalle Valo static int mac80211_hwsim_set_rts_threshold(struct ieee80211_hw *hw, u32 value) 3126f79cbc77SKalle Valo { 3127f79cbc77SKalle Valo return -EOPNOTSUPP; 3128f79cbc77SKalle Valo } 3129f79cbc77SKalle Valo 3130f79cbc77SKalle Valo static int mac80211_hwsim_change_vif_links(struct ieee80211_hw *hw, 3131f79cbc77SKalle Valo struct ieee80211_vif *vif, 3132f79cbc77SKalle Valo u16 old_links, u16 new_links, 3133f79cbc77SKalle Valo struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]) 3134f79cbc77SKalle Valo { 3135f79cbc77SKalle Valo unsigned long rem = old_links & ~new_links; 3136f79cbc77SKalle Valo unsigned long add = new_links & ~old_links; 3137f79cbc77SKalle Valo int i; 3138f79cbc77SKalle Valo 3139f79cbc77SKalle Valo if (!old_links) 3140f79cbc77SKalle Valo rem |= BIT(0); 3141f79cbc77SKalle Valo if (!new_links) 3142f79cbc77SKalle Valo add |= BIT(0); 3143f79cbc77SKalle Valo 3144f79cbc77SKalle Valo for_each_set_bit(i, &rem, IEEE80211_MLD_MAX_NUM_LINKS) 3145f79cbc77SKalle Valo mac80211_hwsim_config_mac_nl(hw, old[i]->addr, false); 3146f79cbc77SKalle Valo 3147f79cbc77SKalle Valo for_each_set_bit(i, &add, IEEE80211_MLD_MAX_NUM_LINKS) { 3148f79cbc77SKalle Valo struct ieee80211_bss_conf *link_conf; 3149f79cbc77SKalle Valo 3150f79cbc77SKalle Valo link_conf = link_conf_dereference_protected(vif, i); 3151f79cbc77SKalle Valo if (WARN_ON(!link_conf)) 3152f79cbc77SKalle Valo continue; 3153f79cbc77SKalle Valo 3154f79cbc77SKalle Valo mac80211_hwsim_config_mac_nl(hw, link_conf->addr, true); 3155f79cbc77SKalle Valo } 3156f79cbc77SKalle Valo 3157f79cbc77SKalle Valo return 0; 3158f79cbc77SKalle Valo } 3159f79cbc77SKalle Valo 3160f79cbc77SKalle Valo static int mac80211_hwsim_change_sta_links(struct ieee80211_hw *hw, 3161f79cbc77SKalle Valo struct ieee80211_vif *vif, 3162f79cbc77SKalle Valo struct ieee80211_sta *sta, 3163f79cbc77SKalle Valo u16 old_links, u16 new_links) 3164f79cbc77SKalle Valo { 3165f79cbc77SKalle Valo struct hwsim_sta_priv *sp = (void *)sta->drv_priv; 3166f79cbc77SKalle Valo 3167f79cbc77SKalle Valo hwsim_check_sta_magic(sta); 3168f79cbc77SKalle Valo 3169f79cbc77SKalle Valo if (vif->type == NL80211_IFTYPE_STATION) 3170f79cbc77SKalle Valo sp->active_links_rx = new_links; 3171f79cbc77SKalle Valo 3172f79cbc77SKalle Valo return 0; 3173f79cbc77SKalle Valo } 3174f79cbc77SKalle Valo 31755530c04cSJaewan Kim static int mac80211_hwsim_send_pmsr_ftm_request_peer(struct sk_buff *msg, 31765530c04cSJaewan Kim struct cfg80211_pmsr_ftm_request_peer *request) 31775530c04cSJaewan Kim { 31785530c04cSJaewan Kim struct nlattr *ftm; 31795530c04cSJaewan Kim 31805530c04cSJaewan Kim if (!request->requested) 31815530c04cSJaewan Kim return -EINVAL; 31825530c04cSJaewan Kim 31835530c04cSJaewan Kim ftm = nla_nest_start(msg, NL80211_PMSR_TYPE_FTM); 31845530c04cSJaewan Kim if (!ftm) 31855530c04cSJaewan Kim return -ENOBUFS; 31865530c04cSJaewan Kim 31875530c04cSJaewan Kim if (nla_put_u32(msg, NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE, request->preamble)) 31885530c04cSJaewan Kim return -ENOBUFS; 31895530c04cSJaewan Kim 31905530c04cSJaewan Kim if (nla_put_u16(msg, NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD, request->burst_period)) 31915530c04cSJaewan Kim return -ENOBUFS; 31925530c04cSJaewan Kim 31935530c04cSJaewan Kim if (request->asap && nla_put_flag(msg, NL80211_PMSR_FTM_REQ_ATTR_ASAP)) 31945530c04cSJaewan Kim return -ENOBUFS; 31955530c04cSJaewan Kim 31965530c04cSJaewan Kim if (request->request_lci && nla_put_flag(msg, NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI)) 31975530c04cSJaewan Kim return -ENOBUFS; 31985530c04cSJaewan Kim 31995530c04cSJaewan Kim if (request->request_civicloc && 32005530c04cSJaewan Kim nla_put_flag(msg, NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC)) 32015530c04cSJaewan Kim return -ENOBUFS; 32025530c04cSJaewan Kim 32035530c04cSJaewan Kim if (request->trigger_based && nla_put_flag(msg, NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED)) 32045530c04cSJaewan Kim return -ENOBUFS; 32055530c04cSJaewan Kim 32065530c04cSJaewan Kim if (request->non_trigger_based && 32075530c04cSJaewan Kim nla_put_flag(msg, NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED)) 32085530c04cSJaewan Kim return -ENOBUFS; 32095530c04cSJaewan Kim 32105530c04cSJaewan Kim if (request->lmr_feedback && nla_put_flag(msg, NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK)) 32115530c04cSJaewan Kim return -ENOBUFS; 32125530c04cSJaewan Kim 32135530c04cSJaewan Kim if (nla_put_u8(msg, NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP, request->num_bursts_exp)) 32145530c04cSJaewan Kim return -ENOBUFS; 32155530c04cSJaewan Kim 32165530c04cSJaewan Kim if (nla_put_u8(msg, NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION, request->burst_duration)) 32175530c04cSJaewan Kim return -ENOBUFS; 32185530c04cSJaewan Kim 32195530c04cSJaewan Kim if (nla_put_u8(msg, NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST, request->ftms_per_burst)) 32205530c04cSJaewan Kim return -ENOBUFS; 32215530c04cSJaewan Kim 32225530c04cSJaewan Kim if (nla_put_u8(msg, NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES, request->ftmr_retries)) 32235530c04cSJaewan Kim return -ENOBUFS; 32245530c04cSJaewan Kim 32255530c04cSJaewan Kim if (nla_put_u8(msg, NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION, request->burst_duration)) 32265530c04cSJaewan Kim return -ENOBUFS; 32275530c04cSJaewan Kim 32285530c04cSJaewan Kim if (nla_put_u8(msg, NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR, request->bss_color)) 32295530c04cSJaewan Kim return -ENOBUFS; 32305530c04cSJaewan Kim 32315530c04cSJaewan Kim nla_nest_end(msg, ftm); 32325530c04cSJaewan Kim 32335530c04cSJaewan Kim return 0; 32345530c04cSJaewan Kim } 32355530c04cSJaewan Kim 32365530c04cSJaewan Kim static int mac80211_hwsim_send_pmsr_request_peer(struct sk_buff *msg, 32375530c04cSJaewan Kim struct cfg80211_pmsr_request_peer *request) 32385530c04cSJaewan Kim { 32395530c04cSJaewan Kim struct nlattr *peer, *chandef, *req, *data; 32405530c04cSJaewan Kim int err; 32415530c04cSJaewan Kim 32425530c04cSJaewan Kim peer = nla_nest_start(msg, NL80211_PMSR_ATTR_PEERS); 32435530c04cSJaewan Kim if (!peer) 32445530c04cSJaewan Kim return -ENOBUFS; 32455530c04cSJaewan Kim 32465530c04cSJaewan Kim if (nla_put(msg, NL80211_PMSR_PEER_ATTR_ADDR, ETH_ALEN, 32475530c04cSJaewan Kim request->addr)) 32485530c04cSJaewan Kim return -ENOBUFS; 32495530c04cSJaewan Kim 32505530c04cSJaewan Kim chandef = nla_nest_start(msg, NL80211_PMSR_PEER_ATTR_CHAN); 32515530c04cSJaewan Kim if (!chandef) 32525530c04cSJaewan Kim return -ENOBUFS; 32535530c04cSJaewan Kim 32545530c04cSJaewan Kim err = nl80211_send_chandef(msg, &request->chandef); 32555530c04cSJaewan Kim if (err) 32565530c04cSJaewan Kim return err; 32575530c04cSJaewan Kim 32585530c04cSJaewan Kim nla_nest_end(msg, chandef); 32595530c04cSJaewan Kim 32605530c04cSJaewan Kim req = nla_nest_start(msg, NL80211_PMSR_PEER_ATTR_REQ); 32615530c04cSJaewan Kim if (!req) 32625530c04cSJaewan Kim return -ENOBUFS; 32635530c04cSJaewan Kim 32645530c04cSJaewan Kim if (request->report_ap_tsf && nla_put_flag(msg, NL80211_PMSR_REQ_ATTR_GET_AP_TSF)) 32655530c04cSJaewan Kim return -ENOBUFS; 32665530c04cSJaewan Kim 32675530c04cSJaewan Kim data = nla_nest_start(msg, NL80211_PMSR_REQ_ATTR_DATA); 32685530c04cSJaewan Kim if (!data) 32695530c04cSJaewan Kim return -ENOBUFS; 32705530c04cSJaewan Kim 32715530c04cSJaewan Kim err = mac80211_hwsim_send_pmsr_ftm_request_peer(msg, &request->ftm); 32725530c04cSJaewan Kim if (err) 32735530c04cSJaewan Kim return err; 32745530c04cSJaewan Kim 32755530c04cSJaewan Kim nla_nest_end(msg, data); 32765530c04cSJaewan Kim nla_nest_end(msg, req); 32775530c04cSJaewan Kim nla_nest_end(msg, peer); 32785530c04cSJaewan Kim 32795530c04cSJaewan Kim return 0; 32805530c04cSJaewan Kim } 32815530c04cSJaewan Kim 32825530c04cSJaewan Kim static int mac80211_hwsim_send_pmsr_request(struct sk_buff *msg, 32835530c04cSJaewan Kim struct cfg80211_pmsr_request *request) 32845530c04cSJaewan Kim { 32855530c04cSJaewan Kim struct nlattr *pmsr; 32865530c04cSJaewan Kim int err; 32875530c04cSJaewan Kim 32885530c04cSJaewan Kim pmsr = nla_nest_start(msg, NL80211_ATTR_PEER_MEASUREMENTS); 32895530c04cSJaewan Kim if (!pmsr) 32905530c04cSJaewan Kim return -ENOBUFS; 32915530c04cSJaewan Kim 32925530c04cSJaewan Kim if (nla_put_u32(msg, NL80211_ATTR_TIMEOUT, request->timeout)) 32935530c04cSJaewan Kim return -ENOBUFS; 32945530c04cSJaewan Kim 32955530c04cSJaewan Kim if (!is_zero_ether_addr(request->mac_addr)) { 32965530c04cSJaewan Kim if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, request->mac_addr)) 32975530c04cSJaewan Kim return -ENOBUFS; 32985530c04cSJaewan Kim if (nla_put(msg, NL80211_ATTR_MAC_MASK, ETH_ALEN, request->mac_addr_mask)) 32995530c04cSJaewan Kim return -ENOBUFS; 33005530c04cSJaewan Kim } 33015530c04cSJaewan Kim 33025530c04cSJaewan Kim for (int i = 0; i < request->n_peers; i++) { 33035530c04cSJaewan Kim err = mac80211_hwsim_send_pmsr_request_peer(msg, &request->peers[i]); 33045530c04cSJaewan Kim if (err) 33055530c04cSJaewan Kim return err; 33065530c04cSJaewan Kim } 33075530c04cSJaewan Kim 33085530c04cSJaewan Kim nla_nest_end(msg, pmsr); 33095530c04cSJaewan Kim 33105530c04cSJaewan Kim return 0; 33115530c04cSJaewan Kim } 33125530c04cSJaewan Kim 33135530c04cSJaewan Kim static int mac80211_hwsim_start_pmsr(struct ieee80211_hw *hw, 33145530c04cSJaewan Kim struct ieee80211_vif *vif, 33155530c04cSJaewan Kim struct cfg80211_pmsr_request *request) 33165530c04cSJaewan Kim { 33175530c04cSJaewan Kim struct mac80211_hwsim_data *data; 33185530c04cSJaewan Kim struct sk_buff *skb = NULL; 33195530c04cSJaewan Kim struct nlattr *pmsr; 33205530c04cSJaewan Kim void *msg_head; 33215530c04cSJaewan Kim u32 _portid; 33225530c04cSJaewan Kim int err = 0; 33235530c04cSJaewan Kim 33245530c04cSJaewan Kim data = hw->priv; 33255530c04cSJaewan Kim _portid = READ_ONCE(data->wmediumd); 33265530c04cSJaewan Kim if (!_portid && !hwsim_virtio_enabled) 33275530c04cSJaewan Kim return -EOPNOTSUPP; 33285530c04cSJaewan Kim 33295530c04cSJaewan Kim mutex_lock(&data->mutex); 33305530c04cSJaewan Kim 33315530c04cSJaewan Kim if (data->pmsr_request) { 33325530c04cSJaewan Kim err = -EBUSY; 33335530c04cSJaewan Kim goto out_free; 33345530c04cSJaewan Kim } 33355530c04cSJaewan Kim 33365530c04cSJaewan Kim skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 33375530c04cSJaewan Kim 33385530c04cSJaewan Kim if (!skb) { 33395530c04cSJaewan Kim err = -ENOMEM; 33405530c04cSJaewan Kim goto out_free; 33415530c04cSJaewan Kim } 33425530c04cSJaewan Kim 33435530c04cSJaewan Kim msg_head = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, HWSIM_CMD_START_PMSR); 33445530c04cSJaewan Kim 33455530c04cSJaewan Kim if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER, 33465530c04cSJaewan Kim ETH_ALEN, data->addresses[1].addr)) { 33475530c04cSJaewan Kim err = -ENOMEM; 33485530c04cSJaewan Kim goto out_free; 33495530c04cSJaewan Kim } 33505530c04cSJaewan Kim 33515530c04cSJaewan Kim pmsr = nla_nest_start(skb, HWSIM_ATTR_PMSR_REQUEST); 33525530c04cSJaewan Kim if (!pmsr) { 33535530c04cSJaewan Kim err = -ENOMEM; 33545530c04cSJaewan Kim goto out_free; 33555530c04cSJaewan Kim } 33565530c04cSJaewan Kim 33575530c04cSJaewan Kim err = mac80211_hwsim_send_pmsr_request(skb, request); 33585530c04cSJaewan Kim if (err) 33595530c04cSJaewan Kim goto out_free; 33605530c04cSJaewan Kim 33615530c04cSJaewan Kim nla_nest_end(skb, pmsr); 33625530c04cSJaewan Kim 33635530c04cSJaewan Kim genlmsg_end(skb, msg_head); 33645530c04cSJaewan Kim if (hwsim_virtio_enabled) 33655530c04cSJaewan Kim hwsim_tx_virtio(data, skb); 33665530c04cSJaewan Kim else 33675530c04cSJaewan Kim hwsim_unicast_netgroup(data, skb, _portid); 33685530c04cSJaewan Kim 33695530c04cSJaewan Kim data->pmsr_request = request; 33705530c04cSJaewan Kim data->pmsr_request_wdev = ieee80211_vif_to_wdev(vif); 33715530c04cSJaewan Kim 33725530c04cSJaewan Kim out_free: 33735530c04cSJaewan Kim if (err && skb) 33745530c04cSJaewan Kim nlmsg_free(skb); 33755530c04cSJaewan Kim 33765530c04cSJaewan Kim mutex_unlock(&data->mutex); 33775530c04cSJaewan Kim return err; 33785530c04cSJaewan Kim } 33795530c04cSJaewan Kim 3380*8ba1da95SJaewan Kim static void mac80211_hwsim_abort_pmsr(struct ieee80211_hw *hw, 3381*8ba1da95SJaewan Kim struct ieee80211_vif *vif, 3382*8ba1da95SJaewan Kim struct cfg80211_pmsr_request *request) 3383*8ba1da95SJaewan Kim { 3384*8ba1da95SJaewan Kim struct mac80211_hwsim_data *data; 3385*8ba1da95SJaewan Kim struct sk_buff *skb = NULL; 3386*8ba1da95SJaewan Kim struct nlattr *pmsr; 3387*8ba1da95SJaewan Kim void *msg_head; 3388*8ba1da95SJaewan Kim u32 _portid; 3389*8ba1da95SJaewan Kim int err = 0; 3390*8ba1da95SJaewan Kim 3391*8ba1da95SJaewan Kim data = hw->priv; 3392*8ba1da95SJaewan Kim _portid = READ_ONCE(data->wmediumd); 3393*8ba1da95SJaewan Kim if (!_portid && !hwsim_virtio_enabled) 3394*8ba1da95SJaewan Kim return; 3395*8ba1da95SJaewan Kim 3396*8ba1da95SJaewan Kim mutex_lock(&data->mutex); 3397*8ba1da95SJaewan Kim 3398*8ba1da95SJaewan Kim if (data->pmsr_request != request) { 3399*8ba1da95SJaewan Kim err = -EINVAL; 3400*8ba1da95SJaewan Kim goto out; 3401*8ba1da95SJaewan Kim } 3402*8ba1da95SJaewan Kim 3403*8ba1da95SJaewan Kim skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 3404*8ba1da95SJaewan Kim if (!skb) { 3405*8ba1da95SJaewan Kim err = -ENOMEM; 3406*8ba1da95SJaewan Kim goto out; 3407*8ba1da95SJaewan Kim } 3408*8ba1da95SJaewan Kim 3409*8ba1da95SJaewan Kim msg_head = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, HWSIM_CMD_ABORT_PMSR); 3410*8ba1da95SJaewan Kim 3411*8ba1da95SJaewan Kim if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER, ETH_ALEN, data->addresses[1].addr)) 3412*8ba1da95SJaewan Kim goto out; 3413*8ba1da95SJaewan Kim 3414*8ba1da95SJaewan Kim pmsr = nla_nest_start(skb, HWSIM_ATTR_PMSR_REQUEST); 3415*8ba1da95SJaewan Kim if (!pmsr) { 3416*8ba1da95SJaewan Kim err = -ENOMEM; 3417*8ba1da95SJaewan Kim goto out; 3418*8ba1da95SJaewan Kim } 3419*8ba1da95SJaewan Kim 3420*8ba1da95SJaewan Kim err = mac80211_hwsim_send_pmsr_request(skb, request); 3421*8ba1da95SJaewan Kim if (err) 3422*8ba1da95SJaewan Kim goto out; 3423*8ba1da95SJaewan Kim 3424*8ba1da95SJaewan Kim err = nla_nest_end(skb, pmsr); 3425*8ba1da95SJaewan Kim if (err) 3426*8ba1da95SJaewan Kim goto out; 3427*8ba1da95SJaewan Kim 3428*8ba1da95SJaewan Kim genlmsg_end(skb, msg_head); 3429*8ba1da95SJaewan Kim if (hwsim_virtio_enabled) 3430*8ba1da95SJaewan Kim hwsim_tx_virtio(data, skb); 3431*8ba1da95SJaewan Kim else 3432*8ba1da95SJaewan Kim hwsim_unicast_netgroup(data, skb, _portid); 3433*8ba1da95SJaewan Kim 3434*8ba1da95SJaewan Kim out: 3435*8ba1da95SJaewan Kim if (err && skb) 3436*8ba1da95SJaewan Kim nlmsg_free(skb); 3437*8ba1da95SJaewan Kim 3438*8ba1da95SJaewan Kim mutex_unlock(&data->mutex); 3439*8ba1da95SJaewan Kim } 3440*8ba1da95SJaewan Kim 3441f79cbc77SKalle Valo #define HWSIM_COMMON_OPS \ 3442f79cbc77SKalle Valo .tx = mac80211_hwsim_tx, \ 3443f79cbc77SKalle Valo .wake_tx_queue = ieee80211_handle_wake_tx_queue, \ 3444f79cbc77SKalle Valo .start = mac80211_hwsim_start, \ 3445f79cbc77SKalle Valo .stop = mac80211_hwsim_stop, \ 3446f79cbc77SKalle Valo .add_interface = mac80211_hwsim_add_interface, \ 3447f79cbc77SKalle Valo .change_interface = mac80211_hwsim_change_interface, \ 3448f79cbc77SKalle Valo .remove_interface = mac80211_hwsim_remove_interface, \ 3449f79cbc77SKalle Valo .config = mac80211_hwsim_config, \ 3450f79cbc77SKalle Valo .configure_filter = mac80211_hwsim_configure_filter, \ 3451f79cbc77SKalle Valo .vif_cfg_changed = mac80211_hwsim_vif_info_changed, \ 3452f79cbc77SKalle Valo .link_info_changed = mac80211_hwsim_link_info_changed, \ 3453f79cbc77SKalle Valo .tx_last_beacon = mac80211_hwsim_tx_last_beacon, \ 3454f79cbc77SKalle Valo .sta_notify = mac80211_hwsim_sta_notify, \ 3455f79cbc77SKalle Valo .sta_rc_update = mac80211_hwsim_sta_rc_update, \ 3456f79cbc77SKalle Valo .conf_tx = mac80211_hwsim_conf_tx, \ 3457f79cbc77SKalle Valo .get_survey = mac80211_hwsim_get_survey, \ 3458f79cbc77SKalle Valo CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd) \ 3459f79cbc77SKalle Valo .ampdu_action = mac80211_hwsim_ampdu_action, \ 3460f79cbc77SKalle Valo .flush = mac80211_hwsim_flush, \ 3461f79cbc77SKalle Valo .get_et_sset_count = mac80211_hwsim_get_et_sset_count, \ 3462f79cbc77SKalle Valo .get_et_stats = mac80211_hwsim_get_et_stats, \ 34635530c04cSJaewan Kim .get_et_strings = mac80211_hwsim_get_et_strings, \ 34645530c04cSJaewan Kim .start_pmsr = mac80211_hwsim_start_pmsr, \ 3465*8ba1da95SJaewan Kim .abort_pmsr = mac80211_hwsim_abort_pmsr, 3466f79cbc77SKalle Valo 3467f79cbc77SKalle Valo #define HWSIM_NON_MLO_OPS \ 3468f79cbc77SKalle Valo .sta_add = mac80211_hwsim_sta_add, \ 3469f79cbc77SKalle Valo .sta_remove = mac80211_hwsim_sta_remove, \ 3470f79cbc77SKalle Valo .set_tim = mac80211_hwsim_set_tim, \ 3471f79cbc77SKalle Valo .get_tsf = mac80211_hwsim_get_tsf, \ 3472f79cbc77SKalle Valo .set_tsf = mac80211_hwsim_set_tsf, 3473f79cbc77SKalle Valo 3474f79cbc77SKalle Valo static const struct ieee80211_ops mac80211_hwsim_ops = { 3475f79cbc77SKalle Valo HWSIM_COMMON_OPS 3476f79cbc77SKalle Valo HWSIM_NON_MLO_OPS 3477f79cbc77SKalle Valo .sw_scan_start = mac80211_hwsim_sw_scan, 3478f79cbc77SKalle Valo .sw_scan_complete = mac80211_hwsim_sw_scan_complete, 3479f79cbc77SKalle Valo }; 3480f79cbc77SKalle Valo 3481f79cbc77SKalle Valo #define HWSIM_CHANCTX_OPS \ 3482f79cbc77SKalle Valo .hw_scan = mac80211_hwsim_hw_scan, \ 3483f79cbc77SKalle Valo .cancel_hw_scan = mac80211_hwsim_cancel_hw_scan, \ 3484f79cbc77SKalle Valo .remain_on_channel = mac80211_hwsim_roc, \ 3485f79cbc77SKalle Valo .cancel_remain_on_channel = mac80211_hwsim_croc, \ 3486f79cbc77SKalle Valo .add_chanctx = mac80211_hwsim_add_chanctx, \ 3487f79cbc77SKalle Valo .remove_chanctx = mac80211_hwsim_remove_chanctx, \ 3488f79cbc77SKalle Valo .change_chanctx = mac80211_hwsim_change_chanctx, \ 3489f79cbc77SKalle Valo .assign_vif_chanctx = mac80211_hwsim_assign_vif_chanctx,\ 3490f79cbc77SKalle Valo .unassign_vif_chanctx = mac80211_hwsim_unassign_vif_chanctx, 3491f79cbc77SKalle Valo 3492f79cbc77SKalle Valo static const struct ieee80211_ops mac80211_hwsim_mchan_ops = { 3493f79cbc77SKalle Valo HWSIM_COMMON_OPS 3494f79cbc77SKalle Valo HWSIM_NON_MLO_OPS 3495f79cbc77SKalle Valo HWSIM_CHANCTX_OPS 3496f79cbc77SKalle Valo }; 3497f79cbc77SKalle Valo 3498f79cbc77SKalle Valo static const struct ieee80211_ops mac80211_hwsim_mlo_ops = { 3499f79cbc77SKalle Valo HWSIM_COMMON_OPS 3500f79cbc77SKalle Valo HWSIM_CHANCTX_OPS 3501f79cbc77SKalle Valo .set_rts_threshold = mac80211_hwsim_set_rts_threshold, 3502f79cbc77SKalle Valo .change_vif_links = mac80211_hwsim_change_vif_links, 3503f79cbc77SKalle Valo .change_sta_links = mac80211_hwsim_change_sta_links, 3504f79cbc77SKalle Valo .sta_state = mac80211_hwsim_sta_state, 3505f79cbc77SKalle Valo }; 3506f79cbc77SKalle Valo 3507f79cbc77SKalle Valo struct hwsim_new_radio_params { 3508f79cbc77SKalle Valo unsigned int channels; 3509f79cbc77SKalle Valo const char *reg_alpha2; 3510f79cbc77SKalle Valo const struct ieee80211_regdomain *regd; 3511f79cbc77SKalle Valo bool reg_strict; 3512f79cbc77SKalle Valo bool p2p_device; 3513f79cbc77SKalle Valo bool use_chanctx; 3514f79cbc77SKalle Valo bool destroy_on_close; 3515f79cbc77SKalle Valo const char *hwname; 3516f79cbc77SKalle Valo bool no_vif; 3517f79cbc77SKalle Valo const u8 *perm_addr; 3518f79cbc77SKalle Valo u32 iftypes; 3519f79cbc77SKalle Valo u32 *ciphers; 3520f79cbc77SKalle Valo u8 n_ciphers; 3521f79cbc77SKalle Valo bool mlo; 352292d13386SJaewan Kim const struct cfg80211_pmsr_capabilities *pmsr_capa; 3523f79cbc77SKalle Valo }; 3524f79cbc77SKalle Valo 3525f79cbc77SKalle Valo static void hwsim_mcast_config_msg(struct sk_buff *mcast_skb, 3526f79cbc77SKalle Valo struct genl_info *info) 3527f79cbc77SKalle Valo { 3528f79cbc77SKalle Valo if (info) 3529f79cbc77SKalle Valo genl_notify(&hwsim_genl_family, mcast_skb, info, 3530f79cbc77SKalle Valo HWSIM_MCGRP_CONFIG, GFP_KERNEL); 3531f79cbc77SKalle Valo else 3532f79cbc77SKalle Valo genlmsg_multicast(&hwsim_genl_family, mcast_skb, 0, 3533f79cbc77SKalle Valo HWSIM_MCGRP_CONFIG, GFP_KERNEL); 3534f79cbc77SKalle Valo } 3535f79cbc77SKalle Valo 3536f79cbc77SKalle Valo static int append_radio_msg(struct sk_buff *skb, int id, 3537f79cbc77SKalle Valo struct hwsim_new_radio_params *param) 3538f79cbc77SKalle Valo { 3539f79cbc77SKalle Valo int ret; 3540f79cbc77SKalle Valo 3541f79cbc77SKalle Valo ret = nla_put_u32(skb, HWSIM_ATTR_RADIO_ID, id); 3542f79cbc77SKalle Valo if (ret < 0) 3543f79cbc77SKalle Valo return ret; 3544f79cbc77SKalle Valo 3545f79cbc77SKalle Valo if (param->channels) { 3546f79cbc77SKalle Valo ret = nla_put_u32(skb, HWSIM_ATTR_CHANNELS, param->channels); 3547f79cbc77SKalle Valo if (ret < 0) 3548f79cbc77SKalle Valo return ret; 3549f79cbc77SKalle Valo } 3550f79cbc77SKalle Valo 3551f79cbc77SKalle Valo if (param->reg_alpha2) { 3552f79cbc77SKalle Valo ret = nla_put(skb, HWSIM_ATTR_REG_HINT_ALPHA2, 2, 3553f79cbc77SKalle Valo param->reg_alpha2); 3554f79cbc77SKalle Valo if (ret < 0) 3555f79cbc77SKalle Valo return ret; 3556f79cbc77SKalle Valo } 3557f79cbc77SKalle Valo 3558f79cbc77SKalle Valo if (param->regd) { 3559f79cbc77SKalle Valo int i; 3560f79cbc77SKalle Valo 3561f79cbc77SKalle Valo for (i = 0; i < ARRAY_SIZE(hwsim_world_regdom_custom); i++) { 3562f79cbc77SKalle Valo if (hwsim_world_regdom_custom[i] != param->regd) 3563f79cbc77SKalle Valo continue; 3564f79cbc77SKalle Valo 3565f79cbc77SKalle Valo ret = nla_put_u32(skb, HWSIM_ATTR_REG_CUSTOM_REG, i); 3566f79cbc77SKalle Valo if (ret < 0) 3567f79cbc77SKalle Valo return ret; 3568f79cbc77SKalle Valo break; 3569f79cbc77SKalle Valo } 3570f79cbc77SKalle Valo } 3571f79cbc77SKalle Valo 3572f79cbc77SKalle Valo if (param->reg_strict) { 3573f79cbc77SKalle Valo ret = nla_put_flag(skb, HWSIM_ATTR_REG_STRICT_REG); 3574f79cbc77SKalle Valo if (ret < 0) 3575f79cbc77SKalle Valo return ret; 3576f79cbc77SKalle Valo } 3577f79cbc77SKalle Valo 3578f79cbc77SKalle Valo if (param->p2p_device) { 3579f79cbc77SKalle Valo ret = nla_put_flag(skb, HWSIM_ATTR_SUPPORT_P2P_DEVICE); 3580f79cbc77SKalle Valo if (ret < 0) 3581f79cbc77SKalle Valo return ret; 3582f79cbc77SKalle Valo } 3583f79cbc77SKalle Valo 3584f79cbc77SKalle Valo if (param->use_chanctx) { 3585f79cbc77SKalle Valo ret = nla_put_flag(skb, HWSIM_ATTR_USE_CHANCTX); 3586f79cbc77SKalle Valo if (ret < 0) 3587f79cbc77SKalle Valo return ret; 3588f79cbc77SKalle Valo } 3589f79cbc77SKalle Valo 3590f79cbc77SKalle Valo if (param->hwname) { 3591f79cbc77SKalle Valo ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME, 3592f79cbc77SKalle Valo strlen(param->hwname), param->hwname); 3593f79cbc77SKalle Valo if (ret < 0) 3594f79cbc77SKalle Valo return ret; 3595f79cbc77SKalle Valo } 3596f79cbc77SKalle Valo 3597f79cbc77SKalle Valo return 0; 3598f79cbc77SKalle Valo } 3599f79cbc77SKalle Valo 3600f79cbc77SKalle Valo static void hwsim_mcast_new_radio(int id, struct genl_info *info, 3601f79cbc77SKalle Valo struct hwsim_new_radio_params *param) 3602f79cbc77SKalle Valo { 3603f79cbc77SKalle Valo struct sk_buff *mcast_skb; 3604f79cbc77SKalle Valo void *data; 3605f79cbc77SKalle Valo 3606f79cbc77SKalle Valo mcast_skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 3607f79cbc77SKalle Valo if (!mcast_skb) 3608f79cbc77SKalle Valo return; 3609f79cbc77SKalle Valo 3610f79cbc77SKalle Valo data = genlmsg_put(mcast_skb, 0, 0, &hwsim_genl_family, 0, 3611f79cbc77SKalle Valo HWSIM_CMD_NEW_RADIO); 3612f79cbc77SKalle Valo if (!data) 3613f79cbc77SKalle Valo goto out_err; 3614f79cbc77SKalle Valo 3615f79cbc77SKalle Valo if (append_radio_msg(mcast_skb, id, param) < 0) 3616f79cbc77SKalle Valo goto out_err; 3617f79cbc77SKalle Valo 3618f79cbc77SKalle Valo genlmsg_end(mcast_skb, data); 3619f79cbc77SKalle Valo 3620f79cbc77SKalle Valo hwsim_mcast_config_msg(mcast_skb, info); 3621f79cbc77SKalle Valo return; 3622f79cbc77SKalle Valo 3623f79cbc77SKalle Valo out_err: 3624f79cbc77SKalle Valo nlmsg_free(mcast_skb); 3625f79cbc77SKalle Valo } 3626f79cbc77SKalle Valo 3627f79cbc77SKalle Valo static const struct ieee80211_sband_iftype_data sband_capa_2ghz[] = { 3628f79cbc77SKalle Valo { 3629f79cbc77SKalle Valo .types_mask = BIT(NL80211_IFTYPE_STATION), 3630f79cbc77SKalle Valo .he_cap = { 3631f79cbc77SKalle Valo .has_he = true, 3632f79cbc77SKalle Valo .he_cap_elem = { 3633f79cbc77SKalle Valo .mac_cap_info[0] = 3634f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP0_HTC_HE, 3635f79cbc77SKalle Valo .mac_cap_info[1] = 3636f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | 3637f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 3638f79cbc77SKalle Valo .mac_cap_info[2] = 3639f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_BSR | 3640f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_MU_CASCADING | 3641f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_ACK_EN, 3642f79cbc77SKalle Valo .mac_cap_info[3] = 3643f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 3644f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 3645f79cbc77SKalle Valo .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 3646f79cbc77SKalle Valo .phy_cap_info[1] = 3647f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 3648f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 3649f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 3650f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 3651f79cbc77SKalle Valo .phy_cap_info[2] = 3652f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | 3653f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | 3654f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | 3655f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | 3656f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO, 3657f79cbc77SKalle Valo 3658f79cbc77SKalle Valo /* Leave all the other PHY capability bytes 3659f79cbc77SKalle Valo * unset, as DCM, beam forming, RU and PPE 3660f79cbc77SKalle Valo * threshold information are not supported 3661f79cbc77SKalle Valo */ 3662f79cbc77SKalle Valo }, 3663f79cbc77SKalle Valo .he_mcs_nss_supp = { 3664f79cbc77SKalle Valo .rx_mcs_80 = cpu_to_le16(0xfffa), 3665f79cbc77SKalle Valo .tx_mcs_80 = cpu_to_le16(0xfffa), 3666f79cbc77SKalle Valo .rx_mcs_160 = cpu_to_le16(0xffff), 3667f79cbc77SKalle Valo .tx_mcs_160 = cpu_to_le16(0xffff), 3668f79cbc77SKalle Valo .rx_mcs_80p80 = cpu_to_le16(0xffff), 3669f79cbc77SKalle Valo .tx_mcs_80p80 = cpu_to_le16(0xffff), 3670f79cbc77SKalle Valo }, 3671f79cbc77SKalle Valo }, 3672f79cbc77SKalle Valo .eht_cap = { 3673f79cbc77SKalle Valo .has_eht = true, 3674f79cbc77SKalle Valo .eht_cap_elem = { 3675f79cbc77SKalle Valo .mac_cap_info[0] = 3676f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | 3677f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_OM_CONTROL | 3678f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1, 3679f79cbc77SKalle Valo .phy_cap_info[0] = 3680f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | 3681f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | 3682f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | 3683f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER | 3684f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE, 3685f79cbc77SKalle Valo .phy_cap_info[3] = 3686f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | 3687f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | 3688f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | 3689f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | 3690f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | 3691f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | 3692f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK, 3693f79cbc77SKalle Valo .phy_cap_info[4] = 3694f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | 3695f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PSR_SR_SUPP | 3696f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | 3697f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI | 3698f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK, 3699f79cbc77SKalle Valo .phy_cap_info[5] = 3700f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | 3701f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP | 3702f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP | 3703f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT | 3704f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK | 3705f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK, 3706f79cbc77SKalle Valo .phy_cap_info[6] = 3707f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK | 3708f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK, 3709f79cbc77SKalle Valo .phy_cap_info[7] = 3710f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_20MHZ_STA_RX_NDP_WIDER_BW, 3711f79cbc77SKalle Valo }, 3712f79cbc77SKalle Valo 3713f79cbc77SKalle Valo /* For all MCS and bandwidth, set 8 NSS for both Tx and 3714f79cbc77SKalle Valo * Rx 3715f79cbc77SKalle Valo */ 3716f79cbc77SKalle Valo .eht_mcs_nss_supp = { 3717f79cbc77SKalle Valo /* 3718f79cbc77SKalle Valo * Since B0, B1, B2 and B3 are not set in 3719f79cbc77SKalle Valo * the supported channel width set field in the 3720f79cbc77SKalle Valo * HE PHY capabilities information field the 3721f79cbc77SKalle Valo * device is a 20MHz only device on 2.4GHz band. 3722f79cbc77SKalle Valo */ 3723f79cbc77SKalle Valo .only_20mhz = { 3724f79cbc77SKalle Valo .rx_tx_mcs7_max_nss = 0x88, 3725f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 3726f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 3727f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 3728f79cbc77SKalle Valo }, 3729f79cbc77SKalle Valo }, 3730f79cbc77SKalle Valo /* PPE threshold information is not supported */ 3731f79cbc77SKalle Valo }, 3732f79cbc77SKalle Valo }, 3733f79cbc77SKalle Valo { 3734f79cbc77SKalle Valo .types_mask = BIT(NL80211_IFTYPE_AP), 3735f79cbc77SKalle Valo .he_cap = { 3736f79cbc77SKalle Valo .has_he = true, 3737f79cbc77SKalle Valo .he_cap_elem = { 3738f79cbc77SKalle Valo .mac_cap_info[0] = 3739f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP0_HTC_HE, 3740f79cbc77SKalle Valo .mac_cap_info[1] = 3741f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | 3742f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 3743f79cbc77SKalle Valo .mac_cap_info[2] = 3744f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_BSR | 3745f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_MU_CASCADING | 3746f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_ACK_EN, 3747f79cbc77SKalle Valo .mac_cap_info[3] = 3748f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 3749f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 3750f79cbc77SKalle Valo .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 3751f79cbc77SKalle Valo .phy_cap_info[1] = 3752f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 3753f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 3754f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 3755f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 3756f79cbc77SKalle Valo .phy_cap_info[2] = 3757f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | 3758f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | 3759f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | 3760f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | 3761f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO, 3762f79cbc77SKalle Valo 3763f79cbc77SKalle Valo /* Leave all the other PHY capability bytes 3764f79cbc77SKalle Valo * unset, as DCM, beam forming, RU and PPE 3765f79cbc77SKalle Valo * threshold information are not supported 3766f79cbc77SKalle Valo */ 3767f79cbc77SKalle Valo }, 3768f79cbc77SKalle Valo .he_mcs_nss_supp = { 3769f79cbc77SKalle Valo .rx_mcs_80 = cpu_to_le16(0xfffa), 3770f79cbc77SKalle Valo .tx_mcs_80 = cpu_to_le16(0xfffa), 3771f79cbc77SKalle Valo .rx_mcs_160 = cpu_to_le16(0xffff), 3772f79cbc77SKalle Valo .tx_mcs_160 = cpu_to_le16(0xffff), 3773f79cbc77SKalle Valo .rx_mcs_80p80 = cpu_to_le16(0xffff), 3774f79cbc77SKalle Valo .tx_mcs_80p80 = cpu_to_le16(0xffff), 3775f79cbc77SKalle Valo }, 3776f79cbc77SKalle Valo }, 3777f79cbc77SKalle Valo .eht_cap = { 3778f79cbc77SKalle Valo .has_eht = true, 3779f79cbc77SKalle Valo .eht_cap_elem = { 3780f79cbc77SKalle Valo .mac_cap_info[0] = 3781f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | 3782f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_OM_CONTROL | 3783f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1, 3784f79cbc77SKalle Valo .phy_cap_info[0] = 3785f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | 3786f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | 3787f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | 3788f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER | 3789f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE, 3790f79cbc77SKalle Valo .phy_cap_info[3] = 3791f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | 3792f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | 3793f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | 3794f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | 3795f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | 3796f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | 3797f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK, 3798f79cbc77SKalle Valo .phy_cap_info[4] = 3799f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | 3800f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PSR_SR_SUPP | 3801f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | 3802f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI | 3803f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK, 3804f79cbc77SKalle Valo .phy_cap_info[5] = 3805f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | 3806f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP | 3807f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP | 3808f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT | 3809f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK | 3810f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK, 3811f79cbc77SKalle Valo .phy_cap_info[6] = 3812f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK | 3813f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK, 3814f79cbc77SKalle Valo .phy_cap_info[7] = 3815f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_20MHZ_STA_RX_NDP_WIDER_BW, 3816f79cbc77SKalle Valo }, 3817f79cbc77SKalle Valo 3818f79cbc77SKalle Valo /* For all MCS and bandwidth, set 8 NSS for both Tx and 3819f79cbc77SKalle Valo * Rx 3820f79cbc77SKalle Valo */ 3821f79cbc77SKalle Valo .eht_mcs_nss_supp = { 3822f79cbc77SKalle Valo /* 3823f79cbc77SKalle Valo * Since B0, B1, B2 and B3 are not set in 3824f79cbc77SKalle Valo * the supported channel width set field in the 3825f79cbc77SKalle Valo * HE PHY capabilities information field the 3826f79cbc77SKalle Valo * device is a 20MHz only device on 2.4GHz band. 3827f79cbc77SKalle Valo */ 3828f79cbc77SKalle Valo .only_20mhz = { 3829f79cbc77SKalle Valo .rx_tx_mcs7_max_nss = 0x88, 3830f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 3831f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 3832f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 3833f79cbc77SKalle Valo }, 3834f79cbc77SKalle Valo }, 3835f79cbc77SKalle Valo /* PPE threshold information is not supported */ 3836f79cbc77SKalle Valo }, 3837f79cbc77SKalle Valo }, 3838f79cbc77SKalle Valo #ifdef CONFIG_MAC80211_MESH 3839f79cbc77SKalle Valo { 3840f79cbc77SKalle Valo .types_mask = BIT(NL80211_IFTYPE_MESH_POINT), 3841f79cbc77SKalle Valo .he_cap = { 3842f79cbc77SKalle Valo .has_he = true, 3843f79cbc77SKalle Valo .he_cap_elem = { 3844f79cbc77SKalle Valo .mac_cap_info[0] = 3845f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP0_HTC_HE, 3846f79cbc77SKalle Valo .mac_cap_info[1] = 3847f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 3848f79cbc77SKalle Valo .mac_cap_info[2] = 3849f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_ACK_EN, 3850f79cbc77SKalle Valo .mac_cap_info[3] = 3851f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 3852f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 3853f79cbc77SKalle Valo .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 3854f79cbc77SKalle Valo .phy_cap_info[1] = 3855f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 3856f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 3857f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 3858f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 3859f79cbc77SKalle Valo .phy_cap_info[2] = 0, 3860f79cbc77SKalle Valo 3861f79cbc77SKalle Valo /* Leave all the other PHY capability bytes 3862f79cbc77SKalle Valo * unset, as DCM, beam forming, RU and PPE 3863f79cbc77SKalle Valo * threshold information are not supported 3864f79cbc77SKalle Valo */ 3865f79cbc77SKalle Valo }, 3866f79cbc77SKalle Valo .he_mcs_nss_supp = { 3867f79cbc77SKalle Valo .rx_mcs_80 = cpu_to_le16(0xfffa), 3868f79cbc77SKalle Valo .tx_mcs_80 = cpu_to_le16(0xfffa), 3869f79cbc77SKalle Valo .rx_mcs_160 = cpu_to_le16(0xffff), 3870f79cbc77SKalle Valo .tx_mcs_160 = cpu_to_le16(0xffff), 3871f79cbc77SKalle Valo .rx_mcs_80p80 = cpu_to_le16(0xffff), 3872f79cbc77SKalle Valo .tx_mcs_80p80 = cpu_to_le16(0xffff), 3873f79cbc77SKalle Valo }, 3874f79cbc77SKalle Valo }, 3875f79cbc77SKalle Valo }, 3876f79cbc77SKalle Valo #endif 3877f79cbc77SKalle Valo }; 3878f79cbc77SKalle Valo 3879f79cbc77SKalle Valo static const struct ieee80211_sband_iftype_data sband_capa_5ghz[] = { 3880f79cbc77SKalle Valo { 3881f79cbc77SKalle Valo /* TODO: should we support other types, e.g., P2P? */ 3882f79cbc77SKalle Valo .types_mask = BIT(NL80211_IFTYPE_STATION), 3883f79cbc77SKalle Valo .he_cap = { 3884f79cbc77SKalle Valo .has_he = true, 3885f79cbc77SKalle Valo .he_cap_elem = { 3886f79cbc77SKalle Valo .mac_cap_info[0] = 3887f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP0_HTC_HE, 3888f79cbc77SKalle Valo .mac_cap_info[1] = 3889f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | 3890f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 3891f79cbc77SKalle Valo .mac_cap_info[2] = 3892f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_BSR | 3893f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_MU_CASCADING | 3894f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_ACK_EN, 3895f79cbc77SKalle Valo .mac_cap_info[3] = 3896f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 3897f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 3898f79cbc77SKalle Valo .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 3899f79cbc77SKalle Valo .phy_cap_info[0] = 3900f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | 3901f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | 3902f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G, 3903f79cbc77SKalle Valo .phy_cap_info[1] = 3904f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 3905f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 3906f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 3907f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 3908f79cbc77SKalle Valo .phy_cap_info[2] = 3909f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | 3910f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | 3911f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | 3912f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | 3913f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO, 3914f79cbc77SKalle Valo 3915f79cbc77SKalle Valo /* Leave all the other PHY capability bytes 3916f79cbc77SKalle Valo * unset, as DCM, beam forming, RU and PPE 3917f79cbc77SKalle Valo * threshold information are not supported 3918f79cbc77SKalle Valo */ 3919f79cbc77SKalle Valo }, 3920f79cbc77SKalle Valo .he_mcs_nss_supp = { 3921f79cbc77SKalle Valo .rx_mcs_80 = cpu_to_le16(0xfffa), 3922f79cbc77SKalle Valo .tx_mcs_80 = cpu_to_le16(0xfffa), 3923f79cbc77SKalle Valo .rx_mcs_160 = cpu_to_le16(0xfffa), 3924f79cbc77SKalle Valo .tx_mcs_160 = cpu_to_le16(0xfffa), 3925f79cbc77SKalle Valo .rx_mcs_80p80 = cpu_to_le16(0xfffa), 3926f79cbc77SKalle Valo .tx_mcs_80p80 = cpu_to_le16(0xfffa), 3927f79cbc77SKalle Valo }, 3928f79cbc77SKalle Valo }, 3929f79cbc77SKalle Valo .eht_cap = { 3930f79cbc77SKalle Valo .has_eht = true, 3931f79cbc77SKalle Valo .eht_cap_elem = { 3932f79cbc77SKalle Valo .mac_cap_info[0] = 3933f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | 3934f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_OM_CONTROL | 3935f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1, 3936f79cbc77SKalle Valo .phy_cap_info[0] = 3937f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | 3938f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | 3939f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | 3940f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER | 3941f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE | 3942f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK, 3943f79cbc77SKalle Valo .phy_cap_info[1] = 3944f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK | 3945f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK, 3946f79cbc77SKalle Valo .phy_cap_info[2] = 3947f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_80MHZ_MASK | 3948f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK, 3949f79cbc77SKalle Valo .phy_cap_info[3] = 3950f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | 3951f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | 3952f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | 3953f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | 3954f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | 3955f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | 3956f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK, 3957f79cbc77SKalle Valo .phy_cap_info[4] = 3958f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | 3959f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PSR_SR_SUPP | 3960f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | 3961f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI | 3962f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK, 3963f79cbc77SKalle Valo .phy_cap_info[5] = 3964f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | 3965f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP | 3966f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP | 3967f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT | 3968f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK | 3969f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK, 3970f79cbc77SKalle Valo .phy_cap_info[6] = 3971f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK | 3972f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK, 3973f79cbc77SKalle Valo .phy_cap_info[7] = 3974f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_20MHZ_STA_RX_NDP_WIDER_BW | 3975f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ | 3976f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ | 3977f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ | 3978f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ, 3979f79cbc77SKalle Valo }, 3980f79cbc77SKalle Valo 3981f79cbc77SKalle Valo /* For all MCS and bandwidth, set 8 NSS for both Tx and 3982f79cbc77SKalle Valo * Rx 3983f79cbc77SKalle Valo */ 3984f79cbc77SKalle Valo .eht_mcs_nss_supp = { 3985f79cbc77SKalle Valo /* 3986f79cbc77SKalle Valo * As B1 and B2 are set in the supported 3987f79cbc77SKalle Valo * channel width set field in the HE PHY 3988f79cbc77SKalle Valo * capabilities information field include all 3989f79cbc77SKalle Valo * the following MCS/NSS. 3990f79cbc77SKalle Valo */ 3991f79cbc77SKalle Valo .bw._80 = { 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 .bw._160 = { 3997f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 3998f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 3999f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 4000f79cbc77SKalle Valo }, 4001f79cbc77SKalle Valo }, 4002f79cbc77SKalle Valo /* PPE threshold information is not supported */ 4003f79cbc77SKalle Valo }, 4004f79cbc77SKalle Valo }, 4005f79cbc77SKalle Valo { 4006f79cbc77SKalle Valo .types_mask = BIT(NL80211_IFTYPE_AP), 4007f79cbc77SKalle Valo .he_cap = { 4008f79cbc77SKalle Valo .has_he = true, 4009f79cbc77SKalle Valo .he_cap_elem = { 4010f79cbc77SKalle Valo .mac_cap_info[0] = 4011f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP0_HTC_HE, 4012f79cbc77SKalle Valo .mac_cap_info[1] = 4013f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | 4014f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 4015f79cbc77SKalle Valo .mac_cap_info[2] = 4016f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_BSR | 4017f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_MU_CASCADING | 4018f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_ACK_EN, 4019f79cbc77SKalle Valo .mac_cap_info[3] = 4020f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 4021f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 4022f79cbc77SKalle Valo .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 4023f79cbc77SKalle Valo .phy_cap_info[0] = 4024f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | 4025f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | 4026f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G, 4027f79cbc77SKalle Valo .phy_cap_info[1] = 4028f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 4029f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 4030f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 4031f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 4032f79cbc77SKalle Valo .phy_cap_info[2] = 4033f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | 4034f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | 4035f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | 4036f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | 4037f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO, 4038f79cbc77SKalle Valo 4039f79cbc77SKalle Valo /* Leave all the other PHY capability bytes 4040f79cbc77SKalle Valo * unset, as DCM, beam forming, RU and PPE 4041f79cbc77SKalle Valo * threshold information are not supported 4042f79cbc77SKalle Valo */ 4043f79cbc77SKalle Valo }, 4044f79cbc77SKalle Valo .he_mcs_nss_supp = { 4045f79cbc77SKalle Valo .rx_mcs_80 = cpu_to_le16(0xfffa), 4046f79cbc77SKalle Valo .tx_mcs_80 = cpu_to_le16(0xfffa), 4047f79cbc77SKalle Valo .rx_mcs_160 = cpu_to_le16(0xfffa), 4048f79cbc77SKalle Valo .tx_mcs_160 = cpu_to_le16(0xfffa), 4049f79cbc77SKalle Valo .rx_mcs_80p80 = cpu_to_le16(0xfffa), 4050f79cbc77SKalle Valo .tx_mcs_80p80 = cpu_to_le16(0xfffa), 4051f79cbc77SKalle Valo }, 4052f79cbc77SKalle Valo }, 4053f79cbc77SKalle Valo .eht_cap = { 4054f79cbc77SKalle Valo .has_eht = true, 4055f79cbc77SKalle Valo .eht_cap_elem = { 4056f79cbc77SKalle Valo .mac_cap_info[0] = 4057f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | 4058f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_OM_CONTROL | 4059f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1, 4060f79cbc77SKalle Valo .phy_cap_info[0] = 4061f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | 4062f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | 4063f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | 4064f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER | 4065f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE | 4066f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK, 4067f79cbc77SKalle Valo .phy_cap_info[1] = 4068f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK | 4069f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK, 4070f79cbc77SKalle Valo .phy_cap_info[2] = 4071f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_80MHZ_MASK | 4072f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK, 4073f79cbc77SKalle Valo .phy_cap_info[3] = 4074f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | 4075f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | 4076f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | 4077f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | 4078f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | 4079f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | 4080f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK, 4081f79cbc77SKalle Valo .phy_cap_info[4] = 4082f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | 4083f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PSR_SR_SUPP | 4084f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | 4085f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI | 4086f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK, 4087f79cbc77SKalle Valo .phy_cap_info[5] = 4088f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | 4089f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP | 4090f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP | 4091f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT | 4092f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK | 4093f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK, 4094f79cbc77SKalle Valo .phy_cap_info[6] = 4095f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK | 4096f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK, 4097f79cbc77SKalle Valo .phy_cap_info[7] = 4098f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_20MHZ_STA_RX_NDP_WIDER_BW | 4099f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ | 4100f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ | 4101f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ | 4102f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ, 4103f79cbc77SKalle Valo }, 4104f79cbc77SKalle Valo 4105f79cbc77SKalle Valo /* For all MCS and bandwidth, set 8 NSS for both Tx and 4106f79cbc77SKalle Valo * Rx 4107f79cbc77SKalle Valo */ 4108f79cbc77SKalle Valo .eht_mcs_nss_supp = { 4109f79cbc77SKalle Valo /* 4110f79cbc77SKalle Valo * As B1 and B2 are set in the supported 4111f79cbc77SKalle Valo * channel width set field in the HE PHY 4112f79cbc77SKalle Valo * capabilities information field include all 4113f79cbc77SKalle Valo * the following MCS/NSS. 4114f79cbc77SKalle Valo */ 4115f79cbc77SKalle Valo .bw._80 = { 4116f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 4117f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 4118f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 4119f79cbc77SKalle Valo }, 4120f79cbc77SKalle Valo .bw._160 = { 4121f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 4122f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 4123f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 4124f79cbc77SKalle Valo }, 4125f79cbc77SKalle Valo }, 4126f79cbc77SKalle Valo /* PPE threshold information is not supported */ 4127f79cbc77SKalle Valo }, 4128f79cbc77SKalle Valo }, 4129f79cbc77SKalle Valo #ifdef CONFIG_MAC80211_MESH 4130f79cbc77SKalle Valo { 4131f79cbc77SKalle Valo /* TODO: should we support other types, e.g., IBSS?*/ 4132f79cbc77SKalle Valo .types_mask = BIT(NL80211_IFTYPE_MESH_POINT), 4133f79cbc77SKalle Valo .he_cap = { 4134f79cbc77SKalle Valo .has_he = true, 4135f79cbc77SKalle Valo .he_cap_elem = { 4136f79cbc77SKalle Valo .mac_cap_info[0] = 4137f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP0_HTC_HE, 4138f79cbc77SKalle Valo .mac_cap_info[1] = 4139f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 4140f79cbc77SKalle Valo .mac_cap_info[2] = 4141f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_ACK_EN, 4142f79cbc77SKalle Valo .mac_cap_info[3] = 4143f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 4144f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 4145f79cbc77SKalle Valo .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 4146f79cbc77SKalle Valo .phy_cap_info[0] = 4147f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | 4148f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | 4149f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G, 4150f79cbc77SKalle Valo .phy_cap_info[1] = 4151f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 4152f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 4153f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 4154f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 4155f79cbc77SKalle Valo .phy_cap_info[2] = 0, 4156f79cbc77SKalle Valo 4157f79cbc77SKalle Valo /* Leave all the other PHY capability bytes 4158f79cbc77SKalle Valo * unset, as DCM, beam forming, RU and PPE 4159f79cbc77SKalle Valo * threshold information are not supported 4160f79cbc77SKalle Valo */ 4161f79cbc77SKalle Valo }, 4162f79cbc77SKalle Valo .he_mcs_nss_supp = { 4163f79cbc77SKalle Valo .rx_mcs_80 = cpu_to_le16(0xfffa), 4164f79cbc77SKalle Valo .tx_mcs_80 = cpu_to_le16(0xfffa), 4165f79cbc77SKalle Valo .rx_mcs_160 = cpu_to_le16(0xfffa), 4166f79cbc77SKalle Valo .tx_mcs_160 = cpu_to_le16(0xfffa), 4167f79cbc77SKalle Valo .rx_mcs_80p80 = cpu_to_le16(0xfffa), 4168f79cbc77SKalle Valo .tx_mcs_80p80 = cpu_to_le16(0xfffa), 4169f79cbc77SKalle Valo }, 4170f79cbc77SKalle Valo }, 4171f79cbc77SKalle Valo }, 4172f79cbc77SKalle Valo #endif 4173f79cbc77SKalle Valo }; 4174f79cbc77SKalle Valo 4175f79cbc77SKalle Valo static const struct ieee80211_sband_iftype_data sband_capa_6ghz[] = { 4176f79cbc77SKalle Valo { 4177f79cbc77SKalle Valo /* TODO: should we support other types, e.g., P2P? */ 4178f79cbc77SKalle Valo .types_mask = BIT(NL80211_IFTYPE_STATION), 4179f79cbc77SKalle Valo .he_6ghz_capa = { 4180f79cbc77SKalle Valo .capa = cpu_to_le16(IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START | 4181f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP | 4182f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN | 4183f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_SM_PS | 4184f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_RD_RESPONDER | 4185f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS | 4186f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS), 4187f79cbc77SKalle Valo }, 4188f79cbc77SKalle Valo .he_cap = { 4189f79cbc77SKalle Valo .has_he = true, 4190f79cbc77SKalle Valo .he_cap_elem = { 4191f79cbc77SKalle Valo .mac_cap_info[0] = 4192f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP0_HTC_HE, 4193f79cbc77SKalle Valo .mac_cap_info[1] = 4194f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | 4195f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 4196f79cbc77SKalle Valo .mac_cap_info[2] = 4197f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_BSR | 4198f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_MU_CASCADING | 4199f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_ACK_EN, 4200f79cbc77SKalle Valo .mac_cap_info[3] = 4201f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 4202f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 4203f79cbc77SKalle Valo .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 4204f79cbc77SKalle Valo .phy_cap_info[0] = 4205f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | 4206f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | 4207f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G, 4208f79cbc77SKalle Valo .phy_cap_info[1] = 4209f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 4210f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 4211f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 4212f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 4213f79cbc77SKalle Valo .phy_cap_info[2] = 4214f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | 4215f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | 4216f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | 4217f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | 4218f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO, 4219f79cbc77SKalle Valo 4220f79cbc77SKalle Valo /* Leave all the other PHY capability bytes 4221f79cbc77SKalle Valo * unset, as DCM, beam forming, RU and PPE 4222f79cbc77SKalle Valo * threshold information are not supported 4223f79cbc77SKalle Valo */ 4224f79cbc77SKalle Valo }, 4225f79cbc77SKalle Valo .he_mcs_nss_supp = { 4226f79cbc77SKalle Valo .rx_mcs_80 = cpu_to_le16(0xfffa), 4227f79cbc77SKalle Valo .tx_mcs_80 = cpu_to_le16(0xfffa), 4228f79cbc77SKalle Valo .rx_mcs_160 = cpu_to_le16(0xfffa), 4229f79cbc77SKalle Valo .tx_mcs_160 = cpu_to_le16(0xfffa), 4230f79cbc77SKalle Valo .rx_mcs_80p80 = cpu_to_le16(0xfffa), 4231f79cbc77SKalle Valo .tx_mcs_80p80 = cpu_to_le16(0xfffa), 4232f79cbc77SKalle Valo }, 4233f79cbc77SKalle Valo }, 4234f79cbc77SKalle Valo .eht_cap = { 4235f79cbc77SKalle Valo .has_eht = true, 4236f79cbc77SKalle Valo .eht_cap_elem = { 4237f79cbc77SKalle Valo .mac_cap_info[0] = 4238f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | 4239f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_OM_CONTROL | 4240f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1, 4241f79cbc77SKalle Valo .phy_cap_info[0] = 4242f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ | 4243f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | 4244f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | 4245f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | 4246f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER | 4247f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE | 4248f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK, 4249f79cbc77SKalle Valo .phy_cap_info[1] = 4250f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK | 4251f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK | 4252f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK, 4253f79cbc77SKalle Valo .phy_cap_info[2] = 4254f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_80MHZ_MASK | 4255f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK | 4256f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_320MHZ_MASK, 4257f79cbc77SKalle Valo .phy_cap_info[3] = 4258f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | 4259f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | 4260f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | 4261f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | 4262f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | 4263f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | 4264f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK, 4265f79cbc77SKalle Valo .phy_cap_info[4] = 4266f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | 4267f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PSR_SR_SUPP | 4268f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | 4269f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI | 4270f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK, 4271f79cbc77SKalle Valo .phy_cap_info[5] = 4272f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | 4273f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP | 4274f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP | 4275f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT | 4276f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK | 4277f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK, 4278f79cbc77SKalle Valo .phy_cap_info[6] = 4279f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK | 4280f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK | 4281f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_EHT_DUP_6GHZ_SUPP, 4282f79cbc77SKalle Valo .phy_cap_info[7] = 4283f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_20MHZ_STA_RX_NDP_WIDER_BW | 4284f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ | 4285f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ | 4286f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_320MHZ | 4287f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ | 4288f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ | 4289f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_320MHZ, 4290f79cbc77SKalle Valo }, 4291f79cbc77SKalle Valo 4292f79cbc77SKalle Valo /* For all MCS and bandwidth, set 8 NSS for both Tx and 4293f79cbc77SKalle Valo * Rx 4294f79cbc77SKalle Valo */ 4295f79cbc77SKalle Valo .eht_mcs_nss_supp = { 4296f79cbc77SKalle Valo /* 4297f79cbc77SKalle Valo * As B1 and B2 are set in the supported 4298f79cbc77SKalle Valo * channel width set field in the HE PHY 4299f79cbc77SKalle Valo * capabilities information field and 320MHz in 4300f79cbc77SKalle Valo * 6GHz is supported include all the following 4301f79cbc77SKalle Valo * MCS/NSS. 4302f79cbc77SKalle Valo */ 4303f79cbc77SKalle Valo .bw._80 = { 4304f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 4305f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 4306f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 4307f79cbc77SKalle Valo }, 4308f79cbc77SKalle Valo .bw._160 = { 4309f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 4310f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 4311f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 4312f79cbc77SKalle Valo }, 4313f79cbc77SKalle Valo .bw._320 = { 4314f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 4315f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 4316f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 4317f79cbc77SKalle Valo }, 4318f79cbc77SKalle Valo }, 4319f79cbc77SKalle Valo /* PPE threshold information is not supported */ 4320f79cbc77SKalle Valo }, 4321f79cbc77SKalle Valo }, 4322f79cbc77SKalle Valo { 4323f79cbc77SKalle Valo .types_mask = BIT(NL80211_IFTYPE_AP), 4324f79cbc77SKalle Valo .he_6ghz_capa = { 4325f79cbc77SKalle Valo .capa = cpu_to_le16(IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START | 4326f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP | 4327f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN | 4328f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_SM_PS | 4329f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_RD_RESPONDER | 4330f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS | 4331f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS), 4332f79cbc77SKalle Valo }, 4333f79cbc77SKalle Valo .he_cap = { 4334f79cbc77SKalle Valo .has_he = true, 4335f79cbc77SKalle Valo .he_cap_elem = { 4336f79cbc77SKalle Valo .mac_cap_info[0] = 4337f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP0_HTC_HE, 4338f79cbc77SKalle Valo .mac_cap_info[1] = 4339f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | 4340f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 4341f79cbc77SKalle Valo .mac_cap_info[2] = 4342f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_BSR | 4343f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_MU_CASCADING | 4344f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_ACK_EN, 4345f79cbc77SKalle Valo .mac_cap_info[3] = 4346f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 4347f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 4348f79cbc77SKalle Valo .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 4349f79cbc77SKalle Valo .phy_cap_info[0] = 4350f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | 4351f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | 4352f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G, 4353f79cbc77SKalle Valo .phy_cap_info[1] = 4354f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 4355f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 4356f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 4357f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 4358f79cbc77SKalle Valo .phy_cap_info[2] = 4359f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | 4360f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | 4361f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | 4362f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | 4363f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO, 4364f79cbc77SKalle Valo 4365f79cbc77SKalle Valo /* Leave all the other PHY capability bytes 4366f79cbc77SKalle Valo * unset, as DCM, beam forming, RU and PPE 4367f79cbc77SKalle Valo * threshold information are not supported 4368f79cbc77SKalle Valo */ 4369f79cbc77SKalle Valo }, 4370f79cbc77SKalle Valo .he_mcs_nss_supp = { 4371f79cbc77SKalle Valo .rx_mcs_80 = cpu_to_le16(0xfffa), 4372f79cbc77SKalle Valo .tx_mcs_80 = cpu_to_le16(0xfffa), 4373f79cbc77SKalle Valo .rx_mcs_160 = cpu_to_le16(0xfffa), 4374f79cbc77SKalle Valo .tx_mcs_160 = cpu_to_le16(0xfffa), 4375f79cbc77SKalle Valo .rx_mcs_80p80 = cpu_to_le16(0xfffa), 4376f79cbc77SKalle Valo .tx_mcs_80p80 = cpu_to_le16(0xfffa), 4377f79cbc77SKalle Valo }, 4378f79cbc77SKalle Valo }, 4379f79cbc77SKalle Valo .eht_cap = { 4380f79cbc77SKalle Valo .has_eht = true, 4381f79cbc77SKalle Valo .eht_cap_elem = { 4382f79cbc77SKalle Valo .mac_cap_info[0] = 4383f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | 4384f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_OM_CONTROL | 4385f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1, 4386f79cbc77SKalle Valo .phy_cap_info[0] = 4387f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ | 4388f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | 4389f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | 4390f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | 4391f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER | 4392f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE | 4393f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK, 4394f79cbc77SKalle Valo .phy_cap_info[1] = 4395f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK | 4396f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK | 4397f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK, 4398f79cbc77SKalle Valo .phy_cap_info[2] = 4399f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_80MHZ_MASK | 4400f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK | 4401f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_320MHZ_MASK, 4402f79cbc77SKalle Valo .phy_cap_info[3] = 4403f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | 4404f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | 4405f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | 4406f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | 4407f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | 4408f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | 4409f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK, 4410f79cbc77SKalle Valo .phy_cap_info[4] = 4411f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | 4412f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PSR_SR_SUPP | 4413f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | 4414f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI | 4415f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK, 4416f79cbc77SKalle Valo .phy_cap_info[5] = 4417f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | 4418f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP | 4419f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP | 4420f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT | 4421f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK | 4422f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK, 4423f79cbc77SKalle Valo .phy_cap_info[6] = 4424f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK | 4425f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK | 4426f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_EHT_DUP_6GHZ_SUPP, 4427f79cbc77SKalle Valo .phy_cap_info[7] = 4428f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_20MHZ_STA_RX_NDP_WIDER_BW | 4429f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ | 4430f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ | 4431f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_320MHZ | 4432f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ | 4433f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ | 4434f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_320MHZ, 4435f79cbc77SKalle Valo }, 4436f79cbc77SKalle Valo 4437f79cbc77SKalle Valo /* For all MCS and bandwidth, set 8 NSS for both Tx and 4438f79cbc77SKalle Valo * Rx 4439f79cbc77SKalle Valo */ 4440f79cbc77SKalle Valo .eht_mcs_nss_supp = { 4441f79cbc77SKalle Valo /* 4442f79cbc77SKalle Valo * As B1 and B2 are set in the supported 4443f79cbc77SKalle Valo * channel width set field in the HE PHY 4444f79cbc77SKalle Valo * capabilities information field and 320MHz in 4445f79cbc77SKalle Valo * 6GHz is supported include all the following 4446f79cbc77SKalle Valo * MCS/NSS. 4447f79cbc77SKalle Valo */ 4448f79cbc77SKalle Valo .bw._80 = { 4449f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 4450f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 4451f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 4452f79cbc77SKalle Valo }, 4453f79cbc77SKalle Valo .bw._160 = { 4454f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 4455f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 4456f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 4457f79cbc77SKalle Valo }, 4458f79cbc77SKalle Valo .bw._320 = { 4459f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 4460f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 4461f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 4462f79cbc77SKalle Valo }, 4463f79cbc77SKalle Valo }, 4464f79cbc77SKalle Valo /* PPE threshold information is not supported */ 4465f79cbc77SKalle Valo }, 4466f79cbc77SKalle Valo }, 4467f79cbc77SKalle Valo #ifdef CONFIG_MAC80211_MESH 4468f79cbc77SKalle Valo { 4469f79cbc77SKalle Valo /* TODO: should we support other types, e.g., IBSS?*/ 4470f79cbc77SKalle Valo .types_mask = BIT(NL80211_IFTYPE_MESH_POINT), 4471f79cbc77SKalle Valo .he_6ghz_capa = { 4472f79cbc77SKalle Valo .capa = cpu_to_le16(IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START | 4473f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP | 4474f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN | 4475f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_SM_PS | 4476f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_RD_RESPONDER | 4477f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS | 4478f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS), 4479f79cbc77SKalle Valo }, 4480f79cbc77SKalle Valo .he_cap = { 4481f79cbc77SKalle Valo .has_he = true, 4482f79cbc77SKalle Valo .he_cap_elem = { 4483f79cbc77SKalle Valo .mac_cap_info[0] = 4484f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP0_HTC_HE, 4485f79cbc77SKalle Valo .mac_cap_info[1] = 4486f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 4487f79cbc77SKalle Valo .mac_cap_info[2] = 4488f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_ACK_EN, 4489f79cbc77SKalle Valo .mac_cap_info[3] = 4490f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 4491f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 4492f79cbc77SKalle Valo .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 4493f79cbc77SKalle Valo .phy_cap_info[0] = 4494f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | 4495f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | 4496f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G, 4497f79cbc77SKalle Valo .phy_cap_info[1] = 4498f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 4499f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 4500f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 4501f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 4502f79cbc77SKalle Valo .phy_cap_info[2] = 0, 4503f79cbc77SKalle Valo 4504f79cbc77SKalle Valo /* Leave all the other PHY capability bytes 4505f79cbc77SKalle Valo * unset, as DCM, beam forming, RU and PPE 4506f79cbc77SKalle Valo * threshold information are not supported 4507f79cbc77SKalle Valo */ 4508f79cbc77SKalle Valo }, 4509f79cbc77SKalle Valo .he_mcs_nss_supp = { 4510f79cbc77SKalle Valo .rx_mcs_80 = cpu_to_le16(0xfffa), 4511f79cbc77SKalle Valo .tx_mcs_80 = cpu_to_le16(0xfffa), 4512f79cbc77SKalle Valo .rx_mcs_160 = cpu_to_le16(0xfffa), 4513f79cbc77SKalle Valo .tx_mcs_160 = cpu_to_le16(0xfffa), 4514f79cbc77SKalle Valo .rx_mcs_80p80 = cpu_to_le16(0xfffa), 4515f79cbc77SKalle Valo .tx_mcs_80p80 = cpu_to_le16(0xfffa), 4516f79cbc77SKalle Valo }, 4517f79cbc77SKalle Valo }, 4518f79cbc77SKalle Valo }, 4519f79cbc77SKalle Valo #endif 4520f79cbc77SKalle Valo }; 4521f79cbc77SKalle Valo 4522f79cbc77SKalle Valo static void mac80211_hwsim_sband_capab(struct ieee80211_supported_band *sband) 4523f79cbc77SKalle Valo { 4524f79cbc77SKalle Valo u16 n_iftype_data; 4525f79cbc77SKalle Valo 4526f79cbc77SKalle Valo if (sband->band == NL80211_BAND_2GHZ) { 4527f79cbc77SKalle Valo n_iftype_data = ARRAY_SIZE(sband_capa_2ghz); 4528f79cbc77SKalle Valo sband->iftype_data = 4529f79cbc77SKalle Valo (struct ieee80211_sband_iftype_data *)sband_capa_2ghz; 4530f79cbc77SKalle Valo } else if (sband->band == NL80211_BAND_5GHZ) { 4531f79cbc77SKalle Valo n_iftype_data = ARRAY_SIZE(sband_capa_5ghz); 4532f79cbc77SKalle Valo sband->iftype_data = 4533f79cbc77SKalle Valo (struct ieee80211_sband_iftype_data *)sband_capa_5ghz; 4534f79cbc77SKalle Valo } else if (sband->band == NL80211_BAND_6GHZ) { 4535f79cbc77SKalle Valo n_iftype_data = ARRAY_SIZE(sband_capa_6ghz); 4536f79cbc77SKalle Valo sband->iftype_data = 4537f79cbc77SKalle Valo (struct ieee80211_sband_iftype_data *)sband_capa_6ghz; 4538f79cbc77SKalle Valo } else { 4539f79cbc77SKalle Valo return; 4540f79cbc77SKalle Valo } 4541f79cbc77SKalle Valo 4542f79cbc77SKalle Valo sband->n_iftype_data = n_iftype_data; 4543f79cbc77SKalle Valo } 4544f79cbc77SKalle Valo 4545f79cbc77SKalle Valo #ifdef CONFIG_MAC80211_MESH 4546f79cbc77SKalle Valo #define HWSIM_MESH_BIT BIT(NL80211_IFTYPE_MESH_POINT) 4547f79cbc77SKalle Valo #else 4548f79cbc77SKalle Valo #define HWSIM_MESH_BIT 0 4549f79cbc77SKalle Valo #endif 4550f79cbc77SKalle Valo 4551f79cbc77SKalle Valo #define HWSIM_DEFAULT_IF_LIMIT \ 4552f79cbc77SKalle Valo (BIT(NL80211_IFTYPE_STATION) | \ 4553f79cbc77SKalle Valo BIT(NL80211_IFTYPE_P2P_CLIENT) | \ 4554f79cbc77SKalle Valo BIT(NL80211_IFTYPE_AP) | \ 4555f79cbc77SKalle Valo BIT(NL80211_IFTYPE_P2P_GO) | \ 4556f79cbc77SKalle Valo HWSIM_MESH_BIT) 4557f79cbc77SKalle Valo 4558f79cbc77SKalle Valo #define HWSIM_IFTYPE_SUPPORT_MASK \ 4559f79cbc77SKalle Valo (BIT(NL80211_IFTYPE_STATION) | \ 4560f79cbc77SKalle Valo BIT(NL80211_IFTYPE_AP) | \ 4561f79cbc77SKalle Valo BIT(NL80211_IFTYPE_P2P_CLIENT) | \ 4562f79cbc77SKalle Valo BIT(NL80211_IFTYPE_P2P_GO) | \ 4563f79cbc77SKalle Valo BIT(NL80211_IFTYPE_ADHOC) | \ 4564f79cbc77SKalle Valo BIT(NL80211_IFTYPE_MESH_POINT) | \ 4565f79cbc77SKalle Valo BIT(NL80211_IFTYPE_OCB)) 4566f79cbc77SKalle Valo 4567f79cbc77SKalle Valo static int mac80211_hwsim_new_radio(struct genl_info *info, 4568f79cbc77SKalle Valo struct hwsim_new_radio_params *param) 4569f79cbc77SKalle Valo { 4570f79cbc77SKalle Valo int err; 4571f79cbc77SKalle Valo u8 addr[ETH_ALEN]; 4572f79cbc77SKalle Valo struct mac80211_hwsim_data *data; 4573f79cbc77SKalle Valo struct ieee80211_hw *hw; 4574f79cbc77SKalle Valo enum nl80211_band band; 4575f79cbc77SKalle Valo const struct ieee80211_ops *ops = &mac80211_hwsim_ops; 4576f79cbc77SKalle Valo struct net *net; 4577f79cbc77SKalle Valo int idx, i; 4578f79cbc77SKalle Valo int n_limits = 0; 4579f79cbc77SKalle Valo 4580f79cbc77SKalle Valo if (WARN_ON(param->channels > 1 && !param->use_chanctx)) 4581f79cbc77SKalle Valo return -EINVAL; 4582f79cbc77SKalle Valo 4583f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 4584f79cbc77SKalle Valo idx = hwsim_radio_idx++; 4585f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 4586f79cbc77SKalle Valo 4587f79cbc77SKalle Valo if (param->mlo) 4588f79cbc77SKalle Valo ops = &mac80211_hwsim_mlo_ops; 4589f79cbc77SKalle Valo else if (param->use_chanctx) 4590f79cbc77SKalle Valo ops = &mac80211_hwsim_mchan_ops; 4591f79cbc77SKalle Valo hw = ieee80211_alloc_hw_nm(sizeof(*data), ops, param->hwname); 4592f79cbc77SKalle Valo if (!hw) { 4593f79cbc77SKalle Valo pr_debug("mac80211_hwsim: ieee80211_alloc_hw failed\n"); 4594f79cbc77SKalle Valo err = -ENOMEM; 4595f79cbc77SKalle Valo goto failed; 4596f79cbc77SKalle Valo } 4597f79cbc77SKalle Valo 4598f79cbc77SKalle Valo /* ieee80211_alloc_hw_nm may have used a default name */ 4599f79cbc77SKalle Valo param->hwname = wiphy_name(hw->wiphy); 4600f79cbc77SKalle Valo 4601f79cbc77SKalle Valo if (info) 4602f79cbc77SKalle Valo net = genl_info_net(info); 4603f79cbc77SKalle Valo else 4604f79cbc77SKalle Valo net = &init_net; 4605f79cbc77SKalle Valo wiphy_net_set(hw->wiphy, net); 4606f79cbc77SKalle Valo 4607f79cbc77SKalle Valo data = hw->priv; 4608f79cbc77SKalle Valo data->hw = hw; 4609f79cbc77SKalle Valo 4610f79cbc77SKalle Valo data->dev = device_create(hwsim_class, NULL, 0, hw, "hwsim%d", idx); 4611f79cbc77SKalle Valo if (IS_ERR(data->dev)) { 4612f79cbc77SKalle Valo printk(KERN_DEBUG 4613f79cbc77SKalle Valo "mac80211_hwsim: device_create failed (%ld)\n", 4614f79cbc77SKalle Valo PTR_ERR(data->dev)); 4615f79cbc77SKalle Valo err = -ENOMEM; 4616f79cbc77SKalle Valo goto failed_drvdata; 4617f79cbc77SKalle Valo } 4618f79cbc77SKalle Valo data->dev->driver = &mac80211_hwsim_driver.driver; 4619f79cbc77SKalle Valo err = device_bind_driver(data->dev); 4620f79cbc77SKalle Valo if (err != 0) { 4621f79cbc77SKalle Valo pr_debug("mac80211_hwsim: device_bind_driver failed (%d)\n", 4622f79cbc77SKalle Valo err); 4623f79cbc77SKalle Valo goto failed_bind; 4624f79cbc77SKalle Valo } 4625f79cbc77SKalle Valo 4626f79cbc77SKalle Valo skb_queue_head_init(&data->pending); 4627f79cbc77SKalle Valo 4628f79cbc77SKalle Valo SET_IEEE80211_DEV(hw, data->dev); 4629f79cbc77SKalle Valo if (!param->perm_addr) { 4630f79cbc77SKalle Valo eth_zero_addr(addr); 4631f79cbc77SKalle Valo addr[0] = 0x02; 4632f79cbc77SKalle Valo addr[3] = idx >> 8; 4633f79cbc77SKalle Valo addr[4] = idx; 4634f79cbc77SKalle Valo memcpy(data->addresses[0].addr, addr, ETH_ALEN); 4635f79cbc77SKalle Valo /* Why need here second address ? */ 4636f79cbc77SKalle Valo memcpy(data->addresses[1].addr, addr, ETH_ALEN); 4637f79cbc77SKalle Valo data->addresses[1].addr[0] |= 0x40; 4638f79cbc77SKalle Valo hw->wiphy->n_addresses = 2; 4639f79cbc77SKalle Valo hw->wiphy->addresses = data->addresses; 4640f79cbc77SKalle Valo /* possible address clash is checked at hash table insertion */ 4641f79cbc77SKalle Valo } else { 4642f79cbc77SKalle Valo memcpy(data->addresses[0].addr, param->perm_addr, ETH_ALEN); 4643f79cbc77SKalle Valo /* compatibility with automatically generated mac addr */ 4644f79cbc77SKalle Valo memcpy(data->addresses[1].addr, param->perm_addr, ETH_ALEN); 4645f79cbc77SKalle Valo hw->wiphy->n_addresses = 2; 4646f79cbc77SKalle Valo hw->wiphy->addresses = data->addresses; 4647f79cbc77SKalle Valo } 4648f79cbc77SKalle Valo 4649f79cbc77SKalle Valo data->channels = param->channels; 4650f79cbc77SKalle Valo data->use_chanctx = param->use_chanctx; 4651f79cbc77SKalle Valo data->idx = idx; 4652f79cbc77SKalle Valo data->destroy_on_close = param->destroy_on_close; 4653f79cbc77SKalle Valo if (info) 4654f79cbc77SKalle Valo data->portid = info->snd_portid; 4655f79cbc77SKalle Valo 4656f79cbc77SKalle Valo /* setup interface limits, only on interface types we support */ 4657f79cbc77SKalle Valo if (param->iftypes & BIT(NL80211_IFTYPE_ADHOC)) { 4658f79cbc77SKalle Valo data->if_limits[n_limits].max = 1; 4659f79cbc77SKalle Valo data->if_limits[n_limits].types = BIT(NL80211_IFTYPE_ADHOC); 4660f79cbc77SKalle Valo n_limits++; 4661f79cbc77SKalle Valo } 4662f79cbc77SKalle Valo 4663f79cbc77SKalle Valo if (param->iftypes & HWSIM_DEFAULT_IF_LIMIT) { 4664f79cbc77SKalle Valo data->if_limits[n_limits].max = 2048; 4665f79cbc77SKalle Valo /* 4666f79cbc77SKalle Valo * For this case, we may only support a subset of 4667f79cbc77SKalle Valo * HWSIM_DEFAULT_IF_LIMIT, therefore we only want to add the 4668f79cbc77SKalle Valo * bits that both param->iftype & HWSIM_DEFAULT_IF_LIMIT have. 4669f79cbc77SKalle Valo */ 4670f79cbc77SKalle Valo data->if_limits[n_limits].types = 4671f79cbc77SKalle Valo HWSIM_DEFAULT_IF_LIMIT & param->iftypes; 4672f79cbc77SKalle Valo n_limits++; 4673f79cbc77SKalle Valo } 4674f79cbc77SKalle Valo 4675f79cbc77SKalle Valo if (param->iftypes & BIT(NL80211_IFTYPE_P2P_DEVICE)) { 4676f79cbc77SKalle Valo data->if_limits[n_limits].max = 1; 4677f79cbc77SKalle Valo data->if_limits[n_limits].types = 4678f79cbc77SKalle Valo BIT(NL80211_IFTYPE_P2P_DEVICE); 4679f79cbc77SKalle Valo n_limits++; 4680f79cbc77SKalle Valo } 4681f79cbc77SKalle Valo 4682f79cbc77SKalle Valo if (data->use_chanctx) { 4683f79cbc77SKalle Valo hw->wiphy->max_scan_ssids = 255; 4684f79cbc77SKalle Valo hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; 4685f79cbc77SKalle Valo hw->wiphy->max_remain_on_channel_duration = 1000; 4686f79cbc77SKalle Valo data->if_combination.radar_detect_widths = 0; 4687f79cbc77SKalle Valo data->if_combination.num_different_channels = data->channels; 4688f79cbc77SKalle Valo } else { 4689f79cbc77SKalle Valo data->if_combination.num_different_channels = 1; 4690f79cbc77SKalle Valo data->if_combination.radar_detect_widths = 4691f79cbc77SKalle Valo BIT(NL80211_CHAN_WIDTH_5) | 4692f79cbc77SKalle Valo BIT(NL80211_CHAN_WIDTH_10) | 4693f79cbc77SKalle Valo BIT(NL80211_CHAN_WIDTH_20_NOHT) | 4694f79cbc77SKalle Valo BIT(NL80211_CHAN_WIDTH_20) | 4695f79cbc77SKalle Valo BIT(NL80211_CHAN_WIDTH_40) | 4696f79cbc77SKalle Valo BIT(NL80211_CHAN_WIDTH_80) | 4697f79cbc77SKalle Valo BIT(NL80211_CHAN_WIDTH_160); 4698f79cbc77SKalle Valo } 4699f79cbc77SKalle Valo 4700f79cbc77SKalle Valo if (!n_limits) { 4701f79cbc77SKalle Valo err = -EINVAL; 4702f79cbc77SKalle Valo goto failed_hw; 4703f79cbc77SKalle Valo } 4704f79cbc77SKalle Valo 4705f79cbc77SKalle Valo data->if_combination.max_interfaces = 0; 4706f79cbc77SKalle Valo for (i = 0; i < n_limits; i++) 4707f79cbc77SKalle Valo data->if_combination.max_interfaces += 4708f79cbc77SKalle Valo data->if_limits[i].max; 4709f79cbc77SKalle Valo 4710f79cbc77SKalle Valo data->if_combination.n_limits = n_limits; 4711f79cbc77SKalle Valo data->if_combination.limits = data->if_limits; 4712f79cbc77SKalle Valo 4713f79cbc77SKalle Valo /* 4714f79cbc77SKalle Valo * If we actually were asked to support combinations, 4715f79cbc77SKalle Valo * advertise them - if there's only a single thing like 4716f79cbc77SKalle Valo * only IBSS then don't advertise it as combinations. 4717f79cbc77SKalle Valo */ 4718f79cbc77SKalle Valo if (data->if_combination.max_interfaces > 1) { 4719f79cbc77SKalle Valo hw->wiphy->iface_combinations = &data->if_combination; 4720f79cbc77SKalle Valo hw->wiphy->n_iface_combinations = 1; 4721f79cbc77SKalle Valo } 4722f79cbc77SKalle Valo 4723f79cbc77SKalle Valo if (param->ciphers) { 4724f79cbc77SKalle Valo memcpy(data->ciphers, param->ciphers, 4725f79cbc77SKalle Valo param->n_ciphers * sizeof(u32)); 4726f79cbc77SKalle Valo hw->wiphy->cipher_suites = data->ciphers; 4727f79cbc77SKalle Valo hw->wiphy->n_cipher_suites = param->n_ciphers; 4728f79cbc77SKalle Valo } 4729f79cbc77SKalle Valo 4730c4f4d9f7SAloka Dixit hw->wiphy->mbssid_max_interfaces = 8; 47310dd45ebcSAloka Dixit hw->wiphy->ema_max_profile_periodicity = 3; 4732c4f4d9f7SAloka Dixit 4733f79cbc77SKalle Valo data->rx_rssi = DEFAULT_RX_RSSI; 4734f79cbc77SKalle Valo 4735f79cbc77SKalle Valo INIT_DELAYED_WORK(&data->roc_start, hw_roc_start); 4736f79cbc77SKalle Valo INIT_DELAYED_WORK(&data->roc_done, hw_roc_done); 4737f79cbc77SKalle Valo INIT_DELAYED_WORK(&data->hw_scan, hw_scan_work); 4738f79cbc77SKalle Valo 4739f79cbc77SKalle Valo hw->queues = 5; 4740f79cbc77SKalle Valo hw->offchannel_tx_hw_queue = 4; 4741f79cbc77SKalle Valo 4742f79cbc77SKalle Valo ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); 4743f79cbc77SKalle Valo ieee80211_hw_set(hw, CHANCTX_STA_CSA); 4744f79cbc77SKalle Valo ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); 4745f79cbc77SKalle Valo ieee80211_hw_set(hw, QUEUE_CONTROL); 4746f79cbc77SKalle Valo ieee80211_hw_set(hw, WANT_MONITOR_VIF); 4747f79cbc77SKalle Valo ieee80211_hw_set(hw, AMPDU_AGGREGATION); 4748f79cbc77SKalle Valo ieee80211_hw_set(hw, MFP_CAPABLE); 4749f79cbc77SKalle Valo ieee80211_hw_set(hw, SIGNAL_DBM); 4750f79cbc77SKalle Valo ieee80211_hw_set(hw, SUPPORTS_PS); 4751f79cbc77SKalle Valo ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); 4752f79cbc77SKalle Valo ieee80211_hw_set(hw, TDLS_WIDER_BW); 4753f79cbc77SKalle Valo ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); 4754f79cbc77SKalle Valo 4755f79cbc77SKalle Valo if (param->mlo) { 4756f79cbc77SKalle Valo hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_MLO; 4757f79cbc77SKalle Valo ieee80211_hw_set(hw, HAS_RATE_CONTROL); 4758f79cbc77SKalle Valo ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); 4759f79cbc77SKalle Valo ieee80211_hw_set(hw, CONNECTION_MONITOR); 4760f79cbc77SKalle Valo ieee80211_hw_set(hw, AP_LINK_PS); 4761f79cbc77SKalle Valo } else { 4762f79cbc77SKalle Valo ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); 4763f79cbc77SKalle Valo ieee80211_hw_set(hw, PS_NULLFUNC_STACK); 4764f79cbc77SKalle Valo if (rctbl) 4765f79cbc77SKalle Valo ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); 4766f79cbc77SKalle Valo } 4767f79cbc77SKalle Valo 4768f79cbc77SKalle Valo hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; 4769f79cbc77SKalle Valo hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | 4770f79cbc77SKalle Valo WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | 4771f79cbc77SKalle Valo WIPHY_FLAG_AP_UAPSD | 4772f79cbc77SKalle Valo WIPHY_FLAG_SUPPORTS_5_10_MHZ | 4773f79cbc77SKalle Valo WIPHY_FLAG_HAS_CHANNEL_SWITCH; 4774f79cbc77SKalle Valo hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR | 4775f79cbc77SKalle Valo NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | 4776f79cbc77SKalle Valo NL80211_FEATURE_STATIC_SMPS | 4777f79cbc77SKalle Valo NL80211_FEATURE_DYNAMIC_SMPS | 4778f79cbc77SKalle Valo NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; 4779f79cbc77SKalle Valo wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS); 4780f79cbc77SKalle Valo wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_BEACON_PROTECTION); 4781f79cbc77SKalle Valo wiphy_ext_feature_set(hw->wiphy, 4782f79cbc77SKalle Valo NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS); 4783f79cbc77SKalle Valo wiphy_ext_feature_set(hw->wiphy, 4784f79cbc77SKalle Valo NL80211_EXT_FEATURE_BEACON_RATE_LEGACY); 478592d13386SJaewan Kim wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER); 4786f79cbc77SKalle Valo 4787f79cbc77SKalle Valo wiphy_ext_feature_set(hw->wiphy, 4788f79cbc77SKalle Valo NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT); 4789f79cbc77SKalle Valo 4790f79cbc77SKalle Valo hw->wiphy->interface_modes = param->iftypes; 4791f79cbc77SKalle Valo 4792f79cbc77SKalle Valo /* ask mac80211 to reserve space for magic */ 4793f79cbc77SKalle Valo hw->vif_data_size = sizeof(struct hwsim_vif_priv); 4794f79cbc77SKalle Valo hw->sta_data_size = sizeof(struct hwsim_sta_priv); 4795f79cbc77SKalle Valo hw->chanctx_data_size = sizeof(struct hwsim_chanctx_priv); 4796f79cbc77SKalle Valo 4797f79cbc77SKalle Valo memcpy(data->channels_2ghz, hwsim_channels_2ghz, 4798f79cbc77SKalle Valo sizeof(hwsim_channels_2ghz)); 4799f79cbc77SKalle Valo memcpy(data->channels_5ghz, hwsim_channels_5ghz, 4800f79cbc77SKalle Valo sizeof(hwsim_channels_5ghz)); 4801f79cbc77SKalle Valo memcpy(data->channels_6ghz, hwsim_channels_6ghz, 4802f79cbc77SKalle Valo sizeof(hwsim_channels_6ghz)); 4803f79cbc77SKalle Valo memcpy(data->channels_s1g, hwsim_channels_s1g, 4804f79cbc77SKalle Valo sizeof(hwsim_channels_s1g)); 4805f79cbc77SKalle Valo memcpy(data->rates, hwsim_rates, sizeof(hwsim_rates)); 4806f79cbc77SKalle Valo 4807f79cbc77SKalle Valo for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; band++) { 4808f79cbc77SKalle Valo struct ieee80211_supported_band *sband = &data->bands[band]; 4809f79cbc77SKalle Valo 4810f79cbc77SKalle Valo sband->band = band; 4811f79cbc77SKalle Valo 4812f79cbc77SKalle Valo switch (band) { 4813f79cbc77SKalle Valo case NL80211_BAND_2GHZ: 4814f79cbc77SKalle Valo sband->channels = data->channels_2ghz; 4815f79cbc77SKalle Valo sband->n_channels = ARRAY_SIZE(hwsim_channels_2ghz); 4816f79cbc77SKalle Valo sband->bitrates = data->rates; 4817f79cbc77SKalle Valo sband->n_bitrates = ARRAY_SIZE(hwsim_rates); 4818f79cbc77SKalle Valo break; 4819f79cbc77SKalle Valo case NL80211_BAND_5GHZ: 4820f79cbc77SKalle Valo sband->channels = data->channels_5ghz; 4821f79cbc77SKalle Valo sband->n_channels = ARRAY_SIZE(hwsim_channels_5ghz); 4822f79cbc77SKalle Valo sband->bitrates = data->rates + 4; 4823f79cbc77SKalle Valo sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4; 4824f79cbc77SKalle Valo 4825f79cbc77SKalle Valo sband->vht_cap.vht_supported = true; 4826f79cbc77SKalle Valo sband->vht_cap.cap = 4827f79cbc77SKalle Valo IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | 4828f79cbc77SKalle Valo IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ | 4829f79cbc77SKalle Valo IEEE80211_VHT_CAP_RXLDPC | 4830f79cbc77SKalle Valo IEEE80211_VHT_CAP_SHORT_GI_80 | 4831f79cbc77SKalle Valo IEEE80211_VHT_CAP_SHORT_GI_160 | 4832f79cbc77SKalle Valo IEEE80211_VHT_CAP_TXSTBC | 4833f79cbc77SKalle Valo IEEE80211_VHT_CAP_RXSTBC_4 | 4834f79cbc77SKalle Valo IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; 4835f79cbc77SKalle Valo sband->vht_cap.vht_mcs.rx_mcs_map = 4836f79cbc77SKalle Valo cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | 4837f79cbc77SKalle Valo IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 | 4838f79cbc77SKalle Valo IEEE80211_VHT_MCS_SUPPORT_0_9 << 4 | 4839f79cbc77SKalle Valo IEEE80211_VHT_MCS_SUPPORT_0_9 << 6 | 4840f79cbc77SKalle Valo IEEE80211_VHT_MCS_SUPPORT_0_9 << 8 | 4841f79cbc77SKalle Valo IEEE80211_VHT_MCS_SUPPORT_0_9 << 10 | 4842f79cbc77SKalle Valo IEEE80211_VHT_MCS_SUPPORT_0_9 << 12 | 4843f79cbc77SKalle Valo IEEE80211_VHT_MCS_SUPPORT_0_9 << 14); 4844f79cbc77SKalle Valo sband->vht_cap.vht_mcs.tx_mcs_map = 4845f79cbc77SKalle Valo sband->vht_cap.vht_mcs.rx_mcs_map; 4846f79cbc77SKalle Valo break; 4847f79cbc77SKalle Valo case NL80211_BAND_6GHZ: 4848f79cbc77SKalle Valo sband->channels = data->channels_6ghz; 4849f79cbc77SKalle Valo sband->n_channels = ARRAY_SIZE(hwsim_channels_6ghz); 4850f79cbc77SKalle Valo sband->bitrates = data->rates + 4; 4851f79cbc77SKalle Valo sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4; 4852f79cbc77SKalle Valo break; 4853f79cbc77SKalle Valo case NL80211_BAND_S1GHZ: 4854f79cbc77SKalle Valo memcpy(&sband->s1g_cap, &hwsim_s1g_cap, 4855f79cbc77SKalle Valo sizeof(sband->s1g_cap)); 4856f79cbc77SKalle Valo sband->channels = data->channels_s1g; 4857f79cbc77SKalle Valo sband->n_channels = ARRAY_SIZE(hwsim_channels_s1g); 4858f79cbc77SKalle Valo break; 4859f79cbc77SKalle Valo default: 4860f79cbc77SKalle Valo continue; 4861f79cbc77SKalle Valo } 4862f79cbc77SKalle Valo 4863f79cbc77SKalle Valo if (band != NL80211_BAND_6GHZ){ 4864f79cbc77SKalle Valo sband->ht_cap.ht_supported = true; 4865f79cbc77SKalle Valo sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | 4866f79cbc77SKalle Valo IEEE80211_HT_CAP_GRN_FLD | 4867f79cbc77SKalle Valo IEEE80211_HT_CAP_SGI_20 | 4868f79cbc77SKalle Valo IEEE80211_HT_CAP_SGI_40 | 4869f79cbc77SKalle Valo IEEE80211_HT_CAP_DSSSCCK40; 4870f79cbc77SKalle Valo sband->ht_cap.ampdu_factor = 0x3; 4871f79cbc77SKalle Valo sband->ht_cap.ampdu_density = 0x6; 4872f79cbc77SKalle Valo memset(&sband->ht_cap.mcs, 0, 4873f79cbc77SKalle Valo sizeof(sband->ht_cap.mcs)); 4874f79cbc77SKalle Valo sband->ht_cap.mcs.rx_mask[0] = 0xff; 4875f79cbc77SKalle Valo sband->ht_cap.mcs.rx_mask[1] = 0xff; 4876f79cbc77SKalle Valo sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; 4877f79cbc77SKalle Valo } 4878f79cbc77SKalle Valo 4879f79cbc77SKalle Valo mac80211_hwsim_sband_capab(sband); 4880f79cbc77SKalle Valo 4881f79cbc77SKalle Valo hw->wiphy->bands[band] = sband; 4882f79cbc77SKalle Valo } 4883f79cbc77SKalle Valo 4884f79cbc77SKalle Valo /* By default all radios belong to the first group */ 4885f79cbc77SKalle Valo data->group = 1; 4886f79cbc77SKalle Valo mutex_init(&data->mutex); 4887f79cbc77SKalle Valo 4888f79cbc77SKalle Valo data->netgroup = hwsim_net_get_netgroup(net); 4889f79cbc77SKalle Valo data->wmediumd = hwsim_net_get_wmediumd(net); 4890f79cbc77SKalle Valo 4891f79cbc77SKalle Valo /* Enable frame retransmissions for lossy channels */ 4892f79cbc77SKalle Valo hw->max_rates = 4; 4893f79cbc77SKalle Valo hw->max_rate_tries = 11; 4894f79cbc77SKalle Valo 4895f79cbc77SKalle Valo hw->wiphy->vendor_commands = mac80211_hwsim_vendor_commands; 4896f79cbc77SKalle Valo hw->wiphy->n_vendor_commands = 4897f79cbc77SKalle Valo ARRAY_SIZE(mac80211_hwsim_vendor_commands); 4898f79cbc77SKalle Valo hw->wiphy->vendor_events = mac80211_hwsim_vendor_events; 4899f79cbc77SKalle Valo hw->wiphy->n_vendor_events = ARRAY_SIZE(mac80211_hwsim_vendor_events); 4900f79cbc77SKalle Valo 4901f79cbc77SKalle Valo if (param->reg_strict) 4902f79cbc77SKalle Valo hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG; 4903f79cbc77SKalle Valo if (param->regd) { 4904f79cbc77SKalle Valo data->regd = param->regd; 4905f79cbc77SKalle Valo hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; 4906f79cbc77SKalle Valo wiphy_apply_custom_regulatory(hw->wiphy, param->regd); 4907f79cbc77SKalle Valo /* give the regulatory workqueue a chance to run */ 4908f79cbc77SKalle Valo schedule_timeout_interruptible(1); 4909f79cbc77SKalle Valo } 4910f79cbc77SKalle Valo 4911f79cbc77SKalle Valo if (param->no_vif) 4912f79cbc77SKalle Valo ieee80211_hw_set(hw, NO_AUTO_VIF); 4913f79cbc77SKalle Valo 4914f79cbc77SKalle Valo wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); 4915f79cbc77SKalle Valo 4916f79cbc77SKalle Valo for (i = 0; i < ARRAY_SIZE(data->link_data); i++) { 4917f79cbc77SKalle Valo hrtimer_init(&data->link_data[i].beacon_timer, CLOCK_MONOTONIC, 4918f79cbc77SKalle Valo HRTIMER_MODE_ABS_SOFT); 4919f79cbc77SKalle Valo data->link_data[i].beacon_timer.function = 4920f79cbc77SKalle Valo mac80211_hwsim_beacon; 4921f79cbc77SKalle Valo data->link_data[i].link_id = i; 4922f79cbc77SKalle Valo } 4923f79cbc77SKalle Valo 4924f79cbc77SKalle Valo err = ieee80211_register_hw(hw); 4925f79cbc77SKalle Valo if (err < 0) { 4926f79cbc77SKalle Valo pr_debug("mac80211_hwsim: ieee80211_register_hw failed (%d)\n", 4927f79cbc77SKalle Valo err); 4928f79cbc77SKalle Valo goto failed_hw; 4929f79cbc77SKalle Valo } 4930f79cbc77SKalle Valo 4931f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "hwaddr %pM registered\n", hw->wiphy->perm_addr); 4932f79cbc77SKalle Valo 4933f79cbc77SKalle Valo if (param->reg_alpha2) { 4934f79cbc77SKalle Valo data->alpha2[0] = param->reg_alpha2[0]; 4935f79cbc77SKalle Valo data->alpha2[1] = param->reg_alpha2[1]; 4936f79cbc77SKalle Valo regulatory_hint(hw->wiphy, param->reg_alpha2); 4937f79cbc77SKalle Valo } 4938f79cbc77SKalle Valo 4939f79cbc77SKalle Valo data->debugfs = debugfs_create_dir("hwsim", hw->wiphy->debugfsdir); 4940f79cbc77SKalle Valo debugfs_create_file("ps", 0666, data->debugfs, data, &hwsim_fops_ps); 4941f79cbc77SKalle Valo debugfs_create_file("group", 0666, data->debugfs, data, 4942f79cbc77SKalle Valo &hwsim_fops_group); 4943f79cbc77SKalle Valo debugfs_create_file("rx_rssi", 0666, data->debugfs, data, 4944f79cbc77SKalle Valo &hwsim_fops_rx_rssi); 4945f79cbc77SKalle Valo if (!data->use_chanctx) 4946f79cbc77SKalle Valo debugfs_create_file("dfs_simulate_radar", 0222, 4947f79cbc77SKalle Valo data->debugfs, 4948f79cbc77SKalle Valo data, &hwsim_simulate_radar); 4949f79cbc77SKalle Valo 495092d13386SJaewan Kim if (param->pmsr_capa) { 495192d13386SJaewan Kim data->pmsr_capa = *param->pmsr_capa; 495292d13386SJaewan Kim hw->wiphy->pmsr_capa = &data->pmsr_capa; 495392d13386SJaewan Kim } 495492d13386SJaewan Kim 4955f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 4956f79cbc77SKalle Valo err = rhashtable_insert_fast(&hwsim_radios_rht, &data->rht, 4957f79cbc77SKalle Valo hwsim_rht_params); 4958f79cbc77SKalle Valo if (err < 0) { 4959f79cbc77SKalle Valo if (info) { 4960f79cbc77SKalle Valo GENL_SET_ERR_MSG(info, "perm addr already present"); 4961f79cbc77SKalle Valo NL_SET_BAD_ATTR(info->extack, 4962f79cbc77SKalle Valo info->attrs[HWSIM_ATTR_PERM_ADDR]); 4963f79cbc77SKalle Valo } 4964f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 4965f79cbc77SKalle Valo goto failed_final_insert; 4966f79cbc77SKalle Valo } 4967f79cbc77SKalle Valo 4968f79cbc77SKalle Valo list_add_tail(&data->list, &hwsim_radios); 4969f79cbc77SKalle Valo hwsim_radios_generation++; 4970f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 4971f79cbc77SKalle Valo 4972f79cbc77SKalle Valo hwsim_mcast_new_radio(idx, info, param); 4973f79cbc77SKalle Valo 4974f79cbc77SKalle Valo return idx; 4975f79cbc77SKalle Valo 4976f79cbc77SKalle Valo failed_final_insert: 4977f79cbc77SKalle Valo debugfs_remove_recursive(data->debugfs); 4978f79cbc77SKalle Valo ieee80211_unregister_hw(data->hw); 4979f79cbc77SKalle Valo failed_hw: 4980f79cbc77SKalle Valo device_release_driver(data->dev); 4981f79cbc77SKalle Valo failed_bind: 4982f79cbc77SKalle Valo device_unregister(data->dev); 4983f79cbc77SKalle Valo failed_drvdata: 4984f79cbc77SKalle Valo ieee80211_free_hw(hw); 4985f79cbc77SKalle Valo failed: 4986f79cbc77SKalle Valo return err; 4987f79cbc77SKalle Valo } 4988f79cbc77SKalle Valo 4989f79cbc77SKalle Valo static void hwsim_mcast_del_radio(int id, const char *hwname, 4990f79cbc77SKalle Valo struct genl_info *info) 4991f79cbc77SKalle Valo { 4992f79cbc77SKalle Valo struct sk_buff *skb; 4993f79cbc77SKalle Valo void *data; 4994f79cbc77SKalle Valo int ret; 4995f79cbc77SKalle Valo 4996f79cbc77SKalle Valo skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 4997f79cbc77SKalle Valo if (!skb) 4998f79cbc77SKalle Valo return; 4999f79cbc77SKalle Valo 5000f79cbc77SKalle Valo data = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, 5001f79cbc77SKalle Valo HWSIM_CMD_DEL_RADIO); 5002f79cbc77SKalle Valo if (!data) 5003f79cbc77SKalle Valo goto error; 5004f79cbc77SKalle Valo 5005f79cbc77SKalle Valo ret = nla_put_u32(skb, HWSIM_ATTR_RADIO_ID, id); 5006f79cbc77SKalle Valo if (ret < 0) 5007f79cbc77SKalle Valo goto error; 5008f79cbc77SKalle Valo 5009f79cbc77SKalle Valo ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME, strlen(hwname), 5010f79cbc77SKalle Valo hwname); 5011f79cbc77SKalle Valo if (ret < 0) 5012f79cbc77SKalle Valo goto error; 5013f79cbc77SKalle Valo 5014f79cbc77SKalle Valo genlmsg_end(skb, data); 5015f79cbc77SKalle Valo 5016f79cbc77SKalle Valo hwsim_mcast_config_msg(skb, info); 5017f79cbc77SKalle Valo 5018f79cbc77SKalle Valo return; 5019f79cbc77SKalle Valo 5020f79cbc77SKalle Valo error: 5021f79cbc77SKalle Valo nlmsg_free(skb); 5022f79cbc77SKalle Valo } 5023f79cbc77SKalle Valo 5024f79cbc77SKalle Valo static void mac80211_hwsim_del_radio(struct mac80211_hwsim_data *data, 5025f79cbc77SKalle Valo const char *hwname, 5026f79cbc77SKalle Valo struct genl_info *info) 5027f79cbc77SKalle Valo { 5028f79cbc77SKalle Valo hwsim_mcast_del_radio(data->idx, hwname, info); 5029f79cbc77SKalle Valo debugfs_remove_recursive(data->debugfs); 5030f79cbc77SKalle Valo ieee80211_unregister_hw(data->hw); 5031f79cbc77SKalle Valo device_release_driver(data->dev); 5032f79cbc77SKalle Valo device_unregister(data->dev); 5033f79cbc77SKalle Valo ieee80211_free_hw(data->hw); 5034f79cbc77SKalle Valo } 5035f79cbc77SKalle Valo 5036f79cbc77SKalle Valo static int mac80211_hwsim_get_radio(struct sk_buff *skb, 5037f79cbc77SKalle Valo struct mac80211_hwsim_data *data, 5038f79cbc77SKalle Valo u32 portid, u32 seq, 5039f79cbc77SKalle Valo struct netlink_callback *cb, int flags) 5040f79cbc77SKalle Valo { 5041f79cbc77SKalle Valo void *hdr; 5042f79cbc77SKalle Valo struct hwsim_new_radio_params param = { }; 5043f79cbc77SKalle Valo int res = -EMSGSIZE; 5044f79cbc77SKalle Valo 5045f79cbc77SKalle Valo hdr = genlmsg_put(skb, portid, seq, &hwsim_genl_family, flags, 5046f79cbc77SKalle Valo HWSIM_CMD_GET_RADIO); 5047f79cbc77SKalle Valo if (!hdr) 5048f79cbc77SKalle Valo return -EMSGSIZE; 5049f79cbc77SKalle Valo 5050f79cbc77SKalle Valo if (cb) 5051f79cbc77SKalle Valo genl_dump_check_consistent(cb, hdr); 5052f79cbc77SKalle Valo 5053f79cbc77SKalle Valo if (data->alpha2[0] && data->alpha2[1]) 5054f79cbc77SKalle Valo param.reg_alpha2 = data->alpha2; 5055f79cbc77SKalle Valo 5056f79cbc77SKalle Valo param.reg_strict = !!(data->hw->wiphy->regulatory_flags & 5057f79cbc77SKalle Valo REGULATORY_STRICT_REG); 5058f79cbc77SKalle Valo param.p2p_device = !!(data->hw->wiphy->interface_modes & 5059f79cbc77SKalle Valo BIT(NL80211_IFTYPE_P2P_DEVICE)); 5060f79cbc77SKalle Valo param.use_chanctx = data->use_chanctx; 5061f79cbc77SKalle Valo param.regd = data->regd; 5062f79cbc77SKalle Valo param.channels = data->channels; 5063f79cbc77SKalle Valo param.hwname = wiphy_name(data->hw->wiphy); 506492d13386SJaewan Kim param.pmsr_capa = &data->pmsr_capa; 5065f79cbc77SKalle Valo 5066f79cbc77SKalle Valo res = append_radio_msg(skb, data->idx, ¶m); 5067f79cbc77SKalle Valo if (res < 0) 5068f79cbc77SKalle Valo goto out_err; 5069f79cbc77SKalle Valo 5070f79cbc77SKalle Valo genlmsg_end(skb, hdr); 5071f79cbc77SKalle Valo return 0; 5072f79cbc77SKalle Valo 5073f79cbc77SKalle Valo out_err: 5074f79cbc77SKalle Valo genlmsg_cancel(skb, hdr); 5075f79cbc77SKalle Valo return res; 5076f79cbc77SKalle Valo } 5077f79cbc77SKalle Valo 5078f79cbc77SKalle Valo static void mac80211_hwsim_free(void) 5079f79cbc77SKalle Valo { 5080f79cbc77SKalle Valo struct mac80211_hwsim_data *data; 5081f79cbc77SKalle Valo 5082f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 5083f79cbc77SKalle Valo while ((data = list_first_entry_or_null(&hwsim_radios, 5084f79cbc77SKalle Valo struct mac80211_hwsim_data, 5085f79cbc77SKalle Valo list))) { 5086f79cbc77SKalle Valo list_del(&data->list); 5087f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 5088f79cbc77SKalle Valo mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy), 5089f79cbc77SKalle Valo NULL); 5090f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 5091f79cbc77SKalle Valo } 5092f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 5093f79cbc77SKalle Valo class_destroy(hwsim_class); 5094f79cbc77SKalle Valo } 5095f79cbc77SKalle Valo 5096f79cbc77SKalle Valo static const struct net_device_ops hwsim_netdev_ops = { 5097f79cbc77SKalle Valo .ndo_start_xmit = hwsim_mon_xmit, 5098f79cbc77SKalle Valo .ndo_set_mac_address = eth_mac_addr, 5099f79cbc77SKalle Valo .ndo_validate_addr = eth_validate_addr, 5100f79cbc77SKalle Valo }; 5101f79cbc77SKalle Valo 5102f79cbc77SKalle Valo static void hwsim_mon_setup(struct net_device *dev) 5103f79cbc77SKalle Valo { 5104f79cbc77SKalle Valo u8 addr[ETH_ALEN]; 5105f79cbc77SKalle Valo 5106f79cbc77SKalle Valo dev->netdev_ops = &hwsim_netdev_ops; 5107f79cbc77SKalle Valo dev->needs_free_netdev = true; 5108f79cbc77SKalle Valo ether_setup(dev); 5109f79cbc77SKalle Valo dev->priv_flags |= IFF_NO_QUEUE; 5110f79cbc77SKalle Valo dev->type = ARPHRD_IEEE80211_RADIOTAP; 5111f79cbc77SKalle Valo eth_zero_addr(addr); 5112f79cbc77SKalle Valo addr[0] = 0x12; 5113f79cbc77SKalle Valo eth_hw_addr_set(dev, addr); 5114f79cbc77SKalle Valo } 5115f79cbc77SKalle Valo 5116f79cbc77SKalle Valo static struct mac80211_hwsim_data *get_hwsim_data_ref_from_addr(const u8 *addr) 5117f79cbc77SKalle Valo { 5118f79cbc77SKalle Valo return rhashtable_lookup_fast(&hwsim_radios_rht, 5119f79cbc77SKalle Valo addr, 5120f79cbc77SKalle Valo hwsim_rht_params); 5121f79cbc77SKalle Valo } 5122f79cbc77SKalle Valo 5123f79cbc77SKalle Valo static void hwsim_register_wmediumd(struct net *net, u32 portid) 5124f79cbc77SKalle Valo { 5125f79cbc77SKalle Valo struct mac80211_hwsim_data *data; 5126f79cbc77SKalle Valo 5127f79cbc77SKalle Valo hwsim_net_set_wmediumd(net, portid); 5128f79cbc77SKalle Valo 5129f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 5130f79cbc77SKalle Valo list_for_each_entry(data, &hwsim_radios, list) { 5131f79cbc77SKalle Valo if (data->netgroup == hwsim_net_get_netgroup(net)) 5132f79cbc77SKalle Valo data->wmediumd = portid; 5133f79cbc77SKalle Valo } 5134f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 5135f79cbc77SKalle Valo } 5136f79cbc77SKalle Valo 5137f79cbc77SKalle Valo static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2, 5138f79cbc77SKalle Valo struct genl_info *info) 5139f79cbc77SKalle Valo { 5140f79cbc77SKalle Valo 5141f79cbc77SKalle Valo struct ieee80211_hdr *hdr; 5142f79cbc77SKalle Valo struct mac80211_hwsim_data *data2; 5143f79cbc77SKalle Valo struct ieee80211_tx_info *txi; 5144f79cbc77SKalle Valo struct hwsim_tx_rate *tx_attempts; 5145f79cbc77SKalle Valo u64 ret_skb_cookie; 5146f79cbc77SKalle Valo struct sk_buff *skb, *tmp; 5147f79cbc77SKalle Valo const u8 *src; 5148f79cbc77SKalle Valo unsigned int hwsim_flags; 5149f79cbc77SKalle Valo int i; 5150f79cbc77SKalle Valo unsigned long flags; 5151f79cbc77SKalle Valo bool found = false; 5152f79cbc77SKalle Valo 5153f79cbc77SKalle Valo if (!info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER] || 5154f79cbc77SKalle Valo !info->attrs[HWSIM_ATTR_FLAGS] || 5155f79cbc77SKalle Valo !info->attrs[HWSIM_ATTR_COOKIE] || 5156f79cbc77SKalle Valo !info->attrs[HWSIM_ATTR_SIGNAL] || 5157f79cbc77SKalle Valo !info->attrs[HWSIM_ATTR_TX_INFO]) 5158f79cbc77SKalle Valo goto out; 5159f79cbc77SKalle Valo 5160f79cbc77SKalle Valo src = (void *)nla_data(info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER]); 5161f79cbc77SKalle Valo hwsim_flags = nla_get_u32(info->attrs[HWSIM_ATTR_FLAGS]); 5162f79cbc77SKalle Valo ret_skb_cookie = nla_get_u64(info->attrs[HWSIM_ATTR_COOKIE]); 5163f79cbc77SKalle Valo 5164f79cbc77SKalle Valo data2 = get_hwsim_data_ref_from_addr(src); 5165f79cbc77SKalle Valo if (!data2) 5166f79cbc77SKalle Valo goto out; 5167f79cbc77SKalle Valo 5168f79cbc77SKalle Valo if (!hwsim_virtio_enabled) { 5169f79cbc77SKalle Valo if (hwsim_net_get_netgroup(genl_info_net(info)) != 5170f79cbc77SKalle Valo data2->netgroup) 5171f79cbc77SKalle Valo goto out; 5172f79cbc77SKalle Valo 5173f79cbc77SKalle Valo if (info->snd_portid != data2->wmediumd) 5174f79cbc77SKalle Valo goto out; 5175f79cbc77SKalle Valo } 5176f79cbc77SKalle Valo 5177f79cbc77SKalle Valo /* look for the skb matching the cookie passed back from user */ 5178f79cbc77SKalle Valo spin_lock_irqsave(&data2->pending.lock, flags); 5179f79cbc77SKalle Valo skb_queue_walk_safe(&data2->pending, skb, tmp) { 5180f79cbc77SKalle Valo uintptr_t skb_cookie; 5181f79cbc77SKalle Valo 5182f79cbc77SKalle Valo txi = IEEE80211_SKB_CB(skb); 5183f79cbc77SKalle Valo skb_cookie = (uintptr_t)txi->rate_driver_data[0]; 5184f79cbc77SKalle Valo 5185f79cbc77SKalle Valo if (skb_cookie == ret_skb_cookie) { 5186f79cbc77SKalle Valo __skb_unlink(skb, &data2->pending); 5187f79cbc77SKalle Valo found = true; 5188f79cbc77SKalle Valo break; 5189f79cbc77SKalle Valo } 5190f79cbc77SKalle Valo } 5191f79cbc77SKalle Valo spin_unlock_irqrestore(&data2->pending.lock, flags); 5192f79cbc77SKalle Valo 5193f79cbc77SKalle Valo /* not found */ 5194f79cbc77SKalle Valo if (!found) 5195f79cbc77SKalle Valo goto out; 5196f79cbc77SKalle Valo 5197f79cbc77SKalle Valo /* Tx info received because the frame was broadcasted on user space, 5198f79cbc77SKalle Valo so we get all the necessary info: tx attempts and skb control buff */ 5199f79cbc77SKalle Valo 5200f79cbc77SKalle Valo tx_attempts = (struct hwsim_tx_rate *)nla_data( 5201f79cbc77SKalle Valo info->attrs[HWSIM_ATTR_TX_INFO]); 5202f79cbc77SKalle Valo 5203f79cbc77SKalle Valo /* now send back TX status */ 5204f79cbc77SKalle Valo txi = IEEE80211_SKB_CB(skb); 5205f79cbc77SKalle Valo 5206f79cbc77SKalle Valo ieee80211_tx_info_clear_status(txi); 5207f79cbc77SKalle Valo 5208f79cbc77SKalle Valo for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { 5209f79cbc77SKalle Valo txi->status.rates[i].idx = tx_attempts[i].idx; 5210f79cbc77SKalle Valo txi->status.rates[i].count = tx_attempts[i].count; 5211f79cbc77SKalle Valo } 5212f79cbc77SKalle Valo 5213f79cbc77SKalle Valo txi->status.ack_signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]); 5214f79cbc77SKalle Valo 5215f79cbc77SKalle Valo if (!(hwsim_flags & HWSIM_TX_CTL_NO_ACK) && 5216f79cbc77SKalle Valo (hwsim_flags & HWSIM_TX_STAT_ACK)) { 5217f79cbc77SKalle Valo if (skb->len >= 16) { 5218f79cbc77SKalle Valo hdr = (struct ieee80211_hdr *) skb->data; 5219f79cbc77SKalle Valo mac80211_hwsim_monitor_ack(data2->channel, 5220f79cbc77SKalle Valo hdr->addr2); 5221f79cbc77SKalle Valo } 5222f79cbc77SKalle Valo txi->flags |= IEEE80211_TX_STAT_ACK; 5223f79cbc77SKalle Valo } 5224f79cbc77SKalle Valo 5225f79cbc77SKalle Valo if (hwsim_flags & HWSIM_TX_CTL_NO_ACK) 5226f79cbc77SKalle Valo txi->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; 5227f79cbc77SKalle Valo 5228f79cbc77SKalle Valo ieee80211_tx_status_irqsafe(data2->hw, skb); 5229f79cbc77SKalle Valo return 0; 5230f79cbc77SKalle Valo out: 5231f79cbc77SKalle Valo return -EINVAL; 5232f79cbc77SKalle Valo 5233f79cbc77SKalle Valo } 5234f79cbc77SKalle Valo 5235f79cbc77SKalle Valo static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, 5236f79cbc77SKalle Valo struct genl_info *info) 5237f79cbc77SKalle Valo { 5238f79cbc77SKalle Valo struct mac80211_hwsim_data *data2; 5239f79cbc77SKalle Valo struct ieee80211_rx_status rx_status; 5240f79cbc77SKalle Valo struct ieee80211_hdr *hdr; 5241f79cbc77SKalle Valo const u8 *dst; 5242f79cbc77SKalle Valo int frame_data_len; 5243f79cbc77SKalle Valo void *frame_data; 5244f79cbc77SKalle Valo struct sk_buff *skb = NULL; 5245f79cbc77SKalle Valo struct ieee80211_channel *channel = NULL; 5246f79cbc77SKalle Valo 5247f79cbc77SKalle Valo if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] || 5248f79cbc77SKalle Valo !info->attrs[HWSIM_ATTR_FRAME] || 5249f79cbc77SKalle Valo !info->attrs[HWSIM_ATTR_RX_RATE] || 5250f79cbc77SKalle Valo !info->attrs[HWSIM_ATTR_SIGNAL]) 5251f79cbc77SKalle Valo goto out; 5252f79cbc77SKalle Valo 5253f79cbc77SKalle Valo dst = (void *)nla_data(info->attrs[HWSIM_ATTR_ADDR_RECEIVER]); 5254f79cbc77SKalle Valo frame_data_len = nla_len(info->attrs[HWSIM_ATTR_FRAME]); 5255f79cbc77SKalle Valo frame_data = (void *)nla_data(info->attrs[HWSIM_ATTR_FRAME]); 5256f79cbc77SKalle Valo 5257f79cbc77SKalle Valo /* Allocate new skb here */ 5258f79cbc77SKalle Valo skb = alloc_skb(frame_data_len, GFP_KERNEL); 5259f79cbc77SKalle Valo if (skb == NULL) 5260f79cbc77SKalle Valo goto err; 5261f79cbc77SKalle Valo 5262f79cbc77SKalle Valo if (frame_data_len > IEEE80211_MAX_DATA_LEN) 5263f79cbc77SKalle Valo goto err; 5264f79cbc77SKalle Valo 5265f79cbc77SKalle Valo /* Copy the data */ 5266f79cbc77SKalle Valo skb_put_data(skb, frame_data, frame_data_len); 5267f79cbc77SKalle Valo 5268f79cbc77SKalle Valo data2 = get_hwsim_data_ref_from_addr(dst); 5269f79cbc77SKalle Valo if (!data2) 5270f79cbc77SKalle Valo goto out; 5271f79cbc77SKalle Valo 5272f79cbc77SKalle Valo if (data2->use_chanctx) { 5273f79cbc77SKalle Valo if (data2->tmp_chan) 5274f79cbc77SKalle Valo channel = data2->tmp_chan; 5275f79cbc77SKalle Valo } else { 5276f79cbc77SKalle Valo channel = data2->channel; 5277f79cbc77SKalle Valo } 5278f79cbc77SKalle Valo 5279f79cbc77SKalle Valo if (!hwsim_virtio_enabled) { 5280f79cbc77SKalle Valo if (hwsim_net_get_netgroup(genl_info_net(info)) != 5281f79cbc77SKalle Valo data2->netgroup) 5282f79cbc77SKalle Valo goto out; 5283f79cbc77SKalle Valo 5284f79cbc77SKalle Valo if (info->snd_portid != data2->wmediumd) 5285f79cbc77SKalle Valo goto out; 5286f79cbc77SKalle Valo } 5287f79cbc77SKalle Valo 5288f79cbc77SKalle Valo /* check if radio is configured properly */ 5289f79cbc77SKalle Valo 5290f79cbc77SKalle Valo if ((data2->idle && !data2->tmp_chan) || !data2->started) 5291f79cbc77SKalle Valo goto out; 5292f79cbc77SKalle Valo 5293f79cbc77SKalle Valo /* A frame is received from user space */ 5294f79cbc77SKalle Valo memset(&rx_status, 0, sizeof(rx_status)); 5295f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_FREQ]) { 5296f79cbc77SKalle Valo struct tx_iter_data iter_data = {}; 5297f79cbc77SKalle Valo 5298f79cbc77SKalle Valo /* throw away off-channel packets, but allow both the temporary 5299f79cbc77SKalle Valo * ("hw" scan/remain-on-channel), regular channels and links, 5300f79cbc77SKalle Valo * since the internal datapath also allows this 5301f79cbc77SKalle Valo */ 5302f79cbc77SKalle Valo rx_status.freq = nla_get_u32(info->attrs[HWSIM_ATTR_FREQ]); 5303f79cbc77SKalle Valo 5304f79cbc77SKalle Valo iter_data.channel = ieee80211_get_channel(data2->hw->wiphy, 5305f79cbc77SKalle Valo rx_status.freq); 5306f79cbc77SKalle Valo if (!iter_data.channel) 5307f79cbc77SKalle Valo goto out; 5308f79cbc77SKalle Valo rx_status.band = iter_data.channel->band; 5309f79cbc77SKalle Valo 5310f79cbc77SKalle Valo mutex_lock(&data2->mutex); 5311f79cbc77SKalle Valo if (!hwsim_chans_compat(iter_data.channel, channel)) { 5312f79cbc77SKalle Valo ieee80211_iterate_active_interfaces_atomic( 5313f79cbc77SKalle Valo data2->hw, IEEE80211_IFACE_ITER_NORMAL, 5314f79cbc77SKalle Valo mac80211_hwsim_tx_iter, &iter_data); 5315f79cbc77SKalle Valo if (!iter_data.receive) { 5316f79cbc77SKalle Valo mutex_unlock(&data2->mutex); 5317f79cbc77SKalle Valo goto out; 5318f79cbc77SKalle Valo } 5319f79cbc77SKalle Valo } 5320f79cbc77SKalle Valo mutex_unlock(&data2->mutex); 5321f79cbc77SKalle Valo } else if (!channel) { 5322f79cbc77SKalle Valo goto out; 5323f79cbc77SKalle Valo } else { 5324f79cbc77SKalle Valo rx_status.freq = channel->center_freq; 5325f79cbc77SKalle Valo rx_status.band = channel->band; 5326f79cbc77SKalle Valo } 5327f79cbc77SKalle Valo 5328f79cbc77SKalle Valo rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]); 5329f79cbc77SKalle Valo if (rx_status.rate_idx >= data2->hw->wiphy->bands[rx_status.band]->n_bitrates) 5330f79cbc77SKalle Valo goto out; 5331f79cbc77SKalle Valo rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]); 5332f79cbc77SKalle Valo 5333f79cbc77SKalle Valo hdr = (void *)skb->data; 5334f79cbc77SKalle Valo 5335f79cbc77SKalle Valo if (ieee80211_is_beacon(hdr->frame_control) || 5336f79cbc77SKalle Valo ieee80211_is_probe_resp(hdr->frame_control)) 5337f79cbc77SKalle Valo rx_status.boottime_ns = ktime_get_boottime_ns(); 5338f79cbc77SKalle Valo 5339f79cbc77SKalle Valo mac80211_hwsim_rx(data2, &rx_status, skb); 5340f79cbc77SKalle Valo 5341f79cbc77SKalle Valo return 0; 5342f79cbc77SKalle Valo err: 5343f79cbc77SKalle Valo pr_debug("mac80211_hwsim: error occurred in %s\n", __func__); 5344f79cbc77SKalle Valo out: 5345f79cbc77SKalle Valo dev_kfree_skb(skb); 5346f79cbc77SKalle Valo return -EINVAL; 5347f79cbc77SKalle Valo } 5348f79cbc77SKalle Valo 5349f79cbc77SKalle Valo static int hwsim_register_received_nl(struct sk_buff *skb_2, 5350f79cbc77SKalle Valo struct genl_info *info) 5351f79cbc77SKalle Valo { 5352f79cbc77SKalle Valo struct net *net = genl_info_net(info); 5353f79cbc77SKalle Valo struct mac80211_hwsim_data *data; 5354f79cbc77SKalle Valo int chans = 1; 5355f79cbc77SKalle Valo 5356f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 5357f79cbc77SKalle Valo list_for_each_entry(data, &hwsim_radios, list) 5358f79cbc77SKalle Valo chans = max(chans, data->channels); 5359f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 5360f79cbc77SKalle Valo 5361f79cbc77SKalle Valo /* In the future we should revise the userspace API and allow it 5362f79cbc77SKalle Valo * to set a flag that it does support multi-channel, then we can 5363f79cbc77SKalle Valo * let this pass conditionally on the flag. 5364f79cbc77SKalle Valo * For current userspace, prohibit it since it won't work right. 5365f79cbc77SKalle Valo */ 5366f79cbc77SKalle Valo if (chans > 1) 5367f79cbc77SKalle Valo return -EOPNOTSUPP; 5368f79cbc77SKalle Valo 5369f79cbc77SKalle Valo if (hwsim_net_get_wmediumd(net)) 5370f79cbc77SKalle Valo return -EBUSY; 5371f79cbc77SKalle Valo 5372f79cbc77SKalle Valo hwsim_register_wmediumd(net, info->snd_portid); 5373f79cbc77SKalle Valo 5374f79cbc77SKalle Valo pr_debug("mac80211_hwsim: received a REGISTER, " 5375f79cbc77SKalle Valo "switching to wmediumd mode with pid %d\n", info->snd_portid); 5376f79cbc77SKalle Valo 5377f79cbc77SKalle Valo return 0; 5378f79cbc77SKalle Valo } 5379f79cbc77SKalle Valo 5380f79cbc77SKalle Valo /* ensures ciphers only include ciphers listed in 'hwsim_ciphers' array */ 5381f79cbc77SKalle Valo static bool hwsim_known_ciphers(const u32 *ciphers, int n_ciphers) 5382f79cbc77SKalle Valo { 5383f79cbc77SKalle Valo int i; 5384f79cbc77SKalle Valo 5385f79cbc77SKalle Valo for (i = 0; i < n_ciphers; i++) { 5386f79cbc77SKalle Valo int j; 5387f79cbc77SKalle Valo int found = 0; 5388f79cbc77SKalle Valo 5389f79cbc77SKalle Valo for (j = 0; j < ARRAY_SIZE(hwsim_ciphers); j++) { 5390f79cbc77SKalle Valo if (ciphers[i] == hwsim_ciphers[j]) { 5391f79cbc77SKalle Valo found = 1; 5392f79cbc77SKalle Valo break; 5393f79cbc77SKalle Valo } 5394f79cbc77SKalle Valo } 5395f79cbc77SKalle Valo 5396f79cbc77SKalle Valo if (!found) 5397f79cbc77SKalle Valo return false; 5398f79cbc77SKalle Valo } 5399f79cbc77SKalle Valo 5400f79cbc77SKalle Valo return true; 5401f79cbc77SKalle Valo } 5402f79cbc77SKalle Valo 540392d13386SJaewan Kim static int parse_ftm_capa(const struct nlattr *ftm_capa, struct cfg80211_pmsr_capabilities *out, 540492d13386SJaewan Kim struct genl_info *info) 540592d13386SJaewan Kim { 540692d13386SJaewan Kim struct nlattr *tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX + 1]; 540792d13386SJaewan Kim int ret; 540892d13386SJaewan Kim 540992d13386SJaewan Kim ret = nla_parse_nested(tb, NL80211_PMSR_FTM_CAPA_ATTR_MAX, ftm_capa, hwsim_ftm_capa_policy, 541092d13386SJaewan Kim NULL); 541192d13386SJaewan Kim if (ret) { 541292d13386SJaewan Kim NL_SET_ERR_MSG_ATTR(info->extack, ftm_capa, "malformed FTM capability"); 541392d13386SJaewan Kim return -EINVAL; 541492d13386SJaewan Kim } 541592d13386SJaewan Kim 541692d13386SJaewan Kim out->ftm.supported = 1; 541792d13386SJaewan Kim if (tb[NL80211_PMSR_FTM_CAPA_ATTR_PREAMBLES]) 541892d13386SJaewan Kim out->ftm.preambles = nla_get_u32(tb[NL80211_PMSR_FTM_CAPA_ATTR_PREAMBLES]); 541992d13386SJaewan Kim if (tb[NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS]) 542092d13386SJaewan Kim out->ftm.bandwidths = nla_get_u32(tb[NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS]); 542192d13386SJaewan Kim if (tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT]) 542292d13386SJaewan Kim out->ftm.max_bursts_exponent = 542392d13386SJaewan Kim nla_get_u8(tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT]); 542492d13386SJaewan Kim if (tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST]) 542592d13386SJaewan Kim out->ftm.max_ftms_per_burst = 542692d13386SJaewan Kim nla_get_u8(tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST]); 542792d13386SJaewan Kim out->ftm.asap = !!tb[NL80211_PMSR_FTM_CAPA_ATTR_ASAP]; 542892d13386SJaewan Kim out->ftm.non_asap = !!tb[NL80211_PMSR_FTM_CAPA_ATTR_NON_ASAP]; 542992d13386SJaewan Kim out->ftm.request_lci = !!tb[NL80211_PMSR_FTM_CAPA_ATTR_REQ_LCI]; 543092d13386SJaewan Kim out->ftm.request_civicloc = !!tb[NL80211_PMSR_FTM_CAPA_ATTR_REQ_CIVICLOC]; 543192d13386SJaewan Kim out->ftm.trigger_based = !!tb[NL80211_PMSR_FTM_CAPA_ATTR_TRIGGER_BASED]; 543292d13386SJaewan Kim out->ftm.non_trigger_based = !!tb[NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED]; 543392d13386SJaewan Kim 543492d13386SJaewan Kim return 0; 543592d13386SJaewan Kim } 543692d13386SJaewan Kim 543792d13386SJaewan Kim static int parse_pmsr_capa(const struct nlattr *pmsr_capa, struct cfg80211_pmsr_capabilities *out, 543892d13386SJaewan Kim struct genl_info *info) 543992d13386SJaewan Kim { 544092d13386SJaewan Kim struct nlattr *tb[NL80211_PMSR_ATTR_MAX + 1]; 544192d13386SJaewan Kim struct nlattr *nla; 544292d13386SJaewan Kim int size; 544392d13386SJaewan Kim int ret; 544492d13386SJaewan Kim 544592d13386SJaewan Kim ret = nla_parse_nested(tb, NL80211_PMSR_ATTR_MAX, pmsr_capa, hwsim_pmsr_capa_policy, NULL); 544692d13386SJaewan Kim if (ret) { 544792d13386SJaewan Kim NL_SET_ERR_MSG_ATTR(info->extack, pmsr_capa, "malformed PMSR capability"); 544892d13386SJaewan Kim return -EINVAL; 544992d13386SJaewan Kim } 545092d13386SJaewan Kim 545192d13386SJaewan Kim if (tb[NL80211_PMSR_ATTR_MAX_PEERS]) 545292d13386SJaewan Kim out->max_peers = nla_get_u32(tb[NL80211_PMSR_ATTR_MAX_PEERS]); 545392d13386SJaewan Kim out->report_ap_tsf = !!tb[NL80211_PMSR_ATTR_REPORT_AP_TSF]; 545492d13386SJaewan Kim out->randomize_mac_addr = !!tb[NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR]; 545592d13386SJaewan Kim 545692d13386SJaewan Kim if (!tb[NL80211_PMSR_ATTR_TYPE_CAPA]) { 545792d13386SJaewan Kim NL_SET_ERR_MSG_ATTR(info->extack, tb[NL80211_PMSR_ATTR_TYPE_CAPA], 545892d13386SJaewan Kim "malformed PMSR type"); 545992d13386SJaewan Kim return -EINVAL; 546092d13386SJaewan Kim } 546192d13386SJaewan Kim 546292d13386SJaewan Kim nla_for_each_nested(nla, tb[NL80211_PMSR_ATTR_TYPE_CAPA], size) { 546392d13386SJaewan Kim switch (nla_type(nla)) { 546492d13386SJaewan Kim case NL80211_PMSR_TYPE_FTM: 546592d13386SJaewan Kim parse_ftm_capa(nla, out, info); 546692d13386SJaewan Kim break; 546792d13386SJaewan Kim default: 546892d13386SJaewan Kim NL_SET_ERR_MSG_ATTR(info->extack, nla, "unsupported measurement type"); 546992d13386SJaewan Kim return -EINVAL; 547092d13386SJaewan Kim } 547192d13386SJaewan Kim } 547292d13386SJaewan Kim 547392d13386SJaewan Kim return 0; 547492d13386SJaewan Kim } 547592d13386SJaewan Kim 5476f79cbc77SKalle Valo static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info) 5477f79cbc77SKalle Valo { 5478f79cbc77SKalle Valo struct hwsim_new_radio_params param = { 0 }; 5479f79cbc77SKalle Valo const char *hwname = NULL; 5480f79cbc77SKalle Valo int ret; 5481f79cbc77SKalle Valo 5482f79cbc77SKalle Valo param.reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG]; 5483f79cbc77SKalle Valo param.p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE]; 5484f79cbc77SKalle Valo param.channels = channels; 5485f79cbc77SKalle Valo param.destroy_on_close = 5486f79cbc77SKalle Valo info->attrs[HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE]; 5487f79cbc77SKalle Valo 5488f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_CHANNELS]) 5489f79cbc77SKalle Valo param.channels = nla_get_u32(info->attrs[HWSIM_ATTR_CHANNELS]); 5490f79cbc77SKalle Valo 5491f79cbc77SKalle Valo if (param.channels < 1) { 5492f79cbc77SKalle Valo GENL_SET_ERR_MSG(info, "must have at least one channel"); 5493f79cbc77SKalle Valo return -EINVAL; 5494f79cbc77SKalle Valo } 5495f79cbc77SKalle Valo 5496f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_NO_VIF]) 5497f79cbc77SKalle Valo param.no_vif = true; 5498f79cbc77SKalle Valo 5499f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_USE_CHANCTX]) 5500f79cbc77SKalle Valo param.use_chanctx = true; 5501f79cbc77SKalle Valo else 5502f79cbc77SKalle Valo param.use_chanctx = (param.channels > 1); 5503f79cbc77SKalle Valo 5504f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]) 5505f79cbc77SKalle Valo param.reg_alpha2 = 5506f79cbc77SKalle Valo nla_data(info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]); 5507f79cbc77SKalle Valo 5508f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]) { 5509f79cbc77SKalle Valo u32 idx = nla_get_u32(info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]); 5510f79cbc77SKalle Valo 5511f79cbc77SKalle Valo if (idx >= ARRAY_SIZE(hwsim_world_regdom_custom)) 5512f79cbc77SKalle Valo return -EINVAL; 5513f79cbc77SKalle Valo 5514f79cbc77SKalle Valo idx = array_index_nospec(idx, 5515f79cbc77SKalle Valo ARRAY_SIZE(hwsim_world_regdom_custom)); 5516f79cbc77SKalle Valo param.regd = hwsim_world_regdom_custom[idx]; 5517f79cbc77SKalle Valo } 5518f79cbc77SKalle Valo 5519f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_PERM_ADDR]) { 5520f79cbc77SKalle Valo if (!is_valid_ether_addr( 5521f79cbc77SKalle Valo nla_data(info->attrs[HWSIM_ATTR_PERM_ADDR]))) { 5522f79cbc77SKalle Valo GENL_SET_ERR_MSG(info,"MAC is no valid source addr"); 5523f79cbc77SKalle Valo NL_SET_BAD_ATTR(info->extack, 5524f79cbc77SKalle Valo info->attrs[HWSIM_ATTR_PERM_ADDR]); 5525f79cbc77SKalle Valo return -EINVAL; 5526f79cbc77SKalle Valo } 5527f79cbc77SKalle Valo 5528f79cbc77SKalle Valo param.perm_addr = nla_data(info->attrs[HWSIM_ATTR_PERM_ADDR]); 5529f79cbc77SKalle Valo } 5530f79cbc77SKalle Valo 5531f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_IFTYPE_SUPPORT]) { 5532f79cbc77SKalle Valo param.iftypes = 5533f79cbc77SKalle Valo nla_get_u32(info->attrs[HWSIM_ATTR_IFTYPE_SUPPORT]); 5534f79cbc77SKalle Valo 5535f79cbc77SKalle Valo if (param.iftypes & ~HWSIM_IFTYPE_SUPPORT_MASK) { 5536f79cbc77SKalle Valo NL_SET_ERR_MSG_ATTR(info->extack, 5537f79cbc77SKalle Valo info->attrs[HWSIM_ATTR_IFTYPE_SUPPORT], 5538f79cbc77SKalle Valo "cannot support more iftypes than kernel"); 5539f79cbc77SKalle Valo return -EINVAL; 5540f79cbc77SKalle Valo } 5541f79cbc77SKalle Valo } else { 5542f79cbc77SKalle Valo param.iftypes = HWSIM_IFTYPE_SUPPORT_MASK; 5543f79cbc77SKalle Valo } 5544f79cbc77SKalle Valo 5545f79cbc77SKalle Valo /* ensure both flag and iftype support is honored */ 5546f79cbc77SKalle Valo if (param.p2p_device || 5547f79cbc77SKalle Valo param.iftypes & BIT(NL80211_IFTYPE_P2P_DEVICE)) { 5548f79cbc77SKalle Valo param.iftypes |= BIT(NL80211_IFTYPE_P2P_DEVICE); 5549f79cbc77SKalle Valo param.p2p_device = true; 5550f79cbc77SKalle Valo } 5551f79cbc77SKalle Valo 5552f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_CIPHER_SUPPORT]) { 5553f79cbc77SKalle Valo u32 len = nla_len(info->attrs[HWSIM_ATTR_CIPHER_SUPPORT]); 5554f79cbc77SKalle Valo 5555f79cbc77SKalle Valo param.ciphers = 5556f79cbc77SKalle Valo nla_data(info->attrs[HWSIM_ATTR_CIPHER_SUPPORT]); 5557f79cbc77SKalle Valo 5558f79cbc77SKalle Valo if (len % sizeof(u32)) { 5559f79cbc77SKalle Valo NL_SET_ERR_MSG_ATTR(info->extack, 5560f79cbc77SKalle Valo info->attrs[HWSIM_ATTR_CIPHER_SUPPORT], 5561f79cbc77SKalle Valo "bad cipher list length"); 5562f79cbc77SKalle Valo return -EINVAL; 5563f79cbc77SKalle Valo } 5564f79cbc77SKalle Valo 5565f79cbc77SKalle Valo param.n_ciphers = len / sizeof(u32); 5566f79cbc77SKalle Valo 5567f79cbc77SKalle Valo if (param.n_ciphers > ARRAY_SIZE(hwsim_ciphers)) { 5568f79cbc77SKalle Valo NL_SET_ERR_MSG_ATTR(info->extack, 5569f79cbc77SKalle Valo info->attrs[HWSIM_ATTR_CIPHER_SUPPORT], 5570f79cbc77SKalle Valo "too many ciphers specified"); 5571f79cbc77SKalle Valo return -EINVAL; 5572f79cbc77SKalle Valo } 5573f79cbc77SKalle Valo 5574f79cbc77SKalle Valo if (!hwsim_known_ciphers(param.ciphers, param.n_ciphers)) { 5575f79cbc77SKalle Valo NL_SET_ERR_MSG_ATTR(info->extack, 5576f79cbc77SKalle Valo info->attrs[HWSIM_ATTR_CIPHER_SUPPORT], 5577f79cbc77SKalle Valo "unsupported ciphers specified"); 5578f79cbc77SKalle Valo return -EINVAL; 5579f79cbc77SKalle Valo } 5580f79cbc77SKalle Valo } 5581f79cbc77SKalle Valo 5582f79cbc77SKalle Valo param.mlo = info->attrs[HWSIM_ATTR_MLO_SUPPORT]; 5583f79cbc77SKalle Valo 5584f79cbc77SKalle Valo if (param.mlo) 5585f79cbc77SKalle Valo param.use_chanctx = true; 5586f79cbc77SKalle Valo 5587f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_RADIO_NAME]) { 5588f79cbc77SKalle Valo hwname = kstrndup((char *)nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME]), 5589f79cbc77SKalle Valo nla_len(info->attrs[HWSIM_ATTR_RADIO_NAME]), 5590f79cbc77SKalle Valo GFP_KERNEL); 5591f79cbc77SKalle Valo if (!hwname) 5592f79cbc77SKalle Valo return -ENOMEM; 5593f79cbc77SKalle Valo param.hwname = hwname; 5594f79cbc77SKalle Valo } 5595f79cbc77SKalle Valo 559692d13386SJaewan Kim if (info->attrs[HWSIM_ATTR_PMSR_SUPPORT]) { 559792d13386SJaewan Kim struct cfg80211_pmsr_capabilities *pmsr_capa; 559892d13386SJaewan Kim 559992d13386SJaewan Kim pmsr_capa = kmalloc(sizeof(*pmsr_capa), GFP_KERNEL); 560092d13386SJaewan Kim if (!pmsr_capa) { 560192d13386SJaewan Kim ret = -ENOMEM; 560292d13386SJaewan Kim goto out_free; 560392d13386SJaewan Kim } 560492d13386SJaewan Kim ret = parse_pmsr_capa(info->attrs[HWSIM_ATTR_PMSR_SUPPORT], pmsr_capa, info); 560592d13386SJaewan Kim if (ret) 560692d13386SJaewan Kim goto out_free; 560792d13386SJaewan Kim param.pmsr_capa = pmsr_capa; 560892d13386SJaewan Kim } 560992d13386SJaewan Kim 5610f79cbc77SKalle Valo ret = mac80211_hwsim_new_radio(info, ¶m); 561192d13386SJaewan Kim 561292d13386SJaewan Kim out_free: 5613f79cbc77SKalle Valo kfree(hwname); 561492d13386SJaewan Kim kfree(param.pmsr_capa); 5615f79cbc77SKalle Valo return ret; 5616f79cbc77SKalle Valo } 5617f79cbc77SKalle Valo 5618f79cbc77SKalle Valo static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info) 5619f79cbc77SKalle Valo { 5620f79cbc77SKalle Valo struct mac80211_hwsim_data *data; 5621f79cbc77SKalle Valo s64 idx = -1; 5622f79cbc77SKalle Valo const char *hwname = NULL; 5623f79cbc77SKalle Valo 5624f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_RADIO_ID]) { 5625f79cbc77SKalle Valo idx = nla_get_u32(info->attrs[HWSIM_ATTR_RADIO_ID]); 5626f79cbc77SKalle Valo } else if (info->attrs[HWSIM_ATTR_RADIO_NAME]) { 5627f79cbc77SKalle Valo hwname = kstrndup((char *)nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME]), 5628f79cbc77SKalle Valo nla_len(info->attrs[HWSIM_ATTR_RADIO_NAME]), 5629f79cbc77SKalle Valo GFP_KERNEL); 5630f79cbc77SKalle Valo if (!hwname) 5631f79cbc77SKalle Valo return -ENOMEM; 5632f79cbc77SKalle Valo } else 5633f79cbc77SKalle Valo return -EINVAL; 5634f79cbc77SKalle Valo 5635f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 5636f79cbc77SKalle Valo list_for_each_entry(data, &hwsim_radios, list) { 5637f79cbc77SKalle Valo if (idx >= 0) { 5638f79cbc77SKalle Valo if (data->idx != idx) 5639f79cbc77SKalle Valo continue; 5640f79cbc77SKalle Valo } else { 5641f79cbc77SKalle Valo if (!hwname || 5642f79cbc77SKalle Valo strcmp(hwname, wiphy_name(data->hw->wiphy))) 5643f79cbc77SKalle Valo continue; 5644f79cbc77SKalle Valo } 5645f79cbc77SKalle Valo 5646f79cbc77SKalle Valo if (!net_eq(wiphy_net(data->hw->wiphy), genl_info_net(info))) 5647f79cbc77SKalle Valo continue; 5648f79cbc77SKalle Valo 5649f79cbc77SKalle Valo list_del(&data->list); 5650f79cbc77SKalle Valo rhashtable_remove_fast(&hwsim_radios_rht, &data->rht, 5651f79cbc77SKalle Valo hwsim_rht_params); 5652f79cbc77SKalle Valo hwsim_radios_generation++; 5653f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 5654f79cbc77SKalle Valo mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy), 5655f79cbc77SKalle Valo info); 5656f79cbc77SKalle Valo kfree(hwname); 5657f79cbc77SKalle Valo return 0; 5658f79cbc77SKalle Valo } 5659f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 5660f79cbc77SKalle Valo 5661f79cbc77SKalle Valo kfree(hwname); 5662f79cbc77SKalle Valo return -ENODEV; 5663f79cbc77SKalle Valo } 5664f79cbc77SKalle Valo 5665f79cbc77SKalle Valo static int hwsim_get_radio_nl(struct sk_buff *msg, struct genl_info *info) 5666f79cbc77SKalle Valo { 5667f79cbc77SKalle Valo struct mac80211_hwsim_data *data; 5668f79cbc77SKalle Valo struct sk_buff *skb; 5669f79cbc77SKalle Valo int idx, res = -ENODEV; 5670f79cbc77SKalle Valo 5671f79cbc77SKalle Valo if (!info->attrs[HWSIM_ATTR_RADIO_ID]) 5672f79cbc77SKalle Valo return -EINVAL; 5673f79cbc77SKalle Valo idx = nla_get_u32(info->attrs[HWSIM_ATTR_RADIO_ID]); 5674f79cbc77SKalle Valo 5675f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 5676f79cbc77SKalle Valo list_for_each_entry(data, &hwsim_radios, list) { 5677f79cbc77SKalle Valo if (data->idx != idx) 5678f79cbc77SKalle Valo continue; 5679f79cbc77SKalle Valo 5680f79cbc77SKalle Valo if (!net_eq(wiphy_net(data->hw->wiphy), genl_info_net(info))) 5681f79cbc77SKalle Valo continue; 5682f79cbc77SKalle Valo 5683f79cbc77SKalle Valo skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); 5684f79cbc77SKalle Valo if (!skb) { 5685f79cbc77SKalle Valo res = -ENOMEM; 5686f79cbc77SKalle Valo goto out_err; 5687f79cbc77SKalle Valo } 5688f79cbc77SKalle Valo 5689f79cbc77SKalle Valo res = mac80211_hwsim_get_radio(skb, data, info->snd_portid, 5690f79cbc77SKalle Valo info->snd_seq, NULL, 0); 5691f79cbc77SKalle Valo if (res < 0) { 5692f79cbc77SKalle Valo nlmsg_free(skb); 5693f79cbc77SKalle Valo goto out_err; 5694f79cbc77SKalle Valo } 5695f79cbc77SKalle Valo 5696f79cbc77SKalle Valo res = genlmsg_reply(skb, info); 5697f79cbc77SKalle Valo break; 5698f79cbc77SKalle Valo } 5699f79cbc77SKalle Valo 5700f79cbc77SKalle Valo out_err: 5701f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 5702f79cbc77SKalle Valo 5703f79cbc77SKalle Valo return res; 5704f79cbc77SKalle Valo } 5705f79cbc77SKalle Valo 5706f79cbc77SKalle Valo static int hwsim_dump_radio_nl(struct sk_buff *skb, 5707f79cbc77SKalle Valo struct netlink_callback *cb) 5708f79cbc77SKalle Valo { 5709f79cbc77SKalle Valo int last_idx = cb->args[0] - 1; 5710f79cbc77SKalle Valo struct mac80211_hwsim_data *data = NULL; 5711f79cbc77SKalle Valo int res = 0; 5712f79cbc77SKalle Valo void *hdr; 5713f79cbc77SKalle Valo 5714f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 5715f79cbc77SKalle Valo cb->seq = hwsim_radios_generation; 5716f79cbc77SKalle Valo 5717f79cbc77SKalle Valo if (last_idx >= hwsim_radio_idx-1) 5718f79cbc77SKalle Valo goto done; 5719f79cbc77SKalle Valo 5720f79cbc77SKalle Valo list_for_each_entry(data, &hwsim_radios, list) { 5721f79cbc77SKalle Valo if (data->idx <= last_idx) 5722f79cbc77SKalle Valo continue; 5723f79cbc77SKalle Valo 5724f79cbc77SKalle Valo if (!net_eq(wiphy_net(data->hw->wiphy), sock_net(skb->sk))) 5725f79cbc77SKalle Valo continue; 5726f79cbc77SKalle Valo 5727f79cbc77SKalle Valo res = mac80211_hwsim_get_radio(skb, data, 5728f79cbc77SKalle Valo NETLINK_CB(cb->skb).portid, 5729f79cbc77SKalle Valo cb->nlh->nlmsg_seq, cb, 5730f79cbc77SKalle Valo NLM_F_MULTI); 5731f79cbc77SKalle Valo if (res < 0) 5732f79cbc77SKalle Valo break; 5733f79cbc77SKalle Valo 5734f79cbc77SKalle Valo last_idx = data->idx; 5735f79cbc77SKalle Valo } 5736f79cbc77SKalle Valo 5737f79cbc77SKalle Valo cb->args[0] = last_idx + 1; 5738f79cbc77SKalle Valo 5739f79cbc77SKalle Valo /* list changed, but no new element sent, set interrupted flag */ 5740f79cbc77SKalle Valo if (skb->len == 0 && cb->prev_seq && cb->seq != cb->prev_seq) { 5741f79cbc77SKalle Valo hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, 5742f79cbc77SKalle Valo cb->nlh->nlmsg_seq, &hwsim_genl_family, 5743f79cbc77SKalle Valo NLM_F_MULTI, HWSIM_CMD_GET_RADIO); 5744f79cbc77SKalle Valo if (hdr) { 5745f79cbc77SKalle Valo genl_dump_check_consistent(cb, hdr); 5746f79cbc77SKalle Valo genlmsg_end(skb, hdr); 5747f79cbc77SKalle Valo } else { 5748f79cbc77SKalle Valo res = -EMSGSIZE; 5749f79cbc77SKalle Valo } 5750f79cbc77SKalle Valo } 5751f79cbc77SKalle Valo 5752f79cbc77SKalle Valo done: 5753f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 5754f79cbc77SKalle Valo return res ?: skb->len; 5755f79cbc77SKalle Valo } 5756f79cbc77SKalle Valo 5757f79cbc77SKalle Valo /* Generic Netlink operations array */ 5758f79cbc77SKalle Valo static const struct genl_small_ops hwsim_ops[] = { 5759f79cbc77SKalle Valo { 5760f79cbc77SKalle Valo .cmd = HWSIM_CMD_REGISTER, 5761f79cbc77SKalle Valo .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 5762f79cbc77SKalle Valo .doit = hwsim_register_received_nl, 5763f79cbc77SKalle Valo .flags = GENL_UNS_ADMIN_PERM, 5764f79cbc77SKalle Valo }, 5765f79cbc77SKalle Valo { 5766f79cbc77SKalle Valo .cmd = HWSIM_CMD_FRAME, 5767f79cbc77SKalle Valo .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 5768f79cbc77SKalle Valo .doit = hwsim_cloned_frame_received_nl, 5769f79cbc77SKalle Valo }, 5770f79cbc77SKalle Valo { 5771f79cbc77SKalle Valo .cmd = HWSIM_CMD_TX_INFO_FRAME, 5772f79cbc77SKalle Valo .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 5773f79cbc77SKalle Valo .doit = hwsim_tx_info_frame_received_nl, 5774f79cbc77SKalle Valo }, 5775f79cbc77SKalle Valo { 5776f79cbc77SKalle Valo .cmd = HWSIM_CMD_NEW_RADIO, 5777f79cbc77SKalle Valo .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 5778f79cbc77SKalle Valo .doit = hwsim_new_radio_nl, 5779f79cbc77SKalle Valo .flags = GENL_UNS_ADMIN_PERM, 5780f79cbc77SKalle Valo }, 5781f79cbc77SKalle Valo { 5782f79cbc77SKalle Valo .cmd = HWSIM_CMD_DEL_RADIO, 5783f79cbc77SKalle Valo .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 5784f79cbc77SKalle Valo .doit = hwsim_del_radio_nl, 5785f79cbc77SKalle Valo .flags = GENL_UNS_ADMIN_PERM, 5786f79cbc77SKalle Valo }, 5787f79cbc77SKalle Valo { 5788f79cbc77SKalle Valo .cmd = HWSIM_CMD_GET_RADIO, 5789f79cbc77SKalle Valo .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 5790f79cbc77SKalle Valo .doit = hwsim_get_radio_nl, 5791f79cbc77SKalle Valo .dumpit = hwsim_dump_radio_nl, 5792f79cbc77SKalle Valo }, 5793f79cbc77SKalle Valo }; 5794f79cbc77SKalle Valo 5795f79cbc77SKalle Valo static struct genl_family hwsim_genl_family __ro_after_init = { 5796f79cbc77SKalle Valo .name = "MAC80211_HWSIM", 5797f79cbc77SKalle Valo .version = 1, 5798f79cbc77SKalle Valo .maxattr = HWSIM_ATTR_MAX, 5799f79cbc77SKalle Valo .policy = hwsim_genl_policy, 5800f79cbc77SKalle Valo .netnsok = true, 5801f79cbc77SKalle Valo .module = THIS_MODULE, 5802f79cbc77SKalle Valo .small_ops = hwsim_ops, 5803f79cbc77SKalle Valo .n_small_ops = ARRAY_SIZE(hwsim_ops), 5804f79cbc77SKalle Valo .resv_start_op = HWSIM_CMD_DEL_MAC_ADDR + 1, 5805f79cbc77SKalle Valo .mcgrps = hwsim_mcgrps, 5806f79cbc77SKalle Valo .n_mcgrps = ARRAY_SIZE(hwsim_mcgrps), 5807f79cbc77SKalle Valo }; 5808f79cbc77SKalle Valo 5809f79cbc77SKalle Valo static void remove_user_radios(u32 portid) 5810f79cbc77SKalle Valo { 5811f79cbc77SKalle Valo struct mac80211_hwsim_data *entry, *tmp; 5812f79cbc77SKalle Valo LIST_HEAD(list); 5813f79cbc77SKalle Valo 5814f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 5815f79cbc77SKalle Valo list_for_each_entry_safe(entry, tmp, &hwsim_radios, list) { 5816f79cbc77SKalle Valo if (entry->destroy_on_close && entry->portid == portid) { 5817f79cbc77SKalle Valo list_move(&entry->list, &list); 5818f79cbc77SKalle Valo rhashtable_remove_fast(&hwsim_radios_rht, &entry->rht, 5819f79cbc77SKalle Valo hwsim_rht_params); 5820f79cbc77SKalle Valo hwsim_radios_generation++; 5821f79cbc77SKalle Valo } 5822f79cbc77SKalle Valo } 5823f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 5824f79cbc77SKalle Valo 5825f79cbc77SKalle Valo list_for_each_entry_safe(entry, tmp, &list, list) { 5826f79cbc77SKalle Valo list_del(&entry->list); 5827f79cbc77SKalle Valo mac80211_hwsim_del_radio(entry, wiphy_name(entry->hw->wiphy), 5828f79cbc77SKalle Valo NULL); 5829f79cbc77SKalle Valo } 5830f79cbc77SKalle Valo } 5831f79cbc77SKalle Valo 5832f79cbc77SKalle Valo static int mac80211_hwsim_netlink_notify(struct notifier_block *nb, 5833f79cbc77SKalle Valo unsigned long state, 5834f79cbc77SKalle Valo void *_notify) 5835f79cbc77SKalle Valo { 5836f79cbc77SKalle Valo struct netlink_notify *notify = _notify; 5837f79cbc77SKalle Valo 5838f79cbc77SKalle Valo if (state != NETLINK_URELEASE) 5839f79cbc77SKalle Valo return NOTIFY_DONE; 5840f79cbc77SKalle Valo 5841f79cbc77SKalle Valo remove_user_radios(notify->portid); 5842f79cbc77SKalle Valo 5843f79cbc77SKalle Valo if (notify->portid == hwsim_net_get_wmediumd(notify->net)) { 5844f79cbc77SKalle Valo printk(KERN_INFO "mac80211_hwsim: wmediumd released netlink" 5845f79cbc77SKalle Valo " socket, switching to perfect channel medium\n"); 5846f79cbc77SKalle Valo hwsim_register_wmediumd(notify->net, 0); 5847f79cbc77SKalle Valo } 5848f79cbc77SKalle Valo return NOTIFY_DONE; 5849f79cbc77SKalle Valo 5850f79cbc77SKalle Valo } 5851f79cbc77SKalle Valo 5852f79cbc77SKalle Valo static struct notifier_block hwsim_netlink_notifier = { 5853f79cbc77SKalle Valo .notifier_call = mac80211_hwsim_netlink_notify, 5854f79cbc77SKalle Valo }; 5855f79cbc77SKalle Valo 5856f79cbc77SKalle Valo static int __init hwsim_init_netlink(void) 5857f79cbc77SKalle Valo { 5858f79cbc77SKalle Valo int rc; 5859f79cbc77SKalle Valo 5860f79cbc77SKalle Valo printk(KERN_INFO "mac80211_hwsim: initializing netlink\n"); 5861f79cbc77SKalle Valo 5862f79cbc77SKalle Valo rc = genl_register_family(&hwsim_genl_family); 5863f79cbc77SKalle Valo if (rc) 5864f79cbc77SKalle Valo goto failure; 5865f79cbc77SKalle Valo 5866f79cbc77SKalle Valo rc = netlink_register_notifier(&hwsim_netlink_notifier); 5867f79cbc77SKalle Valo if (rc) { 5868f79cbc77SKalle Valo genl_unregister_family(&hwsim_genl_family); 5869f79cbc77SKalle Valo goto failure; 5870f79cbc77SKalle Valo } 5871f79cbc77SKalle Valo 5872f79cbc77SKalle Valo return 0; 5873f79cbc77SKalle Valo 5874f79cbc77SKalle Valo failure: 5875f79cbc77SKalle Valo pr_debug("mac80211_hwsim: error occurred in %s\n", __func__); 5876f79cbc77SKalle Valo return -EINVAL; 5877f79cbc77SKalle Valo } 5878f79cbc77SKalle Valo 5879f79cbc77SKalle Valo static __net_init int hwsim_init_net(struct net *net) 5880f79cbc77SKalle Valo { 5881f79cbc77SKalle Valo return hwsim_net_set_netgroup(net); 5882f79cbc77SKalle Valo } 5883f79cbc77SKalle Valo 5884f79cbc77SKalle Valo static void __net_exit hwsim_exit_net(struct net *net) 5885f79cbc77SKalle Valo { 5886f79cbc77SKalle Valo struct mac80211_hwsim_data *data, *tmp; 5887f79cbc77SKalle Valo LIST_HEAD(list); 5888f79cbc77SKalle Valo 5889f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 5890f79cbc77SKalle Valo list_for_each_entry_safe(data, tmp, &hwsim_radios, list) { 5891f79cbc77SKalle Valo if (!net_eq(wiphy_net(data->hw->wiphy), net)) 5892f79cbc77SKalle Valo continue; 5893f79cbc77SKalle Valo 5894f79cbc77SKalle Valo /* Radios created in init_net are returned to init_net. */ 5895f79cbc77SKalle Valo if (data->netgroup == hwsim_net_get_netgroup(&init_net)) 5896f79cbc77SKalle Valo continue; 5897f79cbc77SKalle Valo 5898f79cbc77SKalle Valo list_move(&data->list, &list); 5899f79cbc77SKalle Valo rhashtable_remove_fast(&hwsim_radios_rht, &data->rht, 5900f79cbc77SKalle Valo hwsim_rht_params); 5901f79cbc77SKalle Valo hwsim_radios_generation++; 5902f79cbc77SKalle Valo } 5903f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 5904f79cbc77SKalle Valo 5905f79cbc77SKalle Valo list_for_each_entry_safe(data, tmp, &list, list) { 5906f79cbc77SKalle Valo list_del(&data->list); 5907f79cbc77SKalle Valo mac80211_hwsim_del_radio(data, 5908f79cbc77SKalle Valo wiphy_name(data->hw->wiphy), 5909f79cbc77SKalle Valo NULL); 5910f79cbc77SKalle Valo } 5911f79cbc77SKalle Valo 5912f79cbc77SKalle Valo ida_free(&hwsim_netgroup_ida, hwsim_net_get_netgroup(net)); 5913f79cbc77SKalle Valo } 5914f79cbc77SKalle Valo 5915f79cbc77SKalle Valo static struct pernet_operations hwsim_net_ops = { 5916f79cbc77SKalle Valo .init = hwsim_init_net, 5917f79cbc77SKalle Valo .exit = hwsim_exit_net, 5918f79cbc77SKalle Valo .id = &hwsim_net_id, 5919f79cbc77SKalle Valo .size = sizeof(struct hwsim_net), 5920f79cbc77SKalle Valo }; 5921f79cbc77SKalle Valo 5922f79cbc77SKalle Valo static void hwsim_exit_netlink(void) 5923f79cbc77SKalle Valo { 5924f79cbc77SKalle Valo /* unregister the notifier */ 5925f79cbc77SKalle Valo netlink_unregister_notifier(&hwsim_netlink_notifier); 5926f79cbc77SKalle Valo /* unregister the family */ 5927f79cbc77SKalle Valo genl_unregister_family(&hwsim_genl_family); 5928f79cbc77SKalle Valo } 5929f79cbc77SKalle Valo 5930f79cbc77SKalle Valo #if IS_REACHABLE(CONFIG_VIRTIO) 5931f79cbc77SKalle Valo static void hwsim_virtio_tx_done(struct virtqueue *vq) 5932f79cbc77SKalle Valo { 5933f79cbc77SKalle Valo unsigned int len; 5934f79cbc77SKalle Valo struct sk_buff *skb; 5935f79cbc77SKalle Valo unsigned long flags; 5936f79cbc77SKalle Valo 5937f79cbc77SKalle Valo spin_lock_irqsave(&hwsim_virtio_lock, flags); 5938f79cbc77SKalle Valo while ((skb = virtqueue_get_buf(vq, &len))) 5939f79cbc77SKalle Valo nlmsg_free(skb); 5940f79cbc77SKalle Valo spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 5941f79cbc77SKalle Valo } 5942f79cbc77SKalle Valo 5943f79cbc77SKalle Valo static int hwsim_virtio_handle_cmd(struct sk_buff *skb) 5944f79cbc77SKalle Valo { 5945f79cbc77SKalle Valo struct nlmsghdr *nlh; 5946f79cbc77SKalle Valo struct genlmsghdr *gnlh; 5947f79cbc77SKalle Valo struct nlattr *tb[HWSIM_ATTR_MAX + 1]; 5948f79cbc77SKalle Valo struct genl_info info = {}; 5949f79cbc77SKalle Valo int err; 5950f79cbc77SKalle Valo 5951f79cbc77SKalle Valo nlh = nlmsg_hdr(skb); 5952f79cbc77SKalle Valo gnlh = nlmsg_data(nlh); 5953f79cbc77SKalle Valo 5954f79cbc77SKalle Valo if (skb->len < nlh->nlmsg_len) 5955f79cbc77SKalle Valo return -EINVAL; 5956f79cbc77SKalle Valo 5957f79cbc77SKalle Valo err = genlmsg_parse(nlh, &hwsim_genl_family, tb, HWSIM_ATTR_MAX, 5958f79cbc77SKalle Valo hwsim_genl_policy, NULL); 5959f79cbc77SKalle Valo if (err) { 5960f79cbc77SKalle Valo pr_err_ratelimited("hwsim: genlmsg_parse returned %d\n", err); 5961f79cbc77SKalle Valo return err; 5962f79cbc77SKalle Valo } 5963f79cbc77SKalle Valo 5964f79cbc77SKalle Valo info.attrs = tb; 5965f79cbc77SKalle Valo 5966f79cbc77SKalle Valo switch (gnlh->cmd) { 5967f79cbc77SKalle Valo case HWSIM_CMD_FRAME: 5968f79cbc77SKalle Valo hwsim_cloned_frame_received_nl(skb, &info); 5969f79cbc77SKalle Valo break; 5970f79cbc77SKalle Valo case HWSIM_CMD_TX_INFO_FRAME: 5971f79cbc77SKalle Valo hwsim_tx_info_frame_received_nl(skb, &info); 5972f79cbc77SKalle Valo break; 5973f79cbc77SKalle Valo default: 5974f79cbc77SKalle Valo pr_err_ratelimited("hwsim: invalid cmd: %d\n", gnlh->cmd); 5975f79cbc77SKalle Valo return -EPROTO; 5976f79cbc77SKalle Valo } 5977f79cbc77SKalle Valo return 0; 5978f79cbc77SKalle Valo } 5979f79cbc77SKalle Valo 5980f79cbc77SKalle Valo static void hwsim_virtio_rx_work(struct work_struct *work) 5981f79cbc77SKalle Valo { 5982f79cbc77SKalle Valo struct virtqueue *vq; 5983f79cbc77SKalle Valo unsigned int len; 5984f79cbc77SKalle Valo struct sk_buff *skb; 5985f79cbc77SKalle Valo struct scatterlist sg[1]; 5986f79cbc77SKalle Valo int err; 5987f79cbc77SKalle Valo unsigned long flags; 5988f79cbc77SKalle Valo 5989f79cbc77SKalle Valo spin_lock_irqsave(&hwsim_virtio_lock, flags); 5990f79cbc77SKalle Valo if (!hwsim_virtio_enabled) 5991f79cbc77SKalle Valo goto out_unlock; 5992f79cbc77SKalle Valo 5993f79cbc77SKalle Valo skb = virtqueue_get_buf(hwsim_vqs[HWSIM_VQ_RX], &len); 5994f79cbc77SKalle Valo if (!skb) 5995f79cbc77SKalle Valo goto out_unlock; 5996f79cbc77SKalle Valo spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 5997f79cbc77SKalle Valo 5998f79cbc77SKalle Valo skb->data = skb->head; 5999f79cbc77SKalle Valo skb_reset_tail_pointer(skb); 6000f79cbc77SKalle Valo skb_put(skb, len); 6001f79cbc77SKalle Valo hwsim_virtio_handle_cmd(skb); 6002f79cbc77SKalle Valo 6003f79cbc77SKalle Valo spin_lock_irqsave(&hwsim_virtio_lock, flags); 6004f79cbc77SKalle Valo if (!hwsim_virtio_enabled) { 6005f79cbc77SKalle Valo nlmsg_free(skb); 6006f79cbc77SKalle Valo goto out_unlock; 6007f79cbc77SKalle Valo } 6008f79cbc77SKalle Valo vq = hwsim_vqs[HWSIM_VQ_RX]; 6009f79cbc77SKalle Valo sg_init_one(sg, skb->head, skb_end_offset(skb)); 6010f79cbc77SKalle Valo err = virtqueue_add_inbuf(vq, sg, 1, skb, GFP_ATOMIC); 6011f79cbc77SKalle Valo if (WARN(err, "virtqueue_add_inbuf returned %d\n", err)) 6012f79cbc77SKalle Valo nlmsg_free(skb); 6013f79cbc77SKalle Valo else 6014f79cbc77SKalle Valo virtqueue_kick(vq); 6015f79cbc77SKalle Valo schedule_work(&hwsim_virtio_rx); 6016f79cbc77SKalle Valo 6017f79cbc77SKalle Valo out_unlock: 6018f79cbc77SKalle Valo spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 6019f79cbc77SKalle Valo } 6020f79cbc77SKalle Valo 6021f79cbc77SKalle Valo static void hwsim_virtio_rx_done(struct virtqueue *vq) 6022f79cbc77SKalle Valo { 6023f79cbc77SKalle Valo schedule_work(&hwsim_virtio_rx); 6024f79cbc77SKalle Valo } 6025f79cbc77SKalle Valo 6026f79cbc77SKalle Valo static int init_vqs(struct virtio_device *vdev) 6027f79cbc77SKalle Valo { 6028f79cbc77SKalle Valo vq_callback_t *callbacks[HWSIM_NUM_VQS] = { 6029f79cbc77SKalle Valo [HWSIM_VQ_TX] = hwsim_virtio_tx_done, 6030f79cbc77SKalle Valo [HWSIM_VQ_RX] = hwsim_virtio_rx_done, 6031f79cbc77SKalle Valo }; 6032f79cbc77SKalle Valo const char *names[HWSIM_NUM_VQS] = { 6033f79cbc77SKalle Valo [HWSIM_VQ_TX] = "tx", 6034f79cbc77SKalle Valo [HWSIM_VQ_RX] = "rx", 6035f79cbc77SKalle Valo }; 6036f79cbc77SKalle Valo 6037f79cbc77SKalle Valo return virtio_find_vqs(vdev, HWSIM_NUM_VQS, 6038f79cbc77SKalle Valo hwsim_vqs, callbacks, names, NULL); 6039f79cbc77SKalle Valo } 6040f79cbc77SKalle Valo 6041f79cbc77SKalle Valo static int fill_vq(struct virtqueue *vq) 6042f79cbc77SKalle Valo { 6043f79cbc77SKalle Valo int i, err; 6044f79cbc77SKalle Valo struct sk_buff *skb; 6045f79cbc77SKalle Valo struct scatterlist sg[1]; 6046f79cbc77SKalle Valo 6047f79cbc77SKalle Valo for (i = 0; i < virtqueue_get_vring_size(vq); i++) { 6048f79cbc77SKalle Valo skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 6049f79cbc77SKalle Valo if (!skb) 6050f79cbc77SKalle Valo return -ENOMEM; 6051f79cbc77SKalle Valo 6052f79cbc77SKalle Valo sg_init_one(sg, skb->head, skb_end_offset(skb)); 6053f79cbc77SKalle Valo err = virtqueue_add_inbuf(vq, sg, 1, skb, GFP_KERNEL); 6054f79cbc77SKalle Valo if (err) { 6055f79cbc77SKalle Valo nlmsg_free(skb); 6056f79cbc77SKalle Valo return err; 6057f79cbc77SKalle Valo } 6058f79cbc77SKalle Valo } 6059f79cbc77SKalle Valo virtqueue_kick(vq); 6060f79cbc77SKalle Valo return 0; 6061f79cbc77SKalle Valo } 6062f79cbc77SKalle Valo 6063f79cbc77SKalle Valo static void remove_vqs(struct virtio_device *vdev) 6064f79cbc77SKalle Valo { 6065f79cbc77SKalle Valo int i; 6066f79cbc77SKalle Valo 6067f79cbc77SKalle Valo virtio_reset_device(vdev); 6068f79cbc77SKalle Valo 6069f79cbc77SKalle Valo for (i = 0; i < ARRAY_SIZE(hwsim_vqs); i++) { 6070f79cbc77SKalle Valo struct virtqueue *vq = hwsim_vqs[i]; 6071f79cbc77SKalle Valo struct sk_buff *skb; 6072f79cbc77SKalle Valo 6073f79cbc77SKalle Valo while ((skb = virtqueue_detach_unused_buf(vq))) 6074f79cbc77SKalle Valo nlmsg_free(skb); 6075f79cbc77SKalle Valo } 6076f79cbc77SKalle Valo 6077f79cbc77SKalle Valo vdev->config->del_vqs(vdev); 6078f79cbc77SKalle Valo } 6079f79cbc77SKalle Valo 6080f79cbc77SKalle Valo static int hwsim_virtio_probe(struct virtio_device *vdev) 6081f79cbc77SKalle Valo { 6082f79cbc77SKalle Valo int err; 6083f79cbc77SKalle Valo unsigned long flags; 6084f79cbc77SKalle Valo 6085f79cbc77SKalle Valo spin_lock_irqsave(&hwsim_virtio_lock, flags); 6086f79cbc77SKalle Valo if (hwsim_virtio_enabled) { 6087f79cbc77SKalle Valo spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 6088f79cbc77SKalle Valo return -EEXIST; 6089f79cbc77SKalle Valo } 6090f79cbc77SKalle Valo spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 6091f79cbc77SKalle Valo 6092f79cbc77SKalle Valo err = init_vqs(vdev); 6093f79cbc77SKalle Valo if (err) 6094f79cbc77SKalle Valo return err; 6095f79cbc77SKalle Valo 6096f79cbc77SKalle Valo virtio_device_ready(vdev); 6097f79cbc77SKalle Valo 6098f79cbc77SKalle Valo err = fill_vq(hwsim_vqs[HWSIM_VQ_RX]); 6099f79cbc77SKalle Valo if (err) 6100f79cbc77SKalle Valo goto out_remove; 6101f79cbc77SKalle Valo 6102f79cbc77SKalle Valo spin_lock_irqsave(&hwsim_virtio_lock, flags); 6103f79cbc77SKalle Valo hwsim_virtio_enabled = true; 6104f79cbc77SKalle Valo spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 6105f79cbc77SKalle Valo 6106f79cbc77SKalle Valo schedule_work(&hwsim_virtio_rx); 6107f79cbc77SKalle Valo return 0; 6108f79cbc77SKalle Valo 6109f79cbc77SKalle Valo out_remove: 6110f79cbc77SKalle Valo remove_vqs(vdev); 6111f79cbc77SKalle Valo return err; 6112f79cbc77SKalle Valo } 6113f79cbc77SKalle Valo 6114f79cbc77SKalle Valo static void hwsim_virtio_remove(struct virtio_device *vdev) 6115f79cbc77SKalle Valo { 6116f79cbc77SKalle Valo hwsim_virtio_enabled = false; 6117f79cbc77SKalle Valo 6118f79cbc77SKalle Valo cancel_work_sync(&hwsim_virtio_rx); 6119f79cbc77SKalle Valo 6120f79cbc77SKalle Valo remove_vqs(vdev); 6121f79cbc77SKalle Valo } 6122f79cbc77SKalle Valo 6123f79cbc77SKalle Valo /* MAC80211_HWSIM virtio device id table */ 6124f79cbc77SKalle Valo static const struct virtio_device_id id_table[] = { 6125f79cbc77SKalle Valo { VIRTIO_ID_MAC80211_HWSIM, VIRTIO_DEV_ANY_ID }, 6126f79cbc77SKalle Valo { 0 } 6127f79cbc77SKalle Valo }; 6128f79cbc77SKalle Valo MODULE_DEVICE_TABLE(virtio, id_table); 6129f79cbc77SKalle Valo 6130f79cbc77SKalle Valo static struct virtio_driver virtio_hwsim = { 6131f79cbc77SKalle Valo .driver.name = KBUILD_MODNAME, 6132f79cbc77SKalle Valo .driver.owner = THIS_MODULE, 6133f79cbc77SKalle Valo .id_table = id_table, 6134f79cbc77SKalle Valo .probe = hwsim_virtio_probe, 6135f79cbc77SKalle Valo .remove = hwsim_virtio_remove, 6136f79cbc77SKalle Valo }; 6137f79cbc77SKalle Valo 6138f79cbc77SKalle Valo static int hwsim_register_virtio_driver(void) 6139f79cbc77SKalle Valo { 6140f79cbc77SKalle Valo return register_virtio_driver(&virtio_hwsim); 6141f79cbc77SKalle Valo } 6142f79cbc77SKalle Valo 6143f79cbc77SKalle Valo static void hwsim_unregister_virtio_driver(void) 6144f79cbc77SKalle Valo { 6145f79cbc77SKalle Valo unregister_virtio_driver(&virtio_hwsim); 6146f79cbc77SKalle Valo } 6147f79cbc77SKalle Valo #else 6148f79cbc77SKalle Valo static inline int hwsim_register_virtio_driver(void) 6149f79cbc77SKalle Valo { 6150f79cbc77SKalle Valo return 0; 6151f79cbc77SKalle Valo } 6152f79cbc77SKalle Valo 6153f79cbc77SKalle Valo static inline void hwsim_unregister_virtio_driver(void) 6154f79cbc77SKalle Valo { 6155f79cbc77SKalle Valo } 6156f79cbc77SKalle Valo #endif 6157f79cbc77SKalle Valo 6158f79cbc77SKalle Valo static int __init init_mac80211_hwsim(void) 6159f79cbc77SKalle Valo { 6160f79cbc77SKalle Valo int i, err; 6161f79cbc77SKalle Valo 6162f79cbc77SKalle Valo if (radios < 0 || radios > 100) 6163f79cbc77SKalle Valo return -EINVAL; 6164f79cbc77SKalle Valo 6165f79cbc77SKalle Valo if (channels < 1) 6166f79cbc77SKalle Valo return -EINVAL; 6167f79cbc77SKalle Valo 6168f79cbc77SKalle Valo err = rhashtable_init(&hwsim_radios_rht, &hwsim_rht_params); 6169f79cbc77SKalle Valo if (err) 6170f79cbc77SKalle Valo return err; 6171f79cbc77SKalle Valo 6172f79cbc77SKalle Valo err = register_pernet_device(&hwsim_net_ops); 6173f79cbc77SKalle Valo if (err) 6174f79cbc77SKalle Valo goto out_free_rht; 6175f79cbc77SKalle Valo 6176f79cbc77SKalle Valo err = platform_driver_register(&mac80211_hwsim_driver); 6177f79cbc77SKalle Valo if (err) 6178f79cbc77SKalle Valo goto out_unregister_pernet; 6179f79cbc77SKalle Valo 6180f79cbc77SKalle Valo err = hwsim_init_netlink(); 6181f79cbc77SKalle Valo if (err) 6182f79cbc77SKalle Valo goto out_unregister_driver; 6183f79cbc77SKalle Valo 6184f79cbc77SKalle Valo err = hwsim_register_virtio_driver(); 6185f79cbc77SKalle Valo if (err) 6186f79cbc77SKalle Valo goto out_exit_netlink; 6187f79cbc77SKalle Valo 6188f79cbc77SKalle Valo hwsim_class = class_create(THIS_MODULE, "mac80211_hwsim"); 6189f79cbc77SKalle Valo if (IS_ERR(hwsim_class)) { 6190f79cbc77SKalle Valo err = PTR_ERR(hwsim_class); 6191f79cbc77SKalle Valo goto out_exit_virtio; 6192f79cbc77SKalle Valo } 6193f79cbc77SKalle Valo 6194f79cbc77SKalle Valo hwsim_init_s1g_channels(hwsim_channels_s1g); 6195f79cbc77SKalle Valo 6196f79cbc77SKalle Valo for (i = 0; i < radios; i++) { 6197f79cbc77SKalle Valo struct hwsim_new_radio_params param = { 0 }; 6198f79cbc77SKalle Valo 6199f79cbc77SKalle Valo param.channels = channels; 6200f79cbc77SKalle Valo 6201f79cbc77SKalle Valo switch (regtest) { 6202f79cbc77SKalle Valo case HWSIM_REGTEST_DIFF_COUNTRY: 6203f79cbc77SKalle Valo if (i < ARRAY_SIZE(hwsim_alpha2s)) 6204f79cbc77SKalle Valo param.reg_alpha2 = hwsim_alpha2s[i]; 6205f79cbc77SKalle Valo break; 6206f79cbc77SKalle Valo case HWSIM_REGTEST_DRIVER_REG_FOLLOW: 6207f79cbc77SKalle Valo if (!i) 6208f79cbc77SKalle Valo param.reg_alpha2 = hwsim_alpha2s[0]; 6209f79cbc77SKalle Valo break; 6210f79cbc77SKalle Valo case HWSIM_REGTEST_STRICT_ALL: 6211f79cbc77SKalle Valo param.reg_strict = true; 6212f79cbc77SKalle Valo fallthrough; 6213f79cbc77SKalle Valo case HWSIM_REGTEST_DRIVER_REG_ALL: 6214f79cbc77SKalle Valo param.reg_alpha2 = hwsim_alpha2s[0]; 6215f79cbc77SKalle Valo break; 6216f79cbc77SKalle Valo case HWSIM_REGTEST_WORLD_ROAM: 6217f79cbc77SKalle Valo if (i == 0) 6218f79cbc77SKalle Valo param.regd = &hwsim_world_regdom_custom_01; 6219f79cbc77SKalle Valo break; 6220f79cbc77SKalle Valo case HWSIM_REGTEST_CUSTOM_WORLD: 6221f79cbc77SKalle Valo param.regd = &hwsim_world_regdom_custom_01; 6222f79cbc77SKalle Valo break; 6223f79cbc77SKalle Valo case HWSIM_REGTEST_CUSTOM_WORLD_2: 6224f79cbc77SKalle Valo if (i == 0) 6225f79cbc77SKalle Valo param.regd = &hwsim_world_regdom_custom_01; 6226f79cbc77SKalle Valo else if (i == 1) 6227f79cbc77SKalle Valo param.regd = &hwsim_world_regdom_custom_02; 6228f79cbc77SKalle Valo break; 6229f79cbc77SKalle Valo case HWSIM_REGTEST_STRICT_FOLLOW: 6230f79cbc77SKalle Valo if (i == 0) { 6231f79cbc77SKalle Valo param.reg_strict = true; 6232f79cbc77SKalle Valo param.reg_alpha2 = hwsim_alpha2s[0]; 6233f79cbc77SKalle Valo } 6234f79cbc77SKalle Valo break; 6235f79cbc77SKalle Valo case HWSIM_REGTEST_STRICT_AND_DRIVER_REG: 6236f79cbc77SKalle Valo if (i == 0) { 6237f79cbc77SKalle Valo param.reg_strict = true; 6238f79cbc77SKalle Valo param.reg_alpha2 = hwsim_alpha2s[0]; 6239f79cbc77SKalle Valo } else if (i == 1) { 6240f79cbc77SKalle Valo param.reg_alpha2 = hwsim_alpha2s[1]; 6241f79cbc77SKalle Valo } 6242f79cbc77SKalle Valo break; 6243f79cbc77SKalle Valo case HWSIM_REGTEST_ALL: 6244f79cbc77SKalle Valo switch (i) { 6245f79cbc77SKalle Valo case 0: 6246f79cbc77SKalle Valo param.regd = &hwsim_world_regdom_custom_01; 6247f79cbc77SKalle Valo break; 6248f79cbc77SKalle Valo case 1: 6249f79cbc77SKalle Valo param.regd = &hwsim_world_regdom_custom_02; 6250f79cbc77SKalle Valo break; 6251f79cbc77SKalle Valo case 2: 6252f79cbc77SKalle Valo param.reg_alpha2 = hwsim_alpha2s[0]; 6253f79cbc77SKalle Valo break; 6254f79cbc77SKalle Valo case 3: 6255f79cbc77SKalle Valo param.reg_alpha2 = hwsim_alpha2s[1]; 6256f79cbc77SKalle Valo break; 6257f79cbc77SKalle Valo case 4: 6258f79cbc77SKalle Valo param.reg_strict = true; 6259f79cbc77SKalle Valo param.reg_alpha2 = hwsim_alpha2s[2]; 6260f79cbc77SKalle Valo break; 6261f79cbc77SKalle Valo } 6262f79cbc77SKalle Valo break; 6263f79cbc77SKalle Valo default: 6264f79cbc77SKalle Valo break; 6265f79cbc77SKalle Valo } 6266f79cbc77SKalle Valo 6267f79cbc77SKalle Valo param.p2p_device = support_p2p_device; 6268f79cbc77SKalle Valo param.mlo = mlo; 6269f79cbc77SKalle Valo param.use_chanctx = channels > 1 || mlo; 6270f79cbc77SKalle Valo param.iftypes = HWSIM_IFTYPE_SUPPORT_MASK; 6271f79cbc77SKalle Valo if (param.p2p_device) 6272f79cbc77SKalle Valo param.iftypes |= BIT(NL80211_IFTYPE_P2P_DEVICE); 6273f79cbc77SKalle Valo 6274f79cbc77SKalle Valo err = mac80211_hwsim_new_radio(NULL, ¶m); 6275f79cbc77SKalle Valo if (err < 0) 6276f79cbc77SKalle Valo goto out_free_radios; 6277f79cbc77SKalle Valo } 6278f79cbc77SKalle Valo 6279f79cbc77SKalle Valo hwsim_mon = alloc_netdev(0, "hwsim%d", NET_NAME_UNKNOWN, 6280f79cbc77SKalle Valo hwsim_mon_setup); 6281f79cbc77SKalle Valo if (hwsim_mon == NULL) { 6282f79cbc77SKalle Valo err = -ENOMEM; 6283f79cbc77SKalle Valo goto out_free_radios; 6284f79cbc77SKalle Valo } 6285f79cbc77SKalle Valo 6286f79cbc77SKalle Valo rtnl_lock(); 6287f79cbc77SKalle Valo err = dev_alloc_name(hwsim_mon, hwsim_mon->name); 6288f79cbc77SKalle Valo if (err < 0) { 6289f79cbc77SKalle Valo rtnl_unlock(); 6290f79cbc77SKalle Valo goto out_free_mon; 6291f79cbc77SKalle Valo } 6292f79cbc77SKalle Valo 6293f79cbc77SKalle Valo err = register_netdevice(hwsim_mon); 6294f79cbc77SKalle Valo if (err < 0) { 6295f79cbc77SKalle Valo rtnl_unlock(); 6296f79cbc77SKalle Valo goto out_free_mon; 6297f79cbc77SKalle Valo } 6298f79cbc77SKalle Valo rtnl_unlock(); 6299f79cbc77SKalle Valo 6300f79cbc77SKalle Valo return 0; 6301f79cbc77SKalle Valo 6302f79cbc77SKalle Valo out_free_mon: 6303f79cbc77SKalle Valo free_netdev(hwsim_mon); 6304f79cbc77SKalle Valo out_free_radios: 6305f79cbc77SKalle Valo mac80211_hwsim_free(); 6306f79cbc77SKalle Valo out_exit_virtio: 6307f79cbc77SKalle Valo hwsim_unregister_virtio_driver(); 6308f79cbc77SKalle Valo out_exit_netlink: 6309f79cbc77SKalle Valo hwsim_exit_netlink(); 6310f79cbc77SKalle Valo out_unregister_driver: 6311f79cbc77SKalle Valo platform_driver_unregister(&mac80211_hwsim_driver); 6312f79cbc77SKalle Valo out_unregister_pernet: 6313f79cbc77SKalle Valo unregister_pernet_device(&hwsim_net_ops); 6314f79cbc77SKalle Valo out_free_rht: 6315f79cbc77SKalle Valo rhashtable_destroy(&hwsim_radios_rht); 6316f79cbc77SKalle Valo return err; 6317f79cbc77SKalle Valo } 6318f79cbc77SKalle Valo module_init(init_mac80211_hwsim); 6319f79cbc77SKalle Valo 6320f79cbc77SKalle Valo static void __exit exit_mac80211_hwsim(void) 6321f79cbc77SKalle Valo { 6322f79cbc77SKalle Valo pr_debug("mac80211_hwsim: unregister radios\n"); 6323f79cbc77SKalle Valo 6324f79cbc77SKalle Valo hwsim_unregister_virtio_driver(); 6325f79cbc77SKalle Valo hwsim_exit_netlink(); 6326f79cbc77SKalle Valo 6327f79cbc77SKalle Valo mac80211_hwsim_free(); 6328f79cbc77SKalle Valo 6329f79cbc77SKalle Valo rhashtable_destroy(&hwsim_radios_rht); 6330f79cbc77SKalle Valo unregister_netdev(hwsim_mon); 6331f79cbc77SKalle Valo platform_driver_unregister(&mac80211_hwsim_driver); 6332f79cbc77SKalle Valo unregister_pernet_device(&hwsim_net_ops); 6333f79cbc77SKalle Valo } 6334f79cbc77SKalle Valo module_exit(exit_mac80211_hwsim); 6335