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.

849 lines
19 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. director.c
  5. Abstract:
  6. This module contains the code for director management.
  7. Author:
  8. Abolade Gbadegesin (t-abolag) 16-Feb-1998
  9. Revision History:
  10. Abolade Gbadegesin (aboladeg) 19-Apr-1998
  11. Added support for wildcards in protocol/port of a director registration.
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. //
  16. // GLOBAL DATA DEFINITIONS
  17. //
  18. //
  19. // Count of NAT directors
  20. //
  21. ULONG DirectorCount;
  22. //
  23. // List of NAT directors
  24. //
  25. LIST_ENTRY DirectorList;
  26. //
  27. // Spin-lock controlling access to 'DirectorList'
  28. //
  29. KSPIN_LOCK DirectorLock;
  30. //
  31. // Spin-lock controlling access to the 'MappingList' field of all directors
  32. //
  33. KSPIN_LOCK DirectorMappingLock;
  34. VOID
  35. NatCleanupDirector(
  36. PNAT_DIRECTOR Director
  37. )
  38. /*++
  39. Routine Description:
  40. Called to perform final cleanup for an director.
  41. Arguments:
  42. Director - the director to be cleaned up.
  43. Return Value:
  44. none.
  45. --*/
  46. {
  47. KIRQL Irql;
  48. PLIST_ENTRY Link;
  49. PNAT_DYNAMIC_MAPPING Mapping;
  50. CALLTRACE(("NatCleanupDirector\n"));
  51. //
  52. // Detach the director from all of its mappings
  53. //
  54. KeAcquireSpinLock(&DirectorLock, &Irql);
  55. KeAcquireSpinLockAtDpcLevel(&DirectorMappingLock);
  56. for (Link = Director->MappingList.Flink; Link != &Director->MappingList;
  57. Link = Link->Flink) {
  58. Mapping = CONTAINING_RECORD(Link, NAT_DYNAMIC_MAPPING, DirectorLink);
  59. Link = Link->Blink;
  60. NatMappingDetachDirector(
  61. Director,
  62. Mapping->DirectorContext,
  63. Mapping,
  64. NatCleanupDirectorDeleteReason
  65. );
  66. }
  67. KeReleaseSpinLockFromDpcLevel(&DirectorMappingLock);
  68. KeReleaseSpinLock(&DirectorLock, Irql);
  69. if (Director->UnloadHandler) {
  70. Director->UnloadHandler(Director->Context);
  71. }
  72. ExFreePool(Director);
  73. } // NatCleanupDirector
  74. NTSTATUS
  75. NatCreateDirector(
  76. PIP_NAT_REGISTER_DIRECTOR RegisterContext
  77. )
  78. /*++
  79. Routine Description:
  80. This routine is invoked when an director attempts to register.
  81. It handles creation of a context-block for the director.
  82. Arguments:
  83. RegisterContext - information about the registering director
  84. Return Value:
  85. NTSTATUS - status code.
  86. --*/
  87. {
  88. PNAT_DIRECTOR Director;
  89. PLIST_ENTRY InsertionPoint;
  90. KIRQL Irql;
  91. ULONG Key;
  92. CALLTRACE(("NatCreateDirector\n"));
  93. RegisterContext->DirectorHandle = NULL;
  94. //
  95. // Validate the registration information
  96. //
  97. if (!RegisterContext->QueryHandler &&
  98. !RegisterContext->CreateHandler &&
  99. !RegisterContext->DeleteHandler &&
  100. !RegisterContext->UnloadHandler) {
  101. ERROR(("NatCreateDirector: bad argument\n"));
  102. return STATUS_INVALID_PARAMETER;
  103. }
  104. //
  105. // Allocate a new director-struct
  106. //
  107. Director =
  108. ExAllocatePoolWithTag(
  109. NonPagedPool, sizeof(NAT_DIRECTOR), NAT_TAG_DIRECTOR
  110. );
  111. if (!Director) {
  112. ERROR(("NatCreateDirector: allocation failed\n"));
  113. return STATUS_NO_MEMORY;
  114. }
  115. KeInitializeSpinLock(&Director->Lock);
  116. Director->ReferenceCount = 1;
  117. Director->Flags = RegisterContext->Flags;
  118. Director->Key =
  119. MAKE_DIRECTOR_KEY(RegisterContext->Protocol, RegisterContext->Port);
  120. InitializeListHead(&Director->MappingList);
  121. Director->Context = RegisterContext->DirectorContext;
  122. Director->CreateHandler = RegisterContext->CreateHandler;
  123. Director->DeleteHandler = RegisterContext->DeleteHandler;
  124. Director->QueryHandler = RegisterContext->QueryHandler;
  125. Director->UnloadHandler = RegisterContext->UnloadHandler;
  126. KeAcquireSpinLock(&DirectorLock, &Irql);
  127. if (NatLookupDirector(Director->Key, &InsertionPoint)) {
  128. KeReleaseSpinLock(&DirectorLock, Irql);
  129. ERROR(
  130. ("NatCreateDirector: duplicate director %d/%d\n",
  131. RegisterContext->Protocol, RegisterContext->Port)
  132. );
  133. ExFreePool(Director);
  134. return STATUS_UNSUCCESSFUL;
  135. }
  136. InsertTailList(InsertionPoint, &Director->Link);
  137. KeReleaseSpinLock(&DirectorLock, Irql);
  138. InterlockedIncrement(&DirectorCount);
  139. //
  140. // Supply the caller with 'out' information
  141. //
  142. RegisterContext->DirectorHandle = (PVOID)Director;
  143. RegisterContext->QueryInfoSession = NatDirectorQueryInfoSession;
  144. RegisterContext->Deregister = NatDirectorDeregister;
  145. RegisterContext->DissociateSession = NatDirectorDissociateSession;
  146. return STATUS_SUCCESS;
  147. } // NatCreateDirector
  148. NTSTATUS
  149. NatDeleteDirector(
  150. PNAT_DIRECTOR Director
  151. )
  152. /*++
  153. Routine Description:
  154. Handles director deletion.
  155. Arguments:
  156. Director - specifies the director to be deleted.
  157. Return Value
  158. NTSTATUS - status code.
  159. --*/
  160. {
  161. KIRQL Irql;
  162. CALLTRACE(("NatDeleteDirector\n"));
  163. if (!Director) { return STATUS_INVALID_PARAMETER; }
  164. InterlockedDecrement(&DirectorCount);
  165. //
  166. // Remove the director from the list
  167. //
  168. KeAcquireSpinLock(&DirectorLock, &Irql);
  169. RemoveEntryList(&Director->Link);
  170. Director->Flags |= NAT_DIRECTOR_FLAG_DELETED;
  171. KeReleaseSpinLock(&DirectorLock, Irql);
  172. //
  173. // Drop its reference count and cleanup if necessary
  174. //
  175. if (InterlockedDecrement(&Director->ReferenceCount) > 0) {
  176. return STATUS_PENDING;
  177. }
  178. NatCleanupDirector(Director);
  179. return STATUS_SUCCESS;
  180. } // NatDeleteDirector
  181. VOID
  182. NatInitializeDirectorManagement(
  183. VOID
  184. )
  185. /*++
  186. Routine Description:
  187. This routine prepares the director-management module for operation.
  188. Arguments:
  189. none.
  190. Return Value:
  191. none.
  192. --*/
  193. {
  194. CALLTRACE(("NatInitializeDirectorManagement\n"));
  195. DirectorCount = 0;
  196. KeInitializeSpinLock(&DirectorLock);
  197. InitializeListHead(&DirectorList);
  198. KeInitializeSpinLock(&DirectorMappingLock);
  199. } // NatInitializeDirectorManagement
  200. PNAT_DIRECTOR
  201. NatLookupAndReferenceDirector(
  202. UCHAR Protocol,
  203. USHORT Port
  204. )
  205. /*++
  206. Routine Description:
  207. This routine is called to search for a director for the given
  208. incoming protocol and port, and to obtain a referenced pointer
  209. to such a director.
  210. This routine must be invoked at DISPATCH_LEVEL.
  211. Arguments:
  212. Protocol - the protocol of the director to be looked up
  213. Port - the port-number of the director to be looked up
  214. Return Value:
  215. PNAT_DIRECTOR - the references director if found; NULL otherwise.
  216. --*/
  217. {
  218. PNAT_DIRECTOR Director;
  219. ULONG Key;
  220. PLIST_ENTRY Link;
  221. KeAcquireSpinLockAtDpcLevel(&DirectorLock);
  222. if (IsListEmpty(&DirectorList)) {
  223. KeReleaseSpinLockFromDpcLevel(&DirectorLock); return NULL;
  224. }
  225. Key = MAKE_DIRECTOR_KEY(Protocol, Port);
  226. //
  227. // Our support for wildcards takes advantage of the fact that
  228. // all wildcards are designated by zero; hence, since our list
  229. // is in descending order we only need to look for wildcards
  230. // at the point where we would break off a normal search.
  231. //
  232. for (Link = DirectorList.Flink; Link != &DirectorList; Link = Link->Flink) {
  233. Director = CONTAINING_RECORD(Link, NAT_DIRECTOR, Link);
  234. if (Key < Director->Key) {
  235. continue;
  236. } else if (Key > Director->Key) {
  237. //
  238. // End of normal search. Now look for wildcards
  239. //
  240. do {
  241. if ((!DIRECTOR_KEY_PROTOCOL(Director->Key) ||
  242. Protocol == DIRECTOR_KEY_PROTOCOL(Director->Key)) &&
  243. (!DIRECTOR_KEY_PORT(Director->Key) ||
  244. Port == DIRECTOR_KEY_PORT(Director->Key))) {
  245. //
  246. // We have a matching wildcard.
  247. //
  248. break;
  249. }
  250. Link = Link->Flink;
  251. Director = CONTAINING_RECORD(Link, NAT_DIRECTOR, Link);
  252. } while (Link != &DirectorList);
  253. if (Link == &DirectorList) { break; }
  254. }
  255. //
  256. // We've found it. Reference it and return.
  257. //
  258. if (!NatReferenceDirector(Director)) { Director = NULL; }
  259. KeReleaseSpinLockFromDpcLevel(&DirectorLock);
  260. return Director;
  261. }
  262. KeReleaseSpinLockFromDpcLevel(&DirectorLock);
  263. return NULL;
  264. } // NatLookupAndReferenceDirector
  265. PNAT_DIRECTOR
  266. NatLookupDirector(
  267. ULONG Key,
  268. PLIST_ENTRY* InsertionPoint
  269. )
  270. /*++
  271. Routine Description:
  272. This routine is called to retrieve the director corresponding to the given
  273. key.
  274. Arguments:
  275. Key - the key for which an director is to be found
  276. InsertionPoint - receives the point at which the director should be
  277. inserted if not found
  278. Return Value:
  279. PNAT_DIRECTOR - the required director, if found
  280. --*/
  281. {
  282. PNAT_DIRECTOR Director;
  283. PLIST_ENTRY Link;
  284. for (Link = DirectorList.Flink; Link != &DirectorList; Link = Link->Flink) {
  285. Director = CONTAINING_RECORD(Link, NAT_DIRECTOR, Link);
  286. if (Key < Director->Key) {
  287. continue;
  288. } else if (Key > Director->Key) {
  289. break;
  290. }
  291. return Director;
  292. }
  293. if (InsertionPoint) { *InsertionPoint = Link; }
  294. return NULL;
  295. } // NatLookupDirector
  296. VOID
  297. NatMappingAttachDirector(
  298. PNAT_DIRECTOR Director,
  299. PVOID DirectorSessionContext,
  300. PNAT_DYNAMIC_MAPPING Mapping
  301. )
  302. /*++
  303. Routine Description:
  304. This routine is invoked to attach a mapping to a director.
  305. It serves as a notification that there is one more mapping
  306. associated with the director.
  307. Arguments:
  308. Director - the director for the mapping
  309. DirectorSessionContext - context associated with the mapping by the director
  310. Mapping - the mapping to be attached.
  311. Return Value:
  312. none.
  313. Environment:
  314. Always invoked at dispatch level with 'DirectorLock' and
  315. 'DirectorMappingLock' held by the caller.
  316. --*/
  317. {
  318. Mapping->Director = Director;
  319. Mapping->DirectorContext = DirectorSessionContext;
  320. InsertTailList(&Director->MappingList, &Mapping->DirectorLink);
  321. if (Director->CreateHandler) {
  322. Director->CreateHandler(
  323. Mapping,
  324. Director->Context,
  325. DirectorSessionContext
  326. );
  327. }
  328. } // NatMappingAttachDirector
  329. VOID
  330. NatMappingDetachDirector(
  331. PNAT_DIRECTOR Director,
  332. PVOID DirectorSessionContext,
  333. PNAT_DYNAMIC_MAPPING Mapping,
  334. IP_NAT_DELETE_REASON DeleteReason
  335. )
  336. /*++
  337. Routine Description:
  338. This routine is invoked to detach a mapping from a director.
  339. It serves as a notification that there is one less mapping
  340. associated with the director.
  341. Arguments:
  342. Director - director to be detached
  343. DirectorSessionContext - context associated with the director
  344. Mapping - the mapping to be detached, or NULL if a mapping could not be
  345. created.
  346. Return Value:
  347. none.
  348. Environment:
  349. Always invoked at dispatch level with 'DirectorLock' and
  350. 'DirectorMappingLock' held, in that order.
  351. --*/
  352. {
  353. KIRQL Irql;
  354. if (!Mapping) {
  355. if (Director->DeleteHandler) {
  356. Director->DeleteHandler(
  357. NULL,
  358. Director->Context,
  359. DirectorSessionContext,
  360. DeleteReason
  361. );
  362. }
  363. } else {
  364. if (Director->DeleteHandler) {
  365. Director->DeleteHandler(
  366. Mapping,
  367. Director->Context,
  368. Mapping->DirectorContext,
  369. DeleteReason
  370. );
  371. }
  372. RemoveEntryList(&Mapping->DirectorLink);
  373. Mapping->Director = NULL;
  374. Mapping->DirectorContext = NULL;
  375. }
  376. } // NatMappingDetachDirector
  377. NTSTATUS
  378. NatQueryDirectorTable(
  379. IN PIP_NAT_ENUMERATE_DIRECTORS InputBuffer,
  380. IN PIP_NAT_ENUMERATE_DIRECTORS OutputBuffer,
  381. IN PULONG OutputBufferLength
  382. )
  383. /*++
  384. Routine Description:
  385. This routine is used for enumerating the registered directors.
  386. Arguments:
  387. InputBuffer - supplies context information for the information
  388. OutputBuffer - receives the result of the enumeration
  389. OutputBufferLength - size of the i/o buffer
  390. Return Value:
  391. STATUS_SUCCESS if successful, error code otherwise.
  392. --*/
  393. {
  394. ULONG Count;
  395. ULONG i;
  396. KIRQL Irql;
  397. ULONG Key;
  398. PLIST_ENTRY Link;
  399. PNAT_DIRECTOR Director;
  400. NTSTATUS status;
  401. PIP_NAT_DIRECTOR Table;
  402. CALLTRACE(("NatQueryDirectorTable\n"));
  403. Key = InputBuffer->EnumerateContext;
  404. KeAcquireSpinLock(&DirectorLock, &Irql);
  405. //
  406. // See if this is a new enumeration or a continuation of an old one.
  407. //
  408. if (!Key) {
  409. //
  410. // This is a new enumeration. We start with the first item
  411. // in the list of entries
  412. //
  413. Director =
  414. IsListEmpty(&DirectorList)
  415. ? NULL
  416. : CONTAINING_RECORD(DirectorList.Flink, NAT_DIRECTOR, Link);
  417. } else {
  418. //
  419. // This is a continuation. The context therefore contains
  420. // the key for the next entry.
  421. //
  422. Director = NatLookupDirector(Key, NULL);
  423. }
  424. if (!Director) {
  425. OutputBuffer->EnumerateCount = 0;
  426. OutputBuffer->EnumerateContext = 0;
  427. OutputBuffer->EnumerateTotalHint = DirectorCount;
  428. *OutputBufferLength =
  429. FIELD_OFFSET(IP_NAT_ENUMERATE_DIRECTORS, EnumerateTable);
  430. KeReleaseSpinLock(&DirectorLock, Irql);
  431. return STATUS_SUCCESS;
  432. }
  433. //
  434. // Compute the maximum number of entries we can store
  435. //
  436. Count =
  437. *OutputBufferLength -
  438. FIELD_OFFSET(IP_NAT_ENUMERATE_DIRECTORS, EnumerateTable);
  439. Count /= sizeof(IP_NAT_DIRECTOR);
  440. //
  441. // Walk the list storing entries in the caller's buffer
  442. //
  443. Table = OutputBuffer->EnumerateTable;
  444. for (i = 0, Link = &Director->Link; i < Count && Link != &DirectorList;
  445. i++, Link = Link->Flink) {
  446. Director = CONTAINING_RECORD(Link, NAT_DIRECTOR, Link);
  447. Table[i].Protocol = DIRECTOR_KEY_PROTOCOL(Director->Key);
  448. Table[i].Port = DIRECTOR_KEY_PORT(Director->Key);
  449. }
  450. //
  451. // The enumeration is over; update the output structure
  452. //
  453. *OutputBufferLength =
  454. i * sizeof(IP_NAT_DIRECTOR) +
  455. FIELD_OFFSET(IP_NAT_ENUMERATE_DIRECTORS, EnumerateTable);
  456. OutputBuffer->EnumerateCount = i;
  457. OutputBuffer->EnumerateTotalHint = DirectorCount;
  458. if (Link == &DirectorList) {
  459. //
  460. // We reached the end of the list
  461. //
  462. OutputBuffer->EnumerateContext = 0;
  463. } else {
  464. //
  465. // Save the continuation context
  466. //
  467. OutputBuffer->EnumerateContext =
  468. CONTAINING_RECORD(Link, NAT_DIRECTOR, Link)->Key;
  469. }
  470. KeReleaseSpinLock(&DirectorLock, Irql);
  471. return STATUS_SUCCESS;
  472. } // NatQueryDirectorTable
  473. VOID
  474. NatShutdownDirectorManagement(
  475. VOID
  476. )
  477. /*++
  478. Routine Description:
  479. This routine shuts down the director-management module.
  480. Arguments:
  481. none.
  482. Return Value:
  483. none.
  484. --*/
  485. {
  486. PNAT_DIRECTOR Director;
  487. KIRQL Irql;
  488. CALLTRACE(("NatShutdownDirectorManagement\n"));
  489. //
  490. // Delete all directors
  491. //
  492. KeAcquireSpinLock(&DirectorLock, &Irql);
  493. while (!IsListEmpty(&DirectorList)) {
  494. Director = CONTAINING_RECORD(DirectorList.Flink, NAT_DIRECTOR, Link);
  495. RemoveEntryList(&Director->Link);
  496. KeReleaseSpinLockFromDpcLevel(&DirectorLock);
  497. NatCleanupDirector(Director);
  498. KeAcquireSpinLockAtDpcLevel(&DirectorLock);
  499. }
  500. KeReleaseSpinLock(&DirectorLock, Irql);
  501. } // NatShutdownDirectorManagement
  502. //
  503. // DIRECTOR HELPER ROUTINES
  504. //
  505. // The caller is assumed to be running at DISPATCH_LEVEL.
  506. //
  507. NTSTATUS
  508. NatDirectorDeregister(
  509. IN PVOID DirectorHandle
  510. )
  511. /*++
  512. Routine Description:
  513. This routine is called by a director to remove itself
  514. from the director list.
  515. Arguments:
  516. DirectorHandle - handle of the director to be removed.
  517. Return Value:
  518. NTSTATUS - status code.
  519. --*/
  520. {
  521. CALLTRACE(("NatDirectorDeregister\n"));
  522. return NatDeleteDirector((PNAT_DIRECTOR)DirectorHandle);
  523. } // NatDirectorDeregister
  524. NTSTATUS
  525. NatDirectorDissociateSession(
  526. IN PVOID DirectorHandle,
  527. IN PVOID SessionHandle
  528. )
  529. /*++
  530. Routine Description:
  531. This routine is called by a director to dissociate itself from a specific
  532. session.
  533. Arguments:
  534. DirectorHandle - the director which wishes to dissociate itself.
  535. SessionHandle - the session from which the director is disssociating itself.
  536. Return Value:
  537. NTSTATUS - indicates success/failure
  538. Environment:
  539. Invoked at dispatch level with neither 'DirectorLock' nor
  540. 'DirectorMappingLock' held by the caller.
  541. --*/
  542. {
  543. PNAT_DIRECTOR Director = (PNAT_DIRECTOR)DirectorHandle;
  544. KIRQL Irql;
  545. PNAT_DYNAMIC_MAPPING Mapping = (PNAT_DYNAMIC_MAPPING)SessionHandle;
  546. CALLTRACE(("NatDirectorDissociateSession\n"));
  547. KeAcquireSpinLock(&DirectorLock, &Irql);
  548. if (Mapping->Director != Director) {
  549. KeReleaseSpinLock(&DirectorLock, Irql);
  550. return STATUS_INVALID_PARAMETER;
  551. }
  552. KeAcquireSpinLockAtDpcLevel(&DirectorMappingLock);
  553. NatMappingDetachDirector(
  554. Director,
  555. Mapping->DirectorContext,
  556. Mapping,
  557. NatDissociateDirectorDeleteReason
  558. );
  559. KeReleaseSpinLockFromDpcLevel(&DirectorMappingLock);
  560. if (!NAT_MAPPING_DELETE_ON_DISSOCIATE_DIRECTOR(Mapping)) {
  561. KeReleaseSpinLock(&DirectorLock, Irql);
  562. } else {
  563. KeReleaseSpinLockFromDpcLevel(&DirectorLock);
  564. KeAcquireSpinLockAtDpcLevel(&MappingLock);
  565. NatDeleteMapping(Mapping);
  566. KeReleaseSpinLock(&MappingLock, Irql);
  567. }
  568. return STATUS_SUCCESS;
  569. } // NatDirectorDissociateSession
  570. VOID
  571. NatDirectorQueryInfoSession(
  572. IN PVOID SessionHandle,
  573. OUT PIP_NAT_SESSION_MAPPING_STATISTICS Statistics OPTIONAL
  574. )
  575. /*++
  576. Routine Description:
  577. This routine is invoked by a director to obtain information
  578. about a session.
  579. Arguments:
  580. SessionHandle - the session for which information is required
  581. Statistics - receives statistics for the session
  582. Return Value:
  583. none.
  584. Environment:
  585. Invoked
  586. --*/
  587. {
  588. KIRQL Irql;
  589. KeAcquireSpinLock(&MappingLock, &Irql);
  590. NatQueryInformationMapping(
  591. (PNAT_DYNAMIC_MAPPING)SessionHandle,
  592. NULL,
  593. NULL,
  594. NULL,
  595. NULL,
  596. NULL,
  597. NULL,
  598. NULL,
  599. Statistics
  600. );
  601. KeReleaseSpinLock(&MappingLock, Irql);
  602. } // NatDirectorQueryInfoSession