1*6b4cac81SBjoern A. Zeeb /*- 2*6b4cac81SBjoern A. Zeeb * Copyright (c) 2020-2021 The FreeBSD Foundation 3*6b4cac81SBjoern A. Zeeb * Copyright (c) 2020-2021 Bjoern A. Zeeb 4*6b4cac81SBjoern A. Zeeb * 5*6b4cac81SBjoern A. Zeeb * This software was developed by Björn Zeeb under sponsorship from 6*6b4cac81SBjoern A. Zeeb * the FreeBSD Foundation. 7*6b4cac81SBjoern A. Zeeb * 8*6b4cac81SBjoern A. Zeeb * Redistribution and use in source and binary forms, with or without 9*6b4cac81SBjoern A. Zeeb * modification, are permitted provided that the following conditions 10*6b4cac81SBjoern A. Zeeb * are met: 11*6b4cac81SBjoern A. Zeeb * 1. Redistributions of source code must retain the above copyright 12*6b4cac81SBjoern A. Zeeb * notice, this list of conditions and the following disclaimer. 13*6b4cac81SBjoern A. Zeeb * 2. Redistributions in binary form must reproduce the above copyright 14*6b4cac81SBjoern A. Zeeb * notice, this list of conditions and the following disclaimer in the 15*6b4cac81SBjoern A. Zeeb * documentation and/or other materials provided with the distribution. 16*6b4cac81SBjoern A. Zeeb * 17*6b4cac81SBjoern A. Zeeb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18*6b4cac81SBjoern A. Zeeb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19*6b4cac81SBjoern A. Zeeb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20*6b4cac81SBjoern A. Zeeb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21*6b4cac81SBjoern A. Zeeb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22*6b4cac81SBjoern A. Zeeb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23*6b4cac81SBjoern A. Zeeb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24*6b4cac81SBjoern A. Zeeb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25*6b4cac81SBjoern A. Zeeb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26*6b4cac81SBjoern A. Zeeb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27*6b4cac81SBjoern A. Zeeb * SUCH DAMAGE. 28*6b4cac81SBjoern A. Zeeb */ 29*6b4cac81SBjoern A. Zeeb 30*6b4cac81SBjoern A. Zeeb /* 31*6b4cac81SBjoern A. Zeeb * Public functions are called linuxkpi_*(). 32*6b4cac81SBjoern A. Zeeb * Internal (static) functions are called lkpi_*(). 33*6b4cac81SBjoern A. Zeeb * 34*6b4cac81SBjoern A. Zeeb * The internal structures holding metadata over public structures are also 35*6b4cac81SBjoern A. Zeeb * called lkpi_xxx (usually with a member at the end called xxx). 36*6b4cac81SBjoern A. Zeeb * Note: we do not replicate the structure names but the general variable names 37*6b4cac81SBjoern A. Zeeb * for these (e.g., struct hw -> struct lkpi_hw, struct sta -> struct lkpi_sta). 38*6b4cac81SBjoern A. Zeeb * There are macros to access one from the other. 39*6b4cac81SBjoern A. Zeeb * We call the internal versions lxxx (e.g., hw -> lhw, sta -> lsta). 40*6b4cac81SBjoern A. Zeeb */ 41*6b4cac81SBjoern A. Zeeb 42*6b4cac81SBjoern A. Zeeb #include <sys/cdefs.h> 43*6b4cac81SBjoern A. Zeeb __FBSDID("$FreeBSD$"); 44*6b4cac81SBjoern A. Zeeb 45*6b4cac81SBjoern A. Zeeb #include <sys/param.h> 46*6b4cac81SBjoern A. Zeeb #include <sys/types.h> 47*6b4cac81SBjoern A. Zeeb #include <sys/kernel.h> 48*6b4cac81SBjoern A. Zeeb #include <sys/errno.h> 49*6b4cac81SBjoern A. Zeeb #include <sys/malloc.h> 50*6b4cac81SBjoern A. Zeeb #include <sys/module.h> 51*6b4cac81SBjoern A. Zeeb #include <sys/mutex.h> 52*6b4cac81SBjoern A. Zeeb #include <sys/socket.h> 53*6b4cac81SBjoern A. Zeeb #include <sys/sysctl.h> 54*6b4cac81SBjoern A. Zeeb #include <sys/queue.h> 55*6b4cac81SBjoern A. Zeeb #include <sys/taskqueue.h> 56*6b4cac81SBjoern A. Zeeb 57*6b4cac81SBjoern A. Zeeb #include <net/if.h> 58*6b4cac81SBjoern A. Zeeb #include <net/if_var.h> 59*6b4cac81SBjoern A. Zeeb #include <net/if_media.h> 60*6b4cac81SBjoern A. Zeeb #include <net/ethernet.h> 61*6b4cac81SBjoern A. Zeeb 62*6b4cac81SBjoern A. Zeeb #include <net80211/ieee80211_var.h> 63*6b4cac81SBjoern A. Zeeb #include <net80211/ieee80211_proto.h> 64*6b4cac81SBjoern A. Zeeb #include <net80211/ieee80211_ratectl.h> 65*6b4cac81SBjoern A. Zeeb #include <net80211/ieee80211_radiotap.h> 66*6b4cac81SBjoern A. Zeeb 67*6b4cac81SBjoern A. Zeeb #define LINUXKPI_NET80211 68*6b4cac81SBjoern A. Zeeb #include <net/mac80211.h> 69*6b4cac81SBjoern A. Zeeb 70*6b4cac81SBjoern A. Zeeb #include <linux/workqueue.h> 71*6b4cac81SBjoern A. Zeeb #include "linux_80211.h" 72*6b4cac81SBjoern A. Zeeb 73*6b4cac81SBjoern A. Zeeb static MALLOC_DEFINE(M_LKPI80211, "lkpi80211", "Linux KPI 80211 compat"); 74*6b4cac81SBjoern A. Zeeb 75*6b4cac81SBjoern A. Zeeb /* -------------------------------------------------------------------------- */ 76*6b4cac81SBjoern A. Zeeb /* These are unrelated to 802.11 sysctl bug debugging during 802.11 work so * 77*6b4cac81SBjoern A. Zeeb * keep them here rather than in a more general file. */ 78*6b4cac81SBjoern A. Zeeb 79*6b4cac81SBjoern A. Zeeb int debug_skb; 80*6b4cac81SBjoern A. Zeeb SYSCTL_INT(_compat_linuxkpi, OID_AUTO, debug_skb, CTLFLAG_RWTUN, 81*6b4cac81SBjoern A. Zeeb &debug_skb, 0, "SKB debug level"); 82*6b4cac81SBjoern A. Zeeb 83*6b4cac81SBjoern A. Zeeb /* -------------------------------------------------------------------------- */ 84*6b4cac81SBjoern A. Zeeb 85*6b4cac81SBjoern A. Zeeb int debug_80211; 86*6b4cac81SBjoern A. Zeeb SYSCTL_INT(_compat_linuxkpi, OID_AUTO, debug_80211, CTLFLAG_RWTUN, 87*6b4cac81SBjoern A. Zeeb &debug_80211, 0, "80211 debug Level"); 88*6b4cac81SBjoern A. Zeeb 89*6b4cac81SBjoern A. Zeeb #define LINUXKPI_DEBUG_80211 90*6b4cac81SBjoern A. Zeeb #ifdef LINUXKPI_DEBUG_80211 91*6b4cac81SBjoern A. Zeeb #ifndef D80211_TODO 92*6b4cac81SBjoern A. Zeeb #define D80211_TODO 0x1 93*6b4cac81SBjoern A. Zeeb #endif 94*6b4cac81SBjoern A. Zeeb #ifndef D80211_IMPROVE 95*6b4cac81SBjoern A. Zeeb #define D80211_IMPROVE 0x2 96*6b4cac81SBjoern A. Zeeb #endif 97*6b4cac81SBjoern A. Zeeb #define D80211_TRACE 0x10 98*6b4cac81SBjoern A. Zeeb #define D80211_TRACEOK 0x20 99*6b4cac81SBjoern A. Zeeb #define D80211_TRACE_TX 0x100 100*6b4cac81SBjoern A. Zeeb #define D80211_TRACE_TX_DUMP 0x200 101*6b4cac81SBjoern A. Zeeb #define D80211_TRACE_RX 0x1000 102*6b4cac81SBjoern A. Zeeb #define D80211_TRACE_RX_DUMP 0x2000 103*6b4cac81SBjoern A. Zeeb #define D80211_TRACE_RX_BEACONS 0x4000 104*6b4cac81SBjoern A. Zeeb #define D80211_TRACEX (D80211_TRACE_TX|D80211_TRACE_RX) 105*6b4cac81SBjoern A. Zeeb #define D80211_TRACEX_DUMP (D80211_TRACE_TX_DUMP|D80211_TRACE_RX_DUMP) 106*6b4cac81SBjoern A. Zeeb #define UNIMPLEMENTED if (debug_80211 & D80211_TODO) \ 107*6b4cac81SBjoern A. Zeeb printf("XXX-TODO %s:%d: UNIMPLEMENTED\n", __func__, __LINE__) 108*6b4cac81SBjoern A. Zeeb #define TRACEOK() if (debug_80211 & D80211_TRACEOK) \ 109*6b4cac81SBjoern A. Zeeb printf("XXX-TODO %s:%d: TRACEPOINT\n", __func__, __LINE__) 110*6b4cac81SBjoern A. Zeeb #else 111*6b4cac81SBjoern A. Zeeb #define UNIMPLEMENTED do { } while (0) 112*6b4cac81SBjoern A. Zeeb #define TRACEOK() do { } while (0) 113*6b4cac81SBjoern A. Zeeb #endif 114*6b4cac81SBjoern A. Zeeb 115*6b4cac81SBjoern A. Zeeb /* #define PREP_TX_INFO_DURATION (IEEE80211_TRANS_WAIT * 1000) */ 116*6b4cac81SBjoern A. Zeeb #ifndef PREP_TX_INFO_DURATION 117*6b4cac81SBjoern A. Zeeb #define PREP_TX_INFO_DURATION 0 /* Let the driver do its thing. */ 118*6b4cac81SBjoern A. Zeeb #endif 119*6b4cac81SBjoern A. Zeeb 120*6b4cac81SBjoern A. Zeeb /* This is DSAP | SSAP | CTRL | ProtoID/OrgCode{3}. */ 121*6b4cac81SBjoern A. Zeeb const uint8_t rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; 122*6b4cac81SBjoern A. Zeeb 123*6b4cac81SBjoern A. Zeeb const struct cfg80211_ops linuxkpi_mac80211cfgops = { 124*6b4cac81SBjoern A. Zeeb /* 125*6b4cac81SBjoern A. Zeeb * XXX TODO need a "glue layer" to link cfg80211 ops to 126*6b4cac81SBjoern A. Zeeb * mac80211 and to the driver or net80211. 127*6b4cac81SBjoern A. Zeeb * Can we pass some on 1:1? Need to compare the (*f)(). 128*6b4cac81SBjoern A. Zeeb */ 129*6b4cac81SBjoern A. Zeeb }; 130*6b4cac81SBjoern A. Zeeb 131*6b4cac81SBjoern A. Zeeb static struct lkpi_sta *lkpi_find_lsta_by_ni(struct lkpi_vif *, 132*6b4cac81SBjoern A. Zeeb struct ieee80211_node *); 133*6b4cac81SBjoern A. Zeeb static void lkpi_80211_txq_task(void *, int); 134*6b4cac81SBjoern A. Zeeb static void lkpi_ieee80211_free_skb_mbuf(void *); 135*6b4cac81SBjoern A. Zeeb 136*6b4cac81SBjoern A. Zeeb static enum nl80211_band 137*6b4cac81SBjoern A. Zeeb lkpi_net80211_chan_to_nl80211_band(struct ieee80211_channel *c) 138*6b4cac81SBjoern A. Zeeb { 139*6b4cac81SBjoern A. Zeeb 140*6b4cac81SBjoern A. Zeeb if (IEEE80211_IS_CHAN_2GHZ(c)) 141*6b4cac81SBjoern A. Zeeb return (NL80211_BAND_2GHZ); 142*6b4cac81SBjoern A. Zeeb else if (IEEE80211_IS_CHAN_5GHZ(c)) 143*6b4cac81SBjoern A. Zeeb return (NL80211_BAND_5GHZ); 144*6b4cac81SBjoern A. Zeeb #ifdef __notyet__ 145*6b4cac81SBjoern A. Zeeb else if () 146*6b4cac81SBjoern A. Zeeb return (NL80211_BAND_6GHZ); 147*6b4cac81SBjoern A. Zeeb else if () 148*6b4cac81SBjoern A. Zeeb return (NL80211_BAND_60GHZ); 149*6b4cac81SBjoern A. Zeeb else if (IEEE80211_IS_CHAN_GSM(c)) 150*6b4cac81SBjoern A. Zeeb return (NL80211_BAND_XXX); 151*6b4cac81SBjoern A. Zeeb #endif 152*6b4cac81SBjoern A. Zeeb else 153*6b4cac81SBjoern A. Zeeb panic("%s: unsupported band. c %p flags %#x\n", 154*6b4cac81SBjoern A. Zeeb __func__, c, c->ic_flags); 155*6b4cac81SBjoern A. Zeeb } 156*6b4cac81SBjoern A. Zeeb 157*6b4cac81SBjoern A. Zeeb static uint32_t 158*6b4cac81SBjoern A. Zeeb lkpi_nl80211_band_to_net80211_band(enum nl80211_band band) 159*6b4cac81SBjoern A. Zeeb { 160*6b4cac81SBjoern A. Zeeb 161*6b4cac81SBjoern A. Zeeb /* XXX-BZ this is just silly; net80211 is too convoluted. */ 162*6b4cac81SBjoern A. Zeeb /* IEEE80211_CHAN_A / _G / .. doesn't really work either. */ 163*6b4cac81SBjoern A. Zeeb switch (band) { 164*6b4cac81SBjoern A. Zeeb case NL80211_BAND_2GHZ: 165*6b4cac81SBjoern A. Zeeb return (IEEE80211_CHAN_2GHZ); 166*6b4cac81SBjoern A. Zeeb break; 167*6b4cac81SBjoern A. Zeeb case NL80211_BAND_5GHZ: 168*6b4cac81SBjoern A. Zeeb return (IEEE80211_CHAN_5GHZ); 169*6b4cac81SBjoern A. Zeeb break; 170*6b4cac81SBjoern A. Zeeb case NL80211_BAND_60GHZ: 171*6b4cac81SBjoern A. Zeeb break; 172*6b4cac81SBjoern A. Zeeb case NL80211_BAND_6GHZ: 173*6b4cac81SBjoern A. Zeeb break; 174*6b4cac81SBjoern A. Zeeb default: 175*6b4cac81SBjoern A. Zeeb panic("%s: unsupported band %u\n", __func__, band); 176*6b4cac81SBjoern A. Zeeb break; 177*6b4cac81SBjoern A. Zeeb } 178*6b4cac81SBjoern A. Zeeb 179*6b4cac81SBjoern A. Zeeb IMPROVE(); 180*6b4cac81SBjoern A. Zeeb return (0x00); 181*6b4cac81SBjoern A. Zeeb } 182*6b4cac81SBjoern A. Zeeb 183*6b4cac81SBjoern A. Zeeb static enum ieee80211_ac_numbers 184*6b4cac81SBjoern A. Zeeb lkpi_ac_net_to_l80211(int ac) 185*6b4cac81SBjoern A. Zeeb { 186*6b4cac81SBjoern A. Zeeb 187*6b4cac81SBjoern A. Zeeb switch (ac) { 188*6b4cac81SBjoern A. Zeeb case WME_AC_VO: 189*6b4cac81SBjoern A. Zeeb return (IEEE80211_AC_VO); 190*6b4cac81SBjoern A. Zeeb case WME_AC_VI: 191*6b4cac81SBjoern A. Zeeb return (IEEE80211_AC_VI); 192*6b4cac81SBjoern A. Zeeb case WME_AC_BE: 193*6b4cac81SBjoern A. Zeeb return (IEEE80211_AC_BE); 194*6b4cac81SBjoern A. Zeeb case WME_AC_BK: 195*6b4cac81SBjoern A. Zeeb return (IEEE80211_AC_BK); 196*6b4cac81SBjoern A. Zeeb default: 197*6b4cac81SBjoern A. Zeeb printf("%s: invalid WME_AC_* input: ac = %d\n", __func__, ac); 198*6b4cac81SBjoern A. Zeeb return (IEEE80211_AC_BE); 199*6b4cac81SBjoern A. Zeeb } 200*6b4cac81SBjoern A. Zeeb } 201*6b4cac81SBjoern A. Zeeb 202*6b4cac81SBjoern A. Zeeb static enum nl80211_iftype 203*6b4cac81SBjoern A. Zeeb lkpi_opmode_to_vif_type(enum ieee80211_opmode opmode) 204*6b4cac81SBjoern A. Zeeb { 205*6b4cac81SBjoern A. Zeeb 206*6b4cac81SBjoern A. Zeeb switch (opmode) { 207*6b4cac81SBjoern A. Zeeb case IEEE80211_M_IBSS: 208*6b4cac81SBjoern A. Zeeb return (NL80211_IFTYPE_ADHOC); 209*6b4cac81SBjoern A. Zeeb break; 210*6b4cac81SBjoern A. Zeeb case IEEE80211_M_STA: 211*6b4cac81SBjoern A. Zeeb return (NL80211_IFTYPE_STATION); 212*6b4cac81SBjoern A. Zeeb break; 213*6b4cac81SBjoern A. Zeeb case IEEE80211_M_WDS: 214*6b4cac81SBjoern A. Zeeb return (NL80211_IFTYPE_WDS); 215*6b4cac81SBjoern A. Zeeb break; 216*6b4cac81SBjoern A. Zeeb case IEEE80211_M_HOSTAP: 217*6b4cac81SBjoern A. Zeeb return (NL80211_IFTYPE_AP); 218*6b4cac81SBjoern A. Zeeb break; 219*6b4cac81SBjoern A. Zeeb case IEEE80211_M_MONITOR: 220*6b4cac81SBjoern A. Zeeb return (NL80211_IFTYPE_MONITOR); 221*6b4cac81SBjoern A. Zeeb break; 222*6b4cac81SBjoern A. Zeeb case IEEE80211_M_MBSS: 223*6b4cac81SBjoern A. Zeeb return (NL80211_IFTYPE_MESH_POINT); 224*6b4cac81SBjoern A. Zeeb break; 225*6b4cac81SBjoern A. Zeeb case IEEE80211_M_AHDEMO: 226*6b4cac81SBjoern A. Zeeb /* FALLTHROUGH */ 227*6b4cac81SBjoern A. Zeeb default: 228*6b4cac81SBjoern A. Zeeb printf("ERROR: %s: unsupported opmode %d\n", __func__, opmode); 229*6b4cac81SBjoern A. Zeeb /* FALLTHROUGH */ 230*6b4cac81SBjoern A. Zeeb } 231*6b4cac81SBjoern A. Zeeb return (NL80211_IFTYPE_UNSPECIFIED); 232*6b4cac81SBjoern A. Zeeb } 233*6b4cac81SBjoern A. Zeeb 234*6b4cac81SBjoern A. Zeeb #ifdef __notyet__ 235*6b4cac81SBjoern A. Zeeb static uint32_t 236*6b4cac81SBjoern A. Zeeb lkpi_l80211_to_net80211_cyphers(uint32_t wlan_cipher_suite) 237*6b4cac81SBjoern A. Zeeb { 238*6b4cac81SBjoern A. Zeeb 239*6b4cac81SBjoern A. Zeeb switch (wlan_cipher_suite) { 240*6b4cac81SBjoern A. Zeeb case WLAN_CIPHER_SUITE_WEP40: 241*6b4cac81SBjoern A. Zeeb return (IEEE80211_CRYPTO_WEP); 242*6b4cac81SBjoern A. Zeeb case WLAN_CIPHER_SUITE_TKIP: 243*6b4cac81SBjoern A. Zeeb return (IEEE80211_CRYPTO_TKIP); 244*6b4cac81SBjoern A. Zeeb case WLAN_CIPHER_SUITE_CCMP: 245*6b4cac81SBjoern A. Zeeb return (IEEE80211_CIPHER_AES_CCM); 246*6b4cac81SBjoern A. Zeeb case WLAN_CIPHER_SUITE_WEP104: 247*6b4cac81SBjoern A. Zeeb return (IEEE80211_CRYPTO_WEP); 248*6b4cac81SBjoern A. Zeeb case WLAN_CIPHER_SUITE_AES_CMAC: 249*6b4cac81SBjoern A. Zeeb case WLAN_CIPHER_SUITE_GCMP: 250*6b4cac81SBjoern A. Zeeb case WLAN_CIPHER_SUITE_GCMP_256: 251*6b4cac81SBjoern A. Zeeb case WLAN_CIPHER_SUITE_CCMP_256: 252*6b4cac81SBjoern A. Zeeb case WLAN_CIPHER_SUITE_BIP_GMAC_128: 253*6b4cac81SBjoern A. Zeeb case WLAN_CIPHER_SUITE_BIP_GMAC_256: 254*6b4cac81SBjoern A. Zeeb case WLAN_CIPHER_SUITE_BIP_CMAC_256: 255*6b4cac81SBjoern A. Zeeb printf("%s: unsupported WLAN Cipher Suite %#08x | %u\n", __func__, 256*6b4cac81SBjoern A. Zeeb wlan_cipher_suite >> 8, wlan_cipher_suite & 0xff); 257*6b4cac81SBjoern A. Zeeb break; 258*6b4cac81SBjoern A. Zeeb default: 259*6b4cac81SBjoern A. Zeeb printf("%s: unknown WLAN Cipher Suite %#08x | %u\n", __func__, 260*6b4cac81SBjoern A. Zeeb wlan_cipher_suite >> 8, wlan_cipher_suite & 0xff); 261*6b4cac81SBjoern A. Zeeb } 262*6b4cac81SBjoern A. Zeeb 263*6b4cac81SBjoern A. Zeeb return (0); 264*6b4cac81SBjoern A. Zeeb } 265*6b4cac81SBjoern A. Zeeb #endif 266*6b4cac81SBjoern A. Zeeb 267*6b4cac81SBjoern A. Zeeb #ifdef TRY_HW_CRYPTO 268*6b4cac81SBjoern A. Zeeb static uint32_t 269*6b4cac81SBjoern A. Zeeb lkpi_net80211_to_l80211_cipher_suite(uint32_t cipher, uint8_t keylen) 270*6b4cac81SBjoern A. Zeeb { 271*6b4cac81SBjoern A. Zeeb 272*6b4cac81SBjoern A. Zeeb switch (cipher) { 273*6b4cac81SBjoern A. Zeeb case IEEE80211_CIPHER_TKIP: 274*6b4cac81SBjoern A. Zeeb return (WLAN_CIPHER_SUITE_TKIP); 275*6b4cac81SBjoern A. Zeeb case IEEE80211_CIPHER_AES_CCM: 276*6b4cac81SBjoern A. Zeeb return (WLAN_CIPHER_SUITE_CCMP); 277*6b4cac81SBjoern A. Zeeb case IEEE80211_CIPHER_WEP: 278*6b4cac81SBjoern A. Zeeb if (keylen < 8) 279*6b4cac81SBjoern A. Zeeb return (WLAN_CIPHER_SUITE_WEP40); 280*6b4cac81SBjoern A. Zeeb else 281*6b4cac81SBjoern A. Zeeb return (WLAN_CIPHER_SUITE_WEP104); 282*6b4cac81SBjoern A. Zeeb break; 283*6b4cac81SBjoern A. Zeeb case IEEE80211_CIPHER_AES_OCB: 284*6b4cac81SBjoern A. Zeeb case IEEE80211_CIPHER_TKIPMIC: 285*6b4cac81SBjoern A. Zeeb case IEEE80211_CIPHER_CKIP: 286*6b4cac81SBjoern A. Zeeb case IEEE80211_CIPHER_NONE: 287*6b4cac81SBjoern A. Zeeb printf("%s: unsupported cipher %#010x\n", __func__, cipher); 288*6b4cac81SBjoern A. Zeeb break; 289*6b4cac81SBjoern A. Zeeb default: 290*6b4cac81SBjoern A. Zeeb printf("%s: unknown cipher %#010x\n", __func__, cipher); 291*6b4cac81SBjoern A. Zeeb }; 292*6b4cac81SBjoern A. Zeeb return (0); 293*6b4cac81SBjoern A. Zeeb } 294*6b4cac81SBjoern A. Zeeb #endif 295*6b4cac81SBjoern A. Zeeb 296*6b4cac81SBjoern A. Zeeb #ifdef __notyet__ 297*6b4cac81SBjoern A. Zeeb static enum ieee80211_sta_state 298*6b4cac81SBjoern A. Zeeb lkpi_net80211_state_to_sta_state(enum ieee80211_state state) 299*6b4cac81SBjoern A. Zeeb { 300*6b4cac81SBjoern A. Zeeb 301*6b4cac81SBjoern A. Zeeb /* 302*6b4cac81SBjoern A. Zeeb * XXX-BZ The net80211 states are "try to ..", the lkpi8011 states are 303*6b4cac81SBjoern A. Zeeb * "done". Also ASSOC/AUTHORIZED are both "RUN" then? 304*6b4cac81SBjoern A. Zeeb */ 305*6b4cac81SBjoern A. Zeeb switch (state) { 306*6b4cac81SBjoern A. Zeeb case IEEE80211_S_INIT: 307*6b4cac81SBjoern A. Zeeb return (IEEE80211_STA_NOTEXIST); 308*6b4cac81SBjoern A. Zeeb case IEEE80211_S_SCAN: 309*6b4cac81SBjoern A. Zeeb return (IEEE80211_STA_NONE); 310*6b4cac81SBjoern A. Zeeb case IEEE80211_S_AUTH: 311*6b4cac81SBjoern A. Zeeb return (IEEE80211_STA_AUTH); 312*6b4cac81SBjoern A. Zeeb case IEEE80211_S_ASSOC: 313*6b4cac81SBjoern A. Zeeb return (IEEE80211_STA_ASSOC); 314*6b4cac81SBjoern A. Zeeb case IEEE80211_S_RUN: 315*6b4cac81SBjoern A. Zeeb return (IEEE80211_STA_AUTHORIZED); 316*6b4cac81SBjoern A. Zeeb case IEEE80211_S_CAC: 317*6b4cac81SBjoern A. Zeeb case IEEE80211_S_CSA: 318*6b4cac81SBjoern A. Zeeb case IEEE80211_S_SLEEP: 319*6b4cac81SBjoern A. Zeeb default: 320*6b4cac81SBjoern A. Zeeb UNIMPLEMENTED; 321*6b4cac81SBjoern A. Zeeb }; 322*6b4cac81SBjoern A. Zeeb 323*6b4cac81SBjoern A. Zeeb return (IEEE80211_STA_NOTEXIST); 324*6b4cac81SBjoern A. Zeeb } 325*6b4cac81SBjoern A. Zeeb #endif 326*6b4cac81SBjoern A. Zeeb 327*6b4cac81SBjoern A. Zeeb static struct linuxkpi_ieee80211_channel * 328*6b4cac81SBjoern A. Zeeb lkpi_find_lkpi80211_chan(struct lkpi_hw *lhw, 329*6b4cac81SBjoern A. Zeeb struct ieee80211_channel *c) 330*6b4cac81SBjoern A. Zeeb { 331*6b4cac81SBjoern A. Zeeb struct ieee80211_hw *hw; 332*6b4cac81SBjoern A. Zeeb struct linuxkpi_ieee80211_channel *channels; 333*6b4cac81SBjoern A. Zeeb enum nl80211_band band; 334*6b4cac81SBjoern A. Zeeb int i, nchans; 335*6b4cac81SBjoern A. Zeeb 336*6b4cac81SBjoern A. Zeeb hw = LHW_TO_HW(lhw); 337*6b4cac81SBjoern A. Zeeb band = lkpi_net80211_chan_to_nl80211_band(c); 338*6b4cac81SBjoern A. Zeeb if (hw->wiphy->bands[band] == NULL) 339*6b4cac81SBjoern A. Zeeb return (NULL); 340*6b4cac81SBjoern A. Zeeb 341*6b4cac81SBjoern A. Zeeb nchans = hw->wiphy->bands[band]->n_channels; 342*6b4cac81SBjoern A. Zeeb if (nchans <= 0) 343*6b4cac81SBjoern A. Zeeb return (NULL); 344*6b4cac81SBjoern A. Zeeb 345*6b4cac81SBjoern A. Zeeb channels = hw->wiphy->bands[band]->channels; 346*6b4cac81SBjoern A. Zeeb for (i = 0; i < nchans; i++) { 347*6b4cac81SBjoern A. Zeeb if (channels[i].hw_value == c->ic_ieee) 348*6b4cac81SBjoern A. Zeeb return (&channels[i]); 349*6b4cac81SBjoern A. Zeeb } 350*6b4cac81SBjoern A. Zeeb 351*6b4cac81SBjoern A. Zeeb return (NULL); 352*6b4cac81SBjoern A. Zeeb } 353*6b4cac81SBjoern A. Zeeb 354*6b4cac81SBjoern A. Zeeb static struct linuxkpi_ieee80211_channel * 355*6b4cac81SBjoern A. Zeeb lkpi_get_lkpi80211_chan(struct ieee80211com *ic, struct ieee80211_node *ni) 356*6b4cac81SBjoern A. Zeeb { 357*6b4cac81SBjoern A. Zeeb struct linuxkpi_ieee80211_channel *chan; 358*6b4cac81SBjoern A. Zeeb struct ieee80211_channel *c; 359*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 360*6b4cac81SBjoern A. Zeeb 361*6b4cac81SBjoern A. Zeeb chan = NULL; 362*6b4cac81SBjoern A. Zeeb if (ni != NULL && ni->ni_chan != IEEE80211_CHAN_ANYC) 363*6b4cac81SBjoern A. Zeeb c = ni->ni_chan; 364*6b4cac81SBjoern A. Zeeb else if (ic->ic_bsschan != IEEE80211_CHAN_ANYC) 365*6b4cac81SBjoern A. Zeeb c = ic->ic_bsschan; 366*6b4cac81SBjoern A. Zeeb else if (ic->ic_curchan != IEEE80211_CHAN_ANYC) 367*6b4cac81SBjoern A. Zeeb c = ic->ic_curchan; 368*6b4cac81SBjoern A. Zeeb else 369*6b4cac81SBjoern A. Zeeb c = NULL; 370*6b4cac81SBjoern A. Zeeb 371*6b4cac81SBjoern A. Zeeb if (c != NULL && c != IEEE80211_CHAN_ANYC) { 372*6b4cac81SBjoern A. Zeeb lhw = ic->ic_softc; 373*6b4cac81SBjoern A. Zeeb chan = lkpi_find_lkpi80211_chan(lhw, c); 374*6b4cac81SBjoern A. Zeeb } 375*6b4cac81SBjoern A. Zeeb 376*6b4cac81SBjoern A. Zeeb return (chan); 377*6b4cac81SBjoern A. Zeeb } 378*6b4cac81SBjoern A. Zeeb 379*6b4cac81SBjoern A. Zeeb #ifdef TRY_HW_CRYPTO 380*6b4cac81SBjoern A. Zeeb static int 381*6b4cac81SBjoern A. Zeeb _lkpi_iv_key_set_delete(struct ieee80211vap *vap, const struct ieee80211_key *k, 382*6b4cac81SBjoern A. Zeeb enum set_key_cmd cmd) 383*6b4cac81SBjoern A. Zeeb { 384*6b4cac81SBjoern A. Zeeb struct ieee80211com *ic; 385*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 386*6b4cac81SBjoern A. Zeeb struct ieee80211_hw *hw; 387*6b4cac81SBjoern A. Zeeb struct lkpi_vif *lvif; 388*6b4cac81SBjoern A. Zeeb struct ieee80211_vif *vif; 389*6b4cac81SBjoern A. Zeeb struct ieee80211_sta *sta; 390*6b4cac81SBjoern A. Zeeb struct ieee80211_node *ni; 391*6b4cac81SBjoern A. Zeeb struct ieee80211_key_conf *kc; 392*6b4cac81SBjoern A. Zeeb int error; 393*6b4cac81SBjoern A. Zeeb 394*6b4cac81SBjoern A. Zeeb /* XXX TODO Check (k->wk_flags & IEEE80211_KEY_SWENCRYPT) and don't upload to driver/hw? */ 395*6b4cac81SBjoern A. Zeeb 396*6b4cac81SBjoern A. Zeeb ic = vap->iv_ic; 397*6b4cac81SBjoern A. Zeeb lhw = ic->ic_softc; 398*6b4cac81SBjoern A. Zeeb hw = LHW_TO_HW(lhw); 399*6b4cac81SBjoern A. Zeeb lvif = VAP_TO_LVIF(vap); 400*6b4cac81SBjoern A. Zeeb vif = LVIF_TO_VIF(lvif); 401*6b4cac81SBjoern A. Zeeb 402*6b4cac81SBjoern A. Zeeb memset(&kc, 0, sizeof(kc)); 403*6b4cac81SBjoern A. Zeeb kc = malloc(sizeof(*kc) + k->wk_keylen, M_LKPI80211, M_WAITOK | M_ZERO); 404*6b4cac81SBjoern A. Zeeb kc->cipher = lkpi_net80211_to_l80211_cipher_suite( 405*6b4cac81SBjoern A. Zeeb k->wk_cipher->ic_cipher, k->wk_keylen); 406*6b4cac81SBjoern A. Zeeb kc->keyidx = k->wk_keyix; 407*6b4cac81SBjoern A. Zeeb #if 0 408*6b4cac81SBjoern A. Zeeb kc->hw_key_idx = /* set by hw and needs to be passed for TX */; 409*6b4cac81SBjoern A. Zeeb #endif 410*6b4cac81SBjoern A. Zeeb atomic64_set(&kc->tx_pn, k->wk_keytsc); 411*6b4cac81SBjoern A. Zeeb kc->keylen = k->wk_keylen; 412*6b4cac81SBjoern A. Zeeb memcpy(kc->key, k->wk_key, k->wk_keylen); 413*6b4cac81SBjoern A. Zeeb 414*6b4cac81SBjoern A. Zeeb switch (kc->cipher) { 415*6b4cac81SBjoern A. Zeeb case WLAN_CIPHER_SUITE_CCMP: 416*6b4cac81SBjoern A. Zeeb kc->iv_len = k->wk_cipher->ic_header; 417*6b4cac81SBjoern A. Zeeb kc->icv_len = k->wk_cipher->ic_trailer; 418*6b4cac81SBjoern A. Zeeb break; 419*6b4cac81SBjoern A. Zeeb case WLAN_CIPHER_SUITE_TKIP: 420*6b4cac81SBjoern A. Zeeb default: 421*6b4cac81SBjoern A. Zeeb IMPROVE(); 422*6b4cac81SBjoern A. Zeeb return (0); 423*6b4cac81SBjoern A. Zeeb }; 424*6b4cac81SBjoern A. Zeeb 425*6b4cac81SBjoern A. Zeeb ni = vap->iv_bss; 426*6b4cac81SBjoern A. Zeeb sta = ieee80211_find_sta(vif, ni->ni_bssid); 427*6b4cac81SBjoern A. Zeeb if (sta != NULL) { 428*6b4cac81SBjoern A. Zeeb struct lkpi_sta *lsta; 429*6b4cac81SBjoern A. Zeeb 430*6b4cac81SBjoern A. Zeeb lsta = STA_TO_LSTA(sta); 431*6b4cac81SBjoern A. Zeeb lsta->kc = kc; 432*6b4cac81SBjoern A. Zeeb } 433*6b4cac81SBjoern A. Zeeb 434*6b4cac81SBjoern A. Zeeb error = lkpi_80211_mo_set_key(hw, cmd, vif, sta, kc); 435*6b4cac81SBjoern A. Zeeb if (error != 0) { 436*6b4cac81SBjoern A. Zeeb /* XXX-BZ leaking kc currently */ 437*6b4cac81SBjoern A. Zeeb ic_printf(ic, "%s: set_key failed: %d\n", __func__, error); 438*6b4cac81SBjoern A. Zeeb return (0); 439*6b4cac81SBjoern A. Zeeb } else { 440*6b4cac81SBjoern A. Zeeb ic_printf(ic, "%s: set_key succeeded: keyidx %u hw_key_idx %u " 441*6b4cac81SBjoern A. Zeeb "flags %#10x\n", __func__, 442*6b4cac81SBjoern A. Zeeb kc->keyidx, kc->hw_key_idx, kc->flags); 443*6b4cac81SBjoern A. Zeeb return (1); 444*6b4cac81SBjoern A. Zeeb } 445*6b4cac81SBjoern A. Zeeb } 446*6b4cac81SBjoern A. Zeeb 447*6b4cac81SBjoern A. Zeeb static int 448*6b4cac81SBjoern A. Zeeb lkpi_iv_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) 449*6b4cac81SBjoern A. Zeeb { 450*6b4cac81SBjoern A. Zeeb 451*6b4cac81SBjoern A. Zeeb /* XXX-BZ one day we should replace this iterating over VIFs, or node list? */ 452*6b4cac81SBjoern A. Zeeb return (_lkpi_iv_key_set_delete(vap, k, DISABLE_KEY)); 453*6b4cac81SBjoern A. Zeeb } 454*6b4cac81SBjoern A. Zeeb static int 455*6b4cac81SBjoern A. Zeeb lkpi_iv_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k) 456*6b4cac81SBjoern A. Zeeb { 457*6b4cac81SBjoern A. Zeeb 458*6b4cac81SBjoern A. Zeeb return (_lkpi_iv_key_set_delete(vap, k, SET_KEY)); 459*6b4cac81SBjoern A. Zeeb } 460*6b4cac81SBjoern A. Zeeb #endif 461*6b4cac81SBjoern A. Zeeb 462*6b4cac81SBjoern A. Zeeb static u_int 463*6b4cac81SBjoern A. Zeeb lkpi_ic_update_mcast_copy(void *arg, struct sockaddr_dl *sdl, u_int cnt) 464*6b4cac81SBjoern A. Zeeb { 465*6b4cac81SBjoern A. Zeeb struct netdev_hw_addr_list *mc_list; 466*6b4cac81SBjoern A. Zeeb struct netdev_hw_addr *addr; 467*6b4cac81SBjoern A. Zeeb 468*6b4cac81SBjoern A. Zeeb KASSERT(arg != NULL && sdl != NULL, ("%s: arg %p sdl %p cnt %u\n", 469*6b4cac81SBjoern A. Zeeb __func__, arg, sdl, cnt)); 470*6b4cac81SBjoern A. Zeeb 471*6b4cac81SBjoern A. Zeeb mc_list = arg; 472*6b4cac81SBjoern A. Zeeb /* If it is on the list already skip it. */ 473*6b4cac81SBjoern A. Zeeb netdev_hw_addr_list_for_each(addr, mc_list) { 474*6b4cac81SBjoern A. Zeeb if (!memcmp(addr->addr, LLADDR(sdl), sdl->sdl_alen)) 475*6b4cac81SBjoern A. Zeeb return (0); 476*6b4cac81SBjoern A. Zeeb } 477*6b4cac81SBjoern A. Zeeb 478*6b4cac81SBjoern A. Zeeb addr = malloc(sizeof(*addr), M_LKPI80211, M_NOWAIT | M_ZERO); 479*6b4cac81SBjoern A. Zeeb if (addr == NULL) 480*6b4cac81SBjoern A. Zeeb return (0); 481*6b4cac81SBjoern A. Zeeb 482*6b4cac81SBjoern A. Zeeb INIT_LIST_HEAD(&addr->addr_list); 483*6b4cac81SBjoern A. Zeeb memcpy(addr->addr, LLADDR(sdl), sdl->sdl_alen); 484*6b4cac81SBjoern A. Zeeb /* XXX this should be a netdev function? */ 485*6b4cac81SBjoern A. Zeeb list_add(&addr->addr_list, &mc_list->addr_list); 486*6b4cac81SBjoern A. Zeeb mc_list->count++; 487*6b4cac81SBjoern A. Zeeb 488*6b4cac81SBjoern A. Zeeb if (debug_80211 & D80211_TRACE) 489*6b4cac81SBjoern A. Zeeb printf("%s:%d: mc_list count %d: added %6D\n", 490*6b4cac81SBjoern A. Zeeb __func__, __LINE__, mc_list->count, addr->addr, ":"); 491*6b4cac81SBjoern A. Zeeb 492*6b4cac81SBjoern A. Zeeb return (1); 493*6b4cac81SBjoern A. Zeeb } 494*6b4cac81SBjoern A. Zeeb 495*6b4cac81SBjoern A. Zeeb static void 496*6b4cac81SBjoern A. Zeeb lkpi_update_mcast_filter(struct ieee80211com *ic, bool force) 497*6b4cac81SBjoern A. Zeeb { 498*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 499*6b4cac81SBjoern A. Zeeb struct ieee80211_hw *hw; 500*6b4cac81SBjoern A. Zeeb struct netdev_hw_addr_list mc_list; 501*6b4cac81SBjoern A. Zeeb struct list_head *le, *next; 502*6b4cac81SBjoern A. Zeeb struct netdev_hw_addr *addr; 503*6b4cac81SBjoern A. Zeeb struct ieee80211vap *vap; 504*6b4cac81SBjoern A. Zeeb u64 mc; 505*6b4cac81SBjoern A. Zeeb unsigned int changed_flags, total_flags; 506*6b4cac81SBjoern A. Zeeb 507*6b4cac81SBjoern A. Zeeb lhw = ic->ic_softc; 508*6b4cac81SBjoern A. Zeeb 509*6b4cac81SBjoern A. Zeeb if (lhw->ops->prepare_multicast == NULL || 510*6b4cac81SBjoern A. Zeeb lhw->ops->configure_filter == NULL) 511*6b4cac81SBjoern A. Zeeb return; 512*6b4cac81SBjoern A. Zeeb 513*6b4cac81SBjoern A. Zeeb if (!lhw->update_mc && !force) 514*6b4cac81SBjoern A. Zeeb return; 515*6b4cac81SBjoern A. Zeeb 516*6b4cac81SBjoern A. Zeeb changed_flags = total_flags = 0; 517*6b4cac81SBjoern A. Zeeb mc_list.count = 0; 518*6b4cac81SBjoern A. Zeeb INIT_LIST_HEAD(&mc_list.addr_list); 519*6b4cac81SBjoern A. Zeeb if (ic->ic_allmulti == 0) { 520*6b4cac81SBjoern A. Zeeb TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) 521*6b4cac81SBjoern A. Zeeb if_foreach_llmaddr(vap->iv_ifp, 522*6b4cac81SBjoern A. Zeeb lkpi_ic_update_mcast_copy, &mc_list); 523*6b4cac81SBjoern A. Zeeb } else { 524*6b4cac81SBjoern A. Zeeb changed_flags |= FIF_ALLMULTI; 525*6b4cac81SBjoern A. Zeeb } 526*6b4cac81SBjoern A. Zeeb 527*6b4cac81SBjoern A. Zeeb hw = LHW_TO_HW(lhw); 528*6b4cac81SBjoern A. Zeeb mc = lkpi_80211_mo_prepare_multicast(hw, &mc_list); 529*6b4cac81SBjoern A. Zeeb /* 530*6b4cac81SBjoern A. Zeeb * XXX-BZ make sure to get this sorted what is a change, 531*6b4cac81SBjoern A. Zeeb * what gets all set; what was already set? 532*6b4cac81SBjoern A. Zeeb */ 533*6b4cac81SBjoern A. Zeeb total_flags = changed_flags; 534*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_configure_filter(hw, changed_flags, &total_flags, mc); 535*6b4cac81SBjoern A. Zeeb 536*6b4cac81SBjoern A. Zeeb if (debug_80211 & D80211_TRACE) 537*6b4cac81SBjoern A. Zeeb printf("%s: changed_flags %#06x count %d total_flags %#010x\n", 538*6b4cac81SBjoern A. Zeeb __func__, changed_flags, mc_list.count, total_flags); 539*6b4cac81SBjoern A. Zeeb 540*6b4cac81SBjoern A. Zeeb if (mc_list.count != 0) { 541*6b4cac81SBjoern A. Zeeb list_for_each_safe(le, next, &mc_list.addr_list) { 542*6b4cac81SBjoern A. Zeeb addr = list_entry(le, struct netdev_hw_addr, addr_list); 543*6b4cac81SBjoern A. Zeeb free(addr, M_LKPI80211); 544*6b4cac81SBjoern A. Zeeb mc_list.count--; 545*6b4cac81SBjoern A. Zeeb } 546*6b4cac81SBjoern A. Zeeb } 547*6b4cac81SBjoern A. Zeeb KASSERT(mc_list.count == 0, ("%s: mc_list %p count %d != 0\n", 548*6b4cac81SBjoern A. Zeeb __func__, &mc_list, mc_list.count)); 549*6b4cac81SBjoern A. Zeeb } 550*6b4cac81SBjoern A. Zeeb 551*6b4cac81SBjoern A. Zeeb const uint8_t tid_to_mac80211_ac[] = { 552*6b4cac81SBjoern A. Zeeb IEEE80211_AC_BE, 553*6b4cac81SBjoern A. Zeeb IEEE80211_AC_BK, 554*6b4cac81SBjoern A. Zeeb IEEE80211_AC_BK, 555*6b4cac81SBjoern A. Zeeb IEEE80211_AC_BE, 556*6b4cac81SBjoern A. Zeeb IEEE80211_AC_VI, 557*6b4cac81SBjoern A. Zeeb IEEE80211_AC_VI, 558*6b4cac81SBjoern A. Zeeb IEEE80211_AC_VO, 559*6b4cac81SBjoern A. Zeeb IEEE80211_AC_VO, 560*6b4cac81SBjoern A. Zeeb #if 0 561*6b4cac81SBjoern A. Zeeb IEEE80211_AC_VO, /* We treat MGMT as TID 8, which is set as AC_VO */ 562*6b4cac81SBjoern A. Zeeb #endif 563*6b4cac81SBjoern A. Zeeb }; 564*6b4cac81SBjoern A. Zeeb 565*6b4cac81SBjoern A. Zeeb static void 566*6b4cac81SBjoern A. Zeeb lkpi_stop_hw_scan(struct lkpi_hw *lhw, struct ieee80211_vif *vif) 567*6b4cac81SBjoern A. Zeeb { 568*6b4cac81SBjoern A. Zeeb struct ieee80211_hw *hw; 569*6b4cac81SBjoern A. Zeeb int error; 570*6b4cac81SBjoern A. Zeeb 571*6b4cac81SBjoern A. Zeeb if ((lhw->scan_flags & LKPI_SCAN_RUNNING) == 0) 572*6b4cac81SBjoern A. Zeeb return; 573*6b4cac81SBjoern A. Zeeb 574*6b4cac81SBjoern A. Zeeb hw = LHW_TO_HW(lhw); 575*6b4cac81SBjoern A. Zeeb 576*6b4cac81SBjoern A. Zeeb /* Need to cancel the scan. */ 577*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_cancel_hw_scan(hw, vif); 578*6b4cac81SBjoern A. Zeeb 579*6b4cac81SBjoern A. Zeeb /* Need to make sure we see ieee80211_scan_completed. */ 580*6b4cac81SBjoern A. Zeeb error = msleep(lhw, &lhw->mtx, 0, "lhwscanstop", hz/2); 581*6b4cac81SBjoern A. Zeeb 582*6b4cac81SBjoern A. Zeeb if ((lhw->scan_flags & LKPI_SCAN_RUNNING) != 0) 583*6b4cac81SBjoern A. Zeeb ic_printf(lhw->ic, "%s: failed to cancel scan: %d (%p, %p)\n", 584*6b4cac81SBjoern A. Zeeb __func__, error, lhw, vif); 585*6b4cac81SBjoern A. Zeeb } 586*6b4cac81SBjoern A. Zeeb 587*6b4cac81SBjoern A. Zeeb static void 588*6b4cac81SBjoern A. Zeeb lkpi_disassoc(struct ieee80211_sta *sta, struct ieee80211_vif *vif, 589*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw) 590*6b4cac81SBjoern A. Zeeb { 591*6b4cac81SBjoern A. Zeeb sta->aid = 0; 592*6b4cac81SBjoern A. Zeeb if (vif->bss_conf.assoc) { 593*6b4cac81SBjoern A. Zeeb struct ieee80211_hw *hw; 594*6b4cac81SBjoern A. Zeeb enum ieee80211_bss_changed changed; 595*6b4cac81SBjoern A. Zeeb 596*6b4cac81SBjoern A. Zeeb lhw->update_mc = true; 597*6b4cac81SBjoern A. Zeeb lkpi_update_mcast_filter(lhw->ic, true); 598*6b4cac81SBjoern A. Zeeb 599*6b4cac81SBjoern A. Zeeb changed = 0; 600*6b4cac81SBjoern A. Zeeb vif->bss_conf.assoc = false; 601*6b4cac81SBjoern A. Zeeb vif->bss_conf.aid = 0; 602*6b4cac81SBjoern A. Zeeb changed |= BSS_CHANGED_ASSOC; 603*6b4cac81SBjoern A. Zeeb IMPROVE(); 604*6b4cac81SBjoern A. Zeeb hw = LHW_TO_HW(lhw); 605*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, 606*6b4cac81SBjoern A. Zeeb changed); 607*6b4cac81SBjoern A. Zeeb } 608*6b4cac81SBjoern A. Zeeb } 609*6b4cac81SBjoern A. Zeeb 610*6b4cac81SBjoern A. Zeeb static void 611*6b4cac81SBjoern A. Zeeb lkpi_wake_tx_queues(struct ieee80211_hw *hw, struct ieee80211_sta *sta, 612*6b4cac81SBjoern A. Zeeb bool dequeue_seen, bool no_emptyq) 613*6b4cac81SBjoern A. Zeeb { 614*6b4cac81SBjoern A. Zeeb struct lkpi_txq *ltxq; 615*6b4cac81SBjoern A. Zeeb int tid; 616*6b4cac81SBjoern A. Zeeb 617*6b4cac81SBjoern A. Zeeb /* Wake up all queues to know they are allocated in the driver. */ 618*6b4cac81SBjoern A. Zeeb for (tid = 0; tid < nitems(sta->txq); tid++) { 619*6b4cac81SBjoern A. Zeeb 620*6b4cac81SBjoern A. Zeeb if (tid == IEEE80211_NUM_TIDS) { 621*6b4cac81SBjoern A. Zeeb IMPROVE("station specific?"); 622*6b4cac81SBjoern A. Zeeb if (!ieee80211_hw_check(hw, STA_MMPDU_TXQ)) 623*6b4cac81SBjoern A. Zeeb continue; 624*6b4cac81SBjoern A. Zeeb } else if (tid >= hw->queues) 625*6b4cac81SBjoern A. Zeeb continue; 626*6b4cac81SBjoern A. Zeeb 627*6b4cac81SBjoern A. Zeeb if (sta->txq[tid] == NULL) 628*6b4cac81SBjoern A. Zeeb continue; 629*6b4cac81SBjoern A. Zeeb 630*6b4cac81SBjoern A. Zeeb ltxq = TXQ_TO_LTXQ(sta->txq[tid]); 631*6b4cac81SBjoern A. Zeeb if (dequeue_seen && !ltxq->seen_dequeue) 632*6b4cac81SBjoern A. Zeeb continue; 633*6b4cac81SBjoern A. Zeeb 634*6b4cac81SBjoern A. Zeeb if (no_emptyq && skb_queue_empty(<xq->skbq)) 635*6b4cac81SBjoern A. Zeeb continue; 636*6b4cac81SBjoern A. Zeeb 637*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_wake_tx_queue(hw, sta->txq[tid]); 638*6b4cac81SBjoern A. Zeeb } 639*6b4cac81SBjoern A. Zeeb } 640*6b4cac81SBjoern A. Zeeb 641*6b4cac81SBjoern A. Zeeb /* -------------------------------------------------------------------------- */ 642*6b4cac81SBjoern A. Zeeb 643*6b4cac81SBjoern A. Zeeb static int 644*6b4cac81SBjoern A. Zeeb lkpi_sta_state_do_nada(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 645*6b4cac81SBjoern A. Zeeb { 646*6b4cac81SBjoern A. Zeeb 647*6b4cac81SBjoern A. Zeeb return (0); 648*6b4cac81SBjoern A. Zeeb } 649*6b4cac81SBjoern A. Zeeb 650*6b4cac81SBjoern A. Zeeb /* lkpi_iv_newstate() handles the stop scan case generally. */ 651*6b4cac81SBjoern A. Zeeb #define lkpi_sta_scan_to_init(_v, _n, _a) lkpi_sta_state_do_nada(_v, _n, _a) 652*6b4cac81SBjoern A. Zeeb 653*6b4cac81SBjoern A. Zeeb static int 654*6b4cac81SBjoern A. Zeeb lkpi_sta_scan_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 655*6b4cac81SBjoern A. Zeeb { 656*6b4cac81SBjoern A. Zeeb struct linuxkpi_ieee80211_channel *chan; 657*6b4cac81SBjoern A. Zeeb struct ieee80211_chanctx_conf *conf; 658*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 659*6b4cac81SBjoern A. Zeeb struct ieee80211_hw *hw; 660*6b4cac81SBjoern A. Zeeb struct lkpi_vif *lvif; 661*6b4cac81SBjoern A. Zeeb struct ieee80211_vif *vif; 662*6b4cac81SBjoern A. Zeeb struct ieee80211_node *ni; 663*6b4cac81SBjoern A. Zeeb struct lkpi_sta *lsta; 664*6b4cac81SBjoern A. Zeeb struct ieee80211_sta *sta; 665*6b4cac81SBjoern A. Zeeb enum ieee80211_bss_changed bss_changed; 666*6b4cac81SBjoern A. Zeeb struct ieee80211_prep_tx_info prep_tx_info; 667*6b4cac81SBjoern A. Zeeb uint32_t changed; 668*6b4cac81SBjoern A. Zeeb int error; 669*6b4cac81SBjoern A. Zeeb 670*6b4cac81SBjoern A. Zeeb chan = lkpi_get_lkpi80211_chan(vap->iv_ic, vap->iv_bss); 671*6b4cac81SBjoern A. Zeeb if (chan == NULL) { 672*6b4cac81SBjoern A. Zeeb ic_printf(vap->iv_ic, "%s: failed to get channel\n", __func__); 673*6b4cac81SBjoern A. Zeeb return (ESRCH); 674*6b4cac81SBjoern A. Zeeb } 675*6b4cac81SBjoern A. Zeeb 676*6b4cac81SBjoern A. Zeeb lhw = vap->iv_ic->ic_softc; 677*6b4cac81SBjoern A. Zeeb hw = LHW_TO_HW(lhw); 678*6b4cac81SBjoern A. Zeeb lvif = VAP_TO_LVIF(vap); 679*6b4cac81SBjoern A. Zeeb vif = LVIF_TO_VIF(lvif); 680*6b4cac81SBjoern A. Zeeb 681*6b4cac81SBjoern A. Zeeb IEEE80211_UNLOCK(vap->iv_ic); 682*6b4cac81SBjoern A. Zeeb 683*6b4cac81SBjoern A. Zeeb /* Add chanctx (or if exists, change it). */ 684*6b4cac81SBjoern A. Zeeb if (vif->chanctx_conf != NULL) { 685*6b4cac81SBjoern A. Zeeb conf = vif->chanctx_conf; 686*6b4cac81SBjoern A. Zeeb IMPROVE("diff changes for changed, working on live copy, rcu"); 687*6b4cac81SBjoern A. Zeeb } else { 688*6b4cac81SBjoern A. Zeeb /* Keep separate alloc as in Linux this is rcu managed? */ 689*6b4cac81SBjoern A. Zeeb conf = malloc(sizeof(*conf) + hw->chanctx_data_size, 690*6b4cac81SBjoern A. Zeeb M_LKPI80211, M_WAITOK | M_ZERO); 691*6b4cac81SBjoern A. Zeeb } 692*6b4cac81SBjoern A. Zeeb 693*6b4cac81SBjoern A. Zeeb conf->rx_chains_dynamic = 1; 694*6b4cac81SBjoern A. Zeeb conf->rx_chains_static = 1; 695*6b4cac81SBjoern A. Zeeb conf->radar_enabled = 696*6b4cac81SBjoern A. Zeeb (chan->flags & IEEE80211_CHAN_RADAR) ? true : false; 697*6b4cac81SBjoern A. Zeeb conf->def.chan = chan; 698*6b4cac81SBjoern A. Zeeb conf->def.width = NL80211_CHAN_WIDTH_20_NOHT; 699*6b4cac81SBjoern A. Zeeb conf->def.center_freq1 = chan->center_freq; 700*6b4cac81SBjoern A. Zeeb conf->def.center_freq2 = 0; 701*6b4cac81SBjoern A. Zeeb /* Responder ... */ 702*6b4cac81SBjoern A. Zeeb conf->min_def.chan = chan; 703*6b4cac81SBjoern A. Zeeb conf->min_def.width = NL80211_CHAN_WIDTH_20_NOHT; 704*6b4cac81SBjoern A. Zeeb conf->min_def.center_freq1 = chan->center_freq; 705*6b4cac81SBjoern A. Zeeb conf->min_def.center_freq2 = 0; 706*6b4cac81SBjoern A. Zeeb IMPROVE("currently 20_NOHT only"); 707*6b4cac81SBjoern A. Zeeb 708*6b4cac81SBjoern A. Zeeb ni = NULL; 709*6b4cac81SBjoern A. Zeeb error = 0; 710*6b4cac81SBjoern A. Zeeb if (vif->chanctx_conf != NULL) { 711*6b4cac81SBjoern A. Zeeb changed = IEEE80211_CHANCTX_CHANGE_MIN_WIDTH; 712*6b4cac81SBjoern A. Zeeb changed |= IEEE80211_CHANCTX_CHANGE_RADAR; 713*6b4cac81SBjoern A. Zeeb changed |= IEEE80211_CHANCTX_CHANGE_RX_CHAINS; 714*6b4cac81SBjoern A. Zeeb changed |= IEEE80211_CHANCTX_CHANGE_WIDTH; 715*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_change_chanctx(hw, conf, changed); 716*6b4cac81SBjoern A. Zeeb } else { 717*6b4cac81SBjoern A. Zeeb error = lkpi_80211_mo_add_chanctx(hw, conf); 718*6b4cac81SBjoern A. Zeeb if (error == 0 || error == EOPNOTSUPP) { 719*6b4cac81SBjoern A. Zeeb vif->bss_conf.chandef.chan = conf->def.chan; 720*6b4cac81SBjoern A. Zeeb vif->bss_conf.chandef.width = conf->def.width; 721*6b4cac81SBjoern A. Zeeb vif->bss_conf.chandef.center_freq1 = 722*6b4cac81SBjoern A. Zeeb conf->def.center_freq1; 723*6b4cac81SBjoern A. Zeeb vif->bss_conf.chandef.center_freq2 = 724*6b4cac81SBjoern A. Zeeb conf->def.center_freq2; 725*6b4cac81SBjoern A. Zeeb } else { 726*6b4cac81SBjoern A. Zeeb goto out; 727*6b4cac81SBjoern A. Zeeb } 728*6b4cac81SBjoern A. Zeeb /* Assign vif chanctx. */ 729*6b4cac81SBjoern A. Zeeb if (error == 0) 730*6b4cac81SBjoern A. Zeeb error = lkpi_80211_mo_assign_vif_chanctx(hw, vif, conf); 731*6b4cac81SBjoern A. Zeeb if (error == EOPNOTSUPP) 732*6b4cac81SBjoern A. Zeeb error = 0; 733*6b4cac81SBjoern A. Zeeb if (error != 0) { 734*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_remove_chanctx(hw, conf); 735*6b4cac81SBjoern A. Zeeb free(conf, M_LKPI80211); 736*6b4cac81SBjoern A. Zeeb goto out; 737*6b4cac81SBjoern A. Zeeb } 738*6b4cac81SBjoern A. Zeeb } 739*6b4cac81SBjoern A. Zeeb IMPROVE("update radiotap chan fields too"); 740*6b4cac81SBjoern A. Zeeb 741*6b4cac81SBjoern A. Zeeb ni = ieee80211_ref_node(vap->iv_bss); 742*6b4cac81SBjoern A. Zeeb 743*6b4cac81SBjoern A. Zeeb /* Set bss info (bss_info_changed). */ 744*6b4cac81SBjoern A. Zeeb bss_changed = 0; 745*6b4cac81SBjoern A. Zeeb IEEE80211_ADDR_COPY(vif->bss_conf.bssid, ni->ni_bssid); 746*6b4cac81SBjoern A. Zeeb bss_changed |= BSS_CHANGED_BSSID; 747*6b4cac81SBjoern A. Zeeb vif->bss_conf.txpower = ni->ni_txpower; 748*6b4cac81SBjoern A. Zeeb bss_changed |= BSS_CHANGED_TXPOWER; 749*6b4cac81SBjoern A. Zeeb vif->bss_conf.idle = false; 750*6b4cac81SBjoern A. Zeeb bss_changed |= BSS_CHANGED_IDLE; 751*6b4cac81SBjoern A. Zeeb vif->bss_conf.beacon_int = ni->ni_intval; 752*6b4cac81SBjoern A. Zeeb /* iwlwifi FW bug workaround; iwl_mvm_mac_sta_state. */ 753*6b4cac81SBjoern A. Zeeb if (vif->bss_conf.beacon_int < 16) 754*6b4cac81SBjoern A. Zeeb vif->bss_conf.beacon_int = 16; 755*6b4cac81SBjoern A. Zeeb bss_changed |= BSS_CHANGED_BEACON_INT; 756*6b4cac81SBjoern A. Zeeb /* Should almost assert it is this. */ 757*6b4cac81SBjoern A. Zeeb vif->bss_conf.assoc = false; 758*6b4cac81SBjoern A. Zeeb vif->bss_conf.aid = 0; 759*6b4cac81SBjoern A. Zeeb /* RATES */ 760*6b4cac81SBjoern A. Zeeb IMPROVE("bss info: not all needs to come now and rates are missing"); 761*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, bss_changed); 762*6b4cac81SBjoern A. Zeeb 763*6b4cac81SBjoern A. Zeeb /* Add (or adjust) sta and change state (from NOTEXIST) to NONE. */ 764*6b4cac81SBjoern A. Zeeb lsta = ni->ni_drv_data; 765*6b4cac81SBjoern A. Zeeb KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni)); 766*6b4cac81SBjoern A. Zeeb KASSERT(lsta->state == IEEE80211_STA_NOTEXIST, ("%s: lsta %p state not " 767*6b4cac81SBjoern A. Zeeb "NOTEXIST: %#x\n", __func__, lsta, lsta->state)); 768*6b4cac81SBjoern A. Zeeb sta = LSTA_TO_STA(lsta); 769*6b4cac81SBjoern A. Zeeb error = lkpi_80211_mo_sta_state(hw, vif, sta, IEEE80211_STA_NONE); 770*6b4cac81SBjoern A. Zeeb if (error != 0) { 771*6b4cac81SBjoern A. Zeeb IMPROVE("do we need to undo the chan ctx?"); 772*6b4cac81SBjoern A. Zeeb goto out; 773*6b4cac81SBjoern A. Zeeb } 774*6b4cac81SBjoern A. Zeeb #if 0 775*6b4cac81SBjoern A. Zeeb lsta->added_to_drv = true; /* mo manages. */ 776*6b4cac81SBjoern A. Zeeb #endif 777*6b4cac81SBjoern A. Zeeb 778*6b4cac81SBjoern A. Zeeb /* 779*6b4cac81SBjoern A. Zeeb * Wakeup all queues now that sta is there so we have as much time to 780*6b4cac81SBjoern A. Zeeb * possibly prepare the queue in the driver to be ready for the 1st 781*6b4cac81SBjoern A. Zeeb * packet; lkpi_80211_txq_tx_one() still has a workaround as there 782*6b4cac81SBjoern A. Zeeb * is no guarantee or way to check. 783*6b4cac81SBjoern A. Zeeb */ 784*6b4cac81SBjoern A. Zeeb lkpi_wake_tx_queues(hw, sta, false, false); 785*6b4cac81SBjoern A. Zeeb 786*6b4cac81SBjoern A. Zeeb { 787*6b4cac81SBjoern A. Zeeb int i, count; 788*6b4cac81SBjoern A. Zeeb 789*6b4cac81SBjoern A. Zeeb for (i = 3; i > 0; i++) { 790*6b4cac81SBjoern A. Zeeb struct lkpi_txq *ltxq; 791*6b4cac81SBjoern A. Zeeb int tid; 792*6b4cac81SBjoern A. Zeeb 793*6b4cac81SBjoern A. Zeeb count = 0; 794*6b4cac81SBjoern A. Zeeb /* Wake up all queues to know they are allocated in the driver. */ 795*6b4cac81SBjoern A. Zeeb for (tid = 0; tid < nitems(sta->txq); tid++) { 796*6b4cac81SBjoern A. Zeeb 797*6b4cac81SBjoern A. Zeeb if (tid == IEEE80211_NUM_TIDS) { 798*6b4cac81SBjoern A. Zeeb IMPROVE("station specific?"); 799*6b4cac81SBjoern A. Zeeb if (!ieee80211_hw_check(hw, STA_MMPDU_TXQ)) 800*6b4cac81SBjoern A. Zeeb continue; 801*6b4cac81SBjoern A. Zeeb } else if (tid >= hw->queues) 802*6b4cac81SBjoern A. Zeeb continue; 803*6b4cac81SBjoern A. Zeeb 804*6b4cac81SBjoern A. Zeeb if (sta->txq[tid] == NULL) 805*6b4cac81SBjoern A. Zeeb continue; 806*6b4cac81SBjoern A. Zeeb 807*6b4cac81SBjoern A. Zeeb ltxq = TXQ_TO_LTXQ(sta->txq[tid]); 808*6b4cac81SBjoern A. Zeeb if (!ltxq->seen_dequeue) 809*6b4cac81SBjoern A. Zeeb count++; 810*6b4cac81SBjoern A. Zeeb } 811*6b4cac81SBjoern A. Zeeb if (count == 0) 812*6b4cac81SBjoern A. Zeeb break; 813*6b4cac81SBjoern A. Zeeb #ifdef LINUXKPI_DEBUG_80211 814*6b4cac81SBjoern A. Zeeb if (count > 0) 815*6b4cac81SBjoern A. Zeeb ic_printf(vap->iv_ic, "%s: waiting for %d quuees " 816*6b4cac81SBjoern A. Zeeb "to be allocated by driver\n", __func__, count); 817*6b4cac81SBjoern A. Zeeb #endif 818*6b4cac81SBjoern A. Zeeb DELAY(100); 819*6b4cac81SBjoern A. Zeeb } 820*6b4cac81SBjoern A. Zeeb #ifdef LINUXKPI_DEBUG_80211 821*6b4cac81SBjoern A. Zeeb if (count > 0) 822*6b4cac81SBjoern A. Zeeb ic_printf(vap->iv_ic, "%s: %d quuees still not " 823*6b4cac81SBjoern A. Zeeb "allocated by driver\n", __func__, count); 824*6b4cac81SBjoern A. Zeeb #endif 825*6b4cac81SBjoern A. Zeeb } 826*6b4cac81SBjoern A. Zeeb 827*6b4cac81SBjoern A. Zeeb /* Start mgd_prepare_tx. */ 828*6b4cac81SBjoern A. Zeeb memset(&prep_tx_info, 0, sizeof(prep_tx_info)); 829*6b4cac81SBjoern A. Zeeb prep_tx_info.duration = PREP_TX_INFO_DURATION; 830*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_mgd_prepare_tx(hw, vif, &prep_tx_info); 831*6b4cac81SBjoern A. Zeeb lsta->in_mgd = true; 832*6b4cac81SBjoern A. Zeeb 833*6b4cac81SBjoern A. Zeeb /* 834*6b4cac81SBjoern A. Zeeb * What is going to happen next: 835*6b4cac81SBjoern A. Zeeb * - <twiddle> .. we should end up in "auth_to_assoc" 836*6b4cac81SBjoern A. Zeeb * - event_callback 837*6b4cac81SBjoern A. Zeeb * - update sta_state (NONE to AUTH) 838*6b4cac81SBjoern A. Zeeb * - mgd_complete_tx 839*6b4cac81SBjoern A. Zeeb * (ideally we'd do that on a callback for something else ...) 840*6b4cac81SBjoern A. Zeeb */ 841*6b4cac81SBjoern A. Zeeb 842*6b4cac81SBjoern A. Zeeb out: 843*6b4cac81SBjoern A. Zeeb IEEE80211_LOCK(vap->iv_ic); 844*6b4cac81SBjoern A. Zeeb if (ni != NULL) 845*6b4cac81SBjoern A. Zeeb ieee80211_free_node(ni); 846*6b4cac81SBjoern A. Zeeb return (error); 847*6b4cac81SBjoern A. Zeeb } 848*6b4cac81SBjoern A. Zeeb 849*6b4cac81SBjoern A. Zeeb static int 850*6b4cac81SBjoern A. Zeeb lkpi_sta_auth_to_scan(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 851*6b4cac81SBjoern A. Zeeb { 852*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 853*6b4cac81SBjoern A. Zeeb struct ieee80211_hw *hw; 854*6b4cac81SBjoern A. Zeeb struct lkpi_vif *lvif; 855*6b4cac81SBjoern A. Zeeb struct ieee80211_vif *vif; 856*6b4cac81SBjoern A. Zeeb struct ieee80211_node *ni; 857*6b4cac81SBjoern A. Zeeb struct lkpi_sta *lsta; 858*6b4cac81SBjoern A. Zeeb struct ieee80211_sta *sta; 859*6b4cac81SBjoern A. Zeeb struct ieee80211_prep_tx_info prep_tx_info; 860*6b4cac81SBjoern A. Zeeb int error; 861*6b4cac81SBjoern A. Zeeb 862*6b4cac81SBjoern A. Zeeb lhw = vap->iv_ic->ic_softc; 863*6b4cac81SBjoern A. Zeeb hw = LHW_TO_HW(lhw); 864*6b4cac81SBjoern A. Zeeb lvif = VAP_TO_LVIF(vap); 865*6b4cac81SBjoern A. Zeeb vif = LVIF_TO_VIF(lvif); 866*6b4cac81SBjoern A. Zeeb 867*6b4cac81SBjoern A. Zeeb /* Keep ni around. */ 868*6b4cac81SBjoern A. Zeeb ni = ieee80211_ref_node(vap->iv_bss); 869*6b4cac81SBjoern A. Zeeb 870*6b4cac81SBjoern A. Zeeb IEEE80211_UNLOCK(vap->iv_ic); 871*6b4cac81SBjoern A. Zeeb lsta = ni->ni_drv_data; 872*6b4cac81SBjoern A. Zeeb sta = LSTA_TO_STA(lsta); 873*6b4cac81SBjoern A. Zeeb 874*6b4cac81SBjoern A. Zeeb /* flush, drop. */ 875*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), true); 876*6b4cac81SBjoern A. Zeeb 877*6b4cac81SBjoern A. Zeeb IEEE80211_LOCK(vap->iv_ic); 878*6b4cac81SBjoern A. Zeeb 879*6b4cac81SBjoern A. Zeeb /* Call iv_newstate first so we get potential deauth packet out. */ 880*6b4cac81SBjoern A. Zeeb error = lvif->iv_newstate(vap, nstate, arg); 881*6b4cac81SBjoern A. Zeeb if (error != 0) 882*6b4cac81SBjoern A. Zeeb goto outni; 883*6b4cac81SBjoern A. Zeeb 884*6b4cac81SBjoern A. Zeeb IEEE80211_UNLOCK(vap->iv_ic); 885*6b4cac81SBjoern A. Zeeb 886*6b4cac81SBjoern A. Zeeb /* Wake tx queues to get packet(s) out. */ 887*6b4cac81SBjoern A. Zeeb lkpi_wake_tx_queues(hw, sta, true, true); 888*6b4cac81SBjoern A. Zeeb 889*6b4cac81SBjoern A. Zeeb /* flush, no drop */ 890*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), false); 891*6b4cac81SBjoern A. Zeeb 892*6b4cac81SBjoern A. Zeeb /* Take the station and chan ctx down again. */ 893*6b4cac81SBjoern A. Zeeb 894*6b4cac81SBjoern A. Zeeb IMPROVE("event callback with failure?"); 895*6b4cac81SBjoern A. Zeeb 896*6b4cac81SBjoern A. Zeeb /* End mgd_complete_tx. */ 897*6b4cac81SBjoern A. Zeeb if (lsta->in_mgd) { 898*6b4cac81SBjoern A. Zeeb memset(&prep_tx_info, 0, sizeof(prep_tx_info)); 899*6b4cac81SBjoern A. Zeeb prep_tx_info.success = false; 900*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_mgd_complete_tx(hw, vif, &prep_tx_info); 901*6b4cac81SBjoern A. Zeeb lsta->in_mgd = false; 902*6b4cac81SBjoern A. Zeeb } 903*6b4cac81SBjoern A. Zeeb 904*6b4cac81SBjoern A. Zeeb #ifdef __not_yet__ 905*6b4cac81SBjoern A. Zeeb /* sync_rx_queues */ 906*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_sync_rx_queues(hw); 907*6b4cac81SBjoern A. Zeeb 908*6b4cac81SBjoern A. Zeeb /* sta_pre_rcu_remove */ 909*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_sta_pre_rcu_remove(hw, vif, sta); 910*6b4cac81SBjoern A. Zeeb #endif 911*6b4cac81SBjoern A. Zeeb 912*6b4cac81SBjoern A. Zeeb /* Adjust sta and change state (from NONE) to NOTEXIST. */ 913*6b4cac81SBjoern A. Zeeb KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni)); 914*6b4cac81SBjoern A. Zeeb KASSERT(lsta->state == IEEE80211_STA_NONE, ("%s: lsta %p state not " 915*6b4cac81SBjoern A. Zeeb "NONE: %#x\n", __func__, lsta, lsta->state)); 916*6b4cac81SBjoern A. Zeeb error = lkpi_80211_mo_sta_state(hw, vif, sta, IEEE80211_STA_NOTEXIST); 917*6b4cac81SBjoern A. Zeeb if (error != 0) { 918*6b4cac81SBjoern A. Zeeb IMPROVE("do we need to undo the chan ctx?"); 919*6b4cac81SBjoern A. Zeeb goto out; 920*6b4cac81SBjoern A. Zeeb } 921*6b4cac81SBjoern A. Zeeb #if 0 922*6b4cac81SBjoern A. Zeeb lsta->added_to_drv = false; /* mo manages. */ 923*6b4cac81SBjoern A. Zeeb #endif 924*6b4cac81SBjoern A. Zeeb 925*6b4cac81SBjoern A. Zeeb IMPROVE("Any bss_info changes to announce?"); 926*6b4cac81SBjoern A. Zeeb 927*6b4cac81SBjoern A. Zeeb if (vif->chanctx_conf != NULL) { 928*6b4cac81SBjoern A. Zeeb struct ieee80211_chanctx_conf *conf; 929*6b4cac81SBjoern A. Zeeb 930*6b4cac81SBjoern A. Zeeb conf = vif->chanctx_conf; 931*6b4cac81SBjoern A. Zeeb /* Remove vif context. */ 932*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_unassign_vif_chanctx(hw, vif, &vif->chanctx_conf); 933*6b4cac81SBjoern A. Zeeb /* NB: vif->chanctx_conf is NULL now. */ 934*6b4cac81SBjoern A. Zeeb 935*6b4cac81SBjoern A. Zeeb /* Remove chan ctx. */ 936*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_remove_chanctx(hw, conf); 937*6b4cac81SBjoern A. Zeeb free(conf, M_LKPI80211); 938*6b4cac81SBjoern A. Zeeb } 939*6b4cac81SBjoern A. Zeeb 940*6b4cac81SBjoern A. Zeeb /* No need to start a scan; ic_scan_start should do. */ 941*6b4cac81SBjoern A. Zeeb 942*6b4cac81SBjoern A. Zeeb error = EALREADY; 943*6b4cac81SBjoern A. Zeeb out: 944*6b4cac81SBjoern A. Zeeb IEEE80211_LOCK(vap->iv_ic); 945*6b4cac81SBjoern A. Zeeb outni: 946*6b4cac81SBjoern A. Zeeb if (ni != NULL) 947*6b4cac81SBjoern A. Zeeb ieee80211_free_node(ni); 948*6b4cac81SBjoern A. Zeeb return (error); 949*6b4cac81SBjoern A. Zeeb } 950*6b4cac81SBjoern A. Zeeb 951*6b4cac81SBjoern A. Zeeb static int 952*6b4cac81SBjoern A. Zeeb lkpi_sta_auth_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 953*6b4cac81SBjoern A. Zeeb { 954*6b4cac81SBjoern A. Zeeb int error; 955*6b4cac81SBjoern A. Zeeb 956*6b4cac81SBjoern A. Zeeb error = lkpi_sta_auth_to_scan(vap, nstate, arg); 957*6b4cac81SBjoern A. Zeeb if (error == 0) 958*6b4cac81SBjoern A. Zeeb error = lkpi_sta_scan_to_init(vap, nstate, arg); 959*6b4cac81SBjoern A. Zeeb return (error); 960*6b4cac81SBjoern A. Zeeb } 961*6b4cac81SBjoern A. Zeeb 962*6b4cac81SBjoern A. Zeeb static int 963*6b4cac81SBjoern A. Zeeb lkpi_sta_auth_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 964*6b4cac81SBjoern A. Zeeb { 965*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 966*6b4cac81SBjoern A. Zeeb struct ieee80211_hw *hw; 967*6b4cac81SBjoern A. Zeeb struct lkpi_vif *lvif; 968*6b4cac81SBjoern A. Zeeb struct ieee80211_vif *vif; 969*6b4cac81SBjoern A. Zeeb struct ieee80211_node *ni; 970*6b4cac81SBjoern A. Zeeb struct lkpi_sta *lsta; 971*6b4cac81SBjoern A. Zeeb struct ieee80211_sta *sta; 972*6b4cac81SBjoern A. Zeeb struct ieee80211_prep_tx_info prep_tx_info; 973*6b4cac81SBjoern A. Zeeb int error; 974*6b4cac81SBjoern A. Zeeb 975*6b4cac81SBjoern A. Zeeb lhw = vap->iv_ic->ic_softc; 976*6b4cac81SBjoern A. Zeeb hw = LHW_TO_HW(lhw); 977*6b4cac81SBjoern A. Zeeb lvif = VAP_TO_LVIF(vap); 978*6b4cac81SBjoern A. Zeeb vif = LVIF_TO_VIF(lvif); 979*6b4cac81SBjoern A. Zeeb 980*6b4cac81SBjoern A. Zeeb IEEE80211_UNLOCK(vap->iv_ic); 981*6b4cac81SBjoern A. Zeeb ni = NULL; 982*6b4cac81SBjoern A. Zeeb 983*6b4cac81SBjoern A. Zeeb /* Finish auth. */ 984*6b4cac81SBjoern A. Zeeb IMPROVE("event callback"); 985*6b4cac81SBjoern A. Zeeb 986*6b4cac81SBjoern A. Zeeb /* Update sta_state (NONE to AUTH). */ 987*6b4cac81SBjoern A. Zeeb ni = ieee80211_ref_node(vap->iv_bss); 988*6b4cac81SBjoern A. Zeeb lsta = ni->ni_drv_data; 989*6b4cac81SBjoern A. Zeeb KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni)); 990*6b4cac81SBjoern A. Zeeb KASSERT(lsta->state == IEEE80211_STA_NONE, ("%s: lsta %p state not " 991*6b4cac81SBjoern A. Zeeb "NONE: %#x\n", __func__, lsta, lsta->state)); 992*6b4cac81SBjoern A. Zeeb sta = LSTA_TO_STA(lsta); 993*6b4cac81SBjoern A. Zeeb error = lkpi_80211_mo_sta_state(hw, vif, sta, IEEE80211_STA_AUTH); 994*6b4cac81SBjoern A. Zeeb if (error != 0) 995*6b4cac81SBjoern A. Zeeb goto out; 996*6b4cac81SBjoern A. Zeeb 997*6b4cac81SBjoern A. Zeeb /* End mgd_complete_tx. */ 998*6b4cac81SBjoern A. Zeeb if (lsta->in_mgd) { 999*6b4cac81SBjoern A. Zeeb memset(&prep_tx_info, 0, sizeof(prep_tx_info)); 1000*6b4cac81SBjoern A. Zeeb prep_tx_info.success = true; 1001*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_mgd_complete_tx(hw, vif, &prep_tx_info); 1002*6b4cac81SBjoern A. Zeeb lsta->in_mgd = false; 1003*6b4cac81SBjoern A. Zeeb } 1004*6b4cac81SBjoern A. Zeeb 1005*6b4cac81SBjoern A. Zeeb /* Now start assoc. */ 1006*6b4cac81SBjoern A. Zeeb 1007*6b4cac81SBjoern A. Zeeb /* Start mgd_prepare_tx. */ 1008*6b4cac81SBjoern A. Zeeb if (!lsta->in_mgd) { 1009*6b4cac81SBjoern A. Zeeb memset(&prep_tx_info, 0, sizeof(prep_tx_info)); 1010*6b4cac81SBjoern A. Zeeb prep_tx_info.duration = PREP_TX_INFO_DURATION; 1011*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_mgd_prepare_tx(hw, vif, &prep_tx_info); 1012*6b4cac81SBjoern A. Zeeb lsta->in_mgd = true; 1013*6b4cac81SBjoern A. Zeeb } 1014*6b4cac81SBjoern A. Zeeb 1015*6b4cac81SBjoern A. Zeeb /* Wake tx queue to get packet out. */ 1016*6b4cac81SBjoern A. Zeeb lkpi_wake_tx_queues(hw, sta, true, true); 1017*6b4cac81SBjoern A. Zeeb 1018*6b4cac81SBjoern A. Zeeb /* 1019*6b4cac81SBjoern A. Zeeb * <twiddle> .. we end up in "assoc_to_run" 1020*6b4cac81SBjoern A. Zeeb * - update sta_state (AUTH to ASSOC) 1021*6b4cac81SBjoern A. Zeeb * - conf_tx [all] 1022*6b4cac81SBjoern A. Zeeb * - bss_info_changed (assoc, aid, ssid, ..) 1023*6b4cac81SBjoern A. Zeeb * - change_chanctx (if needed) 1024*6b4cac81SBjoern A. Zeeb * - event_callback 1025*6b4cac81SBjoern A. Zeeb * - mgd_complete_tx 1026*6b4cac81SBjoern A. Zeeb */ 1027*6b4cac81SBjoern A. Zeeb 1028*6b4cac81SBjoern A. Zeeb out: 1029*6b4cac81SBjoern A. Zeeb IEEE80211_LOCK(vap->iv_ic); 1030*6b4cac81SBjoern A. Zeeb if (ni != NULL) 1031*6b4cac81SBjoern A. Zeeb ieee80211_free_node(ni); 1032*6b4cac81SBjoern A. Zeeb return (error); 1033*6b4cac81SBjoern A. Zeeb } 1034*6b4cac81SBjoern A. Zeeb 1035*6b4cac81SBjoern A. Zeeb /* auth_to_auth, assoc_to_assoc. */ 1036*6b4cac81SBjoern A. Zeeb static int 1037*6b4cac81SBjoern A. Zeeb lkpi_sta_a_to_a(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 1038*6b4cac81SBjoern A. Zeeb { 1039*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 1040*6b4cac81SBjoern A. Zeeb struct ieee80211_hw *hw; 1041*6b4cac81SBjoern A. Zeeb struct lkpi_vif *lvif; 1042*6b4cac81SBjoern A. Zeeb struct ieee80211_vif *vif; 1043*6b4cac81SBjoern A. Zeeb struct ieee80211_node *ni; 1044*6b4cac81SBjoern A. Zeeb struct lkpi_sta *lsta; 1045*6b4cac81SBjoern A. Zeeb struct ieee80211_prep_tx_info prep_tx_info; 1046*6b4cac81SBjoern A. Zeeb 1047*6b4cac81SBjoern A. Zeeb lhw = vap->iv_ic->ic_softc; 1048*6b4cac81SBjoern A. Zeeb hw = LHW_TO_HW(lhw); 1049*6b4cac81SBjoern A. Zeeb lvif = VAP_TO_LVIF(vap); 1050*6b4cac81SBjoern A. Zeeb vif = LVIF_TO_VIF(lvif); 1051*6b4cac81SBjoern A. Zeeb 1052*6b4cac81SBjoern A. Zeeb ni = ieee80211_ref_node(vap->iv_bss); 1053*6b4cac81SBjoern A. Zeeb 1054*6b4cac81SBjoern A. Zeeb IEEE80211_UNLOCK(vap->iv_ic); 1055*6b4cac81SBjoern A. Zeeb lsta = ni->ni_drv_data; 1056*6b4cac81SBjoern A. Zeeb 1057*6b4cac81SBjoern A. Zeeb IMPROVE("event callback?"); 1058*6b4cac81SBjoern A. Zeeb 1059*6b4cac81SBjoern A. Zeeb /* End mgd_complete_tx. */ 1060*6b4cac81SBjoern A. Zeeb if (lsta->in_mgd) { 1061*6b4cac81SBjoern A. Zeeb memset(&prep_tx_info, 0, sizeof(prep_tx_info)); 1062*6b4cac81SBjoern A. Zeeb prep_tx_info.success = false; 1063*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_mgd_complete_tx(hw, vif, &prep_tx_info); 1064*6b4cac81SBjoern A. Zeeb lsta->in_mgd = false; 1065*6b4cac81SBjoern A. Zeeb } 1066*6b4cac81SBjoern A. Zeeb 1067*6b4cac81SBjoern A. Zeeb /* Now start assoc. */ 1068*6b4cac81SBjoern A. Zeeb 1069*6b4cac81SBjoern A. Zeeb /* Start mgd_prepare_tx. */ 1070*6b4cac81SBjoern A. Zeeb if (!lsta->in_mgd) { 1071*6b4cac81SBjoern A. Zeeb memset(&prep_tx_info, 0, sizeof(prep_tx_info)); 1072*6b4cac81SBjoern A. Zeeb prep_tx_info.duration = PREP_TX_INFO_DURATION; 1073*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_mgd_prepare_tx(hw, vif, &prep_tx_info); 1074*6b4cac81SBjoern A. Zeeb lsta->in_mgd = true; 1075*6b4cac81SBjoern A. Zeeb } 1076*6b4cac81SBjoern A. Zeeb 1077*6b4cac81SBjoern A. Zeeb IEEE80211_LOCK(vap->iv_ic); 1078*6b4cac81SBjoern A. Zeeb if (ni != NULL) 1079*6b4cac81SBjoern A. Zeeb ieee80211_free_node(ni); 1080*6b4cac81SBjoern A. Zeeb 1081*6b4cac81SBjoern A. Zeeb return (0); 1082*6b4cac81SBjoern A. Zeeb } 1083*6b4cac81SBjoern A. Zeeb 1084*6b4cac81SBjoern A. Zeeb static int 1085*6b4cac81SBjoern A. Zeeb lkpi_sta_assoc_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 1086*6b4cac81SBjoern A. Zeeb { 1087*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 1088*6b4cac81SBjoern A. Zeeb struct ieee80211_hw *hw; 1089*6b4cac81SBjoern A. Zeeb struct lkpi_vif *lvif; 1090*6b4cac81SBjoern A. Zeeb struct ieee80211_vif *vif; 1091*6b4cac81SBjoern A. Zeeb struct ieee80211_node *ni; 1092*6b4cac81SBjoern A. Zeeb struct lkpi_sta *lsta; 1093*6b4cac81SBjoern A. Zeeb struct ieee80211_sta *sta; 1094*6b4cac81SBjoern A. Zeeb struct ieee80211_prep_tx_info prep_tx_info; 1095*6b4cac81SBjoern A. Zeeb int error; 1096*6b4cac81SBjoern A. Zeeb 1097*6b4cac81SBjoern A. Zeeb lhw = vap->iv_ic->ic_softc; 1098*6b4cac81SBjoern A. Zeeb hw = LHW_TO_HW(lhw); 1099*6b4cac81SBjoern A. Zeeb lvif = VAP_TO_LVIF(vap); 1100*6b4cac81SBjoern A. Zeeb vif = LVIF_TO_VIF(lvif); 1101*6b4cac81SBjoern A. Zeeb 1102*6b4cac81SBjoern A. Zeeb /* Keep ni around. */ 1103*6b4cac81SBjoern A. Zeeb ni = ieee80211_ref_node(vap->iv_bss); 1104*6b4cac81SBjoern A. Zeeb 1105*6b4cac81SBjoern A. Zeeb IEEE80211_UNLOCK(vap->iv_ic); 1106*6b4cac81SBjoern A. Zeeb lsta = ni->ni_drv_data; 1107*6b4cac81SBjoern A. Zeeb sta = LSTA_TO_STA(lsta); 1108*6b4cac81SBjoern A. Zeeb 1109*6b4cac81SBjoern A. Zeeb /* End mgd_complete_tx. */ 1110*6b4cac81SBjoern A. Zeeb if (lsta->in_mgd) { 1111*6b4cac81SBjoern A. Zeeb memset(&prep_tx_info, 0, sizeof(prep_tx_info)); 1112*6b4cac81SBjoern A. Zeeb prep_tx_info.success = false; 1113*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_mgd_complete_tx(hw, vif, &prep_tx_info); 1114*6b4cac81SBjoern A. Zeeb lsta->in_mgd = false; 1115*6b4cac81SBjoern A. Zeeb } 1116*6b4cac81SBjoern A. Zeeb 1117*6b4cac81SBjoern A. Zeeb /* Update sta and change state (from AUTH) to NONE. */ 1118*6b4cac81SBjoern A. Zeeb KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni)); 1119*6b4cac81SBjoern A. Zeeb KASSERT(lsta->state == IEEE80211_STA_AUTH, ("%s: lsta %p state not " 1120*6b4cac81SBjoern A. Zeeb "AUTH: %#x\n", __func__, lsta, lsta->state)); 1121*6b4cac81SBjoern A. Zeeb error = lkpi_80211_mo_sta_state(hw, vif, sta, IEEE80211_STA_NONE); 1122*6b4cac81SBjoern A. Zeeb if (error != 0) 1123*6b4cac81SBjoern A. Zeeb goto out; 1124*6b4cac81SBjoern A. Zeeb 1125*6b4cac81SBjoern A. Zeeb IMPROVE("anything else?"); 1126*6b4cac81SBjoern A. Zeeb 1127*6b4cac81SBjoern A. Zeeb out: 1128*6b4cac81SBjoern A. Zeeb IEEE80211_LOCK(vap->iv_ic); 1129*6b4cac81SBjoern A. Zeeb if (ni != NULL) 1130*6b4cac81SBjoern A. Zeeb ieee80211_free_node(ni); 1131*6b4cac81SBjoern A. Zeeb return (error); 1132*6b4cac81SBjoern A. Zeeb } 1133*6b4cac81SBjoern A. Zeeb 1134*6b4cac81SBjoern A. Zeeb static int 1135*6b4cac81SBjoern A. Zeeb lkpi_sta_assoc_to_scan(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 1136*6b4cac81SBjoern A. Zeeb { 1137*6b4cac81SBjoern A. Zeeb int error; 1138*6b4cac81SBjoern A. Zeeb 1139*6b4cac81SBjoern A. Zeeb error = lkpi_sta_assoc_to_auth(vap, nstate, arg); 1140*6b4cac81SBjoern A. Zeeb if (error == 0) 1141*6b4cac81SBjoern A. Zeeb error = lkpi_sta_auth_to_scan(vap, nstate, arg); 1142*6b4cac81SBjoern A. Zeeb return (error); 1143*6b4cac81SBjoern A. Zeeb } 1144*6b4cac81SBjoern A. Zeeb 1145*6b4cac81SBjoern A. Zeeb static int 1146*6b4cac81SBjoern A. Zeeb lkpi_sta_assoc_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 1147*6b4cac81SBjoern A. Zeeb { 1148*6b4cac81SBjoern A. Zeeb int error; 1149*6b4cac81SBjoern A. Zeeb 1150*6b4cac81SBjoern A. Zeeb error = lkpi_sta_assoc_to_scan(vap, nstate, arg); 1151*6b4cac81SBjoern A. Zeeb if (error == 0) 1152*6b4cac81SBjoern A. Zeeb error = lkpi_sta_scan_to_init(vap, nstate, arg); 1153*6b4cac81SBjoern A. Zeeb return (error); 1154*6b4cac81SBjoern A. Zeeb } 1155*6b4cac81SBjoern A. Zeeb 1156*6b4cac81SBjoern A. Zeeb static int 1157*6b4cac81SBjoern A. Zeeb lkpi_sta_assoc_to_run(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 1158*6b4cac81SBjoern A. Zeeb { 1159*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 1160*6b4cac81SBjoern A. Zeeb struct ieee80211_hw *hw; 1161*6b4cac81SBjoern A. Zeeb struct lkpi_vif *lvif; 1162*6b4cac81SBjoern A. Zeeb struct ieee80211_vif *vif; 1163*6b4cac81SBjoern A. Zeeb struct ieee80211_node *ni; 1164*6b4cac81SBjoern A. Zeeb struct lkpi_sta *lsta; 1165*6b4cac81SBjoern A. Zeeb struct ieee80211_sta *sta; 1166*6b4cac81SBjoern A. Zeeb struct ieee80211_prep_tx_info prep_tx_info; 1167*6b4cac81SBjoern A. Zeeb enum ieee80211_bss_changed bss_changed; 1168*6b4cac81SBjoern A. Zeeb int error; 1169*6b4cac81SBjoern A. Zeeb 1170*6b4cac81SBjoern A. Zeeb lhw = vap->iv_ic->ic_softc; 1171*6b4cac81SBjoern A. Zeeb hw = LHW_TO_HW(lhw); 1172*6b4cac81SBjoern A. Zeeb lvif = VAP_TO_LVIF(vap); 1173*6b4cac81SBjoern A. Zeeb vif = LVIF_TO_VIF(lvif); 1174*6b4cac81SBjoern A. Zeeb 1175*6b4cac81SBjoern A. Zeeb IEEE80211_UNLOCK(vap->iv_ic); 1176*6b4cac81SBjoern A. Zeeb ni = NULL; 1177*6b4cac81SBjoern A. Zeeb 1178*6b4cac81SBjoern A. Zeeb IMPROVE("ponder some of this moved to ic_newassoc, scan_assoc_success, " 1179*6b4cac81SBjoern A. Zeeb "and to lesser extend ieee80211_notify_node_join"); 1180*6b4cac81SBjoern A. Zeeb 1181*6b4cac81SBjoern A. Zeeb /* Finish assoc. */ 1182*6b4cac81SBjoern A. Zeeb /* Update sta_state (AUTH to ASSOC) and set aid. */ 1183*6b4cac81SBjoern A. Zeeb ni = ieee80211_ref_node(vap->iv_bss); 1184*6b4cac81SBjoern A. Zeeb lsta = ni->ni_drv_data; 1185*6b4cac81SBjoern A. Zeeb KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni)); 1186*6b4cac81SBjoern A. Zeeb KASSERT(lsta->state == IEEE80211_STA_AUTH, ("%s: lsta %p state not " 1187*6b4cac81SBjoern A. Zeeb "AUTH: %#x\n", __func__, lsta, lsta->state)); 1188*6b4cac81SBjoern A. Zeeb sta = LSTA_TO_STA(lsta); 1189*6b4cac81SBjoern A. Zeeb sta->aid = IEEE80211_NODE_AID(ni); 1190*6b4cac81SBjoern A. Zeeb error = lkpi_80211_mo_sta_state(hw, vif, sta, IEEE80211_STA_ASSOC); 1191*6b4cac81SBjoern A. Zeeb if (error != 0) 1192*6b4cac81SBjoern A. Zeeb goto out; 1193*6b4cac81SBjoern A. Zeeb 1194*6b4cac81SBjoern A. Zeeb IMPROVE("wme / conf_tx [all]"); 1195*6b4cac81SBjoern A. Zeeb 1196*6b4cac81SBjoern A. Zeeb /* Update bss info (bss_info_changed) (assoc, aid, ..). */ 1197*6b4cac81SBjoern A. Zeeb bss_changed = 0; 1198*6b4cac81SBjoern A. Zeeb if (!vif->bss_conf.assoc || vif->bss_conf.aid != IEEE80211_NODE_AID(ni)) { 1199*6b4cac81SBjoern A. Zeeb vif->bss_conf.assoc = true; 1200*6b4cac81SBjoern A. Zeeb vif->bss_conf.aid = IEEE80211_NODE_AID(ni); 1201*6b4cac81SBjoern A. Zeeb bss_changed |= BSS_CHANGED_ASSOC; 1202*6b4cac81SBjoern A. Zeeb } 1203*6b4cac81SBjoern A. Zeeb /* We set SSID but this is not BSSID! */ 1204*6b4cac81SBjoern A. Zeeb vif->bss_conf.ssid_len = ni->ni_esslen; 1205*6b4cac81SBjoern A. Zeeb memcpy(vif->bss_conf.ssid, ni->ni_essid, ni->ni_esslen); 1206*6b4cac81SBjoern A. Zeeb if ((vap->iv_flags & IEEE80211_F_SHPREAMBLE) != 1207*6b4cac81SBjoern A. Zeeb vif->bss_conf.use_short_preamble) { 1208*6b4cac81SBjoern A. Zeeb vif->bss_conf.use_short_preamble ^= 1; 1209*6b4cac81SBjoern A. Zeeb /* bss_changed |= BSS_CHANGED_??? */ 1210*6b4cac81SBjoern A. Zeeb } 1211*6b4cac81SBjoern A. Zeeb if ((vap->iv_flags & IEEE80211_F_SHSLOT) != 1212*6b4cac81SBjoern A. Zeeb vif->bss_conf.use_short_slot) { 1213*6b4cac81SBjoern A. Zeeb vif->bss_conf.use_short_slot ^= 1; 1214*6b4cac81SBjoern A. Zeeb /* bss_changed |= BSS_CHANGED_??? */ 1215*6b4cac81SBjoern A. Zeeb } 1216*6b4cac81SBjoern A. Zeeb if ((ni->ni_flags & IEEE80211_NODE_QOS) != 1217*6b4cac81SBjoern A. Zeeb vif->bss_conf.qos) { 1218*6b4cac81SBjoern A. Zeeb vif->bss_conf.qos ^= 1; 1219*6b4cac81SBjoern A. Zeeb bss_changed |= BSS_CHANGED_QOS; 1220*6b4cac81SBjoern A. Zeeb } 1221*6b4cac81SBjoern A. Zeeb if (vif->bss_conf.beacon_int != ni->ni_intval) { 1222*6b4cac81SBjoern A. Zeeb vif->bss_conf.beacon_int = ni->ni_intval; 1223*6b4cac81SBjoern A. Zeeb /* iwlwifi FW bug workaround; iwl_mvm_mac_sta_state. */ 1224*6b4cac81SBjoern A. Zeeb if (vif->bss_conf.beacon_int < 16) 1225*6b4cac81SBjoern A. Zeeb vif->bss_conf.beacon_int = 16; 1226*6b4cac81SBjoern A. Zeeb bss_changed |= BSS_CHANGED_BEACON_INT; 1227*6b4cac81SBjoern A. Zeeb } 1228*6b4cac81SBjoern A. Zeeb if (vif->bss_conf.dtim_period != vap->iv_dtim_period && 1229*6b4cac81SBjoern A. Zeeb vap->iv_dtim_period > 0) { 1230*6b4cac81SBjoern A. Zeeb vif->bss_conf.dtim_period = vap->iv_dtim_period; 1231*6b4cac81SBjoern A. Zeeb bss_changed |= BSS_CHANGED_BEACON_INFO; 1232*6b4cac81SBjoern A. Zeeb } 1233*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, bss_changed); 1234*6b4cac81SBjoern A. Zeeb 1235*6b4cac81SBjoern A. Zeeb /* - change_chanctx (if needed) 1236*6b4cac81SBjoern A. Zeeb * - event_callback 1237*6b4cac81SBjoern A. Zeeb */ 1238*6b4cac81SBjoern A. Zeeb 1239*6b4cac81SBjoern A. Zeeb /* End mgd_complete_tx. */ 1240*6b4cac81SBjoern A. Zeeb if (lsta->in_mgd) { 1241*6b4cac81SBjoern A. Zeeb memset(&prep_tx_info, 0, sizeof(prep_tx_info)); 1242*6b4cac81SBjoern A. Zeeb prep_tx_info.success = true; 1243*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_mgd_complete_tx(hw, vif, &prep_tx_info); 1244*6b4cac81SBjoern A. Zeeb lsta->in_mgd = false; 1245*6b4cac81SBjoern A. Zeeb } 1246*6b4cac81SBjoern A. Zeeb 1247*6b4cac81SBjoern A. Zeeb /* 1248*6b4cac81SBjoern A. Zeeb * And then: 1249*6b4cac81SBjoern A. Zeeb * - (more packets)? 1250*6b4cac81SBjoern A. Zeeb * - set_key 1251*6b4cac81SBjoern A. Zeeb * - set_default_unicast_key 1252*6b4cac81SBjoern A. Zeeb * - set_key (?) 1253*6b4cac81SBjoern A. Zeeb * - ipv6_addr_change (?) 1254*6b4cac81SBjoern A. Zeeb */ 1255*6b4cac81SBjoern A. Zeeb /* Prepare_multicast && configure_filter. */ 1256*6b4cac81SBjoern A. Zeeb lhw->update_mc = true; 1257*6b4cac81SBjoern A. Zeeb lkpi_update_mcast_filter(vap->iv_ic, true); 1258*6b4cac81SBjoern A. Zeeb 1259*6b4cac81SBjoern A. Zeeb if (!ieee80211_node_is_authorized(ni)) { 1260*6b4cac81SBjoern A. Zeeb IMPROVE("net80211 does not consider node authorized"); 1261*6b4cac81SBjoern A. Zeeb } 1262*6b4cac81SBjoern A. Zeeb 1263*6b4cac81SBjoern A. Zeeb /* Update sta_state (ASSOC to AUTHORIZED). */ 1264*6b4cac81SBjoern A. Zeeb ni = ieee80211_ref_node(vap->iv_bss); 1265*6b4cac81SBjoern A. Zeeb lsta = ni->ni_drv_data; 1266*6b4cac81SBjoern A. Zeeb KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni)); 1267*6b4cac81SBjoern A. Zeeb KASSERT(lsta->state == IEEE80211_STA_ASSOC, ("%s: lsta %p state not " 1268*6b4cac81SBjoern A. Zeeb "ASSOC: %#x\n", __func__, lsta, lsta->state)); 1269*6b4cac81SBjoern A. Zeeb sta = LSTA_TO_STA(lsta); 1270*6b4cac81SBjoern A. Zeeb error = lkpi_80211_mo_sta_state(hw, vif, sta, IEEE80211_STA_AUTHORIZED); 1271*6b4cac81SBjoern A. Zeeb if (error != 0) { 1272*6b4cac81SBjoern A. Zeeb IMPROVE("undo some changes?"); 1273*6b4cac81SBjoern A. Zeeb goto out; 1274*6b4cac81SBjoern A. Zeeb } 1275*6b4cac81SBjoern A. Zeeb 1276*6b4cac81SBjoern A. Zeeb /* - drv_config (?) 1277*6b4cac81SBjoern A. Zeeb * - bss_info_changed 1278*6b4cac81SBjoern A. Zeeb * - set_rekey_data (?) 1279*6b4cac81SBjoern A. Zeeb * 1280*6b4cac81SBjoern A. Zeeb * And now we should be passing packets. 1281*6b4cac81SBjoern A. Zeeb */ 1282*6b4cac81SBjoern A. Zeeb IMPROVE("Need that bssid setting, and the keys"); 1283*6b4cac81SBjoern A. Zeeb 1284*6b4cac81SBjoern A. Zeeb out: 1285*6b4cac81SBjoern A. Zeeb IEEE80211_LOCK(vap->iv_ic); 1286*6b4cac81SBjoern A. Zeeb if (ni != NULL) 1287*6b4cac81SBjoern A. Zeeb ieee80211_free_node(ni); 1288*6b4cac81SBjoern A. Zeeb return (error); 1289*6b4cac81SBjoern A. Zeeb } 1290*6b4cac81SBjoern A. Zeeb 1291*6b4cac81SBjoern A. Zeeb static int 1292*6b4cac81SBjoern A. Zeeb lkpi_sta_auth_to_run(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 1293*6b4cac81SBjoern A. Zeeb { 1294*6b4cac81SBjoern A. Zeeb int error; 1295*6b4cac81SBjoern A. Zeeb 1296*6b4cac81SBjoern A. Zeeb error = lkpi_sta_auth_to_assoc(vap, nstate, arg); 1297*6b4cac81SBjoern A. Zeeb if (error == 0) 1298*6b4cac81SBjoern A. Zeeb error = lkpi_sta_assoc_to_run(vap, nstate, arg); 1299*6b4cac81SBjoern A. Zeeb return (error); 1300*6b4cac81SBjoern A. Zeeb } 1301*6b4cac81SBjoern A. Zeeb 1302*6b4cac81SBjoern A. Zeeb static int 1303*6b4cac81SBjoern A. Zeeb lkpi_sta_run_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 1304*6b4cac81SBjoern A. Zeeb { 1305*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 1306*6b4cac81SBjoern A. Zeeb struct ieee80211_hw *hw; 1307*6b4cac81SBjoern A. Zeeb struct lkpi_vif *lvif; 1308*6b4cac81SBjoern A. Zeeb struct ieee80211_vif *vif; 1309*6b4cac81SBjoern A. Zeeb struct ieee80211_node *ni; 1310*6b4cac81SBjoern A. Zeeb struct lkpi_sta *lsta; 1311*6b4cac81SBjoern A. Zeeb struct ieee80211_sta *sta; 1312*6b4cac81SBjoern A. Zeeb int error; 1313*6b4cac81SBjoern A. Zeeb 1314*6b4cac81SBjoern A. Zeeb lhw = vap->iv_ic->ic_softc; 1315*6b4cac81SBjoern A. Zeeb hw = LHW_TO_HW(lhw); 1316*6b4cac81SBjoern A. Zeeb lvif = VAP_TO_LVIF(vap); 1317*6b4cac81SBjoern A. Zeeb vif = LVIF_TO_VIF(lvif); 1318*6b4cac81SBjoern A. Zeeb 1319*6b4cac81SBjoern A. Zeeb /* Keep ni around. */ 1320*6b4cac81SBjoern A. Zeeb ni = ieee80211_ref_node(vap->iv_bss); 1321*6b4cac81SBjoern A. Zeeb 1322*6b4cac81SBjoern A. Zeeb IEEE80211_UNLOCK(vap->iv_ic); 1323*6b4cac81SBjoern A. Zeeb lsta = ni->ni_drv_data; 1324*6b4cac81SBjoern A. Zeeb sta = LSTA_TO_STA(lsta); 1325*6b4cac81SBjoern A. Zeeb 1326*6b4cac81SBjoern A. Zeeb /* Adjust sta and change state (from AUTHORIZED) to ASSOC. */ 1327*6b4cac81SBjoern A. Zeeb KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni)); 1328*6b4cac81SBjoern A. Zeeb KASSERT(lsta->state == IEEE80211_STA_AUTHORIZED, ("%s: lsta %p state not " 1329*6b4cac81SBjoern A. Zeeb "AUTHORIZED: %#x\n", __func__, lsta, lsta->state)); 1330*6b4cac81SBjoern A. Zeeb error = lkpi_80211_mo_sta_state(hw, vif, sta, IEEE80211_STA_ASSOC); 1331*6b4cac81SBjoern A. Zeeb if (error != 0) 1332*6b4cac81SBjoern A. Zeeb goto out; 1333*6b4cac81SBjoern A. Zeeb 1334*6b4cac81SBjoern A. Zeeb /* Update bss info (bss_info_changed) (assoc, aid, ..). */ 1335*6b4cac81SBjoern A. Zeeb lkpi_disassoc(sta, vif, lhw); 1336*6b4cac81SBjoern A. Zeeb 1337*6b4cac81SBjoern A. Zeeb /* Update sta_state (ASSOC to AUTH). */ 1338*6b4cac81SBjoern A. Zeeb KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni)); 1339*6b4cac81SBjoern A. Zeeb KASSERT(lsta->state == IEEE80211_STA_ASSOC, ("%s: lsta %p state not " 1340*6b4cac81SBjoern A. Zeeb "ASSOC: %#x\n", __func__, lsta, lsta->state)); 1341*6b4cac81SBjoern A. Zeeb sta = LSTA_TO_STA(lsta); 1342*6b4cac81SBjoern A. Zeeb sta->aid = 0; 1343*6b4cac81SBjoern A. Zeeb error = lkpi_80211_mo_sta_state(hw, vif, sta, IEEE80211_STA_AUTH); 1344*6b4cac81SBjoern A. Zeeb if (error != 0) 1345*6b4cac81SBjoern A. Zeeb goto out; 1346*6b4cac81SBjoern A. Zeeb 1347*6b4cac81SBjoern A. Zeeb IMPROVE("if ASSOC is final state, prep_tx_info?"); 1348*6b4cac81SBjoern A. Zeeb 1349*6b4cac81SBjoern A. Zeeb out: 1350*6b4cac81SBjoern A. Zeeb IEEE80211_LOCK(vap->iv_ic); 1351*6b4cac81SBjoern A. Zeeb if (ni != NULL) 1352*6b4cac81SBjoern A. Zeeb ieee80211_free_node(ni); 1353*6b4cac81SBjoern A. Zeeb return (error); 1354*6b4cac81SBjoern A. Zeeb } 1355*6b4cac81SBjoern A. Zeeb 1356*6b4cac81SBjoern A. Zeeb static int 1357*6b4cac81SBjoern A. Zeeb lkpi_sta_run_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 1358*6b4cac81SBjoern A. Zeeb { 1359*6b4cac81SBjoern A. Zeeb int error; 1360*6b4cac81SBjoern A. Zeeb 1361*6b4cac81SBjoern A. Zeeb error = lkpi_sta_run_to_assoc(vap, nstate, arg); 1362*6b4cac81SBjoern A. Zeeb if (error == 0) 1363*6b4cac81SBjoern A. Zeeb error = lkpi_sta_assoc_to_auth(vap, nstate, arg); 1364*6b4cac81SBjoern A. Zeeb return (error); 1365*6b4cac81SBjoern A. Zeeb } 1366*6b4cac81SBjoern A. Zeeb 1367*6b4cac81SBjoern A. Zeeb static int 1368*6b4cac81SBjoern A. Zeeb lkpi_sta_run_to_scan(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 1369*6b4cac81SBjoern A. Zeeb { 1370*6b4cac81SBjoern A. Zeeb int error; 1371*6b4cac81SBjoern A. Zeeb 1372*6b4cac81SBjoern A. Zeeb error = lkpi_sta_run_to_auth(vap, nstate, arg); 1373*6b4cac81SBjoern A. Zeeb if (error == 0) 1374*6b4cac81SBjoern A. Zeeb error = lkpi_sta_auth_to_scan(vap, nstate, arg); 1375*6b4cac81SBjoern A. Zeeb return (error); 1376*6b4cac81SBjoern A. Zeeb } 1377*6b4cac81SBjoern A. Zeeb 1378*6b4cac81SBjoern A. Zeeb static int 1379*6b4cac81SBjoern A. Zeeb lkpi_sta_run_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 1380*6b4cac81SBjoern A. Zeeb { 1381*6b4cac81SBjoern A. Zeeb int error; 1382*6b4cac81SBjoern A. Zeeb 1383*6b4cac81SBjoern A. Zeeb error = lkpi_sta_run_to_scan(vap, nstate, arg); 1384*6b4cac81SBjoern A. Zeeb if (error == 0) 1385*6b4cac81SBjoern A. Zeeb error = lkpi_sta_scan_to_init(vap, nstate, arg); 1386*6b4cac81SBjoern A. Zeeb return (error); 1387*6b4cac81SBjoern A. Zeeb } 1388*6b4cac81SBjoern A. Zeeb 1389*6b4cac81SBjoern A. Zeeb /* 1390*6b4cac81SBjoern A. Zeeb * The matches the documented state changes in net80211::sta_newstate(). 1391*6b4cac81SBjoern A. Zeeb * XXX (1) without CSA and SLEEP yet, * XXX (2) not all unhandled cases 1392*6b4cac81SBjoern A. Zeeb * there are "invalid" (so there is a room for failure here). 1393*6b4cac81SBjoern A. Zeeb */ 1394*6b4cac81SBjoern A. Zeeb struct fsm_state { 1395*6b4cac81SBjoern A. Zeeb /* INIT, SCAN, AUTH, ASSOC, CAC, RUN, CSA, SLEEP */ 1396*6b4cac81SBjoern A. Zeeb enum ieee80211_state ostate; 1397*6b4cac81SBjoern A. Zeeb enum ieee80211_state nstate; 1398*6b4cac81SBjoern A. Zeeb int (*handler)(struct ieee80211vap *, enum ieee80211_state, int); 1399*6b4cac81SBjoern A. Zeeb } sta_state_fsm[] = { 1400*6b4cac81SBjoern A. Zeeb { IEEE80211_S_INIT, IEEE80211_S_INIT, lkpi_sta_state_do_nada }, 1401*6b4cac81SBjoern A. Zeeb { IEEE80211_S_SCAN, IEEE80211_S_INIT, lkpi_sta_state_do_nada }, /* scan_to_init */ 1402*6b4cac81SBjoern A. Zeeb { IEEE80211_S_AUTH, IEEE80211_S_INIT, lkpi_sta_auth_to_init }, /* not explicitly in sta_newstate() */ 1403*6b4cac81SBjoern A. Zeeb { IEEE80211_S_ASSOC, IEEE80211_S_INIT, lkpi_sta_assoc_to_init }, 1404*6b4cac81SBjoern A. Zeeb { IEEE80211_S_RUN, IEEE80211_S_INIT, lkpi_sta_run_to_init }, 1405*6b4cac81SBjoern A. Zeeb 1406*6b4cac81SBjoern A. Zeeb { IEEE80211_S_INIT, IEEE80211_S_SCAN, lkpi_sta_state_do_nada }, 1407*6b4cac81SBjoern A. Zeeb { IEEE80211_S_SCAN, IEEE80211_S_SCAN, lkpi_sta_state_do_nada }, 1408*6b4cac81SBjoern A. Zeeb { IEEE80211_S_AUTH, IEEE80211_S_SCAN, lkpi_sta_auth_to_scan }, 1409*6b4cac81SBjoern A. Zeeb { IEEE80211_S_ASSOC, IEEE80211_S_SCAN, lkpi_sta_assoc_to_scan }, 1410*6b4cac81SBjoern A. Zeeb { IEEE80211_S_RUN, IEEE80211_S_SCAN, lkpi_sta_run_to_scan }, 1411*6b4cac81SBjoern A. Zeeb 1412*6b4cac81SBjoern A. Zeeb { IEEE80211_S_INIT, IEEE80211_S_AUTH, lkpi_sta_scan_to_auth }, 1413*6b4cac81SBjoern A. Zeeb { IEEE80211_S_SCAN, IEEE80211_S_AUTH, lkpi_sta_scan_to_auth }, 1414*6b4cac81SBjoern A. Zeeb { IEEE80211_S_AUTH, IEEE80211_S_AUTH, lkpi_sta_a_to_a }, 1415*6b4cac81SBjoern A. Zeeb { IEEE80211_S_ASSOC, IEEE80211_S_AUTH, lkpi_sta_assoc_to_auth }, 1416*6b4cac81SBjoern A. Zeeb { IEEE80211_S_RUN, IEEE80211_S_AUTH, lkpi_sta_run_to_auth }, 1417*6b4cac81SBjoern A. Zeeb 1418*6b4cac81SBjoern A. Zeeb { IEEE80211_S_AUTH, IEEE80211_S_ASSOC, lkpi_sta_auth_to_assoc }, 1419*6b4cac81SBjoern A. Zeeb { IEEE80211_S_ASSOC, IEEE80211_S_ASSOC, lkpi_sta_a_to_a }, 1420*6b4cac81SBjoern A. Zeeb { IEEE80211_S_RUN, IEEE80211_S_ASSOC, lkpi_sta_run_to_assoc }, 1421*6b4cac81SBjoern A. Zeeb 1422*6b4cac81SBjoern A. Zeeb { IEEE80211_S_AUTH, IEEE80211_S_RUN, lkpi_sta_auth_to_run }, 1423*6b4cac81SBjoern A. Zeeb { IEEE80211_S_ASSOC, IEEE80211_S_RUN, lkpi_sta_assoc_to_run }, 1424*6b4cac81SBjoern A. Zeeb { IEEE80211_S_RUN, IEEE80211_S_RUN, lkpi_sta_state_do_nada }, 1425*6b4cac81SBjoern A. Zeeb 1426*6b4cac81SBjoern A. Zeeb /* Dummy at the end without handler. */ 1427*6b4cac81SBjoern A. Zeeb { IEEE80211_S_INIT, IEEE80211_S_INIT, NULL }, 1428*6b4cac81SBjoern A. Zeeb }; 1429*6b4cac81SBjoern A. Zeeb 1430*6b4cac81SBjoern A. Zeeb static int 1431*6b4cac81SBjoern A. Zeeb lkpi_iv_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 1432*6b4cac81SBjoern A. Zeeb { 1433*6b4cac81SBjoern A. Zeeb struct ieee80211com *ic; 1434*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 1435*6b4cac81SBjoern A. Zeeb struct lkpi_vif *lvif; 1436*6b4cac81SBjoern A. Zeeb struct ieee80211_vif *vif; 1437*6b4cac81SBjoern A. Zeeb struct fsm_state *s; 1438*6b4cac81SBjoern A. Zeeb enum ieee80211_state ostate; 1439*6b4cac81SBjoern A. Zeeb int error; 1440*6b4cac81SBjoern A. Zeeb 1441*6b4cac81SBjoern A. Zeeb ic = vap->iv_ic; 1442*6b4cac81SBjoern A. Zeeb IEEE80211_LOCK_ASSERT(ic); 1443*6b4cac81SBjoern A. Zeeb ostate = vap->iv_state; 1444*6b4cac81SBjoern A. Zeeb 1445*6b4cac81SBjoern A. Zeeb if (debug_80211 & D80211_TRACE) 1446*6b4cac81SBjoern A. Zeeb ic_printf(vap->iv_ic, "%s:%d: vap %p nstate %#x arg %#x\n", 1447*6b4cac81SBjoern A. Zeeb __func__, __LINE__, vap, nstate, arg); 1448*6b4cac81SBjoern A. Zeeb 1449*6b4cac81SBjoern A. Zeeb if (vap->iv_opmode == IEEE80211_M_STA) { 1450*6b4cac81SBjoern A. Zeeb 1451*6b4cac81SBjoern A. Zeeb lhw = ic->ic_softc; 1452*6b4cac81SBjoern A. Zeeb lvif = VAP_TO_LVIF(vap); 1453*6b4cac81SBjoern A. Zeeb vif = LVIF_TO_VIF(lvif); 1454*6b4cac81SBjoern A. Zeeb 1455*6b4cac81SBjoern A. Zeeb /* No need to replicate this in most state handlers. */ 1456*6b4cac81SBjoern A. Zeeb if (ostate == IEEE80211_S_SCAN && nstate != IEEE80211_S_SCAN) 1457*6b4cac81SBjoern A. Zeeb lkpi_stop_hw_scan(lhw, vif); 1458*6b4cac81SBjoern A. Zeeb 1459*6b4cac81SBjoern A. Zeeb s = sta_state_fsm; 1460*6b4cac81SBjoern A. Zeeb 1461*6b4cac81SBjoern A. Zeeb } else { 1462*6b4cac81SBjoern A. Zeeb ic_printf(vap->iv_ic, "%s: only station mode currently supported: " 1463*6b4cac81SBjoern A. Zeeb "cap %p iv_opmode %d\n", __func__, vap, vap->iv_opmode); 1464*6b4cac81SBjoern A. Zeeb return (ENOSYS); 1465*6b4cac81SBjoern A. Zeeb } 1466*6b4cac81SBjoern A. Zeeb 1467*6b4cac81SBjoern A. Zeeb error = 0; 1468*6b4cac81SBjoern A. Zeeb for (; s->handler != NULL; s++) { 1469*6b4cac81SBjoern A. Zeeb if (ostate == s->ostate && nstate == s->nstate) { 1470*6b4cac81SBjoern A. Zeeb error = s->handler(vap, nstate, arg); 1471*6b4cac81SBjoern A. Zeeb break; 1472*6b4cac81SBjoern A. Zeeb } 1473*6b4cac81SBjoern A. Zeeb } 1474*6b4cac81SBjoern A. Zeeb IEEE80211_LOCK_ASSERT(vap->iv_ic); 1475*6b4cac81SBjoern A. Zeeb 1476*6b4cac81SBjoern A. Zeeb if (s->handler == NULL) { 1477*6b4cac81SBjoern A. Zeeb IMPROVE("thurn this into a KASSERT\n"); 1478*6b4cac81SBjoern A. Zeeb ic_printf(vap->iv_ic, "%s: unsupported state transition " 1479*6b4cac81SBjoern A. Zeeb "%d (%s) -> %d (%s)\n", __func__, 1480*6b4cac81SBjoern A. Zeeb ostate, ieee80211_state_name[ostate], 1481*6b4cac81SBjoern A. Zeeb nstate, ieee80211_state_name[nstate]); 1482*6b4cac81SBjoern A. Zeeb return (ENOSYS); 1483*6b4cac81SBjoern A. Zeeb } 1484*6b4cac81SBjoern A. Zeeb 1485*6b4cac81SBjoern A. Zeeb if (error == EALREADY) { 1486*6b4cac81SBjoern A. Zeeb IMPROVE("make this a debug log later"); 1487*6b4cac81SBjoern A. Zeeb ic_printf(vap->iv_ic, "%s: error %d during state transition " 1488*6b4cac81SBjoern A. Zeeb "%d (%s) -> %d (%s): iv_newstate already handled.\n", 1489*6b4cac81SBjoern A. Zeeb __func__, error, 1490*6b4cac81SBjoern A. Zeeb ostate, ieee80211_state_name[ostate], 1491*6b4cac81SBjoern A. Zeeb nstate, ieee80211_state_name[nstate]); 1492*6b4cac81SBjoern A. Zeeb return (0); 1493*6b4cac81SBjoern A. Zeeb } 1494*6b4cac81SBjoern A. Zeeb 1495*6b4cac81SBjoern A. Zeeb if (error != 0) { 1496*6b4cac81SBjoern A. Zeeb /* XXX-BZ currently expected so ignore. */ 1497*6b4cac81SBjoern A. Zeeb ic_printf(vap->iv_ic, "%s: error %d during state transition " 1498*6b4cac81SBjoern A. Zeeb "%d (%s) -> %d (%s)\n", __func__, error, 1499*6b4cac81SBjoern A. Zeeb ostate, ieee80211_state_name[ostate], 1500*6b4cac81SBjoern A. Zeeb nstate, ieee80211_state_name[nstate]); 1501*6b4cac81SBjoern A. Zeeb /* return (error); */ 1502*6b4cac81SBjoern A. Zeeb } 1503*6b4cac81SBjoern A. Zeeb 1504*6b4cac81SBjoern A. Zeeb if (debug_80211 & D80211_TRACE) 1505*6b4cac81SBjoern A. Zeeb ic_printf(vap->iv_ic, "%s:%d: vap %p nstate %#x arg %#x calling net80211 parent\n", 1506*6b4cac81SBjoern A. Zeeb __func__, __LINE__, vap, nstate, arg); 1507*6b4cac81SBjoern A. Zeeb 1508*6b4cac81SBjoern A. Zeeb return (lvif->iv_newstate(vap, nstate, arg)); 1509*6b4cac81SBjoern A. Zeeb } 1510*6b4cac81SBjoern A. Zeeb 1511*6b4cac81SBjoern A. Zeeb /* -------------------------------------------------------------------------- */ 1512*6b4cac81SBjoern A. Zeeb 1513*6b4cac81SBjoern A. Zeeb static int 1514*6b4cac81SBjoern A. Zeeb lkpi_ic_wme_update(struct ieee80211com *ic) 1515*6b4cac81SBjoern A. Zeeb { 1516*6b4cac81SBjoern A. Zeeb /* This needs queuing and go at the right moment. */ 1517*6b4cac81SBjoern A. Zeeb #ifdef WITH_WME_UPDATE 1518*6b4cac81SBjoern A. Zeeb struct ieee80211vap *vap; 1519*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 1520*6b4cac81SBjoern A. Zeeb struct ieee80211_hw *hw; 1521*6b4cac81SBjoern A. Zeeb struct lkpi_vif *lvif; 1522*6b4cac81SBjoern A. Zeeb struct ieee80211_vif *vif; 1523*6b4cac81SBjoern A. Zeeb struct chanAccParams chp; 1524*6b4cac81SBjoern A. Zeeb struct wmeParams wmeparr[WME_NUM_AC]; 1525*6b4cac81SBjoern A. Zeeb struct ieee80211_tx_queue_params txqp; 1526*6b4cac81SBjoern A. Zeeb enum ieee80211_bss_changed changed; 1527*6b4cac81SBjoern A. Zeeb int error; 1528*6b4cac81SBjoern A. Zeeb uint16_t ac; 1529*6b4cac81SBjoern A. Zeeb #endif 1530*6b4cac81SBjoern A. Zeeb 1531*6b4cac81SBjoern A. Zeeb IMPROVE(); 1532*6b4cac81SBjoern A. Zeeb KASSERT(WME_NUM_AC == IEEE80211_NUM_ACS, ("%s: WME_NUM_AC %d != " 1533*6b4cac81SBjoern A. Zeeb "IEEE80211_NUM_ACS %d\n", __func__, WME_NUM_AC, IEEE80211_NUM_ACS)); 1534*6b4cac81SBjoern A. Zeeb 1535*6b4cac81SBjoern A. Zeeb #ifdef WITH_WME_UPDATE 1536*6b4cac81SBjoern A. Zeeb vap = TAILQ_FIRST(&ic->ic_vaps); 1537*6b4cac81SBjoern A. Zeeb if (vap == NULL) 1538*6b4cac81SBjoern A. Zeeb return (0); 1539*6b4cac81SBjoern A. Zeeb 1540*6b4cac81SBjoern A. Zeeb /* We should factor this out into per-vap (*wme_update). */ 1541*6b4cac81SBjoern A. Zeeb lhw = ic->ic_softc; 1542*6b4cac81SBjoern A. Zeeb if (lhw->ops->conf_tx == NULL) 1543*6b4cac81SBjoern A. Zeeb return (0); 1544*6b4cac81SBjoern A. Zeeb 1545*6b4cac81SBjoern A. Zeeb /* XXX-BZ check amount of hw queues */ 1546*6b4cac81SBjoern A. Zeeb hw = LHW_TO_HW(lhw); 1547*6b4cac81SBjoern A. Zeeb lvif = VAP_TO_LVIF(vap); 1548*6b4cac81SBjoern A. Zeeb vif = LVIF_TO_VIF(lvif); 1549*6b4cac81SBjoern A. Zeeb 1550*6b4cac81SBjoern A. Zeeb ieee80211_wme_ic_getparams(ic, &chp); 1551*6b4cac81SBjoern A. Zeeb IEEE80211_LOCK(ic); 1552*6b4cac81SBjoern A. Zeeb for (ac = 0; ac < WME_NUM_AC; ac++) 1553*6b4cac81SBjoern A. Zeeb wmeparr[ac] = chp.cap_wmeParams[ac]; 1554*6b4cac81SBjoern A. Zeeb IEEE80211_UNLOCK(ic); 1555*6b4cac81SBjoern A. Zeeb 1556*6b4cac81SBjoern A. Zeeb /* Configure tx queues (conf_tx) & send BSS_CHANGED_QOS. */ 1557*6b4cac81SBjoern A. Zeeb LKPI_80211_LHW_LOCK(lhw); 1558*6b4cac81SBjoern A. Zeeb for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { 1559*6b4cac81SBjoern A. Zeeb struct wmeParams *wmep; 1560*6b4cac81SBjoern A. Zeeb 1561*6b4cac81SBjoern A. Zeeb /* XXX-BZ should keep this in lvif? */ 1562*6b4cac81SBjoern A. Zeeb wmep = &wmeparr[ac]; 1563*6b4cac81SBjoern A. Zeeb bzero(&txqp, sizeof(txqp)); 1564*6b4cac81SBjoern A. Zeeb txqp.cw_min = wmep->wmep_logcwmin; 1565*6b4cac81SBjoern A. Zeeb txqp.cw_max = wmep->wmep_logcwmax; 1566*6b4cac81SBjoern A. Zeeb txqp.txop = wmep->wmep_txopLimit; 1567*6b4cac81SBjoern A. Zeeb txqp.aifs = wmep->wmep_aifsn; 1568*6b4cac81SBjoern A. Zeeb error = lkpi_80211_mo_conf_tx(hw, vif, ac, &txqp); 1569*6b4cac81SBjoern A. Zeeb if (error != 0) 1570*6b4cac81SBjoern A. Zeeb printf("%s: conf_tx ac %u failed %d\n", 1571*6b4cac81SBjoern A. Zeeb __func__, ac, error); 1572*6b4cac81SBjoern A. Zeeb } 1573*6b4cac81SBjoern A. Zeeb LKPI_80211_LHW_UNLOCK(lhw); 1574*6b4cac81SBjoern A. Zeeb changed = BSS_CHANGED_QOS; 1575*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, changed); 1576*6b4cac81SBjoern A. Zeeb #endif 1577*6b4cac81SBjoern A. Zeeb 1578*6b4cac81SBjoern A. Zeeb return (0); 1579*6b4cac81SBjoern A. Zeeb } 1580*6b4cac81SBjoern A. Zeeb 1581*6b4cac81SBjoern A. Zeeb static struct ieee80211vap * 1582*6b4cac81SBjoern A. Zeeb lkpi_ic_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], 1583*6b4cac81SBjoern A. Zeeb int unit, enum ieee80211_opmode opmode, int flags, 1584*6b4cac81SBjoern A. Zeeb const uint8_t bssid[IEEE80211_ADDR_LEN], 1585*6b4cac81SBjoern A. Zeeb const uint8_t mac[IEEE80211_ADDR_LEN]) 1586*6b4cac81SBjoern A. Zeeb { 1587*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 1588*6b4cac81SBjoern A. Zeeb struct ieee80211_hw *hw; 1589*6b4cac81SBjoern A. Zeeb struct lkpi_vif *lvif; 1590*6b4cac81SBjoern A. Zeeb struct ieee80211vap *vap; 1591*6b4cac81SBjoern A. Zeeb struct ieee80211_vif *vif; 1592*6b4cac81SBjoern A. Zeeb enum ieee80211_bss_changed changed; 1593*6b4cac81SBjoern A. Zeeb size_t len; 1594*6b4cac81SBjoern A. Zeeb int error; 1595*6b4cac81SBjoern A. Zeeb 1596*6b4cac81SBjoern A. Zeeb if (!TAILQ_EMPTY(&ic->ic_vaps)) /* 1 so far. Add <n> once this works. */ 1597*6b4cac81SBjoern A. Zeeb return (NULL); 1598*6b4cac81SBjoern A. Zeeb 1599*6b4cac81SBjoern A. Zeeb lhw = ic->ic_softc; 1600*6b4cac81SBjoern A. Zeeb hw = LHW_TO_HW(lhw); 1601*6b4cac81SBjoern A. Zeeb 1602*6b4cac81SBjoern A. Zeeb len = sizeof(*lvif); 1603*6b4cac81SBjoern A. Zeeb len += hw->vif_data_size; /* vif->drv_priv */ 1604*6b4cac81SBjoern A. Zeeb 1605*6b4cac81SBjoern A. Zeeb lvif = malloc(len, M_80211_VAP, M_WAITOK | M_ZERO); 1606*6b4cac81SBjoern A. Zeeb mtx_init(&lvif->mtx, "lvif", NULL, MTX_DEF); 1607*6b4cac81SBjoern A. Zeeb TAILQ_INIT(&lvif->lsta_head); 1608*6b4cac81SBjoern A. Zeeb vap = LVIF_TO_VAP(lvif); 1609*6b4cac81SBjoern A. Zeeb 1610*6b4cac81SBjoern A. Zeeb vif = LVIF_TO_VIF(lvif); 1611*6b4cac81SBjoern A. Zeeb memcpy(vif->addr, mac, IEEE80211_ADDR_LEN); 1612*6b4cac81SBjoern A. Zeeb vif->p2p = false; 1613*6b4cac81SBjoern A. Zeeb vif->probe_req_reg = false; 1614*6b4cac81SBjoern A. Zeeb vif->type = lkpi_opmode_to_vif_type(opmode); 1615*6b4cac81SBjoern A. Zeeb lvif->wdev.iftype = vif->type; 1616*6b4cac81SBjoern A. Zeeb /* Need to fill in other fields as well. */ 1617*6b4cac81SBjoern A. Zeeb IMPROVE(); 1618*6b4cac81SBjoern A. Zeeb 1619*6b4cac81SBjoern A. Zeeb /* XXX-BZ hardcoded for now! */ 1620*6b4cac81SBjoern A. Zeeb #if 1 1621*6b4cac81SBjoern A. Zeeb vif->chanctx_conf = NULL; 1622*6b4cac81SBjoern A. Zeeb vif->bss_conf.idle = true; 1623*6b4cac81SBjoern A. Zeeb vif->bss_conf.ps = false; 1624*6b4cac81SBjoern A. Zeeb vif->bss_conf.chandef.width = NL80211_CHAN_WIDTH_20_NOHT; 1625*6b4cac81SBjoern A. Zeeb vif->bss_conf.use_short_preamble = false; /* vap->iv_flags IEEE80211_F_SHPREAMBLE */ 1626*6b4cac81SBjoern A. Zeeb vif->bss_conf.use_short_slot = false; /* vap->iv_flags IEEE80211_F_SHSLOT */ 1627*6b4cac81SBjoern A. Zeeb vif->bss_conf.qos = false; 1628*6b4cac81SBjoern A. Zeeb vif->bss_conf.use_cts_prot = false; /* vap->iv_protmode */ 1629*6b4cac81SBjoern A. Zeeb vif->bss_conf.ht_operation_mode = IEEE80211_HT_OP_MODE_PROTECTION_NONE; 1630*6b4cac81SBjoern A. Zeeb vif->bss_conf.assoc = false; 1631*6b4cac81SBjoern A. Zeeb vif->bss_conf.aid = 0; 1632*6b4cac81SBjoern A. Zeeb #endif 1633*6b4cac81SBjoern A. Zeeb #if 0 1634*6b4cac81SBjoern A. Zeeb vif->bss_conf.dtim_period = 0; /* IEEE80211_DTIM_DEFAULT ; must stay 0. */ 1635*6b4cac81SBjoern A. Zeeb IEEE80211_ADDR_COPY(vif->bss_conf.bssid, bssid); 1636*6b4cac81SBjoern A. Zeeb vif->bss_conf.beacon_int = ic->ic_bintval; 1637*6b4cac81SBjoern A. Zeeb /* iwlwifi bug. */ 1638*6b4cac81SBjoern A. Zeeb if (vif->bss_conf.beacon_int < 16) 1639*6b4cac81SBjoern A. Zeeb vif->bss_conf.beacon_int = 16; 1640*6b4cac81SBjoern A. Zeeb #endif 1641*6b4cac81SBjoern A. Zeeb IMPROVE(); 1642*6b4cac81SBjoern A. Zeeb 1643*6b4cac81SBjoern A. Zeeb error = lkpi_80211_mo_start(hw); 1644*6b4cac81SBjoern A. Zeeb if (error != 0) { 1645*6b4cac81SBjoern A. Zeeb printf("%s: failed to start hw: %d\n", __func__, error); 1646*6b4cac81SBjoern A. Zeeb mtx_destroy(&lvif->mtx); 1647*6b4cac81SBjoern A. Zeeb free(lvif, M_80211_VAP); 1648*6b4cac81SBjoern A. Zeeb return (NULL); 1649*6b4cac81SBjoern A. Zeeb } 1650*6b4cac81SBjoern A. Zeeb 1651*6b4cac81SBjoern A. Zeeb error = lkpi_80211_mo_add_interface(hw, vif); 1652*6b4cac81SBjoern A. Zeeb if (error != 0) { 1653*6b4cac81SBjoern A. Zeeb IMPROVE(); /* XXX-BZ mo_stop()? */ 1654*6b4cac81SBjoern A. Zeeb printf("%s: failed to add interface: %d\n", __func__, error); 1655*6b4cac81SBjoern A. Zeeb mtx_destroy(&lvif->mtx); 1656*6b4cac81SBjoern A. Zeeb free(lvif, M_80211_VAP); 1657*6b4cac81SBjoern A. Zeeb return (NULL); 1658*6b4cac81SBjoern A. Zeeb } 1659*6b4cac81SBjoern A. Zeeb 1660*6b4cac81SBjoern A. Zeeb LKPI_80211_LHW_LOCK(lhw); 1661*6b4cac81SBjoern A. Zeeb TAILQ_INSERT_TAIL(&lhw->lvif_head, lvif, lvif_entry); 1662*6b4cac81SBjoern A. Zeeb LKPI_80211_LHW_UNLOCK(lhw); 1663*6b4cac81SBjoern A. Zeeb 1664*6b4cac81SBjoern A. Zeeb /* Set bss_info. */ 1665*6b4cac81SBjoern A. Zeeb changed = 0; 1666*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, changed); 1667*6b4cac81SBjoern A. Zeeb 1668*6b4cac81SBjoern A. Zeeb /* conf_tx setup; default WME? */ 1669*6b4cac81SBjoern A. Zeeb 1670*6b4cac81SBjoern A. Zeeb /* Force MC init. */ 1671*6b4cac81SBjoern A. Zeeb lkpi_update_mcast_filter(ic, true); 1672*6b4cac81SBjoern A. Zeeb 1673*6b4cac81SBjoern A. Zeeb IMPROVE(); 1674*6b4cac81SBjoern A. Zeeb 1675*6b4cac81SBjoern A. Zeeb ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid); 1676*6b4cac81SBjoern A. Zeeb 1677*6b4cac81SBjoern A. Zeeb /* Override with LinuxKPI method so we can drive mac80211/cfg80211. */ 1678*6b4cac81SBjoern A. Zeeb lvif->iv_newstate = vap->iv_newstate; 1679*6b4cac81SBjoern A. Zeeb vap->iv_newstate = lkpi_iv_newstate; 1680*6b4cac81SBjoern A. Zeeb 1681*6b4cac81SBjoern A. Zeeb /* Key management. */ 1682*6b4cac81SBjoern A. Zeeb if (lhw->ops->set_key != NULL) { 1683*6b4cac81SBjoern A. Zeeb #ifdef TRY_HW_CRYPTO 1684*6b4cac81SBjoern A. Zeeb vap->iv_key_set = lkpi_iv_key_set; 1685*6b4cac81SBjoern A. Zeeb vap->iv_key_delete = lkpi_iv_key_delete; 1686*6b4cac81SBjoern A. Zeeb #endif 1687*6b4cac81SBjoern A. Zeeb } 1688*6b4cac81SBjoern A. Zeeb 1689*6b4cac81SBjoern A. Zeeb ieee80211_ratectl_init(vap); 1690*6b4cac81SBjoern A. Zeeb 1691*6b4cac81SBjoern A. Zeeb /* Complete setup. */ 1692*6b4cac81SBjoern A. Zeeb ieee80211_vap_attach(vap, ieee80211_media_change, 1693*6b4cac81SBjoern A. Zeeb ieee80211_media_status, mac); 1694*6b4cac81SBjoern A. Zeeb 1695*6b4cac81SBjoern A. Zeeb if (hw->max_listen_interval == 0) 1696*6b4cac81SBjoern A. Zeeb hw->max_listen_interval = 7 * (ic->ic_lintval / ic->ic_bintval); 1697*6b4cac81SBjoern A. Zeeb hw->conf.listen_interval = hw->max_listen_interval; 1698*6b4cac81SBjoern A. Zeeb ic->ic_set_channel(ic); 1699*6b4cac81SBjoern A. Zeeb 1700*6b4cac81SBjoern A. Zeeb /* XXX-BZ do we need to be able to update these? */ 1701*6b4cac81SBjoern A. Zeeb hw->wiphy->frag_threshold = vap->iv_fragthreshold; 1702*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_set_frag_threshold(hw, vap->iv_fragthreshold); 1703*6b4cac81SBjoern A. Zeeb hw->wiphy->rts_threshold = vap->iv_rtsthreshold; 1704*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_set_rts_threshold(hw, vap->iv_rtsthreshold); 1705*6b4cac81SBjoern A. Zeeb /* any others? */ 1706*6b4cac81SBjoern A. Zeeb IMPROVE(); 1707*6b4cac81SBjoern A. Zeeb 1708*6b4cac81SBjoern A. Zeeb return (vap); 1709*6b4cac81SBjoern A. Zeeb } 1710*6b4cac81SBjoern A. Zeeb 1711*6b4cac81SBjoern A. Zeeb static void 1712*6b4cac81SBjoern A. Zeeb lkpi_ic_vap_delete(struct ieee80211vap *vap) 1713*6b4cac81SBjoern A. Zeeb { 1714*6b4cac81SBjoern A. Zeeb struct ieee80211com *ic; 1715*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 1716*6b4cac81SBjoern A. Zeeb struct ieee80211_hw *hw; 1717*6b4cac81SBjoern A. Zeeb struct lkpi_vif *lvif; 1718*6b4cac81SBjoern A. Zeeb struct ieee80211_vif *vif; 1719*6b4cac81SBjoern A. Zeeb 1720*6b4cac81SBjoern A. Zeeb lvif = VAP_TO_LVIF(vap); 1721*6b4cac81SBjoern A. Zeeb vif = LVIF_TO_VIF(lvif); 1722*6b4cac81SBjoern A. Zeeb ic = vap->iv_ic; 1723*6b4cac81SBjoern A. Zeeb lhw = ic->ic_softc; 1724*6b4cac81SBjoern A. Zeeb hw = LHW_TO_HW(lhw); 1725*6b4cac81SBjoern A. Zeeb 1726*6b4cac81SBjoern A. Zeeb LKPI_80211_LHW_LOCK(lhw); 1727*6b4cac81SBjoern A. Zeeb TAILQ_REMOVE(&lhw->lvif_head, lvif, lvif_entry); 1728*6b4cac81SBjoern A. Zeeb LKPI_80211_LHW_UNLOCK(lhw); 1729*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_remove_interface(hw, vif); 1730*6b4cac81SBjoern A. Zeeb 1731*6b4cac81SBjoern A. Zeeb ieee80211_ratectl_deinit(vap); 1732*6b4cac81SBjoern A. Zeeb ieee80211_vap_detach(vap); 1733*6b4cac81SBjoern A. Zeeb mtx_destroy(&lvif->mtx); 1734*6b4cac81SBjoern A. Zeeb free(lvif, M_80211_VAP); 1735*6b4cac81SBjoern A. Zeeb } 1736*6b4cac81SBjoern A. Zeeb 1737*6b4cac81SBjoern A. Zeeb static void 1738*6b4cac81SBjoern A. Zeeb lkpi_ic_update_mcast(struct ieee80211com *ic) 1739*6b4cac81SBjoern A. Zeeb { 1740*6b4cac81SBjoern A. Zeeb 1741*6b4cac81SBjoern A. Zeeb lkpi_update_mcast_filter(ic, false); 1742*6b4cac81SBjoern A. Zeeb TRACEOK(); 1743*6b4cac81SBjoern A. Zeeb } 1744*6b4cac81SBjoern A. Zeeb 1745*6b4cac81SBjoern A. Zeeb static void 1746*6b4cac81SBjoern A. Zeeb lkpi_ic_update_promisc(struct ieee80211com *ic) 1747*6b4cac81SBjoern A. Zeeb { 1748*6b4cac81SBjoern A. Zeeb 1749*6b4cac81SBjoern A. Zeeb UNIMPLEMENTED; 1750*6b4cac81SBjoern A. Zeeb } 1751*6b4cac81SBjoern A. Zeeb 1752*6b4cac81SBjoern A. Zeeb static void 1753*6b4cac81SBjoern A. Zeeb lkpi_ic_update_chw(struct ieee80211com *ic) 1754*6b4cac81SBjoern A. Zeeb { 1755*6b4cac81SBjoern A. Zeeb 1756*6b4cac81SBjoern A. Zeeb UNIMPLEMENTED; 1757*6b4cac81SBjoern A. Zeeb } 1758*6b4cac81SBjoern A. Zeeb 1759*6b4cac81SBjoern A. Zeeb /* Start / stop device. */ 1760*6b4cac81SBjoern A. Zeeb static void 1761*6b4cac81SBjoern A. Zeeb lkpi_ic_parent(struct ieee80211com *ic) 1762*6b4cac81SBjoern A. Zeeb { 1763*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 1764*6b4cac81SBjoern A. Zeeb struct ieee80211_hw *hw; 1765*6b4cac81SBjoern A. Zeeb int error; 1766*6b4cac81SBjoern A. Zeeb bool start_all; 1767*6b4cac81SBjoern A. Zeeb 1768*6b4cac81SBjoern A. Zeeb IMPROVE(); 1769*6b4cac81SBjoern A. Zeeb 1770*6b4cac81SBjoern A. Zeeb lhw = ic->ic_softc; 1771*6b4cac81SBjoern A. Zeeb hw = LHW_TO_HW(lhw); 1772*6b4cac81SBjoern A. Zeeb start_all = false; 1773*6b4cac81SBjoern A. Zeeb 1774*6b4cac81SBjoern A. Zeeb if (ic->ic_nrunning > 0) { 1775*6b4cac81SBjoern A. Zeeb error = lkpi_80211_mo_start(hw); 1776*6b4cac81SBjoern A. Zeeb if (error == 0) 1777*6b4cac81SBjoern A. Zeeb start_all = true; 1778*6b4cac81SBjoern A. Zeeb } else { 1779*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_stop(hw); 1780*6b4cac81SBjoern A. Zeeb } 1781*6b4cac81SBjoern A. Zeeb 1782*6b4cac81SBjoern A. Zeeb if (start_all) 1783*6b4cac81SBjoern A. Zeeb ieee80211_start_all(ic); 1784*6b4cac81SBjoern A. Zeeb } 1785*6b4cac81SBjoern A. Zeeb 1786*6b4cac81SBjoern A. Zeeb bool 1787*6b4cac81SBjoern A. Zeeb linuxkpi_ieee80211_is_ie_id_in_ie_buf(const u8 ie, const u8 *ie_ids, 1788*6b4cac81SBjoern A. Zeeb size_t ie_ids_len) 1789*6b4cac81SBjoern A. Zeeb { 1790*6b4cac81SBjoern A. Zeeb int i; 1791*6b4cac81SBjoern A. Zeeb 1792*6b4cac81SBjoern A. Zeeb for (i = 0; i < ie_ids_len; i++) { 1793*6b4cac81SBjoern A. Zeeb if (ie == *ie_ids) 1794*6b4cac81SBjoern A. Zeeb return (true); 1795*6b4cac81SBjoern A. Zeeb } 1796*6b4cac81SBjoern A. Zeeb 1797*6b4cac81SBjoern A. Zeeb return (false); 1798*6b4cac81SBjoern A. Zeeb } 1799*6b4cac81SBjoern A. Zeeb 1800*6b4cac81SBjoern A. Zeeb /* Return true if skipped; false if error. */ 1801*6b4cac81SBjoern A. Zeeb bool 1802*6b4cac81SBjoern A. Zeeb linuxkpi_ieee80211_ie_advance(size_t *xp, const u8 *ies, size_t ies_len) 1803*6b4cac81SBjoern A. Zeeb { 1804*6b4cac81SBjoern A. Zeeb size_t x; 1805*6b4cac81SBjoern A. Zeeb uint8_t l; 1806*6b4cac81SBjoern A. Zeeb 1807*6b4cac81SBjoern A. Zeeb x = *xp; 1808*6b4cac81SBjoern A. Zeeb 1809*6b4cac81SBjoern A. Zeeb KASSERT(x < ies_len, ("%s: x %zu ies_len %zu ies %p\n", 1810*6b4cac81SBjoern A. Zeeb __func__, x, ies_len, ies)); 1811*6b4cac81SBjoern A. Zeeb l = ies[x + 1]; 1812*6b4cac81SBjoern A. Zeeb x += 2 + l; 1813*6b4cac81SBjoern A. Zeeb 1814*6b4cac81SBjoern A. Zeeb if (x > ies_len) 1815*6b4cac81SBjoern A. Zeeb return (false); 1816*6b4cac81SBjoern A. Zeeb 1817*6b4cac81SBjoern A. Zeeb *xp = x; 1818*6b4cac81SBjoern A. Zeeb return (true); 1819*6b4cac81SBjoern A. Zeeb } 1820*6b4cac81SBjoern A. Zeeb 1821*6b4cac81SBjoern A. Zeeb static int 1822*6b4cac81SBjoern A. Zeeb lkpi_ieee80211_probereq_ie_alloc(struct ieee80211vap *vap, 1823*6b4cac81SBjoern A. Zeeb struct ieee80211com *ic, struct ieee80211_scan_ies *scan_ies, 1824*6b4cac81SBjoern A. Zeeb const uint8_t *ssid, size_t ssidlen) 1825*6b4cac81SBjoern A. Zeeb { 1826*6b4cac81SBjoern A. Zeeb 1827*6b4cac81SBjoern A. Zeeb return (ieee80211_probereq_ie(vap, ic, 1828*6b4cac81SBjoern A. Zeeb &scan_ies->common_ies, &scan_ies->common_ie_len, 1829*6b4cac81SBjoern A. Zeeb ssid, ssidlen, true)); 1830*6b4cac81SBjoern A. Zeeb } 1831*6b4cac81SBjoern A. Zeeb 1832*6b4cac81SBjoern A. Zeeb static void 1833*6b4cac81SBjoern A. Zeeb lkpi_ic_scan_start(struct ieee80211com *ic) 1834*6b4cac81SBjoern A. Zeeb { 1835*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 1836*6b4cac81SBjoern A. Zeeb struct ieee80211_hw *hw; 1837*6b4cac81SBjoern A. Zeeb struct lkpi_vif *lvif; 1838*6b4cac81SBjoern A. Zeeb struct ieee80211_vif *vif; 1839*6b4cac81SBjoern A. Zeeb struct ieee80211_scan_state *ss; 1840*6b4cac81SBjoern A. Zeeb struct ieee80211vap *vap; 1841*6b4cac81SBjoern A. Zeeb int error; 1842*6b4cac81SBjoern A. Zeeb 1843*6b4cac81SBjoern A. Zeeb lhw = ic->ic_softc; 1844*6b4cac81SBjoern A. Zeeb if ((lhw->scan_flags & LKPI_SCAN_RUNNING) != 0) { 1845*6b4cac81SBjoern A. Zeeb /* A scan is still running. */ 1846*6b4cac81SBjoern A. Zeeb return; 1847*6b4cac81SBjoern A. Zeeb } 1848*6b4cac81SBjoern A. Zeeb 1849*6b4cac81SBjoern A. Zeeb ss = ic->ic_scan; 1850*6b4cac81SBjoern A. Zeeb vap = ss->ss_vap; 1851*6b4cac81SBjoern A. Zeeb if (vap->iv_state != IEEE80211_S_SCAN) { 1852*6b4cac81SBjoern A. Zeeb /* Do not start a scan for now. */ 1853*6b4cac81SBjoern A. Zeeb return; 1854*6b4cac81SBjoern A. Zeeb } 1855*6b4cac81SBjoern A. Zeeb 1856*6b4cac81SBjoern A. Zeeb hw = LHW_TO_HW(lhw); 1857*6b4cac81SBjoern A. Zeeb if ((ic->ic_flags_ext & IEEE80211_FEXT_SCAN_OFFLOAD) == 0) { 1858*6b4cac81SBjoern A. Zeeb 1859*6b4cac81SBjoern A. Zeeb lvif = VAP_TO_LVIF(vap); 1860*6b4cac81SBjoern A. Zeeb vif = LVIF_TO_VIF(lvif); 1861*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_sw_scan_start(hw, vif, vif->addr); 1862*6b4cac81SBjoern A. Zeeb /* net80211::scan_start() handled PS for us. */ 1863*6b4cac81SBjoern A. Zeeb IMPROVE(); 1864*6b4cac81SBjoern A. Zeeb /* XXX Also means it is too late to flush queues? 1865*6b4cac81SBjoern A. Zeeb * need to check iv_sta_ps or overload? */ 1866*6b4cac81SBjoern A. Zeeb /* XXX want to adjust ss end time/ maxdwell? */ 1867*6b4cac81SBjoern A. Zeeb 1868*6b4cac81SBjoern A. Zeeb } else { 1869*6b4cac81SBjoern A. Zeeb struct ieee80211_channel *c; 1870*6b4cac81SBjoern A. Zeeb struct ieee80211_scan_request *hw_req; 1871*6b4cac81SBjoern A. Zeeb struct linuxkpi_ieee80211_channel *lc, **cpp; 1872*6b4cac81SBjoern A. Zeeb struct cfg80211_ssid *ssids; 1873*6b4cac81SBjoern A. Zeeb struct cfg80211_scan_6ghz_params *s6gp; 1874*6b4cac81SBjoern A. Zeeb size_t chan_len, nchan, ssids_len, s6ghzlen; 1875*6b4cac81SBjoern A. Zeeb int i; 1876*6b4cac81SBjoern A. Zeeb 1877*6b4cac81SBjoern A. Zeeb ssids_len = ss->ss_nssid * sizeof(*ssids);; 1878*6b4cac81SBjoern A. Zeeb s6ghzlen = 0 * (sizeof(*s6gp)); /* XXX-BZ */ 1879*6b4cac81SBjoern A. Zeeb 1880*6b4cac81SBjoern A. Zeeb nchan = 0; 1881*6b4cac81SBjoern A. Zeeb for (i = ss->ss_next; i < ss->ss_last; i++) 1882*6b4cac81SBjoern A. Zeeb nchan++; 1883*6b4cac81SBjoern A. Zeeb chan_len = nchan * (sizeof(lc) + sizeof(*lc)); 1884*6b4cac81SBjoern A. Zeeb 1885*6b4cac81SBjoern A. Zeeb KASSERT(lhw->hw_req == NULL, ("%s: ic %p lhw %p hw_req %p " 1886*6b4cac81SBjoern A. Zeeb "!= NULL\n", __func__, ic, lhw, lhw->hw_req)); 1887*6b4cac81SBjoern A. Zeeb lhw->hw_req = hw_req = malloc(sizeof(*hw_req) + ssids_len + 1888*6b4cac81SBjoern A. Zeeb s6ghzlen + chan_len, M_LKPI80211, M_WAITOK | M_ZERO); 1889*6b4cac81SBjoern A. Zeeb 1890*6b4cac81SBjoern A. Zeeb error = lkpi_ieee80211_probereq_ie_alloc(vap, ic, 1891*6b4cac81SBjoern A. Zeeb &hw_req->ies, NULL, -1); 1892*6b4cac81SBjoern A. Zeeb if (error != 0) 1893*6b4cac81SBjoern A. Zeeb ic_printf(ic, "ERROR: %s: probereq_ie returned %d\n", 1894*6b4cac81SBjoern A. Zeeb __func__, error); 1895*6b4cac81SBjoern A. Zeeb 1896*6b4cac81SBjoern A. Zeeb hw_req->req.flags = 0; /* XXX ??? */ 1897*6b4cac81SBjoern A. Zeeb /* hw_req->req.wdev */ 1898*6b4cac81SBjoern A. Zeeb hw_req->req.wiphy = hw->wiphy; 1899*6b4cac81SBjoern A. Zeeb hw_req->req.no_cck = false; /* XXX */ 1900*6b4cac81SBjoern A. Zeeb #if 0 1901*6b4cac81SBjoern A. Zeeb /* This seems to pessimise default scanning behaviour. */ 1902*6b4cac81SBjoern A. Zeeb hw_req->req.duration_mandatory = TICKS_2_USEC(ss->ss_mindwell); 1903*6b4cac81SBjoern A. Zeeb hw_req->req.duration = TICKS_2_USEC(ss->ss_maxdwell); 1904*6b4cac81SBjoern A. Zeeb #endif 1905*6b4cac81SBjoern A. Zeeb #ifdef __notyet__ 1906*6b4cac81SBjoern A. Zeeb hw_req->req.flags |= NL80211_SCAN_FLAG_RANDOM_ADDR; 1907*6b4cac81SBjoern A. Zeeb memcpy(hw_req->req.mac_addr, xxx, IEEE80211_ADDR_LEN); 1908*6b4cac81SBjoern A. Zeeb memset(hw_req->req.mac_addr_mask, 0xxx, IEEE80211_ADDR_LEN); 1909*6b4cac81SBjoern A. Zeeb #endif 1910*6b4cac81SBjoern A. Zeeb #if 0 1911*6b4cac81SBjoern A. Zeeb hw_req->req.ie_len = ; 1912*6b4cac81SBjoern A. Zeeb hw_req->req.ie = ; 1913*6b4cac81SBjoern A. Zeeb #endif 1914*6b4cac81SBjoern A. Zeeb 1915*6b4cac81SBjoern A. Zeeb hw_req->req.n_channels = nchan; 1916*6b4cac81SBjoern A. Zeeb cpp = (struct linuxkpi_ieee80211_channel **)(hw_req + 1); 1917*6b4cac81SBjoern A. Zeeb lc = (struct linuxkpi_ieee80211_channel *)(cpp + nchan); 1918*6b4cac81SBjoern A. Zeeb for (i = 0; i < nchan; i++) { 1919*6b4cac81SBjoern A. Zeeb *(cpp + i) = 1920*6b4cac81SBjoern A. Zeeb (struct linuxkpi_ieee80211_channel *)(lc + i); 1921*6b4cac81SBjoern A. Zeeb } 1922*6b4cac81SBjoern A. Zeeb for (i = 0; i < nchan; i++) { 1923*6b4cac81SBjoern A. Zeeb c = ss->ss_chans[ss->ss_next + i]; 1924*6b4cac81SBjoern A. Zeeb 1925*6b4cac81SBjoern A. Zeeb lc->hw_value = c->ic_ieee; 1926*6b4cac81SBjoern A. Zeeb lc->center_freq = c->ic_freq; 1927*6b4cac81SBjoern A. Zeeb /* lc->flags */ 1928*6b4cac81SBjoern A. Zeeb lc->band = lkpi_net80211_chan_to_nl80211_band(c); 1929*6b4cac81SBjoern A. Zeeb lc->max_power = c->ic_maxpower; 1930*6b4cac81SBjoern A. Zeeb /* lc-> ... */ 1931*6b4cac81SBjoern A. Zeeb lc++; 1932*6b4cac81SBjoern A. Zeeb } 1933*6b4cac81SBjoern A. Zeeb 1934*6b4cac81SBjoern A. Zeeb hw_req->req.n_ssids = ss->ss_nssid; 1935*6b4cac81SBjoern A. Zeeb if (hw_req->req.n_ssids > 0) { 1936*6b4cac81SBjoern A. Zeeb ssids = (struct cfg80211_ssid *)lc; 1937*6b4cac81SBjoern A. Zeeb hw_req->req.ssids = ssids; 1938*6b4cac81SBjoern A. Zeeb for (i = 0; i < ss->ss_nssid; i++) { 1939*6b4cac81SBjoern A. Zeeb ssids->ssid_len = ss->ss_ssid[i].len; 1940*6b4cac81SBjoern A. Zeeb memcpy(ssids->ssid, ss->ss_ssid[i].ssid, 1941*6b4cac81SBjoern A. Zeeb ss->ss_ssid[i].len); 1942*6b4cac81SBjoern A. Zeeb ssids++; 1943*6b4cac81SBjoern A. Zeeb } 1944*6b4cac81SBjoern A. Zeeb s6gp = (struct cfg80211_scan_6ghz_params *)ssids; 1945*6b4cac81SBjoern A. Zeeb } else { 1946*6b4cac81SBjoern A. Zeeb s6gp = (struct cfg80211_scan_6ghz_params *)lc; 1947*6b4cac81SBjoern A. Zeeb } 1948*6b4cac81SBjoern A. Zeeb 1949*6b4cac81SBjoern A. Zeeb /* 6GHz one day. */ 1950*6b4cac81SBjoern A. Zeeb hw_req->req.n_6ghz_params = 0; 1951*6b4cac81SBjoern A. Zeeb hw_req->req.scan_6ghz_params = NULL; 1952*6b4cac81SBjoern A. Zeeb hw_req->req.scan_6ghz = false; /* Weird boolean; not what you think. */ 1953*6b4cac81SBjoern A. Zeeb /* s6gp->... */ 1954*6b4cac81SBjoern A. Zeeb 1955*6b4cac81SBjoern A. Zeeb lvif = VAP_TO_LVIF(vap); 1956*6b4cac81SBjoern A. Zeeb vif = LVIF_TO_VIF(lvif); 1957*6b4cac81SBjoern A. Zeeb error = lkpi_80211_mo_hw_scan(hw, vif, hw_req); 1958*6b4cac81SBjoern A. Zeeb if (error != 0) { 1959*6b4cac81SBjoern A. Zeeb ic_printf(ic, "ERROR: %s: hw_scan returned %d\n", 1960*6b4cac81SBjoern A. Zeeb __func__, error); 1961*6b4cac81SBjoern A. Zeeb ieee80211_cancel_scan(vap); 1962*6b4cac81SBjoern A. Zeeb free(hw_req->ies.common_ies, M_80211_VAP); 1963*6b4cac81SBjoern A. Zeeb free(hw_req, M_LKPI80211); 1964*6b4cac81SBjoern A. Zeeb lhw->hw_req = NULL; 1965*6b4cac81SBjoern A. Zeeb } 1966*6b4cac81SBjoern A. Zeeb } 1967*6b4cac81SBjoern A. Zeeb } 1968*6b4cac81SBjoern A. Zeeb 1969*6b4cac81SBjoern A. Zeeb static void 1970*6b4cac81SBjoern A. Zeeb lkpi_ic_scan_end(struct ieee80211com *ic) 1971*6b4cac81SBjoern A. Zeeb { 1972*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 1973*6b4cac81SBjoern A. Zeeb 1974*6b4cac81SBjoern A. Zeeb lhw = ic->ic_softc; 1975*6b4cac81SBjoern A. Zeeb if ((lhw->scan_flags & LKPI_SCAN_RUNNING) == 0) { 1976*6b4cac81SBjoern A. Zeeb return; 1977*6b4cac81SBjoern A. Zeeb } 1978*6b4cac81SBjoern A. Zeeb 1979*6b4cac81SBjoern A. Zeeb if (ic->ic_flags_ext & IEEE80211_FEXT_SCAN_OFFLOAD) { 1980*6b4cac81SBjoern A. Zeeb /* Nothing to do. */ 1981*6b4cac81SBjoern A. Zeeb } else { 1982*6b4cac81SBjoern A. Zeeb struct ieee80211_hw *hw; 1983*6b4cac81SBjoern A. Zeeb struct lkpi_vif *lvif; 1984*6b4cac81SBjoern A. Zeeb struct ieee80211_vif *vif; 1985*6b4cac81SBjoern A. Zeeb struct ieee80211_scan_state *ss; 1986*6b4cac81SBjoern A. Zeeb struct ieee80211vap *vap; 1987*6b4cac81SBjoern A. Zeeb 1988*6b4cac81SBjoern A. Zeeb hw = LHW_TO_HW(lhw); 1989*6b4cac81SBjoern A. Zeeb ss = ic->ic_scan; 1990*6b4cac81SBjoern A. Zeeb vap = ss->ss_vap; 1991*6b4cac81SBjoern A. Zeeb lvif = VAP_TO_LVIF(vap); 1992*6b4cac81SBjoern A. Zeeb vif = LVIF_TO_VIF(lvif); 1993*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_sw_scan_complete(hw, vif); 1994*6b4cac81SBjoern A. Zeeb 1995*6b4cac81SBjoern A. Zeeb /* Send PS to stop buffering if n80211 does not for us? */ 1996*6b4cac81SBjoern A. Zeeb } 1997*6b4cac81SBjoern A. Zeeb } 1998*6b4cac81SBjoern A. Zeeb 1999*6b4cac81SBjoern A. Zeeb static void 2000*6b4cac81SBjoern A. Zeeb lkpi_ic_scan_curchan_nada(struct ieee80211_scan_state *ss __unused, 2001*6b4cac81SBjoern A. Zeeb unsigned long maxdwell __unused) 2002*6b4cac81SBjoern A. Zeeb { 2003*6b4cac81SBjoern A. Zeeb } 2004*6b4cac81SBjoern A. Zeeb 2005*6b4cac81SBjoern A. Zeeb static void 2006*6b4cac81SBjoern A. Zeeb lkpi_ic_set_channel(struct ieee80211com *ic) 2007*6b4cac81SBjoern A. Zeeb { 2008*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 2009*6b4cac81SBjoern A. Zeeb struct ieee80211_hw *hw; 2010*6b4cac81SBjoern A. Zeeb int error; 2011*6b4cac81SBjoern A. Zeeb 2012*6b4cac81SBjoern A. Zeeb lhw = ic->ic_softc; 2013*6b4cac81SBjoern A. Zeeb #ifdef __no_longer__ 2014*6b4cac81SBjoern A. Zeeb /* For now only be concerned if scanning. */ 2015*6b4cac81SBjoern A. Zeeb if ((lhw->scan_flags & LKPI_SCAN_RUNNING) == 0) { 2016*6b4cac81SBjoern A. Zeeb IMPROVE(); 2017*6b4cac81SBjoern A. Zeeb return; 2018*6b4cac81SBjoern A. Zeeb } 2019*6b4cac81SBjoern A. Zeeb #endif 2020*6b4cac81SBjoern A. Zeeb 2021*6b4cac81SBjoern A. Zeeb if (ic->ic_flags_ext & IEEE80211_FEXT_SCAN_OFFLOAD) { 2022*6b4cac81SBjoern A. Zeeb /* 2023*6b4cac81SBjoern A. Zeeb * AP scanning is taken care of by firmware, so only switch 2024*6b4cac81SBjoern A. Zeeb * channels in monitor mode (maybe, maybe not; to be 2025*6b4cac81SBjoern A. Zeeb * investigated at the right time). 2026*6b4cac81SBjoern A. Zeeb */ 2027*6b4cac81SBjoern A. Zeeb if (ic->ic_opmode == IEEE80211_M_MONITOR) { 2028*6b4cac81SBjoern A. Zeeb UNIMPLEMENTED; 2029*6b4cac81SBjoern A. Zeeb } 2030*6b4cac81SBjoern A. Zeeb } else { 2031*6b4cac81SBjoern A. Zeeb struct ieee80211_channel *c = ic->ic_curchan; 2032*6b4cac81SBjoern A. Zeeb struct linuxkpi_ieee80211_channel *chan; 2033*6b4cac81SBjoern A. Zeeb struct cfg80211_chan_def chandef; 2034*6b4cac81SBjoern A. Zeeb 2035*6b4cac81SBjoern A. Zeeb if (c == NULL || c == IEEE80211_CHAN_ANYC || 2036*6b4cac81SBjoern A. Zeeb lhw->ops->config == NULL) { 2037*6b4cac81SBjoern A. Zeeb ic_printf(ic, "%s: c %p ops->config %p\n", __func__, 2038*6b4cac81SBjoern A. Zeeb c, lhw->ops->config); 2039*6b4cac81SBjoern A. Zeeb return; 2040*6b4cac81SBjoern A. Zeeb } 2041*6b4cac81SBjoern A. Zeeb 2042*6b4cac81SBjoern A. Zeeb chan = lkpi_find_lkpi80211_chan(lhw, c); 2043*6b4cac81SBjoern A. Zeeb if (chan == NULL) { 2044*6b4cac81SBjoern A. Zeeb ic_printf(ic, "%s: c %p chan %p\n", __func__, 2045*6b4cac81SBjoern A. Zeeb c, chan); 2046*6b4cac81SBjoern A. Zeeb return; 2047*6b4cac81SBjoern A. Zeeb } 2048*6b4cac81SBjoern A. Zeeb 2049*6b4cac81SBjoern A. Zeeb memset(&chandef, 0, sizeof(chandef)); 2050*6b4cac81SBjoern A. Zeeb chandef.chan = chan; 2051*6b4cac81SBjoern A. Zeeb chandef.width = NL80211_CHAN_WIDTH_20_NOHT; 2052*6b4cac81SBjoern A. Zeeb chandef.center_freq1 = chandef.chan->center_freq; 2053*6b4cac81SBjoern A. Zeeb 2054*6b4cac81SBjoern A. Zeeb /* XXX max power for scanning? */ 2055*6b4cac81SBjoern A. Zeeb IMPROVE(); 2056*6b4cac81SBjoern A. Zeeb 2057*6b4cac81SBjoern A. Zeeb hw = LHW_TO_HW(lhw); 2058*6b4cac81SBjoern A. Zeeb hw->conf.chandef = chandef; 2059*6b4cac81SBjoern A. Zeeb 2060*6b4cac81SBjoern A. Zeeb hw->conf.flags &= ~IEEE80211_CONF_IDLE; 2061*6b4cac81SBjoern A. Zeeb error = lkpi_80211_mo_config(hw, IEEE80211_CONF_CHANGE_IDLE); 2062*6b4cac81SBjoern A. Zeeb if (error != 0 && error != EOPNOTSUPP) 2063*6b4cac81SBjoern A. Zeeb ic_printf(ic, "ERROR: %s: config %#0x returned %d\n", 2064*6b4cac81SBjoern A. Zeeb __func__, IEEE80211_CONF_CHANGE_IDLE, error); 2065*6b4cac81SBjoern A. Zeeb 2066*6b4cac81SBjoern A. Zeeb error = lkpi_80211_mo_config(hw, IEEE80211_CONF_CHANGE_CHANNEL); 2067*6b4cac81SBjoern A. Zeeb if (error != 0 && error != EOPNOTSUPP) { 2068*6b4cac81SBjoern A. Zeeb ic_printf(ic, "ERROR: %s: config %#0x returned %d\n", 2069*6b4cac81SBjoern A. Zeeb __func__, IEEE80211_CONF_CHANGE_CHANNEL, error); 2070*6b4cac81SBjoern A. Zeeb /* XXX should we unroll to the previous chandef? */ 2071*6b4cac81SBjoern A. Zeeb IMPROVE(); 2072*6b4cac81SBjoern A. Zeeb } else { 2073*6b4cac81SBjoern A. Zeeb /* Update radiotap channels as well. */ 2074*6b4cac81SBjoern A. Zeeb lhw->rtap_tx.wt_chan_freq = htole16(c->ic_freq); 2075*6b4cac81SBjoern A. Zeeb lhw->rtap_tx.wt_chan_flags = htole16(c->ic_flags); 2076*6b4cac81SBjoern A. Zeeb lhw->rtap_rx.wr_chan_freq = htole16(c->ic_freq); 2077*6b4cac81SBjoern A. Zeeb lhw->rtap_rx.wr_chan_flags = htole16(c->ic_flags); 2078*6b4cac81SBjoern A. Zeeb } 2079*6b4cac81SBjoern A. Zeeb 2080*6b4cac81SBjoern A. Zeeb /* Currently PS is hard coded off! Not sure it belongs here. */ 2081*6b4cac81SBjoern A. Zeeb IMPROVE(); 2082*6b4cac81SBjoern A. Zeeb if (ieee80211_hw_check(hw, SUPPORTS_PS) && 2083*6b4cac81SBjoern A. Zeeb (hw->conf.flags & IEEE80211_CONF_PS) != 0) { 2084*6b4cac81SBjoern A. Zeeb hw->conf.flags &= ~IEEE80211_CONF_PS; 2085*6b4cac81SBjoern A. Zeeb error = lkpi_80211_mo_config(hw, IEEE80211_CONF_CHANGE_PS); 2086*6b4cac81SBjoern A. Zeeb if (error != 0 && error != EOPNOTSUPP) 2087*6b4cac81SBjoern A. Zeeb ic_printf(ic, "ERROR: %s: config %#0x returned " 2088*6b4cac81SBjoern A. Zeeb "%d\n", __func__, IEEE80211_CONF_CHANGE_PS, 2089*6b4cac81SBjoern A. Zeeb error); 2090*6b4cac81SBjoern A. Zeeb } 2091*6b4cac81SBjoern A. Zeeb } 2092*6b4cac81SBjoern A. Zeeb } 2093*6b4cac81SBjoern A. Zeeb 2094*6b4cac81SBjoern A. Zeeb static struct ieee80211_node * 2095*6b4cac81SBjoern A. Zeeb lkpi_ic_node_alloc(struct ieee80211vap *vap, 2096*6b4cac81SBjoern A. Zeeb const uint8_t mac[IEEE80211_ADDR_LEN]) 2097*6b4cac81SBjoern A. Zeeb { 2098*6b4cac81SBjoern A. Zeeb struct ieee80211com *ic; 2099*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 2100*6b4cac81SBjoern A. Zeeb struct ieee80211_hw *hw; 2101*6b4cac81SBjoern A. Zeeb struct lkpi_sta *lsta; 2102*6b4cac81SBjoern A. Zeeb struct ieee80211_sta *sta; 2103*6b4cac81SBjoern A. Zeeb struct lkpi_vif *lvif; 2104*6b4cac81SBjoern A. Zeeb struct ieee80211_vif *vif; 2105*6b4cac81SBjoern A. Zeeb struct ieee80211_node *ni; 2106*6b4cac81SBjoern A. Zeeb int tid; 2107*6b4cac81SBjoern A. Zeeb 2108*6b4cac81SBjoern A. Zeeb ic = vap->iv_ic; 2109*6b4cac81SBjoern A. Zeeb lhw = ic->ic_softc; 2110*6b4cac81SBjoern A. Zeeb 2111*6b4cac81SBjoern A. Zeeb /* We keep allocations de-coupled so we can deal with the two worlds. */ 2112*6b4cac81SBjoern A. Zeeb if (lhw->ic_node_alloc != NULL) { 2113*6b4cac81SBjoern A. Zeeb ni = lhw->ic_node_alloc(vap, mac); 2114*6b4cac81SBjoern A. Zeeb if (ni == NULL) 2115*6b4cac81SBjoern A. Zeeb return (NULL); 2116*6b4cac81SBjoern A. Zeeb } 2117*6b4cac81SBjoern A. Zeeb 2118*6b4cac81SBjoern A. Zeeb hw = LHW_TO_HW(lhw); 2119*6b4cac81SBjoern A. Zeeb lsta = malloc(sizeof(*lsta) + hw->sta_data_size, M_LKPI80211, 2120*6b4cac81SBjoern A. Zeeb M_NOWAIT | M_ZERO); 2121*6b4cac81SBjoern A. Zeeb if (lsta == NULL) { 2122*6b4cac81SBjoern A. Zeeb if (lhw->ic_node_free != NULL) 2123*6b4cac81SBjoern A. Zeeb lhw->ic_node_free(ni); 2124*6b4cac81SBjoern A. Zeeb return (NULL); 2125*6b4cac81SBjoern A. Zeeb } 2126*6b4cac81SBjoern A. Zeeb 2127*6b4cac81SBjoern A. Zeeb lsta->added_to_drv = false; 2128*6b4cac81SBjoern A. Zeeb lsta->state = IEEE80211_STA_NOTEXIST; 2129*6b4cac81SBjoern A. Zeeb #if 0 2130*6b4cac81SBjoern A. Zeeb /* 2131*6b4cac81SBjoern A. Zeeb * This needs to be done in node_init() as ieee80211_alloc_node() 2132*6b4cac81SBjoern A. Zeeb * will initialise the refcount after us. 2133*6b4cac81SBjoern A. Zeeb */ 2134*6b4cac81SBjoern A. Zeeb lsta->ni = ieee80211_ref_node(ni); 2135*6b4cac81SBjoern A. Zeeb #endif 2136*6b4cac81SBjoern A. Zeeb /* The back-pointer "drv_data" to net80211_node let's us get lsta. */ 2137*6b4cac81SBjoern A. Zeeb ni->ni_drv_data = lsta; 2138*6b4cac81SBjoern A. Zeeb 2139*6b4cac81SBjoern A. Zeeb lvif = VAP_TO_LVIF(vap); 2140*6b4cac81SBjoern A. Zeeb vif = LVIF_TO_VIF(lvif); 2141*6b4cac81SBjoern A. Zeeb sta = LSTA_TO_STA(lsta); 2142*6b4cac81SBjoern A. Zeeb 2143*6b4cac81SBjoern A. Zeeb IEEE80211_ADDR_COPY(sta->addr, mac); 2144*6b4cac81SBjoern A. Zeeb for (tid = 0; tid < nitems(sta->txq); tid++) { 2145*6b4cac81SBjoern A. Zeeb struct lkpi_txq *ltxq; 2146*6b4cac81SBjoern A. Zeeb 2147*6b4cac81SBjoern A. Zeeb /* 2148*6b4cac81SBjoern A. Zeeb * We are neither limiting ourselves to hw.queues here, 2149*6b4cac81SBjoern A. Zeeb * nor do we check if driver wants IEEE80211_NUM_TIDS queue. 2150*6b4cac81SBjoern A. Zeeb */ 2151*6b4cac81SBjoern A. Zeeb 2152*6b4cac81SBjoern A. Zeeb ltxq = malloc(sizeof(*ltxq) + hw->txq_data_size, 2153*6b4cac81SBjoern A. Zeeb M_LKPI80211, M_NOWAIT | M_ZERO); 2154*6b4cac81SBjoern A. Zeeb if (ltxq == NULL) 2155*6b4cac81SBjoern A. Zeeb goto cleanup; 2156*6b4cac81SBjoern A. Zeeb ltxq->seen_dequeue = false; 2157*6b4cac81SBjoern A. Zeeb skb_queue_head_init(<xq->skbq); 2158*6b4cac81SBjoern A. Zeeb /* iwlwifi//mvm/sta.c::tid_to_mac80211_ac[] */ 2159*6b4cac81SBjoern A. Zeeb if (tid == IEEE80211_NUM_TIDS) { 2160*6b4cac81SBjoern A. Zeeb IMPROVE(); 2161*6b4cac81SBjoern A. Zeeb ltxq->txq.ac = IEEE80211_AC_VO; 2162*6b4cac81SBjoern A. Zeeb } else { 2163*6b4cac81SBjoern A. Zeeb ltxq->txq.ac = tid_to_mac80211_ac[tid & 7]; 2164*6b4cac81SBjoern A. Zeeb } 2165*6b4cac81SBjoern A. Zeeb ltxq->txq.tid = tid; 2166*6b4cac81SBjoern A. Zeeb ltxq->txq.sta = sta; 2167*6b4cac81SBjoern A. Zeeb ltxq->txq.vif = vif; 2168*6b4cac81SBjoern A. Zeeb sta->txq[tid] = <xq->txq; 2169*6b4cac81SBjoern A. Zeeb } 2170*6b4cac81SBjoern A. Zeeb 2171*6b4cac81SBjoern A. Zeeb /* Deferred TX path. */ 2172*6b4cac81SBjoern A. Zeeb mtx_init(&lsta->txq_mtx, "lsta_txq", NULL, MTX_DEF); 2173*6b4cac81SBjoern A. Zeeb TASK_INIT(&lsta->txq_task, 0, lkpi_80211_txq_task, lsta); 2174*6b4cac81SBjoern A. Zeeb mbufq_init(&lsta->txq, IFQ_MAXLEN); 2175*6b4cac81SBjoern A. Zeeb 2176*6b4cac81SBjoern A. Zeeb return (ni); 2177*6b4cac81SBjoern A. Zeeb 2178*6b4cac81SBjoern A. Zeeb cleanup: 2179*6b4cac81SBjoern A. Zeeb for (; tid >= 0; tid--) 2180*6b4cac81SBjoern A. Zeeb free(sta->txq[tid], M_LKPI80211); 2181*6b4cac81SBjoern A. Zeeb free(lsta, M_LKPI80211); 2182*6b4cac81SBjoern A. Zeeb if (lhw->ic_node_free != NULL) 2183*6b4cac81SBjoern A. Zeeb lhw->ic_node_free(ni); 2184*6b4cac81SBjoern A. Zeeb return (NULL); 2185*6b4cac81SBjoern A. Zeeb } 2186*6b4cac81SBjoern A. Zeeb 2187*6b4cac81SBjoern A. Zeeb static int 2188*6b4cac81SBjoern A. Zeeb lkpi_ic_node_init(struct ieee80211_node *ni) 2189*6b4cac81SBjoern A. Zeeb { 2190*6b4cac81SBjoern A. Zeeb struct ieee80211com *ic; 2191*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 2192*6b4cac81SBjoern A. Zeeb struct lkpi_sta *lsta; 2193*6b4cac81SBjoern A. Zeeb struct lkpi_vif *lvif; 2194*6b4cac81SBjoern A. Zeeb int error; 2195*6b4cac81SBjoern A. Zeeb 2196*6b4cac81SBjoern A. Zeeb ic = ni->ni_ic; 2197*6b4cac81SBjoern A. Zeeb lhw = ic->ic_softc; 2198*6b4cac81SBjoern A. Zeeb 2199*6b4cac81SBjoern A. Zeeb if (lhw->ic_node_init != NULL) { 2200*6b4cac81SBjoern A. Zeeb error = lhw->ic_node_init(ni); 2201*6b4cac81SBjoern A. Zeeb if (error != 0) 2202*6b4cac81SBjoern A. Zeeb return (error); 2203*6b4cac81SBjoern A. Zeeb } 2204*6b4cac81SBjoern A. Zeeb 2205*6b4cac81SBjoern A. Zeeb lvif = VAP_TO_LVIF(ni->ni_vap); 2206*6b4cac81SBjoern A. Zeeb 2207*6b4cac81SBjoern A. Zeeb lsta = ni->ni_drv_data; 2208*6b4cac81SBjoern A. Zeeb 2209*6b4cac81SBjoern A. Zeeb /* Now take the reference before linking it to the table. */ 2210*6b4cac81SBjoern A. Zeeb lsta->ni = ieee80211_ref_node(ni); 2211*6b4cac81SBjoern A. Zeeb 2212*6b4cac81SBjoern A. Zeeb LKPI_80211_LVIF_LOCK(lvif); 2213*6b4cac81SBjoern A. Zeeb TAILQ_INSERT_TAIL(&lvif->lsta_head, lsta, lsta_entry); 2214*6b4cac81SBjoern A. Zeeb LKPI_80211_LVIF_UNLOCK(lvif); 2215*6b4cac81SBjoern A. Zeeb 2216*6b4cac81SBjoern A. Zeeb /* XXX-BZ Sync other state over. */ 2217*6b4cac81SBjoern A. Zeeb IMPROVE(); 2218*6b4cac81SBjoern A. Zeeb 2219*6b4cac81SBjoern A. Zeeb return (0); 2220*6b4cac81SBjoern A. Zeeb } 2221*6b4cac81SBjoern A. Zeeb 2222*6b4cac81SBjoern A. Zeeb static void 2223*6b4cac81SBjoern A. Zeeb lkpi_ic_node_cleanup(struct ieee80211_node *ni) 2224*6b4cac81SBjoern A. Zeeb { 2225*6b4cac81SBjoern A. Zeeb struct ieee80211com *ic; 2226*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 2227*6b4cac81SBjoern A. Zeeb 2228*6b4cac81SBjoern A. Zeeb ic = ni->ni_ic; 2229*6b4cac81SBjoern A. Zeeb lhw = ic->ic_softc; 2230*6b4cac81SBjoern A. Zeeb 2231*6b4cac81SBjoern A. Zeeb /* XXX-BZ remove from driver, ... */ 2232*6b4cac81SBjoern A. Zeeb IMPROVE(); 2233*6b4cac81SBjoern A. Zeeb 2234*6b4cac81SBjoern A. Zeeb if (lhw->ic_node_cleanup != NULL) 2235*6b4cac81SBjoern A. Zeeb lhw->ic_node_cleanup(ni); 2236*6b4cac81SBjoern A. Zeeb } 2237*6b4cac81SBjoern A. Zeeb 2238*6b4cac81SBjoern A. Zeeb static void 2239*6b4cac81SBjoern A. Zeeb lkpi_ic_node_free(struct ieee80211_node *ni) 2240*6b4cac81SBjoern A. Zeeb { 2241*6b4cac81SBjoern A. Zeeb struct ieee80211com *ic; 2242*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 2243*6b4cac81SBjoern A. Zeeb struct lkpi_sta *lsta; 2244*6b4cac81SBjoern A. Zeeb 2245*6b4cac81SBjoern A. Zeeb ic = ni->ni_ic; 2246*6b4cac81SBjoern A. Zeeb lhw = ic->ic_softc; 2247*6b4cac81SBjoern A. Zeeb lsta = ni->ni_drv_data; 2248*6b4cac81SBjoern A. Zeeb 2249*6b4cac81SBjoern A. Zeeb /* XXX-BZ free resources, ... */ 2250*6b4cac81SBjoern A. Zeeb IMPROVE(); 2251*6b4cac81SBjoern A. Zeeb 2252*6b4cac81SBjoern A. Zeeb /* Flush mbufq (make sure to release ni refs!). */ 2253*6b4cac81SBjoern A. Zeeb #ifdef __notyet__ 2254*6b4cac81SBjoern A. Zeeb KASSERT(mbufq_len(&lsta->txq) == 0, ("%s: lsta %p has txq len %d != 0\n", 2255*6b4cac81SBjoern A. Zeeb __func__, lsta, mbufq_len(&lsta->txq))); 2256*6b4cac81SBjoern A. Zeeb #endif 2257*6b4cac81SBjoern A. Zeeb /* Drain taskq. */ 2258*6b4cac81SBjoern A. Zeeb 2259*6b4cac81SBjoern A. Zeeb /* Drain sta->txq[] */ 2260*6b4cac81SBjoern A. Zeeb mtx_destroy(&lsta->txq_mtx); 2261*6b4cac81SBjoern A. Zeeb 2262*6b4cac81SBjoern A. Zeeb /* Remove lsta if added_to_drv. */ 2263*6b4cac81SBjoern A. Zeeb /* Remove lsta from vif */ 2264*6b4cac81SBjoern A. Zeeb 2265*6b4cac81SBjoern A. Zeeb /* remove ref from lsta node... */ 2266*6b4cac81SBjoern A. Zeeb 2267*6b4cac81SBjoern A. Zeeb if (lhw->ic_node_free != NULL) 2268*6b4cac81SBjoern A. Zeeb lhw->ic_node_free(ni); 2269*6b4cac81SBjoern A. Zeeb 2270*6b4cac81SBjoern A. Zeeb /* Free lsta. */ 2271*6b4cac81SBjoern A. Zeeb } 2272*6b4cac81SBjoern A. Zeeb 2273*6b4cac81SBjoern A. Zeeb static int 2274*6b4cac81SBjoern A. Zeeb lkpi_ic_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 2275*6b4cac81SBjoern A. Zeeb const struct ieee80211_bpf_params *params __unused) 2276*6b4cac81SBjoern A. Zeeb { 2277*6b4cac81SBjoern A. Zeeb struct lkpi_sta *lsta; 2278*6b4cac81SBjoern A. Zeeb 2279*6b4cac81SBjoern A. Zeeb lsta = ni->ni_drv_data; 2280*6b4cac81SBjoern A. Zeeb 2281*6b4cac81SBjoern A. Zeeb /* Queue the packet and enqueue the task to handle it. */ 2282*6b4cac81SBjoern A. Zeeb LKPI_80211_LSTA_LOCK(lsta); 2283*6b4cac81SBjoern A. Zeeb mbufq_enqueue(&lsta->txq, m); 2284*6b4cac81SBjoern A. Zeeb LKPI_80211_LSTA_UNLOCK(lsta); 2285*6b4cac81SBjoern A. Zeeb 2286*6b4cac81SBjoern A. Zeeb if (debug_80211 & D80211_TRACE_TX) 2287*6b4cac81SBjoern A. Zeeb printf("%s:%d lsta %p ni %p %6D mbuf_qlen %d\n", 2288*6b4cac81SBjoern A. Zeeb __func__, __LINE__, lsta, ni, ni->ni_macaddr, ":", 2289*6b4cac81SBjoern A. Zeeb mbufq_len(&lsta->txq)); 2290*6b4cac81SBjoern A. Zeeb 2291*6b4cac81SBjoern A. Zeeb taskqueue_enqueue(taskqueue_thread, &lsta->txq_task); 2292*6b4cac81SBjoern A. Zeeb return (0); 2293*6b4cac81SBjoern A. Zeeb } 2294*6b4cac81SBjoern A. Zeeb 2295*6b4cac81SBjoern A. Zeeb static void 2296*6b4cac81SBjoern A. Zeeb lkpi_80211_txq_tx_one(struct lkpi_sta *lsta, struct mbuf *m) 2297*6b4cac81SBjoern A. Zeeb { 2298*6b4cac81SBjoern A. Zeeb struct ieee80211_node *ni; 2299*6b4cac81SBjoern A. Zeeb struct ieee80211_frame *wh; 2300*6b4cac81SBjoern A. Zeeb struct ieee80211_key *k; 2301*6b4cac81SBjoern A. Zeeb struct sk_buff *skb; 2302*6b4cac81SBjoern A. Zeeb struct ieee80211com *ic; 2303*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 2304*6b4cac81SBjoern A. Zeeb struct ieee80211_hw *hw; 2305*6b4cac81SBjoern A. Zeeb struct lkpi_vif *lvif; 2306*6b4cac81SBjoern A. Zeeb struct ieee80211_vif *vif; 2307*6b4cac81SBjoern A. Zeeb struct ieee80211_channel *c; 2308*6b4cac81SBjoern A. Zeeb struct ieee80211_tx_control control; 2309*6b4cac81SBjoern A. Zeeb struct ieee80211_tx_info *info; 2310*6b4cac81SBjoern A. Zeeb struct ieee80211_sta *sta; 2311*6b4cac81SBjoern A. Zeeb void *buf; 2312*6b4cac81SBjoern A. Zeeb int ac; 2313*6b4cac81SBjoern A. Zeeb 2314*6b4cac81SBjoern A. Zeeb M_ASSERTPKTHDR(m); 2315*6b4cac81SBjoern A. Zeeb #ifdef LINUXKPI_DEBUG_80211 2316*6b4cac81SBjoern A. Zeeb if (debug_80211 & D80211_TRACE_TX_DUMP) 2317*6b4cac81SBjoern A. Zeeb hexdump(mtod(m, const void *), m->m_len, "RAW TX (plain) ", 0); 2318*6b4cac81SBjoern A. Zeeb #endif 2319*6b4cac81SBjoern A. Zeeb 2320*6b4cac81SBjoern A. Zeeb ni = lsta->ni; 2321*6b4cac81SBjoern A. Zeeb #ifndef TRY_HW_CRYPTO 2322*6b4cac81SBjoern A. Zeeb /* Encrypt the frame if need be; XXX-BZ info->control.hw_key. */ 2323*6b4cac81SBjoern A. Zeeb wh = mtod(m, struct ieee80211_frame *); 2324*6b4cac81SBjoern A. Zeeb if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { 2325*6b4cac81SBjoern A. Zeeb /* Retrieve key for TX && do software encryption. */ 2326*6b4cac81SBjoern A. Zeeb k = ieee80211_crypto_encap(ni, m); 2327*6b4cac81SBjoern A. Zeeb if (k == NULL) { 2328*6b4cac81SBjoern A. Zeeb ieee80211_free_node(ni); 2329*6b4cac81SBjoern A. Zeeb m_freem(m); 2330*6b4cac81SBjoern A. Zeeb return; 2331*6b4cac81SBjoern A. Zeeb } 2332*6b4cac81SBjoern A. Zeeb } 2333*6b4cac81SBjoern A. Zeeb #endif 2334*6b4cac81SBjoern A. Zeeb 2335*6b4cac81SBjoern A. Zeeb ic = ni->ni_ic; 2336*6b4cac81SBjoern A. Zeeb lhw = ic->ic_softc; 2337*6b4cac81SBjoern A. Zeeb hw = LHW_TO_HW(lhw); 2338*6b4cac81SBjoern A. Zeeb c = ni->ni_chan; 2339*6b4cac81SBjoern A. Zeeb 2340*6b4cac81SBjoern A. Zeeb if (ieee80211_radiotap_active_vap(ni->ni_vap)) { 2341*6b4cac81SBjoern A. Zeeb struct lkpi_radiotap_tx_hdr *rtap; 2342*6b4cac81SBjoern A. Zeeb 2343*6b4cac81SBjoern A. Zeeb rtap = &lhw->rtap_tx; 2344*6b4cac81SBjoern A. Zeeb rtap->wt_flags = 0; 2345*6b4cac81SBjoern A. Zeeb if (k != NULL) 2346*6b4cac81SBjoern A. Zeeb rtap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; 2347*6b4cac81SBjoern A. Zeeb if (m->m_flags & M_FRAG) 2348*6b4cac81SBjoern A. Zeeb rtap->wt_flags |= IEEE80211_RADIOTAP_F_FRAG; 2349*6b4cac81SBjoern A. Zeeb IMPROVE(); 2350*6b4cac81SBjoern A. Zeeb rtap->wt_rate = 0; 2351*6b4cac81SBjoern A. Zeeb if (c != NULL && c != IEEE80211_CHAN_ANYC) { 2352*6b4cac81SBjoern A. Zeeb rtap->wt_chan_freq = htole16(c->ic_freq); 2353*6b4cac81SBjoern A. Zeeb rtap->wt_chan_flags = htole16(c->ic_flags); 2354*6b4cac81SBjoern A. Zeeb } 2355*6b4cac81SBjoern A. Zeeb 2356*6b4cac81SBjoern A. Zeeb ieee80211_radiotap_tx(ni->ni_vap, m); 2357*6b4cac81SBjoern A. Zeeb } 2358*6b4cac81SBjoern A. Zeeb 2359*6b4cac81SBjoern A. Zeeb /* 2360*6b4cac81SBjoern A. Zeeb * net80211 should handle hw->extra_tx_headroom. 2361*6b4cac81SBjoern A. Zeeb * Though for as long as we are copying we don't mind. 2362*6b4cac81SBjoern A. Zeeb */ 2363*6b4cac81SBjoern A. Zeeb skb = dev_alloc_skb(hw->extra_tx_headroom + m->m_pkthdr.len); 2364*6b4cac81SBjoern A. Zeeb if (skb == NULL) { 2365*6b4cac81SBjoern A. Zeeb printf("XXX ERROR %s: skb alloc failed\n", __func__); 2366*6b4cac81SBjoern A. Zeeb ieee80211_free_node(ni); 2367*6b4cac81SBjoern A. Zeeb m_freem(m); 2368*6b4cac81SBjoern A. Zeeb return; 2369*6b4cac81SBjoern A. Zeeb } 2370*6b4cac81SBjoern A. Zeeb skb_reserve(skb, hw->extra_tx_headroom); 2371*6b4cac81SBjoern A. Zeeb 2372*6b4cac81SBjoern A. Zeeb /* XXX-BZ we need a SKB version understanding mbuf. */ 2373*6b4cac81SBjoern A. Zeeb /* Save the mbuf for ieee80211_tx_complete(). */ 2374*6b4cac81SBjoern A. Zeeb skb->m_free_func = lkpi_ieee80211_free_skb_mbuf; 2375*6b4cac81SBjoern A. Zeeb skb->m = m; 2376*6b4cac81SBjoern A. Zeeb #if 0 2377*6b4cac81SBjoern A. Zeeb skb_put_data(skb, m->m_data, m->m_pkthdr.len); 2378*6b4cac81SBjoern A. Zeeb #else 2379*6b4cac81SBjoern A. Zeeb buf = skb_put(skb, m->m_pkthdr.len); 2380*6b4cac81SBjoern A. Zeeb m_copydata(m, 0, m->m_pkthdr.len, buf); 2381*6b4cac81SBjoern A. Zeeb #endif 2382*6b4cac81SBjoern A. Zeeb /* Save the ni. */ 2383*6b4cac81SBjoern A. Zeeb m->m_pkthdr.PH_loc.ptr = ni; 2384*6b4cac81SBjoern A. Zeeb 2385*6b4cac81SBjoern A. Zeeb lvif = VAP_TO_LVIF(ni->ni_vap); 2386*6b4cac81SBjoern A. Zeeb vif = LVIF_TO_VIF(lvif); 2387*6b4cac81SBjoern A. Zeeb 2388*6b4cac81SBjoern A. Zeeb /* XXX-BZ review this at some point [4] vs. [8] vs. [16](TID). */ 2389*6b4cac81SBjoern A. Zeeb ac = M_WME_GETAC(m); 2390*6b4cac81SBjoern A. Zeeb skb->priority = WME_AC_TO_TID(ac); 2391*6b4cac81SBjoern A. Zeeb ac = lkpi_ac_net_to_l80211(ac); 2392*6b4cac81SBjoern A. Zeeb skb_set_queue_mapping(skb, ac); 2393*6b4cac81SBjoern A. Zeeb 2394*6b4cac81SBjoern A. Zeeb info = IEEE80211_SKB_CB(skb); 2395*6b4cac81SBjoern A. Zeeb info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; 2396*6b4cac81SBjoern A. Zeeb /* Slight delay; probably only happens on scanning so fine? */ 2397*6b4cac81SBjoern A. Zeeb if (c == NULL || c == IEEE80211_CHAN_ANYC) 2398*6b4cac81SBjoern A. Zeeb c = ic->ic_curchan; 2399*6b4cac81SBjoern A. Zeeb info->band = lkpi_net80211_chan_to_nl80211_band(c); 2400*6b4cac81SBjoern A. Zeeb info->hw_queue = ac; /* XXX-BZ is this correct? */ 2401*6b4cac81SBjoern A. Zeeb if (m->m_flags & M_EAPOL) 2402*6b4cac81SBjoern A. Zeeb info->control.flags |= IEEE80211_TX_CTRL_PORT_CTRL_PROTO; 2403*6b4cac81SBjoern A. Zeeb info->control.vif = vif; 2404*6b4cac81SBjoern A. Zeeb /* XXX-BZ info->control.rates */ 2405*6b4cac81SBjoern A. Zeeb 2406*6b4cac81SBjoern A. Zeeb lsta = lkpi_find_lsta_by_ni(lvif, ni); 2407*6b4cac81SBjoern A. Zeeb if (lsta != NULL) { 2408*6b4cac81SBjoern A. Zeeb sta = LSTA_TO_STA(lsta); 2409*6b4cac81SBjoern A. Zeeb #ifdef TRY_HW_CRYPTO 2410*6b4cac81SBjoern A. Zeeb info->control.hw_key = lsta->kc; 2411*6b4cac81SBjoern A. Zeeb #endif 2412*6b4cac81SBjoern A. Zeeb } else { 2413*6b4cac81SBjoern A. Zeeb sta = NULL; 2414*6b4cac81SBjoern A. Zeeb } 2415*6b4cac81SBjoern A. Zeeb 2416*6b4cac81SBjoern A. Zeeb IMPROVE(); 2417*6b4cac81SBjoern A. Zeeb 2418*6b4cac81SBjoern A. Zeeb if (sta != NULL) { 2419*6b4cac81SBjoern A. Zeeb struct lkpi_txq *ltxq; 2420*6b4cac81SBjoern A. Zeeb 2421*6b4cac81SBjoern A. Zeeb ltxq = TXQ_TO_LTXQ(sta->txq[ac]); /* XXX-BZ re-check */ 2422*6b4cac81SBjoern A. Zeeb /* 2423*6b4cac81SBjoern A. Zeeb * We currently do not use queues but do direct TX. 2424*6b4cac81SBjoern A. Zeeb * The exception to the rule is initial packets, as we cannot 2425*6b4cac81SBjoern A. Zeeb * TX until queues are allocated (at least for iwlwifi). 2426*6b4cac81SBjoern A. Zeeb * So we wake_tx_queue in newstate and register any dequeue 2427*6b4cac81SBjoern A. Zeeb * calls. In the time until then we queue packets and 2428*6b4cac81SBjoern A. Zeeb * let the driver deal with them. 2429*6b4cac81SBjoern A. Zeeb */ 2430*6b4cac81SBjoern A. Zeeb if (!ltxq->seen_dequeue) { 2431*6b4cac81SBjoern A. Zeeb 2432*6b4cac81SBjoern A. Zeeb /* Prevent an ordering problem, likely other issues. */ 2433*6b4cac81SBjoern A. Zeeb while (!skb_queue_empty(<xq->skbq)) { 2434*6b4cac81SBjoern A. Zeeb struct sk_buff *skb2; 2435*6b4cac81SBjoern A. Zeeb 2436*6b4cac81SBjoern A. Zeeb skb2 = skb_dequeue(<xq->skbq); 2437*6b4cac81SBjoern A. Zeeb if (skb2 != NULL) { 2438*6b4cac81SBjoern A. Zeeb memset(&control, 0, sizeof(control)); 2439*6b4cac81SBjoern A. Zeeb control.sta = sta; 2440*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_tx(hw, &control, skb2); 2441*6b4cac81SBjoern A. Zeeb } 2442*6b4cac81SBjoern A. Zeeb } 2443*6b4cac81SBjoern A. Zeeb goto ops_tx; 2444*6b4cac81SBjoern A. Zeeb } 2445*6b4cac81SBjoern A. Zeeb if (0 && ltxq->seen_dequeue && skb_queue_empty(<xq->skbq)) 2446*6b4cac81SBjoern A. Zeeb goto ops_tx; 2447*6b4cac81SBjoern A. Zeeb 2448*6b4cac81SBjoern A. Zeeb skb_queue_tail(<xq->skbq, skb); 2449*6b4cac81SBjoern A. Zeeb if (debug_80211 & D80211_TRACE_TX) 2450*6b4cac81SBjoern A. Zeeb printf("%s:%d lsta %p sta %p ni %p %6D skb %p lxtq %p " 2451*6b4cac81SBjoern A. Zeeb "qlen %u WAKE_TX_Q ac %d prio %u qmap %u\n", 2452*6b4cac81SBjoern A. Zeeb __func__, __LINE__, lsta, sta, ni, 2453*6b4cac81SBjoern A. Zeeb ni->ni_macaddr, ":", skb, ltxq, 2454*6b4cac81SBjoern A. Zeeb skb_queue_len(<xq->skbq), ac, 2455*6b4cac81SBjoern A. Zeeb skb->priority, skb->qmap); 2456*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_wake_tx_queue(hw, sta->txq[ac]); /* XXX-BZ */ 2457*6b4cac81SBjoern A. Zeeb return; 2458*6b4cac81SBjoern A. Zeeb } 2459*6b4cac81SBjoern A. Zeeb 2460*6b4cac81SBjoern A. Zeeb ops_tx: 2461*6b4cac81SBjoern A. Zeeb if (debug_80211 & D80211_TRACE_TX) 2462*6b4cac81SBjoern A. Zeeb printf("%s:%d lsta %p sta %p ni %p %6D skb %p TX ac %d prio %u qmap %u\n", 2463*6b4cac81SBjoern A. Zeeb __func__, __LINE__, lsta, sta, ni, ni->ni_macaddr, ":", 2464*6b4cac81SBjoern A. Zeeb skb, ac, skb->priority, skb->qmap); 2465*6b4cac81SBjoern A. Zeeb memset(&control, 0, sizeof(control)); 2466*6b4cac81SBjoern A. Zeeb control.sta = sta; 2467*6b4cac81SBjoern A. Zeeb 2468*6b4cac81SBjoern A. Zeeb lkpi_80211_mo_tx(hw, &control, skb); 2469*6b4cac81SBjoern A. Zeeb return; 2470*6b4cac81SBjoern A. Zeeb } 2471*6b4cac81SBjoern A. Zeeb 2472*6b4cac81SBjoern A. Zeeb static void 2473*6b4cac81SBjoern A. Zeeb lkpi_80211_txq_task(void *ctx, int pending) 2474*6b4cac81SBjoern A. Zeeb { 2475*6b4cac81SBjoern A. Zeeb struct lkpi_sta *lsta; 2476*6b4cac81SBjoern A. Zeeb struct ieee80211_node *ni; 2477*6b4cac81SBjoern A. Zeeb struct mbufq mq; 2478*6b4cac81SBjoern A. Zeeb struct mbuf *m; 2479*6b4cac81SBjoern A. Zeeb 2480*6b4cac81SBjoern A. Zeeb lsta = ctx; 2481*6b4cac81SBjoern A. Zeeb ni = lsta->ni; 2482*6b4cac81SBjoern A. Zeeb 2483*6b4cac81SBjoern A. Zeeb if (debug_80211 & D80211_TRACE_TX) 2484*6b4cac81SBjoern A. Zeeb printf("%s:%d lsta %p ni %p %6D pending %d mbuf_qlen %d\n", 2485*6b4cac81SBjoern A. Zeeb __func__, __LINE__, lsta, ni, ni->ni_macaddr, ":", 2486*6b4cac81SBjoern A. Zeeb pending, mbufq_len(&lsta->txq)); 2487*6b4cac81SBjoern A. Zeeb 2488*6b4cac81SBjoern A. Zeeb mbufq_init(&mq, IFQ_MAXLEN); 2489*6b4cac81SBjoern A. Zeeb 2490*6b4cac81SBjoern A. Zeeb LKPI_80211_LSTA_LOCK(lsta); 2491*6b4cac81SBjoern A. Zeeb mbufq_concat(&mq, &lsta->txq); 2492*6b4cac81SBjoern A. Zeeb LKPI_80211_LSTA_UNLOCK(lsta); 2493*6b4cac81SBjoern A. Zeeb 2494*6b4cac81SBjoern A. Zeeb m = mbufq_dequeue(&mq); 2495*6b4cac81SBjoern A. Zeeb while (m != NULL) { 2496*6b4cac81SBjoern A. Zeeb lkpi_80211_txq_tx_one(lsta, m); 2497*6b4cac81SBjoern A. Zeeb m = mbufq_dequeue(&mq); 2498*6b4cac81SBjoern A. Zeeb } 2499*6b4cac81SBjoern A. Zeeb } 2500*6b4cac81SBjoern A. Zeeb 2501*6b4cac81SBjoern A. Zeeb static int 2502*6b4cac81SBjoern A. Zeeb lkpi_ic_transmit(struct ieee80211com *ic, struct mbuf *m) 2503*6b4cac81SBjoern A. Zeeb { 2504*6b4cac81SBjoern A. Zeeb 2505*6b4cac81SBjoern A. Zeeb /* XXX TODO */ 2506*6b4cac81SBjoern A. Zeeb IMPROVE(); 2507*6b4cac81SBjoern A. Zeeb 2508*6b4cac81SBjoern A. Zeeb /* Quick and dirty cheating hack. */ 2509*6b4cac81SBjoern A. Zeeb struct ieee80211_node *ni; 2510*6b4cac81SBjoern A. Zeeb 2511*6b4cac81SBjoern A. Zeeb ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 2512*6b4cac81SBjoern A. Zeeb return (lkpi_ic_raw_xmit(ni, m, NULL)); 2513*6b4cac81SBjoern A. Zeeb } 2514*6b4cac81SBjoern A. Zeeb 2515*6b4cac81SBjoern A. Zeeb static void 2516*6b4cac81SBjoern A. Zeeb lkpi_ic_getradiocaps(struct ieee80211com *ic, int maxchan, 2517*6b4cac81SBjoern A. Zeeb int *n, struct ieee80211_channel *c) 2518*6b4cac81SBjoern A. Zeeb { 2519*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 2520*6b4cac81SBjoern A. Zeeb struct ieee80211_hw *hw; 2521*6b4cac81SBjoern A. Zeeb struct linuxkpi_ieee80211_channel *channels; 2522*6b4cac81SBjoern A. Zeeb uint8_t bands[IEEE80211_MODE_BYTES]; 2523*6b4cac81SBjoern A. Zeeb int chan_flags, error, i, nchans; 2524*6b4cac81SBjoern A. Zeeb 2525*6b4cac81SBjoern A. Zeeb /* Channels */ 2526*6b4cac81SBjoern A. Zeeb lhw = ic->ic_softc; 2527*6b4cac81SBjoern A. Zeeb hw = LHW_TO_HW(lhw); 2528*6b4cac81SBjoern A. Zeeb 2529*6b4cac81SBjoern A. Zeeb /* NL80211_BAND_2GHZ */ 2530*6b4cac81SBjoern A. Zeeb nchans = 0; 2531*6b4cac81SBjoern A. Zeeb if (hw->wiphy->bands[NL80211_BAND_2GHZ] != NULL) 2532*6b4cac81SBjoern A. Zeeb nchans = hw->wiphy->bands[NL80211_BAND_2GHZ]->n_channels; 2533*6b4cac81SBjoern A. Zeeb if (nchans > 0) { 2534*6b4cac81SBjoern A. Zeeb memset(bands, 0, sizeof(bands)); 2535*6b4cac81SBjoern A. Zeeb chan_flags = 0; 2536*6b4cac81SBjoern A. Zeeb setbit(bands, IEEE80211_MODE_11B); 2537*6b4cac81SBjoern A. Zeeb /* XXX-BZ unclear how to check for 11g. */ 2538*6b4cac81SBjoern A. Zeeb setbit(bands, IEEE80211_MODE_11G); 2539*6b4cac81SBjoern A. Zeeb #ifdef __notyet__ 2540*6b4cac81SBjoern A. Zeeb if (hw->wiphy->bands[NL80211_BAND_2GHZ]->ht_cap.ht_supported) { 2541*6b4cac81SBjoern A. Zeeb setbit(bands, IEEE80211_MODE_11NG); 2542*6b4cac81SBjoern A. Zeeb chan_flags |= NET80211_CBW_FLAG_HT40; 2543*6b4cac81SBjoern A. Zeeb } 2544*6b4cac81SBjoern A. Zeeb #endif 2545*6b4cac81SBjoern A. Zeeb 2546*6b4cac81SBjoern A. Zeeb channels = hw->wiphy->bands[NL80211_BAND_2GHZ]->channels; 2547*6b4cac81SBjoern A. Zeeb for (i = 0; i < nchans; i++) { 2548*6b4cac81SBjoern A. Zeeb uint32_t nflags = 0; 2549*6b4cac81SBjoern A. Zeeb int cflags = chan_flags; 2550*6b4cac81SBjoern A. Zeeb 2551*6b4cac81SBjoern A. Zeeb if (channels[i].flags & IEEE80211_CHAN_DISABLED) { 2552*6b4cac81SBjoern A. Zeeb printf("%s: %s: Skipping disabled chan " 2553*6b4cac81SBjoern A. Zeeb "[%u/%u/%#x]\n", ic->ic_name, __func__, 2554*6b4cac81SBjoern A. Zeeb channels[i].hw_value, 2555*6b4cac81SBjoern A. Zeeb channels[i].center_freq, channels[i].flags); 2556*6b4cac81SBjoern A. Zeeb continue; 2557*6b4cac81SBjoern A. Zeeb } 2558*6b4cac81SBjoern A. Zeeb if (channels[i].flags & IEEE80211_CHAN_NO_IR) 2559*6b4cac81SBjoern A. Zeeb nflags |= (IEEE80211_CHAN_NOADHOC|IEEE80211_CHAN_PASSIVE); 2560*6b4cac81SBjoern A. Zeeb if (channels[i].flags & IEEE80211_CHAN_RADAR) 2561*6b4cac81SBjoern A. Zeeb nflags |= IEEE80211_CHAN_DFS; 2562*6b4cac81SBjoern A. Zeeb if (channels[i].flags & IEEE80211_CHAN_NO_160MHZ) 2563*6b4cac81SBjoern A. Zeeb cflags &= ~(NET80211_CBW_FLAG_VHT160|NET80211_CBW_FLAG_VHT80P80); 2564*6b4cac81SBjoern A. Zeeb if (channels[i].flags & IEEE80211_CHAN_NO_80MHZ) 2565*6b4cac81SBjoern A. Zeeb cflags &= ~NET80211_CBW_FLAG_VHT80; 2566*6b4cac81SBjoern A. Zeeb /* XXX how to map the remaining enum ieee80211_channel_flags? */ 2567*6b4cac81SBjoern A. Zeeb if (channels[i].flags & IEEE80211_CHAN_NO_HT40) 2568*6b4cac81SBjoern A. Zeeb cflags &= ~NET80211_CBW_FLAG_HT40; 2569*6b4cac81SBjoern A. Zeeb 2570*6b4cac81SBjoern A. Zeeb error = ieee80211_add_channel_cbw(c, maxchan, n, 2571*6b4cac81SBjoern A. Zeeb channels[i].hw_value, channels[i].center_freq, 2572*6b4cac81SBjoern A. Zeeb channels[i].max_power, 2573*6b4cac81SBjoern A. Zeeb nflags, bands, chan_flags); 2574*6b4cac81SBjoern A. Zeeb if (error != 0) { 2575*6b4cac81SBjoern A. Zeeb printf("%s: %s: Adding chan %u/%u/%#x/%#x/%#x/%#x " 2576*6b4cac81SBjoern A. Zeeb "returned error %d\n", ic->ic_name, 2577*6b4cac81SBjoern A. Zeeb __func__, channels[i].hw_value, 2578*6b4cac81SBjoern A. Zeeb channels[i].center_freq, channels[i].flags, 2579*6b4cac81SBjoern A. Zeeb nflags, chan_flags, cflags, error); 2580*6b4cac81SBjoern A. Zeeb break; 2581*6b4cac81SBjoern A. Zeeb } 2582*6b4cac81SBjoern A. Zeeb } 2583*6b4cac81SBjoern A. Zeeb } 2584*6b4cac81SBjoern A. Zeeb 2585*6b4cac81SBjoern A. Zeeb /* NL80211_BAND_5GHZ */ 2586*6b4cac81SBjoern A. Zeeb nchans = 0; 2587*6b4cac81SBjoern A. Zeeb if (hw->wiphy->bands[NL80211_BAND_5GHZ] != NULL) 2588*6b4cac81SBjoern A. Zeeb nchans = hw->wiphy->bands[NL80211_BAND_5GHZ]->n_channels; 2589*6b4cac81SBjoern A. Zeeb if (nchans > 0) { 2590*6b4cac81SBjoern A. Zeeb memset(bands, 0, sizeof(bands)); 2591*6b4cac81SBjoern A. Zeeb chan_flags = 0; 2592*6b4cac81SBjoern A. Zeeb setbit(bands, IEEE80211_MODE_11A); 2593*6b4cac81SBjoern A. Zeeb #ifdef __not_yet__ 2594*6b4cac81SBjoern A. Zeeb if (hw->wiphy->bands[NL80211_BAND_5GHZ]->ht_cap.ht_supported) { 2595*6b4cac81SBjoern A. Zeeb setbit(bands, IEEE80211_MODE_11NA); 2596*6b4cac81SBjoern A. Zeeb chan_flags |= NET80211_CBW_FLAG_HT40; 2597*6b4cac81SBjoern A. Zeeb } 2598*6b4cac81SBjoern A. Zeeb if (hw->wiphy->bands[NL80211_BAND_5GHZ]->vht_cap.vht_supported){ 2599*6b4cac81SBjoern A. Zeeb 2600*6b4cac81SBjoern A. Zeeb ic->ic_flags_ext |= IEEE80211_FEXT_VHT; 2601*6b4cac81SBjoern A. Zeeb ic->ic_vhtcaps = 2602*6b4cac81SBjoern A. Zeeb hw->wiphy->bands[NL80211_BAND_5GHZ]->vht_cap.cap; 2603*6b4cac81SBjoern A. Zeeb 2604*6b4cac81SBjoern A. Zeeb setbit(bands, IEEE80211_MODE_VHT_5GHZ); 2605*6b4cac81SBjoern A. Zeeb chan_flags |= NET80211_CBW_FLAG_VHT80; 2606*6b4cac81SBjoern A. Zeeb if (IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_IS_160MHZ( 2607*6b4cac81SBjoern A. Zeeb ic->ic_vhtcaps)) 2608*6b4cac81SBjoern A. Zeeb chan_flags |= NET80211_CBW_FLAG_VHT160; 2609*6b4cac81SBjoern A. Zeeb if (IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_IS_160_80P80MHZ( 2610*6b4cac81SBjoern A. Zeeb ic->ic_vhtcaps)) 2611*6b4cac81SBjoern A. Zeeb chan_flags |= NET80211_CBW_FLAG_VHT80P80; 2612*6b4cac81SBjoern A. Zeeb } 2613*6b4cac81SBjoern A. Zeeb #endif 2614*6b4cac81SBjoern A. Zeeb 2615*6b4cac81SBjoern A. Zeeb channels = hw->wiphy->bands[NL80211_BAND_5GHZ]->channels; 2616*6b4cac81SBjoern A. Zeeb for (i = 0; i < nchans; i++) { 2617*6b4cac81SBjoern A. Zeeb uint32_t nflags = 0; 2618*6b4cac81SBjoern A. Zeeb int cflags = chan_flags; 2619*6b4cac81SBjoern A. Zeeb 2620*6b4cac81SBjoern A. Zeeb if (channels[i].flags & IEEE80211_CHAN_DISABLED) { 2621*6b4cac81SBjoern A. Zeeb printf("%s: %s: Skipping disabled chan " 2622*6b4cac81SBjoern A. Zeeb "[%u/%u/%#x]\n", ic->ic_name, __func__, 2623*6b4cac81SBjoern A. Zeeb channels[i].hw_value, 2624*6b4cac81SBjoern A. Zeeb channels[i].center_freq, channels[i].flags); 2625*6b4cac81SBjoern A. Zeeb continue; 2626*6b4cac81SBjoern A. Zeeb } 2627*6b4cac81SBjoern A. Zeeb if (channels[i].flags & IEEE80211_CHAN_NO_IR) 2628*6b4cac81SBjoern A. Zeeb nflags |= (IEEE80211_CHAN_NOADHOC|IEEE80211_CHAN_PASSIVE); 2629*6b4cac81SBjoern A. Zeeb if (channels[i].flags & IEEE80211_CHAN_RADAR) 2630*6b4cac81SBjoern A. Zeeb nflags |= IEEE80211_CHAN_DFS; 2631*6b4cac81SBjoern A. Zeeb if (channels[i].flags & IEEE80211_CHAN_NO_160MHZ) 2632*6b4cac81SBjoern A. Zeeb cflags &= ~(NET80211_CBW_FLAG_VHT160|NET80211_CBW_FLAG_VHT80P80); 2633*6b4cac81SBjoern A. Zeeb if (channels[i].flags & IEEE80211_CHAN_NO_80MHZ) 2634*6b4cac81SBjoern A. Zeeb cflags &= ~NET80211_CBW_FLAG_VHT80; 2635*6b4cac81SBjoern A. Zeeb /* XXX hwo to map the remaining enum ieee80211_channel_flags? */ 2636*6b4cac81SBjoern A. Zeeb if (channels[i].flags & IEEE80211_CHAN_NO_HT40) 2637*6b4cac81SBjoern A. Zeeb cflags &= ~NET80211_CBW_FLAG_HT40; 2638*6b4cac81SBjoern A. Zeeb 2639*6b4cac81SBjoern A. Zeeb error = ieee80211_add_channel_cbw(c, maxchan, n, 2640*6b4cac81SBjoern A. Zeeb channels[i].hw_value, channels[i].center_freq, 2641*6b4cac81SBjoern A. Zeeb channels[i].max_power, 2642*6b4cac81SBjoern A. Zeeb nflags, bands, chan_flags); 2643*6b4cac81SBjoern A. Zeeb if (error != 0) { 2644*6b4cac81SBjoern A. Zeeb printf("%s: %s: Adding chan %u/%u/%#x/%#x/%#x/%#x " 2645*6b4cac81SBjoern A. Zeeb "returned error %d\n", ic->ic_name, 2646*6b4cac81SBjoern A. Zeeb __func__, channels[i].hw_value, 2647*6b4cac81SBjoern A. Zeeb channels[i].center_freq, channels[i].flags, 2648*6b4cac81SBjoern A. Zeeb nflags, chan_flags, cflags, error); 2649*6b4cac81SBjoern A. Zeeb break; 2650*6b4cac81SBjoern A. Zeeb } 2651*6b4cac81SBjoern A. Zeeb } 2652*6b4cac81SBjoern A. Zeeb } 2653*6b4cac81SBjoern A. Zeeb } 2654*6b4cac81SBjoern A. Zeeb 2655*6b4cac81SBjoern A. Zeeb static void * 2656*6b4cac81SBjoern A. Zeeb lkpi_ieee80211_ifalloc(void) 2657*6b4cac81SBjoern A. Zeeb { 2658*6b4cac81SBjoern A. Zeeb struct ieee80211com *ic; 2659*6b4cac81SBjoern A. Zeeb 2660*6b4cac81SBjoern A. Zeeb ic = malloc(sizeof(*ic), M_LKPI80211, M_WAITOK | M_ZERO); 2661*6b4cac81SBjoern A. Zeeb if (ic == NULL) 2662*6b4cac81SBjoern A. Zeeb return (NULL); 2663*6b4cac81SBjoern A. Zeeb 2664*6b4cac81SBjoern A. Zeeb /* Setting these happens later when we have device information. */ 2665*6b4cac81SBjoern A. Zeeb ic->ic_softc = NULL; 2666*6b4cac81SBjoern A. Zeeb ic->ic_name = "linuxkpi"; 2667*6b4cac81SBjoern A. Zeeb 2668*6b4cac81SBjoern A. Zeeb return (ic); 2669*6b4cac81SBjoern A. Zeeb } 2670*6b4cac81SBjoern A. Zeeb 2671*6b4cac81SBjoern A. Zeeb struct ieee80211_hw * 2672*6b4cac81SBjoern A. Zeeb linuxkpi_ieee80211_alloc_hw(size_t priv_len, const struct ieee80211_ops *ops) 2673*6b4cac81SBjoern A. Zeeb { 2674*6b4cac81SBjoern A. Zeeb struct ieee80211_hw *hw; 2675*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 2676*6b4cac81SBjoern A. Zeeb struct wiphy *wiphy; 2677*6b4cac81SBjoern A. Zeeb 2678*6b4cac81SBjoern A. Zeeb /* Get us and the driver data also allocated. */ 2679*6b4cac81SBjoern A. Zeeb wiphy = wiphy_new(&linuxkpi_mac80211cfgops, sizeof(*lhw) + priv_len); 2680*6b4cac81SBjoern A. Zeeb if (wiphy == NULL) 2681*6b4cac81SBjoern A. Zeeb return (NULL); 2682*6b4cac81SBjoern A. Zeeb 2683*6b4cac81SBjoern A. Zeeb lhw = wiphy_priv(wiphy); 2684*6b4cac81SBjoern A. Zeeb lhw->ops = ops; 2685*6b4cac81SBjoern A. Zeeb lhw->workq = alloc_ordered_workqueue(wiphy_name(wiphy), 0); 2686*6b4cac81SBjoern A. Zeeb if (lhw->workq == NULL) { 2687*6b4cac81SBjoern A. Zeeb wiphy_free(wiphy); 2688*6b4cac81SBjoern A. Zeeb return (NULL); 2689*6b4cac81SBjoern A. Zeeb } 2690*6b4cac81SBjoern A. Zeeb mtx_init(&lhw->mtx, "lhw", NULL, MTX_DEF | MTX_RECURSE); 2691*6b4cac81SBjoern A. Zeeb TAILQ_INIT(&lhw->lvif_head); 2692*6b4cac81SBjoern A. Zeeb 2693*6b4cac81SBjoern A. Zeeb /* 2694*6b4cac81SBjoern A. Zeeb * XXX-BZ TODO make sure there is a "_null" function to all ops 2695*6b4cac81SBjoern A. Zeeb * not initialized. 2696*6b4cac81SBjoern A. Zeeb */ 2697*6b4cac81SBjoern A. Zeeb hw = LHW_TO_HW(lhw); 2698*6b4cac81SBjoern A. Zeeb hw->wiphy = wiphy; 2699*6b4cac81SBjoern A. Zeeb hw->priv = (void *)(lhw + 1); 2700*6b4cac81SBjoern A. Zeeb 2701*6b4cac81SBjoern A. Zeeb /* BSD Specific. */ 2702*6b4cac81SBjoern A. Zeeb lhw->ic = lkpi_ieee80211_ifalloc(); 2703*6b4cac81SBjoern A. Zeeb if (lhw->ic == NULL) { 2704*6b4cac81SBjoern A. Zeeb ieee80211_free_hw(hw); 2705*6b4cac81SBjoern A. Zeeb return (NULL); 2706*6b4cac81SBjoern A. Zeeb } 2707*6b4cac81SBjoern A. Zeeb 2708*6b4cac81SBjoern A. Zeeb IMPROVE(); 2709*6b4cac81SBjoern A. Zeeb 2710*6b4cac81SBjoern A. Zeeb return (hw); 2711*6b4cac81SBjoern A. Zeeb } 2712*6b4cac81SBjoern A. Zeeb 2713*6b4cac81SBjoern A. Zeeb void 2714*6b4cac81SBjoern A. Zeeb linuxkpi_ieee80211_iffree(struct ieee80211_hw *hw) 2715*6b4cac81SBjoern A. Zeeb { 2716*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 2717*6b4cac81SBjoern A. Zeeb 2718*6b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 2719*6b4cac81SBjoern A. Zeeb free(lhw->ic, M_LKPI80211); 2720*6b4cac81SBjoern A. Zeeb lhw->ic = NULL; 2721*6b4cac81SBjoern A. Zeeb 2722*6b4cac81SBjoern A. Zeeb /* Cleanup more of lhw here or in wiphy_free()? */ 2723*6b4cac81SBjoern A. Zeeb mtx_destroy(&lhw->mtx); 2724*6b4cac81SBjoern A. Zeeb IMPROVE(); 2725*6b4cac81SBjoern A. Zeeb } 2726*6b4cac81SBjoern A. Zeeb 2727*6b4cac81SBjoern A. Zeeb void 2728*6b4cac81SBjoern A. Zeeb linuxkpi_set_ieee80211_dev(struct ieee80211_hw *hw, char *name) 2729*6b4cac81SBjoern A. Zeeb { 2730*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 2731*6b4cac81SBjoern A. Zeeb struct ieee80211com *ic; 2732*6b4cac81SBjoern A. Zeeb 2733*6b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 2734*6b4cac81SBjoern A. Zeeb ic = lhw->ic; 2735*6b4cac81SBjoern A. Zeeb 2736*6b4cac81SBjoern A. Zeeb /* Now set a proper name before ieee80211_ifattach(). */ 2737*6b4cac81SBjoern A. Zeeb ic->ic_softc = lhw; 2738*6b4cac81SBjoern A. Zeeb ic->ic_name = name; 2739*6b4cac81SBjoern A. Zeeb 2740*6b4cac81SBjoern A. Zeeb /* XXX-BZ do we also need to set wiphy name? */ 2741*6b4cac81SBjoern A. Zeeb } 2742*6b4cac81SBjoern A. Zeeb 2743*6b4cac81SBjoern A. Zeeb struct ieee80211_hw * 2744*6b4cac81SBjoern A. Zeeb linuxkpi_wiphy_to_ieee80211_hw(struct wiphy *wiphy) 2745*6b4cac81SBjoern A. Zeeb { 2746*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 2747*6b4cac81SBjoern A. Zeeb 2748*6b4cac81SBjoern A. Zeeb lhw = wiphy_priv(wiphy); 2749*6b4cac81SBjoern A. Zeeb return (LHW_TO_HW(lhw)); 2750*6b4cac81SBjoern A. Zeeb } 2751*6b4cac81SBjoern A. Zeeb 2752*6b4cac81SBjoern A. Zeeb static void 2753*6b4cac81SBjoern A. Zeeb lkpi_radiotap_attach(struct lkpi_hw *lhw) 2754*6b4cac81SBjoern A. Zeeb { 2755*6b4cac81SBjoern A. Zeeb struct ieee80211com *ic; 2756*6b4cac81SBjoern A. Zeeb 2757*6b4cac81SBjoern A. Zeeb ic = lhw->ic; 2758*6b4cac81SBjoern A. Zeeb ieee80211_radiotap_attach(ic, 2759*6b4cac81SBjoern A. Zeeb &lhw->rtap_tx.wt_ihdr, sizeof(lhw->rtap_tx), 2760*6b4cac81SBjoern A. Zeeb LKPI_RTAP_TX_FLAGS_PRESENT, 2761*6b4cac81SBjoern A. Zeeb &lhw->rtap_rx.wr_ihdr, sizeof(lhw->rtap_rx), 2762*6b4cac81SBjoern A. Zeeb LKPI_RTAP_RX_FLAGS_PRESENT); 2763*6b4cac81SBjoern A. Zeeb } 2764*6b4cac81SBjoern A. Zeeb 2765*6b4cac81SBjoern A. Zeeb void 2766*6b4cac81SBjoern A. Zeeb linuxkpi_ieee80211_ifattach(struct ieee80211_hw *hw) 2767*6b4cac81SBjoern A. Zeeb { 2768*6b4cac81SBjoern A. Zeeb struct ieee80211com *ic; 2769*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 2770*6b4cac81SBjoern A. Zeeb #ifdef TRY_HW_CRYPTO 2771*6b4cac81SBjoern A. Zeeb int i; 2772*6b4cac81SBjoern A. Zeeb #endif 2773*6b4cac81SBjoern A. Zeeb 2774*6b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 2775*6b4cac81SBjoern A. Zeeb ic = lhw->ic; 2776*6b4cac81SBjoern A. Zeeb 2777*6b4cac81SBjoern A. Zeeb /* XXX-BZ figure this out how they count his... */ 2778*6b4cac81SBjoern A. Zeeb if (!is_zero_ether_addr(hw->wiphy->perm_addr)) { 2779*6b4cac81SBjoern A. Zeeb IEEE80211_ADDR_COPY(ic->ic_macaddr, 2780*6b4cac81SBjoern A. Zeeb hw->wiphy->perm_addr); 2781*6b4cac81SBjoern A. Zeeb } else if (hw->wiphy->n_addresses > 0) { 2782*6b4cac81SBjoern A. Zeeb /* We take the first one. */ 2783*6b4cac81SBjoern A. Zeeb IEEE80211_ADDR_COPY(ic->ic_macaddr, 2784*6b4cac81SBjoern A. Zeeb hw->wiphy->addresses[0].addr); 2785*6b4cac81SBjoern A. Zeeb } else { 2786*6b4cac81SBjoern A. Zeeb ic_printf(ic, "%s: warning, no hardware address!\n", __func__); 2787*6b4cac81SBjoern A. Zeeb } 2788*6b4cac81SBjoern A. Zeeb 2789*6b4cac81SBjoern A. Zeeb ic->ic_headroom = hw->extra_tx_headroom; 2790*6b4cac81SBjoern A. Zeeb 2791*6b4cac81SBjoern A. Zeeb ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ 2792*6b4cac81SBjoern A. Zeeb ic->ic_opmode = IEEE80211_M_STA; 2793*6b4cac81SBjoern A. Zeeb 2794*6b4cac81SBjoern A. Zeeb /* Set device capabilities. */ 2795*6b4cac81SBjoern A. Zeeb /* XXX-BZ we need to get these from linux80211/drivers and convert. */ 2796*6b4cac81SBjoern A. Zeeb ic->ic_caps = 2797*6b4cac81SBjoern A. Zeeb IEEE80211_C_STA | 2798*6b4cac81SBjoern A. Zeeb IEEE80211_C_MONITOR | 2799*6b4cac81SBjoern A. Zeeb IEEE80211_C_WPA | /* WPA/RSN */ 2800*6b4cac81SBjoern A. Zeeb IEEE80211_C_WME | 2801*6b4cac81SBjoern A. Zeeb #if 0 2802*6b4cac81SBjoern A. Zeeb IEEE80211_C_PMGT | 2803*6b4cac81SBjoern A. Zeeb #endif 2804*6b4cac81SBjoern A. Zeeb IEEE80211_C_SHSLOT | /* short slot time supported */ 2805*6b4cac81SBjoern A. Zeeb IEEE80211_C_SHPREAMBLE /* short preamble supported */ 2806*6b4cac81SBjoern A. Zeeb ; 2807*6b4cac81SBjoern A. Zeeb #if 0 2808*6b4cac81SBjoern A. Zeeb /* Scanning is a different kind of beast to re-work. */ 2809*6b4cac81SBjoern A. Zeeb ic->ic_caps |= IEEE80211_C_BGSCAN; 2810*6b4cac81SBjoern A. Zeeb #endif 2811*6b4cac81SBjoern A. Zeeb if (lhw->ops->hw_scan && 2812*6b4cac81SBjoern A. Zeeb ieee80211_hw_check(hw, SINGLE_SCAN_ON_ALL_BANDS)) { 2813*6b4cac81SBjoern A. Zeeb /* Advertise full-offload scanning */ 2814*6b4cac81SBjoern A. Zeeb ic->ic_flags_ext |= IEEE80211_FEXT_SCAN_OFFLOAD; 2815*6b4cac81SBjoern A. Zeeb } 2816*6b4cac81SBjoern A. Zeeb 2817*6b4cac81SBjoern A. Zeeb #ifdef __notyet__ 2818*6b4cac81SBjoern A. Zeeb ic->ic_htcaps = IEEE80211_HTC_HT /* HT operation */ 2819*6b4cac81SBjoern A. Zeeb | IEEE80211_HTC_AMPDU /* A-MPDU tx/rx */ 2820*6b4cac81SBjoern A. Zeeb | IEEE80211_HTC_AMSDU /* A-MSDU tx/rx */ 2821*6b4cac81SBjoern A. Zeeb | IEEE80211_HTCAP_MAXAMSDU_3839 2822*6b4cac81SBjoern A. Zeeb /* max A-MSDU length */ 2823*6b4cac81SBjoern A. Zeeb | IEEE80211_HTCAP_SMPS_OFF; /* SM power save off */ 2824*6b4cac81SBjoern A. Zeeb ic->ic_htcaps |= IEEE80211_HTCAP_SHORTGI20; 2825*6b4cac81SBjoern A. Zeeb ic->ic_htcaps |= IEEE80211_HTCAP_CHWIDTH40 | IEEE80211_HTCAP_SHORTGI40; 2826*6b4cac81SBjoern A. Zeeb ic->ic_htcaps |= IEEE80211_HTCAP_TXSTBC; 2827*6b4cac81SBjoern A. Zeeb #endif 2828*6b4cac81SBjoern A. Zeeb 2829*6b4cac81SBjoern A. Zeeb ic->ic_cryptocaps = 0; 2830*6b4cac81SBjoern A. Zeeb #ifdef TRY_HW_CRYPTO 2831*6b4cac81SBjoern A. Zeeb if (hw->wiphy->n_cipher_suites > 0) { 2832*6b4cac81SBjoern A. Zeeb for (i = 0; i < hw->wiphy->n_cipher_suites; i++) 2833*6b4cac81SBjoern A. Zeeb ic->ic_cryptocaps |= lkpi_l80211_to_net80211_cyphers( 2834*6b4cac81SBjoern A. Zeeb hw->wiphy->cipher_suites[i]); 2835*6b4cac81SBjoern A. Zeeb } 2836*6b4cac81SBjoern A. Zeeb #endif 2837*6b4cac81SBjoern A. Zeeb 2838*6b4cac81SBjoern A. Zeeb lkpi_ic_getradiocaps(ic, IEEE80211_CHAN_MAX, &ic->ic_nchans, 2839*6b4cac81SBjoern A. Zeeb ic->ic_channels); 2840*6b4cac81SBjoern A. Zeeb 2841*6b4cac81SBjoern A. Zeeb ieee80211_ifattach(ic); 2842*6b4cac81SBjoern A. Zeeb 2843*6b4cac81SBjoern A. Zeeb ic->ic_update_mcast = lkpi_ic_update_mcast; 2844*6b4cac81SBjoern A. Zeeb ic->ic_update_promisc = lkpi_ic_update_promisc; 2845*6b4cac81SBjoern A. Zeeb ic->ic_update_chw = lkpi_ic_update_chw; 2846*6b4cac81SBjoern A. Zeeb ic->ic_parent = lkpi_ic_parent; 2847*6b4cac81SBjoern A. Zeeb ic->ic_scan_start = lkpi_ic_scan_start; 2848*6b4cac81SBjoern A. Zeeb ic->ic_scan_end = lkpi_ic_scan_end; 2849*6b4cac81SBjoern A. Zeeb if (lhw->ops->hw_scan && 2850*6b4cac81SBjoern A. Zeeb ieee80211_hw_check(hw, SINGLE_SCAN_ON_ALL_BANDS)) 2851*6b4cac81SBjoern A. Zeeb ic->ic_scan_curchan = lkpi_ic_scan_curchan_nada; 2852*6b4cac81SBjoern A. Zeeb ic->ic_set_channel = lkpi_ic_set_channel; 2853*6b4cac81SBjoern A. Zeeb ic->ic_transmit = lkpi_ic_transmit; 2854*6b4cac81SBjoern A. Zeeb ic->ic_raw_xmit = lkpi_ic_raw_xmit; 2855*6b4cac81SBjoern A. Zeeb ic->ic_vap_create = lkpi_ic_vap_create; 2856*6b4cac81SBjoern A. Zeeb ic->ic_vap_delete = lkpi_ic_vap_delete; 2857*6b4cac81SBjoern A. Zeeb ic->ic_getradiocaps = lkpi_ic_getradiocaps; 2858*6b4cac81SBjoern A. Zeeb ic->ic_wme.wme_update = lkpi_ic_wme_update; 2859*6b4cac81SBjoern A. Zeeb 2860*6b4cac81SBjoern A. Zeeb lhw->ic_node_alloc = ic->ic_node_alloc; 2861*6b4cac81SBjoern A. Zeeb ic->ic_node_alloc = lkpi_ic_node_alloc; 2862*6b4cac81SBjoern A. Zeeb lhw->ic_node_init = ic->ic_node_init; 2863*6b4cac81SBjoern A. Zeeb ic->ic_node_init = lkpi_ic_node_init; 2864*6b4cac81SBjoern A. Zeeb lhw->ic_node_cleanup = ic->ic_node_cleanup; 2865*6b4cac81SBjoern A. Zeeb ic->ic_node_cleanup = lkpi_ic_node_cleanup; 2866*6b4cac81SBjoern A. Zeeb lhw->ic_node_free = ic->ic_node_free; 2867*6b4cac81SBjoern A. Zeeb ic->ic_node_free = lkpi_ic_node_free; 2868*6b4cac81SBjoern A. Zeeb 2869*6b4cac81SBjoern A. Zeeb lkpi_radiotap_attach(lhw); 2870*6b4cac81SBjoern A. Zeeb 2871*6b4cac81SBjoern A. Zeeb if (bootverbose) 2872*6b4cac81SBjoern A. Zeeb ieee80211_announce(ic); 2873*6b4cac81SBjoern A. Zeeb } 2874*6b4cac81SBjoern A. Zeeb 2875*6b4cac81SBjoern A. Zeeb void 2876*6b4cac81SBjoern A. Zeeb linuxkpi_ieee80211_ifdetach(struct ieee80211_hw *hw) 2877*6b4cac81SBjoern A. Zeeb { 2878*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 2879*6b4cac81SBjoern A. Zeeb struct ieee80211com *ic; 2880*6b4cac81SBjoern A. Zeeb 2881*6b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 2882*6b4cac81SBjoern A. Zeeb ic = lhw->ic; 2883*6b4cac81SBjoern A. Zeeb ieee80211_ifdetach(ic); 2884*6b4cac81SBjoern A. Zeeb } 2885*6b4cac81SBjoern A. Zeeb 2886*6b4cac81SBjoern A. Zeeb void 2887*6b4cac81SBjoern A. Zeeb linuxkpi_ieee80211_iterate_interfaces(struct ieee80211_hw *hw, 2888*6b4cac81SBjoern A. Zeeb enum ieee80211_iface_iter flags, 2889*6b4cac81SBjoern A. Zeeb void(*iterfunc)(void *, uint8_t *, struct ieee80211_vif *), 2890*6b4cac81SBjoern A. Zeeb void *arg) 2891*6b4cac81SBjoern A. Zeeb { 2892*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 2893*6b4cac81SBjoern A. Zeeb struct lkpi_vif *lvif; 2894*6b4cac81SBjoern A. Zeeb struct ieee80211_vif *vif; 2895*6b4cac81SBjoern A. Zeeb bool active, atomic; 2896*6b4cac81SBjoern A. Zeeb 2897*6b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 2898*6b4cac81SBjoern A. Zeeb 2899*6b4cac81SBjoern A. Zeeb if (flags & ~(IEEE80211_IFACE_ITER_NORMAL| 2900*6b4cac81SBjoern A. Zeeb IEEE80211_IFACE_ITER_RESUME_ALL| 2901*6b4cac81SBjoern A. Zeeb IEEE80211_IFACE_ITER__ACTIVE|IEEE80211_IFACE_ITER__ATOMIC)) { 2902*6b4cac81SBjoern A. Zeeb ic_printf(lhw->ic, "XXX TODO %s flags(%#x) not yet supported.\n", 2903*6b4cac81SBjoern A. Zeeb __func__, flags); 2904*6b4cac81SBjoern A. Zeeb } 2905*6b4cac81SBjoern A. Zeeb 2906*6b4cac81SBjoern A. Zeeb active = (flags & IEEE80211_IFACE_ITER__ACTIVE) != 0; 2907*6b4cac81SBjoern A. Zeeb atomic = (flags & IEEE80211_IFACE_ITER__ATOMIC) != 0; 2908*6b4cac81SBjoern A. Zeeb 2909*6b4cac81SBjoern A. Zeeb if (atomic) 2910*6b4cac81SBjoern A. Zeeb LKPI_80211_LHW_LOCK(lhw); 2911*6b4cac81SBjoern A. Zeeb TAILQ_FOREACH(lvif, &lhw->lvif_head, lvif_entry) { 2912*6b4cac81SBjoern A. Zeeb struct ieee80211vap *vap; 2913*6b4cac81SBjoern A. Zeeb 2914*6b4cac81SBjoern A. Zeeb vif = LVIF_TO_VIF(lvif); 2915*6b4cac81SBjoern A. Zeeb 2916*6b4cac81SBjoern A. Zeeb /* 2917*6b4cac81SBjoern A. Zeeb * If we want "active" interfaces, we need to distinguish on 2918*6b4cac81SBjoern A. Zeeb * whether the driver knows about them or not to be able to 2919*6b4cac81SBjoern A. Zeeb * handle the "resume" case correctly. Skip the ones the 2920*6b4cac81SBjoern A. Zeeb * driver does not know about. 2921*6b4cac81SBjoern A. Zeeb */ 2922*6b4cac81SBjoern A. Zeeb if (active && !lvif->added_to_drv && 2923*6b4cac81SBjoern A. Zeeb (flags & IEEE80211_IFACE_ITER_RESUME_ALL) != 0) 2924*6b4cac81SBjoern A. Zeeb continue; 2925*6b4cac81SBjoern A. Zeeb 2926*6b4cac81SBjoern A. Zeeb /* 2927*6b4cac81SBjoern A. Zeeb * Run the iterator function if we are either not asking 2928*6b4cac81SBjoern A. Zeeb * asking for active only or if the VAP is "running". 2929*6b4cac81SBjoern A. Zeeb */ 2930*6b4cac81SBjoern A. Zeeb /* XXX-BZ probably should have state in the lvif as well. */ 2931*6b4cac81SBjoern A. Zeeb vap = LVIF_TO_VAP(lvif); 2932*6b4cac81SBjoern A. Zeeb if (!active || (vap->iv_state != IEEE80211_S_INIT)) 2933*6b4cac81SBjoern A. Zeeb iterfunc(arg, vif->addr, vif); 2934*6b4cac81SBjoern A. Zeeb } 2935*6b4cac81SBjoern A. Zeeb if (atomic) 2936*6b4cac81SBjoern A. Zeeb LKPI_80211_LHW_UNLOCK(lhw); 2937*6b4cac81SBjoern A. Zeeb } 2938*6b4cac81SBjoern A. Zeeb 2939*6b4cac81SBjoern A. Zeeb void 2940*6b4cac81SBjoern A. Zeeb linuxkpi_ieee80211_iterate_keys(struct ieee80211_hw *hw, 2941*6b4cac81SBjoern A. Zeeb struct ieee80211_vif *vif, 2942*6b4cac81SBjoern A. Zeeb void(*iterfunc)(struct ieee80211_hw *, struct ieee80211_vif *, 2943*6b4cac81SBjoern A. Zeeb struct ieee80211_sta *, struct ieee80211_key_conf *, void *), 2944*6b4cac81SBjoern A. Zeeb void *arg) 2945*6b4cac81SBjoern A. Zeeb { 2946*6b4cac81SBjoern A. Zeeb 2947*6b4cac81SBjoern A. Zeeb UNIMPLEMENTED; 2948*6b4cac81SBjoern A. Zeeb } 2949*6b4cac81SBjoern A. Zeeb 2950*6b4cac81SBjoern A. Zeeb void 2951*6b4cac81SBjoern A. Zeeb linuxkpi_ieee80211_iterate_chan_contexts(struct ieee80211_hw *hw, 2952*6b4cac81SBjoern A. Zeeb void(*iterfunc)(struct ieee80211_hw *, struct ieee80211_chanctx_conf *, 2953*6b4cac81SBjoern A. Zeeb void *), 2954*6b4cac81SBjoern A. Zeeb void *arg) 2955*6b4cac81SBjoern A. Zeeb { 2956*6b4cac81SBjoern A. Zeeb 2957*6b4cac81SBjoern A. Zeeb UNIMPLEMENTED; 2958*6b4cac81SBjoern A. Zeeb } 2959*6b4cac81SBjoern A. Zeeb 2960*6b4cac81SBjoern A. Zeeb void 2961*6b4cac81SBjoern A. Zeeb linuxkpi_ieee80211_iterate_stations_atomic(struct ieee80211_hw *hw, 2962*6b4cac81SBjoern A. Zeeb void (*iterfunc)(void *, struct ieee80211_sta *), void *arg) 2963*6b4cac81SBjoern A. Zeeb { 2964*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 2965*6b4cac81SBjoern A. Zeeb struct lkpi_vif *lvif; 2966*6b4cac81SBjoern A. Zeeb struct lkpi_sta *lsta; 2967*6b4cac81SBjoern A. Zeeb struct ieee80211_sta *sta; 2968*6b4cac81SBjoern A. Zeeb 2969*6b4cac81SBjoern A. Zeeb KASSERT(hw != NULL && iterfunc != NULL, 2970*6b4cac81SBjoern A. Zeeb ("%s: hw %p iterfunc %p arg %p\n", __func__, hw, iterfunc, arg)); 2971*6b4cac81SBjoern A. Zeeb 2972*6b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 2973*6b4cac81SBjoern A. Zeeb 2974*6b4cac81SBjoern A. Zeeb LKPI_80211_LHW_LOCK(lhw); 2975*6b4cac81SBjoern A. Zeeb TAILQ_FOREACH(lvif, &lhw->lvif_head, lvif_entry) { 2976*6b4cac81SBjoern A. Zeeb 2977*6b4cac81SBjoern A. Zeeb LKPI_80211_LVIF_LOCK(lvif); 2978*6b4cac81SBjoern A. Zeeb TAILQ_FOREACH(lsta, &lvif->lsta_head, lsta_entry) { 2979*6b4cac81SBjoern A. Zeeb if (!lsta->added_to_drv) 2980*6b4cac81SBjoern A. Zeeb continue; 2981*6b4cac81SBjoern A. Zeeb sta = LSTA_TO_STA(lsta); 2982*6b4cac81SBjoern A. Zeeb iterfunc(arg, sta); 2983*6b4cac81SBjoern A. Zeeb } 2984*6b4cac81SBjoern A. Zeeb LKPI_80211_LVIF_UNLOCK(lvif); 2985*6b4cac81SBjoern A. Zeeb } 2986*6b4cac81SBjoern A. Zeeb LKPI_80211_LHW_UNLOCK(lhw); 2987*6b4cac81SBjoern A. Zeeb } 2988*6b4cac81SBjoern A. Zeeb 2989*6b4cac81SBjoern A. Zeeb int 2990*6b4cac81SBjoern A. Zeeb linuxkpi_regulatory_set_wiphy_regd_sync(struct wiphy *wiphy, 2991*6b4cac81SBjoern A. Zeeb struct linuxkpi_ieee80211_regdomain *regd) 2992*6b4cac81SBjoern A. Zeeb { 2993*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 2994*6b4cac81SBjoern A. Zeeb struct ieee80211com *ic; 2995*6b4cac81SBjoern A. Zeeb struct ieee80211_regdomain *rd; 2996*6b4cac81SBjoern A. Zeeb 2997*6b4cac81SBjoern A. Zeeb lhw = wiphy_priv(wiphy); 2998*6b4cac81SBjoern A. Zeeb ic = lhw->ic; 2999*6b4cac81SBjoern A. Zeeb 3000*6b4cac81SBjoern A. Zeeb rd = &ic->ic_regdomain; 3001*6b4cac81SBjoern A. Zeeb if (rd->isocc[0] == '\0') { 3002*6b4cac81SBjoern A. Zeeb rd->isocc[0] = regd->alpha2[0]; 3003*6b4cac81SBjoern A. Zeeb rd->isocc[1] = regd->alpha2[1]; 3004*6b4cac81SBjoern A. Zeeb } 3005*6b4cac81SBjoern A. Zeeb 3006*6b4cac81SBjoern A. Zeeb TODO(); 3007*6b4cac81SBjoern A. Zeeb /* XXX-BZ finish the rest. */ 3008*6b4cac81SBjoern A. Zeeb 3009*6b4cac81SBjoern A. Zeeb return (0); 3010*6b4cac81SBjoern A. Zeeb } 3011*6b4cac81SBjoern A. Zeeb 3012*6b4cac81SBjoern A. Zeeb void 3013*6b4cac81SBjoern A. Zeeb linuxkpi_ieee80211_scan_completed(struct ieee80211_hw *hw, 3014*6b4cac81SBjoern A. Zeeb struct cfg80211_scan_info *info) 3015*6b4cac81SBjoern A. Zeeb { 3016*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 3017*6b4cac81SBjoern A. Zeeb struct ieee80211com *ic; 3018*6b4cac81SBjoern A. Zeeb struct ieee80211_scan_state *ss; 3019*6b4cac81SBjoern A. Zeeb 3020*6b4cac81SBjoern A. Zeeb lhw = wiphy_priv(hw->wiphy); 3021*6b4cac81SBjoern A. Zeeb ic = lhw->ic; 3022*6b4cac81SBjoern A. Zeeb ss = ic->ic_scan; 3023*6b4cac81SBjoern A. Zeeb 3024*6b4cac81SBjoern A. Zeeb ieee80211_scan_done(ss->ss_vap); 3025*6b4cac81SBjoern A. Zeeb 3026*6b4cac81SBjoern A. Zeeb LKPI_80211_LHW_LOCK(lhw); 3027*6b4cac81SBjoern A. Zeeb free(lhw->hw_req->ies.common_ies, M_80211_VAP); 3028*6b4cac81SBjoern A. Zeeb free(lhw->hw_req, M_LKPI80211); 3029*6b4cac81SBjoern A. Zeeb lhw->hw_req = NULL; 3030*6b4cac81SBjoern A. Zeeb lhw->scan_flags &= ~LKPI_SCAN_RUNNING; 3031*6b4cac81SBjoern A. Zeeb wakeup(lhw); 3032*6b4cac81SBjoern A. Zeeb LKPI_80211_LHW_UNLOCK(lhw); 3033*6b4cac81SBjoern A. Zeeb 3034*6b4cac81SBjoern A. Zeeb return; 3035*6b4cac81SBjoern A. Zeeb } 3036*6b4cac81SBjoern A. Zeeb 3037*6b4cac81SBjoern A. Zeeb void 3038*6b4cac81SBjoern A. Zeeb linuxkpi_ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, 3039*6b4cac81SBjoern A. Zeeb struct ieee80211_sta *sta, struct napi_struct *napi __unused) 3040*6b4cac81SBjoern A. Zeeb { 3041*6b4cac81SBjoern A. Zeeb struct epoch_tracker et; 3042*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 3043*6b4cac81SBjoern A. Zeeb struct ieee80211com *ic; 3044*6b4cac81SBjoern A. Zeeb struct mbuf *m; 3045*6b4cac81SBjoern A. Zeeb struct skb_shared_info *shinfo; 3046*6b4cac81SBjoern A. Zeeb struct ieee80211_rx_status *rx_status; 3047*6b4cac81SBjoern A. Zeeb struct ieee80211_rx_stats rx_stats; 3048*6b4cac81SBjoern A. Zeeb struct ieee80211_node *ni; 3049*6b4cac81SBjoern A. Zeeb struct ieee80211vap *vap; 3050*6b4cac81SBjoern A. Zeeb struct ieee80211_frame_min *wh; 3051*6b4cac81SBjoern A. Zeeb struct ieee80211_hdr *hdr; 3052*6b4cac81SBjoern A. Zeeb struct lkpi_sta *lsta; 3053*6b4cac81SBjoern A. Zeeb int i, offset, ok, type; 3054*6b4cac81SBjoern A. Zeeb 3055*6b4cac81SBjoern A. Zeeb if (skb->len < 2) { 3056*6b4cac81SBjoern A. Zeeb /* Need 80211 stats here. */ 3057*6b4cac81SBjoern A. Zeeb IMPROVE(); 3058*6b4cac81SBjoern A. Zeeb goto err; 3059*6b4cac81SBjoern A. Zeeb } 3060*6b4cac81SBjoern A. Zeeb 3061*6b4cac81SBjoern A. Zeeb /* 3062*6b4cac81SBjoern A. Zeeb * For now do the data copy; we can later improve things. Might even 3063*6b4cac81SBjoern A. Zeeb * have an mbuf backing the skb data then? 3064*6b4cac81SBjoern A. Zeeb */ 3065*6b4cac81SBjoern A. Zeeb m = m_get2(skb->len, M_NOWAIT, MT_DATA, M_PKTHDR); 3066*6b4cac81SBjoern A. Zeeb if (m == NULL) 3067*6b4cac81SBjoern A. Zeeb goto err; 3068*6b4cac81SBjoern A. Zeeb m_copyback(m, 0, skb->tail - skb->data, skb->data); 3069*6b4cac81SBjoern A. Zeeb 3070*6b4cac81SBjoern A. Zeeb shinfo = skb_shinfo(skb); 3071*6b4cac81SBjoern A. Zeeb offset = m->m_len; 3072*6b4cac81SBjoern A. Zeeb for (i = 0; i < shinfo->nr_frags; i++) { 3073*6b4cac81SBjoern A. Zeeb m_copyback(m, offset, shinfo->frags[i].size, 3074*6b4cac81SBjoern A. Zeeb (uint8_t *)linux_page_address(shinfo->frags[i].page) + 3075*6b4cac81SBjoern A. Zeeb shinfo->frags[i].offset); 3076*6b4cac81SBjoern A. Zeeb offset += shinfo->frags[i].size; 3077*6b4cac81SBjoern A. Zeeb } 3078*6b4cac81SBjoern A. Zeeb 3079*6b4cac81SBjoern A. Zeeb rx_status = IEEE80211_SKB_RXCB(skb); 3080*6b4cac81SBjoern A. Zeeb 3081*6b4cac81SBjoern A. Zeeb #ifdef LINUXKPI_DEBUG_80211 3082*6b4cac81SBjoern A. Zeeb hdr = (void *)skb->data; 3083*6b4cac81SBjoern A. Zeeb if ((debug_80211 & D80211_TRACE_RX_BEACONS) == 0 && 3084*6b4cac81SBjoern A. Zeeb ieee80211_is_beacon(hdr->frame_control)) 3085*6b4cac81SBjoern A. Zeeb goto no_trace_beacons; 3086*6b4cac81SBjoern A. Zeeb 3087*6b4cac81SBjoern A. Zeeb if (debug_80211 & D80211_TRACE_RX) 3088*6b4cac81SBjoern A. Zeeb printf("TRACE-RX: %s: skb %p a/l/d/t-len (%u/%u/%u/%u) " 3089*6b4cac81SBjoern A. Zeeb "h %p d %p t %p e %p sh %p (%u) m %p plen %u len %u\n", 3090*6b4cac81SBjoern A. Zeeb __func__, skb, skb->_alloc_len, skb->len, skb->data_len, 3091*6b4cac81SBjoern A. Zeeb skb->truesize, skb->head, skb->data, skb->tail, skb->end, 3092*6b4cac81SBjoern A. Zeeb shinfo, shinfo->nr_frags, 3093*6b4cac81SBjoern A. Zeeb m, m->m_pkthdr.len, m->m_len); 3094*6b4cac81SBjoern A. Zeeb 3095*6b4cac81SBjoern A. Zeeb if (debug_80211 & D80211_TRACE_RX_DUMP) 3096*6b4cac81SBjoern A. Zeeb hexdump(mtod(m, const void *), m->m_len, "RX (raw) ", 0); 3097*6b4cac81SBjoern A. Zeeb 3098*6b4cac81SBjoern A. Zeeb /* Implement a dump_rxcb() !!! */ 3099*6b4cac81SBjoern A. Zeeb if (debug_80211 & D80211_TRACE_RX) 3100*6b4cac81SBjoern A. Zeeb printf("TRACE %s: RXCB: %u %u %u, %#0x, %u, %#0x, %#0x, " 3101*6b4cac81SBjoern A. Zeeb "%u band %u, %u %u %u %u, %u, %#x %#x %#x %#x %u %u %u\n", 3102*6b4cac81SBjoern A. Zeeb __func__, 3103*6b4cac81SBjoern A. Zeeb rx_status->boottime_ns, 3104*6b4cac81SBjoern A. Zeeb rx_status->mactime, 3105*6b4cac81SBjoern A. Zeeb rx_status->device_timestamp, 3106*6b4cac81SBjoern A. Zeeb rx_status->flag, 3107*6b4cac81SBjoern A. Zeeb rx_status->freq, 3108*6b4cac81SBjoern A. Zeeb rx_status->bw, 3109*6b4cac81SBjoern A. Zeeb rx_status->encoding, 3110*6b4cac81SBjoern A. Zeeb rx_status->ampdu_reference, 3111*6b4cac81SBjoern A. Zeeb rx_status->band, 3112*6b4cac81SBjoern A. Zeeb rx_status->chains, 3113*6b4cac81SBjoern A. Zeeb rx_status->chain_signal[0], 3114*6b4cac81SBjoern A. Zeeb rx_status->chain_signal[1], 3115*6b4cac81SBjoern A. Zeeb rx_status->chain_signal[2], 3116*6b4cac81SBjoern A. Zeeb rx_status->signal, 3117*6b4cac81SBjoern A. Zeeb rx_status->enc_flags, 3118*6b4cac81SBjoern A. Zeeb rx_status->he_dcm, 3119*6b4cac81SBjoern A. Zeeb rx_status->he_gi, 3120*6b4cac81SBjoern A. Zeeb rx_status->he_ru, 3121*6b4cac81SBjoern A. Zeeb rx_status->zero_length_psdu_type, 3122*6b4cac81SBjoern A. Zeeb rx_status->nss, 3123*6b4cac81SBjoern A. Zeeb rx_status->rate_idx); 3124*6b4cac81SBjoern A. Zeeb no_trace_beacons: 3125*6b4cac81SBjoern A. Zeeb #endif 3126*6b4cac81SBjoern A. Zeeb 3127*6b4cac81SBjoern A. Zeeb memset(&rx_stats, 0, sizeof(rx_stats)); 3128*6b4cac81SBjoern A. Zeeb rx_stats.r_flags = IEEE80211_R_NF | IEEE80211_R_RSSI; 3129*6b4cac81SBjoern A. Zeeb if (ieee80211_hw_check(hw, SIGNAL_DBM) && 3130*6b4cac81SBjoern A. Zeeb !(rx_status->flag & RX_FLAG_NO_SIGNAL_VAL)) 3131*6b4cac81SBjoern A. Zeeb rx_stats.c_rssi = rx_status->signal; 3132*6b4cac81SBjoern A. Zeeb else 3133*6b4cac81SBjoern A. Zeeb rx_stats.c_rssi = 0; /* XXX */ 3134*6b4cac81SBjoern A. Zeeb rx_stats.c_nf = -96; /* XXX */ 3135*6b4cac81SBjoern A. Zeeb rx_stats.r_flags |= IEEE80211_R_BAND; 3136*6b4cac81SBjoern A. Zeeb rx_stats.c_band = 3137*6b4cac81SBjoern A. Zeeb lkpi_nl80211_band_to_net80211_band(rx_status->band); 3138*6b4cac81SBjoern A. Zeeb rx_stats.r_flags |= IEEE80211_R_FREQ | IEEE80211_R_IEEE; 3139*6b4cac81SBjoern A. Zeeb rx_stats.c_freq = rx_status->freq; 3140*6b4cac81SBjoern A. Zeeb rx_stats.c_ieee = ieee80211_mhz2ieee(rx_stats.c_freq, rx_stats.c_band); 3141*6b4cac81SBjoern A. Zeeb 3142*6b4cac81SBjoern A. Zeeb /* XXX-BZ correct hardcoded rssi and noise floor. */ 3143*6b4cac81SBjoern A. Zeeb /* XXX (*sta_statistics)() to get to some of that? */ 3144*6b4cac81SBjoern A. Zeeb /* XXX-BZ dump the FreeBSD version of rx_stats as well! */ 3145*6b4cac81SBjoern A. Zeeb 3146*6b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 3147*6b4cac81SBjoern A. Zeeb ic = lhw->ic; 3148*6b4cac81SBjoern A. Zeeb 3149*6b4cac81SBjoern A. Zeeb ok = ieee80211_add_rx_params(m, &rx_stats); 3150*6b4cac81SBjoern A. Zeeb if (ok == 0) { 3151*6b4cac81SBjoern A. Zeeb counter_u64_add(ic->ic_ierrors, 1); 3152*6b4cac81SBjoern A. Zeeb goto err; 3153*6b4cac81SBjoern A. Zeeb } 3154*6b4cac81SBjoern A. Zeeb 3155*6b4cac81SBjoern A. Zeeb if (sta != NULL) { 3156*6b4cac81SBjoern A. Zeeb lsta = STA_TO_LSTA(sta); 3157*6b4cac81SBjoern A. Zeeb ni = ieee80211_ref_node(lsta->ni); 3158*6b4cac81SBjoern A. Zeeb } else { 3159*6b4cac81SBjoern A. Zeeb wh = mtod(m, struct ieee80211_frame_min *); 3160*6b4cac81SBjoern A. Zeeb ni = ieee80211_find_rxnode(ic, wh); 3161*6b4cac81SBjoern A. Zeeb if (ni != NULL) 3162*6b4cac81SBjoern A. Zeeb lsta = ni->ni_drv_data; 3163*6b4cac81SBjoern A. Zeeb } 3164*6b4cac81SBjoern A. Zeeb 3165*6b4cac81SBjoern A. Zeeb if (ni != NULL) 3166*6b4cac81SBjoern A. Zeeb vap = ni->ni_vap; 3167*6b4cac81SBjoern A. Zeeb else 3168*6b4cac81SBjoern A. Zeeb /* 3169*6b4cac81SBjoern A. Zeeb * XXX-BZ can we improve this by looking at the frame hdr 3170*6b4cac81SBjoern A. Zeeb * or other meta-data passed up? 3171*6b4cac81SBjoern A. Zeeb */ 3172*6b4cac81SBjoern A. Zeeb vap = TAILQ_FIRST(&ic->ic_vaps); 3173*6b4cac81SBjoern A. Zeeb 3174*6b4cac81SBjoern A. Zeeb if (debug_80211 & D80211_TRACE_RX) 3175*6b4cac81SBjoern A. Zeeb printf("TRACE %s: sta %p lsta %p ni %p vap %p\n", __func__, sta, lsta, ni, vap); 3176*6b4cac81SBjoern A. Zeeb 3177*6b4cac81SBjoern A. Zeeb if (vap != NULL && vap->iv_state > IEEE80211_S_INIT && 3178*6b4cac81SBjoern A. Zeeb ieee80211_radiotap_active_vap(vap)) { 3179*6b4cac81SBjoern A. Zeeb struct lkpi_radiotap_rx_hdr *rtap; 3180*6b4cac81SBjoern A. Zeeb 3181*6b4cac81SBjoern A. Zeeb rtap = &lhw->rtap_rx; 3182*6b4cac81SBjoern A. Zeeb rtap->wr_tsft = rx_status->device_timestamp; 3183*6b4cac81SBjoern A. Zeeb rtap->wr_flags = 0; 3184*6b4cac81SBjoern A. Zeeb if (rx_status->enc_flags & RX_ENC_FLAG_SHORTPRE) 3185*6b4cac81SBjoern A. Zeeb rtap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; 3186*6b4cac81SBjoern A. Zeeb if (rx_status->enc_flags & RX_ENC_FLAG_SHORT_GI) 3187*6b4cac81SBjoern A. Zeeb rtap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTGI; 3188*6b4cac81SBjoern A. Zeeb #if 0 /* .. or it does not given we strip it below. */ 3189*6b4cac81SBjoern A. Zeeb if (ieee80211_hw_check(hw, RX_INCLUDES_FCS)) 3190*6b4cac81SBjoern A. Zeeb rtap->wr_flags |= IEEE80211_RADIOTAP_F_FCS; 3191*6b4cac81SBjoern A. Zeeb #endif 3192*6b4cac81SBjoern A. Zeeb if (rx_status->flag & RX_FLAG_FAILED_FCS_CRC) 3193*6b4cac81SBjoern A. Zeeb rtap->wr_flags |= IEEE80211_RADIOTAP_F_BADFCS; 3194*6b4cac81SBjoern A. Zeeb rtap->wr_rate = 0; 3195*6b4cac81SBjoern A. Zeeb IMPROVE(); 3196*6b4cac81SBjoern A. Zeeb /* XXX TODO status->encoding / rate_index / bw */ 3197*6b4cac81SBjoern A. Zeeb rtap->wr_chan_freq = htole16(rx_stats.c_freq); 3198*6b4cac81SBjoern A. Zeeb if (ic->ic_curchan->ic_ieee == rx_stats.c_ieee) 3199*6b4cac81SBjoern A. Zeeb rtap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags); 3200*6b4cac81SBjoern A. Zeeb rtap->wr_dbm_antsignal = rx_stats.c_rssi; 3201*6b4cac81SBjoern A. Zeeb rtap->wr_dbm_antnoise = rx_stats.c_nf; 3202*6b4cac81SBjoern A. Zeeb } 3203*6b4cac81SBjoern A. Zeeb 3204*6b4cac81SBjoern A. Zeeb if (ieee80211_hw_check(hw, RX_INCLUDES_FCS)) 3205*6b4cac81SBjoern A. Zeeb m_adj(m, -IEEE80211_CRC_LEN); 3206*6b4cac81SBjoern A. Zeeb 3207*6b4cac81SBjoern A. Zeeb NET_EPOCH_ENTER(et); 3208*6b4cac81SBjoern A. Zeeb if (ni != NULL) { 3209*6b4cac81SBjoern A. Zeeb type = ieee80211_input_mimo(ni, m); 3210*6b4cac81SBjoern A. Zeeb ieee80211_free_node(ni); 3211*6b4cac81SBjoern A. Zeeb } else { 3212*6b4cac81SBjoern A. Zeeb type = ieee80211_input_mimo_all(ic, m); 3213*6b4cac81SBjoern A. Zeeb } 3214*6b4cac81SBjoern A. Zeeb NET_EPOCH_EXIT(et); 3215*6b4cac81SBjoern A. Zeeb 3216*6b4cac81SBjoern A. Zeeb if (debug_80211 & D80211_TRACE_RX) 3217*6b4cac81SBjoern A. Zeeb printf("TRACE %s: handled frame type %#0x\n", __func__, type); 3218*6b4cac81SBjoern A. Zeeb 3219*6b4cac81SBjoern A. Zeeb IMPROVE(); 3220*6b4cac81SBjoern A. Zeeb 3221*6b4cac81SBjoern A. Zeeb err: 3222*6b4cac81SBjoern A. Zeeb /* The skb is ours so we can free it :-) */ 3223*6b4cac81SBjoern A. Zeeb kfree_skb(skb); 3224*6b4cac81SBjoern A. Zeeb } 3225*6b4cac81SBjoern A. Zeeb 3226*6b4cac81SBjoern A. Zeeb uint8_t 3227*6b4cac81SBjoern A. Zeeb linuxkpi_ieee80211_get_tid(struct ieee80211_hdr *hdr) 3228*6b4cac81SBjoern A. Zeeb { 3229*6b4cac81SBjoern A. Zeeb const struct ieee80211_frame *wh; 3230*6b4cac81SBjoern A. Zeeb 3231*6b4cac81SBjoern A. Zeeb wh = (const struct ieee80211_frame *)hdr; 3232*6b4cac81SBjoern A. Zeeb return (ieee80211_gettid(wh)); 3233*6b4cac81SBjoern A. Zeeb } 3234*6b4cac81SBjoern A. Zeeb 3235*6b4cac81SBjoern A. Zeeb struct wiphy * 3236*6b4cac81SBjoern A. Zeeb linuxkpi_wiphy_new(const struct cfg80211_ops *ops, size_t priv_len) 3237*6b4cac81SBjoern A. Zeeb { 3238*6b4cac81SBjoern A. Zeeb struct lkpi_wiphy *lwiphy; 3239*6b4cac81SBjoern A. Zeeb 3240*6b4cac81SBjoern A. Zeeb lwiphy = kzalloc(sizeof(*lwiphy) + priv_len, GFP_KERNEL); 3241*6b4cac81SBjoern A. Zeeb if (lwiphy == NULL) 3242*6b4cac81SBjoern A. Zeeb return (NULL); 3243*6b4cac81SBjoern A. Zeeb lwiphy->ops = ops; 3244*6b4cac81SBjoern A. Zeeb 3245*6b4cac81SBjoern A. Zeeb /* XXX TODO */ 3246*6b4cac81SBjoern A. Zeeb return (LWIPHY_TO_WIPHY(lwiphy)); 3247*6b4cac81SBjoern A. Zeeb } 3248*6b4cac81SBjoern A. Zeeb 3249*6b4cac81SBjoern A. Zeeb void 3250*6b4cac81SBjoern A. Zeeb linuxkpi_wiphy_free(struct wiphy *wiphy) 3251*6b4cac81SBjoern A. Zeeb { 3252*6b4cac81SBjoern A. Zeeb struct lkpi_wiphy *lwiphy; 3253*6b4cac81SBjoern A. Zeeb 3254*6b4cac81SBjoern A. Zeeb if (wiphy == NULL) 3255*6b4cac81SBjoern A. Zeeb return; 3256*6b4cac81SBjoern A. Zeeb 3257*6b4cac81SBjoern A. Zeeb lwiphy = WIPHY_TO_LWIPHY(wiphy); 3258*6b4cac81SBjoern A. Zeeb kfree(lwiphy); 3259*6b4cac81SBjoern A. Zeeb } 3260*6b4cac81SBjoern A. Zeeb 3261*6b4cac81SBjoern A. Zeeb uint32_t 3262*6b4cac81SBjoern A. Zeeb linuxkpi_ieee80211_channel_to_frequency(uint32_t channel, 3263*6b4cac81SBjoern A. Zeeb enum nl80211_band band) 3264*6b4cac81SBjoern A. Zeeb { 3265*6b4cac81SBjoern A. Zeeb 3266*6b4cac81SBjoern A. Zeeb switch (band) { 3267*6b4cac81SBjoern A. Zeeb case NL80211_BAND_2GHZ: 3268*6b4cac81SBjoern A. Zeeb return (ieee80211_ieee2mhz(channel, IEEE80211_CHAN_2GHZ)); 3269*6b4cac81SBjoern A. Zeeb break; 3270*6b4cac81SBjoern A. Zeeb case NL80211_BAND_5GHZ: 3271*6b4cac81SBjoern A. Zeeb return (ieee80211_ieee2mhz(channel, IEEE80211_CHAN_5GHZ)); 3272*6b4cac81SBjoern A. Zeeb break; 3273*6b4cac81SBjoern A. Zeeb default: 3274*6b4cac81SBjoern A. Zeeb /* XXX abort, retry, error, panic? */ 3275*6b4cac81SBjoern A. Zeeb break; 3276*6b4cac81SBjoern A. Zeeb } 3277*6b4cac81SBjoern A. Zeeb 3278*6b4cac81SBjoern A. Zeeb return (0); 3279*6b4cac81SBjoern A. Zeeb } 3280*6b4cac81SBjoern A. Zeeb 3281*6b4cac81SBjoern A. Zeeb uint32_t 3282*6b4cac81SBjoern A. Zeeb linuxkpi_ieee80211_frequency_to_channel(uint32_t freq, uint32_t flags __unused) 3283*6b4cac81SBjoern A. Zeeb { 3284*6b4cac81SBjoern A. Zeeb 3285*6b4cac81SBjoern A. Zeeb return (ieee80211_mhz2ieee(freq, 0)); 3286*6b4cac81SBjoern A. Zeeb } 3287*6b4cac81SBjoern A. Zeeb 3288*6b4cac81SBjoern A. Zeeb static struct lkpi_sta * 3289*6b4cac81SBjoern A. Zeeb lkpi_find_lsta_by_ni(struct lkpi_vif *lvif, struct ieee80211_node *ni) 3290*6b4cac81SBjoern A. Zeeb { 3291*6b4cac81SBjoern A. Zeeb struct lkpi_sta *lsta, *temp; 3292*6b4cac81SBjoern A. Zeeb 3293*6b4cac81SBjoern A. Zeeb LKPI_80211_LVIF_LOCK(lvif); 3294*6b4cac81SBjoern A. Zeeb TAILQ_FOREACH_SAFE(lsta, &lvif->lsta_head, lsta_entry, temp) { 3295*6b4cac81SBjoern A. Zeeb if (lsta->ni == ni) { 3296*6b4cac81SBjoern A. Zeeb LKPI_80211_LVIF_UNLOCK(lvif); 3297*6b4cac81SBjoern A. Zeeb return (lsta); 3298*6b4cac81SBjoern A. Zeeb } 3299*6b4cac81SBjoern A. Zeeb } 3300*6b4cac81SBjoern A. Zeeb LKPI_80211_LVIF_UNLOCK(lvif); 3301*6b4cac81SBjoern A. Zeeb 3302*6b4cac81SBjoern A. Zeeb return (NULL); 3303*6b4cac81SBjoern A. Zeeb } 3304*6b4cac81SBjoern A. Zeeb 3305*6b4cac81SBjoern A. Zeeb struct ieee80211_sta * 3306*6b4cac81SBjoern A. Zeeb linuxkpi_ieee80211_find_sta(struct ieee80211_vif *vif, const u8 *peer) 3307*6b4cac81SBjoern A. Zeeb { 3308*6b4cac81SBjoern A. Zeeb struct lkpi_vif *lvif; 3309*6b4cac81SBjoern A. Zeeb struct lkpi_sta *lsta, *temp; 3310*6b4cac81SBjoern A. Zeeb struct ieee80211_sta *sta; 3311*6b4cac81SBjoern A. Zeeb 3312*6b4cac81SBjoern A. Zeeb lvif = VIF_TO_LVIF(vif); 3313*6b4cac81SBjoern A. Zeeb 3314*6b4cac81SBjoern A. Zeeb LKPI_80211_LVIF_LOCK(lvif); 3315*6b4cac81SBjoern A. Zeeb TAILQ_FOREACH_SAFE(lsta, &lvif->lsta_head, lsta_entry, temp) { 3316*6b4cac81SBjoern A. Zeeb sta = LSTA_TO_STA(lsta); 3317*6b4cac81SBjoern A. Zeeb if (IEEE80211_ADDR_EQ(sta->addr, peer)) { 3318*6b4cac81SBjoern A. Zeeb LKPI_80211_LVIF_UNLOCK(lvif); 3319*6b4cac81SBjoern A. Zeeb return (sta); 3320*6b4cac81SBjoern A. Zeeb } 3321*6b4cac81SBjoern A. Zeeb } 3322*6b4cac81SBjoern A. Zeeb LKPI_80211_LVIF_UNLOCK(lvif); 3323*6b4cac81SBjoern A. Zeeb return (NULL); 3324*6b4cac81SBjoern A. Zeeb } 3325*6b4cac81SBjoern A. Zeeb 3326*6b4cac81SBjoern A. Zeeb struct ieee80211_sta * 3327*6b4cac81SBjoern A. Zeeb linuxkpi_ieee80211_find_sta_by_ifaddr(struct ieee80211_hw *hw, uint8_t *addr, 3328*6b4cac81SBjoern A. Zeeb uint8_t *ourvifaddr) 3329*6b4cac81SBjoern A. Zeeb { 3330*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 3331*6b4cac81SBjoern A. Zeeb struct lkpi_vif *lvif; 3332*6b4cac81SBjoern A. Zeeb struct lkpi_sta *lsta; 3333*6b4cac81SBjoern A. Zeeb struct ieee80211_vif *vif; 3334*6b4cac81SBjoern A. Zeeb struct ieee80211_sta *sta; 3335*6b4cac81SBjoern A. Zeeb 3336*6b4cac81SBjoern A. Zeeb lhw = wiphy_priv(hw->wiphy); 3337*6b4cac81SBjoern A. Zeeb sta = NULL; 3338*6b4cac81SBjoern A. Zeeb 3339*6b4cac81SBjoern A. Zeeb LKPI_80211_LHW_LOCK(lhw); 3340*6b4cac81SBjoern A. Zeeb TAILQ_FOREACH(lvif, &lhw->lvif_head, lvif_entry) { 3341*6b4cac81SBjoern A. Zeeb 3342*6b4cac81SBjoern A. Zeeb /* XXX-BZ check our address from the vif. */ 3343*6b4cac81SBjoern A. Zeeb 3344*6b4cac81SBjoern A. Zeeb vif = LVIF_TO_VIF(lvif); 3345*6b4cac81SBjoern A. Zeeb if (ourvifaddr != NULL && 3346*6b4cac81SBjoern A. Zeeb !IEEE80211_ADDR_EQ(vif->addr, ourvifaddr)) 3347*6b4cac81SBjoern A. Zeeb continue; 3348*6b4cac81SBjoern A. Zeeb sta = linuxkpi_ieee80211_find_sta(vif, addr); 3349*6b4cac81SBjoern A. Zeeb if (sta != NULL) 3350*6b4cac81SBjoern A. Zeeb break; 3351*6b4cac81SBjoern A. Zeeb } 3352*6b4cac81SBjoern A. Zeeb LKPI_80211_LHW_UNLOCK(lhw); 3353*6b4cac81SBjoern A. Zeeb 3354*6b4cac81SBjoern A. Zeeb if (sta != NULL) { 3355*6b4cac81SBjoern A. Zeeb lsta = STA_TO_LSTA(sta); 3356*6b4cac81SBjoern A. Zeeb if (!lsta->added_to_drv) 3357*6b4cac81SBjoern A. Zeeb return (NULL); 3358*6b4cac81SBjoern A. Zeeb } 3359*6b4cac81SBjoern A. Zeeb 3360*6b4cac81SBjoern A. Zeeb return (sta); 3361*6b4cac81SBjoern A. Zeeb } 3362*6b4cac81SBjoern A. Zeeb 3363*6b4cac81SBjoern A. Zeeb struct sk_buff * 3364*6b4cac81SBjoern A. Zeeb linuxkpi_ieee80211_tx_dequeue(struct ieee80211_hw *hw, 3365*6b4cac81SBjoern A. Zeeb struct ieee80211_txq *txq) 3366*6b4cac81SBjoern A. Zeeb { 3367*6b4cac81SBjoern A. Zeeb struct lkpi_txq *ltxq; 3368*6b4cac81SBjoern A. Zeeb struct sk_buff *skb; 3369*6b4cac81SBjoern A. Zeeb 3370*6b4cac81SBjoern A. Zeeb ltxq = TXQ_TO_LTXQ(txq); 3371*6b4cac81SBjoern A. Zeeb ltxq->seen_dequeue = true; 3372*6b4cac81SBjoern A. Zeeb 3373*6b4cac81SBjoern A. Zeeb skb = skb_dequeue(<xq->skbq); 3374*6b4cac81SBjoern A. Zeeb 3375*6b4cac81SBjoern A. Zeeb return (skb); 3376*6b4cac81SBjoern A. Zeeb } 3377*6b4cac81SBjoern A. Zeeb 3378*6b4cac81SBjoern A. Zeeb void 3379*6b4cac81SBjoern A. Zeeb linuxkpi_ieee80211_txq_get_depth(struct ieee80211_txq *txq, 3380*6b4cac81SBjoern A. Zeeb uint64_t *frame_cnt, uint64_t *byte_cnt) 3381*6b4cac81SBjoern A. Zeeb { 3382*6b4cac81SBjoern A. Zeeb struct lkpi_txq *ltxq; 3383*6b4cac81SBjoern A. Zeeb struct sk_buff *skb; 3384*6b4cac81SBjoern A. Zeeb uint64_t fc, bc; 3385*6b4cac81SBjoern A. Zeeb 3386*6b4cac81SBjoern A. Zeeb ltxq = TXQ_TO_LTXQ(txq); 3387*6b4cac81SBjoern A. Zeeb 3388*6b4cac81SBjoern A. Zeeb fc = bc = 0; 3389*6b4cac81SBjoern A. Zeeb skb_queue_walk(<xq->skbq, skb) { 3390*6b4cac81SBjoern A. Zeeb fc++; 3391*6b4cac81SBjoern A. Zeeb bc += skb->len; 3392*6b4cac81SBjoern A. Zeeb } 3393*6b4cac81SBjoern A. Zeeb if (frame_cnt) 3394*6b4cac81SBjoern A. Zeeb *frame_cnt = fc; 3395*6b4cac81SBjoern A. Zeeb if (byte_cnt) 3396*6b4cac81SBjoern A. Zeeb *byte_cnt = bc; 3397*6b4cac81SBjoern A. Zeeb 3398*6b4cac81SBjoern A. Zeeb /* Validate that this is doing the correct thing. */ 3399*6b4cac81SBjoern A. Zeeb /* Should we keep track on en/dequeue? */ 3400*6b4cac81SBjoern A. Zeeb IMPROVE(); 3401*6b4cac81SBjoern A. Zeeb } 3402*6b4cac81SBjoern A. Zeeb 3403*6b4cac81SBjoern A. Zeeb /* 3404*6b4cac81SBjoern A. Zeeb * We are called from ieee80211_free_txskb() or ieee80211_tx_status(). 3405*6b4cac81SBjoern A. Zeeb * The latter tries to derive the success status from the info flags 3406*6b4cac81SBjoern A. Zeeb * passed back from the driver. rawx_mit() saves the ni on the m and the 3407*6b4cac81SBjoern A. Zeeb * m on the skb for us to be able to give feedback to net80211. 3408*6b4cac81SBjoern A. Zeeb */ 3409*6b4cac81SBjoern A. Zeeb void 3410*6b4cac81SBjoern A. Zeeb linuxkpi_ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb, 3411*6b4cac81SBjoern A. Zeeb int status) 3412*6b4cac81SBjoern A. Zeeb { 3413*6b4cac81SBjoern A. Zeeb struct ieee80211_node *ni; 3414*6b4cac81SBjoern A. Zeeb struct mbuf *m; 3415*6b4cac81SBjoern A. Zeeb 3416*6b4cac81SBjoern A. Zeeb m = skb->m; 3417*6b4cac81SBjoern A. Zeeb skb->m = NULL; 3418*6b4cac81SBjoern A. Zeeb 3419*6b4cac81SBjoern A. Zeeb if (m != NULL) { 3420*6b4cac81SBjoern A. Zeeb ni = m->m_pkthdr.PH_loc.ptr; 3421*6b4cac81SBjoern A. Zeeb /* Status: 0 is ok, != 0 is error. */ 3422*6b4cac81SBjoern A. Zeeb ieee80211_tx_complete(ni, m, status); 3423*6b4cac81SBjoern A. Zeeb /* ni & mbuf were consumed. */ 3424*6b4cac81SBjoern A. Zeeb } 3425*6b4cac81SBjoern A. Zeeb 3426*6b4cac81SBjoern A. Zeeb kfree_skb(skb); 3427*6b4cac81SBjoern A. Zeeb } 3428*6b4cac81SBjoern A. Zeeb 3429*6b4cac81SBjoern A. Zeeb /* 3430*6b4cac81SBjoern A. Zeeb * This is an internal bandaid for the moment for the way we glue 3431*6b4cac81SBjoern A. Zeeb * skbs and mbufs together for TX. Once we have skbs backed by 3432*6b4cac81SBjoern A. Zeeb * mbufs this should go away. 3433*6b4cac81SBjoern A. Zeeb * This is a public function but kept on the private KPI (lkpi_) 3434*6b4cac81SBjoern A. Zeeb * and is not exposed by a header file. 3435*6b4cac81SBjoern A. Zeeb */ 3436*6b4cac81SBjoern A. Zeeb static void 3437*6b4cac81SBjoern A. Zeeb lkpi_ieee80211_free_skb_mbuf(void *p) 3438*6b4cac81SBjoern A. Zeeb { 3439*6b4cac81SBjoern A. Zeeb struct ieee80211_node *ni; 3440*6b4cac81SBjoern A. Zeeb struct mbuf *m; 3441*6b4cac81SBjoern A. Zeeb 3442*6b4cac81SBjoern A. Zeeb if (p == NULL) 3443*6b4cac81SBjoern A. Zeeb return; 3444*6b4cac81SBjoern A. Zeeb 3445*6b4cac81SBjoern A. Zeeb m = (struct mbuf *)p; 3446*6b4cac81SBjoern A. Zeeb M_ASSERTPKTHDR(m); 3447*6b4cac81SBjoern A. Zeeb 3448*6b4cac81SBjoern A. Zeeb ni = m->m_pkthdr.PH_loc.ptr; 3449*6b4cac81SBjoern A. Zeeb m->m_pkthdr.PH_loc.ptr = NULL; 3450*6b4cac81SBjoern A. Zeeb if (ni != NULL) 3451*6b4cac81SBjoern A. Zeeb ieee80211_free_node(ni); 3452*6b4cac81SBjoern A. Zeeb m_freem(m); 3453*6b4cac81SBjoern A. Zeeb } 3454*6b4cac81SBjoern A. Zeeb 3455*6b4cac81SBjoern A. Zeeb void 3456*6b4cac81SBjoern A. Zeeb linuxkpi_ieee80211_queue_delayed_work(struct ieee80211_hw *hw, 3457*6b4cac81SBjoern A. Zeeb struct delayed_work *w, int delay) 3458*6b4cac81SBjoern A. Zeeb { 3459*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 3460*6b4cac81SBjoern A. Zeeb 3461*6b4cac81SBjoern A. Zeeb /* Need to make sure hw is in a stable (non-suspended) state. */ 3462*6b4cac81SBjoern A. Zeeb IMPROVE(); 3463*6b4cac81SBjoern A. Zeeb 3464*6b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 3465*6b4cac81SBjoern A. Zeeb queue_delayed_work(lhw->workq, w, delay); 3466*6b4cac81SBjoern A. Zeeb } 3467*6b4cac81SBjoern A. Zeeb 3468*6b4cac81SBjoern A. Zeeb void 3469*6b4cac81SBjoern A. Zeeb linuxkpi_ieee80211_queue_work(struct ieee80211_hw *hw, 3470*6b4cac81SBjoern A. Zeeb struct work_struct *w) 3471*6b4cac81SBjoern A. Zeeb { 3472*6b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 3473*6b4cac81SBjoern A. Zeeb 3474*6b4cac81SBjoern A. Zeeb /* Need to make sure hw is in a stable (non-suspended) state. */ 3475*6b4cac81SBjoern A. Zeeb IMPROVE(); 3476*6b4cac81SBjoern A. Zeeb 3477*6b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 3478*6b4cac81SBjoern A. Zeeb queue_work(lhw->workq, w); 3479*6b4cac81SBjoern A. Zeeb } 3480*6b4cac81SBjoern A. Zeeb 3481*6b4cac81SBjoern A. Zeeb struct sk_buff * 3482*6b4cac81SBjoern A. Zeeb linuxkpi_ieee80211_pspoll_get(struct ieee80211_hw *hw, 3483*6b4cac81SBjoern A. Zeeb struct ieee80211_vif *vif) 3484*6b4cac81SBjoern A. Zeeb { 3485*6b4cac81SBjoern A. Zeeb struct lkpi_vif *lvif; 3486*6b4cac81SBjoern A. Zeeb struct ieee80211vap *vap; 3487*6b4cac81SBjoern A. Zeeb struct sk_buff *skb; 3488*6b4cac81SBjoern A. Zeeb struct ieee80211_frame_pspoll *psp; 3489*6b4cac81SBjoern A. Zeeb uint16_t v; 3490*6b4cac81SBjoern A. Zeeb 3491*6b4cac81SBjoern A. Zeeb skb = dev_alloc_skb(hw->extra_tx_headroom + sizeof(*psp)); 3492*6b4cac81SBjoern A. Zeeb if (skb == NULL) 3493*6b4cac81SBjoern A. Zeeb return (NULL); 3494*6b4cac81SBjoern A. Zeeb 3495*6b4cac81SBjoern A. Zeeb skb_reserve(skb, hw->extra_tx_headroom); 3496*6b4cac81SBjoern A. Zeeb 3497*6b4cac81SBjoern A. Zeeb lvif = VIF_TO_LVIF(vif); 3498*6b4cac81SBjoern A. Zeeb vap = LVIF_TO_VAP(lvif); 3499*6b4cac81SBjoern A. Zeeb 3500*6b4cac81SBjoern A. Zeeb psp = skb_put_zero(skb, sizeof(*psp)); 3501*6b4cac81SBjoern A. Zeeb psp->i_fc[0] = IEEE80211_FC0_VERSION_0; 3502*6b4cac81SBjoern A. Zeeb psp->i_fc[0] |= IEEE80211_FC0_SUBTYPE_PS_POLL | IEEE80211_FC0_TYPE_CTL; 3503*6b4cac81SBjoern A. Zeeb v = htole16(vif->bss_conf.aid | 1<<15 | 1<<16); 3504*6b4cac81SBjoern A. Zeeb memcpy(&psp->i_aid, &v, sizeof(v)); 3505*6b4cac81SBjoern A. Zeeb IEEE80211_ADDR_COPY(psp->i_bssid, vap->iv_bss->ni_macaddr); 3506*6b4cac81SBjoern A. Zeeb IEEE80211_ADDR_COPY(psp->i_ta, vif->addr); 3507*6b4cac81SBjoern A. Zeeb 3508*6b4cac81SBjoern A. Zeeb return (skb); 3509*6b4cac81SBjoern A. Zeeb } 3510*6b4cac81SBjoern A. Zeeb 3511*6b4cac81SBjoern A. Zeeb struct sk_buff * 3512*6b4cac81SBjoern A. Zeeb linuxkpi_ieee80211_nullfunc_get(struct ieee80211_hw *hw, 3513*6b4cac81SBjoern A. Zeeb struct ieee80211_vif *vif, bool qos) 3514*6b4cac81SBjoern A. Zeeb { 3515*6b4cac81SBjoern A. Zeeb struct lkpi_vif *lvif; 3516*6b4cac81SBjoern A. Zeeb struct ieee80211vap *vap; 3517*6b4cac81SBjoern A. Zeeb struct sk_buff *skb; 3518*6b4cac81SBjoern A. Zeeb struct ieee80211_frame *nullf; 3519*6b4cac81SBjoern A. Zeeb 3520*6b4cac81SBjoern A. Zeeb skb = dev_alloc_skb(hw->extra_tx_headroom + sizeof(*nullf)); 3521*6b4cac81SBjoern A. Zeeb if (skb == NULL) 3522*6b4cac81SBjoern A. Zeeb return (NULL); 3523*6b4cac81SBjoern A. Zeeb 3524*6b4cac81SBjoern A. Zeeb skb_reserve(skb, hw->extra_tx_headroom); 3525*6b4cac81SBjoern A. Zeeb 3526*6b4cac81SBjoern A. Zeeb lvif = VIF_TO_LVIF(vif); 3527*6b4cac81SBjoern A. Zeeb vap = LVIF_TO_VAP(lvif); 3528*6b4cac81SBjoern A. Zeeb 3529*6b4cac81SBjoern A. Zeeb nullf = skb_put_zero(skb, sizeof(*nullf)); 3530*6b4cac81SBjoern A. Zeeb nullf->i_fc[0] = IEEE80211_FC0_VERSION_0; 3531*6b4cac81SBjoern A. Zeeb nullf->i_fc[0] |= IEEE80211_FC0_SUBTYPE_NODATA | IEEE80211_FC0_TYPE_DATA; 3532*6b4cac81SBjoern A. Zeeb nullf->i_fc[1] = IEEE80211_FC1_DIR_TODS; 3533*6b4cac81SBjoern A. Zeeb 3534*6b4cac81SBjoern A. Zeeb IEEE80211_ADDR_COPY(nullf->i_addr1, vap->iv_bss->ni_bssid); 3535*6b4cac81SBjoern A. Zeeb IEEE80211_ADDR_COPY(nullf->i_addr2, vif->addr); 3536*6b4cac81SBjoern A. Zeeb IEEE80211_ADDR_COPY(nullf->i_addr3, vap->iv_bss->ni_macaddr); 3537*6b4cac81SBjoern A. Zeeb 3538*6b4cac81SBjoern A. Zeeb return (skb); 3539*6b4cac81SBjoern A. Zeeb } 3540*6b4cac81SBjoern A. Zeeb 3541*6b4cac81SBjoern A. Zeeb struct wireless_dev * 3542*6b4cac81SBjoern A. Zeeb linuxkpi_ieee80211_vif_to_wdev(struct ieee80211_vif *vif) 3543*6b4cac81SBjoern A. Zeeb { 3544*6b4cac81SBjoern A. Zeeb struct lkpi_vif *lvif; 3545*6b4cac81SBjoern A. Zeeb 3546*6b4cac81SBjoern A. Zeeb lvif = VIF_TO_LVIF(vif); 3547*6b4cac81SBjoern A. Zeeb return (&lvif->wdev); 3548*6b4cac81SBjoern A. Zeeb } 3549*6b4cac81SBjoern A. Zeeb 3550*6b4cac81SBjoern A. Zeeb void 3551*6b4cac81SBjoern A. Zeeb linuxkpi_ieee80211_connection_loss(struct ieee80211_vif *vif) 3552*6b4cac81SBjoern A. Zeeb { 3553*6b4cac81SBjoern A. Zeeb struct lkpi_vif *lvif; 3554*6b4cac81SBjoern A. Zeeb struct ieee80211vap *vap; 3555*6b4cac81SBjoern A. Zeeb enum ieee80211_state nstate; 3556*6b4cac81SBjoern A. Zeeb int arg; 3557*6b4cac81SBjoern A. Zeeb 3558*6b4cac81SBjoern A. Zeeb lvif = VIF_TO_LVIF(vif); 3559*6b4cac81SBjoern A. Zeeb vap = LVIF_TO_VAP(lvif); 3560*6b4cac81SBjoern A. Zeeb 3561*6b4cac81SBjoern A. Zeeb /* 3562*6b4cac81SBjoern A. Zeeb * Go to scan; otherwise we need to elaborately check state and 3563*6b4cac81SBjoern A. Zeeb * handle accordingly, e.g., if in RUN we could call iv_bmiss. 3564*6b4cac81SBjoern A. Zeeb * Let the statemachine handle all neccessary changes. 3565*6b4cac81SBjoern A. Zeeb */ 3566*6b4cac81SBjoern A. Zeeb nstate = IEEE80211_S_SCAN; 3567*6b4cac81SBjoern A. Zeeb arg = 0; 3568*6b4cac81SBjoern A. Zeeb 3569*6b4cac81SBjoern A. Zeeb if (debug_80211 & D80211_TRACE) 3570*6b4cac81SBjoern A. Zeeb ic_printf(vap->iv_ic, "%s: vif %p\n", __func__, vif); 3571*6b4cac81SBjoern A. Zeeb ieee80211_new_state(vap, nstate, arg); 3572*6b4cac81SBjoern A. Zeeb } 3573*6b4cac81SBjoern A. Zeeb 3574*6b4cac81SBjoern A. Zeeb MODULE_VERSION(linuxkpi_wlan, 1); 3575*6b4cac81SBjoern A. Zeeb MODULE_DEPEND(linuxkpi_wlan, linuxkpi, 1, 1, 1); 3576*6b4cac81SBjoern A. Zeeb MODULE_DEPEND(linuxkpi_wlan, wlan, 1, 1, 1); 3577