Path: blob/main/sys/compat/linuxkpi/common/src/linux_80211.c
101167 views
/*-1* Copyright (c) 2020-2026 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(_fmt, ...) if (linuxkpi_debug_80211 & D80211_TRACEOK) \131printf("%s:%d: TRACEPOINT " _fmt "\n", __func__, __LINE__, ##__VA_ARGS__)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, bool dump_queues)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;294uint8_t tid;295296vif = LVIF_TO_VIF(lvif);297vap = LVIF_TO_VAP(lvif);298lhw = vap->iv_ic->ic_softc;299hw = LHW_TO_HW(lhw);300301wiphy_lock(hw->wiphy);302list_for_each_entry(lsta, &lvif->lsta_list, lsta_list) {303sta = LSTA_TO_STA(lsta);304305sbuf_putc(s, '\n');306sbuf_printf(s, "lsta %p sta %p added_to_drv %d\n", lsta, sta, lsta->added_to_drv);307308memset(&sinfo, 0, sizeof(sinfo));309error = lkpi_80211_mo_sta_statistics(hw, vif, sta, &sinfo);310if (error == EEXIST) /* Not added to driver. */311continue;312if (error == ENOTSUPP) {313sbuf_printf(s, " sta_statistics not supported\n");314continue;315}316if (error != 0) {317sbuf_printf(s, " sta_statistics failed: %d\n", error);318continue;319}320321/* If no RX_BITRATE is reported, try to fill it in from the lsta sinfo. */322if ((sinfo.filled & BIT_ULL(NL80211_STA_INFO_RX_BITRATE)) == 0 &&323(lsta->sinfo.filled & BIT_ULL(NL80211_STA_INFO_RX_BITRATE)) != 0) {324memcpy(&sinfo.rxrate, &lsta->sinfo.rxrate, sizeof(sinfo.rxrate));325sinfo.filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE);326}327/* If no CHAIN_SIGNAL is reported, try to fill it in from the lsta sinfo. */328if ((sinfo.filled & BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL)) == 0 &&329(lsta->sinfo.filled & BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL)) != 0) {330sinfo.chains = lsta->sinfo.chains;331memcpy(sinfo.chain_signal, lsta->sinfo.chain_signal,332sizeof(sinfo.chain_signal));333sinfo.filled |= BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL);334}335336lkpi_nl80211_sta_info_to_str(s, " nl80211_sta_info (valid fields)", sinfo.filled);337sbuf_printf(s, " connected_time %u inactive_time %u\n",338sinfo.connected_time, sinfo.inactive_time);339sbuf_printf(s, " rx_bytes %ju rx_packets %u rx_dropped_misc %u\n",340(uintmax_t)sinfo.rx_bytes, sinfo.rx_packets, sinfo.rx_dropped_misc);341sbuf_printf(s, " rx_duration %ju rx_beacon %u rx_beacon_signal_avg %d\n",342(uintmax_t)sinfo.rx_duration, sinfo.rx_beacon, (int8_t)sinfo.rx_beacon_signal_avg);343344sbuf_printf(s, " tx_bytes %ju tx_packets %u tx_failed %u\n",345(uintmax_t)sinfo.tx_bytes, sinfo.tx_packets, sinfo.tx_failed);346sbuf_printf(s, " tx_duration %ju tx_retries %u\n",347(uintmax_t)sinfo.tx_duration, sinfo.tx_retries);348349sbuf_printf(s, " signal %d signal_avg %d ack_signal %d avg_ack_signal %d\n",350sinfo.signal, sinfo.signal_avg, sinfo.ack_signal, sinfo.avg_ack_signal);351sbuf_printf(s, " generation %d assoc_req_ies_len %zu chains %#04x\n",352sinfo.generation, sinfo.assoc_req_ies_len, sinfo.chains);353354for (int i = 0; i < nitems(sinfo.chain_signal) && i < IEEE80211_MAX_CHAINS; i++) {355if (!(sinfo.chains & BIT(i)))356continue;357sbuf_printf(s, " chain[%d] signal %d signal_avg %d\n",358i, (int8_t)sinfo.chain_signal[i], (int8_t)sinfo.chain_signal_avg[i]);359}360361/* assoc_req_ies, bss_param, sta_flags */362363sbuf_printf(s, " rxrate: flags %b bw %u(%s) legacy %u kbit/s mcs %u nss %u\n",364sinfo.rxrate.flags, CFG80211_RATE_INFO_FLAGS_BITS,365sinfo.rxrate.bw, lkpi_rate_info_bw_to_str(sinfo.rxrate.bw),366sinfo.rxrate.legacy * 100,367sinfo.rxrate.mcs, sinfo.rxrate.nss);368sbuf_printf(s, " he_dcm %u he_gi %u he_ru_alloc %u eht_gi %u\n",369sinfo.rxrate.he_dcm, sinfo.rxrate.he_gi, sinfo.rxrate.he_ru_alloc,370sinfo.rxrate.eht_gi);371sbuf_printf(s, " txrate: flags %b bw %u(%s) legacy %u kbit/s mcs %u nss %u\n",372sinfo.txrate.flags, CFG80211_RATE_INFO_FLAGS_BITS,373sinfo.txrate.bw, lkpi_rate_info_bw_to_str(sinfo.txrate.bw),374sinfo.txrate.legacy * 100,375sinfo.txrate.mcs, sinfo.txrate.nss);376sbuf_printf(s, " he_dcm %u he_gi %u he_ru_alloc %u eht_gi %u\n",377sinfo.txrate.he_dcm, sinfo.txrate.he_gi, sinfo.txrate.he_ru_alloc,378sinfo.txrate.eht_gi);379380if (!dump_queues)381continue;382383/* Dump queue information. */384sbuf_printf(s, " Queue information:\n");385sbuf_printf(s, " frms direct tx %ju\n", lsta->frms_tx);386for (tid = 0; tid <= IEEE80211_NUM_TIDS; tid++) {387struct lkpi_txq *ltxq;388389if (sta->txq[tid] == NULL) {390sbuf_printf(s, " tid %-2u NOQ\n", tid);391continue;392}393394ltxq = TXQ_TO_LTXQ(sta->txq[tid]);395#ifdef __notyet__396sbuf_printf(s, " tid %-2u flags: %b "397"txq_generation %u skbq len %d\n",398tid, ltxq->flags, LKPI_TXQ_FLAGS_BITS,399ltxq->txq_generation,400skb_queue_len_lockless(<xq->skbq));401#else402sbuf_printf(s, " tid %-2u "403"txq_generation %u skbq len %d\n",404tid,405ltxq->txq_generation,406skb_queue_len_lockless(<xq->skbq));407#endif408sbuf_printf(s, " frms_enqueued %ju frms_dequeued %ju "409"frms_tx %ju\n",410ltxq->frms_enqueued, ltxq->frms_dequeued, ltxq->frms_tx);411}412}413wiphy_unlock(hw->wiphy);414}415416static int417lkpi_80211_dump_stas(SYSCTL_HANDLER_ARGS)418{419struct lkpi_vif *lvif;420struct sbuf s;421422if (req->newptr)423return (EPERM);424425lvif = (struct lkpi_vif *)arg1;426427sbuf_new_for_sysctl(&s, NULL, 1024, req);428429lkpi_80211_dump_lvif_stas(lvif, &s, false);430431sbuf_finish(&s);432sbuf_delete(&s);433434return (0);435}436437static int438lkpi_80211_dump_sta_queues(SYSCTL_HANDLER_ARGS)439{440struct lkpi_vif *lvif;441struct sbuf s;442443if (req->newptr)444return (EPERM);445446lvif = (struct lkpi_vif *)arg1;447448sbuf_new_for_sysctl(&s, NULL, 1024, req);449450lkpi_80211_dump_lvif_stas(lvif, &s, true);451452sbuf_finish(&s);453sbuf_delete(&s);454455return (0);456}457458static enum ieee80211_sta_rx_bandwidth459lkpi_cw_to_rx_bw(enum nl80211_chan_width cw)460{461switch (cw) {462case NL80211_CHAN_WIDTH_320:463return (IEEE80211_STA_RX_BW_320);464case NL80211_CHAN_WIDTH_160:465case NL80211_CHAN_WIDTH_80P80:466return (IEEE80211_STA_RX_BW_160);467case NL80211_CHAN_WIDTH_80:468return (IEEE80211_STA_RX_BW_80);469case NL80211_CHAN_WIDTH_40:470return (IEEE80211_STA_RX_BW_40);471case NL80211_CHAN_WIDTH_20:472case NL80211_CHAN_WIDTH_20_NOHT:473return (IEEE80211_STA_RX_BW_20);474case NL80211_CHAN_WIDTH_5:475case NL80211_CHAN_WIDTH_10:476/* Unsupported input. */477return (IEEE80211_STA_RX_BW_20);478}479}480481static enum nl80211_chan_width482lkpi_rx_bw_to_cw(enum ieee80211_sta_rx_bandwidth rx_bw)483{484switch (rx_bw) {485case IEEE80211_STA_RX_BW_20:486return (NL80211_CHAN_WIDTH_20); /* _NOHT */487case IEEE80211_STA_RX_BW_40:488return (NL80211_CHAN_WIDTH_40);489case IEEE80211_STA_RX_BW_80:490return (NL80211_CHAN_WIDTH_80);491case IEEE80211_STA_RX_BW_160:492return (NL80211_CHAN_WIDTH_160); /* 80P80 */493case IEEE80211_STA_RX_BW_320:494return (NL80211_CHAN_WIDTH_320);495}496}497498static void499lkpi_sync_chanctx_cw_from_rx_bw(struct ieee80211_hw *hw,500struct ieee80211_vif *vif, struct ieee80211_sta *sta)501{502struct ieee80211_chanctx_conf *chanctx_conf;503enum ieee80211_sta_rx_bandwidth old_bw;504uint32_t changed;505506chanctx_conf = rcu_dereference_protected(vif->bss_conf.chanctx_conf,507lockdep_is_held(&hw->wiphy->mtx));508if (chanctx_conf == NULL)509return;510511old_bw = lkpi_cw_to_rx_bw(chanctx_conf->def.width);512if (old_bw == sta->deflink.bandwidth)513return;514515chanctx_conf->def.width = lkpi_rx_bw_to_cw(sta->deflink.bandwidth);516if (chanctx_conf->def.width == NL80211_CHAN_WIDTH_20 &&517!sta->deflink.ht_cap.ht_supported)518chanctx_conf->def.width = NL80211_CHAN_WIDTH_20_NOHT;519520chanctx_conf->min_def = chanctx_conf->def;521522vif->bss_conf.chanreq.oper.width = chanctx_conf->def.width;523524changed = IEEE80211_CHANCTX_CHANGE_MIN_WIDTH;525changed |= IEEE80211_CHANCTX_CHANGE_WIDTH;526lkpi_80211_mo_change_chanctx(hw, chanctx_conf, changed);527}528529#if defined(LKPI_80211_HT)530static void531lkpi_sta_sync_ht_from_ni(struct ieee80211_hw *hw, struct ieee80211_vif *vif,532struct ieee80211_sta *sta, struct ieee80211_node *ni)533{534struct ieee80211vap *vap;535uint8_t *ie;536struct ieee80211_ht_cap *htcap;537struct ieee80211_sta_ht_cap *ht_cap, *sta_ht_cap;538enum nl80211_band band;539int i, rx_nss;540541if ((ni->ni_flags & IEEE80211_NODE_HT) == 0) {542sta->deflink.ht_cap.ht_supported = false;543return;544}545546sta->deflink.ht_cap.ht_supported = true;547548/* htcap->ampdu_params_info */549vap = ni->ni_vap;550sta->deflink.ht_cap.ampdu_density = _IEEE80211_MASKSHIFT(ni->ni_htparam, IEEE80211_HTCAP_MPDUDENSITY);551if (sta->deflink.ht_cap.ampdu_density > vap->iv_ampdu_density)552sta->deflink.ht_cap.ampdu_density = vap->iv_ampdu_density;553sta->deflink.ht_cap.ampdu_factor = _IEEE80211_MASKSHIFT(ni->ni_htparam, IEEE80211_HTCAP_MAXRXAMPDU);554if (sta->deflink.ht_cap.ampdu_factor > vap->iv_ampdu_rxmax)555sta->deflink.ht_cap.ampdu_factor = vap->iv_ampdu_rxmax;556557ie = ni->ni_ies.htcap_ie;558KASSERT(ie != NULL, ("%s: HT but no htcap_ie on ni %p\n", __func__, ni));559if (ie[0] == IEEE80211_ELEMID_VENDOR)560ie += 4;561ie += 2;562htcap = (struct ieee80211_ht_cap *)ie;563sta->deflink.ht_cap.cap = htcap->cap_info;564sta->deflink.ht_cap.mcs = htcap->mcs;565566/*567* 802.11n-2009 20.6 Parameters for HT MCSs gives the mandatory/568* optional MCS for Nss=1..4. We need to check the first four569* MCS sets from the Rx MCS Bitmask; then there is MCS 32 and570* MCS33.. is UEQM.571*/572band = vif->bss_conf.chanctx_conf->def.chan->band;573ht_cap = &hw->wiphy->bands[band]->ht_cap;574sta_ht_cap = &sta->deflink.ht_cap;575rx_nss = 0;576for (i = 0; i < 4; i++) {577TRACEOK("HT rx_mask[%d] sta %#04x & hw %#04x", i,578sta_ht_cap->mcs.rx_mask[i], ht_cap->mcs.rx_mask[i]);579sta_ht_cap->mcs.rx_mask[i] =580sta_ht_cap->mcs.rx_mask[i] & ht_cap->mcs.rx_mask[i];581/* XXX-BZ masking unequal modulation? */582583if (sta_ht_cap->mcs.rx_mask[i] != 0)584rx_nss++;585}586if (rx_nss > 0) {587TRACEOK("HT rx_nss = max(%d, %d)", rx_nss, sta->deflink.rx_nss);588sta->deflink.rx_nss = MAX(rx_nss, sta->deflink.rx_nss);589} else {590sta->deflink.ht_cap.ht_supported = false;591return;592}593594if ((sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) != 0 &&595IEEE80211_IS_CHAN_HT40(ni->ni_chan))596sta->deflink.bandwidth = IEEE80211_STA_RX_BW_40;597else598sta->deflink.bandwidth = IEEE80211_STA_RX_BW_20;599600IMPROVE("sta->wme");601602if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_MAX_AMSDU)603sta->deflink.agg.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_HT_7935;604else605sta->deflink.agg.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_HT_3839;606sta->deflink.agg.max_rc_amsdu_len = IEEE80211_MAX_MPDU_LEN_HT_BA;607#ifdef __handled_by_driver__ /* iwlwifi only? actually unused? */608for (i = 0; i < nitems(sta.deflink.agg.max_tid_amsdu_len); i++) {609sta->deflink.agg.max_tid_amsdu_len[j] = ;610}611#endif612}613#endif614615#if defined(LKPI_80211_VHT)616static void617lkpi_sta_sync_vht_from_ni(struct ieee80211_hw *hw, struct ieee80211_vif *vif,618struct ieee80211_sta *sta, struct ieee80211_node *ni)619{620struct ieee80211_sta_vht_cap *vht_cap, *sta_vht_cap;;621enum ieee80211_sta_rx_bandwidth bw;622enum nl80211_band band;623uint32_t width;624int rx_nss;625uint16_t rx_map, tx_map;626627if ((ni->ni_flags & IEEE80211_NODE_VHT) == 0 ||628!IEEE80211_IS_CHAN_VHT_5GHZ(ni->ni_chan)) {629sta->deflink.vht_cap.vht_supported = false;630return;631}632633sta->deflink.vht_cap.vht_supported = true;634635sta->deflink.vht_cap.cap = ni->ni_vhtcap;636sta->deflink.vht_cap.vht_mcs = ni->ni_vht_mcsinfo;637638/*639* If VHT20/40 are selected do not update the bandwidth640* from HT but stya on VHT.641*/642if (ni->ni_vht_chanwidth == IEEE80211_VHT_CHANWIDTH_USE_HT)643goto skip_bw;644645bw = sta->deflink.bandwidth;646width = (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK);647switch (width) {648/* Deprecated. */649case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:650case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:651bw = IEEE80211_STA_RX_BW_160;652break;653default:654/* Check if we do support 160Mhz somehow after all. */655if ((sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK) != 0)656bw = IEEE80211_STA_RX_BW_160;657else658bw = IEEE80211_STA_RX_BW_80;659}660/*661* While we can set what is possibly supported we also need to be662* on a channel which supports that bandwidth; e.g., we can support663* VHT160 but the AP only does VHT80.664* Further ni_chan will also have filtered out what we disabled665* by configuration.666* Once net80211 channel selection is fixed for 802.11-2020 and667* VHT160 we can possibly spare ourselves the above.668*/669if (bw == IEEE80211_STA_RX_BW_160 &&670!IEEE80211_IS_CHAN_VHT160(ni->ni_chan) &&671!IEEE80211_IS_CHAN_VHT80P80(ni->ni_chan))672bw = IEEE80211_STA_RX_BW_80;673if (bw == IEEE80211_STA_RX_BW_80 &&674!IEEE80211_IS_CHAN_VHT80(ni->ni_chan))675bw = sta->deflink.bandwidth;676sta->deflink.bandwidth = bw;677skip_bw:678679band = vif->bss_conf.chanctx_conf->def.chan->band;680vht_cap = &hw->wiphy->bands[band]->vht_cap;681sta_vht_cap = &sta->deflink.vht_cap;682683rx_nss = 0;684rx_map = tx_map = 0;685for (int i = 7; i >= 0; i--) {686uint8_t card, sta;687688card = (vht_cap->vht_mcs.rx_mcs_map >> (2 * i)) & 0x3;689sta = (sta_vht_cap->vht_mcs.rx_mcs_map >> (2 * i)) & 0x3;690if (sta != IEEE80211_VHT_MCS_NOT_SUPPORTED) {691if (card == IEEE80211_VHT_MCS_NOT_SUPPORTED)692sta = IEEE80211_VHT_MCS_NOT_SUPPORTED;693else {694sta = MIN(sta, card);695if (rx_nss == 0)696rx_nss = i + 1;697}698}699rx_map |= (sta << (2 * i));700701card = (vht_cap->vht_mcs.tx_mcs_map >> (2 * i)) & 0x3;702sta = (sta_vht_cap->vht_mcs.tx_mcs_map >> (2 * i)) & 0x3;703if (sta != IEEE80211_VHT_MCS_NOT_SUPPORTED) {704if (card == IEEE80211_VHT_MCS_NOT_SUPPORTED)705sta = IEEE80211_VHT_MCS_NOT_SUPPORTED;706else707sta = MIN(sta, card);708}709tx_map |= (sta << (2 * i));710}711TRACEOK("VHT rx_mcs_map %#010x->%#010x, tx_mcs_map %#010x->%#010x, rx_nss = %d",712sta_vht_cap->vht_mcs.rx_mcs_map, rx_map,713sta_vht_cap->vht_mcs.tx_mcs_map, tx_map, rx_nss);714sta_vht_cap->vht_mcs.rx_mcs_map = rx_map;715sta_vht_cap->vht_mcs.tx_mcs_map = tx_map;716if (rx_nss > 0) {717TRACEOK("VHT rx_nss = max(%d, %d)", rx_nss, sta->deflink.rx_nss);718sta->deflink.rx_nss = MAX(rx_nss, sta->deflink.rx_nss);719} else {720sta->deflink.vht_cap.vht_supported = false;721return;722}723724switch (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK) {725case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:726sta->deflink.agg.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_11454;727break;728case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991:729sta->deflink.agg.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_7991;730break;731case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895:732default:733sta->deflink.agg.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_3895;734break;735}736}737#endif738739static void740lkpi_sta_sync_from_ni(struct ieee80211_hw *hw, struct ieee80211_vif *vif,741struct ieee80211_sta *sta, struct ieee80211_node *ni, bool updchnctx)742{743744/*745* Ensure rx_nss is at least 1 as otherwise drivers run into746* unexpected problems.747*/748sta->deflink.rx_nss = 1;749750#if defined(LKPI_80211_HT)751lkpi_sta_sync_ht_from_ni(hw, vif, sta, ni);752#endif753#if defined(LKPI_80211_VHT)754lkpi_sta_sync_vht_from_ni(hw, vif, sta, ni);755#endif756757/*758* We are also called from node allocation which net80211759* can do even on `ifconfig down`; in that case the chanctx760* may still be valid and we get a discrepancy between761* sta and chanctx. Thus do not try to update the chanctx762* when called from lkpi_lsta_alloc().763*/764if (updchnctx)765lkpi_sync_chanctx_cw_from_rx_bw(hw, vif, sta);766}767768static uint8_t769lkpi_get_max_rx_chains(struct ieee80211_node *ni)770{771uint8_t chains;772#if defined(LKPI_80211_HT) || defined(LKPI_80211_VHT)773struct lkpi_sta *lsta;774struct ieee80211_sta *sta;775776lsta = ni->ni_drv_data;777sta = LSTA_TO_STA(lsta);778#endif779780chains = 1;781#if defined(LKPI_80211_HT)782IMPROVE("We should factor counting MCS/NSS out for sync and here");783if (sta->deflink.ht_cap.ht_supported)784chains = MAX(chains, sta->deflink.rx_nss);785#endif786787#if defined(LKPI_80211_VHT)788if (sta->deflink.vht_cap.vht_supported)789chains = MAX(chains, sta->deflink.rx_nss);790#endif791792return (chains);793}794795static void796lkpi_lsta_dump(struct lkpi_sta *lsta, struct ieee80211_node *ni,797const char *_f, int _l)798{799800#ifdef LINUXKPI_DEBUG_80211801if ((linuxkpi_debug_80211 & D80211_TRACE_STA) == 0)802return;803if (lsta == NULL)804return;805806printf("%s:%d lsta %p ni %p sta %p\n",807_f, _l, lsta, ni, &lsta->sta);808if (ni != NULL)809ieee80211_dump_node(NULL, ni);810printf("\ttxq_task txq len %d mtx\n", mbufq_len(&lsta->txq));811printf("\tkc %p state %d added_to_drv %d in_mgd %d\n",812&lsta->kc[0], lsta->state, lsta->added_to_drv, lsta->in_mgd);813#endif814}815816static void817lkpi_lsta_remove(struct lkpi_sta *lsta, struct lkpi_vif *lvif)818{819820lockdep_assert_wiphy(lsta->hw->wiphy);821822KASSERT(!list_empty(&lsta->lsta_list),823("%s: lsta %p ni %p\n", __func__, lsta, lsta->ni));824list_del_init(&lsta->lsta_list);825}826827static struct lkpi_sta *828lkpi_lsta_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN],829struct ieee80211_hw *hw, struct ieee80211_node *ni)830{831struct lkpi_sta *lsta;832struct lkpi_vif *lvif;833struct ieee80211_vif *vif;834struct ieee80211_sta *sta;835int band, i, tid;836837lsta = malloc(sizeof(*lsta) + hw->sta_data_size, M_LKPI80211,838M_NOWAIT | M_ZERO);839if (lsta == NULL)840return (NULL);841842lsta->hw = hw;843lsta->added_to_drv = false;844lsta->state = IEEE80211_STA_NOTEXIST;845/*846* Link the ni to the lsta here without taking a reference.847* For one we would have to take the reference in node_init()848* as ieee80211_alloc_node() will initialise the refcount after us.849* For the other a ni and an lsta are 1:1 mapped and always together850* from [ic_]node_alloc() to [ic_]node_free() so we are essentally851* using the ni references for the lsta as well despite it being852* two separate allocations.853*/854lsta->ni = ni;855/* The back-pointer "drv_data" to net80211_node let's us get lsta. */856ni->ni_drv_data = lsta;857858lvif = VAP_TO_LVIF(vap);859vif = LVIF_TO_VIF(lvif);860sta = LSTA_TO_STA(lsta);861862IEEE80211_ADDR_COPY(sta->addr, mac);863864/* TXQ */865for (tid = 0; tid < nitems(sta->txq); tid++) {866struct lkpi_txq *ltxq;867868/* We are not limiting ourselves to hw.queues here. */869ltxq = malloc(sizeof(*ltxq) + hw->txq_data_size,870M_LKPI80211, M_NOWAIT | M_ZERO);871if (ltxq == NULL)872goto cleanup;873/* iwlwifi//mvm/sta.c::tid_to_mac80211_ac[] */874if (tid == IEEE80211_NUM_TIDS) {875if (!ieee80211_hw_check(hw, STA_MMPDU_TXQ)) {876free(ltxq, M_LKPI80211);877continue;878}879IMPROVE("AP/if we support non-STA here too");880ltxq->txq.ac = IEEE80211_AC_VO;881} else {882ltxq->txq.ac = ieee80211e_up_to_ac[tid & 7];883}884ltxq->seen_dequeue = false;885ltxq->stopped = false;886ltxq->txq.vif = vif;887ltxq->txq.tid = tid;888ltxq->txq.sta = sta;889TAILQ_ELEM_INIT(ltxq, txq_entry);890skb_queue_head_init(<xq->skbq);891LKPI_80211_LTXQ_LOCK_INIT(ltxq);892sta->txq[tid] = <xq->txq;893}894895/* Deflink information. */896for (band = 0; band < NUM_NL80211_BANDS; band++) {897struct ieee80211_supported_band *supband;898uint32_t rate_mandatory;;899900supband = hw->wiphy->bands[band];901if (supband == NULL)902continue;903904switch (band) {905case NL80211_BAND_2GHZ:906/* We have to assume 11g support here. */907rate_mandatory = IEEE80211_RATE_MANDATORY_G |908IEEE80211_RATE_MANDATORY_B;909break;910case NL80211_BAND_5GHZ:911rate_mandatory = IEEE80211_RATE_MANDATORY_A;912break;913default:914continue;915}916917for (i = 0; i < supband->n_bitrates; i++) {918if ((supband->bitrates[i].flags & rate_mandatory) != 0)919sta->deflink.supp_rates[band] |= BIT(i);920}921}922923sta->deflink.smps_mode = IEEE80211_SMPS_OFF;924sta->deflink.bandwidth = IEEE80211_STA_RX_BW_20;925sta->deflink.agg.max_rc_amsdu_len = IEEE80211_MAX_MPDU_LEN_HT_BA;926sta->deflink.rx_nss = 1;927sta->deflink.sta = sta;928929lkpi_sta_sync_from_ni(hw, vif, sta, ni, false);930931IMPROVE("he, eht, bw_320, ... smps_mode, ..");932933/* Link configuration. */934IEEE80211_ADDR_COPY(sta->deflink.addr, sta->addr);935sta->link[0] = &sta->deflink;936for (i = 1; i < nitems(sta->link); i++) {937IMPROVE("more links; only link[0] = deflink currently.");938}939IMPROVE("11be");940sta->mlo = false;941942/* Deferred TX path. */943LKPI_80211_LSTA_TXQ_LOCK_INIT(lsta);944TASK_INIT(&lsta->txq_task, 0, lkpi_80211_txq_task, lsta);945mbufq_init(&lsta->txq, 32 * NAPI_POLL_WEIGHT);946lsta->txq_ready = true;947948return (lsta);949950cleanup:951for (; tid >= 0; tid--) {952struct lkpi_txq *ltxq;953954ltxq = TXQ_TO_LTXQ(sta->txq[tid]);955LKPI_80211_LTXQ_LOCK_DESTROY(ltxq);956free(sta->txq[tid], M_LKPI80211);957}958free(lsta, M_LKPI80211);959return (NULL);960}961962static void963lkpi_lsta_free(struct lkpi_sta *lsta, struct ieee80211_node *ni)964{965struct mbuf *m;966967if (lsta->added_to_drv)968panic("%s: Trying to free an lsta still known to firmware: "969"lsta %p ni %p added_to_drv %d\n",970__func__, lsta, ni, lsta->added_to_drv);971972/* XXX-BZ free resources, ... */973IMPROVE();974975/* Drain sta->txq[] */976977LKPI_80211_LSTA_TXQ_LOCK(lsta);978lsta->txq_ready = false;979LKPI_80211_LSTA_TXQ_UNLOCK(lsta);980981/* Drain taskq, won't be restarted until added_to_drv is set again. */982while (taskqueue_cancel(taskqueue_thread, &lsta->txq_task, NULL) != 0)983taskqueue_drain(taskqueue_thread, &lsta->txq_task);984985/* Flush mbufq (make sure to release ni refs!). */986m = mbufq_dequeue(&lsta->txq);987while (m != NULL) {988struct ieee80211_node *nim;989990nim = (struct ieee80211_node *)m->m_pkthdr.rcvif;991if (nim != NULL)992ieee80211_free_node(nim);993m_freem(m);994m = mbufq_dequeue(&lsta->txq);995}996KASSERT(mbufq_empty(&lsta->txq), ("%s: lsta %p has txq len %d != 0\n",997__func__, lsta, mbufq_len(&lsta->txq)));998LKPI_80211_LSTA_TXQ_LOCK_DESTROY(lsta);9991000/* Remove lsta from vif; that is done by the state machine. Should assert it? */10011002IMPROVE("Make sure everything is cleaned up.");10031004/* Free lsta. */1005lsta->ni = NULL;1006ni->ni_drv_data = NULL;1007free(lsta, M_LKPI80211);1008}100910101011static enum nl80211_band1012lkpi_net80211_chan_to_nl80211_band(struct ieee80211_channel *c)1013{10141015if (IEEE80211_IS_CHAN_2GHZ(c))1016return (NL80211_BAND_2GHZ);1017else if (IEEE80211_IS_CHAN_5GHZ(c))1018return (NL80211_BAND_5GHZ);1019#ifdef __notyet__1020else if ()1021return (NL80211_BAND_6GHZ);1022else if ()1023return (NL80211_BAND_60GHZ);1024else if (IEEE80211_IS_CHAN_GSM(c))1025return (NL80211_BAND_XXX);1026#endif1027else1028panic("%s: unsupported band. c %p flags %#x\n",1029__func__, c, c->ic_flags);1030}10311032static uint32_t1033lkpi_nl80211_band_to_net80211_band(enum nl80211_band band)1034{10351036/* XXX-BZ this is just silly; net80211 is too convoluted. */1037/* IEEE80211_CHAN_A / _G / .. doesn't really work either. */1038switch (band) {1039case NL80211_BAND_2GHZ:1040return (IEEE80211_CHAN_2GHZ);1041break;1042case NL80211_BAND_5GHZ:1043return (IEEE80211_CHAN_5GHZ);1044break;1045case NL80211_BAND_60GHZ:1046break;1047case NL80211_BAND_6GHZ:1048break;1049default:1050panic("%s: unsupported band %u\n", __func__, band);1051break;1052}10531054IMPROVE();1055return (0x00);1056}10571058#ifdef LINUXKPI_DEBUG_802111059static const char *1060lkpi_nl80211_band_name(enum nl80211_band band)1061{1062switch (band) {1063case NL80211_BAND_2GHZ:1064return "2Ghz";1065break;1066case NL80211_BAND_5GHZ:1067return "5Ghz";1068break;1069case NL80211_BAND_60GHZ:1070return "60Ghz";1071break;1072case NL80211_BAND_6GHZ:1073return "6Ghz";1074break;1075default:1076panic("%s: unsupported band %u\n", __func__, band);1077break;1078}1079}1080#endif10811082#if 01083static enum ieee80211_ac_numbers1084lkpi_ac_net_to_l80211(int ac)1085{10861087switch (ac) {1088case WME_AC_VO:1089return (IEEE80211_AC_VO);1090case WME_AC_VI:1091return (IEEE80211_AC_VI);1092case WME_AC_BE:1093return (IEEE80211_AC_BE);1094case WME_AC_BK:1095return (IEEE80211_AC_BK);1096default:1097printf("%s: invalid WME_AC_* input: ac = %d\n", __func__, ac);1098return (IEEE80211_AC_BE);1099}1100}1101#endif11021103static enum nl80211_iftype1104lkpi_opmode_to_vif_type(enum ieee80211_opmode opmode)1105{11061107switch (opmode) {1108case IEEE80211_M_IBSS:1109return (NL80211_IFTYPE_ADHOC);1110break;1111case IEEE80211_M_STA:1112return (NL80211_IFTYPE_STATION);1113break;1114case IEEE80211_M_WDS:1115return (NL80211_IFTYPE_WDS);1116break;1117case IEEE80211_M_HOSTAP:1118return (NL80211_IFTYPE_AP);1119break;1120case IEEE80211_M_MONITOR:1121return (NL80211_IFTYPE_MONITOR);1122break;1123case IEEE80211_M_MBSS:1124return (NL80211_IFTYPE_MESH_POINT);1125break;1126case IEEE80211_M_AHDEMO:1127/* FALLTHROUGH */1128default:1129printf("ERROR: %s: unsupported opmode %d\n", __func__, opmode);1130/* FALLTHROUGH */1131}1132return (NL80211_IFTYPE_UNSPECIFIED);1133}11341135#ifdef LKPI_80211_HW_CRYPTO1136static const char *1137lkpi_cipher_suite_to_name(uint32_t wlan_cipher_suite)1138{1139switch (wlan_cipher_suite) {1140case WLAN_CIPHER_SUITE_WEP40:1141return ("WEP40");1142case WLAN_CIPHER_SUITE_WEP104:1143return ("WEP104");1144case WLAN_CIPHER_SUITE_TKIP:1145return ("TKIP");1146case WLAN_CIPHER_SUITE_CCMP:1147return ("CCMP");1148case WLAN_CIPHER_SUITE_CCMP_256:1149return ("CCMP_256");1150case WLAN_CIPHER_SUITE_GCMP:1151return ("GCMP");1152case WLAN_CIPHER_SUITE_GCMP_256:1153return ("GCMP_256");1154case WLAN_CIPHER_SUITE_AES_CMAC:1155return ("AES_CMAC");1156case WLAN_CIPHER_SUITE_BIP_CMAC_256:1157return ("BIP_CMAC_256");1158case WLAN_CIPHER_SUITE_BIP_GMAC_128:1159return ("BIP_GMAC_128");1160case WLAN_CIPHER_SUITE_BIP_GMAC_256:1161return ("BIP_GMAC_256");1162default:1163return ("??");1164}1165}11661167static uint32_t1168lkpi_l80211_to_net80211_cyphers(struct ieee80211com *ic,1169uint32_t wlan_cipher_suite)1170{1171switch (wlan_cipher_suite) {1172case WLAN_CIPHER_SUITE_WEP40:1173return (IEEE80211_CRYPTO_WEP);1174case WLAN_CIPHER_SUITE_WEP104:1175return (IEEE80211_CRYPTO_WEP);1176case WLAN_CIPHER_SUITE_TKIP:1177return (IEEE80211_CRYPTO_TKIP);1178case WLAN_CIPHER_SUITE_CCMP:1179return (IEEE80211_CRYPTO_AES_CCM);1180case WLAN_CIPHER_SUITE_CCMP_256:1181return (IEEE80211_CRYPTO_AES_CCM_256);1182case WLAN_CIPHER_SUITE_GCMP:1183return (IEEE80211_CRYPTO_AES_GCM_128);1184case WLAN_CIPHER_SUITE_GCMP_256:1185return (IEEE80211_CRYPTO_AES_GCM_256);1186case WLAN_CIPHER_SUITE_AES_CMAC:1187return (IEEE80211_CRYPTO_BIP_CMAC_128);1188case WLAN_CIPHER_SUITE_BIP_CMAC_256:1189return (IEEE80211_CRYPTO_BIP_CMAC_256);1190case WLAN_CIPHER_SUITE_BIP_GMAC_128:1191return (IEEE80211_CRYPTO_BIP_GMAC_128);1192case WLAN_CIPHER_SUITE_BIP_GMAC_256:1193return (IEEE80211_CRYPTO_BIP_GMAC_256);1194default:1195ic_printf(ic, "%s: unknown WLAN Cipher Suite %#08x | %u (%s)\n",1196__func__,1197wlan_cipher_suite >> 8, wlan_cipher_suite & 0xff,1198lkpi_cipher_suite_to_name(wlan_cipher_suite));1199return (0);1200}1201}12021203static uint32_t1204lkpi_net80211_to_l80211_cipher_suite(uint32_t cipher, uint8_t keylen)1205{12061207switch (cipher) {1208case IEEE80211_CIPHER_WEP:1209if (keylen == (40/NBBY))1210return (WLAN_CIPHER_SUITE_WEP40);1211else if (keylen == (104/NBBY))1212return (WLAN_CIPHER_SUITE_WEP104);1213else {1214printf("%s: WEP with unsupported keylen %d\n",1215__func__, keylen * NBBY);1216return (0);1217}1218break;1219case IEEE80211_CIPHER_TKIP:1220return (WLAN_CIPHER_SUITE_TKIP);1221case IEEE80211_CIPHER_AES_CCM:1222return (WLAN_CIPHER_SUITE_CCMP);1223case IEEE80211_CIPHER_AES_CCM_256:1224return (WLAN_CIPHER_SUITE_CCMP_256);1225case IEEE80211_CIPHER_AES_GCM_128:1226return (WLAN_CIPHER_SUITE_GCMP);1227case IEEE80211_CIPHER_AES_GCM_256:1228return (WLAN_CIPHER_SUITE_GCMP_256);1229case IEEE80211_CIPHER_BIP_CMAC_128:1230return (WLAN_CIPHER_SUITE_AES_CMAC);1231case IEEE80211_CIPHER_BIP_CMAC_256:1232return (WLAN_CIPHER_SUITE_BIP_CMAC_256);1233case IEEE80211_CIPHER_BIP_GMAC_128:1234return (WLAN_CIPHER_SUITE_BIP_GMAC_128);1235case IEEE80211_CIPHER_BIP_GMAC_256:1236return (WLAN_CIPHER_SUITE_BIP_GMAC_256);12371238case IEEE80211_CIPHER_AES_OCB:1239case IEEE80211_CIPHER_TKIPMIC:1240/*1241* TKIP w/ hw MIC support1242* (gone wrong; should really be a crypto flag in net80211).1243*/1244case IEEE80211_CIPHER_CKIP:1245case IEEE80211_CIPHER_NONE:1246printf("%s: unsupported cipher %#010x\n", __func__, cipher);1247break;1248default:1249printf("%s: unknown cipher %#010x\n", __func__, cipher);1250};1251return (0);1252}1253#endif12541255#ifdef __notyet__1256static enum ieee80211_sta_state1257lkpi_net80211_state_to_sta_state(enum ieee80211_state state)1258{12591260/*1261* XXX-BZ The net80211 states are "try to ..", the lkpi8011 states are1262* "done". Also ASSOC/AUTHORIZED are both "RUN" then?1263*/1264switch (state) {1265case IEEE80211_S_INIT:1266return (IEEE80211_STA_NOTEXIST);1267case IEEE80211_S_SCAN:1268return (IEEE80211_STA_NONE);1269case IEEE80211_S_AUTH:1270return (IEEE80211_STA_AUTH);1271case IEEE80211_S_ASSOC:1272return (IEEE80211_STA_ASSOC);1273case IEEE80211_S_RUN:1274return (IEEE80211_STA_AUTHORIZED);1275case IEEE80211_S_CAC:1276case IEEE80211_S_CSA:1277case IEEE80211_S_SLEEP:1278default:1279UNIMPLEMENTED;1280};12811282return (IEEE80211_STA_NOTEXIST);1283}1284#endif12851286static struct linuxkpi_ieee80211_channel *1287lkpi_find_lkpi80211_chan(struct lkpi_hw *lhw,1288struct ieee80211_channel *c)1289{1290struct ieee80211_hw *hw;1291struct linuxkpi_ieee80211_channel *channels;1292enum nl80211_band band;1293int i, nchans;12941295hw = LHW_TO_HW(lhw);1296band = lkpi_net80211_chan_to_nl80211_band(c);1297if (hw->wiphy->bands[band] == NULL)1298return (NULL);12991300nchans = hw->wiphy->bands[band]->n_channels;1301if (nchans <= 0)1302return (NULL);13031304channels = hw->wiphy->bands[band]->channels;1305for (i = 0; i < nchans; i++) {1306if (channels[i].center_freq == c->ic_freq)1307return (&channels[i]);1308}13091310return (NULL);1311}13121313#if 01314static struct linuxkpi_ieee80211_channel *1315lkpi_get_lkpi80211_chan(struct ieee80211com *ic, struct ieee80211_node *ni)1316{1317struct linuxkpi_ieee80211_channel *chan;1318struct ieee80211_channel *c;1319struct lkpi_hw *lhw;13201321chan = NULL;1322if (ni != NULL && ni->ni_chan != IEEE80211_CHAN_ANYC)1323c = ni->ni_chan;1324else if (ic->ic_bsschan != IEEE80211_CHAN_ANYC)1325c = ic->ic_bsschan;1326else if (ic->ic_curchan != IEEE80211_CHAN_ANYC)1327c = ic->ic_curchan;1328else1329c = NULL;13301331if (c != NULL && c != IEEE80211_CHAN_ANYC) {1332lhw = ic->ic_softc;1333chan = lkpi_find_lkpi80211_chan(lhw, c);1334}13351336return (chan);1337}1338#endif13391340struct linuxkpi_ieee80211_channel *1341linuxkpi_ieee80211_get_channel(struct wiphy *wiphy, uint32_t freq)1342{1343enum nl80211_band band;13441345for (band = 0; band < NUM_NL80211_BANDS; band++) {1346struct ieee80211_supported_band *supband;1347struct linuxkpi_ieee80211_channel *channels;1348int i;13491350supband = wiphy->bands[band];1351if (supband == NULL || supband->n_channels == 0)1352continue;13531354channels = supband->channels;1355for (i = 0; i < supband->n_channels; i++) {1356if (channels[i].center_freq == freq)1357return (&channels[i]);1358}1359}13601361return (NULL);1362}13631364#ifdef LKPI_80211_HW_CRYPTO1365static int1366lkpi_sta_del_keys(struct ieee80211_hw *hw, struct ieee80211_vif *vif,1367struct lkpi_sta *lsta)1368{1369int error;13701371if (!lkpi_hwcrypto)1372return (0);13731374lockdep_assert_wiphy(hw->wiphy);1375ieee80211_ref_node(lsta->ni);13761377error = 0;1378for (ieee80211_keyix keyix = 0; keyix < nitems(lsta->kc); keyix++) {1379struct ieee80211_key_conf *kc;1380int err;13811382if (lsta->kc[keyix] == NULL)1383continue;1384kc = lsta->kc[keyix];13851386#ifdef LINUXKPI_DEBUG_802111387if (linuxkpi_debug_80211 & D80211_TRACE_HW_CRYPTO)1388ic_printf(lsta->ni->ni_ic, "%d %lu %s: running set_key cmd %d(%s) for "1389"sta %6D: keyidx %u hw_key_idx %u flags %b\n",1390curthread->td_tid, jiffies, __func__,1391DISABLE_KEY, "DISABLE", lsta->sta.addr, ":",1392kc->keyidx, kc->hw_key_idx, kc->flags, IEEE80211_KEY_FLAG_BITS);1393#endif13941395err = lkpi_80211_mo_set_key(hw, DISABLE_KEY, vif,1396LSTA_TO_STA(lsta), kc);1397if (err != 0) {1398ic_printf(lsta->ni->ni_ic, "%d %lu %s: set_key cmd %d(%s) for "1399"sta %6D failed: %d\n", curthread->td_tid, jiffies, __func__,1400DISABLE_KEY, "DISABLE", lsta->sta.addr, ":", err);1401error++;14021403/*1404* If we free the key here we will never be able to get it1405* removed from the driver/fw which will likely make us1406* crash (firmware).1407*/1408continue;1409}1410#ifdef LINUXKPI_DEBUG_802111411if (linuxkpi_debug_80211 & D80211_TRACE_HW_CRYPTO)1412ic_printf(lsta->ni->ni_ic, "%d %lu %s: set_key cmd %d(%s) for "1413"sta %6D succeeded: keyidx %u hw_key_idx %u flags %b\n",1414curthread->td_tid, jiffies, __func__,1415DISABLE_KEY, "DISABLE", lsta->sta.addr, ":",1416kc->keyidx, kc->hw_key_idx, kc->flags, IEEE80211_KEY_FLAG_BITS);1417#endif14181419lsta->kc[keyix] = NULL;1420free(kc, M_LKPI80211);1421}1422ieee80211_free_node(lsta->ni);1423return (error);1424}14251426/* XXX-BZ one day we should replace this iterating over VIFs, or node list? */1427/* See also lkpi_sta_del_keys() these days. */1428static int1429lkpi_iv_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k)1430{1431struct ieee80211com *ic;1432struct lkpi_hw *lhw;1433struct ieee80211_hw *hw;1434struct lkpi_vif *lvif;1435struct lkpi_sta *lsta;1436struct ieee80211_vif *vif;1437struct ieee80211_sta *sta;1438struct ieee80211_node *ni;1439struct ieee80211_key_conf *kc;1440int error;14411442ic = vap->iv_ic;1443lhw = ic->ic_softc;1444hw = LHW_TO_HW(lhw);1445lvif = VAP_TO_LVIF(vap);1446vif = LVIF_TO_VIF(lvif);14471448/*1449* Make sure we do not make it here without going through1450* lkpi_iv_key_update_begin() first.1451*/1452lockdep_assert_wiphy(hw->wiphy);14531454/*1455* While we are assoc we may still send packets. We cannot delete the1456* keys as otherwise packets could go out unencrypted. Some firmware1457* does not like this and will fire an assert.1458* net80211 needs to drive this better but given we want the disassoc1459* frame out and have to unlock we are open to a race currently.1460* This check should prevent problems.1461* How to test: run 800Mbit/s UDP traffic and during that restart your1462* supplicant. You want to survive that.1463*/1464if (vif->cfg.assoc) {1465if (linuxkpi_debug_80211 & D80211_TRACE_HW_CRYPTO)1466ic_printf(ic, "%d %lu %s: vif still assoc; not deleting keys\n",1467curthread->td_tid, jiffies, __func__);1468return (0);1469}14701471if (IEEE80211_KEY_UNDEFINED(k)) {1472ic_printf(ic, "%s: vap %p key %p is undefined: %p %u\n",1473__func__, vap, k, k->wk_cipher, k->wk_keyix);1474return (0);1475}14761477if (vap->iv_bss == NULL) {1478ic_printf(ic, "%s: iv_bss %p for vap %p is NULL\n",1479__func__, vap->iv_bss, vap);1480return (0);1481}14821483ni = ieee80211_ref_node(vap->iv_bss);1484lsta = ni->ni_drv_data;1485if (lsta == NULL) {1486ic_printf(ic, "%s: ni %p (%6D) with lsta NULL\n",1487__func__, ni, ni->ni_bssid, ":");1488ieee80211_free_node(ni);1489return (0);1490}1491sta = LSTA_TO_STA(lsta);14921493if (lsta->kc[k->wk_keyix] == NULL) {1494#ifdef LINUXKPI_DEBUG_802111495if (linuxkpi_debug_80211 & D80211_TRACE_HW_CRYPTO)1496ic_printf(ic, "%d %lu %s: sta %6D and no key information, "1497"keyidx %u wk_macaddr %6D; returning success\n",1498curthread->td_tid, jiffies, __func__, sta->addr, ":",1499k->wk_keyix, k->wk_macaddr, ":");1500#endif1501ieee80211_free_node(ni);1502return (1);1503}1504kc = lsta->kc[k->wk_keyix];15051506#ifdef LINUXKPI_DEBUG_802111507if (linuxkpi_debug_80211 & D80211_TRACE_HW_CRYPTO)1508ic_printf(ic, "%d %lu %s: running set_key cmd %d(%s) for sta %6D: "1509"keyidx %u hw_key_idx %u flags %b\n",1510curthread->td_tid, jiffies, __func__,1511DISABLE_KEY, "DISABLE", sta->addr, ":",1512kc->keyidx, kc->hw_key_idx, kc->flags, IEEE80211_KEY_FLAG_BITS);1513#endif15141515error = lkpi_80211_mo_set_key(hw, DISABLE_KEY, vif, sta, kc);1516if (error != 0) {1517ic_printf(ic, "%d %lu %s: set_key cmd %d(%s) for sta %6D failed: %d\n",1518curthread->td_tid, jiffies, __func__,1519DISABLE_KEY, "DISABLE", sta->addr, ":", error);1520error = 0;1521goto out;1522}15231524#ifdef LINUXKPI_DEBUG_802111525if (linuxkpi_debug_80211 & D80211_TRACE_HW_CRYPTO)1526ic_printf(ic, "%d %lu %s: set_key cmd %d(%s) for sta %6D succeeded: "1527"keyidx %u hw_key_idx %u flags %b\n",1528curthread->td_tid, jiffies, __func__,1529DISABLE_KEY, "DISABLE", sta->addr, ":",1530kc->keyidx, kc->hw_key_idx, kc->flags, IEEE80211_KEY_FLAG_BITS);1531#endif1532lsta->kc[k->wk_keyix] = NULL;1533free(kc, M_LKPI80211);1534error = 1;1535out:1536ieee80211_free_node(ni);1537return (error);1538}15391540static int1541lkpi_iv_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k)1542{1543struct ieee80211com *ic;1544struct lkpi_hw *lhw;1545struct ieee80211_hw *hw;1546struct lkpi_vif *lvif;1547struct lkpi_sta *lsta;1548struct ieee80211_vif *vif;1549struct ieee80211_sta *sta;1550struct ieee80211_node *ni;1551struct ieee80211_key_conf *kc;1552uint32_t lcipher;1553uint16_t exp_flags;1554uint8_t keylen;1555int error;15561557ic = vap->iv_ic;1558lhw = ic->ic_softc;1559hw = LHW_TO_HW(lhw);15601561/*1562* Make sure we do not make it here without going through1563* lkpi_iv_key_update_begin() first.1564*/1565lockdep_assert_wiphy(hw->wiphy);15661567if (IEEE80211_KEY_UNDEFINED(k)) {1568ic_printf(ic, "%s: vap %p key %p is undefined: %p %u\n",1569__func__, vap, k, k->wk_cipher, k->wk_keyix);1570return (0);1571}15721573if (vap->iv_bss == NULL) {1574ic_printf(ic, "%s: iv_bss %p for vap %p is NULL\n",1575__func__, vap->iv_bss, vap);1576return (0);1577}1578ni = ieee80211_ref_node(vap->iv_bss);1579lsta = ni->ni_drv_data;1580if (lsta == NULL) {1581ic_printf(ic, "%s: ni %p (%6D) with lsta NULL\n",1582__func__, ni, ni->ni_bssid, ":");1583ieee80211_free_node(ni);1584return (0);1585}1586sta = LSTA_TO_STA(lsta);15871588keylen = k->wk_keylen;1589lcipher = lkpi_net80211_to_l80211_cipher_suite(1590k->wk_cipher->ic_cipher, k->wk_keylen);1591switch (lcipher) {1592case WLAN_CIPHER_SUITE_TKIP:1593keylen += 2 * k->wk_cipher->ic_miclen;1594break;1595case WLAN_CIPHER_SUITE_CCMP:1596case WLAN_CIPHER_SUITE_GCMP:1597break;1598default:1599ic_printf(ic, "%s: CIPHER SUITE %#x (%s) not supported\n",1600__func__, lcipher, lkpi_cipher_suite_to_name(lcipher));1601IMPROVE();1602ieee80211_free_node(ni);1603return (0);1604}16051606if (lsta->kc[k->wk_keyix] != NULL) {1607IMPROVE("Still in firmware? Del first. Can we assert this cannot happen?");1608ic_printf(ic, "%s: sta %6D found with key information\n",1609__func__, sta->addr, ":");1610kc = lsta->kc[k->wk_keyix];1611lsta->kc[k->wk_keyix] = NULL;1612free(kc, M_LKPI80211);1613kc = NULL; /* safeguard */1614}16151616kc = malloc(sizeof(*kc) + keylen, M_LKPI80211, M_WAITOK | M_ZERO);1617kc->_k = k; /* Save the pointer to net80211. */1618kc->cipher = lcipher;1619kc->keyidx = k->wk_keyix;1620#if 01621kc->hw_key_idx = /* set by hw and needs to be passed for TX */;1622#endif1623atomic64_set(&kc->tx_pn, k->wk_keytsc);1624kc->keylen = k->wk_keylen;1625memcpy(kc->key, k->wk_key, k->wk_keylen);16261627if (k->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))1628kc->flags |= IEEE80211_KEY_FLAG_PAIRWISE;1629if (k->wk_flags & IEEE80211_KEY_GROUP)1630kc->flags &= ~IEEE80211_KEY_FLAG_PAIRWISE;16311632kc->iv_len = k->wk_cipher->ic_header;1633kc->icv_len = k->wk_cipher->ic_trailer;16341635switch (kc->cipher) {1636case WLAN_CIPHER_SUITE_TKIP:1637memcpy(kc->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY, k->wk_txmic, k->wk_cipher->ic_miclen);1638memcpy(kc->key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY, k->wk_rxmic, k->wk_cipher->ic_miclen);1639break;1640case WLAN_CIPHER_SUITE_CCMP:1641case WLAN_CIPHER_SUITE_GCMP:1642break;1643default:1644/* currently UNREACH */1645IMPROVE();1646break;1647};1648lsta->kc[k->wk_keyix] = kc;16491650#ifdef LINUXKPI_DEBUG_802111651if (linuxkpi_debug_80211 & D80211_TRACE_HW_CRYPTO)1652ic_printf(ic, "%d %lu %s: running set_key cmd %d(%s) for sta %6D: "1653"kc %p keyidx %u hw_key_idx %u keylen %u flags %b\n",1654curthread->td_tid, jiffies, __func__,1655SET_KEY, "SET", sta->addr, ":", kc, kc->keyidx, kc->hw_key_idx,1656kc->keylen, kc->flags, IEEE80211_KEY_FLAG_BITS);1657#endif16581659lvif = VAP_TO_LVIF(vap);1660vif = LVIF_TO_VIF(lvif);1661error = lkpi_80211_mo_set_key(hw, SET_KEY, vif, sta, kc);1662if (error != 0) {1663ic_printf(ic, "%d %lu %s: set_key cmd %d(%s) for sta %6D failed: %d\n",1664curthread->td_tid, jiffies, __func__,1665SET_KEY, "SET", sta->addr, ":", error);1666lsta->kc[k->wk_keyix] = NULL;1667free(kc, M_LKPI80211);1668ieee80211_free_node(ni);1669return (0);1670}16711672#ifdef LINUXKPI_DEBUG_802111673if (linuxkpi_debug_80211 & D80211_TRACE_HW_CRYPTO)1674ic_printf(ic, "%d %lu %s: set_key cmd %d(%s) for sta %6D succeeded: "1675"kc %p keyidx %u hw_key_idx %u flags %b\n",1676curthread->td_tid, jiffies, __func__,1677SET_KEY, "SET", sta->addr, ":",1678kc, kc->keyidx, kc->hw_key_idx, kc->flags, IEEE80211_KEY_FLAG_BITS);1679#endif16801681exp_flags = 0;1682switch (kc->cipher) {1683case WLAN_CIPHER_SUITE_TKIP:1684exp_flags = (IEEE80211_KEY_FLAG_PAIRWISE |1685IEEE80211_KEY_FLAG_PUT_IV_SPACE |1686IEEE80211_KEY_FLAG_GENERATE_MMIC |1687IEEE80211_KEY_FLAG_PUT_MIC_SPACE);1688#define TKIP_INVAL_COMBINATION \1689(IEEE80211_KEY_FLAG_PUT_MIC_SPACE|IEEE80211_KEY_FLAG_GENERATE_MMIC)1690if ((kc->flags & TKIP_INVAL_COMBINATION) == TKIP_INVAL_COMBINATION) {1691ic_printf(ic, "%s: SET_KEY for %s returned invalid "1692"combination %b\n", __func__,1693lkpi_cipher_suite_to_name(kc->cipher),1694kc->flags, IEEE80211_KEY_FLAG_BITS);1695}1696#undef TKIP_INVAL_COMBINATION1697#ifdef __notyet__1698/* Do flags surgery; special see linuxkpi_ieee80211_ifattach(). */1699if ((kc->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) != 0) {1700k->wk_flags &= ~(IEEE80211_KEY_NOMICMGT|IEEE80211_KEY_NOMIC);1701k->wk_flags |= IEEE80211_KEY_SWMIC;1702ic->ic_cryptocaps &= ~IEEE80211_CRYPTO_TKIPMIC1703}1704#endif1705break;1706case WLAN_CIPHER_SUITE_CCMP:1707case WLAN_CIPHER_SUITE_GCMP:1708exp_flags = (IEEE80211_KEY_FLAG_PAIRWISE |1709IEEE80211_KEY_FLAG_PUT_IV_SPACE |1710IEEE80211_KEY_FLAG_GENERATE_IV |1711IEEE80211_KEY_FLAG_GENERATE_IV_MGMT | /* Only needs IV geeration for MGMT frames. */1712IEEE80211_KEY_FLAG_SW_MGMT_TX); /* MFP in software */1713break;1714}1715if ((kc->flags & ~exp_flags) != 0)1716ic_printf(ic, "%s: SET_KEY for %s returned unexpected key flags: "1717" %#06x & ~%#06x = %b\n", __func__,1718lkpi_cipher_suite_to_name(kc->cipher), kc->flags, exp_flags,1719(kc->flags & ~exp_flags), IEEE80211_KEY_FLAG_BITS);17201721#ifdef __notyet__1722/* Do flags surgery. */1723if ((kc->flags & IEEE80211_KEY_FLAG_GENERATE_IV_MGMT) == 0)1724k->wk_flags |= IEEE80211_KEY_NOIVMGT;1725if ((kc->flags & IEEE80211_KEY_FLAG_GENERATE_IV) == 0)1726k->wk_flags |= IEEE80211_KEY_NOIV;1727#endif17281729ieee80211_free_node(ni);1730return (1);1731}17321733static void1734lkpi_iv_key_update_begin(struct ieee80211vap *vap)1735{1736struct ieee80211_node_table *nt;1737struct ieee80211com *ic;1738struct lkpi_hw *lhw;1739struct ieee80211_hw *hw;1740struct lkpi_vif *lvif;1741struct ieee80211_node *ni;1742bool icislocked, ntislocked;17431744ic = vap->iv_ic;1745lhw = ic->ic_softc;1746hw = LHW_TO_HW(lhw);1747lvif = VAP_TO_LVIF(vap);1748nt = &ic->ic_sta;17491750icislocked = IEEE80211_IS_LOCKED(ic);1751ntislocked = IEEE80211_NODE_IS_LOCKED(nt);17521753#ifdef LINUXKPI_DEBUG_802111754if (linuxkpi_debug_80211 & D80211_TRACE_HW_CRYPTO)1755ic_printf(ic, "%d %lu %s: vap %p ic %p %slocked nt %p %slocked "1756"lvif ic_unlocked %d nt_unlocked %d\n",1757curthread->td_tid, jiffies, __func__, vap,1758ic, icislocked ? "" : "un", nt, ntislocked ? "" : "un",1759lvif->ic_unlocked, lvif->nt_unlocked);1760#endif17611762/*1763* This is inconsistent net80211 locking to be fixed one day.1764*/1765/* Try to make sure the node does not go away while possibly unlocked. */1766ni = NULL;1767if (icislocked || ntislocked) {1768if (vap->iv_bss != NULL)1769ni = ieee80211_ref_node(vap->iv_bss);1770}17711772if (icislocked)1773IEEE80211_UNLOCK(ic);1774if (ntislocked)1775IEEE80211_NODE_UNLOCK(nt);17761777wiphy_lock(hw->wiphy);17781779KASSERT(lvif->key_update_iv_bss == NULL, ("%s: key_update_iv_bss not NULL %p",1780__func__, lvif->key_update_iv_bss));1781lvif->key_update_iv_bss = ni;17821783/*1784* ic/nt_unlocked could be a bool given we are under the lock and there1785* must only be a single thread.1786* In case anything in the future disturbs the order the refcnt will1787* help us catching problems a lot easier.1788*/1789if (icislocked)1790refcount_acquire(&lvif->ic_unlocked);1791if (ntislocked)1792refcount_acquire(&lvif->nt_unlocked);17931794/*1795* Stop the queues while doing key updates.1796*/1797ieee80211_stop_queues(hw);1798}17991800static void1801lkpi_iv_key_update_end(struct ieee80211vap *vap)1802{1803struct ieee80211_node_table *nt;1804struct ieee80211com *ic;1805struct lkpi_hw *lhw;1806struct ieee80211_hw *hw;1807struct lkpi_vif *lvif;1808bool icislocked, ntislocked;18091810ic = vap->iv_ic;1811lhw = ic->ic_softc;1812hw = LHW_TO_HW(lhw);1813lvif = VAP_TO_LVIF(vap);1814nt = &ic->ic_sta;18151816/*1817* Re-enabled the queues after the key update.1818*/1819lkpi_ieee80211_wake_queues_locked(hw);18201821icislocked = IEEE80211_IS_LOCKED(ic);1822MPASS(!icislocked);1823ntislocked = IEEE80211_NODE_IS_LOCKED(nt);1824MPASS(!ntislocked);18251826#ifdef LINUXKPI_DEBUG_802111827if (linuxkpi_debug_80211 & D80211_TRACE_HW_CRYPTO)1828ic_printf(ic, "%d %lu %s: vap %p ic %p %slocked nt %p %slocked "1829"lvif ic_unlocked %d nt_unlocked %d\n",1830curthread->td_tid, jiffies, __func__, vap,1831ic, icislocked ? "" : "un", nt, ntislocked ? "" : "un",1832lvif->ic_unlocked, lvif->nt_unlocked);1833#endif18341835/*1836* Check under lock; see comment in lkpi_iv_key_update_begin().1837* In case the refcnt gets out of sync locking in net80211 will1838* quickly barf as well (trying to unlock a lock not held).1839*/1840icislocked = refcount_release_if_last(&lvif->ic_unlocked);1841ntislocked = refcount_release_if_last(&lvif->nt_unlocked);18421843if (lvif->key_update_iv_bss != NULL) {1844ieee80211_free_node(lvif->key_update_iv_bss);1845lvif->key_update_iv_bss = NULL;1846}18471848wiphy_unlock(hw->wiphy);18491850/*1851* This is inconsistent net80211 locking to be fixed one day.1852* ic before nt to avoid a LOR.1853*/1854if (icislocked)1855IEEE80211_LOCK(ic);1856if (ntislocked)1857IEEE80211_NODE_LOCK(nt);1858}1859#endif18601861static void1862lkpi_cleanup_mcast_list_locked(struct lkpi_hw *lhw)1863{1864struct list_head *le, *next;1865struct netdev_hw_addr *addr;18661867if (lhw->mc_list.count != 0) {1868list_for_each_safe(le, next, &lhw->mc_list.addr_list) {1869addr = list_entry(le, struct netdev_hw_addr, addr_list);1870list_del(le);1871lhw->mc_list.count--;1872free(addr, M_LKPI80211);1873}1874}1875KASSERT(lhw->mc_list.count == 0, ("%s: mc_list %p count %d != 0\n",1876__func__, &lhw->mc_list, lhw->mc_list.count));1877}18781879static u_int1880lkpi_ic_update_mcast_copy(void *arg, struct sockaddr_dl *sdl, u_int cnt)1881{1882struct netdev_hw_addr_list *mc_list;1883struct netdev_hw_addr *addr;18841885KASSERT(arg != NULL && sdl != NULL, ("%s: arg %p sdl %p cnt %u\n",1886__func__, arg, sdl, cnt));18871888mc_list = arg;1889/* If it is on the list already skip it. */1890netdev_hw_addr_list_for_each(addr, mc_list) {1891if (!memcmp(addr->addr, LLADDR(sdl), sdl->sdl_alen))1892return (0);1893}18941895addr = malloc(sizeof(*addr), M_LKPI80211, M_NOWAIT | M_ZERO);1896if (addr == NULL)1897return (0);18981899INIT_LIST_HEAD(&addr->addr_list);1900memcpy(addr->addr, LLADDR(sdl), sdl->sdl_alen);1901/* XXX this should be a netdev function? */1902list_add(&addr->addr_list, &mc_list->addr_list);1903mc_list->count++;19041905#ifdef LINUXKPI_DEBUG_802111906if (linuxkpi_debug_80211 & D80211_TRACE)1907printf("%s:%d: mc_list count %d: added %6D\n",1908__func__, __LINE__, mc_list->count, addr->addr, ":");1909#endif19101911return (1);1912}19131914static void1915lkpi_update_mcast_filter(struct ieee80211com *ic)1916{1917struct lkpi_hw *lhw;1918struct ieee80211_hw *hw;1919u64 mc;1920unsigned int changed_flags, flags;1921bool scanning;19221923lhw = ic->ic_softc;19241925LKPI_80211_LHW_SCAN_LOCK(lhw);1926scanning = (lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0;1927LKPI_80211_LHW_SCAN_UNLOCK(lhw);19281929LKPI_80211_LHW_MC_LOCK(lhw);19301931flags = 0;1932if (scanning)1933flags |= FIF_BCN_PRBRESP_PROMISC;1934/* The latter condition may not be as expected but seems wise. */1935if (lhw->mc_all_multi || lhw->ops->prepare_multicast == NULL)1936flags |= FIF_ALLMULTI;19371938hw = LHW_TO_HW(lhw);1939mc = lkpi_80211_mo_prepare_multicast(hw, &lhw->mc_list);19401941changed_flags = (lhw->mc_flags ^ flags) & FIF_FLAGS_MASK;1942lkpi_80211_mo_configure_filter(hw, changed_flags, &flags, mc);1943lhw->mc_flags = flags;19441945#ifdef LINUXKPI_DEBUG_802111946if (linuxkpi_debug_80211 & D80211_TRACE)1947printf("%s: changed_flags %#06x count %d mc_flags %#010x\n",1948__func__, changed_flags, lhw->mc_list.count, lhw->mc_flags);1949#endif19501951LKPI_80211_LHW_MC_UNLOCK(lhw);1952}19531954static enum ieee80211_bss_changed1955lkpi_update_dtim_tsf(struct ieee80211_vif *vif, struct ieee80211_node *ni,1956struct ieee80211vap *vap, const char *_f, int _l)1957{1958enum ieee80211_bss_changed bss_changed;19591960bss_changed = 0;19611962#ifdef LINUXKPI_DEBUG_802111963if (linuxkpi_debug_80211 & D80211_TRACE)1964printf("%s:%d [%s:%d] assoc %d aid %d beacon_int %u "1965"dtim_period %u sync_dtim_count %u sync_tsf %ju "1966"sync_device_ts %u bss_changed %#010jx\n",1967__func__, __LINE__, _f, _l,1968vif->cfg.assoc, vif->cfg.aid,1969vif->bss_conf.beacon_int, vif->bss_conf.dtim_period,1970vif->bss_conf.sync_dtim_count,1971(uintmax_t)vif->bss_conf.sync_tsf,1972vif->bss_conf.sync_device_ts,1973(uintmax_t)bss_changed);1974#endif19751976if (vif->bss_conf.beacon_int != ni->ni_intval) {1977vif->bss_conf.beacon_int = ni->ni_intval;1978/* iwlwifi FW bug workaround; iwl_mvm_mac_sta_state. */1979if (vif->bss_conf.beacon_int < 16)1980vif->bss_conf.beacon_int = 16;1981bss_changed |= BSS_CHANGED_BEACON_INT;1982}19831984/*1985* lkpi_iv_sta_recv_mgmt() will directly call into this function.1986* iwlwifi(4) in iwl_mvm_bss_info_changed_station_common() will1987* stop seesion protection the moment it sees1988* BSS_CHANGED_BEACON_INFO (with the expectations that it was1989* "a beacon from the associated AP"). It will also update1990* the beacon filter in that case. This is the only place1991* we set the BSS_CHANGED_BEACON_INFO on the non-teardown1992* path so make sure we only do run this check once we are1993* assoc. (*iv_recv_mgmt)() will be called before we enter1994* here so the ni will be updates with information from the1995* beacon via net80211::sta_recv_mgmt(). We also need to1996* make sure we do not do it on every beacon we still may1997* get so only do if something changed. vif->bss_conf.dtim_period1998* should be 0 as we start up (we also reset it on teardown).1999*/2000if (vif->cfg.assoc &&2001vif->bss_conf.dtim_period != ni->ni_dtim_period &&2002ni->ni_dtim_period > 0) {2003vif->bss_conf.dtim_period = ni->ni_dtim_period;2004bss_changed |= BSS_CHANGED_BEACON_INFO;2005}20062007vif->bss_conf.sync_dtim_count = ni->ni_dtim_count;2008vif->bss_conf.sync_tsf = le64toh(ni->ni_tstamp.tsf);2009/* vif->bss_conf.sync_device_ts = set in linuxkpi_ieee80211_rx. */20102011#ifdef LINUXKPI_DEBUG_802112012if (linuxkpi_debug_80211 & D80211_TRACE)2013printf("%s:%d [%s:%d] assoc %d aid %d beacon_int %u "2014"dtim_period %u sync_dtim_count %u sync_tsf %ju "2015"sync_device_ts %u bss_changed %#010jx\n",2016__func__, __LINE__, _f, _l,2017vif->cfg.assoc, vif->cfg.aid,2018vif->bss_conf.beacon_int, vif->bss_conf.dtim_period,2019vif->bss_conf.sync_dtim_count,2020(uintmax_t)vif->bss_conf.sync_tsf,2021vif->bss_conf.sync_device_ts,2022(uintmax_t)bss_changed);2023#endif20242025return (bss_changed);2026}20272028static void2029lkpi_stop_hw_scan(struct lkpi_hw *lhw, struct ieee80211_vif *vif)2030{2031struct ieee80211_hw *hw;2032int error;2033bool cancel;20342035TRACE_SCAN(lhw->ic, "scan_flags %b", lhw->scan_flags, LKPI_LHW_SCAN_BITS);20362037LKPI_80211_LHW_SCAN_LOCK(lhw);2038cancel = (lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0;2039LKPI_80211_LHW_SCAN_UNLOCK(lhw);2040if (!cancel)2041return;20422043hw = LHW_TO_HW(lhw);20442045IEEE80211_UNLOCK(lhw->ic);2046wiphy_lock(hw->wiphy);2047/* Need to cancel the scan. */2048lkpi_80211_mo_cancel_hw_scan(hw, vif);2049wiphy_unlock(hw->wiphy);20502051/* Need to make sure we see ieee80211_scan_completed. */2052LKPI_80211_LHW_SCAN_LOCK(lhw);2053if ((lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0)2054error = msleep(lhw, &lhw->scan_mtx, 0, "lhwscanstop", hz/2);2055cancel = (lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0;2056LKPI_80211_LHW_SCAN_UNLOCK(lhw);20572058IEEE80211_LOCK(lhw->ic);20592060if (cancel)2061ic_printf(lhw->ic, "%s: failed to cancel scan: %d (%p, %p)\n",2062__func__, error, lhw, vif);2063}20642065static void2066lkpi_hw_conf_idle(struct ieee80211_hw *hw, bool new)2067{2068struct lkpi_hw *lhw;2069int error;2070bool old;20712072old = hw->conf.flags & IEEE80211_CONF_IDLE;2073if (old == new)2074return;20752076hw->conf.flags ^= IEEE80211_CONF_IDLE;2077error = lkpi_80211_mo_config(hw, IEEE80211_CONF_CHANGE_IDLE);2078if (error != 0 && error != EOPNOTSUPP) {2079lhw = HW_TO_LHW(hw);2080ic_printf(lhw->ic, "ERROR: %s: config %#0x returned %d\n",2081__func__, IEEE80211_CONF_CHANGE_IDLE, error);2082}2083}20842085static enum ieee80211_bss_changed2086lkpi_disassoc(struct ieee80211_sta *sta, struct ieee80211_vif *vif,2087struct lkpi_hw *lhw)2088{2089enum ieee80211_bss_changed changed;2090struct lkpi_vif *lvif;20912092changed = 0;2093sta->aid = 0;2094if (vif->cfg.assoc) {20952096vif->cfg.assoc = false;2097vif->cfg.aid = 0;2098changed |= BSS_CHANGED_ASSOC;2099IMPROVE();21002101lkpi_update_mcast_filter(lhw->ic);21022103/*2104* Executing the bss_info_changed(BSS_CHANGED_ASSOC) with2105* assoc = false right away here will remove the sta from2106* firmware for iwlwifi.2107* We no longer do this but only return the BSS_CHNAGED value.2108* The caller is responsible for removing the sta gong to2109* IEEE80211_STA_NOTEXIST and then executing the2110* bss_info_changed() update.2111* See lkpi_sta_run_to_init() for more detailed comment.2112*/21132114lvif = VIF_TO_LVIF(vif);2115lvif->beacons = 0;2116}21172118return (changed);2119}21202121static void2122lkpi_wake_tx_queues(struct ieee80211_hw *hw, struct ieee80211_sta *sta,2123bool dequeue_seen, bool no_emptyq)2124{2125struct lkpi_txq *ltxq;2126int tid;2127bool ltxq_empty;21282129/* Wake up all queues to know they are allocated in the driver. */2130for (tid = 0; tid < nitems(sta->txq); tid++) {21312132if (tid == IEEE80211_NUM_TIDS) {2133IMPROVE("station specific?");2134if (!ieee80211_hw_check(hw, STA_MMPDU_TXQ))2135continue;2136} else if (tid >= hw->queues)2137continue;21382139if (sta->txq[tid] == NULL)2140continue;21412142ltxq = TXQ_TO_LTXQ(sta->txq[tid]);2143if (dequeue_seen && !ltxq->seen_dequeue)2144continue;21452146LKPI_80211_LTXQ_LOCK(ltxq);2147ltxq_empty = skb_queue_empty(<xq->skbq);2148LKPI_80211_LTXQ_UNLOCK(ltxq);2149if (no_emptyq && ltxq_empty)2150continue;21512152lkpi_80211_mo_wake_tx_queue(hw, sta->txq[tid], false);2153}2154}21552156/*2157* On the way down from RUN -> ASSOC -> AUTH we may send a DISASSOC or DEAUTH2158* packet. The problem is that the state machine functions tend to hold the2159* LHW lock which will prevent lkpi_80211_txq_tx_one() from sending the packet.2160* We call this after dropping the ic lock and before acquiring the LHW lock.2161* we make sure no further packets are queued and if they are queued the task2162* will finish or be cancelled. At the end if a packet is left we manually2163* send it. scan_to_auth() would re-enable sending if the lsta would be2164* re-used.2165*/2166static void2167lkpi_80211_flush_tx(struct lkpi_hw *lhw, struct lkpi_sta *lsta)2168{2169struct ieee80211_hw *hw;2170struct mbufq mq;2171struct mbuf *m;2172int len;21732174/* There is no lockdep_assert_not_held_wiphy(). */2175hw = LHW_TO_HW(lhw);2176lockdep_assert_not_held(&hw->wiphy->mtx);21772178/* Do not accept any new packets until scan_to_auth or lsta_free(). */2179LKPI_80211_LSTA_TXQ_LOCK(lsta);2180lsta->txq_ready = false;2181LKPI_80211_LSTA_TXQ_UNLOCK(lsta);21822183while (taskqueue_cancel(taskqueue_thread, &lsta->txq_task, NULL) != 0)2184taskqueue_drain(taskqueue_thread, &lsta->txq_task);21852186LKPI_80211_LSTA_TXQ_LOCK(lsta);2187len = mbufq_len(&lsta->txq);2188if (len <= 0) {2189LKPI_80211_LSTA_TXQ_UNLOCK(lsta);2190return;2191}21922193mbufq_init(&mq, IFQ_MAXLEN);2194mbufq_concat(&mq, &lsta->txq);2195LKPI_80211_LSTA_TXQ_UNLOCK(lsta);21962197m = mbufq_dequeue(&mq);2198while (m != NULL) {2199lkpi_80211_txq_tx_one(lsta, m);2200m = mbufq_dequeue(&mq);2201}2202}220322042205static void2206lkpi_remove_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif)2207{2208struct ieee80211_chanctx_conf *chanctx_conf;2209struct lkpi_chanctx *lchanctx;22102211chanctx_conf = rcu_dereference_protected(vif->bss_conf.chanctx_conf,2212lockdep_is_held(&hw->wiphy->mtx));22132214if (chanctx_conf == NULL)2215return;22162217/* Remove vif context. */2218lkpi_80211_mo_unassign_vif_chanctx(hw, vif, &vif->bss_conf, chanctx_conf);22192220lkpi_hw_conf_idle(hw, true);22212222/* Remove chan ctx. */2223lkpi_80211_mo_remove_chanctx(hw, chanctx_conf);22242225/* Cleanup. */2226rcu_assign_pointer(vif->bss_conf.chanctx_conf, NULL);2227lchanctx = CHANCTX_CONF_TO_LCHANCTX(chanctx_conf);2228list_del(&lchanctx->entry);2229free(lchanctx, M_LKPI80211);2230}223122322233/* -------------------------------------------------------------------------- */22342235static int2236lkpi_sta_state_do_nada(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)2237{22382239return (0);2240}22412242/* lkpi_iv_newstate() handles the stop scan case generally. */2243#define lkpi_sta_scan_to_init(_v, _n, _a) lkpi_sta_state_do_nada(_v, _n, _a)22442245static int2246lkpi_sta_scan_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)2247{2248struct linuxkpi_ieee80211_channel *chan;2249struct lkpi_chanctx *lchanctx;2250struct ieee80211_chanctx_conf *chanctx_conf;2251struct lkpi_hw *lhw;2252struct ieee80211_hw *hw;2253struct lkpi_vif *lvif;2254struct ieee80211_vif *vif;2255struct ieee80211_node *ni;2256struct lkpi_sta *lsta;2257enum ieee80211_bss_changed bss_changed;2258struct ieee80211_prep_tx_info prep_tx_info;2259uint32_t changed;2260int error;2261bool synched;22622263/*2264* In here we use vap->iv_bss until lvif->lvif_bss is set.2265* For all later (STATE >= AUTH) functions we need to use the lvif2266* cache which will be tracked even through (*iv_update_bss)().2267*/22682269if (vap->iv_bss == NULL) {2270ic_printf(vap->iv_ic, "%s: no iv_bss for vap %p\n", __func__, vap);2271return (EINVAL);2272}2273/*2274* Keep the ni alive locally. In theory (and practice) iv_bss can change2275* once we unlock here. This is due to net80211 allowing state changes2276* and new join1() despite having an active node as well as due to2277* the fact that the iv_bss can be swapped under the hood in (*iv_update_bss).2278*/2279ni = ieee80211_ref_node(vap->iv_bss);2280if (ni->ni_chan == NULL || ni->ni_chan == IEEE80211_CHAN_ANYC) {2281ic_printf(vap->iv_ic, "%s: no channel set for iv_bss ni %p "2282"on vap %p\n", __func__, ni, vap);2283ieee80211_free_node(ni); /* Error handling for the local ni. */2284return (EINVAL);2285}22862287lhw = vap->iv_ic->ic_softc;2288chan = lkpi_find_lkpi80211_chan(lhw, ni->ni_chan);2289if (chan == NULL) {2290ic_printf(vap->iv_ic, "%s: failed to get LKPI channel from "2291"iv_bss ni %p on vap %p\n", __func__, ni, vap);2292ieee80211_free_node(ni); /* Error handling for the local ni. */2293return (ESRCH);2294}22952296hw = LHW_TO_HW(lhw);2297lvif = VAP_TO_LVIF(vap);2298vif = LVIF_TO_VIF(lvif);22992300LKPI_80211_LVIF_LOCK(lvif);2301/* XXX-BZ KASSERT later? */2302if (lvif->lvif_bss_synched || lvif->lvif_bss != NULL) {2303ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "2304"lvif_bss->ni %p synched %d\n", __func__, __LINE__,2305lvif, vap, vap->iv_bss, lvif->lvif_bss,2306(lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,2307lvif->lvif_bss_synched);2308LKPI_80211_LVIF_UNLOCK(lvif);2309ieee80211_free_node(ni); /* Error handling for the local ni. */2310return (EBUSY);2311}2312LKPI_80211_LVIF_UNLOCK(lvif);23132314IEEE80211_UNLOCK(vap->iv_ic);2315wiphy_lock(hw->wiphy);23162317/* Add chanctx (or if exists, change it). */2318chanctx_conf = rcu_dereference_protected(vif->bss_conf.chanctx_conf,2319lockdep_is_held(&hw->wiphy->mtx));2320if (chanctx_conf != NULL) {2321lchanctx = CHANCTX_CONF_TO_LCHANCTX(chanctx_conf);2322IMPROVE("diff changes for changed, working on live copy, rcu");2323} else {2324/* Keep separate alloc as in Linux this is rcu managed? */2325lchanctx = malloc(sizeof(*lchanctx) + hw->chanctx_data_size,2326M_LKPI80211, M_WAITOK | M_ZERO);2327chanctx_conf = &lchanctx->chanctx_conf;2328}23292330chanctx_conf->rx_chains_static = 1;2331chanctx_conf->rx_chains_dynamic = 1;2332chanctx_conf->radar_enabled =2333(chan->flags & IEEE80211_CHAN_RADAR) ? true : false;2334chanctx_conf->def.chan = chan;2335chanctx_conf->def.width = NL80211_CHAN_WIDTH_20_NOHT;2336chanctx_conf->def.center_freq1 = ieee80211_get_channel_center_freq1(ni->ni_chan);2337chanctx_conf->def.center_freq2 = ieee80211_get_channel_center_freq2(ni->ni_chan);2338IMPROVE("Check vht_cap from band not just chan?");2339KASSERT(ni->ni_chan != NULL && ni->ni_chan != IEEE80211_CHAN_ANYC,2340("%s:%d: ni %p ni_chan %p\n", __func__, __LINE__, ni, ni->ni_chan));23412342#ifdef LKPI_80211_HT2343if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) {2344if (IEEE80211_IS_CHAN_HT40(ni->ni_chan))2345chanctx_conf->def.width = NL80211_CHAN_WIDTH_40;2346else2347chanctx_conf->def.width = NL80211_CHAN_WIDTH_20;2348}2349#endif2350#ifdef LKPI_80211_VHT2351if (IEEE80211_IS_CHAN_VHT_5GHZ(ni->ni_chan)) {2352if (IEEE80211_IS_CHAN_VHT80P80(ni->ni_chan))2353chanctx_conf->def.width = NL80211_CHAN_WIDTH_80P80;2354else if (IEEE80211_IS_CHAN_VHT160(ni->ni_chan))2355chanctx_conf->def.width = NL80211_CHAN_WIDTH_160;2356else if (IEEE80211_IS_CHAN_VHT80(ni->ni_chan))2357chanctx_conf->def.width = NL80211_CHAN_WIDTH_80;2358}2359#endif2360chanctx_conf->rx_chains_dynamic = lkpi_get_max_rx_chains(ni);2361/* Responder ... */2362#if 02363chanctx_conf->min_def.chan = chanctx_conf->def.chan;2364chanctx_conf->min_def.width = NL80211_CHAN_WIDTH_20_NOHT;2365#ifdef LKPI_80211_HT2366if (IEEE80211_IS_CHAN_HT(ni->ni_chan) || IEEE80211_IS_CHAN_VHT(ni->ni_chan))2367chanctx_conf->min_def.width = NL80211_CHAN_WIDTH_20;2368#endif2369chanctx_conf->min_def.center_freq1 = chanctx_conf->def.center_freq1;2370chanctx_conf->min_def.center_freq2 = chanctx_conf->def.center_freq2;2371#else2372chanctx_conf->min_def = chanctx_conf->def;2373#endif23742375/* Set bss info (bss_info_changed). */2376bss_changed = 0;2377vif->bss_conf.bssid = ni->ni_bssid;2378bss_changed |= BSS_CHANGED_BSSID;2379vif->bss_conf.txpower = ni->ni_txpower;2380bss_changed |= BSS_CHANGED_TXPOWER;2381vif->cfg.idle = false;2382bss_changed |= BSS_CHANGED_IDLE;23832384/* vif->bss_conf.basic_rates ? Where exactly? */23852386lvif->beacons = 0;2387/* Should almost assert it is this. */2388vif->cfg.assoc = false;2389vif->cfg.aid = 0;23902391bss_changed |= lkpi_update_dtim_tsf(vif, ni, vap, __func__, __LINE__);23922393error = 0;2394if (vif->bss_conf.chanctx_conf == chanctx_conf) {2395changed = IEEE80211_CHANCTX_CHANGE_MIN_WIDTH;2396changed |= IEEE80211_CHANCTX_CHANGE_RADAR;2397changed |= IEEE80211_CHANCTX_CHANGE_RX_CHAINS;2398changed |= IEEE80211_CHANCTX_CHANGE_WIDTH;2399lkpi_80211_mo_change_chanctx(hw, chanctx_conf, changed);2400} else {2401/* The device is no longer idle. */2402IMPROVE("Once we do multi-vif, only do for 1st chanctx");2403lkpi_hw_conf_idle(hw, false);24042405error = lkpi_80211_mo_add_chanctx(hw, chanctx_conf);2406if (error == 0 || error == EOPNOTSUPP) {2407vif->bss_conf.chanreq.oper.chan = chanctx_conf->def.chan;2408vif->bss_conf.chanreq.oper.width = chanctx_conf->def.width;2409vif->bss_conf.chanreq.oper.center_freq1 =2410chanctx_conf->def.center_freq1;2411vif->bss_conf.chanreq.oper.center_freq2 =2412chanctx_conf->def.center_freq2;2413} else {2414ic_printf(vap->iv_ic, "%s:%d: mo_add_chanctx "2415"failed: %d\n", __func__, __LINE__, error);2416goto out;2417}24182419list_add_rcu(&lchanctx->entry, &lhw->lchanctx_list);2420rcu_assign_pointer(vif->bss_conf.chanctx_conf, chanctx_conf);24212422/* Assign vif chanctx. */2423if (error == 0)2424error = lkpi_80211_mo_assign_vif_chanctx(hw, vif,2425&vif->bss_conf, chanctx_conf);2426if (error == EOPNOTSUPP)2427error = 0;2428if (error != 0) {2429ic_printf(vap->iv_ic, "%s:%d: mo_assign_vif_chanctx "2430"failed: %d\n", __func__, __LINE__, error);2431lkpi_80211_mo_remove_chanctx(hw, chanctx_conf);2432rcu_assign_pointer(vif->bss_conf.chanctx_conf, NULL);2433lchanctx = CHANCTX_CONF_TO_LCHANCTX(chanctx_conf);2434list_del(&lchanctx->entry);2435free(lchanctx, M_LKPI80211);2436goto out;2437}2438}2439IMPROVE("update radiotap chan fields too");24402441/* RATES */2442IMPROVE("bss info: not all needs to come now and rates are missing");2443lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, bss_changed);24442445/*2446* Given ni and lsta are 1:1 from alloc to free we can assert that2447* ni always has lsta data attach despite net80211 node swapping2448* under the hoods.2449*/2450KASSERT(ni->ni_drv_data != NULL, ("%s: ni %p ni_drv_data %p\n",2451__func__, ni, ni->ni_drv_data));2452lsta = ni->ni_drv_data;24532454/* Insert the [l]sta into the list of known stations. */2455list_add_tail(&lsta->lsta_list, &lvif->lsta_list);24562457/* Add (or adjust) sta and change state (from NOTEXIST) to NONE. */2458KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));2459KASSERT(lsta->state == IEEE80211_STA_NOTEXIST, ("%s: lsta %p state not "2460"NOTEXIST: %#x\n", __func__, lsta, lsta->state));2461error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_NONE);2462if (error != 0) {2463IMPROVE("do we need to undo the chan ctx?");2464ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(NONE) "2465"failed: %d\n", __func__, __LINE__, error);2466goto out;2467}2468#if 02469lsta->added_to_drv = true; /* mo manages. */2470#endif24712472lkpi_lsta_dump(lsta, ni, __func__, __LINE__);24732474#if 02475/*2476* Wakeup all queues now that sta is there so we have as much time to2477* possibly prepare the queue in the driver to be ready for the 1st2478* packet; lkpi_80211_txq_tx_one() still has a workaround as there2479* is no guarantee or way to check.2480* XXX-BZ and by now we know that this does not work on all drivers2481* for all queues.2482*/2483lkpi_wake_tx_queues(hw, LSTA_TO_STA(lsta), false, false);2484#endif24852486/* Start mgd_prepare_tx. */2487memset(&prep_tx_info, 0, sizeof(prep_tx_info));2488prep_tx_info.duration = PREP_TX_INFO_DURATION;2489lkpi_80211_mo_mgd_prepare_tx(hw, vif, &prep_tx_info);2490lsta->in_mgd = true;24912492/*2493* What is going to happen next:2494* - <twiddle> .. we should end up in "auth_to_assoc"2495* - event_callback2496* - update sta_state (NONE to AUTH)2497* - mgd_complete_tx2498* (ideally we'd do that on a callback for something else ...)2499*/25002501wiphy_unlock(hw->wiphy);2502IEEE80211_LOCK(vap->iv_ic);25032504LKPI_80211_LVIF_LOCK(lvif);2505/* Re-check given (*iv_update_bss) could have happened while we were unlocked. */2506if (lvif->lvif_bss_synched || lvif->lvif_bss != NULL ||2507lsta->ni != vap->iv_bss)2508ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "2509"lvif_bss->ni %p synched %d, ni %p lsta %p\n", __func__, __LINE__,2510lvif, vap, vap->iv_bss, lvif->lvif_bss,2511(lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,2512lvif->lvif_bss_synched, ni, lsta);25132514/*2515* Reference the "ni" for caching the lsta/ni in lvif->lvif_bss.2516* Given we cache lsta we use lsta->ni instead of ni here (even though2517* lsta->ni == ni) to be distinct from the rest of the code where we do2518* assume that ni == vap->iv_bss which it may or may not be.2519* So do NOT use iv_bss here anymore as that may have diverged from our2520* function local ni already while ic was unlocked and would lead to2521* inconsistencies. Go and see if we lost a race and do not update2522* lvif_bss_synched in that case.2523*/2524ieee80211_ref_node(lsta->ni);2525lvif->lvif_bss = lsta;2526if (lsta->ni == vap->iv_bss) {2527lvif->lvif_bss_synched = synched = true;2528} else {2529/* Set to un-synched no matter what. */2530lvif->lvif_bss_synched = synched = false;2531/*2532* We do not error as someone has to take us down.2533* If we are followed by a 2nd, new net80211::join1() going to2534* AUTH lkpi_sta_a_to_a() will error, lkpi_sta_auth_to_{scan,init}()2535* will take the lvif->lvif_bss node down eventually.2536* What happens with the vap->iv_bss node will entirely be up2537* to net80211 as we never used the node beyond alloc()/free()2538* and we do not hold an extra reference for that anymore given2539* ni : lsta == 1:1.2540* Problem is if we do not error a MGMT/AUTH frame will be2541* sent from net80211::sta_newstate(); disable lsta queue below.2542*/2543}2544LKPI_80211_LVIF_UNLOCK(lvif);2545/*2546* Make sure in case the sta did not change and we re-added it,2547* that we can tx again but only if the vif/iv_bss are in sync.2548* Otherwise this should prevent the MGMT/AUTH frame from being2549* sent triggering a warning in iwlwifi.2550*/2551LKPI_80211_LSTA_TXQ_LOCK(lsta);2552lsta->txq_ready = synched;2553LKPI_80211_LSTA_TXQ_UNLOCK(lsta);2554goto out_relocked;25552556out:2557wiphy_unlock(hw->wiphy);2558IEEE80211_LOCK(vap->iv_ic);2559out_relocked:2560/*2561* Release the reference that kept the ni stable locally2562* during the work of this function.2563*/2564if (ni != NULL)2565ieee80211_free_node(ni);2566return (error);2567}25682569static int2570lkpi_sta_auth_to_scan(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)2571{2572struct lkpi_hw *lhw;2573struct ieee80211_hw *hw;2574struct lkpi_vif *lvif;2575struct ieee80211_vif *vif;2576struct ieee80211_node *ni;2577struct lkpi_sta *lsta;2578struct ieee80211_sta *sta;2579struct ieee80211_prep_tx_info prep_tx_info;2580enum ieee80211_bss_changed bss_changed;2581int error;25822583lhw = vap->iv_ic->ic_softc;2584hw = LHW_TO_HW(lhw);2585lvif = VAP_TO_LVIF(vap);2586vif = LVIF_TO_VIF(lvif);25872588LKPI_80211_LVIF_LOCK(lvif);2589#ifdef LINUXKPI_DEBUG_802112590/* XXX-BZ KASSERT later; state going down so no action. */2591if (lvif->lvif_bss == NULL)2592ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "2593"lvif_bss->ni %p synched %d\n", __func__, __LINE__,2594lvif, vap, vap->iv_bss, lvif->lvif_bss,2595(lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,2596lvif->lvif_bss_synched);2597#endif25982599lsta = lvif->lvif_bss;2600LKPI_80211_LVIF_UNLOCK(lvif);2601KASSERT(lsta != NULL && lsta->ni != NULL, ("%s: lsta %p ni %p "2602"lvif %p vap %p\n", __func__,2603lsta, (lsta != NULL) ? lsta->ni : NULL, lvif, vap));2604ni = lsta->ni; /* Reference held for lvif_bss. */2605sta = LSTA_TO_STA(lsta);26062607lkpi_lsta_dump(lsta, ni, __func__, __LINE__);26082609IEEE80211_UNLOCK(vap->iv_ic);2610wiphy_lock(hw->wiphy);26112612/* flush, drop. */2613lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), true);26142615/* Wake tx queues to get packet(s) out. */2616lkpi_wake_tx_queues(hw, sta, false, true);26172618/* flush, no drop */2619lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), false);26202621/* End mgd_complete_tx. */2622if (lsta->in_mgd) {2623memset(&prep_tx_info, 0, sizeof(prep_tx_info));2624prep_tx_info.success = false;2625lkpi_80211_mo_mgd_complete_tx(hw, vif, &prep_tx_info);2626lsta->in_mgd = false;2627}26282629/* sync_rx_queues */2630lkpi_80211_mo_sync_rx_queues(hw);26312632/* sta_pre_rcu_remove */2633lkpi_80211_mo_sta_pre_rcu_remove(hw, vif, sta);26342635/* Take the station down. */26362637/* Adjust sta and change state (from NONE) to NOTEXIST. */2638KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));2639KASSERT(lsta->state == IEEE80211_STA_NONE, ("%s: lsta %p state not "2640"NONE: %#x, nstate %d arg %d\n", __func__, lsta, lsta->state, nstate, arg));2641error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_NOTEXIST);2642if (error != 0) {2643IMPROVE("do we need to undo the chan ctx?");2644ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(NOTEXIST) "2645"failed: %d\n", __func__, __LINE__, error);2646goto out;2647}2648#if 02649lsta->added_to_drv = false; /* mo manages. */2650#endif26512652bss_changed = 0;2653vif->bss_conf.dtim_period = 0; /* go back to 0. */2654bss_changed |= BSS_CHANGED_BEACON_INFO;2655lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, bss_changed);26562657lkpi_lsta_dump(lsta, ni, __func__, __LINE__);26582659LKPI_80211_LVIF_LOCK(lvif);2660/* Remove ni reference for this cache of lsta. */2661lvif->lvif_bss = NULL;2662lvif->lvif_bss_synched = false;2663LKPI_80211_LVIF_UNLOCK(lvif);2664lkpi_lsta_remove(lsta, lvif);26652666/* conf_tx */26672668lkpi_remove_chanctx(hw, vif);26692670out:2671wiphy_unlock(hw->wiphy);2672IEEE80211_LOCK(vap->iv_ic);2673if (error == 0) {2674/*2675* We do this outside the wiphy lock as net80211::node_free() may call2676* into crypto code to delete keys and we have a recursed on2677* non-recursive sx panic. Also only do this if we get here w/o error.2678*2679* The very last release the reference on the ni for the ni/lsta on2680* lvif->lvif_bss. Upon return from this both ni and lsta are invalid2681* and potentially freed.2682*/2683ieee80211_free_node(ni);2684}2685return (error);2686}26872688static int2689lkpi_sta_auth_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)2690{2691int error;26922693error = lkpi_sta_auth_to_scan(vap, nstate, arg);2694if (error == 0)2695error = lkpi_sta_scan_to_init(vap, nstate, arg);2696return (error);2697}26982699static int2700lkpi_sta_auth_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)2701{2702struct lkpi_hw *lhw;2703struct ieee80211_hw *hw;2704struct lkpi_vif *lvif;2705struct ieee80211_vif *vif;2706struct lkpi_sta *lsta;2707struct ieee80211_prep_tx_info prep_tx_info;2708int error;27092710lhw = vap->iv_ic->ic_softc;2711hw = LHW_TO_HW(lhw);2712lvif = VAP_TO_LVIF(vap);2713vif = LVIF_TO_VIF(lvif);27142715IEEE80211_UNLOCK(vap->iv_ic);2716wiphy_lock(hw->wiphy);27172718LKPI_80211_LVIF_LOCK(lvif);2719/* XXX-BZ KASSERT later? */2720if (!lvif->lvif_bss_synched || lvif->lvif_bss == NULL) {2721#ifdef LINUXKPI_DEBUG_802112722ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "2723"lvif_bss->ni %p synched %d\n", __func__, __LINE__,2724lvif, vap, vap->iv_bss, lvif->lvif_bss,2725(lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,2726lvif->lvif_bss_synched);2727#endif2728error = ENOTRECOVERABLE;2729LKPI_80211_LVIF_UNLOCK(lvif);2730goto out;2731}2732lsta = lvif->lvif_bss;2733LKPI_80211_LVIF_UNLOCK(lvif);27342735KASSERT(lsta != NULL, ("%s: lsta %p\n", __func__, lsta));27362737/* Finish auth. */2738IMPROVE("event callback");27392740/* Update sta_state (NONE to AUTH). */2741KASSERT(lsta->state == IEEE80211_STA_NONE, ("%s: lsta %p state not "2742"NONE: %#x\n", __func__, lsta, lsta->state));2743error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_AUTH);2744if (error != 0) {2745ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(AUTH) "2746"failed: %d\n", __func__, __LINE__, error);2747goto out;2748}27492750/* End mgd_complete_tx. */2751if (lsta->in_mgd) {2752memset(&prep_tx_info, 0, sizeof(prep_tx_info));2753prep_tx_info.success = true;2754lkpi_80211_mo_mgd_complete_tx(hw, vif, &prep_tx_info);2755lsta->in_mgd = false;2756}27572758/* Now start assoc. */27592760/* Start mgd_prepare_tx. */2761if (!lsta->in_mgd) {2762memset(&prep_tx_info, 0, sizeof(prep_tx_info));2763prep_tx_info.duration = PREP_TX_INFO_DURATION;2764lkpi_80211_mo_mgd_prepare_tx(hw, vif, &prep_tx_info);2765lsta->in_mgd = true;2766}27672768/* Wake tx queue to get packet out. */2769lkpi_wake_tx_queues(hw, LSTA_TO_STA(lsta), false, true);27702771/*2772* <twiddle> .. we end up in "assoc_to_run"2773* - update sta_state (AUTH to ASSOC)2774* - conf_tx [all]2775* - bss_info_changed (assoc, aid, ssid, ..)2776* - change_chanctx (if needed)2777* - event_callback2778* - mgd_complete_tx2779*/27802781out:2782wiphy_unlock(hw->wiphy);2783IEEE80211_LOCK(vap->iv_ic);2784return (error);2785}27862787/* auth_to_auth, assoc_to_assoc. */2788static int2789lkpi_sta_a_to_a(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)2790{2791struct lkpi_hw *lhw;2792struct ieee80211_hw *hw;2793struct lkpi_vif *lvif;2794struct ieee80211_vif *vif;2795struct lkpi_sta *lsta;2796struct ieee80211_prep_tx_info prep_tx_info;2797int error;27982799lhw = vap->iv_ic->ic_softc;2800hw = LHW_TO_HW(lhw);2801lvif = VAP_TO_LVIF(vap);2802vif = LVIF_TO_VIF(lvif);28032804IEEE80211_UNLOCK(vap->iv_ic);2805wiphy_lock(hw->wiphy);28062807LKPI_80211_LVIF_LOCK(lvif);2808/* XXX-BZ KASSERT later? */2809if (!lvif->lvif_bss_synched || lvif->lvif_bss == NULL) {2810#ifdef LINUXKPI_DEBUG_802112811ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "2812"lvif_bss->ni %p synched %d\n", __func__, __LINE__,2813lvif, vap, vap->iv_bss, lvif->lvif_bss,2814(lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,2815lvif->lvif_bss_synched);2816#endif2817LKPI_80211_LVIF_UNLOCK(lvif);2818error = ENOTRECOVERABLE;2819goto out;2820}2821lsta = lvif->lvif_bss;2822LKPI_80211_LVIF_UNLOCK(lvif);28232824KASSERT(lsta != NULL, ("%s: lsta %p! lvif %p vap %p\n", __func__,2825lsta, lvif, vap));28262827IMPROVE("event callback?");28282829/* End mgd_complete_tx. */2830if (lsta->in_mgd) {2831memset(&prep_tx_info, 0, sizeof(prep_tx_info));2832prep_tx_info.success = false;2833lkpi_80211_mo_mgd_complete_tx(hw, vif, &prep_tx_info);2834lsta->in_mgd = false;2835}28362837/* Now start assoc. */28382839/* Start mgd_prepare_tx. */2840if (!lsta->in_mgd) {2841memset(&prep_tx_info, 0, sizeof(prep_tx_info));2842prep_tx_info.duration = PREP_TX_INFO_DURATION;2843lkpi_80211_mo_mgd_prepare_tx(hw, vif, &prep_tx_info);2844lsta->in_mgd = true;2845}28462847error = 0;2848out:2849wiphy_unlock(hw->wiphy);2850IEEE80211_LOCK(vap->iv_ic);28512852return (error);2853}28542855static int2856_lkpi_sta_assoc_to_down(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)2857{2858struct lkpi_hw *lhw;2859struct ieee80211_hw *hw;2860struct lkpi_vif *lvif;2861struct ieee80211_vif *vif;2862struct ieee80211_node *ni;2863struct lkpi_sta *lsta;2864struct ieee80211_sta *sta;2865struct ieee80211_prep_tx_info prep_tx_info;2866enum ieee80211_bss_changed bss_changed;2867int error;28682869lhw = vap->iv_ic->ic_softc;2870hw = LHW_TO_HW(lhw);2871lvif = VAP_TO_LVIF(vap);2872vif = LVIF_TO_VIF(lvif);28732874IEEE80211_UNLOCK(vap->iv_ic);2875wiphy_lock(hw->wiphy);28762877LKPI_80211_LVIF_LOCK(lvif);2878#ifdef LINUXKPI_DEBUG_802112879/* XXX-BZ KASSERT later; state going down so no action. */2880if (lvif->lvif_bss == NULL)2881ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "2882"lvif_bss->ni %p synched %d\n", __func__, __LINE__,2883lvif, vap, vap->iv_bss, lvif->lvif_bss,2884(lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,2885lvif->lvif_bss_synched);2886#endif2887lsta = lvif->lvif_bss;2888LKPI_80211_LVIF_UNLOCK(lvif);2889KASSERT(lsta != NULL && lsta->ni != NULL, ("%s: lsta %p ni %p "2890"lvif %p vap %p\n", __func__,2891lsta, (lsta != NULL) ? lsta->ni : NULL, lvif, vap));28922893ni = lsta->ni; /* Reference held for lvif_bss. */2894sta = LSTA_TO_STA(lsta);28952896lkpi_lsta_dump(lsta, ni, __func__, __LINE__);28972898/* flush, drop. */2899lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), true);29002901IMPROVE("What are the proper conditions for DEAUTH_NEED_MGD_TX_PREP?");2902if (ieee80211_hw_check(hw, DEAUTH_NEED_MGD_TX_PREP) &&2903!lsta->in_mgd) {2904memset(&prep_tx_info, 0, sizeof(prep_tx_info));2905prep_tx_info.duration = PREP_TX_INFO_DURATION;2906prep_tx_info.was_assoc = true;2907lkpi_80211_mo_mgd_prepare_tx(hw, vif, &prep_tx_info);2908lsta->in_mgd = true;2909}29102911wiphy_unlock(hw->wiphy);2912IEEE80211_LOCK(vap->iv_ic);29132914/* Call iv_newstate first so we get potential DEAUTH packet out. */2915error = lvif->iv_newstate(vap, nstate, arg);2916if (error != 0) {2917ic_printf(vap->iv_ic, "%s:%d: iv_newstate(%p, %d, %d) "2918"failed: %d\n", __func__, __LINE__, vap, nstate, arg, error);2919goto outni;2920}29212922IEEE80211_UNLOCK(vap->iv_ic);29232924/* Ensure the packets get out. */2925lkpi_80211_flush_tx(lhw, lsta);29262927wiphy_lock(hw->wiphy);29282929lkpi_lsta_dump(lsta, ni, __func__, __LINE__);29302931/* Wake tx queues to get packet(s) out. */2932lkpi_wake_tx_queues(hw, sta, false, true);29332934/* flush, no drop */2935lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), false);29362937/* End mgd_complete_tx. */2938if (lsta->in_mgd) {2939memset(&prep_tx_info, 0, sizeof(prep_tx_info));2940prep_tx_info.success = false;2941prep_tx_info.was_assoc = true;2942lkpi_80211_mo_mgd_complete_tx(hw, vif, &prep_tx_info);2943lsta->in_mgd = false;2944}29452946/* sync_rx_queues */2947lkpi_80211_mo_sync_rx_queues(hw);29482949/* sta_pre_rcu_remove */2950lkpi_80211_mo_sta_pre_rcu_remove(hw, vif, sta);29512952/* Take the station down. */29532954/* Update sta and change state (from AUTH) to NONE. */2955KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));2956KASSERT(lsta->state == IEEE80211_STA_AUTH, ("%s: lsta %p state not "2957"AUTH: %#x\n", __func__, lsta, lsta->state));2958error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_NONE);2959if (error != 0) {2960ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(NONE) "2961"failed: %d\n", __func__, __LINE__, error);2962goto out;2963}29642965/* See comment in lkpi_sta_run_to_init(). */2966bss_changed = 0;2967bss_changed |= lkpi_disassoc(sta, vif, lhw);29682969#ifdef LKPI_80211_HW_CRYPTO2970/*2971* In theory we remove keys here but there must not exist any for this2972* state change until we clean them up again into small steps and no2973* code duplication.2974*/2975#endif29762977lkpi_lsta_dump(lsta, ni, __func__, __LINE__);29782979/* Adjust sta and change state (from NONE) to NOTEXIST. */2980KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));2981KASSERT(lsta->state == IEEE80211_STA_NONE, ("%s: lsta %p state not "2982"NONE: %#x, nstate %d arg %d\n", __func__, lsta, lsta->state, nstate, arg));2983error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_NOTEXIST);2984if (error != 0) {2985IMPROVE("do we need to undo the chan ctx?");2986ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(NOTEXIST) "2987"failed: %d\n", __func__, __LINE__, error);2988goto out;2989}29902991lkpi_lsta_dump(lsta, ni, __func__, __LINE__); /* sta no longer save to use. */29922993IMPROVE("Any bss_info changes to announce?");2994vif->bss_conf.qos = 0;2995bss_changed |= BSS_CHANGED_QOS;2996vif->cfg.ssid_len = 0;2997memset(vif->cfg.ssid, '\0', sizeof(vif->cfg.ssid));2998bss_changed |= BSS_CHANGED_BSSID;2999vif->bss_conf.dtim_period = 0; /* go back to 0. */3000bss_changed |= BSS_CHANGED_BEACON_INFO;3001lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, bss_changed);30023003LKPI_80211_LVIF_LOCK(lvif);3004/* Remove ni reference for this cache of lsta. */3005lvif->lvif_bss = NULL;3006lvif->lvif_bss_synched = false;3007LKPI_80211_LVIF_UNLOCK(lvif);3008lkpi_lsta_remove(lsta, lvif);30093010/* conf_tx */30113012lkpi_remove_chanctx(hw, vif);30133014error = EALREADY;3015out:3016wiphy_unlock(hw->wiphy);3017IEEE80211_LOCK(vap->iv_ic);3018if (error == EALREADY) {3019/*3020* We do this outside the wiphy lock as net80211::node_free() may call3021* into crypto code to delete keys and we have a recursed on3022* non-recursive sx panic. Also only do this if we get here w/o error.3023*3024* The very last release the reference on the ni for the ni/lsta on3025* lvif->lvif_bss. Upon return from this both ni and lsta are invalid3026* and potentially freed.3027*/3028ieee80211_free_node(ni);3029}3030outni:3031return (error);3032}30333034static int3035lkpi_sta_assoc_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)3036{3037int error;30383039error = _lkpi_sta_assoc_to_down(vap, nstate, arg);3040if (error != 0 && error != EALREADY)3041return (error);30423043/* At this point iv_bss is long a new node! */30443045error |= lkpi_sta_scan_to_auth(vap, nstate, 0);3046return (error);3047}30483049static int3050lkpi_sta_assoc_to_scan(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)3051{3052int error;30533054error = _lkpi_sta_assoc_to_down(vap, nstate, arg);3055return (error);3056}30573058static int3059lkpi_sta_assoc_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)3060{3061int error;30623063error = _lkpi_sta_assoc_to_down(vap, nstate, arg);3064return (error);3065}30663067static int3068lkpi_sta_assoc_to_run(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)3069{3070struct lkpi_hw *lhw;3071struct ieee80211_hw *hw;3072struct lkpi_vif *lvif;3073struct ieee80211_vif *vif;3074struct ieee80211_node *ni;3075struct lkpi_sta *lsta;3076struct ieee80211_sta *sta;3077struct ieee80211_prep_tx_info prep_tx_info;3078enum ieee80211_bss_changed bss_changed;3079int error;30803081lhw = vap->iv_ic->ic_softc;3082hw = LHW_TO_HW(lhw);3083lvif = VAP_TO_LVIF(vap);3084vif = LVIF_TO_VIF(lvif);30853086IEEE80211_UNLOCK(vap->iv_ic);3087wiphy_lock(hw->wiphy);30883089LKPI_80211_LVIF_LOCK(lvif);3090/* XXX-BZ KASSERT later? */3091if (!lvif->lvif_bss_synched || lvif->lvif_bss == NULL) {3092#ifdef LINUXKPI_DEBUG_802113093ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "3094"lvif_bss->ni %p synched %d\n", __func__, __LINE__,3095lvif, vap, vap->iv_bss, lvif->lvif_bss,3096(lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,3097lvif->lvif_bss_synched);3098#endif3099LKPI_80211_LVIF_UNLOCK(lvif);3100error = ENOTRECOVERABLE;3101goto out;3102}3103lsta = lvif->lvif_bss;3104LKPI_80211_LVIF_UNLOCK(lvif);3105KASSERT(lsta != NULL && lsta->ni != NULL, ("%s: lsta %p ni %p "3106"lvif %p vap %p\n", __func__,3107lsta, (lsta != NULL) ? lsta->ni : NULL, lvif, vap));31083109ni = lsta->ni; /* Reference held for lvif_bss. */31103111IMPROVE("ponder some of this moved to ic_newassoc, scan_assoc_success, "3112"and to lesser extend ieee80211_notify_node_join");31133114/* Finish assoc. */3115/* Update sta_state (AUTH to ASSOC) and set aid. */3116KASSERT(lsta->state == IEEE80211_STA_AUTH, ("%s: lsta %p state not "3117"AUTH: %#x\n", __func__, lsta, lsta->state));3118sta = LSTA_TO_STA(lsta);3119sta->aid = IEEE80211_NODE_AID(ni);3120#ifdef LKPI_80211_WME3121if (vap->iv_flags & IEEE80211_F_WME)3122sta->wme = true;3123#endif3124error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_ASSOC);3125if (error != 0) {3126ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(ASSOC) "3127"failed: %d\n", __func__, __LINE__, error);3128goto out;3129}31303131IMPROVE("wme / conf_tx [all]");31323133/* Update bss info (bss_info_changed) (assoc, aid, ..). */3134bss_changed = 0;3135#ifdef LKPI_80211_WME3136bss_changed |= lkpi_wme_update(lhw, vap, true);3137#endif3138if (!vif->cfg.assoc || vif->cfg.aid != IEEE80211_NODE_AID(ni)) {3139lvif->beacons = 0;3140vif->cfg.assoc = true;3141vif->cfg.aid = IEEE80211_NODE_AID(ni);3142bss_changed |= BSS_CHANGED_ASSOC;3143}3144/* We set SSID but this is not BSSID! */3145vif->cfg.ssid_len = ni->ni_esslen;3146memcpy(vif->cfg.ssid, ni->ni_essid, ni->ni_esslen);3147if ((vap->iv_flags & IEEE80211_F_SHPREAMBLE) !=3148vif->bss_conf.use_short_preamble) {3149vif->bss_conf.use_short_preamble ^= 1;3150/* bss_changed |= BSS_CHANGED_??? */3151}3152if ((vap->iv_flags & IEEE80211_F_SHSLOT) !=3153vif->bss_conf.use_short_slot) {3154vif->bss_conf.use_short_slot ^= 1;3155/* bss_changed |= BSS_CHANGED_??? */3156}3157if ((ni->ni_flags & IEEE80211_NODE_QOS) !=3158vif->bss_conf.qos) {3159vif->bss_conf.qos ^= 1;3160bss_changed |= BSS_CHANGED_QOS;3161}31623163bss_changed |= lkpi_update_dtim_tsf(vif, ni, vap, __func__, __LINE__);3164lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, bss_changed);31653166/* - change_chanctx (if needed)3167* - event_callback3168*/31693170/* End mgd_complete_tx. */3171if (lsta->in_mgd) {3172memset(&prep_tx_info, 0, sizeof(prep_tx_info));3173prep_tx_info.success = true;3174lkpi_80211_mo_mgd_complete_tx(hw, vif, &prep_tx_info);3175lsta->in_mgd = false;3176}31773178/*3179* And then:3180* - (more packets)?3181* - set_key3182* - set_default_unicast_key3183* - set_key (?)3184* - ipv6_addr_change (?)3185*/31863187if (!ieee80211_node_is_authorized(ni)) {3188IMPROVE("net80211 does not consider node authorized");3189}31903191IMPROVE("Is this the right spot, has net80211 done all updates already?");3192lkpi_sta_sync_from_ni(hw, vif, sta, ni, true);31933194/* Update thresholds. */3195hw->wiphy->frag_threshold = vap->iv_fragthreshold;3196lkpi_80211_mo_set_frag_threshold(hw, vap->iv_fragthreshold);3197hw->wiphy->rts_threshold = vap->iv_rtsthreshold;3198lkpi_80211_mo_set_rts_threshold(hw, vap->iv_rtsthreshold);31993200/* Update sta_state (ASSOC to AUTHORIZED). */3201KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));3202KASSERT(lsta->state == IEEE80211_STA_ASSOC, ("%s: lsta %p state not "3203"ASSOC: %#x\n", __func__, lsta, lsta->state));3204error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_AUTHORIZED);3205if (error != 0) {3206IMPROVE("undo some changes?");3207ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(AUTHORIZED) "3208"failed: %d\n", __func__, __LINE__, error);3209goto out;3210}32113212/* - drv_config (?)3213* - bss_info_changed3214* - set_rekey_data (?)3215*3216* And now we should be passing packets.3217*/3218IMPROVE("Need that bssid setting, and the keys");32193220bss_changed = 0;3221bss_changed |= lkpi_update_dtim_tsf(vif, ni, vap, __func__, __LINE__);3222lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, bss_changed);32233224/* Prepare_multicast && configure_filter. */3225lkpi_update_mcast_filter(vap->iv_ic);32263227out:3228wiphy_unlock(hw->wiphy);3229IEEE80211_LOCK(vap->iv_ic);3230return (error);3231}32323233static int3234lkpi_sta_auth_to_run(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)3235{3236int error;32373238error = lkpi_sta_auth_to_assoc(vap, nstate, arg);3239if (error == 0)3240error = lkpi_sta_assoc_to_run(vap, nstate, arg);3241return (error);3242}32433244static int3245lkpi_sta_run_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)3246{3247struct lkpi_hw *lhw;3248struct ieee80211_hw *hw;3249struct lkpi_vif *lvif;3250struct ieee80211_vif *vif;3251struct ieee80211_node *ni;3252struct lkpi_sta *lsta;3253struct ieee80211_sta *sta;3254struct ieee80211_prep_tx_info prep_tx_info;3255#if 03256enum ieee80211_bss_changed bss_changed;3257#endif3258int error;32593260lhw = vap->iv_ic->ic_softc;3261hw = LHW_TO_HW(lhw);3262lvif = VAP_TO_LVIF(vap);3263vif = LVIF_TO_VIF(lvif);32643265LKPI_80211_LVIF_LOCK(lvif);3266#ifdef LINUXKPI_DEBUG_802113267/* XXX-BZ KASSERT later; state going down so no action. */3268if (lvif->lvif_bss == NULL)3269ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "3270"lvif_bss->ni %p synched %d\n", __func__, __LINE__,3271lvif, vap, vap->iv_bss, lvif->lvif_bss,3272(lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,3273lvif->lvif_bss_synched);3274#endif3275lsta = lvif->lvif_bss;3276LKPI_80211_LVIF_UNLOCK(lvif);3277KASSERT(lsta != NULL && lsta->ni != NULL, ("%s: lsta %p ni %p "3278"lvif %p vap %p\n", __func__,3279lsta, (lsta != NULL) ? lsta->ni : NULL, lvif, vap));32803281ni = lsta->ni; /* Reference held for lvif_bss. */3282sta = LSTA_TO_STA(lsta);32833284lkpi_lsta_dump(lsta, ni, __func__, __LINE__);32853286IEEE80211_UNLOCK(vap->iv_ic);3287wiphy_lock(hw->wiphy);32883289/* flush, drop. */3290lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), true);32913292IMPROVE("What are the proper conditions for DEAUTH_NEED_MGD_TX_PREP?");3293if (ieee80211_hw_check(hw, DEAUTH_NEED_MGD_TX_PREP) &&3294!lsta->in_mgd) {3295memset(&prep_tx_info, 0, sizeof(prep_tx_info));3296prep_tx_info.duration = PREP_TX_INFO_DURATION;3297prep_tx_info.was_assoc = true;3298lkpi_80211_mo_mgd_prepare_tx(hw, vif, &prep_tx_info);3299lsta->in_mgd = true;3300}33013302wiphy_unlock(hw->wiphy);3303IEEE80211_LOCK(vap->iv_ic);33043305/* Call iv_newstate first so we get potential DISASSOC packet out. */3306error = lvif->iv_newstate(vap, nstate, arg);3307if (error != 0) {3308ic_printf(vap->iv_ic, "%s:%d: iv_newstate(%p, %d, %d) "3309"failed: %d\n", __func__, __LINE__, vap, nstate, arg, error);3310goto outni;3311}33123313IEEE80211_UNLOCK(vap->iv_ic);33143315/* Ensure the packets get out. */3316lkpi_80211_flush_tx(lhw, lsta);33173318wiphy_lock(hw->wiphy);33193320lkpi_lsta_dump(lsta, ni, __func__, __LINE__);33213322/* Wake tx queues to get packet(s) out. */3323lkpi_wake_tx_queues(hw, sta, false, true);33243325/* flush, no drop */3326lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), false);33273328/* End mgd_complete_tx. */3329if (lsta->in_mgd) {3330memset(&prep_tx_info, 0, sizeof(prep_tx_info));3331prep_tx_info.success = false;3332prep_tx_info.was_assoc = true;3333lkpi_80211_mo_mgd_complete_tx(hw, vif, &prep_tx_info);3334lsta->in_mgd = false;3335}33363337#if 03338/* sync_rx_queues */3339lkpi_80211_mo_sync_rx_queues(hw);33403341/* sta_pre_rcu_remove */3342lkpi_80211_mo_sta_pre_rcu_remove(hw, vif, sta);3343#endif33443345/* Take the station down. */33463347/* Adjust sta and change state (from AUTHORIZED) to ASSOC. */3348KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));3349KASSERT(lsta->state == IEEE80211_STA_AUTHORIZED, ("%s: lsta %p state not "3350"AUTHORIZED: %#x\n", __func__, lsta, lsta->state));3351error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_ASSOC);3352if (error != 0) {3353ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(ASSOC) "3354"failed: %d\n", __func__, __LINE__, error);3355goto out;3356}33573358lkpi_lsta_dump(lsta, ni, __func__, __LINE__);33593360#ifdef LKPI_80211_HW_CRYPTO3361if (lkpi_hwcrypto) {3362error = lkpi_sta_del_keys(hw, vif, lsta);3363if (error != 0) {3364ic_printf(vap->iv_ic, "%s:%d: lkpi_sta_del_keys "3365"failed: %d\n", __func__, __LINE__, error);3366/*3367* Either drv/fw will crash or cleanup itself,3368* otherwise net80211 will delete the keys (at a3369* less appropriate time).3370*/3371/* goto out; */3372}3373}3374#endif33753376/* Update sta_state (ASSOC to AUTH). */3377KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));3378KASSERT(lsta->state == IEEE80211_STA_ASSOC, ("%s: lsta %p state not "3379"ASSOC: %#x\n", __func__, lsta, lsta->state));3380error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_AUTH);3381if (error != 0) {3382ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(AUTH) "3383"failed: %d\n", __func__, __LINE__, error);3384goto out;3385}33863387lkpi_lsta_dump(lsta, ni, __func__, __LINE__);33883389#if 03390/* Update bss info (bss_info_changed) (assoc, aid, ..). */3391lkpi_disassoc(sta, vif, lhw);3392#endif33933394error = EALREADY;3395out:3396wiphy_unlock(hw->wiphy);3397IEEE80211_LOCK(vap->iv_ic);3398outni:3399return (error);3400}34013402static int3403lkpi_sta_run_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)3404{3405struct lkpi_hw *lhw;3406struct ieee80211_hw *hw;3407struct lkpi_vif *lvif;3408struct ieee80211_vif *vif;3409struct ieee80211_node *ni;3410struct lkpi_sta *lsta;3411struct ieee80211_sta *sta;3412struct ieee80211_prep_tx_info prep_tx_info;3413enum ieee80211_bss_changed bss_changed;3414int error;34153416lhw = vap->iv_ic->ic_softc;3417hw = LHW_TO_HW(lhw);3418lvif = VAP_TO_LVIF(vap);3419vif = LVIF_TO_VIF(lvif);34203421IEEE80211_UNLOCK(vap->iv_ic);3422wiphy_lock(hw->wiphy);34233424LKPI_80211_LVIF_LOCK(lvif);3425#ifdef LINUXKPI_DEBUG_802113426/* XXX-BZ KASSERT later; state going down so no action. */3427if (lvif->lvif_bss == NULL)3428ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "3429"lvif_bss->ni %p synched %d\n", __func__, __LINE__,3430lvif, vap, vap->iv_bss, lvif->lvif_bss,3431(lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,3432lvif->lvif_bss_synched);3433#endif3434lsta = lvif->lvif_bss;3435LKPI_80211_LVIF_UNLOCK(lvif);3436KASSERT(lsta != NULL && lsta->ni != NULL, ("%s: lsta %p ni %p "3437"lvif %p vap %p\n", __func__,3438lsta, (lsta != NULL) ? lsta->ni : NULL, lvif, vap));34393440ni = lsta->ni; /* Reference held for lvif_bss. */3441sta = LSTA_TO_STA(lsta);34423443lkpi_lsta_dump(lsta, ni, __func__, __LINE__);34443445/* flush, drop. */3446lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), true);34473448IMPROVE("What are the proper conditions for DEAUTH_NEED_MGD_TX_PREP?");3449if (ieee80211_hw_check(hw, DEAUTH_NEED_MGD_TX_PREP) &&3450!lsta->in_mgd) {3451memset(&prep_tx_info, 0, sizeof(prep_tx_info));3452prep_tx_info.duration = PREP_TX_INFO_DURATION;3453prep_tx_info.was_assoc = true;3454lkpi_80211_mo_mgd_prepare_tx(hw, vif, &prep_tx_info);3455lsta->in_mgd = true;3456}34573458wiphy_unlock(hw->wiphy);3459IEEE80211_LOCK(vap->iv_ic);34603461/* Call iv_newstate first so we get potential DISASSOC packet out. */3462error = lvif->iv_newstate(vap, nstate, arg);3463if (error != 0) {3464ic_printf(vap->iv_ic, "%s:%d: iv_newstate(%p, %d, %d) "3465"failed: %d\n", __func__, __LINE__, vap, nstate, arg, error);3466goto outni;3467}34683469IEEE80211_UNLOCK(vap->iv_ic);34703471/* Ensure the packets get out. */3472lkpi_80211_flush_tx(lhw, lsta);34733474wiphy_lock(hw->wiphy);34753476lkpi_lsta_dump(lsta, ni, __func__, __LINE__);34773478/* Wake tx queues to get packet(s) out. */3479lkpi_wake_tx_queues(hw, sta, false, true);34803481/* flush, no drop */3482lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), false);34833484/* End mgd_complete_tx. */3485if (lsta->in_mgd) {3486memset(&prep_tx_info, 0, sizeof(prep_tx_info));3487prep_tx_info.success = false;3488prep_tx_info.was_assoc = true;3489lkpi_80211_mo_mgd_complete_tx(hw, vif, &prep_tx_info);3490lsta->in_mgd = false;3491}34923493/* sync_rx_queues */3494lkpi_80211_mo_sync_rx_queues(hw);34953496/* sta_pre_rcu_remove */3497lkpi_80211_mo_sta_pre_rcu_remove(hw, vif, sta);34983499/* Take the station down. */35003501/* Adjust sta and change state (from AUTHORIZED) to ASSOC. */3502KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));3503KASSERT(lsta->state == IEEE80211_STA_AUTHORIZED, ("%s: lsta %p state not "3504"AUTHORIZED: %#x\n", __func__, lsta, lsta->state));3505error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_ASSOC);3506if (error != 0) {3507ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(ASSOC) "3508"failed: %d\n", __func__, __LINE__, error);3509goto out;3510}35113512lkpi_lsta_dump(lsta, ni, __func__, __LINE__);35133514#ifdef LKPI_80211_HW_CRYPTO3515if (lkpi_hwcrypto) {3516/*3517* In theory we only need to do this if we changed assoc.3518* If we were not assoc, there should be no keys and we3519* should not be here.3520*/3521#ifdef notyet3522KASSERT((bss_changed & BSS_CHANGED_ASSOC) != 0, ("%s: "3523"trying to remove keys but were not assoc: %#010jx, lvif %p\n",3524__func__, (uintmax_t)bss_changed, lvif));3525#endif3526error = lkpi_sta_del_keys(hw, vif, lsta);3527if (error != 0) {3528ic_printf(vap->iv_ic, "%s:%d: lkpi_sta_del_keys "3529"failed: %d\n", __func__, __LINE__, error);3530/*3531* Either drv/fw will crash or cleanup itself,3532* otherwise net80211 will delete the keys (at a3533* less appropriate time).3534*/3535/* goto out; */3536}3537}3538#endif35393540/* Update sta_state (ASSOC to AUTH). */3541KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));3542KASSERT(lsta->state == IEEE80211_STA_ASSOC, ("%s: lsta %p state not "3543"ASSOC: %#x\n", __func__, lsta, lsta->state));3544error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_AUTH);3545if (error != 0) {3546ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(AUTH) "3547"failed: %d\n", __func__, __LINE__, error);3548goto out;3549}35503551lkpi_lsta_dump(lsta, ni, __func__, __LINE__);35523553/* Update sta and change state (from AUTH) to NONE. */3554KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));3555KASSERT(lsta->state == IEEE80211_STA_AUTH, ("%s: lsta %p state not "3556"AUTH: %#x\n", __func__, lsta, lsta->state));3557error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_NONE);3558if (error != 0) {3559ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(NONE) "3560"failed: %d\n", __func__, __LINE__, error);3561goto out;3562}35633564bss_changed = 0;3565/*3566* Start updating bss info (bss_info_changed) (assoc, aid, ..).3567*3568* One would expect this to happen when going off AUTHORIZED.3569* See comment there; removes the sta from fw if not careful3570* (bss_info_changed() change is executed right away).3571*3572* We need to do this now, before sta changes to IEEE80211_STA_NOTEXIST3573* as otherwise drivers (iwlwifi at least) will silently not remove3574* the sta from the firmware and when we will add a new one trigger3575* a fw assert.3576*3577* The order which works best so far avoiding early removal or silent3578* non-removal seems to be (for iwlwifi::mld-mac80211.c cases;3579* the iwlwifi:mac80211.c case still to be tested):3580* 1) lkpi_disassoc(): set vif->cfg.assoc = false (aid=0 side effect here)3581* 2) call the last sta_state update -> IEEE80211_STA_NOTEXIST3582* (removes the sta given assoc is false)3583* 3) add the remaining BSS_CHANGED changes and call bss_info_changed()3584* 4) call unassign_vif_chanctx3585* 5) call lkpi_hw_conf_idle3586* 6) call remove_chanctx3587*3588* Note: vif->driver_flags & IEEE80211_VIF_REMOVE_AP_AFTER_DISASSOC3589* might change this.3590*/3591bss_changed |= lkpi_disassoc(sta, vif, lhw);35923593lkpi_lsta_dump(lsta, ni, __func__, __LINE__);35943595/* Adjust sta and change state (from NONE) to NOTEXIST. */3596KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));3597KASSERT(lsta->state == IEEE80211_STA_NONE, ("%s: lsta %p state not "3598"NONE: %#x, nstate %d arg %d\n", __func__, lsta, lsta->state, nstate, arg));3599error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_NOTEXIST);3600if (error != 0) {3601IMPROVE("do we need to undo the chan ctx?");3602ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(NOTEXIST) "3603"failed: %d\n", __func__, __LINE__, error);3604goto out;3605}36063607lkpi_lsta_remove(lsta, lvif);36083609lkpi_lsta_dump(lsta, ni, __func__, __LINE__); /* sta no longer save to use. */36103611IMPROVE("Any bss_info changes to announce?");3612vif->bss_conf.qos = 0;3613bss_changed |= BSS_CHANGED_QOS;3614vif->cfg.ssid_len = 0;3615memset(vif->cfg.ssid, '\0', sizeof(vif->cfg.ssid));3616bss_changed |= BSS_CHANGED_BSSID;3617vif->bss_conf.use_short_preamble = false;3618vif->bss_conf.qos = false;3619/* XXX BSS_CHANGED_???? */3620vif->bss_conf.dtim_period = 0; /* go back to 0. */3621bss_changed |= BSS_CHANGED_BEACON_INFO;3622lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, bss_changed);36233624LKPI_80211_LVIF_LOCK(lvif);3625/* Remove ni reference for this cache of lsta. */3626lvif->lvif_bss = NULL;3627lvif->lvif_bss_synched = false;3628LKPI_80211_LVIF_UNLOCK(lvif);36293630/* conf_tx */36313632lkpi_remove_chanctx(hw, vif);36333634error = EALREADY;3635out:3636wiphy_unlock(hw->wiphy);3637IEEE80211_LOCK(vap->iv_ic);3638if (error == EALREADY) {3639/*3640* We do this outside the wiphy lock as net80211::node_free() may call3641* into crypto code to delete keys and we have a recursed on3642* non-recursive sx panic. Also only do this if we get here w/o error.3643*3644* The very last release the reference on the ni for the ni/lsta on3645* lvif->lvif_bss. Upon return from this both ni and lsta are invalid3646* and potentially freed.3647*/3648ieee80211_free_node(ni);3649}3650outni:3651return (error);3652}36533654static int3655lkpi_sta_run_to_scan(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)3656{36573658return (lkpi_sta_run_to_init(vap, nstate, arg));3659}36603661static int3662lkpi_sta_run_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)3663{3664int error;36653666error = lkpi_sta_run_to_init(vap, nstate, arg);3667if (error != 0 && error != EALREADY)3668return (error);36693670/* At this point iv_bss is long a new node! */36713672error |= lkpi_sta_scan_to_auth(vap, nstate, 0);3673return (error);3674}36753676/* -------------------------------------------------------------------------- */36773678/*3679* The matches the documented state changes in net80211::sta_newstate().3680* XXX (1) without CSA and SLEEP yet, * XXX (2) not all unhandled cases3681* there are "invalid" (so there is a room for failure here).3682*/3683struct fsm_state {3684/* INIT, SCAN, AUTH, ASSOC, CAC, RUN, CSA, SLEEP */3685enum ieee80211_state ostate;3686enum ieee80211_state nstate;3687int (*handler)(struct ieee80211vap *, enum ieee80211_state, int);3688} sta_state_fsm[] = {3689{ IEEE80211_S_INIT, IEEE80211_S_INIT, lkpi_sta_state_do_nada },3690{ IEEE80211_S_SCAN, IEEE80211_S_INIT, lkpi_sta_state_do_nada }, /* scan_to_init */3691{ IEEE80211_S_AUTH, IEEE80211_S_INIT, lkpi_sta_auth_to_init }, /* not explicitly in sta_newstate() */3692{ IEEE80211_S_ASSOC, IEEE80211_S_INIT, lkpi_sta_assoc_to_init }, /* Send DEAUTH. */3693{ IEEE80211_S_RUN, IEEE80211_S_INIT, lkpi_sta_run_to_init }, /* Send DISASSOC. */36943695{ IEEE80211_S_INIT, IEEE80211_S_SCAN, lkpi_sta_state_do_nada },3696{ IEEE80211_S_SCAN, IEEE80211_S_SCAN, lkpi_sta_state_do_nada },3697{ IEEE80211_S_AUTH, IEEE80211_S_SCAN, lkpi_sta_auth_to_scan },3698{ IEEE80211_S_ASSOC, IEEE80211_S_SCAN, lkpi_sta_assoc_to_scan },3699{ IEEE80211_S_RUN, IEEE80211_S_SCAN, lkpi_sta_run_to_scan }, /* Beacon miss. */37003701{ IEEE80211_S_INIT, IEEE80211_S_AUTH, lkpi_sta_scan_to_auth }, /* Send AUTH. */3702{ IEEE80211_S_SCAN, IEEE80211_S_AUTH, lkpi_sta_scan_to_auth }, /* Send AUTH. */3703{ IEEE80211_S_AUTH, IEEE80211_S_AUTH, lkpi_sta_a_to_a }, /* Send ?AUTH. */3704{ IEEE80211_S_ASSOC, IEEE80211_S_AUTH, lkpi_sta_assoc_to_auth }, /* Send ?AUTH. */3705{ IEEE80211_S_RUN, IEEE80211_S_AUTH, lkpi_sta_run_to_auth }, /* Send ?AUTH. */37063707{ IEEE80211_S_AUTH, IEEE80211_S_ASSOC, lkpi_sta_auth_to_assoc }, /* Send ASSOCREQ. */3708{ IEEE80211_S_ASSOC, IEEE80211_S_ASSOC, lkpi_sta_a_to_a }, /* Send ASSOCREQ. */3709{ IEEE80211_S_RUN, IEEE80211_S_ASSOC, lkpi_sta_run_to_assoc }, /* Send ASSOCREQ/REASSOCREQ. */37103711{ IEEE80211_S_AUTH, IEEE80211_S_RUN, lkpi_sta_auth_to_run },3712{ IEEE80211_S_ASSOC, IEEE80211_S_RUN, lkpi_sta_assoc_to_run },3713{ IEEE80211_S_RUN, IEEE80211_S_RUN, lkpi_sta_state_do_nada },37143715/* Dummy at the end without handler. */3716{ IEEE80211_S_INIT, IEEE80211_S_INIT, NULL },3717};37183719static int3720lkpi_iv_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)3721{3722struct ieee80211com *ic;3723struct lkpi_hw *lhw;3724struct lkpi_vif *lvif;3725struct ieee80211_vif *vif;3726struct fsm_state *s;3727enum ieee80211_state ostate;3728int error;37293730ic = vap->iv_ic;3731IEEE80211_LOCK_ASSERT(ic);3732ostate = vap->iv_state;37333734#ifdef LINUXKPI_DEBUG_802113735if (linuxkpi_debug_80211 & D80211_TRACE)3736ic_printf(vap->iv_ic, "%s:%d: vap %p nstate %#x arg %#x\n",3737__func__, __LINE__, vap, nstate, arg);3738#endif37393740if (vap->iv_opmode == IEEE80211_M_STA) {37413742lhw = ic->ic_softc;3743lvif = VAP_TO_LVIF(vap);3744vif = LVIF_TO_VIF(lvif);37453746/* No need to replicate this in most state handlers. */3747if (nstate > IEEE80211_S_SCAN)3748lkpi_stop_hw_scan(lhw, vif);37493750s = sta_state_fsm;37513752} else {3753ic_printf(vap->iv_ic, "%s: only station mode currently supported: "3754"cap %p iv_opmode %d\n", __func__, vap, vap->iv_opmode);3755return (ENOSYS);3756}37573758error = 0;3759for (; s->handler != NULL; s++) {3760if (ostate == s->ostate && nstate == s->nstate) {3761#ifdef LINUXKPI_DEBUG_802113762if (linuxkpi_debug_80211 & D80211_TRACE)3763ic_printf(vap->iv_ic, "%s: new state %d (%s) ->"3764" %d (%s): arg %d.\n", __func__,3765ostate, ieee80211_state_name[ostate],3766nstate, ieee80211_state_name[nstate], arg);3767#endif3768error = s->handler(vap, nstate, arg);3769break;3770}3771}3772IEEE80211_LOCK_ASSERT(vap->iv_ic);37733774if (s->handler == NULL) {3775IMPROVE("turn this into a KASSERT\n");3776ic_printf(vap->iv_ic, "%s: unsupported state transition "3777"%d (%s) -> %d (%s)\n", __func__,3778ostate, ieee80211_state_name[ostate],3779nstate, ieee80211_state_name[nstate]);3780return (ENOSYS);3781}37823783if (error == EALREADY) {3784#ifdef LINUXKPI_DEBUG_802113785if (linuxkpi_debug_80211 & D80211_TRACE)3786ic_printf(vap->iv_ic, "%s: state transition %d (%s) -> "3787"%d (%s): iv_newstate already handled: %d.\n",3788__func__, ostate, ieee80211_state_name[ostate],3789nstate, ieee80211_state_name[nstate], error);3790#endif3791return (0);3792}37933794if (error != 0) {3795ic_printf(vap->iv_ic, "%s: error %d during state transition "3796"%d (%s) -> %d (%s)\n", __func__, error,3797ostate, ieee80211_state_name[ostate],3798nstate, ieee80211_state_name[nstate]);3799return (error);3800}38013802#ifdef LINUXKPI_DEBUG_802113803if (linuxkpi_debug_80211 & D80211_TRACE)3804ic_printf(vap->iv_ic, "%s:%d: vap %p nstate %#x arg %#x "3805"calling net80211 parent\n",3806__func__, __LINE__, vap, nstate, arg);3807#endif38083809return (lvif->iv_newstate(vap, nstate, arg));3810}38113812/* -------------------------------------------------------------------------- */38133814/*3815* We overload (*iv_update_bss) as otherwise we have cases in, e.g.,3816* net80211::ieee80211_sta_join1() where vap->iv_bss gets replaced by a3817* new node without us knowing and thus our ni/lsta are out of sync.3818*/3819static struct ieee80211_node *3820lkpi_iv_update_bss(struct ieee80211vap *vap, struct ieee80211_node *ni)3821{3822struct lkpi_vif *lvif;3823struct ieee80211_node *rni;38243825IEEE80211_LOCK_ASSERT(vap->iv_ic);38263827lvif = VAP_TO_LVIF(vap);38283829LKPI_80211_LVIF_LOCK(lvif);3830lvif->lvif_bss_synched = false;3831LKPI_80211_LVIF_UNLOCK(lvif);38323833rni = lvif->iv_update_bss(vap, ni);3834return (rni);3835}38363837#ifdef LKPI_80211_WME3838static int3839lkpi_wme_update(struct lkpi_hw *lhw, struct ieee80211vap *vap, bool planned)3840{3841struct ieee80211com *ic;3842struct ieee80211_hw *hw;3843struct lkpi_vif *lvif;3844struct ieee80211_vif *vif;3845struct chanAccParams chp;3846struct wmeParams wmeparr[WME_NUM_AC];3847struct ieee80211_tx_queue_params txqp;3848enum ieee80211_bss_changed changed;3849int error;3850uint16_t ac;38513852hw = LHW_TO_HW(lhw);3853lockdep_assert_wiphy(hw->wiphy);38543855IMPROVE();3856KASSERT(WME_NUM_AC == IEEE80211_NUM_ACS, ("%s: WME_NUM_AC %d != "3857"IEEE80211_NUM_ACS %d\n", __func__, WME_NUM_AC, IEEE80211_NUM_ACS));38583859if (vap == NULL)3860return (0);38613862if ((vap->iv_flags & IEEE80211_F_WME) == 0)3863return (0);38643865if (lhw->ops->conf_tx == NULL)3866return (0);38673868if (!planned && (vap->iv_state != IEEE80211_S_RUN)) {3869lhw->update_wme = true;3870return (0);3871}3872lhw->update_wme = false;38733874ic = lhw->ic;3875ieee80211_wme_ic_getparams(ic, &chp);3876IEEE80211_LOCK(ic);3877for (ac = 0; ac < WME_NUM_AC; ac++)3878wmeparr[ac] = chp.cap_wmeParams[ac];3879IEEE80211_UNLOCK(ic);38803881lvif = VAP_TO_LVIF(vap);3882vif = LVIF_TO_VIF(lvif);38833884/* Configure tx queues (conf_tx) & send BSS_CHANGED_QOS. */3885for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {3886struct wmeParams *wmep;38873888wmep = &wmeparr[ac];3889bzero(&txqp, sizeof(txqp));3890txqp.cw_min = wmep->wmep_logcwmin;3891txqp.cw_max = wmep->wmep_logcwmax;3892txqp.txop = wmep->wmep_txopLimit;3893txqp.aifs = wmep->wmep_aifsn;3894error = lkpi_80211_mo_conf_tx(hw, vif, /* link_id */0, ac, &txqp);3895if (error != 0)3896ic_printf(ic, "%s: conf_tx ac %u failed %d\n",3897__func__, ac, error);3898}3899changed = BSS_CHANGED_QOS;3900if (!planned)3901lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, changed);39023903return (changed);3904}3905#endif39063907static int3908lkpi_ic_wme_update(struct ieee80211com *ic)3909{3910#ifdef LKPI_80211_WME3911struct ieee80211vap *vap;3912struct lkpi_hw *lhw;3913struct ieee80211_hw *hw;39143915IMPROVE("Use the per-VAP callback in net80211.");3916vap = TAILQ_FIRST(&ic->ic_vaps);3917if (vap == NULL)3918return (0);39193920lhw = ic->ic_softc;3921hw = LHW_TO_HW(lhw);39223923wiphy_lock(hw->wiphy);3924lkpi_wme_update(lhw, vap, false);3925wiphy_unlock(hw->wiphy);3926#endif3927return (0); /* unused */3928}39293930static void3931lkpi_iv_sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,3932int subtype, const struct ieee80211_rx_stats *rxs, int rssi, int nf)3933{3934struct lkpi_hw *lhw;3935struct ieee80211_hw *hw;3936struct lkpi_vif *lvif;3937struct ieee80211_vif *vif;3938enum ieee80211_bss_changed bss_changed;39393940lvif = VAP_TO_LVIF(ni->ni_vap);3941vif = LVIF_TO_VIF(lvif);39423943lvif->iv_recv_mgmt(ni, m0, subtype, rxs, rssi, nf);39443945switch (subtype) {3946case IEEE80211_FC0_SUBTYPE_PROBE_RESP:3947break;3948case IEEE80211_FC0_SUBTYPE_BEACON:3949/*3950* Only count beacons when assoc. SCAN has its own logging.3951* This is for connection/beacon loss/session protection almost3952* over debugging when trying to get into a stable RUN state.3953*/3954if (vif->cfg.assoc)3955lvif->beacons++;3956break;3957default:3958return;3959}39603961lhw = ni->ni_ic->ic_softc;3962hw = LHW_TO_HW(lhw);39633964/*3965* If this direct call to mo_bss_info_changed will not work due to3966* locking, see if queue_work() is fast enough.3967*/3968bss_changed = lkpi_update_dtim_tsf(vif, ni, ni->ni_vap, __func__, __LINE__);3969lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, bss_changed);3970}39713972/*3973* Change link-layer address on the vif (if the vap is not started/"UP").3974* This can happen if a user changes 'ether' using ifconfig.3975* The code is based on net80211/ieee80211_freebsd.c::wlan_iflladdr() but3976* we do use a per-[l]vif event handler to be sure we exist as we3977* cannot assume that from every vap derives a vif and we have a hard3978* time checking based on net80211 information.3979* Should this ever become a real problem we could add a callback function3980* to wlan_iflladdr() to be set optionally but that would be for a3981* single-consumer (or needs a list) -- was just too complicated for an3982* otherwise perfect mechanism FreeBSD already provides.3983*/3984static void3985lkpi_vif_iflladdr(void *arg, struct ifnet *ifp)3986{3987struct epoch_tracker et;3988struct ieee80211_vif *vif;39893990NET_EPOCH_ENTER(et);3991/* NB: identify vap's by if_transmit; left as an extra check. */3992if (if_gettransmitfn(ifp) != ieee80211_vap_transmit ||3993(if_getflags(ifp) & IFF_UP) != 0) {3994NET_EPOCH_EXIT(et);3995return;3996}39973998vif = arg;3999IEEE80211_ADDR_COPY(vif->bss_conf.addr, if_getlladdr(ifp));4000NET_EPOCH_EXIT(et);4001}40024003static struct ieee80211vap *4004lkpi_ic_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ],4005int unit, enum ieee80211_opmode opmode, int flags,4006const uint8_t bssid[IEEE80211_ADDR_LEN],4007const uint8_t mac[IEEE80211_ADDR_LEN])4008{4009struct lkpi_hw *lhw;4010struct ieee80211_hw *hw;4011struct lkpi_vif *lvif;4012struct ieee80211vap *vap;4013struct ieee80211_vif *vif;4014struct ieee80211_tx_queue_params txqp;4015enum ieee80211_bss_changed changed;4016struct sysctl_oid *node;4017size_t len;4018int error, i;4019uint16_t ac;40204021if (!TAILQ_EMPTY(&ic->ic_vaps)) /* 1 so far. Add <n> once this works. */4022return (NULL);40234024lhw = ic->ic_softc;4025hw = LHW_TO_HW(lhw);40264027len = sizeof(*lvif);4028len += hw->vif_data_size; /* vif->drv_priv */40294030lvif = malloc(len, M_80211_VAP, M_WAITOK | M_ZERO);4031mtx_init(&lvif->mtx, "lvif", NULL, MTX_DEF);4032TASK_INIT(&lvif->sw_scan_task, 0, lkpi_sw_scan_task, lvif);4033INIT_LIST_HEAD(&lvif->lsta_list);4034lvif->lvif_bss = NULL;4035refcount_init(&lvif->nt_unlocked, 0);4036lvif->lvif_bss_synched = false;4037vap = LVIF_TO_VAP(lvif);40384039vif = LVIF_TO_VIF(lvif);4040memcpy(vif->addr, mac, IEEE80211_ADDR_LEN);4041vif->p2p = false;4042vif->probe_req_reg = false;4043vif->type = lkpi_opmode_to_vif_type(opmode);4044lvif->wdev.iftype = vif->type;4045/* Need to fill in other fields as well. */4046IMPROVE();40474048/* XXX-BZ hardcoded for now! */4049#if 14050RCU_INIT_POINTER(vif->bss_conf.chanctx_conf, NULL);4051vif->bss_conf.vif = vif;4052/* vap->iv_myaddr is not set until net80211::vap_setup or vap_attach. */4053IEEE80211_ADDR_COPY(vif->bss_conf.addr, mac);4054lvif->lvif_ifllevent = EVENTHANDLER_REGISTER(iflladdr_event,4055lkpi_vif_iflladdr, vif, EVENTHANDLER_PRI_ANY);4056vif->bss_conf.link_id = 0; /* Non-MLO operation. */4057vif->bss_conf.chanreq.oper.width = NL80211_CHAN_WIDTH_20_NOHT;4058vif->bss_conf.use_short_preamble = false; /* vap->iv_flags IEEE80211_F_SHPREAMBLE */4059vif->bss_conf.use_short_slot = false; /* vap->iv_flags IEEE80211_F_SHSLOT */4060vif->bss_conf.qos = false;4061vif->bss_conf.use_cts_prot = false; /* vap->iv_protmode */4062vif->bss_conf.ht_operation_mode = IEEE80211_HT_OP_MODE_PROTECTION_NONE;4063vif->cfg.aid = 0;4064vif->cfg.assoc = false;4065vif->cfg.idle = true;4066vif->cfg.ps = false;4067IMPROVE("Check other fields and then figure out whats is left elsewhere of them");4068/*4069* We need to initialize it to something as the bss_info_changed call4070* will try to copy from it in iwlwifi and NULL is a panic.4071* We will set the proper one in scan_to_auth() before being assoc.4072*/4073vif->bss_conf.bssid = ieee80211broadcastaddr;4074#endif4075#if 04076vif->bss_conf.dtim_period = 0; /* IEEE80211_DTIM_DEFAULT ; must stay 0. */4077IEEE80211_ADDR_COPY(vif->bss_conf.bssid, bssid);4078vif->bss_conf.beacon_int = ic->ic_bintval;4079/* iwlwifi bug. */4080if (vif->bss_conf.beacon_int < 16)4081vif->bss_conf.beacon_int = 16;4082#endif40834084/* Link Config */4085vif->link_conf[0] = &vif->bss_conf;4086for (i = 0; i < nitems(vif->link_conf); i++) {4087IMPROVE("more than 1 link one day");4088}40894090/* Setup queue defaults; driver may override in (*add_interface). */4091for (i = 0; i < IEEE80211_NUM_ACS; i++) {4092if (ieee80211_hw_check(hw, QUEUE_CONTROL))4093vif->hw_queue[i] = IEEE80211_INVAL_HW_QUEUE;4094else if (hw->queues >= IEEE80211_NUM_ACS)4095vif->hw_queue[i] = i;4096else4097vif->hw_queue[i] = 0;40984099/* Initialize the queue to running. Stopped? */4100lvif->hw_queue_stopped[i] = false;4101}4102vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;41034104IMPROVE();41054106wiphy_lock(hw->wiphy);4107error = lkpi_80211_mo_start(hw);4108if (error != 0) {4109wiphy_unlock(hw->wiphy);4110ic_printf(ic, "%s: failed to start hw: %d\n", __func__, error);4111mtx_destroy(&lvif->mtx);4112free(lvif, M_80211_VAP);4113return (NULL);4114}41154116error = lkpi_80211_mo_add_interface(hw, vif);4117if (error != 0) {4118IMPROVE(); /* XXX-BZ mo_stop()? */4119wiphy_unlock(hw->wiphy);4120ic_printf(ic, "%s: failed to add interface: %d\n", __func__, error);4121mtx_destroy(&lvif->mtx);4122free(lvif, M_80211_VAP);4123return (NULL);4124}4125wiphy_unlock(hw->wiphy);41264127LKPI_80211_LHW_LVIF_LOCK(lhw);4128TAILQ_INSERT_TAIL(&lhw->lvif_head, lvif, lvif_entry);4129LKPI_80211_LHW_LVIF_UNLOCK(lhw);41304131/* Set bss_info. */4132changed = 0;4133lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, changed);41344135/* Configure tx queues (conf_tx), default WME & send BSS_CHANGED_QOS. */4136IMPROVE("Hardcoded values; to fix see 802.11-2016, 9.4.2.29 EDCA Parameter Set element");4137wiphy_lock(hw->wiphy);4138for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {41394140bzero(&txqp, sizeof(txqp));4141txqp.cw_min = 15;4142txqp.cw_max = 1023;4143txqp.txop = 0;4144txqp.aifs = 2;4145error = lkpi_80211_mo_conf_tx(hw, vif, /* link_id */0, ac, &txqp);4146if (error != 0)4147ic_printf(ic, "%s: conf_tx ac %u failed %d\n",4148__func__, ac, error);4149}4150wiphy_unlock(hw->wiphy);4151changed = BSS_CHANGED_QOS;4152lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, changed);41534154/* Force MC init. */4155lkpi_update_mcast_filter(ic);41564157ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid);41584159/* Now we have a valid vap->iv_ifp. Any checksum offloading goes below. */41604161IMPROVE();41624163/* Override with LinuxKPI method so we can drive mac80211/cfg80211. */4164lvif->iv_newstate = vap->iv_newstate;4165vap->iv_newstate = lkpi_iv_newstate;4166lvif->iv_update_bss = vap->iv_update_bss;4167vap->iv_update_bss = lkpi_iv_update_bss;4168lvif->iv_recv_mgmt = vap->iv_recv_mgmt;4169vap->iv_recv_mgmt = lkpi_iv_sta_recv_mgmt;41704171#ifdef LKPI_80211_HW_CRYPTO4172/* Key management. */4173if (lkpi_hwcrypto && lhw->ops->set_key != NULL) {4174vap->iv_key_set = lkpi_iv_key_set;4175vap->iv_key_delete = lkpi_iv_key_delete;4176vap->iv_key_update_begin = lkpi_iv_key_update_begin;4177vap->iv_key_update_end = lkpi_iv_key_update_end;4178}4179#endif41804181#ifdef LKPI_80211_HT4182/* Stay with the iv_ampdu_rxmax,limit / iv_ampdu_density defaults until later. */4183#endif41844185ieee80211_ratectl_init(vap);41864187/* Complete setup. */4188ieee80211_vap_attach(vap, ieee80211_media_change,4189ieee80211_media_status, mac);41904191#ifdef LKPI_80211_HT4192/*4193* Modern chipset/fw/drv will do A-MPDU in drv/fw and fail4194* to do so if they cannot do the crypto too.4195*/4196if (!lkpi_hwcrypto && IEEE80211_CONF_AMPDU_OFFLOAD(ic))4197vap->iv_flags_ht &= ~IEEE80211_FHT_AMPDU_RX;4198#endif41994200if (hw->max_listen_interval == 0)4201hw->max_listen_interval = 7 * (ic->ic_lintval / ic->ic_bintval);4202hw->conf.listen_interval = hw->max_listen_interval;4203ic->ic_set_channel(ic);42044205/* XXX-BZ do we need to be able to update these? */4206hw->wiphy->frag_threshold = vap->iv_fragthreshold;4207lkpi_80211_mo_set_frag_threshold(hw, vap->iv_fragthreshold);4208hw->wiphy->rts_threshold = vap->iv_rtsthreshold;4209lkpi_80211_mo_set_rts_threshold(hw, vap->iv_rtsthreshold);4210/* any others? */42114212/* Add per-VIF/VAP sysctls. */4213sysctl_ctx_init(&lvif->sysctl_ctx);42144215node = SYSCTL_ADD_NODE(&lvif->sysctl_ctx,4216SYSCTL_CHILDREN(&sysctl___compat_linuxkpi_80211),4217OID_AUTO, if_name(vap->iv_ifp),4218CTLFLAG_RD | CTLFLAG_SKIP | CTLFLAG_MPSAFE, NULL, "VIF Information");42194220SYSCTL_ADD_PROC(&lvif->sysctl_ctx,4221SYSCTL_CHILDREN(node), OID_AUTO, "dump_stas",4222CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, lvif, 0,4223lkpi_80211_dump_stas, "A", "Dump sta statistics of this vif");4224SYSCTL_ADD_PROC(&lvif->sysctl_ctx,4225SYSCTL_CHILDREN(node), OID_AUTO, "dump_stas_queues",4226CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE | CTLFLAG_SKIP, lvif, 0,4227lkpi_80211_dump_sta_queues, "A",4228"Dump queue statistics for any sta of this vif");42294230IMPROVE();42314232return (vap);4233}42344235void4236linuxkpi_ieee80211_unregister_hw(struct ieee80211_hw *hw)4237{42384239wiphy_unregister(hw->wiphy);4240linuxkpi_ieee80211_ifdetach(hw);42414242IMPROVE();4243}42444245void4246linuxkpi_ieee80211_restart_hw(struct ieee80211_hw *hw)4247{42484249TODO();4250}42514252static void4253lkpi_ic_vap_delete(struct ieee80211vap *vap)4254{4255struct ieee80211com *ic;4256struct lkpi_hw *lhw;4257struct ieee80211_hw *hw;4258struct lkpi_vif *lvif;4259struct ieee80211_vif *vif;42604261lvif = VAP_TO_LVIF(vap);4262vif = LVIF_TO_VIF(lvif);4263ic = vap->iv_ic;4264lhw = ic->ic_softc;4265hw = LHW_TO_HW(lhw);42664267EVENTHANDLER_DEREGISTER(iflladdr_event, lvif->lvif_ifllevent);42684269/* Clear up per-VIF/VAP sysctls. */4270sysctl_ctx_free(&lvif->sysctl_ctx);42714272ieee80211_draintask(ic, &lvif->sw_scan_task);42734274LKPI_80211_LHW_LVIF_LOCK(lhw);4275TAILQ_REMOVE(&lhw->lvif_head, lvif, lvif_entry);4276LKPI_80211_LHW_LVIF_UNLOCK(lhw);42774278ieee80211_ratectl_deinit(vap);4279ieee80211_vap_detach(vap);42804281IMPROVE("clear up other bits in this state");42824283lkpi_80211_mo_remove_interface(hw, vif);42844285/* Single VAP, so we can do this here. */4286lkpi_80211_mo_stop(hw, false); /* XXX SUSPEND */42874288mtx_destroy(&lvif->mtx);4289free(lvif, M_80211_VAP);4290}42914292static void4293lkpi_ic_update_mcast(struct ieee80211com *ic)4294{4295struct ieee80211vap *vap;4296struct lkpi_hw *lhw;42974298lhw = ic->ic_softc;42994300LKPI_80211_LHW_MC_LOCK(lhw);4301/* Cleanup anything on the current list. */4302lkpi_cleanup_mcast_list_locked(lhw);43034304/* Build up the new list (or allmulti). */4305if (ic->ic_allmulti == 0) {4306TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)4307if_foreach_llmaddr(vap->iv_ifp,4308lkpi_ic_update_mcast_copy, &lhw->mc_list);4309lhw->mc_all_multi = false;4310} else {4311lhw->mc_all_multi = true;4312}4313LKPI_80211_LHW_MC_UNLOCK(lhw);43144315lkpi_update_mcast_filter(ic);4316TRACEOK();4317}43184319static void4320lkpi_ic_update_promisc(struct ieee80211com *ic)4321{43224323UNIMPLEMENTED;4324}43254326static void4327lkpi_ic_update_chw(struct ieee80211com *ic)4328{43294330UNIMPLEMENTED;4331}43324333/* Start / stop device. */4334static void4335lkpi_ic_parent(struct ieee80211com *ic)4336{4337struct lkpi_hw *lhw;4338struct ieee80211_hw *hw;4339#ifdef HW_START_STOP4340int error;4341#endif4342bool start_all;43434344IMPROVE();43454346lhw = ic->ic_softc;4347hw = LHW_TO_HW(lhw);4348start_all = false;43494350/* IEEE80211_UNLOCK(ic); */4351wiphy_lock(hw->wiphy);4352if (ic->ic_nrunning > 0) {4353#ifdef HW_START_STOP4354error = lkpi_80211_mo_start(hw);4355if (error == 0)4356#endif4357start_all = true;4358} else {4359#ifdef HW_START_STOP4360lkpi_80211_mo_stop(hw, false); /* XXX SUSPEND */4361#endif4362}4363wiphy_unlock(hw->wiphy);4364/* IEEE80211_LOCK(ic); */43654366if (start_all)4367ieee80211_start_all(ic);4368}43694370bool4371linuxkpi_ieee80211_is_ie_id_in_ie_buf(const u8 ie, const u8 *ie_ids,4372size_t ie_ids_len)4373{4374int i;43754376for (i = 0; i < ie_ids_len; i++) {4377if (ie == *ie_ids)4378return (true);4379}43804381return (false);4382}43834384/* Return true if skipped; false if error. */4385bool4386linuxkpi_ieee80211_ie_advance(size_t *xp, const u8 *ies, size_t ies_len)4387{4388size_t x;4389uint8_t l;43904391x = *xp;43924393KASSERT(x < ies_len, ("%s: x %zu ies_len %zu ies %p\n",4394__func__, x, ies_len, ies));4395l = ies[x + 1];4396x += 2 + l;43974398if (x > ies_len)4399return (false);44004401*xp = x;4402return (true);4403}44044405static uint8_t *4406lkpi_scan_ies_add(uint8_t *p, struct ieee80211_scan_ies *scan_ies,4407uint32_t band_mask, struct ieee80211vap *vap, struct ieee80211_hw *hw)4408{4409struct ieee80211_supported_band *supband;4410struct linuxkpi_ieee80211_channel *channels;4411struct ieee80211com *ic;4412const struct ieee80211_channel *chan;4413const struct ieee80211_rateset *rs;4414uint8_t *pb;4415int band, i;44164417ic = vap->iv_ic;4418for (band = 0; band < NUM_NL80211_BANDS; band++) {4419if ((band_mask & (1 << band)) == 0)4420continue;44214422supband = hw->wiphy->bands[band];4423/*4424* This should not happen;4425* band_mask is a bitmask of valid bands to scan on.4426*/4427if (supband == NULL || supband->n_channels == 0)4428continue;44294430/* Find a first channel to get the mode and rates from. */4431channels = supband->channels;4432chan = NULL;4433for (i = 0; i < supband->n_channels; i++) {4434uint32_t flags;44354436if (channels[i].flags & IEEE80211_CHAN_DISABLED)4437continue;44384439flags = 0;4440switch (band) {4441case NL80211_BAND_2GHZ:4442flags |= IEEE80211_CHAN_G;4443break;4444case NL80211_BAND_5GHZ:4445flags |= IEEE80211_CHAN_A;4446break;4447default:4448panic("%s:%d: unupported band %d\n",4449__func__, __LINE__, band);4450}44514452chan = ieee80211_find_channel(ic,4453channels[i].center_freq, flags);4454if (chan != NULL)4455break;4456}44574458/* This really should not happen. */4459if (chan == NULL)4460continue;44614462pb = p;4463rs = ieee80211_get_suprates(ic, chan); /* calls chan2mode */4464p = ieee80211_add_rates(p, rs);4465p = ieee80211_add_xrates(p, rs);44664467#if defined(LKPI_80211_HT)4468if ((vap->iv_flags_ht & IEEE80211_FHT_HT) != 0) {4469struct ieee80211_channel *c;44704471c = ieee80211_ht_adjust_channel(ic, ic->ic_curchan,4472vap->iv_flags_ht);4473p = ieee80211_add_htcap_ch(p, vap, c);4474}4475#endif4476#if defined(LKPI_80211_VHT)4477if (band == NL80211_BAND_5GHZ &&4478(vap->iv_vht_flags & IEEE80211_FVHT_VHT) != 0) {4479struct ieee80211_channel *c;44804481c = ieee80211_ht_adjust_channel(ic, ic->ic_curchan,4482vap->iv_flags_ht);4483c = ieee80211_vht_adjust_channel(ic, c,4484vap->iv_vht_flags);4485p = ieee80211_add_vhtcap_ch(p, vap, c);4486}4487#endif44884489scan_ies->ies[band] = pb;4490scan_ies->len[band] = p - pb;4491}44924493/* Add common_ies */4494pb = p;4495if ((vap->iv_flags & IEEE80211_F_WPA1) != 0 &&4496vap->iv_wpa_ie != NULL) {4497memcpy(p, vap->iv_wpa_ie, 2 + vap->iv_wpa_ie[1]);4498p += 2 + vap->iv_wpa_ie[1];4499}4500if (vap->iv_appie_probereq != NULL) {4501memcpy(p, vap->iv_appie_probereq->ie_data,4502vap->iv_appie_probereq->ie_len);4503p += vap->iv_appie_probereq->ie_len;4504}4505scan_ies->common_ies = pb;4506scan_ies->common_ie_len = p - pb;45074508return (p);4509}45104511static void4512lkpi_enable_hw_scan(struct lkpi_hw *lhw)4513{45144515if (lhw->ops->hw_scan) {4516/*4517* Advertise full-offload scanning.4518*4519* Not limiting to SINGLE_SCAN_ON_ALL_BANDS here as otherwise4520* we essentially disable hw_scan for all drivers not setting4521* the flag.4522*/4523lhw->ic->ic_flags_ext |= IEEE80211_FEXT_SCAN_OFFLOAD;4524lhw->scan_flags |= LKPI_LHW_SCAN_HW;4525}4526}45274528#ifndef LKPI_80211_USE_SCANLIST4529static const uint32_t chan_pri[] = {45305180, 5500, 5745,45315260, 5580, 5660, 5825,45325220, 5300, 5540, 5620, 5700, 5785, 5865,45332437, 2412, 2422, 2462, 2472, 2432, 24524534};45354536static int4537lkpi_scan_chan_list_idx(const struct linuxkpi_ieee80211_channel *lc)4538{4539int i;45404541for (i = 0; i < nitems(chan_pri); i++) {4542if (lc->center_freq == chan_pri[i])4543return (i);4544}45454546return (-1);4547}45484549static int4550lkpi_scan_chan_list_comp(const struct linuxkpi_ieee80211_channel *lc1,4551const struct linuxkpi_ieee80211_channel *lc2)4552{4553int idx1, idx2;45544555/* Find index in list. */4556idx1 = lkpi_scan_chan_list_idx(lc1);4557idx2 = lkpi_scan_chan_list_idx(lc2);45584559if (idx1 == -1 && idx2 != -1)4560return (1);4561if (idx1 != -1 && idx2 == -1)4562return (-1);45634564/* Neither on the list, use center_freq. */4565if (idx1 == -1 && idx2 == -1)4566return (lc1->center_freq - lc2->center_freq);45674568/* Whichever is first in the list. */4569return (idx1 - idx2);4570}45714572static void4573lkpi_scan_chan_list_resort(struct linuxkpi_ieee80211_channel **cpp, size_t nchan)4574{4575struct linuxkpi_ieee80211_channel *lc, *nc;4576size_t i, j;4577int rc;45784579for (i = (nchan - 1); i > 0; i--) {4580for (j = i; j > 0 ; j--) {4581lc = *(cpp + j);4582nc = *(cpp + j - 1);4583rc = lkpi_scan_chan_list_comp(lc, nc);4584if (rc < 0) {4585*(cpp + j) = nc;4586*(cpp + j - 1) = lc;4587}4588}4589}4590}45914592static bool4593lkpi_scan_chan(struct linuxkpi_ieee80211_channel *c,4594struct ieee80211com *ic, bool log)4595{45964597if ((c->flags & IEEE80211_CHAN_DISABLED) != 0) {4598if (log)4599TRACE_SCAN(ic, "Skipping disabled chan "4600"on band %s [%#x/%u/%#x]",4601lkpi_nl80211_band_name(c->band), c->hw_value,4602c->center_freq, c->flags);4603return (false);4604}4605if (isclr(ic->ic_chan_active, ieee80211_mhz2ieee(c->center_freq,4606lkpi_nl80211_band_to_net80211_band(c->band)))) {4607if (log)4608TRACE_SCAN(ic, "Skipping !active chan "4609"on band %s [%#x/%u/%#x]",4610lkpi_nl80211_band_name(c->band), c->hw_value,4611c->center_freq, c->flags);4612return (false);4613}4614return (true);4615}4616#endif46174618static void4619lkpi_ic_scan_start(struct ieee80211com *ic)4620{4621struct lkpi_hw *lhw;4622struct ieee80211_hw *hw;4623struct lkpi_vif *lvif;4624struct ieee80211_vif *vif;4625struct ieee80211_scan_state *ss;4626struct ieee80211vap *vap;4627int error;4628bool is_hw_scan;46294630lhw = ic->ic_softc;4631ss = ic->ic_scan;4632vap = ss->ss_vap;4633TRACE_SCAN(ic, "scan_flags %b", lhw->scan_flags, LKPI_LHW_SCAN_BITS);46344635LKPI_80211_LHW_SCAN_LOCK(lhw);4636if ((lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0) {4637/* A scan is still running. */4638LKPI_80211_LHW_SCAN_UNLOCK(lhw);4639TRACE_SCAN(ic, "Trying to start new scan while still running; "4640"cancelling new net80211 scan; scan_flags %b",4641lhw->scan_flags, LKPI_LHW_SCAN_BITS);4642ieee80211_cancel_scan(vap);4643return;4644}4645is_hw_scan = (lhw->scan_flags & LKPI_LHW_SCAN_HW) != 0;4646LKPI_80211_LHW_SCAN_UNLOCK(lhw);46474648#if 04649if (vap->iv_state != IEEE80211_S_SCAN) {4650TODO("We need to be able to scan if not in S_SCAN");4651TRACE_SCAN(ic, "scan_flags %b iv_state %d",4652lhw->scan_flags, LKPI_LHW_SCAN_BITS, vap->iv_state);4653ieee80211_cancel_scan(vap);4654return;4655}4656#endif46574658hw = LHW_TO_HW(lhw);4659if (!is_hw_scan) {4660/* If hw_scan is cleared clear FEXT_SCAN_OFFLOAD too. */4661vap->iv_flags_ext &= ~IEEE80211_FEXT_SCAN_OFFLOAD;46624663lvif = VAP_TO_LVIF(vap);4664vif = LVIF_TO_VIF(lvif);46654666if (vap->iv_state == IEEE80211_S_SCAN)4667lkpi_hw_conf_idle(hw, false);46684669LKPI_80211_LHW_SCAN_LOCK(lhw);4670lhw->scan_flags |= LKPI_LHW_SCAN_RUNNING;4671LKPI_80211_LHW_SCAN_UNLOCK(lhw);46724673lkpi_update_mcast_filter(ic);46744675TRACE_SCAN(vap->iv_ic, "Starting SW_SCAN: scan_flags %b",4676lhw->scan_flags, LKPI_LHW_SCAN_BITS);4677lkpi_80211_mo_sw_scan_start(hw, vif, vif->addr);4678/* net80211::scan_start() handled PS for us. */4679IMPROVE();4680/* XXX Also means it is too late to flush queues?4681* need to check iv_sta_ps or overload? */4682/* XXX want to adjust ss end time/ maxdwell? */46834684} else {4685struct ieee80211_scan_request *hw_req;4686struct linuxkpi_ieee80211_channel *lc, **cpp;4687struct cfg80211_ssid *ssids;4688struct cfg80211_scan_6ghz_params *s6gp;4689size_t chan_len, nchan, ssids_len, s6ghzlen;4690int band, i, ssid_count, common_ie_len;4691#ifndef LKPI_80211_USE_SCANLIST4692int n;4693#endif4694uint32_t band_mask;4695uint8_t *ie, *ieend;4696bool running;46974698ssid_count = min(ss->ss_nssid, hw->wiphy->max_scan_ssids);4699ssids_len = ssid_count * sizeof(*ssids);4700s6ghzlen = 0 * (sizeof(*s6gp)); /* XXX-BZ */47014702band_mask = 0;4703nchan = 0;4704if (ieee80211_hw_check(hw, SINGLE_SCAN_ON_ALL_BANDS)) {4705#ifdef LKPI_80211_USE_SCANLIST4706/* Avoid net80211 scan lists until it has proper scan offload support. */4707for (i = ss->ss_next; i < ss->ss_last; i++) {4708nchan++;4709band = lkpi_net80211_chan_to_nl80211_band(4710ss->ss_chans[ss->ss_next + i]);4711band_mask |= (1 << band);4712}4713#else4714/* Instead we scan for all channels all the time. */4715for (band = 0; band < NUM_NL80211_BANDS; band++) {4716switch (band) {4717case NL80211_BAND_2GHZ:4718case NL80211_BAND_5GHZ:4719break;4720default:4721continue;4722}4723if (hw->wiphy->bands[band] != NULL) {4724struct linuxkpi_ieee80211_channel *channels;4725int n;47264727band_mask |= (1 << band);47284729channels = hw->wiphy->bands[band]->channels;4730n = hw->wiphy->bands[band]->n_channels;4731for (i = 0; i < n; i++) {4732if (lkpi_scan_chan(&channels[i], ic, true))4733nchan++;4734}4735}4736}4737#endif4738} else {4739IMPROVE("individual band scans not yet supported, only scanning first band");4740/* In theory net80211 should drive this. */4741/* Probably we need to add local logic for now;4742* need to deal with scan_complete4743* and cancel_scan and keep local state.4744* Also cut the nchan down above.4745*/4746/* XXX-BZ ath10k does not set this but still does it? &$%^ */4747}47484749chan_len = nchan * (sizeof(lc) + sizeof(*lc));47504751common_ie_len = 0;4752if ((vap->iv_flags & IEEE80211_F_WPA1) != 0 &&4753vap->iv_wpa_ie != NULL)4754common_ie_len += vap->iv_wpa_ie[1];4755if (vap->iv_appie_probereq != NULL)4756common_ie_len += vap->iv_appie_probereq->ie_len;47574758/* We would love to check this at an earlier stage... */4759if (common_ie_len > hw->wiphy->max_scan_ie_len) {4760ic_printf(ic, "WARNING: %s: common_ie_len %d > "4761"wiphy->max_scan_ie_len %d\n", __func__,4762common_ie_len, hw->wiphy->max_scan_ie_len);4763}47644765hw_req = malloc(sizeof(*hw_req) + ssids_len +4766s6ghzlen + chan_len + lhw->supbands * lhw->scan_ie_len +4767common_ie_len, M_LKPI80211, M_WAITOK | M_ZERO);47684769hw_req->req.flags = 0; /* XXX ??? */4770/* hw_req->req.wdev */4771hw_req->req.wiphy = hw->wiphy;4772hw_req->req.no_cck = false; /* XXX */47734774/*4775* In general setting duration[_mandatory] seems to pessimise4776* default scanning behaviour. We only use it for BGSCANnig4777* to keep the dwell times small.4778* Setting duration_mandatory makes this the maximum dwell4779* time (otherwise may be shorter). Duration is in TU.4780*/4781if ((ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN) != 0) {4782unsigned long dwell;47834784if ((ic->ic_caps & IEEE80211_C_BGSCAN) == 0 ||4785(vap->iv_flags & IEEE80211_F_BGSCAN) == 0)4786ic_printf(ic, "BGSCAN despite off: %b, %b, %b\n",4787ic->ic_flags_ext, IEEE80211_FEXT_BITS,4788vap->iv_flags, IEEE80211_F_BITS,4789ic->ic_caps, IEEE80211_C_BITS);47904791dwell = ss->ss_mindwell;4792if (dwell == 0)4793dwell = msecs_to_ticks(20);47944795hw_req->req.duration_mandatory = true;4796hw_req->req.duration = TICKS_2_USEC(dwell) / 1024;4797}47984799#ifdef __notyet__4800hw_req->req.flags |= NL80211_SCAN_FLAG_RANDOM_ADDR;4801memcpy(hw_req->req.mac_addr, xxx, IEEE80211_ADDR_LEN);4802memset(hw_req->req.mac_addr_mask, 0xxx, IEEE80211_ADDR_LEN);4803#endif4804eth_broadcast_addr(hw_req->req.bssid);48054806hw_req->req.n_channels = nchan;4807cpp = (struct linuxkpi_ieee80211_channel **)(hw_req + 1);4808lc = (struct linuxkpi_ieee80211_channel *)(cpp + nchan);4809#ifdef LKPI_80211_USE_SCANLIST4810for (i = 0; i < nchan; i++) {4811*(cpp + i) =4812(struct linuxkpi_ieee80211_channel *)(lc + i);4813}4814/* Avoid net80211 scan lists until it has proper scan offload support. */4815for (i = 0; i < nchan; i++) {4816struct ieee80211_channel *c;48174818c = ss->ss_chans[ss->ss_next + i];4819lc->center_freq = c->ic_freq; /* XXX */4820/* lc->flags */4821lc->band = lkpi_net80211_chan_to_nl80211_band(c);4822lc->max_power = c->ic_maxpower;4823/* lc-> ... */4824lc++;4825}4826#else4827/* Add bands in reverse order for scanning. */4828n = 0;4829for (band = NUM_NL80211_BANDS - 1; band >= 0; band--) {4830struct ieee80211_supported_band *supband;4831struct linuxkpi_ieee80211_channel *channels;48324833/* Band disabled for scanning? */4834if ((band_mask & (1 << band)) == 0)4835continue;48364837/* Nothing to scan in band? */4838supband = hw->wiphy->bands[band];4839if (supband == NULL || supband->n_channels == 0)4840continue;48414842channels = supband->channels;4843for (i = 0; i < supband->n_channels; i++) {4844if (lkpi_scan_chan(&channels[i], ic, false))4845*(cpp + n++) = &channels[i];4846}4847}4848if (lkpi_order_scanlist)4849lkpi_scan_chan_list_resort(cpp, nchan);48504851if ((linuxkpi_debug_80211 & D80211_SCAN) != 0) {4852printf("%s:%d: %s SCAN Channel List (nchan=%zu): ",4853__func__, __LINE__, ic->ic_name, nchan);4854for (i = 0; i < nchan; i++) {4855struct linuxkpi_ieee80211_channel *xc;48564857xc = *(cpp + i);4858printf(" %d(%d)",4859ieee80211_mhz2ieee(xc->center_freq,4860lkpi_nl80211_band_to_net80211_band(4861xc->band)),4862xc->center_freq);4863}4864printf("\n");4865}4866#endif48674868hw_req->req.n_ssids = ssid_count;4869if (hw_req->req.n_ssids > 0) {4870ssids = (struct cfg80211_ssid *)lc;4871hw_req->req.ssids = ssids;4872for (i = 0; i < ssid_count; i++) {4873ssids->ssid_len = ss->ss_ssid[i].len;4874memcpy(ssids->ssid, ss->ss_ssid[i].ssid,4875ss->ss_ssid[i].len);4876ssids++;4877}4878s6gp = (struct cfg80211_scan_6ghz_params *)ssids;4879} else {4880s6gp = (struct cfg80211_scan_6ghz_params *)lc;4881}48824883/* 6GHz one day. */4884hw_req->req.n_6ghz_params = 0;4885hw_req->req.scan_6ghz_params = NULL;4886hw_req->req.scan_6ghz = false; /* Weird boolean; not what you think. */4887/* s6gp->... */48884889ie = ieend = (uint8_t *)s6gp;4890/* Copy per-band IEs, copy common IEs */4891ieend = lkpi_scan_ies_add(ie, &hw_req->ies, band_mask, vap, hw);4892hw_req->req.ie = ie;4893hw_req->req.ie_len = ieend - ie;4894hw_req->req.scan_start = jiffies;48954896lvif = VAP_TO_LVIF(vap);4897vif = LVIF_TO_VIF(lvif);48984899LKPI_80211_LHW_SCAN_LOCK(lhw);4900/* Re-check under lock. */4901running = (lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0;4902if (!running) {4903KASSERT(lhw->hw_req == NULL, ("%s: ic %p lhw %p hw_req %p "4904"!= NULL\n", __func__, ic, lhw, lhw->hw_req));49054906lhw->scan_flags |= LKPI_LHW_SCAN_RUNNING;4907lhw->hw_req = hw_req;4908}4909LKPI_80211_LHW_SCAN_UNLOCK(lhw);4910if (running) {4911free(hw_req, M_LKPI80211);4912TRACE_SCAN(ic, "Trying to start new scan while still "4913"running (2); cancelling new net80211 scan; "4914"scan_flags %b",4915lhw->scan_flags, LKPI_LHW_SCAN_BITS);4916ieee80211_cancel_scan(vap);4917return;4918}49194920lkpi_update_mcast_filter(ic);4921TRACE_SCAN(ic, "Starting HW_SCAN: scan_flags %b, "4922"ie_len %d, n_ssids %d, n_chan %d, common_ie_len %d [%d, %d]",4923lhw->scan_flags, LKPI_LHW_SCAN_BITS, hw_req->req.ie_len,4924hw_req->req.n_ssids, hw_req->req.n_channels,4925hw_req->ies.common_ie_len,4926hw_req->ies.len[NL80211_BAND_2GHZ],4927hw_req->ies.len[NL80211_BAND_5GHZ]);49284929error = lkpi_80211_mo_hw_scan(hw, vif, hw_req);4930if (error != 0) {4931bool scan_done;4932int e;49334934TRACE_SCAN(ic, "hw_scan failed; scan_flags %b, error %d",4935lhw->scan_flags, LKPI_LHW_SCAN_BITS, error);4936ieee80211_cancel_scan(vap);49374938/*4939* ieee80211_scan_completed must be called in either4940* case of error or none. So let the free happen there4941* and only there.4942* That would be fine in theory but in practice drivers4943* behave differently:4944* ath10k does not return hw_scan until after scan_complete4945* and can then still return an error.4946* rtw88 can return 1 or -EBUSY without scan_complete4947* iwlwifi can return various errors before scan starts4948* ...4949* So we cannot rely on that behaviour and have to check4950* and balance between both code paths.4951*/4952e = 0;4953scan_done = true;4954LKPI_80211_LHW_SCAN_LOCK(lhw);4955if ((lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0) {49564957free(lhw->hw_req, M_LKPI80211);4958lhw->hw_req = NULL;4959/*4960* The ieee80211_cancel_scan() above runs in a4961* taskq and it may take ages for the previous4962* scan to clear; starting a new one right away4963* we run into the problem that the old one is4964* still active.4965*/4966e = msleep(lhw, &lhw->scan_mtx, 0, "lhwscanstop", hz);4967scan_done = (lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0;49684969/*4970* Now we can clear running if no one else did.4971*/4972lhw->scan_flags &= ~LKPI_LHW_SCAN_RUNNING;4973}4974LKPI_80211_LHW_SCAN_UNLOCK(lhw);4975lkpi_update_mcast_filter(ic);4976if (!scan_done) {4977ic_printf(ic, "ERROR: %s: timeout/error to wait "4978"for ieee80211_cancel_scan: %d\n", __func__, e);4979return;4980}49814982/*4983* XXX-SIGH magic number.4984* rtw88 has a magic "return 1" if offloading scan is4985* not possible. Fall back to sw scan in that case.4986*/4987if (error == 1) {4988/*4989* We need to put this into some defered context4990* the net80211 scan may not be done yet4991* (ic_flags & IEEE80211_F_SCAN) and we cannot4992* wait here; if we do scan_curchan_task always4993* runs after our timeout to finalize the scan.4994*/4995ieee80211_runtask(ic, &lvif->sw_scan_task);4996return;4997}49984999ic_printf(ic, "ERROR: %s: hw_scan returned %d\n",5000__func__, error);5001}5002}5003}50045005static void5006lkpi_sw_scan_task(void *arg, int pending __unused)5007{5008struct lkpi_hw *lhw;5009struct lkpi_vif *lvif;5010struct ieee80211vap *vap;5011struct ieee80211_scan_state *ss;50125013lvif = arg;5014vap = LVIF_TO_VAP(lvif);5015lhw = vap->iv_ic->ic_softc;5016ss = vap->iv_ic->ic_scan;50175018LKPI_80211_LHW_SCAN_LOCK(lhw);5019/*5020* We will re-enable this at scan_end calling lkpi_enable_hw_scan().5021* IEEE80211_FEXT_SCAN_OFFLOAD will be cleared by lkpi_ic_scan_start.5022*/5023lhw->scan_flags &= ~LKPI_LHW_SCAN_HW;5024LKPI_80211_LHW_SCAN_UNLOCK(lhw);50255026TRACE_SCAN(vap->iv_ic, "Triggering SW_SCAN: pending %d, scan_flags %b",5027pending, lhw->scan_flags, LKPI_LHW_SCAN_BITS);50285029/*5030* This will call ic_scan_start() and we will get into the right path5031* unless other scans started in between.5032*/5033ieee80211_start_scan(vap,5034IEEE80211_SCAN_ONCE,5035msecs_to_ticks(10000), /* 10000 ms (=~ 50 chan * 200 ms) */5036ss->ss_mindwell ? ss->ss_mindwell : msecs_to_ticks(20),5037ss->ss_maxdwell ? ss->ss_maxdwell : msecs_to_ticks(200),5038vap->iv_des_nssid, vap->iv_des_ssid);5039}50405041static void5042lkpi_ic_scan_end(struct ieee80211com *ic)5043{5044struct lkpi_hw *lhw;5045bool is_hw_scan;50465047lhw = ic->ic_softc;5048TRACE_SCAN(ic, "scan_flags %b", lhw->scan_flags, LKPI_LHW_SCAN_BITS);50495050LKPI_80211_LHW_SCAN_LOCK(lhw);5051if ((lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) == 0) {5052LKPI_80211_LHW_SCAN_UNLOCK(lhw);5053return;5054}5055is_hw_scan = (lhw->scan_flags & LKPI_LHW_SCAN_HW) != 0;5056LKPI_80211_LHW_SCAN_UNLOCK(lhw);50575058if (!is_hw_scan) {5059struct ieee80211_scan_state *ss;5060struct ieee80211vap *vap;5061struct ieee80211_hw *hw;5062struct lkpi_vif *lvif;5063struct ieee80211_vif *vif;50645065ss = ic->ic_scan;5066vap = ss->ss_vap;5067hw = LHW_TO_HW(lhw);5068lvif = VAP_TO_LVIF(vap);5069vif = LVIF_TO_VIF(lvif);50705071lkpi_80211_mo_sw_scan_complete(hw, vif);50725073/* Send PS to stop buffering if n80211 does not for us? */50745075if (vap->iv_state == IEEE80211_S_SCAN)5076lkpi_hw_conf_idle(hw, true);5077}50785079/*5080* In case we disabled the hw_scan in lkpi_ic_scan_start() and5081* switched to swscan, re-enable hw_scan if available.5082*/5083lkpi_enable_hw_scan(lhw);50845085LKPI_80211_LHW_SCAN_LOCK(lhw);5086wakeup(lhw);5087LKPI_80211_LHW_SCAN_UNLOCK(lhw);5088}50895090static void5091lkpi_ic_scan_curchan(struct ieee80211_scan_state *ss,5092unsigned long maxdwell)5093{5094struct lkpi_hw *lhw;5095bool is_hw_scan;50965097lhw = ss->ss_ic->ic_softc;5098TRACE_SCAN(ss->ss_ic, "scan_flags %b chan %d maxdwell %lu",5099lhw->scan_flags, LKPI_LHW_SCAN_BITS,5100ss->ss_ic->ic_curchan->ic_ieee, maxdwell);51015102LKPI_80211_LHW_SCAN_LOCK(lhw);5103is_hw_scan = (lhw->scan_flags & LKPI_LHW_SCAN_HW) != 0;5104LKPI_80211_LHW_SCAN_UNLOCK(lhw);5105if (!is_hw_scan)5106lhw->ic_scan_curchan(ss, maxdwell);5107}51085109static void5110lkpi_ic_scan_mindwell(struct ieee80211_scan_state *ss)5111{5112struct lkpi_hw *lhw;5113bool is_hw_scan;51145115lhw = ss->ss_ic->ic_softc;5116TRACE_SCAN(ss->ss_ic, "scan_flags %b chan %d mindwell %lu",5117lhw->scan_flags, LKPI_LHW_SCAN_BITS,5118ss->ss_ic->ic_curchan->ic_ieee, ss->ss_mindwell);51195120LKPI_80211_LHW_SCAN_LOCK(lhw);5121is_hw_scan = (lhw->scan_flags & LKPI_LHW_SCAN_HW) != 0;5122LKPI_80211_LHW_SCAN_UNLOCK(lhw);5123if (!is_hw_scan)5124lhw->ic_scan_mindwell(ss);5125}51265127static void5128lkpi_ic_set_channel(struct ieee80211com *ic)5129{5130struct lkpi_hw *lhw;5131struct ieee80211_hw *hw;5132struct ieee80211_channel *c;5133struct linuxkpi_ieee80211_channel *chan;5134int error;5135bool hw_scan_running;51365137lhw = ic->ic_softc;51385139/* If we do not support (*config)() save us the work. */5140if (lhw->ops->config == NULL)5141return;51425143/* If we have a hw_scan running do not switch channels. */5144LKPI_80211_LHW_SCAN_LOCK(lhw);5145hw_scan_running =5146(lhw->scan_flags & (LKPI_LHW_SCAN_RUNNING|LKPI_LHW_SCAN_HW)) ==5147(LKPI_LHW_SCAN_RUNNING|LKPI_LHW_SCAN_HW);5148LKPI_80211_LHW_SCAN_UNLOCK(lhw);5149if (hw_scan_running)5150return;51515152c = ic->ic_curchan;5153if (c == NULL || c == IEEE80211_CHAN_ANYC) {5154ic_printf(ic, "%s: c %p ops->config %p\n", __func__,5155c, lhw->ops->config);5156return;5157}51585159chan = lkpi_find_lkpi80211_chan(lhw, c);5160if (chan == NULL) {5161ic_printf(ic, "%s: c %p chan %p\n", __func__,5162c, chan);5163return;5164}51655166/* XXX max power for scanning? */5167IMPROVE();51685169hw = LHW_TO_HW(lhw);5170cfg80211_chandef_create(&hw->conf.chandef, chan,5171#ifdef LKPI_80211_HT5172(ic->ic_flags_ht & IEEE80211_FHT_HT) ? NL80211_CHAN_HT20 :5173#endif5174NL80211_CHAN_NO_HT);51755176error = lkpi_80211_mo_config(hw, IEEE80211_CONF_CHANGE_CHANNEL);5177if (error != 0 && error != EOPNOTSUPP) {5178ic_printf(ic, "ERROR: %s: config %#0x returned %d\n",5179__func__, IEEE80211_CONF_CHANGE_CHANNEL, error);5180/* XXX should we unroll to the previous chandef? */5181IMPROVE();5182} else {5183/* Update radiotap channels as well. */5184lhw->rtap_tx.wt_chan_freq = htole16(c->ic_freq);5185lhw->rtap_tx.wt_chan_flags = htole16(c->ic_flags);5186lhw->rtap_rx.wr_chan_freq = htole16(c->ic_freq);5187lhw->rtap_rx.wr_chan_flags = htole16(c->ic_flags);5188}51895190/* Currently PS is hard coded off! Not sure it belongs here. */5191IMPROVE();5192if (ieee80211_hw_check(hw, SUPPORTS_PS) &&5193(hw->conf.flags & IEEE80211_CONF_PS) != 0) {5194hw->conf.flags &= ~IEEE80211_CONF_PS;5195error = lkpi_80211_mo_config(hw, IEEE80211_CONF_CHANGE_PS);5196if (error != 0 && error != EOPNOTSUPP)5197ic_printf(ic, "ERROR: %s: config %#0x returned "5198"%d\n", __func__, IEEE80211_CONF_CHANGE_PS,5199error);5200}5201}52025203static struct ieee80211_node *5204lkpi_ic_node_alloc(struct ieee80211vap *vap,5205const uint8_t mac[IEEE80211_ADDR_LEN])5206{5207struct ieee80211com *ic;5208struct lkpi_hw *lhw;5209struct ieee80211_node *ni;5210struct ieee80211_hw *hw;5211struct lkpi_sta *lsta;52125213ic = vap->iv_ic;5214lhw = ic->ic_softc;52155216/* We keep allocations de-coupled so we can deal with the two worlds. */5217if (lhw->ic_node_alloc == NULL)5218return (NULL);52195220ni = lhw->ic_node_alloc(vap, mac);5221if (ni == NULL)5222return (NULL);52235224hw = LHW_TO_HW(lhw);5225lsta = lkpi_lsta_alloc(vap, mac, hw, ni);5226if (lsta == NULL) {5227if (lhw->ic_node_free != NULL)5228lhw->ic_node_free(ni);5229return (NULL);5230}52315232return (ni);5233}52345235static int5236lkpi_ic_node_init(struct ieee80211_node *ni)5237{5238struct ieee80211com *ic;5239struct lkpi_hw *lhw;5240int error;52415242ic = ni->ni_ic;5243lhw = ic->ic_softc;52445245if (lhw->ic_node_init != NULL) {5246error = lhw->ic_node_init(ni);5247if (error != 0)5248return (error);5249}52505251/* XXX-BZ Sync other state over. */5252IMPROVE();52535254return (0);5255}52565257static void5258lkpi_ic_node_cleanup(struct ieee80211_node *ni)5259{5260struct ieee80211com *ic;5261struct lkpi_hw *lhw;52625263ic = ni->ni_ic;5264lhw = ic->ic_softc;52655266/* XXX-BZ remove from driver, ... */5267IMPROVE();52685269if (lhw->ic_node_cleanup != NULL)5270lhw->ic_node_cleanup(ni);5271}52725273static void5274lkpi_ic_node_free(struct ieee80211_node *ni)5275{5276struct ieee80211com *ic;5277struct lkpi_hw *lhw;5278struct lkpi_sta *lsta;52795280ic = ni->ni_ic;5281lhw = ic->ic_softc;5282lsta = ni->ni_drv_data;52835284/* KASSERT lsta is not NULL here. Print ni/ni__refcnt. */52855286/*5287* Pass in the original ni just in case of error we could check that5288* it is the same as lsta->ni.5289*/5290lkpi_lsta_free(lsta, ni);52915292if (lhw->ic_node_free != NULL)5293lhw->ic_node_free(ni);5294}52955296/*5297* lkpi_xmit() called from both the (*ic_raw_xmit) as well as the (*ic_transmit)5298* call path.5299* Unfortunately they have slightly different invariants. See5300* ieee80211_raw_output() and ieee80211_parent_xmitpkt().5301* Both take care of the ni reference in case of error, and otherwise during5302* the callback after transmit.5303* The difference is that in case of error (*ic_raw_xmit) needs us to release5304* the mbuf, while (*ic_transmit) will free the mbuf itself.5305*/5306static int5307lkpi_xmit(struct ieee80211_node *ni, struct mbuf *m,5308const struct ieee80211_bpf_params *params __unused,5309bool freem)5310{5311struct lkpi_sta *lsta;5312int error;53135314lsta = ni->ni_drv_data;5315LKPI_80211_LSTA_TXQ_LOCK(lsta);5316#if 05317if (!lsta->added_to_drv || !lsta->txq_ready) {5318#else5319/*5320* Backout this part of 886653492945f which breaks rtw88 or5321* in general drivers without (*sta_state)() but only the5322* legacy fallback to (*sta_add)().5323*/5324if (!lsta->txq_ready) {5325#endif5326LKPI_80211_LSTA_TXQ_UNLOCK(lsta);5327if (freem)5328m_free(m);5329return (ENETDOWN);5330}53315332/* Queue the packet and enqueue the task to handle it. */5333error = mbufq_enqueue(&lsta->txq, m);5334if (error != 0) {5335LKPI_80211_LSTA_TXQ_UNLOCK(lsta);5336if (freem)5337m_free(m);5338#ifdef LINUXKPI_DEBUG_802115339if (linuxkpi_debug_80211 & D80211_TRACE_TX)5340ic_printf(ni->ni_ic, "%s: mbufq_enqueue failed: %d\n",5341__func__, error);5342#endif5343return (ENETDOWN);5344}5345taskqueue_enqueue(taskqueue_thread, &lsta->txq_task);5346LKPI_80211_LSTA_TXQ_UNLOCK(lsta);53475348#ifdef LINUXKPI_DEBUG_802115349if (linuxkpi_debug_80211 & D80211_TRACE_TX)5350printf("%s:%d lsta %p ni %p %6D mbuf_qlen %d\n",5351__func__, __LINE__, lsta, ni, ni->ni_macaddr, ":",5352mbufq_len(&lsta->txq));5353#endif53545355return (0);5356}53575358static int5359lkpi_ic_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,5360const struct ieee80211_bpf_params *params __unused)5361{5362return (lkpi_xmit(ni, m, NULL, true));5363}53645365#ifdef LKPI_80211_HW_CRYPTO5366/*5367* This is a bit of a hack given we know we are operating on a5368* single frame and we know that hardware will deal with it.5369* But otherwise the enmic bit and the encrypt bit need to be5370* decoupled.5371*/5372static int5373lkpi_hw_crypto_prepare_tkip(struct ieee80211_key *k,5374struct ieee80211_key_conf *kc, struct sk_buff *skb)5375{5376struct ieee80211_hdr *hdr;5377uint32_t hlen, hdrlen;5378uint8_t *p;53795380/*5381* TKIP only happens on data.5382*/5383hdr = (void *)skb->data;5384if (!ieee80211_is_data_present(hdr->frame_control))5385return (0);53865387/*5388* "enmic" (though we do not do that).5389*/5390/* any conditions to not apply this? */5391if (skb_tailroom(skb) < k->wk_cipher->ic_miclen)5392return (ENOBUFS);53935394p = skb_put(skb, k->wk_cipher->ic_miclen);5395if ((kc->flags & IEEE80211_KEY_FLAG_PUT_MIC_SPACE) != 0)5396goto encrypt;53975398/*5399* (*enmic) which we hopefully do not have to do with hw accel.5400* That means if we make it here we have a problem.5401*/5402TODO("(*enmic)");5403return (ENXIO);54045405encrypt:5406/*5407* "encrypt" (though we do not do that).5408*/5409/*5410* Check if we have anything to do as requested by driver5411* or if we are done?5412*/5413if ((kc->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) == 0 &&5414(kc->flags & IEEE80211_KEY_FLAG_GENERATE_IV) == 0)5415return (0);54165417hlen = k->wk_cipher->ic_header;5418if (skb_headroom(skb) < hlen)5419return (ENOBUFS);54205421hdr = (void *)skb->data;5422hdrlen = ieee80211_hdrlen(hdr->frame_control);5423p = skb_push(skb, hlen);5424memmove(p, p + hlen, hdrlen);54255426/* If driver request space only we are done. */5427if ((kc->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) != 0)5428return (0);54295430p += hdrlen;5431k->wk_cipher->ic_setiv(k, p);54325433/* If we make it hear we do sw encryption. */5434TODO("sw encrypt");5435return (ENXIO);5436}54375438static int5439lkpi_hw_crypto_prepare_ccmp(struct ieee80211_key *k,5440struct ieee80211_key_conf *kc, struct sk_buff *skb)5441{5442struct ieee80211_hdr *hdr;5443uint32_t hlen, hdrlen;5444uint8_t *p;54455446hdr = (void *)skb->data;54475448/*5449* Check if we have anythig to do as requested by driver5450* or if we are done?5451*/5452if ((kc->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) == 0 &&5453(kc->flags & IEEE80211_KEY_FLAG_GENERATE_IV) == 0 &&5454/* MFP */5455!((kc->flags & IEEE80211_KEY_FLAG_GENERATE_IV_MGMT) != 0 &&5456ieee80211_is_mgmt(hdr->frame_control)))5457return (0);54585459hlen = k->wk_cipher->ic_header;5460if (skb_headroom(skb) < hlen)5461return (ENOBUFS);54625463hdrlen = ieee80211_hdrlen(hdr->frame_control);5464p = skb_push(skb, hlen);5465memmove(p, p + hlen, hdrlen);54665467/* If driver request space only we are done. */5468if ((kc->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) != 0)5469return (0);54705471p += hdrlen;5472k->wk_cipher->ic_setiv(k, p);54735474return (0);5475}54765477static int5478lkpi_hw_crypto_prepare(struct lkpi_sta *lsta, struct ieee80211_key *k,5479struct sk_buff *skb)5480{5481struct ieee80211_tx_info *info;5482struct ieee80211_key_conf *kc;54835484KASSERT(lsta != NULL, ("%s: lsta is NULL", __func__));5485KASSERT(k != NULL, ("%s: key is NULL", __func__));5486KASSERT(skb != NULL, ("%s: skb is NULL", __func__));54875488kc = lsta->kc[k->wk_keyix];54895490info = IEEE80211_SKB_CB(skb);5491info->control.hw_key = kc;54925493/* MUST NOT happen. KASSERT? */5494if (kc == NULL) {5495ic_printf(lsta->ni->ni_ic, "%s: lsta %p k %p skb %p, "5496"kc is NULL on hw crypto offload\n", __func__, lsta, k, skb);5497return (ENXIO);5498}54995500switch (kc->cipher) {5501case WLAN_CIPHER_SUITE_TKIP:5502return (lkpi_hw_crypto_prepare_tkip(k, kc, skb));5503case WLAN_CIPHER_SUITE_CCMP:5504return (lkpi_hw_crypto_prepare_ccmp(k, kc, skb));5505case WLAN_CIPHER_SUITE_GCMP:5506return (lkpi_hw_crypto_prepare_ccmp(k, kc, skb));5507case WLAN_CIPHER_SUITE_WEP40:5508case WLAN_CIPHER_SUITE_WEP104:5509case WLAN_CIPHER_SUITE_CCMP_256:5510case WLAN_CIPHER_SUITE_GCMP_256:5511case WLAN_CIPHER_SUITE_AES_CMAC:5512case WLAN_CIPHER_SUITE_BIP_CMAC_256:5513case WLAN_CIPHER_SUITE_BIP_GMAC_128:5514case WLAN_CIPHER_SUITE_BIP_GMAC_256:5515default:5516ic_printf(lsta->ni->ni_ic, "%s: lsta %p k %p kc %p skb %p, "5517"unsupported cipher suite %u (%s)\n", __func__, lsta, k, kc,5518skb, kc->cipher, lkpi_cipher_suite_to_name(kc->cipher));5519return (EOPNOTSUPP);5520}5521}55225523static uint8_t5524lkpi_hw_crypto_tailroom(struct lkpi_sta *lsta, struct ieee80211_key *k)5525{5526struct ieee80211_key_conf *kc;55275528kc = lsta->kc[k->wk_keyix];5529if (kc == NULL)5530return (0);55315532IMPROVE("which other flags need tailroom?");5533if (kc->flags & (IEEE80211_KEY_FLAG_PUT_MIC_SPACE))5534return (32); /* Large enough to hold everything and pow2. */55355536return (0);5537}5538#endif55395540static void5541lkpi_80211_txq_tx_one(struct lkpi_sta *lsta, struct mbuf *m)5542{5543struct ieee80211_node *ni;5544struct ieee80211_frame *wh;5545struct ieee80211_key *k;5546struct sk_buff *skb;5547struct ieee80211com *ic;5548struct lkpi_hw *lhw;5549struct ieee80211_hw *hw;5550struct lkpi_vif *lvif;5551struct ieee80211_vif *vif;5552struct ieee80211_channel *c;5553struct ieee80211_tx_control control;5554struct ieee80211_tx_info *info;5555struct ieee80211_sta *sta;5556struct ieee80211_hdr *hdr;5557struct lkpi_txq *ltxq;5558void *buf;5559ieee80211_keyix keyix;5560uint8_t ac, tid, tailroom;55615562M_ASSERTPKTHDR(m);5563#ifdef LINUXKPI_DEBUG_802115564if (linuxkpi_debug_80211 & D80211_TRACE_TX_DUMP)5565hexdump(mtod(m, const void *), m->m_len, "RAW TX (plain) ", 0);5566#endif55675568ni = lsta->ni;5569ieee80211_output_seqno_assign(ni, -1, m);55705571k = NULL;5572keyix = IEEE80211_KEYIX_NONE;5573wh = mtod(m, struct ieee80211_frame *);5574if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {55755576#ifdef LKPI_80211_HW_CRYPTO5577if (lkpi_hwcrypto) {5578k = ieee80211_crypto_get_txkey(ni, m);5579if (k != NULL && lsta->kc[k->wk_keyix] != NULL)5580keyix = k->wk_keyix;5581}5582#endif55835584/* Encrypt the frame if need be. */5585if (keyix == IEEE80211_KEYIX_NONE) {5586/* Retrieve key for TX && do software encryption. */5587k = ieee80211_crypto_encap(ni, m);5588if (k == NULL) {5589ieee80211_free_node(ni);5590m_freem(m);5591return;5592}5593}5594}55955596ic = ni->ni_ic;5597lhw = ic->ic_softc;5598hw = LHW_TO_HW(lhw);5599c = ni->ni_chan;56005601if (ieee80211_radiotap_active_vap(ni->ni_vap)) {5602struct lkpi_radiotap_tx_hdr *rtap;56035604rtap = &lhw->rtap_tx;5605rtap->wt_flags = 0;5606if (k != NULL)5607rtap->wt_flags |= IEEE80211_RADIOTAP_F_WEP;5608if (m->m_flags & M_FRAG)5609rtap->wt_flags |= IEEE80211_RADIOTAP_F_FRAG;5610IMPROVE();5611rtap->wt_rate = 0;5612if (c != NULL && c != IEEE80211_CHAN_ANYC) {5613rtap->wt_chan_freq = htole16(c->ic_freq);5614rtap->wt_chan_flags = htole16(c->ic_flags);5615}56165617ieee80211_radiotap_tx(ni->ni_vap, m);5618}56195620#ifdef LKPI_80211_HW_CRYPTO5621if (lkpi_hwcrypto && keyix != IEEE80211_KEYIX_NONE)5622tailroom = lkpi_hw_crypto_tailroom(lsta, k);5623else5624#endif5625tailroom = 0;56265627/*5628* net80211 should handle hw->extra_tx_headroom.5629* Though for as long as we are copying we don't mind.5630* XXX-BZ rtw88 asks for too much headroom for ipv6+tcp:5631* https://lists.freebsd.org/archives/freebsd-transport/2022-February/000012.html5632*/5633skb = dev_alloc_skb(hw->extra_tx_headroom + tailroom + m->m_pkthdr.len);5634if (skb == NULL) {5635static uint8_t skb_alloc_failures = 0;56365637if (skb_alloc_failures++ == 0) {5638int tid;56395640sta = LSTA_TO_STA(lsta);5641ic_printf(ic, "ERROR %s: skb alloc failed %d + %d, lsta %p sta %p ni %p\n",5642__func__, hw->extra_tx_headroom, m->m_pkthdr.len, lsta, sta, ni);5643for (tid = 0; tid < nitems(sta->txq); tid++) {5644if (sta->txq[tid] == NULL)5645continue;5646ltxq = TXQ_TO_LTXQ(sta->txq[tid]);5647ic_printf(ic, " tid %d ltxq %p seen_dequeue %d stopped %d skb_queue_len %u\n",5648tid, ltxq, ltxq->seen_dequeue, ltxq->stopped, skb_queue_len(<xq->skbq));5649}5650}5651ieee80211_free_node(ni);5652m_freem(m);5653return;5654}5655skb_reserve(skb, hw->extra_tx_headroom);56565657/* XXX-BZ we need a SKB version understanding mbuf. */5658/* Save the mbuf for ieee80211_tx_complete(). */5659skb->m_free_func = lkpi_ieee80211_free_skb_mbuf;5660skb->m = m;5661#if 05662skb_put_data(skb, m->m_data, m->m_pkthdr.len);5663#else5664buf = skb_put(skb, m->m_pkthdr.len);5665m_copydata(m, 0, m->m_pkthdr.len, buf);5666#endif5667/* Save the ni. */5668m->m_pkthdr.PH_loc.ptr = ni;56695670lvif = VAP_TO_LVIF(ni->ni_vap);5671vif = LVIF_TO_VIF(lvif);56725673hdr = (void *)skb->data;5674tid = linuxkpi_ieee80211_get_tid(hdr, true);5675if (tid == IEEE80211_NONQOS_TID) { /* == IEEE80211_NUM_TIDS */5676if (!ieee80211_is_data(hdr->frame_control)) {5677/* MGMT and CTRL frames go on TID 7/VO. */5678skb->priority = 7;5679ac = IEEE80211_AC_VO;5680} else {5681/* Other non-QOS traffic goes to BE. */5682/* Contrary to net80211 we MUST NOT promote M_EAPOL. */5683skb->priority = 0;5684ac = IEEE80211_AC_BE;5685}5686} else {5687skb->priority = tid & IEEE80211_QOS_CTL_TID_MASK;5688ac = ieee80211e_up_to_ac[tid & 7];5689}5690skb_set_queue_mapping(skb, ac);56915692info = IEEE80211_SKB_CB(skb);5693info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;5694/* Slight delay; probably only happens on scanning so fine? */5695if (c == NULL || c == IEEE80211_CHAN_ANYC)5696c = ic->ic_curchan;5697info->band = lkpi_net80211_chan_to_nl80211_band(c);5698info->hw_queue = vif->hw_queue[ac];5699if ((m->m_flags & M_EAPOL) != 0) {5700info->control.flags |= IEEE80211_TX_CTRL_PORT_CTRL_PROTO;5701info->flags |= IEEE80211_TX_CTL_USE_MINRATE; /* mt76 */5702}5703info->control.vif = vif;5704/* XXX-BZ info->control.rates */5705#ifdef __notyet__5706#ifdef LKPI_80211_HT5707info->control.rts_cts_rate_idx=5708info->control.use_rts= /* RTS */5709info->control.use_cts_prot= /* RTS/CTS*/5710#endif5711#endif57125713sta = LSTA_TO_STA(lsta);5714#ifdef LKPI_80211_HW_CRYPTO5715if (lkpi_hwcrypto && keyix != IEEE80211_KEYIX_NONE) {5716int error;57175718error = lkpi_hw_crypto_prepare(lsta, k, skb);5719if (error != 0) {5720/*5721* We only have to free the skb which will free the5722* mbuf and release the reference on the ni.5723*/5724dev_kfree_skb(skb);5725return;5726}5727/* Reset header as data might have moved. */5728hdr = (void *)skb->data;5729}5730#endif57315732IMPROVE();57335734ltxq = NULL;5735if (!ieee80211_is_data_present(hdr->frame_control)) {5736if (vif->type == NL80211_IFTYPE_STATION &&5737lsta->added_to_drv &&5738sta->txq[IEEE80211_NUM_TIDS] != NULL)5739ltxq = TXQ_TO_LTXQ(sta->txq[IEEE80211_NUM_TIDS]);5740} else if (lsta->added_to_drv &&5741sta->txq[skb->priority] != NULL) {5742ltxq = TXQ_TO_LTXQ(sta->txq[skb->priority]);5743}5744if (ltxq == NULL)5745goto ops_tx;57465747KASSERT(ltxq != NULL, ("%s: lsta %p sta %p m %p skb %p "5748"ltxq %p != NULL\n", __func__, lsta, sta, m, skb, ltxq));57495750LKPI_80211_LTXQ_LOCK(ltxq);5751skb_queue_tail(<xq->skbq, skb);5752ltxq->frms_enqueued++;5753#ifdef LINUXKPI_DEBUG_802115754if (linuxkpi_debug_80211 & D80211_TRACE_TX)5755printf("%s:%d mo_wake_tx_queue :: %d %lu lsta %p sta %p "5756"ni %p %6D skb %p lxtq %p { qlen %u, ac %d tid %u } "5757"WAKE_TX_Q ac %d prio %u qmap %u\n",5758__func__, __LINE__,5759curthread->td_tid, jiffies,5760lsta, sta, ni, ni->ni_macaddr, ":", skb, ltxq,5761skb_queue_len(<xq->skbq), ltxq->txq.ac,5762ltxq->txq.tid, ac, skb->priority, skb->qmap);5763#endif5764LKPI_80211_LTXQ_UNLOCK(ltxq);5765wiphy_lock(hw->wiphy);5766lkpi_80211_mo_wake_tx_queue(hw, <xq->txq, true);5767wiphy_unlock(hw->wiphy);5768return;57695770ops_tx:5771#ifdef LINUXKPI_DEBUG_802115772if (linuxkpi_debug_80211 & D80211_TRACE_TX)5773printf("%s:%d mo_tx :: lsta %p sta %p ni %p %6D skb %p "5774"TX ac %d prio %u qmap %u\n",5775__func__, __LINE__, lsta, sta, ni, ni->ni_macaddr, ":",5776skb, ac, skb->priority, skb->qmap);5777#endif5778memset(&control, 0, sizeof(control));5779control.sta = sta;5780wiphy_lock(hw->wiphy);5781lkpi_80211_mo_tx(hw, &control, skb);5782lsta->frms_tx++;5783wiphy_unlock(hw->wiphy);5784}57855786static void5787lkpi_80211_txq_task(void *ctx, int pending)5788{5789struct lkpi_sta *lsta;5790struct mbufq mq;5791struct mbuf *m;5792bool shall_tx;57935794lsta = ctx;57955796#ifdef LINUXKPI_DEBUG_802115797if (linuxkpi_debug_80211 & D80211_TRACE_TX)5798printf("%s:%d lsta %p ni %p %6D pending %d mbuf_qlen %d\n",5799__func__, __LINE__, lsta, lsta->ni, lsta->ni->ni_macaddr, ":",5800pending, mbufq_len(&lsta->txq));5801#endif58025803mbufq_init(&mq, IFQ_MAXLEN);58045805LKPI_80211_LSTA_TXQ_LOCK(lsta);5806/*5807* Do not re-check lsta->txq_ready here; we may have a pending5808* disassoc/deauth frame still. On the contrary if txq_ready is5809* false we do not have a valid sta anymore in the firmware so no5810* point to try to TX.5811* We also use txq_ready as a semaphore and will drain the txq manually5812* if needed on our way towards SCAN/INIT in the state machine.5813*/5814#if 05815shall_tx = lsta->added_to_drv && lsta->txq_ready;5816#else5817/*5818* Backout this part of 886653492945f which breaks rtw88 or5819* in general drivers without (*sta_state)() but only the5820* legacy fallback to (*sta_add)().5821*/5822shall_tx = lsta->txq_ready;5823#endif5824if (__predict_true(shall_tx))5825mbufq_concat(&mq, &lsta->txq);5826/*5827* else a state change will push the packets out manually or5828* lkpi_lsta_free() will drain the lsta->txq and free the mbufs.5829*/5830LKPI_80211_LSTA_TXQ_UNLOCK(lsta);58315832m = mbufq_dequeue(&mq);5833while (m != NULL) {5834lkpi_80211_txq_tx_one(lsta, m);5835m = mbufq_dequeue(&mq);5836}5837}58385839static int5840lkpi_ic_transmit(struct ieee80211com *ic, struct mbuf *m)5841{58425843/* XXX TODO */5844IMPROVE();58455846/* Quick and dirty cheating hack. */5847struct ieee80211_node *ni;58485849ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;5850return (lkpi_xmit(ni, m, NULL, false));5851}58525853#ifdef LKPI_80211_HT5854static int5855lkpi_ic_recv_action(struct ieee80211_node *ni, const struct ieee80211_frame *wh,5856const uint8_t *frm, const uint8_t *efrm)5857{5858struct ieee80211com *ic;5859struct lkpi_hw *lhw;58605861ic = ni->ni_ic;5862lhw = ic->ic_softc;58635864IMPROVE_HT("recv_action called; nothing to do in lkpi; make debugging");58655866return (lhw->ic_recv_action(ni, wh, frm, efrm));5867}58685869static int5870lkpi_ic_send_action(struct ieee80211_node *ni, int category, int action, void *sa)5871{5872struct ieee80211com *ic;5873struct lkpi_hw *lhw;58745875ic = ni->ni_ic;5876lhw = ic->ic_softc;58775878IMPROVE_HT("send_action called; nothing to do in lkpi; make debugging");58795880return (lhw->ic_send_action(ni, category, action, sa));5881}588258835884static int5885lkpi_ic_ampdu_enable(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)5886{5887struct ieee80211com *ic;5888struct lkpi_hw *lhw;58895890ic = ni->ni_ic;5891lhw = ic->ic_softc;58925893IMPROVE_HT("ieee80211_ampdu_enable called; nothing to do in lkpi for now; make debugging");58945895return (lhw->ic_ampdu_enable(ni, tap));5896}58975898/*5899* (*ic_addba_request)() is called by ieee80211_ampdu_request() before5900* calling send_action(CAT_BA, BA_ADDBA_REQUEST).5901*5902* NB: returns 0 on ERROR!5903*/5904static int5905lkpi_ic_addba_request(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap,5906int dialogtoken, int baparamset, int batimeout)5907{5908struct ieee80211com *ic;5909struct lkpi_hw *lhw;5910struct ieee80211_hw *hw;5911struct ieee80211vap *vap;5912struct lkpi_vif *lvif;5913struct ieee80211_vif *vif;5914struct lkpi_sta *lsta;5915struct ieee80211_sta *sta;5916struct ieee80211_ampdu_params params = { };5917int error;59185919ic = ni->ni_ic;5920lhw = ic->ic_softc;5921hw = LHW_TO_HW(lhw);5922vap = ni->ni_vap;5923lvif = VAP_TO_LVIF(vap);5924vif = LVIF_TO_VIF(lvif);5925lsta = ni->ni_drv_data;5926sta = LSTA_TO_STA(lsta);59275928if (!lsta->added_to_drv) {5929ic_printf(ic, "%s: lsta %p ni %p, sta %p not added to firmware\n",5930__func__, lsta, ni, sta);5931return (0);5932}59335934params.sta = sta;5935params.action = IEEE80211_AMPDU_TX_START;5936/* Keep 0 here! */5937params.buf_size = 0;5938params.timeout = 0;5939params.ssn = tap->txa_start & (IEEE80211_SEQ_RANGE-1);5940params.tid = tap->txa_tid;5941params.amsdu = false;59425943IEEE80211_UNLOCK(ic);5944wiphy_lock(hw->wiphy);5945error = lkpi_80211_mo_ampdu_action(hw, vif, ¶ms);5946wiphy_unlock(hw->wiphy);5947IEEE80211_LOCK(ic);5948if (error != 0) {5949ic_printf(ic, "%s: mo_ampdu_action returned %d. ni %p tap %p\n",5950__func__, error, ni, tap);5951return (0);5952}59535954return (lhw->ic_addba_request(ni, tap, dialogtoken, baparamset, batimeout));5955}59565957/*5958* (*ic_addba_response)() is called from ht_recv_action_ba_addba_response()5959* and calls the default ieee80211_addba_response() which always returns 1.5960*5961* NB: No error checking in net80211!5962* Staying with 0 is an error.5963*/5964static int5965lkpi_ic_addba_response(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap,5966int status, int baparamset, int batimeout)5967{5968struct ieee80211com *ic;5969struct lkpi_hw *lhw;5970struct ieee80211_hw *hw;5971struct ieee80211vap *vap;5972struct lkpi_vif *lvif;5973struct ieee80211_vif *vif;5974struct lkpi_sta *lsta;5975struct ieee80211_sta *sta;5976struct ieee80211_ampdu_params params = { };5977int error;59785979ic = ni->ni_ic;5980lhw = ic->ic_softc;5981hw = LHW_TO_HW(lhw);5982vap = ni->ni_vap;5983lvif = VAP_TO_LVIF(vap);5984vif = LVIF_TO_VIF(lvif);5985lsta = ni->ni_drv_data;5986sta = LSTA_TO_STA(lsta);59875988if (!lsta->added_to_drv) {5989ic_printf(ic, "%s: lsta %p ni %p, sta %p not added to firmware\n",5990__func__, lsta, ni, sta);5991return (0);5992}59935994if (status == IEEE80211_STATUS_SUCCESS) {5995params.sta = sta;5996params.action = IEEE80211_AMPDU_TX_OPERATIONAL;5997params.buf_size = tap->txa_wnd;5998params.timeout = 0;5999params.ssn = 0;6000params.tid = tap->txa_tid;6001if ((tap->txa_flags & IEEE80211_AGGR_AMSDU) != 0)6002params.amsdu = true;6003else6004params.amsdu = false;6005} else {6006/* We need to free the allocated resources. */6007params.sta = sta;6008switch (status) {6009/* params.action = FLUSH, FLUSH_CONT */6010default:6011params.action = IEEE80211_AMPDU_TX_STOP_CONT;6012break;6013}6014params.buf_size = 0;6015params.timeout = 0;6016params.ssn = 0;6017params.tid = tap->txa_tid;6018params.amsdu = false;6019}60206021IEEE80211_UNLOCK(ic);6022wiphy_lock(hw->wiphy);6023error = lkpi_80211_mo_ampdu_action(hw, vif, ¶ms);6024wiphy_unlock(hw->wiphy);6025IEEE80211_LOCK(ic);6026if (error != 0) {6027ic_printf(ic, "%s: mo_ampdu_action returned %d. ni %p tap %p\n",6028__func__, error, ni, tap);6029return (0);6030}60316032IMPROVE_HT("who unleashes the TXQ? and when?, do we need to ni->ni_txseqs[tid] = tap->txa_start & 0xfff;");60336034return (lhw->ic_addba_response(ni, tap, status, baparamset, batimeout));6035}60366037/*6038* (*ic_addba_stop)() is called from ampdu_tx_stop(), ht_recv_action_ba_delba(),6039* and ieee80211_ampdu_stop() and calls the default ieee80211_addba_stop().6040*/6041static void6042lkpi_ic_addba_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)6043{6044struct ieee80211com *ic;6045struct lkpi_hw *lhw;6046struct ieee80211_hw *hw;6047struct ieee80211vap *vap;6048struct lkpi_vif *lvif;6049struct ieee80211_vif *vif;6050struct lkpi_sta *lsta;6051struct ieee80211_sta *sta;6052struct ieee80211_ampdu_params params = { };6053int error;60546055ic = ni->ni_ic;6056lhw = ic->ic_softc;6057hw = LHW_TO_HW(lhw);6058vap = ni->ni_vap;6059lvif = VAP_TO_LVIF(vap);6060vif = LVIF_TO_VIF(lvif);6061lsta = ni->ni_drv_data;6062sta = LSTA_TO_STA(lsta);60636064if (!lsta->added_to_drv) {6065ic_printf(ic, "%s: lsta %p ni %p, sta %p not added to firmware\n",6066__func__, lsta, ni, sta);6067goto n80211;6068}60696070/* We need to free the allocated resources. */6071params.sta = sta;6072IMPROVE("net80211 does not provide a reason to us");6073params.action = IEEE80211_AMPDU_TX_STOP_CONT; /* params.action = FLUSH, FLUSH_CONT */6074params.buf_size = 0;6075params.timeout = 0;6076params.ssn = 0;6077params.tid = tap->txa_tid;6078params.amsdu = false;60796080IEEE80211_UNLOCK(ic);6081wiphy_lock(hw->wiphy);6082error = lkpi_80211_mo_ampdu_action(hw, vif, ¶ms);6083wiphy_unlock(hw->wiphy);6084IEEE80211_LOCK(ic);6085if (error != 0) {6086ic_printf(ic, "%s: mo_ampdu_action returned %d. ni %p tap %p\n",6087__func__, error, ni, tap);6088goto n80211;6089}60906091IMPROVE_HT("anyting else?");60926093n80211:6094lhw->ic_addba_stop(ni, tap);6095}60966097static void6098lkpi_ic_addba_response_timeout(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)6099{6100struct ieee80211com *ic;6101struct lkpi_hw *lhw;61026103ic = ni->ni_ic;6104lhw = ic->ic_softc;61056106IMPROVE_HT();61076108lhw->ic_addba_response_timeout(ni, tap);6109}61106111static void6112lkpi_ic_bar_response(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap,6113int status)6114{6115struct ieee80211com *ic;6116struct lkpi_hw *lhw;61176118ic = ni->ni_ic;6119lhw = ic->ic_softc;61206121IMPROVE_HT();61226123lhw->ic_bar_response(ni, tap, status);6124}61256126static int6127lkpi_ic_ampdu_rx_start(struct ieee80211_node *ni, struct ieee80211_rx_ampdu *rap,6128int baparamset, int batimeout, int baseqctl)6129{6130struct ieee80211com *ic;6131struct lkpi_hw *lhw;6132struct ieee80211_hw *hw;6133struct ieee80211vap *vap;6134struct lkpi_vif *lvif;6135struct ieee80211_vif *vif;6136struct lkpi_sta *lsta;6137struct ieee80211_sta *sta;6138struct ieee80211_ampdu_params params = { };6139int error;61406141ic = ni->ni_ic;6142lhw = ic->ic_softc;6143hw = LHW_TO_HW(lhw);6144vap = ni->ni_vap;6145lvif = VAP_TO_LVIF(vap);6146vif = LVIF_TO_VIF(lvif);6147lsta = ni->ni_drv_data;6148sta = LSTA_TO_STA(lsta);61496150IEEE80211_UNLOCK_ASSERT(ic);61516152if (!lsta->added_to_drv) {6153ic_printf(ic, "%s: lsta %p ni %p vap %p, sta %p not added to firmware\n",6154__func__, lsta, ni, vap, sta);6155return (-ENXIO);6156}61576158if (lsta->state != IEEE80211_STA_AUTHORIZED) {6159ic_printf(ic, "%s: lsta %p ni %p vap %p, sta %p state %d not AUTHORIZED\n",6160__func__, lsta, ni, vap, sta, lsta->state);6161return (-ENXIO);6162}61636164params.sta = sta;6165params.action = IEEE80211_AMPDU_RX_START;6166params.buf_size = _IEEE80211_MASKSHIFT(le16toh(baparamset), IEEE80211_BAPS_BUFSIZ);6167if (params.buf_size == 0)6168params.buf_size = IEEE80211_MAX_AMPDU_BUF_HT;6169else6170params.buf_size = min(params.buf_size, IEEE80211_MAX_AMPDU_BUF_HT);6171if (hw->max_rx_aggregation_subframes > 0 &&6172params.buf_size > hw->max_rx_aggregation_subframes)6173params.buf_size = hw->max_rx_aggregation_subframes;6174params.timeout = le16toh(batimeout);6175params.ssn = _IEEE80211_MASKSHIFT(le16toh(baseqctl), IEEE80211_BASEQ_START);6176params.tid = _IEEE80211_MASKSHIFT(le16toh(baparamset), IEEE80211_BAPS_TID);61776178/* Based on net80211::ampdu_rx_start(). */6179if ((vap->iv_htcaps & IEEE80211_HTC_RX_AMSDU_AMPDU) &&6180(_IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_AMSDU)))6181params.amsdu = true;6182else6183params.amsdu = false;61846185wiphy_lock(hw->wiphy);6186error = lkpi_80211_mo_ampdu_action(hw, vif, ¶ms);6187wiphy_unlock(hw->wiphy);6188if (error != 0) {6189ic_printf(ic, "%s: mo_ampdu_action returned %d. ni %p rap %p\n",6190__func__, error, ni, rap);6191return (error);6192}61936194if (!ieee80211_hw_check(hw, SUPPORTS_REORDERING_BUFFER)) {6195IMPROVE("%s: TODO: SUPPORTS_REORDERING_BUFFER not set; check net80211\n", __func__);6196}61976198IMPROVE_HT("net80211 is missing the error check on return and assumes success");61996200error = lhw->ic_ampdu_rx_start(ni, rap, baparamset, batimeout, baseqctl);6201return (error);6202}62036204static void6205lkpi_ic_ampdu_rx_stop(struct ieee80211_node *ni, struct ieee80211_rx_ampdu *rap)6206{6207struct ieee80211com *ic;6208struct lkpi_hw *lhw;6209struct ieee80211_hw *hw;6210struct ieee80211vap *vap;6211struct lkpi_vif *lvif;6212struct ieee80211_vif *vif;6213struct lkpi_sta *lsta;6214struct ieee80211_sta *sta;6215struct ieee80211_ampdu_params params = { };6216int error;6217uint8_t tid;6218bool ic_locked;62196220ic = ni->ni_ic;6221lhw = ic->ic_softc;62226223/*6224* We should not (cannot) call into mac80211 ops with AMPDU_RX_STOP if6225* we did not START. Some drivers pass it down to firmware which will6226* simply barf and net80211 calls ieee80211_ht_node_cleanup() from6227* ieee80211_ht_node_init() amongst others which will iterate over all6228* tid and call ic_ampdu_rx_stop() unconditionally.6229* XXX net80211 should probably be more "gentle" in these cases and6230* track some state itself.6231*/6232if ((rap->rxa_flags & IEEE80211_AGGR_RUNNING) == 0)6233goto net80211_only;62346235hw = LHW_TO_HW(lhw);6236vap = ni->ni_vap;6237lvif = VAP_TO_LVIF(vap);6238vif = LVIF_TO_VIF(lvif);6239lsta = ni->ni_drv_data;6240if (lsta == NULL) {6241ic_printf(ic, "%s: lsta %p ni %p vap %p, lsta is NULL\n",6242__func__, lsta, ni, vap);6243goto net80211_only;6244}6245sta = LSTA_TO_STA(lsta);62466247if (!lsta->added_to_drv) {6248ic_printf(ic, "%s: lsta %p ni %p vap %p, sta %p not added to firmware\n",6249__func__, lsta, ni, vap, sta);6250goto net80211_only;6251}62526253if (lsta->state != IEEE80211_STA_AUTHORIZED) {6254ic_printf(ic, "%s: lsta %p ni %p vap %p, sta %p state %d not AUTHORIZED\n",6255__func__, lsta, ni, vap, sta, lsta->state);6256goto net80211_only;6257}62586259IMPROVE_HT("This really should be passed from ht_recv_action_ba_delba.");6260for (tid = 0; tid < WME_NUM_TID; tid++) {6261if (&ni->ni_rx_ampdu[tid] == rap)6262break;6263}6264if (tid == WME_NUM_TID) {6265ic_printf(ic, "%s: lsta %p ni %p vap %p, sta %p TID not found\n",6266__func__, lsta, ni, vap, sta);6267goto net80211_only;6268}62696270params.sta = sta;6271params.action = IEEE80211_AMPDU_RX_STOP;6272params.buf_size = 0;6273params.timeout = 0;6274params.ssn = 0;6275params.tid = tid;6276params.amsdu = false;62776278ic_locked = IEEE80211_IS_LOCKED(ic);6279if (ic_locked)6280IEEE80211_UNLOCK(ic);6281wiphy_lock(hw->wiphy);6282error = lkpi_80211_mo_ampdu_action(hw, vif, ¶ms);6283wiphy_unlock(hw->wiphy);6284if (ic_locked)6285IEEE80211_LOCK(ic);6286if (error != 0)6287ic_printf(ic, "%s: mo_ampdu_action returned %d. ni %p rap %p\n",6288__func__, error, ni, rap);62896290net80211_only:6291lhw->ic_ampdu_rx_stop(ni, rap);6292}6293#endif62946295static void6296lkpi_ic_getradiocaps_ht(struct ieee80211com *ic, struct ieee80211_hw *hw,6297uint8_t *bands, int *chan_flags, enum nl80211_band band)6298{6299#ifdef LKPI_80211_HT6300struct ieee80211_sta_ht_cap *ht_cap;63016302ht_cap = &hw->wiphy->bands[band]->ht_cap;6303if (!ht_cap->ht_supported)6304return;63056306switch (band) {6307case NL80211_BAND_2GHZ:6308setbit(bands, IEEE80211_MODE_11NG);6309break;6310case NL80211_BAND_5GHZ:6311setbit(bands, IEEE80211_MODE_11NA);6312break;6313default:6314IMPROVE("Unsupported band %d", band);6315return;6316}63176318ic->ic_htcaps = IEEE80211_HTC_HT; /* HT operation */63196320/*6321* Rather than manually checking each flag and6322* translating IEEE80211_HT_CAP_ to IEEE80211_HTCAP_,6323* simply copy the 16bits.6324*/6325ic->ic_htcaps |= ht_cap->cap;63266327/* Then deal with the other flags. */6328if (ieee80211_hw_check(hw, AMPDU_AGGREGATION))6329ic->ic_htcaps |= IEEE80211_HTC_AMPDU;6330#ifdef __notyet__6331if (ieee80211_hw_check(hw, TX_AMSDU))6332ic->ic_htcaps |= IEEE80211_HTC_AMSDU;6333if (ieee80211_hw_check(hw, SUPPORTS_AMSDU_IN_AMPDU))6334ic->ic_htcaps |= (IEEE80211_HTC_RX_AMSDU_AMPDU |6335IEEE80211_HTC_TX_AMSDU_AMPDU);6336#endif63376338IMPROVE("PS, ampdu_*, ht_cap.mcs.tx_params, ...");63396340/* Only add HT40 channels if supported. */6341if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) != 0 &&6342chan_flags != NULL)6343*chan_flags |= NET80211_CBW_FLAG_HT40;6344#endif6345}63466347static void6348lkpi_ic_getradiocaps(struct ieee80211com *ic, int maxchan,6349int *n, struct ieee80211_channel *c)6350{6351struct lkpi_hw *lhw;6352struct ieee80211_hw *hw;6353struct linuxkpi_ieee80211_channel *channels;6354uint8_t bands[IEEE80211_MODE_BYTES];6355int chan_flags, error, i, nchans;63566357/* Channels */6358lhw = ic->ic_softc;6359hw = LHW_TO_HW(lhw);63606361/* NL80211_BAND_2GHZ */6362nchans = 0;6363if (hw->wiphy->bands[NL80211_BAND_2GHZ] != NULL)6364nchans = hw->wiphy->bands[NL80211_BAND_2GHZ]->n_channels;6365if (nchans > 0) {6366memset(bands, 0, sizeof(bands));6367chan_flags = 0;6368setbit(bands, IEEE80211_MODE_11B);6369/* XXX-BZ unclear how to check for 11g. */63706371IMPROVE("the bitrates may have flags?");6372setbit(bands, IEEE80211_MODE_11G);63736374lkpi_ic_getradiocaps_ht(ic, hw, bands, &chan_flags,6375NL80211_BAND_2GHZ);63766377channels = hw->wiphy->bands[NL80211_BAND_2GHZ]->channels;6378for (i = 0; i < nchans && *n < maxchan; i++) {6379uint32_t nflags = 0;6380int cflags = chan_flags;63816382if (channels[i].flags & IEEE80211_CHAN_DISABLED) {6383ic_printf(ic, "%s: Skipping disabled chan "6384"[%u/%u/%#x]\n", __func__,6385channels[i].hw_value,6386channels[i].center_freq, channels[i].flags);6387continue;6388}6389if (channels[i].flags & IEEE80211_CHAN_NO_IR)6390nflags |= (IEEE80211_CHAN_NOADHOC|IEEE80211_CHAN_PASSIVE);6391if (channels[i].flags & IEEE80211_CHAN_RADAR)6392nflags |= IEEE80211_CHAN_DFS;6393if (channels[i].flags & IEEE80211_CHAN_NO_160MHZ)6394cflags &= ~(NET80211_CBW_FLAG_VHT160|NET80211_CBW_FLAG_VHT80P80);6395if (channels[i].flags & IEEE80211_CHAN_NO_80MHZ)6396cflags &= ~NET80211_CBW_FLAG_VHT80;6397/* XXX how to map the remaining enum ieee80211_channel_flags? */6398if (channels[i].flags & IEEE80211_CHAN_NO_HT40)6399cflags &= ~NET80211_CBW_FLAG_HT40;64006401error = ieee80211_add_channel_cbw(c, maxchan, n,6402ieee80211_mhz2ieee(channels[i].center_freq,6403lkpi_nl80211_band_to_net80211_band(channels[i].band)),6404channels[i].center_freq, channels[i].max_power,6405nflags, bands, cflags);6406/* net80211::ENOBUFS: *n >= maxchans */6407if (error != 0 && error != ENOBUFS)6408ic_printf(ic, "%s: Adding chan %u/%u/%#x/%#x/%#x/%#x "6409"returned error %d\n",6410__func__, channels[i].hw_value,6411channels[i].center_freq, channels[i].flags,6412nflags, chan_flags, cflags, error);6413if (error != 0)6414break;6415}6416}64176418/* NL80211_BAND_5GHZ */6419nchans = 0;6420if (hw->wiphy->bands[NL80211_BAND_5GHZ] != NULL)6421nchans = hw->wiphy->bands[NL80211_BAND_5GHZ]->n_channels;6422if (nchans > 0) {6423memset(bands, 0, sizeof(bands));6424chan_flags = 0;6425setbit(bands, IEEE80211_MODE_11A);64266427lkpi_ic_getradiocaps_ht(ic, hw, bands, &chan_flags,6428NL80211_BAND_5GHZ);64296430#ifdef LKPI_80211_VHT6431if (hw->wiphy->bands[NL80211_BAND_5GHZ]->vht_cap.vht_supported) {64326433ic->ic_flags_ext |= IEEE80211_FEXT_VHT;6434ic->ic_vht_cap.vht_cap_info =6435hw->wiphy->bands[NL80211_BAND_5GHZ]->vht_cap.cap;6436ic->ic_vht_cap.supp_mcs =6437hw->wiphy->bands[NL80211_BAND_5GHZ]->vht_cap.vht_mcs;64386439setbit(bands, IEEE80211_MODE_VHT_5GHZ);6440chan_flags |= NET80211_CBW_FLAG_VHT80;6441if (IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_IS_160MHZ(6442ic->ic_vht_cap.vht_cap_info))6443chan_flags |= NET80211_CBW_FLAG_VHT160;6444if (IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_IS_160_80P80MHZ(6445ic->ic_vht_cap.vht_cap_info))6446chan_flags |= NET80211_CBW_FLAG_VHT80P80;6447}6448#endif64496450channels = hw->wiphy->bands[NL80211_BAND_5GHZ]->channels;6451for (i = 0; i < nchans && *n < maxchan; i++) {6452uint32_t nflags = 0;6453int cflags = chan_flags;64546455if (channels[i].flags & IEEE80211_CHAN_DISABLED) {6456ic_printf(ic, "%s: Skipping disabled chan "6457"[%u/%u/%#x]\n", __func__,6458channels[i].hw_value,6459channels[i].center_freq, channels[i].flags);6460continue;6461}6462if (channels[i].flags & IEEE80211_CHAN_NO_IR)6463nflags |= (IEEE80211_CHAN_NOADHOC|IEEE80211_CHAN_PASSIVE);6464if (channels[i].flags & IEEE80211_CHAN_RADAR)6465nflags |= IEEE80211_CHAN_DFS;6466if (channels[i].flags & IEEE80211_CHAN_NO_160MHZ)6467cflags &= ~(NET80211_CBW_FLAG_VHT160|NET80211_CBW_FLAG_VHT80P80);6468if (channels[i].flags & IEEE80211_CHAN_NO_80MHZ)6469cflags &= ~NET80211_CBW_FLAG_VHT80;6470/* XXX hwo to map the remaining enum ieee80211_channel_flags? */6471if (channels[i].flags & IEEE80211_CHAN_NO_HT40)6472cflags &= ~NET80211_CBW_FLAG_HT40;64736474error = ieee80211_add_channel_cbw(c, maxchan, n,6475ieee80211_mhz2ieee(channels[i].center_freq,6476lkpi_nl80211_band_to_net80211_band(channels[i].band)),6477channels[i].center_freq, channels[i].max_power,6478nflags, bands, cflags);6479/* net80211::ENOBUFS: *n >= maxchans */6480if (error != 0 && error != ENOBUFS)6481ic_printf(ic, "%s: Adding chan %u/%u/%#x/%#x/%#x/%#x "6482"returned error %d\n",6483__func__, channels[i].hw_value,6484channels[i].center_freq, channels[i].flags,6485nflags, chan_flags, cflags, error);6486if (error != 0)6487break;6488}6489}6490}64916492static void *6493lkpi_ieee80211_ifalloc(void)6494{6495struct ieee80211com *ic;64966497ic = malloc(sizeof(*ic), M_LKPI80211, M_WAITOK | M_ZERO);64986499/* Setting these happens later when we have device information. */6500ic->ic_softc = NULL;6501ic->ic_name = "linuxkpi";65026503return (ic);6504}65056506struct ieee80211_hw *6507linuxkpi_ieee80211_alloc_hw(size_t priv_len, const struct ieee80211_ops *ops)6508{6509struct ieee80211_hw *hw;6510struct lkpi_hw *lhw;6511struct wiphy *wiphy;6512int ac;65136514/* Get us and the driver data also allocated. */6515wiphy = wiphy_new(&linuxkpi_mac80211cfgops, sizeof(*lhw) + priv_len);6516if (wiphy == NULL)6517return (NULL);65186519lhw = wiphy_priv(wiphy);6520lhw->ops = ops;65216522LKPI_80211_LHW_SCAN_LOCK_INIT(lhw);6523LKPI_80211_LHW_TXQ_LOCK_INIT(lhw);6524spin_lock_init(&lhw->txq_lock);6525sx_init_flags(&lhw->lvif_sx, "lhw-lvif", SX_RECURSE | SX_DUPOK);6526LKPI_80211_LHW_MC_LOCK_INIT(lhw);6527TAILQ_INIT(&lhw->lvif_head);6528__hw_addr_init(&lhw->mc_list);6529for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {6530spin_lock_init(&lhw->txq_scheduled_lock[ac]);6531lhw->txq_generation[ac] = 1;6532TAILQ_INIT(&lhw->txq_scheduled[ac]);6533}65346535/* Chanctx_conf */6536INIT_LIST_HEAD(&lhw->lchanctx_list);65376538/* Deferred RX path. */6539LKPI_80211_LHW_RXQ_LOCK_INIT(lhw);6540TASK_INIT(&lhw->rxq_task, 0, lkpi_80211_lhw_rxq_task, lhw);6541mbufq_init(&lhw->rxq, 32 * NAPI_POLL_WEIGHT);6542lhw->rxq_stopped = false;65436544/*6545* XXX-BZ TODO make sure there is a "_null" function to all ops6546* not initialized.6547*/6548hw = LHW_TO_HW(lhw);6549hw->wiphy = wiphy;6550hw->conf.flags |= IEEE80211_CONF_IDLE;6551hw->priv = (void *)(lhw + 1);65526553/* BSD Specific. */6554lhw->ic = lkpi_ieee80211_ifalloc();65556556IMPROVE();65576558return (hw);6559}65606561void6562linuxkpi_ieee80211_iffree(struct ieee80211_hw *hw)6563{6564struct lkpi_hw *lhw;6565struct mbuf *m;6566int ac;65676568lhw = HW_TO_LHW(hw);6569free(lhw->ic, M_LKPI80211);6570lhw->ic = NULL;65716572/*6573* Drain the deferred RX path.6574*/6575LKPI_80211_LHW_RXQ_LOCK(lhw);6576lhw->rxq_stopped = true;6577LKPI_80211_LHW_RXQ_UNLOCK(lhw);65786579/* Drain taskq, won't be restarted due to rxq_stopped being set. */6580while (taskqueue_cancel(taskqueue_thread, &lhw->rxq_task, NULL) != 0)6581taskqueue_drain(taskqueue_thread, &lhw->rxq_task);65826583/* Flush mbufq (make sure to release ni refs!). */6584m = mbufq_dequeue(&lhw->rxq);6585while (m != NULL) {6586#ifdef LKPI_80211_USE_MTAG6587struct m_tag *mtag;65886589mtag = m_tag_locate(m, MTAG_ABI_LKPI80211, LKPI80211_TAG_RXNI, NULL);6590if (mtag != NULL) {6591struct lkpi_80211_tag_rxni *rxni;65926593rxni = (struct lkpi_80211_tag_rxni *)(mtag + 1);6594ieee80211_free_node(rxni->ni);6595}6596#else6597if (m->m_pkthdr.PH_loc.ptr != NULL) {6598struct ieee80211_node *ni;65996600ni = m->m_pkthdr.PH_loc.ptr;6601ieee80211_free_node(ni);6602}6603#endif6604m_freem(m);6605m = mbufq_dequeue(&lhw->rxq);6606}6607KASSERT(mbufq_empty(&lhw->rxq), ("%s: lhw %p has rxq len %d != 0\n",6608__func__, lhw, mbufq_len(&lhw->rxq)));6609LKPI_80211_LHW_RXQ_LOCK_DESTROY(lhw);66106611/* Chanctx_conf. */6612if (!list_empty_careful(&lhw->lchanctx_list)) {6613struct lkpi_chanctx *lchanctx, *next;6614struct ieee80211_chanctx_conf *chanctx_conf;66156616list_for_each_entry_safe(lchanctx, next, &lhw->lchanctx_list, entry) {6617if (lchanctx->added_to_drv) {6618/* In reality we should panic? */6619chanctx_conf = &lchanctx->chanctx_conf;6620lkpi_80211_mo_remove_chanctx(hw, chanctx_conf);6621}6622list_del(&lchanctx->entry);6623free(lchanctx, M_LKPI80211);6624}6625}66266627LKPI_80211_LHW_MC_LOCK(lhw);6628lkpi_cleanup_mcast_list_locked(lhw);6629LKPI_80211_LHW_MC_UNLOCK(lhw);66306631for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)6632spin_lock_destroy(&lhw->txq_scheduled_lock[ac]);66336634/* Cleanup more of lhw here or in wiphy_free()? */6635spin_lock_destroy(&lhw->txq_lock);6636LKPI_80211_LHW_TXQ_LOCK_DESTROY(lhw);6637LKPI_80211_LHW_SCAN_LOCK_DESTROY(lhw);6638sx_destroy(&lhw->lvif_sx);6639LKPI_80211_LHW_MC_LOCK_DESTROY(lhw)6640IMPROVE();6641}66426643void6644linuxkpi_set_ieee80211_dev(struct ieee80211_hw *hw)6645{6646struct lkpi_hw *lhw;6647struct ieee80211com *ic;6648struct device *dev;66496650lhw = HW_TO_LHW(hw);6651ic = lhw->ic;66526653/* Save the backpointer from net80211 to LinuxKPI. */6654ic->ic_softc = lhw;66556656/*6657* Set a proper name before ieee80211_ifattach() if dev is set.6658* ath1xk also unset the dev so we need to check.6659*/6660dev = wiphy_dev(hw->wiphy);6661if (dev != NULL) {6662ic->ic_name = dev_name(dev);6663} else {6664TODO("adjust arguments to still have the old dev or go through "6665"the hoops of getting the bsddev from hw and detach; "6666"or do in XXX; check ath1kx drivers");6667}66686669/* XXX-BZ do we also need to set wiphy name? */6670}66716672struct ieee80211_hw *6673linuxkpi_wiphy_to_ieee80211_hw(struct wiphy *wiphy)6674{6675struct lkpi_hw *lhw;66766677lhw = wiphy_priv(wiphy);6678return (LHW_TO_HW(lhw));6679}66806681static void6682lkpi_radiotap_attach(struct lkpi_hw *lhw)6683{6684struct ieee80211com *ic;66856686ic = lhw->ic;6687ieee80211_radiotap_attach(ic,6688&lhw->rtap_tx.wt_ihdr, sizeof(lhw->rtap_tx),6689LKPI_RTAP_TX_FLAGS_PRESENT,6690&lhw->rtap_rx.wr_ihdr, sizeof(lhw->rtap_rx),6691LKPI_RTAP_RX_FLAGS_PRESENT);6692}66936694int6695linuxkpi_ieee80211_ifattach(struct ieee80211_hw *hw)6696{6697struct ieee80211com *ic;6698struct lkpi_hw *lhw;6699int band, i;67006701lhw = HW_TO_LHW(hw);6702ic = lhw->ic;67036704/* We do it this late as wiphy->dev should be set for the name. */6705lhw->workq = alloc_ordered_workqueue(wiphy_name(hw->wiphy), 0);6706if (lhw->workq == NULL)6707return (-EAGAIN);67086709/* XXX-BZ figure this out how they count his... */6710if (!is_zero_ether_addr(hw->wiphy->perm_addr)) {6711IEEE80211_ADDR_COPY(ic->ic_macaddr,6712hw->wiphy->perm_addr);6713} else if (hw->wiphy->n_addresses > 0) {6714/* We take the first one. */6715IEEE80211_ADDR_COPY(ic->ic_macaddr,6716hw->wiphy->addresses[0].addr);6717} else {6718ic_printf(ic, "%s: warning, no hardware address!\n", __func__);6719}67206721#ifdef __not_yet__6722/* See comment in lkpi_80211_txq_tx_one(). */6723ic->ic_headroom = hw->extra_tx_headroom;6724#endif67256726ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */6727ic->ic_opmode = IEEE80211_M_STA;67286729/* Set device capabilities. */6730/* XXX-BZ we need to get these from linux80211/drivers and convert. */6731ic->ic_caps =6732IEEE80211_C_STA |6733IEEE80211_C_MONITOR |6734IEEE80211_C_WPA | /* WPA/RSN */6735#ifdef LKPI_80211_WME6736IEEE80211_C_WME |6737#endif6738#if 06739IEEE80211_C_PMGT |6740#endif6741IEEE80211_C_SHSLOT | /* short slot time supported */6742IEEE80211_C_SHPREAMBLE /* short preamble supported */6743;67446745#ifdef LKPI_80211_BGSCAN6746if (lhw->ops->hw_scan)6747ic->ic_caps |= IEEE80211_C_BGSCAN;6748#endif67496750lkpi_enable_hw_scan(lhw);67516752/* Does HW support Fragmentation offload? */6753if (ieee80211_hw_check(hw, SUPPORTS_TX_FRAG))6754ic->ic_flags_ext |= IEEE80211_FEXT_FRAG_OFFLOAD;67556756/* Does HW support full AMPDU[-TX] offload? */6757if (ieee80211_hw_check(hw, AMPDU_AGGREGATION))6758ic->ic_flags_ext |= IEEE80211_FEXT_AMPDU_OFFLOAD;6759#ifdef __notyet__6760if (ieee80211_hw_check(hw, TX_AMSDU))6761if (ieee80211_hw_check(hw, SUPPORTS_AMSDU_IN_AMPDU))6762#endif67636764/*6765* The wiphy variables report bitmasks of avail antennas.6766* (*get_antenna) get the current bitmask sets which can be6767* altered by (*set_antenna) for some drivers.6768* XXX-BZ will the count alone do us much good long-term in net80211?6769*/6770if (hw->wiphy->available_antennas_rx ||6771hw->wiphy->available_antennas_tx) {6772uint32_t rxs, txs;67736774if (lkpi_80211_mo_get_antenna(hw, &txs, &rxs) == 0) {6775ic->ic_rxstream = bitcount32(rxs);6776ic->ic_txstream = bitcount32(txs);6777}6778}67796780ic->ic_cryptocaps = 0;6781#ifdef LKPI_80211_HW_CRYPTO6782if (lkpi_hwcrypto && hw->wiphy->n_cipher_suites > 0) {6783uint32_t hwciphers;67846785hwciphers = 0;6786for (i = 0; i < hw->wiphy->n_cipher_suites; i++) {6787uint32_t cs;67886789cs = lkpi_l80211_to_net80211_cyphers(6790ic, hw->wiphy->cipher_suites[i]);6791if (cs == IEEE80211_CRYPTO_TKIP) {6792/*6793* We do set this here. We will only find out6794* when doing a SET_KEY operation depending on6795* what the driver returns.6796* net80211::ieee80211_crypto_newkey()6797* checks this so we will have to do flags6798* surgery later.6799*/6800cs |= IEEE80211_CRYPTO_TKIPMIC;6801}6802hwciphers |= cs;6803}6804/*6805* (20250415) nothing anywhere in the path checks we actually6806* support all these in net80211.6807* net80211 supports _256 variants but the ioctl does not.6808*/6809IMPROVE("as net80211 grows more support, enable them");6810hwciphers &= (IEEE80211_CRYPTO_WEP |6811IEEE80211_CRYPTO_TKIP | IEEE80211_CRYPTO_TKIPMIC |6812IEEE80211_CRYPTO_AES_CCM | IEEE80211_CRYPTO_AES_GCM_128);6813/*6814* We only support CCMP here, so further filter.6815* Also permit TKIP if turned on.6816*/6817hwciphers &= (IEEE80211_CRYPTO_AES_CCM |6818IEEE80211_CRYPTO_AES_GCM_128 |6819(lkpi_hwcrypto_tkip ? (IEEE80211_CRYPTO_TKIP |6820IEEE80211_CRYPTO_TKIPMIC) : 0));6821ieee80211_set_hardware_ciphers(ic, hwciphers);6822}6823#endif68246825lkpi_ic_getradiocaps(ic, IEEE80211_CHAN_MAX, &ic->ic_nchans,6826ic->ic_channels);68276828ieee80211_ifattach(ic);68296830ic->ic_update_mcast = lkpi_ic_update_mcast;6831ic->ic_update_promisc = lkpi_ic_update_promisc;6832ic->ic_update_chw = lkpi_ic_update_chw;6833ic->ic_parent = lkpi_ic_parent;6834ic->ic_scan_start = lkpi_ic_scan_start;6835ic->ic_scan_end = lkpi_ic_scan_end;6836ic->ic_set_channel = lkpi_ic_set_channel;6837ic->ic_transmit = lkpi_ic_transmit;6838ic->ic_raw_xmit = lkpi_ic_raw_xmit;6839ic->ic_vap_create = lkpi_ic_vap_create;6840ic->ic_vap_delete = lkpi_ic_vap_delete;6841ic->ic_getradiocaps = lkpi_ic_getradiocaps;6842ic->ic_wme.wme_update = lkpi_ic_wme_update;68436844lhw->ic_scan_curchan = ic->ic_scan_curchan;6845ic->ic_scan_curchan = lkpi_ic_scan_curchan;6846lhw->ic_scan_mindwell = ic->ic_scan_mindwell;6847ic->ic_scan_mindwell = lkpi_ic_scan_mindwell;68486849lhw->ic_node_alloc = ic->ic_node_alloc;6850ic->ic_node_alloc = lkpi_ic_node_alloc;6851lhw->ic_node_init = ic->ic_node_init;6852ic->ic_node_init = lkpi_ic_node_init;6853lhw->ic_node_cleanup = ic->ic_node_cleanup;6854ic->ic_node_cleanup = lkpi_ic_node_cleanup;6855lhw->ic_node_free = ic->ic_node_free;6856ic->ic_node_free = lkpi_ic_node_free;68576858#ifdef LKPI_80211_HT6859/*6860* Only attach if the driver/firmware supports (*ampdu_action)().6861* Otherwise it is in the hands of net80211.6862*/6863if (lhw->ops->ampdu_action != NULL) {6864lhw->ic_recv_action = ic->ic_recv_action;6865ic->ic_recv_action = lkpi_ic_recv_action;6866lhw->ic_send_action = ic->ic_send_action;6867ic->ic_send_action = lkpi_ic_send_action;68686869lhw->ic_ampdu_enable = ic->ic_ampdu_enable;6870ic->ic_ampdu_enable = lkpi_ic_ampdu_enable;68716872lhw->ic_addba_request = ic->ic_addba_request;6873ic->ic_addba_request = lkpi_ic_addba_request;6874lhw->ic_addba_response = ic->ic_addba_response;6875ic->ic_addba_response = lkpi_ic_addba_response;6876lhw->ic_addba_stop = ic->ic_addba_stop;6877ic->ic_addba_stop = lkpi_ic_addba_stop;6878lhw->ic_addba_response_timeout = ic->ic_addba_response_timeout;6879ic->ic_addba_response_timeout = lkpi_ic_addba_response_timeout;68806881lhw->ic_bar_response = ic->ic_bar_response;6882ic->ic_bar_response = lkpi_ic_bar_response;68836884lhw->ic_ampdu_rx_start = ic->ic_ampdu_rx_start;6885ic->ic_ampdu_rx_start = lkpi_ic_ampdu_rx_start;6886lhw->ic_ampdu_rx_stop = ic->ic_ampdu_rx_stop;6887ic->ic_ampdu_rx_stop = lkpi_ic_ampdu_rx_stop;6888}6889#endif68906891lkpi_radiotap_attach(lhw);68926893/*6894* Assign the first possible channel for now; seems Realtek drivers6895* expect one.6896* Also remember the amount of bands we support and the most rates6897* in any band so we can scale [(ext) sup rates] IE(s) accordingly.6898*/6899lhw->supbands = lhw->max_rates = 0;6900for (band = 0; band < NUM_NL80211_BANDS; band++) {6901struct ieee80211_supported_band *supband;6902struct linuxkpi_ieee80211_channel *channels;69036904supband = hw->wiphy->bands[band];6905if (supband == NULL || supband->n_channels == 0)6906continue;69076908lhw->supbands++;6909lhw->max_rates = max(lhw->max_rates, supband->n_bitrates);69106911/* If we have a channel, we need to keep counting supbands. */6912if (hw->conf.chandef.chan != NULL)6913continue;69146915channels = supband->channels;6916for (i = 0; i < supband->n_channels; i++) {69176918if (channels[i].flags & IEEE80211_CHAN_DISABLED)6919continue;69206921cfg80211_chandef_create(&hw->conf.chandef, &channels[i],6922#ifdef LKPI_80211_HT6923(ic->ic_flags_ht & IEEE80211_FHT_HT) ? NL80211_CHAN_HT20 :6924#endif6925NL80211_CHAN_NO_HT);6926break;6927}6928}69296930IMPROVE("see net80211::ieee80211_chan_init vs. wiphy->bands[].bitrates possibly in lkpi_ic_getradiocaps?");69316932/* Make sure we do not support more than net80211 is willing to take. */6933if (lhw->max_rates > IEEE80211_RATE_MAXSIZE) {6934ic_printf(ic, "%s: limiting max_rates %d to %d!\n", __func__,6935lhw->max_rates, IEEE80211_RATE_MAXSIZE);6936lhw->max_rates = IEEE80211_RATE_MAXSIZE;6937}69386939/*6940* The maximum supported bitrates on any band + size for6941* DSSS Parameter Set give our per-band IE size.6942* SSID is the responsibility of the driver and goes on the side.6943* The user specified bits coming from the vap go into the6944* "common ies" fields.6945*/6946lhw->scan_ie_len = 2 + IEEE80211_RATE_SIZE;6947if (lhw->max_rates > IEEE80211_RATE_SIZE)6948lhw->scan_ie_len += 2 + (lhw->max_rates - IEEE80211_RATE_SIZE);69496950if (hw->wiphy->features & NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) {6951/*6952* net80211 does not seem to support the DSSS Parameter Set but6953* some of the drivers insert it so calculate the extra fixed6954* space in.6955*/6956lhw->scan_ie_len += 2 + 1;6957}69586959#if defined(LKPI_80211_HT)6960if ((ic->ic_htcaps & IEEE80211_HTC_HT) != 0)6961lhw->scan_ie_len += sizeof(struct ieee80211_ie_htcap);6962#endif6963#if defined(LKPI_80211_VHT)6964if (IEEE80211_CONF_VHT(ic))6965lhw->scan_ie_len += 2 + sizeof(struct ieee80211_vht_cap);6966#endif69676968/* Reduce the max_scan_ie_len "left" by the amount we consume already. */6969if (hw->wiphy->max_scan_ie_len > 0) {6970if (lhw->scan_ie_len > hw->wiphy->max_scan_ie_len)6971goto err;6972hw->wiphy->max_scan_ie_len -= lhw->scan_ie_len;6973}69746975if (bootverbose) {6976if (hw->netdev_features != 0)6977ic_printf(ic, "netdev_features %b\n",6978hw->netdev_features, NETIF_F_BITS);6979ieee80211_announce(ic);6980}69816982return (0);6983err:6984IMPROVE("TODO FIXME CLEANUP");6985return (-EAGAIN);6986}69876988void6989linuxkpi_ieee80211_ifdetach(struct ieee80211_hw *hw)6990{6991struct lkpi_hw *lhw;6992struct ieee80211com *ic;69936994lhw = HW_TO_LHW(hw);6995ic = lhw->ic;6996ieee80211_ifdetach(ic);6997}69986999void7000linuxkpi_ieee80211_iterate_interfaces(struct ieee80211_hw *hw,7001enum ieee80211_iface_iter flags,7002void(*iterfunc)(void *, uint8_t *, struct ieee80211_vif *),7003void *arg)7004{7005struct lkpi_hw *lhw;7006struct lkpi_vif *lvif;7007struct ieee80211_vif *vif;7008bool active, atomic, nin_drv;70097010lhw = HW_TO_LHW(hw);70117012if (flags & ~(IEEE80211_IFACE_ITER_NORMAL|7013IEEE80211_IFACE_ITER_RESUME_ALL|7014IEEE80211_IFACE_SKIP_SDATA_NOT_IN_DRIVER|7015IEEE80211_IFACE_ITER_ACTIVE|IEEE80211_IFACE_ITER__ATOMIC|7016IEEE80211_IFACE_ITER__MTX)) {7017ic_printf(lhw->ic, "XXX TODO %s flags(%#x) not yet supported.\n",7018__func__, flags);7019}70207021if ((flags & IEEE80211_IFACE_ITER__MTX) != 0)7022lockdep_assert_wiphy(hw->wiphy);70237024active = (flags & IEEE80211_IFACE_ITER_ACTIVE) != 0;7025atomic = (flags & IEEE80211_IFACE_ITER__ATOMIC) != 0;7026nin_drv = (flags & IEEE80211_IFACE_SKIP_SDATA_NOT_IN_DRIVER) != 0;70277028if (atomic) {7029IMPROVE("LKPI_80211_LHW_LVIF_LOCK atomic assume to be rcu?");7030LKPI_80211_LHW_LVIF_LOCK(lhw);7031}7032TAILQ_FOREACH(lvif, &lhw->lvif_head, lvif_entry) {7033struct ieee80211vap *vap;70347035vif = LVIF_TO_VIF(lvif);70367037/*7038* If we want "active" interfaces, we need to distinguish on7039* whether the driver knows about them or not to be able to7040* handle the "resume" case correctly. Skip the ones the7041* driver does not know about.7042*/7043if (active && !lvif->added_to_drv &&7044(flags & IEEE80211_IFACE_ITER_RESUME_ALL) != 0)7045continue;70467047/*7048* If we shall skip interfaces not added to the driver do so7049* if we haven't yet.7050*/7051if (nin_drv && !lvif->added_to_drv)7052continue;70537054/*7055* Run the iterator function if we are either not asking7056* asking for active only or if the VAP is "running".7057*/7058/* XXX-BZ probably should have state in the lvif as well. */7059vap = LVIF_TO_VAP(lvif);7060if (!active || (vap->iv_state != IEEE80211_S_INIT))7061iterfunc(arg, vif->addr, vif);7062}7063if (atomic)7064LKPI_80211_LHW_LVIF_UNLOCK(lhw);7065}70667067static void7068lkpi_ieee80211_iterate_keys(struct ieee80211_hw *hw, struct ieee80211_vif *vif,7069ieee80211_keyix keyix, struct lkpi_sta *lsta,7070void(*iterfunc)(struct ieee80211_hw *, struct ieee80211_vif *,7071struct ieee80211_sta *, struct ieee80211_key_conf *, void *),7072void *arg)7073{7074if (!lsta->added_to_drv)7075return;70767077if (lsta->kc[keyix] == NULL)7078return;70797080iterfunc(hw, vif, LSTA_TO_STA(lsta), lsta->kc[keyix], arg);7081}70827083void7084linuxkpi_ieee80211_iterate_keys(struct ieee80211_hw *hw,7085struct ieee80211_vif *vif,7086void(*iterfunc)(struct ieee80211_hw *, struct ieee80211_vif *,7087struct ieee80211_sta *, struct ieee80211_key_conf *, void *),7088void *arg, bool rcu)7089{7090struct lkpi_sta *lsta;7091struct lkpi_vif *lvif;70927093lvif = VIF_TO_LVIF(vif);70947095if (rcu) {7096rcu_read_lock_held(); /* XXX-BZ is this correct? */70977098if (vif == NULL) {7099TODO();7100} else {7101list_for_each_entry_rcu(lsta, &lvif->lsta_list, lsta_list) {7102for (ieee80211_keyix keyix = 0; keyix < nitems(lsta->kc);7103keyix++)7104lkpi_ieee80211_iterate_keys(hw, vif,7105keyix, lsta, iterfunc, arg);7106}7107}7108} else {7109TODO("Used by suspend/resume; order of keys as installed to "7110"firmware is important; we'll need to rewrite some code for that");7111lockdep_assert_wiphy(hw->wiphy);71127113if (vif == NULL) {7114TODO();7115} else {7116list_for_each_entry(lsta, &lvif->lsta_list, lsta_list) {7117for (ieee80211_keyix keyix = 0; keyix < nitems(lsta->kc);7118keyix++)7119lkpi_ieee80211_iterate_keys(hw, vif,7120keyix, lsta, iterfunc, arg);7121}7122}7123}7124}71257126void7127linuxkpi_ieee80211_iterate_chan_contexts(struct ieee80211_hw *hw,7128void(*iterfunc)(struct ieee80211_hw *, struct ieee80211_chanctx_conf *,7129void *),7130void *arg)7131{7132struct lkpi_hw *lhw;7133struct lkpi_chanctx *lchanctx;71347135KASSERT(hw != NULL && iterfunc != NULL,7136("%s: hw %p iterfunc %p arg %p\n", __func__, hw, iterfunc, arg));71377138lhw = HW_TO_LHW(hw);71397140rcu_read_lock();7141list_for_each_entry_rcu(lchanctx, &lhw->lchanctx_list, entry) {7142if (!lchanctx->added_to_drv)7143continue;7144iterfunc(hw, &lchanctx->chanctx_conf, arg);7145}7146rcu_read_unlock();7147}71487149void7150linuxkpi_ieee80211_iterate_stations_atomic(struct ieee80211_hw *hw,7151void (*iterfunc)(void *, struct ieee80211_sta *), void *arg)7152{7153struct lkpi_hw *lhw;7154struct lkpi_vif *lvif;7155struct lkpi_sta *lsta;7156struct ieee80211_sta *sta;71577158KASSERT(hw != NULL && iterfunc != NULL,7159("%s: hw %p iterfunc %p arg %p\n", __func__, hw, iterfunc, arg));71607161lhw = HW_TO_LHW(hw);71627163LKPI_80211_LHW_LVIF_LOCK(lhw);7164TAILQ_FOREACH(lvif, &lhw->lvif_head, lvif_entry) {71657166rcu_read_lock();7167list_for_each_entry_rcu(lsta, &lvif->lsta_list, lsta_list) {7168if (!lsta->added_to_drv)7169continue;7170sta = LSTA_TO_STA(lsta);7171iterfunc(arg, sta);7172}7173rcu_read_unlock();7174}7175LKPI_80211_LHW_LVIF_UNLOCK(lhw);7176}71777178struct linuxkpi_ieee80211_regdomain *7179lkpi_get_linuxkpi_ieee80211_regdomain(size_t n)7180{7181struct linuxkpi_ieee80211_regdomain *regd;71827183regd = kzalloc(sizeof(*regd) + n * sizeof(struct ieee80211_reg_rule),7184GFP_KERNEL);7185return (regd);7186}71877188int7189linuxkpi_regulatory_set_wiphy_regd_sync(struct wiphy *wiphy,7190struct linuxkpi_ieee80211_regdomain *regd)7191{7192struct lkpi_hw *lhw;7193struct ieee80211com *ic;7194struct ieee80211_regdomain *rd;71957196lhw = wiphy_priv(wiphy);7197ic = lhw->ic;71987199rd = &ic->ic_regdomain;7200if (rd->isocc[0] == '\0') {7201rd->isocc[0] = regd->alpha2[0];7202rd->isocc[1] = regd->alpha2[1];7203}72047205TODO();7206/* XXX-BZ finish the rest. */72077208return (0);7209}72107211void7212linuxkpi_ieee80211_scan_completed(struct ieee80211_hw *hw,7213struct cfg80211_scan_info *info)7214{7215struct lkpi_hw *lhw;7216struct ieee80211com *ic;7217struct ieee80211_scan_state *ss;72187219lhw = wiphy_priv(hw->wiphy);7220ic = lhw->ic;7221ss = ic->ic_scan;72227223TRACE_SCAN(ic, "scan_flags %b info { %ju, %6D, aborted %d }",7224lhw->scan_flags, LKPI_LHW_SCAN_BITS,7225(uintmax_t)info->scan_start_tsf, info->tsf_bssid, ":",7226info->aborted);72277228ieee80211_scan_done(ss->ss_vap);72297230LKPI_80211_LHW_SCAN_LOCK(lhw);7231free(lhw->hw_req, M_LKPI80211);7232lhw->hw_req = NULL;7233lhw->scan_flags &= ~LKPI_LHW_SCAN_RUNNING;7234/* The wakeup(lhw) will be called from lkpi_ic_scan_end(). */7235/* wakeup(lhw); */7236LKPI_80211_LHW_SCAN_UNLOCK(lhw);72377238return;7239}72407241static void7242lkpi_80211_lhw_rxq_rx_one(struct lkpi_hw *lhw, struct mbuf *m)7243{7244struct ieee80211_node *ni;7245#ifdef LKPI_80211_USE_MTAG7246struct m_tag *mtag;7247#endif7248int ok;72497250ni = NULL;7251#ifdef LKPI_80211_USE_MTAG7252mtag = m_tag_locate(m, MTAG_ABI_LKPI80211, LKPI80211_TAG_RXNI, NULL);7253if (mtag != NULL) {7254struct lkpi_80211_tag_rxni *rxni;72557256rxni = (struct lkpi_80211_tag_rxni *)(mtag + 1);7257ni = rxni->ni;7258}7259#else7260if (m->m_pkthdr.PH_loc.ptr != NULL) {7261ni = m->m_pkthdr.PH_loc.ptr;7262m->m_pkthdr.PH_loc.ptr = NULL;7263}7264#endif72657266if (ni != NULL) {7267ok = ieee80211_input_mimo(ni, m);7268ieee80211_free_node(ni); /* Release the reference. */7269if (ok < 0)7270m_freem(m);7271} else {7272ok = ieee80211_input_mimo_all(lhw->ic, m);7273/* mbuf got consumed. */7274}72757276#ifdef LINUXKPI_DEBUG_802117277if (linuxkpi_debug_80211 & D80211_TRACE_RX)7278printf("TRACE-RX: %s: handled frame type %#0x\n", __func__, ok);7279#endif7280}72817282static void7283lkpi_80211_lhw_rxq_task(void *ctx, int pending)7284{7285struct lkpi_hw *lhw;7286struct mbufq mq;7287struct mbuf *m;72887289lhw = ctx;72907291#ifdef LINUXKPI_DEBUG_802117292if (linuxkpi_debug_80211 & D80211_TRACE_RX)7293printf("TRACE-RX: %s: lhw %p pending %d mbuf_qlen %d\n",7294__func__, lhw, pending, mbufq_len(&lhw->rxq));7295#endif72967297mbufq_init(&mq, IFQ_MAXLEN);72987299LKPI_80211_LHW_RXQ_LOCK(lhw);7300mbufq_concat(&mq, &lhw->rxq);7301LKPI_80211_LHW_RXQ_UNLOCK(lhw);73027303m = mbufq_dequeue(&mq);7304while (m != NULL) {7305lkpi_80211_lhw_rxq_rx_one(lhw, m);7306m = mbufq_dequeue(&mq);7307}7308}73097310static void7311lkpi_convert_rx_status(struct ieee80211_hw *hw, struct lkpi_sta *lsta,7312struct ieee80211_rx_status *rx_status,7313struct ieee80211_rx_stats *rx_stats,7314uint8_t *rssip)7315{7316struct ieee80211_supported_band *supband;7317struct rate_info rxrate;7318int i;7319uint8_t rssi;73207321memset(&rxrate, 0, sizeof(rxrate));7322memset(rx_stats, 0, sizeof(*rx_stats));7323rx_stats->r_flags = IEEE80211_R_NF | IEEE80211_R_RSSI;7324/* XXX-BZ correct hardcoded noise floor, survey data? */7325rx_stats->c_nf = -96;7326if (ieee80211_hw_check(hw, SIGNAL_DBM) &&7327!(rx_status->flag & RX_FLAG_NO_SIGNAL_VAL))7328rssi = rx_status->signal;7329else7330rssi = rx_stats->c_nf;7331/*7332* net80211 signal strength data are in .5 dBm units relative to7333* the current noise floor (see comment in ieee80211_node.h).7334*/7335rssi -= rx_stats->c_nf;7336if (rssip != NULL)7337*rssip = rssi;7338rx_stats->c_rssi = rssi * 2;7339rx_stats->r_flags |= IEEE80211_R_BAND;7340rx_stats->c_band =7341lkpi_nl80211_band_to_net80211_band(rx_status->band);7342rx_stats->r_flags |= IEEE80211_R_FREQ | IEEE80211_R_IEEE;7343rx_stats->c_freq = rx_status->freq;7344rx_stats->c_ieee = ieee80211_mhz2ieee(rx_stats->c_freq, rx_stats->c_band);73457346rx_stats->c_rx_tsf = rx_status->mactime;73477348/* XXX RX_FLAG_MACTIME_IS_RTAP_TS64 ? */7349if ((rx_status->flag & RX_FLAG_MACTIME) ==7350(RX_FLAG_MACTIME_START|RX_FLAG_MACTIME_END)) {7351rx_stats->r_flags |= IEEE80211_R_TSF64;7352/* XXX RX_FLAG_MACTIME_PLCP_START ? */7353if ((rx_status->flag & RX_FLAG_MACTIME) == RX_FLAG_MACTIME_START)7354rx_stats->r_flags |= IEEE80211_R_TSF_START;7355if ((rx_status->flag & RX_FLAG_MACTIME) == RX_FLAG_MACTIME_END)7356rx_stats->r_flags |= IEEE80211_R_TSF_END;7357/* XXX-BZ if TSF_END will net80211 do the unwind of time? */7358}73597360if (rx_status->chains != 0) {7361int cc;7362int8_t crssi;73637364rx_stats->c_chain = rx_status->chains;7365rx_stats->r_flags |= IEEE80211_R_C_CHAIN;73667367cc = 0;7368for (i = 0; i < nitems(rx_status->chain_signal); i++) {7369if (!(rx_status->chains & BIT(i)))7370continue;7371crssi = rx_status->chain_signal[i];7372crssi -= rx_stats->c_nf;7373rx_stats->c_rssi_ctl[i] = crssi * 2;7374rx_stats->c_rssi_ext[i] = crssi * 2; /* XXX _ext ??? ATH thing? */7375/* We currently only have the global noise floor value. */7376rx_stats->c_nf_ctl[i] = rx_stats->c_nf;7377rx_stats->c_nf_ext[i] = rx_stats->c_nf;7378cc++;7379}7380if (cc > 0)7381rx_stats->r_flags |= (IEEE80211_R_C_NF | IEEE80211_R_C_RSSI);7382}73837384/* XXX-NET80211 We are not going to populate c_phytype! */73857386switch (rx_status->encoding) {7387case RX_ENC_LEGACY:7388{7389uint32_t legacy = 0;73907391supband = hw->wiphy->bands[rx_status->band];7392if (supband != NULL)7393legacy = supband->bitrates[rx_status->rate_idx].bitrate;7394rx_stats->c_rate = legacy;7395rxrate.legacy = legacy;7396/* Is there a LinuxKPI way of reporting IEEE80211_RX_F_CCK / _OFDM? */7397break;7398}7399case RX_ENC_HT:7400rx_stats->c_pktflags |= IEEE80211_RX_F_HT;7401rx_stats->c_rate = rx_status->rate_idx; /* mcs */7402rxrate.flags |= RATE_INFO_FLAGS_MCS;7403rxrate.mcs = rx_status->rate_idx;7404if ((rx_status->enc_flags & RX_ENC_FLAG_SHORT_GI) != 0) {7405rx_stats->c_pktflags |= IEEE80211_RX_F_SHORTGI;7406rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI;7407}7408break;7409case RX_ENC_VHT:7410rx_stats->c_pktflags |= IEEE80211_RX_F_VHT;7411rx_stats->c_rate = rx_status->rate_idx; /* mcs */7412rx_stats->c_vhtnss = rx_status->nss;7413rxrate.flags |= RATE_INFO_FLAGS_VHT_MCS;7414rxrate.mcs = rx_status->rate_idx;7415rxrate.nss = rx_status->nss;7416if ((rx_status->enc_flags & RX_ENC_FLAG_SHORT_GI) != 0) {7417rx_stats->c_pktflags |= IEEE80211_RX_F_SHORTGI;7418rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI;7419}7420break;7421case RX_ENC_HE:7422rxrate.flags |= RATE_INFO_FLAGS_HE_MCS;7423rxrate.mcs = rx_status->rate_idx;7424rxrate.nss = rx_status->nss;7425/* XXX TODO */7426TODO("net80211 has not matching encoding for %u", rx_status->encoding);7427break;7428case RX_ENC_EHT:7429rxrate.flags |= RATE_INFO_FLAGS_EHT_MCS;7430rxrate.mcs = rx_status->rate_idx;7431rxrate.nss = rx_status->nss;7432/* XXX TODO */7433TODO("net80211 has not matching encoding for %u", rx_status->encoding);7434break;7435}74367437rxrate.bw = rx_status->bw;7438switch (rx_status->bw) {7439case RATE_INFO_BW_20:7440rx_stats->c_width = IEEE80211_RX_FW_20MHZ;7441break;7442case RATE_INFO_BW_40:7443rx_stats->c_width = IEEE80211_RX_FW_40MHZ;7444break;7445case RATE_INFO_BW_80:7446rx_stats->c_width = IEEE80211_RX_FW_80MHZ;7447break;7448case RATE_INFO_BW_160:7449rx_stats->c_width = IEEE80211_RX_FW_160MHZ;7450break;7451case RATE_INFO_BW_320:7452case RATE_INFO_BW_HE_RU:7453case RATE_INFO_BW_EHT_RU:7454case RATE_INFO_BW_5:7455case RATE_INFO_BW_10:7456TODO("net80211 has not matching bandwidth for %u", rx_status->bw);7457break;7458}74597460if ((rx_status->enc_flags & RX_ENC_FLAG_LDPC) != 0)7461rx_stats->c_pktflags |= IEEE80211_RX_F_LDPC;7462if ((rx_status->enc_flags & RX_ENC_FLAG_STBC_MASK) != 0)7463rx_stats->c_pktflags |= IEEE80211_RX_F_STBC;74647465/*7466* We only need these for LKPI_80211_HW_CRYPTO in theory but in7467* case the hardware does something we do not expect always leave7468* these enabled. Leaving this commant as documentation for the || 1.7469*/7470#if defined(LKPI_80211_HW_CRYPTO) || 17471if (rx_status->flag & RX_FLAG_DECRYPTED) {7472rx_stats->c_pktflags |= IEEE80211_RX_F_DECRYPTED;7473/* Only valid if decrypted is set. */7474if (rx_status->flag & RX_FLAG_PN_VALIDATED)7475rx_stats->c_pktflags |= IEEE80211_RX_F_PN_VALIDATED;7476}7477if (rx_status->flag & RX_FLAG_IV_STRIPPED)7478rx_stats->c_pktflags |= IEEE80211_RX_F_IV_STRIP;7479if (rx_status->flag & RX_FLAG_ICV_STRIPPED)7480rx_stats->c_pktflags |= IEEE80211_RX_F_ICV_STRIP;7481if (rx_status->flag & RX_FLAG_MIC_STRIPPED)7482rx_stats->c_pktflags |= IEEE80211_RX_F_MIC_STRIP;7483if (rx_status->flag & RX_FLAG_MMIC_STRIPPED)7484rx_stats->c_pktflags |= IEEE80211_RX_F_MMIC_STRIP;7485if (rx_status->flag & RX_FLAG_MMIC_ERROR)7486rx_stats->c_pktflags |= IEEE80211_RX_F_FAIL_MMIC;7487if (rx_status->flag & RX_FLAG_FAILED_FCS_CRC)7488rx_stats->c_pktflags |= IEEE80211_RX_F_FAIL_FCSCRC;7489#endif74907491/* Fill in some sinfo bits to fill gaps not reported byt the driver. */7492if (lsta != NULL) {7493memcpy(&lsta->sinfo.rxrate, &rxrate, sizeof(rxrate));7494lsta->sinfo.filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE);74957496if (rx_status->chains != 0) {7497lsta->sinfo.chains = rx_status->chains;7498memcpy(lsta->sinfo.chain_signal, rx_status->chain_signal,7499sizeof(lsta->sinfo.chain_signal));7500lsta->sinfo.filled |= BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL);7501}7502}7503}75047505#ifdef LINUXKPI_DEBUG_802117506static void7507lkpi_rx_log_beacon(struct mbuf *m, struct lkpi_hw *lhw,7508struct ieee80211_rx_status *rx_status)7509{7510struct ieee80211_mgmt *f;7511uint8_t *e;7512char ssid[IEEE80211_NWID_LEN * 4 + 1];75137514memset(ssid, '\0', sizeof(ssid));75157516f = mtod(m, struct ieee80211_mgmt *);7517e = f->u.beacon.variable;7518/*7519* Usually SSID is right after the fixed part and for debugging we will7520* be fine should we miss it if it is not.7521*/7522while ((e - (uint8_t *)f) < m->m_len) {7523if (*e == IEEE80211_ELEMID_SSID)7524break;7525e += (2 + *(e + 1));7526}7527if (*e == IEEE80211_ELEMID_SSID) {7528int i, len;7529char *p;75307531p = ssid;7532len = m->m_len - ((e + 2) - (uint8_t *)f);7533if (len > *(e + 1))7534len = *(e + 1);7535e += 2;7536for (i = 0; i < len; i++) {7537/* Printable character? */7538if (*e >= 0x20 && *e < 0x7f) {7539*p++ = *e++;7540} else {7541snprintf(p, 5, "%#04x", *e++);7542p += 4;7543}7544}7545*p = '\0';7546}75477548/* We print skb, skb->data, m as we are seeing 'ghost beacons'. */7549TRACE_SCAN_BEACON(lhw->ic, "Beacon: scan_flags %b, band %s freq %u chan %-4d "7550"len %d { %#06x %#06x %6D %6D %6D %#06x %ju %u %#06x SSID '%s' }",7551lhw->scan_flags, LKPI_LHW_SCAN_BITS,7552lkpi_nl80211_band_name(rx_status->band), rx_status->freq,7553linuxkpi_ieee80211_frequency_to_channel(rx_status->freq, 0),7554m->m_pkthdr.len, f->frame_control, f->duration_id,7555f->da, ":", f->sa, ":", f->bssid, ":", f->seq_ctrl,7556(uintmax_t)le64_to_cpu(f->u.beacon.timestamp),7557le16_to_cpu(f->u.beacon.beacon_int),7558le16_to_cpu(f->u.beacon.capab_info), ssid);7559}7560#endif75617562/* For %list see comment towards the end of the function. */7563void7564linuxkpi_ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,7565struct ieee80211_sta *sta, struct napi_struct *napi __unused,7566struct list_head *list __unused)7567{7568struct lkpi_hw *lhw;7569struct ieee80211com *ic;7570struct mbuf *m;7571struct skb_shared_info *shinfo;7572struct ieee80211_rx_status *rx_status;7573struct ieee80211_rx_stats rx_stats;7574struct ieee80211_node *ni;7575struct ieee80211vap *vap;7576struct ieee80211_hdr *hdr;7577struct lkpi_sta *lsta;7578int i, offset, ok, error;7579uint8_t rssi;7580bool is_beacon;75817582lhw = HW_TO_LHW(hw);7583ic = lhw->ic;75847585if (skb->len < 2) {7586/* Need 80211 stats here. */7587counter_u64_add(ic->ic_ierrors, 1);7588IMPROVE();7589goto err;7590}75917592/*7593* For now do the data copy; we can later improve things. Might even7594* have an mbuf backing the skb data then?7595*/7596m = m_get3(skb->len, M_NOWAIT, MT_DATA, M_PKTHDR);7597if (m == NULL) {7598counter_u64_add(ic->ic_ierrors, 1);7599goto err;7600}7601m_copyback(m, 0, skb->tail - skb->data, skb->data);76027603shinfo = skb_shinfo(skb);7604offset = m->m_len;7605for (i = 0; i < shinfo->nr_frags; i++) {7606m_copyback(m, offset, shinfo->frags[i].size,7607(uint8_t *)linux_page_address(shinfo->frags[i].page) +7608shinfo->frags[i].offset);7609offset += shinfo->frags[i].size;7610}76117612rx_status = IEEE80211_SKB_RXCB(skb);76137614hdr = (void *)skb->data;7615is_beacon = ieee80211_is_beacon(hdr->frame_control);76167617#ifdef LINUXKPI_DEBUG_802117618/*7619* We use the mbuf here as otherwise the variable part might7620* be in skb frags.7621*/7622if (is_beacon && ((linuxkpi_debug_80211 & D80211_SCAN_BEACON) != 0))7623lkpi_rx_log_beacon(m, lhw, rx_status);76247625if (is_beacon && (linuxkpi_debug_80211 & D80211_TRACE_RX_BEACONS) == 0 &&7626(linuxkpi_debug_80211 & D80211_SCAN_BEACON) == 0)7627goto no_trace_beacons;76287629if (linuxkpi_debug_80211 & D80211_TRACE_RX)7630printf("TRACE-RX: %s: skb %p l/d/t-len (%u/%u/%u) "7631"h %p d %p t %p e %p sh %p (%u) m %p plen %u len %u%s\n",7632__func__, skb, skb->len, skb->data_len,7633skb->truesize, skb->head, skb->data, skb->tail, skb->end,7634shinfo, shinfo->nr_frags,7635m, m->m_pkthdr.len, m->m_len, is_beacon ? " beacon" : "");76367637if (linuxkpi_debug_80211 & D80211_TRACE_RX_DUMP)7638hexdump(mtod(m, const void *), m->m_len, "RX (raw) ", 0);76397640/* Implement a dump_rxcb() !!! */7641if ((linuxkpi_debug_80211 & D80211_TRACE_RX) != 0 ||7642(linuxkpi_debug_80211 & D80211_SCAN_BEACON) != 0)7643printf("TRACE-RX: %s: RXCB: %ju %ju %u, %b, %u, %#0x, %#0x, "7644"%u band %u, %u { %d %d %d %d }, %d, %#x %#x %#x %#x %u %u %u\n",7645__func__,7646(uintmax_t)rx_status->boottime_ns,7647(uintmax_t)rx_status->mactime,7648rx_status->device_timestamp,7649rx_status->flag, IEEE80211_RX_STATUS_FLAGS_BITS,7650rx_status->freq,7651rx_status->bw,7652rx_status->encoding,7653rx_status->ampdu_reference,7654rx_status->band,7655rx_status->chains,7656rx_status->chain_signal[0],7657rx_status->chain_signal[1],7658rx_status->chain_signal[2],7659rx_status->chain_signal[3],7660rx_status->signal,7661rx_status->enc_flags,7662rx_status->he_dcm,7663rx_status->he_gi,7664rx_status->he_ru,7665rx_status->zero_length_psdu_type,7666rx_status->nss,7667rx_status->rate_idx);7668no_trace_beacons:7669#endif76707671lsta = NULL;7672if (sta != NULL) {7673lsta = STA_TO_LSTA(sta);7674ni = ieee80211_ref_node(lsta->ni);7675} else {7676struct ieee80211_frame_min *wh;76777678wh = mtod(m, struct ieee80211_frame_min *);7679ni = ieee80211_find_rxnode(ic, wh);7680if (ni != NULL)7681lsta = ni->ni_drv_data;7682}76837684rssi = 0;7685lkpi_convert_rx_status(hw, lsta, rx_status, &rx_stats, &rssi);76867687ok = ieee80211_add_rx_params(m, &rx_stats);7688if (ok == 0) {7689m_freem(m);7690counter_u64_add(ic->ic_ierrors, 1);7691goto err;7692}76937694if (ni != NULL)7695vap = ni->ni_vap;7696else7697/*7698* XXX-BZ can we improve this by looking at the frame hdr7699* or other meta-data passed up?7700*/7701vap = TAILQ_FIRST(&ic->ic_vaps);77027703#ifdef LINUXKPI_DEBUG_802117704if (linuxkpi_debug_80211 & D80211_TRACE_RX)7705printf("TRACE-RX: %s: sta %p lsta %p state %d ni %p vap %p%s\n",7706__func__, sta, lsta, (lsta != NULL) ? lsta->state : -1,7707ni, vap, is_beacon ? " beacon" : "");7708#endif77097710if (ni != NULL && vap != NULL && is_beacon &&7711rx_status->device_timestamp > 0 &&7712m->m_pkthdr.len >= sizeof(struct ieee80211_frame)) {7713struct lkpi_vif *lvif;7714struct ieee80211_vif *vif;7715struct ieee80211_frame *wh;77167717wh = mtod(m, struct ieee80211_frame *);7718if (!IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_bssid))7719goto skip_device_ts;77207721lvif = VAP_TO_LVIF(vap);7722vif = LVIF_TO_VIF(lvif);77237724IMPROVE("TIMING_BEACON_ONLY?");7725/* mac80211 specific (not net80211) so keep it here. */7726vif->bss_conf.sync_device_ts = rx_status->device_timestamp;7727/*7728* net80211 should take care of the other information (sync_tsf,7729* sync_dtim_count) as otherwise we need to parse the beacon.7730*/7731skip_device_ts:7732;7733}77347735if (vap != NULL && vap->iv_state > IEEE80211_S_INIT &&7736ieee80211_radiotap_active_vap(vap)) {7737struct lkpi_radiotap_rx_hdr *rtap;77387739rtap = &lhw->rtap_rx;7740rtap->wr_tsft = rx_status->device_timestamp;7741rtap->wr_flags = 0;7742if (rx_status->enc_flags & RX_ENC_FLAG_SHORTPRE)7743rtap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;7744if (rx_status->enc_flags & RX_ENC_FLAG_SHORT_GI)7745rtap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTGI;7746#if 0 /* .. or it does not given we strip it below. */7747if (ieee80211_hw_check(hw, RX_INCLUDES_FCS))7748rtap->wr_flags |= IEEE80211_RADIOTAP_F_FCS;7749#endif7750if (rx_status->flag & RX_FLAG_FAILED_FCS_CRC)7751rtap->wr_flags |= IEEE80211_RADIOTAP_F_BADFCS;7752rtap->wr_rate = 0;7753IMPROVE();7754/* XXX TODO status->encoding / rate_index / bw */7755rtap->wr_chan_freq = htole16(rx_stats.c_freq);7756if (ic->ic_curchan->ic_ieee == rx_stats.c_ieee)7757rtap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);7758rtap->wr_dbm_antsignal = rssi;7759rtap->wr_dbm_antnoise = rx_stats.c_nf;7760}77617762if (ieee80211_hw_check(hw, RX_INCLUDES_FCS))7763m_adj(m, -IEEE80211_CRC_LEN);77647765#if 07766if (list != NULL) {7767/*7768* Normally this would be queued up and delivered by7769* netif_receive_skb_list(), napi_gro_receive(), or the like.7770* See mt76::mac80211.c as only current possible consumer.7771*/7772IMPROVE("we simply pass the packet to net80211 to deal with.");7773}7774#endif77757776/* Attach meta-information to the mbuf for the deferred RX path. */7777if (ni != NULL) {7778#ifdef LKPI_80211_USE_MTAG7779struct m_tag *mtag;7780struct lkpi_80211_tag_rxni *rxni;77817782mtag = m_tag_alloc(MTAG_ABI_LKPI80211, LKPI80211_TAG_RXNI,7783sizeof(*rxni), IEEE80211_M_NOWAIT);7784if (mtag == NULL) {7785m_freem(m);7786counter_u64_add(ic->ic_ierrors, 1);7787goto err;7788}7789rxni = (struct lkpi_80211_tag_rxni *)(mtag + 1);7790rxni->ni = ni; /* We hold a reference. */7791m_tag_prepend(m, mtag);7792#else7793m->m_pkthdr.PH_loc.ptr = ni; /* We hold a reference. */7794#endif7795}77967797LKPI_80211_LHW_RXQ_LOCK(lhw);7798if (lhw->rxq_stopped) {7799LKPI_80211_LHW_RXQ_UNLOCK(lhw);7800m_freem(m);7801counter_u64_add(ic->ic_ierrors, 1);7802goto err;7803}78047805error = mbufq_enqueue(&lhw->rxq, m);7806if (error != 0) {7807LKPI_80211_LHW_RXQ_UNLOCK(lhw);7808m_freem(m);7809counter_u64_add(ic->ic_ierrors, 1);7810#ifdef LINUXKPI_DEBUG_802117811if (linuxkpi_debug_80211 & D80211_TRACE_RX)7812ic_printf(ni->ni_ic, "%s: mbufq_enqueue failed: %d\n",7813__func__, error);7814#endif7815goto err;7816}7817taskqueue_enqueue(taskqueue_thread, &lhw->rxq_task);7818LKPI_80211_LHW_RXQ_UNLOCK(lhw);78197820IMPROVE();78217822err:7823/* The skb is ours so we can free it :-) */7824kfree_skb(skb);7825}78267827uint8_t7828linuxkpi_ieee80211_get_tid(struct ieee80211_hdr *hdr, bool nonqos_ok)7829{7830const struct ieee80211_frame *wh;7831uint8_t tid;78327833/* Linux seems to assume this is a QOS-Data-Frame */7834KASSERT(nonqos_ok || ieee80211_is_data_qos(hdr->frame_control),7835("%s: hdr %p fc %#06x not qos_data\n", __func__, hdr,7836hdr->frame_control));78377838wh = (const struct ieee80211_frame *)hdr;7839tid = ieee80211_gettid(wh);7840KASSERT(nonqos_ok || tid == (tid & IEEE80211_QOS_TID), ("%s: tid %u "7841"not expected (%u?)\n", __func__, tid, IEEE80211_NONQOS_TID));78427843return (tid);7844}78457846/* -------------------------------------------------------------------------- */78477848static void7849lkpi_wiphy_work(struct work_struct *work)7850{7851struct lkpi_wiphy *lwiphy;7852struct wiphy *wiphy;7853struct wiphy_work *wk;78547855lwiphy = container_of(work, struct lkpi_wiphy, wwk);7856wiphy = LWIPHY_TO_WIPHY(lwiphy);78577858wiphy_lock(wiphy);78597860LKPI_80211_LWIPHY_WORK_LOCK(lwiphy);7861wk = list_first_entry_or_null(&lwiphy->wwk_list, struct wiphy_work, entry);7862/* If there is nothing we do nothing. */7863if (wk == NULL) {7864LKPI_80211_LWIPHY_WORK_UNLOCK(lwiphy);7865wiphy_unlock(wiphy);7866return;7867}7868list_del_init(&wk->entry);78697870/* More work to do? */7871if (!list_empty(&lwiphy->wwk_list))7872schedule_work(work);7873LKPI_80211_LWIPHY_WORK_UNLOCK(lwiphy);78747875/* Finally call the (*wiphy_work_fn)() function. */7876wk->fn(wiphy, wk);78777878wiphy_unlock(wiphy);7879}78807881void7882linuxkpi_wiphy_work_queue(struct wiphy *wiphy, struct wiphy_work *wwk)7883{7884struct lkpi_wiphy *lwiphy;78857886lwiphy = WIPHY_TO_LWIPHY(wiphy);78877888LKPI_80211_LWIPHY_WORK_LOCK(lwiphy);7889/* Do not double-queue. */7890if (list_empty(&wwk->entry))7891list_add_tail(&wwk->entry, &lwiphy->wwk_list);7892LKPI_80211_LWIPHY_WORK_UNLOCK(lwiphy);78937894/*7895* See how ieee80211_queue_work() work continues in Linux or if things7896* migrate here over time?7897* Use a system queue from linux/workqueue.h for now.7898*/7899queue_work(system_wq, &lwiphy->wwk);7900}79017902void7903linuxkpi_wiphy_work_cancel(struct wiphy *wiphy, struct wiphy_work *wwk)7904{7905struct lkpi_wiphy *lwiphy;79067907lwiphy = WIPHY_TO_LWIPHY(wiphy);79087909LKPI_80211_LWIPHY_WORK_LOCK(lwiphy);7910/* Only cancel if queued. */7911if (!list_empty(&wwk->entry))7912list_del_init(&wwk->entry);7913LKPI_80211_LWIPHY_WORK_UNLOCK(lwiphy);7914}79157916void7917linuxkpi_wiphy_work_flush(struct wiphy *wiphy, struct wiphy_work *wwk)7918{7919struct lkpi_wiphy *lwiphy;7920struct wiphy_work *wk;79217922lwiphy = WIPHY_TO_LWIPHY(wiphy);7923LKPI_80211_LWIPHY_WORK_LOCK(lwiphy);7924/* If wwk is unset, flush everything; called when wiphy is shut down. */7925if (wwk != NULL && list_empty(&wwk->entry)) {7926LKPI_80211_LWIPHY_WORK_UNLOCK(lwiphy);7927return;7928}79297930while (!list_empty(&lwiphy->wwk_list)) {79317932wk = list_first_entry(&lwiphy->wwk_list, struct wiphy_work,7933entry);7934list_del_init(&wk->entry);7935LKPI_80211_LWIPHY_WORK_UNLOCK(lwiphy);7936wk->fn(wiphy, wk);7937LKPI_80211_LWIPHY_WORK_LOCK(lwiphy);7938if (wk == wwk)7939break;7940}7941LKPI_80211_LWIPHY_WORK_UNLOCK(lwiphy);7942}79437944void7945lkpi_wiphy_delayed_work_timer(struct timer_list *tl)7946{7947struct wiphy_delayed_work *wdwk;79487949wdwk = timer_container_of(wdwk, tl, timer);7950wiphy_work_queue(wdwk->wiphy, &wdwk->work);7951}79527953void7954linuxkpi_wiphy_delayed_work_queue(struct wiphy *wiphy,7955struct wiphy_delayed_work *wdwk, unsigned long delay)7956{7957if (delay == 0) {7958/* Run right away. */7959del_timer(&wdwk->timer);7960wiphy_work_queue(wiphy, &wdwk->work);7961} else {7962wdwk->wiphy = wiphy;7963mod_timer(&wdwk->timer, jiffies + delay);7964}7965}79667967void7968linuxkpi_wiphy_delayed_work_cancel(struct wiphy *wiphy,7969struct wiphy_delayed_work *wdwk)7970{7971del_timer_sync(&wdwk->timer);7972wiphy_work_cancel(wiphy, &wdwk->work);7973}79747975void7976linuxkpi_wiphy_delayed_work_flush(struct wiphy *wiphy,7977struct wiphy_delayed_work *wdwk)7978{7979lockdep_assert_held(&wiphy->mtx);79807981del_timer_sync(&wdwk->timer);7982wiphy_work_flush(wiphy, &wdwk->work);7983}79847985/* -------------------------------------------------------------------------- */79867987struct wiphy *7988linuxkpi_wiphy_new(const struct cfg80211_ops *ops, size_t priv_len)7989{7990struct lkpi_wiphy *lwiphy;7991struct wiphy *wiphy;79927993lwiphy = kzalloc(sizeof(*lwiphy) + priv_len, GFP_KERNEL);7994if (lwiphy == NULL)7995return (NULL);7996lwiphy->ops = ops;79977998LKPI_80211_LWIPHY_WORK_LOCK_INIT(lwiphy);7999INIT_LIST_HEAD(&lwiphy->wwk_list);8000INIT_WORK(&lwiphy->wwk, lkpi_wiphy_work);80018002wiphy = LWIPHY_TO_WIPHY(lwiphy);80038004mutex_init(&wiphy->mtx);8005TODO();80068007return (wiphy);8008}80098010void8011linuxkpi_wiphy_free(struct wiphy *wiphy)8012{8013struct lkpi_wiphy *lwiphy;80148015if (wiphy == NULL)8016return;80178018linuxkpi_wiphy_work_flush(wiphy, NULL);8019mutex_destroy(&wiphy->mtx);80208021lwiphy = WIPHY_TO_LWIPHY(wiphy);8022LKPI_80211_LWIPHY_WORK_LOCK_DESTROY(lwiphy);80238024kfree(lwiphy);8025}80268027static void8028lkpi_wiphy_band_annotate(struct wiphy *wiphy)8029{8030int band;80318032for (band = 0; band < NUM_NL80211_BANDS; band++) {8033struct ieee80211_supported_band *supband;8034int i;80358036supband = wiphy->bands[band];8037if (supband == NULL)8038continue;80398040switch (band) {8041case NL80211_BAND_2GHZ:8042case NL80211_BAND_5GHZ:8043break;8044default:8045#ifdef LINUXKPI_DEBUG_802118046IMPROVE("band %d(%s) not yet supported",8047band, lkpi_nl80211_band_name(band));8048/* For bands added here, also check lkpi_lsta_alloc(). */8049#endif8050continue;8051}80528053for (i = 0; i < supband->n_bitrates; i++) {8054switch (band) {8055case NL80211_BAND_2GHZ:8056switch (supband->bitrates[i].bitrate) {8057case 110:8058case 55:8059case 20:8060case 10:8061supband->bitrates[i].flags |=8062IEEE80211_RATE_MANDATORY_B;8063/* FALLTHROUGH */8064/* 11g only */8065case 240:8066case 120:8067case 60:8068supband->bitrates[i].flags |=8069IEEE80211_RATE_MANDATORY_G;8070break;8071}8072break;8073case NL80211_BAND_5GHZ:8074switch (supband->bitrates[i].bitrate) {8075case 240:8076case 120:8077case 60:8078supband->bitrates[i].flags |=8079IEEE80211_RATE_MANDATORY_A;8080break;8081}8082break;8083}8084}8085}8086}80878088int8089linuxkpi_80211_wiphy_register(struct wiphy *wiphy)8090{8091TODO("Lots of checks and initialization");80928093lkpi_wiphy_band_annotate(wiphy);80948095return (0);8096}80978098static uint32_t8099lkpi_cfg80211_calculate_bitrate_ht(struct rate_info *rate)8100{8101TODO("cfg80211_calculate_bitrate_ht");8102return (rate->legacy);8103}81048105static uint32_t8106lkpi_cfg80211_calculate_bitrate_vht(struct rate_info *rate)8107{8108TODO("cfg80211_calculate_bitrate_vht");8109return (rate->legacy);8110}81118112uint32_t8113linuxkpi_cfg80211_calculate_bitrate(struct rate_info *rate)8114{81158116/* Beware: order! */8117if (rate->flags & RATE_INFO_FLAGS_MCS)8118return (lkpi_cfg80211_calculate_bitrate_ht(rate));81198120if (rate->flags & RATE_INFO_FLAGS_VHT_MCS)8121return (lkpi_cfg80211_calculate_bitrate_vht(rate));81228123IMPROVE("HE/EHT/...");81248125return (rate->legacy);8126}81278128uint32_t8129linuxkpi_ieee80211_channel_to_frequency(uint32_t channel,8130enum nl80211_band band)8131{81328133switch (band) {8134case NL80211_BAND_2GHZ:8135return (ieee80211_ieee2mhz(channel, IEEE80211_CHAN_2GHZ));8136break;8137case NL80211_BAND_5GHZ:8138return (ieee80211_ieee2mhz(channel, IEEE80211_CHAN_5GHZ));8139break;8140default:8141/* XXX abort, retry, error, panic? */8142break;8143}81448145return (0);8146}81478148uint32_t8149linuxkpi_ieee80211_frequency_to_channel(uint32_t freq, uint32_t flags __unused)8150{81518152return (ieee80211_mhz2ieee(freq, 0));8153}81548155#if 08156static struct lkpi_sta *8157lkpi_find_lsta_by_ni(struct lkpi_vif *lvif, struct ieee80211_node *ni)8158{8159struct lkpi_sta *lsta, *temp;81608161rcu_read_lock();8162list_for_each_entry_rcu(lsta, &lvif->lsta_list, lsta_list) {8163if (lsta->ni == ni) {8164rcu_read_unlock();8165return (lsta);8166}8167}8168rcu_read_unlock();81698170return (NULL);8171}8172#endif81738174struct ieee80211_sta *8175linuxkpi_ieee80211_find_sta(struct ieee80211_vif *vif, const u8 *peer)8176{8177struct lkpi_vif *lvif;8178struct lkpi_sta *lsta;8179struct ieee80211_sta *sta;81808181lvif = VIF_TO_LVIF(vif);81828183rcu_read_lock();8184list_for_each_entry_rcu(lsta, &lvif->lsta_list, lsta_list) {8185sta = LSTA_TO_STA(lsta);8186if (IEEE80211_ADDR_EQ(sta->addr, peer)) {8187rcu_read_unlock();8188return (sta);8189}8190}8191rcu_read_unlock();8192return (NULL);8193}81948195struct ieee80211_sta *8196linuxkpi_ieee80211_find_sta_by_ifaddr(struct ieee80211_hw *hw,8197const uint8_t *addr, const uint8_t *ourvifaddr)8198{8199struct lkpi_hw *lhw;8200struct lkpi_vif *lvif;8201struct lkpi_sta *lsta;8202struct ieee80211_vif *vif;8203struct ieee80211_sta *sta;82048205lhw = wiphy_priv(hw->wiphy);8206sta = NULL;82078208LKPI_80211_LHW_LVIF_LOCK(lhw);8209TAILQ_FOREACH(lvif, &lhw->lvif_head, lvif_entry) {82108211/* XXX-BZ check our address from the vif. */82128213vif = LVIF_TO_VIF(lvif);8214if (ourvifaddr != NULL &&8215!IEEE80211_ADDR_EQ(vif->addr, ourvifaddr))8216continue;8217sta = linuxkpi_ieee80211_find_sta(vif, addr);8218if (sta != NULL)8219break;8220}8221LKPI_80211_LHW_LVIF_UNLOCK(lhw);82228223if (sta != NULL) {8224lsta = STA_TO_LSTA(sta);8225if (!lsta->added_to_drv)8226return (NULL);8227}82288229return (sta);8230}82318232struct sk_buff *8233linuxkpi_ieee80211_tx_dequeue(struct ieee80211_hw *hw,8234struct ieee80211_txq *txq)8235{8236struct lkpi_txq *ltxq;8237struct lkpi_vif *lvif;8238struct sk_buff *skb;82398240IMPROVE("wiphy_lock? or assert?");8241skb = NULL;8242ltxq = TXQ_TO_LTXQ(txq);8243ltxq->seen_dequeue = true;82448245if (ltxq->stopped)8246goto stopped;82478248lvif = VIF_TO_LVIF(ltxq->txq.vif);8249if (lvif->hw_queue_stopped[ltxq->txq.ac]) {8250ltxq->stopped = true;8251goto stopped;8252}82538254IMPROVE("hw(TX_FRAG_LIST)");82558256LKPI_80211_LTXQ_LOCK(ltxq);8257skb = skb_dequeue(<xq->skbq);8258if (skb != NULL)8259ltxq->frms_dequeued++;8260LKPI_80211_LTXQ_UNLOCK(ltxq);82618262stopped:8263return (skb);8264}82658266void8267linuxkpi_ieee80211_txq_get_depth(struct ieee80211_txq *txq,8268unsigned long *frame_cnt, unsigned long *byte_cnt)8269{8270struct lkpi_txq *ltxq;8271struct sk_buff *skb;8272unsigned long fc, bc;82738274ltxq = TXQ_TO_LTXQ(txq);82758276fc = bc = 0;8277LKPI_80211_LTXQ_LOCK(ltxq);8278skb_queue_walk(<xq->skbq, skb) {8279fc++;8280bc += skb->len;8281}8282LKPI_80211_LTXQ_UNLOCK(ltxq);8283if (frame_cnt)8284*frame_cnt = fc;8285if (byte_cnt)8286*byte_cnt = bc;82878288/* Validate that this is doing the correct thing. */8289/* Should we keep track on en/dequeue? */8290IMPROVE();8291}82928293/*8294* We are called from ieee80211_free_txskb() or ieee80211_tx_status().8295* The latter tries to derive the success status from the info flags8296* passed back from the driver. rawx_mit() saves the ni on the m and the8297* m on the skb for us to be able to give feedback to net80211.8298*/8299static void8300_lkpi_ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb,8301int status)8302{8303struct ieee80211_node *ni;8304struct mbuf *m;83058306if (skb == NULL)8307return;83088309m = skb->m;8310skb->m = NULL;83118312if (m != NULL) {8313ni = m->m_pkthdr.PH_loc.ptr;8314/* Status: 0 is ok, != 0 is error. */8315ieee80211_tx_complete(ni, m, status);8316/* ni & mbuf were consumed. */8317}8318}83198320void8321linuxkpi_ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb,8322int status)8323{83248325_lkpi_ieee80211_free_txskb(hw, skb, status);8326kfree_skb(skb);8327}83288329void8330linuxkpi_ieee80211_tx_status_ext(struct ieee80211_hw *hw,8331struct ieee80211_tx_status *txstat)8332{8333struct sk_buff *skb;8334struct ieee80211_tx_info *info, _info = { };8335struct ieee80211_ratectl_tx_status txs;8336struct ieee80211_node *ni;8337int status;83388339skb = txstat->skb;8340if (skb != NULL && skb->m != NULL) {8341struct mbuf *m;83428343m = skb->m;8344ni = m->m_pkthdr.PH_loc.ptr;8345memset(&txs, 0, sizeof(txs));8346} else {8347ni = NULL;8348}83498350/*8351* If we have no info information on tx, set info to an all-zero struct8352* to make the code (and debug output) simpler.8353*/8354info = txstat->info;8355if (info == NULL)8356info = &_info;8357if (info->flags & IEEE80211_TX_STAT_ACK) {8358status = 0; /* No error. */8359txs.status = IEEE80211_RATECTL_TX_SUCCESS;8360} else {8361status = 1;8362txs.status = IEEE80211_RATECTL_TX_FAIL_UNSPECIFIED;8363}83648365if (ni != NULL) {8366txs.pktlen = skb->len;8367txs.flags |= IEEE80211_RATECTL_STATUS_PKTLEN;8368if (info->status.rates[0].count > 1) {8369txs.long_retries = info->status.rates[0].count - 1; /* 1 + retries in drivers. */8370txs.flags |= IEEE80211_RATECTL_STATUS_LONG_RETRY;8371}8372#if 0 /* Unused in net80211 currently. */8373/* XXX-BZ convert check .flags for MCS/VHT/.. */8374txs.final_rate = info->status.rates[0].idx;8375txs.flags |= IEEE80211_RATECTL_STATUS_FINAL_RATE;8376#endif8377if (info->status.flags & IEEE80211_TX_STATUS_ACK_SIGNAL_VALID) {8378txs.rssi = info->status.ack_signal; /* XXX-BZ CONVERT? */8379txs.flags |= IEEE80211_RATECTL_STATUS_RSSI;8380}83818382IMPROVE("only update rate if needed but that requires us to get a proper rate from mo_sta_statistics");8383ieee80211_ratectl_tx_complete(ni, &txs);8384ieee80211_ratectl_rate(ni->ni_vap->iv_bss, NULL, 0);83858386#ifdef LINUXKPI_DEBUG_802118387if (linuxkpi_debug_80211 & D80211_TRACE_TX) {8388printf("TX-RATE: %s: long_retries %d\n", __func__,8389txs.long_retries);8390}8391#endif8392}83938394#ifdef LINUXKPI_DEBUG_802118395if (linuxkpi_debug_80211 & D80211_TRACE_TX)8396printf("TX-STATUS: %s: hw %p skb %p status %d : flags %#x "8397"band %u hw_queue %u tx_time_est %d : "8398"rates [ %u %u %#x, %u %u %#x, %u %u %#x, %u %u %#x ] "8399"ack_signal %u ampdu_ack_len %u ampdu_len %u antenna %u "8400"tx_time %u flags %#x "8401"status_driver_data [ %p %p ]\n",8402__func__, hw, skb, status, info->flags,8403info->band, info->hw_queue, info->tx_time_est,8404info->status.rates[0].idx, info->status.rates[0].count,8405info->status.rates[0].flags,8406info->status.rates[1].idx, info->status.rates[1].count,8407info->status.rates[1].flags,8408info->status.rates[2].idx, info->status.rates[2].count,8409info->status.rates[2].flags,8410info->status.rates[3].idx, info->status.rates[3].count,8411info->status.rates[3].flags,8412info->status.ack_signal, info->status.ampdu_ack_len,8413info->status.ampdu_len, info->status.antenna,8414info->status.tx_time, info->status.flags,8415info->status.status_driver_data[0],8416info->status.status_driver_data[1]);8417#endif84188419if (txstat->free_list) {8420_lkpi_ieee80211_free_txskb(hw, skb, status);8421if (skb != NULL)8422list_add_tail(&skb->list, txstat->free_list);8423} else {8424linuxkpi_ieee80211_free_txskb(hw, skb, status);8425}8426}84278428void8429linuxkpi_ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)8430{8431struct ieee80211_tx_status status;84328433memset(&status, 0, sizeof(status));8434status.info = IEEE80211_SKB_CB(skb);8435status.skb = skb;8436/* sta, n_rates, rates, free_list? */84378438ieee80211_tx_status_ext(hw, &status);8439}84408441/*8442* This is an internal bandaid for the moment for the way we glue8443* skbs and mbufs together for TX. Once we have skbs backed by8444* mbufs this should go away.8445* This is a public function but kept on the private KPI (lkpi_)8446* and is not exposed by a header file.8447*/8448static void8449lkpi_ieee80211_free_skb_mbuf(void *p)8450{8451struct ieee80211_node *ni;8452struct mbuf *m;84538454if (p == NULL)8455return;84568457m = (struct mbuf *)p;8458M_ASSERTPKTHDR(m);84598460ni = m->m_pkthdr.PH_loc.ptr;8461m->m_pkthdr.PH_loc.ptr = NULL;8462if (ni != NULL)8463ieee80211_free_node(ni);8464m_freem(m);8465}84668467void8468linuxkpi_ieee80211_queue_delayed_work(struct ieee80211_hw *hw,8469struct delayed_work *w, int delay)8470{8471struct lkpi_hw *lhw;84728473/* Need to make sure hw is in a stable (non-suspended) state. */8474IMPROVE();84758476lhw = HW_TO_LHW(hw);8477queue_delayed_work(lhw->workq, w, delay);8478}84798480void8481linuxkpi_ieee80211_queue_work(struct ieee80211_hw *hw,8482struct work_struct *w)8483{8484struct lkpi_hw *lhw;84858486/* Need to make sure hw is in a stable (non-suspended) state. */8487IMPROVE();84888489lhw = HW_TO_LHW(hw);8490queue_work(lhw->workq, w);8491}84928493struct sk_buff *8494linuxkpi_ieee80211_probereq_get(struct ieee80211_hw *hw, const uint8_t *addr,8495const uint8_t *ssid, size_t ssid_len, size_t tailroom)8496{8497struct sk_buff *skb;8498struct ieee80211_frame *wh;8499uint8_t *p;8500size_t len;85018502len = sizeof(*wh);8503len += 2 + ssid_len;85048505skb = dev_alloc_skb(hw->extra_tx_headroom + len + tailroom);8506if (skb == NULL)8507return (NULL);85088509skb_reserve(skb, hw->extra_tx_headroom);85108511wh = skb_put_zero(skb, sizeof(*wh));8512wh->i_fc[0] = IEEE80211_FC0_VERSION_0;8513wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_PROBE_REQ | IEEE80211_FC0_TYPE_MGT;8514IEEE80211_ADDR_COPY(wh->i_addr1, ieee80211broadcastaddr);8515IEEE80211_ADDR_COPY(wh->i_addr2, addr);8516IEEE80211_ADDR_COPY(wh->i_addr3, ieee80211broadcastaddr);85178518p = skb_put(skb, 2 + ssid_len);8519*p++ = IEEE80211_ELEMID_SSID;8520*p++ = ssid_len;8521if (ssid_len > 0)8522memcpy(p, ssid, ssid_len);85238524return (skb);8525}85268527struct sk_buff *8528linuxkpi_ieee80211_pspoll_get(struct ieee80211_hw *hw,8529struct ieee80211_vif *vif)8530{8531struct lkpi_vif *lvif;8532struct ieee80211vap *vap;8533struct sk_buff *skb;8534struct ieee80211_frame_pspoll *psp;8535uint16_t v;85368537skb = dev_alloc_skb(hw->extra_tx_headroom + sizeof(*psp));8538if (skb == NULL)8539return (NULL);85408541skb_reserve(skb, hw->extra_tx_headroom);85428543lvif = VIF_TO_LVIF(vif);8544vap = LVIF_TO_VAP(lvif);85458546psp = skb_put_zero(skb, sizeof(*psp));8547psp->i_fc[0] = IEEE80211_FC0_VERSION_0;8548psp->i_fc[0] |= IEEE80211_FC0_SUBTYPE_PS_POLL | IEEE80211_FC0_TYPE_CTL;8549v = htole16(vif->cfg.aid | 1<<15 | 1<<16);8550memcpy(&psp->i_aid, &v, sizeof(v));8551IEEE80211_ADDR_COPY(psp->i_bssid, vap->iv_bss->ni_macaddr);8552IEEE80211_ADDR_COPY(psp->i_ta, vif->addr);85538554return (skb);8555}85568557struct sk_buff *8558linuxkpi_ieee80211_nullfunc_get(struct ieee80211_hw *hw,8559struct ieee80211_vif *vif, int linkid, bool qos)8560{8561struct lkpi_vif *lvif;8562struct ieee80211vap *vap;8563struct sk_buff *skb;8564struct ieee80211_frame *nullf;85658566IMPROVE("linkid");85678568skb = dev_alloc_skb(hw->extra_tx_headroom + sizeof(*nullf));8569if (skb == NULL)8570return (NULL);85718572skb_reserve(skb, hw->extra_tx_headroom);85738574lvif = VIF_TO_LVIF(vif);8575vap = LVIF_TO_VAP(lvif);85768577nullf = skb_put_zero(skb, sizeof(*nullf));8578nullf->i_fc[0] = IEEE80211_FC0_VERSION_0;8579nullf->i_fc[0] |= IEEE80211_FC0_SUBTYPE_NODATA | IEEE80211_FC0_TYPE_DATA;8580nullf->i_fc[1] = IEEE80211_FC1_DIR_TODS;85818582IEEE80211_ADDR_COPY(nullf->i_addr1, vap->iv_bss->ni_bssid);8583IEEE80211_ADDR_COPY(nullf->i_addr2, vif->addr);8584IEEE80211_ADDR_COPY(nullf->i_addr3, vap->iv_bss->ni_macaddr);85858586return (skb);8587}85888589struct wireless_dev *8590linuxkpi_ieee80211_vif_to_wdev(struct ieee80211_vif *vif)8591{8592struct lkpi_vif *lvif;85938594lvif = VIF_TO_LVIF(vif);8595return (&lvif->wdev);8596}85978598void8599linuxkpi_ieee80211_connection_loss(struct ieee80211_vif *vif)8600{8601struct lkpi_vif *lvif;8602struct ieee80211vap *vap;8603enum ieee80211_state nstate;8604int arg;86058606lvif = VIF_TO_LVIF(vif);8607vap = LVIF_TO_VAP(lvif);86088609/*8610* Go to init; otherwise we need to elaborately check state and8611* handle accordingly, e.g., if in RUN we could call iv_bmiss.8612* Let the statemachine handle all neccessary changes.8613*/8614nstate = IEEE80211_S_INIT;8615arg = 0; /* Not a valid reason. */86168617ic_printf(vap->iv_ic, "%s: vif %p vap %p state %s (synched %d, assoc %d "8618"beacons %d dtim_period %d)\n", __func__, vif, vap,8619ieee80211_state_name[vap->iv_state],8620lvif->lvif_bss_synched, vif->cfg.assoc, lvif->beacons,8621vif->bss_conf.dtim_period);8622ieee80211_new_state(vap, nstate, arg);8623}86248625void8626linuxkpi_ieee80211_beacon_loss(struct ieee80211_vif *vif)8627{8628struct lkpi_vif *lvif;8629struct ieee80211vap *vap;86308631lvif = VIF_TO_LVIF(vif);8632vap = LVIF_TO_VAP(lvif);86338634ic_printf(vap->iv_ic, "%s: vif %p vap %p state %s (synched %d, assoc %d "8635"beacons %d dtim_period %d)\n", __func__, vif, vap,8636ieee80211_state_name[vap->iv_state],8637lvif->lvif_bss_synched, vif->cfg.assoc, lvif->beacons,8638vif->bss_conf.dtim_period);8639ieee80211_beacon_miss(vap->iv_ic);8640}86418642/* -------------------------------------------------------------------------- */86438644void8645linuxkpi_ieee80211_stop_queue(struct ieee80211_hw *hw, int qnum)8646{8647struct lkpi_hw *lhw;8648struct lkpi_vif *lvif;8649struct ieee80211_vif *vif;8650int ac_count, ac;86518652KASSERT(qnum < hw->queues, ("%s: qnum %d >= hw->queues %d, hw %p\n",8653__func__, qnum, hw->queues, hw));86548655lhw = wiphy_priv(hw->wiphy);86568657/* See lkpi_ic_vap_create(). */8658if (hw->queues >= IEEE80211_NUM_ACS)8659ac_count = IEEE80211_NUM_ACS;8660else8661ac_count = 1;86628663LKPI_80211_LHW_LVIF_LOCK(lhw);8664TAILQ_FOREACH(lvif, &lhw->lvif_head, lvif_entry) {86658666vif = LVIF_TO_VIF(lvif);8667for (ac = 0; ac < ac_count; ac++) {8668IMPROVE_TXQ("LOCKING");8669if (qnum == vif->hw_queue[ac]) {8670#ifdef LINUXKPI_DEBUG_802118671/*8672* For now log this to better understand8673* how this is supposed to work.8674*/8675if (lvif->hw_queue_stopped[ac] &&8676(linuxkpi_debug_80211 & D80211_IMPROVE_TXQ) != 0)8677ic_printf(lhw->ic, "%s:%d: lhw %p hw %p "8678"lvif %p vif %p ac %d qnum %d already "8679"stopped\n", __func__, __LINE__,8680lhw, hw, lvif, vif, ac, qnum);8681#endif8682lvif->hw_queue_stopped[ac] = true;8683}8684}8685}8686LKPI_80211_LHW_LVIF_UNLOCK(lhw);8687}86888689void8690linuxkpi_ieee80211_stop_queues(struct ieee80211_hw *hw)8691{8692int i;86938694IMPROVE_TXQ("Locking; do we need further info?");8695for (i = 0; i < hw->queues; i++)8696linuxkpi_ieee80211_stop_queue(hw, i);8697}869886998700static void8701lkpi_ieee80211_wake_queues(struct ieee80211_hw *hw, int hwq)8702{8703struct lkpi_hw *lhw;8704struct lkpi_vif *lvif;8705struct lkpi_sta *lsta;8706int ac_count, ac, tid;87078708/* See lkpi_ic_vap_create(). */8709if (hw->queues >= IEEE80211_NUM_ACS)8710ac_count = IEEE80211_NUM_ACS;8711else8712ac_count = 1;87138714lhw = wiphy_priv(hw->wiphy);87158716IMPROVE_TXQ("Locking");8717LKPI_80211_LHW_LVIF_LOCK(lhw);8718TAILQ_FOREACH(lvif, &lhw->lvif_head, lvif_entry) {8719struct ieee80211_vif *vif;87208721vif = LVIF_TO_VIF(lvif);8722for (ac = 0; ac < ac_count; ac++) {87238724if (hwq == vif->hw_queue[ac]) {87258726/* XXX-BZ what about software scan? */87278728#ifdef LINUXKPI_DEBUG_802118729/*8730* For now log this to better understand8731* how this is supposed to work.8732*/8733if (!lvif->hw_queue_stopped[ac] &&8734(linuxkpi_debug_80211 & D80211_IMPROVE_TXQ) != 0)8735ic_printf(lhw->ic, "%s:%d: lhw %p hw %p "8736"lvif %p vif %p ac %d hw_q not stopped\n",8737__func__, __LINE__,8738lhw, hw, lvif, vif, ac);8739#endif8740lvif->hw_queue_stopped[ac] = false;87418742rcu_read_lock();8743list_for_each_entry_rcu(lsta, &lvif->lsta_list, lsta_list) {8744struct ieee80211_sta *sta;87458746sta = LSTA_TO_STA(lsta);8747for (tid = 0; tid < nitems(sta->txq); tid++) {8748struct lkpi_txq *ltxq;87498750if (sta->txq[tid] == NULL)8751continue;87528753if (sta->txq[tid]->ac != ac)8754continue;87558756ltxq = TXQ_TO_LTXQ(sta->txq[tid]);8757if (!ltxq->stopped)8758continue;87598760ltxq->stopped = false;87618762if (!skb_queue_empty(<xq->skbq))8763lkpi_80211_mo_wake_tx_queue(hw, sta->txq[tid], false);8764}8765}8766rcu_read_unlock();8767}8768}8769}8770LKPI_80211_LHW_LVIF_UNLOCK(lhw);8771}87728773static void8774lkpi_ieee80211_wake_queues_locked(struct ieee80211_hw *hw)8775{8776int i;87778778IMPROVE_TXQ("Is this all/enough here?");8779for (i = 0; i < hw->queues; i++)8780lkpi_ieee80211_wake_queues(hw, i);8781}87828783void8784linuxkpi_ieee80211_wake_queues(struct ieee80211_hw *hw)8785{8786struct lkpi_hw *lhw;8787unsigned long flags;87888789lhw = HW_TO_LHW(hw);87908791spin_lock_irqsave(&lhw->txq_lock, flags);8792lkpi_ieee80211_wake_queues_locked(hw);8793spin_unlock_irqrestore(&lhw->txq_lock, flags);8794}87958796void8797linuxkpi_ieee80211_wake_queue(struct ieee80211_hw *hw, int qnum)8798{8799struct lkpi_hw *lhw;8800unsigned long flags;88018802KASSERT(qnum < hw->queues, ("%s: qnum %d >= hw->queues %d, hw %p\n",8803__func__, qnum, hw->queues, hw));88048805lhw = HW_TO_LHW(hw);88068807spin_lock_irqsave(&lhw->txq_lock, flags);8808lkpi_ieee80211_wake_queues(hw, qnum);8809spin_unlock_irqrestore(&lhw->txq_lock, flags);8810}88118812/* -------------------------------------------------------------------------- */88138814/* This is just hardware queues. */8815/*8816* Being called from the driver thus use _bh() locking.8817*/8818void8819linuxkpi_ieee80211_txq_schedule_start(struct ieee80211_hw *hw, uint8_t ac)8820{8821struct lkpi_hw *lhw;88228823lhw = HW_TO_LHW(hw);88248825if (ac >= IEEE80211_NUM_ACS) {8826ic_printf(lhw->ic, "%s: ac %u out of bounds.\n", __func__, ac);8827return;8828}88298830spin_lock_bh(&lhw->txq_scheduled_lock[ac]);8831IMPROVE("check AIRTIME_FAIRNESS");8832if (++lhw->txq_generation[ac] == 0)8833lhw->txq_generation[ac]++;8834spin_unlock_bh(&lhw->txq_scheduled_lock[ac]);8835}88368837struct ieee80211_txq *8838linuxkpi_ieee80211_next_txq(struct ieee80211_hw *hw, uint8_t ac)8839{8840struct lkpi_hw *lhw;8841struct ieee80211_txq *txq;8842struct lkpi_txq *ltxq;88438844lhw = HW_TO_LHW(hw);8845txq = NULL;88468847if (ac >= IEEE80211_NUM_ACS) {8848ic_printf(lhw->ic, "%s: ac %u out of bounds.\n", __func__, ac);8849return (NULL);8850}88518852spin_lock_bh(&lhw->txq_scheduled_lock[ac]);88538854/* Check that we are scheduled. */8855if (lhw->txq_generation[ac] == 0)8856goto out;88578858ltxq = TAILQ_FIRST(&lhw->txq_scheduled[ac]);8859if (ltxq == NULL)8860goto out;8861if (ltxq->txq_generation == lhw->txq_generation[ac])8862goto out;88638864IMPROVE("check AIRTIME_FAIRNESS");88658866TAILQ_REMOVE(&lhw->txq_scheduled[ac], ltxq, txq_entry);8867ltxq->txq_generation = lhw->txq_generation[ac];8868txq = <xq->txq;8869TAILQ_ELEM_INIT(ltxq, txq_entry);88708871out:8872spin_unlock_bh(&lhw->txq_scheduled_lock[ac]);88738874return (txq);8875}88768877void linuxkpi_ieee80211_schedule_txq(struct ieee80211_hw *hw,8878struct ieee80211_txq *txq, bool withoutpkts)8879{8880struct lkpi_hw *lhw;8881struct lkpi_txq *ltxq;8882bool ltxq_empty;88838884ltxq = TXQ_TO_LTXQ(txq);88858886/* Only schedule if work to do or asked to anyway. */8887LKPI_80211_LTXQ_LOCK(ltxq);8888ltxq_empty = skb_queue_empty(<xq->skbq);8889LKPI_80211_LTXQ_UNLOCK(ltxq);8890if (!withoutpkts && ltxq_empty)8891goto out;88928893lhw = HW_TO_LHW(hw);8894spin_lock_bh(&lhw->txq_scheduled_lock[txq->ac]);8895/*8896* Make sure we do not double-schedule. We do this by checking tqe_prev,8897* the previous entry in our tailq. tqe_prev is always valid if this entry8898* is queued, tqe_next may be NULL if this is the only element in the list.8899*/8900if (ltxq->txq_entry.tqe_prev != NULL)8901goto unlock;89028903TAILQ_INSERT_TAIL(&lhw->txq_scheduled[txq->ac], ltxq, txq_entry);8904unlock:8905spin_unlock_bh(&lhw->txq_scheduled_lock[txq->ac]);89068907out:8908return;8909}89108911/* -------------------------------------------------------------------------- */89128913void8914linuxkpi_ieee80211_handle_wake_tx_queue(struct ieee80211_hw *hw,8915struct ieee80211_txq *txq)8916{8917struct lkpi_hw *lhw;89188919lhw = HW_TO_LHW(hw);89208921LKPI_80211_LHW_TXQ_LOCK(lhw);8922ieee80211_txq_schedule_start(hw, txq->ac);8923do {8924struct lkpi_txq *ltxq;8925struct ieee80211_txq *ntxq;8926struct ieee80211_tx_control control;8927struct sk_buff *skb;89288929ntxq = ieee80211_next_txq(hw, txq->ac);8930if (ntxq == NULL)8931break;8932ltxq = TXQ_TO_LTXQ(ntxq);89338934memset(&control, 0, sizeof(control));8935control.sta = ntxq->sta;8936do {8937skb = linuxkpi_ieee80211_tx_dequeue(hw, ntxq);8938if (skb == NULL)8939break;8940ltxq->frms_tx++;8941lkpi_80211_mo_tx(hw, &control, skb);8942} while(1);89438944ieee80211_return_txq(hw, ntxq, false);8945} while (1);8946ieee80211_txq_schedule_end(hw, txq->ac);8947LKPI_80211_LHW_TXQ_UNLOCK(lhw);8948}89498950/* -------------------------------------------------------------------------- */89518952struct lkpi_cfg80211_bss {8953u_int refcnt;8954struct cfg80211_bss bss;8955};89568957struct lkpi_cfg80211_get_bss_iter_lookup {8958struct wiphy *wiphy;8959struct linuxkpi_ieee80211_channel *chan;8960const uint8_t *bssid;8961const uint8_t *ssid;8962size_t ssid_len;8963enum ieee80211_bss_type bss_type;8964enum ieee80211_privacy privacy;89658966/*8967* Something to store a copy of the result as the net80211 scan cache8968* is not refoucnted so a scan entry might go away any time.8969*/8970bool match;8971struct cfg80211_bss *bss;8972};89738974static void8975lkpi_cfg80211_get_bss_iterf(void *arg, const struct ieee80211_scan_entry *se)8976{8977struct lkpi_cfg80211_get_bss_iter_lookup *lookup;8978size_t ielen;89798980lookup = arg;89818982/* Do not try to find another match. */8983if (lookup->match)8984return;89858986/* Nothing to store result. */8987if (lookup->bss == NULL)8988return;89898990if (lookup->privacy != IEEE80211_PRIVACY_ANY) {8991/* if (se->se_capinfo & IEEE80211_CAPINFO_PRIVACY) */8992/* We have no idea what to compare to as the drivers only request ANY */8993return;8994}89958996if (lookup->bss_type != IEEE80211_BSS_TYPE_ANY) {8997/* if (se->se_capinfo & (IEEE80211_CAPINFO_IBSS|IEEE80211_CAPINFO_ESS)) */8998/* We have no idea what to compare to as the drivers only request ANY */8999return;9000}90019002if (lookup->chan != NULL) {9003struct linuxkpi_ieee80211_channel *chan;90049005chan = linuxkpi_ieee80211_get_channel(lookup->wiphy,9006se->se_chan->ic_freq);9007if (chan == NULL || chan != lookup->chan)9008return;9009}90109011if (lookup->bssid && !IEEE80211_ADDR_EQ(lookup->bssid, se->se_bssid))9012return;90139014if (lookup->ssid) {9015if (lookup->ssid_len != se->se_ssid[1] ||9016se->se_ssid[1] == 0)9017return;9018if (memcmp(lookup->ssid, se->se_ssid+2, lookup->ssid_len) != 0)9019return;9020}90219022ielen = se->se_ies.len;90239024lookup->bss->ies = malloc(sizeof(*lookup->bss->ies) + ielen,9025M_LKPI80211, M_NOWAIT | M_ZERO);9026if (lookup->bss->ies == NULL)9027return;90289029lookup->bss->ies->data = (uint8_t *)lookup->bss->ies + sizeof(*lookup->bss->ies);9030lookup->bss->ies->len = ielen;9031if (ielen)9032memcpy(lookup->bss->ies->data, se->se_ies.data, ielen);90339034lookup->match = true;9035}90369037struct cfg80211_bss *9038linuxkpi_cfg80211_get_bss(struct wiphy *wiphy, struct linuxkpi_ieee80211_channel *chan,9039const uint8_t *bssid, const uint8_t *ssid, size_t ssid_len,9040enum ieee80211_bss_type bss_type, enum ieee80211_privacy privacy)9041{9042struct lkpi_cfg80211_bss *lbss;9043struct lkpi_cfg80211_get_bss_iter_lookup lookup;9044struct lkpi_hw *lhw;9045struct ieee80211vap *vap;90469047lhw = wiphy_priv(wiphy);90489049/* Let's hope we can alloc. */9050lbss = malloc(sizeof(*lbss), M_LKPI80211, M_NOWAIT | M_ZERO);9051if (lbss == NULL) {9052ic_printf(lhw->ic, "%s: alloc failed.\n", __func__);9053return (NULL);9054}90559056lookup.wiphy = wiphy;9057lookup.chan = chan;9058lookup.bssid = bssid;9059lookup.ssid = ssid;9060lookup.ssid_len = ssid_len;9061lookup.bss_type = bss_type;9062lookup.privacy = privacy;9063lookup.match = false;9064lookup.bss = &lbss->bss;90659066IMPROVE("Iterate over all VAPs comparing perm_addr and addresses?");9067vap = TAILQ_FIRST(&lhw->ic->ic_vaps);9068ieee80211_scan_iterate(vap, lkpi_cfg80211_get_bss_iterf, &lookup);9069if (!lookup.match) {9070free(lbss, M_LKPI80211);9071return (NULL);9072}90739074refcount_init(&lbss->refcnt, 1);9075return (&lbss->bss);9076}90779078void9079linuxkpi_cfg80211_put_bss(struct wiphy *wiphy, struct cfg80211_bss *bss)9080{9081struct lkpi_cfg80211_bss *lbss;90829083lbss = container_of(bss, struct lkpi_cfg80211_bss, bss);90849085/* Free everything again on refcount ... */9086if (refcount_release(&lbss->refcnt)) {9087free(lbss->bss.ies, M_LKPI80211);9088free(lbss, M_LKPI80211);9089}9090}90919092void9093linuxkpi_cfg80211_bss_flush(struct wiphy *wiphy)9094{9095struct lkpi_hw *lhw;9096struct ieee80211com *ic;9097struct ieee80211vap *vap;90989099lhw = wiphy_priv(wiphy);9100ic = lhw->ic;91019102/*9103* If we haven't called ieee80211_ifattach() yet9104* or there is no VAP, there are no scans to flush.9105*/9106if (ic == NULL ||9107(lhw->sc_flags & LKPI_MAC80211_DRV_STARTED) == 0)9108return;91099110/* Should only happen on the current one? Not seen it late enough. */9111IEEE80211_LOCK(ic);9112TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)9113ieee80211_scan_flush(vap);9114IEEE80211_UNLOCK(ic);9115}91169117/* -------------------------------------------------------------------------- */91189119/*9120* hw->conf get initialized/set in various places for us:9121* - linuxkpi_ieee80211_alloc_hw(): flags9122* - linuxkpi_ieee80211_ifattach(): chandef9123* - lkpi_ic_vap_create(): listen_interval9124* - lkpi_ic_set_channel(): chandef, flags9125*/91269127int lkpi_80211_update_chandef(struct ieee80211_hw *hw,9128struct ieee80211_chanctx_conf *new)9129{9130struct cfg80211_chan_def *cd;9131uint32_t changed;9132int error;91339134changed = 0;9135if (new == NULL || new->def.chan == NULL)9136cd = NULL;9137else9138cd = &new->def;91399140if (cd && cd->chan != hw->conf.chandef.chan) {9141/* Copy; the chan pointer is fine and will stay valid. */9142hw->conf.chandef = *cd;9143changed |= IEEE80211_CONF_CHANGE_CHANNEL;9144}9145IMPROVE("IEEE80211_CONF_CHANGE_PS, IEEE80211_CONF_CHANGE_POWER");91469147if (changed == 0)9148return (0);91499150error = lkpi_80211_mo_config(hw, changed);9151return (error);9152}91539154/* -------------------------------------------------------------------------- */91559156MODULE_VERSION(linuxkpi_wlan, 1);9157MODULE_DEPEND(linuxkpi_wlan, linuxkpi, 1, 1, 1);9158MODULE_DEPEND(linuxkpi_wlan, wlan, 1, 1, 1);915991609161