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.

1384 lines
34 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. if.c
  5. Abstract:
  6. This file contains code for interface management.
  7. Author:
  8. Abolade Gbadegesin (t-abolag) 12-July-1997
  9. Revision History:
  10. Abolade Gbadegesin (aboladeg) 19-July-1998
  11. Substantially rewritten as part of change to a global mapping-tree.
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. //
  16. // GLOBAL DATA DEFINITIONS
  17. //
  18. ULONG FirewalledInterfaceCount;
  19. CACHE_ENTRY InterfaceCache[CACHE_SIZE];
  20. ULONG InterfaceCount;
  21. LIST_ENTRY InterfaceList;
  22. KSPIN_LOCK InterfaceLock;
  23. KSPIN_LOCK InterfaceMappingLock;
  24. VOID
  25. NatCleanupInterface(
  26. PNAT_INTERFACE Interfacep
  27. )
  28. /*++
  29. Routine Description:
  30. Called to perform cleanup for an interface.
  31. On completion, the memory for the interface is freed and its context
  32. becomes invalid.
  33. Arguments:
  34. Interfacep - the interface to be cleaned up.
  35. Return Value:
  36. none.
  37. Environment:
  38. Invoked with no references to 'Interfacep', and with 'Interfacep' already
  39. removed from the interface list.
  40. --*/
  41. {
  42. KIRQL Irql;
  43. CALLTRACE(("NatCleanupInterface\n"));
  44. InterlockedClearCache(InterfaceCache, Interfacep->Index);
  45. KeAcquireSpinLock(&InterfaceLock, &Irql);
  46. NatResetInterface(Interfacep);
  47. KeReleaseSpinLock(&InterfaceLock, Irql);
  48. if (Interfacep->AddressArray) { ExFreePool(Interfacep->AddressArray); }
  49. if (Interfacep->Info) { ExFreePool(Interfacep->Info); }
  50. ExFreePool(Interfacep);
  51. InterlockedDecrement(&InterfaceCount);
  52. } // NatCleanupInterface
  53. LONG
  54. FASTCALL
  55. NatCompareAddressMappingCallback(
  56. VOID* a,
  57. VOID* b
  58. )
  59. /*++
  60. Routine Description:
  61. This routine is the callback invoked by our sorting routine
  62. when we ask it to sort the array of configured address-mappings.
  63. The sorting treats the 'PublicAddress' field as an integer.
  64. Arguments:
  65. a - first mapping
  66. b - second mapping
  67. Return Value:
  68. LONG - the result of the comparison (<0, ==0, >0).
  69. --*/
  70. {
  71. return
  72. ((PIP_NAT_ADDRESS_MAPPING)a)->PrivateAddress -
  73. ((PIP_NAT_ADDRESS_MAPPING)b)->PrivateAddress;
  74. }
  75. LONG
  76. FASTCALL
  77. NatComparePortMappingCallback(
  78. VOID* a,
  79. VOID* b
  80. )
  81. /*++
  82. Routine Description:
  83. This routine is the callback invoked by our sorting routine
  84. when we ask it to sort the array of configured port-mappings.
  85. The sorting catenates the 'Protocol' and 'PublicPort' fields
  86. and treats the result as a 24 bit integer.
  87. Arguments:
  88. a - first mapping
  89. b - second mapping
  90. Return Value:
  91. LONG - the result of the comparison (<0, ==0, >0).
  92. --*/
  93. {
  94. return
  95. (((PIP_NAT_PORT_MAPPING)a)->Protocol -
  96. ((PIP_NAT_PORT_MAPPING)b)->Protocol) ||
  97. (((PIP_NAT_PORT_MAPPING)a)->PublicPort -
  98. ((PIP_NAT_PORT_MAPPING)b)->PublicPort);
  99. }
  100. NTSTATUS
  101. NatConfigureInterface(
  102. IN PIP_NAT_INTERFACE_INFO InterfaceInfo,
  103. IN PFILE_OBJECT FileObject
  104. )
  105. /*++
  106. Routine Description:
  107. This routine handles the (re)configuration of an interface on receipt
  108. of IOCTL_IP_NAT_SET_INTERFACE_INFO from a user-mode client.
  109. Arguments:
  110. InterfaceInfo - contains the new configuration
  111. FileObject - file-object of the requestor
  112. Return Value:
  113. NTSTATUS - status code.
  114. --*/
  115. {
  116. PRTR_TOC_ENTRY Entry;
  117. PRTR_INFO_BLOCK_HEADER Header;
  118. ULONG i;
  119. PIP_NAT_INTERFACE_INFO Info;
  120. PNAT_INTERFACE Interfacep;
  121. ULONG Index;
  122. KIRQL Irql;
  123. ULONG j;
  124. ULONG Size;
  125. NTSTATUS status = STATUS_SUCCESS;
  126. BOOLEAN WaitRequired;
  127. CALLTRACE(("NatConfigureInterface\n"));
  128. //
  129. // Create a copy of the new configuration;
  130. // we must do this before raising IRQL since 'InterfaceInfo' may be
  131. // a pageable user-mode buffer.
  132. //
  133. Header = &InterfaceInfo->Header;
  134. Size = FIELD_OFFSET(IP_NAT_INTERFACE_INFO, Header) + Header->Size;
  135. Info = ExAllocatePoolWithTag(NonPagedPool, Size, NAT_TAG_IF_CONFIG);
  136. if (!Info) {
  137. ERROR(("NatConfigureInterface: allocation failed\n"));
  138. return STATUS_NO_MEMORY;
  139. }
  140. RtlCopyMemory(Info, InterfaceInfo, Size);
  141. //
  142. // Lookup the interface to be configured
  143. //
  144. KeAcquireSpinLock(&InterfaceLock, &Irql);
  145. Interfacep = NatLookupInterface(InterfaceInfo->Index, NULL);
  146. if (!Interfacep || Interfacep->FileObject != FileObject) {
  147. KeReleaseSpinLock(&InterfaceLock, Irql);
  148. ExFreePool(Info);
  149. return STATUS_INVALID_PARAMETER;
  150. }
  151. NatReferenceInterface(Interfacep);
  152. KeAcquireSpinLockAtDpcLevel(&Interfacep->Lock);
  153. NatResetInterface(Interfacep);
  154. if (NAT_INTERFACE_FW(Interfacep)) {
  155. ASSERT(FirewalledInterfaceCount > 0);
  156. InterlockedDecrement(&FirewalledInterfaceCount);
  157. }
  158. Interfacep->Flags &= ~IP_NAT_INTERFACE_FLAGS_ALL;
  159. Interfacep->Flags |=
  160. (Info->Flags & IP_NAT_INTERFACE_FLAGS_ALL);
  161. if (NAT_INTERFACE_FW(Interfacep)) {
  162. InterlockedIncrement(&FirewalledInterfaceCount);
  163. }
  164. KeReleaseSpinLockFromDpcLevel(&InterfaceLock);
  165. //
  166. // Destroy the original configuration, if any.
  167. //
  168. if (Interfacep->Info) { ExFreePool(Interfacep->Info); }
  169. Interfacep->Info = Info;
  170. Interfacep->AddressRangeCount = 0;
  171. Interfacep->AddressRangeArray = NULL;
  172. Interfacep->AddressMappingCount = 0;
  173. Interfacep->AddressMappingArray = NULL;
  174. Interfacep->PortMappingCount = 0;
  175. Interfacep->PortMappingArray = NULL;
  176. Header = &Interfacep->Info->Header;
  177. //
  178. // Parse the new configuration
  179. //
  180. for (i = 0; i < Header->TocEntriesCount && NT_SUCCESS(status); i++) {
  181. Entry = &Header->TocEntry[i];
  182. switch (Entry->InfoType) {
  183. case IP_NAT_ADDRESS_RANGE_TYPE: {
  184. Interfacep->AddressRangeCount = Entry->Count;
  185. Interfacep->AddressRangeArray =
  186. (PIP_NAT_ADDRESS_RANGE)GetInfoFromTocEntry(Header,Entry);
  187. break;
  188. }
  189. case IP_NAT_PORT_MAPPING_TYPE: {
  190. Interfacep->PortMappingCount = Entry->Count;
  191. Interfacep->PortMappingArray =
  192. (PIP_NAT_PORT_MAPPING)GetInfoFromTocEntry(Header,Entry);
  193. //
  194. // Sort the mappings so that we can do fast lookups
  195. // using binary search later on in the translate-path.
  196. //
  197. status =
  198. ShellSort(
  199. Interfacep->PortMappingArray,
  200. Entry->InfoSize,
  201. Entry->Count,
  202. NatComparePortMappingCallback,
  203. NULL
  204. );
  205. if (!NT_SUCCESS(status)) {
  206. ERROR(("NatConfigureInterface: ShellSort failed\n"));
  207. break;
  208. }
  209. break;
  210. }
  211. case IP_NAT_ADDRESS_MAPPING_TYPE: {
  212. Interfacep->AddressMappingCount = Entry->Count;
  213. Interfacep->AddressMappingArray =
  214. (PIP_NAT_ADDRESS_MAPPING)GetInfoFromTocEntry(Header,Entry);
  215. //
  216. // Sort the mappings so that we can do fast lookups
  217. // using binary search later on in the translate-path.
  218. //
  219. status =
  220. ShellSort(
  221. Interfacep->AddressMappingArray,
  222. Entry->InfoSize,
  223. Entry->Count,
  224. NatCompareAddressMappingCallback,
  225. NULL
  226. );
  227. if (!NT_SUCCESS(status)) {
  228. ERROR(("NatConfigureInterface: ShellSort failed\n"));
  229. break;
  230. }
  231. break;
  232. }
  233. case IP_NAT_ICMP_CONFIG_TYPE: {
  234. Interfacep->IcmpFlags =
  235. *(PULONG) GetInfoFromTocEntry(Header,Entry);
  236. break;
  237. }
  238. }
  239. }
  240. InterlockedExchange(
  241. &Interfacep->NoStaticMappingExists,
  242. !(Interfacep->AddressMappingCount || Interfacep->PortMappingCount)
  243. );
  244. if (NT_SUCCESS(status)) {
  245. status = NatCreateAddressPool(Interfacep);
  246. }
  247. if (!NT_SUCCESS(status)) {
  248. KeReleaseSpinLockFromDpcLevel(&Interfacep->Lock);
  249. KeAcquireSpinLockAtDpcLevel(&InterfaceLock);
  250. KeAcquireSpinLockAtDpcLevel(&Interfacep->Lock);
  251. NatResetInterface(Interfacep);
  252. KeReleaseSpinLockFromDpcLevel(&InterfaceLock);
  253. }
  254. KeReleaseSpinLock(&Interfacep->Lock, Irql);
  255. NatDereferenceInterface(Interfacep);
  256. return status;
  257. } // NatConfigureInterface
  258. USHORT
  259. NatpGetInterfaceMTU(
  260. ULONG index
  261. )
  262. /*++
  263. Routine Description:
  264. This routine returns the MTU of a interface.
  265. The code here is a copy-paste version of those in http.sys.
  266. Arguments:
  267. index - the inteface index
  268. Return Value:
  269. ULONG - the MTU of the specified interface
  270. --*/
  271. {
  272. IFEntry *IFEntryPtr = NULL;
  273. TDIEntityID *EntityTable = NULL, *EntityPtr = NULL;
  274. BYTE IFBuf[sizeof(IFEntry) + MAX_IFDESCR_LEN];
  275. TCP_REQUEST_QUERY_INFORMATION_EX ReqInBuf;
  276. IO_STATUS_BLOCK IoStatus;
  277. KEVENT LocalEvent;
  278. NTSTATUS status = STATUS_SUCCESS;
  279. ULONG InBufLen = 0, OutBufLen = 0;
  280. TDIObjectID *ID = NULL;
  281. USHORT InterfaceMTU = 0;
  282. ULONG i, NumEntities = 0;
  283. HANDLE EventHandle;
  284. CALLTRACE(("NatpGetInterfaceMTU (0x%08X)\n", index));
  285. if (NULL == TcpDeviceHandle) {
  286. return 0;
  287. }
  288. //
  289. // Find the interface instance corresponding to the interface index
  290. //
  291. InBufLen = sizeof(TCP_REQUEST_QUERY_INFORMATION_EX);
  292. OutBufLen = sizeof(TDIEntityID) * MAX_TDI_ENTITIES;
  293. EntityTable =
  294. (TDIEntityID *) ExAllocatePoolWithTag(
  295. PagedPool, OutBufLen, NAT_TAG_IF_CONFIG);
  296. if (!EntityTable)
  297. {
  298. ERROR(("NatpGetInterfaceMTU: TDIEntityID Buffer Allocation Failed\n"));
  299. return 0;
  300. }
  301. RtlZeroMemory(EntityTable, OutBufLen);
  302. RtlZeroMemory(&ReqInBuf, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX));
  303. ID = &(ReqInBuf.ID);
  304. ID->toi_entity.tei_entity = GENERIC_ENTITY;
  305. ID->toi_entity.tei_instance = 0;
  306. ID->toi_class = INFO_CLASS_GENERIC;
  307. ID->toi_type = INFO_TYPE_PROVIDER;
  308. ID->toi_id = ENTITY_LIST_ID;
  309. status = ZwCreateEvent (&EventHandle, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE);
  310. if (!NT_SUCCESS(status)) {
  311. ERROR(("NatpGetInterfaceMTU: ZwCreateEvent = 0x%08X\n", status));
  312. if (EntityTable)
  313. ExFreePool(EntityTable);
  314. return 0;
  315. }
  316. status =
  317. ZwDeviceIoControlFile(
  318. TcpDeviceHandle, // FileHandle
  319. EventHandle, // Event
  320. NULL, // ApcRoutine
  321. NULL, // ApcContext
  322. &IoStatus, // IoStatusBlock
  323. IOCTL_TCP_QUERY_INFORMATION_EX, // IoControlCode
  324. (PVOID)&ReqInBuf, // InputBuffer
  325. InBufLen, // InputBufferLength
  326. (PVOID)EntityTable, // OutputBuffer
  327. OutBufLen // OutputBufferLength
  328. );
  329. if ( STATUS_PENDING == status ) {
  330. ZwWaitForSingleObject(
  331. EventHandle,
  332. FALSE,
  333. NULL
  334. );
  335. status = IoStatus.Status;
  336. }
  337. ZwResetEvent(EventHandle, NULL);
  338. if (!NT_SUCCESS(status)) {
  339. ERROR(("NatpGetInterfaceMTU: TcpQueryInformationEx = 0x%08X\n", status));
  340. if (EntityTable)
  341. ExFreePool(EntityTable);
  342. return 0;
  343. }
  344. //
  345. // Now we have all the TDI entities.
  346. //
  347. NumEntities = ((ULONG)(IoStatus.Information)) / sizeof(TDIEntityID);
  348. TRACE(XLATE, ("NatpGetInterfaceMTU: Find %d TDI entities\n", NumEntities));
  349. // Search through the interface entries
  350. for (i = 0, EntityPtr = EntityTable; i < NumEntities; i++, EntityPtr++)
  351. {
  352. if (EntityPtr->tei_entity == IF_ENTITY)
  353. {
  354. //
  355. // Get the full IFEntry. It's a pitty that we only look at the
  356. // Mtu size after getting such a big structure.
  357. //
  358. OutBufLen = sizeof(IFEntry) + MAX_IFDESCR_LEN;
  359. IFEntryPtr = (IFEntry *)IFBuf;
  360. RtlZeroMemory(IFEntryPtr, OutBufLen);
  361. InBufLen = sizeof(TCP_REQUEST_QUERY_INFORMATION_EX);
  362. RtlZeroMemory(&ReqInBuf,sizeof(TCP_REQUEST_QUERY_INFORMATION_EX));
  363. ID = &(ReqInBuf.ID);
  364. ID->toi_entity.tei_entity = IF_ENTITY;
  365. ID->toi_entity.tei_instance = EntityPtr->tei_instance;
  366. ID->toi_class = INFO_CLASS_PROTOCOL;
  367. ID->toi_type = INFO_TYPE_PROVIDER;
  368. ID->toi_id = IF_MIB_STATS_ID;
  369. status =
  370. ZwDeviceIoControlFile(
  371. TcpDeviceHandle, // FileHandle
  372. EventHandle, // Event
  373. NULL, // ApcRoutine
  374. NULL, // ApcContext
  375. &IoStatus, // IoStatusBlock
  376. IOCTL_TCP_QUERY_INFORMATION_EX, // IoControlCode
  377. (PVOID)&ReqInBuf, // InputBuffer
  378. InBufLen, // InputBufferLength
  379. (PVOID)IFEntryPtr, // OutputBuffer
  380. OutBufLen // OutputBufferLength
  381. );
  382. if ( STATUS_PENDING == status ) {
  383. ZwWaitForSingleObject(
  384. EventHandle,
  385. FALSE,
  386. NULL
  387. );
  388. status = IoStatus.Status;
  389. }
  390. ZwResetEvent(EventHandle, NULL);
  391. if (!NT_SUCCESS(status)) {
  392. ERROR(("NatpGetInterfaceMTU: TcpQueryInformationEx (2) = 0x%08X\n", status));
  393. break;
  394. }
  395. if (IFEntryPtr) {
  396. if (IFEntryPtr->if_index == index) {
  397. //
  398. // find the specific interface so return its MTU.
  399. //
  400. if (IFEntryPtr->if_mtu <= MAXUSHORT)
  401. InterfaceMTU = (USHORT)(IFEntryPtr->if_mtu);
  402. TRACE(
  403. XLATE,
  404. ("NatpGetInterfaceMTU: Interface (0x%08X)'s MTU = %d\n",
  405. index, InterfaceMTU));
  406. break;
  407. }
  408. }
  409. }
  410. }
  411. if (EventHandle) {
  412. ZwClose(EventHandle);
  413. }
  414. if (EntityTable) {
  415. ExFreePool(EntityTable);
  416. }
  417. if (MIN_VALID_MTU > InterfaceMTU) {
  418. return 0;
  419. } else {
  420. return InterfaceMTU;
  421. }
  422. }
  423. NTSTATUS
  424. NatCreateInterface(
  425. IN PIP_NAT_CREATE_INTERFACE CreateInterface,
  426. IN PFILE_OBJECT FileObject
  427. )
  428. /*++
  429. Routine Description:
  430. This routine handles the creation of a NAT interface-object.
  431. The interface is initialized and placed on the interface-list;
  432. the configuration information is later supplied to 'NatConfigureInterface'.
  433. Arguments:
  434. CreateInterface - describes the interface to be created
  435. FileObject - identifies the user-mode process associated with the interface
  436. Return Value:
  437. NTSTATUS - status code.
  438. --*/
  439. {
  440. PNAT_ADDRESS AddressArray;
  441. ULONG AddressCount;
  442. PIP_ADAPTER_BINDING_INFO BindingInfo;
  443. ULONG i;
  444. ULONG Index;
  445. PLIST_ENTRY InsertionPoint;
  446. PNAT_INTERFACE Interfacep;
  447. KIRQL Irql;
  448. USHORT mtu = 0;
  449. CALLTRACE(("NatCreateInterface\n"));
  450. //
  451. // Allocate space for the interface's address.
  452. // We do this before raising IRQL since 'CreateInterface' may be
  453. // a pageable user-mode buffer.
  454. //
  455. // N.B. We allocate one more address than needed,
  456. // to ensure that 'AddressArray[0]' can be always read
  457. // even if there are no addresses. This allows us to optimize
  458. // checks for locally-destined packets in 'NatpReceivePacket'
  459. // and for locally-originated packets in 'NatpSendPacket'.
  460. //
  461. BindingInfo = (PIP_ADAPTER_BINDING_INFO)CreateInterface->BindingInfo;
  462. AddressArray =
  463. (PNAT_ADDRESS)
  464. ExAllocatePoolWithTag(
  465. NonPagedPool,
  466. (BindingInfo->AddressCount + 1) * sizeof(NAT_ADDRESS),
  467. NAT_TAG_ADDRESS
  468. );
  469. if (!AddressArray) {
  470. ERROR(("NatCreateInterface: address-array allocation failed\n"));
  471. return STATUS_NO_MEMORY;
  472. }
  473. //
  474. // Copy the binding information to the allocated space.
  475. //
  476. AddressCount = BindingInfo->AddressCount;
  477. for (i = 0; i < BindingInfo->AddressCount; i++) {
  478. AddressArray[i].Address = BindingInfo->Address[i].Address;
  479. AddressArray[i].Mask = BindingInfo->Address[i].Mask;
  480. AddressArray[i].NegatedClassMask =
  481. ~(GET_CLASS_MASK(BindingInfo->Address[i].Address));
  482. }
  483. //
  484. // Obtain the MTU of this interface. If failed, set to the mininum value.
  485. //
  486. mtu = NatpGetInterfaceMTU(CreateInterface->Index);
  487. //
  488. // See if an interface with the given index exists already
  489. //
  490. Index = CreateInterface->Index;
  491. KeAcquireSpinLock(&InterfaceLock, &Irql);
  492. if (NatLookupInterface(Index, &InsertionPoint)) {
  493. KeReleaseSpinLock(&InterfaceLock, Irql);
  494. ERROR(("NatCreateInterface: interface %d already exists\n", Index));
  495. ExFreePool(AddressArray);
  496. return STATUS_INVALID_PARAMETER;
  497. }
  498. //
  499. // Allocate space for the new interface
  500. //
  501. Interfacep =
  502. (PNAT_INTERFACE)
  503. ExAllocatePoolWithTag(
  504. NonPagedPool,
  505. sizeof(NAT_INTERFACE),
  506. NAT_TAG_INTERFACE
  507. );
  508. if (!Interfacep) {
  509. KeReleaseSpinLock(&InterfaceLock, Irql);
  510. ERROR(("NatCreateInterface: interface allocation failed\n"));
  511. ExFreePool(AddressArray);
  512. return STATUS_NO_MEMORY;
  513. }
  514. RtlZeroMemory(Interfacep, sizeof(NAT_INTERFACE));
  515. //
  516. // Initialize the interface
  517. //
  518. KeInitializeSpinLock(&Interfacep->Lock);
  519. Interfacep->ReferenceCount = 1;
  520. Interfacep->Index = Index;
  521. Interfacep->FileObject = FileObject;
  522. Interfacep->AddressArray = AddressArray;
  523. Interfacep->AddressCount = AddressCount;
  524. Interfacep->MTU = mtu;
  525. InitializeListHead(&Interfacep->Link);
  526. InitializeListHead(&Interfacep->UsedAddressList);
  527. InitializeListHead(&Interfacep->MappingList);
  528. InitializeListHead(&Interfacep->TicketList);
  529. InsertTailList(InsertionPoint, &Interfacep->Link);
  530. KeReleaseSpinLock(&InterfaceLock, Irql);
  531. InterlockedIncrement(&InterfaceCount);
  532. return STATUS_SUCCESS;
  533. } // NatCreateInterface
  534. NTSTATUS
  535. NatDeleteInterface(
  536. IN ULONG Index,
  537. IN PFILE_OBJECT FileObject
  538. )
  539. /*++
  540. Routine Description:
  541. Handles interface deletion. The interface is removed from the interface
  542. list, and if there are no references to it, it is immediately cleaned up.
  543. Arguments:
  544. Index - specifies the interface to be deleted.
  545. FileObject - indicates the file-object of the requestor
  546. Return Value
  547. NTSTATUS - status code.
  548. --*/
  549. {
  550. PNAT_INTERFACE Interfacep;
  551. KIRQL Irql;
  552. CALLTRACE(("NatDeleteInterface\n"));
  553. KeAcquireSpinLock(&InterfaceLock, &Irql);
  554. Interfacep = NatLookupInterface(Index, NULL);
  555. if (!Interfacep || Interfacep->FileObject != FileObject) {
  556. KeReleaseSpinLock(&InterfaceLock, Irql);
  557. return STATUS_INVALID_PARAMETER;
  558. }
  559. RemoveEntryList(&Interfacep->Link);
  560. InterlockedClearCache(InterfaceCache, Interfacep->Index);
  561. Interfacep->Flags |= NAT_INTERFACE_FLAGS_DELETED;
  562. if (NAT_INTERFACE_FW(Interfacep)) {
  563. ASSERT(FirewalledInterfaceCount > 0);
  564. InterlockedDecrement(&FirewalledInterfaceCount);
  565. }
  566. KeReleaseSpinLock(&InterfaceLock, Irql);
  567. if (InterlockedDecrement(&Interfacep->ReferenceCount) > 0) {
  568. return STATUS_PENDING;
  569. }
  570. NatCleanupInterface(Interfacep);
  571. return STATUS_SUCCESS;
  572. } // NatDeleteInterface
  573. VOID
  574. NatDeleteAnyAssociatedInterface(
  575. PFILE_OBJECT FileObject
  576. )
  577. /*++
  578. Routine Description:
  579. This routine is invoked to delete any interface associated with
  580. the given file-object.
  581. Arguments:
  582. FileObject - the file-object to be cleaned up
  583. Return Value:
  584. none.
  585. --*/
  586. {
  587. PNAT_INTERFACE Interfacep;
  588. ULONG Index;
  589. KIRQL Irql;
  590. PLIST_ENTRY Link;
  591. CALLTRACE(("NatDeleteAnyAssociatedInterface\n"));
  592. KeAcquireSpinLock(&InterfaceLock, &Irql);
  593. for (Link = InterfaceList.Flink; Link != &InterfaceList;
  594. Link = Link->Flink) {
  595. Interfacep = CONTAINING_RECORD(Link, NAT_INTERFACE, Link);
  596. if (Interfacep->FileObject != FileObject) { continue; }
  597. Index = Interfacep->Index;
  598. KeReleaseSpinLockFromDpcLevel(&InterfaceLock);
  599. NatDeleteInterface(Index, FileObject);
  600. KeAcquireSpinLockAtDpcLevel(&InterfaceLock);
  601. Link = &InterfaceList;
  602. }
  603. KeReleaseSpinLock(&InterfaceLock, Irql);
  604. } // NatDeleteAnyAssociatedInterface
  605. VOID
  606. NatInitializeInterfaceManagement(
  607. VOID
  608. )
  609. /*++
  610. Routine Description:
  611. This routine prepares the interface-management module for operation.
  612. Arguments:
  613. none.
  614. Return Value:
  615. none.
  616. --*/
  617. {
  618. CALLTRACE(("NatInitializeInterfaceManagement\n"));
  619. FirewalledInterfaceCount = 0;
  620. InterfaceCount = 0;
  621. TicketCount = 0;
  622. KeInitializeSpinLock(&InterfaceLock);
  623. KeInitializeSpinLock(&InterfaceMappingLock);
  624. InitializeListHead(&InterfaceList);
  625. InitializeCache(InterfaceCache);
  626. } // NatInitializeInterfaceManagement
  627. PIP_NAT_ADDRESS_MAPPING
  628. NatLookupAddressMappingOnInterface(
  629. IN PNAT_INTERFACE Interfacep,
  630. IN ULONG PublicAddress
  631. )
  632. /*++
  633. Routine Description:
  634. This routine is invoked to look up an address-mapping on an interface.
  635. The interface's address-mappings are stored in sorted-order, allowing
  636. us to use binary-search to quickly locate an address-mapping.
  637. (See 'NatConfigureInterface' for the code which does the sorting).
  638. This routine is only of benefit in cases where there are many mappings
  639. configured, since there is overhead involved in setting up the search.
  640. Arguments:
  641. Interfacep - the interface on which to perform the search
  642. PublicAddress - the public address of the mapping to be looked up
  643. Return Value:
  644. PIP_NAT_ADDRESS_MAPPING - the mapping if found, NULL otherwise.
  645. Environment:
  646. Invoked with 'Interfacep->Lock' held by the caller.
  647. --*/
  648. {
  649. LONG Left = 0;
  650. LONG Right = (LONG)Interfacep->AddressMappingCount;
  651. LONG i;
  652. for ( ; Left <= Right; ) {
  653. i = Left + (Right - Left) / 2;
  654. if (PublicAddress < Interfacep->AddressMappingArray[i].PublicAddress) {
  655. Right = i - 1; continue;
  656. } else if (PublicAddress >
  657. Interfacep->AddressMappingArray[i].PublicAddress) {
  658. Left = i + 1; continue;
  659. }
  660. return &Interfacep->AddressMappingArray[i];
  661. }
  662. return NULL;
  663. } // NatLookupAddressMappingOnInterface
  664. PNAT_INTERFACE
  665. NatLookupInterface(
  666. IN ULONG Index,
  667. OUT PLIST_ENTRY* InsertionPoint OPTIONAL
  668. )
  669. /*++
  670. Routine Description:
  671. This routine is invoked to search for an interface with the given index
  672. in our list of interfaces.
  673. Arguments:
  674. Index - identifies the interface to be found
  675. InsertionPoint - optionally receives the link in the list before which
  676. the interface would be inserted
  677. Return Value:
  678. PNAT_INTERFACE - the interface, if found; otherwise, NULL.
  679. Environment:
  680. Invoked with 'InterfaceLock' held by the caller.
  681. --*/
  682. {
  683. PNAT_INTERFACE Interfacep;
  684. PLIST_ENTRY Link;
  685. TRACE(PER_PACKET, ("NatLookupInterface\n"));
  686. for (Link = InterfaceList.Flink; Link != &InterfaceList;
  687. Link = Link->Flink) {
  688. Interfacep = CONTAINING_RECORD(Link, NAT_INTERFACE, Link);
  689. if (Interfacep->Index > Index) {
  690. continue;
  691. } else if (Interfacep->Index < Index) {
  692. break;
  693. }
  694. return Interfacep;
  695. }
  696. if (InsertionPoint) { *InsertionPoint = Link; }
  697. return NULL;
  698. } // NatLookupInterface
  699. PIP_NAT_PORT_MAPPING
  700. NatLookupPortMappingOnInterface(
  701. IN PNAT_INTERFACE Interfacep,
  702. IN UCHAR Protocol,
  703. IN USHORT PublicPort
  704. )
  705. /*++
  706. Routine Description:
  707. This routine is invoked to look up a port-mapping on an interface.
  708. The interface's port-mappings are stored in sorted-order, allowing
  709. us to use binary-search to quickly locate a port-mapping.
  710. (See 'NatConfigureInterface' for the code which does the sorting).
  711. This routine is only of benefit in cases where there are many mappings
  712. configured, since there is overhead involved in setting up the search.
  713. Arguments:
  714. Interfacep - the interface on which to perform the search
  715. Protocol - the protocol of the mapping to be looked up
  716. PublicPort - the public port of the mapping to be looked up
  717. Return Value:
  718. PIP_NAT_PORT_MAPPING - the mapping if found, NULL otherwise.
  719. Environment:
  720. Invoked with 'Interfacep->Lock' held by the caller.
  721. --*/
  722. {
  723. LONG Left = 0;
  724. LONG Right = (LONG)Interfacep->PortMappingCount;
  725. LONG i;
  726. ULONG SearchKey, ElementKey;
  727. SearchKey = (Protocol << 16) | PublicPort;
  728. for ( ; Left <= Right; ) {
  729. i = Left + (Right - Left) / 2;
  730. ElementKey =
  731. (Interfacep->PortMappingArray[i].Protocol << 16) |
  732. Interfacep->PortMappingArray[i].PublicPort;
  733. if (SearchKey < ElementKey) {
  734. Right = i - 1; continue;
  735. } else if (SearchKey > ElementKey) {
  736. Left = i + 1; continue;
  737. }
  738. return &Interfacep->PortMappingArray[i];
  739. }
  740. return NULL;
  741. } // NatLookupPortMappingOnInterface
  742. VOID
  743. NatMappingAttachInterface(
  744. PNAT_INTERFACE Interfacep,
  745. PVOID InterfaceContext,
  746. PNAT_DYNAMIC_MAPPING Mapping
  747. )
  748. /*++
  749. Routine Description:
  750. This routine is invoked to attach a mapping to an interface.
  751. It serves as a notification that there is one more mapping
  752. associated with the interface.
  753. Arguments:
  754. Interfacep - the interface for the mapping
  755. InterfaceContext - context associated with the interface;
  756. in our case, holds the address-pool entry in use by the mapping
  757. Mapping - the mapping to be attached.
  758. Return Value:
  759. none.
  760. Environment:
  761. Always invoked at dispatch level, with 'InterfaceLock' and
  762. 'InterfaceMappingLock' held.
  763. --*/
  764. {
  765. Mapping->Interfacep = Interfacep;
  766. Mapping->InterfaceContext = InterfaceContext;
  767. InsertTailList(&Interfacep->MappingList, &Mapping->InterfaceLink);
  768. InterlockedIncrement(&Interfacep->Statistics.TotalMappings);
  769. if (NAT_MAPPING_INBOUND(Mapping)) {
  770. InterlockedIncrement(&Interfacep->Statistics.InboundMappings);
  771. }
  772. } // NatMappingAttachInterface
  773. VOID
  774. NatMappingDetachInterface(
  775. PNAT_INTERFACE Interfacep,
  776. PVOID InterfaceContext,
  777. PNAT_DYNAMIC_MAPPING Mapping
  778. )
  779. /*++
  780. Routine Description:
  781. This routine is invoked to detach a mapping from an interface.
  782. It serves as a notification that there is one less mapping
  783. associated with the interface.
  784. Arguments:
  785. Interfacep - the interface for the mapping
  786. InterfaceContext - context associated with the interface;
  787. in our case, holds the address-pool entry in use by the mapping
  788. Mapping - the mapping to be attached, or NULL if a mapping could not be
  789. created.
  790. Return Value:
  791. none.
  792. Environment:
  793. Always invoked at dispatch level, with 'InterfaceLock' and
  794. 'InterfaceMappingLock' held.
  795. --*/
  796. {
  797. //
  798. // N.B. The mapping may be NULL, e.g. if its creation failed.
  799. // In that case we just release the address acquired for the mapping.
  800. //
  801. if (Mapping) {
  802. RemoveEntryList(&Mapping->InterfaceLink);
  803. Mapping->Interfacep = NULL;
  804. Mapping->InterfaceContext = NULL;
  805. if (NAT_MAPPING_INBOUND(Mapping)) {
  806. InterlockedDecrement(&Interfacep->Statistics.InboundMappings);
  807. }
  808. InterlockedDecrement(&Interfacep->Statistics.TotalMappings);
  809. }
  810. NatDereferenceAddressPoolEntry(
  811. Interfacep,
  812. (PNAT_USED_ADDRESS)InterfaceContext
  813. );
  814. } // NatMappingDetachInterface
  815. NTSTATUS
  816. NatQueryInformationInterface(
  817. IN ULONG Index,
  818. IN PIP_NAT_INTERFACE_INFO InterfaceInfo,
  819. IN PULONG Size
  820. )
  821. /*++
  822. Routine Description:
  823. Called to construct the optional information in use on the interface.
  824. Arguments:
  825. Index - identifies the interface
  826. InterfaceInfo - receives the retrieved configuration
  827. Size - the size of the given buffer
  828. Return Value:
  829. STATUS_SUCCESS if retrieved, STATUS_BUFFER_TOO_SMALL if '*Size' is too
  830. small, error otherwise.
  831. --*/
  832. {
  833. PRTR_INFO_BLOCK_HEADER Header;
  834. ULONG InfoSize;
  835. PNAT_INTERFACE Interfacep;
  836. KIRQL Irql;
  837. NTSTATUS status = STATUS_SUCCESS;
  838. PVOID Temp;
  839. CALLTRACE(("NatQueryInformationInterface\n"));
  840. KeAcquireSpinLock(&InterfaceLock, &Irql);
  841. Interfacep = NatLookupInterface(Index, NULL);
  842. if (!Interfacep) {
  843. KeReleaseSpinLock(&InterfaceLock, Irql);
  844. return STATUS_INVALID_PARAMETER;
  845. }
  846. NatReferenceInterface(Interfacep);
  847. KeReleaseSpinLockFromDpcLevel(&InterfaceLock);
  848. KeAcquireSpinLockAtDpcLevel(&Interfacep->Lock);
  849. Header = &Interfacep->Info->Header;
  850. InfoSize = FIELD_OFFSET(IP_NAT_INTERFACE_INFO, Header) + Header->Size;
  851. if (*Size < InfoSize) {
  852. KeReleaseSpinLock(&Interfacep->Lock, Irql);
  853. } else {
  854. //
  855. // In transferring the requested information, we must be careful
  856. // because the output-buffer may be a pageable user-mode address.
  857. // We cannot take a page-fault while holding the interface's lock
  858. // at dispatch level, so we make a non-paged copy of the information,
  859. // release the interface's lock to return to passive level,
  860. // and then copy the information to the caller's buffer.
  861. //
  862. Temp = ExAllocatePoolWithTag(NonPagedPool, InfoSize, NAT_TAG_IF_CONFIG);
  863. if (!Temp) {
  864. KeReleaseSpinLock(&Interfacep->Lock, Irql);
  865. status = STATUS_NO_MEMORY;
  866. InfoSize = 0;
  867. } else {
  868. RtlCopyMemory(Temp, Interfacep->Info, InfoSize);
  869. KeReleaseSpinLock(&Interfacep->Lock, Irql);
  870. __try {
  871. RtlCopyMemory(InterfaceInfo, Temp, InfoSize);
  872. } __except(EXCEPTION_EXECUTE_HANDLER) {
  873. status = GetExceptionCode();
  874. }
  875. ExFreePool(Temp);
  876. }
  877. }
  878. *Size = InfoSize;
  879. NatDereferenceInterface(Interfacep);
  880. return status;
  881. } // NatQueryInformationInterface
  882. NTSTATUS
  883. NatQueryStatisticsInterface(
  884. ULONG Index,
  885. IN PIP_NAT_INTERFACE_STATISTICS InterfaceStatistics
  886. )
  887. /*++
  888. Routine Description:
  889. This routine is invoked to copy the statistics for an interface.
  890. Note that we do not need to lock the interface to access the statistics,
  891. since they are all updated using interlocked operations.
  892. Arguments:
  893. Index - identifies the interface
  894. InterfaceStatistics - i/o buffer used for transfer of information
  895. Return Value:
  896. STATUS_SUCCESS if successful, error code otherwise.
  897. --*/
  898. {
  899. PNAT_INTERFACE Interfacep;
  900. KIRQL Irql;
  901. NTSTATUS Status;
  902. CALLTRACE(("NatQueryStatisticsInterface\n"));
  903. KeAcquireSpinLock(&InterfaceLock, &Irql);
  904. Interfacep = NatLookupInterface(Index, NULL);
  905. if (!Interfacep) {
  906. KeReleaseSpinLock(&InterfaceLock, Irql);
  907. return STATUS_INVALID_PARAMETER;
  908. }
  909. NatReferenceInterface(Interfacep);
  910. KeReleaseSpinLock(&InterfaceLock, Irql);
  911. //
  912. // Copy the statistics to the caller's buffer
  913. //
  914. Status = STATUS_SUCCESS;
  915. __try {
  916. *InterfaceStatistics = Interfacep->Statistics;
  917. } __except(EXCEPTION_EXECUTE_HANDLER) {
  918. Status = GetExceptionCode();
  919. }
  920. NatDereferenceInterface(Interfacep);
  921. return Status;
  922. } // NatQueryStatisticsInterface
  923. VOID
  924. NatResetInterface(
  925. IN PNAT_INTERFACE Interfacep
  926. )
  927. /*++
  928. Routine Description:
  929. This routine is called to destroy all structures hanging off an interface.
  930. It is used when reconfiguring or cleaning up an interface.
  931. Arguments:
  932. Interfacep - the interface to be reset.
  933. Return Value:
  934. none.
  935. Environment:
  936. Invoked with 'InterfaceLock' held by the caller, and
  937. (a) 'Interfacep->Lock' also held by the caller, or
  938. (b) the last reference to the interface released.
  939. --*/
  940. {
  941. PLIST_ENTRY List;
  942. PLIST_ENTRY Link;
  943. PNAT_IP_MAPPING IpMapping;
  944. KIRQL Irql;
  945. PNAT_DYNAMIC_MAPPING Mapping;
  946. PNAT_TICKET Ticket;
  947. CALLTRACE(("NatResetInterface\n"));
  948. //
  949. // Clean out the interface's dynamic mappings
  950. //
  951. KeAcquireSpinLockAtDpcLevel(&InterfaceMappingLock);
  952. List = &Interfacep->MappingList;
  953. while (!IsListEmpty(List)) {
  954. Mapping =
  955. CONTAINING_RECORD(List->Flink, NAT_DYNAMIC_MAPPING, InterfaceLink);
  956. NatExpireMapping(Mapping);
  957. NatMappingDetachInterface(
  958. Interfacep, Mapping->InterfaceContext, Mapping
  959. );
  960. }
  961. KeReleaseSpinLockFromDpcLevel(&InterfaceMappingLock);
  962. //
  963. // Clean out the interface's tickets
  964. //
  965. List = &Interfacep->TicketList;
  966. while (!IsListEmpty(List)) {
  967. Ticket = CONTAINING_RECORD(List->Flink, NAT_TICKET, Link);
  968. NatDeleteTicket(Interfacep, Ticket);
  969. }
  970. //
  971. // Clean out the interface's address-pool and port-pool
  972. //
  973. NatDeleteAddressPool(Interfacep);
  974. } // NatResetInterface
  975. VOID
  976. NatShutdownInterfaceManagement(
  977. VOID
  978. )
  979. /*++
  980. Routine Description:
  981. This routine shuts down the interface-management module.
  982. Arguments:
  983. none.
  984. Return Value:
  985. none.
  986. --*/
  987. {
  988. PNAT_INTERFACE Interfacep;
  989. KIRQL Irql;
  990. CALLTRACE(("NatShutdownInterfaceManagement\n"));
  991. //
  992. // Delete all interfaces
  993. //
  994. KeAcquireSpinLock(&InterfaceLock, &Irql);
  995. while (!IsListEmpty(&InterfaceList)) {
  996. Interfacep =
  997. CONTAINING_RECORD(InterfaceList.Flink, NAT_INTERFACE, Link);
  998. RemoveEntryList(&Interfacep->Link);
  999. KeReleaseSpinLockFromDpcLevel(&InterfaceLock);
  1000. NatCleanupInterface(Interfacep);
  1001. KeAcquireSpinLockAtDpcLevel(&InterfaceLock);
  1002. }
  1003. KeReleaseSpinLock(&InterfaceLock, Irql);
  1004. InterfaceCount = 0;
  1005. TicketCount = 0;
  1006. } // NatShutdownInterfaceManagement