Windows-Server-2003/net/dhcp/server/mm/subnet.c

796 lines
25 KiB
C

//================================================================================
// Copyright (C) 1997 Microsoft Corporation
// Author: RameshV
// Description: implements the basic structures for managing (multicast) scopes
// ThreadSafe: no
// Locks: none
// Please read stdinfo.txt for programming style.
//================================================================================
#include <mm.h>
#include <array.h>
#include <opt.h>
#include <optl.h>
#include <optclass.h>
#include <bitmask.h>
#include <range.h>
#include <reserve.h>
#include <dhcp.h>
#include <winnls.h>
#include "server\uniqid.h"
#include "subnet.h"
// the following are the flags bits used for subnet object.
#define DEFAULT_SCOPE 0x01
#define IS_DEFAULT_SCOPE( _subnet ) ((_subnet)->Flags & DEFAULT_SCOPE == DEFAULT_SCOPE )
#define SET_DEFAULT_SCOPE( _subnet ) ((_subnet)->Flags |= DEFAULT_SCOPE )
#define RESET_DEFAULT_SCOPE( _subnet ) ((_subnet)->Flags &= ~DEFAULT_SCOPE)
//BeginExport(function)
DWORD
MemSubnetInit(
OUT PM_SUBNET *pSubnet,
IN DWORD Address,
IN DWORD Mask,
IN DWORD State,
IN DWORD SuperScopeId,
IN LPWSTR Name,
IN LPWSTR Description
) //EndExport(function)
{
DWORD Error;
DWORD Size;
PM_SUBNET Subnet;
AssertRet(pSubnet, ERROR_INVALID_PARAMETER);
AssertRet( !(CLASSD_HOST_ADDR(Address)||CLASSE_HOST_ADDR(Address)),
ERROR_INVALID_PARAMETER );
Require((Address&Mask));
*pSubnet = NULL;
Size = ROUND_UP_COUNT(sizeof(*Subnet), ALIGN_WORST);
Size += sizeof(WCHAR) * (Name?(1+wcslen(Name)):0);
Size += sizeof(WCHAR) * (Description?(1+wcslen(Description)):0);
Subnet = MemAlloc(Size);
if( NULL == Subnet) return ERROR_NOT_ENOUGH_MEMORY;
Size = ROUND_UP_COUNT(sizeof(*Subnet), ALIGN_WORST);
Subnet->Name = Subnet->Description = NULL;
if( Name ) {
Subnet->Name = (LPWSTR)(Size + (LPBYTE)Subnet);
wcscpy(Subnet->Name, Name);
Size += sizeof(WCHAR) * ( 1 + wcslen(Name));
}
if( Description ) {
Subnet->Description = (LPWSTR)( Size + (LPBYTE)Subnet );
wcscpy(Subnet->Description, Description);
}
Subnet->ServerPtr = NULL;
Subnet->Address = Address;
Subnet->Mask = Mask;
Subnet->State = State;
Subnet->SuperScopeId = SuperScopeId;
Subnet->fSubnet = TRUE;
Subnet->Policy = AddressPolicyNone;
Subnet->UniqId = INVALID_UNIQ_ID;
Error = MemOptClassInit(&Subnet->Options);
if( ERROR_SUCCESS != Error ) { MemFree(Subnet); return Error; }
Error = MemArrayInit(&Subnet->Ranges);
if( ERROR_SUCCESS != Error ) { MemFree(Subnet); return Error; }
Error = MemArrayInit(&Subnet->Exclusions);
if( ERROR_SUCCESS != Error ) { MemFree(Subnet); return Error; }
Error = MemArrayInit(&Subnet->Servers);
if( ERROR_SUCCESS != Error ) { MemFree(Subnet); return Error; }
Error = MemReserveInit(&Subnet->Reservations);
if( ERROR_SUCCESS != Error ) { MemFree(Subnet); return Error; }
*pSubnet = Subnet;
return ERROR_SUCCESS;
}
VOID
GetLangTag(
WCHAR LangTag[]
)
{
WCHAR b1[8], b2[8];
b1[0] = b2[0] = L'\0';
GetLocaleInfoW(
LOCALE_SYSTEM_DEFAULT, LOCALE_SISO639LANGNAME,
b1, sizeof(b1)/sizeof(b1[0])
);
GetLocaleInfoW(
LOCALE_SYSTEM_DEFAULT, LOCALE_SISO3166CTRYNAME,
b2, sizeof(b2)/sizeof(b2[0])
);
if (_wcsicmp(b1, b2))
wsprintf(LangTag, L"%s-%s", b1, b2);
else
wcscpy(LangTag, b1);
}
//BeginExport(function)
DWORD
MemMScopeInit(
OUT PM_SUBNET *pMScope,
IN DWORD MScopeId,
IN DWORD State,
IN DWORD AddressPolicy,
IN BYTE TTL,
IN LPWSTR Name,
IN LPWSTR Description,
IN LPWSTR LangTag,
IN DATE_TIME ExpiryTime
) //EndExport(function)
{
DWORD Error;
DWORD Size;
PM_SUBNET MScope;
WCHAR DummyLangTag[100];
AssertRet(pMScope, ERROR_INVALID_PARAMETER);
//AssertRet(MScopeId, ERROR_INVALID_PARAMETER);
Require(LangTag);
if( NULL == LangTag ) {
LangTag = DummyLangTag;
GetLangTag(DummyLangTag);
}
*pMScope = NULL;
Size = ROUND_UP_COUNT(sizeof(*MScope), ALIGN_WORST);
Size += sizeof(WCHAR) * (Name?(1+wcslen(Name)):0);
Size += sizeof(WCHAR) * (Description?(1+wcslen(Description)):0);
Size += sizeof(WCHAR) * (1+wcslen(LangTag));
MScope = MemAlloc(Size);
if( NULL == MScope) return ERROR_NOT_ENOUGH_MEMORY;
Size = ROUND_UP_COUNT(sizeof(*MScope), ALIGN_WORST);
MScope->Name = MScope->Description = MScope->LangTag = NULL;
if( Name ) {
MScope->Name = (LPWSTR)(Size + (LPBYTE)MScope);
wcscpy(MScope->Name, Name);
Size += sizeof(WCHAR) * ( 1 + wcslen(Name));
}
if( Description ) {
MScope->Description = (LPWSTR)( Size + (LPBYTE)MScope );
wcscpy(MScope->Description, Description);
Size += sizeof(WCHAR) * ( 1 + wcslen(Description));
}
MScope->LangTag = (LPWSTR)( Size + (LPBYTE)MScope );
wcscpy(MScope->LangTag, LangTag);
MScope->ServerPtr = NULL;
MScope->MScopeId = MScopeId;
MScope->State = State;
MScope->TTL = TTL;
MScope->fSubnet = FALSE;
MScope->Policy = AddressPolicy;
MScope->ExpiryTime = ExpiryTime;
Error = MemOptClassInit(&MScope->Options);
if( ERROR_SUCCESS != Error ) { MemFree(MScope); return Error; }
Error = MemArrayInit(&MScope->Ranges);
if( ERROR_SUCCESS != Error ) { MemFree(MScope); return Error; }
Error = MemArrayInit(&MScope->Exclusions);
if( ERROR_SUCCESS != Error ) { MemFree(MScope); return Error; }
Error = MemArrayInit(&MScope->Servers);
if( ERROR_SUCCESS != Error ) { MemFree(MScope); return Error; }
Error = MemReserveInit(&MScope->Reservations);
if( ERROR_SUCCESS != Error ) { MemFree(MScope); return Error; }
*pMScope = MScope;
return ERROR_SUCCESS;
}
//BeginExport(function)
DWORD // SUCCESS if either of Excl or Range get filled, else FILE_NOT_FOUND
MemSubnetGetAddressInfo(
IN PM_SUBNET Subnet,
IN DWORD Address,
OUT PM_RANGE *Range, // OPTIONAL -- filled if a range could be found -- even if excluded
OUT PM_EXCL *Excl, // OPTIONAL -- filled if an exclusion could be found
OUT PM_RESERVATION *Reservation // OPTIONAL -- filled with a matching reservation, if found
) //EndExport(function)
{
ARRAY_LOCATION Location;
DWORD Error;
DWORD RetError;
PM_RANGE ThisRange;
PM_EXCL ThisExcl;
AssertRet(Subnet && (Range || Excl || Reservation), ERROR_INVALID_PARAMETER );
if( Subnet->fSubnet && (Address & Subnet->Mask) != Subnet->Address )
return ERROR_FILE_NOT_FOUND; // it is ok for MSCOPE objects, as Address refers to ScopeId
RetError = ERROR_FILE_NOT_FOUND;
if( Range ) {
*Range = NULL;
Error = MemArrayInitLoc(&Subnet->Ranges, &Location);
while( ERROR_FILE_NOT_FOUND != Error ) {
Require(ERROR_SUCCESS == Error);
Error = MemArrayGetElement(&Subnet->Ranges, &Location, (LPVOID *)&ThisRange);
Require(ERROR_SUCCESS == Error && ThisRange);
if( ThisRange->Start <= Address && Address <= ThisRange->End ) {
*Range = ThisRange;
RetError = ERROR_SUCCESS;
break;
}
Error = MemArrayNextLoc(&Subnet->Ranges, &Location);
}
}
if( Excl ) {
*Excl = NULL;
Error = MemArrayInitLoc(&Subnet->Exclusions, &Location);
while( ERROR_FILE_NOT_FOUND != Error ) {
Require(ERROR_SUCCESS == Error);
Error = MemArrayGetElement(&Subnet->Exclusions, &Location, (LPVOID *)&ThisExcl);
Require(ERROR_SUCCESS == Error && ThisExcl);
if( ThisExcl->Start <= Address && Address <= ThisExcl->End ) {
*Excl = ThisExcl;
RetError = ERROR_SUCCESS;
break;
}
Error = MemArrayNextLoc(&Subnet->Exclusions, &Location);
}
}
if( Reservation ) {
*Reservation = NULL;
Error = MemReserveFindByAddress(&Subnet->Reservations, Address, Reservation);
if( ERROR_SUCCESS == Error ) RetError = ERROR_SUCCESS;
}
return RetError;
}
//BeginExport(function)
DWORD // ERROR_SUCCESS on finding a collition, else ERROR_FILE_NOT_FOUND
MemSubnetFindCollision(
IN OUT PM_SUBNET Subnet,
IN DWORD Start,
IN DWORD End,
OUT PM_RANGE *Range, // OPTIONAL
OUT PM_EXCL *Excl // OPTIONAL
) //EndExport(function)
{
ARRAY_LOCATION Location;
DWORD Error;
DWORD RetError;
DWORD Cond;
PM_RANGE ThisRange;
PM_EXCL ThisExcl;
Require(Subnet && (Range || Excl));
if( Subnet->fSubnet ) { // checks ommitted for MCAST scopes.
if( (Start & Subnet->Mask) != (End & Subnet->Mask) )
return ERROR_INVALID_PARAMETER;
if( (Start & Subnet->Mask) != (Subnet->Address & Subnet->Mask) )
return ERROR_INVALID_PARAMETER;
}
RetError = ERROR_FILE_NOT_FOUND;
if(Range) {
*Range = NULL;
Error = MemArrayInitLoc(&Subnet->Ranges, &Location);
while( ERROR_FILE_NOT_FOUND != Error ) {
Require(ERROR_SUCCESS == Error);
Error = MemArrayGetElement(&Subnet->Ranges, &Location, (LPVOID *)&ThisRange);
Require(ERROR_SUCCESS == Error && ThisRange);
Cond = MemRangeCompare(Start,End, ThisRange->Start, ThisRange->End);
if( Cond != X_LESSTHAN_Y && Cond != Y_LESSTHAN_X ) {
// Collision has occured
*Range = ThisRange;
RetError = ERROR_SUCCESS;
break;
}
Error = MemArrayNextLoc(&Subnet->Ranges, &Location);
}
}
if( Excl ) {
*Excl = NULL;
Error = MemArrayInitLoc(&Subnet->Exclusions, &Location);
while( ERROR_FILE_NOT_FOUND != Error ) {
Require(ERROR_SUCCESS == Error);
Error = MemArrayGetElement(&Subnet->Exclusions, &Location, (LPVOID *)&ThisExcl);
Require(ERROR_SUCCESS == Error && ThisExcl);
Cond = MemRangeCompare(Start,End, ThisExcl->Start, ThisExcl->End);
if( Cond != X_LESSTHAN_Y && Cond != Y_LESSTHAN_X ) {
*Excl = ThisExcl;
RetError = ERROR_SUCCESS;
break;
}
Error = MemArrayNextLoc(&Subnet->Exclusions, &Location);
}
}
return RetError;
}
//BeginExport(function)
DWORD // ERROR_OBJECT_ALREADY_EXISTS on collision
MemSubnetAddRange( // check if the range is valid, and only then add it
IN OUT PM_SUBNET Subnet,
IN DWORD Start,
IN DWORD End,
IN DWORD State,
IN ULONG BootpAllocated,
IN ULONG MaxBootpAllowed,
OUT PM_RANGE *OverlappingRange,
IN ULONG UniqId
) //EndExport(function)
{
DWORD Error;
DWORD LocalError;
PM_RANGE NewRange;
AssertRet(Subnet && OverlappingRange, ERROR_INVALID_PARAMETER);
if( Subnet->fSubnet ) {
if( (Subnet->Address & Subnet->Mask) != (Start & Subnet->Mask) ||
(Start & Subnet->Mask) != (End & Subnet->Mask) )
return ERROR_INVALID_PARAMETER;
} else {
if (!CLASSD_HOST_ADDR(Start) || !CLASSD_HOST_ADDR(End)) {
return ERROR_INVALID_PARAMETER;
}
}
if( Start > End ) return ERROR_INVALID_PARAMETER;
*OverlappingRange = NULL;
Error = MemSubnetFindCollision(
Subnet,
Start,
End,
OverlappingRange,
NULL
);
if(ERROR_FILE_NOT_FOUND != Error ) { // collision with a range?
Require(ERROR_SUCCESS == Error);
return ERROR_OBJECT_ALREADY_EXISTS;
}
NewRange = MemAlloc(sizeof(*NewRange));
if( NULL == NewRange ) return ERROR_NOT_ENOUGH_MEMORY;
Error = MemRangeInit(
NewRange, Start, End, Subnet->fSubnet ? Subnet->Mask : 0, State,
BootpAllocated, MaxBootpAllowed );
if( ERROR_SUCCESS != Error ) {
MemFree(NewRange);
return Error;
}
NewRange->UniqId = UniqId;
Error = MemArrayAddElement(
&Subnet->Ranges,
NewRange
);
if( ERROR_SUCCESS != Error ) {
LocalError = MemRangeCleanup(NewRange);
Require(LocalError == ERROR_SUCCESS);
MemFree(NewRange);
}
return Error;
} // MemSubnetAddRange()
//BeginExport(function)
DWORD
MemSubnetAddRangeExpandOrContract(
IN PM_SUBNET Subnet,
IN DWORD StartAddress,
IN DWORD EndAddress,
OUT DWORD *OldStartAddress,
OUT DWORD *OldEndAddress
) //EndExport(function)
{
DWORD Error;
DWORD LocalError;
DWORD Cond;
DWORD nAddresses;
BOOL fExtend;
PM_RANGE OldRange;
PM_RANGE ThisRange;
PARRAY Ranges;
ARRAY_LOCATION Loc;
Ranges = &Subnet->Ranges;
*OldStartAddress = *OldEndAddress = 0;
OldRange = NULL;
Error = MemArrayInitLoc(Ranges, &Loc);
while( ERROR_FILE_NOT_FOUND != Error ) {
Require(ERROR_SUCCESS == Error);
Error = MemArrayGetElement(Ranges, &Loc, (LPVOID *)&ThisRange);
Require(ERROR_SUCCESS == Error && ThisRange);
Cond = MemRangeCompare(StartAddress, EndAddress, ThisRange->Start, ThisRange->End);
if( Cond != X_LESSTHAN_Y && Cond != Y_LESSTHAN_X ) {
if( OldRange ) return ERROR_OBJECT_ALREADY_EXISTS;
if( X_IN_Y != Cond && Y_IN_X != Cond )
return ERROR_OBJECT_ALREADY_EXISTS;
OldRange = ThisRange;
}
Error = MemArrayNextLoc(Ranges, &Loc);
} // while
if( NULL == OldRange ) return ERROR_FILE_NOT_FOUND;
*OldStartAddress = OldRange->Start;
*OldEndAddress = OldRange->End;
if( OldRange->Start < StartAddress ) {
fExtend = FALSE;
nAddresses = StartAddress - OldRange->Start;
} else {
fExtend = TRUE;
nAddresses = OldRange->Start - StartAddress;
}
Error = ERROR_SUCCESS;
if( nAddresses ) Error = MemRangeExtendOrContract(
OldRange,
nAddresses,
fExtend,
FALSE
);
if( ERROR_SUCCESS != Error ) return Error;
if( OldRange->End < EndAddress ) {
fExtend = TRUE;
nAddresses = EndAddress - OldRange->End;
} else {
fExtend = FALSE;
nAddresses = OldRange->End - EndAddress;
}
if( nAddresses ) Error = MemRangeExtendOrContract(
OldRange,
nAddresses,
fExtend,
TRUE
);
if ( ERROR_SUCCESS == Error ) {
// range changed, update the database
Error = DeleteRecord( OldRange->UniqId );
if ( ERROR_SUCCESS != Error ) {
return Error;
}
// mark it so that a new record is created.
OldRange->UniqId = INVALID_UNIQ_ID;
} // if
return Error;
} // MemSubnetAddRangeExpandOrContract()
//BeginExport(function)
DWORD
MemSubnetAddExcl(
IN OUT PM_SUBNET Subnet,
IN DWORD Start,
IN DWORD End,
OUT PM_EXCL *OverlappingExcl,
IN ULONG UniqId
) //EndExport(function)
{
DWORD Error;
DWORD LocalError;
PM_EXCL NewExcl;
AssertRet(Subnet && OverlappingExcl, ERROR_INVALID_PARAMETER);
if( Subnet->fSubnet ) {
if( (Subnet->Address & Subnet->Mask) != (Start & Subnet->Mask) ||
(Start & Subnet->Mask) != (End & Subnet->Mask) )
return ERROR_INVALID_PARAMETER;
}
if( Start > End ) return ERROR_INVALID_PARAMETER;
*OverlappingExcl = NULL;
Error = MemSubnetFindCollision(
Subnet,
Start,
End,
NULL,
OverlappingExcl
);
if(ERROR_FILE_NOT_FOUND != Error ) { // collision with a range?
Require(ERROR_SUCCESS == Error);
return ERROR_OBJECT_ALREADY_EXISTS;
}
NewExcl = MemAlloc(sizeof(*NewExcl));
if( NULL == NewExcl ) return ERROR_NOT_ENOUGH_MEMORY;
NewExcl->Start = Start;
NewExcl->End = End;
NewExcl->UniqId = UniqId;
Error = MemArrayAddElement(
&Subnet->Exclusions,
NewExcl
);
if( ERROR_SUCCESS != Error ) {
MemFree(NewExcl);
}
return Error;
} // MemSubnetAddExcl()
//BeginExport(function)
DWORD
MemSubnetDelRange(
IN OUT PM_SUBNET Subnet,
IN DWORD Start
) //EndExport(function)
{
DWORD Error;
PM_RANGE ThisRange;
ARRAY_LOCATION Location;
Error = MemArrayInitLoc(&Subnet->Ranges, &Location);
while( ERROR_FILE_NOT_FOUND != Error ) {
Require(ERROR_SUCCESS == Error);
Error = MemArrayGetElement(&Subnet->Ranges, &Location, (LPVOID *)&ThisRange);
Require(ERROR_SUCCESS == Error && ThisRange);
if( ThisRange->Start == Start ) { // Collision has occured
Error = DeleteRecord( ThisRange->UniqId );
if ( ERROR_SUCCESS != Error ) {
return Error;
}
Error = MemRangeCleanup(ThisRange);
Require(ERROR_SUCCESS == Error);
MemFree(ThisRange);
Error = MemArrayDelElement(&Subnet->Ranges, &Location, (LPVOID *)&ThisRange);
return ERROR_SUCCESS;
}
Error = MemArrayNextLoc(&Subnet->Ranges, &Location);
} // while
return ERROR_FILE_NOT_FOUND;
} // MemSubnetDelRange()
//BeginExport(function)
DWORD
MemSubnetDelExcl(
IN OUT PM_SUBNET Subnet,
IN DWORD Start
) //EndExport(function)
{
DWORD Error;
PM_EXCL ThisExcl;
ARRAY_LOCATION Location;
Error = MemArrayInitLoc(&Subnet->Exclusions, &Location);
while( ERROR_FILE_NOT_FOUND != Error ) {
Require(ERROR_SUCCESS == Error);
Error = MemArrayGetElement(&Subnet->Exclusions, &Location, (LPVOID *)&ThisExcl);
Require(ERROR_SUCCESS == Error && ThisExcl);
if( ThisExcl->Start == Start ) {
Error = DeleteRecord( ThisExcl->UniqId );
if ( ERROR_SUCCESS != Error ) {
return Error;
}
Error = MemArrayDelElement(&Subnet->Exclusions, &Location, (LPVOID *)&ThisExcl);
MemFree(ThisExcl);
return ERROR_SUCCESS;
}
Error = MemArrayNextLoc(&Subnet->Exclusions, &Location);
} // while
return ERROR_FILE_NOT_FOUND;
} // MemSubnetDelExcl()
//BeginExport(function)
DWORD
MemSubnetExtendOrContractRange(
IN OUT PM_SUBNET Subnet,
IN OUT PM_RANGE Range,
IN DWORD nAddresses, // how many addresses to extend by
IN BOOL fExtend, // is this an EXTEND? or a CONTRACT?
IN BOOL fEnd // is this operation to be done to END of range or START?
) //EndExport(function)
{
DWORD Error;
PM_RANGE CollidedRange;
AssertRet(Subnet && Range, ERROR_INVALID_PARAMETER);
if( Subnet->fSubnet ) { // for real subnets (non-multicast-scopes) do sanity check
if( fExtend ) {
if( fEnd ) {
if( ((Range->End + nAddresses) & Subnet->Mask) != (Range->Start & Subnet->Mask) )
return ERROR_INVALID_PARAMETER;
Error = MemSubnetFindCollision(
Subnet,
Range->End +1,
Range->End +nAddresses,
&CollidedRange,
NULL
);
if( ERROR_SUCCESS == Error && NULL != CollidedRange)
return ERROR_OBJECT_ALREADY_EXISTS;
} else {
if( ((Range->Start - nAddresses) & Subnet->Mask) != (Range->End & Subnet->Mask) )
return ERROR_INVALID_PARAMETER;
Error = MemSubnetFindCollision(
Subnet,
Range->Start - nAddresses,
Range->Start - 1,
&CollidedRange,
NULL
);
if( ERROR_SUCCESS == Error && NULL != CollidedRange)
return ERROR_OBJECT_ALREADY_EXISTS;
} // else
} // if
} // if
if( !fExtend && nAddresses > Range->End - Range->Start )
return ERROR_INVALID_PARAMETER;
Error = MemRangeExtendOrContract(
Range,
nAddresses,
fExtend,
fEnd
);
if ( ERROR_SUCCESS == Error ) {
// record modified
Error = DeleteRecord( Range->UniqId );
if ( ERROR_SUCCESS != Error ) {
return Error;
}
// mark for new rec creation
Range->UniqId = INVALID_UNIQ_ID;
} // if
return Error;
} // MemSubnetExtendOrContractRange()
//BeginExport(function)
DWORD
MemSubnetExtendOrContractExcl(
IN OUT PM_SUBNET Subnet,
IN OUT PM_EXCL Excl,
IN DWORD nAddresses, // how many addresses to extend by
IN BOOL fExtend, // is this an EXTEND? or a CONTRACT?
IN BOOL fEnd // is this operation to be done to END of range or START?
) //EndExport(function)
{
DWORD Error;
PM_EXCL CollidedExcl;
AssertRet(Subnet && Excl, ERROR_INVALID_PARAMETER);
if( Subnet->fSubnet ) { // for real subnets (non-multicast-scopes) do sanity check
if( fExtend ) {
if( fEnd ) {
if( ((Excl->End + nAddresses) & Subnet->Mask) != (Excl->Start & Subnet->Mask) )
return ERROR_INVALID_PARAMETER;
Error = MemSubnetFindCollision(
Subnet,
Excl->End +1,
Excl->End +nAddresses,
NULL,
&CollidedExcl
);
if( ERROR_SUCCESS == Error && NULL != CollidedExcl)
return ERROR_OBJECT_ALREADY_EXISTS;
} else {
if( ((Excl->Start - nAddresses) & Subnet->Mask) != (Excl->End & Subnet->Mask) )
return ERROR_INVALID_PARAMETER;
Error = MemSubnetFindCollision(
Subnet,
Excl->Start - nAddresses,
Excl->Start - 1,
NULL,
&CollidedExcl
);
if( ERROR_SUCCESS == Error && NULL != CollidedExcl)
return ERROR_OBJECT_ALREADY_EXISTS;
}
} // if
} // if
if( !fExtend && nAddresses > Excl->End - Excl->Start )
return ERROR_INVALID_PARAMETER;
if( fExtend )
if( fEnd )
Excl->End += nAddresses;
else
Excl->Start -= nAddresses;
else
if( fEnd )
Excl->End -= nAddresses;
else
Excl->Start += nAddresses;
Error = DeleteRecord( Excl->UniqId );
if ( ERROR_SUCCESS != Error ) {
return Error;
}
Excl->UniqId = INVALID_UNIQ_ID;
return NO_ERROR;
} // MemSubnetExtendOrContractExcl()
//================================================================================
// Multicast Scopes implementation
//================================================================================
//================================================================================
// end of file
//================================================================================