summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/st/rcveng.c
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/tdi/st/rcveng.c
downloadNT4.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.c383
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);
+ }
+
+}