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.

2209 lines
60 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. mapping.c
  5. Abstract:
  6. This file contains the code for mapping management.
  7. Author:
  8. Abolade Gbadegesin (t-abolag) 11-July-1997
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. //
  14. // GLOBAL VARIABLE DEFINITIONS
  15. //
  16. ULONG ExpiredMappingCount;
  17. CACHE_ENTRY MappingCache[NatMaximumPath][CACHE_SIZE];
  18. ULONG MappingCount;
  19. LIST_ENTRY MappingList;
  20. KSPIN_LOCK MappingLock;
  21. NPAGED_LOOKASIDE_LIST MappingLookasideList;
  22. PNAT_DYNAMIC_MAPPING MappingTree[NatMaximumPath];
  23. PVOID
  24. NatAllocateFunction(
  25. POOL_TYPE PoolType,
  26. SIZE_T NumberOfBytes,
  27. ULONG Tag
  28. )
  29. /*++
  30. Routine Description:
  31. Called by lookaside lists to allocate memory from the low-priority
  32. pool.
  33. Arguments:
  34. PoolType - the pool to allocate from (e.g., non-paged)
  35. NumberOfBytes - the number of bytes to allocate
  36. Tag - the tag for the allocation
  37. Return Value:
  38. PVOID - pointer to the allocated memory, or NULL for failure.
  39. --*/
  40. {
  41. return
  42. ExAllocatePoolWithTagPriority(
  43. PoolType,
  44. NumberOfBytes,
  45. Tag,
  46. LowPoolPriority
  47. );
  48. } // NatAllocateFunction
  49. VOID
  50. NatCleanupMapping(
  51. PNAT_DYNAMIC_MAPPING Mapping
  52. )
  53. /*++
  54. Routine Description:
  55. Called to perform final cleanup for a mapping.
  56. Arguments:
  57. Mapping - the mapping to be deleted.
  58. Return Value:
  59. none.
  60. Environment:
  61. Invoked with the last reference to the mapping released.
  62. --*/
  63. {
  64. KIRQL Irql;
  65. CALLTRACE(("NatCleanupMapping\n"));
  66. //
  67. // The last reference to the mapping has been released;
  68. //
  69. // Let the mapping's director know that it's expired
  70. //
  71. KeAcquireSpinLock(&DirectorLock, &Irql);
  72. if (Mapping->Director) {
  73. KeAcquireSpinLockAtDpcLevel(&DirectorMappingLock);
  74. NatMappingDetachDirector(
  75. Mapping->Director,
  76. Mapping->DirectorContext,
  77. Mapping,
  78. NatCleanupSessionDeleteReason
  79. );
  80. KeReleaseSpinLockFromDpcLevel(&DirectorMappingLock);
  81. }
  82. KeReleaseSpinLockFromDpcLevel(&DirectorLock);
  83. //
  84. // Let the mapping's editor know that it's expired
  85. //
  86. KeAcquireSpinLockAtDpcLevel(&EditorLock);
  87. if (Mapping->Editor) {
  88. KeAcquireSpinLockAtDpcLevel(&EditorMappingLock);
  89. NatMappingDetachEditor(Mapping->Editor, Mapping);
  90. KeReleaseSpinLockFromDpcLevel(&EditorMappingLock);
  91. }
  92. KeReleaseSpinLockFromDpcLevel(&EditorLock);
  93. //
  94. // If the mapping is associated with an address-pool, release the address,
  95. // and update the statistics for the mapping's interface
  96. //
  97. KeAcquireSpinLockAtDpcLevel(&InterfaceLock);
  98. if (Mapping->Interfacep) {
  99. KeAcquireSpinLockAtDpcLevel(&InterfaceMappingLock);
  100. NatMappingDetachInterface(
  101. Mapping->Interfacep, Mapping->InterfaceContext, Mapping
  102. );
  103. KeReleaseSpinLockFromDpcLevel(&InterfaceMappingLock);
  104. }
  105. KeReleaseSpinLock(&InterfaceLock, Irql);
  106. //
  107. // Clear the location the mapping would occupy in the cache,
  108. // in case it is cached.
  109. //
  110. ClearCache(
  111. MappingCache[NatForwardPath],
  112. (ULONG)Mapping->DestinationKey[NatForwardPath]
  113. );
  114. ClearCache(
  115. MappingCache[NatReversePath],
  116. (ULONG)Mapping->DestinationKey[NatReversePath]
  117. );
  118. FREE_MAPPING_BLOCK(Mapping);
  119. } // NatCleanupMapping
  120. NTSTATUS
  121. NatCreateMapping(
  122. ULONG Flags,
  123. ULONG64 DestinationKey[],
  124. ULONG64 SourceKey[],
  125. PNAT_INTERFACE Interfacep,
  126. PVOID InterfaceContext,
  127. USHORT MaxMSS,
  128. PNAT_DIRECTOR Director,
  129. PVOID DirectorSessionContext,
  130. PNAT_DYNAMIC_MAPPING* ForwardInsertionPoint,
  131. PNAT_DYNAMIC_MAPPING* ReverseInsertionPoint,
  132. PNAT_DYNAMIC_MAPPING* MappingCreated
  133. )
  134. /*++
  135. Routine Description:
  136. This function initializes the fields of a mapping.
  137. On returning, the routine will have made an initial reference
  138. to the mapping. The caller must call 'NatDereferenceMapping'
  139. to release this reference.
  140. Arguments:
  141. Flags - controls creation of the mapping
  142. DestinationKey[] - the forward and reverse destination-endpoint keys
  143. SourceKey[] - the forward and reverse source-endpoint keys
  144. Interface* - the interface, if any, with which the mapping is associated,
  145. and the associated context
  146. MaxMSS - the maximum MSS value allowed on the outgoing interface.
  147. Director* - the director, if any, with which the mapping is associated,
  148. and the associated context
  149. ForwardInsertionPoint - optionally supplies the point of insertion
  150. in the forward-lookup mapping-tree
  151. ReverseInsertionPoint - optionally supplies the point of insertion
  152. in the reverse-lookup mapping-tree
  153. MappingCreated - receives the mapping created.
  154. Return Value:
  155. none.
  156. Environment:
  157. Invoked with 'MappingLock' held by the caller, and with both 'Interfacep'
  158. and 'Director' referenced, if specified.
  159. --*/
  160. {
  161. PNAT_EDITOR Editor;
  162. ULONG InboundKey;
  163. PNAT_DYNAMIC_MAPPING InsertionPoint1;
  164. PNAT_DYNAMIC_MAPPING InsertionPoint2;
  165. ULONG InterfaceFlags;
  166. PLIST_ENTRY Link;
  167. PNAT_DYNAMIC_MAPPING Mapping;
  168. ULONG OutboundKey;
  169. UCHAR Protocol;
  170. PRTL_SPLAY_LINKS SLink;
  171. NTSTATUS status;
  172. BOOLEAN FirewallMode = FALSE;
  173. CALLTRACE(("NatCreateMapping\n"));
  174. //
  175. // Allocate the memory for the new block
  176. //
  177. Mapping = ALLOCATE_MAPPING_BLOCK();
  178. if (!Mapping) {
  179. ERROR(("NatCreateMapping: allocation failed\n"));
  180. if (Interfacep) {
  181. NatMappingDetachInterface(Interfacep, InterfaceContext, NULL);
  182. }
  183. if (Director) {
  184. NatMappingDetachDirector(
  185. Director,
  186. DirectorSessionContext,
  187. NULL,
  188. NatCreateFailureDeleteReason
  189. );
  190. }
  191. return STATUS_NO_MEMORY;
  192. }
  193. RtlZeroMemory(Mapping, sizeof(*Mapping));
  194. KeInitializeSpinLock(&Mapping->Lock);
  195. Mapping->ReferenceCount = 1;
  196. Mapping->Flags = Flags;
  197. Mapping->MaxMSS = MaxMSS;
  198. Mapping->DestinationKey[NatForwardPath] = DestinationKey[NatForwardPath];
  199. Mapping->DestinationKey[NatReversePath] = DestinationKey[NatReversePath];
  200. Mapping->SourceKey[NatForwardPath] = SourceKey[NatForwardPath];
  201. Mapping->SourceKey[NatReversePath] = SourceKey[NatReversePath];
  202. Mapping->AccessCount[NatForwardPath] = NAT_MAPPING_RESPLAY_THRESHOLD;
  203. Mapping->AccessCount[NatReversePath] = NAT_MAPPING_RESPLAY_THRESHOLD;
  204. InitializeListHead(&Mapping->Link);
  205. InitializeListHead(&Mapping->DirectorLink);
  206. InitializeListHead(&Mapping->EditorLink);
  207. InitializeListHead(&Mapping->InterfaceLink);
  208. RtlInitializeSplayLinks(&Mapping->SLink[NatForwardPath]);
  209. RtlInitializeSplayLinks(&Mapping->SLink[NatReversePath]);
  210. Protocol = MAPPING_PROTOCOL(DestinationKey[0]);
  211. if (SourceKey[NatForwardPath] == DestinationKey[NatReversePath]
  212. && DestinationKey[NatForwardPath] == SourceKey[NatReversePath]) {
  213. //
  214. // This mapping is being created for firewall puposes -- no actual
  215. // translation needs to be performed. Knowing this, we can use
  216. // different translation routines and save us some time...
  217. //
  218. TRACE(MAPPING,("NAT: Creating FW null mapping\n"));
  219. FirewallMode = TRUE;
  220. if (Protocol == NAT_PROTOCOL_TCP) {
  221. Mapping->TranslateRoutine[NatForwardPath] = NatTranslateForwardTcpNull;
  222. Mapping->TranslateRoutine[NatReversePath] = NatTranslateReverseTcpNull;
  223. } else {
  224. Mapping->TranslateRoutine[NatForwardPath] = NatTranslateForwardUdpNull;
  225. Mapping->TranslateRoutine[NatReversePath] = NatTranslateReverseUdpNull;
  226. }
  227. } else if (Protocol == NAT_PROTOCOL_TCP) {
  228. Mapping->TranslateRoutine[NatForwardPath] = NatTranslateForwardTcp;
  229. Mapping->TranslateRoutine[NatReversePath] = NatTranslateReverseTcp;
  230. } else {
  231. Mapping->TranslateRoutine[NatForwardPath] = NatTranslateForwardUdp;
  232. Mapping->TranslateRoutine[NatReversePath] = NatTranslateReverseUdp;
  233. }
  234. //
  235. // Increment the reference count on the mapping;
  236. // the caller should then do a 'Dereference'.
  237. //
  238. ++Mapping->ReferenceCount;
  239. //
  240. // Attach the mapping to its interface, if any
  241. //
  242. if (Interfacep) {
  243. KeAcquireSpinLockAtDpcLevel(&InterfaceLock);
  244. KeAcquireSpinLockAtDpcLevel(&InterfaceMappingLock);
  245. NatMappingAttachInterface(Interfacep, InterfaceContext, Mapping);
  246. KeReleaseSpinLockFromDpcLevel(&InterfaceMappingLock);
  247. InterfaceFlags = Interfacep->Flags;
  248. KeReleaseSpinLockFromDpcLevel(&InterfaceLock);
  249. }
  250. //
  251. // Attach the mapping to its director, if any
  252. //
  253. if (Director) {
  254. KeAcquireSpinLockAtDpcLevel(&DirectorLock);
  255. KeAcquireSpinLockAtDpcLevel(&DirectorMappingLock);
  256. NatMappingAttachDirector(Director, DirectorSessionContext, Mapping);
  257. KeReleaseSpinLockFromDpcLevel(&DirectorMappingLock);
  258. KeReleaseSpinLockFromDpcLevel(&DirectorLock);
  259. }
  260. //
  261. // We now set up any editors interested in this session,
  262. // if the mapping is associated with a boundary interface.
  263. //
  264. if (Interfacep) {
  265. InboundKey =
  266. MAKE_EDITOR_KEY(
  267. Protocol,
  268. MAPPING_PORT(DestinationKey[NatForwardPath]),
  269. NatInboundDirection
  270. );
  271. OutboundKey =
  272. MAKE_EDITOR_KEY(
  273. Protocol,
  274. MAPPING_PORT(DestinationKey[NatForwardPath]),
  275. NatOutboundDirection
  276. );
  277. KeAcquireSpinLockAtDpcLevel(&EditorLock);
  278. for (Link = EditorList.Flink; Link != &EditorList; Link = Link->Flink) {
  279. Editor = CONTAINING_RECORD(Link, NAT_EDITOR, Link);
  280. //
  281. // Skip any built-in editors that are administratively disabled.
  282. //
  283. if (((InterfaceFlags & IP_NAT_INTERFACE_FLAGS_DISABLE_PPTP) &&
  284. (PVOID)Editor == PptpRegisterEditorClient.EditorHandle) ||
  285. ((InterfaceFlags & IP_NAT_INTERFACE_FLAGS_DISABLE_PPTP) &&
  286. (PVOID)Editor == PptpRegisterEditorServer.EditorHandle)) {
  287. continue;
  288. }
  289. if (Editor->Key == InboundKey && NAT_MAPPING_INBOUND(Mapping)) {
  290. KeAcquireSpinLockAtDpcLevel(&EditorMappingLock);
  291. NatMappingAttachEditor(Editor, Mapping);
  292. KeReleaseSpinLockFromDpcLevel(&EditorMappingLock);
  293. //
  294. // Update the mapping's translation-routine table
  295. //
  296. if (Protocol == NAT_PROTOCOL_UDP) {
  297. Mapping->TranslateRoutine[NatForwardPath] =
  298. NatTranslateForwardUdpEdit;
  299. Mapping->TranslateRoutine[NatReversePath] =
  300. NatTranslateReverseUdpEdit;
  301. } else if (!NAT_EDITOR_RESIZE(Editor)) {
  302. Mapping->TranslateRoutine[NatForwardPath] =
  303. NatTranslateForwardTcpEdit;
  304. Mapping->TranslateRoutine[NatReversePath] =
  305. NatTranslateReverseTcpEdit;
  306. } else {
  307. Mapping->TranslateRoutine[NatForwardPath] =
  308. NatTranslateForwardTcpResize;
  309. Mapping->TranslateRoutine[NatReversePath] =
  310. NatTranslateReverseTcpResize;
  311. }
  312. break;
  313. } else if (Editor->Key == OutboundKey &&
  314. !NAT_MAPPING_INBOUND(Mapping)) {
  315. KeAcquireSpinLockAtDpcLevel(&EditorMappingLock);
  316. NatMappingAttachEditor(Editor, Mapping);
  317. KeReleaseSpinLockFromDpcLevel(&EditorMappingLock);
  318. //
  319. // Update the mapping's translation-routine table
  320. //
  321. if (Protocol == NAT_PROTOCOL_UDP) {
  322. Mapping->TranslateRoutine[NatForwardPath] =
  323. NatTranslateForwardUdpEdit;
  324. Mapping->TranslateRoutine[NatReversePath] =
  325. NatTranslateReverseUdpEdit;
  326. } else if (!NAT_EDITOR_RESIZE(Editor)) {
  327. Mapping->TranslateRoutine[NatForwardPath] =
  328. NatTranslateForwardTcpEdit;
  329. Mapping->TranslateRoutine[NatReversePath] =
  330. NatTranslateReverseTcpEdit;
  331. } else {
  332. Mapping->TranslateRoutine[NatForwardPath] =
  333. NatTranslateForwardTcpResize;
  334. Mapping->TranslateRoutine[NatReversePath] =
  335. NatTranslateReverseTcpResize;
  336. }
  337. break;
  338. }
  339. }
  340. KeReleaseSpinLockFromDpcLevel(&EditorLock);
  341. } // Interfacep
  342. if (!FirewallMode) {
  343. //
  344. // Initialize the checksum deltas;
  345. // See RFC1624 for details on the incremental update of the checksum;
  346. //
  347. Mapping->IpChecksumDelta[NatForwardPath] =
  348. (USHORT)~MAPPING_ADDRESS(SourceKey[NatForwardPath]) +
  349. (USHORT)~(MAPPING_ADDRESS(SourceKey[NatForwardPath]) >> 16) +
  350. (USHORT)~MAPPING_ADDRESS(DestinationKey[NatForwardPath]) +
  351. (USHORT)~(MAPPING_ADDRESS(DestinationKey[NatForwardPath]) >> 16) +
  352. (USHORT)MAPPING_ADDRESS(SourceKey[NatReversePath]) +
  353. (USHORT)(MAPPING_ADDRESS(SourceKey[NatReversePath]) >> 16) +
  354. (USHORT)MAPPING_ADDRESS(DestinationKey[NatReversePath]) +
  355. (USHORT)(MAPPING_ADDRESS(DestinationKey[NatReversePath]) >> 16);
  356. Mapping->IpChecksumDelta[NatReversePath] =
  357. (USHORT)MAPPING_ADDRESS(SourceKey[NatForwardPath]) +
  358. (USHORT)(MAPPING_ADDRESS(SourceKey[NatForwardPath]) >> 16) +
  359. (USHORT)MAPPING_ADDRESS(DestinationKey[NatForwardPath]) +
  360. (USHORT)(MAPPING_ADDRESS(DestinationKey[NatForwardPath]) >> 16) +
  361. (USHORT)~MAPPING_ADDRESS(SourceKey[NatReversePath]) +
  362. (USHORT)~(MAPPING_ADDRESS(SourceKey[NatReversePath]) >> 16) +
  363. (USHORT)~MAPPING_ADDRESS(DestinationKey[NatReversePath]) +
  364. (USHORT)~(MAPPING_ADDRESS(DestinationKey[NatReversePath]) >> 16);
  365. Mapping->ProtocolChecksumDelta[NatForwardPath] =
  366. Mapping->IpChecksumDelta[NatForwardPath] +
  367. (USHORT)~MAPPING_PORT(SourceKey[NatForwardPath]) +
  368. (USHORT)~MAPPING_PORT(DestinationKey[NatForwardPath]) +
  369. (USHORT)MAPPING_PORT(SourceKey[NatReversePath]) +
  370. (USHORT)MAPPING_PORT(DestinationKey[NatReversePath]);
  371. Mapping->ProtocolChecksumDelta[NatReversePath] =
  372. Mapping->IpChecksumDelta[NatReversePath] +
  373. (USHORT)MAPPING_PORT(SourceKey[NatForwardPath]) +
  374. (USHORT)MAPPING_PORT(DestinationKey[NatForwardPath]) +
  375. (USHORT)~MAPPING_PORT(SourceKey[NatReversePath]) +
  376. (USHORT)~MAPPING_PORT(DestinationKey[NatReversePath]);
  377. //
  378. // If the mapping has the loopback address as the source on either
  379. // path set NAT_MAPPING_FLAG_CLEAR_DF_BIT. When we change the source
  380. // address of a packet from the loopback address to some other address
  381. // there is the possibility that we'll create an MTU mismatch that
  382. // would result in the packet getting dropped by the stack if the
  383. // DF bit was sent. (Note that since this would occur on the local-send
  384. // path no ICMP error message would be generated.)
  385. //
  386. // Clearing the DF bit for these packets ensures that the stack will
  387. // succeed in sending the packet, though some performance may be
  388. // lost due to the fragmentation.
  389. //
  390. if (MAPPING_ADDRESS(SourceKey[NatForwardPath]) == 0x0100007f ||
  391. MAPPING_ADDRESS(SourceKey[NatReversePath]) == 0x0100007f) {
  392. Mapping->Flags |= NAT_MAPPING_FLAG_CLEAR_DF_BIT;
  393. }
  394. }
  395. //
  396. // Find the insertion points, in the process checking for collisions
  397. //
  398. if (!ForwardInsertionPoint) {
  399. ForwardInsertionPoint = &InsertionPoint1;
  400. if (NatLookupForwardMapping(
  401. DestinationKey[NatForwardPath],
  402. SourceKey[NatForwardPath],
  403. ForwardInsertionPoint
  404. )) {
  405. //
  406. // A collision has been detected.
  407. //
  408. NatCleanupMapping(Mapping);
  409. return STATUS_UNSUCCESSFUL;
  410. }
  411. }
  412. if (!ReverseInsertionPoint) {
  413. ReverseInsertionPoint = &InsertionPoint2;
  414. if (NatLookupReverseMapping(
  415. DestinationKey[NatReversePath],
  416. SourceKey[NatReversePath],
  417. ReverseInsertionPoint
  418. )) {
  419. //
  420. // A collision has been detected.
  421. //
  422. NatCleanupMapping(Mapping);
  423. return STATUS_UNSUCCESSFUL;
  424. }
  425. }
  426. MappingTree[NatForwardPath] =
  427. NatInsertForwardMapping(*ForwardInsertionPoint, Mapping);
  428. MappingTree[NatReversePath] =
  429. NatInsertReverseMapping(*ReverseInsertionPoint, Mapping);
  430. InsertTailList(&MappingList, &Mapping->Link);
  431. InterlockedIncrement(&MappingCount);
  432. *MappingCreated = Mapping;
  433. #if NAT_WMI
  434. //
  435. // Log the creation. Logging always uses public addresses,
  436. // not private.
  437. //
  438. if (!NAT_MAPPING_DO_NOT_LOG(Mapping)) {
  439. if (NAT_MAPPING_INBOUND(Mapping)) {
  440. NatLogConnectionCreation(
  441. MAPPING_ADDRESS(DestinationKey[NatForwardPath]),
  442. MAPPING_ADDRESS(SourceKey[NatForwardPath]),
  443. MAPPING_PORT(DestinationKey[NatForwardPath]),
  444. MAPPING_PORT(SourceKey[NatForwardPath]),
  445. Protocol,
  446. TRUE
  447. );
  448. } else {
  449. NatLogConnectionCreation(
  450. MAPPING_ADDRESS(DestinationKey[NatReversePath]),
  451. MAPPING_ADDRESS(SourceKey[NatReversePath]),
  452. MAPPING_PORT(DestinationKey[NatReversePath]),
  453. MAPPING_PORT(SourceKey[NatReversePath]),
  454. Protocol,
  455. FALSE
  456. );
  457. }
  458. }
  459. #endif
  460. return STATUS_SUCCESS;
  461. } // NatCreateMapping
  462. NTSTATUS
  463. NatDeleteMapping(
  464. PNAT_DYNAMIC_MAPPING Mapping
  465. )
  466. /*++
  467. Routine Description:
  468. Called to delete a mapping from an interface. The initial reference
  469. to the mapping is released, so that cleanup occurs whenever the last
  470. reference is released.
  471. Arguments:
  472. Mapping - the mapping to be deleted.
  473. Return Value:
  474. NTSTATUS - indicates success/failure.
  475. Environment:
  476. Invoked with 'MappingLock' held by the caller.
  477. --*/
  478. {
  479. KIRQL Irql;
  480. PRTL_SPLAY_LINKS SLink;
  481. CALLTRACE(("NatDeleteMapping\n"));
  482. if (NAT_MAPPING_DELETED(Mapping)) { return STATUS_PENDING; }
  483. //
  484. // Mark the mapping as deleted so attempts to reference it
  485. // will fail from now on.
  486. //
  487. Mapping->Flags |= NAT_MAPPING_FLAG_DELETED;
  488. //
  489. // Take the mapping off the list and splay-trees
  490. //
  491. InterlockedDecrement(&MappingCount);
  492. RemoveEntryList(&Mapping->Link);
  493. if (NAT_MAPPING_EXPIRED(Mapping)) {
  494. InterlockedDecrement(&ExpiredMappingCount);
  495. }
  496. SLink = RtlDelete(&Mapping->SLink[NatForwardPath]);
  497. MappingTree[NatForwardPath] =
  498. (SLink
  499. ? CONTAINING_RECORD(SLink,NAT_DYNAMIC_MAPPING,SLink[NatForwardPath])
  500. : NULL);
  501. SLink = RtlDelete(&Mapping->SLink[NatReversePath]);
  502. MappingTree[NatReversePath] =
  503. (SLink
  504. ? CONTAINING_RECORD(SLink,NAT_DYNAMIC_MAPPING,SLink[NatReversePath])
  505. : NULL);
  506. #if NAT_WMI
  507. //
  508. // Log the deletion. Logging always uses public addresses,
  509. // not private.
  510. //
  511. if (!NAT_MAPPING_DO_NOT_LOG(Mapping)) {
  512. if (NAT_MAPPING_INBOUND(Mapping)) {
  513. NatLogConnectionDeletion(
  514. MAPPING_ADDRESS(Mapping->DestinationKey[NatForwardPath]),
  515. MAPPING_ADDRESS(Mapping->SourceKey[NatForwardPath]),
  516. MAPPING_PORT(Mapping->DestinationKey[NatForwardPath]),
  517. MAPPING_PORT(Mapping->SourceKey[NatForwardPath]),
  518. MAPPING_PROTOCOL(Mapping->SourceKey[NatForwardPath]),
  519. TRUE
  520. );
  521. } else {
  522. NatLogConnectionDeletion(
  523. MAPPING_ADDRESS(Mapping->DestinationKey[NatReversePath]),
  524. MAPPING_ADDRESS(Mapping->SourceKey[NatReversePath]),
  525. MAPPING_PORT(Mapping->DestinationKey[NatReversePath]),
  526. MAPPING_PORT(Mapping->SourceKey[NatReversePath]),
  527. MAPPING_PROTOCOL(Mapping->SourceKey[NatForwardPath]),
  528. FALSE
  529. );
  530. }
  531. }
  532. #endif
  533. if (InterlockedDecrement(&Mapping->ReferenceCount) > 0) {
  534. //
  535. // The mapping is in use, defer final cleanup
  536. //
  537. return STATUS_PENDING;
  538. }
  539. //
  540. // Go ahead with final cleanup
  541. //
  542. NatCleanupMapping(Mapping);
  543. return STATUS_SUCCESS;
  544. } // NatDeleteMapping
  545. PNAT_DYNAMIC_MAPPING
  546. NatDestinationLookupForwardMapping(
  547. ULONG64 DestinationKey
  548. )
  549. /*++
  550. Routine Description:
  551. This routine retrieves the mapping which matches the given destination
  552. key. The source key of the mapping is not examined.
  553. Arguments:
  554. DestinationKey - the primary key used to search for a mapping.
  555. Return Value:
  556. PNAT_DYNAMIC_MAPPING - the item found, or NULL if no match is found
  557. Environment:
  558. Invoked with 'MappingLock' held by the caller.
  559. --*/
  560. {
  561. PNAT_DYNAMIC_MAPPING Root;
  562. PNAT_DYNAMIC_MAPPING Mapping;
  563. PRTL_SPLAY_LINKS SLink;
  564. TRACE(PER_PACKET, ("NatDestinationLookupForwardMapping\n"));
  565. //
  566. // First look in the mapping-cache
  567. //
  568. if ((Mapping =
  569. (PNAT_DYNAMIC_MAPPING)ProbeCache(
  570. MappingCache[NatForwardPath],
  571. (ULONG)DestinationKey
  572. )) &&
  573. Mapping->DestinationKey[NatForwardPath] == DestinationKey
  574. ) {
  575. TRACE(PER_PACKET, ("NatDestinationLookupForwardMapping: cache hit\n"));
  576. return Mapping;
  577. }
  578. //
  579. // Search the full tree
  580. //
  581. Root = MappingTree[NatForwardPath];
  582. for (SLink = !Root ? NULL : &Root->SLink[NatForwardPath]; SLink; ) {
  583. Mapping =
  584. CONTAINING_RECORD(SLink,NAT_DYNAMIC_MAPPING,SLink[NatForwardPath]);
  585. if (DestinationKey < Mapping->DestinationKey[NatForwardPath]) {
  586. SLink = RtlLeftChild(SLink);
  587. continue;
  588. } else if (DestinationKey > Mapping->DestinationKey[NatForwardPath]) {
  589. SLink = RtlRightChild(SLink);
  590. continue;
  591. }
  592. //
  593. // We found the mapping. We don't update the cache for partial
  594. // lookups.
  595. //
  596. return Mapping;
  597. }
  598. //
  599. // No partial match was found
  600. //
  601. return NULL;
  602. } // NatDestinationLookupForwardMapping
  603. PNAT_DYNAMIC_MAPPING
  604. NatDestinationLookupReverseMapping(
  605. ULONG64 DestinationKey
  606. )
  607. /*++
  608. Routine Description:
  609. This routine retrieves the mapping which matches the given destination
  610. key. The source key of the mapping is not examined.
  611. Arguments:
  612. DestinationKey - the primary key used to search for a mapping.
  613. Return Value:
  614. PNAT_DYNAMIC_MAPPING - the item found, or NULL if no match is found
  615. Environment:
  616. Invoked with 'MappingLock' held by the caller.
  617. --*/
  618. {
  619. PNAT_DYNAMIC_MAPPING Root;
  620. PNAT_DYNAMIC_MAPPING Mapping;
  621. PRTL_SPLAY_LINKS SLink;
  622. TRACE(PER_PACKET, ("NatDestinationLookupReverseMapping\n"));
  623. //
  624. // First look in the mapping-cache
  625. //
  626. if ((Mapping =
  627. (PNAT_DYNAMIC_MAPPING)ProbeCache(
  628. MappingCache[NatReversePath],
  629. (ULONG)DestinationKey
  630. )) &&
  631. Mapping->DestinationKey[NatReversePath] == DestinationKey
  632. ) {
  633. TRACE(PER_PACKET, ("NatDestinationLookupReverseMapping: cache hit\n"));
  634. return Mapping;
  635. }
  636. //
  637. // Search the full tree
  638. //
  639. Root = MappingTree[NatReversePath];
  640. for (SLink = !Root ? NULL : &Root->SLink[NatReversePath]; SLink; ) {
  641. Mapping =
  642. CONTAINING_RECORD(SLink,NAT_DYNAMIC_MAPPING,SLink[NatReversePath]);
  643. if (DestinationKey < Mapping->DestinationKey[NatReversePath]) {
  644. SLink = RtlLeftChild(SLink);
  645. continue;
  646. } else if (DestinationKey > Mapping->DestinationKey[NatReversePath]) {
  647. SLink = RtlRightChild(SLink);
  648. continue;
  649. }
  650. //
  651. // We found the mapping. We don't update the cache for partial
  652. // lookups.
  653. //
  654. return Mapping;
  655. }
  656. //
  657. // No partial match was found
  658. //
  659. return NULL;
  660. } // NatDestinationLookupReverseMapping
  661. VOID
  662. NatInitializeMappingManagement(
  663. VOID
  664. )
  665. /*++
  666. Routine Description:
  667. This routine is invoked to initialize the NAT's mapping-management module.
  668. Arguments:
  669. none.
  670. Return Value:
  671. none.
  672. --*/
  673. {
  674. CALLTRACE(("NatInitializeMappingManagement\n"));
  675. MappingCount = 0;
  676. ExpiredMappingCount = 0;
  677. InitializeListHead(&MappingList);
  678. KeInitializeSpinLock(&MappingLock);
  679. MappingTree[NatForwardPath] = NULL;
  680. MappingTree[NatReversePath] = NULL;
  681. InitializeCache(MappingCache[NatForwardPath]);
  682. InitializeCache(MappingCache[NatReversePath]);
  683. ExInitializeNPagedLookasideList(
  684. &MappingLookasideList,
  685. NatAllocateFunction,
  686. NULL,
  687. 0,
  688. sizeof(NAT_DYNAMIC_MAPPING),
  689. NAT_TAG_MAPPING,
  690. MAPPING_LOOKASIDE_DEPTH
  691. );
  692. } // NatInitializeMappingManagement
  693. PNAT_DYNAMIC_MAPPING
  694. NatInsertForwardMapping(
  695. PNAT_DYNAMIC_MAPPING Parent,
  696. PNAT_DYNAMIC_MAPPING Mapping
  697. )
  698. /*++
  699. Routine Description:
  700. This routine inserts a mapping into the tree.
  701. Arguments:
  702. Parent - the node to be the parent for the new mapping.
  703. If NULL, the new mapping becomes the root.
  704. Mapping - the new mapping to be inserted.
  705. Return Value:
  706. PNAT_DYNAMIC_MAPPING - The new root of the tree.
  707. If insertion fails, returns NULL.
  708. Environment:
  709. Invoked with 'MappingLock' held by the caller.
  710. --*/
  711. {
  712. PRTL_SPLAY_LINKS Root;
  713. CALLTRACE(("NatInsertForwardMapping\n"));
  714. if (!Parent) {
  715. TRACE(MAPPING, ("NatInsertForwardMapping: inserting as root\n"));
  716. return Mapping;
  717. }
  718. //
  719. // Insert as left or right child
  720. //
  721. if (Mapping->DestinationKey[NatForwardPath] <
  722. Parent->DestinationKey[NatForwardPath]) {
  723. RtlInsertAsLeftChild(
  724. &Parent->SLink[NatForwardPath], &Mapping->SLink[NatForwardPath]
  725. );
  726. } else if (Mapping->DestinationKey[NatForwardPath] >
  727. Parent->DestinationKey[NatForwardPath]) {
  728. RtlInsertAsRightChild(
  729. &Parent->SLink[NatForwardPath], &Mapping->SLink[NatForwardPath]
  730. );
  731. } else {
  732. //
  733. // Primary keys are equal; check secondary keys
  734. //
  735. if (Mapping->SourceKey[NatForwardPath] <
  736. Parent->SourceKey[NatForwardPath]) {
  737. RtlInsertAsLeftChild(
  738. &Parent->SLink[NatForwardPath], &Mapping->SLink[NatForwardPath]
  739. );
  740. } else if (Mapping->SourceKey[NatForwardPath] >
  741. Parent->SourceKey[NatForwardPath]) {
  742. RtlInsertAsRightChild(
  743. &Parent->SLink[NatForwardPath], &Mapping->SLink[NatForwardPath]
  744. );
  745. } else {
  746. //
  747. // Secondary keys equal too; fail.
  748. //
  749. ERROR((
  750. "NatInsertForwardMapping: collision 0x%016I64X,0x%016I64X\n",
  751. Mapping->DestinationKey[NatForwardPath],
  752. Mapping->SourceKey[NatForwardPath]
  753. ));
  754. return NULL;
  755. }
  756. }
  757. //
  758. // Splay the new node and return the resulting root.
  759. //
  760. Root = RtlSplay(&Mapping->SLink[NatForwardPath]);
  761. return CONTAINING_RECORD(Root, NAT_DYNAMIC_MAPPING, SLink[NatForwardPath]);
  762. } // NatInsertForwardMapping
  763. PNAT_DYNAMIC_MAPPING
  764. NatInsertReverseMapping(
  765. PNAT_DYNAMIC_MAPPING Parent,
  766. PNAT_DYNAMIC_MAPPING Mapping
  767. )
  768. /*++
  769. Routine Description:
  770. This routine inserts a mapping into the tree.
  771. Arguments:
  772. Parent - the node to be the parent for the new mapping.
  773. If NULL, the new mapping becomes the root.
  774. Mapping - the new mapping to be inserted.
  775. Return Value:
  776. PNAT_DYNAMIC_MAPPING - The new root of the tree.
  777. If insertion fails, returns NULL.
  778. Environment:
  779. Invoked with 'MappingLock' held by the caller.
  780. --*/
  781. {
  782. PRTL_SPLAY_LINKS Root;
  783. CALLTRACE(("NatInsertReverseMapping\n"));
  784. if (!Parent) {
  785. TRACE(MAPPING, ("NatInsertReverseMapping: inserting as root\n"));
  786. return Mapping;
  787. }
  788. //
  789. // Insert as left or right child
  790. //
  791. if (Mapping->DestinationKey[NatReversePath] <
  792. Parent->DestinationKey[NatReversePath]) {
  793. RtlInsertAsLeftChild(
  794. &Parent->SLink[NatReversePath], &Mapping->SLink[NatReversePath]
  795. );
  796. } else if (Mapping->DestinationKey[NatReversePath] >
  797. Parent->DestinationKey[NatReversePath]) {
  798. RtlInsertAsRightChild(
  799. &Parent->SLink[NatReversePath], &Mapping->SLink[NatReversePath]
  800. );
  801. } else {
  802. //
  803. // Primary keys are equal; check secondary keys
  804. //
  805. if (Mapping->SourceKey[NatReversePath] <
  806. Parent->SourceKey[NatReversePath]) {
  807. RtlInsertAsLeftChild(
  808. &Parent->SLink[NatReversePath], &Mapping->SLink[NatReversePath]
  809. );
  810. } else if (Mapping->SourceKey[NatReversePath] >
  811. Parent->SourceKey[NatReversePath]) {
  812. RtlInsertAsRightChild(
  813. &Parent->SLink[NatReversePath], &Mapping->SLink[NatReversePath]
  814. );
  815. } else {
  816. //
  817. // Secondary keys equal too; fail.
  818. //
  819. ERROR((
  820. "NatInsertReverseMapping: collision 0x%016I64X,0x%016I64X\n",
  821. Mapping->DestinationKey[NatReversePath],
  822. Mapping->SourceKey[NatReversePath]
  823. ));
  824. return NULL;
  825. }
  826. }
  827. //
  828. // Splay the new node and return the resulting root.
  829. //
  830. Root = RtlSplay(&Mapping->SLink[NatReversePath]);
  831. return CONTAINING_RECORD(Root, NAT_DYNAMIC_MAPPING, SLink[NatReversePath]);
  832. } // NatInsertReverseMapping
  833. NTSTATUS
  834. NatLookupAndQueryInformationMapping(
  835. UCHAR Protocol,
  836. ULONG DestinationAddress,
  837. USHORT DestinationPort,
  838. ULONG SourceAddress,
  839. USHORT SourcePort,
  840. OUT PVOID Information,
  841. ULONG InformationLength,
  842. NAT_SESSION_MAPPING_INFORMATION_CLASS InformationClass
  843. )
  844. /*++
  845. Routine Description:
  846. This routine attempts to locate a particular session mapping using either
  847. its forward key or reverse key, and to query information for the mapping,
  848. if found.
  849. Arguments:
  850. Protocol - the IP protocol for the mapping to be located
  851. Destination* - the destination endpoint for the mapping
  852. Source* - the source endpoint for the mapping
  853. Information - on output, receives the requested information
  854. InformationLength - contains the length of the buffer at 'Information'
  855. InformationClass - specifies
  856. Return Value:
  857. NTSTATUS - indicates success/failure.
  858. --*/
  859. {
  860. ULONG64 DestinationKey;
  861. KIRQL Irql;
  862. PNAT_DYNAMIC_MAPPING Mapping;
  863. ULONG64 SourceKey;
  864. NTSTATUS status;
  865. CALLTRACE(("NatLookupAndQueryInformationMapping\n"));
  866. //
  867. // Construct the destination and source key for the mapping,
  868. // and attempt to retrieve it. We try all four possible combinations
  869. // of these keys since the caller can't be guaranteed to know which
  870. // direction the session was headed when it was initiated.
  871. //
  872. MAKE_MAPPING_KEY(
  873. DestinationKey,
  874. Protocol,
  875. DestinationAddress,
  876. DestinationPort
  877. );
  878. MAKE_MAPPING_KEY(
  879. SourceKey,
  880. Protocol,
  881. SourceAddress,
  882. SourcePort
  883. );
  884. KeAcquireSpinLock(&MappingLock, &Irql);
  885. if (!(Mapping = NatLookupForwardMapping(DestinationKey, SourceKey, NULL)) &&
  886. !(Mapping = NatLookupReverseMapping(DestinationKey, SourceKey, NULL)) &&
  887. !(Mapping = NatLookupForwardMapping(SourceKey, DestinationKey, NULL)) &&
  888. !(Mapping = NatLookupReverseMapping(SourceKey, DestinationKey, NULL))) {
  889. KeReleaseSpinLock(&MappingLock, Irql);
  890. return STATUS_UNSUCCESSFUL;
  891. }
  892. NatReferenceMapping(Mapping);
  893. KeReleaseSpinLock(&MappingLock, Irql);
  894. //
  895. // Attempt to supply the information requested about the mapping.
  896. //
  897. switch(InformationClass) {
  898. case NatKeySessionMappingInformation: {
  899. ((PIP_NAT_SESSION_MAPPING_KEY)Information)->DestinationAddress =
  900. MAPPING_ADDRESS(Mapping->DestinationKey[NatForwardPath]);
  901. ((PIP_NAT_SESSION_MAPPING_KEY)Information)->DestinationPort =
  902. MAPPING_PORT(Mapping->DestinationKey[NatForwardPath]);
  903. ((PIP_NAT_SESSION_MAPPING_KEY)Information)->SourceAddress =
  904. MAPPING_ADDRESS(Mapping->SourceKey[NatForwardPath]);
  905. ((PIP_NAT_SESSION_MAPPING_KEY)Information)->SourcePort =
  906. MAPPING_PORT(Mapping->SourceKey[NatForwardPath]);
  907. ((PIP_NAT_SESSION_MAPPING_KEY)Information)->NewDestinationAddress =
  908. MAPPING_ADDRESS(Mapping->SourceKey[NatReversePath]);
  909. ((PIP_NAT_SESSION_MAPPING_KEY)Information)->NewDestinationPort =
  910. MAPPING_PORT(Mapping->SourceKey[NatReversePath]);
  911. ((PIP_NAT_SESSION_MAPPING_KEY)Information)->NewSourceAddress =
  912. MAPPING_ADDRESS(Mapping->DestinationKey[NatReversePath]);
  913. ((PIP_NAT_SESSION_MAPPING_KEY)Information)->NewSourcePort =
  914. MAPPING_PORT(Mapping->DestinationKey[NatReversePath]);
  915. status = STATUS_SUCCESS;
  916. break;
  917. }
  918. #if _WIN32_WINNT > 0x0500
  919. case NatKeySessionMappingExInformation: {
  920. ((PIP_NAT_SESSION_MAPPING_KEY_EX)Information)->DestinationAddress =
  921. MAPPING_ADDRESS(Mapping->DestinationKey[NatForwardPath]);
  922. ((PIP_NAT_SESSION_MAPPING_KEY_EX)Information)->DestinationPort =
  923. MAPPING_PORT(Mapping->DestinationKey[NatForwardPath]);
  924. ((PIP_NAT_SESSION_MAPPING_KEY_EX)Information)->SourceAddress =
  925. MAPPING_ADDRESS(Mapping->SourceKey[NatForwardPath]);
  926. ((PIP_NAT_SESSION_MAPPING_KEY_EX)Information)->SourcePort =
  927. MAPPING_PORT(Mapping->SourceKey[NatForwardPath]);
  928. ((PIP_NAT_SESSION_MAPPING_KEY_EX)Information)->NewDestinationAddress =
  929. MAPPING_ADDRESS(Mapping->SourceKey[NatReversePath]);
  930. ((PIP_NAT_SESSION_MAPPING_KEY_EX)Information)->NewDestinationPort =
  931. MAPPING_PORT(Mapping->SourceKey[NatReversePath]);
  932. ((PIP_NAT_SESSION_MAPPING_KEY_EX)Information)->NewSourceAddress =
  933. MAPPING_ADDRESS(Mapping->DestinationKey[NatReversePath]);
  934. ((PIP_NAT_SESSION_MAPPING_KEY_EX)Information)->NewSourcePort =
  935. MAPPING_PORT(Mapping->DestinationKey[NatReversePath]);
  936. //
  937. // If this mapping was created by the Redirect director, attempt
  938. // to supply to interface that the redirect was triggered on
  939. //
  940. if (Mapping->Director ==
  941. (PNAT_DIRECTOR)RedirectRegisterDirector.DirectorHandle
  942. && Mapping->DirectorContext != NULL) {
  943. ((PIP_NAT_SESSION_MAPPING_KEY_EX)Information)->AdapterIndex =
  944. ((PNAT_REDIRECT)Mapping->DirectorContext)->RestrictAdapterIndex;
  945. } else {
  946. ((PIP_NAT_SESSION_MAPPING_KEY_EX)Information)->AdapterIndex =
  947. INVALID_IF_INDEX;
  948. }
  949. status = STATUS_SUCCESS;
  950. break;
  951. }
  952. #endif
  953. case NatStatisticsSessionMappingInformation: {
  954. NatQueryInformationMapping(
  955. Mapping,
  956. NULL,
  957. NULL,
  958. NULL,
  959. NULL,
  960. NULL,
  961. NULL,
  962. NULL,
  963. (PIP_NAT_SESSION_MAPPING_STATISTICS)Information
  964. );
  965. status = STATUS_SUCCESS;
  966. break;
  967. }
  968. default: {
  969. status = STATUS_INVALID_PARAMETER;
  970. break;
  971. }
  972. }
  973. NatDereferenceMapping(Mapping);
  974. return status;
  975. } // NatLookupAndQueryInformationMapping
  976. PNAT_DYNAMIC_MAPPING
  977. NatLookupForwardMapping(
  978. ULONG64 DestinationKey,
  979. ULONG64 SourceKey,
  980. PNAT_DYNAMIC_MAPPING* InsertionPoint
  981. )
  982. /*++
  983. Routine Description:
  984. This routine retrieves the mapping which matches the given key.
  985. If the item is not found, the caller is supplied with the point
  986. at which a new item should be inserted for the given key.
  987. Arguments:
  988. DestinationKey - the primary key used to search for a mapping.
  989. SourceKey - the secondary search key.
  990. InsertionPoint - receives point of insertion in case no match is found.
  991. Return Value:
  992. PNAT_DYNAMIC_MAPPING - The item found, or NULL if no exact match is found.
  993. Environment:
  994. Invoked with 'MappingLock' held by the caller.
  995. --*/
  996. {
  997. PNAT_DYNAMIC_MAPPING Root;
  998. PNAT_DYNAMIC_MAPPING Mapping;
  999. PNAT_DYNAMIC_MAPPING Parent = NULL;
  1000. PRTL_SPLAY_LINKS SLink;
  1001. TRACE(PER_PACKET, ("NatLookupForwardMapping\n"));
  1002. //
  1003. // First look in the mapping-cache
  1004. //
  1005. if ((Mapping =
  1006. (PNAT_DYNAMIC_MAPPING)ProbeCache(
  1007. MappingCache[NatForwardPath],
  1008. (ULONG)DestinationKey
  1009. )) &&
  1010. Mapping->DestinationKey[NatForwardPath] == DestinationKey &&
  1011. Mapping->SourceKey[NatForwardPath] == SourceKey
  1012. ) {
  1013. TRACE(PER_PACKET, ("NatLookupForwardMapping: cache hit\n"));
  1014. return Mapping;
  1015. }
  1016. //
  1017. // Search the full tree
  1018. //
  1019. Root = MappingTree[NatForwardPath];
  1020. for (SLink = !Root ? NULL : &Root->SLink[NatForwardPath]; SLink; ) {
  1021. Mapping =
  1022. CONTAINING_RECORD(SLink,NAT_DYNAMIC_MAPPING,SLink[NatForwardPath]);
  1023. if (DestinationKey < Mapping->DestinationKey[NatForwardPath]) {
  1024. Parent = Mapping;
  1025. SLink = RtlLeftChild(SLink);
  1026. continue;
  1027. } else if (DestinationKey > Mapping->DestinationKey[NatForwardPath]) {
  1028. Parent = Mapping;
  1029. SLink = RtlRightChild(SLink);
  1030. continue;
  1031. }
  1032. //
  1033. // Primary keys match; check the secondary keys.
  1034. //
  1035. if (SourceKey < Mapping->SourceKey[NatForwardPath]) {
  1036. Parent = Mapping;
  1037. SLink = RtlLeftChild(SLink);
  1038. continue;
  1039. } else if (SourceKey > Mapping->SourceKey[NatForwardPath]) {
  1040. Parent = Mapping;
  1041. SLink = RtlRightChild(SLink);
  1042. continue;
  1043. }
  1044. //
  1045. // Secondary keys match; we got it.
  1046. //
  1047. UpdateCache(
  1048. MappingCache[NatForwardPath],
  1049. (ULONG)DestinationKey,
  1050. (PVOID)Mapping
  1051. );
  1052. return Mapping;
  1053. }
  1054. //
  1055. // We didn't get it; tell the caller where to insert it.
  1056. //
  1057. if (InsertionPoint) { *InsertionPoint = Parent; }
  1058. return NULL;
  1059. } // NatLookupForwardMapping
  1060. PNAT_DYNAMIC_MAPPING
  1061. NatLookupReverseMapping(
  1062. ULONG64 DestinationKey,
  1063. ULONG64 SourceKey,
  1064. PNAT_DYNAMIC_MAPPING* InsertionPoint
  1065. )
  1066. /*++
  1067. Routine Description:
  1068. This routine retrieves the mapping which matches the given key.
  1069. If the item is not found, the caller is supplied with the point
  1070. at which a new item should be inserted for the given key.
  1071. Arguments:
  1072. DestinationKey - the primary key used to search for a mapping.
  1073. SourceKey - the secondary search key.
  1074. InsertionPoint - receives point of insertion in case no match is found.
  1075. Return Value:
  1076. PNAT_DYNAMIC_MAPPING - The item found, or NULL if no exact match is found.
  1077. Environment:
  1078. Invoked with 'MappingLock' held by the caller.
  1079. --*/
  1080. {
  1081. PNAT_DYNAMIC_MAPPING Root;
  1082. PNAT_DYNAMIC_MAPPING Mapping;
  1083. PNAT_DYNAMIC_MAPPING Parent = NULL;
  1084. PRTL_SPLAY_LINKS SLink;
  1085. TRACE(PER_PACKET, ("NatLookupReverseMapping\n"));
  1086. //
  1087. // First look in the mapping-cache
  1088. //
  1089. if ((Mapping =
  1090. (PNAT_DYNAMIC_MAPPING)ProbeCache(
  1091. MappingCache[NatReversePath],
  1092. (ULONG)DestinationKey
  1093. )) &&
  1094. Mapping->DestinationKey[NatReversePath] == DestinationKey &&
  1095. Mapping->SourceKey[NatReversePath] == SourceKey
  1096. ) {
  1097. TRACE(PER_PACKET, ("NatLookupReverseMapping: cache hit\n"));
  1098. return Mapping;
  1099. }
  1100. //
  1101. // Search the full tree
  1102. //
  1103. Root = MappingTree[NatReversePath];
  1104. for (SLink = !Root ? NULL : &Root->SLink[NatReversePath]; SLink; ) {
  1105. Mapping =
  1106. CONTAINING_RECORD(SLink,NAT_DYNAMIC_MAPPING,SLink[NatReversePath]);
  1107. if (DestinationKey < Mapping->DestinationKey[NatReversePath]) {
  1108. Parent = Mapping;
  1109. SLink = RtlLeftChild(SLink);
  1110. continue;
  1111. } else if (DestinationKey > Mapping->DestinationKey[NatReversePath]) {
  1112. Parent = Mapping;
  1113. SLink = RtlRightChild(SLink);
  1114. continue;
  1115. }
  1116. //
  1117. // Primary keys match; check the secondary keys.
  1118. //
  1119. if (SourceKey < Mapping->SourceKey[NatReversePath]) {
  1120. Parent = Mapping;
  1121. SLink = RtlLeftChild(SLink);
  1122. continue;
  1123. } else if (SourceKey > Mapping->SourceKey[NatReversePath]) {
  1124. Parent = Mapping;
  1125. SLink = RtlRightChild(SLink);
  1126. continue;
  1127. }
  1128. //
  1129. // Secondary keys match; we got it.
  1130. //
  1131. UpdateCache(
  1132. MappingCache[NatReversePath],
  1133. (ULONG)DestinationKey,
  1134. (PVOID)Mapping
  1135. );
  1136. return Mapping;
  1137. }
  1138. //
  1139. // We didn't get it; tell the caller where to insert it.
  1140. //
  1141. if (InsertionPoint) { *InsertionPoint = Parent; }
  1142. return NULL;
  1143. } // NatLookupReverseMapping
  1144. VOID
  1145. NatQueryInformationMapping(
  1146. IN PNAT_DYNAMIC_MAPPING Mapping,
  1147. OUT PUCHAR Protocol OPTIONAL,
  1148. OUT PULONG PrivateAddress OPTIONAL,
  1149. OUT PUSHORT PrivatePort OPTIONAL,
  1150. OUT PULONG RemoteAddress OPTIONAL,
  1151. OUT PUSHORT RemotePort OPTIONAL,
  1152. OUT PULONG PublicAddress OPTIONAL,
  1153. OUT PUSHORT PublicPort OPTIONAL,
  1154. OUT PIP_NAT_SESSION_MAPPING_STATISTICS Statistics OPTIONAL
  1155. )
  1156. /*++
  1157. Routine Description:
  1158. This routine is invoked to retrieve information about a mapping.
  1159. This is used, for instance, to extract public/private/remote information
  1160. from the mapping-keys of mappings associated with boundary interfaces.
  1161. Arguments:
  1162. Mapping - the mapping for which information is required
  1163. Protocol - receives the mapping's protocol
  1164. Private* - receive information about the private endpoint
  1165. Remote* - receive information about the remote endpoint
  1166. Public* - receive information about the public endpoint
  1167. Statistics - receives the mapping's statistics
  1168. Return Value:
  1169. none.
  1170. Environment:
  1171. Invoked with 'MappingLock' held by the caller.
  1172. --*/
  1173. {
  1174. IP_NAT_PATH ForwardPath =
  1175. NAT_MAPPING_INBOUND(Mapping) ? NatReversePath : NatForwardPath;
  1176. IP_NAT_PATH ReversePath =
  1177. NAT_MAPPING_INBOUND(Mapping) ? NatForwardPath : NatReversePath;
  1178. CALLTRACE(("NatQueryInformationMapping\n"));
  1179. if (Protocol) {
  1180. *Protocol = MAPPING_PROTOCOL(Mapping->SourceKey[ForwardPath]);
  1181. }
  1182. if (PrivateAddress) {
  1183. *PrivateAddress = MAPPING_ADDRESS(Mapping->SourceKey[ForwardPath]);
  1184. }
  1185. if (PrivatePort) {
  1186. *PrivatePort = MAPPING_PORT(Mapping->SourceKey[ForwardPath]);
  1187. }
  1188. if (PublicAddress) {
  1189. *PublicAddress = MAPPING_ADDRESS(Mapping->DestinationKey[ReversePath]);
  1190. }
  1191. if (PublicPort) {
  1192. *PublicPort = MAPPING_PORT(Mapping->DestinationKey[ReversePath]);
  1193. }
  1194. if (RemoteAddress) {
  1195. *RemoteAddress = MAPPING_ADDRESS(Mapping->DestinationKey[ForwardPath]);
  1196. }
  1197. if (RemotePort) {
  1198. *RemotePort = MAPPING_PORT(Mapping->DestinationKey[ForwardPath]);
  1199. }
  1200. if (Statistics) {
  1201. NatUpdateStatisticsMapping(Mapping); *Statistics = Mapping->Statistics;
  1202. }
  1203. } // NatQueryInformationMapping
  1204. NTSTATUS
  1205. NatQueryInterfaceMappingTable(
  1206. IN PIP_NAT_ENUMERATE_SESSION_MAPPINGS InputBuffer,
  1207. IN PIP_NAT_ENUMERATE_SESSION_MAPPINGS OutputBuffer,
  1208. IN PULONG OutputBufferLength
  1209. )
  1210. /*++
  1211. Routine Description:
  1212. This routine is used for enumerating the session-mappings.
  1213. Enumeration makes use of a context structure which is passed
  1214. in with each enumeration attempt. The context structure
  1215. is updated each time with the key of the next mapping to be enumerated.
  1216. Arguments:
  1217. InputBuffer - supplies context information for the information
  1218. OutputBuffer - receives the result of the enumeration
  1219. OutputBufferLength - size of the i/o buffer
  1220. Return Value:
  1221. STATUS_SUCCESS if successful, error code otherwise.
  1222. --*/
  1223. {
  1224. PULONG Context;
  1225. ULONG Count;
  1226. LONG64 CurrentTime;
  1227. ULONG64 DestinationKey;
  1228. ULONG i;
  1229. LONG64 IdleTime;
  1230. PNAT_INTERFACE Interfacep;
  1231. KIRQL Irql;
  1232. PLIST_ENTRY Link;
  1233. PNAT_DYNAMIC_MAPPING Mapping;
  1234. ULONG64 SourceKey;
  1235. NTSTATUS status;
  1236. PIP_NAT_SESSION_MAPPING Table;
  1237. CALLTRACE(("NatQueryInterfaceMappingTable\n"));
  1238. KeAcquireSpinLock(&MappingLock, &Irql);
  1239. KeAcquireSpinLockAtDpcLevel(&InterfaceLock);
  1240. Interfacep = NatLookupInterface(InputBuffer->Index, NULL);
  1241. if (!Interfacep) {
  1242. KeReleaseSpinLockFromDpcLevel(&InterfaceLock);
  1243. KeReleaseSpinLock(&MappingLock, Irql);
  1244. return STATUS_INVALID_PARAMETER;
  1245. }
  1246. //
  1247. // See if this is a new enumeration or a continuation of an old one.
  1248. //
  1249. Context = InputBuffer->EnumerateContext;
  1250. if (!Context[0]) {
  1251. //
  1252. // This is a new enumeration. We start with the first item
  1253. // in the interface's list of mappings
  1254. //
  1255. Mapping =
  1256. IsListEmpty(&Interfacep->MappingList)
  1257. ? NULL
  1258. : CONTAINING_RECORD(
  1259. Interfacep->MappingList.Flink,
  1260. NAT_DYNAMIC_MAPPING,
  1261. InterfaceLink
  1262. );
  1263. } else {
  1264. //
  1265. // This is a continuation. The context therefore contains
  1266. // the keys for the next mapping, in the fields
  1267. // Context[0-1] and Context[2-3] respectively
  1268. //
  1269. DestinationKey = MAKE_LONG64(Context[0], Context[1]);
  1270. SourceKey = MAKE_LONG64(Context[2], Context[3]);
  1271. Mapping =
  1272. NatLookupForwardMapping(
  1273. DestinationKey,
  1274. SourceKey,
  1275. NULL
  1276. );
  1277. if (Mapping && !Mapping->Interfacep) { Mapping = NULL; }
  1278. }
  1279. if (!Mapping) {
  1280. OutputBuffer->EnumerateCount = 0;
  1281. OutputBuffer->EnumerateContext[0] = 0;
  1282. OutputBuffer->EnumerateTotalHint = MappingCount;
  1283. *OutputBufferLength =
  1284. FIELD_OFFSET(IP_NAT_ENUMERATE_SESSION_MAPPINGS, EnumerateTable);
  1285. KeReleaseSpinLockFromDpcLevel(&InterfaceLock);
  1286. KeReleaseSpinLock(&MappingLock, Irql);
  1287. return STATUS_SUCCESS;
  1288. }
  1289. KeReleaseSpinLockFromDpcLevel(&MappingLock);
  1290. //
  1291. // Compute the maximum number of mappings we can store
  1292. //
  1293. Count =
  1294. *OutputBufferLength -
  1295. FIELD_OFFSET(IP_NAT_ENUMERATE_SESSION_MAPPINGS, EnumerateTable);
  1296. Count /= sizeof(IP_NAT_SESSION_MAPPING);
  1297. //
  1298. // Walk the list storing mappings in the caller's buffer
  1299. //
  1300. Table = OutputBuffer->EnumerateTable;
  1301. KeQueryTickCount((PLARGE_INTEGER)&CurrentTime);
  1302. for (i = 0, Link = &Mapping->InterfaceLink;
  1303. i < Count && Link != &Interfacep->MappingList;
  1304. i++, Link = Link->Flink
  1305. ) {
  1306. Mapping = CONTAINING_RECORD(Link, NAT_DYNAMIC_MAPPING, InterfaceLink);
  1307. NatQueryInformationMapping(
  1308. Mapping,
  1309. &Table[i].Protocol,
  1310. &Table[i].PrivateAddress,
  1311. &Table[i].PrivatePort,
  1312. &Table[i].RemoteAddress,
  1313. &Table[i].RemotePort,
  1314. &Table[i].PublicAddress,
  1315. &Table[i].PublicPort,
  1316. NULL
  1317. );
  1318. Table[i].Direction =
  1319. NAT_MAPPING_INBOUND(Mapping)
  1320. ? NatInboundDirection : NatOutboundDirection;
  1321. IdleTime = CurrentTime - Mapping->LastAccessTime;
  1322. Table[i].IdleTime = (ULONG)TICKS_TO_SECONDS(IdleTime);
  1323. }
  1324. //
  1325. // The enumeration is over; update the output structure
  1326. //
  1327. *OutputBufferLength =
  1328. i * sizeof(IP_NAT_SESSION_MAPPING) +
  1329. FIELD_OFFSET(IP_NAT_ENUMERATE_SESSION_MAPPINGS, EnumerateTable);
  1330. OutputBuffer->EnumerateCount = i;
  1331. OutputBuffer->EnumerateTotalHint = MappingCount;
  1332. if (Link == &Interfacep->MappingList) {
  1333. //
  1334. // We reached the end of the mapping list
  1335. //
  1336. OutputBuffer->EnumerateContext[0] = 0;
  1337. } else {
  1338. //
  1339. // Save the continuation context
  1340. //
  1341. Mapping =
  1342. CONTAINING_RECORD(
  1343. Link, NAT_DYNAMIC_MAPPING, InterfaceLink
  1344. );
  1345. OutputBuffer->EnumerateContext[0] =
  1346. (ULONG)Mapping->DestinationKey[NatForwardPath];
  1347. OutputBuffer->EnumerateContext[1] =
  1348. (ULONG)(Mapping->DestinationKey[NatForwardPath] >> 32);
  1349. OutputBuffer->EnumerateContext[2] =
  1350. (ULONG)Mapping->SourceKey[NatForwardPath];
  1351. OutputBuffer->EnumerateContext[3] =
  1352. (ULONG)(Mapping->SourceKey[NatForwardPath] >> 32);
  1353. }
  1354. KeReleaseSpinLock(&InterfaceLock, Irql);
  1355. return STATUS_SUCCESS;
  1356. } // NatQueryInterfaceMappingTable
  1357. NTSTATUS
  1358. NatQueryMappingTable(
  1359. IN PIP_NAT_ENUMERATE_SESSION_MAPPINGS InputBuffer,
  1360. IN PIP_NAT_ENUMERATE_SESSION_MAPPINGS OutputBuffer,
  1361. IN PULONG OutputBufferLength
  1362. )
  1363. /*++
  1364. Routine Description:
  1365. This routine is used for enumerating the session-mappings.
  1366. Arguments:
  1367. InputBuffer - supplies context information for the information
  1368. OutputBuffer - receives the result of the enumeration
  1369. OutputBufferLength - size of the i/o buffer
  1370. Return Value:
  1371. STATUS_SUCCESS if successful, error code otherwise.
  1372. --*/
  1373. {
  1374. PULONG Context;
  1375. ULONG Count;
  1376. LONG64 CurrentTime;
  1377. ULONG64 DestinationKey;
  1378. ULONG i;
  1379. LONG64 IdleTime;
  1380. KIRQL Irql;
  1381. PLIST_ENTRY Link;
  1382. PNAT_DYNAMIC_MAPPING Mapping;
  1383. ULONG64 SourceKey;
  1384. NTSTATUS status;
  1385. PIP_NAT_SESSION_MAPPING Table;
  1386. CALLTRACE(("NatQueryMappingTable\n"));
  1387. Context = InputBuffer->EnumerateContext;
  1388. KeAcquireSpinLock(&MappingLock, &Irql);
  1389. //
  1390. // See if this is a new enumeration or a continuation of an old one.
  1391. //
  1392. if (!Context[0]) {
  1393. //
  1394. // This is a new enumeration. We start with the first item
  1395. // in the interface's list of mappings
  1396. //
  1397. Mapping =
  1398. IsListEmpty(&MappingList)
  1399. ? NULL
  1400. : CONTAINING_RECORD(
  1401. MappingList.Flink, NAT_DYNAMIC_MAPPING, Link
  1402. );
  1403. } else {
  1404. //
  1405. // This is a continuation. The context therefore contains
  1406. // the keys for the next mapping, in the fields
  1407. // Context[0-1] and Context[2-3] respectively
  1408. //
  1409. DestinationKey = MAKE_LONG64(Context[0], Context[1]);
  1410. SourceKey = MAKE_LONG64(Context[2], Context[3]);
  1411. Mapping =
  1412. NatLookupForwardMapping(
  1413. DestinationKey,
  1414. SourceKey,
  1415. NULL
  1416. );
  1417. }
  1418. if (!Mapping) {
  1419. OutputBuffer->EnumerateCount = 0;
  1420. OutputBuffer->EnumerateContext[0] = 0;
  1421. OutputBuffer->EnumerateTotalHint = MappingCount;
  1422. *OutputBufferLength =
  1423. FIELD_OFFSET(IP_NAT_ENUMERATE_SESSION_MAPPINGS, EnumerateTable);
  1424. KeReleaseSpinLock(&MappingLock, Irql);
  1425. return STATUS_SUCCESS;
  1426. }
  1427. //
  1428. // Compute the maximum number of mappings we can store
  1429. //
  1430. Count =
  1431. *OutputBufferLength -
  1432. FIELD_OFFSET(IP_NAT_ENUMERATE_SESSION_MAPPINGS, EnumerateTable);
  1433. Count /= sizeof(IP_NAT_SESSION_MAPPING);
  1434. //
  1435. // Walk the list storing mappings in the caller's buffer
  1436. //
  1437. Table = OutputBuffer->EnumerateTable;
  1438. KeQueryTickCount((PLARGE_INTEGER)&CurrentTime);
  1439. for (i = 0, Link = &Mapping->Link;
  1440. i < Count && Link != &MappingList;
  1441. i++, Link = Link->Flink
  1442. ) {
  1443. Mapping = CONTAINING_RECORD(Link, NAT_DYNAMIC_MAPPING, Link);
  1444. NatQueryInformationMapping(
  1445. Mapping,
  1446. &Table[i].Protocol,
  1447. &Table[i].PrivateAddress,
  1448. &Table[i].PrivatePort,
  1449. &Table[i].RemoteAddress,
  1450. &Table[i].RemotePort,
  1451. &Table[i].PublicAddress,
  1452. &Table[i].PublicPort,
  1453. NULL
  1454. );
  1455. Table[i].Direction =
  1456. NAT_MAPPING_INBOUND(Mapping)
  1457. ? NatInboundDirection : NatOutboundDirection;
  1458. IdleTime = CurrentTime - Mapping->LastAccessTime;
  1459. Table[i].IdleTime = (ULONG)TICKS_TO_SECONDS(IdleTime);
  1460. }
  1461. //
  1462. // The enumeration is over; update the output structure
  1463. //
  1464. *OutputBufferLength =
  1465. i * sizeof(IP_NAT_SESSION_MAPPING) +
  1466. FIELD_OFFSET(IP_NAT_ENUMERATE_SESSION_MAPPINGS, EnumerateTable);
  1467. OutputBuffer->EnumerateCount = i;
  1468. OutputBuffer->EnumerateTotalHint = MappingCount;
  1469. if (Link == &MappingList) {
  1470. //
  1471. // We reached the end of the mapping list
  1472. //
  1473. OutputBuffer->EnumerateContext[0] = 0;
  1474. } else {
  1475. //
  1476. // Save the continuation context
  1477. //
  1478. Mapping = CONTAINING_RECORD(Link, NAT_DYNAMIC_MAPPING, Link);
  1479. OutputBuffer->EnumerateContext[0] =
  1480. (ULONG)Mapping->DestinationKey[NatForwardPath];
  1481. OutputBuffer->EnumerateContext[1] =
  1482. (ULONG)(Mapping->DestinationKey[NatForwardPath] >> 32);
  1483. OutputBuffer->EnumerateContext[2] =
  1484. (ULONG)Mapping->SourceKey[NatForwardPath];
  1485. OutputBuffer->EnumerateContext[3] =
  1486. (ULONG)(Mapping->SourceKey[NatForwardPath] >> 32);
  1487. }
  1488. KeReleaseSpinLock(&MappingLock, Irql);
  1489. return STATUS_SUCCESS;
  1490. } // NatQueryMappingTable
  1491. PNAT_DYNAMIC_MAPPING
  1492. NatSourceLookupForwardMapping(
  1493. ULONG64 SourceKey
  1494. )
  1495. /*++
  1496. Routine Description:
  1497. This routine retrieves the mapping which matches the given source key.
  1498. The destination key of the mapping is not examined.
  1499. Arguments:
  1500. SourceKey - the primary key used to search for a mapping.
  1501. PublicAddressp - receives the private address of the mapping
  1502. PublicPortp - receives the private port of the mapping
  1503. Return Value:
  1504. PNAT_DYNAMIC_MAPPING - the item found, or NULL if no match is found
  1505. Environment:
  1506. Invoked with 'MappingLock' held by the caller.
  1507. --*/
  1508. {
  1509. PNAT_DYNAMIC_MAPPING Root;
  1510. PNAT_DYNAMIC_MAPPING Mapping;
  1511. PRTL_SPLAY_LINKS SLink;
  1512. TRACE(PER_PACKET, ("NatSourceLookupForwardMapping\n"));
  1513. //
  1514. // Search the full tree -- the mapping cache can only be used
  1515. // for destination lookups.
  1516. //
  1517. Root = MappingTree[NatForwardPath];
  1518. for (SLink = !Root ? NULL : &Root->SLink[NatForwardPath]; SLink; ) {
  1519. Mapping =
  1520. CONTAINING_RECORD(SLink,NAT_DYNAMIC_MAPPING,SLink[NatForwardPath]);
  1521. if (SourceKey < Mapping->SourceKey[NatForwardPath]) {
  1522. SLink = RtlLeftChild(SLink);
  1523. continue;
  1524. } else if (SourceKey > Mapping->SourceKey[NatForwardPath]) {
  1525. SLink = RtlRightChild(SLink);
  1526. continue;
  1527. }
  1528. //
  1529. // We found the mapping.
  1530. //
  1531. return Mapping;
  1532. }
  1533. //
  1534. // No partial match was found
  1535. //
  1536. return NULL;
  1537. } // NatSourceLookupForwardMapping
  1538. PNAT_DYNAMIC_MAPPING
  1539. NatSourceLookupReverseMapping(
  1540. ULONG64 SourceKey
  1541. )
  1542. /*++
  1543. Routine Description:
  1544. This routine retrieves the mapping which matches the given source key.
  1545. The destination key of the mapping is not examined.
  1546. Arguments:
  1547. SourceKey - the primary key used to search for a mapping.
  1548. Return Value:
  1549. PNAT_DYNAMIC_MAPPING - the item found, or NULL if no match is found
  1550. Environment:
  1551. Invoked with 'MappingLock' held by the caller.
  1552. --*/
  1553. {
  1554. PNAT_DYNAMIC_MAPPING Root;
  1555. PNAT_DYNAMIC_MAPPING Mapping;
  1556. PRTL_SPLAY_LINKS SLink;
  1557. TRACE(PER_PACKET, ("NatSourceLookupReverseMapping\n"));
  1558. //
  1559. // Search the full tree -- the mapping cache can only be used
  1560. // for destination lookups.
  1561. //
  1562. Root = MappingTree[NatReversePath];
  1563. for (SLink = !Root ? NULL : &Root->SLink[NatReversePath]; SLink; ) {
  1564. Mapping =
  1565. CONTAINING_RECORD(SLink,NAT_DYNAMIC_MAPPING,SLink[NatReversePath]);
  1566. if (SourceKey < Mapping->SourceKey[NatReversePath]) {
  1567. SLink = RtlLeftChild(SLink);
  1568. continue;
  1569. } else if (SourceKey > Mapping->SourceKey[NatReversePath]) {
  1570. SLink = RtlRightChild(SLink);
  1571. continue;
  1572. }
  1573. //
  1574. // We found the mapping.
  1575. //
  1576. return Mapping;
  1577. }
  1578. //
  1579. // No partial match was found
  1580. //
  1581. return NULL;
  1582. } // NatSourceLookupReverseMapping
  1583. VOID
  1584. NatShutdownMappingManagement(
  1585. VOID
  1586. )
  1587. /*++
  1588. Routine Description:
  1589. This routine is invoked to shutdown the mapping-management module.
  1590. Arguments:
  1591. none.
  1592. Return Value:
  1593. none.
  1594. Environment:
  1595. Invoked with no references made to any mappings.
  1596. --*/
  1597. {
  1598. KIRQL Irql;
  1599. PNAT_DYNAMIC_MAPPING Mapping;
  1600. CALLTRACE(("NatShutdownMappingManagement\n"));
  1601. KeAcquireSpinLock(&MappingLock, &Irql);
  1602. while (!IsListEmpty(&MappingList)) {
  1603. Mapping =
  1604. CONTAINING_RECORD(MappingList.Flink, NAT_DYNAMIC_MAPPING, Link);
  1605. RemoveEntryList(&Mapping->Link);
  1606. NatCleanupMapping(Mapping);
  1607. }
  1608. MappingTree[NatForwardPath] = NULL;
  1609. MappingTree[NatReversePath] = NULL;
  1610. KeReleaseSpinLock(&MappingLock, Irql);
  1611. ExDeleteNPagedLookasideList(&MappingLookasideList);
  1612. } // NatShutdownMappingManagement
  1613. VOID
  1614. NatUpdateStatisticsMapping(
  1615. PNAT_DYNAMIC_MAPPING Mapping
  1616. )
  1617. /*++
  1618. Routine Description:
  1619. This routine is invoked to immediately update the statistics for a mapping,
  1620. adding the 32-bit incremental counters to the 64-bit cumulative counters.
  1621. Arguments:
  1622. Mapping - the mapping whose statistics are to be updated
  1623. Return Value:
  1624. none.
  1625. Environment:
  1626. Invoked with 'MappingLock' held by the caller.
  1627. --*/
  1628. {
  1629. ULONG BytesForward;
  1630. ULONG BytesReverse;
  1631. ULONG PacketsForward;
  1632. ULONG PacketsReverse;
  1633. ULONG RejectsForward;
  1634. ULONG RejectsReverse;
  1635. CALLTRACE(("NatUpdateStatisticsMapping\n"));
  1636. //
  1637. // Read the statistics accrued since the last incremental update
  1638. //
  1639. BytesForward = InterlockedExchange(&Mapping->BytesForward, 0);
  1640. BytesReverse = InterlockedExchange(&Mapping->BytesReverse, 0);
  1641. PacketsForward = InterlockedExchange(&Mapping->PacketsForward, 0);
  1642. PacketsReverse = InterlockedExchange(&Mapping->PacketsReverse, 0);
  1643. RejectsForward = InterlockedExchange(&Mapping->RejectsForward, 0);
  1644. RejectsReverse = InterlockedExchange(&Mapping->RejectsReverse, 0);
  1645. # define UPDATE_STATISTIC(x,y) \
  1646. if (y) { \
  1647. ExInterlockedAddLargeStatistic( \
  1648. (PLARGE_INTEGER)&x->Statistics.y, y \
  1649. ); \
  1650. }
  1651. //
  1652. // Update the cumulative statistics for the mapping
  1653. //
  1654. UPDATE_STATISTIC(Mapping, BytesForward);
  1655. UPDATE_STATISTIC(Mapping, BytesReverse);
  1656. UPDATE_STATISTIC(Mapping, PacketsForward);
  1657. UPDATE_STATISTIC(Mapping, PacketsReverse);
  1658. UPDATE_STATISTIC(Mapping, RejectsForward);
  1659. UPDATE_STATISTIC(Mapping, RejectsReverse);
  1660. //
  1661. // Update cumulative statistics for the mapping's interface, if any
  1662. //
  1663. KeAcquireSpinLockAtDpcLevel(&InterfaceLock);
  1664. if (Mapping->Interfacep) {
  1665. UPDATE_STATISTIC(Mapping->Interfacep, BytesForward);
  1666. UPDATE_STATISTIC(Mapping->Interfacep, BytesReverse);
  1667. UPDATE_STATISTIC(Mapping->Interfacep, PacketsForward);
  1668. UPDATE_STATISTIC(Mapping->Interfacep, PacketsReverse);
  1669. UPDATE_STATISTIC(Mapping->Interfacep, RejectsForward);
  1670. UPDATE_STATISTIC(Mapping->Interfacep, RejectsReverse);
  1671. }
  1672. KeReleaseSpinLockFromDpcLevel(&InterfaceLock);
  1673. # undef UPDATE_STATISTIC
  1674. } // NatUpdateStatisticsMapping