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