354 lines
8.6 KiB
C
354 lines
8.6 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
ntinit.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
NT specific routines for loading and configuring the
|
|||
|
automatic connection notification driver (acd.sys).
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Anthony Discolo (adiscolo) 18-Apr-1995
|
|||
|
|
|||
|
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"
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Global variables
|
|||
|
//
|
|||
|
#if DBG
|
|||
|
ULONG AcdDebugG = 0x0; // see debug.h for flags
|
|||
|
#endif
|
|||
|
|
|||
|
PDRIVER_OBJECT pAcdDriverObjectG;
|
|||
|
PDEVICE_OBJECT pAcdDeviceObjectG;
|
|||
|
PACD_DISABLED_ADDRESSES pDisabledAddressesG = NULL;
|
|||
|
|
|||
|
|
|||
|
HANDLE hSignalNotificationThreadG;
|
|||
|
|
|||
|
BOOLEAN AcdStopThread = FALSE; // Set to TRUE to stop system thread
|
|||
|
PETHREAD NotificationThread;
|
|||
|
BOOLEAN fAcdEnableRedirNotifs = FALSE;
|
|||
|
|
|||
|
extern LONG lOutstandingRequestsG;
|
|||
|
|
|||
|
//
|
|||
|
// Imported routines
|
|||
|
//
|
|||
|
VOID
|
|||
|
AcdNotificationRequestThread(
|
|||
|
PVOID context
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// External function prototypes
|
|||
|
//
|
|||
|
NTSTATUS
|
|||
|
AcdDispatch(
|
|||
|
IN PDEVICE_OBJECT pDeviceObject,
|
|||
|
IN PIRP pIrp
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
AcdConnectionTimer(
|
|||
|
IN PDEVICE_OBJECT pDeviceObject,
|
|||
|
IN PVOID pContext
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Internal function prototypes
|
|||
|
//
|
|||
|
NTSTATUS
|
|||
|
DriverEntry(
|
|||
|
IN PDRIVER_OBJECT pDriverObject,
|
|||
|
IN PUNICODE_STRING pRegistryPath
|
|||
|
);
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
GetComputerName(
|
|||
|
IN PUCHAR szName,
|
|||
|
IN USHORT cbName
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
AcdUnload(
|
|||
|
IN PDRIVER_OBJECT pDriverObject
|
|||
|
);
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text(INIT, DriverEntry)
|
|||
|
#pragma alloc_text(PAGE, AcdUnload)
|
|||
|
#endif // ALLOC_PRAGMA
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DriverEntry(
|
|||
|
IN PDRIVER_OBJECT pDriverObject,
|
|||
|
IN PUNICODE_STRING pRegistryPath
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
DESCRIPTION
|
|||
|
Initialization routine for the network connection notification driver.
|
|||
|
It creates the device object and initializes the driver.
|
|||
|
|
|||
|
ARGUMENTS
|
|||
|
pDriverObject: a pointer to the driver object created by the system.
|
|||
|
|
|||
|
pRegistryPath - the name of the configuration node in the registry.
|
|||
|
|
|||
|
RETURN VALUE
|
|||
|
The final status from the initialization operation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
UNICODE_STRING deviceName;
|
|||
|
ULONG i;
|
|||
|
OBJECT_ATTRIBUTES objectAttributes;
|
|||
|
IO_STATUS_BLOCK ioStatusBlock;
|
|||
|
PDEVICE_OBJECT pDeviceObject;
|
|||
|
PFILE_OBJECT pFileObject;
|
|||
|
PACD_DISABLED_ADDRESS pDisabledAddress = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the spin lock.
|
|||
|
//
|
|||
|
KeInitializeSpinLock(&AcdSpinLockG);
|
|||
|
//
|
|||
|
// Initialize the notification and completion
|
|||
|
// connection queues.
|
|||
|
//
|
|||
|
InitializeListHead(&AcdNotificationQueueG);
|
|||
|
InitializeListHead(&AcdCompletionQueueG);
|
|||
|
InitializeListHead(&AcdConnectionQueueG);
|
|||
|
InitializeListHead(&AcdDriverListG);
|
|||
|
lOutstandingRequestsG = 0;
|
|||
|
//
|
|||
|
// Initialize our zone allocator.
|
|||
|
//
|
|||
|
status = InitializeObjectAllocator();
|
|||
|
if(!NT_SUCCESS(status))
|
|||
|
{
|
|||
|
#if DBG
|
|||
|
DbgPrint("AcdDriverEntry: InitializeObjectAllocator"
|
|||
|
" failed. (status=0x%x)\n",
|
|||
|
status);
|
|||
|
#endif
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
//
|
|||
|
// Create the device object.
|
|||
|
//
|
|||
|
pAcdDriverObjectG = pDriverObject;
|
|||
|
RtlInitUnicodeString(&deviceName, ACD_DEVICE_NAME);
|
|||
|
status = IoCreateDevice(
|
|||
|
pDriverObject,
|
|||
|
0,
|
|||
|
&deviceName,
|
|||
|
FILE_DEVICE_ACD,
|
|||
|
0,
|
|||
|
FALSE,
|
|||
|
&pAcdDeviceObjectG);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
DbgPrint(
|
|||
|
"AcdDriverEntry: IoCreateDevice failed (status=0x%x)\n",
|
|||
|
status);
|
|||
|
FreeObjectAllocator();
|
|||
|
return status;
|
|||
|
}
|
|||
|
//
|
|||
|
// Initialize the driver object.
|
|||
|
//
|
|||
|
pDriverObject->DriverUnload = AcdUnload;
|
|||
|
for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
|
|||
|
pDriverObject->MajorFunction[i] = AcdDispatch;
|
|||
|
pDriverObject->FastIoDispatch = NULL;
|
|||
|
//
|
|||
|
// Initialize the connection timer. This is
|
|||
|
// used to make sure pending requests aren't
|
|||
|
// blocked forever because the user-space
|
|||
|
// process died trying to make a connection.
|
|||
|
//
|
|||
|
IoInitializeTimer(pAcdDeviceObjectG, AcdConnectionTimer, NULL);
|
|||
|
|
|||
|
{
|
|||
|
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
|
|||
|
PWSTR EnableRedirNotifs = L"EnableRedirNotifications";
|
|||
|
PWSTR ParameterKey = L"RasAcd\\Parameters";
|
|||
|
ULONG ulEnableRedirNotifs = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Read the registry key that enables redir notifications
|
|||
|
//
|
|||
|
RtlZeroMemory(&QueryTable, sizeof(QueryTable));
|
|||
|
QueryTable[0].QueryRoutine = NULL;
|
|||
|
QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|||
|
QueryTable[0].Name = EnableRedirNotifs;
|
|||
|
QueryTable[0].EntryContext = (PVOID)&ulEnableRedirNotifs;
|
|||
|
QueryTable[0].DefaultType = 0;
|
|||
|
status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
|
|||
|
ParameterKey,
|
|||
|
&QueryTable[0],
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
|
|||
|
if((status == STATUS_SUCCESS) && (ulEnableRedirNotifs != 0))
|
|||
|
{
|
|||
|
fAcdEnableRedirNotifs = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
// KdPrint(("AcdDriverEntry: EnableRedirNotifs=%d\n", fAcdEnableRedirNotifs));
|
|||
|
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Create the worker thread. We need
|
|||
|
// a thread because these operations can occur at
|
|||
|
// DPC irql.
|
|||
|
//
|
|||
|
KeInitializeEvent(
|
|||
|
&AcdRequestThreadEventG,
|
|||
|
NotificationEvent,
|
|||
|
FALSE);
|
|||
|
status = PsCreateSystemThread(
|
|||
|
&hSignalNotificationThreadG,
|
|||
|
THREAD_ALL_ACCESS,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
AcdNotificationRequestThread,
|
|||
|
NULL);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
DbgPrint(
|
|||
|
"AcdDriverEntry: PsCreateSystemThread failed (status=0x%x)\n",
|
|||
|
status);
|
|||
|
IoDeleteDevice(pAcdDeviceObjectG);
|
|||
|
FreeObjectAllocator();
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Allocate memory for keeping track of disabled addresses
|
|||
|
//
|
|||
|
ALLOCATE_MEMORY(sizeof(ACD_DISABLED_ADDRESSES), pDisabledAddressesG);
|
|||
|
|
|||
|
if(pDisabledAddressesG == NULL)
|
|||
|
{
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
IoDeleteDevice(pAcdDeviceObjectG);
|
|||
|
FreeObjectAllocator();
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
ALLOCATE_MEMORY(sizeof(ACD_DISABLED_ADDRESS), pDisabledAddress);
|
|||
|
|
|||
|
if(pDisabledAddress == NULL)
|
|||
|
{
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
IoDeleteDevice(pAcdDeviceObjectG);
|
|||
|
FREE_MEMORY(pDisabledAddressesG);
|
|||
|
FreeObjectAllocator();
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
RtlZeroMemory(pDisabledAddressesG, sizeof(ACD_DISABLED_ADDRESSES));
|
|||
|
RtlZeroMemory(pDisabledAddress, sizeof(ACD_DISABLED_ADDRESS));
|
|||
|
|
|||
|
InitializeListHead(&pDisabledAddressesG->ListEntry);
|
|||
|
InsertTailList(&pDisabledAddressesG->ListEntry, &pDisabledAddress->ListEntry);
|
|||
|
pDisabledAddressesG->ulNumAddresses = 1;
|
|||
|
|
|||
|
pDisabledAddressesG->ulMaxAddresses = 10;
|
|||
|
|
|||
|
//
|
|||
|
// If this fails then we have no way to wait for the thread to terminate
|
|||
|
//
|
|||
|
status = ObReferenceObjectByHandle (hSignalNotificationThreadG,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
KernelMode,
|
|||
|
&NotificationThread,
|
|||
|
NULL);
|
|||
|
ASSERT (NT_SUCCESS (status));
|
|||
|
return STATUS_SUCCESS;
|
|||
|
} // DriverEntry
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
AcdUnload(
|
|||
|
IN PDRIVER_OBJECT pDriverObject
|
|||
|
)
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
//
|
|||
|
// Terminate the system thread and wait for it to exit
|
|||
|
//
|
|||
|
AcdStopThread = TRUE;
|
|||
|
KeSetEvent(&AcdRequestThreadEventG, 0, FALSE); // Wake the thread so it sees to exit
|
|||
|
//
|
|||
|
// Wait for the thread to leave the drivers address space.
|
|||
|
//
|
|||
|
KeWaitForSingleObject (NotificationThread, Executive, KernelMode, FALSE, 0);
|
|||
|
|
|||
|
ObDereferenceObject (NotificationThread);
|
|||
|
ZwClose (hSignalNotificationThreadG);
|
|||
|
//
|
|||
|
// Make sure to unlink all driver
|
|||
|
// blocks before unloading!
|
|||
|
//
|
|||
|
IoDeleteDevice(pAcdDeviceObjectG);
|
|||
|
|
|||
|
if(pDisabledAddressesG)
|
|||
|
{
|
|||
|
PLIST_ENTRY pListEntry;
|
|||
|
PACD_DISABLED_ADDRESS pDisabledAddress;
|
|||
|
|
|||
|
while(!IsListEmpty(&pDisabledAddressesG->ListEntry))
|
|||
|
{
|
|||
|
pListEntry = RemoveHeadList(&pDisabledAddressesG->ListEntry);
|
|||
|
pDisabledAddress =
|
|||
|
CONTAINING_RECORD(pListEntry, ACD_DISABLED_ADDRESS, ListEntry);
|
|||
|
|
|||
|
FREE_MEMORY(pDisabledAddress);
|
|||
|
}
|
|||
|
|
|||
|
FREE_MEMORY(pDisabledAddressesG);
|
|||
|
pDisabledAddressesG = NULL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free zone allocator.
|
|||
|
//
|
|||
|
FreeObjectAllocator();
|
|||
|
|
|||
|
} // AcdUnload
|