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 void cdce_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) { struct cdce_softc *sc = usbd_xfer_softc(xfer); struct mbuf *m; uint8_t x; int actlen, aframes, len; usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: DPRINTF("received %u bytes in %u frames\n", actlen, aframes); for (x = 0; x != aframes; x++) { m = sc->sc_rx_buf[x]; sc->sc_rx_buf[x] = NULL; len = usbd_xfer_frame_len(xfer, x); /* Strip off CRC added by Zaurus, if any */ if ((sc->sc_flags & CDCE_FLAG_ZAURUS) && len >= 14) len -= 4; if (len < sizeof(struct ether_header)) { m_freem(m); continue; } /* queue up mbuf */ uether_rxmbuf(&sc->sc_ue, m, len); } /* FALLTHROUGH */ case USB_ST_SETUP: /* * TODO: Implement support for multi frame transfers, * when the USB hardware supports it. */ for (x = 0; x != 1; x++) { if (sc->sc_rx_buf[x] == NULL) { m = uether_newbuf(); if (m == NULL) goto tr_stall; sc->sc_rx_buf[x] = m; } else { m = sc->sc_rx_buf[x]; } usbd_xfer_set_frame_data(xfer, x, m->m_data, m->m_len); } /* set number of frames and start hardware */ usbd_xfer_set_frames(xfer, x); usbd_transfer_submit(xfer); /* flush any received frames */ uether_rxflush(&sc->sc_ue); break; default: /* Error */ DPRINTF("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; } /* need to free the RX-mbufs when we are cancelled */ cdce_free_queue(sc->sc_rx_buf, CDCE_FRAMES_MAX); break; } }
static void ipheth_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) { struct ipheth_softc *sc = usbd_xfer_softc(xfer); struct mbuf *m; uint8_t x; int actlen; int aframes; int len; usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: DPRINTF("received %u bytes in %u frames\n", actlen, aframes); for (x = 0; x != aframes; x++) { m = sc->sc_rx_buf[x]; sc->sc_rx_buf[x] = NULL; len = usbd_xfer_frame_len(xfer, x); if (len < (sizeof(struct ether_header) + IPHETH_RX_ADJ)) { m_freem(m); continue; } m_adj(m, IPHETH_RX_ADJ); /* queue up mbuf */ uether_rxmbuf(&sc->sc_ue, m, len - IPHETH_RX_ADJ); } /* FALLTHROUGH */ case USB_ST_SETUP: for (x = 0; x != IPHETH_RX_FRAMES_MAX; x++) { if (sc->sc_rx_buf[x] == NULL) { m = uether_newbuf(); if (m == NULL) goto tr_stall; /* cancel alignment for ethernet */ m_adj(m, ETHER_ALIGN); sc->sc_rx_buf[x] = m; } else { m = sc->sc_rx_buf[x]; } usbd_xfer_set_frame_data(xfer, x, m->m_data, m->m_len); } /* set number of frames and start hardware */ usbd_xfer_set_frames(xfer, x); usbd_transfer_submit(xfer); /* flush any received frames */ uether_rxflush(&sc->sc_ue); break; default: /* Error */ DPRINTF("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; } /* need to free the RX-mbufs when we are cancelled */ ipheth_free_queue(sc->sc_rx_buf, IPHETH_RX_FRAMES_MAX); break; } }