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