823 lines
23 KiB
C
823 lines
23 KiB
C
/*++
|
||
|
||
Copyright (c) 1989, 1990, 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
rcveng.c
|
||
|
||
Abstract:
|
||
|
||
This module contains code that implements the receive engine for the
|
||
Jetbeui transport provider. This code is responsible for the following
|
||
basic activities:
|
||
|
||
1. Transitioning a TdiReceive request from an inactive state on the
|
||
connection's ReceiveQueue to the active state on that connection
|
||
(ActivateReceive).
|
||
|
||
2. Advancing the status of the active receive request by copying 0 or
|
||
more bytes of data from an incoming DATA_FIRST_MIDDLE or DATA_ONLY_LAST
|
||
NBF frame.
|
||
|
||
3. Completing receive requests.
|
||
|
||
Author:
|
||
|
||
David Beaver (dbeaver) 1-July-1991
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
|
||
|
||
VOID
|
||
ActivateReceive(
|
||
PTP_CONNECTION Connection
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine activates the next TdiReceive request on the specified
|
||
connection object if there is no active request on that connection
|
||
already. This allows the request to accept data on the connection.
|
||
|
||
NOTE: THIS FUNCTION MUST BE CALLED AT DPC LEVEL.
|
||
|
||
Arguments:
|
||
|
||
Connection - Pointer to a TP_CONNECTION object.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
PIRP Irp;
|
||
|
||
ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
|
||
|
||
IF_NBFDBG (NBF_DEBUG_RCVENG) {
|
||
NbfPrint0 (" ActivateReceive: Entered.\n");
|
||
}
|
||
|
||
//
|
||
// The ACTIVE_RECEIVE bitflag will be set on the connection if
|
||
// the receive-fields in the CONNECTION object are valid. If
|
||
// this flag is cleared, then we try to make the next TdiReceive
|
||
// request in the ReceiveQueue the active request.
|
||
//
|
||
|
||
ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
|
||
if (!(Connection->Flags & CONNECTION_FLAGS_ACTIVE_RECEIVE)) {
|
||
if (!IsListEmpty (&Connection->ReceiveQueue)) {
|
||
|
||
//
|
||
// Found a receive, so make it the active one.
|
||
//
|
||
|
||
Connection->Flags |= CONNECTION_FLAGS_ACTIVE_RECEIVE;
|
||
|
||
Irp = CONTAINING_RECORD(
|
||
Connection->ReceiveQueue.Flink,
|
||
IRP,
|
||
Tail.Overlay.ListEntry);
|
||
Connection->MessageBytesReceived = 0;
|
||
Connection->MessageBytesAcked = 0;
|
||
Connection->MessageInitAccepted = 0;
|
||
Connection->CurrentReceiveIrp = Irp;
|
||
Connection->CurrentReceiveSynchronous =
|
||
Connection->Provider->MacInfo.SingleReceive;
|
||
Connection->CurrentReceiveMdl = Irp->MdlAddress;
|
||
Connection->ReceiveLength = IRP_RECEIVE_LENGTH(IoGetCurrentIrpStackLocation(Irp));
|
||
Connection->ReceiveByteOffset = 0;
|
||
}
|
||
}
|
||
RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
|
||
IF_NBFDBG (NBF_DEBUG_RCVENG) {
|
||
NbfPrint0 (" ActivateReceive: Exiting.\n");
|
||
}
|
||
} /* ActivateReceive */
|
||
|
||
|
||
VOID
|
||
AwakenReceive(
|
||
PTP_CONNECTION Connection
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to reactivate a sleeping connection with the
|
||
RECEIVE_WAKEUP bitflag set because data arrived for which no receive
|
||
was available. The caller has made a receive available at the connection,
|
||
so here we activate the next receive, and send the appropriate protocol
|
||
to restart the message at the first byte offset past the one received
|
||
by the last receive.
|
||
|
||
NOTE: THIS FUNCTION MUST BE CALLED AT DPC LEVEL. IT IS CALLED
|
||
WITH CONNECTION->LINKSPINLOCK HELD.
|
||
|
||
Arguments:
|
||
|
||
Connection - Pointer to a TP_CONNECTION object.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
IF_NBFDBG (NBF_DEBUG_RCVENG) {
|
||
NbfPrint0 (" AwakenReceive: Entered.\n");
|
||
}
|
||
|
||
//
|
||
// If the RECEIVE_WAKEUP bitflag is set, then awaken the connection.
|
||
//
|
||
|
||
if (Connection->Flags & CONNECTION_FLAGS_RECEIVE_WAKEUP) {
|
||
if (Connection->ReceiveQueue.Flink != &Connection->ReceiveQueue) {
|
||
Connection->Flags &= ~CONNECTION_FLAGS_RECEIVE_WAKEUP;
|
||
|
||
//
|
||
// Found a receive, so turn off the wakeup flag, activate
|
||
// the next receive, and send the protocol.
|
||
//
|
||
|
||
//
|
||
// Quick fix: So there is no window where a receive
|
||
// is active but the bit is not on (otherwise we could
|
||
// accept whatever data happens to show up in the
|
||
// interim).
|
||
//
|
||
|
||
Connection->Flags |= CONNECTION_FLAGS_W_RESYNCH;
|
||
|
||
NbfReferenceConnection ("temp AwakenReceive", Connection, CREF_BY_ID); // release lookup hold.
|
||
|
||
RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
|
||
|
||
ActivateReceive (Connection);
|
||
|
||
//
|
||
// What if this fails? The successful queueing
|
||
// of a RCV_O should cause ActivateReceive to be called.
|
||
//
|
||
// NOTE: Send this after ActivateReceive, since that
|
||
// is where the MessageBytesAcked/Received variables
|
||
// are initialized.
|
||
//
|
||
|
||
NbfSendReceiveOutstanding (Connection);
|
||
|
||
IF_NBFDBG (NBF_DEBUG_RCVENG) {
|
||
NbfPrint0 (" AwakenReceive: Returned from NbfSendReceive.\n");
|
||
}
|
||
|
||
NbfDereferenceConnection("temp AwakenReceive", Connection, CREF_BY_ID);
|
||
return;
|
||
}
|
||
}
|
||
RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
|
||
} /* AwakenReceive */
|
||
|
||
|
||
VOID
|
||
CompleteReceive(
|
||
PTP_CONNECTION Connection,
|
||
BOOLEAN EndOfMessage,
|
||
IN ULONG BytesTransferred
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called by ProcessIncomingData when the current receive
|
||
must be completed. Depending on whether the current frame being
|
||
processed is a DATA_FIRST_MIDDLE or DATA_ONLY_LAST, and also whether
|
||
all of the data was processed, the EndOfMessage flag will be set accordingly
|
||
by the caller to indicate that a message boundary was received.
|
||
|
||
NOTE: THIS FUNCTION MUST BE CALLED AT DPC LEVEL.
|
||
|
||
Arguments:
|
||
|
||
Connection - Pointer to a TP_CONNECTION object.
|
||
|
||
EndOfMessage - BOOLEAN set to true if TDI_END_OF_RECORD should be reported.
|
||
|
||
BytesTransferred - Number of bytes copied in this receive.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
PLIST_ENTRY p;
|
||
PIRP Irp;
|
||
ULONG BytesReceived;
|
||
PIO_STACK_LOCATION IrpSp;
|
||
|
||
IF_NBFDBG (NBF_DEBUG_RCVENG) {
|
||
NbfPrint0 (" CompleteReceive: Entered.\n");
|
||
}
|
||
|
||
|
||
if (Connection->SpecialReceiveIrp) {
|
||
|
||
PIRP Irp = Connection->SpecialReceiveIrp;
|
||
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
Irp->IoStatus.Information = BytesTransferred;
|
||
|
||
ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
|
||
|
||
Connection->Flags |= CONNECTION_FLAGS_RC_PENDING;
|
||
Connection->Flags &= ~CONNECTION_FLAGS_ACTIVE_RECEIVE;
|
||
Connection->SpecialReceiveIrp = FALSE;
|
||
|
||
++Connection->ReceivedTsdus;
|
||
|
||
ExInterlockedInsertHeadList(
|
||
&Connection->Provider->IrpCompletionQueue,
|
||
&Irp->Tail.Overlay.ListEntry,
|
||
Connection->ProviderInterlock);
|
||
|
||
//
|
||
// NOTE: NbfAcknowledgeDataOnlyLast releases
|
||
// the connection spinlock.
|
||
//
|
||
|
||
NbfAcknowledgeDataOnlyLast(
|
||
Connection,
|
||
Connection->MessageBytesReceived
|
||
);
|
||
|
||
} else {
|
||
KIRQL cancelIrql;
|
||
|
||
if (EndOfMessage) {
|
||
|
||
//
|
||
// The messages has been completely received, ack it.
|
||
//
|
||
// We set DEFERRED_ACK and DEFERRED_NOT_Q here, which
|
||
// will cause an ack to be piggybacked if any data is
|
||
// sent during the call to CompleteReceive. If this
|
||
// does not happen, then we will call AcknowledgeDataOnlyLast
|
||
// which will will send a DATA ACK or queue a request for
|
||
// a piggyback ack. We do this *after* calling CompleteReceive
|
||
// so we know that we will complete the receive back to
|
||
// the client before we ack the data, to prevent the
|
||
// next receive from being sent before this one is
|
||
// completed.
|
||
//
|
||
|
||
IoAcquireCancelSpinLock(&cancelIrql);
|
||
ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
|
||
|
||
Connection->DeferredFlags |=
|
||
(CONNECTION_FLAGS_DEFERRED_ACK | CONNECTION_FLAGS_DEFERRED_NOT_Q);
|
||
Connection->Flags |= CONNECTION_FLAGS_RC_PENDING;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Send a receive outstanding (even though we don't
|
||
// know that we have a receive) to get him to
|
||
// reframe his send. Pre-2.0 clients require a
|
||
// no receive before the receive outstanding.
|
||
//
|
||
// what if this fails (due to no send packets)?
|
||
//
|
||
|
||
if ((Connection->Flags & CONNECTION_FLAGS_VERSION2) == 0) {
|
||
NbfSendNoReceive (Connection);
|
||
}
|
||
NbfSendReceiveOutstanding (Connection);
|
||
|
||
//
|
||
// If there is a receive posted, make it current and
|
||
// send a receive outstanding.
|
||
//
|
||
// need general function for this, which sends NO_RECEIVE if appropriate.
|
||
//
|
||
|
||
ActivateReceive (Connection);
|
||
|
||
IoAcquireCancelSpinLock(&cancelIrql);
|
||
ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
|
||
|
||
}
|
||
|
||
//
|
||
// If we indicated to the client, adjust this down by the
|
||
// amount of data taken, when it hits zero we can reindicate.
|
||
//
|
||
|
||
if (Connection->ReceiveBytesUnaccepted) {
|
||
if (Connection->MessageBytesReceived >= Connection->ReceiveBytesUnaccepted) {
|
||
Connection->ReceiveBytesUnaccepted = 0;
|
||
} else {
|
||
Connection->ReceiveBytesUnaccepted -= Connection->MessageBytesReceived;
|
||
}
|
||
}
|
||
|
||
//
|
||
// NOTE: The connection lock is held here.
|
||
//
|
||
|
||
if (IsListEmpty (&Connection->ReceiveQueue)) {
|
||
|
||
ASSERT ((Connection->Flags2 & CONNECTION_FLAGS2_STOPPING) != 0);
|
||
|
||
//
|
||
// Release the cancel spinlock out of order. Since we were
|
||
// already at DPC level when it was acquired, there is no
|
||
// need to swap irqls.
|
||
//
|
||
ASSERT(cancelIrql == DISPATCH_LEVEL);
|
||
IoReleaseCancelSpinLock(cancelIrql);
|
||
|
||
} else {
|
||
|
||
Connection->Flags &= ~CONNECTION_FLAGS_ACTIVE_RECEIVE;
|
||
BytesReceived = Connection->MessageBytesReceived;
|
||
|
||
|
||
//
|
||
// Complete the TdiReceive request at the head of the
|
||
// connection's ReceiveQueue.
|
||
//
|
||
|
||
IF_NBFDBG (NBF_DEBUG_RCVENG) {
|
||
NbfPrint0 (" CompleteReceive: Normal IRP is present.\n");
|
||
}
|
||
|
||
p = RemoveHeadList (&Connection->ReceiveQueue);
|
||
Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
|
||
|
||
IoSetCancelRoutine(Irp, NULL);
|
||
|
||
//
|
||
// Release the cancel spinlock out of order. Since we were
|
||
// already at DPC level when it was acquired, there is no
|
||
// need to swap irqls.
|
||
//
|
||
ASSERT(cancelIrql == DISPATCH_LEVEL);
|
||
IoReleaseCancelSpinLock(cancelIrql);
|
||
|
||
//
|
||
// If this request should generate no back traffic, then
|
||
// disable piggyback acks for it.
|
||
//
|
||
|
||
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||
if (IRP_RECEIVE_FLAGS(IrpSp) & TDI_RECEIVE_NO_RESPONSE_EXP) {
|
||
Connection->CurrentReceiveAckQueueable = FALSE;
|
||
}
|
||
|
||
#if DBG
|
||
NbfCompletedReceives[NbfCompletedReceivesNext].Irp = Irp;
|
||
NbfCompletedReceives[NbfCompletedReceivesNext].Request = NULL;
|
||
NbfCompletedReceives[NbfCompletedReceivesNext].Status =
|
||
EndOfMessage ? STATUS_SUCCESS : STATUS_BUFFER_OVERFLOW;
|
||
{
|
||
ULONG i,j,k;
|
||
PUCHAR va;
|
||
PMDL mdl;
|
||
|
||
mdl = Irp->MdlAddress;
|
||
|
||
if (BytesReceived > TRACK_TDI_CAPTURE) {
|
||
NbfCompletedReceives[NbfCompletedReceivesNext].Contents[0] = 0xFF;
|
||
} else {
|
||
NbfCompletedReceives[NbfCompletedReceivesNext].Contents[0] = (UCHAR)BytesReceived;
|
||
}
|
||
|
||
i = 1;
|
||
while (i<TRACK_TDI_CAPTURE) {
|
||
if (mdl == NULL) break;
|
||
va = MmGetSystemAddressForMdl (mdl);
|
||
j = MmGetMdlByteCount (mdl);
|
||
|
||
for (i=i,k=0;(i<TRACK_TDI_CAPTURE)&&(k<j);i++,k++) {
|
||
NbfCompletedReceives[NbfCompletedReceivesNext].Contents[i] = *va++;
|
||
}
|
||
mdl = mdl->Next;
|
||
}
|
||
}
|
||
|
||
NbfCompletedReceivesNext = (NbfCompletedReceivesNext++) % TRACK_TDI_LIMIT;
|
||
#endif
|
||
++Connection->ReceivedTsdus;
|
||
|
||
//
|
||
// This can be called with locks held.
|
||
//
|
||
NbfCompleteReceiveIrp(
|
||
Irp,
|
||
EndOfMessage ? STATUS_SUCCESS : STATUS_BUFFER_OVERFLOW,
|
||
BytesReceived);
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// If NOT_Q is still set, that means that the deferred ack was
|
||
// not satisfied by anything resulting from the call to
|
||
// CompleteReceive, so we need to ack or queue an ack here.
|
||
//
|
||
|
||
|
||
if ((Connection->DeferredFlags & CONNECTION_FLAGS_DEFERRED_NOT_Q) != 0) {
|
||
|
||
Connection->DeferredFlags &=
|
||
~(CONNECTION_FLAGS_DEFERRED_ACK | CONNECTION_FLAGS_DEFERRED_NOT_Q);
|
||
|
||
//
|
||
// NOTE: NbfAcknowledgeDataOnlyLast releases
|
||
// the connection spinlock.
|
||
//
|
||
|
||
NbfAcknowledgeDataOnlyLast(
|
||
Connection,
|
||
Connection->MessageBytesReceived
|
||
);
|
||
|
||
} else {
|
||
|
||
RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
} /* CompleteReceive */
|
||
|
||
|
||
VOID
|
||
NbfCancelReceive(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called by the I/O system to cancel a receive.
|
||
The receive is found on the connection's receive queue; if it
|
||
is the current request it is cancelled and the connection
|
||
goes into "cancelled receive" mode, otherwise it is cancelled
|
||
silently.
|
||
|
||
In "cancelled receive" mode the connection makes it appear to
|
||
the remote the data is being received, but in fact it is not
|
||
indicated to the transport or buffered on our end
|
||
|
||
NOTE: This routine is called with the CancelSpinLock held and
|
||
is responsible for releasing it.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to the device object for this driver.
|
||
|
||
Irp - Pointer to the request packet representing the I/O request.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
KIRQL oldirql;
|
||
PIO_STACK_LOCATION IrpSp;
|
||
PIRP ReceiveIrp;
|
||
PTP_CONNECTION Connection;
|
||
PLIST_ENTRY p;
|
||
ULONG BytesReceived;
|
||
BOOLEAN Found;
|
||
|
||
UNREFERENCED_PARAMETER (DeviceObject);
|
||
|
||
//
|
||
// Get a pointer to the current stack location in the IRP. This is where
|
||
// the function codes and parameters are stored.
|
||
//
|
||
|
||
IrpSp = IoGetCurrentIrpStackLocation (Irp);
|
||
|
||
ASSERT ((IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
|
||
(IrpSp->MinorFunction == TDI_RECEIVE));
|
||
|
||
Connection = IrpSp->FileObject->FsContext;
|
||
|
||
//
|
||
// Since this IRP is still in the cancellable state, we know
|
||
// that the connection is still around (although it may be in
|
||
// the process of being torn down).
|
||
//
|
||
|
||
//
|
||
// See if this is the IRP for the current receive request.
|
||
//
|
||
|
||
ACQUIRE_SPIN_LOCK (Connection->LinkSpinLock, &oldirql);
|
||
|
||
BytesReceived = Connection->MessageBytesReceived;
|
||
|
||
p = Connection->ReceiveQueue.Flink;
|
||
|
||
//
|
||
// If there is a receive active and it is not a special
|
||
// IRP, then see if this is it.
|
||
//
|
||
|
||
if (((Connection->Flags & CONNECTION_FLAGS_ACTIVE_RECEIVE) != 0) &&
|
||
(!Connection->SpecialReceiveIrp)) {
|
||
|
||
ReceiveIrp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
|
||
|
||
if (ReceiveIrp == Irp) {
|
||
|
||
//
|
||
// yes, it is the active receive. Turn on the RCV_CANCELLED
|
||
// bit instructing the connection to drop the rest of the
|
||
// data received (until the DOL comes in).
|
||
//
|
||
|
||
Connection->Flags |= CONNECTION_FLAGS_RCV_CANCELLED;
|
||
Connection->Flags &= ~CONNECTION_FLAGS_ACTIVE_RECEIVE;
|
||
|
||
(VOID)RemoveHeadList (&Connection->ReceiveQueue);
|
||
|
||
#if DBG
|
||
NbfCompletedReceives[NbfCompletedReceivesNext].Irp = ReceiveIrp;
|
||
NbfCompletedReceives[NbfCompletedReceivesNext].Request = NULL;
|
||
NbfCompletedReceives[NbfCompletedReceivesNext].Status = STATUS_CANCELLED;
|
||
{
|
||
ULONG i,j,k;
|
||
PUCHAR va;
|
||
PMDL mdl;
|
||
|
||
mdl = ReceiveIrp->MdlAddress;
|
||
|
||
if (BytesReceived > TRACK_TDI_CAPTURE) {
|
||
NbfCompletedReceives[NbfCompletedReceivesNext].Contents[0] = 0xFF;
|
||
} else {
|
||
NbfCompletedReceives[NbfCompletedReceivesNext].Contents[0] = (UCHAR)BytesReceived;
|
||
}
|
||
|
||
i = 1;
|
||
while (i<TRACK_TDI_CAPTURE) {
|
||
if (mdl == NULL) break;
|
||
va = MmGetSystemAddressForMdl (mdl);
|
||
j = MmGetMdlByteCount (mdl);
|
||
|
||
for (i=i,k=0;(i<TRACK_TDI_CAPTURE)&&(k<j);i++,k++) {
|
||
NbfCompletedReceives[NbfCompletedReceivesNext].Contents[i] = *va++;
|
||
}
|
||
mdl = mdl->Next;
|
||
}
|
||
}
|
||
|
||
NbfCompletedReceivesNext = (NbfCompletedReceivesNext++) % TRACK_TDI_LIMIT;
|
||
#endif
|
||
|
||
RELEASE_SPIN_LOCK (Connection->LinkSpinLock, oldirql);
|
||
IoReleaseCancelSpinLock (Irp->CancelIrql);
|
||
|
||
#if DBG
|
||
DbgPrint("NBF: Canceled in-progress receive %lx on %lx\n",
|
||
Irp, Connection);
|
||
#endif
|
||
|
||
//
|
||
// The following dereference will complete the I/O, provided removes
|
||
// the last reference on the request object. The I/O will complete
|
||
// with the status and information stored in the Irp. Therefore,
|
||
// we set those values here before the dereference.
|
||
//
|
||
|
||
NbfCompleteReceiveIrp (ReceiveIrp, STATUS_CANCELLED, 0);
|
||
return;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// If we fall through to here, the IRP was not the active receive.
|
||
// Scan through the list, looking for this IRP.
|
||
//
|
||
|
||
Found = FALSE;
|
||
|
||
while (p != &Connection->ReceiveQueue) {
|
||
|
||
ReceiveIrp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
|
||
if (ReceiveIrp == Irp) {
|
||
|
||
//
|
||
// Found it, remove it from the list here.
|
||
//
|
||
|
||
RemoveEntryList (p);
|
||
|
||
Found = TRUE;
|
||
|
||
#if DBG
|
||
NbfCompletedReceives[NbfCompletedReceivesNext].Irp = ReceiveIrp;
|
||
NbfCompletedReceives[NbfCompletedReceivesNext].Request = NULL;
|
||
NbfCompletedReceives[NbfCompletedReceivesNext].Status = STATUS_CANCELLED;
|
||
{
|
||
ULONG i,j,k;
|
||
PUCHAR va;
|
||
PMDL mdl;
|
||
|
||
mdl = ReceiveIrp->MdlAddress;
|
||
|
||
if (BytesReceived > TRACK_TDI_CAPTURE) {
|
||
NbfCompletedReceives[NbfCompletedReceivesNext].Contents[0] = 0xFF;
|
||
} else {
|
||
NbfCompletedReceives[NbfCompletedReceivesNext].Contents[0] = (UCHAR)BytesReceived;
|
||
}
|
||
|
||
i = 1;
|
||
while (i<TRACK_TDI_CAPTURE) {
|
||
if (mdl == NULL) break;
|
||
va = MmGetSystemAddressForMdl (mdl);
|
||
j = MmGetMdlByteCount (mdl);
|
||
|
||
for (i=i,k=0;(i<TRACK_TDI_CAPTURE)&&(k<j);i++,k++) {
|
||
NbfCompletedReceives[NbfCompletedReceivesNext].Contents[i] = *va++;
|
||
}
|
||
mdl = mdl->Next;
|
||
}
|
||
}
|
||
|
||
NbfCompletedReceivesNext = (NbfCompletedReceivesNext++) % TRACK_TDI_LIMIT;
|
||
#endif
|
||
|
||
RELEASE_SPIN_LOCK (Connection->LinkSpinLock, oldirql);
|
||
IoReleaseCancelSpinLock (Irp->CancelIrql);
|
||
|
||
#if DBG
|
||
DbgPrint("NBF: Canceled receive %lx on %lx\n",
|
||
ReceiveIrp, Connection);
|
||
#endif
|
||
|
||
//
|
||
// The following dereference will complete the I/O, provided removes
|
||
// the last reference on the request object. The I/O will complete
|
||
// with the status and information stored in the Irp. Therefore,
|
||
// we set those values here before the dereference.
|
||
//
|
||
|
||
NbfCompleteReceiveIrp (ReceiveIrp, STATUS_CANCELLED, 0);
|
||
break;
|
||
|
||
}
|
||
|
||
p = p->Flink;
|
||
|
||
}
|
||
|
||
if (!Found) {
|
||
|
||
//
|
||
// We didn't find it!
|
||
//
|
||
|
||
#if DBG
|
||
DbgPrint("NBF: Tried to cancel receive %lx on %lx, not found\n",
|
||
Irp, Connection);
|
||
#endif
|
||
RELEASE_SPIN_LOCK (Connection->LinkSpinLock, oldirql);
|
||
IoReleaseCancelSpinLock (Irp->CancelIrql);
|
||
}
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
NbfCancelReceiveDatagram(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called by the I/O system to cancel a receive
|
||
datagram. The receive is looked for on the address file's
|
||
receive datagram queue; if it is found it is cancelled.
|
||
|
||
NOTE: This routine is called with the CancelSpinLock held and
|
||
is responsible for releasing it.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to the device object for this driver.
|
||
|
||
Irp - Pointer to the request packet representing the I/O request.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
KIRQL oldirql;
|
||
PIO_STACK_LOCATION IrpSp;
|
||
PTP_ADDRESS_FILE AddressFile;
|
||
PTP_ADDRESS Address;
|
||
PLIST_ENTRY p;
|
||
BOOLEAN Found;
|
||
|
||
UNREFERENCED_PARAMETER (DeviceObject);
|
||
|
||
//
|
||
// Get a pointer to the current stack location in the IRP. This is where
|
||
// the function codes and parameters are stored.
|
||
//
|
||
|
||
IrpSp = IoGetCurrentIrpStackLocation (Irp);
|
||
|
||
ASSERT ((IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
|
||
(IrpSp->MinorFunction == TDI_RECEIVE_DATAGRAM));
|
||
|
||
AddressFile = IrpSp->FileObject->FsContext;
|
||
Address = AddressFile->Address;
|
||
|
||
//
|
||
// Since this IRP is still in the cancellable state, we know
|
||
// that the address file is still around (although it may be in
|
||
// the process of being torn down). See if the IRP is on the list.
|
||
//
|
||
|
||
Found = FALSE;
|
||
|
||
ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
|
||
|
||
for (p = AddressFile->ReceiveDatagramQueue.Flink;
|
||
p != &AddressFile->ReceiveDatagramQueue;
|
||
p = p->Flink) {
|
||
|
||
if (CONTAINING_RECORD(p, IRP, Tail.Overlay.ListEntry) == Irp) {
|
||
RemoveEntryList (p);
|
||
Found = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
|
||
IoReleaseCancelSpinLock (Irp->CancelIrql);
|
||
|
||
if (Found) {
|
||
|
||
#if DBG
|
||
DbgPrint("NBF: Canceled receive datagram %lx on %lx\n",
|
||
Irp, AddressFile);
|
||
#endif
|
||
|
||
Irp->IoStatus.Information = 0;
|
||
Irp->IoStatus.Status = STATUS_CANCELLED;
|
||
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
|
||
|
||
NbfDereferenceAddress ("Receive DG cancelled", Address, AREF_REQUEST);
|
||
|
||
} else {
|
||
|
||
#if DBG
|
||
DbgPrint("NBF: Tried to cancel receive datagram %lx on %lx, not found\n",
|
||
Irp, AddressFile);
|
||
#endif
|
||
|
||
}
|
||
|
||
} /* NbfCancelReceiveDatagram */
|
||
|