mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1263 lines
33 KiB
1263 lines
33 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
initunlo.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the code that is very specific to initialization
|
|
and unload operations in the modem driver
|
|
|
|
Author:
|
|
|
|
Anthony V. Ercolano 13-Aug-1995
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History :
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
|
|
|
|
#if DBG
|
|
ULONG UniDebugLevel = 0;
|
|
#endif
|
|
|
|
//
|
|
// Holds the service key name of the driver (i.e. CCS\Services\ServiceKeyName)
|
|
// The service key name is used to call IoQueryDeviceEnumInfo and
|
|
// IoOpenDeviceInstanceKey APIs. It is for SUR only.
|
|
//
|
|
|
|
UNICODE_STRING UniServiceKeyName;
|
|
|
|
NTSTATUS
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
);
|
|
|
|
VOID
|
|
UniUnload(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
);
|
|
|
|
NTSTATUS
|
|
UniDispatch(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
VOID
|
|
UniGetAllModems(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath,
|
|
IN PLIST_ENTRY ConfigList
|
|
);
|
|
|
|
VOID
|
|
UniInitializeItem(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath,
|
|
IN PCONFIG_DATA ConfigData
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(INIT,DriverEntry)
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The entry point that the system point calls to initialize
|
|
any driver.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - Just what it says, really of little use
|
|
to the driver itself, it is something that the IO system
|
|
cares more about.
|
|
|
|
PathToRegistry - points to the entry for this driver
|
|
in the current control set of the registry.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if we could initialize a single device,
|
|
otherwise STATUS_NO_SUCH_DEVICE.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Holds status information return by various OS and driver
|
|
// initialization routines.
|
|
//
|
|
NTSTATUS status;
|
|
|
|
//
|
|
// We use this to query into the registry as to whether we
|
|
// should break at driver entry.
|
|
//
|
|
RTL_QUERY_REGISTRY_TABLE paramTable[3];
|
|
ULONG zero = 0;
|
|
ULONG debugLevel = 0;
|
|
ULONG shouldBreak = 0;
|
|
ULONG notThereDefault = 1234567;
|
|
PWCHAR path;
|
|
LIST_ENTRY configList;
|
|
USHORT i;
|
|
PWSTR string;
|
|
|
|
//
|
|
// Allocate pool to remember the service key name such that we can
|
|
// call IoQueryDeviceEnumInfo and IoOpenDeviceInstanceKey.
|
|
//
|
|
|
|
string = RegistryPath->Buffer + RegistryPath->Length / sizeof(WCHAR) - 1;
|
|
if (*string == L'\\') {
|
|
string--;
|
|
}
|
|
i = 0;
|
|
while (*string != L'\\' && string != RegistryPath->Buffer) {
|
|
string--;
|
|
i += sizeof(WCHAR);
|
|
}
|
|
string++;
|
|
UniServiceKeyName.Buffer = (PWSTR)ExAllocatePool(PagedPool, i + sizeof(UNICODE_NULL));
|
|
if (UniServiceKeyName.Buffer == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlMoveMemory(UniServiceKeyName.Buffer, string, i);
|
|
UniServiceKeyName.Buffer[ i / sizeof(WCHAR)] = UNICODE_NULL;
|
|
UniServiceKeyName.Length = i;
|
|
UniServiceKeyName.MaximumLength = i + sizeof(UNICODE_NULL);
|
|
|
|
//
|
|
// Since the registry path parameter is a "counted" UNICODE string, it
|
|
// might not be zero terminated. For a very short time allocate memory
|
|
// to hold the registry path zero terminated so that we can use it to
|
|
// delve into the registry.
|
|
//
|
|
// NOTE NOTE!!!! This is not an architected way of breaking into
|
|
// a driver. It happens to work for this driver because the author
|
|
// likes to do things this way.
|
|
//
|
|
|
|
if (path = ExAllocatePool(
|
|
PagedPool,
|
|
RegistryPath->Length+sizeof(WCHAR)
|
|
)) {
|
|
|
|
RtlZeroMemory(
|
|
¶mTable[0],
|
|
sizeof(paramTable)
|
|
);
|
|
RtlZeroMemory(
|
|
path,
|
|
RegistryPath->Length+sizeof(WCHAR)
|
|
);
|
|
RtlMoveMemory(
|
|
path,
|
|
RegistryPath->Buffer,
|
|
RegistryPath->Length
|
|
);
|
|
paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|
paramTable[0].Name = L"BreakOnEntry";
|
|
paramTable[0].EntryContext = &shouldBreak;
|
|
paramTable[0].DefaultType = REG_DWORD;
|
|
paramTable[0].DefaultData = &zero;
|
|
paramTable[0].DefaultLength = sizeof(ULONG);
|
|
paramTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|
paramTable[1].Name = L"DebugLevel";
|
|
paramTable[1].EntryContext = &debugLevel;
|
|
paramTable[1].DefaultType = REG_DWORD;
|
|
paramTable[1].DefaultData = &zero;
|
|
paramTable[1].DefaultLength = sizeof(ULONG);
|
|
|
|
if (!NT_SUCCESS(RtlQueryRegistryValues(
|
|
RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
|
|
path,
|
|
¶mTable[0],
|
|
NULL,
|
|
NULL
|
|
))) {
|
|
|
|
shouldBreak = 0;
|
|
debugLevel = 0;
|
|
|
|
}
|
|
|
|
ExFreePool(path);
|
|
}
|
|
|
|
#if DBG
|
|
UniDebugLevel = debugLevel;
|
|
#endif
|
|
|
|
if (shouldBreak) {
|
|
|
|
DbgBreakPoint();
|
|
|
|
}
|
|
|
|
//
|
|
// Link list of configuration information found by scrounging
|
|
// the registry. If the list is empty then we didn't find
|
|
// anything.
|
|
//
|
|
|
|
UniGetAllModems(
|
|
DriverObject,
|
|
RegistryPath,
|
|
&configList
|
|
);
|
|
|
|
|
|
//
|
|
// Initialize each item in the list of configuration records.
|
|
//
|
|
|
|
while (!IsListEmpty(&configList)) {
|
|
|
|
PCONFIG_DATA currentConfig;
|
|
PLIST_ENTRY head;
|
|
|
|
head = RemoveHeadList(&configList);
|
|
|
|
currentConfig = CONTAINING_RECORD(
|
|
head,
|
|
CONFIG_DATA,
|
|
ConfigList
|
|
);
|
|
|
|
UniInitializeItem(
|
|
DriverObject,
|
|
RegistryPath,
|
|
currentConfig
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (DriverObject->DeviceObject) {
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Initialize the Driver Object with driver's entry points
|
|
//
|
|
|
|
DriverObject->DriverUnload = UniUnload;
|
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = UniOpen;
|
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] = UniClose;
|
|
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = UniIoControl;
|
|
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = UniDispatch;
|
|
DriverObject->MajorFunction[IRP_MJ_WRITE] = UniReadWrite;
|
|
DriverObject->MajorFunction[IRP_MJ_READ] = UniReadWrite;
|
|
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = UniCleanup;
|
|
DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] =
|
|
UniQueryInformationFile;
|
|
DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] =
|
|
UniSetInformationFile;
|
|
|
|
} else {
|
|
|
|
status = STATUS_NO_SUCH_DEVICE;
|
|
|
|
}
|
|
|
|
//
|
|
// If anything goes wrong, free service key name buffer.
|
|
//
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
ExFreePool(UniServiceKeyName.Buffer);
|
|
}
|
|
return status;
|
|
|
|
}
|
|
|
|
VOID
|
|
UniUnload(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
)
|
|
{
|
|
|
|
|
|
PDEVICE_OBJECT currentDevice = DriverObject->DeviceObject;
|
|
|
|
UniDump(
|
|
UNIDIAG3,
|
|
("UNIMDM: In UniUnload\n")
|
|
);
|
|
|
|
while (currentDevice) {
|
|
|
|
PDEVICE_EXTENSION extension = currentDevice->DeviceExtension;
|
|
currentDevice = currentDevice->NextDevice;
|
|
|
|
//
|
|
// Kill the symbolic link.
|
|
// Free the pointers to strings
|
|
// Finnally delete the device.
|
|
//
|
|
|
|
IoDeleteSymbolicLink(&extension->FullLinkName);
|
|
ExFreePool(extension->FullLinkName.Buffer);
|
|
IoDeleteDevice(extension->DeviceObject);
|
|
|
|
}
|
|
|
|
//
|
|
// Free the buffer for service key name.
|
|
//
|
|
|
|
ExFreePool(UniServiceKeyName.Buffer);
|
|
}
|
|
|
|
VOID
|
|
UniGetAllModems(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath,
|
|
IN PLIST_ENTRY ConfigList
|
|
)
|
|
|
|
{
|
|
|
|
|
|
PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
|
|
|
|
//
|
|
// Where user data from the registry will be placed.
|
|
//
|
|
|
|
UNICODE_STRING friendlySymbolicLink;
|
|
UNICODE_STRING deviceInstanceString;
|
|
|
|
ULONG maxDeviceInstances;
|
|
|
|
InitializeListHead(ConfigList);
|
|
|
|
RtlInitUnicodeString(
|
|
&friendlySymbolicLink,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// We will initially allocate space for 257 wchars.
|
|
// we will then set the maximum size to 256
|
|
// This way the rtl routine could return a 256
|
|
// WCHAR wide string with no null terminator.
|
|
// We'll remember that the buffer is one WCHAR
|
|
// longer then it says it is so that we can always
|
|
// have a NULL terminator at the end.
|
|
//
|
|
|
|
friendlySymbolicLink.MaximumLength = sizeof(WCHAR)*256;
|
|
friendlySymbolicLink.Buffer = ExAllocatePool(
|
|
PagedPool,
|
|
sizeof(WCHAR)*257
|
|
);
|
|
|
|
if (!friendlySymbolicLink.Buffer) {
|
|
|
|
UniLogError(
|
|
DriverObject,
|
|
NULL,
|
|
0,
|
|
0,
|
|
0,
|
|
24,
|
|
STATUS_SUCCESS,
|
|
MODEM_INSUFFICIENT_RESOURCES,
|
|
0,
|
|
NULL,
|
|
0,
|
|
NULL
|
|
);
|
|
UniDump(
|
|
UNIERRORS,
|
|
("UNI32: Couldn't allocate buffer for the symbolic link\n"
|
|
"------ for parameters items in %wZ",
|
|
RegistryPath)
|
|
);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// See if there are any devices available via the obsolete
|
|
// plug and play calls.
|
|
//
|
|
|
|
if (NT_SUCCESS(IoQueryDeviceEnumInfo(
|
|
&UniServiceKeyName,
|
|
&maxDeviceInstances
|
|
))) {
|
|
|
|
//
|
|
// Get the info via plug and play functions.
|
|
//
|
|
|
|
ULONG currentInstance;
|
|
ACCESS_MASK simpleAccess = FILE_ALL_ACCESS;
|
|
HANDLE regKey;
|
|
|
|
parameters = ExAllocatePool(
|
|
PagedPool,
|
|
sizeof(RTL_QUERY_REGISTRY_TABLE)*2
|
|
);
|
|
|
|
if (!parameters) {
|
|
|
|
UniLogError(
|
|
DriverObject,
|
|
NULL,
|
|
0,
|
|
0,
|
|
0,
|
|
123,
|
|
STATUS_SUCCESS,
|
|
MODEM_INSUFFICIENT_RESOURCES,
|
|
0,
|
|
NULL,
|
|
0,
|
|
NULL
|
|
);
|
|
UniDump(
|
|
UNIERRORS,
|
|
("UNI32: Couldn't allocate table for rtl query\n"
|
|
"------ to parameters for %wZ",
|
|
RegistryPath)
|
|
);
|
|
ExFreePool(friendlySymbolicLink.Buffer);
|
|
return;
|
|
|
|
}
|
|
|
|
RtlZeroMemory(
|
|
parameters,
|
|
sizeof(RTL_QUERY_REGISTRY_TABLE)*2
|
|
);
|
|
|
|
parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|
parameters[0].Name = L"FriendlyName";
|
|
parameters[0].EntryContext = &friendlySymbolicLink;
|
|
parameters[0].DefaultType = REG_SZ;
|
|
parameters[0].DefaultData = L"";
|
|
parameters[0].DefaultLength = 0;
|
|
|
|
for (
|
|
currentInstance = 0;
|
|
currentInstance < maxDeviceInstances;
|
|
currentInstance++
|
|
) {
|
|
|
|
PCONFIG_DATA newConfig;
|
|
NTSTATUS status;
|
|
|
|
status = IoOpenDeviceInstanceKey(
|
|
&UniServiceKeyName,
|
|
currentInstance,
|
|
PLUGPLAY_REGKEY_DRIVER,
|
|
simpleAccess,
|
|
®Key
|
|
);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// We have a valid device instance. Get the
|
|
// friendly name.
|
|
//
|
|
|
|
status = RtlQueryRegistryValues(
|
|
RTL_REGISTRY_HANDLE,
|
|
regKey,
|
|
parameters,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// We have a valid friendly name. Make a config
|
|
// record.
|
|
//
|
|
|
|
RtlZeroMemory(
|
|
((PUCHAR)(&friendlySymbolicLink.Buffer[0]))+
|
|
friendlySymbolicLink.Length,
|
|
sizeof(WCHAR)
|
|
);
|
|
|
|
if (!friendlySymbolicLink.Length) {
|
|
|
|
UniLogError(
|
|
DriverObject,
|
|
NULL,
|
|
0,
|
|
0,
|
|
0,
|
|
160,
|
|
STATUS_SUCCESS,
|
|
STATUS_INSUFFICIENT_RESOURCES,
|
|
0,
|
|
NULL,
|
|
0,
|
|
NULL
|
|
);
|
|
UniDump(
|
|
UNIERRORS,
|
|
("UNI32: bogus value for %d\n",
|
|
currentInstance)
|
|
);
|
|
ZwClose(regKey);
|
|
continue;
|
|
|
|
}
|
|
|
|
//
|
|
// Allocate the config record.
|
|
//
|
|
|
|
newConfig = ExAllocatePool(
|
|
PagedPool,
|
|
sizeof(CONFIG_DATA)
|
|
);
|
|
|
|
if (!newConfig) {
|
|
|
|
UniLogError(
|
|
DriverObject,
|
|
NULL,
|
|
0,
|
|
0,
|
|
0,
|
|
37,
|
|
STATUS_SUCCESS,
|
|
MODEM_INSUFFICIENT_RESOURCES,
|
|
0,
|
|
NULL,
|
|
0,
|
|
NULL
|
|
);
|
|
UniDump(
|
|
UNIERRORS,
|
|
("UNI32: Couldn't allocate memory for the\n"
|
|
"------ user configuration record\n"
|
|
"------ for %d\n",
|
|
currentInstance)
|
|
);
|
|
ZwClose(regKey);
|
|
continue;
|
|
|
|
}
|
|
|
|
RtlZeroMemory(
|
|
newConfig,
|
|
sizeof(CONFIG_DATA)
|
|
);
|
|
newConfig->DeviceInstance = currentInstance;
|
|
|
|
RtlInitUnicodeString(
|
|
&newConfig->NtNameForPort,
|
|
NULL
|
|
);
|
|
|
|
newConfig->NtNameForPort.MaximumLength = sizeof(WCHAR)*40;
|
|
newConfig->NtNameForPort.Buffer = ExAllocatePool(
|
|
PagedPool,
|
|
sizeof(WCHAR)*41
|
|
);
|
|
if (!newConfig->NtNameForPort.Buffer) {
|
|
|
|
UniDump(
|
|
UNIERRORS,
|
|
("UNI32: Couldn't memory for ntname\n"
|
|
"------ to parameters for %d",
|
|
currentInstance)
|
|
);
|
|
ExFreePool(newConfig);
|
|
ZwClose(regKey);
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!NT_SUCCESS(RtlIntegerToUnicodeString(
|
|
currentInstance,
|
|
10,
|
|
&newConfig->NtNameForPort
|
|
))) {
|
|
|
|
UniLogError(
|
|
DriverObject,
|
|
NULL,
|
|
0,
|
|
0,
|
|
0,
|
|
118,
|
|
STATUS_SUCCESS,
|
|
MODEM_INSUFFICIENT_RESOURCES,
|
|
0,
|
|
NULL,
|
|
0,
|
|
NULL
|
|
);
|
|
UniDump(
|
|
UNIERRORS,
|
|
("UNI32: couldn't convert instance number %d\n",
|
|
currentInstance)
|
|
);
|
|
ExFreePool(newConfig->NtNameForPort.Buffer);
|
|
ExFreePool(newConfig);
|
|
ZwClose(regKey);
|
|
continue;
|
|
|
|
}
|
|
|
|
newConfig->FriendlyName = friendlySymbolicLink;
|
|
newConfig->FriendlyName.MaximumLength += sizeof(WCHAR);
|
|
|
|
newConfig->FriendlyName.Buffer =
|
|
ExAllocatePool(
|
|
PagedPool,
|
|
newConfig->FriendlyName.MaximumLength
|
|
);
|
|
|
|
if (!newConfig->FriendlyName.Buffer) {
|
|
|
|
UniLogError(
|
|
DriverObject,
|
|
NULL,
|
|
0,
|
|
0,
|
|
0,
|
|
40,
|
|
STATUS_SUCCESS,
|
|
MODEM_INSUFFICIENT_RESOURCES,
|
|
0,
|
|
NULL,
|
|
0,
|
|
NULL
|
|
);
|
|
UniDump(
|
|
UNIERRORS,
|
|
("UNI32: Couldn't allocate memory for symbolic\n"
|
|
"------ name from user data\n"
|
|
"------ %d\n",
|
|
currentInstance)
|
|
);
|
|
ExFreePool(newConfig->NtNameForPort.Buffer);
|
|
ExFreePool(newConfig);
|
|
ZwClose(regKey);
|
|
continue;
|
|
|
|
} else {
|
|
|
|
RtlZeroMemory(
|
|
newConfig->FriendlyName.Buffer,
|
|
newConfig->FriendlyName.MaximumLength
|
|
);
|
|
|
|
newConfig->FriendlyName.Length = 0;
|
|
RtlAppendUnicodeStringToString(
|
|
&newConfig->FriendlyName,
|
|
&friendlySymbolicLink
|
|
);
|
|
|
|
}
|
|
|
|
InitializeListHead(&newConfig->ConfigList);
|
|
InsertTailList(
|
|
ConfigList,
|
|
&newConfig->ConfigList
|
|
);
|
|
|
|
} else {
|
|
|
|
UniLogError(
|
|
DriverObject,
|
|
NULL,
|
|
0,
|
|
0,
|
|
0,
|
|
161,
|
|
STATUS_SUCCESS,
|
|
status,
|
|
0,
|
|
NULL,
|
|
0,
|
|
NULL
|
|
);
|
|
UniDump(
|
|
UNIERRORS,
|
|
("UNI32: Bad status returned: %x \n"
|
|
"------- for the value entries of\n"
|
|
"------- %d\n",
|
|
status,
|
|
currentInstance)
|
|
);
|
|
|
|
}
|
|
|
|
ZwClose(regKey);
|
|
|
|
} else {
|
|
|
|
UniLogError(
|
|
DriverObject,
|
|
NULL,
|
|
0,
|
|
0,
|
|
0,
|
|
162,
|
|
STATUS_SUCCESS,
|
|
status,
|
|
0,
|
|
NULL,
|
|
0,
|
|
NULL
|
|
);
|
|
UniDump(
|
|
UNIERRORS,
|
|
("UNI32: Bad status returned: %x \n"
|
|
"------- for the query of\n"
|
|
"------- %d\n",
|
|
status,
|
|
currentInstance)
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (friendlySymbolicLink.Buffer) {
|
|
|
|
ExFreePool(friendlySymbolicLink.Buffer);
|
|
|
|
}
|
|
|
|
if (parameters) {
|
|
|
|
ExFreePool(parameters);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
VOID
|
|
UniInitializeItem(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath,
|
|
IN PCONFIG_DATA ConfigData
|
|
)
|
|
|
|
{
|
|
|
|
|
|
//
|
|
// This will hold the string that we need to use to describe
|
|
// the name of the device to the IO system.
|
|
//
|
|
UNICODE_STRING uniNameString;
|
|
|
|
//
|
|
// Holds the full path for the symbolic link
|
|
//
|
|
UNICODE_STRING fullLinkName;
|
|
|
|
|
|
//
|
|
// Holds the NT Status that is returned from each call to the
|
|
// kernel and executive.
|
|
//
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Points to the device object (not the extension) created
|
|
// for this device.
|
|
//
|
|
PDEVICE_OBJECT deviceObject = NULL;
|
|
|
|
//
|
|
// Pointer to the device extension created for this
|
|
// device
|
|
//
|
|
PDEVICE_EXTENSION deviceExtension = NULL;
|
|
|
|
//
|
|
// Create the device object for the modem.
|
|
// Allocates the device extension. Note that
|
|
// the device is marked non-exclusive.
|
|
//
|
|
|
|
|
|
UniDump(
|
|
UNIDIAG1,
|
|
("UNIMDM: Initializing for configuration record of %wZ\n",
|
|
&ConfigData->NtNameForPort)
|
|
);
|
|
|
|
//
|
|
// Form a name like \Device\Modem0.
|
|
//
|
|
// First we allocate space for the name.
|
|
//
|
|
|
|
RtlInitUnicodeString(
|
|
&uniNameString,
|
|
NULL
|
|
);
|
|
RtlInitUnicodeString(
|
|
&fullLinkName,
|
|
NULL
|
|
);
|
|
|
|
uniNameString.MaximumLength = sizeof(L"\\Device\\Modem") +
|
|
ConfigData->NtNameForPort.Length+sizeof(WCHAR);
|
|
uniNameString.Buffer = ExAllocatePool(
|
|
PagedPool,
|
|
uniNameString.MaximumLength
|
|
);
|
|
|
|
//
|
|
// The only reason the above could have failed is if
|
|
// there wasn't enough system memory to form the UNICODE
|
|
// string.
|
|
//
|
|
|
|
if (!uniNameString.Buffer) {
|
|
|
|
UniDump(
|
|
UNIERRORS,
|
|
("UNIMDM: Could not form Unicode name string for %wZ\n",
|
|
&ConfigData->NtNameForPort)
|
|
);
|
|
UniLogError(
|
|
DriverObject,
|
|
NULL,
|
|
0,
|
|
0,
|
|
0,
|
|
4,
|
|
STATUS_SUCCESS,
|
|
MODEM_INSUFFICIENT_RESOURCES,
|
|
0,
|
|
NULL,
|
|
0,
|
|
NULL
|
|
);
|
|
ExFreePool(ConfigData->NtNameForPort.Buffer);
|
|
ExFreePool(ConfigData->FriendlyName.Buffer);
|
|
ExFreePool(ConfigData);
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Actually form the Name.
|
|
//
|
|
|
|
RtlZeroMemory(
|
|
uniNameString.Buffer,
|
|
uniNameString.MaximumLength
|
|
);
|
|
|
|
RtlAppendUnicodeToString(
|
|
&uniNameString,
|
|
L"\\Device\\Modem"
|
|
);
|
|
|
|
RtlAppendUnicodeStringToString(
|
|
&uniNameString,
|
|
&ConfigData->NtNameForPort
|
|
);
|
|
|
|
//
|
|
// Create the device object for this device.
|
|
//
|
|
|
|
status = IoCreateDevice(
|
|
DriverObject,
|
|
sizeof(DEVICE_EXTENSION),
|
|
&uniNameString,
|
|
FILE_DEVICE_MODEM,
|
|
0,
|
|
FALSE,
|
|
&deviceObject
|
|
);
|
|
|
|
//
|
|
// If we couldn't create the device object, then there
|
|
// is no point in going on.
|
|
//
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
UniDump(
|
|
UNIERRORS,
|
|
("UNIMDM: Could not create a device for %wZ\n",
|
|
&ConfigData->NtNameForPort)
|
|
);
|
|
UniLogError(
|
|
DriverObject,
|
|
NULL,
|
|
0,
|
|
0,
|
|
0,
|
|
5,
|
|
status,
|
|
MODEM_INSUFFICIENT_RESOURCES,
|
|
0,
|
|
NULL,
|
|
0,
|
|
NULL
|
|
);
|
|
ExFreePool(ConfigData->NtNameForPort.Buffer);
|
|
ExFreePool(ConfigData->FriendlyName.Buffer);
|
|
ExFreePool(ConfigData);
|
|
ExFreePool(uniNameString.Buffer);
|
|
return;
|
|
|
|
}
|
|
|
|
RtlZeroMemory(
|
|
deviceObject->DeviceExtension,
|
|
sizeof(DEVICE_EXTENSION)
|
|
);
|
|
|
|
deviceObject->Flags |= DO_BUFFERED_IO;
|
|
deviceExtension = deviceObject->DeviceExtension;
|
|
deviceExtension->DeviceObject = deviceObject;
|
|
KeInitializeSpinLock(&deviceExtension->DeviceLock);
|
|
InitializeListHead(&deviceExtension->OpenClose);
|
|
InitializeListHead(&deviceExtension->PassThroughQueue);
|
|
InitializeListHead(&deviceExtension->MaskOps);
|
|
deviceExtension->MaskStates[0].Extension = deviceExtension;
|
|
deviceExtension->MaskStates[1].Extension = deviceExtension;
|
|
deviceExtension->MaskStates[0].OtherState = &deviceExtension->MaskStates[1];
|
|
deviceExtension->MaskStates[1].OtherState = &deviceExtension->MaskStates[0];
|
|
|
|
//
|
|
// Create the symbolic link of the friendly name
|
|
//
|
|
|
|
RtlInitUnicodeString(
|
|
&deviceExtension->FullLinkName,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Allocate some pool for the name.
|
|
//
|
|
|
|
deviceExtension->FullLinkName.MaximumLength =
|
|
sizeof(OBJECT_DIRECTORY) +
|
|
ConfigData->FriendlyName.Length+
|
|
sizeof(WCHAR);
|
|
|
|
deviceExtension->FullLinkName.Buffer = ExAllocatePool(
|
|
PagedPool,
|
|
deviceExtension->
|
|
FullLinkName.MaximumLength
|
|
);
|
|
|
|
if (!deviceExtension->FullLinkName.Buffer) {
|
|
|
|
//
|
|
// Couldn't allocate space for the name.
|
|
//
|
|
|
|
UniLogError(
|
|
deviceExtension->DeviceObject->DriverObject,
|
|
deviceExtension->DeviceObject,
|
|
0,
|
|
0,
|
|
0,
|
|
51,
|
|
STATUS_SUCCESS,
|
|
MODEM_INSUFFICIENT_RESOURCES,
|
|
0,
|
|
NULL,
|
|
0,
|
|
NULL
|
|
);
|
|
UniDump(
|
|
UNIERRORS,
|
|
("UNIMDM: Couldn't allocate space for the symbolic \n"
|
|
"------- name for creating the link\n"
|
|
"------- for port %wZ\n",
|
|
&uniNameString)
|
|
);
|
|
|
|
goto ErrorCleanup;
|
|
|
|
} else {
|
|
|
|
RtlZeroMemory(
|
|
deviceExtension->FullLinkName.Buffer,
|
|
deviceExtension->FullLinkName.MaximumLength
|
|
);
|
|
|
|
RtlAppendUnicodeToString(
|
|
&deviceExtension->FullLinkName,
|
|
OBJECT_DIRECTORY
|
|
);
|
|
|
|
RtlAppendUnicodeStringToString(
|
|
&deviceExtension->FullLinkName,
|
|
&ConfigData->FriendlyName
|
|
);
|
|
|
|
status = IoCreateSymbolicLink(
|
|
&deviceExtension->FullLinkName,
|
|
&uniNameString
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// Oh well, couldn't create the symbolic link. No point
|
|
// in trying to create the device map entry.
|
|
//
|
|
|
|
UniLogError(
|
|
deviceExtension->DeviceObject->DriverObject,
|
|
deviceExtension->DeviceObject,
|
|
0,
|
|
0,
|
|
0,
|
|
52,
|
|
status,
|
|
MODEM_NO_SYMLINK_CREATED,
|
|
0,
|
|
0,
|
|
0,
|
|
NULL
|
|
);
|
|
UniDump(
|
|
UNIERRORS,
|
|
("UNIMDM: Couldn't create the symbolic link\n"
|
|
"------- for port %wZ\n",
|
|
&uniNameString)
|
|
);
|
|
|
|
goto ErrorCleanup;
|
|
|
|
}
|
|
deviceExtension->DeviceInstance = ConfigData->DeviceInstance;
|
|
}
|
|
|
|
|
|
goto OkCleanup;
|
|
|
|
ErrorCleanup:;
|
|
if (deviceExtension->FullLinkName.Buffer) {
|
|
ExFreePool(deviceExtension->FullLinkName.Buffer);
|
|
}
|
|
IoDeleteDevice(deviceObject);
|
|
|
|
OkCleanup: ;
|
|
ExFreePool(ConfigData->NtNameForPort.Buffer);
|
|
ExFreePool(ConfigData->FriendlyName.Buffer);
|
|
ExFreePool(ConfigData);
|
|
ExFreePool(uniNameString.Buffer);
|
|
|
|
}
|
|
|
|
VOID
|
|
UniLogError(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT DeviceObject OPTIONAL,
|
|
IN ULONG SequenceNumber,
|
|
IN UCHAR MajorFunctionCode,
|
|
IN UCHAR RetryCount,
|
|
IN ULONG UniqueErrorValue,
|
|
IN NTSTATUS FinalStatus,
|
|
IN NTSTATUS SpecificIOStatus,
|
|
IN ULONG LengthOfInsert1,
|
|
IN PWCHAR Insert1,
|
|
IN ULONG LengthOfInsert2,
|
|
IN PWCHAR Insert2
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine allocates an error log entry, copies the supplied data
|
|
to it, and requests that it be written to the error log file.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - A pointer to the driver object for the device.
|
|
|
|
DeviceObject - A pointer to the device object associated with the
|
|
device that had the error, early in initialization, one may not
|
|
yet exist.
|
|
|
|
SequenceNumber - A ulong value that is unique to an IRP over the
|
|
life of the irp in this driver - 0 generally means an error not
|
|
associated with an irp.
|
|
|
|
MajorFunctionCode - If there is an error associated with the irp,
|
|
this is the major function code of that irp.
|
|
|
|
RetryCount - The number of times a particular operation has been
|
|
retried.
|
|
|
|
UniqueErrorValue - A unique long word that identifies the particular
|
|
call to this function.
|
|
|
|
FinalStatus - The final status given to the irp that was associated
|
|
with this error. If this log entry is being made during one of
|
|
the retries this value will be STATUS_SUCCESS.
|
|
|
|
SpecificIOStatus - The IO status for a particular error.
|
|
|
|
LengthOfInsert1 - The length in bytes (including the terminating NULL)
|
|
of the first insertion string.
|
|
|
|
Insert1 - The first insertion string.
|
|
|
|
LengthOfInsert2 - The length in bytes (including the terminating NULL)
|
|
of the second insertion string. NOTE, there must
|
|
be a first insertion string for their to be
|
|
a second insertion string.
|
|
|
|
Insert2 - The second insertion string.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PIO_ERROR_LOG_PACKET errorLogEntry;
|
|
|
|
PVOID objectToUse;
|
|
PUCHAR ptrToFirstInsert;
|
|
PUCHAR ptrToSecondInsert;
|
|
|
|
|
|
if (ARGUMENT_PRESENT(DeviceObject)) {
|
|
|
|
objectToUse = DeviceObject;
|
|
|
|
} else {
|
|
|
|
objectToUse = DriverObject;
|
|
|
|
}
|
|
|
|
errorLogEntry = IoAllocateErrorLogEntry(
|
|
objectToUse,
|
|
(UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
|
|
LengthOfInsert1 +
|
|
LengthOfInsert2)
|
|
);
|
|
|
|
if ( errorLogEntry != NULL ) {
|
|
|
|
errorLogEntry->ErrorCode = SpecificIOStatus;
|
|
errorLogEntry->SequenceNumber = SequenceNumber;
|
|
errorLogEntry->MajorFunctionCode = MajorFunctionCode;
|
|
errorLogEntry->RetryCount = RetryCount;
|
|
errorLogEntry->UniqueErrorValue = UniqueErrorValue;
|
|
errorLogEntry->FinalStatus = FinalStatus;
|
|
|
|
ptrToFirstInsert = (PUCHAR)&errorLogEntry->DumpData[0];
|
|
|
|
ptrToSecondInsert = ptrToFirstInsert + LengthOfInsert1;
|
|
|
|
if (LengthOfInsert1) {
|
|
|
|
errorLogEntry->NumberOfStrings = 1;
|
|
errorLogEntry->StringOffset = (USHORT)(ptrToFirstInsert -
|
|
(PUCHAR)errorLogEntry);
|
|
RtlCopyMemory(
|
|
ptrToFirstInsert,
|
|
Insert1,
|
|
LengthOfInsert1
|
|
);
|
|
|
|
if (LengthOfInsert2) {
|
|
|
|
errorLogEntry->NumberOfStrings = 2;
|
|
RtlCopyMemory(
|
|
ptrToSecondInsert,
|
|
Insert2,
|
|
LengthOfInsert2
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
IoWriteErrorLogEntry(errorLogEntry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
UniDispatch(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
{
|
|
|
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if ((deviceExtension->PassThrough != MODEM_NOPASSTHROUGH) ||
|
|
(irpSp->FileObject->FsContext)) {
|
|
|
|
Irp->CurrentLocation++;
|
|
Irp->Tail.Overlay.CurrentStackLocation++;
|
|
return IoCallDriver(
|
|
deviceExtension->AttachedDeviceObject,
|
|
Irp
|
|
);
|
|
|
|
} else {
|
|
|
|
Irp->IoStatus.Status = STATUS_PORT_DISCONNECTED;
|
|
Irp->IoStatus.Information=0L;
|
|
IoCompleteRequest(
|
|
Irp,
|
|
IO_NO_INCREMENT
|
|
);
|
|
return STATUS_PORT_DISCONNECTED;
|
|
|
|
}
|
|
|
|
}
|