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
57 void
rtwn_drain_mbufq(struct rtwn_softc * sc)58 rtwn_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
72 void
rtwn_ff_flush_all(struct rtwn_softc * sc,union sec_param * data)73 rtwn_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
83 static uint8_t
rtwn_get_cipher(u_int ic_cipher)84 rtwn_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
108 static uint8_t
rtwn_tx_ratectl_to_ridx(struct rtwn_softc * sc,struct ieee80211_node * ni,struct ieee80211_node_txrate * txr)109 rtwn_tx_ratectl_to_ridx(struct rtwn_softc *sc, struct ieee80211_node *ni,
110 struct ieee80211_node_txrate *txr)
111 {
112 /* TODO: this should be based on the node channel */
113 struct ieee80211com *ic = &sc->sc_ic;
114 uint8_t ridx;
115
116 switch (txr->type) {
117 case IEEE80211_NODE_TXRATE_LEGACY:
118 case IEEE80211_NODE_TXRATE_HT:
119 ridx = rate2ridx(txr->dot11rate);
120 break;
121 case IEEE80211_NODE_TXRATE_VHT:
122 ridx = RTWN_RIDX_VHT_MCS(txr->nss - 1, txr->mcs);
123 break;
124 default:
125 if (ic->ic_curmode != IEEE80211_MODE_11B)
126 ridx = RTWN_RIDX_OFDM36;
127 else
128 ridx = RTWN_RIDX_CCK55;
129 break;
130 }
131
132 return (ridx);
133 }
134
135 static int
rtwn_tx_data(struct rtwn_softc * sc,struct ieee80211_node * ni,struct mbuf * m)136 rtwn_tx_data(struct rtwn_softc *sc, struct ieee80211_node *ni,
137 struct mbuf *m)
138 {
139 const struct ieee80211_txparam *tp = ni->ni_txparms;
140 struct ieee80211com *ic = &sc->sc_ic;
141 struct ieee80211vap *vap = ni->ni_vap;
142 struct ieee80211_key *k = NULL;
143 struct ieee80211_frame *wh;
144 struct rtwn_tx_desc_common *txd;
145 struct rtwn_tx_buf buf;
146 uint8_t ridx, type;
147 bool force_rate = false;
148 u_int cipher;
149 int ismcast;
150
151 RTWN_ASSERT_LOCKED(sc);
152
153 wh = mtod(m, struct ieee80211_frame *);
154 type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
155 ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
156
157 /* Choose a TX rate index. */
158 if (type == IEEE80211_FC0_TYPE_MGT ||
159 type == IEEE80211_FC0_TYPE_CTL ||
160 (m->m_flags & M_EAPOL) != 0) {
161 ridx = rate2ridx(tp->mgmtrate);
162 force_rate = true;
163 } else if (ismcast) {
164 ridx = rate2ridx(tp->mcastrate);
165 force_rate = true;
166 } else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) {
167 ridx = rate2ridx(tp->ucastrate);
168 force_rate = true;
169 } else {
170 if (sc->sc_ratectl == RTWN_RATECTL_NET80211) {
171 struct ieee80211_node_txrate txr = { 0 };
172 /* XXX pass pktlen */
173 ieee80211_ratectl_rate(ni, NULL, 0);
174 ieee80211_node_get_txrate(ni, &txr);
175 ridx = rtwn_tx_ratectl_to_ridx(sc, ni, &txr);
176 } else {
177 if (ni->ni_flags & IEEE80211_NODE_HT)
178 ridx = rate2ridx(IEEE80211_RATE_MCS | 0x4); /* MCS4 */
179 else if (ic->ic_curmode != IEEE80211_MODE_11B)
180 ridx = RTWN_RIDX_OFDM36;
181 else
182 ridx = RTWN_RIDX_CCK55;
183 }
184 }
185
186 /* seqno allocate, only if AMPDU isn't running */
187 if ((m->m_flags & M_AMPDU_MPDU) == 0)
188 ieee80211_output_seqno_assign(ni, -1, m);
189
190 cipher = IEEE80211_CIPHER_NONE;
191 if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
192 k = ieee80211_crypto_encap(ni, m);
193 if (k == NULL) {
194 device_printf(sc->sc_dev,
195 "ieee80211_crypto_encap returns NULL.\n");
196 return (ENOBUFS);
197 }
198 if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT))
199 cipher = k->wk_cipher->ic_cipher;
200
201 /* in case packet header moved, reset pointer */
202 wh = mtod(m, struct ieee80211_frame *);
203 }
204
205 /* Fill Tx descriptor. */
206 txd = (struct rtwn_tx_desc_common *)&buf;
207 memset(txd, 0, sc->txdesc_len);
208 txd->txdw1 = htole32(SM(RTWN_TXDW1_CIPHER, rtwn_get_cipher(cipher)));
209
210 rtwn_fill_tx_desc(sc, ni, m, txd, ridx, force_rate, tp->maxretry);
211
212 if (ieee80211_radiotap_active_vap(vap)) {
213 struct rtwn_tx_radiotap_header *tap = &sc->sc_txtap;
214
215 tap->wt_flags = rtwn_tx_radiotap_flags(sc, txd);
216 if (k != NULL)
217 tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP;
218 ieee80211_radiotap_tx(vap, m);
219 }
220
221 return (rtwn_tx_start(sc, ni, m, (uint8_t *)txd, type, 0));
222 }
223
224 static int
rtwn_tx_raw(struct rtwn_softc * sc,struct ieee80211_node * ni,struct mbuf * m,const struct ieee80211_bpf_params * params)225 rtwn_tx_raw(struct rtwn_softc *sc, struct ieee80211_node *ni,
226 struct mbuf *m, const struct ieee80211_bpf_params *params)
227 {
228 struct ieee80211vap *vap = ni->ni_vap;
229 struct ieee80211_key *k = NULL;
230 struct ieee80211_frame *wh;
231 struct rtwn_tx_desc_common *txd;
232 struct rtwn_tx_buf buf;
233 uint8_t type;
234 u_int cipher;
235
236 /* seqno allocate, only if AMPDU isn't running */
237 if ((m->m_flags & M_AMPDU_MPDU) == 0)
238 ieee80211_output_seqno_assign(ni, -1, m);
239
240 /* Encrypt the frame if need be. */
241 cipher = IEEE80211_CIPHER_NONE;
242 if (params->ibp_flags & IEEE80211_BPF_CRYPTO) {
243 /* Retrieve key for TX. */
244 k = ieee80211_crypto_encap(ni, m);
245 if (k == NULL) {
246 device_printf(sc->sc_dev,
247 "ieee80211_crypto_encap returns NULL.\n");
248 return (ENOBUFS);
249 }
250 if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT))
251 cipher = k->wk_cipher->ic_cipher;
252 }
253
254 wh = mtod(m, struct ieee80211_frame *);
255 type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
256
257 /* Fill Tx descriptor. */
258 txd = (struct rtwn_tx_desc_common *)&buf;
259 memset(txd, 0, sc->txdesc_len);
260 txd->txdw1 = htole32(SM(RTWN_TXDW1_CIPHER, rtwn_get_cipher(cipher)));
261
262 rtwn_fill_tx_desc_raw(sc, ni, m, txd, params);
263
264 if (ieee80211_radiotap_active_vap(vap)) {
265 struct rtwn_tx_radiotap_header *tap = &sc->sc_txtap;
266
267 tap->wt_flags = rtwn_tx_radiotap_flags(sc, txd);
268 if (k != NULL)
269 tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP;
270 ieee80211_radiotap_tx(vap, m);
271 }
272
273 return (rtwn_tx_start(sc, ni, m, (uint8_t *)txd, type, 0));
274 }
275
276 int
rtwn_transmit(struct ieee80211com * ic,struct mbuf * m)277 rtwn_transmit(struct ieee80211com *ic, struct mbuf *m)
278 {
279 struct rtwn_softc *sc = ic->ic_softc;
280 int error;
281
282 RTWN_LOCK(sc);
283 if ((sc->sc_flags & RTWN_RUNNING) == 0) {
284 RTWN_UNLOCK(sc);
285 return (ENXIO);
286 }
287 error = mbufq_enqueue(&sc->sc_snd, m);
288 if (error) {
289 RTWN_UNLOCK(sc);
290 return (error);
291 }
292 rtwn_start(sc);
293 RTWN_UNLOCK(sc);
294
295 return (0);
296 }
297
298 void
rtwn_start(struct rtwn_softc * sc)299 rtwn_start(struct rtwn_softc *sc)
300 {
301 struct ieee80211_node *ni;
302 struct mbuf *m;
303
304 RTWN_ASSERT_LOCKED(sc);
305
306 /* Ensure no work is scheduled during reset/teardown */
307 if ((sc->sc_flags & RTWN_RUNNING) == 0)
308 return;
309
310 while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
311 if (sc->qfullmsk != 0) {
312 mbufq_prepend(&sc->sc_snd, m);
313 break;
314 }
315 ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
316 m->m_pkthdr.rcvif = NULL;
317
318 RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT,
319 "%s: called; m %p, ni %p\n", __func__, m, ni);
320
321 if (rtwn_tx_data(sc, ni, m) != 0) {
322 if_inc_counter(ni->ni_vap->iv_ifp,
323 IFCOUNTER_OERRORS, 1);
324 m_freem(m);
325 #ifdef D4054
326 ieee80211_tx_watchdog_refresh(ni->ni_ic, -1, 0);
327 #endif
328 ieee80211_free_node(ni);
329 break;
330 }
331 }
332 }
333
334 int
rtwn_raw_xmit(struct ieee80211_node * ni,struct mbuf * m,const struct ieee80211_bpf_params * params)335 rtwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
336 const struct ieee80211_bpf_params *params)
337 {
338 struct ieee80211com *ic = ni->ni_ic;
339 struct rtwn_softc *sc = ic->ic_softc;
340 int error;
341
342 RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, "%s: called; m %p, ni %p\n",
343 __func__, m, ni);
344
345 /* prevent management frames from being sent if we're not ready */
346 RTWN_LOCK(sc);
347 if (!(sc->sc_flags & RTWN_RUNNING)) {
348 error = ENETDOWN;
349 goto end;
350 }
351
352 if (sc->qfullmsk != 0) {
353 error = ENOBUFS;
354 goto end;
355 }
356
357 if (params == NULL) {
358 /*
359 * Legacy path; interpret frame contents to decide
360 * precisely how to send the frame.
361 */
362 error = rtwn_tx_data(sc, ni, m);
363 } else {
364 /*
365 * Caller supplied explicit parameters to use in
366 * sending the frame.
367 */
368 error = rtwn_tx_raw(sc, ni, m, params);
369 }
370
371 end:
372 if (error != 0) {
373 if (m->m_flags & M_TXCB)
374 ieee80211_process_callback(ni, m, 1);
375 m_freem(m);
376 }
377
378 RTWN_UNLOCK(sc);
379
380 return (error);
381 }
382