xref: /freebsd/sys/dev/rtwn/if_rtwn_tx.c (revision 7453645f2a9411a3f9d982b768bcc323f41cf906)
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