xref: /openbsd/sys/dev/usb/if_cdce.c (revision 81508fe3)
1 /*	$OpenBSD: if_cdce.c,v 1.83 2024/05/23 03:21:08 jsg Exp $ */
2 
3 /*
4  * Copyright (c) 1997, 1998, 1999, 2000-2003 Bill Paul <wpaul@windriver.com>
5  * Copyright (c) 2003 Craig Boston
6  * Copyright (c) 2004 Daniel Hartmeier
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *	This product includes software developed by Bill Paul.
20  * 4. Neither the name of the author nor the names of any co-contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul, THE VOICES IN HIS HEAD OR
28  * THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
31  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
33  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
34  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  */
36 
37 /*
38  * USB Communication Device Class (Ethernet Networking Control Model)
39  * https://www.usb.org/sites/default/files/CDC1.2_WMC1.1_012011.zip
40  *
41  */
42 
43 #include <bpfilter.h>
44 
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/sockio.h>
48 #include <sys/mbuf.h>
49 #include <sys/device.h>
50 
51 #include <net/if.h>
52 
53 #if NBPFILTER > 0
54 #include <net/bpf.h>
55 #endif
56 
57 #include <netinet/in.h>
58 #include <netinet/if_ether.h>
59 
60 #include <dev/usb/usb.h>
61 #include <dev/usb/usbdi.h>
62 #include <dev/usb/usbdi_util.h>
63 #include <dev/usb/usbdevs.h>
64 #include <dev/usb/usbcdc.h>
65 
66 #include <dev/usb/if_cdcereg.h>
67 
68 #ifdef CDCE_DEBUG
69 #define DPRINTFN(n, x)	do { if (cdcedebug > (n)) printf x; } while (0)
70 int cdcedebug = 0;
71 #else
72 #define DPRINTFN(n, x)
73 #endif
74 #define DPRINTF(x)	DPRINTFN(0, x)
75 
76 int	 cdce_tx_list_init(struct cdce_softc *);
77 int	 cdce_rx_list_init(struct cdce_softc *);
78 int	 cdce_newbuf(struct cdce_softc *, struct cdce_chain *,
79 		    struct mbuf *);
80 int	 cdce_encap(struct cdce_softc *, struct mbuf *, int);
81 void	 cdce_rxeof(struct usbd_xfer *, void *, usbd_status);
82 void	 cdce_txeof(struct usbd_xfer *, void *, usbd_status);
83 void	 cdce_start(struct ifnet *);
84 int	 cdce_ioctl(struct ifnet *, u_long, caddr_t);
85 void	 cdce_init(void *);
86 void	 cdce_watchdog(struct ifnet *);
87 void	 cdce_stop(struct cdce_softc *);
88 void	 cdce_intr(struct usbd_xfer *, void *, usbd_status);
89 
90 const struct cdce_type cdce_devs[] = {
91     {{ USB_VENDOR_ACERLABS, USB_PRODUCT_ACERLABS_M5632 }, 0 },
92     {{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2501 }, 0 },
93     {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5500 }, CDCE_CRC32 },
94     {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_A300 }, CDCE_CRC32 },
95     {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5600 }, CDCE_CRC32 },
96     {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_C700 }, CDCE_CRC32 },
97     {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_C750 }, CDCE_CRC32 },
98     {{ USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_USBLAN }, CDCE_CRC32 },
99     {{ USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_USBLAN2 }, CDCE_CRC32 },
100     {{ USB_VENDOR_GMATE, USB_PRODUCT_GMATE_YP3X00 }, 0 },
101     {{ USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_IPAQLINUX }, 0 },
102     {{ USB_VENDOR_AMBIT, USB_PRODUCT_AMBIT_NTL_250 }, CDCE_SWAPUNION },
103 };
104 #define cdce_lookup(v, p) \
105     ((const struct cdce_type *)usb_lookup(cdce_devs, v, p))
106 
107 int cdce_match(struct device *, void *, void *);
108 void cdce_attach(struct device *, struct device *, void *);
109 int cdce_detach(struct device *, int);
110 
111 struct cfdriver cdce_cd = {
112 	NULL, "cdce", DV_IFNET
113 };
114 
115 const struct cfattach cdce_ca = {
116 	sizeof(struct cdce_softc), cdce_match, cdce_attach, cdce_detach
117 };
118 
119 int
cdce_match(struct device * parent,void * match,void * aux)120 cdce_match(struct device *parent, void *match, void *aux)
121 {
122 	struct usb_attach_arg *uaa = aux;
123 	usb_interface_descriptor_t *id;
124 
125 	if (uaa->iface == NULL)
126 		return (UMATCH_NONE);
127 
128 	id = usbd_get_interface_descriptor(uaa->iface);
129 	if (id == NULL)
130 		return (UMATCH_NONE);
131 
132 	if (cdce_lookup(uaa->vendor, uaa->product) != NULL)
133 		return (UMATCH_VENDOR_PRODUCT);
134 
135 	if (id->bInterfaceClass == UICLASS_CDC &&
136 	    (id->bInterfaceSubClass ==
137 	    UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL ||
138 	    id->bInterfaceSubClass == UISUBCLASS_MOBILE_DIRECT_LINE_MODEL))
139 		return (UMATCH_IFACECLASS_GENERIC);
140 
141 	return (UMATCH_NONE);
142 }
143 
144 void
cdce_attach(struct device * parent,struct device * self,void * aux)145 cdce_attach(struct device *parent, struct device *self, void *aux)
146 {
147 	struct cdce_softc		*sc = (struct cdce_softc *)self;
148 	struct usb_attach_arg		*uaa = aux;
149 	int				 s;
150 	struct ifnet			*ifp = GET_IFP(sc);
151 	struct usbd_device		*dev = uaa->device;
152 	const struct cdce_type		*t;
153 	usb_interface_descriptor_t	*id;
154 	usb_endpoint_descriptor_t	*ed;
155 	struct usb_cdc_union_descriptor	*ud;
156 	struct usb_cdc_ethernet_descriptor *ethd;
157 	usb_config_descriptor_t		*cd;
158 	const usb_descriptor_t		*desc;
159 	struct usbd_desc_iter		 iter;
160 	usb_string_descriptor_t		 eaddr_str;
161 	int				 i, j, numalts, len;
162 	int				 ctl_ifcno = -1;
163 	int				 data_ifcno = -1;
164 
165 	sc->cdce_udev = uaa->device;
166 	sc->cdce_ctl_iface = uaa->iface;
167 	id = usbd_get_interface_descriptor(sc->cdce_ctl_iface);
168 	ctl_ifcno = id->bInterfaceNumber;
169 
170 	t = cdce_lookup(uaa->vendor, uaa->product);
171 	if (t)
172 		sc->cdce_flags = t->cdce_flags;
173 
174 	/* Get the data interface no. and capabilities */
175 	ethd = NULL;
176 	usbd_desc_iter_init(dev, &iter);
177 	desc = usbd_desc_iter_next(&iter);
178 	while (desc) {
179 		if (desc->bDescriptorType != UDESC_CS_INTERFACE) {
180 			desc = usbd_desc_iter_next(&iter);
181 			continue;
182 		}
183 		switch(desc->bDescriptorSubtype) {
184 		case UDESCSUB_CDC_UNION:
185 			ud = (struct usb_cdc_union_descriptor *)desc;
186 			if ((sc->cdce_flags & CDCE_SWAPUNION) == 0 &&
187 			    ud->bMasterInterface == ctl_ifcno)
188 				data_ifcno = ud->bSlaveInterface[0];
189 			if ((sc->cdce_flags & CDCE_SWAPUNION) &&
190 			    ud->bSlaveInterface[0] == ctl_ifcno)
191 				data_ifcno = ud->bMasterInterface;
192 			break;
193 		case UDESCSUB_CDC_ENF:
194 			if (ethd) {
195 				printf("%s: ", sc->cdce_dev.dv_xname);
196 				printf("extra ethernet descriptor\n");
197 				return;
198 			}
199 			ethd = (struct usb_cdc_ethernet_descriptor *)desc;
200 			break;
201 		}
202 		desc = usbd_desc_iter_next(&iter);
203 	}
204 
205 	if (data_ifcno == -1) {
206 		DPRINTF(("cdce_attach: no union interface\n"));
207 		sc->cdce_data_iface = sc->cdce_ctl_iface;
208 	} else {
209 		DPRINTF(("cdce_attach: union interface: ctl=%d, data=%d\n",
210 		    ctl_ifcno, data_ifcno));
211 		for (i = 0; i < uaa->nifaces; i++) {
212 			if (usbd_iface_claimed(sc->cdce_udev, i))
213 				continue;
214 			id = usbd_get_interface_descriptor(uaa->ifaces[i]);
215 			if (id != NULL && id->bInterfaceNumber == data_ifcno) {
216 				sc->cdce_data_iface = uaa->ifaces[i];
217 				usbd_claim_iface(sc->cdce_udev, i);
218 			}
219 		}
220 	}
221 
222 	if (sc->cdce_data_iface == NULL) {
223 		printf("%s: no data interface\n", sc->cdce_dev.dv_xname);
224 		return;
225 	}
226 
227 	id = usbd_get_interface_descriptor(sc->cdce_ctl_iface);
228 	sc->cdce_intr_no = -1;
229 	for (i = 0; i < id->bNumEndpoints && sc->cdce_intr_no == -1; i++) {
230 		ed = usbd_interface2endpoint_descriptor(sc->cdce_ctl_iface, i);
231 		if (!ed) {
232 			printf("%s: no descriptor for interrupt endpoint %d\n",
233 			    sc->cdce_dev.dv_xname, i);
234 			return;
235 		}
236 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
237 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
238 			sc->cdce_intr_no = ed->bEndpointAddress;
239 			sc->cdce_intr_size = sizeof(sc->cdce_intr_buf);
240 		}
241 	}
242 
243 	id = usbd_get_interface_descriptor(sc->cdce_data_iface);
244 	cd = usbd_get_config_descriptor(sc->cdce_udev);
245 	numalts = usbd_get_no_alts(cd, id->bInterfaceNumber);
246 
247 	for (j = 0; j < numalts; j++) {
248 		if (usbd_set_interface(sc->cdce_data_iface, j)) {
249 			printf("%s: interface alternate setting %d failed\n",
250 			    sc->cdce_dev.dv_xname, j);
251 			return;
252 		}
253 		/* Find endpoints. */
254 		id = usbd_get_interface_descriptor(sc->cdce_data_iface);
255 		sc->cdce_bulkin_no = sc->cdce_bulkout_no = -1;
256 		for (i = 0; i < id->bNumEndpoints; i++) {
257 			ed = usbd_interface2endpoint_descriptor(
258 			    sc->cdce_data_iface, i);
259 			if (!ed) {
260 				printf("%s: no descriptor for bulk endpoint "
261 				    "%d\n", sc->cdce_dev.dv_xname, i);
262 				return;
263 			}
264 			if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
265 			    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
266 				sc->cdce_bulkin_no = ed->bEndpointAddress;
267 			} else if (
268 			    UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
269 			    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
270 				sc->cdce_bulkout_no = ed->bEndpointAddress;
271 			}
272 #ifdef CDCE_DEBUG
273 			else if (
274 			    UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN &&
275 			    UE_GET_XFERTYPE(ed->bmAttributes) != UE_INTERRUPT) {
276 				printf("%s: unexpected endpoint, ep=%x attr=%x"
277 				    "\n", sc->cdce_dev.dv_xname,
278 				    ed->bEndpointAddress, ed->bmAttributes);
279 			}
280 #endif
281 		}
282 		if ((sc->cdce_bulkin_no != -1) && (sc->cdce_bulkout_no != -1)) {
283 			DPRINTF(("cdce_attach: intr=0x%x, in=0x%x, out=0x%x\n",
284 			    sc->cdce_intr_no, sc->cdce_bulkin_no,
285 			    sc->cdce_bulkout_no));
286 			goto found;
287 		}
288 	}
289 
290 	if (sc->cdce_bulkin_no == -1) {
291 		printf("%s: could not find data bulk in\n",
292 		    sc->cdce_dev.dv_xname);
293 		return;
294 	}
295 	if (sc->cdce_bulkout_no == -1 ) {
296 		printf("%s: could not find data bulk out\n",
297 		    sc->cdce_dev.dv_xname);
298 		return;
299 	}
300 
301 found:
302 	s = splnet();
303 
304 	if (!ethd || usbd_get_string_desc(sc->cdce_udev, ethd->iMacAddress, 0,
305 	    &eaddr_str, &len)) {
306 		ether_fakeaddr(ifp);
307 	} else {
308 		for (i = 0; i < ETHER_ADDR_LEN * 2; i++) {
309 			int c = UGETW(eaddr_str.bString[i]);
310 
311 			if ('0' <= c && c <= '9')
312 				c -= '0';
313 			else if ('A' <= c && c <= 'F')
314 				c -= 'A' - 10;
315 			else if ('a' <= c && c <= 'f')
316 				c -= 'a' - 10;
317 			c &= 0xf;
318 			if (i % 2 == 0)
319 				c <<= 4;
320 			sc->cdce_arpcom.ac_enaddr[i / 2] |= c;
321 		}
322 	}
323 
324 	printf("%s: address %s\n", sc->cdce_dev.dv_xname,
325 	    ether_sprintf(sc->cdce_arpcom.ac_enaddr));
326 
327 	ifp->if_softc = sc;
328 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
329 	ifp->if_ioctl = cdce_ioctl;
330 	ifp->if_start = cdce_start;
331 	ifp->if_watchdog = cdce_watchdog;
332 	strlcpy(ifp->if_xname, sc->cdce_dev.dv_xname, IFNAMSIZ);
333 
334 	if_attach(ifp);
335 	ether_ifattach(ifp);
336 
337 	sc->cdce_attached = 1;
338 	splx(s);
339 }
340 
341 int
cdce_detach(struct device * self,int flags)342 cdce_detach(struct device *self, int flags)
343 {
344 	struct cdce_softc	*sc = (struct cdce_softc *)self;
345 	struct ifnet		*ifp = GET_IFP(sc);
346 	int			 s;
347 
348 	if (!sc->cdce_attached)
349 		return (0);
350 
351 	s = splusb();
352 
353 	if (ifp->if_flags & IFF_RUNNING)
354 		cdce_stop(sc);
355 
356 	if (ifp->if_softc != NULL) {
357 		ether_ifdetach(ifp);
358 		if_detach(ifp);
359 	}
360 
361 	sc->cdce_attached = 0;
362 	splx(s);
363 
364 	return (0);
365 }
366 
367 void
cdce_start(struct ifnet * ifp)368 cdce_start(struct ifnet *ifp)
369 {
370 	struct cdce_softc	*sc = ifp->if_softc;
371 	struct mbuf		*m_head = NULL;
372 
373 	if (usbd_is_dying(sc->cdce_udev) || ifq_is_oactive(&ifp->if_snd))
374 		return;
375 
376 	m_head = ifq_dequeue(&ifp->if_snd);
377 	if (m_head == NULL)
378 		return;
379 
380 	if (cdce_encap(sc, m_head, 0)) {
381 		m_freem(m_head);
382 		ifq_set_oactive(&ifp->if_snd);
383 		return;
384 	}
385 
386 #if NBPFILTER > 0
387 	if (ifp->if_bpf)
388 		bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
389 #endif
390 
391 	ifq_set_oactive(&ifp->if_snd);
392 
393 	ifp->if_timer = 6;
394 }
395 
396 int
cdce_encap(struct cdce_softc * sc,struct mbuf * m,int idx)397 cdce_encap(struct cdce_softc *sc, struct mbuf *m, int idx)
398 {
399 	struct cdce_chain	*c;
400 	usbd_status		 err;
401 	int			 extra = 0;
402 
403 	c = &sc->cdce_cdata.cdce_tx_chain[idx];
404 
405 	m_copydata(m, 0, m->m_pkthdr.len, c->cdce_buf);
406 	if (sc->cdce_flags & CDCE_CRC32) {
407 		/* Some devices want a 32-bit CRC appended to every frame */
408 		u_int32_t crc;
409 
410 		crc = ether_crc32_le(c->cdce_buf, m->m_pkthdr.len) ^ ~0U;
411 		bcopy(&crc, c->cdce_buf + m->m_pkthdr.len, 4);
412 		extra = 4;
413 	}
414 	c->cdce_mbuf = m;
415 
416 	usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkout_pipe, c, c->cdce_buf,
417 	    m->m_pkthdr.len + extra, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
418 	    10000, cdce_txeof);
419 	err = usbd_transfer(c->cdce_xfer);
420 	if (err != USBD_IN_PROGRESS) {
421 		c->cdce_mbuf = NULL;
422 		cdce_stop(sc);
423 		return (EIO);
424 	}
425 
426 	sc->cdce_cdata.cdce_tx_cnt++;
427 
428 	return (0);
429 }
430 
431 void
cdce_stop(struct cdce_softc * sc)432 cdce_stop(struct cdce_softc *sc)
433 {
434 	usbd_status	 err;
435 	struct ifnet	*ifp = GET_IFP(sc);
436 	int		 i;
437 
438 	ifp->if_timer = 0;
439 	ifp->if_flags &= ~IFF_RUNNING;
440 	ifq_clr_oactive(&ifp->if_snd);
441 
442 	if (sc->cdce_bulkin_pipe != NULL) {
443 		err = usbd_close_pipe(sc->cdce_bulkin_pipe);
444 		if (err)
445 			printf("%s: close rx pipe failed: %s\n",
446 			    sc->cdce_dev.dv_xname, usbd_errstr(err));
447 		sc->cdce_bulkin_pipe = NULL;
448 	}
449 
450 	if (sc->cdce_bulkout_pipe != NULL) {
451 		err = usbd_close_pipe(sc->cdce_bulkout_pipe);
452 		if (err)
453 			printf("%s: close tx pipe failed: %s\n",
454 			    sc->cdce_dev.dv_xname, usbd_errstr(err));
455 		sc->cdce_bulkout_pipe = NULL;
456 	}
457 
458 	if (sc->cdce_intr_pipe != NULL) {
459 		err = usbd_close_pipe(sc->cdce_intr_pipe);
460 		if (err)
461 			printf("%s: close interrupt pipe failed: %s\n",
462 			    sc->cdce_dev.dv_xname, usbd_errstr(err));
463 		sc->cdce_intr_pipe = NULL;
464 	}
465 
466 	for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
467 		if (sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf != NULL) {
468 			m_freem(sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf);
469 			sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf = NULL;
470 		}
471 		if (sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer != NULL) {
472 			usbd_free_xfer(sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer);
473 			sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer = NULL;
474 		}
475 	}
476 
477 	for (i = 0; i < CDCE_TX_LIST_CNT; i++) {
478 		if (sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf != NULL) {
479 			m_freem(sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf);
480 			sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf = NULL;
481 		}
482 		if (sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer != NULL) {
483 			usbd_free_xfer(
484 			    sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer);
485 			sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer = NULL;
486 		}
487 	}
488 }
489 
490 int
cdce_ioctl(struct ifnet * ifp,u_long command,caddr_t data)491 cdce_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
492 {
493 	struct cdce_softc	*sc = ifp->if_softc;
494 	int			 s, error = 0;
495 
496 	if (usbd_is_dying(sc->cdce_udev))
497 		return ENXIO;
498 
499 	s = splnet();
500 
501 	switch(command) {
502 	case SIOCSIFADDR:
503 		ifp->if_flags |= IFF_UP;
504 		if (!(ifp->if_flags & IFF_RUNNING))
505 			cdce_init(sc);
506 		break;
507 
508 	case SIOCSIFFLAGS:
509 		if (ifp->if_flags & IFF_UP) {
510 			if (ifp->if_flags & IFF_RUNNING)
511 				error = ENETRESET;
512 			else
513 				cdce_init(sc);
514 		} else {
515 			if (ifp->if_flags & IFF_RUNNING)
516 				cdce_stop(sc);
517 		}
518 		break;
519 
520 	default:
521 		error = ether_ioctl(ifp, &sc->cdce_arpcom, command, data);
522 		break;
523 	}
524 
525 	if (error == ENETRESET)
526 		error = 0;
527 
528 	splx(s);
529 	return (error);
530 }
531 
532 void
cdce_watchdog(struct ifnet * ifp)533 cdce_watchdog(struct ifnet *ifp)
534 {
535 	struct cdce_softc	*sc = ifp->if_softc;
536 
537 	if (usbd_is_dying(sc->cdce_udev))
538 		return;
539 
540 	ifp->if_oerrors++;
541 	printf("%s: watchdog timeout\n", sc->cdce_dev.dv_xname);
542 }
543 
544 void
cdce_init(void * xsc)545 cdce_init(void *xsc)
546 {
547 	struct cdce_softc	*sc = xsc;
548 	struct ifnet		*ifp = GET_IFP(sc);
549 	struct cdce_chain	*c;
550 	usbd_status		 err;
551 	int			 s, i;
552 
553 	s = splnet();
554 
555 	if (sc->cdce_intr_no != -1 && sc->cdce_intr_pipe == NULL) {
556 		DPRINTFN(1, ("cdce_init: establish interrupt pipe\n"));
557 		err = usbd_open_pipe_intr(sc->cdce_ctl_iface, sc->cdce_intr_no,
558 		    USBD_SHORT_XFER_OK, &sc->cdce_intr_pipe, sc,
559 		    &sc->cdce_intr_buf, sc->cdce_intr_size, cdce_intr,
560 		    USBD_DEFAULT_INTERVAL);
561 		if (err) {
562 			printf("%s: open interrupt pipe failed: %s\n",
563 			    sc->cdce_dev.dv_xname, usbd_errstr(err));
564 			splx(s);
565 			return;
566 		}
567 	}
568 
569 	if (cdce_tx_list_init(sc) == ENOBUFS) {
570 		printf("%s: tx list init failed\n", sc->cdce_dev.dv_xname);
571 		splx(s);
572 		return;
573 	}
574 
575 	if (cdce_rx_list_init(sc) == ENOBUFS) {
576 		printf("%s: rx list init failed\n", sc->cdce_dev.dv_xname);
577 		splx(s);
578 		return;
579 	}
580 
581 	/* Maybe set multicast / broadcast here??? */
582 
583 	err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkin_no,
584 	    USBD_EXCLUSIVE_USE, &sc->cdce_bulkin_pipe);
585 	if (err) {
586 		printf("%s: open rx pipe failed: %s\n", sc->cdce_dev.dv_xname,
587 		    usbd_errstr(err));
588 		splx(s);
589 		return;
590 	}
591 
592 	err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkout_no,
593 	    USBD_EXCLUSIVE_USE, &sc->cdce_bulkout_pipe);
594 	if (err) {
595 		printf("%s: open tx pipe failed: %s\n", sc->cdce_dev.dv_xname,
596 		    usbd_errstr(err));
597 		splx(s);
598 		return;
599 	}
600 
601 	for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
602 		c = &sc->cdce_cdata.cdce_rx_chain[i];
603 		usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkin_pipe, c,
604 		    c->cdce_buf, CDCE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
605 		    USBD_NO_TIMEOUT, cdce_rxeof);
606 		usbd_transfer(c->cdce_xfer);
607 	}
608 
609 	ifp->if_flags |= IFF_RUNNING;
610 	ifq_clr_oactive(&ifp->if_snd);
611 
612 	splx(s);
613 }
614 
615 int
cdce_newbuf(struct cdce_softc * sc,struct cdce_chain * c,struct mbuf * m)616 cdce_newbuf(struct cdce_softc *sc, struct cdce_chain *c, struct mbuf *m)
617 {
618 	struct mbuf	*m_new = NULL;
619 
620 	if (m == NULL) {
621 		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
622 		if (m_new == NULL) {
623 			printf("%s: no memory for rx list "
624 			    "-- packet dropped!\n", sc->cdce_dev.dv_xname);
625 			return (ENOBUFS);
626 		}
627 		MCLGET(m_new, M_DONTWAIT);
628 		if (!(m_new->m_flags & M_EXT)) {
629 			printf("%s: no memory for rx list "
630 			    "-- packet dropped!\n", sc->cdce_dev.dv_xname);
631 			m_freem(m_new);
632 			return (ENOBUFS);
633 		}
634 		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
635 	} else {
636 		m_new = m;
637 		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
638 		m_new->m_data = m_new->m_ext.ext_buf;
639 	}
640 
641 	m_adj(m_new, ETHER_ALIGN);
642 	c->cdce_mbuf = m_new;
643 	return (0);
644 }
645 
646 int
cdce_rx_list_init(struct cdce_softc * sc)647 cdce_rx_list_init(struct cdce_softc *sc)
648 {
649 	struct cdce_cdata	*cd;
650 	struct cdce_chain	*c;
651 	int			 i;
652 
653 	cd = &sc->cdce_cdata;
654 	for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
655 		c = &cd->cdce_rx_chain[i];
656 		c->cdce_sc = sc;
657 		c->cdce_idx = i;
658 		if (cdce_newbuf(sc, c, NULL) == ENOBUFS)
659 			return (ENOBUFS);
660 		if (c->cdce_xfer == NULL) {
661 			c->cdce_xfer = usbd_alloc_xfer(sc->cdce_udev);
662 			if (c->cdce_xfer == NULL)
663 				return (ENOBUFS);
664 			c->cdce_buf = usbd_alloc_buffer(c->cdce_xfer,
665 			    CDCE_BUFSZ);
666 			if (c->cdce_buf == NULL)
667 				return (ENOBUFS);
668 		}
669 	}
670 
671 	return (0);
672 }
673 
674 int
cdce_tx_list_init(struct cdce_softc * sc)675 cdce_tx_list_init(struct cdce_softc *sc)
676 {
677 	struct cdce_cdata	*cd;
678 	struct cdce_chain	*c;
679 	int			 i;
680 
681 	cd = &sc->cdce_cdata;
682 	for (i = 0; i < CDCE_TX_LIST_CNT; i++) {
683 		c = &cd->cdce_tx_chain[i];
684 		c->cdce_sc = sc;
685 		c->cdce_idx = i;
686 		c->cdce_mbuf = NULL;
687 		if (c->cdce_xfer == NULL) {
688 			c->cdce_xfer = usbd_alloc_xfer(sc->cdce_udev);
689 			if (c->cdce_xfer == NULL)
690 				return (ENOBUFS);
691 			c->cdce_buf = usbd_alloc_buffer(c->cdce_xfer,
692 			    CDCE_BUFSZ);
693 			if (c->cdce_buf == NULL)
694 				return (ENOBUFS);
695 		}
696 	}
697 
698 	return (0);
699 }
700 
701 void
cdce_rxeof(struct usbd_xfer * xfer,void * priv,usbd_status status)702 cdce_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
703 {
704 	struct cdce_chain	*c = priv;
705 	struct cdce_softc	*sc = c->cdce_sc;
706 	struct ifnet		*ifp = GET_IFP(sc);
707 	struct mbuf		*m;
708 	struct mbuf_list	 ml = MBUF_LIST_INITIALIZER();
709 	int			 total_len = 0;
710 	int			 s;
711 
712 	if (usbd_is_dying(sc->cdce_udev) || !(ifp->if_flags & IFF_RUNNING))
713 		return;
714 
715 	if (status != USBD_NORMAL_COMPLETION) {
716 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
717 			return;
718 		if (sc->cdce_rxeof_errors == 0)
719 			printf("%s: usb error on rx: %s\n",
720 			    sc->cdce_dev.dv_xname, usbd_errstr(status));
721 		if (status == USBD_STALLED)
722 			usbd_clear_endpoint_stall_async(sc->cdce_bulkin_pipe);
723 		DELAY(sc->cdce_rxeof_errors * 10000);
724 		if (sc->cdce_rxeof_errors++ > 10) {
725 			printf("%s: too many errors, disabling\n",
726 			    sc->cdce_dev.dv_xname);
727 			usbd_deactivate(sc->cdce_udev);
728 			return;
729 		}
730 		goto done;
731 	}
732 
733 	sc->cdce_rxeof_errors = 0;
734 
735 	usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
736 	if (sc->cdce_flags & CDCE_CRC32)
737 		total_len -= 4;	/* Strip off added CRC */
738 	if (total_len <= 1)
739 		goto done;
740 
741 	m = c->cdce_mbuf;
742 	memcpy(mtod(m, char *), c->cdce_buf, total_len);
743 
744 	if (total_len < sizeof(struct ether_header)) {
745 		ifp->if_ierrors++;
746 		goto done;
747 	}
748 
749 	m->m_pkthdr.len = m->m_len = total_len;
750 	ml_enqueue(&ml, m);
751 
752 	if (cdce_newbuf(sc, c, NULL) == ENOBUFS) {
753 		ifp->if_ierrors++;
754 		goto done;
755 	}
756 
757 	s = splnet();
758 	if_input(ifp, &ml);
759 	splx(s);
760 
761 done:
762 	/* Setup new transfer. */
763 	usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkin_pipe, c, c->cdce_buf,
764 	    CDCE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
765 	    cdce_rxeof);
766 	usbd_transfer(c->cdce_xfer);
767 }
768 
769 void
cdce_txeof(struct usbd_xfer * xfer,void * priv,usbd_status status)770 cdce_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
771 {
772 	struct cdce_chain	*c = priv;
773 	struct cdce_softc	*sc = c->cdce_sc;
774 	struct ifnet		*ifp = GET_IFP(sc);
775 	usbd_status		 err;
776 	int			 s;
777 
778 	if (usbd_is_dying(sc->cdce_udev))
779 		return;
780 
781 	s = splnet();
782 
783 	ifp->if_timer = 0;
784 	ifq_clr_oactive(&ifp->if_snd);
785 
786 	if (status != USBD_NORMAL_COMPLETION) {
787 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
788 			splx(s);
789 			return;
790 		}
791 		ifp->if_oerrors++;
792 		printf("%s: usb error on tx: %s\n", sc->cdce_dev.dv_xname,
793 		    usbd_errstr(status));
794 		if (status == USBD_STALLED)
795 			usbd_clear_endpoint_stall_async(sc->cdce_bulkout_pipe);
796 		splx(s);
797 		return;
798 	}
799 
800 	usbd_get_xfer_status(c->cdce_xfer, NULL, NULL, NULL, &err);
801 
802 	if (c->cdce_mbuf != NULL) {
803 		m_freem(c->cdce_mbuf);
804 		c->cdce_mbuf = NULL;
805 	}
806 
807 	if (err)
808 		ifp->if_oerrors++;
809 
810 	if (ifq_empty(&ifp->if_snd) == 0)
811 		cdce_start(ifp);
812 
813 	splx(s);
814 }
815 
816 void
cdce_intr(struct usbd_xfer * xfer,void * addr,usbd_status status)817 cdce_intr(struct usbd_xfer *xfer, void *addr, usbd_status status)
818 {
819 	struct cdce_softc	*sc = addr;
820 	struct usb_cdc_notification *buf = &sc->cdce_intr_buf;
821 	struct usb_cdc_connection_speed	*speed;
822 	u_int32_t		 count;
823 
824 	if (status == USBD_CANCELLED)
825 		return;
826 
827 	if (status != USBD_NORMAL_COMPLETION) {
828 		DPRINTFN(2, ("cdce_intr: status=%d\n", status));
829 		if (status == USBD_STALLED)
830 			usbd_clear_endpoint_stall_async(sc->cdce_intr_pipe);
831 		return;
832 	}
833 
834 	usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
835 
836 	if (buf->bmRequestType == UCDC_NOTIFICATION) {
837 		switch (buf->bNotification) {
838 		case UCDC_N_NETWORK_CONNECTION:
839 			DPRINTFN(1, ("cdce_intr: network %s\n",
840 			    UGETW(buf->wValue) ? "connected" : "disconnected"));
841 			break;
842 		case UCDC_N_CONNECTION_SPEED_CHANGE:
843 			speed = (struct usb_cdc_connection_speed *)&buf->data;
844 			DPRINTFN(1, ("cdce_intr: up=%d, down=%d\n",
845 			    UGETDW(speed->dwUSBitRate),
846 			    UGETDW(speed->dwDSBitRate)));
847 			break;
848 		default:
849 			DPRINTF(("cdce_intr: bNotification 0x%x\n",
850 			    buf->bNotification));
851 		}
852 	}
853 #ifdef CDCE_DEBUG
854 	else {
855 		printf("cdce_intr: bmRequestType=%d ", buf->bmRequestType);
856 		printf("wValue=%d wIndex=%d wLength=%d\n", UGETW(buf->wValue),
857 		    UGETW(buf->wIndex), UGETW(buf->wLength));
858 	}
859 #endif
860 }
861