Path: blob/main/sys/compat/linuxkpi/common/src/linux_80211.c
39586 views
/*-1* Copyright (c) 2020-2025 The FreeBSD Foundation2* Copyright (c) 2020-2025 Bjoern A. Zeeb3*4* This software was developed by Björn Zeeb under sponsorship from5* the FreeBSD Foundation.6*7* Redistribution and use in source and binary forms, with or without8* modification, are permitted provided that the following conditions9* are met:10* 1. Redistributions of source code must retain the above copyright11* notice, this list of conditions and the following disclaimer.12* 2. Redistributions in binary form must reproduce the above copyright13* notice, this list of conditions and the following disclaimer in the14* documentation and/or other materials provided with the distribution.15*16* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND17* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE18* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE19* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE20* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL21* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS22* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)23* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT24* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY25* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF26* SUCH DAMAGE.27*/2829/*30* Public functions are called linuxkpi_*().31* Internal (static) functions are called lkpi_*().32*33* The internal structures holding metadata over public structures are also34* called lkpi_xxx (usually with a member at the end called xxx).35* Note: we do not replicate the structure names but the general variable names36* for these (e.g., struct hw -> struct lkpi_hw, struct sta -> struct lkpi_sta).37* There are macros to access one from the other.38* We call the internal versions lxxx (e.g., hw -> lhw, sta -> lsta).39*/4041/*42* TODO:43* - lots :)44* - HW_CRYPTO: we need a "keystore" and an ordered list for suspend/resume.45*/4647#include <sys/param.h>48#include <sys/types.h>49#include <sys/kernel.h>50#include <sys/errno.h>51#include <sys/malloc.h>52#include <sys/module.h>53#include <sys/mutex.h>54#include <sys/sbuf.h>55#include <sys/socket.h>56#include <sys/sysctl.h>57#include <sys/queue.h>58#include <sys/taskqueue.h>59#include <sys/libkern.h>6061#include <net/if.h>62#include <net/if_var.h>63#include <net/if_media.h>64#include <net/ethernet.h>6566#include <net80211/ieee80211_var.h>67#include <net80211/ieee80211_proto.h>68#include <net80211/ieee80211_ratectl.h>69#include <net80211/ieee80211_radiotap.h>70#include <net80211/ieee80211_vht.h>7172#define LINUXKPI_NET8021173#include <net/mac80211.h>7475#include <linux/workqueue.h>76#include <linux/rculist.h>77#include "linux_80211.h"7879/* #define LKPI_80211_USE_SCANLIST */80/* #define LKPI_80211_BGSCAN */81#define LKPI_80211_WME82#define LKPI_80211_HW_CRYPTO83#define LKPI_80211_HT84#define LKPI_80211_VHT8586#if defined(LKPI_80211_VHT) && !defined(LKPI_80211_HT)87#define LKPI_80211_HT88#endif89#if defined(LKPI_80211_HT) && !defined(LKPI_80211_HW_CRYPTO)90#define LKPI_80211_HW_CRYPTO91#endif9293static MALLOC_DEFINE(M_LKPI80211, "lkpi80211", "LinuxKPI 80211 compat");9495/* XXX-BZ really want this and others in queue.h */96#define TAILQ_ELEM_INIT(elm, field) do { \97(elm)->field.tqe_next = NULL; \98(elm)->field.tqe_prev = NULL; \99} while (0)100101/* -------------------------------------------------------------------------- */102103SYSCTL_DECL(_compat_linuxkpi);104SYSCTL_NODE(_compat_linuxkpi, OID_AUTO, 80211, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,105"LinuxKPI 802.11 compatibility layer");106107static bool lkpi_order_scanlist = false;108SYSCTL_BOOL(_compat_linuxkpi_80211, OID_AUTO, order_scanlist, CTLFLAG_RW,109&lkpi_order_scanlist, 0, "Enable LinuxKPI 802.11 scan list shuffeling");110111#if defined(LKPI_80211_HW_CRYPTO)112static bool lkpi_hwcrypto = false;113SYSCTL_BOOL(_compat_linuxkpi_80211, OID_AUTO, hw_crypto, CTLFLAG_RDTUN,114&lkpi_hwcrypto, 0, "Enable LinuxKPI 802.11 hardware crypto offload");115116static bool lkpi_hwcrypto_tkip = false;117SYSCTL_BOOL(_compat_linuxkpi_80211, OID_AUTO, tkip, CTLFLAG_RDTUN,118&lkpi_hwcrypto_tkip, 0, "Enable LinuxKPI 802.11 TKIP crypto offload");119#endif120121/* Keep public for as long as header files are using it too. */122int linuxkpi_debug_80211;123124#ifdef LINUXKPI_DEBUG_80211125SYSCTL_INT(_compat_linuxkpi_80211, OID_AUTO, debug, CTLFLAG_RWTUN,126&linuxkpi_debug_80211, 0, "LinuxKPI 802.11 debug level");127128#define UNIMPLEMENTED if (linuxkpi_debug_80211 & D80211_TODO) \129printf("XXX-TODO %s:%d: UNIMPLEMENTED\n", __func__, __LINE__)130#define TRACEOK() if (linuxkpi_debug_80211 & D80211_TRACEOK) \131printf("XXX-TODO %s:%d: TRACEPOINT\n", __func__, __LINE__)132#else133#define UNIMPLEMENTED do { } while (0)134#define TRACEOK() do { } while (0)135#endif136137/* #define PREP_TX_INFO_DURATION (IEEE80211_TRANS_WAIT * 1000) */138#ifndef PREP_TX_INFO_DURATION139#define PREP_TX_INFO_DURATION 0 /* Let the driver do its thing. */140#endif141142/* This is DSAP | SSAP | CTRL | ProtoID/OrgCode{3}. */143const uint8_t rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };144145/* IEEE 802.11-05/0257r1 */146const uint8_t bridge_tunnel_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };147148/* IEEE 802.11e Table 20i-UP-to-AC mappings. */149static const uint8_t ieee80211e_up_to_ac[] = {150IEEE80211_AC_BE,151IEEE80211_AC_BK,152IEEE80211_AC_BK,153IEEE80211_AC_BE,154IEEE80211_AC_VI,155IEEE80211_AC_VI,156IEEE80211_AC_VO,157IEEE80211_AC_VO,158#if 0159IEEE80211_AC_VO, /* We treat MGMT as TID 8, which is set as AC_VO */160#endif161};162163const struct cfg80211_ops linuxkpi_mac80211cfgops = {164/*165* XXX TODO need a "glue layer" to link cfg80211 ops to166* mac80211 and to the driver or net80211.167* Can we pass some on 1:1? Need to compare the (*f)().168*/169};170171#if 0172static struct lkpi_sta *lkpi_find_lsta_by_ni(struct lkpi_vif *,173struct ieee80211_node *);174#endif175static void lkpi_sw_scan_task(void *, int);176static void lkpi_80211_txq_tx_one(struct lkpi_sta *, struct mbuf *);177static void lkpi_80211_txq_task(void *, int);178static void lkpi_80211_lhw_rxq_task(void *, int);179static void lkpi_ieee80211_free_skb_mbuf(void *);180#ifdef LKPI_80211_WME181static int lkpi_wme_update(struct lkpi_hw *, struct ieee80211vap *, bool);182#endif183static void lkpi_ieee80211_wake_queues_locked(struct ieee80211_hw *);184185static const char *186lkpi_rate_info_bw_to_str(enum rate_info_bw bw)187{188189switch (bw) {190191case RATE_INFO_BW_20:192return ("20");193break;194case RATE_INFO_BW_5:195return ("5");196break;197case RATE_INFO_BW_10:198return ("10");199break;200case RATE_INFO_BW_40:201return ("40");202break;203case RATE_INFO_BW_80:204return ("80");205break;206case RATE_INFO_BW_160:207return ("160");208break;209case RATE_INFO_BW_HE_RU:210IMPROVE("nl80211_he_ru_alloc");211return ("HE_RU");212break;213case RATE_INFO_BW_320:214return ("320");215break;216case RATE_INFO_BW_EHT_RU:217IMPROVE("nl80211_eht_ru_alloc");218return ("EHT_RU");219break;220default:221return ("?");222break;223}224}225226static void227lkpi_nl80211_sta_info_to_str(struct sbuf *s, const char *prefix,228const uint64_t flags)229{230int bit, i;231232sbuf_printf(s, "%s %#010jx", prefix, flags);233234i = 0;235for (bit = 0; bit < BITS_PER_TYPE(flags); bit++) {236237if ((flags & BIT_ULL(bit)) == 0)238continue;239240#define EXPAND_CASE(_flag) \241case NL80211_STA_INFO_ ## _flag: \242sbuf_printf(s, "%c%s", (i == 0) ? '<' : ',', #_flag); \243i++; \244break;245246switch (bit) {247EXPAND_CASE(BEACON_RX)248EXPAND_CASE(BEACON_SIGNAL_AVG)249EXPAND_CASE(BSS_PARAM)250EXPAND_CASE(CHAIN_SIGNAL)251EXPAND_CASE(CHAIN_SIGNAL_AVG)252EXPAND_CASE(CONNECTED_TIME)253EXPAND_CASE(INACTIVE_TIME)254EXPAND_CASE(SIGNAL)255EXPAND_CASE(SIGNAL_AVG)256EXPAND_CASE(STA_FLAGS)257EXPAND_CASE(RX_BITRATE)258EXPAND_CASE(RX_PACKETS)259EXPAND_CASE(RX_BYTES)260EXPAND_CASE(RX_DROP_MISC)261EXPAND_CASE(TX_BITRATE)262EXPAND_CASE(TX_PACKETS)263EXPAND_CASE(TX_BYTES)264EXPAND_CASE(TX_BYTES64)265EXPAND_CASE(RX_BYTES64)266EXPAND_CASE(TX_FAILED)267EXPAND_CASE(TX_RETRIES)268EXPAND_CASE(RX_DURATION)269EXPAND_CASE(TX_DURATION)270EXPAND_CASE(ACK_SIGNAL)271EXPAND_CASE(ACK_SIGNAL_AVG)272default:273sbuf_printf(s, "%c?%d", (i == 0) ? '<' : ',', bit);274break;275}276}277#undef EXPAND_CASE278if (i > 0)279sbuf_printf(s, ">");280sbuf_printf(s, "\n");281}282283static void284lkpi_80211_dump_lvif_stas(struct lkpi_vif *lvif, struct sbuf *s)285{286struct lkpi_hw *lhw;287struct ieee80211_hw *hw;288struct ieee80211vap *vap;289struct ieee80211_vif *vif;290struct lkpi_sta *lsta;291struct ieee80211_sta *sta;292struct station_info sinfo;293int error;294295vif = LVIF_TO_VIF(lvif);296vap = LVIF_TO_VAP(lvif);297lhw = vap->iv_ic->ic_softc;298hw = LHW_TO_HW(lhw);299300wiphy_lock(hw->wiphy);301list_for_each_entry(lsta, &lvif->lsta_list, lsta_list) {302sta = LSTA_TO_STA(lsta);303304sbuf_putc(s, '\n');305sbuf_printf(s, "lsta %p sta %p added_to_drv %d\n", lsta, sta, lsta->added_to_drv);306307memset(&sinfo, 0, sizeof(sinfo));308error = lkpi_80211_mo_sta_statistics(hw, vif, sta, &sinfo);309if (error == EEXIST) /* Not added to driver. */310continue;311if (error == ENOTSUPP) {312sbuf_printf(s, " sta_statistics not supported\n");313continue;314}315if (error != 0) {316sbuf_printf(s, " sta_statistics failed: %d\n", error);317continue;318}319320/* If no RX_BITRATE is reported, try to fill it in from the lsta sinfo. */321if ((sinfo.filled & BIT_ULL(NL80211_STA_INFO_RX_BITRATE)) == 0 &&322(lsta->sinfo.filled & BIT_ULL(NL80211_STA_INFO_RX_BITRATE)) != 0) {323memcpy(&sinfo.rxrate, &lsta->sinfo.rxrate, sizeof(sinfo.rxrate));324sinfo.filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE);325}326/* If no CHAIN_SIGNAL is reported, try to fill it in from the lsta sinfo. */327if ((sinfo.filled & BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL)) == 0 &&328(lsta->sinfo.filled & BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL)) != 0) {329sinfo.chains = lsta->sinfo.chains;330memcpy(sinfo.chain_signal, lsta->sinfo.chain_signal,331sizeof(sinfo.chain_signal));332sinfo.filled |= BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL);333}334335lkpi_nl80211_sta_info_to_str(s, " nl80211_sta_info (valid fields)", sinfo.filled);336sbuf_printf(s, " connected_time %u inactive_time %u\n",337sinfo.connected_time, sinfo.inactive_time);338sbuf_printf(s, " rx_bytes %ju rx_packets %u rx_dropped_misc %u\n",339(uintmax_t)sinfo.rx_bytes, sinfo.rx_packets, sinfo.rx_dropped_misc);340sbuf_printf(s, " rx_duration %ju rx_beacon %u rx_beacon_signal_avg %d\n",341(uintmax_t)sinfo.rx_duration, sinfo.rx_beacon, (int8_t)sinfo.rx_beacon_signal_avg);342343sbuf_printf(s, " tx_bytes %ju tx_packets %u tx_failed %u\n",344(uintmax_t)sinfo.tx_bytes, sinfo.tx_packets, sinfo.tx_failed);345sbuf_printf(s, " tx_duration %ju tx_retries %u\n",346(uintmax_t)sinfo.tx_duration, sinfo.tx_retries);347348sbuf_printf(s, " signal %d signal_avg %d ack_signal %d avg_ack_signal %d\n",349sinfo.signal, sinfo.signal_avg, sinfo.ack_signal, sinfo.avg_ack_signal);350sbuf_printf(s, " generation %d assoc_req_ies_len %zu chains %#04x\n",351sinfo.generation, sinfo.assoc_req_ies_len, sinfo.chains);352353for (int i = 0; i < nitems(sinfo.chain_signal) && i < IEEE80211_MAX_CHAINS; i++) {354if (!(sinfo.chains & BIT(i)))355continue;356sbuf_printf(s, " chain[%d] signal %d signal_avg %d\n",357i, (int8_t)sinfo.chain_signal[i], (int8_t)sinfo.chain_signal_avg[i]);358}359360/* assoc_req_ies, bss_param, sta_flags */361362sbuf_printf(s, " rxrate: flags %b bw %u(%s) legacy %u kbit/s mcs %u nss %u\n",363sinfo.rxrate.flags, CFG80211_RATE_INFO_FLAGS_BITS,364sinfo.rxrate.bw, lkpi_rate_info_bw_to_str(sinfo.rxrate.bw),365sinfo.rxrate.legacy * 100,366sinfo.rxrate.mcs, sinfo.rxrate.nss);367sbuf_printf(s, " he_dcm %u he_gi %u he_ru_alloc %u eht_gi %u\n",368sinfo.rxrate.he_dcm, sinfo.rxrate.he_gi, sinfo.rxrate.he_ru_alloc,369sinfo.rxrate.eht_gi);370sbuf_printf(s, " txrate: flags %b bw %u(%s) legacy %u kbit/s mcs %u nss %u\n",371sinfo.txrate.flags, CFG80211_RATE_INFO_FLAGS_BITS,372sinfo.txrate.bw, lkpi_rate_info_bw_to_str(sinfo.txrate.bw),373sinfo.txrate.legacy * 100,374sinfo.txrate.mcs, sinfo.txrate.nss);375sbuf_printf(s, " he_dcm %u he_gi %u he_ru_alloc %u eht_gi %u\n",376sinfo.txrate.he_dcm, sinfo.txrate.he_gi, sinfo.txrate.he_ru_alloc,377sinfo.txrate.eht_gi);378}379wiphy_unlock(hw->wiphy);380}381382static int383lkpi_80211_dump_stas(SYSCTL_HANDLER_ARGS)384{385struct lkpi_vif *lvif;386struct sbuf s;387388if (req->newptr)389return (EPERM);390391lvif = (struct lkpi_vif *)arg1;392393sbuf_new_for_sysctl(&s, NULL, 1024, req);394395lkpi_80211_dump_lvif_stas(lvif, &s);396397sbuf_finish(&s);398sbuf_delete(&s);399400return (0);401}402403static enum ieee80211_sta_rx_bandwidth404lkpi_cw_to_rx_bw(enum nl80211_chan_width cw)405{406switch (cw) {407case NL80211_CHAN_WIDTH_320:408return (IEEE80211_STA_RX_BW_320);409case NL80211_CHAN_WIDTH_160:410case NL80211_CHAN_WIDTH_80P80:411return (IEEE80211_STA_RX_BW_160);412case NL80211_CHAN_WIDTH_80:413return (IEEE80211_STA_RX_BW_80);414case NL80211_CHAN_WIDTH_40:415return (IEEE80211_STA_RX_BW_40);416case NL80211_CHAN_WIDTH_20:417case NL80211_CHAN_WIDTH_20_NOHT:418return (IEEE80211_STA_RX_BW_20);419case NL80211_CHAN_WIDTH_5:420case NL80211_CHAN_WIDTH_10:421/* Unsupported input. */422return (IEEE80211_STA_RX_BW_20);423}424}425426static enum nl80211_chan_width427lkpi_rx_bw_to_cw(enum ieee80211_sta_rx_bandwidth rx_bw)428{429switch (rx_bw) {430case IEEE80211_STA_RX_BW_20:431return (NL80211_CHAN_WIDTH_20); /* _NOHT */432case IEEE80211_STA_RX_BW_40:433return (NL80211_CHAN_WIDTH_40);434case IEEE80211_STA_RX_BW_80:435return (NL80211_CHAN_WIDTH_80);436case IEEE80211_STA_RX_BW_160:437return (NL80211_CHAN_WIDTH_160); /* 80P80 */438case IEEE80211_STA_RX_BW_320:439return (NL80211_CHAN_WIDTH_320);440}441}442443static void444lkpi_sync_chanctx_cw_from_rx_bw(struct ieee80211_hw *hw,445struct ieee80211_vif *vif, struct ieee80211_sta *sta)446{447struct ieee80211_chanctx_conf *chanctx_conf;448enum ieee80211_sta_rx_bandwidth old_bw;449uint32_t changed;450451chanctx_conf = rcu_dereference_protected(vif->bss_conf.chanctx_conf,452lockdep_is_held(&hw->wiphy->mtx));453if (chanctx_conf == NULL)454return;455456old_bw = lkpi_cw_to_rx_bw(chanctx_conf->def.width);457if (old_bw == sta->deflink.bandwidth)458return;459460chanctx_conf->def.width = lkpi_rx_bw_to_cw(sta->deflink.bandwidth);461if (chanctx_conf->def.width == NL80211_CHAN_WIDTH_20 &&462!sta->deflink.ht_cap.ht_supported)463chanctx_conf->def.width = NL80211_CHAN_WIDTH_20_NOHT;464465chanctx_conf->min_def = chanctx_conf->def;466467vif->bss_conf.chanreq.oper.width = chanctx_conf->def.width;468469changed = IEEE80211_CHANCTX_CHANGE_MIN_WIDTH;470changed |= IEEE80211_CHANCTX_CHANGE_WIDTH;471lkpi_80211_mo_change_chanctx(hw, chanctx_conf, changed);472}473474#if defined(LKPI_80211_HT)475static void476lkpi_sta_sync_ht_from_ni(struct ieee80211_vif *vif, struct ieee80211_sta *sta,477struct ieee80211_node *ni)478{479struct ieee80211vap *vap;480uint8_t *ie;481struct ieee80211_ht_cap *htcap;482int i, rx_nss;483484if ((ni->ni_flags & IEEE80211_NODE_HT) == 0) {485sta->deflink.ht_cap.ht_supported = false;486return;487}488489sta->deflink.ht_cap.ht_supported = true;490491/* htcap->ampdu_params_info */492vap = ni->ni_vap;493sta->deflink.ht_cap.ampdu_density = _IEEE80211_MASKSHIFT(ni->ni_htparam, IEEE80211_HTCAP_MPDUDENSITY);494if (sta->deflink.ht_cap.ampdu_density > vap->iv_ampdu_density)495sta->deflink.ht_cap.ampdu_density = vap->iv_ampdu_density;496sta->deflink.ht_cap.ampdu_factor = _IEEE80211_MASKSHIFT(ni->ni_htparam, IEEE80211_HTCAP_MAXRXAMPDU);497if (sta->deflink.ht_cap.ampdu_factor > vap->iv_ampdu_rxmax)498sta->deflink.ht_cap.ampdu_factor = vap->iv_ampdu_rxmax;499500ie = ni->ni_ies.htcap_ie;501KASSERT(ie != NULL, ("%s: HT but no htcap_ie on ni %p\n", __func__, ni));502if (ie[0] == IEEE80211_ELEMID_VENDOR)503ie += 4;504ie += 2;505htcap = (struct ieee80211_ht_cap *)ie;506sta->deflink.ht_cap.cap = htcap->cap_info;507sta->deflink.ht_cap.mcs = htcap->mcs;508509/*510* 802.11n-2009 20.6 Parameters for HT MCSs gives the mandatory/511* optional MCS for Nss=1..4. We need to check the first four512* MCS sets from the Rx MCS Bitmask; then there is MCS 32 and513* MCS33.. is UEQM.514*/515rx_nss = 0;516for (i = 0; i < 4; i++) {517if (htcap->mcs.rx_mask[i] != 0)518rx_nss++;519}520if (rx_nss > 0) {521sta->deflink.rx_nss = rx_nss;522} else {523sta->deflink.ht_cap.ht_supported = false;524return;525}526527if ((sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) != 0 &&528IEEE80211_IS_CHAN_HT40(ni->ni_chan))529sta->deflink.bandwidth = IEEE80211_STA_RX_BW_40;530else531sta->deflink.bandwidth = IEEE80211_STA_RX_BW_20;532533IMPROVE("sta->wme");534535if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_MAX_AMSDU)536sta->deflink.agg.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_HT_7935;537else538sta->deflink.agg.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_HT_3839;539sta->deflink.agg.max_rc_amsdu_len = IEEE80211_MAX_MPDU_LEN_HT_BA;540#ifdef __handled_by_driver__ /* iwlwifi only? actually unused? */541for (i = 0; i < nitems(sta.deflink.agg.max_tid_amsdu_len); i++) {542sta->deflink.agg.max_tid_amsdu_len[j] = ;543}544#endif545}546#endif547548#if defined(LKPI_80211_VHT)549static void550lkpi_sta_sync_vht_from_ni(struct ieee80211_vif *vif, struct ieee80211_sta *sta,551struct ieee80211_node *ni)552{553enum ieee80211_sta_rx_bandwidth bw;554uint32_t width;555int rx_nss;556uint16_t rx_mcs_map;557uint8_t mcs;558559if ((ni->ni_flags & IEEE80211_NODE_VHT) == 0 ||560!IEEE80211_IS_CHAN_VHT_5GHZ(ni->ni_chan)) {561sta->deflink.vht_cap.vht_supported = false;562return;563}564565sta->deflink.vht_cap.vht_supported = true;566567sta->deflink.vht_cap.cap = ni->ni_vhtcap;568sta->deflink.vht_cap.vht_mcs = ni->ni_vht_mcsinfo;569570/*571* If VHT20/40 are selected do not update the bandwidth572* from HT but stya on VHT.573*/574if (ni->ni_vht_chanwidth == IEEE80211_VHT_CHANWIDTH_USE_HT)575goto skip_bw;576577bw = sta->deflink.bandwidth;578width = (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK);579switch (width) {580/* Deprecated. */581case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:582case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:583bw = IEEE80211_STA_RX_BW_160;584break;585default:586/* Check if we do support 160Mhz somehow after all. */587if ((sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK) != 0)588bw = IEEE80211_STA_RX_BW_160;589else590bw = IEEE80211_STA_RX_BW_80;591}592/*593* While we can set what is possibly supported we also need to be594* on a channel which supports that bandwidth; e.g., we can support595* VHT160 but the AP only does VHT80.596* Further ni_chan will also have filtered out what we disabled597* by configuration.598* Once net80211 channel selection is fixed for 802.11-2020 and599* VHT160 we can possibly spare ourselves the above.600*/601if (bw == IEEE80211_STA_RX_BW_160 &&602!IEEE80211_IS_CHAN_VHT160(ni->ni_chan) &&603!IEEE80211_IS_CHAN_VHT80P80(ni->ni_chan))604bw = IEEE80211_STA_RX_BW_80;605if (bw == IEEE80211_STA_RX_BW_80 &&606!IEEE80211_IS_CHAN_VHT80(ni->ni_chan))607bw = sta->deflink.bandwidth;608sta->deflink.bandwidth = bw;609skip_bw:610611rx_nss = 0;612rx_mcs_map = sta->deflink.vht_cap.vht_mcs.rx_mcs_map;613for (int i = 7; i >= 0; i--) {614mcs = rx_mcs_map >> (2 * i);615mcs &= 0x3;616if (mcs != IEEE80211_VHT_MCS_NOT_SUPPORTED) {617rx_nss = i + 1;618break;619}620}621if (rx_nss > 0)622sta->deflink.rx_nss = rx_nss;623624switch (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK) {625case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:626sta->deflink.agg.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_11454;627break;628case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991:629sta->deflink.agg.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_7991;630break;631case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895:632default:633sta->deflink.agg.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_3895;634break;635}636}637#endif638639static void640lkpi_sta_sync_from_ni(struct ieee80211_hw *hw, struct ieee80211_vif *vif,641struct ieee80211_sta *sta, struct ieee80211_node *ni, bool updchnctx)642{643644#if defined(LKPI_80211_HT)645lkpi_sta_sync_ht_from_ni(vif, sta, ni);646#endif647#if defined(LKPI_80211_VHT)648lkpi_sta_sync_vht_from_ni(vif, sta, ni);649#endif650651/*652* Ensure rx_nss is at least 1 as otherwise drivers run into653* unexpected problems.654*/655sta->deflink.rx_nss = MAX(1, sta->deflink.rx_nss);656657/*658* We are also called from node allocation which net80211659* can do even on `ifconfig down`; in that case the chanctx660* may still be valid and we get a discrepancy between661* sta and chanctx. Thus do not try to update the chanctx662* when called from lkpi_lsta_alloc().663*/664if (updchnctx)665lkpi_sync_chanctx_cw_from_rx_bw(hw, vif, sta);666}667668static uint8_t669lkpi_get_max_rx_chains(struct ieee80211_node *ni)670{671uint8_t chains;672#if defined(LKPI_80211_HT) || defined(LKPI_80211_VHT)673struct lkpi_sta *lsta;674struct ieee80211_sta *sta;675676lsta = ni->ni_drv_data;677sta = LSTA_TO_STA(lsta);678#endif679680chains = 1;681#if defined(LKPI_80211_HT)682IMPROVE("We should factor counting MCS/NSS out for sync and here");683if (sta->deflink.ht_cap.ht_supported)684chains = MAX(chains, sta->deflink.rx_nss);685#endif686687#if defined(LKPI_80211_VHT)688if (sta->deflink.vht_cap.vht_supported)689chains = MAX(chains, sta->deflink.rx_nss);690#endif691692return (chains);693}694695static void696lkpi_lsta_dump(struct lkpi_sta *lsta, struct ieee80211_node *ni,697const char *_f, int _l)698{699700#ifdef LINUXKPI_DEBUG_80211701if ((linuxkpi_debug_80211 & D80211_TRACE_STA) == 0)702return;703if (lsta == NULL)704return;705706printf("%s:%d lsta %p ni %p sta %p\n",707_f, _l, lsta, ni, &lsta->sta);708if (ni != NULL)709ieee80211_dump_node(NULL, ni);710printf("\ttxq_task txq len %d mtx\n", mbufq_len(&lsta->txq));711printf("\tkc %p state %d added_to_drv %d in_mgd %d\n",712&lsta->kc[0], lsta->state, lsta->added_to_drv, lsta->in_mgd);713#endif714}715716static void717lkpi_lsta_remove(struct lkpi_sta *lsta, struct lkpi_vif *lvif)718{719720lockdep_assert_wiphy(lsta->hw->wiphy);721722KASSERT(!list_empty(&lsta->lsta_list),723("%s: lsta %p ni %p\n", __func__, lsta, lsta->ni));724list_del_init(&lsta->lsta_list);725}726727static struct lkpi_sta *728lkpi_lsta_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN],729struct ieee80211_hw *hw, struct ieee80211_node *ni)730{731struct lkpi_sta *lsta;732struct lkpi_vif *lvif;733struct ieee80211_vif *vif;734struct ieee80211_sta *sta;735int band, i, tid;736737lsta = malloc(sizeof(*lsta) + hw->sta_data_size, M_LKPI80211,738M_NOWAIT | M_ZERO);739if (lsta == NULL)740return (NULL);741742lsta->hw = hw;743lsta->added_to_drv = false;744lsta->state = IEEE80211_STA_NOTEXIST;745/*746* Link the ni to the lsta here without taking a reference.747* For one we would have to take the reference in node_init()748* as ieee80211_alloc_node() will initialise the refcount after us.749* For the other a ni and an lsta are 1:1 mapped and always together750* from [ic_]node_alloc() to [ic_]node_free() so we are essentally751* using the ni references for the lsta as well despite it being752* two separate allocations.753*/754lsta->ni = ni;755/* The back-pointer "drv_data" to net80211_node let's us get lsta. */756ni->ni_drv_data = lsta;757758lvif = VAP_TO_LVIF(vap);759vif = LVIF_TO_VIF(lvif);760sta = LSTA_TO_STA(lsta);761762IEEE80211_ADDR_COPY(sta->addr, mac);763764/* TXQ */765for (tid = 0; tid < nitems(sta->txq); tid++) {766struct lkpi_txq *ltxq;767768/* We are not limiting ourselves to hw.queues here. */769ltxq = malloc(sizeof(*ltxq) + hw->txq_data_size,770M_LKPI80211, M_NOWAIT | M_ZERO);771if (ltxq == NULL)772goto cleanup;773/* iwlwifi//mvm/sta.c::tid_to_mac80211_ac[] */774if (tid == IEEE80211_NUM_TIDS) {775if (!ieee80211_hw_check(hw, STA_MMPDU_TXQ)) {776free(ltxq, M_LKPI80211);777continue;778}779IMPROVE("AP/if we support non-STA here too");780ltxq->txq.ac = IEEE80211_AC_VO;781} else {782ltxq->txq.ac = ieee80211e_up_to_ac[tid & 7];783}784ltxq->seen_dequeue = false;785ltxq->stopped = false;786ltxq->txq.vif = vif;787ltxq->txq.tid = tid;788ltxq->txq.sta = sta;789TAILQ_ELEM_INIT(ltxq, txq_entry);790skb_queue_head_init(<xq->skbq);791LKPI_80211_LTXQ_LOCK_INIT(ltxq);792sta->txq[tid] = <xq->txq;793}794795/* Deflink information. */796for (band = 0; band < NUM_NL80211_BANDS; band++) {797struct ieee80211_supported_band *supband;798799supband = hw->wiphy->bands[band];800if (supband == NULL)801continue;802803for (i = 0; i < supband->n_bitrates; i++) {804switch (band) {805case NL80211_BAND_2GHZ:806switch (supband->bitrates[i].bitrate) {807case 240: /* 11g only */808case 120: /* 11g only */809case 110:810case 60: /* 11g only */811case 55:812case 20:813case 10:814sta->deflink.supp_rates[band] |= BIT(i);815break;816}817break;818case NL80211_BAND_5GHZ:819switch (supband->bitrates[i].bitrate) {820case 240:821case 120:822case 60:823sta->deflink.supp_rates[band] |= BIT(i);824break;825}826break;827}828}829}830831sta->deflink.smps_mode = IEEE80211_SMPS_OFF;832sta->deflink.bandwidth = IEEE80211_STA_RX_BW_20;833sta->deflink.rx_nss = 1;834835lkpi_sta_sync_from_ni(hw, vif, sta, ni, false);836837IMPROVE("he, eht, bw_320, ... smps_mode, ..");838839/* Link configuration. */840IEEE80211_ADDR_COPY(sta->deflink.addr, sta->addr);841sta->link[0] = &sta->deflink;842for (i = 1; i < nitems(sta->link); i++) {843IMPROVE("more links; only link[0] = deflink currently.");844}845IMPROVE("11be");846sta->mlo = false;847848/* Deferred TX path. */849LKPI_80211_LSTA_TXQ_LOCK_INIT(lsta);850TASK_INIT(&lsta->txq_task, 0, lkpi_80211_txq_task, lsta);851mbufq_init(&lsta->txq, 32 * NAPI_POLL_WEIGHT);852lsta->txq_ready = true;853854return (lsta);855856cleanup:857for (; tid >= 0; tid--) {858struct lkpi_txq *ltxq;859860ltxq = TXQ_TO_LTXQ(sta->txq[tid]);861LKPI_80211_LTXQ_LOCK_DESTROY(ltxq);862free(sta->txq[tid], M_LKPI80211);863}864free(lsta, M_LKPI80211);865return (NULL);866}867868static void869lkpi_lsta_free(struct lkpi_sta *lsta, struct ieee80211_node *ni)870{871struct mbuf *m;872873if (lsta->added_to_drv)874panic("%s: Trying to free an lsta still known to firmware: "875"lsta %p ni %p added_to_drv %d\n",876__func__, lsta, ni, lsta->added_to_drv);877878/* XXX-BZ free resources, ... */879IMPROVE();880881/* Drain sta->txq[] */882883LKPI_80211_LSTA_TXQ_LOCK(lsta);884lsta->txq_ready = false;885LKPI_80211_LSTA_TXQ_UNLOCK(lsta);886887/* Drain taskq, won't be restarted until added_to_drv is set again. */888while (taskqueue_cancel(taskqueue_thread, &lsta->txq_task, NULL) != 0)889taskqueue_drain(taskqueue_thread, &lsta->txq_task);890891/* Flush mbufq (make sure to release ni refs!). */892m = mbufq_dequeue(&lsta->txq);893while (m != NULL) {894struct ieee80211_node *nim;895896nim = (struct ieee80211_node *)m->m_pkthdr.rcvif;897if (nim != NULL)898ieee80211_free_node(nim);899m_freem(m);900m = mbufq_dequeue(&lsta->txq);901}902KASSERT(mbufq_empty(&lsta->txq), ("%s: lsta %p has txq len %d != 0\n",903__func__, lsta, mbufq_len(&lsta->txq)));904LKPI_80211_LSTA_TXQ_LOCK_DESTROY(lsta);905906/* Remove lsta from vif; that is done by the state machine. Should assert it? */907908IMPROVE("Make sure everything is cleaned up.");909910/* Free lsta. */911lsta->ni = NULL;912ni->ni_drv_data = NULL;913free(lsta, M_LKPI80211);914}915916917static enum nl80211_band918lkpi_net80211_chan_to_nl80211_band(struct ieee80211_channel *c)919{920921if (IEEE80211_IS_CHAN_2GHZ(c))922return (NL80211_BAND_2GHZ);923else if (IEEE80211_IS_CHAN_5GHZ(c))924return (NL80211_BAND_5GHZ);925#ifdef __notyet__926else if ()927return (NL80211_BAND_6GHZ);928else if ()929return (NL80211_BAND_60GHZ);930else if (IEEE80211_IS_CHAN_GSM(c))931return (NL80211_BAND_XXX);932#endif933else934panic("%s: unsupported band. c %p flags %#x\n",935__func__, c, c->ic_flags);936}937938static uint32_t939lkpi_nl80211_band_to_net80211_band(enum nl80211_band band)940{941942/* XXX-BZ this is just silly; net80211 is too convoluted. */943/* IEEE80211_CHAN_A / _G / .. doesn't really work either. */944switch (band) {945case NL80211_BAND_2GHZ:946return (IEEE80211_CHAN_2GHZ);947break;948case NL80211_BAND_5GHZ:949return (IEEE80211_CHAN_5GHZ);950break;951case NL80211_BAND_60GHZ:952break;953case NL80211_BAND_6GHZ:954break;955default:956panic("%s: unsupported band %u\n", __func__, band);957break;958}959960IMPROVE();961return (0x00);962}963964#ifdef LINUXKPI_DEBUG_80211965static const char *966lkpi_nl80211_band_name(enum nl80211_band band)967{968switch (band) {969case NL80211_BAND_2GHZ:970return "2Ghz";971break;972case NL80211_BAND_5GHZ:973return "5Ghz";974break;975case NL80211_BAND_60GHZ:976return "60Ghz";977break;978case NL80211_BAND_6GHZ:979return "6Ghz";980break;981default:982panic("%s: unsupported band %u\n", __func__, band);983break;984}985}986#endif987988#if 0989static enum ieee80211_ac_numbers990lkpi_ac_net_to_l80211(int ac)991{992993switch (ac) {994case WME_AC_VO:995return (IEEE80211_AC_VO);996case WME_AC_VI:997return (IEEE80211_AC_VI);998case WME_AC_BE:999return (IEEE80211_AC_BE);1000case WME_AC_BK:1001return (IEEE80211_AC_BK);1002default:1003printf("%s: invalid WME_AC_* input: ac = %d\n", __func__, ac);1004return (IEEE80211_AC_BE);1005}1006}1007#endif10081009static enum nl80211_iftype1010lkpi_opmode_to_vif_type(enum ieee80211_opmode opmode)1011{10121013switch (opmode) {1014case IEEE80211_M_IBSS:1015return (NL80211_IFTYPE_ADHOC);1016break;1017case IEEE80211_M_STA:1018return (NL80211_IFTYPE_STATION);1019break;1020case IEEE80211_M_WDS:1021return (NL80211_IFTYPE_WDS);1022break;1023case IEEE80211_M_HOSTAP:1024return (NL80211_IFTYPE_AP);1025break;1026case IEEE80211_M_MONITOR:1027return (NL80211_IFTYPE_MONITOR);1028break;1029case IEEE80211_M_MBSS:1030return (NL80211_IFTYPE_MESH_POINT);1031break;1032case IEEE80211_M_AHDEMO:1033/* FALLTHROUGH */1034default:1035printf("ERROR: %s: unsupported opmode %d\n", __func__, opmode);1036/* FALLTHROUGH */1037}1038return (NL80211_IFTYPE_UNSPECIFIED);1039}10401041#ifdef LKPI_80211_HW_CRYPTO1042static const char *1043lkpi_cipher_suite_to_name(uint32_t wlan_cipher_suite)1044{1045switch (wlan_cipher_suite) {1046case WLAN_CIPHER_SUITE_WEP40:1047return ("WEP40");1048case WLAN_CIPHER_SUITE_WEP104:1049return ("WEP104");1050case WLAN_CIPHER_SUITE_TKIP:1051return ("TKIP");1052case WLAN_CIPHER_SUITE_CCMP:1053return ("CCMP");1054case WLAN_CIPHER_SUITE_CCMP_256:1055return ("CCMP_256");1056case WLAN_CIPHER_SUITE_GCMP:1057return ("GCMP");1058case WLAN_CIPHER_SUITE_GCMP_256:1059return ("GCMP_256");1060case WLAN_CIPHER_SUITE_AES_CMAC:1061return ("AES_CMAC");1062case WLAN_CIPHER_SUITE_BIP_CMAC_256:1063return ("BIP_CMAC_256");1064case WLAN_CIPHER_SUITE_BIP_GMAC_128:1065return ("BIP_GMAC_128");1066case WLAN_CIPHER_SUITE_BIP_GMAC_256:1067return ("BIP_GMAC_256");1068default:1069return ("??");1070}1071}10721073static uint32_t1074lkpi_l80211_to_net80211_cyphers(struct ieee80211com *ic,1075uint32_t wlan_cipher_suite)1076{1077switch (wlan_cipher_suite) {1078case WLAN_CIPHER_SUITE_WEP40:1079return (IEEE80211_CRYPTO_WEP);1080case WLAN_CIPHER_SUITE_WEP104:1081return (IEEE80211_CRYPTO_WEP);1082case WLAN_CIPHER_SUITE_TKIP:1083return (IEEE80211_CRYPTO_TKIP);1084case WLAN_CIPHER_SUITE_CCMP:1085return (IEEE80211_CRYPTO_AES_CCM);1086case WLAN_CIPHER_SUITE_CCMP_256:1087return (IEEE80211_CRYPTO_AES_CCM_256);1088case WLAN_CIPHER_SUITE_GCMP:1089return (IEEE80211_CRYPTO_AES_GCM_128);1090case WLAN_CIPHER_SUITE_GCMP_256:1091return (IEEE80211_CRYPTO_AES_GCM_256);1092case WLAN_CIPHER_SUITE_AES_CMAC:1093return (IEEE80211_CRYPTO_BIP_CMAC_128);1094case WLAN_CIPHER_SUITE_BIP_CMAC_256:1095return (IEEE80211_CRYPTO_BIP_CMAC_256);1096case WLAN_CIPHER_SUITE_BIP_GMAC_128:1097return (IEEE80211_CRYPTO_BIP_GMAC_128);1098case WLAN_CIPHER_SUITE_BIP_GMAC_256:1099return (IEEE80211_CRYPTO_BIP_GMAC_256);1100default:1101ic_printf(ic, "%s: unknown WLAN Cipher Suite %#08x | %u (%s)\n",1102__func__,1103wlan_cipher_suite >> 8, wlan_cipher_suite & 0xff,1104lkpi_cipher_suite_to_name(wlan_cipher_suite));1105return (0);1106}1107}11081109static uint32_t1110lkpi_net80211_to_l80211_cipher_suite(uint32_t cipher, uint8_t keylen)1111{11121113switch (cipher) {1114case IEEE80211_CIPHER_WEP:1115if (keylen == (40/NBBY))1116return (WLAN_CIPHER_SUITE_WEP40);1117else if (keylen == (104/NBBY))1118return (WLAN_CIPHER_SUITE_WEP104);1119else {1120printf("%s: WEP with unsupported keylen %d\n",1121__func__, keylen * NBBY);1122return (0);1123}1124break;1125case IEEE80211_CIPHER_TKIP:1126return (WLAN_CIPHER_SUITE_TKIP);1127case IEEE80211_CIPHER_AES_CCM:1128return (WLAN_CIPHER_SUITE_CCMP);1129case IEEE80211_CIPHER_AES_CCM_256:1130return (WLAN_CIPHER_SUITE_CCMP_256);1131case IEEE80211_CIPHER_AES_GCM_128:1132return (WLAN_CIPHER_SUITE_GCMP);1133case IEEE80211_CIPHER_AES_GCM_256:1134return (WLAN_CIPHER_SUITE_GCMP_256);1135case IEEE80211_CIPHER_BIP_CMAC_128:1136return (WLAN_CIPHER_SUITE_AES_CMAC);1137case IEEE80211_CIPHER_BIP_CMAC_256:1138return (WLAN_CIPHER_SUITE_BIP_CMAC_256);1139case IEEE80211_CIPHER_BIP_GMAC_128:1140return (WLAN_CIPHER_SUITE_BIP_GMAC_128);1141case IEEE80211_CIPHER_BIP_GMAC_256:1142return (WLAN_CIPHER_SUITE_BIP_GMAC_256);11431144case IEEE80211_CIPHER_AES_OCB:1145case IEEE80211_CIPHER_TKIPMIC:1146/*1147* TKIP w/ hw MIC support1148* (gone wrong; should really be a crypto flag in net80211).1149*/1150case IEEE80211_CIPHER_CKIP:1151case IEEE80211_CIPHER_NONE:1152printf("%s: unsupported cipher %#010x\n", __func__, cipher);1153break;1154default:1155printf("%s: unknown cipher %#010x\n", __func__, cipher);1156};1157return (0);1158}1159#endif11601161#ifdef __notyet__1162static enum ieee80211_sta_state1163lkpi_net80211_state_to_sta_state(enum ieee80211_state state)1164{11651166/*1167* XXX-BZ The net80211 states are "try to ..", the lkpi8011 states are1168* "done". Also ASSOC/AUTHORIZED are both "RUN" then?1169*/1170switch (state) {1171case IEEE80211_S_INIT:1172return (IEEE80211_STA_NOTEXIST);1173case IEEE80211_S_SCAN:1174return (IEEE80211_STA_NONE);1175case IEEE80211_S_AUTH:1176return (IEEE80211_STA_AUTH);1177case IEEE80211_S_ASSOC:1178return (IEEE80211_STA_ASSOC);1179case IEEE80211_S_RUN:1180return (IEEE80211_STA_AUTHORIZED);1181case IEEE80211_S_CAC:1182case IEEE80211_S_CSA:1183case IEEE80211_S_SLEEP:1184default:1185UNIMPLEMENTED;1186};11871188return (IEEE80211_STA_NOTEXIST);1189}1190#endif11911192static struct linuxkpi_ieee80211_channel *1193lkpi_find_lkpi80211_chan(struct lkpi_hw *lhw,1194struct ieee80211_channel *c)1195{1196struct ieee80211_hw *hw;1197struct linuxkpi_ieee80211_channel *channels;1198enum nl80211_band band;1199int i, nchans;12001201hw = LHW_TO_HW(lhw);1202band = lkpi_net80211_chan_to_nl80211_band(c);1203if (hw->wiphy->bands[band] == NULL)1204return (NULL);12051206nchans = hw->wiphy->bands[band]->n_channels;1207if (nchans <= 0)1208return (NULL);12091210channels = hw->wiphy->bands[band]->channels;1211for (i = 0; i < nchans; i++) {1212if (channels[i].center_freq == c->ic_freq)1213return (&channels[i]);1214}12151216return (NULL);1217}12181219#if 01220static struct linuxkpi_ieee80211_channel *1221lkpi_get_lkpi80211_chan(struct ieee80211com *ic, struct ieee80211_node *ni)1222{1223struct linuxkpi_ieee80211_channel *chan;1224struct ieee80211_channel *c;1225struct lkpi_hw *lhw;12261227chan = NULL;1228if (ni != NULL && ni->ni_chan != IEEE80211_CHAN_ANYC)1229c = ni->ni_chan;1230else if (ic->ic_bsschan != IEEE80211_CHAN_ANYC)1231c = ic->ic_bsschan;1232else if (ic->ic_curchan != IEEE80211_CHAN_ANYC)1233c = ic->ic_curchan;1234else1235c = NULL;12361237if (c != NULL && c != IEEE80211_CHAN_ANYC) {1238lhw = ic->ic_softc;1239chan = lkpi_find_lkpi80211_chan(lhw, c);1240}12411242return (chan);1243}1244#endif12451246struct linuxkpi_ieee80211_channel *1247linuxkpi_ieee80211_get_channel(struct wiphy *wiphy, uint32_t freq)1248{1249enum nl80211_band band;12501251for (band = 0; band < NUM_NL80211_BANDS; band++) {1252struct ieee80211_supported_band *supband;1253struct linuxkpi_ieee80211_channel *channels;1254int i;12551256supband = wiphy->bands[band];1257if (supband == NULL || supband->n_channels == 0)1258continue;12591260channels = supband->channels;1261for (i = 0; i < supband->n_channels; i++) {1262if (channels[i].center_freq == freq)1263return (&channels[i]);1264}1265}12661267return (NULL);1268}12691270#ifdef LKPI_80211_HW_CRYPTO1271static int1272lkpi_sta_del_keys(struct ieee80211_hw *hw, struct ieee80211_vif *vif,1273struct lkpi_sta *lsta)1274{1275int error;12761277if (!lkpi_hwcrypto)1278return (0);12791280lockdep_assert_wiphy(hw->wiphy);1281ieee80211_ref_node(lsta->ni);12821283error = 0;1284for (ieee80211_keyix keyix = 0; keyix < nitems(lsta->kc); keyix++) {1285struct ieee80211_key_conf *kc;1286int err;12871288if (lsta->kc[keyix] == NULL)1289continue;1290kc = lsta->kc[keyix];12911292#ifdef LINUXKPI_DEBUG_802111293if (linuxkpi_debug_80211 & D80211_TRACE_HW_CRYPTO)1294ic_printf(lsta->ni->ni_ic, "%d %lu %s: running set_key cmd %d(%s) for "1295"sta %6D: keyidx %u hw_key_idx %u flags %b\n",1296curthread->td_tid, jiffies, __func__,1297DISABLE_KEY, "DISABLE", lsta->sta.addr, ":",1298kc->keyidx, kc->hw_key_idx, kc->flags, IEEE80211_KEY_FLAG_BITS);1299#endif13001301err = lkpi_80211_mo_set_key(hw, DISABLE_KEY, vif,1302LSTA_TO_STA(lsta), kc);1303if (err != 0) {1304ic_printf(lsta->ni->ni_ic, "%d %lu %s: set_key cmd %d(%s) for "1305"sta %6D failed: %d\n", curthread->td_tid, jiffies, __func__,1306DISABLE_KEY, "DISABLE", lsta->sta.addr, ":", err);1307error++;13081309/*1310* If we free the key here we will never be able to get it1311* removed from the driver/fw which will likely make us1312* crash (firmware).1313*/1314continue;1315}1316#ifdef LINUXKPI_DEBUG_802111317if (linuxkpi_debug_80211 & D80211_TRACE_HW_CRYPTO)1318ic_printf(lsta->ni->ni_ic, "%d %lu %s: set_key cmd %d(%s) for "1319"sta %6D succeeded: keyidx %u hw_key_idx %u flags %b\n",1320curthread->td_tid, jiffies, __func__,1321DISABLE_KEY, "DISABLE", lsta->sta.addr, ":",1322kc->keyidx, kc->hw_key_idx, kc->flags, IEEE80211_KEY_FLAG_BITS);1323#endif13241325lsta->kc[keyix] = NULL;1326free(kc, M_LKPI80211);1327}1328ieee80211_free_node(lsta->ni);1329return (error);1330}13311332/* XXX-BZ one day we should replace this iterating over VIFs, or node list? */1333/* See also lkpi_sta_del_keys() these days. */1334static int1335lkpi_iv_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k)1336{1337struct ieee80211com *ic;1338struct lkpi_hw *lhw;1339struct ieee80211_hw *hw;1340struct lkpi_vif *lvif;1341struct lkpi_sta *lsta;1342struct ieee80211_vif *vif;1343struct ieee80211_sta *sta;1344struct ieee80211_node *ni;1345struct ieee80211_key_conf *kc;1346int error;13471348ic = vap->iv_ic;1349lhw = ic->ic_softc;1350hw = LHW_TO_HW(lhw);1351lvif = VAP_TO_LVIF(vap);1352vif = LVIF_TO_VIF(lvif);13531354/*1355* Make sure we do not make it here without going through1356* lkpi_iv_key_update_begin() first.1357*/1358lockdep_assert_wiphy(hw->wiphy);13591360/*1361* While we are assoc we may still send packets. We cannot delete the1362* keys as otherwise packets could go out unencrypted. Some firmware1363* does not like this and will fire an assert.1364* net80211 needs to drive this better but given we want the disassoc1365* frame out and have to unlock we are open to a race currently.1366* This check should prevent problems.1367* How to test: run 800Mbit/s UDP traffic and during that restart your1368* supplicant. You want to survive that.1369*/1370if (vif->cfg.assoc) {1371if (linuxkpi_debug_80211 & D80211_TRACE_HW_CRYPTO)1372ic_printf(ic, "%d %lu %s: vif still assoc; not deleting keys\n",1373curthread->td_tid, jiffies, __func__);1374return (0);1375}13761377if (IEEE80211_KEY_UNDEFINED(k)) {1378ic_printf(ic, "%s: vap %p key %p is undefined: %p %u\n",1379__func__, vap, k, k->wk_cipher, k->wk_keyix);1380return (0);1381}13821383if (vap->iv_bss == NULL) {1384ic_printf(ic, "%s: iv_bss %p for vap %p is NULL\n",1385__func__, vap->iv_bss, vap);1386return (0);1387}13881389ni = ieee80211_ref_node(vap->iv_bss);1390lsta = ni->ni_drv_data;1391if (lsta == NULL) {1392ic_printf(ic, "%s: ni %p (%6D) with lsta NULL\n",1393__func__, ni, ni->ni_bssid, ":");1394ieee80211_free_node(ni);1395return (0);1396}1397sta = LSTA_TO_STA(lsta);13981399if (lsta->kc[k->wk_keyix] == NULL) {1400#ifdef LINUXKPI_DEBUG_802111401if (linuxkpi_debug_80211 & D80211_TRACE_HW_CRYPTO)1402ic_printf(ic, "%d %lu %s: sta %6D and no key information, "1403"keyidx %u wk_macaddr %6D; returning success\n",1404curthread->td_tid, jiffies, __func__, sta->addr, ":",1405k->wk_keyix, k->wk_macaddr, ":");1406#endif1407ieee80211_free_node(ni);1408return (1);1409}1410kc = lsta->kc[k->wk_keyix];14111412#ifdef LINUXKPI_DEBUG_802111413if (linuxkpi_debug_80211 & D80211_TRACE_HW_CRYPTO)1414ic_printf(ic, "%d %lu %s: running set_key cmd %d(%s) for sta %6D: "1415"keyidx %u hw_key_idx %u flags %b\n",1416curthread->td_tid, jiffies, __func__,1417DISABLE_KEY, "DISABLE", sta->addr, ":",1418kc->keyidx, kc->hw_key_idx, kc->flags, IEEE80211_KEY_FLAG_BITS);1419#endif14201421error = lkpi_80211_mo_set_key(hw, DISABLE_KEY, vif, sta, kc);1422if (error != 0) {1423ic_printf(ic, "%d %lu %s: set_key cmd %d(%s) for sta %6D failed: %d\n",1424curthread->td_tid, jiffies, __func__,1425DISABLE_KEY, "DISABLE", sta->addr, ":", error);1426error = 0;1427goto out;1428}14291430#ifdef LINUXKPI_DEBUG_802111431if (linuxkpi_debug_80211 & D80211_TRACE_HW_CRYPTO)1432ic_printf(ic, "%d %lu %s: set_key cmd %d(%s) for sta %6D succeeded: "1433"keyidx %u hw_key_idx %u flags %b\n",1434curthread->td_tid, jiffies, __func__,1435DISABLE_KEY, "DISABLE", sta->addr, ":",1436kc->keyidx, kc->hw_key_idx, kc->flags, IEEE80211_KEY_FLAG_BITS);1437#endif1438lsta->kc[k->wk_keyix] = NULL;1439free(kc, M_LKPI80211);1440error = 1;1441out:1442ieee80211_free_node(ni);1443return (error);1444}14451446static int1447lkpi_iv_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k)1448{1449struct ieee80211com *ic;1450struct lkpi_hw *lhw;1451struct ieee80211_hw *hw;1452struct lkpi_vif *lvif;1453struct lkpi_sta *lsta;1454struct ieee80211_vif *vif;1455struct ieee80211_sta *sta;1456struct ieee80211_node *ni;1457struct ieee80211_key_conf *kc;1458uint32_t lcipher;1459uint16_t exp_flags;1460uint8_t keylen;1461int error;14621463ic = vap->iv_ic;1464lhw = ic->ic_softc;1465hw = LHW_TO_HW(lhw);14661467/*1468* Make sure we do not make it here without going through1469* lkpi_iv_key_update_begin() first.1470*/1471lockdep_assert_wiphy(hw->wiphy);14721473if (IEEE80211_KEY_UNDEFINED(k)) {1474ic_printf(ic, "%s: vap %p key %p is undefined: %p %u\n",1475__func__, vap, k, k->wk_cipher, k->wk_keyix);1476return (0);1477}14781479if (vap->iv_bss == NULL) {1480ic_printf(ic, "%s: iv_bss %p for vap %p is NULL\n",1481__func__, vap->iv_bss, vap);1482return (0);1483}1484ni = ieee80211_ref_node(vap->iv_bss);1485lsta = ni->ni_drv_data;1486if (lsta == NULL) {1487ic_printf(ic, "%s: ni %p (%6D) with lsta NULL\n",1488__func__, ni, ni->ni_bssid, ":");1489ieee80211_free_node(ni);1490return (0);1491}1492sta = LSTA_TO_STA(lsta);14931494keylen = k->wk_keylen;1495lcipher = lkpi_net80211_to_l80211_cipher_suite(1496k->wk_cipher->ic_cipher, k->wk_keylen);1497switch (lcipher) {1498case WLAN_CIPHER_SUITE_TKIP:1499keylen += 2 * k->wk_cipher->ic_miclen;1500break;1501case WLAN_CIPHER_SUITE_CCMP:1502case WLAN_CIPHER_SUITE_GCMP:1503break;1504default:1505ic_printf(ic, "%s: CIPHER SUITE %#x (%s) not supported\n",1506__func__, lcipher, lkpi_cipher_suite_to_name(lcipher));1507IMPROVE();1508ieee80211_free_node(ni);1509return (0);1510}15111512if (lsta->kc[k->wk_keyix] != NULL) {1513IMPROVE("Still in firmware? Del first. Can we assert this cannot happen?");1514ic_printf(ic, "%s: sta %6D found with key information\n",1515__func__, sta->addr, ":");1516kc = lsta->kc[k->wk_keyix];1517lsta->kc[k->wk_keyix] = NULL;1518free(kc, M_LKPI80211);1519kc = NULL; /* safeguard */1520}15211522kc = malloc(sizeof(*kc) + keylen, M_LKPI80211, M_WAITOK | M_ZERO);1523kc->_k = k; /* Save the pointer to net80211. */1524kc->cipher = lcipher;1525kc->keyidx = k->wk_keyix;1526#if 01527kc->hw_key_idx = /* set by hw and needs to be passed for TX */;1528#endif1529atomic64_set(&kc->tx_pn, k->wk_keytsc);1530kc->keylen = k->wk_keylen;1531memcpy(kc->key, k->wk_key, k->wk_keylen);15321533if (k->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))1534kc->flags |= IEEE80211_KEY_FLAG_PAIRWISE;1535if (k->wk_flags & IEEE80211_KEY_GROUP)1536kc->flags &= ~IEEE80211_KEY_FLAG_PAIRWISE;15371538kc->iv_len = k->wk_cipher->ic_header;1539kc->icv_len = k->wk_cipher->ic_trailer;15401541switch (kc->cipher) {1542case WLAN_CIPHER_SUITE_TKIP:1543memcpy(kc->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY, k->wk_txmic, k->wk_cipher->ic_miclen);1544memcpy(kc->key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY, k->wk_rxmic, k->wk_cipher->ic_miclen);1545break;1546case WLAN_CIPHER_SUITE_CCMP:1547case WLAN_CIPHER_SUITE_GCMP:1548break;1549default:1550/* currently UNREACH */1551IMPROVE();1552break;1553};1554lsta->kc[k->wk_keyix] = kc;15551556#ifdef LINUXKPI_DEBUG_802111557if (linuxkpi_debug_80211 & D80211_TRACE_HW_CRYPTO)1558ic_printf(ic, "%d %lu %s: running set_key cmd %d(%s) for sta %6D: "1559"kc %p keyidx %u hw_key_idx %u keylen %u flags %b\n",1560curthread->td_tid, jiffies, __func__,1561SET_KEY, "SET", sta->addr, ":", kc, kc->keyidx, kc->hw_key_idx,1562kc->keylen, kc->flags, IEEE80211_KEY_FLAG_BITS);1563#endif15641565lvif = VAP_TO_LVIF(vap);1566vif = LVIF_TO_VIF(lvif);1567error = lkpi_80211_mo_set_key(hw, SET_KEY, vif, sta, kc);1568if (error != 0) {1569ic_printf(ic, "%d %lu %s: set_key cmd %d(%s) for sta %6D failed: %d\n",1570curthread->td_tid, jiffies, __func__,1571SET_KEY, "SET", sta->addr, ":", error);1572lsta->kc[k->wk_keyix] = NULL;1573free(kc, M_LKPI80211);1574ieee80211_free_node(ni);1575return (0);1576}15771578#ifdef LINUXKPI_DEBUG_802111579if (linuxkpi_debug_80211 & D80211_TRACE_HW_CRYPTO)1580ic_printf(ic, "%d %lu %s: set_key cmd %d(%s) for sta %6D succeeded: "1581"kc %p keyidx %u hw_key_idx %u flags %b\n",1582curthread->td_tid, jiffies, __func__,1583SET_KEY, "SET", sta->addr, ":",1584kc, kc->keyidx, kc->hw_key_idx, kc->flags, IEEE80211_KEY_FLAG_BITS);1585#endif15861587exp_flags = 0;1588switch (kc->cipher) {1589case WLAN_CIPHER_SUITE_TKIP:1590exp_flags = (IEEE80211_KEY_FLAG_PAIRWISE |1591IEEE80211_KEY_FLAG_PUT_IV_SPACE |1592IEEE80211_KEY_FLAG_GENERATE_MMIC |1593IEEE80211_KEY_FLAG_PUT_MIC_SPACE);1594#define TKIP_INVAL_COMBINATION \1595(IEEE80211_KEY_FLAG_PUT_MIC_SPACE|IEEE80211_KEY_FLAG_GENERATE_MMIC)1596if ((kc->flags & TKIP_INVAL_COMBINATION) == TKIP_INVAL_COMBINATION) {1597ic_printf(ic, "%s: SET_KEY for %s returned invalid "1598"combination %b\n", __func__,1599lkpi_cipher_suite_to_name(kc->cipher),1600kc->flags, IEEE80211_KEY_FLAG_BITS);1601}1602#undef TKIP_INVAL_COMBINATION1603#ifdef __notyet__1604/* Do flags surgery; special see linuxkpi_ieee80211_ifattach(). */1605if ((kc->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) != 0) {1606k->wk_flags &= ~(IEEE80211_KEY_NOMICMGT|IEEE80211_KEY_NOMIC);1607k->wk_flags |= IEEE80211_KEY_SWMIC;1608ic->ic_cryptocaps &= ~IEEE80211_CRYPTO_TKIPMIC1609}1610#endif1611break;1612case WLAN_CIPHER_SUITE_CCMP:1613case WLAN_CIPHER_SUITE_GCMP:1614exp_flags = (IEEE80211_KEY_FLAG_PAIRWISE |1615IEEE80211_KEY_FLAG_PUT_IV_SPACE |1616IEEE80211_KEY_FLAG_GENERATE_IV |1617IEEE80211_KEY_FLAG_GENERATE_IV_MGMT | /* Only needs IV geeration for MGMT frames. */1618IEEE80211_KEY_FLAG_SW_MGMT_TX); /* MFP in software */1619break;1620}1621if ((kc->flags & ~exp_flags) != 0)1622ic_printf(ic, "%s: SET_KEY for %s returned unexpected key flags: "1623" %#06x & ~%#06x = %b\n", __func__,1624lkpi_cipher_suite_to_name(kc->cipher), kc->flags, exp_flags,1625(kc->flags & ~exp_flags), IEEE80211_KEY_FLAG_BITS);16261627#ifdef __notyet__1628/* Do flags surgery. */1629if ((kc->flags & IEEE80211_KEY_FLAG_GENERATE_IV_MGMT) == 0)1630k->wk_flags |= IEEE80211_KEY_NOIVMGT;1631if ((kc->flags & IEEE80211_KEY_FLAG_GENERATE_IV) == 0)1632k->wk_flags |= IEEE80211_KEY_NOIV;1633#endif16341635ieee80211_free_node(ni);1636return (1);1637}16381639static void1640lkpi_iv_key_update_begin(struct ieee80211vap *vap)1641{1642struct ieee80211_node_table *nt;1643struct ieee80211com *ic;1644struct lkpi_hw *lhw;1645struct ieee80211_hw *hw;1646struct lkpi_vif *lvif;1647struct ieee80211_node *ni;1648bool icislocked, ntislocked;16491650ic = vap->iv_ic;1651lhw = ic->ic_softc;1652hw = LHW_TO_HW(lhw);1653lvif = VAP_TO_LVIF(vap);1654nt = &ic->ic_sta;16551656icislocked = IEEE80211_IS_LOCKED(ic);1657ntislocked = IEEE80211_NODE_IS_LOCKED(nt);16581659#ifdef LINUXKPI_DEBUG_802111660if (linuxkpi_debug_80211 & D80211_TRACE_HW_CRYPTO)1661ic_printf(ic, "%d %lu %s: vap %p ic %p %slocked nt %p %slocked "1662"lvif ic_unlocked %d nt_unlocked %d\n",1663curthread->td_tid, jiffies, __func__, vap,1664ic, icislocked ? "" : "un", nt, ntislocked ? "" : "un",1665lvif->ic_unlocked, lvif->nt_unlocked);1666#endif16671668/*1669* This is inconsistent net80211 locking to be fixed one day.1670*/1671/* Try to make sure the node does not go away while possibly unlocked. */1672ni = NULL;1673if (icislocked || ntislocked) {1674if (vap->iv_bss != NULL)1675ni = ieee80211_ref_node(vap->iv_bss);1676}16771678if (icislocked)1679IEEE80211_UNLOCK(ic);1680if (ntislocked)1681IEEE80211_NODE_UNLOCK(nt);16821683wiphy_lock(hw->wiphy);16841685KASSERT(lvif->key_update_iv_bss == NULL, ("%s: key_update_iv_bss not NULL %p",1686__func__, lvif->key_update_iv_bss));1687lvif->key_update_iv_bss = ni;16881689/*1690* ic/nt_unlocked could be a bool given we are under the lock and there1691* must only be a single thread.1692* In case anything in the future disturbs the order the refcnt will1693* help us catching problems a lot easier.1694*/1695if (icislocked)1696refcount_acquire(&lvif->ic_unlocked);1697if (ntislocked)1698refcount_acquire(&lvif->nt_unlocked);16991700/*1701* Stop the queues while doing key updates.1702*/1703ieee80211_stop_queues(hw);1704}17051706static void1707lkpi_iv_key_update_end(struct ieee80211vap *vap)1708{1709struct ieee80211_node_table *nt;1710struct ieee80211com *ic;1711struct lkpi_hw *lhw;1712struct ieee80211_hw *hw;1713struct lkpi_vif *lvif;1714bool icislocked, ntislocked;17151716ic = vap->iv_ic;1717lhw = ic->ic_softc;1718hw = LHW_TO_HW(lhw);1719lvif = VAP_TO_LVIF(vap);1720nt = &ic->ic_sta;17211722/*1723* Re-enabled the queues after the key update.1724*/1725lkpi_ieee80211_wake_queues_locked(hw);17261727icislocked = IEEE80211_IS_LOCKED(ic);1728MPASS(!icislocked);1729ntislocked = IEEE80211_NODE_IS_LOCKED(nt);1730MPASS(!ntislocked);17311732#ifdef LINUXKPI_DEBUG_802111733if (linuxkpi_debug_80211 & D80211_TRACE_HW_CRYPTO)1734ic_printf(ic, "%d %lu %s: vap %p ic %p %slocked nt %p %slocked "1735"lvif ic_unlocked %d nt_unlocked %d\n",1736curthread->td_tid, jiffies, __func__, vap,1737ic, icislocked ? "" : "un", nt, ntislocked ? "" : "un",1738lvif->ic_unlocked, lvif->nt_unlocked);1739#endif17401741/*1742* Check under lock; see comment in lkpi_iv_key_update_begin().1743* In case the refcnt gets out of sync locking in net80211 will1744* quickly barf as well (trying to unlock a lock not held).1745*/1746icislocked = refcount_release_if_last(&lvif->ic_unlocked);1747ntislocked = refcount_release_if_last(&lvif->nt_unlocked);17481749if (lvif->key_update_iv_bss != NULL) {1750ieee80211_free_node(lvif->key_update_iv_bss);1751lvif->key_update_iv_bss = NULL;1752}17531754wiphy_unlock(hw->wiphy);17551756/*1757* This is inconsistent net80211 locking to be fixed one day.1758* ic before nt to avoid a LOR.1759*/1760if (icislocked)1761IEEE80211_LOCK(ic);1762if (ntislocked)1763IEEE80211_NODE_LOCK(nt);1764}1765#endif17661767static void1768lkpi_cleanup_mcast_list_locked(struct lkpi_hw *lhw)1769{1770struct list_head *le, *next;1771struct netdev_hw_addr *addr;17721773if (lhw->mc_list.count != 0) {1774list_for_each_safe(le, next, &lhw->mc_list.addr_list) {1775addr = list_entry(le, struct netdev_hw_addr, addr_list);1776list_del(le);1777lhw->mc_list.count--;1778free(addr, M_LKPI80211);1779}1780}1781KASSERT(lhw->mc_list.count == 0, ("%s: mc_list %p count %d != 0\n",1782__func__, &lhw->mc_list, lhw->mc_list.count));1783}17841785static u_int1786lkpi_ic_update_mcast_copy(void *arg, struct sockaddr_dl *sdl, u_int cnt)1787{1788struct netdev_hw_addr_list *mc_list;1789struct netdev_hw_addr *addr;17901791KASSERT(arg != NULL && sdl != NULL, ("%s: arg %p sdl %p cnt %u\n",1792__func__, arg, sdl, cnt));17931794mc_list = arg;1795/* If it is on the list already skip it. */1796netdev_hw_addr_list_for_each(addr, mc_list) {1797if (!memcmp(addr->addr, LLADDR(sdl), sdl->sdl_alen))1798return (0);1799}18001801addr = malloc(sizeof(*addr), M_LKPI80211, M_NOWAIT | M_ZERO);1802if (addr == NULL)1803return (0);18041805INIT_LIST_HEAD(&addr->addr_list);1806memcpy(addr->addr, LLADDR(sdl), sdl->sdl_alen);1807/* XXX this should be a netdev function? */1808list_add(&addr->addr_list, &mc_list->addr_list);1809mc_list->count++;18101811#ifdef LINUXKPI_DEBUG_802111812if (linuxkpi_debug_80211 & D80211_TRACE)1813printf("%s:%d: mc_list count %d: added %6D\n",1814__func__, __LINE__, mc_list->count, addr->addr, ":");1815#endif18161817return (1);1818}18191820static void1821lkpi_update_mcast_filter(struct ieee80211com *ic)1822{1823struct lkpi_hw *lhw;1824struct ieee80211_hw *hw;1825u64 mc;1826unsigned int changed_flags, flags;1827bool scanning;18281829lhw = ic->ic_softc;18301831if (lhw->ops->prepare_multicast == NULL ||1832lhw->ops->configure_filter == NULL)1833return;18341835LKPI_80211_LHW_SCAN_LOCK(lhw);1836scanning = (lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0;1837LKPI_80211_LHW_SCAN_UNLOCK(lhw);18381839LKPI_80211_LHW_MC_LOCK(lhw);18401841flags = 0;1842if (scanning)1843flags |= FIF_BCN_PRBRESP_PROMISC;1844if (lhw->mc_all_multi)1845flags |= FIF_ALLMULTI;18461847hw = LHW_TO_HW(lhw);1848mc = lkpi_80211_mo_prepare_multicast(hw, &lhw->mc_list);18491850changed_flags = (lhw->mc_flags ^ flags) & FIF_FLAGS_MASK;1851lkpi_80211_mo_configure_filter(hw, changed_flags, &flags, mc);1852lhw->mc_flags = flags;18531854#ifdef LINUXKPI_DEBUG_802111855if (linuxkpi_debug_80211 & D80211_TRACE)1856printf("%s: changed_flags %#06x count %d mc_flags %#010x\n",1857__func__, changed_flags, lhw->mc_list.count, lhw->mc_flags);1858#endif18591860LKPI_80211_LHW_MC_UNLOCK(lhw);1861}18621863static enum ieee80211_bss_changed1864lkpi_update_dtim_tsf(struct ieee80211_vif *vif, struct ieee80211_node *ni,1865struct ieee80211vap *vap, const char *_f, int _l)1866{1867enum ieee80211_bss_changed bss_changed;18681869bss_changed = 0;18701871#ifdef LINUXKPI_DEBUG_802111872if (linuxkpi_debug_80211 & D80211_TRACE)1873printf("%s:%d [%s:%d] assoc %d aid %d beacon_int %u "1874"dtim_period %u sync_dtim_count %u sync_tsf %ju "1875"sync_device_ts %u bss_changed %#010jx\n",1876__func__, __LINE__, _f, _l,1877vif->cfg.assoc, vif->cfg.aid,1878vif->bss_conf.beacon_int, vif->bss_conf.dtim_period,1879vif->bss_conf.sync_dtim_count,1880(uintmax_t)vif->bss_conf.sync_tsf,1881vif->bss_conf.sync_device_ts,1882(uintmax_t)bss_changed);1883#endif18841885if (vif->bss_conf.beacon_int != ni->ni_intval) {1886vif->bss_conf.beacon_int = ni->ni_intval;1887/* iwlwifi FW bug workaround; iwl_mvm_mac_sta_state. */1888if (vif->bss_conf.beacon_int < 16)1889vif->bss_conf.beacon_int = 16;1890bss_changed |= BSS_CHANGED_BEACON_INT;1891}18921893/*1894* lkpi_iv_sta_recv_mgmt() will directly call into this function.1895* iwlwifi(4) in iwl_mvm_bss_info_changed_station_common() will1896* stop seesion protection the moment it sees1897* BSS_CHANGED_BEACON_INFO (with the expectations that it was1898* "a beacon from the associated AP"). It will also update1899* the beacon filter in that case. This is the only place1900* we set the BSS_CHANGED_BEACON_INFO on the non-teardown1901* path so make sure we only do run this check once we are1902* assoc. (*iv_recv_mgmt)() will be called before we enter1903* here so the ni will be updates with information from the1904* beacon via net80211::sta_recv_mgmt(). We also need to1905* make sure we do not do it on every beacon we still may1906* get so only do if something changed. vif->bss_conf.dtim_period1907* should be 0 as we start up (we also reset it on teardown).1908*/1909if (vif->cfg.assoc &&1910vif->bss_conf.dtim_period != ni->ni_dtim_period &&1911ni->ni_dtim_period > 0) {1912vif->bss_conf.dtim_period = ni->ni_dtim_period;1913bss_changed |= BSS_CHANGED_BEACON_INFO;1914}19151916vif->bss_conf.sync_dtim_count = ni->ni_dtim_count;1917vif->bss_conf.sync_tsf = le64toh(ni->ni_tstamp.tsf);1918/* vif->bss_conf.sync_device_ts = set in linuxkpi_ieee80211_rx. */19191920#ifdef LINUXKPI_DEBUG_802111921if (linuxkpi_debug_80211 & D80211_TRACE)1922printf("%s:%d [%s:%d] assoc %d aid %d beacon_int %u "1923"dtim_period %u sync_dtim_count %u sync_tsf %ju "1924"sync_device_ts %u bss_changed %#010jx\n",1925__func__, __LINE__, _f, _l,1926vif->cfg.assoc, vif->cfg.aid,1927vif->bss_conf.beacon_int, vif->bss_conf.dtim_period,1928vif->bss_conf.sync_dtim_count,1929(uintmax_t)vif->bss_conf.sync_tsf,1930vif->bss_conf.sync_device_ts,1931(uintmax_t)bss_changed);1932#endif19331934return (bss_changed);1935}19361937static void1938lkpi_stop_hw_scan(struct lkpi_hw *lhw, struct ieee80211_vif *vif)1939{1940struct ieee80211_hw *hw;1941int error;1942bool cancel;19431944TRACE_SCAN(lhw->ic, "scan_flags %b", lhw->scan_flags, LKPI_LHW_SCAN_BITS);19451946LKPI_80211_LHW_SCAN_LOCK(lhw);1947cancel = (lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0;1948LKPI_80211_LHW_SCAN_UNLOCK(lhw);1949if (!cancel)1950return;19511952hw = LHW_TO_HW(lhw);19531954IEEE80211_UNLOCK(lhw->ic);1955wiphy_lock(hw->wiphy);1956/* Need to cancel the scan. */1957lkpi_80211_mo_cancel_hw_scan(hw, vif);1958wiphy_unlock(hw->wiphy);19591960/* Need to make sure we see ieee80211_scan_completed. */1961LKPI_80211_LHW_SCAN_LOCK(lhw);1962if ((lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0)1963error = msleep(lhw, &lhw->scan_mtx, 0, "lhwscanstop", hz/2);1964cancel = (lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0;1965LKPI_80211_LHW_SCAN_UNLOCK(lhw);19661967IEEE80211_LOCK(lhw->ic);19681969if (cancel)1970ic_printf(lhw->ic, "%s: failed to cancel scan: %d (%p, %p)\n",1971__func__, error, lhw, vif);1972}19731974static void1975lkpi_hw_conf_idle(struct ieee80211_hw *hw, bool new)1976{1977struct lkpi_hw *lhw;1978int error;1979bool old;19801981old = hw->conf.flags & IEEE80211_CONF_IDLE;1982if (old == new)1983return;19841985hw->conf.flags ^= IEEE80211_CONF_IDLE;1986error = lkpi_80211_mo_config(hw, IEEE80211_CONF_CHANGE_IDLE);1987if (error != 0 && error != EOPNOTSUPP) {1988lhw = HW_TO_LHW(hw);1989ic_printf(lhw->ic, "ERROR: %s: config %#0x returned %d\n",1990__func__, IEEE80211_CONF_CHANGE_IDLE, error);1991}1992}19931994static enum ieee80211_bss_changed1995lkpi_disassoc(struct ieee80211_sta *sta, struct ieee80211_vif *vif,1996struct lkpi_hw *lhw)1997{1998enum ieee80211_bss_changed changed;1999struct lkpi_vif *lvif;20002001changed = 0;2002sta->aid = 0;2003if (vif->cfg.assoc) {20042005vif->cfg.assoc = false;2006vif->cfg.aid = 0;2007changed |= BSS_CHANGED_ASSOC;2008IMPROVE();20092010lkpi_update_mcast_filter(lhw->ic);20112012/*2013* Executing the bss_info_changed(BSS_CHANGED_ASSOC) with2014* assoc = false right away here will remove the sta from2015* firmware for iwlwifi.2016* We no longer do this but only return the BSS_CHNAGED value.2017* The caller is responsible for removing the sta gong to2018* IEEE80211_STA_NOTEXIST and then executing the2019* bss_info_changed() update.2020* See lkpi_sta_run_to_init() for more detailed comment.2021*/20222023lvif = VIF_TO_LVIF(vif);2024lvif->beacons = 0;2025}20262027return (changed);2028}20292030static void2031lkpi_wake_tx_queues(struct ieee80211_hw *hw, struct ieee80211_sta *sta,2032bool dequeue_seen, bool no_emptyq)2033{2034struct lkpi_txq *ltxq;2035int tid;2036bool ltxq_empty;20372038/* Wake up all queues to know they are allocated in the driver. */2039for (tid = 0; tid < nitems(sta->txq); tid++) {20402041if (tid == IEEE80211_NUM_TIDS) {2042IMPROVE("station specific?");2043if (!ieee80211_hw_check(hw, STA_MMPDU_TXQ))2044continue;2045} else if (tid >= hw->queues)2046continue;20472048if (sta->txq[tid] == NULL)2049continue;20502051ltxq = TXQ_TO_LTXQ(sta->txq[tid]);2052if (dequeue_seen && !ltxq->seen_dequeue)2053continue;20542055LKPI_80211_LTXQ_LOCK(ltxq);2056ltxq_empty = skb_queue_empty(<xq->skbq);2057LKPI_80211_LTXQ_UNLOCK(ltxq);2058if (no_emptyq && ltxq_empty)2059continue;20602061lkpi_80211_mo_wake_tx_queue(hw, sta->txq[tid]);2062}2063}20642065/*2066* On the way down from RUN -> ASSOC -> AUTH we may send a DISASSOC or DEAUTH2067* packet. The problem is that the state machine functions tend to hold the2068* LHW lock which will prevent lkpi_80211_txq_tx_one() from sending the packet.2069* We call this after dropping the ic lock and before acquiring the LHW lock.2070* we make sure no further packets are queued and if they are queued the task2071* will finish or be cancelled. At the end if a packet is left we manually2072* send it. scan_to_auth() would re-enable sending if the lsta would be2073* re-used.2074*/2075static void2076lkpi_80211_flush_tx(struct lkpi_hw *lhw, struct lkpi_sta *lsta)2077{2078struct ieee80211_hw *hw;2079struct mbufq mq;2080struct mbuf *m;2081int len;20822083/* There is no lockdep_assert_not_held_wiphy(). */2084hw = LHW_TO_HW(lhw);2085lockdep_assert_not_held(&hw->wiphy->mtx);20862087/* Do not accept any new packets until scan_to_auth or lsta_free(). */2088LKPI_80211_LSTA_TXQ_LOCK(lsta);2089lsta->txq_ready = false;2090LKPI_80211_LSTA_TXQ_UNLOCK(lsta);20912092while (taskqueue_cancel(taskqueue_thread, &lsta->txq_task, NULL) != 0)2093taskqueue_drain(taskqueue_thread, &lsta->txq_task);20942095LKPI_80211_LSTA_TXQ_LOCK(lsta);2096len = mbufq_len(&lsta->txq);2097if (len <= 0) {2098LKPI_80211_LSTA_TXQ_UNLOCK(lsta);2099return;2100}21012102mbufq_init(&mq, IFQ_MAXLEN);2103mbufq_concat(&mq, &lsta->txq);2104LKPI_80211_LSTA_TXQ_UNLOCK(lsta);21052106m = mbufq_dequeue(&mq);2107while (m != NULL) {2108lkpi_80211_txq_tx_one(lsta, m);2109m = mbufq_dequeue(&mq);2110}2111}211221132114static void2115lkpi_remove_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif)2116{2117struct ieee80211_chanctx_conf *chanctx_conf;2118struct lkpi_chanctx *lchanctx;21192120chanctx_conf = rcu_dereference_protected(vif->bss_conf.chanctx_conf,2121lockdep_is_held(&hw->wiphy->mtx));21222123if (chanctx_conf == NULL)2124return;21252126/* Remove vif context. */2127lkpi_80211_mo_unassign_vif_chanctx(hw, vif, &vif->bss_conf, chanctx_conf);21282129lkpi_hw_conf_idle(hw, true);21302131/* Remove chan ctx. */2132lkpi_80211_mo_remove_chanctx(hw, chanctx_conf);21332134/* Cleanup. */2135rcu_assign_pointer(vif->bss_conf.chanctx_conf, NULL);2136lchanctx = CHANCTX_CONF_TO_LCHANCTX(chanctx_conf);2137list_del(&lchanctx->entry);2138free(lchanctx, M_LKPI80211);2139}214021412142/* -------------------------------------------------------------------------- */21432144static int2145lkpi_sta_state_do_nada(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)2146{21472148return (0);2149}21502151/* lkpi_iv_newstate() handles the stop scan case generally. */2152#define lkpi_sta_scan_to_init(_v, _n, _a) lkpi_sta_state_do_nada(_v, _n, _a)21532154static int2155lkpi_sta_scan_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)2156{2157struct linuxkpi_ieee80211_channel *chan;2158struct lkpi_chanctx *lchanctx;2159struct ieee80211_chanctx_conf *chanctx_conf;2160struct lkpi_hw *lhw;2161struct ieee80211_hw *hw;2162struct lkpi_vif *lvif;2163struct ieee80211_vif *vif;2164struct ieee80211_node *ni;2165struct lkpi_sta *lsta;2166enum ieee80211_bss_changed bss_changed;2167struct ieee80211_prep_tx_info prep_tx_info;2168uint32_t changed;2169int error;2170bool synched;21712172/*2173* In here we use vap->iv_bss until lvif->lvif_bss is set.2174* For all later (STATE >= AUTH) functions we need to use the lvif2175* cache which will be tracked even through (*iv_update_bss)().2176*/21772178if (vap->iv_bss == NULL) {2179ic_printf(vap->iv_ic, "%s: no iv_bss for vap %p\n", __func__, vap);2180return (EINVAL);2181}2182/*2183* Keep the ni alive locally. In theory (and practice) iv_bss can change2184* once we unlock here. This is due to net80211 allowing state changes2185* and new join1() despite having an active node as well as due to2186* the fact that the iv_bss can be swapped under the hood in (*iv_update_bss).2187*/2188ni = ieee80211_ref_node(vap->iv_bss);2189if (ni->ni_chan == NULL || ni->ni_chan == IEEE80211_CHAN_ANYC) {2190ic_printf(vap->iv_ic, "%s: no channel set for iv_bss ni %p "2191"on vap %p\n", __func__, ni, vap);2192ieee80211_free_node(ni); /* Error handling for the local ni. */2193return (EINVAL);2194}21952196lhw = vap->iv_ic->ic_softc;2197chan = lkpi_find_lkpi80211_chan(lhw, ni->ni_chan);2198if (chan == NULL) {2199ic_printf(vap->iv_ic, "%s: failed to get LKPI channel from "2200"iv_bss ni %p on vap %p\n", __func__, ni, vap);2201ieee80211_free_node(ni); /* Error handling for the local ni. */2202return (ESRCH);2203}22042205hw = LHW_TO_HW(lhw);2206lvif = VAP_TO_LVIF(vap);2207vif = LVIF_TO_VIF(lvif);22082209LKPI_80211_LVIF_LOCK(lvif);2210/* XXX-BZ KASSERT later? */2211if (lvif->lvif_bss_synched || lvif->lvif_bss != NULL) {2212ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "2213"lvif_bss->ni %p synched %d\n", __func__, __LINE__,2214lvif, vap, vap->iv_bss, lvif->lvif_bss,2215(lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,2216lvif->lvif_bss_synched);2217LKPI_80211_LVIF_UNLOCK(lvif);2218ieee80211_free_node(ni); /* Error handling for the local ni. */2219return (EBUSY);2220}2221LKPI_80211_LVIF_UNLOCK(lvif);22222223IEEE80211_UNLOCK(vap->iv_ic);2224wiphy_lock(hw->wiphy);22252226/* Add chanctx (or if exists, change it). */2227chanctx_conf = rcu_dereference_protected(vif->bss_conf.chanctx_conf,2228lockdep_is_held(&hw->wiphy->mtx));2229if (chanctx_conf != NULL) {2230lchanctx = CHANCTX_CONF_TO_LCHANCTX(chanctx_conf);2231IMPROVE("diff changes for changed, working on live copy, rcu");2232} else {2233/* Keep separate alloc as in Linux this is rcu managed? */2234lchanctx = malloc(sizeof(*lchanctx) + hw->chanctx_data_size,2235M_LKPI80211, M_WAITOK | M_ZERO);2236chanctx_conf = &lchanctx->chanctx_conf;2237}22382239chanctx_conf->rx_chains_static = 1;2240chanctx_conf->rx_chains_dynamic = 1;2241chanctx_conf->radar_enabled =2242(chan->flags & IEEE80211_CHAN_RADAR) ? true : false;2243chanctx_conf->def.chan = chan;2244chanctx_conf->def.width = NL80211_CHAN_WIDTH_20_NOHT;2245chanctx_conf->def.center_freq1 = ieee80211_get_channel_center_freq1(ni->ni_chan);2246chanctx_conf->def.center_freq2 = ieee80211_get_channel_center_freq2(ni->ni_chan);2247IMPROVE("Check vht_cap from band not just chan?");2248KASSERT(ni->ni_chan != NULL && ni->ni_chan != IEEE80211_CHAN_ANYC,2249("%s:%d: ni %p ni_chan %p\n", __func__, __LINE__, ni, ni->ni_chan));22502251#ifdef LKPI_80211_HT2252if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) {2253if (IEEE80211_IS_CHAN_HT40(ni->ni_chan))2254chanctx_conf->def.width = NL80211_CHAN_WIDTH_40;2255else2256chanctx_conf->def.width = NL80211_CHAN_WIDTH_20;2257}2258#endif2259#ifdef LKPI_80211_VHT2260if (IEEE80211_IS_CHAN_VHT_5GHZ(ni->ni_chan)) {2261if (IEEE80211_IS_CHAN_VHT80P80(ni->ni_chan))2262chanctx_conf->def.width = NL80211_CHAN_WIDTH_80P80;2263else if (IEEE80211_IS_CHAN_VHT160(ni->ni_chan))2264chanctx_conf->def.width = NL80211_CHAN_WIDTH_160;2265else if (IEEE80211_IS_CHAN_VHT80(ni->ni_chan))2266chanctx_conf->def.width = NL80211_CHAN_WIDTH_80;2267}2268#endif2269chanctx_conf->rx_chains_dynamic = lkpi_get_max_rx_chains(ni);2270/* Responder ... */2271#if 02272chanctx_conf->min_def.chan = chanctx_conf->def.chan;2273chanctx_conf->min_def.width = NL80211_CHAN_WIDTH_20_NOHT;2274#ifdef LKPI_80211_HT2275if (IEEE80211_IS_CHAN_HT(ni->ni_chan) || IEEE80211_IS_CHAN_VHT(ni->ni_chan))2276chanctx_conf->min_def.width = NL80211_CHAN_WIDTH_20;2277#endif2278chanctx_conf->min_def.center_freq1 = chanctx_conf->def.center_freq1;2279chanctx_conf->min_def.center_freq2 = chanctx_conf->def.center_freq2;2280#else2281chanctx_conf->min_def = chanctx_conf->def;2282#endif22832284/* Set bss info (bss_info_changed). */2285bss_changed = 0;2286vif->bss_conf.bssid = ni->ni_bssid;2287bss_changed |= BSS_CHANGED_BSSID;2288vif->bss_conf.txpower = ni->ni_txpower;2289bss_changed |= BSS_CHANGED_TXPOWER;2290vif->cfg.idle = false;2291bss_changed |= BSS_CHANGED_IDLE;22922293/* vif->bss_conf.basic_rates ? Where exactly? */22942295lvif->beacons = 0;2296/* Should almost assert it is this. */2297vif->cfg.assoc = false;2298vif->cfg.aid = 0;22992300bss_changed |= lkpi_update_dtim_tsf(vif, ni, vap, __func__, __LINE__);23012302error = 0;2303if (vif->bss_conf.chanctx_conf == chanctx_conf) {2304changed = IEEE80211_CHANCTX_CHANGE_MIN_WIDTH;2305changed |= IEEE80211_CHANCTX_CHANGE_RADAR;2306changed |= IEEE80211_CHANCTX_CHANGE_RX_CHAINS;2307changed |= IEEE80211_CHANCTX_CHANGE_WIDTH;2308lkpi_80211_mo_change_chanctx(hw, chanctx_conf, changed);2309} else {2310error = lkpi_80211_mo_add_chanctx(hw, chanctx_conf);2311if (error == 0 || error == EOPNOTSUPP) {2312vif->bss_conf.chanreq.oper.chan = chanctx_conf->def.chan;2313vif->bss_conf.chanreq.oper.width = chanctx_conf->def.width;2314vif->bss_conf.chanreq.oper.center_freq1 =2315chanctx_conf->def.center_freq1;2316vif->bss_conf.chanreq.oper.center_freq2 =2317chanctx_conf->def.center_freq2;2318} else {2319ic_printf(vap->iv_ic, "%s:%d: mo_add_chanctx "2320"failed: %d\n", __func__, __LINE__, error);2321goto out;2322}23232324list_add_rcu(&lchanctx->entry, &lhw->lchanctx_list);2325rcu_assign_pointer(vif->bss_conf.chanctx_conf, chanctx_conf);23262327/* Assign vif chanctx. */2328if (error == 0)2329error = lkpi_80211_mo_assign_vif_chanctx(hw, vif,2330&vif->bss_conf, chanctx_conf);2331if (error == EOPNOTSUPP)2332error = 0;2333if (error != 0) {2334ic_printf(vap->iv_ic, "%s:%d: mo_assign_vif_chanctx "2335"failed: %d\n", __func__, __LINE__, error);2336lkpi_80211_mo_remove_chanctx(hw, chanctx_conf);2337rcu_assign_pointer(vif->bss_conf.chanctx_conf, NULL);2338lchanctx = CHANCTX_CONF_TO_LCHANCTX(chanctx_conf);2339list_del(&lchanctx->entry);2340free(lchanctx, M_LKPI80211);2341goto out;2342}2343}2344IMPROVE("update radiotap chan fields too");23452346/* RATES */2347IMPROVE("bss info: not all needs to come now and rates are missing");2348lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, bss_changed);23492350/*2351* Given ni and lsta are 1:1 from alloc to free we can assert that2352* ni always has lsta data attach despite net80211 node swapping2353* under the hoods.2354*/2355KASSERT(ni->ni_drv_data != NULL, ("%s: ni %p ni_drv_data %p\n",2356__func__, ni, ni->ni_drv_data));2357lsta = ni->ni_drv_data;23582359/* Insert the [l]sta into the list of known stations. */2360list_add_tail(&lsta->lsta_list, &lvif->lsta_list);23612362/* Add (or adjust) sta and change state (from NOTEXIST) to NONE. */2363KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));2364KASSERT(lsta->state == IEEE80211_STA_NOTEXIST, ("%s: lsta %p state not "2365"NOTEXIST: %#x\n", __func__, lsta, lsta->state));2366error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_NONE);2367if (error != 0) {2368IMPROVE("do we need to undo the chan ctx?");2369ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(NONE) "2370"failed: %d\n", __func__, __LINE__, error);2371goto out;2372}2373#if 02374lsta->added_to_drv = true; /* mo manages. */2375#endif23762377lkpi_lsta_dump(lsta, ni, __func__, __LINE__);23782379#if 02380/*2381* Wakeup all queues now that sta is there so we have as much time to2382* possibly prepare the queue in the driver to be ready for the 1st2383* packet; lkpi_80211_txq_tx_one() still has a workaround as there2384* is no guarantee or way to check.2385* XXX-BZ and by now we know that this does not work on all drivers2386* for all queues.2387*/2388lkpi_wake_tx_queues(hw, LSTA_TO_STA(lsta), false, false);2389#endif23902391/* Start mgd_prepare_tx. */2392memset(&prep_tx_info, 0, sizeof(prep_tx_info));2393prep_tx_info.duration = PREP_TX_INFO_DURATION;2394lkpi_80211_mo_mgd_prepare_tx(hw, vif, &prep_tx_info);2395lsta->in_mgd = true;23962397/*2398* What is going to happen next:2399* - <twiddle> .. we should end up in "auth_to_assoc"2400* - event_callback2401* - update sta_state (NONE to AUTH)2402* - mgd_complete_tx2403* (ideally we'd do that on a callback for something else ...)2404*/24052406wiphy_unlock(hw->wiphy);2407IEEE80211_LOCK(vap->iv_ic);24082409LKPI_80211_LVIF_LOCK(lvif);2410/* Re-check given (*iv_update_bss) could have happened while we were unlocked. */2411if (lvif->lvif_bss_synched || lvif->lvif_bss != NULL ||2412lsta->ni != vap->iv_bss)2413ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "2414"lvif_bss->ni %p synched %d, ni %p lsta %p\n", __func__, __LINE__,2415lvif, vap, vap->iv_bss, lvif->lvif_bss,2416(lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,2417lvif->lvif_bss_synched, ni, lsta);24182419/*2420* Reference the "ni" for caching the lsta/ni in lvif->lvif_bss.2421* Given we cache lsta we use lsta->ni instead of ni here (even though2422* lsta->ni == ni) to be distinct from the rest of the code where we do2423* assume that ni == vap->iv_bss which it may or may not be.2424* So do NOT use iv_bss here anymore as that may have diverged from our2425* function local ni already while ic was unlocked and would lead to2426* inconsistencies. Go and see if we lost a race and do not update2427* lvif_bss_synched in that case.2428*/2429ieee80211_ref_node(lsta->ni);2430lvif->lvif_bss = lsta;2431if (lsta->ni == vap->iv_bss) {2432lvif->lvif_bss_synched = synched = true;2433} else {2434/* Set to un-synched no matter what. */2435lvif->lvif_bss_synched = synched = false;2436/*2437* We do not error as someone has to take us down.2438* If we are followed by a 2nd, new net80211::join1() going to2439* AUTH lkpi_sta_a_to_a() will error, lkpi_sta_auth_to_{scan,init}()2440* will take the lvif->lvif_bss node down eventually.2441* What happens with the vap->iv_bss node will entirely be up2442* to net80211 as we never used the node beyond alloc()/free()2443* and we do not hold an extra reference for that anymore given2444* ni : lsta == 1:1.2445* Problem is if we do not error a MGMT/AUTH frame will be2446* sent from net80211::sta_newstate(); disable lsta queue below.2447*/2448}2449LKPI_80211_LVIF_UNLOCK(lvif);2450/*2451* Make sure in case the sta did not change and we re-added it,2452* that we can tx again but only if the vif/iv_bss are in sync.2453* Otherwise this should prevent the MGMT/AUTH frame from being2454* sent triggering a warning in iwlwifi.2455*/2456LKPI_80211_LSTA_TXQ_LOCK(lsta);2457lsta->txq_ready = synched;2458LKPI_80211_LSTA_TXQ_UNLOCK(lsta);2459goto out_relocked;24602461out:2462wiphy_unlock(hw->wiphy);2463IEEE80211_LOCK(vap->iv_ic);2464out_relocked:2465/*2466* Release the reference that kept the ni stable locally2467* during the work of this function.2468*/2469if (ni != NULL)2470ieee80211_free_node(ni);2471return (error);2472}24732474static int2475lkpi_sta_auth_to_scan(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)2476{2477struct lkpi_hw *lhw;2478struct ieee80211_hw *hw;2479struct lkpi_vif *lvif;2480struct ieee80211_vif *vif;2481struct ieee80211_node *ni;2482struct lkpi_sta *lsta;2483struct ieee80211_sta *sta;2484struct ieee80211_prep_tx_info prep_tx_info;2485enum ieee80211_bss_changed bss_changed;2486int error;24872488lhw = vap->iv_ic->ic_softc;2489hw = LHW_TO_HW(lhw);2490lvif = VAP_TO_LVIF(vap);2491vif = LVIF_TO_VIF(lvif);24922493LKPI_80211_LVIF_LOCK(lvif);2494#ifdef LINUXKPI_DEBUG_802112495/* XXX-BZ KASSERT later; state going down so no action. */2496if (lvif->lvif_bss == NULL)2497ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "2498"lvif_bss->ni %p synched %d\n", __func__, __LINE__,2499lvif, vap, vap->iv_bss, lvif->lvif_bss,2500(lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,2501lvif->lvif_bss_synched);2502#endif25032504lsta = lvif->lvif_bss;2505LKPI_80211_LVIF_UNLOCK(lvif);2506KASSERT(lsta != NULL && lsta->ni != NULL, ("%s: lsta %p ni %p "2507"lvif %p vap %p\n", __func__,2508lsta, (lsta != NULL) ? lsta->ni : NULL, lvif, vap));2509ni = lsta->ni; /* Reference held for lvif_bss. */2510sta = LSTA_TO_STA(lsta);25112512lkpi_lsta_dump(lsta, ni, __func__, __LINE__);25132514IEEE80211_UNLOCK(vap->iv_ic);2515wiphy_lock(hw->wiphy);25162517/* flush, drop. */2518lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), true);25192520/* Wake tx queues to get packet(s) out. */2521lkpi_wake_tx_queues(hw, sta, false, true);25222523/* flush, no drop */2524lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), false);25252526/* End mgd_complete_tx. */2527if (lsta->in_mgd) {2528memset(&prep_tx_info, 0, sizeof(prep_tx_info));2529prep_tx_info.success = false;2530lkpi_80211_mo_mgd_complete_tx(hw, vif, &prep_tx_info);2531lsta->in_mgd = false;2532}25332534/* sync_rx_queues */2535lkpi_80211_mo_sync_rx_queues(hw);25362537/* sta_pre_rcu_remove */2538lkpi_80211_mo_sta_pre_rcu_remove(hw, vif, sta);25392540/* Take the station down. */25412542/* Adjust sta and change state (from NONE) to NOTEXIST. */2543KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));2544KASSERT(lsta->state == IEEE80211_STA_NONE, ("%s: lsta %p state not "2545"NONE: %#x, nstate %d arg %d\n", __func__, lsta, lsta->state, nstate, arg));2546error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_NOTEXIST);2547if (error != 0) {2548IMPROVE("do we need to undo the chan ctx?");2549ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(NOTEXIST) "2550"failed: %d\n", __func__, __LINE__, error);2551goto out;2552}2553#if 02554lsta->added_to_drv = false; /* mo manages. */2555#endif25562557bss_changed = 0;2558vif->bss_conf.dtim_period = 0; /* go back to 0. */2559bss_changed |= BSS_CHANGED_BEACON_INFO;2560lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, bss_changed);25612562lkpi_lsta_dump(lsta, ni, __func__, __LINE__);25632564LKPI_80211_LVIF_LOCK(lvif);2565/* Remove ni reference for this cache of lsta. */2566lvif->lvif_bss = NULL;2567lvif->lvif_bss_synched = false;2568LKPI_80211_LVIF_UNLOCK(lvif);2569lkpi_lsta_remove(lsta, lvif);25702571/* conf_tx */25722573lkpi_remove_chanctx(hw, vif);25742575out:2576wiphy_unlock(hw->wiphy);2577IEEE80211_LOCK(vap->iv_ic);2578if (error == 0) {2579/*2580* We do this outside the wiphy lock as net80211::node_free() may call2581* into crypto code to delete keys and we have a recursed on2582* non-recursive sx panic. Also only do this if we get here w/o error.2583*2584* The very last release the reference on the ni for the ni/lsta on2585* lvif->lvif_bss. Upon return from this both ni and lsta are invalid2586* and potentially freed.2587*/2588ieee80211_free_node(ni);2589}2590return (error);2591}25922593static int2594lkpi_sta_auth_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)2595{2596int error;25972598error = lkpi_sta_auth_to_scan(vap, nstate, arg);2599if (error == 0)2600error = lkpi_sta_scan_to_init(vap, nstate, arg);2601return (error);2602}26032604static int2605lkpi_sta_auth_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)2606{2607struct lkpi_hw *lhw;2608struct ieee80211_hw *hw;2609struct lkpi_vif *lvif;2610struct ieee80211_vif *vif;2611struct lkpi_sta *lsta;2612struct ieee80211_prep_tx_info prep_tx_info;2613int error;26142615lhw = vap->iv_ic->ic_softc;2616hw = LHW_TO_HW(lhw);2617lvif = VAP_TO_LVIF(vap);2618vif = LVIF_TO_VIF(lvif);26192620IEEE80211_UNLOCK(vap->iv_ic);2621wiphy_lock(hw->wiphy);26222623LKPI_80211_LVIF_LOCK(lvif);2624/* XXX-BZ KASSERT later? */2625if (!lvif->lvif_bss_synched || lvif->lvif_bss == NULL) {2626#ifdef LINUXKPI_DEBUG_802112627ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "2628"lvif_bss->ni %p synched %d\n", __func__, __LINE__,2629lvif, vap, vap->iv_bss, lvif->lvif_bss,2630(lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,2631lvif->lvif_bss_synched);2632#endif2633error = ENOTRECOVERABLE;2634LKPI_80211_LVIF_UNLOCK(lvif);2635goto out;2636}2637lsta = lvif->lvif_bss;2638LKPI_80211_LVIF_UNLOCK(lvif);26392640KASSERT(lsta != NULL, ("%s: lsta %p\n", __func__, lsta));26412642/* Finish auth. */2643IMPROVE("event callback");26442645/* Update sta_state (NONE to AUTH). */2646KASSERT(lsta->state == IEEE80211_STA_NONE, ("%s: lsta %p state not "2647"NONE: %#x\n", __func__, lsta, lsta->state));2648error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_AUTH);2649if (error != 0) {2650ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(AUTH) "2651"failed: %d\n", __func__, __LINE__, error);2652goto out;2653}26542655/* End mgd_complete_tx. */2656if (lsta->in_mgd) {2657memset(&prep_tx_info, 0, sizeof(prep_tx_info));2658prep_tx_info.success = true;2659lkpi_80211_mo_mgd_complete_tx(hw, vif, &prep_tx_info);2660lsta->in_mgd = false;2661}26622663/* Now start assoc. */26642665/* Start mgd_prepare_tx. */2666if (!lsta->in_mgd) {2667memset(&prep_tx_info, 0, sizeof(prep_tx_info));2668prep_tx_info.duration = PREP_TX_INFO_DURATION;2669lkpi_80211_mo_mgd_prepare_tx(hw, vif, &prep_tx_info);2670lsta->in_mgd = true;2671}26722673/* Wake tx queue to get packet out. */2674lkpi_wake_tx_queues(hw, LSTA_TO_STA(lsta), false, true);26752676/*2677* <twiddle> .. we end up in "assoc_to_run"2678* - update sta_state (AUTH to ASSOC)2679* - conf_tx [all]2680* - bss_info_changed (assoc, aid, ssid, ..)2681* - change_chanctx (if needed)2682* - event_callback2683* - mgd_complete_tx2684*/26852686out:2687wiphy_unlock(hw->wiphy);2688IEEE80211_LOCK(vap->iv_ic);2689return (error);2690}26912692/* auth_to_auth, assoc_to_assoc. */2693static int2694lkpi_sta_a_to_a(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)2695{2696struct lkpi_hw *lhw;2697struct ieee80211_hw *hw;2698struct lkpi_vif *lvif;2699struct ieee80211_vif *vif;2700struct lkpi_sta *lsta;2701struct ieee80211_prep_tx_info prep_tx_info;2702int error;27032704lhw = vap->iv_ic->ic_softc;2705hw = LHW_TO_HW(lhw);2706lvif = VAP_TO_LVIF(vap);2707vif = LVIF_TO_VIF(lvif);27082709IEEE80211_UNLOCK(vap->iv_ic);2710wiphy_lock(hw->wiphy);27112712LKPI_80211_LVIF_LOCK(lvif);2713/* XXX-BZ KASSERT later? */2714if (!lvif->lvif_bss_synched || lvif->lvif_bss == NULL) {2715#ifdef LINUXKPI_DEBUG_802112716ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "2717"lvif_bss->ni %p synched %d\n", __func__, __LINE__,2718lvif, vap, vap->iv_bss, lvif->lvif_bss,2719(lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,2720lvif->lvif_bss_synched);2721#endif2722LKPI_80211_LVIF_UNLOCK(lvif);2723error = ENOTRECOVERABLE;2724goto out;2725}2726lsta = lvif->lvif_bss;2727LKPI_80211_LVIF_UNLOCK(lvif);27282729KASSERT(lsta != NULL, ("%s: lsta %p! lvif %p vap %p\n", __func__,2730lsta, lvif, vap));27312732IMPROVE("event callback?");27332734/* End mgd_complete_tx. */2735if (lsta->in_mgd) {2736memset(&prep_tx_info, 0, sizeof(prep_tx_info));2737prep_tx_info.success = false;2738lkpi_80211_mo_mgd_complete_tx(hw, vif, &prep_tx_info);2739lsta->in_mgd = false;2740}27412742/* Now start assoc. */27432744/* Start mgd_prepare_tx. */2745if (!lsta->in_mgd) {2746memset(&prep_tx_info, 0, sizeof(prep_tx_info));2747prep_tx_info.duration = PREP_TX_INFO_DURATION;2748lkpi_80211_mo_mgd_prepare_tx(hw, vif, &prep_tx_info);2749lsta->in_mgd = true;2750}27512752error = 0;2753out:2754wiphy_unlock(hw->wiphy);2755IEEE80211_LOCK(vap->iv_ic);27562757return (error);2758}27592760static int2761_lkpi_sta_assoc_to_down(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)2762{2763struct lkpi_hw *lhw;2764struct ieee80211_hw *hw;2765struct lkpi_vif *lvif;2766struct ieee80211_vif *vif;2767struct ieee80211_node *ni;2768struct lkpi_sta *lsta;2769struct ieee80211_sta *sta;2770struct ieee80211_prep_tx_info prep_tx_info;2771enum ieee80211_bss_changed bss_changed;2772int error;27732774lhw = vap->iv_ic->ic_softc;2775hw = LHW_TO_HW(lhw);2776lvif = VAP_TO_LVIF(vap);2777vif = LVIF_TO_VIF(lvif);27782779IEEE80211_UNLOCK(vap->iv_ic);2780wiphy_lock(hw->wiphy);27812782LKPI_80211_LVIF_LOCK(lvif);2783#ifdef LINUXKPI_DEBUG_802112784/* XXX-BZ KASSERT later; state going down so no action. */2785if (lvif->lvif_bss == NULL)2786ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "2787"lvif_bss->ni %p synched %d\n", __func__, __LINE__,2788lvif, vap, vap->iv_bss, lvif->lvif_bss,2789(lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,2790lvif->lvif_bss_synched);2791#endif2792lsta = lvif->lvif_bss;2793LKPI_80211_LVIF_UNLOCK(lvif);2794KASSERT(lsta != NULL && lsta->ni != NULL, ("%s: lsta %p ni %p "2795"lvif %p vap %p\n", __func__,2796lsta, (lsta != NULL) ? lsta->ni : NULL, lvif, vap));27972798ni = lsta->ni; /* Reference held for lvif_bss. */2799sta = LSTA_TO_STA(lsta);28002801lkpi_lsta_dump(lsta, ni, __func__, __LINE__);28022803/* flush, drop. */2804lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), true);28052806IMPROVE("What are the proper conditions for DEAUTH_NEED_MGD_TX_PREP?");2807if (ieee80211_hw_check(hw, DEAUTH_NEED_MGD_TX_PREP) &&2808!lsta->in_mgd) {2809memset(&prep_tx_info, 0, sizeof(prep_tx_info));2810prep_tx_info.duration = PREP_TX_INFO_DURATION;2811prep_tx_info.was_assoc = true;2812lkpi_80211_mo_mgd_prepare_tx(hw, vif, &prep_tx_info);2813lsta->in_mgd = true;2814}28152816wiphy_unlock(hw->wiphy);2817IEEE80211_LOCK(vap->iv_ic);28182819/* Call iv_newstate first so we get potential DEAUTH packet out. */2820error = lvif->iv_newstate(vap, nstate, arg);2821if (error != 0) {2822ic_printf(vap->iv_ic, "%s:%d: iv_newstate(%p, %d, %d) "2823"failed: %d\n", __func__, __LINE__, vap, nstate, arg, error);2824goto outni;2825}28262827IEEE80211_UNLOCK(vap->iv_ic);28282829/* Ensure the packets get out. */2830lkpi_80211_flush_tx(lhw, lsta);28312832wiphy_lock(hw->wiphy);28332834lkpi_lsta_dump(lsta, ni, __func__, __LINE__);28352836/* Wake tx queues to get packet(s) out. */2837lkpi_wake_tx_queues(hw, sta, false, true);28382839/* flush, no drop */2840lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), false);28412842/* End mgd_complete_tx. */2843if (lsta->in_mgd) {2844memset(&prep_tx_info, 0, sizeof(prep_tx_info));2845prep_tx_info.success = false;2846prep_tx_info.was_assoc = true;2847lkpi_80211_mo_mgd_complete_tx(hw, vif, &prep_tx_info);2848lsta->in_mgd = false;2849}28502851/* sync_rx_queues */2852lkpi_80211_mo_sync_rx_queues(hw);28532854/* sta_pre_rcu_remove */2855lkpi_80211_mo_sta_pre_rcu_remove(hw, vif, sta);28562857/* Take the station down. */28582859/* Update sta and change state (from AUTH) to NONE. */2860KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));2861KASSERT(lsta->state == IEEE80211_STA_AUTH, ("%s: lsta %p state not "2862"AUTH: %#x\n", __func__, lsta, lsta->state));2863error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_NONE);2864if (error != 0) {2865ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(NONE) "2866"failed: %d\n", __func__, __LINE__, error);2867goto out;2868}28692870/* See comment in lkpi_sta_run_to_init(). */2871bss_changed = 0;2872bss_changed |= lkpi_disassoc(sta, vif, lhw);28732874#ifdef LKPI_80211_HW_CRYPTO2875/*2876* In theory we remove keys here but there must not exist any for this2877* state change until we clean them up again into small steps and no2878* code duplication.2879*/2880#endif28812882lkpi_lsta_dump(lsta, ni, __func__, __LINE__);28832884/* Adjust sta and change state (from NONE) to NOTEXIST. */2885KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));2886KASSERT(lsta->state == IEEE80211_STA_NONE, ("%s: lsta %p state not "2887"NONE: %#x, nstate %d arg %d\n", __func__, lsta, lsta->state, nstate, arg));2888error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_NOTEXIST);2889if (error != 0) {2890IMPROVE("do we need to undo the chan ctx?");2891ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(NOTEXIST) "2892"failed: %d\n", __func__, __LINE__, error);2893goto out;2894}28952896lkpi_lsta_dump(lsta, ni, __func__, __LINE__); /* sta no longer save to use. */28972898IMPROVE("Any bss_info changes to announce?");2899vif->bss_conf.qos = 0;2900bss_changed |= BSS_CHANGED_QOS;2901vif->cfg.ssid_len = 0;2902memset(vif->cfg.ssid, '\0', sizeof(vif->cfg.ssid));2903bss_changed |= BSS_CHANGED_BSSID;2904vif->bss_conf.dtim_period = 0; /* go back to 0. */2905bss_changed |= BSS_CHANGED_BEACON_INFO;2906lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, bss_changed);29072908LKPI_80211_LVIF_LOCK(lvif);2909/* Remove ni reference for this cache of lsta. */2910lvif->lvif_bss = NULL;2911lvif->lvif_bss_synched = false;2912LKPI_80211_LVIF_UNLOCK(lvif);2913lkpi_lsta_remove(lsta, lvif);29142915/* conf_tx */29162917lkpi_remove_chanctx(hw, vif);29182919error = EALREADY;2920out:2921wiphy_unlock(hw->wiphy);2922IEEE80211_LOCK(vap->iv_ic);2923if (error == EALREADY) {2924/*2925* We do this outside the wiphy lock as net80211::node_free() may call2926* into crypto code to delete keys and we have a recursed on2927* non-recursive sx panic. Also only do this if we get here w/o error.2928*2929* The very last release the reference on the ni for the ni/lsta on2930* lvif->lvif_bss. Upon return from this both ni and lsta are invalid2931* and potentially freed.2932*/2933ieee80211_free_node(ni);2934}2935outni:2936return (error);2937}29382939static int2940lkpi_sta_assoc_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)2941{2942int error;29432944error = _lkpi_sta_assoc_to_down(vap, nstate, arg);2945if (error != 0 && error != EALREADY)2946return (error);29472948/* At this point iv_bss is long a new node! */29492950error |= lkpi_sta_scan_to_auth(vap, nstate, 0);2951return (error);2952}29532954static int2955lkpi_sta_assoc_to_scan(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)2956{2957int error;29582959error = _lkpi_sta_assoc_to_down(vap, nstate, arg);2960return (error);2961}29622963static int2964lkpi_sta_assoc_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)2965{2966int error;29672968error = _lkpi_sta_assoc_to_down(vap, nstate, arg);2969return (error);2970}29712972static int2973lkpi_sta_assoc_to_run(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)2974{2975struct lkpi_hw *lhw;2976struct ieee80211_hw *hw;2977struct lkpi_vif *lvif;2978struct ieee80211_vif *vif;2979struct ieee80211_node *ni;2980struct lkpi_sta *lsta;2981struct ieee80211_sta *sta;2982struct ieee80211_prep_tx_info prep_tx_info;2983enum ieee80211_bss_changed bss_changed;2984int error;29852986lhw = vap->iv_ic->ic_softc;2987hw = LHW_TO_HW(lhw);2988lvif = VAP_TO_LVIF(vap);2989vif = LVIF_TO_VIF(lvif);29902991IEEE80211_UNLOCK(vap->iv_ic);2992wiphy_lock(hw->wiphy);29932994LKPI_80211_LVIF_LOCK(lvif);2995/* XXX-BZ KASSERT later? */2996if (!lvif->lvif_bss_synched || lvif->lvif_bss == NULL) {2997#ifdef LINUXKPI_DEBUG_802112998ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "2999"lvif_bss->ni %p synched %d\n", __func__, __LINE__,3000lvif, vap, vap->iv_bss, lvif->lvif_bss,3001(lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,3002lvif->lvif_bss_synched);3003#endif3004LKPI_80211_LVIF_UNLOCK(lvif);3005error = ENOTRECOVERABLE;3006goto out;3007}3008lsta = lvif->lvif_bss;3009LKPI_80211_LVIF_UNLOCK(lvif);3010KASSERT(lsta != NULL && lsta->ni != NULL, ("%s: lsta %p ni %p "3011"lvif %p vap %p\n", __func__,3012lsta, (lsta != NULL) ? lsta->ni : NULL, lvif, vap));30133014ni = lsta->ni; /* Reference held for lvif_bss. */30153016IMPROVE("ponder some of this moved to ic_newassoc, scan_assoc_success, "3017"and to lesser extend ieee80211_notify_node_join");30183019/* Finish assoc. */3020/* Update sta_state (AUTH to ASSOC) and set aid. */3021KASSERT(lsta->state == IEEE80211_STA_AUTH, ("%s: lsta %p state not "3022"AUTH: %#x\n", __func__, lsta, lsta->state));3023sta = LSTA_TO_STA(lsta);3024sta->aid = IEEE80211_NODE_AID(ni);3025#ifdef LKPI_80211_WME3026if (vap->iv_flags & IEEE80211_F_WME)3027sta->wme = true;3028#endif3029error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_ASSOC);3030if (error != 0) {3031ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(ASSOC) "3032"failed: %d\n", __func__, __LINE__, error);3033goto out;3034}30353036IMPROVE("wme / conf_tx [all]");30373038/* Update bss info (bss_info_changed) (assoc, aid, ..). */3039bss_changed = 0;3040#ifdef LKPI_80211_WME3041bss_changed |= lkpi_wme_update(lhw, vap, true);3042#endif3043if (!vif->cfg.assoc || vif->cfg.aid != IEEE80211_NODE_AID(ni)) {3044lvif->beacons = 0;3045vif->cfg.assoc = true;3046vif->cfg.aid = IEEE80211_NODE_AID(ni);3047bss_changed |= BSS_CHANGED_ASSOC;3048}3049/* We set SSID but this is not BSSID! */3050vif->cfg.ssid_len = ni->ni_esslen;3051memcpy(vif->cfg.ssid, ni->ni_essid, ni->ni_esslen);3052if ((vap->iv_flags & IEEE80211_F_SHPREAMBLE) !=3053vif->bss_conf.use_short_preamble) {3054vif->bss_conf.use_short_preamble ^= 1;3055/* bss_changed |= BSS_CHANGED_??? */3056}3057if ((vap->iv_flags & IEEE80211_F_SHSLOT) !=3058vif->bss_conf.use_short_slot) {3059vif->bss_conf.use_short_slot ^= 1;3060/* bss_changed |= BSS_CHANGED_??? */3061}3062if ((ni->ni_flags & IEEE80211_NODE_QOS) !=3063vif->bss_conf.qos) {3064vif->bss_conf.qos ^= 1;3065bss_changed |= BSS_CHANGED_QOS;3066}30673068bss_changed |= lkpi_update_dtim_tsf(vif, ni, vap, __func__, __LINE__);3069lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, bss_changed);30703071/* - change_chanctx (if needed)3072* - event_callback3073*/30743075/* End mgd_complete_tx. */3076if (lsta->in_mgd) {3077memset(&prep_tx_info, 0, sizeof(prep_tx_info));3078prep_tx_info.success = true;3079lkpi_80211_mo_mgd_complete_tx(hw, vif, &prep_tx_info);3080lsta->in_mgd = false;3081}30823083lkpi_hw_conf_idle(hw, false);30843085/*3086* And then:3087* - (more packets)?3088* - set_key3089* - set_default_unicast_key3090* - set_key (?)3091* - ipv6_addr_change (?)3092*/30933094if (!ieee80211_node_is_authorized(ni)) {3095IMPROVE("net80211 does not consider node authorized");3096}30973098IMPROVE("Is this the right spot, has net80211 done all updates already?");3099lkpi_sta_sync_from_ni(hw, vif, sta, ni, true);31003101/* Update thresholds. */3102hw->wiphy->frag_threshold = vap->iv_fragthreshold;3103lkpi_80211_mo_set_frag_threshold(hw, vap->iv_fragthreshold);3104hw->wiphy->rts_threshold = vap->iv_rtsthreshold;3105lkpi_80211_mo_set_rts_threshold(hw, vap->iv_rtsthreshold);31063107/* Update sta_state (ASSOC to AUTHORIZED). */3108KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));3109KASSERT(lsta->state == IEEE80211_STA_ASSOC, ("%s: lsta %p state not "3110"ASSOC: %#x\n", __func__, lsta, lsta->state));3111error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_AUTHORIZED);3112if (error != 0) {3113IMPROVE("undo some changes?");3114ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(AUTHORIZED) "3115"failed: %d\n", __func__, __LINE__, error);3116goto out;3117}31183119/* - drv_config (?)3120* - bss_info_changed3121* - set_rekey_data (?)3122*3123* And now we should be passing packets.3124*/3125IMPROVE("Need that bssid setting, and the keys");31263127bss_changed = 0;3128bss_changed |= lkpi_update_dtim_tsf(vif, ni, vap, __func__, __LINE__);3129lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, bss_changed);31303131/* Prepare_multicast && configure_filter. */3132lkpi_update_mcast_filter(vap->iv_ic);31333134out:3135wiphy_unlock(hw->wiphy);3136IEEE80211_LOCK(vap->iv_ic);3137return (error);3138}31393140static int3141lkpi_sta_auth_to_run(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)3142{3143int error;31443145error = lkpi_sta_auth_to_assoc(vap, nstate, arg);3146if (error == 0)3147error = lkpi_sta_assoc_to_run(vap, nstate, arg);3148return (error);3149}31503151static int3152lkpi_sta_run_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)3153{3154struct lkpi_hw *lhw;3155struct ieee80211_hw *hw;3156struct lkpi_vif *lvif;3157struct ieee80211_vif *vif;3158struct ieee80211_node *ni;3159struct lkpi_sta *lsta;3160struct ieee80211_sta *sta;3161struct ieee80211_prep_tx_info prep_tx_info;3162#if 03163enum ieee80211_bss_changed bss_changed;3164#endif3165int error;31663167lhw = vap->iv_ic->ic_softc;3168hw = LHW_TO_HW(lhw);3169lvif = VAP_TO_LVIF(vap);3170vif = LVIF_TO_VIF(lvif);31713172LKPI_80211_LVIF_LOCK(lvif);3173#ifdef LINUXKPI_DEBUG_802113174/* XXX-BZ KASSERT later; state going down so no action. */3175if (lvif->lvif_bss == NULL)3176ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "3177"lvif_bss->ni %p synched %d\n", __func__, __LINE__,3178lvif, vap, vap->iv_bss, lvif->lvif_bss,3179(lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,3180lvif->lvif_bss_synched);3181#endif3182lsta = lvif->lvif_bss;3183LKPI_80211_LVIF_UNLOCK(lvif);3184KASSERT(lsta != NULL && lsta->ni != NULL, ("%s: lsta %p ni %p "3185"lvif %p vap %p\n", __func__,3186lsta, (lsta != NULL) ? lsta->ni : NULL, lvif, vap));31873188ni = lsta->ni; /* Reference held for lvif_bss. */3189sta = LSTA_TO_STA(lsta);31903191lkpi_lsta_dump(lsta, ni, __func__, __LINE__);31923193IEEE80211_UNLOCK(vap->iv_ic);3194wiphy_lock(hw->wiphy);31953196/* flush, drop. */3197lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), true);31983199IMPROVE("What are the proper conditions for DEAUTH_NEED_MGD_TX_PREP?");3200if (ieee80211_hw_check(hw, DEAUTH_NEED_MGD_TX_PREP) &&3201!lsta->in_mgd) {3202memset(&prep_tx_info, 0, sizeof(prep_tx_info));3203prep_tx_info.duration = PREP_TX_INFO_DURATION;3204prep_tx_info.was_assoc = true;3205lkpi_80211_mo_mgd_prepare_tx(hw, vif, &prep_tx_info);3206lsta->in_mgd = true;3207}32083209wiphy_unlock(hw->wiphy);3210IEEE80211_LOCK(vap->iv_ic);32113212/* Call iv_newstate first so we get potential DISASSOC packet out. */3213error = lvif->iv_newstate(vap, nstate, arg);3214if (error != 0) {3215ic_printf(vap->iv_ic, "%s:%d: iv_newstate(%p, %d, %d) "3216"failed: %d\n", __func__, __LINE__, vap, nstate, arg, error);3217goto outni;3218}32193220IEEE80211_UNLOCK(vap->iv_ic);32213222/* Ensure the packets get out. */3223lkpi_80211_flush_tx(lhw, lsta);32243225wiphy_lock(hw->wiphy);32263227lkpi_lsta_dump(lsta, ni, __func__, __LINE__);32283229/* Wake tx queues to get packet(s) out. */3230lkpi_wake_tx_queues(hw, sta, false, true);32313232/* flush, no drop */3233lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), false);32343235/* End mgd_complete_tx. */3236if (lsta->in_mgd) {3237memset(&prep_tx_info, 0, sizeof(prep_tx_info));3238prep_tx_info.success = false;3239prep_tx_info.was_assoc = true;3240lkpi_80211_mo_mgd_complete_tx(hw, vif, &prep_tx_info);3241lsta->in_mgd = false;3242}32433244#if 03245/* sync_rx_queues */3246lkpi_80211_mo_sync_rx_queues(hw);32473248/* sta_pre_rcu_remove */3249lkpi_80211_mo_sta_pre_rcu_remove(hw, vif, sta);3250#endif32513252/* Take the station down. */32533254/* Adjust sta and change state (from AUTHORIZED) to ASSOC. */3255KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));3256KASSERT(lsta->state == IEEE80211_STA_AUTHORIZED, ("%s: lsta %p state not "3257"AUTHORIZED: %#x\n", __func__, lsta, lsta->state));3258error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_ASSOC);3259if (error != 0) {3260ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(ASSOC) "3261"failed: %d\n", __func__, __LINE__, error);3262goto out;3263}32643265lkpi_lsta_dump(lsta, ni, __func__, __LINE__);32663267#ifdef LKPI_80211_HW_CRYPTO3268if (lkpi_hwcrypto) {3269error = lkpi_sta_del_keys(hw, vif, lsta);3270if (error != 0) {3271ic_printf(vap->iv_ic, "%s:%d: lkpi_sta_del_keys "3272"failed: %d\n", __func__, __LINE__, error);3273/*3274* Either drv/fw will crash or cleanup itself,3275* otherwise net80211 will delete the keys (at a3276* less appropriate time).3277*/3278/* goto out; */3279}3280}3281#endif32823283/* Update sta_state (ASSOC to AUTH). */3284KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));3285KASSERT(lsta->state == IEEE80211_STA_ASSOC, ("%s: lsta %p state not "3286"ASSOC: %#x\n", __func__, lsta, lsta->state));3287error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_AUTH);3288if (error != 0) {3289ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(AUTH) "3290"failed: %d\n", __func__, __LINE__, error);3291goto out;3292}32933294lkpi_lsta_dump(lsta, ni, __func__, __LINE__);32953296#if 03297/* Update bss info (bss_info_changed) (assoc, aid, ..). */3298lkpi_disassoc(sta, vif, lhw);3299#endif33003301error = EALREADY;3302out:3303wiphy_unlock(hw->wiphy);3304IEEE80211_LOCK(vap->iv_ic);3305outni:3306return (error);3307}33083309static int3310lkpi_sta_run_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)3311{3312struct lkpi_hw *lhw;3313struct ieee80211_hw *hw;3314struct lkpi_vif *lvif;3315struct ieee80211_vif *vif;3316struct ieee80211_node *ni;3317struct lkpi_sta *lsta;3318struct ieee80211_sta *sta;3319struct ieee80211_prep_tx_info prep_tx_info;3320enum ieee80211_bss_changed bss_changed;3321int error;33223323lhw = vap->iv_ic->ic_softc;3324hw = LHW_TO_HW(lhw);3325lvif = VAP_TO_LVIF(vap);3326vif = LVIF_TO_VIF(lvif);33273328IEEE80211_UNLOCK(vap->iv_ic);3329wiphy_lock(hw->wiphy);33303331LKPI_80211_LVIF_LOCK(lvif);3332#ifdef LINUXKPI_DEBUG_802113333/* XXX-BZ KASSERT later; state going down so no action. */3334if (lvif->lvif_bss == NULL)3335ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "3336"lvif_bss->ni %p synched %d\n", __func__, __LINE__,3337lvif, vap, vap->iv_bss, lvif->lvif_bss,3338(lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,3339lvif->lvif_bss_synched);3340#endif3341lsta = lvif->lvif_bss;3342LKPI_80211_LVIF_UNLOCK(lvif);3343KASSERT(lsta != NULL && lsta->ni != NULL, ("%s: lsta %p ni %p "3344"lvif %p vap %p\n", __func__,3345lsta, (lsta != NULL) ? lsta->ni : NULL, lvif, vap));33463347ni = lsta->ni; /* Reference held for lvif_bss. */3348sta = LSTA_TO_STA(lsta);33493350lkpi_lsta_dump(lsta, ni, __func__, __LINE__);33513352/* flush, drop. */3353lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), true);33543355IMPROVE("What are the proper conditions for DEAUTH_NEED_MGD_TX_PREP?");3356if (ieee80211_hw_check(hw, DEAUTH_NEED_MGD_TX_PREP) &&3357!lsta->in_mgd) {3358memset(&prep_tx_info, 0, sizeof(prep_tx_info));3359prep_tx_info.duration = PREP_TX_INFO_DURATION;3360prep_tx_info.was_assoc = true;3361lkpi_80211_mo_mgd_prepare_tx(hw, vif, &prep_tx_info);3362lsta->in_mgd = true;3363}33643365wiphy_unlock(hw->wiphy);3366IEEE80211_LOCK(vap->iv_ic);33673368/* Call iv_newstate first so we get potential DISASSOC packet out. */3369error = lvif->iv_newstate(vap, nstate, arg);3370if (error != 0) {3371ic_printf(vap->iv_ic, "%s:%d: iv_newstate(%p, %d, %d) "3372"failed: %d\n", __func__, __LINE__, vap, nstate, arg, error);3373goto outni;3374}33753376IEEE80211_UNLOCK(vap->iv_ic);33773378/* Ensure the packets get out. */3379lkpi_80211_flush_tx(lhw, lsta);33803381wiphy_lock(hw->wiphy);33823383lkpi_lsta_dump(lsta, ni, __func__, __LINE__);33843385/* Wake tx queues to get packet(s) out. */3386lkpi_wake_tx_queues(hw, sta, false, true);33873388/* flush, no drop */3389lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), false);33903391/* End mgd_complete_tx. */3392if (lsta->in_mgd) {3393memset(&prep_tx_info, 0, sizeof(prep_tx_info));3394prep_tx_info.success = false;3395prep_tx_info.was_assoc = true;3396lkpi_80211_mo_mgd_complete_tx(hw, vif, &prep_tx_info);3397lsta->in_mgd = false;3398}33993400/* sync_rx_queues */3401lkpi_80211_mo_sync_rx_queues(hw);34023403/* sta_pre_rcu_remove */3404lkpi_80211_mo_sta_pre_rcu_remove(hw, vif, sta);34053406/* Take the station down. */34073408/* Adjust sta and change state (from AUTHORIZED) to ASSOC. */3409KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));3410KASSERT(lsta->state == IEEE80211_STA_AUTHORIZED, ("%s: lsta %p state not "3411"AUTHORIZED: %#x\n", __func__, lsta, lsta->state));3412error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_ASSOC);3413if (error != 0) {3414ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(ASSOC) "3415"failed: %d\n", __func__, __LINE__, error);3416goto out;3417}34183419lkpi_lsta_dump(lsta, ni, __func__, __LINE__);34203421#ifdef LKPI_80211_HW_CRYPTO3422if (lkpi_hwcrypto) {3423/*3424* In theory we only need to do this if we changed assoc.3425* If we were not assoc, there should be no keys and we3426* should not be here.3427*/3428#ifdef notyet3429KASSERT((bss_changed & BSS_CHANGED_ASSOC) != 0, ("%s: "3430"trying to remove keys but were not assoc: %#010jx, lvif %p\n",3431__func__, (uintmax_t)bss_changed, lvif));3432#endif3433error = lkpi_sta_del_keys(hw, vif, lsta);3434if (error != 0) {3435ic_printf(vap->iv_ic, "%s:%d: lkpi_sta_del_keys "3436"failed: %d\n", __func__, __LINE__, error);3437/*3438* Either drv/fw will crash or cleanup itself,3439* otherwise net80211 will delete the keys (at a3440* less appropriate time).3441*/3442/* goto out; */3443}3444}3445#endif34463447/* Update sta_state (ASSOC to AUTH). */3448KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));3449KASSERT(lsta->state == IEEE80211_STA_ASSOC, ("%s: lsta %p state not "3450"ASSOC: %#x\n", __func__, lsta, lsta->state));3451error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_AUTH);3452if (error != 0) {3453ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(AUTH) "3454"failed: %d\n", __func__, __LINE__, error);3455goto out;3456}34573458lkpi_lsta_dump(lsta, ni, __func__, __LINE__);34593460/* Update sta and change state (from AUTH) to NONE. */3461KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));3462KASSERT(lsta->state == IEEE80211_STA_AUTH, ("%s: lsta %p state not "3463"AUTH: %#x\n", __func__, lsta, lsta->state));3464error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_NONE);3465if (error != 0) {3466ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(NONE) "3467"failed: %d\n", __func__, __LINE__, error);3468goto out;3469}34703471bss_changed = 0;3472/*3473* Start updating bss info (bss_info_changed) (assoc, aid, ..).3474*3475* One would expect this to happen when going off AUTHORIZED.3476* See comment there; removes the sta from fw if not careful3477* (bss_info_changed() change is executed right away).3478*3479* We need to do this now, before sta changes to IEEE80211_STA_NOTEXIST3480* as otherwise drivers (iwlwifi at least) will silently not remove3481* the sta from the firmware and when we will add a new one trigger3482* a fw assert.3483*3484* The order which works best so far avoiding early removal or silent3485* non-removal seems to be (for iwlwifi::mld-mac80211.c cases;3486* the iwlwifi:mac80211.c case still to be tested):3487* 1) lkpi_disassoc(): set vif->cfg.assoc = false (aid=0 side effect here)3488* 2) call the last sta_state update -> IEEE80211_STA_NOTEXIST3489* (removes the sta given assoc is false)3490* 3) add the remaining BSS_CHANGED changes and call bss_info_changed()3491* 4) call unassign_vif_chanctx3492* 5) call lkpi_hw_conf_idle3493* 6) call remove_chanctx3494*3495* Note: vif->driver_flags & IEEE80211_VIF_REMOVE_AP_AFTER_DISASSOC3496* might change this.3497*/3498bss_changed |= lkpi_disassoc(sta, vif, lhw);34993500lkpi_lsta_dump(lsta, ni, __func__, __LINE__);35013502/* Adjust sta and change state (from NONE) to NOTEXIST. */3503KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));3504KASSERT(lsta->state == IEEE80211_STA_NONE, ("%s: lsta %p state not "3505"NONE: %#x, nstate %d arg %d\n", __func__, lsta, lsta->state, nstate, arg));3506error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_NOTEXIST);3507if (error != 0) {3508IMPROVE("do we need to undo the chan ctx?");3509ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(NOTEXIST) "3510"failed: %d\n", __func__, __LINE__, error);3511goto out;3512}35133514lkpi_lsta_remove(lsta, lvif);35153516lkpi_lsta_dump(lsta, ni, __func__, __LINE__); /* sta no longer save to use. */35173518IMPROVE("Any bss_info changes to announce?");3519vif->bss_conf.qos = 0;3520bss_changed |= BSS_CHANGED_QOS;3521vif->cfg.ssid_len = 0;3522memset(vif->cfg.ssid, '\0', sizeof(vif->cfg.ssid));3523bss_changed |= BSS_CHANGED_BSSID;3524vif->bss_conf.use_short_preamble = false;3525vif->bss_conf.qos = false;3526/* XXX BSS_CHANGED_???? */3527vif->bss_conf.dtim_period = 0; /* go back to 0. */3528bss_changed |= BSS_CHANGED_BEACON_INFO;3529lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, bss_changed);35303531LKPI_80211_LVIF_LOCK(lvif);3532/* Remove ni reference for this cache of lsta. */3533lvif->lvif_bss = NULL;3534lvif->lvif_bss_synched = false;3535LKPI_80211_LVIF_UNLOCK(lvif);35363537/* conf_tx */35383539lkpi_remove_chanctx(hw, vif);35403541error = EALREADY;3542out:3543wiphy_unlock(hw->wiphy);3544IEEE80211_LOCK(vap->iv_ic);3545if (error == EALREADY) {3546/*3547* We do this outside the wiphy lock as net80211::node_free() may call3548* into crypto code to delete keys and we have a recursed on3549* non-recursive sx panic. Also only do this if we get here w/o error.3550*3551* The very last release the reference on the ni for the ni/lsta on3552* lvif->lvif_bss. Upon return from this both ni and lsta are invalid3553* and potentially freed.3554*/3555ieee80211_free_node(ni);3556}3557outni:3558return (error);3559}35603561static int3562lkpi_sta_run_to_scan(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)3563{35643565return (lkpi_sta_run_to_init(vap, nstate, arg));3566}35673568static int3569lkpi_sta_run_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)3570{3571int error;35723573error = lkpi_sta_run_to_init(vap, nstate, arg);3574if (error != 0 && error != EALREADY)3575return (error);35763577/* At this point iv_bss is long a new node! */35783579error |= lkpi_sta_scan_to_auth(vap, nstate, 0);3580return (error);3581}35823583/* -------------------------------------------------------------------------- */35843585/*3586* The matches the documented state changes in net80211::sta_newstate().3587* XXX (1) without CSA and SLEEP yet, * XXX (2) not all unhandled cases3588* there are "invalid" (so there is a room for failure here).3589*/3590struct fsm_state {3591/* INIT, SCAN, AUTH, ASSOC, CAC, RUN, CSA, SLEEP */3592enum ieee80211_state ostate;3593enum ieee80211_state nstate;3594int (*handler)(struct ieee80211vap *, enum ieee80211_state, int);3595} sta_state_fsm[] = {3596{ IEEE80211_S_INIT, IEEE80211_S_INIT, lkpi_sta_state_do_nada },3597{ IEEE80211_S_SCAN, IEEE80211_S_INIT, lkpi_sta_state_do_nada }, /* scan_to_init */3598{ IEEE80211_S_AUTH, IEEE80211_S_INIT, lkpi_sta_auth_to_init }, /* not explicitly in sta_newstate() */3599{ IEEE80211_S_ASSOC, IEEE80211_S_INIT, lkpi_sta_assoc_to_init }, /* Send DEAUTH. */3600{ IEEE80211_S_RUN, IEEE80211_S_INIT, lkpi_sta_run_to_init }, /* Send DISASSOC. */36013602{ IEEE80211_S_INIT, IEEE80211_S_SCAN, lkpi_sta_state_do_nada },3603{ IEEE80211_S_SCAN, IEEE80211_S_SCAN, lkpi_sta_state_do_nada },3604{ IEEE80211_S_AUTH, IEEE80211_S_SCAN, lkpi_sta_auth_to_scan },3605{ IEEE80211_S_ASSOC, IEEE80211_S_SCAN, lkpi_sta_assoc_to_scan },3606{ IEEE80211_S_RUN, IEEE80211_S_SCAN, lkpi_sta_run_to_scan }, /* Beacon miss. */36073608{ IEEE80211_S_INIT, IEEE80211_S_AUTH, lkpi_sta_scan_to_auth }, /* Send AUTH. */3609{ IEEE80211_S_SCAN, IEEE80211_S_AUTH, lkpi_sta_scan_to_auth }, /* Send AUTH. */3610{ IEEE80211_S_AUTH, IEEE80211_S_AUTH, lkpi_sta_a_to_a }, /* Send ?AUTH. */3611{ IEEE80211_S_ASSOC, IEEE80211_S_AUTH, lkpi_sta_assoc_to_auth }, /* Send ?AUTH. */3612{ IEEE80211_S_RUN, IEEE80211_S_AUTH, lkpi_sta_run_to_auth }, /* Send ?AUTH. */36133614{ IEEE80211_S_AUTH, IEEE80211_S_ASSOC, lkpi_sta_auth_to_assoc }, /* Send ASSOCREQ. */3615{ IEEE80211_S_ASSOC, IEEE80211_S_ASSOC, lkpi_sta_a_to_a }, /* Send ASSOCREQ. */3616{ IEEE80211_S_RUN, IEEE80211_S_ASSOC, lkpi_sta_run_to_assoc }, /* Send ASSOCREQ/REASSOCREQ. */36173618{ IEEE80211_S_AUTH, IEEE80211_S_RUN, lkpi_sta_auth_to_run },3619{ IEEE80211_S_ASSOC, IEEE80211_S_RUN, lkpi_sta_assoc_to_run },3620{ IEEE80211_S_RUN, IEEE80211_S_RUN, lkpi_sta_state_do_nada },36213622/* Dummy at the end without handler. */3623{ IEEE80211_S_INIT, IEEE80211_S_INIT, NULL },3624};36253626static int3627lkpi_iv_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)3628{3629struct ieee80211com *ic;3630struct lkpi_hw *lhw;3631struct lkpi_vif *lvif;3632struct ieee80211_vif *vif;3633struct fsm_state *s;3634enum ieee80211_state ostate;3635int error;36363637ic = vap->iv_ic;3638IEEE80211_LOCK_ASSERT(ic);3639ostate = vap->iv_state;36403641#ifdef LINUXKPI_DEBUG_802113642if (linuxkpi_debug_80211 & D80211_TRACE)3643ic_printf(vap->iv_ic, "%s:%d: vap %p nstate %#x arg %#x\n",3644__func__, __LINE__, vap, nstate, arg);3645#endif36463647if (vap->iv_opmode == IEEE80211_M_STA) {36483649lhw = ic->ic_softc;3650lvif = VAP_TO_LVIF(vap);3651vif = LVIF_TO_VIF(lvif);36523653/* No need to replicate this in most state handlers. */3654if (nstate > IEEE80211_S_SCAN)3655lkpi_stop_hw_scan(lhw, vif);36563657s = sta_state_fsm;36583659} else {3660ic_printf(vap->iv_ic, "%s: only station mode currently supported: "3661"cap %p iv_opmode %d\n", __func__, vap, vap->iv_opmode);3662return (ENOSYS);3663}36643665error = 0;3666for (; s->handler != NULL; s++) {3667if (ostate == s->ostate && nstate == s->nstate) {3668#ifdef LINUXKPI_DEBUG_802113669if (linuxkpi_debug_80211 & D80211_TRACE)3670ic_printf(vap->iv_ic, "%s: new state %d (%s) ->"3671" %d (%s): arg %d.\n", __func__,3672ostate, ieee80211_state_name[ostate],3673nstate, ieee80211_state_name[nstate], arg);3674#endif3675error = s->handler(vap, nstate, arg);3676break;3677}3678}3679IEEE80211_LOCK_ASSERT(vap->iv_ic);36803681if (s->handler == NULL) {3682IMPROVE("turn this into a KASSERT\n");3683ic_printf(vap->iv_ic, "%s: unsupported state transition "3684"%d (%s) -> %d (%s)\n", __func__,3685ostate, ieee80211_state_name[ostate],3686nstate, ieee80211_state_name[nstate]);3687return (ENOSYS);3688}36893690if (error == EALREADY) {3691#ifdef LINUXKPI_DEBUG_802113692if (linuxkpi_debug_80211 & D80211_TRACE)3693ic_printf(vap->iv_ic, "%s: state transition %d (%s) -> "3694"%d (%s): iv_newstate already handled: %d.\n",3695__func__, ostate, ieee80211_state_name[ostate],3696nstate, ieee80211_state_name[nstate], error);3697#endif3698return (0);3699}37003701if (error != 0) {3702ic_printf(vap->iv_ic, "%s: error %d during state transition "3703"%d (%s) -> %d (%s)\n", __func__, error,3704ostate, ieee80211_state_name[ostate],3705nstate, ieee80211_state_name[nstate]);3706return (error);3707}37083709#ifdef LINUXKPI_DEBUG_802113710if (linuxkpi_debug_80211 & D80211_TRACE)3711ic_printf(vap->iv_ic, "%s:%d: vap %p nstate %#x arg %#x "3712"calling net80211 parent\n",3713__func__, __LINE__, vap, nstate, arg);3714#endif37153716return (lvif->iv_newstate(vap, nstate, arg));3717}37183719/* -------------------------------------------------------------------------- */37203721/*3722* We overload (*iv_update_bss) as otherwise we have cases in, e.g.,3723* net80211::ieee80211_sta_join1() where vap->iv_bss gets replaced by a3724* new node without us knowing and thus our ni/lsta are out of sync.3725*/3726static struct ieee80211_node *3727lkpi_iv_update_bss(struct ieee80211vap *vap, struct ieee80211_node *ni)3728{3729struct lkpi_vif *lvif;3730struct ieee80211_node *rni;37313732IEEE80211_LOCK_ASSERT(vap->iv_ic);37333734lvif = VAP_TO_LVIF(vap);37353736LKPI_80211_LVIF_LOCK(lvif);3737lvif->lvif_bss_synched = false;3738LKPI_80211_LVIF_UNLOCK(lvif);37393740rni = lvif->iv_update_bss(vap, ni);3741return (rni);3742}37433744#ifdef LKPI_80211_WME3745static int3746lkpi_wme_update(struct lkpi_hw *lhw, struct ieee80211vap *vap, bool planned)3747{3748struct ieee80211com *ic;3749struct ieee80211_hw *hw;3750struct lkpi_vif *lvif;3751struct ieee80211_vif *vif;3752struct chanAccParams chp;3753struct wmeParams wmeparr[WME_NUM_AC];3754struct ieee80211_tx_queue_params txqp;3755enum ieee80211_bss_changed changed;3756int error;3757uint16_t ac;37583759hw = LHW_TO_HW(lhw);3760lockdep_assert_wiphy(hw->wiphy);37613762IMPROVE();3763KASSERT(WME_NUM_AC == IEEE80211_NUM_ACS, ("%s: WME_NUM_AC %d != "3764"IEEE80211_NUM_ACS %d\n", __func__, WME_NUM_AC, IEEE80211_NUM_ACS));37653766if (vap == NULL)3767return (0);37683769if ((vap->iv_flags & IEEE80211_F_WME) == 0)3770return (0);37713772if (lhw->ops->conf_tx == NULL)3773return (0);37743775if (!planned && (vap->iv_state != IEEE80211_S_RUN)) {3776lhw->update_wme = true;3777return (0);3778}3779lhw->update_wme = false;37803781ic = lhw->ic;3782ieee80211_wme_ic_getparams(ic, &chp);3783IEEE80211_LOCK(ic);3784for (ac = 0; ac < WME_NUM_AC; ac++)3785wmeparr[ac] = chp.cap_wmeParams[ac];3786IEEE80211_UNLOCK(ic);37873788lvif = VAP_TO_LVIF(vap);3789vif = LVIF_TO_VIF(lvif);37903791/* Configure tx queues (conf_tx) & send BSS_CHANGED_QOS. */3792for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {3793struct wmeParams *wmep;37943795wmep = &wmeparr[ac];3796bzero(&txqp, sizeof(txqp));3797txqp.cw_min = wmep->wmep_logcwmin;3798txqp.cw_max = wmep->wmep_logcwmax;3799txqp.txop = wmep->wmep_txopLimit;3800txqp.aifs = wmep->wmep_aifsn;3801error = lkpi_80211_mo_conf_tx(hw, vif, /* link_id */0, ac, &txqp);3802if (error != 0)3803ic_printf(ic, "%s: conf_tx ac %u failed %d\n",3804__func__, ac, error);3805}3806changed = BSS_CHANGED_QOS;3807if (!planned)3808lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, changed);38093810return (changed);3811}3812#endif38133814static int3815lkpi_ic_wme_update(struct ieee80211com *ic)3816{3817#ifdef LKPI_80211_WME3818struct ieee80211vap *vap;3819struct lkpi_hw *lhw;3820struct ieee80211_hw *hw;38213822IMPROVE("Use the per-VAP callback in net80211.");3823vap = TAILQ_FIRST(&ic->ic_vaps);3824if (vap == NULL)3825return (0);38263827lhw = ic->ic_softc;3828hw = LHW_TO_HW(lhw);38293830wiphy_lock(hw->wiphy);3831lkpi_wme_update(lhw, vap, false);3832wiphy_unlock(hw->wiphy);3833#endif3834return (0); /* unused */3835}38363837static void3838lkpi_iv_sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,3839int subtype, const struct ieee80211_rx_stats *rxs, int rssi, int nf)3840{3841struct lkpi_hw *lhw;3842struct ieee80211_hw *hw;3843struct lkpi_vif *lvif;3844struct ieee80211_vif *vif;3845enum ieee80211_bss_changed bss_changed;38463847lvif = VAP_TO_LVIF(ni->ni_vap);3848vif = LVIF_TO_VIF(lvif);38493850lvif->iv_recv_mgmt(ni, m0, subtype, rxs, rssi, nf);38513852switch (subtype) {3853case IEEE80211_FC0_SUBTYPE_PROBE_RESP:3854break;3855case IEEE80211_FC0_SUBTYPE_BEACON:3856/*3857* Only count beacons when assoc. SCAN has its own logging.3858* This is for connection/beacon loss/session protection almost3859* over debugging when trying to get into a stable RUN state.3860*/3861if (vif->cfg.assoc)3862lvif->beacons++;3863break;3864default:3865return;3866}38673868lhw = ni->ni_ic->ic_softc;3869hw = LHW_TO_HW(lhw);38703871/*3872* If this direct call to mo_bss_info_changed will not work due to3873* locking, see if queue_work() is fast enough.3874*/3875bss_changed = lkpi_update_dtim_tsf(vif, ni, ni->ni_vap, __func__, __LINE__);3876lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, bss_changed);3877}38783879/*3880* Change link-layer address on the vif (if the vap is not started/"UP").3881* This can happen if a user changes 'ether' using ifconfig.3882* The code is based on net80211/ieee80211_freebsd.c::wlan_iflladdr() but3883* we do use a per-[l]vif event handler to be sure we exist as we3884* cannot assume that from every vap derives a vif and we have a hard3885* time checking based on net80211 information.3886* Should this ever become a real problem we could add a callback function3887* to wlan_iflladdr() to be set optionally but that would be for a3888* single-consumer (or needs a list) -- was just too complicated for an3889* otherwise perfect mechanism FreeBSD already provides.3890*/3891static void3892lkpi_vif_iflladdr(void *arg, struct ifnet *ifp)3893{3894struct epoch_tracker et;3895struct ieee80211_vif *vif;38963897NET_EPOCH_ENTER(et);3898/* NB: identify vap's by if_transmit; left as an extra check. */3899if (if_gettransmitfn(ifp) != ieee80211_vap_transmit ||3900(if_getflags(ifp) & IFF_UP) != 0) {3901NET_EPOCH_EXIT(et);3902return;3903}39043905vif = arg;3906IEEE80211_ADDR_COPY(vif->bss_conf.addr, if_getlladdr(ifp));3907NET_EPOCH_EXIT(et);3908}39093910static struct ieee80211vap *3911lkpi_ic_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ],3912int unit, enum ieee80211_opmode opmode, int flags,3913const uint8_t bssid[IEEE80211_ADDR_LEN],3914const uint8_t mac[IEEE80211_ADDR_LEN])3915{3916struct lkpi_hw *lhw;3917struct ieee80211_hw *hw;3918struct lkpi_vif *lvif;3919struct ieee80211vap *vap;3920struct ieee80211_vif *vif;3921struct ieee80211_tx_queue_params txqp;3922enum ieee80211_bss_changed changed;3923struct sysctl_oid *node;3924size_t len;3925int error, i;3926uint16_t ac;39273928if (!TAILQ_EMPTY(&ic->ic_vaps)) /* 1 so far. Add <n> once this works. */3929return (NULL);39303931lhw = ic->ic_softc;3932hw = LHW_TO_HW(lhw);39333934len = sizeof(*lvif);3935len += hw->vif_data_size; /* vif->drv_priv */39363937lvif = malloc(len, M_80211_VAP, M_WAITOK | M_ZERO);3938mtx_init(&lvif->mtx, "lvif", NULL, MTX_DEF);3939TASK_INIT(&lvif->sw_scan_task, 0, lkpi_sw_scan_task, lvif);3940INIT_LIST_HEAD(&lvif->lsta_list);3941lvif->lvif_bss = NULL;3942refcount_init(&lvif->nt_unlocked, 0);3943lvif->lvif_bss_synched = false;3944vap = LVIF_TO_VAP(lvif);39453946vif = LVIF_TO_VIF(lvif);3947memcpy(vif->addr, mac, IEEE80211_ADDR_LEN);3948vif->p2p = false;3949vif->probe_req_reg = false;3950vif->type = lkpi_opmode_to_vif_type(opmode);3951lvif->wdev.iftype = vif->type;3952/* Need to fill in other fields as well. */3953IMPROVE();39543955/* XXX-BZ hardcoded for now! */3956#if 13957RCU_INIT_POINTER(vif->bss_conf.chanctx_conf, NULL);3958vif->bss_conf.vif = vif;3959/* vap->iv_myaddr is not set until net80211::vap_setup or vap_attach. */3960IEEE80211_ADDR_COPY(vif->bss_conf.addr, mac);3961lvif->lvif_ifllevent = EVENTHANDLER_REGISTER(iflladdr_event,3962lkpi_vif_iflladdr, vif, EVENTHANDLER_PRI_ANY);3963vif->bss_conf.link_id = 0; /* Non-MLO operation. */3964vif->bss_conf.chanreq.oper.width = NL80211_CHAN_WIDTH_20_NOHT;3965vif->bss_conf.use_short_preamble = false; /* vap->iv_flags IEEE80211_F_SHPREAMBLE */3966vif->bss_conf.use_short_slot = false; /* vap->iv_flags IEEE80211_F_SHSLOT */3967vif->bss_conf.qos = false;3968vif->bss_conf.use_cts_prot = false; /* vap->iv_protmode */3969vif->bss_conf.ht_operation_mode = IEEE80211_HT_OP_MODE_PROTECTION_NONE;3970vif->cfg.aid = 0;3971vif->cfg.assoc = false;3972vif->cfg.idle = true;3973vif->cfg.ps = false;3974IMPROVE("Check other fields and then figure out whats is left elsewhere of them");3975/*3976* We need to initialize it to something as the bss_info_changed call3977* will try to copy from it in iwlwifi and NULL is a panic.3978* We will set the proper one in scan_to_auth() before being assoc.3979*/3980vif->bss_conf.bssid = ieee80211broadcastaddr;3981#endif3982#if 03983vif->bss_conf.dtim_period = 0; /* IEEE80211_DTIM_DEFAULT ; must stay 0. */3984IEEE80211_ADDR_COPY(vif->bss_conf.bssid, bssid);3985vif->bss_conf.beacon_int = ic->ic_bintval;3986/* iwlwifi bug. */3987if (vif->bss_conf.beacon_int < 16)3988vif->bss_conf.beacon_int = 16;3989#endif39903991/* Link Config */3992vif->link_conf[0] = &vif->bss_conf;3993for (i = 0; i < nitems(vif->link_conf); i++) {3994IMPROVE("more than 1 link one day");3995}39963997/* Setup queue defaults; driver may override in (*add_interface). */3998for (i = 0; i < IEEE80211_NUM_ACS; i++) {3999if (ieee80211_hw_check(hw, QUEUE_CONTROL))4000vif->hw_queue[i] = IEEE80211_INVAL_HW_QUEUE;4001else if (hw->queues >= IEEE80211_NUM_ACS)4002vif->hw_queue[i] = i;4003else4004vif->hw_queue[i] = 0;40054006/* Initialize the queue to running. Stopped? */4007lvif->hw_queue_stopped[i] = false;4008}4009vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;40104011IMPROVE();40124013wiphy_lock(hw->wiphy);4014error = lkpi_80211_mo_start(hw);4015if (error != 0) {4016wiphy_unlock(hw->wiphy);4017ic_printf(ic, "%s: failed to start hw: %d\n", __func__, error);4018mtx_destroy(&lvif->mtx);4019free(lvif, M_80211_VAP);4020return (NULL);4021}40224023error = lkpi_80211_mo_add_interface(hw, vif);4024if (error != 0) {4025IMPROVE(); /* XXX-BZ mo_stop()? */4026wiphy_unlock(hw->wiphy);4027ic_printf(ic, "%s: failed to add interface: %d\n", __func__, error);4028mtx_destroy(&lvif->mtx);4029free(lvif, M_80211_VAP);4030return (NULL);4031}4032wiphy_unlock(hw->wiphy);40334034LKPI_80211_LHW_LVIF_LOCK(lhw);4035TAILQ_INSERT_TAIL(&lhw->lvif_head, lvif, lvif_entry);4036LKPI_80211_LHW_LVIF_UNLOCK(lhw);40374038/* Set bss_info. */4039changed = 0;4040lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, changed);40414042/* Configure tx queues (conf_tx), default WME & send BSS_CHANGED_QOS. */4043IMPROVE("Hardcoded values; to fix see 802.11-2016, 9.4.2.29 EDCA Parameter Set element");4044wiphy_lock(hw->wiphy);4045for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {40464047bzero(&txqp, sizeof(txqp));4048txqp.cw_min = 15;4049txqp.cw_max = 1023;4050txqp.txop = 0;4051txqp.aifs = 2;4052error = lkpi_80211_mo_conf_tx(hw, vif, /* link_id */0, ac, &txqp);4053if (error != 0)4054ic_printf(ic, "%s: conf_tx ac %u failed %d\n",4055__func__, ac, error);4056}4057wiphy_unlock(hw->wiphy);4058changed = BSS_CHANGED_QOS;4059lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, changed);40604061/* Force MC init. */4062lkpi_update_mcast_filter(ic);40634064ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid);40654066/* Now we have a valid vap->iv_ifp. Any checksum offloading goes below. */40674068IMPROVE();40694070/* Override with LinuxKPI method so we can drive mac80211/cfg80211. */4071lvif->iv_newstate = vap->iv_newstate;4072vap->iv_newstate = lkpi_iv_newstate;4073lvif->iv_update_bss = vap->iv_update_bss;4074vap->iv_update_bss = lkpi_iv_update_bss;4075lvif->iv_recv_mgmt = vap->iv_recv_mgmt;4076vap->iv_recv_mgmt = lkpi_iv_sta_recv_mgmt;40774078#ifdef LKPI_80211_HW_CRYPTO4079/* Key management. */4080if (lkpi_hwcrypto && lhw->ops->set_key != NULL) {4081vap->iv_key_set = lkpi_iv_key_set;4082vap->iv_key_delete = lkpi_iv_key_delete;4083vap->iv_key_update_begin = lkpi_iv_key_update_begin;4084vap->iv_key_update_end = lkpi_iv_key_update_end;4085}4086#endif40874088#ifdef LKPI_80211_HT4089/* Stay with the iv_ampdu_rxmax,limit / iv_ampdu_density defaults until later. */4090#endif40914092ieee80211_ratectl_init(vap);40934094/* Complete setup. */4095ieee80211_vap_attach(vap, ieee80211_media_change,4096ieee80211_media_status, mac);40974098#ifdef LKPI_80211_HT4099/*4100* Modern chipset/fw/drv will do A-MPDU in drv/fw and fail4101* to do so if they cannot do the crypto too.4102*/4103if (!lkpi_hwcrypto && IEEE80211_CONF_AMPDU_OFFLOAD(ic))4104vap->iv_flags_ht &= ~IEEE80211_FHT_AMPDU_RX;4105#endif41064107if (hw->max_listen_interval == 0)4108hw->max_listen_interval = 7 * (ic->ic_lintval / ic->ic_bintval);4109hw->conf.listen_interval = hw->max_listen_interval;4110ic->ic_set_channel(ic);41114112/* XXX-BZ do we need to be able to update these? */4113hw->wiphy->frag_threshold = vap->iv_fragthreshold;4114lkpi_80211_mo_set_frag_threshold(hw, vap->iv_fragthreshold);4115hw->wiphy->rts_threshold = vap->iv_rtsthreshold;4116lkpi_80211_mo_set_rts_threshold(hw, vap->iv_rtsthreshold);4117/* any others? */41184119/* Add per-VIF/VAP sysctls. */4120sysctl_ctx_init(&lvif->sysctl_ctx);41214122node = SYSCTL_ADD_NODE(&lvif->sysctl_ctx,4123SYSCTL_CHILDREN(&sysctl___compat_linuxkpi_80211),4124OID_AUTO, if_name(vap->iv_ifp),4125CTLFLAG_RD | CTLFLAG_SKIP | CTLFLAG_MPSAFE, NULL, "VIF Information");41264127SYSCTL_ADD_PROC(&lvif->sysctl_ctx,4128SYSCTL_CHILDREN(node), OID_AUTO, "dump_stas",4129CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, lvif, 0,4130lkpi_80211_dump_stas, "A", "Dump sta statistics of this vif");41314132IMPROVE();41334134return (vap);4135}41364137void4138linuxkpi_ieee80211_unregister_hw(struct ieee80211_hw *hw)4139{41404141wiphy_unregister(hw->wiphy);4142linuxkpi_ieee80211_ifdetach(hw);41434144IMPROVE();4145}41464147void4148linuxkpi_ieee80211_restart_hw(struct ieee80211_hw *hw)4149{41504151TODO();4152}41534154static void4155lkpi_ic_vap_delete(struct ieee80211vap *vap)4156{4157struct ieee80211com *ic;4158struct lkpi_hw *lhw;4159struct ieee80211_hw *hw;4160struct lkpi_vif *lvif;4161struct ieee80211_vif *vif;41624163lvif = VAP_TO_LVIF(vap);4164vif = LVIF_TO_VIF(lvif);4165ic = vap->iv_ic;4166lhw = ic->ic_softc;4167hw = LHW_TO_HW(lhw);41684169EVENTHANDLER_DEREGISTER(iflladdr_event, lvif->lvif_ifllevent);41704171/* Clear up per-VIF/VAP sysctls. */4172sysctl_ctx_free(&lvif->sysctl_ctx);41734174ieee80211_draintask(ic, &lvif->sw_scan_task);41754176LKPI_80211_LHW_LVIF_LOCK(lhw);4177TAILQ_REMOVE(&lhw->lvif_head, lvif, lvif_entry);4178LKPI_80211_LHW_LVIF_UNLOCK(lhw);41794180ieee80211_ratectl_deinit(vap);4181ieee80211_vap_detach(vap);41824183IMPROVE("clear up other bits in this state");41844185lkpi_80211_mo_remove_interface(hw, vif);41864187/* Single VAP, so we can do this here. */4188lkpi_80211_mo_stop(hw, false); /* XXX SUSPEND */41894190mtx_destroy(&lvif->mtx);4191free(lvif, M_80211_VAP);4192}41934194static void4195lkpi_ic_update_mcast(struct ieee80211com *ic)4196{4197struct ieee80211vap *vap;4198struct lkpi_hw *lhw;41994200lhw = ic->ic_softc;4201if (lhw->ops->prepare_multicast == NULL ||4202lhw->ops->configure_filter == NULL)4203return;42044205LKPI_80211_LHW_MC_LOCK(lhw);4206/* Cleanup anything on the current list. */4207lkpi_cleanup_mcast_list_locked(lhw);42084209/* Build up the new list (or allmulti). */4210if (ic->ic_allmulti == 0) {4211TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)4212if_foreach_llmaddr(vap->iv_ifp,4213lkpi_ic_update_mcast_copy, &lhw->mc_list);4214lhw->mc_all_multi = false;4215} else {4216lhw->mc_all_multi = true;4217}4218LKPI_80211_LHW_MC_UNLOCK(lhw);42194220lkpi_update_mcast_filter(ic);4221TRACEOK();4222}42234224static void4225lkpi_ic_update_promisc(struct ieee80211com *ic)4226{42274228UNIMPLEMENTED;4229}42304231static void4232lkpi_ic_update_chw(struct ieee80211com *ic)4233{42344235UNIMPLEMENTED;4236}42374238/* Start / stop device. */4239static void4240lkpi_ic_parent(struct ieee80211com *ic)4241{4242struct lkpi_hw *lhw;4243struct ieee80211_hw *hw;4244#ifdef HW_START_STOP4245int error;4246#endif4247bool start_all;42484249IMPROVE();42504251lhw = ic->ic_softc;4252hw = LHW_TO_HW(lhw);4253start_all = false;42544255/* IEEE80211_UNLOCK(ic); */4256wiphy_lock(hw->wiphy);4257if (ic->ic_nrunning > 0) {4258#ifdef HW_START_STOP4259error = lkpi_80211_mo_start(hw);4260if (error == 0)4261#endif4262start_all = true;4263} else {4264#ifdef HW_START_STOP4265lkpi_80211_mo_stop(hw, false); /* XXX SUSPEND */4266#endif4267}4268wiphy_unlock(hw->wiphy);4269/* IEEE80211_LOCK(ic); */42704271if (start_all)4272ieee80211_start_all(ic);4273}42744275bool4276linuxkpi_ieee80211_is_ie_id_in_ie_buf(const u8 ie, const u8 *ie_ids,4277size_t ie_ids_len)4278{4279int i;42804281for (i = 0; i < ie_ids_len; i++) {4282if (ie == *ie_ids)4283return (true);4284}42854286return (false);4287}42884289/* Return true if skipped; false if error. */4290bool4291linuxkpi_ieee80211_ie_advance(size_t *xp, const u8 *ies, size_t ies_len)4292{4293size_t x;4294uint8_t l;42954296x = *xp;42974298KASSERT(x < ies_len, ("%s: x %zu ies_len %zu ies %p\n",4299__func__, x, ies_len, ies));4300l = ies[x + 1];4301x += 2 + l;43024303if (x > ies_len)4304return (false);43054306*xp = x;4307return (true);4308}43094310static uint8_t *4311lkpi_scan_ies_add(uint8_t *p, struct ieee80211_scan_ies *scan_ies,4312uint32_t band_mask, struct ieee80211vap *vap, struct ieee80211_hw *hw)4313{4314struct ieee80211_supported_band *supband;4315struct linuxkpi_ieee80211_channel *channels;4316struct ieee80211com *ic;4317const struct ieee80211_channel *chan;4318const struct ieee80211_rateset *rs;4319uint8_t *pb;4320int band, i;43214322ic = vap->iv_ic;4323for (band = 0; band < NUM_NL80211_BANDS; band++) {4324if ((band_mask & (1 << band)) == 0)4325continue;43264327supband = hw->wiphy->bands[band];4328/*4329* This should not happen;4330* band_mask is a bitmask of valid bands to scan on.4331*/4332if (supband == NULL || supband->n_channels == 0)4333continue;43344335/* Find a first channel to get the mode and rates from. */4336channels = supband->channels;4337chan = NULL;4338for (i = 0; i < supband->n_channels; i++) {4339uint32_t flags;43404341if (channels[i].flags & IEEE80211_CHAN_DISABLED)4342continue;43434344flags = 0;4345switch (band) {4346case NL80211_BAND_2GHZ:4347flags |= IEEE80211_CHAN_G;4348break;4349case NL80211_BAND_5GHZ:4350flags |= IEEE80211_CHAN_A;4351break;4352default:4353panic("%s:%d: unupported band %d\n",4354__func__, __LINE__, band);4355}43564357chan = ieee80211_find_channel(ic,4358channels[i].center_freq, flags);4359if (chan != NULL)4360break;4361}43624363/* This really should not happen. */4364if (chan == NULL)4365continue;43664367pb = p;4368rs = ieee80211_get_suprates(ic, chan); /* calls chan2mode */4369p = ieee80211_add_rates(p, rs);4370p = ieee80211_add_xrates(p, rs);43714372#if defined(LKPI_80211_HT)4373if ((vap->iv_flags_ht & IEEE80211_FHT_HT) != 0) {4374struct ieee80211_channel *c;43754376c = ieee80211_ht_adjust_channel(ic, ic->ic_curchan,4377vap->iv_flags_ht);4378p = ieee80211_add_htcap_ch(p, vap, c);4379}4380#endif4381#if defined(LKPI_80211_VHT)4382if (band == NL80211_BAND_5GHZ &&4383(vap->iv_vht_flags & IEEE80211_FVHT_VHT) != 0) {4384struct ieee80211_channel *c;43854386c = ieee80211_ht_adjust_channel(ic, ic->ic_curchan,4387vap->iv_flags_ht);4388c = ieee80211_vht_adjust_channel(ic, c,4389vap->iv_vht_flags);4390p = ieee80211_add_vhtcap_ch(p, vap, c);4391}4392#endif43934394scan_ies->ies[band] = pb;4395scan_ies->len[band] = p - pb;4396}43974398/* Add common_ies */4399pb = p;4400if ((vap->iv_flags & IEEE80211_F_WPA1) != 0 &&4401vap->iv_wpa_ie != NULL) {4402memcpy(p, vap->iv_wpa_ie, 2 + vap->iv_wpa_ie[1]);4403p += 2 + vap->iv_wpa_ie[1];4404}4405if (vap->iv_appie_probereq != NULL) {4406memcpy(p, vap->iv_appie_probereq->ie_data,4407vap->iv_appie_probereq->ie_len);4408p += vap->iv_appie_probereq->ie_len;4409}4410scan_ies->common_ies = pb;4411scan_ies->common_ie_len = p - pb;44124413return (p);4414}44154416static void4417lkpi_enable_hw_scan(struct lkpi_hw *lhw)4418{44194420if (lhw->ops->hw_scan) {4421/*4422* Advertise full-offload scanning.4423*4424* Not limiting to SINGLE_SCAN_ON_ALL_BANDS here as otherwise4425* we essentially disable hw_scan for all drivers not setting4426* the flag.4427*/4428lhw->ic->ic_flags_ext |= IEEE80211_FEXT_SCAN_OFFLOAD;4429lhw->scan_flags |= LKPI_LHW_SCAN_HW;4430}4431}44324433#ifndef LKPI_80211_USE_SCANLIST4434static const uint32_t chan_pri[] = {44355180, 5500, 5745,44365260, 5580, 5660, 5825,44375220, 5300, 5540, 5620, 5700, 5785, 5865,44382437, 2412, 2422, 2462, 2472, 2432, 24524439};44404441static int4442lkpi_scan_chan_list_idx(const struct linuxkpi_ieee80211_channel *lc)4443{4444int i;44454446for (i = 0; i < nitems(chan_pri); i++) {4447if (lc->center_freq == chan_pri[i])4448return (i);4449}44504451return (-1);4452}44534454static int4455lkpi_scan_chan_list_comp(const struct linuxkpi_ieee80211_channel *lc1,4456const struct linuxkpi_ieee80211_channel *lc2)4457{4458int idx1, idx2;44594460/* Find index in list. */4461idx1 = lkpi_scan_chan_list_idx(lc1);4462idx2 = lkpi_scan_chan_list_idx(lc2);44634464if (idx1 == -1 && idx2 != -1)4465return (1);4466if (idx1 != -1 && idx2 == -1)4467return (-1);44684469/* Neither on the list, use center_freq. */4470if (idx1 == -1 && idx2 == -1)4471return (lc1->center_freq - lc2->center_freq);44724473/* Whichever is first in the list. */4474return (idx1 - idx2);4475}44764477static void4478lkpi_scan_chan_list_resort(struct linuxkpi_ieee80211_channel **cpp, size_t nchan)4479{4480struct linuxkpi_ieee80211_channel *lc, *nc;4481size_t i, j;4482int rc;44834484for (i = (nchan - 1); i > 0; i--) {4485for (j = i; j > 0 ; j--) {4486lc = *(cpp + j);4487nc = *(cpp + j - 1);4488rc = lkpi_scan_chan_list_comp(lc, nc);4489if (rc < 0) {4490*(cpp + j) = nc;4491*(cpp + j - 1) = lc;4492}4493}4494}4495}44964497static bool4498lkpi_scan_chan(struct linuxkpi_ieee80211_channel *c,4499struct ieee80211com *ic, bool log)4500{45014502if ((c->flags & IEEE80211_CHAN_DISABLED) != 0) {4503if (log)4504TRACE_SCAN(ic, "Skipping disabled chan "4505"on band %s [%#x/%u/%#x]",4506lkpi_nl80211_band_name(c->band), c->hw_value,4507c->center_freq, c->flags);4508return (false);4509}4510if (isclr(ic->ic_chan_active, ieee80211_mhz2ieee(c->center_freq,4511lkpi_nl80211_band_to_net80211_band(c->band)))) {4512if (log)4513TRACE_SCAN(ic, "Skipping !active chan "4514"on band %s [%#x/%u/%#x]",4515lkpi_nl80211_band_name(c->band), c->hw_value,4516c->center_freq, c->flags);4517return (false);4518}4519return (true);4520}4521#endif45224523static void4524lkpi_ic_scan_start(struct ieee80211com *ic)4525{4526struct lkpi_hw *lhw;4527struct ieee80211_hw *hw;4528struct lkpi_vif *lvif;4529struct ieee80211_vif *vif;4530struct ieee80211_scan_state *ss;4531struct ieee80211vap *vap;4532int error;4533bool is_hw_scan;45344535lhw = ic->ic_softc;4536ss = ic->ic_scan;4537vap = ss->ss_vap;4538TRACE_SCAN(ic, "scan_flags %b", lhw->scan_flags, LKPI_LHW_SCAN_BITS);45394540LKPI_80211_LHW_SCAN_LOCK(lhw);4541if ((lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0) {4542/* A scan is still running. */4543LKPI_80211_LHW_SCAN_UNLOCK(lhw);4544TRACE_SCAN(ic, "Trying to start new scan while still running; "4545"cancelling new net80211 scan; scan_flags %b",4546lhw->scan_flags, LKPI_LHW_SCAN_BITS);4547ieee80211_cancel_scan(vap);4548return;4549}4550is_hw_scan = (lhw->scan_flags & LKPI_LHW_SCAN_HW) != 0;4551LKPI_80211_LHW_SCAN_UNLOCK(lhw);45524553#if 04554if (vap->iv_state != IEEE80211_S_SCAN) {4555TODO("We need to be able to scan if not in S_SCAN");4556TRACE_SCAN(ic, "scan_flags %b iv_state %d",4557lhw->scan_flags, LKPI_LHW_SCAN_BITS, vap->iv_state);4558ieee80211_cancel_scan(vap);4559return;4560}4561#endif45624563hw = LHW_TO_HW(lhw);4564if (!is_hw_scan) {4565/* If hw_scan is cleared clear FEXT_SCAN_OFFLOAD too. */4566vap->iv_flags_ext &= ~IEEE80211_FEXT_SCAN_OFFLOAD;45674568lvif = VAP_TO_LVIF(vap);4569vif = LVIF_TO_VIF(lvif);45704571if (vap->iv_state == IEEE80211_S_SCAN)4572lkpi_hw_conf_idle(hw, false);45734574LKPI_80211_LHW_SCAN_LOCK(lhw);4575lhw->scan_flags |= LKPI_LHW_SCAN_RUNNING;4576LKPI_80211_LHW_SCAN_UNLOCK(lhw);45774578lkpi_update_mcast_filter(ic);45794580TRACE_SCAN(vap->iv_ic, "Starting SW_SCAN: scan_flags %b",4581lhw->scan_flags, LKPI_LHW_SCAN_BITS);4582lkpi_80211_mo_sw_scan_start(hw, vif, vif->addr);4583/* net80211::scan_start() handled PS for us. */4584IMPROVE();4585/* XXX Also means it is too late to flush queues?4586* need to check iv_sta_ps or overload? */4587/* XXX want to adjust ss end time/ maxdwell? */45884589} else {4590struct ieee80211_scan_request *hw_req;4591struct linuxkpi_ieee80211_channel *lc, **cpp;4592struct cfg80211_ssid *ssids;4593struct cfg80211_scan_6ghz_params *s6gp;4594size_t chan_len, nchan, ssids_len, s6ghzlen;4595int band, i, ssid_count, common_ie_len;4596#ifndef LKPI_80211_USE_SCANLIST4597int n;4598#endif4599uint32_t band_mask;4600uint8_t *ie, *ieend;4601bool running;46024603ssid_count = min(ss->ss_nssid, hw->wiphy->max_scan_ssids);4604ssids_len = ssid_count * sizeof(*ssids);4605s6ghzlen = 0 * (sizeof(*s6gp)); /* XXX-BZ */46064607band_mask = 0;4608nchan = 0;4609if (ieee80211_hw_check(hw, SINGLE_SCAN_ON_ALL_BANDS)) {4610#ifdef LKPI_80211_USE_SCANLIST4611/* Avoid net80211 scan lists until it has proper scan offload support. */4612for (i = ss->ss_next; i < ss->ss_last; i++) {4613nchan++;4614band = lkpi_net80211_chan_to_nl80211_band(4615ss->ss_chans[ss->ss_next + i]);4616band_mask |= (1 << band);4617}4618#else4619/* Instead we scan for all channels all the time. */4620for (band = 0; band < NUM_NL80211_BANDS; band++) {4621switch (band) {4622case NL80211_BAND_2GHZ:4623case NL80211_BAND_5GHZ:4624break;4625default:4626continue;4627}4628if (hw->wiphy->bands[band] != NULL) {4629struct linuxkpi_ieee80211_channel *channels;4630int n;46314632band_mask |= (1 << band);46334634channels = hw->wiphy->bands[band]->channels;4635n = hw->wiphy->bands[band]->n_channels;4636for (i = 0; i < n; i++) {4637if (lkpi_scan_chan(&channels[i], ic, true))4638nchan++;4639}4640}4641}4642#endif4643} else {4644IMPROVE("individual band scans not yet supported, only scanning first band");4645/* In theory net80211 should drive this. */4646/* Probably we need to add local logic for now;4647* need to deal with scan_complete4648* and cancel_scan and keep local state.4649* Also cut the nchan down above.4650*/4651/* XXX-BZ ath10k does not set this but still does it? &$%^ */4652}46534654chan_len = nchan * (sizeof(lc) + sizeof(*lc));46554656common_ie_len = 0;4657if ((vap->iv_flags & IEEE80211_F_WPA1) != 0 &&4658vap->iv_wpa_ie != NULL)4659common_ie_len += vap->iv_wpa_ie[1];4660if (vap->iv_appie_probereq != NULL)4661common_ie_len += vap->iv_appie_probereq->ie_len;46624663/* We would love to check this at an earlier stage... */4664if (common_ie_len > hw->wiphy->max_scan_ie_len) {4665ic_printf(ic, "WARNING: %s: common_ie_len %d > "4666"wiphy->max_scan_ie_len %d\n", __func__,4667common_ie_len, hw->wiphy->max_scan_ie_len);4668}46694670hw_req = malloc(sizeof(*hw_req) + ssids_len +4671s6ghzlen + chan_len + lhw->supbands * lhw->scan_ie_len +4672common_ie_len, M_LKPI80211, M_WAITOK | M_ZERO);46734674hw_req->req.flags = 0; /* XXX ??? */4675/* hw_req->req.wdev */4676hw_req->req.wiphy = hw->wiphy;4677hw_req->req.no_cck = false; /* XXX */46784679/*4680* In general setting duration[_mandatory] seems to pessimise4681* default scanning behaviour. We only use it for BGSCANnig4682* to keep the dwell times small.4683* Setting duration_mandatory makes this the maximum dwell4684* time (otherwise may be shorter). Duration is in TU.4685*/4686if ((ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN) != 0) {4687unsigned long dwell;46884689if ((ic->ic_caps & IEEE80211_C_BGSCAN) == 0 ||4690(vap->iv_flags & IEEE80211_F_BGSCAN) == 0)4691ic_printf(ic, "BGSCAN despite off: %b, %b, %b\n",4692ic->ic_flags_ext, IEEE80211_FEXT_BITS,4693vap->iv_flags, IEEE80211_F_BITS,4694ic->ic_caps, IEEE80211_C_BITS);46954696dwell = ss->ss_mindwell;4697if (dwell == 0)4698dwell = msecs_to_ticks(20);46994700hw_req->req.duration_mandatory = true;4701hw_req->req.duration = TICKS_2_USEC(dwell) / 1024;4702}47034704#ifdef __notyet__4705hw_req->req.flags |= NL80211_SCAN_FLAG_RANDOM_ADDR;4706memcpy(hw_req->req.mac_addr, xxx, IEEE80211_ADDR_LEN);4707memset(hw_req->req.mac_addr_mask, 0xxx, IEEE80211_ADDR_LEN);4708#endif4709eth_broadcast_addr(hw_req->req.bssid);47104711hw_req->req.n_channels = nchan;4712cpp = (struct linuxkpi_ieee80211_channel **)(hw_req + 1);4713lc = (struct linuxkpi_ieee80211_channel *)(cpp + nchan);4714#ifdef LKPI_80211_USE_SCANLIST4715for (i = 0; i < nchan; i++) {4716*(cpp + i) =4717(struct linuxkpi_ieee80211_channel *)(lc + i);4718}4719/* Avoid net80211 scan lists until it has proper scan offload support. */4720for (i = 0; i < nchan; i++) {4721struct ieee80211_channel *c;47224723c = ss->ss_chans[ss->ss_next + i];4724lc->center_freq = c->ic_freq; /* XXX */4725/* lc->flags */4726lc->band = lkpi_net80211_chan_to_nl80211_band(c);4727lc->max_power = c->ic_maxpower;4728/* lc-> ... */4729lc++;4730}4731#else4732/* Add bands in reverse order for scanning. */4733n = 0;4734for (band = NUM_NL80211_BANDS - 1; band >= 0; band--) {4735struct ieee80211_supported_band *supband;4736struct linuxkpi_ieee80211_channel *channels;47374738/* Band disabled for scanning? */4739if ((band_mask & (1 << band)) == 0)4740continue;47414742/* Nothing to scan in band? */4743supband = hw->wiphy->bands[band];4744if (supband == NULL || supband->n_channels == 0)4745continue;47464747channels = supband->channels;4748for (i = 0; i < supband->n_channels; i++) {4749if (lkpi_scan_chan(&channels[i], ic, false))4750*(cpp + n++) = &channels[i];4751}4752}4753if (lkpi_order_scanlist)4754lkpi_scan_chan_list_resort(cpp, nchan);47554756if ((linuxkpi_debug_80211 & D80211_SCAN) != 0) {4757printf("%s:%d: %s SCAN Channel List (nchan=%zu): ",4758__func__, __LINE__, ic->ic_name, nchan);4759for (i = 0; i < nchan; i++) {4760struct linuxkpi_ieee80211_channel *xc;47614762xc = *(cpp + i);4763printf(" %d(%d)",4764ieee80211_mhz2ieee(xc->center_freq,4765lkpi_nl80211_band_to_net80211_band(4766xc->band)),4767xc->center_freq);4768}4769printf("\n");4770}4771#endif47724773hw_req->req.n_ssids = ssid_count;4774if (hw_req->req.n_ssids > 0) {4775ssids = (struct cfg80211_ssid *)lc;4776hw_req->req.ssids = ssids;4777for (i = 0; i < ssid_count; i++) {4778ssids->ssid_len = ss->ss_ssid[i].len;4779memcpy(ssids->ssid, ss->ss_ssid[i].ssid,4780ss->ss_ssid[i].len);4781ssids++;4782}4783s6gp = (struct cfg80211_scan_6ghz_params *)ssids;4784} else {4785s6gp = (struct cfg80211_scan_6ghz_params *)lc;4786}47874788/* 6GHz one day. */4789hw_req->req.n_6ghz_params = 0;4790hw_req->req.scan_6ghz_params = NULL;4791hw_req->req.scan_6ghz = false; /* Weird boolean; not what you think. */4792/* s6gp->... */47934794ie = ieend = (uint8_t *)s6gp;4795/* Copy per-band IEs, copy common IEs */4796ieend = lkpi_scan_ies_add(ie, &hw_req->ies, band_mask, vap, hw);4797hw_req->req.ie = ie;4798hw_req->req.ie_len = ieend - ie;4799hw_req->req.scan_start = jiffies;48004801lvif = VAP_TO_LVIF(vap);4802vif = LVIF_TO_VIF(lvif);48034804LKPI_80211_LHW_SCAN_LOCK(lhw);4805/* Re-check under lock. */4806running = (lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0;4807if (!running) {4808KASSERT(lhw->hw_req == NULL, ("%s: ic %p lhw %p hw_req %p "4809"!= NULL\n", __func__, ic, lhw, lhw->hw_req));48104811lhw->scan_flags |= LKPI_LHW_SCAN_RUNNING;4812lhw->hw_req = hw_req;4813}4814LKPI_80211_LHW_SCAN_UNLOCK(lhw);4815if (running) {4816free(hw_req, M_LKPI80211);4817TRACE_SCAN(ic, "Trying to start new scan while still "4818"running (2); cancelling new net80211 scan; "4819"scan_flags %b",4820lhw->scan_flags, LKPI_LHW_SCAN_BITS);4821ieee80211_cancel_scan(vap);4822return;4823}48244825lkpi_update_mcast_filter(ic);4826TRACE_SCAN(ic, "Starting HW_SCAN: scan_flags %b, "4827"ie_len %d, n_ssids %d, n_chan %d, common_ie_len %d [%d, %d]",4828lhw->scan_flags, LKPI_LHW_SCAN_BITS, hw_req->req.ie_len,4829hw_req->req.n_ssids, hw_req->req.n_channels,4830hw_req->ies.common_ie_len,4831hw_req->ies.len[NL80211_BAND_2GHZ],4832hw_req->ies.len[NL80211_BAND_5GHZ]);48334834error = lkpi_80211_mo_hw_scan(hw, vif, hw_req);4835if (error != 0) {4836bool scan_done;4837int e;48384839TRACE_SCAN(ic, "hw_scan failed; scan_flags %b, error %d",4840lhw->scan_flags, LKPI_LHW_SCAN_BITS, error);4841ieee80211_cancel_scan(vap);48424843/*4844* ieee80211_scan_completed must be called in either4845* case of error or none. So let the free happen there4846* and only there.4847* That would be fine in theory but in practice drivers4848* behave differently:4849* ath10k does not return hw_scan until after scan_complete4850* and can then still return an error.4851* rtw88 can return 1 or -EBUSY without scan_complete4852* iwlwifi can return various errors before scan starts4853* ...4854* So we cannot rely on that behaviour and have to check4855* and balance between both code paths.4856*/4857e = 0;4858scan_done = true;4859LKPI_80211_LHW_SCAN_LOCK(lhw);4860if ((lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0) {48614862free(lhw->hw_req, M_LKPI80211);4863lhw->hw_req = NULL;4864/*4865* The ieee80211_cancel_scan() above runs in a4866* taskq and it may take ages for the previous4867* scan to clear; starting a new one right away4868* we run into the problem that the old one is4869* still active.4870*/4871e = msleep(lhw, &lhw->scan_mtx, 0, "lhwscanstop", hz);4872scan_done = (lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0;48734874/*4875* Now we can clear running if no one else did.4876*/4877lhw->scan_flags &= ~LKPI_LHW_SCAN_RUNNING;4878}4879LKPI_80211_LHW_SCAN_UNLOCK(lhw);4880lkpi_update_mcast_filter(ic);4881if (!scan_done) {4882ic_printf(ic, "ERROR: %s: timeout/error to wait "4883"for ieee80211_cancel_scan: %d\n", __func__, e);4884return;4885}48864887/*4888* XXX-SIGH magic number.4889* rtw88 has a magic "return 1" if offloading scan is4890* not possible. Fall back to sw scan in that case.4891*/4892if (error == 1) {4893/*4894* We need to put this into some defered context4895* the net80211 scan may not be done yet4896* (ic_flags & IEEE80211_F_SCAN) and we cannot4897* wait here; if we do scan_curchan_task always4898* runs after our timeout to finalize the scan.4899*/4900ieee80211_runtask(ic, &lvif->sw_scan_task);4901return;4902}49034904ic_printf(ic, "ERROR: %s: hw_scan returned %d\n",4905__func__, error);4906}4907}4908}49094910static void4911lkpi_sw_scan_task(void *arg, int pending __unused)4912{4913struct lkpi_hw *lhw;4914struct lkpi_vif *lvif;4915struct ieee80211vap *vap;4916struct ieee80211_scan_state *ss;49174918lvif = arg;4919vap = LVIF_TO_VAP(lvif);4920lhw = vap->iv_ic->ic_softc;4921ss = vap->iv_ic->ic_scan;49224923LKPI_80211_LHW_SCAN_LOCK(lhw);4924/*4925* We will re-enable this at scan_end calling lkpi_enable_hw_scan().4926* IEEE80211_FEXT_SCAN_OFFLOAD will be cleared by lkpi_ic_scan_start.4927*/4928lhw->scan_flags &= ~LKPI_LHW_SCAN_HW;4929LKPI_80211_LHW_SCAN_UNLOCK(lhw);49304931TRACE_SCAN(vap->iv_ic, "Triggering SW_SCAN: pending %d, scan_flags %b",4932pending, lhw->scan_flags, LKPI_LHW_SCAN_BITS);49334934/*4935* This will call ic_scan_start() and we will get into the right path4936* unless other scans started in between.4937*/4938ieee80211_start_scan(vap,4939IEEE80211_SCAN_ONCE,4940msecs_to_ticks(10000), /* 10000 ms (=~ 50 chan * 200 ms) */4941ss->ss_mindwell ? ss->ss_mindwell : msecs_to_ticks(20),4942ss->ss_maxdwell ? ss->ss_maxdwell : msecs_to_ticks(200),4943vap->iv_des_nssid, vap->iv_des_ssid);4944}49454946static void4947lkpi_ic_scan_end(struct ieee80211com *ic)4948{4949struct lkpi_hw *lhw;4950bool is_hw_scan;49514952lhw = ic->ic_softc;4953TRACE_SCAN(ic, "scan_flags %b", lhw->scan_flags, LKPI_LHW_SCAN_BITS);49544955LKPI_80211_LHW_SCAN_LOCK(lhw);4956if ((lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) == 0) {4957LKPI_80211_LHW_SCAN_UNLOCK(lhw);4958return;4959}4960is_hw_scan = (lhw->scan_flags & LKPI_LHW_SCAN_HW) != 0;4961LKPI_80211_LHW_SCAN_UNLOCK(lhw);49624963if (!is_hw_scan) {4964struct ieee80211_scan_state *ss;4965struct ieee80211vap *vap;4966struct ieee80211_hw *hw;4967struct lkpi_vif *lvif;4968struct ieee80211_vif *vif;49694970ss = ic->ic_scan;4971vap = ss->ss_vap;4972hw = LHW_TO_HW(lhw);4973lvif = VAP_TO_LVIF(vap);4974vif = LVIF_TO_VIF(lvif);49754976lkpi_80211_mo_sw_scan_complete(hw, vif);49774978/* Send PS to stop buffering if n80211 does not for us? */49794980if (vap->iv_state == IEEE80211_S_SCAN)4981lkpi_hw_conf_idle(hw, true);4982}49834984/*4985* In case we disabled the hw_scan in lkpi_ic_scan_start() and4986* switched to swscan, re-enable hw_scan if available.4987*/4988lkpi_enable_hw_scan(lhw);49894990LKPI_80211_LHW_SCAN_LOCK(lhw);4991wakeup(lhw);4992LKPI_80211_LHW_SCAN_UNLOCK(lhw);4993}49944995static void4996lkpi_ic_scan_curchan(struct ieee80211_scan_state *ss,4997unsigned long maxdwell)4998{4999struct lkpi_hw *lhw;5000bool is_hw_scan;50015002lhw = ss->ss_ic->ic_softc;5003TRACE_SCAN(ss->ss_ic, "scan_flags %b chan %d maxdwell %lu",5004lhw->scan_flags, LKPI_LHW_SCAN_BITS,5005ss->ss_ic->ic_curchan->ic_ieee, maxdwell);50065007LKPI_80211_LHW_SCAN_LOCK(lhw);5008is_hw_scan = (lhw->scan_flags & LKPI_LHW_SCAN_HW) != 0;5009LKPI_80211_LHW_SCAN_UNLOCK(lhw);5010if (!is_hw_scan)5011lhw->ic_scan_curchan(ss, maxdwell);5012}50135014static void5015lkpi_ic_scan_mindwell(struct ieee80211_scan_state *ss)5016{5017struct lkpi_hw *lhw;5018bool is_hw_scan;50195020lhw = ss->ss_ic->ic_softc;5021TRACE_SCAN(ss->ss_ic, "scan_flags %b chan %d mindwell %lu",5022lhw->scan_flags, LKPI_LHW_SCAN_BITS,5023ss->ss_ic->ic_curchan->ic_ieee, ss->ss_mindwell);50245025LKPI_80211_LHW_SCAN_LOCK(lhw);5026is_hw_scan = (lhw->scan_flags & LKPI_LHW_SCAN_HW) != 0;5027LKPI_80211_LHW_SCAN_UNLOCK(lhw);5028if (!is_hw_scan)5029lhw->ic_scan_mindwell(ss);5030}50315032static void5033lkpi_ic_set_channel(struct ieee80211com *ic)5034{5035struct lkpi_hw *lhw;5036struct ieee80211_hw *hw;5037struct ieee80211_channel *c;5038struct linuxkpi_ieee80211_channel *chan;5039int error;5040bool hw_scan_running;50415042lhw = ic->ic_softc;50435044/* If we do not support (*config)() save us the work. */5045if (lhw->ops->config == NULL)5046return;50475048/* If we have a hw_scan running do not switch channels. */5049LKPI_80211_LHW_SCAN_LOCK(lhw);5050hw_scan_running =5051(lhw->scan_flags & (LKPI_LHW_SCAN_RUNNING|LKPI_LHW_SCAN_HW)) ==5052(LKPI_LHW_SCAN_RUNNING|LKPI_LHW_SCAN_HW);5053LKPI_80211_LHW_SCAN_UNLOCK(lhw);5054if (hw_scan_running)5055return;50565057c = ic->ic_curchan;5058if (c == NULL || c == IEEE80211_CHAN_ANYC) {5059ic_printf(ic, "%s: c %p ops->config %p\n", __func__,5060c, lhw->ops->config);5061return;5062}50635064chan = lkpi_find_lkpi80211_chan(lhw, c);5065if (chan == NULL) {5066ic_printf(ic, "%s: c %p chan %p\n", __func__,5067c, chan);5068return;5069}50705071/* XXX max power for scanning? */5072IMPROVE();50735074hw = LHW_TO_HW(lhw);5075cfg80211_chandef_create(&hw->conf.chandef, chan,5076#ifdef LKPI_80211_HT5077(ic->ic_flags_ht & IEEE80211_FHT_HT) ? NL80211_CHAN_HT20 :5078#endif5079NL80211_CHAN_NO_HT);50805081error = lkpi_80211_mo_config(hw, IEEE80211_CONF_CHANGE_CHANNEL);5082if (error != 0 && error != EOPNOTSUPP) {5083ic_printf(ic, "ERROR: %s: config %#0x returned %d\n",5084__func__, IEEE80211_CONF_CHANGE_CHANNEL, error);5085/* XXX should we unroll to the previous chandef? */5086IMPROVE();5087} else {5088/* Update radiotap channels as well. */5089lhw->rtap_tx.wt_chan_freq = htole16(c->ic_freq);5090lhw->rtap_tx.wt_chan_flags = htole16(c->ic_flags);5091lhw->rtap_rx.wr_chan_freq = htole16(c->ic_freq);5092lhw->rtap_rx.wr_chan_flags = htole16(c->ic_flags);5093}50945095/* Currently PS is hard coded off! Not sure it belongs here. */5096IMPROVE();5097if (ieee80211_hw_check(hw, SUPPORTS_PS) &&5098(hw->conf.flags & IEEE80211_CONF_PS) != 0) {5099hw->conf.flags &= ~IEEE80211_CONF_PS;5100error = lkpi_80211_mo_config(hw, IEEE80211_CONF_CHANGE_PS);5101if (error != 0 && error != EOPNOTSUPP)5102ic_printf(ic, "ERROR: %s: config %#0x returned "5103"%d\n", __func__, IEEE80211_CONF_CHANGE_PS,5104error);5105}5106}51075108static struct ieee80211_node *5109lkpi_ic_node_alloc(struct ieee80211vap *vap,5110const uint8_t mac[IEEE80211_ADDR_LEN])5111{5112struct ieee80211com *ic;5113struct lkpi_hw *lhw;5114struct ieee80211_node *ni;5115struct ieee80211_hw *hw;5116struct lkpi_sta *lsta;51175118ic = vap->iv_ic;5119lhw = ic->ic_softc;51205121/* We keep allocations de-coupled so we can deal with the two worlds. */5122if (lhw->ic_node_alloc == NULL)5123return (NULL);51245125ni = lhw->ic_node_alloc(vap, mac);5126if (ni == NULL)5127return (NULL);51285129hw = LHW_TO_HW(lhw);5130lsta = lkpi_lsta_alloc(vap, mac, hw, ni);5131if (lsta == NULL) {5132if (lhw->ic_node_free != NULL)5133lhw->ic_node_free(ni);5134return (NULL);5135}51365137return (ni);5138}51395140static int5141lkpi_ic_node_init(struct ieee80211_node *ni)5142{5143struct ieee80211com *ic;5144struct lkpi_hw *lhw;5145int error;51465147ic = ni->ni_ic;5148lhw = ic->ic_softc;51495150if (lhw->ic_node_init != NULL) {5151error = lhw->ic_node_init(ni);5152if (error != 0)5153return (error);5154}51555156/* XXX-BZ Sync other state over. */5157IMPROVE();51585159return (0);5160}51615162static void5163lkpi_ic_node_cleanup(struct ieee80211_node *ni)5164{5165struct ieee80211com *ic;5166struct lkpi_hw *lhw;51675168ic = ni->ni_ic;5169lhw = ic->ic_softc;51705171/* XXX-BZ remove from driver, ... */5172IMPROVE();51735174if (lhw->ic_node_cleanup != NULL)5175lhw->ic_node_cleanup(ni);5176}51775178static void5179lkpi_ic_node_free(struct ieee80211_node *ni)5180{5181struct ieee80211com *ic;5182struct lkpi_hw *lhw;5183struct lkpi_sta *lsta;51845185ic = ni->ni_ic;5186lhw = ic->ic_softc;5187lsta = ni->ni_drv_data;51885189/* KASSERT lsta is not NULL here. Print ni/ni__refcnt. */51905191/*5192* Pass in the original ni just in case of error we could check that5193* it is the same as lsta->ni.5194*/5195lkpi_lsta_free(lsta, ni);51965197if (lhw->ic_node_free != NULL)5198lhw->ic_node_free(ni);5199}52005201/*5202* lkpi_xmit() called from both the (*ic_raw_xmit) as well as the (*ic_transmit)5203* call path.5204* Unfortunately they have slightly different invariants. See5205* ieee80211_raw_output() and ieee80211_parent_xmitpkt().5206* Both take care of the ni reference in case of error, and otherwise during5207* the callback after transmit.5208* The difference is that in case of error (*ic_raw_xmit) needs us to release5209* the mbuf, while (*ic_transmit) will free the mbuf itself.5210*/5211static int5212lkpi_xmit(struct ieee80211_node *ni, struct mbuf *m,5213const struct ieee80211_bpf_params *params __unused,5214bool freem)5215{5216struct lkpi_sta *lsta;5217int error;52185219lsta = ni->ni_drv_data;5220LKPI_80211_LSTA_TXQ_LOCK(lsta);5221#if 05222if (!lsta->added_to_drv || !lsta->txq_ready) {5223#else5224/*5225* Backout this part of 886653492945f which breaks rtw88 or5226* in general drivers without (*sta_state)() but only the5227* legacy fallback to (*sta_add)().5228*/5229if (!lsta->txq_ready) {5230#endif5231LKPI_80211_LSTA_TXQ_UNLOCK(lsta);5232if (freem)5233m_free(m);5234return (ENETDOWN);5235}52365237/* Queue the packet and enqueue the task to handle it. */5238error = mbufq_enqueue(&lsta->txq, m);5239if (error != 0) {5240LKPI_80211_LSTA_TXQ_UNLOCK(lsta);5241if (freem)5242m_free(m);5243#ifdef LINUXKPI_DEBUG_802115244if (linuxkpi_debug_80211 & D80211_TRACE_TX)5245ic_printf(ni->ni_ic, "%s: mbufq_enqueue failed: %d\n",5246__func__, error);5247#endif5248return (ENETDOWN);5249}5250taskqueue_enqueue(taskqueue_thread, &lsta->txq_task);5251LKPI_80211_LSTA_TXQ_UNLOCK(lsta);52525253#ifdef LINUXKPI_DEBUG_802115254if (linuxkpi_debug_80211 & D80211_TRACE_TX)5255printf("%s:%d lsta %p ni %p %6D mbuf_qlen %d\n",5256__func__, __LINE__, lsta, ni, ni->ni_macaddr, ":",5257mbufq_len(&lsta->txq));5258#endif52595260return (0);5261}52625263static int5264lkpi_ic_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,5265const struct ieee80211_bpf_params *params __unused)5266{5267return (lkpi_xmit(ni, m, NULL, true));5268}52695270#ifdef LKPI_80211_HW_CRYPTO5271/*5272* This is a bit of a hack given we know we are operating on a5273* single frame and we know that hardware will deal with it.5274* But otherwise the enmic bit and the encrypt bit need to be5275* decoupled.5276*/5277static int5278lkpi_hw_crypto_prepare_tkip(struct ieee80211_key *k,5279struct ieee80211_key_conf *kc, struct sk_buff *skb)5280{5281struct ieee80211_hdr *hdr;5282uint32_t hlen, hdrlen;5283uint8_t *p;52845285/*5286* TKIP only happens on data.5287*/5288hdr = (void *)skb->data;5289if (!ieee80211_is_data_present(hdr->frame_control))5290return (0);52915292/*5293* "enmic" (though we do not do that).5294*/5295/* any conditions to not apply this? */5296if (skb_tailroom(skb) < k->wk_cipher->ic_miclen)5297return (ENOBUFS);52985299p = skb_put(skb, k->wk_cipher->ic_miclen);5300if ((kc->flags & IEEE80211_KEY_FLAG_PUT_MIC_SPACE) != 0)5301goto encrypt;53025303/*5304* (*enmic) which we hopefully do not have to do with hw accel.5305* That means if we make it here we have a problem.5306*/5307TODO("(*enmic)");5308return (ENXIO);53095310encrypt:5311/*5312* "encrypt" (though we do not do that).5313*/5314/*5315* Check if we have anything to do as requested by driver5316* or if we are done?5317*/5318if ((kc->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) == 0 &&5319(kc->flags & IEEE80211_KEY_FLAG_GENERATE_IV) == 0)5320return (0);53215322hlen = k->wk_cipher->ic_header;5323if (skb_headroom(skb) < hlen)5324return (ENOBUFS);53255326hdr = (void *)skb->data;5327hdrlen = ieee80211_hdrlen(hdr->frame_control);5328p = skb_push(skb, hlen);5329memmove(p, p + hlen, hdrlen);53305331/* If driver request space only we are done. */5332if ((kc->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) != 0)5333return (0);53345335p += hdrlen;5336k->wk_cipher->ic_setiv(k, p);53375338/* If we make it hear we do sw encryption. */5339TODO("sw encrypt");5340return (ENXIO);5341}53425343static int5344lkpi_hw_crypto_prepare_ccmp(struct ieee80211_key *k,5345struct ieee80211_key_conf *kc, struct sk_buff *skb)5346{5347struct ieee80211_hdr *hdr;5348uint32_t hlen, hdrlen;5349uint8_t *p;53505351hdr = (void *)skb->data;53525353/*5354* Check if we have anythig to do as requested by driver5355* or if we are done?5356*/5357if ((kc->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) == 0 &&5358(kc->flags & IEEE80211_KEY_FLAG_GENERATE_IV) == 0 &&5359/* MFP */5360!((kc->flags & IEEE80211_KEY_FLAG_GENERATE_IV_MGMT) != 0 &&5361ieee80211_is_mgmt(hdr->frame_control)))5362return (0);53635364hlen = k->wk_cipher->ic_header;5365if (skb_headroom(skb) < hlen)5366return (ENOBUFS);53675368hdrlen = ieee80211_hdrlen(hdr->frame_control);5369p = skb_push(skb, hlen);5370memmove(p, p + hlen, hdrlen);53715372/* If driver request space only we are done. */5373if ((kc->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) != 0)5374return (0);53755376p += hdrlen;5377k->wk_cipher->ic_setiv(k, p);53785379return (0);5380}53815382static int5383lkpi_hw_crypto_prepare(struct lkpi_sta *lsta, struct ieee80211_key *k,5384struct sk_buff *skb)5385{5386struct ieee80211_tx_info *info;5387struct ieee80211_key_conf *kc;53885389KASSERT(lsta != NULL, ("%s: lsta is NULL", __func__));5390KASSERT(k != NULL, ("%s: key is NULL", __func__));5391KASSERT(skb != NULL, ("%s: skb is NULL", __func__));53925393kc = lsta->kc[k->wk_keyix];53945395info = IEEE80211_SKB_CB(skb);5396info->control.hw_key = kc;53975398/* MUST NOT happen. KASSERT? */5399if (kc == NULL) {5400ic_printf(lsta->ni->ni_ic, "%s: lsta %p k %p skb %p, "5401"kc is NULL on hw crypto offload\n", __func__, lsta, k, skb);5402return (ENXIO);5403}54045405switch (kc->cipher) {5406case WLAN_CIPHER_SUITE_TKIP:5407return (lkpi_hw_crypto_prepare_tkip(k, kc, skb));5408case WLAN_CIPHER_SUITE_CCMP:5409return (lkpi_hw_crypto_prepare_ccmp(k, kc, skb));5410case WLAN_CIPHER_SUITE_GCMP:5411return (lkpi_hw_crypto_prepare_ccmp(k, kc, skb));5412case WLAN_CIPHER_SUITE_WEP40:5413case WLAN_CIPHER_SUITE_WEP104:5414case WLAN_CIPHER_SUITE_CCMP_256:5415case WLAN_CIPHER_SUITE_GCMP_256:5416case WLAN_CIPHER_SUITE_AES_CMAC:5417case WLAN_CIPHER_SUITE_BIP_CMAC_256:5418case WLAN_CIPHER_SUITE_BIP_GMAC_128:5419case WLAN_CIPHER_SUITE_BIP_GMAC_256:5420default:5421ic_printf(lsta->ni->ni_ic, "%s: lsta %p k %p kc %p skb %p, "5422"unsupported cipher suite %u (%s)\n", __func__, lsta, k, kc,5423skb, kc->cipher, lkpi_cipher_suite_to_name(kc->cipher));5424return (EOPNOTSUPP);5425}5426}54275428static uint8_t5429lkpi_hw_crypto_tailroom(struct lkpi_sta *lsta, struct ieee80211_key *k)5430{5431struct ieee80211_key_conf *kc;54325433kc = lsta->kc[k->wk_keyix];5434if (kc == NULL)5435return (0);54365437IMPROVE("which other flags need tailroom?");5438if (kc->flags & (IEEE80211_KEY_FLAG_PUT_MIC_SPACE))5439return (32); /* Large enough to hold everything and pow2. */54405441return (0);5442}5443#endif54445445static void5446lkpi_80211_txq_tx_one(struct lkpi_sta *lsta, struct mbuf *m)5447{5448struct ieee80211_node *ni;5449struct ieee80211_frame *wh;5450struct ieee80211_key *k;5451struct sk_buff *skb;5452struct ieee80211com *ic;5453struct lkpi_hw *lhw;5454struct ieee80211_hw *hw;5455struct lkpi_vif *lvif;5456struct ieee80211_vif *vif;5457struct ieee80211_channel *c;5458struct ieee80211_tx_control control;5459struct ieee80211_tx_info *info;5460struct ieee80211_sta *sta;5461struct ieee80211_hdr *hdr;5462struct lkpi_txq *ltxq;5463void *buf;5464ieee80211_keyix keyix;5465uint8_t ac, tid, tailroom;54665467M_ASSERTPKTHDR(m);5468#ifdef LINUXKPI_DEBUG_802115469if (linuxkpi_debug_80211 & D80211_TRACE_TX_DUMP)5470hexdump(mtod(m, const void *), m->m_len, "RAW TX (plain) ", 0);5471#endif54725473ni = lsta->ni;5474k = NULL;5475keyix = IEEE80211_KEYIX_NONE;5476wh = mtod(m, struct ieee80211_frame *);5477if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {54785479#ifdef LKPI_80211_HW_CRYPTO5480if (lkpi_hwcrypto) {5481k = ieee80211_crypto_get_txkey(ni, m);5482if (k != NULL && lsta->kc[k->wk_keyix] != NULL)5483keyix = k->wk_keyix;5484}5485#endif54865487/* Encrypt the frame if need be. */5488if (keyix == IEEE80211_KEYIX_NONE) {5489/* Retrieve key for TX && do software encryption. */5490k = ieee80211_crypto_encap(ni, m);5491if (k == NULL) {5492ieee80211_free_node(ni);5493m_freem(m);5494return;5495}5496}5497}54985499ic = ni->ni_ic;5500lhw = ic->ic_softc;5501hw = LHW_TO_HW(lhw);5502c = ni->ni_chan;55035504if (ieee80211_radiotap_active_vap(ni->ni_vap)) {5505struct lkpi_radiotap_tx_hdr *rtap;55065507rtap = &lhw->rtap_tx;5508rtap->wt_flags = 0;5509if (k != NULL)5510rtap->wt_flags |= IEEE80211_RADIOTAP_F_WEP;5511if (m->m_flags & M_FRAG)5512rtap->wt_flags |= IEEE80211_RADIOTAP_F_FRAG;5513IMPROVE();5514rtap->wt_rate = 0;5515if (c != NULL && c != IEEE80211_CHAN_ANYC) {5516rtap->wt_chan_freq = htole16(c->ic_freq);5517rtap->wt_chan_flags = htole16(c->ic_flags);5518}55195520ieee80211_radiotap_tx(ni->ni_vap, m);5521}55225523#ifdef LKPI_80211_HW_CRYPTO5524if (lkpi_hwcrypto && keyix != IEEE80211_KEYIX_NONE)5525tailroom = lkpi_hw_crypto_tailroom(lsta, k);5526else5527#endif5528tailroom = 0;55295530/*5531* net80211 should handle hw->extra_tx_headroom.5532* Though for as long as we are copying we don't mind.5533* XXX-BZ rtw88 asks for too much headroom for ipv6+tcp:5534* https://lists.freebsd.org/archives/freebsd-transport/2022-February/000012.html5535*/5536skb = dev_alloc_skb(hw->extra_tx_headroom + tailroom + m->m_pkthdr.len);5537if (skb == NULL) {5538static uint8_t skb_alloc_failures = 0;55395540if (skb_alloc_failures++ == 0) {5541int tid;55425543sta = LSTA_TO_STA(lsta);5544ic_printf(ic, "ERROR %s: skb alloc failed %d + %d, lsta %p sta %p ni %p\n",5545__func__, hw->extra_tx_headroom, m->m_pkthdr.len, lsta, sta, ni);5546for (tid = 0; tid < nitems(sta->txq); tid++) {5547if (sta->txq[tid] == NULL)5548continue;5549ltxq = TXQ_TO_LTXQ(sta->txq[tid]);5550ic_printf(ic, " tid %d ltxq %p seen_dequeue %d stopped %d skb_queue_len %u\n",5551tid, ltxq, ltxq->seen_dequeue, ltxq->stopped, skb_queue_len(<xq->skbq));5552}5553}5554ieee80211_free_node(ni);5555m_freem(m);5556return;5557}5558skb_reserve(skb, hw->extra_tx_headroom);55595560/* XXX-BZ we need a SKB version understanding mbuf. */5561/* Save the mbuf for ieee80211_tx_complete(). */5562skb->m_free_func = lkpi_ieee80211_free_skb_mbuf;5563skb->m = m;5564#if 05565skb_put_data(skb, m->m_data, m->m_pkthdr.len);5566#else5567buf = skb_put(skb, m->m_pkthdr.len);5568m_copydata(m, 0, m->m_pkthdr.len, buf);5569#endif5570/* Save the ni. */5571m->m_pkthdr.PH_loc.ptr = ni;55725573lvif = VAP_TO_LVIF(ni->ni_vap);5574vif = LVIF_TO_VIF(lvif);55755576hdr = (void *)skb->data;5577tid = linuxkpi_ieee80211_get_tid(hdr, true);5578if (tid == IEEE80211_NONQOS_TID) { /* == IEEE80211_NUM_TIDS */5579if (!ieee80211_is_data(hdr->frame_control)) {5580/* MGMT and CTRL frames go on TID 7/VO. */5581skb->priority = 7;5582ac = IEEE80211_AC_VO;5583} else {5584/* Other non-QOS traffic goes to BE. */5585/* Contrary to net80211 we MUST NOT promote M_EAPOL. */5586skb->priority = 0;5587ac = IEEE80211_AC_BE;5588}5589} else {5590skb->priority = tid & IEEE80211_QOS_CTL_TID_MASK;5591ac = ieee80211e_up_to_ac[tid & 7];5592}5593skb_set_queue_mapping(skb, ac);55945595info = IEEE80211_SKB_CB(skb);5596info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;5597/* Slight delay; probably only happens on scanning so fine? */5598if (c == NULL || c == IEEE80211_CHAN_ANYC)5599c = ic->ic_curchan;5600info->band = lkpi_net80211_chan_to_nl80211_band(c);5601info->hw_queue = vif->hw_queue[ac];5602if (m->m_flags & M_EAPOL)5603info->control.flags |= IEEE80211_TX_CTRL_PORT_CTRL_PROTO;5604info->control.vif = vif;5605/* XXX-BZ info->control.rates */5606#ifdef __notyet__5607#ifdef LKPI_80211_HT5608info->control.rts_cts_rate_idx=5609info->control.use_rts= /* RTS */5610info->control.use_cts_prot= /* RTS/CTS*/5611#endif5612#endif56135614sta = LSTA_TO_STA(lsta);5615#ifdef LKPI_80211_HW_CRYPTO5616if (lkpi_hwcrypto && keyix != IEEE80211_KEYIX_NONE) {5617int error;56185619error = lkpi_hw_crypto_prepare(lsta, k, skb);5620if (error != 0) {5621/*5622* We only have to free the skb which will free the5623* mbuf and release the reference on the ni.5624*/5625dev_kfree_skb(skb);5626return;5627}5628}5629#endif56305631IMPROVE();56325633ltxq = NULL;5634if (!ieee80211_is_data_present(hdr->frame_control)) {5635if (vif->type == NL80211_IFTYPE_STATION &&5636lsta->added_to_drv &&5637sta->txq[IEEE80211_NUM_TIDS] != NULL)5638ltxq = TXQ_TO_LTXQ(sta->txq[IEEE80211_NUM_TIDS]);5639} else if (lsta->added_to_drv &&5640sta->txq[skb->priority] != NULL) {5641ltxq = TXQ_TO_LTXQ(sta->txq[skb->priority]);5642}5643if (ltxq == NULL)5644goto ops_tx;56455646KASSERT(ltxq != NULL, ("%s: lsta %p sta %p m %p skb %p "5647"ltxq %p != NULL\n", __func__, lsta, sta, m, skb, ltxq));56485649LKPI_80211_LTXQ_LOCK(ltxq);5650skb_queue_tail(<xq->skbq, skb);5651#ifdef LINUXKPI_DEBUG_802115652if (linuxkpi_debug_80211 & D80211_TRACE_TX)5653printf("%s:%d mo_wake_tx_queue :: %d %lu lsta %p sta %p "5654"ni %p %6D skb %p lxtq %p { qlen %u, ac %d tid %u } "5655"WAKE_TX_Q ac %d prio %u qmap %u\n",5656__func__, __LINE__,5657curthread->td_tid, jiffies,5658lsta, sta, ni, ni->ni_macaddr, ":", skb, ltxq,5659skb_queue_len(<xq->skbq), ltxq->txq.ac,5660ltxq->txq.tid, ac, skb->priority, skb->qmap);5661#endif5662LKPI_80211_LTXQ_UNLOCK(ltxq);5663wiphy_lock(hw->wiphy);5664lkpi_80211_mo_wake_tx_queue(hw, <xq->txq);5665wiphy_unlock(hw->wiphy);5666return;56675668ops_tx:5669#ifdef LINUXKPI_DEBUG_802115670if (linuxkpi_debug_80211 & D80211_TRACE_TX)5671printf("%s:%d mo_tx :: lsta %p sta %p ni %p %6D skb %p "5672"TX ac %d prio %u qmap %u\n",5673__func__, __LINE__, lsta, sta, ni, ni->ni_macaddr, ":",5674skb, ac, skb->priority, skb->qmap);5675#endif5676memset(&control, 0, sizeof(control));5677control.sta = sta;5678wiphy_lock(hw->wiphy);5679lkpi_80211_mo_tx(hw, &control, skb);5680wiphy_unlock(hw->wiphy);5681}56825683static void5684lkpi_80211_txq_task(void *ctx, int pending)5685{5686struct lkpi_sta *lsta;5687struct mbufq mq;5688struct mbuf *m;5689bool shall_tx;56905691lsta = ctx;56925693#ifdef LINUXKPI_DEBUG_802115694if (linuxkpi_debug_80211 & D80211_TRACE_TX)5695printf("%s:%d lsta %p ni %p %6D pending %d mbuf_qlen %d\n",5696__func__, __LINE__, lsta, lsta->ni, lsta->ni->ni_macaddr, ":",5697pending, mbufq_len(&lsta->txq));5698#endif56995700mbufq_init(&mq, IFQ_MAXLEN);57015702LKPI_80211_LSTA_TXQ_LOCK(lsta);5703/*5704* Do not re-check lsta->txq_ready here; we may have a pending5705* disassoc/deauth frame still. On the contrary if txq_ready is5706* false we do not have a valid sta anymore in the firmware so no5707* point to try to TX.5708* We also use txq_ready as a semaphore and will drain the txq manually5709* if needed on our way towards SCAN/INIT in the state machine.5710*/5711#if 05712shall_tx = lsta->added_to_drv && lsta->txq_ready;5713#else5714/*5715* Backout this part of 886653492945f which breaks rtw88 or5716* in general drivers without (*sta_state)() but only the5717* legacy fallback to (*sta_add)().5718*/5719shall_tx = lsta->txq_ready;5720#endif5721if (__predict_true(shall_tx))5722mbufq_concat(&mq, &lsta->txq);5723/*5724* else a state change will push the packets out manually or5725* lkpi_lsta_free() will drain the lsta->txq and free the mbufs.5726*/5727LKPI_80211_LSTA_TXQ_UNLOCK(lsta);57285729m = mbufq_dequeue(&mq);5730while (m != NULL) {5731lkpi_80211_txq_tx_one(lsta, m);5732m = mbufq_dequeue(&mq);5733}5734}57355736static int5737lkpi_ic_transmit(struct ieee80211com *ic, struct mbuf *m)5738{57395740/* XXX TODO */5741IMPROVE();57425743/* Quick and dirty cheating hack. */5744struct ieee80211_node *ni;57455746ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;5747return (lkpi_xmit(ni, m, NULL, false));5748}57495750#ifdef LKPI_80211_HT5751static int5752lkpi_ic_recv_action(struct ieee80211_node *ni, const struct ieee80211_frame *wh,5753const uint8_t *frm, const uint8_t *efrm)5754{5755struct ieee80211com *ic;5756struct lkpi_hw *lhw;57575758ic = ni->ni_ic;5759lhw = ic->ic_softc;57605761IMPROVE_HT("recv_action called; nothing to do in lkpi; make debugging");57625763return (lhw->ic_recv_action(ni, wh, frm, efrm));5764}57655766static int5767lkpi_ic_send_action(struct ieee80211_node *ni, int category, int action, void *sa)5768{5769struct ieee80211com *ic;5770struct lkpi_hw *lhw;57715772ic = ni->ni_ic;5773lhw = ic->ic_softc;57745775IMPROVE_HT("send_action called; nothing to do in lkpi; make debugging");57765777return (lhw->ic_send_action(ni, category, action, sa));5778}577957805781static int5782lkpi_ic_ampdu_enable(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)5783{5784struct ieee80211com *ic;5785struct lkpi_hw *lhw;57865787ic = ni->ni_ic;5788lhw = ic->ic_softc;57895790IMPROVE_HT("ieee80211_ampdu_enable called; nothing to do in lkpi for now; make debugging");57915792return (lhw->ic_ampdu_enable(ni, tap));5793}57945795/*5796* (*ic_addba_request)() is called by ieee80211_ampdu_request() before5797* calling send_action(CAT_BA, BA_ADDBA_REQUEST).5798*5799* NB: returns 0 on ERROR!5800*/5801static int5802lkpi_ic_addba_request(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap,5803int dialogtoken, int baparamset, int batimeout)5804{5805struct ieee80211com *ic;5806struct lkpi_hw *lhw;5807struct ieee80211_hw *hw;5808struct ieee80211vap *vap;5809struct lkpi_vif *lvif;5810struct ieee80211_vif *vif;5811struct lkpi_sta *lsta;5812struct ieee80211_sta *sta;5813struct ieee80211_ampdu_params params = { };5814int error;58155816ic = ni->ni_ic;5817lhw = ic->ic_softc;5818hw = LHW_TO_HW(lhw);5819vap = ni->ni_vap;5820lvif = VAP_TO_LVIF(vap);5821vif = LVIF_TO_VIF(lvif);5822lsta = ni->ni_drv_data;5823sta = LSTA_TO_STA(lsta);58245825if (!lsta->added_to_drv) {5826ic_printf(ic, "%s: lsta %p ni %p, sta %p not added to firmware\n",5827__func__, lsta, ni, sta);5828return (0);5829}58305831params.sta = sta;5832params.action = IEEE80211_AMPDU_TX_START;5833/* Keep 0 here! */5834params.buf_size = 0;5835params.timeout = 0;5836params.ssn = tap->txa_start & (IEEE80211_SEQ_RANGE-1);5837params.tid = tap->txa_tid;5838params.amsdu = false;58395840IEEE80211_UNLOCK(ic);5841wiphy_lock(hw->wiphy);5842error = lkpi_80211_mo_ampdu_action(hw, vif, ¶ms);5843wiphy_unlock(hw->wiphy);5844IEEE80211_LOCK(ic);5845if (error != 0) {5846ic_printf(ic, "%s: mo_ampdu_action returned %d. ni %p tap %p\n",5847__func__, error, ni, tap);5848return (0);5849}58505851return (lhw->ic_addba_request(ni, tap, dialogtoken, baparamset, batimeout));5852}58535854/*5855* (*ic_addba_response)() is called from ht_recv_action_ba_addba_response()5856* and calls the default ieee80211_addba_response() which always returns 1.5857*5858* NB: No error checking in net80211!5859* Staying with 0 is an error.5860*/5861static int5862lkpi_ic_addba_response(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap,5863int status, int baparamset, int batimeout)5864{5865struct ieee80211com *ic;5866struct lkpi_hw *lhw;5867struct ieee80211_hw *hw;5868struct ieee80211vap *vap;5869struct lkpi_vif *lvif;5870struct ieee80211_vif *vif;5871struct lkpi_sta *lsta;5872struct ieee80211_sta *sta;5873struct ieee80211_ampdu_params params = { };5874int error;58755876ic = ni->ni_ic;5877lhw = ic->ic_softc;5878hw = LHW_TO_HW(lhw);5879vap = ni->ni_vap;5880lvif = VAP_TO_LVIF(vap);5881vif = LVIF_TO_VIF(lvif);5882lsta = ni->ni_drv_data;5883sta = LSTA_TO_STA(lsta);58845885if (!lsta->added_to_drv) {5886ic_printf(ic, "%s: lsta %p ni %p, sta %p not added to firmware\n",5887__func__, lsta, ni, sta);5888return (0);5889}58905891if (status == IEEE80211_STATUS_SUCCESS) {5892params.sta = sta;5893params.action = IEEE80211_AMPDU_TX_OPERATIONAL;5894params.buf_size = tap->txa_wnd;5895params.timeout = 0;5896params.ssn = 0;5897params.tid = tap->txa_tid;5898if ((tap->txa_flags & IEEE80211_AGGR_AMSDU) != 0)5899params.amsdu = true;5900else5901params.amsdu = false;5902} else {5903/* We need to free the allocated resources. */5904params.sta = sta;5905switch (status) {5906/* params.action = FLUSH, FLUSH_CONT */5907default:5908params.action = IEEE80211_AMPDU_TX_STOP_CONT;5909break;5910}5911params.buf_size = 0;5912params.timeout = 0;5913params.ssn = 0;5914params.tid = tap->txa_tid;5915params.amsdu = false;5916}59175918IEEE80211_UNLOCK(ic);5919wiphy_lock(hw->wiphy);5920error = lkpi_80211_mo_ampdu_action(hw, vif, ¶ms);5921wiphy_unlock(hw->wiphy);5922IEEE80211_LOCK(ic);5923if (error != 0) {5924ic_printf(ic, "%s: mo_ampdu_action returned %d. ni %p tap %p\n",5925__func__, error, ni, tap);5926return (0);5927}59285929IMPROVE_HT("who unleashes the TXQ? and when?, do we need to ni->ni_txseqs[tid] = tap->txa_start & 0xfff;");59305931return (lhw->ic_addba_response(ni, tap, status, baparamset, batimeout));5932}59335934/*5935* (*ic_addba_stop)() is called from ampdu_tx_stop(), ht_recv_action_ba_delba(),5936* and ieee80211_ampdu_stop() and calls the default ieee80211_addba_stop().5937*/5938static void5939lkpi_ic_addba_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)5940{5941struct ieee80211com *ic;5942struct lkpi_hw *lhw;5943struct ieee80211_hw *hw;5944struct ieee80211vap *vap;5945struct lkpi_vif *lvif;5946struct ieee80211_vif *vif;5947struct lkpi_sta *lsta;5948struct ieee80211_sta *sta;5949struct ieee80211_ampdu_params params = { };5950int error;59515952ic = ni->ni_ic;5953lhw = ic->ic_softc;5954hw = LHW_TO_HW(lhw);5955vap = ni->ni_vap;5956lvif = VAP_TO_LVIF(vap);5957vif = LVIF_TO_VIF(lvif);5958lsta = ni->ni_drv_data;5959sta = LSTA_TO_STA(lsta);59605961if (!lsta->added_to_drv) {5962ic_printf(ic, "%s: lsta %p ni %p, sta %p not added to firmware\n",5963__func__, lsta, ni, sta);5964goto n80211;5965}59665967/* We need to free the allocated resources. */5968params.sta = sta;5969IMPROVE("net80211 does not provide a reason to us");5970params.action = IEEE80211_AMPDU_TX_STOP_CONT; /* params.action = FLUSH, FLUSH_CONT */5971params.buf_size = 0;5972params.timeout = 0;5973params.ssn = 0;5974params.tid = tap->txa_tid;5975params.amsdu = false;59765977IEEE80211_UNLOCK(ic);5978wiphy_lock(hw->wiphy);5979error = lkpi_80211_mo_ampdu_action(hw, vif, ¶ms);5980wiphy_unlock(hw->wiphy);5981IEEE80211_LOCK(ic);5982if (error != 0) {5983ic_printf(ic, "%s: mo_ampdu_action returned %d. ni %p tap %p\n",5984__func__, error, ni, tap);5985goto n80211;5986}59875988IMPROVE_HT("anyting else?");59895990n80211:5991lhw->ic_addba_stop(ni, tap);5992}59935994static void5995lkpi_ic_addba_response_timeout(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)5996{5997struct ieee80211com *ic;5998struct lkpi_hw *lhw;59996000ic = ni->ni_ic;6001lhw = ic->ic_softc;60026003IMPROVE_HT();60046005lhw->ic_addba_response_timeout(ni, tap);6006}60076008static void6009lkpi_ic_bar_response(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap,6010int status)6011{6012struct ieee80211com *ic;6013struct lkpi_hw *lhw;60146015ic = ni->ni_ic;6016lhw = ic->ic_softc;60176018IMPROVE_HT();60196020lhw->ic_bar_response(ni, tap, status);6021}60226023static int6024lkpi_ic_ampdu_rx_start(struct ieee80211_node *ni, struct ieee80211_rx_ampdu *rap,6025int baparamset, int batimeout, int baseqctl)6026{6027struct ieee80211com *ic;6028struct lkpi_hw *lhw;6029struct ieee80211_hw *hw;6030struct ieee80211vap *vap;6031struct lkpi_vif *lvif;6032struct ieee80211_vif *vif;6033struct lkpi_sta *lsta;6034struct ieee80211_sta *sta;6035struct ieee80211_ampdu_params params = { };6036int error;60376038ic = ni->ni_ic;6039lhw = ic->ic_softc;6040hw = LHW_TO_HW(lhw);6041vap = ni->ni_vap;6042lvif = VAP_TO_LVIF(vap);6043vif = LVIF_TO_VIF(lvif);6044lsta = ni->ni_drv_data;6045sta = LSTA_TO_STA(lsta);60466047IEEE80211_UNLOCK_ASSERT(ic);60486049if (!lsta->added_to_drv) {6050ic_printf(ic, "%s: lsta %p ni %p vap %p, sta %p not added to firmware\n",6051__func__, lsta, ni, vap, sta);6052return (-ENXIO);6053}60546055if (lsta->state != IEEE80211_STA_AUTHORIZED) {6056ic_printf(ic, "%s: lsta %p ni %p vap %p, sta %p state %d not AUTHORIZED\n",6057__func__, lsta, ni, vap, sta, lsta->state);6058return (-ENXIO);6059}60606061params.sta = sta;6062params.action = IEEE80211_AMPDU_RX_START;6063params.buf_size = _IEEE80211_MASKSHIFT(le16toh(baparamset), IEEE80211_BAPS_BUFSIZ);6064if (params.buf_size == 0)6065params.buf_size = IEEE80211_MAX_AMPDU_BUF_HT;6066else6067params.buf_size = min(params.buf_size, IEEE80211_MAX_AMPDU_BUF_HT);6068if (hw->max_rx_aggregation_subframes > 0 &&6069params.buf_size > hw->max_rx_aggregation_subframes)6070params.buf_size = hw->max_rx_aggregation_subframes;6071params.timeout = le16toh(batimeout);6072params.ssn = _IEEE80211_MASKSHIFT(le16toh(baseqctl), IEEE80211_BASEQ_START);6073params.tid = _IEEE80211_MASKSHIFT(le16toh(baparamset), IEEE80211_BAPS_TID);60746075/* Based on net80211::ampdu_rx_start(). */6076if ((vap->iv_htcaps & IEEE80211_HTC_RX_AMSDU_AMPDU) &&6077(_IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_AMSDU)))6078params.amsdu = true;6079else6080params.amsdu = false;60816082wiphy_lock(hw->wiphy);6083error = lkpi_80211_mo_ampdu_action(hw, vif, ¶ms);6084wiphy_unlock(hw->wiphy);6085if (error != 0) {6086ic_printf(ic, "%s: mo_ampdu_action returned %d. ni %p rap %p\n",6087__func__, error, ni, rap);6088return (error);6089}60906091if (!ieee80211_hw_check(hw, SUPPORTS_REORDERING_BUFFER)) {6092IMPROVE("%s: TODO: SUPPORTS_REORDERING_BUFFER not set; check net80211\n", __func__);6093}60946095IMPROVE_HT("net80211 is missing the error check on return and assumes success");60966097error = lhw->ic_ampdu_rx_start(ni, rap, baparamset, batimeout, baseqctl);6098return (error);6099}61006101static void6102lkpi_ic_ampdu_rx_stop(struct ieee80211_node *ni, struct ieee80211_rx_ampdu *rap)6103{6104struct ieee80211com *ic;6105struct lkpi_hw *lhw;6106struct ieee80211_hw *hw;6107struct ieee80211vap *vap;6108struct lkpi_vif *lvif;6109struct ieee80211_vif *vif;6110struct lkpi_sta *lsta;6111struct ieee80211_sta *sta;6112struct ieee80211_ampdu_params params = { };6113int error;6114uint8_t tid;6115bool ic_locked;61166117ic = ni->ni_ic;6118lhw = ic->ic_softc;61196120/*6121* We should not (cannot) call into mac80211 ops with AMPDU_RX_STOP if6122* we did not START. Some drivers pass it down to firmware which will6123* simply barf and net80211 calls ieee80211_ht_node_cleanup() from6124* ieee80211_ht_node_init() amongst others which will iterate over all6125* tid and call ic_ampdu_rx_stop() unconditionally.6126* XXX net80211 should probably be more "gentle" in these cases and6127* track some state itself.6128*/6129if ((rap->rxa_flags & IEEE80211_AGGR_RUNNING) == 0)6130goto net80211_only;61316132hw = LHW_TO_HW(lhw);6133vap = ni->ni_vap;6134lvif = VAP_TO_LVIF(vap);6135vif = LVIF_TO_VIF(lvif);6136lsta = ni->ni_drv_data;6137if (lsta == NULL) {6138ic_printf(ic, "%s: lsta %p ni %p vap %p, lsta is NULL\n",6139__func__, lsta, ni, vap);6140goto net80211_only;6141}6142sta = LSTA_TO_STA(lsta);61436144if (!lsta->added_to_drv) {6145ic_printf(ic, "%s: lsta %p ni %p vap %p, sta %p not added to firmware\n",6146__func__, lsta, ni, vap, sta);6147goto net80211_only;6148}61496150if (lsta->state != IEEE80211_STA_AUTHORIZED) {6151ic_printf(ic, "%s: lsta %p ni %p vap %p, sta %p state %d not AUTHORIZED\n",6152__func__, lsta, ni, vap, sta, lsta->state);6153goto net80211_only;6154}61556156IMPROVE_HT("This really should be passed from ht_recv_action_ba_delba.");6157for (tid = 0; tid < WME_NUM_TID; tid++) {6158if (&ni->ni_rx_ampdu[tid] == rap)6159break;6160}6161if (tid == WME_NUM_TID) {6162ic_printf(ic, "%s: lsta %p ni %p vap %p, sta %p TID not found\n",6163__func__, lsta, ni, vap, sta);6164goto net80211_only;6165}61666167params.sta = sta;6168params.action = IEEE80211_AMPDU_RX_STOP;6169params.buf_size = 0;6170params.timeout = 0;6171params.ssn = 0;6172params.tid = tid;6173params.amsdu = false;61746175ic_locked = IEEE80211_IS_LOCKED(ic);6176if (ic_locked)6177IEEE80211_UNLOCK(ic);6178wiphy_lock(hw->wiphy);6179error = lkpi_80211_mo_ampdu_action(hw, vif, ¶ms);6180wiphy_unlock(hw->wiphy);6181if (ic_locked)6182IEEE80211_LOCK(ic);6183if (error != 0)6184ic_printf(ic, "%s: mo_ampdu_action returned %d. ni %p rap %p\n",6185__func__, error, ni, rap);61866187net80211_only:6188lhw->ic_ampdu_rx_stop(ni, rap);6189}6190#endif61916192static void6193lkpi_ic_getradiocaps_ht(struct ieee80211com *ic, struct ieee80211_hw *hw,6194uint8_t *bands, int *chan_flags, enum nl80211_band band)6195{6196#ifdef LKPI_80211_HT6197struct ieee80211_sta_ht_cap *ht_cap;61986199ht_cap = &hw->wiphy->bands[band]->ht_cap;6200if (!ht_cap->ht_supported)6201return;62026203switch (band) {6204case NL80211_BAND_2GHZ:6205setbit(bands, IEEE80211_MODE_11NG);6206break;6207case NL80211_BAND_5GHZ:6208setbit(bands, IEEE80211_MODE_11NA);6209break;6210default:6211IMPROVE("Unsupported band %d", band);6212return;6213}62146215ic->ic_htcaps = IEEE80211_HTC_HT; /* HT operation */62166217/*6218* Rather than manually checking each flag and6219* translating IEEE80211_HT_CAP_ to IEEE80211_HTCAP_,6220* simply copy the 16bits.6221*/6222ic->ic_htcaps |= ht_cap->cap;62236224/* Then deal with the other flags. */6225if (ieee80211_hw_check(hw, AMPDU_AGGREGATION))6226ic->ic_htcaps |= IEEE80211_HTC_AMPDU;6227#ifdef __notyet__6228if (ieee80211_hw_check(hw, TX_AMSDU))6229ic->ic_htcaps |= IEEE80211_HTC_AMSDU;6230if (ieee80211_hw_check(hw, SUPPORTS_AMSDU_IN_AMPDU))6231ic->ic_htcaps |= (IEEE80211_HTC_RX_AMSDU_AMPDU |6232IEEE80211_HTC_TX_AMSDU_AMPDU);6233#endif62346235IMPROVE("PS, ampdu_*, ht_cap.mcs.tx_params, ...");6236ic->ic_htcaps |= IEEE80211_HTCAP_SMPS_OFF;62376238/* Only add HT40 channels if supported. */6239if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) != 0 &&6240chan_flags != NULL)6241*chan_flags |= NET80211_CBW_FLAG_HT40;6242#endif6243}62446245static void6246lkpi_ic_getradiocaps(struct ieee80211com *ic, int maxchan,6247int *n, struct ieee80211_channel *c)6248{6249struct lkpi_hw *lhw;6250struct ieee80211_hw *hw;6251struct linuxkpi_ieee80211_channel *channels;6252uint8_t bands[IEEE80211_MODE_BYTES];6253int chan_flags, error, i, nchans;62546255/* Channels */6256lhw = ic->ic_softc;6257hw = LHW_TO_HW(lhw);62586259/* NL80211_BAND_2GHZ */6260nchans = 0;6261if (hw->wiphy->bands[NL80211_BAND_2GHZ] != NULL)6262nchans = hw->wiphy->bands[NL80211_BAND_2GHZ]->n_channels;6263if (nchans > 0) {6264memset(bands, 0, sizeof(bands));6265chan_flags = 0;6266setbit(bands, IEEE80211_MODE_11B);6267/* XXX-BZ unclear how to check for 11g. */62686269IMPROVE("the bitrates may have flags?");6270setbit(bands, IEEE80211_MODE_11G);62716272lkpi_ic_getradiocaps_ht(ic, hw, bands, &chan_flags,6273NL80211_BAND_2GHZ);62746275channels = hw->wiphy->bands[NL80211_BAND_2GHZ]->channels;6276for (i = 0; i < nchans && *n < maxchan; i++) {6277uint32_t nflags = 0;6278int cflags = chan_flags;62796280if (channels[i].flags & IEEE80211_CHAN_DISABLED) {6281ic_printf(ic, "%s: Skipping disabled chan "6282"[%u/%u/%#x]\n", __func__,6283channels[i].hw_value,6284channels[i].center_freq, channels[i].flags);6285continue;6286}6287if (channels[i].flags & IEEE80211_CHAN_NO_IR)6288nflags |= (IEEE80211_CHAN_NOADHOC|IEEE80211_CHAN_PASSIVE);6289if (channels[i].flags & IEEE80211_CHAN_RADAR)6290nflags |= IEEE80211_CHAN_DFS;6291if (channels[i].flags & IEEE80211_CHAN_NO_160MHZ)6292cflags &= ~(NET80211_CBW_FLAG_VHT160|NET80211_CBW_FLAG_VHT80P80);6293if (channels[i].flags & IEEE80211_CHAN_NO_80MHZ)6294cflags &= ~NET80211_CBW_FLAG_VHT80;6295/* XXX how to map the remaining enum ieee80211_channel_flags? */6296if (channels[i].flags & IEEE80211_CHAN_NO_HT40)6297cflags &= ~NET80211_CBW_FLAG_HT40;62986299error = ieee80211_add_channel_cbw(c, maxchan, n,6300ieee80211_mhz2ieee(channels[i].center_freq,6301lkpi_nl80211_band_to_net80211_band(channels[i].band)),6302channels[i].center_freq, channels[i].max_power,6303nflags, bands, cflags);6304/* net80211::ENOBUFS: *n >= maxchans */6305if (error != 0 && error != ENOBUFS)6306ic_printf(ic, "%s: Adding chan %u/%u/%#x/%#x/%#x/%#x "6307"returned error %d\n",6308__func__, channels[i].hw_value,6309channels[i].center_freq, channels[i].flags,6310nflags, chan_flags, cflags, error);6311if (error != 0)6312break;6313}6314}63156316/* NL80211_BAND_5GHZ */6317nchans = 0;6318if (hw->wiphy->bands[NL80211_BAND_5GHZ] != NULL)6319nchans = hw->wiphy->bands[NL80211_BAND_5GHZ]->n_channels;6320if (nchans > 0) {6321memset(bands, 0, sizeof(bands));6322chan_flags = 0;6323setbit(bands, IEEE80211_MODE_11A);63246325lkpi_ic_getradiocaps_ht(ic, hw, bands, &chan_flags,6326NL80211_BAND_5GHZ);63276328#ifdef LKPI_80211_VHT6329if (hw->wiphy->bands[NL80211_BAND_5GHZ]->vht_cap.vht_supported) {63306331ic->ic_flags_ext |= IEEE80211_FEXT_VHT;6332ic->ic_vht_cap.vht_cap_info =6333hw->wiphy->bands[NL80211_BAND_5GHZ]->vht_cap.cap;6334ic->ic_vht_cap.supp_mcs =6335hw->wiphy->bands[NL80211_BAND_5GHZ]->vht_cap.vht_mcs;63366337setbit(bands, IEEE80211_MODE_VHT_5GHZ);6338chan_flags |= NET80211_CBW_FLAG_VHT80;6339if (IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_IS_160MHZ(6340ic->ic_vht_cap.vht_cap_info))6341chan_flags |= NET80211_CBW_FLAG_VHT160;6342if (IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_IS_160_80P80MHZ(6343ic->ic_vht_cap.vht_cap_info))6344chan_flags |= NET80211_CBW_FLAG_VHT80P80;6345}6346#endif63476348channels = hw->wiphy->bands[NL80211_BAND_5GHZ]->channels;6349for (i = 0; i < nchans && *n < maxchan; i++) {6350uint32_t nflags = 0;6351int cflags = chan_flags;63526353if (channels[i].flags & IEEE80211_CHAN_DISABLED) {6354ic_printf(ic, "%s: Skipping disabled chan "6355"[%u/%u/%#x]\n", __func__,6356channels[i].hw_value,6357channels[i].center_freq, channels[i].flags);6358continue;6359}6360if (channels[i].flags & IEEE80211_CHAN_NO_IR)6361nflags |= (IEEE80211_CHAN_NOADHOC|IEEE80211_CHAN_PASSIVE);6362if (channels[i].flags & IEEE80211_CHAN_RADAR)6363nflags |= IEEE80211_CHAN_DFS;6364if (channels[i].flags & IEEE80211_CHAN_NO_160MHZ)6365cflags &= ~(NET80211_CBW_FLAG_VHT160|NET80211_CBW_FLAG_VHT80P80);6366if (channels[i].flags & IEEE80211_CHAN_NO_80MHZ)6367cflags &= ~NET80211_CBW_FLAG_VHT80;6368/* XXX hwo to map the remaining enum ieee80211_channel_flags? */6369if (channels[i].flags & IEEE80211_CHAN_NO_HT40)6370cflags &= ~NET80211_CBW_FLAG_HT40;63716372error = ieee80211_add_channel_cbw(c, maxchan, n,6373ieee80211_mhz2ieee(channels[i].center_freq,6374lkpi_nl80211_band_to_net80211_band(channels[i].band)),6375channels[i].center_freq, channels[i].max_power,6376nflags, bands, cflags);6377/* net80211::ENOBUFS: *n >= maxchans */6378if (error != 0 && error != ENOBUFS)6379ic_printf(ic, "%s: Adding chan %u/%u/%#x/%#x/%#x/%#x "6380"returned error %d\n",6381__func__, channels[i].hw_value,6382channels[i].center_freq, channels[i].flags,6383nflags, chan_flags, cflags, error);6384if (error != 0)6385break;6386}6387}6388}63896390static void *6391lkpi_ieee80211_ifalloc(void)6392{6393struct ieee80211com *ic;63946395ic = malloc(sizeof(*ic), M_LKPI80211, M_WAITOK | M_ZERO);63966397/* Setting these happens later when we have device information. */6398ic->ic_softc = NULL;6399ic->ic_name = "linuxkpi";64006401return (ic);6402}64036404struct ieee80211_hw *6405linuxkpi_ieee80211_alloc_hw(size_t priv_len, const struct ieee80211_ops *ops)6406{6407struct ieee80211_hw *hw;6408struct lkpi_hw *lhw;6409struct wiphy *wiphy;6410int ac;64116412/* Get us and the driver data also allocated. */6413wiphy = wiphy_new(&linuxkpi_mac80211cfgops, sizeof(*lhw) + priv_len);6414if (wiphy == NULL)6415return (NULL);64166417lhw = wiphy_priv(wiphy);6418lhw->ops = ops;64196420LKPI_80211_LHW_SCAN_LOCK_INIT(lhw);6421LKPI_80211_LHW_TXQ_LOCK_INIT(lhw);6422spin_lock_init(&lhw->txq_lock);6423sx_init_flags(&lhw->lvif_sx, "lhw-lvif", SX_RECURSE | SX_DUPOK);6424LKPI_80211_LHW_MC_LOCK_INIT(lhw);6425TAILQ_INIT(&lhw->lvif_head);6426__hw_addr_init(&lhw->mc_list);6427for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {6428lhw->txq_generation[ac] = 1;6429TAILQ_INIT(&lhw->scheduled_txqs[ac]);6430}64316432/* Chanctx_conf */6433INIT_LIST_HEAD(&lhw->lchanctx_list);64346435/* Deferred RX path. */6436LKPI_80211_LHW_RXQ_LOCK_INIT(lhw);6437TASK_INIT(&lhw->rxq_task, 0, lkpi_80211_lhw_rxq_task, lhw);6438mbufq_init(&lhw->rxq, 32 * NAPI_POLL_WEIGHT);6439lhw->rxq_stopped = false;64406441/*6442* XXX-BZ TODO make sure there is a "_null" function to all ops6443* not initialized.6444*/6445hw = LHW_TO_HW(lhw);6446hw->wiphy = wiphy;6447hw->conf.flags |= IEEE80211_CONF_IDLE;6448hw->priv = (void *)(lhw + 1);64496450/* BSD Specific. */6451lhw->ic = lkpi_ieee80211_ifalloc();64526453IMPROVE();64546455return (hw);6456}64576458void6459linuxkpi_ieee80211_iffree(struct ieee80211_hw *hw)6460{6461struct lkpi_hw *lhw;6462struct mbuf *m;64636464lhw = HW_TO_LHW(hw);6465free(lhw->ic, M_LKPI80211);6466lhw->ic = NULL;64676468/*6469* Drain the deferred RX path.6470*/6471LKPI_80211_LHW_RXQ_LOCK(lhw);6472lhw->rxq_stopped = true;6473LKPI_80211_LHW_RXQ_UNLOCK(lhw);64746475/* Drain taskq, won't be restarted due to rxq_stopped being set. */6476while (taskqueue_cancel(taskqueue_thread, &lhw->rxq_task, NULL) != 0)6477taskqueue_drain(taskqueue_thread, &lhw->rxq_task);64786479/* Flush mbufq (make sure to release ni refs!). */6480m = mbufq_dequeue(&lhw->rxq);6481while (m != NULL) {6482#ifdef LKPI_80211_USE_MTAG6483struct m_tag *mtag;64846485mtag = m_tag_locate(m, MTAG_ABI_LKPI80211, LKPI80211_TAG_RXNI, NULL);6486if (mtag != NULL) {6487struct lkpi_80211_tag_rxni *rxni;64886489rxni = (struct lkpi_80211_tag_rxni *)(mtag + 1);6490ieee80211_free_node(rxni->ni);6491}6492#else6493if (m->m_pkthdr.PH_loc.ptr != NULL) {6494struct ieee80211_node *ni;64956496ni = m->m_pkthdr.PH_loc.ptr;6497ieee80211_free_node(ni);6498}6499#endif6500m_freem(m);6501m = mbufq_dequeue(&lhw->rxq);6502}6503KASSERT(mbufq_empty(&lhw->rxq), ("%s: lhw %p has rxq len %d != 0\n",6504__func__, lhw, mbufq_len(&lhw->rxq)));6505LKPI_80211_LHW_RXQ_LOCK_DESTROY(lhw);65066507/* Chanctx_conf. */6508if (!list_empty_careful(&lhw->lchanctx_list)) {6509struct lkpi_chanctx *lchanctx, *next;6510struct ieee80211_chanctx_conf *chanctx_conf;65116512list_for_each_entry_safe(lchanctx, next, &lhw->lchanctx_list, entry) {6513if (lchanctx->added_to_drv) {6514/* In reality we should panic? */6515chanctx_conf = &lchanctx->chanctx_conf;6516lkpi_80211_mo_remove_chanctx(hw, chanctx_conf);6517}6518list_del(&lchanctx->entry);6519free(lchanctx, M_LKPI80211);6520}6521}65226523LKPI_80211_LHW_MC_LOCK(lhw);6524lkpi_cleanup_mcast_list_locked(lhw);6525LKPI_80211_LHW_MC_UNLOCK(lhw);65266527/* Cleanup more of lhw here or in wiphy_free()? */6528spin_lock_destroy(&lhw->txq_lock);6529LKPI_80211_LHW_TXQ_LOCK_DESTROY(lhw);6530LKPI_80211_LHW_SCAN_LOCK_DESTROY(lhw);6531sx_destroy(&lhw->lvif_sx);6532LKPI_80211_LHW_MC_LOCK_DESTROY(lhw)6533IMPROVE();6534}65356536void6537linuxkpi_set_ieee80211_dev(struct ieee80211_hw *hw)6538{6539struct lkpi_hw *lhw;6540struct ieee80211com *ic;6541struct device *dev;65426543lhw = HW_TO_LHW(hw);6544ic = lhw->ic;65456546/* Save the backpointer from net80211 to LinuxKPI. */6547ic->ic_softc = lhw;65486549/*6550* Set a proper name before ieee80211_ifattach() if dev is set.6551* ath1xk also unset the dev so we need to check.6552*/6553dev = wiphy_dev(hw->wiphy);6554if (dev != NULL) {6555ic->ic_name = dev_name(dev);6556} else {6557TODO("adjust arguments to still have the old dev or go through "6558"the hoops of getting the bsddev from hw and detach; "6559"or do in XXX; check ath1kx drivers");6560}65616562/* XXX-BZ do we also need to set wiphy name? */6563}65646565struct ieee80211_hw *6566linuxkpi_wiphy_to_ieee80211_hw(struct wiphy *wiphy)6567{6568struct lkpi_hw *lhw;65696570lhw = wiphy_priv(wiphy);6571return (LHW_TO_HW(lhw));6572}65736574static void6575lkpi_radiotap_attach(struct lkpi_hw *lhw)6576{6577struct ieee80211com *ic;65786579ic = lhw->ic;6580ieee80211_radiotap_attach(ic,6581&lhw->rtap_tx.wt_ihdr, sizeof(lhw->rtap_tx),6582LKPI_RTAP_TX_FLAGS_PRESENT,6583&lhw->rtap_rx.wr_ihdr, sizeof(lhw->rtap_rx),6584LKPI_RTAP_RX_FLAGS_PRESENT);6585}65866587int6588linuxkpi_ieee80211_ifattach(struct ieee80211_hw *hw)6589{6590struct ieee80211com *ic;6591struct lkpi_hw *lhw;6592int band, i;65936594lhw = HW_TO_LHW(hw);6595ic = lhw->ic;65966597/* We do it this late as wiphy->dev should be set for the name. */6598lhw->workq = alloc_ordered_workqueue(wiphy_name(hw->wiphy), 0);6599if (lhw->workq == NULL)6600return (-EAGAIN);66016602/* XXX-BZ figure this out how they count his... */6603if (!is_zero_ether_addr(hw->wiphy->perm_addr)) {6604IEEE80211_ADDR_COPY(ic->ic_macaddr,6605hw->wiphy->perm_addr);6606} else if (hw->wiphy->n_addresses > 0) {6607/* We take the first one. */6608IEEE80211_ADDR_COPY(ic->ic_macaddr,6609hw->wiphy->addresses[0].addr);6610} else {6611ic_printf(ic, "%s: warning, no hardware address!\n", __func__);6612}66136614#ifdef __not_yet__6615/* See comment in lkpi_80211_txq_tx_one(). */6616ic->ic_headroom = hw->extra_tx_headroom;6617#endif66186619ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */6620ic->ic_opmode = IEEE80211_M_STA;66216622/* Set device capabilities. */6623/* XXX-BZ we need to get these from linux80211/drivers and convert. */6624ic->ic_caps =6625IEEE80211_C_STA |6626IEEE80211_C_MONITOR |6627IEEE80211_C_WPA | /* WPA/RSN */6628#ifdef LKPI_80211_WME6629IEEE80211_C_WME |6630#endif6631#if 06632IEEE80211_C_PMGT |6633#endif6634IEEE80211_C_SHSLOT | /* short slot time supported */6635IEEE80211_C_SHPREAMBLE /* short preamble supported */6636;66376638#ifdef LKPI_80211_BGSCAN6639if (lhw->ops->hw_scan)6640ic->ic_caps |= IEEE80211_C_BGSCAN;6641#endif66426643lkpi_enable_hw_scan(lhw);66446645/* Does HW support Fragmentation offload? */6646if (ieee80211_hw_check(hw, SUPPORTS_TX_FRAG))6647ic->ic_flags_ext |= IEEE80211_FEXT_FRAG_OFFLOAD;66486649/* Does HW support full AMPDU[-TX] offload? */6650if (ieee80211_hw_check(hw, AMPDU_AGGREGATION))6651ic->ic_flags_ext |= IEEE80211_FEXT_AMPDU_OFFLOAD;6652#ifdef __notyet__6653if (ieee80211_hw_check(hw, TX_AMSDU))6654if (ieee80211_hw_check(hw, SUPPORTS_AMSDU_IN_AMPDU))6655#endif66566657/*6658* The wiphy variables report bitmasks of avail antennas.6659* (*get_antenna) get the current bitmask sets which can be6660* altered by (*set_antenna) for some drivers.6661* XXX-BZ will the count alone do us much good long-term in net80211?6662*/6663if (hw->wiphy->available_antennas_rx ||6664hw->wiphy->available_antennas_tx) {6665uint32_t rxs, txs;66666667if (lkpi_80211_mo_get_antenna(hw, &txs, &rxs) == 0) {6668ic->ic_rxstream = bitcount32(rxs);6669ic->ic_txstream = bitcount32(txs);6670}6671}66726673ic->ic_cryptocaps = 0;6674#ifdef LKPI_80211_HW_CRYPTO6675if (lkpi_hwcrypto && hw->wiphy->n_cipher_suites > 0) {6676uint32_t hwciphers;66776678hwciphers = 0;6679for (i = 0; i < hw->wiphy->n_cipher_suites; i++) {6680uint32_t cs;66816682cs = lkpi_l80211_to_net80211_cyphers(6683ic, hw->wiphy->cipher_suites[i]);6684if (cs == IEEE80211_CRYPTO_TKIP) {6685/*6686* We do set this here. We will only find out6687* when doing a SET_KEY operation depending on6688* what the driver returns.6689* net80211::ieee80211_crypto_newkey()6690* checks this so we will have to do flags6691* surgery later.6692*/6693cs |= IEEE80211_CRYPTO_TKIPMIC;6694}6695hwciphers |= cs;6696}6697/*6698* (20250415) nothing anywhere in the path checks we actually6699* support all these in net80211.6700* net80211 supports _256 variants but the ioctl does not.6701*/6702IMPROVE("as net80211 grows more support, enable them");6703hwciphers &= (IEEE80211_CRYPTO_WEP |6704IEEE80211_CRYPTO_TKIP | IEEE80211_CRYPTO_TKIPMIC |6705IEEE80211_CRYPTO_AES_CCM | IEEE80211_CRYPTO_AES_GCM_128);6706/*6707* We only support CCMP here, so further filter.6708* Also permit TKIP if turned on.6709*/6710hwciphers &= (IEEE80211_CRYPTO_AES_CCM |6711IEEE80211_CRYPTO_AES_GCM_128 |6712(lkpi_hwcrypto_tkip ? (IEEE80211_CRYPTO_TKIP |6713IEEE80211_CRYPTO_TKIPMIC) : 0));6714ieee80211_set_hardware_ciphers(ic, hwciphers);6715}6716#endif67176718lkpi_ic_getradiocaps(ic, IEEE80211_CHAN_MAX, &ic->ic_nchans,6719ic->ic_channels);67206721ieee80211_ifattach(ic);67226723ic->ic_update_mcast = lkpi_ic_update_mcast;6724ic->ic_update_promisc = lkpi_ic_update_promisc;6725ic->ic_update_chw = lkpi_ic_update_chw;6726ic->ic_parent = lkpi_ic_parent;6727ic->ic_scan_start = lkpi_ic_scan_start;6728ic->ic_scan_end = lkpi_ic_scan_end;6729ic->ic_set_channel = lkpi_ic_set_channel;6730ic->ic_transmit = lkpi_ic_transmit;6731ic->ic_raw_xmit = lkpi_ic_raw_xmit;6732ic->ic_vap_create = lkpi_ic_vap_create;6733ic->ic_vap_delete = lkpi_ic_vap_delete;6734ic->ic_getradiocaps = lkpi_ic_getradiocaps;6735ic->ic_wme.wme_update = lkpi_ic_wme_update;67366737lhw->ic_scan_curchan = ic->ic_scan_curchan;6738ic->ic_scan_curchan = lkpi_ic_scan_curchan;6739lhw->ic_scan_mindwell = ic->ic_scan_mindwell;6740ic->ic_scan_mindwell = lkpi_ic_scan_mindwell;67416742lhw->ic_node_alloc = ic->ic_node_alloc;6743ic->ic_node_alloc = lkpi_ic_node_alloc;6744lhw->ic_node_init = ic->ic_node_init;6745ic->ic_node_init = lkpi_ic_node_init;6746lhw->ic_node_cleanup = ic->ic_node_cleanup;6747ic->ic_node_cleanup = lkpi_ic_node_cleanup;6748lhw->ic_node_free = ic->ic_node_free;6749ic->ic_node_free = lkpi_ic_node_free;67506751#ifdef LKPI_80211_HT6752/*6753* Only attach if the driver/firmware supports (*ampdu_action)().6754* Otherwise it is in the hands of net80211.6755*/6756if (lhw->ops->ampdu_action != NULL) {6757lhw->ic_recv_action = ic->ic_recv_action;6758ic->ic_recv_action = lkpi_ic_recv_action;6759lhw->ic_send_action = ic->ic_send_action;6760ic->ic_send_action = lkpi_ic_send_action;67616762lhw->ic_ampdu_enable = ic->ic_ampdu_enable;6763ic->ic_ampdu_enable = lkpi_ic_ampdu_enable;67646765lhw->ic_addba_request = ic->ic_addba_request;6766ic->ic_addba_request = lkpi_ic_addba_request;6767lhw->ic_addba_response = ic->ic_addba_response;6768ic->ic_addba_response = lkpi_ic_addba_response;6769lhw->ic_addba_stop = ic->ic_addba_stop;6770ic->ic_addba_stop = lkpi_ic_addba_stop;6771lhw->ic_addba_response_timeout = ic->ic_addba_response_timeout;6772ic->ic_addba_response_timeout = lkpi_ic_addba_response_timeout;67736774lhw->ic_bar_response = ic->ic_bar_response;6775ic->ic_bar_response = lkpi_ic_bar_response;67766777lhw->ic_ampdu_rx_start = ic->ic_ampdu_rx_start;6778ic->ic_ampdu_rx_start = lkpi_ic_ampdu_rx_start;6779lhw->ic_ampdu_rx_stop = ic->ic_ampdu_rx_stop;6780ic->ic_ampdu_rx_stop = lkpi_ic_ampdu_rx_stop;6781}6782#endif67836784lkpi_radiotap_attach(lhw);67856786/*6787* Assign the first possible channel for now; seems Realtek drivers6788* expect one.6789* Also remember the amount of bands we support and the most rates6790* in any band so we can scale [(ext) sup rates] IE(s) accordingly.6791*/6792lhw->supbands = lhw->max_rates = 0;6793for (band = 0; band < NUM_NL80211_BANDS; band++) {6794struct ieee80211_supported_band *supband;6795struct linuxkpi_ieee80211_channel *channels;67966797supband = hw->wiphy->bands[band];6798if (supband == NULL || supband->n_channels == 0)6799continue;68006801lhw->supbands++;6802lhw->max_rates = max(lhw->max_rates, supband->n_bitrates);68036804/* If we have a channel, we need to keep counting supbands. */6805if (hw->conf.chandef.chan != NULL)6806continue;68076808channels = supband->channels;6809for (i = 0; i < supband->n_channels; i++) {68106811if (channels[i].flags & IEEE80211_CHAN_DISABLED)6812continue;68136814cfg80211_chandef_create(&hw->conf.chandef, &channels[i],6815#ifdef LKPI_80211_HT6816(ic->ic_flags_ht & IEEE80211_FHT_HT) ? NL80211_CHAN_HT20 :6817#endif6818NL80211_CHAN_NO_HT);6819break;6820}6821}68226823IMPROVE("see net80211::ieee80211_chan_init vs. wiphy->bands[].bitrates possibly in lkpi_ic_getradiocaps?");68246825/* Make sure we do not support more than net80211 is willing to take. */6826if (lhw->max_rates > IEEE80211_RATE_MAXSIZE) {6827ic_printf(ic, "%s: limiting max_rates %d to %d!\n", __func__,6828lhw->max_rates, IEEE80211_RATE_MAXSIZE);6829lhw->max_rates = IEEE80211_RATE_MAXSIZE;6830}68316832/*6833* The maximum supported bitrates on any band + size for6834* DSSS Parameter Set give our per-band IE size.6835* SSID is the responsibility of the driver and goes on the side.6836* The user specified bits coming from the vap go into the6837* "common ies" fields.6838*/6839lhw->scan_ie_len = 2 + IEEE80211_RATE_SIZE;6840if (lhw->max_rates > IEEE80211_RATE_SIZE)6841lhw->scan_ie_len += 2 + (lhw->max_rates - IEEE80211_RATE_SIZE);68426843if (hw->wiphy->features & NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) {6844/*6845* net80211 does not seem to support the DSSS Parameter Set but6846* some of the drivers insert it so calculate the extra fixed6847* space in.6848*/6849lhw->scan_ie_len += 2 + 1;6850}68516852#if defined(LKPI_80211_HT)6853if ((ic->ic_htcaps & IEEE80211_HTC_HT) != 0)6854lhw->scan_ie_len += sizeof(struct ieee80211_ie_htcap);6855#endif6856#if defined(LKPI_80211_VHT)6857if (IEEE80211_CONF_VHT(ic))6858lhw->scan_ie_len += 2 + sizeof(struct ieee80211_vht_cap);6859#endif68606861/* Reduce the max_scan_ie_len "left" by the amount we consume already. */6862if (hw->wiphy->max_scan_ie_len > 0) {6863if (lhw->scan_ie_len > hw->wiphy->max_scan_ie_len)6864goto err;6865hw->wiphy->max_scan_ie_len -= lhw->scan_ie_len;6866}68676868if (bootverbose) {6869ic_printf(ic, "netdev_features %b\n", hw->netdev_features, NETIF_F_BITS);6870ieee80211_announce(ic);6871}68726873return (0);6874err:6875IMPROVE("TODO FIXME CLEANUP");6876return (-EAGAIN);6877}68786879void6880linuxkpi_ieee80211_ifdetach(struct ieee80211_hw *hw)6881{6882struct lkpi_hw *lhw;6883struct ieee80211com *ic;68846885lhw = HW_TO_LHW(hw);6886ic = lhw->ic;6887ieee80211_ifdetach(ic);6888}68896890void6891linuxkpi_ieee80211_iterate_interfaces(struct ieee80211_hw *hw,6892enum ieee80211_iface_iter flags,6893void(*iterfunc)(void *, uint8_t *, struct ieee80211_vif *),6894void *arg)6895{6896struct lkpi_hw *lhw;6897struct lkpi_vif *lvif;6898struct ieee80211_vif *vif;6899bool active, atomic, nin_drv;69006901lhw = HW_TO_LHW(hw);69026903if (flags & ~(IEEE80211_IFACE_ITER_NORMAL|6904IEEE80211_IFACE_ITER_RESUME_ALL|6905IEEE80211_IFACE_SKIP_SDATA_NOT_IN_DRIVER|6906IEEE80211_IFACE_ITER_ACTIVE|IEEE80211_IFACE_ITER__ATOMIC)) {6907ic_printf(lhw->ic, "XXX TODO %s flags(%#x) not yet supported.\n",6908__func__, flags);6909}69106911active = (flags & IEEE80211_IFACE_ITER_ACTIVE) != 0;6912atomic = (flags & IEEE80211_IFACE_ITER__ATOMIC) != 0;6913nin_drv = (flags & IEEE80211_IFACE_SKIP_SDATA_NOT_IN_DRIVER) != 0;69146915if (atomic)6916LKPI_80211_LHW_LVIF_LOCK(lhw);6917TAILQ_FOREACH(lvif, &lhw->lvif_head, lvif_entry) {6918struct ieee80211vap *vap;69196920vif = LVIF_TO_VIF(lvif);69216922/*6923* If we want "active" interfaces, we need to distinguish on6924* whether the driver knows about them or not to be able to6925* handle the "resume" case correctly. Skip the ones the6926* driver does not know about.6927*/6928if (active && !lvif->added_to_drv &&6929(flags & IEEE80211_IFACE_ITER_RESUME_ALL) != 0)6930continue;69316932/*6933* If we shall skip interfaces not added to the driver do so6934* if we haven't yet.6935*/6936if (nin_drv && !lvif->added_to_drv)6937continue;69386939/*6940* Run the iterator function if we are either not asking6941* asking for active only or if the VAP is "running".6942*/6943/* XXX-BZ probably should have state in the lvif as well. */6944vap = LVIF_TO_VAP(lvif);6945if (!active || (vap->iv_state != IEEE80211_S_INIT))6946iterfunc(arg, vif->addr, vif);6947}6948if (atomic)6949LKPI_80211_LHW_LVIF_UNLOCK(lhw);6950}69516952static void6953lkpi_ieee80211_iterate_keys(struct ieee80211_hw *hw, struct ieee80211_vif *vif,6954ieee80211_keyix keyix, struct lkpi_sta *lsta,6955void(*iterfunc)(struct ieee80211_hw *, struct ieee80211_vif *,6956struct ieee80211_sta *, struct ieee80211_key_conf *, void *),6957void *arg)6958{6959if (!lsta->added_to_drv)6960return;69616962if (lsta->kc[keyix] == NULL)6963return;69646965iterfunc(hw, vif, LSTA_TO_STA(lsta), lsta->kc[keyix], arg);6966}69676968void6969linuxkpi_ieee80211_iterate_keys(struct ieee80211_hw *hw,6970struct ieee80211_vif *vif,6971void(*iterfunc)(struct ieee80211_hw *, struct ieee80211_vif *,6972struct ieee80211_sta *, struct ieee80211_key_conf *, void *),6973void *arg, bool rcu)6974{6975struct lkpi_sta *lsta;6976struct lkpi_vif *lvif;69776978lvif = VIF_TO_LVIF(vif);69796980if (rcu) {6981rcu_read_lock_held(); /* XXX-BZ is this correct? */69826983if (vif == NULL) {6984TODO();6985} else {6986list_for_each_entry_rcu(lsta, &lvif->lsta_list, lsta_list) {6987for (ieee80211_keyix keyix = 0; keyix < nitems(lsta->kc);6988keyix++)6989lkpi_ieee80211_iterate_keys(hw, vif,6990keyix, lsta, iterfunc, arg);6991}6992}6993} else {6994TODO("Used by suspend/resume; order of keys as installed to "6995"firmware is important; we'll need to rewrite some code for that");6996lockdep_assert_wiphy(hw->wiphy);69976998if (vif == NULL) {6999TODO();7000} else {7001list_for_each_entry(lsta, &lvif->lsta_list, lsta_list) {7002for (ieee80211_keyix keyix = 0; keyix < nitems(lsta->kc);7003keyix++)7004lkpi_ieee80211_iterate_keys(hw, vif,7005keyix, lsta, iterfunc, arg);7006}7007}7008}7009}70107011void7012linuxkpi_ieee80211_iterate_chan_contexts(struct ieee80211_hw *hw,7013void(*iterfunc)(struct ieee80211_hw *, struct ieee80211_chanctx_conf *,7014void *),7015void *arg)7016{7017struct lkpi_hw *lhw;7018struct lkpi_chanctx *lchanctx;70197020KASSERT(hw != NULL && iterfunc != NULL,7021("%s: hw %p iterfunc %p arg %p\n", __func__, hw, iterfunc, arg));70227023lhw = HW_TO_LHW(hw);70247025rcu_read_lock();7026list_for_each_entry_rcu(lchanctx, &lhw->lchanctx_list, entry) {7027if (!lchanctx->added_to_drv)7028continue;7029iterfunc(hw, &lchanctx->chanctx_conf, arg);7030}7031rcu_read_unlock();7032}70337034void7035linuxkpi_ieee80211_iterate_stations_atomic(struct ieee80211_hw *hw,7036void (*iterfunc)(void *, struct ieee80211_sta *), void *arg)7037{7038struct lkpi_hw *lhw;7039struct lkpi_vif *lvif;7040struct lkpi_sta *lsta;7041struct ieee80211_sta *sta;70427043KASSERT(hw != NULL && iterfunc != NULL,7044("%s: hw %p iterfunc %p arg %p\n", __func__, hw, iterfunc, arg));70457046lhw = HW_TO_LHW(hw);70477048LKPI_80211_LHW_LVIF_LOCK(lhw);7049TAILQ_FOREACH(lvif, &lhw->lvif_head, lvif_entry) {70507051rcu_read_lock();7052list_for_each_entry_rcu(lsta, &lvif->lsta_list, lsta_list) {7053if (!lsta->added_to_drv)7054continue;7055sta = LSTA_TO_STA(lsta);7056iterfunc(arg, sta);7057}7058rcu_read_unlock();7059}7060LKPI_80211_LHW_LVIF_UNLOCK(lhw);7061}70627063struct linuxkpi_ieee80211_regdomain *7064lkpi_get_linuxkpi_ieee80211_regdomain(size_t n)7065{7066struct linuxkpi_ieee80211_regdomain *regd;70677068regd = kzalloc(sizeof(*regd) + n * sizeof(struct ieee80211_reg_rule),7069GFP_KERNEL);7070return (regd);7071}70727073int7074linuxkpi_regulatory_set_wiphy_regd_sync(struct wiphy *wiphy,7075struct linuxkpi_ieee80211_regdomain *regd)7076{7077struct lkpi_hw *lhw;7078struct ieee80211com *ic;7079struct ieee80211_regdomain *rd;70807081lhw = wiphy_priv(wiphy);7082ic = lhw->ic;70837084rd = &ic->ic_regdomain;7085if (rd->isocc[0] == '\0') {7086rd->isocc[0] = regd->alpha2[0];7087rd->isocc[1] = regd->alpha2[1];7088}70897090TODO();7091/* XXX-BZ finish the rest. */70927093return (0);7094}70957096void7097linuxkpi_ieee80211_scan_completed(struct ieee80211_hw *hw,7098struct cfg80211_scan_info *info)7099{7100struct lkpi_hw *lhw;7101struct ieee80211com *ic;7102struct ieee80211_scan_state *ss;71037104lhw = wiphy_priv(hw->wiphy);7105ic = lhw->ic;7106ss = ic->ic_scan;71077108TRACE_SCAN(ic, "scan_flags %b info { %ju, %6D, aborted %d }",7109lhw->scan_flags, LKPI_LHW_SCAN_BITS,7110(uintmax_t)info->scan_start_tsf, info->tsf_bssid, ":",7111info->aborted);71127113ieee80211_scan_done(ss->ss_vap);71147115LKPI_80211_LHW_SCAN_LOCK(lhw);7116free(lhw->hw_req, M_LKPI80211);7117lhw->hw_req = NULL;7118lhw->scan_flags &= ~LKPI_LHW_SCAN_RUNNING;7119/* The wakeup(lhw) will be called from lkpi_ic_scan_end(). */7120/* wakeup(lhw); */7121LKPI_80211_LHW_SCAN_UNLOCK(lhw);71227123return;7124}71257126static void7127lkpi_80211_lhw_rxq_rx_one(struct lkpi_hw *lhw, struct mbuf *m)7128{7129struct ieee80211_node *ni;7130#ifdef LKPI_80211_USE_MTAG7131struct m_tag *mtag;7132#endif7133int ok;71347135ni = NULL;7136#ifdef LKPI_80211_USE_MTAG7137mtag = m_tag_locate(m, MTAG_ABI_LKPI80211, LKPI80211_TAG_RXNI, NULL);7138if (mtag != NULL) {7139struct lkpi_80211_tag_rxni *rxni;71407141rxni = (struct lkpi_80211_tag_rxni *)(mtag + 1);7142ni = rxni->ni;7143}7144#else7145if (m->m_pkthdr.PH_loc.ptr != NULL) {7146ni = m->m_pkthdr.PH_loc.ptr;7147m->m_pkthdr.PH_loc.ptr = NULL;7148}7149#endif71507151if (ni != NULL) {7152ok = ieee80211_input_mimo(ni, m);7153ieee80211_free_node(ni); /* Release the reference. */7154if (ok < 0)7155m_freem(m);7156} else {7157ok = ieee80211_input_mimo_all(lhw->ic, m);7158/* mbuf got consumed. */7159}71607161#ifdef LINUXKPI_DEBUG_802117162if (linuxkpi_debug_80211 & D80211_TRACE_RX)7163printf("TRACE-RX: %s: handled frame type %#0x\n", __func__, ok);7164#endif7165}71667167static void7168lkpi_80211_lhw_rxq_task(void *ctx, int pending)7169{7170struct lkpi_hw *lhw;7171struct mbufq mq;7172struct mbuf *m;71737174lhw = ctx;71757176#ifdef LINUXKPI_DEBUG_802117177if (linuxkpi_debug_80211 & D80211_TRACE_RX)7178printf("TRACE-RX: %s: lhw %p pending %d mbuf_qlen %d\n",7179__func__, lhw, pending, mbufq_len(&lhw->rxq));7180#endif71817182mbufq_init(&mq, IFQ_MAXLEN);71837184LKPI_80211_LHW_RXQ_LOCK(lhw);7185mbufq_concat(&mq, &lhw->rxq);7186LKPI_80211_LHW_RXQ_UNLOCK(lhw);71877188m = mbufq_dequeue(&mq);7189while (m != NULL) {7190lkpi_80211_lhw_rxq_rx_one(lhw, m);7191m = mbufq_dequeue(&mq);7192}7193}71947195static void7196lkpi_convert_rx_status(struct ieee80211_hw *hw, struct lkpi_sta *lsta,7197struct ieee80211_rx_status *rx_status,7198struct ieee80211_rx_stats *rx_stats,7199uint8_t *rssip)7200{7201struct ieee80211_supported_band *supband;7202struct rate_info rxrate;7203int i;7204uint8_t rssi;72057206memset(&rxrate, 0, sizeof(rxrate));7207memset(rx_stats, 0, sizeof(*rx_stats));7208rx_stats->r_flags = IEEE80211_R_NF | IEEE80211_R_RSSI;7209/* XXX-BZ correct hardcoded noise floor, survey data? */7210rx_stats->c_nf = -96;7211if (ieee80211_hw_check(hw, SIGNAL_DBM) &&7212!(rx_status->flag & RX_FLAG_NO_SIGNAL_VAL))7213rssi = rx_status->signal;7214else7215rssi = rx_stats->c_nf;7216/*7217* net80211 signal strength data are in .5 dBm units relative to7218* the current noise floor (see comment in ieee80211_node.h).7219*/7220rssi -= rx_stats->c_nf;7221if (rssip != NULL)7222*rssip = rssi;7223rx_stats->c_rssi = rssi * 2;7224rx_stats->r_flags |= IEEE80211_R_BAND;7225rx_stats->c_band =7226lkpi_nl80211_band_to_net80211_band(rx_status->band);7227rx_stats->r_flags |= IEEE80211_R_FREQ | IEEE80211_R_IEEE;7228rx_stats->c_freq = rx_status->freq;7229rx_stats->c_ieee = ieee80211_mhz2ieee(rx_stats->c_freq, rx_stats->c_band);72307231rx_stats->c_rx_tsf = rx_status->mactime;72327233/* XXX RX_FLAG_MACTIME_IS_RTAP_TS64 ? */7234if ((rx_status->flag & RX_FLAG_MACTIME) ==7235(RX_FLAG_MACTIME_START|RX_FLAG_MACTIME_END)) {7236rx_stats->r_flags |= IEEE80211_R_TSF64;7237/* XXX RX_FLAG_MACTIME_PLCP_START ? */7238if ((rx_status->flag & RX_FLAG_MACTIME) == RX_FLAG_MACTIME_START)7239rx_stats->r_flags |= IEEE80211_R_TSF_START;7240if ((rx_status->flag & RX_FLAG_MACTIME) == RX_FLAG_MACTIME_END)7241rx_stats->r_flags |= IEEE80211_R_TSF_END;7242/* XXX-BZ if TSF_END will net80211 do the unwind of time? */7243}72447245if (rx_status->chains != 0) {7246int cc;7247int8_t crssi;72487249rx_stats->c_chain = rx_status->chains;7250rx_stats->r_flags |= IEEE80211_R_C_CHAIN;72517252cc = 0;7253for (i = 0; i < nitems(rx_status->chain_signal); i++) {7254if (!(rx_status->chains & BIT(i)))7255continue;7256crssi = rx_status->chain_signal[i];7257crssi -= rx_stats->c_nf;7258rx_stats->c_rssi_ctl[i] = crssi * 2;7259rx_stats->c_rssi_ext[i] = crssi * 2; /* XXX _ext ??? ATH thing? */7260/* We currently only have the global noise floor value. */7261rx_stats->c_nf_ctl[i] = rx_stats->c_nf;7262rx_stats->c_nf_ext[i] = rx_stats->c_nf;7263cc++;7264}7265if (cc > 0)7266rx_stats->r_flags |= (IEEE80211_R_C_NF | IEEE80211_R_C_RSSI);7267}72687269/* XXX-NET80211 We are not going to populate c_phytype! */72707271switch (rx_status->encoding) {7272case RX_ENC_LEGACY:7273{7274uint32_t legacy = 0;72757276supband = hw->wiphy->bands[rx_status->band];7277if (supband != NULL)7278legacy = supband->bitrates[rx_status->rate_idx].bitrate;7279rx_stats->c_rate = legacy;7280rxrate.legacy = legacy;7281/* Is there a LinuxKPI way of reporting IEEE80211_RX_F_CCK / _OFDM? */7282break;7283}7284case RX_ENC_HT:7285rx_stats->c_pktflags |= IEEE80211_RX_F_HT;7286rx_stats->c_rate = rx_status->rate_idx; /* mcs */7287rxrate.flags |= RATE_INFO_FLAGS_MCS;7288rxrate.mcs = rx_status->rate_idx;7289if ((rx_status->enc_flags & RX_ENC_FLAG_SHORT_GI) != 0) {7290rx_stats->c_pktflags |= IEEE80211_RX_F_SHORTGI;7291rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI;7292}7293break;7294case RX_ENC_VHT:7295rx_stats->c_pktflags |= IEEE80211_RX_F_VHT;7296rx_stats->c_rate = rx_status->rate_idx; /* mcs */7297rx_stats->c_vhtnss = rx_status->nss;7298rxrate.flags |= RATE_INFO_FLAGS_VHT_MCS;7299rxrate.mcs = rx_status->rate_idx;7300rxrate.nss = rx_status->nss;7301if ((rx_status->enc_flags & RX_ENC_FLAG_SHORT_GI) != 0) {7302rx_stats->c_pktflags |= IEEE80211_RX_F_SHORTGI;7303rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI;7304}7305break;7306case RX_ENC_HE:7307rxrate.flags |= RATE_INFO_FLAGS_HE_MCS;7308rxrate.mcs = rx_status->rate_idx;7309rxrate.nss = rx_status->nss;7310/* XXX TODO */7311TODO("net80211 has not matching encoding for %u", rx_status->encoding);7312break;7313case RX_ENC_EHT:7314rxrate.flags |= RATE_INFO_FLAGS_EHT_MCS;7315rxrate.mcs = rx_status->rate_idx;7316rxrate.nss = rx_status->nss;7317/* XXX TODO */7318TODO("net80211 has not matching encoding for %u", rx_status->encoding);7319break;7320}73217322rxrate.bw = rx_status->bw;7323switch (rx_status->bw) {7324case RATE_INFO_BW_20:7325rx_stats->c_width = IEEE80211_RX_FW_20MHZ;7326break;7327case RATE_INFO_BW_40:7328rx_stats->c_width = IEEE80211_RX_FW_40MHZ;7329break;7330case RATE_INFO_BW_80:7331rx_stats->c_width = IEEE80211_RX_FW_80MHZ;7332break;7333case RATE_INFO_BW_160:7334rx_stats->c_width = IEEE80211_RX_FW_160MHZ;7335break;7336case RATE_INFO_BW_320:7337case RATE_INFO_BW_HE_RU:7338case RATE_INFO_BW_EHT_RU:7339case RATE_INFO_BW_5:7340case RATE_INFO_BW_10:7341TODO("net80211 has not matching bandwidth for %u", rx_status->bw);7342break;7343}73447345if ((rx_status->enc_flags & RX_ENC_FLAG_LDPC) != 0)7346rx_stats->c_pktflags |= IEEE80211_RX_F_LDPC;7347if ((rx_status->enc_flags & RX_ENC_FLAG_STBC_MASK) != 0)7348rx_stats->c_pktflags |= IEEE80211_RX_F_STBC;73497350/*7351* We only need these for LKPI_80211_HW_CRYPTO in theory but in7352* case the hardware does something we do not expect always leave7353* these enabled. Leaving this commant as documentation for the || 1.7354*/7355#if defined(LKPI_80211_HW_CRYPTO) || 17356if (rx_status->flag & RX_FLAG_DECRYPTED) {7357rx_stats->c_pktflags |= IEEE80211_RX_F_DECRYPTED;7358/* Only valid if decrypted is set. */7359if (rx_status->flag & RX_FLAG_PN_VALIDATED)7360rx_stats->c_pktflags |= IEEE80211_RX_F_PN_VALIDATED;7361}7362if (rx_status->flag & RX_FLAG_IV_STRIPPED)7363rx_stats->c_pktflags |= IEEE80211_RX_F_IV_STRIP;7364if (rx_status->flag & RX_FLAG_ICV_STRIPPED)7365rx_stats->c_pktflags |= IEEE80211_RX_F_ICV_STRIP;7366if (rx_status->flag & RX_FLAG_MIC_STRIPPED)7367rx_stats->c_pktflags |= IEEE80211_RX_F_MIC_STRIP;7368if (rx_status->flag & RX_FLAG_MMIC_STRIPPED)7369rx_stats->c_pktflags |= IEEE80211_RX_F_MMIC_STRIP;7370if (rx_status->flag & RX_FLAG_MMIC_ERROR)7371rx_stats->c_pktflags |= IEEE80211_RX_F_FAIL_MMIC;7372if (rx_status->flag & RX_FLAG_FAILED_FCS_CRC)7373rx_stats->c_pktflags |= IEEE80211_RX_F_FAIL_FCSCRC;7374#endif73757376/* Fill in some sinfo bits to fill gaps not reported byt the driver. */7377if (lsta != NULL) {7378memcpy(&lsta->sinfo.rxrate, &rxrate, sizeof(rxrate));7379lsta->sinfo.filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE);73807381if (rx_status->chains != 0) {7382lsta->sinfo.chains = rx_status->chains;7383memcpy(lsta->sinfo.chain_signal, rx_status->chain_signal,7384sizeof(lsta->sinfo.chain_signal));7385lsta->sinfo.filled |= BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL);7386}7387}7388}73897390#ifdef LINUXKPI_DEBUG_802117391static void7392lkpi_rx_log_beacon(struct mbuf *m, struct lkpi_hw *lhw,7393struct ieee80211_rx_status *rx_status)7394{7395struct ieee80211_mgmt *f;7396uint8_t *e;7397char ssid[IEEE80211_NWID_LEN * 4 + 1];73987399memset(ssid, '\0', sizeof(ssid));74007401f = mtod(m, struct ieee80211_mgmt *);7402e = f->u.beacon.variable;7403/*7404* Usually SSID is right after the fixed part and for debugging we will7405* be fine should we miss it if it is not.7406*/7407while ((e - (uint8_t *)f) < m->m_len) {7408if (*e == IEEE80211_ELEMID_SSID)7409break;7410e += (2 + *(e + 1));7411}7412if (*e == IEEE80211_ELEMID_SSID) {7413int i, len;7414char *p;74157416p = ssid;7417len = m->m_len - ((e + 2) - (uint8_t *)f);7418if (len > *(e + 1))7419len = *(e + 1);7420e += 2;7421for (i = 0; i < len; i++) {7422/* Printable character? */7423if (*e >= 0x20 && *e < 0x7f) {7424*p++ = *e++;7425} else {7426snprintf(p, 5, "%#04x", *e++);7427p += 4;7428}7429}7430*p = '\0';7431}74327433/* We print skb, skb->data, m as we are seeing 'ghost beacons'. */7434TRACE_SCAN_BEACON(lhw->ic, "Beacon: scan_flags %b, band %s freq %u chan %-4d "7435"len %d { %#06x %#06x %6D %6D %6D %#06x %ju %u %#06x SSID '%s' }",7436lhw->scan_flags, LKPI_LHW_SCAN_BITS,7437lkpi_nl80211_band_name(rx_status->band), rx_status->freq,7438linuxkpi_ieee80211_frequency_to_channel(rx_status->freq, 0),7439m->m_pkthdr.len, f->frame_control, f->duration_id,7440f->da, ":", f->sa, ":", f->bssid, ":", f->seq_ctrl,7441(uintmax_t)le64_to_cpu(f->u.beacon.timestamp),7442le16_to_cpu(f->u.beacon.beacon_int),7443le16_to_cpu(f->u.beacon.capab_info), ssid);7444}7445#endif74467447/* For %list see comment towards the end of the function. */7448void7449linuxkpi_ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,7450struct ieee80211_sta *sta, struct napi_struct *napi __unused,7451struct list_head *list __unused)7452{7453struct lkpi_hw *lhw;7454struct ieee80211com *ic;7455struct mbuf *m;7456struct skb_shared_info *shinfo;7457struct ieee80211_rx_status *rx_status;7458struct ieee80211_rx_stats rx_stats;7459struct ieee80211_node *ni;7460struct ieee80211vap *vap;7461struct ieee80211_hdr *hdr;7462struct lkpi_sta *lsta;7463int i, offset, ok, error;7464uint8_t rssi;7465bool is_beacon;74667467lhw = HW_TO_LHW(hw);7468ic = lhw->ic;74697470if (skb->len < 2) {7471/* Need 80211 stats here. */7472counter_u64_add(ic->ic_ierrors, 1);7473IMPROVE();7474goto err;7475}74767477/*7478* For now do the data copy; we can later improve things. Might even7479* have an mbuf backing the skb data then?7480*/7481m = m_get3(skb->len, M_NOWAIT, MT_DATA, M_PKTHDR);7482if (m == NULL) {7483counter_u64_add(ic->ic_ierrors, 1);7484goto err;7485}7486m_copyback(m, 0, skb->tail - skb->data, skb->data);74877488shinfo = skb_shinfo(skb);7489offset = m->m_len;7490for (i = 0; i < shinfo->nr_frags; i++) {7491m_copyback(m, offset, shinfo->frags[i].size,7492(uint8_t *)linux_page_address(shinfo->frags[i].page) +7493shinfo->frags[i].offset);7494offset += shinfo->frags[i].size;7495}74967497rx_status = IEEE80211_SKB_RXCB(skb);74987499hdr = (void *)skb->data;7500is_beacon = ieee80211_is_beacon(hdr->frame_control);75017502#ifdef LINUXKPI_DEBUG_802117503/*7504* We use the mbuf here as otherwise the variable part might7505* be in skb frags.7506*/7507if (is_beacon && ((linuxkpi_debug_80211 & D80211_SCAN_BEACON) != 0))7508lkpi_rx_log_beacon(m, lhw, rx_status);75097510if (is_beacon && (linuxkpi_debug_80211 & D80211_TRACE_RX_BEACONS) == 0 &&7511(linuxkpi_debug_80211 & D80211_SCAN_BEACON) == 0)7512goto no_trace_beacons;75137514if (linuxkpi_debug_80211 & D80211_TRACE_RX)7515printf("TRACE-RX: %s: skb %p l/d/t-len (%u/%u/%u) "7516"h %p d %p t %p e %p sh %p (%u) m %p plen %u len %u%s\n",7517__func__, skb, skb->len, skb->data_len,7518skb->truesize, skb->head, skb->data, skb->tail, skb->end,7519shinfo, shinfo->nr_frags,7520m, m->m_pkthdr.len, m->m_len, is_beacon ? " beacon" : "");75217522if (linuxkpi_debug_80211 & D80211_TRACE_RX_DUMP)7523hexdump(mtod(m, const void *), m->m_len, "RX (raw) ", 0);75247525/* Implement a dump_rxcb() !!! */7526if ((linuxkpi_debug_80211 & D80211_TRACE_RX) != 0 ||7527(linuxkpi_debug_80211 & D80211_SCAN_BEACON) != 0)7528printf("TRACE-RX: %s: RXCB: %ju %ju %u, %b, %u, %#0x, %#0x, "7529"%u band %u, %u { %d %d %d %d }, %d, %#x %#x %#x %#x %u %u %u\n",7530__func__,7531(uintmax_t)rx_status->boottime_ns,7532(uintmax_t)rx_status->mactime,7533rx_status->device_timestamp,7534rx_status->flag, IEEE80211_RX_STATUS_FLAGS_BITS,7535rx_status->freq,7536rx_status->bw,7537rx_status->encoding,7538rx_status->ampdu_reference,7539rx_status->band,7540rx_status->chains,7541rx_status->chain_signal[0],7542rx_status->chain_signal[1],7543rx_status->chain_signal[2],7544rx_status->chain_signal[3],7545rx_status->signal,7546rx_status->enc_flags,7547rx_status->he_dcm,7548rx_status->he_gi,7549rx_status->he_ru,7550rx_status->zero_length_psdu_type,7551rx_status->nss,7552rx_status->rate_idx);7553no_trace_beacons:7554#endif75557556lsta = NULL;7557if (sta != NULL) {7558lsta = STA_TO_LSTA(sta);7559ni = ieee80211_ref_node(lsta->ni);7560} else {7561struct ieee80211_frame_min *wh;75627563wh = mtod(m, struct ieee80211_frame_min *);7564ni = ieee80211_find_rxnode(ic, wh);7565if (ni != NULL)7566lsta = ni->ni_drv_data;7567}75687569rssi = 0;7570lkpi_convert_rx_status(hw, lsta, rx_status, &rx_stats, &rssi);75717572ok = ieee80211_add_rx_params(m, &rx_stats);7573if (ok == 0) {7574m_freem(m);7575counter_u64_add(ic->ic_ierrors, 1);7576goto err;7577}75787579if (ni != NULL)7580vap = ni->ni_vap;7581else7582/*7583* XXX-BZ can we improve this by looking at the frame hdr7584* or other meta-data passed up?7585*/7586vap = TAILQ_FIRST(&ic->ic_vaps);75877588#ifdef LINUXKPI_DEBUG_802117589if (linuxkpi_debug_80211 & D80211_TRACE_RX)7590printf("TRACE-RX: %s: sta %p lsta %p state %d ni %p vap %p%s\n",7591__func__, sta, lsta, (lsta != NULL) ? lsta->state : -1,7592ni, vap, is_beacon ? " beacon" : "");7593#endif75947595if (ni != NULL && vap != NULL && is_beacon &&7596rx_status->device_timestamp > 0 &&7597m->m_pkthdr.len >= sizeof(struct ieee80211_frame)) {7598struct lkpi_vif *lvif;7599struct ieee80211_vif *vif;7600struct ieee80211_frame *wh;76017602wh = mtod(m, struct ieee80211_frame *);7603if (!IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_bssid))7604goto skip_device_ts;76057606lvif = VAP_TO_LVIF(vap);7607vif = LVIF_TO_VIF(lvif);76087609IMPROVE("TIMING_BEACON_ONLY?");7610/* mac80211 specific (not net80211) so keep it here. */7611vif->bss_conf.sync_device_ts = rx_status->device_timestamp;7612/*7613* net80211 should take care of the other information (sync_tsf,7614* sync_dtim_count) as otherwise we need to parse the beacon.7615*/7616skip_device_ts:7617;7618}76197620if (vap != NULL && vap->iv_state > IEEE80211_S_INIT &&7621ieee80211_radiotap_active_vap(vap)) {7622struct lkpi_radiotap_rx_hdr *rtap;76237624rtap = &lhw->rtap_rx;7625rtap->wr_tsft = rx_status->device_timestamp;7626rtap->wr_flags = 0;7627if (rx_status->enc_flags & RX_ENC_FLAG_SHORTPRE)7628rtap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;7629if (rx_status->enc_flags & RX_ENC_FLAG_SHORT_GI)7630rtap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTGI;7631#if 0 /* .. or it does not given we strip it below. */7632if (ieee80211_hw_check(hw, RX_INCLUDES_FCS))7633rtap->wr_flags |= IEEE80211_RADIOTAP_F_FCS;7634#endif7635if (rx_status->flag & RX_FLAG_FAILED_FCS_CRC)7636rtap->wr_flags |= IEEE80211_RADIOTAP_F_BADFCS;7637rtap->wr_rate = 0;7638IMPROVE();7639/* XXX TODO status->encoding / rate_index / bw */7640rtap->wr_chan_freq = htole16(rx_stats.c_freq);7641if (ic->ic_curchan->ic_ieee == rx_stats.c_ieee)7642rtap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);7643rtap->wr_dbm_antsignal = rssi;7644rtap->wr_dbm_antnoise = rx_stats.c_nf;7645}76467647if (ieee80211_hw_check(hw, RX_INCLUDES_FCS))7648m_adj(m, -IEEE80211_CRC_LEN);76497650#if 07651if (list != NULL) {7652/*7653* Normally this would be queued up and delivered by7654* netif_receive_skb_list(), napi_gro_receive(), or the like.7655* See mt76::mac80211.c as only current possible consumer.7656*/7657IMPROVE("we simply pass the packet to net80211 to deal with.");7658}7659#endif76607661/* Attach meta-information to the mbuf for the deferred RX path. */7662if (ni != NULL) {7663#ifdef LKPI_80211_USE_MTAG7664struct m_tag *mtag;7665struct lkpi_80211_tag_rxni *rxni;76667667mtag = m_tag_alloc(MTAG_ABI_LKPI80211, LKPI80211_TAG_RXNI,7668sizeof(*rxni), IEEE80211_M_NOWAIT);7669if (mtag == NULL) {7670m_freem(m);7671counter_u64_add(ic->ic_ierrors, 1);7672goto err;7673}7674rxni = (struct lkpi_80211_tag_rxni *)(mtag + 1);7675rxni->ni = ni; /* We hold a reference. */7676m_tag_prepend(m, mtag);7677#else7678m->m_pkthdr.PH_loc.ptr = ni; /* We hold a reference. */7679#endif7680}76817682LKPI_80211_LHW_RXQ_LOCK(lhw);7683if (lhw->rxq_stopped) {7684LKPI_80211_LHW_RXQ_UNLOCK(lhw);7685m_freem(m);7686counter_u64_add(ic->ic_ierrors, 1);7687goto err;7688}76897690error = mbufq_enqueue(&lhw->rxq, m);7691if (error != 0) {7692LKPI_80211_LHW_RXQ_UNLOCK(lhw);7693m_freem(m);7694counter_u64_add(ic->ic_ierrors, 1);7695#ifdef LINUXKPI_DEBUG_802117696if (linuxkpi_debug_80211 & D80211_TRACE_RX)7697ic_printf(ni->ni_ic, "%s: mbufq_enqueue failed: %d\n",7698__func__, error);7699#endif7700goto err;7701}7702taskqueue_enqueue(taskqueue_thread, &lhw->rxq_task);7703LKPI_80211_LHW_RXQ_UNLOCK(lhw);77047705IMPROVE();77067707err:7708/* The skb is ours so we can free it :-) */7709kfree_skb(skb);7710}77117712uint8_t7713linuxkpi_ieee80211_get_tid(struct ieee80211_hdr *hdr, bool nonqos_ok)7714{7715const struct ieee80211_frame *wh;7716uint8_t tid;77177718/* Linux seems to assume this is a QOS-Data-Frame */7719KASSERT(nonqos_ok || ieee80211_is_data_qos(hdr->frame_control),7720("%s: hdr %p fc %#06x not qos_data\n", __func__, hdr,7721hdr->frame_control));77227723wh = (const struct ieee80211_frame *)hdr;7724tid = ieee80211_gettid(wh);7725KASSERT(nonqos_ok || tid == (tid & IEEE80211_QOS_TID), ("%s: tid %u "7726"not expected (%u?)\n", __func__, tid, IEEE80211_NONQOS_TID));77277728return (tid);7729}77307731/* -------------------------------------------------------------------------- */77327733static void7734lkpi_wiphy_work(struct work_struct *work)7735{7736struct lkpi_wiphy *lwiphy;7737struct wiphy *wiphy;7738struct wiphy_work *wk;77397740lwiphy = container_of(work, struct lkpi_wiphy, wwk);7741wiphy = LWIPHY_TO_WIPHY(lwiphy);77427743wiphy_lock(wiphy);77447745LKPI_80211_LWIPHY_WORK_LOCK(lwiphy);7746wk = list_first_entry_or_null(&lwiphy->wwk_list, struct wiphy_work, entry);7747/* If there is nothing we do nothing. */7748if (wk == NULL) {7749LKPI_80211_LWIPHY_WORK_UNLOCK(lwiphy);7750wiphy_unlock(wiphy);7751return;7752}7753list_del_init(&wk->entry);77547755/* More work to do? */7756if (!list_empty(&lwiphy->wwk_list))7757schedule_work(work);7758LKPI_80211_LWIPHY_WORK_UNLOCK(lwiphy);77597760/* Finally call the (*wiphy_work_fn)() function. */7761wk->fn(wiphy, wk);77627763wiphy_unlock(wiphy);7764}77657766void7767linuxkpi_wiphy_work_queue(struct wiphy *wiphy, struct wiphy_work *wwk)7768{7769struct lkpi_wiphy *lwiphy;77707771lwiphy = WIPHY_TO_LWIPHY(wiphy);77727773LKPI_80211_LWIPHY_WORK_LOCK(lwiphy);7774/* Do not double-queue. */7775if (list_empty(&wwk->entry))7776list_add_tail(&wwk->entry, &lwiphy->wwk_list);7777LKPI_80211_LWIPHY_WORK_UNLOCK(lwiphy);77787779/*7780* See how ieee80211_queue_work() work continues in Linux or if things7781* migrate here over time?7782* Use a system queue from linux/workqueue.h for now.7783*/7784queue_work(system_wq, &lwiphy->wwk);7785}77867787void7788linuxkpi_wiphy_work_cancel(struct wiphy *wiphy, struct wiphy_work *wwk)7789{7790struct lkpi_wiphy *lwiphy;77917792lwiphy = WIPHY_TO_LWIPHY(wiphy);77937794LKPI_80211_LWIPHY_WORK_LOCK(lwiphy);7795/* Only cancel if queued. */7796if (!list_empty(&wwk->entry))7797list_del_init(&wwk->entry);7798LKPI_80211_LWIPHY_WORK_UNLOCK(lwiphy);7799}78007801void7802linuxkpi_wiphy_work_flush(struct wiphy *wiphy, struct wiphy_work *wwk)7803{7804struct lkpi_wiphy *lwiphy;7805struct wiphy_work *wk;78067807lwiphy = WIPHY_TO_LWIPHY(wiphy);7808LKPI_80211_LWIPHY_WORK_LOCK(lwiphy);7809/* If wwk is unset, flush everything; called when wiphy is shut down. */7810if (wwk != NULL && list_empty(&wwk->entry)) {7811LKPI_80211_LWIPHY_WORK_UNLOCK(lwiphy);7812return;7813}78147815while (!list_empty(&lwiphy->wwk_list)) {78167817wk = list_first_entry(&lwiphy->wwk_list, struct wiphy_work,7818entry);7819list_del_init(&wk->entry);7820LKPI_80211_LWIPHY_WORK_UNLOCK(lwiphy);7821wk->fn(wiphy, wk);7822LKPI_80211_LWIPHY_WORK_LOCK(lwiphy);7823if (wk == wwk)7824break;7825}7826LKPI_80211_LWIPHY_WORK_UNLOCK(lwiphy);7827}78287829void7830lkpi_wiphy_delayed_work_timer(struct timer_list *tl)7831{7832struct wiphy_delayed_work *wdwk;78337834wdwk = timer_container_of(wdwk, tl, timer);7835wiphy_work_queue(wdwk->wiphy, &wdwk->work);7836}78377838void7839linuxkpi_wiphy_delayed_work_queue(struct wiphy *wiphy,7840struct wiphy_delayed_work *wdwk, unsigned long delay)7841{7842if (delay == 0) {7843/* Run right away. */7844del_timer(&wdwk->timer);7845wiphy_work_queue(wiphy, &wdwk->work);7846} else {7847wdwk->wiphy = wiphy;7848mod_timer(&wdwk->timer, jiffies + delay);7849}7850}78517852void7853linuxkpi_wiphy_delayed_work_cancel(struct wiphy *wiphy,7854struct wiphy_delayed_work *wdwk)7855{7856del_timer_sync(&wdwk->timer);7857wiphy_work_cancel(wiphy, &wdwk->work);7858}78597860/* -------------------------------------------------------------------------- */78617862struct wiphy *7863linuxkpi_wiphy_new(const struct cfg80211_ops *ops, size_t priv_len)7864{7865struct lkpi_wiphy *lwiphy;7866struct wiphy *wiphy;78677868lwiphy = kzalloc(sizeof(*lwiphy) + priv_len, GFP_KERNEL);7869if (lwiphy == NULL)7870return (NULL);7871lwiphy->ops = ops;78727873LKPI_80211_LWIPHY_WORK_LOCK_INIT(lwiphy);7874INIT_LIST_HEAD(&lwiphy->wwk_list);7875INIT_WORK(&lwiphy->wwk, lkpi_wiphy_work);78767877wiphy = LWIPHY_TO_WIPHY(lwiphy);78787879mutex_init(&wiphy->mtx);7880TODO();78817882return (wiphy);7883}78847885void7886linuxkpi_wiphy_free(struct wiphy *wiphy)7887{7888struct lkpi_wiphy *lwiphy;78897890if (wiphy == NULL)7891return;78927893linuxkpi_wiphy_work_flush(wiphy, NULL);7894mutex_destroy(&wiphy->mtx);78957896lwiphy = WIPHY_TO_LWIPHY(wiphy);7897LKPI_80211_LWIPHY_WORK_LOCK_DESTROY(lwiphy);78987899kfree(lwiphy);7900}79017902static uint32_t7903lkpi_cfg80211_calculate_bitrate_ht(struct rate_info *rate)7904{7905TODO("cfg80211_calculate_bitrate_ht");7906return (rate->legacy);7907}79087909static uint32_t7910lkpi_cfg80211_calculate_bitrate_vht(struct rate_info *rate)7911{7912TODO("cfg80211_calculate_bitrate_vht");7913return (rate->legacy);7914}79157916uint32_t7917linuxkpi_cfg80211_calculate_bitrate(struct rate_info *rate)7918{79197920/* Beware: order! */7921if (rate->flags & RATE_INFO_FLAGS_MCS)7922return (lkpi_cfg80211_calculate_bitrate_ht(rate));79237924if (rate->flags & RATE_INFO_FLAGS_VHT_MCS)7925return (lkpi_cfg80211_calculate_bitrate_vht(rate));79267927IMPROVE("HE/EHT/...");79287929return (rate->legacy);7930}79317932uint32_t7933linuxkpi_ieee80211_channel_to_frequency(uint32_t channel,7934enum nl80211_band band)7935{79367937switch (band) {7938case NL80211_BAND_2GHZ:7939return (ieee80211_ieee2mhz(channel, IEEE80211_CHAN_2GHZ));7940break;7941case NL80211_BAND_5GHZ:7942return (ieee80211_ieee2mhz(channel, IEEE80211_CHAN_5GHZ));7943break;7944default:7945/* XXX abort, retry, error, panic? */7946break;7947}79487949return (0);7950}79517952uint32_t7953linuxkpi_ieee80211_frequency_to_channel(uint32_t freq, uint32_t flags __unused)7954{79557956return (ieee80211_mhz2ieee(freq, 0));7957}79587959#if 07960static struct lkpi_sta *7961lkpi_find_lsta_by_ni(struct lkpi_vif *lvif, struct ieee80211_node *ni)7962{7963struct lkpi_sta *lsta, *temp;79647965rcu_read_lock();7966list_for_each_entry_rcu(lsta, &lvif->lsta_list, lsta_list) {7967if (lsta->ni == ni) {7968rcu_read_unlock();7969return (lsta);7970}7971}7972rcu_read_unlock();79737974return (NULL);7975}7976#endif79777978struct ieee80211_sta *7979linuxkpi_ieee80211_find_sta(struct ieee80211_vif *vif, const u8 *peer)7980{7981struct lkpi_vif *lvif;7982struct lkpi_sta *lsta;7983struct ieee80211_sta *sta;79847985lvif = VIF_TO_LVIF(vif);79867987rcu_read_lock();7988list_for_each_entry_rcu(lsta, &lvif->lsta_list, lsta_list) {7989sta = LSTA_TO_STA(lsta);7990if (IEEE80211_ADDR_EQ(sta->addr, peer)) {7991rcu_read_unlock();7992return (sta);7993}7994}7995rcu_read_unlock();7996return (NULL);7997}79987999struct ieee80211_sta *8000linuxkpi_ieee80211_find_sta_by_ifaddr(struct ieee80211_hw *hw,8001const uint8_t *addr, const uint8_t *ourvifaddr)8002{8003struct lkpi_hw *lhw;8004struct lkpi_vif *lvif;8005struct lkpi_sta *lsta;8006struct ieee80211_vif *vif;8007struct ieee80211_sta *sta;80088009lhw = wiphy_priv(hw->wiphy);8010sta = NULL;80118012LKPI_80211_LHW_LVIF_LOCK(lhw);8013TAILQ_FOREACH(lvif, &lhw->lvif_head, lvif_entry) {80148015/* XXX-BZ check our address from the vif. */80168017vif = LVIF_TO_VIF(lvif);8018if (ourvifaddr != NULL &&8019!IEEE80211_ADDR_EQ(vif->addr, ourvifaddr))8020continue;8021sta = linuxkpi_ieee80211_find_sta(vif, addr);8022if (sta != NULL)8023break;8024}8025LKPI_80211_LHW_LVIF_UNLOCK(lhw);80268027if (sta != NULL) {8028lsta = STA_TO_LSTA(sta);8029if (!lsta->added_to_drv)8030return (NULL);8031}80328033return (sta);8034}80358036struct sk_buff *8037linuxkpi_ieee80211_tx_dequeue(struct ieee80211_hw *hw,8038struct ieee80211_txq *txq)8039{8040struct lkpi_txq *ltxq;8041struct lkpi_vif *lvif;8042struct sk_buff *skb;80438044IMPROVE("wiphy_lock? or assert?");8045skb = NULL;8046ltxq = TXQ_TO_LTXQ(txq);8047ltxq->seen_dequeue = true;80488049if (ltxq->stopped)8050goto stopped;80518052lvif = VIF_TO_LVIF(ltxq->txq.vif);8053if (lvif->hw_queue_stopped[ltxq->txq.ac]) {8054ltxq->stopped = true;8055goto stopped;8056}80578058IMPROVE("hw(TX_FRAG_LIST)");80598060LKPI_80211_LTXQ_LOCK(ltxq);8061skb = skb_dequeue(<xq->skbq);8062LKPI_80211_LTXQ_UNLOCK(ltxq);80638064stopped:8065return (skb);8066}80678068void8069linuxkpi_ieee80211_txq_get_depth(struct ieee80211_txq *txq,8070unsigned long *frame_cnt, unsigned long *byte_cnt)8071{8072struct lkpi_txq *ltxq;8073struct sk_buff *skb;8074unsigned long fc, bc;80758076ltxq = TXQ_TO_LTXQ(txq);80778078fc = bc = 0;8079LKPI_80211_LTXQ_LOCK(ltxq);8080skb_queue_walk(<xq->skbq, skb) {8081fc++;8082bc += skb->len;8083}8084LKPI_80211_LTXQ_UNLOCK(ltxq);8085if (frame_cnt)8086*frame_cnt = fc;8087if (byte_cnt)8088*byte_cnt = bc;80898090/* Validate that this is doing the correct thing. */8091/* Should we keep track on en/dequeue? */8092IMPROVE();8093}80948095/*8096* We are called from ieee80211_free_txskb() or ieee80211_tx_status().8097* The latter tries to derive the success status from the info flags8098* passed back from the driver. rawx_mit() saves the ni on the m and the8099* m on the skb for us to be able to give feedback to net80211.8100*/8101static void8102_lkpi_ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb,8103int status)8104{8105struct ieee80211_node *ni;8106struct mbuf *m;81078108m = skb->m;8109skb->m = NULL;81108111if (m != NULL) {8112ni = m->m_pkthdr.PH_loc.ptr;8113/* Status: 0 is ok, != 0 is error. */8114ieee80211_tx_complete(ni, m, status);8115/* ni & mbuf were consumed. */8116}8117}81188119void8120linuxkpi_ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb,8121int status)8122{81238124_lkpi_ieee80211_free_txskb(hw, skb, status);8125kfree_skb(skb);8126}81278128void8129linuxkpi_ieee80211_tx_status_ext(struct ieee80211_hw *hw,8130struct ieee80211_tx_status *txstat)8131{8132struct sk_buff *skb;8133struct ieee80211_tx_info *info;8134struct ieee80211_ratectl_tx_status txs;8135struct ieee80211_node *ni;8136int status;81378138skb = txstat->skb;8139if (skb->m != NULL) {8140struct mbuf *m;81418142m = skb->m;8143ni = m->m_pkthdr.PH_loc.ptr;8144memset(&txs, 0, sizeof(txs));8145} else {8146ni = NULL;8147}81488149info = txstat->info;8150if (info->flags & IEEE80211_TX_STAT_ACK) {8151status = 0; /* No error. */8152txs.status = IEEE80211_RATECTL_TX_SUCCESS;8153} else {8154status = 1;8155txs.status = IEEE80211_RATECTL_TX_FAIL_UNSPECIFIED;8156}81578158if (ni != NULL) {8159txs.pktlen = skb->len;8160txs.flags |= IEEE80211_RATECTL_STATUS_PKTLEN;8161if (info->status.rates[0].count > 1) {8162txs.long_retries = info->status.rates[0].count - 1; /* 1 + retries in drivers. */8163txs.flags |= IEEE80211_RATECTL_STATUS_LONG_RETRY;8164}8165#if 0 /* Unused in net80211 currently. */8166/* XXX-BZ convert check .flags for MCS/VHT/.. */8167txs.final_rate = info->status.rates[0].idx;8168txs.flags |= IEEE80211_RATECTL_STATUS_FINAL_RATE;8169#endif8170if (info->status.flags & IEEE80211_TX_STATUS_ACK_SIGNAL_VALID) {8171txs.rssi = info->status.ack_signal; /* XXX-BZ CONVERT? */8172txs.flags |= IEEE80211_RATECTL_STATUS_RSSI;8173}81748175IMPROVE("only update rate if needed but that requires us to get a proper rate from mo_sta_statistics");8176ieee80211_ratectl_tx_complete(ni, &txs);8177ieee80211_ratectl_rate(ni->ni_vap->iv_bss, NULL, 0);81788179#ifdef LINUXKPI_DEBUG_802118180if (linuxkpi_debug_80211 & D80211_TRACE_TX) {8181printf("TX-RATE: %s: long_retries %d\n", __func__,8182txs.long_retries);8183}8184#endif8185}81868187#ifdef LINUXKPI_DEBUG_802118188if (linuxkpi_debug_80211 & D80211_TRACE_TX)8189printf("TX-STATUS: %s: hw %p skb %p status %d : flags %#x "8190"band %u hw_queue %u tx_time_est %d : "8191"rates [ %u %u %#x, %u %u %#x, %u %u %#x, %u %u %#x ] "8192"ack_signal %u ampdu_ack_len %u ampdu_len %u antenna %u "8193"tx_time %u flags %#x "8194"status_driver_data [ %p %p ]\n",8195__func__, hw, skb, status, info->flags,8196info->band, info->hw_queue, info->tx_time_est,8197info->status.rates[0].idx, info->status.rates[0].count,8198info->status.rates[0].flags,8199info->status.rates[1].idx, info->status.rates[1].count,8200info->status.rates[1].flags,8201info->status.rates[2].idx, info->status.rates[2].count,8202info->status.rates[2].flags,8203info->status.rates[3].idx, info->status.rates[3].count,8204info->status.rates[3].flags,8205info->status.ack_signal, info->status.ampdu_ack_len,8206info->status.ampdu_len, info->status.antenna,8207info->status.tx_time, info->status.flags,8208info->status.status_driver_data[0],8209info->status.status_driver_data[1]);8210#endif82118212if (txstat->free_list) {8213_lkpi_ieee80211_free_txskb(hw, skb, status);8214list_add_tail(&skb->list, txstat->free_list);8215} else {8216linuxkpi_ieee80211_free_txskb(hw, skb, status);8217}8218}82198220void8221linuxkpi_ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)8222{8223struct ieee80211_tx_status status;82248225memset(&status, 0, sizeof(status));8226status.info = IEEE80211_SKB_CB(skb);8227status.skb = skb;8228/* sta, n_rates, rates, free_list? */82298230ieee80211_tx_status_ext(hw, &status);8231}82328233/*8234* This is an internal bandaid for the moment for the way we glue8235* skbs and mbufs together for TX. Once we have skbs backed by8236* mbufs this should go away.8237* This is a public function but kept on the private KPI (lkpi_)8238* and is not exposed by a header file.8239*/8240static void8241lkpi_ieee80211_free_skb_mbuf(void *p)8242{8243struct ieee80211_node *ni;8244struct mbuf *m;82458246if (p == NULL)8247return;82488249m = (struct mbuf *)p;8250M_ASSERTPKTHDR(m);82518252ni = m->m_pkthdr.PH_loc.ptr;8253m->m_pkthdr.PH_loc.ptr = NULL;8254if (ni != NULL)8255ieee80211_free_node(ni);8256m_freem(m);8257}82588259void8260linuxkpi_ieee80211_queue_delayed_work(struct ieee80211_hw *hw,8261struct delayed_work *w, int delay)8262{8263struct lkpi_hw *lhw;82648265/* Need to make sure hw is in a stable (non-suspended) state. */8266IMPROVE();82678268lhw = HW_TO_LHW(hw);8269queue_delayed_work(lhw->workq, w, delay);8270}82718272void8273linuxkpi_ieee80211_queue_work(struct ieee80211_hw *hw,8274struct work_struct *w)8275{8276struct lkpi_hw *lhw;82778278/* Need to make sure hw is in a stable (non-suspended) state. */8279IMPROVE();82808281lhw = HW_TO_LHW(hw);8282queue_work(lhw->workq, w);8283}82848285struct sk_buff *8286linuxkpi_ieee80211_probereq_get(struct ieee80211_hw *hw, const uint8_t *addr,8287const uint8_t *ssid, size_t ssid_len, size_t tailroom)8288{8289struct sk_buff *skb;8290struct ieee80211_frame *wh;8291uint8_t *p;8292size_t len;82938294len = sizeof(*wh);8295len += 2 + ssid_len;82968297skb = dev_alloc_skb(hw->extra_tx_headroom + len + tailroom);8298if (skb == NULL)8299return (NULL);83008301skb_reserve(skb, hw->extra_tx_headroom);83028303wh = skb_put_zero(skb, sizeof(*wh));8304wh->i_fc[0] = IEEE80211_FC0_VERSION_0;8305wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_PROBE_REQ | IEEE80211_FC0_TYPE_MGT;8306IEEE80211_ADDR_COPY(wh->i_addr1, ieee80211broadcastaddr);8307IEEE80211_ADDR_COPY(wh->i_addr2, addr);8308IEEE80211_ADDR_COPY(wh->i_addr3, ieee80211broadcastaddr);83098310p = skb_put(skb, 2 + ssid_len);8311*p++ = IEEE80211_ELEMID_SSID;8312*p++ = ssid_len;8313if (ssid_len > 0)8314memcpy(p, ssid, ssid_len);83158316return (skb);8317}83188319struct sk_buff *8320linuxkpi_ieee80211_pspoll_get(struct ieee80211_hw *hw,8321struct ieee80211_vif *vif)8322{8323struct lkpi_vif *lvif;8324struct ieee80211vap *vap;8325struct sk_buff *skb;8326struct ieee80211_frame_pspoll *psp;8327uint16_t v;83288329skb = dev_alloc_skb(hw->extra_tx_headroom + sizeof(*psp));8330if (skb == NULL)8331return (NULL);83328333skb_reserve(skb, hw->extra_tx_headroom);83348335lvif = VIF_TO_LVIF(vif);8336vap = LVIF_TO_VAP(lvif);83378338psp = skb_put_zero(skb, sizeof(*psp));8339psp->i_fc[0] = IEEE80211_FC0_VERSION_0;8340psp->i_fc[0] |= IEEE80211_FC0_SUBTYPE_PS_POLL | IEEE80211_FC0_TYPE_CTL;8341v = htole16(vif->cfg.aid | 1<<15 | 1<<16);8342memcpy(&psp->i_aid, &v, sizeof(v));8343IEEE80211_ADDR_COPY(psp->i_bssid, vap->iv_bss->ni_macaddr);8344IEEE80211_ADDR_COPY(psp->i_ta, vif->addr);83458346return (skb);8347}83488349struct sk_buff *8350linuxkpi_ieee80211_nullfunc_get(struct ieee80211_hw *hw,8351struct ieee80211_vif *vif, int linkid, bool qos)8352{8353struct lkpi_vif *lvif;8354struct ieee80211vap *vap;8355struct sk_buff *skb;8356struct ieee80211_frame *nullf;83578358IMPROVE("linkid");83598360skb = dev_alloc_skb(hw->extra_tx_headroom + sizeof(*nullf));8361if (skb == NULL)8362return (NULL);83638364skb_reserve(skb, hw->extra_tx_headroom);83658366lvif = VIF_TO_LVIF(vif);8367vap = LVIF_TO_VAP(lvif);83688369nullf = skb_put_zero(skb, sizeof(*nullf));8370nullf->i_fc[0] = IEEE80211_FC0_VERSION_0;8371nullf->i_fc[0] |= IEEE80211_FC0_SUBTYPE_NODATA | IEEE80211_FC0_TYPE_DATA;8372nullf->i_fc[1] = IEEE80211_FC1_DIR_TODS;83738374IEEE80211_ADDR_COPY(nullf->i_addr1, vap->iv_bss->ni_bssid);8375IEEE80211_ADDR_COPY(nullf->i_addr2, vif->addr);8376IEEE80211_ADDR_COPY(nullf->i_addr3, vap->iv_bss->ni_macaddr);83778378return (skb);8379}83808381struct wireless_dev *8382linuxkpi_ieee80211_vif_to_wdev(struct ieee80211_vif *vif)8383{8384struct lkpi_vif *lvif;83858386lvif = VIF_TO_LVIF(vif);8387return (&lvif->wdev);8388}83898390void8391linuxkpi_ieee80211_connection_loss(struct ieee80211_vif *vif)8392{8393struct lkpi_vif *lvif;8394struct ieee80211vap *vap;8395enum ieee80211_state nstate;8396int arg;83978398lvif = VIF_TO_LVIF(vif);8399vap = LVIF_TO_VAP(lvif);84008401/*8402* Go to init; otherwise we need to elaborately check state and8403* handle accordingly, e.g., if in RUN we could call iv_bmiss.8404* Let the statemachine handle all neccessary changes.8405*/8406nstate = IEEE80211_S_INIT;8407arg = 0; /* Not a valid reason. */84088409ic_printf(vap->iv_ic, "%s: vif %p vap %p state %s (synched %d, assoc %d "8410"beacons %d dtim_period %d)\n", __func__, vif, vap,8411ieee80211_state_name[vap->iv_state],8412lvif->lvif_bss_synched, vif->cfg.assoc, lvif->beacons,8413vif->bss_conf.dtim_period);8414ieee80211_new_state(vap, nstate, arg);8415}84168417void8418linuxkpi_ieee80211_beacon_loss(struct ieee80211_vif *vif)8419{8420struct lkpi_vif *lvif;8421struct ieee80211vap *vap;84228423lvif = VIF_TO_LVIF(vif);8424vap = LVIF_TO_VAP(lvif);84258426ic_printf(vap->iv_ic, "%s: vif %p vap %p state %s (synched %d, assoc %d "8427"beacons %d dtim_period %d)\n", __func__, vif, vap,8428ieee80211_state_name[vap->iv_state],8429lvif->lvif_bss_synched, vif->cfg.assoc, lvif->beacons,8430vif->bss_conf.dtim_period);8431ieee80211_beacon_miss(vap->iv_ic);8432}84338434/* -------------------------------------------------------------------------- */84358436void8437linuxkpi_ieee80211_stop_queue(struct ieee80211_hw *hw, int qnum)8438{8439struct lkpi_hw *lhw;8440struct lkpi_vif *lvif;8441struct ieee80211_vif *vif;8442int ac_count, ac;84438444KASSERT(qnum < hw->queues, ("%s: qnum %d >= hw->queues %d, hw %p\n",8445__func__, qnum, hw->queues, hw));84468447lhw = wiphy_priv(hw->wiphy);84488449/* See lkpi_ic_vap_create(). */8450if (hw->queues >= IEEE80211_NUM_ACS)8451ac_count = IEEE80211_NUM_ACS;8452else8453ac_count = 1;84548455LKPI_80211_LHW_LVIF_LOCK(lhw);8456TAILQ_FOREACH(lvif, &lhw->lvif_head, lvif_entry) {84578458vif = LVIF_TO_VIF(lvif);8459for (ac = 0; ac < ac_count; ac++) {8460IMPROVE_TXQ("LOCKING");8461if (qnum == vif->hw_queue[ac]) {8462#ifdef LINUXKPI_DEBUG_802118463/*8464* For now log this to better understand8465* how this is supposed to work.8466*/8467if (lvif->hw_queue_stopped[ac] &&8468(linuxkpi_debug_80211 & D80211_IMPROVE_TXQ) != 0)8469ic_printf(lhw->ic, "%s:%d: lhw %p hw %p "8470"lvif %p vif %p ac %d qnum %d already "8471"stopped\n", __func__, __LINE__,8472lhw, hw, lvif, vif, ac, qnum);8473#endif8474lvif->hw_queue_stopped[ac] = true;8475}8476}8477}8478LKPI_80211_LHW_LVIF_UNLOCK(lhw);8479}84808481void8482linuxkpi_ieee80211_stop_queues(struct ieee80211_hw *hw)8483{8484int i;84858486IMPROVE_TXQ("Locking; do we need further info?");8487for (i = 0; i < hw->queues; i++)8488linuxkpi_ieee80211_stop_queue(hw, i);8489}849084918492static void8493lkpi_ieee80211_wake_queues(struct ieee80211_hw *hw, int hwq)8494{8495struct lkpi_hw *lhw;8496struct lkpi_vif *lvif;8497struct lkpi_sta *lsta;8498int ac_count, ac, tid;84998500/* See lkpi_ic_vap_create(). */8501if (hw->queues >= IEEE80211_NUM_ACS)8502ac_count = IEEE80211_NUM_ACS;8503else8504ac_count = 1;85058506lhw = wiphy_priv(hw->wiphy);85078508IMPROVE_TXQ("Locking");8509LKPI_80211_LHW_LVIF_LOCK(lhw);8510TAILQ_FOREACH(lvif, &lhw->lvif_head, lvif_entry) {8511struct ieee80211_vif *vif;85128513vif = LVIF_TO_VIF(lvif);8514for (ac = 0; ac < ac_count; ac++) {85158516if (hwq == vif->hw_queue[ac]) {85178518/* XXX-BZ what about software scan? */85198520#ifdef LINUXKPI_DEBUG_802118521/*8522* For now log this to better understand8523* how this is supposed to work.8524*/8525if (!lvif->hw_queue_stopped[ac] &&8526(linuxkpi_debug_80211 & D80211_IMPROVE_TXQ) != 0)8527ic_printf(lhw->ic, "%s:%d: lhw %p hw %p "8528"lvif %p vif %p ac %d hw_q not stopped\n",8529__func__, __LINE__,8530lhw, hw, lvif, vif, ac);8531#endif8532lvif->hw_queue_stopped[ac] = false;85338534rcu_read_lock();8535list_for_each_entry_rcu(lsta, &lvif->lsta_list, lsta_list) {8536struct ieee80211_sta *sta;85378538sta = LSTA_TO_STA(lsta);8539for (tid = 0; tid < nitems(sta->txq); tid++) {8540struct lkpi_txq *ltxq;85418542if (sta->txq[tid] == NULL)8543continue;85448545if (sta->txq[tid]->ac != ac)8546continue;85478548ltxq = TXQ_TO_LTXQ(sta->txq[tid]);8549if (!ltxq->stopped)8550continue;85518552ltxq->stopped = false;85538554if (!skb_queue_empty(<xq->skbq))8555lkpi_80211_mo_wake_tx_queue(hw, sta->txq[tid]);8556}8557}8558rcu_read_unlock();8559}8560}8561}8562LKPI_80211_LHW_LVIF_UNLOCK(lhw);8563}85648565static void8566lkpi_ieee80211_wake_queues_locked(struct ieee80211_hw *hw)8567{8568int i;85698570IMPROVE_TXQ("Is this all/enough here?");8571for (i = 0; i < hw->queues; i++)8572lkpi_ieee80211_wake_queues(hw, i);8573}85748575void8576linuxkpi_ieee80211_wake_queues(struct ieee80211_hw *hw)8577{8578struct lkpi_hw *lhw;8579unsigned long flags;85808581lhw = HW_TO_LHW(hw);85828583spin_lock_irqsave(&lhw->txq_lock, flags);8584lkpi_ieee80211_wake_queues_locked(hw);8585spin_unlock_irqrestore(&lhw->txq_lock, flags);8586}85878588void8589linuxkpi_ieee80211_wake_queue(struct ieee80211_hw *hw, int qnum)8590{8591struct lkpi_hw *lhw;8592unsigned long flags;85938594KASSERT(qnum < hw->queues, ("%s: qnum %d >= hw->queues %d, hw %p\n",8595__func__, qnum, hw->queues, hw));85968597lhw = HW_TO_LHW(hw);85988599spin_lock_irqsave(&lhw->txq_lock, flags);8600lkpi_ieee80211_wake_queues(hw, qnum);8601spin_unlock_irqrestore(&lhw->txq_lock, flags);8602}86038604/* This is just hardware queues. */8605void8606linuxkpi_ieee80211_txq_schedule_start(struct ieee80211_hw *hw, uint8_t ac)8607{8608struct lkpi_hw *lhw;86098610lhw = HW_TO_LHW(hw);86118612IMPROVE_TXQ("Are there reasons why we wouldn't schedule?");8613IMPROVE_TXQ("LOCKING");8614if (++lhw->txq_generation[ac] == 0)8615lhw->txq_generation[ac]++;8616}86178618struct ieee80211_txq *8619linuxkpi_ieee80211_next_txq(struct ieee80211_hw *hw, uint8_t ac)8620{8621struct lkpi_hw *lhw;8622struct ieee80211_txq *txq;8623struct lkpi_txq *ltxq;86248625lhw = HW_TO_LHW(hw);8626txq = NULL;86278628IMPROVE_TXQ("LOCKING");86298630/* Check that we are scheduled. */8631if (lhw->txq_generation[ac] == 0)8632goto out;86338634ltxq = TAILQ_FIRST(&lhw->scheduled_txqs[ac]);8635if (ltxq == NULL)8636goto out;8637if (ltxq->txq_generation == lhw->txq_generation[ac])8638goto out;86398640ltxq->txq_generation = lhw->txq_generation[ac];8641TAILQ_REMOVE(&lhw->scheduled_txqs[ac], ltxq, txq_entry);8642txq = <xq->txq;8643TAILQ_ELEM_INIT(ltxq, txq_entry);86448645out:8646return (txq);8647}86488649void linuxkpi_ieee80211_schedule_txq(struct ieee80211_hw *hw,8650struct ieee80211_txq *txq, bool withoutpkts)8651{8652struct lkpi_hw *lhw;8653struct lkpi_txq *ltxq;8654bool ltxq_empty;86558656ltxq = TXQ_TO_LTXQ(txq);86578658IMPROVE_TXQ("LOCKING");86598660/* Only schedule if work to do or asked to anyway. */8661LKPI_80211_LTXQ_LOCK(ltxq);8662ltxq_empty = skb_queue_empty(<xq->skbq);8663LKPI_80211_LTXQ_UNLOCK(ltxq);8664if (!withoutpkts && ltxq_empty)8665goto out;86668667/*8668* Make sure we do not double-schedule. We do this by checking tqe_prev,8669* the previous entry in our tailq. tqe_prev is always valid if this entry8670* is queued, tqe_next may be NULL if this is the only element in the list.8671*/8672if (ltxq->txq_entry.tqe_prev != NULL)8673goto out;86748675lhw = HW_TO_LHW(hw);8676TAILQ_INSERT_TAIL(&lhw->scheduled_txqs[txq->ac], ltxq, txq_entry);8677out:8678return;8679}86808681void8682linuxkpi_ieee80211_handle_wake_tx_queue(struct ieee80211_hw *hw,8683struct ieee80211_txq *txq)8684{8685struct lkpi_hw *lhw;8686struct ieee80211_txq *ntxq;8687struct ieee80211_tx_control control;8688struct sk_buff *skb;86898690lhw = HW_TO_LHW(hw);86918692LKPI_80211_LHW_TXQ_LOCK(lhw);8693ieee80211_txq_schedule_start(hw, txq->ac);8694do {8695ntxq = ieee80211_next_txq(hw, txq->ac);8696if (ntxq == NULL)8697break;86988699memset(&control, 0, sizeof(control));8700control.sta = ntxq->sta;8701do {8702skb = linuxkpi_ieee80211_tx_dequeue(hw, ntxq);8703if (skb == NULL)8704break;8705lkpi_80211_mo_tx(hw, &control, skb);8706} while(1);87078708ieee80211_return_txq(hw, ntxq, false);8709} while (1);8710ieee80211_txq_schedule_end(hw, txq->ac);8711LKPI_80211_LHW_TXQ_UNLOCK(lhw);8712}87138714/* -------------------------------------------------------------------------- */87158716struct lkpi_cfg80211_bss {8717u_int refcnt;8718struct cfg80211_bss bss;8719};87208721struct lkpi_cfg80211_get_bss_iter_lookup {8722struct wiphy *wiphy;8723struct linuxkpi_ieee80211_channel *chan;8724const uint8_t *bssid;8725const uint8_t *ssid;8726size_t ssid_len;8727enum ieee80211_bss_type bss_type;8728enum ieee80211_privacy privacy;87298730/*8731* Something to store a copy of the result as the net80211 scan cache8732* is not refoucnted so a scan entry might go away any time.8733*/8734bool match;8735struct cfg80211_bss *bss;8736};87378738static void8739lkpi_cfg80211_get_bss_iterf(void *arg, const struct ieee80211_scan_entry *se)8740{8741struct lkpi_cfg80211_get_bss_iter_lookup *lookup;8742size_t ielen;87438744lookup = arg;87458746/* Do not try to find another match. */8747if (lookup->match)8748return;87498750/* Nothing to store result. */8751if (lookup->bss == NULL)8752return;87538754if (lookup->privacy != IEEE80211_PRIVACY_ANY) {8755/* if (se->se_capinfo & IEEE80211_CAPINFO_PRIVACY) */8756/* We have no idea what to compare to as the drivers only request ANY */8757return;8758}87598760if (lookup->bss_type != IEEE80211_BSS_TYPE_ANY) {8761/* if (se->se_capinfo & (IEEE80211_CAPINFO_IBSS|IEEE80211_CAPINFO_ESS)) */8762/* We have no idea what to compare to as the drivers only request ANY */8763return;8764}87658766if (lookup->chan != NULL) {8767struct linuxkpi_ieee80211_channel *chan;87688769chan = linuxkpi_ieee80211_get_channel(lookup->wiphy,8770se->se_chan->ic_freq);8771if (chan == NULL || chan != lookup->chan)8772return;8773}87748775if (lookup->bssid && !IEEE80211_ADDR_EQ(lookup->bssid, se->se_bssid))8776return;87778778if (lookup->ssid) {8779if (lookup->ssid_len != se->se_ssid[1] ||8780se->se_ssid[1] == 0)8781return;8782if (memcmp(lookup->ssid, se->se_ssid+2, lookup->ssid_len) != 0)8783return;8784}87858786ielen = se->se_ies.len;87878788lookup->bss->ies = malloc(sizeof(*lookup->bss->ies) + ielen,8789M_LKPI80211, M_NOWAIT | M_ZERO);8790if (lookup->bss->ies == NULL)8791return;87928793lookup->bss->ies->data = (uint8_t *)lookup->bss->ies + sizeof(*lookup->bss->ies);8794lookup->bss->ies->len = ielen;8795if (ielen)8796memcpy(lookup->bss->ies->data, se->se_ies.data, ielen);87978798lookup->match = true;8799}88008801struct cfg80211_bss *8802linuxkpi_cfg80211_get_bss(struct wiphy *wiphy, struct linuxkpi_ieee80211_channel *chan,8803const uint8_t *bssid, const uint8_t *ssid, size_t ssid_len,8804enum ieee80211_bss_type bss_type, enum ieee80211_privacy privacy)8805{8806struct lkpi_cfg80211_bss *lbss;8807struct lkpi_cfg80211_get_bss_iter_lookup lookup;8808struct lkpi_hw *lhw;8809struct ieee80211vap *vap;88108811lhw = wiphy_priv(wiphy);88128813/* Let's hope we can alloc. */8814lbss = malloc(sizeof(*lbss), M_LKPI80211, M_NOWAIT | M_ZERO);8815if (lbss == NULL) {8816ic_printf(lhw->ic, "%s: alloc failed.\n", __func__);8817return (NULL);8818}88198820lookup.wiphy = wiphy;8821lookup.chan = chan;8822lookup.bssid = bssid;8823lookup.ssid = ssid;8824lookup.ssid_len = ssid_len;8825lookup.bss_type = bss_type;8826lookup.privacy = privacy;8827lookup.match = false;8828lookup.bss = &lbss->bss;88298830IMPROVE("Iterate over all VAPs comparing perm_addr and addresses?");8831vap = TAILQ_FIRST(&lhw->ic->ic_vaps);8832ieee80211_scan_iterate(vap, lkpi_cfg80211_get_bss_iterf, &lookup);8833if (!lookup.match) {8834free(lbss, M_LKPI80211);8835return (NULL);8836}88378838refcount_init(&lbss->refcnt, 1);8839return (&lbss->bss);8840}88418842void8843linuxkpi_cfg80211_put_bss(struct wiphy *wiphy, struct cfg80211_bss *bss)8844{8845struct lkpi_cfg80211_bss *lbss;88468847lbss = container_of(bss, struct lkpi_cfg80211_bss, bss);88488849/* Free everything again on refcount ... */8850if (refcount_release(&lbss->refcnt)) {8851free(lbss->bss.ies, M_LKPI80211);8852free(lbss, M_LKPI80211);8853}8854}88558856void8857linuxkpi_cfg80211_bss_flush(struct wiphy *wiphy)8858{8859struct lkpi_hw *lhw;8860struct ieee80211com *ic;8861struct ieee80211vap *vap;88628863lhw = wiphy_priv(wiphy);8864ic = lhw->ic;88658866/*8867* If we haven't called ieee80211_ifattach() yet8868* or there is no VAP, there are no scans to flush.8869*/8870if (ic == NULL ||8871(lhw->sc_flags & LKPI_MAC80211_DRV_STARTED) == 0)8872return;88738874/* Should only happen on the current one? Not seen it late enough. */8875IEEE80211_LOCK(ic);8876TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)8877ieee80211_scan_flush(vap);8878IEEE80211_UNLOCK(ic);8879}88808881/* -------------------------------------------------------------------------- */88828883/*8884* hw->conf get initialized/set in various places for us:8885* - linuxkpi_ieee80211_alloc_hw(): flags8886* - linuxkpi_ieee80211_ifattach(): chandef8887* - lkpi_ic_vap_create(): listen_interval8888* - lkpi_ic_set_channel(): chandef, flags8889*/88908891int lkpi_80211_update_chandef(struct ieee80211_hw *hw,8892struct ieee80211_chanctx_conf *new)8893{8894struct cfg80211_chan_def *cd;8895uint32_t changed;8896int error;88978898changed = 0;8899if (new == NULL || new->def.chan == NULL)8900cd = NULL;8901else8902cd = &new->def;89038904if (cd && cd->chan != hw->conf.chandef.chan) {8905/* Copy; the chan pointer is fine and will stay valid. */8906hw->conf.chandef = *cd;8907changed |= IEEE80211_CONF_CHANGE_CHANNEL;8908}8909IMPROVE("IEEE80211_CONF_CHANGE_PS, IEEE80211_CONF_CHANGE_POWER");89108911if (changed == 0)8912return (0);89138914error = lkpi_80211_mo_config(hw, changed);8915return (error);8916}89178918/* -------------------------------------------------------------------------- */89198920MODULE_VERSION(linuxkpi_wlan, 1);8921MODULE_DEPEND(linuxkpi_wlan, linuxkpi, 1, 1, 1);8922MODULE_DEPEND(linuxkpi_wlan, wlan, 1, 1, 1);892389248925