diff options
author | wpaul <wpaul@FreeBSD.org> | 2006-02-04 19:42:49 +0000 |
---|---|---|
committer | wpaul <wpaul@FreeBSD.org> | 2006-02-04 19:42:49 +0000 |
commit | 6861e36921baf8f75582b54208ee7f1e93f010cf (patch) | |
tree | e41bb0c06f079574642a7ba51f17c52571c2e5b9 /sys/dev | |
parent | 1f5e50bc4722f6ef14571e6030274a47d7c1ff5d (diff) | |
download | FreeBSD-src-6861e36921baf8f75582b54208ee7f1e93f010cf.zip FreeBSD-src-6861e36921baf8f75582b54208ee7f1e93f010cf.tar.gz |
When ndis_attach() runs, it has to very briefly initialize the card
in order to query the underlying Windows driver for the station address
and some other properties. There is a slim chance that the card may
receive a packet and indicate it up to us before ndis_attach() can call
ndis_halt_nic(). This is bad, because both the softc structure and
the ifnet structure aren't fully initialized yet: many pointers are
still NULL, so if we make it into ndis_rxeof(), we will panic.
To fix this, we need to do the following:
- Move the calls to IoAllocateWorkItem() to before the call to ndis_init_nic().
- Move the initialization of the RX DPC and status callback function pointers
to before ndis_init_nic() as well.
- Modify ndis_rxeof() to check if the IFF_DRV_RUNNING flag is set. If it
isn't, we return any supplied NDIS_PACKETs to the NIC without processing
them.
This fixes a crash than can occur when activating a wireless NIC in
close proximity to a very busy wireless network, reported by Ryan
Beasley (ryan%^$!ATgoddamnbastard-****!!!DOTorg.
MFC after: 3 days
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/if_ndis/if_ndis.c | 48 |
1 files changed, 34 insertions, 14 deletions
diff --git a/sys/dev/if_ndis/if_ndis.c b/sys/dev/if_ndis/if_ndis.c index 296d9a7..6532978 100644 --- a/sys/dev/if_ndis/if_ndis.c +++ b/sys/dev/if_ndis/if_ndis.c @@ -552,6 +552,21 @@ ndis_attach(dev) sc->ndis_block->nmb_ethrxdone_func = ndis_rxeof_done_wrap; sc->ndis_block->nmb_tdcond_func = ndis_rxeof_xfr_done_wrap; + /* Override the status handler so we can detect link changes. */ + sc->ndis_block->nmb_status_func = ndis_linksts_wrap; + sc->ndis_block->nmb_statusdone_func = ndis_linksts_done_wrap; + + /* Set up work item handlers. */ + sc->ndis_tickitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj); + sc->ndis_startitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj); + sc->ndis_resetitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj); + sc->ndis_inputitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj); + KeInitializeDpc(&sc->ndis_rxdpc, ndis_rxeof_xfr_wrap, sc->ndis_block); + + /* make sure drv flags are all cleared before initing the NIC. */ + + ifp->if_drv_flags = 0; + /* Call driver's init routine. */ if (ndis_init_nic(sc)) { device_printf (dev, "init handler failed\n"); @@ -902,18 +917,6 @@ got_crypto: ether_ifattach(ifp, eaddr); } - /* Override the status handler so we can detect link changes. */ - sc->ndis_block->nmb_status_func = ndis_linksts_wrap; - sc->ndis_block->nmb_statusdone_func = ndis_linksts_done_wrap; - - /* Set up work item handlers. */ - sc->ndis_tickitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj); - sc->ndis_startitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj); - sc->ndis_resetitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj); - sc->ndis_inputitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj); - KeInitializeDpc(&sc->ndis_rxdpc, ndis_rxeof_xfr_wrap, sc->ndis_block); - - fail: if (error) ndis_detach(dev); @@ -1317,6 +1320,23 @@ ndis_rxeof(adapter, packets, pktcnt) sc = device_get_softc(block->nmb_physdeviceobj->do_devext); ifp = sc->ifp; + /* + * There's a slim chance the driver may indicate some packets + * before we're completely ready to handle them. If we detect this, + * we need to return them to the miniport and ignore them. + */ + + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { + for (i = 0; i < pktcnt; i++) { + p = packets[i]; + if (p->np_oob.npo_status == NDIS_STATUS_SUCCESS) { + p->np_refcnt++; + ndis_return_packet(p, block); + } + } + return; + } + for (i = 0; i < pktcnt; i++) { p = packets[i]; /* Stash the softc here so ptom can use it. */ @@ -1324,7 +1344,7 @@ ndis_rxeof(adapter, packets, pktcnt) 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); + ndis_return_packet(p, block); } else { #ifdef notdef if (p->np_oob.npo_status == NDIS_STATUS_RESOURCES) { @@ -1380,7 +1400,7 @@ ndis_rxeof(adapter, packets, pktcnt) } KeAcquireSpinLockAtDpcLevel(&sc->ndis_rxlock); - _IF_ENQUEUE(&sc->ndis_rxqueue, m); + _IF_ENQUEUE(&sc->ndis_rxqueue, m0); KeReleaseSpinLockFromDpcLevel(&sc->ndis_rxlock); IoQueueWorkItem(sc->ndis_inputitem, (io_workitem_func)ndis_inputtask_wrap, |