1*7453645fSAndriy Voskoboinyk /* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ 2*7453645fSAndriy Voskoboinyk 3*7453645fSAndriy Voskoboinyk /*- 4*7453645fSAndriy Voskoboinyk * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr> 5*7453645fSAndriy Voskoboinyk * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org> 6*7453645fSAndriy Voskoboinyk * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org> 7*7453645fSAndriy Voskoboinyk * 8*7453645fSAndriy Voskoboinyk * Permission to use, copy, modify, and distribute this software for any 9*7453645fSAndriy Voskoboinyk * purpose with or without fee is hereby granted, provided that the above 10*7453645fSAndriy Voskoboinyk * copyright notice and this permission notice appear in all copies. 11*7453645fSAndriy Voskoboinyk * 12*7453645fSAndriy Voskoboinyk * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13*7453645fSAndriy Voskoboinyk * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14*7453645fSAndriy Voskoboinyk * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15*7453645fSAndriy Voskoboinyk * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16*7453645fSAndriy Voskoboinyk * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17*7453645fSAndriy Voskoboinyk * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18*7453645fSAndriy Voskoboinyk * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19*7453645fSAndriy Voskoboinyk */ 20*7453645fSAndriy Voskoboinyk 21*7453645fSAndriy Voskoboinyk #include <sys/cdefs.h> 22*7453645fSAndriy Voskoboinyk __FBSDID("$FreeBSD$"); 23*7453645fSAndriy Voskoboinyk 24*7453645fSAndriy Voskoboinyk #include "opt_wlan.h" 25*7453645fSAndriy Voskoboinyk 26*7453645fSAndriy Voskoboinyk #include <sys/param.h> 27*7453645fSAndriy Voskoboinyk #include <sys/lock.h> 28*7453645fSAndriy Voskoboinyk #include <sys/mutex.h> 29*7453645fSAndriy Voskoboinyk #include <sys/mbuf.h> 30*7453645fSAndriy Voskoboinyk #include <sys/kernel.h> 31*7453645fSAndriy Voskoboinyk #include <sys/socket.h> 32*7453645fSAndriy Voskoboinyk #include <sys/systm.h> 33*7453645fSAndriy Voskoboinyk #include <sys/malloc.h> 34*7453645fSAndriy Voskoboinyk #include <sys/queue.h> 35*7453645fSAndriy Voskoboinyk #include <sys/taskqueue.h> 36*7453645fSAndriy Voskoboinyk #include <sys/bus.h> 37*7453645fSAndriy Voskoboinyk #include <sys/endian.h> 38*7453645fSAndriy Voskoboinyk 39*7453645fSAndriy Voskoboinyk #include <net/if.h> 40*7453645fSAndriy Voskoboinyk #include <net/if_var.h> 41*7453645fSAndriy Voskoboinyk #include <net/ethernet.h> 42*7453645fSAndriy Voskoboinyk #include <net/if_media.h> 43*7453645fSAndriy Voskoboinyk 44*7453645fSAndriy Voskoboinyk #include <net80211/ieee80211_var.h> 45*7453645fSAndriy Voskoboinyk #include <net80211/ieee80211_radiotap.h> 46*7453645fSAndriy Voskoboinyk #include <net80211/ieee80211_ratectl.h> 47*7453645fSAndriy Voskoboinyk #ifdef IEEE80211_SUPPORT_SUPERG 48*7453645fSAndriy Voskoboinyk #include <net80211/ieee80211_superg.h> 49*7453645fSAndriy Voskoboinyk #endif 50*7453645fSAndriy Voskoboinyk 51*7453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwnreg.h> 52*7453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwnvar.h> 53*7453645fSAndriy Voskoboinyk 54*7453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwn_beacon.h> 55*7453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwn_debug.h> 56*7453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwn_ridx.h> 57*7453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwn_tx.h> 58*7453645fSAndriy Voskoboinyk 59*7453645fSAndriy Voskoboinyk 60*7453645fSAndriy Voskoboinyk void 61*7453645fSAndriy Voskoboinyk rtwn_drain_mbufq(struct rtwn_softc *sc) 62*7453645fSAndriy Voskoboinyk { 63*7453645fSAndriy Voskoboinyk struct mbuf *m; 64*7453645fSAndriy Voskoboinyk struct ieee80211_node *ni; 65*7453645fSAndriy Voskoboinyk RTWN_ASSERT_LOCKED(sc); 66*7453645fSAndriy Voskoboinyk while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { 67*7453645fSAndriy Voskoboinyk ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 68*7453645fSAndriy Voskoboinyk m->m_pkthdr.rcvif = NULL; 69*7453645fSAndriy Voskoboinyk ieee80211_free_node(ni); 70*7453645fSAndriy Voskoboinyk m_freem(m); 71*7453645fSAndriy Voskoboinyk } 72*7453645fSAndriy Voskoboinyk } 73*7453645fSAndriy Voskoboinyk 74*7453645fSAndriy Voskoboinyk #ifdef IEEE80211_SUPPORT_SUPERG 75*7453645fSAndriy Voskoboinyk void 76*7453645fSAndriy Voskoboinyk rtwn_ff_flush_all(struct rtwn_softc *sc, union sec_param *data) 77*7453645fSAndriy Voskoboinyk { 78*7453645fSAndriy Voskoboinyk struct ieee80211com *ic = &sc->sc_ic; 79*7453645fSAndriy Voskoboinyk 80*7453645fSAndriy Voskoboinyk RTWN_UNLOCK(sc); 81*7453645fSAndriy Voskoboinyk ieee80211_ff_flush_all(ic); 82*7453645fSAndriy Voskoboinyk RTWN_LOCK(sc); 83*7453645fSAndriy Voskoboinyk } 84*7453645fSAndriy Voskoboinyk #endif 85*7453645fSAndriy Voskoboinyk 86*7453645fSAndriy Voskoboinyk static uint8_t 87*7453645fSAndriy Voskoboinyk rtwn_get_cipher(u_int ic_cipher) 88*7453645fSAndriy Voskoboinyk { 89*7453645fSAndriy Voskoboinyk uint8_t cipher; 90*7453645fSAndriy Voskoboinyk 91*7453645fSAndriy Voskoboinyk switch (ic_cipher) { 92*7453645fSAndriy Voskoboinyk case IEEE80211_CIPHER_NONE: 93*7453645fSAndriy Voskoboinyk cipher = RTWN_TXDW1_CIPHER_NONE; 94*7453645fSAndriy Voskoboinyk break; 95*7453645fSAndriy Voskoboinyk case IEEE80211_CIPHER_WEP: 96*7453645fSAndriy Voskoboinyk case IEEE80211_CIPHER_TKIP: 97*7453645fSAndriy Voskoboinyk cipher = RTWN_TXDW1_CIPHER_RC4; 98*7453645fSAndriy Voskoboinyk break; 99*7453645fSAndriy Voskoboinyk case IEEE80211_CIPHER_AES_CCM: 100*7453645fSAndriy Voskoboinyk cipher = RTWN_TXDW1_CIPHER_AES; 101*7453645fSAndriy Voskoboinyk break; 102*7453645fSAndriy Voskoboinyk default: 103*7453645fSAndriy Voskoboinyk KASSERT(0, ("%s: unknown cipher %d\n", __func__, 104*7453645fSAndriy Voskoboinyk ic_cipher)); 105*7453645fSAndriy Voskoboinyk return (RTWN_TXDW1_CIPHER_SM4); 106*7453645fSAndriy Voskoboinyk } 107*7453645fSAndriy Voskoboinyk 108*7453645fSAndriy Voskoboinyk return (cipher); 109*7453645fSAndriy Voskoboinyk } 110*7453645fSAndriy Voskoboinyk 111*7453645fSAndriy Voskoboinyk static int 112*7453645fSAndriy Voskoboinyk rtwn_tx_data(struct rtwn_softc *sc, struct ieee80211_node *ni, 113*7453645fSAndriy Voskoboinyk struct mbuf *m) 114*7453645fSAndriy Voskoboinyk { 115*7453645fSAndriy Voskoboinyk const struct ieee80211_txparam *tp; 116*7453645fSAndriy Voskoboinyk struct ieee80211com *ic = &sc->sc_ic; 117*7453645fSAndriy Voskoboinyk struct ieee80211vap *vap = ni->ni_vap; 118*7453645fSAndriy Voskoboinyk struct ieee80211_key *k = NULL; 119*7453645fSAndriy Voskoboinyk struct ieee80211_channel *chan; 120*7453645fSAndriy Voskoboinyk struct ieee80211_frame *wh; 121*7453645fSAndriy Voskoboinyk struct rtwn_tx_desc_common *txd; 122*7453645fSAndriy Voskoboinyk struct rtwn_tx_buf buf; 123*7453645fSAndriy Voskoboinyk uint8_t rate, ridx, type; 124*7453645fSAndriy Voskoboinyk u_int cipher; 125*7453645fSAndriy Voskoboinyk int ismcast, maxretry; 126*7453645fSAndriy Voskoboinyk 127*7453645fSAndriy Voskoboinyk RTWN_ASSERT_LOCKED(sc); 128*7453645fSAndriy Voskoboinyk 129*7453645fSAndriy Voskoboinyk wh = mtod(m, struct ieee80211_frame *); 130*7453645fSAndriy Voskoboinyk type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 131*7453645fSAndriy Voskoboinyk ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); 132*7453645fSAndriy Voskoboinyk 133*7453645fSAndriy Voskoboinyk chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ? 134*7453645fSAndriy Voskoboinyk ni->ni_chan : ic->ic_curchan; 135*7453645fSAndriy Voskoboinyk tp = &vap->iv_txparms[ieee80211_chan2mode(chan)]; 136*7453645fSAndriy Voskoboinyk maxretry = tp->maxretry; 137*7453645fSAndriy Voskoboinyk 138*7453645fSAndriy Voskoboinyk /* Choose a TX rate index. */ 139*7453645fSAndriy Voskoboinyk if (type == IEEE80211_FC0_TYPE_MGT) 140*7453645fSAndriy Voskoboinyk rate = tp->mgmtrate; 141*7453645fSAndriy Voskoboinyk else if (ismcast) 142*7453645fSAndriy Voskoboinyk rate = tp->mcastrate; 143*7453645fSAndriy Voskoboinyk else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) 144*7453645fSAndriy Voskoboinyk rate = tp->ucastrate; 145*7453645fSAndriy Voskoboinyk else if (m->m_flags & M_EAPOL) 146*7453645fSAndriy Voskoboinyk rate = tp->mgmtrate; 147*7453645fSAndriy Voskoboinyk else { 148*7453645fSAndriy Voskoboinyk if (sc->sc_ratectl == RTWN_RATECTL_NET80211) { 149*7453645fSAndriy Voskoboinyk /* XXX pass pktlen */ 150*7453645fSAndriy Voskoboinyk (void) ieee80211_ratectl_rate(ni, NULL, 0); 151*7453645fSAndriy Voskoboinyk rate = ni->ni_txrate; 152*7453645fSAndriy Voskoboinyk } else { 153*7453645fSAndriy Voskoboinyk if (ni->ni_flags & IEEE80211_NODE_HT) 154*7453645fSAndriy Voskoboinyk rate = IEEE80211_RATE_MCS | 0x4; /* MCS4 */ 155*7453645fSAndriy Voskoboinyk else if (ic->ic_curmode != IEEE80211_MODE_11B) 156*7453645fSAndriy Voskoboinyk rate = ridx2rate[RTWN_RIDX_OFDM36]; 157*7453645fSAndriy Voskoboinyk else 158*7453645fSAndriy Voskoboinyk rate = ridx2rate[RTWN_RIDX_CCK55]; 159*7453645fSAndriy Voskoboinyk } 160*7453645fSAndriy Voskoboinyk } 161*7453645fSAndriy Voskoboinyk 162*7453645fSAndriy Voskoboinyk ridx = rate2ridx(rate); 163*7453645fSAndriy Voskoboinyk 164*7453645fSAndriy Voskoboinyk cipher = IEEE80211_CIPHER_NONE; 165*7453645fSAndriy Voskoboinyk if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { 166*7453645fSAndriy Voskoboinyk k = ieee80211_crypto_encap(ni, m); 167*7453645fSAndriy Voskoboinyk if (k == NULL) { 168*7453645fSAndriy Voskoboinyk device_printf(sc->sc_dev, 169*7453645fSAndriy Voskoboinyk "ieee80211_crypto_encap returns NULL.\n"); 170*7453645fSAndriy Voskoboinyk return (ENOBUFS); 171*7453645fSAndriy Voskoboinyk } 172*7453645fSAndriy Voskoboinyk if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT)) 173*7453645fSAndriy Voskoboinyk cipher = k->wk_cipher->ic_cipher; 174*7453645fSAndriy Voskoboinyk 175*7453645fSAndriy Voskoboinyk /* in case packet header moved, reset pointer */ 176*7453645fSAndriy Voskoboinyk wh = mtod(m, struct ieee80211_frame *); 177*7453645fSAndriy Voskoboinyk } 178*7453645fSAndriy Voskoboinyk 179*7453645fSAndriy Voskoboinyk /* Fill Tx descriptor. */ 180*7453645fSAndriy Voskoboinyk txd = (struct rtwn_tx_desc_common *)&buf; 181*7453645fSAndriy Voskoboinyk memset(txd, 0, sc->txdesc_len); 182*7453645fSAndriy Voskoboinyk txd->txdw1 = htole32(SM(RTWN_TXDW1_CIPHER, rtwn_get_cipher(cipher))); 183*7453645fSAndriy Voskoboinyk 184*7453645fSAndriy Voskoboinyk rtwn_fill_tx_desc(sc, ni, m, txd, ridx, maxretry); 185*7453645fSAndriy Voskoboinyk 186*7453645fSAndriy Voskoboinyk if (ieee80211_radiotap_active_vap(vap)) { 187*7453645fSAndriy Voskoboinyk struct rtwn_tx_radiotap_header *tap = &sc->sc_txtap; 188*7453645fSAndriy Voskoboinyk 189*7453645fSAndriy Voskoboinyk tap->wt_flags = rtwn_tx_radiotap_flags(sc, txd); 190*7453645fSAndriy Voskoboinyk if (k != NULL) 191*7453645fSAndriy Voskoboinyk tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; 192*7453645fSAndriy Voskoboinyk ieee80211_radiotap_tx(vap, m); 193*7453645fSAndriy Voskoboinyk } 194*7453645fSAndriy Voskoboinyk 195*7453645fSAndriy Voskoboinyk return (rtwn_tx_start(sc, ni, m, (uint8_t *)txd, type, 0)); 196*7453645fSAndriy Voskoboinyk } 197*7453645fSAndriy Voskoboinyk 198*7453645fSAndriy Voskoboinyk static int 199*7453645fSAndriy Voskoboinyk rtwn_tx_raw(struct rtwn_softc *sc, struct ieee80211_node *ni, 200*7453645fSAndriy Voskoboinyk struct mbuf *m, const struct ieee80211_bpf_params *params) 201*7453645fSAndriy Voskoboinyk { 202*7453645fSAndriy Voskoboinyk struct ieee80211vap *vap = ni->ni_vap; 203*7453645fSAndriy Voskoboinyk struct ieee80211_key *k = NULL; 204*7453645fSAndriy Voskoboinyk struct ieee80211_frame *wh; 205*7453645fSAndriy Voskoboinyk struct rtwn_tx_desc_common *txd; 206*7453645fSAndriy Voskoboinyk struct rtwn_tx_buf buf; 207*7453645fSAndriy Voskoboinyk uint8_t type; 208*7453645fSAndriy Voskoboinyk u_int cipher; 209*7453645fSAndriy Voskoboinyk 210*7453645fSAndriy Voskoboinyk /* Encrypt the frame if need be. */ 211*7453645fSAndriy Voskoboinyk cipher = IEEE80211_CIPHER_NONE; 212*7453645fSAndriy Voskoboinyk if (params->ibp_flags & IEEE80211_BPF_CRYPTO) { 213*7453645fSAndriy Voskoboinyk /* Retrieve key for TX. */ 214*7453645fSAndriy Voskoboinyk k = ieee80211_crypto_encap(ni, m); 215*7453645fSAndriy Voskoboinyk if (k == NULL) { 216*7453645fSAndriy Voskoboinyk device_printf(sc->sc_dev, 217*7453645fSAndriy Voskoboinyk "ieee80211_crypto_encap returns NULL.\n"); 218*7453645fSAndriy Voskoboinyk return (ENOBUFS); 219*7453645fSAndriy Voskoboinyk } 220*7453645fSAndriy Voskoboinyk if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT)) 221*7453645fSAndriy Voskoboinyk cipher = k->wk_cipher->ic_cipher; 222*7453645fSAndriy Voskoboinyk } 223*7453645fSAndriy Voskoboinyk 224*7453645fSAndriy Voskoboinyk wh = mtod(m, struct ieee80211_frame *); 225*7453645fSAndriy Voskoboinyk type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 226*7453645fSAndriy Voskoboinyk 227*7453645fSAndriy Voskoboinyk /* Fill Tx descriptor. */ 228*7453645fSAndriy Voskoboinyk txd = (struct rtwn_tx_desc_common *)&buf; 229*7453645fSAndriy Voskoboinyk memset(txd, 0, sc->txdesc_len); 230*7453645fSAndriy Voskoboinyk txd->txdw1 = htole32(SM(RTWN_TXDW1_CIPHER, rtwn_get_cipher(cipher))); 231*7453645fSAndriy Voskoboinyk 232*7453645fSAndriy Voskoboinyk rtwn_fill_tx_desc_raw(sc, ni, m, txd, params); 233*7453645fSAndriy Voskoboinyk 234*7453645fSAndriy Voskoboinyk if (ieee80211_radiotap_active_vap(vap)) { 235*7453645fSAndriy Voskoboinyk struct rtwn_tx_radiotap_header *tap = &sc->sc_txtap; 236*7453645fSAndriy Voskoboinyk 237*7453645fSAndriy Voskoboinyk tap->wt_flags = rtwn_tx_radiotap_flags(sc, txd); 238*7453645fSAndriy Voskoboinyk if (k != NULL) 239*7453645fSAndriy Voskoboinyk tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; 240*7453645fSAndriy Voskoboinyk ieee80211_radiotap_tx(vap, m); 241*7453645fSAndriy Voskoboinyk } 242*7453645fSAndriy Voskoboinyk 243*7453645fSAndriy Voskoboinyk return (rtwn_tx_start(sc, ni, m, (uint8_t *)txd, type, 0)); 244*7453645fSAndriy Voskoboinyk } 245*7453645fSAndriy Voskoboinyk 246*7453645fSAndriy Voskoboinyk int 247*7453645fSAndriy Voskoboinyk rtwn_transmit(struct ieee80211com *ic, struct mbuf *m) 248*7453645fSAndriy Voskoboinyk { 249*7453645fSAndriy Voskoboinyk struct rtwn_softc *sc = ic->ic_softc; 250*7453645fSAndriy Voskoboinyk int error; 251*7453645fSAndriy Voskoboinyk 252*7453645fSAndriy Voskoboinyk RTWN_LOCK(sc); 253*7453645fSAndriy Voskoboinyk if ((sc->sc_flags & RTWN_RUNNING) == 0) { 254*7453645fSAndriy Voskoboinyk RTWN_UNLOCK(sc); 255*7453645fSAndriy Voskoboinyk return (ENXIO); 256*7453645fSAndriy Voskoboinyk } 257*7453645fSAndriy Voskoboinyk error = mbufq_enqueue(&sc->sc_snd, m); 258*7453645fSAndriy Voskoboinyk if (error) { 259*7453645fSAndriy Voskoboinyk RTWN_UNLOCK(sc); 260*7453645fSAndriy Voskoboinyk return (error); 261*7453645fSAndriy Voskoboinyk } 262*7453645fSAndriy Voskoboinyk rtwn_start(sc); 263*7453645fSAndriy Voskoboinyk RTWN_UNLOCK(sc); 264*7453645fSAndriy Voskoboinyk 265*7453645fSAndriy Voskoboinyk return (0); 266*7453645fSAndriy Voskoboinyk } 267*7453645fSAndriy Voskoboinyk 268*7453645fSAndriy Voskoboinyk void 269*7453645fSAndriy Voskoboinyk rtwn_start(struct rtwn_softc *sc) 270*7453645fSAndriy Voskoboinyk { 271*7453645fSAndriy Voskoboinyk struct ieee80211_node *ni; 272*7453645fSAndriy Voskoboinyk struct mbuf *m; 273*7453645fSAndriy Voskoboinyk 274*7453645fSAndriy Voskoboinyk RTWN_ASSERT_LOCKED(sc); 275*7453645fSAndriy Voskoboinyk while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { 276*7453645fSAndriy Voskoboinyk if (sc->qfullmsk != 0) { 277*7453645fSAndriy Voskoboinyk mbufq_prepend(&sc->sc_snd, m); 278*7453645fSAndriy Voskoboinyk break; 279*7453645fSAndriy Voskoboinyk } 280*7453645fSAndriy Voskoboinyk ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 281*7453645fSAndriy Voskoboinyk m->m_pkthdr.rcvif = NULL; 282*7453645fSAndriy Voskoboinyk 283*7453645fSAndriy Voskoboinyk RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, 284*7453645fSAndriy Voskoboinyk "%s: called; m %p, ni %p\n", __func__, m, ni); 285*7453645fSAndriy Voskoboinyk 286*7453645fSAndriy Voskoboinyk if (rtwn_tx_data(sc, ni, m) != 0) { 287*7453645fSAndriy Voskoboinyk if_inc_counter(ni->ni_vap->iv_ifp, 288*7453645fSAndriy Voskoboinyk IFCOUNTER_OERRORS, 1); 289*7453645fSAndriy Voskoboinyk m_freem(m); 290*7453645fSAndriy Voskoboinyk #ifdef D4054 291*7453645fSAndriy Voskoboinyk ieee80211_tx_watchdog_refresh(ni->ni_ic, -1, 0); 292*7453645fSAndriy Voskoboinyk #endif 293*7453645fSAndriy Voskoboinyk ieee80211_free_node(ni); 294*7453645fSAndriy Voskoboinyk break; 295*7453645fSAndriy Voskoboinyk } 296*7453645fSAndriy Voskoboinyk } 297*7453645fSAndriy Voskoboinyk } 298*7453645fSAndriy Voskoboinyk 299*7453645fSAndriy Voskoboinyk int 300*7453645fSAndriy Voskoboinyk rtwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 301*7453645fSAndriy Voskoboinyk const struct ieee80211_bpf_params *params) 302*7453645fSAndriy Voskoboinyk { 303*7453645fSAndriy Voskoboinyk struct ieee80211com *ic = ni->ni_ic; 304*7453645fSAndriy Voskoboinyk struct rtwn_softc *sc = ic->ic_softc; 305*7453645fSAndriy Voskoboinyk int error; 306*7453645fSAndriy Voskoboinyk 307*7453645fSAndriy Voskoboinyk RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, "%s: called; m %p, ni %p\n", 308*7453645fSAndriy Voskoboinyk __func__, m, ni); 309*7453645fSAndriy Voskoboinyk 310*7453645fSAndriy Voskoboinyk /* prevent management frames from being sent if we're not ready */ 311*7453645fSAndriy Voskoboinyk RTWN_LOCK(sc); 312*7453645fSAndriy Voskoboinyk if (!(sc->sc_flags & RTWN_RUNNING)) { 313*7453645fSAndriy Voskoboinyk error = ENETDOWN; 314*7453645fSAndriy Voskoboinyk goto end; 315*7453645fSAndriy Voskoboinyk } 316*7453645fSAndriy Voskoboinyk 317*7453645fSAndriy Voskoboinyk if (sc->qfullmsk != 0) { 318*7453645fSAndriy Voskoboinyk error = ENOBUFS; 319*7453645fSAndriy Voskoboinyk goto end; 320*7453645fSAndriy Voskoboinyk } 321*7453645fSAndriy Voskoboinyk 322*7453645fSAndriy Voskoboinyk if (params == NULL) { 323*7453645fSAndriy Voskoboinyk /* 324*7453645fSAndriy Voskoboinyk * Legacy path; interpret frame contents to decide 325*7453645fSAndriy Voskoboinyk * precisely how to send the frame. 326*7453645fSAndriy Voskoboinyk */ 327*7453645fSAndriy Voskoboinyk error = rtwn_tx_data(sc, ni, m); 328*7453645fSAndriy Voskoboinyk } else { 329*7453645fSAndriy Voskoboinyk /* 330*7453645fSAndriy Voskoboinyk * Caller supplied explicit parameters to use in 331*7453645fSAndriy Voskoboinyk * sending the frame. 332*7453645fSAndriy Voskoboinyk */ 333*7453645fSAndriy Voskoboinyk error = rtwn_tx_raw(sc, ni, m, params); 334*7453645fSAndriy Voskoboinyk } 335*7453645fSAndriy Voskoboinyk 336*7453645fSAndriy Voskoboinyk end: 337*7453645fSAndriy Voskoboinyk if (error != 0) { 338*7453645fSAndriy Voskoboinyk if (m->m_flags & M_TXCB) 339*7453645fSAndriy Voskoboinyk ieee80211_process_callback(ni, m, 1); 340*7453645fSAndriy Voskoboinyk m_freem(m); 341*7453645fSAndriy Voskoboinyk } 342*7453645fSAndriy Voskoboinyk 343*7453645fSAndriy Voskoboinyk RTWN_UNLOCK(sc); 344*7453645fSAndriy Voskoboinyk 345*7453645fSAndriy Voskoboinyk return (error); 346*7453645fSAndriy Voskoboinyk } 347