162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * mac80211_hwsim - software simulator of 802.11 radio(s) for mac80211 462306a36Sopenharmony_ci * Copyright (c) 2008, Jouni Malinen <j@w1.fi> 562306a36Sopenharmony_ci * Copyright (c) 2011, Javier Lopez <jlopex@gmail.com> 662306a36Sopenharmony_ci * Copyright (c) 2016 - 2017 Intel Deutschland GmbH 762306a36Sopenharmony_ci * Copyright (C) 2018 - 2023 Intel Corporation 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/* 1162306a36Sopenharmony_ci * TODO: 1262306a36Sopenharmony_ci * - Add TSF sync and fix IBSS beacon transmission by adding 1362306a36Sopenharmony_ci * competition for "air time" at TBTT 1462306a36Sopenharmony_ci * - RX filtering based on filter configuration (data->rx_filter) 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/list.h> 1862306a36Sopenharmony_ci#include <linux/slab.h> 1962306a36Sopenharmony_ci#include <linux/spinlock.h> 2062306a36Sopenharmony_ci#include <net/dst.h> 2162306a36Sopenharmony_ci#include <net/xfrm.h> 2262306a36Sopenharmony_ci#include <net/mac80211.h> 2362306a36Sopenharmony_ci#include <net/ieee80211_radiotap.h> 2462306a36Sopenharmony_ci#include <linux/if_arp.h> 2562306a36Sopenharmony_ci#include <linux/rtnetlink.h> 2662306a36Sopenharmony_ci#include <linux/etherdevice.h> 2762306a36Sopenharmony_ci#include <linux/platform_device.h> 2862306a36Sopenharmony_ci#include <linux/debugfs.h> 2962306a36Sopenharmony_ci#include <linux/module.h> 3062306a36Sopenharmony_ci#include <linux/ktime.h> 3162306a36Sopenharmony_ci#include <net/genetlink.h> 3262306a36Sopenharmony_ci#include <net/net_namespace.h> 3362306a36Sopenharmony_ci#include <net/netns/generic.h> 3462306a36Sopenharmony_ci#include <linux/rhashtable.h> 3562306a36Sopenharmony_ci#include <linux/nospec.h> 3662306a36Sopenharmony_ci#include <linux/virtio.h> 3762306a36Sopenharmony_ci#include <linux/virtio_ids.h> 3862306a36Sopenharmony_ci#include <linux/virtio_config.h> 3962306a36Sopenharmony_ci#include "mac80211_hwsim.h" 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define WARN_QUEUE 100 4262306a36Sopenharmony_ci#define MAX_QUEUE 200 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ciMODULE_AUTHOR("Jouni Malinen"); 4562306a36Sopenharmony_ciMODULE_DESCRIPTION("Software simulator of 802.11 radio(s) for mac80211"); 4662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic int radios = 2; 4962306a36Sopenharmony_cimodule_param(radios, int, 0444); 5062306a36Sopenharmony_ciMODULE_PARM_DESC(radios, "Number of simulated radios"); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic int channels = 1; 5362306a36Sopenharmony_cimodule_param(channels, int, 0444); 5462306a36Sopenharmony_ciMODULE_PARM_DESC(channels, "Number of concurrent channels"); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic bool paged_rx = false; 5762306a36Sopenharmony_cimodule_param(paged_rx, bool, 0644); 5862306a36Sopenharmony_ciMODULE_PARM_DESC(paged_rx, "Use paged SKBs for RX instead of linear ones"); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic bool rctbl = false; 6162306a36Sopenharmony_cimodule_param(rctbl, bool, 0444); 6262306a36Sopenharmony_ciMODULE_PARM_DESC(rctbl, "Handle rate control table"); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic bool support_p2p_device = true; 6562306a36Sopenharmony_cimodule_param(support_p2p_device, bool, 0444); 6662306a36Sopenharmony_ciMODULE_PARM_DESC(support_p2p_device, "Support P2P-Device interface type"); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic bool mlo; 6962306a36Sopenharmony_cimodule_param(mlo, bool, 0444); 7062306a36Sopenharmony_ciMODULE_PARM_DESC(mlo, "Support MLO"); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/** 7362306a36Sopenharmony_ci * enum hwsim_regtest - the type of regulatory tests we offer 7462306a36Sopenharmony_ci * 7562306a36Sopenharmony_ci * These are the different values you can use for the regtest 7662306a36Sopenharmony_ci * module parameter. This is useful to help test world roaming 7762306a36Sopenharmony_ci * and the driver regulatory_hint() call and combinations of these. 7862306a36Sopenharmony_ci * If you want to do specific alpha2 regulatory domain tests simply 7962306a36Sopenharmony_ci * use the userspace regulatory request as that will be respected as 8062306a36Sopenharmony_ci * well without the need of this module parameter. This is designed 8162306a36Sopenharmony_ci * only for testing the driver regulatory request, world roaming 8262306a36Sopenharmony_ci * and all possible combinations. 8362306a36Sopenharmony_ci * 8462306a36Sopenharmony_ci * @HWSIM_REGTEST_DISABLED: No regulatory tests are performed, 8562306a36Sopenharmony_ci * this is the default value. 8662306a36Sopenharmony_ci * @HWSIM_REGTEST_DRIVER_REG_FOLLOW: Used for testing the driver regulatory 8762306a36Sopenharmony_ci * hint, only one driver regulatory hint will be sent as such the 8862306a36Sopenharmony_ci * secondary radios are expected to follow. 8962306a36Sopenharmony_ci * @HWSIM_REGTEST_DRIVER_REG_ALL: Used for testing the driver regulatory 9062306a36Sopenharmony_ci * request with all radios reporting the same regulatory domain. 9162306a36Sopenharmony_ci * @HWSIM_REGTEST_DIFF_COUNTRY: Used for testing the drivers calling 9262306a36Sopenharmony_ci * different regulatory domains requests. Expected behaviour is for 9362306a36Sopenharmony_ci * an intersection to occur but each device will still use their 9462306a36Sopenharmony_ci * respective regulatory requested domains. Subsequent radios will 9562306a36Sopenharmony_ci * use the resulting intersection. 9662306a36Sopenharmony_ci * @HWSIM_REGTEST_WORLD_ROAM: Used for testing the world roaming. We accomplish 9762306a36Sopenharmony_ci * this by using a custom beacon-capable regulatory domain for the first 9862306a36Sopenharmony_ci * radio. All other device world roam. 9962306a36Sopenharmony_ci * @HWSIM_REGTEST_CUSTOM_WORLD: Used for testing the custom world regulatory 10062306a36Sopenharmony_ci * domain requests. All radios will adhere to this custom world regulatory 10162306a36Sopenharmony_ci * domain. 10262306a36Sopenharmony_ci * @HWSIM_REGTEST_CUSTOM_WORLD_2: Used for testing 2 custom world regulatory 10362306a36Sopenharmony_ci * domain requests. The first radio will adhere to the first custom world 10462306a36Sopenharmony_ci * regulatory domain, the second one to the second custom world regulatory 10562306a36Sopenharmony_ci * domain. All other devices will world roam. 10662306a36Sopenharmony_ci * @HWSIM_REGTEST_STRICT_FOLLOW: Used for testing strict regulatory domain 10762306a36Sopenharmony_ci * settings, only the first radio will send a regulatory domain request 10862306a36Sopenharmony_ci * and use strict settings. The rest of the radios are expected to follow. 10962306a36Sopenharmony_ci * @HWSIM_REGTEST_STRICT_ALL: Used for testing strict regulatory domain 11062306a36Sopenharmony_ci * settings. All radios will adhere to this. 11162306a36Sopenharmony_ci * @HWSIM_REGTEST_STRICT_AND_DRIVER_REG: Used for testing strict regulatory 11262306a36Sopenharmony_ci * domain settings, combined with secondary driver regulatory domain 11362306a36Sopenharmony_ci * settings. The first radio will get a strict regulatory domain setting 11462306a36Sopenharmony_ci * using the first driver regulatory request and the second radio will use 11562306a36Sopenharmony_ci * non-strict settings using the second driver regulatory request. All 11662306a36Sopenharmony_ci * other devices should follow the intersection created between the 11762306a36Sopenharmony_ci * first two. 11862306a36Sopenharmony_ci * @HWSIM_REGTEST_ALL: Used for testing every possible mix. You will need 11962306a36Sopenharmony_ci * at least 6 radios for a complete test. We will test in this order: 12062306a36Sopenharmony_ci * 1 - driver custom world regulatory domain 12162306a36Sopenharmony_ci * 2 - second custom world regulatory domain 12262306a36Sopenharmony_ci * 3 - first driver regulatory domain request 12362306a36Sopenharmony_ci * 4 - second driver regulatory domain request 12462306a36Sopenharmony_ci * 5 - strict regulatory domain settings using the third driver regulatory 12562306a36Sopenharmony_ci * domain request 12662306a36Sopenharmony_ci * 6 and on - should follow the intersection of the 3rd, 4rth and 5th radio 12762306a36Sopenharmony_ci * regulatory requests. 12862306a36Sopenharmony_ci */ 12962306a36Sopenharmony_cienum hwsim_regtest { 13062306a36Sopenharmony_ci HWSIM_REGTEST_DISABLED = 0, 13162306a36Sopenharmony_ci HWSIM_REGTEST_DRIVER_REG_FOLLOW = 1, 13262306a36Sopenharmony_ci HWSIM_REGTEST_DRIVER_REG_ALL = 2, 13362306a36Sopenharmony_ci HWSIM_REGTEST_DIFF_COUNTRY = 3, 13462306a36Sopenharmony_ci HWSIM_REGTEST_WORLD_ROAM = 4, 13562306a36Sopenharmony_ci HWSIM_REGTEST_CUSTOM_WORLD = 5, 13662306a36Sopenharmony_ci HWSIM_REGTEST_CUSTOM_WORLD_2 = 6, 13762306a36Sopenharmony_ci HWSIM_REGTEST_STRICT_FOLLOW = 7, 13862306a36Sopenharmony_ci HWSIM_REGTEST_STRICT_ALL = 8, 13962306a36Sopenharmony_ci HWSIM_REGTEST_STRICT_AND_DRIVER_REG = 9, 14062306a36Sopenharmony_ci HWSIM_REGTEST_ALL = 10, 14162306a36Sopenharmony_ci}; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/* Set to one of the HWSIM_REGTEST_* values above */ 14462306a36Sopenharmony_cistatic int regtest = HWSIM_REGTEST_DISABLED; 14562306a36Sopenharmony_cimodule_param(regtest, int, 0444); 14662306a36Sopenharmony_ciMODULE_PARM_DESC(regtest, "The type of regulatory test we want to run"); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic const char *hwsim_alpha2s[] = { 14962306a36Sopenharmony_ci "FI", 15062306a36Sopenharmony_ci "AL", 15162306a36Sopenharmony_ci "US", 15262306a36Sopenharmony_ci "DE", 15362306a36Sopenharmony_ci "JP", 15462306a36Sopenharmony_ci "AL", 15562306a36Sopenharmony_ci}; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic const struct ieee80211_regdomain hwsim_world_regdom_custom_01 = { 15862306a36Sopenharmony_ci .n_reg_rules = 5, 15962306a36Sopenharmony_ci .alpha2 = "99", 16062306a36Sopenharmony_ci .reg_rules = { 16162306a36Sopenharmony_ci REG_RULE(2412-10, 2462+10, 40, 0, 20, 0), 16262306a36Sopenharmony_ci REG_RULE(2484-10, 2484+10, 40, 0, 20, 0), 16362306a36Sopenharmony_ci REG_RULE(5150-10, 5240+10, 40, 0, 30, 0), 16462306a36Sopenharmony_ci REG_RULE(5745-10, 5825+10, 40, 0, 30, 0), 16562306a36Sopenharmony_ci REG_RULE(5855-10, 5925+10, 40, 0, 33, 0), 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci}; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic const struct ieee80211_regdomain hwsim_world_regdom_custom_02 = { 17062306a36Sopenharmony_ci .n_reg_rules = 3, 17162306a36Sopenharmony_ci .alpha2 = "99", 17262306a36Sopenharmony_ci .reg_rules = { 17362306a36Sopenharmony_ci REG_RULE(2412-10, 2462+10, 40, 0, 20, 0), 17462306a36Sopenharmony_ci REG_RULE(5725-10, 5850+10, 40, 0, 30, 17562306a36Sopenharmony_ci NL80211_RRF_NO_IR), 17662306a36Sopenharmony_ci REG_RULE(5855-10, 5925+10, 40, 0, 33, 0), 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci}; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic const struct ieee80211_regdomain hwsim_world_regdom_custom_03 = { 18162306a36Sopenharmony_ci .n_reg_rules = 6, 18262306a36Sopenharmony_ci .alpha2 = "99", 18362306a36Sopenharmony_ci .reg_rules = { 18462306a36Sopenharmony_ci REG_RULE(2412 - 10, 2462 + 10, 40, 0, 20, 0), 18562306a36Sopenharmony_ci REG_RULE(2484 - 10, 2484 + 10, 40, 0, 20, 0), 18662306a36Sopenharmony_ci REG_RULE(5150 - 10, 5240 + 10, 40, 0, 30, 0), 18762306a36Sopenharmony_ci REG_RULE(5745 - 10, 5825 + 10, 40, 0, 30, 0), 18862306a36Sopenharmony_ci REG_RULE(5855 - 10, 5925 + 10, 40, 0, 33, 0), 18962306a36Sopenharmony_ci REG_RULE(5955 - 10, 7125 + 10, 320, 0, 33, 0), 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci}; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic const struct ieee80211_regdomain *hwsim_world_regdom_custom[] = { 19462306a36Sopenharmony_ci &hwsim_world_regdom_custom_01, 19562306a36Sopenharmony_ci &hwsim_world_regdom_custom_02, 19662306a36Sopenharmony_ci &hwsim_world_regdom_custom_03, 19762306a36Sopenharmony_ci}; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistruct hwsim_vif_priv { 20062306a36Sopenharmony_ci u32 magic; 20162306a36Sopenharmony_ci u8 bssid[ETH_ALEN]; 20262306a36Sopenharmony_ci bool assoc; 20362306a36Sopenharmony_ci bool bcn_en; 20462306a36Sopenharmony_ci u16 aid; 20562306a36Sopenharmony_ci}; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci#define HWSIM_VIF_MAGIC 0x69537748 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic inline void hwsim_check_magic(struct ieee80211_vif *vif) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci struct hwsim_vif_priv *vp = (void *)vif->drv_priv; 21262306a36Sopenharmony_ci WARN(vp->magic != HWSIM_VIF_MAGIC, 21362306a36Sopenharmony_ci "Invalid VIF (%p) magic %#x, %pM, %d/%d\n", 21462306a36Sopenharmony_ci vif, vp->magic, vif->addr, vif->type, vif->p2p); 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic inline void hwsim_set_magic(struct ieee80211_vif *vif) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci struct hwsim_vif_priv *vp = (void *)vif->drv_priv; 22062306a36Sopenharmony_ci vp->magic = HWSIM_VIF_MAGIC; 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic inline void hwsim_clear_magic(struct ieee80211_vif *vif) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci struct hwsim_vif_priv *vp = (void *)vif->drv_priv; 22662306a36Sopenharmony_ci vp->magic = 0; 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistruct hwsim_sta_priv { 23062306a36Sopenharmony_ci u32 magic; 23162306a36Sopenharmony_ci unsigned int last_link; 23262306a36Sopenharmony_ci u16 active_links_rx; 23362306a36Sopenharmony_ci}; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci#define HWSIM_STA_MAGIC 0x6d537749 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic inline void hwsim_check_sta_magic(struct ieee80211_sta *sta) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci struct hwsim_sta_priv *sp = (void *)sta->drv_priv; 24062306a36Sopenharmony_ci WARN_ON(sp->magic != HWSIM_STA_MAGIC); 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic inline void hwsim_set_sta_magic(struct ieee80211_sta *sta) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci struct hwsim_sta_priv *sp = (void *)sta->drv_priv; 24662306a36Sopenharmony_ci sp->magic = HWSIM_STA_MAGIC; 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_cistatic inline void hwsim_clear_sta_magic(struct ieee80211_sta *sta) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci struct hwsim_sta_priv *sp = (void *)sta->drv_priv; 25262306a36Sopenharmony_ci sp->magic = 0; 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_cistruct hwsim_chanctx_priv { 25662306a36Sopenharmony_ci u32 magic; 25762306a36Sopenharmony_ci}; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci#define HWSIM_CHANCTX_MAGIC 0x6d53774a 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_cistatic inline void hwsim_check_chanctx_magic(struct ieee80211_chanctx_conf *c) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci struct hwsim_chanctx_priv *cp = (void *)c->drv_priv; 26462306a36Sopenharmony_ci WARN_ON(cp->magic != HWSIM_CHANCTX_MAGIC); 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic inline void hwsim_set_chanctx_magic(struct ieee80211_chanctx_conf *c) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci struct hwsim_chanctx_priv *cp = (void *)c->drv_priv; 27062306a36Sopenharmony_ci cp->magic = HWSIM_CHANCTX_MAGIC; 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic inline void hwsim_clear_chanctx_magic(struct ieee80211_chanctx_conf *c) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci struct hwsim_chanctx_priv *cp = (void *)c->drv_priv; 27662306a36Sopenharmony_ci cp->magic = 0; 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic unsigned int hwsim_net_id; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic DEFINE_IDA(hwsim_netgroup_ida); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistruct hwsim_net { 28462306a36Sopenharmony_ci int netgroup; 28562306a36Sopenharmony_ci u32 wmediumd; 28662306a36Sopenharmony_ci}; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic inline int hwsim_net_get_netgroup(struct net *net) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci struct hwsim_net *hwsim_net = net_generic(net, hwsim_net_id); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci return hwsim_net->netgroup; 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_cistatic inline int hwsim_net_set_netgroup(struct net *net) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci struct hwsim_net *hwsim_net = net_generic(net, hwsim_net_id); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci hwsim_net->netgroup = ida_alloc(&hwsim_netgroup_ida, GFP_KERNEL); 30062306a36Sopenharmony_ci return hwsim_net->netgroup >= 0 ? 0 : -ENOMEM; 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistatic inline u32 hwsim_net_get_wmediumd(struct net *net) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci struct hwsim_net *hwsim_net = net_generic(net, hwsim_net_id); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci return hwsim_net->wmediumd; 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic inline void hwsim_net_set_wmediumd(struct net *net, u32 portid) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci struct hwsim_net *hwsim_net = net_generic(net, hwsim_net_id); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci hwsim_net->wmediumd = portid; 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic struct class *hwsim_class; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic struct net_device *hwsim_mon; /* global monitor netdev */ 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci#define CHAN2G(_freq) { \ 32262306a36Sopenharmony_ci .band = NL80211_BAND_2GHZ, \ 32362306a36Sopenharmony_ci .center_freq = (_freq), \ 32462306a36Sopenharmony_ci .hw_value = (_freq), \ 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci#define CHAN5G(_freq) { \ 32862306a36Sopenharmony_ci .band = NL80211_BAND_5GHZ, \ 32962306a36Sopenharmony_ci .center_freq = (_freq), \ 33062306a36Sopenharmony_ci .hw_value = (_freq), \ 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci#define CHAN6G(_freq) { \ 33462306a36Sopenharmony_ci .band = NL80211_BAND_6GHZ, \ 33562306a36Sopenharmony_ci .center_freq = (_freq), \ 33662306a36Sopenharmony_ci .hw_value = (_freq), \ 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistatic const struct ieee80211_channel hwsim_channels_2ghz[] = { 34062306a36Sopenharmony_ci CHAN2G(2412), /* Channel 1 */ 34162306a36Sopenharmony_ci CHAN2G(2417), /* Channel 2 */ 34262306a36Sopenharmony_ci CHAN2G(2422), /* Channel 3 */ 34362306a36Sopenharmony_ci CHAN2G(2427), /* Channel 4 */ 34462306a36Sopenharmony_ci CHAN2G(2432), /* Channel 5 */ 34562306a36Sopenharmony_ci CHAN2G(2437), /* Channel 6 */ 34662306a36Sopenharmony_ci CHAN2G(2442), /* Channel 7 */ 34762306a36Sopenharmony_ci CHAN2G(2447), /* Channel 8 */ 34862306a36Sopenharmony_ci CHAN2G(2452), /* Channel 9 */ 34962306a36Sopenharmony_ci CHAN2G(2457), /* Channel 10 */ 35062306a36Sopenharmony_ci CHAN2G(2462), /* Channel 11 */ 35162306a36Sopenharmony_ci CHAN2G(2467), /* Channel 12 */ 35262306a36Sopenharmony_ci CHAN2G(2472), /* Channel 13 */ 35362306a36Sopenharmony_ci CHAN2G(2484), /* Channel 14 */ 35462306a36Sopenharmony_ci}; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic const struct ieee80211_channel hwsim_channels_5ghz[] = { 35762306a36Sopenharmony_ci CHAN5G(5180), /* Channel 36 */ 35862306a36Sopenharmony_ci CHAN5G(5200), /* Channel 40 */ 35962306a36Sopenharmony_ci CHAN5G(5220), /* Channel 44 */ 36062306a36Sopenharmony_ci CHAN5G(5240), /* Channel 48 */ 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci CHAN5G(5260), /* Channel 52 */ 36362306a36Sopenharmony_ci CHAN5G(5280), /* Channel 56 */ 36462306a36Sopenharmony_ci CHAN5G(5300), /* Channel 60 */ 36562306a36Sopenharmony_ci CHAN5G(5320), /* Channel 64 */ 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci CHAN5G(5500), /* Channel 100 */ 36862306a36Sopenharmony_ci CHAN5G(5520), /* Channel 104 */ 36962306a36Sopenharmony_ci CHAN5G(5540), /* Channel 108 */ 37062306a36Sopenharmony_ci CHAN5G(5560), /* Channel 112 */ 37162306a36Sopenharmony_ci CHAN5G(5580), /* Channel 116 */ 37262306a36Sopenharmony_ci CHAN5G(5600), /* Channel 120 */ 37362306a36Sopenharmony_ci CHAN5G(5620), /* Channel 124 */ 37462306a36Sopenharmony_ci CHAN5G(5640), /* Channel 128 */ 37562306a36Sopenharmony_ci CHAN5G(5660), /* Channel 132 */ 37662306a36Sopenharmony_ci CHAN5G(5680), /* Channel 136 */ 37762306a36Sopenharmony_ci CHAN5G(5700), /* Channel 140 */ 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci CHAN5G(5745), /* Channel 149 */ 38062306a36Sopenharmony_ci CHAN5G(5765), /* Channel 153 */ 38162306a36Sopenharmony_ci CHAN5G(5785), /* Channel 157 */ 38262306a36Sopenharmony_ci CHAN5G(5805), /* Channel 161 */ 38362306a36Sopenharmony_ci CHAN5G(5825), /* Channel 165 */ 38462306a36Sopenharmony_ci CHAN5G(5845), /* Channel 169 */ 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci CHAN5G(5855), /* Channel 171 */ 38762306a36Sopenharmony_ci CHAN5G(5860), /* Channel 172 */ 38862306a36Sopenharmony_ci CHAN5G(5865), /* Channel 173 */ 38962306a36Sopenharmony_ci CHAN5G(5870), /* Channel 174 */ 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci CHAN5G(5875), /* Channel 175 */ 39262306a36Sopenharmony_ci CHAN5G(5880), /* Channel 176 */ 39362306a36Sopenharmony_ci CHAN5G(5885), /* Channel 177 */ 39462306a36Sopenharmony_ci CHAN5G(5890), /* Channel 178 */ 39562306a36Sopenharmony_ci CHAN5G(5895), /* Channel 179 */ 39662306a36Sopenharmony_ci CHAN5G(5900), /* Channel 180 */ 39762306a36Sopenharmony_ci CHAN5G(5905), /* Channel 181 */ 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci CHAN5G(5910), /* Channel 182 */ 40062306a36Sopenharmony_ci CHAN5G(5915), /* Channel 183 */ 40162306a36Sopenharmony_ci CHAN5G(5920), /* Channel 184 */ 40262306a36Sopenharmony_ci CHAN5G(5925), /* Channel 185 */ 40362306a36Sopenharmony_ci}; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_cistatic const struct ieee80211_channel hwsim_channels_6ghz[] = { 40662306a36Sopenharmony_ci CHAN6G(5955), /* Channel 1 */ 40762306a36Sopenharmony_ci CHAN6G(5975), /* Channel 5 */ 40862306a36Sopenharmony_ci CHAN6G(5995), /* Channel 9 */ 40962306a36Sopenharmony_ci CHAN6G(6015), /* Channel 13 */ 41062306a36Sopenharmony_ci CHAN6G(6035), /* Channel 17 */ 41162306a36Sopenharmony_ci CHAN6G(6055), /* Channel 21 */ 41262306a36Sopenharmony_ci CHAN6G(6075), /* Channel 25 */ 41362306a36Sopenharmony_ci CHAN6G(6095), /* Channel 29 */ 41462306a36Sopenharmony_ci CHAN6G(6115), /* Channel 33 */ 41562306a36Sopenharmony_ci CHAN6G(6135), /* Channel 37 */ 41662306a36Sopenharmony_ci CHAN6G(6155), /* Channel 41 */ 41762306a36Sopenharmony_ci CHAN6G(6175), /* Channel 45 */ 41862306a36Sopenharmony_ci CHAN6G(6195), /* Channel 49 */ 41962306a36Sopenharmony_ci CHAN6G(6215), /* Channel 53 */ 42062306a36Sopenharmony_ci CHAN6G(6235), /* Channel 57 */ 42162306a36Sopenharmony_ci CHAN6G(6255), /* Channel 61 */ 42262306a36Sopenharmony_ci CHAN6G(6275), /* Channel 65 */ 42362306a36Sopenharmony_ci CHAN6G(6295), /* Channel 69 */ 42462306a36Sopenharmony_ci CHAN6G(6315), /* Channel 73 */ 42562306a36Sopenharmony_ci CHAN6G(6335), /* Channel 77 */ 42662306a36Sopenharmony_ci CHAN6G(6355), /* Channel 81 */ 42762306a36Sopenharmony_ci CHAN6G(6375), /* Channel 85 */ 42862306a36Sopenharmony_ci CHAN6G(6395), /* Channel 89 */ 42962306a36Sopenharmony_ci CHAN6G(6415), /* Channel 93 */ 43062306a36Sopenharmony_ci CHAN6G(6435), /* Channel 97 */ 43162306a36Sopenharmony_ci CHAN6G(6455), /* Channel 181 */ 43262306a36Sopenharmony_ci CHAN6G(6475), /* Channel 105 */ 43362306a36Sopenharmony_ci CHAN6G(6495), /* Channel 109 */ 43462306a36Sopenharmony_ci CHAN6G(6515), /* Channel 113 */ 43562306a36Sopenharmony_ci CHAN6G(6535), /* Channel 117 */ 43662306a36Sopenharmony_ci CHAN6G(6555), /* Channel 121 */ 43762306a36Sopenharmony_ci CHAN6G(6575), /* Channel 125 */ 43862306a36Sopenharmony_ci CHAN6G(6595), /* Channel 129 */ 43962306a36Sopenharmony_ci CHAN6G(6615), /* Channel 133 */ 44062306a36Sopenharmony_ci CHAN6G(6635), /* Channel 137 */ 44162306a36Sopenharmony_ci CHAN6G(6655), /* Channel 141 */ 44262306a36Sopenharmony_ci CHAN6G(6675), /* Channel 145 */ 44362306a36Sopenharmony_ci CHAN6G(6695), /* Channel 149 */ 44462306a36Sopenharmony_ci CHAN6G(6715), /* Channel 153 */ 44562306a36Sopenharmony_ci CHAN6G(6735), /* Channel 157 */ 44662306a36Sopenharmony_ci CHAN6G(6755), /* Channel 161 */ 44762306a36Sopenharmony_ci CHAN6G(6775), /* Channel 165 */ 44862306a36Sopenharmony_ci CHAN6G(6795), /* Channel 169 */ 44962306a36Sopenharmony_ci CHAN6G(6815), /* Channel 173 */ 45062306a36Sopenharmony_ci CHAN6G(6835), /* Channel 177 */ 45162306a36Sopenharmony_ci CHAN6G(6855), /* Channel 181 */ 45262306a36Sopenharmony_ci CHAN6G(6875), /* Channel 185 */ 45362306a36Sopenharmony_ci CHAN6G(6895), /* Channel 189 */ 45462306a36Sopenharmony_ci CHAN6G(6915), /* Channel 193 */ 45562306a36Sopenharmony_ci CHAN6G(6935), /* Channel 197 */ 45662306a36Sopenharmony_ci CHAN6G(6955), /* Channel 201 */ 45762306a36Sopenharmony_ci CHAN6G(6975), /* Channel 205 */ 45862306a36Sopenharmony_ci CHAN6G(6995), /* Channel 209 */ 45962306a36Sopenharmony_ci CHAN6G(7015), /* Channel 213 */ 46062306a36Sopenharmony_ci CHAN6G(7035), /* Channel 217 */ 46162306a36Sopenharmony_ci CHAN6G(7055), /* Channel 221 */ 46262306a36Sopenharmony_ci CHAN6G(7075), /* Channel 225 */ 46362306a36Sopenharmony_ci CHAN6G(7095), /* Channel 229 */ 46462306a36Sopenharmony_ci CHAN6G(7115), /* Channel 233 */ 46562306a36Sopenharmony_ci}; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci#define NUM_S1G_CHANS_US 51 46862306a36Sopenharmony_cistatic struct ieee80211_channel hwsim_channels_s1g[NUM_S1G_CHANS_US]; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_cistatic const struct ieee80211_sta_s1g_cap hwsim_s1g_cap = { 47162306a36Sopenharmony_ci .s1g = true, 47262306a36Sopenharmony_ci .cap = { S1G_CAP0_SGI_1MHZ | S1G_CAP0_SGI_2MHZ, 47362306a36Sopenharmony_ci 0, 47462306a36Sopenharmony_ci 0, 47562306a36Sopenharmony_ci S1G_CAP3_MAX_MPDU_LEN, 47662306a36Sopenharmony_ci 0, 47762306a36Sopenharmony_ci S1G_CAP5_AMPDU, 47862306a36Sopenharmony_ci 0, 47962306a36Sopenharmony_ci S1G_CAP7_DUP_1MHZ, 48062306a36Sopenharmony_ci S1G_CAP8_TWT_RESPOND | S1G_CAP8_TWT_REQUEST, 48162306a36Sopenharmony_ci 0}, 48262306a36Sopenharmony_ci .nss_mcs = { 0xfc | 1, /* MCS 7 for 1 SS */ 48362306a36Sopenharmony_ci /* RX Highest Supported Long GI Data Rate 0:7 */ 48462306a36Sopenharmony_ci 0, 48562306a36Sopenharmony_ci /* RX Highest Supported Long GI Data Rate 0:7 */ 48662306a36Sopenharmony_ci /* TX S1G MCS Map 0:6 */ 48762306a36Sopenharmony_ci 0xfa, 48862306a36Sopenharmony_ci /* TX S1G MCS Map :7 */ 48962306a36Sopenharmony_ci /* TX Highest Supported Long GI Data Rate 0:6 */ 49062306a36Sopenharmony_ci 0x80, 49162306a36Sopenharmony_ci /* TX Highest Supported Long GI Data Rate 7:8 */ 49262306a36Sopenharmony_ci /* Rx Single spatial stream and S1G-MCS Map for 1MHz */ 49362306a36Sopenharmony_ci /* Tx Single spatial stream and S1G-MCS Map for 1MHz */ 49462306a36Sopenharmony_ci 0 }, 49562306a36Sopenharmony_ci}; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_cistatic void hwsim_init_s1g_channels(struct ieee80211_channel *chans) 49862306a36Sopenharmony_ci{ 49962306a36Sopenharmony_ci int ch, freq; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci for (ch = 0; ch < NUM_S1G_CHANS_US; ch++) { 50262306a36Sopenharmony_ci freq = 902000 + (ch + 1) * 500; 50362306a36Sopenharmony_ci chans[ch].band = NL80211_BAND_S1GHZ; 50462306a36Sopenharmony_ci chans[ch].center_freq = KHZ_TO_MHZ(freq); 50562306a36Sopenharmony_ci chans[ch].freq_offset = freq % 1000; 50662306a36Sopenharmony_ci chans[ch].hw_value = ch + 1; 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cistatic const struct ieee80211_rate hwsim_rates[] = { 51162306a36Sopenharmony_ci { .bitrate = 10 }, 51262306a36Sopenharmony_ci { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, 51362306a36Sopenharmony_ci { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, 51462306a36Sopenharmony_ci { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, 51562306a36Sopenharmony_ci { .bitrate = 60 }, 51662306a36Sopenharmony_ci { .bitrate = 90 }, 51762306a36Sopenharmony_ci { .bitrate = 120 }, 51862306a36Sopenharmony_ci { .bitrate = 180 }, 51962306a36Sopenharmony_ci { .bitrate = 240 }, 52062306a36Sopenharmony_ci { .bitrate = 360 }, 52162306a36Sopenharmony_ci { .bitrate = 480 }, 52262306a36Sopenharmony_ci { .bitrate = 540 } 52362306a36Sopenharmony_ci}; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci#define DEFAULT_RX_RSSI -50 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_cistatic const u32 hwsim_ciphers[] = { 52862306a36Sopenharmony_ci WLAN_CIPHER_SUITE_WEP40, 52962306a36Sopenharmony_ci WLAN_CIPHER_SUITE_WEP104, 53062306a36Sopenharmony_ci WLAN_CIPHER_SUITE_TKIP, 53162306a36Sopenharmony_ci WLAN_CIPHER_SUITE_CCMP, 53262306a36Sopenharmony_ci WLAN_CIPHER_SUITE_CCMP_256, 53362306a36Sopenharmony_ci WLAN_CIPHER_SUITE_GCMP, 53462306a36Sopenharmony_ci WLAN_CIPHER_SUITE_GCMP_256, 53562306a36Sopenharmony_ci WLAN_CIPHER_SUITE_AES_CMAC, 53662306a36Sopenharmony_ci WLAN_CIPHER_SUITE_BIP_CMAC_256, 53762306a36Sopenharmony_ci WLAN_CIPHER_SUITE_BIP_GMAC_128, 53862306a36Sopenharmony_ci WLAN_CIPHER_SUITE_BIP_GMAC_256, 53962306a36Sopenharmony_ci}; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci#define OUI_QCA 0x001374 54262306a36Sopenharmony_ci#define QCA_NL80211_SUBCMD_TEST 1 54362306a36Sopenharmony_cienum qca_nl80211_vendor_subcmds { 54462306a36Sopenharmony_ci QCA_WLAN_VENDOR_ATTR_TEST = 8, 54562306a36Sopenharmony_ci QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_TEST 54662306a36Sopenharmony_ci}; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_cistatic const struct nla_policy 54962306a36Sopenharmony_cihwsim_vendor_test_policy[QCA_WLAN_VENDOR_ATTR_MAX + 1] = { 55062306a36Sopenharmony_ci [QCA_WLAN_VENDOR_ATTR_MAX] = { .type = NLA_U32 }, 55162306a36Sopenharmony_ci}; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_cistatic int mac80211_hwsim_vendor_cmd_test(struct wiphy *wiphy, 55462306a36Sopenharmony_ci struct wireless_dev *wdev, 55562306a36Sopenharmony_ci const void *data, int data_len) 55662306a36Sopenharmony_ci{ 55762306a36Sopenharmony_ci struct sk_buff *skb; 55862306a36Sopenharmony_ci struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX + 1]; 55962306a36Sopenharmony_ci int err; 56062306a36Sopenharmony_ci u32 val; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci err = nla_parse_deprecated(tb, QCA_WLAN_VENDOR_ATTR_MAX, data, 56362306a36Sopenharmony_ci data_len, hwsim_vendor_test_policy, NULL); 56462306a36Sopenharmony_ci if (err) 56562306a36Sopenharmony_ci return err; 56662306a36Sopenharmony_ci if (!tb[QCA_WLAN_VENDOR_ATTR_TEST]) 56762306a36Sopenharmony_ci return -EINVAL; 56862306a36Sopenharmony_ci val = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_TEST]); 56962306a36Sopenharmony_ci wiphy_dbg(wiphy, "%s: test=%u\n", __func__, val); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci /* Send a vendor event as a test. Note that this would not normally be 57262306a36Sopenharmony_ci * done within a command handler, but rather, based on some other 57362306a36Sopenharmony_ci * trigger. For simplicity, this command is used to trigger the event 57462306a36Sopenharmony_ci * here. 57562306a36Sopenharmony_ci * 57662306a36Sopenharmony_ci * event_idx = 0 (index in mac80211_hwsim_vendor_commands) 57762306a36Sopenharmony_ci */ 57862306a36Sopenharmony_ci skb = cfg80211_vendor_event_alloc(wiphy, wdev, 100, 0, GFP_KERNEL); 57962306a36Sopenharmony_ci if (skb) { 58062306a36Sopenharmony_ci /* skb_put() or nla_put() will fill up data within 58162306a36Sopenharmony_ci * NL80211_ATTR_VENDOR_DATA. 58262306a36Sopenharmony_ci */ 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci /* Add vendor data */ 58562306a36Sopenharmony_ci nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_TEST, val + 1); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci /* Send the event - this will call nla_nest_end() */ 58862306a36Sopenharmony_ci cfg80211_vendor_event(skb, GFP_KERNEL); 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci /* Send a response to the command */ 59262306a36Sopenharmony_ci skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, 10); 59362306a36Sopenharmony_ci if (!skb) 59462306a36Sopenharmony_ci return -ENOMEM; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci /* skb_put() or nla_put() will fill up data within 59762306a36Sopenharmony_ci * NL80211_ATTR_VENDOR_DATA 59862306a36Sopenharmony_ci */ 59962306a36Sopenharmony_ci nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_TEST, val + 2); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci return cfg80211_vendor_cmd_reply(skb); 60262306a36Sopenharmony_ci} 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_cistatic struct wiphy_vendor_command mac80211_hwsim_vendor_commands[] = { 60562306a36Sopenharmony_ci { 60662306a36Sopenharmony_ci .info = { .vendor_id = OUI_QCA, 60762306a36Sopenharmony_ci .subcmd = QCA_NL80211_SUBCMD_TEST }, 60862306a36Sopenharmony_ci .flags = WIPHY_VENDOR_CMD_NEED_NETDEV, 60962306a36Sopenharmony_ci .doit = mac80211_hwsim_vendor_cmd_test, 61062306a36Sopenharmony_ci .policy = hwsim_vendor_test_policy, 61162306a36Sopenharmony_ci .maxattr = QCA_WLAN_VENDOR_ATTR_MAX, 61262306a36Sopenharmony_ci } 61362306a36Sopenharmony_ci}; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci/* Advertise support vendor specific events */ 61662306a36Sopenharmony_cistatic const struct nl80211_vendor_cmd_info mac80211_hwsim_vendor_events[] = { 61762306a36Sopenharmony_ci { .vendor_id = OUI_QCA, .subcmd = 1 }, 61862306a36Sopenharmony_ci}; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_cistatic DEFINE_SPINLOCK(hwsim_radio_lock); 62162306a36Sopenharmony_cistatic LIST_HEAD(hwsim_radios); 62262306a36Sopenharmony_cistatic struct rhashtable hwsim_radios_rht; 62362306a36Sopenharmony_cistatic int hwsim_radio_idx; 62462306a36Sopenharmony_cistatic int hwsim_radios_generation = 1; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_cistatic struct platform_driver mac80211_hwsim_driver = { 62762306a36Sopenharmony_ci .driver = { 62862306a36Sopenharmony_ci .name = "mac80211_hwsim", 62962306a36Sopenharmony_ci }, 63062306a36Sopenharmony_ci}; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_cistruct mac80211_hwsim_link_data { 63362306a36Sopenharmony_ci u32 link_id; 63462306a36Sopenharmony_ci u64 beacon_int /* beacon interval in us */; 63562306a36Sopenharmony_ci struct hrtimer beacon_timer; 63662306a36Sopenharmony_ci}; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_cistruct mac80211_hwsim_data { 63962306a36Sopenharmony_ci struct list_head list; 64062306a36Sopenharmony_ci struct rhash_head rht; 64162306a36Sopenharmony_ci struct ieee80211_hw *hw; 64262306a36Sopenharmony_ci struct device *dev; 64362306a36Sopenharmony_ci struct ieee80211_supported_band bands[NUM_NL80211_BANDS]; 64462306a36Sopenharmony_ci struct ieee80211_channel channels_2ghz[ARRAY_SIZE(hwsim_channels_2ghz)]; 64562306a36Sopenharmony_ci struct ieee80211_channel channels_5ghz[ARRAY_SIZE(hwsim_channels_5ghz)]; 64662306a36Sopenharmony_ci struct ieee80211_channel channels_6ghz[ARRAY_SIZE(hwsim_channels_6ghz)]; 64762306a36Sopenharmony_ci struct ieee80211_channel channels_s1g[ARRAY_SIZE(hwsim_channels_s1g)]; 64862306a36Sopenharmony_ci struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)]; 64962306a36Sopenharmony_ci struct ieee80211_iface_combination if_combination; 65062306a36Sopenharmony_ci struct ieee80211_iface_limit if_limits[3]; 65162306a36Sopenharmony_ci int n_if_limits; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci u32 ciphers[ARRAY_SIZE(hwsim_ciphers)]; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci struct mac_address addresses[2]; 65662306a36Sopenharmony_ci int channels, idx; 65762306a36Sopenharmony_ci bool use_chanctx; 65862306a36Sopenharmony_ci bool destroy_on_close; 65962306a36Sopenharmony_ci u32 portid; 66062306a36Sopenharmony_ci char alpha2[2]; 66162306a36Sopenharmony_ci const struct ieee80211_regdomain *regd; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci struct ieee80211_channel *tmp_chan; 66462306a36Sopenharmony_ci struct ieee80211_channel *roc_chan; 66562306a36Sopenharmony_ci u32 roc_duration; 66662306a36Sopenharmony_ci struct delayed_work roc_start; 66762306a36Sopenharmony_ci struct delayed_work roc_done; 66862306a36Sopenharmony_ci struct delayed_work hw_scan; 66962306a36Sopenharmony_ci struct cfg80211_scan_request *hw_scan_request; 67062306a36Sopenharmony_ci struct ieee80211_vif *hw_scan_vif; 67162306a36Sopenharmony_ci int scan_chan_idx; 67262306a36Sopenharmony_ci u8 scan_addr[ETH_ALEN]; 67362306a36Sopenharmony_ci struct { 67462306a36Sopenharmony_ci struct ieee80211_channel *channel; 67562306a36Sopenharmony_ci unsigned long next_start, start, end; 67662306a36Sopenharmony_ci } survey_data[ARRAY_SIZE(hwsim_channels_2ghz) + 67762306a36Sopenharmony_ci ARRAY_SIZE(hwsim_channels_5ghz) + 67862306a36Sopenharmony_ci ARRAY_SIZE(hwsim_channels_6ghz)]; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci struct ieee80211_channel *channel; 68162306a36Sopenharmony_ci enum nl80211_chan_width bw; 68262306a36Sopenharmony_ci unsigned int rx_filter; 68362306a36Sopenharmony_ci bool started, idle, scanning; 68462306a36Sopenharmony_ci struct mutex mutex; 68562306a36Sopenharmony_ci enum ps_mode { 68662306a36Sopenharmony_ci PS_DISABLED, PS_ENABLED, PS_AUTO_POLL, PS_MANUAL_POLL 68762306a36Sopenharmony_ci } ps; 68862306a36Sopenharmony_ci bool ps_poll_pending; 68962306a36Sopenharmony_ci struct dentry *debugfs; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci atomic_t pending_cookie; 69262306a36Sopenharmony_ci struct sk_buff_head pending; /* packets pending */ 69362306a36Sopenharmony_ci /* 69462306a36Sopenharmony_ci * Only radios in the same group can communicate together (the 69562306a36Sopenharmony_ci * channel has to match too). Each bit represents a group. A 69662306a36Sopenharmony_ci * radio can be in more than one group. 69762306a36Sopenharmony_ci */ 69862306a36Sopenharmony_ci u64 group; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci /* group shared by radios created in the same netns */ 70162306a36Sopenharmony_ci int netgroup; 70262306a36Sopenharmony_ci /* wmediumd portid responsible for netgroup of this radio */ 70362306a36Sopenharmony_ci u32 wmediumd; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci /* difference between this hw's clock and the real clock, in usecs */ 70662306a36Sopenharmony_ci s64 tsf_offset; 70762306a36Sopenharmony_ci s64 bcn_delta; 70862306a36Sopenharmony_ci /* absolute beacon transmission time. Used to cover up "tx" delay. */ 70962306a36Sopenharmony_ci u64 abs_bcn_ts; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci /* Stats */ 71262306a36Sopenharmony_ci u64 tx_pkts; 71362306a36Sopenharmony_ci u64 rx_pkts; 71462306a36Sopenharmony_ci u64 tx_bytes; 71562306a36Sopenharmony_ci u64 rx_bytes; 71662306a36Sopenharmony_ci u64 tx_dropped; 71762306a36Sopenharmony_ci u64 tx_failed; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci /* RSSI in rx status of the receiver */ 72062306a36Sopenharmony_ci int rx_rssi; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci /* only used when pmsr capability is supplied */ 72362306a36Sopenharmony_ci struct cfg80211_pmsr_capabilities pmsr_capa; 72462306a36Sopenharmony_ci struct cfg80211_pmsr_request *pmsr_request; 72562306a36Sopenharmony_ci struct wireless_dev *pmsr_request_wdev; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci struct mac80211_hwsim_link_data link_data[IEEE80211_MLD_MAX_NUM_LINKS]; 72862306a36Sopenharmony_ci}; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_cistatic const struct rhashtable_params hwsim_rht_params = { 73162306a36Sopenharmony_ci .nelem_hint = 2, 73262306a36Sopenharmony_ci .automatic_shrinking = true, 73362306a36Sopenharmony_ci .key_len = ETH_ALEN, 73462306a36Sopenharmony_ci .key_offset = offsetof(struct mac80211_hwsim_data, addresses[1]), 73562306a36Sopenharmony_ci .head_offset = offsetof(struct mac80211_hwsim_data, rht), 73662306a36Sopenharmony_ci}; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_cistruct hwsim_radiotap_hdr { 73962306a36Sopenharmony_ci struct ieee80211_radiotap_header hdr; 74062306a36Sopenharmony_ci __le64 rt_tsft; 74162306a36Sopenharmony_ci u8 rt_flags; 74262306a36Sopenharmony_ci u8 rt_rate; 74362306a36Sopenharmony_ci __le16 rt_channel; 74462306a36Sopenharmony_ci __le16 rt_chbitmask; 74562306a36Sopenharmony_ci} __packed; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_cistruct hwsim_radiotap_ack_hdr { 74862306a36Sopenharmony_ci struct ieee80211_radiotap_header hdr; 74962306a36Sopenharmony_ci u8 rt_flags; 75062306a36Sopenharmony_ci u8 pad; 75162306a36Sopenharmony_ci __le16 rt_channel; 75262306a36Sopenharmony_ci __le16 rt_chbitmask; 75362306a36Sopenharmony_ci} __packed; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_cistatic struct mac80211_hwsim_data *get_hwsim_data_ref_from_addr(const u8 *addr) 75662306a36Sopenharmony_ci{ 75762306a36Sopenharmony_ci return rhashtable_lookup_fast(&hwsim_radios_rht, addr, hwsim_rht_params); 75862306a36Sopenharmony_ci} 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci/* MAC80211_HWSIM netlink family */ 76162306a36Sopenharmony_cistatic struct genl_family hwsim_genl_family; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_cienum hwsim_multicast_groups { 76462306a36Sopenharmony_ci HWSIM_MCGRP_CONFIG, 76562306a36Sopenharmony_ci}; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_cistatic const struct genl_multicast_group hwsim_mcgrps[] = { 76862306a36Sopenharmony_ci [HWSIM_MCGRP_CONFIG] = { .name = "config", }, 76962306a36Sopenharmony_ci}; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci/* MAC80211_HWSIM netlink policy */ 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_cistatic const struct nla_policy 77462306a36Sopenharmony_cihwsim_rate_info_policy[HWSIM_RATE_INFO_ATTR_MAX + 1] = { 77562306a36Sopenharmony_ci [HWSIM_RATE_INFO_ATTR_FLAGS] = { .type = NLA_U8 }, 77662306a36Sopenharmony_ci [HWSIM_RATE_INFO_ATTR_MCS] = { .type = NLA_U8 }, 77762306a36Sopenharmony_ci [HWSIM_RATE_INFO_ATTR_LEGACY] = { .type = NLA_U16 }, 77862306a36Sopenharmony_ci [HWSIM_RATE_INFO_ATTR_NSS] = { .type = NLA_U8 }, 77962306a36Sopenharmony_ci [HWSIM_RATE_INFO_ATTR_BW] = { .type = NLA_U8 }, 78062306a36Sopenharmony_ci [HWSIM_RATE_INFO_ATTR_HE_GI] = { .type = NLA_U8 }, 78162306a36Sopenharmony_ci [HWSIM_RATE_INFO_ATTR_HE_DCM] = { .type = NLA_U8 }, 78262306a36Sopenharmony_ci [HWSIM_RATE_INFO_ATTR_HE_RU_ALLOC] = { .type = NLA_U8 }, 78362306a36Sopenharmony_ci [HWSIM_RATE_INFO_ATTR_N_BOUNDED_CH] = { .type = NLA_U8 }, 78462306a36Sopenharmony_ci [HWSIM_RATE_INFO_ATTR_EHT_GI] = { .type = NLA_U8 }, 78562306a36Sopenharmony_ci [HWSIM_RATE_INFO_ATTR_EHT_RU_ALLOC] = { .type = NLA_U8 }, 78662306a36Sopenharmony_ci}; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_cistatic const struct nla_policy 78962306a36Sopenharmony_cihwsim_ftm_result_policy[NL80211_PMSR_FTM_RESP_ATTR_MAX + 1] = { 79062306a36Sopenharmony_ci [NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON] = { .type = NLA_U32 }, 79162306a36Sopenharmony_ci [NL80211_PMSR_FTM_RESP_ATTR_BURST_INDEX] = { .type = NLA_U16 }, 79262306a36Sopenharmony_ci [NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_ATTEMPTS] = { .type = NLA_U32 }, 79362306a36Sopenharmony_ci [NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_SUCCESSES] = { .type = NLA_U32 }, 79462306a36Sopenharmony_ci [NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME] = { .type = NLA_U8 }, 79562306a36Sopenharmony_ci [NL80211_PMSR_FTM_RESP_ATTR_NUM_BURSTS_EXP] = { .type = NLA_U8 }, 79662306a36Sopenharmony_ci [NL80211_PMSR_FTM_RESP_ATTR_BURST_DURATION] = { .type = NLA_U8 }, 79762306a36Sopenharmony_ci [NL80211_PMSR_FTM_RESP_ATTR_FTMS_PER_BURST] = { .type = NLA_U8 }, 79862306a36Sopenharmony_ci [NL80211_PMSR_FTM_RESP_ATTR_RSSI_AVG] = { .type = NLA_U32 }, 79962306a36Sopenharmony_ci [NL80211_PMSR_FTM_RESP_ATTR_RSSI_SPREAD] = { .type = NLA_U32 }, 80062306a36Sopenharmony_ci [NL80211_PMSR_FTM_RESP_ATTR_TX_RATE] = NLA_POLICY_NESTED(hwsim_rate_info_policy), 80162306a36Sopenharmony_ci [NL80211_PMSR_FTM_RESP_ATTR_RX_RATE] = NLA_POLICY_NESTED(hwsim_rate_info_policy), 80262306a36Sopenharmony_ci [NL80211_PMSR_FTM_RESP_ATTR_RTT_AVG] = { .type = NLA_U64 }, 80362306a36Sopenharmony_ci [NL80211_PMSR_FTM_RESP_ATTR_RTT_VARIANCE] = { .type = NLA_U64 }, 80462306a36Sopenharmony_ci [NL80211_PMSR_FTM_RESP_ATTR_RTT_SPREAD] = { .type = NLA_U64 }, 80562306a36Sopenharmony_ci [NL80211_PMSR_FTM_RESP_ATTR_DIST_AVG] = { .type = NLA_U64 }, 80662306a36Sopenharmony_ci [NL80211_PMSR_FTM_RESP_ATTR_DIST_VARIANCE] = { .type = NLA_U64 }, 80762306a36Sopenharmony_ci [NL80211_PMSR_FTM_RESP_ATTR_DIST_SPREAD] = { .type = NLA_U64 }, 80862306a36Sopenharmony_ci [NL80211_PMSR_FTM_RESP_ATTR_LCI] = { .type = NLA_STRING }, 80962306a36Sopenharmony_ci [NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC] = { .type = NLA_STRING }, 81062306a36Sopenharmony_ci}; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_cistatic const struct nla_policy 81362306a36Sopenharmony_cihwsim_pmsr_resp_type_policy[NL80211_PMSR_TYPE_MAX + 1] = { 81462306a36Sopenharmony_ci [NL80211_PMSR_TYPE_FTM] = NLA_POLICY_NESTED(hwsim_ftm_result_policy), 81562306a36Sopenharmony_ci}; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_cistatic const struct nla_policy 81862306a36Sopenharmony_cihwsim_pmsr_resp_policy[NL80211_PMSR_RESP_ATTR_MAX + 1] = { 81962306a36Sopenharmony_ci [NL80211_PMSR_RESP_ATTR_STATUS] = { .type = NLA_U32 }, 82062306a36Sopenharmony_ci [NL80211_PMSR_RESP_ATTR_HOST_TIME] = { .type = NLA_U64 }, 82162306a36Sopenharmony_ci [NL80211_PMSR_RESP_ATTR_AP_TSF] = { .type = NLA_U64 }, 82262306a36Sopenharmony_ci [NL80211_PMSR_RESP_ATTR_FINAL] = { .type = NLA_FLAG }, 82362306a36Sopenharmony_ci [NL80211_PMSR_RESP_ATTR_DATA] = NLA_POLICY_NESTED(hwsim_pmsr_resp_type_policy), 82462306a36Sopenharmony_ci}; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_cistatic const struct nla_policy 82762306a36Sopenharmony_cihwsim_pmsr_peer_result_policy[NL80211_PMSR_PEER_ATTR_MAX + 1] = { 82862306a36Sopenharmony_ci [NL80211_PMSR_PEER_ATTR_ADDR] = NLA_POLICY_ETH_ADDR_COMPAT, 82962306a36Sopenharmony_ci [NL80211_PMSR_PEER_ATTR_CHAN] = { .type = NLA_REJECT }, 83062306a36Sopenharmony_ci [NL80211_PMSR_PEER_ATTR_REQ] = { .type = NLA_REJECT }, 83162306a36Sopenharmony_ci [NL80211_PMSR_PEER_ATTR_RESP] = NLA_POLICY_NESTED(hwsim_pmsr_resp_policy), 83262306a36Sopenharmony_ci}; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_cistatic const struct nla_policy 83562306a36Sopenharmony_cihwsim_pmsr_peers_result_policy[NL80211_PMSR_ATTR_MAX + 1] = { 83662306a36Sopenharmony_ci [NL80211_PMSR_ATTR_MAX_PEERS] = { .type = NLA_REJECT }, 83762306a36Sopenharmony_ci [NL80211_PMSR_ATTR_REPORT_AP_TSF] = { .type = NLA_REJECT }, 83862306a36Sopenharmony_ci [NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR] = { .type = NLA_REJECT }, 83962306a36Sopenharmony_ci [NL80211_PMSR_ATTR_TYPE_CAPA] = { .type = NLA_REJECT }, 84062306a36Sopenharmony_ci [NL80211_PMSR_ATTR_PEERS] = NLA_POLICY_NESTED_ARRAY(hwsim_pmsr_peer_result_policy), 84162306a36Sopenharmony_ci}; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_cistatic const struct nla_policy 84462306a36Sopenharmony_cihwsim_ftm_capa_policy[NL80211_PMSR_FTM_CAPA_ATTR_MAX + 1] = { 84562306a36Sopenharmony_ci [NL80211_PMSR_FTM_CAPA_ATTR_ASAP] = { .type = NLA_FLAG }, 84662306a36Sopenharmony_ci [NL80211_PMSR_FTM_CAPA_ATTR_NON_ASAP] = { .type = NLA_FLAG }, 84762306a36Sopenharmony_ci [NL80211_PMSR_FTM_CAPA_ATTR_REQ_LCI] = { .type = NLA_FLAG }, 84862306a36Sopenharmony_ci [NL80211_PMSR_FTM_CAPA_ATTR_REQ_CIVICLOC] = { .type = NLA_FLAG }, 84962306a36Sopenharmony_ci [NL80211_PMSR_FTM_CAPA_ATTR_PREAMBLES] = { .type = NLA_U32 }, 85062306a36Sopenharmony_ci [NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS] = { .type = NLA_U32 }, 85162306a36Sopenharmony_ci [NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT] = NLA_POLICY_MAX(NLA_U8, 15), 85262306a36Sopenharmony_ci [NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST] = NLA_POLICY_MAX(NLA_U8, 31), 85362306a36Sopenharmony_ci [NL80211_PMSR_FTM_CAPA_ATTR_TRIGGER_BASED] = { .type = NLA_FLAG }, 85462306a36Sopenharmony_ci [NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED] = { .type = NLA_FLAG }, 85562306a36Sopenharmony_ci}; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_cistatic const struct nla_policy 85862306a36Sopenharmony_cihwsim_pmsr_capa_type_policy[NL80211_PMSR_TYPE_MAX + 1] = { 85962306a36Sopenharmony_ci [NL80211_PMSR_TYPE_FTM] = NLA_POLICY_NESTED(hwsim_ftm_capa_policy), 86062306a36Sopenharmony_ci}; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_cistatic const struct nla_policy 86362306a36Sopenharmony_cihwsim_pmsr_capa_policy[NL80211_PMSR_ATTR_MAX + 1] = { 86462306a36Sopenharmony_ci [NL80211_PMSR_ATTR_MAX_PEERS] = { .type = NLA_U32 }, 86562306a36Sopenharmony_ci [NL80211_PMSR_ATTR_REPORT_AP_TSF] = { .type = NLA_FLAG }, 86662306a36Sopenharmony_ci [NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR] = { .type = NLA_FLAG }, 86762306a36Sopenharmony_ci [NL80211_PMSR_ATTR_TYPE_CAPA] = NLA_POLICY_NESTED(hwsim_pmsr_capa_type_policy), 86862306a36Sopenharmony_ci [NL80211_PMSR_ATTR_PEERS] = { .type = NLA_REJECT }, // only for request. 86962306a36Sopenharmony_ci}; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_cistatic const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = { 87262306a36Sopenharmony_ci [HWSIM_ATTR_ADDR_RECEIVER] = NLA_POLICY_ETH_ADDR_COMPAT, 87362306a36Sopenharmony_ci [HWSIM_ATTR_ADDR_TRANSMITTER] = NLA_POLICY_ETH_ADDR_COMPAT, 87462306a36Sopenharmony_ci [HWSIM_ATTR_FRAME] = { .type = NLA_BINARY, 87562306a36Sopenharmony_ci .len = IEEE80211_MAX_DATA_LEN }, 87662306a36Sopenharmony_ci [HWSIM_ATTR_FLAGS] = { .type = NLA_U32 }, 87762306a36Sopenharmony_ci [HWSIM_ATTR_RX_RATE] = { .type = NLA_U32 }, 87862306a36Sopenharmony_ci [HWSIM_ATTR_SIGNAL] = { .type = NLA_U32 }, 87962306a36Sopenharmony_ci [HWSIM_ATTR_TX_INFO] = { .type = NLA_BINARY, 88062306a36Sopenharmony_ci .len = IEEE80211_TX_MAX_RATES * 88162306a36Sopenharmony_ci sizeof(struct hwsim_tx_rate)}, 88262306a36Sopenharmony_ci [HWSIM_ATTR_COOKIE] = { .type = NLA_U64 }, 88362306a36Sopenharmony_ci [HWSIM_ATTR_CHANNELS] = { .type = NLA_U32 }, 88462306a36Sopenharmony_ci [HWSIM_ATTR_RADIO_ID] = { .type = NLA_U32 }, 88562306a36Sopenharmony_ci [HWSIM_ATTR_REG_HINT_ALPHA2] = { .type = NLA_STRING, .len = 2 }, 88662306a36Sopenharmony_ci [HWSIM_ATTR_REG_CUSTOM_REG] = { .type = NLA_U32 }, 88762306a36Sopenharmony_ci [HWSIM_ATTR_REG_STRICT_REG] = { .type = NLA_FLAG }, 88862306a36Sopenharmony_ci [HWSIM_ATTR_SUPPORT_P2P_DEVICE] = { .type = NLA_FLAG }, 88962306a36Sopenharmony_ci [HWSIM_ATTR_USE_CHANCTX] = { .type = NLA_FLAG }, 89062306a36Sopenharmony_ci [HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE] = { .type = NLA_FLAG }, 89162306a36Sopenharmony_ci [HWSIM_ATTR_RADIO_NAME] = { .type = NLA_STRING }, 89262306a36Sopenharmony_ci [HWSIM_ATTR_NO_VIF] = { .type = NLA_FLAG }, 89362306a36Sopenharmony_ci [HWSIM_ATTR_FREQ] = { .type = NLA_U32 }, 89462306a36Sopenharmony_ci [HWSIM_ATTR_TX_INFO_FLAGS] = { .type = NLA_BINARY }, 89562306a36Sopenharmony_ci [HWSIM_ATTR_PERM_ADDR] = NLA_POLICY_ETH_ADDR_COMPAT, 89662306a36Sopenharmony_ci [HWSIM_ATTR_IFTYPE_SUPPORT] = { .type = NLA_U32 }, 89762306a36Sopenharmony_ci [HWSIM_ATTR_CIPHER_SUPPORT] = { .type = NLA_BINARY }, 89862306a36Sopenharmony_ci [HWSIM_ATTR_MLO_SUPPORT] = { .type = NLA_FLAG }, 89962306a36Sopenharmony_ci [HWSIM_ATTR_PMSR_SUPPORT] = NLA_POLICY_NESTED(hwsim_pmsr_capa_policy), 90062306a36Sopenharmony_ci [HWSIM_ATTR_PMSR_RESULT] = NLA_POLICY_NESTED(hwsim_pmsr_peers_result_policy), 90162306a36Sopenharmony_ci}; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci#if IS_REACHABLE(CONFIG_VIRTIO) 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci/* MAC80211_HWSIM virtio queues */ 90662306a36Sopenharmony_cistatic struct virtqueue *hwsim_vqs[HWSIM_NUM_VQS]; 90762306a36Sopenharmony_cistatic bool hwsim_virtio_enabled; 90862306a36Sopenharmony_cistatic DEFINE_SPINLOCK(hwsim_virtio_lock); 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_cistatic void hwsim_virtio_rx_work(struct work_struct *work); 91162306a36Sopenharmony_cistatic DECLARE_WORK(hwsim_virtio_rx, hwsim_virtio_rx_work); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_cistatic int hwsim_tx_virtio(struct mac80211_hwsim_data *data, 91462306a36Sopenharmony_ci struct sk_buff *skb) 91562306a36Sopenharmony_ci{ 91662306a36Sopenharmony_ci struct scatterlist sg[1]; 91762306a36Sopenharmony_ci unsigned long flags; 91862306a36Sopenharmony_ci int err; 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci spin_lock_irqsave(&hwsim_virtio_lock, flags); 92162306a36Sopenharmony_ci if (!hwsim_virtio_enabled) { 92262306a36Sopenharmony_ci err = -ENODEV; 92362306a36Sopenharmony_ci goto out_free; 92462306a36Sopenharmony_ci } 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci sg_init_one(sg, skb->head, skb_end_offset(skb)); 92762306a36Sopenharmony_ci err = virtqueue_add_outbuf(hwsim_vqs[HWSIM_VQ_TX], sg, 1, skb, 92862306a36Sopenharmony_ci GFP_ATOMIC); 92962306a36Sopenharmony_ci if (err) 93062306a36Sopenharmony_ci goto out_free; 93162306a36Sopenharmony_ci virtqueue_kick(hwsim_vqs[HWSIM_VQ_TX]); 93262306a36Sopenharmony_ci spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 93362306a36Sopenharmony_ci return 0; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ciout_free: 93662306a36Sopenharmony_ci spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 93762306a36Sopenharmony_ci nlmsg_free(skb); 93862306a36Sopenharmony_ci return err; 93962306a36Sopenharmony_ci} 94062306a36Sopenharmony_ci#else 94162306a36Sopenharmony_ci/* cause a linker error if this ends up being needed */ 94262306a36Sopenharmony_ciextern int hwsim_tx_virtio(struct mac80211_hwsim_data *data, 94362306a36Sopenharmony_ci struct sk_buff *skb); 94462306a36Sopenharmony_ci#define hwsim_virtio_enabled false 94562306a36Sopenharmony_ci#endif 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_cistatic int hwsim_get_chanwidth(enum nl80211_chan_width bw) 94862306a36Sopenharmony_ci{ 94962306a36Sopenharmony_ci switch (bw) { 95062306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_20_NOHT: 95162306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_20: 95262306a36Sopenharmony_ci return 20; 95362306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_40: 95462306a36Sopenharmony_ci return 40; 95562306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_80: 95662306a36Sopenharmony_ci return 80; 95762306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_80P80: 95862306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_160: 95962306a36Sopenharmony_ci return 160; 96062306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_320: 96162306a36Sopenharmony_ci return 320; 96262306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_5: 96362306a36Sopenharmony_ci return 5; 96462306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_10: 96562306a36Sopenharmony_ci return 10; 96662306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_1: 96762306a36Sopenharmony_ci return 1; 96862306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_2: 96962306a36Sopenharmony_ci return 2; 97062306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_4: 97162306a36Sopenharmony_ci return 4; 97262306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_8: 97362306a36Sopenharmony_ci return 8; 97462306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_16: 97562306a36Sopenharmony_ci return 16; 97662306a36Sopenharmony_ci } 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci return INT_MAX; 97962306a36Sopenharmony_ci} 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_cistatic void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, 98262306a36Sopenharmony_ci struct sk_buff *skb, 98362306a36Sopenharmony_ci struct ieee80211_channel *chan); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci/* sysfs attributes */ 98662306a36Sopenharmony_cistatic void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) 98762306a36Sopenharmony_ci{ 98862306a36Sopenharmony_ci struct mac80211_hwsim_data *data = dat; 98962306a36Sopenharmony_ci struct hwsim_vif_priv *vp = (void *)vif->drv_priv; 99062306a36Sopenharmony_ci struct sk_buff *skb; 99162306a36Sopenharmony_ci struct ieee80211_pspoll *pspoll; 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci if (!vp->assoc) 99462306a36Sopenharmony_ci return; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci wiphy_dbg(data->hw->wiphy, 99762306a36Sopenharmony_ci "%s: send PS-Poll to %pM for aid %d\n", 99862306a36Sopenharmony_ci __func__, vp->bssid, vp->aid); 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci skb = dev_alloc_skb(sizeof(*pspoll)); 100162306a36Sopenharmony_ci if (!skb) 100262306a36Sopenharmony_ci return; 100362306a36Sopenharmony_ci pspoll = skb_put(skb, sizeof(*pspoll)); 100462306a36Sopenharmony_ci pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | 100562306a36Sopenharmony_ci IEEE80211_STYPE_PSPOLL | 100662306a36Sopenharmony_ci IEEE80211_FCTL_PM); 100762306a36Sopenharmony_ci pspoll->aid = cpu_to_le16(0xc000 | vp->aid); 100862306a36Sopenharmony_ci memcpy(pspoll->bssid, vp->bssid, ETH_ALEN); 100962306a36Sopenharmony_ci memcpy(pspoll->ta, mac, ETH_ALEN); 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci rcu_read_lock(); 101262306a36Sopenharmony_ci mac80211_hwsim_tx_frame(data->hw, skb, 101362306a36Sopenharmony_ci rcu_dereference(vif->bss_conf.chanctx_conf)->def.chan); 101462306a36Sopenharmony_ci rcu_read_unlock(); 101562306a36Sopenharmony_ci} 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_cistatic void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, 101862306a36Sopenharmony_ci struct ieee80211_vif *vif, int ps) 101962306a36Sopenharmony_ci{ 102062306a36Sopenharmony_ci struct hwsim_vif_priv *vp = (void *)vif->drv_priv; 102162306a36Sopenharmony_ci struct sk_buff *skb; 102262306a36Sopenharmony_ci struct ieee80211_hdr *hdr; 102362306a36Sopenharmony_ci struct ieee80211_tx_info *cb; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci if (!vp->assoc) 102662306a36Sopenharmony_ci return; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci wiphy_dbg(data->hw->wiphy, 102962306a36Sopenharmony_ci "%s: send data::nullfunc to %pM ps=%d\n", 103062306a36Sopenharmony_ci __func__, vp->bssid, ps); 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci skb = dev_alloc_skb(sizeof(*hdr)); 103362306a36Sopenharmony_ci if (!skb) 103462306a36Sopenharmony_ci return; 103562306a36Sopenharmony_ci hdr = skb_put(skb, sizeof(*hdr) - ETH_ALEN); 103662306a36Sopenharmony_ci hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | 103762306a36Sopenharmony_ci IEEE80211_STYPE_NULLFUNC | 103862306a36Sopenharmony_ci IEEE80211_FCTL_TODS | 103962306a36Sopenharmony_ci (ps ? IEEE80211_FCTL_PM : 0)); 104062306a36Sopenharmony_ci hdr->duration_id = cpu_to_le16(0); 104162306a36Sopenharmony_ci memcpy(hdr->addr1, vp->bssid, ETH_ALEN); 104262306a36Sopenharmony_ci memcpy(hdr->addr2, mac, ETH_ALEN); 104362306a36Sopenharmony_ci memcpy(hdr->addr3, vp->bssid, ETH_ALEN); 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci cb = IEEE80211_SKB_CB(skb); 104662306a36Sopenharmony_ci cb->control.rates[0].count = 1; 104762306a36Sopenharmony_ci cb->control.rates[1].idx = -1; 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci rcu_read_lock(); 105062306a36Sopenharmony_ci mac80211_hwsim_tx_frame(data->hw, skb, 105162306a36Sopenharmony_ci rcu_dereference(vif->bss_conf.chanctx_conf)->def.chan); 105262306a36Sopenharmony_ci rcu_read_unlock(); 105362306a36Sopenharmony_ci} 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_cistatic void hwsim_send_nullfunc_ps(void *dat, u8 *mac, 105762306a36Sopenharmony_ci struct ieee80211_vif *vif) 105862306a36Sopenharmony_ci{ 105962306a36Sopenharmony_ci struct mac80211_hwsim_data *data = dat; 106062306a36Sopenharmony_ci hwsim_send_nullfunc(data, mac, vif, 1); 106162306a36Sopenharmony_ci} 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_cistatic void hwsim_send_nullfunc_no_ps(void *dat, u8 *mac, 106462306a36Sopenharmony_ci struct ieee80211_vif *vif) 106562306a36Sopenharmony_ci{ 106662306a36Sopenharmony_ci struct mac80211_hwsim_data *data = dat; 106762306a36Sopenharmony_ci hwsim_send_nullfunc(data, mac, vif, 0); 106862306a36Sopenharmony_ci} 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_cistatic int hwsim_fops_ps_read(void *dat, u64 *val) 107162306a36Sopenharmony_ci{ 107262306a36Sopenharmony_ci struct mac80211_hwsim_data *data = dat; 107362306a36Sopenharmony_ci *val = data->ps; 107462306a36Sopenharmony_ci return 0; 107562306a36Sopenharmony_ci} 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_cistatic int hwsim_fops_ps_write(void *dat, u64 val) 107862306a36Sopenharmony_ci{ 107962306a36Sopenharmony_ci struct mac80211_hwsim_data *data = dat; 108062306a36Sopenharmony_ci enum ps_mode old_ps; 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci if (val != PS_DISABLED && val != PS_ENABLED && val != PS_AUTO_POLL && 108362306a36Sopenharmony_ci val != PS_MANUAL_POLL) 108462306a36Sopenharmony_ci return -EINVAL; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci if (val == PS_MANUAL_POLL) { 108762306a36Sopenharmony_ci if (data->ps != PS_ENABLED) 108862306a36Sopenharmony_ci return -EINVAL; 108962306a36Sopenharmony_ci local_bh_disable(); 109062306a36Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic( 109162306a36Sopenharmony_ci data->hw, IEEE80211_IFACE_ITER_NORMAL, 109262306a36Sopenharmony_ci hwsim_send_ps_poll, data); 109362306a36Sopenharmony_ci local_bh_enable(); 109462306a36Sopenharmony_ci return 0; 109562306a36Sopenharmony_ci } 109662306a36Sopenharmony_ci old_ps = data->ps; 109762306a36Sopenharmony_ci data->ps = val; 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci local_bh_disable(); 110062306a36Sopenharmony_ci if (old_ps == PS_DISABLED && val != PS_DISABLED) { 110162306a36Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic( 110262306a36Sopenharmony_ci data->hw, IEEE80211_IFACE_ITER_NORMAL, 110362306a36Sopenharmony_ci hwsim_send_nullfunc_ps, data); 110462306a36Sopenharmony_ci } else if (old_ps != PS_DISABLED && val == PS_DISABLED) { 110562306a36Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic( 110662306a36Sopenharmony_ci data->hw, IEEE80211_IFACE_ITER_NORMAL, 110762306a36Sopenharmony_ci hwsim_send_nullfunc_no_ps, data); 110862306a36Sopenharmony_ci } 110962306a36Sopenharmony_ci local_bh_enable(); 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci return 0; 111262306a36Sopenharmony_ci} 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write, 111562306a36Sopenharmony_ci "%llu\n"); 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_cistatic int hwsim_write_simulate_radar(void *dat, u64 val) 111862306a36Sopenharmony_ci{ 111962306a36Sopenharmony_ci struct mac80211_hwsim_data *data = dat; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci ieee80211_radar_detected(data->hw); 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci return 0; 112462306a36Sopenharmony_ci} 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(hwsim_simulate_radar, NULL, 112762306a36Sopenharmony_ci hwsim_write_simulate_radar, "%llu\n"); 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_cistatic int hwsim_fops_group_read(void *dat, u64 *val) 113062306a36Sopenharmony_ci{ 113162306a36Sopenharmony_ci struct mac80211_hwsim_data *data = dat; 113262306a36Sopenharmony_ci *val = data->group; 113362306a36Sopenharmony_ci return 0; 113462306a36Sopenharmony_ci} 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_cistatic int hwsim_fops_group_write(void *dat, u64 val) 113762306a36Sopenharmony_ci{ 113862306a36Sopenharmony_ci struct mac80211_hwsim_data *data = dat; 113962306a36Sopenharmony_ci data->group = val; 114062306a36Sopenharmony_ci return 0; 114162306a36Sopenharmony_ci} 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(hwsim_fops_group, 114462306a36Sopenharmony_ci hwsim_fops_group_read, hwsim_fops_group_write, 114562306a36Sopenharmony_ci "%llx\n"); 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_cistatic int hwsim_fops_rx_rssi_read(void *dat, u64 *val) 114862306a36Sopenharmony_ci{ 114962306a36Sopenharmony_ci struct mac80211_hwsim_data *data = dat; 115062306a36Sopenharmony_ci *val = data->rx_rssi; 115162306a36Sopenharmony_ci return 0; 115262306a36Sopenharmony_ci} 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_cistatic int hwsim_fops_rx_rssi_write(void *dat, u64 val) 115562306a36Sopenharmony_ci{ 115662306a36Sopenharmony_ci struct mac80211_hwsim_data *data = dat; 115762306a36Sopenharmony_ci int rssi = (int)val; 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci if (rssi >= 0 || rssi < -100) 116062306a36Sopenharmony_ci return -EINVAL; 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci data->rx_rssi = rssi; 116362306a36Sopenharmony_ci return 0; 116462306a36Sopenharmony_ci} 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(hwsim_fops_rx_rssi, 116762306a36Sopenharmony_ci hwsim_fops_rx_rssi_read, hwsim_fops_rx_rssi_write, 116862306a36Sopenharmony_ci "%lld\n"); 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_cistatic netdev_tx_t hwsim_mon_xmit(struct sk_buff *skb, 117162306a36Sopenharmony_ci struct net_device *dev) 117262306a36Sopenharmony_ci{ 117362306a36Sopenharmony_ci /* TODO: allow packet injection */ 117462306a36Sopenharmony_ci dev_kfree_skb(skb); 117562306a36Sopenharmony_ci return NETDEV_TX_OK; 117662306a36Sopenharmony_ci} 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_cistatic inline u64 mac80211_hwsim_get_tsf_raw(void) 117962306a36Sopenharmony_ci{ 118062306a36Sopenharmony_ci return ktime_to_us(ktime_get_real()); 118162306a36Sopenharmony_ci} 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_cistatic __le64 __mac80211_hwsim_get_tsf(struct mac80211_hwsim_data *data) 118462306a36Sopenharmony_ci{ 118562306a36Sopenharmony_ci u64 now = mac80211_hwsim_get_tsf_raw(); 118662306a36Sopenharmony_ci return cpu_to_le64(now + data->tsf_offset); 118762306a36Sopenharmony_ci} 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_cistatic u64 mac80211_hwsim_get_tsf(struct ieee80211_hw *hw, 119062306a36Sopenharmony_ci struct ieee80211_vif *vif) 119162306a36Sopenharmony_ci{ 119262306a36Sopenharmony_ci struct mac80211_hwsim_data *data = hw->priv; 119362306a36Sopenharmony_ci return le64_to_cpu(__mac80211_hwsim_get_tsf(data)); 119462306a36Sopenharmony_ci} 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_cistatic void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw, 119762306a36Sopenharmony_ci struct ieee80211_vif *vif, u64 tsf) 119862306a36Sopenharmony_ci{ 119962306a36Sopenharmony_ci struct mac80211_hwsim_data *data = hw->priv; 120062306a36Sopenharmony_ci u64 now = mac80211_hwsim_get_tsf(hw, vif); 120162306a36Sopenharmony_ci /* MLD not supported here */ 120262306a36Sopenharmony_ci u32 bcn_int = data->link_data[0].beacon_int; 120362306a36Sopenharmony_ci u64 delta = abs(tsf - now); 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci /* adjust after beaconing with new timestamp at old TBTT */ 120662306a36Sopenharmony_ci if (tsf > now) { 120762306a36Sopenharmony_ci data->tsf_offset += delta; 120862306a36Sopenharmony_ci data->bcn_delta = do_div(delta, bcn_int); 120962306a36Sopenharmony_ci } else { 121062306a36Sopenharmony_ci data->tsf_offset -= delta; 121162306a36Sopenharmony_ci data->bcn_delta = -(s64)do_div(delta, bcn_int); 121262306a36Sopenharmony_ci } 121362306a36Sopenharmony_ci} 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_cistatic void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, 121662306a36Sopenharmony_ci struct sk_buff *tx_skb, 121762306a36Sopenharmony_ci struct ieee80211_channel *chan) 121862306a36Sopenharmony_ci{ 121962306a36Sopenharmony_ci struct mac80211_hwsim_data *data = hw->priv; 122062306a36Sopenharmony_ci struct sk_buff *skb; 122162306a36Sopenharmony_ci struct hwsim_radiotap_hdr *hdr; 122262306a36Sopenharmony_ci u16 flags, bitrate; 122362306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_skb); 122462306a36Sopenharmony_ci struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info); 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci if (!txrate) 122762306a36Sopenharmony_ci bitrate = 0; 122862306a36Sopenharmony_ci else 122962306a36Sopenharmony_ci bitrate = txrate->bitrate; 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci if (!netif_running(hwsim_mon)) 123262306a36Sopenharmony_ci return; 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci skb = skb_copy_expand(tx_skb, sizeof(*hdr), 0, GFP_ATOMIC); 123562306a36Sopenharmony_ci if (skb == NULL) 123662306a36Sopenharmony_ci return; 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci hdr = skb_push(skb, sizeof(*hdr)); 123962306a36Sopenharmony_ci hdr->hdr.it_version = PKTHDR_RADIOTAP_VERSION; 124062306a36Sopenharmony_ci hdr->hdr.it_pad = 0; 124162306a36Sopenharmony_ci hdr->hdr.it_len = cpu_to_le16(sizeof(*hdr)); 124262306a36Sopenharmony_ci hdr->hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | 124362306a36Sopenharmony_ci (1 << IEEE80211_RADIOTAP_RATE) | 124462306a36Sopenharmony_ci (1 << IEEE80211_RADIOTAP_TSFT) | 124562306a36Sopenharmony_ci (1 << IEEE80211_RADIOTAP_CHANNEL)); 124662306a36Sopenharmony_ci hdr->rt_tsft = __mac80211_hwsim_get_tsf(data); 124762306a36Sopenharmony_ci hdr->rt_flags = 0; 124862306a36Sopenharmony_ci hdr->rt_rate = bitrate / 5; 124962306a36Sopenharmony_ci hdr->rt_channel = cpu_to_le16(chan->center_freq); 125062306a36Sopenharmony_ci flags = IEEE80211_CHAN_2GHZ; 125162306a36Sopenharmony_ci if (txrate && txrate->flags & IEEE80211_RATE_ERP_G) 125262306a36Sopenharmony_ci flags |= IEEE80211_CHAN_OFDM; 125362306a36Sopenharmony_ci else 125462306a36Sopenharmony_ci flags |= IEEE80211_CHAN_CCK; 125562306a36Sopenharmony_ci hdr->rt_chbitmask = cpu_to_le16(flags); 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci skb->dev = hwsim_mon; 125862306a36Sopenharmony_ci skb_reset_mac_header(skb); 125962306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 126062306a36Sopenharmony_ci skb->pkt_type = PACKET_OTHERHOST; 126162306a36Sopenharmony_ci skb->protocol = htons(ETH_P_802_2); 126262306a36Sopenharmony_ci memset(skb->cb, 0, sizeof(skb->cb)); 126362306a36Sopenharmony_ci netif_rx(skb); 126462306a36Sopenharmony_ci} 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_cistatic void mac80211_hwsim_monitor_ack(struct ieee80211_channel *chan, 126862306a36Sopenharmony_ci const u8 *addr) 126962306a36Sopenharmony_ci{ 127062306a36Sopenharmony_ci struct sk_buff *skb; 127162306a36Sopenharmony_ci struct hwsim_radiotap_ack_hdr *hdr; 127262306a36Sopenharmony_ci u16 flags; 127362306a36Sopenharmony_ci struct ieee80211_hdr *hdr11; 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci if (!netif_running(hwsim_mon)) 127662306a36Sopenharmony_ci return; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci skb = dev_alloc_skb(100); 127962306a36Sopenharmony_ci if (skb == NULL) 128062306a36Sopenharmony_ci return; 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci hdr = skb_put(skb, sizeof(*hdr)); 128362306a36Sopenharmony_ci hdr->hdr.it_version = PKTHDR_RADIOTAP_VERSION; 128462306a36Sopenharmony_ci hdr->hdr.it_pad = 0; 128562306a36Sopenharmony_ci hdr->hdr.it_len = cpu_to_le16(sizeof(*hdr)); 128662306a36Sopenharmony_ci hdr->hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | 128762306a36Sopenharmony_ci (1 << IEEE80211_RADIOTAP_CHANNEL)); 128862306a36Sopenharmony_ci hdr->rt_flags = 0; 128962306a36Sopenharmony_ci hdr->pad = 0; 129062306a36Sopenharmony_ci hdr->rt_channel = cpu_to_le16(chan->center_freq); 129162306a36Sopenharmony_ci flags = IEEE80211_CHAN_2GHZ; 129262306a36Sopenharmony_ci hdr->rt_chbitmask = cpu_to_le16(flags); 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci hdr11 = skb_put(skb, 10); 129562306a36Sopenharmony_ci hdr11->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | 129662306a36Sopenharmony_ci IEEE80211_STYPE_ACK); 129762306a36Sopenharmony_ci hdr11->duration_id = cpu_to_le16(0); 129862306a36Sopenharmony_ci memcpy(hdr11->addr1, addr, ETH_ALEN); 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci skb->dev = hwsim_mon; 130162306a36Sopenharmony_ci skb_reset_mac_header(skb); 130262306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 130362306a36Sopenharmony_ci skb->pkt_type = PACKET_OTHERHOST; 130462306a36Sopenharmony_ci skb->protocol = htons(ETH_P_802_2); 130562306a36Sopenharmony_ci memset(skb->cb, 0, sizeof(skb->cb)); 130662306a36Sopenharmony_ci netif_rx(skb); 130762306a36Sopenharmony_ci} 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_cistruct mac80211_hwsim_addr_match_data { 131062306a36Sopenharmony_ci u8 addr[ETH_ALEN]; 131162306a36Sopenharmony_ci bool ret; 131262306a36Sopenharmony_ci}; 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_cistatic void mac80211_hwsim_addr_iter(void *data, u8 *mac, 131562306a36Sopenharmony_ci struct ieee80211_vif *vif) 131662306a36Sopenharmony_ci{ 131762306a36Sopenharmony_ci int i; 131862306a36Sopenharmony_ci struct mac80211_hwsim_addr_match_data *md = data; 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci if (memcmp(mac, md->addr, ETH_ALEN) == 0) { 132162306a36Sopenharmony_ci md->ret = true; 132262306a36Sopenharmony_ci return; 132362306a36Sopenharmony_ci } 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci /* Match the link address */ 132662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(vif->link_conf); i++) { 132762306a36Sopenharmony_ci struct ieee80211_bss_conf *conf; 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci conf = rcu_dereference(vif->link_conf[i]); 133062306a36Sopenharmony_ci if (!conf) 133162306a36Sopenharmony_ci continue; 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci if (memcmp(conf->addr, md->addr, ETH_ALEN) == 0) { 133462306a36Sopenharmony_ci md->ret = true; 133562306a36Sopenharmony_ci return; 133662306a36Sopenharmony_ci } 133762306a36Sopenharmony_ci } 133862306a36Sopenharmony_ci} 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_cistatic bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data, 134162306a36Sopenharmony_ci const u8 *addr) 134262306a36Sopenharmony_ci{ 134362306a36Sopenharmony_ci struct mac80211_hwsim_addr_match_data md = { 134462306a36Sopenharmony_ci .ret = false, 134562306a36Sopenharmony_ci }; 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci if (data->scanning && memcmp(addr, data->scan_addr, ETH_ALEN) == 0) 134862306a36Sopenharmony_ci return true; 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci memcpy(md.addr, addr, ETH_ALEN); 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic(data->hw, 135362306a36Sopenharmony_ci IEEE80211_IFACE_ITER_NORMAL, 135462306a36Sopenharmony_ci mac80211_hwsim_addr_iter, 135562306a36Sopenharmony_ci &md); 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci return md.ret; 135862306a36Sopenharmony_ci} 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_cistatic bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data, 136162306a36Sopenharmony_ci struct sk_buff *skb) 136262306a36Sopenharmony_ci{ 136362306a36Sopenharmony_ci switch (data->ps) { 136462306a36Sopenharmony_ci case PS_DISABLED: 136562306a36Sopenharmony_ci return true; 136662306a36Sopenharmony_ci case PS_ENABLED: 136762306a36Sopenharmony_ci return false; 136862306a36Sopenharmony_ci case PS_AUTO_POLL: 136962306a36Sopenharmony_ci /* TODO: accept (some) Beacons by default and other frames only 137062306a36Sopenharmony_ci * if pending PS-Poll has been sent */ 137162306a36Sopenharmony_ci return true; 137262306a36Sopenharmony_ci case PS_MANUAL_POLL: 137362306a36Sopenharmony_ci /* Allow unicast frames to own address if there is a pending 137462306a36Sopenharmony_ci * PS-Poll */ 137562306a36Sopenharmony_ci if (data->ps_poll_pending && 137662306a36Sopenharmony_ci mac80211_hwsim_addr_match(data, skb->data + 4)) { 137762306a36Sopenharmony_ci data->ps_poll_pending = false; 137862306a36Sopenharmony_ci return true; 137962306a36Sopenharmony_ci } 138062306a36Sopenharmony_ci return false; 138162306a36Sopenharmony_ci } 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci return true; 138462306a36Sopenharmony_ci} 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_cistatic int hwsim_unicast_netgroup(struct mac80211_hwsim_data *data, 138762306a36Sopenharmony_ci struct sk_buff *skb, int portid) 138862306a36Sopenharmony_ci{ 138962306a36Sopenharmony_ci struct net *net; 139062306a36Sopenharmony_ci bool found = false; 139162306a36Sopenharmony_ci int res = -ENOENT; 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci rcu_read_lock(); 139462306a36Sopenharmony_ci for_each_net_rcu(net) { 139562306a36Sopenharmony_ci if (data->netgroup == hwsim_net_get_netgroup(net)) { 139662306a36Sopenharmony_ci res = genlmsg_unicast(net, skb, portid); 139762306a36Sopenharmony_ci found = true; 139862306a36Sopenharmony_ci break; 139962306a36Sopenharmony_ci } 140062306a36Sopenharmony_ci } 140162306a36Sopenharmony_ci rcu_read_unlock(); 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci if (!found) 140462306a36Sopenharmony_ci nlmsg_free(skb); 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci return res; 140762306a36Sopenharmony_ci} 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_cistatic void mac80211_hwsim_config_mac_nl(struct ieee80211_hw *hw, 141062306a36Sopenharmony_ci const u8 *addr, bool add) 141162306a36Sopenharmony_ci{ 141262306a36Sopenharmony_ci struct mac80211_hwsim_data *data = hw->priv; 141362306a36Sopenharmony_ci u32 _portid = READ_ONCE(data->wmediumd); 141462306a36Sopenharmony_ci struct sk_buff *skb; 141562306a36Sopenharmony_ci void *msg_head; 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci WARN_ON(!is_valid_ether_addr(addr)); 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci if (!_portid && !hwsim_virtio_enabled) 142062306a36Sopenharmony_ci return; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_ATOMIC); 142362306a36Sopenharmony_ci if (!skb) 142462306a36Sopenharmony_ci return; 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci msg_head = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, 142762306a36Sopenharmony_ci add ? HWSIM_CMD_ADD_MAC_ADDR : 142862306a36Sopenharmony_ci HWSIM_CMD_DEL_MAC_ADDR); 142962306a36Sopenharmony_ci if (!msg_head) { 143062306a36Sopenharmony_ci pr_debug("mac80211_hwsim: problem with msg_head\n"); 143162306a36Sopenharmony_ci goto nla_put_failure; 143262306a36Sopenharmony_ci } 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER, 143562306a36Sopenharmony_ci ETH_ALEN, data->addresses[1].addr)) 143662306a36Sopenharmony_ci goto nla_put_failure; 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci if (nla_put(skb, HWSIM_ATTR_ADDR_RECEIVER, ETH_ALEN, addr)) 143962306a36Sopenharmony_ci goto nla_put_failure; 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci genlmsg_end(skb, msg_head); 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci if (hwsim_virtio_enabled) 144462306a36Sopenharmony_ci hwsim_tx_virtio(data, skb); 144562306a36Sopenharmony_ci else 144662306a36Sopenharmony_ci hwsim_unicast_netgroup(data, skb, _portid); 144762306a36Sopenharmony_ci return; 144862306a36Sopenharmony_cinla_put_failure: 144962306a36Sopenharmony_ci nlmsg_free(skb); 145062306a36Sopenharmony_ci} 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_cistatic inline u16 trans_tx_rate_flags_ieee2hwsim(struct ieee80211_tx_rate *rate) 145362306a36Sopenharmony_ci{ 145462306a36Sopenharmony_ci u16 result = 0; 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci if (rate->flags & IEEE80211_TX_RC_USE_RTS_CTS) 145762306a36Sopenharmony_ci result |= MAC80211_HWSIM_TX_RC_USE_RTS_CTS; 145862306a36Sopenharmony_ci if (rate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT) 145962306a36Sopenharmony_ci result |= MAC80211_HWSIM_TX_RC_USE_CTS_PROTECT; 146062306a36Sopenharmony_ci if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) 146162306a36Sopenharmony_ci result |= MAC80211_HWSIM_TX_RC_USE_SHORT_PREAMBLE; 146262306a36Sopenharmony_ci if (rate->flags & IEEE80211_TX_RC_MCS) 146362306a36Sopenharmony_ci result |= MAC80211_HWSIM_TX_RC_MCS; 146462306a36Sopenharmony_ci if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD) 146562306a36Sopenharmony_ci result |= MAC80211_HWSIM_TX_RC_GREEN_FIELD; 146662306a36Sopenharmony_ci if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) 146762306a36Sopenharmony_ci result |= MAC80211_HWSIM_TX_RC_40_MHZ_WIDTH; 146862306a36Sopenharmony_ci if (rate->flags & IEEE80211_TX_RC_DUP_DATA) 146962306a36Sopenharmony_ci result |= MAC80211_HWSIM_TX_RC_DUP_DATA; 147062306a36Sopenharmony_ci if (rate->flags & IEEE80211_TX_RC_SHORT_GI) 147162306a36Sopenharmony_ci result |= MAC80211_HWSIM_TX_RC_SHORT_GI; 147262306a36Sopenharmony_ci if (rate->flags & IEEE80211_TX_RC_VHT_MCS) 147362306a36Sopenharmony_ci result |= MAC80211_HWSIM_TX_RC_VHT_MCS; 147462306a36Sopenharmony_ci if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH) 147562306a36Sopenharmony_ci result |= MAC80211_HWSIM_TX_RC_80_MHZ_WIDTH; 147662306a36Sopenharmony_ci if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH) 147762306a36Sopenharmony_ci result |= MAC80211_HWSIM_TX_RC_160_MHZ_WIDTH; 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci return result; 148062306a36Sopenharmony_ci} 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_cistatic void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, 148362306a36Sopenharmony_ci struct sk_buff *my_skb, 148462306a36Sopenharmony_ci int dst_portid, 148562306a36Sopenharmony_ci struct ieee80211_channel *channel) 148662306a36Sopenharmony_ci{ 148762306a36Sopenharmony_ci struct sk_buff *skb; 148862306a36Sopenharmony_ci struct mac80211_hwsim_data *data = hw->priv; 148962306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) my_skb->data; 149062306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(my_skb); 149162306a36Sopenharmony_ci void *msg_head; 149262306a36Sopenharmony_ci unsigned int hwsim_flags = 0; 149362306a36Sopenharmony_ci int i; 149462306a36Sopenharmony_ci struct hwsim_tx_rate tx_attempts[IEEE80211_TX_MAX_RATES]; 149562306a36Sopenharmony_ci struct hwsim_tx_rate_flag tx_attempts_flags[IEEE80211_TX_MAX_RATES]; 149662306a36Sopenharmony_ci uintptr_t cookie; 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci if (data->ps != PS_DISABLED) 149962306a36Sopenharmony_ci hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); 150062306a36Sopenharmony_ci /* If the queue contains MAX_QUEUE skb's drop some */ 150162306a36Sopenharmony_ci if (skb_queue_len(&data->pending) >= MAX_QUEUE) { 150262306a36Sopenharmony_ci /* Dropping until WARN_QUEUE level */ 150362306a36Sopenharmony_ci while (skb_queue_len(&data->pending) >= WARN_QUEUE) { 150462306a36Sopenharmony_ci ieee80211_free_txskb(hw, skb_dequeue(&data->pending)); 150562306a36Sopenharmony_ci data->tx_dropped++; 150662306a36Sopenharmony_ci } 150762306a36Sopenharmony_ci } 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_ATOMIC); 151062306a36Sopenharmony_ci if (skb == NULL) 151162306a36Sopenharmony_ci goto nla_put_failure; 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci msg_head = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, 151462306a36Sopenharmony_ci HWSIM_CMD_FRAME); 151562306a36Sopenharmony_ci if (msg_head == NULL) { 151662306a36Sopenharmony_ci pr_debug("mac80211_hwsim: problem with msg_head\n"); 151762306a36Sopenharmony_ci goto nla_put_failure; 151862306a36Sopenharmony_ci } 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER, 152162306a36Sopenharmony_ci ETH_ALEN, data->addresses[1].addr)) 152262306a36Sopenharmony_ci goto nla_put_failure; 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci /* We get the skb->data */ 152562306a36Sopenharmony_ci if (nla_put(skb, HWSIM_ATTR_FRAME, my_skb->len, my_skb->data)) 152662306a36Sopenharmony_ci goto nla_put_failure; 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci /* We get the flags for this transmission, and we translate them to 152962306a36Sopenharmony_ci wmediumd flags */ 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) 153262306a36Sopenharmony_ci hwsim_flags |= HWSIM_TX_CTL_REQ_TX_STATUS; 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci if (info->flags & IEEE80211_TX_CTL_NO_ACK) 153562306a36Sopenharmony_ci hwsim_flags |= HWSIM_TX_CTL_NO_ACK; 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci if (nla_put_u32(skb, HWSIM_ATTR_FLAGS, hwsim_flags)) 153862306a36Sopenharmony_ci goto nla_put_failure; 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci if (nla_put_u32(skb, HWSIM_ATTR_FREQ, channel->center_freq)) 154162306a36Sopenharmony_ci goto nla_put_failure; 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci /* We get the tx control (rate and retries) info*/ 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { 154662306a36Sopenharmony_ci tx_attempts[i].idx = info->status.rates[i].idx; 154762306a36Sopenharmony_ci tx_attempts_flags[i].idx = info->status.rates[i].idx; 154862306a36Sopenharmony_ci tx_attempts[i].count = info->status.rates[i].count; 154962306a36Sopenharmony_ci tx_attempts_flags[i].flags = 155062306a36Sopenharmony_ci trans_tx_rate_flags_ieee2hwsim( 155162306a36Sopenharmony_ci &info->status.rates[i]); 155262306a36Sopenharmony_ci } 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci if (nla_put(skb, HWSIM_ATTR_TX_INFO, 155562306a36Sopenharmony_ci sizeof(struct hwsim_tx_rate)*IEEE80211_TX_MAX_RATES, 155662306a36Sopenharmony_ci tx_attempts)) 155762306a36Sopenharmony_ci goto nla_put_failure; 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci if (nla_put(skb, HWSIM_ATTR_TX_INFO_FLAGS, 156062306a36Sopenharmony_ci sizeof(struct hwsim_tx_rate_flag) * IEEE80211_TX_MAX_RATES, 156162306a36Sopenharmony_ci tx_attempts_flags)) 156262306a36Sopenharmony_ci goto nla_put_failure; 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_ci /* We create a cookie to identify this skb */ 156562306a36Sopenharmony_ci cookie = atomic_inc_return(&data->pending_cookie); 156662306a36Sopenharmony_ci info->rate_driver_data[0] = (void *)cookie; 156762306a36Sopenharmony_ci if (nla_put_u64_64bit(skb, HWSIM_ATTR_COOKIE, cookie, HWSIM_ATTR_PAD)) 156862306a36Sopenharmony_ci goto nla_put_failure; 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci genlmsg_end(skb, msg_head); 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci if (hwsim_virtio_enabled) { 157362306a36Sopenharmony_ci if (hwsim_tx_virtio(data, skb)) 157462306a36Sopenharmony_ci goto err_free_txskb; 157562306a36Sopenharmony_ci } else { 157662306a36Sopenharmony_ci if (hwsim_unicast_netgroup(data, skb, dst_portid)) 157762306a36Sopenharmony_ci goto err_free_txskb; 157862306a36Sopenharmony_ci } 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci /* Enqueue the packet */ 158162306a36Sopenharmony_ci skb_queue_tail(&data->pending, my_skb); 158262306a36Sopenharmony_ci data->tx_pkts++; 158362306a36Sopenharmony_ci data->tx_bytes += my_skb->len; 158462306a36Sopenharmony_ci return; 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_cinla_put_failure: 158762306a36Sopenharmony_ci nlmsg_free(skb); 158862306a36Sopenharmony_cierr_free_txskb: 158962306a36Sopenharmony_ci pr_debug("mac80211_hwsim: error occurred in %s\n", __func__); 159062306a36Sopenharmony_ci ieee80211_free_txskb(hw, my_skb); 159162306a36Sopenharmony_ci data->tx_failed++; 159262306a36Sopenharmony_ci} 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_cistatic bool hwsim_chans_compat(struct ieee80211_channel *c1, 159562306a36Sopenharmony_ci struct ieee80211_channel *c2) 159662306a36Sopenharmony_ci{ 159762306a36Sopenharmony_ci if (!c1 || !c2) 159862306a36Sopenharmony_ci return false; 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_ci return c1->center_freq == c2->center_freq; 160162306a36Sopenharmony_ci} 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_cistruct tx_iter_data { 160462306a36Sopenharmony_ci struct ieee80211_channel *channel; 160562306a36Sopenharmony_ci bool receive; 160662306a36Sopenharmony_ci}; 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_cistatic void mac80211_hwsim_tx_iter(void *_data, u8 *addr, 160962306a36Sopenharmony_ci struct ieee80211_vif *vif) 161062306a36Sopenharmony_ci{ 161162306a36Sopenharmony_ci struct tx_iter_data *data = _data; 161262306a36Sopenharmony_ci int i; 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(vif->link_conf); i++) { 161562306a36Sopenharmony_ci struct ieee80211_bss_conf *conf; 161662306a36Sopenharmony_ci struct ieee80211_chanctx_conf *chanctx; 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci conf = rcu_dereference(vif->link_conf[i]); 161962306a36Sopenharmony_ci if (!conf) 162062306a36Sopenharmony_ci continue; 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci chanctx = rcu_dereference(conf->chanctx_conf); 162362306a36Sopenharmony_ci if (!chanctx) 162462306a36Sopenharmony_ci continue; 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci if (!hwsim_chans_compat(data->channel, chanctx->def.chan)) 162762306a36Sopenharmony_ci continue; 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci data->receive = true; 163062306a36Sopenharmony_ci return; 163162306a36Sopenharmony_ci } 163262306a36Sopenharmony_ci} 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_cistatic void mac80211_hwsim_add_vendor_rtap(struct sk_buff *skb) 163562306a36Sopenharmony_ci{ 163662306a36Sopenharmony_ci /* 163762306a36Sopenharmony_ci * To enable this code, #define the HWSIM_RADIOTAP_OUI, 163862306a36Sopenharmony_ci * e.g. like this: 163962306a36Sopenharmony_ci * #define HWSIM_RADIOTAP_OUI "\x02\x00\x00" 164062306a36Sopenharmony_ci * (but you should use a valid OUI, not that) 164162306a36Sopenharmony_ci * 164262306a36Sopenharmony_ci * If anyone wants to 'donate' a radiotap OUI/subns code 164362306a36Sopenharmony_ci * please send a patch removing this #ifdef and changing 164462306a36Sopenharmony_ci * the values accordingly. 164562306a36Sopenharmony_ci */ 164662306a36Sopenharmony_ci#ifdef HWSIM_RADIOTAP_OUI 164762306a36Sopenharmony_ci struct ieee80211_radiotap_vendor_tlv *rtap; 164862306a36Sopenharmony_ci static const char vendor_data[8] = "ABCDEFGH"; 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_ci // Make sure no padding is needed 165162306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(vendor_data) % 4); 165262306a36Sopenharmony_ci /* this is last radiotap info before the mac header, so 165362306a36Sopenharmony_ci * skb_reset_mac_header for mac8022 to know the end of 165462306a36Sopenharmony_ci * the radiotap TLV/beginning of the 802.11 header 165562306a36Sopenharmony_ci */ 165662306a36Sopenharmony_ci skb_reset_mac_header(skb); 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci /* 165962306a36Sopenharmony_ci * Note that this code requires the headroom in the SKB 166062306a36Sopenharmony_ci * that was allocated earlier. 166162306a36Sopenharmony_ci */ 166262306a36Sopenharmony_ci rtap = skb_push(skb, sizeof(*rtap) + sizeof(vendor_data)); 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ci rtap->len = cpu_to_le16(sizeof(*rtap) - 166562306a36Sopenharmony_ci sizeof(struct ieee80211_radiotap_tlv) + 166662306a36Sopenharmony_ci sizeof(vendor_data)); 166762306a36Sopenharmony_ci rtap->type = cpu_to_le16(IEEE80211_RADIOTAP_VENDOR_NAMESPACE); 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_ci rtap->content.oui[0] = HWSIM_RADIOTAP_OUI[0]; 167062306a36Sopenharmony_ci rtap->content.oui[1] = HWSIM_RADIOTAP_OUI[1]; 167162306a36Sopenharmony_ci rtap->content.oui[2] = HWSIM_RADIOTAP_OUI[2]; 167262306a36Sopenharmony_ci rtap->content.oui_subtype = 127; 167362306a36Sopenharmony_ci /* clear reserved field */ 167462306a36Sopenharmony_ci rtap->content.reserved = 0; 167562306a36Sopenharmony_ci rtap->content.vendor_type = 0; 167662306a36Sopenharmony_ci memcpy(rtap->content.data, vendor_data, sizeof(vendor_data)); 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci IEEE80211_SKB_RXCB(skb)->flag |= RX_FLAG_RADIOTAP_TLV_AT_END; 167962306a36Sopenharmony_ci#endif 168062306a36Sopenharmony_ci} 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_cistatic void mac80211_hwsim_rx(struct mac80211_hwsim_data *data, 168362306a36Sopenharmony_ci struct ieee80211_rx_status *rx_status, 168462306a36Sopenharmony_ci struct sk_buff *skb) 168562306a36Sopenharmony_ci{ 168662306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (void *)skb->data; 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_ci if (!ieee80211_has_morefrags(hdr->frame_control) && 168962306a36Sopenharmony_ci !is_multicast_ether_addr(hdr->addr1) && 169062306a36Sopenharmony_ci (ieee80211_is_mgmt(hdr->frame_control) || 169162306a36Sopenharmony_ci ieee80211_is_data(hdr->frame_control))) { 169262306a36Sopenharmony_ci struct ieee80211_sta *sta; 169362306a36Sopenharmony_ci unsigned int link_id; 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci rcu_read_lock(); 169662306a36Sopenharmony_ci sta = ieee80211_find_sta_by_link_addrs(data->hw, hdr->addr2, 169762306a36Sopenharmony_ci hdr->addr1, &link_id); 169862306a36Sopenharmony_ci if (sta) { 169962306a36Sopenharmony_ci struct hwsim_sta_priv *sp = (void *)sta->drv_priv; 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci if (ieee80211_has_pm(hdr->frame_control)) 170262306a36Sopenharmony_ci sp->active_links_rx &= ~BIT(link_id); 170362306a36Sopenharmony_ci else 170462306a36Sopenharmony_ci sp->active_links_rx |= BIT(link_id); 170562306a36Sopenharmony_ci } 170662306a36Sopenharmony_ci rcu_read_unlock(); 170762306a36Sopenharmony_ci } 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status)); 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ci mac80211_hwsim_add_vendor_rtap(skb); 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci data->rx_pkts++; 171462306a36Sopenharmony_ci data->rx_bytes += skb->len; 171562306a36Sopenharmony_ci ieee80211_rx_irqsafe(data->hw, skb); 171662306a36Sopenharmony_ci} 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_cistatic bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, 171962306a36Sopenharmony_ci struct sk_buff *skb, 172062306a36Sopenharmony_ci struct ieee80211_channel *chan) 172162306a36Sopenharmony_ci{ 172262306a36Sopenharmony_ci struct mac80211_hwsim_data *data = hw->priv, *data2; 172362306a36Sopenharmony_ci bool ack = false; 172462306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 172562306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 172662306a36Sopenharmony_ci struct ieee80211_rx_status rx_status; 172762306a36Sopenharmony_ci u64 now; 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci memset(&rx_status, 0, sizeof(rx_status)); 173062306a36Sopenharmony_ci rx_status.flag |= RX_FLAG_MACTIME_START; 173162306a36Sopenharmony_ci rx_status.freq = chan->center_freq; 173262306a36Sopenharmony_ci rx_status.freq_offset = chan->freq_offset ? 1 : 0; 173362306a36Sopenharmony_ci rx_status.band = chan->band; 173462306a36Sopenharmony_ci if (info->control.rates[0].flags & IEEE80211_TX_RC_VHT_MCS) { 173562306a36Sopenharmony_ci rx_status.rate_idx = 173662306a36Sopenharmony_ci ieee80211_rate_get_vht_mcs(&info->control.rates[0]); 173762306a36Sopenharmony_ci rx_status.nss = 173862306a36Sopenharmony_ci ieee80211_rate_get_vht_nss(&info->control.rates[0]); 173962306a36Sopenharmony_ci rx_status.encoding = RX_ENC_VHT; 174062306a36Sopenharmony_ci } else { 174162306a36Sopenharmony_ci rx_status.rate_idx = info->control.rates[0].idx; 174262306a36Sopenharmony_ci if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS) 174362306a36Sopenharmony_ci rx_status.encoding = RX_ENC_HT; 174462306a36Sopenharmony_ci } 174562306a36Sopenharmony_ci if (info->control.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) 174662306a36Sopenharmony_ci rx_status.bw = RATE_INFO_BW_40; 174762306a36Sopenharmony_ci else if (info->control.rates[0].flags & IEEE80211_TX_RC_80_MHZ_WIDTH) 174862306a36Sopenharmony_ci rx_status.bw = RATE_INFO_BW_80; 174962306a36Sopenharmony_ci else if (info->control.rates[0].flags & IEEE80211_TX_RC_160_MHZ_WIDTH) 175062306a36Sopenharmony_ci rx_status.bw = RATE_INFO_BW_160; 175162306a36Sopenharmony_ci else 175262306a36Sopenharmony_ci rx_status.bw = RATE_INFO_BW_20; 175362306a36Sopenharmony_ci if (info->control.rates[0].flags & IEEE80211_TX_RC_SHORT_GI) 175462306a36Sopenharmony_ci rx_status.enc_flags |= RX_ENC_FLAG_SHORT_GI; 175562306a36Sopenharmony_ci /* TODO: simulate optional packet loss */ 175662306a36Sopenharmony_ci rx_status.signal = data->rx_rssi; 175762306a36Sopenharmony_ci if (info->control.vif) 175862306a36Sopenharmony_ci rx_status.signal += info->control.vif->bss_conf.txpower; 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_ci if (data->ps != PS_DISABLED) 176162306a36Sopenharmony_ci hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_ci /* release the skb's source info */ 176462306a36Sopenharmony_ci skb_orphan(skb); 176562306a36Sopenharmony_ci skb_dst_drop(skb); 176662306a36Sopenharmony_ci skb->mark = 0; 176762306a36Sopenharmony_ci skb_ext_reset(skb); 176862306a36Sopenharmony_ci nf_reset_ct(skb); 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci /* 177162306a36Sopenharmony_ci * Get absolute mactime here so all HWs RX at the "same time", and 177262306a36Sopenharmony_ci * absolute TX time for beacon mactime so the timestamp matches. 177362306a36Sopenharmony_ci * Giving beacons a different mactime than non-beacons looks messy, but 177462306a36Sopenharmony_ci * it helps the Toffset be exact and a ~10us mactime discrepancy 177562306a36Sopenharmony_ci * probably doesn't really matter. 177662306a36Sopenharmony_ci */ 177762306a36Sopenharmony_ci if (ieee80211_is_beacon(hdr->frame_control) || 177862306a36Sopenharmony_ci ieee80211_is_probe_resp(hdr->frame_control)) { 177962306a36Sopenharmony_ci rx_status.boottime_ns = ktime_get_boottime_ns(); 178062306a36Sopenharmony_ci now = data->abs_bcn_ts; 178162306a36Sopenharmony_ci } else { 178262306a36Sopenharmony_ci now = mac80211_hwsim_get_tsf_raw(); 178362306a36Sopenharmony_ci } 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci /* Copy skb to all enabled radios that are on the current frequency */ 178662306a36Sopenharmony_ci spin_lock(&hwsim_radio_lock); 178762306a36Sopenharmony_ci list_for_each_entry(data2, &hwsim_radios, list) { 178862306a36Sopenharmony_ci struct sk_buff *nskb; 178962306a36Sopenharmony_ci struct tx_iter_data tx_iter_data = { 179062306a36Sopenharmony_ci .receive = false, 179162306a36Sopenharmony_ci .channel = chan, 179262306a36Sopenharmony_ci }; 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci if (data == data2) 179562306a36Sopenharmony_ci continue; 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_ci if (!data2->started || (data2->idle && !data2->tmp_chan) || 179862306a36Sopenharmony_ci !hwsim_ps_rx_ok(data2, skb)) 179962306a36Sopenharmony_ci continue; 180062306a36Sopenharmony_ci 180162306a36Sopenharmony_ci if (!(data->group & data2->group)) 180262306a36Sopenharmony_ci continue; 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci if (data->netgroup != data2->netgroup) 180562306a36Sopenharmony_ci continue; 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci if (!hwsim_chans_compat(chan, data2->tmp_chan) && 180862306a36Sopenharmony_ci !hwsim_chans_compat(chan, data2->channel)) { 180962306a36Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic( 181062306a36Sopenharmony_ci data2->hw, IEEE80211_IFACE_ITER_NORMAL, 181162306a36Sopenharmony_ci mac80211_hwsim_tx_iter, &tx_iter_data); 181262306a36Sopenharmony_ci if (!tx_iter_data.receive) 181362306a36Sopenharmony_ci continue; 181462306a36Sopenharmony_ci } 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci /* 181762306a36Sopenharmony_ci * reserve some space for our vendor and the normal 181862306a36Sopenharmony_ci * radiotap header, since we're copying anyway 181962306a36Sopenharmony_ci */ 182062306a36Sopenharmony_ci if (skb->len < PAGE_SIZE && paged_rx) { 182162306a36Sopenharmony_ci struct page *page = alloc_page(GFP_ATOMIC); 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_ci if (!page) 182462306a36Sopenharmony_ci continue; 182562306a36Sopenharmony_ci 182662306a36Sopenharmony_ci nskb = dev_alloc_skb(128); 182762306a36Sopenharmony_ci if (!nskb) { 182862306a36Sopenharmony_ci __free_page(page); 182962306a36Sopenharmony_ci continue; 183062306a36Sopenharmony_ci } 183162306a36Sopenharmony_ci 183262306a36Sopenharmony_ci memcpy(page_address(page), skb->data, skb->len); 183362306a36Sopenharmony_ci skb_add_rx_frag(nskb, 0, page, 0, skb->len, skb->len); 183462306a36Sopenharmony_ci } else { 183562306a36Sopenharmony_ci nskb = skb_copy(skb, GFP_ATOMIC); 183662306a36Sopenharmony_ci if (!nskb) 183762306a36Sopenharmony_ci continue; 183862306a36Sopenharmony_ci } 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_ci if (mac80211_hwsim_addr_match(data2, hdr->addr1)) 184162306a36Sopenharmony_ci ack = true; 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ci rx_status.mactime = now + data2->tsf_offset; 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci mac80211_hwsim_rx(data2, &rx_status, nskb); 184662306a36Sopenharmony_ci } 184762306a36Sopenharmony_ci spin_unlock(&hwsim_radio_lock); 184862306a36Sopenharmony_ci 184962306a36Sopenharmony_ci return ack; 185062306a36Sopenharmony_ci} 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_cistatic struct ieee80211_bss_conf * 185362306a36Sopenharmony_cimac80211_hwsim_select_tx_link(struct mac80211_hwsim_data *data, 185462306a36Sopenharmony_ci struct ieee80211_vif *vif, 185562306a36Sopenharmony_ci struct ieee80211_sta *sta, 185662306a36Sopenharmony_ci struct ieee80211_hdr *hdr, 185762306a36Sopenharmony_ci struct ieee80211_link_sta **link_sta) 185862306a36Sopenharmony_ci{ 185962306a36Sopenharmony_ci struct hwsim_sta_priv *sp = (void *)sta->drv_priv; 186062306a36Sopenharmony_ci int i; 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci if (!ieee80211_vif_is_mld(vif)) 186362306a36Sopenharmony_ci return &vif->bss_conf; 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_ci WARN_ON(is_multicast_ether_addr(hdr->addr1)); 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_ci if (WARN_ON_ONCE(!sta || !sta->valid_links)) 186862306a36Sopenharmony_ci return &vif->bss_conf; 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(vif->link_conf); i++) { 187162306a36Sopenharmony_ci struct ieee80211_bss_conf *bss_conf; 187262306a36Sopenharmony_ci unsigned int link_id; 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ci /* round-robin the available link IDs */ 187562306a36Sopenharmony_ci link_id = (sp->last_link + i + 1) % ARRAY_SIZE(vif->link_conf); 187662306a36Sopenharmony_ci 187762306a36Sopenharmony_ci if (!(vif->active_links & BIT(link_id))) 187862306a36Sopenharmony_ci continue; 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci if (!(sp->active_links_rx & BIT(link_id))) 188162306a36Sopenharmony_ci continue; 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ci *link_sta = rcu_dereference(sta->link[link_id]); 188462306a36Sopenharmony_ci if (!*link_sta) 188562306a36Sopenharmony_ci continue; 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_ci bss_conf = rcu_dereference(vif->link_conf[link_id]); 188862306a36Sopenharmony_ci if (WARN_ON_ONCE(!bss_conf)) 188962306a36Sopenharmony_ci continue; 189062306a36Sopenharmony_ci 189162306a36Sopenharmony_ci /* can happen while switching links */ 189262306a36Sopenharmony_ci if (!rcu_access_pointer(bss_conf->chanctx_conf)) 189362306a36Sopenharmony_ci continue; 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci sp->last_link = link_id; 189662306a36Sopenharmony_ci return bss_conf; 189762306a36Sopenharmony_ci } 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci return NULL; 190062306a36Sopenharmony_ci} 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_cistatic void mac80211_hwsim_tx(struct ieee80211_hw *hw, 190362306a36Sopenharmony_ci struct ieee80211_tx_control *control, 190462306a36Sopenharmony_ci struct sk_buff *skb) 190562306a36Sopenharmony_ci{ 190662306a36Sopenharmony_ci struct mac80211_hwsim_data *data = hw->priv; 190762306a36Sopenharmony_ci struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb); 190862306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (void *)skb->data; 190962306a36Sopenharmony_ci struct ieee80211_chanctx_conf *chanctx_conf; 191062306a36Sopenharmony_ci struct ieee80211_channel *channel; 191162306a36Sopenharmony_ci bool ack; 191262306a36Sopenharmony_ci enum nl80211_chan_width confbw = NL80211_CHAN_WIDTH_20_NOHT; 191362306a36Sopenharmony_ci u32 _portid, i; 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_ci if (WARN_ON(skb->len < 10)) { 191662306a36Sopenharmony_ci /* Should not happen; just a sanity check for addr1 use */ 191762306a36Sopenharmony_ci ieee80211_free_txskb(hw, skb); 191862306a36Sopenharmony_ci return; 191962306a36Sopenharmony_ci } 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_ci if (!data->use_chanctx) { 192262306a36Sopenharmony_ci channel = data->channel; 192362306a36Sopenharmony_ci confbw = data->bw; 192462306a36Sopenharmony_ci } else if (txi->hw_queue == 4) { 192562306a36Sopenharmony_ci channel = data->tmp_chan; 192662306a36Sopenharmony_ci } else { 192762306a36Sopenharmony_ci u8 link = u32_get_bits(IEEE80211_SKB_CB(skb)->control.flags, 192862306a36Sopenharmony_ci IEEE80211_TX_CTRL_MLO_LINK); 192962306a36Sopenharmony_ci struct ieee80211_vif *vif = txi->control.vif; 193062306a36Sopenharmony_ci struct ieee80211_link_sta *link_sta = NULL; 193162306a36Sopenharmony_ci struct ieee80211_sta *sta = control->sta; 193262306a36Sopenharmony_ci struct ieee80211_bss_conf *bss_conf; 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_ci if (link != IEEE80211_LINK_UNSPECIFIED) { 193562306a36Sopenharmony_ci bss_conf = rcu_dereference(txi->control.vif->link_conf[link]); 193662306a36Sopenharmony_ci if (sta) 193762306a36Sopenharmony_ci link_sta = rcu_dereference(sta->link[link]); 193862306a36Sopenharmony_ci } else { 193962306a36Sopenharmony_ci bss_conf = mac80211_hwsim_select_tx_link(data, vif, sta, 194062306a36Sopenharmony_ci hdr, &link_sta); 194162306a36Sopenharmony_ci } 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_ci if (unlikely(!bss_conf)) { 194462306a36Sopenharmony_ci /* if it's an MLO STA, it might have deactivated all 194562306a36Sopenharmony_ci * links temporarily - but we don't handle real PS in 194662306a36Sopenharmony_ci * this code yet, so just drop the frame in that case 194762306a36Sopenharmony_ci */ 194862306a36Sopenharmony_ci WARN(link != IEEE80211_LINK_UNSPECIFIED || !sta || !sta->mlo, 194962306a36Sopenharmony_ci "link:%d, sta:%pM, sta->mlo:%d\n", 195062306a36Sopenharmony_ci link, sta ? sta->addr : NULL, sta ? sta->mlo : -1); 195162306a36Sopenharmony_ci ieee80211_free_txskb(hw, skb); 195262306a36Sopenharmony_ci return; 195362306a36Sopenharmony_ci } 195462306a36Sopenharmony_ci 195562306a36Sopenharmony_ci if (sta && sta->mlo) { 195662306a36Sopenharmony_ci if (WARN_ON(!link_sta)) { 195762306a36Sopenharmony_ci ieee80211_free_txskb(hw, skb); 195862306a36Sopenharmony_ci return; 195962306a36Sopenharmony_ci } 196062306a36Sopenharmony_ci /* address translation to link addresses on TX */ 196162306a36Sopenharmony_ci ether_addr_copy(hdr->addr1, link_sta->addr); 196262306a36Sopenharmony_ci ether_addr_copy(hdr->addr2, bss_conf->addr); 196362306a36Sopenharmony_ci /* translate A3 only if it's the BSSID */ 196462306a36Sopenharmony_ci if (!ieee80211_has_tods(hdr->frame_control) && 196562306a36Sopenharmony_ci !ieee80211_has_fromds(hdr->frame_control)) { 196662306a36Sopenharmony_ci if (ether_addr_equal(hdr->addr3, sta->addr)) 196762306a36Sopenharmony_ci ether_addr_copy(hdr->addr3, link_sta->addr); 196862306a36Sopenharmony_ci else if (ether_addr_equal(hdr->addr3, vif->addr)) 196962306a36Sopenharmony_ci ether_addr_copy(hdr->addr3, bss_conf->addr); 197062306a36Sopenharmony_ci } 197162306a36Sopenharmony_ci /* no need to look at A4, if present it's SA */ 197262306a36Sopenharmony_ci } 197362306a36Sopenharmony_ci 197462306a36Sopenharmony_ci chanctx_conf = rcu_dereference(bss_conf->chanctx_conf); 197562306a36Sopenharmony_ci if (chanctx_conf) { 197662306a36Sopenharmony_ci channel = chanctx_conf->def.chan; 197762306a36Sopenharmony_ci confbw = chanctx_conf->def.width; 197862306a36Sopenharmony_ci } else { 197962306a36Sopenharmony_ci channel = NULL; 198062306a36Sopenharmony_ci } 198162306a36Sopenharmony_ci } 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci if (WARN(!channel, "TX w/o channel - queue = %d\n", txi->hw_queue)) { 198462306a36Sopenharmony_ci ieee80211_free_txskb(hw, skb); 198562306a36Sopenharmony_ci return; 198662306a36Sopenharmony_ci } 198762306a36Sopenharmony_ci 198862306a36Sopenharmony_ci if (data->idle && !data->tmp_chan) { 198962306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, "Trying to TX when idle - reject\n"); 199062306a36Sopenharmony_ci ieee80211_free_txskb(hw, skb); 199162306a36Sopenharmony_ci return; 199262306a36Sopenharmony_ci } 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_ci if (txi->control.vif) 199562306a36Sopenharmony_ci hwsim_check_magic(txi->control.vif); 199662306a36Sopenharmony_ci if (control->sta) 199762306a36Sopenharmony_ci hwsim_check_sta_magic(control->sta); 199862306a36Sopenharmony_ci 199962306a36Sopenharmony_ci if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE)) 200062306a36Sopenharmony_ci ieee80211_get_tx_rates(txi->control.vif, control->sta, skb, 200162306a36Sopenharmony_ci txi->control.rates, 200262306a36Sopenharmony_ci ARRAY_SIZE(txi->control.rates)); 200362306a36Sopenharmony_ci 200462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(txi->control.rates); i++) { 200562306a36Sopenharmony_ci u16 rflags = txi->control.rates[i].flags; 200662306a36Sopenharmony_ci /* initialize to data->bw for 5/10 MHz handling */ 200762306a36Sopenharmony_ci enum nl80211_chan_width bw = data->bw; 200862306a36Sopenharmony_ci 200962306a36Sopenharmony_ci if (txi->control.rates[i].idx == -1) 201062306a36Sopenharmony_ci break; 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_ci if (rflags & IEEE80211_TX_RC_40_MHZ_WIDTH) 201362306a36Sopenharmony_ci bw = NL80211_CHAN_WIDTH_40; 201462306a36Sopenharmony_ci else if (rflags & IEEE80211_TX_RC_80_MHZ_WIDTH) 201562306a36Sopenharmony_ci bw = NL80211_CHAN_WIDTH_80; 201662306a36Sopenharmony_ci else if (rflags & IEEE80211_TX_RC_160_MHZ_WIDTH) 201762306a36Sopenharmony_ci bw = NL80211_CHAN_WIDTH_160; 201862306a36Sopenharmony_ci 201962306a36Sopenharmony_ci if (WARN_ON(hwsim_get_chanwidth(bw) > hwsim_get_chanwidth(confbw))) 202062306a36Sopenharmony_ci return; 202162306a36Sopenharmony_ci } 202262306a36Sopenharmony_ci 202362306a36Sopenharmony_ci if (skb->len >= 24 + 8 && 202462306a36Sopenharmony_ci ieee80211_is_probe_resp(hdr->frame_control)) { 202562306a36Sopenharmony_ci /* fake header transmission time */ 202662306a36Sopenharmony_ci struct ieee80211_mgmt *mgmt; 202762306a36Sopenharmony_ci struct ieee80211_rate *txrate; 202862306a36Sopenharmony_ci /* TODO: get MCS */ 202962306a36Sopenharmony_ci int bitrate = 100; 203062306a36Sopenharmony_ci u64 ts; 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_ci mgmt = (struct ieee80211_mgmt *)skb->data; 203362306a36Sopenharmony_ci txrate = ieee80211_get_tx_rate(hw, txi); 203462306a36Sopenharmony_ci if (txrate) 203562306a36Sopenharmony_ci bitrate = txrate->bitrate; 203662306a36Sopenharmony_ci ts = mac80211_hwsim_get_tsf_raw(); 203762306a36Sopenharmony_ci mgmt->u.probe_resp.timestamp = 203862306a36Sopenharmony_ci cpu_to_le64(ts + data->tsf_offset + 203962306a36Sopenharmony_ci 24 * 8 * 10 / bitrate); 204062306a36Sopenharmony_ci } 204162306a36Sopenharmony_ci 204262306a36Sopenharmony_ci mac80211_hwsim_monitor_rx(hw, skb, channel); 204362306a36Sopenharmony_ci 204462306a36Sopenharmony_ci /* wmediumd mode check */ 204562306a36Sopenharmony_ci _portid = READ_ONCE(data->wmediumd); 204662306a36Sopenharmony_ci 204762306a36Sopenharmony_ci if (_portid || hwsim_virtio_enabled) 204862306a36Sopenharmony_ci return mac80211_hwsim_tx_frame_nl(hw, skb, _portid, channel); 204962306a36Sopenharmony_ci 205062306a36Sopenharmony_ci /* NO wmediumd detected, perfect medium simulation */ 205162306a36Sopenharmony_ci data->tx_pkts++; 205262306a36Sopenharmony_ci data->tx_bytes += skb->len; 205362306a36Sopenharmony_ci ack = mac80211_hwsim_tx_frame_no_nl(hw, skb, channel); 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_ci if (ack && skb->len >= 16) 205662306a36Sopenharmony_ci mac80211_hwsim_monitor_ack(channel, hdr->addr2); 205762306a36Sopenharmony_ci 205862306a36Sopenharmony_ci ieee80211_tx_info_clear_status(txi); 205962306a36Sopenharmony_ci 206062306a36Sopenharmony_ci /* frame was transmitted at most favorable rate at first attempt */ 206162306a36Sopenharmony_ci txi->control.rates[0].count = 1; 206262306a36Sopenharmony_ci txi->control.rates[1].idx = -1; 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_ci if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) && ack) 206562306a36Sopenharmony_ci txi->flags |= IEEE80211_TX_STAT_ACK; 206662306a36Sopenharmony_ci ieee80211_tx_status_irqsafe(hw, skb); 206762306a36Sopenharmony_ci} 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_ci 207062306a36Sopenharmony_cistatic int mac80211_hwsim_start(struct ieee80211_hw *hw) 207162306a36Sopenharmony_ci{ 207262306a36Sopenharmony_ci struct mac80211_hwsim_data *data = hw->priv; 207362306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, "%s\n", __func__); 207462306a36Sopenharmony_ci data->started = true; 207562306a36Sopenharmony_ci return 0; 207662306a36Sopenharmony_ci} 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_ci 207962306a36Sopenharmony_cistatic void mac80211_hwsim_stop(struct ieee80211_hw *hw) 208062306a36Sopenharmony_ci{ 208162306a36Sopenharmony_ci struct mac80211_hwsim_data *data = hw->priv; 208262306a36Sopenharmony_ci int i; 208362306a36Sopenharmony_ci 208462306a36Sopenharmony_ci data->started = false; 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(data->link_data); i++) 208762306a36Sopenharmony_ci hrtimer_cancel(&data->link_data[i].beacon_timer); 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_ci while (!skb_queue_empty(&data->pending)) 209062306a36Sopenharmony_ci ieee80211_free_txskb(hw, skb_dequeue(&data->pending)); 209162306a36Sopenharmony_ci 209262306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, "%s\n", __func__); 209362306a36Sopenharmony_ci} 209462306a36Sopenharmony_ci 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_cistatic int mac80211_hwsim_add_interface(struct ieee80211_hw *hw, 209762306a36Sopenharmony_ci struct ieee80211_vif *vif) 209862306a36Sopenharmony_ci{ 209962306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, "%s (type=%d mac_addr=%pM)\n", 210062306a36Sopenharmony_ci __func__, ieee80211_vif_type_p2p(vif), 210162306a36Sopenharmony_ci vif->addr); 210262306a36Sopenharmony_ci hwsim_set_magic(vif); 210362306a36Sopenharmony_ci 210462306a36Sopenharmony_ci if (vif->type != NL80211_IFTYPE_MONITOR) 210562306a36Sopenharmony_ci mac80211_hwsim_config_mac_nl(hw, vif->addr, true); 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_ci vif->cab_queue = 0; 210862306a36Sopenharmony_ci vif->hw_queue[IEEE80211_AC_VO] = 0; 210962306a36Sopenharmony_ci vif->hw_queue[IEEE80211_AC_VI] = 1; 211062306a36Sopenharmony_ci vif->hw_queue[IEEE80211_AC_BE] = 2; 211162306a36Sopenharmony_ci vif->hw_queue[IEEE80211_AC_BK] = 3; 211262306a36Sopenharmony_ci 211362306a36Sopenharmony_ci return 0; 211462306a36Sopenharmony_ci} 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_cistatic int mac80211_hwsim_change_interface(struct ieee80211_hw *hw, 211862306a36Sopenharmony_ci struct ieee80211_vif *vif, 211962306a36Sopenharmony_ci enum nl80211_iftype newtype, 212062306a36Sopenharmony_ci bool newp2p) 212162306a36Sopenharmony_ci{ 212262306a36Sopenharmony_ci newtype = ieee80211_iftype_p2p(newtype, newp2p); 212362306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, 212462306a36Sopenharmony_ci "%s (old type=%d, new type=%d, mac_addr=%pM)\n", 212562306a36Sopenharmony_ci __func__, ieee80211_vif_type_p2p(vif), 212662306a36Sopenharmony_ci newtype, vif->addr); 212762306a36Sopenharmony_ci hwsim_check_magic(vif); 212862306a36Sopenharmony_ci 212962306a36Sopenharmony_ci /* 213062306a36Sopenharmony_ci * interface may change from non-AP to AP in 213162306a36Sopenharmony_ci * which case this needs to be set up again 213262306a36Sopenharmony_ci */ 213362306a36Sopenharmony_ci vif->cab_queue = 0; 213462306a36Sopenharmony_ci 213562306a36Sopenharmony_ci return 0; 213662306a36Sopenharmony_ci} 213762306a36Sopenharmony_ci 213862306a36Sopenharmony_cistatic void mac80211_hwsim_remove_interface( 213962306a36Sopenharmony_ci struct ieee80211_hw *hw, struct ieee80211_vif *vif) 214062306a36Sopenharmony_ci{ 214162306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, "%s (type=%d mac_addr=%pM)\n", 214262306a36Sopenharmony_ci __func__, ieee80211_vif_type_p2p(vif), 214362306a36Sopenharmony_ci vif->addr); 214462306a36Sopenharmony_ci hwsim_check_magic(vif); 214562306a36Sopenharmony_ci hwsim_clear_magic(vif); 214662306a36Sopenharmony_ci if (vif->type != NL80211_IFTYPE_MONITOR) 214762306a36Sopenharmony_ci mac80211_hwsim_config_mac_nl(hw, vif->addr, false); 214862306a36Sopenharmony_ci} 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_cistatic void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, 215162306a36Sopenharmony_ci struct sk_buff *skb, 215262306a36Sopenharmony_ci struct ieee80211_channel *chan) 215362306a36Sopenharmony_ci{ 215462306a36Sopenharmony_ci struct mac80211_hwsim_data *data = hw->priv; 215562306a36Sopenharmony_ci u32 _portid = READ_ONCE(data->wmediumd); 215662306a36Sopenharmony_ci 215762306a36Sopenharmony_ci if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE)) { 215862306a36Sopenharmony_ci struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb); 215962306a36Sopenharmony_ci ieee80211_get_tx_rates(txi->control.vif, NULL, skb, 216062306a36Sopenharmony_ci txi->control.rates, 216162306a36Sopenharmony_ci ARRAY_SIZE(txi->control.rates)); 216262306a36Sopenharmony_ci } 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci mac80211_hwsim_monitor_rx(hw, skb, chan); 216562306a36Sopenharmony_ci 216662306a36Sopenharmony_ci if (_portid || hwsim_virtio_enabled) 216762306a36Sopenharmony_ci return mac80211_hwsim_tx_frame_nl(hw, skb, _portid, chan); 216862306a36Sopenharmony_ci 216962306a36Sopenharmony_ci data->tx_pkts++; 217062306a36Sopenharmony_ci data->tx_bytes += skb->len; 217162306a36Sopenharmony_ci mac80211_hwsim_tx_frame_no_nl(hw, skb, chan); 217262306a36Sopenharmony_ci dev_kfree_skb(skb); 217362306a36Sopenharmony_ci} 217462306a36Sopenharmony_ci 217562306a36Sopenharmony_cistatic void __mac80211_hwsim_beacon_tx(struct ieee80211_bss_conf *link_conf, 217662306a36Sopenharmony_ci struct mac80211_hwsim_data *data, 217762306a36Sopenharmony_ci struct ieee80211_hw *hw, 217862306a36Sopenharmony_ci struct ieee80211_vif *vif, 217962306a36Sopenharmony_ci struct sk_buff *skb) 218062306a36Sopenharmony_ci{ 218162306a36Sopenharmony_ci struct ieee80211_tx_info *info; 218262306a36Sopenharmony_ci struct ieee80211_rate *txrate; 218362306a36Sopenharmony_ci struct ieee80211_mgmt *mgmt; 218462306a36Sopenharmony_ci /* TODO: get MCS */ 218562306a36Sopenharmony_ci int bitrate = 100; 218662306a36Sopenharmony_ci 218762306a36Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 218862306a36Sopenharmony_ci if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE)) 218962306a36Sopenharmony_ci ieee80211_get_tx_rates(vif, NULL, skb, 219062306a36Sopenharmony_ci info->control.rates, 219162306a36Sopenharmony_ci ARRAY_SIZE(info->control.rates)); 219262306a36Sopenharmony_ci 219362306a36Sopenharmony_ci txrate = ieee80211_get_tx_rate(hw, info); 219462306a36Sopenharmony_ci if (txrate) 219562306a36Sopenharmony_ci bitrate = txrate->bitrate; 219662306a36Sopenharmony_ci 219762306a36Sopenharmony_ci mgmt = (struct ieee80211_mgmt *) skb->data; 219862306a36Sopenharmony_ci /* fake header transmission time */ 219962306a36Sopenharmony_ci data->abs_bcn_ts = mac80211_hwsim_get_tsf_raw(); 220062306a36Sopenharmony_ci if (ieee80211_is_s1g_beacon(mgmt->frame_control)) { 220162306a36Sopenharmony_ci struct ieee80211_ext *ext = (void *) mgmt; 220262306a36Sopenharmony_ci 220362306a36Sopenharmony_ci ext->u.s1g_beacon.timestamp = cpu_to_le32(data->abs_bcn_ts + 220462306a36Sopenharmony_ci data->tsf_offset + 220562306a36Sopenharmony_ci 10 * 8 * 10 / 220662306a36Sopenharmony_ci bitrate); 220762306a36Sopenharmony_ci } else { 220862306a36Sopenharmony_ci mgmt->u.beacon.timestamp = cpu_to_le64(data->abs_bcn_ts + 220962306a36Sopenharmony_ci data->tsf_offset + 221062306a36Sopenharmony_ci 24 * 8 * 10 / 221162306a36Sopenharmony_ci bitrate); 221262306a36Sopenharmony_ci } 221362306a36Sopenharmony_ci 221462306a36Sopenharmony_ci mac80211_hwsim_tx_frame(hw, skb, 221562306a36Sopenharmony_ci rcu_dereference(link_conf->chanctx_conf)->def.chan); 221662306a36Sopenharmony_ci} 221762306a36Sopenharmony_ci 221862306a36Sopenharmony_cistatic void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, 221962306a36Sopenharmony_ci struct ieee80211_vif *vif) 222062306a36Sopenharmony_ci{ 222162306a36Sopenharmony_ci struct mac80211_hwsim_link_data *link_data = arg; 222262306a36Sopenharmony_ci u32 link_id = link_data->link_id; 222362306a36Sopenharmony_ci struct ieee80211_bss_conf *link_conf; 222462306a36Sopenharmony_ci struct mac80211_hwsim_data *data = 222562306a36Sopenharmony_ci container_of(link_data, struct mac80211_hwsim_data, 222662306a36Sopenharmony_ci link_data[link_id]); 222762306a36Sopenharmony_ci struct ieee80211_hw *hw = data->hw; 222862306a36Sopenharmony_ci struct sk_buff *skb; 222962306a36Sopenharmony_ci 223062306a36Sopenharmony_ci hwsim_check_magic(vif); 223162306a36Sopenharmony_ci 223262306a36Sopenharmony_ci link_conf = rcu_dereference(vif->link_conf[link_id]); 223362306a36Sopenharmony_ci if (!link_conf) 223462306a36Sopenharmony_ci return; 223562306a36Sopenharmony_ci 223662306a36Sopenharmony_ci if (vif->type != NL80211_IFTYPE_AP && 223762306a36Sopenharmony_ci vif->type != NL80211_IFTYPE_MESH_POINT && 223862306a36Sopenharmony_ci vif->type != NL80211_IFTYPE_ADHOC && 223962306a36Sopenharmony_ci vif->type != NL80211_IFTYPE_OCB) 224062306a36Sopenharmony_ci return; 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_ci if (vif->mbssid_tx_vif && vif->mbssid_tx_vif != vif) 224362306a36Sopenharmony_ci return; 224462306a36Sopenharmony_ci 224562306a36Sopenharmony_ci if (vif->bss_conf.ema_ap) { 224662306a36Sopenharmony_ci struct ieee80211_ema_beacons *ema; 224762306a36Sopenharmony_ci u8 i = 0; 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_ci ema = ieee80211_beacon_get_template_ema_list(hw, vif, link_id); 225062306a36Sopenharmony_ci if (!ema || !ema->cnt) 225162306a36Sopenharmony_ci return; 225262306a36Sopenharmony_ci 225362306a36Sopenharmony_ci for (i = 0; i < ema->cnt; i++) { 225462306a36Sopenharmony_ci __mac80211_hwsim_beacon_tx(link_conf, data, hw, vif, 225562306a36Sopenharmony_ci ema->bcn[i].skb); 225662306a36Sopenharmony_ci ema->bcn[i].skb = NULL; /* Already freed */ 225762306a36Sopenharmony_ci } 225862306a36Sopenharmony_ci ieee80211_beacon_free_ema_list(ema); 225962306a36Sopenharmony_ci } else { 226062306a36Sopenharmony_ci skb = ieee80211_beacon_get(hw, vif, link_id); 226162306a36Sopenharmony_ci if (!skb) 226262306a36Sopenharmony_ci return; 226362306a36Sopenharmony_ci 226462306a36Sopenharmony_ci __mac80211_hwsim_beacon_tx(link_conf, data, hw, vif, skb); 226562306a36Sopenharmony_ci } 226662306a36Sopenharmony_ci 226762306a36Sopenharmony_ci while ((skb = ieee80211_get_buffered_bc(hw, vif)) != NULL) { 226862306a36Sopenharmony_ci mac80211_hwsim_tx_frame(hw, skb, 226962306a36Sopenharmony_ci rcu_dereference(link_conf->chanctx_conf)->def.chan); 227062306a36Sopenharmony_ci } 227162306a36Sopenharmony_ci 227262306a36Sopenharmony_ci if (link_conf->csa_active && ieee80211_beacon_cntdwn_is_complete(vif)) 227362306a36Sopenharmony_ci ieee80211_csa_finish(vif); 227462306a36Sopenharmony_ci} 227562306a36Sopenharmony_ci 227662306a36Sopenharmony_cistatic enum hrtimer_restart 227762306a36Sopenharmony_cimac80211_hwsim_beacon(struct hrtimer *timer) 227862306a36Sopenharmony_ci{ 227962306a36Sopenharmony_ci struct mac80211_hwsim_link_data *link_data = 228062306a36Sopenharmony_ci container_of(timer, struct mac80211_hwsim_link_data, beacon_timer); 228162306a36Sopenharmony_ci struct mac80211_hwsim_data *data = 228262306a36Sopenharmony_ci container_of(link_data, struct mac80211_hwsim_data, 228362306a36Sopenharmony_ci link_data[link_data->link_id]); 228462306a36Sopenharmony_ci struct ieee80211_hw *hw = data->hw; 228562306a36Sopenharmony_ci u64 bcn_int = link_data->beacon_int; 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_ci if (!data->started) 228862306a36Sopenharmony_ci return HRTIMER_NORESTART; 228962306a36Sopenharmony_ci 229062306a36Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic( 229162306a36Sopenharmony_ci hw, IEEE80211_IFACE_ITER_NORMAL, 229262306a36Sopenharmony_ci mac80211_hwsim_beacon_tx, link_data); 229362306a36Sopenharmony_ci 229462306a36Sopenharmony_ci /* beacon at new TBTT + beacon interval */ 229562306a36Sopenharmony_ci if (data->bcn_delta) { 229662306a36Sopenharmony_ci bcn_int -= data->bcn_delta; 229762306a36Sopenharmony_ci data->bcn_delta = 0; 229862306a36Sopenharmony_ci } 229962306a36Sopenharmony_ci hrtimer_forward_now(&link_data->beacon_timer, 230062306a36Sopenharmony_ci ns_to_ktime(bcn_int * NSEC_PER_USEC)); 230162306a36Sopenharmony_ci return HRTIMER_RESTART; 230262306a36Sopenharmony_ci} 230362306a36Sopenharmony_ci 230462306a36Sopenharmony_cistatic const char * const hwsim_chanwidths[] = { 230562306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_5] = "ht5", 230662306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_10] = "ht10", 230762306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_20_NOHT] = "noht", 230862306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_20] = "ht20", 230962306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_40] = "ht40", 231062306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_80] = "vht80", 231162306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_80P80] = "vht80p80", 231262306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_160] = "vht160", 231362306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_1] = "1MHz", 231462306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_2] = "2MHz", 231562306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_4] = "4MHz", 231662306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_8] = "8MHz", 231762306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_16] = "16MHz", 231862306a36Sopenharmony_ci}; 231962306a36Sopenharmony_ci 232062306a36Sopenharmony_cistatic int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) 232162306a36Sopenharmony_ci{ 232262306a36Sopenharmony_ci struct mac80211_hwsim_data *data = hw->priv; 232362306a36Sopenharmony_ci struct ieee80211_conf *conf = &hw->conf; 232462306a36Sopenharmony_ci static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = { 232562306a36Sopenharmony_ci [IEEE80211_SMPS_AUTOMATIC] = "auto", 232662306a36Sopenharmony_ci [IEEE80211_SMPS_OFF] = "off", 232762306a36Sopenharmony_ci [IEEE80211_SMPS_STATIC] = "static", 232862306a36Sopenharmony_ci [IEEE80211_SMPS_DYNAMIC] = "dynamic", 232962306a36Sopenharmony_ci }; 233062306a36Sopenharmony_ci int idx; 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_ci if (conf->chandef.chan) 233362306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, 233462306a36Sopenharmony_ci "%s (freq=%d(%d - %d)/%s idle=%d ps=%d smps=%s)\n", 233562306a36Sopenharmony_ci __func__, 233662306a36Sopenharmony_ci conf->chandef.chan->center_freq, 233762306a36Sopenharmony_ci conf->chandef.center_freq1, 233862306a36Sopenharmony_ci conf->chandef.center_freq2, 233962306a36Sopenharmony_ci hwsim_chanwidths[conf->chandef.width], 234062306a36Sopenharmony_ci !!(conf->flags & IEEE80211_CONF_IDLE), 234162306a36Sopenharmony_ci !!(conf->flags & IEEE80211_CONF_PS), 234262306a36Sopenharmony_ci smps_modes[conf->smps_mode]); 234362306a36Sopenharmony_ci else 234462306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, 234562306a36Sopenharmony_ci "%s (freq=0 idle=%d ps=%d smps=%s)\n", 234662306a36Sopenharmony_ci __func__, 234762306a36Sopenharmony_ci !!(conf->flags & IEEE80211_CONF_IDLE), 234862306a36Sopenharmony_ci !!(conf->flags & IEEE80211_CONF_PS), 234962306a36Sopenharmony_ci smps_modes[conf->smps_mode]); 235062306a36Sopenharmony_ci 235162306a36Sopenharmony_ci data->idle = !!(conf->flags & IEEE80211_CONF_IDLE); 235262306a36Sopenharmony_ci 235362306a36Sopenharmony_ci WARN_ON(conf->chandef.chan && data->use_chanctx); 235462306a36Sopenharmony_ci 235562306a36Sopenharmony_ci mutex_lock(&data->mutex); 235662306a36Sopenharmony_ci if (data->scanning && conf->chandef.chan) { 235762306a36Sopenharmony_ci for (idx = 0; idx < ARRAY_SIZE(data->survey_data); idx++) { 235862306a36Sopenharmony_ci if (data->survey_data[idx].channel == data->channel) { 235962306a36Sopenharmony_ci data->survey_data[idx].start = 236062306a36Sopenharmony_ci data->survey_data[idx].next_start; 236162306a36Sopenharmony_ci data->survey_data[idx].end = jiffies; 236262306a36Sopenharmony_ci break; 236362306a36Sopenharmony_ci } 236462306a36Sopenharmony_ci } 236562306a36Sopenharmony_ci 236662306a36Sopenharmony_ci data->channel = conf->chandef.chan; 236762306a36Sopenharmony_ci data->bw = conf->chandef.width; 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_ci for (idx = 0; idx < ARRAY_SIZE(data->survey_data); idx++) { 237062306a36Sopenharmony_ci if (data->survey_data[idx].channel && 237162306a36Sopenharmony_ci data->survey_data[idx].channel != data->channel) 237262306a36Sopenharmony_ci continue; 237362306a36Sopenharmony_ci data->survey_data[idx].channel = data->channel; 237462306a36Sopenharmony_ci data->survey_data[idx].next_start = jiffies; 237562306a36Sopenharmony_ci break; 237662306a36Sopenharmony_ci } 237762306a36Sopenharmony_ci } else { 237862306a36Sopenharmony_ci data->channel = conf->chandef.chan; 237962306a36Sopenharmony_ci data->bw = conf->chandef.width; 238062306a36Sopenharmony_ci } 238162306a36Sopenharmony_ci mutex_unlock(&data->mutex); 238262306a36Sopenharmony_ci 238362306a36Sopenharmony_ci for (idx = 0; idx < ARRAY_SIZE(data->link_data); idx++) { 238462306a36Sopenharmony_ci struct mac80211_hwsim_link_data *link_data = 238562306a36Sopenharmony_ci &data->link_data[idx]; 238662306a36Sopenharmony_ci 238762306a36Sopenharmony_ci if (!data->started || !link_data->beacon_int) { 238862306a36Sopenharmony_ci hrtimer_cancel(&link_data->beacon_timer); 238962306a36Sopenharmony_ci } else if (!hrtimer_is_queued(&link_data->beacon_timer)) { 239062306a36Sopenharmony_ci u64 tsf = mac80211_hwsim_get_tsf(hw, NULL); 239162306a36Sopenharmony_ci u32 bcn_int = link_data->beacon_int; 239262306a36Sopenharmony_ci u64 until_tbtt = bcn_int - do_div(tsf, bcn_int); 239362306a36Sopenharmony_ci 239462306a36Sopenharmony_ci hrtimer_start(&link_data->beacon_timer, 239562306a36Sopenharmony_ci ns_to_ktime(until_tbtt * NSEC_PER_USEC), 239662306a36Sopenharmony_ci HRTIMER_MODE_REL_SOFT); 239762306a36Sopenharmony_ci } 239862306a36Sopenharmony_ci } 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_ci return 0; 240162306a36Sopenharmony_ci} 240262306a36Sopenharmony_ci 240362306a36Sopenharmony_ci 240462306a36Sopenharmony_cistatic void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw, 240562306a36Sopenharmony_ci unsigned int changed_flags, 240662306a36Sopenharmony_ci unsigned int *total_flags,u64 multicast) 240762306a36Sopenharmony_ci{ 240862306a36Sopenharmony_ci struct mac80211_hwsim_data *data = hw->priv; 240962306a36Sopenharmony_ci 241062306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, "%s\n", __func__); 241162306a36Sopenharmony_ci 241262306a36Sopenharmony_ci data->rx_filter = 0; 241362306a36Sopenharmony_ci if (*total_flags & FIF_ALLMULTI) 241462306a36Sopenharmony_ci data->rx_filter |= FIF_ALLMULTI; 241562306a36Sopenharmony_ci if (*total_flags & FIF_MCAST_ACTION) 241662306a36Sopenharmony_ci data->rx_filter |= FIF_MCAST_ACTION; 241762306a36Sopenharmony_ci 241862306a36Sopenharmony_ci *total_flags = data->rx_filter; 241962306a36Sopenharmony_ci} 242062306a36Sopenharmony_ci 242162306a36Sopenharmony_cistatic void mac80211_hwsim_bcn_en_iter(void *data, u8 *mac, 242262306a36Sopenharmony_ci struct ieee80211_vif *vif) 242362306a36Sopenharmony_ci{ 242462306a36Sopenharmony_ci unsigned int *count = data; 242562306a36Sopenharmony_ci struct hwsim_vif_priv *vp = (void *)vif->drv_priv; 242662306a36Sopenharmony_ci 242762306a36Sopenharmony_ci if (vp->bcn_en) 242862306a36Sopenharmony_ci (*count)++; 242962306a36Sopenharmony_ci} 243062306a36Sopenharmony_ci 243162306a36Sopenharmony_cistatic void mac80211_hwsim_vif_info_changed(struct ieee80211_hw *hw, 243262306a36Sopenharmony_ci struct ieee80211_vif *vif, 243362306a36Sopenharmony_ci u64 changed) 243462306a36Sopenharmony_ci{ 243562306a36Sopenharmony_ci struct hwsim_vif_priv *vp = (void *)vif->drv_priv; 243662306a36Sopenharmony_ci 243762306a36Sopenharmony_ci hwsim_check_magic(vif); 243862306a36Sopenharmony_ci 243962306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, "%s(changed=0x%llx vif->addr=%pM)\n", 244062306a36Sopenharmony_ci __func__, changed, vif->addr); 244162306a36Sopenharmony_ci 244262306a36Sopenharmony_ci if (changed & BSS_CHANGED_ASSOC) { 244362306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, " ASSOC: assoc=%d aid=%d\n", 244462306a36Sopenharmony_ci vif->cfg.assoc, vif->cfg.aid); 244562306a36Sopenharmony_ci vp->assoc = vif->cfg.assoc; 244662306a36Sopenharmony_ci vp->aid = vif->cfg.aid; 244762306a36Sopenharmony_ci } 244862306a36Sopenharmony_ci} 244962306a36Sopenharmony_ci 245062306a36Sopenharmony_cistatic void mac80211_hwsim_link_info_changed(struct ieee80211_hw *hw, 245162306a36Sopenharmony_ci struct ieee80211_vif *vif, 245262306a36Sopenharmony_ci struct ieee80211_bss_conf *info, 245362306a36Sopenharmony_ci u64 changed) 245462306a36Sopenharmony_ci{ 245562306a36Sopenharmony_ci struct hwsim_vif_priv *vp = (void *)vif->drv_priv; 245662306a36Sopenharmony_ci struct mac80211_hwsim_data *data = hw->priv; 245762306a36Sopenharmony_ci unsigned int link_id = info->link_id; 245862306a36Sopenharmony_ci struct mac80211_hwsim_link_data *link_data = &data->link_data[link_id]; 245962306a36Sopenharmony_ci 246062306a36Sopenharmony_ci hwsim_check_magic(vif); 246162306a36Sopenharmony_ci 246262306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, "%s(changed=0x%llx vif->addr=%pM, link id %u)\n", 246362306a36Sopenharmony_ci __func__, (unsigned long long)changed, vif->addr, link_id); 246462306a36Sopenharmony_ci 246562306a36Sopenharmony_ci if (changed & BSS_CHANGED_BSSID) { 246662306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, "%s: BSSID changed: %pM\n", 246762306a36Sopenharmony_ci __func__, info->bssid); 246862306a36Sopenharmony_ci memcpy(vp->bssid, info->bssid, ETH_ALEN); 246962306a36Sopenharmony_ci } 247062306a36Sopenharmony_ci 247162306a36Sopenharmony_ci if (changed & BSS_CHANGED_BEACON_ENABLED) { 247262306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, " BCN EN: %d (BI=%u)\n", 247362306a36Sopenharmony_ci info->enable_beacon, info->beacon_int); 247462306a36Sopenharmony_ci vp->bcn_en = info->enable_beacon; 247562306a36Sopenharmony_ci if (data->started && 247662306a36Sopenharmony_ci !hrtimer_is_queued(&link_data->beacon_timer) && 247762306a36Sopenharmony_ci info->enable_beacon) { 247862306a36Sopenharmony_ci u64 tsf, until_tbtt; 247962306a36Sopenharmony_ci u32 bcn_int; 248062306a36Sopenharmony_ci link_data->beacon_int = info->beacon_int * 1024; 248162306a36Sopenharmony_ci tsf = mac80211_hwsim_get_tsf(hw, vif); 248262306a36Sopenharmony_ci bcn_int = link_data->beacon_int; 248362306a36Sopenharmony_ci until_tbtt = bcn_int - do_div(tsf, bcn_int); 248462306a36Sopenharmony_ci 248562306a36Sopenharmony_ci hrtimer_start(&link_data->beacon_timer, 248662306a36Sopenharmony_ci ns_to_ktime(until_tbtt * NSEC_PER_USEC), 248762306a36Sopenharmony_ci HRTIMER_MODE_REL_SOFT); 248862306a36Sopenharmony_ci } else if (!info->enable_beacon) { 248962306a36Sopenharmony_ci unsigned int count = 0; 249062306a36Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic( 249162306a36Sopenharmony_ci data->hw, IEEE80211_IFACE_ITER_NORMAL, 249262306a36Sopenharmony_ci mac80211_hwsim_bcn_en_iter, &count); 249362306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, " beaconing vifs remaining: %u", 249462306a36Sopenharmony_ci count); 249562306a36Sopenharmony_ci if (count == 0) { 249662306a36Sopenharmony_ci hrtimer_cancel(&link_data->beacon_timer); 249762306a36Sopenharmony_ci link_data->beacon_int = 0; 249862306a36Sopenharmony_ci } 249962306a36Sopenharmony_ci } 250062306a36Sopenharmony_ci } 250162306a36Sopenharmony_ci 250262306a36Sopenharmony_ci if (changed & BSS_CHANGED_ERP_CTS_PROT) { 250362306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, " ERP_CTS_PROT: %d\n", 250462306a36Sopenharmony_ci info->use_cts_prot); 250562306a36Sopenharmony_ci } 250662306a36Sopenharmony_ci 250762306a36Sopenharmony_ci if (changed & BSS_CHANGED_ERP_PREAMBLE) { 250862306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, " ERP_PREAMBLE: %d\n", 250962306a36Sopenharmony_ci info->use_short_preamble); 251062306a36Sopenharmony_ci } 251162306a36Sopenharmony_ci 251262306a36Sopenharmony_ci if (changed & BSS_CHANGED_ERP_SLOT) { 251362306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, " ERP_SLOT: %d\n", info->use_short_slot); 251462306a36Sopenharmony_ci } 251562306a36Sopenharmony_ci 251662306a36Sopenharmony_ci if (changed & BSS_CHANGED_HT) { 251762306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, " HT: op_mode=0x%x\n", 251862306a36Sopenharmony_ci info->ht_operation_mode); 251962306a36Sopenharmony_ci } 252062306a36Sopenharmony_ci 252162306a36Sopenharmony_ci if (changed & BSS_CHANGED_BASIC_RATES) { 252262306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, " BASIC_RATES: 0x%llx\n", 252362306a36Sopenharmony_ci (unsigned long long) info->basic_rates); 252462306a36Sopenharmony_ci } 252562306a36Sopenharmony_ci 252662306a36Sopenharmony_ci if (changed & BSS_CHANGED_TXPOWER) 252762306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, " TX Power: %d dBm\n", info->txpower); 252862306a36Sopenharmony_ci} 252962306a36Sopenharmony_ci 253062306a36Sopenharmony_cistatic void 253162306a36Sopenharmony_cimac80211_hwsim_sta_rc_update(struct ieee80211_hw *hw, 253262306a36Sopenharmony_ci struct ieee80211_vif *vif, 253362306a36Sopenharmony_ci struct ieee80211_sta *sta, 253462306a36Sopenharmony_ci u32 changed) 253562306a36Sopenharmony_ci{ 253662306a36Sopenharmony_ci struct mac80211_hwsim_data *data = hw->priv; 253762306a36Sopenharmony_ci u32 bw = U32_MAX; 253862306a36Sopenharmony_ci int link_id; 253962306a36Sopenharmony_ci 254062306a36Sopenharmony_ci rcu_read_lock(); 254162306a36Sopenharmony_ci for (link_id = 0; 254262306a36Sopenharmony_ci link_id < ARRAY_SIZE(vif->link_conf); 254362306a36Sopenharmony_ci link_id++) { 254462306a36Sopenharmony_ci enum nl80211_chan_width confbw = NL80211_CHAN_WIDTH_20_NOHT; 254562306a36Sopenharmony_ci struct ieee80211_bss_conf *vif_conf; 254662306a36Sopenharmony_ci struct ieee80211_link_sta *link_sta; 254762306a36Sopenharmony_ci 254862306a36Sopenharmony_ci link_sta = rcu_dereference(sta->link[link_id]); 254962306a36Sopenharmony_ci 255062306a36Sopenharmony_ci if (!link_sta) 255162306a36Sopenharmony_ci continue; 255262306a36Sopenharmony_ci 255362306a36Sopenharmony_ci switch (link_sta->bandwidth) { 255462306a36Sopenharmony_ci#define C(_bw) case IEEE80211_STA_RX_BW_##_bw: bw = _bw; break 255562306a36Sopenharmony_ci C(20); 255662306a36Sopenharmony_ci C(40); 255762306a36Sopenharmony_ci C(80); 255862306a36Sopenharmony_ci C(160); 255962306a36Sopenharmony_ci C(320); 256062306a36Sopenharmony_ci#undef C 256162306a36Sopenharmony_ci } 256262306a36Sopenharmony_ci 256362306a36Sopenharmony_ci if (!data->use_chanctx) { 256462306a36Sopenharmony_ci confbw = data->bw; 256562306a36Sopenharmony_ci } else { 256662306a36Sopenharmony_ci struct ieee80211_chanctx_conf *chanctx_conf; 256762306a36Sopenharmony_ci 256862306a36Sopenharmony_ci vif_conf = rcu_dereference(vif->link_conf[link_id]); 256962306a36Sopenharmony_ci if (WARN_ON(!vif_conf)) 257062306a36Sopenharmony_ci continue; 257162306a36Sopenharmony_ci 257262306a36Sopenharmony_ci chanctx_conf = rcu_dereference(vif_conf->chanctx_conf); 257362306a36Sopenharmony_ci 257462306a36Sopenharmony_ci if (!WARN_ON(!chanctx_conf)) 257562306a36Sopenharmony_ci confbw = chanctx_conf->def.width; 257662306a36Sopenharmony_ci } 257762306a36Sopenharmony_ci 257862306a36Sopenharmony_ci WARN(bw > hwsim_get_chanwidth(confbw), 257962306a36Sopenharmony_ci "intf %pM [link=%d]: bad STA %pM bandwidth %d MHz (%d) > channel config %d MHz (%d)\n", 258062306a36Sopenharmony_ci vif->addr, link_id, sta->addr, bw, sta->deflink.bandwidth, 258162306a36Sopenharmony_ci hwsim_get_chanwidth(data->bw), data->bw); 258262306a36Sopenharmony_ci 258362306a36Sopenharmony_ci 258462306a36Sopenharmony_ci } 258562306a36Sopenharmony_ci rcu_read_unlock(); 258662306a36Sopenharmony_ci 258762306a36Sopenharmony_ci 258862306a36Sopenharmony_ci} 258962306a36Sopenharmony_ci 259062306a36Sopenharmony_cistatic int mac80211_hwsim_sta_add(struct ieee80211_hw *hw, 259162306a36Sopenharmony_ci struct ieee80211_vif *vif, 259262306a36Sopenharmony_ci struct ieee80211_sta *sta) 259362306a36Sopenharmony_ci{ 259462306a36Sopenharmony_ci struct hwsim_sta_priv *sp = (void *)sta->drv_priv; 259562306a36Sopenharmony_ci 259662306a36Sopenharmony_ci hwsim_check_magic(vif); 259762306a36Sopenharmony_ci hwsim_set_sta_magic(sta); 259862306a36Sopenharmony_ci mac80211_hwsim_sta_rc_update(hw, vif, sta, 0); 259962306a36Sopenharmony_ci 260062306a36Sopenharmony_ci if (sta->valid_links) { 260162306a36Sopenharmony_ci WARN(hweight16(sta->valid_links) > 1, 260262306a36Sopenharmony_ci "expect to add STA with single link, have 0x%x\n", 260362306a36Sopenharmony_ci sta->valid_links); 260462306a36Sopenharmony_ci sp->active_links_rx = sta->valid_links; 260562306a36Sopenharmony_ci } 260662306a36Sopenharmony_ci 260762306a36Sopenharmony_ci return 0; 260862306a36Sopenharmony_ci} 260962306a36Sopenharmony_ci 261062306a36Sopenharmony_cistatic int mac80211_hwsim_sta_remove(struct ieee80211_hw *hw, 261162306a36Sopenharmony_ci struct ieee80211_vif *vif, 261262306a36Sopenharmony_ci struct ieee80211_sta *sta) 261362306a36Sopenharmony_ci{ 261462306a36Sopenharmony_ci hwsim_check_magic(vif); 261562306a36Sopenharmony_ci hwsim_clear_sta_magic(sta); 261662306a36Sopenharmony_ci 261762306a36Sopenharmony_ci return 0; 261862306a36Sopenharmony_ci} 261962306a36Sopenharmony_ci 262062306a36Sopenharmony_cistatic int mac80211_hwsim_sta_state(struct ieee80211_hw *hw, 262162306a36Sopenharmony_ci struct ieee80211_vif *vif, 262262306a36Sopenharmony_ci struct ieee80211_sta *sta, 262362306a36Sopenharmony_ci enum ieee80211_sta_state old_state, 262462306a36Sopenharmony_ci enum ieee80211_sta_state new_state) 262562306a36Sopenharmony_ci{ 262662306a36Sopenharmony_ci if (new_state == IEEE80211_STA_NOTEXIST) 262762306a36Sopenharmony_ci return mac80211_hwsim_sta_remove(hw, vif, sta); 262862306a36Sopenharmony_ci 262962306a36Sopenharmony_ci if (old_state == IEEE80211_STA_NOTEXIST) 263062306a36Sopenharmony_ci return mac80211_hwsim_sta_add(hw, vif, sta); 263162306a36Sopenharmony_ci 263262306a36Sopenharmony_ci /* 263362306a36Sopenharmony_ci * when client is authorized (AP station marked as such), 263462306a36Sopenharmony_ci * enable all links 263562306a36Sopenharmony_ci */ 263662306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_STATION && 263762306a36Sopenharmony_ci new_state == IEEE80211_STA_AUTHORIZED && !sta->tdls) 263862306a36Sopenharmony_ci ieee80211_set_active_links_async(vif, 263962306a36Sopenharmony_ci ieee80211_vif_usable_links(vif)); 264062306a36Sopenharmony_ci 264162306a36Sopenharmony_ci return 0; 264262306a36Sopenharmony_ci} 264362306a36Sopenharmony_ci 264462306a36Sopenharmony_cistatic void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw, 264562306a36Sopenharmony_ci struct ieee80211_vif *vif, 264662306a36Sopenharmony_ci enum sta_notify_cmd cmd, 264762306a36Sopenharmony_ci struct ieee80211_sta *sta) 264862306a36Sopenharmony_ci{ 264962306a36Sopenharmony_ci hwsim_check_magic(vif); 265062306a36Sopenharmony_ci 265162306a36Sopenharmony_ci switch (cmd) { 265262306a36Sopenharmony_ci case STA_NOTIFY_SLEEP: 265362306a36Sopenharmony_ci case STA_NOTIFY_AWAKE: 265462306a36Sopenharmony_ci /* TODO: make good use of these flags */ 265562306a36Sopenharmony_ci break; 265662306a36Sopenharmony_ci default: 265762306a36Sopenharmony_ci WARN(1, "Invalid sta notify: %d\n", cmd); 265862306a36Sopenharmony_ci break; 265962306a36Sopenharmony_ci } 266062306a36Sopenharmony_ci} 266162306a36Sopenharmony_ci 266262306a36Sopenharmony_cistatic int mac80211_hwsim_set_tim(struct ieee80211_hw *hw, 266362306a36Sopenharmony_ci struct ieee80211_sta *sta, 266462306a36Sopenharmony_ci bool set) 266562306a36Sopenharmony_ci{ 266662306a36Sopenharmony_ci hwsim_check_sta_magic(sta); 266762306a36Sopenharmony_ci return 0; 266862306a36Sopenharmony_ci} 266962306a36Sopenharmony_ci 267062306a36Sopenharmony_cistatic int mac80211_hwsim_conf_tx(struct ieee80211_hw *hw, 267162306a36Sopenharmony_ci struct ieee80211_vif *vif, 267262306a36Sopenharmony_ci unsigned int link_id, u16 queue, 267362306a36Sopenharmony_ci const struct ieee80211_tx_queue_params *params) 267462306a36Sopenharmony_ci{ 267562306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, 267662306a36Sopenharmony_ci "%s (queue=%d txop=%d cw_min=%d cw_max=%d aifs=%d)\n", 267762306a36Sopenharmony_ci __func__, queue, 267862306a36Sopenharmony_ci params->txop, params->cw_min, 267962306a36Sopenharmony_ci params->cw_max, params->aifs); 268062306a36Sopenharmony_ci return 0; 268162306a36Sopenharmony_ci} 268262306a36Sopenharmony_ci 268362306a36Sopenharmony_cistatic int mac80211_hwsim_get_survey(struct ieee80211_hw *hw, int idx, 268462306a36Sopenharmony_ci struct survey_info *survey) 268562306a36Sopenharmony_ci{ 268662306a36Sopenharmony_ci struct mac80211_hwsim_data *hwsim = hw->priv; 268762306a36Sopenharmony_ci 268862306a36Sopenharmony_ci if (idx < 0 || idx >= ARRAY_SIZE(hwsim->survey_data)) 268962306a36Sopenharmony_ci return -ENOENT; 269062306a36Sopenharmony_ci 269162306a36Sopenharmony_ci mutex_lock(&hwsim->mutex); 269262306a36Sopenharmony_ci survey->channel = hwsim->survey_data[idx].channel; 269362306a36Sopenharmony_ci if (!survey->channel) { 269462306a36Sopenharmony_ci mutex_unlock(&hwsim->mutex); 269562306a36Sopenharmony_ci return -ENOENT; 269662306a36Sopenharmony_ci } 269762306a36Sopenharmony_ci 269862306a36Sopenharmony_ci /* 269962306a36Sopenharmony_ci * Magically conjured dummy values --- this is only ok for simulated hardware. 270062306a36Sopenharmony_ci * 270162306a36Sopenharmony_ci * A real driver which cannot determine real values noise MUST NOT 270262306a36Sopenharmony_ci * report any, especially not a magically conjured ones :-) 270362306a36Sopenharmony_ci */ 270462306a36Sopenharmony_ci survey->filled = SURVEY_INFO_NOISE_DBM | 270562306a36Sopenharmony_ci SURVEY_INFO_TIME | 270662306a36Sopenharmony_ci SURVEY_INFO_TIME_BUSY; 270762306a36Sopenharmony_ci survey->noise = -92; 270862306a36Sopenharmony_ci survey->time = 270962306a36Sopenharmony_ci jiffies_to_msecs(hwsim->survey_data[idx].end - 271062306a36Sopenharmony_ci hwsim->survey_data[idx].start); 271162306a36Sopenharmony_ci /* report 12.5% of channel time is used */ 271262306a36Sopenharmony_ci survey->time_busy = survey->time/8; 271362306a36Sopenharmony_ci mutex_unlock(&hwsim->mutex); 271462306a36Sopenharmony_ci 271562306a36Sopenharmony_ci return 0; 271662306a36Sopenharmony_ci} 271762306a36Sopenharmony_ci 271862306a36Sopenharmony_ci#ifdef CONFIG_NL80211_TESTMODE 271962306a36Sopenharmony_ci/* 272062306a36Sopenharmony_ci * This section contains example code for using netlink 272162306a36Sopenharmony_ci * attributes with the testmode command in nl80211. 272262306a36Sopenharmony_ci */ 272362306a36Sopenharmony_ci 272462306a36Sopenharmony_ci/* These enums need to be kept in sync with userspace */ 272562306a36Sopenharmony_cienum hwsim_testmode_attr { 272662306a36Sopenharmony_ci __HWSIM_TM_ATTR_INVALID = 0, 272762306a36Sopenharmony_ci HWSIM_TM_ATTR_CMD = 1, 272862306a36Sopenharmony_ci HWSIM_TM_ATTR_PS = 2, 272962306a36Sopenharmony_ci 273062306a36Sopenharmony_ci /* keep last */ 273162306a36Sopenharmony_ci __HWSIM_TM_ATTR_AFTER_LAST, 273262306a36Sopenharmony_ci HWSIM_TM_ATTR_MAX = __HWSIM_TM_ATTR_AFTER_LAST - 1 273362306a36Sopenharmony_ci}; 273462306a36Sopenharmony_ci 273562306a36Sopenharmony_cienum hwsim_testmode_cmd { 273662306a36Sopenharmony_ci HWSIM_TM_CMD_SET_PS = 0, 273762306a36Sopenharmony_ci HWSIM_TM_CMD_GET_PS = 1, 273862306a36Sopenharmony_ci HWSIM_TM_CMD_STOP_QUEUES = 2, 273962306a36Sopenharmony_ci HWSIM_TM_CMD_WAKE_QUEUES = 3, 274062306a36Sopenharmony_ci}; 274162306a36Sopenharmony_ci 274262306a36Sopenharmony_cistatic const struct nla_policy hwsim_testmode_policy[HWSIM_TM_ATTR_MAX + 1] = { 274362306a36Sopenharmony_ci [HWSIM_TM_ATTR_CMD] = { .type = NLA_U32 }, 274462306a36Sopenharmony_ci [HWSIM_TM_ATTR_PS] = { .type = NLA_U32 }, 274562306a36Sopenharmony_ci}; 274662306a36Sopenharmony_ci 274762306a36Sopenharmony_cistatic int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw, 274862306a36Sopenharmony_ci struct ieee80211_vif *vif, 274962306a36Sopenharmony_ci void *data, int len) 275062306a36Sopenharmony_ci{ 275162306a36Sopenharmony_ci struct mac80211_hwsim_data *hwsim = hw->priv; 275262306a36Sopenharmony_ci struct nlattr *tb[HWSIM_TM_ATTR_MAX + 1]; 275362306a36Sopenharmony_ci struct sk_buff *skb; 275462306a36Sopenharmony_ci int err, ps; 275562306a36Sopenharmony_ci 275662306a36Sopenharmony_ci err = nla_parse_deprecated(tb, HWSIM_TM_ATTR_MAX, data, len, 275762306a36Sopenharmony_ci hwsim_testmode_policy, NULL); 275862306a36Sopenharmony_ci if (err) 275962306a36Sopenharmony_ci return err; 276062306a36Sopenharmony_ci 276162306a36Sopenharmony_ci if (!tb[HWSIM_TM_ATTR_CMD]) 276262306a36Sopenharmony_ci return -EINVAL; 276362306a36Sopenharmony_ci 276462306a36Sopenharmony_ci switch (nla_get_u32(tb[HWSIM_TM_ATTR_CMD])) { 276562306a36Sopenharmony_ci case HWSIM_TM_CMD_SET_PS: 276662306a36Sopenharmony_ci if (!tb[HWSIM_TM_ATTR_PS]) 276762306a36Sopenharmony_ci return -EINVAL; 276862306a36Sopenharmony_ci ps = nla_get_u32(tb[HWSIM_TM_ATTR_PS]); 276962306a36Sopenharmony_ci return hwsim_fops_ps_write(hwsim, ps); 277062306a36Sopenharmony_ci case HWSIM_TM_CMD_GET_PS: 277162306a36Sopenharmony_ci skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 277262306a36Sopenharmony_ci nla_total_size(sizeof(u32))); 277362306a36Sopenharmony_ci if (!skb) 277462306a36Sopenharmony_ci return -ENOMEM; 277562306a36Sopenharmony_ci if (nla_put_u32(skb, HWSIM_TM_ATTR_PS, hwsim->ps)) 277662306a36Sopenharmony_ci goto nla_put_failure; 277762306a36Sopenharmony_ci return cfg80211_testmode_reply(skb); 277862306a36Sopenharmony_ci case HWSIM_TM_CMD_STOP_QUEUES: 277962306a36Sopenharmony_ci ieee80211_stop_queues(hw); 278062306a36Sopenharmony_ci return 0; 278162306a36Sopenharmony_ci case HWSIM_TM_CMD_WAKE_QUEUES: 278262306a36Sopenharmony_ci ieee80211_wake_queues(hw); 278362306a36Sopenharmony_ci return 0; 278462306a36Sopenharmony_ci default: 278562306a36Sopenharmony_ci return -EOPNOTSUPP; 278662306a36Sopenharmony_ci } 278762306a36Sopenharmony_ci 278862306a36Sopenharmony_ci nla_put_failure: 278962306a36Sopenharmony_ci kfree_skb(skb); 279062306a36Sopenharmony_ci return -ENOBUFS; 279162306a36Sopenharmony_ci} 279262306a36Sopenharmony_ci#endif 279362306a36Sopenharmony_ci 279462306a36Sopenharmony_cistatic int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw, 279562306a36Sopenharmony_ci struct ieee80211_vif *vif, 279662306a36Sopenharmony_ci struct ieee80211_ampdu_params *params) 279762306a36Sopenharmony_ci{ 279862306a36Sopenharmony_ci struct ieee80211_sta *sta = params->sta; 279962306a36Sopenharmony_ci enum ieee80211_ampdu_mlme_action action = params->action; 280062306a36Sopenharmony_ci u16 tid = params->tid; 280162306a36Sopenharmony_ci 280262306a36Sopenharmony_ci switch (action) { 280362306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_START: 280462306a36Sopenharmony_ci return IEEE80211_AMPDU_TX_START_IMMEDIATE; 280562306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_STOP_CONT: 280662306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_STOP_FLUSH: 280762306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: 280862306a36Sopenharmony_ci ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); 280962306a36Sopenharmony_ci break; 281062306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_OPERATIONAL: 281162306a36Sopenharmony_ci break; 281262306a36Sopenharmony_ci case IEEE80211_AMPDU_RX_START: 281362306a36Sopenharmony_ci case IEEE80211_AMPDU_RX_STOP: 281462306a36Sopenharmony_ci break; 281562306a36Sopenharmony_ci default: 281662306a36Sopenharmony_ci return -EOPNOTSUPP; 281762306a36Sopenharmony_ci } 281862306a36Sopenharmony_ci 281962306a36Sopenharmony_ci return 0; 282062306a36Sopenharmony_ci} 282162306a36Sopenharmony_ci 282262306a36Sopenharmony_cistatic void mac80211_hwsim_flush(struct ieee80211_hw *hw, 282362306a36Sopenharmony_ci struct ieee80211_vif *vif, 282462306a36Sopenharmony_ci u32 queues, bool drop) 282562306a36Sopenharmony_ci{ 282662306a36Sopenharmony_ci /* Not implemented, queues only on kernel side */ 282762306a36Sopenharmony_ci} 282862306a36Sopenharmony_ci 282962306a36Sopenharmony_cistatic void hw_scan_work(struct work_struct *work) 283062306a36Sopenharmony_ci{ 283162306a36Sopenharmony_ci struct mac80211_hwsim_data *hwsim = 283262306a36Sopenharmony_ci container_of(work, struct mac80211_hwsim_data, hw_scan.work); 283362306a36Sopenharmony_ci struct cfg80211_scan_request *req = hwsim->hw_scan_request; 283462306a36Sopenharmony_ci int dwell, i; 283562306a36Sopenharmony_ci 283662306a36Sopenharmony_ci mutex_lock(&hwsim->mutex); 283762306a36Sopenharmony_ci if (hwsim->scan_chan_idx >= req->n_channels) { 283862306a36Sopenharmony_ci struct cfg80211_scan_info info = { 283962306a36Sopenharmony_ci .aborted = false, 284062306a36Sopenharmony_ci }; 284162306a36Sopenharmony_ci 284262306a36Sopenharmony_ci wiphy_dbg(hwsim->hw->wiphy, "hw scan complete\n"); 284362306a36Sopenharmony_ci ieee80211_scan_completed(hwsim->hw, &info); 284462306a36Sopenharmony_ci hwsim->hw_scan_request = NULL; 284562306a36Sopenharmony_ci hwsim->hw_scan_vif = NULL; 284662306a36Sopenharmony_ci hwsim->tmp_chan = NULL; 284762306a36Sopenharmony_ci mutex_unlock(&hwsim->mutex); 284862306a36Sopenharmony_ci mac80211_hwsim_config_mac_nl(hwsim->hw, hwsim->scan_addr, 284962306a36Sopenharmony_ci false); 285062306a36Sopenharmony_ci return; 285162306a36Sopenharmony_ci } 285262306a36Sopenharmony_ci 285362306a36Sopenharmony_ci wiphy_dbg(hwsim->hw->wiphy, "hw scan %d MHz\n", 285462306a36Sopenharmony_ci req->channels[hwsim->scan_chan_idx]->center_freq); 285562306a36Sopenharmony_ci 285662306a36Sopenharmony_ci hwsim->tmp_chan = req->channels[hwsim->scan_chan_idx]; 285762306a36Sopenharmony_ci if (hwsim->tmp_chan->flags & (IEEE80211_CHAN_NO_IR | 285862306a36Sopenharmony_ci IEEE80211_CHAN_RADAR) || 285962306a36Sopenharmony_ci !req->n_ssids) { 286062306a36Sopenharmony_ci dwell = 120; 286162306a36Sopenharmony_ci } else { 286262306a36Sopenharmony_ci dwell = 30; 286362306a36Sopenharmony_ci /* send probes */ 286462306a36Sopenharmony_ci for (i = 0; i < req->n_ssids; i++) { 286562306a36Sopenharmony_ci struct sk_buff *probe; 286662306a36Sopenharmony_ci struct ieee80211_mgmt *mgmt; 286762306a36Sopenharmony_ci 286862306a36Sopenharmony_ci probe = ieee80211_probereq_get(hwsim->hw, 286962306a36Sopenharmony_ci hwsim->scan_addr, 287062306a36Sopenharmony_ci req->ssids[i].ssid, 287162306a36Sopenharmony_ci req->ssids[i].ssid_len, 287262306a36Sopenharmony_ci req->ie_len); 287362306a36Sopenharmony_ci if (!probe) 287462306a36Sopenharmony_ci continue; 287562306a36Sopenharmony_ci 287662306a36Sopenharmony_ci mgmt = (struct ieee80211_mgmt *) probe->data; 287762306a36Sopenharmony_ci memcpy(mgmt->da, req->bssid, ETH_ALEN); 287862306a36Sopenharmony_ci memcpy(mgmt->bssid, req->bssid, ETH_ALEN); 287962306a36Sopenharmony_ci 288062306a36Sopenharmony_ci if (req->ie_len) 288162306a36Sopenharmony_ci skb_put_data(probe, req->ie, req->ie_len); 288262306a36Sopenharmony_ci 288362306a36Sopenharmony_ci rcu_read_lock(); 288462306a36Sopenharmony_ci if (!ieee80211_tx_prepare_skb(hwsim->hw, 288562306a36Sopenharmony_ci hwsim->hw_scan_vif, 288662306a36Sopenharmony_ci probe, 288762306a36Sopenharmony_ci hwsim->tmp_chan->band, 288862306a36Sopenharmony_ci NULL)) { 288962306a36Sopenharmony_ci rcu_read_unlock(); 289062306a36Sopenharmony_ci kfree_skb(probe); 289162306a36Sopenharmony_ci continue; 289262306a36Sopenharmony_ci } 289362306a36Sopenharmony_ci 289462306a36Sopenharmony_ci local_bh_disable(); 289562306a36Sopenharmony_ci mac80211_hwsim_tx_frame(hwsim->hw, probe, 289662306a36Sopenharmony_ci hwsim->tmp_chan); 289762306a36Sopenharmony_ci rcu_read_unlock(); 289862306a36Sopenharmony_ci local_bh_enable(); 289962306a36Sopenharmony_ci } 290062306a36Sopenharmony_ci } 290162306a36Sopenharmony_ci ieee80211_queue_delayed_work(hwsim->hw, &hwsim->hw_scan, 290262306a36Sopenharmony_ci msecs_to_jiffies(dwell)); 290362306a36Sopenharmony_ci hwsim->survey_data[hwsim->scan_chan_idx].channel = hwsim->tmp_chan; 290462306a36Sopenharmony_ci hwsim->survey_data[hwsim->scan_chan_idx].start = jiffies; 290562306a36Sopenharmony_ci hwsim->survey_data[hwsim->scan_chan_idx].end = 290662306a36Sopenharmony_ci jiffies + msecs_to_jiffies(dwell); 290762306a36Sopenharmony_ci hwsim->scan_chan_idx++; 290862306a36Sopenharmony_ci mutex_unlock(&hwsim->mutex); 290962306a36Sopenharmony_ci} 291062306a36Sopenharmony_ci 291162306a36Sopenharmony_cistatic int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw, 291262306a36Sopenharmony_ci struct ieee80211_vif *vif, 291362306a36Sopenharmony_ci struct ieee80211_scan_request *hw_req) 291462306a36Sopenharmony_ci{ 291562306a36Sopenharmony_ci struct mac80211_hwsim_data *hwsim = hw->priv; 291662306a36Sopenharmony_ci struct cfg80211_scan_request *req = &hw_req->req; 291762306a36Sopenharmony_ci 291862306a36Sopenharmony_ci mutex_lock(&hwsim->mutex); 291962306a36Sopenharmony_ci if (WARN_ON(hwsim->tmp_chan || hwsim->hw_scan_request)) { 292062306a36Sopenharmony_ci mutex_unlock(&hwsim->mutex); 292162306a36Sopenharmony_ci return -EBUSY; 292262306a36Sopenharmony_ci } 292362306a36Sopenharmony_ci hwsim->hw_scan_request = req; 292462306a36Sopenharmony_ci hwsim->hw_scan_vif = vif; 292562306a36Sopenharmony_ci hwsim->scan_chan_idx = 0; 292662306a36Sopenharmony_ci if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) 292762306a36Sopenharmony_ci get_random_mask_addr(hwsim->scan_addr, 292862306a36Sopenharmony_ci hw_req->req.mac_addr, 292962306a36Sopenharmony_ci hw_req->req.mac_addr_mask); 293062306a36Sopenharmony_ci else 293162306a36Sopenharmony_ci memcpy(hwsim->scan_addr, vif->addr, ETH_ALEN); 293262306a36Sopenharmony_ci memset(hwsim->survey_data, 0, sizeof(hwsim->survey_data)); 293362306a36Sopenharmony_ci mutex_unlock(&hwsim->mutex); 293462306a36Sopenharmony_ci 293562306a36Sopenharmony_ci mac80211_hwsim_config_mac_nl(hw, hwsim->scan_addr, true); 293662306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, "hwsim hw_scan request\n"); 293762306a36Sopenharmony_ci 293862306a36Sopenharmony_ci ieee80211_queue_delayed_work(hwsim->hw, &hwsim->hw_scan, 0); 293962306a36Sopenharmony_ci 294062306a36Sopenharmony_ci return 0; 294162306a36Sopenharmony_ci} 294262306a36Sopenharmony_ci 294362306a36Sopenharmony_cistatic void mac80211_hwsim_cancel_hw_scan(struct ieee80211_hw *hw, 294462306a36Sopenharmony_ci struct ieee80211_vif *vif) 294562306a36Sopenharmony_ci{ 294662306a36Sopenharmony_ci struct mac80211_hwsim_data *hwsim = hw->priv; 294762306a36Sopenharmony_ci struct cfg80211_scan_info info = { 294862306a36Sopenharmony_ci .aborted = true, 294962306a36Sopenharmony_ci }; 295062306a36Sopenharmony_ci 295162306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, "hwsim cancel_hw_scan\n"); 295262306a36Sopenharmony_ci 295362306a36Sopenharmony_ci cancel_delayed_work_sync(&hwsim->hw_scan); 295462306a36Sopenharmony_ci 295562306a36Sopenharmony_ci mutex_lock(&hwsim->mutex); 295662306a36Sopenharmony_ci ieee80211_scan_completed(hwsim->hw, &info); 295762306a36Sopenharmony_ci hwsim->tmp_chan = NULL; 295862306a36Sopenharmony_ci hwsim->hw_scan_request = NULL; 295962306a36Sopenharmony_ci hwsim->hw_scan_vif = NULL; 296062306a36Sopenharmony_ci mutex_unlock(&hwsim->mutex); 296162306a36Sopenharmony_ci} 296262306a36Sopenharmony_ci 296362306a36Sopenharmony_cistatic void mac80211_hwsim_sw_scan(struct ieee80211_hw *hw, 296462306a36Sopenharmony_ci struct ieee80211_vif *vif, 296562306a36Sopenharmony_ci const u8 *mac_addr) 296662306a36Sopenharmony_ci{ 296762306a36Sopenharmony_ci struct mac80211_hwsim_data *hwsim = hw->priv; 296862306a36Sopenharmony_ci 296962306a36Sopenharmony_ci mutex_lock(&hwsim->mutex); 297062306a36Sopenharmony_ci 297162306a36Sopenharmony_ci if (hwsim->scanning) { 297262306a36Sopenharmony_ci pr_debug("two hwsim sw_scans detected!\n"); 297362306a36Sopenharmony_ci goto out; 297462306a36Sopenharmony_ci } 297562306a36Sopenharmony_ci 297662306a36Sopenharmony_ci pr_debug("hwsim sw_scan request, prepping stuff\n"); 297762306a36Sopenharmony_ci 297862306a36Sopenharmony_ci memcpy(hwsim->scan_addr, mac_addr, ETH_ALEN); 297962306a36Sopenharmony_ci mac80211_hwsim_config_mac_nl(hw, hwsim->scan_addr, true); 298062306a36Sopenharmony_ci hwsim->scanning = true; 298162306a36Sopenharmony_ci memset(hwsim->survey_data, 0, sizeof(hwsim->survey_data)); 298262306a36Sopenharmony_ci 298362306a36Sopenharmony_ciout: 298462306a36Sopenharmony_ci mutex_unlock(&hwsim->mutex); 298562306a36Sopenharmony_ci} 298662306a36Sopenharmony_ci 298762306a36Sopenharmony_cistatic void mac80211_hwsim_sw_scan_complete(struct ieee80211_hw *hw, 298862306a36Sopenharmony_ci struct ieee80211_vif *vif) 298962306a36Sopenharmony_ci{ 299062306a36Sopenharmony_ci struct mac80211_hwsim_data *hwsim = hw->priv; 299162306a36Sopenharmony_ci 299262306a36Sopenharmony_ci mutex_lock(&hwsim->mutex); 299362306a36Sopenharmony_ci 299462306a36Sopenharmony_ci pr_debug("hwsim sw_scan_complete\n"); 299562306a36Sopenharmony_ci hwsim->scanning = false; 299662306a36Sopenharmony_ci mac80211_hwsim_config_mac_nl(hw, hwsim->scan_addr, false); 299762306a36Sopenharmony_ci eth_zero_addr(hwsim->scan_addr); 299862306a36Sopenharmony_ci 299962306a36Sopenharmony_ci mutex_unlock(&hwsim->mutex); 300062306a36Sopenharmony_ci} 300162306a36Sopenharmony_ci 300262306a36Sopenharmony_cistatic void hw_roc_start(struct work_struct *work) 300362306a36Sopenharmony_ci{ 300462306a36Sopenharmony_ci struct mac80211_hwsim_data *hwsim = 300562306a36Sopenharmony_ci container_of(work, struct mac80211_hwsim_data, roc_start.work); 300662306a36Sopenharmony_ci 300762306a36Sopenharmony_ci mutex_lock(&hwsim->mutex); 300862306a36Sopenharmony_ci 300962306a36Sopenharmony_ci wiphy_dbg(hwsim->hw->wiphy, "hwsim ROC begins\n"); 301062306a36Sopenharmony_ci hwsim->tmp_chan = hwsim->roc_chan; 301162306a36Sopenharmony_ci ieee80211_ready_on_channel(hwsim->hw); 301262306a36Sopenharmony_ci 301362306a36Sopenharmony_ci ieee80211_queue_delayed_work(hwsim->hw, &hwsim->roc_done, 301462306a36Sopenharmony_ci msecs_to_jiffies(hwsim->roc_duration)); 301562306a36Sopenharmony_ci 301662306a36Sopenharmony_ci mutex_unlock(&hwsim->mutex); 301762306a36Sopenharmony_ci} 301862306a36Sopenharmony_ci 301962306a36Sopenharmony_cistatic void hw_roc_done(struct work_struct *work) 302062306a36Sopenharmony_ci{ 302162306a36Sopenharmony_ci struct mac80211_hwsim_data *hwsim = 302262306a36Sopenharmony_ci container_of(work, struct mac80211_hwsim_data, roc_done.work); 302362306a36Sopenharmony_ci 302462306a36Sopenharmony_ci mutex_lock(&hwsim->mutex); 302562306a36Sopenharmony_ci ieee80211_remain_on_channel_expired(hwsim->hw); 302662306a36Sopenharmony_ci hwsim->tmp_chan = NULL; 302762306a36Sopenharmony_ci mutex_unlock(&hwsim->mutex); 302862306a36Sopenharmony_ci 302962306a36Sopenharmony_ci wiphy_dbg(hwsim->hw->wiphy, "hwsim ROC expired\n"); 303062306a36Sopenharmony_ci} 303162306a36Sopenharmony_ci 303262306a36Sopenharmony_cistatic int mac80211_hwsim_roc(struct ieee80211_hw *hw, 303362306a36Sopenharmony_ci struct ieee80211_vif *vif, 303462306a36Sopenharmony_ci struct ieee80211_channel *chan, 303562306a36Sopenharmony_ci int duration, 303662306a36Sopenharmony_ci enum ieee80211_roc_type type) 303762306a36Sopenharmony_ci{ 303862306a36Sopenharmony_ci struct mac80211_hwsim_data *hwsim = hw->priv; 303962306a36Sopenharmony_ci 304062306a36Sopenharmony_ci mutex_lock(&hwsim->mutex); 304162306a36Sopenharmony_ci if (WARN_ON(hwsim->tmp_chan || hwsim->hw_scan_request)) { 304262306a36Sopenharmony_ci mutex_unlock(&hwsim->mutex); 304362306a36Sopenharmony_ci return -EBUSY; 304462306a36Sopenharmony_ci } 304562306a36Sopenharmony_ci 304662306a36Sopenharmony_ci hwsim->roc_chan = chan; 304762306a36Sopenharmony_ci hwsim->roc_duration = duration; 304862306a36Sopenharmony_ci mutex_unlock(&hwsim->mutex); 304962306a36Sopenharmony_ci 305062306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, "hwsim ROC (%d MHz, %d ms)\n", 305162306a36Sopenharmony_ci chan->center_freq, duration); 305262306a36Sopenharmony_ci ieee80211_queue_delayed_work(hw, &hwsim->roc_start, HZ/50); 305362306a36Sopenharmony_ci 305462306a36Sopenharmony_ci return 0; 305562306a36Sopenharmony_ci} 305662306a36Sopenharmony_ci 305762306a36Sopenharmony_cistatic int mac80211_hwsim_croc(struct ieee80211_hw *hw, 305862306a36Sopenharmony_ci struct ieee80211_vif *vif) 305962306a36Sopenharmony_ci{ 306062306a36Sopenharmony_ci struct mac80211_hwsim_data *hwsim = hw->priv; 306162306a36Sopenharmony_ci 306262306a36Sopenharmony_ci cancel_delayed_work_sync(&hwsim->roc_start); 306362306a36Sopenharmony_ci cancel_delayed_work_sync(&hwsim->roc_done); 306462306a36Sopenharmony_ci 306562306a36Sopenharmony_ci mutex_lock(&hwsim->mutex); 306662306a36Sopenharmony_ci hwsim->tmp_chan = NULL; 306762306a36Sopenharmony_ci mutex_unlock(&hwsim->mutex); 306862306a36Sopenharmony_ci 306962306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, "hwsim ROC canceled\n"); 307062306a36Sopenharmony_ci 307162306a36Sopenharmony_ci return 0; 307262306a36Sopenharmony_ci} 307362306a36Sopenharmony_ci 307462306a36Sopenharmony_cistatic int mac80211_hwsim_add_chanctx(struct ieee80211_hw *hw, 307562306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx) 307662306a36Sopenharmony_ci{ 307762306a36Sopenharmony_ci hwsim_set_chanctx_magic(ctx); 307862306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, 307962306a36Sopenharmony_ci "add channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n", 308062306a36Sopenharmony_ci ctx->def.chan->center_freq, ctx->def.width, 308162306a36Sopenharmony_ci ctx->def.center_freq1, ctx->def.center_freq2); 308262306a36Sopenharmony_ci return 0; 308362306a36Sopenharmony_ci} 308462306a36Sopenharmony_ci 308562306a36Sopenharmony_cistatic void mac80211_hwsim_remove_chanctx(struct ieee80211_hw *hw, 308662306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx) 308762306a36Sopenharmony_ci{ 308862306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, 308962306a36Sopenharmony_ci "remove channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n", 309062306a36Sopenharmony_ci ctx->def.chan->center_freq, ctx->def.width, 309162306a36Sopenharmony_ci ctx->def.center_freq1, ctx->def.center_freq2); 309262306a36Sopenharmony_ci hwsim_check_chanctx_magic(ctx); 309362306a36Sopenharmony_ci hwsim_clear_chanctx_magic(ctx); 309462306a36Sopenharmony_ci} 309562306a36Sopenharmony_ci 309662306a36Sopenharmony_cistatic void mac80211_hwsim_change_chanctx(struct ieee80211_hw *hw, 309762306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx, 309862306a36Sopenharmony_ci u32 changed) 309962306a36Sopenharmony_ci{ 310062306a36Sopenharmony_ci hwsim_check_chanctx_magic(ctx); 310162306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, 310262306a36Sopenharmony_ci "change channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n", 310362306a36Sopenharmony_ci ctx->def.chan->center_freq, ctx->def.width, 310462306a36Sopenharmony_ci ctx->def.center_freq1, ctx->def.center_freq2); 310562306a36Sopenharmony_ci} 310662306a36Sopenharmony_ci 310762306a36Sopenharmony_cistatic int mac80211_hwsim_assign_vif_chanctx(struct ieee80211_hw *hw, 310862306a36Sopenharmony_ci struct ieee80211_vif *vif, 310962306a36Sopenharmony_ci struct ieee80211_bss_conf *link_conf, 311062306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx) 311162306a36Sopenharmony_ci{ 311262306a36Sopenharmony_ci hwsim_check_magic(vif); 311362306a36Sopenharmony_ci hwsim_check_chanctx_magic(ctx); 311462306a36Sopenharmony_ci 311562306a36Sopenharmony_ci /* if we activate a link while already associated wake it up */ 311662306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_STATION && vif->cfg.assoc) { 311762306a36Sopenharmony_ci struct sk_buff *skb; 311862306a36Sopenharmony_ci 311962306a36Sopenharmony_ci skb = ieee80211_nullfunc_get(hw, vif, link_conf->link_id, true); 312062306a36Sopenharmony_ci if (skb) { 312162306a36Sopenharmony_ci local_bh_disable(); 312262306a36Sopenharmony_ci mac80211_hwsim_tx_frame(hw, skb, ctx->def.chan); 312362306a36Sopenharmony_ci local_bh_enable(); 312462306a36Sopenharmony_ci } 312562306a36Sopenharmony_ci } 312662306a36Sopenharmony_ci 312762306a36Sopenharmony_ci return 0; 312862306a36Sopenharmony_ci} 312962306a36Sopenharmony_ci 313062306a36Sopenharmony_cistatic void mac80211_hwsim_unassign_vif_chanctx(struct ieee80211_hw *hw, 313162306a36Sopenharmony_ci struct ieee80211_vif *vif, 313262306a36Sopenharmony_ci struct ieee80211_bss_conf *link_conf, 313362306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx) 313462306a36Sopenharmony_ci{ 313562306a36Sopenharmony_ci hwsim_check_magic(vif); 313662306a36Sopenharmony_ci hwsim_check_chanctx_magic(ctx); 313762306a36Sopenharmony_ci 313862306a36Sopenharmony_ci /* if we deactivate a link while associated suspend it first */ 313962306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_STATION && vif->cfg.assoc) { 314062306a36Sopenharmony_ci struct sk_buff *skb; 314162306a36Sopenharmony_ci 314262306a36Sopenharmony_ci skb = ieee80211_nullfunc_get(hw, vif, link_conf->link_id, true); 314362306a36Sopenharmony_ci if (skb) { 314462306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (void *)skb->data; 314562306a36Sopenharmony_ci 314662306a36Sopenharmony_ci hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); 314762306a36Sopenharmony_ci 314862306a36Sopenharmony_ci local_bh_disable(); 314962306a36Sopenharmony_ci mac80211_hwsim_tx_frame(hw, skb, ctx->def.chan); 315062306a36Sopenharmony_ci local_bh_enable(); 315162306a36Sopenharmony_ci } 315262306a36Sopenharmony_ci } 315362306a36Sopenharmony_ci} 315462306a36Sopenharmony_ci 315562306a36Sopenharmony_cistatic const char mac80211_hwsim_gstrings_stats[][ETH_GSTRING_LEN] = { 315662306a36Sopenharmony_ci "tx_pkts_nic", 315762306a36Sopenharmony_ci "tx_bytes_nic", 315862306a36Sopenharmony_ci "rx_pkts_nic", 315962306a36Sopenharmony_ci "rx_bytes_nic", 316062306a36Sopenharmony_ci "d_tx_dropped", 316162306a36Sopenharmony_ci "d_tx_failed", 316262306a36Sopenharmony_ci "d_ps_mode", 316362306a36Sopenharmony_ci "d_group", 316462306a36Sopenharmony_ci}; 316562306a36Sopenharmony_ci 316662306a36Sopenharmony_ci#define MAC80211_HWSIM_SSTATS_LEN ARRAY_SIZE(mac80211_hwsim_gstrings_stats) 316762306a36Sopenharmony_ci 316862306a36Sopenharmony_cistatic void mac80211_hwsim_get_et_strings(struct ieee80211_hw *hw, 316962306a36Sopenharmony_ci struct ieee80211_vif *vif, 317062306a36Sopenharmony_ci u32 sset, u8 *data) 317162306a36Sopenharmony_ci{ 317262306a36Sopenharmony_ci if (sset == ETH_SS_STATS) 317362306a36Sopenharmony_ci memcpy(data, mac80211_hwsim_gstrings_stats, 317462306a36Sopenharmony_ci sizeof(mac80211_hwsim_gstrings_stats)); 317562306a36Sopenharmony_ci} 317662306a36Sopenharmony_ci 317762306a36Sopenharmony_cistatic int mac80211_hwsim_get_et_sset_count(struct ieee80211_hw *hw, 317862306a36Sopenharmony_ci struct ieee80211_vif *vif, int sset) 317962306a36Sopenharmony_ci{ 318062306a36Sopenharmony_ci if (sset == ETH_SS_STATS) 318162306a36Sopenharmony_ci return MAC80211_HWSIM_SSTATS_LEN; 318262306a36Sopenharmony_ci return 0; 318362306a36Sopenharmony_ci} 318462306a36Sopenharmony_ci 318562306a36Sopenharmony_cistatic void mac80211_hwsim_get_et_stats(struct ieee80211_hw *hw, 318662306a36Sopenharmony_ci struct ieee80211_vif *vif, 318762306a36Sopenharmony_ci struct ethtool_stats *stats, u64 *data) 318862306a36Sopenharmony_ci{ 318962306a36Sopenharmony_ci struct mac80211_hwsim_data *ar = hw->priv; 319062306a36Sopenharmony_ci int i = 0; 319162306a36Sopenharmony_ci 319262306a36Sopenharmony_ci data[i++] = ar->tx_pkts; 319362306a36Sopenharmony_ci data[i++] = ar->tx_bytes; 319462306a36Sopenharmony_ci data[i++] = ar->rx_pkts; 319562306a36Sopenharmony_ci data[i++] = ar->rx_bytes; 319662306a36Sopenharmony_ci data[i++] = ar->tx_dropped; 319762306a36Sopenharmony_ci data[i++] = ar->tx_failed; 319862306a36Sopenharmony_ci data[i++] = ar->ps; 319962306a36Sopenharmony_ci data[i++] = ar->group; 320062306a36Sopenharmony_ci 320162306a36Sopenharmony_ci WARN_ON(i != MAC80211_HWSIM_SSTATS_LEN); 320262306a36Sopenharmony_ci} 320362306a36Sopenharmony_ci 320462306a36Sopenharmony_cistatic int mac80211_hwsim_tx_last_beacon(struct ieee80211_hw *hw) 320562306a36Sopenharmony_ci{ 320662306a36Sopenharmony_ci return 1; 320762306a36Sopenharmony_ci} 320862306a36Sopenharmony_ci 320962306a36Sopenharmony_cistatic int mac80211_hwsim_set_rts_threshold(struct ieee80211_hw *hw, u32 value) 321062306a36Sopenharmony_ci{ 321162306a36Sopenharmony_ci return -EOPNOTSUPP; 321262306a36Sopenharmony_ci} 321362306a36Sopenharmony_ci 321462306a36Sopenharmony_cistatic int mac80211_hwsim_change_vif_links(struct ieee80211_hw *hw, 321562306a36Sopenharmony_ci struct ieee80211_vif *vif, 321662306a36Sopenharmony_ci u16 old_links, u16 new_links, 321762306a36Sopenharmony_ci struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]) 321862306a36Sopenharmony_ci{ 321962306a36Sopenharmony_ci unsigned long rem = old_links & ~new_links; 322062306a36Sopenharmony_ci unsigned long add = new_links & ~old_links; 322162306a36Sopenharmony_ci int i; 322262306a36Sopenharmony_ci 322362306a36Sopenharmony_ci if (!old_links) 322462306a36Sopenharmony_ci rem |= BIT(0); 322562306a36Sopenharmony_ci if (!new_links) 322662306a36Sopenharmony_ci add |= BIT(0); 322762306a36Sopenharmony_ci 322862306a36Sopenharmony_ci for_each_set_bit(i, &rem, IEEE80211_MLD_MAX_NUM_LINKS) 322962306a36Sopenharmony_ci mac80211_hwsim_config_mac_nl(hw, old[i]->addr, false); 323062306a36Sopenharmony_ci 323162306a36Sopenharmony_ci for_each_set_bit(i, &add, IEEE80211_MLD_MAX_NUM_LINKS) { 323262306a36Sopenharmony_ci struct ieee80211_bss_conf *link_conf; 323362306a36Sopenharmony_ci 323462306a36Sopenharmony_ci link_conf = link_conf_dereference_protected(vif, i); 323562306a36Sopenharmony_ci if (WARN_ON(!link_conf)) 323662306a36Sopenharmony_ci continue; 323762306a36Sopenharmony_ci 323862306a36Sopenharmony_ci mac80211_hwsim_config_mac_nl(hw, link_conf->addr, true); 323962306a36Sopenharmony_ci } 324062306a36Sopenharmony_ci 324162306a36Sopenharmony_ci return 0; 324262306a36Sopenharmony_ci} 324362306a36Sopenharmony_ci 324462306a36Sopenharmony_cistatic int mac80211_hwsim_change_sta_links(struct ieee80211_hw *hw, 324562306a36Sopenharmony_ci struct ieee80211_vif *vif, 324662306a36Sopenharmony_ci struct ieee80211_sta *sta, 324762306a36Sopenharmony_ci u16 old_links, u16 new_links) 324862306a36Sopenharmony_ci{ 324962306a36Sopenharmony_ci struct hwsim_sta_priv *sp = (void *)sta->drv_priv; 325062306a36Sopenharmony_ci 325162306a36Sopenharmony_ci hwsim_check_sta_magic(sta); 325262306a36Sopenharmony_ci 325362306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_STATION) 325462306a36Sopenharmony_ci sp->active_links_rx = new_links; 325562306a36Sopenharmony_ci 325662306a36Sopenharmony_ci return 0; 325762306a36Sopenharmony_ci} 325862306a36Sopenharmony_ci 325962306a36Sopenharmony_cistatic int mac80211_hwsim_send_pmsr_ftm_request_peer(struct sk_buff *msg, 326062306a36Sopenharmony_ci struct cfg80211_pmsr_ftm_request_peer *request) 326162306a36Sopenharmony_ci{ 326262306a36Sopenharmony_ci struct nlattr *ftm; 326362306a36Sopenharmony_ci 326462306a36Sopenharmony_ci if (!request->requested) 326562306a36Sopenharmony_ci return -EINVAL; 326662306a36Sopenharmony_ci 326762306a36Sopenharmony_ci ftm = nla_nest_start(msg, NL80211_PMSR_TYPE_FTM); 326862306a36Sopenharmony_ci if (!ftm) 326962306a36Sopenharmony_ci return -ENOBUFS; 327062306a36Sopenharmony_ci 327162306a36Sopenharmony_ci if (nla_put_u32(msg, NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE, request->preamble)) 327262306a36Sopenharmony_ci return -ENOBUFS; 327362306a36Sopenharmony_ci 327462306a36Sopenharmony_ci if (nla_put_u16(msg, NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD, request->burst_period)) 327562306a36Sopenharmony_ci return -ENOBUFS; 327662306a36Sopenharmony_ci 327762306a36Sopenharmony_ci if (request->asap && nla_put_flag(msg, NL80211_PMSR_FTM_REQ_ATTR_ASAP)) 327862306a36Sopenharmony_ci return -ENOBUFS; 327962306a36Sopenharmony_ci 328062306a36Sopenharmony_ci if (request->request_lci && nla_put_flag(msg, NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI)) 328162306a36Sopenharmony_ci return -ENOBUFS; 328262306a36Sopenharmony_ci 328362306a36Sopenharmony_ci if (request->request_civicloc && 328462306a36Sopenharmony_ci nla_put_flag(msg, NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC)) 328562306a36Sopenharmony_ci return -ENOBUFS; 328662306a36Sopenharmony_ci 328762306a36Sopenharmony_ci if (request->trigger_based && nla_put_flag(msg, NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED)) 328862306a36Sopenharmony_ci return -ENOBUFS; 328962306a36Sopenharmony_ci 329062306a36Sopenharmony_ci if (request->non_trigger_based && 329162306a36Sopenharmony_ci nla_put_flag(msg, NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED)) 329262306a36Sopenharmony_ci return -ENOBUFS; 329362306a36Sopenharmony_ci 329462306a36Sopenharmony_ci if (request->lmr_feedback && nla_put_flag(msg, NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK)) 329562306a36Sopenharmony_ci return -ENOBUFS; 329662306a36Sopenharmony_ci 329762306a36Sopenharmony_ci if (nla_put_u8(msg, NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP, request->num_bursts_exp)) 329862306a36Sopenharmony_ci return -ENOBUFS; 329962306a36Sopenharmony_ci 330062306a36Sopenharmony_ci if (nla_put_u8(msg, NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION, request->burst_duration)) 330162306a36Sopenharmony_ci return -ENOBUFS; 330262306a36Sopenharmony_ci 330362306a36Sopenharmony_ci if (nla_put_u8(msg, NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST, request->ftms_per_burst)) 330462306a36Sopenharmony_ci return -ENOBUFS; 330562306a36Sopenharmony_ci 330662306a36Sopenharmony_ci if (nla_put_u8(msg, NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES, request->ftmr_retries)) 330762306a36Sopenharmony_ci return -ENOBUFS; 330862306a36Sopenharmony_ci 330962306a36Sopenharmony_ci if (nla_put_u8(msg, NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION, request->burst_duration)) 331062306a36Sopenharmony_ci return -ENOBUFS; 331162306a36Sopenharmony_ci 331262306a36Sopenharmony_ci if (nla_put_u8(msg, NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR, request->bss_color)) 331362306a36Sopenharmony_ci return -ENOBUFS; 331462306a36Sopenharmony_ci 331562306a36Sopenharmony_ci nla_nest_end(msg, ftm); 331662306a36Sopenharmony_ci 331762306a36Sopenharmony_ci return 0; 331862306a36Sopenharmony_ci} 331962306a36Sopenharmony_ci 332062306a36Sopenharmony_cistatic int mac80211_hwsim_send_pmsr_request_peer(struct sk_buff *msg, 332162306a36Sopenharmony_ci struct cfg80211_pmsr_request_peer *request) 332262306a36Sopenharmony_ci{ 332362306a36Sopenharmony_ci struct nlattr *peer, *chandef, *req, *data; 332462306a36Sopenharmony_ci int err; 332562306a36Sopenharmony_ci 332662306a36Sopenharmony_ci peer = nla_nest_start(msg, NL80211_PMSR_ATTR_PEERS); 332762306a36Sopenharmony_ci if (!peer) 332862306a36Sopenharmony_ci return -ENOBUFS; 332962306a36Sopenharmony_ci 333062306a36Sopenharmony_ci if (nla_put(msg, NL80211_PMSR_PEER_ATTR_ADDR, ETH_ALEN, 333162306a36Sopenharmony_ci request->addr)) 333262306a36Sopenharmony_ci return -ENOBUFS; 333362306a36Sopenharmony_ci 333462306a36Sopenharmony_ci chandef = nla_nest_start(msg, NL80211_PMSR_PEER_ATTR_CHAN); 333562306a36Sopenharmony_ci if (!chandef) 333662306a36Sopenharmony_ci return -ENOBUFS; 333762306a36Sopenharmony_ci 333862306a36Sopenharmony_ci err = nl80211_send_chandef(msg, &request->chandef); 333962306a36Sopenharmony_ci if (err) 334062306a36Sopenharmony_ci return err; 334162306a36Sopenharmony_ci 334262306a36Sopenharmony_ci nla_nest_end(msg, chandef); 334362306a36Sopenharmony_ci 334462306a36Sopenharmony_ci req = nla_nest_start(msg, NL80211_PMSR_PEER_ATTR_REQ); 334562306a36Sopenharmony_ci if (!req) 334662306a36Sopenharmony_ci return -ENOBUFS; 334762306a36Sopenharmony_ci 334862306a36Sopenharmony_ci if (request->report_ap_tsf && nla_put_flag(msg, NL80211_PMSR_REQ_ATTR_GET_AP_TSF)) 334962306a36Sopenharmony_ci return -ENOBUFS; 335062306a36Sopenharmony_ci 335162306a36Sopenharmony_ci data = nla_nest_start(msg, NL80211_PMSR_REQ_ATTR_DATA); 335262306a36Sopenharmony_ci if (!data) 335362306a36Sopenharmony_ci return -ENOBUFS; 335462306a36Sopenharmony_ci 335562306a36Sopenharmony_ci err = mac80211_hwsim_send_pmsr_ftm_request_peer(msg, &request->ftm); 335662306a36Sopenharmony_ci if (err) 335762306a36Sopenharmony_ci return err; 335862306a36Sopenharmony_ci 335962306a36Sopenharmony_ci nla_nest_end(msg, data); 336062306a36Sopenharmony_ci nla_nest_end(msg, req); 336162306a36Sopenharmony_ci nla_nest_end(msg, peer); 336262306a36Sopenharmony_ci 336362306a36Sopenharmony_ci return 0; 336462306a36Sopenharmony_ci} 336562306a36Sopenharmony_ci 336662306a36Sopenharmony_cistatic int mac80211_hwsim_send_pmsr_request(struct sk_buff *msg, 336762306a36Sopenharmony_ci struct cfg80211_pmsr_request *request) 336862306a36Sopenharmony_ci{ 336962306a36Sopenharmony_ci struct nlattr *pmsr; 337062306a36Sopenharmony_ci int err; 337162306a36Sopenharmony_ci 337262306a36Sopenharmony_ci pmsr = nla_nest_start(msg, NL80211_ATTR_PEER_MEASUREMENTS); 337362306a36Sopenharmony_ci if (!pmsr) 337462306a36Sopenharmony_ci return -ENOBUFS; 337562306a36Sopenharmony_ci 337662306a36Sopenharmony_ci if (nla_put_u32(msg, NL80211_ATTR_TIMEOUT, request->timeout)) 337762306a36Sopenharmony_ci return -ENOBUFS; 337862306a36Sopenharmony_ci 337962306a36Sopenharmony_ci if (!is_zero_ether_addr(request->mac_addr)) { 338062306a36Sopenharmony_ci if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, request->mac_addr)) 338162306a36Sopenharmony_ci return -ENOBUFS; 338262306a36Sopenharmony_ci if (nla_put(msg, NL80211_ATTR_MAC_MASK, ETH_ALEN, request->mac_addr_mask)) 338362306a36Sopenharmony_ci return -ENOBUFS; 338462306a36Sopenharmony_ci } 338562306a36Sopenharmony_ci 338662306a36Sopenharmony_ci for (int i = 0; i < request->n_peers; i++) { 338762306a36Sopenharmony_ci err = mac80211_hwsim_send_pmsr_request_peer(msg, &request->peers[i]); 338862306a36Sopenharmony_ci if (err) 338962306a36Sopenharmony_ci return err; 339062306a36Sopenharmony_ci } 339162306a36Sopenharmony_ci 339262306a36Sopenharmony_ci nla_nest_end(msg, pmsr); 339362306a36Sopenharmony_ci 339462306a36Sopenharmony_ci return 0; 339562306a36Sopenharmony_ci} 339662306a36Sopenharmony_ci 339762306a36Sopenharmony_cistatic int mac80211_hwsim_start_pmsr(struct ieee80211_hw *hw, 339862306a36Sopenharmony_ci struct ieee80211_vif *vif, 339962306a36Sopenharmony_ci struct cfg80211_pmsr_request *request) 340062306a36Sopenharmony_ci{ 340162306a36Sopenharmony_ci struct mac80211_hwsim_data *data; 340262306a36Sopenharmony_ci struct sk_buff *skb = NULL; 340362306a36Sopenharmony_ci struct nlattr *pmsr; 340462306a36Sopenharmony_ci void *msg_head; 340562306a36Sopenharmony_ci u32 _portid; 340662306a36Sopenharmony_ci int err = 0; 340762306a36Sopenharmony_ci 340862306a36Sopenharmony_ci data = hw->priv; 340962306a36Sopenharmony_ci _portid = READ_ONCE(data->wmediumd); 341062306a36Sopenharmony_ci if (!_portid && !hwsim_virtio_enabled) 341162306a36Sopenharmony_ci return -EOPNOTSUPP; 341262306a36Sopenharmony_ci 341362306a36Sopenharmony_ci mutex_lock(&data->mutex); 341462306a36Sopenharmony_ci 341562306a36Sopenharmony_ci if (data->pmsr_request) { 341662306a36Sopenharmony_ci err = -EBUSY; 341762306a36Sopenharmony_ci goto out_free; 341862306a36Sopenharmony_ci } 341962306a36Sopenharmony_ci 342062306a36Sopenharmony_ci skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 342162306a36Sopenharmony_ci 342262306a36Sopenharmony_ci if (!skb) { 342362306a36Sopenharmony_ci err = -ENOMEM; 342462306a36Sopenharmony_ci goto out_free; 342562306a36Sopenharmony_ci } 342662306a36Sopenharmony_ci 342762306a36Sopenharmony_ci msg_head = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, HWSIM_CMD_START_PMSR); 342862306a36Sopenharmony_ci 342962306a36Sopenharmony_ci if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER, 343062306a36Sopenharmony_ci ETH_ALEN, data->addresses[1].addr)) { 343162306a36Sopenharmony_ci err = -ENOMEM; 343262306a36Sopenharmony_ci goto out_free; 343362306a36Sopenharmony_ci } 343462306a36Sopenharmony_ci 343562306a36Sopenharmony_ci pmsr = nla_nest_start(skb, HWSIM_ATTR_PMSR_REQUEST); 343662306a36Sopenharmony_ci if (!pmsr) { 343762306a36Sopenharmony_ci err = -ENOMEM; 343862306a36Sopenharmony_ci goto out_free; 343962306a36Sopenharmony_ci } 344062306a36Sopenharmony_ci 344162306a36Sopenharmony_ci err = mac80211_hwsim_send_pmsr_request(skb, request); 344262306a36Sopenharmony_ci if (err) 344362306a36Sopenharmony_ci goto out_free; 344462306a36Sopenharmony_ci 344562306a36Sopenharmony_ci nla_nest_end(skb, pmsr); 344662306a36Sopenharmony_ci 344762306a36Sopenharmony_ci genlmsg_end(skb, msg_head); 344862306a36Sopenharmony_ci if (hwsim_virtio_enabled) 344962306a36Sopenharmony_ci hwsim_tx_virtio(data, skb); 345062306a36Sopenharmony_ci else 345162306a36Sopenharmony_ci hwsim_unicast_netgroup(data, skb, _portid); 345262306a36Sopenharmony_ci 345362306a36Sopenharmony_ci data->pmsr_request = request; 345462306a36Sopenharmony_ci data->pmsr_request_wdev = ieee80211_vif_to_wdev(vif); 345562306a36Sopenharmony_ci 345662306a36Sopenharmony_ciout_free: 345762306a36Sopenharmony_ci if (err && skb) 345862306a36Sopenharmony_ci nlmsg_free(skb); 345962306a36Sopenharmony_ci 346062306a36Sopenharmony_ci mutex_unlock(&data->mutex); 346162306a36Sopenharmony_ci return err; 346262306a36Sopenharmony_ci} 346362306a36Sopenharmony_ci 346462306a36Sopenharmony_cistatic void mac80211_hwsim_abort_pmsr(struct ieee80211_hw *hw, 346562306a36Sopenharmony_ci struct ieee80211_vif *vif, 346662306a36Sopenharmony_ci struct cfg80211_pmsr_request *request) 346762306a36Sopenharmony_ci{ 346862306a36Sopenharmony_ci struct mac80211_hwsim_data *data; 346962306a36Sopenharmony_ci struct sk_buff *skb = NULL; 347062306a36Sopenharmony_ci struct nlattr *pmsr; 347162306a36Sopenharmony_ci void *msg_head; 347262306a36Sopenharmony_ci u32 _portid; 347362306a36Sopenharmony_ci int err = 0; 347462306a36Sopenharmony_ci 347562306a36Sopenharmony_ci data = hw->priv; 347662306a36Sopenharmony_ci _portid = READ_ONCE(data->wmediumd); 347762306a36Sopenharmony_ci if (!_portid && !hwsim_virtio_enabled) 347862306a36Sopenharmony_ci return; 347962306a36Sopenharmony_ci 348062306a36Sopenharmony_ci mutex_lock(&data->mutex); 348162306a36Sopenharmony_ci 348262306a36Sopenharmony_ci if (data->pmsr_request != request) { 348362306a36Sopenharmony_ci err = -EINVAL; 348462306a36Sopenharmony_ci goto out; 348562306a36Sopenharmony_ci } 348662306a36Sopenharmony_ci 348762306a36Sopenharmony_ci skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 348862306a36Sopenharmony_ci if (!skb) { 348962306a36Sopenharmony_ci err = -ENOMEM; 349062306a36Sopenharmony_ci goto out; 349162306a36Sopenharmony_ci } 349262306a36Sopenharmony_ci 349362306a36Sopenharmony_ci msg_head = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, HWSIM_CMD_ABORT_PMSR); 349462306a36Sopenharmony_ci 349562306a36Sopenharmony_ci if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER, ETH_ALEN, data->addresses[1].addr)) 349662306a36Sopenharmony_ci goto out; 349762306a36Sopenharmony_ci 349862306a36Sopenharmony_ci pmsr = nla_nest_start(skb, HWSIM_ATTR_PMSR_REQUEST); 349962306a36Sopenharmony_ci if (!pmsr) { 350062306a36Sopenharmony_ci err = -ENOMEM; 350162306a36Sopenharmony_ci goto out; 350262306a36Sopenharmony_ci } 350362306a36Sopenharmony_ci 350462306a36Sopenharmony_ci err = mac80211_hwsim_send_pmsr_request(skb, request); 350562306a36Sopenharmony_ci if (err) 350662306a36Sopenharmony_ci goto out; 350762306a36Sopenharmony_ci 350862306a36Sopenharmony_ci err = nla_nest_end(skb, pmsr); 350962306a36Sopenharmony_ci if (err) 351062306a36Sopenharmony_ci goto out; 351162306a36Sopenharmony_ci 351262306a36Sopenharmony_ci genlmsg_end(skb, msg_head); 351362306a36Sopenharmony_ci if (hwsim_virtio_enabled) 351462306a36Sopenharmony_ci hwsim_tx_virtio(data, skb); 351562306a36Sopenharmony_ci else 351662306a36Sopenharmony_ci hwsim_unicast_netgroup(data, skb, _portid); 351762306a36Sopenharmony_ci 351862306a36Sopenharmony_ciout: 351962306a36Sopenharmony_ci if (err && skb) 352062306a36Sopenharmony_ci nlmsg_free(skb); 352162306a36Sopenharmony_ci 352262306a36Sopenharmony_ci mutex_unlock(&data->mutex); 352362306a36Sopenharmony_ci} 352462306a36Sopenharmony_ci 352562306a36Sopenharmony_cistatic int mac80211_hwsim_parse_rate_info(struct nlattr *rateattr, 352662306a36Sopenharmony_ci struct rate_info *rate_info, 352762306a36Sopenharmony_ci struct genl_info *info) 352862306a36Sopenharmony_ci{ 352962306a36Sopenharmony_ci struct nlattr *tb[HWSIM_RATE_INFO_ATTR_MAX + 1]; 353062306a36Sopenharmony_ci int ret; 353162306a36Sopenharmony_ci 353262306a36Sopenharmony_ci ret = nla_parse_nested(tb, HWSIM_RATE_INFO_ATTR_MAX, 353362306a36Sopenharmony_ci rateattr, hwsim_rate_info_policy, info->extack); 353462306a36Sopenharmony_ci if (ret) 353562306a36Sopenharmony_ci return ret; 353662306a36Sopenharmony_ci 353762306a36Sopenharmony_ci if (tb[HWSIM_RATE_INFO_ATTR_FLAGS]) 353862306a36Sopenharmony_ci rate_info->flags = nla_get_u8(tb[HWSIM_RATE_INFO_ATTR_FLAGS]); 353962306a36Sopenharmony_ci 354062306a36Sopenharmony_ci if (tb[HWSIM_RATE_INFO_ATTR_MCS]) 354162306a36Sopenharmony_ci rate_info->mcs = nla_get_u8(tb[HWSIM_RATE_INFO_ATTR_MCS]); 354262306a36Sopenharmony_ci 354362306a36Sopenharmony_ci if (tb[HWSIM_RATE_INFO_ATTR_LEGACY]) 354462306a36Sopenharmony_ci rate_info->legacy = nla_get_u16(tb[HWSIM_RATE_INFO_ATTR_LEGACY]); 354562306a36Sopenharmony_ci 354662306a36Sopenharmony_ci if (tb[HWSIM_RATE_INFO_ATTR_NSS]) 354762306a36Sopenharmony_ci rate_info->nss = nla_get_u8(tb[HWSIM_RATE_INFO_ATTR_NSS]); 354862306a36Sopenharmony_ci 354962306a36Sopenharmony_ci if (tb[HWSIM_RATE_INFO_ATTR_BW]) 355062306a36Sopenharmony_ci rate_info->bw = nla_get_u8(tb[HWSIM_RATE_INFO_ATTR_BW]); 355162306a36Sopenharmony_ci 355262306a36Sopenharmony_ci if (tb[HWSIM_RATE_INFO_ATTR_HE_GI]) 355362306a36Sopenharmony_ci rate_info->he_gi = nla_get_u8(tb[HWSIM_RATE_INFO_ATTR_HE_GI]); 355462306a36Sopenharmony_ci 355562306a36Sopenharmony_ci if (tb[HWSIM_RATE_INFO_ATTR_HE_DCM]) 355662306a36Sopenharmony_ci rate_info->he_dcm = nla_get_u8(tb[HWSIM_RATE_INFO_ATTR_HE_DCM]); 355762306a36Sopenharmony_ci 355862306a36Sopenharmony_ci if (tb[HWSIM_RATE_INFO_ATTR_HE_RU_ALLOC]) 355962306a36Sopenharmony_ci rate_info->he_ru_alloc = 356062306a36Sopenharmony_ci nla_get_u8(tb[HWSIM_RATE_INFO_ATTR_HE_RU_ALLOC]); 356162306a36Sopenharmony_ci 356262306a36Sopenharmony_ci if (tb[HWSIM_RATE_INFO_ATTR_N_BOUNDED_CH]) 356362306a36Sopenharmony_ci rate_info->n_bonded_ch = nla_get_u8(tb[HWSIM_RATE_INFO_ATTR_N_BOUNDED_CH]); 356462306a36Sopenharmony_ci 356562306a36Sopenharmony_ci if (tb[HWSIM_RATE_INFO_ATTR_EHT_GI]) 356662306a36Sopenharmony_ci rate_info->eht_gi = nla_get_u8(tb[HWSIM_RATE_INFO_ATTR_EHT_GI]); 356762306a36Sopenharmony_ci 356862306a36Sopenharmony_ci if (tb[HWSIM_RATE_INFO_ATTR_EHT_RU_ALLOC]) 356962306a36Sopenharmony_ci rate_info->eht_ru_alloc = nla_get_u8(tb[HWSIM_RATE_INFO_ATTR_EHT_RU_ALLOC]); 357062306a36Sopenharmony_ci 357162306a36Sopenharmony_ci return 0; 357262306a36Sopenharmony_ci} 357362306a36Sopenharmony_ci 357462306a36Sopenharmony_cistatic int mac80211_hwsim_parse_ftm_result(struct nlattr *ftm, 357562306a36Sopenharmony_ci struct cfg80211_pmsr_ftm_result *result, 357662306a36Sopenharmony_ci struct genl_info *info) 357762306a36Sopenharmony_ci{ 357862306a36Sopenharmony_ci struct nlattr *tb[NL80211_PMSR_FTM_RESP_ATTR_MAX + 1]; 357962306a36Sopenharmony_ci int ret; 358062306a36Sopenharmony_ci 358162306a36Sopenharmony_ci ret = nla_parse_nested(tb, NL80211_PMSR_FTM_RESP_ATTR_MAX, 358262306a36Sopenharmony_ci ftm, hwsim_ftm_result_policy, info->extack); 358362306a36Sopenharmony_ci if (ret) 358462306a36Sopenharmony_ci return ret; 358562306a36Sopenharmony_ci 358662306a36Sopenharmony_ci if (tb[NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON]) 358762306a36Sopenharmony_ci result->failure_reason = nla_get_u32(tb[NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON]); 358862306a36Sopenharmony_ci 358962306a36Sopenharmony_ci if (tb[NL80211_PMSR_FTM_RESP_ATTR_BURST_INDEX]) 359062306a36Sopenharmony_ci result->burst_index = nla_get_u16(tb[NL80211_PMSR_FTM_RESP_ATTR_BURST_INDEX]); 359162306a36Sopenharmony_ci 359262306a36Sopenharmony_ci if (tb[NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_ATTEMPTS]) { 359362306a36Sopenharmony_ci result->num_ftmr_attempts_valid = 1; 359462306a36Sopenharmony_ci result->num_ftmr_attempts = 359562306a36Sopenharmony_ci nla_get_u32(tb[NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_ATTEMPTS]); 359662306a36Sopenharmony_ci } 359762306a36Sopenharmony_ci 359862306a36Sopenharmony_ci if (tb[NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_SUCCESSES]) { 359962306a36Sopenharmony_ci result->num_ftmr_successes_valid = 1; 360062306a36Sopenharmony_ci result->num_ftmr_successes = 360162306a36Sopenharmony_ci nla_get_u32(tb[NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_SUCCESSES]); 360262306a36Sopenharmony_ci } 360362306a36Sopenharmony_ci 360462306a36Sopenharmony_ci if (tb[NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME]) 360562306a36Sopenharmony_ci result->busy_retry_time = 360662306a36Sopenharmony_ci nla_get_u8(tb[NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME]); 360762306a36Sopenharmony_ci 360862306a36Sopenharmony_ci if (tb[NL80211_PMSR_FTM_RESP_ATTR_NUM_BURSTS_EXP]) 360962306a36Sopenharmony_ci result->num_bursts_exp = nla_get_u8(tb[NL80211_PMSR_FTM_RESP_ATTR_NUM_BURSTS_EXP]); 361062306a36Sopenharmony_ci 361162306a36Sopenharmony_ci if (tb[NL80211_PMSR_FTM_RESP_ATTR_BURST_DURATION]) 361262306a36Sopenharmony_ci result->burst_duration = nla_get_u8(tb[NL80211_PMSR_FTM_RESP_ATTR_BURST_DURATION]); 361362306a36Sopenharmony_ci 361462306a36Sopenharmony_ci if (tb[NL80211_PMSR_FTM_RESP_ATTR_FTMS_PER_BURST]) 361562306a36Sopenharmony_ci result->ftms_per_burst = nla_get_u8(tb[NL80211_PMSR_FTM_RESP_ATTR_FTMS_PER_BURST]); 361662306a36Sopenharmony_ci 361762306a36Sopenharmony_ci if (tb[NL80211_PMSR_FTM_RESP_ATTR_RSSI_AVG]) { 361862306a36Sopenharmony_ci result->rssi_avg_valid = 1; 361962306a36Sopenharmony_ci result->rssi_avg = nla_get_s32(tb[NL80211_PMSR_FTM_RESP_ATTR_RSSI_AVG]); 362062306a36Sopenharmony_ci } 362162306a36Sopenharmony_ci if (tb[NL80211_PMSR_FTM_RESP_ATTR_RSSI_SPREAD]) { 362262306a36Sopenharmony_ci result->rssi_spread_valid = 1; 362362306a36Sopenharmony_ci result->rssi_spread = 362462306a36Sopenharmony_ci nla_get_s32(tb[NL80211_PMSR_FTM_RESP_ATTR_RSSI_SPREAD]); 362562306a36Sopenharmony_ci } 362662306a36Sopenharmony_ci 362762306a36Sopenharmony_ci if (tb[NL80211_PMSR_FTM_RESP_ATTR_TX_RATE]) { 362862306a36Sopenharmony_ci result->tx_rate_valid = 1; 362962306a36Sopenharmony_ci ret = mac80211_hwsim_parse_rate_info(tb[NL80211_PMSR_FTM_RESP_ATTR_TX_RATE], 363062306a36Sopenharmony_ci &result->tx_rate, info); 363162306a36Sopenharmony_ci if (ret) 363262306a36Sopenharmony_ci return ret; 363362306a36Sopenharmony_ci } 363462306a36Sopenharmony_ci 363562306a36Sopenharmony_ci if (tb[NL80211_PMSR_FTM_RESP_ATTR_RX_RATE]) { 363662306a36Sopenharmony_ci result->rx_rate_valid = 1; 363762306a36Sopenharmony_ci ret = mac80211_hwsim_parse_rate_info(tb[NL80211_PMSR_FTM_RESP_ATTR_RX_RATE], 363862306a36Sopenharmony_ci &result->rx_rate, info); 363962306a36Sopenharmony_ci if (ret) 364062306a36Sopenharmony_ci return ret; 364162306a36Sopenharmony_ci } 364262306a36Sopenharmony_ci 364362306a36Sopenharmony_ci if (tb[NL80211_PMSR_FTM_RESP_ATTR_RTT_AVG]) { 364462306a36Sopenharmony_ci result->rtt_avg_valid = 1; 364562306a36Sopenharmony_ci result->rtt_avg = 364662306a36Sopenharmony_ci nla_get_u64(tb[NL80211_PMSR_FTM_RESP_ATTR_RTT_AVG]); 364762306a36Sopenharmony_ci } 364862306a36Sopenharmony_ci if (tb[NL80211_PMSR_FTM_RESP_ATTR_RTT_VARIANCE]) { 364962306a36Sopenharmony_ci result->rtt_variance_valid = 1; 365062306a36Sopenharmony_ci result->rtt_variance = 365162306a36Sopenharmony_ci nla_get_u64(tb[NL80211_PMSR_FTM_RESP_ATTR_RTT_VARIANCE]); 365262306a36Sopenharmony_ci } 365362306a36Sopenharmony_ci if (tb[NL80211_PMSR_FTM_RESP_ATTR_RTT_SPREAD]) { 365462306a36Sopenharmony_ci result->rtt_spread_valid = 1; 365562306a36Sopenharmony_ci result->rtt_spread = 365662306a36Sopenharmony_ci nla_get_u64(tb[NL80211_PMSR_FTM_RESP_ATTR_RTT_SPREAD]); 365762306a36Sopenharmony_ci } 365862306a36Sopenharmony_ci if (tb[NL80211_PMSR_FTM_RESP_ATTR_DIST_AVG]) { 365962306a36Sopenharmony_ci result->dist_avg_valid = 1; 366062306a36Sopenharmony_ci result->dist_avg = 366162306a36Sopenharmony_ci nla_get_u64(tb[NL80211_PMSR_FTM_RESP_ATTR_DIST_AVG]); 366262306a36Sopenharmony_ci } 366362306a36Sopenharmony_ci if (tb[NL80211_PMSR_FTM_RESP_ATTR_DIST_VARIANCE]) { 366462306a36Sopenharmony_ci result->dist_variance_valid = 1; 366562306a36Sopenharmony_ci result->dist_variance = 366662306a36Sopenharmony_ci nla_get_u64(tb[NL80211_PMSR_FTM_RESP_ATTR_DIST_VARIANCE]); 366762306a36Sopenharmony_ci } 366862306a36Sopenharmony_ci if (tb[NL80211_PMSR_FTM_RESP_ATTR_DIST_SPREAD]) { 366962306a36Sopenharmony_ci result->dist_spread_valid = 1; 367062306a36Sopenharmony_ci result->dist_spread = 367162306a36Sopenharmony_ci nla_get_u64(tb[NL80211_PMSR_FTM_RESP_ATTR_DIST_SPREAD]); 367262306a36Sopenharmony_ci } 367362306a36Sopenharmony_ci 367462306a36Sopenharmony_ci if (tb[NL80211_PMSR_FTM_RESP_ATTR_LCI]) { 367562306a36Sopenharmony_ci result->lci = nla_data(tb[NL80211_PMSR_FTM_RESP_ATTR_LCI]); 367662306a36Sopenharmony_ci result->lci_len = nla_len(tb[NL80211_PMSR_FTM_RESP_ATTR_LCI]); 367762306a36Sopenharmony_ci } 367862306a36Sopenharmony_ci 367962306a36Sopenharmony_ci if (tb[NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC]) { 368062306a36Sopenharmony_ci result->civicloc = nla_data(tb[NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC]); 368162306a36Sopenharmony_ci result->civicloc_len = nla_len(tb[NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC]); 368262306a36Sopenharmony_ci } 368362306a36Sopenharmony_ci 368462306a36Sopenharmony_ci return 0; 368562306a36Sopenharmony_ci} 368662306a36Sopenharmony_ci 368762306a36Sopenharmony_cistatic int mac80211_hwsim_parse_pmsr_resp(struct nlattr *resp, 368862306a36Sopenharmony_ci struct cfg80211_pmsr_result *result, 368962306a36Sopenharmony_ci struct genl_info *info) 369062306a36Sopenharmony_ci{ 369162306a36Sopenharmony_ci struct nlattr *tb[NL80211_PMSR_RESP_ATTR_MAX + 1]; 369262306a36Sopenharmony_ci struct nlattr *pmsr; 369362306a36Sopenharmony_ci int rem; 369462306a36Sopenharmony_ci int ret; 369562306a36Sopenharmony_ci 369662306a36Sopenharmony_ci ret = nla_parse_nested(tb, NL80211_PMSR_RESP_ATTR_MAX, resp, hwsim_pmsr_resp_policy, 369762306a36Sopenharmony_ci info->extack); 369862306a36Sopenharmony_ci if (ret) 369962306a36Sopenharmony_ci return ret; 370062306a36Sopenharmony_ci 370162306a36Sopenharmony_ci if (tb[NL80211_PMSR_RESP_ATTR_STATUS]) 370262306a36Sopenharmony_ci result->status = nla_get_u32(tb[NL80211_PMSR_RESP_ATTR_STATUS]); 370362306a36Sopenharmony_ci 370462306a36Sopenharmony_ci if (tb[NL80211_PMSR_RESP_ATTR_HOST_TIME]) 370562306a36Sopenharmony_ci result->host_time = nla_get_u64(tb[NL80211_PMSR_RESP_ATTR_HOST_TIME]); 370662306a36Sopenharmony_ci 370762306a36Sopenharmony_ci if (tb[NL80211_PMSR_RESP_ATTR_AP_TSF]) { 370862306a36Sopenharmony_ci result->ap_tsf_valid = 1; 370962306a36Sopenharmony_ci result->ap_tsf = nla_get_u64(tb[NL80211_PMSR_RESP_ATTR_AP_TSF]); 371062306a36Sopenharmony_ci } 371162306a36Sopenharmony_ci 371262306a36Sopenharmony_ci result->final = !!tb[NL80211_PMSR_RESP_ATTR_FINAL]; 371362306a36Sopenharmony_ci 371462306a36Sopenharmony_ci if (!tb[NL80211_PMSR_RESP_ATTR_DATA]) 371562306a36Sopenharmony_ci return 0; 371662306a36Sopenharmony_ci 371762306a36Sopenharmony_ci nla_for_each_nested(pmsr, tb[NL80211_PMSR_RESP_ATTR_DATA], rem) { 371862306a36Sopenharmony_ci switch (nla_type(pmsr)) { 371962306a36Sopenharmony_ci case NL80211_PMSR_TYPE_FTM: 372062306a36Sopenharmony_ci result->type = NL80211_PMSR_TYPE_FTM; 372162306a36Sopenharmony_ci ret = mac80211_hwsim_parse_ftm_result(pmsr, &result->ftm, info); 372262306a36Sopenharmony_ci if (ret) 372362306a36Sopenharmony_ci return ret; 372462306a36Sopenharmony_ci break; 372562306a36Sopenharmony_ci default: 372662306a36Sopenharmony_ci NL_SET_ERR_MSG_ATTR(info->extack, pmsr, "Unknown pmsr resp type"); 372762306a36Sopenharmony_ci return -EINVAL; 372862306a36Sopenharmony_ci } 372962306a36Sopenharmony_ci } 373062306a36Sopenharmony_ci 373162306a36Sopenharmony_ci return 0; 373262306a36Sopenharmony_ci} 373362306a36Sopenharmony_ci 373462306a36Sopenharmony_cistatic int mac80211_hwsim_parse_pmsr_result(struct nlattr *peer, 373562306a36Sopenharmony_ci struct cfg80211_pmsr_result *result, 373662306a36Sopenharmony_ci struct genl_info *info) 373762306a36Sopenharmony_ci{ 373862306a36Sopenharmony_ci struct nlattr *tb[NL80211_PMSR_PEER_ATTR_MAX + 1]; 373962306a36Sopenharmony_ci int ret; 374062306a36Sopenharmony_ci 374162306a36Sopenharmony_ci if (!peer) 374262306a36Sopenharmony_ci return -EINVAL; 374362306a36Sopenharmony_ci 374462306a36Sopenharmony_ci ret = nla_parse_nested(tb, NL80211_PMSR_PEER_ATTR_MAX, peer, 374562306a36Sopenharmony_ci hwsim_pmsr_peer_result_policy, info->extack); 374662306a36Sopenharmony_ci if (ret) 374762306a36Sopenharmony_ci return ret; 374862306a36Sopenharmony_ci 374962306a36Sopenharmony_ci if (tb[NL80211_PMSR_PEER_ATTR_ADDR]) 375062306a36Sopenharmony_ci memcpy(result->addr, nla_data(tb[NL80211_PMSR_PEER_ATTR_ADDR]), 375162306a36Sopenharmony_ci ETH_ALEN); 375262306a36Sopenharmony_ci 375362306a36Sopenharmony_ci if (tb[NL80211_PMSR_PEER_ATTR_RESP]) { 375462306a36Sopenharmony_ci ret = mac80211_hwsim_parse_pmsr_resp(tb[NL80211_PMSR_PEER_ATTR_RESP], result, info); 375562306a36Sopenharmony_ci if (ret) 375662306a36Sopenharmony_ci return ret; 375762306a36Sopenharmony_ci } 375862306a36Sopenharmony_ci 375962306a36Sopenharmony_ci return 0; 376062306a36Sopenharmony_ci}; 376162306a36Sopenharmony_ci 376262306a36Sopenharmony_cistatic int hwsim_pmsr_report_nl(struct sk_buff *msg, struct genl_info *info) 376362306a36Sopenharmony_ci{ 376462306a36Sopenharmony_ci struct mac80211_hwsim_data *data; 376562306a36Sopenharmony_ci struct nlattr *peers, *peer; 376662306a36Sopenharmony_ci struct nlattr *reqattr; 376762306a36Sopenharmony_ci const u8 *src; 376862306a36Sopenharmony_ci int err; 376962306a36Sopenharmony_ci int rem; 377062306a36Sopenharmony_ci 377162306a36Sopenharmony_ci if (!info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER]) 377262306a36Sopenharmony_ci return -EINVAL; 377362306a36Sopenharmony_ci 377462306a36Sopenharmony_ci src = nla_data(info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER]); 377562306a36Sopenharmony_ci data = get_hwsim_data_ref_from_addr(src); 377662306a36Sopenharmony_ci if (!data) 377762306a36Sopenharmony_ci return -EINVAL; 377862306a36Sopenharmony_ci 377962306a36Sopenharmony_ci mutex_lock(&data->mutex); 378062306a36Sopenharmony_ci if (!data->pmsr_request) { 378162306a36Sopenharmony_ci err = -EINVAL; 378262306a36Sopenharmony_ci goto out; 378362306a36Sopenharmony_ci } 378462306a36Sopenharmony_ci 378562306a36Sopenharmony_ci reqattr = info->attrs[HWSIM_ATTR_PMSR_RESULT]; 378662306a36Sopenharmony_ci if (!reqattr) { 378762306a36Sopenharmony_ci err = -EINVAL; 378862306a36Sopenharmony_ci goto out; 378962306a36Sopenharmony_ci } 379062306a36Sopenharmony_ci 379162306a36Sopenharmony_ci peers = nla_find_nested(reqattr, NL80211_PMSR_ATTR_PEERS); 379262306a36Sopenharmony_ci if (!peers) { 379362306a36Sopenharmony_ci err = -EINVAL; 379462306a36Sopenharmony_ci goto out; 379562306a36Sopenharmony_ci } 379662306a36Sopenharmony_ci 379762306a36Sopenharmony_ci nla_for_each_nested(peer, peers, rem) { 379862306a36Sopenharmony_ci struct cfg80211_pmsr_result result; 379962306a36Sopenharmony_ci 380062306a36Sopenharmony_ci err = mac80211_hwsim_parse_pmsr_result(peer, &result, info); 380162306a36Sopenharmony_ci if (err) 380262306a36Sopenharmony_ci goto out; 380362306a36Sopenharmony_ci 380462306a36Sopenharmony_ci cfg80211_pmsr_report(data->pmsr_request_wdev, 380562306a36Sopenharmony_ci data->pmsr_request, &result, GFP_KERNEL); 380662306a36Sopenharmony_ci } 380762306a36Sopenharmony_ci 380862306a36Sopenharmony_ci cfg80211_pmsr_complete(data->pmsr_request_wdev, data->pmsr_request, GFP_KERNEL); 380962306a36Sopenharmony_ci 381062306a36Sopenharmony_ci err = 0; 381162306a36Sopenharmony_ciout: 381262306a36Sopenharmony_ci data->pmsr_request = NULL; 381362306a36Sopenharmony_ci data->pmsr_request_wdev = NULL; 381462306a36Sopenharmony_ci 381562306a36Sopenharmony_ci mutex_unlock(&data->mutex); 381662306a36Sopenharmony_ci return err; 381762306a36Sopenharmony_ci} 381862306a36Sopenharmony_ci 381962306a36Sopenharmony_ci#define HWSIM_COMMON_OPS \ 382062306a36Sopenharmony_ci .tx = mac80211_hwsim_tx, \ 382162306a36Sopenharmony_ci .wake_tx_queue = ieee80211_handle_wake_tx_queue, \ 382262306a36Sopenharmony_ci .start = mac80211_hwsim_start, \ 382362306a36Sopenharmony_ci .stop = mac80211_hwsim_stop, \ 382462306a36Sopenharmony_ci .add_interface = mac80211_hwsim_add_interface, \ 382562306a36Sopenharmony_ci .change_interface = mac80211_hwsim_change_interface, \ 382662306a36Sopenharmony_ci .remove_interface = mac80211_hwsim_remove_interface, \ 382762306a36Sopenharmony_ci .config = mac80211_hwsim_config, \ 382862306a36Sopenharmony_ci .configure_filter = mac80211_hwsim_configure_filter, \ 382962306a36Sopenharmony_ci .vif_cfg_changed = mac80211_hwsim_vif_info_changed, \ 383062306a36Sopenharmony_ci .link_info_changed = mac80211_hwsim_link_info_changed, \ 383162306a36Sopenharmony_ci .tx_last_beacon = mac80211_hwsim_tx_last_beacon, \ 383262306a36Sopenharmony_ci .sta_notify = mac80211_hwsim_sta_notify, \ 383362306a36Sopenharmony_ci .sta_rc_update = mac80211_hwsim_sta_rc_update, \ 383462306a36Sopenharmony_ci .conf_tx = mac80211_hwsim_conf_tx, \ 383562306a36Sopenharmony_ci .get_survey = mac80211_hwsim_get_survey, \ 383662306a36Sopenharmony_ci CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd) \ 383762306a36Sopenharmony_ci .ampdu_action = mac80211_hwsim_ampdu_action, \ 383862306a36Sopenharmony_ci .flush = mac80211_hwsim_flush, \ 383962306a36Sopenharmony_ci .get_et_sset_count = mac80211_hwsim_get_et_sset_count, \ 384062306a36Sopenharmony_ci .get_et_stats = mac80211_hwsim_get_et_stats, \ 384162306a36Sopenharmony_ci .get_et_strings = mac80211_hwsim_get_et_strings, \ 384262306a36Sopenharmony_ci .start_pmsr = mac80211_hwsim_start_pmsr, \ 384362306a36Sopenharmony_ci .abort_pmsr = mac80211_hwsim_abort_pmsr, 384462306a36Sopenharmony_ci 384562306a36Sopenharmony_ci#define HWSIM_NON_MLO_OPS \ 384662306a36Sopenharmony_ci .sta_add = mac80211_hwsim_sta_add, \ 384762306a36Sopenharmony_ci .sta_remove = mac80211_hwsim_sta_remove, \ 384862306a36Sopenharmony_ci .set_tim = mac80211_hwsim_set_tim, \ 384962306a36Sopenharmony_ci .get_tsf = mac80211_hwsim_get_tsf, \ 385062306a36Sopenharmony_ci .set_tsf = mac80211_hwsim_set_tsf, 385162306a36Sopenharmony_ci 385262306a36Sopenharmony_cistatic const struct ieee80211_ops mac80211_hwsim_ops = { 385362306a36Sopenharmony_ci HWSIM_COMMON_OPS 385462306a36Sopenharmony_ci HWSIM_NON_MLO_OPS 385562306a36Sopenharmony_ci .sw_scan_start = mac80211_hwsim_sw_scan, 385662306a36Sopenharmony_ci .sw_scan_complete = mac80211_hwsim_sw_scan_complete, 385762306a36Sopenharmony_ci}; 385862306a36Sopenharmony_ci 385962306a36Sopenharmony_ci#define HWSIM_CHANCTX_OPS \ 386062306a36Sopenharmony_ci .hw_scan = mac80211_hwsim_hw_scan, \ 386162306a36Sopenharmony_ci .cancel_hw_scan = mac80211_hwsim_cancel_hw_scan, \ 386262306a36Sopenharmony_ci .remain_on_channel = mac80211_hwsim_roc, \ 386362306a36Sopenharmony_ci .cancel_remain_on_channel = mac80211_hwsim_croc, \ 386462306a36Sopenharmony_ci .add_chanctx = mac80211_hwsim_add_chanctx, \ 386562306a36Sopenharmony_ci .remove_chanctx = mac80211_hwsim_remove_chanctx, \ 386662306a36Sopenharmony_ci .change_chanctx = mac80211_hwsim_change_chanctx, \ 386762306a36Sopenharmony_ci .assign_vif_chanctx = mac80211_hwsim_assign_vif_chanctx,\ 386862306a36Sopenharmony_ci .unassign_vif_chanctx = mac80211_hwsim_unassign_vif_chanctx, 386962306a36Sopenharmony_ci 387062306a36Sopenharmony_cistatic const struct ieee80211_ops mac80211_hwsim_mchan_ops = { 387162306a36Sopenharmony_ci HWSIM_COMMON_OPS 387262306a36Sopenharmony_ci HWSIM_NON_MLO_OPS 387362306a36Sopenharmony_ci HWSIM_CHANCTX_OPS 387462306a36Sopenharmony_ci}; 387562306a36Sopenharmony_ci 387662306a36Sopenharmony_cistatic const struct ieee80211_ops mac80211_hwsim_mlo_ops = { 387762306a36Sopenharmony_ci HWSIM_COMMON_OPS 387862306a36Sopenharmony_ci HWSIM_CHANCTX_OPS 387962306a36Sopenharmony_ci .set_rts_threshold = mac80211_hwsim_set_rts_threshold, 388062306a36Sopenharmony_ci .change_vif_links = mac80211_hwsim_change_vif_links, 388162306a36Sopenharmony_ci .change_sta_links = mac80211_hwsim_change_sta_links, 388262306a36Sopenharmony_ci .sta_state = mac80211_hwsim_sta_state, 388362306a36Sopenharmony_ci}; 388462306a36Sopenharmony_ci 388562306a36Sopenharmony_cistruct hwsim_new_radio_params { 388662306a36Sopenharmony_ci unsigned int channels; 388762306a36Sopenharmony_ci const char *reg_alpha2; 388862306a36Sopenharmony_ci const struct ieee80211_regdomain *regd; 388962306a36Sopenharmony_ci bool reg_strict; 389062306a36Sopenharmony_ci bool p2p_device; 389162306a36Sopenharmony_ci bool use_chanctx; 389262306a36Sopenharmony_ci bool destroy_on_close; 389362306a36Sopenharmony_ci const char *hwname; 389462306a36Sopenharmony_ci bool no_vif; 389562306a36Sopenharmony_ci const u8 *perm_addr; 389662306a36Sopenharmony_ci u32 iftypes; 389762306a36Sopenharmony_ci u32 *ciphers; 389862306a36Sopenharmony_ci u8 n_ciphers; 389962306a36Sopenharmony_ci bool mlo; 390062306a36Sopenharmony_ci const struct cfg80211_pmsr_capabilities *pmsr_capa; 390162306a36Sopenharmony_ci}; 390262306a36Sopenharmony_ci 390362306a36Sopenharmony_cistatic void hwsim_mcast_config_msg(struct sk_buff *mcast_skb, 390462306a36Sopenharmony_ci struct genl_info *info) 390562306a36Sopenharmony_ci{ 390662306a36Sopenharmony_ci if (info) 390762306a36Sopenharmony_ci genl_notify(&hwsim_genl_family, mcast_skb, info, 390862306a36Sopenharmony_ci HWSIM_MCGRP_CONFIG, GFP_KERNEL); 390962306a36Sopenharmony_ci else 391062306a36Sopenharmony_ci genlmsg_multicast(&hwsim_genl_family, mcast_skb, 0, 391162306a36Sopenharmony_ci HWSIM_MCGRP_CONFIG, GFP_KERNEL); 391262306a36Sopenharmony_ci} 391362306a36Sopenharmony_ci 391462306a36Sopenharmony_cistatic int append_radio_msg(struct sk_buff *skb, int id, 391562306a36Sopenharmony_ci struct hwsim_new_radio_params *param) 391662306a36Sopenharmony_ci{ 391762306a36Sopenharmony_ci int ret; 391862306a36Sopenharmony_ci 391962306a36Sopenharmony_ci ret = nla_put_u32(skb, HWSIM_ATTR_RADIO_ID, id); 392062306a36Sopenharmony_ci if (ret < 0) 392162306a36Sopenharmony_ci return ret; 392262306a36Sopenharmony_ci 392362306a36Sopenharmony_ci if (param->channels) { 392462306a36Sopenharmony_ci ret = nla_put_u32(skb, HWSIM_ATTR_CHANNELS, param->channels); 392562306a36Sopenharmony_ci if (ret < 0) 392662306a36Sopenharmony_ci return ret; 392762306a36Sopenharmony_ci } 392862306a36Sopenharmony_ci 392962306a36Sopenharmony_ci if (param->reg_alpha2) { 393062306a36Sopenharmony_ci ret = nla_put(skb, HWSIM_ATTR_REG_HINT_ALPHA2, 2, 393162306a36Sopenharmony_ci param->reg_alpha2); 393262306a36Sopenharmony_ci if (ret < 0) 393362306a36Sopenharmony_ci return ret; 393462306a36Sopenharmony_ci } 393562306a36Sopenharmony_ci 393662306a36Sopenharmony_ci if (param->regd) { 393762306a36Sopenharmony_ci int i; 393862306a36Sopenharmony_ci 393962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(hwsim_world_regdom_custom); i++) { 394062306a36Sopenharmony_ci if (hwsim_world_regdom_custom[i] != param->regd) 394162306a36Sopenharmony_ci continue; 394262306a36Sopenharmony_ci 394362306a36Sopenharmony_ci ret = nla_put_u32(skb, HWSIM_ATTR_REG_CUSTOM_REG, i); 394462306a36Sopenharmony_ci if (ret < 0) 394562306a36Sopenharmony_ci return ret; 394662306a36Sopenharmony_ci break; 394762306a36Sopenharmony_ci } 394862306a36Sopenharmony_ci } 394962306a36Sopenharmony_ci 395062306a36Sopenharmony_ci if (param->reg_strict) { 395162306a36Sopenharmony_ci ret = nla_put_flag(skb, HWSIM_ATTR_REG_STRICT_REG); 395262306a36Sopenharmony_ci if (ret < 0) 395362306a36Sopenharmony_ci return ret; 395462306a36Sopenharmony_ci } 395562306a36Sopenharmony_ci 395662306a36Sopenharmony_ci if (param->p2p_device) { 395762306a36Sopenharmony_ci ret = nla_put_flag(skb, HWSIM_ATTR_SUPPORT_P2P_DEVICE); 395862306a36Sopenharmony_ci if (ret < 0) 395962306a36Sopenharmony_ci return ret; 396062306a36Sopenharmony_ci } 396162306a36Sopenharmony_ci 396262306a36Sopenharmony_ci if (param->use_chanctx) { 396362306a36Sopenharmony_ci ret = nla_put_flag(skb, HWSIM_ATTR_USE_CHANCTX); 396462306a36Sopenharmony_ci if (ret < 0) 396562306a36Sopenharmony_ci return ret; 396662306a36Sopenharmony_ci } 396762306a36Sopenharmony_ci 396862306a36Sopenharmony_ci if (param->hwname) { 396962306a36Sopenharmony_ci ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME, 397062306a36Sopenharmony_ci strlen(param->hwname), param->hwname); 397162306a36Sopenharmony_ci if (ret < 0) 397262306a36Sopenharmony_ci return ret; 397362306a36Sopenharmony_ci } 397462306a36Sopenharmony_ci 397562306a36Sopenharmony_ci return 0; 397662306a36Sopenharmony_ci} 397762306a36Sopenharmony_ci 397862306a36Sopenharmony_cistatic void hwsim_mcast_new_radio(int id, struct genl_info *info, 397962306a36Sopenharmony_ci struct hwsim_new_radio_params *param) 398062306a36Sopenharmony_ci{ 398162306a36Sopenharmony_ci struct sk_buff *mcast_skb; 398262306a36Sopenharmony_ci void *data; 398362306a36Sopenharmony_ci 398462306a36Sopenharmony_ci mcast_skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 398562306a36Sopenharmony_ci if (!mcast_skb) 398662306a36Sopenharmony_ci return; 398762306a36Sopenharmony_ci 398862306a36Sopenharmony_ci data = genlmsg_put(mcast_skb, 0, 0, &hwsim_genl_family, 0, 398962306a36Sopenharmony_ci HWSIM_CMD_NEW_RADIO); 399062306a36Sopenharmony_ci if (!data) 399162306a36Sopenharmony_ci goto out_err; 399262306a36Sopenharmony_ci 399362306a36Sopenharmony_ci if (append_radio_msg(mcast_skb, id, param) < 0) 399462306a36Sopenharmony_ci goto out_err; 399562306a36Sopenharmony_ci 399662306a36Sopenharmony_ci genlmsg_end(mcast_skb, data); 399762306a36Sopenharmony_ci 399862306a36Sopenharmony_ci hwsim_mcast_config_msg(mcast_skb, info); 399962306a36Sopenharmony_ci return; 400062306a36Sopenharmony_ci 400162306a36Sopenharmony_ciout_err: 400262306a36Sopenharmony_ci nlmsg_free(mcast_skb); 400362306a36Sopenharmony_ci} 400462306a36Sopenharmony_ci 400562306a36Sopenharmony_cistatic const struct ieee80211_sband_iftype_data sband_capa_2ghz[] = { 400662306a36Sopenharmony_ci { 400762306a36Sopenharmony_ci .types_mask = BIT(NL80211_IFTYPE_STATION), 400862306a36Sopenharmony_ci .he_cap = { 400962306a36Sopenharmony_ci .has_he = true, 401062306a36Sopenharmony_ci .he_cap_elem = { 401162306a36Sopenharmony_ci .mac_cap_info[0] = 401262306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP0_HTC_HE, 401362306a36Sopenharmony_ci .mac_cap_info[1] = 401462306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | 401562306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 401662306a36Sopenharmony_ci .mac_cap_info[2] = 401762306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP2_BSR | 401862306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP2_MU_CASCADING | 401962306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP2_ACK_EN, 402062306a36Sopenharmony_ci .mac_cap_info[3] = 402162306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 402262306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 402362306a36Sopenharmony_ci .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 402462306a36Sopenharmony_ci .phy_cap_info[1] = 402562306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 402662306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 402762306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 402862306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 402962306a36Sopenharmony_ci .phy_cap_info[2] = 403062306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | 403162306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | 403262306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | 403362306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | 403462306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO, 403562306a36Sopenharmony_ci 403662306a36Sopenharmony_ci /* Leave all the other PHY capability bytes 403762306a36Sopenharmony_ci * unset, as DCM, beam forming, RU and PPE 403862306a36Sopenharmony_ci * threshold information are not supported 403962306a36Sopenharmony_ci */ 404062306a36Sopenharmony_ci }, 404162306a36Sopenharmony_ci .he_mcs_nss_supp = { 404262306a36Sopenharmony_ci .rx_mcs_80 = cpu_to_le16(0xfffa), 404362306a36Sopenharmony_ci .tx_mcs_80 = cpu_to_le16(0xfffa), 404462306a36Sopenharmony_ci .rx_mcs_160 = cpu_to_le16(0xffff), 404562306a36Sopenharmony_ci .tx_mcs_160 = cpu_to_le16(0xffff), 404662306a36Sopenharmony_ci .rx_mcs_80p80 = cpu_to_le16(0xffff), 404762306a36Sopenharmony_ci .tx_mcs_80p80 = cpu_to_le16(0xffff), 404862306a36Sopenharmony_ci }, 404962306a36Sopenharmony_ci }, 405062306a36Sopenharmony_ci .eht_cap = { 405162306a36Sopenharmony_ci .has_eht = true, 405262306a36Sopenharmony_ci .eht_cap_elem = { 405362306a36Sopenharmony_ci .mac_cap_info[0] = 405462306a36Sopenharmony_ci IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | 405562306a36Sopenharmony_ci IEEE80211_EHT_MAC_CAP0_OM_CONTROL | 405662306a36Sopenharmony_ci IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1, 405762306a36Sopenharmony_ci .phy_cap_info[0] = 405862306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | 405962306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | 406062306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | 406162306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER | 406262306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE, 406362306a36Sopenharmony_ci .phy_cap_info[3] = 406462306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | 406562306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | 406662306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | 406762306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | 406862306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | 406962306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | 407062306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK, 407162306a36Sopenharmony_ci .phy_cap_info[4] = 407262306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | 407362306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP4_PSR_SR_SUPP | 407462306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | 407562306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI | 407662306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK, 407762306a36Sopenharmony_ci .phy_cap_info[5] = 407862306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | 407962306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP | 408062306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP | 408162306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT | 408262306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK | 408362306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK, 408462306a36Sopenharmony_ci .phy_cap_info[6] = 408562306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK | 408662306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK, 408762306a36Sopenharmony_ci .phy_cap_info[7] = 408862306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP7_20MHZ_STA_RX_NDP_WIDER_BW, 408962306a36Sopenharmony_ci }, 409062306a36Sopenharmony_ci 409162306a36Sopenharmony_ci /* For all MCS and bandwidth, set 8 NSS for both Tx and 409262306a36Sopenharmony_ci * Rx 409362306a36Sopenharmony_ci */ 409462306a36Sopenharmony_ci .eht_mcs_nss_supp = { 409562306a36Sopenharmony_ci /* 409662306a36Sopenharmony_ci * Since B0, B1, B2 and B3 are not set in 409762306a36Sopenharmony_ci * the supported channel width set field in the 409862306a36Sopenharmony_ci * HE PHY capabilities information field the 409962306a36Sopenharmony_ci * device is a 20MHz only device on 2.4GHz band. 410062306a36Sopenharmony_ci */ 410162306a36Sopenharmony_ci .only_20mhz = { 410262306a36Sopenharmony_ci .rx_tx_mcs7_max_nss = 0x88, 410362306a36Sopenharmony_ci .rx_tx_mcs9_max_nss = 0x88, 410462306a36Sopenharmony_ci .rx_tx_mcs11_max_nss = 0x88, 410562306a36Sopenharmony_ci .rx_tx_mcs13_max_nss = 0x88, 410662306a36Sopenharmony_ci }, 410762306a36Sopenharmony_ci }, 410862306a36Sopenharmony_ci /* PPE threshold information is not supported */ 410962306a36Sopenharmony_ci }, 411062306a36Sopenharmony_ci }, 411162306a36Sopenharmony_ci { 411262306a36Sopenharmony_ci .types_mask = BIT(NL80211_IFTYPE_AP), 411362306a36Sopenharmony_ci .he_cap = { 411462306a36Sopenharmony_ci .has_he = true, 411562306a36Sopenharmony_ci .he_cap_elem = { 411662306a36Sopenharmony_ci .mac_cap_info[0] = 411762306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP0_HTC_HE, 411862306a36Sopenharmony_ci .mac_cap_info[1] = 411962306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | 412062306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 412162306a36Sopenharmony_ci .mac_cap_info[2] = 412262306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP2_BSR | 412362306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP2_MU_CASCADING | 412462306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP2_ACK_EN, 412562306a36Sopenharmony_ci .mac_cap_info[3] = 412662306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 412762306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 412862306a36Sopenharmony_ci .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 412962306a36Sopenharmony_ci .phy_cap_info[1] = 413062306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 413162306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 413262306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 413362306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 413462306a36Sopenharmony_ci .phy_cap_info[2] = 413562306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | 413662306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | 413762306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | 413862306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | 413962306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO, 414062306a36Sopenharmony_ci 414162306a36Sopenharmony_ci /* Leave all the other PHY capability bytes 414262306a36Sopenharmony_ci * unset, as DCM, beam forming, RU and PPE 414362306a36Sopenharmony_ci * threshold information are not supported 414462306a36Sopenharmony_ci */ 414562306a36Sopenharmony_ci }, 414662306a36Sopenharmony_ci .he_mcs_nss_supp = { 414762306a36Sopenharmony_ci .rx_mcs_80 = cpu_to_le16(0xfffa), 414862306a36Sopenharmony_ci .tx_mcs_80 = cpu_to_le16(0xfffa), 414962306a36Sopenharmony_ci .rx_mcs_160 = cpu_to_le16(0xffff), 415062306a36Sopenharmony_ci .tx_mcs_160 = cpu_to_le16(0xffff), 415162306a36Sopenharmony_ci .rx_mcs_80p80 = cpu_to_le16(0xffff), 415262306a36Sopenharmony_ci .tx_mcs_80p80 = cpu_to_le16(0xffff), 415362306a36Sopenharmony_ci }, 415462306a36Sopenharmony_ci }, 415562306a36Sopenharmony_ci .eht_cap = { 415662306a36Sopenharmony_ci .has_eht = true, 415762306a36Sopenharmony_ci .eht_cap_elem = { 415862306a36Sopenharmony_ci .mac_cap_info[0] = 415962306a36Sopenharmony_ci IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | 416062306a36Sopenharmony_ci IEEE80211_EHT_MAC_CAP0_OM_CONTROL | 416162306a36Sopenharmony_ci IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1, 416262306a36Sopenharmony_ci .phy_cap_info[0] = 416362306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | 416462306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | 416562306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | 416662306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER | 416762306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE, 416862306a36Sopenharmony_ci .phy_cap_info[3] = 416962306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | 417062306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | 417162306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | 417262306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | 417362306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | 417462306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | 417562306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK, 417662306a36Sopenharmony_ci .phy_cap_info[4] = 417762306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | 417862306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP4_PSR_SR_SUPP | 417962306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | 418062306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI | 418162306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK, 418262306a36Sopenharmony_ci .phy_cap_info[5] = 418362306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | 418462306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP | 418562306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP | 418662306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT | 418762306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK | 418862306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK, 418962306a36Sopenharmony_ci .phy_cap_info[6] = 419062306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK | 419162306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK, 419262306a36Sopenharmony_ci .phy_cap_info[7] = 419362306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP7_20MHZ_STA_RX_NDP_WIDER_BW, 419462306a36Sopenharmony_ci }, 419562306a36Sopenharmony_ci 419662306a36Sopenharmony_ci /* For all MCS and bandwidth, set 8 NSS for both Tx and 419762306a36Sopenharmony_ci * Rx 419862306a36Sopenharmony_ci */ 419962306a36Sopenharmony_ci .eht_mcs_nss_supp = { 420062306a36Sopenharmony_ci /* 420162306a36Sopenharmony_ci * Since B0, B1, B2 and B3 are not set in 420262306a36Sopenharmony_ci * the supported channel width set field in the 420362306a36Sopenharmony_ci * HE PHY capabilities information field the 420462306a36Sopenharmony_ci * device is a 20MHz only device on 2.4GHz band. 420562306a36Sopenharmony_ci */ 420662306a36Sopenharmony_ci .only_20mhz = { 420762306a36Sopenharmony_ci .rx_tx_mcs7_max_nss = 0x88, 420862306a36Sopenharmony_ci .rx_tx_mcs9_max_nss = 0x88, 420962306a36Sopenharmony_ci .rx_tx_mcs11_max_nss = 0x88, 421062306a36Sopenharmony_ci .rx_tx_mcs13_max_nss = 0x88, 421162306a36Sopenharmony_ci }, 421262306a36Sopenharmony_ci }, 421362306a36Sopenharmony_ci /* PPE threshold information is not supported */ 421462306a36Sopenharmony_ci }, 421562306a36Sopenharmony_ci }, 421662306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_MESH 421762306a36Sopenharmony_ci { 421862306a36Sopenharmony_ci .types_mask = BIT(NL80211_IFTYPE_MESH_POINT), 421962306a36Sopenharmony_ci .he_cap = { 422062306a36Sopenharmony_ci .has_he = true, 422162306a36Sopenharmony_ci .he_cap_elem = { 422262306a36Sopenharmony_ci .mac_cap_info[0] = 422362306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP0_HTC_HE, 422462306a36Sopenharmony_ci .mac_cap_info[1] = 422562306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 422662306a36Sopenharmony_ci .mac_cap_info[2] = 422762306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP2_ACK_EN, 422862306a36Sopenharmony_ci .mac_cap_info[3] = 422962306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 423062306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 423162306a36Sopenharmony_ci .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 423262306a36Sopenharmony_ci .phy_cap_info[1] = 423362306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 423462306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 423562306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 423662306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 423762306a36Sopenharmony_ci .phy_cap_info[2] = 0, 423862306a36Sopenharmony_ci 423962306a36Sopenharmony_ci /* Leave all the other PHY capability bytes 424062306a36Sopenharmony_ci * unset, as DCM, beam forming, RU and PPE 424162306a36Sopenharmony_ci * threshold information are not supported 424262306a36Sopenharmony_ci */ 424362306a36Sopenharmony_ci }, 424462306a36Sopenharmony_ci .he_mcs_nss_supp = { 424562306a36Sopenharmony_ci .rx_mcs_80 = cpu_to_le16(0xfffa), 424662306a36Sopenharmony_ci .tx_mcs_80 = cpu_to_le16(0xfffa), 424762306a36Sopenharmony_ci .rx_mcs_160 = cpu_to_le16(0xffff), 424862306a36Sopenharmony_ci .tx_mcs_160 = cpu_to_le16(0xffff), 424962306a36Sopenharmony_ci .rx_mcs_80p80 = cpu_to_le16(0xffff), 425062306a36Sopenharmony_ci .tx_mcs_80p80 = cpu_to_le16(0xffff), 425162306a36Sopenharmony_ci }, 425262306a36Sopenharmony_ci }, 425362306a36Sopenharmony_ci }, 425462306a36Sopenharmony_ci#endif 425562306a36Sopenharmony_ci}; 425662306a36Sopenharmony_ci 425762306a36Sopenharmony_cistatic const struct ieee80211_sband_iftype_data sband_capa_5ghz[] = { 425862306a36Sopenharmony_ci { 425962306a36Sopenharmony_ci /* TODO: should we support other types, e.g., P2P? */ 426062306a36Sopenharmony_ci .types_mask = BIT(NL80211_IFTYPE_STATION), 426162306a36Sopenharmony_ci .he_cap = { 426262306a36Sopenharmony_ci .has_he = true, 426362306a36Sopenharmony_ci .he_cap_elem = { 426462306a36Sopenharmony_ci .mac_cap_info[0] = 426562306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP0_HTC_HE, 426662306a36Sopenharmony_ci .mac_cap_info[1] = 426762306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | 426862306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 426962306a36Sopenharmony_ci .mac_cap_info[2] = 427062306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP2_BSR | 427162306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP2_MU_CASCADING | 427262306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP2_ACK_EN, 427362306a36Sopenharmony_ci .mac_cap_info[3] = 427462306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 427562306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 427662306a36Sopenharmony_ci .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 427762306a36Sopenharmony_ci .phy_cap_info[0] = 427862306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | 427962306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | 428062306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G, 428162306a36Sopenharmony_ci .phy_cap_info[1] = 428262306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 428362306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 428462306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 428562306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 428662306a36Sopenharmony_ci .phy_cap_info[2] = 428762306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | 428862306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | 428962306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | 429062306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | 429162306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO, 429262306a36Sopenharmony_ci 429362306a36Sopenharmony_ci /* Leave all the other PHY capability bytes 429462306a36Sopenharmony_ci * unset, as DCM, beam forming, RU and PPE 429562306a36Sopenharmony_ci * threshold information are not supported 429662306a36Sopenharmony_ci */ 429762306a36Sopenharmony_ci }, 429862306a36Sopenharmony_ci .he_mcs_nss_supp = { 429962306a36Sopenharmony_ci .rx_mcs_80 = cpu_to_le16(0xfffa), 430062306a36Sopenharmony_ci .tx_mcs_80 = cpu_to_le16(0xfffa), 430162306a36Sopenharmony_ci .rx_mcs_160 = cpu_to_le16(0xfffa), 430262306a36Sopenharmony_ci .tx_mcs_160 = cpu_to_le16(0xfffa), 430362306a36Sopenharmony_ci .rx_mcs_80p80 = cpu_to_le16(0xfffa), 430462306a36Sopenharmony_ci .tx_mcs_80p80 = cpu_to_le16(0xfffa), 430562306a36Sopenharmony_ci }, 430662306a36Sopenharmony_ci }, 430762306a36Sopenharmony_ci .eht_cap = { 430862306a36Sopenharmony_ci .has_eht = true, 430962306a36Sopenharmony_ci .eht_cap_elem = { 431062306a36Sopenharmony_ci .mac_cap_info[0] = 431162306a36Sopenharmony_ci IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | 431262306a36Sopenharmony_ci IEEE80211_EHT_MAC_CAP0_OM_CONTROL | 431362306a36Sopenharmony_ci IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1, 431462306a36Sopenharmony_ci .phy_cap_info[0] = 431562306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | 431662306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | 431762306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | 431862306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER | 431962306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE | 432062306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK, 432162306a36Sopenharmony_ci .phy_cap_info[1] = 432262306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK | 432362306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK, 432462306a36Sopenharmony_ci .phy_cap_info[2] = 432562306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_80MHZ_MASK | 432662306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK, 432762306a36Sopenharmony_ci .phy_cap_info[3] = 432862306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | 432962306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | 433062306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | 433162306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | 433262306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | 433362306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | 433462306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK, 433562306a36Sopenharmony_ci .phy_cap_info[4] = 433662306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | 433762306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP4_PSR_SR_SUPP | 433862306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | 433962306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI | 434062306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK, 434162306a36Sopenharmony_ci .phy_cap_info[5] = 434262306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | 434362306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP | 434462306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP | 434562306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT | 434662306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK | 434762306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK, 434862306a36Sopenharmony_ci .phy_cap_info[6] = 434962306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK | 435062306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK, 435162306a36Sopenharmony_ci .phy_cap_info[7] = 435262306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP7_20MHZ_STA_RX_NDP_WIDER_BW | 435362306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ | 435462306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ | 435562306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ | 435662306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ, 435762306a36Sopenharmony_ci }, 435862306a36Sopenharmony_ci 435962306a36Sopenharmony_ci /* For all MCS and bandwidth, set 8 NSS for both Tx and 436062306a36Sopenharmony_ci * Rx 436162306a36Sopenharmony_ci */ 436262306a36Sopenharmony_ci .eht_mcs_nss_supp = { 436362306a36Sopenharmony_ci /* 436462306a36Sopenharmony_ci * As B1 and B2 are set in the supported 436562306a36Sopenharmony_ci * channel width set field in the HE PHY 436662306a36Sopenharmony_ci * capabilities information field include all 436762306a36Sopenharmony_ci * the following MCS/NSS. 436862306a36Sopenharmony_ci */ 436962306a36Sopenharmony_ci .bw._80 = { 437062306a36Sopenharmony_ci .rx_tx_mcs9_max_nss = 0x88, 437162306a36Sopenharmony_ci .rx_tx_mcs11_max_nss = 0x88, 437262306a36Sopenharmony_ci .rx_tx_mcs13_max_nss = 0x88, 437362306a36Sopenharmony_ci }, 437462306a36Sopenharmony_ci .bw._160 = { 437562306a36Sopenharmony_ci .rx_tx_mcs9_max_nss = 0x88, 437662306a36Sopenharmony_ci .rx_tx_mcs11_max_nss = 0x88, 437762306a36Sopenharmony_ci .rx_tx_mcs13_max_nss = 0x88, 437862306a36Sopenharmony_ci }, 437962306a36Sopenharmony_ci }, 438062306a36Sopenharmony_ci /* PPE threshold information is not supported */ 438162306a36Sopenharmony_ci }, 438262306a36Sopenharmony_ci }, 438362306a36Sopenharmony_ci { 438462306a36Sopenharmony_ci .types_mask = BIT(NL80211_IFTYPE_AP), 438562306a36Sopenharmony_ci .he_cap = { 438662306a36Sopenharmony_ci .has_he = true, 438762306a36Sopenharmony_ci .he_cap_elem = { 438862306a36Sopenharmony_ci .mac_cap_info[0] = 438962306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP0_HTC_HE, 439062306a36Sopenharmony_ci .mac_cap_info[1] = 439162306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | 439262306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 439362306a36Sopenharmony_ci .mac_cap_info[2] = 439462306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP2_BSR | 439562306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP2_MU_CASCADING | 439662306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP2_ACK_EN, 439762306a36Sopenharmony_ci .mac_cap_info[3] = 439862306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 439962306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 440062306a36Sopenharmony_ci .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 440162306a36Sopenharmony_ci .phy_cap_info[0] = 440262306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | 440362306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | 440462306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G, 440562306a36Sopenharmony_ci .phy_cap_info[1] = 440662306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 440762306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 440862306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 440962306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 441062306a36Sopenharmony_ci .phy_cap_info[2] = 441162306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | 441262306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | 441362306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | 441462306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | 441562306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO, 441662306a36Sopenharmony_ci 441762306a36Sopenharmony_ci /* Leave all the other PHY capability bytes 441862306a36Sopenharmony_ci * unset, as DCM, beam forming, RU and PPE 441962306a36Sopenharmony_ci * threshold information are not supported 442062306a36Sopenharmony_ci */ 442162306a36Sopenharmony_ci }, 442262306a36Sopenharmony_ci .he_mcs_nss_supp = { 442362306a36Sopenharmony_ci .rx_mcs_80 = cpu_to_le16(0xfffa), 442462306a36Sopenharmony_ci .tx_mcs_80 = cpu_to_le16(0xfffa), 442562306a36Sopenharmony_ci .rx_mcs_160 = cpu_to_le16(0xfffa), 442662306a36Sopenharmony_ci .tx_mcs_160 = cpu_to_le16(0xfffa), 442762306a36Sopenharmony_ci .rx_mcs_80p80 = cpu_to_le16(0xfffa), 442862306a36Sopenharmony_ci .tx_mcs_80p80 = cpu_to_le16(0xfffa), 442962306a36Sopenharmony_ci }, 443062306a36Sopenharmony_ci }, 443162306a36Sopenharmony_ci .eht_cap = { 443262306a36Sopenharmony_ci .has_eht = true, 443362306a36Sopenharmony_ci .eht_cap_elem = { 443462306a36Sopenharmony_ci .mac_cap_info[0] = 443562306a36Sopenharmony_ci IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | 443662306a36Sopenharmony_ci IEEE80211_EHT_MAC_CAP0_OM_CONTROL | 443762306a36Sopenharmony_ci IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1, 443862306a36Sopenharmony_ci .phy_cap_info[0] = 443962306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | 444062306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | 444162306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | 444262306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER | 444362306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE | 444462306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK, 444562306a36Sopenharmony_ci .phy_cap_info[1] = 444662306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK | 444762306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK, 444862306a36Sopenharmony_ci .phy_cap_info[2] = 444962306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_80MHZ_MASK | 445062306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK, 445162306a36Sopenharmony_ci .phy_cap_info[3] = 445262306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | 445362306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | 445462306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | 445562306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | 445662306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | 445762306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | 445862306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK, 445962306a36Sopenharmony_ci .phy_cap_info[4] = 446062306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | 446162306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP4_PSR_SR_SUPP | 446262306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | 446362306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI | 446462306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK, 446562306a36Sopenharmony_ci .phy_cap_info[5] = 446662306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | 446762306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP | 446862306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP | 446962306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT | 447062306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK | 447162306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK, 447262306a36Sopenharmony_ci .phy_cap_info[6] = 447362306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK | 447462306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK, 447562306a36Sopenharmony_ci .phy_cap_info[7] = 447662306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP7_20MHZ_STA_RX_NDP_WIDER_BW | 447762306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ | 447862306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ | 447962306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ | 448062306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ, 448162306a36Sopenharmony_ci }, 448262306a36Sopenharmony_ci 448362306a36Sopenharmony_ci /* For all MCS and bandwidth, set 8 NSS for both Tx and 448462306a36Sopenharmony_ci * Rx 448562306a36Sopenharmony_ci */ 448662306a36Sopenharmony_ci .eht_mcs_nss_supp = { 448762306a36Sopenharmony_ci /* 448862306a36Sopenharmony_ci * As B1 and B2 are set in the supported 448962306a36Sopenharmony_ci * channel width set field in the HE PHY 449062306a36Sopenharmony_ci * capabilities information field include all 449162306a36Sopenharmony_ci * the following MCS/NSS. 449262306a36Sopenharmony_ci */ 449362306a36Sopenharmony_ci .bw._80 = { 449462306a36Sopenharmony_ci .rx_tx_mcs9_max_nss = 0x88, 449562306a36Sopenharmony_ci .rx_tx_mcs11_max_nss = 0x88, 449662306a36Sopenharmony_ci .rx_tx_mcs13_max_nss = 0x88, 449762306a36Sopenharmony_ci }, 449862306a36Sopenharmony_ci .bw._160 = { 449962306a36Sopenharmony_ci .rx_tx_mcs9_max_nss = 0x88, 450062306a36Sopenharmony_ci .rx_tx_mcs11_max_nss = 0x88, 450162306a36Sopenharmony_ci .rx_tx_mcs13_max_nss = 0x88, 450262306a36Sopenharmony_ci }, 450362306a36Sopenharmony_ci }, 450462306a36Sopenharmony_ci /* PPE threshold information is not supported */ 450562306a36Sopenharmony_ci }, 450662306a36Sopenharmony_ci }, 450762306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_MESH 450862306a36Sopenharmony_ci { 450962306a36Sopenharmony_ci /* TODO: should we support other types, e.g., IBSS?*/ 451062306a36Sopenharmony_ci .types_mask = BIT(NL80211_IFTYPE_MESH_POINT), 451162306a36Sopenharmony_ci .he_cap = { 451262306a36Sopenharmony_ci .has_he = true, 451362306a36Sopenharmony_ci .he_cap_elem = { 451462306a36Sopenharmony_ci .mac_cap_info[0] = 451562306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP0_HTC_HE, 451662306a36Sopenharmony_ci .mac_cap_info[1] = 451762306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 451862306a36Sopenharmony_ci .mac_cap_info[2] = 451962306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP2_ACK_EN, 452062306a36Sopenharmony_ci .mac_cap_info[3] = 452162306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 452262306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 452362306a36Sopenharmony_ci .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 452462306a36Sopenharmony_ci .phy_cap_info[0] = 452562306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | 452662306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | 452762306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G, 452862306a36Sopenharmony_ci .phy_cap_info[1] = 452962306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 453062306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 453162306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 453262306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 453362306a36Sopenharmony_ci .phy_cap_info[2] = 0, 453462306a36Sopenharmony_ci 453562306a36Sopenharmony_ci /* Leave all the other PHY capability bytes 453662306a36Sopenharmony_ci * unset, as DCM, beam forming, RU and PPE 453762306a36Sopenharmony_ci * threshold information are not supported 453862306a36Sopenharmony_ci */ 453962306a36Sopenharmony_ci }, 454062306a36Sopenharmony_ci .he_mcs_nss_supp = { 454162306a36Sopenharmony_ci .rx_mcs_80 = cpu_to_le16(0xfffa), 454262306a36Sopenharmony_ci .tx_mcs_80 = cpu_to_le16(0xfffa), 454362306a36Sopenharmony_ci .rx_mcs_160 = cpu_to_le16(0xfffa), 454462306a36Sopenharmony_ci .tx_mcs_160 = cpu_to_le16(0xfffa), 454562306a36Sopenharmony_ci .rx_mcs_80p80 = cpu_to_le16(0xfffa), 454662306a36Sopenharmony_ci .tx_mcs_80p80 = cpu_to_le16(0xfffa), 454762306a36Sopenharmony_ci }, 454862306a36Sopenharmony_ci }, 454962306a36Sopenharmony_ci }, 455062306a36Sopenharmony_ci#endif 455162306a36Sopenharmony_ci}; 455262306a36Sopenharmony_ci 455362306a36Sopenharmony_cistatic const struct ieee80211_sband_iftype_data sband_capa_6ghz[] = { 455462306a36Sopenharmony_ci { 455562306a36Sopenharmony_ci /* TODO: should we support other types, e.g., P2P? */ 455662306a36Sopenharmony_ci .types_mask = BIT(NL80211_IFTYPE_STATION), 455762306a36Sopenharmony_ci .he_6ghz_capa = { 455862306a36Sopenharmony_ci .capa = cpu_to_le16(IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START | 455962306a36Sopenharmony_ci IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP | 456062306a36Sopenharmony_ci IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN | 456162306a36Sopenharmony_ci IEEE80211_HE_6GHZ_CAP_SM_PS | 456262306a36Sopenharmony_ci IEEE80211_HE_6GHZ_CAP_RD_RESPONDER | 456362306a36Sopenharmony_ci IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS | 456462306a36Sopenharmony_ci IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS), 456562306a36Sopenharmony_ci }, 456662306a36Sopenharmony_ci .he_cap = { 456762306a36Sopenharmony_ci .has_he = true, 456862306a36Sopenharmony_ci .he_cap_elem = { 456962306a36Sopenharmony_ci .mac_cap_info[0] = 457062306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP0_HTC_HE, 457162306a36Sopenharmony_ci .mac_cap_info[1] = 457262306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | 457362306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 457462306a36Sopenharmony_ci .mac_cap_info[2] = 457562306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP2_BSR | 457662306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP2_MU_CASCADING | 457762306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP2_ACK_EN, 457862306a36Sopenharmony_ci .mac_cap_info[3] = 457962306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 458062306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 458162306a36Sopenharmony_ci .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 458262306a36Sopenharmony_ci .phy_cap_info[0] = 458362306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | 458462306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | 458562306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G, 458662306a36Sopenharmony_ci .phy_cap_info[1] = 458762306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 458862306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 458962306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 459062306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 459162306a36Sopenharmony_ci .phy_cap_info[2] = 459262306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | 459362306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | 459462306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | 459562306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | 459662306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO, 459762306a36Sopenharmony_ci 459862306a36Sopenharmony_ci /* Leave all the other PHY capability bytes 459962306a36Sopenharmony_ci * unset, as DCM, beam forming, RU and PPE 460062306a36Sopenharmony_ci * threshold information are not supported 460162306a36Sopenharmony_ci */ 460262306a36Sopenharmony_ci }, 460362306a36Sopenharmony_ci .he_mcs_nss_supp = { 460462306a36Sopenharmony_ci .rx_mcs_80 = cpu_to_le16(0xfffa), 460562306a36Sopenharmony_ci .tx_mcs_80 = cpu_to_le16(0xfffa), 460662306a36Sopenharmony_ci .rx_mcs_160 = cpu_to_le16(0xfffa), 460762306a36Sopenharmony_ci .tx_mcs_160 = cpu_to_le16(0xfffa), 460862306a36Sopenharmony_ci .rx_mcs_80p80 = cpu_to_le16(0xfffa), 460962306a36Sopenharmony_ci .tx_mcs_80p80 = cpu_to_le16(0xfffa), 461062306a36Sopenharmony_ci }, 461162306a36Sopenharmony_ci }, 461262306a36Sopenharmony_ci .eht_cap = { 461362306a36Sopenharmony_ci .has_eht = true, 461462306a36Sopenharmony_ci .eht_cap_elem = { 461562306a36Sopenharmony_ci .mac_cap_info[0] = 461662306a36Sopenharmony_ci IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | 461762306a36Sopenharmony_ci IEEE80211_EHT_MAC_CAP0_OM_CONTROL | 461862306a36Sopenharmony_ci IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1, 461962306a36Sopenharmony_ci .phy_cap_info[0] = 462062306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ | 462162306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | 462262306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | 462362306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | 462462306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER | 462562306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE | 462662306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK, 462762306a36Sopenharmony_ci .phy_cap_info[1] = 462862306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK | 462962306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK | 463062306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK, 463162306a36Sopenharmony_ci .phy_cap_info[2] = 463262306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_80MHZ_MASK | 463362306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK | 463462306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_320MHZ_MASK, 463562306a36Sopenharmony_ci .phy_cap_info[3] = 463662306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | 463762306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | 463862306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | 463962306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | 464062306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | 464162306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | 464262306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK, 464362306a36Sopenharmony_ci .phy_cap_info[4] = 464462306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | 464562306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP4_PSR_SR_SUPP | 464662306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | 464762306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI | 464862306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK, 464962306a36Sopenharmony_ci .phy_cap_info[5] = 465062306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | 465162306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP | 465262306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP | 465362306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT | 465462306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK | 465562306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK, 465662306a36Sopenharmony_ci .phy_cap_info[6] = 465762306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK | 465862306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK | 465962306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP6_EHT_DUP_6GHZ_SUPP, 466062306a36Sopenharmony_ci .phy_cap_info[7] = 466162306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP7_20MHZ_STA_RX_NDP_WIDER_BW | 466262306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ | 466362306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ | 466462306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_320MHZ | 466562306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ | 466662306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ | 466762306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_320MHZ, 466862306a36Sopenharmony_ci }, 466962306a36Sopenharmony_ci 467062306a36Sopenharmony_ci /* For all MCS and bandwidth, set 8 NSS for both Tx and 467162306a36Sopenharmony_ci * Rx 467262306a36Sopenharmony_ci */ 467362306a36Sopenharmony_ci .eht_mcs_nss_supp = { 467462306a36Sopenharmony_ci /* 467562306a36Sopenharmony_ci * As B1 and B2 are set in the supported 467662306a36Sopenharmony_ci * channel width set field in the HE PHY 467762306a36Sopenharmony_ci * capabilities information field and 320MHz in 467862306a36Sopenharmony_ci * 6GHz is supported include all the following 467962306a36Sopenharmony_ci * MCS/NSS. 468062306a36Sopenharmony_ci */ 468162306a36Sopenharmony_ci .bw._80 = { 468262306a36Sopenharmony_ci .rx_tx_mcs9_max_nss = 0x88, 468362306a36Sopenharmony_ci .rx_tx_mcs11_max_nss = 0x88, 468462306a36Sopenharmony_ci .rx_tx_mcs13_max_nss = 0x88, 468562306a36Sopenharmony_ci }, 468662306a36Sopenharmony_ci .bw._160 = { 468762306a36Sopenharmony_ci .rx_tx_mcs9_max_nss = 0x88, 468862306a36Sopenharmony_ci .rx_tx_mcs11_max_nss = 0x88, 468962306a36Sopenharmony_ci .rx_tx_mcs13_max_nss = 0x88, 469062306a36Sopenharmony_ci }, 469162306a36Sopenharmony_ci .bw._320 = { 469262306a36Sopenharmony_ci .rx_tx_mcs9_max_nss = 0x88, 469362306a36Sopenharmony_ci .rx_tx_mcs11_max_nss = 0x88, 469462306a36Sopenharmony_ci .rx_tx_mcs13_max_nss = 0x88, 469562306a36Sopenharmony_ci }, 469662306a36Sopenharmony_ci }, 469762306a36Sopenharmony_ci /* PPE threshold information is not supported */ 469862306a36Sopenharmony_ci }, 469962306a36Sopenharmony_ci }, 470062306a36Sopenharmony_ci { 470162306a36Sopenharmony_ci .types_mask = BIT(NL80211_IFTYPE_AP), 470262306a36Sopenharmony_ci .he_6ghz_capa = { 470362306a36Sopenharmony_ci .capa = cpu_to_le16(IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START | 470462306a36Sopenharmony_ci IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP | 470562306a36Sopenharmony_ci IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN | 470662306a36Sopenharmony_ci IEEE80211_HE_6GHZ_CAP_SM_PS | 470762306a36Sopenharmony_ci IEEE80211_HE_6GHZ_CAP_RD_RESPONDER | 470862306a36Sopenharmony_ci IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS | 470962306a36Sopenharmony_ci IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS), 471062306a36Sopenharmony_ci }, 471162306a36Sopenharmony_ci .he_cap = { 471262306a36Sopenharmony_ci .has_he = true, 471362306a36Sopenharmony_ci .he_cap_elem = { 471462306a36Sopenharmony_ci .mac_cap_info[0] = 471562306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP0_HTC_HE, 471662306a36Sopenharmony_ci .mac_cap_info[1] = 471762306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | 471862306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 471962306a36Sopenharmony_ci .mac_cap_info[2] = 472062306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP2_BSR | 472162306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP2_MU_CASCADING | 472262306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP2_ACK_EN, 472362306a36Sopenharmony_ci .mac_cap_info[3] = 472462306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 472562306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 472662306a36Sopenharmony_ci .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 472762306a36Sopenharmony_ci .phy_cap_info[0] = 472862306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | 472962306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | 473062306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G, 473162306a36Sopenharmony_ci .phy_cap_info[1] = 473262306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 473362306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 473462306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 473562306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 473662306a36Sopenharmony_ci .phy_cap_info[2] = 473762306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | 473862306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | 473962306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | 474062306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | 474162306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO, 474262306a36Sopenharmony_ci 474362306a36Sopenharmony_ci /* Leave all the other PHY capability bytes 474462306a36Sopenharmony_ci * unset, as DCM, beam forming, RU and PPE 474562306a36Sopenharmony_ci * threshold information are not supported 474662306a36Sopenharmony_ci */ 474762306a36Sopenharmony_ci }, 474862306a36Sopenharmony_ci .he_mcs_nss_supp = { 474962306a36Sopenharmony_ci .rx_mcs_80 = cpu_to_le16(0xfffa), 475062306a36Sopenharmony_ci .tx_mcs_80 = cpu_to_le16(0xfffa), 475162306a36Sopenharmony_ci .rx_mcs_160 = cpu_to_le16(0xfffa), 475262306a36Sopenharmony_ci .tx_mcs_160 = cpu_to_le16(0xfffa), 475362306a36Sopenharmony_ci .rx_mcs_80p80 = cpu_to_le16(0xfffa), 475462306a36Sopenharmony_ci .tx_mcs_80p80 = cpu_to_le16(0xfffa), 475562306a36Sopenharmony_ci }, 475662306a36Sopenharmony_ci }, 475762306a36Sopenharmony_ci .eht_cap = { 475862306a36Sopenharmony_ci .has_eht = true, 475962306a36Sopenharmony_ci .eht_cap_elem = { 476062306a36Sopenharmony_ci .mac_cap_info[0] = 476162306a36Sopenharmony_ci IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | 476262306a36Sopenharmony_ci IEEE80211_EHT_MAC_CAP0_OM_CONTROL | 476362306a36Sopenharmony_ci IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1, 476462306a36Sopenharmony_ci .phy_cap_info[0] = 476562306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ | 476662306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | 476762306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | 476862306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | 476962306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER | 477062306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE | 477162306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK, 477262306a36Sopenharmony_ci .phy_cap_info[1] = 477362306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK | 477462306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK | 477562306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK, 477662306a36Sopenharmony_ci .phy_cap_info[2] = 477762306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_80MHZ_MASK | 477862306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK | 477962306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_320MHZ_MASK, 478062306a36Sopenharmony_ci .phy_cap_info[3] = 478162306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | 478262306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | 478362306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | 478462306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | 478562306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | 478662306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | 478762306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK, 478862306a36Sopenharmony_ci .phy_cap_info[4] = 478962306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | 479062306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP4_PSR_SR_SUPP | 479162306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | 479262306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI | 479362306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK, 479462306a36Sopenharmony_ci .phy_cap_info[5] = 479562306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | 479662306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP | 479762306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP | 479862306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT | 479962306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK | 480062306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK, 480162306a36Sopenharmony_ci .phy_cap_info[6] = 480262306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK | 480362306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK | 480462306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP6_EHT_DUP_6GHZ_SUPP, 480562306a36Sopenharmony_ci .phy_cap_info[7] = 480662306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP7_20MHZ_STA_RX_NDP_WIDER_BW | 480762306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ | 480862306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ | 480962306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_320MHZ | 481062306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ | 481162306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ | 481262306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_320MHZ, 481362306a36Sopenharmony_ci }, 481462306a36Sopenharmony_ci 481562306a36Sopenharmony_ci /* For all MCS and bandwidth, set 8 NSS for both Tx and 481662306a36Sopenharmony_ci * Rx 481762306a36Sopenharmony_ci */ 481862306a36Sopenharmony_ci .eht_mcs_nss_supp = { 481962306a36Sopenharmony_ci /* 482062306a36Sopenharmony_ci * As B1 and B2 are set in the supported 482162306a36Sopenharmony_ci * channel width set field in the HE PHY 482262306a36Sopenharmony_ci * capabilities information field and 320MHz in 482362306a36Sopenharmony_ci * 6GHz is supported include all the following 482462306a36Sopenharmony_ci * MCS/NSS. 482562306a36Sopenharmony_ci */ 482662306a36Sopenharmony_ci .bw._80 = { 482762306a36Sopenharmony_ci .rx_tx_mcs9_max_nss = 0x88, 482862306a36Sopenharmony_ci .rx_tx_mcs11_max_nss = 0x88, 482962306a36Sopenharmony_ci .rx_tx_mcs13_max_nss = 0x88, 483062306a36Sopenharmony_ci }, 483162306a36Sopenharmony_ci .bw._160 = { 483262306a36Sopenharmony_ci .rx_tx_mcs9_max_nss = 0x88, 483362306a36Sopenharmony_ci .rx_tx_mcs11_max_nss = 0x88, 483462306a36Sopenharmony_ci .rx_tx_mcs13_max_nss = 0x88, 483562306a36Sopenharmony_ci }, 483662306a36Sopenharmony_ci .bw._320 = { 483762306a36Sopenharmony_ci .rx_tx_mcs9_max_nss = 0x88, 483862306a36Sopenharmony_ci .rx_tx_mcs11_max_nss = 0x88, 483962306a36Sopenharmony_ci .rx_tx_mcs13_max_nss = 0x88, 484062306a36Sopenharmony_ci }, 484162306a36Sopenharmony_ci }, 484262306a36Sopenharmony_ci /* PPE threshold information is not supported */ 484362306a36Sopenharmony_ci }, 484462306a36Sopenharmony_ci }, 484562306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_MESH 484662306a36Sopenharmony_ci { 484762306a36Sopenharmony_ci /* TODO: should we support other types, e.g., IBSS?*/ 484862306a36Sopenharmony_ci .types_mask = BIT(NL80211_IFTYPE_MESH_POINT), 484962306a36Sopenharmony_ci .he_6ghz_capa = { 485062306a36Sopenharmony_ci .capa = cpu_to_le16(IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START | 485162306a36Sopenharmony_ci IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP | 485262306a36Sopenharmony_ci IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN | 485362306a36Sopenharmony_ci IEEE80211_HE_6GHZ_CAP_SM_PS | 485462306a36Sopenharmony_ci IEEE80211_HE_6GHZ_CAP_RD_RESPONDER | 485562306a36Sopenharmony_ci IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS | 485662306a36Sopenharmony_ci IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS), 485762306a36Sopenharmony_ci }, 485862306a36Sopenharmony_ci .he_cap = { 485962306a36Sopenharmony_ci .has_he = true, 486062306a36Sopenharmony_ci .he_cap_elem = { 486162306a36Sopenharmony_ci .mac_cap_info[0] = 486262306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP0_HTC_HE, 486362306a36Sopenharmony_ci .mac_cap_info[1] = 486462306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 486562306a36Sopenharmony_ci .mac_cap_info[2] = 486662306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP2_ACK_EN, 486762306a36Sopenharmony_ci .mac_cap_info[3] = 486862306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 486962306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, 487062306a36Sopenharmony_ci .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, 487162306a36Sopenharmony_ci .phy_cap_info[0] = 487262306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | 487362306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | 487462306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G, 487562306a36Sopenharmony_ci .phy_cap_info[1] = 487662306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 487762306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 487862306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | 487962306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, 488062306a36Sopenharmony_ci .phy_cap_info[2] = 0, 488162306a36Sopenharmony_ci 488262306a36Sopenharmony_ci /* Leave all the other PHY capability bytes 488362306a36Sopenharmony_ci * unset, as DCM, beam forming, RU and PPE 488462306a36Sopenharmony_ci * threshold information are not supported 488562306a36Sopenharmony_ci */ 488662306a36Sopenharmony_ci }, 488762306a36Sopenharmony_ci .he_mcs_nss_supp = { 488862306a36Sopenharmony_ci .rx_mcs_80 = cpu_to_le16(0xfffa), 488962306a36Sopenharmony_ci .tx_mcs_80 = cpu_to_le16(0xfffa), 489062306a36Sopenharmony_ci .rx_mcs_160 = cpu_to_le16(0xfffa), 489162306a36Sopenharmony_ci .tx_mcs_160 = cpu_to_le16(0xfffa), 489262306a36Sopenharmony_ci .rx_mcs_80p80 = cpu_to_le16(0xfffa), 489362306a36Sopenharmony_ci .tx_mcs_80p80 = cpu_to_le16(0xfffa), 489462306a36Sopenharmony_ci }, 489562306a36Sopenharmony_ci }, 489662306a36Sopenharmony_ci }, 489762306a36Sopenharmony_ci#endif 489862306a36Sopenharmony_ci}; 489962306a36Sopenharmony_ci 490062306a36Sopenharmony_cistatic void mac80211_hwsim_sband_capab(struct ieee80211_supported_band *sband) 490162306a36Sopenharmony_ci{ 490262306a36Sopenharmony_ci u16 n_iftype_data; 490362306a36Sopenharmony_ci 490462306a36Sopenharmony_ci if (sband->band == NL80211_BAND_2GHZ) { 490562306a36Sopenharmony_ci n_iftype_data = ARRAY_SIZE(sband_capa_2ghz); 490662306a36Sopenharmony_ci sband->iftype_data = 490762306a36Sopenharmony_ci (struct ieee80211_sband_iftype_data *)sband_capa_2ghz; 490862306a36Sopenharmony_ci } else if (sband->band == NL80211_BAND_5GHZ) { 490962306a36Sopenharmony_ci n_iftype_data = ARRAY_SIZE(sband_capa_5ghz); 491062306a36Sopenharmony_ci sband->iftype_data = 491162306a36Sopenharmony_ci (struct ieee80211_sband_iftype_data *)sband_capa_5ghz; 491262306a36Sopenharmony_ci } else if (sband->band == NL80211_BAND_6GHZ) { 491362306a36Sopenharmony_ci n_iftype_data = ARRAY_SIZE(sband_capa_6ghz); 491462306a36Sopenharmony_ci sband->iftype_data = 491562306a36Sopenharmony_ci (struct ieee80211_sband_iftype_data *)sband_capa_6ghz; 491662306a36Sopenharmony_ci } else { 491762306a36Sopenharmony_ci return; 491862306a36Sopenharmony_ci } 491962306a36Sopenharmony_ci 492062306a36Sopenharmony_ci sband->n_iftype_data = n_iftype_data; 492162306a36Sopenharmony_ci} 492262306a36Sopenharmony_ci 492362306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_MESH 492462306a36Sopenharmony_ci#define HWSIM_MESH_BIT BIT(NL80211_IFTYPE_MESH_POINT) 492562306a36Sopenharmony_ci#else 492662306a36Sopenharmony_ci#define HWSIM_MESH_BIT 0 492762306a36Sopenharmony_ci#endif 492862306a36Sopenharmony_ci 492962306a36Sopenharmony_ci#define HWSIM_DEFAULT_IF_LIMIT \ 493062306a36Sopenharmony_ci (BIT(NL80211_IFTYPE_STATION) | \ 493162306a36Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_CLIENT) | \ 493262306a36Sopenharmony_ci BIT(NL80211_IFTYPE_AP) | \ 493362306a36Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_GO) | \ 493462306a36Sopenharmony_ci HWSIM_MESH_BIT) 493562306a36Sopenharmony_ci 493662306a36Sopenharmony_ci#define HWSIM_IFTYPE_SUPPORT_MASK \ 493762306a36Sopenharmony_ci (BIT(NL80211_IFTYPE_STATION) | \ 493862306a36Sopenharmony_ci BIT(NL80211_IFTYPE_AP) | \ 493962306a36Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_CLIENT) | \ 494062306a36Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_GO) | \ 494162306a36Sopenharmony_ci BIT(NL80211_IFTYPE_ADHOC) | \ 494262306a36Sopenharmony_ci BIT(NL80211_IFTYPE_MESH_POINT) | \ 494362306a36Sopenharmony_ci BIT(NL80211_IFTYPE_OCB)) 494462306a36Sopenharmony_ci 494562306a36Sopenharmony_cistatic int mac80211_hwsim_new_radio(struct genl_info *info, 494662306a36Sopenharmony_ci struct hwsim_new_radio_params *param) 494762306a36Sopenharmony_ci{ 494862306a36Sopenharmony_ci int err; 494962306a36Sopenharmony_ci u8 addr[ETH_ALEN]; 495062306a36Sopenharmony_ci struct mac80211_hwsim_data *data; 495162306a36Sopenharmony_ci struct ieee80211_hw *hw; 495262306a36Sopenharmony_ci enum nl80211_band band; 495362306a36Sopenharmony_ci const struct ieee80211_ops *ops = &mac80211_hwsim_ops; 495462306a36Sopenharmony_ci struct net *net; 495562306a36Sopenharmony_ci int idx, i; 495662306a36Sopenharmony_ci int n_limits = 0; 495762306a36Sopenharmony_ci 495862306a36Sopenharmony_ci if (WARN_ON(param->channels > 1 && !param->use_chanctx)) 495962306a36Sopenharmony_ci return -EINVAL; 496062306a36Sopenharmony_ci 496162306a36Sopenharmony_ci spin_lock_bh(&hwsim_radio_lock); 496262306a36Sopenharmony_ci idx = hwsim_radio_idx++; 496362306a36Sopenharmony_ci spin_unlock_bh(&hwsim_radio_lock); 496462306a36Sopenharmony_ci 496562306a36Sopenharmony_ci if (param->mlo) 496662306a36Sopenharmony_ci ops = &mac80211_hwsim_mlo_ops; 496762306a36Sopenharmony_ci else if (param->use_chanctx) 496862306a36Sopenharmony_ci ops = &mac80211_hwsim_mchan_ops; 496962306a36Sopenharmony_ci hw = ieee80211_alloc_hw_nm(sizeof(*data), ops, param->hwname); 497062306a36Sopenharmony_ci if (!hw) { 497162306a36Sopenharmony_ci pr_debug("mac80211_hwsim: ieee80211_alloc_hw failed\n"); 497262306a36Sopenharmony_ci err = -ENOMEM; 497362306a36Sopenharmony_ci goto failed; 497462306a36Sopenharmony_ci } 497562306a36Sopenharmony_ci 497662306a36Sopenharmony_ci /* ieee80211_alloc_hw_nm may have used a default name */ 497762306a36Sopenharmony_ci param->hwname = wiphy_name(hw->wiphy); 497862306a36Sopenharmony_ci 497962306a36Sopenharmony_ci if (info) 498062306a36Sopenharmony_ci net = genl_info_net(info); 498162306a36Sopenharmony_ci else 498262306a36Sopenharmony_ci net = &init_net; 498362306a36Sopenharmony_ci wiphy_net_set(hw->wiphy, net); 498462306a36Sopenharmony_ci 498562306a36Sopenharmony_ci data = hw->priv; 498662306a36Sopenharmony_ci data->hw = hw; 498762306a36Sopenharmony_ci 498862306a36Sopenharmony_ci data->dev = device_create(hwsim_class, NULL, 0, hw, "hwsim%d", idx); 498962306a36Sopenharmony_ci if (IS_ERR(data->dev)) { 499062306a36Sopenharmony_ci printk(KERN_DEBUG 499162306a36Sopenharmony_ci "mac80211_hwsim: device_create failed (%ld)\n", 499262306a36Sopenharmony_ci PTR_ERR(data->dev)); 499362306a36Sopenharmony_ci err = -ENOMEM; 499462306a36Sopenharmony_ci goto failed_drvdata; 499562306a36Sopenharmony_ci } 499662306a36Sopenharmony_ci data->dev->driver = &mac80211_hwsim_driver.driver; 499762306a36Sopenharmony_ci err = device_bind_driver(data->dev); 499862306a36Sopenharmony_ci if (err != 0) { 499962306a36Sopenharmony_ci pr_debug("mac80211_hwsim: device_bind_driver failed (%d)\n", 500062306a36Sopenharmony_ci err); 500162306a36Sopenharmony_ci goto failed_bind; 500262306a36Sopenharmony_ci } 500362306a36Sopenharmony_ci 500462306a36Sopenharmony_ci skb_queue_head_init(&data->pending); 500562306a36Sopenharmony_ci 500662306a36Sopenharmony_ci SET_IEEE80211_DEV(hw, data->dev); 500762306a36Sopenharmony_ci if (!param->perm_addr) { 500862306a36Sopenharmony_ci eth_zero_addr(addr); 500962306a36Sopenharmony_ci addr[0] = 0x02; 501062306a36Sopenharmony_ci addr[3] = idx >> 8; 501162306a36Sopenharmony_ci addr[4] = idx; 501262306a36Sopenharmony_ci memcpy(data->addresses[0].addr, addr, ETH_ALEN); 501362306a36Sopenharmony_ci /* Why need here second address ? */ 501462306a36Sopenharmony_ci memcpy(data->addresses[1].addr, addr, ETH_ALEN); 501562306a36Sopenharmony_ci data->addresses[1].addr[0] |= 0x40; 501662306a36Sopenharmony_ci hw->wiphy->n_addresses = 2; 501762306a36Sopenharmony_ci hw->wiphy->addresses = data->addresses; 501862306a36Sopenharmony_ci /* possible address clash is checked at hash table insertion */ 501962306a36Sopenharmony_ci } else { 502062306a36Sopenharmony_ci memcpy(data->addresses[0].addr, param->perm_addr, ETH_ALEN); 502162306a36Sopenharmony_ci /* compatibility with automatically generated mac addr */ 502262306a36Sopenharmony_ci memcpy(data->addresses[1].addr, param->perm_addr, ETH_ALEN); 502362306a36Sopenharmony_ci hw->wiphy->n_addresses = 2; 502462306a36Sopenharmony_ci hw->wiphy->addresses = data->addresses; 502562306a36Sopenharmony_ci } 502662306a36Sopenharmony_ci 502762306a36Sopenharmony_ci data->channels = param->channels; 502862306a36Sopenharmony_ci data->use_chanctx = param->use_chanctx; 502962306a36Sopenharmony_ci data->idx = idx; 503062306a36Sopenharmony_ci data->destroy_on_close = param->destroy_on_close; 503162306a36Sopenharmony_ci if (info) 503262306a36Sopenharmony_ci data->portid = info->snd_portid; 503362306a36Sopenharmony_ci 503462306a36Sopenharmony_ci /* setup interface limits, only on interface types we support */ 503562306a36Sopenharmony_ci if (param->iftypes & BIT(NL80211_IFTYPE_ADHOC)) { 503662306a36Sopenharmony_ci data->if_limits[n_limits].max = 1; 503762306a36Sopenharmony_ci data->if_limits[n_limits].types = BIT(NL80211_IFTYPE_ADHOC); 503862306a36Sopenharmony_ci n_limits++; 503962306a36Sopenharmony_ci } 504062306a36Sopenharmony_ci 504162306a36Sopenharmony_ci if (param->iftypes & HWSIM_DEFAULT_IF_LIMIT) { 504262306a36Sopenharmony_ci data->if_limits[n_limits].max = 2048; 504362306a36Sopenharmony_ci /* 504462306a36Sopenharmony_ci * For this case, we may only support a subset of 504562306a36Sopenharmony_ci * HWSIM_DEFAULT_IF_LIMIT, therefore we only want to add the 504662306a36Sopenharmony_ci * bits that both param->iftype & HWSIM_DEFAULT_IF_LIMIT have. 504762306a36Sopenharmony_ci */ 504862306a36Sopenharmony_ci data->if_limits[n_limits].types = 504962306a36Sopenharmony_ci HWSIM_DEFAULT_IF_LIMIT & param->iftypes; 505062306a36Sopenharmony_ci n_limits++; 505162306a36Sopenharmony_ci } 505262306a36Sopenharmony_ci 505362306a36Sopenharmony_ci if (param->iftypes & BIT(NL80211_IFTYPE_P2P_DEVICE)) { 505462306a36Sopenharmony_ci data->if_limits[n_limits].max = 1; 505562306a36Sopenharmony_ci data->if_limits[n_limits].types = 505662306a36Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_DEVICE); 505762306a36Sopenharmony_ci n_limits++; 505862306a36Sopenharmony_ci } 505962306a36Sopenharmony_ci 506062306a36Sopenharmony_ci if (data->use_chanctx) { 506162306a36Sopenharmony_ci hw->wiphy->max_scan_ssids = 255; 506262306a36Sopenharmony_ci hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; 506362306a36Sopenharmony_ci hw->wiphy->max_remain_on_channel_duration = 1000; 506462306a36Sopenharmony_ci data->if_combination.radar_detect_widths = 0; 506562306a36Sopenharmony_ci data->if_combination.num_different_channels = data->channels; 506662306a36Sopenharmony_ci } else { 506762306a36Sopenharmony_ci data->if_combination.num_different_channels = 1; 506862306a36Sopenharmony_ci data->if_combination.radar_detect_widths = 506962306a36Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_5) | 507062306a36Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_10) | 507162306a36Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_20_NOHT) | 507262306a36Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_20) | 507362306a36Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_40) | 507462306a36Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_80) | 507562306a36Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_160); 507662306a36Sopenharmony_ci } 507762306a36Sopenharmony_ci 507862306a36Sopenharmony_ci if (!n_limits) { 507962306a36Sopenharmony_ci err = -EINVAL; 508062306a36Sopenharmony_ci goto failed_hw; 508162306a36Sopenharmony_ci } 508262306a36Sopenharmony_ci 508362306a36Sopenharmony_ci data->if_combination.max_interfaces = 0; 508462306a36Sopenharmony_ci for (i = 0; i < n_limits; i++) 508562306a36Sopenharmony_ci data->if_combination.max_interfaces += 508662306a36Sopenharmony_ci data->if_limits[i].max; 508762306a36Sopenharmony_ci 508862306a36Sopenharmony_ci data->if_combination.n_limits = n_limits; 508962306a36Sopenharmony_ci data->if_combination.limits = data->if_limits; 509062306a36Sopenharmony_ci 509162306a36Sopenharmony_ci /* 509262306a36Sopenharmony_ci * If we actually were asked to support combinations, 509362306a36Sopenharmony_ci * advertise them - if there's only a single thing like 509462306a36Sopenharmony_ci * only IBSS then don't advertise it as combinations. 509562306a36Sopenharmony_ci */ 509662306a36Sopenharmony_ci if (data->if_combination.max_interfaces > 1) { 509762306a36Sopenharmony_ci hw->wiphy->iface_combinations = &data->if_combination; 509862306a36Sopenharmony_ci hw->wiphy->n_iface_combinations = 1; 509962306a36Sopenharmony_ci } 510062306a36Sopenharmony_ci 510162306a36Sopenharmony_ci if (param->ciphers) { 510262306a36Sopenharmony_ci memcpy(data->ciphers, param->ciphers, 510362306a36Sopenharmony_ci param->n_ciphers * sizeof(u32)); 510462306a36Sopenharmony_ci hw->wiphy->cipher_suites = data->ciphers; 510562306a36Sopenharmony_ci hw->wiphy->n_cipher_suites = param->n_ciphers; 510662306a36Sopenharmony_ci } 510762306a36Sopenharmony_ci 510862306a36Sopenharmony_ci hw->wiphy->mbssid_max_interfaces = 8; 510962306a36Sopenharmony_ci hw->wiphy->ema_max_profile_periodicity = 3; 511062306a36Sopenharmony_ci 511162306a36Sopenharmony_ci data->rx_rssi = DEFAULT_RX_RSSI; 511262306a36Sopenharmony_ci 511362306a36Sopenharmony_ci INIT_DELAYED_WORK(&data->roc_start, hw_roc_start); 511462306a36Sopenharmony_ci INIT_DELAYED_WORK(&data->roc_done, hw_roc_done); 511562306a36Sopenharmony_ci INIT_DELAYED_WORK(&data->hw_scan, hw_scan_work); 511662306a36Sopenharmony_ci 511762306a36Sopenharmony_ci hw->queues = 5; 511862306a36Sopenharmony_ci hw->offchannel_tx_hw_queue = 4; 511962306a36Sopenharmony_ci 512062306a36Sopenharmony_ci ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); 512162306a36Sopenharmony_ci ieee80211_hw_set(hw, CHANCTX_STA_CSA); 512262306a36Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); 512362306a36Sopenharmony_ci ieee80211_hw_set(hw, QUEUE_CONTROL); 512462306a36Sopenharmony_ci ieee80211_hw_set(hw, WANT_MONITOR_VIF); 512562306a36Sopenharmony_ci ieee80211_hw_set(hw, AMPDU_AGGREGATION); 512662306a36Sopenharmony_ci ieee80211_hw_set(hw, MFP_CAPABLE); 512762306a36Sopenharmony_ci ieee80211_hw_set(hw, SIGNAL_DBM); 512862306a36Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_PS); 512962306a36Sopenharmony_ci ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); 513062306a36Sopenharmony_ci ieee80211_hw_set(hw, TDLS_WIDER_BW); 513162306a36Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); 513262306a36Sopenharmony_ci 513362306a36Sopenharmony_ci if (param->mlo) { 513462306a36Sopenharmony_ci hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_MLO; 513562306a36Sopenharmony_ci ieee80211_hw_set(hw, HAS_RATE_CONTROL); 513662306a36Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); 513762306a36Sopenharmony_ci ieee80211_hw_set(hw, CONNECTION_MONITOR); 513862306a36Sopenharmony_ci ieee80211_hw_set(hw, AP_LINK_PS); 513962306a36Sopenharmony_ci } else { 514062306a36Sopenharmony_ci ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); 514162306a36Sopenharmony_ci ieee80211_hw_set(hw, PS_NULLFUNC_STACK); 514262306a36Sopenharmony_ci if (rctbl) 514362306a36Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); 514462306a36Sopenharmony_ci } 514562306a36Sopenharmony_ci 514662306a36Sopenharmony_ci hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; 514762306a36Sopenharmony_ci hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | 514862306a36Sopenharmony_ci WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | 514962306a36Sopenharmony_ci WIPHY_FLAG_AP_UAPSD | 515062306a36Sopenharmony_ci WIPHY_FLAG_SUPPORTS_5_10_MHZ | 515162306a36Sopenharmony_ci WIPHY_FLAG_HAS_CHANNEL_SWITCH; 515262306a36Sopenharmony_ci hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR | 515362306a36Sopenharmony_ci NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | 515462306a36Sopenharmony_ci NL80211_FEATURE_STATIC_SMPS | 515562306a36Sopenharmony_ci NL80211_FEATURE_DYNAMIC_SMPS | 515662306a36Sopenharmony_ci NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; 515762306a36Sopenharmony_ci wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS); 515862306a36Sopenharmony_ci wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_BEACON_PROTECTION); 515962306a36Sopenharmony_ci wiphy_ext_feature_set(hw->wiphy, 516062306a36Sopenharmony_ci NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS); 516162306a36Sopenharmony_ci wiphy_ext_feature_set(hw->wiphy, 516262306a36Sopenharmony_ci NL80211_EXT_FEATURE_BEACON_RATE_LEGACY); 516362306a36Sopenharmony_ci wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER); 516462306a36Sopenharmony_ci 516562306a36Sopenharmony_ci wiphy_ext_feature_set(hw->wiphy, 516662306a36Sopenharmony_ci NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT); 516762306a36Sopenharmony_ci 516862306a36Sopenharmony_ci hw->wiphy->interface_modes = param->iftypes; 516962306a36Sopenharmony_ci 517062306a36Sopenharmony_ci /* ask mac80211 to reserve space for magic */ 517162306a36Sopenharmony_ci hw->vif_data_size = sizeof(struct hwsim_vif_priv); 517262306a36Sopenharmony_ci hw->sta_data_size = sizeof(struct hwsim_sta_priv); 517362306a36Sopenharmony_ci hw->chanctx_data_size = sizeof(struct hwsim_chanctx_priv); 517462306a36Sopenharmony_ci 517562306a36Sopenharmony_ci memcpy(data->channels_2ghz, hwsim_channels_2ghz, 517662306a36Sopenharmony_ci sizeof(hwsim_channels_2ghz)); 517762306a36Sopenharmony_ci memcpy(data->channels_5ghz, hwsim_channels_5ghz, 517862306a36Sopenharmony_ci sizeof(hwsim_channels_5ghz)); 517962306a36Sopenharmony_ci memcpy(data->channels_6ghz, hwsim_channels_6ghz, 518062306a36Sopenharmony_ci sizeof(hwsim_channels_6ghz)); 518162306a36Sopenharmony_ci memcpy(data->channels_s1g, hwsim_channels_s1g, 518262306a36Sopenharmony_ci sizeof(hwsim_channels_s1g)); 518362306a36Sopenharmony_ci memcpy(data->rates, hwsim_rates, sizeof(hwsim_rates)); 518462306a36Sopenharmony_ci 518562306a36Sopenharmony_ci for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; band++) { 518662306a36Sopenharmony_ci struct ieee80211_supported_band *sband = &data->bands[band]; 518762306a36Sopenharmony_ci 518862306a36Sopenharmony_ci sband->band = band; 518962306a36Sopenharmony_ci 519062306a36Sopenharmony_ci switch (band) { 519162306a36Sopenharmony_ci case NL80211_BAND_2GHZ: 519262306a36Sopenharmony_ci sband->channels = data->channels_2ghz; 519362306a36Sopenharmony_ci sband->n_channels = ARRAY_SIZE(hwsim_channels_2ghz); 519462306a36Sopenharmony_ci sband->bitrates = data->rates; 519562306a36Sopenharmony_ci sband->n_bitrates = ARRAY_SIZE(hwsim_rates); 519662306a36Sopenharmony_ci break; 519762306a36Sopenharmony_ci case NL80211_BAND_5GHZ: 519862306a36Sopenharmony_ci sband->channels = data->channels_5ghz; 519962306a36Sopenharmony_ci sband->n_channels = ARRAY_SIZE(hwsim_channels_5ghz); 520062306a36Sopenharmony_ci sband->bitrates = data->rates + 4; 520162306a36Sopenharmony_ci sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4; 520262306a36Sopenharmony_ci 520362306a36Sopenharmony_ci sband->vht_cap.vht_supported = true; 520462306a36Sopenharmony_ci sband->vht_cap.cap = 520562306a36Sopenharmony_ci IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | 520662306a36Sopenharmony_ci IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ | 520762306a36Sopenharmony_ci IEEE80211_VHT_CAP_RXLDPC | 520862306a36Sopenharmony_ci IEEE80211_VHT_CAP_SHORT_GI_80 | 520962306a36Sopenharmony_ci IEEE80211_VHT_CAP_SHORT_GI_160 | 521062306a36Sopenharmony_ci IEEE80211_VHT_CAP_TXSTBC | 521162306a36Sopenharmony_ci IEEE80211_VHT_CAP_RXSTBC_4 | 521262306a36Sopenharmony_ci IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; 521362306a36Sopenharmony_ci sband->vht_cap.vht_mcs.rx_mcs_map = 521462306a36Sopenharmony_ci cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | 521562306a36Sopenharmony_ci IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 | 521662306a36Sopenharmony_ci IEEE80211_VHT_MCS_SUPPORT_0_9 << 4 | 521762306a36Sopenharmony_ci IEEE80211_VHT_MCS_SUPPORT_0_9 << 6 | 521862306a36Sopenharmony_ci IEEE80211_VHT_MCS_SUPPORT_0_9 << 8 | 521962306a36Sopenharmony_ci IEEE80211_VHT_MCS_SUPPORT_0_9 << 10 | 522062306a36Sopenharmony_ci IEEE80211_VHT_MCS_SUPPORT_0_9 << 12 | 522162306a36Sopenharmony_ci IEEE80211_VHT_MCS_SUPPORT_0_9 << 14); 522262306a36Sopenharmony_ci sband->vht_cap.vht_mcs.tx_mcs_map = 522362306a36Sopenharmony_ci sband->vht_cap.vht_mcs.rx_mcs_map; 522462306a36Sopenharmony_ci break; 522562306a36Sopenharmony_ci case NL80211_BAND_6GHZ: 522662306a36Sopenharmony_ci sband->channels = data->channels_6ghz; 522762306a36Sopenharmony_ci sband->n_channels = ARRAY_SIZE(hwsim_channels_6ghz); 522862306a36Sopenharmony_ci sband->bitrates = data->rates + 4; 522962306a36Sopenharmony_ci sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4; 523062306a36Sopenharmony_ci break; 523162306a36Sopenharmony_ci case NL80211_BAND_S1GHZ: 523262306a36Sopenharmony_ci memcpy(&sband->s1g_cap, &hwsim_s1g_cap, 523362306a36Sopenharmony_ci sizeof(sband->s1g_cap)); 523462306a36Sopenharmony_ci sband->channels = data->channels_s1g; 523562306a36Sopenharmony_ci sband->n_channels = ARRAY_SIZE(hwsim_channels_s1g); 523662306a36Sopenharmony_ci break; 523762306a36Sopenharmony_ci default: 523862306a36Sopenharmony_ci continue; 523962306a36Sopenharmony_ci } 524062306a36Sopenharmony_ci 524162306a36Sopenharmony_ci if (band != NL80211_BAND_6GHZ){ 524262306a36Sopenharmony_ci sband->ht_cap.ht_supported = true; 524362306a36Sopenharmony_ci sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | 524462306a36Sopenharmony_ci IEEE80211_HT_CAP_GRN_FLD | 524562306a36Sopenharmony_ci IEEE80211_HT_CAP_SGI_20 | 524662306a36Sopenharmony_ci IEEE80211_HT_CAP_SGI_40 | 524762306a36Sopenharmony_ci IEEE80211_HT_CAP_DSSSCCK40; 524862306a36Sopenharmony_ci sband->ht_cap.ampdu_factor = 0x3; 524962306a36Sopenharmony_ci sband->ht_cap.ampdu_density = 0x6; 525062306a36Sopenharmony_ci memset(&sband->ht_cap.mcs, 0, 525162306a36Sopenharmony_ci sizeof(sband->ht_cap.mcs)); 525262306a36Sopenharmony_ci sband->ht_cap.mcs.rx_mask[0] = 0xff; 525362306a36Sopenharmony_ci sband->ht_cap.mcs.rx_mask[1] = 0xff; 525462306a36Sopenharmony_ci sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; 525562306a36Sopenharmony_ci } 525662306a36Sopenharmony_ci 525762306a36Sopenharmony_ci mac80211_hwsim_sband_capab(sband); 525862306a36Sopenharmony_ci 525962306a36Sopenharmony_ci hw->wiphy->bands[band] = sband; 526062306a36Sopenharmony_ci } 526162306a36Sopenharmony_ci 526262306a36Sopenharmony_ci /* By default all radios belong to the first group */ 526362306a36Sopenharmony_ci data->group = 1; 526462306a36Sopenharmony_ci mutex_init(&data->mutex); 526562306a36Sopenharmony_ci 526662306a36Sopenharmony_ci data->netgroup = hwsim_net_get_netgroup(net); 526762306a36Sopenharmony_ci data->wmediumd = hwsim_net_get_wmediumd(net); 526862306a36Sopenharmony_ci 526962306a36Sopenharmony_ci /* Enable frame retransmissions for lossy channels */ 527062306a36Sopenharmony_ci hw->max_rates = 4; 527162306a36Sopenharmony_ci hw->max_rate_tries = 11; 527262306a36Sopenharmony_ci 527362306a36Sopenharmony_ci hw->wiphy->vendor_commands = mac80211_hwsim_vendor_commands; 527462306a36Sopenharmony_ci hw->wiphy->n_vendor_commands = 527562306a36Sopenharmony_ci ARRAY_SIZE(mac80211_hwsim_vendor_commands); 527662306a36Sopenharmony_ci hw->wiphy->vendor_events = mac80211_hwsim_vendor_events; 527762306a36Sopenharmony_ci hw->wiphy->n_vendor_events = ARRAY_SIZE(mac80211_hwsim_vendor_events); 527862306a36Sopenharmony_ci 527962306a36Sopenharmony_ci if (param->reg_strict) 528062306a36Sopenharmony_ci hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG; 528162306a36Sopenharmony_ci if (param->regd) { 528262306a36Sopenharmony_ci data->regd = param->regd; 528362306a36Sopenharmony_ci hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; 528462306a36Sopenharmony_ci wiphy_apply_custom_regulatory(hw->wiphy, param->regd); 528562306a36Sopenharmony_ci /* give the regulatory workqueue a chance to run */ 528662306a36Sopenharmony_ci schedule_timeout_interruptible(1); 528762306a36Sopenharmony_ci } 528862306a36Sopenharmony_ci 528962306a36Sopenharmony_ci if (param->no_vif) 529062306a36Sopenharmony_ci ieee80211_hw_set(hw, NO_AUTO_VIF); 529162306a36Sopenharmony_ci 529262306a36Sopenharmony_ci wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); 529362306a36Sopenharmony_ci 529462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(data->link_data); i++) { 529562306a36Sopenharmony_ci hrtimer_init(&data->link_data[i].beacon_timer, CLOCK_MONOTONIC, 529662306a36Sopenharmony_ci HRTIMER_MODE_ABS_SOFT); 529762306a36Sopenharmony_ci data->link_data[i].beacon_timer.function = 529862306a36Sopenharmony_ci mac80211_hwsim_beacon; 529962306a36Sopenharmony_ci data->link_data[i].link_id = i; 530062306a36Sopenharmony_ci } 530162306a36Sopenharmony_ci 530262306a36Sopenharmony_ci err = ieee80211_register_hw(hw); 530362306a36Sopenharmony_ci if (err < 0) { 530462306a36Sopenharmony_ci pr_debug("mac80211_hwsim: ieee80211_register_hw failed (%d)\n", 530562306a36Sopenharmony_ci err); 530662306a36Sopenharmony_ci goto failed_hw; 530762306a36Sopenharmony_ci } 530862306a36Sopenharmony_ci 530962306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, "hwaddr %pM registered\n", hw->wiphy->perm_addr); 531062306a36Sopenharmony_ci 531162306a36Sopenharmony_ci if (param->reg_alpha2) { 531262306a36Sopenharmony_ci data->alpha2[0] = param->reg_alpha2[0]; 531362306a36Sopenharmony_ci data->alpha2[1] = param->reg_alpha2[1]; 531462306a36Sopenharmony_ci regulatory_hint(hw->wiphy, param->reg_alpha2); 531562306a36Sopenharmony_ci } 531662306a36Sopenharmony_ci 531762306a36Sopenharmony_ci data->debugfs = debugfs_create_dir("hwsim", hw->wiphy->debugfsdir); 531862306a36Sopenharmony_ci debugfs_create_file("ps", 0666, data->debugfs, data, &hwsim_fops_ps); 531962306a36Sopenharmony_ci debugfs_create_file("group", 0666, data->debugfs, data, 532062306a36Sopenharmony_ci &hwsim_fops_group); 532162306a36Sopenharmony_ci debugfs_create_file("rx_rssi", 0666, data->debugfs, data, 532262306a36Sopenharmony_ci &hwsim_fops_rx_rssi); 532362306a36Sopenharmony_ci if (!data->use_chanctx) 532462306a36Sopenharmony_ci debugfs_create_file("dfs_simulate_radar", 0222, 532562306a36Sopenharmony_ci data->debugfs, 532662306a36Sopenharmony_ci data, &hwsim_simulate_radar); 532762306a36Sopenharmony_ci 532862306a36Sopenharmony_ci if (param->pmsr_capa) { 532962306a36Sopenharmony_ci data->pmsr_capa = *param->pmsr_capa; 533062306a36Sopenharmony_ci hw->wiphy->pmsr_capa = &data->pmsr_capa; 533162306a36Sopenharmony_ci } 533262306a36Sopenharmony_ci 533362306a36Sopenharmony_ci spin_lock_bh(&hwsim_radio_lock); 533462306a36Sopenharmony_ci err = rhashtable_insert_fast(&hwsim_radios_rht, &data->rht, 533562306a36Sopenharmony_ci hwsim_rht_params); 533662306a36Sopenharmony_ci if (err < 0) { 533762306a36Sopenharmony_ci if (info) { 533862306a36Sopenharmony_ci GENL_SET_ERR_MSG(info, "perm addr already present"); 533962306a36Sopenharmony_ci NL_SET_BAD_ATTR(info->extack, 534062306a36Sopenharmony_ci info->attrs[HWSIM_ATTR_PERM_ADDR]); 534162306a36Sopenharmony_ci } 534262306a36Sopenharmony_ci spin_unlock_bh(&hwsim_radio_lock); 534362306a36Sopenharmony_ci goto failed_final_insert; 534462306a36Sopenharmony_ci } 534562306a36Sopenharmony_ci 534662306a36Sopenharmony_ci list_add_tail(&data->list, &hwsim_radios); 534762306a36Sopenharmony_ci hwsim_radios_generation++; 534862306a36Sopenharmony_ci spin_unlock_bh(&hwsim_radio_lock); 534962306a36Sopenharmony_ci 535062306a36Sopenharmony_ci hwsim_mcast_new_radio(idx, info, param); 535162306a36Sopenharmony_ci 535262306a36Sopenharmony_ci return idx; 535362306a36Sopenharmony_ci 535462306a36Sopenharmony_cifailed_final_insert: 535562306a36Sopenharmony_ci debugfs_remove_recursive(data->debugfs); 535662306a36Sopenharmony_ci ieee80211_unregister_hw(data->hw); 535762306a36Sopenharmony_cifailed_hw: 535862306a36Sopenharmony_ci device_release_driver(data->dev); 535962306a36Sopenharmony_cifailed_bind: 536062306a36Sopenharmony_ci device_unregister(data->dev); 536162306a36Sopenharmony_cifailed_drvdata: 536262306a36Sopenharmony_ci ieee80211_free_hw(hw); 536362306a36Sopenharmony_cifailed: 536462306a36Sopenharmony_ci return err; 536562306a36Sopenharmony_ci} 536662306a36Sopenharmony_ci 536762306a36Sopenharmony_cistatic void hwsim_mcast_del_radio(int id, const char *hwname, 536862306a36Sopenharmony_ci struct genl_info *info) 536962306a36Sopenharmony_ci{ 537062306a36Sopenharmony_ci struct sk_buff *skb; 537162306a36Sopenharmony_ci void *data; 537262306a36Sopenharmony_ci int ret; 537362306a36Sopenharmony_ci 537462306a36Sopenharmony_ci skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 537562306a36Sopenharmony_ci if (!skb) 537662306a36Sopenharmony_ci return; 537762306a36Sopenharmony_ci 537862306a36Sopenharmony_ci data = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, 537962306a36Sopenharmony_ci HWSIM_CMD_DEL_RADIO); 538062306a36Sopenharmony_ci if (!data) 538162306a36Sopenharmony_ci goto error; 538262306a36Sopenharmony_ci 538362306a36Sopenharmony_ci ret = nla_put_u32(skb, HWSIM_ATTR_RADIO_ID, id); 538462306a36Sopenharmony_ci if (ret < 0) 538562306a36Sopenharmony_ci goto error; 538662306a36Sopenharmony_ci 538762306a36Sopenharmony_ci ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME, strlen(hwname), 538862306a36Sopenharmony_ci hwname); 538962306a36Sopenharmony_ci if (ret < 0) 539062306a36Sopenharmony_ci goto error; 539162306a36Sopenharmony_ci 539262306a36Sopenharmony_ci genlmsg_end(skb, data); 539362306a36Sopenharmony_ci 539462306a36Sopenharmony_ci hwsim_mcast_config_msg(skb, info); 539562306a36Sopenharmony_ci 539662306a36Sopenharmony_ci return; 539762306a36Sopenharmony_ci 539862306a36Sopenharmony_cierror: 539962306a36Sopenharmony_ci nlmsg_free(skb); 540062306a36Sopenharmony_ci} 540162306a36Sopenharmony_ci 540262306a36Sopenharmony_cistatic void mac80211_hwsim_del_radio(struct mac80211_hwsim_data *data, 540362306a36Sopenharmony_ci const char *hwname, 540462306a36Sopenharmony_ci struct genl_info *info) 540562306a36Sopenharmony_ci{ 540662306a36Sopenharmony_ci hwsim_mcast_del_radio(data->idx, hwname, info); 540762306a36Sopenharmony_ci debugfs_remove_recursive(data->debugfs); 540862306a36Sopenharmony_ci ieee80211_unregister_hw(data->hw); 540962306a36Sopenharmony_ci device_release_driver(data->dev); 541062306a36Sopenharmony_ci device_unregister(data->dev); 541162306a36Sopenharmony_ci ieee80211_free_hw(data->hw); 541262306a36Sopenharmony_ci} 541362306a36Sopenharmony_ci 541462306a36Sopenharmony_cistatic int mac80211_hwsim_get_radio(struct sk_buff *skb, 541562306a36Sopenharmony_ci struct mac80211_hwsim_data *data, 541662306a36Sopenharmony_ci u32 portid, u32 seq, 541762306a36Sopenharmony_ci struct netlink_callback *cb, int flags) 541862306a36Sopenharmony_ci{ 541962306a36Sopenharmony_ci void *hdr; 542062306a36Sopenharmony_ci struct hwsim_new_radio_params param = { }; 542162306a36Sopenharmony_ci int res = -EMSGSIZE; 542262306a36Sopenharmony_ci 542362306a36Sopenharmony_ci hdr = genlmsg_put(skb, portid, seq, &hwsim_genl_family, flags, 542462306a36Sopenharmony_ci HWSIM_CMD_GET_RADIO); 542562306a36Sopenharmony_ci if (!hdr) 542662306a36Sopenharmony_ci return -EMSGSIZE; 542762306a36Sopenharmony_ci 542862306a36Sopenharmony_ci if (cb) 542962306a36Sopenharmony_ci genl_dump_check_consistent(cb, hdr); 543062306a36Sopenharmony_ci 543162306a36Sopenharmony_ci if (data->alpha2[0] && data->alpha2[1]) 543262306a36Sopenharmony_ci param.reg_alpha2 = data->alpha2; 543362306a36Sopenharmony_ci 543462306a36Sopenharmony_ci param.reg_strict = !!(data->hw->wiphy->regulatory_flags & 543562306a36Sopenharmony_ci REGULATORY_STRICT_REG); 543662306a36Sopenharmony_ci param.p2p_device = !!(data->hw->wiphy->interface_modes & 543762306a36Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_DEVICE)); 543862306a36Sopenharmony_ci param.use_chanctx = data->use_chanctx; 543962306a36Sopenharmony_ci param.regd = data->regd; 544062306a36Sopenharmony_ci param.channels = data->channels; 544162306a36Sopenharmony_ci param.hwname = wiphy_name(data->hw->wiphy); 544262306a36Sopenharmony_ci param.pmsr_capa = &data->pmsr_capa; 544362306a36Sopenharmony_ci 544462306a36Sopenharmony_ci res = append_radio_msg(skb, data->idx, ¶m); 544562306a36Sopenharmony_ci if (res < 0) 544662306a36Sopenharmony_ci goto out_err; 544762306a36Sopenharmony_ci 544862306a36Sopenharmony_ci genlmsg_end(skb, hdr); 544962306a36Sopenharmony_ci return 0; 545062306a36Sopenharmony_ci 545162306a36Sopenharmony_ciout_err: 545262306a36Sopenharmony_ci genlmsg_cancel(skb, hdr); 545362306a36Sopenharmony_ci return res; 545462306a36Sopenharmony_ci} 545562306a36Sopenharmony_ci 545662306a36Sopenharmony_cistatic void mac80211_hwsim_free(void) 545762306a36Sopenharmony_ci{ 545862306a36Sopenharmony_ci struct mac80211_hwsim_data *data; 545962306a36Sopenharmony_ci 546062306a36Sopenharmony_ci spin_lock_bh(&hwsim_radio_lock); 546162306a36Sopenharmony_ci while ((data = list_first_entry_or_null(&hwsim_radios, 546262306a36Sopenharmony_ci struct mac80211_hwsim_data, 546362306a36Sopenharmony_ci list))) { 546462306a36Sopenharmony_ci list_del(&data->list); 546562306a36Sopenharmony_ci spin_unlock_bh(&hwsim_radio_lock); 546662306a36Sopenharmony_ci mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy), 546762306a36Sopenharmony_ci NULL); 546862306a36Sopenharmony_ci spin_lock_bh(&hwsim_radio_lock); 546962306a36Sopenharmony_ci } 547062306a36Sopenharmony_ci spin_unlock_bh(&hwsim_radio_lock); 547162306a36Sopenharmony_ci class_destroy(hwsim_class); 547262306a36Sopenharmony_ci} 547362306a36Sopenharmony_ci 547462306a36Sopenharmony_cistatic const struct net_device_ops hwsim_netdev_ops = { 547562306a36Sopenharmony_ci .ndo_start_xmit = hwsim_mon_xmit, 547662306a36Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 547762306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 547862306a36Sopenharmony_ci}; 547962306a36Sopenharmony_ci 548062306a36Sopenharmony_cistatic void hwsim_mon_setup(struct net_device *dev) 548162306a36Sopenharmony_ci{ 548262306a36Sopenharmony_ci u8 addr[ETH_ALEN]; 548362306a36Sopenharmony_ci 548462306a36Sopenharmony_ci dev->netdev_ops = &hwsim_netdev_ops; 548562306a36Sopenharmony_ci dev->needs_free_netdev = true; 548662306a36Sopenharmony_ci ether_setup(dev); 548762306a36Sopenharmony_ci dev->priv_flags |= IFF_NO_QUEUE; 548862306a36Sopenharmony_ci dev->type = ARPHRD_IEEE80211_RADIOTAP; 548962306a36Sopenharmony_ci eth_zero_addr(addr); 549062306a36Sopenharmony_ci addr[0] = 0x12; 549162306a36Sopenharmony_ci eth_hw_addr_set(dev, addr); 549262306a36Sopenharmony_ci} 549362306a36Sopenharmony_ci 549462306a36Sopenharmony_cistatic void hwsim_register_wmediumd(struct net *net, u32 portid) 549562306a36Sopenharmony_ci{ 549662306a36Sopenharmony_ci struct mac80211_hwsim_data *data; 549762306a36Sopenharmony_ci 549862306a36Sopenharmony_ci hwsim_net_set_wmediumd(net, portid); 549962306a36Sopenharmony_ci 550062306a36Sopenharmony_ci spin_lock_bh(&hwsim_radio_lock); 550162306a36Sopenharmony_ci list_for_each_entry(data, &hwsim_radios, list) { 550262306a36Sopenharmony_ci if (data->netgroup == hwsim_net_get_netgroup(net)) 550362306a36Sopenharmony_ci data->wmediumd = portid; 550462306a36Sopenharmony_ci } 550562306a36Sopenharmony_ci spin_unlock_bh(&hwsim_radio_lock); 550662306a36Sopenharmony_ci} 550762306a36Sopenharmony_ci 550862306a36Sopenharmony_cistatic int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2, 550962306a36Sopenharmony_ci struct genl_info *info) 551062306a36Sopenharmony_ci{ 551162306a36Sopenharmony_ci 551262306a36Sopenharmony_ci struct ieee80211_hdr *hdr; 551362306a36Sopenharmony_ci struct mac80211_hwsim_data *data2; 551462306a36Sopenharmony_ci struct ieee80211_tx_info *txi; 551562306a36Sopenharmony_ci struct hwsim_tx_rate *tx_attempts; 551662306a36Sopenharmony_ci u64 ret_skb_cookie; 551762306a36Sopenharmony_ci struct sk_buff *skb, *tmp; 551862306a36Sopenharmony_ci const u8 *src; 551962306a36Sopenharmony_ci unsigned int hwsim_flags; 552062306a36Sopenharmony_ci int i; 552162306a36Sopenharmony_ci unsigned long flags; 552262306a36Sopenharmony_ci bool found = false; 552362306a36Sopenharmony_ci 552462306a36Sopenharmony_ci if (!info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER] || 552562306a36Sopenharmony_ci !info->attrs[HWSIM_ATTR_FLAGS] || 552662306a36Sopenharmony_ci !info->attrs[HWSIM_ATTR_COOKIE] || 552762306a36Sopenharmony_ci !info->attrs[HWSIM_ATTR_SIGNAL] || 552862306a36Sopenharmony_ci !info->attrs[HWSIM_ATTR_TX_INFO]) 552962306a36Sopenharmony_ci goto out; 553062306a36Sopenharmony_ci 553162306a36Sopenharmony_ci src = (void *)nla_data(info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER]); 553262306a36Sopenharmony_ci hwsim_flags = nla_get_u32(info->attrs[HWSIM_ATTR_FLAGS]); 553362306a36Sopenharmony_ci ret_skb_cookie = nla_get_u64(info->attrs[HWSIM_ATTR_COOKIE]); 553462306a36Sopenharmony_ci 553562306a36Sopenharmony_ci data2 = get_hwsim_data_ref_from_addr(src); 553662306a36Sopenharmony_ci if (!data2) 553762306a36Sopenharmony_ci goto out; 553862306a36Sopenharmony_ci 553962306a36Sopenharmony_ci if (!hwsim_virtio_enabled) { 554062306a36Sopenharmony_ci if (hwsim_net_get_netgroup(genl_info_net(info)) != 554162306a36Sopenharmony_ci data2->netgroup) 554262306a36Sopenharmony_ci goto out; 554362306a36Sopenharmony_ci 554462306a36Sopenharmony_ci if (info->snd_portid != data2->wmediumd) 554562306a36Sopenharmony_ci goto out; 554662306a36Sopenharmony_ci } 554762306a36Sopenharmony_ci 554862306a36Sopenharmony_ci /* look for the skb matching the cookie passed back from user */ 554962306a36Sopenharmony_ci spin_lock_irqsave(&data2->pending.lock, flags); 555062306a36Sopenharmony_ci skb_queue_walk_safe(&data2->pending, skb, tmp) { 555162306a36Sopenharmony_ci uintptr_t skb_cookie; 555262306a36Sopenharmony_ci 555362306a36Sopenharmony_ci txi = IEEE80211_SKB_CB(skb); 555462306a36Sopenharmony_ci skb_cookie = (uintptr_t)txi->rate_driver_data[0]; 555562306a36Sopenharmony_ci 555662306a36Sopenharmony_ci if (skb_cookie == ret_skb_cookie) { 555762306a36Sopenharmony_ci __skb_unlink(skb, &data2->pending); 555862306a36Sopenharmony_ci found = true; 555962306a36Sopenharmony_ci break; 556062306a36Sopenharmony_ci } 556162306a36Sopenharmony_ci } 556262306a36Sopenharmony_ci spin_unlock_irqrestore(&data2->pending.lock, flags); 556362306a36Sopenharmony_ci 556462306a36Sopenharmony_ci /* not found */ 556562306a36Sopenharmony_ci if (!found) 556662306a36Sopenharmony_ci goto out; 556762306a36Sopenharmony_ci 556862306a36Sopenharmony_ci /* Tx info received because the frame was broadcasted on user space, 556962306a36Sopenharmony_ci so we get all the necessary info: tx attempts and skb control buff */ 557062306a36Sopenharmony_ci 557162306a36Sopenharmony_ci tx_attempts = (struct hwsim_tx_rate *)nla_data( 557262306a36Sopenharmony_ci info->attrs[HWSIM_ATTR_TX_INFO]); 557362306a36Sopenharmony_ci 557462306a36Sopenharmony_ci /* now send back TX status */ 557562306a36Sopenharmony_ci txi = IEEE80211_SKB_CB(skb); 557662306a36Sopenharmony_ci 557762306a36Sopenharmony_ci ieee80211_tx_info_clear_status(txi); 557862306a36Sopenharmony_ci 557962306a36Sopenharmony_ci for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { 558062306a36Sopenharmony_ci txi->status.rates[i].idx = tx_attempts[i].idx; 558162306a36Sopenharmony_ci txi->status.rates[i].count = tx_attempts[i].count; 558262306a36Sopenharmony_ci } 558362306a36Sopenharmony_ci 558462306a36Sopenharmony_ci txi->status.ack_signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]); 558562306a36Sopenharmony_ci 558662306a36Sopenharmony_ci if (!(hwsim_flags & HWSIM_TX_CTL_NO_ACK) && 558762306a36Sopenharmony_ci (hwsim_flags & HWSIM_TX_STAT_ACK)) { 558862306a36Sopenharmony_ci if (skb->len >= 16) { 558962306a36Sopenharmony_ci hdr = (struct ieee80211_hdr *) skb->data; 559062306a36Sopenharmony_ci mac80211_hwsim_monitor_ack(data2->channel, 559162306a36Sopenharmony_ci hdr->addr2); 559262306a36Sopenharmony_ci } 559362306a36Sopenharmony_ci txi->flags |= IEEE80211_TX_STAT_ACK; 559462306a36Sopenharmony_ci } 559562306a36Sopenharmony_ci 559662306a36Sopenharmony_ci if (hwsim_flags & HWSIM_TX_CTL_NO_ACK) 559762306a36Sopenharmony_ci txi->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; 559862306a36Sopenharmony_ci 559962306a36Sopenharmony_ci ieee80211_tx_status_irqsafe(data2->hw, skb); 560062306a36Sopenharmony_ci return 0; 560162306a36Sopenharmony_ciout: 560262306a36Sopenharmony_ci return -EINVAL; 560362306a36Sopenharmony_ci 560462306a36Sopenharmony_ci} 560562306a36Sopenharmony_ci 560662306a36Sopenharmony_cistatic int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, 560762306a36Sopenharmony_ci struct genl_info *info) 560862306a36Sopenharmony_ci{ 560962306a36Sopenharmony_ci struct mac80211_hwsim_data *data2; 561062306a36Sopenharmony_ci struct ieee80211_rx_status rx_status; 561162306a36Sopenharmony_ci struct ieee80211_hdr *hdr; 561262306a36Sopenharmony_ci const u8 *dst; 561362306a36Sopenharmony_ci int frame_data_len; 561462306a36Sopenharmony_ci void *frame_data; 561562306a36Sopenharmony_ci struct sk_buff *skb = NULL; 561662306a36Sopenharmony_ci struct ieee80211_channel *channel = NULL; 561762306a36Sopenharmony_ci 561862306a36Sopenharmony_ci if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] || 561962306a36Sopenharmony_ci !info->attrs[HWSIM_ATTR_FRAME] || 562062306a36Sopenharmony_ci !info->attrs[HWSIM_ATTR_RX_RATE] || 562162306a36Sopenharmony_ci !info->attrs[HWSIM_ATTR_SIGNAL]) 562262306a36Sopenharmony_ci goto out; 562362306a36Sopenharmony_ci 562462306a36Sopenharmony_ci dst = (void *)nla_data(info->attrs[HWSIM_ATTR_ADDR_RECEIVER]); 562562306a36Sopenharmony_ci frame_data_len = nla_len(info->attrs[HWSIM_ATTR_FRAME]); 562662306a36Sopenharmony_ci frame_data = (void *)nla_data(info->attrs[HWSIM_ATTR_FRAME]); 562762306a36Sopenharmony_ci 562862306a36Sopenharmony_ci if (frame_data_len < sizeof(struct ieee80211_hdr_3addr) || 562962306a36Sopenharmony_ci frame_data_len > IEEE80211_MAX_DATA_LEN) 563062306a36Sopenharmony_ci goto err; 563162306a36Sopenharmony_ci 563262306a36Sopenharmony_ci /* Allocate new skb here */ 563362306a36Sopenharmony_ci skb = alloc_skb(frame_data_len, GFP_KERNEL); 563462306a36Sopenharmony_ci if (skb == NULL) 563562306a36Sopenharmony_ci goto err; 563662306a36Sopenharmony_ci 563762306a36Sopenharmony_ci /* Copy the data */ 563862306a36Sopenharmony_ci skb_put_data(skb, frame_data, frame_data_len); 563962306a36Sopenharmony_ci 564062306a36Sopenharmony_ci data2 = get_hwsim_data_ref_from_addr(dst); 564162306a36Sopenharmony_ci if (!data2) 564262306a36Sopenharmony_ci goto out; 564362306a36Sopenharmony_ci 564462306a36Sopenharmony_ci if (data2->use_chanctx) { 564562306a36Sopenharmony_ci if (data2->tmp_chan) 564662306a36Sopenharmony_ci channel = data2->tmp_chan; 564762306a36Sopenharmony_ci } else { 564862306a36Sopenharmony_ci channel = data2->channel; 564962306a36Sopenharmony_ci } 565062306a36Sopenharmony_ci 565162306a36Sopenharmony_ci if (!hwsim_virtio_enabled) { 565262306a36Sopenharmony_ci if (hwsim_net_get_netgroup(genl_info_net(info)) != 565362306a36Sopenharmony_ci data2->netgroup) 565462306a36Sopenharmony_ci goto out; 565562306a36Sopenharmony_ci 565662306a36Sopenharmony_ci if (info->snd_portid != data2->wmediumd) 565762306a36Sopenharmony_ci goto out; 565862306a36Sopenharmony_ci } 565962306a36Sopenharmony_ci 566062306a36Sopenharmony_ci /* check if radio is configured properly */ 566162306a36Sopenharmony_ci 566262306a36Sopenharmony_ci if ((data2->idle && !data2->tmp_chan) || !data2->started) 566362306a36Sopenharmony_ci goto out; 566462306a36Sopenharmony_ci 566562306a36Sopenharmony_ci /* A frame is received from user space */ 566662306a36Sopenharmony_ci memset(&rx_status, 0, sizeof(rx_status)); 566762306a36Sopenharmony_ci if (info->attrs[HWSIM_ATTR_FREQ]) { 566862306a36Sopenharmony_ci struct tx_iter_data iter_data = {}; 566962306a36Sopenharmony_ci 567062306a36Sopenharmony_ci /* throw away off-channel packets, but allow both the temporary 567162306a36Sopenharmony_ci * ("hw" scan/remain-on-channel), regular channels and links, 567262306a36Sopenharmony_ci * since the internal datapath also allows this 567362306a36Sopenharmony_ci */ 567462306a36Sopenharmony_ci rx_status.freq = nla_get_u32(info->attrs[HWSIM_ATTR_FREQ]); 567562306a36Sopenharmony_ci 567662306a36Sopenharmony_ci iter_data.channel = ieee80211_get_channel(data2->hw->wiphy, 567762306a36Sopenharmony_ci rx_status.freq); 567862306a36Sopenharmony_ci if (!iter_data.channel) 567962306a36Sopenharmony_ci goto out; 568062306a36Sopenharmony_ci rx_status.band = iter_data.channel->band; 568162306a36Sopenharmony_ci 568262306a36Sopenharmony_ci mutex_lock(&data2->mutex); 568362306a36Sopenharmony_ci if (!hwsim_chans_compat(iter_data.channel, channel)) { 568462306a36Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic( 568562306a36Sopenharmony_ci data2->hw, IEEE80211_IFACE_ITER_NORMAL, 568662306a36Sopenharmony_ci mac80211_hwsim_tx_iter, &iter_data); 568762306a36Sopenharmony_ci if (!iter_data.receive) { 568862306a36Sopenharmony_ci mutex_unlock(&data2->mutex); 568962306a36Sopenharmony_ci goto out; 569062306a36Sopenharmony_ci } 569162306a36Sopenharmony_ci } 569262306a36Sopenharmony_ci mutex_unlock(&data2->mutex); 569362306a36Sopenharmony_ci } else if (!channel) { 569462306a36Sopenharmony_ci goto out; 569562306a36Sopenharmony_ci } else { 569662306a36Sopenharmony_ci rx_status.freq = channel->center_freq; 569762306a36Sopenharmony_ci rx_status.band = channel->band; 569862306a36Sopenharmony_ci } 569962306a36Sopenharmony_ci 570062306a36Sopenharmony_ci rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]); 570162306a36Sopenharmony_ci if (rx_status.rate_idx >= data2->hw->wiphy->bands[rx_status.band]->n_bitrates) 570262306a36Sopenharmony_ci goto out; 570362306a36Sopenharmony_ci rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]); 570462306a36Sopenharmony_ci 570562306a36Sopenharmony_ci hdr = (void *)skb->data; 570662306a36Sopenharmony_ci 570762306a36Sopenharmony_ci if (ieee80211_is_beacon(hdr->frame_control) || 570862306a36Sopenharmony_ci ieee80211_is_probe_resp(hdr->frame_control)) 570962306a36Sopenharmony_ci rx_status.boottime_ns = ktime_get_boottime_ns(); 571062306a36Sopenharmony_ci 571162306a36Sopenharmony_ci mac80211_hwsim_rx(data2, &rx_status, skb); 571262306a36Sopenharmony_ci 571362306a36Sopenharmony_ci return 0; 571462306a36Sopenharmony_cierr: 571562306a36Sopenharmony_ci pr_debug("mac80211_hwsim: error occurred in %s\n", __func__); 571662306a36Sopenharmony_ciout: 571762306a36Sopenharmony_ci dev_kfree_skb(skb); 571862306a36Sopenharmony_ci return -EINVAL; 571962306a36Sopenharmony_ci} 572062306a36Sopenharmony_ci 572162306a36Sopenharmony_cistatic int hwsim_register_received_nl(struct sk_buff *skb_2, 572262306a36Sopenharmony_ci struct genl_info *info) 572362306a36Sopenharmony_ci{ 572462306a36Sopenharmony_ci struct net *net = genl_info_net(info); 572562306a36Sopenharmony_ci struct mac80211_hwsim_data *data; 572662306a36Sopenharmony_ci int chans = 1; 572762306a36Sopenharmony_ci 572862306a36Sopenharmony_ci spin_lock_bh(&hwsim_radio_lock); 572962306a36Sopenharmony_ci list_for_each_entry(data, &hwsim_radios, list) 573062306a36Sopenharmony_ci chans = max(chans, data->channels); 573162306a36Sopenharmony_ci spin_unlock_bh(&hwsim_radio_lock); 573262306a36Sopenharmony_ci 573362306a36Sopenharmony_ci /* In the future we should revise the userspace API and allow it 573462306a36Sopenharmony_ci * to set a flag that it does support multi-channel, then we can 573562306a36Sopenharmony_ci * let this pass conditionally on the flag. 573662306a36Sopenharmony_ci * For current userspace, prohibit it since it won't work right. 573762306a36Sopenharmony_ci */ 573862306a36Sopenharmony_ci if (chans > 1) 573962306a36Sopenharmony_ci return -EOPNOTSUPP; 574062306a36Sopenharmony_ci 574162306a36Sopenharmony_ci if (hwsim_net_get_wmediumd(net)) 574262306a36Sopenharmony_ci return -EBUSY; 574362306a36Sopenharmony_ci 574462306a36Sopenharmony_ci hwsim_register_wmediumd(net, info->snd_portid); 574562306a36Sopenharmony_ci 574662306a36Sopenharmony_ci pr_debug("mac80211_hwsim: received a REGISTER, " 574762306a36Sopenharmony_ci "switching to wmediumd mode with pid %d\n", info->snd_portid); 574862306a36Sopenharmony_ci 574962306a36Sopenharmony_ci return 0; 575062306a36Sopenharmony_ci} 575162306a36Sopenharmony_ci 575262306a36Sopenharmony_ci/* ensures ciphers only include ciphers listed in 'hwsim_ciphers' array */ 575362306a36Sopenharmony_cistatic bool hwsim_known_ciphers(const u32 *ciphers, int n_ciphers) 575462306a36Sopenharmony_ci{ 575562306a36Sopenharmony_ci int i; 575662306a36Sopenharmony_ci 575762306a36Sopenharmony_ci for (i = 0; i < n_ciphers; i++) { 575862306a36Sopenharmony_ci int j; 575962306a36Sopenharmony_ci int found = 0; 576062306a36Sopenharmony_ci 576162306a36Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(hwsim_ciphers); j++) { 576262306a36Sopenharmony_ci if (ciphers[i] == hwsim_ciphers[j]) { 576362306a36Sopenharmony_ci found = 1; 576462306a36Sopenharmony_ci break; 576562306a36Sopenharmony_ci } 576662306a36Sopenharmony_ci } 576762306a36Sopenharmony_ci 576862306a36Sopenharmony_ci if (!found) 576962306a36Sopenharmony_ci return false; 577062306a36Sopenharmony_ci } 577162306a36Sopenharmony_ci 577262306a36Sopenharmony_ci return true; 577362306a36Sopenharmony_ci} 577462306a36Sopenharmony_ci 577562306a36Sopenharmony_cistatic int parse_ftm_capa(const struct nlattr *ftm_capa, struct cfg80211_pmsr_capabilities *out, 577662306a36Sopenharmony_ci struct genl_info *info) 577762306a36Sopenharmony_ci{ 577862306a36Sopenharmony_ci struct nlattr *tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX + 1]; 577962306a36Sopenharmony_ci int ret; 578062306a36Sopenharmony_ci 578162306a36Sopenharmony_ci ret = nla_parse_nested(tb, NL80211_PMSR_FTM_CAPA_ATTR_MAX, ftm_capa, hwsim_ftm_capa_policy, 578262306a36Sopenharmony_ci NULL); 578362306a36Sopenharmony_ci if (ret) { 578462306a36Sopenharmony_ci NL_SET_ERR_MSG_ATTR(info->extack, ftm_capa, "malformed FTM capability"); 578562306a36Sopenharmony_ci return -EINVAL; 578662306a36Sopenharmony_ci } 578762306a36Sopenharmony_ci 578862306a36Sopenharmony_ci out->ftm.supported = 1; 578962306a36Sopenharmony_ci if (tb[NL80211_PMSR_FTM_CAPA_ATTR_PREAMBLES]) 579062306a36Sopenharmony_ci out->ftm.preambles = nla_get_u32(tb[NL80211_PMSR_FTM_CAPA_ATTR_PREAMBLES]); 579162306a36Sopenharmony_ci if (tb[NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS]) 579262306a36Sopenharmony_ci out->ftm.bandwidths = nla_get_u32(tb[NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS]); 579362306a36Sopenharmony_ci if (tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT]) 579462306a36Sopenharmony_ci out->ftm.max_bursts_exponent = 579562306a36Sopenharmony_ci nla_get_u8(tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT]); 579662306a36Sopenharmony_ci if (tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST]) 579762306a36Sopenharmony_ci out->ftm.max_ftms_per_burst = 579862306a36Sopenharmony_ci nla_get_u8(tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST]); 579962306a36Sopenharmony_ci out->ftm.asap = !!tb[NL80211_PMSR_FTM_CAPA_ATTR_ASAP]; 580062306a36Sopenharmony_ci out->ftm.non_asap = !!tb[NL80211_PMSR_FTM_CAPA_ATTR_NON_ASAP]; 580162306a36Sopenharmony_ci out->ftm.request_lci = !!tb[NL80211_PMSR_FTM_CAPA_ATTR_REQ_LCI]; 580262306a36Sopenharmony_ci out->ftm.request_civicloc = !!tb[NL80211_PMSR_FTM_CAPA_ATTR_REQ_CIVICLOC]; 580362306a36Sopenharmony_ci out->ftm.trigger_based = !!tb[NL80211_PMSR_FTM_CAPA_ATTR_TRIGGER_BASED]; 580462306a36Sopenharmony_ci out->ftm.non_trigger_based = !!tb[NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED]; 580562306a36Sopenharmony_ci 580662306a36Sopenharmony_ci return 0; 580762306a36Sopenharmony_ci} 580862306a36Sopenharmony_ci 580962306a36Sopenharmony_cistatic int parse_pmsr_capa(const struct nlattr *pmsr_capa, struct cfg80211_pmsr_capabilities *out, 581062306a36Sopenharmony_ci struct genl_info *info) 581162306a36Sopenharmony_ci{ 581262306a36Sopenharmony_ci struct nlattr *tb[NL80211_PMSR_ATTR_MAX + 1]; 581362306a36Sopenharmony_ci struct nlattr *nla; 581462306a36Sopenharmony_ci int size; 581562306a36Sopenharmony_ci int ret; 581662306a36Sopenharmony_ci 581762306a36Sopenharmony_ci ret = nla_parse_nested(tb, NL80211_PMSR_ATTR_MAX, pmsr_capa, hwsim_pmsr_capa_policy, NULL); 581862306a36Sopenharmony_ci if (ret) { 581962306a36Sopenharmony_ci NL_SET_ERR_MSG_ATTR(info->extack, pmsr_capa, "malformed PMSR capability"); 582062306a36Sopenharmony_ci return -EINVAL; 582162306a36Sopenharmony_ci } 582262306a36Sopenharmony_ci 582362306a36Sopenharmony_ci if (tb[NL80211_PMSR_ATTR_MAX_PEERS]) 582462306a36Sopenharmony_ci out->max_peers = nla_get_u32(tb[NL80211_PMSR_ATTR_MAX_PEERS]); 582562306a36Sopenharmony_ci out->report_ap_tsf = !!tb[NL80211_PMSR_ATTR_REPORT_AP_TSF]; 582662306a36Sopenharmony_ci out->randomize_mac_addr = !!tb[NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR]; 582762306a36Sopenharmony_ci 582862306a36Sopenharmony_ci if (!tb[NL80211_PMSR_ATTR_TYPE_CAPA]) { 582962306a36Sopenharmony_ci NL_SET_ERR_MSG_ATTR(info->extack, tb[NL80211_PMSR_ATTR_TYPE_CAPA], 583062306a36Sopenharmony_ci "malformed PMSR type"); 583162306a36Sopenharmony_ci return -EINVAL; 583262306a36Sopenharmony_ci } 583362306a36Sopenharmony_ci 583462306a36Sopenharmony_ci nla_for_each_nested(nla, tb[NL80211_PMSR_ATTR_TYPE_CAPA], size) { 583562306a36Sopenharmony_ci switch (nla_type(nla)) { 583662306a36Sopenharmony_ci case NL80211_PMSR_TYPE_FTM: 583762306a36Sopenharmony_ci parse_ftm_capa(nla, out, info); 583862306a36Sopenharmony_ci break; 583962306a36Sopenharmony_ci default: 584062306a36Sopenharmony_ci NL_SET_ERR_MSG_ATTR(info->extack, nla, "unsupported measurement type"); 584162306a36Sopenharmony_ci return -EINVAL; 584262306a36Sopenharmony_ci } 584362306a36Sopenharmony_ci } 584462306a36Sopenharmony_ci 584562306a36Sopenharmony_ci return 0; 584662306a36Sopenharmony_ci} 584762306a36Sopenharmony_ci 584862306a36Sopenharmony_cistatic int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info) 584962306a36Sopenharmony_ci{ 585062306a36Sopenharmony_ci struct hwsim_new_radio_params param = { 0 }; 585162306a36Sopenharmony_ci const char *hwname = NULL; 585262306a36Sopenharmony_ci int ret; 585362306a36Sopenharmony_ci 585462306a36Sopenharmony_ci param.reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG]; 585562306a36Sopenharmony_ci param.p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE]; 585662306a36Sopenharmony_ci param.channels = channels; 585762306a36Sopenharmony_ci param.destroy_on_close = 585862306a36Sopenharmony_ci info->attrs[HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE]; 585962306a36Sopenharmony_ci 586062306a36Sopenharmony_ci if (info->attrs[HWSIM_ATTR_CHANNELS]) 586162306a36Sopenharmony_ci param.channels = nla_get_u32(info->attrs[HWSIM_ATTR_CHANNELS]); 586262306a36Sopenharmony_ci 586362306a36Sopenharmony_ci if (param.channels < 1) { 586462306a36Sopenharmony_ci GENL_SET_ERR_MSG(info, "must have at least one channel"); 586562306a36Sopenharmony_ci return -EINVAL; 586662306a36Sopenharmony_ci } 586762306a36Sopenharmony_ci 586862306a36Sopenharmony_ci if (info->attrs[HWSIM_ATTR_NO_VIF]) 586962306a36Sopenharmony_ci param.no_vif = true; 587062306a36Sopenharmony_ci 587162306a36Sopenharmony_ci if (info->attrs[HWSIM_ATTR_USE_CHANCTX]) 587262306a36Sopenharmony_ci param.use_chanctx = true; 587362306a36Sopenharmony_ci else 587462306a36Sopenharmony_ci param.use_chanctx = (param.channels > 1); 587562306a36Sopenharmony_ci 587662306a36Sopenharmony_ci if (info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]) 587762306a36Sopenharmony_ci param.reg_alpha2 = 587862306a36Sopenharmony_ci nla_data(info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]); 587962306a36Sopenharmony_ci 588062306a36Sopenharmony_ci if (info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]) { 588162306a36Sopenharmony_ci u32 idx = nla_get_u32(info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]); 588262306a36Sopenharmony_ci 588362306a36Sopenharmony_ci if (idx >= ARRAY_SIZE(hwsim_world_regdom_custom)) 588462306a36Sopenharmony_ci return -EINVAL; 588562306a36Sopenharmony_ci 588662306a36Sopenharmony_ci idx = array_index_nospec(idx, 588762306a36Sopenharmony_ci ARRAY_SIZE(hwsim_world_regdom_custom)); 588862306a36Sopenharmony_ci param.regd = hwsim_world_regdom_custom[idx]; 588962306a36Sopenharmony_ci } 589062306a36Sopenharmony_ci 589162306a36Sopenharmony_ci if (info->attrs[HWSIM_ATTR_PERM_ADDR]) { 589262306a36Sopenharmony_ci if (!is_valid_ether_addr( 589362306a36Sopenharmony_ci nla_data(info->attrs[HWSIM_ATTR_PERM_ADDR]))) { 589462306a36Sopenharmony_ci GENL_SET_ERR_MSG(info,"MAC is no valid source addr"); 589562306a36Sopenharmony_ci NL_SET_BAD_ATTR(info->extack, 589662306a36Sopenharmony_ci info->attrs[HWSIM_ATTR_PERM_ADDR]); 589762306a36Sopenharmony_ci return -EINVAL; 589862306a36Sopenharmony_ci } 589962306a36Sopenharmony_ci 590062306a36Sopenharmony_ci param.perm_addr = nla_data(info->attrs[HWSIM_ATTR_PERM_ADDR]); 590162306a36Sopenharmony_ci } 590262306a36Sopenharmony_ci 590362306a36Sopenharmony_ci if (info->attrs[HWSIM_ATTR_IFTYPE_SUPPORT]) { 590462306a36Sopenharmony_ci param.iftypes = 590562306a36Sopenharmony_ci nla_get_u32(info->attrs[HWSIM_ATTR_IFTYPE_SUPPORT]); 590662306a36Sopenharmony_ci 590762306a36Sopenharmony_ci if (param.iftypes & ~HWSIM_IFTYPE_SUPPORT_MASK) { 590862306a36Sopenharmony_ci NL_SET_ERR_MSG_ATTR(info->extack, 590962306a36Sopenharmony_ci info->attrs[HWSIM_ATTR_IFTYPE_SUPPORT], 591062306a36Sopenharmony_ci "cannot support more iftypes than kernel"); 591162306a36Sopenharmony_ci return -EINVAL; 591262306a36Sopenharmony_ci } 591362306a36Sopenharmony_ci } else { 591462306a36Sopenharmony_ci param.iftypes = HWSIM_IFTYPE_SUPPORT_MASK; 591562306a36Sopenharmony_ci } 591662306a36Sopenharmony_ci 591762306a36Sopenharmony_ci /* ensure both flag and iftype support is honored */ 591862306a36Sopenharmony_ci if (param.p2p_device || 591962306a36Sopenharmony_ci param.iftypes & BIT(NL80211_IFTYPE_P2P_DEVICE)) { 592062306a36Sopenharmony_ci param.iftypes |= BIT(NL80211_IFTYPE_P2P_DEVICE); 592162306a36Sopenharmony_ci param.p2p_device = true; 592262306a36Sopenharmony_ci } 592362306a36Sopenharmony_ci 592462306a36Sopenharmony_ci if (info->attrs[HWSIM_ATTR_CIPHER_SUPPORT]) { 592562306a36Sopenharmony_ci u32 len = nla_len(info->attrs[HWSIM_ATTR_CIPHER_SUPPORT]); 592662306a36Sopenharmony_ci 592762306a36Sopenharmony_ci param.ciphers = 592862306a36Sopenharmony_ci nla_data(info->attrs[HWSIM_ATTR_CIPHER_SUPPORT]); 592962306a36Sopenharmony_ci 593062306a36Sopenharmony_ci if (len % sizeof(u32)) { 593162306a36Sopenharmony_ci NL_SET_ERR_MSG_ATTR(info->extack, 593262306a36Sopenharmony_ci info->attrs[HWSIM_ATTR_CIPHER_SUPPORT], 593362306a36Sopenharmony_ci "bad cipher list length"); 593462306a36Sopenharmony_ci return -EINVAL; 593562306a36Sopenharmony_ci } 593662306a36Sopenharmony_ci 593762306a36Sopenharmony_ci param.n_ciphers = len / sizeof(u32); 593862306a36Sopenharmony_ci 593962306a36Sopenharmony_ci if (param.n_ciphers > ARRAY_SIZE(hwsim_ciphers)) { 594062306a36Sopenharmony_ci NL_SET_ERR_MSG_ATTR(info->extack, 594162306a36Sopenharmony_ci info->attrs[HWSIM_ATTR_CIPHER_SUPPORT], 594262306a36Sopenharmony_ci "too many ciphers specified"); 594362306a36Sopenharmony_ci return -EINVAL; 594462306a36Sopenharmony_ci } 594562306a36Sopenharmony_ci 594662306a36Sopenharmony_ci if (!hwsim_known_ciphers(param.ciphers, param.n_ciphers)) { 594762306a36Sopenharmony_ci NL_SET_ERR_MSG_ATTR(info->extack, 594862306a36Sopenharmony_ci info->attrs[HWSIM_ATTR_CIPHER_SUPPORT], 594962306a36Sopenharmony_ci "unsupported ciphers specified"); 595062306a36Sopenharmony_ci return -EINVAL; 595162306a36Sopenharmony_ci } 595262306a36Sopenharmony_ci } 595362306a36Sopenharmony_ci 595462306a36Sopenharmony_ci param.mlo = info->attrs[HWSIM_ATTR_MLO_SUPPORT]; 595562306a36Sopenharmony_ci 595662306a36Sopenharmony_ci if (param.mlo) 595762306a36Sopenharmony_ci param.use_chanctx = true; 595862306a36Sopenharmony_ci 595962306a36Sopenharmony_ci if (info->attrs[HWSIM_ATTR_RADIO_NAME]) { 596062306a36Sopenharmony_ci hwname = kstrndup((char *)nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME]), 596162306a36Sopenharmony_ci nla_len(info->attrs[HWSIM_ATTR_RADIO_NAME]), 596262306a36Sopenharmony_ci GFP_KERNEL); 596362306a36Sopenharmony_ci if (!hwname) 596462306a36Sopenharmony_ci return -ENOMEM; 596562306a36Sopenharmony_ci param.hwname = hwname; 596662306a36Sopenharmony_ci } 596762306a36Sopenharmony_ci 596862306a36Sopenharmony_ci if (info->attrs[HWSIM_ATTR_PMSR_SUPPORT]) { 596962306a36Sopenharmony_ci struct cfg80211_pmsr_capabilities *pmsr_capa; 597062306a36Sopenharmony_ci 597162306a36Sopenharmony_ci pmsr_capa = kmalloc(sizeof(*pmsr_capa), GFP_KERNEL); 597262306a36Sopenharmony_ci if (!pmsr_capa) { 597362306a36Sopenharmony_ci ret = -ENOMEM; 597462306a36Sopenharmony_ci goto out_free; 597562306a36Sopenharmony_ci } 597662306a36Sopenharmony_ci param.pmsr_capa = pmsr_capa; 597762306a36Sopenharmony_ci 597862306a36Sopenharmony_ci ret = parse_pmsr_capa(info->attrs[HWSIM_ATTR_PMSR_SUPPORT], pmsr_capa, info); 597962306a36Sopenharmony_ci if (ret) 598062306a36Sopenharmony_ci goto out_free; 598162306a36Sopenharmony_ci } 598262306a36Sopenharmony_ci 598362306a36Sopenharmony_ci ret = mac80211_hwsim_new_radio(info, ¶m); 598462306a36Sopenharmony_ci 598562306a36Sopenharmony_ciout_free: 598662306a36Sopenharmony_ci kfree(hwname); 598762306a36Sopenharmony_ci kfree(param.pmsr_capa); 598862306a36Sopenharmony_ci return ret; 598962306a36Sopenharmony_ci} 599062306a36Sopenharmony_ci 599162306a36Sopenharmony_cistatic int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info) 599262306a36Sopenharmony_ci{ 599362306a36Sopenharmony_ci struct mac80211_hwsim_data *data; 599462306a36Sopenharmony_ci s64 idx = -1; 599562306a36Sopenharmony_ci const char *hwname = NULL; 599662306a36Sopenharmony_ci 599762306a36Sopenharmony_ci if (info->attrs[HWSIM_ATTR_RADIO_ID]) { 599862306a36Sopenharmony_ci idx = nla_get_u32(info->attrs[HWSIM_ATTR_RADIO_ID]); 599962306a36Sopenharmony_ci } else if (info->attrs[HWSIM_ATTR_RADIO_NAME]) { 600062306a36Sopenharmony_ci hwname = kstrndup((char *)nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME]), 600162306a36Sopenharmony_ci nla_len(info->attrs[HWSIM_ATTR_RADIO_NAME]), 600262306a36Sopenharmony_ci GFP_KERNEL); 600362306a36Sopenharmony_ci if (!hwname) 600462306a36Sopenharmony_ci return -ENOMEM; 600562306a36Sopenharmony_ci } else 600662306a36Sopenharmony_ci return -EINVAL; 600762306a36Sopenharmony_ci 600862306a36Sopenharmony_ci spin_lock_bh(&hwsim_radio_lock); 600962306a36Sopenharmony_ci list_for_each_entry(data, &hwsim_radios, list) { 601062306a36Sopenharmony_ci if (idx >= 0) { 601162306a36Sopenharmony_ci if (data->idx != idx) 601262306a36Sopenharmony_ci continue; 601362306a36Sopenharmony_ci } else { 601462306a36Sopenharmony_ci if (!hwname || 601562306a36Sopenharmony_ci strcmp(hwname, wiphy_name(data->hw->wiphy))) 601662306a36Sopenharmony_ci continue; 601762306a36Sopenharmony_ci } 601862306a36Sopenharmony_ci 601962306a36Sopenharmony_ci if (!net_eq(wiphy_net(data->hw->wiphy), genl_info_net(info))) 602062306a36Sopenharmony_ci continue; 602162306a36Sopenharmony_ci 602262306a36Sopenharmony_ci list_del(&data->list); 602362306a36Sopenharmony_ci rhashtable_remove_fast(&hwsim_radios_rht, &data->rht, 602462306a36Sopenharmony_ci hwsim_rht_params); 602562306a36Sopenharmony_ci hwsim_radios_generation++; 602662306a36Sopenharmony_ci spin_unlock_bh(&hwsim_radio_lock); 602762306a36Sopenharmony_ci mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy), 602862306a36Sopenharmony_ci info); 602962306a36Sopenharmony_ci kfree(hwname); 603062306a36Sopenharmony_ci return 0; 603162306a36Sopenharmony_ci } 603262306a36Sopenharmony_ci spin_unlock_bh(&hwsim_radio_lock); 603362306a36Sopenharmony_ci 603462306a36Sopenharmony_ci kfree(hwname); 603562306a36Sopenharmony_ci return -ENODEV; 603662306a36Sopenharmony_ci} 603762306a36Sopenharmony_ci 603862306a36Sopenharmony_cistatic int hwsim_get_radio_nl(struct sk_buff *msg, struct genl_info *info) 603962306a36Sopenharmony_ci{ 604062306a36Sopenharmony_ci struct mac80211_hwsim_data *data; 604162306a36Sopenharmony_ci struct sk_buff *skb; 604262306a36Sopenharmony_ci int idx, res = -ENODEV; 604362306a36Sopenharmony_ci 604462306a36Sopenharmony_ci if (!info->attrs[HWSIM_ATTR_RADIO_ID]) 604562306a36Sopenharmony_ci return -EINVAL; 604662306a36Sopenharmony_ci idx = nla_get_u32(info->attrs[HWSIM_ATTR_RADIO_ID]); 604762306a36Sopenharmony_ci 604862306a36Sopenharmony_ci spin_lock_bh(&hwsim_radio_lock); 604962306a36Sopenharmony_ci list_for_each_entry(data, &hwsim_radios, list) { 605062306a36Sopenharmony_ci if (data->idx != idx) 605162306a36Sopenharmony_ci continue; 605262306a36Sopenharmony_ci 605362306a36Sopenharmony_ci if (!net_eq(wiphy_net(data->hw->wiphy), genl_info_net(info))) 605462306a36Sopenharmony_ci continue; 605562306a36Sopenharmony_ci 605662306a36Sopenharmony_ci skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); 605762306a36Sopenharmony_ci if (!skb) { 605862306a36Sopenharmony_ci res = -ENOMEM; 605962306a36Sopenharmony_ci goto out_err; 606062306a36Sopenharmony_ci } 606162306a36Sopenharmony_ci 606262306a36Sopenharmony_ci res = mac80211_hwsim_get_radio(skb, data, info->snd_portid, 606362306a36Sopenharmony_ci info->snd_seq, NULL, 0); 606462306a36Sopenharmony_ci if (res < 0) { 606562306a36Sopenharmony_ci nlmsg_free(skb); 606662306a36Sopenharmony_ci goto out_err; 606762306a36Sopenharmony_ci } 606862306a36Sopenharmony_ci 606962306a36Sopenharmony_ci res = genlmsg_reply(skb, info); 607062306a36Sopenharmony_ci break; 607162306a36Sopenharmony_ci } 607262306a36Sopenharmony_ci 607362306a36Sopenharmony_ciout_err: 607462306a36Sopenharmony_ci spin_unlock_bh(&hwsim_radio_lock); 607562306a36Sopenharmony_ci 607662306a36Sopenharmony_ci return res; 607762306a36Sopenharmony_ci} 607862306a36Sopenharmony_ci 607962306a36Sopenharmony_cistatic int hwsim_dump_radio_nl(struct sk_buff *skb, 608062306a36Sopenharmony_ci struct netlink_callback *cb) 608162306a36Sopenharmony_ci{ 608262306a36Sopenharmony_ci int last_idx = cb->args[0] - 1; 608362306a36Sopenharmony_ci struct mac80211_hwsim_data *data = NULL; 608462306a36Sopenharmony_ci int res = 0; 608562306a36Sopenharmony_ci void *hdr; 608662306a36Sopenharmony_ci 608762306a36Sopenharmony_ci spin_lock_bh(&hwsim_radio_lock); 608862306a36Sopenharmony_ci cb->seq = hwsim_radios_generation; 608962306a36Sopenharmony_ci 609062306a36Sopenharmony_ci if (last_idx >= hwsim_radio_idx-1) 609162306a36Sopenharmony_ci goto done; 609262306a36Sopenharmony_ci 609362306a36Sopenharmony_ci list_for_each_entry(data, &hwsim_radios, list) { 609462306a36Sopenharmony_ci if (data->idx <= last_idx) 609562306a36Sopenharmony_ci continue; 609662306a36Sopenharmony_ci 609762306a36Sopenharmony_ci if (!net_eq(wiphy_net(data->hw->wiphy), sock_net(skb->sk))) 609862306a36Sopenharmony_ci continue; 609962306a36Sopenharmony_ci 610062306a36Sopenharmony_ci res = mac80211_hwsim_get_radio(skb, data, 610162306a36Sopenharmony_ci NETLINK_CB(cb->skb).portid, 610262306a36Sopenharmony_ci cb->nlh->nlmsg_seq, cb, 610362306a36Sopenharmony_ci NLM_F_MULTI); 610462306a36Sopenharmony_ci if (res < 0) 610562306a36Sopenharmony_ci break; 610662306a36Sopenharmony_ci 610762306a36Sopenharmony_ci last_idx = data->idx; 610862306a36Sopenharmony_ci } 610962306a36Sopenharmony_ci 611062306a36Sopenharmony_ci cb->args[0] = last_idx + 1; 611162306a36Sopenharmony_ci 611262306a36Sopenharmony_ci /* list changed, but no new element sent, set interrupted flag */ 611362306a36Sopenharmony_ci if (skb->len == 0 && cb->prev_seq && cb->seq != cb->prev_seq) { 611462306a36Sopenharmony_ci hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, 611562306a36Sopenharmony_ci cb->nlh->nlmsg_seq, &hwsim_genl_family, 611662306a36Sopenharmony_ci NLM_F_MULTI, HWSIM_CMD_GET_RADIO); 611762306a36Sopenharmony_ci if (hdr) { 611862306a36Sopenharmony_ci genl_dump_check_consistent(cb, hdr); 611962306a36Sopenharmony_ci genlmsg_end(skb, hdr); 612062306a36Sopenharmony_ci } else { 612162306a36Sopenharmony_ci res = -EMSGSIZE; 612262306a36Sopenharmony_ci } 612362306a36Sopenharmony_ci } 612462306a36Sopenharmony_ci 612562306a36Sopenharmony_cidone: 612662306a36Sopenharmony_ci spin_unlock_bh(&hwsim_radio_lock); 612762306a36Sopenharmony_ci return res ?: skb->len; 612862306a36Sopenharmony_ci} 612962306a36Sopenharmony_ci 613062306a36Sopenharmony_ci/* Generic Netlink operations array */ 613162306a36Sopenharmony_cistatic const struct genl_small_ops hwsim_ops[] = { 613262306a36Sopenharmony_ci { 613362306a36Sopenharmony_ci .cmd = HWSIM_CMD_REGISTER, 613462306a36Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 613562306a36Sopenharmony_ci .doit = hwsim_register_received_nl, 613662306a36Sopenharmony_ci .flags = GENL_UNS_ADMIN_PERM, 613762306a36Sopenharmony_ci }, 613862306a36Sopenharmony_ci { 613962306a36Sopenharmony_ci .cmd = HWSIM_CMD_FRAME, 614062306a36Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 614162306a36Sopenharmony_ci .doit = hwsim_cloned_frame_received_nl, 614262306a36Sopenharmony_ci }, 614362306a36Sopenharmony_ci { 614462306a36Sopenharmony_ci .cmd = HWSIM_CMD_TX_INFO_FRAME, 614562306a36Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 614662306a36Sopenharmony_ci .doit = hwsim_tx_info_frame_received_nl, 614762306a36Sopenharmony_ci }, 614862306a36Sopenharmony_ci { 614962306a36Sopenharmony_ci .cmd = HWSIM_CMD_NEW_RADIO, 615062306a36Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 615162306a36Sopenharmony_ci .doit = hwsim_new_radio_nl, 615262306a36Sopenharmony_ci .flags = GENL_UNS_ADMIN_PERM, 615362306a36Sopenharmony_ci }, 615462306a36Sopenharmony_ci { 615562306a36Sopenharmony_ci .cmd = HWSIM_CMD_DEL_RADIO, 615662306a36Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 615762306a36Sopenharmony_ci .doit = hwsim_del_radio_nl, 615862306a36Sopenharmony_ci .flags = GENL_UNS_ADMIN_PERM, 615962306a36Sopenharmony_ci }, 616062306a36Sopenharmony_ci { 616162306a36Sopenharmony_ci .cmd = HWSIM_CMD_GET_RADIO, 616262306a36Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 616362306a36Sopenharmony_ci .doit = hwsim_get_radio_nl, 616462306a36Sopenharmony_ci .dumpit = hwsim_dump_radio_nl, 616562306a36Sopenharmony_ci }, 616662306a36Sopenharmony_ci { 616762306a36Sopenharmony_ci .cmd = HWSIM_CMD_REPORT_PMSR, 616862306a36Sopenharmony_ci .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 616962306a36Sopenharmony_ci .doit = hwsim_pmsr_report_nl, 617062306a36Sopenharmony_ci }, 617162306a36Sopenharmony_ci}; 617262306a36Sopenharmony_ci 617362306a36Sopenharmony_cistatic struct genl_family hwsim_genl_family __ro_after_init = { 617462306a36Sopenharmony_ci .name = "MAC80211_HWSIM", 617562306a36Sopenharmony_ci .version = 1, 617662306a36Sopenharmony_ci .maxattr = HWSIM_ATTR_MAX, 617762306a36Sopenharmony_ci .policy = hwsim_genl_policy, 617862306a36Sopenharmony_ci .netnsok = true, 617962306a36Sopenharmony_ci .module = THIS_MODULE, 618062306a36Sopenharmony_ci .small_ops = hwsim_ops, 618162306a36Sopenharmony_ci .n_small_ops = ARRAY_SIZE(hwsim_ops), 618262306a36Sopenharmony_ci .resv_start_op = HWSIM_CMD_REPORT_PMSR + 1, // match with __HWSIM_CMD_MAX 618362306a36Sopenharmony_ci .mcgrps = hwsim_mcgrps, 618462306a36Sopenharmony_ci .n_mcgrps = ARRAY_SIZE(hwsim_mcgrps), 618562306a36Sopenharmony_ci}; 618662306a36Sopenharmony_ci 618762306a36Sopenharmony_cistatic void remove_user_radios(u32 portid) 618862306a36Sopenharmony_ci{ 618962306a36Sopenharmony_ci struct mac80211_hwsim_data *entry, *tmp; 619062306a36Sopenharmony_ci LIST_HEAD(list); 619162306a36Sopenharmony_ci 619262306a36Sopenharmony_ci spin_lock_bh(&hwsim_radio_lock); 619362306a36Sopenharmony_ci list_for_each_entry_safe(entry, tmp, &hwsim_radios, list) { 619462306a36Sopenharmony_ci if (entry->destroy_on_close && entry->portid == portid) { 619562306a36Sopenharmony_ci list_move(&entry->list, &list); 619662306a36Sopenharmony_ci rhashtable_remove_fast(&hwsim_radios_rht, &entry->rht, 619762306a36Sopenharmony_ci hwsim_rht_params); 619862306a36Sopenharmony_ci hwsim_radios_generation++; 619962306a36Sopenharmony_ci } 620062306a36Sopenharmony_ci } 620162306a36Sopenharmony_ci spin_unlock_bh(&hwsim_radio_lock); 620262306a36Sopenharmony_ci 620362306a36Sopenharmony_ci list_for_each_entry_safe(entry, tmp, &list, list) { 620462306a36Sopenharmony_ci list_del(&entry->list); 620562306a36Sopenharmony_ci mac80211_hwsim_del_radio(entry, wiphy_name(entry->hw->wiphy), 620662306a36Sopenharmony_ci NULL); 620762306a36Sopenharmony_ci } 620862306a36Sopenharmony_ci} 620962306a36Sopenharmony_ci 621062306a36Sopenharmony_cistatic int mac80211_hwsim_netlink_notify(struct notifier_block *nb, 621162306a36Sopenharmony_ci unsigned long state, 621262306a36Sopenharmony_ci void *_notify) 621362306a36Sopenharmony_ci{ 621462306a36Sopenharmony_ci struct netlink_notify *notify = _notify; 621562306a36Sopenharmony_ci 621662306a36Sopenharmony_ci if (state != NETLINK_URELEASE) 621762306a36Sopenharmony_ci return NOTIFY_DONE; 621862306a36Sopenharmony_ci 621962306a36Sopenharmony_ci remove_user_radios(notify->portid); 622062306a36Sopenharmony_ci 622162306a36Sopenharmony_ci if (notify->portid == hwsim_net_get_wmediumd(notify->net)) { 622262306a36Sopenharmony_ci printk(KERN_INFO "mac80211_hwsim: wmediumd released netlink" 622362306a36Sopenharmony_ci " socket, switching to perfect channel medium\n"); 622462306a36Sopenharmony_ci hwsim_register_wmediumd(notify->net, 0); 622562306a36Sopenharmony_ci } 622662306a36Sopenharmony_ci return NOTIFY_DONE; 622762306a36Sopenharmony_ci 622862306a36Sopenharmony_ci} 622962306a36Sopenharmony_ci 623062306a36Sopenharmony_cistatic struct notifier_block hwsim_netlink_notifier = { 623162306a36Sopenharmony_ci .notifier_call = mac80211_hwsim_netlink_notify, 623262306a36Sopenharmony_ci}; 623362306a36Sopenharmony_ci 623462306a36Sopenharmony_cistatic int __init hwsim_init_netlink(void) 623562306a36Sopenharmony_ci{ 623662306a36Sopenharmony_ci int rc; 623762306a36Sopenharmony_ci 623862306a36Sopenharmony_ci printk(KERN_INFO "mac80211_hwsim: initializing netlink\n"); 623962306a36Sopenharmony_ci 624062306a36Sopenharmony_ci rc = genl_register_family(&hwsim_genl_family); 624162306a36Sopenharmony_ci if (rc) 624262306a36Sopenharmony_ci goto failure; 624362306a36Sopenharmony_ci 624462306a36Sopenharmony_ci rc = netlink_register_notifier(&hwsim_netlink_notifier); 624562306a36Sopenharmony_ci if (rc) { 624662306a36Sopenharmony_ci genl_unregister_family(&hwsim_genl_family); 624762306a36Sopenharmony_ci goto failure; 624862306a36Sopenharmony_ci } 624962306a36Sopenharmony_ci 625062306a36Sopenharmony_ci return 0; 625162306a36Sopenharmony_ci 625262306a36Sopenharmony_cifailure: 625362306a36Sopenharmony_ci pr_debug("mac80211_hwsim: error occurred in %s\n", __func__); 625462306a36Sopenharmony_ci return -EINVAL; 625562306a36Sopenharmony_ci} 625662306a36Sopenharmony_ci 625762306a36Sopenharmony_cistatic __net_init int hwsim_init_net(struct net *net) 625862306a36Sopenharmony_ci{ 625962306a36Sopenharmony_ci return hwsim_net_set_netgroup(net); 626062306a36Sopenharmony_ci} 626162306a36Sopenharmony_ci 626262306a36Sopenharmony_cistatic void __net_exit hwsim_exit_net(struct net *net) 626362306a36Sopenharmony_ci{ 626462306a36Sopenharmony_ci struct mac80211_hwsim_data *data, *tmp; 626562306a36Sopenharmony_ci LIST_HEAD(list); 626662306a36Sopenharmony_ci 626762306a36Sopenharmony_ci spin_lock_bh(&hwsim_radio_lock); 626862306a36Sopenharmony_ci list_for_each_entry_safe(data, tmp, &hwsim_radios, list) { 626962306a36Sopenharmony_ci if (!net_eq(wiphy_net(data->hw->wiphy), net)) 627062306a36Sopenharmony_ci continue; 627162306a36Sopenharmony_ci 627262306a36Sopenharmony_ci /* Radios created in init_net are returned to init_net. */ 627362306a36Sopenharmony_ci if (data->netgroup == hwsim_net_get_netgroup(&init_net)) 627462306a36Sopenharmony_ci continue; 627562306a36Sopenharmony_ci 627662306a36Sopenharmony_ci list_move(&data->list, &list); 627762306a36Sopenharmony_ci rhashtable_remove_fast(&hwsim_radios_rht, &data->rht, 627862306a36Sopenharmony_ci hwsim_rht_params); 627962306a36Sopenharmony_ci hwsim_radios_generation++; 628062306a36Sopenharmony_ci } 628162306a36Sopenharmony_ci spin_unlock_bh(&hwsim_radio_lock); 628262306a36Sopenharmony_ci 628362306a36Sopenharmony_ci list_for_each_entry_safe(data, tmp, &list, list) { 628462306a36Sopenharmony_ci list_del(&data->list); 628562306a36Sopenharmony_ci mac80211_hwsim_del_radio(data, 628662306a36Sopenharmony_ci wiphy_name(data->hw->wiphy), 628762306a36Sopenharmony_ci NULL); 628862306a36Sopenharmony_ci } 628962306a36Sopenharmony_ci 629062306a36Sopenharmony_ci ida_free(&hwsim_netgroup_ida, hwsim_net_get_netgroup(net)); 629162306a36Sopenharmony_ci} 629262306a36Sopenharmony_ci 629362306a36Sopenharmony_cistatic struct pernet_operations hwsim_net_ops = { 629462306a36Sopenharmony_ci .init = hwsim_init_net, 629562306a36Sopenharmony_ci .exit = hwsim_exit_net, 629662306a36Sopenharmony_ci .id = &hwsim_net_id, 629762306a36Sopenharmony_ci .size = sizeof(struct hwsim_net), 629862306a36Sopenharmony_ci}; 629962306a36Sopenharmony_ci 630062306a36Sopenharmony_cistatic void hwsim_exit_netlink(void) 630162306a36Sopenharmony_ci{ 630262306a36Sopenharmony_ci /* unregister the notifier */ 630362306a36Sopenharmony_ci netlink_unregister_notifier(&hwsim_netlink_notifier); 630462306a36Sopenharmony_ci /* unregister the family */ 630562306a36Sopenharmony_ci genl_unregister_family(&hwsim_genl_family); 630662306a36Sopenharmony_ci} 630762306a36Sopenharmony_ci 630862306a36Sopenharmony_ci#if IS_REACHABLE(CONFIG_VIRTIO) 630962306a36Sopenharmony_cistatic void hwsim_virtio_tx_done(struct virtqueue *vq) 631062306a36Sopenharmony_ci{ 631162306a36Sopenharmony_ci unsigned int len; 631262306a36Sopenharmony_ci struct sk_buff *skb; 631362306a36Sopenharmony_ci unsigned long flags; 631462306a36Sopenharmony_ci 631562306a36Sopenharmony_ci spin_lock_irqsave(&hwsim_virtio_lock, flags); 631662306a36Sopenharmony_ci while ((skb = virtqueue_get_buf(vq, &len))) 631762306a36Sopenharmony_ci dev_kfree_skb_irq(skb); 631862306a36Sopenharmony_ci spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 631962306a36Sopenharmony_ci} 632062306a36Sopenharmony_ci 632162306a36Sopenharmony_cistatic int hwsim_virtio_handle_cmd(struct sk_buff *skb) 632262306a36Sopenharmony_ci{ 632362306a36Sopenharmony_ci struct nlmsghdr *nlh; 632462306a36Sopenharmony_ci struct genlmsghdr *gnlh; 632562306a36Sopenharmony_ci struct nlattr *tb[HWSIM_ATTR_MAX + 1]; 632662306a36Sopenharmony_ci struct genl_info info = {}; 632762306a36Sopenharmony_ci int err; 632862306a36Sopenharmony_ci 632962306a36Sopenharmony_ci nlh = nlmsg_hdr(skb); 633062306a36Sopenharmony_ci gnlh = nlmsg_data(nlh); 633162306a36Sopenharmony_ci 633262306a36Sopenharmony_ci if (skb->len < nlh->nlmsg_len) 633362306a36Sopenharmony_ci return -EINVAL; 633462306a36Sopenharmony_ci 633562306a36Sopenharmony_ci err = genlmsg_parse(nlh, &hwsim_genl_family, tb, HWSIM_ATTR_MAX, 633662306a36Sopenharmony_ci hwsim_genl_policy, NULL); 633762306a36Sopenharmony_ci if (err) { 633862306a36Sopenharmony_ci pr_err_ratelimited("hwsim: genlmsg_parse returned %d\n", err); 633962306a36Sopenharmony_ci return err; 634062306a36Sopenharmony_ci } 634162306a36Sopenharmony_ci 634262306a36Sopenharmony_ci info.attrs = tb; 634362306a36Sopenharmony_ci 634462306a36Sopenharmony_ci switch (gnlh->cmd) { 634562306a36Sopenharmony_ci case HWSIM_CMD_FRAME: 634662306a36Sopenharmony_ci hwsim_cloned_frame_received_nl(skb, &info); 634762306a36Sopenharmony_ci break; 634862306a36Sopenharmony_ci case HWSIM_CMD_TX_INFO_FRAME: 634962306a36Sopenharmony_ci hwsim_tx_info_frame_received_nl(skb, &info); 635062306a36Sopenharmony_ci break; 635162306a36Sopenharmony_ci case HWSIM_CMD_REPORT_PMSR: 635262306a36Sopenharmony_ci hwsim_pmsr_report_nl(skb, &info); 635362306a36Sopenharmony_ci break; 635462306a36Sopenharmony_ci default: 635562306a36Sopenharmony_ci pr_err_ratelimited("hwsim: invalid cmd: %d\n", gnlh->cmd); 635662306a36Sopenharmony_ci return -EPROTO; 635762306a36Sopenharmony_ci } 635862306a36Sopenharmony_ci return 0; 635962306a36Sopenharmony_ci} 636062306a36Sopenharmony_ci 636162306a36Sopenharmony_cistatic void hwsim_virtio_rx_work(struct work_struct *work) 636262306a36Sopenharmony_ci{ 636362306a36Sopenharmony_ci struct virtqueue *vq; 636462306a36Sopenharmony_ci unsigned int len; 636562306a36Sopenharmony_ci struct sk_buff *skb; 636662306a36Sopenharmony_ci struct scatterlist sg[1]; 636762306a36Sopenharmony_ci int err; 636862306a36Sopenharmony_ci unsigned long flags; 636962306a36Sopenharmony_ci 637062306a36Sopenharmony_ci spin_lock_irqsave(&hwsim_virtio_lock, flags); 637162306a36Sopenharmony_ci if (!hwsim_virtio_enabled) 637262306a36Sopenharmony_ci goto out_unlock; 637362306a36Sopenharmony_ci 637462306a36Sopenharmony_ci skb = virtqueue_get_buf(hwsim_vqs[HWSIM_VQ_RX], &len); 637562306a36Sopenharmony_ci if (!skb) 637662306a36Sopenharmony_ci goto out_unlock; 637762306a36Sopenharmony_ci spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 637862306a36Sopenharmony_ci 637962306a36Sopenharmony_ci skb->data = skb->head; 638062306a36Sopenharmony_ci skb_reset_tail_pointer(skb); 638162306a36Sopenharmony_ci skb_put(skb, len); 638262306a36Sopenharmony_ci hwsim_virtio_handle_cmd(skb); 638362306a36Sopenharmony_ci 638462306a36Sopenharmony_ci spin_lock_irqsave(&hwsim_virtio_lock, flags); 638562306a36Sopenharmony_ci if (!hwsim_virtio_enabled) { 638662306a36Sopenharmony_ci dev_kfree_skb_irq(skb); 638762306a36Sopenharmony_ci goto out_unlock; 638862306a36Sopenharmony_ci } 638962306a36Sopenharmony_ci vq = hwsim_vqs[HWSIM_VQ_RX]; 639062306a36Sopenharmony_ci sg_init_one(sg, skb->head, skb_end_offset(skb)); 639162306a36Sopenharmony_ci err = virtqueue_add_inbuf(vq, sg, 1, skb, GFP_ATOMIC); 639262306a36Sopenharmony_ci if (WARN(err, "virtqueue_add_inbuf returned %d\n", err)) 639362306a36Sopenharmony_ci dev_kfree_skb_irq(skb); 639462306a36Sopenharmony_ci else 639562306a36Sopenharmony_ci virtqueue_kick(vq); 639662306a36Sopenharmony_ci schedule_work(&hwsim_virtio_rx); 639762306a36Sopenharmony_ci 639862306a36Sopenharmony_ciout_unlock: 639962306a36Sopenharmony_ci spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 640062306a36Sopenharmony_ci} 640162306a36Sopenharmony_ci 640262306a36Sopenharmony_cistatic void hwsim_virtio_rx_done(struct virtqueue *vq) 640362306a36Sopenharmony_ci{ 640462306a36Sopenharmony_ci schedule_work(&hwsim_virtio_rx); 640562306a36Sopenharmony_ci} 640662306a36Sopenharmony_ci 640762306a36Sopenharmony_cistatic int init_vqs(struct virtio_device *vdev) 640862306a36Sopenharmony_ci{ 640962306a36Sopenharmony_ci vq_callback_t *callbacks[HWSIM_NUM_VQS] = { 641062306a36Sopenharmony_ci [HWSIM_VQ_TX] = hwsim_virtio_tx_done, 641162306a36Sopenharmony_ci [HWSIM_VQ_RX] = hwsim_virtio_rx_done, 641262306a36Sopenharmony_ci }; 641362306a36Sopenharmony_ci const char *names[HWSIM_NUM_VQS] = { 641462306a36Sopenharmony_ci [HWSIM_VQ_TX] = "tx", 641562306a36Sopenharmony_ci [HWSIM_VQ_RX] = "rx", 641662306a36Sopenharmony_ci }; 641762306a36Sopenharmony_ci 641862306a36Sopenharmony_ci return virtio_find_vqs(vdev, HWSIM_NUM_VQS, 641962306a36Sopenharmony_ci hwsim_vqs, callbacks, names, NULL); 642062306a36Sopenharmony_ci} 642162306a36Sopenharmony_ci 642262306a36Sopenharmony_cistatic int fill_vq(struct virtqueue *vq) 642362306a36Sopenharmony_ci{ 642462306a36Sopenharmony_ci int i, err; 642562306a36Sopenharmony_ci struct sk_buff *skb; 642662306a36Sopenharmony_ci struct scatterlist sg[1]; 642762306a36Sopenharmony_ci 642862306a36Sopenharmony_ci for (i = 0; i < virtqueue_get_vring_size(vq); i++) { 642962306a36Sopenharmony_ci skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 643062306a36Sopenharmony_ci if (!skb) 643162306a36Sopenharmony_ci return -ENOMEM; 643262306a36Sopenharmony_ci 643362306a36Sopenharmony_ci sg_init_one(sg, skb->head, skb_end_offset(skb)); 643462306a36Sopenharmony_ci err = virtqueue_add_inbuf(vq, sg, 1, skb, GFP_KERNEL); 643562306a36Sopenharmony_ci if (err) { 643662306a36Sopenharmony_ci nlmsg_free(skb); 643762306a36Sopenharmony_ci return err; 643862306a36Sopenharmony_ci } 643962306a36Sopenharmony_ci } 644062306a36Sopenharmony_ci virtqueue_kick(vq); 644162306a36Sopenharmony_ci return 0; 644262306a36Sopenharmony_ci} 644362306a36Sopenharmony_ci 644462306a36Sopenharmony_cistatic void remove_vqs(struct virtio_device *vdev) 644562306a36Sopenharmony_ci{ 644662306a36Sopenharmony_ci int i; 644762306a36Sopenharmony_ci 644862306a36Sopenharmony_ci virtio_reset_device(vdev); 644962306a36Sopenharmony_ci 645062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(hwsim_vqs); i++) { 645162306a36Sopenharmony_ci struct virtqueue *vq = hwsim_vqs[i]; 645262306a36Sopenharmony_ci struct sk_buff *skb; 645362306a36Sopenharmony_ci 645462306a36Sopenharmony_ci while ((skb = virtqueue_detach_unused_buf(vq))) 645562306a36Sopenharmony_ci nlmsg_free(skb); 645662306a36Sopenharmony_ci } 645762306a36Sopenharmony_ci 645862306a36Sopenharmony_ci vdev->config->del_vqs(vdev); 645962306a36Sopenharmony_ci} 646062306a36Sopenharmony_ci 646162306a36Sopenharmony_cistatic int hwsim_virtio_probe(struct virtio_device *vdev) 646262306a36Sopenharmony_ci{ 646362306a36Sopenharmony_ci int err; 646462306a36Sopenharmony_ci unsigned long flags; 646562306a36Sopenharmony_ci 646662306a36Sopenharmony_ci spin_lock_irqsave(&hwsim_virtio_lock, flags); 646762306a36Sopenharmony_ci if (hwsim_virtio_enabled) { 646862306a36Sopenharmony_ci spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 646962306a36Sopenharmony_ci return -EEXIST; 647062306a36Sopenharmony_ci } 647162306a36Sopenharmony_ci spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 647262306a36Sopenharmony_ci 647362306a36Sopenharmony_ci err = init_vqs(vdev); 647462306a36Sopenharmony_ci if (err) 647562306a36Sopenharmony_ci return err; 647662306a36Sopenharmony_ci 647762306a36Sopenharmony_ci virtio_device_ready(vdev); 647862306a36Sopenharmony_ci 647962306a36Sopenharmony_ci err = fill_vq(hwsim_vqs[HWSIM_VQ_RX]); 648062306a36Sopenharmony_ci if (err) 648162306a36Sopenharmony_ci goto out_remove; 648262306a36Sopenharmony_ci 648362306a36Sopenharmony_ci spin_lock_irqsave(&hwsim_virtio_lock, flags); 648462306a36Sopenharmony_ci hwsim_virtio_enabled = true; 648562306a36Sopenharmony_ci spin_unlock_irqrestore(&hwsim_virtio_lock, flags); 648662306a36Sopenharmony_ci 648762306a36Sopenharmony_ci schedule_work(&hwsim_virtio_rx); 648862306a36Sopenharmony_ci return 0; 648962306a36Sopenharmony_ci 649062306a36Sopenharmony_ciout_remove: 649162306a36Sopenharmony_ci remove_vqs(vdev); 649262306a36Sopenharmony_ci return err; 649362306a36Sopenharmony_ci} 649462306a36Sopenharmony_ci 649562306a36Sopenharmony_cistatic void hwsim_virtio_remove(struct virtio_device *vdev) 649662306a36Sopenharmony_ci{ 649762306a36Sopenharmony_ci hwsim_virtio_enabled = false; 649862306a36Sopenharmony_ci 649962306a36Sopenharmony_ci cancel_work_sync(&hwsim_virtio_rx); 650062306a36Sopenharmony_ci 650162306a36Sopenharmony_ci remove_vqs(vdev); 650262306a36Sopenharmony_ci} 650362306a36Sopenharmony_ci 650462306a36Sopenharmony_ci/* MAC80211_HWSIM virtio device id table */ 650562306a36Sopenharmony_cistatic const struct virtio_device_id id_table[] = { 650662306a36Sopenharmony_ci { VIRTIO_ID_MAC80211_HWSIM, VIRTIO_DEV_ANY_ID }, 650762306a36Sopenharmony_ci { 0 } 650862306a36Sopenharmony_ci}; 650962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(virtio, id_table); 651062306a36Sopenharmony_ci 651162306a36Sopenharmony_cistatic struct virtio_driver virtio_hwsim = { 651262306a36Sopenharmony_ci .driver.name = KBUILD_MODNAME, 651362306a36Sopenharmony_ci .driver.owner = THIS_MODULE, 651462306a36Sopenharmony_ci .id_table = id_table, 651562306a36Sopenharmony_ci .probe = hwsim_virtio_probe, 651662306a36Sopenharmony_ci .remove = hwsim_virtio_remove, 651762306a36Sopenharmony_ci}; 651862306a36Sopenharmony_ci 651962306a36Sopenharmony_cistatic int hwsim_register_virtio_driver(void) 652062306a36Sopenharmony_ci{ 652162306a36Sopenharmony_ci return register_virtio_driver(&virtio_hwsim); 652262306a36Sopenharmony_ci} 652362306a36Sopenharmony_ci 652462306a36Sopenharmony_cistatic void hwsim_unregister_virtio_driver(void) 652562306a36Sopenharmony_ci{ 652662306a36Sopenharmony_ci unregister_virtio_driver(&virtio_hwsim); 652762306a36Sopenharmony_ci} 652862306a36Sopenharmony_ci#else 652962306a36Sopenharmony_cistatic inline int hwsim_register_virtio_driver(void) 653062306a36Sopenharmony_ci{ 653162306a36Sopenharmony_ci return 0; 653262306a36Sopenharmony_ci} 653362306a36Sopenharmony_ci 653462306a36Sopenharmony_cistatic inline void hwsim_unregister_virtio_driver(void) 653562306a36Sopenharmony_ci{ 653662306a36Sopenharmony_ci} 653762306a36Sopenharmony_ci#endif 653862306a36Sopenharmony_ci 653962306a36Sopenharmony_cistatic int __init init_mac80211_hwsim(void) 654062306a36Sopenharmony_ci{ 654162306a36Sopenharmony_ci int i, err; 654262306a36Sopenharmony_ci 654362306a36Sopenharmony_ci if (radios < 0 || radios > 100) 654462306a36Sopenharmony_ci return -EINVAL; 654562306a36Sopenharmony_ci 654662306a36Sopenharmony_ci if (channels < 1) 654762306a36Sopenharmony_ci return -EINVAL; 654862306a36Sopenharmony_ci 654962306a36Sopenharmony_ci err = rhashtable_init(&hwsim_radios_rht, &hwsim_rht_params); 655062306a36Sopenharmony_ci if (err) 655162306a36Sopenharmony_ci return err; 655262306a36Sopenharmony_ci 655362306a36Sopenharmony_ci err = register_pernet_device(&hwsim_net_ops); 655462306a36Sopenharmony_ci if (err) 655562306a36Sopenharmony_ci goto out_free_rht; 655662306a36Sopenharmony_ci 655762306a36Sopenharmony_ci err = platform_driver_register(&mac80211_hwsim_driver); 655862306a36Sopenharmony_ci if (err) 655962306a36Sopenharmony_ci goto out_unregister_pernet; 656062306a36Sopenharmony_ci 656162306a36Sopenharmony_ci err = hwsim_init_netlink(); 656262306a36Sopenharmony_ci if (err) 656362306a36Sopenharmony_ci goto out_unregister_driver; 656462306a36Sopenharmony_ci 656562306a36Sopenharmony_ci err = hwsim_register_virtio_driver(); 656662306a36Sopenharmony_ci if (err) 656762306a36Sopenharmony_ci goto out_exit_netlink; 656862306a36Sopenharmony_ci 656962306a36Sopenharmony_ci hwsim_class = class_create("mac80211_hwsim"); 657062306a36Sopenharmony_ci if (IS_ERR(hwsim_class)) { 657162306a36Sopenharmony_ci err = PTR_ERR(hwsim_class); 657262306a36Sopenharmony_ci goto out_exit_virtio; 657362306a36Sopenharmony_ci } 657462306a36Sopenharmony_ci 657562306a36Sopenharmony_ci hwsim_init_s1g_channels(hwsim_channels_s1g); 657662306a36Sopenharmony_ci 657762306a36Sopenharmony_ci for (i = 0; i < radios; i++) { 657862306a36Sopenharmony_ci struct hwsim_new_radio_params param = { 0 }; 657962306a36Sopenharmony_ci 658062306a36Sopenharmony_ci param.channels = channels; 658162306a36Sopenharmony_ci 658262306a36Sopenharmony_ci switch (regtest) { 658362306a36Sopenharmony_ci case HWSIM_REGTEST_DIFF_COUNTRY: 658462306a36Sopenharmony_ci if (i < ARRAY_SIZE(hwsim_alpha2s)) 658562306a36Sopenharmony_ci param.reg_alpha2 = hwsim_alpha2s[i]; 658662306a36Sopenharmony_ci break; 658762306a36Sopenharmony_ci case HWSIM_REGTEST_DRIVER_REG_FOLLOW: 658862306a36Sopenharmony_ci if (!i) 658962306a36Sopenharmony_ci param.reg_alpha2 = hwsim_alpha2s[0]; 659062306a36Sopenharmony_ci break; 659162306a36Sopenharmony_ci case HWSIM_REGTEST_STRICT_ALL: 659262306a36Sopenharmony_ci param.reg_strict = true; 659362306a36Sopenharmony_ci fallthrough; 659462306a36Sopenharmony_ci case HWSIM_REGTEST_DRIVER_REG_ALL: 659562306a36Sopenharmony_ci param.reg_alpha2 = hwsim_alpha2s[0]; 659662306a36Sopenharmony_ci break; 659762306a36Sopenharmony_ci case HWSIM_REGTEST_WORLD_ROAM: 659862306a36Sopenharmony_ci if (i == 0) 659962306a36Sopenharmony_ci param.regd = &hwsim_world_regdom_custom_01; 660062306a36Sopenharmony_ci break; 660162306a36Sopenharmony_ci case HWSIM_REGTEST_CUSTOM_WORLD: 660262306a36Sopenharmony_ci param.regd = &hwsim_world_regdom_custom_01; 660362306a36Sopenharmony_ci break; 660462306a36Sopenharmony_ci case HWSIM_REGTEST_CUSTOM_WORLD_2: 660562306a36Sopenharmony_ci if (i == 0) 660662306a36Sopenharmony_ci param.regd = &hwsim_world_regdom_custom_01; 660762306a36Sopenharmony_ci else if (i == 1) 660862306a36Sopenharmony_ci param.regd = &hwsim_world_regdom_custom_02; 660962306a36Sopenharmony_ci break; 661062306a36Sopenharmony_ci case HWSIM_REGTEST_STRICT_FOLLOW: 661162306a36Sopenharmony_ci if (i == 0) { 661262306a36Sopenharmony_ci param.reg_strict = true; 661362306a36Sopenharmony_ci param.reg_alpha2 = hwsim_alpha2s[0]; 661462306a36Sopenharmony_ci } 661562306a36Sopenharmony_ci break; 661662306a36Sopenharmony_ci case HWSIM_REGTEST_STRICT_AND_DRIVER_REG: 661762306a36Sopenharmony_ci if (i == 0) { 661862306a36Sopenharmony_ci param.reg_strict = true; 661962306a36Sopenharmony_ci param.reg_alpha2 = hwsim_alpha2s[0]; 662062306a36Sopenharmony_ci } else if (i == 1) { 662162306a36Sopenharmony_ci param.reg_alpha2 = hwsim_alpha2s[1]; 662262306a36Sopenharmony_ci } 662362306a36Sopenharmony_ci break; 662462306a36Sopenharmony_ci case HWSIM_REGTEST_ALL: 662562306a36Sopenharmony_ci switch (i) { 662662306a36Sopenharmony_ci case 0: 662762306a36Sopenharmony_ci param.regd = &hwsim_world_regdom_custom_01; 662862306a36Sopenharmony_ci break; 662962306a36Sopenharmony_ci case 1: 663062306a36Sopenharmony_ci param.regd = &hwsim_world_regdom_custom_02; 663162306a36Sopenharmony_ci break; 663262306a36Sopenharmony_ci case 2: 663362306a36Sopenharmony_ci param.reg_alpha2 = hwsim_alpha2s[0]; 663462306a36Sopenharmony_ci break; 663562306a36Sopenharmony_ci case 3: 663662306a36Sopenharmony_ci param.reg_alpha2 = hwsim_alpha2s[1]; 663762306a36Sopenharmony_ci break; 663862306a36Sopenharmony_ci case 4: 663962306a36Sopenharmony_ci param.reg_strict = true; 664062306a36Sopenharmony_ci param.reg_alpha2 = hwsim_alpha2s[2]; 664162306a36Sopenharmony_ci break; 664262306a36Sopenharmony_ci } 664362306a36Sopenharmony_ci break; 664462306a36Sopenharmony_ci default: 664562306a36Sopenharmony_ci break; 664662306a36Sopenharmony_ci } 664762306a36Sopenharmony_ci 664862306a36Sopenharmony_ci param.p2p_device = support_p2p_device; 664962306a36Sopenharmony_ci param.mlo = mlo; 665062306a36Sopenharmony_ci param.use_chanctx = channels > 1 || mlo; 665162306a36Sopenharmony_ci param.iftypes = HWSIM_IFTYPE_SUPPORT_MASK; 665262306a36Sopenharmony_ci if (param.p2p_device) 665362306a36Sopenharmony_ci param.iftypes |= BIT(NL80211_IFTYPE_P2P_DEVICE); 665462306a36Sopenharmony_ci 665562306a36Sopenharmony_ci err = mac80211_hwsim_new_radio(NULL, ¶m); 665662306a36Sopenharmony_ci if (err < 0) 665762306a36Sopenharmony_ci goto out_free_radios; 665862306a36Sopenharmony_ci } 665962306a36Sopenharmony_ci 666062306a36Sopenharmony_ci hwsim_mon = alloc_netdev(0, "hwsim%d", NET_NAME_UNKNOWN, 666162306a36Sopenharmony_ci hwsim_mon_setup); 666262306a36Sopenharmony_ci if (hwsim_mon == NULL) { 666362306a36Sopenharmony_ci err = -ENOMEM; 666462306a36Sopenharmony_ci goto out_free_radios; 666562306a36Sopenharmony_ci } 666662306a36Sopenharmony_ci 666762306a36Sopenharmony_ci rtnl_lock(); 666862306a36Sopenharmony_ci err = dev_alloc_name(hwsim_mon, hwsim_mon->name); 666962306a36Sopenharmony_ci if (err < 0) { 667062306a36Sopenharmony_ci rtnl_unlock(); 667162306a36Sopenharmony_ci goto out_free_mon; 667262306a36Sopenharmony_ci } 667362306a36Sopenharmony_ci 667462306a36Sopenharmony_ci err = register_netdevice(hwsim_mon); 667562306a36Sopenharmony_ci if (err < 0) { 667662306a36Sopenharmony_ci rtnl_unlock(); 667762306a36Sopenharmony_ci goto out_free_mon; 667862306a36Sopenharmony_ci } 667962306a36Sopenharmony_ci rtnl_unlock(); 668062306a36Sopenharmony_ci 668162306a36Sopenharmony_ci return 0; 668262306a36Sopenharmony_ci 668362306a36Sopenharmony_ciout_free_mon: 668462306a36Sopenharmony_ci free_netdev(hwsim_mon); 668562306a36Sopenharmony_ciout_free_radios: 668662306a36Sopenharmony_ci mac80211_hwsim_free(); 668762306a36Sopenharmony_ciout_exit_virtio: 668862306a36Sopenharmony_ci hwsim_unregister_virtio_driver(); 668962306a36Sopenharmony_ciout_exit_netlink: 669062306a36Sopenharmony_ci hwsim_exit_netlink(); 669162306a36Sopenharmony_ciout_unregister_driver: 669262306a36Sopenharmony_ci platform_driver_unregister(&mac80211_hwsim_driver); 669362306a36Sopenharmony_ciout_unregister_pernet: 669462306a36Sopenharmony_ci unregister_pernet_device(&hwsim_net_ops); 669562306a36Sopenharmony_ciout_free_rht: 669662306a36Sopenharmony_ci rhashtable_destroy(&hwsim_radios_rht); 669762306a36Sopenharmony_ci return err; 669862306a36Sopenharmony_ci} 669962306a36Sopenharmony_cimodule_init(init_mac80211_hwsim); 670062306a36Sopenharmony_ci 670162306a36Sopenharmony_cistatic void __exit exit_mac80211_hwsim(void) 670262306a36Sopenharmony_ci{ 670362306a36Sopenharmony_ci pr_debug("mac80211_hwsim: unregister radios\n"); 670462306a36Sopenharmony_ci 670562306a36Sopenharmony_ci hwsim_unregister_virtio_driver(); 670662306a36Sopenharmony_ci hwsim_exit_netlink(); 670762306a36Sopenharmony_ci 670862306a36Sopenharmony_ci mac80211_hwsim_free(); 670962306a36Sopenharmony_ci 671062306a36Sopenharmony_ci rhashtable_destroy(&hwsim_radios_rht); 671162306a36Sopenharmony_ci unregister_netdev(hwsim_mon); 671262306a36Sopenharmony_ci platform_driver_unregister(&mac80211_hwsim_driver); 671362306a36Sopenharmony_ci unregister_pernet_device(&hwsim_net_ops); 671462306a36Sopenharmony_ci} 671562306a36Sopenharmony_cimodule_exit(exit_mac80211_hwsim); 6716