//================================================================================ // 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 #include #include #include #include #include #include #include #include #include #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 //================================================================================