Sorry, David
I have mistake in statmement of my last post, the *binding handle* is indeed different with *binding context*.
So, as what you said, to avoid blindly using the *binding handle*, i think i should do some synchronization btw receive handler and MpHalt.
Add a *State* variable in PADAPT and a *SpinLock* to guard the *State*. Each time i enter recv handler, check binding state. if the binding state is IDLE (which means, unbinding is undergoing), abandon the packet. Note that all recv handler works at DISPATCH_LEVEL, so if the check is passed, NdisCloseAdapter will not get called in MPHalt() until recv handler return, so i can safely use the binding handle to NdisSend a packet in recv handler.
Is following code OK?
NDIS_STATUS
PtReceive(
IN NDIS_HANDLE ProtocolBindingContext,
…
)
{
PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
…
KeAcquireSpinLock( &pAdapt->SpinLock, &OldIrql);
if ( pAdapt->State != BINDING_STATE_ACTIVE) {
KeReleaseSpinLock( &pAdapt->SpinLock, OldIrql);
return NDIS_NOT_ACCEPT;
}
KeReleaseSpinLock( &pAdapt->SpinLock, OldIrql);
// actraully recv operation
// …
// send reply in PtReceive context.
NdisSend( &Status, pAdapt->BindingHandle, pPacket);
…
}
INT
PtReceivePacket(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET Packet
)
{
PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
…
KeAcquireSpinLock( &pAdapt->SpinLock, &OldIrql);
if ( pAdapt->State != BINDING_STATE_ACTIVE) {
KeReleaseSpinLock( &pAdapt->SpinLock, OldIrql);
return 0;
}
KeReleaseSpinLock( &pAdapt->SpinLock, OldIrql);
// actraully recv operation
// …
// send reply in PtReceive context.
NdisSend( &Status, pAdapt->BindingHandle, pPacket);
…
}
VOID
MPHalt(
IN NDIS_HANDLE MiniportAdapterContext
)
{
PADAPT pAdapt = (PADAPT)MiniportAdapterContext;
…
// set binding state to IDLE
KeAcquireSpinLock( &pAdapt->SpinLock, &OldIrql);
SET_BINDING_STATE( pAdapt, BINDING_STATE_IDLE);
KeReleaseSpinLock( &pAdapt->SpinLock, OldIrql);
…
//
// Make sure any threads trying to send have finished.
//
for (LoopCount = 0; LoopCount < 60; LoopCount++)
{
if ( (PendingCount = NdisPacketPoolUsage(pAdapt->SendPacketPoolHandle)) == 0)
{
break;
}
DBGPRINT((“%d pended sending, waiting …\n”, PendingCount));
_SLEEP(1);
}
ASSERT(LoopCount < 60);
//
// Make sure no outstanding recv operations.
//
for (LoopCount = 0; LoopCount < 60; LoopCount++)
{
if ( (PendingCount = NdisPacketPoolUsage(pAdapt->RecvPacketPoolHandle)) == 0)
{
break;
}
DBGPRINT((“%d pended recving, waiting …\n”, PendingCount));
_SLEEP(1);
}
ASSERT(LoopCount < 60);
…
//
// If we have a valid bind, close the miniport below the protocol
//
if (pAdapt->BindingHandle != NULL)
{
//
// Close the binding below. and wait for it to complete
//
NdisResetEvent(&pAdapt->Event);
NdisCloseAdapter(&Status, pAdapt->BindingHandle);
if (Status == NDIS_STATUS_PENDING)
{
NdisWaitEvent(&pAdapt->Event, 0);
Status = pAdapt->Status;
}
ASSERT (Status == NDIS_STATUS_SUCCESS);
pAdapt->BindingHandle = NULL;
}
//
// Before MiniportHalt routine is called, all binding btw. upper protocols and me
// have already been released, and after NdisCloseAdapter is called, all bindings
// btw. under NICs and me have already been released. Now, i’ll not recv any
// sending request from upper protocol, and i’ll not recv any recving request from
// below NICs, so now i can go ahead to release packet pool.
//
if (pAdapt->SendPacketPoolHandle != NULL)
{
ASSERT( 0 == NdisPacketPoolUsage(pAdapt->SendPacketPoolHandle));
NdisFreePacketPool(pAdapt->SendPacketPoolHandle);
}
if (pAdapt->RecvPacketPoolHandle != NULL)
{
ASSERT( 0 == NdisPacketPoolUsage(pAdapt->RecvPacketPoolHandle));
NdisFreePacketPool(pAdapt->RecvPacketPoolHandle);
}
NdisFreeMemory( pAdapt);
return;
}
ÇÀ×¢ÑÅ»¢Ãâ·ÑÓÊÏä-3.5GÈÝÁ¿£¬20M¸½¼þ£¡