xref: /freebsd/sys/dev/rtwn/if_rtwn_tx.c (revision fdc88416118759692fb1773deffe298e86cc902b)
17453645fSAndriy Voskoboinyk /*	$OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $	*/
27453645fSAndriy Voskoboinyk 
37453645fSAndriy Voskoboinyk /*-
47453645fSAndriy Voskoboinyk  * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
57453645fSAndriy Voskoboinyk  * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
67453645fSAndriy Voskoboinyk  * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
77453645fSAndriy Voskoboinyk  *
87453645fSAndriy Voskoboinyk  * Permission to use, copy, modify, and distribute this software for any
97453645fSAndriy Voskoboinyk  * purpose with or without fee is hereby granted, provided that the above
107453645fSAndriy Voskoboinyk  * copyright notice and this permission notice appear in all copies.
117453645fSAndriy Voskoboinyk  *
127453645fSAndriy Voskoboinyk  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
137453645fSAndriy Voskoboinyk  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
147453645fSAndriy Voskoboinyk  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
157453645fSAndriy Voskoboinyk  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
167453645fSAndriy Voskoboinyk  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
177453645fSAndriy Voskoboinyk  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
187453645fSAndriy Voskoboinyk  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
197453645fSAndriy Voskoboinyk  */
207453645fSAndriy Voskoboinyk 
217453645fSAndriy Voskoboinyk #include <sys/cdefs.h>
227453645fSAndriy Voskoboinyk #include "opt_wlan.h"
237453645fSAndriy Voskoboinyk 
247453645fSAndriy Voskoboinyk #include <sys/param.h>
257453645fSAndriy Voskoboinyk #include <sys/lock.h>
267453645fSAndriy Voskoboinyk #include <sys/mutex.h>
277453645fSAndriy Voskoboinyk #include <sys/mbuf.h>
287453645fSAndriy Voskoboinyk #include <sys/kernel.h>
297453645fSAndriy Voskoboinyk #include <sys/socket.h>
307453645fSAndriy Voskoboinyk #include <sys/systm.h>
317453645fSAndriy Voskoboinyk #include <sys/malloc.h>
327453645fSAndriy Voskoboinyk #include <sys/queue.h>
337453645fSAndriy Voskoboinyk #include <sys/taskqueue.h>
347453645fSAndriy Voskoboinyk #include <sys/bus.h>
357453645fSAndriy Voskoboinyk #include <sys/endian.h>
367453645fSAndriy Voskoboinyk 
377453645fSAndriy Voskoboinyk #include <net/if.h>
387453645fSAndriy Voskoboinyk #include <net/if_var.h>
397453645fSAndriy Voskoboinyk #include <net/ethernet.h>
407453645fSAndriy Voskoboinyk #include <net/if_media.h>
417453645fSAndriy Voskoboinyk 
427453645fSAndriy Voskoboinyk #include <net80211/ieee80211_var.h>
437453645fSAndriy Voskoboinyk #include <net80211/ieee80211_radiotap.h>
447453645fSAndriy Voskoboinyk #include <net80211/ieee80211_ratectl.h>
457453645fSAndriy Voskoboinyk #ifdef	IEEE80211_SUPPORT_SUPERG
467453645fSAndriy Voskoboinyk #include <net80211/ieee80211_superg.h>
477453645fSAndriy Voskoboinyk #endif
487453645fSAndriy Voskoboinyk 
497453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwnreg.h>
507453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwnvar.h>
517453645fSAndriy Voskoboinyk 
527453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwn_beacon.h>
537453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwn_debug.h>
547453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwn_ridx.h>
557453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwn_tx.h>
567453645fSAndriy Voskoboinyk 
577453645fSAndriy Voskoboinyk void
rtwn_drain_mbufq(struct rtwn_softc * sc)587453645fSAndriy Voskoboinyk rtwn_drain_mbufq(struct rtwn_softc *sc)
597453645fSAndriy Voskoboinyk {
607453645fSAndriy Voskoboinyk 	struct mbuf *m;
617453645fSAndriy Voskoboinyk 	struct ieee80211_node *ni;
627453645fSAndriy Voskoboinyk 	RTWN_ASSERT_LOCKED(sc);
637453645fSAndriy Voskoboinyk 	while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
647453645fSAndriy Voskoboinyk 		ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
657453645fSAndriy Voskoboinyk 		m->m_pkthdr.rcvif = NULL;
667453645fSAndriy Voskoboinyk 		ieee80211_free_node(ni);
677453645fSAndriy Voskoboinyk 		m_freem(m);
687453645fSAndriy Voskoboinyk 	}
697453645fSAndriy Voskoboinyk }
707453645fSAndriy Voskoboinyk 
717453645fSAndriy Voskoboinyk #ifdef IEEE80211_SUPPORT_SUPERG
727453645fSAndriy Voskoboinyk void
rtwn_ff_flush_all(struct rtwn_softc * sc,union sec_param * data)737453645fSAndriy Voskoboinyk rtwn_ff_flush_all(struct rtwn_softc *sc, union sec_param *data)
747453645fSAndriy Voskoboinyk {
757453645fSAndriy Voskoboinyk 	struct ieee80211com *ic = &sc->sc_ic;
767453645fSAndriy Voskoboinyk 
777453645fSAndriy Voskoboinyk 	RTWN_UNLOCK(sc);
787453645fSAndriy Voskoboinyk 	ieee80211_ff_flush_all(ic);
797453645fSAndriy Voskoboinyk 	RTWN_LOCK(sc);
807453645fSAndriy Voskoboinyk }
817453645fSAndriy Voskoboinyk #endif
827453645fSAndriy Voskoboinyk 
837453645fSAndriy Voskoboinyk static uint8_t
rtwn_get_cipher(u_int ic_cipher)847453645fSAndriy Voskoboinyk rtwn_get_cipher(u_int ic_cipher)
857453645fSAndriy Voskoboinyk {
867453645fSAndriy Voskoboinyk 	uint8_t cipher;
877453645fSAndriy Voskoboinyk 
887453645fSAndriy Voskoboinyk 	switch (ic_cipher) {
897453645fSAndriy Voskoboinyk 	case IEEE80211_CIPHER_NONE:
907453645fSAndriy Voskoboinyk 		cipher = RTWN_TXDW1_CIPHER_NONE;
917453645fSAndriy Voskoboinyk 		break;
927453645fSAndriy Voskoboinyk 	case IEEE80211_CIPHER_WEP:
937453645fSAndriy Voskoboinyk 	case IEEE80211_CIPHER_TKIP:
947453645fSAndriy Voskoboinyk 		cipher = RTWN_TXDW1_CIPHER_RC4;
957453645fSAndriy Voskoboinyk 		break;
967453645fSAndriy Voskoboinyk 	case IEEE80211_CIPHER_AES_CCM:
977453645fSAndriy Voskoboinyk 		cipher = RTWN_TXDW1_CIPHER_AES;
987453645fSAndriy Voskoboinyk 		break;
997453645fSAndriy Voskoboinyk 	default:
1007453645fSAndriy Voskoboinyk 		KASSERT(0, ("%s: unknown cipher %d\n", __func__,
1017453645fSAndriy Voskoboinyk 		    ic_cipher));
1027453645fSAndriy Voskoboinyk 		return (RTWN_TXDW1_CIPHER_SM4);
1037453645fSAndriy Voskoboinyk 	}
1047453645fSAndriy Voskoboinyk 
1057453645fSAndriy Voskoboinyk 	return (cipher);
1067453645fSAndriy Voskoboinyk }
1077453645fSAndriy Voskoboinyk 
108*fdc88416SAdrian Chadd static uint8_t
rtwn_tx_ratectl_to_ridx(struct rtwn_softc * sc,struct ieee80211_node * ni,struct ieee80211_node_txrate * txr)109*fdc88416SAdrian Chadd rtwn_tx_ratectl_to_ridx(struct rtwn_softc *sc, struct ieee80211_node *ni,
110*fdc88416SAdrian Chadd     struct ieee80211_node_txrate *txr)
111*fdc88416SAdrian Chadd {
112*fdc88416SAdrian Chadd 	/* TODO: this should be based on the node channel */
113*fdc88416SAdrian Chadd 	struct ieee80211com *ic = &sc->sc_ic;
114*fdc88416SAdrian Chadd 	uint8_t ridx;
115*fdc88416SAdrian Chadd 
116*fdc88416SAdrian Chadd 	switch (txr->type) {
117*fdc88416SAdrian Chadd 	case IEEE80211_NODE_TXRATE_LEGACY:
118*fdc88416SAdrian Chadd 	case IEEE80211_NODE_TXRATE_HT:
119*fdc88416SAdrian Chadd 		ridx = rate2ridx(txr->dot11rate);
120*fdc88416SAdrian Chadd 		break;
121*fdc88416SAdrian Chadd 	case IEEE80211_NODE_TXRATE_VHT:
122*fdc88416SAdrian Chadd 		ridx = RTWN_RIDX_VHT_MCS(txr->nss - 1, txr->mcs);
123*fdc88416SAdrian Chadd 		break;
124*fdc88416SAdrian Chadd 	default:
125*fdc88416SAdrian Chadd 		if (ic->ic_curmode != IEEE80211_MODE_11B)
126*fdc88416SAdrian Chadd 			ridx = RTWN_RIDX_OFDM36;
127*fdc88416SAdrian Chadd 		else
128*fdc88416SAdrian Chadd 			ridx = RTWN_RIDX_CCK55;
129*fdc88416SAdrian Chadd 		break;
130*fdc88416SAdrian Chadd 	}
131*fdc88416SAdrian Chadd 
132*fdc88416SAdrian Chadd 	return (ridx);
133*fdc88416SAdrian Chadd }
134*fdc88416SAdrian Chadd 
1357453645fSAndriy Voskoboinyk static int
rtwn_tx_data(struct rtwn_softc * sc,struct ieee80211_node * ni,struct mbuf * m)1367453645fSAndriy Voskoboinyk rtwn_tx_data(struct rtwn_softc *sc, struct ieee80211_node *ni,
1377453645fSAndriy Voskoboinyk     struct mbuf *m)
1387453645fSAndriy Voskoboinyk {
139f6313575SAndriy Voskoboinyk 	const struct ieee80211_txparam *tp = ni->ni_txparms;
1407453645fSAndriy Voskoboinyk 	struct ieee80211com *ic = &sc->sc_ic;
1417453645fSAndriy Voskoboinyk 	struct ieee80211vap *vap = ni->ni_vap;
1427453645fSAndriy Voskoboinyk 	struct ieee80211_key *k = NULL;
1437453645fSAndriy Voskoboinyk 	struct ieee80211_frame *wh;
1447453645fSAndriy Voskoboinyk 	struct rtwn_tx_desc_common *txd;
1457453645fSAndriy Voskoboinyk 	struct rtwn_tx_buf buf;
146*fdc88416SAdrian Chadd 	uint8_t ridx, type;
14764ecfc27SAdrian Chadd 	bool force_rate = false;
1487453645fSAndriy Voskoboinyk 	u_int cipher;
149f6313575SAndriy Voskoboinyk 	int ismcast;
1507453645fSAndriy Voskoboinyk 
1517453645fSAndriy Voskoboinyk 	RTWN_ASSERT_LOCKED(sc);
1527453645fSAndriy Voskoboinyk 
1537453645fSAndriy Voskoboinyk 	wh = mtod(m, struct ieee80211_frame *);
1547453645fSAndriy Voskoboinyk 	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
1557453645fSAndriy Voskoboinyk 	ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
1567453645fSAndriy Voskoboinyk 
1577453645fSAndriy Voskoboinyk 	/* Choose a TX rate index. */
158f6313575SAndriy Voskoboinyk 	if (type == IEEE80211_FC0_TYPE_MGT ||
159f6313575SAndriy Voskoboinyk 	    type == IEEE80211_FC0_TYPE_CTL ||
16064ecfc27SAdrian Chadd 	    (m->m_flags & M_EAPOL) != 0) {
161*fdc88416SAdrian Chadd 		ridx = rate2ridx(tp->mgmtrate);
16264ecfc27SAdrian Chadd 		force_rate = true;
16364ecfc27SAdrian Chadd 	} else if (ismcast) {
164*fdc88416SAdrian Chadd 		ridx = rate2ridx(tp->mcastrate);
16564ecfc27SAdrian Chadd 		force_rate = true;
16664ecfc27SAdrian Chadd 	} else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) {
167*fdc88416SAdrian Chadd 		ridx = rate2ridx(tp->ucastrate);
16864ecfc27SAdrian Chadd 		force_rate = true;
16964ecfc27SAdrian Chadd 	} else {
1707453645fSAndriy Voskoboinyk 		if (sc->sc_ratectl == RTWN_RATECTL_NET80211) {
171*fdc88416SAdrian Chadd 			struct ieee80211_node_txrate txr = { 0 };
1727453645fSAndriy Voskoboinyk 			/* XXX pass pktlen */
173*fdc88416SAdrian Chadd 			ieee80211_ratectl_rate(ni, NULL, 0);
174*fdc88416SAdrian Chadd 			ieee80211_node_get_txrate(ni, &txr);
175*fdc88416SAdrian Chadd 			ridx = rtwn_tx_ratectl_to_ridx(sc, ni, &txr);
1767453645fSAndriy Voskoboinyk 		} else {
1777453645fSAndriy Voskoboinyk 			if (ni->ni_flags & IEEE80211_NODE_HT)
178*fdc88416SAdrian Chadd 				ridx = rate2ridx(IEEE80211_RATE_MCS | 0x4); /* MCS4 */
1797453645fSAndriy Voskoboinyk 			else if (ic->ic_curmode != IEEE80211_MODE_11B)
180*fdc88416SAdrian Chadd 				ridx = RTWN_RIDX_OFDM36;
1817453645fSAndriy Voskoboinyk 			else
182*fdc88416SAdrian Chadd 				ridx = RTWN_RIDX_CCK55;
1837453645fSAndriy Voskoboinyk 		}
1847453645fSAndriy Voskoboinyk 	}
1857453645fSAndriy Voskoboinyk 
1867453645fSAndriy Voskoboinyk 	cipher = IEEE80211_CIPHER_NONE;
1877453645fSAndriy Voskoboinyk 	if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
1887453645fSAndriy Voskoboinyk 		k = ieee80211_crypto_encap(ni, m);
1897453645fSAndriy Voskoboinyk 		if (k == NULL) {
1907453645fSAndriy Voskoboinyk 			device_printf(sc->sc_dev,
1917453645fSAndriy Voskoboinyk 			    "ieee80211_crypto_encap returns NULL.\n");
1927453645fSAndriy Voskoboinyk 			return (ENOBUFS);
1937453645fSAndriy Voskoboinyk 		}
1947453645fSAndriy Voskoboinyk 		if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT))
1957453645fSAndriy Voskoboinyk 			cipher = k->wk_cipher->ic_cipher;
1967453645fSAndriy Voskoboinyk 
1977453645fSAndriy Voskoboinyk 		/* in case packet header moved, reset pointer */
1987453645fSAndriy Voskoboinyk 		wh = mtod(m, struct ieee80211_frame *);
1997453645fSAndriy Voskoboinyk 	}
2007453645fSAndriy Voskoboinyk 
2017453645fSAndriy Voskoboinyk 	/* Fill Tx descriptor. */
2027453645fSAndriy Voskoboinyk 	txd = (struct rtwn_tx_desc_common *)&buf;
2037453645fSAndriy Voskoboinyk 	memset(txd, 0, sc->txdesc_len);
2047453645fSAndriy Voskoboinyk 	txd->txdw1 = htole32(SM(RTWN_TXDW1_CIPHER, rtwn_get_cipher(cipher)));
2057453645fSAndriy Voskoboinyk 
20664ecfc27SAdrian Chadd 	rtwn_fill_tx_desc(sc, ni, m, txd, ridx, force_rate, tp->maxretry);
2077453645fSAndriy Voskoboinyk 
2087453645fSAndriy Voskoboinyk 	if (ieee80211_radiotap_active_vap(vap)) {
2097453645fSAndriy Voskoboinyk 		struct rtwn_tx_radiotap_header *tap = &sc->sc_txtap;
2107453645fSAndriy Voskoboinyk 
2117453645fSAndriy Voskoboinyk 		tap->wt_flags = rtwn_tx_radiotap_flags(sc, txd);
2127453645fSAndriy Voskoboinyk 		if (k != NULL)
2137453645fSAndriy Voskoboinyk 			tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP;
2147453645fSAndriy Voskoboinyk 		ieee80211_radiotap_tx(vap, m);
2157453645fSAndriy Voskoboinyk 	}
2167453645fSAndriy Voskoboinyk 
2177453645fSAndriy Voskoboinyk 	return (rtwn_tx_start(sc, ni, m, (uint8_t *)txd, type, 0));
2187453645fSAndriy Voskoboinyk }
2197453645fSAndriy Voskoboinyk 
2207453645fSAndriy Voskoboinyk static int
rtwn_tx_raw(struct rtwn_softc * sc,struct ieee80211_node * ni,struct mbuf * m,const struct ieee80211_bpf_params * params)2217453645fSAndriy Voskoboinyk rtwn_tx_raw(struct rtwn_softc *sc, struct ieee80211_node *ni,
2227453645fSAndriy Voskoboinyk     struct mbuf *m, const struct ieee80211_bpf_params *params)
2237453645fSAndriy Voskoboinyk {
2247453645fSAndriy Voskoboinyk 	struct ieee80211vap *vap = ni->ni_vap;
2257453645fSAndriy Voskoboinyk 	struct ieee80211_key *k = NULL;
2267453645fSAndriy Voskoboinyk 	struct ieee80211_frame *wh;
2277453645fSAndriy Voskoboinyk 	struct rtwn_tx_desc_common *txd;
2287453645fSAndriy Voskoboinyk 	struct rtwn_tx_buf buf;
2297453645fSAndriy Voskoboinyk 	uint8_t type;
2307453645fSAndriy Voskoboinyk 	u_int cipher;
2317453645fSAndriy Voskoboinyk 
2327453645fSAndriy Voskoboinyk 	/* Encrypt the frame if need be. */
2337453645fSAndriy Voskoboinyk 	cipher = IEEE80211_CIPHER_NONE;
2347453645fSAndriy Voskoboinyk 	if (params->ibp_flags & IEEE80211_BPF_CRYPTO) {
2357453645fSAndriy Voskoboinyk 		/* Retrieve key for TX. */
2367453645fSAndriy Voskoboinyk 		k = ieee80211_crypto_encap(ni, m);
2377453645fSAndriy Voskoboinyk 		if (k == NULL) {
2387453645fSAndriy Voskoboinyk 			device_printf(sc->sc_dev,
2397453645fSAndriy Voskoboinyk 			    "ieee80211_crypto_encap returns NULL.\n");
2407453645fSAndriy Voskoboinyk 			return (ENOBUFS);
2417453645fSAndriy Voskoboinyk 		}
2427453645fSAndriy Voskoboinyk 		if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT))
2437453645fSAndriy Voskoboinyk 			cipher = k->wk_cipher->ic_cipher;
2447453645fSAndriy Voskoboinyk 	}
2457453645fSAndriy Voskoboinyk 
2467453645fSAndriy Voskoboinyk 	wh = mtod(m, struct ieee80211_frame *);
2477453645fSAndriy Voskoboinyk 	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
2487453645fSAndriy Voskoboinyk 
2497453645fSAndriy Voskoboinyk 	/* Fill Tx descriptor. */
2507453645fSAndriy Voskoboinyk 	txd = (struct rtwn_tx_desc_common *)&buf;
2517453645fSAndriy Voskoboinyk 	memset(txd, 0, sc->txdesc_len);
2527453645fSAndriy Voskoboinyk 	txd->txdw1 = htole32(SM(RTWN_TXDW1_CIPHER, rtwn_get_cipher(cipher)));
2537453645fSAndriy Voskoboinyk 
2547453645fSAndriy Voskoboinyk 	rtwn_fill_tx_desc_raw(sc, ni, m, txd, params);
2557453645fSAndriy Voskoboinyk 
2567453645fSAndriy Voskoboinyk 	if (ieee80211_radiotap_active_vap(vap)) {
2577453645fSAndriy Voskoboinyk 		struct rtwn_tx_radiotap_header *tap = &sc->sc_txtap;
2587453645fSAndriy Voskoboinyk 
2597453645fSAndriy Voskoboinyk 		tap->wt_flags = rtwn_tx_radiotap_flags(sc, txd);
2607453645fSAndriy Voskoboinyk 		if (k != NULL)
2617453645fSAndriy Voskoboinyk 			tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP;
2627453645fSAndriy Voskoboinyk 		ieee80211_radiotap_tx(vap, m);
2637453645fSAndriy Voskoboinyk 	}
2647453645fSAndriy Voskoboinyk 
2657453645fSAndriy Voskoboinyk 	return (rtwn_tx_start(sc, ni, m, (uint8_t *)txd, type, 0));
2667453645fSAndriy Voskoboinyk }
2677453645fSAndriy Voskoboinyk 
2687453645fSAndriy Voskoboinyk int
rtwn_transmit(struct ieee80211com * ic,struct mbuf * m)2697453645fSAndriy Voskoboinyk rtwn_transmit(struct ieee80211com *ic, struct mbuf *m)
2707453645fSAndriy Voskoboinyk {
2717453645fSAndriy Voskoboinyk 	struct rtwn_softc *sc = ic->ic_softc;
2727453645fSAndriy Voskoboinyk 	int error;
2737453645fSAndriy Voskoboinyk 
2747453645fSAndriy Voskoboinyk 	RTWN_LOCK(sc);
2757453645fSAndriy Voskoboinyk 	if ((sc->sc_flags & RTWN_RUNNING) == 0) {
2767453645fSAndriy Voskoboinyk 		RTWN_UNLOCK(sc);
2777453645fSAndriy Voskoboinyk 		return (ENXIO);
2787453645fSAndriy Voskoboinyk 	}
2797453645fSAndriy Voskoboinyk 	error = mbufq_enqueue(&sc->sc_snd, m);
2807453645fSAndriy Voskoboinyk 	if (error) {
2817453645fSAndriy Voskoboinyk 		RTWN_UNLOCK(sc);
2827453645fSAndriy Voskoboinyk 		return (error);
2837453645fSAndriy Voskoboinyk 	}
2847453645fSAndriy Voskoboinyk 	rtwn_start(sc);
2857453645fSAndriy Voskoboinyk 	RTWN_UNLOCK(sc);
2867453645fSAndriy Voskoboinyk 
2877453645fSAndriy Voskoboinyk 	return (0);
2887453645fSAndriy Voskoboinyk }
2897453645fSAndriy Voskoboinyk 
2907453645fSAndriy Voskoboinyk void
rtwn_start(struct rtwn_softc * sc)2917453645fSAndriy Voskoboinyk rtwn_start(struct rtwn_softc *sc)
2927453645fSAndriy Voskoboinyk {
2937453645fSAndriy Voskoboinyk 	struct ieee80211_node *ni;
2947453645fSAndriy Voskoboinyk 	struct mbuf *m;
2957453645fSAndriy Voskoboinyk 
2967453645fSAndriy Voskoboinyk 	RTWN_ASSERT_LOCKED(sc);
2978838f3c3SAdrian Chadd 
2988838f3c3SAdrian Chadd 	/* Ensure no work is scheduled during reset/teardown */
2998838f3c3SAdrian Chadd 	if ((sc->sc_flags & RTWN_RUNNING) == 0)
3008838f3c3SAdrian Chadd 		return;
3018838f3c3SAdrian Chadd 
3027453645fSAndriy Voskoboinyk 	while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
3037453645fSAndriy Voskoboinyk 		if (sc->qfullmsk != 0) {
3047453645fSAndriy Voskoboinyk 			mbufq_prepend(&sc->sc_snd, m);
3057453645fSAndriy Voskoboinyk 			break;
3067453645fSAndriy Voskoboinyk 		}
3077453645fSAndriy Voskoboinyk 		ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
3087453645fSAndriy Voskoboinyk 		m->m_pkthdr.rcvif = NULL;
3097453645fSAndriy Voskoboinyk 
3107453645fSAndriy Voskoboinyk 		RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT,
3117453645fSAndriy Voskoboinyk 		    "%s: called; m %p, ni %p\n", __func__, m, ni);
3127453645fSAndriy Voskoboinyk 
3137453645fSAndriy Voskoboinyk 		if (rtwn_tx_data(sc, ni, m) != 0) {
3147453645fSAndriy Voskoboinyk 			if_inc_counter(ni->ni_vap->iv_ifp,
3157453645fSAndriy Voskoboinyk 			    IFCOUNTER_OERRORS, 1);
3167453645fSAndriy Voskoboinyk 			m_freem(m);
3177453645fSAndriy Voskoboinyk #ifdef D4054
3187453645fSAndriy Voskoboinyk 			ieee80211_tx_watchdog_refresh(ni->ni_ic, -1, 0);
3197453645fSAndriy Voskoboinyk #endif
3207453645fSAndriy Voskoboinyk 			ieee80211_free_node(ni);
3217453645fSAndriy Voskoboinyk 			break;
3227453645fSAndriy Voskoboinyk 		}
3237453645fSAndriy Voskoboinyk 	}
3247453645fSAndriy Voskoboinyk }
3257453645fSAndriy Voskoboinyk 
3267453645fSAndriy Voskoboinyk int
rtwn_raw_xmit(struct ieee80211_node * ni,struct mbuf * m,const struct ieee80211_bpf_params * params)3277453645fSAndriy Voskoboinyk rtwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
3287453645fSAndriy Voskoboinyk     const struct ieee80211_bpf_params *params)
3297453645fSAndriy Voskoboinyk {
3307453645fSAndriy Voskoboinyk 	struct ieee80211com *ic = ni->ni_ic;
3317453645fSAndriy Voskoboinyk 	struct rtwn_softc *sc = ic->ic_softc;
3327453645fSAndriy Voskoboinyk 	int error;
3337453645fSAndriy Voskoboinyk 
3347453645fSAndriy Voskoboinyk 	RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, "%s: called; m %p, ni %p\n",
3357453645fSAndriy Voskoboinyk 	    __func__, m, ni);
3367453645fSAndriy Voskoboinyk 
3377453645fSAndriy Voskoboinyk 	/* prevent management frames from being sent if we're not ready */
3387453645fSAndriy Voskoboinyk 	RTWN_LOCK(sc);
3397453645fSAndriy Voskoboinyk 	if (!(sc->sc_flags & RTWN_RUNNING)) {
3407453645fSAndriy Voskoboinyk 		error = ENETDOWN;
3417453645fSAndriy Voskoboinyk 		goto end;
3427453645fSAndriy Voskoboinyk 	}
3437453645fSAndriy Voskoboinyk 
3447453645fSAndriy Voskoboinyk 	if (sc->qfullmsk != 0) {
3457453645fSAndriy Voskoboinyk 		error = ENOBUFS;
3467453645fSAndriy Voskoboinyk 		goto end;
3477453645fSAndriy Voskoboinyk 	}
3487453645fSAndriy Voskoboinyk 
3497453645fSAndriy Voskoboinyk 	if (params == NULL) {
3507453645fSAndriy Voskoboinyk 		/*
3517453645fSAndriy Voskoboinyk 		 * Legacy path; interpret frame contents to decide
3527453645fSAndriy Voskoboinyk 		 * precisely how to send the frame.
3537453645fSAndriy Voskoboinyk 		 */
3547453645fSAndriy Voskoboinyk 		error = rtwn_tx_data(sc, ni, m);
3557453645fSAndriy Voskoboinyk 	} else {
3567453645fSAndriy Voskoboinyk 		/*
3577453645fSAndriy Voskoboinyk 		 * Caller supplied explicit parameters to use in
3587453645fSAndriy Voskoboinyk 		 * sending the frame.
3597453645fSAndriy Voskoboinyk 		 */
3607453645fSAndriy Voskoboinyk 		error = rtwn_tx_raw(sc, ni, m, params);
3617453645fSAndriy Voskoboinyk 	}
3627453645fSAndriy Voskoboinyk 
3637453645fSAndriy Voskoboinyk end:
3647453645fSAndriy Voskoboinyk 	if (error != 0) {
3657453645fSAndriy Voskoboinyk 		if (m->m_flags & M_TXCB)
3667453645fSAndriy Voskoboinyk 			ieee80211_process_callback(ni, m, 1);
3677453645fSAndriy Voskoboinyk 		m_freem(m);
3687453645fSAndriy Voskoboinyk 	}
3697453645fSAndriy Voskoboinyk 
3707453645fSAndriy Voskoboinyk 	RTWN_UNLOCK(sc);
3717453645fSAndriy Voskoboinyk 
3727453645fSAndriy Voskoboinyk 	return (error);
3737453645fSAndriy Voskoboinyk }
374