/*++

Copyright (c) Microsoft Corporation. All rights reserved. 

You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.


Module Name:

    wmikmp.h

Abstract:

    Private header for WMI kernel mode component

--*/

#ifndef _WMIUMDS_
#define _WMIUMDS_

//
// Define this to track reference counts
//#define TRACK_REFERNECES

#include <wchar.h>

extern const GUID WmipBinaryMofGuid;
extern const GUID RegChangeNotificationGuid;

//
// Chunk Management definitions
// All structures that rely upon the chunk allocator must be defined so that
// their members match that of ENTRYHEADER. These include DATASOURCE,
// GUIDENTRY, INSTANCESET, DCENTRY, NOTIFICATIONENTRY, MOFCLASS, MOFRESOURCE
// Also ENTRYHEADER reserves 0x80000000 for its own flag.

struct _CHUNKINFO;
struct _ENTRYHEADER;

typedef void (*ENTRYCLEANUP)(
    struct _CHUNKINFO *,
    struct _ENTRYHEADER *
    );

typedef struct _CHUNKINFO
{
    LIST_ENTRY ChunkHead;        // Head of list of chunks
    ULONG EntrySize;            // Size of a single entry
    ULONG EntriesPerChunk;        // Number of entries per chunk allocation
    ENTRYCLEANUP EntryCleanup;   // Entry cleanup routine
    ULONG InitialFlags;         // Initial flags for all entries
    ULONG Signature;
#if DBG
    LONG AllocCount;
    LONG FreeCount;
#endif
} CHUNKINFO, *PCHUNKINFO;

typedef struct
{
    LIST_ENTRY ChunkList;        // Node in list of chunks
    LIST_ENTRY FreeEntryHead;    // Head of list of free entries in chunk
    ULONG EntriesInUse;            // Count of entries being used
} CHUNKHEADER, *PCHUNKHEADER;

typedef struct _ENTRYHEADER
{
    union
    {
        LIST_ENTRY FreeEntryList;    // Node in list of free entries
        LIST_ENTRY InUseEntryList;   // Node in list ofin use entries
    };
    PCHUNKHEADER Chunk;            // Chunk in which entry is located
    ULONG Flags;                // Flags
    ULONG RefCount;                 // Reference Count
    ULONG Signature;
} ENTRYHEADER, *PENTRYHEADER;

                                // Set if the entry is free
#define FLAG_ENTRY_ON_FREE_LIST       0x80000000
#define FLAG_ENTRY_ON_INUSE_LIST      0x40000000
#define FLAG_ENTRY_INVALID            0x20000000
#define FLAG_ENTRY_REMOVE_LIST        0x10000000


#define WmipReferenceEntry(Entry) \
    InterlockedIncrement((PLONG)&((PENTRYHEADER)(Entry))->RefCount)

// chunk.c
ULONG WmipUnreferenceEntry(
    PCHUNKINFO ChunkInfo,
    PENTRYHEADER Entry);

PENTRYHEADER WmipAllocEntry(
    PCHUNKINFO ChunkInfo
    );

void WmipFreeEntry(
    PCHUNKINFO ChunkInfo,
    PENTRYHEADER Entry
    );

PWCHAR WmipCountedToSz(
    PWCHAR Counted
    );

struct tagGUIDENTRY;
typedef struct tagGUIDENTRY GUIDENTRY, *PGUIDENTRY, *PBGUIDENTRY;



//
// An INSTANCESET contains the information a set of instances that is provided
// by a single data source. An instance set is part of two lists. One list is
// the set of instance sets for a particular guid. The other list is the list
// of instance sets supported by a data source.
//

//
// Instance names for an instance set registered with a base name and count
// are stored in a ISBASENAME structure. This structure is tracked by
// PDFISBASENAME in wmicore.idl.
typedef struct
{
    ULONG BaseIndex;                // First index to append to base name
    WCHAR BaseName[ANYSIZE_ARRAY];  // Actual base name
} ISBASENAME, *PISBASENAME, *PBISBASENAME;

//
// This defines the maximum number of characters that can be part of a suffix
// to a basename. The current value of 6 will allow up to 999999 instances
// of a guid with a static base name
#define MAXBASENAMESUFFIXLENGTH  6
#define MAXBASENAMESUFFIXVALUE   999999
#define BASENAMEFORMATSTRING     L"%d"

//
// Instance names for an instance set registered with a set of static names
// are kept in a ISSTATICNAMES structure. This structure is tracked by
// PDFISSTATICNAMES defined in wmicore.idl
typedef struct
{
    PWCHAR StaticNamePtr[ANYSIZE_ARRAY];    // pointers to static names
} ISSTATICENAMES, *PISSTATICNAMES, *PBISSTATICNAMES;

typedef struct tagInstanceSet
{
    union
    {
        // Entry in list of instances within a guid
        LIST_ENTRY GuidISList;

        // Entry in main list of free instances
        LIST_ENTRY FreeISList;
    };
    PCHUNKHEADER Chunk;            // Chunk in which entry is located
    ULONG Flags;

    // Reference count of number of guids using this instance set
    ULONG RefCount;

    // Signature to identify entry
    ULONG Signature;

    // Entry in list of instances within a data source
    LIST_ENTRY DSISList;

    // Back link to guid that this instance set is a member
    PBGUIDENTRY GuidEntry;

    // Back link to data source that this instance set is a member
    struct tagDATASOURCE *DataSource;

    // Count of instances in instance set
    ULONG Count;

    // Size needed to place all instance names in a WNODE_ALL_DATA
    ULONG WADInstanceNameSize;

    // ProviderId for the DS associated with this IS
    ULONG ProviderId;

    //
    // If IS_INSTANCE_BASENAME is set then IsBaseName pointed at instance base
    // name structure. Else if IS_INSTANCE_STATICNAME is set then
    // IsStaticNames points to static instance name list. If
    union
    {
        PBISBASENAME IsBaseName;
        PBISSTATICNAMES IsStaticNames;
    };

} INSTANCESET, *PINSTANCESET, *PBINSTANCESET;

#define IS_SIGNATURE 'SImW'

//
// Guid Map Entry List maintains the list of Guid and their maps.
// Only those Guids that are Unregistered while a logger session is in
// progress is kept in this list.
// It is also used as a placeholder for InstanceIds. Trace Guid Registration
// calls return a handle to a GUIDMAPENTRY which maintains the map and the
// Instance Ids.
//

typedef struct tagTRACE_REG_INFO
{
    ULONG       RegistrationCookie;
    HANDLE      InProgressEvent; // Registration is in Progress Event
    BOOLEAN     EnabledState;    // Indicates if this GUID is Enabled or not.
    PVOID       NotifyRoutine;
    PVOID       TraceCtxHandle;
} TRACE_REG_INFO, *PTRACE_REG_INFO;

typedef struct
{
    LIST_ENTRY      Entry;
    TRACEGUIDMAP    GuidMap;
    ULONG           InstanceId;
    ULONG64         LoggerContext;
    PTRACE_REG_INFO pControlGuidData;
} GUIDMAPENTRY, *PGUIDMAPENTRY;


//
// These flags are also by the WMIINSTANCEINFO structure in wmicore.idl
#define IS_INSTANCE_BASENAME        0x00000001
#define IS_INSTANCE_STATICNAMES     0x00000002
#define IS_EXPENSIVE                0x00000004    // set if collection must be enabled
#define IS_COLLECTING               0x00000008    // set when collecting

#define IS_KM_PROVIDER              0x00000080    // KM data provider
#define IS_SM_PROVIDER              0x00000100    // Shared memory provider
#define IS_UM_PROVIDER              0x00000200    // User mode provider
#define IS_NEWLY_REGISTERED         0x00000800    // set if IS is registering

//
// Any traced guids are used for trace logging and not querying
#define IS_TRACED                   0x00001000

// Set when events are enabled for instance set
#define IS_ENABLE_EVENT             0x00002000

// Set when events are enabled for instance set
#define IS_ENABLE_COLLECTION        0x00004000

// Set if guid is used only for firing events and not querying
#define IS_EVENT_ONLY               0x00008000

// Set if data provider for instance set is expecting ansi instsance names
#define IS_ANSI_INSTANCENAMES       0x00010000

// Set if instance names are originated from a PDO
#define IS_PDO_INSTANCENAME         0x00020000

// Set if a Traced Guid is also a Trace Control Guid
#define IS_CONTROL_GUID             0x00080000

#define IS_ON_FREE_LIST             0x80000000

typedef struct tagGUIDENTRY
{
    union
    {
        // Entry in list of all guids registered with WMI
        LIST_ENTRY MainGEList;

        // Entry in list of free guid entry blocks
        LIST_ENTRY FreeGEList;
    };
    PCHUNKHEADER Chunk;            // Chunk in which entry is located
    ULONG Flags;

    // Count of number of data sources using this guid
    ULONG RefCount;

    // Signature to identify entry
    ULONG Signature;

    // Head of list of open objects to this guid
    LIST_ENTRY ObjectHead;

    // Count of InstanceSets headed by this guid
    ULONG ISCount;

    // Head of list of all instances for guid
    LIST_ENTRY ISHead;

    // Guid that represents data block
    GUID Guid;

    ULONG EventRefCount;                // Global count of event enables
    ULONG CollectRefCount;              // Global count of collection enables

    ULONG64 LoggerContext;              // Logger context handle

    PWMI_LOGGER_INFORMATION LoggerInfo; // LoggerInfo. Used in case of Ntdll tracing

    PKEVENT CollectInProgress;          // Event set when all collect complete

} GUIDENTRY, *PGUIDENTRY, *PBGUIDENTRY;

#define GE_SIGNATURE 'EGmW'

#define GE_ON_FREE_LIST        0x80000000

//
// When set this guid is an internally defined guid that has no data source
// attached to it.
#define GE_FLAG_INTERNAL    0x00000001

// Set when a notification request is being processed by the data providers
#define GE_FLAG_NOTIFICATION_IN_PROGRESS 0x00000002

// Set when a collection request is being processed by the data providers
#define GE_FLAG_COLLECTION_IN_PROGRESS 0x00000004

// Set when a trace disable is being processed by a worker thread
#define GE_FLAG_TRACEDISABLE_IN_PROGRESS 0x00000008

// Set when there is a wait in progress for collect/event enable/disable
#define GE_FLAG_WAIT_ENABLED 0x00000010

// Set when the guid has had an enable collection sent to it
#define GE_FLAG_COLLECTION_ENABLED 0x00000020

// Set when the guid has had an enable notifications sent to it
#define GE_FLAG_NOTIFICATIONS_ENABLED 0x00000040

#define GE_NOTIFICATION_TRACE_FLAG 0x00000080

// Set when an enabled guid receives another enable notification
#define GE_NOTIFICATION_TRACE_UPDATE 0x00000100

typedef struct
{
    union
    {
        // Entry in list of all DS
        LIST_ENTRY MainMRList;

        // Entry in list of free DS
        LIST_ENTRY FreeMRList;
    };
    PCHUNKHEADER Chunk;            // Chunk in which entry is located
    ULONG Flags;

    ULONG RefCount;

    // Signature to identify entry
    ULONG Signature;

    PWCHAR RegistryPath;           // Path to image file with resource
    PWCHAR MofResourceName;        // Name of resource containing mof data
} MOFRESOURCE, *PMOFRESOURCE;

#define MR_SIGNATURE 'RMmW'

//
// This is a user mode resource so the RegistryPath is really an image path
#define MR_FLAG_USER_MODE  0x00000001

#if DBG
#define AVGMOFRESOURCECOUNT 1
#else
#define AVGMOFRESOURCECOUNT 4
#endif
struct _WMIGUIDOBJECT;

typedef struct tagDATASOURCE
{
    union
    {
        // Entry in list of all DS
        LIST_ENTRY MainDSList;

        // Entry in list of free DS
        LIST_ENTRY FreeDSList;
    };
    PCHUNKHEADER Chunk;            // Chunk in which entry is located
    ULONG Flags;

    ULONG RefCount;

    ULONG Signature;

    // Head of list of instances for this DS
    LIST_ENTRY ISHead;

    // Provider id of kernel mode driver
    ULONG ProviderId;

    // Path to registry holding ACLs
    PTCHAR RegistryPath;

    // Head of list of MofResources attached to data source
    ULONG MofResourceCount;
    PMOFRESOURCE *MofResources;
    PMOFRESOURCE StaticMofResources[AVGMOFRESOURCECOUNT];
    
    // Guid object if this is a UM provider
    struct _WMIGUIDOBJECT *RequestObject;
};

#define DS_SIGNATURE 'SDmW'

#define VERIFY_DPCTXHANDLE(DsCtxHandle) \
    ( ((DsCtxHandle) == NULL) || \
      (((PBDATASOURCE)(DsCtxHandle))->Signature == DS_SIGNATURE) )
    
typedef struct tagDATASOURCE DATASOURCE, *PDATASOURCE, *PBDATASOURCE;

#define DS_ALLOW_ALL_ACCESS    0x00000001
#define DS_KERNEL_MODE         0x00000002

#define DS_USER_MODE           0x00000008

#define DS_ON_FREE_LIST        0x80000000

//
// AVGGUIDSPERDS defines a guess as to the number of guids that get registered
// by any data provider. It is used to allocate the buffer used to deliver
// registration change notifications.
#if DBG
#define AVGGUIDSPERDS    2
#else
#define AVGGUIDSPERDS    256
#endif

//
// Guid and InstanceSet cache
#if DBG
#define PTRCACHEGROWSIZE 2
#else
#define PTRCACHEGROWSIZE 64
#endif

typedef struct
{
    LPGUID Guid;
    PBINSTANCESET InstanceSet;
} PTRCACHE;

typedef struct
{
    ULONG ProviderId;
    ULONG Flags;
    ULONG InstanceCount;
    ULONG InstanceNameSize;
    PWCHAR **StaticNamePtr;
    ULONG BaseIndex;
    PWCHAR BaseName;
}    WMIINSTANCEINFO, *PWMIINSTANCEINFO;


//
// Location of built in MOF for the system
//
#define WMICOREIMAGEPATH L"advapi32.dll"
#define WMICORERESOURCENAME L"MofResourceName"


void WmipGenerateBinaryMofNotification(
    PBINSTANCESET BinaryMofInstanceSet,
    LPCGUID Guid        
    );

void WmipGenerateMofResourceNotification(
    LPWSTR ImagePath,
    LPWSTR ResourceName,
    LPCGUID Guid,
    ULONG ActionCode
    );

//
// alloc.c


extern LIST_ENTRY WmipGEHead;
extern PLIST_ENTRY WmipGEHeadPtr;
extern CHUNKINFO WmipGEChunkInfo;

extern LIST_ENTRY WmipDSHead;
extern PLIST_ENTRY WmipDSHeadPtr;
extern CHUNKINFO WmipDSChunkInfo;

extern LIST_ENTRY WmipMRHead;
extern PLIST_ENTRY WmipMRHeadPtr;
extern CHUNKINFO WmipMRChunkInfo;

extern CHUNKINFO WmipISChunkInfo;

extern LIST_ENTRY WmipGMHead;
extern PLIST_ENTRY WmipGMHeadPtr;

#define WmipUnreferenceDS(DataSource) \
    WmipUnreferenceEntry(&WmipDSChunkInfo, (PENTRYHEADER)DataSource)

#define WmipReferenceDS(DataSource) \
    WmipReferenceEntry((PENTRYHEADER)DataSource)

#define WmipUnreferenceGE(GuidEntry) \
    WmipUnreferenceEntry(&WmipGEChunkInfo, (PENTRYHEADER)GuidEntry)

#define WmipReferenceGE(GuidEntry) \
    WmipReferenceEntry((PENTRYHEADER)GuidEntry)

#define WmipUnreferenceIS(InstanceSet) \
    WmipUnreferenceEntry(&WmipISChunkInfo, (PENTRYHEADER)InstanceSet)

#define WmipReferenceIS(InstanceSet) \
    WmipReferenceEntry((PENTRYHEADER)InstanceSet)

#define WmipUnreferenceDC(DataConsumer) \
    WmipUnreferenceEntry(&WmipDCChunkInfo, (PENTRYHEADER)DataConsumer)

#define WmipReferenceDC(DataConsumer) \
    WmipReferenceEntry((PENTRYHEADER)DataConsumer)

#define WmipUnreferenceMR(MofResource) \
    WmipUnreferenceEntry(&WmipMRChunkInfo, (PENTRYHEADER)MofResource)

#define WmipReferenceMR(MofResource) \
    WmipReferenceEntry((PENTRYHEADER)MofResource)

PBDATASOURCE WmipAllocDataSource(
    void
    );

PBGUIDENTRY WmipAllocGuidEntryX(
    ULONG Line,
    PCHAR File
    );

#define WmipAllocGuidEntry() WmipAllocGuidEntryX(__LINE__, __FILE__)

#define WmipAllocInstanceSet() ((PBINSTANCESET)WmipAllocEntry(&WmipISChunkInfo))

#define WmipAllocMofResource() ((PMOFRESOURCE)WmipAllocEntry(&WmipMRChunkInfo))

BOOLEAN WmipIsNumber(
    LPCWSTR String
    );
        
#define WmipAlloc(Size) \
    ExAllocatePoolWithTag(PagedPool, Size, 'pimW')

#define WmipAllocWithTag(Size, Tag) \
    ExAllocatePoolWithTag(PagedPool, Size, Tag)

#define WmipFree(Ptr) \
    ExFreePool(Ptr)

#define WmipAllocNP(Size) \
    ExAllocatePoolWithTag(NonPagedPool, Size, 'pimW')

#define WmipAllocNPWithTag(Size, Tag) \
    ExAllocatePoolWithTag(NonPagedPool, Size, Tag)


BOOLEAN WmipRealloc(
    PVOID *Buffer,
    ULONG CurrentSize,
    ULONG NewSize,
    BOOLEAN FreeOriginalBuffer
    );

PBGUIDENTRY WmipFindGEByGuid(
    LPGUID Guid,
    BOOLEAN MakeTopOfList
    );

PBDATASOURCE WmipFindDSByProviderId(
    ULONG_PTR ProviderId
    );

PBINSTANCESET WmipFindISByGuid(
    PBDATASOURCE DataSource,
    GUID UNALIGNED *Guid
    );

PMOFRESOURCE WmipFindMRByNames(
    LPCWSTR ImagePath,
    LPCWSTR MofResourceName
    );

PBINSTANCESET WmipFindISinGEbyName(
    PBGUIDENTRY GuidEntry,
    PWCHAR InstanceName,
    PULONG InstanceIndex
    );

#define WmipReportEventLog(a,b,c,d,e,f,g)

#endif

