summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/acd/request.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/tdi/acd/request.c')
-rw-r--r--private/ntos/tdi/acd/request.c303
1 files changed, 303 insertions, 0 deletions
diff --git a/private/ntos/tdi/acd/request.c b/private/ntos/tdi/acd/request.c
new file mode 100644
index 000000000..7976e733d
--- /dev/null
+++ b/private/ntos/tdi/acd/request.c
@@ -0,0 +1,303 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ request.c
+
+Abstract:
+
+ Worker thread for the automatic connection driver.
+
+Author:
+
+ Anthony Discolo (adiscolo) 17-Apr-1995
+
+Environment:
+
+ Kernel Mode
+
+Revision History:
+
+--*/
+
+#include <ndis.h>
+#include <cxport.h>
+#include <tdi.h>
+#include <tdikrnl.h>
+#include <tdistat.h>
+#include <tdiinfo.h>
+#include <acd.h>
+
+#include "acdapi.h"
+#include "acddefs.h"
+#include "mem.h"
+#include "debug.h"
+
+//
+// External declarations
+//
+VOID AcdPrintAddress(
+ IN PACD_ADDR pAddr
+ );
+
+
+
+VOID
+ProcessCompletion(
+ IN PACD_COMPLETION pCompletion,
+ IN KIRQL irqlCancel,
+ IN KIRQL irqlLock
+ )
+{
+ PLIST_ENTRY pHead;
+ KIRQL irql;
+ PIRP pIrp;
+ PIO_STACK_LOCATION pIrpSp;
+ PACD_NOTIFICATION pNotification;
+
+ ASSERT(!IsListEmpty(&AcdNotificationQueueG));
+ //
+ // Complete the next irp in the
+ // AcdNotificationQueueG queue. These
+ // represent the ioctl completions the
+ // system service has posted. Completing
+ // this request will start the system service
+ // to create a new RAS connection.
+ // Logically, there is always just one.
+ //
+ pHead = RemoveHeadList(&AcdNotificationQueueG);
+ pIrp = CONTAINING_RECORD(pHead, IRP, Tail.Overlay.ListEntry);
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ //
+ // Disable the irp's cancel routine.
+ //
+ IoSetCancelRoutine(pIrp, NULL);
+ //
+ // Copy the success flag and the address into the
+ // system buffer. This will get copied into the
+ // user's buffer on return.
+ //
+ pNotification = (PACD_NOTIFICATION)pIrp->AssociatedIrp.SystemBuffer;
+ RtlCopyMemory(
+ pNotification,
+ &pCompletion->notif,
+ sizeof (ACD_NOTIFICATION));
+ IF_ACDDBG(ACD_DEBUG_WORKER) {
+ AcdPrint(("AcdNotificationRequestThread: "));
+ AcdPrintAddress(&pCompletion->notif.addr);
+ AcdPrint((", ulFlags=0x%x\n", pCompletion->notif.ulFlags));
+ }
+ //
+ // We can release both the cancel lock
+ // and our lock now.
+ //
+ KeReleaseSpinLock(&AcdSpinLockG, irqlLock);
+ IoReleaseCancelSpinLock(irqlCancel);
+ //
+ // Set the status code and the number
+ // of bytes to be copied back to the user
+ // buffer.
+ //
+ pIrp->IoStatus.Status = STATUS_SUCCESS;
+ pIrp->IoStatus.Information = sizeof (ACD_NOTIFICATION);
+ //
+ // Complete the irp.
+ //
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+} // ProcessCompletion
+
+
+
+VOID
+AcdNotificationRequestThread(
+ PVOID context
+ )
+
+/*++
+
+DESCRIPTION
+ This thread handles the notification that an automatic
+ connection may need to be initiated. This needs to
+ happen in a separate thread, because the notification
+ may occur at DPC irql.
+
+ARGUMENTS
+ None.
+
+RETURN VALUE
+ None.
+
+--*/
+
+{
+ KIRQL irql, irql2;
+ PLIST_ENTRY pEntry, pEntry2;
+ PACD_CONNECTION pConnection;
+ PACD_COMPLETION pCompletion;
+ BOOLEAN bStartTimer, bStopTimer;
+
+ UNREFERENCED_PARAMETER(context);
+
+ IoStartTimer(pAcdDeviceObjectG);
+
+ for (;;) {
+ bStartTimer = bStopTimer = FALSE;
+ //
+ // Acquire our lock.
+ //
+ IoAcquireCancelSpinLock(&irql);
+ KeAcquireSpinLock(&AcdSpinLockG, &irql2);
+ //
+ // If there are no irps to complete,
+ // then go back to sleep.
+ //
+ if (IsListEmpty(&AcdNotificationQueueG)) {
+ IF_ACDDBG(ACD_DEBUG_WORKER) {
+ AcdPrint(("AcdNotificationRequestThread: no ioctl to complete\n"));
+ }
+ KeReleaseSpinLock(&AcdSpinLockG, irql2);
+ IoReleaseCancelSpinLock(irql);
+ goto again;
+ }
+ //
+ // Search for connections that haven't
+ // been processed yet.
+ //
+ for (pEntry = AcdConnectionQueueG.Flink;
+ pEntry != &AcdConnectionQueueG;
+ pEntry = pEntry->Flink)
+ {
+ pConnection = CONTAINING_RECORD(pEntry, ACD_CONNECTION, ListEntry);
+
+ //
+ // Don't issue a request to the service
+ // for more than one simultaneous connection.
+ //
+ IF_ACDDBG(ACD_DEBUG_WORKER) {
+ AcdPrint((
+ "AcdNotificationRequestThread: pConnection=0x%x, fNotif=%d, fCompleting=%d\n",
+ pConnection,
+ pConnection->fNotif,
+ pConnection->fCompleting));
+ }
+ if (pConnection->fNotif)
+ break;
+ //
+ // Skip all connections that are in
+ // the process of being completed.
+ //
+ if (pConnection->fCompleting)
+ continue;
+ //
+ // Make sure there is at least one
+ // request in this connection that
+ // hasn't been canceled.
+ //
+ for (pEntry2 = pConnection->CompletionList.Flink;
+ pEntry2 != &pConnection->CompletionList;
+ pEntry2 = pEntry2->Flink)
+ {
+ pCompletion = CONTAINING_RECORD(pEntry2, ACD_COMPLETION, ListEntry);
+
+ if (!pCompletion->fCanceled) {
+ IF_ACDDBG(ACD_DEBUG_WORKER) {
+ AcdPrint((
+ "AcdNotificationRequestThread: starting pConnection=0x%x, pCompletion=0x%x\n",
+ pConnection,
+ pCompletion));
+ }
+ pConnection->fNotif = TRUE;
+ //
+ // This call releases both the cancel lock
+ // and our lock.
+ //
+ ProcessCompletion(pCompletion, irql, irql2);
+ //
+ // Start the connection timer.
+ //
+ bStartTimer = TRUE;
+ //
+ // We can only process one completion
+ // at a time.
+ //
+ goto again;
+ }
+ }
+ }
+ //
+ // Complete other requests.
+ //
+ if (!IsListEmpty(&AcdCompletionQueueG)) {
+ pEntry = RemoveHeadList(&AcdCompletionQueueG);
+ pCompletion = CONTAINING_RECORD(pEntry, ACD_COMPLETION, ListEntry);
+
+ IF_ACDDBG(ACD_DEBUG_WORKER) {
+ AcdPrint((
+ "AcdNotificationRequestThread: starting pCompletion=0x%x\n",
+ pCompletion));
+ }
+ //
+ // This call releases both the cancel lock
+ // and our lock.
+ //
+ ProcessCompletion(pCompletion, irql, irql2);
+ //
+ // We are done with the completion,
+ // so we can free the memory now.
+ //
+ FREE_MEMORY(pCompletion);
+ //
+ // We can only process one completion
+ // at a time.
+ //
+ goto again;
+
+ }
+ //
+ // If there are no connections pending,
+ // then stop the connection timer.
+ //
+ if (IsListEmpty(&AcdConnectionQueueG))
+ bStopTimer = TRUE;
+ //
+ // Release our lock.
+ //
+ KeReleaseSpinLock(&AcdSpinLockG, irql2);
+ IoReleaseCancelSpinLock(irql);
+again:
+ //
+ // Start or stop the timer, depending
+ // on what we found while we had the
+ // spinlock. We can't hold our spin
+ // lock when we call the Io*Timer
+ // routines.
+ //
+#ifdef notdef
+ if (bStopTimer)
+ IoStopTimer(pAcdDeviceObjectG);
+ else if (bStartTimer)
+ IoStartTimer(pAcdDeviceObjectG);
+#endif
+ //
+ // Wait for something to do. This event
+ // will be signaled by AcdSignalNotification().
+ //
+ IF_ACDDBG(ACD_DEBUG_WORKER) {
+ AcdPrint(("AcdNotificationRequestThread: waiting on AcdPendingCompletionEventG\n"));
+ }
+ KeWaitForSingleObject(
+ &AcdRequestThreadEventG,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ KeClearEvent(&AcdRequestThreadEventG);
+ IF_ACDDBG(ACD_DEBUG_WORKER) {
+ AcdPrint(("AcdNotificationRequestThread: AcdPendingCompletionEventG signalled\n"));
+ }
+ }
+} // AcdNotificationRequestThread
+
+