windows-nt/Source/XPSP1/NT/net/rras/ip/nat/natwmi.c

1320 lines
32 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
wmi.c
Abstract:
This file contains the code for handling WMI requests.
Author:
Jonathan Burstein (jonburs) 24-Jan-2000
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
#if NAT_WMI
//
// Data structures for identifying the guids and reporting them to
// WMI. Since the WMILIB callbacks pass an index into the guid list we make
// definitions for the various guids indicies.
//
GUID ConnectionCreationEventGuid = MSIPNAT_ConnectionCreationEventGuid;
GUID ConnectionDeletionEventGuid = MSIPNAT_ConnectionDeletionEventGuid;
GUID PacketDroppedEventGuid = MSIPNAT_PacketDroppedEventGuid;
WMIGUIDREGINFO NatWmiGuidList[] =
{
{
&ConnectionCreationEventGuid,
1,
WMIREG_FLAG_TRACED_GUID | WMIREG_FLAG_TRACE_CONTROL_GUID
},
{
&ConnectionDeletionEventGuid,
1,
WMIREG_FLAG_TRACED_GUID
},
{
&PacketDroppedEventGuid,
1,
WMIREG_FLAG_TRACED_GUID | WMIREG_FLAG_TRACE_CONTROL_GUID
}
};
#define NatWmiGuidCount (sizeof(NatWmiGuidList) / sizeof(WMIGUIDREGINFO))
//
// Enabled events and associated log handles.
//
// NatWmiLogHandles should only be accessed while holding
// NatWmiLock.
//
// NatWmiEnabledEvents should only be modified while holding
// NatWmiLock. It may be read without holding the lock, according
// to these rules:
//
// If NatWmiEnabledEvents[ Event ] is 0, the that event is definately
// _not_ enabled, and there is no need to grab the spin lock.
//
// If NatWmiEnabledEvents[ Event ] is 1, the event _may_ be enabled.
// To determine if the event is truly enabled, grab the spin lock and
// see if NatWmiLogHandles[ Event ] is not 0.
//
LONG NatWmiEnabledEvents[ NatWmiGuidCount ];
UINT64 NatWmiLogHandles[ NatWmiGuidCount ];
KSPIN_LOCK NatWmiLock;
//
// Context block for WMILib routines
//
WMILIB_CONTEXT WmilibContext;
//
// MOF Resource Name
//
WCHAR IPNATMofResource[] = L"IPNATMofResource";
//
// WMI Base instance name
//
WCHAR BaseInstanceName[] = L"IPNat";
//
// Function Prototypes
//
NTSTATUS
NatpWmiFunctionControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN ULONG GuidIndex,
IN WMIENABLEDISABLECONTROL Function,
IN BOOLEAN Enable
);
NTSTATUS
NatpExecuteWmiMethod(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN ULONG GuidIndex,
IN ULONG InstanceIndex,
IN ULONG MethodId,
IN ULONG InBufferSize,
IN ULONG OutBufferSize,
IN PUCHAR Buffer
);
NTSTATUS
NatpSetWmiDataItem(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN ULONG InstanceIndex,
IN ULONG GuidIndex,
IN ULONG DataItemId,
IN ULONG BufferSize,
IN PUCHAR Buffer
);
NTSTATUS
NatpSetWmiDataBlock(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN ULONG GuidIndex,
IN ULONG InstanceIndex,
IN ULONG BufferSize,
IN PUCHAR Buffer
);
NTSTATUS
NatpQueryWmiDataBlock(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN ULONG GuidIndex,
IN ULONG InstanceIndex,
IN ULONG InstanceCount,
IN OUT PULONG InstanceLengthArray,
IN ULONG BufferAvail,
OUT PUCHAR Buffer
);
NTSTATUS
NatpQueryWmiRegInfo(
IN PDEVICE_OBJECT DeviceObject,
OUT ULONG *RegFlags,
OUT PUNICODE_STRING InstanceName,
OUT PUNICODE_STRING *RegistryPath,
OUT PUNICODE_STRING MofResourceName,
OUT PDEVICE_OBJECT *Pdo
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, NatpQueryWmiRegInfo)
#pragma alloc_text(PAGE, NatpQueryWmiDataBlock)
#pragma alloc_text(PAGE, NatpSetWmiDataBlock)
#pragma alloc_text(PAGE, NatpSetWmiDataItem)
#pragma alloc_text(PAGE, NatpExecuteWmiMethod)
#pragma alloc_text(PAGE, NatpWmiFunctionControl)
#endif
NTSTATUS
NatExecuteSystemControl(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PBOOLEAN ShouldComplete
)
/*++
Routine Description:
Dispatch routine for System Control IRPs (MajorFunction ==
IRP_MJ_SYSTEM_CONTROL)
Arguments:
DeviceObject - The device object for the firewall
Irp - Io Request Packet
ShouldComplete - [out] true on exit if the IRP needs to be complete
Return Value:
NT status code
--*/
{
NTSTATUS status;
SYSCTL_IRP_DISPOSITION disposition;
CALLTRACE(( "NatExecuteSystemControl\n" ));
*ShouldComplete = FALSE;
//
// Call Wmilib helper function to crack the irp. If this is a wmi irp
// that is targetted for this device then WmiSystemControl will callback
// at the appropriate callback routine.
//
status = WmiSystemControl(
&WmilibContext,
DeviceObject,
Irp,
&disposition
);
switch(disposition)
{
case IrpProcessed:
{
//
// This irp has been processed and may be completed or pending.
//
break;
}
case IrpNotCompleted:
{
//
// This irp has not been completed, but has been fully processed.
// so we need to complete it
//
*ShouldComplete = TRUE;
break;
}
case IrpNotWmi:
{
//
// Not an WMI IRP -- just complete it. We don't handle
// IRP_MJ_SYSTEM_CONTROL in any other way
//
*ShouldComplete = TRUE;
break;
}
case IrpForward:
default:
{
//
// We really should never get here...
//
ASSERT(FALSE);
break;
}
}
if( !NT_SUCCESS( status ))
{
ERROR(( "NAT: Error (%08x) in NatExecuteSystemControl\n", status ));
}
return status;
} //NatExecuteSystemControl
VOID
NatInitializeWMI(
VOID
)
/*++
Routine Description:
This routine is called to initialize WMI.
Arguments:
none.
Return Value:
none.
--*/
{
NTSTATUS status;
CALLTRACE(( "NatInitializeWMI\n" ));
//
// Initialize the spinlock that protects the structure below.
//
KeInitializeSpinLock( &NatWmiLock );
//
// Zero-out the event tracking structure
//
RtlZeroMemory( NatWmiEnabledEvents, sizeof( NatWmiEnabledEvents ));
RtlZeroMemory( NatWmiLogHandles, sizeof( NatWmiLogHandles ));
//
// Fill in the WMILIB_CONTEXT structure with a pointer to the
// callback routines and a pointer to the list of guids
// supported by the driver
//
WmilibContext.GuidCount = NatWmiGuidCount;
WmilibContext.GuidList = NatWmiGuidList;
WmilibContext.QueryWmiRegInfo = NatpQueryWmiRegInfo;
WmilibContext.QueryWmiDataBlock = NatpQueryWmiDataBlock;
WmilibContext.SetWmiDataBlock = NatpSetWmiDataBlock;
WmilibContext.SetWmiDataItem = NatpSetWmiDataItem;
WmilibContext.ExecuteWmiMethod = NatpExecuteWmiMethod;
WmilibContext.WmiFunctionControl = NatpWmiFunctionControl;
//
// Register w/ WMI
//
status = IoWMIRegistrationControl(
NatDeviceObject,
WMIREG_ACTION_REGISTER
);
if( !NT_SUCCESS( status ))
{
ERROR(( "Nat: Error initializing WMI (%08x)\n", status ));
}
} // NatInitializeWMI
VOID
FASTCALL
NatLogConnectionCreation(
ULONG LocalAddress,
ULONG RemoteAddress,
USHORT LocalPort,
USHORT RemotePort,
UCHAR Protocol,
BOOLEAN InboundConnection
)
/*++
Routine Description:
This routine is called to log the creation of a TCP/UDP connection
(mapping). If this event is not enabled, no action is taken.
Arguments:
Return Value:
none.
--*/
{
NTSTATUS Status;
KIRQL Irql;
UINT64 Logger;
ULONG Size;
UCHAR Buffer[ sizeof(EVENT_TRACE_HEADER) + sizeof(MSIPNAT_ConnectionCreationEvent) ];
PEVENT_TRACE_HEADER EventHeaderp;
PMSIPNAT_ConnectionCreationEvent EventDatap;
CALLTRACE(( "NatLogConnectionCreation\n" ));
if( !NatWmiEnabledEvents[ NAT_WMI_CONNECTION_CREATION_EVENT ] )
{
//
// Event not enabled -- exit quickly.
//
TRACE(WMI, ("NatLogConnectionCreation: Event not enabled\n"));
return;
}
KeAcquireSpinLock( &NatWmiLock, &Irql );
Logger = NatWmiLogHandles[ NAT_WMI_CONNECTION_CREATION_EVENT ];
KeReleaseSpinLock( &NatWmiLock, Irql );
if( Logger )
{
//
// Zero out the buffer
//
RtlZeroMemory( Buffer, sizeof( Buffer ));
//
// Locate structure locations within the buffer
//
EventHeaderp = (PEVENT_TRACE_HEADER) Buffer;
EventDatap =
(PMSIPNAT_ConnectionCreationEvent) ((PUCHAR)Buffer + sizeof(EVENT_TRACE_HEADER));
//
// Fill out the event header
//
EventHeaderp->Size = sizeof( Buffer );
EventHeaderp->Version = 0;
EventHeaderp->GuidPtr = (ULONGLONG) &ConnectionCreationEventGuid;
EventHeaderp->Flags = WNODE_FLAG_TRACED_GUID
| WNODE_FLAG_USE_GUID_PTR
| WNODE_FLAG_USE_TIMESTAMP;
((PWNODE_HEADER)EventHeaderp)->HistoricalContext = Logger;
KeQuerySystemTime( &EventHeaderp->TimeStamp );
//
// Fill out event data
//
EventDatap->LocalAddress = LocalAddress;
EventDatap->RemoteAddress = RemoteAddress,
EventDatap->LocalPort = LocalPort;
EventDatap->RemotePort = RemotePort;
EventDatap->Protocol = Protocol;
EventDatap->InboundConnection = InboundConnection;
//
// Fire the event. Since this is a trace event and not a standard
// WMI event, IoWMIWriteEvent will not attempt to free the buffer
// passed into it.
//
Status = IoWMIWriteEvent( Buffer );
if( !NT_SUCCESS( Status ))
{
TRACE(
WMI,
("NatLogConnectionCreation: IoWMIWriteEvent returned %08x\n", Status )
);
}
}
else
{
TRACE(WMI, ("NatLogConnectionCreation: No logging handle\n"));
}
} // NatLogConnectionCreation
VOID
FASTCALL
NatLogConnectionDeletion(
ULONG LocalAddress,
ULONG RemoteAddress,
USHORT LocalPort,
USHORT RemotePort,
UCHAR Protocol,
BOOLEAN InboundConnection
)
/*++
Routine Description:
This routine is called to log the deletion of a TCP/UDP connection
(mapping). If this event is not enabled, no action is taken.
Arguments:
Return Value:
none.
--*/
{
NTSTATUS Status;
KIRQL Irql;
UINT64 Logger;
ULONG Size;
UCHAR Buffer[ sizeof(EVENT_TRACE_HEADER) + sizeof(MSIPNAT_ConnectionDeletionEvent) ];
PEVENT_TRACE_HEADER EventHeaderp;
PMSIPNAT_ConnectionDeletionEvent EventDatap;
CALLTRACE(( "NatLogConnectionDeletion\n" ));
if( !NatWmiEnabledEvents[ NAT_WMI_CONNECTION_DELETION_EVENT ] )
{
//
// Event not enabled -- exit quickly.
//
TRACE(WMI, ("NatLogConnectionDeletion: Event not enabled\n"));
return;
}
KeAcquireSpinLock( &NatWmiLock, &Irql );
Logger = NatWmiLogHandles[ NAT_WMI_CONNECTION_DELETION_EVENT ];
KeReleaseSpinLock( &NatWmiLock, Irql );
if( Logger )
{
//
// Zero out the buffer
//
RtlZeroMemory( Buffer, sizeof( Buffer ));
//
// Locate structure locations within the buffer
//
EventHeaderp = (PEVENT_TRACE_HEADER) Buffer;
EventDatap =
(PMSIPNAT_ConnectionDeletionEvent) ((PUCHAR)Buffer + sizeof(EVENT_TRACE_HEADER));
//
// Fill out the event header
//
EventHeaderp->Size = sizeof( Buffer );
EventHeaderp->Version = 0;
EventHeaderp->GuidPtr = (ULONGLONG) &ConnectionDeletionEventGuid;
EventHeaderp->Flags = WNODE_FLAG_TRACED_GUID
| WNODE_FLAG_USE_GUID_PTR
| WNODE_FLAG_USE_TIMESTAMP;
((PWNODE_HEADER)EventHeaderp)->HistoricalContext = Logger;
KeQuerySystemTime( &EventHeaderp->TimeStamp );
//
// Fill out event data
//
EventDatap->LocalAddress = LocalAddress;
EventDatap->RemoteAddress = RemoteAddress,
EventDatap->LocalPort = LocalPort;
EventDatap->RemotePort = RemotePort;
EventDatap->Protocol = Protocol;
EventDatap->InboundConnection = InboundConnection;
//
// Fire the event. Since this is a trace event and not a standard
// WMI event, IoWMIWriteEvent will not attempt to free the buffer
// passed into it.
//
Status = IoWMIWriteEvent( Buffer );
if( !NT_SUCCESS( Status ))
{
TRACE(
WMI,
("NatLogConnectionDeletion: IoWMIWriteEvent returned %08x\n", Status )
);
}
}
else
{
TRACE(WMI, ("NatLogConnectionDeletion: No logging handle\n"));
}
} // NatLogConnectionDeletion
VOID
FASTCALL
NatLogDroppedPacket(
NAT_XLATE_CONTEXT *Contextp
)
/*++
Routine Description:
This routine is called to log a dropped packet. If no packet dropped
logging events are enabled, the routine will take no action.
Arguments:
Contextp - the translation context of the packet
Return Value:
none.
--*/
{
NTSTATUS Status;
KIRQL Irql;
UINT64 Logger;
ULONG Size;
IPRcvBuf *PacketBuffer;
UCHAR Protocol;
UCHAR Buffer[ sizeof(EVENT_TRACE_HEADER) + sizeof(MSIPNAT_PacketDroppedEvent) ];
PEVENT_TRACE_HEADER EventHeaderp;
PMSIPNAT_PacketDroppedEvent EventDatap;
CALLTRACE(( "NatLogDroppedPacket\n" ));
if( !NatWmiEnabledEvents[ NAT_WMI_PACKET_DROPPED_EVENT ] )
{
//
// Event not enabled -- exit quickly.
//
TRACE(WMI, ("NatLogDroppedPacket: Event not enabled\n"));
return;
}
//
// Exit if this packet has already been logged
//
if( NAT_XLATE_LOGGED( Contextp ))
{
TRACE( WMI, ("NatLogDroppedPacket: Duplicate dropped packet log attemp\n" ));
return;
}
KeAcquireSpinLock( &NatWmiLock, &Irql );
Logger = NatWmiLogHandles[ NAT_WMI_PACKET_DROPPED_EVENT ];
KeReleaseSpinLock( &NatWmiLock, Irql );
if( Logger )
{
//
// Zero out the buffer
//
RtlZeroMemory( Buffer, sizeof( Buffer ));
//
// Locate structure locations within the buffer
//
EventHeaderp = (PEVENT_TRACE_HEADER) Buffer;
EventDatap = (PMSIPNAT_PacketDroppedEvent) ((PUCHAR)Buffer + sizeof(EVENT_TRACE_HEADER));
//
// Fill out the event header
//
EventHeaderp->Size = sizeof( Buffer );
EventHeaderp->Version = 0;
EventHeaderp->GuidPtr = (ULONGLONG) &PacketDroppedEventGuid;
EventHeaderp->Flags = WNODE_FLAG_TRACED_GUID
| WNODE_FLAG_USE_GUID_PTR
| WNODE_FLAG_USE_TIMESTAMP;
((PWNODE_HEADER)EventHeaderp)->HistoricalContext = Logger;
KeQuerySystemTime( &EventHeaderp->TimeStamp );
//
// Fill out event data
//
Protocol = Contextp->Header->Protocol;
EventDatap->SourceAddress = Contextp->SourceAddress;
EventDatap->DestinationAddress = Contextp->DestinationAddress;
EventDatap->Protocol = Protocol;
//
// Compute packet size. We need to walk our buffer chain to do
// this...
//
EventDatap->PacketSize = 0;
PacketBuffer = Contextp->RecvBuffer;
do
{
EventDatap->PacketSize += PacketBuffer->ipr_size;
PacketBuffer = PacketBuffer->ipr_next;
} while( NULL != PacketBuffer );
if( NAT_PROTOCOL_TCP == Protocol || NAT_PROTOCOL_UDP == Protocol )
{
EventDatap->SourceIdentifier =
((PUSHORT)Contextp->ProtocolHeader)[0];
EventDatap->DestinationIdentifier =
((PUSHORT)Contextp->ProtocolHeader)[1];
if( NAT_PROTOCOL_TCP == Protocol )
{
EventDatap->ProtocolData1 =
((PTCP_HEADER)Contextp->ProtocolHeader)->SequenceNumber;
EventDatap->ProtocolData2 =
((PTCP_HEADER)Contextp->ProtocolHeader)->AckNumber;
EventDatap->ProtocolData3 =
((PTCP_HEADER)Contextp->ProtocolHeader)->WindowSize;
EventDatap->ProtocolData4 =
TCP_ALL_FLAGS( (PTCP_HEADER)Contextp->ProtocolHeader );
}
}
else if( NAT_PROTOCOL_ICMP == Protocol )
{
EventDatap->ProtocolData1 =
((PICMP_HEADER)Contextp->ProtocolHeader)->Type;
EventDatap->ProtocolData2 =
((PICMP_HEADER)Contextp->ProtocolHeader)->Code;
}
//
// Fire the event. Since this is a trace event and not a standard
// WMI event, IoWMIWriteEvent will not attempt to free the buffer
// passed into it.
//
Status = IoWMIWriteEvent( Buffer );
if( !NT_SUCCESS( Status ))
{
TRACE(
WMI,
("NatLogDroppedPacket: IoWMIWriteEvent returned %08x\n", Status )
);
}
Contextp->Flags |= NAT_XLATE_FLAG_LOGGED;
}
else
{
TRACE(WMI, ("NatLogDroppedPacket: No logging handle\n"));
}
} // NatLogDroppedPacket
NTSTATUS
NatpExecuteWmiMethod(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN ULONG GuidIndex,
IN ULONG InstanceIndex,
IN ULONG MethodId,
IN ULONG InBufferSize,
IN ULONG OutBufferSize,
IN PUCHAR Buffer
)
/*++
Routine Description:
This routine is a callback into the driver to execute a method. If
the driver can complete the method within the callback it should
call WmiCompleteRequest to complete the irp before returning to the
caller. Or the driver can return STATUS_PENDING if the irp cannot be
completed immediately and must then call WmiCompleteRequest once the
data is changed.
Arguments:
DeviceObject is the device whose method is being executed
Irp is the Irp that makes this request
GuidIndex is the index into the list of guids provided when the
device registered
MethodId has the id of the method being called
InBufferSize has the size of the data block passed in as the input to
the method.
OutBufferSize on entry has the maximum size available to write the
returned data block.
Buffer is filled with the input buffer on entry and returns with
the output data block
Return Value:
status
--*/
{
NTSTATUS status;
PAGED_CODE();
CALLTRACE(( "NatpExecuteWmiMethod\n" ));
status = WmiCompleteRequest(
DeviceObject,
Irp,
STATUS_WMI_GUID_NOT_FOUND,
0,
IO_NO_INCREMENT
);
return status;
} // NatpExecuteWmiMethod
NTSTATUS
NatpQueryWmiDataBlock(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN ULONG GuidIndex,
IN ULONG InstanceIndex,
IN ULONG InstanceCount,
IN OUT PULONG InstanceLengthArray,
IN ULONG BufferAvail,
OUT PUCHAR Buffer
)
/*++
Routine Description:
This routine is a callback into the driver to query for the contents of
all instances of a data block. If the driver can satisfy the query within
the callback it should call WmiCompleteRequest to complete the irp before
returning to the caller. Or the driver can return STATUS_PENDING if the
irp cannot be completed immediately and must then call WmiCompleteRequest
once the query is satisfied.
Arguments:
DeviceObject is the device whose data block is being queried
Irp is the Irp that makes this request
GuidIndex is the index into the list of guids provided when the
device registered
InstanceCount is the number of instances expected to be returned for
the data block.
InstanceLengthArray is a pointer to an array of ULONG that returns the
lengths of each instance of the data block. If this is NULL then
there was not enough space in the output buffer to fufill the request
so the irp should be completed with the buffer needed.
BufferAvail on entry has the maximum size available to write the data
blocks.
Buffer on return is filled with the returned data blocks. Note that each
instance of the data block must be aligned on a 8 byte boundry.
Return Value:
status
--*/
{
NTSTATUS status;
PAGED_CODE();
CALLTRACE(( "NatpQueryWmiDataBlock\n" ));
status = WmiCompleteRequest(
DeviceObject,
Irp,
STATUS_WMI_GUID_NOT_FOUND,
0,
IO_NO_INCREMENT
);
return status;
} // NatpQueryWmiDataBlock
NTSTATUS
NatpQueryWmiRegInfo(
IN PDEVICE_OBJECT DeviceObject,
OUT ULONG *RegFlags,
OUT PUNICODE_STRING InstanceName,
OUT PUNICODE_STRING *RegistryPath,
OUT PUNICODE_STRING MofResourceName,
OUT PDEVICE_OBJECT *Pdo
)
/*++
Routine Description:
This routine is a callback into the driver to retrieve the list of
guids or data blocks that the driver wants to register with WMI. This
routine may not pend or block. Driver should NOT call
WmiCompleteRequest.
Arguments:
DeviceObject is the device whose registration info is being queried
*RegFlags returns with a set of flags that describe the guids being
registered for this device. If the device wants enable and disable
collection callbacks before receiving queries for the registered
guids then it should return the WMIREG_FLAG_EXPENSIVE flag. Also the
returned flags may specify WMIREG_FLAG_INSTANCE_PDO in which case
the instance name is determined from the PDO associated with the
device object. Note that the PDO must have an associated devnode. If
WMIREG_FLAG_INSTANCE_PDO is not set then Name must return a unique
name for the device.
InstanceName returns with the instance name for the guids if
WMIREG_FLAG_INSTANCE_PDO is not set in the returned *RegFlags. The
caller will call ExFreePool with the buffer returned.
*RegistryPath returns with the registry path of the driver. The caller
does NOT free this buffer.
*MofResourceName returns with the name of the MOF resource attached to
the binary file. If the driver does not have a mof resource attached
then this can be returned as NULL. The caller does NOT free this
buffer.
*Pdo returns with the device object for the PDO associated with this
device if the WMIREG_FLAG_INSTANCE_PDO flag is retured in
*RegFlags.
Return Value:
status
--*/
{
PAGED_CODE();
CALLTRACE(( "NatpQueryWmiRegInfo\n" ));
//
// Return the registry path for this driver. This is required so WMI
// can find your driver image and can attribute any eventlog messages to
// your driver.
//
*RegistryPath = &NatRegistryPath;
//
// Return the name specified in the .rc file of the resource which
// contains the bianry mof data. By default WMI will look for this
// resource in the driver image (.sys) file, however if the value
// MofImagePath is specified in the driver's registry key
// then WMI will look for the resource in the file specified there.
//
RtlInitUnicodeString(MofResourceName, IPNATMofResource);
//
// Tell WMI to generate instance names off of a static base name
//
*RegFlags = WMIREG_FLAG_INSTANCE_BASENAME;
//
// Set our base instance name. WmiLib will call ExFreePool on the buffer
// of the string, so we need to allocate it from paged pool.
//
InstanceName->Length = wcslen( BaseInstanceName ) * sizeof( WCHAR );
InstanceName->MaximumLength = InstanceName->Length + sizeof( UNICODE_NULL );
InstanceName->Buffer = ExAllocatePoolWithTag(
PagedPool,
InstanceName->MaximumLength,
NAT_TAG_WMI
);
if( NULL != InstanceName->Buffer )
{
RtlCopyMemory(
InstanceName->Buffer,
BaseInstanceName,
InstanceName->Length
);
}
else
{
ERROR(( "NAT: NatpQueryWmiRegInfo unable to allocate memory\n" ));
return STATUS_NO_MEMORY;
}
return STATUS_SUCCESS;
} // NatpQueryWmiRegInfo
NTSTATUS
NatpSetWmiDataBlock(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN ULONG GuidIndex,
IN ULONG InstanceIndex,
IN ULONG BufferSize,
IN PUCHAR Buffer
)
/*++
Routine Description:
This routine is a callback into the driver to change the contents of
a data block. If the driver can change the data block within
the callback it should call WmiCompleteRequest to complete the irp before
returning to the caller. Or the driver can return STATUS_PENDING if the
irp cannot be completed immediately and must then call WmiCompleteRequest
once the data is changed.
Arguments:
DeviceObject is the device whose data block is being queried
Irp is the Irp that makes this request
GuidIndex is the index into the list of guids provided when the
device registered
BufferSize has the size of the data block passed
Buffer has the new values for the data block
Return Value:
status
--*/
{
NTSTATUS status;
PAGED_CODE();
CALLTRACE(( "NatpSetWmiDataBlock\n" ));
status = WmiCompleteRequest(
DeviceObject,
Irp,
STATUS_WMI_GUID_NOT_FOUND,
0,
IO_NO_INCREMENT
);
return status;
} // NatpSetWmiDataBlock
NTSTATUS
NatpSetWmiDataItem(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN ULONG GuidIndex,
IN ULONG InstanceIndex,
IN ULONG DataItemId,
IN ULONG BufferSize,
IN PUCHAR Buffer
)
/*++
Routine Description:
This routine is a callback into the driver to change the contents of
a data block. If the driver can change the data block within
the callback it should call WmiCompleteRequest to complete the irp before
returning to the caller. Or the driver can return STATUS_PENDING if the
irp cannot be completed immediately and must then call WmiCompleteRequest
once the data is changed.
Arguments:
DeviceObject is the device whose data block is being changed
Irp is the Irp that makes this request
GuidIndex is the index into the list of guids provided when the
device registered
DataItemId has the id of the data item being set
BufferSize has the size of the data item passed
Buffer has the new values for the data item
Return Value:
status
--*/
{
NTSTATUS status;
PAGED_CODE();
CALLTRACE(( "NatpSetWmiDataItem\n" ));
status = WmiCompleteRequest(
DeviceObject,
Irp,
STATUS_WMI_GUID_NOT_FOUND,
0,
IO_NO_INCREMENT
);
return status;
} // NatpSetWmiDataItem
NTSTATUS
NatpWmiFunctionControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN ULONG GuidIndex,
IN WMIENABLEDISABLECONTROL Function,
IN BOOLEAN Enable
)
/*++
Routine Description:
This routine is a callback into the driver to enabled or disable event
generation or data block collection. A device should only expect a
single enable when the first event or data consumer enables events or
data collection and a single disable when the last event or data
consumer disables events or data collection. Data blocks will only
receive collection enable/disable if they were registered as requiring
it. If the driver can complete enabling/disabling within the callback it
should call WmiCompleteRequest to complete the irp before returning to
the caller. Or the driver can return STATUS_PENDING if the irp cannot be
completed immediately and must then call WmiCompleteRequest once the
data is changed.
Arguments:
DeviceObject is the device object
GuidIndex is the index into the list of guids provided when the
device registered
Function specifies which functionality is being enabled or disabled
Enable is TRUE then the function is being enabled else disabled
Return Value:
status
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PIO_STACK_LOCATION IrpSp;
PUINT64 Loggerp;
UINT64 Logger;
KIRQL Irql;
PAGED_CODE();
CALLTRACE(( "NatpWmiFunctionControl\n" ));
if( WmiEventControl == Function )
{
if( GuidIndex < NatWmiGuidCount )
{
if( Enable )
{
//
// Get the logger handle from the Irp
//
IrpSp = IoGetCurrentIrpStackLocation( Irp );
//
// The logging handle is in the first UINT64 following the
// WNODE header.
//
if( ((PWNODE_HEADER)IrpSp->Parameters.WMI.Buffer)->BufferSize
>= sizeof(WNODE_HEADER) + sizeof(UINT64) )
{
Loggerp = (PUINT64) ((PUCHAR)IrpSp->Parameters.WMI.Buffer + sizeof(WNODE_HEADER));
Logger = *Loggerp;
}
else
{
TRACE(WMI, ("NatpWmiFunctionControl: Wnode too small for logger handle\n"));
Logger = 0;
Enable = FALSE;
}
}
else
{
Logger = 0;
}
KeAcquireSpinLock( &NatWmiLock, &Irql );
NatWmiLogHandles[ GuidIndex ] = Logger;
NatWmiEnabledEvents[ GuidIndex ] = (Enable ? 1 : 0);
if( NAT_WMI_CONNECTION_CREATION_EVENT == GuidIndex )
{
//
// NAT_WMI_CONNECTION_CREATION_EVENT is the control guid for
// NAT_WMI_CONNECTION_DELETION_EVENT, so we also need to update
// that latter's entry
//
NatWmiLogHandles[ NAT_WMI_CONNECTION_DELETION_EVENT ] = Logger;
NatWmiEnabledEvents[ NAT_WMI_CONNECTION_DELETION_EVENT ] =
(Enable ? 1 : 0);
}
KeReleaseSpinLock( &NatWmiLock, Irql );
TRACE(
WMI,
("NatpWmiFunctionControl: %s event %i; Logger = 0x%016x\n",
(Enable ? "Enabled" : "Disabled"), GuidIndex, Logger ));
}
else
{
//
// Invalid guid index.
//
status = STATUS_WMI_GUID_NOT_FOUND;
TRACE( WMI, ( "NatpWmiFunctionControl: Invalid WMI guid %i",
GuidIndex ));
}
}
else
{
//
// We currently don't have any (expensive) data blocks
//
status = STATUS_INVALID_DEVICE_REQUEST;
}
status = WmiCompleteRequest(
DeviceObject,
Irp,
status,
0,
IO_NO_INCREMENT
);
return status;
} // NatpWmiFunctionControl
VOID
NatShutdownWMI(
VOID
)
/*++
Routine Description:
This routine is called to shutdown WMI.
Arguments:
none.
Return Value:
none.
--*/
{
NTSTATUS status;
CALLTRACE(( "NatShutdownWMI\n" ));
//
// Deregister w/ WMI
//
status = IoWMIRegistrationControl(
NatDeviceObject,
WMIREG_ACTION_DEREGISTER
);
if( !NT_SUCCESS( status ))
{
ERROR(( "Nat: Error shutting down WMI (%08x)\n", status ));
}
} // NatShutdownWMI
#endif