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
|
|||
|
|
|||
|
|