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