windows-nt/Source/XPSP1/NT/net/rras/ras/autodial/rasacd/request.c

349 lines
9.3 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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
);
extern LONG lOutstandingRequestsG;
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);
//
// The irp thats being completed below will always be
// from a 64bit process. We are doing the check below
// to protect against some penetration program trying
// to break this code.
//
#if defined (_WIN64)
if(IoIs32bitProcess(pIrp))
{
ACD_NOTIFICATION_32 *pNotification32 =
(PACD_NOTIFICATION_32) pIrp->AssociatedIrp.SystemBuffer;
RtlCopyMemory(
&pNotification32->addr,
&pCompletion->notif.addr,
sizeof(ACD_ADDR));
RtlCopyMemory(
&pNotification32->adapter,
&pCompletion->notif.adapter,
sizeof(ACD_ADAPTER));
pNotification32->ulFlags = pCompletion->notif.ulFlags;
pNotification32->Pid = (VOID * POINTER_32) HandleToUlong(
pCompletion->notif.Pid);
}
else
#endif
{
//
// 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));
}
lOutstandingRequestsG--;
//
// 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
//
// Unload is telling us to stop. Exit
//
if (AcdStopThread == TRUE) {
break;
}
//
// 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