linux/drivers/net/wireless/virtual/mac80211_hwsim.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * mac80211_hwsim - software simulator of 802.11 radio(s) for mac80211
 * Copyright (c) 2008, Jouni Malinen <[email protected]>
 * Copyright (c) 2011, Javier Lopez <[email protected]>
 * Copyright (c) 2016 - 2017 Intel Deutschland GmbH
 * Copyright (C) 2018 - 2024 Intel Corporation
 */

/*
 * TODO:
 * - Add TSF sync and fix IBSS beacon transmission by adding
 *   competition for "air time" at TBTT
 * - RX filtering based on filter configuration (data->rx_filter)
 */

#include <linux/list.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <net/dst.h>
#include <net/xfrm.h>
#include <net/mac80211.h>
#include <net/ieee80211_radiotap.h>
#include <linux/if_arp.h>
#include <linux/rtnetlink.h>
#include <linux/etherdevice.h>
#include <linux/platform_device.h>
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/ktime.h>
#include <net/genetlink.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <linux/rhashtable.h>
#include <linux/nospec.h>
#include <linux/virtio.h>
#include <linux/virtio_ids.h>
#include <linux/virtio_config.h>
#include "mac80211_hwsim.h"

#define WARN_QUEUE
#define MAX_QUEUE

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();

static int radios =;
module_param(radios, int, 0444);
MODULE_PARM_DESC();

static int channels =;
module_param(channels, int, 0444);
MODULE_PARM_DESC();

static bool paged_rx =;
module_param(paged_rx, bool, 0644);
MODULE_PARM_DESC();

static bool rctbl =;
module_param(rctbl, bool, 0444);
MODULE_PARM_DESC();

static bool support_p2p_device =;
module_param(support_p2p_device, bool, 0444);
MODULE_PARM_DESC();

static bool mlo;
module_param(mlo, bool, 0444);
MODULE_PARM_DESC();

static bool multi_radio;
module_param(multi_radio, bool, 0444);
MODULE_PARM_DESC();

/**
 * enum hwsim_regtest - the type of regulatory tests we offer
 *
 * @HWSIM_REGTEST_DISABLED: No regulatory tests are performed,
 * 	this is the default value.
 * @HWSIM_REGTEST_DRIVER_REG_FOLLOW: Used for testing the driver regulatory
 *	hint, only one driver regulatory hint will be sent as such the
 * 	secondary radios are expected to follow.
 * @HWSIM_REGTEST_DRIVER_REG_ALL: Used for testing the driver regulatory
 * 	request with all radios reporting the same regulatory domain.
 * @HWSIM_REGTEST_DIFF_COUNTRY: Used for testing the drivers calling
 * 	different regulatory domains requests. Expected behaviour is for
 * 	an intersection to occur but each device will still use their
 * 	respective regulatory requested domains. Subsequent radios will
 * 	use the resulting intersection.
 * @HWSIM_REGTEST_WORLD_ROAM: Used for testing the world roaming. We accomplish
 *	this by using a custom beacon-capable regulatory domain for the first
 *	radio. All other device world roam.
 * @HWSIM_REGTEST_CUSTOM_WORLD: Used for testing the custom world regulatory
 * 	domain requests. All radios will adhere to this custom world regulatory
 * 	domain.
 * @HWSIM_REGTEST_CUSTOM_WORLD_2: Used for testing 2 custom world regulatory
 * 	domain requests. The first radio will adhere to the first custom world
 * 	regulatory domain, the second one to the second custom world regulatory
 * 	domain. All other devices will world roam.
 * @HWSIM_REGTEST_STRICT_FOLLOW: Used for testing strict regulatory domain
 *	settings, only the first radio will send a regulatory domain request
 *	and use strict settings. The rest of the radios are expected to follow.
 * @HWSIM_REGTEST_STRICT_ALL: Used for testing strict regulatory domain
 *	settings. All radios will adhere to this.
 * @HWSIM_REGTEST_STRICT_AND_DRIVER_REG: Used for testing strict regulatory
 *	domain settings, combined with secondary driver regulatory domain
 *	settings. The first radio will get a strict regulatory domain setting
 *	using the first driver regulatory request and the second radio will use
 *	non-strict settings using the second driver regulatory request. All
 *	other devices should follow the intersection created between the
 *	first two.
 * @HWSIM_REGTEST_ALL: Used for testing every possible mix. You will need
 * 	at least 6 radios for a complete test. We will test in this order:
 * 	1 - driver custom world regulatory domain
 * 	2 - second custom world regulatory domain
 * 	3 - first driver regulatory domain request
 * 	4 - second driver regulatory domain request
 * 	5 - strict regulatory domain settings using the third driver regulatory
 * 	    domain request
 * 	6 and on - should follow the intersection of the 3rd, 4rth and 5th radio
 * 	           regulatory requests.
 *
 * These are the different values you can use for the regtest
 * module parameter. This is useful to help test world roaming
 * and the driver regulatory_hint() call and combinations of these.
 * If you want to do specific alpha2 regulatory domain tests simply
 * use the userspace regulatory request as that will be respected as
 * well without the need of this module parameter. This is designed
 * only for testing the driver regulatory request, world roaming
 * and all possible combinations.
 */
enum hwsim_regtest {};

/* Set to one of the HWSIM_REGTEST_* values above */
static int regtest =;
module_param(regtest, int, 0444);
MODULE_PARM_DESC();

static const char *hwsim_alpha2s[] =;

static const struct ieee80211_regdomain hwsim_world_regdom_custom_01 =;

static const struct ieee80211_regdomain hwsim_world_regdom_custom_02 =;

static const struct ieee80211_regdomain hwsim_world_regdom_custom_03 =;

static const struct ieee80211_regdomain hwsim_world_regdom_custom_04 =;

static const struct ieee80211_regdomain *hwsim_world_regdom_custom[] =;

struct hwsim_vif_priv {};

#define HWSIM_VIF_MAGIC

static inline void hwsim_check_magic(struct ieee80211_vif *vif)
{}

static inline void hwsim_set_magic(struct ieee80211_vif *vif)
{}

static inline void hwsim_clear_magic(struct ieee80211_vif *vif)
{}

struct hwsim_sta_priv {};

#define HWSIM_STA_MAGIC

static inline void hwsim_check_sta_magic(struct ieee80211_sta *sta)
{}

static inline void hwsim_set_sta_magic(struct ieee80211_sta *sta)
{}

static inline void hwsim_clear_sta_magic(struct ieee80211_sta *sta)
{}

struct hwsim_chanctx_priv {};

#define HWSIM_CHANCTX_MAGIC

static inline void hwsim_check_chanctx_magic(struct ieee80211_chanctx_conf *c)
{}

static inline void hwsim_set_chanctx_magic(struct ieee80211_chanctx_conf *c)
{}

static inline void hwsim_clear_chanctx_magic(struct ieee80211_chanctx_conf *c)
{}

static unsigned int hwsim_net_id;

static DEFINE_IDA(hwsim_netgroup_ida);

struct hwsim_net {};

static inline int hwsim_net_get_netgroup(struct net *net)
{}

static inline int hwsim_net_set_netgroup(struct net *net)
{}

static inline u32 hwsim_net_get_wmediumd(struct net *net)
{}

static inline void hwsim_net_set_wmediumd(struct net *net, u32 portid)
{}

static struct class *hwsim_class;

static struct net_device *hwsim_mon; /* global monitor netdev */

#define CHAN2G(_freq)

#define CHAN5G(_freq)

#define CHAN6G(_freq)

static const struct ieee80211_channel hwsim_channels_2ghz[] =;

static const struct ieee80211_channel hwsim_channels_5ghz[] =;

static const struct ieee80211_channel hwsim_channels_6ghz[] =;

#define NUM_S1G_CHANS_US
static struct ieee80211_channel hwsim_channels_s1g[NUM_S1G_CHANS_US];

static const struct ieee80211_sta_s1g_cap hwsim_s1g_cap =;

static void hwsim_init_s1g_channels(struct ieee80211_channel *chans)
{}

static const struct ieee80211_rate hwsim_rates[] =;

#define DEFAULT_RX_RSSI

static const u32 hwsim_ciphers[] =;

#define OUI_QCA
#define QCA_NL80211_SUBCMD_TEST
enum qca_nl80211_vendor_subcmds {};

static const struct nla_policy
hwsim_vendor_test_policy[QCA_WLAN_VENDOR_ATTR_MAX + 1] =;

static int mac80211_hwsim_vendor_cmd_test(struct wiphy *wiphy,
					  struct wireless_dev *wdev,
					  const void *data, int data_len)
{}

static struct wiphy_vendor_command mac80211_hwsim_vendor_commands[] =;

/* Advertise support vendor specific events */
static const struct nl80211_vendor_cmd_info mac80211_hwsim_vendor_events[] =;

static DEFINE_SPINLOCK(hwsim_radio_lock);
static LIST_HEAD(hwsim_radios);
static struct rhashtable hwsim_radios_rht;
static int hwsim_radio_idx;
static int hwsim_radios_generation =;

static struct platform_driver mac80211_hwsim_driver =;

struct mac80211_hwsim_link_data {};

struct mac80211_hwsim_data {};

static const struct rhashtable_params hwsim_rht_params =;

struct hwsim_radiotap_hdr {} __packed;

struct hwsim_radiotap_ack_hdr {} __packed;

static struct mac80211_hwsim_data *get_hwsim_data_ref_from_addr(const u8 *addr)
{}

/* MAC80211_HWSIM netlink family */
static struct genl_family hwsim_genl_family;

enum hwsim_multicast_groups {};

static const struct genl_multicast_group hwsim_mcgrps[] =;

/* MAC80211_HWSIM netlink policy */

static const struct nla_policy
hwsim_rate_info_policy[HWSIM_RATE_INFO_ATTR_MAX + 1] =;

static const struct nla_policy
hwsim_ftm_result_policy[NL80211_PMSR_FTM_RESP_ATTR_MAX + 1] =;

static const struct nla_policy
hwsim_pmsr_resp_type_policy[NL80211_PMSR_TYPE_MAX + 1] =;

static const struct nla_policy
hwsim_pmsr_resp_policy[NL80211_PMSR_RESP_ATTR_MAX + 1] =;

static const struct nla_policy
hwsim_pmsr_peer_result_policy[NL80211_PMSR_PEER_ATTR_MAX + 1] =;

static const struct nla_policy
hwsim_pmsr_peers_result_policy[NL80211_PMSR_ATTR_MAX + 1] =;

static const struct nla_policy
hwsim_ftm_capa_policy[NL80211_PMSR_FTM_CAPA_ATTR_MAX + 1] =;

static const struct nla_policy
hwsim_pmsr_capa_type_policy[NL80211_PMSR_TYPE_MAX + 1] =;

static const struct nla_policy
hwsim_pmsr_capa_policy[NL80211_PMSR_ATTR_MAX + 1] =;

static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] =;

#if IS_REACHABLE(CONFIG_VIRTIO)

/* MAC80211_HWSIM virtio queues */
static struct virtqueue *hwsim_vqs[HWSIM_NUM_VQS];
static bool hwsim_virtio_enabled;
static DEFINE_SPINLOCK(hwsim_virtio_lock);

static void hwsim_virtio_rx_work(struct work_struct *work);
static DECLARE_WORK(hwsim_virtio_rx, hwsim_virtio_rx_work);

static int hwsim_tx_virtio(struct mac80211_hwsim_data *data,
			   struct sk_buff *skb)
{}
#else
/* cause a linker error if this ends up being needed */
extern int hwsim_tx_virtio(struct mac80211_hwsim_data *data,
			   struct sk_buff *skb);
#define hwsim_virtio_enabled
#endif

static int hwsim_get_chanwidth(enum nl80211_chan_width bw)
{}

static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
				    struct sk_buff *skb,
				    struct ieee80211_channel *chan);

/* sysfs attributes */
static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif)
{}

static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,
				struct ieee80211_vif *vif, int ps)
{}


static void hwsim_send_nullfunc_ps(void *dat, u8 *mac,
				   struct ieee80211_vif *vif)
{}

static void hwsim_send_nullfunc_no_ps(void *dat, u8 *mac,
				      struct ieee80211_vif *vif)
{}

static int hwsim_fops_ps_read(void *dat, u64 *val)
{}

static int hwsim_fops_ps_write(void *dat, u64 val)
{}

DEFINE_DEBUGFS_ATTRIBUTE();

static int hwsim_write_simulate_radar(void *dat, u64 val)
{}

DEFINE_DEBUGFS_ATTRIBUTE();

static int hwsim_fops_group_read(void *dat, u64 *val)
{}

static int hwsim_fops_group_write(void *dat, u64 val)
{}

DEFINE_DEBUGFS_ATTRIBUTE();

static int hwsim_fops_rx_rssi_read(void *dat, u64 *val)
{}

static int hwsim_fops_rx_rssi_write(void *dat, u64 val)
{}

DEFINE_DEBUGFS_ATTRIBUTE();

static netdev_tx_t hwsim_mon_xmit(struct sk_buff *skb,
					struct net_device *dev)
{}

static inline u64 mac80211_hwsim_get_tsf_raw(void)
{}

static __le64 __mac80211_hwsim_get_tsf(struct mac80211_hwsim_data *data)
{}

static u64 mac80211_hwsim_get_tsf(struct ieee80211_hw *hw,
				  struct ieee80211_vif *vif)
{}

static void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw,
		struct ieee80211_vif *vif, u64 tsf)
{}

static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
				      struct sk_buff *tx_skb,
				      struct ieee80211_channel *chan)
{}


static void mac80211_hwsim_monitor_ack(struct ieee80211_channel *chan,
				       const u8 *addr)
{}

struct mac80211_hwsim_addr_match_data {};

static void mac80211_hwsim_addr_iter(void *data, u8 *mac,
				     struct ieee80211_vif *vif)
{}

static bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data,
				      const u8 *addr)
{}

static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data,
			   struct sk_buff *skb)
{}

static int hwsim_unicast_netgroup(struct mac80211_hwsim_data *data,
				  struct sk_buff *skb, int portid)
{}

static void mac80211_hwsim_config_mac_nl(struct ieee80211_hw *hw,
					 const u8 *addr, bool add)
{}

static inline u16 trans_tx_rate_flags_ieee2hwsim(struct ieee80211_tx_rate *rate)
{}

static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
				       struct sk_buff *my_skb,
				       int dst_portid,
				       struct ieee80211_channel *channel)
{}

static bool hwsim_chans_compat(struct ieee80211_channel *c1,
			       struct ieee80211_channel *c2)
{}

struct tx_iter_data {};

static void mac80211_hwsim_tx_iter(void *_data, u8 *addr,
				   struct ieee80211_vif *vif)
{}

static void mac80211_hwsim_add_vendor_rtap(struct sk_buff *skb)
{}

static void mac80211_hwsim_rx(struct mac80211_hwsim_data *data,
			      struct ieee80211_rx_status *rx_status,
			      struct sk_buff *skb)
{}

static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
					  struct sk_buff *skb,
					  struct ieee80211_channel *chan)
{}

static struct ieee80211_bss_conf *
mac80211_hwsim_select_tx_link(struct mac80211_hwsim_data *data,
			      struct ieee80211_vif *vif,
			      struct ieee80211_sta *sta,
			      struct ieee80211_hdr *hdr,
			      struct ieee80211_link_sta **link_sta)
{}

static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
			      struct ieee80211_tx_control *control,
			      struct sk_buff *skb)
{}


static int mac80211_hwsim_start(struct ieee80211_hw *hw)
{}


static void mac80211_hwsim_stop(struct ieee80211_hw *hw, bool suspend)
{}


static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw,
					struct ieee80211_vif *vif)
{}

#ifdef CONFIG_MAC80211_DEBUGFS
static void
mac80211_hwsim_link_add_debugfs(struct ieee80211_hw *hw,
				struct ieee80211_vif *vif,
				struct ieee80211_bss_conf *link_conf,
				struct dentry *dir)
{}
#endif

static int mac80211_hwsim_change_interface(struct ieee80211_hw *hw,
					   struct ieee80211_vif *vif,
					   enum nl80211_iftype newtype,
					   bool newp2p)
{}

static void mac80211_hwsim_remove_interface(
	struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{}

static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
				    struct sk_buff *skb,
				    struct ieee80211_channel *chan)
{}

static void __mac80211_hwsim_beacon_tx(struct ieee80211_bss_conf *link_conf,
				       struct mac80211_hwsim_data *data,
				       struct ieee80211_hw *hw,
				       struct ieee80211_vif *vif,
				       struct sk_buff *skb)
{}

static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
				     struct ieee80211_vif *vif)
{}

static enum hrtimer_restart
mac80211_hwsim_beacon(struct hrtimer *timer)
{}

static const char * const hwsim_chanwidths[] =;

static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
{}


static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw,
					    unsigned int changed_flags,
					    unsigned int *total_flags,u64 multicast)
{}

static void mac80211_hwsim_bcn_en_iter(void *data, u8 *mac,
				       struct ieee80211_vif *vif)
{}

static void mac80211_hwsim_vif_info_changed(struct ieee80211_hw *hw,
					    struct ieee80211_vif *vif,
					    u64 changed)
{}

static void mac80211_hwsim_link_info_changed(struct ieee80211_hw *hw,
					     struct ieee80211_vif *vif,
					     struct ieee80211_bss_conf *info,
					     u64 changed)
{}

static void
mac80211_hwsim_sta_rc_update(struct ieee80211_hw *hw,
			     struct ieee80211_vif *vif,
			     struct ieee80211_sta *sta,
			     u32 changed)
{}

static int mac80211_hwsim_sta_add(struct ieee80211_hw *hw,
				  struct ieee80211_vif *vif,
				  struct ieee80211_sta *sta)
{}

static int mac80211_hwsim_sta_remove(struct ieee80211_hw *hw,
				     struct ieee80211_vif *vif,
				     struct ieee80211_sta *sta)
{}

static int mac80211_hwsim_sta_state(struct ieee80211_hw *hw,
				    struct ieee80211_vif *vif,
				    struct ieee80211_sta *sta,
				    enum ieee80211_sta_state old_state,
				    enum ieee80211_sta_state new_state)
{}

static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw,
				      struct ieee80211_vif *vif,
				      enum sta_notify_cmd cmd,
				      struct ieee80211_sta *sta)
{}

static int mac80211_hwsim_set_tim(struct ieee80211_hw *hw,
				  struct ieee80211_sta *sta,
				  bool set)
{}

static int mac80211_hwsim_conf_tx(struct ieee80211_hw *hw,
				  struct ieee80211_vif *vif,
				  unsigned int link_id, u16 queue,
				  const struct ieee80211_tx_queue_params *params)
{}

static int mac80211_hwsim_get_survey(struct ieee80211_hw *hw, int idx,
				     struct survey_info *survey)
{}

static enum ieee80211_neg_ttlm_res
mac80211_hwsim_can_neg_ttlm(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
			    struct ieee80211_neg_ttlm *neg_ttlm)
{}

#ifdef CONFIG_NL80211_TESTMODE
/*
 * This section contains example code for using netlink
 * attributes with the testmode command in nl80211.
 */

/* These enums need to be kept in sync with userspace */
enum hwsim_testmode_attr {};

enum hwsim_testmode_cmd {};

static const struct nla_policy hwsim_testmode_policy[HWSIM_TM_ATTR_MAX + 1] =;

static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw,
				       struct ieee80211_vif *vif,
				       void *data, int len)
{}
#endif

static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw,
				       struct ieee80211_vif *vif,
				       struct ieee80211_ampdu_params *params)
{}

static void mac80211_hwsim_flush(struct ieee80211_hw *hw,
				 struct ieee80211_vif *vif,
				 u32 queues, bool drop)
{}

static void hw_scan_work(struct work_struct *work)
{}

static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw,
				  struct ieee80211_vif *vif,
				  struct ieee80211_scan_request *hw_req)
{}

static void mac80211_hwsim_cancel_hw_scan(struct ieee80211_hw *hw,
					  struct ieee80211_vif *vif)
{}

static void mac80211_hwsim_sw_scan(struct ieee80211_hw *hw,
				   struct ieee80211_vif *vif,
				   const u8 *mac_addr)
{}

static void mac80211_hwsim_sw_scan_complete(struct ieee80211_hw *hw,
					    struct ieee80211_vif *vif)
{}

static void hw_roc_start(struct work_struct *work)
{}

static void hw_roc_done(struct work_struct *work)
{}

static int mac80211_hwsim_roc(struct ieee80211_hw *hw,
			      struct ieee80211_vif *vif,
			      struct ieee80211_channel *chan,
			      int duration,
			      enum ieee80211_roc_type type)
{}

static int mac80211_hwsim_croc(struct ieee80211_hw *hw,
			       struct ieee80211_vif *vif)
{}

static int mac80211_hwsim_add_chanctx(struct ieee80211_hw *hw,
				      struct ieee80211_chanctx_conf *ctx)
{}

static void mac80211_hwsim_remove_chanctx(struct ieee80211_hw *hw,
					  struct ieee80211_chanctx_conf *ctx)
{}

static void mac80211_hwsim_change_chanctx(struct ieee80211_hw *hw,
					  struct ieee80211_chanctx_conf *ctx,
					  u32 changed)
{}

static int mac80211_hwsim_assign_vif_chanctx(struct ieee80211_hw *hw,
					     struct ieee80211_vif *vif,
					     struct ieee80211_bss_conf *link_conf,
					     struct ieee80211_chanctx_conf *ctx)
{}

static void mac80211_hwsim_unassign_vif_chanctx(struct ieee80211_hw *hw,
						struct ieee80211_vif *vif,
						struct ieee80211_bss_conf *link_conf,
						struct ieee80211_chanctx_conf *ctx)
{}

static int mac80211_hwsim_switch_vif_chanctx(struct ieee80211_hw *hw,
					     struct ieee80211_vif_chanctx_switch *vifs,
					     int n_vifs,
					     enum ieee80211_chanctx_switch_mode mode)
{}

static const char mac80211_hwsim_gstrings_stats[][ETH_GSTRING_LEN] =;

#define MAC80211_HWSIM_SSTATS_LEN

static void mac80211_hwsim_get_et_strings(struct ieee80211_hw *hw,
					  struct ieee80211_vif *vif,
					  u32 sset, u8 *data)
{}

static int mac80211_hwsim_get_et_sset_count(struct ieee80211_hw *hw,
					    struct ieee80211_vif *vif, int sset)
{}

static void mac80211_hwsim_get_et_stats(struct ieee80211_hw *hw,
					struct ieee80211_vif *vif,
					struct ethtool_stats *stats, u64 *data)
{}

static int mac80211_hwsim_tx_last_beacon(struct ieee80211_hw *hw)
{}

static int mac80211_hwsim_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
{}

static int mac80211_hwsim_change_vif_links(struct ieee80211_hw *hw,
					   struct ieee80211_vif *vif,
					   u16 old_links, u16 new_links,
					   struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS])
{}

static int mac80211_hwsim_change_sta_links(struct ieee80211_hw *hw,
					   struct ieee80211_vif *vif,
					   struct ieee80211_sta *sta,
					   u16 old_links, u16 new_links)
{}

static int mac80211_hwsim_send_pmsr_ftm_request_peer(struct sk_buff *msg,
						     struct cfg80211_pmsr_ftm_request_peer *request)
{}

static int mac80211_hwsim_send_pmsr_request_peer(struct sk_buff *msg,
						 struct cfg80211_pmsr_request_peer *request)
{}

static int mac80211_hwsim_send_pmsr_request(struct sk_buff *msg,
					    struct cfg80211_pmsr_request *request)
{}

static int mac80211_hwsim_start_pmsr(struct ieee80211_hw *hw,
				     struct ieee80211_vif *vif,
				     struct cfg80211_pmsr_request *request)
{}

static void mac80211_hwsim_abort_pmsr(struct ieee80211_hw *hw,
				      struct ieee80211_vif *vif,
				      struct cfg80211_pmsr_request *request)
{}

static int mac80211_hwsim_parse_rate_info(struct nlattr *rateattr,
					  struct rate_info *rate_info,
					  struct genl_info *info)
{}

static int mac80211_hwsim_parse_ftm_result(struct nlattr *ftm,
					   struct cfg80211_pmsr_ftm_result *result,
					   struct genl_info *info)
{}

static int mac80211_hwsim_parse_pmsr_resp(struct nlattr *resp,
					  struct cfg80211_pmsr_result *result,
					  struct genl_info *info)
{}

static int mac80211_hwsim_parse_pmsr_result(struct nlattr *peer,
					    struct cfg80211_pmsr_result *result,
					    struct genl_info *info)
{
	struct nlattr *tb[NL80211_PMSR_PEER_ATTR_MAX + 1];
	int ret;

	if (!peer)
		return -EINVAL;

	ret = nla_parse_nested(tb, NL80211_PMSR_PEER_ATTR_MAX, peer,
			       hwsim_pmsr_peer_result_policy, info->extack);
	if (ret)
		return ret;

	if (tb[NL80211_PMSR_PEER_ATTR_ADDR])
		memcpy(result->addr, nla_data(tb[NL80211_PMSR_PEER_ATTR_ADDR]),
		       ETH_ALEN);

	if (tb[NL80211_PMSR_PEER_ATTR_RESP]) {
		ret = mac80211_hwsim_parse_pmsr_resp(tb[NL80211_PMSR_PEER_ATTR_RESP], result, info);
		if (ret)
			return ret;
	}

	return 0;
};

static int hwsim_pmsr_report_nl(struct sk_buff *msg, struct genl_info *info)
{}

#ifdef CONFIG_MAC80211_DEBUGFS
#define HWSIM_DEBUGFS_OPS
#else
#define HWSIM_DEBUGFS_OPS
#endif

#define HWSIM_COMMON_OPS

#define HWSIM_NON_MLO_OPS

static const struct ieee80211_ops mac80211_hwsim_ops =;

#define HWSIM_CHANCTX_OPS

static const struct ieee80211_ops mac80211_hwsim_mchan_ops =;

static const struct ieee80211_ops mac80211_hwsim_mlo_ops =;

struct hwsim_new_radio_params {};

static void hwsim_mcast_config_msg(struct sk_buff *mcast_skb,
				   struct genl_info *info)
{}

static int append_radio_msg(struct sk_buff *skb, int id,
			    struct hwsim_new_radio_params *param)
{}

static void hwsim_mcast_new_radio(int id, struct genl_info *info,
				  struct hwsim_new_radio_params *param)
{}

static const struct ieee80211_sband_iftype_data sband_capa_2ghz[] =;

static const struct ieee80211_sband_iftype_data sband_capa_5ghz[] =;

static const struct ieee80211_sband_iftype_data sband_capa_6ghz[] =;

static void mac80211_hwsim_sband_capab(struct ieee80211_supported_band *sband)
{}

#ifdef CONFIG_MAC80211_MESH
#define HWSIM_MESH_BIT
#else
#define HWSIM_MESH_BIT
#endif

#define HWSIM_DEFAULT_IF_LIMIT

#define HWSIM_IFTYPE_SUPPORT_MASK

static const u8 iftypes_ext_capa_ap[] =;

#define MAC80211_HWSIM_MLD_CAPA_OPS

static const struct wiphy_iftype_ext_capab mac80211_hwsim_iftypes_ext_capa[] =;

static int mac80211_hwsim_new_radio(struct genl_info *info,
				    struct hwsim_new_radio_params *param)
{}

static void hwsim_mcast_del_radio(int id, const char *hwname,
				  struct genl_info *info)
{}

static void mac80211_hwsim_del_radio(struct mac80211_hwsim_data *data,
				     const char *hwname,
				     struct genl_info *info)
{}

static int mac80211_hwsim_get_radio(struct sk_buff *skb,
				    struct mac80211_hwsim_data *data,
				    u32 portid, u32 seq,
				    struct netlink_callback *cb, int flags)
{}

static void mac80211_hwsim_free(void)
{}

static const struct net_device_ops hwsim_netdev_ops =;

static void hwsim_mon_setup(struct net_device *dev)
{}

static void hwsim_register_wmediumd(struct net *net, u32 portid)
{}

static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
					   struct genl_info *info)
{}

static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
					  struct genl_info *info)
{}

static int hwsim_register_received_nl(struct sk_buff *skb_2,
				      struct genl_info *info)
{}

/* ensures ciphers only include ciphers listed in 'hwsim_ciphers' array */
static bool hwsim_known_ciphers(const u32 *ciphers, int n_ciphers)
{}

static int parse_ftm_capa(const struct nlattr *ftm_capa, struct cfg80211_pmsr_capabilities *out,
			  struct genl_info *info)
{}

static int parse_pmsr_capa(const struct nlattr *pmsr_capa, struct cfg80211_pmsr_capabilities *out,
			   struct genl_info *info)
{}

static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info)
{}

static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info)
{}

static int hwsim_get_radio_nl(struct sk_buff *msg, struct genl_info *info)
{}

static int hwsim_dump_radio_nl(struct sk_buff *skb,
			       struct netlink_callback *cb)
{}

/* Generic Netlink operations array */
static const struct genl_small_ops hwsim_ops[] =;

static struct genl_family hwsim_genl_family __ro_after_init =;

static void remove_user_radios(u32 portid)
{}

static int mac80211_hwsim_netlink_notify(struct notifier_block *nb,
					 unsigned long state,
					 void *_notify)
{}

static struct notifier_block hwsim_netlink_notifier =;

static int __init hwsim_init_netlink(void)
{}

static __net_init int hwsim_init_net(struct net *net)
{}

static void __net_exit hwsim_exit_net(struct net *net)
{}

static struct pernet_operations hwsim_net_ops =;

static void hwsim_exit_netlink(void)
{}

#if IS_REACHABLE(CONFIG_VIRTIO)
static void hwsim_virtio_tx_done(struct virtqueue *vq)
{}

static int hwsim_virtio_handle_cmd(struct sk_buff *skb)
{}

static void hwsim_virtio_rx_work(struct work_struct *work)
{}

static void hwsim_virtio_rx_done(struct virtqueue *vq)
{}

static int init_vqs(struct virtio_device *vdev)
{}

static int fill_vq(struct virtqueue *vq)
{}

static void remove_vqs(struct virtio_device *vdev)
{}

static int hwsim_virtio_probe(struct virtio_device *vdev)
{}

static void hwsim_virtio_remove(struct virtio_device *vdev)
{}

/* MAC80211_HWSIM virtio device id table */
static const struct virtio_device_id id_table[] =;
MODULE_DEVICE_TABLE(virtio, id_table);

static struct virtio_driver virtio_hwsim =;

static int hwsim_register_virtio_driver(void)
{}

static void hwsim_unregister_virtio_driver(void)
{}
#else
static inline int hwsim_register_virtio_driver(void)
{
	return 0;
}

static inline void hwsim_unregister_virtio_driver(void)
{
}
#endif

static int __init init_mac80211_hwsim(void)
{}
module_init();

static void __exit exit_mac80211_hwsim(void)
{}
module_exit(exit_mac80211_hwsim);