2190 lines
59 KiB
C
2190 lines
59 KiB
C
/*++
|
|
|
|
Copyright (C) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
mmapi.c
|
|
|
|
Abstract:
|
|
|
|
Server interface to the MM module
|
|
|
|
Environment:
|
|
|
|
User mode, Win32
|
|
|
|
--*/
|
|
|
|
#include <dhcppch.h>
|
|
#include <rpcapi.h>
|
|
#include <dsreg.h>
|
|
|
|
//
|
|
// file static variable.
|
|
//
|
|
|
|
//
|
|
// Exported routines begin here.
|
|
//
|
|
|
|
//BeginExport(function)
|
|
DWORD
|
|
DhcpRegistryInitOld(
|
|
VOID
|
|
) //EndExport(function)
|
|
/*++
|
|
|
|
Initializes registry so far as MM is concerned -- just read the objects
|
|
and fill in the internal structures.
|
|
|
|
--*/
|
|
{
|
|
DhcpAssert( NULL == DhcpGlobalThisServer );
|
|
return DhcpRegReadThisServer(&DhcpGlobalThisServer);
|
|
}
|
|
|
|
//BeginExport(function)
|
|
DWORD
|
|
DhcpConfigInit(
|
|
VOID
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Error;
|
|
|
|
Error = DhcpReadConfigInfo(&DhcpGlobalThisServer);
|
|
if( NO_ERROR != Error ) return Error;
|
|
|
|
return DhcpRegReadServerBitmasks(DhcpGlobalThisServer);
|
|
}
|
|
|
|
//BeginExport(function)
|
|
VOID
|
|
DhcpConfigCleanup(
|
|
VOID
|
|
) //EndExport(function)
|
|
/*++
|
|
|
|
This undoes the effect of DhcpConfigInit, closing all handles and
|
|
freeing all resources.
|
|
|
|
--*/
|
|
{
|
|
if(DhcpGlobalThisServer) {
|
|
|
|
DhcpRegFlushServer(FLUSH_ANYWAY);
|
|
MemServerFree(DhcpGlobalThisServer);
|
|
DhcpGlobalThisServer = NULL;
|
|
}
|
|
}
|
|
|
|
//BeginExport(function)
|
|
DWORD
|
|
DhcpConfigSave(
|
|
IN BOOL fClassChanged,
|
|
IN BOOL fOptionsChanged,
|
|
IN DHCP_IP_ADDRESS Subnet OPTIONAL,
|
|
IN DWORD Mscope OPTIONAL,
|
|
IN DHCP_IP_ADDRESS Reservation OPTIONAL
|
|
) //EndExport(function)
|
|
{
|
|
return DhcpSaveConfigInfo(
|
|
DhcpGlobalThisServer, fClassChanged, fOptionsChanged,
|
|
Subnet, Mscope, Reservation );
|
|
}
|
|
|
|
//BeginExport(function)
|
|
PM_SERVER
|
|
DhcpGetCurrentServer(
|
|
VOID
|
|
) //EndExport(function)
|
|
{
|
|
return DhcpGlobalThisServer;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
VOID
|
|
DhcpSetCurrentServer(
|
|
IN PM_SERVER NewCurrentServer
|
|
) //EndExport(function)
|
|
{
|
|
DhcpAssert(NewCurrentServer);
|
|
DhcpGlobalThisServer = NewCurrentServer;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
DWORD
|
|
DhcpFindReservationByAddress(
|
|
IN PM_SUBNET Subnet,
|
|
IN DHCP_IP_ADDRESS Address,
|
|
OUT LPBYTE *ClientUID,
|
|
OUT ULONG *ClientUIDSize
|
|
) //EndExport(function)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function searches a subnet for a reservation with a given IP
|
|
address, and if found returns the ClientUID and size. The ClientUID is
|
|
an internally allocated pointer that is valid only so long as the
|
|
"ReadLock" (see lock.c) is taken.... It could get modified after
|
|
that..
|
|
|
|
Arguments:
|
|
|
|
Subnet -- valid subnet object pointer
|
|
Address -- non-zero IP address of the reservation to check for
|
|
ClientUID -- return pointer to memory that is valid only so long as
|
|
readlock is held. (Do not free this memory).
|
|
ClientUIDSize -- size of above pointer in bytes.
|
|
|
|
Return Value:
|
|
|
|
Win32 errors
|
|
|
|
--*/
|
|
{
|
|
ULONG Error;
|
|
PM_RESERVATION Reservation;
|
|
|
|
Error = MemReserveFindByAddress(
|
|
&Subnet->Reservations, Address, &Reservation
|
|
);
|
|
if( ERROR_SUCCESS != Error ) return Error;
|
|
|
|
*ClientUID = Reservation->ClientUID;
|
|
*ClientUIDSize = Reservation->nBytes;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
//BeginExport(function)
|
|
DWORD
|
|
DhcpLoopThruSubnetRanges(
|
|
IN PM_SUBNET Subnet,
|
|
IN LPVOID Context1 OPTIONAL,
|
|
IN LPVOID Context2 OPTIONAL,
|
|
IN LPVOID Context3 OPTIONAL,
|
|
IN DWORD (*FillRangesFunc)(
|
|
IN PM_RANGE Range,
|
|
IN LPVOID Context1,
|
|
IN LPVOID Context2,
|
|
IN LPVOID Context3,
|
|
IN LPDHCP_BINARY_DATA InUseData,
|
|
IN LPDHCP_BINARY_DATA UsedData
|
|
)
|
|
) //EndExport(function)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This routine can be used to loop though the ranges of a subnet to
|
|
process each range. Three contexts can be supplied which will be
|
|
passed directly to the FillRangesFunc routine as parameter.
|
|
|
|
Arguments:
|
|
Subnet -- this is the subnet to loop through.
|
|
Context1 -- caller specified context, passed to FillRangesFunc.
|
|
Context2 -- caller specified context, passed to FillRangesFunc.
|
|
Context3 -- caller specified context, passed to FillRangesFunc.
|
|
FillRangesFunc -- caller specified routine that is called on each
|
|
range found for the subnet. This routine is called with the
|
|
InUseData and UsedData clusters as appropriate for this range.
|
|
(These last two parameters should not be modified in anyway)
|
|
|
|
Return Value:
|
|
If any invocation of FillRangesFunc returns an error, then that error is
|
|
immediately returned. If there is any error in retreiving the InUseData
|
|
and the UsedData binary structures for any range, then an error is
|
|
returned.
|
|
|
|
Win32 errors.
|
|
|
|
--*/
|
|
{
|
|
ULONG Error;
|
|
ARRAY_LOCATION Loc;
|
|
PM_RANGE ThisRange = NULL;
|
|
DHCP_BINARY_DATA InUseData, UsedData;
|
|
|
|
for( Error = MemArrayInitLoc(&Subnet->Ranges, &Loc) ;
|
|
ERROR_SUCCESS == Error ;
|
|
Error = MemArrayNextLoc(&Subnet->Ranges, &Loc)
|
|
) {
|
|
Error = MemArrayGetElement(&Subnet->Ranges, &Loc, &ThisRange);
|
|
|
|
Error = MemRangeConvertToClusters(
|
|
ThisRange, &InUseData.Data, &InUseData.DataLength,
|
|
&UsedData.Data, &UsedData.DataLength
|
|
);
|
|
if( ERROR_SUCCESS != Error ) return Error;
|
|
|
|
Error = FillRangesFunc(
|
|
ThisRange, Context1, Context2, Context3, &InUseData, &UsedData
|
|
);
|
|
if( UsedData.Data ) MemFree(UsedData.Data);
|
|
if( InUseData.Data ) MemFree(InUseData.Data);
|
|
|
|
if( ERROR_SUCCESS != Error ) return Error;
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
DWORD
|
|
DhcpOptClassGetMemOptionExact(
|
|
IN LPDHCP_REQUEST_CONTEXT Ctxt,
|
|
IN PM_OPTCLASS Options,
|
|
IN DWORD Option,
|
|
IN DWORD ClassId,
|
|
IN DWORD VendorId,
|
|
OUT PM_OPTION *Opt
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This routine tries to find an option matching the option ID specified
|
|
in "Option" parameter and belonging to the class specified by ClassId
|
|
and VendorId. (Note that ClassId and VendorId are used for exact
|
|
matches).
|
|
|
|
If an option is found, then the option structure is returned in the
|
|
"Opt" parameter -- this can be used only so long as the global readlock
|
|
on all memory structures are in place. (see lock.c). It is an internal
|
|
pointer and should not be modified.
|
|
|
|
N.B. If VendorId actually belongs to a microsoft vendor class ID, then
|
|
the MSFT class is also applied..
|
|
|
|
Arguments:
|
|
Ctxt -- client request context
|
|
Options -- the option-class list to search for the particular option
|
|
Option -- the option ID of the option to search for
|
|
ClassId -- the exact class id of the option needed
|
|
VendorId -- the exact vendor id of the option needed
|
|
Opt -- a variable that will be filled with pointer to the in memory
|
|
option structure.
|
|
|
|
Return Value:
|
|
Win32 errors.
|
|
--*/
|
|
{
|
|
DWORD Error;
|
|
PM_OPTLIST OptList;
|
|
|
|
//
|
|
// get list of options for classid, vendorid pair.
|
|
//
|
|
|
|
do {
|
|
OptList = NULL;
|
|
Error = MemOptClassFindClassOptions(
|
|
Options,
|
|
ClassId,
|
|
VendorId,
|
|
&OptList
|
|
);
|
|
if( ERROR_SUCCESS != Error ) {
|
|
if( VendorId != DhcpGlobalMsftClass
|
|
&& Ctxt->fMSFTClient ) {
|
|
//
|
|
// If it belongs to a microsoft client,
|
|
// try the MSFT class also.
|
|
//
|
|
VendorId = DhcpGlobalMsftClass;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if( ERROR_SUCCESS != Error ) break;
|
|
|
|
//
|
|
// search for reqd option id
|
|
//
|
|
|
|
DhcpAssert(NULL != OptList);
|
|
Error = MemOptListFindOption(
|
|
OptList,
|
|
Option,
|
|
Opt
|
|
);
|
|
if( ERROR_SUCCESS != Error ) {
|
|
if( VendorId != DhcpGlobalMsftClass
|
|
&& Ctxt->fMSFTClient ) {
|
|
//
|
|
// If it belongs to a microsoft client,
|
|
// try the MSFT class also.
|
|
//
|
|
VendorId = DhcpGlobalMsftClass;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
break;
|
|
} while ( 1 );
|
|
return Error;
|
|
}
|
|
|
|
DWORD
|
|
DhcpOptClassGetMemOption(
|
|
IN LPDHCP_REQUEST_CONTEXT Ctxt,
|
|
IN PM_OPTCLASS Options,
|
|
IN DWORD Option,
|
|
IN DWORD ClassId OPTIONAL,
|
|
IN DWORD VendorId OPTIONAL,
|
|
OUT PM_OPTION *Opt
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This routine is almost exactly the same as
|
|
DhcpOptClassGetMemOptionExact except that the ClassId and VendorId are
|
|
optional, and the following search logic is used to identify the
|
|
options.
|
|
|
|
1. An exact search is made for <Option, ClassId, VendorId>.
|
|
|
|
Note that the returned option is valid only so long as the global
|
|
memory read lock is taken... (see lock.c)
|
|
|
|
Arguments:
|
|
Ctxt -- client request context
|
|
Options -- list of opt-class to search for desired option
|
|
Option -- option id to search for
|
|
ClassId -- reqd class id
|
|
VendorId -- reqd vendor id
|
|
Opt -- variable to store the found option.
|
|
|
|
Return Value:
|
|
Win32 errors
|
|
|
|
--*/
|
|
{
|
|
DWORD Error;
|
|
|
|
//
|
|
// exact match.
|
|
//
|
|
|
|
Error = DhcpOptClassGetMemOptionExact(
|
|
Ctxt,
|
|
Options,
|
|
Option,
|
|
ClassId,
|
|
VendorId,
|
|
Opt
|
|
);
|
|
|
|
return Error;
|
|
} // DhcpOptClassGetMemOption()
|
|
|
|
DWORD
|
|
DhcpOptClassGetOptionSimple(
|
|
IN PDHCP_REQUEST_CONTEXT Ctxt,
|
|
IN PM_OPTCLASS Options,
|
|
IN DWORD Option,
|
|
IN DWORD ClassId,
|
|
IN DWORD VendorId,
|
|
OUT LPBYTE OptData OPTIONAL,
|
|
IN OUT DWORD *OptDataSize,
|
|
IN BOOL fUtf8
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This routine copies the option data value for the option id specified
|
|
by the "Option" parameter onto the buffer "OptData" and fills the size
|
|
of the buffer filled onto the parameter "OptDataSize". If the buffer
|
|
is of insufficient size (input size is also specified by the
|
|
"OptDataSize" parameter), then the required size is filled in, and
|
|
ERROR_MORE_DATA is returned.
|
|
|
|
No special processing is done for option OPTION_VENDOR_SPEC_INFO --
|
|
i.e. if there are multiple vendor specific option ID's defined, the
|
|
information is not collated. Use DhcpOptClassGetOption for that.
|
|
|
|
The buffer "OptData" is filled in with the option as it would need to
|
|
be sent on the wire.
|
|
|
|
Arguments:
|
|
Ctxt -- client request context
|
|
Options -- the option-class list to search in for reqd option
|
|
Option -- option id to search for
|
|
ClassId -- the user class to seach for
|
|
VendorId -- the vendor class to seach for
|
|
OptData -- the input buffer to fill in with option data information
|
|
This can be NULL if OptDataSize is set to zero on input.
|
|
OptDataSize -- on input this should be the size of the above buffer,
|
|
and on output it would be set to the actual size required or used
|
|
for this option.
|
|
|
|
Return Value:
|
|
ERROR_MORE_DATA if the input buffer size is insufficient.
|
|
Other Win32 errors
|
|
|
|
--*/
|
|
{
|
|
DWORD Error;
|
|
PM_OPTION Opt;
|
|
|
|
//
|
|
// get the option first.
|
|
//
|
|
|
|
Opt = NULL;
|
|
Error = DhcpOptClassGetMemOption(
|
|
Ctxt,
|
|
Options,
|
|
Option,
|
|
ClassId,
|
|
VendorId,
|
|
&Opt
|
|
);
|
|
if( ERROR_SUCCESS != Error ) return ERROR_FILE_NOT_FOUND;
|
|
|
|
DhcpAssert(NULL != Opt);
|
|
|
|
//
|
|
// Convert formats.
|
|
//
|
|
|
|
return DhcpParseRegistryOption(
|
|
Opt->Val,
|
|
Opt->Len,
|
|
OptData,
|
|
OptDataSize,
|
|
fUtf8
|
|
);
|
|
|
|
}
|
|
|
|
DWORD
|
|
DhcpOptClassGetOption(
|
|
IN PDHCP_REQUEST_CONTEXT Ctxt,
|
|
IN PM_OPTCLASS Options,
|
|
IN DWORD Option,
|
|
IN DWORD ClassId,
|
|
IN DWORD VendorId,
|
|
OUT LPBYTE OptData OPTIONAL,
|
|
IN OUT DWORD *OptDataSize,
|
|
IN BOOL fUtf8
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This routine copies the option data value for the option id specified
|
|
by the "Option" parameter onto the buffer "OptData" and fills the size
|
|
of the buffer filled onto the parameter "OptDataSize". If the buffer
|
|
is of insufficient size (input size is also specified by the
|
|
"OptDataSize" parameter), then the required size is filled in, and
|
|
ERROR_MORE_DATA is returned.
|
|
|
|
If the "Option" parameter is OPTION_VENDOR_SPEC_INFO, then, this
|
|
routine collates the information for ALL vendor id's (vendor id 1 to
|
|
vendor id 254) that are present for the particular class id and vendor
|
|
id, and pulls them together (constructing the resulting option as
|
|
required by the DHCP draft) and returns that in the OptData buffer.
|
|
Note that if the size of the resultant buffer would end up bigger than
|
|
255 (which is the erstwhile maximum size allowed on wire), only so many
|
|
vendor optiosn are included as is possible to keep the count within
|
|
this size. Also, if there is already an OPTION_VENDOR_SPEC_INFO option
|
|
defined, then that is used instead of the specific options.
|
|
|
|
The buffer "OptData" is filled in with the option as it would need to
|
|
be sent on the wire.
|
|
|
|
Arguments:
|
|
Ctxt -- client request context
|
|
Options -- the option-class list to search in for reqd option
|
|
Option -- option id to search for
|
|
ClassId -- the user class to seach for
|
|
VendorId -- the vendor class to seach for
|
|
OptData -- the input buffer to fill in with option data information
|
|
This can be NULL if OptDataSize is set to zero on input.
|
|
OptDataSize -- on input this should be the size of the above buffer,
|
|
and on output it would be set to the actual size required or used
|
|
for this option.
|
|
|
|
Return Value:
|
|
ERROR_MORE_DATA if the input buffer size is insufficient.
|
|
Other Win32 errors
|
|
|
|
--*/
|
|
{
|
|
DWORD Error, Index, InBufferSize;
|
|
DWORD ThisSize, InBufferSizeTmp, OutBufferSize;
|
|
|
|
//
|
|
// Jus' try to get 'un option.
|
|
//
|
|
|
|
Error = DhcpOptClassGetOptionSimple(
|
|
Ctxt,
|
|
Options,
|
|
Option,
|
|
ClassId,
|
|
VendorId,
|
|
OptData,
|
|
OptDataSize,
|
|
fUtf8
|
|
);
|
|
if( OPTION_VENDOR_SPEC_INFO != Option
|
|
|| ERROR_FILE_NOT_FOUND != Error ) {
|
|
//
|
|
// Vendor spec option not requested, or succeeded or unknown error
|
|
//
|
|
return Error;
|
|
}
|
|
|
|
//
|
|
// process each vendor spec option and collate 'em
|
|
//
|
|
|
|
InBufferSize = InBufferSizeTmp = *OptDataSize;
|
|
OutBufferSize = 0;
|
|
for( Index = 1; Index < OPTION_END ; Index ++ ) {
|
|
if(InBufferSizeTmp > 0) {
|
|
*OptData = (BYTE)Index;
|
|
}
|
|
ThisSize = (InBufferSizeTmp>1)?(InBufferSizeTmp-2):0;
|
|
Error = DhcpOptClassGetOptionSimple(
|
|
Ctxt,
|
|
Options,
|
|
ConvertOptIdToMemValue(Index, TRUE),
|
|
ClassId,
|
|
VendorId,
|
|
OptData+2,
|
|
&ThisSize,
|
|
fUtf8
|
|
);
|
|
if( ERROR_SUCCESS != Error && ERROR_MORE_DATA != Error ) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// found a vendor spec option, check buffer size.. if too big
|
|
// but we have found some before, then quit loop..
|
|
//
|
|
|
|
if( InBufferSizeTmp + ThisSize + 2 > OPTION_END ) {
|
|
if( OutBufferSize ) break;
|
|
continue;
|
|
}
|
|
|
|
if( InBufferSizeTmp < ThisSize + 2) {
|
|
InBufferSizeTmp = 0;
|
|
} else {
|
|
InBufferSizeTmp -= ThisSize + 2;
|
|
OptData[1] =(BYTE)ThisSize;
|
|
OptData += ThisSize + 2;
|
|
}
|
|
OutBufferSize += ThisSize + 2;
|
|
}
|
|
|
|
if( OutBufferSize == 0 ) return ERROR_FILE_NOT_FOUND;
|
|
*OptDataSize = OutBufferSize;
|
|
if( OutBufferSize > InBufferSize ) return ERROR_MORE_DATA;
|
|
return ERROR_SUCCESS;
|
|
} // DhcpOptClassGetOption()
|
|
|
|
|
|
//
|
|
//
|
|
// abstract: options priority (1) Reservation, (2) Scope Level and (3) Global
|
|
// get the options for the client based on its context.( resv, userid or vendorid )
|
|
// this function grovels through the internal ( residing in memory ) options
|
|
// based on the client context. The options at the reservation level has the highest priority, at the scope level
|
|
// the next highest priority and the global level the lowest priority.
|
|
//
|
|
//
|
|
|
|
DWORD
|
|
DhcpGetOptionByContext(
|
|
IN DHCP_IP_ADDRESS Address,
|
|
IN PDHCP_REQUEST_CONTEXT Ctxt,
|
|
IN DWORD Option,
|
|
IN OUT LPBYTE OptData,
|
|
IN OUT DWORD *OptDataSize,
|
|
OUT DWORD *Level,
|
|
IN BOOL fUtf8
|
|
)
|
|
{
|
|
|
|
DWORD Error = ERROR_FILE_NOT_FOUND;
|
|
PM_OPTLIST OptList = NULL;
|
|
|
|
if( !DhcpGlobalThisServer ) return ERROR_FILE_NOT_FOUND;
|
|
if( !Ctxt ) return ERROR_FILE_NOT_FOUND;
|
|
|
|
if( Level ) *Level = DHCP_OPTION_LEVEL_RESERVATION;
|
|
if( Ctxt->Reservation )
|
|
Error = DhcpOptClassGetOption(
|
|
Ctxt,
|
|
&(Ctxt->Reservation->Options),
|
|
Option,
|
|
Ctxt->ClassId,
|
|
Ctxt->VendorId,
|
|
OptData,
|
|
OptDataSize,
|
|
fUtf8
|
|
);
|
|
|
|
if( ERROR_SUCCESS == Error) return ERROR_SUCCESS;
|
|
if( ERROR_MORE_DATA == Error) return Error;
|
|
|
|
if( Level ) *Level = DHCP_OPTION_LEVEL_SCOPE;
|
|
|
|
if( Ctxt->Subnet )
|
|
Error = DhcpOptClassGetOption(
|
|
Ctxt,
|
|
&(Ctxt->Subnet->Options),
|
|
Option,
|
|
Ctxt->ClassId,
|
|
Ctxt->VendorId,
|
|
OptData,
|
|
OptDataSize,
|
|
fUtf8
|
|
);
|
|
|
|
if( ERROR_SUCCESS == Error) return ERROR_SUCCESS;
|
|
if( ERROR_MORE_DATA == Error) return Error;
|
|
if( Level ) *Level = DHCP_OPTION_LEVEL_GLOBAL;
|
|
|
|
if( Ctxt->Server )
|
|
Error = DhcpOptClassGetOption(
|
|
Ctxt,
|
|
&(Ctxt->Server->Options),
|
|
Option,
|
|
Ctxt->ClassId,
|
|
Ctxt->VendorId,
|
|
OptData,
|
|
OptDataSize,
|
|
fUtf8
|
|
);
|
|
|
|
return Error;
|
|
|
|
} // DhcpGetOptionByContext()
|
|
|
|
//
|
|
//
|
|
// checks the options based on userid/classid. This function follows the following algorithm.
|
|
// (a) Check for options with the passed classid/vendorid if both are non NULL. If success return.
|
|
// (b) If vendorid is non NULL and userid is NULL, get value for this option. If success return.
|
|
// (c) If userid is non NULL and vendor id is NULL, get value for this option. If success return.
|
|
// (d) If all else fails, go for the default options with zero value for vendorid and userid.
|
|
//
|
|
// To figure out the size of the option this function may be called
|
|
// with OptData set to NULL. In that case the error code is ERROR_MORE_DATA
|
|
// and the function will return.
|
|
//
|
|
//
|
|
|
|
DWORD
|
|
DhcpGetOption(
|
|
IN DHCP_IP_ADDRESS Address,
|
|
IN PDHCP_REQUEST_CONTEXT Ctxt,
|
|
IN DWORD Option,
|
|
IN OUT LPBYTE OptData, // copied into buffer
|
|
IN OUT DWORD *OptDataSize, // input buffer size and filled with output buffer size
|
|
OUT DWORD *Level, // OPTIONAL
|
|
IN BOOL fUtf8
|
|
)
|
|
{
|
|
DWORD Error = ERROR_FILE_NOT_FOUND;
|
|
DWORD lClsId;
|
|
DWORD lVendId;
|
|
|
|
|
|
if( !DhcpGlobalThisServer ) return ERROR_FILE_NOT_FOUND;
|
|
if( !Ctxt ) return ERROR_FILE_NOT_FOUND;
|
|
|
|
//
|
|
// local variables that will hold the classid/vendorid
|
|
//
|
|
|
|
lClsId = Ctxt -> ClassId;
|
|
lVendId = Ctxt -> VendorId;
|
|
|
|
//
|
|
// both classid and vendorid are present.
|
|
//
|
|
|
|
if (( Ctxt -> ClassId ) &&
|
|
( Ctxt -> VendorId )) {
|
|
Error = DhcpGetOptionByContext( Address, Ctxt, Option, OptData, OptDataSize, Level, fUtf8 );
|
|
}
|
|
|
|
if (( Error == ERROR_SUCCESS ) ||
|
|
( Error == ERROR_MORE_DATA )) {
|
|
return( Error );
|
|
}
|
|
|
|
//
|
|
// only vendor id is present or the above call failed.
|
|
//
|
|
|
|
if ( Ctxt -> VendorId ) {
|
|
Ctxt -> ClassId = 0;
|
|
Error = DhcpGetOptionByContext( Address, Ctxt, Option, OptData, OptDataSize, Level, fUtf8 );
|
|
}
|
|
|
|
Ctxt -> ClassId = lClsId;
|
|
|
|
if (( Error == ERROR_SUCCESS ) ||
|
|
( Error == ERROR_MORE_DATA )) {
|
|
return( Error );
|
|
}
|
|
|
|
//
|
|
// only classid is present or the above call failed
|
|
//
|
|
|
|
if ( Ctxt -> ClassId ) {
|
|
Ctxt -> VendorId = 0;
|
|
Error = DhcpGetOptionByContext( Address, Ctxt, Option, OptData, OptDataSize, Level, fUtf8 );
|
|
}
|
|
|
|
Ctxt -> VendorId = lVendId;
|
|
if (( Error == ERROR_SUCCESS ) ||
|
|
( Error == ERROR_MORE_DATA )) {
|
|
return ( Error );
|
|
}
|
|
|
|
//
|
|
// niether classid nor vendorid is present or all the calls above failed, get default options.
|
|
//
|
|
|
|
Ctxt -> VendorId = Ctxt -> ClassId = 0;
|
|
Error = DhcpGetOptionByContext( Address, Ctxt, Option, OptData, OptDataSize, Level, fUtf8 );
|
|
Ctxt -> VendorId = lVendId;
|
|
Ctxt -> ClassId = lClsId;
|
|
return Error;
|
|
} // DhcpGetOption()
|
|
|
|
//BeginExport(function)
|
|
DWORD
|
|
DhcpGetParameter(
|
|
IN DHCP_IP_ADDRESS Address,
|
|
IN PDHCP_REQUEST_CONTEXT Ctxt,
|
|
IN DWORD Option,
|
|
OUT LPBYTE *OptData, // allocated by funciton
|
|
OUT DWORD *OptDataSize,
|
|
OUT DWORD *Level // OPTIONAL
|
|
) //EndExport(function)
|
|
{
|
|
LPBYTE Ptr;
|
|
LPBYTE RetVal;
|
|
DWORD Size;
|
|
DWORD Error;
|
|
|
|
*OptData = NULL;
|
|
*OptDataSize = 0;
|
|
|
|
Size = 0;
|
|
Error = DhcpGetOption(Address, Ctxt, Option, NULL, &Size,
|
|
Level,FALSE);
|
|
if( ERROR_MORE_DATA != Error ) return Error;
|
|
|
|
if( 0 == Size ) return ERROR_SUCCESS;
|
|
|
|
RetVal = DhcpAllocateMemory(Size);
|
|
if( NULL == RetVal ) return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
Error = DhcpGetOption(Address, Ctxt, Option, RetVal, &Size,
|
|
Level, FALSE);
|
|
if( ERROR_SUCCESS != Error ) {
|
|
DhcpAssert(ERROR_MORE_DATA != Error);
|
|
DhcpFreeMemory(RetVal);
|
|
} else {
|
|
*OptData = RetVal;
|
|
*OptDataSize = Size;
|
|
}
|
|
|
|
return Error;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
DWORD
|
|
DhcpGetParameterForAddress(
|
|
IN DHCP_IP_ADDRESS Address,
|
|
IN DWORD ClassId,
|
|
IN DWORD Option,
|
|
OUT LPBYTE *OptData, // allocated by function
|
|
OUT DWORD *OptDataSize,
|
|
OUT DWORD *Level // OPTIONAL
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Error;
|
|
DHCP_REQUEST_CONTEXT Ctxt;
|
|
|
|
// this routine does not work for multicast address.
|
|
DhcpAssert( !CLASSD_HOST_ADDR(Address) );
|
|
|
|
Ctxt.Server = DhcpGetCurrentServer();
|
|
Ctxt.Subnet = NULL;
|
|
Ctxt.Range = NULL;
|
|
Ctxt.Reservation = NULL;
|
|
Ctxt.ClassId = ClassId;
|
|
Ctxt.VendorId = 0;
|
|
Ctxt.fMSFTClient = FALSE;
|
|
|
|
Error = DhcpGetSubnetForAddress(Address, &Ctxt);
|
|
if( ERROR_SUCCESS != Error ) return Error;
|
|
|
|
return DhcpGetParameter(Address, &Ctxt, Option, OptData, OptDataSize, Level);
|
|
}
|
|
|
|
//BeginExport(function)
|
|
DWORD
|
|
DhcpGetAndCopyOption(
|
|
IN DHCP_IP_ADDRESS Address,
|
|
IN PDHCP_REQUEST_CONTEXT Ctxt,
|
|
IN DWORD Option,
|
|
IN OUT LPBYTE OptData, // fill input buffer --max size is given as OptDataSize parameter
|
|
IN OUT DWORD *OptDataSize,
|
|
OUT DWORD *Level, // OPTIONAL
|
|
IN BOOL fUtf8
|
|
) //EndExport(function)
|
|
{
|
|
return DhcpGetOption(
|
|
Address, Ctxt, Option, OptData, OptDataSize, Level, fUtf8);
|
|
}
|
|
|
|
//BeginExport(function)
|
|
DHCP_IP_ADDRESS
|
|
DhcpGetSubnetMaskForAddress(
|
|
IN DHCP_IP_ADDRESS AnyIpAddress
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Error;
|
|
PM_SUBNET Subnet;
|
|
|
|
if( !DhcpGlobalThisServer ) return 0;
|
|
Error = MemServerGetAddressInfo(
|
|
DhcpGlobalThisServer,
|
|
AnyIpAddress,
|
|
&Subnet,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
if( ERROR_SUCCESS != Error ) return 0;
|
|
DhcpAssert(Subnet);
|
|
return Subnet->Mask;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
DWORD
|
|
DhcpLookupReservationByHardwareAddress(
|
|
IN DHCP_IP_ADDRESS ClientSubnetAddress,
|
|
IN LPBYTE RawHwAddr,
|
|
IN DWORD RawHwAddrSize,
|
|
IN OUT PDHCP_REQUEST_CONTEXT ClientCtxt // fill in the Subnet and Reservation of the client
|
|
) //EndExport(function)
|
|
{
|
|
PM_SUBNET Subnet = NULL;
|
|
ARRAY_LOCATION Loc;
|
|
DWORD Error;
|
|
DWORD SScopeId;
|
|
DWORD UIDSize;
|
|
LPBYTE UID;
|
|
|
|
Error = MemServerGetAddressInfo(
|
|
ClientCtxt->Server,
|
|
ClientSubnetAddress,
|
|
&(ClientCtxt->Subnet),
|
|
&(ClientCtxt->Range),
|
|
&(ClientCtxt->Excl),
|
|
&(ClientCtxt->Reservation)
|
|
);
|
|
if( ERROR_SUCCESS != Error ) return Error;
|
|
if( NULL == ClientCtxt->Subnet ) return ERROR_FILE_NOT_FOUND;
|
|
SScopeId = ClientCtxt->Subnet->SuperScopeId;
|
|
|
|
Error = MemArrayInitLoc(&(ClientCtxt->Server->Subnets), &Loc);
|
|
DhcpAssert(ERROR_SUCCESS == Error );
|
|
|
|
while( ERROR_FILE_NOT_FOUND != Error ) {
|
|
DhcpAssert(ERROR_SUCCESS == Error );
|
|
|
|
Error = MemArrayGetElement(&(ClientCtxt->Server->Subnets), &Loc, (LPVOID *)&Subnet);
|
|
DhcpAssert(ERROR_SUCCESS == Error);
|
|
|
|
if( 0 == SScopeId && ClientCtxt->Subnet != Subnet ) {
|
|
Error = MemArrayNextLoc(&(ClientCtxt->Server->Subnets), &Loc);
|
|
continue;
|
|
}
|
|
if( Subnet->SuperScopeId == SScopeId ) {
|
|
UID = NULL;
|
|
Error = DhcpMakeClientUID(
|
|
RawHwAddr,
|
|
RawHwAddrSize,
|
|
0 /* hardware type is hardcoded anyways.. */,
|
|
Subnet->Address,
|
|
&UID,
|
|
&UIDSize
|
|
);
|
|
if( ERROR_SUCCESS != Error ) return Error;
|
|
|
|
Error = MemReserveFindByClientUID(
|
|
&(Subnet->Reservations),
|
|
UID,
|
|
UIDSize,
|
|
&(ClientCtxt->Reservation)
|
|
);
|
|
DhcpFreeMemory(UID);
|
|
if( ERROR_SUCCESS == Error && NULL != &(ClientCtxt->Reservation) ) {
|
|
ClientCtxt->Subnet = Subnet;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
Error = MemArrayNextLoc(&(ClientCtxt->Server->Subnets), &Loc);
|
|
}
|
|
|
|
return ERROR_FILE_NOT_FOUND;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
VOID
|
|
DhcpReservationGetAddressAndType(
|
|
IN PM_RESERVATION Reservation,
|
|
OUT DHCP_IP_ADDRESS *Address,
|
|
OUT BYTE *Type
|
|
) //EndExport(function)
|
|
{
|
|
if( NULL == Reservation ) {
|
|
DhcpAssert(FALSE);
|
|
*Address = 0; *Type = 0;
|
|
return;
|
|
}
|
|
*Address = Reservation->Address;
|
|
*Type = (BYTE)Reservation->Flags;
|
|
}
|
|
|
|
|
|
//BeginExport(function)
|
|
VOID
|
|
DhcpSubnetGetSubnetAddressAndMask(
|
|
IN PM_SUBNET Subnet,
|
|
OUT DHCP_IP_ADDRESS *Address,
|
|
OUT DHCP_IP_ADDRESS *Mask
|
|
) //EndExport(function)
|
|
{
|
|
if( NULL == Subnet ) {
|
|
DhcpAssert(FALSE);
|
|
*Address = *Mask = 0;
|
|
return;
|
|
}
|
|
|
|
*Address = Subnet->Address;
|
|
*Mask = Subnet->Mask;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
BOOL
|
|
DhcpSubnetIsDisabled(
|
|
IN PM_SUBNET Subnet,
|
|
IN BOOL fBootp
|
|
) //EndExport(function)
|
|
{
|
|
|
|
if( Subnet?(IS_DISABLED(Subnet->State)):TRUE )
|
|
return TRUE;
|
|
|
|
if( FALSE == Subnet->fSubnet ) {
|
|
//
|
|
// no more checks for MADCAP Scopes
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
return !MemSubnetCheckBootpDhcp(Subnet, fBootp, TRUE);
|
|
}
|
|
|
|
//BeginExport(function)
|
|
BOOL
|
|
DhcpSubnetIsSwitched(
|
|
IN PM_SUBNET Subnet
|
|
) //EndExport(function)
|
|
{
|
|
return Subnet?(IS_SWITCHED(Subnet->State)):FALSE;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
DWORD
|
|
DhcpGetSubnetForAddress( // fill in with the right subnet for given address
|
|
IN DHCP_IP_ADDRESS Address,
|
|
IN OUT PDHCP_REQUEST_CONTEXT ClientCtxt
|
|
) //EndExport(function)
|
|
{
|
|
if( NULL == ClientCtxt->Server ) return ERROR_FILE_NOT_FOUND;
|
|
return MemServerGetAddressInfo(
|
|
ClientCtxt->Server,
|
|
Address,
|
|
&(ClientCtxt->Subnet),
|
|
&(ClientCtxt->Range),
|
|
&(ClientCtxt->Excl),
|
|
&(ClientCtxt->Reservation)
|
|
);
|
|
}
|
|
|
|
//BeginExport(function)
|
|
DWORD
|
|
DhcpGetMScopeForAddress( // fill in with the right subnet for given address
|
|
IN DHCP_IP_ADDRESS Address,
|
|
IN OUT PDHCP_REQUEST_CONTEXT ClientCtxt
|
|
) //EndExport(function)
|
|
{
|
|
if( NULL == ClientCtxt->Server ) return ERROR_FILE_NOT_FOUND;
|
|
return MemServerGetMAddressInfo(
|
|
ClientCtxt->Server,
|
|
Address,
|
|
&(ClientCtxt->Subnet),
|
|
&(ClientCtxt->Range),
|
|
&(ClientCtxt->Excl),
|
|
NULL
|
|
);
|
|
}
|
|
|
|
//BeginExport(function)
|
|
DWORD
|
|
DhcpLookupDatabaseByHardwareAddress( // see if the client has any previous address in the database
|
|
IN OUT PDHCP_REQUEST_CONTEXT ClientCtxt, // set this with details if found
|
|
IN LPBYTE RawHwAddr,
|
|
IN DWORD RawHwAddrSize,
|
|
OUT DHCP_IP_ADDRESS *desiredIpAddress // if found, fill this with the ip address found
|
|
) //EndExport(function)
|
|
{
|
|
PM_SUBNET Subnet = NULL;
|
|
ARRAY_LOCATION Loc;
|
|
DWORD Error;
|
|
DWORD SScopeId;
|
|
DWORD UIDSize;
|
|
DWORD Size;
|
|
LPBYTE UID;
|
|
|
|
DhcpAssert(NULL != ClientCtxt->Subnet);
|
|
if( NULL == ClientCtxt->Subnet ) return ERROR_INVALID_PARAMETER;
|
|
SScopeId = ClientCtxt->Subnet->SuperScopeId;
|
|
|
|
Error = MemArrayInitLoc(&(ClientCtxt->Server->Subnets), &Loc);
|
|
DhcpAssert(ERROR_SUCCESS == Error );
|
|
|
|
while( ERROR_FILE_NOT_FOUND != Error ) {
|
|
DhcpAssert(ERROR_SUCCESS == Error );
|
|
|
|
Error = MemArrayGetElement(&(ClientCtxt->Server->Subnets), &Loc, (LPVOID *)&Subnet);
|
|
DhcpAssert(ERROR_SUCCESS == Error);
|
|
|
|
if( 0 == SScopeId && ClientCtxt->Subnet != Subnet ) {
|
|
Error = MemArrayNextLoc(&(ClientCtxt->Server->Subnets), &Loc);
|
|
continue;
|
|
}
|
|
|
|
if( Subnet->SuperScopeId == SScopeId ) {
|
|
UID = NULL;
|
|
Error = DhcpMakeClientUID(
|
|
RawHwAddr,
|
|
RawHwAddrSize,
|
|
0 /* hardware type is hardcoded anyways.. */,
|
|
Subnet->Address,
|
|
&UID,
|
|
&UIDSize
|
|
);
|
|
if( ERROR_SUCCESS != Error ) return Error;
|
|
|
|
LOCK_DATABASE();
|
|
Error = DhcpJetOpenKey(
|
|
DhcpGlobalClientTable[HARDWARE_ADDRESS_INDEX].ColName,
|
|
UID,
|
|
UIDSize
|
|
);
|
|
DhcpFreeMemory(UID);
|
|
if( ERROR_SUCCESS == Error ) {
|
|
Size = sizeof(DHCP_IP_ADDRESS);
|
|
Error = DhcpJetGetValue(
|
|
DhcpGlobalClientTable[IPADDRESS_INDEX].ColHandle,
|
|
desiredIpAddress,
|
|
&Size
|
|
);
|
|
if( ERROR_SUCCESS == Error ) {
|
|
DhcpAssert(((*desiredIpAddress) & Subnet->Mask) == Subnet->Address);
|
|
UNLOCK_DATABASE();
|
|
return DhcpGetSubnetForAddress(
|
|
*desiredIpAddress,
|
|
ClientCtxt
|
|
);
|
|
}
|
|
}
|
|
UNLOCK_DATABASE();
|
|
}
|
|
|
|
Error = MemArrayNextLoc(&(ClientCtxt->Server->Subnets), &Loc);
|
|
}
|
|
|
|
return ERROR_FILE_NOT_FOUND;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
DWORD
|
|
DhcpRequestSomeAddress( // get some address in this context
|
|
IN PDHCP_REQUEST_CONTEXT ClientCtxt,
|
|
OUT DHCP_IP_ADDRESS *desiredIpAddress,
|
|
IN BOOL fBootp
|
|
) //EndExport(function)
|
|
{
|
|
static BOOL DhcpRangeFull = FALSE;
|
|
static BOOL BootpRangeFull = FALSE;
|
|
BOOL Result;
|
|
PM_SUBNET Subnet;
|
|
DWORD Error;
|
|
|
|
*desiredIpAddress = 0;
|
|
|
|
if( ClientCtxt->Subnet->fSubnet == TRUE &&
|
|
FALSE == MemSubnetCheckBootpDhcp(ClientCtxt->Subnet, fBootp, TRUE ) ) {
|
|
//
|
|
// For DHCP Scopes, check to see if any required type of addreses
|
|
// are present.. If not, return error saying none available.
|
|
// No such checks for MADCAP Scopes.
|
|
//
|
|
return ERROR_DHCP_INVALID_DHCP_CLIENT;
|
|
}
|
|
|
|
|
|
LOCK_MEMORY();
|
|
Result = MemSubnetRequestAddress(
|
|
ClientCtxt->Subnet,
|
|
0,
|
|
TRUE, /* also acquire the address */
|
|
fBootp, /* asking for dynamic bootp address? */
|
|
desiredIpAddress,
|
|
&Subnet
|
|
);
|
|
UNLOCK_MEMORY();
|
|
if( Result ) {
|
|
DhcpAssert(*desiredIpAddress && Subnet);
|
|
ClientCtxt->Subnet = Subnet;
|
|
Error = MemSubnetGetAddressInfo(
|
|
Subnet,
|
|
*desiredIpAddress,
|
|
&(ClientCtxt->Range),
|
|
&(ClientCtxt->Excl),
|
|
&(ClientCtxt->Reservation)
|
|
);
|
|
DhcpAssert(ERROR_SUCCESS == Error);
|
|
if( fBootp ) {
|
|
BootpRangeFull = FALSE;
|
|
} else {
|
|
DhcpRangeFull = FALSE;
|
|
}
|
|
return Error;
|
|
}
|
|
|
|
if( FALSE == (fBootp? BootpRangeFull : DhcpRangeFull) ) {
|
|
//
|
|
// avoid repeated logging..
|
|
//
|
|
if( fBootp ) BootpRangeFull = TRUE; else DhcpRangeFull = TRUE;
|
|
DhcpUpdateAuditLog(
|
|
fBootp?DHCP_IP_BOOTP_LOG_RANGE_FULL:DHCP_IP_LOG_RANGE_FULL,
|
|
fBootp? GETSTRING( DHCP_IP_BOOTP_LOG_RANGE_FULL_NAME)
|
|
: GETSTRING( DHCP_IP_LOG_RANGE_FULL_NAME ),
|
|
ClientCtxt->Subnet->Address,
|
|
NULL,
|
|
0,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
return ERROR_DHCP_RANGE_FULL;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
BOOL
|
|
DhcpSubnetInSameSuperScope(
|
|
IN PM_SUBNET Subnet,
|
|
IN DHCP_IP_ADDRESS IpAddress2
|
|
) //EndExport(function)
|
|
{
|
|
ULONG SubnetMask, SubnetAddress, Error;
|
|
PM_SUBNET Subnet2;
|
|
|
|
DhcpSubnetGetSubnetAddressAndMask(
|
|
Subnet,
|
|
&SubnetAddress,
|
|
&SubnetMask
|
|
);
|
|
|
|
if( (IpAddress2 & SubnetMask ) == SubnetAddress ) return TRUE;
|
|
|
|
Error = MemServerGetAddressInfo(
|
|
DhcpGlobalThisServer,
|
|
IpAddress2,
|
|
&Subnet2,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
if( ERROR_SUCCESS != Error ) return FALSE;
|
|
|
|
// --ft: Addresses are in the same superscope if in the same subnet or if there is a
|
|
// superscope and both subnets belong to it. (Subnets out of a superscope have SuperScopeId == 0)
|
|
|
|
if (Subnet == Subnet2 ) return TRUE;
|
|
|
|
return (Subnet->SuperScopeId == Subnet2->SuperScopeId) && ( 0 != Subnet->SuperScopeId );
|
|
}
|
|
|
|
//BeginExport(function)
|
|
BOOL
|
|
DhcpInSameSuperScope(
|
|
IN DHCP_IP_ADDRESS Address1,
|
|
IN DHCP_IP_ADDRESS Address2
|
|
) //EndExport(function)
|
|
{
|
|
PM_SUBNET Subnet;
|
|
DWORD Error;
|
|
|
|
if( !DhcpGlobalThisServer ) return FALSE;
|
|
|
|
Error = MemServerGetAddressInfo(
|
|
DhcpGlobalThisServer,
|
|
Address1,
|
|
&Subnet,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
if( ERROR_SUCCESS != Error ) return FALSE;
|
|
|
|
return DhcpSubnetInSameSuperScope(Subnet, Address2);
|
|
}
|
|
|
|
//BeginExport(function)
|
|
BOOL
|
|
DhcpAddressIsOutOfRange(
|
|
IN DHCP_IP_ADDRESS Address,
|
|
IN PDHCP_REQUEST_CONTEXT ClientCtxt,
|
|
IN BOOL fBootp
|
|
) //EndExport(function)
|
|
{
|
|
return MemServerIsOutOfRangeAddress(ClientCtxt->Server, Address, fBootp);
|
|
}
|
|
|
|
//BeginExport(function)
|
|
BOOL
|
|
DhcpAddressIsExcluded(
|
|
IN DHCP_IP_ADDRESS Address,
|
|
IN PDHCP_REQUEST_CONTEXT ClientCtxt
|
|
) //EndExport(function)
|
|
{
|
|
return MemServerIsExcludedAddress(ClientCtxt->Server, Address);
|
|
}
|
|
|
|
//BeginExport(function)
|
|
BOOL
|
|
DhcpRequestSpecificAddress(
|
|
IN PDHCP_REQUEST_CONTEXT ClientCtxt,
|
|
IN DHCP_IP_ADDRESS Address
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Error;
|
|
|
|
Error = MemServerGetAddressInfo(
|
|
ClientCtxt->Server,
|
|
Address,
|
|
&(ClientCtxt->Subnet),
|
|
&(ClientCtxt->Range),
|
|
&(ClientCtxt->Excl),
|
|
&(ClientCtxt->Reservation)
|
|
);
|
|
|
|
if( ERROR_SUCCESS != Error || !ClientCtxt->Range || ClientCtxt->Excl )
|
|
return FALSE;
|
|
|
|
LOCK_MEMORY();
|
|
Error = MemSubnetRequestAddress(
|
|
ClientCtxt->Subnet,
|
|
Address,
|
|
TRUE,
|
|
FALSE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
UNLOCK_MEMORY();
|
|
|
|
if( TRUE != Error )
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
LogReleaseAddress(
|
|
IN DHCP_IP_ADDRESS Address
|
|
)
|
|
{
|
|
//
|
|
// For DBG builds alone, just print the fact that an
|
|
// IP address got released..
|
|
//
|
|
#if DBG
|
|
DhcpUpdateAuditLog(
|
|
DHCP_IP_LOG_DELETED,
|
|
GETSTRING( DHCP_IP_LOG_DELETED_NAME ),
|
|
Address,
|
|
NULL,
|
|
0,
|
|
L"IPAddr Released"
|
|
);
|
|
#endif
|
|
}
|
|
|
|
//BeginExport(function)
|
|
DWORD
|
|
DhcpReleaseBootpAddress(
|
|
IN DHCP_IP_ADDRESS Address
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Error;
|
|
|
|
LOCK_MEMORY();
|
|
Error = MemServerReleaseAddress(
|
|
DhcpGlobalThisServer,
|
|
Address,
|
|
TRUE
|
|
);
|
|
UNLOCK_MEMORY();
|
|
|
|
if( ERROR_SUCCESS == Error ) LogReleaseAddress(Address);
|
|
return Error;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
DWORD
|
|
DhcpReleaseAddress(
|
|
IN DHCP_IP_ADDRESS Address
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Error;
|
|
|
|
LOCK_MEMORY();
|
|
Error = MemServerReleaseAddress(
|
|
DhcpGlobalThisServer,
|
|
Address,
|
|
FALSE
|
|
);
|
|
UNLOCK_MEMORY();
|
|
|
|
if( ERROR_SUCCESS == Error ) LogReleaseAddress(Address);
|
|
return Error;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
DWORD
|
|
DhcpServerGetSubnetCount(
|
|
IN PM_SERVER Server
|
|
) //EndExport(function)
|
|
{
|
|
return Server?MemArraySize(&(Server->Subnets)):0;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
DWORD
|
|
DhcpServerGetMScopeCount(
|
|
IN PM_SERVER Server
|
|
) //EndExport(function)
|
|
{
|
|
return Server?MemArraySize(&(Server->MScopes)):0;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
DWORD
|
|
DhcpServerGetClassId(
|
|
IN PM_SERVER Server,
|
|
IN LPBYTE ClassIdBytes,
|
|
IN DWORD nClassIdBytes
|
|
) //EndExport(function)
|
|
{
|
|
PM_CLASSDEF ClassDef;
|
|
DWORD Error;
|
|
|
|
if( NULL == ClassIdBytes || 0 == nClassIdBytes )
|
|
return 0;
|
|
|
|
Error = MemServerGetClassDef(
|
|
Server,
|
|
0,
|
|
NULL,
|
|
nClassIdBytes,
|
|
ClassIdBytes,
|
|
&ClassDef
|
|
);
|
|
if( ERROR_SUCCESS != Error ) return 0;
|
|
if( TRUE == ClassDef->IsVendor ) return 0;
|
|
return ClassDef->ClassId;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
DWORD
|
|
DhcpServerGetVendorId(
|
|
IN PM_SERVER Server,
|
|
IN LPBYTE VendorIdBytes,
|
|
IN DWORD nVendorIdBytes
|
|
) //EndExport(function)
|
|
{
|
|
PM_CLASSDEF ClassDef;
|
|
DWORD Error;
|
|
|
|
if( NULL == VendorIdBytes || 0 == nVendorIdBytes )
|
|
return 0;
|
|
|
|
Error = MemServerGetClassDef(
|
|
Server,
|
|
0,
|
|
NULL,
|
|
nVendorIdBytes,
|
|
VendorIdBytes,
|
|
&ClassDef
|
|
);
|
|
if( ERROR_SUCCESS != Error ) return 0;
|
|
if( FALSE == ClassDef->IsVendor ) return 0;
|
|
return ClassDef->ClassId;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
BOOL
|
|
DhcpServerIsAddressReserved(
|
|
IN PM_SERVER Server,
|
|
IN DHCP_IP_ADDRESS Address
|
|
) //EndExport(function)
|
|
{
|
|
return MemServerIsReservedAddress(Server,Address);
|
|
}
|
|
|
|
//BeginExport(function)
|
|
BOOL
|
|
DhcpServerIsAddressOutOfRange(
|
|
IN PM_SERVER Server,
|
|
IN DHCP_IP_ADDRESS Address,
|
|
IN BOOL fBootp
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Error;
|
|
PM_RANGE Range;
|
|
PM_EXCL Excl;
|
|
|
|
Error = MemServerGetAddressInfo(
|
|
Server,
|
|
Address,
|
|
NULL,
|
|
&Range,
|
|
&Excl,
|
|
NULL
|
|
);
|
|
if( ERROR_SUCCESS != Error ) return TRUE;
|
|
|
|
if( Excl || NULL == Range ) return TRUE;
|
|
if( 0 == (Range->State & (fBootp? MM_FLAG_ALLOW_BOOTP : MM_FLAG_ALLOW_DHCP) ) ) {
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
BOOL
|
|
DhcpSubnetIsAddressExcluded(
|
|
IN PM_SUBNET Subnet,
|
|
IN DHCP_IP_ADDRESS Address
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Error;
|
|
PM_EXCL Excl;
|
|
|
|
Error = MemSubnetGetAddressInfo(
|
|
Subnet,
|
|
Address,
|
|
NULL,
|
|
&Excl,
|
|
NULL
|
|
);
|
|
if( ERROR_SUCCESS != Error ) return FALSE;
|
|
return NULL != Excl;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
BOOL
|
|
DhcpSubnetIsAddressOutOfRange(
|
|
IN PM_SUBNET Subnet,
|
|
IN DHCP_IP_ADDRESS Address,
|
|
IN BOOL fBootp
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Error;
|
|
PM_RANGE Range;
|
|
PM_EXCL Excl;
|
|
PM_RESERVATION Resv;
|
|
|
|
//
|
|
// passing exclusion and resvation info to check if the address is ok.
|
|
//
|
|
|
|
Error = MemSubnetGetAddressInfo(
|
|
Subnet,
|
|
Address,
|
|
&Range,
|
|
&Excl,
|
|
&Resv
|
|
);
|
|
|
|
if( ERROR_SUCCESS != Error ) return TRUE;
|
|
if( NULL == Range ) return TRUE;
|
|
if( 0 == (Range->State & (fBootp? MM_FLAG_ALLOW_BOOTP : MM_FLAG_ALLOW_DHCP) ) ) {
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
BOOL
|
|
DhcpSubnetIsAddressReserved(
|
|
IN PM_SUBNET Subnet,
|
|
IN DHCP_IP_ADDRESS Address
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Error;
|
|
PM_RESERVATION Reservation;
|
|
|
|
Error = MemSubnetGetAddressInfo(
|
|
Subnet,
|
|
Address,
|
|
NULL,
|
|
NULL,
|
|
&Reservation
|
|
);
|
|
|
|
if( ERROR_SUCCESS == Error && NULL != Reservation )
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#if 0 // defined in rpcapi2.c with better implementation
|
|
//BeginExport(function)
|
|
DWORD
|
|
DhcpUpdateReservationInfo(
|
|
IN DHCP_IP_ADDRESS IpAddress,
|
|
IN LPBYTE SetClientUID,
|
|
IN DWORD SetClientUIDLength
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Error;
|
|
DWORD Flags;
|
|
PM_SUBNET Subnet;
|
|
PM_RESERVATION Reservation;
|
|
|
|
Error = MemServerGetAddressInfo(
|
|
DhcpGetCurrentServer(),
|
|
IpAddress,
|
|
&Subnet,
|
|
NULL,
|
|
NULL,
|
|
&Reservation
|
|
);
|
|
if( ERROR_SUCCESS != Error || NULL == Subnet || NULL == Reservation ) {
|
|
DhcpAssert(FALSE);
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
Flags = Reservation->Flags;
|
|
|
|
return MemReserveReplace(
|
|
&Subnet->Reservations,
|
|
IpAddress,
|
|
Flags,
|
|
SetClientUID,
|
|
SetClientUIDLength
|
|
);
|
|
}
|
|
#endif 0
|
|
|
|
static const
|
|
DWORD TryThreshold = 5;
|
|
//BeginExport(function)
|
|
DWORD
|
|
DhcpRegFlushServerIfNeeded(
|
|
VOID
|
|
) //EndExport(function)
|
|
{
|
|
static ULONG DummyLong = 0;
|
|
|
|
if( TryThreshold <= (ULONG)InterlockedIncrement(&DummyLong) ) {
|
|
DummyLong = 0;
|
|
return DhcpRegFlushServer(FALSE);
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
DWORD
|
|
DhcpFlushBitmaps( // do a flush of all bitmaps that have changed
|
|
VOID
|
|
) //EndExport(function)
|
|
{
|
|
|
|
return DhcpRegFlushServer(TRUE);
|
|
}
|
|
|
|
//BeginExport(function)
|
|
DWORD
|
|
DhcpServerFindMScope(
|
|
IN PM_SERVER Server,
|
|
IN DWORD ScopeId,
|
|
IN LPWSTR Name, // Multicast scope name or NULL if this is not the key to search on
|
|
OUT PM_MSCOPE *MScope
|
|
) //EndExport(function)
|
|
{
|
|
return MemServerFindMScope(
|
|
Server,
|
|
ScopeId,
|
|
Name,
|
|
MScope
|
|
);
|
|
}
|
|
|
|
|
|
//BeginExport(function)
|
|
BOOL
|
|
DhcpServerValidateNewMScopeId(
|
|
IN PM_SERVER Server,
|
|
IN DWORD MScopeId
|
|
) //EndExport(function)
|
|
{
|
|
PM_SUBNET pMScope;
|
|
DWORD Error;
|
|
|
|
Error = MemServerFindMScope(
|
|
Server,
|
|
MScopeId,
|
|
INVALID_MSCOPE_NAME,
|
|
&pMScope
|
|
);
|
|
|
|
if ( ERROR_SUCCESS == Error ) {
|
|
return FALSE;
|
|
} else {
|
|
DhcpAssert( ERROR_FILE_NOT_FOUND == Error );
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
//BeginExport(function)
|
|
BOOL
|
|
DhcpServerValidateNewMScopeName(
|
|
IN PM_SERVER Server,
|
|
IN LPWSTR Name
|
|
) //EndExport(function)
|
|
{
|
|
PM_SUBNET pMScope;
|
|
DWORD Error;
|
|
|
|
Error = MemServerFindMScope(
|
|
Server,
|
|
INVALID_MSCOPE_ID,
|
|
Name,
|
|
&pMScope
|
|
);
|
|
|
|
if ( ERROR_SUCCESS == Error ) {
|
|
return FALSE;
|
|
} else {
|
|
DhcpAssert( ERROR_FILE_NOT_FOUND == Error );
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
//BeginExport(function)
|
|
DWORD
|
|
DhcpMScopeReleaseAddress(
|
|
IN DWORD MScopeId,
|
|
IN DHCP_IP_ADDRESS Address
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Error;
|
|
PM_SUBNET pMScope;
|
|
|
|
Error = DhcpServerFindMScope(
|
|
DhcpGetCurrentServer(),
|
|
MScopeId,
|
|
NULL, /* scope name */
|
|
&pMScope
|
|
);
|
|
if ( ERROR_SUCCESS != Error ) {
|
|
DhcpPrint((DEBUG_ERRORS, "Could not find MScope object - id %lx, %ld\n", MScopeId, Error));
|
|
return Error;
|
|
}
|
|
|
|
LOCK_MEMORY();
|
|
Error = MemSubnetReleaseAddress(
|
|
pMScope,
|
|
Address,
|
|
FALSE
|
|
);
|
|
UNLOCK_MEMORY();
|
|
|
|
if( ERROR_SUCCESS == Error ) LogReleaseAddress(Address);
|
|
return Error;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
DWORD
|
|
DhcpSubnetRequestSpecificAddress(
|
|
PM_SUBNET Subnet,
|
|
DHCP_IP_ADDRESS IpAddress
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Error;
|
|
|
|
LOCK_MEMORY();
|
|
Error = MemSubnetRequestAddress(
|
|
Subnet,
|
|
IpAddress,
|
|
TRUE,
|
|
FALSE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
UNLOCK_MEMORY();
|
|
return Error;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
DWORD
|
|
DhcpSubnetReleaseAddress(
|
|
IN PM_SUBNET Subnet,
|
|
IN DHCP_IP_ADDRESS Address
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Error;
|
|
|
|
LOCK_MEMORY();
|
|
Error = MemSubnetReleaseAddress(
|
|
Subnet,
|
|
Address,
|
|
FALSE
|
|
);
|
|
UNLOCK_MEMORY();
|
|
|
|
if( ERROR_SUCCESS == Error ) LogReleaseAddress(Address);
|
|
return Error;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
DWORD
|
|
MadcapGetMScopeListOption(
|
|
IN DHCP_IP_ADDRESS ServerIpAddress,
|
|
OUT LPBYTE *OptVal,
|
|
IN OUT WORD *OptSize
|
|
) //EndExport(function)
|
|
{
|
|
PM_SERVER pServer;
|
|
PM_SUBNET pScope = NULL;
|
|
ARRAY_LOCATION Loc;
|
|
WORD TotalScopeDescLen;
|
|
WORD ScopeCount;
|
|
DWORD Error;
|
|
WORD TotalSize;
|
|
PBYTE pBuf,pScopeBuf;
|
|
WORD DbgScopeCount = 0;
|
|
|
|
pServer = DhcpGetCurrentServer();
|
|
|
|
Error = MemArrayInitLoc(&(pServer->MScopes), &Loc);
|
|
if ( ERROR_FILE_NOT_FOUND == Error ) {
|
|
return Error;
|
|
}
|
|
|
|
// First find out how much memory do we need.
|
|
ScopeCount = TotalScopeDescLen = 0;
|
|
while ( ERROR_FILE_NOT_FOUND != Error ) {
|
|
|
|
Error = MemArrayGetElement(&(pServer->MScopes), &Loc, (LPVOID *)&pScope);
|
|
DhcpAssert(ERROR_SUCCESS == Error);
|
|
|
|
if (!IS_DISABLED(pScope->State)) {
|
|
if (pScope->Name) {
|
|
TotalScopeDescLen += (WORD) ConvertUnicodeToUTF8(pScope->Name, -1, NULL, 0 );
|
|
// add for the lang tag, flags, name length etc.
|
|
TotalScopeDescLen += (3 + wcslen(pScope->LangTag));
|
|
|
|
}
|
|
ScopeCount++;
|
|
}
|
|
|
|
Error = MemArrayNextLoc(&(pServer->MScopes), &Loc);
|
|
}
|
|
|
|
if (!ScopeCount) {
|
|
return ERROR_FILE_NOT_FOUND;
|
|
}
|
|
// MBUG - assumes IPv4
|
|
TotalSize = 1 // scope count
|
|
+ ScopeCount * ( 10 ) // scope id, last addr, TTL, name count
|
|
+ TotalScopeDescLen; // all the descriptor.
|
|
|
|
pScopeBuf = DhcpAllocateMemory( TotalSize );
|
|
|
|
if ( !pScopeBuf ) {
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
RtlZeroMemory( pScopeBuf, TotalSize );
|
|
|
|
pBuf = pScopeBuf;
|
|
// store the scope count
|
|
*pBuf++ = (BYTE)ScopeCount;
|
|
|
|
// now for each scope store the id and the descriptor.
|
|
Error = MemArrayInitLoc(&(pServer->MScopes), &Loc);
|
|
DhcpAssert(ERROR_SUCCESS == Error);
|
|
|
|
while ( ERROR_FILE_NOT_FOUND != Error ) {
|
|
LPSTR pDesc;
|
|
BYTE DescLen;
|
|
DWORD LastAddr;
|
|
|
|
Error = MemArrayGetElement(&(pServer->MScopes), &Loc, (LPVOID *)&pScope);
|
|
DhcpAssert(ERROR_SUCCESS == Error);
|
|
|
|
|
|
if (!IS_DISABLED(pScope->State)) {
|
|
PM_RANGE Range = NULL;
|
|
ARRAY_LOCATION LastLoc = 0;
|
|
|
|
*(DWORD UNALIGNED *)pBuf = htonl(pScope->MScopeId);
|
|
pBuf += 4;
|
|
// store last address
|
|
Error = MemArrayLastLoc(&(pScope->Ranges), &LastLoc);
|
|
if (ERROR_SUCCESS == Error) {
|
|
Error = MemArrayGetElement(&(pScope->Ranges), &LastLoc, &Range);
|
|
DhcpAssert(ERROR_SUCCESS == Error);
|
|
LastAddr = htonl(Range->End);
|
|
} else {
|
|
LastAddr = htonl(pScope->MScopeId);
|
|
}
|
|
*(DWORD UNALIGNED *)pBuf = LastAddr;
|
|
pBuf += 4;
|
|
// store the ttl
|
|
*pBuf++ = pScope->TTL;
|
|
// name count
|
|
*pBuf++ = 1;
|
|
|
|
|
|
if ( pScope->Name ) {
|
|
char LangTag[80];
|
|
// Name flags
|
|
*pBuf++ = 128;
|
|
// Language tag
|
|
DhcpAssert(pScope->LangTag);
|
|
if (NULL == DhcpUnicodeToOem(pScope->LangTag, LangTag) ) {
|
|
DhcpFreeMemory( pScopeBuf );
|
|
return ERROR_INVALID_DATA;
|
|
}
|
|
*pBuf++ = (BYTE)strlen(LangTag);
|
|
memcpy(pBuf, LangTag, strlen(LangTag));
|
|
pBuf += strlen(LangTag);
|
|
TotalScopeDescLen -= (3 + strlen(LangTag));
|
|
pDesc = pBuf + 1;
|
|
if ( 0 == (DescLen = (BYTE) ConvertUnicodeToUTF8(pScope->Name, -1, pDesc, TotalScopeDescLen) ) ) {
|
|
DhcpFreeMemory( pScopeBuf );
|
|
return ERROR_BAD_FORMAT;
|
|
}
|
|
TotalScopeDescLen -= DescLen;
|
|
} else {
|
|
DescLen = 0;
|
|
}
|
|
*pBuf++ = DescLen;
|
|
pBuf += DescLen;
|
|
#ifdef DBG
|
|
DbgScopeCount++;
|
|
#endif
|
|
}
|
|
|
|
Error = MemArrayNextLoc(&(pServer->MScopes), &Loc);
|
|
}
|
|
|
|
DhcpAssert( ScopeCount == DbgScopeCount );
|
|
|
|
*OptVal = pScopeBuf;
|
|
*OptSize = TotalSize;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
BOOL
|
|
DhcpRequestSpecificMAddress(
|
|
IN PDHCP_REQUEST_CONTEXT ClientCtxt,
|
|
IN DHCP_IP_ADDRESS Address
|
|
) //EndExport(function)
|
|
{
|
|
DWORD Error;
|
|
|
|
Error = MemSubnetGetAddressInfo(
|
|
ClientCtxt->Subnet,
|
|
Address,
|
|
&(ClientCtxt->Range),
|
|
&(ClientCtxt->Excl),
|
|
&(ClientCtxt->Reservation)
|
|
);
|
|
|
|
if( ERROR_SUCCESS != Error || !ClientCtxt->Range || ClientCtxt->Excl )
|
|
return FALSE;
|
|
|
|
LOCK_MEMORY();
|
|
Error = MemSubnetRequestAddress(
|
|
ClientCtxt->Subnet,
|
|
Address,
|
|
TRUE,
|
|
FALSE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
UNLOCK_MEMORY();
|
|
|
|
if( ERROR_SUCCESS != Error )
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
BOOL
|
|
DhcpMScopeIsAddressReserved(
|
|
IN DWORD MScopeId,
|
|
IN DHCP_IP_ADDRESS Address
|
|
) //EndExport(function)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//BeginExport(function)
|
|
BOOL
|
|
DhcpIsSubnetStateDisabled(
|
|
IN ULONG SubnetState
|
|
) //EndExport(function)
|
|
{
|
|
return IS_DISABLED(SubnetState);
|
|
}
|
|
|
|
|
|
// This function returns TRUE if the subnet address in question does not exist in
|
|
// the list of subnets for the current server. This SHOULD NOT BE CALLED with the
|
|
// Read/Write lock taken as the lock is taken right here.
|
|
//BeginExport(function)
|
|
BOOL
|
|
DhcpServerIsNotServicingSubnet(
|
|
IN DWORD IpAddressInSubnet
|
|
) //EndExport(function)
|
|
{
|
|
|
|
DWORD Mask;
|
|
|
|
DhcpAcquireReadLock();
|
|
|
|
Mask = DhcpGetSubnetMaskForAddress(IpAddressInSubnet);
|
|
|
|
DhcpReleaseReadLock();
|
|
|
|
return Mask == 0;
|
|
}
|
|
|
|
VOID _inline
|
|
ConvertHostToNetworkString(
|
|
IN LPWSTR String,
|
|
IN ULONG NChars
|
|
)
|
|
{
|
|
while(NChars--) {
|
|
*String = htons(*String);
|
|
String ++;
|
|
}
|
|
}
|
|
|
|
// this function takes a class def and converts it into packs into a buffer as follows
|
|
// [size-hi] [size-lo] class-id-bytes [size-hi] [size-lo] name [size-hi] [lo] descr
|
|
// where name and descr are LPWSTR (nul terminated) that are just copied over..
|
|
VOID
|
|
ConvertClassDefToWireFormat(
|
|
IN PM_CLASSDEF ClassDef,
|
|
OUT LPBYTE *Buf, // allocated by this function
|
|
OUT DWORD *BufSize // size allocated by this function
|
|
)
|
|
{
|
|
DWORD Size;
|
|
LPBYTE Mem;
|
|
|
|
*Buf = NULL; *BufSize = 0;
|
|
Size = 6+ ((3+ClassDef->nBytes)&~3) // round off nbytes by "4"
|
|
+ sizeof(WCHAR)*(1+wcslen(ClassDef->Name));
|
|
if( NULL == ClassDef->Comment ) Size += sizeof(WCHAR);
|
|
else Size += sizeof(WCHAR)*(1+wcslen(ClassDef->Comment));
|
|
|
|
Mem = DhcpAllocateMemory(Size);
|
|
if( NULL == Mem ) return ;
|
|
|
|
*Buf = Mem; *BufSize = Size;
|
|
Mem[0] = (BYTE)(ClassDef->nBytes >> 8) ;
|
|
Mem[1] = (BYTE)(ClassDef->nBytes & 0xFF);
|
|
Mem += 2;
|
|
memcpy(Mem, ClassDef->ActualBytes, ClassDef->nBytes);
|
|
Mem += (ClassDef->nBytes+3)&~3; // round off to multiple of "4"
|
|
Size = sizeof(WCHAR)*(1+wcslen(ClassDef->Name));
|
|
Mem[0] = (BYTE)(Size>>8);
|
|
Mem[1] = (BYTE)(Size&0xFF);
|
|
Mem += 2;
|
|
memcpy(Mem, (LPBYTE)(ClassDef->Name), Size);
|
|
ConvertHostToNetworkString((LPWSTR)Mem, Size/2);
|
|
Mem += Size;
|
|
if( NULL == ClassDef->Comment ) {
|
|
Mem[0] = 0; Mem[1] = sizeof(WCHAR);
|
|
Mem += 2; memset(Mem, 0, sizeof(WCHAR));
|
|
Mem += sizeof(WCHAR);
|
|
} else {
|
|
Size = sizeof(WCHAR)*(1+wcslen(ClassDef->Comment));
|
|
Mem[0] = (BYTE)(Size>>8);
|
|
Mem[1] = (BYTE)(Size&0xFF);
|
|
Mem += 2;
|
|
memcpy(Mem, (LPBYTE)(ClassDef->Comment), Size);
|
|
ConvertHostToNetworkString((LPWSTR)Mem, Size/2);
|
|
Mem += Size;
|
|
}
|
|
}
|
|
|
|
//BeginExport(function)
|
|
// This function tries to create a list of all classes (wire-class-id, class name, descr)
|
|
// and send this as an option. but since the list can be > 255 it has to be make a continuation...
|
|
// and also, we dont want the list truncated somewhere in the middle.. so we try to append
|
|
// information for each class separately to see if it succeeds..
|
|
LPBYTE
|
|
DhcpAppendClassList(
|
|
IN OUT LPBYTE BufStart,
|
|
IN OUT LPBYTE BufEnd
|
|
) //EndExport(function)
|
|
{
|
|
PARRAY ClassDefList;
|
|
ARRAY_LOCATION Loc;
|
|
PM_CLASSDEF ThisClassDef = NULL;
|
|
DWORD Result, Size;
|
|
LPBYTE Buf;
|
|
|
|
ClassDefList = &(DhcpGetCurrentServer()->ClassDefs.ClassDefArray);
|
|
for( Result = MemArrayInitLoc(ClassDefList, &Loc)
|
|
; ERROR_FILE_NOT_FOUND != Result ;
|
|
Result = MemArrayNextLoc(ClassDefList, &Loc)
|
|
) { // walk thru the array and add classes..
|
|
Result = MemArrayGetElement(ClassDefList, &Loc, (LPVOID)&ThisClassDef);
|
|
DhcpAssert(ERROR_SUCCESS == Result && NULL != ThisClassDef);
|
|
|
|
if( ThisClassDef->IsVendor ) continue; // don't list vendor classes
|
|
|
|
Buf = NULL; Size = 0;
|
|
ConvertClassDefToWireFormat(ThisClassDef, &Buf, &Size);
|
|
if( NULL == Buf || 0 == Size ) { // some error.. could not convert this class.. ignore..
|
|
DhcpAssert(FALSE);
|
|
continue;
|
|
}
|
|
|
|
BufStart = (LPBYTE)DhcpAppendOption(
|
|
(LPOPTION)BufStart,
|
|
OPTION_USER_CLASS,
|
|
(PVOID)Buf,
|
|
Size,
|
|
(LPVOID)BufEnd
|
|
);
|
|
DhcpFreeMemory(Buf);
|
|
}
|
|
|
|
return BufStart;
|
|
}
|
|
|
|
|
|
//BeginExport(function)
|
|
DWORD
|
|
DhcpMemInit(
|
|
VOID
|
|
) //EndExport(function)
|
|
{
|
|
#if DBG_MEM
|
|
return MemInit();
|
|
#else
|
|
return ERROR_SUCCESS;
|
|
#endif
|
|
}
|
|
|
|
//BeginExport(function)
|
|
VOID
|
|
DhcpMemCleanup(
|
|
VOID
|
|
) //EndExport(function)
|
|
{
|
|
#if DBG_MEM
|
|
MemCleanup();
|
|
#endif
|
|
}
|
|
|
|
ULONG DhcpGlobalMemoryAllocated = 0;
|
|
|
|
#if DBG_MEM
|
|
#undef DhcpAllocateMemory
|
|
#undef DhcpFreeMemory
|
|
LPVOID
|
|
DhcpAllocateMemory(
|
|
IN DWORD nBytes
|
|
)
|
|
{
|
|
DWORD SizeBytes = ROUND_UP_COUNT(sizeof(DWORD),ALIGN_WORST);
|
|
LPDWORD RetVal;
|
|
|
|
DhcpAssert(nBytes != 0);
|
|
RetVal = MemAlloc(nBytes+SizeBytes);
|
|
if( NULL == RetVal ) return NULL;
|
|
|
|
*RetVal = nBytes+SizeBytes;
|
|
InterlockedExchangeAdd(&DhcpGlobalMemoryAllocated, nBytes+SizeBytes);
|
|
return SizeBytes + (LPBYTE)RetVal;
|
|
}
|
|
|
|
VOID
|
|
DhcpFreeMemory(
|
|
IN LPVOID Ptr
|
|
)
|
|
{
|
|
DWORD Result;
|
|
LONG Size;
|
|
|
|
if( NULL == Ptr ) {
|
|
Require(FALSE);
|
|
return;
|
|
}
|
|
|
|
Ptr = ((LPBYTE)Ptr) - ROUND_UP_COUNT(sizeof(DWORD), ALIGN_WORST);
|
|
Size = *((LPLONG)Ptr);
|
|
|
|
Result = MemFree(Ptr);
|
|
DhcpAssert(ERROR_SUCCESS == Result);
|
|
InterlockedExchangeAdd(&DhcpGlobalMemoryAllocated, -Size);
|
|
}
|
|
#endif DBG
|
|
|
|
//================================================================================
|
|
// end of file
|
|
//================================================================================
|
|
|
|
|
|
|
|
|