|
|
/*++
Copyright(c) 2001 Microsoft Corporation
Module Name:
nlbwmi.c
Abstract:
Network Load Balancing (NLB) Driver - WMI event generation
Author:
karthicn
--*/
#include "wlbsparm.h"
#include <wmistr.h>
#include <wmiguid.h>
#include <wmilib.h>
#include "main.h"
#include "univ.h"
#include "nlbwmimof.h"
#include "nlbwmi.h"
#include "nlbwmi.tmh"
//
// MOF Resource Name
//
WCHAR NLBMofResourceName[] = L"NLBMofResource";
//
// Base Instance Name
//
WCHAR NLBBaseInstanceName[] = L"NLB_Block";
// NLB Event Guids - the MicrosoftNLB* variables are autogenerated (in nlbwmimof.h)
GUID NodeControlEventGuid = MicrosoftNLB_NodeControlEventGuid; GUID PortRuleControlEventGuid = MicrosoftNLB_PortControlEventGuid; GUID ConvergingEventGuid = MicrosoftNLB_ConvergingEventGuid; GUID ConvergedEventGuid = MicrosoftNLB_ConvergedEventGuid; GUID StartupEventGuid = MicrosoftNLB_StartupEventGuid; GUID ShutdownEventGuid = MicrosoftNLB_ShutdownEventGuid;
// NLB Event Guid Registration Information
WMIGUIDREGINFO NlbWmiGuidList[] = { { &NodeControlEventGuid, 1, WMIREG_FLAG_EVENT_ONLY_GUID }, { &PortRuleControlEventGuid, 1, WMIREG_FLAG_EVENT_ONLY_GUID }, { &ConvergingEventGuid, 1, WMIREG_FLAG_EVENT_ONLY_GUID }, { &ConvergedEventGuid, 1, WMIREG_FLAG_EVENT_ONLY_GUID }, { &StartupEventGuid, 1, WMIREG_FLAG_EVENT_ONLY_GUID }, { &ShutdownEventGuid, 1, WMIREG_FLAG_EVENT_ONLY_GUID }, // Add new event info here
};
#define NlbWmiGuidCount (ULONG)(sizeof(NlbWmiGuidList)/sizeof(WMIGUIDREGINFO))
// NLB Event Information
NLB_WMI_EVENT NlbWmiEvents[] = { { &NodeControlEventGuid, FALSE }, { &PortRuleControlEventGuid, FALSE }, { &ConvergingEventGuid, FALSE }, { &ConvergedEventGuid, FALSE }, { &StartupEventGuid, FALSE }, { &ShutdownEventGuid, FALSE }, // Add new event info here as well
};
//
// Prototype declarations
//
NTSTATUS NlbWmi_Query_RegInfo( IN PDEVICE_OBJECT DeviceObject, OUT ULONG *RegFlags, OUT PUNICODE_STRING InstanceName, OUT PUNICODE_STRING *RegistryPath, OUT PUNICODE_STRING MofResourceName, OUT PDEVICE_OBJECT *Pdo );
NTSTATUS NlbWmi_Query_DataBlock( 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 NlbWmi_Function_Control( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN ULONG GuidIndex, IN WMIENABLEDISABLECONTROL Function, IN BOOLEAN Enable );
//
// WMI Helper Library context
//
WMILIB_CONTEXT NlbWmiLibContext = { NlbWmiGuidCount, NlbWmiGuidList, NlbWmi_Query_RegInfo, NlbWmi_Query_DataBlock, NULL, NULL, NULL, NlbWmi_Function_Control };
/*
Name : NlbWmi_Initialize Description : This function initializes the data structures and registers the supported guids with the wmi system Arguments : None Return Value: status */
NTSTATUS NlbWmi_Initialize() { ULONG idx; NTSTATUS status;
TRACE_VERB("->%!FUNC!");
/* Disable event generation for all events */ for (idx = 0 ; idx < NlbWmiGuidCount ; idx++) { NlbWmiEvents[idx].Enable = FALSE; }
if (univ_device_object != NULL) { /* Register with WMI */ status = IoWMIRegistrationControl(univ_device_object, WMIREG_ACTION_REGISTER); if (status != STATUS_SUCCESS) { TRACE_CRIT("%!FUNC! IoWMIRegistrationControl(DeviceObject : %p, REGISTER) returned Error : 0x%x",univ_device_object, status); } } else // Device Object is NULL
{ status = STATUS_INVALID_DEVICE_OBJECT_PARAMETER; TRACE_CRIT("%!FUNC! Device Object is NULL, Could not call IoWMIRegistrationControl() to register with WMI"); }
TRACE_VERB("<-%!FUNC! return : 0x%x", status); return status; }
/*
Name : NlbWmi_Shutdown Description : This function de-registers with the wmi system Arguments : None Return Value: void */
VOID NlbWmi_Shutdown() { NTSTATUS ntStatus;
TRACE_VERB("->%!FUNC!");
if (univ_device_object != NULL) { /* DeRegister with WMI */ ntStatus = IoWMIRegistrationControl(univ_device_object, WMIREG_ACTION_DEREGISTER); if (ntStatus != STATUS_SUCCESS) { TRACE_CRIT("%!FUNC! IoWMIRegistrationControl(DeviceObject : %p, DEREGISTER) returned Error : 0x%x",univ_device_object, ntStatus); } } else { TRACE_CRIT("%!FUNC! Device Object is NULL, Could not call IoWMIRegistrationControl() to deregister with WMI"); }
TRACE_VERB("<-%!FUNC!"); return; }
/*
Name : NlbWmi_System_Control Description : This function is responsible for handling the IRP_MJ_SYSTEM_CONTROL irps. It uses the wmi helper library function to crack the irp to have the appropriate call back functions called Arguments : Device Object, Irp Return Value: status */
NTSTATUS NlbWmi_System_Control (PVOID DeviceObject, PIRP pIrp) { NTSTATUS status; SYSCTL_IRP_DISPOSITION disposition;
TRACE_VERB("->%!FUNC!");
//
// Call Wmilib helper function to crack the irp. If this is a wmi irp
// that is targetted for the supported guids, then WmiSystemControl will callback
// at the appropriate callback routine.
//
status = WmiSystemControl( &NlbWmiLibContext, DeviceObject, pIrp, &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
// (Must be a IRP_MN_REG_INFO)
//
IoCompleteRequest(pIrp, IO_NO_INCREMENT); break;
default: case IrpNotWmi: case IrpForward: { TRACE_CRIT("%!FUNC! WmiSystemControl returned disposition : 0x%x, Unexpected", disposition); pIrp->IoStatus.Status = status; IoCompleteRequest(pIrp, IO_NO_INCREMENT); break; }
}
if( !NT_SUCCESS( status )) { TRACE_CRIT("%!FUNC! WmiSystemControl returned error : 0x%x", status); }
TRACE_VERB("<-%!FUNC! return : 0x%x", status); return status; } // NlbWmi_System_Control
/*
Name : NlbWmi_Query_RegInfo Description : This function is called back by the Wmi helper library to process a IRP_MN_REG_INFO irp. It registers the Instance name, registry path & Mof resource name with wmi. For more information about this function, please look in the DDK under "WMI library Callback Routines"->"DpWmiQueryReginfo" Return Value: status */
NTSTATUS NlbWmi_Query_RegInfo( IN PDEVICE_OBJECT DeviceObject, OUT ULONG *RegFlags, OUT PUNICODE_STRING InstanceName, OUT PUNICODE_STRING *RegistryPath, OUT PUNICODE_STRING MofResourceName, OUT PDEVICE_OBJECT *Pdo ) { PAGED_CODE();
TRACE_VERB("->%!FUNC!"); //
// 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( NLBBaseInstanceName ) * sizeof( WCHAR ); InstanceName->MaximumLength = InstanceName->Length + sizeof( UNICODE_NULL ); InstanceName->Buffer = ExAllocatePoolWithTag( PagedPool, InstanceName->MaximumLength, UNIV_POOL_TAG ); if( NULL != InstanceName->Buffer ) { RtlCopyMemory( InstanceName->Buffer, NLBBaseInstanceName, InstanceName->Length ); InstanceName->Buffer[InstanceName->Length / sizeof(WCHAR)] = UNICODE_NULL; } else { TRACE_CRIT("%!FUNC! Error allocating memory"); TRACE_VERB("<-%!FUNC! return status = STATUS_INSUFFICIENT_RESOURCES"); return STATUS_INSUFFICIENT_RESOURCES; }
//
// 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 = &DriverEntryRegistryPath;
//
// Return the name specified in the .rc file of the resource which
// contains the binary mof data.
//
RtlInitUnicodeString(MofResourceName, NLBMofResourceName);
TRACE_VERB("<-%!FUNC! return=0x%x", STATUS_SUCCESS); return STATUS_SUCCESS; } // NlbWmi_Query_RegInfo
/*
Name : NlbWmi_Query_DataBlock Description : This function is called back by the Wmi helper library to process IRP_MN_QUERY_ALL_DATA & IRP_MN_QUERY_SINGLE_INSTANCE irps. We DO NOT SUPPORT these irps. However, this is a required callback and hence we implement it. We DO NOT EXPECT THIS FUNCTION TO BE CALLED. For more information about this function, please look in the DDK under "WMI library Callback Routines"->"DpWmiQueryDataBlock" Return Value: status */
NTSTATUS NlbWmi_Query_DataBlock( 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 status;
PAGED_CODE();
TRACE_VERB("->%!FUNC!"); status = WmiCompleteRequest( DeviceObject, Irp, STATUS_WMI_GUID_NOT_FOUND, 0, IO_NO_INCREMENT );
TRACE_VERB("<-%!FUNC! return=0x%x", status); return status; } // NlbWmi_Query_DataBlock
/*
Name : NlbWmi_Function_Control Description : This function is called back by the Wmi helper library to process IRP_MN_ENABLE_EVENTS, IRP_MN_DISABLE_EVENTS, IRP_MN_ENABLE_COLLECTION & IRP_MN_DISABLE_COLLECTION irps. We only support IRP_MN_ENABLE_EVENTS & IRP_MN_DISABLE_EVENTS irps. The function enables/disables events generation. For more information about this function, please look in the DDK under "WMI library Callback Routines"->"DpWmiQueryReginfo" Return Value: status */
NTSTATUS NlbWmi_Function_Control( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN ULONG GuidIndex, IN WMIENABLEDISABLECONTROL Function, IN BOOLEAN Enable ) { NTSTATUS status = STATUS_SUCCESS;
PAGED_CODE();
TRACE_VERB("->%!FUNC! %ls Event Index : %d", Enable ? L"ENABLE" : L"DISABLE", GuidIndex);
if( WmiEventControl == Function ) { // Verify that the guid index is in the range 0 - (NlbWmiGuidCount - 1)
// Also, verify that the guid has not been flagged as removed. Although
// we never flag a guid as being removed, do this check as part of
// following "best practices".
if( (GuidIndex < NlbWmiGuidCount) && !(NlbWmiGuidList[GuidIndex].Flags & WMIREG_FLAG_REMOVE_GUID)) { NlbWmiEvents[GuidIndex].Enable = Enable; } else { //
// Invalid guid index.
//
status = STATUS_WMI_GUID_NOT_FOUND;
TRACE_CRIT("%!FUNC! Invalid WMI guid or guid flagged as removed, guid index: %d", GuidIndex); } } else { //
// We currently don't have any (expensive) data blocks
//
status = STATUS_INVALID_DEVICE_REQUEST; TRACE_CRIT("%!FUNC! Invalid Device Request"); }
status = WmiCompleteRequest( DeviceObject, Irp, status, 0, IO_NO_INCREMENT ); TRACE_VERB("<-%!FUNC! return status = 0x%x", status); return status; } // NlbWmi_Function_Control
/*
Name : NlbWmi_Fire_Event Description : This function fires wmi events. It allocates memory, fills it in with the incoming event data and calls WmiFireEvent to fire the event. Arguments : Event Id, Event Data (statically allocated) Return Value: status */
NTSTATUS NlbWmi_Fire_Event(NlbWmiEventId EventId, PVOID pvInEventData, ULONG ulInEventDataSize) { NTSTATUS status; PVOID pvOutEventData;
TRACE_VERB("->%!FUNC! Event : %d", EventId);
if (ulInEventDataSize > 0) { pvOutEventData = ExAllocatePoolWithTag(NonPagedPool, ulInEventDataSize, UNIV_POOL_TAG); if (pvOutEventData == NULL) { TRACE_CRIT("%!FUNC! Error allocating memory"); TRACE_VERB("<-%!FUNC! return status = STATUS_INSUFFICIENT_RESOURCES"); return STATUS_INSUFFICIENT_RESOURCES; }
RtlCopyMemory(pvOutEventData, pvInEventData, ulInEventDataSize); } else { pvOutEventData = NULL; }
status = WmiFireEvent(univ_device_object, NlbWmiEvents[EventId].pGuid, 0, ulInEventDataSize, pvOutEventData); if( !NT_SUCCESS( status )) { TRACE_CRIT("%!FUNC! WmiFireEvent returned error : 0x%x", status); }
TRACE_VERB("<-%!FUNC! return status = 0x%x", status); return status; } // NlbWmi_Fire_Event
// This macro fills in the common properties(Adapter Guid, IP Address, Host priority) of all events
#define FillCommonProperties() \
{ \ Event.AdapterGuid[0] = sizeof(Event.AdapterGuid) - sizeof(Event.AdapterGuid[0]); \ wcsncpy(&(Event.AdapterGuid[1]), univ_adapters[ctxtp->adapter_id].device_name + 8, Event.AdapterGuid[0]/sizeof(WCHAR)); \ Event.ClusterIPAddress[0] = sizeof(Event.ClusterIPAddress) - sizeof(Event.ClusterIPAddress[0]); \ wcsncpy(&(Event.ClusterIPAddress[1]), ctxtp->params.cl_ip_addr, Event.ClusterIPAddress[0]/sizeof(WCHAR)); \ Event.HostPriority = ctxtp->params.host_priority; \ }
/*
Name : NlbWmi_Fire_NodeControlEvent Description : This function fires Node Control events. It extracts the common event properties (out of the given pointer to the MAIN_CTXT structure) and fills in a local structure. It also fills in Node Control Event specific fields from the arguments passed to it. It then fires the actual event by calling NlbWmi_Fire_Event. Arguments : Pointer to MAIN_CTXT, NodeControlEventId Return Value: void */
void NlbWmi_Fire_NodeControlEvent(PMAIN_CTXT ctxtp, NodeControlEventId Id) { MicrosoftNLB_NodeControlEvent Event;
TRACE_VERB("->%!FUNC! Event : %d", Id);
NdisZeroMemory(&Event, MicrosoftNLB_NodeControlEvent_SIZE);
// Fill in common properties - Adapter Guid, Cluster IP Address & Host Priority
FillCommonProperties()
// Fill event specific properties
Event.Id = Id;
// Fire the event
NlbWmi_Fire_Event(NodeControlEvent, &Event, MicrosoftNLB_NodeControlEvent_SIZE);
TRACE_VERB("<-%!FUNC!"); return; }
/*
Name : NlbWmi_Fire_PortControlEvent Description : This function fires Port Control events. It extracts the common event properties (out of the given pointer to the MAIN_CTXT structure) and fills in a local structure. It also fills in Port Control Event specific fields (id, vip, port) from the arguments passed to it. It then fires the actual event by calling NlbWmi_Fire_Event. Arguments : Pointer to MAIN_CTXT, PortControlEventId, Vip, Port Return Value: void */
void NlbWmi_Fire_PortControlEvent(PMAIN_CTXT ctxtp, PortControlEventId Id, WCHAR *pwcVip, ULONG ulPort) { MicrosoftNLB_PortControlEvent Event;
TRACE_VERB("->%!FUNC! Event : %d, Vip : %ls, Start Port : %d", Id, pwcVip, ulPort);
NdisZeroMemory(&Event, MicrosoftNLB_PortControlEvent_SIZE);
// Fill in common properties - Adapter Guid, Cluster IP Address & Host Priority
FillCommonProperties()
// Fill event specific properties
Event.Id = Id; Event.VirtualIPAddress[0] = sizeof(Event.VirtualIPAddress) - sizeof(Event.VirtualIPAddress[0]); wcsncpy(&(Event.VirtualIPAddress[1]), pwcVip, Event.VirtualIPAddress[0]/sizeof(WCHAR)); Event.Port = ulPort;
// Fire the event
NlbWmi_Fire_Event(PortRuleControlEvent, &Event, MicrosoftNLB_PortControlEvent_SIZE);
TRACE_VERB("<-%!FUNC!"); return; }
/*
Name : NlbWmi_Fire_ConvergingEvent Description : This function fires Converging events. It extracts the common event properties (out of the given pointer to the MAIN_CTXT structure) and fills in a local structure. It also fills in Converging Event specific fields from the arguments passed to it. It then fires the actual event by calling NlbWmi_Fire_Event. Arguments : Pointer to MAIN_CTXT, NodeControlEventId, Initiator DIP, Initiator Host Priority Return Value: void */
void NlbWmi_Fire_ConvergingEvent( PMAIN_CTXT ctxtp, ConvergingEventId Cause, WCHAR *pwcInitiatorDip, ULONG ulInitiatorHostPriority) { MicrosoftNLB_ConvergingEvent Event;
TRACE_VERB("->%!FUNC! Cause : %d, Initiator DIP : %ls, Initiator Host Priority : %d", Cause, pwcInitiatorDip, ulInitiatorHostPriority);
NdisZeroMemory(&Event, MicrosoftNLB_ConvergingEvent_SIZE);
// Fill in common properties - Adapter Guid, Cluster IP Address & Host Priority
FillCommonProperties()
// Fill event specific properties
Event.Cause = Cause; Event.InitiatorDedicatedIP[0] = sizeof(Event.InitiatorDedicatedIP) - sizeof(Event.InitiatorDedicatedIP[0]); wcsncpy(&(Event.InitiatorDedicatedIP[1]), pwcInitiatorDip, Event.InitiatorDedicatedIP[0]/sizeof(WCHAR)); Event.InitiatorHostPriority = ulInitiatorHostPriority;
// Fire the event
NlbWmi_Fire_Event(ConvergingEvent, &Event, MicrosoftNLB_ConvergingEvent_SIZE);
TRACE_VERB("<-%!FUNC!"); return; }
/*
Name : NlbWmi_Fire_ConvergedEvent Description : This function fires Converged events. It extracts the common event properties (out of the given pointer to the MAIN_CTXT structure) and fills in a local structure. It also fills in Converged Event specific fields from the arguments passed to it. It then fires the actual event by calling NlbWmi_Fire_Event. Arguments : Pointer to MAIN_CTXT, HostMap Return Value: void */
void NlbWmi_Fire_ConvergedEvent(PMAIN_CTXT ctxtp, ULONG ulHostMap) { MicrosoftNLB_ConvergedEvent Event;
TRACE_VERB("->%!FUNC! Host Map : %d", ulHostMap);
NdisZeroMemory(&Event, MicrosoftNLB_ConvergedEvent_SIZE);
// Fill in common properties - Adapter Guid, Cluster IP Address & Host Priority
FillCommonProperties()
// Fill event specific properties
Event.HostMap = ulHostMap;
// Fire the event
NlbWmi_Fire_Event(ConvergedEvent, &Event, MicrosoftNLB_ConvergedEvent_SIZE);
TRACE_VERB("<-%!FUNC!"); return; }
|