📄 ndisbind.c
字号:
//
// Wait for any pending sends or requests on
// the binding to complete.
//
ndisprotWaitForPendingIO(pOpenContext, TRUE);
//
// Discard any queued receives.
//
ndisprotFlushReceiveQueue(pOpenContext);
//
// Close the binding now.
//
NPROT_INIT_EVENT(&pOpenContext->BindEvent);
DEBUGP(DL_INFO, ("ShutdownBinding: Closing OpenContext %p,"
" BindingHandle %p\n",
pOpenContext, pOpenContext->BindingHandle));
NdisCloseAdapter(&Status, pOpenContext->BindingHandle);
if (Status == NDIS_STATUS_PENDING)
{
NPROT_WAIT_EVENT(&pOpenContext->BindEvent, 0);
Status = pOpenContext->BindStatus;
}
NPROT_ASSERT(Status == NDIS_STATUS_SUCCESS);
pOpenContext->BindingHandle = NULL;
}
if (DoCloseBinding)
{
NPROT_ACQUIRE_LOCK(&pOpenContext->Lock);
NPROT_SET_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_IDLE);
NPROT_SET_FLAGS(pOpenContext->Flags, NUIOO_UNBIND_FLAGS, 0);
NPROT_RELEASE_LOCK(&pOpenContext->Lock);
}
//
// Remove it from the global list.
//
NPROT_ACQUIRE_LOCK(&Globals.GlobalLock);
NPROT_REMOVE_ENTRY_LIST(&pOpenContext->Link);
NPROT_RELEASE_LOCK(&Globals.GlobalLock);
//
// Free any other resources allocated for this bind.
//
ndisprotFreeBindResources(pOpenContext);
NPROT_DEREF_OPEN(pOpenContext); // Shutdown binding
}
while (FALSE);
}
VOID
ndisprotFreeBindResources(
IN PNDISPROT_OPEN_CONTEXT pOpenContext
)
/*++
Routine Description:
Free any resources set up for an NDIS binding.
Arguments:
pOpenContext - pointer to open context block
Return Value:
None
--*/
{
if (pOpenContext->SendPacketPool != NULL)
{
NdisFreePacketPool(pOpenContext->SendPacketPool);
pOpenContext->SendPacketPool = NULL;
}
if (pOpenContext->RecvPacketPool != NULL)
{
NdisFreePacketPool(pOpenContext->RecvPacketPool);
pOpenContext->RecvPacketPool = NULL;
}
if (pOpenContext->RecvBufferPool != NULL)
{
NdisFreeBufferPool(pOpenContext->RecvBufferPool);
pOpenContext->RecvBufferPool = NULL;
}
if (pOpenContext->SendBufferPool != NULL)
{
NdisFreeBufferPool(pOpenContext->SendBufferPool);
pOpenContext->SendBufferPool = NULL;
}
if (pOpenContext->DeviceName.Buffer != NULL)
{
NPROT_FREE_MEM(pOpenContext->DeviceName.Buffer);
pOpenContext->DeviceName.Buffer = NULL;
pOpenContext->DeviceName.Length =
pOpenContext->DeviceName.MaximumLength = 0;
}
if (pOpenContext->DeviceDescr.Buffer != NULL)
{
//
// this would have been allocated by NdisQueryAdpaterInstanceName.
//
NdisFreeMemory(pOpenContext->DeviceDescr.Buffer, 0, 0);
pOpenContext->DeviceDescr.Buffer = NULL;
}
}
VOID
ndisprotWaitForPendingIO(
IN PNDISPROT_OPEN_CONTEXT pOpenContext,
IN BOOLEAN DoCancelReads
)
/*++
Routine Description:
Utility function to wait for all outstanding I/O to complete
on an open context. It is assumed that the open context
won't go away while we are in this routine.
Arguments:
pOpenContext - pointer to open context structure
DoCancelReads - do we wait for pending reads to go away (and cancel them)?
Return Value:
None
--*/
{
NDIS_STATUS Status;
ULONG LoopCount;
ULONG PendingCount;
#ifdef NDIS51
//
// Wait for any pending sends or requests on the binding to complete.
//
for (LoopCount = 0; LoopCount < 60; LoopCount++)
{
Status = NdisQueryPendingIOCount(
pOpenContext->BindingHandle,
&PendingCount);
if ((Status != NDIS_STATUS_SUCCESS) ||
(PendingCount == 0))
{
break;
}
DEBUGP(DL_INFO, ("WaitForPendingIO: Open %p, %d pending I/O at NDIS\n",
pOpenContext, PendingCount));
NPROT_SLEEP(2);
}
NPROT_ASSERT(LoopCount < 60);
#endif // NDIS51
//
// Make sure any threads trying to send have finished.
//
for (LoopCount = 0; LoopCount < 60; LoopCount++)
{
if (pOpenContext->PendedSendCount == 0)
{
break;
}
DEBUGP(DL_WARN, ("WaitForPendingIO: Open %p, %d pended sends\n",
pOpenContext, pOpenContext->PendedSendCount));
NPROT_SLEEP(1);
}
NPROT_ASSERT(LoopCount < 60);
if (DoCancelReads)
{
//
// Wait for any pended reads to complete/cancel.
//
while (pOpenContext->PendedReadCount != 0)
{
DEBUGP(DL_INFO, ("WaitForPendingIO: Open %p, %d pended reads\n",
pOpenContext, pOpenContext->PendedReadCount));
//
// Cancel any pending reads.
//
ndisprotCancelPendingReads(pOpenContext);
NPROT_SLEEP(1);
}
}
}
VOID
ndisprotDoProtocolUnload(
VOID
)
/*++
Routine Description:
Utility routine to handle unload from the NDIS protocol side.
Arguments:
None
Return Value:
None
--*/
{
NDIS_HANDLE ProtocolHandle;
NDIS_STATUS Status;
DEBUGP(DL_INFO, ("ProtocolUnload: ProtocolHandle %lx\n",
Globals.NdisProtocolHandle));
if (Globals.NdisProtocolHandle != NULL)
{
ProtocolHandle = Globals.NdisProtocolHandle;
Globals.NdisProtocolHandle = NULL;
NdisDeregisterProtocol(
&Status,
ProtocolHandle
);
}
}
NDIS_STATUS
ndisprotDoRequest(
IN PNDISPROT_OPEN_CONTEXT pOpenContext,
IN NDIS_REQUEST_TYPE RequestType,
IN NDIS_OID Oid,
IN PVOID InformationBuffer,
IN ULONG InformationBufferLength,
OUT PULONG pBytesProcessed
)
/*++
Routine Description:
Utility routine that forms and sends an NDIS_REQUEST to the
miniport, waits for it to complete, and returns status
to the caller.
NOTE: this assumes that the calling routine ensures validity
of the binding handle until this returns.
Arguments:
pOpenContext - pointer to our open context
RequestType - NdisRequest[Set|Query]Information
Oid - the object being set/queried
InformationBuffer - data for the request
InformationBufferLength - length of the above
pBytesProcessed - place to return bytes read/written
Return Value:
Status of the set/query request
--*/
{
NDISPROT_REQUEST ReqContext;
PNDIS_REQUEST pNdisRequest = &ReqContext.Request;
NDIS_STATUS Status;
NPROT_INIT_EVENT(&ReqContext.ReqEvent);
pNdisRequest->RequestType = RequestType;
switch (RequestType)
{
case NdisRequestQueryInformation:
pNdisRequest->DATA.QUERY_INFORMATION.Oid = Oid;
pNdisRequest->DATA.QUERY_INFORMATION.InformationBuffer =
InformationBuffer;
pNdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength =
InformationBufferLength;
break;
case NdisRequestSetInformation:
pNdisRequest->DATA.SET_INFORMATION.Oid = Oid;
pNdisRequest->DATA.SET_INFORMATION.InformationBuffer =
InformationBuffer;
pNdisRequest->DATA.SET_INFORMATION.InformationBufferLength =
InformationBufferLength;
break;
default:
NPROT_ASSERT(FALSE);
break;
}
NdisRequest(&Status,
pOpenContext->BindingHandle,
pNdisRequest);
if (Status == NDIS_STATUS_PENDING)
{
NPROT_WAIT_EVENT(&ReqContext.ReqEvent, 0);
Status = ReqContext.Status;
}
if (Status == NDIS_STATUS_SUCCESS)
{
*pBytesProcessed = (RequestType == NdisRequestQueryInformation)?
pNdisRequest->DATA.QUERY_INFORMATION.BytesWritten:
pNdisRequest->DATA.SET_INFORMATION.BytesRead;
//
// The driver below should set the correct value to BytesWritten
// or BytesRead. But now, we just truncate the value to InformationBufferLength
//
if (*pBytesProcessed > InformationBufferLength)
{
*pBytesProcessed = InformationBufferLength;
}
}
return (Status);
}
NDIS_STATUS
ndisprotValidateOpenAndDoRequest(
IN PNDISPROT_OPEN_CONTEXT pOpenContext,
IN NDIS_REQUEST_TYPE RequestType,
IN NDIS_OID Oid,
IN PVOID InformationBuffer,
IN ULONG InformationBufferLength,
OUT PULONG pBytesProcessed,
IN BOOLEAN bWaitForPowerOn
)
/*++
Routine Description:
Utility routine to prevalidate and reference an open context
before calling ndisprotDoRequest. This routine makes sure
we have a valid binding.
Arguments:
pOpenContext - pointer to our open context
RequestType - NdisRequest[Set|Query]Information
Oid - the object being set/queried
InformationBuffer - data for the request
InformationBufferLength - length of the above
pBytesProcessed - place to return bytes read/written
bWaitForPowerOn - Wait for the device to be powered on if it isn't already.
Return Value:
Status of the set/query request
--*/
{
NDIS_STATUS Status;
do
{
if (pOpenContext == NULL)
{
DEBUGP(DL_WARN, ("ValidateOpenAndDoRequest: request on unassociated file object!\n"));
Status = NDIS_STATUS_INVALID_DATA;
break;
}
NPROT_STRUCT_ASSERT(pOpenContext, oc);
NPROT_ACQUIRE_LOCK(&pOpenContext->Lock);
//
// Proceed only if we have a binding.
//
if (!NPROT_TEST_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_ACTIVE))
{
NPROT_RELEASE_LOCK(&pOpenContext->Lock);
Status = NDIS_STATUS_INVALID_DATA;
break;
}
NPROT_ASSERT(pOpenContext->BindingHandle != NULL);
//
// Make sure that the binding does not go away until we
// are finished with the request.
//
NdisInterlockedIncrement((PLONG)&pOpenContext->PendedSendCount);
NPROT_RELEASE_LOCK(&pOpenContext->Lock);
if (bWaitForPowerOn)
{
//
// Wait for the device below to be powered up.
// We don't wait indefinitely here - this is to avoid
// a PROCESS_HAS_LOCKED_PAGES bugcheck that could happen
// if the calling process terminates, and this IRP doesn't
// complete within a reasonable time. An alternative would
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -