diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/tdi/st/rcveng.c | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to 'private/ntos/tdi/st/rcveng.c')
-rw-r--r-- | private/ntos/tdi/st/rcveng.c | 383 |
1 files changed, 383 insertions, 0 deletions
diff --git a/private/ntos/tdi/st/rcveng.c b/private/ntos/tdi/st/rcveng.c new file mode 100644 index 000000000..8e104a954 --- /dev/null +++ b/private/ntos/tdi/st/rcveng.c @@ -0,0 +1,383 @@ +/*++ + +Copyright (c) 1989-1993 Microsoft Corporation + +Module Name: + + rcveng.c + +Abstract: + + This module contains code that implements the receive engine for the + Sample transport provider. + +Environment: + + Kernel mode + +Revision History: + +--*/ + +#include "st.h" + + +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. + +Arguments: + + Connection - Pointer to a TP_CONNECTION object. + +Return Value: + + none. + +--*/ + +{ + KIRQL oldirql; + PTP_REQUEST Request; + + // + // 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_SPIN_LOCK (&Connection->SpinLock, &oldirql); + 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; + + Request = CONTAINING_RECORD ( + Connection->ReceiveQueue.Flink, + TP_REQUEST, + Linkage); + Connection->MessageBytesReceived = 0; + Connection->MessageBytesAcked = 0; + Connection->CurrentReceiveRequest = Request; + Connection->CurrentReceiveMdl = Request->Buffer2; + Connection->ReceiveLength = Request->Buffer2Length; + Connection->ReceiveByteOffset = 0; + } + } + + RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); + +} /* 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. + +Arguments: + + Connection - Pointer to a TP_CONNECTION object. + +Return Value: + + none. + +--*/ + +{ + KIRQL oldirql; + + // + // If the RECEIVE_WAKEUP bitflag is set, then awaken the connection. + // + + ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql); + 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, and activate + // the next receive. + // + + RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); + ActivateReceive (Connection); + + return; + } + } + RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); +} /* AwakenReceive */ + + +VOID +CompleteReceive( + PTP_CONNECTION Connection, + BOOLEAN EndOfRecord, + KIRQL ConnectionIrql, + KIRQL CancelIrql + ) + +/*++ + +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 EndOfRecord flag will be set accordingly + by the caller to indicate that a message boundary was received. + + NOTE: This function is called with the connection and cancel + IRQLs held, and returns with them released. + +Arguments: + + Connection - Pointer to a TP_CONNECTION object. + + EndOfRecord - BOOLEAN set to true if TDI_END_OF_RECORD should be reported. + + ConnectionIrql - The IRQL at which the connection spinlock was acquired. + + CancelIrql - The IRQL at which the cancel spinlock was acquired. + +Return Value: + + none. + +--*/ + +{ + PLIST_ENTRY p; + PTP_REQUEST Request; + KIRQL oldirql = ConnectionIrql; + KIRQL cancelirql = CancelIrql; + ULONG BytesReceived; + + + if (IsListEmpty (&Connection->ReceiveQueue)) { + + ASSERT ((Connection->Flags & CONNECTION_FLAGS_STOPPING) != 0); + + RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); + IoReleaseCancelSpinLock(cancelirql); + return; + } + + Connection->Flags &= ~CONNECTION_FLAGS_ACTIVE_RECEIVE; + BytesReceived = Connection->MessageBytesReceived; + + + // + // Complete the TdiReceive request at the head of the + // connection's ReceiveQueue. + // + + p = RemoveHeadList (&Connection->ReceiveQueue); + Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage); + + Request->IoRequestPacket->CancelRoutine = (PDRIVER_CANCEL)NULL; + + RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); + IoReleaseCancelSpinLock(cancelirql); + + + Request->Flags |= REQUEST_FLAGS_DELAY; + + StCompleteRequest( + Request, + EndOfRecord ? STATUS_SUCCESS : STATUS_BUFFER_OVERFLOW, + BytesReceived); + +} /* CompleteReceive */ + + +VOID +StCancelReceive( + 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; + PTP_CONNECTION Connection; + PTP_REQUEST Request; + 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->SpinLock, &oldirql); + + BytesReceived = Connection->MessageBytesReceived; + + p = Connection->ReceiveQueue.Flink; + + // + // If there is a receive active, then see if this is it. + // + + if ((Connection->Flags & CONNECTION_FLAGS_ACTIVE_RECEIVE) != 0) { + + Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage); + + if (Request->IoRequestPacket == 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->Flags2 |= CONNECTION_FLAGS2_RCV_CANCELLED; + Connection->Flags &= ~CONNECTION_FLAGS_ACTIVE_RECEIVE; + + (VOID)RemoveHeadList (&Connection->ReceiveQueue); + + RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); + IoReleaseCancelSpinLock (Irp->CancelIrql); + + // + // 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. + // + + StCompleteRequest (Request, 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) { + + Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage); + if (Request->IoRequestPacket == Irp) { + + // + // Found it, remove it from the list here. + // + + RemoveEntryList (p); + Found = TRUE; + + RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); + IoReleaseCancelSpinLock (Irp->CancelIrql); + + // + // 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. + // + + StCompleteRequest (Request, STATUS_CANCELLED, 0); + break; + + } + + p = p->Flink; + + } + + if (!Found) { + + // + // We didn't find it! + // + + RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); + IoReleaseCancelSpinLock (Irp->CancelIrql); + } + +} |