diff options
Diffstat (limited to 'private/ntos/tdi/acd/request.c')
-rw-r--r-- | private/ntos/tdi/acd/request.c | 303 |
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 + + |