windows-nt/Source/XPSP1/NT/net/dhcp/server/mm/server.c

907 lines
27 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
//================================================================================
// Copyright (C) 1997 Microsoft Corporation
// Author: RameshV
// Description: implements the basic structures for a server object
// ThreadSafe: no
// Locks: none
// Please read stdinfo.txt for programming style.
//================================================================================
#include <mm.h>
#include <winbase.h>
#include <array.h>
#include <opt.h>
#include <optl.h>
#include <optclass.h>
#include <bitmask.h>
#include <range.h>
#include <reserve.h>
#include <subnet.h>
#include <optdefl.h>
#include <classdefl.h>
#include <oclassdl.h>
#include <sscope.h>
//BeginExport(constants)
#include <dhcp.h>
//EndExport(constants)
//BeginExport(typedef)
typedef struct _M_SERVER {
DWORD Address;
DWORD State;
DWORD Policy;
ARRAY Subnets;
ARRAY MScopes;
ARRAY_LOCATION Loc; // if RoundRobin on, then we need this to keep track
ARRAY SuperScopes;
M_OPTCLASS Options;
M_OPTCLASSDEFLIST OptDefs;
M_CLASSDEFLIST ClassDefs;
LPWSTR Name;
LPWSTR Comment;
} M_SERVER, *PM_SERVER, *LPM_SERVER;
//EndExport(typedef)
//BeginExport(function)
DWORD
MemServerInit(
OUT PM_SERVER *Server,
IN DWORD Address,
IN DWORD State,
IN DWORD Policy,
IN LPWSTR Name,
IN LPWSTR Comment
) //EndExport(function)
{
DWORD Error;
DWORD Size;
PM_SERVER Srv;
AssertRet(Server, ERROR_INVALID_PARAMETER );
Size = ROUND_UP_COUNT(sizeof(M_SERVER), ALIGN_WORST);
if(Name) Size += sizeof(WCHAR)*(1+wcslen(Name));
if(Comment) Size += sizeof(WCHAR)*(1+wcslen(Comment));
Srv = MemAlloc(Size);
if( NULL == Srv ) return ERROR_NOT_ENOUGH_MEMORY;
Srv->Address = Address;
Srv->State = State;
Srv->Policy = Policy;
Error = MemArrayInit(&Srv->Subnets);
if( ERROR_SUCCESS != Error ) { MemFree(Srv); return Error; }
Error = MemArrayInitLoc(&Srv->Subnets, &Srv->Loc);
// Require(ERROR_SUCCESS == Error); // guaranteed failure as the array is empty now..
Error = MemArrayInit(&Srv->MScopes);
if( ERROR_SUCCESS != Error ) { MemFree(Srv); return Error; }
Error = MemArrayInit(&Srv->SuperScopes);
if( ERROR_SUCCESS != Error ) { MemFree(Srv); return Error; }
Error = MemOptClassInit(&Srv->Options);
if( ERROR_SUCCESS != Error ) { MemFree(Srv); return Error; }
Error = MemOptClassDefListInit(&Srv->OptDefs);
if( ERROR_SUCCESS != Error ) { MemFree(Srv); return Error; }
Error = MemClassDefListInit(&Srv->ClassDefs);
if( ERROR_SUCCESS != Error ) { MemFree(Srv); return Error; }
Size = ROUND_UP_COUNT(sizeof(M_SERVER), ALIGN_WORST);
if( Name ) {
Srv->Name = (LPWSTR)(Size + (LPBYTE)Srv);
Size += sizeof(WCHAR)*(1 + wcslen(Name));
wcscpy(Srv->Name, Name);
}
if( Comment ) {
Srv->Comment = (LPWSTR)(Size + (LPBYTE)Srv);
wcscpy(Srv->Comment, Comment);
}
*Server = Srv;
return ERROR_SUCCESS;
}
//BeginExport(function)
DWORD
MemServerCleanup(
IN OUT PM_SERVER Server
) //EndExport(function)
{
DWORD Error;
AssertRet(Server, ERROR_INVALID_PARAMETER);
Error = MemArrayCleanup(&Server->Subnets);
Require( ERROR_SUCCESS == Error);
Error = MemArrayCleanup(&Server->MScopes);
Require( ERROR_SUCCESS == Error);
Error = MemArrayCleanup(&Server->SuperScopes);
Require( ERROR_SUCCESS == Error);
Error = MemOptClassCleanup(&Server->Options);
Require( ERROR_SUCCESS == Error);
Error = MemOptClassDefListCleanup(&Server->OptDefs);
Require( ERROR_SUCCESS == Error);
Error = MemClassDefListCleanup(&Server->ClassDefs);
Require( ERROR_SUCCESS == Error);
MemFree(Server);
return ERROR_SUCCESS;
}
//================================================================================
// subnet related functions on the server
//================================================================================
//BeginExport(function)
DWORD
MemServerGetUAddressInfo(
IN PM_SERVER Server,
IN DWORD Address,
OUT PM_SUBNET *Subnet, // OPTIONAL
OUT PM_RANGE *Range, // OPTIONAL
OUT PM_EXCL *Excl, // OPTIONAL
OUT PM_RESERVATION *Reservation // OPTIONAL
) //EndExport(function)
{
ARRAY_LOCATION Loc;
PM_SUBNET ThisSubnet;
DWORD Error;
LONG Start, End, Mid;
AssertRet(Server && (Subnet || Range || Excl || Reservation ), ERROR_INVALID_PARAMETER);
Require( !CLASSD_HOST_ADDR( Address ) );
#if 0
//
// this is a linear search. need to optimize this loop with binary search
//
Error = MemArrayInitLoc(&Server->Subnets, &Loc);
while ( ERROR_FILE_NOT_FOUND != Error ) {
Require(ERROR_SUCCESS == Error);
Error = MemArrayGetElement(&Server->Subnets, &Loc, (LPVOID*)&ThisSubnet);
Require(ERROR_SUCCESS == Error);
if( ThisSubnet->fSubnet && ThisSubnet->Address == (ThisSubnet->Mask & Address) ) {
if( Subnet ) {
*Subnet = ThisSubnet;
if( NULL == Range && NULL == Excl && NULL == Reservation )
return ERROR_SUCCESS; // nothing else requested
}
Error = MemSubnetGetAddressInfo(
ThisSubnet,
Address,
Range,
Excl,
Reservation
);
if( Subnet && *Subnet ) {
return ERROR_SUCCESS; // return success as we DID find the subnet
} else {
return Error; // if subnet was not requested, the retval is decided by Subnet* fn
}
}
Error = MemArrayNextLoc(&Server->Subnets, &Loc);
}
#else
//
// more efficient binary search
//
if( Subnet ) {
*Subnet = NULL;
}
Start = 0;
End = MemArraySize(&Server->Subnets) - 1;
while( Start <= End ) { // still got an element to go by..
Mid = (Start + End) /2 ;
Error = MemArrayGetElement(&Server->Subnets, &Mid, &ThisSubnet);
Require( ERROR_SUCCESS == Error );
Require(ThisSubnet->fSubnet); // can't work if something inbetween aint a subnet
if( Address < ThisSubnet->Address) { // not in this subnet ..
End = Mid - 1;
} else if( ThisSubnet->Address == (ThisSubnet->Mask & Address) ) {
//
// We got the subnet we're looking for..
//
if( Subnet ) {
*Subnet = ThisSubnet;
if( NULL == Range && NULL == Excl && NULL == Reservation )
return ERROR_SUCCESS;
}
if( Range || Excl || Reservation ) {
Error = MemSubnetGetAddressInfo(
ThisSubnet,
Address,
Range,
Excl,
Reservation
);
}
//
// if we got a subnet, but didn't suceed above.. still we got something
// so return success... otherwise return whatever above returned..
//
return ( Subnet && (*Subnet) ) ? ERROR_SUCCESS: Error;
} else {
//
// Has to be one of the furhter down subnets..
//
Start = Mid + 1;
}
}
#endif
//
// couldn't find it unfortunately..
//
return ERROR_FILE_NOT_FOUND;
}
//BeginExport(function)
DWORD
MemServerGetMAddressInfo(
IN PM_SERVER Server,
IN DWORD Address,
OUT PM_SUBNET *Subnet, // OPTIONAL
OUT PM_RANGE *Range, // OPTIONAL
OUT PM_EXCL *Excl, // OPTIONAL
OUT PM_RESERVATION *Reservation // OPTIONAL
) //EndExport(function)
{
ARRAY_LOCATION Loc;
PM_SUBNET ThisMScope;
DWORD Error,Error2;
PM_RANGE RangeTmp;
AssertRet(Server && (Subnet || Range || Excl || Reservation ), ERROR_INVALID_PARAMETER);
if( NULL == Range ) Range = &RangeTmp;
Error = MemArrayInitLoc(&Server->MScopes, &Loc);
while ( ERROR_FILE_NOT_FOUND != Error ) {
Require(ERROR_SUCCESS == Error);
Error = MemArrayGetElement(&Server->MScopes, &Loc, (LPVOID*)&ThisMScope);
Require(ERROR_SUCCESS == Error);
Error2 = MemSubnetGetAddressInfo(
ThisMScope,
Address,
Range,
Excl,
Reservation
);
if (ERROR_SUCCESS == Error2) {
if( Subnet ) *Subnet = ThisMScope;
return ERROR_SUCCESS;
}
Error = MemArrayNextLoc(&Server->MScopes, &Loc);
continue;
}
return ERROR_FILE_NOT_FOUND;
}
//BeginExport(inline)
DWORD _inline
MemServerGetAddressInfo(
IN PM_SERVER Server,
IN DWORD Address,
OUT PM_SUBNET *Subnet, // OPTIONAL
OUT PM_RANGE *Range, // OPTIONAL
OUT PM_EXCL *Excl, // OPTIONAL
OUT PM_RESERVATION *Reservation // OPTIONAL
) {
if (CLASSD_HOST_ADDR( Address )) {
return MemServerGetMAddressInfo(
Server,
Address,
Subnet,
Range,
Excl,
Reservation
);
} else {
return MemServerGetUAddressInfo(
Server,
Address,
Subnet,
Range,
Excl,
Reservation
);
}
}
//EndExport(inline)
//BeginExport(function)
DWORD
MemServerAddSubnet(
IN OUT PM_SERVER Server,
IN PM_SUBNET Subnet // completely created subnet, must not be in Server's list tho'
) //EndExport(function)
{
DWORD Error;
PM_SUBNET OldSubnet;
ARRAY_LOCATION Loc;
AssertRet(Server && Subnet, ERROR_INVALID_PARAMETER);
AssertRet((Subnet->Mask & Subnet->Address), ERROR_INVALID_PARAMETER);
Subnet->ServerPtr = Server; // set the backptr for future use
//
// First check if subnet duplicates exist and avoid that
//
//
for(
Error = MemArrayInitLoc(&Server->Subnets, &Loc);
NO_ERROR == Error ;
Error = MemArrayNextLoc(&Server->Subnets, &Loc)
) {
Error = MemArrayGetElement(&Server->Subnets, &Loc, &OldSubnet);
Require(ERROR_SUCCESS == Error);
if( (Subnet->Address & OldSubnet->Mask) == OldSubnet->Address
||
(OldSubnet->Address & Subnet->Mask) == Subnet->Address
) {
return ERROR_OBJECT_ALREADY_EXISTS;
}
}
//
// Subnets are stored in ascending order of IP addresses.. so insert
// at the right location
//
for(
Error = MemArrayInitLoc(&Server->Subnets, &Loc)
; ERROR_SUCCESS == Error ;
Error = MemArrayNextLoc(&Server->Subnets, &Loc)
) {
Error = MemArrayGetElement(&Server->Subnets, &Loc, &OldSubnet);
Require(ERROR_SUCCESS == Error);
if( Subnet->Address == OldSubnet->Address ) {
//
// Subnet already present?
//
return ERROR_OBJECT_ALREADY_EXISTS;
}
if( Subnet->Address < OldSubnet->Address ) {
//
// right place to insert the new subnet..
//
Error = MemArrayInitLoc(&Server->Subnets, &Server->Loc);
Require(ERROR_SUCCESS == Error);
Error = MemArrayInsElement(&Server->Subnets, &Loc, Subnet);
Require(ERROR_SUCCESS == Error);
return Error;
}
}
//
// This subnet's address is greater than all others.. so add it at end
//
Error = MemArrayAddElement(&Server->Subnets, Subnet);
if( ERROR_SUCCESS != Error) return Error;
Error = MemArrayInitLoc(&Server->Subnets, &Server->Loc);
Require(ERROR_SUCCESS == Error);
return ERROR_SUCCESS;
}
//BeginExport(function)
DWORD
MemServerDelSubnet(
IN OUT PM_SERVER Server,
IN DWORD SubnetAddress,
OUT PM_SUBNET *Subnet
) //EndExport(function)
{
DWORD Error;
PM_SUBNET DeletedSubnet;
ARRAY_LOCATION Loc;
AssertRet(Server && Subnet, ERROR_INVALID_PARAMETER);
Error = MemArrayInitLoc(&Server->Subnets, &Loc);
while( ERROR_FILE_NOT_FOUND != Error ) {
Require(ERROR_SUCCESS == Error);
Error = MemArrayGetElement(&Server->Subnets, &Loc, (LPVOID*)&DeletedSubnet);
Require(ERROR_SUCCESS == Error && DeletedSubnet);
if( SubnetAddress == DeletedSubnet->Address) {
Error = MemArrayDelElement(&Server->Subnets, &Loc, (LPVOID*)Subnet);
Require(ERROR_SUCCESS == Error && Subnet);
Require(*Subnet == DeletedSubnet);
Error = MemArrayInitLoc(&Server->Subnets, &Server->Loc);
// Require(ERROR_SUCCESS == Error); // this may fail if this is the last subnet being deleted
return ERROR_SUCCESS;
}
Error = MemArrayNextLoc(&Server->Subnets, &Loc);
}
return ERROR_FILE_NOT_FOUND;
}
//BeginExport(function)
DWORD
MemServerFindSubnetByName(
IN PM_SERVER Server,
IN LPWSTR Name,
OUT PM_SUBNET *Subnet
) //EndExport(function)
{
DWORD Error;
PM_SUBNET ThisSubnet;
ARRAY_LOCATION Loc;
AssertRet(Server && Name && Subnet, ERROR_INVALID_PARAMETER);
Error = MemArrayInitLoc(&Server->Subnets, &Loc);
while( ERROR_FILE_NOT_FOUND != Error ) {
Require(ERROR_SUCCESS == Error);
Error = MemArrayGetElement(&Server->Subnets, &Loc, (LPVOID*)&ThisSubnet);
Require(ERROR_SUCCESS == Error && ThisSubnet);
if( 0 == wcscmp(Name, ThisSubnet->Name) ) {
*Subnet = ThisSubnet;
return ERROR_SUCCESS;
}
Error = MemArrayNextLoc(&Server->Subnets, &Loc);
}
return ERROR_FILE_NOT_FOUND;
}
//================================================================================
// superscope functionality
//================================================================================
//BeginExport(constant)
#define INVALID_SSCOPE_ID 0xFFFFFFFF
#define INVALID_SSCOPE_NAME NULL
//EndExport(constant)
//BeginExport(function)
DWORD
MemServerFindSScope( // find matching with EITHER scopeid ir sscopename
IN OUT PM_SERVER Server,
IN DWORD SScopeId, // 0xFFFFFFFF == invalid scope id, dont use for search
IN LPWSTR SScopeName, // NULL == invalid scope name
OUT PM_SSCOPE *SScope
) //EndExport(function)
{
ARRAY_LOCATION Loc;
DWORD Error;
PM_SSCOPE ThisSScope;
AssertRet(Server && SScope, ERROR_INVALID_PARAMETER);
AssertRet(SScopeId != INVALID_SSCOPE_ID || SScopeName != INVALID_SSCOPE_NAME, ERROR_INVALID_PARAMETER);
Error = MemArrayInitLoc(&Server->SuperScopes, &Loc);
while( ERROR_FILE_NOT_FOUND != Error ) {
Require(ERROR_SUCCESS == Error);
Error = MemArrayGetElement(&Server->SuperScopes, &Loc, &ThisSScope);
Require(ERROR_SUCCESS == Error && ThisSScope);
if( ThisSScope->SScopeId == SScopeId ||
(INVALID_SSCOPE_NAME != SScopeName && 0 == wcscmp(ThisSScope->Name, SScopeName) )) {
*SScope = ThisSScope;
return ERROR_SUCCESS;
}
Error = MemArrayNextLoc(&Server->SuperScopes, &Loc);
}
return ERROR_FILE_NOT_FOUND;
}
//BeginExport(function)
DWORD
MemServerAddSScope(
IN OUT PM_SERVER Server,
IN PM_SSCOPE SScope
) //EndExport(function)
{
DWORD Error;
PM_SSCOPE OldSScope;
AssertRet(
Server && SScope && INVALID_SSCOPE_ID != SScope->SScopeId && INVALID_SSCOPE_NAME != SScope->Name,
ERROR_INVALID_PARAMETER
);
Error = MemServerFindSScope(
Server,
SScope->SScopeId,
SScope->Name,
&OldSScope
);
if( ERROR_SUCCESS == Error && OldSScope ) return ERROR_OBJECT_ALREADY_EXISTS;
Error = MemArrayAddElement(&Server->SuperScopes, SScope);
return Error;
}
//BeginExport(function)
DWORD
MemServerDelSScope(
IN OUT PM_SERVER Server,
IN DWORD SScopeId,
OUT PM_SSCOPE *SScope
) //EndExport(function)
{
DWORD Error;
ARRAY_LOCATION Loc;
PM_SSCOPE ThisSScope;
AssertRet(Server && SScope && INVALID_SSCOPE_ID != SScopeId, ERROR_INVALID_PARAMETER);
Error = MemArrayInitLoc(&Server->SuperScopes, &Loc);
while( ERROR_FILE_NOT_FOUND != Error ) {
Require(ERROR_SUCCESS == Error);
Error = MemArrayGetElement(&Server->SuperScopes, &Loc, (LPVOID *)&ThisSScope);
Require(ERROR_SUCCESS == Error && ThisSScope );
if( ThisSScope->SScopeId == SScopeId ) {
Error = MemArrayDelElement(&Server->SuperScopes, &Loc, (LPVOID *)SScope);
Require(ERROR_SUCCESS == Error && *SScope == ThisSScope);
return Error;
}
Error = MemArrayNextLoc(&Server->SuperScopes, &Loc);
}
return ERROR_FILE_NOT_FOUND;
}
//================================================================================
// MCAST scope functionality
//================================================================================
//BeginExport(constants)
#define INVALID_MSCOPE_ID 0x0
#define INVALID_MSCOPE_NAME NULL
//EndExport(constants)
//BeginExport(function)
DWORD
MemServerFindMScope( // search either based on ScopeId or ScopeName
IN PM_SERVER Server,
IN DWORD MScopeId, // Multicast scope id, or 0 if this is not the key to search on
IN LPWSTR Name, // Multicast scope name or NULL if this is not the key to search on
OUT PM_MSCOPE *MScope
) //EndExport(function)
{
ARRAY_LOCATION Loc;
DWORD Error;
PM_MSCOPE ThisMScope;
AssertRet(Server && MScope, ERROR_INVALID_PARAMETER);
Error = MemArrayInitLoc(&Server->MScopes, &Loc);
while (ERROR_FILE_NOT_FOUND != Error) {
Require(ERROR_SUCCESS == Error);
Error = MemArrayGetElement(&Server->MScopes, &Loc, &ThisMScope);
Require(ERROR_SUCCESS == Error && ThisMScope );
if( MScopeId == ThisMScope->MScopeId ||
(Name != INVALID_MSCOPE_NAME && 0 == wcscmp(Name, ThisMScope->Name)) ) {
*MScope = ThisMScope;
return ERROR_SUCCESS;
}
Error = MemArrayNextLoc(&Server->MScopes, &Loc);
}
return ERROR_FILE_NOT_FOUND;
}
//BeginExport(function)
DWORD
MemServerAddMScope(
IN OUT PM_SERVER Server,
IN OUT PM_MSCOPE MScope
) //EndExport(function)
{
DWORD Error;
PM_MSCOPE OldMScope;
AssertRet(Server && MScope, ERROR_INVALID_PARAMETER);
AssertRet(MScope->MScopeId != INVALID_MSCOPE_ID && MScope->Name != INVALID_MSCOPE_NAME, ERROR_INVALID_PARAMETER);
MScope->ServerPtr = Server; // set the backptr for future use
Error = MemServerFindMScope(
Server,
MScope->Address,
MScope->Name,
&OldMScope
);
if( ERROR_SUCCESS == Error && OldMScope ) return ERROR_OBJECT_ALREADY_EXISTS;
Error = MemArrayAddElement(&Server->MScopes, (LPVOID)MScope);
Require(ERROR_SUCCESS == Error);
return Error;
}
//BeginExport(function)
DWORD
MemServerDelMScope(
IN OUT PM_SERVER Server,
IN DWORD MScopeId,
IN LPWSTR MScopeName,
OUT PM_MSCOPE *MScope
) //EndExport(function)
{
DWORD Error;
ARRAY_LOCATION Loc;
PM_MSCOPE ThisMScope;
AssertRet(Server && MScope && (MScopeId != INVALID_MSCOPE_ID || MScopeName != INVALID_MSCOPE_NAME),
ERROR_INVALID_PARAMETER);
Error = MemArrayInitLoc(&Server->MScopes, &Loc);
while (ERROR_FILE_NOT_FOUND != Error) {
Require(ERROR_SUCCESS == Error);
Error = MemArrayGetElement(&Server->MScopes, &Loc, &ThisMScope);
Require(ERROR_SUCCESS == Error && ThisMScope );
if ( INVALID_MSCOPE_ID != MScopeId ) {
if( MScopeId == ThisMScope->MScopeId ) {
Error = MemArrayDelElement(&Server->MScopes, &Loc, MScope);
Require(ERROR_SUCCESS == Error && *MScope == ThisMScope);
return Error;
}
}
if ( INVALID_MSCOPE_NAME != MScopeName ) {
if( !wcscmp(MScopeName, ThisMScope->Name ) ) {
Error = MemArrayDelElement(&Server->MScopes, &Loc, MScope);
Require(ERROR_SUCCESS == Error && *MScope == ThisMScope);
return Error;
}
}
Error = MemArrayNextLoc(&Server->MScopes, &Loc);
}
return ERROR_FILE_NOT_FOUND;
}
//================================================================================
// ClassId related stuff
//================================================================================
//BeginExport(inline)
DWORD _inline
MemServerGetClassDef( // look up a class id def on Key=ClassId or Key=ClassIdBytes
IN PM_SERVER Server,
IN DWORD ClassId, // OPTIONAL, 0 if not used
IN LPWSTR Name, // OPTIONAL, NULL if not used
IN DWORD nClassIdBytes, // OPTIONAL, 0 if not used
IN LPBYTE ClassIdBytes, // OPTIONAL, NULL if not used
OUT PM_CLASSDEF *ClassDef
) {
AssertRet(Server && ClassDef && (0 != ClassId || 0 != nClassIdBytes || Name ), ERROR_INVALID_PARAMETER);
AssertRet( 0 == nClassIdBytes || NULL != ClassIdBytes, ERROR_INVALID_PARAMETER);
AssertRet( 0 != nClassIdBytes || NULL == ClassIdBytes, ERROR_INVALID_PARAMETER);
return MemClassDefListFindOptDef(
&Server->ClassDefs,
ClassId,
Name,
ClassIdBytes,
nClassIdBytes,
ClassDef
);
}
//EndExport(inline)
//BeginExport(inline)
DWORD _inline
MemServerAddClassDef(
IN OUT PM_SERVER Server,
IN DWORD ClassId,
IN BOOL IsVendor,
IN LPWSTR Name,
IN LPWSTR Comment,
IN DWORD nClassIdBytes,
IN LPBYTE ClassIdBytes
) {
AssertRet(Server, ERROR_INVALID_PARAMETER);
return MemClassDefListAddClassDef(
&Server->ClassDefs,
ClassId,
IsVendor,
0,
Name,
Comment,
ClassIdBytes,
nClassIdBytes
);
}
//EndExport(inline)
//BeginExport(inline)
DWORD _inline
MemServerDelClassDef(
IN OUT PM_SERVER Server,
IN DWORD ClassId,
IN LPWSTR Name,
IN DWORD nClassIdBytes,
IN LPBYTE ClassIdBytes
) {
AssertRet(Server, ERROR_INVALID_PARAMETER);
return MemClassDefListDelClassDef(
&Server->ClassDefs,
ClassId,
Name,
ClassIdBytes,
nClassIdBytes
);
}
//EndExport(inline)
//BeginExport(function)
DWORD
MemServerGetOptDef(
IN OUT PM_SERVER Server,
IN DWORD ClassId, // required, strict search, no defaulting class to zero
IN DWORD VendorId, // required, strict search, no defaulting vendor to zero
IN DWORD OptId, // OPTIONAL - search by this or following param
IN LPWSTR OptName, // OPTIONAL - search by name or above param
OUT PM_OPTDEF *OptDef // if found return the opt def here
) //EndExport(function)
{
DWORD Error;
PM_OPTDEFLIST OptDefList;
Require(OptDef);
Error = MemOptClassDefListFindOptDefList(
&Server->OptDefs,
ClassId,
VendorId,
&OptDefList
);
if( ERROR_SUCCESS != Error ) return Error;
Require(OptDefList);
return MemOptDefListFindOptDef(
OptDefList,
OptId,
OptName,
OptDef
);
}
//BeginExport(function)
DWORD
MemServerAddOptDef(
IN OUT PM_SERVER Server,
IN DWORD ClassId,
IN DWORD VendorId,
IN DWORD OptId,
IN LPWSTR OptName,
IN LPWSTR OptComment,
IN DWORD Type,
IN LPBYTE OptVal,
IN DWORD OptValLen
) //EndExport(function)
{
DWORD Error;
PM_OPTDEF OptDef;
// Error = MemServerGetOptDef(
// IN Server,
// IN ClassId,
// IN OptName,
// IN &OptDef
// );
//
// if( ERROR_SUCCESS == Error ) {
// return ERROR_OBJECT_ALREADY_EXISTS;
// }
//
return MemOptClassDefListAddOptDef(
&Server->OptDefs,
ClassId,
VendorId,
OptId,
Type,
OptName,
OptComment,
OptVal,
OptValLen
);
}
//BeginExport(function)
DWORD
MemServerDelOptDef(
IN OUT PM_SERVER Server,
IN DWORD ClassId,
IN DWORD VendorId,
IN DWORD OptId
) //EndExport(function)
{
DWORD Error;
PM_OPTDEFLIST OptDefList;
Error = MemOptClassDefListFindOptDefList(
&Server->OptDefs,
ClassId,
VendorId,
&OptDefList
);
if( ERROR_SUCCESS != Error ) return Error;
return MemOptDefListDelOptDef(
OptDefList,
OptId
);
}
//================================================================================
// end of File
//================================================================================