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 70cc80943SIlan Peer * Copyright (C) 2018 - 2023 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 */ 5851b78dd34SJohannes Berg nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_TEST, val + 1); 5861b78dd34SJohannes Berg 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 7552af3b2a6SJaewan Kim static struct mac80211_hwsim_data *get_hwsim_data_ref_from_addr(const u8 *addr) 7562af3b2a6SJaewan Kim { 7572af3b2a6SJaewan Kim return rhashtable_lookup_fast(&hwsim_radios_rht, addr, hwsim_rht_params); 7582af3b2a6SJaewan Kim } 7592af3b2a6SJaewan Kim 760f79cbc77SKalle Valo /* MAC80211_HWSIM netlink family */ 761f79cbc77SKalle Valo static struct genl_family hwsim_genl_family; 762f79cbc77SKalle Valo 763f79cbc77SKalle Valo enum hwsim_multicast_groups { 764f79cbc77SKalle Valo HWSIM_MCGRP_CONFIG, 765f79cbc77SKalle Valo }; 766f79cbc77SKalle Valo 767f79cbc77SKalle Valo static const struct genl_multicast_group hwsim_mcgrps[] = { 768f79cbc77SKalle Valo [HWSIM_MCGRP_CONFIG] = { .name = "config", }, 769f79cbc77SKalle Valo }; 770f79cbc77SKalle Valo 771f79cbc77SKalle Valo /* MAC80211_HWSIM netlink policy */ 772f79cbc77SKalle Valo 77392d13386SJaewan Kim static const struct nla_policy 7742af3b2a6SJaewan Kim hwsim_rate_info_policy[HWSIM_RATE_INFO_ATTR_MAX + 1] = { 7752af3b2a6SJaewan Kim [HWSIM_RATE_INFO_ATTR_FLAGS] = { .type = NLA_U8 }, 7762af3b2a6SJaewan Kim [HWSIM_RATE_INFO_ATTR_MCS] = { .type = NLA_U8 }, 7772af3b2a6SJaewan Kim [HWSIM_RATE_INFO_ATTR_LEGACY] = { .type = NLA_U16 }, 7782af3b2a6SJaewan Kim [HWSIM_RATE_INFO_ATTR_NSS] = { .type = NLA_U8 }, 7792af3b2a6SJaewan Kim [HWSIM_RATE_INFO_ATTR_BW] = { .type = NLA_U8 }, 7802af3b2a6SJaewan Kim [HWSIM_RATE_INFO_ATTR_HE_GI] = { .type = NLA_U8 }, 7812af3b2a6SJaewan Kim [HWSIM_RATE_INFO_ATTR_HE_DCM] = { .type = NLA_U8 }, 7822af3b2a6SJaewan Kim [HWSIM_RATE_INFO_ATTR_HE_RU_ALLOC] = { .type = NLA_U8 }, 7832af3b2a6SJaewan Kim [HWSIM_RATE_INFO_ATTR_N_BOUNDED_CH] = { .type = NLA_U8 }, 7842af3b2a6SJaewan Kim [HWSIM_RATE_INFO_ATTR_EHT_GI] = { .type = NLA_U8 }, 7852af3b2a6SJaewan Kim [HWSIM_RATE_INFO_ATTR_EHT_RU_ALLOC] = { .type = NLA_U8 }, 7862af3b2a6SJaewan Kim }; 7872af3b2a6SJaewan Kim 7882af3b2a6SJaewan Kim static const struct nla_policy 7892af3b2a6SJaewan Kim hwsim_ftm_result_policy[NL80211_PMSR_FTM_RESP_ATTR_MAX + 1] = { 7902af3b2a6SJaewan Kim [NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON] = { .type = NLA_U32 }, 7912af3b2a6SJaewan Kim [NL80211_PMSR_FTM_RESP_ATTR_BURST_INDEX] = { .type = NLA_U16 }, 7922af3b2a6SJaewan Kim [NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_ATTEMPTS] = { .type = NLA_U32 }, 7932af3b2a6SJaewan Kim [NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_SUCCESSES] = { .type = NLA_U32 }, 7942af3b2a6SJaewan Kim [NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME] = { .type = NLA_U8 }, 7952af3b2a6SJaewan Kim [NL80211_PMSR_FTM_RESP_ATTR_NUM_BURSTS_EXP] = { .type = NLA_U8 }, 7962af3b2a6SJaewan Kim [NL80211_PMSR_FTM_RESP_ATTR_BURST_DURATION] = { .type = NLA_U8 }, 7972af3b2a6SJaewan Kim [NL80211_PMSR_FTM_RESP_ATTR_FTMS_PER_BURST] = { .type = NLA_U8 }, 7982af3b2a6SJaewan Kim [NL80211_PMSR_FTM_RESP_ATTR_RSSI_AVG] = { .type = NLA_U32 }, 7992af3b2a6SJaewan Kim [NL80211_PMSR_FTM_RESP_ATTR_RSSI_SPREAD] = { .type = NLA_U32 }, 8002af3b2a6SJaewan Kim [NL80211_PMSR_FTM_RESP_ATTR_TX_RATE] = NLA_POLICY_NESTED(hwsim_rate_info_policy), 8012af3b2a6SJaewan Kim [NL80211_PMSR_FTM_RESP_ATTR_RX_RATE] = NLA_POLICY_NESTED(hwsim_rate_info_policy), 8022af3b2a6SJaewan Kim [NL80211_PMSR_FTM_RESP_ATTR_RTT_AVG] = { .type = NLA_U64 }, 8032af3b2a6SJaewan Kim [NL80211_PMSR_FTM_RESP_ATTR_RTT_VARIANCE] = { .type = NLA_U64 }, 8042af3b2a6SJaewan Kim [NL80211_PMSR_FTM_RESP_ATTR_RTT_SPREAD] = { .type = NLA_U64 }, 8052af3b2a6SJaewan Kim [NL80211_PMSR_FTM_RESP_ATTR_DIST_AVG] = { .type = NLA_U64 }, 8062af3b2a6SJaewan Kim [NL80211_PMSR_FTM_RESP_ATTR_DIST_VARIANCE] = { .type = NLA_U64 }, 8072af3b2a6SJaewan Kim [NL80211_PMSR_FTM_RESP_ATTR_DIST_SPREAD] = { .type = NLA_U64 }, 8082af3b2a6SJaewan Kim [NL80211_PMSR_FTM_RESP_ATTR_LCI] = { .type = NLA_STRING }, 8092af3b2a6SJaewan Kim [NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC] = { .type = NLA_STRING }, 8102af3b2a6SJaewan Kim }; 8112af3b2a6SJaewan Kim 8122af3b2a6SJaewan Kim static const struct nla_policy 8132af3b2a6SJaewan Kim hwsim_pmsr_resp_type_policy[NL80211_PMSR_TYPE_MAX + 1] = { 8142af3b2a6SJaewan Kim [NL80211_PMSR_TYPE_FTM] = NLA_POLICY_NESTED(hwsim_ftm_result_policy), 8152af3b2a6SJaewan Kim }; 8162af3b2a6SJaewan Kim 8172af3b2a6SJaewan Kim static const struct nla_policy 8182af3b2a6SJaewan Kim hwsim_pmsr_resp_policy[NL80211_PMSR_RESP_ATTR_MAX + 1] = { 8192af3b2a6SJaewan Kim [NL80211_PMSR_RESP_ATTR_STATUS] = { .type = NLA_U32 }, 8202af3b2a6SJaewan Kim [NL80211_PMSR_RESP_ATTR_HOST_TIME] = { .type = NLA_U64 }, 8212af3b2a6SJaewan Kim [NL80211_PMSR_RESP_ATTR_AP_TSF] = { .type = NLA_U64 }, 8222af3b2a6SJaewan Kim [NL80211_PMSR_RESP_ATTR_FINAL] = { .type = NLA_FLAG }, 8232af3b2a6SJaewan Kim [NL80211_PMSR_RESP_ATTR_DATA] = NLA_POLICY_NESTED(hwsim_pmsr_resp_type_policy), 8242af3b2a6SJaewan Kim }; 8252af3b2a6SJaewan Kim 8262af3b2a6SJaewan Kim static const struct nla_policy 8272af3b2a6SJaewan Kim hwsim_pmsr_peer_result_policy[NL80211_PMSR_PEER_ATTR_MAX + 1] = { 8282af3b2a6SJaewan Kim [NL80211_PMSR_PEER_ATTR_ADDR] = NLA_POLICY_ETH_ADDR_COMPAT, 8292af3b2a6SJaewan Kim [NL80211_PMSR_PEER_ATTR_CHAN] = { .type = NLA_REJECT }, 8302af3b2a6SJaewan Kim [NL80211_PMSR_PEER_ATTR_REQ] = { .type = NLA_REJECT }, 8312af3b2a6SJaewan Kim [NL80211_PMSR_PEER_ATTR_RESP] = NLA_POLICY_NESTED(hwsim_pmsr_resp_policy), 8322af3b2a6SJaewan Kim }; 8332af3b2a6SJaewan Kim 8342af3b2a6SJaewan Kim static const struct nla_policy 8352af3b2a6SJaewan Kim hwsim_pmsr_peers_result_policy[NL80211_PMSR_ATTR_MAX + 1] = { 8362af3b2a6SJaewan Kim [NL80211_PMSR_ATTR_MAX_PEERS] = { .type = NLA_REJECT }, 8372af3b2a6SJaewan Kim [NL80211_PMSR_ATTR_REPORT_AP_TSF] = { .type = NLA_REJECT }, 8382af3b2a6SJaewan Kim [NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR] = { .type = NLA_REJECT }, 8392af3b2a6SJaewan Kim [NL80211_PMSR_ATTR_TYPE_CAPA] = { .type = NLA_REJECT }, 8402af3b2a6SJaewan Kim [NL80211_PMSR_ATTR_PEERS] = NLA_POLICY_NESTED_ARRAY(hwsim_pmsr_peer_result_policy), 8412af3b2a6SJaewan Kim }; 8422af3b2a6SJaewan Kim 8432af3b2a6SJaewan Kim static const struct nla_policy 84492d13386SJaewan Kim hwsim_ftm_capa_policy[NL80211_PMSR_FTM_CAPA_ATTR_MAX + 1] = { 84592d13386SJaewan Kim [NL80211_PMSR_FTM_CAPA_ATTR_ASAP] = { .type = NLA_FLAG }, 84692d13386SJaewan Kim [NL80211_PMSR_FTM_CAPA_ATTR_NON_ASAP] = { .type = NLA_FLAG }, 84792d13386SJaewan Kim [NL80211_PMSR_FTM_CAPA_ATTR_REQ_LCI] = { .type = NLA_FLAG }, 84892d13386SJaewan Kim [NL80211_PMSR_FTM_CAPA_ATTR_REQ_CIVICLOC] = { .type = NLA_FLAG }, 84992d13386SJaewan Kim [NL80211_PMSR_FTM_CAPA_ATTR_PREAMBLES] = { .type = NLA_U32 }, 85092d13386SJaewan Kim [NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS] = { .type = NLA_U32 }, 85192d13386SJaewan Kim [NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT] = NLA_POLICY_MAX(NLA_U8, 15), 85292d13386SJaewan Kim [NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST] = NLA_POLICY_MAX(NLA_U8, 31), 85392d13386SJaewan Kim [NL80211_PMSR_FTM_CAPA_ATTR_TRIGGER_BASED] = { .type = NLA_FLAG }, 85492d13386SJaewan Kim [NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED] = { .type = NLA_FLAG }, 85592d13386SJaewan Kim }; 85692d13386SJaewan Kim 85792d13386SJaewan Kim static const struct nla_policy 85892d13386SJaewan Kim hwsim_pmsr_capa_type_policy[NL80211_PMSR_TYPE_MAX + 1] = { 85992d13386SJaewan Kim [NL80211_PMSR_TYPE_FTM] = NLA_POLICY_NESTED(hwsim_ftm_capa_policy), 86092d13386SJaewan Kim }; 86192d13386SJaewan Kim 86292d13386SJaewan Kim static const struct nla_policy 86392d13386SJaewan Kim hwsim_pmsr_capa_policy[NL80211_PMSR_ATTR_MAX + 1] = { 86492d13386SJaewan Kim [NL80211_PMSR_ATTR_MAX_PEERS] = { .type = NLA_U32 }, 86592d13386SJaewan Kim [NL80211_PMSR_ATTR_REPORT_AP_TSF] = { .type = NLA_FLAG }, 86692d13386SJaewan Kim [NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR] = { .type = NLA_FLAG }, 86792d13386SJaewan Kim [NL80211_PMSR_ATTR_TYPE_CAPA] = NLA_POLICY_NESTED(hwsim_pmsr_capa_type_policy), 86892d13386SJaewan Kim [NL80211_PMSR_ATTR_PEERS] = { .type = NLA_REJECT }, // only for request. 86992d13386SJaewan Kim }; 87092d13386SJaewan Kim 871f79cbc77SKalle Valo static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = { 872f79cbc77SKalle Valo [HWSIM_ATTR_ADDR_RECEIVER] = NLA_POLICY_ETH_ADDR_COMPAT, 873f79cbc77SKalle Valo [HWSIM_ATTR_ADDR_TRANSMITTER] = NLA_POLICY_ETH_ADDR_COMPAT, 874f79cbc77SKalle Valo [HWSIM_ATTR_FRAME] = { .type = NLA_BINARY, 875f79cbc77SKalle Valo .len = IEEE80211_MAX_DATA_LEN }, 876f79cbc77SKalle Valo [HWSIM_ATTR_FLAGS] = { .type = NLA_U32 }, 877f79cbc77SKalle Valo [HWSIM_ATTR_RX_RATE] = { .type = NLA_U32 }, 878f79cbc77SKalle Valo [HWSIM_ATTR_SIGNAL] = { .type = NLA_U32 }, 879f79cbc77SKalle Valo [HWSIM_ATTR_TX_INFO] = { .type = NLA_BINARY, 880f79cbc77SKalle Valo .len = IEEE80211_TX_MAX_RATES * 881f79cbc77SKalle Valo sizeof(struct hwsim_tx_rate)}, 882f79cbc77SKalle Valo [HWSIM_ATTR_COOKIE] = { .type = NLA_U64 }, 883f79cbc77SKalle Valo [HWSIM_ATTR_CHANNELS] = { .type = NLA_U32 }, 884f79cbc77SKalle Valo [HWSIM_ATTR_RADIO_ID] = { .type = NLA_U32 }, 885f79cbc77SKalle Valo [HWSIM_ATTR_REG_HINT_ALPHA2] = { .type = NLA_STRING, .len = 2 }, 886f79cbc77SKalle Valo [HWSIM_ATTR_REG_CUSTOM_REG] = { .type = NLA_U32 }, 887f79cbc77SKalle Valo [HWSIM_ATTR_REG_STRICT_REG] = { .type = NLA_FLAG }, 888f79cbc77SKalle Valo [HWSIM_ATTR_SUPPORT_P2P_DEVICE] = { .type = NLA_FLAG }, 889f79cbc77SKalle Valo [HWSIM_ATTR_USE_CHANCTX] = { .type = NLA_FLAG }, 890f79cbc77SKalle Valo [HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE] = { .type = NLA_FLAG }, 891f79cbc77SKalle Valo [HWSIM_ATTR_RADIO_NAME] = { .type = NLA_STRING }, 892f79cbc77SKalle Valo [HWSIM_ATTR_NO_VIF] = { .type = NLA_FLAG }, 893f79cbc77SKalle Valo [HWSIM_ATTR_FREQ] = { .type = NLA_U32 }, 894f79cbc77SKalle Valo [HWSIM_ATTR_TX_INFO_FLAGS] = { .type = NLA_BINARY }, 895f79cbc77SKalle Valo [HWSIM_ATTR_PERM_ADDR] = NLA_POLICY_ETH_ADDR_COMPAT, 896f79cbc77SKalle Valo [HWSIM_ATTR_IFTYPE_SUPPORT] = { .type = NLA_U32 }, 897f79cbc77SKalle Valo [HWSIM_ATTR_CIPHER_SUPPORT] = { .type = NLA_BINARY }, 898f79cbc77SKalle Valo [HWSIM_ATTR_MLO_SUPPORT] = { .type = NLA_FLAG }, 89992d13386SJaewan Kim [HWSIM_ATTR_PMSR_SUPPORT] = NLA_POLICY_NESTED(hwsim_pmsr_capa_policy), 9002af3b2a6SJaewan Kim [HWSIM_ATTR_PMSR_RESULT] = NLA_POLICY_NESTED(hwsim_pmsr_peers_result_policy), 901f79cbc77SKalle Valo }; 902f79cbc77SKalle Valo 903f79cbc77SKalle Valo #if IS_REACHABLE(CONFIG_VIRTIO) 904f79cbc77SKalle Valo 905f79cbc77SKalle Valo /* MAC80211_HWSIM virtio queues */ 906f79cbc77SKalle Valo static struct virtqueue *hwsim_vqs[HWSIM_NUM_VQS]; 907f79cbc77SKalle Valo static bool hwsim_virtio_enabled; 908f79cbc77SKalle Valo static DEFINE_SPINLOCK(hwsim_virtio_lock); 909f79cbc77SKalle Valo 910f79cbc77SKalle Valo static void hwsim_virtio_rx_work(struct work_struct *work); 911f79cbc77SKalle Valo static DECLARE_WORK(hwsim_virtio_rx, hwsim_virtio_rx_work); 912f79cbc77SKalle Valo 913f79cbc77SKalle Valo static int hwsim_tx_virtio(struct mac80211_hwsim_data *data, 914f79cbc77SKalle Valo struct sk_buff *skb) 915f79cbc77SKalle Valo { 916f79cbc77SKalle Valo struct scatterlist sg[1]; 917f79cbc77SKalle Valo unsigned long flags; 918f79cbc77SKalle Valo int err; 919f79cbc77SKalle Valo 920f79cbc77SKalle Valo spin_lock_irqsave(&hwsim_virtio_lock, flags); 921f79cbc77SKalle Valo if (!hwsim_virtio_enabled) { 922f79cbc77SKalle Valo err = -ENODEV; 923f79cbc77SKalle Valo goto out_free; 924f79cbc77SKalle Valo } 925f79cbc77SKalle Valo 926f79cbc77SKalle Valo sg_init_one(sg, skb->head, skb_end_offset(skb)); 927f79cbc77SKalle Valo err = virtqueue_add_outbuf(hwsim_vqs[HWSIM_VQ_TX], sg, 1, skb, 928f79cbc77SKalle Valo GFP_ATOMIC); 929f79cbc77SKalle Valo if (err) 930f79cbc77SKalle Valo goto out_free; 931f79cbc77SKalle Valo virtqueue_kick(hwsim_vqs[HWSIM_VQ_TX]); 932f79cbc77SKalle Valo spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 933f79cbc77SKalle Valo return 0; 934f79cbc77SKalle Valo 935f79cbc77SKalle Valo out_free: 936f79cbc77SKalle Valo spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 937f79cbc77SKalle Valo nlmsg_free(skb); 938f79cbc77SKalle Valo return err; 939f79cbc77SKalle Valo } 940f79cbc77SKalle Valo #else 941f79cbc77SKalle Valo /* cause a linker error if this ends up being needed */ 942f79cbc77SKalle Valo extern int hwsim_tx_virtio(struct mac80211_hwsim_data *data, 943f79cbc77SKalle Valo struct sk_buff *skb); 944f79cbc77SKalle Valo #define hwsim_virtio_enabled false 945f79cbc77SKalle Valo #endif 946f79cbc77SKalle Valo 947f79cbc77SKalle Valo static int hwsim_get_chanwidth(enum nl80211_chan_width bw) 948f79cbc77SKalle Valo { 949f79cbc77SKalle Valo switch (bw) { 950f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_20_NOHT: 951f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_20: 952f79cbc77SKalle Valo return 20; 953f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_40: 954f79cbc77SKalle Valo return 40; 955f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_80: 956f79cbc77SKalle Valo return 80; 957f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_80P80: 958f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_160: 959f79cbc77SKalle Valo return 160; 960f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_320: 961f79cbc77SKalle Valo return 320; 962f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_5: 963f79cbc77SKalle Valo return 5; 964f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_10: 965f79cbc77SKalle Valo return 10; 966f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_1: 967f79cbc77SKalle Valo return 1; 968f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_2: 969f79cbc77SKalle Valo return 2; 970f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_4: 971f79cbc77SKalle Valo return 4; 972f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_8: 973f79cbc77SKalle Valo return 8; 974f79cbc77SKalle Valo case NL80211_CHAN_WIDTH_16: 975f79cbc77SKalle Valo return 16; 976f79cbc77SKalle Valo } 977f79cbc77SKalle Valo 978f79cbc77SKalle Valo return INT_MAX; 979f79cbc77SKalle Valo } 980f79cbc77SKalle Valo 981f79cbc77SKalle Valo static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, 982f79cbc77SKalle Valo struct sk_buff *skb, 983f79cbc77SKalle Valo struct ieee80211_channel *chan); 984f79cbc77SKalle Valo 985f79cbc77SKalle Valo /* sysfs attributes */ 986f79cbc77SKalle Valo static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) 987f79cbc77SKalle Valo { 988f79cbc77SKalle Valo struct mac80211_hwsim_data *data = dat; 989f79cbc77SKalle Valo struct hwsim_vif_priv *vp = (void *)vif->drv_priv; 990f79cbc77SKalle Valo struct sk_buff *skb; 991f79cbc77SKalle Valo struct ieee80211_pspoll *pspoll; 992f79cbc77SKalle Valo 993f79cbc77SKalle Valo if (!vp->assoc) 994f79cbc77SKalle Valo return; 995f79cbc77SKalle Valo 996f79cbc77SKalle Valo wiphy_dbg(data->hw->wiphy, 997f79cbc77SKalle Valo "%s: send PS-Poll to %pM for aid %d\n", 998f79cbc77SKalle Valo __func__, vp->bssid, vp->aid); 999f79cbc77SKalle Valo 1000f79cbc77SKalle Valo skb = dev_alloc_skb(sizeof(*pspoll)); 1001f79cbc77SKalle Valo if (!skb) 1002f79cbc77SKalle Valo return; 1003f79cbc77SKalle Valo pspoll = skb_put(skb, sizeof(*pspoll)); 1004f79cbc77SKalle Valo pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | 1005f79cbc77SKalle Valo IEEE80211_STYPE_PSPOLL | 1006f79cbc77SKalle Valo IEEE80211_FCTL_PM); 1007f79cbc77SKalle Valo pspoll->aid = cpu_to_le16(0xc000 | vp->aid); 1008f79cbc77SKalle Valo memcpy(pspoll->bssid, vp->bssid, ETH_ALEN); 1009f79cbc77SKalle Valo memcpy(pspoll->ta, mac, ETH_ALEN); 1010f79cbc77SKalle Valo 1011f79cbc77SKalle Valo rcu_read_lock(); 1012f79cbc77SKalle Valo mac80211_hwsim_tx_frame(data->hw, skb, 1013f79cbc77SKalle Valo rcu_dereference(vif->bss_conf.chanctx_conf)->def.chan); 1014f79cbc77SKalle Valo rcu_read_unlock(); 1015f79cbc77SKalle Valo } 1016f79cbc77SKalle Valo 1017f79cbc77SKalle Valo static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, 1018f79cbc77SKalle Valo struct ieee80211_vif *vif, int ps) 1019f79cbc77SKalle Valo { 1020f79cbc77SKalle Valo struct hwsim_vif_priv *vp = (void *)vif->drv_priv; 1021f79cbc77SKalle Valo struct sk_buff *skb; 1022f79cbc77SKalle Valo struct ieee80211_hdr *hdr; 1023f79cbc77SKalle Valo struct ieee80211_tx_info *cb; 1024f79cbc77SKalle Valo 1025f79cbc77SKalle Valo if (!vp->assoc) 1026f79cbc77SKalle Valo return; 1027f79cbc77SKalle Valo 1028f79cbc77SKalle Valo wiphy_dbg(data->hw->wiphy, 1029f79cbc77SKalle Valo "%s: send data::nullfunc to %pM ps=%d\n", 1030f79cbc77SKalle Valo __func__, vp->bssid, ps); 1031f79cbc77SKalle Valo 1032f79cbc77SKalle Valo skb = dev_alloc_skb(sizeof(*hdr)); 1033f79cbc77SKalle Valo if (!skb) 1034f79cbc77SKalle Valo return; 1035f79cbc77SKalle Valo hdr = skb_put(skb, sizeof(*hdr) - ETH_ALEN); 1036f79cbc77SKalle Valo hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | 1037f79cbc77SKalle Valo IEEE80211_STYPE_NULLFUNC | 1038f79cbc77SKalle Valo IEEE80211_FCTL_TODS | 1039f79cbc77SKalle Valo (ps ? IEEE80211_FCTL_PM : 0)); 1040f79cbc77SKalle Valo hdr->duration_id = cpu_to_le16(0); 1041f79cbc77SKalle Valo memcpy(hdr->addr1, vp->bssid, ETH_ALEN); 1042f79cbc77SKalle Valo memcpy(hdr->addr2, mac, ETH_ALEN); 1043f79cbc77SKalle Valo memcpy(hdr->addr3, vp->bssid, ETH_ALEN); 1044f79cbc77SKalle Valo 1045f79cbc77SKalle Valo cb = IEEE80211_SKB_CB(skb); 1046f79cbc77SKalle Valo cb->control.rates[0].count = 1; 1047f79cbc77SKalle Valo cb->control.rates[1].idx = -1; 1048f79cbc77SKalle Valo 1049f79cbc77SKalle Valo rcu_read_lock(); 1050f79cbc77SKalle Valo mac80211_hwsim_tx_frame(data->hw, skb, 1051f79cbc77SKalle Valo rcu_dereference(vif->bss_conf.chanctx_conf)->def.chan); 1052f79cbc77SKalle Valo rcu_read_unlock(); 1053f79cbc77SKalle Valo } 1054f79cbc77SKalle Valo 1055f79cbc77SKalle Valo 1056f79cbc77SKalle Valo static void hwsim_send_nullfunc_ps(void *dat, u8 *mac, 1057f79cbc77SKalle Valo struct ieee80211_vif *vif) 1058f79cbc77SKalle Valo { 1059f79cbc77SKalle Valo struct mac80211_hwsim_data *data = dat; 1060f79cbc77SKalle Valo hwsim_send_nullfunc(data, mac, vif, 1); 1061f79cbc77SKalle Valo } 1062f79cbc77SKalle Valo 1063f79cbc77SKalle Valo static void hwsim_send_nullfunc_no_ps(void *dat, u8 *mac, 1064f79cbc77SKalle Valo struct ieee80211_vif *vif) 1065f79cbc77SKalle Valo { 1066f79cbc77SKalle Valo struct mac80211_hwsim_data *data = dat; 1067f79cbc77SKalle Valo hwsim_send_nullfunc(data, mac, vif, 0); 1068f79cbc77SKalle Valo } 1069f79cbc77SKalle Valo 1070f79cbc77SKalle Valo static int hwsim_fops_ps_read(void *dat, u64 *val) 1071f79cbc77SKalle Valo { 1072f79cbc77SKalle Valo struct mac80211_hwsim_data *data = dat; 1073f79cbc77SKalle Valo *val = data->ps; 1074f79cbc77SKalle Valo return 0; 1075f79cbc77SKalle Valo } 1076f79cbc77SKalle Valo 1077f79cbc77SKalle Valo static int hwsim_fops_ps_write(void *dat, u64 val) 1078f79cbc77SKalle Valo { 1079f79cbc77SKalle Valo struct mac80211_hwsim_data *data = dat; 1080f79cbc77SKalle Valo enum ps_mode old_ps; 1081f79cbc77SKalle Valo 1082f79cbc77SKalle Valo if (val != PS_DISABLED && val != PS_ENABLED && val != PS_AUTO_POLL && 1083f79cbc77SKalle Valo val != PS_MANUAL_POLL) 1084f79cbc77SKalle Valo return -EINVAL; 1085f79cbc77SKalle Valo 1086f79cbc77SKalle Valo if (val == PS_MANUAL_POLL) { 1087f79cbc77SKalle Valo if (data->ps != PS_ENABLED) 1088f79cbc77SKalle Valo return -EINVAL; 1089f79cbc77SKalle Valo local_bh_disable(); 1090f79cbc77SKalle Valo ieee80211_iterate_active_interfaces_atomic( 1091f79cbc77SKalle Valo data->hw, IEEE80211_IFACE_ITER_NORMAL, 1092f79cbc77SKalle Valo hwsim_send_ps_poll, data); 1093f79cbc77SKalle Valo local_bh_enable(); 1094f79cbc77SKalle Valo return 0; 1095f79cbc77SKalle Valo } 1096f79cbc77SKalle Valo old_ps = data->ps; 1097f79cbc77SKalle Valo data->ps = val; 1098f79cbc77SKalle Valo 1099f79cbc77SKalle Valo local_bh_disable(); 1100f79cbc77SKalle Valo if (old_ps == PS_DISABLED && val != PS_DISABLED) { 1101f79cbc77SKalle Valo ieee80211_iterate_active_interfaces_atomic( 1102f79cbc77SKalle Valo data->hw, IEEE80211_IFACE_ITER_NORMAL, 1103f79cbc77SKalle Valo hwsim_send_nullfunc_ps, data); 1104f79cbc77SKalle Valo } else if (old_ps != PS_DISABLED && val == PS_DISABLED) { 1105f79cbc77SKalle Valo ieee80211_iterate_active_interfaces_atomic( 1106f79cbc77SKalle Valo data->hw, IEEE80211_IFACE_ITER_NORMAL, 1107f79cbc77SKalle Valo hwsim_send_nullfunc_no_ps, data); 1108f79cbc77SKalle Valo } 1109f79cbc77SKalle Valo local_bh_enable(); 1110f79cbc77SKalle Valo 1111f79cbc77SKalle Valo return 0; 1112f79cbc77SKalle Valo } 1113f79cbc77SKalle Valo 1114f79cbc77SKalle Valo DEFINE_DEBUGFS_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write, 1115f79cbc77SKalle Valo "%llu\n"); 1116f79cbc77SKalle Valo 1117f79cbc77SKalle Valo static int hwsim_write_simulate_radar(void *dat, u64 val) 1118f79cbc77SKalle Valo { 1119f79cbc77SKalle Valo struct mac80211_hwsim_data *data = dat; 1120f79cbc77SKalle Valo 1121f79cbc77SKalle Valo ieee80211_radar_detected(data->hw); 1122f79cbc77SKalle Valo 1123f79cbc77SKalle Valo return 0; 1124f79cbc77SKalle Valo } 1125f79cbc77SKalle Valo 1126f79cbc77SKalle Valo DEFINE_DEBUGFS_ATTRIBUTE(hwsim_simulate_radar, NULL, 1127f79cbc77SKalle Valo hwsim_write_simulate_radar, "%llu\n"); 1128f79cbc77SKalle Valo 1129f79cbc77SKalle Valo static int hwsim_fops_group_read(void *dat, u64 *val) 1130f79cbc77SKalle Valo { 1131f79cbc77SKalle Valo struct mac80211_hwsim_data *data = dat; 1132f79cbc77SKalle Valo *val = data->group; 1133f79cbc77SKalle Valo return 0; 1134f79cbc77SKalle Valo } 1135f79cbc77SKalle Valo 1136f79cbc77SKalle Valo static int hwsim_fops_group_write(void *dat, u64 val) 1137f79cbc77SKalle Valo { 1138f79cbc77SKalle Valo struct mac80211_hwsim_data *data = dat; 1139f79cbc77SKalle Valo data->group = val; 1140f79cbc77SKalle Valo return 0; 1141f79cbc77SKalle Valo } 1142f79cbc77SKalle Valo 1143f79cbc77SKalle Valo DEFINE_DEBUGFS_ATTRIBUTE(hwsim_fops_group, 1144f79cbc77SKalle Valo hwsim_fops_group_read, hwsim_fops_group_write, 1145f79cbc77SKalle Valo "%llx\n"); 1146f79cbc77SKalle Valo 1147f79cbc77SKalle Valo static int hwsim_fops_rx_rssi_read(void *dat, u64 *val) 1148f79cbc77SKalle Valo { 1149f79cbc77SKalle Valo struct mac80211_hwsim_data *data = dat; 1150f79cbc77SKalle Valo *val = data->rx_rssi; 1151f79cbc77SKalle Valo return 0; 1152f79cbc77SKalle Valo } 1153f79cbc77SKalle Valo 1154f79cbc77SKalle Valo static int hwsim_fops_rx_rssi_write(void *dat, u64 val) 1155f79cbc77SKalle Valo { 1156f79cbc77SKalle Valo struct mac80211_hwsim_data *data = dat; 1157f79cbc77SKalle Valo int rssi = (int)val; 1158f79cbc77SKalle Valo 1159f79cbc77SKalle Valo if (rssi >= 0 || rssi < -100) 1160f79cbc77SKalle Valo return -EINVAL; 1161f79cbc77SKalle Valo 1162f79cbc77SKalle Valo data->rx_rssi = rssi; 1163f79cbc77SKalle Valo return 0; 1164f79cbc77SKalle Valo } 1165f79cbc77SKalle Valo 1166f79cbc77SKalle Valo DEFINE_DEBUGFS_ATTRIBUTE(hwsim_fops_rx_rssi, 1167f79cbc77SKalle Valo hwsim_fops_rx_rssi_read, hwsim_fops_rx_rssi_write, 1168f79cbc77SKalle Valo "%lld\n"); 1169f79cbc77SKalle Valo 1170f79cbc77SKalle Valo static netdev_tx_t hwsim_mon_xmit(struct sk_buff *skb, 1171f79cbc77SKalle Valo struct net_device *dev) 1172f79cbc77SKalle Valo { 1173f79cbc77SKalle Valo /* TODO: allow packet injection */ 1174f79cbc77SKalle Valo dev_kfree_skb(skb); 1175f79cbc77SKalle Valo return NETDEV_TX_OK; 1176f79cbc77SKalle Valo } 1177f79cbc77SKalle Valo 1178f79cbc77SKalle Valo static inline u64 mac80211_hwsim_get_tsf_raw(void) 1179f79cbc77SKalle Valo { 1180f79cbc77SKalle Valo return ktime_to_us(ktime_get_real()); 1181f79cbc77SKalle Valo } 1182f79cbc77SKalle Valo 1183f79cbc77SKalle Valo static __le64 __mac80211_hwsim_get_tsf(struct mac80211_hwsim_data *data) 1184f79cbc77SKalle Valo { 1185f79cbc77SKalle Valo u64 now = mac80211_hwsim_get_tsf_raw(); 1186f79cbc77SKalle Valo return cpu_to_le64(now + data->tsf_offset); 1187f79cbc77SKalle Valo } 1188f79cbc77SKalle Valo 1189f79cbc77SKalle Valo static u64 mac80211_hwsim_get_tsf(struct ieee80211_hw *hw, 1190f79cbc77SKalle Valo struct ieee80211_vif *vif) 1191f79cbc77SKalle Valo { 1192f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 1193f79cbc77SKalle Valo return le64_to_cpu(__mac80211_hwsim_get_tsf(data)); 1194f79cbc77SKalle Valo } 1195f79cbc77SKalle Valo 1196f79cbc77SKalle Valo static void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw, 1197f79cbc77SKalle Valo struct ieee80211_vif *vif, u64 tsf) 1198f79cbc77SKalle Valo { 1199f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 1200f79cbc77SKalle Valo u64 now = mac80211_hwsim_get_tsf(hw, vif); 1201f79cbc77SKalle Valo /* MLD not supported here */ 1202f79cbc77SKalle Valo u32 bcn_int = data->link_data[0].beacon_int; 1203f79cbc77SKalle Valo u64 delta = abs(tsf - now); 1204f79cbc77SKalle Valo 1205f79cbc77SKalle Valo /* adjust after beaconing with new timestamp at old TBTT */ 1206f79cbc77SKalle Valo if (tsf > now) { 1207f79cbc77SKalle Valo data->tsf_offset += delta; 1208f79cbc77SKalle Valo data->bcn_delta = do_div(delta, bcn_int); 1209f79cbc77SKalle Valo } else { 1210f79cbc77SKalle Valo data->tsf_offset -= delta; 1211f79cbc77SKalle Valo data->bcn_delta = -(s64)do_div(delta, bcn_int); 1212f79cbc77SKalle Valo } 1213f79cbc77SKalle Valo } 1214f79cbc77SKalle Valo 1215f79cbc77SKalle Valo static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, 1216f79cbc77SKalle Valo struct sk_buff *tx_skb, 1217f79cbc77SKalle Valo struct ieee80211_channel *chan) 1218f79cbc77SKalle Valo { 1219f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 1220f79cbc77SKalle Valo struct sk_buff *skb; 1221f79cbc77SKalle Valo struct hwsim_radiotap_hdr *hdr; 1222f79cbc77SKalle Valo u16 flags, bitrate; 1223f79cbc77SKalle Valo struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_skb); 1224f79cbc77SKalle Valo struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info); 1225f79cbc77SKalle Valo 1226f79cbc77SKalle Valo if (!txrate) 1227f79cbc77SKalle Valo bitrate = 0; 1228f79cbc77SKalle Valo else 1229f79cbc77SKalle Valo bitrate = txrate->bitrate; 1230f79cbc77SKalle Valo 1231f79cbc77SKalle Valo if (!netif_running(hwsim_mon)) 1232f79cbc77SKalle Valo return; 1233f79cbc77SKalle Valo 1234f79cbc77SKalle Valo skb = skb_copy_expand(tx_skb, sizeof(*hdr), 0, GFP_ATOMIC); 1235f79cbc77SKalle Valo if (skb == NULL) 1236f79cbc77SKalle Valo return; 1237f79cbc77SKalle Valo 1238f79cbc77SKalle Valo hdr = skb_push(skb, sizeof(*hdr)); 1239f79cbc77SKalle Valo hdr->hdr.it_version = PKTHDR_RADIOTAP_VERSION; 1240f79cbc77SKalle Valo hdr->hdr.it_pad = 0; 1241f79cbc77SKalle Valo hdr->hdr.it_len = cpu_to_le16(sizeof(*hdr)); 1242f79cbc77SKalle Valo hdr->hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | 1243f79cbc77SKalle Valo (1 << IEEE80211_RADIOTAP_RATE) | 1244f79cbc77SKalle Valo (1 << IEEE80211_RADIOTAP_TSFT) | 1245f79cbc77SKalle Valo (1 << IEEE80211_RADIOTAP_CHANNEL)); 1246f79cbc77SKalle Valo hdr->rt_tsft = __mac80211_hwsim_get_tsf(data); 1247f79cbc77SKalle Valo hdr->rt_flags = 0; 1248f79cbc77SKalle Valo hdr->rt_rate = bitrate / 5; 1249f79cbc77SKalle Valo hdr->rt_channel = cpu_to_le16(chan->center_freq); 1250f79cbc77SKalle Valo flags = IEEE80211_CHAN_2GHZ; 1251f79cbc77SKalle Valo if (txrate && txrate->flags & IEEE80211_RATE_ERP_G) 1252f79cbc77SKalle Valo flags |= IEEE80211_CHAN_OFDM; 1253f79cbc77SKalle Valo else 1254f79cbc77SKalle Valo flags |= IEEE80211_CHAN_CCK; 1255f79cbc77SKalle Valo hdr->rt_chbitmask = cpu_to_le16(flags); 1256f79cbc77SKalle Valo 1257f79cbc77SKalle Valo skb->dev = hwsim_mon; 1258f79cbc77SKalle Valo skb_reset_mac_header(skb); 1259f79cbc77SKalle Valo skb->ip_summed = CHECKSUM_UNNECESSARY; 1260f79cbc77SKalle Valo skb->pkt_type = PACKET_OTHERHOST; 1261f79cbc77SKalle Valo skb->protocol = htons(ETH_P_802_2); 1262f79cbc77SKalle Valo memset(skb->cb, 0, sizeof(skb->cb)); 1263f79cbc77SKalle Valo netif_rx(skb); 1264f79cbc77SKalle Valo } 1265f79cbc77SKalle Valo 1266f79cbc77SKalle Valo 1267f79cbc77SKalle Valo static void mac80211_hwsim_monitor_ack(struct ieee80211_channel *chan, 1268f79cbc77SKalle Valo const u8 *addr) 1269f79cbc77SKalle Valo { 1270f79cbc77SKalle Valo struct sk_buff *skb; 1271f79cbc77SKalle Valo struct hwsim_radiotap_ack_hdr *hdr; 1272f79cbc77SKalle Valo u16 flags; 1273f79cbc77SKalle Valo struct ieee80211_hdr *hdr11; 1274f79cbc77SKalle Valo 1275f79cbc77SKalle Valo if (!netif_running(hwsim_mon)) 1276f79cbc77SKalle Valo return; 1277f79cbc77SKalle Valo 1278f79cbc77SKalle Valo skb = dev_alloc_skb(100); 1279f79cbc77SKalle Valo if (skb == NULL) 1280f79cbc77SKalle Valo return; 1281f79cbc77SKalle Valo 1282f79cbc77SKalle Valo hdr = skb_put(skb, sizeof(*hdr)); 1283f79cbc77SKalle Valo hdr->hdr.it_version = PKTHDR_RADIOTAP_VERSION; 1284f79cbc77SKalle Valo hdr->hdr.it_pad = 0; 1285f79cbc77SKalle Valo hdr->hdr.it_len = cpu_to_le16(sizeof(*hdr)); 1286f79cbc77SKalle Valo hdr->hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | 1287f79cbc77SKalle Valo (1 << IEEE80211_RADIOTAP_CHANNEL)); 1288f79cbc77SKalle Valo hdr->rt_flags = 0; 1289f79cbc77SKalle Valo hdr->pad = 0; 1290f79cbc77SKalle Valo hdr->rt_channel = cpu_to_le16(chan->center_freq); 1291f79cbc77SKalle Valo flags = IEEE80211_CHAN_2GHZ; 1292f79cbc77SKalle Valo hdr->rt_chbitmask = cpu_to_le16(flags); 1293f79cbc77SKalle Valo 1294f79cbc77SKalle Valo hdr11 = skb_put(skb, 10); 1295f79cbc77SKalle Valo hdr11->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | 1296f79cbc77SKalle Valo IEEE80211_STYPE_ACK); 1297f79cbc77SKalle Valo hdr11->duration_id = cpu_to_le16(0); 1298f79cbc77SKalle Valo memcpy(hdr11->addr1, addr, ETH_ALEN); 1299f79cbc77SKalle Valo 1300f79cbc77SKalle Valo skb->dev = hwsim_mon; 1301f79cbc77SKalle Valo skb_reset_mac_header(skb); 1302f79cbc77SKalle Valo skb->ip_summed = CHECKSUM_UNNECESSARY; 1303f79cbc77SKalle Valo skb->pkt_type = PACKET_OTHERHOST; 1304f79cbc77SKalle Valo skb->protocol = htons(ETH_P_802_2); 1305f79cbc77SKalle Valo memset(skb->cb, 0, sizeof(skb->cb)); 1306f79cbc77SKalle Valo netif_rx(skb); 1307f79cbc77SKalle Valo } 1308f79cbc77SKalle Valo 1309f79cbc77SKalle Valo struct mac80211_hwsim_addr_match_data { 1310f79cbc77SKalle Valo u8 addr[ETH_ALEN]; 1311f79cbc77SKalle Valo bool ret; 1312f79cbc77SKalle Valo }; 1313f79cbc77SKalle Valo 1314f79cbc77SKalle Valo static void mac80211_hwsim_addr_iter(void *data, u8 *mac, 1315f79cbc77SKalle Valo struct ieee80211_vif *vif) 1316f79cbc77SKalle Valo { 1317f79cbc77SKalle Valo int i; 1318f79cbc77SKalle Valo struct mac80211_hwsim_addr_match_data *md = data; 1319f79cbc77SKalle Valo 1320f79cbc77SKalle Valo if (memcmp(mac, md->addr, ETH_ALEN) == 0) { 1321f79cbc77SKalle Valo md->ret = true; 1322f79cbc77SKalle Valo return; 1323f79cbc77SKalle Valo } 1324f79cbc77SKalle Valo 1325f79cbc77SKalle Valo /* Match the link address */ 1326f79cbc77SKalle Valo for (i = 0; i < ARRAY_SIZE(vif->link_conf); i++) { 1327f79cbc77SKalle Valo struct ieee80211_bss_conf *conf; 1328f79cbc77SKalle Valo 1329f79cbc77SKalle Valo conf = rcu_dereference(vif->link_conf[i]); 1330f79cbc77SKalle Valo if (!conf) 1331f79cbc77SKalle Valo continue; 1332f79cbc77SKalle Valo 1333f79cbc77SKalle Valo if (memcmp(conf->addr, md->addr, ETH_ALEN) == 0) { 1334f79cbc77SKalle Valo md->ret = true; 1335f79cbc77SKalle Valo return; 1336f79cbc77SKalle Valo } 1337f79cbc77SKalle Valo } 1338f79cbc77SKalle Valo } 1339f79cbc77SKalle Valo 1340f79cbc77SKalle Valo static bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data, 1341f79cbc77SKalle Valo const u8 *addr) 1342f79cbc77SKalle Valo { 1343f79cbc77SKalle Valo struct mac80211_hwsim_addr_match_data md = { 1344f79cbc77SKalle Valo .ret = false, 1345f79cbc77SKalle Valo }; 1346f79cbc77SKalle Valo 1347f79cbc77SKalle Valo if (data->scanning && memcmp(addr, data->scan_addr, ETH_ALEN) == 0) 1348f79cbc77SKalle Valo return true; 1349f79cbc77SKalle Valo 1350f79cbc77SKalle Valo memcpy(md.addr, addr, ETH_ALEN); 1351f79cbc77SKalle Valo 1352f79cbc77SKalle Valo ieee80211_iterate_active_interfaces_atomic(data->hw, 1353f79cbc77SKalle Valo IEEE80211_IFACE_ITER_NORMAL, 1354f79cbc77SKalle Valo mac80211_hwsim_addr_iter, 1355f79cbc77SKalle Valo &md); 1356f79cbc77SKalle Valo 1357f79cbc77SKalle Valo return md.ret; 1358f79cbc77SKalle Valo } 1359f79cbc77SKalle Valo 1360f79cbc77SKalle Valo static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data, 1361f79cbc77SKalle Valo struct sk_buff *skb) 1362f79cbc77SKalle Valo { 1363f79cbc77SKalle Valo switch (data->ps) { 1364f79cbc77SKalle Valo case PS_DISABLED: 1365f79cbc77SKalle Valo return true; 1366f79cbc77SKalle Valo case PS_ENABLED: 1367f79cbc77SKalle Valo return false; 1368f79cbc77SKalle Valo case PS_AUTO_POLL: 1369f79cbc77SKalle Valo /* TODO: accept (some) Beacons by default and other frames only 1370f79cbc77SKalle Valo * if pending PS-Poll has been sent */ 1371f79cbc77SKalle Valo return true; 1372f79cbc77SKalle Valo case PS_MANUAL_POLL: 1373f79cbc77SKalle Valo /* Allow unicast frames to own address if there is a pending 1374f79cbc77SKalle Valo * PS-Poll */ 1375f79cbc77SKalle Valo if (data->ps_poll_pending && 1376f79cbc77SKalle Valo mac80211_hwsim_addr_match(data, skb->data + 4)) { 1377f79cbc77SKalle Valo data->ps_poll_pending = false; 1378f79cbc77SKalle Valo return true; 1379f79cbc77SKalle Valo } 1380f79cbc77SKalle Valo return false; 1381f79cbc77SKalle Valo } 1382f79cbc77SKalle Valo 1383f79cbc77SKalle Valo return true; 1384f79cbc77SKalle Valo } 1385f79cbc77SKalle Valo 1386f79cbc77SKalle Valo static int hwsim_unicast_netgroup(struct mac80211_hwsim_data *data, 1387f79cbc77SKalle Valo struct sk_buff *skb, int portid) 1388f79cbc77SKalle Valo { 1389f79cbc77SKalle Valo struct net *net; 1390f79cbc77SKalle Valo bool found = false; 1391f79cbc77SKalle Valo int res = -ENOENT; 1392f79cbc77SKalle Valo 1393f79cbc77SKalle Valo rcu_read_lock(); 1394f79cbc77SKalle Valo for_each_net_rcu(net) { 1395f79cbc77SKalle Valo if (data->netgroup == hwsim_net_get_netgroup(net)) { 1396f79cbc77SKalle Valo res = genlmsg_unicast(net, skb, portid); 1397f79cbc77SKalle Valo found = true; 1398f79cbc77SKalle Valo break; 1399f79cbc77SKalle Valo } 1400f79cbc77SKalle Valo } 1401f79cbc77SKalle Valo rcu_read_unlock(); 1402f79cbc77SKalle Valo 1403f79cbc77SKalle Valo if (!found) 1404f79cbc77SKalle Valo nlmsg_free(skb); 1405f79cbc77SKalle Valo 1406f79cbc77SKalle Valo return res; 1407f79cbc77SKalle Valo } 1408f79cbc77SKalle Valo 1409f79cbc77SKalle Valo static void mac80211_hwsim_config_mac_nl(struct ieee80211_hw *hw, 1410f79cbc77SKalle Valo const u8 *addr, bool add) 1411f79cbc77SKalle Valo { 1412f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 1413f79cbc77SKalle Valo u32 _portid = READ_ONCE(data->wmediumd); 1414f79cbc77SKalle Valo struct sk_buff *skb; 1415f79cbc77SKalle Valo void *msg_head; 1416f79cbc77SKalle Valo 1417f79cbc77SKalle Valo WARN_ON(!is_valid_ether_addr(addr)); 1418f79cbc77SKalle Valo 1419f79cbc77SKalle Valo if (!_portid && !hwsim_virtio_enabled) 1420f79cbc77SKalle Valo return; 1421f79cbc77SKalle Valo 1422f79cbc77SKalle Valo skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_ATOMIC); 1423f79cbc77SKalle Valo if (!skb) 1424f79cbc77SKalle Valo return; 1425f79cbc77SKalle Valo 1426f79cbc77SKalle Valo msg_head = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, 1427f79cbc77SKalle Valo add ? HWSIM_CMD_ADD_MAC_ADDR : 1428f79cbc77SKalle Valo HWSIM_CMD_DEL_MAC_ADDR); 1429f79cbc77SKalle Valo if (!msg_head) { 1430f79cbc77SKalle Valo pr_debug("mac80211_hwsim: problem with msg_head\n"); 1431f79cbc77SKalle Valo goto nla_put_failure; 1432f79cbc77SKalle Valo } 1433f79cbc77SKalle Valo 1434f79cbc77SKalle Valo if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER, 1435f79cbc77SKalle Valo ETH_ALEN, data->addresses[1].addr)) 1436f79cbc77SKalle Valo goto nla_put_failure; 1437f79cbc77SKalle Valo 1438f79cbc77SKalle Valo if (nla_put(skb, HWSIM_ATTR_ADDR_RECEIVER, ETH_ALEN, addr)) 1439f79cbc77SKalle Valo goto nla_put_failure; 1440f79cbc77SKalle Valo 1441f79cbc77SKalle Valo genlmsg_end(skb, msg_head); 1442f79cbc77SKalle Valo 1443f79cbc77SKalle Valo if (hwsim_virtio_enabled) 1444f79cbc77SKalle Valo hwsim_tx_virtio(data, skb); 1445f79cbc77SKalle Valo else 1446f79cbc77SKalle Valo hwsim_unicast_netgroup(data, skb, _portid); 1447f79cbc77SKalle Valo return; 1448f79cbc77SKalle Valo nla_put_failure: 1449f79cbc77SKalle Valo nlmsg_free(skb); 1450f79cbc77SKalle Valo } 1451f79cbc77SKalle Valo 1452f79cbc77SKalle Valo static inline u16 trans_tx_rate_flags_ieee2hwsim(struct ieee80211_tx_rate *rate) 1453f79cbc77SKalle Valo { 1454f79cbc77SKalle Valo u16 result = 0; 1455f79cbc77SKalle Valo 1456f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_USE_RTS_CTS) 1457f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_USE_RTS_CTS; 1458f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT) 1459f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_USE_CTS_PROTECT; 1460f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) 1461f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_USE_SHORT_PREAMBLE; 1462f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_MCS) 1463f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_MCS; 1464f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD) 1465f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_GREEN_FIELD; 1466f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) 1467f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_40_MHZ_WIDTH; 1468f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_DUP_DATA) 1469f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_DUP_DATA; 1470f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_SHORT_GI) 1471f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_SHORT_GI; 1472f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_VHT_MCS) 1473f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_VHT_MCS; 1474f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH) 1475f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_80_MHZ_WIDTH; 1476f79cbc77SKalle Valo if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH) 1477f79cbc77SKalle Valo result |= MAC80211_HWSIM_TX_RC_160_MHZ_WIDTH; 1478f79cbc77SKalle Valo 1479f79cbc77SKalle Valo return result; 1480f79cbc77SKalle Valo } 1481f79cbc77SKalle Valo 1482f79cbc77SKalle Valo static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, 1483f79cbc77SKalle Valo struct sk_buff *my_skb, 1484f79cbc77SKalle Valo int dst_portid, 1485f79cbc77SKalle Valo struct ieee80211_channel *channel) 1486f79cbc77SKalle Valo { 1487f79cbc77SKalle Valo struct sk_buff *skb; 1488f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 1489f79cbc77SKalle Valo struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) my_skb->data; 1490f79cbc77SKalle Valo struct ieee80211_tx_info *info = IEEE80211_SKB_CB(my_skb); 1491f79cbc77SKalle Valo void *msg_head; 1492f79cbc77SKalle Valo unsigned int hwsim_flags = 0; 1493f79cbc77SKalle Valo int i; 1494f79cbc77SKalle Valo struct hwsim_tx_rate tx_attempts[IEEE80211_TX_MAX_RATES]; 1495f79cbc77SKalle Valo struct hwsim_tx_rate_flag tx_attempts_flags[IEEE80211_TX_MAX_RATES]; 1496f79cbc77SKalle Valo uintptr_t cookie; 1497f79cbc77SKalle Valo 1498f79cbc77SKalle Valo if (data->ps != PS_DISABLED) 1499f79cbc77SKalle Valo hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); 1500f79cbc77SKalle Valo /* If the queue contains MAX_QUEUE skb's drop some */ 1501f79cbc77SKalle Valo if (skb_queue_len(&data->pending) >= MAX_QUEUE) { 1502f79cbc77SKalle Valo /* Dropping until WARN_QUEUE level */ 1503f79cbc77SKalle Valo while (skb_queue_len(&data->pending) >= WARN_QUEUE) { 1504f79cbc77SKalle Valo ieee80211_free_txskb(hw, skb_dequeue(&data->pending)); 1505f79cbc77SKalle Valo data->tx_dropped++; 1506f79cbc77SKalle Valo } 1507f79cbc77SKalle Valo } 1508f79cbc77SKalle Valo 1509f79cbc77SKalle Valo skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_ATOMIC); 1510f79cbc77SKalle Valo if (skb == NULL) 1511f79cbc77SKalle Valo goto nla_put_failure; 1512f79cbc77SKalle Valo 1513f79cbc77SKalle Valo msg_head = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, 1514f79cbc77SKalle Valo HWSIM_CMD_FRAME); 1515f79cbc77SKalle Valo if (msg_head == NULL) { 1516f79cbc77SKalle Valo pr_debug("mac80211_hwsim: problem with msg_head\n"); 1517f79cbc77SKalle Valo goto nla_put_failure; 1518f79cbc77SKalle Valo } 1519f79cbc77SKalle Valo 1520f79cbc77SKalle Valo if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER, 1521f79cbc77SKalle Valo ETH_ALEN, data->addresses[1].addr)) 1522f79cbc77SKalle Valo goto nla_put_failure; 1523f79cbc77SKalle Valo 1524f79cbc77SKalle Valo /* We get the skb->data */ 1525f79cbc77SKalle Valo if (nla_put(skb, HWSIM_ATTR_FRAME, my_skb->len, my_skb->data)) 1526f79cbc77SKalle Valo goto nla_put_failure; 1527f79cbc77SKalle Valo 1528f79cbc77SKalle Valo /* We get the flags for this transmission, and we translate them to 1529f79cbc77SKalle Valo wmediumd flags */ 1530f79cbc77SKalle Valo 1531f79cbc77SKalle Valo if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) 1532f79cbc77SKalle Valo hwsim_flags |= HWSIM_TX_CTL_REQ_TX_STATUS; 1533f79cbc77SKalle Valo 1534f79cbc77SKalle Valo if (info->flags & IEEE80211_TX_CTL_NO_ACK) 1535f79cbc77SKalle Valo hwsim_flags |= HWSIM_TX_CTL_NO_ACK; 1536f79cbc77SKalle Valo 1537f79cbc77SKalle Valo if (nla_put_u32(skb, HWSIM_ATTR_FLAGS, hwsim_flags)) 1538f79cbc77SKalle Valo goto nla_put_failure; 1539f79cbc77SKalle Valo 1540f79cbc77SKalle Valo if (nla_put_u32(skb, HWSIM_ATTR_FREQ, channel->center_freq)) 1541f79cbc77SKalle Valo goto nla_put_failure; 1542f79cbc77SKalle Valo 1543f79cbc77SKalle Valo /* We get the tx control (rate and retries) info*/ 1544f79cbc77SKalle Valo 1545f79cbc77SKalle Valo for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { 1546f79cbc77SKalle Valo tx_attempts[i].idx = info->status.rates[i].idx; 1547f79cbc77SKalle Valo tx_attempts_flags[i].idx = info->status.rates[i].idx; 1548f79cbc77SKalle Valo tx_attempts[i].count = info->status.rates[i].count; 1549f79cbc77SKalle Valo tx_attempts_flags[i].flags = 1550f79cbc77SKalle Valo trans_tx_rate_flags_ieee2hwsim( 1551f79cbc77SKalle Valo &info->status.rates[i]); 1552f79cbc77SKalle Valo } 1553f79cbc77SKalle Valo 1554f79cbc77SKalle Valo if (nla_put(skb, HWSIM_ATTR_TX_INFO, 1555f79cbc77SKalle Valo sizeof(struct hwsim_tx_rate)*IEEE80211_TX_MAX_RATES, 1556f79cbc77SKalle Valo tx_attempts)) 1557f79cbc77SKalle Valo goto nla_put_failure; 1558f79cbc77SKalle Valo 1559f79cbc77SKalle Valo if (nla_put(skb, HWSIM_ATTR_TX_INFO_FLAGS, 1560f79cbc77SKalle Valo sizeof(struct hwsim_tx_rate_flag) * IEEE80211_TX_MAX_RATES, 1561f79cbc77SKalle Valo tx_attempts_flags)) 1562f79cbc77SKalle Valo goto nla_put_failure; 1563f79cbc77SKalle Valo 1564f79cbc77SKalle Valo /* We create a cookie to identify this skb */ 1565f79cbc77SKalle Valo cookie = atomic_inc_return(&data->pending_cookie); 1566f79cbc77SKalle Valo info->rate_driver_data[0] = (void *)cookie; 1567f79cbc77SKalle Valo if (nla_put_u64_64bit(skb, HWSIM_ATTR_COOKIE, cookie, HWSIM_ATTR_PAD)) 1568f79cbc77SKalle Valo goto nla_put_failure; 1569f79cbc77SKalle Valo 1570f79cbc77SKalle Valo genlmsg_end(skb, msg_head); 1571f79cbc77SKalle Valo 1572f79cbc77SKalle Valo if (hwsim_virtio_enabled) { 1573f79cbc77SKalle Valo if (hwsim_tx_virtio(data, skb)) 1574f79cbc77SKalle Valo goto err_free_txskb; 1575f79cbc77SKalle Valo } else { 1576f79cbc77SKalle Valo if (hwsim_unicast_netgroup(data, skb, dst_portid)) 1577f79cbc77SKalle Valo goto err_free_txskb; 1578f79cbc77SKalle Valo } 1579f79cbc77SKalle Valo 1580f79cbc77SKalle Valo /* Enqueue the packet */ 1581f79cbc77SKalle Valo skb_queue_tail(&data->pending, my_skb); 1582f79cbc77SKalle Valo data->tx_pkts++; 1583f79cbc77SKalle Valo data->tx_bytes += my_skb->len; 1584f79cbc77SKalle Valo return; 1585f79cbc77SKalle Valo 1586f79cbc77SKalle Valo nla_put_failure: 1587f79cbc77SKalle Valo nlmsg_free(skb); 1588f79cbc77SKalle Valo err_free_txskb: 1589f79cbc77SKalle Valo pr_debug("mac80211_hwsim: error occurred in %s\n", __func__); 1590f79cbc77SKalle Valo ieee80211_free_txskb(hw, my_skb); 1591f79cbc77SKalle Valo data->tx_failed++; 1592f79cbc77SKalle Valo } 1593f79cbc77SKalle Valo 1594f79cbc77SKalle Valo static bool hwsim_chans_compat(struct ieee80211_channel *c1, 1595f79cbc77SKalle Valo struct ieee80211_channel *c2) 1596f79cbc77SKalle Valo { 1597f79cbc77SKalle Valo if (!c1 || !c2) 1598f79cbc77SKalle Valo return false; 1599f79cbc77SKalle Valo 1600f79cbc77SKalle Valo return c1->center_freq == c2->center_freq; 1601f79cbc77SKalle Valo } 1602f79cbc77SKalle Valo 1603f79cbc77SKalle Valo struct tx_iter_data { 1604f79cbc77SKalle Valo struct ieee80211_channel *channel; 1605f79cbc77SKalle Valo bool receive; 1606f79cbc77SKalle Valo }; 1607f79cbc77SKalle Valo 1608f79cbc77SKalle Valo static void mac80211_hwsim_tx_iter(void *_data, u8 *addr, 1609f79cbc77SKalle Valo struct ieee80211_vif *vif) 1610f79cbc77SKalle Valo { 1611f79cbc77SKalle Valo struct tx_iter_data *data = _data; 1612f79cbc77SKalle Valo int i; 1613f79cbc77SKalle Valo 1614f79cbc77SKalle Valo for (i = 0; i < ARRAY_SIZE(vif->link_conf); i++) { 1615f79cbc77SKalle Valo struct ieee80211_bss_conf *conf; 1616f79cbc77SKalle Valo struct ieee80211_chanctx_conf *chanctx; 1617f79cbc77SKalle Valo 1618f79cbc77SKalle Valo conf = rcu_dereference(vif->link_conf[i]); 1619f79cbc77SKalle Valo if (!conf) 1620f79cbc77SKalle Valo continue; 1621f79cbc77SKalle Valo 1622f79cbc77SKalle Valo chanctx = rcu_dereference(conf->chanctx_conf); 1623f79cbc77SKalle Valo if (!chanctx) 1624f79cbc77SKalle Valo continue; 1625f79cbc77SKalle Valo 1626f79cbc77SKalle Valo if (!hwsim_chans_compat(data->channel, chanctx->def.chan)) 1627f79cbc77SKalle Valo continue; 1628f79cbc77SKalle Valo 1629f79cbc77SKalle Valo data->receive = true; 1630f79cbc77SKalle Valo return; 1631f79cbc77SKalle Valo } 1632f79cbc77SKalle Valo } 1633f79cbc77SKalle Valo 1634f79cbc77SKalle Valo static void mac80211_hwsim_add_vendor_rtap(struct sk_buff *skb) 1635f79cbc77SKalle Valo { 1636f79cbc77SKalle Valo /* 1637f79cbc77SKalle Valo * To enable this code, #define the HWSIM_RADIOTAP_OUI, 1638f79cbc77SKalle Valo * e.g. like this: 1639f79cbc77SKalle Valo * #define HWSIM_RADIOTAP_OUI "\x02\x00\x00" 1640f79cbc77SKalle Valo * (but you should use a valid OUI, not that) 1641f79cbc77SKalle Valo * 1642f79cbc77SKalle Valo * If anyone wants to 'donate' a radiotap OUI/subns code 1643f79cbc77SKalle Valo * please send a patch removing this #ifdef and changing 1644f79cbc77SKalle Valo * the values accordingly. 1645f79cbc77SKalle Valo */ 1646f79cbc77SKalle Valo #ifdef HWSIM_RADIOTAP_OUI 1647f79cbc77SKalle Valo struct ieee80211_radiotap_vendor_tlv *rtap; 1648f79cbc77SKalle Valo static const char vendor_data[8] = "ABCDEFGH"; 1649f79cbc77SKalle Valo 1650f79cbc77SKalle Valo // Make sure no padding is needed 1651f79cbc77SKalle Valo BUILD_BUG_ON(sizeof(vendor_data) % 4); 1652f79cbc77SKalle Valo /* this is last radiotap info before the mac header, so 1653f79cbc77SKalle Valo * skb_reset_mac_header for mac8022 to know the end of 1654f79cbc77SKalle Valo * the radiotap TLV/beginning of the 802.11 header 1655f79cbc77SKalle Valo */ 1656f79cbc77SKalle Valo skb_reset_mac_header(skb); 1657f79cbc77SKalle Valo 1658f79cbc77SKalle Valo /* 1659f79cbc77SKalle Valo * Note that this code requires the headroom in the SKB 1660f79cbc77SKalle Valo * that was allocated earlier. 1661f79cbc77SKalle Valo */ 1662f79cbc77SKalle Valo rtap = skb_push(skb, sizeof(*rtap) + sizeof(vendor_data)); 1663f79cbc77SKalle Valo 1664f79cbc77SKalle Valo rtap->len = cpu_to_le16(sizeof(*rtap) - 1665f79cbc77SKalle Valo sizeof(struct ieee80211_radiotap_tlv) + 1666f79cbc77SKalle Valo sizeof(vendor_data)); 1667f79cbc77SKalle Valo rtap->type = cpu_to_le16(IEEE80211_RADIOTAP_VENDOR_NAMESPACE); 1668f79cbc77SKalle Valo 1669f79cbc77SKalle Valo rtap->content.oui[0] = HWSIM_RADIOTAP_OUI[0]; 1670f79cbc77SKalle Valo rtap->content.oui[1] = HWSIM_RADIOTAP_OUI[1]; 1671f79cbc77SKalle Valo rtap->content.oui[2] = HWSIM_RADIOTAP_OUI[2]; 1672f79cbc77SKalle Valo rtap->content.oui_subtype = 127; 1673f79cbc77SKalle Valo /* clear reserved field */ 1674f79cbc77SKalle Valo rtap->content.reserved = 0; 1675f79cbc77SKalle Valo rtap->content.vendor_type = 0; 1676f79cbc77SKalle Valo memcpy(rtap->content.data, vendor_data, sizeof(vendor_data)); 1677f79cbc77SKalle Valo 1678f79cbc77SKalle Valo IEEE80211_SKB_RXCB(skb)->flag |= RX_FLAG_RADIOTAP_TLV_AT_END; 1679f79cbc77SKalle Valo #endif 1680f79cbc77SKalle Valo } 1681f79cbc77SKalle Valo 1682f79cbc77SKalle Valo static void mac80211_hwsim_rx(struct mac80211_hwsim_data *data, 1683f79cbc77SKalle Valo struct ieee80211_rx_status *rx_status, 1684f79cbc77SKalle Valo struct sk_buff *skb) 1685f79cbc77SKalle Valo { 1686f79cbc77SKalle Valo struct ieee80211_hdr *hdr = (void *)skb->data; 1687f79cbc77SKalle Valo 1688f79cbc77SKalle Valo if (!ieee80211_has_morefrags(hdr->frame_control) && 1689f79cbc77SKalle Valo !is_multicast_ether_addr(hdr->addr1) && 1690f79cbc77SKalle Valo (ieee80211_is_mgmt(hdr->frame_control) || 1691f79cbc77SKalle Valo ieee80211_is_data(hdr->frame_control))) { 1692f79cbc77SKalle Valo struct ieee80211_sta *sta; 1693f79cbc77SKalle Valo unsigned int link_id; 1694f79cbc77SKalle Valo 1695f79cbc77SKalle Valo rcu_read_lock(); 1696f79cbc77SKalle Valo sta = ieee80211_find_sta_by_link_addrs(data->hw, hdr->addr2, 1697f79cbc77SKalle Valo hdr->addr1, &link_id); 1698f79cbc77SKalle Valo if (sta) { 1699f79cbc77SKalle Valo struct hwsim_sta_priv *sp = (void *)sta->drv_priv; 1700f79cbc77SKalle Valo 1701f79cbc77SKalle Valo if (ieee80211_has_pm(hdr->frame_control)) 1702f79cbc77SKalle Valo sp->active_links_rx &= ~BIT(link_id); 1703f79cbc77SKalle Valo else 1704f79cbc77SKalle Valo sp->active_links_rx |= BIT(link_id); 1705f79cbc77SKalle Valo } 1706f79cbc77SKalle Valo rcu_read_unlock(); 1707f79cbc77SKalle Valo } 1708f79cbc77SKalle Valo 1709f79cbc77SKalle Valo memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status)); 1710f79cbc77SKalle Valo 1711f79cbc77SKalle Valo mac80211_hwsim_add_vendor_rtap(skb); 1712f79cbc77SKalle Valo 1713f79cbc77SKalle Valo data->rx_pkts++; 1714f79cbc77SKalle Valo data->rx_bytes += skb->len; 1715f79cbc77SKalle Valo ieee80211_rx_irqsafe(data->hw, skb); 1716f79cbc77SKalle Valo } 1717f79cbc77SKalle Valo 1718f79cbc77SKalle Valo static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, 1719f79cbc77SKalle Valo struct sk_buff *skb, 1720f79cbc77SKalle Valo struct ieee80211_channel *chan) 1721f79cbc77SKalle Valo { 1722f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv, *data2; 1723f79cbc77SKalle Valo bool ack = false; 1724f79cbc77SKalle Valo struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 1725f79cbc77SKalle Valo struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 1726f79cbc77SKalle Valo struct ieee80211_rx_status rx_status; 1727f79cbc77SKalle Valo u64 now; 1728f79cbc77SKalle Valo 1729f79cbc77SKalle Valo memset(&rx_status, 0, sizeof(rx_status)); 1730f79cbc77SKalle Valo rx_status.flag |= RX_FLAG_MACTIME_START; 1731f79cbc77SKalle Valo rx_status.freq = chan->center_freq; 1732f79cbc77SKalle Valo rx_status.freq_offset = chan->freq_offset ? 1 : 0; 1733f79cbc77SKalle Valo rx_status.band = chan->band; 1734f79cbc77SKalle Valo if (info->control.rates[0].flags & IEEE80211_TX_RC_VHT_MCS) { 1735f79cbc77SKalle Valo rx_status.rate_idx = 1736f79cbc77SKalle Valo ieee80211_rate_get_vht_mcs(&info->control.rates[0]); 1737f79cbc77SKalle Valo rx_status.nss = 1738f79cbc77SKalle Valo ieee80211_rate_get_vht_nss(&info->control.rates[0]); 1739f79cbc77SKalle Valo rx_status.encoding = RX_ENC_VHT; 1740f79cbc77SKalle Valo } else { 1741f79cbc77SKalle Valo rx_status.rate_idx = info->control.rates[0].idx; 1742f79cbc77SKalle Valo if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS) 1743f79cbc77SKalle Valo rx_status.encoding = RX_ENC_HT; 1744f79cbc77SKalle Valo } 1745f79cbc77SKalle Valo if (info->control.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) 1746f79cbc77SKalle Valo rx_status.bw = RATE_INFO_BW_40; 1747f79cbc77SKalle Valo else if (info->control.rates[0].flags & IEEE80211_TX_RC_80_MHZ_WIDTH) 1748f79cbc77SKalle Valo rx_status.bw = RATE_INFO_BW_80; 1749f79cbc77SKalle Valo else if (info->control.rates[0].flags & IEEE80211_TX_RC_160_MHZ_WIDTH) 1750f79cbc77SKalle Valo rx_status.bw = RATE_INFO_BW_160; 1751f79cbc77SKalle Valo else 1752f79cbc77SKalle Valo rx_status.bw = RATE_INFO_BW_20; 1753f79cbc77SKalle Valo if (info->control.rates[0].flags & IEEE80211_TX_RC_SHORT_GI) 1754f79cbc77SKalle Valo rx_status.enc_flags |= RX_ENC_FLAG_SHORT_GI; 1755f79cbc77SKalle Valo /* TODO: simulate optional packet loss */ 1756f79cbc77SKalle Valo rx_status.signal = data->rx_rssi; 1757f79cbc77SKalle Valo if (info->control.vif) 1758f79cbc77SKalle Valo rx_status.signal += info->control.vif->bss_conf.txpower; 1759f79cbc77SKalle Valo 1760f79cbc77SKalle Valo if (data->ps != PS_DISABLED) 1761f79cbc77SKalle Valo hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); 1762f79cbc77SKalle Valo 1763f79cbc77SKalle Valo /* release the skb's source info */ 1764f79cbc77SKalle Valo skb_orphan(skb); 1765f79cbc77SKalle Valo skb_dst_drop(skb); 1766f79cbc77SKalle Valo skb->mark = 0; 1767f79cbc77SKalle Valo skb_ext_reset(skb); 1768f79cbc77SKalle Valo nf_reset_ct(skb); 1769f79cbc77SKalle Valo 1770f79cbc77SKalle Valo /* 1771f79cbc77SKalle Valo * Get absolute mactime here so all HWs RX at the "same time", and 1772f79cbc77SKalle Valo * absolute TX time for beacon mactime so the timestamp matches. 1773f79cbc77SKalle Valo * Giving beacons a different mactime than non-beacons looks messy, but 1774f79cbc77SKalle Valo * it helps the Toffset be exact and a ~10us mactime discrepancy 1775f79cbc77SKalle Valo * probably doesn't really matter. 1776f79cbc77SKalle Valo */ 1777f79cbc77SKalle Valo if (ieee80211_is_beacon(hdr->frame_control) || 1778f79cbc77SKalle Valo ieee80211_is_probe_resp(hdr->frame_control)) { 1779f79cbc77SKalle Valo rx_status.boottime_ns = ktime_get_boottime_ns(); 1780f79cbc77SKalle Valo now = data->abs_bcn_ts; 1781f79cbc77SKalle Valo } else { 1782f79cbc77SKalle Valo now = mac80211_hwsim_get_tsf_raw(); 1783f79cbc77SKalle Valo } 1784f79cbc77SKalle Valo 1785f79cbc77SKalle Valo /* Copy skb to all enabled radios that are on the current frequency */ 1786f79cbc77SKalle Valo spin_lock(&hwsim_radio_lock); 1787f79cbc77SKalle Valo list_for_each_entry(data2, &hwsim_radios, list) { 1788f79cbc77SKalle Valo struct sk_buff *nskb; 1789f79cbc77SKalle Valo struct tx_iter_data tx_iter_data = { 1790f79cbc77SKalle Valo .receive = false, 1791f79cbc77SKalle Valo .channel = chan, 1792f79cbc77SKalle Valo }; 1793f79cbc77SKalle Valo 1794f79cbc77SKalle Valo if (data == data2) 1795f79cbc77SKalle Valo continue; 1796f79cbc77SKalle Valo 1797f79cbc77SKalle Valo if (!data2->started || (data2->idle && !data2->tmp_chan) || 1798f79cbc77SKalle Valo !hwsim_ps_rx_ok(data2, skb)) 1799f79cbc77SKalle Valo continue; 1800f79cbc77SKalle Valo 1801f79cbc77SKalle Valo if (!(data->group & data2->group)) 1802f79cbc77SKalle Valo continue; 1803f79cbc77SKalle Valo 1804f79cbc77SKalle Valo if (data->netgroup != data2->netgroup) 1805f79cbc77SKalle Valo continue; 1806f79cbc77SKalle Valo 1807f79cbc77SKalle Valo if (!hwsim_chans_compat(chan, data2->tmp_chan) && 1808f79cbc77SKalle Valo !hwsim_chans_compat(chan, data2->channel)) { 1809f79cbc77SKalle Valo ieee80211_iterate_active_interfaces_atomic( 1810f79cbc77SKalle Valo data2->hw, IEEE80211_IFACE_ITER_NORMAL, 1811f79cbc77SKalle Valo mac80211_hwsim_tx_iter, &tx_iter_data); 1812f79cbc77SKalle Valo if (!tx_iter_data.receive) 1813f79cbc77SKalle Valo continue; 1814f79cbc77SKalle Valo } 1815f79cbc77SKalle Valo 1816f79cbc77SKalle Valo /* 1817f79cbc77SKalle Valo * reserve some space for our vendor and the normal 1818f79cbc77SKalle Valo * radiotap header, since we're copying anyway 1819f79cbc77SKalle Valo */ 1820f79cbc77SKalle Valo if (skb->len < PAGE_SIZE && paged_rx) { 1821f79cbc77SKalle Valo struct page *page = alloc_page(GFP_ATOMIC); 1822f79cbc77SKalle Valo 1823f79cbc77SKalle Valo if (!page) 1824f79cbc77SKalle Valo continue; 1825f79cbc77SKalle Valo 1826f79cbc77SKalle Valo nskb = dev_alloc_skb(128); 1827f79cbc77SKalle Valo if (!nskb) { 1828f79cbc77SKalle Valo __free_page(page); 1829f79cbc77SKalle Valo continue; 1830f79cbc77SKalle Valo } 1831f79cbc77SKalle Valo 1832f79cbc77SKalle Valo memcpy(page_address(page), skb->data, skb->len); 1833f79cbc77SKalle Valo skb_add_rx_frag(nskb, 0, page, 0, skb->len, skb->len); 1834f79cbc77SKalle Valo } else { 1835f79cbc77SKalle Valo nskb = skb_copy(skb, GFP_ATOMIC); 1836f79cbc77SKalle Valo if (!nskb) 1837f79cbc77SKalle Valo continue; 1838f79cbc77SKalle Valo } 1839f79cbc77SKalle Valo 1840f79cbc77SKalle Valo if (mac80211_hwsim_addr_match(data2, hdr->addr1)) 1841f79cbc77SKalle Valo ack = true; 1842f79cbc77SKalle Valo 1843f79cbc77SKalle Valo rx_status.mactime = now + data2->tsf_offset; 1844f79cbc77SKalle Valo 1845f79cbc77SKalle Valo mac80211_hwsim_rx(data2, &rx_status, nskb); 1846f79cbc77SKalle Valo } 1847f79cbc77SKalle Valo spin_unlock(&hwsim_radio_lock); 1848f79cbc77SKalle Valo 1849f79cbc77SKalle Valo return ack; 1850f79cbc77SKalle Valo } 1851f79cbc77SKalle Valo 1852f79cbc77SKalle Valo static struct ieee80211_bss_conf * 1853f79cbc77SKalle Valo mac80211_hwsim_select_tx_link(struct mac80211_hwsim_data *data, 1854f79cbc77SKalle Valo struct ieee80211_vif *vif, 1855f79cbc77SKalle Valo struct ieee80211_sta *sta, 1856f79cbc77SKalle Valo struct ieee80211_hdr *hdr, 1857f79cbc77SKalle Valo struct ieee80211_link_sta **link_sta) 1858f79cbc77SKalle Valo { 1859f79cbc77SKalle Valo struct hwsim_sta_priv *sp = (void *)sta->drv_priv; 1860f79cbc77SKalle Valo int i; 1861f79cbc77SKalle Valo 186201ae1209SIlan Peer if (!ieee80211_vif_is_mld(vif)) 1863f79cbc77SKalle Valo return &vif->bss_conf; 1864f79cbc77SKalle Valo 1865f79cbc77SKalle Valo WARN_ON(is_multicast_ether_addr(hdr->addr1)); 1866f79cbc77SKalle Valo 18670cc80943SIlan Peer if (WARN_ON_ONCE(!sta || !sta->valid_links)) 1868f79cbc77SKalle Valo return &vif->bss_conf; 1869f79cbc77SKalle Valo 1870f79cbc77SKalle Valo for (i = 0; i < ARRAY_SIZE(vif->link_conf); i++) { 1871f79cbc77SKalle Valo struct ieee80211_bss_conf *bss_conf; 1872f79cbc77SKalle Valo unsigned int link_id; 1873f79cbc77SKalle Valo 1874f79cbc77SKalle Valo /* round-robin the available link IDs */ 1875f79cbc77SKalle Valo link_id = (sp->last_link + i + 1) % ARRAY_SIZE(vif->link_conf); 1876f79cbc77SKalle Valo 1877f79cbc77SKalle Valo if (!(vif->active_links & BIT(link_id))) 1878f79cbc77SKalle Valo continue; 1879f79cbc77SKalle Valo 1880f79cbc77SKalle Valo if (!(sp->active_links_rx & BIT(link_id))) 1881f79cbc77SKalle Valo continue; 1882f79cbc77SKalle Valo 1883f79cbc77SKalle Valo *link_sta = rcu_dereference(sta->link[link_id]); 1884f79cbc77SKalle Valo if (!*link_sta) 1885f79cbc77SKalle Valo continue; 1886f79cbc77SKalle Valo 1887f79cbc77SKalle Valo bss_conf = rcu_dereference(vif->link_conf[link_id]); 1888f79cbc77SKalle Valo if (WARN_ON_ONCE(!bss_conf)) 1889f79cbc77SKalle Valo continue; 1890f79cbc77SKalle Valo 1891f79cbc77SKalle Valo /* can happen while switching links */ 1892f79cbc77SKalle Valo if (!rcu_access_pointer(bss_conf->chanctx_conf)) 1893f79cbc77SKalle Valo continue; 1894f79cbc77SKalle Valo 1895f79cbc77SKalle Valo sp->last_link = link_id; 1896f79cbc77SKalle Valo return bss_conf; 1897f79cbc77SKalle Valo } 1898f79cbc77SKalle Valo 1899f79cbc77SKalle Valo return NULL; 1900f79cbc77SKalle Valo } 1901f79cbc77SKalle Valo 1902f79cbc77SKalle Valo static void mac80211_hwsim_tx(struct ieee80211_hw *hw, 1903f79cbc77SKalle Valo struct ieee80211_tx_control *control, 1904f79cbc77SKalle Valo struct sk_buff *skb) 1905f79cbc77SKalle Valo { 1906f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 1907f79cbc77SKalle Valo struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb); 1908f79cbc77SKalle Valo struct ieee80211_hdr *hdr = (void *)skb->data; 1909f79cbc77SKalle Valo struct ieee80211_chanctx_conf *chanctx_conf; 1910f79cbc77SKalle Valo struct ieee80211_channel *channel; 1911f79cbc77SKalle Valo bool ack; 1912f79cbc77SKalle Valo enum nl80211_chan_width confbw = NL80211_CHAN_WIDTH_20_NOHT; 1913f79cbc77SKalle Valo u32 _portid, i; 1914f79cbc77SKalle Valo 1915f79cbc77SKalle Valo if (WARN_ON(skb->len < 10)) { 1916f79cbc77SKalle Valo /* Should not happen; just a sanity check for addr1 use */ 1917f79cbc77SKalle Valo ieee80211_free_txskb(hw, skb); 1918f79cbc77SKalle Valo return; 1919f79cbc77SKalle Valo } 1920f79cbc77SKalle Valo 1921f79cbc77SKalle Valo if (!data->use_chanctx) { 1922f79cbc77SKalle Valo channel = data->channel; 1923f79cbc77SKalle Valo confbw = data->bw; 1924f79cbc77SKalle Valo } else if (txi->hw_queue == 4) { 1925f79cbc77SKalle Valo channel = data->tmp_chan; 1926f79cbc77SKalle Valo } else { 1927f79cbc77SKalle Valo u8 link = u32_get_bits(IEEE80211_SKB_CB(skb)->control.flags, 1928f79cbc77SKalle Valo IEEE80211_TX_CTRL_MLO_LINK); 1929f79cbc77SKalle Valo struct ieee80211_vif *vif = txi->control.vif; 1930f79cbc77SKalle Valo struct ieee80211_link_sta *link_sta = NULL; 1931f79cbc77SKalle Valo struct ieee80211_sta *sta = control->sta; 1932f79cbc77SKalle Valo struct ieee80211_bss_conf *bss_conf; 1933f79cbc77SKalle Valo 1934f79cbc77SKalle Valo if (link != IEEE80211_LINK_UNSPECIFIED) { 1935f79cbc77SKalle Valo bss_conf = rcu_dereference(txi->control.vif->link_conf[link]); 1936f79cbc77SKalle Valo if (sta) 1937f79cbc77SKalle Valo link_sta = rcu_dereference(sta->link[link]); 1938f79cbc77SKalle Valo } else { 1939f79cbc77SKalle Valo bss_conf = mac80211_hwsim_select_tx_link(data, vif, sta, 1940f79cbc77SKalle Valo hdr, &link_sta); 1941f79cbc77SKalle Valo } 1942f79cbc77SKalle Valo 19432d22be01SJohannes Berg if (unlikely(!bss_conf)) { 19442d22be01SJohannes Berg /* if it's an MLO STA, it might have deactivated all 19452d22be01SJohannes Berg * links temporarily - but we don't handle real PS in 19462d22be01SJohannes Berg * this code yet, so just drop the frame in that case 19472d22be01SJohannes Berg */ 19482d22be01SJohannes Berg WARN(link != IEEE80211_LINK_UNSPECIFIED || !sta || !sta->mlo, 19492d22be01SJohannes Berg "link:%d, sta:%pM, sta->mlo:%d\n", 19502d22be01SJohannes Berg link, sta ? sta->addr : NULL, sta ? sta->mlo : -1); 1951f79cbc77SKalle Valo ieee80211_free_txskb(hw, skb); 1952f79cbc77SKalle Valo return; 1953f79cbc77SKalle Valo } 1954f79cbc77SKalle Valo 1955f79cbc77SKalle Valo if (sta && sta->mlo) { 1956f79cbc77SKalle Valo if (WARN_ON(!link_sta)) { 1957f79cbc77SKalle Valo ieee80211_free_txskb(hw, skb); 1958f79cbc77SKalle Valo return; 1959f79cbc77SKalle Valo } 1960f79cbc77SKalle Valo /* address translation to link addresses on TX */ 1961f79cbc77SKalle Valo ether_addr_copy(hdr->addr1, link_sta->addr); 1962f79cbc77SKalle Valo ether_addr_copy(hdr->addr2, bss_conf->addr); 1963f79cbc77SKalle Valo /* translate A3 only if it's the BSSID */ 1964f79cbc77SKalle Valo if (!ieee80211_has_tods(hdr->frame_control) && 1965f79cbc77SKalle Valo !ieee80211_has_fromds(hdr->frame_control)) { 1966f79cbc77SKalle Valo if (ether_addr_equal(hdr->addr3, sta->addr)) 1967f79cbc77SKalle Valo ether_addr_copy(hdr->addr3, link_sta->addr); 1968f79cbc77SKalle Valo else if (ether_addr_equal(hdr->addr3, vif->addr)) 1969f79cbc77SKalle Valo ether_addr_copy(hdr->addr3, bss_conf->addr); 1970f79cbc77SKalle Valo } 1971f79cbc77SKalle Valo /* no need to look at A4, if present it's SA */ 1972f79cbc77SKalle Valo } 1973f79cbc77SKalle Valo 1974f79cbc77SKalle Valo chanctx_conf = rcu_dereference(bss_conf->chanctx_conf); 1975f79cbc77SKalle Valo if (chanctx_conf) { 1976f79cbc77SKalle Valo channel = chanctx_conf->def.chan; 1977f79cbc77SKalle Valo confbw = chanctx_conf->def.width; 1978f79cbc77SKalle Valo } else { 1979f79cbc77SKalle Valo channel = NULL; 1980f79cbc77SKalle Valo } 1981f79cbc77SKalle Valo } 1982f79cbc77SKalle Valo 1983f79cbc77SKalle Valo if (WARN(!channel, "TX w/o channel - queue = %d\n", txi->hw_queue)) { 1984f79cbc77SKalle Valo ieee80211_free_txskb(hw, skb); 1985f79cbc77SKalle Valo return; 1986f79cbc77SKalle Valo } 1987f79cbc77SKalle Valo 1988f79cbc77SKalle Valo if (data->idle && !data->tmp_chan) { 1989f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "Trying to TX when idle - reject\n"); 1990f79cbc77SKalle Valo ieee80211_free_txskb(hw, skb); 1991f79cbc77SKalle Valo return; 1992f79cbc77SKalle Valo } 1993f79cbc77SKalle Valo 1994f79cbc77SKalle Valo if (txi->control.vif) 1995f79cbc77SKalle Valo hwsim_check_magic(txi->control.vif); 1996f79cbc77SKalle Valo if (control->sta) 1997f79cbc77SKalle Valo hwsim_check_sta_magic(control->sta); 1998f79cbc77SKalle Valo 1999f79cbc77SKalle Valo if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE)) 2000f79cbc77SKalle Valo ieee80211_get_tx_rates(txi->control.vif, control->sta, skb, 2001f79cbc77SKalle Valo txi->control.rates, 2002f79cbc77SKalle Valo ARRAY_SIZE(txi->control.rates)); 2003f79cbc77SKalle Valo 2004f79cbc77SKalle Valo for (i = 0; i < ARRAY_SIZE(txi->control.rates); i++) { 2005f79cbc77SKalle Valo u16 rflags = txi->control.rates[i].flags; 2006f79cbc77SKalle Valo /* initialize to data->bw for 5/10 MHz handling */ 2007f79cbc77SKalle Valo enum nl80211_chan_width bw = data->bw; 2008f79cbc77SKalle Valo 2009f79cbc77SKalle Valo if (txi->control.rates[i].idx == -1) 2010f79cbc77SKalle Valo break; 2011f79cbc77SKalle Valo 2012f79cbc77SKalle Valo if (rflags & IEEE80211_TX_RC_40_MHZ_WIDTH) 2013f79cbc77SKalle Valo bw = NL80211_CHAN_WIDTH_40; 2014f79cbc77SKalle Valo else if (rflags & IEEE80211_TX_RC_80_MHZ_WIDTH) 2015f79cbc77SKalle Valo bw = NL80211_CHAN_WIDTH_80; 2016f79cbc77SKalle Valo else if (rflags & IEEE80211_TX_RC_160_MHZ_WIDTH) 2017f79cbc77SKalle Valo bw = NL80211_CHAN_WIDTH_160; 2018f79cbc77SKalle Valo 2019f79cbc77SKalle Valo if (WARN_ON(hwsim_get_chanwidth(bw) > hwsim_get_chanwidth(confbw))) 2020f79cbc77SKalle Valo return; 2021f79cbc77SKalle Valo } 2022f79cbc77SKalle Valo 2023f79cbc77SKalle Valo if (skb->len >= 24 + 8 && 2024f79cbc77SKalle Valo ieee80211_is_probe_resp(hdr->frame_control)) { 2025f79cbc77SKalle Valo /* fake header transmission time */ 2026f79cbc77SKalle Valo struct ieee80211_mgmt *mgmt; 2027f79cbc77SKalle Valo struct ieee80211_rate *txrate; 2028f79cbc77SKalle Valo /* TODO: get MCS */ 2029f79cbc77SKalle Valo int bitrate = 100; 2030f79cbc77SKalle Valo u64 ts; 2031f79cbc77SKalle Valo 2032f79cbc77SKalle Valo mgmt = (struct ieee80211_mgmt *)skb->data; 2033f79cbc77SKalle Valo txrate = ieee80211_get_tx_rate(hw, txi); 2034f79cbc77SKalle Valo if (txrate) 2035f79cbc77SKalle Valo bitrate = txrate->bitrate; 2036f79cbc77SKalle Valo ts = mac80211_hwsim_get_tsf_raw(); 2037f79cbc77SKalle Valo mgmt->u.probe_resp.timestamp = 2038f79cbc77SKalle Valo cpu_to_le64(ts + data->tsf_offset + 2039f79cbc77SKalle Valo 24 * 8 * 10 / bitrate); 2040f79cbc77SKalle Valo } 2041f79cbc77SKalle Valo 2042f79cbc77SKalle Valo mac80211_hwsim_monitor_rx(hw, skb, channel); 2043f79cbc77SKalle Valo 2044f79cbc77SKalle Valo /* wmediumd mode check */ 2045f79cbc77SKalle Valo _portid = READ_ONCE(data->wmediumd); 2046f79cbc77SKalle Valo 2047f79cbc77SKalle Valo if (_portid || hwsim_virtio_enabled) 2048f79cbc77SKalle Valo return mac80211_hwsim_tx_frame_nl(hw, skb, _portid, channel); 2049f79cbc77SKalle Valo 2050f79cbc77SKalle Valo /* NO wmediumd detected, perfect medium simulation */ 2051f79cbc77SKalle Valo data->tx_pkts++; 2052f79cbc77SKalle Valo data->tx_bytes += skb->len; 2053f79cbc77SKalle Valo ack = mac80211_hwsim_tx_frame_no_nl(hw, skb, channel); 2054f79cbc77SKalle Valo 2055f79cbc77SKalle Valo if (ack && skb->len >= 16) 2056f79cbc77SKalle Valo mac80211_hwsim_monitor_ack(channel, hdr->addr2); 2057f79cbc77SKalle Valo 2058f79cbc77SKalle Valo ieee80211_tx_info_clear_status(txi); 2059f79cbc77SKalle Valo 2060f79cbc77SKalle Valo /* frame was transmitted at most favorable rate at first attempt */ 2061f79cbc77SKalle Valo txi->control.rates[0].count = 1; 2062f79cbc77SKalle Valo txi->control.rates[1].idx = -1; 2063f79cbc77SKalle Valo 2064f79cbc77SKalle Valo if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) && ack) 2065f79cbc77SKalle Valo txi->flags |= IEEE80211_TX_STAT_ACK; 2066f79cbc77SKalle Valo ieee80211_tx_status_irqsafe(hw, skb); 2067f79cbc77SKalle Valo } 2068f79cbc77SKalle Valo 2069f79cbc77SKalle Valo 2070f79cbc77SKalle Valo static int mac80211_hwsim_start(struct ieee80211_hw *hw) 2071f79cbc77SKalle Valo { 2072f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 2073f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "%s\n", __func__); 2074f79cbc77SKalle Valo data->started = true; 2075f79cbc77SKalle Valo return 0; 2076f79cbc77SKalle Valo } 2077f79cbc77SKalle Valo 2078f79cbc77SKalle Valo 2079f79cbc77SKalle Valo static void mac80211_hwsim_stop(struct ieee80211_hw *hw) 2080f79cbc77SKalle Valo { 2081f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 2082f79cbc77SKalle Valo int i; 2083f79cbc77SKalle Valo 2084f79cbc77SKalle Valo data->started = false; 2085f79cbc77SKalle Valo 2086f79cbc77SKalle Valo for (i = 0; i < ARRAY_SIZE(data->link_data); i++) 2087f79cbc77SKalle Valo hrtimer_cancel(&data->link_data[i].beacon_timer); 2088f79cbc77SKalle Valo 2089f79cbc77SKalle Valo while (!skb_queue_empty(&data->pending)) 2090f79cbc77SKalle Valo ieee80211_free_txskb(hw, skb_dequeue(&data->pending)); 2091f79cbc77SKalle Valo 2092f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "%s\n", __func__); 2093f79cbc77SKalle Valo } 2094f79cbc77SKalle Valo 2095f79cbc77SKalle Valo 2096f79cbc77SKalle Valo static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw, 2097f79cbc77SKalle Valo struct ieee80211_vif *vif) 2098f79cbc77SKalle Valo { 2099f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "%s (type=%d mac_addr=%pM)\n", 2100f79cbc77SKalle Valo __func__, ieee80211_vif_type_p2p(vif), 2101f79cbc77SKalle Valo vif->addr); 2102f79cbc77SKalle Valo hwsim_set_magic(vif); 2103f79cbc77SKalle Valo 2104f79cbc77SKalle Valo if (vif->type != NL80211_IFTYPE_MONITOR) 2105f79cbc77SKalle Valo mac80211_hwsim_config_mac_nl(hw, vif->addr, true); 2106f79cbc77SKalle Valo 2107f79cbc77SKalle Valo vif->cab_queue = 0; 2108f79cbc77SKalle Valo vif->hw_queue[IEEE80211_AC_VO] = 0; 2109f79cbc77SKalle Valo vif->hw_queue[IEEE80211_AC_VI] = 1; 2110f79cbc77SKalle Valo vif->hw_queue[IEEE80211_AC_BE] = 2; 2111f79cbc77SKalle Valo vif->hw_queue[IEEE80211_AC_BK] = 3; 2112f79cbc77SKalle Valo 2113f79cbc77SKalle Valo return 0; 2114f79cbc77SKalle Valo } 2115f79cbc77SKalle Valo 2116f79cbc77SKalle Valo 2117f79cbc77SKalle Valo static int mac80211_hwsim_change_interface(struct ieee80211_hw *hw, 2118f79cbc77SKalle Valo struct ieee80211_vif *vif, 2119f79cbc77SKalle Valo enum nl80211_iftype newtype, 2120f79cbc77SKalle Valo bool newp2p) 2121f79cbc77SKalle Valo { 2122f79cbc77SKalle Valo newtype = ieee80211_iftype_p2p(newtype, newp2p); 2123f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, 2124f79cbc77SKalle Valo "%s (old type=%d, new type=%d, mac_addr=%pM)\n", 2125f79cbc77SKalle Valo __func__, ieee80211_vif_type_p2p(vif), 2126f79cbc77SKalle Valo newtype, vif->addr); 2127f79cbc77SKalle Valo hwsim_check_magic(vif); 2128f79cbc77SKalle Valo 2129f79cbc77SKalle Valo /* 2130f79cbc77SKalle Valo * interface may change from non-AP to AP in 2131f79cbc77SKalle Valo * which case this needs to be set up again 2132f79cbc77SKalle Valo */ 2133f79cbc77SKalle Valo vif->cab_queue = 0; 2134f79cbc77SKalle Valo 2135f79cbc77SKalle Valo return 0; 2136f79cbc77SKalle Valo } 2137f79cbc77SKalle Valo 2138f79cbc77SKalle Valo static void mac80211_hwsim_remove_interface( 2139f79cbc77SKalle Valo struct ieee80211_hw *hw, struct ieee80211_vif *vif) 2140f79cbc77SKalle Valo { 2141f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "%s (type=%d mac_addr=%pM)\n", 2142f79cbc77SKalle Valo __func__, ieee80211_vif_type_p2p(vif), 2143f79cbc77SKalle Valo vif->addr); 2144f79cbc77SKalle Valo hwsim_check_magic(vif); 2145f79cbc77SKalle Valo hwsim_clear_magic(vif); 2146f79cbc77SKalle Valo if (vif->type != NL80211_IFTYPE_MONITOR) 2147f79cbc77SKalle Valo mac80211_hwsim_config_mac_nl(hw, vif->addr, false); 2148f79cbc77SKalle Valo } 2149f79cbc77SKalle Valo 2150f79cbc77SKalle Valo static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, 2151f79cbc77SKalle Valo struct sk_buff *skb, 2152f79cbc77SKalle Valo struct ieee80211_channel *chan) 2153f79cbc77SKalle Valo { 2154f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 2155f79cbc77SKalle Valo u32 _portid = READ_ONCE(data->wmediumd); 2156f79cbc77SKalle Valo 2157f79cbc77SKalle Valo if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE)) { 2158f79cbc77SKalle Valo struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb); 2159f79cbc77SKalle Valo ieee80211_get_tx_rates(txi->control.vif, NULL, skb, 2160f79cbc77SKalle Valo txi->control.rates, 2161f79cbc77SKalle Valo ARRAY_SIZE(txi->control.rates)); 2162f79cbc77SKalle Valo } 2163f79cbc77SKalle Valo 2164f79cbc77SKalle Valo mac80211_hwsim_monitor_rx(hw, skb, chan); 2165f79cbc77SKalle Valo 2166f79cbc77SKalle Valo if (_portid || hwsim_virtio_enabled) 2167f79cbc77SKalle Valo return mac80211_hwsim_tx_frame_nl(hw, skb, _portid, chan); 2168f79cbc77SKalle Valo 2169f79cbc77SKalle Valo data->tx_pkts++; 2170f79cbc77SKalle Valo data->tx_bytes += skb->len; 2171f79cbc77SKalle Valo mac80211_hwsim_tx_frame_no_nl(hw, skb, chan); 2172f79cbc77SKalle Valo dev_kfree_skb(skb); 2173f79cbc77SKalle Valo } 2174f79cbc77SKalle Valo 2175b3a912e3SAloka Dixit static void __mac80211_hwsim_beacon_tx(struct ieee80211_bss_conf *link_conf, 2176b3a912e3SAloka Dixit struct mac80211_hwsim_data *data, 2177b3a912e3SAloka Dixit struct ieee80211_hw *hw, 2178b3a912e3SAloka Dixit struct ieee80211_vif *vif, 2179b3a912e3SAloka Dixit struct sk_buff *skb) 2180f79cbc77SKalle Valo { 2181f79cbc77SKalle Valo struct ieee80211_tx_info *info; 2182f79cbc77SKalle Valo struct ieee80211_rate *txrate; 2183f79cbc77SKalle Valo struct ieee80211_mgmt *mgmt; 2184f79cbc77SKalle Valo /* TODO: get MCS */ 2185f79cbc77SKalle Valo int bitrate = 100; 2186f79cbc77SKalle Valo 2187f79cbc77SKalle Valo info = IEEE80211_SKB_CB(skb); 2188f79cbc77SKalle Valo if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE)) 2189f79cbc77SKalle Valo ieee80211_get_tx_rates(vif, NULL, skb, 2190f79cbc77SKalle Valo info->control.rates, 2191f79cbc77SKalle Valo ARRAY_SIZE(info->control.rates)); 2192f79cbc77SKalle Valo 2193f79cbc77SKalle Valo txrate = ieee80211_get_tx_rate(hw, info); 2194f79cbc77SKalle Valo if (txrate) 2195f79cbc77SKalle Valo bitrate = txrate->bitrate; 2196f79cbc77SKalle Valo 2197f79cbc77SKalle Valo mgmt = (struct ieee80211_mgmt *) skb->data; 2198f79cbc77SKalle Valo /* fake header transmission time */ 2199f79cbc77SKalle Valo data->abs_bcn_ts = mac80211_hwsim_get_tsf_raw(); 2200f79cbc77SKalle Valo if (ieee80211_is_s1g_beacon(mgmt->frame_control)) { 2201f79cbc77SKalle Valo struct ieee80211_ext *ext = (void *) mgmt; 2202f79cbc77SKalle Valo 2203f79cbc77SKalle Valo ext->u.s1g_beacon.timestamp = cpu_to_le32(data->abs_bcn_ts + 2204f79cbc77SKalle Valo data->tsf_offset + 2205f79cbc77SKalle Valo 10 * 8 * 10 / 2206f79cbc77SKalle Valo bitrate); 2207f79cbc77SKalle Valo } else { 2208f79cbc77SKalle Valo mgmt->u.beacon.timestamp = cpu_to_le64(data->abs_bcn_ts + 2209f79cbc77SKalle Valo data->tsf_offset + 2210f79cbc77SKalle Valo 24 * 8 * 10 / 2211f79cbc77SKalle Valo bitrate); 2212f79cbc77SKalle Valo } 2213f79cbc77SKalle Valo 2214f79cbc77SKalle Valo mac80211_hwsim_tx_frame(hw, skb, 2215f79cbc77SKalle Valo rcu_dereference(link_conf->chanctx_conf)->def.chan); 2216b3a912e3SAloka Dixit } 2217b3a912e3SAloka Dixit 2218b3a912e3SAloka Dixit static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, 2219b3a912e3SAloka Dixit struct ieee80211_vif *vif) 2220b3a912e3SAloka Dixit { 2221b3a912e3SAloka Dixit struct mac80211_hwsim_link_data *link_data = arg; 2222b3a912e3SAloka Dixit u32 link_id = link_data->link_id; 2223b3a912e3SAloka Dixit struct ieee80211_bss_conf *link_conf; 2224b3a912e3SAloka Dixit struct mac80211_hwsim_data *data = 2225b3a912e3SAloka Dixit container_of(link_data, struct mac80211_hwsim_data, 2226b3a912e3SAloka Dixit link_data[link_id]); 2227b3a912e3SAloka Dixit struct ieee80211_hw *hw = data->hw; 2228b3a912e3SAloka Dixit struct sk_buff *skb; 2229b3a912e3SAloka Dixit 2230b3a912e3SAloka Dixit hwsim_check_magic(vif); 2231b3a912e3SAloka Dixit 2232b3a912e3SAloka Dixit link_conf = rcu_dereference(vif->link_conf[link_id]); 2233b3a912e3SAloka Dixit if (!link_conf) 2234b3a912e3SAloka Dixit return; 2235b3a912e3SAloka Dixit 2236b3a912e3SAloka Dixit if (vif->type != NL80211_IFTYPE_AP && 2237b3a912e3SAloka Dixit vif->type != NL80211_IFTYPE_MESH_POINT && 2238b3a912e3SAloka Dixit vif->type != NL80211_IFTYPE_ADHOC && 2239b3a912e3SAloka Dixit vif->type != NL80211_IFTYPE_OCB) 2240b3a912e3SAloka Dixit return; 2241b3a912e3SAloka Dixit 2242c4f4d9f7SAloka Dixit if (vif->mbssid_tx_vif && vif->mbssid_tx_vif != vif) 2243c4f4d9f7SAloka Dixit return; 2244c4f4d9f7SAloka Dixit 22450dd45ebcSAloka Dixit if (vif->bss_conf.ema_ap) { 22460dd45ebcSAloka Dixit struct ieee80211_ema_beacons *ema; 22470dd45ebcSAloka Dixit u8 i = 0; 22480dd45ebcSAloka Dixit 22490dd45ebcSAloka Dixit ema = ieee80211_beacon_get_template_ema_list(hw, vif, link_id); 22500dd45ebcSAloka Dixit if (!ema || !ema->cnt) 22510dd45ebcSAloka Dixit return; 22520dd45ebcSAloka Dixit 22530dd45ebcSAloka Dixit for (i = 0; i < ema->cnt; i++) { 22540dd45ebcSAloka Dixit __mac80211_hwsim_beacon_tx(link_conf, data, hw, vif, 22550dd45ebcSAloka Dixit ema->bcn[i].skb); 22560dd45ebcSAloka Dixit ema->bcn[i].skb = NULL; /* Already freed */ 22570dd45ebcSAloka Dixit } 22580dd45ebcSAloka Dixit ieee80211_beacon_free_ema_list(ema); 22590dd45ebcSAloka Dixit } else { 2260b3a912e3SAloka Dixit skb = ieee80211_beacon_get(hw, vif, link_id); 2261b3a912e3SAloka Dixit if (!skb) 2262b3a912e3SAloka Dixit return; 2263b3a912e3SAloka Dixit 2264b3a912e3SAloka Dixit __mac80211_hwsim_beacon_tx(link_conf, data, hw, vif, skb); 22650dd45ebcSAloka Dixit } 2266f79cbc77SKalle Valo 2267f79cbc77SKalle Valo while ((skb = ieee80211_get_buffered_bc(hw, vif)) != NULL) { 2268f79cbc77SKalle Valo mac80211_hwsim_tx_frame(hw, skb, 2269f79cbc77SKalle Valo rcu_dereference(link_conf->chanctx_conf)->def.chan); 2270f79cbc77SKalle Valo } 2271f79cbc77SKalle Valo 2272f79cbc77SKalle Valo if (link_conf->csa_active && ieee80211_beacon_cntdwn_is_complete(vif)) 2273f79cbc77SKalle Valo ieee80211_csa_finish(vif); 2274f79cbc77SKalle Valo } 2275f79cbc77SKalle Valo 2276f79cbc77SKalle Valo static enum hrtimer_restart 2277f79cbc77SKalle Valo mac80211_hwsim_beacon(struct hrtimer *timer) 2278f79cbc77SKalle Valo { 2279f79cbc77SKalle Valo struct mac80211_hwsim_link_data *link_data = 2280f79cbc77SKalle Valo container_of(timer, struct mac80211_hwsim_link_data, beacon_timer); 2281f79cbc77SKalle Valo struct mac80211_hwsim_data *data = 2282f79cbc77SKalle Valo container_of(link_data, struct mac80211_hwsim_data, 2283f79cbc77SKalle Valo link_data[link_data->link_id]); 2284f79cbc77SKalle Valo struct ieee80211_hw *hw = data->hw; 2285f79cbc77SKalle Valo u64 bcn_int = link_data->beacon_int; 2286f79cbc77SKalle Valo 2287f79cbc77SKalle Valo if (!data->started) 2288f79cbc77SKalle Valo return HRTIMER_NORESTART; 2289f79cbc77SKalle Valo 2290f79cbc77SKalle Valo ieee80211_iterate_active_interfaces_atomic( 2291f79cbc77SKalle Valo hw, IEEE80211_IFACE_ITER_NORMAL, 2292f79cbc77SKalle Valo mac80211_hwsim_beacon_tx, link_data); 2293f79cbc77SKalle Valo 2294f79cbc77SKalle Valo /* beacon at new TBTT + beacon interval */ 2295f79cbc77SKalle Valo if (data->bcn_delta) { 2296f79cbc77SKalle Valo bcn_int -= data->bcn_delta; 2297f79cbc77SKalle Valo data->bcn_delta = 0; 2298f79cbc77SKalle Valo } 2299f79cbc77SKalle Valo hrtimer_forward_now(&link_data->beacon_timer, 2300f79cbc77SKalle Valo ns_to_ktime(bcn_int * NSEC_PER_USEC)); 2301f79cbc77SKalle Valo return HRTIMER_RESTART; 2302f79cbc77SKalle Valo } 2303f79cbc77SKalle Valo 2304f79cbc77SKalle Valo static const char * const hwsim_chanwidths[] = { 2305f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_5] = "ht5", 2306f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_10] = "ht10", 2307f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_20_NOHT] = "noht", 2308f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_20] = "ht20", 2309f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_40] = "ht40", 2310f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_80] = "vht80", 2311f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_80P80] = "vht80p80", 2312f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_160] = "vht160", 2313f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_1] = "1MHz", 2314f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_2] = "2MHz", 2315f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_4] = "4MHz", 2316f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_8] = "8MHz", 2317f79cbc77SKalle Valo [NL80211_CHAN_WIDTH_16] = "16MHz", 2318f79cbc77SKalle Valo }; 2319f79cbc77SKalle Valo 2320f79cbc77SKalle Valo static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) 2321f79cbc77SKalle Valo { 2322f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 2323f79cbc77SKalle Valo struct ieee80211_conf *conf = &hw->conf; 2324f79cbc77SKalle Valo static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = { 2325f79cbc77SKalle Valo [IEEE80211_SMPS_AUTOMATIC] = "auto", 2326f79cbc77SKalle Valo [IEEE80211_SMPS_OFF] = "off", 2327f79cbc77SKalle Valo [IEEE80211_SMPS_STATIC] = "static", 2328f79cbc77SKalle Valo [IEEE80211_SMPS_DYNAMIC] = "dynamic", 2329f79cbc77SKalle Valo }; 2330f79cbc77SKalle Valo int idx; 2331f79cbc77SKalle Valo 2332f79cbc77SKalle Valo if (conf->chandef.chan) 2333f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, 2334f79cbc77SKalle Valo "%s (freq=%d(%d - %d)/%s idle=%d ps=%d smps=%s)\n", 2335f79cbc77SKalle Valo __func__, 2336f79cbc77SKalle Valo conf->chandef.chan->center_freq, 2337f79cbc77SKalle Valo conf->chandef.center_freq1, 2338f79cbc77SKalle Valo conf->chandef.center_freq2, 2339f79cbc77SKalle Valo hwsim_chanwidths[conf->chandef.width], 2340f79cbc77SKalle Valo !!(conf->flags & IEEE80211_CONF_IDLE), 2341f79cbc77SKalle Valo !!(conf->flags & IEEE80211_CONF_PS), 2342f79cbc77SKalle Valo smps_modes[conf->smps_mode]); 2343f79cbc77SKalle Valo else 2344f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, 2345f79cbc77SKalle Valo "%s (freq=0 idle=%d ps=%d smps=%s)\n", 2346f79cbc77SKalle Valo __func__, 2347f79cbc77SKalle Valo !!(conf->flags & IEEE80211_CONF_IDLE), 2348f79cbc77SKalle Valo !!(conf->flags & IEEE80211_CONF_PS), 2349f79cbc77SKalle Valo smps_modes[conf->smps_mode]); 2350f79cbc77SKalle Valo 2351f79cbc77SKalle Valo data->idle = !!(conf->flags & IEEE80211_CONF_IDLE); 2352f79cbc77SKalle Valo 2353f79cbc77SKalle Valo WARN_ON(conf->chandef.chan && data->use_chanctx); 2354f79cbc77SKalle Valo 2355f79cbc77SKalle Valo mutex_lock(&data->mutex); 2356f79cbc77SKalle Valo if (data->scanning && conf->chandef.chan) { 2357f79cbc77SKalle Valo for (idx = 0; idx < ARRAY_SIZE(data->survey_data); idx++) { 2358f79cbc77SKalle Valo if (data->survey_data[idx].channel == data->channel) { 2359f79cbc77SKalle Valo data->survey_data[idx].start = 2360f79cbc77SKalle Valo data->survey_data[idx].next_start; 2361f79cbc77SKalle Valo data->survey_data[idx].end = jiffies; 2362f79cbc77SKalle Valo break; 2363f79cbc77SKalle Valo } 2364f79cbc77SKalle Valo } 2365f79cbc77SKalle Valo 2366f79cbc77SKalle Valo data->channel = conf->chandef.chan; 2367f79cbc77SKalle Valo data->bw = conf->chandef.width; 2368f79cbc77SKalle Valo 2369f79cbc77SKalle Valo for (idx = 0; idx < ARRAY_SIZE(data->survey_data); idx++) { 2370f79cbc77SKalle Valo if (data->survey_data[idx].channel && 2371f79cbc77SKalle Valo data->survey_data[idx].channel != data->channel) 2372f79cbc77SKalle Valo continue; 2373f79cbc77SKalle Valo data->survey_data[idx].channel = data->channel; 2374f79cbc77SKalle Valo data->survey_data[idx].next_start = jiffies; 2375f79cbc77SKalle Valo break; 2376f79cbc77SKalle Valo } 2377f79cbc77SKalle Valo } else { 2378f79cbc77SKalle Valo data->channel = conf->chandef.chan; 2379f79cbc77SKalle Valo data->bw = conf->chandef.width; 2380f79cbc77SKalle Valo } 2381f79cbc77SKalle Valo mutex_unlock(&data->mutex); 2382f79cbc77SKalle Valo 2383f79cbc77SKalle Valo for (idx = 0; idx < ARRAY_SIZE(data->link_data); idx++) { 2384f79cbc77SKalle Valo struct mac80211_hwsim_link_data *link_data = 2385f79cbc77SKalle Valo &data->link_data[idx]; 2386f79cbc77SKalle Valo 2387f79cbc77SKalle Valo if (!data->started || !link_data->beacon_int) { 2388f79cbc77SKalle Valo hrtimer_cancel(&link_data->beacon_timer); 2389f79cbc77SKalle Valo } else if (!hrtimer_is_queued(&link_data->beacon_timer)) { 2390f79cbc77SKalle Valo u64 tsf = mac80211_hwsim_get_tsf(hw, NULL); 2391f79cbc77SKalle Valo u32 bcn_int = link_data->beacon_int; 2392f79cbc77SKalle Valo u64 until_tbtt = bcn_int - do_div(tsf, bcn_int); 2393f79cbc77SKalle Valo 2394f79cbc77SKalle Valo hrtimer_start(&link_data->beacon_timer, 2395f79cbc77SKalle Valo ns_to_ktime(until_tbtt * NSEC_PER_USEC), 2396f79cbc77SKalle Valo HRTIMER_MODE_REL_SOFT); 2397f79cbc77SKalle Valo } 2398f79cbc77SKalle Valo } 2399f79cbc77SKalle Valo 2400f79cbc77SKalle Valo return 0; 2401f79cbc77SKalle Valo } 2402f79cbc77SKalle Valo 2403f79cbc77SKalle Valo 2404f79cbc77SKalle Valo static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw, 2405f79cbc77SKalle Valo unsigned int changed_flags, 2406f79cbc77SKalle Valo unsigned int *total_flags,u64 multicast) 2407f79cbc77SKalle Valo { 2408f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 2409f79cbc77SKalle Valo 2410f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "%s\n", __func__); 2411f79cbc77SKalle Valo 2412f79cbc77SKalle Valo data->rx_filter = 0; 2413f79cbc77SKalle Valo if (*total_flags & FIF_ALLMULTI) 2414f79cbc77SKalle Valo data->rx_filter |= FIF_ALLMULTI; 2415f79cbc77SKalle Valo if (*total_flags & FIF_MCAST_ACTION) 2416f79cbc77SKalle Valo data->rx_filter |= FIF_MCAST_ACTION; 2417f79cbc77SKalle Valo 2418f79cbc77SKalle Valo *total_flags = data->rx_filter; 2419f79cbc77SKalle Valo } 2420f79cbc77SKalle Valo 2421f79cbc77SKalle Valo static void mac80211_hwsim_bcn_en_iter(void *data, u8 *mac, 2422f79cbc77SKalle Valo struct ieee80211_vif *vif) 2423f79cbc77SKalle Valo { 2424f79cbc77SKalle Valo unsigned int *count = data; 2425f79cbc77SKalle Valo struct hwsim_vif_priv *vp = (void *)vif->drv_priv; 2426f79cbc77SKalle Valo 2427f79cbc77SKalle Valo if (vp->bcn_en) 2428f79cbc77SKalle Valo (*count)++; 2429f79cbc77SKalle Valo } 2430f79cbc77SKalle Valo 2431f79cbc77SKalle Valo static void mac80211_hwsim_vif_info_changed(struct ieee80211_hw *hw, 2432f79cbc77SKalle Valo struct ieee80211_vif *vif, 2433f79cbc77SKalle Valo u64 changed) 2434f79cbc77SKalle Valo { 2435f79cbc77SKalle Valo struct hwsim_vif_priv *vp = (void *)vif->drv_priv; 2436f79cbc77SKalle Valo 2437f79cbc77SKalle Valo hwsim_check_magic(vif); 2438f79cbc77SKalle Valo 2439f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "%s(changed=0x%llx vif->addr=%pM)\n", 2440f79cbc77SKalle Valo __func__, changed, vif->addr); 2441f79cbc77SKalle Valo 2442f79cbc77SKalle Valo if (changed & BSS_CHANGED_ASSOC) { 2443f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, " ASSOC: assoc=%d aid=%d\n", 2444f79cbc77SKalle Valo vif->cfg.assoc, vif->cfg.aid); 2445f79cbc77SKalle Valo vp->assoc = vif->cfg.assoc; 2446f79cbc77SKalle Valo vp->aid = vif->cfg.aid; 2447f79cbc77SKalle Valo } 2448f79cbc77SKalle Valo } 2449f79cbc77SKalle Valo 2450f79cbc77SKalle Valo static void mac80211_hwsim_link_info_changed(struct ieee80211_hw *hw, 2451f79cbc77SKalle Valo struct ieee80211_vif *vif, 2452f79cbc77SKalle Valo struct ieee80211_bss_conf *info, 2453f79cbc77SKalle Valo u64 changed) 2454f79cbc77SKalle Valo { 2455f79cbc77SKalle Valo struct hwsim_vif_priv *vp = (void *)vif->drv_priv; 2456f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 2457f79cbc77SKalle Valo unsigned int link_id = info->link_id; 2458f79cbc77SKalle Valo struct mac80211_hwsim_link_data *link_data = &data->link_data[link_id]; 2459f79cbc77SKalle Valo 2460f79cbc77SKalle Valo hwsim_check_magic(vif); 2461f79cbc77SKalle Valo 2462f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "%s(changed=0x%llx vif->addr=%pM, link id %u)\n", 2463f79cbc77SKalle Valo __func__, (unsigned long long)changed, vif->addr, link_id); 2464f79cbc77SKalle Valo 2465f79cbc77SKalle Valo if (changed & BSS_CHANGED_BSSID) { 2466f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "%s: BSSID changed: %pM\n", 2467f79cbc77SKalle Valo __func__, info->bssid); 2468f79cbc77SKalle Valo memcpy(vp->bssid, info->bssid, ETH_ALEN); 2469f79cbc77SKalle Valo } 2470f79cbc77SKalle Valo 2471f79cbc77SKalle Valo if (changed & BSS_CHANGED_BEACON_ENABLED) { 2472f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, " BCN EN: %d (BI=%u)\n", 2473f79cbc77SKalle Valo info->enable_beacon, info->beacon_int); 2474f79cbc77SKalle Valo vp->bcn_en = info->enable_beacon; 2475f79cbc77SKalle Valo if (data->started && 2476f79cbc77SKalle Valo !hrtimer_is_queued(&link_data->beacon_timer) && 2477f79cbc77SKalle Valo info->enable_beacon) { 2478f79cbc77SKalle Valo u64 tsf, until_tbtt; 2479f79cbc77SKalle Valo u32 bcn_int; 2480f79cbc77SKalle Valo link_data->beacon_int = info->beacon_int * 1024; 2481f79cbc77SKalle Valo tsf = mac80211_hwsim_get_tsf(hw, vif); 2482f79cbc77SKalle Valo bcn_int = link_data->beacon_int; 2483f79cbc77SKalle Valo until_tbtt = bcn_int - do_div(tsf, bcn_int); 2484f79cbc77SKalle Valo 2485f79cbc77SKalle Valo hrtimer_start(&link_data->beacon_timer, 2486f79cbc77SKalle Valo ns_to_ktime(until_tbtt * NSEC_PER_USEC), 2487f79cbc77SKalle Valo HRTIMER_MODE_REL_SOFT); 2488f79cbc77SKalle Valo } else if (!info->enable_beacon) { 2489f79cbc77SKalle Valo unsigned int count = 0; 2490f79cbc77SKalle Valo ieee80211_iterate_active_interfaces_atomic( 2491f79cbc77SKalle Valo data->hw, IEEE80211_IFACE_ITER_NORMAL, 2492f79cbc77SKalle Valo mac80211_hwsim_bcn_en_iter, &count); 2493f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, " beaconing vifs remaining: %u", 2494f79cbc77SKalle Valo count); 2495f79cbc77SKalle Valo if (count == 0) { 2496f79cbc77SKalle Valo hrtimer_cancel(&link_data->beacon_timer); 2497f79cbc77SKalle Valo link_data->beacon_int = 0; 2498f79cbc77SKalle Valo } 2499f79cbc77SKalle Valo } 2500f79cbc77SKalle Valo } 2501f79cbc77SKalle Valo 2502f79cbc77SKalle Valo if (changed & BSS_CHANGED_ERP_CTS_PROT) { 2503f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, " ERP_CTS_PROT: %d\n", 2504f79cbc77SKalle Valo info->use_cts_prot); 2505f79cbc77SKalle Valo } 2506f79cbc77SKalle Valo 2507f79cbc77SKalle Valo if (changed & BSS_CHANGED_ERP_PREAMBLE) { 2508f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, " ERP_PREAMBLE: %d\n", 2509f79cbc77SKalle Valo info->use_short_preamble); 2510f79cbc77SKalle Valo } 2511f79cbc77SKalle Valo 2512f79cbc77SKalle Valo if (changed & BSS_CHANGED_ERP_SLOT) { 2513f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, " ERP_SLOT: %d\n", info->use_short_slot); 2514f79cbc77SKalle Valo } 2515f79cbc77SKalle Valo 2516f79cbc77SKalle Valo if (changed & BSS_CHANGED_HT) { 2517f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, " HT: op_mode=0x%x\n", 2518f79cbc77SKalle Valo info->ht_operation_mode); 2519f79cbc77SKalle Valo } 2520f79cbc77SKalle Valo 2521f79cbc77SKalle Valo if (changed & BSS_CHANGED_BASIC_RATES) { 2522f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, " BASIC_RATES: 0x%llx\n", 2523f79cbc77SKalle Valo (unsigned long long) info->basic_rates); 2524f79cbc77SKalle Valo } 2525f79cbc77SKalle Valo 2526f79cbc77SKalle Valo if (changed & BSS_CHANGED_TXPOWER) 2527f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, " TX Power: %d dBm\n", info->txpower); 2528f79cbc77SKalle Valo } 2529f79cbc77SKalle Valo 2530f79cbc77SKalle Valo static void 2531f79cbc77SKalle Valo mac80211_hwsim_sta_rc_update(struct ieee80211_hw *hw, 2532f79cbc77SKalle Valo struct ieee80211_vif *vif, 2533f79cbc77SKalle Valo struct ieee80211_sta *sta, 2534f79cbc77SKalle Valo u32 changed) 2535f79cbc77SKalle Valo { 2536f79cbc77SKalle Valo struct mac80211_hwsim_data *data = hw->priv; 2537f79cbc77SKalle Valo u32 bw = U32_MAX; 2538f79cbc77SKalle Valo int link_id; 2539f79cbc77SKalle Valo 2540f79cbc77SKalle Valo rcu_read_lock(); 2541f79cbc77SKalle Valo for (link_id = 0; 2542f79cbc77SKalle Valo link_id < ARRAY_SIZE(vif->link_conf); 2543f79cbc77SKalle Valo link_id++) { 2544f79cbc77SKalle Valo enum nl80211_chan_width confbw = NL80211_CHAN_WIDTH_20_NOHT; 2545f79cbc77SKalle Valo struct ieee80211_bss_conf *vif_conf; 2546f79cbc77SKalle Valo struct ieee80211_link_sta *link_sta; 2547f79cbc77SKalle Valo 2548f79cbc77SKalle Valo link_sta = rcu_dereference(sta->link[link_id]); 2549f79cbc77SKalle Valo 2550f79cbc77SKalle Valo if (!link_sta) 2551f79cbc77SKalle Valo continue; 2552f79cbc77SKalle Valo 2553f79cbc77SKalle Valo switch (link_sta->bandwidth) { 2554f79cbc77SKalle Valo #define C(_bw) case IEEE80211_STA_RX_BW_##_bw: bw = _bw; break 2555f79cbc77SKalle Valo C(20); 2556f79cbc77SKalle Valo C(40); 2557f79cbc77SKalle Valo C(80); 2558f79cbc77SKalle Valo C(160); 2559f79cbc77SKalle Valo C(320); 2560f79cbc77SKalle Valo #undef C 2561f79cbc77SKalle Valo } 2562f79cbc77SKalle Valo 2563f79cbc77SKalle Valo if (!data->use_chanctx) { 2564f79cbc77SKalle Valo confbw = data->bw; 2565f79cbc77SKalle Valo } else { 2566f79cbc77SKalle Valo struct ieee80211_chanctx_conf *chanctx_conf; 2567f79cbc77SKalle Valo 2568f79cbc77SKalle Valo vif_conf = rcu_dereference(vif->link_conf[link_id]); 2569f79cbc77SKalle Valo if (WARN_ON(!vif_conf)) 2570f79cbc77SKalle Valo continue; 2571f79cbc77SKalle Valo 2572f79cbc77SKalle Valo chanctx_conf = rcu_dereference(vif_conf->chanctx_conf); 2573f79cbc77SKalle Valo 2574f79cbc77SKalle Valo if (!WARN_ON(!chanctx_conf)) 2575f79cbc77SKalle Valo confbw = chanctx_conf->def.width; 2576f79cbc77SKalle Valo } 2577f79cbc77SKalle Valo 2578f79cbc77SKalle Valo WARN(bw > hwsim_get_chanwidth(confbw), 2579f79cbc77SKalle Valo "intf %pM [link=%d]: bad STA %pM bandwidth %d MHz (%d) > channel config %d MHz (%d)\n", 2580f79cbc77SKalle Valo vif->addr, link_id, sta->addr, bw, sta->deflink.bandwidth, 2581f79cbc77SKalle Valo hwsim_get_chanwidth(data->bw), data->bw); 2582f79cbc77SKalle Valo 2583f79cbc77SKalle Valo 2584f79cbc77SKalle Valo } 2585f79cbc77SKalle Valo rcu_read_unlock(); 2586f79cbc77SKalle Valo 2587f79cbc77SKalle Valo 2588f79cbc77SKalle Valo } 2589f79cbc77SKalle Valo 2590f79cbc77SKalle Valo static int mac80211_hwsim_sta_add(struct ieee80211_hw *hw, 2591f79cbc77SKalle Valo struct ieee80211_vif *vif, 2592f79cbc77SKalle Valo struct ieee80211_sta *sta) 2593f79cbc77SKalle Valo { 2594f79cbc77SKalle Valo struct hwsim_sta_priv *sp = (void *)sta->drv_priv; 2595f79cbc77SKalle Valo 2596f79cbc77SKalle Valo hwsim_check_magic(vif); 2597f79cbc77SKalle Valo hwsim_set_sta_magic(sta); 2598f79cbc77SKalle Valo mac80211_hwsim_sta_rc_update(hw, vif, sta, 0); 2599f79cbc77SKalle Valo 2600f79cbc77SKalle Valo if (sta->valid_links) { 2601f79cbc77SKalle Valo WARN(hweight16(sta->valid_links) > 1, 2602f79cbc77SKalle Valo "expect to add STA with single link, have 0x%x\n", 2603f79cbc77SKalle Valo sta->valid_links); 2604f79cbc77SKalle Valo sp->active_links_rx = sta->valid_links; 2605f79cbc77SKalle Valo } 2606f79cbc77SKalle Valo 2607f79cbc77SKalle Valo return 0; 2608f79cbc77SKalle Valo } 2609f79cbc77SKalle Valo 2610f79cbc77SKalle Valo static int mac80211_hwsim_sta_remove(struct ieee80211_hw *hw, 2611f79cbc77SKalle Valo struct ieee80211_vif *vif, 2612f79cbc77SKalle Valo struct ieee80211_sta *sta) 2613f79cbc77SKalle Valo { 2614f79cbc77SKalle Valo hwsim_check_magic(vif); 2615f79cbc77SKalle Valo hwsim_clear_sta_magic(sta); 2616f79cbc77SKalle Valo 2617f79cbc77SKalle Valo return 0; 2618f79cbc77SKalle Valo } 2619f79cbc77SKalle Valo 2620f79cbc77SKalle Valo static int mac80211_hwsim_sta_state(struct ieee80211_hw *hw, 2621f79cbc77SKalle Valo struct ieee80211_vif *vif, 2622f79cbc77SKalle Valo struct ieee80211_sta *sta, 2623f79cbc77SKalle Valo enum ieee80211_sta_state old_state, 2624f79cbc77SKalle Valo enum ieee80211_sta_state new_state) 2625f79cbc77SKalle Valo { 2626f79cbc77SKalle Valo if (new_state == IEEE80211_STA_NOTEXIST) 2627f79cbc77SKalle Valo return mac80211_hwsim_sta_remove(hw, vif, sta); 2628f79cbc77SKalle Valo 2629f79cbc77SKalle Valo if (old_state == IEEE80211_STA_NOTEXIST) 2630f79cbc77SKalle Valo return mac80211_hwsim_sta_add(hw, vif, sta); 2631f79cbc77SKalle Valo 2632f79cbc77SKalle Valo /* 2633f79cbc77SKalle Valo * when client is authorized (AP station marked as such), 2634f79cbc77SKalle Valo * enable all links 2635f79cbc77SKalle Valo */ 2636f79cbc77SKalle Valo if (vif->type == NL80211_IFTYPE_STATION && 2637f79cbc77SKalle Valo new_state == IEEE80211_STA_AUTHORIZED && !sta->tdls) 263801ae1209SIlan Peer ieee80211_set_active_links_async(vif, 263901ae1209SIlan Peer ieee80211_vif_usable_links(vif)); 2640f79cbc77SKalle Valo 2641f79cbc77SKalle Valo return 0; 2642f79cbc77SKalle Valo } 2643f79cbc77SKalle Valo 2644f79cbc77SKalle Valo static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw, 2645f79cbc77SKalle Valo struct ieee80211_vif *vif, 2646f79cbc77SKalle Valo enum sta_notify_cmd cmd, 2647f79cbc77SKalle Valo struct ieee80211_sta *sta) 2648f79cbc77SKalle Valo { 2649f79cbc77SKalle Valo hwsim_check_magic(vif); 2650f79cbc77SKalle Valo 2651f79cbc77SKalle Valo switch (cmd) { 2652f79cbc77SKalle Valo case STA_NOTIFY_SLEEP: 2653f79cbc77SKalle Valo case STA_NOTIFY_AWAKE: 2654f79cbc77SKalle Valo /* TODO: make good use of these flags */ 2655f79cbc77SKalle Valo break; 2656f79cbc77SKalle Valo default: 2657f79cbc77SKalle Valo WARN(1, "Invalid sta notify: %d\n", cmd); 2658f79cbc77SKalle Valo break; 2659f79cbc77SKalle Valo } 2660f79cbc77SKalle Valo } 2661f79cbc77SKalle Valo 2662f79cbc77SKalle Valo static int mac80211_hwsim_set_tim(struct ieee80211_hw *hw, 2663f79cbc77SKalle Valo struct ieee80211_sta *sta, 2664f79cbc77SKalle Valo bool set) 2665f79cbc77SKalle Valo { 2666f79cbc77SKalle Valo hwsim_check_sta_magic(sta); 2667f79cbc77SKalle Valo return 0; 2668f79cbc77SKalle Valo } 2669f79cbc77SKalle Valo 2670f79cbc77SKalle Valo static int mac80211_hwsim_conf_tx(struct ieee80211_hw *hw, 2671f79cbc77SKalle Valo struct ieee80211_vif *vif, 2672f79cbc77SKalle Valo unsigned int link_id, u16 queue, 2673f79cbc77SKalle Valo const struct ieee80211_tx_queue_params *params) 2674f79cbc77SKalle Valo { 2675f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, 2676f79cbc77SKalle Valo "%s (queue=%d txop=%d cw_min=%d cw_max=%d aifs=%d)\n", 2677f79cbc77SKalle Valo __func__, queue, 2678f79cbc77SKalle Valo params->txop, params->cw_min, 2679f79cbc77SKalle Valo params->cw_max, params->aifs); 2680f79cbc77SKalle Valo return 0; 2681f79cbc77SKalle Valo } 2682f79cbc77SKalle Valo 2683f79cbc77SKalle Valo static int mac80211_hwsim_get_survey(struct ieee80211_hw *hw, int idx, 2684f79cbc77SKalle Valo struct survey_info *survey) 2685f79cbc77SKalle Valo { 2686f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = hw->priv; 2687f79cbc77SKalle Valo 2688f79cbc77SKalle Valo if (idx < 0 || idx >= ARRAY_SIZE(hwsim->survey_data)) 2689f79cbc77SKalle Valo return -ENOENT; 2690f79cbc77SKalle Valo 2691f79cbc77SKalle Valo mutex_lock(&hwsim->mutex); 2692f79cbc77SKalle Valo survey->channel = hwsim->survey_data[idx].channel; 2693f79cbc77SKalle Valo if (!survey->channel) { 2694f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2695f79cbc77SKalle Valo return -ENOENT; 2696f79cbc77SKalle Valo } 2697f79cbc77SKalle Valo 2698f79cbc77SKalle Valo /* 2699f79cbc77SKalle Valo * Magically conjured dummy values --- this is only ok for simulated hardware. 2700f79cbc77SKalle Valo * 2701f79cbc77SKalle Valo * A real driver which cannot determine real values noise MUST NOT 2702f79cbc77SKalle Valo * report any, especially not a magically conjured ones :-) 2703f79cbc77SKalle Valo */ 2704f79cbc77SKalle Valo survey->filled = SURVEY_INFO_NOISE_DBM | 2705f79cbc77SKalle Valo SURVEY_INFO_TIME | 2706f79cbc77SKalle Valo SURVEY_INFO_TIME_BUSY; 2707f79cbc77SKalle Valo survey->noise = -92; 2708f79cbc77SKalle Valo survey->time = 2709f79cbc77SKalle Valo jiffies_to_msecs(hwsim->survey_data[idx].end - 2710f79cbc77SKalle Valo hwsim->survey_data[idx].start); 2711f79cbc77SKalle Valo /* report 12.5% of channel time is used */ 2712f79cbc77SKalle Valo survey->time_busy = survey->time/8; 2713f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2714f79cbc77SKalle Valo 2715f79cbc77SKalle Valo return 0; 2716f79cbc77SKalle Valo } 2717f79cbc77SKalle Valo 2718f79cbc77SKalle Valo #ifdef CONFIG_NL80211_TESTMODE 2719f79cbc77SKalle Valo /* 2720f79cbc77SKalle Valo * This section contains example code for using netlink 2721f79cbc77SKalle Valo * attributes with the testmode command in nl80211. 2722f79cbc77SKalle Valo */ 2723f79cbc77SKalle Valo 2724f79cbc77SKalle Valo /* These enums need to be kept in sync with userspace */ 2725f79cbc77SKalle Valo enum hwsim_testmode_attr { 2726f79cbc77SKalle Valo __HWSIM_TM_ATTR_INVALID = 0, 2727f79cbc77SKalle Valo HWSIM_TM_ATTR_CMD = 1, 2728f79cbc77SKalle Valo HWSIM_TM_ATTR_PS = 2, 2729f79cbc77SKalle Valo 2730f79cbc77SKalle Valo /* keep last */ 2731f79cbc77SKalle Valo __HWSIM_TM_ATTR_AFTER_LAST, 2732f79cbc77SKalle Valo HWSIM_TM_ATTR_MAX = __HWSIM_TM_ATTR_AFTER_LAST - 1 2733f79cbc77SKalle Valo }; 2734f79cbc77SKalle Valo 2735f79cbc77SKalle Valo enum hwsim_testmode_cmd { 2736f79cbc77SKalle Valo HWSIM_TM_CMD_SET_PS = 0, 2737f79cbc77SKalle Valo HWSIM_TM_CMD_GET_PS = 1, 2738f79cbc77SKalle Valo HWSIM_TM_CMD_STOP_QUEUES = 2, 2739f79cbc77SKalle Valo HWSIM_TM_CMD_WAKE_QUEUES = 3, 2740f79cbc77SKalle Valo }; 2741f79cbc77SKalle Valo 2742f79cbc77SKalle Valo static const struct nla_policy hwsim_testmode_policy[HWSIM_TM_ATTR_MAX + 1] = { 2743f79cbc77SKalle Valo [HWSIM_TM_ATTR_CMD] = { .type = NLA_U32 }, 2744f79cbc77SKalle Valo [HWSIM_TM_ATTR_PS] = { .type = NLA_U32 }, 2745f79cbc77SKalle Valo }; 2746f79cbc77SKalle Valo 2747f79cbc77SKalle Valo static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw, 2748f79cbc77SKalle Valo struct ieee80211_vif *vif, 2749f79cbc77SKalle Valo void *data, int len) 2750f79cbc77SKalle Valo { 2751f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = hw->priv; 2752f79cbc77SKalle Valo struct nlattr *tb[HWSIM_TM_ATTR_MAX + 1]; 2753f79cbc77SKalle Valo struct sk_buff *skb; 2754f79cbc77SKalle Valo int err, ps; 2755f79cbc77SKalle Valo 2756f79cbc77SKalle Valo err = nla_parse_deprecated(tb, HWSIM_TM_ATTR_MAX, data, len, 2757f79cbc77SKalle Valo hwsim_testmode_policy, NULL); 2758f79cbc77SKalle Valo if (err) 2759f79cbc77SKalle Valo return err; 2760f79cbc77SKalle Valo 2761f79cbc77SKalle Valo if (!tb[HWSIM_TM_ATTR_CMD]) 2762f79cbc77SKalle Valo return -EINVAL; 2763f79cbc77SKalle Valo 2764f79cbc77SKalle Valo switch (nla_get_u32(tb[HWSIM_TM_ATTR_CMD])) { 2765f79cbc77SKalle Valo case HWSIM_TM_CMD_SET_PS: 2766f79cbc77SKalle Valo if (!tb[HWSIM_TM_ATTR_PS]) 2767f79cbc77SKalle Valo return -EINVAL; 2768f79cbc77SKalle Valo ps = nla_get_u32(tb[HWSIM_TM_ATTR_PS]); 2769f79cbc77SKalle Valo return hwsim_fops_ps_write(hwsim, ps); 2770f79cbc77SKalle Valo case HWSIM_TM_CMD_GET_PS: 2771f79cbc77SKalle Valo skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 2772f79cbc77SKalle Valo nla_total_size(sizeof(u32))); 2773f79cbc77SKalle Valo if (!skb) 2774f79cbc77SKalle Valo return -ENOMEM; 2775f79cbc77SKalle Valo if (nla_put_u32(skb, HWSIM_TM_ATTR_PS, hwsim->ps)) 2776f79cbc77SKalle Valo goto nla_put_failure; 2777f79cbc77SKalle Valo return cfg80211_testmode_reply(skb); 2778f79cbc77SKalle Valo case HWSIM_TM_CMD_STOP_QUEUES: 2779f79cbc77SKalle Valo ieee80211_stop_queues(hw); 2780f79cbc77SKalle Valo return 0; 2781f79cbc77SKalle Valo case HWSIM_TM_CMD_WAKE_QUEUES: 2782f79cbc77SKalle Valo ieee80211_wake_queues(hw); 2783f79cbc77SKalle Valo return 0; 2784f79cbc77SKalle Valo default: 2785f79cbc77SKalle Valo return -EOPNOTSUPP; 2786f79cbc77SKalle Valo } 2787f79cbc77SKalle Valo 2788f79cbc77SKalle Valo nla_put_failure: 2789f79cbc77SKalle Valo kfree_skb(skb); 2790f79cbc77SKalle Valo return -ENOBUFS; 2791f79cbc77SKalle Valo } 2792f79cbc77SKalle Valo #endif 2793f79cbc77SKalle Valo 2794f79cbc77SKalle Valo static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw, 2795f79cbc77SKalle Valo struct ieee80211_vif *vif, 2796f79cbc77SKalle Valo struct ieee80211_ampdu_params *params) 2797f79cbc77SKalle Valo { 2798f79cbc77SKalle Valo struct ieee80211_sta *sta = params->sta; 2799f79cbc77SKalle Valo enum ieee80211_ampdu_mlme_action action = params->action; 2800f79cbc77SKalle Valo u16 tid = params->tid; 2801f79cbc77SKalle Valo 2802f79cbc77SKalle Valo switch (action) { 2803f79cbc77SKalle Valo case IEEE80211_AMPDU_TX_START: 2804f79cbc77SKalle Valo return IEEE80211_AMPDU_TX_START_IMMEDIATE; 2805f79cbc77SKalle Valo case IEEE80211_AMPDU_TX_STOP_CONT: 2806f79cbc77SKalle Valo case IEEE80211_AMPDU_TX_STOP_FLUSH: 2807f79cbc77SKalle Valo case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: 2808f79cbc77SKalle Valo ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); 2809f79cbc77SKalle Valo break; 2810f79cbc77SKalle Valo case IEEE80211_AMPDU_TX_OPERATIONAL: 2811f79cbc77SKalle Valo break; 2812f79cbc77SKalle Valo case IEEE80211_AMPDU_RX_START: 2813f79cbc77SKalle Valo case IEEE80211_AMPDU_RX_STOP: 2814f79cbc77SKalle Valo break; 2815f79cbc77SKalle Valo default: 2816f79cbc77SKalle Valo return -EOPNOTSUPP; 2817f79cbc77SKalle Valo } 2818f79cbc77SKalle Valo 2819f79cbc77SKalle Valo return 0; 2820f79cbc77SKalle Valo } 2821f79cbc77SKalle Valo 2822f79cbc77SKalle Valo static void mac80211_hwsim_flush(struct ieee80211_hw *hw, 2823f79cbc77SKalle Valo struct ieee80211_vif *vif, 2824f79cbc77SKalle Valo u32 queues, bool drop) 2825f79cbc77SKalle Valo { 2826f79cbc77SKalle Valo /* Not implemented, queues only on kernel side */ 2827f79cbc77SKalle Valo } 2828f79cbc77SKalle Valo 2829f79cbc77SKalle Valo static void hw_scan_work(struct work_struct *work) 2830f79cbc77SKalle Valo { 2831f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = 2832f79cbc77SKalle Valo container_of(work, struct mac80211_hwsim_data, hw_scan.work); 2833f79cbc77SKalle Valo struct cfg80211_scan_request *req = hwsim->hw_scan_request; 2834f79cbc77SKalle Valo int dwell, i; 2835f79cbc77SKalle Valo 2836f79cbc77SKalle Valo mutex_lock(&hwsim->mutex); 2837f79cbc77SKalle Valo if (hwsim->scan_chan_idx >= req->n_channels) { 2838f79cbc77SKalle Valo struct cfg80211_scan_info info = { 2839f79cbc77SKalle Valo .aborted = false, 2840f79cbc77SKalle Valo }; 2841f79cbc77SKalle Valo 2842f79cbc77SKalle Valo wiphy_dbg(hwsim->hw->wiphy, "hw scan complete\n"); 2843f79cbc77SKalle Valo ieee80211_scan_completed(hwsim->hw, &info); 2844f79cbc77SKalle Valo hwsim->hw_scan_request = NULL; 2845f79cbc77SKalle Valo hwsim->hw_scan_vif = NULL; 2846f79cbc77SKalle Valo hwsim->tmp_chan = NULL; 2847f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2848f79cbc77SKalle Valo mac80211_hwsim_config_mac_nl(hwsim->hw, hwsim->scan_addr, 2849f79cbc77SKalle Valo false); 2850f79cbc77SKalle Valo return; 2851f79cbc77SKalle Valo } 2852f79cbc77SKalle Valo 2853f79cbc77SKalle Valo wiphy_dbg(hwsim->hw->wiphy, "hw scan %d MHz\n", 2854f79cbc77SKalle Valo req->channels[hwsim->scan_chan_idx]->center_freq); 2855f79cbc77SKalle Valo 2856f79cbc77SKalle Valo hwsim->tmp_chan = req->channels[hwsim->scan_chan_idx]; 2857f79cbc77SKalle Valo if (hwsim->tmp_chan->flags & (IEEE80211_CHAN_NO_IR | 2858f79cbc77SKalle Valo IEEE80211_CHAN_RADAR) || 2859f79cbc77SKalle Valo !req->n_ssids) { 2860f79cbc77SKalle Valo dwell = 120; 2861f79cbc77SKalle Valo } else { 2862f79cbc77SKalle Valo dwell = 30; 2863f79cbc77SKalle Valo /* send probes */ 2864f79cbc77SKalle Valo for (i = 0; i < req->n_ssids; i++) { 2865f79cbc77SKalle Valo struct sk_buff *probe; 2866f79cbc77SKalle Valo struct ieee80211_mgmt *mgmt; 2867f79cbc77SKalle Valo 2868f79cbc77SKalle Valo probe = ieee80211_probereq_get(hwsim->hw, 2869f79cbc77SKalle Valo hwsim->scan_addr, 2870f79cbc77SKalle Valo req->ssids[i].ssid, 2871f79cbc77SKalle Valo req->ssids[i].ssid_len, 2872f79cbc77SKalle Valo req->ie_len); 2873f79cbc77SKalle Valo if (!probe) 2874f79cbc77SKalle Valo continue; 2875f79cbc77SKalle Valo 2876f79cbc77SKalle Valo mgmt = (struct ieee80211_mgmt *) probe->data; 2877f79cbc77SKalle Valo memcpy(mgmt->da, req->bssid, ETH_ALEN); 2878f79cbc77SKalle Valo memcpy(mgmt->bssid, req->bssid, ETH_ALEN); 2879f79cbc77SKalle Valo 2880f79cbc77SKalle Valo if (req->ie_len) 2881f79cbc77SKalle Valo skb_put_data(probe, req->ie, req->ie_len); 2882f79cbc77SKalle Valo 2883f79cbc77SKalle Valo rcu_read_lock(); 2884f79cbc77SKalle Valo if (!ieee80211_tx_prepare_skb(hwsim->hw, 2885f79cbc77SKalle Valo hwsim->hw_scan_vif, 2886f79cbc77SKalle Valo probe, 2887f79cbc77SKalle Valo hwsim->tmp_chan->band, 2888f79cbc77SKalle Valo NULL)) { 2889f79cbc77SKalle Valo rcu_read_unlock(); 2890f79cbc77SKalle Valo kfree_skb(probe); 2891f79cbc77SKalle Valo continue; 2892f79cbc77SKalle Valo } 2893f79cbc77SKalle Valo 2894f79cbc77SKalle Valo local_bh_disable(); 2895f79cbc77SKalle Valo mac80211_hwsim_tx_frame(hwsim->hw, probe, 2896f79cbc77SKalle Valo hwsim->tmp_chan); 2897f79cbc77SKalle Valo rcu_read_unlock(); 2898f79cbc77SKalle Valo local_bh_enable(); 2899f79cbc77SKalle Valo } 2900f79cbc77SKalle Valo } 2901f79cbc77SKalle Valo ieee80211_queue_delayed_work(hwsim->hw, &hwsim->hw_scan, 2902f79cbc77SKalle Valo msecs_to_jiffies(dwell)); 2903f79cbc77SKalle Valo hwsim->survey_data[hwsim->scan_chan_idx].channel = hwsim->tmp_chan; 2904f79cbc77SKalle Valo hwsim->survey_data[hwsim->scan_chan_idx].start = jiffies; 2905f79cbc77SKalle Valo hwsim->survey_data[hwsim->scan_chan_idx].end = 2906f79cbc77SKalle Valo jiffies + msecs_to_jiffies(dwell); 2907f79cbc77SKalle Valo hwsim->scan_chan_idx++; 2908f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2909f79cbc77SKalle Valo } 2910f79cbc77SKalle Valo 2911f79cbc77SKalle Valo static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw, 2912f79cbc77SKalle Valo struct ieee80211_vif *vif, 2913f79cbc77SKalle Valo struct ieee80211_scan_request *hw_req) 2914f79cbc77SKalle Valo { 2915f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = hw->priv; 2916f79cbc77SKalle Valo struct cfg80211_scan_request *req = &hw_req->req; 2917f79cbc77SKalle Valo 2918f79cbc77SKalle Valo mutex_lock(&hwsim->mutex); 2919f79cbc77SKalle Valo if (WARN_ON(hwsim->tmp_chan || hwsim->hw_scan_request)) { 2920f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2921f79cbc77SKalle Valo return -EBUSY; 2922f79cbc77SKalle Valo } 2923f79cbc77SKalle Valo hwsim->hw_scan_request = req; 2924f79cbc77SKalle Valo hwsim->hw_scan_vif = vif; 2925f79cbc77SKalle Valo hwsim->scan_chan_idx = 0; 2926f79cbc77SKalle Valo if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) 2927f79cbc77SKalle Valo get_random_mask_addr(hwsim->scan_addr, 2928f79cbc77SKalle Valo hw_req->req.mac_addr, 2929f79cbc77SKalle Valo hw_req->req.mac_addr_mask); 2930f79cbc77SKalle Valo else 2931f79cbc77SKalle Valo memcpy(hwsim->scan_addr, vif->addr, ETH_ALEN); 2932f79cbc77SKalle Valo memset(hwsim->survey_data, 0, sizeof(hwsim->survey_data)); 2933f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2934f79cbc77SKalle Valo 2935f79cbc77SKalle Valo mac80211_hwsim_config_mac_nl(hw, hwsim->scan_addr, true); 2936f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "hwsim hw_scan request\n"); 2937f79cbc77SKalle Valo 2938f79cbc77SKalle Valo ieee80211_queue_delayed_work(hwsim->hw, &hwsim->hw_scan, 0); 2939f79cbc77SKalle Valo 2940f79cbc77SKalle Valo return 0; 2941f79cbc77SKalle Valo } 2942f79cbc77SKalle Valo 2943f79cbc77SKalle Valo static void mac80211_hwsim_cancel_hw_scan(struct ieee80211_hw *hw, 2944f79cbc77SKalle Valo struct ieee80211_vif *vif) 2945f79cbc77SKalle Valo { 2946f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = hw->priv; 2947f79cbc77SKalle Valo struct cfg80211_scan_info info = { 2948f79cbc77SKalle Valo .aborted = true, 2949f79cbc77SKalle Valo }; 2950f79cbc77SKalle Valo 2951f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "hwsim cancel_hw_scan\n"); 2952f79cbc77SKalle Valo 2953f79cbc77SKalle Valo cancel_delayed_work_sync(&hwsim->hw_scan); 2954f79cbc77SKalle Valo 2955f79cbc77SKalle Valo mutex_lock(&hwsim->mutex); 2956f79cbc77SKalle Valo ieee80211_scan_completed(hwsim->hw, &info); 2957f79cbc77SKalle Valo hwsim->tmp_chan = NULL; 2958f79cbc77SKalle Valo hwsim->hw_scan_request = NULL; 2959f79cbc77SKalle Valo hwsim->hw_scan_vif = NULL; 2960f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2961f79cbc77SKalle Valo } 2962f79cbc77SKalle Valo 2963f79cbc77SKalle Valo static void mac80211_hwsim_sw_scan(struct ieee80211_hw *hw, 2964f79cbc77SKalle Valo struct ieee80211_vif *vif, 2965f79cbc77SKalle Valo const u8 *mac_addr) 2966f79cbc77SKalle Valo { 2967f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = hw->priv; 2968f79cbc77SKalle Valo 2969f79cbc77SKalle Valo mutex_lock(&hwsim->mutex); 2970f79cbc77SKalle Valo 2971f79cbc77SKalle Valo if (hwsim->scanning) { 2972f79cbc77SKalle Valo pr_debug("two hwsim sw_scans detected!\n"); 2973f79cbc77SKalle Valo goto out; 2974f79cbc77SKalle Valo } 2975f79cbc77SKalle Valo 2976f79cbc77SKalle Valo pr_debug("hwsim sw_scan request, prepping stuff\n"); 2977f79cbc77SKalle Valo 2978f79cbc77SKalle Valo memcpy(hwsim->scan_addr, mac_addr, ETH_ALEN); 2979f79cbc77SKalle Valo mac80211_hwsim_config_mac_nl(hw, hwsim->scan_addr, true); 2980f79cbc77SKalle Valo hwsim->scanning = true; 2981f79cbc77SKalle Valo memset(hwsim->survey_data, 0, sizeof(hwsim->survey_data)); 2982f79cbc77SKalle Valo 2983f79cbc77SKalle Valo out: 2984f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 2985f79cbc77SKalle Valo } 2986f79cbc77SKalle Valo 2987f79cbc77SKalle Valo static void mac80211_hwsim_sw_scan_complete(struct ieee80211_hw *hw, 2988f79cbc77SKalle Valo struct ieee80211_vif *vif) 2989f79cbc77SKalle Valo { 2990f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = hw->priv; 2991f79cbc77SKalle Valo 2992f79cbc77SKalle Valo mutex_lock(&hwsim->mutex); 2993f79cbc77SKalle Valo 2994f79cbc77SKalle Valo pr_debug("hwsim sw_scan_complete\n"); 2995f79cbc77SKalle Valo hwsim->scanning = false; 2996f79cbc77SKalle Valo mac80211_hwsim_config_mac_nl(hw, hwsim->scan_addr, false); 2997f79cbc77SKalle Valo eth_zero_addr(hwsim->scan_addr); 2998f79cbc77SKalle Valo 2999f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 3000f79cbc77SKalle Valo } 3001f79cbc77SKalle Valo 3002f79cbc77SKalle Valo static void hw_roc_start(struct work_struct *work) 3003f79cbc77SKalle Valo { 3004f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = 3005f79cbc77SKalle Valo container_of(work, struct mac80211_hwsim_data, roc_start.work); 3006f79cbc77SKalle Valo 3007f79cbc77SKalle Valo mutex_lock(&hwsim->mutex); 3008f79cbc77SKalle Valo 3009f79cbc77SKalle Valo wiphy_dbg(hwsim->hw->wiphy, "hwsim ROC begins\n"); 3010f79cbc77SKalle Valo hwsim->tmp_chan = hwsim->roc_chan; 3011f79cbc77SKalle Valo ieee80211_ready_on_channel(hwsim->hw); 3012f79cbc77SKalle Valo 3013f79cbc77SKalle Valo ieee80211_queue_delayed_work(hwsim->hw, &hwsim->roc_done, 3014f79cbc77SKalle Valo msecs_to_jiffies(hwsim->roc_duration)); 3015f79cbc77SKalle Valo 3016f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 3017f79cbc77SKalle Valo } 3018f79cbc77SKalle Valo 3019f79cbc77SKalle Valo static void hw_roc_done(struct work_struct *work) 3020f79cbc77SKalle Valo { 3021f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = 3022f79cbc77SKalle Valo container_of(work, struct mac80211_hwsim_data, roc_done.work); 3023f79cbc77SKalle Valo 3024f79cbc77SKalle Valo mutex_lock(&hwsim->mutex); 3025f79cbc77SKalle Valo ieee80211_remain_on_channel_expired(hwsim->hw); 3026f79cbc77SKalle Valo hwsim->tmp_chan = NULL; 3027f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 3028f79cbc77SKalle Valo 3029f79cbc77SKalle Valo wiphy_dbg(hwsim->hw->wiphy, "hwsim ROC expired\n"); 3030f79cbc77SKalle Valo } 3031f79cbc77SKalle Valo 3032f79cbc77SKalle Valo static int mac80211_hwsim_roc(struct ieee80211_hw *hw, 3033f79cbc77SKalle Valo struct ieee80211_vif *vif, 3034f79cbc77SKalle Valo struct ieee80211_channel *chan, 3035f79cbc77SKalle Valo int duration, 3036f79cbc77SKalle Valo enum ieee80211_roc_type type) 3037f79cbc77SKalle Valo { 3038f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = hw->priv; 3039f79cbc77SKalle Valo 3040f79cbc77SKalle Valo mutex_lock(&hwsim->mutex); 3041f79cbc77SKalle Valo if (WARN_ON(hwsim->tmp_chan || hwsim->hw_scan_request)) { 3042f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 3043f79cbc77SKalle Valo return -EBUSY; 3044f79cbc77SKalle Valo } 3045f79cbc77SKalle Valo 3046f79cbc77SKalle Valo hwsim->roc_chan = chan; 3047f79cbc77SKalle Valo hwsim->roc_duration = duration; 3048f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 3049f79cbc77SKalle Valo 3050f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "hwsim ROC (%d MHz, %d ms)\n", 3051f79cbc77SKalle Valo chan->center_freq, duration); 3052f79cbc77SKalle Valo ieee80211_queue_delayed_work(hw, &hwsim->roc_start, HZ/50); 3053f79cbc77SKalle Valo 3054f79cbc77SKalle Valo return 0; 3055f79cbc77SKalle Valo } 3056f79cbc77SKalle Valo 3057f79cbc77SKalle Valo static int mac80211_hwsim_croc(struct ieee80211_hw *hw, 3058f79cbc77SKalle Valo struct ieee80211_vif *vif) 3059f79cbc77SKalle Valo { 3060f79cbc77SKalle Valo struct mac80211_hwsim_data *hwsim = hw->priv; 3061f79cbc77SKalle Valo 3062f79cbc77SKalle Valo cancel_delayed_work_sync(&hwsim->roc_start); 3063f79cbc77SKalle Valo cancel_delayed_work_sync(&hwsim->roc_done); 3064f79cbc77SKalle Valo 3065f79cbc77SKalle Valo mutex_lock(&hwsim->mutex); 3066f79cbc77SKalle Valo hwsim->tmp_chan = NULL; 3067f79cbc77SKalle Valo mutex_unlock(&hwsim->mutex); 3068f79cbc77SKalle Valo 3069f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "hwsim ROC canceled\n"); 3070f79cbc77SKalle Valo 3071f79cbc77SKalle Valo return 0; 3072f79cbc77SKalle Valo } 3073f79cbc77SKalle Valo 3074f79cbc77SKalle Valo static int mac80211_hwsim_add_chanctx(struct ieee80211_hw *hw, 3075f79cbc77SKalle Valo struct ieee80211_chanctx_conf *ctx) 3076f79cbc77SKalle Valo { 3077f79cbc77SKalle Valo hwsim_set_chanctx_magic(ctx); 3078f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, 3079f79cbc77SKalle Valo "add channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n", 3080f79cbc77SKalle Valo ctx->def.chan->center_freq, ctx->def.width, 3081f79cbc77SKalle Valo ctx->def.center_freq1, ctx->def.center_freq2); 3082f79cbc77SKalle Valo return 0; 3083f79cbc77SKalle Valo } 3084f79cbc77SKalle Valo 3085f79cbc77SKalle Valo static void mac80211_hwsim_remove_chanctx(struct ieee80211_hw *hw, 3086f79cbc77SKalle Valo struct ieee80211_chanctx_conf *ctx) 3087f79cbc77SKalle Valo { 3088f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, 3089f79cbc77SKalle Valo "remove channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n", 3090f79cbc77SKalle Valo ctx->def.chan->center_freq, ctx->def.width, 3091f79cbc77SKalle Valo ctx->def.center_freq1, ctx->def.center_freq2); 3092f79cbc77SKalle Valo hwsim_check_chanctx_magic(ctx); 3093f79cbc77SKalle Valo hwsim_clear_chanctx_magic(ctx); 3094f79cbc77SKalle Valo } 3095f79cbc77SKalle Valo 3096f79cbc77SKalle Valo static void mac80211_hwsim_change_chanctx(struct ieee80211_hw *hw, 3097f79cbc77SKalle Valo struct ieee80211_chanctx_conf *ctx, 3098f79cbc77SKalle Valo u32 changed) 3099f79cbc77SKalle Valo { 3100f79cbc77SKalle Valo hwsim_check_chanctx_magic(ctx); 3101f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, 3102f79cbc77SKalle Valo "change channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n", 3103f79cbc77SKalle Valo ctx->def.chan->center_freq, ctx->def.width, 3104f79cbc77SKalle Valo ctx->def.center_freq1, ctx->def.center_freq2); 3105f79cbc77SKalle Valo } 3106f79cbc77SKalle Valo 3107f79cbc77SKalle Valo static int mac80211_hwsim_assign_vif_chanctx(struct ieee80211_hw *hw, 3108f79cbc77SKalle Valo struct ieee80211_vif *vif, 3109f79cbc77SKalle Valo struct ieee80211_bss_conf *link_conf, 3110f79cbc77SKalle Valo struct ieee80211_chanctx_conf *ctx) 3111f79cbc77SKalle Valo { 3112f79cbc77SKalle Valo hwsim_check_magic(vif); 3113f79cbc77SKalle Valo hwsim_check_chanctx_magic(ctx); 3114f79cbc77SKalle Valo 3115f79cbc77SKalle Valo /* if we activate a link while already associated wake it up */ 3116f79cbc77SKalle Valo if (vif->type == NL80211_IFTYPE_STATION && vif->cfg.assoc) { 3117f79cbc77SKalle Valo struct sk_buff *skb; 3118f79cbc77SKalle Valo 3119f79cbc77SKalle Valo skb = ieee80211_nullfunc_get(hw, vif, link_conf->link_id, true); 3120f79cbc77SKalle Valo if (skb) { 3121f79cbc77SKalle Valo local_bh_disable(); 3122f79cbc77SKalle Valo mac80211_hwsim_tx_frame(hw, skb, ctx->def.chan); 3123f79cbc77SKalle Valo local_bh_enable(); 3124f79cbc77SKalle Valo } 3125f79cbc77SKalle Valo } 3126f79cbc77SKalle Valo 3127f79cbc77SKalle Valo return 0; 3128f79cbc77SKalle Valo } 3129f79cbc77SKalle Valo 3130f79cbc77SKalle Valo static void mac80211_hwsim_unassign_vif_chanctx(struct ieee80211_hw *hw, 3131f79cbc77SKalle Valo struct ieee80211_vif *vif, 3132f79cbc77SKalle Valo struct ieee80211_bss_conf *link_conf, 3133f79cbc77SKalle Valo struct ieee80211_chanctx_conf *ctx) 3134f79cbc77SKalle Valo { 3135f79cbc77SKalle Valo hwsim_check_magic(vif); 3136f79cbc77SKalle Valo hwsim_check_chanctx_magic(ctx); 3137f79cbc77SKalle Valo 3138f79cbc77SKalle Valo /* if we deactivate a link while associated suspend it first */ 3139f79cbc77SKalle Valo if (vif->type == NL80211_IFTYPE_STATION && vif->cfg.assoc) { 3140f79cbc77SKalle Valo struct sk_buff *skb; 3141f79cbc77SKalle Valo 3142f79cbc77SKalle Valo skb = ieee80211_nullfunc_get(hw, vif, link_conf->link_id, true); 3143f79cbc77SKalle Valo if (skb) { 3144f79cbc77SKalle Valo struct ieee80211_hdr *hdr = (void *)skb->data; 3145f79cbc77SKalle Valo 3146f79cbc77SKalle Valo hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); 3147f79cbc77SKalle Valo 3148f79cbc77SKalle Valo local_bh_disable(); 3149f79cbc77SKalle Valo mac80211_hwsim_tx_frame(hw, skb, ctx->def.chan); 3150f79cbc77SKalle Valo local_bh_enable(); 3151f79cbc77SKalle Valo } 3152f79cbc77SKalle Valo } 3153f79cbc77SKalle Valo } 3154f79cbc77SKalle Valo 3155f79cbc77SKalle Valo static const char mac80211_hwsim_gstrings_stats[][ETH_GSTRING_LEN] = { 3156f79cbc77SKalle Valo "tx_pkts_nic", 3157f79cbc77SKalle Valo "tx_bytes_nic", 3158f79cbc77SKalle Valo "rx_pkts_nic", 3159f79cbc77SKalle Valo "rx_bytes_nic", 3160f79cbc77SKalle Valo "d_tx_dropped", 3161f79cbc77SKalle Valo "d_tx_failed", 3162f79cbc77SKalle Valo "d_ps_mode", 3163f79cbc77SKalle Valo "d_group", 3164f79cbc77SKalle Valo }; 3165f79cbc77SKalle Valo 3166f79cbc77SKalle Valo #define MAC80211_HWSIM_SSTATS_LEN ARRAY_SIZE(mac80211_hwsim_gstrings_stats) 3167f79cbc77SKalle Valo 3168f79cbc77SKalle Valo static void mac80211_hwsim_get_et_strings(struct ieee80211_hw *hw, 3169f79cbc77SKalle Valo struct ieee80211_vif *vif, 3170f79cbc77SKalle Valo u32 sset, u8 *data) 3171f79cbc77SKalle Valo { 3172f79cbc77SKalle Valo if (sset == ETH_SS_STATS) 317390e7d2adSDmitry Antipov memcpy(data, mac80211_hwsim_gstrings_stats, 3174f79cbc77SKalle Valo sizeof(mac80211_hwsim_gstrings_stats)); 3175f79cbc77SKalle Valo } 3176f79cbc77SKalle Valo 3177f79cbc77SKalle Valo static int mac80211_hwsim_get_et_sset_count(struct ieee80211_hw *hw, 3178f79cbc77SKalle Valo struct ieee80211_vif *vif, int sset) 3179f79cbc77SKalle Valo { 3180f79cbc77SKalle Valo if (sset == ETH_SS_STATS) 3181f79cbc77SKalle Valo return MAC80211_HWSIM_SSTATS_LEN; 3182f79cbc77SKalle Valo return 0; 3183f79cbc77SKalle Valo } 3184f79cbc77SKalle Valo 3185f79cbc77SKalle Valo static void mac80211_hwsim_get_et_stats(struct ieee80211_hw *hw, 3186f79cbc77SKalle Valo struct ieee80211_vif *vif, 3187f79cbc77SKalle Valo struct ethtool_stats *stats, u64 *data) 3188f79cbc77SKalle Valo { 3189f79cbc77SKalle Valo struct mac80211_hwsim_data *ar = hw->priv; 3190f79cbc77SKalle Valo int i = 0; 3191f79cbc77SKalle Valo 3192f79cbc77SKalle Valo data[i++] = ar->tx_pkts; 3193f79cbc77SKalle Valo data[i++] = ar->tx_bytes; 3194f79cbc77SKalle Valo data[i++] = ar->rx_pkts; 3195f79cbc77SKalle Valo data[i++] = ar->rx_bytes; 3196f79cbc77SKalle Valo data[i++] = ar->tx_dropped; 3197f79cbc77SKalle Valo data[i++] = ar->tx_failed; 3198f79cbc77SKalle Valo data[i++] = ar->ps; 3199f79cbc77SKalle Valo data[i++] = ar->group; 3200f79cbc77SKalle Valo 3201f79cbc77SKalle Valo WARN_ON(i != MAC80211_HWSIM_SSTATS_LEN); 3202f79cbc77SKalle Valo } 3203f79cbc77SKalle Valo 3204f79cbc77SKalle Valo static int mac80211_hwsim_tx_last_beacon(struct ieee80211_hw *hw) 3205f79cbc77SKalle Valo { 3206f79cbc77SKalle Valo return 1; 3207f79cbc77SKalle Valo } 3208f79cbc77SKalle Valo 3209f79cbc77SKalle Valo static int mac80211_hwsim_set_rts_threshold(struct ieee80211_hw *hw, u32 value) 3210f79cbc77SKalle Valo { 3211f79cbc77SKalle Valo return -EOPNOTSUPP; 3212f79cbc77SKalle Valo } 3213f79cbc77SKalle Valo 3214f79cbc77SKalle Valo static int mac80211_hwsim_change_vif_links(struct ieee80211_hw *hw, 3215f79cbc77SKalle Valo struct ieee80211_vif *vif, 3216f79cbc77SKalle Valo u16 old_links, u16 new_links, 3217f79cbc77SKalle Valo struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]) 3218f79cbc77SKalle Valo { 3219f79cbc77SKalle Valo unsigned long rem = old_links & ~new_links; 3220f79cbc77SKalle Valo unsigned long add = new_links & ~old_links; 3221f79cbc77SKalle Valo int i; 3222f79cbc77SKalle Valo 3223f79cbc77SKalle Valo if (!old_links) 3224f79cbc77SKalle Valo rem |= BIT(0); 3225f79cbc77SKalle Valo if (!new_links) 3226f79cbc77SKalle Valo add |= BIT(0); 3227f79cbc77SKalle Valo 3228f79cbc77SKalle Valo for_each_set_bit(i, &rem, IEEE80211_MLD_MAX_NUM_LINKS) 3229f79cbc77SKalle Valo mac80211_hwsim_config_mac_nl(hw, old[i]->addr, false); 3230f79cbc77SKalle Valo 3231f79cbc77SKalle Valo for_each_set_bit(i, &add, IEEE80211_MLD_MAX_NUM_LINKS) { 3232f79cbc77SKalle Valo struct ieee80211_bss_conf *link_conf; 3233f79cbc77SKalle Valo 3234f79cbc77SKalle Valo link_conf = link_conf_dereference_protected(vif, i); 3235f79cbc77SKalle Valo if (WARN_ON(!link_conf)) 3236f79cbc77SKalle Valo continue; 3237f79cbc77SKalle Valo 3238f79cbc77SKalle Valo mac80211_hwsim_config_mac_nl(hw, link_conf->addr, true); 3239f79cbc77SKalle Valo } 3240f79cbc77SKalle Valo 3241f79cbc77SKalle Valo return 0; 3242f79cbc77SKalle Valo } 3243f79cbc77SKalle Valo 3244f79cbc77SKalle Valo static int mac80211_hwsim_change_sta_links(struct ieee80211_hw *hw, 3245f79cbc77SKalle Valo struct ieee80211_vif *vif, 3246f79cbc77SKalle Valo struct ieee80211_sta *sta, 3247f79cbc77SKalle Valo u16 old_links, u16 new_links) 3248f79cbc77SKalle Valo { 3249f79cbc77SKalle Valo struct hwsim_sta_priv *sp = (void *)sta->drv_priv; 3250f79cbc77SKalle Valo 3251f79cbc77SKalle Valo hwsim_check_sta_magic(sta); 3252f79cbc77SKalle Valo 3253f79cbc77SKalle Valo if (vif->type == NL80211_IFTYPE_STATION) 3254f79cbc77SKalle Valo sp->active_links_rx = new_links; 3255f79cbc77SKalle Valo 3256f79cbc77SKalle Valo return 0; 3257f79cbc77SKalle Valo } 3258f79cbc77SKalle Valo 32595530c04cSJaewan Kim static int mac80211_hwsim_send_pmsr_ftm_request_peer(struct sk_buff *msg, 32605530c04cSJaewan Kim struct cfg80211_pmsr_ftm_request_peer *request) 32615530c04cSJaewan Kim { 32625530c04cSJaewan Kim struct nlattr *ftm; 32635530c04cSJaewan Kim 32645530c04cSJaewan Kim if (!request->requested) 32655530c04cSJaewan Kim return -EINVAL; 32665530c04cSJaewan Kim 32675530c04cSJaewan Kim ftm = nla_nest_start(msg, NL80211_PMSR_TYPE_FTM); 32685530c04cSJaewan Kim if (!ftm) 32695530c04cSJaewan Kim return -ENOBUFS; 32705530c04cSJaewan Kim 32715530c04cSJaewan Kim if (nla_put_u32(msg, NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE, request->preamble)) 32725530c04cSJaewan Kim return -ENOBUFS; 32735530c04cSJaewan Kim 32745530c04cSJaewan Kim if (nla_put_u16(msg, NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD, request->burst_period)) 32755530c04cSJaewan Kim return -ENOBUFS; 32765530c04cSJaewan Kim 32775530c04cSJaewan Kim if (request->asap && nla_put_flag(msg, NL80211_PMSR_FTM_REQ_ATTR_ASAP)) 32785530c04cSJaewan Kim return -ENOBUFS; 32795530c04cSJaewan Kim 32805530c04cSJaewan Kim if (request->request_lci && nla_put_flag(msg, NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI)) 32815530c04cSJaewan Kim return -ENOBUFS; 32825530c04cSJaewan Kim 32835530c04cSJaewan Kim if (request->request_civicloc && 32845530c04cSJaewan Kim nla_put_flag(msg, NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC)) 32855530c04cSJaewan Kim return -ENOBUFS; 32865530c04cSJaewan Kim 32875530c04cSJaewan Kim if (request->trigger_based && nla_put_flag(msg, NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED)) 32885530c04cSJaewan Kim return -ENOBUFS; 32895530c04cSJaewan Kim 32905530c04cSJaewan Kim if (request->non_trigger_based && 32915530c04cSJaewan Kim nla_put_flag(msg, NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED)) 32925530c04cSJaewan Kim return -ENOBUFS; 32935530c04cSJaewan Kim 32945530c04cSJaewan Kim if (request->lmr_feedback && nla_put_flag(msg, NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK)) 32955530c04cSJaewan Kim return -ENOBUFS; 32965530c04cSJaewan Kim 32975530c04cSJaewan Kim if (nla_put_u8(msg, NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP, request->num_bursts_exp)) 32985530c04cSJaewan Kim return -ENOBUFS; 32995530c04cSJaewan Kim 33005530c04cSJaewan Kim if (nla_put_u8(msg, NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION, request->burst_duration)) 33015530c04cSJaewan Kim return -ENOBUFS; 33025530c04cSJaewan Kim 33035530c04cSJaewan Kim if (nla_put_u8(msg, NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST, request->ftms_per_burst)) 33045530c04cSJaewan Kim return -ENOBUFS; 33055530c04cSJaewan Kim 33065530c04cSJaewan Kim if (nla_put_u8(msg, NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES, request->ftmr_retries)) 33075530c04cSJaewan Kim return -ENOBUFS; 33085530c04cSJaewan Kim 33095530c04cSJaewan Kim if (nla_put_u8(msg, NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION, request->burst_duration)) 33105530c04cSJaewan Kim return -ENOBUFS; 33115530c04cSJaewan Kim 33125530c04cSJaewan Kim if (nla_put_u8(msg, NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR, request->bss_color)) 33135530c04cSJaewan Kim return -ENOBUFS; 33145530c04cSJaewan Kim 33155530c04cSJaewan Kim nla_nest_end(msg, ftm); 33165530c04cSJaewan Kim 33175530c04cSJaewan Kim return 0; 33185530c04cSJaewan Kim } 33195530c04cSJaewan Kim 33205530c04cSJaewan Kim static int mac80211_hwsim_send_pmsr_request_peer(struct sk_buff *msg, 33215530c04cSJaewan Kim struct cfg80211_pmsr_request_peer *request) 33225530c04cSJaewan Kim { 33235530c04cSJaewan Kim struct nlattr *peer, *chandef, *req, *data; 33245530c04cSJaewan Kim int err; 33255530c04cSJaewan Kim 33265530c04cSJaewan Kim peer = nla_nest_start(msg, NL80211_PMSR_ATTR_PEERS); 33275530c04cSJaewan Kim if (!peer) 33285530c04cSJaewan Kim return -ENOBUFS; 33295530c04cSJaewan Kim 33305530c04cSJaewan Kim if (nla_put(msg, NL80211_PMSR_PEER_ATTR_ADDR, ETH_ALEN, 33315530c04cSJaewan Kim request->addr)) 33325530c04cSJaewan Kim return -ENOBUFS; 33335530c04cSJaewan Kim 33345530c04cSJaewan Kim chandef = nla_nest_start(msg, NL80211_PMSR_PEER_ATTR_CHAN); 33355530c04cSJaewan Kim if (!chandef) 33365530c04cSJaewan Kim return -ENOBUFS; 33375530c04cSJaewan Kim 33385530c04cSJaewan Kim err = nl80211_send_chandef(msg, &request->chandef); 33395530c04cSJaewan Kim if (err) 33405530c04cSJaewan Kim return err; 33415530c04cSJaewan Kim 33425530c04cSJaewan Kim nla_nest_end(msg, chandef); 33435530c04cSJaewan Kim 33445530c04cSJaewan Kim req = nla_nest_start(msg, NL80211_PMSR_PEER_ATTR_REQ); 33455530c04cSJaewan Kim if (!req) 33465530c04cSJaewan Kim return -ENOBUFS; 33475530c04cSJaewan Kim 33485530c04cSJaewan Kim if (request->report_ap_tsf && nla_put_flag(msg, NL80211_PMSR_REQ_ATTR_GET_AP_TSF)) 33495530c04cSJaewan Kim return -ENOBUFS; 33505530c04cSJaewan Kim 33515530c04cSJaewan Kim data = nla_nest_start(msg, NL80211_PMSR_REQ_ATTR_DATA); 33525530c04cSJaewan Kim if (!data) 33535530c04cSJaewan Kim return -ENOBUFS; 33545530c04cSJaewan Kim 33555530c04cSJaewan Kim err = mac80211_hwsim_send_pmsr_ftm_request_peer(msg, &request->ftm); 33565530c04cSJaewan Kim if (err) 33575530c04cSJaewan Kim return err; 33585530c04cSJaewan Kim 33595530c04cSJaewan Kim nla_nest_end(msg, data); 33605530c04cSJaewan Kim nla_nest_end(msg, req); 33615530c04cSJaewan Kim nla_nest_end(msg, peer); 33625530c04cSJaewan Kim 33635530c04cSJaewan Kim return 0; 33645530c04cSJaewan Kim } 33655530c04cSJaewan Kim 33665530c04cSJaewan Kim static int mac80211_hwsim_send_pmsr_request(struct sk_buff *msg, 33675530c04cSJaewan Kim struct cfg80211_pmsr_request *request) 33685530c04cSJaewan Kim { 33695530c04cSJaewan Kim struct nlattr *pmsr; 33705530c04cSJaewan Kim int err; 33715530c04cSJaewan Kim 33725530c04cSJaewan Kim pmsr = nla_nest_start(msg, NL80211_ATTR_PEER_MEASUREMENTS); 33735530c04cSJaewan Kim if (!pmsr) 33745530c04cSJaewan Kim return -ENOBUFS; 33755530c04cSJaewan Kim 33765530c04cSJaewan Kim if (nla_put_u32(msg, NL80211_ATTR_TIMEOUT, request->timeout)) 33775530c04cSJaewan Kim return -ENOBUFS; 33785530c04cSJaewan Kim 33795530c04cSJaewan Kim if (!is_zero_ether_addr(request->mac_addr)) { 33805530c04cSJaewan Kim if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, request->mac_addr)) 33815530c04cSJaewan Kim return -ENOBUFS; 33825530c04cSJaewan Kim if (nla_put(msg, NL80211_ATTR_MAC_MASK, ETH_ALEN, request->mac_addr_mask)) 33835530c04cSJaewan Kim return -ENOBUFS; 33845530c04cSJaewan Kim } 33855530c04cSJaewan Kim 33865530c04cSJaewan Kim for (int i = 0; i < request->n_peers; i++) { 33875530c04cSJaewan Kim err = mac80211_hwsim_send_pmsr_request_peer(msg, &request->peers[i]); 33885530c04cSJaewan Kim if (err) 33895530c04cSJaewan Kim return err; 33905530c04cSJaewan Kim } 33915530c04cSJaewan Kim 33925530c04cSJaewan Kim nla_nest_end(msg, pmsr); 33935530c04cSJaewan Kim 33945530c04cSJaewan Kim return 0; 33955530c04cSJaewan Kim } 33965530c04cSJaewan Kim 33975530c04cSJaewan Kim static int mac80211_hwsim_start_pmsr(struct ieee80211_hw *hw, 33985530c04cSJaewan Kim struct ieee80211_vif *vif, 33995530c04cSJaewan Kim struct cfg80211_pmsr_request *request) 34005530c04cSJaewan Kim { 34015530c04cSJaewan Kim struct mac80211_hwsim_data *data; 34025530c04cSJaewan Kim struct sk_buff *skb = NULL; 34035530c04cSJaewan Kim struct nlattr *pmsr; 34045530c04cSJaewan Kim void *msg_head; 34055530c04cSJaewan Kim u32 _portid; 34065530c04cSJaewan Kim int err = 0; 34075530c04cSJaewan Kim 34085530c04cSJaewan Kim data = hw->priv; 34095530c04cSJaewan Kim _portid = READ_ONCE(data->wmediumd); 34105530c04cSJaewan Kim if (!_portid && !hwsim_virtio_enabled) 34115530c04cSJaewan Kim return -EOPNOTSUPP; 34125530c04cSJaewan Kim 34135530c04cSJaewan Kim mutex_lock(&data->mutex); 34145530c04cSJaewan Kim 34155530c04cSJaewan Kim if (data->pmsr_request) { 34165530c04cSJaewan Kim err = -EBUSY; 34175530c04cSJaewan Kim goto out_free; 34185530c04cSJaewan Kim } 34195530c04cSJaewan Kim 34205530c04cSJaewan Kim skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 34215530c04cSJaewan Kim 34225530c04cSJaewan Kim if (!skb) { 34235530c04cSJaewan Kim err = -ENOMEM; 34245530c04cSJaewan Kim goto out_free; 34255530c04cSJaewan Kim } 34265530c04cSJaewan Kim 34275530c04cSJaewan Kim msg_head = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, HWSIM_CMD_START_PMSR); 34285530c04cSJaewan Kim 34295530c04cSJaewan Kim if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER, 34305530c04cSJaewan Kim ETH_ALEN, data->addresses[1].addr)) { 34315530c04cSJaewan Kim err = -ENOMEM; 34325530c04cSJaewan Kim goto out_free; 34335530c04cSJaewan Kim } 34345530c04cSJaewan Kim 34355530c04cSJaewan Kim pmsr = nla_nest_start(skb, HWSIM_ATTR_PMSR_REQUEST); 34365530c04cSJaewan Kim if (!pmsr) { 34375530c04cSJaewan Kim err = -ENOMEM; 34385530c04cSJaewan Kim goto out_free; 34395530c04cSJaewan Kim } 34405530c04cSJaewan Kim 34415530c04cSJaewan Kim err = mac80211_hwsim_send_pmsr_request(skb, request); 34425530c04cSJaewan Kim if (err) 34435530c04cSJaewan Kim goto out_free; 34445530c04cSJaewan Kim 34455530c04cSJaewan Kim nla_nest_end(skb, pmsr); 34465530c04cSJaewan Kim 34475530c04cSJaewan Kim genlmsg_end(skb, msg_head); 34485530c04cSJaewan Kim if (hwsim_virtio_enabled) 34495530c04cSJaewan Kim hwsim_tx_virtio(data, skb); 34505530c04cSJaewan Kim else 34515530c04cSJaewan Kim hwsim_unicast_netgroup(data, skb, _portid); 34525530c04cSJaewan Kim 34535530c04cSJaewan Kim data->pmsr_request = request; 34545530c04cSJaewan Kim data->pmsr_request_wdev = ieee80211_vif_to_wdev(vif); 34555530c04cSJaewan Kim 34565530c04cSJaewan Kim out_free: 34575530c04cSJaewan Kim if (err && skb) 34585530c04cSJaewan Kim nlmsg_free(skb); 34595530c04cSJaewan Kim 34605530c04cSJaewan Kim mutex_unlock(&data->mutex); 34615530c04cSJaewan Kim return err; 34625530c04cSJaewan Kim } 34635530c04cSJaewan Kim 34648ba1da95SJaewan Kim static void mac80211_hwsim_abort_pmsr(struct ieee80211_hw *hw, 34658ba1da95SJaewan Kim struct ieee80211_vif *vif, 34668ba1da95SJaewan Kim struct cfg80211_pmsr_request *request) 34678ba1da95SJaewan Kim { 34688ba1da95SJaewan Kim struct mac80211_hwsim_data *data; 34698ba1da95SJaewan Kim struct sk_buff *skb = NULL; 34708ba1da95SJaewan Kim struct nlattr *pmsr; 34718ba1da95SJaewan Kim void *msg_head; 34728ba1da95SJaewan Kim u32 _portid; 34738ba1da95SJaewan Kim int err = 0; 34748ba1da95SJaewan Kim 34758ba1da95SJaewan Kim data = hw->priv; 34768ba1da95SJaewan Kim _portid = READ_ONCE(data->wmediumd); 34778ba1da95SJaewan Kim if (!_portid && !hwsim_virtio_enabled) 34788ba1da95SJaewan Kim return; 34798ba1da95SJaewan Kim 34808ba1da95SJaewan Kim mutex_lock(&data->mutex); 34818ba1da95SJaewan Kim 34828ba1da95SJaewan Kim if (data->pmsr_request != request) { 34838ba1da95SJaewan Kim err = -EINVAL; 34848ba1da95SJaewan Kim goto out; 34858ba1da95SJaewan Kim } 34868ba1da95SJaewan Kim 34878ba1da95SJaewan Kim skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 34888ba1da95SJaewan Kim if (!skb) { 34898ba1da95SJaewan Kim err = -ENOMEM; 34908ba1da95SJaewan Kim goto out; 34918ba1da95SJaewan Kim } 34928ba1da95SJaewan Kim 34938ba1da95SJaewan Kim msg_head = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, HWSIM_CMD_ABORT_PMSR); 34948ba1da95SJaewan Kim 34958ba1da95SJaewan Kim if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER, ETH_ALEN, data->addresses[1].addr)) 34968ba1da95SJaewan Kim goto out; 34978ba1da95SJaewan Kim 34988ba1da95SJaewan Kim pmsr = nla_nest_start(skb, HWSIM_ATTR_PMSR_REQUEST); 34998ba1da95SJaewan Kim if (!pmsr) { 35008ba1da95SJaewan Kim err = -ENOMEM; 35018ba1da95SJaewan Kim goto out; 35028ba1da95SJaewan Kim } 35038ba1da95SJaewan Kim 35048ba1da95SJaewan Kim err = mac80211_hwsim_send_pmsr_request(skb, request); 35058ba1da95SJaewan Kim if (err) 35068ba1da95SJaewan Kim goto out; 35078ba1da95SJaewan Kim 35088ba1da95SJaewan Kim err = nla_nest_end(skb, pmsr); 35098ba1da95SJaewan Kim if (err) 35108ba1da95SJaewan Kim goto out; 35118ba1da95SJaewan Kim 35128ba1da95SJaewan Kim genlmsg_end(skb, msg_head); 35138ba1da95SJaewan Kim if (hwsim_virtio_enabled) 35148ba1da95SJaewan Kim hwsim_tx_virtio(data, skb); 35158ba1da95SJaewan Kim else 35168ba1da95SJaewan Kim hwsim_unicast_netgroup(data, skb, _portid); 35178ba1da95SJaewan Kim 35188ba1da95SJaewan Kim out: 35198ba1da95SJaewan Kim if (err && skb) 35208ba1da95SJaewan Kim nlmsg_free(skb); 35218ba1da95SJaewan Kim 35228ba1da95SJaewan Kim mutex_unlock(&data->mutex); 35238ba1da95SJaewan Kim } 35248ba1da95SJaewan Kim 35252af3b2a6SJaewan Kim static int mac80211_hwsim_parse_rate_info(struct nlattr *rateattr, 35262af3b2a6SJaewan Kim struct rate_info *rate_info, 35272af3b2a6SJaewan Kim struct genl_info *info) 35282af3b2a6SJaewan Kim { 35292af3b2a6SJaewan Kim struct nlattr *tb[HWSIM_RATE_INFO_ATTR_MAX + 1]; 35302af3b2a6SJaewan Kim int ret; 35312af3b2a6SJaewan Kim 35322af3b2a6SJaewan Kim ret = nla_parse_nested(tb, HWSIM_RATE_INFO_ATTR_MAX, 35332af3b2a6SJaewan Kim rateattr, hwsim_rate_info_policy, info->extack); 35342af3b2a6SJaewan Kim if (ret) 35352af3b2a6SJaewan Kim return ret; 35362af3b2a6SJaewan Kim 35372af3b2a6SJaewan Kim if (tb[HWSIM_RATE_INFO_ATTR_FLAGS]) 35382af3b2a6SJaewan Kim rate_info->flags = nla_get_u8(tb[HWSIM_RATE_INFO_ATTR_FLAGS]); 35392af3b2a6SJaewan Kim 35402af3b2a6SJaewan Kim if (tb[HWSIM_RATE_INFO_ATTR_MCS]) 35412af3b2a6SJaewan Kim rate_info->mcs = nla_get_u8(tb[HWSIM_RATE_INFO_ATTR_MCS]); 35422af3b2a6SJaewan Kim 35432af3b2a6SJaewan Kim if (tb[HWSIM_RATE_INFO_ATTR_LEGACY]) 35442af3b2a6SJaewan Kim rate_info->legacy = nla_get_u16(tb[HWSIM_RATE_INFO_ATTR_LEGACY]); 35452af3b2a6SJaewan Kim 35462af3b2a6SJaewan Kim if (tb[HWSIM_RATE_INFO_ATTR_NSS]) 35472af3b2a6SJaewan Kim rate_info->nss = nla_get_u8(tb[HWSIM_RATE_INFO_ATTR_NSS]); 35482af3b2a6SJaewan Kim 35492af3b2a6SJaewan Kim if (tb[HWSIM_RATE_INFO_ATTR_BW]) 35502af3b2a6SJaewan Kim rate_info->bw = nla_get_u8(tb[HWSIM_RATE_INFO_ATTR_BW]); 35512af3b2a6SJaewan Kim 35522af3b2a6SJaewan Kim if (tb[HWSIM_RATE_INFO_ATTR_HE_GI]) 35532af3b2a6SJaewan Kim rate_info->he_gi = nla_get_u8(tb[HWSIM_RATE_INFO_ATTR_HE_GI]); 35542af3b2a6SJaewan Kim 35552af3b2a6SJaewan Kim if (tb[HWSIM_RATE_INFO_ATTR_HE_DCM]) 35562af3b2a6SJaewan Kim rate_info->he_dcm = nla_get_u8(tb[HWSIM_RATE_INFO_ATTR_HE_DCM]); 35572af3b2a6SJaewan Kim 35582af3b2a6SJaewan Kim if (tb[HWSIM_RATE_INFO_ATTR_HE_RU_ALLOC]) 35592af3b2a6SJaewan Kim rate_info->he_ru_alloc = 35602af3b2a6SJaewan Kim nla_get_u8(tb[HWSIM_RATE_INFO_ATTR_HE_RU_ALLOC]); 35612af3b2a6SJaewan Kim 35622af3b2a6SJaewan Kim if (tb[HWSIM_RATE_INFO_ATTR_N_BOUNDED_CH]) 35632af3b2a6SJaewan Kim rate_info->n_bonded_ch = nla_get_u8(tb[HWSIM_RATE_INFO_ATTR_N_BOUNDED_CH]); 35642af3b2a6SJaewan Kim 35652af3b2a6SJaewan Kim if (tb[HWSIM_RATE_INFO_ATTR_EHT_GI]) 35662af3b2a6SJaewan Kim rate_info->eht_gi = nla_get_u8(tb[HWSIM_RATE_INFO_ATTR_EHT_GI]); 35672af3b2a6SJaewan Kim 35682af3b2a6SJaewan Kim if (tb[HWSIM_RATE_INFO_ATTR_EHT_RU_ALLOC]) 35692af3b2a6SJaewan Kim rate_info->eht_ru_alloc = nla_get_u8(tb[HWSIM_RATE_INFO_ATTR_EHT_RU_ALLOC]); 35702af3b2a6SJaewan Kim 35712af3b2a6SJaewan Kim return 0; 35722af3b2a6SJaewan Kim } 35732af3b2a6SJaewan Kim 35742af3b2a6SJaewan Kim static int mac80211_hwsim_parse_ftm_result(struct nlattr *ftm, 35752af3b2a6SJaewan Kim struct cfg80211_pmsr_ftm_result *result, 35762af3b2a6SJaewan Kim struct genl_info *info) 35772af3b2a6SJaewan Kim { 35782af3b2a6SJaewan Kim struct nlattr *tb[NL80211_PMSR_FTM_RESP_ATTR_MAX + 1]; 35792af3b2a6SJaewan Kim int ret; 35802af3b2a6SJaewan Kim 35812af3b2a6SJaewan Kim ret = nla_parse_nested(tb, NL80211_PMSR_FTM_RESP_ATTR_MAX, 35822af3b2a6SJaewan Kim ftm, hwsim_ftm_result_policy, info->extack); 35832af3b2a6SJaewan Kim if (ret) 35842af3b2a6SJaewan Kim return ret; 35852af3b2a6SJaewan Kim 35862af3b2a6SJaewan Kim if (tb[NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON]) 35872af3b2a6SJaewan Kim result->failure_reason = nla_get_u32(tb[NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON]); 35882af3b2a6SJaewan Kim 35892af3b2a6SJaewan Kim if (tb[NL80211_PMSR_FTM_RESP_ATTR_BURST_INDEX]) 35902af3b2a6SJaewan Kim result->burst_index = nla_get_u16(tb[NL80211_PMSR_FTM_RESP_ATTR_BURST_INDEX]); 35912af3b2a6SJaewan Kim 35922af3b2a6SJaewan Kim if (tb[NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_ATTEMPTS]) { 35932af3b2a6SJaewan Kim result->num_ftmr_attempts_valid = 1; 35942af3b2a6SJaewan Kim result->num_ftmr_attempts = 35952af3b2a6SJaewan Kim nla_get_u32(tb[NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_ATTEMPTS]); 35962af3b2a6SJaewan Kim } 35972af3b2a6SJaewan Kim 35982af3b2a6SJaewan Kim if (tb[NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_SUCCESSES]) { 35992af3b2a6SJaewan Kim result->num_ftmr_successes_valid = 1; 36002af3b2a6SJaewan Kim result->num_ftmr_successes = 36012af3b2a6SJaewan Kim nla_get_u32(tb[NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_SUCCESSES]); 36022af3b2a6SJaewan Kim } 36032af3b2a6SJaewan Kim 36042af3b2a6SJaewan Kim if (tb[NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME]) 36052af3b2a6SJaewan Kim result->busy_retry_time = 36062af3b2a6SJaewan Kim nla_get_u8(tb[NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME]); 36072af3b2a6SJaewan Kim 36082af3b2a6SJaewan Kim if (tb[NL80211_PMSR_FTM_RESP_ATTR_NUM_BURSTS_EXP]) 36092af3b2a6SJaewan Kim result->num_bursts_exp = nla_get_u8(tb[NL80211_PMSR_FTM_RESP_ATTR_NUM_BURSTS_EXP]); 36102af3b2a6SJaewan Kim 36112af3b2a6SJaewan Kim if (tb[NL80211_PMSR_FTM_RESP_ATTR_BURST_DURATION]) 36122af3b2a6SJaewan Kim result->burst_duration = nla_get_u8(tb[NL80211_PMSR_FTM_RESP_ATTR_BURST_DURATION]); 36132af3b2a6SJaewan Kim 36142af3b2a6SJaewan Kim if (tb[NL80211_PMSR_FTM_RESP_ATTR_FTMS_PER_BURST]) 36152af3b2a6SJaewan Kim result->ftms_per_burst = nla_get_u8(tb[NL80211_PMSR_FTM_RESP_ATTR_FTMS_PER_BURST]); 36162af3b2a6SJaewan Kim 36172af3b2a6SJaewan Kim if (tb[NL80211_PMSR_FTM_RESP_ATTR_RSSI_AVG]) { 36182af3b2a6SJaewan Kim result->rssi_avg_valid = 1; 36192af3b2a6SJaewan Kim result->rssi_avg = nla_get_s32(tb[NL80211_PMSR_FTM_RESP_ATTR_RSSI_AVG]); 36202af3b2a6SJaewan Kim } 36212af3b2a6SJaewan Kim if (tb[NL80211_PMSR_FTM_RESP_ATTR_RSSI_SPREAD]) { 36222af3b2a6SJaewan Kim result->rssi_spread_valid = 1; 36232af3b2a6SJaewan Kim result->rssi_spread = 36242af3b2a6SJaewan Kim nla_get_s32(tb[NL80211_PMSR_FTM_RESP_ATTR_RSSI_SPREAD]); 36252af3b2a6SJaewan Kim } 36262af3b2a6SJaewan Kim 36272af3b2a6SJaewan Kim if (tb[NL80211_PMSR_FTM_RESP_ATTR_TX_RATE]) { 36282af3b2a6SJaewan Kim result->tx_rate_valid = 1; 36292af3b2a6SJaewan Kim ret = mac80211_hwsim_parse_rate_info(tb[NL80211_PMSR_FTM_RESP_ATTR_TX_RATE], 36302af3b2a6SJaewan Kim &result->tx_rate, info); 36312af3b2a6SJaewan Kim if (ret) 36322af3b2a6SJaewan Kim return ret; 36332af3b2a6SJaewan Kim } 36342af3b2a6SJaewan Kim 36352af3b2a6SJaewan Kim if (tb[NL80211_PMSR_FTM_RESP_ATTR_RX_RATE]) { 36362af3b2a6SJaewan Kim result->rx_rate_valid = 1; 36372af3b2a6SJaewan Kim ret = mac80211_hwsim_parse_rate_info(tb[NL80211_PMSR_FTM_RESP_ATTR_RX_RATE], 36382af3b2a6SJaewan Kim &result->rx_rate, info); 36392af3b2a6SJaewan Kim if (ret) 36402af3b2a6SJaewan Kim return ret; 36412af3b2a6SJaewan Kim } 36422af3b2a6SJaewan Kim 36432af3b2a6SJaewan Kim if (tb[NL80211_PMSR_FTM_RESP_ATTR_RTT_AVG]) { 36442af3b2a6SJaewan Kim result->rtt_avg_valid = 1; 36452af3b2a6SJaewan Kim result->rtt_avg = 36462af3b2a6SJaewan Kim nla_get_u64(tb[NL80211_PMSR_FTM_RESP_ATTR_RTT_AVG]); 36472af3b2a6SJaewan Kim } 36482af3b2a6SJaewan Kim if (tb[NL80211_PMSR_FTM_RESP_ATTR_RTT_VARIANCE]) { 36492af3b2a6SJaewan Kim result->rtt_variance_valid = 1; 36502af3b2a6SJaewan Kim result->rtt_variance = 36512af3b2a6SJaewan Kim nla_get_u64(tb[NL80211_PMSR_FTM_RESP_ATTR_RTT_VARIANCE]); 36522af3b2a6SJaewan Kim } 36532af3b2a6SJaewan Kim if (tb[NL80211_PMSR_FTM_RESP_ATTR_RTT_SPREAD]) { 36542af3b2a6SJaewan Kim result->rtt_spread_valid = 1; 36552af3b2a6SJaewan Kim result->rtt_spread = 36562af3b2a6SJaewan Kim nla_get_u64(tb[NL80211_PMSR_FTM_RESP_ATTR_RTT_SPREAD]); 36572af3b2a6SJaewan Kim } 36582af3b2a6SJaewan Kim if (tb[NL80211_PMSR_FTM_RESP_ATTR_DIST_AVG]) { 36592af3b2a6SJaewan Kim result->dist_avg_valid = 1; 36602af3b2a6SJaewan Kim result->dist_avg = 36612af3b2a6SJaewan Kim nla_get_u64(tb[NL80211_PMSR_FTM_RESP_ATTR_DIST_AVG]); 36622af3b2a6SJaewan Kim } 36632af3b2a6SJaewan Kim if (tb[NL80211_PMSR_FTM_RESP_ATTR_DIST_VARIANCE]) { 36642af3b2a6SJaewan Kim result->dist_variance_valid = 1; 36652af3b2a6SJaewan Kim result->dist_variance = 36662af3b2a6SJaewan Kim nla_get_u64(tb[NL80211_PMSR_FTM_RESP_ATTR_DIST_VARIANCE]); 36672af3b2a6SJaewan Kim } 36682af3b2a6SJaewan Kim if (tb[NL80211_PMSR_FTM_RESP_ATTR_DIST_SPREAD]) { 36692af3b2a6SJaewan Kim result->dist_spread_valid = 1; 36702af3b2a6SJaewan Kim result->dist_spread = 36712af3b2a6SJaewan Kim nla_get_u64(tb[NL80211_PMSR_FTM_RESP_ATTR_DIST_SPREAD]); 36722af3b2a6SJaewan Kim } 36732af3b2a6SJaewan Kim 36742af3b2a6SJaewan Kim if (tb[NL80211_PMSR_FTM_RESP_ATTR_LCI]) { 36752af3b2a6SJaewan Kim result->lci = nla_data(tb[NL80211_PMSR_FTM_RESP_ATTR_LCI]); 36762af3b2a6SJaewan Kim result->lci_len = nla_len(tb[NL80211_PMSR_FTM_RESP_ATTR_LCI]); 36772af3b2a6SJaewan Kim } 36782af3b2a6SJaewan Kim 36792af3b2a6SJaewan Kim if (tb[NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC]) { 36802af3b2a6SJaewan Kim result->civicloc = nla_data(tb[NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC]); 36812af3b2a6SJaewan Kim result->civicloc_len = nla_len(tb[NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC]); 36822af3b2a6SJaewan Kim } 36832af3b2a6SJaewan Kim 36842af3b2a6SJaewan Kim return 0; 36852af3b2a6SJaewan Kim } 36862af3b2a6SJaewan Kim 36872af3b2a6SJaewan Kim static int mac80211_hwsim_parse_pmsr_resp(struct nlattr *resp, 36882af3b2a6SJaewan Kim struct cfg80211_pmsr_result *result, 36892af3b2a6SJaewan Kim struct genl_info *info) 36902af3b2a6SJaewan Kim { 36912af3b2a6SJaewan Kim struct nlattr *tb[NL80211_PMSR_RESP_ATTR_MAX + 1]; 36922af3b2a6SJaewan Kim struct nlattr *pmsr; 36932af3b2a6SJaewan Kim int rem; 36942af3b2a6SJaewan Kim int ret; 36952af3b2a6SJaewan Kim 36962af3b2a6SJaewan Kim ret = nla_parse_nested(tb, NL80211_PMSR_RESP_ATTR_MAX, resp, hwsim_pmsr_resp_policy, 36972af3b2a6SJaewan Kim info->extack); 36982af3b2a6SJaewan Kim if (ret) 36992af3b2a6SJaewan Kim return ret; 37002af3b2a6SJaewan Kim 37012af3b2a6SJaewan Kim if (tb[NL80211_PMSR_RESP_ATTR_STATUS]) 37022af3b2a6SJaewan Kim result->status = nla_get_u32(tb[NL80211_PMSR_RESP_ATTR_STATUS]); 37032af3b2a6SJaewan Kim 37042af3b2a6SJaewan Kim if (tb[NL80211_PMSR_RESP_ATTR_HOST_TIME]) 37052af3b2a6SJaewan Kim result->host_time = nla_get_u64(tb[NL80211_PMSR_RESP_ATTR_HOST_TIME]); 37062af3b2a6SJaewan Kim 37072af3b2a6SJaewan Kim if (tb[NL80211_PMSR_RESP_ATTR_AP_TSF]) { 37082af3b2a6SJaewan Kim result->ap_tsf_valid = 1; 37092af3b2a6SJaewan Kim result->ap_tsf = nla_get_u64(tb[NL80211_PMSR_RESP_ATTR_AP_TSF]); 37102af3b2a6SJaewan Kim } 37112af3b2a6SJaewan Kim 37122af3b2a6SJaewan Kim result->final = !!tb[NL80211_PMSR_RESP_ATTR_FINAL]; 37132af3b2a6SJaewan Kim 37142af3b2a6SJaewan Kim if (!tb[NL80211_PMSR_RESP_ATTR_DATA]) 37152af3b2a6SJaewan Kim return 0; 37162af3b2a6SJaewan Kim 37172af3b2a6SJaewan Kim nla_for_each_nested(pmsr, tb[NL80211_PMSR_RESP_ATTR_DATA], rem) { 37182af3b2a6SJaewan Kim switch (nla_type(pmsr)) { 37192af3b2a6SJaewan Kim case NL80211_PMSR_TYPE_FTM: 37202af3b2a6SJaewan Kim result->type = NL80211_PMSR_TYPE_FTM; 37212af3b2a6SJaewan Kim ret = mac80211_hwsim_parse_ftm_result(pmsr, &result->ftm, info); 37222af3b2a6SJaewan Kim if (ret) 37232af3b2a6SJaewan Kim return ret; 37242af3b2a6SJaewan Kim break; 37252af3b2a6SJaewan Kim default: 37262af3b2a6SJaewan Kim NL_SET_ERR_MSG_ATTR(info->extack, pmsr, "Unknown pmsr resp type"); 37272af3b2a6SJaewan Kim return -EINVAL; 37282af3b2a6SJaewan Kim } 37292af3b2a6SJaewan Kim } 37302af3b2a6SJaewan Kim 37312af3b2a6SJaewan Kim return 0; 37322af3b2a6SJaewan Kim } 37332af3b2a6SJaewan Kim 37342af3b2a6SJaewan Kim static int mac80211_hwsim_parse_pmsr_result(struct nlattr *peer, 37352af3b2a6SJaewan Kim struct cfg80211_pmsr_result *result, 37362af3b2a6SJaewan Kim struct genl_info *info) 37372af3b2a6SJaewan Kim { 37382af3b2a6SJaewan Kim struct nlattr *tb[NL80211_PMSR_PEER_ATTR_MAX + 1]; 37392af3b2a6SJaewan Kim int ret; 37402af3b2a6SJaewan Kim 37412af3b2a6SJaewan Kim if (!peer) 37422af3b2a6SJaewan Kim return -EINVAL; 37432af3b2a6SJaewan Kim 37442af3b2a6SJaewan Kim ret = nla_parse_nested(tb, NL80211_PMSR_PEER_ATTR_MAX, peer, 37452af3b2a6SJaewan Kim hwsim_pmsr_peer_result_policy, info->extack); 37462af3b2a6SJaewan Kim if (ret) 37472af3b2a6SJaewan Kim return ret; 37482af3b2a6SJaewan Kim 37492af3b2a6SJaewan Kim if (tb[NL80211_PMSR_PEER_ATTR_ADDR]) 37502af3b2a6SJaewan Kim memcpy(result->addr, nla_data(tb[NL80211_PMSR_PEER_ATTR_ADDR]), 37512af3b2a6SJaewan Kim ETH_ALEN); 37522af3b2a6SJaewan Kim 37532af3b2a6SJaewan Kim if (tb[NL80211_PMSR_PEER_ATTR_RESP]) { 37542af3b2a6SJaewan Kim ret = mac80211_hwsim_parse_pmsr_resp(tb[NL80211_PMSR_PEER_ATTR_RESP], result, info); 37552af3b2a6SJaewan Kim if (ret) 37562af3b2a6SJaewan Kim return ret; 37572af3b2a6SJaewan Kim } 37582af3b2a6SJaewan Kim 37592af3b2a6SJaewan Kim return 0; 37602af3b2a6SJaewan Kim }; 37612af3b2a6SJaewan Kim 37622af3b2a6SJaewan Kim static int hwsim_pmsr_report_nl(struct sk_buff *msg, struct genl_info *info) 37632af3b2a6SJaewan Kim { 37642af3b2a6SJaewan Kim struct mac80211_hwsim_data *data; 37652af3b2a6SJaewan Kim struct nlattr *peers, *peer; 37662af3b2a6SJaewan Kim struct nlattr *reqattr; 37672af3b2a6SJaewan Kim const u8 *src; 37682af3b2a6SJaewan Kim int err; 37692af3b2a6SJaewan Kim int rem; 37702af3b2a6SJaewan Kim 37712bef4d1fSEric Dumazet if (!info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER]) 37722bef4d1fSEric Dumazet return -EINVAL; 37732bef4d1fSEric Dumazet 37742af3b2a6SJaewan Kim src = nla_data(info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER]); 37752af3b2a6SJaewan Kim data = get_hwsim_data_ref_from_addr(src); 37762af3b2a6SJaewan Kim if (!data) 37772af3b2a6SJaewan Kim return -EINVAL; 37782af3b2a6SJaewan Kim 37792af3b2a6SJaewan Kim mutex_lock(&data->mutex); 37802af3b2a6SJaewan Kim if (!data->pmsr_request) { 37812af3b2a6SJaewan Kim err = -EINVAL; 37822af3b2a6SJaewan Kim goto out; 37832af3b2a6SJaewan Kim } 37842af3b2a6SJaewan Kim 37852af3b2a6SJaewan Kim reqattr = info->attrs[HWSIM_ATTR_PMSR_RESULT]; 37862af3b2a6SJaewan Kim if (!reqattr) { 37872af3b2a6SJaewan Kim err = -EINVAL; 37882af3b2a6SJaewan Kim goto out; 37892af3b2a6SJaewan Kim } 37902af3b2a6SJaewan Kim 37912af3b2a6SJaewan Kim peers = nla_find_nested(reqattr, NL80211_PMSR_ATTR_PEERS); 37922af3b2a6SJaewan Kim if (!peers) { 37932af3b2a6SJaewan Kim err = -EINVAL; 37942af3b2a6SJaewan Kim goto out; 37952af3b2a6SJaewan Kim } 37962af3b2a6SJaewan Kim 37972af3b2a6SJaewan Kim nla_for_each_nested(peer, peers, rem) { 3798*115cd096SJohannes Berg struct cfg80211_pmsr_result result = {}; 37992af3b2a6SJaewan Kim 38002af3b2a6SJaewan Kim err = mac80211_hwsim_parse_pmsr_result(peer, &result, info); 38012af3b2a6SJaewan Kim if (err) 38022af3b2a6SJaewan Kim goto out; 38032af3b2a6SJaewan Kim 38042af3b2a6SJaewan Kim cfg80211_pmsr_report(data->pmsr_request_wdev, 38052af3b2a6SJaewan Kim data->pmsr_request, &result, GFP_KERNEL); 38062af3b2a6SJaewan Kim } 38072af3b2a6SJaewan Kim 38082af3b2a6SJaewan Kim cfg80211_pmsr_complete(data->pmsr_request_wdev, data->pmsr_request, GFP_KERNEL); 38092af3b2a6SJaewan Kim 38102af3b2a6SJaewan Kim err = 0; 38112af3b2a6SJaewan Kim out: 38122af3b2a6SJaewan Kim data->pmsr_request = NULL; 38132af3b2a6SJaewan Kim data->pmsr_request_wdev = NULL; 38142af3b2a6SJaewan Kim 38152af3b2a6SJaewan Kim mutex_unlock(&data->mutex); 38162af3b2a6SJaewan Kim return err; 38172af3b2a6SJaewan Kim } 38182af3b2a6SJaewan Kim 3819f79cbc77SKalle Valo #define HWSIM_COMMON_OPS \ 3820f79cbc77SKalle Valo .tx = mac80211_hwsim_tx, \ 3821f79cbc77SKalle Valo .wake_tx_queue = ieee80211_handle_wake_tx_queue, \ 3822f79cbc77SKalle Valo .start = mac80211_hwsim_start, \ 3823f79cbc77SKalle Valo .stop = mac80211_hwsim_stop, \ 3824f79cbc77SKalle Valo .add_interface = mac80211_hwsim_add_interface, \ 3825f79cbc77SKalle Valo .change_interface = mac80211_hwsim_change_interface, \ 3826f79cbc77SKalle Valo .remove_interface = mac80211_hwsim_remove_interface, \ 3827f79cbc77SKalle Valo .config = mac80211_hwsim_config, \ 3828f79cbc77SKalle Valo .configure_filter = mac80211_hwsim_configure_filter, \ 3829f79cbc77SKalle Valo .vif_cfg_changed = mac80211_hwsim_vif_info_changed, \ 3830f79cbc77SKalle Valo .link_info_changed = mac80211_hwsim_link_info_changed, \ 3831f79cbc77SKalle Valo .tx_last_beacon = mac80211_hwsim_tx_last_beacon, \ 3832f79cbc77SKalle Valo .sta_notify = mac80211_hwsim_sta_notify, \ 3833f79cbc77SKalle Valo .sta_rc_update = mac80211_hwsim_sta_rc_update, \ 3834f79cbc77SKalle Valo .conf_tx = mac80211_hwsim_conf_tx, \ 3835f79cbc77SKalle Valo .get_survey = mac80211_hwsim_get_survey, \ 3836f79cbc77SKalle Valo CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd) \ 3837f79cbc77SKalle Valo .ampdu_action = mac80211_hwsim_ampdu_action, \ 3838f79cbc77SKalle Valo .flush = mac80211_hwsim_flush, \ 3839f79cbc77SKalle Valo .get_et_sset_count = mac80211_hwsim_get_et_sset_count, \ 3840f79cbc77SKalle Valo .get_et_stats = mac80211_hwsim_get_et_stats, \ 38415530c04cSJaewan Kim .get_et_strings = mac80211_hwsim_get_et_strings, \ 38425530c04cSJaewan Kim .start_pmsr = mac80211_hwsim_start_pmsr, \ 38438ba1da95SJaewan Kim .abort_pmsr = mac80211_hwsim_abort_pmsr, 3844f79cbc77SKalle Valo 3845f79cbc77SKalle Valo #define HWSIM_NON_MLO_OPS \ 3846f79cbc77SKalle Valo .sta_add = mac80211_hwsim_sta_add, \ 3847f79cbc77SKalle Valo .sta_remove = mac80211_hwsim_sta_remove, \ 3848f79cbc77SKalle Valo .set_tim = mac80211_hwsim_set_tim, \ 3849f79cbc77SKalle Valo .get_tsf = mac80211_hwsim_get_tsf, \ 3850f79cbc77SKalle Valo .set_tsf = mac80211_hwsim_set_tsf, 3851f79cbc77SKalle Valo 3852f79cbc77SKalle Valo static const struct ieee80211_ops mac80211_hwsim_ops = { 3853f79cbc77SKalle Valo HWSIM_COMMON_OPS 3854f79cbc77SKalle Valo HWSIM_NON_MLO_OPS 3855f79cbc77SKalle Valo .sw_scan_start = mac80211_hwsim_sw_scan, 3856f79cbc77SKalle Valo .sw_scan_complete = mac80211_hwsim_sw_scan_complete, 3857f79cbc77SKalle Valo }; 3858f79cbc77SKalle Valo 3859f79cbc77SKalle Valo #define HWSIM_CHANCTX_OPS \ 3860f79cbc77SKalle Valo .hw_scan = mac80211_hwsim_hw_scan, \ 3861f79cbc77SKalle Valo .cancel_hw_scan = mac80211_hwsim_cancel_hw_scan, \ 3862f79cbc77SKalle Valo .remain_on_channel = mac80211_hwsim_roc, \ 3863f79cbc77SKalle Valo .cancel_remain_on_channel = mac80211_hwsim_croc, \ 3864f79cbc77SKalle Valo .add_chanctx = mac80211_hwsim_add_chanctx, \ 3865f79cbc77SKalle Valo .remove_chanctx = mac80211_hwsim_remove_chanctx, \ 3866f79cbc77SKalle Valo .change_chanctx = mac80211_hwsim_change_chanctx, \ 3867f79cbc77SKalle Valo .assign_vif_chanctx = mac80211_hwsim_assign_vif_chanctx,\ 3868f79cbc77SKalle Valo .unassign_vif_chanctx = mac80211_hwsim_unassign_vif_chanctx, 3869f79cbc77SKalle Valo 3870f79cbc77SKalle Valo static const struct ieee80211_ops mac80211_hwsim_mchan_ops = { 3871f79cbc77SKalle Valo HWSIM_COMMON_OPS 3872f79cbc77SKalle Valo HWSIM_NON_MLO_OPS 3873f79cbc77SKalle Valo HWSIM_CHANCTX_OPS 3874f79cbc77SKalle Valo }; 3875f79cbc77SKalle Valo 3876f79cbc77SKalle Valo static const struct ieee80211_ops mac80211_hwsim_mlo_ops = { 3877f79cbc77SKalle Valo HWSIM_COMMON_OPS 3878f79cbc77SKalle Valo HWSIM_CHANCTX_OPS 3879f79cbc77SKalle Valo .set_rts_threshold = mac80211_hwsim_set_rts_threshold, 3880f79cbc77SKalle Valo .change_vif_links = mac80211_hwsim_change_vif_links, 3881f79cbc77SKalle Valo .change_sta_links = mac80211_hwsim_change_sta_links, 3882f79cbc77SKalle Valo .sta_state = mac80211_hwsim_sta_state, 3883f79cbc77SKalle Valo }; 3884f79cbc77SKalle Valo 3885f79cbc77SKalle Valo struct hwsim_new_radio_params { 3886f79cbc77SKalle Valo unsigned int channels; 3887f79cbc77SKalle Valo const char *reg_alpha2; 3888f79cbc77SKalle Valo const struct ieee80211_regdomain *regd; 3889f79cbc77SKalle Valo bool reg_strict; 3890f79cbc77SKalle Valo bool p2p_device; 3891f79cbc77SKalle Valo bool use_chanctx; 3892f79cbc77SKalle Valo bool destroy_on_close; 3893f79cbc77SKalle Valo const char *hwname; 3894f79cbc77SKalle Valo bool no_vif; 3895f79cbc77SKalle Valo const u8 *perm_addr; 3896f79cbc77SKalle Valo u32 iftypes; 3897f79cbc77SKalle Valo u32 *ciphers; 3898f79cbc77SKalle Valo u8 n_ciphers; 3899f79cbc77SKalle Valo bool mlo; 390092d13386SJaewan Kim const struct cfg80211_pmsr_capabilities *pmsr_capa; 3901f79cbc77SKalle Valo }; 3902f79cbc77SKalle Valo 3903f79cbc77SKalle Valo static void hwsim_mcast_config_msg(struct sk_buff *mcast_skb, 3904f79cbc77SKalle Valo struct genl_info *info) 3905f79cbc77SKalle Valo { 3906f79cbc77SKalle Valo if (info) 3907f79cbc77SKalle Valo genl_notify(&hwsim_genl_family, mcast_skb, info, 3908f79cbc77SKalle Valo HWSIM_MCGRP_CONFIG, GFP_KERNEL); 3909f79cbc77SKalle Valo else 3910f79cbc77SKalle Valo genlmsg_multicast(&hwsim_genl_family, mcast_skb, 0, 3911f79cbc77SKalle Valo HWSIM_MCGRP_CONFIG, GFP_KERNEL); 3912f79cbc77SKalle Valo } 3913f79cbc77SKalle Valo 3914f79cbc77SKalle Valo static int append_radio_msg(struct sk_buff *skb, int id, 3915f79cbc77SKalle Valo struct hwsim_new_radio_params *param) 3916f79cbc77SKalle Valo { 3917f79cbc77SKalle Valo int ret; 3918f79cbc77SKalle Valo 3919f79cbc77SKalle Valo ret = nla_put_u32(skb, HWSIM_ATTR_RADIO_ID, id); 3920f79cbc77SKalle Valo if (ret < 0) 3921f79cbc77SKalle Valo return ret; 3922f79cbc77SKalle Valo 3923f79cbc77SKalle Valo if (param->channels) { 3924f79cbc77SKalle Valo ret = nla_put_u32(skb, HWSIM_ATTR_CHANNELS, param->channels); 3925f79cbc77SKalle Valo if (ret < 0) 3926f79cbc77SKalle Valo return ret; 3927f79cbc77SKalle Valo } 3928f79cbc77SKalle Valo 3929f79cbc77SKalle Valo if (param->reg_alpha2) { 3930f79cbc77SKalle Valo ret = nla_put(skb, HWSIM_ATTR_REG_HINT_ALPHA2, 2, 3931f79cbc77SKalle Valo param->reg_alpha2); 3932f79cbc77SKalle Valo if (ret < 0) 3933f79cbc77SKalle Valo return ret; 3934f79cbc77SKalle Valo } 3935f79cbc77SKalle Valo 3936f79cbc77SKalle Valo if (param->regd) { 3937f79cbc77SKalle Valo int i; 3938f79cbc77SKalle Valo 3939f79cbc77SKalle Valo for (i = 0; i < ARRAY_SIZE(hwsim_world_regdom_custom); i++) { 3940f79cbc77SKalle Valo if (hwsim_world_regdom_custom[i] != param->regd) 3941f79cbc77SKalle Valo continue; 3942f79cbc77SKalle Valo 3943f79cbc77SKalle Valo ret = nla_put_u32(skb, HWSIM_ATTR_REG_CUSTOM_REG, i); 3944f79cbc77SKalle Valo if (ret < 0) 3945f79cbc77SKalle Valo return ret; 3946f79cbc77SKalle Valo break; 3947f79cbc77SKalle Valo } 3948f79cbc77SKalle Valo } 3949f79cbc77SKalle Valo 3950f79cbc77SKalle Valo if (param->reg_strict) { 3951f79cbc77SKalle Valo ret = nla_put_flag(skb, HWSIM_ATTR_REG_STRICT_REG); 3952f79cbc77SKalle Valo if (ret < 0) 3953f79cbc77SKalle Valo return ret; 3954f79cbc77SKalle Valo } 3955f79cbc77SKalle Valo 3956f79cbc77SKalle Valo if (param->p2p_device) { 3957f79cbc77SKalle Valo ret = nla_put_flag(skb, HWSIM_ATTR_SUPPORT_P2P_DEVICE); 3958f79cbc77SKalle Valo if (ret < 0) 3959f79cbc77SKalle Valo return ret; 3960f79cbc77SKalle Valo } 3961f79cbc77SKalle Valo 3962f79cbc77SKalle Valo if (param->use_chanctx) { 3963f79cbc77SKalle Valo ret = nla_put_flag(skb, HWSIM_ATTR_USE_CHANCTX); 3964f79cbc77SKalle Valo if (ret < 0) 3965f79cbc77SKalle Valo return ret; 3966f79cbc77SKalle Valo } 3967f79cbc77SKalle Valo 3968f79cbc77SKalle Valo if (param->hwname) { 3969f79cbc77SKalle Valo ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME, 3970f79cbc77SKalle Valo strlen(param->hwname), param->hwname); 3971f79cbc77SKalle Valo if (ret < 0) 3972f79cbc77SKalle Valo return ret; 3973f79cbc77SKalle Valo } 3974f79cbc77SKalle Valo 3975f79cbc77SKalle Valo return 0; 3976f79cbc77SKalle Valo } 3977f79cbc77SKalle Valo 3978f79cbc77SKalle Valo static void hwsim_mcast_new_radio(int id, struct genl_info *info, 3979f79cbc77SKalle Valo struct hwsim_new_radio_params *param) 3980f79cbc77SKalle Valo { 3981f79cbc77SKalle Valo struct sk_buff *mcast_skb; 3982f79cbc77SKalle Valo void *data; 3983f79cbc77SKalle Valo 3984f79cbc77SKalle Valo mcast_skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 3985f79cbc77SKalle Valo if (!mcast_skb) 3986f79cbc77SKalle Valo return; 3987f79cbc77SKalle Valo 3988f79cbc77SKalle Valo data = genlmsg_put(mcast_skb, 0, 0, &hwsim_genl_family, 0, 3989f79cbc77SKalle Valo HWSIM_CMD_NEW_RADIO); 3990f79cbc77SKalle Valo if (!data) 3991f79cbc77SKalle Valo goto out_err; 3992f79cbc77SKalle Valo 3993f79cbc77SKalle Valo if (append_radio_msg(mcast_skb, id, param) < 0) 3994f79cbc77SKalle Valo goto out_err; 3995f79cbc77SKalle Valo 3996f79cbc77SKalle Valo genlmsg_end(mcast_skb, data); 3997f79cbc77SKalle Valo 3998f79cbc77SKalle Valo hwsim_mcast_config_msg(mcast_skb, info); 3999f79cbc77SKalle Valo return; 4000f79cbc77SKalle Valo 4001f79cbc77SKalle Valo out_err: 4002f79cbc77SKalle Valo nlmsg_free(mcast_skb); 4003f79cbc77SKalle Valo } 4004f79cbc77SKalle Valo 4005f79cbc77SKalle Valo static const struct ieee80211_sband_iftype_data sband_capa_2ghz[] = { 4006f79cbc77SKalle Valo { 4007f79cbc77SKalle Valo .types_mask = BIT(NL80211_IFTYPE_STATION), 4008f79cbc77SKalle Valo .he_cap = { 4009f79cbc77SKalle Valo .has_he = true, 4010f79cbc77SKalle Valo .he_cap_elem = { 4011f79cbc77SKalle Valo .mac_cap_info[0] = 4012f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP0_HTC_HE, 4013f79cbc77SKalle Valo .mac_cap_info[1] = 4014f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | 4015f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 4016f79cbc77SKalle Valo .mac_cap_info[2] = 4017f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_BSR | 4018f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_MU_CASCADING | 4019f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_ACK_EN, 4020f79cbc77SKalle Valo .mac_cap_info[3] = 4021f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 4022f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 4023f79cbc77SKalle Valo .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 4024f79cbc77SKalle Valo .phy_cap_info[1] = 4025f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 4026f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 4027f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 4028f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 4029f79cbc77SKalle Valo .phy_cap_info[2] = 4030f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | 4031f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | 4032f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | 4033f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | 4034f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO, 4035f79cbc77SKalle Valo 4036f79cbc77SKalle Valo /* Leave all the other PHY capability bytes 4037f79cbc77SKalle Valo * unset, as DCM, beam forming, RU and PPE 4038f79cbc77SKalle Valo * threshold information are not supported 4039f79cbc77SKalle Valo */ 4040f79cbc77SKalle Valo }, 4041f79cbc77SKalle Valo .he_mcs_nss_supp = { 4042f79cbc77SKalle Valo .rx_mcs_80 = cpu_to_le16(0xfffa), 4043f79cbc77SKalle Valo .tx_mcs_80 = cpu_to_le16(0xfffa), 4044f79cbc77SKalle Valo .rx_mcs_160 = cpu_to_le16(0xffff), 4045f79cbc77SKalle Valo .tx_mcs_160 = cpu_to_le16(0xffff), 4046f79cbc77SKalle Valo .rx_mcs_80p80 = cpu_to_le16(0xffff), 4047f79cbc77SKalle Valo .tx_mcs_80p80 = cpu_to_le16(0xffff), 4048f79cbc77SKalle Valo }, 4049f79cbc77SKalle Valo }, 4050f79cbc77SKalle Valo .eht_cap = { 4051f79cbc77SKalle Valo .has_eht = true, 4052f79cbc77SKalle Valo .eht_cap_elem = { 4053f79cbc77SKalle Valo .mac_cap_info[0] = 4054f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | 4055f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_OM_CONTROL | 4056f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1, 4057f79cbc77SKalle Valo .phy_cap_info[0] = 4058f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | 4059f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | 4060f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | 4061f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER | 4062f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE, 4063f79cbc77SKalle Valo .phy_cap_info[3] = 4064f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | 4065f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | 4066f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | 4067f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | 4068f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | 4069f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | 4070f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK, 4071f79cbc77SKalle Valo .phy_cap_info[4] = 4072f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | 4073f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PSR_SR_SUPP | 4074f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | 4075f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI | 4076f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK, 4077f79cbc77SKalle Valo .phy_cap_info[5] = 4078f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | 4079f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP | 4080f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP | 4081f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT | 4082f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK | 4083f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK, 4084f79cbc77SKalle Valo .phy_cap_info[6] = 4085f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK | 4086f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK, 4087f79cbc77SKalle Valo .phy_cap_info[7] = 4088f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_20MHZ_STA_RX_NDP_WIDER_BW, 4089f79cbc77SKalle Valo }, 4090f79cbc77SKalle Valo 4091f79cbc77SKalle Valo /* For all MCS and bandwidth, set 8 NSS for both Tx and 4092f79cbc77SKalle Valo * Rx 4093f79cbc77SKalle Valo */ 4094f79cbc77SKalle Valo .eht_mcs_nss_supp = { 4095f79cbc77SKalle Valo /* 4096f79cbc77SKalle Valo * Since B0, B1, B2 and B3 are not set in 4097f79cbc77SKalle Valo * the supported channel width set field in the 4098f79cbc77SKalle Valo * HE PHY capabilities information field the 4099f79cbc77SKalle Valo * device is a 20MHz only device on 2.4GHz band. 4100f79cbc77SKalle Valo */ 4101f79cbc77SKalle Valo .only_20mhz = { 4102f79cbc77SKalle Valo .rx_tx_mcs7_max_nss = 0x88, 4103f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 4104f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 4105f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 4106f79cbc77SKalle Valo }, 4107f79cbc77SKalle Valo }, 4108f79cbc77SKalle Valo /* PPE threshold information is not supported */ 4109f79cbc77SKalle Valo }, 4110f79cbc77SKalle Valo }, 4111f79cbc77SKalle Valo { 4112f79cbc77SKalle Valo .types_mask = BIT(NL80211_IFTYPE_AP), 4113f79cbc77SKalle Valo .he_cap = { 4114f79cbc77SKalle Valo .has_he = true, 4115f79cbc77SKalle Valo .he_cap_elem = { 4116f79cbc77SKalle Valo .mac_cap_info[0] = 4117f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP0_HTC_HE, 4118f79cbc77SKalle Valo .mac_cap_info[1] = 4119f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | 4120f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 4121f79cbc77SKalle Valo .mac_cap_info[2] = 4122f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_BSR | 4123f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_MU_CASCADING | 4124f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_ACK_EN, 4125f79cbc77SKalle Valo .mac_cap_info[3] = 4126f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 4127f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 4128f79cbc77SKalle Valo .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 4129f79cbc77SKalle Valo .phy_cap_info[1] = 4130f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 4131f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 4132f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 4133f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 4134f79cbc77SKalle Valo .phy_cap_info[2] = 4135f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | 4136f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | 4137f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | 4138f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | 4139f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO, 4140f79cbc77SKalle Valo 4141f79cbc77SKalle Valo /* Leave all the other PHY capability bytes 4142f79cbc77SKalle Valo * unset, as DCM, beam forming, RU and PPE 4143f79cbc77SKalle Valo * threshold information are not supported 4144f79cbc77SKalle Valo */ 4145f79cbc77SKalle Valo }, 4146f79cbc77SKalle Valo .he_mcs_nss_supp = { 4147f79cbc77SKalle Valo .rx_mcs_80 = cpu_to_le16(0xfffa), 4148f79cbc77SKalle Valo .tx_mcs_80 = cpu_to_le16(0xfffa), 4149f79cbc77SKalle Valo .rx_mcs_160 = cpu_to_le16(0xffff), 4150f79cbc77SKalle Valo .tx_mcs_160 = cpu_to_le16(0xffff), 4151f79cbc77SKalle Valo .rx_mcs_80p80 = cpu_to_le16(0xffff), 4152f79cbc77SKalle Valo .tx_mcs_80p80 = cpu_to_le16(0xffff), 4153f79cbc77SKalle Valo }, 4154f79cbc77SKalle Valo }, 4155f79cbc77SKalle Valo .eht_cap = { 4156f79cbc77SKalle Valo .has_eht = true, 4157f79cbc77SKalle Valo .eht_cap_elem = { 4158f79cbc77SKalle Valo .mac_cap_info[0] = 4159f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | 4160f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_OM_CONTROL | 4161f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1, 4162f79cbc77SKalle Valo .phy_cap_info[0] = 4163f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | 4164f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | 4165f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | 4166f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER | 4167f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE, 4168f79cbc77SKalle Valo .phy_cap_info[3] = 4169f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | 4170f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | 4171f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | 4172f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | 4173f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | 4174f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | 4175f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK, 4176f79cbc77SKalle Valo .phy_cap_info[4] = 4177f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | 4178f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PSR_SR_SUPP | 4179f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | 4180f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI | 4181f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK, 4182f79cbc77SKalle Valo .phy_cap_info[5] = 4183f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | 4184f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP | 4185f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP | 4186f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT | 4187f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK | 4188f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK, 4189f79cbc77SKalle Valo .phy_cap_info[6] = 4190f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK | 4191f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK, 4192f79cbc77SKalle Valo .phy_cap_info[7] = 4193f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_20MHZ_STA_RX_NDP_WIDER_BW, 4194f79cbc77SKalle Valo }, 4195f79cbc77SKalle Valo 4196f79cbc77SKalle Valo /* For all MCS and bandwidth, set 8 NSS for both Tx and 4197f79cbc77SKalle Valo * Rx 4198f79cbc77SKalle Valo */ 4199f79cbc77SKalle Valo .eht_mcs_nss_supp = { 4200f79cbc77SKalle Valo /* 4201f79cbc77SKalle Valo * Since B0, B1, B2 and B3 are not set in 4202f79cbc77SKalle Valo * the supported channel width set field in the 4203f79cbc77SKalle Valo * HE PHY capabilities information field the 4204f79cbc77SKalle Valo * device is a 20MHz only device on 2.4GHz band. 4205f79cbc77SKalle Valo */ 4206f79cbc77SKalle Valo .only_20mhz = { 4207f79cbc77SKalle Valo .rx_tx_mcs7_max_nss = 0x88, 4208f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 4209f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 4210f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 4211f79cbc77SKalle Valo }, 4212f79cbc77SKalle Valo }, 4213f79cbc77SKalle Valo /* PPE threshold information is not supported */ 4214f79cbc77SKalle Valo }, 4215f79cbc77SKalle Valo }, 4216f79cbc77SKalle Valo #ifdef CONFIG_MAC80211_MESH 4217f79cbc77SKalle Valo { 4218f79cbc77SKalle Valo .types_mask = BIT(NL80211_IFTYPE_MESH_POINT), 4219f79cbc77SKalle Valo .he_cap = { 4220f79cbc77SKalle Valo .has_he = true, 4221f79cbc77SKalle Valo .he_cap_elem = { 4222f79cbc77SKalle Valo .mac_cap_info[0] = 4223f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP0_HTC_HE, 4224f79cbc77SKalle Valo .mac_cap_info[1] = 4225f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 4226f79cbc77SKalle Valo .mac_cap_info[2] = 4227f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_ACK_EN, 4228f79cbc77SKalle Valo .mac_cap_info[3] = 4229f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 4230f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 4231f79cbc77SKalle Valo .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 4232f79cbc77SKalle Valo .phy_cap_info[1] = 4233f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 4234f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 4235f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 4236f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 4237f79cbc77SKalle Valo .phy_cap_info[2] = 0, 4238f79cbc77SKalle Valo 4239f79cbc77SKalle Valo /* Leave all the other PHY capability bytes 4240f79cbc77SKalle Valo * unset, as DCM, beam forming, RU and PPE 4241f79cbc77SKalle Valo * threshold information are not supported 4242f79cbc77SKalle Valo */ 4243f79cbc77SKalle Valo }, 4244f79cbc77SKalle Valo .he_mcs_nss_supp = { 4245f79cbc77SKalle Valo .rx_mcs_80 = cpu_to_le16(0xfffa), 4246f79cbc77SKalle Valo .tx_mcs_80 = cpu_to_le16(0xfffa), 4247f79cbc77SKalle Valo .rx_mcs_160 = cpu_to_le16(0xffff), 4248f79cbc77SKalle Valo .tx_mcs_160 = cpu_to_le16(0xffff), 4249f79cbc77SKalle Valo .rx_mcs_80p80 = cpu_to_le16(0xffff), 4250f79cbc77SKalle Valo .tx_mcs_80p80 = cpu_to_le16(0xffff), 4251f79cbc77SKalle Valo }, 4252f79cbc77SKalle Valo }, 4253f79cbc77SKalle Valo }, 4254f79cbc77SKalle Valo #endif 4255f79cbc77SKalle Valo }; 4256f79cbc77SKalle Valo 4257f79cbc77SKalle Valo static const struct ieee80211_sband_iftype_data sband_capa_5ghz[] = { 4258f79cbc77SKalle Valo { 4259f79cbc77SKalle Valo /* TODO: should we support other types, e.g., P2P? */ 4260f79cbc77SKalle Valo .types_mask = BIT(NL80211_IFTYPE_STATION), 4261f79cbc77SKalle Valo .he_cap = { 4262f79cbc77SKalle Valo .has_he = true, 4263f79cbc77SKalle Valo .he_cap_elem = { 4264f79cbc77SKalle Valo .mac_cap_info[0] = 4265f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP0_HTC_HE, 4266f79cbc77SKalle Valo .mac_cap_info[1] = 4267f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | 4268f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 4269f79cbc77SKalle Valo .mac_cap_info[2] = 4270f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_BSR | 4271f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_MU_CASCADING | 4272f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_ACK_EN, 4273f79cbc77SKalle Valo .mac_cap_info[3] = 4274f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 4275f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 4276f79cbc77SKalle Valo .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 4277f79cbc77SKalle Valo .phy_cap_info[0] = 4278f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | 4279f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | 4280f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G, 4281f79cbc77SKalle Valo .phy_cap_info[1] = 4282f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 4283f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 4284f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 4285f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 4286f79cbc77SKalle Valo .phy_cap_info[2] = 4287f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | 4288f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | 4289f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | 4290f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | 4291f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO, 4292f79cbc77SKalle Valo 4293f79cbc77SKalle Valo /* Leave all the other PHY capability bytes 4294f79cbc77SKalle Valo * unset, as DCM, beam forming, RU and PPE 4295f79cbc77SKalle Valo * threshold information are not supported 4296f79cbc77SKalle Valo */ 4297f79cbc77SKalle Valo }, 4298f79cbc77SKalle Valo .he_mcs_nss_supp = { 4299f79cbc77SKalle Valo .rx_mcs_80 = cpu_to_le16(0xfffa), 4300f79cbc77SKalle Valo .tx_mcs_80 = cpu_to_le16(0xfffa), 4301f79cbc77SKalle Valo .rx_mcs_160 = cpu_to_le16(0xfffa), 4302f79cbc77SKalle Valo .tx_mcs_160 = cpu_to_le16(0xfffa), 4303f79cbc77SKalle Valo .rx_mcs_80p80 = cpu_to_le16(0xfffa), 4304f79cbc77SKalle Valo .tx_mcs_80p80 = cpu_to_le16(0xfffa), 4305f79cbc77SKalle Valo }, 4306f79cbc77SKalle Valo }, 4307f79cbc77SKalle Valo .eht_cap = { 4308f79cbc77SKalle Valo .has_eht = true, 4309f79cbc77SKalle Valo .eht_cap_elem = { 4310f79cbc77SKalle Valo .mac_cap_info[0] = 4311f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | 4312f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_OM_CONTROL | 4313f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1, 4314f79cbc77SKalle Valo .phy_cap_info[0] = 4315f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | 4316f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | 4317f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | 4318f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER | 4319f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE | 4320f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK, 4321f79cbc77SKalle Valo .phy_cap_info[1] = 4322f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK | 4323f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK, 4324f79cbc77SKalle Valo .phy_cap_info[2] = 4325f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_80MHZ_MASK | 4326f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK, 4327f79cbc77SKalle Valo .phy_cap_info[3] = 4328f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | 4329f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | 4330f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | 4331f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | 4332f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | 4333f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | 4334f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK, 4335f79cbc77SKalle Valo .phy_cap_info[4] = 4336f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | 4337f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PSR_SR_SUPP | 4338f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | 4339f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI | 4340f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK, 4341f79cbc77SKalle Valo .phy_cap_info[5] = 4342f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | 4343f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP | 4344f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP | 4345f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT | 4346f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK | 4347f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK, 4348f79cbc77SKalle Valo .phy_cap_info[6] = 4349f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK | 4350f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK, 4351f79cbc77SKalle Valo .phy_cap_info[7] = 4352f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_20MHZ_STA_RX_NDP_WIDER_BW | 4353f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ | 4354f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ | 4355f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ | 4356f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ, 4357f79cbc77SKalle Valo }, 4358f79cbc77SKalle Valo 4359f79cbc77SKalle Valo /* For all MCS and bandwidth, set 8 NSS for both Tx and 4360f79cbc77SKalle Valo * Rx 4361f79cbc77SKalle Valo */ 4362f79cbc77SKalle Valo .eht_mcs_nss_supp = { 4363f79cbc77SKalle Valo /* 4364f79cbc77SKalle Valo * As B1 and B2 are set in the supported 4365f79cbc77SKalle Valo * channel width set field in the HE PHY 4366f79cbc77SKalle Valo * capabilities information field include all 4367f79cbc77SKalle Valo * the following MCS/NSS. 4368f79cbc77SKalle Valo */ 4369f79cbc77SKalle Valo .bw._80 = { 4370f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 4371f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 4372f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 4373f79cbc77SKalle Valo }, 4374f79cbc77SKalle Valo .bw._160 = { 4375f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 4376f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 4377f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 4378f79cbc77SKalle Valo }, 4379f79cbc77SKalle Valo }, 4380f79cbc77SKalle Valo /* PPE threshold information is not supported */ 4381f79cbc77SKalle Valo }, 4382f79cbc77SKalle Valo }, 4383f79cbc77SKalle Valo { 4384f79cbc77SKalle Valo .types_mask = BIT(NL80211_IFTYPE_AP), 4385f79cbc77SKalle Valo .he_cap = { 4386f79cbc77SKalle Valo .has_he = true, 4387f79cbc77SKalle Valo .he_cap_elem = { 4388f79cbc77SKalle Valo .mac_cap_info[0] = 4389f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP0_HTC_HE, 4390f79cbc77SKalle Valo .mac_cap_info[1] = 4391f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | 4392f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 4393f79cbc77SKalle Valo .mac_cap_info[2] = 4394f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_BSR | 4395f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_MU_CASCADING | 4396f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_ACK_EN, 4397f79cbc77SKalle Valo .mac_cap_info[3] = 4398f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 4399f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 4400f79cbc77SKalle Valo .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 4401f79cbc77SKalle Valo .phy_cap_info[0] = 4402f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | 4403f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | 4404f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G, 4405f79cbc77SKalle Valo .phy_cap_info[1] = 4406f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 4407f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 4408f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 4409f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 4410f79cbc77SKalle Valo .phy_cap_info[2] = 4411f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | 4412f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | 4413f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | 4414f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | 4415f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO, 4416f79cbc77SKalle Valo 4417f79cbc77SKalle Valo /* Leave all the other PHY capability bytes 4418f79cbc77SKalle Valo * unset, as DCM, beam forming, RU and PPE 4419f79cbc77SKalle Valo * threshold information are not supported 4420f79cbc77SKalle Valo */ 4421f79cbc77SKalle Valo }, 4422f79cbc77SKalle Valo .he_mcs_nss_supp = { 4423f79cbc77SKalle Valo .rx_mcs_80 = cpu_to_le16(0xfffa), 4424f79cbc77SKalle Valo .tx_mcs_80 = cpu_to_le16(0xfffa), 4425f79cbc77SKalle Valo .rx_mcs_160 = cpu_to_le16(0xfffa), 4426f79cbc77SKalle Valo .tx_mcs_160 = cpu_to_le16(0xfffa), 4427f79cbc77SKalle Valo .rx_mcs_80p80 = cpu_to_le16(0xfffa), 4428f79cbc77SKalle Valo .tx_mcs_80p80 = cpu_to_le16(0xfffa), 4429f79cbc77SKalle Valo }, 4430f79cbc77SKalle Valo }, 4431f79cbc77SKalle Valo .eht_cap = { 4432f79cbc77SKalle Valo .has_eht = true, 4433f79cbc77SKalle Valo .eht_cap_elem = { 4434f79cbc77SKalle Valo .mac_cap_info[0] = 4435f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | 4436f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_OM_CONTROL | 4437f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1, 4438f79cbc77SKalle Valo .phy_cap_info[0] = 4439f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | 4440f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | 4441f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | 4442f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER | 4443f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE | 4444f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK, 4445f79cbc77SKalle Valo .phy_cap_info[1] = 4446f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK | 4447f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK, 4448f79cbc77SKalle Valo .phy_cap_info[2] = 4449f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_80MHZ_MASK | 4450f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK, 4451f79cbc77SKalle Valo .phy_cap_info[3] = 4452f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | 4453f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | 4454f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | 4455f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | 4456f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | 4457f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | 4458f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK, 4459f79cbc77SKalle Valo .phy_cap_info[4] = 4460f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | 4461f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PSR_SR_SUPP | 4462f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | 4463f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI | 4464f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK, 4465f79cbc77SKalle Valo .phy_cap_info[5] = 4466f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | 4467f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP | 4468f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP | 4469f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT | 4470f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK | 4471f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK, 4472f79cbc77SKalle Valo .phy_cap_info[6] = 4473f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK | 4474f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK, 4475f79cbc77SKalle Valo .phy_cap_info[7] = 4476f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_20MHZ_STA_RX_NDP_WIDER_BW | 4477f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ | 4478f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ | 4479f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ | 4480f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ, 4481f79cbc77SKalle Valo }, 4482f79cbc77SKalle Valo 4483f79cbc77SKalle Valo /* For all MCS and bandwidth, set 8 NSS for both Tx and 4484f79cbc77SKalle Valo * Rx 4485f79cbc77SKalle Valo */ 4486f79cbc77SKalle Valo .eht_mcs_nss_supp = { 4487f79cbc77SKalle Valo /* 4488f79cbc77SKalle Valo * As B1 and B2 are set in the supported 4489f79cbc77SKalle Valo * channel width set field in the HE PHY 4490f79cbc77SKalle Valo * capabilities information field include all 4491f79cbc77SKalle Valo * the following MCS/NSS. 4492f79cbc77SKalle Valo */ 4493f79cbc77SKalle Valo .bw._80 = { 4494f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 4495f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 4496f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 4497f79cbc77SKalle Valo }, 4498f79cbc77SKalle Valo .bw._160 = { 4499f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 4500f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 4501f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 4502f79cbc77SKalle Valo }, 4503f79cbc77SKalle Valo }, 4504f79cbc77SKalle Valo /* PPE threshold information is not supported */ 4505f79cbc77SKalle Valo }, 4506f79cbc77SKalle Valo }, 4507f79cbc77SKalle Valo #ifdef CONFIG_MAC80211_MESH 4508f79cbc77SKalle Valo { 4509f79cbc77SKalle Valo /* TODO: should we support other types, e.g., IBSS?*/ 4510f79cbc77SKalle Valo .types_mask = BIT(NL80211_IFTYPE_MESH_POINT), 4511f79cbc77SKalle Valo .he_cap = { 4512f79cbc77SKalle Valo .has_he = true, 4513f79cbc77SKalle Valo .he_cap_elem = { 4514f79cbc77SKalle Valo .mac_cap_info[0] = 4515f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP0_HTC_HE, 4516f79cbc77SKalle Valo .mac_cap_info[1] = 4517f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 4518f79cbc77SKalle Valo .mac_cap_info[2] = 4519f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_ACK_EN, 4520f79cbc77SKalle Valo .mac_cap_info[3] = 4521f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 4522f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 4523f79cbc77SKalle Valo .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 4524f79cbc77SKalle Valo .phy_cap_info[0] = 4525f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | 4526f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | 4527f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G, 4528f79cbc77SKalle Valo .phy_cap_info[1] = 4529f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 4530f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 4531f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 4532f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 4533f79cbc77SKalle Valo .phy_cap_info[2] = 0, 4534f79cbc77SKalle Valo 4535f79cbc77SKalle Valo /* Leave all the other PHY capability bytes 4536f79cbc77SKalle Valo * unset, as DCM, beam forming, RU and PPE 4537f79cbc77SKalle Valo * threshold information are not supported 4538f79cbc77SKalle Valo */ 4539f79cbc77SKalle Valo }, 4540f79cbc77SKalle Valo .he_mcs_nss_supp = { 4541f79cbc77SKalle Valo .rx_mcs_80 = cpu_to_le16(0xfffa), 4542f79cbc77SKalle Valo .tx_mcs_80 = cpu_to_le16(0xfffa), 4543f79cbc77SKalle Valo .rx_mcs_160 = cpu_to_le16(0xfffa), 4544f79cbc77SKalle Valo .tx_mcs_160 = cpu_to_le16(0xfffa), 4545f79cbc77SKalle Valo .rx_mcs_80p80 = cpu_to_le16(0xfffa), 4546f79cbc77SKalle Valo .tx_mcs_80p80 = cpu_to_le16(0xfffa), 4547f79cbc77SKalle Valo }, 4548f79cbc77SKalle Valo }, 4549f79cbc77SKalle Valo }, 4550f79cbc77SKalle Valo #endif 4551f79cbc77SKalle Valo }; 4552f79cbc77SKalle Valo 4553f79cbc77SKalle Valo static const struct ieee80211_sband_iftype_data sband_capa_6ghz[] = { 4554f79cbc77SKalle Valo { 4555f79cbc77SKalle Valo /* TODO: should we support other types, e.g., P2P? */ 4556f79cbc77SKalle Valo .types_mask = BIT(NL80211_IFTYPE_STATION), 4557f79cbc77SKalle Valo .he_6ghz_capa = { 4558f79cbc77SKalle Valo .capa = cpu_to_le16(IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START | 4559f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP | 4560f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN | 4561f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_SM_PS | 4562f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_RD_RESPONDER | 4563f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS | 4564f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS), 4565f79cbc77SKalle Valo }, 4566f79cbc77SKalle Valo .he_cap = { 4567f79cbc77SKalle Valo .has_he = true, 4568f79cbc77SKalle Valo .he_cap_elem = { 4569f79cbc77SKalle Valo .mac_cap_info[0] = 4570f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP0_HTC_HE, 4571f79cbc77SKalle Valo .mac_cap_info[1] = 4572f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | 4573f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 4574f79cbc77SKalle Valo .mac_cap_info[2] = 4575f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_BSR | 4576f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_MU_CASCADING | 4577f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_ACK_EN, 4578f79cbc77SKalle Valo .mac_cap_info[3] = 4579f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 4580f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 4581f79cbc77SKalle Valo .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 4582f79cbc77SKalle Valo .phy_cap_info[0] = 4583f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | 4584f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | 4585f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G, 4586f79cbc77SKalle Valo .phy_cap_info[1] = 4587f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 4588f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 4589f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 4590f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 4591f79cbc77SKalle Valo .phy_cap_info[2] = 4592f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | 4593f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | 4594f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | 4595f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | 4596f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO, 4597f79cbc77SKalle Valo 4598f79cbc77SKalle Valo /* Leave all the other PHY capability bytes 4599f79cbc77SKalle Valo * unset, as DCM, beam forming, RU and PPE 4600f79cbc77SKalle Valo * threshold information are not supported 4601f79cbc77SKalle Valo */ 4602f79cbc77SKalle Valo }, 4603f79cbc77SKalle Valo .he_mcs_nss_supp = { 4604f79cbc77SKalle Valo .rx_mcs_80 = cpu_to_le16(0xfffa), 4605f79cbc77SKalle Valo .tx_mcs_80 = cpu_to_le16(0xfffa), 4606f79cbc77SKalle Valo .rx_mcs_160 = cpu_to_le16(0xfffa), 4607f79cbc77SKalle Valo .tx_mcs_160 = cpu_to_le16(0xfffa), 4608f79cbc77SKalle Valo .rx_mcs_80p80 = cpu_to_le16(0xfffa), 4609f79cbc77SKalle Valo .tx_mcs_80p80 = cpu_to_le16(0xfffa), 4610f79cbc77SKalle Valo }, 4611f79cbc77SKalle Valo }, 4612f79cbc77SKalle Valo .eht_cap = { 4613f79cbc77SKalle Valo .has_eht = true, 4614f79cbc77SKalle Valo .eht_cap_elem = { 4615f79cbc77SKalle Valo .mac_cap_info[0] = 4616f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | 4617f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_OM_CONTROL | 4618f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1, 4619f79cbc77SKalle Valo .phy_cap_info[0] = 4620f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ | 4621f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | 4622f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | 4623f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | 4624f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER | 4625f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE | 4626f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK, 4627f79cbc77SKalle Valo .phy_cap_info[1] = 4628f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK | 4629f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK | 4630f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK, 4631f79cbc77SKalle Valo .phy_cap_info[2] = 4632f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_80MHZ_MASK | 4633f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK | 4634f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_320MHZ_MASK, 4635f79cbc77SKalle Valo .phy_cap_info[3] = 4636f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | 4637f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | 4638f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | 4639f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | 4640f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | 4641f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | 4642f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK, 4643f79cbc77SKalle Valo .phy_cap_info[4] = 4644f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | 4645f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PSR_SR_SUPP | 4646f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | 4647f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI | 4648f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK, 4649f79cbc77SKalle Valo .phy_cap_info[5] = 4650f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | 4651f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP | 4652f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP | 4653f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT | 4654f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK | 4655f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK, 4656f79cbc77SKalle Valo .phy_cap_info[6] = 4657f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK | 4658f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK | 4659f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_EHT_DUP_6GHZ_SUPP, 4660f79cbc77SKalle Valo .phy_cap_info[7] = 4661f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_20MHZ_STA_RX_NDP_WIDER_BW | 4662f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ | 4663f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ | 4664f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_320MHZ | 4665f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ | 4666f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ | 4667f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_320MHZ, 4668f79cbc77SKalle Valo }, 4669f79cbc77SKalle Valo 4670f79cbc77SKalle Valo /* For all MCS and bandwidth, set 8 NSS for both Tx and 4671f79cbc77SKalle Valo * Rx 4672f79cbc77SKalle Valo */ 4673f79cbc77SKalle Valo .eht_mcs_nss_supp = { 4674f79cbc77SKalle Valo /* 4675f79cbc77SKalle Valo * As B1 and B2 are set in the supported 4676f79cbc77SKalle Valo * channel width set field in the HE PHY 4677f79cbc77SKalle Valo * capabilities information field and 320MHz in 4678f79cbc77SKalle Valo * 6GHz is supported include all the following 4679f79cbc77SKalle Valo * MCS/NSS. 4680f79cbc77SKalle Valo */ 4681f79cbc77SKalle Valo .bw._80 = { 4682f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 4683f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 4684f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 4685f79cbc77SKalle Valo }, 4686f79cbc77SKalle Valo .bw._160 = { 4687f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 4688f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 4689f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 4690f79cbc77SKalle Valo }, 4691f79cbc77SKalle Valo .bw._320 = { 4692f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 4693f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 4694f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 4695f79cbc77SKalle Valo }, 4696f79cbc77SKalle Valo }, 4697f79cbc77SKalle Valo /* PPE threshold information is not supported */ 4698f79cbc77SKalle Valo }, 4699f79cbc77SKalle Valo }, 4700f79cbc77SKalle Valo { 4701f79cbc77SKalle Valo .types_mask = BIT(NL80211_IFTYPE_AP), 4702f79cbc77SKalle Valo .he_6ghz_capa = { 4703f79cbc77SKalle Valo .capa = cpu_to_le16(IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START | 4704f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP | 4705f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN | 4706f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_SM_PS | 4707f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_RD_RESPONDER | 4708f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS | 4709f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS), 4710f79cbc77SKalle Valo }, 4711f79cbc77SKalle Valo .he_cap = { 4712f79cbc77SKalle Valo .has_he = true, 4713f79cbc77SKalle Valo .he_cap_elem = { 4714f79cbc77SKalle Valo .mac_cap_info[0] = 4715f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP0_HTC_HE, 4716f79cbc77SKalle Valo .mac_cap_info[1] = 4717f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | 4718f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 4719f79cbc77SKalle Valo .mac_cap_info[2] = 4720f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_BSR | 4721f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_MU_CASCADING | 4722f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_ACK_EN, 4723f79cbc77SKalle Valo .mac_cap_info[3] = 4724f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 4725f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 4726f79cbc77SKalle Valo .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 4727f79cbc77SKalle Valo .phy_cap_info[0] = 4728f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | 4729f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | 4730f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G, 4731f79cbc77SKalle Valo .phy_cap_info[1] = 4732f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 4733f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 4734f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 4735f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 4736f79cbc77SKalle Valo .phy_cap_info[2] = 4737f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | 4738f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | 4739f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | 4740f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | 4741f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO, 4742f79cbc77SKalle Valo 4743f79cbc77SKalle Valo /* Leave all the other PHY capability bytes 4744f79cbc77SKalle Valo * unset, as DCM, beam forming, RU and PPE 4745f79cbc77SKalle Valo * threshold information are not supported 4746f79cbc77SKalle Valo */ 4747f79cbc77SKalle Valo }, 4748f79cbc77SKalle Valo .he_mcs_nss_supp = { 4749f79cbc77SKalle Valo .rx_mcs_80 = cpu_to_le16(0xfffa), 4750f79cbc77SKalle Valo .tx_mcs_80 = cpu_to_le16(0xfffa), 4751f79cbc77SKalle Valo .rx_mcs_160 = cpu_to_le16(0xfffa), 4752f79cbc77SKalle Valo .tx_mcs_160 = cpu_to_le16(0xfffa), 4753f79cbc77SKalle Valo .rx_mcs_80p80 = cpu_to_le16(0xfffa), 4754f79cbc77SKalle Valo .tx_mcs_80p80 = cpu_to_le16(0xfffa), 4755f79cbc77SKalle Valo }, 4756f79cbc77SKalle Valo }, 4757f79cbc77SKalle Valo .eht_cap = { 4758f79cbc77SKalle Valo .has_eht = true, 4759f79cbc77SKalle Valo .eht_cap_elem = { 4760f79cbc77SKalle Valo .mac_cap_info[0] = 4761f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | 4762f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_OM_CONTROL | 4763f79cbc77SKalle Valo IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1, 4764f79cbc77SKalle Valo .phy_cap_info[0] = 4765f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ | 4766f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | 4767f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | 4768f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | 4769f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER | 4770f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE | 4771f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK, 4772f79cbc77SKalle Valo .phy_cap_info[1] = 4773f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK | 4774f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK | 4775f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK, 4776f79cbc77SKalle Valo .phy_cap_info[2] = 4777f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_80MHZ_MASK | 4778f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK | 4779f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_320MHZ_MASK, 4780f79cbc77SKalle Valo .phy_cap_info[3] = 4781f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | 4782f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | 4783f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | 4784f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | 4785f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | 4786f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | 4787f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK, 4788f79cbc77SKalle Valo .phy_cap_info[4] = 4789f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | 4790f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_PSR_SR_SUPP | 4791f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | 4792f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI | 4793f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK, 4794f79cbc77SKalle Valo .phy_cap_info[5] = 4795f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | 4796f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP | 4797f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP | 4798f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT | 4799f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK | 4800f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK, 4801f79cbc77SKalle Valo .phy_cap_info[6] = 4802f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK | 4803f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK | 4804f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP6_EHT_DUP_6GHZ_SUPP, 4805f79cbc77SKalle Valo .phy_cap_info[7] = 4806f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_20MHZ_STA_RX_NDP_WIDER_BW | 4807f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ | 4808f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ | 4809f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_320MHZ | 4810f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ | 4811f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ | 4812f79cbc77SKalle Valo IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_320MHZ, 4813f79cbc77SKalle Valo }, 4814f79cbc77SKalle Valo 4815f79cbc77SKalle Valo /* For all MCS and bandwidth, set 8 NSS for both Tx and 4816f79cbc77SKalle Valo * Rx 4817f79cbc77SKalle Valo */ 4818f79cbc77SKalle Valo .eht_mcs_nss_supp = { 4819f79cbc77SKalle Valo /* 4820f79cbc77SKalle Valo * As B1 and B2 are set in the supported 4821f79cbc77SKalle Valo * channel width set field in the HE PHY 4822f79cbc77SKalle Valo * capabilities information field and 320MHz in 4823f79cbc77SKalle Valo * 6GHz is supported include all the following 4824f79cbc77SKalle Valo * MCS/NSS. 4825f79cbc77SKalle Valo */ 4826f79cbc77SKalle Valo .bw._80 = { 4827f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 4828f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 4829f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 4830f79cbc77SKalle Valo }, 4831f79cbc77SKalle Valo .bw._160 = { 4832f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 4833f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 4834f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 4835f79cbc77SKalle Valo }, 4836f79cbc77SKalle Valo .bw._320 = { 4837f79cbc77SKalle Valo .rx_tx_mcs9_max_nss = 0x88, 4838f79cbc77SKalle Valo .rx_tx_mcs11_max_nss = 0x88, 4839f79cbc77SKalle Valo .rx_tx_mcs13_max_nss = 0x88, 4840f79cbc77SKalle Valo }, 4841f79cbc77SKalle Valo }, 4842f79cbc77SKalle Valo /* PPE threshold information is not supported */ 4843f79cbc77SKalle Valo }, 4844f79cbc77SKalle Valo }, 4845f79cbc77SKalle Valo #ifdef CONFIG_MAC80211_MESH 4846f79cbc77SKalle Valo { 4847f79cbc77SKalle Valo /* TODO: should we support other types, e.g., IBSS?*/ 4848f79cbc77SKalle Valo .types_mask = BIT(NL80211_IFTYPE_MESH_POINT), 4849f79cbc77SKalle Valo .he_6ghz_capa = { 4850f79cbc77SKalle Valo .capa = cpu_to_le16(IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START | 4851f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP | 4852f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN | 4853f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_SM_PS | 4854f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_RD_RESPONDER | 4855f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS | 4856f79cbc77SKalle Valo IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS), 4857f79cbc77SKalle Valo }, 4858f79cbc77SKalle Valo .he_cap = { 4859f79cbc77SKalle Valo .has_he = true, 4860f79cbc77SKalle Valo .he_cap_elem = { 4861f79cbc77SKalle Valo .mac_cap_info[0] = 4862f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP0_HTC_HE, 4863f79cbc77SKalle Valo .mac_cap_info[1] = 4864f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 4865f79cbc77SKalle Valo .mac_cap_info[2] = 4866f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP2_ACK_EN, 4867f79cbc77SKalle Valo .mac_cap_info[3] = 4868f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 4869f79cbc77SKalle Valo IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 4870f79cbc77SKalle Valo .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 4871f79cbc77SKalle Valo .phy_cap_info[0] = 4872f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | 4873f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | 4874f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G, 4875f79cbc77SKalle Valo .phy_cap_info[1] = 4876f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 4877f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 4878f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 4879f79cbc77SKalle Valo IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 4880f79cbc77SKalle Valo .phy_cap_info[2] = 0, 4881f79cbc77SKalle Valo 4882f79cbc77SKalle Valo /* Leave all the other PHY capability bytes 4883f79cbc77SKalle Valo * unset, as DCM, beam forming, RU and PPE 4884f79cbc77SKalle Valo * threshold information are not supported 4885f79cbc77SKalle Valo */ 4886f79cbc77SKalle Valo }, 4887f79cbc77SKalle Valo .he_mcs_nss_supp = { 4888f79cbc77SKalle Valo .rx_mcs_80 = cpu_to_le16(0xfffa), 4889f79cbc77SKalle Valo .tx_mcs_80 = cpu_to_le16(0xfffa), 4890f79cbc77SKalle Valo .rx_mcs_160 = cpu_to_le16(0xfffa), 4891f79cbc77SKalle Valo .tx_mcs_160 = cpu_to_le16(0xfffa), 4892f79cbc77SKalle Valo .rx_mcs_80p80 = cpu_to_le16(0xfffa), 4893f79cbc77SKalle Valo .tx_mcs_80p80 = cpu_to_le16(0xfffa), 4894f79cbc77SKalle Valo }, 4895f79cbc77SKalle Valo }, 4896f79cbc77SKalle Valo }, 4897f79cbc77SKalle Valo #endif 4898f79cbc77SKalle Valo }; 4899f79cbc77SKalle Valo 4900f79cbc77SKalle Valo static void mac80211_hwsim_sband_capab(struct ieee80211_supported_band *sband) 4901f79cbc77SKalle Valo { 4902f79cbc77SKalle Valo u16 n_iftype_data; 4903f79cbc77SKalle Valo 4904f79cbc77SKalle Valo if (sband->band == NL80211_BAND_2GHZ) { 4905f79cbc77SKalle Valo n_iftype_data = ARRAY_SIZE(sband_capa_2ghz); 4906f79cbc77SKalle Valo sband->iftype_data = 4907f79cbc77SKalle Valo (struct ieee80211_sband_iftype_data *)sband_capa_2ghz; 4908f79cbc77SKalle Valo } else if (sband->band == NL80211_BAND_5GHZ) { 4909f79cbc77SKalle Valo n_iftype_data = ARRAY_SIZE(sband_capa_5ghz); 4910f79cbc77SKalle Valo sband->iftype_data = 4911f79cbc77SKalle Valo (struct ieee80211_sband_iftype_data *)sband_capa_5ghz; 4912f79cbc77SKalle Valo } else if (sband->band == NL80211_BAND_6GHZ) { 4913f79cbc77SKalle Valo n_iftype_data = ARRAY_SIZE(sband_capa_6ghz); 4914f79cbc77SKalle Valo sband->iftype_data = 4915f79cbc77SKalle Valo (struct ieee80211_sband_iftype_data *)sband_capa_6ghz; 4916f79cbc77SKalle Valo } else { 4917f79cbc77SKalle Valo return; 4918f79cbc77SKalle Valo } 4919f79cbc77SKalle Valo 4920f79cbc77SKalle Valo sband->n_iftype_data = n_iftype_data; 4921f79cbc77SKalle Valo } 4922f79cbc77SKalle Valo 4923f79cbc77SKalle Valo #ifdef CONFIG_MAC80211_MESH 4924f79cbc77SKalle Valo #define HWSIM_MESH_BIT BIT(NL80211_IFTYPE_MESH_POINT) 4925f79cbc77SKalle Valo #else 4926f79cbc77SKalle Valo #define HWSIM_MESH_BIT 0 4927f79cbc77SKalle Valo #endif 4928f79cbc77SKalle Valo 4929f79cbc77SKalle Valo #define HWSIM_DEFAULT_IF_LIMIT \ 4930f79cbc77SKalle Valo (BIT(NL80211_IFTYPE_STATION) | \ 4931f79cbc77SKalle Valo BIT(NL80211_IFTYPE_P2P_CLIENT) | \ 4932f79cbc77SKalle Valo BIT(NL80211_IFTYPE_AP) | \ 4933f79cbc77SKalle Valo BIT(NL80211_IFTYPE_P2P_GO) | \ 4934f79cbc77SKalle Valo HWSIM_MESH_BIT) 4935f79cbc77SKalle Valo 4936f79cbc77SKalle Valo #define HWSIM_IFTYPE_SUPPORT_MASK \ 4937f79cbc77SKalle Valo (BIT(NL80211_IFTYPE_STATION) | \ 4938f79cbc77SKalle Valo BIT(NL80211_IFTYPE_AP) | \ 4939f79cbc77SKalle Valo BIT(NL80211_IFTYPE_P2P_CLIENT) | \ 4940f79cbc77SKalle Valo BIT(NL80211_IFTYPE_P2P_GO) | \ 4941f79cbc77SKalle Valo BIT(NL80211_IFTYPE_ADHOC) | \ 4942f79cbc77SKalle Valo BIT(NL80211_IFTYPE_MESH_POINT) | \ 4943f79cbc77SKalle Valo BIT(NL80211_IFTYPE_OCB)) 4944f79cbc77SKalle Valo 4945f79cbc77SKalle Valo static int mac80211_hwsim_new_radio(struct genl_info *info, 4946f79cbc77SKalle Valo struct hwsim_new_radio_params *param) 4947f79cbc77SKalle Valo { 4948f79cbc77SKalle Valo int err; 4949f79cbc77SKalle Valo u8 addr[ETH_ALEN]; 4950f79cbc77SKalle Valo struct mac80211_hwsim_data *data; 4951f79cbc77SKalle Valo struct ieee80211_hw *hw; 4952f79cbc77SKalle Valo enum nl80211_band band; 4953f79cbc77SKalle Valo const struct ieee80211_ops *ops = &mac80211_hwsim_ops; 4954f79cbc77SKalle Valo struct net *net; 4955f79cbc77SKalle Valo int idx, i; 4956f79cbc77SKalle Valo int n_limits = 0; 4957f79cbc77SKalle Valo 4958f79cbc77SKalle Valo if (WARN_ON(param->channels > 1 && !param->use_chanctx)) 4959f79cbc77SKalle Valo return -EINVAL; 4960f79cbc77SKalle Valo 4961f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 4962f79cbc77SKalle Valo idx = hwsim_radio_idx++; 4963f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 4964f79cbc77SKalle Valo 4965f79cbc77SKalle Valo if (param->mlo) 4966f79cbc77SKalle Valo ops = &mac80211_hwsim_mlo_ops; 4967f79cbc77SKalle Valo else if (param->use_chanctx) 4968f79cbc77SKalle Valo ops = &mac80211_hwsim_mchan_ops; 4969f79cbc77SKalle Valo hw = ieee80211_alloc_hw_nm(sizeof(*data), ops, param->hwname); 4970f79cbc77SKalle Valo if (!hw) { 4971f79cbc77SKalle Valo pr_debug("mac80211_hwsim: ieee80211_alloc_hw failed\n"); 4972f79cbc77SKalle Valo err = -ENOMEM; 4973f79cbc77SKalle Valo goto failed; 4974f79cbc77SKalle Valo } 4975f79cbc77SKalle Valo 4976f79cbc77SKalle Valo /* ieee80211_alloc_hw_nm may have used a default name */ 4977f79cbc77SKalle Valo param->hwname = wiphy_name(hw->wiphy); 4978f79cbc77SKalle Valo 4979f79cbc77SKalle Valo if (info) 4980f79cbc77SKalle Valo net = genl_info_net(info); 4981f79cbc77SKalle Valo else 4982f79cbc77SKalle Valo net = &init_net; 4983f79cbc77SKalle Valo wiphy_net_set(hw->wiphy, net); 4984f79cbc77SKalle Valo 4985f79cbc77SKalle Valo data = hw->priv; 4986f79cbc77SKalle Valo data->hw = hw; 4987f79cbc77SKalle Valo 4988f79cbc77SKalle Valo data->dev = device_create(hwsim_class, NULL, 0, hw, "hwsim%d", idx); 4989f79cbc77SKalle Valo if (IS_ERR(data->dev)) { 4990f79cbc77SKalle Valo printk(KERN_DEBUG 4991f79cbc77SKalle Valo "mac80211_hwsim: device_create failed (%ld)\n", 4992f79cbc77SKalle Valo PTR_ERR(data->dev)); 4993f79cbc77SKalle Valo err = -ENOMEM; 4994f79cbc77SKalle Valo goto failed_drvdata; 4995f79cbc77SKalle Valo } 4996f79cbc77SKalle Valo data->dev->driver = &mac80211_hwsim_driver.driver; 4997f79cbc77SKalle Valo err = device_bind_driver(data->dev); 4998f79cbc77SKalle Valo if (err != 0) { 4999f79cbc77SKalle Valo pr_debug("mac80211_hwsim: device_bind_driver failed (%d)\n", 5000f79cbc77SKalle Valo err); 5001f79cbc77SKalle Valo goto failed_bind; 5002f79cbc77SKalle Valo } 5003f79cbc77SKalle Valo 5004f79cbc77SKalle Valo skb_queue_head_init(&data->pending); 5005f79cbc77SKalle Valo 5006f79cbc77SKalle Valo SET_IEEE80211_DEV(hw, data->dev); 5007f79cbc77SKalle Valo if (!param->perm_addr) { 5008f79cbc77SKalle Valo eth_zero_addr(addr); 5009f79cbc77SKalle Valo addr[0] = 0x02; 5010f79cbc77SKalle Valo addr[3] = idx >> 8; 5011f79cbc77SKalle Valo addr[4] = idx; 5012f79cbc77SKalle Valo memcpy(data->addresses[0].addr, addr, ETH_ALEN); 5013f79cbc77SKalle Valo /* Why need here second address ? */ 5014f79cbc77SKalle Valo memcpy(data->addresses[1].addr, addr, ETH_ALEN); 5015f79cbc77SKalle Valo data->addresses[1].addr[0] |= 0x40; 5016f79cbc77SKalle Valo hw->wiphy->n_addresses = 2; 5017f79cbc77SKalle Valo hw->wiphy->addresses = data->addresses; 5018f79cbc77SKalle Valo /* possible address clash is checked at hash table insertion */ 5019f79cbc77SKalle Valo } else { 5020f79cbc77SKalle Valo memcpy(data->addresses[0].addr, param->perm_addr, ETH_ALEN); 5021f79cbc77SKalle Valo /* compatibility with automatically generated mac addr */ 5022f79cbc77SKalle Valo memcpy(data->addresses[1].addr, param->perm_addr, ETH_ALEN); 5023f79cbc77SKalle Valo hw->wiphy->n_addresses = 2; 5024f79cbc77SKalle Valo hw->wiphy->addresses = data->addresses; 5025f79cbc77SKalle Valo } 5026f79cbc77SKalle Valo 5027f79cbc77SKalle Valo data->channels = param->channels; 5028f79cbc77SKalle Valo data->use_chanctx = param->use_chanctx; 5029f79cbc77SKalle Valo data->idx = idx; 5030f79cbc77SKalle Valo data->destroy_on_close = param->destroy_on_close; 5031f79cbc77SKalle Valo if (info) 5032f79cbc77SKalle Valo data->portid = info->snd_portid; 5033f79cbc77SKalle Valo 5034f79cbc77SKalle Valo /* setup interface limits, only on interface types we support */ 5035f79cbc77SKalle Valo if (param->iftypes & BIT(NL80211_IFTYPE_ADHOC)) { 5036f79cbc77SKalle Valo data->if_limits[n_limits].max = 1; 5037f79cbc77SKalle Valo data->if_limits[n_limits].types = BIT(NL80211_IFTYPE_ADHOC); 5038f79cbc77SKalle Valo n_limits++; 5039f79cbc77SKalle Valo } 5040f79cbc77SKalle Valo 5041f79cbc77SKalle Valo if (param->iftypes & HWSIM_DEFAULT_IF_LIMIT) { 5042f79cbc77SKalle Valo data->if_limits[n_limits].max = 2048; 5043f79cbc77SKalle Valo /* 5044f79cbc77SKalle Valo * For this case, we may only support a subset of 5045f79cbc77SKalle Valo * HWSIM_DEFAULT_IF_LIMIT, therefore we only want to add the 5046f79cbc77SKalle Valo * bits that both param->iftype & HWSIM_DEFAULT_IF_LIMIT have. 5047f79cbc77SKalle Valo */ 5048f79cbc77SKalle Valo data->if_limits[n_limits].types = 5049f79cbc77SKalle Valo HWSIM_DEFAULT_IF_LIMIT & param->iftypes; 5050f79cbc77SKalle Valo n_limits++; 5051f79cbc77SKalle Valo } 5052f79cbc77SKalle Valo 5053f79cbc77SKalle Valo if (param->iftypes & BIT(NL80211_IFTYPE_P2P_DEVICE)) { 5054f79cbc77SKalle Valo data->if_limits[n_limits].max = 1; 5055f79cbc77SKalle Valo data->if_limits[n_limits].types = 5056f79cbc77SKalle Valo BIT(NL80211_IFTYPE_P2P_DEVICE); 5057f79cbc77SKalle Valo n_limits++; 5058f79cbc77SKalle Valo } 5059f79cbc77SKalle Valo 5060f79cbc77SKalle Valo if (data->use_chanctx) { 5061f79cbc77SKalle Valo hw->wiphy->max_scan_ssids = 255; 5062f79cbc77SKalle Valo hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; 5063f79cbc77SKalle Valo hw->wiphy->max_remain_on_channel_duration = 1000; 5064f79cbc77SKalle Valo data->if_combination.radar_detect_widths = 0; 5065f79cbc77SKalle Valo data->if_combination.num_different_channels = data->channels; 5066f79cbc77SKalle Valo } else { 5067f79cbc77SKalle Valo data->if_combination.num_different_channels = 1; 5068f79cbc77SKalle Valo data->if_combination.radar_detect_widths = 5069f79cbc77SKalle Valo BIT(NL80211_CHAN_WIDTH_5) | 5070f79cbc77SKalle Valo BIT(NL80211_CHAN_WIDTH_10) | 5071f79cbc77SKalle Valo BIT(NL80211_CHAN_WIDTH_20_NOHT) | 5072f79cbc77SKalle Valo BIT(NL80211_CHAN_WIDTH_20) | 5073f79cbc77SKalle Valo BIT(NL80211_CHAN_WIDTH_40) | 5074f79cbc77SKalle Valo BIT(NL80211_CHAN_WIDTH_80) | 5075f79cbc77SKalle Valo BIT(NL80211_CHAN_WIDTH_160); 5076f79cbc77SKalle Valo } 5077f79cbc77SKalle Valo 5078f79cbc77SKalle Valo if (!n_limits) { 5079f79cbc77SKalle Valo err = -EINVAL; 5080f79cbc77SKalle Valo goto failed_hw; 5081f79cbc77SKalle Valo } 5082f79cbc77SKalle Valo 5083f79cbc77SKalle Valo data->if_combination.max_interfaces = 0; 5084f79cbc77SKalle Valo for (i = 0; i < n_limits; i++) 5085f79cbc77SKalle Valo data->if_combination.max_interfaces += 5086f79cbc77SKalle Valo data->if_limits[i].max; 5087f79cbc77SKalle Valo 5088f79cbc77SKalle Valo data->if_combination.n_limits = n_limits; 5089f79cbc77SKalle Valo data->if_combination.limits = data->if_limits; 5090f79cbc77SKalle Valo 5091f79cbc77SKalle Valo /* 5092f79cbc77SKalle Valo * If we actually were asked to support combinations, 5093f79cbc77SKalle Valo * advertise them - if there's only a single thing like 5094f79cbc77SKalle Valo * only IBSS then don't advertise it as combinations. 5095f79cbc77SKalle Valo */ 5096f79cbc77SKalle Valo if (data->if_combination.max_interfaces > 1) { 5097f79cbc77SKalle Valo hw->wiphy->iface_combinations = &data->if_combination; 5098f79cbc77SKalle Valo hw->wiphy->n_iface_combinations = 1; 5099f79cbc77SKalle Valo } 5100f79cbc77SKalle Valo 5101f79cbc77SKalle Valo if (param->ciphers) { 5102f79cbc77SKalle Valo memcpy(data->ciphers, param->ciphers, 5103f79cbc77SKalle Valo param->n_ciphers * sizeof(u32)); 5104f79cbc77SKalle Valo hw->wiphy->cipher_suites = data->ciphers; 5105f79cbc77SKalle Valo hw->wiphy->n_cipher_suites = param->n_ciphers; 5106f79cbc77SKalle Valo } 5107f79cbc77SKalle Valo 5108c4f4d9f7SAloka Dixit hw->wiphy->mbssid_max_interfaces = 8; 51090dd45ebcSAloka Dixit hw->wiphy->ema_max_profile_periodicity = 3; 5110c4f4d9f7SAloka Dixit 5111f79cbc77SKalle Valo data->rx_rssi = DEFAULT_RX_RSSI; 5112f79cbc77SKalle Valo 5113f79cbc77SKalle Valo INIT_DELAYED_WORK(&data->roc_start, hw_roc_start); 5114f79cbc77SKalle Valo INIT_DELAYED_WORK(&data->roc_done, hw_roc_done); 5115f79cbc77SKalle Valo INIT_DELAYED_WORK(&data->hw_scan, hw_scan_work); 5116f79cbc77SKalle Valo 5117f79cbc77SKalle Valo hw->queues = 5; 5118f79cbc77SKalle Valo hw->offchannel_tx_hw_queue = 4; 5119f79cbc77SKalle Valo 5120f79cbc77SKalle Valo ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); 5121f79cbc77SKalle Valo ieee80211_hw_set(hw, CHANCTX_STA_CSA); 5122f79cbc77SKalle Valo ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); 5123f79cbc77SKalle Valo ieee80211_hw_set(hw, QUEUE_CONTROL); 5124f79cbc77SKalle Valo ieee80211_hw_set(hw, WANT_MONITOR_VIF); 5125f79cbc77SKalle Valo ieee80211_hw_set(hw, AMPDU_AGGREGATION); 5126f79cbc77SKalle Valo ieee80211_hw_set(hw, MFP_CAPABLE); 5127f79cbc77SKalle Valo ieee80211_hw_set(hw, SIGNAL_DBM); 5128f79cbc77SKalle Valo ieee80211_hw_set(hw, SUPPORTS_PS); 5129f79cbc77SKalle Valo ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); 5130f79cbc77SKalle Valo ieee80211_hw_set(hw, TDLS_WIDER_BW); 5131f79cbc77SKalle Valo ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); 5132f79cbc77SKalle Valo 5133f79cbc77SKalle Valo if (param->mlo) { 5134f79cbc77SKalle Valo hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_MLO; 5135f79cbc77SKalle Valo ieee80211_hw_set(hw, HAS_RATE_CONTROL); 5136f79cbc77SKalle Valo ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); 5137f79cbc77SKalle Valo ieee80211_hw_set(hw, CONNECTION_MONITOR); 5138f79cbc77SKalle Valo ieee80211_hw_set(hw, AP_LINK_PS); 5139f79cbc77SKalle Valo } else { 5140f79cbc77SKalle Valo ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); 5141f79cbc77SKalle Valo ieee80211_hw_set(hw, PS_NULLFUNC_STACK); 5142f79cbc77SKalle Valo if (rctbl) 5143f79cbc77SKalle Valo ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); 5144f79cbc77SKalle Valo } 5145f79cbc77SKalle Valo 5146f79cbc77SKalle Valo hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; 5147f79cbc77SKalle Valo hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | 5148f79cbc77SKalle Valo WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | 5149f79cbc77SKalle Valo WIPHY_FLAG_AP_UAPSD | 5150f79cbc77SKalle Valo WIPHY_FLAG_SUPPORTS_5_10_MHZ | 5151f79cbc77SKalle Valo WIPHY_FLAG_HAS_CHANNEL_SWITCH; 5152f79cbc77SKalle Valo hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR | 5153f79cbc77SKalle Valo NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | 5154f79cbc77SKalle Valo NL80211_FEATURE_STATIC_SMPS | 5155f79cbc77SKalle Valo NL80211_FEATURE_DYNAMIC_SMPS | 5156f79cbc77SKalle Valo NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; 5157f79cbc77SKalle Valo wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS); 5158f79cbc77SKalle Valo wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_BEACON_PROTECTION); 5159f79cbc77SKalle Valo wiphy_ext_feature_set(hw->wiphy, 5160f79cbc77SKalle Valo NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS); 5161f79cbc77SKalle Valo wiphy_ext_feature_set(hw->wiphy, 5162f79cbc77SKalle Valo NL80211_EXT_FEATURE_BEACON_RATE_LEGACY); 516392d13386SJaewan Kim wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER); 5164f79cbc77SKalle Valo 5165f79cbc77SKalle Valo wiphy_ext_feature_set(hw->wiphy, 5166f79cbc77SKalle Valo NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT); 5167f79cbc77SKalle Valo 5168f79cbc77SKalle Valo hw->wiphy->interface_modes = param->iftypes; 5169f79cbc77SKalle Valo 5170f79cbc77SKalle Valo /* ask mac80211 to reserve space for magic */ 5171f79cbc77SKalle Valo hw->vif_data_size = sizeof(struct hwsim_vif_priv); 5172f79cbc77SKalle Valo hw->sta_data_size = sizeof(struct hwsim_sta_priv); 5173f79cbc77SKalle Valo hw->chanctx_data_size = sizeof(struct hwsim_chanctx_priv); 5174f79cbc77SKalle Valo 5175f79cbc77SKalle Valo memcpy(data->channels_2ghz, hwsim_channels_2ghz, 5176f79cbc77SKalle Valo sizeof(hwsim_channels_2ghz)); 5177f79cbc77SKalle Valo memcpy(data->channels_5ghz, hwsim_channels_5ghz, 5178f79cbc77SKalle Valo sizeof(hwsim_channels_5ghz)); 5179f79cbc77SKalle Valo memcpy(data->channels_6ghz, hwsim_channels_6ghz, 5180f79cbc77SKalle Valo sizeof(hwsim_channels_6ghz)); 5181f79cbc77SKalle Valo memcpy(data->channels_s1g, hwsim_channels_s1g, 5182f79cbc77SKalle Valo sizeof(hwsim_channels_s1g)); 5183f79cbc77SKalle Valo memcpy(data->rates, hwsim_rates, sizeof(hwsim_rates)); 5184f79cbc77SKalle Valo 5185f79cbc77SKalle Valo for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; band++) { 5186f79cbc77SKalle Valo struct ieee80211_supported_band *sband = &data->bands[band]; 5187f79cbc77SKalle Valo 5188f79cbc77SKalle Valo sband->band = band; 5189f79cbc77SKalle Valo 5190f79cbc77SKalle Valo switch (band) { 5191f79cbc77SKalle Valo case NL80211_BAND_2GHZ: 5192f79cbc77SKalle Valo sband->channels = data->channels_2ghz; 5193f79cbc77SKalle Valo sband->n_channels = ARRAY_SIZE(hwsim_channels_2ghz); 5194f79cbc77SKalle Valo sband->bitrates = data->rates; 5195f79cbc77SKalle Valo sband->n_bitrates = ARRAY_SIZE(hwsim_rates); 5196f79cbc77SKalle Valo break; 5197f79cbc77SKalle Valo case NL80211_BAND_5GHZ: 5198f79cbc77SKalle Valo sband->channels = data->channels_5ghz; 5199f79cbc77SKalle Valo sband->n_channels = ARRAY_SIZE(hwsim_channels_5ghz); 5200f79cbc77SKalle Valo sband->bitrates = data->rates + 4; 5201f79cbc77SKalle Valo sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4; 5202f79cbc77SKalle Valo 5203f79cbc77SKalle Valo sband->vht_cap.vht_supported = true; 5204f79cbc77SKalle Valo sband->vht_cap.cap = 5205f79cbc77SKalle Valo IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | 5206f79cbc77SKalle Valo IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ | 5207f79cbc77SKalle Valo IEEE80211_VHT_CAP_RXLDPC | 5208f79cbc77SKalle Valo IEEE80211_VHT_CAP_SHORT_GI_80 | 5209f79cbc77SKalle Valo IEEE80211_VHT_CAP_SHORT_GI_160 | 5210f79cbc77SKalle Valo IEEE80211_VHT_CAP_TXSTBC | 5211f79cbc77SKalle Valo IEEE80211_VHT_CAP_RXSTBC_4 | 5212f79cbc77SKalle Valo IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; 5213f79cbc77SKalle Valo sband->vht_cap.vht_mcs.rx_mcs_map = 5214f79cbc77SKalle Valo cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | 5215f79cbc77SKalle Valo IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 | 5216f79cbc77SKalle Valo IEEE80211_VHT_MCS_SUPPORT_0_9 << 4 | 5217f79cbc77SKalle Valo IEEE80211_VHT_MCS_SUPPORT_0_9 << 6 | 5218f79cbc77SKalle Valo IEEE80211_VHT_MCS_SUPPORT_0_9 << 8 | 5219f79cbc77SKalle Valo IEEE80211_VHT_MCS_SUPPORT_0_9 << 10 | 5220f79cbc77SKalle Valo IEEE80211_VHT_MCS_SUPPORT_0_9 << 12 | 5221f79cbc77SKalle Valo IEEE80211_VHT_MCS_SUPPORT_0_9 << 14); 5222f79cbc77SKalle Valo sband->vht_cap.vht_mcs.tx_mcs_map = 5223f79cbc77SKalle Valo sband->vht_cap.vht_mcs.rx_mcs_map; 5224f79cbc77SKalle Valo break; 5225f79cbc77SKalle Valo case NL80211_BAND_6GHZ: 5226f79cbc77SKalle Valo sband->channels = data->channels_6ghz; 5227f79cbc77SKalle Valo sband->n_channels = ARRAY_SIZE(hwsim_channels_6ghz); 5228f79cbc77SKalle Valo sband->bitrates = data->rates + 4; 5229f79cbc77SKalle Valo sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4; 5230f79cbc77SKalle Valo break; 5231f79cbc77SKalle Valo case NL80211_BAND_S1GHZ: 5232f79cbc77SKalle Valo memcpy(&sband->s1g_cap, &hwsim_s1g_cap, 5233f79cbc77SKalle Valo sizeof(sband->s1g_cap)); 5234f79cbc77SKalle Valo sband->channels = data->channels_s1g; 5235f79cbc77SKalle Valo sband->n_channels = ARRAY_SIZE(hwsim_channels_s1g); 5236f79cbc77SKalle Valo break; 5237f79cbc77SKalle Valo default: 5238f79cbc77SKalle Valo continue; 5239f79cbc77SKalle Valo } 5240f79cbc77SKalle Valo 5241f79cbc77SKalle Valo if (band != NL80211_BAND_6GHZ){ 5242f79cbc77SKalle Valo sband->ht_cap.ht_supported = true; 5243f79cbc77SKalle Valo sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | 5244f79cbc77SKalle Valo IEEE80211_HT_CAP_GRN_FLD | 5245f79cbc77SKalle Valo IEEE80211_HT_CAP_SGI_20 | 5246f79cbc77SKalle Valo IEEE80211_HT_CAP_SGI_40 | 5247f79cbc77SKalle Valo IEEE80211_HT_CAP_DSSSCCK40; 5248f79cbc77SKalle Valo sband->ht_cap.ampdu_factor = 0x3; 5249f79cbc77SKalle Valo sband->ht_cap.ampdu_density = 0x6; 5250f79cbc77SKalle Valo memset(&sband->ht_cap.mcs, 0, 5251f79cbc77SKalle Valo sizeof(sband->ht_cap.mcs)); 5252f79cbc77SKalle Valo sband->ht_cap.mcs.rx_mask[0] = 0xff; 5253f79cbc77SKalle Valo sband->ht_cap.mcs.rx_mask[1] = 0xff; 5254f79cbc77SKalle Valo sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; 5255f79cbc77SKalle Valo } 5256f79cbc77SKalle Valo 5257f79cbc77SKalle Valo mac80211_hwsim_sband_capab(sband); 5258f79cbc77SKalle Valo 5259f79cbc77SKalle Valo hw->wiphy->bands[band] = sband; 5260f79cbc77SKalle Valo } 5261f79cbc77SKalle Valo 5262f79cbc77SKalle Valo /* By default all radios belong to the first group */ 5263f79cbc77SKalle Valo data->group = 1; 5264f79cbc77SKalle Valo mutex_init(&data->mutex); 5265f79cbc77SKalle Valo 5266f79cbc77SKalle Valo data->netgroup = hwsim_net_get_netgroup(net); 5267f79cbc77SKalle Valo data->wmediumd = hwsim_net_get_wmediumd(net); 5268f79cbc77SKalle Valo 5269f79cbc77SKalle Valo /* Enable frame retransmissions for lossy channels */ 5270f79cbc77SKalle Valo hw->max_rates = 4; 5271f79cbc77SKalle Valo hw->max_rate_tries = 11; 5272f79cbc77SKalle Valo 5273f79cbc77SKalle Valo hw->wiphy->vendor_commands = mac80211_hwsim_vendor_commands; 5274f79cbc77SKalle Valo hw->wiphy->n_vendor_commands = 5275f79cbc77SKalle Valo ARRAY_SIZE(mac80211_hwsim_vendor_commands); 5276f79cbc77SKalle Valo hw->wiphy->vendor_events = mac80211_hwsim_vendor_events; 5277f79cbc77SKalle Valo hw->wiphy->n_vendor_events = ARRAY_SIZE(mac80211_hwsim_vendor_events); 5278f79cbc77SKalle Valo 5279f79cbc77SKalle Valo if (param->reg_strict) 5280f79cbc77SKalle Valo hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG; 5281f79cbc77SKalle Valo if (param->regd) { 5282f79cbc77SKalle Valo data->regd = param->regd; 5283f79cbc77SKalle Valo hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; 5284f79cbc77SKalle Valo wiphy_apply_custom_regulatory(hw->wiphy, param->regd); 5285f79cbc77SKalle Valo /* give the regulatory workqueue a chance to run */ 5286f79cbc77SKalle Valo schedule_timeout_interruptible(1); 5287f79cbc77SKalle Valo } 5288f79cbc77SKalle Valo 5289f79cbc77SKalle Valo if (param->no_vif) 5290f79cbc77SKalle Valo ieee80211_hw_set(hw, NO_AUTO_VIF); 5291f79cbc77SKalle Valo 5292f79cbc77SKalle Valo wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); 5293f79cbc77SKalle Valo 5294f79cbc77SKalle Valo for (i = 0; i < ARRAY_SIZE(data->link_data); i++) { 5295f79cbc77SKalle Valo hrtimer_init(&data->link_data[i].beacon_timer, CLOCK_MONOTONIC, 5296f79cbc77SKalle Valo HRTIMER_MODE_ABS_SOFT); 5297f79cbc77SKalle Valo data->link_data[i].beacon_timer.function = 5298f79cbc77SKalle Valo mac80211_hwsim_beacon; 5299f79cbc77SKalle Valo data->link_data[i].link_id = i; 5300f79cbc77SKalle Valo } 5301f79cbc77SKalle Valo 5302f79cbc77SKalle Valo err = ieee80211_register_hw(hw); 5303f79cbc77SKalle Valo if (err < 0) { 5304f79cbc77SKalle Valo pr_debug("mac80211_hwsim: ieee80211_register_hw failed (%d)\n", 5305f79cbc77SKalle Valo err); 5306f79cbc77SKalle Valo goto failed_hw; 5307f79cbc77SKalle Valo } 5308f79cbc77SKalle Valo 5309f79cbc77SKalle Valo wiphy_dbg(hw->wiphy, "hwaddr %pM registered\n", hw->wiphy->perm_addr); 5310f79cbc77SKalle Valo 5311f79cbc77SKalle Valo if (param->reg_alpha2) { 5312f79cbc77SKalle Valo data->alpha2[0] = param->reg_alpha2[0]; 5313f79cbc77SKalle Valo data->alpha2[1] = param->reg_alpha2[1]; 5314f79cbc77SKalle Valo regulatory_hint(hw->wiphy, param->reg_alpha2); 5315f79cbc77SKalle Valo } 5316f79cbc77SKalle Valo 5317f79cbc77SKalle Valo data->debugfs = debugfs_create_dir("hwsim", hw->wiphy->debugfsdir); 5318f79cbc77SKalle Valo debugfs_create_file("ps", 0666, data->debugfs, data, &hwsim_fops_ps); 5319f79cbc77SKalle Valo debugfs_create_file("group", 0666, data->debugfs, data, 5320f79cbc77SKalle Valo &hwsim_fops_group); 5321f79cbc77SKalle Valo debugfs_create_file("rx_rssi", 0666, data->debugfs, data, 5322f79cbc77SKalle Valo &hwsim_fops_rx_rssi); 5323f79cbc77SKalle Valo if (!data->use_chanctx) 5324f79cbc77SKalle Valo debugfs_create_file("dfs_simulate_radar", 0222, 5325f79cbc77SKalle Valo data->debugfs, 5326f79cbc77SKalle Valo data, &hwsim_simulate_radar); 5327f79cbc77SKalle Valo 532892d13386SJaewan Kim if (param->pmsr_capa) { 532992d13386SJaewan Kim data->pmsr_capa = *param->pmsr_capa; 533092d13386SJaewan Kim hw->wiphy->pmsr_capa = &data->pmsr_capa; 533192d13386SJaewan Kim } 533292d13386SJaewan Kim 5333f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 5334f79cbc77SKalle Valo err = rhashtable_insert_fast(&hwsim_radios_rht, &data->rht, 5335f79cbc77SKalle Valo hwsim_rht_params); 5336f79cbc77SKalle Valo if (err < 0) { 5337f79cbc77SKalle Valo if (info) { 5338f79cbc77SKalle Valo GENL_SET_ERR_MSG(info, "perm addr already present"); 5339f79cbc77SKalle Valo NL_SET_BAD_ATTR(info->extack, 5340f79cbc77SKalle Valo info->attrs[HWSIM_ATTR_PERM_ADDR]); 5341f79cbc77SKalle Valo } 5342f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 5343f79cbc77SKalle Valo goto failed_final_insert; 5344f79cbc77SKalle Valo } 5345f79cbc77SKalle Valo 5346f79cbc77SKalle Valo list_add_tail(&data->list, &hwsim_radios); 5347f79cbc77SKalle Valo hwsim_radios_generation++; 5348f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 5349f79cbc77SKalle Valo 5350f79cbc77SKalle Valo hwsim_mcast_new_radio(idx, info, param); 5351f79cbc77SKalle Valo 5352f79cbc77SKalle Valo return idx; 5353f79cbc77SKalle Valo 5354f79cbc77SKalle Valo failed_final_insert: 5355f79cbc77SKalle Valo debugfs_remove_recursive(data->debugfs); 5356f79cbc77SKalle Valo ieee80211_unregister_hw(data->hw); 5357f79cbc77SKalle Valo failed_hw: 5358f79cbc77SKalle Valo device_release_driver(data->dev); 5359f79cbc77SKalle Valo failed_bind: 5360f79cbc77SKalle Valo device_unregister(data->dev); 5361f79cbc77SKalle Valo failed_drvdata: 5362f79cbc77SKalle Valo ieee80211_free_hw(hw); 5363f79cbc77SKalle Valo failed: 5364f79cbc77SKalle Valo return err; 5365f79cbc77SKalle Valo } 5366f79cbc77SKalle Valo 5367f79cbc77SKalle Valo static void hwsim_mcast_del_radio(int id, const char *hwname, 5368f79cbc77SKalle Valo struct genl_info *info) 5369f79cbc77SKalle Valo { 5370f79cbc77SKalle Valo struct sk_buff *skb; 5371f79cbc77SKalle Valo void *data; 5372f79cbc77SKalle Valo int ret; 5373f79cbc77SKalle Valo 5374f79cbc77SKalle Valo skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 5375f79cbc77SKalle Valo if (!skb) 5376f79cbc77SKalle Valo return; 5377f79cbc77SKalle Valo 5378f79cbc77SKalle Valo data = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, 5379f79cbc77SKalle Valo HWSIM_CMD_DEL_RADIO); 5380f79cbc77SKalle Valo if (!data) 5381f79cbc77SKalle Valo goto error; 5382f79cbc77SKalle Valo 5383f79cbc77SKalle Valo ret = nla_put_u32(skb, HWSIM_ATTR_RADIO_ID, id); 5384f79cbc77SKalle Valo if (ret < 0) 5385f79cbc77SKalle Valo goto error; 5386f79cbc77SKalle Valo 5387f79cbc77SKalle Valo ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME, strlen(hwname), 5388f79cbc77SKalle Valo hwname); 5389f79cbc77SKalle Valo if (ret < 0) 5390f79cbc77SKalle Valo goto error; 5391f79cbc77SKalle Valo 5392f79cbc77SKalle Valo genlmsg_end(skb, data); 5393f79cbc77SKalle Valo 5394f79cbc77SKalle Valo hwsim_mcast_config_msg(skb, info); 5395f79cbc77SKalle Valo 5396f79cbc77SKalle Valo return; 5397f79cbc77SKalle Valo 5398f79cbc77SKalle Valo error: 5399f79cbc77SKalle Valo nlmsg_free(skb); 5400f79cbc77SKalle Valo } 5401f79cbc77SKalle Valo 5402f79cbc77SKalle Valo static void mac80211_hwsim_del_radio(struct mac80211_hwsim_data *data, 5403f79cbc77SKalle Valo const char *hwname, 5404f79cbc77SKalle Valo struct genl_info *info) 5405f79cbc77SKalle Valo { 5406f79cbc77SKalle Valo hwsim_mcast_del_radio(data->idx, hwname, info); 5407f79cbc77SKalle Valo debugfs_remove_recursive(data->debugfs); 5408f79cbc77SKalle Valo ieee80211_unregister_hw(data->hw); 5409f79cbc77SKalle Valo device_release_driver(data->dev); 5410f79cbc77SKalle Valo device_unregister(data->dev); 5411f79cbc77SKalle Valo ieee80211_free_hw(data->hw); 5412f79cbc77SKalle Valo } 5413f79cbc77SKalle Valo 5414f79cbc77SKalle Valo static int mac80211_hwsim_get_radio(struct sk_buff *skb, 5415f79cbc77SKalle Valo struct mac80211_hwsim_data *data, 5416f79cbc77SKalle Valo u32 portid, u32 seq, 5417f79cbc77SKalle Valo struct netlink_callback *cb, int flags) 5418f79cbc77SKalle Valo { 5419f79cbc77SKalle Valo void *hdr; 5420f79cbc77SKalle Valo struct hwsim_new_radio_params param = { }; 5421f79cbc77SKalle Valo int res = -EMSGSIZE; 5422f79cbc77SKalle Valo 5423f79cbc77SKalle Valo hdr = genlmsg_put(skb, portid, seq, &hwsim_genl_family, flags, 5424f79cbc77SKalle Valo HWSIM_CMD_GET_RADIO); 5425f79cbc77SKalle Valo if (!hdr) 5426f79cbc77SKalle Valo return -EMSGSIZE; 5427f79cbc77SKalle Valo 5428f79cbc77SKalle Valo if (cb) 5429f79cbc77SKalle Valo genl_dump_check_consistent(cb, hdr); 5430f79cbc77SKalle Valo 5431f79cbc77SKalle Valo if (data->alpha2[0] && data->alpha2[1]) 5432f79cbc77SKalle Valo param.reg_alpha2 = data->alpha2; 5433f79cbc77SKalle Valo 5434f79cbc77SKalle Valo param.reg_strict = !!(data->hw->wiphy->regulatory_flags & 5435f79cbc77SKalle Valo REGULATORY_STRICT_REG); 5436f79cbc77SKalle Valo param.p2p_device = !!(data->hw->wiphy->interface_modes & 5437f79cbc77SKalle Valo BIT(NL80211_IFTYPE_P2P_DEVICE)); 5438f79cbc77SKalle Valo param.use_chanctx = data->use_chanctx; 5439f79cbc77SKalle Valo param.regd = data->regd; 5440f79cbc77SKalle Valo param.channels = data->channels; 5441f79cbc77SKalle Valo param.hwname = wiphy_name(data->hw->wiphy); 544292d13386SJaewan Kim param.pmsr_capa = &data->pmsr_capa; 5443f79cbc77SKalle Valo 5444f79cbc77SKalle Valo res = append_radio_msg(skb, data->idx, ¶m); 5445f79cbc77SKalle Valo if (res < 0) 5446f79cbc77SKalle Valo goto out_err; 5447f79cbc77SKalle Valo 5448f79cbc77SKalle Valo genlmsg_end(skb, hdr); 5449f79cbc77SKalle Valo return 0; 5450f79cbc77SKalle Valo 5451f79cbc77SKalle Valo out_err: 5452f79cbc77SKalle Valo genlmsg_cancel(skb, hdr); 5453f79cbc77SKalle Valo return res; 5454f79cbc77SKalle Valo } 5455f79cbc77SKalle Valo 5456f79cbc77SKalle Valo static void mac80211_hwsim_free(void) 5457f79cbc77SKalle Valo { 5458f79cbc77SKalle Valo struct mac80211_hwsim_data *data; 5459f79cbc77SKalle Valo 5460f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 5461f79cbc77SKalle Valo while ((data = list_first_entry_or_null(&hwsim_radios, 5462f79cbc77SKalle Valo struct mac80211_hwsim_data, 5463f79cbc77SKalle Valo list))) { 5464f79cbc77SKalle Valo list_del(&data->list); 5465f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 5466f79cbc77SKalle Valo mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy), 5467f79cbc77SKalle Valo NULL); 5468f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 5469f79cbc77SKalle Valo } 5470f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 5471f79cbc77SKalle Valo class_destroy(hwsim_class); 5472f79cbc77SKalle Valo } 5473f79cbc77SKalle Valo 5474f79cbc77SKalle Valo static const struct net_device_ops hwsim_netdev_ops = { 5475f79cbc77SKalle Valo .ndo_start_xmit = hwsim_mon_xmit, 5476f79cbc77SKalle Valo .ndo_set_mac_address = eth_mac_addr, 5477f79cbc77SKalle Valo .ndo_validate_addr = eth_validate_addr, 5478f79cbc77SKalle Valo }; 5479f79cbc77SKalle Valo 5480f79cbc77SKalle Valo static void hwsim_mon_setup(struct net_device *dev) 5481f79cbc77SKalle Valo { 5482f79cbc77SKalle Valo u8 addr[ETH_ALEN]; 5483f79cbc77SKalle Valo 5484f79cbc77SKalle Valo dev->netdev_ops = &hwsim_netdev_ops; 5485f79cbc77SKalle Valo dev->needs_free_netdev = true; 5486f79cbc77SKalle Valo ether_setup(dev); 5487f79cbc77SKalle Valo dev->priv_flags |= IFF_NO_QUEUE; 5488f79cbc77SKalle Valo dev->type = ARPHRD_IEEE80211_RADIOTAP; 5489f79cbc77SKalle Valo eth_zero_addr(addr); 5490f79cbc77SKalle Valo addr[0] = 0x12; 5491f79cbc77SKalle Valo eth_hw_addr_set(dev, addr); 5492f79cbc77SKalle Valo } 5493f79cbc77SKalle Valo 5494f79cbc77SKalle Valo static void hwsim_register_wmediumd(struct net *net, u32 portid) 5495f79cbc77SKalle Valo { 5496f79cbc77SKalle Valo struct mac80211_hwsim_data *data; 5497f79cbc77SKalle Valo 5498f79cbc77SKalle Valo hwsim_net_set_wmediumd(net, portid); 5499f79cbc77SKalle Valo 5500f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 5501f79cbc77SKalle Valo list_for_each_entry(data, &hwsim_radios, list) { 5502f79cbc77SKalle Valo if (data->netgroup == hwsim_net_get_netgroup(net)) 5503f79cbc77SKalle Valo data->wmediumd = portid; 5504f79cbc77SKalle Valo } 5505f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 5506f79cbc77SKalle Valo } 5507f79cbc77SKalle Valo 5508f79cbc77SKalle Valo static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2, 5509f79cbc77SKalle Valo struct genl_info *info) 5510f79cbc77SKalle Valo { 5511f79cbc77SKalle Valo 5512f79cbc77SKalle Valo struct ieee80211_hdr *hdr; 5513f79cbc77SKalle Valo struct mac80211_hwsim_data *data2; 5514f79cbc77SKalle Valo struct ieee80211_tx_info *txi; 5515f79cbc77SKalle Valo struct hwsim_tx_rate *tx_attempts; 5516f79cbc77SKalle Valo u64 ret_skb_cookie; 5517f79cbc77SKalle Valo struct sk_buff *skb, *tmp; 5518f79cbc77SKalle Valo const u8 *src; 5519f79cbc77SKalle Valo unsigned int hwsim_flags; 5520f79cbc77SKalle Valo int i; 5521f79cbc77SKalle Valo unsigned long flags; 5522f79cbc77SKalle Valo bool found = false; 5523f79cbc77SKalle Valo 5524f79cbc77SKalle Valo if (!info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER] || 5525f79cbc77SKalle Valo !info->attrs[HWSIM_ATTR_FLAGS] || 5526f79cbc77SKalle Valo !info->attrs[HWSIM_ATTR_COOKIE] || 5527f79cbc77SKalle Valo !info->attrs[HWSIM_ATTR_SIGNAL] || 5528f79cbc77SKalle Valo !info->attrs[HWSIM_ATTR_TX_INFO]) 5529f79cbc77SKalle Valo goto out; 5530f79cbc77SKalle Valo 5531f79cbc77SKalle Valo src = (void *)nla_data(info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER]); 5532f79cbc77SKalle Valo hwsim_flags = nla_get_u32(info->attrs[HWSIM_ATTR_FLAGS]); 5533f79cbc77SKalle Valo ret_skb_cookie = nla_get_u64(info->attrs[HWSIM_ATTR_COOKIE]); 5534f79cbc77SKalle Valo 5535f79cbc77SKalle Valo data2 = get_hwsim_data_ref_from_addr(src); 5536f79cbc77SKalle Valo if (!data2) 5537f79cbc77SKalle Valo goto out; 5538f79cbc77SKalle Valo 5539f79cbc77SKalle Valo if (!hwsim_virtio_enabled) { 5540f79cbc77SKalle Valo if (hwsim_net_get_netgroup(genl_info_net(info)) != 5541f79cbc77SKalle Valo data2->netgroup) 5542f79cbc77SKalle Valo goto out; 5543f79cbc77SKalle Valo 5544f79cbc77SKalle Valo if (info->snd_portid != data2->wmediumd) 5545f79cbc77SKalle Valo goto out; 5546f79cbc77SKalle Valo } 5547f79cbc77SKalle Valo 5548f79cbc77SKalle Valo /* look for the skb matching the cookie passed back from user */ 5549f79cbc77SKalle Valo spin_lock_irqsave(&data2->pending.lock, flags); 5550f79cbc77SKalle Valo skb_queue_walk_safe(&data2->pending, skb, tmp) { 5551f79cbc77SKalle Valo uintptr_t skb_cookie; 5552f79cbc77SKalle Valo 5553f79cbc77SKalle Valo txi = IEEE80211_SKB_CB(skb); 5554f79cbc77SKalle Valo skb_cookie = (uintptr_t)txi->rate_driver_data[0]; 5555f79cbc77SKalle Valo 5556f79cbc77SKalle Valo if (skb_cookie == ret_skb_cookie) { 5557f79cbc77SKalle Valo __skb_unlink(skb, &data2->pending); 5558f79cbc77SKalle Valo found = true; 5559f79cbc77SKalle Valo break; 5560f79cbc77SKalle Valo } 5561f79cbc77SKalle Valo } 5562f79cbc77SKalle Valo spin_unlock_irqrestore(&data2->pending.lock, flags); 5563f79cbc77SKalle Valo 5564f79cbc77SKalle Valo /* not found */ 5565f79cbc77SKalle Valo if (!found) 5566f79cbc77SKalle Valo goto out; 5567f79cbc77SKalle Valo 5568f79cbc77SKalle Valo /* Tx info received because the frame was broadcasted on user space, 5569f79cbc77SKalle Valo so we get all the necessary info: tx attempts and skb control buff */ 5570f79cbc77SKalle Valo 5571f79cbc77SKalle Valo tx_attempts = (struct hwsim_tx_rate *)nla_data( 5572f79cbc77SKalle Valo info->attrs[HWSIM_ATTR_TX_INFO]); 5573f79cbc77SKalle Valo 5574f79cbc77SKalle Valo /* now send back TX status */ 5575f79cbc77SKalle Valo txi = IEEE80211_SKB_CB(skb); 5576f79cbc77SKalle Valo 5577f79cbc77SKalle Valo ieee80211_tx_info_clear_status(txi); 5578f79cbc77SKalle Valo 5579f79cbc77SKalle Valo for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { 5580f79cbc77SKalle Valo txi->status.rates[i].idx = tx_attempts[i].idx; 5581f79cbc77SKalle Valo txi->status.rates[i].count = tx_attempts[i].count; 5582f79cbc77SKalle Valo } 5583f79cbc77SKalle Valo 5584f79cbc77SKalle Valo txi->status.ack_signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]); 5585f79cbc77SKalle Valo 5586f79cbc77SKalle Valo if (!(hwsim_flags & HWSIM_TX_CTL_NO_ACK) && 5587f79cbc77SKalle Valo (hwsim_flags & HWSIM_TX_STAT_ACK)) { 5588f79cbc77SKalle Valo if (skb->len >= 16) { 5589f79cbc77SKalle Valo hdr = (struct ieee80211_hdr *) skb->data; 5590f79cbc77SKalle Valo mac80211_hwsim_monitor_ack(data2->channel, 5591f79cbc77SKalle Valo hdr->addr2); 5592f79cbc77SKalle Valo } 5593f79cbc77SKalle Valo txi->flags |= IEEE80211_TX_STAT_ACK; 5594f79cbc77SKalle Valo } 5595f79cbc77SKalle Valo 5596f79cbc77SKalle Valo if (hwsim_flags & HWSIM_TX_CTL_NO_ACK) 5597f79cbc77SKalle Valo txi->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; 5598f79cbc77SKalle Valo 5599f79cbc77SKalle Valo ieee80211_tx_status_irqsafe(data2->hw, skb); 5600f79cbc77SKalle Valo return 0; 5601f79cbc77SKalle Valo out: 5602f79cbc77SKalle Valo return -EINVAL; 5603f79cbc77SKalle Valo 5604f79cbc77SKalle Valo } 5605f79cbc77SKalle Valo 5606f79cbc77SKalle Valo static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, 5607f79cbc77SKalle Valo struct genl_info *info) 5608f79cbc77SKalle Valo { 5609f79cbc77SKalle Valo struct mac80211_hwsim_data *data2; 5610f79cbc77SKalle Valo struct ieee80211_rx_status rx_status; 5611f79cbc77SKalle Valo struct ieee80211_hdr *hdr; 5612f79cbc77SKalle Valo const u8 *dst; 5613f79cbc77SKalle Valo int frame_data_len; 5614f79cbc77SKalle Valo void *frame_data; 5615f79cbc77SKalle Valo struct sk_buff *skb = NULL; 5616f79cbc77SKalle Valo struct ieee80211_channel *channel = NULL; 5617f79cbc77SKalle Valo 5618f79cbc77SKalle Valo if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] || 5619f79cbc77SKalle Valo !info->attrs[HWSIM_ATTR_FRAME] || 5620f79cbc77SKalle Valo !info->attrs[HWSIM_ATTR_RX_RATE] || 5621f79cbc77SKalle Valo !info->attrs[HWSIM_ATTR_SIGNAL]) 5622f79cbc77SKalle Valo goto out; 5623f79cbc77SKalle Valo 5624f79cbc77SKalle Valo dst = (void *)nla_data(info->attrs[HWSIM_ATTR_ADDR_RECEIVER]); 5625f79cbc77SKalle Valo frame_data_len = nla_len(info->attrs[HWSIM_ATTR_FRAME]); 5626f79cbc77SKalle Valo frame_data = (void *)nla_data(info->attrs[HWSIM_ATTR_FRAME]); 5627f79cbc77SKalle Valo 5628fba360a0SJohannes Berg if (frame_data_len < sizeof(struct ieee80211_hdr_3addr) || 5629fba360a0SJohannes Berg frame_data_len > IEEE80211_MAX_DATA_LEN) 5630fba360a0SJohannes Berg goto err; 5631fba360a0SJohannes Berg 5632f79cbc77SKalle Valo /* Allocate new skb here */ 5633f79cbc77SKalle Valo skb = alloc_skb(frame_data_len, GFP_KERNEL); 5634f79cbc77SKalle Valo if (skb == NULL) 5635f79cbc77SKalle Valo goto err; 5636f79cbc77SKalle Valo 5637f79cbc77SKalle Valo /* Copy the data */ 5638f79cbc77SKalle Valo skb_put_data(skb, frame_data, frame_data_len); 5639f79cbc77SKalle Valo 5640f79cbc77SKalle Valo data2 = get_hwsim_data_ref_from_addr(dst); 5641f79cbc77SKalle Valo if (!data2) 5642f79cbc77SKalle Valo goto out; 5643f79cbc77SKalle Valo 5644f79cbc77SKalle Valo if (data2->use_chanctx) { 5645f79cbc77SKalle Valo if (data2->tmp_chan) 5646f79cbc77SKalle Valo channel = data2->tmp_chan; 5647f79cbc77SKalle Valo } else { 5648f79cbc77SKalle Valo channel = data2->channel; 5649f79cbc77SKalle Valo } 5650f79cbc77SKalle Valo 5651f79cbc77SKalle Valo if (!hwsim_virtio_enabled) { 5652f79cbc77SKalle Valo if (hwsim_net_get_netgroup(genl_info_net(info)) != 5653f79cbc77SKalle Valo data2->netgroup) 5654f79cbc77SKalle Valo goto out; 5655f79cbc77SKalle Valo 5656f79cbc77SKalle Valo if (info->snd_portid != data2->wmediumd) 5657f79cbc77SKalle Valo goto out; 5658f79cbc77SKalle Valo } 5659f79cbc77SKalle Valo 5660f79cbc77SKalle Valo /* check if radio is configured properly */ 5661f79cbc77SKalle Valo 5662f79cbc77SKalle Valo if ((data2->idle && !data2->tmp_chan) || !data2->started) 5663f79cbc77SKalle Valo goto out; 5664f79cbc77SKalle Valo 5665f79cbc77SKalle Valo /* A frame is received from user space */ 5666f79cbc77SKalle Valo memset(&rx_status, 0, sizeof(rx_status)); 5667f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_FREQ]) { 5668f79cbc77SKalle Valo struct tx_iter_data iter_data = {}; 5669f79cbc77SKalle Valo 5670f79cbc77SKalle Valo /* throw away off-channel packets, but allow both the temporary 5671f79cbc77SKalle Valo * ("hw" scan/remain-on-channel), regular channels and links, 5672f79cbc77SKalle Valo * since the internal datapath also allows this 5673f79cbc77SKalle Valo */ 5674f79cbc77SKalle Valo rx_status.freq = nla_get_u32(info->attrs[HWSIM_ATTR_FREQ]); 5675f79cbc77SKalle Valo 5676f79cbc77SKalle Valo iter_data.channel = ieee80211_get_channel(data2->hw->wiphy, 5677f79cbc77SKalle Valo rx_status.freq); 5678f79cbc77SKalle Valo if (!iter_data.channel) 5679f79cbc77SKalle Valo goto out; 5680f79cbc77SKalle Valo rx_status.band = iter_data.channel->band; 5681f79cbc77SKalle Valo 5682f79cbc77SKalle Valo mutex_lock(&data2->mutex); 5683f79cbc77SKalle Valo if (!hwsim_chans_compat(iter_data.channel, channel)) { 5684f79cbc77SKalle Valo ieee80211_iterate_active_interfaces_atomic( 5685f79cbc77SKalle Valo data2->hw, IEEE80211_IFACE_ITER_NORMAL, 5686f79cbc77SKalle Valo mac80211_hwsim_tx_iter, &iter_data); 5687f79cbc77SKalle Valo if (!iter_data.receive) { 5688f79cbc77SKalle Valo mutex_unlock(&data2->mutex); 5689f79cbc77SKalle Valo goto out; 5690f79cbc77SKalle Valo } 5691f79cbc77SKalle Valo } 5692f79cbc77SKalle Valo mutex_unlock(&data2->mutex); 5693f79cbc77SKalle Valo } else if (!channel) { 5694f79cbc77SKalle Valo goto out; 5695f79cbc77SKalle Valo } else { 5696f79cbc77SKalle Valo rx_status.freq = channel->center_freq; 5697f79cbc77SKalle Valo rx_status.band = channel->band; 5698f79cbc77SKalle Valo } 5699f79cbc77SKalle Valo 5700f79cbc77SKalle Valo rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]); 5701f79cbc77SKalle Valo if (rx_status.rate_idx >= data2->hw->wiphy->bands[rx_status.band]->n_bitrates) 5702f79cbc77SKalle Valo goto out; 5703f79cbc77SKalle Valo rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]); 5704f79cbc77SKalle Valo 5705f79cbc77SKalle Valo hdr = (void *)skb->data; 5706f79cbc77SKalle Valo 5707f79cbc77SKalle Valo if (ieee80211_is_beacon(hdr->frame_control) || 5708f79cbc77SKalle Valo ieee80211_is_probe_resp(hdr->frame_control)) 5709f79cbc77SKalle Valo rx_status.boottime_ns = ktime_get_boottime_ns(); 5710f79cbc77SKalle Valo 5711f79cbc77SKalle Valo mac80211_hwsim_rx(data2, &rx_status, skb); 5712f79cbc77SKalle Valo 5713f79cbc77SKalle Valo return 0; 5714f79cbc77SKalle Valo err: 5715f79cbc77SKalle Valo pr_debug("mac80211_hwsim: error occurred in %s\n", __func__); 5716f79cbc77SKalle Valo out: 5717f79cbc77SKalle Valo dev_kfree_skb(skb); 5718f79cbc77SKalle Valo return -EINVAL; 5719f79cbc77SKalle Valo } 5720f79cbc77SKalle Valo 5721f79cbc77SKalle Valo static int hwsim_register_received_nl(struct sk_buff *skb_2, 5722f79cbc77SKalle Valo struct genl_info *info) 5723f79cbc77SKalle Valo { 5724f79cbc77SKalle Valo struct net *net = genl_info_net(info); 5725f79cbc77SKalle Valo struct mac80211_hwsim_data *data; 5726f79cbc77SKalle Valo int chans = 1; 5727f79cbc77SKalle Valo 5728f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 5729f79cbc77SKalle Valo list_for_each_entry(data, &hwsim_radios, list) 5730f79cbc77SKalle Valo chans = max(chans, data->channels); 5731f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 5732f79cbc77SKalle Valo 5733f79cbc77SKalle Valo /* In the future we should revise the userspace API and allow it 5734f79cbc77SKalle Valo * to set a flag that it does support multi-channel, then we can 5735f79cbc77SKalle Valo * let this pass conditionally on the flag. 5736f79cbc77SKalle Valo * For current userspace, prohibit it since it won't work right. 5737f79cbc77SKalle Valo */ 5738f79cbc77SKalle Valo if (chans > 1) 5739f79cbc77SKalle Valo return -EOPNOTSUPP; 5740f79cbc77SKalle Valo 5741f79cbc77SKalle Valo if (hwsim_net_get_wmediumd(net)) 5742f79cbc77SKalle Valo return -EBUSY; 5743f79cbc77SKalle Valo 5744f79cbc77SKalle Valo hwsim_register_wmediumd(net, info->snd_portid); 5745f79cbc77SKalle Valo 5746f79cbc77SKalle Valo pr_debug("mac80211_hwsim: received a REGISTER, " 5747f79cbc77SKalle Valo "switching to wmediumd mode with pid %d\n", info->snd_portid); 5748f79cbc77SKalle Valo 5749f79cbc77SKalle Valo return 0; 5750f79cbc77SKalle Valo } 5751f79cbc77SKalle Valo 5752f79cbc77SKalle Valo /* ensures ciphers only include ciphers listed in 'hwsim_ciphers' array */ 5753f79cbc77SKalle Valo static bool hwsim_known_ciphers(const u32 *ciphers, int n_ciphers) 5754f79cbc77SKalle Valo { 5755f79cbc77SKalle Valo int i; 5756f79cbc77SKalle Valo 5757f79cbc77SKalle Valo for (i = 0; i < n_ciphers; i++) { 5758f79cbc77SKalle Valo int j; 5759f79cbc77SKalle Valo int found = 0; 5760f79cbc77SKalle Valo 5761f79cbc77SKalle Valo for (j = 0; j < ARRAY_SIZE(hwsim_ciphers); j++) { 5762f79cbc77SKalle Valo if (ciphers[i] == hwsim_ciphers[j]) { 5763f79cbc77SKalle Valo found = 1; 5764f79cbc77SKalle Valo break; 5765f79cbc77SKalle Valo } 5766f79cbc77SKalle Valo } 5767f79cbc77SKalle Valo 5768f79cbc77SKalle Valo if (!found) 5769f79cbc77SKalle Valo return false; 5770f79cbc77SKalle Valo } 5771f79cbc77SKalle Valo 5772f79cbc77SKalle Valo return true; 5773f79cbc77SKalle Valo } 5774f79cbc77SKalle Valo 577592d13386SJaewan Kim static int parse_ftm_capa(const struct nlattr *ftm_capa, struct cfg80211_pmsr_capabilities *out, 577692d13386SJaewan Kim struct genl_info *info) 577792d13386SJaewan Kim { 577892d13386SJaewan Kim struct nlattr *tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX + 1]; 577992d13386SJaewan Kim int ret; 578092d13386SJaewan Kim 578192d13386SJaewan Kim ret = nla_parse_nested(tb, NL80211_PMSR_FTM_CAPA_ATTR_MAX, ftm_capa, hwsim_ftm_capa_policy, 578292d13386SJaewan Kim NULL); 578392d13386SJaewan Kim if (ret) { 578492d13386SJaewan Kim NL_SET_ERR_MSG_ATTR(info->extack, ftm_capa, "malformed FTM capability"); 578592d13386SJaewan Kim return -EINVAL; 578692d13386SJaewan Kim } 578792d13386SJaewan Kim 578892d13386SJaewan Kim out->ftm.supported = 1; 578992d13386SJaewan Kim if (tb[NL80211_PMSR_FTM_CAPA_ATTR_PREAMBLES]) 579092d13386SJaewan Kim out->ftm.preambles = nla_get_u32(tb[NL80211_PMSR_FTM_CAPA_ATTR_PREAMBLES]); 579192d13386SJaewan Kim if (tb[NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS]) 579292d13386SJaewan Kim out->ftm.bandwidths = nla_get_u32(tb[NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS]); 579392d13386SJaewan Kim if (tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT]) 579492d13386SJaewan Kim out->ftm.max_bursts_exponent = 579592d13386SJaewan Kim nla_get_u8(tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT]); 579692d13386SJaewan Kim if (tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST]) 579792d13386SJaewan Kim out->ftm.max_ftms_per_burst = 579892d13386SJaewan Kim nla_get_u8(tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST]); 579992d13386SJaewan Kim out->ftm.asap = !!tb[NL80211_PMSR_FTM_CAPA_ATTR_ASAP]; 580092d13386SJaewan Kim out->ftm.non_asap = !!tb[NL80211_PMSR_FTM_CAPA_ATTR_NON_ASAP]; 580192d13386SJaewan Kim out->ftm.request_lci = !!tb[NL80211_PMSR_FTM_CAPA_ATTR_REQ_LCI]; 580292d13386SJaewan Kim out->ftm.request_civicloc = !!tb[NL80211_PMSR_FTM_CAPA_ATTR_REQ_CIVICLOC]; 580392d13386SJaewan Kim out->ftm.trigger_based = !!tb[NL80211_PMSR_FTM_CAPA_ATTR_TRIGGER_BASED]; 580492d13386SJaewan Kim out->ftm.non_trigger_based = !!tb[NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED]; 580592d13386SJaewan Kim 580692d13386SJaewan Kim return 0; 580792d13386SJaewan Kim } 580892d13386SJaewan Kim 580992d13386SJaewan Kim static int parse_pmsr_capa(const struct nlattr *pmsr_capa, struct cfg80211_pmsr_capabilities *out, 581092d13386SJaewan Kim struct genl_info *info) 581192d13386SJaewan Kim { 581292d13386SJaewan Kim struct nlattr *tb[NL80211_PMSR_ATTR_MAX + 1]; 581392d13386SJaewan Kim struct nlattr *nla; 581492d13386SJaewan Kim int size; 581592d13386SJaewan Kim int ret; 581692d13386SJaewan Kim 581792d13386SJaewan Kim ret = nla_parse_nested(tb, NL80211_PMSR_ATTR_MAX, pmsr_capa, hwsim_pmsr_capa_policy, NULL); 581892d13386SJaewan Kim if (ret) { 581992d13386SJaewan Kim NL_SET_ERR_MSG_ATTR(info->extack, pmsr_capa, "malformed PMSR capability"); 582092d13386SJaewan Kim return -EINVAL; 582192d13386SJaewan Kim } 582292d13386SJaewan Kim 582392d13386SJaewan Kim if (tb[NL80211_PMSR_ATTR_MAX_PEERS]) 582492d13386SJaewan Kim out->max_peers = nla_get_u32(tb[NL80211_PMSR_ATTR_MAX_PEERS]); 582592d13386SJaewan Kim out->report_ap_tsf = !!tb[NL80211_PMSR_ATTR_REPORT_AP_TSF]; 582692d13386SJaewan Kim out->randomize_mac_addr = !!tb[NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR]; 582792d13386SJaewan Kim 582892d13386SJaewan Kim if (!tb[NL80211_PMSR_ATTR_TYPE_CAPA]) { 582992d13386SJaewan Kim NL_SET_ERR_MSG_ATTR(info->extack, tb[NL80211_PMSR_ATTR_TYPE_CAPA], 583092d13386SJaewan Kim "malformed PMSR type"); 583192d13386SJaewan Kim return -EINVAL; 583292d13386SJaewan Kim } 583392d13386SJaewan Kim 583492d13386SJaewan Kim nla_for_each_nested(nla, tb[NL80211_PMSR_ATTR_TYPE_CAPA], size) { 583592d13386SJaewan Kim switch (nla_type(nla)) { 583692d13386SJaewan Kim case NL80211_PMSR_TYPE_FTM: 583792d13386SJaewan Kim parse_ftm_capa(nla, out, info); 583892d13386SJaewan Kim break; 583992d13386SJaewan Kim default: 584092d13386SJaewan Kim NL_SET_ERR_MSG_ATTR(info->extack, nla, "unsupported measurement type"); 584192d13386SJaewan Kim return -EINVAL; 584292d13386SJaewan Kim } 584392d13386SJaewan Kim } 584492d13386SJaewan Kim 584592d13386SJaewan Kim return 0; 584692d13386SJaewan Kim } 584792d13386SJaewan Kim 5848f79cbc77SKalle Valo static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info) 5849f79cbc77SKalle Valo { 5850f79cbc77SKalle Valo struct hwsim_new_radio_params param = { 0 }; 5851f79cbc77SKalle Valo const char *hwname = NULL; 5852f79cbc77SKalle Valo int ret; 5853f79cbc77SKalle Valo 5854f79cbc77SKalle Valo param.reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG]; 5855f79cbc77SKalle Valo param.p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE]; 5856f79cbc77SKalle Valo param.channels = channels; 5857f79cbc77SKalle Valo param.destroy_on_close = 5858f79cbc77SKalle Valo info->attrs[HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE]; 5859f79cbc77SKalle Valo 5860f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_CHANNELS]) 5861f79cbc77SKalle Valo param.channels = nla_get_u32(info->attrs[HWSIM_ATTR_CHANNELS]); 5862f79cbc77SKalle Valo 5863f79cbc77SKalle Valo if (param.channels < 1) { 5864f79cbc77SKalle Valo GENL_SET_ERR_MSG(info, "must have at least one channel"); 5865f79cbc77SKalle Valo return -EINVAL; 5866f79cbc77SKalle Valo } 5867f79cbc77SKalle Valo 5868f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_NO_VIF]) 5869f79cbc77SKalle Valo param.no_vif = true; 5870f79cbc77SKalle Valo 5871f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_USE_CHANCTX]) 5872f79cbc77SKalle Valo param.use_chanctx = true; 5873f79cbc77SKalle Valo else 5874f79cbc77SKalle Valo param.use_chanctx = (param.channels > 1); 5875f79cbc77SKalle Valo 5876f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]) 5877f79cbc77SKalle Valo param.reg_alpha2 = 5878f79cbc77SKalle Valo nla_data(info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]); 5879f79cbc77SKalle Valo 5880f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]) { 5881f79cbc77SKalle Valo u32 idx = nla_get_u32(info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]); 5882f79cbc77SKalle Valo 5883f79cbc77SKalle Valo if (idx >= ARRAY_SIZE(hwsim_world_regdom_custom)) 5884f79cbc77SKalle Valo return -EINVAL; 5885f79cbc77SKalle Valo 5886f79cbc77SKalle Valo idx = array_index_nospec(idx, 5887f79cbc77SKalle Valo ARRAY_SIZE(hwsim_world_regdom_custom)); 5888f79cbc77SKalle Valo param.regd = hwsim_world_regdom_custom[idx]; 5889f79cbc77SKalle Valo } 5890f79cbc77SKalle Valo 5891f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_PERM_ADDR]) { 5892f79cbc77SKalle Valo if (!is_valid_ether_addr( 5893f79cbc77SKalle Valo nla_data(info->attrs[HWSIM_ATTR_PERM_ADDR]))) { 5894f79cbc77SKalle Valo GENL_SET_ERR_MSG(info,"MAC is no valid source addr"); 5895f79cbc77SKalle Valo NL_SET_BAD_ATTR(info->extack, 5896f79cbc77SKalle Valo info->attrs[HWSIM_ATTR_PERM_ADDR]); 5897f79cbc77SKalle Valo return -EINVAL; 5898f79cbc77SKalle Valo } 5899f79cbc77SKalle Valo 5900f79cbc77SKalle Valo param.perm_addr = nla_data(info->attrs[HWSIM_ATTR_PERM_ADDR]); 5901f79cbc77SKalle Valo } 5902f79cbc77SKalle Valo 5903f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_IFTYPE_SUPPORT]) { 5904f79cbc77SKalle Valo param.iftypes = 5905f79cbc77SKalle Valo nla_get_u32(info->attrs[HWSIM_ATTR_IFTYPE_SUPPORT]); 5906f79cbc77SKalle Valo 5907f79cbc77SKalle Valo if (param.iftypes & ~HWSIM_IFTYPE_SUPPORT_MASK) { 5908f79cbc77SKalle Valo NL_SET_ERR_MSG_ATTR(info->extack, 5909f79cbc77SKalle Valo info->attrs[HWSIM_ATTR_IFTYPE_SUPPORT], 5910f79cbc77SKalle Valo "cannot support more iftypes than kernel"); 5911f79cbc77SKalle Valo return -EINVAL; 5912f79cbc77SKalle Valo } 5913f79cbc77SKalle Valo } else { 5914f79cbc77SKalle Valo param.iftypes = HWSIM_IFTYPE_SUPPORT_MASK; 5915f79cbc77SKalle Valo } 5916f79cbc77SKalle Valo 5917f79cbc77SKalle Valo /* ensure both flag and iftype support is honored */ 5918f79cbc77SKalle Valo if (param.p2p_device || 5919f79cbc77SKalle Valo param.iftypes & BIT(NL80211_IFTYPE_P2P_DEVICE)) { 5920f79cbc77SKalle Valo param.iftypes |= BIT(NL80211_IFTYPE_P2P_DEVICE); 5921f79cbc77SKalle Valo param.p2p_device = true; 5922f79cbc77SKalle Valo } 5923f79cbc77SKalle Valo 5924f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_CIPHER_SUPPORT]) { 5925f79cbc77SKalle Valo u32 len = nla_len(info->attrs[HWSIM_ATTR_CIPHER_SUPPORT]); 5926f79cbc77SKalle Valo 5927f79cbc77SKalle Valo param.ciphers = 5928f79cbc77SKalle Valo nla_data(info->attrs[HWSIM_ATTR_CIPHER_SUPPORT]); 5929f79cbc77SKalle Valo 5930f79cbc77SKalle Valo if (len % sizeof(u32)) { 5931f79cbc77SKalle Valo NL_SET_ERR_MSG_ATTR(info->extack, 5932f79cbc77SKalle Valo info->attrs[HWSIM_ATTR_CIPHER_SUPPORT], 5933f79cbc77SKalle Valo "bad cipher list length"); 5934f79cbc77SKalle Valo return -EINVAL; 5935f79cbc77SKalle Valo } 5936f79cbc77SKalle Valo 5937f79cbc77SKalle Valo param.n_ciphers = len / sizeof(u32); 5938f79cbc77SKalle Valo 5939f79cbc77SKalle Valo if (param.n_ciphers > ARRAY_SIZE(hwsim_ciphers)) { 5940f79cbc77SKalle Valo NL_SET_ERR_MSG_ATTR(info->extack, 5941f79cbc77SKalle Valo info->attrs[HWSIM_ATTR_CIPHER_SUPPORT], 5942f79cbc77SKalle Valo "too many ciphers specified"); 5943f79cbc77SKalle Valo return -EINVAL; 5944f79cbc77SKalle Valo } 5945f79cbc77SKalle Valo 5946f79cbc77SKalle Valo if (!hwsim_known_ciphers(param.ciphers, param.n_ciphers)) { 5947f79cbc77SKalle Valo NL_SET_ERR_MSG_ATTR(info->extack, 5948f79cbc77SKalle Valo info->attrs[HWSIM_ATTR_CIPHER_SUPPORT], 5949f79cbc77SKalle Valo "unsupported ciphers specified"); 5950f79cbc77SKalle Valo return -EINVAL; 5951f79cbc77SKalle Valo } 5952f79cbc77SKalle Valo } 5953f79cbc77SKalle Valo 5954f79cbc77SKalle Valo param.mlo = info->attrs[HWSIM_ATTR_MLO_SUPPORT]; 5955f79cbc77SKalle Valo 5956f79cbc77SKalle Valo if (param.mlo) 5957f79cbc77SKalle Valo param.use_chanctx = true; 5958f79cbc77SKalle Valo 5959f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_RADIO_NAME]) { 5960f79cbc77SKalle Valo hwname = kstrndup((char *)nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME]), 5961f79cbc77SKalle Valo nla_len(info->attrs[HWSIM_ATTR_RADIO_NAME]), 5962f79cbc77SKalle Valo GFP_KERNEL); 5963f79cbc77SKalle Valo if (!hwname) 5964f79cbc77SKalle Valo return -ENOMEM; 5965f79cbc77SKalle Valo param.hwname = hwname; 5966f79cbc77SKalle Valo } 5967f79cbc77SKalle Valo 596892d13386SJaewan Kim if (info->attrs[HWSIM_ATTR_PMSR_SUPPORT]) { 596992d13386SJaewan Kim struct cfg80211_pmsr_capabilities *pmsr_capa; 597092d13386SJaewan Kim 597192d13386SJaewan Kim pmsr_capa = kmalloc(sizeof(*pmsr_capa), GFP_KERNEL); 597292d13386SJaewan Kim if (!pmsr_capa) { 597392d13386SJaewan Kim ret = -ENOMEM; 597492d13386SJaewan Kim goto out_free; 597592d13386SJaewan Kim } 5976098abbd4SZhengchao Shao param.pmsr_capa = pmsr_capa; 5977098abbd4SZhengchao Shao 597892d13386SJaewan Kim ret = parse_pmsr_capa(info->attrs[HWSIM_ATTR_PMSR_SUPPORT], pmsr_capa, info); 597992d13386SJaewan Kim if (ret) 598092d13386SJaewan Kim goto out_free; 598192d13386SJaewan Kim } 598292d13386SJaewan Kim 5983f79cbc77SKalle Valo ret = mac80211_hwsim_new_radio(info, ¶m); 598492d13386SJaewan Kim 598592d13386SJaewan Kim out_free: 5986f79cbc77SKalle Valo kfree(hwname); 598792d13386SJaewan Kim kfree(param.pmsr_capa); 5988f79cbc77SKalle Valo return ret; 5989f79cbc77SKalle Valo } 5990f79cbc77SKalle Valo 5991f79cbc77SKalle Valo static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info) 5992f79cbc77SKalle Valo { 5993f79cbc77SKalle Valo struct mac80211_hwsim_data *data; 5994f79cbc77SKalle Valo s64 idx = -1; 5995f79cbc77SKalle Valo const char *hwname = NULL; 5996f79cbc77SKalle Valo 5997f79cbc77SKalle Valo if (info->attrs[HWSIM_ATTR_RADIO_ID]) { 5998f79cbc77SKalle Valo idx = nla_get_u32(info->attrs[HWSIM_ATTR_RADIO_ID]); 5999f79cbc77SKalle Valo } else if (info->attrs[HWSIM_ATTR_RADIO_NAME]) { 6000f79cbc77SKalle Valo hwname = kstrndup((char *)nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME]), 6001f79cbc77SKalle Valo nla_len(info->attrs[HWSIM_ATTR_RADIO_NAME]), 6002f79cbc77SKalle Valo GFP_KERNEL); 6003f79cbc77SKalle Valo if (!hwname) 6004f79cbc77SKalle Valo return -ENOMEM; 6005f79cbc77SKalle Valo } else 6006f79cbc77SKalle Valo return -EINVAL; 6007f79cbc77SKalle Valo 6008f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 6009f79cbc77SKalle Valo list_for_each_entry(data, &hwsim_radios, list) { 6010f79cbc77SKalle Valo if (idx >= 0) { 6011f79cbc77SKalle Valo if (data->idx != idx) 6012f79cbc77SKalle Valo continue; 6013f79cbc77SKalle Valo } else { 6014f79cbc77SKalle Valo if (!hwname || 6015f79cbc77SKalle Valo strcmp(hwname, wiphy_name(data->hw->wiphy))) 6016f79cbc77SKalle Valo continue; 6017f79cbc77SKalle Valo } 6018f79cbc77SKalle Valo 6019f79cbc77SKalle Valo if (!net_eq(wiphy_net(data->hw->wiphy), genl_info_net(info))) 6020f79cbc77SKalle Valo continue; 6021f79cbc77SKalle Valo 6022f79cbc77SKalle Valo list_del(&data->list); 6023f79cbc77SKalle Valo rhashtable_remove_fast(&hwsim_radios_rht, &data->rht, 6024f79cbc77SKalle Valo hwsim_rht_params); 6025f79cbc77SKalle Valo hwsim_radios_generation++; 6026f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 6027f79cbc77SKalle Valo mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy), 6028f79cbc77SKalle Valo info); 6029f79cbc77SKalle Valo kfree(hwname); 6030f79cbc77SKalle Valo return 0; 6031f79cbc77SKalle Valo } 6032f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 6033f79cbc77SKalle Valo 6034f79cbc77SKalle Valo kfree(hwname); 6035f79cbc77SKalle Valo return -ENODEV; 6036f79cbc77SKalle Valo } 6037f79cbc77SKalle Valo 6038f79cbc77SKalle Valo static int hwsim_get_radio_nl(struct sk_buff *msg, struct genl_info *info) 6039f79cbc77SKalle Valo { 6040f79cbc77SKalle Valo struct mac80211_hwsim_data *data; 6041f79cbc77SKalle Valo struct sk_buff *skb; 6042f79cbc77SKalle Valo int idx, res = -ENODEV; 6043f79cbc77SKalle Valo 6044f79cbc77SKalle Valo if (!info->attrs[HWSIM_ATTR_RADIO_ID]) 6045f79cbc77SKalle Valo return -EINVAL; 6046f79cbc77SKalle Valo idx = nla_get_u32(info->attrs[HWSIM_ATTR_RADIO_ID]); 6047f79cbc77SKalle Valo 6048f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 6049f79cbc77SKalle Valo list_for_each_entry(data, &hwsim_radios, list) { 6050f79cbc77SKalle Valo if (data->idx != idx) 6051f79cbc77SKalle Valo continue; 6052f79cbc77SKalle Valo 6053f79cbc77SKalle Valo if (!net_eq(wiphy_net(data->hw->wiphy), genl_info_net(info))) 6054f79cbc77SKalle Valo continue; 6055f79cbc77SKalle Valo 6056f79cbc77SKalle Valo skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); 6057f79cbc77SKalle Valo if (!skb) { 6058f79cbc77SKalle Valo res = -ENOMEM; 6059f79cbc77SKalle Valo goto out_err; 6060f79cbc77SKalle Valo } 6061f79cbc77SKalle Valo 6062f79cbc77SKalle Valo res = mac80211_hwsim_get_radio(skb, data, info->snd_portid, 6063f79cbc77SKalle Valo info->snd_seq, NULL, 0); 6064f79cbc77SKalle Valo if (res < 0) { 6065f79cbc77SKalle Valo nlmsg_free(skb); 6066f79cbc77SKalle Valo goto out_err; 6067f79cbc77SKalle Valo } 6068f79cbc77SKalle Valo 6069f79cbc77SKalle Valo res = genlmsg_reply(skb, info); 6070f79cbc77SKalle Valo break; 6071f79cbc77SKalle Valo } 6072f79cbc77SKalle Valo 6073f79cbc77SKalle Valo out_err: 6074f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 6075f79cbc77SKalle Valo 6076f79cbc77SKalle Valo return res; 6077f79cbc77SKalle Valo } 6078f79cbc77SKalle Valo 6079f79cbc77SKalle Valo static int hwsim_dump_radio_nl(struct sk_buff *skb, 6080f79cbc77SKalle Valo struct netlink_callback *cb) 6081f79cbc77SKalle Valo { 6082f79cbc77SKalle Valo int last_idx = cb->args[0] - 1; 6083f79cbc77SKalle Valo struct mac80211_hwsim_data *data = NULL; 6084f79cbc77SKalle Valo int res = 0; 6085f79cbc77SKalle Valo void *hdr; 6086f79cbc77SKalle Valo 6087f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 6088f79cbc77SKalle Valo cb->seq = hwsim_radios_generation; 6089f79cbc77SKalle Valo 6090f79cbc77SKalle Valo if (last_idx >= hwsim_radio_idx-1) 6091f79cbc77SKalle Valo goto done; 6092f79cbc77SKalle Valo 6093f79cbc77SKalle Valo list_for_each_entry(data, &hwsim_radios, list) { 6094f79cbc77SKalle Valo if (data->idx <= last_idx) 6095f79cbc77SKalle Valo continue; 6096f79cbc77SKalle Valo 6097f79cbc77SKalle Valo if (!net_eq(wiphy_net(data->hw->wiphy), sock_net(skb->sk))) 6098f79cbc77SKalle Valo continue; 6099f79cbc77SKalle Valo 6100f79cbc77SKalle Valo res = mac80211_hwsim_get_radio(skb, data, 6101f79cbc77SKalle Valo NETLINK_CB(cb->skb).portid, 6102f79cbc77SKalle Valo cb->nlh->nlmsg_seq, cb, 6103f79cbc77SKalle Valo NLM_F_MULTI); 6104f79cbc77SKalle Valo if (res < 0) 6105f79cbc77SKalle Valo break; 6106f79cbc77SKalle Valo 6107f79cbc77SKalle Valo last_idx = data->idx; 6108f79cbc77SKalle Valo } 6109f79cbc77SKalle Valo 6110f79cbc77SKalle Valo cb->args[0] = last_idx + 1; 6111f79cbc77SKalle Valo 6112f79cbc77SKalle Valo /* list changed, but no new element sent, set interrupted flag */ 6113f79cbc77SKalle Valo if (skb->len == 0 && cb->prev_seq && cb->seq != cb->prev_seq) { 6114f79cbc77SKalle Valo hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, 6115f79cbc77SKalle Valo cb->nlh->nlmsg_seq, &hwsim_genl_family, 6116f79cbc77SKalle Valo NLM_F_MULTI, HWSIM_CMD_GET_RADIO); 6117f79cbc77SKalle Valo if (hdr) { 6118f79cbc77SKalle Valo genl_dump_check_consistent(cb, hdr); 6119f79cbc77SKalle Valo genlmsg_end(skb, hdr); 6120f79cbc77SKalle Valo } else { 6121f79cbc77SKalle Valo res = -EMSGSIZE; 6122f79cbc77SKalle Valo } 6123f79cbc77SKalle Valo } 6124f79cbc77SKalle Valo 6125f79cbc77SKalle Valo done: 6126f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 6127f79cbc77SKalle Valo return res ?: skb->len; 6128f79cbc77SKalle Valo } 6129f79cbc77SKalle Valo 6130f79cbc77SKalle Valo /* Generic Netlink operations array */ 6131f79cbc77SKalle Valo static const struct genl_small_ops hwsim_ops[] = { 6132f79cbc77SKalle Valo { 6133f79cbc77SKalle Valo .cmd = HWSIM_CMD_REGISTER, 6134f79cbc77SKalle Valo .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 6135f79cbc77SKalle Valo .doit = hwsim_register_received_nl, 6136f79cbc77SKalle Valo .flags = GENL_UNS_ADMIN_PERM, 6137f79cbc77SKalle Valo }, 6138f79cbc77SKalle Valo { 6139f79cbc77SKalle Valo .cmd = HWSIM_CMD_FRAME, 6140f79cbc77SKalle Valo .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 6141f79cbc77SKalle Valo .doit = hwsim_cloned_frame_received_nl, 6142f79cbc77SKalle Valo }, 6143f79cbc77SKalle Valo { 6144f79cbc77SKalle Valo .cmd = HWSIM_CMD_TX_INFO_FRAME, 6145f79cbc77SKalle Valo .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 6146f79cbc77SKalle Valo .doit = hwsim_tx_info_frame_received_nl, 6147f79cbc77SKalle Valo }, 6148f79cbc77SKalle Valo { 6149f79cbc77SKalle Valo .cmd = HWSIM_CMD_NEW_RADIO, 6150f79cbc77SKalle Valo .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 6151f79cbc77SKalle Valo .doit = hwsim_new_radio_nl, 6152f79cbc77SKalle Valo .flags = GENL_UNS_ADMIN_PERM, 6153f79cbc77SKalle Valo }, 6154f79cbc77SKalle Valo { 6155f79cbc77SKalle Valo .cmd = HWSIM_CMD_DEL_RADIO, 6156f79cbc77SKalle Valo .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 6157f79cbc77SKalle Valo .doit = hwsim_del_radio_nl, 6158f79cbc77SKalle Valo .flags = GENL_UNS_ADMIN_PERM, 6159f79cbc77SKalle Valo }, 6160f79cbc77SKalle Valo { 6161f79cbc77SKalle Valo .cmd = HWSIM_CMD_GET_RADIO, 6162f79cbc77SKalle Valo .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 6163f79cbc77SKalle Valo .doit = hwsim_get_radio_nl, 6164f79cbc77SKalle Valo .dumpit = hwsim_dump_radio_nl, 6165f79cbc77SKalle Valo }, 61662af3b2a6SJaewan Kim { 61672af3b2a6SJaewan Kim .cmd = HWSIM_CMD_REPORT_PMSR, 61682af3b2a6SJaewan Kim .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 61692af3b2a6SJaewan Kim .doit = hwsim_pmsr_report_nl, 61702af3b2a6SJaewan Kim }, 6171f79cbc77SKalle Valo }; 6172f79cbc77SKalle Valo 6173f79cbc77SKalle Valo static struct genl_family hwsim_genl_family __ro_after_init = { 6174f79cbc77SKalle Valo .name = "MAC80211_HWSIM", 6175f79cbc77SKalle Valo .version = 1, 6176f79cbc77SKalle Valo .maxattr = HWSIM_ATTR_MAX, 6177f79cbc77SKalle Valo .policy = hwsim_genl_policy, 6178f79cbc77SKalle Valo .netnsok = true, 6179f79cbc77SKalle Valo .module = THIS_MODULE, 6180f79cbc77SKalle Valo .small_ops = hwsim_ops, 6181f79cbc77SKalle Valo .n_small_ops = ARRAY_SIZE(hwsim_ops), 61822af3b2a6SJaewan Kim .resv_start_op = HWSIM_CMD_REPORT_PMSR + 1, // match with __HWSIM_CMD_MAX 6183f79cbc77SKalle Valo .mcgrps = hwsim_mcgrps, 6184f79cbc77SKalle Valo .n_mcgrps = ARRAY_SIZE(hwsim_mcgrps), 6185f79cbc77SKalle Valo }; 6186f79cbc77SKalle Valo 6187f79cbc77SKalle Valo static void remove_user_radios(u32 portid) 6188f79cbc77SKalle Valo { 6189f79cbc77SKalle Valo struct mac80211_hwsim_data *entry, *tmp; 6190f79cbc77SKalle Valo LIST_HEAD(list); 6191f79cbc77SKalle Valo 6192f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 6193f79cbc77SKalle Valo list_for_each_entry_safe(entry, tmp, &hwsim_radios, list) { 6194f79cbc77SKalle Valo if (entry->destroy_on_close && entry->portid == portid) { 6195f79cbc77SKalle Valo list_move(&entry->list, &list); 6196f79cbc77SKalle Valo rhashtable_remove_fast(&hwsim_radios_rht, &entry->rht, 6197f79cbc77SKalle Valo hwsim_rht_params); 6198f79cbc77SKalle Valo hwsim_radios_generation++; 6199f79cbc77SKalle Valo } 6200f79cbc77SKalle Valo } 6201f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 6202f79cbc77SKalle Valo 6203f79cbc77SKalle Valo list_for_each_entry_safe(entry, tmp, &list, list) { 6204f79cbc77SKalle Valo list_del(&entry->list); 6205f79cbc77SKalle Valo mac80211_hwsim_del_radio(entry, wiphy_name(entry->hw->wiphy), 6206f79cbc77SKalle Valo NULL); 6207f79cbc77SKalle Valo } 6208f79cbc77SKalle Valo } 6209f79cbc77SKalle Valo 6210f79cbc77SKalle Valo static int mac80211_hwsim_netlink_notify(struct notifier_block *nb, 6211f79cbc77SKalle Valo unsigned long state, 6212f79cbc77SKalle Valo void *_notify) 6213f79cbc77SKalle Valo { 6214f79cbc77SKalle Valo struct netlink_notify *notify = _notify; 6215f79cbc77SKalle Valo 6216f79cbc77SKalle Valo if (state != NETLINK_URELEASE) 6217f79cbc77SKalle Valo return NOTIFY_DONE; 6218f79cbc77SKalle Valo 6219f79cbc77SKalle Valo remove_user_radios(notify->portid); 6220f79cbc77SKalle Valo 6221f79cbc77SKalle Valo if (notify->portid == hwsim_net_get_wmediumd(notify->net)) { 6222f79cbc77SKalle Valo printk(KERN_INFO "mac80211_hwsim: wmediumd released netlink" 6223f79cbc77SKalle Valo " socket, switching to perfect channel medium\n"); 6224f79cbc77SKalle Valo hwsim_register_wmediumd(notify->net, 0); 6225f79cbc77SKalle Valo } 6226f79cbc77SKalle Valo return NOTIFY_DONE; 6227f79cbc77SKalle Valo 6228f79cbc77SKalle Valo } 6229f79cbc77SKalle Valo 6230f79cbc77SKalle Valo static struct notifier_block hwsim_netlink_notifier = { 6231f79cbc77SKalle Valo .notifier_call = mac80211_hwsim_netlink_notify, 6232f79cbc77SKalle Valo }; 6233f79cbc77SKalle Valo 6234f79cbc77SKalle Valo static int __init hwsim_init_netlink(void) 6235f79cbc77SKalle Valo { 6236f79cbc77SKalle Valo int rc; 6237f79cbc77SKalle Valo 6238f79cbc77SKalle Valo printk(KERN_INFO "mac80211_hwsim: initializing netlink\n"); 6239f79cbc77SKalle Valo 6240f79cbc77SKalle Valo rc = genl_register_family(&hwsim_genl_family); 6241f79cbc77SKalle Valo if (rc) 6242f79cbc77SKalle Valo goto failure; 6243f79cbc77SKalle Valo 6244f79cbc77SKalle Valo rc = netlink_register_notifier(&hwsim_netlink_notifier); 6245f79cbc77SKalle Valo if (rc) { 6246f79cbc77SKalle Valo genl_unregister_family(&hwsim_genl_family); 6247f79cbc77SKalle Valo goto failure; 6248f79cbc77SKalle Valo } 6249f79cbc77SKalle Valo 6250f79cbc77SKalle Valo return 0; 6251f79cbc77SKalle Valo 6252f79cbc77SKalle Valo failure: 6253f79cbc77SKalle Valo pr_debug("mac80211_hwsim: error occurred in %s\n", __func__); 6254f79cbc77SKalle Valo return -EINVAL; 6255f79cbc77SKalle Valo } 6256f79cbc77SKalle Valo 6257f79cbc77SKalle Valo static __net_init int hwsim_init_net(struct net *net) 6258f79cbc77SKalle Valo { 6259f79cbc77SKalle Valo return hwsim_net_set_netgroup(net); 6260f79cbc77SKalle Valo } 6261f79cbc77SKalle Valo 6262f79cbc77SKalle Valo static void __net_exit hwsim_exit_net(struct net *net) 6263f79cbc77SKalle Valo { 6264f79cbc77SKalle Valo struct mac80211_hwsim_data *data, *tmp; 6265f79cbc77SKalle Valo LIST_HEAD(list); 6266f79cbc77SKalle Valo 6267f79cbc77SKalle Valo spin_lock_bh(&hwsim_radio_lock); 6268f79cbc77SKalle Valo list_for_each_entry_safe(data, tmp, &hwsim_radios, list) { 6269f79cbc77SKalle Valo if (!net_eq(wiphy_net(data->hw->wiphy), net)) 6270f79cbc77SKalle Valo continue; 6271f79cbc77SKalle Valo 6272f79cbc77SKalle Valo /* Radios created in init_net are returned to init_net. */ 6273f79cbc77SKalle Valo if (data->netgroup == hwsim_net_get_netgroup(&init_net)) 6274f79cbc77SKalle Valo continue; 6275f79cbc77SKalle Valo 6276f79cbc77SKalle Valo list_move(&data->list, &list); 6277f79cbc77SKalle Valo rhashtable_remove_fast(&hwsim_radios_rht, &data->rht, 6278f79cbc77SKalle Valo hwsim_rht_params); 6279f79cbc77SKalle Valo hwsim_radios_generation++; 6280f79cbc77SKalle Valo } 6281f79cbc77SKalle Valo spin_unlock_bh(&hwsim_radio_lock); 6282f79cbc77SKalle Valo 6283f79cbc77SKalle Valo list_for_each_entry_safe(data, tmp, &list, list) { 6284f79cbc77SKalle Valo list_del(&data->list); 6285f79cbc77SKalle Valo mac80211_hwsim_del_radio(data, 6286f79cbc77SKalle Valo wiphy_name(data->hw->wiphy), 6287f79cbc77SKalle Valo NULL); 6288f79cbc77SKalle Valo } 6289f79cbc77SKalle Valo 6290f79cbc77SKalle Valo ida_free(&hwsim_netgroup_ida, hwsim_net_get_netgroup(net)); 6291f79cbc77SKalle Valo } 6292f79cbc77SKalle Valo 6293f79cbc77SKalle Valo static struct pernet_operations hwsim_net_ops = { 6294f79cbc77SKalle Valo .init = hwsim_init_net, 6295f79cbc77SKalle Valo .exit = hwsim_exit_net, 6296f79cbc77SKalle Valo .id = &hwsim_net_id, 6297f79cbc77SKalle Valo .size = sizeof(struct hwsim_net), 6298f79cbc77SKalle Valo }; 6299f79cbc77SKalle Valo 6300f79cbc77SKalle Valo static void hwsim_exit_netlink(void) 6301f79cbc77SKalle Valo { 6302f79cbc77SKalle Valo /* unregister the notifier */ 6303f79cbc77SKalle Valo netlink_unregister_notifier(&hwsim_netlink_notifier); 6304f79cbc77SKalle Valo /* unregister the family */ 6305f79cbc77SKalle Valo genl_unregister_family(&hwsim_genl_family); 6306f79cbc77SKalle Valo } 6307f79cbc77SKalle Valo 6308f79cbc77SKalle Valo #if IS_REACHABLE(CONFIG_VIRTIO) 6309f79cbc77SKalle Valo static void hwsim_virtio_tx_done(struct virtqueue *vq) 6310f79cbc77SKalle Valo { 6311f79cbc77SKalle Valo unsigned int len; 6312f79cbc77SKalle Valo struct sk_buff *skb; 6313f79cbc77SKalle Valo unsigned long flags; 6314f79cbc77SKalle Valo 6315f79cbc77SKalle Valo spin_lock_irqsave(&hwsim_virtio_lock, flags); 6316f79cbc77SKalle Valo while ((skb = virtqueue_get_buf(vq, &len))) 6317d40de0adSEN-WEI WU dev_kfree_skb_irq(skb); 6318f79cbc77SKalle Valo spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 6319f79cbc77SKalle Valo } 6320f79cbc77SKalle Valo 6321f79cbc77SKalle Valo static int hwsim_virtio_handle_cmd(struct sk_buff *skb) 6322f79cbc77SKalle Valo { 6323f79cbc77SKalle Valo struct nlmsghdr *nlh; 6324f79cbc77SKalle Valo struct genlmsghdr *gnlh; 6325f79cbc77SKalle Valo struct nlattr *tb[HWSIM_ATTR_MAX + 1]; 6326f79cbc77SKalle Valo struct genl_info info = {}; 6327f79cbc77SKalle Valo int err; 6328f79cbc77SKalle Valo 6329f79cbc77SKalle Valo nlh = nlmsg_hdr(skb); 6330f79cbc77SKalle Valo gnlh = nlmsg_data(nlh); 6331f79cbc77SKalle Valo 6332f79cbc77SKalle Valo if (skb->len < nlh->nlmsg_len) 6333f79cbc77SKalle Valo return -EINVAL; 6334f79cbc77SKalle Valo 6335f79cbc77SKalle Valo err = genlmsg_parse(nlh, &hwsim_genl_family, tb, HWSIM_ATTR_MAX, 6336f79cbc77SKalle Valo hwsim_genl_policy, NULL); 6337f79cbc77SKalle Valo if (err) { 6338f79cbc77SKalle Valo pr_err_ratelimited("hwsim: genlmsg_parse returned %d\n", err); 6339f79cbc77SKalle Valo return err; 6340f79cbc77SKalle Valo } 6341f79cbc77SKalle Valo 6342f79cbc77SKalle Valo info.attrs = tb; 6343f79cbc77SKalle Valo 6344f79cbc77SKalle Valo switch (gnlh->cmd) { 6345f79cbc77SKalle Valo case HWSIM_CMD_FRAME: 6346f79cbc77SKalle Valo hwsim_cloned_frame_received_nl(skb, &info); 6347f79cbc77SKalle Valo break; 6348f79cbc77SKalle Valo case HWSIM_CMD_TX_INFO_FRAME: 6349f79cbc77SKalle Valo hwsim_tx_info_frame_received_nl(skb, &info); 6350f79cbc77SKalle Valo break; 63512af3b2a6SJaewan Kim case HWSIM_CMD_REPORT_PMSR: 63522af3b2a6SJaewan Kim hwsim_pmsr_report_nl(skb, &info); 63532af3b2a6SJaewan Kim break; 6354f79cbc77SKalle Valo default: 6355f79cbc77SKalle Valo pr_err_ratelimited("hwsim: invalid cmd: %d\n", gnlh->cmd); 6356f79cbc77SKalle Valo return -EPROTO; 6357f79cbc77SKalle Valo } 6358f79cbc77SKalle Valo return 0; 6359f79cbc77SKalle Valo } 6360f79cbc77SKalle Valo 6361f79cbc77SKalle Valo static void hwsim_virtio_rx_work(struct work_struct *work) 6362f79cbc77SKalle Valo { 6363f79cbc77SKalle Valo struct virtqueue *vq; 6364f79cbc77SKalle Valo unsigned int len; 6365f79cbc77SKalle Valo struct sk_buff *skb; 6366f79cbc77SKalle Valo struct scatterlist sg[1]; 6367f79cbc77SKalle Valo int err; 6368f79cbc77SKalle Valo unsigned long flags; 6369f79cbc77SKalle Valo 6370f79cbc77SKalle Valo spin_lock_irqsave(&hwsim_virtio_lock, flags); 6371f79cbc77SKalle Valo if (!hwsim_virtio_enabled) 6372f79cbc77SKalle Valo goto out_unlock; 6373f79cbc77SKalle Valo 6374f79cbc77SKalle Valo skb = virtqueue_get_buf(hwsim_vqs[HWSIM_VQ_RX], &len); 6375f79cbc77SKalle Valo if (!skb) 6376f79cbc77SKalle Valo goto out_unlock; 6377f79cbc77SKalle Valo spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 6378f79cbc77SKalle Valo 6379f79cbc77SKalle Valo skb->data = skb->head; 6380f79cbc77SKalle Valo skb_reset_tail_pointer(skb); 6381f79cbc77SKalle Valo skb_put(skb, len); 6382f79cbc77SKalle Valo hwsim_virtio_handle_cmd(skb); 6383f79cbc77SKalle Valo 6384f79cbc77SKalle Valo spin_lock_irqsave(&hwsim_virtio_lock, flags); 6385f79cbc77SKalle Valo if (!hwsim_virtio_enabled) { 6386d40de0adSEN-WEI WU dev_kfree_skb_irq(skb); 6387f79cbc77SKalle Valo goto out_unlock; 6388f79cbc77SKalle Valo } 6389f79cbc77SKalle Valo vq = hwsim_vqs[HWSIM_VQ_RX]; 6390f79cbc77SKalle Valo sg_init_one(sg, skb->head, skb_end_offset(skb)); 6391f79cbc77SKalle Valo err = virtqueue_add_inbuf(vq, sg, 1, skb, GFP_ATOMIC); 6392f79cbc77SKalle Valo if (WARN(err, "virtqueue_add_inbuf returned %d\n", err)) 6393d40de0adSEN-WEI WU dev_kfree_skb_irq(skb); 6394f79cbc77SKalle Valo else 6395f79cbc77SKalle Valo virtqueue_kick(vq); 6396f79cbc77SKalle Valo schedule_work(&hwsim_virtio_rx); 6397f79cbc77SKalle Valo 6398f79cbc77SKalle Valo out_unlock: 6399f79cbc77SKalle Valo spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 6400f79cbc77SKalle Valo } 6401f79cbc77SKalle Valo 6402f79cbc77SKalle Valo static void hwsim_virtio_rx_done(struct virtqueue *vq) 6403f79cbc77SKalle Valo { 6404f79cbc77SKalle Valo schedule_work(&hwsim_virtio_rx); 6405f79cbc77SKalle Valo } 6406f79cbc77SKalle Valo 6407f79cbc77SKalle Valo static int init_vqs(struct virtio_device *vdev) 6408f79cbc77SKalle Valo { 6409f79cbc77SKalle Valo vq_callback_t *callbacks[HWSIM_NUM_VQS] = { 6410f79cbc77SKalle Valo [HWSIM_VQ_TX] = hwsim_virtio_tx_done, 6411f79cbc77SKalle Valo [HWSIM_VQ_RX] = hwsim_virtio_rx_done, 6412f79cbc77SKalle Valo }; 6413f79cbc77SKalle Valo const char *names[HWSIM_NUM_VQS] = { 6414f79cbc77SKalle Valo [HWSIM_VQ_TX] = "tx", 6415f79cbc77SKalle Valo [HWSIM_VQ_RX] = "rx", 6416f79cbc77SKalle Valo }; 6417f79cbc77SKalle Valo 6418f79cbc77SKalle Valo return virtio_find_vqs(vdev, HWSIM_NUM_VQS, 6419f79cbc77SKalle Valo hwsim_vqs, callbacks, names, NULL); 6420f79cbc77SKalle Valo } 6421f79cbc77SKalle Valo 6422f79cbc77SKalle Valo static int fill_vq(struct virtqueue *vq) 6423f79cbc77SKalle Valo { 6424f79cbc77SKalle Valo int i, err; 6425f79cbc77SKalle Valo struct sk_buff *skb; 6426f79cbc77SKalle Valo struct scatterlist sg[1]; 6427f79cbc77SKalle Valo 6428f79cbc77SKalle Valo for (i = 0; i < virtqueue_get_vring_size(vq); i++) { 6429f79cbc77SKalle Valo skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 6430f79cbc77SKalle Valo if (!skb) 6431f79cbc77SKalle Valo return -ENOMEM; 6432f79cbc77SKalle Valo 6433f79cbc77SKalle Valo sg_init_one(sg, skb->head, skb_end_offset(skb)); 6434f79cbc77SKalle Valo err = virtqueue_add_inbuf(vq, sg, 1, skb, GFP_KERNEL); 6435f79cbc77SKalle Valo if (err) { 6436f79cbc77SKalle Valo nlmsg_free(skb); 6437f79cbc77SKalle Valo return err; 6438f79cbc77SKalle Valo } 6439f79cbc77SKalle Valo } 6440f79cbc77SKalle Valo virtqueue_kick(vq); 6441f79cbc77SKalle Valo return 0; 6442f79cbc77SKalle Valo } 6443f79cbc77SKalle Valo 6444f79cbc77SKalle Valo static void remove_vqs(struct virtio_device *vdev) 6445f79cbc77SKalle Valo { 6446f79cbc77SKalle Valo int i; 6447f79cbc77SKalle Valo 6448f79cbc77SKalle Valo virtio_reset_device(vdev); 6449f79cbc77SKalle Valo 6450f79cbc77SKalle Valo for (i = 0; i < ARRAY_SIZE(hwsim_vqs); i++) { 6451f79cbc77SKalle Valo struct virtqueue *vq = hwsim_vqs[i]; 6452f79cbc77SKalle Valo struct sk_buff *skb; 6453f79cbc77SKalle Valo 6454f79cbc77SKalle Valo while ((skb = virtqueue_detach_unused_buf(vq))) 6455f79cbc77SKalle Valo nlmsg_free(skb); 6456f79cbc77SKalle Valo } 6457f79cbc77SKalle Valo 6458f79cbc77SKalle Valo vdev->config->del_vqs(vdev); 6459f79cbc77SKalle Valo } 6460f79cbc77SKalle Valo 6461f79cbc77SKalle Valo static int hwsim_virtio_probe(struct virtio_device *vdev) 6462f79cbc77SKalle Valo { 6463f79cbc77SKalle Valo int err; 6464f79cbc77SKalle Valo unsigned long flags; 6465f79cbc77SKalle Valo 6466f79cbc77SKalle Valo spin_lock_irqsave(&hwsim_virtio_lock, flags); 6467f79cbc77SKalle Valo if (hwsim_virtio_enabled) { 6468f79cbc77SKalle Valo spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 6469f79cbc77SKalle Valo return -EEXIST; 6470f79cbc77SKalle Valo } 6471f79cbc77SKalle Valo spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 6472f79cbc77SKalle Valo 6473f79cbc77SKalle Valo err = init_vqs(vdev); 6474f79cbc77SKalle Valo if (err) 6475f79cbc77SKalle Valo return err; 6476f79cbc77SKalle Valo 6477f79cbc77SKalle Valo virtio_device_ready(vdev); 6478f79cbc77SKalle Valo 6479f79cbc77SKalle Valo err = fill_vq(hwsim_vqs[HWSIM_VQ_RX]); 6480f79cbc77SKalle Valo if (err) 6481f79cbc77SKalle Valo goto out_remove; 6482f79cbc77SKalle Valo 6483f79cbc77SKalle Valo spin_lock_irqsave(&hwsim_virtio_lock, flags); 6484f79cbc77SKalle Valo hwsim_virtio_enabled = true; 6485f79cbc77SKalle Valo spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 6486f79cbc77SKalle Valo 6487f79cbc77SKalle Valo schedule_work(&hwsim_virtio_rx); 6488f79cbc77SKalle Valo return 0; 6489f79cbc77SKalle Valo 6490f79cbc77SKalle Valo out_remove: 6491f79cbc77SKalle Valo remove_vqs(vdev); 6492f79cbc77SKalle Valo return err; 6493f79cbc77SKalle Valo } 6494f79cbc77SKalle Valo 6495f79cbc77SKalle Valo static void hwsim_virtio_remove(struct virtio_device *vdev) 6496f79cbc77SKalle Valo { 6497f79cbc77SKalle Valo hwsim_virtio_enabled = false; 6498f79cbc77SKalle Valo 6499f79cbc77SKalle Valo cancel_work_sync(&hwsim_virtio_rx); 6500f79cbc77SKalle Valo 6501f79cbc77SKalle Valo remove_vqs(vdev); 6502f79cbc77SKalle Valo } 6503f79cbc77SKalle Valo 6504f79cbc77SKalle Valo /* MAC80211_HWSIM virtio device id table */ 6505f79cbc77SKalle Valo static const struct virtio_device_id id_table[] = { 6506f79cbc77SKalle Valo { VIRTIO_ID_MAC80211_HWSIM, VIRTIO_DEV_ANY_ID }, 6507f79cbc77SKalle Valo { 0 } 6508f79cbc77SKalle Valo }; 6509f79cbc77SKalle Valo MODULE_DEVICE_TABLE(virtio, id_table); 6510f79cbc77SKalle Valo 6511f79cbc77SKalle Valo static struct virtio_driver virtio_hwsim = { 6512f79cbc77SKalle Valo .driver.name = KBUILD_MODNAME, 6513f79cbc77SKalle Valo .driver.owner = THIS_MODULE, 6514f79cbc77SKalle Valo .id_table = id_table, 6515f79cbc77SKalle Valo .probe = hwsim_virtio_probe, 6516f79cbc77SKalle Valo .remove = hwsim_virtio_remove, 6517f79cbc77SKalle Valo }; 6518f79cbc77SKalle Valo 6519f79cbc77SKalle Valo static int hwsim_register_virtio_driver(void) 6520f79cbc77SKalle Valo { 6521f79cbc77SKalle Valo return register_virtio_driver(&virtio_hwsim); 6522f79cbc77SKalle Valo } 6523f79cbc77SKalle Valo 6524f79cbc77SKalle Valo static void hwsim_unregister_virtio_driver(void) 6525f79cbc77SKalle Valo { 6526f79cbc77SKalle Valo unregister_virtio_driver(&virtio_hwsim); 6527f79cbc77SKalle Valo } 6528f79cbc77SKalle Valo #else 6529f79cbc77SKalle Valo static inline int hwsim_register_virtio_driver(void) 6530f79cbc77SKalle Valo { 6531f79cbc77SKalle Valo return 0; 6532f79cbc77SKalle Valo } 6533f79cbc77SKalle Valo 6534f79cbc77SKalle Valo static inline void hwsim_unregister_virtio_driver(void) 6535f79cbc77SKalle Valo { 6536f79cbc77SKalle Valo } 6537f79cbc77SKalle Valo #endif 6538f79cbc77SKalle Valo 6539f79cbc77SKalle Valo static int __init init_mac80211_hwsim(void) 6540f79cbc77SKalle Valo { 6541f79cbc77SKalle Valo int i, err; 6542f79cbc77SKalle Valo 6543f79cbc77SKalle Valo if (radios < 0 || radios > 100) 6544f79cbc77SKalle Valo return -EINVAL; 6545f79cbc77SKalle Valo 6546f79cbc77SKalle Valo if (channels < 1) 6547f79cbc77SKalle Valo return -EINVAL; 6548f79cbc77SKalle Valo 6549f79cbc77SKalle Valo err = rhashtable_init(&hwsim_radios_rht, &hwsim_rht_params); 6550f79cbc77SKalle Valo if (err) 6551f79cbc77SKalle Valo return err; 6552f79cbc77SKalle Valo 6553f79cbc77SKalle Valo err = register_pernet_device(&hwsim_net_ops); 6554f79cbc77SKalle Valo if (err) 6555f79cbc77SKalle Valo goto out_free_rht; 6556f79cbc77SKalle Valo 6557f79cbc77SKalle Valo err = platform_driver_register(&mac80211_hwsim_driver); 6558f79cbc77SKalle Valo if (err) 6559f79cbc77SKalle Valo goto out_unregister_pernet; 6560f79cbc77SKalle Valo 6561f79cbc77SKalle Valo err = hwsim_init_netlink(); 6562f79cbc77SKalle Valo if (err) 6563f79cbc77SKalle Valo goto out_unregister_driver; 6564f79cbc77SKalle Valo 6565f79cbc77SKalle Valo err = hwsim_register_virtio_driver(); 6566f79cbc77SKalle Valo if (err) 6567f79cbc77SKalle Valo goto out_exit_netlink; 6568f79cbc77SKalle Valo 6569556eb8b7SLinus Torvalds hwsim_class = class_create("mac80211_hwsim"); 6570f79cbc77SKalle Valo if (IS_ERR(hwsim_class)) { 6571f79cbc77SKalle Valo err = PTR_ERR(hwsim_class); 6572f79cbc77SKalle Valo goto out_exit_virtio; 6573f79cbc77SKalle Valo } 6574f79cbc77SKalle Valo 6575f79cbc77SKalle Valo hwsim_init_s1g_channels(hwsim_channels_s1g); 6576f79cbc77SKalle Valo 6577f79cbc77SKalle Valo for (i = 0; i < radios; i++) { 6578f79cbc77SKalle Valo struct hwsim_new_radio_params param = { 0 }; 6579f79cbc77SKalle Valo 6580f79cbc77SKalle Valo param.channels = channels; 6581f79cbc77SKalle Valo 6582f79cbc77SKalle Valo switch (regtest) { 6583f79cbc77SKalle Valo case HWSIM_REGTEST_DIFF_COUNTRY: 6584f79cbc77SKalle Valo if (i < ARRAY_SIZE(hwsim_alpha2s)) 6585f79cbc77SKalle Valo param.reg_alpha2 = hwsim_alpha2s[i]; 6586f79cbc77SKalle Valo break; 6587f79cbc77SKalle Valo case HWSIM_REGTEST_DRIVER_REG_FOLLOW: 6588f79cbc77SKalle Valo if (!i) 6589f79cbc77SKalle Valo param.reg_alpha2 = hwsim_alpha2s[0]; 6590f79cbc77SKalle Valo break; 6591f79cbc77SKalle Valo case HWSIM_REGTEST_STRICT_ALL: 6592f79cbc77SKalle Valo param.reg_strict = true; 6593f79cbc77SKalle Valo fallthrough; 6594f79cbc77SKalle Valo case HWSIM_REGTEST_DRIVER_REG_ALL: 6595f79cbc77SKalle Valo param.reg_alpha2 = hwsim_alpha2s[0]; 6596f79cbc77SKalle Valo break; 6597f79cbc77SKalle Valo case HWSIM_REGTEST_WORLD_ROAM: 6598f79cbc77SKalle Valo if (i == 0) 6599f79cbc77SKalle Valo param.regd = &hwsim_world_regdom_custom_01; 6600f79cbc77SKalle Valo break; 6601f79cbc77SKalle Valo case HWSIM_REGTEST_CUSTOM_WORLD: 6602f79cbc77SKalle Valo param.regd = &hwsim_world_regdom_custom_01; 6603f79cbc77SKalle Valo break; 6604f79cbc77SKalle Valo case HWSIM_REGTEST_CUSTOM_WORLD_2: 6605f79cbc77SKalle Valo if (i == 0) 6606f79cbc77SKalle Valo param.regd = &hwsim_world_regdom_custom_01; 6607f79cbc77SKalle Valo else if (i == 1) 6608f79cbc77SKalle Valo param.regd = &hwsim_world_regdom_custom_02; 6609f79cbc77SKalle Valo break; 6610f79cbc77SKalle Valo case HWSIM_REGTEST_STRICT_FOLLOW: 6611f79cbc77SKalle Valo if (i == 0) { 6612f79cbc77SKalle Valo param.reg_strict = true; 6613f79cbc77SKalle Valo param.reg_alpha2 = hwsim_alpha2s[0]; 6614f79cbc77SKalle Valo } 6615f79cbc77SKalle Valo break; 6616f79cbc77SKalle Valo case HWSIM_REGTEST_STRICT_AND_DRIVER_REG: 6617f79cbc77SKalle Valo if (i == 0) { 6618f79cbc77SKalle Valo param.reg_strict = true; 6619f79cbc77SKalle Valo param.reg_alpha2 = hwsim_alpha2s[0]; 6620f79cbc77SKalle Valo } else if (i == 1) { 6621f79cbc77SKalle Valo param.reg_alpha2 = hwsim_alpha2s[1]; 6622f79cbc77SKalle Valo } 6623f79cbc77SKalle Valo break; 6624f79cbc77SKalle Valo case HWSIM_REGTEST_ALL: 6625f79cbc77SKalle Valo switch (i) { 6626f79cbc77SKalle Valo case 0: 6627f79cbc77SKalle Valo param.regd = &hwsim_world_regdom_custom_01; 6628f79cbc77SKalle Valo break; 6629f79cbc77SKalle Valo case 1: 6630f79cbc77SKalle Valo param.regd = &hwsim_world_regdom_custom_02; 6631f79cbc77SKalle Valo break; 6632f79cbc77SKalle Valo case 2: 6633f79cbc77SKalle Valo param.reg_alpha2 = hwsim_alpha2s[0]; 6634f79cbc77SKalle Valo break; 6635f79cbc77SKalle Valo case 3: 6636f79cbc77SKalle Valo param.reg_alpha2 = hwsim_alpha2s[1]; 6637f79cbc77SKalle Valo break; 6638f79cbc77SKalle Valo case 4: 6639f79cbc77SKalle Valo param.reg_strict = true; 6640f79cbc77SKalle Valo param.reg_alpha2 = hwsim_alpha2s[2]; 6641f79cbc77SKalle Valo break; 6642f79cbc77SKalle Valo } 6643f79cbc77SKalle Valo break; 6644f79cbc77SKalle Valo default: 6645f79cbc77SKalle Valo break; 6646f79cbc77SKalle Valo } 6647f79cbc77SKalle Valo 6648f79cbc77SKalle Valo param.p2p_device = support_p2p_device; 6649f79cbc77SKalle Valo param.mlo = mlo; 6650f79cbc77SKalle Valo param.use_chanctx = channels > 1 || mlo; 6651f79cbc77SKalle Valo param.iftypes = HWSIM_IFTYPE_SUPPORT_MASK; 6652f79cbc77SKalle Valo if (param.p2p_device) 6653f79cbc77SKalle Valo param.iftypes |= BIT(NL80211_IFTYPE_P2P_DEVICE); 6654f79cbc77SKalle Valo 6655f79cbc77SKalle Valo err = mac80211_hwsim_new_radio(NULL, ¶m); 6656f79cbc77SKalle Valo if (err < 0) 6657f79cbc77SKalle Valo goto out_free_radios; 6658f79cbc77SKalle Valo } 6659f79cbc77SKalle Valo 6660f79cbc77SKalle Valo hwsim_mon = alloc_netdev(0, "hwsim%d", NET_NAME_UNKNOWN, 6661f79cbc77SKalle Valo hwsim_mon_setup); 6662f79cbc77SKalle Valo if (hwsim_mon == NULL) { 6663f79cbc77SKalle Valo err = -ENOMEM; 6664f79cbc77SKalle Valo goto out_free_radios; 6665f79cbc77SKalle Valo } 6666f79cbc77SKalle Valo 6667f79cbc77SKalle Valo rtnl_lock(); 6668f79cbc77SKalle Valo err = dev_alloc_name(hwsim_mon, hwsim_mon->name); 6669f79cbc77SKalle Valo if (err < 0) { 6670f79cbc77SKalle Valo rtnl_unlock(); 6671f79cbc77SKalle Valo goto out_free_mon; 6672f79cbc77SKalle Valo } 6673f79cbc77SKalle Valo 6674f79cbc77SKalle Valo err = register_netdevice(hwsim_mon); 6675f79cbc77SKalle Valo if (err < 0) { 6676f79cbc77SKalle Valo rtnl_unlock(); 6677f79cbc77SKalle Valo goto out_free_mon; 6678f79cbc77SKalle Valo } 6679f79cbc77SKalle Valo rtnl_unlock(); 6680f79cbc77SKalle Valo 6681f79cbc77SKalle Valo return 0; 6682f79cbc77SKalle Valo 6683f79cbc77SKalle Valo out_free_mon: 6684f79cbc77SKalle Valo free_netdev(hwsim_mon); 6685f79cbc77SKalle Valo out_free_radios: 6686f79cbc77SKalle Valo mac80211_hwsim_free(); 6687f79cbc77SKalle Valo out_exit_virtio: 6688f79cbc77SKalle Valo hwsim_unregister_virtio_driver(); 6689f79cbc77SKalle Valo out_exit_netlink: 6690f79cbc77SKalle Valo hwsim_exit_netlink(); 6691f79cbc77SKalle Valo out_unregister_driver: 6692f79cbc77SKalle Valo platform_driver_unregister(&mac80211_hwsim_driver); 6693f79cbc77SKalle Valo out_unregister_pernet: 6694f79cbc77SKalle Valo unregister_pernet_device(&hwsim_net_ops); 6695f79cbc77SKalle Valo out_free_rht: 6696f79cbc77SKalle Valo rhashtable_destroy(&hwsim_radios_rht); 6697f79cbc77SKalle Valo return err; 6698f79cbc77SKalle Valo } 6699f79cbc77SKalle Valo module_init(init_mac80211_hwsim); 6700f79cbc77SKalle Valo 6701f79cbc77SKalle Valo static void __exit exit_mac80211_hwsim(void) 6702f79cbc77SKalle Valo { 6703f79cbc77SKalle Valo pr_debug("mac80211_hwsim: unregister radios\n"); 6704f79cbc77SKalle Valo 6705f79cbc77SKalle Valo hwsim_unregister_virtio_driver(); 6706f79cbc77SKalle Valo hwsim_exit_netlink(); 6707f79cbc77SKalle Valo 6708f79cbc77SKalle Valo mac80211_hwsim_free(); 6709f79cbc77SKalle Valo 6710f79cbc77SKalle Valo rhashtable_destroy(&hwsim_radios_rht); 6711f79cbc77SKalle Valo unregister_netdev(hwsim_mon); 6712f79cbc77SKalle Valo platform_driver_unregister(&mac80211_hwsim_driver); 6713f79cbc77SKalle Valo unregister_pernet_device(&hwsim_net_ops); 6714f79cbc77SKalle Valo } 6715f79cbc77SKalle Valo module_exit(exit_mac80211_hwsim); 6716