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_dl.h>
41 #include <net/if_media.h>
42
43 #include <net80211/ieee80211_var.h>
44 #include <net80211/ieee80211_radiotap.h>
45 #ifdef IEEE80211_SUPPORT_SUPERG
46 #include <net80211/ieee80211_superg.h>
47 #endif
48
49 #include <dev/usb/usb.h>
50 #include <dev/usb/usbdi.h>
51
52 #include <dev/rtwn/if_rtwnreg.h>
53 #include <dev/rtwn/if_rtwnvar.h>
54
55 #include <dev/rtwn/if_rtwn_debug.h>
56 #include <dev/rtwn/if_rtwn_ridx.h>
57 #include <dev/rtwn/if_rtwn_rx.h>
58 #include <dev/rtwn/if_rtwn_task.h>
59 #include <dev/rtwn/if_rtwn_tx.h>
60
61 #include <dev/rtwn/usb/rtwn_usb_var.h>
62 #include <dev/rtwn/usb/rtwn_usb_rx.h>
63
64 static struct mbuf * rtwn_rxeof(struct rtwn_softc *, struct rtwn_data *,
65 uint8_t *, int);
66
67 static int
rtwn_rx_check_pre_alloc(struct rtwn_softc * sc,struct rtwn_rx_stat_common * stat)68 rtwn_rx_check_pre_alloc(struct rtwn_softc *sc,
69 struct rtwn_rx_stat_common *stat)
70 {
71 uint32_t rxdw0;
72 int pktlen;
73
74 RTWN_ASSERT_LOCKED(sc);
75
76 /*
77 * don't pass packets to the ieee80211 framework if the driver isn't
78 * RUNNING.
79 */
80 if (!(sc->sc_flags & RTWN_RUNNING))
81 return (-1);
82
83 rxdw0 = le32toh(stat->rxdw0);
84 if (__predict_false(rxdw0 & (RTWN_RXDW0_CRCERR | RTWN_RXDW0_ICVERR))) {
85 /*
86 * This should not happen since we setup our Rx filter
87 * to not receive these frames.
88 */
89 RTWN_DPRINTF(sc, RTWN_DEBUG_RECV,
90 "%s: RX flags error (%s)\n", __func__,
91 rxdw0 & RTWN_RXDW0_CRCERR ? "CRC" : "ICV");
92 return (-1);
93 }
94
95 pktlen = MS(rxdw0, RTWN_RXDW0_PKTLEN);
96 if (__predict_false(pktlen < sizeof(struct ieee80211_frame_ack))) {
97 /*
98 * Should not happen (because of Rx filter setup).
99 */
100 RTWN_DPRINTF(sc, RTWN_DEBUG_RECV,
101 "%s: frame is too short: %d\n", __func__, pktlen);
102 return (-1);
103 }
104
105 return (0);
106 }
107
108 static struct mbuf *
rtwn_rx_copy_to_mbuf(struct rtwn_softc * sc,struct rtwn_rx_stat_common * stat,int totlen)109 rtwn_rx_copy_to_mbuf(struct rtwn_softc *sc, struct rtwn_rx_stat_common *stat,
110 int totlen)
111 {
112 struct ieee80211com *ic = &sc->sc_ic;
113 struct mbuf *m;
114
115 RTWN_ASSERT_LOCKED(sc);
116
117 /* Dump Rx descriptor. */
118 RTWN_DPRINTF(sc, RTWN_DEBUG_RECV_DESC,
119 "%s: dw: 0 %08X, 1 %08X, 2 %08X, 3 %08X, 4 %08X, tsfl %08X\n",
120 __func__, le32toh(stat->rxdw0), le32toh(stat->rxdw1),
121 le32toh(stat->rxdw2), le32toh(stat->rxdw3), le32toh(stat->rxdw4),
122 le32toh(stat->tsf_low));
123
124 if (rtwn_rx_check_pre_alloc(sc, stat) != 0)
125 goto fail;
126
127 /*
128 * Note: this can require >4 KiB (eg de-aggregating an A-MSDU
129 * from an USB frame. See kern/286366 for more information.
130 */
131 m = m_get3(totlen, M_NOWAIT, MT_DATA, M_PKTHDR);
132 if (__predict_false(m == NULL)) {
133 device_printf(sc->sc_dev,
134 "%s: could not allocate RX mbuf (%d bytes)\n",
135 __func__, totlen);
136 goto fail;
137 }
138
139 /* Finalize mbuf. */
140 memcpy(mtod(m, uint8_t *), (uint8_t *)stat, totlen);
141 m->m_pkthdr.len = m->m_len = totlen;
142
143 if (rtwn_check_frame(sc, m) != 0) {
144 m_freem(m);
145 goto fail;
146 }
147
148 return (m);
149 fail:
150 counter_u64_add(ic->ic_ierrors, 1);
151 return (NULL);
152 }
153
154 static struct mbuf *
rtwn_rxeof_fragmented(struct rtwn_usb_softc * uc,struct rtwn_data * data,uint8_t * buf,int len)155 rtwn_rxeof_fragmented(struct rtwn_usb_softc *uc, struct rtwn_data *data,
156 uint8_t *buf, int len)
157 {
158 struct rtwn_softc *sc = &uc->uc_sc;
159 struct ieee80211com *ic = &sc->sc_ic;
160 struct rtwn_rx_stat_common *stat = &uc->uc_rx_stat;
161 uint32_t rxdw0;
162 int totlen, pktlen, infosz, min_len;
163 int orig_len = len;
164 int alloc_mbuf = 0;
165
166 /* Check if Rx descriptor is not truncated. */
167 if (uc->uc_rx_stat_len < sizeof(*stat)) {
168 min_len = min(sizeof(*stat) - uc->uc_rx_stat_len, len);
169 memcpy((uint8_t *)stat + uc->uc_rx_stat_len, buf, min_len);
170
171 uc->uc_rx_stat_len += min_len;
172 buf += min_len;
173 len -= min_len;
174
175 if (uc->uc_rx_stat_len < sizeof(*stat))
176 goto end;
177
178 KASSERT(data->m == NULL, ("%s: data->m != NULL!\n", __func__));
179 alloc_mbuf = 1;
180
181 /* Dump Rx descriptor. */
182 RTWN_DPRINTF(sc, RTWN_DEBUG_RECV_DESC,
183 "%s: dw: 0 %08X, 1 %08X, 2 %08X, 3 %08X, 4 %08X, "
184 "tsfl %08X\n", __func__, le32toh(stat->rxdw0),
185 le32toh(stat->rxdw1), le32toh(stat->rxdw2),
186 le32toh(stat->rxdw3), le32toh(stat->rxdw4),
187 le32toh(stat->tsf_low));
188 }
189
190 rxdw0 = le32toh(stat->rxdw0);
191 pktlen = MS(rxdw0, RTWN_RXDW0_PKTLEN);
192 infosz = MS(rxdw0, RTWN_RXDW0_INFOSZ) * 8;
193 totlen = sizeof(*stat) + infosz + pktlen;
194 if (alloc_mbuf) {
195 if (rtwn_rx_check_pre_alloc(sc, stat) == 0) {
196 data->m = m_getm(NULL, totlen, M_NOWAIT, MT_DATA);
197 if (data->m != NULL) {
198 m_copyback(data->m, 0, uc->uc_rx_stat_len,
199 (caddr_t)stat);
200
201 if (rtwn_check_frame(sc, data->m) != 0) {
202 m_freem(data->m);
203 data->m = NULL;
204 counter_u64_add(ic->ic_ierrors, 1);
205 }
206 } else
207 counter_u64_add(ic->ic_ierrors, 1);
208 } else
209 counter_u64_add(ic->ic_ierrors, 1);
210
211 uc->uc_rx_off = sizeof(*stat);
212 }
213
214 /* If mbuf allocation fails just discard the data. */
215 min_len = min(totlen - uc->uc_rx_off, len);
216 if (data->m != NULL)
217 m_copyback(data->m, uc->uc_rx_off, min_len, buf);
218
219 uc->uc_rx_off += min_len;
220 if (uc->uc_rx_off == totlen) {
221 /* Align next frame. */
222 min_len = rtwn_usb_align_rx(uc,
223 orig_len - len + min_len, orig_len);
224 min_len -= (orig_len - len);
225 KASSERT(len >= min_len, ("%s: len (%d) < min_len (%d)!\n",
226 __func__, len, min_len));
227
228 /* Clear mbuf stats. */
229 uc->uc_rx_stat_len = 0;
230 uc->uc_rx_off = 0;
231 }
232 len -= min_len;
233 buf += min_len;
234 end:
235 if (uc->uc_rx_stat_len == 0)
236 return (rtwn_rxeof(sc, data, buf, len));
237 else
238 return (NULL);
239 }
240
241 static struct mbuf *
rtwn_rxeof(struct rtwn_softc * sc,struct rtwn_data * data,uint8_t * buf,int len)242 rtwn_rxeof(struct rtwn_softc *sc, struct rtwn_data *data, uint8_t *buf,
243 int len)
244 {
245 struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
246 struct rtwn_rx_stat_common *stat;
247 struct mbuf *m, *m0 = NULL;
248 uint32_t rxdw0;
249 int totlen, pktlen, infosz;
250
251 /* Prepend defragmented frame (if any). */
252 if (data->m != NULL) {
253 m0 = m = data->m;
254 data->m = NULL;
255 }
256
257 /* Process packets. */
258 while (len >= sizeof(*stat)) {
259 stat = (struct rtwn_rx_stat_common *)buf;
260 rxdw0 = le32toh(stat->rxdw0);
261
262 pktlen = MS(rxdw0, RTWN_RXDW0_PKTLEN);
263 if (__predict_false(pktlen == 0))
264 break;
265
266 infosz = MS(rxdw0, RTWN_RXDW0_INFOSZ) * 8;
267
268 /* Make sure everything fits in xfer. */
269 totlen = sizeof(*stat) + infosz + pktlen;
270 if (totlen > len) {
271 RTWN_DPRINTF(sc, RTWN_DEBUG_RECV,
272 "%s: frame is fragmented (totlen %d len %d)\n",
273 __func__, totlen, len);
274 break;
275 }
276
277 if (m0 == NULL)
278 m0 = m = rtwn_rx_copy_to_mbuf(sc, stat, totlen);
279 else {
280 m->m_nextpkt = rtwn_rx_copy_to_mbuf(sc, stat, totlen);
281 if (m->m_nextpkt != NULL)
282 m = m->m_nextpkt;
283 }
284
285 /* Align next frame. */
286 totlen = rtwn_usb_align_rx(uc, totlen, len);
287 buf += totlen;
288 len -= totlen;
289 }
290
291 if (len > 0)
292 (void)rtwn_rxeof_fragmented(uc, data, buf, len);
293
294 return (m0);
295 }
296
297 static struct mbuf *
rtwn_report_intr(struct rtwn_usb_softc * uc,struct usb_xfer * xfer,struct rtwn_data * data)298 rtwn_report_intr(struct rtwn_usb_softc *uc, struct usb_xfer *xfer,
299 struct rtwn_data *data)
300 {
301 struct rtwn_softc *sc = &uc->uc_sc;
302 struct ieee80211com *ic = &sc->sc_ic;
303 uint8_t *buf;
304 int len;
305
306 usbd_xfer_status(xfer, &len, NULL, NULL, NULL);
307
308 if (__predict_false(len < sizeof(struct rtwn_rx_stat_common) &&
309 uc->uc_rx_stat_len == 0)) {
310 counter_u64_add(ic->ic_ierrors, 1);
311 return (NULL);
312 }
313
314 buf = data->buf;
315 if (uc->uc_rx_stat_len > 0)
316 return (rtwn_rxeof_fragmented(uc, data, data->buf, len));
317
318 switch (rtwn_classify_intr(sc, buf, len)) {
319 case RTWN_RX_DATA:
320 return (rtwn_rxeof(sc, data, buf, len));
321 case RTWN_RX_TX_REPORT:
322 if (sc->sc_ratectl != RTWN_RATECTL_NET80211) {
323 /* shouldn't happen */
324 device_printf(sc->sc_dev,
325 "%s called while ratectl = %d!\n",
326 __func__, sc->sc_ratectl);
327 break;
328 }
329
330 RTWN_NT_LOCK(sc);
331 rtwn_handle_tx_report(sc, buf, len);
332 RTWN_NT_UNLOCK(sc);
333
334 #ifdef IEEE80211_SUPPORT_SUPERG
335 /*
336 * NB: this will executed only when 'report' bit is set.
337 */
338 if (sc->sc_tx_n_active > 0 && --sc->sc_tx_n_active <= 1)
339 rtwn_cmd_sleepable(sc, NULL, 0, rtwn_ff_flush_all);
340 #endif
341 break;
342 case RTWN_RX_TX_REPORT2:
343 if (sc->sc_ratectl != RTWN_RATECTL_NET80211) {
344 /* shouldn't happen */
345 device_printf(sc->sc_dev,
346 "%s called while ratectl = %d!\n",
347 __func__, sc->sc_ratectl);
348 break;
349 }
350
351 RTWN_NT_LOCK(sc);
352 rtwn_handle_tx_report2(sc, buf, len);
353 RTWN_NT_UNLOCK(sc);
354
355 #ifdef IEEE80211_SUPPORT_SUPERG
356 /*
357 * NB: this will executed only when 'report' bit is set.
358 */
359 if (sc->sc_tx_n_active > 0 && --sc->sc_tx_n_active <= 1)
360 rtwn_cmd_sleepable(sc, NULL, 0, rtwn_ff_flush_all);
361 #endif
362 break;
363 case RTWN_RX_OTHER:
364 rtwn_handle_c2h_report(sc, buf, len);
365 break;
366 default:
367 /* NOTREACHED */
368 KASSERT(0, ("unknown Rx classification code"));
369 break;
370 }
371
372 return (NULL);
373 }
374
375 static struct ieee80211_node *
rtwn_rx_frame(struct rtwn_softc * sc,struct mbuf * m)376 rtwn_rx_frame(struct rtwn_softc *sc, struct mbuf *m)
377 {
378 struct rtwn_rx_stat_common stat;
379
380 /* Imitate PCIe layout. */
381 m_copydata(m, 0, sizeof(stat), (caddr_t)&stat);
382 m_adj(m, sizeof(stat));
383
384 return (rtwn_rx_common(sc, m, &stat));
385 }
386
387 void
rtwn_bulk_rx_callback(struct usb_xfer * xfer,usb_error_t error)388 rtwn_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error)
389 {
390 struct rtwn_usb_softc *uc = usbd_xfer_softc(xfer);
391 struct rtwn_softc *sc = &uc->uc_sc;
392 struct ieee80211com *ic = &sc->sc_ic;
393 struct ieee80211_node *ni;
394 struct mbuf *m0, *m = NULL, *next;
395 struct rtwn_data *data;
396
397 RTWN_ASSERT_LOCKED(sc);
398
399 switch (USB_GET_STATE(xfer)) {
400 case USB_ST_TRANSFERRED:
401 data = STAILQ_FIRST(&uc->uc_rx_active);
402 if (data == NULL)
403 goto tr_setup;
404 STAILQ_REMOVE_HEAD(&uc->uc_rx_active, next);
405 m = rtwn_report_intr(uc, xfer, data);
406 STAILQ_INSERT_TAIL(&uc->uc_rx_inactive, data, next);
407 /* FALLTHROUGH */
408 case USB_ST_SETUP:
409 tr_setup:
410 data = STAILQ_FIRST(&uc->uc_rx_inactive);
411 if (data == NULL) {
412 KASSERT(m == NULL, ("mbuf isn't NULL"));
413 goto finish;
414 }
415 STAILQ_REMOVE_HEAD(&uc->uc_rx_inactive, next);
416 STAILQ_INSERT_TAIL(&uc->uc_rx_active, data, next);
417 usbd_xfer_set_frame_data(xfer, 0, data->buf,
418 usbd_xfer_max_len(xfer));
419 usbd_transfer_submit(xfer);
420
421 /*
422 * To avoid LOR we should unlock our private mutex here to call
423 * ieee80211_input() because here is at the end of a USB
424 * callback and safe to unlock.
425 */
426 m0 = m;
427 while (m != NULL) {
428 M_ASSERTPKTHDR(m);
429 m->m_pkthdr.PH_loc.ptr = rtwn_rx_frame(sc, m);
430 m = m->m_nextpkt;
431 }
432 RTWN_UNLOCK(sc);
433 m = m0;
434 while (m != NULL) {
435 next = m->m_nextpkt;
436 m->m_nextpkt = NULL;
437
438 ni = m->m_pkthdr.PH_loc.ptr;
439 m->m_pkthdr.PH_loc.ptr = NULL;
440 if (ni != NULL) {
441 (void)ieee80211_input_mimo(ni, m);
442 ieee80211_free_node(ni);
443 } else {
444 (void)ieee80211_input_mimo_all(ic, m);
445 }
446 m = next;
447 }
448 RTWN_LOCK(sc);
449 break;
450 default:
451 /* needs it to the inactive queue due to a error. */
452 data = STAILQ_FIRST(&uc->uc_rx_active);
453 if (data != NULL) {
454 STAILQ_REMOVE_HEAD(&uc->uc_rx_active, next);
455 STAILQ_INSERT_TAIL(&uc->uc_rx_inactive, data, next);
456 }
457 if (error != USB_ERR_CANCELLED) {
458 /* XXX restart device if frame was fragmented? */
459
460 usbd_xfer_set_stall(xfer);
461 counter_u64_add(ic->ic_ierrors, 1);
462 goto tr_setup;
463 }
464 break;
465 }
466 finish:
467 /* Kick-start more transmit in case we stalled */
468 rtwn_start(sc);
469 }
470