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