1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (C) 2012 Ben Gray <[email protected]>.
5 * Copyright (C) 2018 The FreeBSD Foundation.
6 * Copyright (c) 2019 Edward Tomasz Napierala <[email protected]>
7 *
8 * This software was developed by Arshan Khanifar <[email protected]>
9 * under sponsorship from the FreeBSD Foundation.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 /*
34 * Universal Serial Bus Communications Class Subclass Specification
35 * for Ethernet Emulation Model Devices:
36 *
37 * https://usb.org/sites/default/files/CDC_EEM10.pdf
38 */
39
40 #include <sys/cdefs.h>
41 __FBSDID("$FreeBSD$");
42
43 #include <sys/gsb_crc32.h>
44 #include <sys/eventhandler.h>
45 #include <sys/stdint.h>
46 #include <sys/stddef.h>
47 #include <sys/queue.h>
48 #include <sys/systm.h>
49 #include <sys/socket.h>
50 #include <sys/kernel.h>
51 #include <sys/bus.h>
52 #include <sys/module.h>
53 #include <sys/lock.h>
54 #include <sys/mutex.h>
55 #include <sys/condvar.h>
56 #include <sys/sysctl.h>
57 #include <sys/sx.h>
58 #include <sys/unistd.h>
59 #include <sys/callout.h>
60 #include <sys/malloc.h>
61 #include <sys/priv.h>
62
63 #include <net/if.h>
64 #include <net/if_var.h>
65
66 #include <dev/usb/usb.h>
67 #include <dev/usb/usbdi.h>
68 #include <dev/usb/usbdi_util.h>
69 #include <dev/usb/usb_cdc.h>
70 #include "usbdevs.h"
71
72 #define USB_DEBUG_VAR cdceem_debug
73 #include <dev/usb/usb_debug.h>
74 #include <dev/usb/usb_process.h>
75 #include <dev/usb/usb_msctest.h>
76 #include "usb_if.h"
77
78 #include <dev/usb/net/usb_ethernet.h>
79
80 #define CDCEEM_FRAMES_MAX 1
81 #define CDCEEM_ECHO_MAX 1024
82
83 #define CDCEEM_ECHO_PAYLOAD \
84 "ICH DALEKOPIS FALSZUJE GDY PROBY XQV NIE WYTRZYMUJE 1234567890"
85
86 enum {
87 CDCEEM_BULK_RX,
88 CDCEEM_BULK_TX,
89 CDCEEM_N_TRANSFER,
90 };
91
92 struct cdceem_softc {
93 struct usb_ether sc_ue;
94 struct mtx sc_mtx;
95 int sc_flags;
96 struct usb_xfer *sc_xfer[CDCEEM_N_TRANSFER];
97 size_t sc_echo_len;
98 char sc_echo_buffer[CDCEEM_ECHO_MAX];
99 };
100
101 #define CDCEEM_SC_FLAGS_ECHO_RESPONSE_PENDING 0x1
102 #define CDCEEM_SC_FLAGS_ECHO_PENDING 0x2
103
104 static SYSCTL_NODE(_hw_usb, OID_AUTO, cdceem, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
105 "USB CDC EEM");
106 static int cdceem_debug = 1;
107 SYSCTL_INT(_hw_usb_cdceem, OID_AUTO, debug, CTLFLAG_RWTUN,
108 &cdceem_debug, 0, "Debug level");
109 static int cdceem_send_echoes = 0;
110 SYSCTL_INT(_hw_usb_cdceem, OID_AUTO, send_echoes, CTLFLAG_RWTUN,
111 &cdceem_send_echoes, 0, "Send an Echo command");
112 static int cdceem_send_fake_crc = 0;
113 SYSCTL_INT(_hw_usb_cdceem, OID_AUTO, send_fake_crc, CTLFLAG_RWTUN,
114 &cdceem_send_fake_crc, 0, "Use 0xdeadbeef instead of CRC");
115
116 #define CDCEEM_DEBUG(S, X, ...) \
117 do { \
118 if (cdceem_debug > 1) { \
119 device_printf(S->sc_ue.ue_dev, "%s: " X "\n", \
120 __func__, ## __VA_ARGS__); \
121 } \
122 } while (0)
123
124 #define CDCEEM_WARN(S, X, ...) \
125 do { \
126 if (cdceem_debug > 0) { \
127 device_printf(S->sc_ue.ue_dev, \
128 "WARNING: %s: " X "\n", \
129 __func__, ## __VA_ARGS__); \
130 } \
131 } while (0)
132
133 #define CDCEEM_LOCK(X) mtx_lock(&(X)->sc_mtx)
134 #define CDCEEM_UNLOCK(X) mtx_unlock(&(X)->sc_mtx)
135
136 #define CDCEEM_TYPE_CMD (0x1 << 15)
137
138 #define CDCEEM_CMD_MASK (0x7 << 11)
139
140 #define CDCEEM_CMD_ECHO (0x0 << 11)
141 #define CDCEEM_CMD_ECHO_RESPONSE (0x1 << 11)
142 #define CDCEEM_CMD_SUSPEND_HINT (0x2 << 11)
143 #define CDCEEM_CMD_RESPONSE_HINT (0x3 << 11)
144 #define CDCEEM_CMD_RESPONSE_COMPLETE_HINT (0x4 << 11)
145 #define CDCEEM_CMD_TICKLE (0x5 << 11)
146
147 #define CDCEEM_CMD_RESERVED (0x1 << 14)
148
149 #define CDCEEM_ECHO_LEN_MASK 0x3ff
150
151 #define CDCEEM_DATA_CRC (0x1 << 14)
152 #define CDCEEM_DATA_LEN_MASK 0x3fff
153
154 static device_probe_t cdceem_probe;
155 static device_attach_t cdceem_attach;
156 static device_detach_t cdceem_detach;
157 static device_suspend_t cdceem_suspend;
158 static device_resume_t cdceem_resume;
159
160 static usb_callback_t cdceem_bulk_write_callback;
161 static usb_callback_t cdceem_bulk_read_callback;
162
163 static uether_fn_t cdceem_attach_post;
164 static uether_fn_t cdceem_init;
165 static uether_fn_t cdceem_stop;
166 static uether_fn_t cdceem_start;
167 static uether_fn_t cdceem_setmulti;
168 static uether_fn_t cdceem_setpromisc;
169
170 static uint32_t cdceem_m_crc32(struct mbuf *, uint32_t, uint32_t);
171
172 static const struct usb_config cdceem_config[CDCEEM_N_TRANSFER] = {
173 [CDCEEM_BULK_TX] = {
174 .type = UE_BULK,
175 .endpoint = UE_ADDR_ANY,
176 .direction = UE_DIR_TX,
177 .bufsize = 16 * (MCLBYTES + 16),
178 .flags = {.pipe_bof = 1,.force_short_xfer = 1,},
179 .callback = cdceem_bulk_write_callback,
180 .timeout = 10000, /* 10 seconds */
181 .usb_mode = USB_MODE_DUAL,
182 },
183
184 [CDCEEM_BULK_RX] = {
185 .type = UE_BULK,
186 .endpoint = UE_ADDR_ANY,
187 .direction = UE_DIR_RX,
188 .bufsize = 20480, /* bytes */
189 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
190 .callback = cdceem_bulk_read_callback,
191 .timeout = 0, /* no timeout */
192 .usb_mode = USB_MODE_DUAL,
193 },
194 };
195
196 static device_method_t cdceem_methods[] = {
197 /* Device interface */
198 DEVMETHOD(device_probe, cdceem_probe),
199 DEVMETHOD(device_attach, cdceem_attach),
200 DEVMETHOD(device_detach, cdceem_detach),
201 DEVMETHOD(device_suspend, cdceem_suspend),
202 DEVMETHOD(device_resume, cdceem_resume),
203
204 DEVMETHOD_END
205 };
206
207 static driver_t cdceem_driver = {
208 .name = "cdceem",
209 .methods = cdceem_methods,
210 .size = sizeof(struct cdceem_softc),
211 };
212
213 static devclass_t cdceem_devclass;
214
215 static const STRUCT_USB_DUAL_ID cdceem_dual_devs[] = {
216 {USB_IFACE_CLASS(UICLASS_CDC),
217 USB_IFACE_SUBCLASS(UISUBCLASS_ETHERNET_EMULATION_MODEL),
218 0},
219 };
220
221 DRIVER_MODULE(cdceem, uhub, cdceem_driver, cdceem_devclass, NULL, NULL);
222 MODULE_VERSION(cdceem, 1);
223 MODULE_DEPEND(cdceem, uether, 1, 1, 1);
224 MODULE_DEPEND(cdceem, usb, 1, 1, 1);
225 MODULE_DEPEND(cdceem, ether, 1, 1, 1);
226 USB_PNP_DUAL_INFO(cdceem_dual_devs);
227
228 static const struct usb_ether_methods cdceem_ue_methods = {
229 .ue_attach_post = cdceem_attach_post,
230 .ue_start = cdceem_start,
231 .ue_init = cdceem_init,
232 .ue_stop = cdceem_stop,
233 .ue_setmulti = cdceem_setmulti,
234 .ue_setpromisc = cdceem_setpromisc,
235 };
236
237 static int
cdceem_probe(device_t dev)238 cdceem_probe(device_t dev)
239 {
240 struct usb_attach_arg *uaa;
241 int error;
242
243 uaa = device_get_ivars(dev);
244 error = usbd_lookup_id_by_uaa(cdceem_dual_devs,
245 sizeof(cdceem_dual_devs), uaa);
246
247 return (error);
248 }
249
250 static void
cdceem_attach_post(struct usb_ether * ue)251 cdceem_attach_post(struct usb_ether *ue)
252 {
253
254 return;
255 }
256
257 static int
cdceem_attach(device_t dev)258 cdceem_attach(device_t dev)
259 {
260 struct cdceem_softc *sc;
261 struct usb_ether *ue;
262 struct usb_attach_arg *uaa;
263 int error;
264 uint8_t iface_index;
265
266 sc = device_get_softc(dev);
267 ue = &sc->sc_ue;
268 uaa = device_get_ivars(dev);
269
270 device_set_usb_desc(dev);
271
272 mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
273
274 /* Setup the endpoints. */
275 iface_index = 0;
276 error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_xfer,
277 cdceem_config, CDCEEM_N_TRANSFER, sc, &sc->sc_mtx);
278 if (error != 0) {
279 CDCEEM_WARN(sc,
280 "allocating USB transfers failed, error %d", error);
281 mtx_destroy(&sc->sc_mtx);
282 return (error);
283 }
284
285 /* Random MAC address. */
286 arc4rand(ue->ue_eaddr, ETHER_ADDR_LEN, 0);
287 ue->ue_eaddr[0] &= ~0x01; /* unicast */
288 ue->ue_eaddr[0] |= 0x02; /* locally administered */
289
290 ue->ue_sc = sc;
291 ue->ue_dev = dev;
292 ue->ue_udev = uaa->device;
293 ue->ue_mtx = &sc->sc_mtx;
294 ue->ue_methods = &cdceem_ue_methods;
295
296 error = uether_ifattach(ue);
297 if (error != 0) {
298 CDCEEM_WARN(sc, "could not attach interface, error %d", error);
299 usbd_transfer_unsetup(sc->sc_xfer, CDCEEM_N_TRANSFER);
300 mtx_destroy(&sc->sc_mtx);
301 return (error);
302 }
303
304 return (0);
305 }
306
307 static int
cdceem_detach(device_t dev)308 cdceem_detach(device_t dev)
309 {
310 struct cdceem_softc *sc = device_get_softc(dev);
311 struct usb_ether *ue = &sc->sc_ue;
312
313 /* Stop all USB transfers first. */
314 usbd_transfer_unsetup(sc->sc_xfer, CDCEEM_N_TRANSFER);
315 uether_ifdetach(ue);
316 mtx_destroy(&sc->sc_mtx);
317
318 return (0);
319 }
320
321 static void
cdceem_handle_cmd(struct usb_xfer * xfer,uint16_t hdr,int * offp)322 cdceem_handle_cmd(struct usb_xfer *xfer, uint16_t hdr, int *offp)
323 {
324 struct cdceem_softc *sc;
325 struct usb_page_cache *pc;
326 int actlen, off;
327 uint16_t pktlen;
328
329 off = *offp;
330 sc = usbd_xfer_softc(xfer);
331 pc = usbd_xfer_get_frame(xfer, 0);
332 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
333
334 if (hdr & CDCEEM_CMD_RESERVED) {
335 CDCEEM_WARN(sc, "received command header %#x "
336 "with Reserved bit set; ignoring", hdr);
337 return;
338 }
339
340 switch (hdr & CDCEEM_CMD_MASK) {
341 case CDCEEM_CMD_ECHO:
342 pktlen = hdr & CDCEEM_ECHO_LEN_MASK;
343 CDCEEM_DEBUG(sc, "received Echo, length %d", pktlen);
344
345 if (pktlen > (actlen - off)) {
346 CDCEEM_WARN(sc,
347 "bad Echo length %d, should be at most %d",
348 pktlen, actlen - off);
349 break;
350 }
351
352 if (pktlen > sizeof(sc->sc_echo_buffer)) {
353 CDCEEM_WARN(sc,
354 "Echo length %u too big, must be less than %zd",
355 pktlen, sizeof(sc->sc_echo_buffer));
356 break;
357 }
358
359 sc->sc_flags |= CDCEEM_SC_FLAGS_ECHO_RESPONSE_PENDING;
360 sc->sc_echo_len = pktlen;
361 usbd_copy_out(pc, off, sc->sc_echo_buffer, pktlen);
362 off += pktlen;
363 break;
364
365 case CDCEEM_CMD_ECHO_RESPONSE:
366 pktlen = hdr & CDCEEM_ECHO_LEN_MASK;
367 CDCEEM_DEBUG(sc, "received Echo Response, length %d", pktlen);
368
369 if (pktlen > (actlen - off)) {
370 CDCEEM_WARN(sc,
371 "bad Echo Response length %d, "
372 "should be at most %d",
373 pktlen, actlen - off);
374 break;
375 }
376
377 if (pktlen != sizeof(CDCEEM_ECHO_PAYLOAD)) {
378 CDCEEM_WARN(sc, "received Echo Response with bad "
379 "length %hu, should be %zd",
380 pktlen, sizeof(CDCEEM_ECHO_PAYLOAD));
381 break;
382 }
383
384 usbd_copy_out(pc, off, sc->sc_echo_buffer, pktlen);
385 off += pktlen;
386
387 if (memcmp(sc->sc_echo_buffer, CDCEEM_ECHO_PAYLOAD,
388 sizeof(CDCEEM_ECHO_PAYLOAD)) != 0) {
389 CDCEEM_WARN(sc,
390 "received Echo Response payload does not match");
391 } else {
392 CDCEEM_DEBUG(sc, "received Echo Response is valid");
393 }
394 break;
395
396 case CDCEEM_CMD_SUSPEND_HINT:
397 CDCEEM_DEBUG(sc, "received SuspendHint; ignoring");
398 break;
399
400 case CDCEEM_CMD_RESPONSE_HINT:
401 CDCEEM_DEBUG(sc, "received ResponseHint; ignoring");
402 break;
403
404 case CDCEEM_CMD_RESPONSE_COMPLETE_HINT:
405 CDCEEM_DEBUG(sc, "received ResponseCompleteHint; ignoring");
406 break;
407
408 case CDCEEM_CMD_TICKLE:
409 CDCEEM_DEBUG(sc, "received Tickle; ignoring");
410 break;
411
412 default:
413 CDCEEM_WARN(sc,
414 "received unknown command %u, header %#x; ignoring",
415 (hdr & CDCEEM_CMD_MASK >> 11), hdr);
416 break;
417 }
418
419 *offp = off;
420 }
421
422 static void
cdceem_handle_data(struct usb_xfer * xfer,uint16_t hdr,int * offp)423 cdceem_handle_data(struct usb_xfer *xfer, uint16_t hdr, int *offp)
424 {
425 struct cdceem_softc *sc;
426 struct usb_page_cache *pc;
427 struct usb_ether *ue;
428 struct ifnet *ifp;
429 struct mbuf *m;
430 uint32_t computed_crc, received_crc;
431 int pktlen;
432 int actlen;
433 int off;
434
435 off = *offp;
436 sc = usbd_xfer_softc(xfer);
437 pc = usbd_xfer_get_frame(xfer, 0);
438 ue = &sc->sc_ue;
439 ifp = uether_getifp(ue);
440 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
441
442 pktlen = hdr & CDCEEM_DATA_LEN_MASK;
443 CDCEEM_DEBUG(sc, "received Data, CRC %s, length %d",
444 (hdr & CDCEEM_DATA_CRC) ? "valid" : "absent",
445 pktlen);
446
447 if (pktlen < (ETHER_HDR_LEN + 4)) {
448 CDCEEM_WARN(sc,
449 "bad ethernet frame length %d, should be at least %d",
450 pktlen, ETHER_HDR_LEN);
451 if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
452 return;
453 }
454
455 if (pktlen > (actlen - off)) {
456 CDCEEM_WARN(sc,
457 "bad ethernet frame length %d, should be at most %d",
458 pktlen, actlen - off);
459 if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
460 return;
461 }
462
463 m = uether_newbuf();
464 if (m == NULL) {
465 CDCEEM_WARN(sc, "uether_newbuf() failed");
466 if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
467 return;
468 }
469
470 pktlen -= 4; /* Subtract the CRC. */
471
472 if (pktlen > m->m_len) {
473 CDCEEM_WARN(sc, "buffer too small %d vs %d bytes",
474 pktlen, m->m_len);
475 if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
476 m_freem(m);
477 return;
478 }
479 usbd_copy_out(pc, off, mtod(m, uint8_t *), pktlen);
480 off += pktlen;
481
482 usbd_copy_out(pc, off, &received_crc, sizeof(received_crc));
483 off += sizeof(received_crc);
484
485 if (hdr & CDCEEM_DATA_CRC) {
486 computed_crc = cdceem_m_crc32(m, 0, pktlen);
487 } else {
488 computed_crc = be32toh(0xdeadbeef);
489 }
490
491 if (received_crc != computed_crc) {
492 CDCEEM_WARN(sc,
493 "received Data packet with wrong CRC %#x, expected %#x",
494 received_crc, computed_crc);
495 if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
496 m_freem(m);
497 return;
498 } else {
499 CDCEEM_DEBUG(sc, "received correct CRC %#x", received_crc);
500 }
501
502 uether_rxmbuf(ue, m, pktlen);
503 *offp = off;
504 }
505
506 static void
cdceem_bulk_read_callback(struct usb_xfer * xfer,usb_error_t usb_error)507 cdceem_bulk_read_callback(struct usb_xfer *xfer, usb_error_t usb_error)
508 {
509 struct cdceem_softc *sc;
510 struct usb_page_cache *pc;
511 int actlen, aframes, off;
512 uint16_t hdr;
513
514 sc = usbd_xfer_softc(xfer);
515 usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
516
517 switch (USB_GET_STATE(xfer)) {
518 case USB_ST_TRANSFERRED:
519 CDCEEM_DEBUG(sc,
520 "received %u bytes in %u frames", actlen, aframes);
521
522 pc = usbd_xfer_get_frame(xfer, 0);
523 off = 0;
524
525 while ((off + sizeof(hdr)) <= actlen) {
526 usbd_copy_out(pc, off, &hdr, sizeof(hdr));
527 CDCEEM_DEBUG(sc, "hdr = %#x", hdr);
528 off += sizeof(hdr);
529
530 if (hdr == 0) {
531 CDCEEM_DEBUG(sc, "received Zero Length EEM");
532 continue;
533 }
534
535 hdr = le16toh(hdr);
536
537 if ((hdr & CDCEEM_TYPE_CMD) != 0) {
538 cdceem_handle_cmd(xfer, hdr, &off);
539 } else {
540 cdceem_handle_data(xfer, hdr, &off);
541 }
542
543 KASSERT(off <= actlen,
544 ("%s: went past the buffer, off %d, actlen %d",
545 __func__, off, actlen));
546 }
547
548 /* FALLTHROUGH */
549 case USB_ST_SETUP:
550 CDCEEM_DEBUG(sc, "setup");
551 tr_setup:
552 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
553 usbd_transfer_submit(xfer);
554 uether_rxflush(&sc->sc_ue);
555 break;
556
557 default:
558 CDCEEM_WARN(sc, "USB_ST_ERROR: %s", usbd_errstr(usb_error));
559
560 if (usb_error != USB_ERR_CANCELLED) {
561 /* try to clear stall first */
562 usbd_xfer_set_stall(xfer);
563 goto tr_setup;
564 }
565 break;
566 }
567 }
568
569 static void
cdceem_send_echo(struct usb_xfer * xfer,int * offp)570 cdceem_send_echo(struct usb_xfer *xfer, int *offp)
571 {
572 struct cdceem_softc *sc;
573 struct usb_page_cache *pc;
574 int maxlen, off;
575 uint16_t hdr;
576
577 off = *offp;
578 sc = usbd_xfer_softc(xfer);
579 pc = usbd_xfer_get_frame(xfer, 0);
580 maxlen = usbd_xfer_max_len(xfer);
581
582 CDCEEM_DEBUG(sc, "sending Echo, length %zd",
583 sizeof(CDCEEM_ECHO_PAYLOAD));
584
585 KASSERT(off + sizeof(hdr) + sizeof(CDCEEM_ECHO_PAYLOAD) < maxlen,
586 ("%s: out of space; have %d, need %zd", __func__, maxlen,
587 off + sizeof(hdr) + sizeof(CDCEEM_ECHO_PAYLOAD)));
588
589 hdr = 0;
590 hdr |= CDCEEM_TYPE_CMD;
591 hdr |= CDCEEM_CMD_ECHO;
592 hdr |= sizeof(CDCEEM_ECHO_PAYLOAD);
593 CDCEEM_DEBUG(sc, "hdr = %#x", hdr);
594 hdr = htole16(hdr);
595
596 usbd_copy_in(pc, off, &hdr, sizeof(hdr));
597 off += sizeof(hdr);
598
599 usbd_copy_in(pc, off, CDCEEM_ECHO_PAYLOAD,
600 sizeof(CDCEEM_ECHO_PAYLOAD));
601 off += sizeof(CDCEEM_ECHO_PAYLOAD);
602
603 sc->sc_flags &= ~CDCEEM_SC_FLAGS_ECHO_PENDING;
604
605 *offp = off;
606 }
607
608 static void
cdceem_send_echo_response(struct usb_xfer * xfer,int * offp)609 cdceem_send_echo_response(struct usb_xfer *xfer, int *offp)
610 {
611 struct cdceem_softc *sc;
612 struct usb_page_cache *pc;
613 int maxlen, off;
614 uint16_t hdr;
615
616 off = *offp;
617 sc = usbd_xfer_softc(xfer);
618 pc = usbd_xfer_get_frame(xfer, 0);
619 maxlen = usbd_xfer_max_len(xfer);
620
621 KASSERT(off + sizeof(hdr) + sc->sc_echo_len < maxlen,
622 ("%s: out of space; have %d, need %zd", __func__, maxlen,
623 off + sizeof(hdr) + sc->sc_echo_len));
624
625 CDCEEM_DEBUG(sc, "sending Echo Response, length %zd", sc->sc_echo_len);
626
627 hdr = 0;
628 hdr |= CDCEEM_TYPE_CMD;
629 hdr |= CDCEEM_CMD_ECHO_RESPONSE;
630 hdr |= sc->sc_echo_len;
631 CDCEEM_DEBUG(sc, "hdr = %#x", hdr);
632 hdr = htole16(hdr);
633
634 usbd_copy_in(pc, off, &hdr, sizeof(hdr));
635 off += sizeof(hdr);
636
637 usbd_copy_in(pc, off, sc->sc_echo_buffer, sc->sc_echo_len);
638 off += sc->sc_echo_len;
639
640 sc->sc_flags &= ~CDCEEM_SC_FLAGS_ECHO_RESPONSE_PENDING;
641 sc->sc_echo_len = 0;
642
643 *offp = off;
644 }
645
646 static void
cdceem_send_data(struct usb_xfer * xfer,int * offp)647 cdceem_send_data(struct usb_xfer *xfer, int *offp)
648 {
649 struct cdceem_softc *sc;
650 struct usb_page_cache *pc;
651 struct ifnet *ifp;
652 struct mbuf *m;
653 int maxlen, off;
654 uint32_t crc;
655 uint16_t hdr;
656
657 off = *offp;
658 sc = usbd_xfer_softc(xfer);
659 pc = usbd_xfer_get_frame(xfer, 0);
660 ifp = uether_getifp(&sc->sc_ue);
661 maxlen = usbd_xfer_max_len(xfer);
662
663 IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
664 if (m == NULL) {
665 CDCEEM_DEBUG(sc, "no Data packets to send");
666 return;
667 }
668
669 KASSERT((m->m_pkthdr.len & CDCEEM_DATA_LEN_MASK) == m->m_pkthdr.len,
670 ("%s: packet too long: %d, should be %d\n", __func__,
671 m->m_pkthdr.len, m->m_pkthdr.len & CDCEEM_DATA_LEN_MASK));
672 KASSERT(off + sizeof(hdr) + m->m_pkthdr.len + 4 < maxlen,
673 ("%s: out of space; have %d, need %zd", __func__, maxlen,
674 off + sizeof(hdr) + m->m_pkthdr.len + 4));
675
676 CDCEEM_DEBUG(sc, "sending Data, length %d + 4", m->m_pkthdr.len);
677
678 hdr = 0;
679 if (!cdceem_send_fake_crc)
680 hdr |= CDCEEM_DATA_CRC;
681 hdr |= (m->m_pkthdr.len + 4); /* +4 for CRC */
682 CDCEEM_DEBUG(sc, "hdr = %#x", hdr);
683 hdr = htole16(hdr);
684
685 usbd_copy_in(pc, off, &hdr, sizeof(hdr));
686 off += sizeof(hdr);
687
688 usbd_m_copy_in(pc, off, m, 0, m->m_pkthdr.len);
689 off += m->m_pkthdr.len;
690
691 if (cdceem_send_fake_crc) {
692 crc = htobe32(0xdeadbeef);
693 } else {
694 crc = cdceem_m_crc32(m, 0, m->m_pkthdr.len);
695 }
696 CDCEEM_DEBUG(sc, "CRC = %#x", crc);
697
698 usbd_copy_in(pc, off, &crc, sizeof(crc));
699 off += sizeof(crc);
700
701 if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
702
703 /*
704 * If there's a BPF listener, bounce a copy of this frame to it.
705 */
706 BPF_MTAP(ifp, m);
707 m_freem(m);
708
709 *offp = off;
710 }
711
712 static void
cdceem_bulk_write_callback(struct usb_xfer * xfer,usb_error_t usb_error)713 cdceem_bulk_write_callback(struct usb_xfer *xfer, usb_error_t usb_error)
714 {
715 struct cdceem_softc *sc;
716 struct ifnet *ifp;
717 int actlen, aframes, maxlen, off;
718
719 sc = usbd_xfer_softc(xfer);
720 maxlen = usbd_xfer_max_len(xfer);
721
722 switch (USB_GET_STATE(xfer)) {
723 case USB_ST_TRANSFERRED:
724 usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
725 CDCEEM_DEBUG(sc, "transferred %u bytes in %u frames",
726 actlen, aframes);
727
728 /* FALLTHROUGH */
729 case USB_ST_SETUP:
730 CDCEEM_DEBUG(sc, "setup");
731 tr_setup:
732
733 off = 0;
734 usbd_xfer_set_frame_offset(xfer, 0, 0);
735
736 if (sc->sc_flags & CDCEEM_SC_FLAGS_ECHO_PENDING) {
737 cdceem_send_echo(xfer, &off);
738 } else if (sc->sc_flags & CDCEEM_SC_FLAGS_ECHO_RESPONSE_PENDING) {
739 cdceem_send_echo_response(xfer, &off);
740 } else {
741 cdceem_send_data(xfer, &off);
742 }
743
744 KASSERT(off <= maxlen,
745 ("%s: went past the buffer, off %d, maxlen %d",
746 __func__, off, maxlen));
747
748 if (off > 0) {
749 CDCEEM_DEBUG(sc, "starting transfer, length %d", off);
750 usbd_xfer_set_frame_len(xfer, 0, off);
751 usbd_transfer_submit(xfer);
752 } else {
753 CDCEEM_DEBUG(sc, "nothing to transfer");
754 }
755
756 break;
757
758 default:
759 CDCEEM_WARN(sc, "USB_ST_ERROR: %s", usbd_errstr(usb_error));
760
761 ifp = uether_getifp(&sc->sc_ue);
762 if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
763
764 if (usb_error != USB_ERR_CANCELLED) {
765 /* try to clear stall first */
766 usbd_xfer_set_stall(xfer);
767 goto tr_setup;
768 }
769 break;
770 }
771 }
772
773 static int32_t
cdceem_m_crc32_cb(void * arg,void * src,uint32_t count)774 cdceem_m_crc32_cb(void *arg, void *src, uint32_t count)
775 {
776 uint32_t *p_crc = arg;
777
778 *p_crc = crc32_raw(src, count, *p_crc);
779 return (0);
780 }
781
782 static uint32_t
cdceem_m_crc32(struct mbuf * m,uint32_t src_offset,uint32_t src_len)783 cdceem_m_crc32(struct mbuf *m, uint32_t src_offset, uint32_t src_len)
784 {
785 uint32_t crc = 0xFFFFFFFF;
786 int error;
787
788 error = m_apply(m, src_offset, src_len, cdceem_m_crc32_cb, &crc);
789 return (crc ^ 0xFFFFFFFF);
790 }
791
792 static void
cdceem_start(struct usb_ether * ue)793 cdceem_start(struct usb_ether *ue)
794 {
795 struct cdceem_softc *sc;
796
797 sc = uether_getsc(ue);
798
799 /*
800 * Start the USB transfers, if not already started.
801 */
802 usbd_transfer_start(sc->sc_xfer[CDCEEM_BULK_RX]);
803 usbd_transfer_start(sc->sc_xfer[CDCEEM_BULK_TX]);
804 }
805
806 static void
cdceem_init(struct usb_ether * ue)807 cdceem_init(struct usb_ether *ue)
808 {
809 struct cdceem_softc *sc;
810 struct ifnet *ifp;
811
812 sc = uether_getsc(ue);
813 ifp = uether_getifp(ue);
814
815 ifp->if_drv_flags |= IFF_DRV_RUNNING;
816
817 if (cdceem_send_echoes)
818 sc->sc_flags = CDCEEM_SC_FLAGS_ECHO_PENDING;
819 else
820 sc->sc_flags = 0;
821
822 /*
823 * Stall data write direction, which depends on USB mode.
824 *
825 * Some USB host stacks (e.g. Mac OS X) don't clears stall
826 * bit as it should, so set it in our host mode only.
827 */
828 if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST)
829 usbd_xfer_set_stall(sc->sc_xfer[CDCEEM_BULK_TX]);
830
831 cdceem_start(ue);
832 }
833
834 static void
cdceem_stop(struct usb_ether * ue)835 cdceem_stop(struct usb_ether *ue)
836 {
837 struct cdceem_softc *sc;
838 struct ifnet *ifp;
839
840 sc = uether_getsc(ue);
841 ifp = uether_getifp(ue);
842
843 ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
844
845 usbd_transfer_stop(sc->sc_xfer[CDCEEM_BULK_RX]);
846 usbd_transfer_stop(sc->sc_xfer[CDCEEM_BULK_TX]);
847 }
848
849 static void
cdceem_setmulti(struct usb_ether * ue)850 cdceem_setmulti(struct usb_ether *ue)
851 {
852 /* no-op */
853 return;
854 }
855
856 static void
cdceem_setpromisc(struct usb_ether * ue)857 cdceem_setpromisc(struct usb_ether *ue)
858 {
859 /* no-op */
860 return;
861 }
862
863 static int
cdceem_suspend(device_t dev)864 cdceem_suspend(device_t dev)
865 {
866 struct cdceem_softc *sc = device_get_softc(dev);
867
868 CDCEEM_DEBUG(sc, "go");
869 return (0);
870 }
871
872 static int
cdceem_resume(device_t dev)873 cdceem_resume(device_t dev)
874 {
875 struct cdceem_softc *sc = device_get_softc(dev);
876
877 CDCEEM_DEBUG(sc, "go");
878 return (0);
879 }
880