Leaked source code of windows server 2003
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.

1180 lines
29 KiB

  1. /*++
  2. Copyright (c) 1997-2001 Microsoft Corporation
  3. Module Name:
  4. NsConn.c
  5. Abstract:
  6. IpSec NAT shim connection entry management
  7. Author:
  8. Jonathan Burstein (jonburs) 11-July-2001
  9. Environment:
  10. Kernel mode
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. //
  16. // Global Variables
  17. //
  18. CACHE_ENTRY NsConnectionCache[CACHE_SIZE];
  19. ULONG NsConnectionCount;
  20. LIST_ENTRY NsConnectionList;
  21. KSPIN_LOCK NsConnectionLock;
  22. NPAGED_LOOKASIDE_LIST NsConnectionLookasideList;
  23. PNS_CONNECTION_ENTRY NsConnectionTree[NsMaximumDirection];
  24. USHORT NsNextSourcePort;
  25. //
  26. // Function Prototypes
  27. //
  28. PNS_CONNECTION_ENTRY
  29. NspInsertInboundConnectionEntry(
  30. PNS_CONNECTION_ENTRY pParent,
  31. PNS_CONNECTION_ENTRY pEntry
  32. );
  33. PNS_CONNECTION_ENTRY
  34. NspInsertOutboundConnectionEntry(
  35. PNS_CONNECTION_ENTRY pParent,
  36. PNS_CONNECTION_ENTRY pEntry
  37. );
  38. NTSTATUS
  39. NsAllocateSourcePort(
  40. ULONG64 ul64AddressKey,
  41. ULONG ulPortKey,
  42. UCHAR ucProtocol,
  43. BOOLEAN fPortConflicts,
  44. PNS_CONNECTION_ENTRY *ppOutboundInsertionPoint,
  45. PULONG pulTranslatedPortKey
  46. )
  47. /*++
  48. Routine Description:
  49. Called to allocate a source port for a connection entry. If the original
  50. port does not conflict with any existing connection entry it will be used.
  51. Arguments:
  52. ul64AddressKey - the addressing information for the connection
  53. ulPortKey - the original port information for the connection
  54. ucProtocol - the protocol for the connection
  55. fPortConflicts - if TRUE, indicates that the caller knows that the original
  56. port information conflicts w/ an existing connection. If FALSE the
  57. caller does not know whether or not a conflict definately exists.
  58. ppOutboundInsertionPoint - receives the insertion point for the
  59. outbound path
  60. pulTranslatedPortKey - on success, receives the allocated port information.
  61. Return Value:
  62. NTSTATUS.
  63. Environment:
  64. Invoked with NsConnectionLock held by the caller.
  65. --*/
  66. {
  67. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  68. ULONG ulOutboundPortKey;
  69. USHORT usLocalPort;
  70. USHORT usStopPort;
  71. ASSERT(NULL != ppOutboundInsertionPoint);
  72. ASSERT(NULL != pulTranslatedPortKey);
  73. TRACE(
  74. PORT_ALLOC,
  75. ("NsAllocateSourcePort: %d: %d.%d.%d.%d/%d -> %d.%d.%d.%d/%d\n",
  76. ucProtocol,
  77. ADDRESS_BYTES(CONNECTION_REMOTE_ADDRESS(ul64AddressKey)),
  78. NTOHS(CONNECTION_REMOTE_PORT(ulPortKey)),
  79. ADDRESS_BYTES(CONNECTION_LOCAL_ADDRESS(ul64AddressKey)),
  80. NTOHS(CONNECTION_LOCAL_PORT(ulPortKey))
  81. ));
  82. usLocalPort = CONNECTION_LOCAL_PORT(ulPortKey);
  83. if (FALSE == fPortConflicts)
  84. {
  85. //
  86. // The caller indicates that the remote port does not
  87. // conflict on the inbound path, so we'll first attempt
  88. // to use the original port.
  89. //
  90. ulOutboundPortKey = ulPortKey;
  91. usStopPort =
  92. (NS_SOURCE_PORT_END == NsNextSourcePort
  93. ? NS_SOURCE_PORT_BASE
  94. : NsNextSourcePort + 1);
  95. }
  96. else
  97. {
  98. //
  99. // The caller indicates that the remote port conflicts
  100. // on the inbound path, so we'll assume that it also
  101. // conflicts on the outbound path and start by trying
  102. // out a new port.
  103. //
  104. usStopPort = NsNextSourcePort--;
  105. MAKE_PORT_KEY(
  106. ulOutboundPortKey,
  107. usLocalPort,
  108. usStopPort
  109. );
  110. if (NsNextSourcePort < NS_SOURCE_PORT_BASE)
  111. {
  112. NsNextSourcePort = NS_SOURCE_PORT_END;
  113. }
  114. }
  115. do
  116. {
  117. //
  118. // Check to see if our current candidate conflicts
  119. // with any connection entries on the outbound path.
  120. //
  121. if (NULL ==
  122. NsLookupOutboundConnectionEntry(
  123. ul64AddressKey,
  124. ulOutboundPortKey,
  125. ucProtocol,
  126. ppOutboundInsertionPoint
  127. ))
  128. {
  129. //
  130. // No conflict was found -- break out of the loop and
  131. // return this info to the caller.
  132. //
  133. TRACE(PORT_ALLOC, ("NsAllocateSourcePort: Assigning %d\n",
  134. NTOHS(CONNECTION_REMOTE_PORT(ulOutboundPortKey))));
  135. *pulTranslatedPortKey = ulOutboundPortKey;
  136. Status = STATUS_SUCCESS;
  137. break;
  138. }
  139. //
  140. // This candidate conflicted; move on to the next.
  141. //
  142. MAKE_PORT_KEY(
  143. ulOutboundPortKey,
  144. usLocalPort,
  145. NsNextSourcePort--
  146. );
  147. if (NsNextSourcePort < NS_SOURCE_PORT_BASE)
  148. {
  149. NsNextSourcePort = NS_SOURCE_PORT_END;
  150. }
  151. }
  152. while (usStopPort != CONNECTION_REMOTE_PORT(ulOutboundPortKey));
  153. TRACE(PORT_ALLOC, ("NsAllocateSourcePort: No port available\n"));
  154. return Status;
  155. } // NsAllocateSourcePort
  156. VOID
  157. NsCleanupConnectionEntry(
  158. PNS_CONNECTION_ENTRY pEntry
  159. )
  160. /*++
  161. Routine Description:
  162. Called to perform final cleanup for a connection entry.
  163. Arguments:
  164. pEntry - the connection entry to be deleted.
  165. Return Value:
  166. none.
  167. Environment:
  168. Invoked with the last reference to the connection entry released.
  169. --*/
  170. {
  171. TRACE(CONN_LIFETIME, ("NsCleanupConnectionEntry\n"));
  172. ASSERT(NULL != pEntry);
  173. FREE_CONNECTION_BLOCK(pEntry);
  174. } // NsCleanupConnectionEntry
  175. NTSTATUS
  176. NsCreateConnectionEntry(
  177. ULONG64 ul64AddressKey,
  178. ULONG ulInboundPortKey,
  179. ULONG ulOutboundPortKey,
  180. UCHAR ucProtocol,
  181. PVOID pvIpSecContext,
  182. PNS_CONNECTION_ENTRY pInboundInsertionPoint,
  183. PNS_CONNECTION_ENTRY pOutboundInsertionPoint,
  184. PNS_CONNECTION_ENTRY *ppNewEntry
  185. )
  186. /*++
  187. Routine Description:
  188. Called to create a connection entry. On success, the connection entry
  189. will have been referenced twice -- the initial reference for the entry
  190. (which is released in NsDeleteConnectionEntry) and a reference for the
  191. caller. Thus, the caller must call NsDereferenceConnectionEntry on the
  192. new entry.
  193. Arguments:
  194. ul64AddressKey - the addressing information for this entry
  195. ulInboundPortKey - the inbound (original) ports for this entry
  196. ulOutboundPortKey - the outbound (translated) ports for this entry
  197. ucProtocol - the protocol for this entry
  198. pvIpSecContext - the IpSec context for this entry
  199. p*InsertionPoint - the inbound and outbound insertion points (normally
  200. obtained through NsAllocateSourcePort).
  201. ppEntry - receives a pointer to the newley-created connection entry. The
  202. caller must call NsDereferenceConnectionEntry on this pointer.
  203. Return Value:
  204. NTSTATUS - indicates success/failure.
  205. Environment:
  206. Invoked with 'NsConnectionLock' held by the caller.
  207. --*/
  208. {
  209. PNS_CONNECTION_ENTRY pEntry;
  210. TRACE(
  211. CONN_LIFETIME,
  212. ("NsCreateConnectionEntry: %d: %d.%d.%d.%d/%d/%d -> %d.%d.%d.%d/%d : %d\n",
  213. ucProtocol,
  214. ADDRESS_BYTES(CONNECTION_REMOTE_ADDRESS(ul64AddressKey)),
  215. NTOHS(CONNECTION_REMOTE_PORT(ulInboundPortKey)),
  216. NTOHS(CONNECTION_REMOTE_PORT(ulOutboundPortKey)),
  217. ADDRESS_BYTES(CONNECTION_LOCAL_ADDRESS(ul64AddressKey)),
  218. NTOHS(CONNECTION_LOCAL_PORT(ulInboundPortKey)),
  219. pvIpSecContext
  220. ));
  221. ASSERT(NULL != ppNewEntry);
  222. ASSERT(NS_PROTOCOL_TCP == ucProtocol || NS_PROTOCOL_UDP == ucProtocol);
  223. pEntry = ALLOCATE_CONNECTION_BLOCK();
  224. if (NULL == pEntry)
  225. {
  226. ERROR(("NsCreateConnectionEntry: Unable to allocate entry\n"));
  227. return STATUS_NO_MEMORY;
  228. }
  229. RtlZeroMemory(pEntry, sizeof(*pEntry));
  230. KeInitializeSpinLock(&pEntry->Lock);
  231. pEntry->ulReferenceCount = 1;
  232. pEntry->ul64AddressKey = ul64AddressKey;
  233. pEntry->ulPortKey[NsInboundDirection] = ulInboundPortKey;
  234. pEntry->ulPortKey[NsOutboundDirection] = ulOutboundPortKey;
  235. pEntry->ucProtocol = ucProtocol;
  236. pEntry->pvIpSecContext = pvIpSecContext;
  237. pEntry->ulAccessCount[NsInboundDirection] = NS_CONNECTION_RESPLAY_THRESHOLD;
  238. pEntry->ulAccessCount[NsOutboundDirection] = NS_CONNECTION_RESPLAY_THRESHOLD;
  239. InitializeListHead(&pEntry->Link);
  240. RtlInitializeSplayLinks(&pEntry->SLink[NsInboundDirection]);
  241. RtlInitializeSplayLinks(&pEntry->SLink[NsOutboundDirection]);
  242. //
  243. // Incremeent the reference count on the connection; the caller
  244. // is required to do a dereference.
  245. //
  246. pEntry->ulReferenceCount += 1;
  247. //
  248. // Setup checksum deltas (if necessary) and per-packet routines
  249. //
  250. if (ulInboundPortKey != ulOutboundPortKey)
  251. {
  252. //
  253. // This connection entry is translating the remote port, so
  254. // precompute the checksum deltas (see RFC 1624).
  255. //
  256. pEntry->ulProtocolChecksumDelta[NsInboundDirection] =
  257. (USHORT)~CONNECTION_REMOTE_PORT(ulInboundPortKey)
  258. + (USHORT)CONNECTION_REMOTE_PORT(ulOutboundPortKey);
  259. pEntry->ulProtocolChecksumDelta[NsOutboundDirection] =
  260. (USHORT)~CONNECTION_REMOTE_PORT(ulOutboundPortKey)
  261. + (USHORT)CONNECTION_REMOTE_PORT(ulInboundPortKey);
  262. if (NS_PROTOCOL_TCP == ucProtocol)
  263. {
  264. pEntry->PacketRoutine[NsInboundDirection] =
  265. NsInboundTcpTranslatePortPacketRoutine;
  266. pEntry->PacketRoutine[NsOutboundDirection] =
  267. NsOutboundTcpTranslatePortPacketRoutine;
  268. }
  269. else
  270. {
  271. pEntry->PacketRoutine[NsInboundDirection] =
  272. NsInboundUdpTranslatePortPacketRoutine;
  273. pEntry->PacketRoutine[NsOutboundDirection] =
  274. NsOutboundUdpTranslatePortPacketRoutine;
  275. }
  276. }
  277. else if (NS_PROTOCOL_TCP == ucProtocol)
  278. {
  279. pEntry->PacketRoutine[NsInboundDirection] = NsInboundTcpPacketRoutine;
  280. pEntry->PacketRoutine[NsOutboundDirection] = NsOutboundTcpPacketRoutine;
  281. }
  282. else
  283. {
  284. pEntry->PacketRoutine[NsInboundDirection] = NsInboundUdpPacketRoutine;
  285. pEntry->PacketRoutine[NsOutboundDirection] = NsOutboundUdpPacketRoutine;
  286. }
  287. NsConnectionTree[NsInboundDirection] =
  288. NspInsertInboundConnectionEntry(pInboundInsertionPoint, pEntry);
  289. NsConnectionTree[NsOutboundDirection] =
  290. NspInsertOutboundConnectionEntry(pOutboundInsertionPoint, pEntry);
  291. InsertTailList(&NsConnectionList, &pEntry->Link);
  292. InterlockedIncrement(&NsConnectionCount);
  293. *ppNewEntry = pEntry;
  294. return STATUS_SUCCESS;
  295. } // NsCreateConnectionEntry
  296. NTSTATUS
  297. NsDeleteConnectionEntry(
  298. PNS_CONNECTION_ENTRY pEntry
  299. )
  300. /*++
  301. Routine Description:
  302. Called to delete a connection entry. The initial reference to the entry
  303. is released, so that cleanup occurs whenever the last reference is released.
  304. Arguments:
  305. pEntry - the connection entry to be deleted.
  306. Return Value:
  307. NTSTATUS - indicates success/failure.
  308. Environment:
  309. Invoked with 'NsConnectionLock' held by the caller.
  310. --*/
  311. {
  312. PRTL_SPLAY_LINKS SLink;
  313. TRACE(CONN_LIFETIME, ("NsDeleteConnectionEntry\n"));
  314. ASSERT(NULL != pEntry);
  315. if (NS_CONNECTION_DELETED(pEntry))
  316. {
  317. return STATUS_PENDING;
  318. }
  319. //
  320. // Mark the entry as deleted so attempts to reference it
  321. // will fail from now on.
  322. //
  323. pEntry->ulFlags |= NS_CONNECTION_FLAG_DELETED;
  324. //
  325. // Take the entry off the list and splay-trees
  326. //
  327. InterlockedDecrement(&NsConnectionCount);
  328. RemoveEntryList(&pEntry->Link);
  329. SLink = RtlDelete(&pEntry->SLink[NsInboundDirection]);
  330. NsConnectionTree[NsInboundDirection] =
  331. (SLink
  332. ? CONTAINING_RECORD(SLink,NS_CONNECTION_ENTRY,SLink[NsInboundDirection])
  333. : NULL);
  334. SLink = RtlDelete(&pEntry->SLink[NsOutboundDirection]);
  335. NsConnectionTree[NsOutboundDirection] =
  336. (SLink
  337. ? CONTAINING_RECORD(SLink,NS_CONNECTION_ENTRY,SLink[NsOutboundDirection])
  338. : NULL);
  339. //
  340. // Clear the entry from the connection cache
  341. //
  342. ClearCache(
  343. NsConnectionCache,
  344. (ULONG)pEntry->ul64AddressKey
  345. );
  346. if (0 != InterlockedDecrement(&pEntry->ulReferenceCount)) {
  347. //
  348. // The entry is in use, defer final cleanup
  349. //
  350. return STATUS_PENDING;
  351. }
  352. //
  353. // Go ahead with final cleanup
  354. //
  355. NsCleanupConnectionEntry(pEntry);
  356. return STATUS_SUCCESS;
  357. } // NsDeleteConnectionEntry
  358. NTSTATUS
  359. NsInitializeConnectionManagement(
  360. VOID
  361. )
  362. /*++
  363. Routine Description:
  364. This routine is invoked to initialize the connection management module.
  365. Arguments:
  366. none.
  367. Return Value:
  368. NTSTATUS.
  369. --*/
  370. {
  371. CALLTRACE(("NsInitializeConnectionManagement\n"));
  372. InitializeCache(NsConnectionCache);
  373. NsConnectionCount = 0;
  374. InitializeListHead(&NsConnectionList);
  375. KeInitializeSpinLock(&NsConnectionLock);
  376. ExInitializeNPagedLookasideList(
  377. &NsConnectionLookasideList,
  378. NULL,
  379. NULL,
  380. 0,
  381. sizeof(NS_CONNECTION_ENTRY),
  382. NS_TAG_CONNECTION,
  383. NS_CONNECTION_LOOKASIDE_DEPTH
  384. );
  385. NsConnectionTree[NsInboundDirection] = NULL;
  386. NsConnectionTree[NsOutboundDirection] = NULL;
  387. NsNextSourcePort = NS_SOURCE_PORT_END;
  388. return STATUS_SUCCESS;
  389. } // NsInitializeConnectionManagement
  390. PNS_CONNECTION_ENTRY
  391. NsLookupInboundConnectionEntry(
  392. ULONG64 ul64AddressKey,
  393. ULONG ulPortKey,
  394. UCHAR ucProtocol,
  395. PVOID pvIpSecContext,
  396. BOOLEAN *pfPortConflicts OPTIONAL,
  397. PNS_CONNECTION_ENTRY *ppInsertionPoint OPTIONAL
  398. )
  399. /*++
  400. Routine Description:
  401. Called to lookup an inbound connection entry.
  402. Arguments:
  403. ul64AddressKey - the addressing information for the connection
  404. ulPortKey - the port information for the connection
  405. ucProtocol - the protocol for the connection
  406. pvIpSecContext - the IpSec context for the connection
  407. pfPortConflicts - on failure, receives a boolean the indicates why
  408. the lookup failed: TRUE if the lookup failed because there is
  409. an identical connection entry w/ different IpSec context, FALSE
  410. otherwise.
  411. ppInsertionPoint - receives the insertion point if not found
  412. Return Value:
  413. PNS_CONNECTION_ENTRY - a pointer to the connection entry, if found, or
  414. NULL otherwise.
  415. Environment:
  416. Invoked with NsConnectionLock held by the caller.
  417. --*/
  418. {
  419. PNS_CONNECTION_ENTRY pRoot;
  420. PNS_CONNECTION_ENTRY pEntry;
  421. PNS_CONNECTION_ENTRY pParent = NULL;
  422. PRTL_SPLAY_LINKS SLink;
  423. TRACE(
  424. CONN_LOOKUP,
  425. ("NsLookupInboundConnectionEntry: %d: %d.%d.%d.%d/%d -> %d.%d.%d.%d/%d : %d\n",
  426. ucProtocol,
  427. ADDRESS_BYTES(CONNECTION_REMOTE_ADDRESS(ul64AddressKey)),
  428. NTOHS(CONNECTION_REMOTE_PORT(ulPortKey)),
  429. ADDRESS_BYTES(CONNECTION_LOCAL_ADDRESS(ul64AddressKey)),
  430. NTOHS(CONNECTION_LOCAL_PORT(ulPortKey)),
  431. pvIpSecContext
  432. ));
  433. //
  434. // First look in the cache
  435. //
  436. pEntry = (PNS_CONNECTION_ENTRY)
  437. ProbeCache(
  438. NsConnectionCache,
  439. (ULONG)ul64AddressKey
  440. );
  441. if (NULL != pEntry
  442. && pEntry->ul64AddressKey == ul64AddressKey
  443. && pEntry->ucProtocol == ucProtocol
  444. && pEntry->ulPortKey[NsInboundDirection] == ulPortKey
  445. && pEntry->pvIpSecContext == pvIpSecContext)
  446. {
  447. TRACE(CONN_LOOKUP, ("NsLookupInboundConnectionEntry: Cache Hit\n"));
  448. return pEntry;
  449. }
  450. if (pfPortConflicts)
  451. {
  452. *pfPortConflicts = FALSE;
  453. }
  454. //
  455. // Search the full tree. Keys are checked in the
  456. // following order:
  457. //
  458. // 1. Address Key
  459. // 2. Protocol
  460. // 3. Inbound port key
  461. // 4. IpSec context
  462. //
  463. pRoot = NsConnectionTree[NsInboundDirection];
  464. for (SLink = (pRoot ? &pRoot->SLink[NsInboundDirection] : NULL ); SLink; )
  465. {
  466. pEntry =
  467. CONTAINING_RECORD(SLink, NS_CONNECTION_ENTRY, SLink[NsInboundDirection]);
  468. if (ul64AddressKey < pEntry->ul64AddressKey)
  469. {
  470. pParent = pEntry;
  471. SLink = RtlLeftChild(SLink);
  472. continue;
  473. }
  474. else if (ul64AddressKey > pEntry->ul64AddressKey)
  475. {
  476. pParent = pEntry;
  477. SLink = RtlRightChild(SLink);
  478. continue;
  479. }
  480. else if (ucProtocol < pEntry->ucProtocol)
  481. {
  482. pParent = pEntry;
  483. SLink = RtlLeftChild(SLink);
  484. continue;
  485. }
  486. else if (ucProtocol > pEntry->ucProtocol)
  487. {
  488. pParent = pEntry;
  489. SLink = RtlRightChild(SLink);
  490. continue;
  491. }
  492. else if (ulPortKey < pEntry->ulPortKey[NsInboundDirection])
  493. {
  494. pParent = pEntry;
  495. SLink = RtlLeftChild(SLink);
  496. continue;
  497. }
  498. else if (ulPortKey > pEntry->ulPortKey[NsInboundDirection])
  499. {
  500. pParent = pEntry;
  501. SLink = RtlRightChild(SLink);
  502. continue;
  503. }
  504. else if (pvIpSecContext < pEntry->pvIpSecContext)
  505. {
  506. //
  507. // Everything matched w/ the exception of the IpSec
  508. // context -- we have a port conflict.
  509. //
  510. if (pfPortConflicts)
  511. {
  512. *pfPortConflicts = TRUE;
  513. }
  514. pParent = pEntry;
  515. SLink = RtlLeftChild(SLink);
  516. continue;
  517. }
  518. else if (pvIpSecContext > pEntry->pvIpSecContext)
  519. {
  520. //
  521. // Everything matched w/ the exception of the IpSec
  522. // context -- we have a port conflict.
  523. //
  524. if (pfPortConflicts)
  525. {
  526. *pfPortConflicts = TRUE;
  527. }
  528. pParent = pEntry;
  529. SLink = RtlRightChild(SLink);
  530. continue;
  531. }
  532. //
  533. // We found the entry -- update cache and return
  534. //
  535. UpdateCache(
  536. NsConnectionCache,
  537. (ULONG)ul64AddressKey,
  538. (PVOID)pEntry
  539. );
  540. return pEntry;
  541. }
  542. //
  543. // Not found -- provide insertion point if requested
  544. //
  545. if (ppInsertionPoint)
  546. {
  547. *ppInsertionPoint = pParent;
  548. }
  549. return NULL;
  550. } // NsLookupInboundConnectionEntry
  551. PNS_CONNECTION_ENTRY
  552. NsLookupOutboundConnectionEntry(
  553. ULONG64 ul64AddressKey,
  554. ULONG ulPortKey,
  555. UCHAR ucProtocol,
  556. PNS_CONNECTION_ENTRY *ppInsertionPoint OPTIONAL
  557. )
  558. /*++
  559. Routine Description:
  560. Called to lookup an outbound connection entry.
  561. Arguments:
  562. ul64AddressKey - the addressing information for the connection
  563. ulPortKey - the port information for the connection
  564. ucProtocol - the protocol for the connection
  565. ppInsertionPoint - receives the insertion point if not found
  566. Return Value:
  567. PNS_CONNECTION_ENTRY - a pointer to the connection entry, if found, or
  568. NULL otherwise.
  569. Environment:
  570. Invoked with NsConnectionLock held by the caller.
  571. --*/
  572. {
  573. PNS_CONNECTION_ENTRY pRoot;
  574. PNS_CONNECTION_ENTRY pEntry;
  575. PNS_CONNECTION_ENTRY pParent = NULL;
  576. PRTL_SPLAY_LINKS SLink;
  577. TRACE(
  578. CONN_LOOKUP,
  579. ("NsLookupOutboundConnectionEntry: %d: %d.%d.%d.%d/%d -> %d.%d.%d.%d/%d\n",
  580. ucProtocol,
  581. ADDRESS_BYTES(CONNECTION_LOCAL_ADDRESS(ul64AddressKey)),
  582. NTOHS(CONNECTION_LOCAL_PORT(ulPortKey)),
  583. ADDRESS_BYTES(CONNECTION_REMOTE_ADDRESS(ul64AddressKey)),
  584. NTOHS(CONNECTION_REMOTE_PORT(ulPortKey))
  585. ));
  586. //
  587. // First look in the cache
  588. //
  589. pEntry = (PNS_CONNECTION_ENTRY)
  590. ProbeCache(
  591. NsConnectionCache,
  592. (ULONG)ul64AddressKey
  593. );
  594. if (NULL != pEntry
  595. && pEntry->ul64AddressKey == ul64AddressKey
  596. && pEntry->ucProtocol == ucProtocol
  597. && pEntry->ulPortKey[NsOutboundDirection] == ulPortKey)
  598. {
  599. TRACE(CONN_LOOKUP, ("NsLookupOutboundConnectionEntry: Cache Hit\n"));
  600. return pEntry;
  601. }
  602. //
  603. // Search the full tree. Keys are checked in the
  604. // following order:
  605. //
  606. // 1. Address Key
  607. // 2. Protocol
  608. // 3. Outbound port key
  609. //
  610. pRoot = NsConnectionTree[NsOutboundDirection];
  611. for (SLink = (pRoot ? &pRoot->SLink[NsOutboundDirection] : NULL ); SLink; )
  612. {
  613. pEntry =
  614. CONTAINING_RECORD(SLink, NS_CONNECTION_ENTRY, SLink[NsOutboundDirection]);
  615. if (ul64AddressKey < pEntry->ul64AddressKey)
  616. {
  617. pParent = pEntry;
  618. SLink = RtlLeftChild(SLink);
  619. continue;
  620. }
  621. else if (ul64AddressKey > pEntry->ul64AddressKey)
  622. {
  623. pParent = pEntry;
  624. SLink = RtlRightChild(SLink);
  625. continue;
  626. }
  627. else if (ucProtocol < pEntry->ucProtocol)
  628. {
  629. pParent = pEntry;
  630. SLink = RtlLeftChild(SLink);
  631. continue;
  632. }
  633. else if (ucProtocol > pEntry->ucProtocol)
  634. {
  635. pParent = pEntry;
  636. SLink = RtlRightChild(SLink);
  637. continue;
  638. }
  639. else if (ulPortKey < pEntry->ulPortKey[NsOutboundDirection])
  640. {
  641. pParent = pEntry;
  642. SLink = RtlLeftChild(SLink);
  643. continue;
  644. }
  645. else if (ulPortKey > pEntry->ulPortKey[NsOutboundDirection])
  646. {
  647. pParent = pEntry;
  648. SLink = RtlRightChild(SLink);
  649. continue;
  650. }
  651. //
  652. // We found the entry -- update cache and return
  653. //
  654. UpdateCache(
  655. NsConnectionCache,
  656. (ULONG)ul64AddressKey,
  657. (PVOID)pEntry
  658. );
  659. return pEntry;
  660. }
  661. //
  662. // Not found -- provide insertion point if requested
  663. //
  664. if (ppInsertionPoint)
  665. {
  666. *ppInsertionPoint = pParent;
  667. }
  668. return NULL;
  669. } // NsLookupOutboundConnectionEntry
  670. PNS_CONNECTION_ENTRY
  671. NspInsertInboundConnectionEntry(
  672. PNS_CONNECTION_ENTRY pParent,
  673. PNS_CONNECTION_ENTRY pEntry
  674. )
  675. /*++
  676. Routine Description:
  677. This routine inserts a connection entry into the tree.
  678. Arguments:
  679. pParent - the node to be the parent for the new connection entry.
  680. If NULL, the new entry becomes the root.
  681. pEntry - the new connection entry to be inserted.
  682. Return Value:
  683. PNS_CONNECTION_ENTRY - The new root of the tree.
  684. If insertion fails, returns NULL.
  685. Environment:
  686. Invoked with 'NsConnectionLock' held by the caller.
  687. --*/
  688. {
  689. PRTL_SPLAY_LINKS pRoot;
  690. ASSERT(NULL != pEntry);
  691. if (NULL == pParent)
  692. {
  693. //
  694. // The new entry is to be the root.
  695. //
  696. return pEntry;
  697. }
  698. //
  699. // Insert as left or right child. Keys are checked in the
  700. // following order:
  701. //
  702. // 1. Address Key
  703. // 2. Protocol
  704. // 3. Inbound port key
  705. // 4. IpSec context
  706. //
  707. if (pEntry->ul64AddressKey < pParent->ul64AddressKey)
  708. {
  709. RtlInsertAsLeftChild(
  710. &pParent->SLink[NsInboundDirection],
  711. &pEntry->SLink[NsInboundDirection]
  712. );
  713. }
  714. else if (pEntry->ul64AddressKey > pParent->ul64AddressKey)
  715. {
  716. RtlInsertAsRightChild(
  717. &pParent->SLink[NsInboundDirection],
  718. &pEntry->SLink[NsInboundDirection]
  719. );
  720. }
  721. else if (pEntry->ucProtocol < pParent->ucProtocol)
  722. {
  723. RtlInsertAsLeftChild(
  724. &pParent->SLink[NsInboundDirection],
  725. &pEntry->SLink[NsInboundDirection]
  726. );
  727. }
  728. else if (pEntry->ucProtocol > pParent->ucProtocol)
  729. {
  730. RtlInsertAsRightChild(
  731. &pParent->SLink[NsInboundDirection],
  732. &pEntry->SLink[NsInboundDirection]
  733. );
  734. }
  735. else if (pEntry->ulPortKey[NsInboundDirection] < pParent->ulPortKey[NsInboundDirection])
  736. {
  737. RtlInsertAsLeftChild(
  738. &pParent->SLink[NsInboundDirection],
  739. &pEntry->SLink[NsInboundDirection]
  740. );
  741. }
  742. else if (pEntry->ulPortKey[NsInboundDirection] > pParent->ulPortKey[NsInboundDirection])
  743. {
  744. RtlInsertAsRightChild(
  745. &pParent->SLink[NsInboundDirection],
  746. &pEntry->SLink[NsInboundDirection]
  747. );
  748. }
  749. else if (pEntry->pvIpSecContext < pParent->pvIpSecContext)
  750. {
  751. RtlInsertAsLeftChild(
  752. &pParent->SLink[NsInboundDirection],
  753. &pEntry->SLink[NsInboundDirection]
  754. );
  755. }
  756. else if (pEntry->pvIpSecContext > pParent->pvIpSecContext)
  757. {
  758. RtlInsertAsRightChild(
  759. &pParent->SLink[NsInboundDirection],
  760. &pEntry->SLink[NsInboundDirection]
  761. );
  762. }
  763. else
  764. {
  765. //
  766. // Duplicate entry -- this should not happen.
  767. //
  768. ASSERT(FALSE);
  769. return NULL;
  770. }
  771. //
  772. // Splay the new node and return the resulting root.
  773. //
  774. pRoot = RtlSplay(&pEntry->SLink[NsInboundDirection]);
  775. return CONTAINING_RECORD(pRoot, NS_CONNECTION_ENTRY, SLink[NsInboundDirection]);
  776. } // NspInsertInboundConnectionEntry
  777. PNS_CONNECTION_ENTRY
  778. NspInsertOutboundConnectionEntry(
  779. PNS_CONNECTION_ENTRY pParent,
  780. PNS_CONNECTION_ENTRY pEntry
  781. )
  782. /*++
  783. Routine Description:
  784. This routine inserts a connection entry into the tree.
  785. Arguments:
  786. pParent - the node to be the parent for the new connection entry.
  787. If NULL, the new entry becomes the root.
  788. pEntry - the new connection entry to be inserted.
  789. Return Value:
  790. PNS_CONNECTION_ENTRY - The new root of the tree.
  791. If insertion fails, returns NULL.
  792. Environment:
  793. Invoked with 'NsConnectionLock' held by the caller.
  794. --*/
  795. {
  796. PRTL_SPLAY_LINKS pRoot;
  797. ASSERT(NULL != pEntry);
  798. if (NULL == pParent)
  799. {
  800. //
  801. // The new entry is to be the root.
  802. //
  803. return pEntry;
  804. }
  805. //
  806. // Insert as left or right child. Keys are checked in the
  807. // following order:
  808. //
  809. // 1. Address Key
  810. // 2. Protocol
  811. // 3. Outbound port key
  812. //
  813. if (pEntry->ul64AddressKey < pParent->ul64AddressKey)
  814. {
  815. RtlInsertAsLeftChild(
  816. &pParent->SLink[NsOutboundDirection],
  817. &pEntry->SLink[NsOutboundDirection]
  818. );
  819. }
  820. else if (pEntry->ul64AddressKey > pParent->ul64AddressKey)
  821. {
  822. RtlInsertAsRightChild(
  823. &pParent->SLink[NsOutboundDirection],
  824. &pEntry->SLink[NsOutboundDirection]
  825. );
  826. }
  827. else if (pEntry->ucProtocol < pParent->ucProtocol)
  828. {
  829. RtlInsertAsLeftChild(
  830. &pParent->SLink[NsOutboundDirection],
  831. &pEntry->SLink[NsOutboundDirection]
  832. );
  833. }
  834. else if (pEntry->ucProtocol > pParent->ucProtocol)
  835. {
  836. RtlInsertAsRightChild(
  837. &pParent->SLink[NsOutboundDirection],
  838. &pEntry->SLink[NsOutboundDirection]
  839. );
  840. }
  841. else if (pEntry->ulPortKey[NsOutboundDirection] < pParent->ulPortKey[NsOutboundDirection])
  842. {
  843. RtlInsertAsLeftChild(
  844. &pParent->SLink[NsOutboundDirection],
  845. &pEntry->SLink[NsOutboundDirection]
  846. );
  847. }
  848. else if (pEntry->ulPortKey[NsOutboundDirection] > pParent->ulPortKey[NsOutboundDirection])
  849. {
  850. RtlInsertAsRightChild(
  851. &pParent->SLink[NsOutboundDirection],
  852. &pEntry->SLink[NsOutboundDirection]
  853. );
  854. }
  855. else
  856. {
  857. //
  858. // Duplicate entry -- this should not happen.
  859. //
  860. ASSERT(FALSE);
  861. return NULL;
  862. }
  863. //
  864. // Splay the new node and return the resulting root.
  865. //
  866. pRoot = RtlSplay(&pEntry->SLink[NsOutboundDirection]);
  867. return CONTAINING_RECORD(pRoot, NS_CONNECTION_ENTRY, SLink[NsOutboundDirection]);
  868. } // NspInsertOutboundConnectionEntry
  869. VOID
  870. NsShutdownConnectionManagement(
  871. VOID
  872. )
  873. /*++
  874. Routine Description:
  875. This routine is invoked to shutdown the connection management module.
  876. Arguments:
  877. none.
  878. Return Value:
  879. none.
  880. Environment:
  881. Invoked with no references made to any connection entry.
  882. --*/
  883. {
  884. KIRQL Irql;
  885. PNS_CONNECTION_ENTRY pEntry;
  886. CALLTRACE(("NsShutdownConnectionManagement\n"));
  887. KeAcquireSpinLock(&NsConnectionLock, &Irql);
  888. while (!IsListEmpty(&NsConnectionList))
  889. {
  890. pEntry =
  891. CONTAINING_RECORD(
  892. RemoveHeadList(&NsConnectionList),
  893. NS_CONNECTION_ENTRY,
  894. Link
  895. );
  896. NsCleanupConnectionEntry(pEntry);
  897. }
  898. NsConnectionTree[NsInboundDirection] = NULL;
  899. NsConnectionTree[NsOutboundDirection] = NULL;
  900. KeReleaseSpinLock(&NsConnectionLock, Irql);
  901. ExDeleteNPagedLookasideList(&NsConnectionLookasideList);
  902. } // NsShutdownConnectionManagement