summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/nbf/rcveng.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/ntos/tdi/nbf/rcveng.c823
1 files changed, 823 insertions, 0 deletions
diff --git a/private/ntos/tdi/nbf/rcveng.c b/private/ntos/tdi/nbf/rcveng.c
new file mode 100644
index 000000000..f3b3eab33
--- /dev/null
+++ b/private/ntos/tdi/nbf/rcveng.c
@@ -0,0 +1,823 @@
+/*++
+
+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);
+
+ //
+ // BUGBUG: 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.
+ //
+ // BUGBUG: 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.
+ //
+ // BUGBUG: 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 */
+