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.

456 lines
14 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 <winbase.h>
  11. #include <array.h>
  12. #include <opt.h>
  13. #include <optl.h>
  14. #include <optclass.h>
  15. #include <bitmask.h>
  16. #include <range.h>
  17. #include <reserve.h>
  18. #include <subnet.h>
  19. #include <optdefl.h>
  20. #include <classdefl.h>
  21. #include <oclassdl.h>
  22. #include <sscope.h>
  23. #include <server.h>
  24. //BeginExport(constants)
  25. #define IS_SWITCHED(X) (((X) & 0x00000002)?TRUE:FALSE)
  26. #define IS_DISABLED(X) (((X) & 0x00000001)?TRUE:FALSE)
  27. #define SWITCHED(X) ((X) |= 0x00000002 )
  28. #define DISABLED(X) ((X) |= 0x00000001 )
  29. //EndExport(constants)
  30. //================================================================================
  31. // subnet only address api's
  32. //================================================================================
  33. BOOL
  34. MemSubnetGetThisAddress(
  35. IN PM_SUBNET Subnet,
  36. IN DWORD Address,
  37. IN BOOL fAcquire, // if available, also acquire?
  38. IN BOOL fBootp
  39. )
  40. {
  41. DWORD Error;
  42. DWORD Offset;
  43. DWORD OldState;
  44. PM_RANGE Range;
  45. Error = MemSubnetGetAddressInfo(
  46. Subnet,
  47. Address,
  48. &Range,
  49. NULL,
  50. NULL
  51. );
  52. if( ERROR_SUCCESS != Error ) return FALSE;
  53. Require(Range);
  54. if( fBootp ) {
  55. if( 0 == (Range->State & MM_FLAG_ALLOW_BOOTP))
  56. return FALSE;
  57. if( fAcquire &&
  58. Range->BootpAllocated >= Range->MaxBootpAllowed ) {
  59. return FALSE;
  60. }
  61. } else {
  62. if( 0 == (Range->State & MM_FLAG_ALLOW_DHCP) )
  63. return FALSE;
  64. }
  65. Offset = Address - Range->Start;
  66. if( !fAcquire ) return MemBitIsSet(Range->BitMask, Offset);
  67. Error = MemBitSetOrClear(
  68. Range->BitMask,
  69. Offset,
  70. TRUE /* Acquire */,
  71. &OldState
  72. );
  73. if( ERROR_SUCCESS != Error ) { Require(FALSE); return FALSE; }
  74. if( FALSE == OldState ) {
  75. InterlockedIncrement(&Range->DirtyOps);
  76. if( fBootp ) InterlockedIncrement( &Range->BootpAllocated );
  77. }
  78. return !OldState;
  79. }
  80. BOOL
  81. MemSubnetGetAnAddress(
  82. IN PM_SUBNET Subnet,
  83. OUT LPDWORD AltAddress,
  84. IN DWORD fAcquire,
  85. IN BOOL fBootp
  86. ) {
  87. DWORD Error;
  88. DWORD Offset;
  89. DWORD Policy;
  90. ARRAY_LOCATION Loc;
  91. PM_RANGE Range;
  92. if( IS_DISABLED(Subnet->State)) return FALSE;
  93. Policy = Subnet->Policy;
  94. if( AddressPolicyNone == Policy )
  95. Policy = ((PM_SERVER)(Subnet->ServerPtr))->Policy;
  96. if( AddressPolicyRoundRobin == Policy ) {
  97. Error = MemArrayRotateCyclical(&Subnet->Ranges);
  98. Require(ERROR_SUCCESS == Error);
  99. }
  100. for ( Error = MemArrayInitLoc(&Subnet->Ranges, &Loc);
  101. ERROR_FILE_NOT_FOUND != Error ;
  102. Error = MemArrayNextLoc(&Subnet->Ranges, &Loc) ) {
  103. Require(ERROR_SUCCESS == Error);
  104. Error = MemArrayGetElement(&Subnet->Ranges, &Loc, (LPVOID *)&Range);
  105. Require(ERROR_SUCCESS == Error && Range);
  106. if( fBootp ) {
  107. if( 0 == (Range->State & MM_FLAG_ALLOW_BOOTP) ) {
  108. continue;
  109. }
  110. if( fAcquire &&
  111. Range->BootpAllocated >= Range->MaxBootpAllowed ) {
  112. continue;
  113. }
  114. } else {
  115. if( 0 == (Range->State & MM_FLAG_ALLOW_DHCP ) ) {
  116. continue;
  117. }
  118. }
  119. Error = MemBitGetSomeClearedBit(
  120. Range->BitMask,
  121. &Offset,
  122. fAcquire,
  123. Range->Start,
  124. &Subnet->Exclusions
  125. );
  126. if( ERROR_SUCCESS == Error ) {
  127. *AltAddress = Range->Start + Offset;
  128. InterlockedIncrement(&Range->DirtyOps);
  129. if( fBootp && fAcquire ) {
  130. InterlockedIncrement(&Range->BootpAllocated);
  131. }
  132. return TRUE;
  133. }
  134. }
  135. return FALSE;
  136. }
  137. //================================================================================
  138. // per-server scans
  139. //================================================================================
  140. BOOL
  141. MemServerGetAddress( // acquire address or check for availability
  142. IN OUT PM_SERVER Server,
  143. IN PM_SUBNET Subnet, // search all subnets in superscope with this, except for this subnet alone
  144. IN BOOL fAcquire, // is this just a lookup or a full blown request?
  145. IN BOOL fBootp, // is this a DHCP address or BOOTP address?
  146. OUT DWORD *AltAddress, // the address that looks available
  147. OUT PM_SUBNET *AltSubnet // got it from this subnet
  148. ) {
  149. DWORD Error;
  150. DWORD SScopeId;
  151. DWORD Size;
  152. DWORD Policy;
  153. BOOL Obtained;
  154. PM_SUBNET NextSubnet;
  155. PM_SSCOPE SScope;
  156. AssertRet(Server && Subnet && AltAddress && AltSubnet, ERROR_INVALID_PARAMETER );
  157. AssertRet(NULL == AltAddress || NULL != AltSubnet, ERROR_INVALID_PARAMETER);
  158. AssertRet(Subnet->fSubnet, FALSE );
  159. SScopeId = Subnet->SuperScopeId;
  160. if( 0 == SScopeId ) {
  161. if( AltSubnet ) *AltSubnet = Subnet;
  162. return MemSubnetGetAnAddress(Subnet,AltAddress, fAcquire, fBootp);
  163. }
  164. Error = MemServerFindSScope(Server, SScopeId, NULL, &SScope);
  165. if( ERROR_FILE_NOT_FOUND == Error ) { // the superscope quietly died ?
  166. Subnet->SuperScopeId = 0; // no superscope at all
  167. if( AltSubnet ) *AltSubnet = Subnet;
  168. return MemSubnetGetAnAddress(Subnet, AltAddress, fAcquire, fBootp);
  169. }
  170. Require(ERROR_SUCCESS == Error);
  171. Policy = SScope->Policy;
  172. if( AddressPolicyNone == Policy )
  173. Policy = Server->Policy;
  174. if( AddressPolicyRoundRobin != Policy )
  175. Error = MemArrayInitLoc(&Server->Subnets, &Server->Loc);
  176. else Error = MemArrayNextLoc(&Server->Subnets, &Server->Loc);
  177. Size = MemArraySize(&Server->Subnets);
  178. while( Size -- ) {
  179. if(ERROR_FILE_NOT_FOUND == Error) { // wraparound
  180. Error = MemArrayInitLoc(&Server->Subnets, &Server->Loc);
  181. }
  182. Require(ERROR_SUCCESS == Error);
  183. Error = MemArrayGetElement(&Server->Subnets, &Server->Loc, &NextSubnet);
  184. Require(ERROR_SUCCESS == Error && NextSubnet);
  185. if( NextSubnet->SuperScopeId == SScopeId ) {
  186. Obtained = MemSubnetGetAnAddress(NextSubnet,AltAddress,fAcquire, fBootp);
  187. if( Obtained ) {
  188. *AltSubnet = NextSubnet;
  189. return TRUE;
  190. }
  191. }
  192. Error = MemArrayNextLoc(&Server->Subnets, &Server->Loc);
  193. }
  194. return FALSE;
  195. }
  196. //BeginExport(function)
  197. BOOL
  198. MemSubnetRequestAddress(
  199. IN OUT PM_SUBNET Subnet, // the subnet to start the search in
  200. IN DWORD Address, // init. addr: 0 => search in SuperScope, SubnetAddr = try subnet first
  201. IN BOOL fAcquire, // also acquire the address? or just test for availability?
  202. IN BOOL fBootp, // acquire BOOTP address?
  203. OUT DWORD *RetAddress, // OPTIONAL if Address is not 0 or SubnetAddr -- address obtained
  204. OUT PM_SUBNET *RetSubnet // OPTIONAL if Address is not 0 - which subnet is the address from
  205. ) //EndExport(function)
  206. {
  207. BOOL Obtained;
  208. AssertRet( Subnet , ERROR_INVALID_PARAMETER);
  209. if( 0 == Address ) AssertRet(RetAddress && RetSubnet, ERROR_INVALID_PARAMETER);
  210. if( Subnet->fSubnet && Subnet->Address == Address ) AssertRet(RetAddress, ERROR_INVALID_PARAMETER);
  211. if( (!Subnet->fSubnet || Subnet->Address != Address ) && 0 != Address ) {
  212. Obtained = MemSubnetGetThisAddress( // for the specific address requested
  213. Subnet,
  214. Address,
  215. fAcquire,
  216. fBootp
  217. );
  218. if( Obtained ) {
  219. if( RetAddress ) *RetAddress = Address;
  220. if( RetSubnet ) *RetSubnet = Subnet;
  221. return TRUE;
  222. }
  223. }
  224. if( !RetAddress ) return FALSE;
  225. if (0) {
  226. if( 0 == Address && Subnet->fSubnet ) Obtained = FALSE; // this case, dont try subnet first.. go thru sscope list instead
  227. else
  228. Obtained = MemSubnetGetAnAddress( // try for some address in this subnet?
  229. Subnet,
  230. RetAddress,
  231. fAcquire,
  232. fBootp
  233. );
  234. }
  235. Obtained = MemSubnetGetAnAddress( // try for some address in this subnet?
  236. Subnet,
  237. RetAddress,
  238. fAcquire,
  239. fBootp
  240. );
  241. if( Obtained && RetSubnet ) *RetSubnet = Subnet;
  242. if( Obtained ) return TRUE;
  243. // if the address was requested from a particular subnet OR
  244. // multicast address requested then return FALSE now.
  245. if( !Subnet->fSubnet || Subnet->Address == Address ) return FALSE;
  246. return MemServerGetAddress(
  247. Subnet->ServerPtr,
  248. Subnet,
  249. fAcquire,
  250. fBootp,
  251. RetAddress,
  252. RetSubnet
  253. );
  254. }
  255. DWORD _inline
  256. MemSubnetReleaseAddress(
  257. IN OUT PM_SUBNET Subnet,
  258. IN DWORD Address,
  259. IN BOOL fBootp
  260. );
  261. //BeginExport(function)
  262. DWORD
  263. MemServerReleaseAddress(
  264. IN OUT PM_SERVER Server,
  265. IN DWORD Address,
  266. IN BOOL fBootp
  267. ) //EndExport(function)
  268. {
  269. DWORD Error;
  270. PM_SUBNET Subnet;
  271. AssertRet(Server, ERROR_INVALID_PARAMETER);
  272. Error = MemServerGetAddressInfo(
  273. Server,
  274. Address,
  275. &Subnet,
  276. NULL,
  277. NULL,
  278. NULL
  279. );
  280. if( ERROR_SUCCESS != Error ) return Error;
  281. Require(Subnet);
  282. if( Subnet->fSubnet ) {
  283. Require((Subnet->Mask & Address) == Subnet->Address);
  284. }
  285. return MemSubnetReleaseAddress(Subnet, Address, fBootp);
  286. }
  287. //BeginExport(_inline)
  288. DWORD _inline
  289. MemSubnetReleaseAddress(
  290. IN OUT PM_SUBNET Subnet,
  291. IN DWORD Address,
  292. IN BOOL fBootp
  293. )
  294. {
  295. DWORD Error;
  296. DWORD OldState;
  297. PM_RANGE Range;
  298. PM_EXCL Excl;
  299. PM_RESERVATION Reservation;
  300. AssertRet(Subnet, ERROR_INVALID_PARAMETER);
  301. if( Subnet->fSubnet && Subnet->Address != (Address & Subnet->Mask ) )
  302. return MemServerReleaseAddress(
  303. Subnet->ServerPtr,
  304. Address,
  305. fBootp
  306. );
  307. Error = MemSubnetGetAddressInfo(
  308. Subnet,
  309. Address,
  310. &Range,
  311. NULL,
  312. &Reservation
  313. );
  314. if( ERROR_SUCCESS != Error ) return Error;
  315. Require(Range);
  316. if( NULL != Reservation ) {
  317. Require(FALSE);
  318. return ERROR_INVALID_PARAMETER;
  319. }
  320. if( 0 == (Range->State & (fBootp? MM_FLAG_ALLOW_BOOTP: MM_FLAG_ALLOW_DHCP))) {
  321. return ERROR_INVALID_PARAMETER;
  322. }
  323. Error = MemBitSetOrClear(
  324. Range->BitMask,
  325. Address - Range->Start,
  326. FALSE /* Release */,
  327. &OldState
  328. );
  329. if( ERROR_SUCCESS != Error ) return Error;
  330. if( OldState == FALSE ) return ERROR_FILE_NOT_FOUND;
  331. InterlockedIncrement(&Range->DirtyOps);
  332. if( fBootp && 0 != Range->BootpAllocated ) {
  333. InterlockedDecrement( &Range->BootpAllocated );
  334. }
  335. return ERROR_SUCCESS;
  336. }
  337. //EndExport(inline)
  338. //BeginExport(function)
  339. BOOL // TRUE ==> allowed, FALSE ==> not allowed
  340. MemSubnetCheckBootpDhcp(
  341. IN PM_SUBNET Subnet,
  342. IN BOOL fBootp,
  343. IN BOOL fCheckSuperScope
  344. ) //EndExport(function)
  345. {
  346. ARRAY_LOCATION Loc;
  347. ULONG Error;
  348. PM_RANGE Range;
  349. PM_SUBNET ThisSubnet;
  350. PARRAY Array;
  351. if( Subnet->fSubnet && !IS_DISABLED( Subnet->State ) ) {
  352. for( Error = MemArrayInitLoc( &Subnet->Ranges, &Loc );
  353. ERROR_SUCCESS == Error ;
  354. Error = MemArrayNextLoc( &Subnet->Ranges, &Loc ) ) {
  355. Error = MemArrayGetElement( &Subnet->Ranges, &Loc , &Range );
  356. Require( ERROR_SUCCESS == Error );
  357. if( 0 == (Range->State & (fBootp? MM_FLAG_ALLOW_BOOTP : MM_FLAG_ALLOW_DHCP) ) ) {
  358. continue;
  359. }
  360. return TRUE;
  361. }
  362. }
  363. if( FALSE == fCheckSuperScope || 0 == Subnet->SuperScopeId ) {
  364. return FALSE;
  365. }
  366. Array = &((PM_SERVER) (Subnet->ServerPtr))->Subnets;
  367. for( Error = MemArrayInitLoc( Array, &Loc );
  368. ERROR_SUCCESS == Error ;
  369. Error = MemArrayNextLoc( Array, &Loc ) ) {
  370. Error = MemArrayGetElement( Array, &Loc, &ThisSubnet );
  371. Require( ERROR_SUCCESS == Error );
  372. if( ThisSubnet == Subnet ) continue;
  373. if( ThisSubnet->SuperScopeId != Subnet->SuperScopeId ) continue;
  374. if( FALSE == MemSubnetCheckBootpDhcp( ThisSubnet, fBootp, FALSE ) )
  375. continue;
  376. return TRUE;
  377. }
  378. return FALSE;
  379. }
  380. //================================================================================
  381. // end of file
  382. //================================================================================