162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Interface handling 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2002-2005, Instant802 Networks, Inc. 662306a36Sopenharmony_ci * Copyright 2005-2006, Devicescape Software, Inc. 762306a36Sopenharmony_ci * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz> 862306a36Sopenharmony_ci * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> 962306a36Sopenharmony_ci * Copyright 2013-2014 Intel Mobile Communications GmbH 1062306a36Sopenharmony_ci * Copyright (c) 2016 Intel Deutschland GmbH 1162306a36Sopenharmony_ci * Copyright (C) 2018-2023 Intel Corporation 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci#include <linux/slab.h> 1462306a36Sopenharmony_ci#include <linux/kernel.h> 1562306a36Sopenharmony_ci#include <linux/if_arp.h> 1662306a36Sopenharmony_ci#include <linux/netdevice.h> 1762306a36Sopenharmony_ci#include <linux/rtnetlink.h> 1862306a36Sopenharmony_ci#include <linux/kcov.h> 1962306a36Sopenharmony_ci#include <net/mac80211.h> 2062306a36Sopenharmony_ci#include <net/ieee80211_radiotap.h> 2162306a36Sopenharmony_ci#include "ieee80211_i.h" 2262306a36Sopenharmony_ci#include "sta_info.h" 2362306a36Sopenharmony_ci#include "debugfs_netdev.h" 2462306a36Sopenharmony_ci#include "mesh.h" 2562306a36Sopenharmony_ci#include "led.h" 2662306a36Sopenharmony_ci#include "driver-ops.h" 2762306a36Sopenharmony_ci#include "wme.h" 2862306a36Sopenharmony_ci#include "rate.h" 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/** 3162306a36Sopenharmony_ci * DOC: Interface list locking 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * The interface list in each struct ieee80211_local is protected 3462306a36Sopenharmony_ci * three-fold: 3562306a36Sopenharmony_ci * 3662306a36Sopenharmony_ci * (1) modifications may only be done under the RTNL 3762306a36Sopenharmony_ci * (2) modifications and readers are protected against each other by 3862306a36Sopenharmony_ci * the iflist_mtx. 3962306a36Sopenharmony_ci * (3) modifications are done in an RCU manner so atomic readers 4062306a36Sopenharmony_ci * can traverse the list in RCU-safe blocks. 4162306a36Sopenharmony_ci * 4262306a36Sopenharmony_ci * As a consequence, reads (traversals) of the list can be protected 4362306a36Sopenharmony_ci * by either the RTNL, the iflist_mtx or RCU. 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic void ieee80211_iface_work(struct wiphy *wiphy, struct wiphy_work *work); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cibool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci struct ieee80211_chanctx_conf *chanctx_conf; 5162306a36Sopenharmony_ci int power; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci rcu_read_lock(); 5462306a36Sopenharmony_ci chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); 5562306a36Sopenharmony_ci if (!chanctx_conf) { 5662306a36Sopenharmony_ci rcu_read_unlock(); 5762306a36Sopenharmony_ci return false; 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci power = ieee80211_chandef_max_power(&chanctx_conf->def); 6162306a36Sopenharmony_ci rcu_read_unlock(); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci if (sdata->deflink.user_power_level != IEEE80211_UNSET_POWER_LEVEL) 6462306a36Sopenharmony_ci power = min(power, sdata->deflink.user_power_level); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci if (sdata->deflink.ap_power_level != IEEE80211_UNSET_POWER_LEVEL) 6762306a36Sopenharmony_ci power = min(power, sdata->deflink.ap_power_level); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci if (power != sdata->vif.bss_conf.txpower) { 7062306a36Sopenharmony_ci sdata->vif.bss_conf.txpower = power; 7162306a36Sopenharmony_ci ieee80211_hw_config(sdata->local, 0); 7262306a36Sopenharmony_ci return true; 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci return false; 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_civoid ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata, 7962306a36Sopenharmony_ci bool update_bss) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci if (__ieee80211_recalc_txpower(sdata) || 8262306a36Sopenharmony_ci (update_bss && ieee80211_sdata_running(sdata))) 8362306a36Sopenharmony_ci ieee80211_link_info_change_notify(sdata, &sdata->deflink, 8462306a36Sopenharmony_ci BSS_CHANGED_TXPOWER); 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic u32 __ieee80211_idle_off(struct ieee80211_local *local) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE)) 9062306a36Sopenharmony_ci return 0; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci local->hw.conf.flags &= ~IEEE80211_CONF_IDLE; 9362306a36Sopenharmony_ci return IEEE80211_CONF_CHANGE_IDLE; 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic u32 __ieee80211_idle_on(struct ieee80211_local *local) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci if (local->hw.conf.flags & IEEE80211_CONF_IDLE) 9962306a36Sopenharmony_ci return 0; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci ieee80211_flush_queues(local, NULL, false); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci local->hw.conf.flags |= IEEE80211_CONF_IDLE; 10462306a36Sopenharmony_ci return IEEE80211_CONF_CHANGE_IDLE; 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic u32 __ieee80211_recalc_idle(struct ieee80211_local *local, 10862306a36Sopenharmony_ci bool force_active) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci bool working, scanning, active; 11162306a36Sopenharmony_ci unsigned int led_trig_start = 0, led_trig_stop = 0; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci lockdep_assert_held(&local->mtx); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci active = force_active || 11662306a36Sopenharmony_ci !list_empty(&local->chanctx_list) || 11762306a36Sopenharmony_ci local->monitors; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci working = !local->ops->remain_on_channel && 12062306a36Sopenharmony_ci !list_empty(&local->roc_list); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci scanning = test_bit(SCAN_SW_SCANNING, &local->scanning) || 12362306a36Sopenharmony_ci test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (working || scanning) 12662306a36Sopenharmony_ci led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK; 12762306a36Sopenharmony_ci else 12862306a36Sopenharmony_ci led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (active) 13162306a36Sopenharmony_ci led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; 13262306a36Sopenharmony_ci else 13362306a36Sopenharmony_ci led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci if (working || scanning || active) 13862306a36Sopenharmony_ci return __ieee80211_idle_off(local); 13962306a36Sopenharmony_ci return __ieee80211_idle_on(local); 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ciu32 ieee80211_idle_off(struct ieee80211_local *local) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci return __ieee80211_recalc_idle(local, true); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_civoid ieee80211_recalc_idle(struct ieee80211_local *local) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci u32 change = __ieee80211_recalc_idle(local, false); 15062306a36Sopenharmony_ci if (change) 15162306a36Sopenharmony_ci ieee80211_hw_config(local, change); 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic int ieee80211_verify_mac(struct ieee80211_sub_if_data *sdata, u8 *addr, 15562306a36Sopenharmony_ci bool check_dup) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 15862306a36Sopenharmony_ci struct ieee80211_sub_if_data *iter; 15962306a36Sopenharmony_ci u64 new, mask, tmp; 16062306a36Sopenharmony_ci u8 *m; 16162306a36Sopenharmony_ci int ret = 0; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (is_zero_ether_addr(local->hw.wiphy->addr_mask)) 16462306a36Sopenharmony_ci return 0; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci m = addr; 16762306a36Sopenharmony_ci new = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) | 16862306a36Sopenharmony_ci ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) | 16962306a36Sopenharmony_ci ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci m = local->hw.wiphy->addr_mask; 17262306a36Sopenharmony_ci mask = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) | 17362306a36Sopenharmony_ci ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) | 17462306a36Sopenharmony_ci ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci if (!check_dup) 17762306a36Sopenharmony_ci return ret; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci mutex_lock(&local->iflist_mtx); 18062306a36Sopenharmony_ci list_for_each_entry(iter, &local->interfaces, list) { 18162306a36Sopenharmony_ci if (iter == sdata) 18262306a36Sopenharmony_ci continue; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (iter->vif.type == NL80211_IFTYPE_MONITOR && 18562306a36Sopenharmony_ci !(iter->u.mntr.flags & MONITOR_FLAG_ACTIVE)) 18662306a36Sopenharmony_ci continue; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci m = iter->vif.addr; 18962306a36Sopenharmony_ci tmp = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) | 19062306a36Sopenharmony_ci ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) | 19162306a36Sopenharmony_ci ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if ((new & ~mask) != (tmp & ~mask)) { 19462306a36Sopenharmony_ci ret = -EINVAL; 19562306a36Sopenharmony_ci break; 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci mutex_unlock(&local->iflist_mtx); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci return ret; 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic int ieee80211_can_powered_addr_change(struct ieee80211_sub_if_data *sdata) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci struct ieee80211_roc_work *roc; 20662306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 20762306a36Sopenharmony_ci struct ieee80211_sub_if_data *scan_sdata; 20862306a36Sopenharmony_ci int ret = 0; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci /* To be the most flexible here we want to only limit changing the 21162306a36Sopenharmony_ci * address if the specific interface is doing offchannel work or 21262306a36Sopenharmony_ci * scanning. 21362306a36Sopenharmony_ci */ 21462306a36Sopenharmony_ci if (netif_carrier_ok(sdata->dev)) 21562306a36Sopenharmony_ci return -EBUSY; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci mutex_lock(&local->mtx); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci /* First check no ROC work is happening on this iface */ 22062306a36Sopenharmony_ci list_for_each_entry(roc, &local->roc_list, list) { 22162306a36Sopenharmony_ci if (roc->sdata != sdata) 22262306a36Sopenharmony_ci continue; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci if (roc->started) { 22562306a36Sopenharmony_ci ret = -EBUSY; 22662306a36Sopenharmony_ci goto unlock; 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci /* And if this iface is scanning */ 23162306a36Sopenharmony_ci if (local->scanning) { 23262306a36Sopenharmony_ci scan_sdata = rcu_dereference_protected(local->scan_sdata, 23362306a36Sopenharmony_ci lockdep_is_held(&local->mtx)); 23462306a36Sopenharmony_ci if (sdata == scan_sdata) 23562306a36Sopenharmony_ci ret = -EBUSY; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci switch (sdata->vif.type) { 23962306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 24062306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_CLIENT: 24162306a36Sopenharmony_ci /* More interface types could be added here but changing the 24262306a36Sopenharmony_ci * address while powered makes the most sense in client modes. 24362306a36Sopenharmony_ci */ 24462306a36Sopenharmony_ci break; 24562306a36Sopenharmony_ci default: 24662306a36Sopenharmony_ci ret = -EOPNOTSUPP; 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ciunlock: 25062306a36Sopenharmony_ci mutex_unlock(&local->mtx); 25162306a36Sopenharmony_ci return ret; 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic int ieee80211_change_mac(struct net_device *dev, void *addr) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 25762306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 25862306a36Sopenharmony_ci struct sockaddr *sa = addr; 25962306a36Sopenharmony_ci bool check_dup = true; 26062306a36Sopenharmony_ci bool live = false; 26162306a36Sopenharmony_ci int ret; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci if (ieee80211_sdata_running(sdata)) { 26462306a36Sopenharmony_ci ret = ieee80211_can_powered_addr_change(sdata); 26562306a36Sopenharmony_ci if (ret) 26662306a36Sopenharmony_ci return ret; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci live = true; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_MONITOR && 27262306a36Sopenharmony_ci !(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE)) 27362306a36Sopenharmony_ci check_dup = false; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci ret = ieee80211_verify_mac(sdata, sa->sa_data, check_dup); 27662306a36Sopenharmony_ci if (ret) 27762306a36Sopenharmony_ci return ret; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci if (live) 28062306a36Sopenharmony_ci drv_remove_interface(local, sdata); 28162306a36Sopenharmony_ci ret = eth_mac_addr(dev, sa); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if (ret == 0) { 28462306a36Sopenharmony_ci memcpy(sdata->vif.addr, sa->sa_data, ETH_ALEN); 28562306a36Sopenharmony_ci ether_addr_copy(sdata->vif.bss_conf.addr, sdata->vif.addr); 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci /* Regardless of eth_mac_addr() return we still want to add the 28962306a36Sopenharmony_ci * interface back. This should not fail... 29062306a36Sopenharmony_ci */ 29162306a36Sopenharmony_ci if (live) 29262306a36Sopenharmony_ci WARN_ON(drv_add_interface(local, sdata)); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci return ret; 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic inline int identical_mac_addr_allowed(int type1, int type2) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci return type1 == NL80211_IFTYPE_MONITOR || 30062306a36Sopenharmony_ci type2 == NL80211_IFTYPE_MONITOR || 30162306a36Sopenharmony_ci type1 == NL80211_IFTYPE_P2P_DEVICE || 30262306a36Sopenharmony_ci type2 == NL80211_IFTYPE_P2P_DEVICE || 30362306a36Sopenharmony_ci (type1 == NL80211_IFTYPE_AP && type2 == NL80211_IFTYPE_AP_VLAN) || 30462306a36Sopenharmony_ci (type1 == NL80211_IFTYPE_AP_VLAN && 30562306a36Sopenharmony_ci (type2 == NL80211_IFTYPE_AP || 30662306a36Sopenharmony_ci type2 == NL80211_IFTYPE_AP_VLAN)); 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_cistatic int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata, 31062306a36Sopenharmony_ci enum nl80211_iftype iftype) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 31362306a36Sopenharmony_ci struct ieee80211_sub_if_data *nsdata; 31462306a36Sopenharmony_ci int ret; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci ASSERT_RTNL(); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci /* we hold the RTNL here so can safely walk the list */ 31962306a36Sopenharmony_ci list_for_each_entry(nsdata, &local->interfaces, list) { 32062306a36Sopenharmony_ci if (nsdata != sdata && ieee80211_sdata_running(nsdata)) { 32162306a36Sopenharmony_ci /* 32262306a36Sopenharmony_ci * Only OCB and monitor mode may coexist 32362306a36Sopenharmony_ci */ 32462306a36Sopenharmony_ci if ((sdata->vif.type == NL80211_IFTYPE_OCB && 32562306a36Sopenharmony_ci nsdata->vif.type != NL80211_IFTYPE_MONITOR) || 32662306a36Sopenharmony_ci (sdata->vif.type != NL80211_IFTYPE_MONITOR && 32762306a36Sopenharmony_ci nsdata->vif.type == NL80211_IFTYPE_OCB)) 32862306a36Sopenharmony_ci return -EBUSY; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci /* 33162306a36Sopenharmony_ci * Allow only a single IBSS interface to be up at any 33262306a36Sopenharmony_ci * time. This is restricted because beacon distribution 33362306a36Sopenharmony_ci * cannot work properly if both are in the same IBSS. 33462306a36Sopenharmony_ci * 33562306a36Sopenharmony_ci * To remove this restriction we'd have to disallow them 33662306a36Sopenharmony_ci * from setting the same SSID on different IBSS interfaces 33762306a36Sopenharmony_ci * belonging to the same hardware. Then, however, we're 33862306a36Sopenharmony_ci * faced with having to adopt two different TSF timers... 33962306a36Sopenharmony_ci */ 34062306a36Sopenharmony_ci if (iftype == NL80211_IFTYPE_ADHOC && 34162306a36Sopenharmony_ci nsdata->vif.type == NL80211_IFTYPE_ADHOC) 34262306a36Sopenharmony_ci return -EBUSY; 34362306a36Sopenharmony_ci /* 34462306a36Sopenharmony_ci * will not add another interface while any channel 34562306a36Sopenharmony_ci * switch is active. 34662306a36Sopenharmony_ci */ 34762306a36Sopenharmony_ci if (nsdata->vif.bss_conf.csa_active) 34862306a36Sopenharmony_ci return -EBUSY; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci /* 35162306a36Sopenharmony_ci * The remaining checks are only performed for interfaces 35262306a36Sopenharmony_ci * with the same MAC address. 35362306a36Sopenharmony_ci */ 35462306a36Sopenharmony_ci if (!ether_addr_equal(sdata->vif.addr, 35562306a36Sopenharmony_ci nsdata->vif.addr)) 35662306a36Sopenharmony_ci continue; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci /* 35962306a36Sopenharmony_ci * check whether it may have the same address 36062306a36Sopenharmony_ci */ 36162306a36Sopenharmony_ci if (!identical_mac_addr_allowed(iftype, 36262306a36Sopenharmony_ci nsdata->vif.type)) 36362306a36Sopenharmony_ci return -ENOTUNIQ; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci /* No support for VLAN with MLO yet */ 36662306a36Sopenharmony_ci if (iftype == NL80211_IFTYPE_AP_VLAN && 36762306a36Sopenharmony_ci sdata->wdev.use_4addr && 36862306a36Sopenharmony_ci nsdata->vif.type == NL80211_IFTYPE_AP && 36962306a36Sopenharmony_ci nsdata->vif.valid_links) 37062306a36Sopenharmony_ci return -EOPNOTSUPP; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci /* 37362306a36Sopenharmony_ci * can only add VLANs to enabled APs 37462306a36Sopenharmony_ci */ 37562306a36Sopenharmony_ci if (iftype == NL80211_IFTYPE_AP_VLAN && 37662306a36Sopenharmony_ci nsdata->vif.type == NL80211_IFTYPE_AP) 37762306a36Sopenharmony_ci sdata->bss = &nsdata->u.ap; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci mutex_lock(&local->chanctx_mtx); 38262306a36Sopenharmony_ci ret = ieee80211_check_combinations(sdata, NULL, 0, 0); 38362306a36Sopenharmony_ci mutex_unlock(&local->chanctx_mtx); 38462306a36Sopenharmony_ci return ret; 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic int ieee80211_check_queues(struct ieee80211_sub_if_data *sdata, 38862306a36Sopenharmony_ci enum nl80211_iftype iftype) 38962306a36Sopenharmony_ci{ 39062306a36Sopenharmony_ci int n_queues = sdata->local->hw.queues; 39162306a36Sopenharmony_ci int i; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci if (iftype == NL80211_IFTYPE_NAN) 39462306a36Sopenharmony_ci return 0; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if (iftype != NL80211_IFTYPE_P2P_DEVICE) { 39762306a36Sopenharmony_ci for (i = 0; i < IEEE80211_NUM_ACS; i++) { 39862306a36Sopenharmony_ci if (WARN_ON_ONCE(sdata->vif.hw_queue[i] == 39962306a36Sopenharmony_ci IEEE80211_INVAL_HW_QUEUE)) 40062306a36Sopenharmony_ci return -EINVAL; 40162306a36Sopenharmony_ci if (WARN_ON_ONCE(sdata->vif.hw_queue[i] >= 40262306a36Sopenharmony_ci n_queues)) 40362306a36Sopenharmony_ci return -EINVAL; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci if ((iftype != NL80211_IFTYPE_AP && 40862306a36Sopenharmony_ci iftype != NL80211_IFTYPE_P2P_GO && 40962306a36Sopenharmony_ci iftype != NL80211_IFTYPE_MESH_POINT) || 41062306a36Sopenharmony_ci !ieee80211_hw_check(&sdata->local->hw, QUEUE_CONTROL)) { 41162306a36Sopenharmony_ci sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE; 41262306a36Sopenharmony_ci return 0; 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci if (WARN_ON_ONCE(sdata->vif.cab_queue == IEEE80211_INVAL_HW_QUEUE)) 41662306a36Sopenharmony_ci return -EINVAL; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci if (WARN_ON_ONCE(sdata->vif.cab_queue >= n_queues)) 41962306a36Sopenharmony_ci return -EINVAL; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci return 0; 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cistatic int ieee80211_open(struct net_device *dev) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 42762306a36Sopenharmony_ci int err; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci /* fail early if user set an invalid address */ 43062306a36Sopenharmony_ci if (!is_valid_ether_addr(dev->dev_addr)) 43162306a36Sopenharmony_ci return -EADDRNOTAVAIL; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci err = ieee80211_check_concurrent_iface(sdata, sdata->vif.type); 43462306a36Sopenharmony_ci if (err) 43562306a36Sopenharmony_ci return err; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci wiphy_lock(sdata->local->hw.wiphy); 43862306a36Sopenharmony_ci err = ieee80211_do_open(&sdata->wdev, true); 43962306a36Sopenharmony_ci wiphy_unlock(sdata->local->hw.wiphy); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci return err; 44262306a36Sopenharmony_ci} 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_down) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 44762306a36Sopenharmony_ci unsigned long flags; 44862306a36Sopenharmony_ci struct sk_buff *skb, *tmp; 44962306a36Sopenharmony_ci u32 hw_reconf_flags = 0; 45062306a36Sopenharmony_ci int i, flushed; 45162306a36Sopenharmony_ci struct ps_data *ps; 45262306a36Sopenharmony_ci struct cfg80211_chan_def chandef; 45362306a36Sopenharmony_ci bool cancel_scan; 45462306a36Sopenharmony_ci struct cfg80211_nan_func *func; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci clear_bit(SDATA_STATE_RUNNING, &sdata->state); 45762306a36Sopenharmony_ci synchronize_rcu(); /* flush _ieee80211_wake_txqs() */ 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci cancel_scan = rcu_access_pointer(local->scan_sdata) == sdata; 46062306a36Sopenharmony_ci if (cancel_scan) 46162306a36Sopenharmony_ci ieee80211_scan_cancel(local); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci ieee80211_roc_purge(local, sdata); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci switch (sdata->vif.type) { 46662306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 46762306a36Sopenharmony_ci ieee80211_mgd_stop(sdata); 46862306a36Sopenharmony_ci break; 46962306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 47062306a36Sopenharmony_ci ieee80211_ibss_stop(sdata); 47162306a36Sopenharmony_ci break; 47262306a36Sopenharmony_ci case NL80211_IFTYPE_MONITOR: 47362306a36Sopenharmony_ci if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES) 47462306a36Sopenharmony_ci break; 47562306a36Sopenharmony_ci list_del_rcu(&sdata->u.mntr.list); 47662306a36Sopenharmony_ci break; 47762306a36Sopenharmony_ci default: 47862306a36Sopenharmony_ci break; 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci /* 48262306a36Sopenharmony_ci * Remove all stations associated with this interface. 48362306a36Sopenharmony_ci * 48462306a36Sopenharmony_ci * This must be done before calling ops->remove_interface() 48562306a36Sopenharmony_ci * because otherwise we can later invoke ops->sta_notify() 48662306a36Sopenharmony_ci * whenever the STAs are removed, and that invalidates driver 48762306a36Sopenharmony_ci * assumptions about always getting a vif pointer that is valid 48862306a36Sopenharmony_ci * (because if we remove a STA after ops->remove_interface() 48962306a36Sopenharmony_ci * the driver will have removed the vif info already!) 49062306a36Sopenharmony_ci * 49162306a36Sopenharmony_ci * For AP_VLANs stations may exist since there's nothing else that 49262306a36Sopenharmony_ci * would have removed them, but in other modes there shouldn't 49362306a36Sopenharmony_ci * be any stations. 49462306a36Sopenharmony_ci */ 49562306a36Sopenharmony_ci flushed = sta_info_flush(sdata); 49662306a36Sopenharmony_ci WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_AP_VLAN && flushed > 0); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci /* don't count this interface for allmulti while it is down */ 49962306a36Sopenharmony_ci if (sdata->flags & IEEE80211_SDATA_ALLMULTI) 50062306a36Sopenharmony_ci atomic_dec(&local->iff_allmultis); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_AP) { 50362306a36Sopenharmony_ci local->fif_pspoll--; 50462306a36Sopenharmony_ci local->fif_probe_req--; 50562306a36Sopenharmony_ci } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { 50662306a36Sopenharmony_ci local->fif_probe_req--; 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci if (sdata->dev) { 51062306a36Sopenharmony_ci netif_addr_lock_bh(sdata->dev); 51162306a36Sopenharmony_ci spin_lock_bh(&local->filter_lock); 51262306a36Sopenharmony_ci __hw_addr_unsync(&local->mc_list, &sdata->dev->mc, 51362306a36Sopenharmony_ci sdata->dev->addr_len); 51462306a36Sopenharmony_ci spin_unlock_bh(&local->filter_lock); 51562306a36Sopenharmony_ci netif_addr_unlock_bh(sdata->dev); 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci del_timer_sync(&local->dynamic_ps_timer); 51962306a36Sopenharmony_ci cancel_work_sync(&local->dynamic_ps_enable_work); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci cancel_work_sync(&sdata->recalc_smps); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci sdata_lock(sdata); 52462306a36Sopenharmony_ci WARN(ieee80211_vif_is_mld(&sdata->vif), 52562306a36Sopenharmony_ci "destroying interface with valid links 0x%04x\n", 52662306a36Sopenharmony_ci sdata->vif.valid_links); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci mutex_lock(&local->mtx); 52962306a36Sopenharmony_ci sdata->vif.bss_conf.csa_active = false; 53062306a36Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_STATION) 53162306a36Sopenharmony_ci sdata->deflink.u.mgd.csa_waiting_bcn = false; 53262306a36Sopenharmony_ci if (sdata->deflink.csa_block_tx) { 53362306a36Sopenharmony_ci ieee80211_wake_vif_queues(local, sdata, 53462306a36Sopenharmony_ci IEEE80211_QUEUE_STOP_REASON_CSA); 53562306a36Sopenharmony_ci sdata->deflink.csa_block_tx = false; 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci mutex_unlock(&local->mtx); 53862306a36Sopenharmony_ci sdata_unlock(sdata); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci cancel_work_sync(&sdata->deflink.csa_finalize_work); 54162306a36Sopenharmony_ci cancel_work_sync(&sdata->deflink.color_change_finalize_work); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci cancel_delayed_work_sync(&sdata->deflink.dfs_cac_timer_work); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci if (sdata->wdev.cac_started) { 54662306a36Sopenharmony_ci chandef = sdata->vif.bss_conf.chandef; 54762306a36Sopenharmony_ci WARN_ON(local->suspended); 54862306a36Sopenharmony_ci mutex_lock(&local->mtx); 54962306a36Sopenharmony_ci ieee80211_link_release_channel(&sdata->deflink); 55062306a36Sopenharmony_ci mutex_unlock(&local->mtx); 55162306a36Sopenharmony_ci cfg80211_cac_event(sdata->dev, &chandef, 55262306a36Sopenharmony_ci NL80211_RADAR_CAC_ABORTED, 55362306a36Sopenharmony_ci GFP_KERNEL); 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_AP) { 55762306a36Sopenharmony_ci WARN_ON(!list_empty(&sdata->u.ap.vlans)); 55862306a36Sopenharmony_ci } else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { 55962306a36Sopenharmony_ci /* remove all packets in parent bc_buf pointing to this dev */ 56062306a36Sopenharmony_ci ps = &sdata->bss->ps; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci spin_lock_irqsave(&ps->bc_buf.lock, flags); 56362306a36Sopenharmony_ci skb_queue_walk_safe(&ps->bc_buf, skb, tmp) { 56462306a36Sopenharmony_ci if (skb->dev == sdata->dev) { 56562306a36Sopenharmony_ci __skb_unlink(skb, &ps->bc_buf); 56662306a36Sopenharmony_ci local->total_ps_buffered--; 56762306a36Sopenharmony_ci ieee80211_free_txskb(&local->hw, skb); 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci spin_unlock_irqrestore(&ps->bc_buf.lock, flags); 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (going_down) 57462306a36Sopenharmony_ci local->open_count--; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci switch (sdata->vif.type) { 57762306a36Sopenharmony_ci case NL80211_IFTYPE_AP_VLAN: 57862306a36Sopenharmony_ci mutex_lock(&local->mtx); 57962306a36Sopenharmony_ci list_del(&sdata->u.vlan.list); 58062306a36Sopenharmony_ci mutex_unlock(&local->mtx); 58162306a36Sopenharmony_ci RCU_INIT_POINTER(sdata->vif.bss_conf.chanctx_conf, NULL); 58262306a36Sopenharmony_ci /* see comment in the default case below */ 58362306a36Sopenharmony_ci ieee80211_free_keys(sdata, true); 58462306a36Sopenharmony_ci /* no need to tell driver */ 58562306a36Sopenharmony_ci break; 58662306a36Sopenharmony_ci case NL80211_IFTYPE_MONITOR: 58762306a36Sopenharmony_ci if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES) { 58862306a36Sopenharmony_ci local->cooked_mntrs--; 58962306a36Sopenharmony_ci break; 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci local->monitors--; 59362306a36Sopenharmony_ci if (local->monitors == 0) { 59462306a36Sopenharmony_ci local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR; 59562306a36Sopenharmony_ci hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci ieee80211_adjust_monitor_flags(sdata, -1); 59962306a36Sopenharmony_ci break; 60062306a36Sopenharmony_ci case NL80211_IFTYPE_NAN: 60162306a36Sopenharmony_ci /* clean all the functions */ 60262306a36Sopenharmony_ci spin_lock_bh(&sdata->u.nan.func_lock); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci idr_for_each_entry(&sdata->u.nan.function_inst_ids, func, i) { 60562306a36Sopenharmony_ci idr_remove(&sdata->u.nan.function_inst_ids, i); 60662306a36Sopenharmony_ci cfg80211_free_nan_func(func); 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci idr_destroy(&sdata->u.nan.function_inst_ids); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci spin_unlock_bh(&sdata->u.nan.func_lock); 61162306a36Sopenharmony_ci break; 61262306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_DEVICE: 61362306a36Sopenharmony_ci /* relies on synchronize_rcu() below */ 61462306a36Sopenharmony_ci RCU_INIT_POINTER(local->p2p_sdata, NULL); 61562306a36Sopenharmony_ci fallthrough; 61662306a36Sopenharmony_ci default: 61762306a36Sopenharmony_ci wiphy_work_cancel(sdata->local->hw.wiphy, &sdata->work); 61862306a36Sopenharmony_ci /* 61962306a36Sopenharmony_ci * When we get here, the interface is marked down. 62062306a36Sopenharmony_ci * Free the remaining keys, if there are any 62162306a36Sopenharmony_ci * (which can happen in AP mode if userspace sets 62262306a36Sopenharmony_ci * keys before the interface is operating) 62362306a36Sopenharmony_ci * 62462306a36Sopenharmony_ci * Force the key freeing to always synchronize_net() 62562306a36Sopenharmony_ci * to wait for the RX path in case it is using this 62662306a36Sopenharmony_ci * interface enqueuing frames at this very time on 62762306a36Sopenharmony_ci * another CPU. 62862306a36Sopenharmony_ci */ 62962306a36Sopenharmony_ci ieee80211_free_keys(sdata, true); 63062306a36Sopenharmony_ci skb_queue_purge(&sdata->skb_queue); 63162306a36Sopenharmony_ci skb_queue_purge(&sdata->status_queue); 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 63562306a36Sopenharmony_ci for (i = 0; i < IEEE80211_MAX_QUEUES; i++) { 63662306a36Sopenharmony_ci skb_queue_walk_safe(&local->pending[i], skb, tmp) { 63762306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 63862306a36Sopenharmony_ci if (info->control.vif == &sdata->vif) { 63962306a36Sopenharmony_ci __skb_unlink(skb, &local->pending[i]); 64062306a36Sopenharmony_ci ieee80211_free_txskb(&local->hw, skb); 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci } 64462306a36Sopenharmony_ci spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 64762306a36Sopenharmony_ci ieee80211_txq_remove_vlan(local, sdata); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci sdata->bss = NULL; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci if (local->open_count == 0) 65262306a36Sopenharmony_ci ieee80211_clear_tx_pending(local); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci sdata->vif.bss_conf.beacon_int = 0; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci /* 65762306a36Sopenharmony_ci * If the interface goes down while suspended, presumably because 65862306a36Sopenharmony_ci * the device was unplugged and that happens before our resume, 65962306a36Sopenharmony_ci * then the driver is already unconfigured and the remainder of 66062306a36Sopenharmony_ci * this function isn't needed. 66162306a36Sopenharmony_ci * XXX: what about WoWLAN? If the device has software state, e.g. 66262306a36Sopenharmony_ci * memory allocated, it might expect teardown commands from 66362306a36Sopenharmony_ci * mac80211 here? 66462306a36Sopenharmony_ci */ 66562306a36Sopenharmony_ci if (local->suspended) { 66662306a36Sopenharmony_ci WARN_ON(local->wowlan); 66762306a36Sopenharmony_ci WARN_ON(rcu_access_pointer(local->monitor_sdata)); 66862306a36Sopenharmony_ci return; 66962306a36Sopenharmony_ci } 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci switch (sdata->vif.type) { 67262306a36Sopenharmony_ci case NL80211_IFTYPE_AP_VLAN: 67362306a36Sopenharmony_ci break; 67462306a36Sopenharmony_ci case NL80211_IFTYPE_MONITOR: 67562306a36Sopenharmony_ci if (local->monitors == 0) 67662306a36Sopenharmony_ci ieee80211_del_virtual_monitor(local); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci mutex_lock(&local->mtx); 67962306a36Sopenharmony_ci ieee80211_recalc_idle(local); 68062306a36Sopenharmony_ci mutex_unlock(&local->mtx); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE)) 68362306a36Sopenharmony_ci break; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci fallthrough; 68662306a36Sopenharmony_ci default: 68762306a36Sopenharmony_ci if (going_down) 68862306a36Sopenharmony_ci drv_remove_interface(local, sdata); 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci ieee80211_recalc_ps(local); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci if (cancel_scan) 69462306a36Sopenharmony_ci wiphy_delayed_work_flush(local->hw.wiphy, &local->scan_work); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci if (local->open_count == 0) { 69762306a36Sopenharmony_ci ieee80211_stop_device(local); 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci /* no reconfiguring after stop! */ 70062306a36Sopenharmony_ci return; 70162306a36Sopenharmony_ci } 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci /* do after stop to avoid reconfiguring when we stop anyway */ 70462306a36Sopenharmony_ci ieee80211_configure_filter(local); 70562306a36Sopenharmony_ci ieee80211_hw_config(local, hw_reconf_flags); 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci if (local->monitors == local->open_count) 70862306a36Sopenharmony_ci ieee80211_add_virtual_monitor(local); 70962306a36Sopenharmony_ci} 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_cistatic void ieee80211_stop_mbssid(struct ieee80211_sub_if_data *sdata) 71262306a36Sopenharmony_ci{ 71362306a36Sopenharmony_ci struct ieee80211_sub_if_data *tx_sdata, *non_tx_sdata, *tmp_sdata; 71462306a36Sopenharmony_ci struct ieee80211_vif *tx_vif = sdata->vif.mbssid_tx_vif; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci if (!tx_vif) 71762306a36Sopenharmony_ci return; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci tx_sdata = vif_to_sdata(tx_vif); 72062306a36Sopenharmony_ci sdata->vif.mbssid_tx_vif = NULL; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci list_for_each_entry_safe(non_tx_sdata, tmp_sdata, 72362306a36Sopenharmony_ci &tx_sdata->local->interfaces, list) { 72462306a36Sopenharmony_ci if (non_tx_sdata != sdata && non_tx_sdata != tx_sdata && 72562306a36Sopenharmony_ci non_tx_sdata->vif.mbssid_tx_vif == tx_vif && 72662306a36Sopenharmony_ci ieee80211_sdata_running(non_tx_sdata)) { 72762306a36Sopenharmony_ci non_tx_sdata->vif.mbssid_tx_vif = NULL; 72862306a36Sopenharmony_ci dev_close(non_tx_sdata->wdev.netdev); 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci if (sdata != tx_sdata && ieee80211_sdata_running(tx_sdata)) { 73362306a36Sopenharmony_ci tx_sdata->vif.mbssid_tx_vif = NULL; 73462306a36Sopenharmony_ci dev_close(tx_sdata->wdev.netdev); 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_cistatic int ieee80211_stop(struct net_device *dev) 73962306a36Sopenharmony_ci{ 74062306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci /* close dependent VLAN and MBSSID interfaces before locking wiphy */ 74362306a36Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_AP) { 74462306a36Sopenharmony_ci struct ieee80211_sub_if_data *vlan, *tmpsdata; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans, 74762306a36Sopenharmony_ci u.vlan.list) 74862306a36Sopenharmony_ci dev_close(vlan->dev); 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci ieee80211_stop_mbssid(sdata); 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci cancel_work_sync(&sdata->activate_links_work); 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci wiphy_lock(sdata->local->hw.wiphy); 75662306a36Sopenharmony_ci ieee80211_do_stop(sdata, true); 75762306a36Sopenharmony_ci wiphy_unlock(sdata->local->hw.wiphy); 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci return 0; 76062306a36Sopenharmony_ci} 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_cistatic void ieee80211_set_multicast_list(struct net_device *dev) 76362306a36Sopenharmony_ci{ 76462306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 76562306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 76662306a36Sopenharmony_ci int allmulti, sdata_allmulti; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci allmulti = !!(dev->flags & IFF_ALLMULTI); 76962306a36Sopenharmony_ci sdata_allmulti = !!(sdata->flags & IEEE80211_SDATA_ALLMULTI); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci if (allmulti != sdata_allmulti) { 77262306a36Sopenharmony_ci if (dev->flags & IFF_ALLMULTI) 77362306a36Sopenharmony_ci atomic_inc(&local->iff_allmultis); 77462306a36Sopenharmony_ci else 77562306a36Sopenharmony_ci atomic_dec(&local->iff_allmultis); 77662306a36Sopenharmony_ci sdata->flags ^= IEEE80211_SDATA_ALLMULTI; 77762306a36Sopenharmony_ci } 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci spin_lock_bh(&local->filter_lock); 78062306a36Sopenharmony_ci __hw_addr_sync(&local->mc_list, &dev->mc, dev->addr_len); 78162306a36Sopenharmony_ci spin_unlock_bh(&local->filter_lock); 78262306a36Sopenharmony_ci ieee80211_queue_work(&local->hw, &local->reconfig_filter); 78362306a36Sopenharmony_ci} 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci/* 78662306a36Sopenharmony_ci * Called when the netdev is removed or, by the code below, before 78762306a36Sopenharmony_ci * the interface type changes. 78862306a36Sopenharmony_ci */ 78962306a36Sopenharmony_cistatic void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci /* free extra data */ 79262306a36Sopenharmony_ci ieee80211_free_keys(sdata, false); 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci ieee80211_debugfs_remove_netdev(sdata); 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci ieee80211_destroy_frag_cache(&sdata->frags); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci if (ieee80211_vif_is_mesh(&sdata->vif)) 79962306a36Sopenharmony_ci ieee80211_mesh_teardown_sdata(sdata); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci ieee80211_vif_clear_links(sdata); 80262306a36Sopenharmony_ci ieee80211_link_stop(&sdata->deflink); 80362306a36Sopenharmony_ci} 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_cistatic void ieee80211_uninit(struct net_device *dev) 80662306a36Sopenharmony_ci{ 80762306a36Sopenharmony_ci ieee80211_teardown_sdata(IEEE80211_DEV_TO_SUB_IF(dev)); 80862306a36Sopenharmony_ci} 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_cistatic void 81162306a36Sopenharmony_ciieee80211_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) 81262306a36Sopenharmony_ci{ 81362306a36Sopenharmony_ci dev_fetch_sw_netstats(stats, dev->tstats); 81462306a36Sopenharmony_ci} 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_cistatic int ieee80211_netdev_setup_tc(struct net_device *dev, 81762306a36Sopenharmony_ci enum tc_setup_type type, void *type_data) 81862306a36Sopenharmony_ci{ 81962306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 82062306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci return drv_net_setup_tc(local, sdata, dev, type, type_data); 82362306a36Sopenharmony_ci} 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_cistatic const struct net_device_ops ieee80211_dataif_ops = { 82662306a36Sopenharmony_ci .ndo_open = ieee80211_open, 82762306a36Sopenharmony_ci .ndo_stop = ieee80211_stop, 82862306a36Sopenharmony_ci .ndo_uninit = ieee80211_uninit, 82962306a36Sopenharmony_ci .ndo_start_xmit = ieee80211_subif_start_xmit, 83062306a36Sopenharmony_ci .ndo_set_rx_mode = ieee80211_set_multicast_list, 83162306a36Sopenharmony_ci .ndo_set_mac_address = ieee80211_change_mac, 83262306a36Sopenharmony_ci .ndo_get_stats64 = ieee80211_get_stats64, 83362306a36Sopenharmony_ci .ndo_setup_tc = ieee80211_netdev_setup_tc, 83462306a36Sopenharmony_ci}; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_cistatic u16 ieee80211_monitor_select_queue(struct net_device *dev, 83762306a36Sopenharmony_ci struct sk_buff *skb, 83862306a36Sopenharmony_ci struct net_device *sb_dev) 83962306a36Sopenharmony_ci{ 84062306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 84162306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 84262306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 84362306a36Sopenharmony_ci struct ieee80211_hdr *hdr; 84462306a36Sopenharmony_ci int len_rthdr; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci if (local->hw.queues < IEEE80211_NUM_ACS) 84762306a36Sopenharmony_ci return 0; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci /* reset flags and info before parsing radiotap header */ 85062306a36Sopenharmony_ci memset(info, 0, sizeof(*info)); 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci if (!ieee80211_parse_tx_radiotap(skb, dev)) 85362306a36Sopenharmony_ci return 0; /* doesn't matter, frame will be dropped */ 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci len_rthdr = ieee80211_get_radiotap_len(skb->data); 85662306a36Sopenharmony_ci hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr); 85762306a36Sopenharmony_ci if (skb->len < len_rthdr + 2 || 85862306a36Sopenharmony_ci skb->len < len_rthdr + ieee80211_hdrlen(hdr->frame_control)) 85962306a36Sopenharmony_ci return 0; /* doesn't matter, frame will be dropped */ 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci return ieee80211_select_queue_80211(sdata, skb, hdr); 86262306a36Sopenharmony_ci} 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_cistatic const struct net_device_ops ieee80211_monitorif_ops = { 86562306a36Sopenharmony_ci .ndo_open = ieee80211_open, 86662306a36Sopenharmony_ci .ndo_stop = ieee80211_stop, 86762306a36Sopenharmony_ci .ndo_uninit = ieee80211_uninit, 86862306a36Sopenharmony_ci .ndo_start_xmit = ieee80211_monitor_start_xmit, 86962306a36Sopenharmony_ci .ndo_set_rx_mode = ieee80211_set_multicast_list, 87062306a36Sopenharmony_ci .ndo_set_mac_address = ieee80211_change_mac, 87162306a36Sopenharmony_ci .ndo_select_queue = ieee80211_monitor_select_queue, 87262306a36Sopenharmony_ci .ndo_get_stats64 = ieee80211_get_stats64, 87362306a36Sopenharmony_ci}; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_cistatic int ieee80211_netdev_fill_forward_path(struct net_device_path_ctx *ctx, 87662306a36Sopenharmony_ci struct net_device_path *path) 87762306a36Sopenharmony_ci{ 87862306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata; 87962306a36Sopenharmony_ci struct ieee80211_local *local; 88062306a36Sopenharmony_ci struct sta_info *sta; 88162306a36Sopenharmony_ci int ret = -ENOENT; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci sdata = IEEE80211_DEV_TO_SUB_IF(ctx->dev); 88462306a36Sopenharmony_ci local = sdata->local; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci if (!local->ops->net_fill_forward_path) 88762306a36Sopenharmony_ci return -EOPNOTSUPP; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci rcu_read_lock(); 89062306a36Sopenharmony_ci switch (sdata->vif.type) { 89162306a36Sopenharmony_ci case NL80211_IFTYPE_AP_VLAN: 89262306a36Sopenharmony_ci sta = rcu_dereference(sdata->u.vlan.sta); 89362306a36Sopenharmony_ci if (sta) 89462306a36Sopenharmony_ci break; 89562306a36Sopenharmony_ci if (sdata->wdev.use_4addr) 89662306a36Sopenharmony_ci goto out; 89762306a36Sopenharmony_ci if (is_multicast_ether_addr(ctx->daddr)) 89862306a36Sopenharmony_ci goto out; 89962306a36Sopenharmony_ci sta = sta_info_get_bss(sdata, ctx->daddr); 90062306a36Sopenharmony_ci break; 90162306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 90262306a36Sopenharmony_ci if (is_multicast_ether_addr(ctx->daddr)) 90362306a36Sopenharmony_ci goto out; 90462306a36Sopenharmony_ci sta = sta_info_get(sdata, ctx->daddr); 90562306a36Sopenharmony_ci break; 90662306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 90762306a36Sopenharmony_ci if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) { 90862306a36Sopenharmony_ci sta = sta_info_get(sdata, ctx->daddr); 90962306a36Sopenharmony_ci if (sta && test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { 91062306a36Sopenharmony_ci if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH)) 91162306a36Sopenharmony_ci goto out; 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci break; 91462306a36Sopenharmony_ci } 91562306a36Sopenharmony_ci } 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci sta = sta_info_get(sdata, sdata->deflink.u.mgd.bssid); 91862306a36Sopenharmony_ci break; 91962306a36Sopenharmony_ci default: 92062306a36Sopenharmony_ci goto out; 92162306a36Sopenharmony_ci } 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci if (!sta) 92462306a36Sopenharmony_ci goto out; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci ret = drv_net_fill_forward_path(local, sdata, &sta->sta, ctx, path); 92762306a36Sopenharmony_ciout: 92862306a36Sopenharmony_ci rcu_read_unlock(); 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci return ret; 93162306a36Sopenharmony_ci} 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_cistatic const struct net_device_ops ieee80211_dataif_8023_ops = { 93462306a36Sopenharmony_ci .ndo_open = ieee80211_open, 93562306a36Sopenharmony_ci .ndo_stop = ieee80211_stop, 93662306a36Sopenharmony_ci .ndo_uninit = ieee80211_uninit, 93762306a36Sopenharmony_ci .ndo_start_xmit = ieee80211_subif_start_xmit_8023, 93862306a36Sopenharmony_ci .ndo_set_rx_mode = ieee80211_set_multicast_list, 93962306a36Sopenharmony_ci .ndo_set_mac_address = ieee80211_change_mac, 94062306a36Sopenharmony_ci .ndo_get_stats64 = ieee80211_get_stats64, 94162306a36Sopenharmony_ci .ndo_fill_forward_path = ieee80211_netdev_fill_forward_path, 94262306a36Sopenharmony_ci .ndo_setup_tc = ieee80211_netdev_setup_tc, 94362306a36Sopenharmony_ci}; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_cistatic bool ieee80211_iftype_supports_hdr_offload(enum nl80211_iftype iftype) 94662306a36Sopenharmony_ci{ 94762306a36Sopenharmony_ci switch (iftype) { 94862306a36Sopenharmony_ci /* P2P GO and client are mapped to AP/STATION types */ 94962306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 95062306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 95162306a36Sopenharmony_ci return true; 95262306a36Sopenharmony_ci default: 95362306a36Sopenharmony_ci return false; 95462306a36Sopenharmony_ci } 95562306a36Sopenharmony_ci} 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_cistatic bool ieee80211_set_sdata_offload_flags(struct ieee80211_sub_if_data *sdata) 95862306a36Sopenharmony_ci{ 95962306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 96062306a36Sopenharmony_ci u32 flags; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci flags = sdata->vif.offload_flags; 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci if (ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD) && 96562306a36Sopenharmony_ci ieee80211_iftype_supports_hdr_offload(sdata->vif.type)) { 96662306a36Sopenharmony_ci flags |= IEEE80211_OFFLOAD_ENCAP_ENABLED; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_FRAG) && 96962306a36Sopenharmony_ci local->hw.wiphy->frag_threshold != (u32)-1) 97062306a36Sopenharmony_ci flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci if (local->monitors) 97362306a36Sopenharmony_ci flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED; 97462306a36Sopenharmony_ci } else { 97562306a36Sopenharmony_ci flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED; 97662306a36Sopenharmony_ci } 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci if (ieee80211_hw_check(&local->hw, SUPPORTS_RX_DECAP_OFFLOAD) && 97962306a36Sopenharmony_ci ieee80211_iftype_supports_hdr_offload(sdata->vif.type)) { 98062306a36Sopenharmony_ci flags |= IEEE80211_OFFLOAD_DECAP_ENABLED; 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci if (local->monitors && 98362306a36Sopenharmony_ci !ieee80211_hw_check(&local->hw, SUPPORTS_CONC_MON_RX_DECAP)) 98462306a36Sopenharmony_ci flags &= ~IEEE80211_OFFLOAD_DECAP_ENABLED; 98562306a36Sopenharmony_ci } else { 98662306a36Sopenharmony_ci flags &= ~IEEE80211_OFFLOAD_DECAP_ENABLED; 98762306a36Sopenharmony_ci } 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci if (sdata->vif.offload_flags == flags) 99062306a36Sopenharmony_ci return false; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci sdata->vif.offload_flags = flags; 99362306a36Sopenharmony_ci ieee80211_check_fast_rx_iface(sdata); 99462306a36Sopenharmony_ci return true; 99562306a36Sopenharmony_ci} 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_cistatic void ieee80211_set_vif_encap_ops(struct ieee80211_sub_if_data *sdata) 99862306a36Sopenharmony_ci{ 99962306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 100062306a36Sopenharmony_ci struct ieee80211_sub_if_data *bss = sdata; 100162306a36Sopenharmony_ci bool enabled; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { 100462306a36Sopenharmony_ci if (!sdata->bss) 100562306a36Sopenharmony_ci return; 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci bss = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap); 100862306a36Sopenharmony_ci } 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD) || 101162306a36Sopenharmony_ci !ieee80211_iftype_supports_hdr_offload(bss->vif.type)) 101262306a36Sopenharmony_ci return; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci enabled = bss->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED; 101562306a36Sopenharmony_ci if (sdata->wdev.use_4addr && 101662306a36Sopenharmony_ci !(bss->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_4ADDR)) 101762306a36Sopenharmony_ci enabled = false; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci sdata->dev->netdev_ops = enabled ? &ieee80211_dataif_8023_ops : 102062306a36Sopenharmony_ci &ieee80211_dataif_ops; 102162306a36Sopenharmony_ci} 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_cistatic void ieee80211_recalc_sdata_offload(struct ieee80211_sub_if_data *sdata) 102462306a36Sopenharmony_ci{ 102562306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 102662306a36Sopenharmony_ci struct ieee80211_sub_if_data *vsdata; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci if (ieee80211_set_sdata_offload_flags(sdata)) { 102962306a36Sopenharmony_ci drv_update_vif_offload(local, sdata); 103062306a36Sopenharmony_ci ieee80211_set_vif_encap_ops(sdata); 103162306a36Sopenharmony_ci } 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci list_for_each_entry(vsdata, &local->interfaces, list) { 103462306a36Sopenharmony_ci if (vsdata->vif.type != NL80211_IFTYPE_AP_VLAN || 103562306a36Sopenharmony_ci vsdata->bss != &sdata->u.ap) 103662306a36Sopenharmony_ci continue; 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci ieee80211_set_vif_encap_ops(vsdata); 103962306a36Sopenharmony_ci } 104062306a36Sopenharmony_ci} 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_civoid ieee80211_recalc_offload(struct ieee80211_local *local) 104362306a36Sopenharmony_ci{ 104462306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD)) 104762306a36Sopenharmony_ci return; 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci mutex_lock(&local->iflist_mtx); 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci list_for_each_entry(sdata, &local->interfaces, list) { 105262306a36Sopenharmony_ci if (!ieee80211_sdata_running(sdata)) 105362306a36Sopenharmony_ci continue; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci ieee80211_recalc_sdata_offload(sdata); 105662306a36Sopenharmony_ci } 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci mutex_unlock(&local->iflist_mtx); 105962306a36Sopenharmony_ci} 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_civoid ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, 106262306a36Sopenharmony_ci const int offset) 106362306a36Sopenharmony_ci{ 106462306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 106562306a36Sopenharmony_ci u32 flags = sdata->u.mntr.flags; 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci#define ADJUST(_f, _s) do { \ 106862306a36Sopenharmony_ci if (flags & MONITOR_FLAG_##_f) \ 106962306a36Sopenharmony_ci local->fif_##_s += offset; \ 107062306a36Sopenharmony_ci } while (0) 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci ADJUST(FCSFAIL, fcsfail); 107362306a36Sopenharmony_ci ADJUST(PLCPFAIL, plcpfail); 107462306a36Sopenharmony_ci ADJUST(CONTROL, control); 107562306a36Sopenharmony_ci ADJUST(CONTROL, pspoll); 107662306a36Sopenharmony_ci ADJUST(OTHER_BSS, other_bss); 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci#undef ADJUST 107962306a36Sopenharmony_ci} 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_cistatic void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata) 108262306a36Sopenharmony_ci{ 108362306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 108462306a36Sopenharmony_ci int i; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci for (i = 0; i < IEEE80211_NUM_ACS; i++) { 108762306a36Sopenharmony_ci if (ieee80211_hw_check(&local->hw, QUEUE_CONTROL)) 108862306a36Sopenharmony_ci sdata->vif.hw_queue[i] = IEEE80211_INVAL_HW_QUEUE; 108962306a36Sopenharmony_ci else if (local->hw.queues >= IEEE80211_NUM_ACS) 109062306a36Sopenharmony_ci sdata->vif.hw_queue[i] = i; 109162306a36Sopenharmony_ci else 109262306a36Sopenharmony_ci sdata->vif.hw_queue[i] = 0; 109362306a36Sopenharmony_ci } 109462306a36Sopenharmony_ci sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE; 109562306a36Sopenharmony_ci} 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_cistatic void ieee80211_sdata_init(struct ieee80211_local *local, 109862306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata) 109962306a36Sopenharmony_ci{ 110062306a36Sopenharmony_ci sdata->local = local; 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci /* 110362306a36Sopenharmony_ci * Initialize the default link, so we can use link_id 0 for non-MLD, 110462306a36Sopenharmony_ci * and that continues to work for non-MLD-aware drivers that use just 110562306a36Sopenharmony_ci * vif.bss_conf instead of vif.link_conf. 110662306a36Sopenharmony_ci * 110762306a36Sopenharmony_ci * Note that we never change this, so if link ID 0 isn't used in an 110862306a36Sopenharmony_ci * MLD connection, we get a separate allocation for it. 110962306a36Sopenharmony_ci */ 111062306a36Sopenharmony_ci ieee80211_link_init(sdata, -1, &sdata->deflink, &sdata->vif.bss_conf); 111162306a36Sopenharmony_ci} 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ciint ieee80211_add_virtual_monitor(struct ieee80211_local *local) 111462306a36Sopenharmony_ci{ 111562306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata; 111662306a36Sopenharmony_ci int ret; 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci if (!ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF)) 111962306a36Sopenharmony_ci return 0; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci ASSERT_RTNL(); 112262306a36Sopenharmony_ci lockdep_assert_wiphy(local->hw.wiphy); 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci if (local->monitor_sdata) 112562306a36Sopenharmony_ci return 0; 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL); 112862306a36Sopenharmony_ci if (!sdata) 112962306a36Sopenharmony_ci return -ENOMEM; 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci /* set up data */ 113262306a36Sopenharmony_ci sdata->vif.type = NL80211_IFTYPE_MONITOR; 113362306a36Sopenharmony_ci snprintf(sdata->name, IFNAMSIZ, "%s-monitor", 113462306a36Sopenharmony_ci wiphy_name(local->hw.wiphy)); 113562306a36Sopenharmony_ci sdata->wdev.iftype = NL80211_IFTYPE_MONITOR; 113662306a36Sopenharmony_ci mutex_init(&sdata->wdev.mtx); 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci ieee80211_sdata_init(local, sdata); 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci ieee80211_set_default_queues(sdata); 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci ret = drv_add_interface(local, sdata); 114362306a36Sopenharmony_ci if (WARN_ON(ret)) { 114462306a36Sopenharmony_ci /* ok .. stupid driver, it asked for this! */ 114562306a36Sopenharmony_ci kfree(sdata); 114662306a36Sopenharmony_ci return ret; 114762306a36Sopenharmony_ci } 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci set_bit(SDATA_STATE_RUNNING, &sdata->state); 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci ret = ieee80211_check_queues(sdata, NL80211_IFTYPE_MONITOR); 115262306a36Sopenharmony_ci if (ret) { 115362306a36Sopenharmony_ci kfree(sdata); 115462306a36Sopenharmony_ci return ret; 115562306a36Sopenharmony_ci } 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci mutex_lock(&local->iflist_mtx); 115862306a36Sopenharmony_ci rcu_assign_pointer(local->monitor_sdata, sdata); 115962306a36Sopenharmony_ci mutex_unlock(&local->iflist_mtx); 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci sdata_lock(sdata); 116262306a36Sopenharmony_ci mutex_lock(&local->mtx); 116362306a36Sopenharmony_ci ret = ieee80211_link_use_channel(&sdata->deflink, &local->monitor_chandef, 116462306a36Sopenharmony_ci IEEE80211_CHANCTX_EXCLUSIVE); 116562306a36Sopenharmony_ci mutex_unlock(&local->mtx); 116662306a36Sopenharmony_ci sdata_unlock(sdata); 116762306a36Sopenharmony_ci if (ret) { 116862306a36Sopenharmony_ci mutex_lock(&local->iflist_mtx); 116962306a36Sopenharmony_ci RCU_INIT_POINTER(local->monitor_sdata, NULL); 117062306a36Sopenharmony_ci mutex_unlock(&local->iflist_mtx); 117162306a36Sopenharmony_ci synchronize_net(); 117262306a36Sopenharmony_ci drv_remove_interface(local, sdata); 117362306a36Sopenharmony_ci mutex_destroy(&sdata->wdev.mtx); 117462306a36Sopenharmony_ci kfree(sdata); 117562306a36Sopenharmony_ci return ret; 117662306a36Sopenharmony_ci } 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci skb_queue_head_init(&sdata->skb_queue); 117962306a36Sopenharmony_ci skb_queue_head_init(&sdata->status_queue); 118062306a36Sopenharmony_ci wiphy_work_init(&sdata->work, ieee80211_iface_work); 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci return 0; 118362306a36Sopenharmony_ci} 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_civoid ieee80211_del_virtual_monitor(struct ieee80211_local *local) 118662306a36Sopenharmony_ci{ 118762306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata; 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci if (!ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF)) 119062306a36Sopenharmony_ci return; 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci ASSERT_RTNL(); 119362306a36Sopenharmony_ci lockdep_assert_wiphy(local->hw.wiphy); 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci mutex_lock(&local->iflist_mtx); 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci sdata = rcu_dereference_protected(local->monitor_sdata, 119862306a36Sopenharmony_ci lockdep_is_held(&local->iflist_mtx)); 119962306a36Sopenharmony_ci if (!sdata) { 120062306a36Sopenharmony_ci mutex_unlock(&local->iflist_mtx); 120162306a36Sopenharmony_ci return; 120262306a36Sopenharmony_ci } 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci RCU_INIT_POINTER(local->monitor_sdata, NULL); 120562306a36Sopenharmony_ci mutex_unlock(&local->iflist_mtx); 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci synchronize_net(); 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci sdata_lock(sdata); 121062306a36Sopenharmony_ci mutex_lock(&local->mtx); 121162306a36Sopenharmony_ci ieee80211_link_release_channel(&sdata->deflink); 121262306a36Sopenharmony_ci mutex_unlock(&local->mtx); 121362306a36Sopenharmony_ci sdata_unlock(sdata); 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci drv_remove_interface(local, sdata); 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci mutex_destroy(&sdata->wdev.mtx); 121862306a36Sopenharmony_ci kfree(sdata); 121962306a36Sopenharmony_ci} 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci/* 122262306a36Sopenharmony_ci * NOTE: Be very careful when changing this function, it must NOT return 122362306a36Sopenharmony_ci * an error on interface type changes that have been pre-checked, so most 122462306a36Sopenharmony_ci * checks should be in ieee80211_check_concurrent_iface. 122562306a36Sopenharmony_ci */ 122662306a36Sopenharmony_ciint ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) 122762306a36Sopenharmony_ci{ 122862306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); 122962306a36Sopenharmony_ci struct net_device *dev = wdev->netdev; 123062306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 123162306a36Sopenharmony_ci u64 changed = 0; 123262306a36Sopenharmony_ci int res; 123362306a36Sopenharmony_ci u32 hw_reconf_flags = 0; 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci switch (sdata->vif.type) { 123662306a36Sopenharmony_ci case NL80211_IFTYPE_AP_VLAN: { 123762306a36Sopenharmony_ci struct ieee80211_sub_if_data *master; 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci if (!sdata->bss) 124062306a36Sopenharmony_ci return -ENOLINK; 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci mutex_lock(&local->mtx); 124362306a36Sopenharmony_ci list_add(&sdata->u.vlan.list, &sdata->bss->vlans); 124462306a36Sopenharmony_ci mutex_unlock(&local->mtx); 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci master = container_of(sdata->bss, 124762306a36Sopenharmony_ci struct ieee80211_sub_if_data, u.ap); 124862306a36Sopenharmony_ci sdata->control_port_protocol = 124962306a36Sopenharmony_ci master->control_port_protocol; 125062306a36Sopenharmony_ci sdata->control_port_no_encrypt = 125162306a36Sopenharmony_ci master->control_port_no_encrypt; 125262306a36Sopenharmony_ci sdata->control_port_over_nl80211 = 125362306a36Sopenharmony_ci master->control_port_over_nl80211; 125462306a36Sopenharmony_ci sdata->control_port_no_preauth = 125562306a36Sopenharmony_ci master->control_port_no_preauth; 125662306a36Sopenharmony_ci sdata->vif.cab_queue = master->vif.cab_queue; 125762306a36Sopenharmony_ci memcpy(sdata->vif.hw_queue, master->vif.hw_queue, 125862306a36Sopenharmony_ci sizeof(sdata->vif.hw_queue)); 125962306a36Sopenharmony_ci sdata->vif.bss_conf.chandef = master->vif.bss_conf.chandef; 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci mutex_lock(&local->key_mtx); 126262306a36Sopenharmony_ci sdata->crypto_tx_tailroom_needed_cnt += 126362306a36Sopenharmony_ci master->crypto_tx_tailroom_needed_cnt; 126462306a36Sopenharmony_ci mutex_unlock(&local->key_mtx); 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci break; 126762306a36Sopenharmony_ci } 126862306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 126962306a36Sopenharmony_ci sdata->bss = &sdata->u.ap; 127062306a36Sopenharmony_ci break; 127162306a36Sopenharmony_ci case NL80211_IFTYPE_MESH_POINT: 127262306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 127362306a36Sopenharmony_ci case NL80211_IFTYPE_MONITOR: 127462306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 127562306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_DEVICE: 127662306a36Sopenharmony_ci case NL80211_IFTYPE_OCB: 127762306a36Sopenharmony_ci case NL80211_IFTYPE_NAN: 127862306a36Sopenharmony_ci /* no special treatment */ 127962306a36Sopenharmony_ci break; 128062306a36Sopenharmony_ci case NL80211_IFTYPE_UNSPECIFIED: 128162306a36Sopenharmony_ci case NUM_NL80211_IFTYPES: 128262306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_CLIENT: 128362306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_GO: 128462306a36Sopenharmony_ci case NL80211_IFTYPE_WDS: 128562306a36Sopenharmony_ci /* cannot happen */ 128662306a36Sopenharmony_ci WARN_ON(1); 128762306a36Sopenharmony_ci break; 128862306a36Sopenharmony_ci } 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci if (local->open_count == 0) { 129162306a36Sopenharmony_ci /* here we can consider everything in good order (again) */ 129262306a36Sopenharmony_ci local->reconfig_failure = false; 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci res = drv_start(local); 129562306a36Sopenharmony_ci if (res) 129662306a36Sopenharmony_ci goto err_del_bss; 129762306a36Sopenharmony_ci /* we're brought up, everything changes */ 129862306a36Sopenharmony_ci hw_reconf_flags = ~0; 129962306a36Sopenharmony_ci ieee80211_led_radio(local, true); 130062306a36Sopenharmony_ci ieee80211_mod_tpt_led_trig(local, 130162306a36Sopenharmony_ci IEEE80211_TPT_LEDTRIG_FL_RADIO, 0); 130262306a36Sopenharmony_ci } 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci /* 130562306a36Sopenharmony_ci * Copy the hopefully now-present MAC address to 130662306a36Sopenharmony_ci * this interface, if it has the special null one. 130762306a36Sopenharmony_ci */ 130862306a36Sopenharmony_ci if (dev && is_zero_ether_addr(dev->dev_addr)) { 130962306a36Sopenharmony_ci eth_hw_addr_set(dev, local->hw.wiphy->perm_addr); 131062306a36Sopenharmony_ci memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN); 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci if (!is_valid_ether_addr(dev->dev_addr)) { 131362306a36Sopenharmony_ci res = -EADDRNOTAVAIL; 131462306a36Sopenharmony_ci goto err_stop; 131562306a36Sopenharmony_ci } 131662306a36Sopenharmony_ci } 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci switch (sdata->vif.type) { 131962306a36Sopenharmony_ci case NL80211_IFTYPE_AP_VLAN: 132062306a36Sopenharmony_ci /* no need to tell driver, but set carrier and chanctx */ 132162306a36Sopenharmony_ci if (sdata->bss->active) { 132262306a36Sopenharmony_ci ieee80211_link_vlan_copy_chanctx(&sdata->deflink); 132362306a36Sopenharmony_ci netif_carrier_on(dev); 132462306a36Sopenharmony_ci ieee80211_set_vif_encap_ops(sdata); 132562306a36Sopenharmony_ci } else { 132662306a36Sopenharmony_ci netif_carrier_off(dev); 132762306a36Sopenharmony_ci } 132862306a36Sopenharmony_ci break; 132962306a36Sopenharmony_ci case NL80211_IFTYPE_MONITOR: 133062306a36Sopenharmony_ci if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES) { 133162306a36Sopenharmony_ci local->cooked_mntrs++; 133262306a36Sopenharmony_ci break; 133362306a36Sopenharmony_ci } 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci if (sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) { 133662306a36Sopenharmony_ci res = drv_add_interface(local, sdata); 133762306a36Sopenharmony_ci if (res) 133862306a36Sopenharmony_ci goto err_stop; 133962306a36Sopenharmony_ci } else if (local->monitors == 0 && local->open_count == 0) { 134062306a36Sopenharmony_ci res = ieee80211_add_virtual_monitor(local); 134162306a36Sopenharmony_ci if (res) 134262306a36Sopenharmony_ci goto err_stop; 134362306a36Sopenharmony_ci } 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci /* must be before the call to ieee80211_configure_filter */ 134662306a36Sopenharmony_ci local->monitors++; 134762306a36Sopenharmony_ci if (local->monitors == 1) { 134862306a36Sopenharmony_ci local->hw.conf.flags |= IEEE80211_CONF_MONITOR; 134962306a36Sopenharmony_ci hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; 135062306a36Sopenharmony_ci } 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci ieee80211_adjust_monitor_flags(sdata, 1); 135362306a36Sopenharmony_ci ieee80211_configure_filter(local); 135462306a36Sopenharmony_ci ieee80211_recalc_offload(local); 135562306a36Sopenharmony_ci mutex_lock(&local->mtx); 135662306a36Sopenharmony_ci ieee80211_recalc_idle(local); 135762306a36Sopenharmony_ci mutex_unlock(&local->mtx); 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci netif_carrier_on(dev); 136062306a36Sopenharmony_ci break; 136162306a36Sopenharmony_ci default: 136262306a36Sopenharmony_ci if (coming_up) { 136362306a36Sopenharmony_ci ieee80211_del_virtual_monitor(local); 136462306a36Sopenharmony_ci ieee80211_set_sdata_offload_flags(sdata); 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci res = drv_add_interface(local, sdata); 136762306a36Sopenharmony_ci if (res) 136862306a36Sopenharmony_ci goto err_stop; 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci ieee80211_set_vif_encap_ops(sdata); 137162306a36Sopenharmony_ci res = ieee80211_check_queues(sdata, 137262306a36Sopenharmony_ci ieee80211_vif_type_p2p(&sdata->vif)); 137362306a36Sopenharmony_ci if (res) 137462306a36Sopenharmony_ci goto err_del_interface; 137562306a36Sopenharmony_ci } 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_AP) { 137862306a36Sopenharmony_ci local->fif_pspoll++; 137962306a36Sopenharmony_ci local->fif_probe_req++; 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci ieee80211_configure_filter(local); 138262306a36Sopenharmony_ci } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { 138362306a36Sopenharmony_ci local->fif_probe_req++; 138462306a36Sopenharmony_ci } 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci if (sdata->vif.probe_req_reg) 138762306a36Sopenharmony_ci drv_config_iface_filter(local, sdata, 138862306a36Sopenharmony_ci FIF_PROBE_REQ, 138962306a36Sopenharmony_ci FIF_PROBE_REQ); 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && 139262306a36Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_NAN) 139362306a36Sopenharmony_ci changed |= ieee80211_reset_erp_info(sdata); 139462306a36Sopenharmony_ci ieee80211_link_info_change_notify(sdata, &sdata->deflink, 139562306a36Sopenharmony_ci changed); 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci switch (sdata->vif.type) { 139862306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 139962306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 140062306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 140162306a36Sopenharmony_ci case NL80211_IFTYPE_MESH_POINT: 140262306a36Sopenharmony_ci case NL80211_IFTYPE_OCB: 140362306a36Sopenharmony_ci netif_carrier_off(dev); 140462306a36Sopenharmony_ci break; 140562306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_DEVICE: 140662306a36Sopenharmony_ci case NL80211_IFTYPE_NAN: 140762306a36Sopenharmony_ci break; 140862306a36Sopenharmony_ci default: 140962306a36Sopenharmony_ci /* not reached */ 141062306a36Sopenharmony_ci WARN_ON(1); 141162306a36Sopenharmony_ci } 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci /* 141462306a36Sopenharmony_ci * Set default queue parameters so drivers don't 141562306a36Sopenharmony_ci * need to initialise the hardware if the hardware 141662306a36Sopenharmony_ci * doesn't start up with sane defaults. 141762306a36Sopenharmony_ci * Enable QoS for anything but station interfaces. 141862306a36Sopenharmony_ci */ 141962306a36Sopenharmony_ci ieee80211_set_wmm_default(&sdata->deflink, true, 142062306a36Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_STATION); 142162306a36Sopenharmony_ci } 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci switch (sdata->vif.type) { 142462306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_DEVICE: 142562306a36Sopenharmony_ci rcu_assign_pointer(local->p2p_sdata, sdata); 142662306a36Sopenharmony_ci break; 142762306a36Sopenharmony_ci case NL80211_IFTYPE_MONITOR: 142862306a36Sopenharmony_ci if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES) 142962306a36Sopenharmony_ci break; 143062306a36Sopenharmony_ci list_add_tail_rcu(&sdata->u.mntr.list, &local->mon_list); 143162306a36Sopenharmony_ci break; 143262306a36Sopenharmony_ci default: 143362306a36Sopenharmony_ci break; 143462306a36Sopenharmony_ci } 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci /* 143762306a36Sopenharmony_ci * set_multicast_list will be invoked by the networking core 143862306a36Sopenharmony_ci * which will check whether any increments here were done in 143962306a36Sopenharmony_ci * error and sync them down to the hardware as filter flags. 144062306a36Sopenharmony_ci */ 144162306a36Sopenharmony_ci if (sdata->flags & IEEE80211_SDATA_ALLMULTI) 144262306a36Sopenharmony_ci atomic_inc(&local->iff_allmultis); 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci if (coming_up) 144562306a36Sopenharmony_ci local->open_count++; 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci if (hw_reconf_flags) 144862306a36Sopenharmony_ci ieee80211_hw_config(local, hw_reconf_flags); 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci ieee80211_recalc_ps(local); 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci set_bit(SDATA_STATE_RUNNING, &sdata->state); 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci return 0; 145562306a36Sopenharmony_ci err_del_interface: 145662306a36Sopenharmony_ci drv_remove_interface(local, sdata); 145762306a36Sopenharmony_ci err_stop: 145862306a36Sopenharmony_ci if (!local->open_count) 145962306a36Sopenharmony_ci drv_stop(local); 146062306a36Sopenharmony_ci err_del_bss: 146162306a36Sopenharmony_ci sdata->bss = NULL; 146262306a36Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { 146362306a36Sopenharmony_ci mutex_lock(&local->mtx); 146462306a36Sopenharmony_ci list_del(&sdata->u.vlan.list); 146562306a36Sopenharmony_ci mutex_unlock(&local->mtx); 146662306a36Sopenharmony_ci } 146762306a36Sopenharmony_ci /* might already be clear but that doesn't matter */ 146862306a36Sopenharmony_ci clear_bit(SDATA_STATE_RUNNING, &sdata->state); 146962306a36Sopenharmony_ci return res; 147062306a36Sopenharmony_ci} 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_cistatic void ieee80211_if_free(struct net_device *dev) 147362306a36Sopenharmony_ci{ 147462306a36Sopenharmony_ci free_percpu(dev->tstats); 147562306a36Sopenharmony_ci} 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_cistatic void ieee80211_if_setup(struct net_device *dev) 147862306a36Sopenharmony_ci{ 147962306a36Sopenharmony_ci ether_setup(dev); 148062306a36Sopenharmony_ci dev->priv_flags &= ~IFF_TX_SKB_SHARING; 148162306a36Sopenharmony_ci dev->priv_flags |= IFF_NO_QUEUE; 148262306a36Sopenharmony_ci dev->netdev_ops = &ieee80211_dataif_ops; 148362306a36Sopenharmony_ci dev->needs_free_netdev = true; 148462306a36Sopenharmony_ci dev->priv_destructor = ieee80211_if_free; 148562306a36Sopenharmony_ci} 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_cistatic void ieee80211_iface_process_skb(struct ieee80211_local *local, 148862306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata, 148962306a36Sopenharmony_ci struct sk_buff *skb) 149062306a36Sopenharmony_ci{ 149162306a36Sopenharmony_ci struct ieee80211_mgmt *mgmt = (void *)skb->data; 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci if (ieee80211_is_action(mgmt->frame_control) && 149462306a36Sopenharmony_ci mgmt->u.action.category == WLAN_CATEGORY_BACK) { 149562306a36Sopenharmony_ci struct sta_info *sta; 149662306a36Sopenharmony_ci int len = skb->len; 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci mutex_lock(&local->sta_mtx); 149962306a36Sopenharmony_ci sta = sta_info_get_bss(sdata, mgmt->sa); 150062306a36Sopenharmony_ci if (sta) { 150162306a36Sopenharmony_ci switch (mgmt->u.action.u.addba_req.action_code) { 150262306a36Sopenharmony_ci case WLAN_ACTION_ADDBA_REQ: 150362306a36Sopenharmony_ci ieee80211_process_addba_request(local, sta, 150462306a36Sopenharmony_ci mgmt, len); 150562306a36Sopenharmony_ci break; 150662306a36Sopenharmony_ci case WLAN_ACTION_ADDBA_RESP: 150762306a36Sopenharmony_ci ieee80211_process_addba_resp(local, sta, 150862306a36Sopenharmony_ci mgmt, len); 150962306a36Sopenharmony_ci break; 151062306a36Sopenharmony_ci case WLAN_ACTION_DELBA: 151162306a36Sopenharmony_ci ieee80211_process_delba(sdata, sta, 151262306a36Sopenharmony_ci mgmt, len); 151362306a36Sopenharmony_ci break; 151462306a36Sopenharmony_ci default: 151562306a36Sopenharmony_ci WARN_ON(1); 151662306a36Sopenharmony_ci break; 151762306a36Sopenharmony_ci } 151862306a36Sopenharmony_ci } 151962306a36Sopenharmony_ci mutex_unlock(&local->sta_mtx); 152062306a36Sopenharmony_ci } else if (ieee80211_is_action(mgmt->frame_control) && 152162306a36Sopenharmony_ci mgmt->u.action.category == WLAN_CATEGORY_VHT) { 152262306a36Sopenharmony_ci switch (mgmt->u.action.u.vht_group_notif.action_code) { 152362306a36Sopenharmony_ci case WLAN_VHT_ACTION_OPMODE_NOTIF: { 152462306a36Sopenharmony_ci struct ieee80211_rx_status *status; 152562306a36Sopenharmony_ci enum nl80211_band band; 152662306a36Sopenharmony_ci struct sta_info *sta; 152762306a36Sopenharmony_ci u8 opmode; 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci status = IEEE80211_SKB_RXCB(skb); 153062306a36Sopenharmony_ci band = status->band; 153162306a36Sopenharmony_ci opmode = mgmt->u.action.u.vht_opmode_notif.operating_mode; 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci mutex_lock(&local->sta_mtx); 153462306a36Sopenharmony_ci sta = sta_info_get_bss(sdata, mgmt->sa); 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci if (sta) 153762306a36Sopenharmony_ci ieee80211_vht_handle_opmode(sdata, 153862306a36Sopenharmony_ci &sta->deflink, 153962306a36Sopenharmony_ci opmode, band); 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci mutex_unlock(&local->sta_mtx); 154262306a36Sopenharmony_ci break; 154362306a36Sopenharmony_ci } 154462306a36Sopenharmony_ci case WLAN_VHT_ACTION_GROUPID_MGMT: 154562306a36Sopenharmony_ci ieee80211_process_mu_groups(sdata, &sdata->deflink, 154662306a36Sopenharmony_ci mgmt); 154762306a36Sopenharmony_ci break; 154862306a36Sopenharmony_ci default: 154962306a36Sopenharmony_ci WARN_ON(1); 155062306a36Sopenharmony_ci break; 155162306a36Sopenharmony_ci } 155262306a36Sopenharmony_ci } else if (ieee80211_is_action(mgmt->frame_control) && 155362306a36Sopenharmony_ci mgmt->u.action.category == WLAN_CATEGORY_S1G) { 155462306a36Sopenharmony_ci switch (mgmt->u.action.u.s1g.action_code) { 155562306a36Sopenharmony_ci case WLAN_S1G_TWT_TEARDOWN: 155662306a36Sopenharmony_ci case WLAN_S1G_TWT_SETUP: 155762306a36Sopenharmony_ci ieee80211_s1g_rx_twt_action(sdata, skb); 155862306a36Sopenharmony_ci break; 155962306a36Sopenharmony_ci default: 156062306a36Sopenharmony_ci break; 156162306a36Sopenharmony_ci } 156262306a36Sopenharmony_ci } else if (ieee80211_is_ext(mgmt->frame_control)) { 156362306a36Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_STATION) 156462306a36Sopenharmony_ci ieee80211_sta_rx_queued_ext(sdata, skb); 156562306a36Sopenharmony_ci else 156662306a36Sopenharmony_ci WARN_ON(1); 156762306a36Sopenharmony_ci } else if (ieee80211_is_data_qos(mgmt->frame_control)) { 156862306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (void *)mgmt; 156962306a36Sopenharmony_ci struct sta_info *sta; 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci /* 157262306a36Sopenharmony_ci * So the frame isn't mgmt, but frame_control 157362306a36Sopenharmony_ci * is at the right place anyway, of course, so 157462306a36Sopenharmony_ci * the if statement is correct. 157562306a36Sopenharmony_ci * 157662306a36Sopenharmony_ci * Warn if we have other data frame types here, 157762306a36Sopenharmony_ci * they must not get here. 157862306a36Sopenharmony_ci */ 157962306a36Sopenharmony_ci WARN_ON(hdr->frame_control & 158062306a36Sopenharmony_ci cpu_to_le16(IEEE80211_STYPE_NULLFUNC)); 158162306a36Sopenharmony_ci WARN_ON(!(hdr->seq_ctrl & 158262306a36Sopenharmony_ci cpu_to_le16(IEEE80211_SCTL_FRAG))); 158362306a36Sopenharmony_ci /* 158462306a36Sopenharmony_ci * This was a fragment of a frame, received while 158562306a36Sopenharmony_ci * a block-ack session was active. That cannot be 158662306a36Sopenharmony_ci * right, so terminate the session. 158762306a36Sopenharmony_ci */ 158862306a36Sopenharmony_ci mutex_lock(&local->sta_mtx); 158962306a36Sopenharmony_ci sta = sta_info_get_bss(sdata, mgmt->sa); 159062306a36Sopenharmony_ci if (sta) { 159162306a36Sopenharmony_ci u16 tid = ieee80211_get_tid(hdr); 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci __ieee80211_stop_rx_ba_session( 159462306a36Sopenharmony_ci sta, tid, WLAN_BACK_RECIPIENT, 159562306a36Sopenharmony_ci WLAN_REASON_QSTA_REQUIRE_SETUP, 159662306a36Sopenharmony_ci true); 159762306a36Sopenharmony_ci } 159862306a36Sopenharmony_ci mutex_unlock(&local->sta_mtx); 159962306a36Sopenharmony_ci } else switch (sdata->vif.type) { 160062306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 160162306a36Sopenharmony_ci ieee80211_sta_rx_queued_mgmt(sdata, skb); 160262306a36Sopenharmony_ci break; 160362306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 160462306a36Sopenharmony_ci ieee80211_ibss_rx_queued_mgmt(sdata, skb); 160562306a36Sopenharmony_ci break; 160662306a36Sopenharmony_ci case NL80211_IFTYPE_MESH_POINT: 160762306a36Sopenharmony_ci if (!ieee80211_vif_is_mesh(&sdata->vif)) 160862306a36Sopenharmony_ci break; 160962306a36Sopenharmony_ci ieee80211_mesh_rx_queued_mgmt(sdata, skb); 161062306a36Sopenharmony_ci break; 161162306a36Sopenharmony_ci default: 161262306a36Sopenharmony_ci WARN(1, "frame for unexpected interface type"); 161362306a36Sopenharmony_ci break; 161462306a36Sopenharmony_ci } 161562306a36Sopenharmony_ci} 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_cistatic void ieee80211_iface_process_status(struct ieee80211_sub_if_data *sdata, 161862306a36Sopenharmony_ci struct sk_buff *skb) 161962306a36Sopenharmony_ci{ 162062306a36Sopenharmony_ci struct ieee80211_mgmt *mgmt = (void *)skb->data; 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci if (ieee80211_is_action(mgmt->frame_control) && 162362306a36Sopenharmony_ci mgmt->u.action.category == WLAN_CATEGORY_S1G) { 162462306a36Sopenharmony_ci switch (mgmt->u.action.u.s1g.action_code) { 162562306a36Sopenharmony_ci case WLAN_S1G_TWT_TEARDOWN: 162662306a36Sopenharmony_ci case WLAN_S1G_TWT_SETUP: 162762306a36Sopenharmony_ci ieee80211_s1g_status_twt_action(sdata, skb); 162862306a36Sopenharmony_ci break; 162962306a36Sopenharmony_ci default: 163062306a36Sopenharmony_ci break; 163162306a36Sopenharmony_ci } 163262306a36Sopenharmony_ci } 163362306a36Sopenharmony_ci} 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_cistatic void ieee80211_iface_work(struct wiphy *wiphy, struct wiphy_work *work) 163662306a36Sopenharmony_ci{ 163762306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata = 163862306a36Sopenharmony_ci container_of(work, struct ieee80211_sub_if_data, work); 163962306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 164062306a36Sopenharmony_ci struct sk_buff *skb; 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci if (!ieee80211_sdata_running(sdata)) 164362306a36Sopenharmony_ci return; 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci if (test_bit(SCAN_SW_SCANNING, &local->scanning)) 164662306a36Sopenharmony_ci return; 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci if (!ieee80211_can_run_worker(local)) 164962306a36Sopenharmony_ci return; 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci /* first process frames */ 165262306a36Sopenharmony_ci while ((skb = skb_dequeue(&sdata->skb_queue))) { 165362306a36Sopenharmony_ci kcov_remote_start_common(skb_get_kcov_handle(skb)); 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ci if (skb->protocol == cpu_to_be16(ETH_P_TDLS)) 165662306a36Sopenharmony_ci ieee80211_process_tdls_channel_switch(sdata, skb); 165762306a36Sopenharmony_ci else 165862306a36Sopenharmony_ci ieee80211_iface_process_skb(local, sdata, skb); 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_ci kfree_skb(skb); 166162306a36Sopenharmony_ci kcov_remote_stop(); 166262306a36Sopenharmony_ci } 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ci /* process status queue */ 166562306a36Sopenharmony_ci while ((skb = skb_dequeue(&sdata->status_queue))) { 166662306a36Sopenharmony_ci kcov_remote_start_common(skb_get_kcov_handle(skb)); 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_ci ieee80211_iface_process_status(sdata, skb); 166962306a36Sopenharmony_ci kfree_skb(skb); 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci kcov_remote_stop(); 167262306a36Sopenharmony_ci } 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci /* then other type-dependent work */ 167562306a36Sopenharmony_ci switch (sdata->vif.type) { 167662306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 167762306a36Sopenharmony_ci ieee80211_sta_work(sdata); 167862306a36Sopenharmony_ci break; 167962306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 168062306a36Sopenharmony_ci ieee80211_ibss_work(sdata); 168162306a36Sopenharmony_ci break; 168262306a36Sopenharmony_ci case NL80211_IFTYPE_MESH_POINT: 168362306a36Sopenharmony_ci if (!ieee80211_vif_is_mesh(&sdata->vif)) 168462306a36Sopenharmony_ci break; 168562306a36Sopenharmony_ci ieee80211_mesh_work(sdata); 168662306a36Sopenharmony_ci break; 168762306a36Sopenharmony_ci case NL80211_IFTYPE_OCB: 168862306a36Sopenharmony_ci ieee80211_ocb_work(sdata); 168962306a36Sopenharmony_ci break; 169062306a36Sopenharmony_ci default: 169162306a36Sopenharmony_ci break; 169262306a36Sopenharmony_ci } 169362306a36Sopenharmony_ci} 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_cistatic void ieee80211_recalc_smps_work(struct work_struct *work) 169662306a36Sopenharmony_ci{ 169762306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata = 169862306a36Sopenharmony_ci container_of(work, struct ieee80211_sub_if_data, recalc_smps); 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci ieee80211_recalc_smps(sdata, &sdata->deflink); 170162306a36Sopenharmony_ci} 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_cistatic void ieee80211_activate_links_work(struct work_struct *work) 170462306a36Sopenharmony_ci{ 170562306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata = 170662306a36Sopenharmony_ci container_of(work, struct ieee80211_sub_if_data, 170762306a36Sopenharmony_ci activate_links_work); 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci ieee80211_set_active_links(&sdata->vif, sdata->desired_active_links); 171062306a36Sopenharmony_ci} 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci/* 171362306a36Sopenharmony_ci * Helper function to initialise an interface to a specific type. 171462306a36Sopenharmony_ci */ 171562306a36Sopenharmony_cistatic void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, 171662306a36Sopenharmony_ci enum nl80211_iftype type) 171762306a36Sopenharmony_ci{ 171862306a36Sopenharmony_ci static const u8 bssid_wildcard[ETH_ALEN] = {0xff, 0xff, 0xff, 171962306a36Sopenharmony_ci 0xff, 0xff, 0xff}; 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci /* clear type-dependent unions */ 172262306a36Sopenharmony_ci memset(&sdata->u, 0, sizeof(sdata->u)); 172362306a36Sopenharmony_ci memset(&sdata->deflink.u, 0, sizeof(sdata->deflink.u)); 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci /* and set some type-dependent values */ 172662306a36Sopenharmony_ci sdata->vif.type = type; 172762306a36Sopenharmony_ci sdata->vif.p2p = false; 172862306a36Sopenharmony_ci sdata->wdev.iftype = type; 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ci sdata->control_port_protocol = cpu_to_be16(ETH_P_PAE); 173162306a36Sopenharmony_ci sdata->control_port_no_encrypt = false; 173262306a36Sopenharmony_ci sdata->control_port_over_nl80211 = false; 173362306a36Sopenharmony_ci sdata->control_port_no_preauth = false; 173462306a36Sopenharmony_ci sdata->vif.cfg.idle = true; 173562306a36Sopenharmony_ci sdata->vif.bss_conf.txpower = INT_MIN; /* unset */ 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci sdata->noack_map = 0; 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_ci /* only monitor/p2p-device differ */ 174062306a36Sopenharmony_ci if (sdata->dev) { 174162306a36Sopenharmony_ci sdata->dev->netdev_ops = &ieee80211_dataif_ops; 174262306a36Sopenharmony_ci sdata->dev->type = ARPHRD_ETHER; 174362306a36Sopenharmony_ci } 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci skb_queue_head_init(&sdata->skb_queue); 174662306a36Sopenharmony_ci skb_queue_head_init(&sdata->status_queue); 174762306a36Sopenharmony_ci wiphy_work_init(&sdata->work, ieee80211_iface_work); 174862306a36Sopenharmony_ci INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work); 174962306a36Sopenharmony_ci INIT_WORK(&sdata->activate_links_work, ieee80211_activate_links_work); 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ci switch (type) { 175262306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_GO: 175362306a36Sopenharmony_ci type = NL80211_IFTYPE_AP; 175462306a36Sopenharmony_ci sdata->vif.type = type; 175562306a36Sopenharmony_ci sdata->vif.p2p = true; 175662306a36Sopenharmony_ci fallthrough; 175762306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 175862306a36Sopenharmony_ci skb_queue_head_init(&sdata->u.ap.ps.bc_buf); 175962306a36Sopenharmony_ci INIT_LIST_HEAD(&sdata->u.ap.vlans); 176062306a36Sopenharmony_ci sdata->vif.bss_conf.bssid = sdata->vif.addr; 176162306a36Sopenharmony_ci break; 176262306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_CLIENT: 176362306a36Sopenharmony_ci type = NL80211_IFTYPE_STATION; 176462306a36Sopenharmony_ci sdata->vif.type = type; 176562306a36Sopenharmony_ci sdata->vif.p2p = true; 176662306a36Sopenharmony_ci fallthrough; 176762306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 176862306a36Sopenharmony_ci sdata->vif.bss_conf.bssid = sdata->deflink.u.mgd.bssid; 176962306a36Sopenharmony_ci ieee80211_sta_setup_sdata(sdata); 177062306a36Sopenharmony_ci break; 177162306a36Sopenharmony_ci case NL80211_IFTYPE_OCB: 177262306a36Sopenharmony_ci sdata->vif.bss_conf.bssid = bssid_wildcard; 177362306a36Sopenharmony_ci ieee80211_ocb_setup_sdata(sdata); 177462306a36Sopenharmony_ci break; 177562306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 177662306a36Sopenharmony_ci sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; 177762306a36Sopenharmony_ci ieee80211_ibss_setup_sdata(sdata); 177862306a36Sopenharmony_ci break; 177962306a36Sopenharmony_ci case NL80211_IFTYPE_MESH_POINT: 178062306a36Sopenharmony_ci if (ieee80211_vif_is_mesh(&sdata->vif)) 178162306a36Sopenharmony_ci ieee80211_mesh_init_sdata(sdata); 178262306a36Sopenharmony_ci break; 178362306a36Sopenharmony_ci case NL80211_IFTYPE_MONITOR: 178462306a36Sopenharmony_ci sdata->dev->type = ARPHRD_IEEE80211_RADIOTAP; 178562306a36Sopenharmony_ci sdata->dev->netdev_ops = &ieee80211_monitorif_ops; 178662306a36Sopenharmony_ci sdata->u.mntr.flags = MONITOR_FLAG_CONTROL | 178762306a36Sopenharmony_ci MONITOR_FLAG_OTHER_BSS; 178862306a36Sopenharmony_ci break; 178962306a36Sopenharmony_ci case NL80211_IFTYPE_NAN: 179062306a36Sopenharmony_ci idr_init(&sdata->u.nan.function_inst_ids); 179162306a36Sopenharmony_ci spin_lock_init(&sdata->u.nan.func_lock); 179262306a36Sopenharmony_ci sdata->vif.bss_conf.bssid = sdata->vif.addr; 179362306a36Sopenharmony_ci break; 179462306a36Sopenharmony_ci case NL80211_IFTYPE_AP_VLAN: 179562306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_DEVICE: 179662306a36Sopenharmony_ci sdata->vif.bss_conf.bssid = sdata->vif.addr; 179762306a36Sopenharmony_ci break; 179862306a36Sopenharmony_ci case NL80211_IFTYPE_UNSPECIFIED: 179962306a36Sopenharmony_ci case NL80211_IFTYPE_WDS: 180062306a36Sopenharmony_ci case NUM_NL80211_IFTYPES: 180162306a36Sopenharmony_ci WARN_ON(1); 180262306a36Sopenharmony_ci break; 180362306a36Sopenharmony_ci } 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci /* need to do this after the switch so vif.type is correct */ 180662306a36Sopenharmony_ci ieee80211_link_setup(&sdata->deflink); 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_ci ieee80211_debugfs_add_netdev(sdata); 180962306a36Sopenharmony_ci} 181062306a36Sopenharmony_ci 181162306a36Sopenharmony_cistatic int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata, 181262306a36Sopenharmony_ci enum nl80211_iftype type) 181362306a36Sopenharmony_ci{ 181462306a36Sopenharmony_ci struct ieee80211_local *local = sdata->local; 181562306a36Sopenharmony_ci int ret, err; 181662306a36Sopenharmony_ci enum nl80211_iftype internal_type = type; 181762306a36Sopenharmony_ci bool p2p = false; 181862306a36Sopenharmony_ci 181962306a36Sopenharmony_ci ASSERT_RTNL(); 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_ci if (!local->ops->change_interface) 182262306a36Sopenharmony_ci return -EBUSY; 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_ci /* for now, don't support changing while links exist */ 182562306a36Sopenharmony_ci if (ieee80211_vif_is_mld(&sdata->vif)) 182662306a36Sopenharmony_ci return -EBUSY; 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_ci switch (sdata->vif.type) { 182962306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 183062306a36Sopenharmony_ci if (!list_empty(&sdata->u.ap.vlans)) 183162306a36Sopenharmony_ci return -EBUSY; 183262306a36Sopenharmony_ci break; 183362306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 183462306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 183562306a36Sopenharmony_ci case NL80211_IFTYPE_OCB: 183662306a36Sopenharmony_ci /* 183762306a36Sopenharmony_ci * Could maybe also all others here? 183862306a36Sopenharmony_ci * Just not sure how that interacts 183962306a36Sopenharmony_ci * with the RX/config path e.g. for 184062306a36Sopenharmony_ci * mesh. 184162306a36Sopenharmony_ci */ 184262306a36Sopenharmony_ci break; 184362306a36Sopenharmony_ci default: 184462306a36Sopenharmony_ci return -EBUSY; 184562306a36Sopenharmony_ci } 184662306a36Sopenharmony_ci 184762306a36Sopenharmony_ci switch (type) { 184862306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 184962306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 185062306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 185162306a36Sopenharmony_ci case NL80211_IFTYPE_OCB: 185262306a36Sopenharmony_ci /* 185362306a36Sopenharmony_ci * Could probably support everything 185462306a36Sopenharmony_ci * but here. 185562306a36Sopenharmony_ci */ 185662306a36Sopenharmony_ci break; 185762306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_CLIENT: 185862306a36Sopenharmony_ci p2p = true; 185962306a36Sopenharmony_ci internal_type = NL80211_IFTYPE_STATION; 186062306a36Sopenharmony_ci break; 186162306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_GO: 186262306a36Sopenharmony_ci p2p = true; 186362306a36Sopenharmony_ci internal_type = NL80211_IFTYPE_AP; 186462306a36Sopenharmony_ci break; 186562306a36Sopenharmony_ci default: 186662306a36Sopenharmony_ci return -EBUSY; 186762306a36Sopenharmony_ci } 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_ci ret = ieee80211_check_concurrent_iface(sdata, internal_type); 187062306a36Sopenharmony_ci if (ret) 187162306a36Sopenharmony_ci return ret; 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci ieee80211_stop_vif_queues(local, sdata, 187462306a36Sopenharmony_ci IEEE80211_QUEUE_STOP_REASON_IFTYPE_CHANGE); 187562306a36Sopenharmony_ci /* do_stop will synchronize_rcu() first thing */ 187662306a36Sopenharmony_ci ieee80211_do_stop(sdata, false); 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci ieee80211_teardown_sdata(sdata); 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci ieee80211_set_sdata_offload_flags(sdata); 188162306a36Sopenharmony_ci ret = drv_change_interface(local, sdata, internal_type, p2p); 188262306a36Sopenharmony_ci if (ret) 188362306a36Sopenharmony_ci type = ieee80211_vif_type_p2p(&sdata->vif); 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ci /* 188662306a36Sopenharmony_ci * Ignore return value here, there's not much we can do since 188762306a36Sopenharmony_ci * the driver changed the interface type internally already. 188862306a36Sopenharmony_ci * The warnings will hopefully make driver authors fix it :-) 188962306a36Sopenharmony_ci */ 189062306a36Sopenharmony_ci ieee80211_check_queues(sdata, type); 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci ieee80211_setup_sdata(sdata, type); 189362306a36Sopenharmony_ci ieee80211_set_vif_encap_ops(sdata); 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci err = ieee80211_do_open(&sdata->wdev, false); 189662306a36Sopenharmony_ci WARN(err, "type change: do_open returned %d", err); 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_ci ieee80211_wake_vif_queues(local, sdata, 189962306a36Sopenharmony_ci IEEE80211_QUEUE_STOP_REASON_IFTYPE_CHANGE); 190062306a36Sopenharmony_ci return ret; 190162306a36Sopenharmony_ci} 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ciint ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, 190462306a36Sopenharmony_ci enum nl80211_iftype type) 190562306a36Sopenharmony_ci{ 190662306a36Sopenharmony_ci int ret; 190762306a36Sopenharmony_ci 190862306a36Sopenharmony_ci ASSERT_RTNL(); 190962306a36Sopenharmony_ci 191062306a36Sopenharmony_ci if (type == ieee80211_vif_type_p2p(&sdata->vif)) 191162306a36Sopenharmony_ci return 0; 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci if (ieee80211_sdata_running(sdata)) { 191462306a36Sopenharmony_ci ret = ieee80211_runtime_change_iftype(sdata, type); 191562306a36Sopenharmony_ci if (ret) 191662306a36Sopenharmony_ci return ret; 191762306a36Sopenharmony_ci } else { 191862306a36Sopenharmony_ci /* Purge and reset type-dependent state. */ 191962306a36Sopenharmony_ci ieee80211_teardown_sdata(sdata); 192062306a36Sopenharmony_ci ieee80211_setup_sdata(sdata, type); 192162306a36Sopenharmony_ci } 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_ci /* reset some values that shouldn't be kept across type changes */ 192462306a36Sopenharmony_ci if (type == NL80211_IFTYPE_STATION) 192562306a36Sopenharmony_ci sdata->u.mgd.use_4addr = false; 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_ci return 0; 192862306a36Sopenharmony_ci} 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_cistatic void ieee80211_assign_perm_addr(struct ieee80211_local *local, 193162306a36Sopenharmony_ci u8 *perm_addr, enum nl80211_iftype type) 193262306a36Sopenharmony_ci{ 193362306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata; 193462306a36Sopenharmony_ci u64 mask, start, addr, val, inc; 193562306a36Sopenharmony_ci u8 *m; 193662306a36Sopenharmony_ci u8 tmp_addr[ETH_ALEN]; 193762306a36Sopenharmony_ci int i; 193862306a36Sopenharmony_ci 193962306a36Sopenharmony_ci /* default ... something at least */ 194062306a36Sopenharmony_ci memcpy(perm_addr, local->hw.wiphy->perm_addr, ETH_ALEN); 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ci if (is_zero_ether_addr(local->hw.wiphy->addr_mask) && 194362306a36Sopenharmony_ci local->hw.wiphy->n_addresses <= 1) 194462306a36Sopenharmony_ci return; 194562306a36Sopenharmony_ci 194662306a36Sopenharmony_ci mutex_lock(&local->iflist_mtx); 194762306a36Sopenharmony_ci 194862306a36Sopenharmony_ci switch (type) { 194962306a36Sopenharmony_ci case NL80211_IFTYPE_MONITOR: 195062306a36Sopenharmony_ci /* doesn't matter */ 195162306a36Sopenharmony_ci break; 195262306a36Sopenharmony_ci case NL80211_IFTYPE_AP_VLAN: 195362306a36Sopenharmony_ci /* match up with an AP interface */ 195462306a36Sopenharmony_ci list_for_each_entry(sdata, &local->interfaces, list) { 195562306a36Sopenharmony_ci if (sdata->vif.type != NL80211_IFTYPE_AP) 195662306a36Sopenharmony_ci continue; 195762306a36Sopenharmony_ci memcpy(perm_addr, sdata->vif.addr, ETH_ALEN); 195862306a36Sopenharmony_ci break; 195962306a36Sopenharmony_ci } 196062306a36Sopenharmony_ci /* keep default if no AP interface present */ 196162306a36Sopenharmony_ci break; 196262306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_CLIENT: 196362306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_GO: 196462306a36Sopenharmony_ci if (ieee80211_hw_check(&local->hw, P2P_DEV_ADDR_FOR_INTF)) { 196562306a36Sopenharmony_ci list_for_each_entry(sdata, &local->interfaces, list) { 196662306a36Sopenharmony_ci if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE) 196762306a36Sopenharmony_ci continue; 196862306a36Sopenharmony_ci if (!ieee80211_sdata_running(sdata)) 196962306a36Sopenharmony_ci continue; 197062306a36Sopenharmony_ci memcpy(perm_addr, sdata->vif.addr, ETH_ALEN); 197162306a36Sopenharmony_ci goto out_unlock; 197262306a36Sopenharmony_ci } 197362306a36Sopenharmony_ci } 197462306a36Sopenharmony_ci fallthrough; 197562306a36Sopenharmony_ci default: 197662306a36Sopenharmony_ci /* assign a new address if possible -- try n_addresses first */ 197762306a36Sopenharmony_ci for (i = 0; i < local->hw.wiphy->n_addresses; i++) { 197862306a36Sopenharmony_ci bool used = false; 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci list_for_each_entry(sdata, &local->interfaces, list) { 198162306a36Sopenharmony_ci if (ether_addr_equal(local->hw.wiphy->addresses[i].addr, 198262306a36Sopenharmony_ci sdata->vif.addr)) { 198362306a36Sopenharmony_ci used = true; 198462306a36Sopenharmony_ci break; 198562306a36Sopenharmony_ci } 198662306a36Sopenharmony_ci } 198762306a36Sopenharmony_ci 198862306a36Sopenharmony_ci if (!used) { 198962306a36Sopenharmony_ci memcpy(perm_addr, 199062306a36Sopenharmony_ci local->hw.wiphy->addresses[i].addr, 199162306a36Sopenharmony_ci ETH_ALEN); 199262306a36Sopenharmony_ci break; 199362306a36Sopenharmony_ci } 199462306a36Sopenharmony_ci } 199562306a36Sopenharmony_ci 199662306a36Sopenharmony_ci /* try mask if available */ 199762306a36Sopenharmony_ci if (is_zero_ether_addr(local->hw.wiphy->addr_mask)) 199862306a36Sopenharmony_ci break; 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_ci m = local->hw.wiphy->addr_mask; 200162306a36Sopenharmony_ci mask = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) | 200262306a36Sopenharmony_ci ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) | 200362306a36Sopenharmony_ci ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8); 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_ci if (__ffs64(mask) + hweight64(mask) != fls64(mask)) { 200662306a36Sopenharmony_ci /* not a contiguous mask ... not handled now! */ 200762306a36Sopenharmony_ci pr_info("not contiguous\n"); 200862306a36Sopenharmony_ci break; 200962306a36Sopenharmony_ci } 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_ci /* 201262306a36Sopenharmony_ci * Pick address of existing interface in case user changed 201362306a36Sopenharmony_ci * MAC address manually, default to perm_addr. 201462306a36Sopenharmony_ci */ 201562306a36Sopenharmony_ci m = local->hw.wiphy->perm_addr; 201662306a36Sopenharmony_ci list_for_each_entry(sdata, &local->interfaces, list) { 201762306a36Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_MONITOR) 201862306a36Sopenharmony_ci continue; 201962306a36Sopenharmony_ci m = sdata->vif.addr; 202062306a36Sopenharmony_ci break; 202162306a36Sopenharmony_ci } 202262306a36Sopenharmony_ci start = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) | 202362306a36Sopenharmony_ci ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) | 202462306a36Sopenharmony_ci ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8); 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_ci inc = 1ULL<<__ffs64(mask); 202762306a36Sopenharmony_ci val = (start & mask); 202862306a36Sopenharmony_ci addr = (start & ~mask) | (val & mask); 202962306a36Sopenharmony_ci do { 203062306a36Sopenharmony_ci bool used = false; 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_ci tmp_addr[5] = addr >> 0*8; 203362306a36Sopenharmony_ci tmp_addr[4] = addr >> 1*8; 203462306a36Sopenharmony_ci tmp_addr[3] = addr >> 2*8; 203562306a36Sopenharmony_ci tmp_addr[2] = addr >> 3*8; 203662306a36Sopenharmony_ci tmp_addr[1] = addr >> 4*8; 203762306a36Sopenharmony_ci tmp_addr[0] = addr >> 5*8; 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_ci val += inc; 204062306a36Sopenharmony_ci 204162306a36Sopenharmony_ci list_for_each_entry(sdata, &local->interfaces, list) { 204262306a36Sopenharmony_ci if (ether_addr_equal(tmp_addr, sdata->vif.addr)) { 204362306a36Sopenharmony_ci used = true; 204462306a36Sopenharmony_ci break; 204562306a36Sopenharmony_ci } 204662306a36Sopenharmony_ci } 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_ci if (!used) { 204962306a36Sopenharmony_ci memcpy(perm_addr, tmp_addr, ETH_ALEN); 205062306a36Sopenharmony_ci break; 205162306a36Sopenharmony_ci } 205262306a36Sopenharmony_ci addr = (start & ~mask) | (val & mask); 205362306a36Sopenharmony_ci } while (addr != start); 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_ci break; 205662306a36Sopenharmony_ci } 205762306a36Sopenharmony_ci 205862306a36Sopenharmony_ci out_unlock: 205962306a36Sopenharmony_ci mutex_unlock(&local->iflist_mtx); 206062306a36Sopenharmony_ci} 206162306a36Sopenharmony_ci 206262306a36Sopenharmony_ciint ieee80211_if_add(struct ieee80211_local *local, const char *name, 206362306a36Sopenharmony_ci unsigned char name_assign_type, 206462306a36Sopenharmony_ci struct wireless_dev **new_wdev, enum nl80211_iftype type, 206562306a36Sopenharmony_ci struct vif_params *params) 206662306a36Sopenharmony_ci{ 206762306a36Sopenharmony_ci struct net_device *ndev = NULL; 206862306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata = NULL; 206962306a36Sopenharmony_ci struct txq_info *txqi; 207062306a36Sopenharmony_ci int ret, i; 207162306a36Sopenharmony_ci 207262306a36Sopenharmony_ci ASSERT_RTNL(); 207362306a36Sopenharmony_ci 207462306a36Sopenharmony_ci if (type == NL80211_IFTYPE_P2P_DEVICE || type == NL80211_IFTYPE_NAN) { 207562306a36Sopenharmony_ci struct wireless_dev *wdev; 207662306a36Sopenharmony_ci 207762306a36Sopenharmony_ci sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, 207862306a36Sopenharmony_ci GFP_KERNEL); 207962306a36Sopenharmony_ci if (!sdata) 208062306a36Sopenharmony_ci return -ENOMEM; 208162306a36Sopenharmony_ci wdev = &sdata->wdev; 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_ci sdata->dev = NULL; 208462306a36Sopenharmony_ci strscpy(sdata->name, name, IFNAMSIZ); 208562306a36Sopenharmony_ci ieee80211_assign_perm_addr(local, wdev->address, type); 208662306a36Sopenharmony_ci memcpy(sdata->vif.addr, wdev->address, ETH_ALEN); 208762306a36Sopenharmony_ci ether_addr_copy(sdata->vif.bss_conf.addr, sdata->vif.addr); 208862306a36Sopenharmony_ci } else { 208962306a36Sopenharmony_ci int size = ALIGN(sizeof(*sdata) + local->hw.vif_data_size, 209062306a36Sopenharmony_ci sizeof(void *)); 209162306a36Sopenharmony_ci int txq_size = 0; 209262306a36Sopenharmony_ci 209362306a36Sopenharmony_ci if (type != NL80211_IFTYPE_AP_VLAN && 209462306a36Sopenharmony_ci (type != NL80211_IFTYPE_MONITOR || 209562306a36Sopenharmony_ci (params->flags & MONITOR_FLAG_ACTIVE))) 209662306a36Sopenharmony_ci txq_size += sizeof(struct txq_info) + 209762306a36Sopenharmony_ci local->hw.txq_data_size; 209862306a36Sopenharmony_ci 209962306a36Sopenharmony_ci ndev = alloc_netdev_mqs(size + txq_size, 210062306a36Sopenharmony_ci name, name_assign_type, 210162306a36Sopenharmony_ci ieee80211_if_setup, 1, 1); 210262306a36Sopenharmony_ci if (!ndev) 210362306a36Sopenharmony_ci return -ENOMEM; 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci dev_net_set(ndev, wiphy_net(local->hw.wiphy)); 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_ci ndev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); 210862306a36Sopenharmony_ci if (!ndev->tstats) { 210962306a36Sopenharmony_ci free_netdev(ndev); 211062306a36Sopenharmony_ci return -ENOMEM; 211162306a36Sopenharmony_ci } 211262306a36Sopenharmony_ci 211362306a36Sopenharmony_ci ndev->needed_headroom = local->tx_headroom + 211462306a36Sopenharmony_ci 4*6 /* four MAC addresses */ 211562306a36Sopenharmony_ci + 2 + 2 + 2 + 2 /* ctl, dur, seq, qos */ 211662306a36Sopenharmony_ci + 6 /* mesh */ 211762306a36Sopenharmony_ci + 8 /* rfc1042/bridge tunnel */ 211862306a36Sopenharmony_ci - ETH_HLEN /* ethernet hard_header_len */ 211962306a36Sopenharmony_ci + IEEE80211_ENCRYPT_HEADROOM; 212062306a36Sopenharmony_ci ndev->needed_tailroom = IEEE80211_ENCRYPT_TAILROOM; 212162306a36Sopenharmony_ci 212262306a36Sopenharmony_ci ret = dev_alloc_name(ndev, ndev->name); 212362306a36Sopenharmony_ci if (ret < 0) { 212462306a36Sopenharmony_ci ieee80211_if_free(ndev); 212562306a36Sopenharmony_ci free_netdev(ndev); 212662306a36Sopenharmony_ci return ret; 212762306a36Sopenharmony_ci } 212862306a36Sopenharmony_ci 212962306a36Sopenharmony_ci ieee80211_assign_perm_addr(local, ndev->perm_addr, type); 213062306a36Sopenharmony_ci if (is_valid_ether_addr(params->macaddr)) 213162306a36Sopenharmony_ci eth_hw_addr_set(ndev, params->macaddr); 213262306a36Sopenharmony_ci else 213362306a36Sopenharmony_ci eth_hw_addr_set(ndev, ndev->perm_addr); 213462306a36Sopenharmony_ci SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); 213562306a36Sopenharmony_ci 213662306a36Sopenharmony_ci /* don't use IEEE80211_DEV_TO_SUB_IF -- it checks too much */ 213762306a36Sopenharmony_ci sdata = netdev_priv(ndev); 213862306a36Sopenharmony_ci ndev->ieee80211_ptr = &sdata->wdev; 213962306a36Sopenharmony_ci memcpy(sdata->vif.addr, ndev->dev_addr, ETH_ALEN); 214062306a36Sopenharmony_ci ether_addr_copy(sdata->vif.bss_conf.addr, sdata->vif.addr); 214162306a36Sopenharmony_ci memcpy(sdata->name, ndev->name, IFNAMSIZ); 214262306a36Sopenharmony_ci 214362306a36Sopenharmony_ci if (txq_size) { 214462306a36Sopenharmony_ci txqi = netdev_priv(ndev) + size; 214562306a36Sopenharmony_ci ieee80211_txq_init(sdata, NULL, txqi, 0); 214662306a36Sopenharmony_ci } 214762306a36Sopenharmony_ci 214862306a36Sopenharmony_ci sdata->dev = ndev; 214962306a36Sopenharmony_ci } 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_ci /* initialise type-independent data */ 215262306a36Sopenharmony_ci sdata->wdev.wiphy = local->hw.wiphy; 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_ci ieee80211_sdata_init(local, sdata); 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci ieee80211_init_frag_cache(&sdata->frags); 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci INIT_LIST_HEAD(&sdata->key_list); 215962306a36Sopenharmony_ci 216062306a36Sopenharmony_ci INIT_DELAYED_WORK(&sdata->dec_tailroom_needed_wk, 216162306a36Sopenharmony_ci ieee80211_delayed_tailroom_dec); 216262306a36Sopenharmony_ci 216362306a36Sopenharmony_ci for (i = 0; i < NUM_NL80211_BANDS; i++) { 216462306a36Sopenharmony_ci struct ieee80211_supported_band *sband; 216562306a36Sopenharmony_ci sband = local->hw.wiphy->bands[i]; 216662306a36Sopenharmony_ci sdata->rc_rateidx_mask[i] = 216762306a36Sopenharmony_ci sband ? (1 << sband->n_bitrates) - 1 : 0; 216862306a36Sopenharmony_ci if (sband) { 216962306a36Sopenharmony_ci __le16 cap; 217062306a36Sopenharmony_ci u16 *vht_rate_mask; 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ci memcpy(sdata->rc_rateidx_mcs_mask[i], 217362306a36Sopenharmony_ci sband->ht_cap.mcs.rx_mask, 217462306a36Sopenharmony_ci sizeof(sdata->rc_rateidx_mcs_mask[i])); 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_ci cap = sband->vht_cap.vht_mcs.rx_mcs_map; 217762306a36Sopenharmony_ci vht_rate_mask = sdata->rc_rateidx_vht_mcs_mask[i]; 217862306a36Sopenharmony_ci ieee80211_get_vht_mask_from_cap(cap, vht_rate_mask); 217962306a36Sopenharmony_ci } else { 218062306a36Sopenharmony_ci memset(sdata->rc_rateidx_mcs_mask[i], 0, 218162306a36Sopenharmony_ci sizeof(sdata->rc_rateidx_mcs_mask[i])); 218262306a36Sopenharmony_ci memset(sdata->rc_rateidx_vht_mcs_mask[i], 0, 218362306a36Sopenharmony_ci sizeof(sdata->rc_rateidx_vht_mcs_mask[i])); 218462306a36Sopenharmony_ci } 218562306a36Sopenharmony_ci } 218662306a36Sopenharmony_ci 218762306a36Sopenharmony_ci ieee80211_set_default_queues(sdata); 218862306a36Sopenharmony_ci 218962306a36Sopenharmony_ci sdata->deflink.ap_power_level = IEEE80211_UNSET_POWER_LEVEL; 219062306a36Sopenharmony_ci sdata->deflink.user_power_level = local->user_power_level; 219162306a36Sopenharmony_ci 219262306a36Sopenharmony_ci /* setup type-dependent data */ 219362306a36Sopenharmony_ci ieee80211_setup_sdata(sdata, type); 219462306a36Sopenharmony_ci 219562306a36Sopenharmony_ci if (ndev) { 219662306a36Sopenharmony_ci ndev->ieee80211_ptr->use_4addr = params->use_4addr; 219762306a36Sopenharmony_ci if (type == NL80211_IFTYPE_STATION) 219862306a36Sopenharmony_ci sdata->u.mgd.use_4addr = params->use_4addr; 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ci ndev->features |= local->hw.netdev_features; 220162306a36Sopenharmony_ci ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE; 220262306a36Sopenharmony_ci ndev->hw_features |= ndev->features & 220362306a36Sopenharmony_ci MAC80211_SUPPORTED_FEATURES_TX; 220462306a36Sopenharmony_ci sdata->vif.netdev_features = local->hw.netdev_features; 220562306a36Sopenharmony_ci 220662306a36Sopenharmony_ci netdev_set_default_ethtool_ops(ndev, &ieee80211_ethtool_ops); 220762306a36Sopenharmony_ci 220862306a36Sopenharmony_ci /* MTU range is normally 256 - 2304, where the upper limit is 220962306a36Sopenharmony_ci * the maximum MSDU size. Monitor interfaces send and receive 221062306a36Sopenharmony_ci * MPDU and A-MSDU frames which may be much larger so we do 221162306a36Sopenharmony_ci * not impose an upper limit in that case. 221262306a36Sopenharmony_ci */ 221362306a36Sopenharmony_ci ndev->min_mtu = 256; 221462306a36Sopenharmony_ci if (type == NL80211_IFTYPE_MONITOR) 221562306a36Sopenharmony_ci ndev->max_mtu = 0; 221662306a36Sopenharmony_ci else 221762306a36Sopenharmony_ci ndev->max_mtu = local->hw.max_mtu; 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_ci ret = cfg80211_register_netdevice(ndev); 222062306a36Sopenharmony_ci if (ret) { 222162306a36Sopenharmony_ci free_netdev(ndev); 222262306a36Sopenharmony_ci return ret; 222362306a36Sopenharmony_ci } 222462306a36Sopenharmony_ci } 222562306a36Sopenharmony_ci 222662306a36Sopenharmony_ci mutex_lock(&local->iflist_mtx); 222762306a36Sopenharmony_ci list_add_tail_rcu(&sdata->list, &local->interfaces); 222862306a36Sopenharmony_ci mutex_unlock(&local->iflist_mtx); 222962306a36Sopenharmony_ci 223062306a36Sopenharmony_ci if (new_wdev) 223162306a36Sopenharmony_ci *new_wdev = &sdata->wdev; 223262306a36Sopenharmony_ci 223362306a36Sopenharmony_ci return 0; 223462306a36Sopenharmony_ci} 223562306a36Sopenharmony_ci 223662306a36Sopenharmony_civoid ieee80211_if_remove(struct ieee80211_sub_if_data *sdata) 223762306a36Sopenharmony_ci{ 223862306a36Sopenharmony_ci ASSERT_RTNL(); 223962306a36Sopenharmony_ci 224062306a36Sopenharmony_ci mutex_lock(&sdata->local->iflist_mtx); 224162306a36Sopenharmony_ci list_del_rcu(&sdata->list); 224262306a36Sopenharmony_ci mutex_unlock(&sdata->local->iflist_mtx); 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_ci if (sdata->vif.txq) 224562306a36Sopenharmony_ci ieee80211_txq_purge(sdata->local, to_txq_info(sdata->vif.txq)); 224662306a36Sopenharmony_ci 224762306a36Sopenharmony_ci synchronize_rcu(); 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_ci cfg80211_unregister_wdev(&sdata->wdev); 225062306a36Sopenharmony_ci 225162306a36Sopenharmony_ci if (!sdata->dev) { 225262306a36Sopenharmony_ci ieee80211_teardown_sdata(sdata); 225362306a36Sopenharmony_ci kfree(sdata); 225462306a36Sopenharmony_ci } 225562306a36Sopenharmony_ci} 225662306a36Sopenharmony_ci 225762306a36Sopenharmony_civoid ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata) 225862306a36Sopenharmony_ci{ 225962306a36Sopenharmony_ci if (WARN_ON_ONCE(!test_bit(SDATA_STATE_RUNNING, &sdata->state))) 226062306a36Sopenharmony_ci return; 226162306a36Sopenharmony_ci ieee80211_do_stop(sdata, true); 226262306a36Sopenharmony_ci} 226362306a36Sopenharmony_ci 226462306a36Sopenharmony_civoid ieee80211_remove_interfaces(struct ieee80211_local *local) 226562306a36Sopenharmony_ci{ 226662306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata, *tmp; 226762306a36Sopenharmony_ci LIST_HEAD(unreg_list); 226862306a36Sopenharmony_ci 226962306a36Sopenharmony_ci ASSERT_RTNL(); 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci /* Before destroying the interfaces, make sure they're all stopped so 227262306a36Sopenharmony_ci * that the hardware is stopped. Otherwise, the driver might still be 227362306a36Sopenharmony_ci * iterating the interfaces during the shutdown, e.g. from a worker 227462306a36Sopenharmony_ci * or from RX processing or similar, and if it does so (using atomic 227562306a36Sopenharmony_ci * iteration) while we're manipulating the list, the iteration will 227662306a36Sopenharmony_ci * crash. 227762306a36Sopenharmony_ci * 227862306a36Sopenharmony_ci * After this, the hardware should be stopped and the driver should 227962306a36Sopenharmony_ci * have stopped all of its activities, so that we can do RCU-unaware 228062306a36Sopenharmony_ci * manipulations of the interface list below. 228162306a36Sopenharmony_ci */ 228262306a36Sopenharmony_ci cfg80211_shutdown_all_interfaces(local->hw.wiphy); 228362306a36Sopenharmony_ci 228462306a36Sopenharmony_ci WARN(local->open_count, "%s: open count remains %d\n", 228562306a36Sopenharmony_ci wiphy_name(local->hw.wiphy), local->open_count); 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_ci ieee80211_txq_teardown_flows(local); 228862306a36Sopenharmony_ci 228962306a36Sopenharmony_ci mutex_lock(&local->iflist_mtx); 229062306a36Sopenharmony_ci list_splice_init(&local->interfaces, &unreg_list); 229162306a36Sopenharmony_ci mutex_unlock(&local->iflist_mtx); 229262306a36Sopenharmony_ci 229362306a36Sopenharmony_ci wiphy_lock(local->hw.wiphy); 229462306a36Sopenharmony_ci list_for_each_entry_safe(sdata, tmp, &unreg_list, list) { 229562306a36Sopenharmony_ci bool netdev = sdata->dev; 229662306a36Sopenharmony_ci 229762306a36Sopenharmony_ci list_del(&sdata->list); 229862306a36Sopenharmony_ci cfg80211_unregister_wdev(&sdata->wdev); 229962306a36Sopenharmony_ci 230062306a36Sopenharmony_ci if (!netdev) 230162306a36Sopenharmony_ci kfree(sdata); 230262306a36Sopenharmony_ci } 230362306a36Sopenharmony_ci wiphy_unlock(local->hw.wiphy); 230462306a36Sopenharmony_ci} 230562306a36Sopenharmony_ci 230662306a36Sopenharmony_cistatic int netdev_notify(struct notifier_block *nb, 230762306a36Sopenharmony_ci unsigned long state, void *ptr) 230862306a36Sopenharmony_ci{ 230962306a36Sopenharmony_ci struct net_device *dev = netdev_notifier_info_to_dev(ptr); 231062306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata; 231162306a36Sopenharmony_ci 231262306a36Sopenharmony_ci if (state != NETDEV_CHANGENAME) 231362306a36Sopenharmony_ci return NOTIFY_DONE; 231462306a36Sopenharmony_ci 231562306a36Sopenharmony_ci if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy) 231662306a36Sopenharmony_ci return NOTIFY_DONE; 231762306a36Sopenharmony_ci 231862306a36Sopenharmony_ci if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid) 231962306a36Sopenharmony_ci return NOTIFY_DONE; 232062306a36Sopenharmony_ci 232162306a36Sopenharmony_ci sdata = IEEE80211_DEV_TO_SUB_IF(dev); 232262306a36Sopenharmony_ci memcpy(sdata->name, dev->name, IFNAMSIZ); 232362306a36Sopenharmony_ci ieee80211_debugfs_rename_netdev(sdata); 232462306a36Sopenharmony_ci 232562306a36Sopenharmony_ci return NOTIFY_OK; 232662306a36Sopenharmony_ci} 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_cistatic struct notifier_block mac80211_netdev_notifier = { 232962306a36Sopenharmony_ci .notifier_call = netdev_notify, 233062306a36Sopenharmony_ci}; 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_ciint ieee80211_iface_init(void) 233362306a36Sopenharmony_ci{ 233462306a36Sopenharmony_ci return register_netdevice_notifier(&mac80211_netdev_notifier); 233562306a36Sopenharmony_ci} 233662306a36Sopenharmony_ci 233762306a36Sopenharmony_civoid ieee80211_iface_exit(void) 233862306a36Sopenharmony_ci{ 233962306a36Sopenharmony_ci unregister_netdevice_notifier(&mac80211_netdev_notifier); 234062306a36Sopenharmony_ci} 234162306a36Sopenharmony_ci 234262306a36Sopenharmony_civoid ieee80211_vif_inc_num_mcast(struct ieee80211_sub_if_data *sdata) 234362306a36Sopenharmony_ci{ 234462306a36Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_AP) 234562306a36Sopenharmony_ci atomic_inc(&sdata->u.ap.num_mcast_sta); 234662306a36Sopenharmony_ci else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 234762306a36Sopenharmony_ci atomic_inc(&sdata->u.vlan.num_mcast_sta); 234862306a36Sopenharmony_ci} 234962306a36Sopenharmony_ci 235062306a36Sopenharmony_civoid ieee80211_vif_dec_num_mcast(struct ieee80211_sub_if_data *sdata) 235162306a36Sopenharmony_ci{ 235262306a36Sopenharmony_ci if (sdata->vif.type == NL80211_IFTYPE_AP) 235362306a36Sopenharmony_ci atomic_dec(&sdata->u.ap.num_mcast_sta); 235462306a36Sopenharmony_ci else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 235562306a36Sopenharmony_ci atomic_dec(&sdata->u.vlan.num_mcast_sta); 235662306a36Sopenharmony_ci} 2357