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.

1856 lines
47 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. pool.c
  5. Abstract:
  6. This module contains code for managing the NAT's pool of addresses
  7. as well as its ranges of ports.
  8. Author:
  9. Abolade Gbadegesin (t-abolag) 13-July-1997
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #define IP_NAT_MAX_ADDRESS_RANGE (1<<16)
  15. #define IP_NAT_MAX_CLIENT_COUNT (5+2)
  16. //
  17. // Macro used to avoid the fact that RtlInitializeBitMap is pageable
  18. // and hence cannot be called at DPC-level
  19. //
  20. #define INITIALIZE_BITMAP(BMH,B,S) \
  21. ((BMH)->Buffer = (B), (BMH)->SizeOfBitMap = (S))
  22. //
  23. // FORWARD DECLARATIONS
  24. //
  25. NTSTATUS
  26. NatCreateAddressPoolEntry(
  27. PNAT_INTERFACE Interfacep,
  28. ULONG PrivateAddress,
  29. ULONG PublicAddress,
  30. DWORD InitialFlags,
  31. PNAT_USED_ADDRESS* InsertionPoint,
  32. PNAT_USED_ADDRESS* AddressCreated
  33. );
  34. PNAT_USED_ADDRESS
  35. NatInsertAddressPoolEntry(
  36. PNAT_USED_ADDRESS Parent,
  37. PNAT_USED_ADDRESS Addressp
  38. );
  39. //
  40. // ADDRESS-POOL ROUTINES (alphabetically)
  41. //
  42. NTSTATUS
  43. NatAcquireFromAddressPool(
  44. PNAT_INTERFACE Interfacep,
  45. ULONG PrivateAddress,
  46. ULONG PublicAddress OPTIONAL,
  47. PNAT_USED_ADDRESS* AddressAcquired
  48. )
  49. /*++
  50. Routine Description:
  51. This routine acquires an address from an address pool.
  52. It initializes the address's port-pool.
  53. Arguments:
  54. Interfacep - interface on which to acquire an address.
  55. PrivateAddress - private address for whom to acquire a public address
  56. PublicAddress - optionally specifies the public-address to be acquired
  57. AddressAcquired - receives a pointer to the address acquired.
  58. Return Value:
  59. NTSTATUS - status code.
  60. --*/
  61. {
  62. ULONG ClientCount;
  63. PNAT_USED_ADDRESS InsertionPoint;
  64. PLIST_ENTRY Link;
  65. PNAT_USED_ADDRESS Sharedp;
  66. NTSTATUS status;
  67. PNAT_USED_ADDRESS Usedp;
  68. CALLTRACE(("NatAcquireFromAddressPool\n"));
  69. *AddressAcquired = NULL;
  70. TRACE(
  71. POOL, ("NatAcquireFromAddressPool: acquiring for %d.%d.%d.%d\n",
  72. ADDRESS_BYTES(PrivateAddress)
  73. ));
  74. //
  75. // See if the requesting private address already has a public address
  76. //
  77. for (Link = Interfacep->UsedAddressList.Flink, ClientCount = 0;
  78. Link != &Interfacep->UsedAddressList;
  79. Link = Link->Flink, ClientCount++) {
  80. Usedp = CONTAINING_RECORD(Link, NAT_USED_ADDRESS, Link);
  81. if (Usedp->PrivateAddress == PrivateAddress &&
  82. (!PublicAddress || Usedp->PublicAddress == PublicAddress)) {
  83. break;
  84. }
  85. }
  86. if (Link != &Interfacep->UsedAddressList) {
  87. NatReferenceAddressPoolEntry(Usedp);
  88. *AddressAcquired = Usedp;
  89. return STATUS_SUCCESS;
  90. } else if (ClientCount > IP_NAT_MAX_CLIENT_COUNT &&
  91. SharedUserData->NtProductType == NtProductWinNt) {
  92. #if 0
  93. TRACE(
  94. POOL, ("NatAcquireFromAddressPool: quota exceeded (%d clients)\n",
  95. ClientCount
  96. ));
  97. return STATUS_LICENSE_QUOTA_EXCEEDED;
  98. #endif
  99. }
  100. //
  101. // Create a new entry, inserting it in the list and tree
  102. //
  103. status =
  104. NatCreateAddressPoolEntry(
  105. Interfacep,
  106. PrivateAddress,
  107. PublicAddress,
  108. 0,
  109. NULL,
  110. AddressAcquired
  111. );
  112. if (NT_SUCCESS(status)) { return STATUS_SUCCESS; }
  113. TRACE(POOL, ("NatAcquireFromAddressPool: no free addresses\n"));
  114. //
  115. // No entry was available;
  116. // if the caller specified a specific address
  117. // or if the interface has port-translation disabled,
  118. // this is a total failure.
  119. // Otherwise, we can try to find an address which we can share.
  120. //
  121. if (PublicAddress || !NAT_INTERFACE_NAPT(Interfacep)) {
  122. return STATUS_UNSUCCESSFUL;
  123. }
  124. //
  125. // Look for an address which can be shared
  126. //
  127. for (Link = Interfacep->UsedAddressList.Flink;
  128. Link != &Interfacep->UsedAddressList; Link = Link->Flink) {
  129. Usedp = CONTAINING_RECORD(Link, NAT_USED_ADDRESS, Link);
  130. //
  131. // We cannot reuse statically mapped addresses,
  132. // and we ignore placeholders while searching.
  133. //
  134. if (NAT_POOL_STATIC(Usedp) || NAT_POOL_PLACEHOLDER(Usedp)) { continue; }
  135. //
  136. // We cannot reuse an entry which would result in our tree
  137. // containing duplicate keys.
  138. //
  139. if (NatLookupAddressPoolEntry(
  140. Interfacep->UsedAddressTree,
  141. PrivateAddress,
  142. Usedp->PublicAddress,
  143. &InsertionPoint
  144. )) { continue; }
  145. break;
  146. }
  147. if (Link == &Interfacep->UsedAddressList) { return STATUS_UNSUCCESSFUL; }
  148. //
  149. // Reuse the used-address;
  150. // If it is referenced, we're sharing it.
  151. //
  152. TRACE(
  153. POOL, ("NatAcquireFromAddressPool: reusing %d.%d.%d.%d\n",
  154. ADDRESS_BYTES(Usedp->PublicAddress)
  155. ));
  156. //
  157. // Allocate and initialize a placeholder which we can find
  158. // by searching on 'PrivateAddress'
  159. //
  160. Sharedp =
  161. ExAllocatePoolWithTag(
  162. NonPagedPool,
  163. sizeof(NAT_USED_ADDRESS),
  164. NAT_TAG_USED_ADDRESS
  165. );
  166. if (!Sharedp) {
  167. ERROR(("NatAcquireFromAddressPool: allocation failed\n"));
  168. return STATUS_NO_MEMORY;
  169. }
  170. RtlZeroMemory(Sharedp, sizeof(*Sharedp));
  171. Sharedp->Flags = NAT_POOL_FLAG_PLACEHOLDER;
  172. Sharedp->PrivateAddress = PrivateAddress;
  173. Sharedp->PublicAddress = Usedp->PublicAddress;
  174. Sharedp->Key =
  175. MAKE_USED_ADDRESS_KEY(
  176. Sharedp->PrivateAddress, Sharedp->PublicAddress
  177. );
  178. Sharedp->ReferenceCount = 1;
  179. InitializeListHead(&Sharedp->Link);
  180. RtlInitializeSplayLinks(&Sharedp->SLink);
  181. InsertTailList(&Interfacep->UsedAddressList, &Sharedp->Link);
  182. Interfacep->UsedAddressTree =
  183. NatInsertAddressPoolEntry(InsertionPoint, Sharedp);
  184. //
  185. // Set the placeholder's 'SharedAddress' field
  186. // to point to the actual address containing the port-pools
  187. //
  188. Sharedp->SharedAddress = Usedp;
  189. NatReferenceAddressPoolEntry(Usedp);
  190. *AddressAcquired = Sharedp;
  191. return STATUS_SUCCESS;
  192. } // NatAcquireFromAddressPool
  193. NTSTATUS
  194. NatAcquireEndpointFromAddressPool(
  195. PNAT_INTERFACE Interfacep,
  196. ULONG64 PrivateKey,
  197. ULONG64 RemoteKey,
  198. ULONG PublicAddress OPTIONAL,
  199. USHORT PreferredPort,
  200. BOOLEAN AllowAnyPort,
  201. PNAT_USED_ADDRESS* AddressAcquired,
  202. PUSHORT PortAcquired
  203. )
  204. /*++
  205. Routine Description:
  206. This routine is called to acquire an address and port for a session.
  207. Arguments:
  208. PrivateKey - the private endpoint for the session
  209. RemoteKey - the remote endpoint for the session
  210. PublicAddress - optionally specifies the public address to be acquired
  211. PreferredPort - optionally specifies the port preferred by the caller
  212. AllowAnyPort - if TRUE, any available port can be used for the mapping
  213. if 'Portp' is not available.
  214. AddressAcquired - receives the address acquired
  215. PortAcquired - receives the port acquired
  216. Return Value:
  217. NTSTATUS - indicates success/failure.
  218. Environment:
  219. Invoked with 'MappingLock' and 'Interfacep->Lock' held by the caller.
  220. --*/
  221. {
  222. PNAT_USED_ADDRESS Addressp;
  223. USHORT StopPort;
  224. ULONG i;
  225. PLIST_ENTRY Link;
  226. USHORT Port;
  227. UCHAR Protocol;
  228. ULONG64 PublicKey;
  229. PNAT_USED_ADDRESS SharedAddress;
  230. NTSTATUS status;
  231. CALLTRACE(("NatAcquireEndpointFromAddressPool\n"));
  232. //
  233. // Acquire an address for the session
  234. //
  235. status =
  236. NatAcquireFromAddressPool(
  237. Interfacep,
  238. MAPPING_ADDRESS(PrivateKey),
  239. PublicAddress,
  240. &Addressp
  241. );
  242. if (!NT_SUCCESS(status)) { return status; }
  243. SharedAddress = Addressp;
  244. PLACEHOLDER_TO_ADDRESS(SharedAddress);
  245. //
  246. // Now look for a port range which contains the preferred port
  247. //
  248. Protocol = MAPPING_PROTOCOL(PrivateKey);
  249. if (PreferredPort) {
  250. do {
  251. //
  252. // The caller prefers that we acquire a particular port;
  253. // see if we can satisfy the request.
  254. //
  255. Port = NTOHS(PreferredPort);
  256. if (Port < NTOHS(SharedAddress->StartPort) ||
  257. Port > NTOHS(SharedAddress->EndPort)) {
  258. break;
  259. }
  260. //
  261. // The preferred port is in the current range.
  262. // See if it is in use by another mapping
  263. //
  264. MAKE_MAPPING_KEY(
  265. PublicKey,
  266. Protocol,
  267. Addressp->PublicAddress,
  268. PreferredPort
  269. );
  270. if (NatLookupReverseMapping(PublicKey, RemoteKey, NULL)) { break; }
  271. //
  272. // Now see if it is in use by a ticket
  273. //
  274. if (NatIsPortUsedByTicket(Interfacep, Protocol, PreferredPort)) {
  275. break;
  276. }
  277. //
  278. // The preferred port is available; return
  279. //
  280. *AddressAcquired = Addressp;
  281. *PortAcquired = PreferredPort;
  282. TRACE(
  283. POOL,
  284. ("NatAcquireEndpointFromAddressPool: using preferred port %d\n",
  285. NTOHS(PreferredPort)
  286. ));
  287. return STATUS_SUCCESS;
  288. } while(FALSE);
  289. //
  290. // We couldn't acquire the preferred port;
  291. // fail if no other port is acceptable.
  292. //
  293. if (!AllowAnyPort || !NAT_INTERFACE_NAPT(Interfacep)) {
  294. NatDereferenceAddressPoolEntry(Interfacep, Addressp);
  295. return STATUS_UNSUCCESSFUL;
  296. }
  297. }
  298. //
  299. // If this is for a UDP session, check to see if there is another
  300. // session with the same private endpoint. If such a session
  301. // exists we want to use the same public endpoint for this session.
  302. //
  303. if (NAT_PROTOCOL_UDP == MAPPING_PROTOCOL(PrivateKey)) {
  304. PNAT_DYNAMIC_MAPPING Mapping;
  305. IP_NAT_PATH Path;
  306. //
  307. // Perform a source-only mapping lookup
  308. //
  309. Mapping = NatSourceLookupForwardMapping(PrivateKey);
  310. if (NULL == Mapping) {
  311. Mapping = NatSourceLookupReverseMapping(PrivateKey);
  312. }
  313. if (NULL != Mapping) {
  314. //
  315. // There's another UDP session with this private endpoint;
  316. // if it has the same public address that we've already
  317. // acquired then use the same public port.
  318. //
  319. Path = NAT_MAPPING_INBOUND(Mapping)
  320. ? NatForwardPath
  321. : NatReversePath;
  322. if (SharedAddress->PublicAddress
  323. == MAPPING_ADDRESS(Mapping->DestinationKey[Path])) {
  324. //
  325. // Same public address -- use the port from
  326. // this session.
  327. //
  328. *AddressAcquired = Addressp;
  329. *PortAcquired = MAPPING_PORT(Mapping->DestinationKey[Path]);
  330. TRACE(
  331. POOL,
  332. ("NatAcquireEndpointFromAddressPool: reusing UDP port %d\n",
  333. NTOHS(*PortAcquired)
  334. ));
  335. return STATUS_SUCCESS;
  336. }
  337. }
  338. }
  339. //
  340. // Acquire the first available port for the session
  341. //
  342. if (SharedAddress->NextPortToTry != SharedAddress->StartPort) {
  343. StopPort =
  344. RtlUshortByteSwap(
  345. (USHORT)(NTOHS(SharedAddress->NextPortToTry) - 1)
  346. );
  347. } else {
  348. StopPort = SharedAddress->EndPort;
  349. }
  350. for (Port = SharedAddress->NextPortToTry; Port != StopPort;
  351. Port = (Port != SharedAddress->EndPort
  352. ? RtlUshortByteSwap((USHORT)(NTOHS(Port) + 1))
  353. : SharedAddress->StartPort)) {
  354. //
  355. // See if this port is in use by a mapping
  356. //
  357. MAKE_MAPPING_KEY(PublicKey, Protocol, Addressp->PublicAddress, Port);
  358. if (NatLookupReverseMapping(PublicKey, RemoteKey, NULL)) { continue; }
  359. //
  360. // Now see if it is in use by a ticket
  361. //
  362. if (NatIsPortUsedByTicket(Interfacep, Protocol, Port)) { continue; }
  363. //
  364. // The port is available; return
  365. //
  366. *AddressAcquired = Addressp;
  367. *PortAcquired = Port;
  368. //
  369. // Update the address pool entry with the port with which to
  370. // start the search on the next allocation attempt.
  371. //
  372. if (Port == SharedAddress->EndPort) {
  373. SharedAddress->NextPortToTry = SharedAddress->StartPort;
  374. } else {
  375. SharedAddress->NextPortToTry =
  376. RtlUshortByteSwap(
  377. (USHORT)(NTOHS(Port) + 1)
  378. );
  379. }
  380. TRACE(
  381. POOL, ("NatAcquireEndpointFromAddressPool: using port %d\n",
  382. NTOHS(Port)
  383. ));
  384. return STATUS_SUCCESS;
  385. }
  386. //
  387. // We were unable to acquire a port for the session; fail.
  388. //
  389. NatDereferenceAddressPoolEntry(Interfacep, Addressp);
  390. TRACE(POOL, ("NatAcquireEndpointFromAddressPool: no ports available\n"));
  391. return STATUS_UNSUCCESSFUL;
  392. } // NatAcquireEndpointFromAddressPool
  393. NTSTATUS
  394. NatCreateAddressPool(
  395. PNAT_INTERFACE Interfacep
  396. )
  397. /*++
  398. Routine Description:
  399. This routine initializes an interface's address-pool.
  400. This involves setting up the bitmap of free addresses
  401. and reserving the statically mapped IP addresses.
  402. Arguments:
  403. Interfacep - the interface on which to create the address pool.
  404. Return Value:
  405. NTSTATUS - status code
  406. --*/
  407. {
  408. ULONG Address;
  409. BOOLEAN Changed;
  410. PNAT_FREE_ADDRESS FreeMapArray;
  411. ULONG FreeMapCount;
  412. PNAT_FREE_ADDRESS Freep;
  413. ULONG i;
  414. PNAT_USED_ADDRESS InsertionPoint;
  415. ULONG j;
  416. PRTL_SPLAY_LINKS Parent;
  417. PIP_NAT_ADDRESS_RANGE* RangeArrayIndirect;
  418. NTSTATUS status;
  419. PNAT_USED_ADDRESS Usedp;
  420. CALLTRACE(("NatCreateAddressPool\n"));
  421. if (Interfacep->AddressRangeCount <= 1) {
  422. RangeArrayIndirect = &Interfacep->AddressRangeArray;
  423. } else {
  424. //
  425. // Allocate a temporary block of pointers
  426. // to be used to do an indirect sort of the range-array.
  427. //
  428. RangeArrayIndirect =
  429. (PIP_NAT_ADDRESS_RANGE*)ExAllocatePoolWithTag(
  430. NonPagedPool,
  431. Interfacep->AddressRangeCount * sizeof(PVOID),
  432. NAT_TAG_RANGE_ARRAY
  433. );
  434. if (!RangeArrayIndirect) {
  435. ERROR(("NatCreateAddressPool: error allocating sort-buffer\n"));
  436. return STATUS_NO_MEMORY;
  437. }
  438. for (i = 0; i < Interfacep->AddressRangeCount; i++) {
  439. RangeArrayIndirect[i] = &Interfacep->AddressRangeArray[i];
  440. }
  441. do {
  442. //
  443. // Now do a bubble-sort of the ranges
  444. //
  445. Changed = FALSE;
  446. for (i = 0; i < Interfacep->AddressRangeCount - 1; i++) {
  447. PIP_NAT_ADDRESS_RANGE CurrentRange = RangeArrayIndirect[i];
  448. ULONG CurrentRangeStartAddress =
  449. RtlUlongByteSwap(CurrentRange->StartAddress);
  450. PIP_NAT_ADDRESS_RANGE NextRange;
  451. for (j = i+1, NextRange = RangeArrayIndirect[j];
  452. j < Interfacep->AddressRangeCount;
  453. j++, NextRange = RangeArrayIndirect[j]) {
  454. //
  455. // Do a swap if necessary
  456. //
  457. if (CurrentRangeStartAddress <=
  458. RtlUlongByteSwap(NextRange->StartAddress)) { continue; }
  459. RangeArrayIndirect[i] = NextRange;
  460. RangeArrayIndirect[j] = CurrentRange;
  461. CurrentRange = NextRange;
  462. CurrentRangeStartAddress =
  463. RtlUlongByteSwap(NextRange->StartAddress);
  464. Changed = TRUE;
  465. }
  466. }
  467. } while (Changed);
  468. }
  469. //
  470. // Copy the ranges into NAT_FREE_ADDRESS blocks.
  471. // There will be at most 'RangeCount' of these,
  472. // and possibly less, since we will merge any ranges
  473. // which overlap or are adjacent.
  474. //
  475. FreeMapCount = 0;
  476. if (!Interfacep->AddressRangeCount) {
  477. FreeMapArray = NULL;
  478. } else {
  479. FreeMapArray =
  480. (PNAT_FREE_ADDRESS)ExAllocatePoolWithTag(
  481. NonPagedPool,
  482. Interfacep->AddressRangeCount * sizeof(NAT_FREE_ADDRESS),
  483. NAT_TAG_FREE_MAP
  484. );
  485. if (!FreeMapArray) {
  486. ExFreePool(RangeArrayIndirect);
  487. return STATUS_NO_MEMORY;
  488. }
  489. }
  490. for (i = 0, j = 0; i < Interfacep->AddressRangeCount; i++) {
  491. ULONG RangeStartAddress =
  492. RtlUlongByteSwap(RangeArrayIndirect[i]->StartAddress);
  493. //
  494. // See if we should merge with the preceding block;
  495. //
  496. if (FreeMapCount) {
  497. //
  498. // Incrementing the end-address of the preceding range
  499. // enables us to catch both overlaps and adjacencies.
  500. //
  501. if (RangeStartAddress <=
  502. RtlUlongByteSwap(FreeMapArray[j].EndAddress) + 1) {
  503. //
  504. // We need to merge.
  505. //
  506. if (RtlUlongByteSwap(FreeMapArray[j].EndAddress) <
  507. RtlUlongByteSwap(RangeArrayIndirect[i]->EndAddress)) {
  508. FreeMapArray[j].EndAddress =
  509. RangeArrayIndirect[i]->EndAddress;
  510. }
  511. if (RtlUlongByteSwap(FreeMapArray[j].SubnetMask) <
  512. RtlUlongByteSwap(RangeArrayIndirect[i]->SubnetMask)) {
  513. FreeMapArray[j].SubnetMask =
  514. RangeArrayIndirect[i]->SubnetMask;
  515. }
  516. continue;
  517. }
  518. //
  519. // No merge; move to next slot.
  520. //
  521. ++j;
  522. }
  523. FreeMapArray[j].StartAddress = RangeArrayIndirect[i]->StartAddress;
  524. FreeMapArray[j].EndAddress = RangeArrayIndirect[i]->EndAddress;
  525. FreeMapArray[j].SubnetMask = RangeArrayIndirect[i]->SubnetMask;
  526. FreeMapCount++;
  527. }
  528. if (Interfacep->AddressRangeCount > 1) { ExFreePool(RangeArrayIndirect); }
  529. //
  530. // Now we have an array of disjoint, non-adjacent address-ranges;
  531. // Initialize the bitmap for each address-range.
  532. //
  533. for (i = 0; i < FreeMapCount; i++) {
  534. //
  535. // We can't allocate large enough bitmaps to support huge ranges;
  536. // for instance, if the address pool is 128.0.0.0-128.255.255.255,
  537. // the corresponding bitmap would have 2^24 bits, or 2MB.
  538. // For now, shrink all ranges to allow at most 2^16 bits, or 8K.
  539. //
  540. j = RtlUlongByteSwap(FreeMapArray[i].EndAddress) -
  541. RtlUlongByteSwap(FreeMapArray[i].StartAddress) + 1;
  542. if (j >= IP_NAT_MAX_ADDRESS_RANGE) {
  543. ERROR(("NatCreateAddressPool: shrinking %d-bit bitmap\n", j));
  544. //
  545. // Resize the range
  546. //
  547. FreeMapArray[i].EndAddress =
  548. RtlUlongByteSwap(
  549. RtlUlongByteSwap(FreeMapArray[i].StartAddress) +
  550. IP_NAT_MAX_ADDRESS_RANGE
  551. );
  552. j = IP_NAT_MAX_ADDRESS_RANGE;
  553. }
  554. //
  555. // Allocate a bitmap for the range
  556. //
  557. FreeMapArray[i].Bitmap =
  558. (PRTL_BITMAP)ExAllocatePoolWithTag(
  559. NonPagedPool,
  560. sizeof(RTL_BITMAP) +
  561. (j + sizeof(ULONG) * 8 - 1) / sizeof(ULONG) * 8,
  562. NAT_TAG_BITMAP
  563. );
  564. if (!FreeMapArray[i].Bitmap) {
  565. ERROR(("NatCreateAddressPool: error allocating bitmap\n"));
  566. while ((LONG)--i >= 0) { ExFreePool(FreeMapArray[i].Bitmap); }
  567. ExFreePool(FreeMapArray);
  568. return STATUS_NO_MEMORY;
  569. }
  570. INITIALIZE_BITMAP(
  571. FreeMapArray[i].Bitmap, (PULONG)(FreeMapArray[i].Bitmap + 1), j
  572. );
  573. RtlClearAllBits(FreeMapArray[i].Bitmap);
  574. }
  575. status = STATUS_SUCCESS;
  576. Interfacep->FreeMapArray = FreeMapArray;
  577. Interfacep->FreeMapCount = FreeMapCount;
  578. //
  579. // Create address-pool entries for each local address
  580. //
  581. for (i = 0; i < Interfacep->AddressCount; i++) {
  582. TRACE(
  583. POOL, ("NatCreateAddressPool: address %d.%d.%d.%d\n",
  584. ADDRESS_BYTES(Interfacep->AddressArray[i].Address))
  585. );
  586. status =
  587. NatCreateAddressPoolEntry(
  588. Interfacep,
  589. Interfacep->AddressArray[i].Address,
  590. Interfacep->AddressArray[i].Address,
  591. NAT_POOL_FLAG_BINDING,
  592. NULL,
  593. &Usedp
  594. );
  595. if (!NT_SUCCESS(status)) { break; }
  596. }
  597. //
  598. // Creating address-pool entries for each statically-mapped address
  599. //
  600. for (i = 0; i < Interfacep->AddressMappingCount; i++) {
  601. TRACE(
  602. POOL, ("NatCreateAddressPool: mapping %d.%d.%d.%d\n",
  603. ADDRESS_BYTES(Interfacep->AddressMappingArray[i].PrivateAddress))
  604. );
  605. status =
  606. NatCreateAddressPoolEntry(
  607. Interfacep,
  608. Interfacep->AddressMappingArray[i].PrivateAddress,
  609. Interfacep->AddressMappingArray[i].PublicAddress,
  610. NAT_POOL_FLAG_STATIC,
  611. NULL,
  612. &Usedp
  613. );
  614. if (!NT_SUCCESS(status)) { break; }
  615. Usedp->AddressMapping = &Interfacep->AddressMappingArray[i];
  616. }
  617. //
  618. // Create address-pool entries for statically-mapped port's address
  619. //
  620. for (i = Interfacep->PortMappingCount; i > 0; i--) {
  621. status =
  622. NatCreateStaticPortMapping(
  623. Interfacep,
  624. &Interfacep->PortMappingArray[i - 1]
  625. );
  626. if (!NT_SUCCESS(status)) { break; }
  627. }
  628. if (!NT_SUCCESS(status)) {
  629. //
  630. // An error occurred. Restore the original state.
  631. //
  632. NatDeleteAddressPool(Interfacep);
  633. return status;
  634. }
  635. return STATUS_SUCCESS;
  636. } // NatCreateAddressPool
  637. NTSTATUS
  638. NatCreateAddressPoolEntry(
  639. PNAT_INTERFACE Interfacep,
  640. ULONG PrivateAddress,
  641. ULONG PublicAddress,
  642. DWORD InitialFlags,
  643. PNAT_USED_ADDRESS* InsertionPoint,
  644. PNAT_USED_ADDRESS* AddressCreated
  645. )
  646. /*++
  647. Routine Description:
  648. This routine creates, initializes and inserts an address pool entry.
  649. Arguments:
  650. Interfacep - theinterface on which to create the entry.
  651. PrivateAddress - the address of the private machine using the address
  652. PublicAddress - the address for the entry, or 0 to allocate any address.
  653. InitialFlags - initial flags for the address-entry, as follows:
  654. NAT_POOL_FLAG_BINDING - if set, the address-entry is treated as
  655. a binding-entry
  656. NAT_POOL_FLAG_STATIC - if set, the address-entry corresponds to
  657. a static mapping
  658. InsertionPoint - optionally supplies the point where the entry
  659. should be inserted in the tree.
  660. AddressCreated - receives the entry created, or the existing entry
  661. if there is a collision.
  662. Return Value:
  663. NTSTATUS - success/failure code.
  664. --*/
  665. {
  666. ULONG ClassMask;
  667. ULONG Hint;
  668. ULONG HostOrderPublicAddress;
  669. ULONG i;
  670. ULONG Index;
  671. PNAT_USED_ADDRESS Insert;
  672. NTSTATUS status = STATUS_SUCCESS;
  673. PNAT_USED_ADDRESS Usedp;
  674. CALLTRACE(("NatCreateAddressPoolEntry\n"));
  675. *AddressCreated = NULL;
  676. if (PublicAddress) {
  677. HostOrderPublicAddress = RtlUlongByteSwap(PublicAddress);
  678. }
  679. //
  680. // Find the free-map which contains this binding, if any.
  681. //
  682. Index = (ULONG)-1;
  683. for (i = 0; i < Interfacep->FreeMapCount; i++) {
  684. //
  685. // See if we're supposed to be looking for a free address
  686. //
  687. if (!PublicAddress) {
  688. //
  689. // See if this free-map has any free addresses.
  690. //
  691. for (Hint = 0; ; Hint = Index + 1) {
  692. Index =
  693. RtlFindClearBits(
  694. Interfacep->FreeMapArray[i].Bitmap, 1, Hint
  695. );
  696. if (Index == (ULONG)-1) { break; }
  697. //
  698. // We've got a free address.
  699. // Make sure it isn't a prohibited address
  700. // (i.e. having 0 or all-ones in the subnet host portion).
  701. //
  702. PublicAddress =
  703. RtlUlongByteSwap(
  704. Index +
  705. RtlUlongByteSwap(
  706. Interfacep->FreeMapArray[i].StartAddress
  707. ));
  708. ClassMask = GET_CLASS_MASK(PublicAddress);
  709. if ((PublicAddress &
  710. ~Interfacep->FreeMapArray[i].SubnetMask) == 0 ||
  711. (PublicAddress & ~Interfacep->FreeMapArray[i].SubnetMask) ==
  712. ~Interfacep->FreeMapArray[i].SubnetMask ||
  713. (PublicAddress & ~ClassMask) == 0 ||
  714. (PublicAddress & ~ClassMask) == ~ClassMask) {
  715. //
  716. // The address is prohibited.
  717. // Mark it as unavailable so we don't waste time
  718. // looking at it ever again.
  719. //
  720. RtlSetBits(Interfacep->FreeMapArray[i].Bitmap, Index, 1);
  721. PublicAddress = 0; continue;
  722. }
  723. //
  724. // The address is not prohibited
  725. //
  726. break;
  727. }
  728. //
  729. // Go on to the next free-map if this one was of no use
  730. //
  731. if (Index == (ULONG)-1) { continue; }
  732. //
  733. // We found an address in the current free-map;
  734. // go on to initialize a used-address entry
  735. //
  736. break;
  737. }
  738. //
  739. // We're not looking for just any free-address;
  740. // We're looking for the free-map of a particular address.
  741. // See if the current free-map contains the address in question.
  742. //
  743. if (HostOrderPublicAddress >
  744. RtlUlongByteSwap(Interfacep->FreeMapArray[i].EndAddress)) {
  745. continue;
  746. } else {
  747. Index = RtlUlongByteSwap(Interfacep->FreeMapArray[i].StartAddress);
  748. if (HostOrderPublicAddress < Index) {
  749. Index = (ULONG)-1;
  750. continue;
  751. }
  752. }
  753. //
  754. // This is the free-map we want.
  755. // See if the address is prohibited, and if so fail.
  756. //
  757. Index = HostOrderPublicAddress - Index;
  758. if ((PublicAddress & ~Interfacep->FreeMapArray[i].SubnetMask) == 0 ||
  759. (PublicAddress & ~Interfacep->FreeMapArray[i].SubnetMask) ==
  760. ~Interfacep->FreeMapArray[i].SubnetMask) {
  761. //
  762. // The address is prohibited. Mark it so we don't waste time
  763. // looking at it ever again.
  764. //
  765. RtlSetBits(Interfacep->FreeMapArray[i].Bitmap, Index, 1);
  766. TRACE(POOL, ("NatCreateAddressPoolEntry: bad address requested\n"));
  767. return STATUS_UNSUCCESSFUL;
  768. }
  769. break;
  770. }
  771. if (!PublicAddress) {
  772. //
  773. // We couldn't find a free address.
  774. //
  775. TRACE(POOL, ("NatCreateAddressPoolEntry: no free addresses\n"));
  776. return STATUS_UNSUCCESSFUL;
  777. }
  778. //
  779. // Find the insertion point in the used-tree.
  780. //
  781. if (!InsertionPoint) {
  782. InsertionPoint = &Insert;
  783. Usedp =
  784. NatLookupAddressPoolEntry(
  785. Interfacep->UsedAddressTree,
  786. PrivateAddress,
  787. PublicAddress,
  788. InsertionPoint
  789. );
  790. if (Usedp) {
  791. //
  792. // This private-address already has a mapping; fail.
  793. //
  794. TRACE(POOL, ("NatCreateAddressPoolEntry: duplicate mapping\n"));
  795. return STATUS_UNSUCCESSFUL;
  796. }
  797. }
  798. //
  799. // Allocate a new entry for the new address
  800. //
  801. Usedp =
  802. ExAllocatePoolWithTag(
  803. NonPagedPool,
  804. sizeof(NAT_USED_ADDRESS),
  805. NAT_TAG_USED_ADDRESS
  806. );
  807. if (!Usedp) {
  808. ERROR(("NatCreateAddressPoolEntry: allocation failed\n"));
  809. return STATUS_NO_MEMORY;
  810. }
  811. RtlZeroMemory(Usedp, sizeof(*Usedp));
  812. Usedp->PrivateAddress = PrivateAddress;
  813. Usedp->PublicAddress = PublicAddress;
  814. Usedp->Key = MAKE_USED_ADDRESS_KEY(PrivateAddress, PublicAddress);
  815. Usedp->Flags = InitialFlags;
  816. Usedp->ReferenceCount = 1;
  817. InitializeListHead(&Usedp->Link);
  818. RtlInitializeSplayLinks(&Usedp->SLink);
  819. if (NAT_POOL_BINDING(Usedp)) {
  820. Usedp->StartPort = ReservedPortsLowerRange;
  821. Usedp->EndPort = ReservedPortsUpperRange;
  822. } else {
  823. Usedp->StartPort = NTOHS(1);
  824. Usedp->EndPort = NTOHS(65534);
  825. }
  826. Usedp->NextPortToTry = Usedp->StartPort;
  827. //
  828. // Insert the entry in the splay tree and list.
  829. //
  830. InsertTailList(&Interfacep->UsedAddressList, &Usedp->Link);
  831. Interfacep->UsedAddressTree =
  832. NatInsertAddressPoolEntry(*InsertionPoint, Usedp);
  833. //
  834. // Update the free-map
  835. //
  836. if (Index != (ULONG)-1) {
  837. RtlSetBits(Interfacep->FreeMapArray[i].Bitmap, Index, 1);
  838. }
  839. *AddressCreated = Usedp;
  840. return STATUS_SUCCESS;
  841. }
  842. NTSTATUS
  843. NatCreateStaticPortMapping(
  844. PNAT_INTERFACE Interfacep,
  845. PIP_NAT_PORT_MAPPING PortMapping
  846. )
  847. /*++
  848. Routine Description:
  849. This routine creates a static port mapping (i.e., persistent
  850. ticket) on an interace
  851. Arguments:
  852. Interfacep - the interface on which to create the port mapping.
  853. PortMapping - describes the port mapping to be created.
  854. Return Value:
  855. NTSTATUS - status code
  856. Environment:
  857. Invoked with Interfacep->Lock held by the caller.
  858. --*/
  859. {
  860. PNAT_USED_ADDRESS InsertionPoint;
  861. ULONG PublicAddress;
  862. USHORT PublicPort;
  863. NTSTATUS status;
  864. PNAT_TICKET Ticketp;
  865. PNAT_USED_ADDRESS Usedp;
  866. CALLTRACE(("NatCreateStaticPortMapping\n"));
  867. //
  868. // The handling of the static port-mapping depends upon whether
  869. // its public address is for the interface or from the address-pool.
  870. // If the 'PublicAddress' is zero, then the port-mapping refers
  871. // to sessions destined for the interface's actual address.
  872. // Otherwise, the port-mapping refers to sessions destined for
  873. // an address in the interface's address pool.
  874. //
  875. if (!PortMapping->PublicAddress) {
  876. status =
  877. NatAcquireFromAddressPool(
  878. Interfacep,
  879. PortMapping->PrivateAddress,
  880. 0,
  881. &Usedp
  882. );
  883. } else {
  884. Usedp =
  885. NatLookupAddressPoolEntry(
  886. Interfacep->UsedAddressTree,
  887. PortMapping->PrivateAddress,
  888. PortMapping->PublicAddress,
  889. &InsertionPoint
  890. );
  891. if (Usedp) {
  892. status = STATUS_SUCCESS;
  893. NatReferenceAddressPoolEntry(Usedp);
  894. } else {
  895. //
  896. // The mapping was not in use, so we need to create an
  897. // entry for its address.
  898. //
  899. status =
  900. NatCreateAddressPoolEntry(
  901. Interfacep,
  902. PortMapping->PrivateAddress,
  903. PortMapping->PublicAddress,
  904. 0,
  905. &InsertionPoint,
  906. &Usedp
  907. );
  908. }
  909. }
  910. //
  911. // Now create a ticket which will direct all incoming sessions
  912. // to the private endpoint specified in the static port-mapping.
  913. //
  914. if (NT_SUCCESS(status)) {
  915. status =
  916. NatCreateTicket(
  917. Interfacep,
  918. PortMapping->Protocol,
  919. PortMapping->PrivateAddress,
  920. PortMapping->PrivatePort,
  921. 0,
  922. 0,
  923. NAT_TICKET_FLAG_PORT_MAPPING|NAT_TICKET_FLAG_PERSISTENT,
  924. Usedp,
  925. PortMapping->PublicPort,
  926. &PublicAddress,
  927. &PublicPort
  928. );
  929. NatDereferenceAddressPoolEntry(Interfacep, Usedp);
  930. }
  931. return status;
  932. }// NatCreateStaticPortMapping
  933. NTSTATUS
  934. NatDeleteAddressPool(
  935. PNAT_INTERFACE Interfacep
  936. )
  937. /*++
  938. Routine Description:
  939. Destroys an address pool, freeing the memory used by the free-maps
  940. and optionally, the used-address entries.
  941. Arguments:
  942. Interfacep - the interface whose address pool is to be deleted.
  943. Return Value:
  944. NTSTATUS - status code.
  945. --*/
  946. {
  947. ULONG i;
  948. PLIST_ENTRY Link;
  949. PNAT_TICKET Ticketp;
  950. PNAT_USED_ADDRESS Usedp;
  951. CALLTRACE(("NatDeleteAddressPool\n"));
  952. //
  953. // Dispose of the free-maps
  954. //
  955. for (i = 0; i < Interfacep->FreeMapCount; i++) {
  956. if (Interfacep->FreeMapArray[i].Bitmap) {
  957. ExFreePool(Interfacep->FreeMapArray[i].Bitmap);
  958. }
  959. }
  960. Interfacep->FreeMapCount = 0;
  961. if (Interfacep->FreeMapArray) { ExFreePool(Interfacep->FreeMapArray); }
  962. Interfacep->FreeMapArray = NULL;
  963. //
  964. // Clear out port-mappings created as tickets
  965. //
  966. for (Link = Interfacep->TicketList.Flink; Link != &Interfacep->TicketList;
  967. Link = Link->Flink) {
  968. Ticketp = CONTAINING_RECORD(Link, NAT_TICKET, Link);
  969. if (!NAT_TICKET_PORT_MAPPING(Ticketp)) { continue; }
  970. Link = Link->Blink;
  971. NatDeleteTicket(Interfacep, Ticketp);
  972. }
  973. //
  974. // Deal with the used-list;
  975. //
  976. while (!IsListEmpty(&Interfacep->UsedAddressList)) {
  977. Link = RemoveHeadList(&Interfacep->UsedAddressList);
  978. Usedp = CONTAINING_RECORD(Link, NAT_USED_ADDRESS, Link);
  979. Usedp->Flags |= NAT_POOL_FLAG_DELETED;
  980. NatDereferenceAddressPoolEntry(Interfacep, Usedp);
  981. }
  982. Interfacep->UsedAddressTree = NULL;
  983. return STATUS_SUCCESS;
  984. } // NatDeleteAddressPool
  985. PNAT_USED_ADDRESS
  986. NatInsertAddressPoolEntry(
  987. PNAT_USED_ADDRESS Parent,
  988. PNAT_USED_ADDRESS Addressp
  989. )
  990. /*++
  991. Routine Description:
  992. This routine is called to insert an address in the interface's
  993. splay-tree of address-pool entries. The key is the 'PrivateAddress'
  994. field of the address-pool entry.
  995. Arguments:
  996. Parent - the parent of the entry to be inserted, which may be obtained
  997. from NatLookupAddressPoolEntry
  998. Addressp - the address pool entry to be inserted
  999. Return Value:
  1000. The new root of the splay tree if successful, NULL otherwise.
  1001. --*/
  1002. {
  1003. ULONG64 Key;
  1004. PRTL_SPLAY_LINKS Root;
  1005. CALLTRACE(("NatInsertAddressPoolEntry\n"));
  1006. if (!Parent) {
  1007. TRACE(POOL, ("NatInsertAddressPoolEntry: inserting as root\n"));
  1008. return Addressp;
  1009. }
  1010. //
  1011. // Insert as left or right child
  1012. //
  1013. Key =
  1014. MAKE_USED_ADDRESS_KEY(Addressp->PrivateAddress,Addressp->PublicAddress);
  1015. if (Addressp->Key < Parent->Key) {
  1016. RtlInsertAsLeftChild(&Parent->SLink, &Addressp->SLink);
  1017. } else if (Addressp->Key > Parent->Key) {
  1018. RtlInsertAsRightChild(&Parent->SLink, &Addressp->SLink);
  1019. } else {
  1020. //
  1021. // Keys are equal; fail.
  1022. //
  1023. ERROR((
  1024. "NatInsertAddressPoolEntry: collision on key 0x%016I64X\n",
  1025. Addressp->Key
  1026. ));
  1027. return NULL;
  1028. }
  1029. //
  1030. // Splay the new node and return the resulting root.
  1031. //
  1032. Root = RtlSplay(&Addressp->SLink);
  1033. return CONTAINING_RECORD(Root, NAT_USED_ADDRESS, SLink);
  1034. } // NatInsertAddressPoolEntry
  1035. PNAT_USED_ADDRESS
  1036. NatLookupAddressPoolEntry(
  1037. PNAT_USED_ADDRESS Root,
  1038. ULONG PrivateAddress,
  1039. ULONG PublicAddress,
  1040. PNAT_USED_ADDRESS* InsertionPoint
  1041. )
  1042. /*++
  1043. Routine Description:
  1044. This routine searches the interface's splay tree of address-pool entries
  1045. for a particular entry, returning the entry if found, otherwise supplying
  1046. the insertion point for the entry.
  1047. Arguments:
  1048. Root - the root of the splay tree ('Interfacep->UsedAddressTree').
  1049. PrivateAddress - the private part of the address-mapping to be looked up
  1050. PublicAddress - the public part of the address-mapping to be looked up
  1051. InsertionPoint - receives the insertion point for the entry
  1052. Return Value:
  1053. The entry if found, NULL otherwise.
  1054. --*/
  1055. {
  1056. PNAT_USED_ADDRESS Addressp;
  1057. ULONG64 Key;
  1058. PNAT_USED_ADDRESS Parent = NULL;
  1059. PRTL_SPLAY_LINKS SLink;
  1060. TRACE(PER_PACKET, ("NatLookupAddressPoolEntry\n"));
  1061. Key = MAKE_USED_ADDRESS_KEY(PrivateAddress, PublicAddress);
  1062. for (SLink = !Root ? NULL : &Root->SLink; SLink; ) {
  1063. Addressp = CONTAINING_RECORD(SLink, NAT_USED_ADDRESS, SLink);
  1064. if (Key < Addressp->Key) {
  1065. Parent = Addressp;
  1066. SLink = RtlLeftChild(SLink);
  1067. continue;
  1068. } else if (Key > Addressp->Key) {
  1069. Parent = Addressp;
  1070. SLink = RtlRightChild(SLink);
  1071. continue;
  1072. }
  1073. //
  1074. // Private-addresses match; we got it.
  1075. //
  1076. return Addressp;
  1077. }
  1078. //
  1079. // We didn't get it; tell the caller where to insert it.
  1080. //
  1081. if (InsertionPoint) { *InsertionPoint = Parent; }
  1082. return NULL;
  1083. } // NatLookupAddressPoolEntry
  1084. PNAT_USED_ADDRESS
  1085. NatLookupStaticAddressPoolEntry(
  1086. PNAT_INTERFACE Interfacep,
  1087. ULONG PublicAddress,
  1088. BOOLEAN RequireInboundSessions
  1089. )
  1090. /*++
  1091. Routine Description:
  1092. This routine is invoked to search for an address pool entry
  1093. which is marked static and which corresponds to the given public address.
  1094. Arguments:
  1095. Interfacep - the interface whose address pool is to be searched
  1096. PublicAddress - the public address for which to search
  1097. RequireInboundSessions - if TRUE, a match is declared only if
  1098. the entry found allows inbound sessions.
  1099. Return Value:
  1100. PNAT_USED_ADDRESS - the address pool entry found, if any.
  1101. --*/
  1102. {
  1103. ULONG i;
  1104. PNAT_USED_ADDRESS Addressp;
  1105. PIP_NAT_ADDRESS_MAPPING AddressMapping;
  1106. if (!Interfacep->AddressMappingCount) {
  1107. return NULL;
  1108. } else {
  1109. //
  1110. // Perform exhaustive search since static address-mappings
  1111. // are sorted by private address rather than public address.
  1112. //
  1113. AddressMapping = NULL;
  1114. for (i = 0; i < Interfacep->AddressMappingCount; i++) {
  1115. if (PublicAddress !=
  1116. Interfacep->AddressMappingArray[i].PublicAddress) {
  1117. continue;
  1118. }
  1119. AddressMapping = &Interfacep->AddressMappingArray[i];
  1120. break;
  1121. }
  1122. }
  1123. if (!AddressMapping ||
  1124. !(Addressp =
  1125. NatLookupAddressPoolEntry(
  1126. Interfacep->UsedAddressTree,
  1127. AddressMapping->PrivateAddress,
  1128. AddressMapping->PublicAddress,
  1129. NULL
  1130. )) ||
  1131. !NAT_POOL_STATIC(Addressp) ||
  1132. (RequireInboundSessions && !AddressMapping->AllowInboundSessions)) {
  1133. return NULL;
  1134. }
  1135. return Addressp;
  1136. } // NatLookupStaticAddressPoolEntry
  1137. NTSTATUS
  1138. NatDereferenceAddressPoolEntry(
  1139. PNAT_INTERFACE Interfacep,
  1140. PNAT_USED_ADDRESS AddressToRelease
  1141. )
  1142. /*++
  1143. Routine Description:
  1144. Drops the reference count on an address pool entry.
  1145. This routine invalidates the supplied NAT_USED_ADDRESS pointer.
  1146. Note, though, that it might not be freed, e.g. in the case where
  1147. the address is being shared.
  1148. If the entry is a placeholder and its reference count drops to zero,
  1149. we also drop the reference count of its target ('SharedAddress') entry.
  1150. N.B. If the entry is marked 'deleted', we ignore the 'Interfacep' argument
  1151. since the entry must have been already removed from its interface's
  1152. address pool.
  1153. Arguments:
  1154. Interfacep - the interface whose address pool is to be deleted.
  1155. AddressToRelease - contains a pointer to the address to be released.
  1156. Return Value:
  1157. NTSTATUS - status code.
  1158. --*/
  1159. {
  1160. ULONG HostOrderPublicAddress;
  1161. ULONG i;
  1162. ULONG Index;
  1163. PRTL_SPLAY_LINKS SLink;
  1164. PNAT_USED_ADDRESS Usedp = AddressToRelease;
  1165. CALLTRACE(("NatDereferenceAddressPoolEntry\n"));
  1166. if (NAT_POOL_PLACEHOLDER(Usedp)) {
  1167. //
  1168. // Do nothing if there are other references to the placeholder
  1169. //
  1170. if (InterlockedDecrement(&Usedp->ReferenceCount)) {
  1171. return STATUS_SUCCESS;
  1172. }
  1173. //
  1174. // Unlink and free the placeholder
  1175. //
  1176. if (!NAT_POOL_DELETED(Usedp)) {
  1177. RemoveEntryList(&Usedp->Link);
  1178. SLink = RtlDelete(&Usedp->SLink);
  1179. Interfacep->UsedAddressTree =
  1180. !SLink
  1181. ? NULL
  1182. : CONTAINING_RECORD(SLink, NAT_USED_ADDRESS, SLink);
  1183. }
  1184. //
  1185. // Move on to the shared-address
  1186. //
  1187. Usedp = Usedp->SharedAddress;
  1188. ExFreePool(AddressToRelease);
  1189. }
  1190. //
  1191. // Do nothing if there are others sharing this address
  1192. //
  1193. if (InterlockedDecrement(&Usedp->ReferenceCount)) { return STATUS_SUCCESS; }
  1194. if (!NAT_POOL_DELETED(Usedp)) {
  1195. //
  1196. // Marking the entry's address as free in the interface's bitmap.
  1197. //
  1198. Index = Usedp->PublicAddress;
  1199. HostOrderPublicAddress = RtlUlongByteSwap(Usedp->PublicAddress);
  1200. for (i = 0; i < Interfacep->FreeMapCount; i++) {
  1201. if (HostOrderPublicAddress <
  1202. RtlUlongByteSwap(Interfacep->FreeMapArray[i].StartAddress) ||
  1203. HostOrderPublicAddress >
  1204. RtlUlongByteSwap(Interfacep->FreeMapArray[i].EndAddress)) {
  1205. continue;
  1206. }
  1207. Index =
  1208. HostOrderPublicAddress -
  1209. RtlUlongByteSwap(Interfacep->FreeMapArray[i].StartAddress);
  1210. RtlClearBits(Interfacep->FreeMapArray[i].Bitmap, Index, 1);
  1211. break;
  1212. }
  1213. //
  1214. // Now we're done; just unlink and free the used-address block
  1215. //
  1216. RemoveEntryList(&Usedp->Link);
  1217. SLink = RtlDelete(&Usedp->SLink);
  1218. Interfacep->UsedAddressTree =
  1219. !SLink ? NULL : CONTAINING_RECORD(SLink, NAT_USED_ADDRESS, SLink);
  1220. }
  1221. ExFreePool(Usedp);
  1222. return STATUS_SUCCESS;
  1223. } // NatDereferenceAddressPoolEntry
  1224. //
  1225. // PORT-POOL ROUTINES (alphabetically)
  1226. //
  1227. NTSTATUS
  1228. NatAcquireFromPortPool(
  1229. PNAT_INTERFACE Interfacep,
  1230. PNAT_USED_ADDRESS Addressp,
  1231. UCHAR Protocol,
  1232. USHORT PreferredPort,
  1233. PUSHORT PortAcquired
  1234. )
  1235. /*++
  1236. Routine Description:
  1237. This routine is invoked to acquire a unique public port from the pool.
  1238. The port acquired is guaranteed to not be in use by any mapping.
  1239. This is needed, for instance, when we are obtaining a port for a ticket
  1240. to be created by an editor for a dynamically negotiated session.
  1241. Arguments:
  1242. Interfacep - the interface on which to acquire the port
  1243. Addressp - the address on which to acquire the port
  1244. Protocol - the protocol for which to acquire the port
  1245. PreferredPort - the port preferred by the caller
  1246. PortAcquired - receives the port acquired
  1247. Return Value:
  1248. NTSTATUS - success/failure code.
  1249. Environment:
  1250. Invoked with 'MappingLock' and 'Interfacep->Lock' held by the caller.
  1251. --*/
  1252. {
  1253. #define QUERY_PUBLIC_PORT(m,p) \
  1254. NatQueryInformationMapping((m),NULL,NULL,NULL,NULL,NULL,NULL,p,NULL)
  1255. USHORT EndPort;
  1256. ULONG i;
  1257. PLIST_ENTRY Link;
  1258. PNAT_DYNAMIC_MAPPING Mapping;
  1259. USHORT Port;
  1260. USHORT PublicPort;
  1261. PNAT_USED_ADDRESS SharedAddress;
  1262. CALLTRACE(("NatAcquireFromPortPool\n"));
  1263. SharedAddress = Addressp;
  1264. PLACEHOLDER_TO_ADDRESS(SharedAddress);
  1265. //
  1266. // First attempt to satisfy the caller's preference
  1267. //
  1268. if (PreferredPort) {
  1269. //
  1270. // The caller prefers that we acquire a particular port;
  1271. // see if we can satisfy the request.
  1272. //
  1273. do {
  1274. Port = NTOHS(PreferredPort);
  1275. if (Port < NTOHS(SharedAddress->StartPort) ||
  1276. Port > NTOHS(SharedAddress->EndPort)) {
  1277. break;
  1278. }
  1279. //
  1280. // The preferred port is in the current range.
  1281. // See if it is in use by another mapping
  1282. //
  1283. KeAcquireSpinLockAtDpcLevel(&InterfaceMappingLock);
  1284. for (Link = Interfacep->MappingList.Flink;
  1285. Link != &Interfacep->MappingList; Link = Link->Flink) {
  1286. Mapping =
  1287. CONTAINING_RECORD(Link, NAT_DYNAMIC_MAPPING, InterfaceLink);
  1288. QUERY_PUBLIC_PORT(Mapping, &PublicPort);
  1289. if (PreferredPort == PublicPort) { break; }
  1290. }
  1291. if (Link != &Interfacep->MappingList) {
  1292. KeReleaseSpinLockFromDpcLevel(&InterfaceMappingLock);
  1293. break;
  1294. }
  1295. KeReleaseSpinLockFromDpcLevel(&InterfaceMappingLock);
  1296. //
  1297. // Now see if it is in use by a ticket
  1298. //
  1299. if (NatIsPortUsedByTicket(Interfacep, Protocol, PreferredPort)) {
  1300. break;
  1301. }
  1302. //
  1303. // The preferred port is available; return
  1304. //
  1305. TRACE(
  1306. POOL,
  1307. ("NatAcquireFromPortPool: using preferred port %d\n",
  1308. NTOHS(PreferredPort)
  1309. ));
  1310. *PortAcquired = PreferredPort;
  1311. return STATUS_SUCCESS;
  1312. } while(FALSE);
  1313. //
  1314. // We couldn't acquire the preferred port;
  1315. // fail if no other port is acceptable.
  1316. //
  1317. if (!NAT_INTERFACE_NAPT(Interfacep)) {
  1318. TRACE(
  1319. POOL,
  1320. ("NatAcquireFromPortPool: unable to use preferred port %d\n",
  1321. NTOHS(PreferredPort)
  1322. ));
  1323. return STATUS_UNSUCCESSFUL;
  1324. }
  1325. }
  1326. //
  1327. // Search the port pool, looking for a port which
  1328. // (a) is not already in use by any mapping, and
  1329. // (b) is not already in use by any ticket.
  1330. //
  1331. EndPort = RtlUshortByteSwap((USHORT)(NTOHS(SharedAddress->EndPort) + 1));
  1332. for (Port = SharedAddress->StartPort; Port != EndPort;
  1333. Port = RtlUshortByteSwap((USHORT)(NTOHS(Port) + 1))) {
  1334. //
  1335. // Look through the interface's mappings
  1336. //
  1337. KeAcquireSpinLockAtDpcLevel(&InterfaceMappingLock);
  1338. for (Link = Interfacep->MappingList.Flink;
  1339. Link != &Interfacep->MappingList; Link = Link->Flink) {
  1340. Mapping =
  1341. CONTAINING_RECORD(Link, NAT_DYNAMIC_MAPPING, InterfaceLink);
  1342. QUERY_PUBLIC_PORT(Mapping, &PublicPort);
  1343. if (Port == PublicPort) { break; }
  1344. }
  1345. if (Link != &Interfacep->MappingList) {
  1346. KeReleaseSpinLockFromDpcLevel(&InterfaceMappingLock);
  1347. continue;
  1348. }
  1349. KeReleaseSpinLockFromDpcLevel(&InterfaceMappingLock);
  1350. //
  1351. // No mapping is using the public-port;
  1352. // Now see if any ticket is using the public port
  1353. //
  1354. if (NatIsPortUsedByTicket(Interfacep, Protocol, Port)) { continue; }
  1355. //
  1356. // The port is not in use by any mapping or ticket; we're done.
  1357. //
  1358. TRACE(
  1359. POOL, ("NatAcquireFromPortPool: acquiring port %d\n",
  1360. NTOHS(Port)
  1361. ));
  1362. *PortAcquired = Port;
  1363. return STATUS_SUCCESS;
  1364. }
  1365. TRACE(POOL, ("NatAcquireFromPortPool: no available ports\n"));
  1366. return STATUS_UNSUCCESSFUL;
  1367. } // NatAcquireFromPortPool