525 lines
13 KiB
C
525 lines
13 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1996 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
ntentry.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
NT System entry points for ATMARP.
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
Who When What
|
||
|
-------- -------- ----------------------------------------------
|
||
|
arvindm 08-08-96 Created
|
||
|
|
||
|
Notes:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#ifdef ATMARP_WIN98
|
||
|
|
||
|
#undef BINARY_COMPATIBLE
|
||
|
#define BINARY_COMPATIBLE 0
|
||
|
|
||
|
#endif // ATMARP_WIN98
|
||
|
|
||
|
#include <precomp.h>
|
||
|
|
||
|
#define _FILENUMBER 'NETN'
|
||
|
|
||
|
//
|
||
|
// The INIT code is discardable
|
||
|
//
|
||
|
#ifdef ALLOC_PRAGMA
|
||
|
|
||
|
#pragma alloc_text(INIT, DriverEntry)
|
||
|
|
||
|
#endif // ALLOC_PRAGMA
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
DriverEntry(
|
||
|
IN PDRIVER_OBJECT pDriverObject,
|
||
|
IN PUNICODE_STRING pRegistryPath
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is the "init" routine, called by the system when the ATMARP
|
||
|
module is loaded. We initialize all our global objects, fill in our
|
||
|
Dispatch and Unload routine addresses in the driver object, and create
|
||
|
a device object for receiving I/O requests on (IOCTLs).
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pDriverObject - Pointer to the driver object created by the system.
|
||
|
pRegistryPath - Pointer to our global registry path. This is ignored.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NT Status code: STATUS_SUCCESS if successful, error code otherwise.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
PDEVICE_OBJECT pDeviceObject;
|
||
|
UNICODE_STRING DeviceName;
|
||
|
INT i;
|
||
|
|
||
|
AADEBUGP(AAD_INFO, ("DriverEntry: entered, pAtmArpGlobal 0x%x\n", pAtmArpGlobalInfo));
|
||
|
AADEBUGP(AAD_FATAL, ("&AaDebugLevel: 0x%x, AaDebugLevel now is %d\n",
|
||
|
&AaDebugLevel, AaDebugLevel));
|
||
|
AADEBUGP(AAD_FATAL, ("&AaDataDebugLevel: 0x%x, AaDataDebugLevel now is %d\n",
|
||
|
&AaDataDebugLevel, AaDataDebugLevel));
|
||
|
#ifdef IPMCAST
|
||
|
AAMCDEBUGP(AAD_FATAL, ("&AaMcDebugLevel: 0x%x, AaMcDebugLevel now is %d\n",
|
||
|
&AaMcDebugLevel, AaMcDebugLevel));
|
||
|
#endif
|
||
|
#if DBG
|
||
|
AADEBUGP(AAD_FATAL, ("To skip everything set AaSkipAll at 0x%x to 1\n",
|
||
|
&AaSkipAll));
|
||
|
if (AaSkipAll)
|
||
|
{
|
||
|
AADEBUGP(AAD_ERROR, ("Aborting DriverEntry\n"));
|
||
|
return (STATUS_UNSUCCESSFUL);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// Initialize our globals.
|
||
|
//
|
||
|
AtmArpInitGlobals();
|
||
|
|
||
|
#ifdef GPC
|
||
|
//
|
||
|
// Init GPC
|
||
|
//
|
||
|
AtmArpGpcInitialize();
|
||
|
#endif // GPC
|
||
|
|
||
|
#if !BINARY_COMPATIBLE
|
||
|
//
|
||
|
// Initialize the Driver Object.
|
||
|
//
|
||
|
pDriverObject->DriverUnload = Unload;
|
||
|
pDriverObject->FastIoDispatch = NULL;
|
||
|
for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
|
||
|
{
|
||
|
pDriverObject->MajorFunction[i] = Dispatch;
|
||
|
}
|
||
|
|
||
|
#ifdef CUBDD
|
||
|
pDriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
|
||
|
AtmArpInternalDeviceControl;
|
||
|
#endif // CUBDD
|
||
|
|
||
|
#ifdef ATMARP_WMI
|
||
|
|
||
|
pDriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = AtmArpWmiDispatch;
|
||
|
|
||
|
#endif // ATMARP_WMI
|
||
|
|
||
|
pAtmArpGlobalInfo->pDriverObject = (PVOID)pDriverObject;
|
||
|
|
||
|
//
|
||
|
// Create a device object for the ATMARP module.
|
||
|
//
|
||
|
RtlInitUnicodeString(&DeviceName, ATMARP_DEVICE_NAME);
|
||
|
|
||
|
Status = IoCreateDevice(
|
||
|
pDriverObject,
|
||
|
0,
|
||
|
&DeviceName,
|
||
|
FILE_DEVICE_NETWORK,
|
||
|
0,
|
||
|
FALSE,
|
||
|
&pDeviceObject
|
||
|
);
|
||
|
|
||
|
if (NT_SUCCESS(Status))
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// Set up a symbolic name for interaction with the user-mode
|
||
|
// admin application.
|
||
|
//
|
||
|
#define ATMARP_SYMBOLIC_NAME L"\\DosDevices\\ATMARPC"
|
||
|
UNICODE_STRING SymbolicName;
|
||
|
RtlInitUnicodeString(&SymbolicName, ATMARP_SYMBOLIC_NAME);
|
||
|
IoCreateSymbolicLink(&SymbolicName, &DeviceName);
|
||
|
|
||
|
//
|
||
|
// Initialize the Device Object.
|
||
|
//
|
||
|
pDeviceObject->Flags |= DO_DIRECT_IO;
|
||
|
|
||
|
//
|
||
|
// Retain the device object pointer -- we'll need this
|
||
|
// if/when we are asked to unload ourselves.
|
||
|
//
|
||
|
pAtmArpGlobalInfo->pDeviceObject = (PVOID)pDeviceObject;
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pDeviceObject = NULL;
|
||
|
}
|
||
|
|
||
|
#endif // !BINARY_COMPATIBLE
|
||
|
|
||
|
//
|
||
|
// Fill in our Protocol and Client characteristics structures.
|
||
|
//
|
||
|
AA_SET_MEM(&AtmArpProtocolCharacteristics, 0, sizeof(AtmArpProtocolCharacteristics));
|
||
|
AtmArpProtocolCharacteristics.MajorNdisVersion = ATMARP_NDIS_MAJOR_VERSION;
|
||
|
AtmArpProtocolCharacteristics.MinorNdisVersion = ATMARP_NDIS_MINOR_VERSION;
|
||
|
AtmArpProtocolCharacteristics.OpenAdapterCompleteHandler = AtmArpOpenAdapterCompleteHandler;
|
||
|
AtmArpProtocolCharacteristics.CloseAdapterCompleteHandler = AtmArpCloseAdapterCompleteHandler;
|
||
|
AtmArpProtocolCharacteristics.SendCompleteHandler = AtmArpSendCompleteHandler;
|
||
|
AtmArpProtocolCharacteristics.TransferDataCompleteHandler = AtmArpTransferDataCompleteHandler;
|
||
|
AtmArpProtocolCharacteristics.ResetCompleteHandler = AtmArpResetCompleteHandler;
|
||
|
AtmArpProtocolCharacteristics.RequestCompleteHandler = AtmArpRequestCompleteHandler;
|
||
|
AtmArpProtocolCharacteristics.ReceiveHandler = AtmArpReceiveHandler;
|
||
|
AtmArpProtocolCharacteristics.ReceiveCompleteHandler = AtmArpReceiveCompleteHandler;
|
||
|
AtmArpProtocolCharacteristics.StatusHandler = AtmArpStatusHandler;
|
||
|
AtmArpProtocolCharacteristics.StatusCompleteHandler = AtmArpStatusCompleteHandler;
|
||
|
NdisInitUnicodeString(
|
||
|
&AtmArpProtocolCharacteristics.Name,
|
||
|
ATMARP_LL_NAME
|
||
|
);
|
||
|
AtmArpProtocolCharacteristics.ReceivePacketHandler = AtmArpReceivePacketHandler;
|
||
|
AtmArpProtocolCharacteristics.BindAdapterHandler = AtmArpBindAdapterHandler;
|
||
|
AtmArpProtocolCharacteristics.UnbindAdapterHandler = AtmArpUnbindAdapterHandler;
|
||
|
AtmArpProtocolCharacteristics.UnloadHandler = (UNLOAD_PROTOCOL_HANDLER)AtmArpUnloadProtocol;
|
||
|
#ifdef _PNP_POWER_
|
||
|
AtmArpProtocolCharacteristics.PnPEventHandler = AtmArpPnPEventHandler;
|
||
|
#endif // _PNP_POWER_
|
||
|
AtmArpProtocolCharacteristics.CoSendCompleteHandler = AtmArpCoSendCompleteHandler;
|
||
|
AtmArpProtocolCharacteristics.CoStatusHandler = AtmArpCoStatusHandler;
|
||
|
AtmArpProtocolCharacteristics.CoReceivePacketHandler = AtmArpCoReceivePacketHandler;
|
||
|
AtmArpProtocolCharacteristics.CoAfRegisterNotifyHandler = AtmArpCoAfRegisterNotifyHandler;
|
||
|
|
||
|
AA_SET_MEM(&AtmArpClientCharacteristics, 0, sizeof(AtmArpClientCharacteristics));
|
||
|
AtmArpClientCharacteristics.MajorVersion = ATMARP_NDIS_MAJOR_VERSION;
|
||
|
AtmArpClientCharacteristics.MinorVersion = ATMARP_NDIS_MINOR_VERSION;
|
||
|
AtmArpClientCharacteristics.ClCreateVcHandler = AtmArpCreateVcHandler;
|
||
|
AtmArpClientCharacteristics.ClDeleteVcHandler = AtmArpDeleteVcHandler;
|
||
|
AtmArpClientCharacteristics.ClRequestHandler = AtmArpCoRequestHandler;
|
||
|
AtmArpClientCharacteristics.ClRequestCompleteHandler = AtmArpCoRequestCompleteHandler;
|
||
|
AtmArpClientCharacteristics.ClOpenAfCompleteHandler = AtmArpOpenAfCompleteHandler;
|
||
|
AtmArpClientCharacteristics.ClCloseAfCompleteHandler = AtmArpCloseAfCompleteHandler;
|
||
|
AtmArpClientCharacteristics.ClRegisterSapCompleteHandler = AtmArpRegisterSapCompleteHandler;
|
||
|
AtmArpClientCharacteristics.ClDeregisterSapCompleteHandler = AtmArpDeregisterSapCompleteHandler;
|
||
|
AtmArpClientCharacteristics.ClMakeCallCompleteHandler = AtmArpMakeCallCompleteHandler;
|
||
|
AtmArpClientCharacteristics.ClModifyCallQoSCompleteHandler = AtmArpModifyQosCompleteHandler;
|
||
|
AtmArpClientCharacteristics.ClCloseCallCompleteHandler = AtmArpCloseCallCompleteHandler;
|
||
|
AtmArpClientCharacteristics.ClAddPartyCompleteHandler = AtmArpAddPartyCompleteHandler;
|
||
|
AtmArpClientCharacteristics.ClDropPartyCompleteHandler = AtmArpDropPartyCompleteHandler;
|
||
|
AtmArpClientCharacteristics.ClIncomingCallHandler = AtmArpIncomingCallHandler;
|
||
|
AtmArpClientCharacteristics.ClIncomingCallQoSChangeHandler = (CL_INCOMING_CALL_QOS_CHANGE_HANDLER)NULL;
|
||
|
AtmArpClientCharacteristics.ClIncomingCloseCallHandler = AtmArpIncomingCloseHandler;
|
||
|
AtmArpClientCharacteristics.ClIncomingDropPartyHandler = AtmArpIncomingDropPartyHandler;
|
||
|
AtmArpClientCharacteristics.ClCallConnectedHandler = AtmArpCallConnectedHandler;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
//
|
||
|
// Register ourselves as a protocol with NDIS.
|
||
|
//
|
||
|
NdisRegisterProtocol(
|
||
|
&Status,
|
||
|
&(pAtmArpGlobalInfo->ProtocolHandle),
|
||
|
&AtmArpProtocolCharacteristics,
|
||
|
sizeof(AtmArpProtocolCharacteristics)
|
||
|
);
|
||
|
|
||
|
if (Status != NDIS_STATUS_SUCCESS)
|
||
|
{
|
||
|
AADEBUGP(AAD_FATAL,
|
||
|
("NdisRegisterProtocol failed: %x\n", Status));
|
||
|
pAtmArpGlobalInfo->ProtocolHandle = NULL;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
#ifdef NEWARP
|
||
|
//
|
||
|
// Register ourselves as an ARP Module with IP.
|
||
|
//
|
||
|
{
|
||
|
NDIS_STRING AtmArpName;
|
||
|
|
||
|
#if IFCHANGE1
|
||
|
#ifndef ATMARP_WIN98
|
||
|
IP_CHANGE_INDEX IpChangeIndex;
|
||
|
IP_RESERVE_INDEX IpReserveIndex;
|
||
|
IP_DERESERVE_INDEX IpDereserveIndex;
|
||
|
#endif
|
||
|
#endif // IFCHANGE1
|
||
|
|
||
|
NdisInitUnicodeString(&AtmArpName, ATMARP_UL_NAME);
|
||
|
|
||
|
Status = IPRegisterARP(
|
||
|
&AtmArpName,
|
||
|
IP_ARP_BIND_VERSION,
|
||
|
AtmArpBindAdapterHandler,
|
||
|
&(pAtmArpGlobalInfo->pIPAddInterfaceRtn),
|
||
|
&(pAtmArpGlobalInfo->pIPDelInterfaceRtn),
|
||
|
&(pAtmArpGlobalInfo->pIPBindCompleteRtn),
|
||
|
#if P2MP
|
||
|
&(pAtmArpGlobalInfo->pIPAddLinkRtn),
|
||
|
&(pAtmArpGlobalInfo->pIpDeleteLinkRtn),
|
||
|
#endif // P2MP
|
||
|
#if IFCHANGE1
|
||
|
#ifndef ATMARP_WIN98
|
||
|
//
|
||
|
// Following 3 are placeholders -- we don't use this information.
|
||
|
// See 10/14/1998 entry in notes.txt
|
||
|
//
|
||
|
&IpChangeIndex,
|
||
|
&IpReserveIndex,
|
||
|
&IpDereserveIndex,
|
||
|
#endif // ATMARP_WIN98
|
||
|
#endif // IFCHANGE1
|
||
|
&(pAtmArpGlobalInfo->ARPRegisterHandle)
|
||
|
);
|
||
|
|
||
|
if (!NT_SUCCESS(Status))
|
||
|
{
|
||
|
|
||
|
AADEBUGP(AAD_FATAL, ("DriverEntry: IPRegisterARP FAILS. Status = 0x%08lx\n", Status));
|
||
|
pAtmArpGlobalInfo->ARPRegisterHandle = NULL;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
#endif // NEWARP
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
while (FALSE);
|
||
|
|
||
|
if (Status != NDIS_STATUS_SUCCESS)
|
||
|
{
|
||
|
NDIS_STATUS CleanupStatus;
|
||
|
|
||
|
//
|
||
|
// Clean up.
|
||
|
//
|
||
|
|
||
|
#if !BINARY_COMPATIBLE
|
||
|
if (pDeviceObject != NULL)
|
||
|
{
|
||
|
UNICODE_STRING SymbolicName;
|
||
|
RtlInitUnicodeString(&SymbolicName, ATMARP_SYMBOLIC_NAME);
|
||
|
IoDeleteSymbolicLink(&SymbolicName);
|
||
|
IoDeleteDevice(pDeviceObject);
|
||
|
pDeviceObject = NULL;
|
||
|
}
|
||
|
#endif // !BINARY_COMPATIBLE
|
||
|
|
||
|
if (pAtmArpGlobalInfo->ProtocolHandle)
|
||
|
{
|
||
|
NdisDeregisterProtocol(
|
||
|
&CleanupStatus,
|
||
|
pAtmArpGlobalInfo->ProtocolHandle
|
||
|
);
|
||
|
|
||
|
pAtmArpGlobalInfo->ProtocolHandle = NULL;
|
||
|
}
|
||
|
|
||
|
if (pAtmArpGlobalInfo->ARPRegisterHandle != NULL)
|
||
|
{
|
||
|
CleanupStatus = IPDeregisterARP(pAtmArpGlobalInfo->ARPRegisterHandle);
|
||
|
AA_ASSERT(CleanupStatus == NDIS_STATUS_SUCCESS);
|
||
|
|
||
|
pAtmArpGlobalInfo->ARPRegisterHandle = NULL;
|
||
|
}
|
||
|
|
||
|
#ifdef GPC
|
||
|
//
|
||
|
// DeInit GPC
|
||
|
//
|
||
|
AtmArpGpcShutdown();
|
||
|
#endif // GPC
|
||
|
|
||
|
}
|
||
|
|
||
|
return (Status);
|
||
|
}
|
||
|
|
||
|
|
||
|
#if !BINARY_COMPATIBLE
|
||
|
|
||
|
NTSTATUS
|
||
|
Dispatch(
|
||
|
IN PDEVICE_OBJECT pDeviceObject,
|
||
|
IN PIRP pIrp
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine is called by the system when there is an IRP
|
||
|
to be processed.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pDeviceObject - Pointer to device object we created for ourselves.
|
||
|
pIrp - Pointer to IRP to be processed.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NT Status code.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NTSTATUS Status; // Return value
|
||
|
PIO_STACK_LOCATION pIrpStack;
|
||
|
PVOID pIoBuffer; // Values in/out
|
||
|
ULONG InputBufferLength; // Length of input parameters
|
||
|
ULONG OutputBufferLength; // Space for output values
|
||
|
|
||
|
//
|
||
|
// Initialize
|
||
|
//
|
||
|
Status = (NTSTATUS)NDIS_STATUS_SUCCESS;
|
||
|
pIrp->IoStatus.Status = (NTSTATUS)NDIS_STATUS_SUCCESS;
|
||
|
pIrp->IoStatus.Information = 0;
|
||
|
|
||
|
//
|
||
|
// Get all information in the IRP
|
||
|
//
|
||
|
pIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
|
||
|
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
|
||
|
InputBufferLength = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
|
||
|
OutputBufferLength = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
|
||
|
|
||
|
switch (pIrpStack->MajorFunction)
|
||
|
{
|
||
|
case IRP_MJ_CREATE:
|
||
|
AADEBUGP(AAD_INFO, ("Dispatch: IRP_MJ_CREATE\n"));
|
||
|
//
|
||
|
// Return a pointer to the first ATMARP interface available, as the
|
||
|
// FsContext.
|
||
|
//
|
||
|
pIrpStack->FileObject->FsContext = NULL; // Initialize
|
||
|
if (pAtmArpGlobalInfo->pAdapterList != (PATMARP_ADAPTER)NULL)
|
||
|
{
|
||
|
pIrpStack->FileObject->FsContext =
|
||
|
(PVOID)(pAtmArpGlobalInfo->pAdapterList->pInterfaceList);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case IRP_MJ_CLOSE:
|
||
|
AADEBUGP(AAD_INFO, ("Dispatch: IRP_MJ_CLOSE\n"));
|
||
|
break;
|
||
|
|
||
|
case IRP_MJ_CLEANUP:
|
||
|
AADEBUGP(AAD_INFO, ("Dispatch: IRP_MJ_CLEANUP\n"));
|
||
|
break;
|
||
|
|
||
|
case IRP_MJ_DEVICE_CONTROL:
|
||
|
AADEBUGP(AAD_INFO, ("Dispatch: IRP_MJ_DEVICE_CONTROL\n"));
|
||
|
|
||
|
#ifndef ATMARP_WIN98
|
||
|
Status = AtmArpHandleIoctlRequest(pIrp, pIrpStack);
|
||
|
#endif // ATMARP_WIN98
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
AADEBUGP(AAD_INFO, ("Dispatch: IRP: Unknown major function 0x%x\n",
|
||
|
pIrpStack->MajorFunction));
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (Status != (NTSTATUS)NDIS_STATUS_PENDING)
|
||
|
{
|
||
|
pIrp->IoStatus.Status = Status;
|
||
|
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
|
||
|
}
|
||
|
|
||
|
return (Status);
|
||
|
|
||
|
}
|
||
|
|
||
|
#endif // !BINARY_COMPATIBLE
|
||
|
|
||
|
|
||
|
VOID
|
||
|
Unload(
|
||
|
IN PDRIVER_OBJECT pDriverObject
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine is called by the system prior to unloading us.
|
||
|
Currently, we just undo everything we did in DriverEntry,
|
||
|
that is, de-register ourselves as an NDIS protocol, and delete
|
||
|
the device object we had created.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pDriverObject - Pointer to the driver object created by the system.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NDIS_STATUS Status;
|
||
|
#if DBG
|
||
|
AA_IRQL EntryIrq, ExitIrq;
|
||
|
#endif
|
||
|
|
||
|
AA_GET_ENTRY_IRQL(EntryIrq);
|
||
|
|
||
|
AADEBUGP(AAD_INFO, ("Unload Entered!\n"));
|
||
|
|
||
|
if (pAtmArpGlobalInfo->ARPRegisterHandle != NULL)
|
||
|
{
|
||
|
Status = IPDeregisterARP(pAtmArpGlobalInfo->ARPRegisterHandle);
|
||
|
AA_ASSERT(Status == NDIS_STATUS_SUCCESS);
|
||
|
}
|
||
|
|
||
|
AtmArpUnloadProtocol();
|
||
|
|
||
|
//
|
||
|
// Delay for a while.
|
||
|
//
|
||
|
AADEBUGP(AAD_INFO, ("Unload: will delay for a while...\n"));
|
||
|
|
||
|
NdisInitializeEvent(&pAtmArpGlobalInfo->Block.Event);
|
||
|
|
||
|
NdisWaitEvent(&pAtmArpGlobalInfo->Block.Event, 250);
|
||
|
|
||
|
#if !BINARY_COMPATIBLE
|
||
|
{
|
||
|
UNICODE_STRING SymbolicName;
|
||
|
RtlInitUnicodeString(&SymbolicName, ATMARP_SYMBOLIC_NAME);
|
||
|
IoDeleteSymbolicLink(&SymbolicName);
|
||
|
|
||
|
//
|
||
|
// Delete our device object.
|
||
|
//
|
||
|
IoDeleteDevice((PDEVICE_OBJECT)pAtmArpGlobalInfo->pDeviceObject);
|
||
|
}
|
||
|
#endif // !BINARY_COMPATIBLE
|
||
|
|
||
|
AADEBUGP(AAD_INFO, ("Unload done!\n"));
|
||
|
AA_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
|