162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2002-2005, Instant802 Networks, Inc. 462306a36Sopenharmony_ci * Copyright 2005-2006, Devicescape Software, Inc. 562306a36Sopenharmony_ci * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> 662306a36Sopenharmony_ci * Copyright 2013-2014 Intel Mobile Communications GmbH 762306a36Sopenharmony_ci * Copyright (C) 2017 Intel Deutschland GmbH 862306a36Sopenharmony_ci * Copyright (C) 2018-2023 Intel Corporation 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <net/mac80211.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/fips.h> 1462306a36Sopenharmony_ci#include <linux/init.h> 1562306a36Sopenharmony_ci#include <linux/netdevice.h> 1662306a36Sopenharmony_ci#include <linux/types.h> 1762306a36Sopenharmony_ci#include <linux/slab.h> 1862306a36Sopenharmony_ci#include <linux/skbuff.h> 1962306a36Sopenharmony_ci#include <linux/etherdevice.h> 2062306a36Sopenharmony_ci#include <linux/if_arp.h> 2162306a36Sopenharmony_ci#include <linux/rtnetlink.h> 2262306a36Sopenharmony_ci#include <linux/bitmap.h> 2362306a36Sopenharmony_ci#include <linux/inetdevice.h> 2462306a36Sopenharmony_ci#include <net/net_namespace.h> 2562306a36Sopenharmony_ci#include <net/dropreason.h> 2662306a36Sopenharmony_ci#include <net/cfg80211.h> 2762306a36Sopenharmony_ci#include <net/addrconf.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include "ieee80211_i.h" 3062306a36Sopenharmony_ci#include "driver-ops.h" 3162306a36Sopenharmony_ci#include "rate.h" 3262306a36Sopenharmony_ci#include "mesh.h" 3362306a36Sopenharmony_ci#include "wep.h" 3462306a36Sopenharmony_ci#include "led.h" 3562306a36Sopenharmony_ci#include "debugfs.h" 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_civoid ieee80211_configure_filter(struct ieee80211_local *local) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci u64 mc; 4062306a36Sopenharmony_ci unsigned int changed_flags; 4162306a36Sopenharmony_ci unsigned int new_flags = 0; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci if (atomic_read(&local->iff_allmultis)) 4462306a36Sopenharmony_ci new_flags |= FIF_ALLMULTI; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci if (local->monitors || test_bit(SCAN_SW_SCANNING, &local->scanning) || 4762306a36Sopenharmony_ci test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) 4862306a36Sopenharmony_ci new_flags |= FIF_BCN_PRBRESP_PROMISC; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci if (local->fif_probe_req || local->probe_req_reg) 5162306a36Sopenharmony_ci new_flags |= FIF_PROBE_REQ; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci if (local->fif_fcsfail) 5462306a36Sopenharmony_ci new_flags |= FIF_FCSFAIL; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci if (local->fif_plcpfail) 5762306a36Sopenharmony_ci new_flags |= FIF_PLCPFAIL; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci if (local->fif_control) 6062306a36Sopenharmony_ci new_flags |= FIF_CONTROL; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci if (local->fif_other_bss) 6362306a36Sopenharmony_ci new_flags |= FIF_OTHER_BSS; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (local->fif_pspoll) 6662306a36Sopenharmony_ci new_flags |= FIF_PSPOLL; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci if (local->rx_mcast_action_reg) 6962306a36Sopenharmony_ci new_flags |= FIF_MCAST_ACTION; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci spin_lock_bh(&local->filter_lock); 7262306a36Sopenharmony_ci changed_flags = local->filter_flags ^ new_flags; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci mc = drv_prepare_multicast(local, &local->mc_list); 7562306a36Sopenharmony_ci spin_unlock_bh(&local->filter_lock); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci /* be a bit nasty */ 7862306a36Sopenharmony_ci new_flags |= (1<<31); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci drv_configure_filter(local, changed_flags, &new_flags, mc); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci WARN_ON(new_flags & (1<<31)); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci local->filter_flags = new_flags & ~(1<<31); 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic void ieee80211_reconfig_filter(struct work_struct *work) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci struct ieee80211_local *local = 9062306a36Sopenharmony_ci container_of(work, struct ieee80211_local, reconfig_filter); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci ieee80211_configure_filter(local); 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic u32 ieee80211_hw_conf_chan(struct ieee80211_local *local) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata; 9862306a36Sopenharmony_ci struct cfg80211_chan_def chandef = {}; 9962306a36Sopenharmony_ci u32 changed = 0; 10062306a36Sopenharmony_ci int power; 10162306a36Sopenharmony_ci u32 offchannel_flag; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci if (local->scan_chandef.chan) { 10662306a36Sopenharmony_ci chandef = local->scan_chandef; 10762306a36Sopenharmony_ci } else if (local->tmp_channel) { 10862306a36Sopenharmony_ci chandef.chan = local->tmp_channel; 10962306a36Sopenharmony_ci chandef.width = NL80211_CHAN_WIDTH_20_NOHT; 11062306a36Sopenharmony_ci chandef.center_freq1 = chandef.chan->center_freq; 11162306a36Sopenharmony_ci chandef.freq1_offset = chandef.chan->freq_offset; 11262306a36Sopenharmony_ci } else 11362306a36Sopenharmony_ci chandef = local->_oper_chandef; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci WARN(!cfg80211_chandef_valid(&chandef), 11662306a36Sopenharmony_ci "control:%d.%03d MHz width:%d center: %d.%03d/%d MHz", 11762306a36Sopenharmony_ci chandef.chan->center_freq, chandef.chan->freq_offset, 11862306a36Sopenharmony_ci chandef.width, chandef.center_freq1, chandef.freq1_offset, 11962306a36Sopenharmony_ci chandef.center_freq2); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci if (!cfg80211_chandef_identical(&chandef, &local->_oper_chandef)) 12262306a36Sopenharmony_ci local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL; 12362306a36Sopenharmony_ci else 12462306a36Sopenharmony_ci local->hw.conf.flags &= ~IEEE80211_CONF_OFFCHANNEL; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci offchannel_flag ^= local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci if (offchannel_flag || 12962306a36Sopenharmony_ci !cfg80211_chandef_identical(&local->hw.conf.chandef, 13062306a36Sopenharmony_ci &local->_oper_chandef)) { 13162306a36Sopenharmony_ci local->hw.conf.chandef = chandef; 13262306a36Sopenharmony_ci changed |= IEEE80211_CONF_CHANGE_CHANNEL; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (!conf_is_ht(&local->hw.conf)) { 13662306a36Sopenharmony_ci /* 13762306a36Sopenharmony_ci * mac80211.h documents that this is only valid 13862306a36Sopenharmony_ci * when the channel is set to an HT type, and 13962306a36Sopenharmony_ci * that otherwise STATIC is used. 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_ci local->hw.conf.smps_mode = IEEE80211_SMPS_STATIC; 14262306a36Sopenharmony_ci } else if (local->hw.conf.smps_mode != local->smps_mode) { 14362306a36Sopenharmony_ci local->hw.conf.smps_mode = local->smps_mode; 14462306a36Sopenharmony_ci changed |= IEEE80211_CONF_CHANGE_SMPS; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci power = ieee80211_chandef_max_power(&chandef); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci rcu_read_lock(); 15062306a36Sopenharmony_ci list_for_each_entry_rcu(sdata, &local->interfaces, list) { 15162306a36Sopenharmony_ci if (!rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf)) 15262306a36Sopenharmony_ci continue; 15362306a36Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 15462306a36Sopenharmony_ci continue; 15562306a36Sopenharmony_ci if (sdata->vif.bss_conf.txpower == INT_MIN) 15662306a36Sopenharmony_ci continue; 15762306a36Sopenharmony_ci power = min(power, sdata->vif.bss_conf.txpower); 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci rcu_read_unlock(); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci if (local->hw.conf.power_level != power) { 16262306a36Sopenharmony_ci changed |= IEEE80211_CONF_CHANGE_POWER; 16362306a36Sopenharmony_ci local->hw.conf.power_level = power; 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci return changed; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ciint ieee80211_hw_config(struct ieee80211_local *local, u32 changed) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci int ret = 0; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci might_sleep(); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci if (!local->use_chanctx) 17662306a36Sopenharmony_ci changed |= ieee80211_hw_conf_chan(local); 17762306a36Sopenharmony_ci else 17862306a36Sopenharmony_ci changed &= ~(IEEE80211_CONF_CHANGE_CHANNEL | 17962306a36Sopenharmony_ci IEEE80211_CONF_CHANGE_POWER | 18062306a36Sopenharmony_ci IEEE80211_CONF_CHANGE_SMPS); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if (changed && local->open_count) { 18362306a36Sopenharmony_ci ret = drv_config(local, changed); 18462306a36Sopenharmony_ci /* 18562306a36Sopenharmony_ci * Goal: 18662306a36Sopenharmony_ci * HW reconfiguration should never fail, the driver has told 18762306a36Sopenharmony_ci * us what it can support so it should live up to that promise. 18862306a36Sopenharmony_ci * 18962306a36Sopenharmony_ci * Current status: 19062306a36Sopenharmony_ci * rfkill is not integrated with mac80211 and a 19162306a36Sopenharmony_ci * configuration command can thus fail if hardware rfkill 19262306a36Sopenharmony_ci * is enabled 19362306a36Sopenharmony_ci * 19462306a36Sopenharmony_ci * FIXME: integrate rfkill with mac80211 and then add this 19562306a36Sopenharmony_ci * WARN_ON() back 19662306a36Sopenharmony_ci * 19762306a36Sopenharmony_ci */ 19862306a36Sopenharmony_ci /* WARN_ON(ret); */ 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci return ret; 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci#define BSS_CHANGED_VIF_CFG_FLAGS (BSS_CHANGED_ASSOC |\ 20562306a36Sopenharmony_ci BSS_CHANGED_IDLE |\ 20662306a36Sopenharmony_ci BSS_CHANGED_PS |\ 20762306a36Sopenharmony_ci BSS_CHANGED_IBSS |\ 20862306a36Sopenharmony_ci BSS_CHANGED_ARP_FILTER |\ 20962306a36Sopenharmony_ci BSS_CHANGED_SSID) 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_civoid ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, 21262306a36Sopenharmony_ci u64 changed) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci might_sleep(); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci if (!changed || sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 21962306a36Sopenharmony_ci return; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci if (WARN_ON_ONCE(changed & (BSS_CHANGED_BEACON | 22262306a36Sopenharmony_ci BSS_CHANGED_BEACON_ENABLED) && 22362306a36Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_AP && 22462306a36Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_ADHOC && 22562306a36Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_MESH_POINT && 22662306a36Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_OCB)) 22762306a36Sopenharmony_ci return; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE || 23062306a36Sopenharmony_ci sdata->vif.type == NL80211_IFTYPE_NAN || 23162306a36Sopenharmony_ci (sdata->vif.type == NL80211_IFTYPE_MONITOR && 23262306a36Sopenharmony_ci !sdata->vif.bss_conf.mu_mimo_owner && 23362306a36Sopenharmony_ci !(changed & BSS_CHANGED_TXPOWER)))) 23462306a36Sopenharmony_ci return; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci if (!check_sdata_in_driver(sdata)) 23762306a36Sopenharmony_ci return; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci if (changed & BSS_CHANGED_VIF_CFG_FLAGS) { 24062306a36Sopenharmony_ci u64 ch = changed & BSS_CHANGED_VIF_CFG_FLAGS; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci trace_drv_vif_cfg_changed(local, sdata, changed); 24362306a36Sopenharmony_ci if (local->ops->vif_cfg_changed) 24462306a36Sopenharmony_ci local->ops->vif_cfg_changed(&local->hw, &sdata->vif, ch); 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci if (changed & ~BSS_CHANGED_VIF_CFG_FLAGS) { 24862306a36Sopenharmony_ci u64 ch = changed & ~BSS_CHANGED_VIF_CFG_FLAGS; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci /* FIXME: should be for each link */ 25162306a36Sopenharmony_ci trace_drv_link_info_changed(local, sdata, &sdata->vif.bss_conf, 25262306a36Sopenharmony_ci changed); 25362306a36Sopenharmony_ci if (local->ops->link_info_changed) 25462306a36Sopenharmony_ci local->ops->link_info_changed(&local->hw, &sdata->vif, 25562306a36Sopenharmony_ci &sdata->vif.bss_conf, ch); 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (local->ops->bss_info_changed) 25962306a36Sopenharmony_ci local->ops->bss_info_changed(&local->hw, &sdata->vif, 26062306a36Sopenharmony_ci &sdata->vif.bss_conf, changed); 26162306a36Sopenharmony_ci trace_drv_return_void(local); 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_civoid ieee80211_vif_cfg_change_notify(struct ieee80211_sub_if_data *sdata, 26562306a36Sopenharmony_ci u64 changed) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci WARN_ON_ONCE(changed & ~BSS_CHANGED_VIF_CFG_FLAGS); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci if (!changed || sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 27262306a36Sopenharmony_ci return; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci drv_vif_cfg_changed(local, sdata, changed); 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_civoid ieee80211_link_info_change_notify(struct ieee80211_sub_if_data *sdata, 27862306a36Sopenharmony_ci struct ieee80211_link_data *link, 27962306a36Sopenharmony_ci u64 changed) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci WARN_ON_ONCE(changed & BSS_CHANGED_VIF_CFG_FLAGS); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci if (!changed || sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 28662306a36Sopenharmony_ci return; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (!check_sdata_in_driver(sdata)) 28962306a36Sopenharmony_ci return; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci drv_link_info_changed(local, sdata, link->conf, link->link_id, changed); 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ciu64 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci sdata->vif.bss_conf.use_cts_prot = false; 29762306a36Sopenharmony_ci sdata->vif.bss_conf.use_short_preamble = false; 29862306a36Sopenharmony_ci sdata->vif.bss_conf.use_short_slot = false; 29962306a36Sopenharmony_ci return BSS_CHANGED_ERP_CTS_PROT | 30062306a36Sopenharmony_ci BSS_CHANGED_ERP_PREAMBLE | 30162306a36Sopenharmony_ci BSS_CHANGED_ERP_SLOT; 30262306a36Sopenharmony_ci} 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic void ieee80211_tasklet_handler(struct tasklet_struct *t) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci struct ieee80211_local *local = from_tasklet(local, t, tasklet); 30762306a36Sopenharmony_ci struct sk_buff *skb; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci while ((skb = skb_dequeue(&local->skb_queue)) || 31062306a36Sopenharmony_ci (skb = skb_dequeue(&local->skb_queue_unreliable))) { 31162306a36Sopenharmony_ci switch (skb->pkt_type) { 31262306a36Sopenharmony_ci case IEEE80211_RX_MSG: 31362306a36Sopenharmony_ci /* Clear skb->pkt_type in order to not confuse kernel 31462306a36Sopenharmony_ci * netstack. */ 31562306a36Sopenharmony_ci skb->pkt_type = 0; 31662306a36Sopenharmony_ci ieee80211_rx(&local->hw, skb); 31762306a36Sopenharmony_ci break; 31862306a36Sopenharmony_ci case IEEE80211_TX_STATUS_MSG: 31962306a36Sopenharmony_ci skb->pkt_type = 0; 32062306a36Sopenharmony_ci ieee80211_tx_status(&local->hw, skb); 32162306a36Sopenharmony_ci break; 32262306a36Sopenharmony_ci default: 32362306a36Sopenharmony_ci WARN(1, "mac80211: Packet is of unknown type %d\n", 32462306a36Sopenharmony_ci skb->pkt_type); 32562306a36Sopenharmony_ci dev_kfree_skb(skb); 32662306a36Sopenharmony_ci break; 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistatic void ieee80211_restart_work(struct work_struct *work) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci struct ieee80211_local *local = 33462306a36Sopenharmony_ci container_of(work, struct ieee80211_local, restart_work); 33562306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata; 33662306a36Sopenharmony_ci int ret; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci flush_workqueue(local->workqueue); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci rtnl_lock(); 34162306a36Sopenharmony_ci /* we might do interface manipulations, so need both */ 34262306a36Sopenharmony_ci wiphy_lock(local->hw.wiphy); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci WARN(test_bit(SCAN_HW_SCANNING, &local->scanning), 34562306a36Sopenharmony_ci "%s called with hardware scan in progress\n", __func__); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci list_for_each_entry(sdata, &local->interfaces, list) { 34862306a36Sopenharmony_ci /* 34962306a36Sopenharmony_ci * XXX: there may be more work for other vif types and even 35062306a36Sopenharmony_ci * for station mode: a good thing would be to run most of 35162306a36Sopenharmony_ci * the iface type's dependent _stop (ieee80211_mg_stop, 35262306a36Sopenharmony_ci * ieee80211_ibss_stop) etc... 35362306a36Sopenharmony_ci * For now, fix only the specific bug that was seen: race 35462306a36Sopenharmony_ci * between csa_connection_drop_work and us. 35562306a36Sopenharmony_ci */ 35662306a36Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_STATION) { 35762306a36Sopenharmony_ci /* 35862306a36Sopenharmony_ci * This worker is scheduled from the iface worker that 35962306a36Sopenharmony_ci * runs on mac80211's workqueue, so we can't be 36062306a36Sopenharmony_ci * scheduling this worker after the cancel right here. 36162306a36Sopenharmony_ci * The exception is ieee80211_chswitch_done. 36262306a36Sopenharmony_ci * Then we can have a race... 36362306a36Sopenharmony_ci */ 36462306a36Sopenharmony_ci wiphy_work_cancel(local->hw.wiphy, 36562306a36Sopenharmony_ci &sdata->u.mgd.csa_connection_drop_work); 36662306a36Sopenharmony_ci if (sdata->vif.bss_conf.csa_active) { 36762306a36Sopenharmony_ci sdata_lock(sdata); 36862306a36Sopenharmony_ci ieee80211_sta_connection_lost(sdata, 36962306a36Sopenharmony_ci WLAN_REASON_UNSPECIFIED, 37062306a36Sopenharmony_ci false); 37162306a36Sopenharmony_ci sdata_unlock(sdata); 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci flush_delayed_work(&sdata->dec_tailroom_needed_wk); 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci ieee80211_scan_cancel(local); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci /* make sure any new ROC will consider local->in_reconfig */ 37962306a36Sopenharmony_ci wiphy_delayed_work_flush(local->hw.wiphy, &local->roc_work); 38062306a36Sopenharmony_ci wiphy_work_flush(local->hw.wiphy, &local->hw_roc_done); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci /* wait for all packet processing to be done */ 38362306a36Sopenharmony_ci synchronize_net(); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci ret = ieee80211_reconfig(local); 38662306a36Sopenharmony_ci wiphy_unlock(local->hw.wiphy); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci if (ret) 38962306a36Sopenharmony_ci cfg80211_shutdown_all_interfaces(local->hw.wiphy); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci rtnl_unlock(); 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_civoid ieee80211_restart_hw(struct ieee80211_hw *hw) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci struct ieee80211_local *local = hw_to_local(hw); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci trace_api_restart_hw(local); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci wiphy_info(hw->wiphy, 40162306a36Sopenharmony_ci "Hardware restart was requested\n"); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci /* use this reason, ieee80211_reconfig will unblock it */ 40462306a36Sopenharmony_ci ieee80211_stop_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, 40562306a36Sopenharmony_ci IEEE80211_QUEUE_STOP_REASON_SUSPEND, 40662306a36Sopenharmony_ci false); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci /* 40962306a36Sopenharmony_ci * Stop all Rx during the reconfig. We don't want state changes 41062306a36Sopenharmony_ci * or driver callbacks while this is in progress. 41162306a36Sopenharmony_ci */ 41262306a36Sopenharmony_ci local->in_reconfig = true; 41362306a36Sopenharmony_ci barrier(); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci queue_work(system_freezable_wq, &local->restart_work); 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_restart_hw); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci#ifdef CONFIG_INET 42062306a36Sopenharmony_cistatic int ieee80211_ifa_changed(struct notifier_block *nb, 42162306a36Sopenharmony_ci unsigned long data, void *arg) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci struct in_ifaddr *ifa = arg; 42462306a36Sopenharmony_ci struct ieee80211_local *local = 42562306a36Sopenharmony_ci container_of(nb, struct ieee80211_local, 42662306a36Sopenharmony_ci ifa_notifier); 42762306a36Sopenharmony_ci struct net_device *ndev = ifa->ifa_dev->dev; 42862306a36Sopenharmony_ci struct wireless_dev *wdev = ndev->ieee80211_ptr; 42962306a36Sopenharmony_ci struct in_device *idev; 43062306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata; 43162306a36Sopenharmony_ci struct ieee80211_vif_cfg *vif_cfg; 43262306a36Sopenharmony_ci struct ieee80211_if_managed *ifmgd; 43362306a36Sopenharmony_ci int c = 0; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci /* Make sure it's our interface that got changed */ 43662306a36Sopenharmony_ci if (!wdev) 43762306a36Sopenharmony_ci return NOTIFY_DONE; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci if (wdev->wiphy != local->hw.wiphy) 44062306a36Sopenharmony_ci return NOTIFY_DONE; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci sdata = IEEE80211_DEV_TO_SUB_IF(ndev); 44362306a36Sopenharmony_ci vif_cfg = &sdata->vif.cfg; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci /* ARP filtering is only supported in managed mode */ 44662306a36Sopenharmony_ci if (sdata->vif.type != NL80211_IFTYPE_STATION) 44762306a36Sopenharmony_ci return NOTIFY_DONE; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci idev = __in_dev_get_rtnl(sdata->dev); 45062306a36Sopenharmony_ci if (!idev) 45162306a36Sopenharmony_ci return NOTIFY_DONE; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci ifmgd = &sdata->u.mgd; 45462306a36Sopenharmony_ci sdata_lock(sdata); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci /* Copy the addresses to the vif config list */ 45762306a36Sopenharmony_ci ifa = rtnl_dereference(idev->ifa_list); 45862306a36Sopenharmony_ci while (ifa) { 45962306a36Sopenharmony_ci if (c < IEEE80211_BSS_ARP_ADDR_LIST_LEN) 46062306a36Sopenharmony_ci vif_cfg->arp_addr_list[c] = ifa->ifa_address; 46162306a36Sopenharmony_ci ifa = rtnl_dereference(ifa->ifa_next); 46262306a36Sopenharmony_ci c++; 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci vif_cfg->arp_addr_cnt = c; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci /* Configure driver only if associated (which also implies it is up) */ 46862306a36Sopenharmony_ci if (ifmgd->associated) 46962306a36Sopenharmony_ci ieee80211_vif_cfg_change_notify(sdata, BSS_CHANGED_ARP_FILTER); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci sdata_unlock(sdata); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci return NOTIFY_OK; 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci#endif 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 47862306a36Sopenharmony_cistatic int ieee80211_ifa6_changed(struct notifier_block *nb, 47962306a36Sopenharmony_ci unsigned long data, void *arg) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)arg; 48262306a36Sopenharmony_ci struct inet6_dev *idev = ifa->idev; 48362306a36Sopenharmony_ci struct net_device *ndev = ifa->idev->dev; 48462306a36Sopenharmony_ci struct ieee80211_local *local = 48562306a36Sopenharmony_ci container_of(nb, struct ieee80211_local, ifa6_notifier); 48662306a36Sopenharmony_ci struct wireless_dev *wdev = ndev->ieee80211_ptr; 48762306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci /* Make sure it's our interface that got changed */ 49062306a36Sopenharmony_ci if (!wdev || wdev->wiphy != local->hw.wiphy) 49162306a36Sopenharmony_ci return NOTIFY_DONE; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci sdata = IEEE80211_DEV_TO_SUB_IF(ndev); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci /* 49662306a36Sopenharmony_ci * For now only support station mode. This is mostly because 49762306a36Sopenharmony_ci * doing AP would have to handle AP_VLAN in some way ... 49862306a36Sopenharmony_ci */ 49962306a36Sopenharmony_ci if (sdata->vif.type != NL80211_IFTYPE_STATION) 50062306a36Sopenharmony_ci return NOTIFY_DONE; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci drv_ipv6_addr_change(local, sdata, idev); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci return NOTIFY_OK; 50562306a36Sopenharmony_ci} 50662306a36Sopenharmony_ci#endif 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci/* There isn't a lot of sense in it, but you can transmit anything you like */ 50962306a36Sopenharmony_cistatic const struct ieee80211_txrx_stypes 51062306a36Sopenharmony_ciieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { 51162306a36Sopenharmony_ci [NL80211_IFTYPE_ADHOC] = { 51262306a36Sopenharmony_ci .tx = 0xffff, 51362306a36Sopenharmony_ci .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | 51462306a36Sopenharmony_ci BIT(IEEE80211_STYPE_AUTH >> 4) | 51562306a36Sopenharmony_ci BIT(IEEE80211_STYPE_DEAUTH >> 4) | 51662306a36Sopenharmony_ci BIT(IEEE80211_STYPE_PROBE_REQ >> 4), 51762306a36Sopenharmony_ci }, 51862306a36Sopenharmony_ci [NL80211_IFTYPE_STATION] = { 51962306a36Sopenharmony_ci .tx = 0xffff, 52062306a36Sopenharmony_ci /* 52162306a36Sopenharmony_ci * To support Pre Association Security Negotiation (PASN) while 52262306a36Sopenharmony_ci * already associated to one AP, allow user space to register to 52362306a36Sopenharmony_ci * Rx authentication frames, so that the user space logic would 52462306a36Sopenharmony_ci * be able to receive/handle authentication frames from a 52562306a36Sopenharmony_ci * different AP as part of PASN. 52662306a36Sopenharmony_ci * It is expected that user space would intelligently register 52762306a36Sopenharmony_ci * for Rx authentication frames, i.e., only when PASN is used 52862306a36Sopenharmony_ci * and configure a match filter only for PASN authentication 52962306a36Sopenharmony_ci * algorithm, as otherwise the MLME functionality of mac80211 53062306a36Sopenharmony_ci * would be broken. 53162306a36Sopenharmony_ci */ 53262306a36Sopenharmony_ci .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | 53362306a36Sopenharmony_ci BIT(IEEE80211_STYPE_AUTH >> 4) | 53462306a36Sopenharmony_ci BIT(IEEE80211_STYPE_PROBE_REQ >> 4), 53562306a36Sopenharmony_ci }, 53662306a36Sopenharmony_ci [NL80211_IFTYPE_AP] = { 53762306a36Sopenharmony_ci .tx = 0xffff, 53862306a36Sopenharmony_ci .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | 53962306a36Sopenharmony_ci BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | 54062306a36Sopenharmony_ci BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | 54162306a36Sopenharmony_ci BIT(IEEE80211_STYPE_DISASSOC >> 4) | 54262306a36Sopenharmony_ci BIT(IEEE80211_STYPE_AUTH >> 4) | 54362306a36Sopenharmony_ci BIT(IEEE80211_STYPE_DEAUTH >> 4) | 54462306a36Sopenharmony_ci BIT(IEEE80211_STYPE_ACTION >> 4), 54562306a36Sopenharmony_ci }, 54662306a36Sopenharmony_ci [NL80211_IFTYPE_AP_VLAN] = { 54762306a36Sopenharmony_ci /* copy AP */ 54862306a36Sopenharmony_ci .tx = 0xffff, 54962306a36Sopenharmony_ci .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | 55062306a36Sopenharmony_ci BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | 55162306a36Sopenharmony_ci BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | 55262306a36Sopenharmony_ci BIT(IEEE80211_STYPE_DISASSOC >> 4) | 55362306a36Sopenharmony_ci BIT(IEEE80211_STYPE_AUTH >> 4) | 55462306a36Sopenharmony_ci BIT(IEEE80211_STYPE_DEAUTH >> 4) | 55562306a36Sopenharmony_ci BIT(IEEE80211_STYPE_ACTION >> 4), 55662306a36Sopenharmony_ci }, 55762306a36Sopenharmony_ci [NL80211_IFTYPE_P2P_CLIENT] = { 55862306a36Sopenharmony_ci .tx = 0xffff, 55962306a36Sopenharmony_ci .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | 56062306a36Sopenharmony_ci BIT(IEEE80211_STYPE_PROBE_REQ >> 4), 56162306a36Sopenharmony_ci }, 56262306a36Sopenharmony_ci [NL80211_IFTYPE_P2P_GO] = { 56362306a36Sopenharmony_ci .tx = 0xffff, 56462306a36Sopenharmony_ci .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | 56562306a36Sopenharmony_ci BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | 56662306a36Sopenharmony_ci BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | 56762306a36Sopenharmony_ci BIT(IEEE80211_STYPE_DISASSOC >> 4) | 56862306a36Sopenharmony_ci BIT(IEEE80211_STYPE_AUTH >> 4) | 56962306a36Sopenharmony_ci BIT(IEEE80211_STYPE_DEAUTH >> 4) | 57062306a36Sopenharmony_ci BIT(IEEE80211_STYPE_ACTION >> 4), 57162306a36Sopenharmony_ci }, 57262306a36Sopenharmony_ci [NL80211_IFTYPE_MESH_POINT] = { 57362306a36Sopenharmony_ci .tx = 0xffff, 57462306a36Sopenharmony_ci .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | 57562306a36Sopenharmony_ci BIT(IEEE80211_STYPE_AUTH >> 4) | 57662306a36Sopenharmony_ci BIT(IEEE80211_STYPE_DEAUTH >> 4), 57762306a36Sopenharmony_ci }, 57862306a36Sopenharmony_ci [NL80211_IFTYPE_P2P_DEVICE] = { 57962306a36Sopenharmony_ci .tx = 0xffff, 58062306a36Sopenharmony_ci .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | 58162306a36Sopenharmony_ci BIT(IEEE80211_STYPE_PROBE_REQ >> 4), 58262306a36Sopenharmony_ci }, 58362306a36Sopenharmony_ci}; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_cistatic const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = { 58662306a36Sopenharmony_ci .ampdu_params_info = IEEE80211_HT_AMPDU_PARM_FACTOR | 58762306a36Sopenharmony_ci IEEE80211_HT_AMPDU_PARM_DENSITY, 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci .cap_info = cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40 | 59062306a36Sopenharmony_ci IEEE80211_HT_CAP_MAX_AMSDU | 59162306a36Sopenharmony_ci IEEE80211_HT_CAP_SGI_20 | 59262306a36Sopenharmony_ci IEEE80211_HT_CAP_SGI_40 | 59362306a36Sopenharmony_ci IEEE80211_HT_CAP_TX_STBC | 59462306a36Sopenharmony_ci IEEE80211_HT_CAP_RX_STBC | 59562306a36Sopenharmony_ci IEEE80211_HT_CAP_LDPC_CODING | 59662306a36Sopenharmony_ci IEEE80211_HT_CAP_40MHZ_INTOLERANT), 59762306a36Sopenharmony_ci .mcs = { 59862306a36Sopenharmony_ci .rx_mask = { 0xff, 0xff, 0xff, 0xff, 0xff, 59962306a36Sopenharmony_ci 0xff, 0xff, 0xff, 0xff, 0xff, }, 60062306a36Sopenharmony_ci }, 60162306a36Sopenharmony_ci}; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_cistatic const struct ieee80211_vht_cap mac80211_vht_capa_mod_mask = { 60462306a36Sopenharmony_ci .vht_cap_info = 60562306a36Sopenharmony_ci cpu_to_le32(IEEE80211_VHT_CAP_RXLDPC | 60662306a36Sopenharmony_ci IEEE80211_VHT_CAP_SHORT_GI_80 | 60762306a36Sopenharmony_ci IEEE80211_VHT_CAP_SHORT_GI_160 | 60862306a36Sopenharmony_ci IEEE80211_VHT_CAP_RXSTBC_MASK | 60962306a36Sopenharmony_ci IEEE80211_VHT_CAP_TXSTBC | 61062306a36Sopenharmony_ci IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | 61162306a36Sopenharmony_ci IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | 61262306a36Sopenharmony_ci IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN | 61362306a36Sopenharmony_ci IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN | 61462306a36Sopenharmony_ci IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK), 61562306a36Sopenharmony_ci .supp_mcs = { 61662306a36Sopenharmony_ci .rx_mcs_map = cpu_to_le16(~0), 61762306a36Sopenharmony_ci .tx_mcs_map = cpu_to_le16(~0), 61862306a36Sopenharmony_ci }, 61962306a36Sopenharmony_ci}; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_cistruct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, 62262306a36Sopenharmony_ci const struct ieee80211_ops *ops, 62362306a36Sopenharmony_ci const char *requested_name) 62462306a36Sopenharmony_ci{ 62562306a36Sopenharmony_ci struct ieee80211_local *local; 62662306a36Sopenharmony_ci int priv_size, i; 62762306a36Sopenharmony_ci struct wiphy *wiphy; 62862306a36Sopenharmony_ci bool use_chanctx; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci if (WARN_ON(!ops->tx || !ops->start || !ops->stop || !ops->config || 63162306a36Sopenharmony_ci !ops->add_interface || !ops->remove_interface || 63262306a36Sopenharmony_ci !ops->configure_filter || !ops->wake_tx_queue)) 63362306a36Sopenharmony_ci return NULL; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci if (WARN_ON(ops->sta_state && (ops->sta_add || ops->sta_remove))) 63662306a36Sopenharmony_ci return NULL; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci if (WARN_ON(!!ops->link_info_changed != !!ops->vif_cfg_changed || 63962306a36Sopenharmony_ci (ops->link_info_changed && ops->bss_info_changed))) 64062306a36Sopenharmony_ci return NULL; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci /* check all or no channel context operations exist */ 64362306a36Sopenharmony_ci i = !!ops->add_chanctx + !!ops->remove_chanctx + 64462306a36Sopenharmony_ci !!ops->change_chanctx + !!ops->assign_vif_chanctx + 64562306a36Sopenharmony_ci !!ops->unassign_vif_chanctx; 64662306a36Sopenharmony_ci if (WARN_ON(i != 0 && i != 5)) 64762306a36Sopenharmony_ci return NULL; 64862306a36Sopenharmony_ci use_chanctx = i == 5; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci /* Ensure 32-byte alignment of our private data and hw private data. 65162306a36Sopenharmony_ci * We use the wiphy priv data for both our ieee80211_local and for 65262306a36Sopenharmony_ci * the driver's private data 65362306a36Sopenharmony_ci * 65462306a36Sopenharmony_ci * In memory it'll be like this: 65562306a36Sopenharmony_ci * 65662306a36Sopenharmony_ci * +-------------------------+ 65762306a36Sopenharmony_ci * | struct wiphy | 65862306a36Sopenharmony_ci * +-------------------------+ 65962306a36Sopenharmony_ci * | struct ieee80211_local | 66062306a36Sopenharmony_ci * +-------------------------+ 66162306a36Sopenharmony_ci * | driver's private data | 66262306a36Sopenharmony_ci * +-------------------------+ 66362306a36Sopenharmony_ci * 66462306a36Sopenharmony_ci */ 66562306a36Sopenharmony_ci priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci wiphy = wiphy_new_nm(&mac80211_config_ops, priv_size, requested_name); 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci if (!wiphy) 67062306a36Sopenharmony_ci return NULL; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci wiphy->mgmt_stypes = ieee80211_default_mgmt_stypes; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci wiphy->privid = mac80211_wiphy_privid; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci wiphy->flags |= WIPHY_FLAG_NETNS_OK | 67762306a36Sopenharmony_ci WIPHY_FLAG_4ADDR_AP | 67862306a36Sopenharmony_ci WIPHY_FLAG_4ADDR_STATION | 67962306a36Sopenharmony_ci WIPHY_FLAG_REPORTS_OBSS | 68062306a36Sopenharmony_ci WIPHY_FLAG_OFFCHAN_TX; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci if (!use_chanctx || ops->remain_on_channel) 68362306a36Sopenharmony_ci wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci wiphy->features |= NL80211_FEATURE_SK_TX_STATUS | 68662306a36Sopenharmony_ci NL80211_FEATURE_SAE | 68762306a36Sopenharmony_ci NL80211_FEATURE_HT_IBSS | 68862306a36Sopenharmony_ci NL80211_FEATURE_VIF_TXPOWER | 68962306a36Sopenharmony_ci NL80211_FEATURE_MAC_ON_CREATE | 69062306a36Sopenharmony_ci NL80211_FEATURE_USERSPACE_MPM | 69162306a36Sopenharmony_ci NL80211_FEATURE_FULL_AP_CLIENT_STATE; 69262306a36Sopenharmony_ci wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_STA); 69362306a36Sopenharmony_ci wiphy_ext_feature_set(wiphy, 69462306a36Sopenharmony_ci NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211); 69562306a36Sopenharmony_ci wiphy_ext_feature_set(wiphy, 69662306a36Sopenharmony_ci NL80211_EXT_FEATURE_CONTROL_PORT_NO_PREAUTH); 69762306a36Sopenharmony_ci wiphy_ext_feature_set(wiphy, 69862306a36Sopenharmony_ci NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211_TX_STATUS); 69962306a36Sopenharmony_ci wiphy_ext_feature_set(wiphy, 70062306a36Sopenharmony_ci NL80211_EXT_FEATURE_SCAN_FREQ_KHZ); 70162306a36Sopenharmony_ci wiphy_ext_feature_set(wiphy, 70262306a36Sopenharmony_ci NL80211_EXT_FEATURE_POWERED_ADDR_CHANGE); 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci if (!ops->hw_scan) { 70562306a36Sopenharmony_ci wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | 70662306a36Sopenharmony_ci NL80211_FEATURE_AP_SCAN; 70762306a36Sopenharmony_ci /* 70862306a36Sopenharmony_ci * if the driver behaves correctly using the probe request 70962306a36Sopenharmony_ci * (template) from mac80211, then both of these should be 71062306a36Sopenharmony_ci * supported even with hw scan - but let drivers opt in. 71162306a36Sopenharmony_ci */ 71262306a36Sopenharmony_ci wiphy_ext_feature_set(wiphy, 71362306a36Sopenharmony_ci NL80211_EXT_FEATURE_SCAN_RANDOM_SN); 71462306a36Sopenharmony_ci wiphy_ext_feature_set(wiphy, 71562306a36Sopenharmony_ci NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT); 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci if (!ops->set_key) 71962306a36Sopenharmony_ci wiphy->flags |= WIPHY_FLAG_IBSS_RSN; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_TXQS); 72262306a36Sopenharmony_ci wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_RRM); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci wiphy->bss_priv_size = sizeof(struct ieee80211_bss); 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci local = wiphy_priv(wiphy); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci if (sta_info_init(local)) 72962306a36Sopenharmony_ci goto err_free; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci local->hw.wiphy = wiphy; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci local->ops = ops; 73662306a36Sopenharmony_ci local->use_chanctx = use_chanctx; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci /* 73962306a36Sopenharmony_ci * We need a bit of data queued to build aggregates properly, so 74062306a36Sopenharmony_ci * instruct the TCP stack to allow more than a single ms of data 74162306a36Sopenharmony_ci * to be queued in the stack. The value is a bit-shift of 1 74262306a36Sopenharmony_ci * second, so 7 is ~8ms of queued data. Only affects local TCP 74362306a36Sopenharmony_ci * sockets. 74462306a36Sopenharmony_ci * This is the default, anyhow - drivers may need to override it 74562306a36Sopenharmony_ci * for local reasons (longer buffers, longer completion time, or 74662306a36Sopenharmony_ci * similar). 74762306a36Sopenharmony_ci */ 74862306a36Sopenharmony_ci local->hw.tx_sk_pacing_shift = 7; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci /* set up some defaults */ 75162306a36Sopenharmony_ci local->hw.queues = 1; 75262306a36Sopenharmony_ci local->hw.max_rates = 1; 75362306a36Sopenharmony_ci local->hw.max_report_rates = 0; 75462306a36Sopenharmony_ci local->hw.max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HT; 75562306a36Sopenharmony_ci local->hw.max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HT; 75662306a36Sopenharmony_ci local->hw.offchannel_tx_hw_queue = IEEE80211_INVAL_HW_QUEUE; 75762306a36Sopenharmony_ci local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; 75862306a36Sopenharmony_ci local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; 75962306a36Sopenharmony_ci local->hw.radiotap_mcs_details = IEEE80211_RADIOTAP_MCS_HAVE_MCS | 76062306a36Sopenharmony_ci IEEE80211_RADIOTAP_MCS_HAVE_GI | 76162306a36Sopenharmony_ci IEEE80211_RADIOTAP_MCS_HAVE_BW; 76262306a36Sopenharmony_ci local->hw.radiotap_vht_details = IEEE80211_RADIOTAP_VHT_KNOWN_GI | 76362306a36Sopenharmony_ci IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH; 76462306a36Sopenharmony_ci local->hw.uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES; 76562306a36Sopenharmony_ci local->hw.uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN; 76662306a36Sopenharmony_ci local->hw.max_mtu = IEEE80211_MAX_DATA_LEN; 76762306a36Sopenharmony_ci local->user_power_level = IEEE80211_UNSET_POWER_LEVEL; 76862306a36Sopenharmony_ci wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask; 76962306a36Sopenharmony_ci wiphy->vht_capa_mod_mask = &mac80211_vht_capa_mod_mask; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci local->ext_capa[7] = WLAN_EXT_CAPA8_OPMODE_NOTIF; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci wiphy->extended_capabilities = local->ext_capa; 77462306a36Sopenharmony_ci wiphy->extended_capabilities_mask = local->ext_capa; 77562306a36Sopenharmony_ci wiphy->extended_capabilities_len = 77662306a36Sopenharmony_ci ARRAY_SIZE(local->ext_capa); 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci INIT_LIST_HEAD(&local->interfaces); 77962306a36Sopenharmony_ci INIT_LIST_HEAD(&local->mon_list); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci __hw_addr_init(&local->mc_list); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci mutex_init(&local->iflist_mtx); 78462306a36Sopenharmony_ci mutex_init(&local->mtx); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci mutex_init(&local->key_mtx); 78762306a36Sopenharmony_ci spin_lock_init(&local->filter_lock); 78862306a36Sopenharmony_ci spin_lock_init(&local->rx_path_lock); 78962306a36Sopenharmony_ci spin_lock_init(&local->queue_stop_reason_lock); 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci for (i = 0; i < IEEE80211_NUM_ACS; i++) { 79262306a36Sopenharmony_ci INIT_LIST_HEAD(&local->active_txqs[i]); 79362306a36Sopenharmony_ci spin_lock_init(&local->active_txq_lock[i]); 79462306a36Sopenharmony_ci local->aql_txq_limit_low[i] = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L; 79562306a36Sopenharmony_ci local->aql_txq_limit_high[i] = 79662306a36Sopenharmony_ci IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H; 79762306a36Sopenharmony_ci atomic_set(&local->aql_ac_pending_airtime[i], 0); 79862306a36Sopenharmony_ci } 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci local->airtime_flags = AIRTIME_USE_TX | AIRTIME_USE_RX; 80162306a36Sopenharmony_ci local->aql_threshold = IEEE80211_AQL_THRESHOLD; 80262306a36Sopenharmony_ci atomic_set(&local->aql_total_pending_airtime, 0); 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci spin_lock_init(&local->handle_wake_tx_queue_lock); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci INIT_LIST_HEAD(&local->chanctx_list); 80762306a36Sopenharmony_ci mutex_init(&local->chanctx_mtx); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci wiphy_delayed_work_init(&local->scan_work, ieee80211_scan_work); 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci INIT_WORK(&local->restart_work, ieee80211_restart_work); 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci wiphy_work_init(&local->radar_detected_work, 81462306a36Sopenharmony_ci ieee80211_dfs_radar_detected_work); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); 81762306a36Sopenharmony_ci local->smps_mode = IEEE80211_SMPS_OFF; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci INIT_WORK(&local->dynamic_ps_enable_work, 82062306a36Sopenharmony_ci ieee80211_dynamic_ps_enable_work); 82162306a36Sopenharmony_ci INIT_WORK(&local->dynamic_ps_disable_work, 82262306a36Sopenharmony_ci ieee80211_dynamic_ps_disable_work); 82362306a36Sopenharmony_ci timer_setup(&local->dynamic_ps_timer, ieee80211_dynamic_ps_timer, 0); 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci wiphy_work_init(&local->sched_scan_stopped_work, 82662306a36Sopenharmony_ci ieee80211_sched_scan_stopped_work); 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci spin_lock_init(&local->ack_status_lock); 82962306a36Sopenharmony_ci idr_init(&local->ack_status_frames); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci for (i = 0; i < IEEE80211_MAX_QUEUES; i++) { 83262306a36Sopenharmony_ci skb_queue_head_init(&local->pending[i]); 83362306a36Sopenharmony_ci atomic_set(&local->agg_queue_stop[i], 0); 83462306a36Sopenharmony_ci } 83562306a36Sopenharmony_ci tasklet_setup(&local->tx_pending_tasklet, ieee80211_tx_pending); 83662306a36Sopenharmony_ci tasklet_setup(&local->wake_txqs_tasklet, ieee80211_wake_txqs); 83762306a36Sopenharmony_ci tasklet_setup(&local->tasklet, ieee80211_tasklet_handler); 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci skb_queue_head_init(&local->skb_queue); 84062306a36Sopenharmony_ci skb_queue_head_init(&local->skb_queue_unreliable); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci ieee80211_alloc_led_names(local); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci ieee80211_roc_setup(local); 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci local->hw.radiotap_timestamp.units_pos = -1; 84762306a36Sopenharmony_ci local->hw.radiotap_timestamp.accuracy = -1; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci return &local->hw; 85062306a36Sopenharmony_ci err_free: 85162306a36Sopenharmony_ci wiphy_free(wiphy); 85262306a36Sopenharmony_ci return NULL; 85362306a36Sopenharmony_ci} 85462306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_alloc_hw_nm); 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_cistatic int ieee80211_init_cipher_suites(struct ieee80211_local *local) 85762306a36Sopenharmony_ci{ 85862306a36Sopenharmony_ci bool have_wep = !fips_enabled; /* FIPS does not permit the use of RC4 */ 85962306a36Sopenharmony_ci bool have_mfp = ieee80211_hw_check(&local->hw, MFP_CAPABLE); 86062306a36Sopenharmony_ci int r = 0, w = 0; 86162306a36Sopenharmony_ci u32 *suites; 86262306a36Sopenharmony_ci static const u32 cipher_suites[] = { 86362306a36Sopenharmony_ci /* keep WEP first, it may be removed below */ 86462306a36Sopenharmony_ci WLAN_CIPHER_SUITE_WEP40, 86562306a36Sopenharmony_ci WLAN_CIPHER_SUITE_WEP104, 86662306a36Sopenharmony_ci WLAN_CIPHER_SUITE_TKIP, 86762306a36Sopenharmony_ci WLAN_CIPHER_SUITE_CCMP, 86862306a36Sopenharmony_ci WLAN_CIPHER_SUITE_CCMP_256, 86962306a36Sopenharmony_ci WLAN_CIPHER_SUITE_GCMP, 87062306a36Sopenharmony_ci WLAN_CIPHER_SUITE_GCMP_256, 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci /* keep last -- depends on hw flags! */ 87362306a36Sopenharmony_ci WLAN_CIPHER_SUITE_AES_CMAC, 87462306a36Sopenharmony_ci WLAN_CIPHER_SUITE_BIP_CMAC_256, 87562306a36Sopenharmony_ci WLAN_CIPHER_SUITE_BIP_GMAC_128, 87662306a36Sopenharmony_ci WLAN_CIPHER_SUITE_BIP_GMAC_256, 87762306a36Sopenharmony_ci }; 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci if (ieee80211_hw_check(&local->hw, SW_CRYPTO_CONTROL) || 88062306a36Sopenharmony_ci local->hw.wiphy->cipher_suites) { 88162306a36Sopenharmony_ci /* If the driver advertises, or doesn't support SW crypto, 88262306a36Sopenharmony_ci * we only need to remove WEP if necessary. 88362306a36Sopenharmony_ci */ 88462306a36Sopenharmony_ci if (have_wep) 88562306a36Sopenharmony_ci return 0; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci /* well if it has _no_ ciphers ... fine */ 88862306a36Sopenharmony_ci if (!local->hw.wiphy->n_cipher_suites) 88962306a36Sopenharmony_ci return 0; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci /* Driver provides cipher suites, but we need to exclude WEP */ 89262306a36Sopenharmony_ci suites = kmemdup(local->hw.wiphy->cipher_suites, 89362306a36Sopenharmony_ci sizeof(u32) * local->hw.wiphy->n_cipher_suites, 89462306a36Sopenharmony_ci GFP_KERNEL); 89562306a36Sopenharmony_ci if (!suites) 89662306a36Sopenharmony_ci return -ENOMEM; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) { 89962306a36Sopenharmony_ci u32 suite = local->hw.wiphy->cipher_suites[r]; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci if (suite == WLAN_CIPHER_SUITE_WEP40 || 90262306a36Sopenharmony_ci suite == WLAN_CIPHER_SUITE_WEP104) 90362306a36Sopenharmony_ci continue; 90462306a36Sopenharmony_ci suites[w++] = suite; 90562306a36Sopenharmony_ci } 90662306a36Sopenharmony_ci } else { 90762306a36Sopenharmony_ci /* assign the (software supported and perhaps offloaded) 90862306a36Sopenharmony_ci * cipher suites 90962306a36Sopenharmony_ci */ 91062306a36Sopenharmony_ci local->hw.wiphy->cipher_suites = cipher_suites; 91162306a36Sopenharmony_ci local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci if (!have_mfp) 91462306a36Sopenharmony_ci local->hw.wiphy->n_cipher_suites -= 4; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci if (!have_wep) { 91762306a36Sopenharmony_ci local->hw.wiphy->cipher_suites += 2; 91862306a36Sopenharmony_ci local->hw.wiphy->n_cipher_suites -= 2; 91962306a36Sopenharmony_ci } 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci /* not dynamically allocated, so just return */ 92262306a36Sopenharmony_ci return 0; 92362306a36Sopenharmony_ci } 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci local->hw.wiphy->cipher_suites = suites; 92662306a36Sopenharmony_ci local->hw.wiphy->n_cipher_suites = w; 92762306a36Sopenharmony_ci local->wiphy_ciphers_allocated = true; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci return 0; 93062306a36Sopenharmony_ci} 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ciint ieee80211_register_hw(struct ieee80211_hw *hw) 93362306a36Sopenharmony_ci{ 93462306a36Sopenharmony_ci struct ieee80211_local *local = hw_to_local(hw); 93562306a36Sopenharmony_ci int result, i; 93662306a36Sopenharmony_ci enum nl80211_band band; 93762306a36Sopenharmony_ci int channels, max_bitrates; 93862306a36Sopenharmony_ci bool supp_ht, supp_vht, supp_he, supp_eht; 93962306a36Sopenharmony_ci struct cfg80211_chan_def dflt_chandef = {}; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci if (ieee80211_hw_check(hw, QUEUE_CONTROL) && 94262306a36Sopenharmony_ci (local->hw.offchannel_tx_hw_queue == IEEE80211_INVAL_HW_QUEUE || 94362306a36Sopenharmony_ci local->hw.offchannel_tx_hw_queue >= local->hw.queues)) 94462306a36Sopenharmony_ci return -EINVAL; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci if ((hw->wiphy->features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH) && 94762306a36Sopenharmony_ci (!local->ops->tdls_channel_switch || 94862306a36Sopenharmony_ci !local->ops->tdls_cancel_channel_switch || 94962306a36Sopenharmony_ci !local->ops->tdls_recv_channel_switch)) 95062306a36Sopenharmony_ci return -EOPNOTSUPP; 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci if (WARN_ON(ieee80211_hw_check(hw, SUPPORTS_TX_FRAG) && 95362306a36Sopenharmony_ci !local->ops->set_frag_threshold)) 95462306a36Sopenharmony_ci return -EINVAL; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci if (WARN_ON(local->hw.wiphy->interface_modes & 95762306a36Sopenharmony_ci BIT(NL80211_IFTYPE_NAN) && 95862306a36Sopenharmony_ci (!local->ops->start_nan || !local->ops->stop_nan))) 95962306a36Sopenharmony_ci return -EINVAL; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci if (hw->wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO) { 96262306a36Sopenharmony_ci /* 96362306a36Sopenharmony_ci * For drivers capable of doing MLO, assume modern driver 96462306a36Sopenharmony_ci * or firmware facilities, so software doesn't have to do 96562306a36Sopenharmony_ci * as much, e.g. monitoring beacons would be hard if we 96662306a36Sopenharmony_ci * might not even know which link is active at which time. 96762306a36Sopenharmony_ci */ 96862306a36Sopenharmony_ci if (WARN_ON(!local->use_chanctx)) 96962306a36Sopenharmony_ci return -EINVAL; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci if (WARN_ON(!local->ops->link_info_changed)) 97262306a36Sopenharmony_ci return -EINVAL; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci if (WARN_ON(!ieee80211_hw_check(hw, HAS_RATE_CONTROL))) 97562306a36Sopenharmony_ci return -EINVAL; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci if (WARN_ON(!ieee80211_hw_check(hw, AMPDU_AGGREGATION))) 97862306a36Sopenharmony_ci return -EINVAL; 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci if (WARN_ON(ieee80211_hw_check(hw, HOST_BROADCAST_PS_BUFFERING))) 98162306a36Sopenharmony_ci return -EINVAL; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci if (WARN_ON(ieee80211_hw_check(hw, SUPPORTS_PS) && 98462306a36Sopenharmony_ci (!ieee80211_hw_check(hw, SUPPORTS_DYNAMIC_PS) || 98562306a36Sopenharmony_ci ieee80211_hw_check(hw, PS_NULLFUNC_STACK)))) 98662306a36Sopenharmony_ci return -EINVAL; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci if (WARN_ON(!ieee80211_hw_check(hw, MFP_CAPABLE))) 98962306a36Sopenharmony_ci return -EINVAL; 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci if (WARN_ON(!ieee80211_hw_check(hw, CONNECTION_MONITOR))) 99262306a36Sopenharmony_ci return -EINVAL; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci if (WARN_ON(ieee80211_hw_check(hw, NEED_DTIM_BEFORE_ASSOC))) 99562306a36Sopenharmony_ci return -EINVAL; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci if (WARN_ON(ieee80211_hw_check(hw, TIMING_BEACON_ONLY))) 99862306a36Sopenharmony_ci return -EINVAL; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci if (WARN_ON(!ieee80211_hw_check(hw, AP_LINK_PS))) 100162306a36Sopenharmony_ci return -EINVAL; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci if (WARN_ON(ieee80211_hw_check(hw, DEAUTH_NEED_MGD_TX_PREP))) 100462306a36Sopenharmony_ci return -EINVAL; 100562306a36Sopenharmony_ci } 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci#ifdef CONFIG_PM 100862306a36Sopenharmony_ci if (hw->wiphy->wowlan && (!local->ops->suspend || !local->ops->resume)) 100962306a36Sopenharmony_ci return -EINVAL; 101062306a36Sopenharmony_ci#endif 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci if (!local->use_chanctx) { 101362306a36Sopenharmony_ci for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) { 101462306a36Sopenharmony_ci const struct ieee80211_iface_combination *comb; 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci comb = &local->hw.wiphy->iface_combinations[i]; 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci if (comb->num_different_channels > 1) 101962306a36Sopenharmony_ci return -EINVAL; 102062306a36Sopenharmony_ci } 102162306a36Sopenharmony_ci } else { 102262306a36Sopenharmony_ci /* DFS is not supported with multi-channel combinations yet */ 102362306a36Sopenharmony_ci for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) { 102462306a36Sopenharmony_ci const struct ieee80211_iface_combination *comb; 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci comb = &local->hw.wiphy->iface_combinations[i]; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci if (comb->radar_detect_widths && 102962306a36Sopenharmony_ci comb->num_different_channels > 1) 103062306a36Sopenharmony_ci return -EINVAL; 103162306a36Sopenharmony_ci } 103262306a36Sopenharmony_ci } 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci /* Only HW csum features are currently compatible with mac80211 */ 103562306a36Sopenharmony_ci if (WARN_ON(hw->netdev_features & ~MAC80211_SUPPORTED_FEATURES)) 103662306a36Sopenharmony_ci return -EINVAL; 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci if (hw->max_report_rates == 0) 103962306a36Sopenharmony_ci hw->max_report_rates = hw->max_rates; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci local->rx_chains = 1; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci /* 104462306a36Sopenharmony_ci * generic code guarantees at least one band, 104562306a36Sopenharmony_ci * set this very early because much code assumes 104662306a36Sopenharmony_ci * that hw.conf.channel is assigned 104762306a36Sopenharmony_ci */ 104862306a36Sopenharmony_ci channels = 0; 104962306a36Sopenharmony_ci max_bitrates = 0; 105062306a36Sopenharmony_ci supp_ht = false; 105162306a36Sopenharmony_ci supp_vht = false; 105262306a36Sopenharmony_ci supp_he = false; 105362306a36Sopenharmony_ci supp_eht = false; 105462306a36Sopenharmony_ci for (band = 0; band < NUM_NL80211_BANDS; band++) { 105562306a36Sopenharmony_ci struct ieee80211_supported_band *sband; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci sband = local->hw.wiphy->bands[band]; 105862306a36Sopenharmony_ci if (!sband) 105962306a36Sopenharmony_ci continue; 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci if (!dflt_chandef.chan) { 106262306a36Sopenharmony_ci /* 106362306a36Sopenharmony_ci * Assign the first enabled channel to dflt_chandef 106462306a36Sopenharmony_ci * from the list of channels 106562306a36Sopenharmony_ci */ 106662306a36Sopenharmony_ci for (i = 0; i < sband->n_channels; i++) 106762306a36Sopenharmony_ci if (!(sband->channels[i].flags & 106862306a36Sopenharmony_ci IEEE80211_CHAN_DISABLED)) 106962306a36Sopenharmony_ci break; 107062306a36Sopenharmony_ci /* if none found then use the first anyway */ 107162306a36Sopenharmony_ci if (i == sband->n_channels) 107262306a36Sopenharmony_ci i = 0; 107362306a36Sopenharmony_ci cfg80211_chandef_create(&dflt_chandef, 107462306a36Sopenharmony_ci &sband->channels[i], 107562306a36Sopenharmony_ci NL80211_CHAN_NO_HT); 107662306a36Sopenharmony_ci /* init channel we're on */ 107762306a36Sopenharmony_ci if (!local->use_chanctx && !local->_oper_chandef.chan) { 107862306a36Sopenharmony_ci local->hw.conf.chandef = dflt_chandef; 107962306a36Sopenharmony_ci local->_oper_chandef = dflt_chandef; 108062306a36Sopenharmony_ci } 108162306a36Sopenharmony_ci local->monitor_chandef = dflt_chandef; 108262306a36Sopenharmony_ci } 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci channels += sband->n_channels; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci /* 108762306a36Sopenharmony_ci * Due to the way the aggregation code handles this and it 108862306a36Sopenharmony_ci * being an HT capability, we can't really support delayed 108962306a36Sopenharmony_ci * BA in MLO (yet). 109062306a36Sopenharmony_ci */ 109162306a36Sopenharmony_ci if (WARN_ON(sband->ht_cap.ht_supported && 109262306a36Sopenharmony_ci (sband->ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA) && 109362306a36Sopenharmony_ci hw->wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO)) 109462306a36Sopenharmony_ci return -EINVAL; 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci if (max_bitrates < sband->n_bitrates) 109762306a36Sopenharmony_ci max_bitrates = sband->n_bitrates; 109862306a36Sopenharmony_ci supp_ht = supp_ht || sband->ht_cap.ht_supported; 109962306a36Sopenharmony_ci supp_vht = supp_vht || sband->vht_cap.vht_supported; 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci for (i = 0; i < sband->n_iftype_data; i++) { 110262306a36Sopenharmony_ci const struct ieee80211_sband_iftype_data *iftd; 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci iftd = &sband->iftype_data[i]; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci supp_he = supp_he || iftd->he_cap.has_he; 110762306a36Sopenharmony_ci supp_eht = supp_eht || iftd->eht_cap.has_eht; 110862306a36Sopenharmony_ci } 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci /* HT, VHT, HE require QoS, thus >= 4 queues */ 111162306a36Sopenharmony_ci if (WARN_ON(local->hw.queues < IEEE80211_NUM_ACS && 111262306a36Sopenharmony_ci (supp_ht || supp_vht || supp_he))) 111362306a36Sopenharmony_ci return -EINVAL; 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci /* EHT requires HE support */ 111662306a36Sopenharmony_ci if (WARN_ON(supp_eht && !supp_he)) 111762306a36Sopenharmony_ci return -EINVAL; 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci if (!sband->ht_cap.ht_supported) 112062306a36Sopenharmony_ci continue; 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci /* TODO: consider VHT for RX chains, hopefully it's the same */ 112362306a36Sopenharmony_ci local->rx_chains = 112462306a36Sopenharmony_ci max(ieee80211_mcs_to_chains(&sband->ht_cap.mcs), 112562306a36Sopenharmony_ci local->rx_chains); 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci /* no need to mask, SM_PS_DISABLED has all bits set */ 112862306a36Sopenharmony_ci sband->ht_cap.cap |= WLAN_HT_CAP_SM_PS_DISABLED << 112962306a36Sopenharmony_ci IEEE80211_HT_CAP_SM_PS_SHIFT; 113062306a36Sopenharmony_ci } 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci /* if low-level driver supports AP, we also support VLAN. 113362306a36Sopenharmony_ci * drivers advertising SW_CRYPTO_CONTROL should enable AP_VLAN 113462306a36Sopenharmony_ci * based on their support to transmit SW encrypted packets. 113562306a36Sopenharmony_ci */ 113662306a36Sopenharmony_ci if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP) && 113762306a36Sopenharmony_ci !ieee80211_hw_check(&local->hw, SW_CRYPTO_CONTROL)) { 113862306a36Sopenharmony_ci hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); 113962306a36Sopenharmony_ci hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_AP_VLAN); 114062306a36Sopenharmony_ci } 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci /* mac80211 always supports monitor */ 114362306a36Sopenharmony_ci hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); 114462306a36Sopenharmony_ci hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR); 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci /* mac80211 doesn't support more than one IBSS interface right now */ 114762306a36Sopenharmony_ci for (i = 0; i < hw->wiphy->n_iface_combinations; i++) { 114862306a36Sopenharmony_ci const struct ieee80211_iface_combination *c; 114962306a36Sopenharmony_ci int j; 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci c = &hw->wiphy->iface_combinations[i]; 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci for (j = 0; j < c->n_limits; j++) 115462306a36Sopenharmony_ci if ((c->limits[j].types & BIT(NL80211_IFTYPE_ADHOC)) && 115562306a36Sopenharmony_ci c->limits[j].max > 1) 115662306a36Sopenharmony_ci return -EINVAL; 115762306a36Sopenharmony_ci } 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) + 116062306a36Sopenharmony_ci sizeof(void *) * channels, GFP_KERNEL); 116162306a36Sopenharmony_ci if (!local->int_scan_req) 116262306a36Sopenharmony_ci return -ENOMEM; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci eth_broadcast_addr(local->int_scan_req->bssid); 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci for (band = 0; band < NUM_NL80211_BANDS; band++) { 116762306a36Sopenharmony_ci if (!local->hw.wiphy->bands[band]) 116862306a36Sopenharmony_ci continue; 116962306a36Sopenharmony_ci local->int_scan_req->rates[band] = (u32) -1; 117062306a36Sopenharmony_ci } 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci#ifndef CONFIG_MAC80211_MESH 117362306a36Sopenharmony_ci /* mesh depends on Kconfig, but drivers should set it if they want */ 117462306a36Sopenharmony_ci local->hw.wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MESH_POINT); 117562306a36Sopenharmony_ci#endif 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci /* if the underlying driver supports mesh, mac80211 will (at least) 117862306a36Sopenharmony_ci * provide routing of mesh authentication frames to userspace */ 117962306a36Sopenharmony_ci if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_MESH_POINT)) 118062306a36Sopenharmony_ci local->hw.wiphy->flags |= WIPHY_FLAG_MESH_AUTH; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci /* mac80211 supports control port protocol changing */ 118362306a36Sopenharmony_ci local->hw.wiphy->flags |= WIPHY_FLAG_CONTROL_PORT_PROTOCOL; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci if (ieee80211_hw_check(&local->hw, SIGNAL_DBM)) { 118662306a36Sopenharmony_ci local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; 118762306a36Sopenharmony_ci } else if (ieee80211_hw_check(&local->hw, SIGNAL_UNSPEC)) { 118862306a36Sopenharmony_ci local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; 118962306a36Sopenharmony_ci if (hw->max_signal <= 0) { 119062306a36Sopenharmony_ci result = -EINVAL; 119162306a36Sopenharmony_ci goto fail_workqueue; 119262306a36Sopenharmony_ci } 119362306a36Sopenharmony_ci } 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci /* Mac80211 and therefore all drivers using SW crypto only 119662306a36Sopenharmony_ci * are able to handle PTK rekeys and Extended Key ID. 119762306a36Sopenharmony_ci */ 119862306a36Sopenharmony_ci if (!local->ops->set_key) { 119962306a36Sopenharmony_ci wiphy_ext_feature_set(local->hw.wiphy, 120062306a36Sopenharmony_ci NL80211_EXT_FEATURE_CAN_REPLACE_PTK0); 120162306a36Sopenharmony_ci wiphy_ext_feature_set(local->hw.wiphy, 120262306a36Sopenharmony_ci NL80211_EXT_FEATURE_EXT_KEY_ID); 120362306a36Sopenharmony_ci } 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_ADHOC)) 120662306a36Sopenharmony_ci wiphy_ext_feature_set(local->hw.wiphy, 120762306a36Sopenharmony_ci NL80211_EXT_FEATURE_DEL_IBSS_STA); 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci /* 121062306a36Sopenharmony_ci * Calculate scan IE length -- we need this to alloc 121162306a36Sopenharmony_ci * memory and to subtract from the driver limit. It 121262306a36Sopenharmony_ci * includes the DS Params, (extended) supported rates, and HT 121362306a36Sopenharmony_ci * information -- SSID is the driver's responsibility. 121462306a36Sopenharmony_ci */ 121562306a36Sopenharmony_ci local->scan_ies_len = 4 + max_bitrates /* (ext) supp rates */ + 121662306a36Sopenharmony_ci 3 /* DS Params */; 121762306a36Sopenharmony_ci if (supp_ht) 121862306a36Sopenharmony_ci local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap); 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci if (supp_vht) 122162306a36Sopenharmony_ci local->scan_ies_len += 122262306a36Sopenharmony_ci 2 + sizeof(struct ieee80211_vht_cap); 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci /* 122562306a36Sopenharmony_ci * HE cap element is variable in size - set len to allow max size */ 122662306a36Sopenharmony_ci if (supp_he) { 122762306a36Sopenharmony_ci local->scan_ies_len += 122862306a36Sopenharmony_ci 3 + sizeof(struct ieee80211_he_cap_elem) + 122962306a36Sopenharmony_ci sizeof(struct ieee80211_he_mcs_nss_supp) + 123062306a36Sopenharmony_ci IEEE80211_HE_PPE_THRES_MAX_LEN; 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci if (supp_eht) 123362306a36Sopenharmony_ci local->scan_ies_len += 123462306a36Sopenharmony_ci 3 + sizeof(struct ieee80211_eht_cap_elem) + 123562306a36Sopenharmony_ci sizeof(struct ieee80211_eht_mcs_nss_supp) + 123662306a36Sopenharmony_ci IEEE80211_EHT_PPE_THRES_MAX_LEN; 123762306a36Sopenharmony_ci } 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci if (!local->ops->hw_scan) { 124062306a36Sopenharmony_ci /* For hw_scan, driver needs to set these up. */ 124162306a36Sopenharmony_ci local->hw.wiphy->max_scan_ssids = 4; 124262306a36Sopenharmony_ci local->hw.wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; 124362306a36Sopenharmony_ci } 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci /* 124662306a36Sopenharmony_ci * If the driver supports any scan IEs, then assume the 124762306a36Sopenharmony_ci * limit includes the IEs mac80211 will add, otherwise 124862306a36Sopenharmony_ci * leave it at zero and let the driver sort it out; we 124962306a36Sopenharmony_ci * still pass our IEs to the driver but userspace will 125062306a36Sopenharmony_ci * not be allowed to in that case. 125162306a36Sopenharmony_ci */ 125262306a36Sopenharmony_ci if (local->hw.wiphy->max_scan_ie_len) 125362306a36Sopenharmony_ci local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len; 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci result = ieee80211_init_cipher_suites(local); 125662306a36Sopenharmony_ci if (result < 0) 125762306a36Sopenharmony_ci goto fail_workqueue; 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci if (!local->ops->remain_on_channel) 126062306a36Sopenharmony_ci local->hw.wiphy->max_remain_on_channel_duration = 5000; 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci /* mac80211 based drivers don't support internal TDLS setup */ 126362306a36Sopenharmony_ci if (local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) 126462306a36Sopenharmony_ci local->hw.wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP; 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci /* mac80211 supports eCSA, if the driver supports STA CSA at all */ 126762306a36Sopenharmony_ci if (ieee80211_hw_check(&local->hw, CHANCTX_STA_CSA)) 126862306a36Sopenharmony_ci local->ext_capa[0] |= WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING; 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci /* mac80211 supports multi BSSID, if the driver supports it */ 127162306a36Sopenharmony_ci if (ieee80211_hw_check(&local->hw, SUPPORTS_MULTI_BSSID)) { 127262306a36Sopenharmony_ci local->hw.wiphy->support_mbssid = true; 127362306a36Sopenharmony_ci if (ieee80211_hw_check(&local->hw, 127462306a36Sopenharmony_ci SUPPORTS_ONLY_HE_MULTI_BSSID)) 127562306a36Sopenharmony_ci local->hw.wiphy->support_only_he_mbssid = true; 127662306a36Sopenharmony_ci else 127762306a36Sopenharmony_ci local->ext_capa[2] |= 127862306a36Sopenharmony_ci WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT; 127962306a36Sopenharmony_ci } 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci local->hw.wiphy->max_num_csa_counters = IEEE80211_MAX_CNTDWN_COUNTERS_NUM; 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci /* 128462306a36Sopenharmony_ci * We use the number of queues for feature tests (QoS, HT) internally 128562306a36Sopenharmony_ci * so restrict them appropriately. 128662306a36Sopenharmony_ci */ 128762306a36Sopenharmony_ci if (hw->queues > IEEE80211_MAX_QUEUES) 128862306a36Sopenharmony_ci hw->queues = IEEE80211_MAX_QUEUES; 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci local->workqueue = 129162306a36Sopenharmony_ci alloc_ordered_workqueue("%s", 0, wiphy_name(local->hw.wiphy)); 129262306a36Sopenharmony_ci if (!local->workqueue) { 129362306a36Sopenharmony_ci result = -ENOMEM; 129462306a36Sopenharmony_ci goto fail_workqueue; 129562306a36Sopenharmony_ci } 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci /* 129862306a36Sopenharmony_ci * The hardware needs headroom for sending the frame, 129962306a36Sopenharmony_ci * and we need some headroom for passing the frame to monitor 130062306a36Sopenharmony_ci * interfaces, but never both at the same time. 130162306a36Sopenharmony_ci */ 130262306a36Sopenharmony_ci local->tx_headroom = max_t(unsigned int , local->hw.extra_tx_headroom, 130362306a36Sopenharmony_ci IEEE80211_TX_STATUS_HEADROOM); 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci /* 130662306a36Sopenharmony_ci * if the driver doesn't specify a max listen interval we 130762306a36Sopenharmony_ci * use 5 which should be a safe default 130862306a36Sopenharmony_ci */ 130962306a36Sopenharmony_ci if (local->hw.max_listen_interval == 0) 131062306a36Sopenharmony_ci local->hw.max_listen_interval = 5; 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci local->hw.conf.listen_interval = local->hw.max_listen_interval; 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci local->dynamic_ps_forced_timeout = -1; 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci if (!local->hw.max_nan_de_entries) 131762306a36Sopenharmony_ci local->hw.max_nan_de_entries = IEEE80211_MAX_NAN_INSTANCE_ID; 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci if (!local->hw.weight_multiplier) 132062306a36Sopenharmony_ci local->hw.weight_multiplier = 1; 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci ieee80211_wep_init(local); 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci local->hw.conf.flags = IEEE80211_CONF_IDLE; 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci ieee80211_led_init(local); 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci result = ieee80211_txq_setup_flows(local); 132962306a36Sopenharmony_ci if (result) 133062306a36Sopenharmony_ci goto fail_flows; 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci rtnl_lock(); 133362306a36Sopenharmony_ci result = ieee80211_init_rate_ctrl_alg(local, 133462306a36Sopenharmony_ci hw->rate_control_algorithm); 133562306a36Sopenharmony_ci rtnl_unlock(); 133662306a36Sopenharmony_ci if (result < 0) { 133762306a36Sopenharmony_ci wiphy_debug(local->hw.wiphy, 133862306a36Sopenharmony_ci "Failed to initialize rate control algorithm\n"); 133962306a36Sopenharmony_ci goto fail_rate; 134062306a36Sopenharmony_ci } 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci if (local->rate_ctrl) { 134362306a36Sopenharmony_ci clear_bit(IEEE80211_HW_SUPPORTS_VHT_EXT_NSS_BW, hw->flags); 134462306a36Sopenharmony_ci if (local->rate_ctrl->ops->capa & RATE_CTRL_CAPA_VHT_EXT_NSS_BW) 134562306a36Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW); 134662306a36Sopenharmony_ci } 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci /* 134962306a36Sopenharmony_ci * If the VHT capabilities don't have IEEE80211_VHT_EXT_NSS_BW_CAPABLE, 135062306a36Sopenharmony_ci * or have it when we don't, copy the sband structure and set/clear it. 135162306a36Sopenharmony_ci * This is necessary because rate scaling algorithms could be switched 135262306a36Sopenharmony_ci * and have different support values. 135362306a36Sopenharmony_ci * Print a message so that in the common case the reallocation can be 135462306a36Sopenharmony_ci * avoided. 135562306a36Sopenharmony_ci */ 135662306a36Sopenharmony_ci BUILD_BUG_ON(NUM_NL80211_BANDS > 8 * sizeof(local->sband_allocated)); 135762306a36Sopenharmony_ci for (band = 0; band < NUM_NL80211_BANDS; band++) { 135862306a36Sopenharmony_ci struct ieee80211_supported_band *sband; 135962306a36Sopenharmony_ci bool local_cap, ie_cap; 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci local_cap = ieee80211_hw_check(hw, SUPPORTS_VHT_EXT_NSS_BW); 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci sband = local->hw.wiphy->bands[band]; 136462306a36Sopenharmony_ci if (!sband || !sband->vht_cap.vht_supported) 136562306a36Sopenharmony_ci continue; 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci ie_cap = !!(sband->vht_cap.vht_mcs.tx_highest & 136862306a36Sopenharmony_ci cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE)); 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci if (local_cap == ie_cap) 137162306a36Sopenharmony_ci continue; 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci sband = kmemdup(sband, sizeof(*sband), GFP_KERNEL); 137462306a36Sopenharmony_ci if (!sband) { 137562306a36Sopenharmony_ci result = -ENOMEM; 137662306a36Sopenharmony_ci goto fail_rate; 137762306a36Sopenharmony_ci } 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci wiphy_dbg(hw->wiphy, "copying sband (band %d) due to VHT EXT NSS BW flag\n", 138062306a36Sopenharmony_ci band); 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci sband->vht_cap.vht_mcs.tx_highest ^= 138362306a36Sopenharmony_ci cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE); 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci local->hw.wiphy->bands[band] = sband; 138662306a36Sopenharmony_ci local->sband_allocated |= BIT(band); 138762306a36Sopenharmony_ci } 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci result = wiphy_register(local->hw.wiphy); 139062306a36Sopenharmony_ci if (result < 0) 139162306a36Sopenharmony_ci goto fail_wiphy_register; 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci debugfs_hw_add(local); 139462306a36Sopenharmony_ci rate_control_add_debugfs(local); 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci rtnl_lock(); 139762306a36Sopenharmony_ci wiphy_lock(hw->wiphy); 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci /* add one default STA interface if supported */ 140062306a36Sopenharmony_ci if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION) && 140162306a36Sopenharmony_ci !ieee80211_hw_check(hw, NO_AUTO_VIF)) { 140262306a36Sopenharmony_ci struct vif_params params = {0}; 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci result = ieee80211_if_add(local, "wlan%d", NET_NAME_ENUM, NULL, 140562306a36Sopenharmony_ci NL80211_IFTYPE_STATION, ¶ms); 140662306a36Sopenharmony_ci if (result) 140762306a36Sopenharmony_ci wiphy_warn(local->hw.wiphy, 140862306a36Sopenharmony_ci "Failed to add default virtual iface\n"); 140962306a36Sopenharmony_ci } 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci wiphy_unlock(hw->wiphy); 141262306a36Sopenharmony_ci rtnl_unlock(); 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci#ifdef CONFIG_INET 141562306a36Sopenharmony_ci local->ifa_notifier.notifier_call = ieee80211_ifa_changed; 141662306a36Sopenharmony_ci result = register_inetaddr_notifier(&local->ifa_notifier); 141762306a36Sopenharmony_ci if (result) 141862306a36Sopenharmony_ci goto fail_ifa; 141962306a36Sopenharmony_ci#endif 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 142262306a36Sopenharmony_ci local->ifa6_notifier.notifier_call = ieee80211_ifa6_changed; 142362306a36Sopenharmony_ci result = register_inet6addr_notifier(&local->ifa6_notifier); 142462306a36Sopenharmony_ci if (result) 142562306a36Sopenharmony_ci goto fail_ifa6; 142662306a36Sopenharmony_ci#endif 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci return 0; 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 143162306a36Sopenharmony_ci fail_ifa6: 143262306a36Sopenharmony_ci#ifdef CONFIG_INET 143362306a36Sopenharmony_ci unregister_inetaddr_notifier(&local->ifa_notifier); 143462306a36Sopenharmony_ci#endif 143562306a36Sopenharmony_ci#endif 143662306a36Sopenharmony_ci#if defined(CONFIG_INET) || defined(CONFIG_IPV6) 143762306a36Sopenharmony_ci fail_ifa: 143862306a36Sopenharmony_ci#endif 143962306a36Sopenharmony_ci wiphy_unregister(local->hw.wiphy); 144062306a36Sopenharmony_ci fail_wiphy_register: 144162306a36Sopenharmony_ci rtnl_lock(); 144262306a36Sopenharmony_ci rate_control_deinitialize(local); 144362306a36Sopenharmony_ci ieee80211_remove_interfaces(local); 144462306a36Sopenharmony_ci rtnl_unlock(); 144562306a36Sopenharmony_ci fail_rate: 144662306a36Sopenharmony_ci fail_flows: 144762306a36Sopenharmony_ci ieee80211_led_exit(local); 144862306a36Sopenharmony_ci destroy_workqueue(local->workqueue); 144962306a36Sopenharmony_ci fail_workqueue: 145062306a36Sopenharmony_ci if (local->wiphy_ciphers_allocated) { 145162306a36Sopenharmony_ci kfree(local->hw.wiphy->cipher_suites); 145262306a36Sopenharmony_ci local->wiphy_ciphers_allocated = false; 145362306a36Sopenharmony_ci } 145462306a36Sopenharmony_ci kfree(local->int_scan_req); 145562306a36Sopenharmony_ci return result; 145662306a36Sopenharmony_ci} 145762306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_register_hw); 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_civoid ieee80211_unregister_hw(struct ieee80211_hw *hw) 146062306a36Sopenharmony_ci{ 146162306a36Sopenharmony_ci struct ieee80211_local *local = hw_to_local(hw); 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci tasklet_kill(&local->tx_pending_tasklet); 146462306a36Sopenharmony_ci tasklet_kill(&local->tasklet); 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci#ifdef CONFIG_INET 146762306a36Sopenharmony_ci unregister_inetaddr_notifier(&local->ifa_notifier); 146862306a36Sopenharmony_ci#endif 146962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 147062306a36Sopenharmony_ci unregister_inet6addr_notifier(&local->ifa6_notifier); 147162306a36Sopenharmony_ci#endif 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci rtnl_lock(); 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci /* 147662306a36Sopenharmony_ci * At this point, interface list manipulations are fine 147762306a36Sopenharmony_ci * because the driver cannot be handing us frames any 147862306a36Sopenharmony_ci * more and the tasklet is killed. 147962306a36Sopenharmony_ci */ 148062306a36Sopenharmony_ci ieee80211_remove_interfaces(local); 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci wiphy_lock(local->hw.wiphy); 148362306a36Sopenharmony_ci wiphy_delayed_work_cancel(local->hw.wiphy, &local->roc_work); 148462306a36Sopenharmony_ci wiphy_work_cancel(local->hw.wiphy, &local->sched_scan_stopped_work); 148562306a36Sopenharmony_ci wiphy_work_cancel(local->hw.wiphy, &local->radar_detected_work); 148662306a36Sopenharmony_ci wiphy_unlock(local->hw.wiphy); 148762306a36Sopenharmony_ci rtnl_unlock(); 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci cancel_work_sync(&local->restart_work); 149062306a36Sopenharmony_ci cancel_work_sync(&local->reconfig_filter); 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci ieee80211_clear_tx_pending(local); 149362306a36Sopenharmony_ci rate_control_deinitialize(local); 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci if (skb_queue_len(&local->skb_queue) || 149662306a36Sopenharmony_ci skb_queue_len(&local->skb_queue_unreliable)) 149762306a36Sopenharmony_ci wiphy_warn(local->hw.wiphy, "skb_queue not empty\n"); 149862306a36Sopenharmony_ci skb_queue_purge(&local->skb_queue); 149962306a36Sopenharmony_ci skb_queue_purge(&local->skb_queue_unreliable); 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci wiphy_unregister(local->hw.wiphy); 150262306a36Sopenharmony_ci destroy_workqueue(local->workqueue); 150362306a36Sopenharmony_ci ieee80211_led_exit(local); 150462306a36Sopenharmony_ci kfree(local->int_scan_req); 150562306a36Sopenharmony_ci} 150662306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_unregister_hw); 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_cistatic int ieee80211_free_ack_frame(int id, void *p, void *data) 150962306a36Sopenharmony_ci{ 151062306a36Sopenharmony_ci WARN_ONCE(1, "Have pending ack frames!\n"); 151162306a36Sopenharmony_ci kfree_skb(p); 151262306a36Sopenharmony_ci return 0; 151362306a36Sopenharmony_ci} 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_civoid ieee80211_free_hw(struct ieee80211_hw *hw) 151662306a36Sopenharmony_ci{ 151762306a36Sopenharmony_ci struct ieee80211_local *local = hw_to_local(hw); 151862306a36Sopenharmony_ci enum nl80211_band band; 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci mutex_destroy(&local->iflist_mtx); 152162306a36Sopenharmony_ci mutex_destroy(&local->mtx); 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci if (local->wiphy_ciphers_allocated) { 152462306a36Sopenharmony_ci kfree(local->hw.wiphy->cipher_suites); 152562306a36Sopenharmony_ci local->wiphy_ciphers_allocated = false; 152662306a36Sopenharmony_ci } 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci idr_for_each(&local->ack_status_frames, 152962306a36Sopenharmony_ci ieee80211_free_ack_frame, NULL); 153062306a36Sopenharmony_ci idr_destroy(&local->ack_status_frames); 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci sta_info_stop(local); 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci ieee80211_free_led_names(local); 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci for (band = 0; band < NUM_NL80211_BANDS; band++) { 153762306a36Sopenharmony_ci if (!(local->sband_allocated & BIT(band))) 153862306a36Sopenharmony_ci continue; 153962306a36Sopenharmony_ci kfree(local->hw.wiphy->bands[band]); 154062306a36Sopenharmony_ci } 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci wiphy_free(local->hw.wiphy); 154362306a36Sopenharmony_ci} 154462306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_free_hw); 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_cistatic const char * const drop_reasons_monitor[] = { 154762306a36Sopenharmony_ci#define V(x) #x, 154862306a36Sopenharmony_ci [0] = "RX_DROP_MONITOR", 154962306a36Sopenharmony_ci MAC80211_DROP_REASONS_MONITOR(V) 155062306a36Sopenharmony_ci}; 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_cistatic struct drop_reason_list drop_reason_list_monitor = { 155362306a36Sopenharmony_ci .reasons = drop_reasons_monitor, 155462306a36Sopenharmony_ci .n_reasons = ARRAY_SIZE(drop_reasons_monitor), 155562306a36Sopenharmony_ci}; 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_cistatic const char * const drop_reasons_unusable[] = { 155862306a36Sopenharmony_ci [0] = "RX_DROP_UNUSABLE", 155962306a36Sopenharmony_ci MAC80211_DROP_REASONS_UNUSABLE(V) 156062306a36Sopenharmony_ci#undef V 156162306a36Sopenharmony_ci}; 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_cistatic struct drop_reason_list drop_reason_list_unusable = { 156462306a36Sopenharmony_ci .reasons = drop_reasons_unusable, 156562306a36Sopenharmony_ci .n_reasons = ARRAY_SIZE(drop_reasons_unusable), 156662306a36Sopenharmony_ci}; 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_cistatic int __init ieee80211_init(void) 156962306a36Sopenharmony_ci{ 157062306a36Sopenharmony_ci struct sk_buff *skb; 157162306a36Sopenharmony_ci int ret; 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct ieee80211_tx_info) > sizeof(skb->cb)); 157462306a36Sopenharmony_ci BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, driver_data) + 157562306a36Sopenharmony_ci IEEE80211_TX_INFO_DRIVER_DATA_SIZE > sizeof(skb->cb)); 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci ret = rc80211_minstrel_init(); 157862306a36Sopenharmony_ci if (ret) 157962306a36Sopenharmony_ci return ret; 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci ret = ieee80211_iface_init(); 158262306a36Sopenharmony_ci if (ret) 158362306a36Sopenharmony_ci goto err_netdev; 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci drop_reasons_register_subsys(SKB_DROP_REASON_SUBSYS_MAC80211_MONITOR, 158662306a36Sopenharmony_ci &drop_reason_list_monitor); 158762306a36Sopenharmony_ci drop_reasons_register_subsys(SKB_DROP_REASON_SUBSYS_MAC80211_UNUSABLE, 158862306a36Sopenharmony_ci &drop_reason_list_unusable); 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_ci return 0; 159162306a36Sopenharmony_ci err_netdev: 159262306a36Sopenharmony_ci rc80211_minstrel_exit(); 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_ci return ret; 159562306a36Sopenharmony_ci} 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_cistatic void __exit ieee80211_exit(void) 159862306a36Sopenharmony_ci{ 159962306a36Sopenharmony_ci rc80211_minstrel_exit(); 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci ieee80211s_stop(); 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci ieee80211_iface_exit(); 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci drop_reasons_unregister_subsys(SKB_DROP_REASON_SUBSYS_MAC80211_MONITOR); 160662306a36Sopenharmony_ci drop_reasons_unregister_subsys(SKB_DROP_REASON_SUBSYS_MAC80211_UNUSABLE); 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_ci rcu_barrier(); 160962306a36Sopenharmony_ci} 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_cisubsys_initcall(ieee80211_init); 161362306a36Sopenharmony_cimodule_exit(ieee80211_exit); 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ciMODULE_DESCRIPTION("IEEE 802.11 subsystem"); 161662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1617