Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

912 lines
29 KiB

  1. //================================================================================
  2. // Copyright (C) 1997 Microsoft Corporation
  3. // Author: RameshV
  4. // Description: implements the basic structures for managing (multicast) scopes
  5. // ThreadSafe: no
  6. // Locks: none
  7. // Please read stdinfo.txt for programming style.
  8. //================================================================================
  9. #include <mm.h>
  10. #include <array.h>
  11. #include <opt.h>
  12. #include <optl.h>
  13. #include <optclass.h>
  14. #include <bitmask.h>
  15. #include <range.h>
  16. #include <reserve.h>
  17. #include <dhcp.h>
  18. #include <winnls.h>
  19. //BeginExport(typedef)
  20. typedef struct _M_SUBNET {
  21. LPVOID ServerPtr; // Ptr to Server object
  22. union {
  23. struct { // for normal subnet.
  24. DWORD Address;
  25. DWORD Mask;
  26. DWORD SuperScopeId; // unused for MCAST scopes
  27. };
  28. struct { // for multicast scope
  29. DWORD MScopeId;
  30. LPWSTR LangTag; // the language tag for multicast scope
  31. BYTE TTL;
  32. };
  33. };
  34. DWORD fSubnet; // TRUE => Subnet, FALSE => MSCOPE
  35. DWORD State;
  36. DWORD Policy;
  37. DATE_TIME ExpiryTime; // Scope Lifetime. Currently used for MCast only.
  38. M_OPTCLASS Options;
  39. ARRAY Ranges;
  40. ARRAY Exclusions;
  41. M_RESERVATIONS Reservations;
  42. ARRAY Servers; // future use, Server-Server protocol
  43. LPWSTR Name;
  44. LPWSTR Description;
  45. } M_SUBNET, *PM_SUBNET, *LPM_SUBNET;
  46. //EndExport(typedef)
  47. // the following are the flags bits used for subnet object.
  48. #define DEFAULT_SCOPE 0x01
  49. #define IS_DEFAULT_SCOPE( _subnet ) ((_subnet)->Flags & DEFAULT_SCOPE == DEFAULT_SCOPE )
  50. #define SET_DEFAULT_SCOPE( _subnet ) ((_subnet)->Flags |= DEFAULT_SCOPE )
  51. #define RESET_DEFAULT_SCOPE( _subnet ) ((_subnet)->Flags &= ~DEFAULT_SCOPE)
  52. //BeginExport(enum)
  53. enum /* Anonymous */ {
  54. AddressPolicyNone = 0,
  55. AddressPolicySequential,
  56. AddressPolicyRoundRobin
  57. };
  58. //EndExport(enum)
  59. //BeginExport(function)
  60. DWORD
  61. MemSubnetInit(
  62. OUT PM_SUBNET *pSubnet,
  63. IN DWORD Address,
  64. IN DWORD Mask,
  65. IN DWORD State,
  66. IN DWORD SuperScopeId,
  67. IN LPWSTR Name,
  68. IN LPWSTR Description
  69. ) //EndExport(function)
  70. {
  71. DWORD Error;
  72. DWORD Size;
  73. PM_SUBNET Subnet;
  74. AssertRet(pSubnet, ERROR_INVALID_PARAMETER);
  75. AssertRet( !(CLASSD_HOST_ADDR(Address)||CLASSE_HOST_ADDR(Address)),
  76. ERROR_INVALID_PARAMETER );
  77. Require((Address&Mask));
  78. *pSubnet = NULL;
  79. Size = ROUND_UP_COUNT(sizeof(*Subnet), ALIGN_WORST);
  80. Size += sizeof(WCHAR) * (Name?(1+wcslen(Name)):0);
  81. Size += sizeof(WCHAR) * (Description?(1+wcslen(Description)):0);
  82. Subnet = MemAlloc(Size);
  83. if( NULL == Subnet) return ERROR_NOT_ENOUGH_MEMORY;
  84. Size = ROUND_UP_COUNT(sizeof(*Subnet), ALIGN_WORST);
  85. Subnet->Name = Subnet->Description = NULL;
  86. if( Name ) {
  87. Subnet->Name = (LPWSTR)(Size + (LPBYTE)Subnet);
  88. wcscpy(Subnet->Name, Name);
  89. Size += sizeof(WCHAR) * ( 1 + wcslen(Name));
  90. }
  91. if( Description ) {
  92. Subnet->Description = (LPWSTR)( Size + (LPBYTE)Subnet );
  93. wcscpy(Subnet->Description, Description);
  94. }
  95. Subnet->ServerPtr = NULL;
  96. Subnet->Address = Address;
  97. Subnet->Mask = Mask;
  98. Subnet->State = State;
  99. Subnet->SuperScopeId = SuperScopeId;
  100. Subnet->fSubnet = TRUE;
  101. Subnet->Policy = AddressPolicyNone;
  102. Error = MemOptClassInit(&Subnet->Options);
  103. if( ERROR_SUCCESS != Error ) { MemFree(Subnet); return Error; }
  104. Error = MemArrayInit(&Subnet->Ranges);
  105. if( ERROR_SUCCESS != Error ) { MemFree(Subnet); return Error; }
  106. Error = MemArrayInit(&Subnet->Exclusions);
  107. if( ERROR_SUCCESS != Error ) { MemFree(Subnet); return Error; }
  108. Error = MemArrayInit(&Subnet->Servers);
  109. if( ERROR_SUCCESS != Error ) { MemFree(Subnet); return Error; }
  110. Error = MemReserveInit(&Subnet->Reservations);
  111. if( ERROR_SUCCESS != Error ) { MemFree(Subnet); return Error; }
  112. *pSubnet = Subnet;
  113. return ERROR_SUCCESS;
  114. }
  115. VOID
  116. GetLangTag(
  117. WCHAR LangTag[]
  118. )
  119. {
  120. WCHAR b1[8], b2[8];
  121. b1[0] = b2[0] = L'\0';
  122. GetLocaleInfoW(
  123. LOCALE_SYSTEM_DEFAULT, LOCALE_SISO639LANGNAME,
  124. b1, sizeof(b1)/sizeof(b1[0])
  125. );
  126. GetLocaleInfoW(
  127. LOCALE_SYSTEM_DEFAULT, LOCALE_SISO3166CTRYNAME,
  128. b2, sizeof(b2)/sizeof(b2[0])
  129. );
  130. if (_wcsicmp(b1, b2))
  131. wsprintf(LangTag, L"%s-%s", b1, b2);
  132. else
  133. wcscpy(LangTag, b1);
  134. }
  135. //BeginExport(function)
  136. DWORD
  137. MemMScopeInit(
  138. OUT PM_SUBNET *pMScope,
  139. IN DWORD MScopeId,
  140. IN DWORD State,
  141. IN DWORD AddressPolicy,
  142. IN BYTE TTL,
  143. IN LPWSTR Name,
  144. IN LPWSTR Description,
  145. IN LPWSTR LangTag,
  146. IN DATE_TIME ExpiryTime
  147. ) //EndExport(function)
  148. {
  149. DWORD Error;
  150. DWORD Size;
  151. PM_SUBNET MScope;
  152. WCHAR DummyLangTag[100];
  153. AssertRet(pMScope, ERROR_INVALID_PARAMETER);
  154. //AssertRet(MScopeId, ERROR_INVALID_PARAMETER);
  155. Require(LangTag);
  156. if( NULL == LangTag ) {
  157. LangTag = DummyLangTag;
  158. GetLangTag(DummyLangTag);
  159. }
  160. *pMScope = NULL;
  161. Size = ROUND_UP_COUNT(sizeof(*MScope), ALIGN_WORST);
  162. Size += sizeof(WCHAR) * (Name?(1+wcslen(Name)):0);
  163. Size += sizeof(WCHAR) * (Description?(1+wcslen(Description)):0);
  164. Size += sizeof(WCHAR) * (1+wcslen(LangTag));
  165. MScope = MemAlloc(Size);
  166. if( NULL == MScope) return ERROR_NOT_ENOUGH_MEMORY;
  167. Size = ROUND_UP_COUNT(sizeof(*MScope), ALIGN_WORST);
  168. MScope->Name = MScope->Description = MScope->LangTag = NULL;
  169. if( Name ) {
  170. MScope->Name = (LPWSTR)(Size + (LPBYTE)MScope);
  171. wcscpy(MScope->Name, Name);
  172. Size += sizeof(WCHAR) * ( 1 + wcslen(Name));
  173. }
  174. if( Description ) {
  175. MScope->Description = (LPWSTR)( Size + (LPBYTE)MScope );
  176. wcscpy(MScope->Description, Description);
  177. Size += sizeof(WCHAR) * ( 1 + wcslen(Description));
  178. }
  179. MScope->LangTag = (LPWSTR)( Size + (LPBYTE)MScope );
  180. wcscpy(MScope->LangTag, LangTag);
  181. MScope->ServerPtr = NULL;
  182. MScope->MScopeId = MScopeId;
  183. MScope->State = State;
  184. MScope->TTL = TTL;
  185. MScope->fSubnet = FALSE;
  186. MScope->Policy = AddressPolicy;
  187. MScope->ExpiryTime = ExpiryTime;
  188. Error = MemOptClassInit(&MScope->Options);
  189. if( ERROR_SUCCESS != Error ) { MemFree(MScope); return Error; }
  190. Error = MemArrayInit(&MScope->Ranges);
  191. if( ERROR_SUCCESS != Error ) { MemFree(MScope); return Error; }
  192. Error = MemArrayInit(&MScope->Exclusions);
  193. if( ERROR_SUCCESS != Error ) { MemFree(MScope); return Error; }
  194. Error = MemArrayInit(&MScope->Servers);
  195. if( ERROR_SUCCESS != Error ) { MemFree(MScope); return Error; }
  196. Error = MemReserveInit(&MScope->Reservations);
  197. if( ERROR_SUCCESS != Error ) { MemFree(MScope); return Error; }
  198. *pMScope = MScope;
  199. return ERROR_SUCCESS;
  200. }
  201. //BeginExport(inline)
  202. DWORD _inline
  203. MemSubnetCleanup(
  204. IN OUT PM_SUBNET Subnet
  205. )
  206. {
  207. DWORD Error;
  208. AssertRet(Subnet, ERROR_INVALID_PARAMETER);
  209. Require(Subnet->Address&Subnet->Mask);
  210. Error = MemOptClassCleanup(&Subnet->Options);
  211. if( ERROR_SUCCESS != Error ) return Error;
  212. Error = MemArrayCleanup(&Subnet->Ranges);
  213. if( ERROR_SUCCESS != Error ) return Error;
  214. Error = MemArrayCleanup(&Subnet->Exclusions);
  215. if( ERROR_SUCCESS != Error ) return Error;
  216. Error = MemArrayCleanup(&Subnet->Servers);
  217. if( ERROR_SUCCESS != Error ) return Error;
  218. Error = MemReserveCleanup(&Subnet->Reservations);
  219. if( ERROR_SUCCESS != Error ) return Error;
  220. MemFree(Subnet);
  221. return ERROR_SUCCESS;
  222. }
  223. //EndExport(inline)
  224. //BeginExport(function)
  225. DWORD // SUCCESS if either of Excl or Range get filled, else FILE_NOT_FOUND
  226. MemSubnetGetAddressInfo(
  227. IN PM_SUBNET Subnet,
  228. IN DWORD Address,
  229. OUT PM_RANGE *Range, // OPTIONAL -- filled if a range could be found -- even if excluded
  230. OUT PM_EXCL *Excl, // OPTIONAL -- filled if an exclusion could be found
  231. OUT PM_RESERVATION *Reservation // OPTIONAL -- filled with a matching reservation, if found
  232. ) //EndExport(function)
  233. {
  234. ARRAY_LOCATION Location;
  235. DWORD Error;
  236. DWORD RetError;
  237. PM_RANGE ThisRange;
  238. PM_EXCL ThisExcl;
  239. AssertRet(Subnet && (Range || Excl || Reservation), ERROR_INVALID_PARAMETER );
  240. if( Subnet->fSubnet && (Address & Subnet->Mask) != Subnet->Address )
  241. return ERROR_FILE_NOT_FOUND; // it is ok for MSCOPE objects, as Address refers to ScopeId
  242. RetError = ERROR_FILE_NOT_FOUND;
  243. if( Range ) {
  244. *Range = NULL;
  245. Error = MemArrayInitLoc(&Subnet->Ranges, &Location);
  246. while( ERROR_FILE_NOT_FOUND != Error ) {
  247. Require(ERROR_SUCCESS == Error);
  248. Error = MemArrayGetElement(&Subnet->Ranges, &Location, (LPVOID *)&ThisRange);
  249. Require(ERROR_SUCCESS == Error && ThisRange);
  250. if( ThisRange->Start <= Address && Address <= ThisRange->End ) {
  251. *Range = ThisRange;
  252. RetError = ERROR_SUCCESS;
  253. break;
  254. }
  255. Error = MemArrayNextLoc(&Subnet->Ranges, &Location);
  256. }
  257. }
  258. if( Excl ) {
  259. *Excl = NULL;
  260. Error = MemArrayInitLoc(&Subnet->Exclusions, &Location);
  261. while( ERROR_FILE_NOT_FOUND != Error ) {
  262. Require(ERROR_SUCCESS == Error);
  263. Error = MemArrayGetElement(&Subnet->Exclusions, &Location, (LPVOID *)&ThisExcl);
  264. Require(ERROR_SUCCESS == Error && ThisExcl);
  265. if( ThisExcl->Start <= Address && Address <= ThisExcl->End ) {
  266. *Excl = ThisExcl;
  267. RetError = ERROR_SUCCESS;
  268. break;
  269. }
  270. Error = MemArrayNextLoc(&Subnet->Exclusions, &Location);
  271. }
  272. }
  273. if( Reservation ) {
  274. *Reservation = NULL;
  275. Error = MemReserveFindByAddress(&Subnet->Reservations, Address, Reservation);
  276. if( ERROR_SUCCESS == Error ) RetError = ERROR_SUCCESS;
  277. }
  278. return RetError;
  279. }
  280. //BeginExport(function)
  281. DWORD // ERROR_SUCCESS on finding a collition, else ERROR_FILE_NOT_FOUND
  282. MemSubnetFindCollision(
  283. IN OUT PM_SUBNET Subnet,
  284. IN DWORD Start,
  285. IN DWORD End,
  286. OUT PM_RANGE *Range, // OPTIONAL
  287. OUT PM_EXCL *Excl // OPTIONAL
  288. ) //EndExport(function)
  289. {
  290. ARRAY_LOCATION Location;
  291. DWORD Error;
  292. DWORD RetError;
  293. DWORD Cond;
  294. PM_RANGE ThisRange;
  295. PM_EXCL ThisExcl;
  296. Require(Subnet && (Range || Excl));
  297. if( Subnet->fSubnet ) { // checks ommitted for MCAST scopes.
  298. if( (Start & Subnet->Mask) != (End & Subnet->Mask) )
  299. return ERROR_INVALID_PARAMETER;
  300. if( (Start & Subnet->Mask) != (Subnet->Address & Subnet->Mask) )
  301. return ERROR_INVALID_PARAMETER;
  302. }
  303. RetError = ERROR_FILE_NOT_FOUND;
  304. if(Range) {
  305. *Range = NULL;
  306. Error = MemArrayInitLoc(&Subnet->Ranges, &Location);
  307. while( ERROR_FILE_NOT_FOUND != Error ) {
  308. Require(ERROR_SUCCESS == Error);
  309. Error = MemArrayGetElement(&Subnet->Ranges, &Location, (LPVOID *)&ThisRange);
  310. Require(ERROR_SUCCESS == Error && ThisRange);
  311. Cond = MemRangeCompare(Start,End, ThisRange->Start, ThisRange->End);
  312. if( Cond != X_LESSTHAN_Y && Cond != Y_LESSTHAN_X ) {
  313. // Collision has occured
  314. *Range = ThisRange;
  315. RetError = ERROR_SUCCESS;
  316. break;
  317. }
  318. Error = MemArrayNextLoc(&Subnet->Ranges, &Location);
  319. }
  320. }
  321. if( Excl ) {
  322. *Excl = NULL;
  323. Error = MemArrayInitLoc(&Subnet->Exclusions, &Location);
  324. while( ERROR_FILE_NOT_FOUND != Error ) {
  325. Require(ERROR_SUCCESS == Error);
  326. Error = MemArrayGetElement(&Subnet->Exclusions, &Location, (LPVOID *)&ThisExcl);
  327. Require(ERROR_SUCCESS == Error && ThisExcl);
  328. Cond = MemRangeCompare(Start,End, ThisExcl->Start, ThisExcl->End);
  329. if( Cond != X_LESSTHAN_Y && Cond != Y_LESSTHAN_X ) {
  330. *Excl = ThisExcl;
  331. RetError = ERROR_SUCCESS;
  332. break;
  333. }
  334. Error = MemArrayNextLoc(&Subnet->Exclusions, &Location);
  335. }
  336. }
  337. return RetError;
  338. }
  339. //BeginExport(function)
  340. DWORD // ERROR_OBJECT_ALREADY_EXISTS on collision
  341. MemSubnetAddRange( // check if the range is valid, and only then add it
  342. IN OUT PM_SUBNET Subnet,
  343. IN DWORD Start,
  344. IN DWORD End,
  345. IN DWORD State,
  346. IN ULONG BootpAllocated,
  347. IN ULONG MaxBootpAllowed,
  348. OUT PM_RANGE *OverlappingRange
  349. ) //EndExport(function)
  350. {
  351. DWORD Error;
  352. DWORD LocalError;
  353. PM_RANGE NewRange;
  354. AssertRet(Subnet && OverlappingRange, ERROR_INVALID_PARAMETER);
  355. if( Subnet->fSubnet ) {
  356. if( (Subnet->Address & Subnet->Mask) != (Start & Subnet->Mask) ||
  357. (Start & Subnet->Mask) != (End & Subnet->Mask) )
  358. return ERROR_INVALID_PARAMETER;
  359. } else {
  360. if (!CLASSD_HOST_ADDR(Start) || !CLASSD_HOST_ADDR(End)) {
  361. return ERROR_INVALID_PARAMETER;
  362. }
  363. }
  364. if( Start > End ) return ERROR_INVALID_PARAMETER;
  365. *OverlappingRange = NULL;
  366. Error = MemSubnetFindCollision(
  367. Subnet,
  368. Start,
  369. End,
  370. OverlappingRange,
  371. NULL
  372. );
  373. if(ERROR_FILE_NOT_FOUND != Error ) { // collision with a range?
  374. Require(ERROR_SUCCESS == Error);
  375. return ERROR_OBJECT_ALREADY_EXISTS;
  376. }
  377. NewRange = MemAlloc(sizeof(*NewRange));
  378. if( NULL == NewRange ) return ERROR_NOT_ENOUGH_MEMORY;
  379. Error = MemRangeInit(
  380. NewRange, Start, End, Subnet->fSubnet ? Subnet->Mask : 0, State,
  381. BootpAllocated, MaxBootpAllowed
  382. );
  383. if( ERROR_SUCCESS != Error ) {
  384. MemFree(NewRange);
  385. return Error;
  386. }
  387. Error = MemArrayAddElement(
  388. &Subnet->Ranges,
  389. NewRange
  390. );
  391. if( ERROR_SUCCESS != Error ) {
  392. LocalError = MemRangeCleanup(NewRange);
  393. Require(LocalError == ERROR_SUCCESS);
  394. MemFree(NewRange);
  395. }
  396. return Error;
  397. }
  398. //BeginExport(function)
  399. DWORD
  400. MemSubnetAddRangeExpandOrContract(
  401. IN PM_SUBNET Subnet,
  402. IN DWORD StartAddress,
  403. IN DWORD EndAddress,
  404. OUT DWORD *OldStartAddress,
  405. OUT DWORD *OldEndAddress
  406. ) //EndExport(function)
  407. {
  408. DWORD Error;
  409. DWORD LocalError;
  410. DWORD Cond;
  411. DWORD nAddresses;
  412. BOOL fExtend;
  413. PM_RANGE OldRange;
  414. PM_RANGE ThisRange;
  415. PARRAY Ranges;
  416. ARRAY_LOCATION Loc;
  417. Ranges = &Subnet->Ranges;
  418. *OldStartAddress = *OldEndAddress = 0;
  419. OldRange = NULL;
  420. Error = MemArrayInitLoc(Ranges, &Loc);
  421. while( ERROR_FILE_NOT_FOUND != Error ) {
  422. Require(ERROR_SUCCESS == Error);
  423. Error = MemArrayGetElement(Ranges, &Loc, (LPVOID *)&ThisRange);
  424. Require(ERROR_SUCCESS == Error && ThisRange);
  425. Cond = MemRangeCompare(StartAddress, EndAddress, ThisRange->Start, ThisRange->End);
  426. if( Cond != X_LESSTHAN_Y && Cond != Y_LESSTHAN_X ) {
  427. if( OldRange ) return ERROR_OBJECT_ALREADY_EXISTS;
  428. if( X_IN_Y != Cond && Y_IN_X != Cond )
  429. return ERROR_OBJECT_ALREADY_EXISTS;
  430. OldRange = ThisRange;
  431. }
  432. Error = MemArrayNextLoc(Ranges, &Loc);
  433. }
  434. if( NULL == OldRange ) return ERROR_FILE_NOT_FOUND;
  435. *OldStartAddress = OldRange->Start;
  436. *OldEndAddress = OldRange->End;
  437. if( OldRange->Start < StartAddress ) {
  438. fExtend = FALSE;
  439. nAddresses = StartAddress - OldRange->Start;
  440. } else {
  441. fExtend = TRUE;
  442. nAddresses = OldRange->Start - StartAddress;
  443. }
  444. Error = ERROR_SUCCESS;
  445. if( nAddresses ) Error = MemRangeExtendOrContract(
  446. OldRange,
  447. nAddresses,
  448. fExtend,
  449. FALSE
  450. );
  451. if( ERROR_SUCCESS != Error ) return Error;
  452. if( OldRange->End < EndAddress ) {
  453. fExtend = TRUE;
  454. nAddresses = EndAddress - OldRange->End;
  455. } else {
  456. fExtend = FALSE;
  457. nAddresses = OldRange->End - EndAddress;
  458. }
  459. if( nAddresses ) Error = MemRangeExtendOrContract(
  460. OldRange,
  461. nAddresses,
  462. fExtend,
  463. TRUE
  464. );
  465. return Error;
  466. }
  467. //BeginExport(function)
  468. DWORD
  469. MemSubnetAddExcl(
  470. IN OUT PM_SUBNET Subnet,
  471. IN DWORD Start,
  472. IN DWORD End,
  473. OUT PM_EXCL *OverlappingExcl
  474. ) //EndExport(function)
  475. {
  476. DWORD Error;
  477. DWORD LocalError;
  478. PM_EXCL NewExcl;
  479. AssertRet(Subnet && OverlappingExcl, ERROR_INVALID_PARAMETER);
  480. if( Subnet->fSubnet ) {
  481. if( (Subnet->Address & Subnet->Mask) != (Start & Subnet->Mask) ||
  482. (Start & Subnet->Mask) != (End & Subnet->Mask) )
  483. return ERROR_INVALID_PARAMETER;
  484. }
  485. if( Start > End ) return ERROR_INVALID_PARAMETER;
  486. *OverlappingExcl = NULL;
  487. Error = MemSubnetFindCollision(
  488. Subnet,
  489. Start,
  490. End,
  491. NULL,
  492. OverlappingExcl
  493. );
  494. if(ERROR_FILE_NOT_FOUND != Error ) { // collision with a range?
  495. Require(ERROR_SUCCESS == Error);
  496. return ERROR_OBJECT_ALREADY_EXISTS;
  497. }
  498. NewExcl = MemAlloc(sizeof(*NewExcl));
  499. if( NULL == NewExcl ) return ERROR_NOT_ENOUGH_MEMORY;
  500. NewExcl->Start = Start;
  501. NewExcl->End = End;
  502. Error = MemArrayAddElement(
  503. &Subnet->Exclusions,
  504. NewExcl
  505. );
  506. if( ERROR_SUCCESS != Error ) {
  507. MemFree(NewExcl);
  508. }
  509. return Error;
  510. }
  511. //BeginExport(function)
  512. DWORD
  513. MemSubnetDelRange(
  514. IN OUT PM_SUBNET Subnet,
  515. IN DWORD Start
  516. ) //EndExport(function)
  517. {
  518. DWORD Error;
  519. PM_RANGE ThisRange;
  520. ARRAY_LOCATION Location;
  521. Error = MemArrayInitLoc(&Subnet->Ranges, &Location);
  522. while( ERROR_FILE_NOT_FOUND != Error ) {
  523. Require(ERROR_SUCCESS == Error);
  524. Error = MemArrayGetElement(&Subnet->Ranges, &Location, (LPVOID *)&ThisRange);
  525. Require(ERROR_SUCCESS == Error && ThisRange);
  526. if( ThisRange->Start == Start ) { // Collision has occured
  527. Error = MemRangeCleanup(ThisRange);
  528. Require(ERROR_SUCCESS == Error);
  529. MemFree(ThisRange);
  530. Error = MemArrayDelElement(&Subnet->Ranges, &Location, (LPVOID *)&ThisRange);
  531. return ERROR_SUCCESS;
  532. }
  533. Error = MemArrayNextLoc(&Subnet->Ranges, &Location);
  534. }
  535. return ERROR_FILE_NOT_FOUND;
  536. }
  537. //BeginExport(function)
  538. DWORD
  539. MemSubnetDelExcl(
  540. IN OUT PM_SUBNET Subnet,
  541. IN DWORD Start
  542. ) //EndExport(function)
  543. {
  544. DWORD Error;
  545. PM_EXCL ThisExcl;
  546. ARRAY_LOCATION Location;
  547. Error = MemArrayInitLoc(&Subnet->Exclusions, &Location);
  548. while( ERROR_FILE_NOT_FOUND != Error ) {
  549. Require(ERROR_SUCCESS == Error);
  550. Error = MemArrayGetElement(&Subnet->Exclusions, &Location, (LPVOID *)&ThisExcl);
  551. Require(ERROR_SUCCESS == Error && ThisExcl);
  552. if( ThisExcl->Start == Start ) {
  553. Error = MemArrayDelElement(&Subnet->Exclusions, &Location, (LPVOID *)&ThisExcl);
  554. MemFree(ThisExcl);
  555. return ERROR_SUCCESS;
  556. }
  557. Error = MemArrayNextLoc(&Subnet->Exclusions, &Location);
  558. }
  559. return ERROR_FILE_NOT_FOUND;
  560. }
  561. //BeginExport(function)
  562. DWORD
  563. MemSubnetExtendOrContractRange(
  564. IN OUT PM_SUBNET Subnet,
  565. IN OUT PM_RANGE Range,
  566. IN DWORD nAddresses, // how many addresses to extend by
  567. IN BOOL fExtend, // is this an EXTEND? or a CONTRACT?
  568. IN BOOL fEnd // is this operation to be done to END of range or START?
  569. ) //EndExport(function)
  570. {
  571. DWORD Error;
  572. PM_RANGE CollidedRange;
  573. AssertRet(Subnet && Range, ERROR_INVALID_PARAMETER);
  574. if( Subnet->fSubnet ) { // for real subnets (non-multicast-scopes) do sanity check
  575. if( fExtend ) {
  576. if( fEnd ) {
  577. if( ((Range->End + nAddresses) & Subnet->Mask) != (Range->Start & Subnet->Mask) )
  578. return ERROR_INVALID_PARAMETER;
  579. Error = MemSubnetFindCollision(
  580. Subnet,
  581. Range->End +1,
  582. Range->End +nAddresses,
  583. &CollidedRange,
  584. NULL
  585. );
  586. if( ERROR_SUCCESS == Error && NULL != CollidedRange)
  587. return ERROR_OBJECT_ALREADY_EXISTS;
  588. } else {
  589. if( ((Range->Start - nAddresses) & Subnet->Mask) != (Range->End & Subnet->Mask) )
  590. return ERROR_INVALID_PARAMETER;
  591. Error = MemSubnetFindCollision(
  592. Subnet,
  593. Range->Start - nAddresses,
  594. Range->Start - 1,
  595. &CollidedRange,
  596. NULL
  597. );
  598. if( ERROR_SUCCESS == Error && NULL != CollidedRange)
  599. return ERROR_OBJECT_ALREADY_EXISTS;
  600. }
  601. }
  602. }
  603. if( !fExtend && nAddresses > Range->End - Range->Start )
  604. return ERROR_INVALID_PARAMETER;
  605. Error = MemRangeExtendOrContract(
  606. Range,
  607. nAddresses,
  608. fExtend,
  609. fEnd
  610. );
  611. return Error;
  612. }
  613. //BeginExport(function)
  614. DWORD
  615. MemSubnetExtendOrContractExcl(
  616. IN OUT PM_SUBNET Subnet,
  617. IN OUT PM_EXCL Excl,
  618. IN DWORD nAddresses, // how many addresses to extend by
  619. IN BOOL fExtend, // is this an EXTEND? or a CONTRACT?
  620. IN BOOL fEnd // is this operation to be done to END of range or START?
  621. ) //EndExport(function)
  622. {
  623. DWORD Error;
  624. PM_EXCL CollidedExcl;
  625. AssertRet(Subnet && Excl, ERROR_INVALID_PARAMETER);
  626. if( Subnet->fSubnet ) { // for real subnets (non-multicast-scopes) do sanity check
  627. if( fExtend ) {
  628. if( fEnd ) {
  629. if( ((Excl->End + nAddresses) & Subnet->Mask) != (Excl->Start & Subnet->Mask) )
  630. return ERROR_INVALID_PARAMETER;
  631. Error = MemSubnetFindCollision(
  632. Subnet,
  633. Excl->End +1,
  634. Excl->End +nAddresses,
  635. NULL,
  636. &CollidedExcl
  637. );
  638. if( ERROR_SUCCESS == Error && NULL != CollidedExcl)
  639. return ERROR_OBJECT_ALREADY_EXISTS;
  640. } else {
  641. if( ((Excl->Start - nAddresses) & Subnet->Mask) != (Excl->End & Subnet->Mask) )
  642. return ERROR_INVALID_PARAMETER;
  643. Error = MemSubnetFindCollision(
  644. Subnet,
  645. Excl->Start - nAddresses,
  646. Excl->Start - 1,
  647. NULL,
  648. &CollidedExcl
  649. );
  650. if( ERROR_SUCCESS == Error && NULL != CollidedExcl)
  651. return ERROR_OBJECT_ALREADY_EXISTS;
  652. }
  653. }
  654. }
  655. if( !fExtend && nAddresses > Excl->End - Excl->Start )
  656. return ERROR_INVALID_PARAMETER;
  657. if( fExtend )
  658. if( fEnd )
  659. Excl->End += nAddresses;
  660. else
  661. Excl->Start -= nAddresses;
  662. else
  663. if( fEnd )
  664. Excl->End -= nAddresses;
  665. else
  666. Excl->Start += nAddresses;
  667. return NO_ERROR;
  668. }
  669. //================================================================================
  670. // Multicast Scopes implementation
  671. //================================================================================
  672. //BeginExport(typedef)
  673. typedef M_SUBNET M_MSCOPE; // same structure for Multicast Scopes and Subnets
  674. typedef PM_SUBNET PM_MSCOPE; // still, use the correct functions for MScope
  675. typedef LPM_SUBNET LPM_MSCOPE;
  676. //EndExport(typedef)
  677. //BeginExport(inline)
  678. DWORD _inline
  679. MemMScopeCleanup(
  680. IN PM_MSCOPE MScope
  681. ) {
  682. return MemSubnetCleanup(MScope);
  683. }
  684. //EndExport(inline)
  685. //BeginExport(decl)
  686. #define MemMScopeGetAddressInfo MemSubnetGetAddressInfo
  687. #define MemMScopeFindCollision MemSubnetFindCollision
  688. #define MemMScopeAddExcl MemSubnetAddExcl
  689. #define MemMScopeDelRange MemSubnetDelRange
  690. #define MemMScopeDelExcl MemSubnetDelExcl
  691. #define MemMScopeExtendOrContractRange MemSubnetExtendOrContractRange
  692. #define MemMScopeExtendOrContractExcl MemSubnetExtendOrContractExcl
  693. DWORD
  694. MemMScopeGetAddressInfo(
  695. IN PM_MSCOPE MScope,
  696. IN DWORD MCastAddress,
  697. OUT PM_RANGE *Range, // OPTIONAL -- filled if a range could be found -- even if excluded
  698. OUT PM_EXCL *Excl, // OPTIONAL -- filled if an exclusion could be found
  699. OUT PM_RESERVATION *Reservation // OPTIONAL -- filled with a matching reservation, if found
  700. );
  701. DWORD // ERROR_SUCCESS on finding a collition, else ERROR_FILE_NOT_FOUND
  702. MemMScopeFindCollision(
  703. IN OUT PM_MSCOPE Subnet,
  704. IN DWORD MCastStart,
  705. IN DWORD MCastEnd,
  706. OUT PM_RANGE *Range, // OPTIONAL
  707. OUT PM_EXCL *Excl // OPTIONAL
  708. );
  709. //EndExport(decl)
  710. //BeginExport(inline)
  711. DWORD _inline // ERROR_OBJECT_ALREADY_EXISTS on collision
  712. MemMScopeAddRange( // check if the range is valid, and only then add it
  713. IN OUT PM_MSCOPE Subnet,
  714. IN DWORD MCastStart,
  715. IN DWORD MCastEnd,
  716. IN DWORD State,
  717. OUT PM_RANGE *OverlappingRange
  718. )
  719. {
  720. return MemSubnetAddRange(Subnet,MCastStart, MCastEnd, State, 0, 0, OverlappingRange);
  721. }
  722. DWORD
  723. MemMScopeAddExcl(
  724. IN OUT PM_MSCOPE Subnet,
  725. IN DWORD MCastStart,
  726. IN DWORD MCastEnd,
  727. OUT PM_EXCL *OverlappingExcl
  728. );
  729. DWORD
  730. MemMScopeDelRange(
  731. IN OUT PM_MSCOPE Subnet,
  732. IN DWORD MCastStart
  733. );
  734. DWORD
  735. MemMScopeDelExcl(
  736. IN OUT PM_MSCOPE Subnet,
  737. IN DWORD MCastStart
  738. );
  739. DWORD
  740. MemMScopeExtendOrContractRange(
  741. IN OUT PM_MSCOPE Subnet,
  742. IN OUT PM_RANGE Range,
  743. IN DWORD nAddresses, // how many addresses to extend by
  744. IN BOOL fExtend, // is this an EXTEND? or a CONTRACT?
  745. IN BOOL fEnd // is this operation to be done to END of range or START?
  746. );
  747. DWORD
  748. MemMScopeExtendOrContractExcl(
  749. IN OUT PM_MSCOPE Subnet,
  750. IN OUT PM_EXCL Excl,
  751. IN DWORD nAddresses, // how many addresses to extend by
  752. IN BOOL fExtend, // is this an EXTEND? or a CONTRACT?
  753. IN BOOL fEnd // is this operation to be done to END of range or START?
  754. );
  755. //EndExport(decl)
  756. //================================================================================
  757. // end of file
  758. //================================================================================