349 lines
9.3 KiB
C
349 lines
9.3 KiB
C
/*++
|
||
|
||
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
|
||
|
||
|