static void cdce_init(struct usb_ether *ue) { struct cdce_softc *sc = uether_getsc(ue); struct ifnet *ifp = uether_getifp(ue); CDCE_LOCK_ASSERT(sc, MA_OWNED); ifp->if_drv_flags |= IFF_DRV_RUNNING; /* start interrupt transfer */ usbd_transfer_start(sc->sc_xfer[CDCE_INTR_RX]); usbd_transfer_start(sc->sc_xfer[CDCE_INTR_TX]); /* * Stall data write direction, which depends on USB mode. * * Some USB host stacks (e.g. Mac OS X) don't clears stall * bit as it should, so set it in our host mode only. */ if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST) usbd_xfer_set_stall(sc->sc_xfer[CDCE_BULK_TX]); /* start data transfers */ cdce_start(ue); }
int uether_rxbuf(struct usb_ether *ue, struct usb_page_cache *pc, unsigned int offset, unsigned int len) { struct ifnet *ifp = uether_getifp(ue); struct mbuf *m; UE_LOCK_ASSERT(ue); if (len < ETHER_HDR_LEN || len > MCLBYTES - ETHER_ALIGN) return (1); m = uether_newbuf(); if (m == NULL) { IFNET_STAT_INC(ifp, iqdrops, 1); return (ENOMEM); } usbd_copy_out(pc, offset, mtod(m, uint8_t *), len); /* finalize mbuf */ IFNET_STAT_INC(ifp, ipackets, 1); m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = len; /* enqueue for later when the lock can be released */ IF_ENQUEUE(&ue->ue_rxq, m); return (0); }
static void cdce_ncm_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) { struct cdce_softc *sc = usbd_xfer_softc(xfer); struct ifnet *ifp = uether_getifp(&sc->sc_ue); uint16_t x; uint8_t temp; int actlen; int aframes; switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); DPRINTFN(10, "transfer complete: " "%u bytes in %u frames\n", actlen, aframes); case USB_ST_SETUP: for (x = 0; x != CDCE_NCM_TX_FRAMES_MAX; x++) { temp = cdce_ncm_fill_tx_frames(xfer, x); if (temp == 0) break; if (temp == 1) { x++; break; } } if (x != 0) { #ifdef USB_DEBUG usbd_xfer_set_interval(xfer, cdce_tx_interval); #endif usbd_xfer_set_frames(xfer, x); usbd_transfer_submit(xfer); } break; default: /* Error */ DPRINTFN(10, "Transfer error: %s\n", usbd_errstr(error)); /* update error counter */ if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); if (error != USB_ERR_CANCELLED) { if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST) { /* try to clear stall first */ usbd_xfer_set_stall(xfer); usbd_xfer_set_frames(xfer, 0); usbd_transfer_submit(xfer); } } break; } }
static void ue_ifmedia_task(struct usb_proc_msg *_task) { struct usb_ether_cfg_task *task = (struct usb_ether_cfg_task *)_task; struct usb_ether *ue = task->ue; struct ifnet *ifp = uether_getifp(ue); ue->ue_methods->ue_mii_upd(ifp); }
static void ue_tick_task(struct usb_proc_msg *_task) { struct usb_ether_cfg_task *task = (struct usb_ether_cfg_task *)_task; struct usb_ether *ue = task->ue; struct ifnet *ifp = uether_getifp(ue); if ((ifp->if_flags & IFF_RUNNING) == 0) return; ue->ue_methods->ue_tick(ue); }
static void ue_watchdog(void *arg) { struct usb_ether *ue = arg; struct ifnet *ifp = uether_getifp(ue); if ((ifp->if_flags & IFF_RUNNING) == 0) return; ue_queue_command(ue, ue_tick_task, &ue->ue_tick_task[0].hdr, &ue->ue_tick_task[1].hdr); usb_callout_reset(&ue->ue_watchdog, hz, ue_watchdog, ue); }
static void ipheth_init(struct usb_ether *ue) { struct ipheth_softc *sc = uether_getsc(ue); struct ifnet *ifp = uether_getifp(ue); IPHETH_LOCK_ASSERT(sc, MA_OWNED); ifp->if_drv_flags |= IFF_DRV_RUNNING; /* stall data write direction, which depends on USB mode */ usbd_xfer_set_stall(sc->sc_xfer[IPHETH_BULK_TX]); /* start data transfers */ ipheth_start(ue); }
int uether_rxmbuf(struct usb_ether *ue, struct mbuf *m, unsigned int len) { struct ifnet *ifp = uether_getifp(ue); UE_LOCK_ASSERT(ue); /* finalize mbuf */ IFNET_STAT_INC(ifp, ipackets, 1); m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = len; /* enqueue for later when the lock can be released */ IF_ENQUEUE(&ue->ue_rxq, m); return (0); }
static void cdce_stop(struct usb_ether *ue) { struct cdce_softc *sc = uether_getsc(ue); struct ifnet *ifp = uether_getifp(ue); CDCE_LOCK_ASSERT(sc, MA_OWNED); ifp->if_drv_flags &= ~IFF_DRV_RUNNING; /* * stop all the transfers, if not already stopped: */ usbd_transfer_stop(sc->sc_xfer[CDCE_BULK_RX]); usbd_transfer_stop(sc->sc_xfer[CDCE_BULK_TX]); usbd_transfer_stop(sc->sc_xfer[CDCE_INTR_RX]); usbd_transfer_stop(sc->sc_xfer[CDCE_INTR_TX]); }
static void ue_start_task(struct usb_proc_msg *_task) { struct usb_ether_cfg_task *task = (struct usb_ether_cfg_task *)_task; struct usb_ether *ue = task->ue; struct ifnet *ifp = uether_getifp(ue); UE_LOCK_ASSERT(ue); ue->ue_methods->ue_init(ue); if ((ifp->if_flags & IFF_RUNNING) == 0) return; if (ue->ue_methods->ue_tick != NULL) usb_callout_reset(&ue->ue_watchdog, hz, ue_watchdog, ue); }
static void cdce_init(struct usb_ether *ue) { struct cdce_softc *sc = uether_getsc(ue); struct ifnet *ifp = uether_getifp(ue); CDCE_LOCK_ASSERT(sc, MA_OWNED); ifp->if_drv_flags |= IFF_DRV_RUNNING; /* start interrupt transfer */ usbd_transfer_start(sc->sc_xfer[CDCE_INTR_RX]); usbd_transfer_start(sc->sc_xfer[CDCE_INTR_TX]); /* stall data write direction, which depends on USB mode */ usbd_xfer_set_stall(sc->sc_xfer[CDCE_BULK_TX]); /* start data transfers */ cdce_start(ue); }
void uether_rxflush(struct usb_ether *ue) { struct ifnet *ifp = uether_getifp(ue); struct mbuf *m; UE_LOCK_ASSERT(ue); for (;;) { IF_DEQUEUE(&ue->ue_rxq, m); if (m == NULL) break; /* * The USB xfer has been resubmitted so its safe to unlock now. */ UE_UNLOCK(ue); ifp->if_input(ifp, m, NULL, -1); UE_LOCK(ue); } }
void uether_ifdetach(struct usb_ether *ue) { struct ifnet *ifp; /* wait for any post attach or other command to complete */ usb_proc_drain(&ue->ue_tq); /* read "ifnet" pointer after taskqueue drain */ ifp = uether_getifp(ue); if (ifp != NULL) { /* we are not running any more */ UE_LOCK(ue); ifp->if_flags &= ~IFF_RUNNING; UE_UNLOCK(ue); /* drain any callouts */ usb_callout_drain(&ue->ue_watchdog); /* detach miibus */ if (ue->ue_miibus != NULL) { device_delete_child(ue->ue_dev, ue->ue_miibus); } /* detach ethernet */ ether_ifdetach(ifp); /* free sysctl */ sysctl_ctx_free(&ue->ue_sysctl_ctx); /* free unit */ devfs_clone_bitmap_put(&DEVFS_CLONE_BITMAP(ue), ue->ue_unit); } /* free taskqueue, if any */ usb_proc_free(&ue->ue_tq); }
static void cdce_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) { struct cdce_softc *sc = usbd_xfer_softc(xfer); struct ifnet *ifp = uether_getifp(&sc->sc_ue); struct mbuf *m; struct mbuf *mt; uint32_t crc; uint8_t x; int actlen, aframes; usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); DPRINTFN(1, "\n"); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: DPRINTFN(11, "transfer complete: %u bytes in %u frames\n", actlen, aframes); ifp->if_opackets++; /* free all previous TX buffers */ cdce_free_queue(sc->sc_tx_buf, CDCE_FRAMES_MAX); /* FALLTHROUGH */ case USB_ST_SETUP: tr_setup: for (x = 0; x != CDCE_FRAMES_MAX; x++) { IFQ_DRV_DEQUEUE(&ifp->if_snd, m); if (m == NULL) break; if (sc->sc_flags & CDCE_FLAG_ZAURUS) { /* * Zaurus wants a 32-bit CRC appended * to every frame */ crc = cdce_m_crc32(m, 0, m->m_pkthdr.len); crc = htole32(crc); if (!m_append(m, 4, (void *)&crc)) { m_freem(m); ifp->if_oerrors++; continue; } } if (m->m_len != m->m_pkthdr.len) { mt = m_defrag(m, M_DONTWAIT); if (mt == NULL) { m_freem(m); ifp->if_oerrors++; continue; } m = mt; } if (m->m_pkthdr.len > MCLBYTES) { m->m_pkthdr.len = MCLBYTES; } sc->sc_tx_buf[x] = m; usbd_xfer_set_frame_data(xfer, x, m->m_data, m->m_len); /* * If there's a BPF listener, bounce a copy of * this frame to him: */ BPF_MTAP(ifp, m); } if (x != 0) { usbd_xfer_set_frames(xfer, x); usbd_transfer_submit(xfer); } break; default: /* Error */ DPRINTFN(11, "transfer error, %s\n", usbd_errstr(error)); /* free all previous TX buffers */ cdce_free_queue(sc->sc_tx_buf, CDCE_FRAMES_MAX); /* count output errors */ ifp->if_oerrors++; if (error != USB_ERR_CANCELLED) { /* try to clear stall first */ usbd_xfer_set_stall(xfer); goto tr_setup; } break; } }
static void cdce_ncm_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) { struct cdce_softc *sc = usbd_xfer_softc(xfer); struct usb_page_cache *pc = usbd_xfer_get_frame(xfer, 0); struct ifnet *ifp = uether_getifp(&sc->sc_ue); struct mbuf *m; int sumdata; int sumlen; int actlen; int aframes; int temp; int nframes; int x; int offset; switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: usbd_xfer_status(xfer, &actlen, &sumlen, &aframes, NULL); DPRINTFN(1, "received %u bytes in %u frames\n", actlen, aframes); if (actlen < (sizeof(sc->sc_ncm.hdr) + sizeof(sc->sc_ncm.dpt))) { DPRINTFN(1, "frame too short\n"); goto tr_setup; } usbd_copy_out(pc, 0, &(sc->sc_ncm.hdr), sizeof(sc->sc_ncm.hdr)); if ((sc->sc_ncm.hdr.dwSignature[0] != 'N') || (sc->sc_ncm.hdr.dwSignature[1] != 'C') || (sc->sc_ncm.hdr.dwSignature[2] != 'M') || (sc->sc_ncm.hdr.dwSignature[3] != 'H')) { DPRINTFN(1, "invalid HDR signature: " "0x%02x:0x%02x:0x%02x:0x%02x\n", sc->sc_ncm.hdr.dwSignature[0], sc->sc_ncm.hdr.dwSignature[1], sc->sc_ncm.hdr.dwSignature[2], sc->sc_ncm.hdr.dwSignature[3]); goto tr_stall; } temp = UGETW(sc->sc_ncm.hdr.wBlockLength); if (temp > sumlen) { DPRINTFN(1, "unsupported block length %u/%u\n", temp, sumlen); goto tr_stall; } temp = UGETW(sc->sc_ncm.hdr.wDptIndex); if ((temp + sizeof(sc->sc_ncm.dpt)) > actlen) { DPRINTFN(1, "invalid DPT index: 0x%04x\n", temp); goto tr_stall; } usbd_copy_out(pc, temp, &(sc->sc_ncm.dpt), sizeof(sc->sc_ncm.dpt)); if ((sc->sc_ncm.dpt.dwSignature[0] != 'N') || (sc->sc_ncm.dpt.dwSignature[1] != 'C') || (sc->sc_ncm.dpt.dwSignature[2] != 'M') || (sc->sc_ncm.dpt.dwSignature[3] != '0')) { DPRINTFN(1, "invalid DPT signature" "0x%02x:0x%02x:0x%02x:0x%02x\n", sc->sc_ncm.dpt.dwSignature[0], sc->sc_ncm.dpt.dwSignature[1], sc->sc_ncm.dpt.dwSignature[2], sc->sc_ncm.dpt.dwSignature[3]); goto tr_stall; } nframes = UGETW(sc->sc_ncm.dpt.wLength) / 4; /* Subtract size of header and last zero padded entry */ if (nframes >= (2 + 1)) nframes -= (2 + 1); else nframes = 0; DPRINTFN(1, "nframes = %u\n", nframes); temp += sizeof(sc->sc_ncm.dpt); if ((temp + (4 * nframes)) > actlen) goto tr_stall; if (nframes > CDCE_NCM_SUBFRAMES_MAX) { DPRINTFN(1, "Truncating number of frames from %u to %u\n", nframes, CDCE_NCM_SUBFRAMES_MAX); nframes = CDCE_NCM_SUBFRAMES_MAX; } usbd_copy_out(pc, temp, &(sc->sc_ncm.dp), (4 * nframes)); sumdata = 0; for (x = 0; x != nframes; x++) { offset = UGETW(sc->sc_ncm.dp[x].wFrameIndex); temp = UGETW(sc->sc_ncm.dp[x].wFrameLength); if ((offset == 0) || (temp < sizeof(struct ether_header)) || (temp > (MCLBYTES - ETHER_ALIGN))) { DPRINTFN(1, "NULL frame detected at %d\n", x); m = NULL; /* silently ignore this frame */ continue; } else if ((offset + temp) > actlen) { DPRINTFN(1, "invalid frame " "detected at %d\n", x); m = NULL; /* silently ignore this frame */ continue; } else if (temp > (MHLEN - ETHER_ALIGN)) { m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); } else { m = m_gethdr(M_DONTWAIT, MT_DATA); } DPRINTFN(16, "frame %u, offset = %u, length = %u \n", x, offset, temp); /* check if we have a buffer */ if (m) { m_adj(m, ETHER_ALIGN); usbd_copy_out(pc, offset, m->m_data, temp); /* enqueue */ uether_rxmbuf(&sc->sc_ue, m, temp); sumdata += temp; } else { ifp->if_ierrors++; } } DPRINTFN(1, "Efficiency: %u/%u bytes\n", sumdata, actlen); case USB_ST_SETUP: tr_setup: usbd_xfer_set_frame_len(xfer, 0, sc->sc_ncm.rx_max); usbd_xfer_set_frames(xfer, 1); usbd_transfer_submit(xfer); uether_rxflush(&sc->sc_ue); /* must be last */ break; default: /* Error */ DPRINTFN(1, "error = %s\n", usbd_errstr(error)); if (error != USB_ERR_CANCELLED) { tr_stall: /* try to clear stall first */ usbd_xfer_set_stall(xfer); usbd_xfer_set_frames(xfer, 0); usbd_transfer_submit(xfer); } break; } }
static uint8_t cdce_ncm_fill_tx_frames(struct usb_xfer *xfer, uint8_t index) { struct cdce_softc *sc = usbd_xfer_softc(xfer); struct ifnet *ifp = uether_getifp(&sc->sc_ue); struct usb_page_cache *pc = usbd_xfer_get_frame(xfer, index); struct mbuf *m; uint32_t rem; uint32_t offset; uint32_t last_offset; uint16_t n; uint8_t retval; usbd_xfer_set_frame_offset(xfer, index * CDCE_NCM_TX_MAXLEN, index); offset = sizeof(sc->sc_ncm.hdr) + sizeof(sc->sc_ncm.dpt) + sizeof(sc->sc_ncm.dp); /* Store last valid offset before alignment */ last_offset = offset; /* Align offset */ offset = CDCE_NCM_ALIGN(sc->sc_ncm.tx_remainder, offset, sc->sc_ncm.tx_modulus); /* Zero pad */ cdce_ncm_tx_zero(pc, last_offset, offset); /* buffer full */ retval = 2; for (n = 0; n != sc->sc_ncm.tx_nframe; n++) { /* check if end of transmit buffer is reached */ if (offset >= sc->sc_ncm.tx_max) break; /* compute maximum buffer size */ rem = sc->sc_ncm.tx_max - offset; IFQ_DRV_DEQUEUE(&(ifp->if_snd), m); if (m == NULL) { /* buffer not full */ retval = 1; break; } if (m->m_pkthdr.len > rem) { if (n == 0) { /* The frame won't fit in our buffer */ DPRINTFN(1, "Frame too big to be transmitted!\n"); m_freem(m); ifp->if_oerrors++; n--; continue; } /* Wait till next buffer becomes ready */ IFQ_DRV_PREPEND(&(ifp->if_snd), m); break; } usbd_m_copy_in(pc, offset, m, 0, m->m_pkthdr.len); USETW(sc->sc_ncm.dp[n].wFrameLength, m->m_pkthdr.len); USETW(sc->sc_ncm.dp[n].wFrameIndex, offset); /* Update offset */ offset += m->m_pkthdr.len; /* Store last valid offset before alignment */ last_offset = offset; /* Align offset */ offset = CDCE_NCM_ALIGN(sc->sc_ncm.tx_remainder, offset, sc->sc_ncm.tx_modulus); /* Zero pad */ cdce_ncm_tx_zero(pc, last_offset, offset); /* * If there's a BPF listener, bounce a copy * of this frame to him: */ BPF_MTAP(ifp, m); /* Free mbuf */ m_freem(m); /* Pre-increment interface counter */ ifp->if_opackets++; } if (n == 0) return (0); rem = (sizeof(sc->sc_ncm.dpt) + (4 * n) + 4); USETW(sc->sc_ncm.dpt.wLength, rem); /* zero the rest of the data pointer entries */ for (; n != CDCE_NCM_SUBFRAMES_MAX; n++) { USETW(sc->sc_ncm.dp[n].wFrameLength, 0); USETW(sc->sc_ncm.dp[n].wFrameIndex, 0); } offset = last_offset; /* Align offset */ offset = CDCE_NCM_ALIGN(0, offset, CDCE_NCM_TX_MINLEN); /* Optimise, save bandwidth and force short termination */ if (offset >= sc->sc_ncm.tx_max) offset = sc->sc_ncm.tx_max; else offset ++; /* Zero pad */ cdce_ncm_tx_zero(pc, last_offset, offset); /* set frame length */ usbd_xfer_set_frame_len(xfer, index, offset); /* Fill out 16-bit header */ sc->sc_ncm.hdr.dwSignature[0] = 'N'; sc->sc_ncm.hdr.dwSignature[1] = 'C'; sc->sc_ncm.hdr.dwSignature[2] = 'M'; sc->sc_ncm.hdr.dwSignature[3] = 'H'; USETW(sc->sc_ncm.hdr.wHeaderLength, sizeof(sc->sc_ncm.hdr)); USETW(sc->sc_ncm.hdr.wBlockLength, offset); USETW(sc->sc_ncm.hdr.wSequence, sc->sc_ncm.tx_seq); USETW(sc->sc_ncm.hdr.wDptIndex, sizeof(sc->sc_ncm.hdr)); sc->sc_ncm.tx_seq++; /* Fill out 16-bit frame table header */ sc->sc_ncm.dpt.dwSignature[0] = 'N'; sc->sc_ncm.dpt.dwSignature[1] = 'C'; sc->sc_ncm.dpt.dwSignature[2] = 'M'; sc->sc_ncm.dpt.dwSignature[3] = '0'; USETW(sc->sc_ncm.dpt.wNextNdpIndex, 0); /* reserved */ usbd_copy_in(pc, 0, &(sc->sc_ncm.hdr), sizeof(sc->sc_ncm.hdr)); usbd_copy_in(pc, sizeof(sc->sc_ncm.hdr), &(sc->sc_ncm.dpt), sizeof(sc->sc_ncm.dpt)); usbd_copy_in(pc, sizeof(sc->sc_ncm.hdr) + sizeof(sc->sc_ncm.dpt), &(sc->sc_ncm.dp), sizeof(sc->sc_ncm.dp)); return (retval); }
static void ipheth_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) { struct ipheth_softc *sc = usbd_xfer_softc(xfer); struct ifnet *ifp = uether_getifp(&sc->sc_ue); struct usb_page_cache *pc; struct mbuf *m; uint8_t x; int actlen; int aframes; usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); DPRINTFN(1, "\n"); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: DPRINTFN(11, "transfer complete: %u bytes in %u frames\n", actlen, aframes); ifp->if_opackets++; /* free all previous TX buffers */ ipheth_free_queue(sc->sc_tx_buf, IPHETH_TX_FRAMES_MAX); /* FALLTHROUGH */ case USB_ST_SETUP: tr_setup: for (x = 0; x != IPHETH_TX_FRAMES_MAX; x++) { IFQ_DRV_DEQUEUE(&ifp->if_snd, m); if (m == NULL) break; usbd_xfer_set_frame_offset(xfer, x * IPHETH_BUF_SIZE, x); pc = usbd_xfer_get_frame(xfer, x); sc->sc_tx_buf[x] = m; if (m->m_pkthdr.len > IPHETH_BUF_SIZE) m->m_pkthdr.len = IPHETH_BUF_SIZE; usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len); usbd_xfer_set_frame_len(xfer, x, IPHETH_BUF_SIZE); if (IPHETH_BUF_SIZE != m->m_pkthdr.len) { usbd_frame_zero(pc, m->m_pkthdr.len, IPHETH_BUF_SIZE - m->m_pkthdr.len); } /* * If there's a BPF listener, bounce a copy of * this frame to him: */ BPF_MTAP(ifp, m); } if (x != 0) { usbd_xfer_set_frames(xfer, x); usbd_transfer_submit(xfer); } break; default: /* Error */ DPRINTFN(11, "transfer error, %s\n", usbd_errstr(error)); /* free all previous TX buffers */ ipheth_free_queue(sc->sc_tx_buf, IPHETH_TX_FRAMES_MAX); /* count output errors */ ifp->if_oerrors++; if (error != USB_ERR_CANCELLED) { /* try to clear stall first */ usbd_xfer_set_stall(xfer); goto tr_setup; } break; } }
static void ue_attach_post_task(struct usb_proc_msg *_task) { struct usb_ether_cfg_task *task = (struct usb_ether_cfg_task *)_task; struct usb_ether *ue = task->ue; struct ifnet *ifp = uether_getifp(ue); int error; char num[14]; /* sufficient for 32 bits */ /* first call driver's post attach routine */ ue->ue_methods->ue_attach_post(ue); UE_UNLOCK(ue); KKASSERT(!lockowned(ue->ue_lock)); ue->ue_unit = devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(ue), 0); usb_callout_init_mtx(&ue->ue_watchdog, ue->ue_lock, 0); sysctl_ctx_init(&ue->ue_sysctl_ctx); KKASSERT(!lockowned(ue->ue_lock)); error = 0; ifp->if_softc = ue; if_initname(ifp, "ue", ue->ue_unit); if (ue->ue_methods->ue_attach_post_sub != NULL) { error = ue->ue_methods->ue_attach_post_sub(ue); KKASSERT(!lockowned(ue->ue_lock)); } else { ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; if (ue->ue_methods->ue_ioctl != NULL) ifp->if_ioctl = ue->ue_methods->ue_ioctl; else ifp->if_ioctl = uether_ioctl; ifp->if_start = ue_start; ifp->if_init = ue_init; ifq_set_maxlen(&ifp->if_snd, ifqmaxlen); ifq_set_ready(&ifp->if_snd); if (ue->ue_methods->ue_mii_upd != NULL && ue->ue_methods->ue_mii_sts != NULL) { error = mii_phy_probe(ue->ue_dev, &ue->ue_miibus, ue_ifmedia_upd, ue->ue_methods->ue_mii_sts); } } if (error) { device_printf(ue->ue_dev, "attaching PHYs failed\n"); goto fail; } if_printf(ifp, "<USB Ethernet> on %s\n", device_get_nameunit(ue->ue_dev)); ether_ifattach(ifp, ue->ue_eaddr, NULL); /* Tell upper layer we support VLAN oversized frames. */ if (ifp->if_capabilities & IFCAP_VLAN_MTU) ifp->if_hdrlen = sizeof(struct ether_vlan_header); ksnprintf(num, sizeof(num), "%u", ue->ue_unit); ue->ue_sysctl_oid = SYSCTL_ADD_NODE(&ue->ue_sysctl_ctx, &SYSCTL_NODE_CHILDREN(_net, ue), OID_AUTO, num, CTLFLAG_RD, NULL, ""); SYSCTL_ADD_PROC(&ue->ue_sysctl_ctx, SYSCTL_CHILDREN(ue->ue_sysctl_oid), OID_AUTO, "%parent", CTLTYPE_STRING | CTLFLAG_RD, ue, 0, ue_sysctl_parent, "A", "parent device"); KKASSERT(!lockowned(ue->ue_lock)); UE_LOCK(ue); return; fail: devfs_clone_bitmap_put(&DEVFS_CLONE_BITMAP(ue), ue->ue_unit); UE_LOCK(ue); return; }