Avoid sleeping with mutex held in kern_ndis.c.

Remove unused fields from ndis_miniport_block.

Fix a bug in KeFlushQueuedDpcs() (we weren't calculating the kq pointer
correctly).

In if_ndis.c, clear the IFF_RUNNING flag before calling ndis_halt_nic().

Add some guards in kern_ndis.c to avoid letting anyone invoke ndis_get_info()
or ndis_set_info() if the NIC isn't fully initialized. Apparently, mdnsd
will sometimes try to invoke the ndis_ioctl() routine at exactly the
wrong moment (to futz with its multicast filters) when the interface
comes up, and can trigger a crash unless we guard against it.
This commit is contained in:
Bill Paul 2005-05-05 06:14:59 +00:00
parent 5514ba90b2
commit eb31d50cc7
4 changed files with 34 additions and 37 deletions

View File

@ -838,8 +838,6 @@ ndis_set_info(arg, oid, buf, buflen)
sc = arg;
mtx_lock(&ndis_req_mtx);
KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
if (sc->ndis_block->nmb_pendingreq != NULL)
@ -847,16 +845,20 @@ ndis_set_info(arg, oid, buf, buflen)
else
sc->ndis_block->nmb_pendingreq = (ndis_request *)sc;
NDIS_LOCK(sc);
setfunc = sc->ndis_chars->nmc_setinfo_func;
adapter = sc->ndis_block->nmb_miniportadapterctx;
if (adapter == NULL || setfunc == NULL) {
if (adapter == NULL || setfunc == NULL ||
sc->ndis_block->nmb_devicectx == NULL) {
sc->ndis_block->nmb_pendingreq = NULL;
NDIS_UNLOCK(sc);
KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
mtx_unlock(&ndis_req_mtx);
return(ENXIO);
}
NDIS_UNLOCK(sc);
rval = MSCALL6(setfunc, adapter, oid, buf, *buflen,
&byteswritten, &bytesneeded);
@ -865,13 +867,13 @@ ndis_set_info(arg, oid, buf, buflen)
KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
if (rval == NDIS_STATUS_PENDING) {
mtx_lock(&ndis_req_mtx);
error = msleep(&sc->ndis_block->nmb_setstat,
&ndis_req_mtx,
curthread->td_priority|PDROP,
"ndisset", 5 * hz);
rval = sc->ndis_block->nmb_setstat;
} else
mtx_unlock(&ndis_req_mtx);
}
if (byteswritten)
@ -1044,20 +1046,22 @@ ndis_reset_nic(arg)
ndis_handle adapter;
ndis_reset_handler resetfunc;
uint8_t addressing_reset;
struct ifnet *ifp;
int rval;
uint8_t irql;
sc = arg;
ifp = &sc->arpcom.ac_if;
NDIS_LOCK(sc);
adapter = sc->ndis_block->nmb_miniportadapterctx;
resetfunc = sc->ndis_chars->nmc_reset_func;
if (adapter == NULL || resetfunc == NULL)
if (adapter == NULL || resetfunc == NULL ||
sc->ndis_block->nmb_devicectx == NULL) {
NDIS_UNLOCK(sc);
return(EIO);
}
mtx_lock(&ndis_req_mtx);
NDIS_UNLOCK(sc);
if (NDIS_SERIALIZED(sc->ndis_block))
KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
@ -1068,10 +1072,10 @@ ndis_reset_nic(arg)
KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
if (rval == NDIS_STATUS_PENDING) {
mtx_lock(&ndis_req_mtx);
msleep(sc, &ndis_req_mtx,
curthread->td_priority|PDROP, "ndisrst", 0);
} else
mtx_unlock(&ndis_req_mtx);
}
return(0);
}
@ -1085,14 +1089,11 @@ ndis_halt_nic(arg)
struct ndis_softc *sc;
ndis_handle adapter;
ndis_halt_handler haltfunc;
struct ifnet *ifp;
#ifdef NDIS_REAP_TIMERS
ndis_miniport_timer *t, *n;
uint8_t irql;
#endif
sc = arg;
ifp = &sc->arpcom.ac_if;
NDIS_LOCK(sc);
adapter = sc->ndis_block->nmb_miniportadapterctx;
@ -1101,6 +1102,8 @@ ndis_halt_nic(arg)
return(EIO);
}
sc->ndis_block->nmb_devicectx = NULL;
#ifdef NDIS_REAP_TIMERS
/*
* Drivers are sometimes very lax about cancelling all
@ -1110,7 +1113,6 @@ ndis_halt_nic(arg)
* the timers reside will no longer be valid.
*/
KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
t = sc->ndis_block->nmb_timerlist;
while (t != NULL) {
KeCancelTimer(&t->nmt_ktimer);
@ -1119,7 +1121,6 @@ ndis_halt_nic(arg)
n->nmt_nexttimer = NULL;
}
sc->ndis_block->nmb_timerlist = NULL;
KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
KeFlushQueuedDpcs();
#endif
@ -1132,9 +1133,7 @@ ndis_halt_nic(arg)
haltfunc = sc->ndis_chars->nmc_halt_func;
NDIS_UNLOCK(sc);
mtx_lock(&ndis_req_mtx);
MSCALL1(haltfunc, adapter);
mtx_unlock(&ndis_req_mtx);
NDIS_LOCK(sc);
sc->ndis_block->nmb_miniportadapterctx = NULL;
@ -1194,10 +1193,8 @@ ndis_init_nic(arg)
for (i = 0; i < NdisMediumMax; i++)
mediumarray[i] = i;
mtx_lock(&ndis_req_mtx);
status = MSCALL6(initfunc, &openstatus, &chosenmedium,
mediumarray, NdisMediumMax, block, block);
mtx_unlock(&ndis_req_mtx);
/*
* If the init fails, blow away the other exported routines
@ -1223,6 +1220,10 @@ ndis_init_nic(arg)
ndis_thsuspend(curthread->td_proc, NULL, hz);
NDIS_LOCK(sc);
sc->ndis_block->nmb_devicectx = sc;
NDIS_UNLOCK(sc);
return(0);
}
@ -1340,7 +1341,7 @@ ndis_get_info(arg, oid, buf, buflen)
uint8_t irql;
sc = arg;
mtx_lock(&ndis_req_mtx);
KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
if (sc->ndis_block->nmb_pendingreq != NULL)
@ -1348,16 +1349,20 @@ ndis_get_info(arg, oid, buf, buflen)
else
sc->ndis_block->nmb_pendingreq = (ndis_request *)sc;
NDIS_LOCK(sc);
queryfunc = sc->ndis_chars->nmc_queryinfo_func;
adapter = sc->ndis_block->nmb_miniportadapterctx;
if (adapter == NULL || queryfunc == NULL) {
if (adapter == NULL || queryfunc == NULL ||
sc->ndis_block->nmb_devicectx == NULL) {
sc->ndis_block->nmb_pendingreq = NULL;
NDIS_UNLOCK(sc);
KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
mtx_unlock(&ndis_req_mtx);
return(ENXIO);
}
NDIS_UNLOCK(sc);
rval = MSCALL6(queryfunc, adapter, oid, buf, *buflen,
&byteswritten, &bytesneeded);
@ -1368,13 +1373,13 @@ ndis_get_info(arg, oid, buf, buflen)
/* Wait for requests that block. */
if (rval == NDIS_STATUS_PENDING) {
mtx_lock(&ndis_req_mtx);
error = msleep(&sc->ndis_block->nmb_getstat,
&ndis_req_mtx,
curthread->td_priority|PDROP,
"ndisget", 5 * hz);
rval = sc->ndis_block->nmb_getstat;
} else
mtx_unlock(&ndis_req_mtx);
}
if (byteswritten)
*buflen = byteswritten;

View File

@ -1476,19 +1476,12 @@ struct ndis_miniport_block {
* End of windows-specific portion of miniport block. Everything
* below is BSD-specific.
*/
struct ifnet *nmb_ifp;
uint8_t nmb_dummybuf[128];
device_object nmb_devobj;
ndis_config_parm nmb_replyparm;
int nmb_pciidx;
device_t nmb_dev;
ndis_resource_list *nmb_rlist;
ndis_status nmb_getstat;
ndis_status nmb_setstat;
vm_offset_t nmb_img;
ndis_miniport_timer *nmb_timerlist;
io_workitem *nmb_workitems[NUMBER_OF_SINGLE_WORK_ITEMS];
int nmb_item_idx;
TAILQ_ENTRY(ndis_miniport_block) link;
};

View File

@ -3108,9 +3108,8 @@ KeFlushQueuedDpcs(void)
* for them to drain.
*/
kq = kq_queues;
for (i = 0; i < mp_ncpus; i++) {
kq += i;
kq = kq_queues + i;
KeSetEvent(&kq->kq_proc, 0, FALSE);
KeWaitForSingleObject((nt_dispatch_header *)&kq->kq_done,
0, 0, TRUE, NULL);

View File

@ -2768,14 +2768,14 @@ ndis_stop(sc)
ifp = &sc->arpcom.ac_if;
untimeout(ndis_tick, sc, sc->ndis_stat_ch);
ndis_halt_nic(sc);
NDIS_LOCK(sc);
ifp->if_timer = 0;
sc->ndis_link = 0;
ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
NDIS_UNLOCK(sc);
ndis_halt_nic(sc);
return;
}