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
|