diff options
-rw-r--r-- | sys/compat/ndis/subr_ndis.c | 1 | ||||
-rw-r--r-- | sys/dev/if_ndis/if_ndis.c | 123 |
2 files changed, 124 insertions, 0 deletions
diff --git a/sys/compat/ndis/subr_ndis.c b/sys/compat/ndis/subr_ndis.c index 80f5180..8543c8d 100644 --- a/sys/compat/ndis/subr_ndis.c +++ b/sys/compat/ndis/subr_ndis.c @@ -472,6 +472,7 @@ ndis_setattr_ex(adapter_handle, adapter_ctx, hangsecs, block = (ndis_miniport_block *)adapter_handle; block->nmb_miniportadapterctx = adapter_ctx; block->nmb_checkforhangsecs = hangsecs; + block->nmb_flags = flags; return(NDIS_STATUS_SUCCESS); } diff --git a/sys/dev/if_ndis/if_ndis.c b/sys/dev/if_ndis/if_ndis.c index e9edb8b..929f793 100644 --- a/sys/dev/if_ndis/if_ndis.c +++ b/sys/dev/if_ndis/if_ndis.c @@ -86,10 +86,14 @@ int ndis_suspend (device_t); int ndis_resume (device_t); void ndis_shutdown (device_t); +static void ndis_serial_input (void *); + static __stdcall void ndis_txeof (ndis_handle, ndis_packet *, ndis_status); static __stdcall void ndis_rxeof (ndis_handle, ndis_packet **, uint32_t); +static __stdcall void ndis_rxeof_serial (ndis_handle, + ndis_packet **, uint32_t); static __stdcall void ndis_linksts (ndis_handle, ndis_status, void *, uint32_t); static __stdcall void ndis_linksts_done (ndis_handle); @@ -411,6 +415,14 @@ ndis_attach(dev) goto fail; } + /* + * Check to see if this driver is deserialized or + * not. If not, we need to do use a special serialized + * receive handler. + */ + if (!(sc->ndis_block.nmb_flags & NDIS_ATTRIBUTE_DESERIALIZE)) + sc->ndis_block.nmb_pktind_func = ndis_rxeof_serial; + /* Reset the adapter. */ ndis_reset_nic(sc); @@ -835,6 +847,15 @@ ndis_rxeof(adapter, packets, pktcnt) } else { if (p->np_oob.npo_status == NDIS_STATUS_RESOURCES) { m = m_dup(m0, M_DONTWAIT); + /* + * NOTE: we want to destroy the mbuf here, but + * we don't actually want to return it to the + * driver via the return packet handler. By + * bumping np_refcnt, we can prevent the + * ndis_return_packet() routine from actually + * doing anything. + */ + p->np_refcnt++; m_freem(m0); if (m == NULL) ifp->if_ierrors++; @@ -872,6 +893,108 @@ ndis_rxeof(adapter, packets, pktcnt) return; } +static void +ndis_serial_input(arg) + void *arg; +{ + struct mbuf *m; + struct ifnet *ifp; + + m = arg; + ifp = m->m_pkthdr.rcvif; + (*ifp->if_input)(ifp, m); + + return; +} + +/* + * Special receive handler for serialized miniports. To really serialize + * things, we have to make sure not to try and return packets to the driver + * until after this routine returns. The best way to do that is put the + * call to (*ifp->if_input)() on the ndis swi work queue. In theory, + * we could also copy the packet. I'm not sure which is faster. + */ + +__stdcall static void +ndis_rxeof_serial(adapter, packets, pktcnt) + ndis_handle adapter; + ndis_packet **packets; + uint32_t pktcnt; +{ + struct ndis_softc *sc; + ndis_miniport_block *block; + ndis_packet *p; + uint32_t s; + ndis_tcpip_csum *csum; + struct ifnet *ifp; + struct mbuf *m0, *m; + int i; + + block = (ndis_miniport_block *)adapter; + sc = (struct ndis_softc *)(block->nmb_ifp); + ifp = block->nmb_ifp; + + for (i = 0; i < pktcnt; i++) { + p = packets[i]; + /* Stash the softc here so ptom can use it. */ + p->np_softc = sc; + if (ndis_ptom(&m0, p)) { + device_printf (sc->ndis_dev, "ptom failed\n"); + if (p->np_oob.npo_status == NDIS_STATUS_SUCCESS) + ndis_return_packet(sc, p); + } else { + if (p->np_oob.npo_status == NDIS_STATUS_RESOURCES) { + m = m_dup(m0, M_DONTWAIT); + /* + * NOTE: we want to destroy the mbuf here, but + * we don't actually want to return it to the + * driver via the return packet handler. By + * bumping np_refcnt, we can prevent the + * ndis_return_packet() routine from actually + * doing anything. + */ + p->np_refcnt++; + m_freem(m0); + if (m == NULL) + ifp->if_ierrors++; + else + m0 = m; + } else + p->np_oob.npo_status = NDIS_STATUS_PENDING; + m0->m_pkthdr.rcvif = ifp; + + /* Deal with checksum offload. */ + + if (ifp->if_capenable & IFCAP_RXCSUM && + p->np_ext.npe_info[ndis_tcpipcsum_info] != NULL) { + s = (uintptr_t) + p->np_ext.npe_info[ndis_tcpipcsum_info]; + csum = (ndis_tcpip_csum *)&s; + if (csum->u.ntc_rxflags & + NDIS_RXCSUM_IP_PASSED) + m0->m_pkthdr.csum_flags |= + CSUM_IP_CHECKED|CSUM_IP_VALID; + if (csum->u.ntc_rxflags & + (NDIS_RXCSUM_TCP_PASSED | + NDIS_RXCSUM_UDP_PASSED)) { + m0->m_pkthdr.csum_flags |= + CSUM_DATA_VALID|CSUM_PSEUDO_HDR; + m0->m_pkthdr.csum_data = 0xFFFF; + } + } + + if (ndis_sched(ndis_serial_input, m0, NDIS_SWI)) { + p->np_refcnt++; + m_freem(m0); + ifp->if_ierrors++; + p->np_oob.npo_status = NDIS_STATUS_SUCCESS; + } else + ifp->if_ipackets++; + } + } + + return; +} /* * A frame was downloaded to the chip. It's safe for us to clean up * the list buffers. |