xref: /freebsd/sys/dev/usb/net/if_cdceem.c (revision ca48e43ba9ee73a07cdbad8365117793b01273bb)
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