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.

1259 lines
29 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. editor.c
  5. Abstract:
  6. This module contains the code for editor management.
  7. Author:
  8. Abolade Gbadegesin (t-abolag) 14-July-1997
  9. Return Value:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. //
  14. // GLOBAL DATA DEFINITIONS
  15. //
  16. //
  17. // Count of NAT editors
  18. //
  19. ULONG EditorCount;
  20. //
  21. // List of NAT editors
  22. //
  23. LIST_ENTRY EditorList;
  24. //
  25. // Spin-lock controlling access to 'EditorList'.
  26. //
  27. KSPIN_LOCK EditorLock;
  28. //
  29. // Spin-lock controlling access to the 'MappingList' field of all editors.
  30. //
  31. KSPIN_LOCK EditorMappingLock;
  32. VOID
  33. NatCleanupEditor(
  34. PNAT_EDITOR Editor
  35. )
  36. /*++
  37. Routine Description:
  38. Called to perform final cleanup for an editor.
  39. Arguments:
  40. Editor - the editor to be cleaned up.
  41. Return Value:
  42. none.
  43. Environment:
  44. Invoked with 'EditorLock' NOT held by the caller.
  45. --*/
  46. {
  47. KIRQL Irql;
  48. PLIST_ENTRY Link;
  49. PNAT_DYNAMIC_MAPPING Mapping;
  50. KeAcquireSpinLock(&EditorLock, &Irql);
  51. KeAcquireSpinLockAtDpcLevel(&EditorMappingLock);
  52. for (Link = Editor->MappingList.Flink; Link != &Editor->MappingList;
  53. Link = Link->Flink) {
  54. Mapping = CONTAINING_RECORD(Link, NAT_DYNAMIC_MAPPING, EditorLink);
  55. Link = Link->Blink;
  56. NatMappingDetachEditor(Editor, Mapping);
  57. }
  58. KeReleaseSpinLockFromDpcLevel(&EditorMappingLock);
  59. KeReleaseSpinLock(&EditorLock, Irql);
  60. ExFreePool(Editor);
  61. } // NatCleanupEditor
  62. NTSTATUS
  63. NatCreateEditor(
  64. PIP_NAT_REGISTER_EDITOR RegisterContext
  65. )
  66. /*++
  67. Routine Description:
  68. This routine is invoked when an editor attempts to register.
  69. It handles creation of a context-block for the editor.
  70. Arguments:
  71. RegisterContext - information about the registering editor
  72. Return Value:
  73. NTSTATUS - status code.
  74. --*/
  75. {
  76. PNAT_EDITOR Editor;
  77. PLIST_ENTRY InsertionPoint;
  78. KIRQL Irql;
  79. CALLTRACE(("NatCreateEditor\n"));
  80. //
  81. // Validate the registration information
  82. //
  83. if ((RegisterContext->Protocol != NAT_PROTOCOL_TCP &&
  84. RegisterContext->Protocol != NAT_PROTOCOL_UDP) ||
  85. (!RegisterContext->Port) ||
  86. (RegisterContext->Direction != NatInboundDirection &&
  87. RegisterContext->Direction != NatOutboundDirection) ||
  88. (!RegisterContext->ForwardDataHandler &&
  89. !RegisterContext->ReverseDataHandler)) {
  90. ERROR(("NatCreateEditor: bad argument\n"));
  91. return STATUS_INVALID_PARAMETER;
  92. }
  93. //
  94. // Allocate a new editor-struct
  95. //
  96. Editor =
  97. ExAllocatePoolWithTag(NonPagedPool, sizeof(NAT_EDITOR), NAT_TAG_EDITOR);
  98. if (!Editor) {
  99. ERROR(("NatCreateEditor: allocation failed\n"));
  100. return STATUS_NO_MEMORY;
  101. }
  102. KeInitializeSpinLock(&Editor->Lock);
  103. Editor->ReferenceCount = 1;
  104. Editor->Flags = RegisterContext->Flags;
  105. Editor->Key =
  106. MAKE_EDITOR_KEY(
  107. RegisterContext->Protocol,
  108. RegisterContext->Port,
  109. RegisterContext->Direction
  110. );
  111. InitializeListHead(&Editor->MappingList);
  112. Editor->Context = RegisterContext->EditorContext;
  113. Editor->CreateHandler = RegisterContext->CreateHandler;
  114. Editor->DeleteHandler = RegisterContext->DeleteHandler;
  115. Editor->ForwardDataHandler = RegisterContext->ForwardDataHandler;
  116. Editor->ReverseDataHandler = RegisterContext->ReverseDataHandler;
  117. KeAcquireSpinLock(&EditorLock, &Irql);
  118. if (NatLookupEditor(Editor->Key, &InsertionPoint)) {
  119. KeReleaseSpinLock(&EditorLock, Irql);
  120. ERROR(
  121. ("NatCreateEditor: duplicate editor %d/%d\n",
  122. RegisterContext->Protocol, RegisterContext->Port)
  123. );
  124. ExFreePool(Editor);
  125. return STATUS_UNSUCCESSFUL;
  126. }
  127. InsertTailList(InsertionPoint, &Editor->Link);
  128. KeReleaseSpinLock(&EditorLock, Irql);
  129. InterlockedIncrement(&EditorCount);
  130. //
  131. // Supply the caller with 'out' information
  132. //
  133. RegisterContext->EditorHandle = (PVOID)Editor;
  134. RegisterContext->CreateTicket = NatEditorCreateTicket;
  135. RegisterContext->DeleteTicket = NatEditorDeleteTicket;
  136. RegisterContext->Deregister = NatEditorDeregister;
  137. RegisterContext->DissociateSession = NatEditorDissociateSession;
  138. RegisterContext->EditSession = NatEditorEditSession;
  139. RegisterContext->QueryInfoSession = NatEditorQueryInfoSession;
  140. RegisterContext->TimeoutSession = NatEditorTimeoutSession;
  141. return STATUS_SUCCESS;
  142. } // NatCreateEditor
  143. NTSTATUS
  144. NatDeleteEditor(
  145. PNAT_EDITOR Editor
  146. )
  147. /*++
  148. Routine Description:
  149. Handles editor deletion.
  150. This routine assumes that EditorLock is NOT held by the caller.
  151. Arguments:
  152. Editor - specifies the editor to be deleted.
  153. Return Value
  154. NTSTATUS - status code.
  155. --*/
  156. {
  157. KIRQL Irql;
  158. CALLTRACE(("NatDeleteEditor\n"));
  159. InterlockedDecrement(&EditorCount);
  160. //
  161. // Remove the editor for the list
  162. //
  163. KeAcquireSpinLock(&EditorLock, &Irql);
  164. Editor->Flags |= NAT_EDITOR_FLAG_DELETED;
  165. RemoveEntryList(&Editor->Link);
  166. KeReleaseSpinLock(&EditorLock, Irql);
  167. //
  168. // Drop its reference count and clean up if necessary
  169. //
  170. if (InterlockedDecrement(&Editor->ReferenceCount) > 0) {
  171. return STATUS_PENDING;
  172. }
  173. NatCleanupEditor(Editor);
  174. return STATUS_SUCCESS;
  175. } // NatDeleteEditor
  176. VOID
  177. NatInitializeEditorManagement(
  178. VOID
  179. )
  180. /*++
  181. Routine Description:
  182. This routine prepares the editor-management module for operation.
  183. Arguments:
  184. none.
  185. Return Value:
  186. none.
  187. --*/
  188. {
  189. CALLTRACE(("NatInitializeEditorManagement\n"));
  190. EditorCount = 0;
  191. KeInitializeSpinLock(&EditorLock);
  192. InitializeListHead(&EditorList);
  193. KeInitializeSpinLock(&EditorMappingLock);
  194. } // NatInitializeEditorManagement
  195. PNAT_EDITOR
  196. NatLookupEditor(
  197. ULONG Key,
  198. PLIST_ENTRY* InsertionPoint
  199. )
  200. /*++
  201. Routine Description:
  202. This routine is called to retrieve the editor corresponding to the given
  203. key.
  204. Arguments:
  205. Key - the key for which an editor is to be found
  206. InsertionPoint - receives the point at which the editor should be inserted
  207. if not found
  208. Return Value:
  209. PNAT_EDITOR - the required editor, if found
  210. --*/
  211. {
  212. PNAT_EDITOR Editor;
  213. PLIST_ENTRY Link;
  214. for (Link = EditorList.Flink; Link != &EditorList; Link = Link->Flink) {
  215. Editor = CONTAINING_RECORD(Link, NAT_EDITOR, Link);
  216. if (Key > Editor->Key) {
  217. continue;
  218. } else if (Key < Editor->Key) {
  219. break;
  220. }
  221. return Editor;
  222. }
  223. if (InsertionPoint) { *InsertionPoint = Link; }
  224. return NULL;
  225. } // NatLookupEditor
  226. VOID
  227. NatMappingAttachEditor(
  228. PNAT_EDITOR Editor,
  229. PNAT_DYNAMIC_MAPPING Mapping
  230. )
  231. /*++
  232. Routine Description:
  233. This routine is invoked to attach a mapping to an editor.
  234. It serves as a notification that there is one more mapping
  235. associated with the editor.
  236. Arguments:
  237. Editor - the editor for the mapping
  238. Mapping - the mapping to be attached.
  239. Return Value:
  240. none.
  241. Environment:
  242. Always invoked at dispatch level with 'EditorLock' and 'EditorMappingLock'
  243. held by the caller.
  244. --*/
  245. {
  246. ULONG PrivateAddress;
  247. USHORT PrivatePort;
  248. ULONG PublicAddress;
  249. USHORT PublicPort;
  250. ULONG RemoteAddress;
  251. USHORT RemotePort;
  252. CALLTRACE(("NatMappingAttachEditor\n"));
  253. if (Editor->CreateHandler) {
  254. NatQueryInformationMapping(
  255. Mapping,
  256. NULL,
  257. &PrivateAddress,
  258. &PrivatePort,
  259. &RemoteAddress,
  260. &RemotePort,
  261. &PublicAddress,
  262. &PublicPort,
  263. NULL
  264. );
  265. Editor->CreateHandler(
  266. Editor->Context,
  267. PrivateAddress,
  268. PrivatePort,
  269. RemoteAddress,
  270. RemotePort,
  271. PublicAddress,
  272. PublicPort,
  273. &Mapping->EditorContext
  274. );
  275. }
  276. Mapping->Editor = Editor;
  277. InsertTailList(&Editor->MappingList, &Mapping->EditorLink);
  278. } // NatMappingAttachEditor
  279. VOID
  280. NatMappingDetachEditor(
  281. PNAT_EDITOR Editor,
  282. PNAT_DYNAMIC_MAPPING Mapping
  283. )
  284. /*++
  285. Routine Description:
  286. This routine is invoked to detach a mapping from a editor.
  287. It serves as a notification that there is one less mapping
  288. associated with the editor.
  289. Arguments:
  290. Editor - editor to be detached
  291. Mapping - the mapping to be detached
  292. Return Value:
  293. none.
  294. Environment:
  295. Always invoked at dispatch level with 'EditorLock' and 'EditorMappingLock'
  296. held by the caller.
  297. --*/
  298. {
  299. KIRQL Irql;
  300. if (Editor->DeleteHandler && Mapping->Interfacep) {
  301. Editor->DeleteHandler(
  302. Mapping->Interfacep,
  303. Mapping,
  304. Editor->Context,
  305. Mapping->EditorContext
  306. );
  307. }
  308. RemoveEntryList(&Mapping->EditorLink);
  309. Mapping->Editor = NULL;
  310. Mapping->EditorContext = NULL;
  311. } // NatMappingDetachEditor
  312. NTSTATUS
  313. NatQueryEditorTable(
  314. IN PIP_NAT_ENUMERATE_EDITORS InputBuffer,
  315. IN PIP_NAT_ENUMERATE_EDITORS OutputBuffer,
  316. IN PULONG OutputBufferLength
  317. )
  318. /*++
  319. Routine Description:
  320. This routine is used for enumerating the registered editors.
  321. Arguments:
  322. InputBuffer - supplies context information for the information
  323. OutputBuffer - receives the result of the enumeration
  324. OutputBufferLength - size of the i/o buffer
  325. Return Value:
  326. STATUS_SUCCESS if successful, error code otherwise.
  327. --*/
  328. {
  329. ULONG Count;
  330. ULONG i;
  331. KIRQL Irql;
  332. ULONG Key;
  333. PLIST_ENTRY Link;
  334. PNAT_EDITOR Editor;
  335. NTSTATUS status;
  336. PIP_NAT_EDITOR Table;
  337. CALLTRACE(("NatQueryEditorTable\n"));
  338. Key = InputBuffer->EnumerateContext;
  339. KeAcquireSpinLock(&EditorLock, &Irql);
  340. //
  341. // See if this is a new enumeration or a continuation of an old one.
  342. //
  343. if (!Key) {
  344. //
  345. // This is a new enumeration. We start with the first item
  346. // in the list of editors
  347. //
  348. Editor =
  349. IsListEmpty(&EditorList)
  350. ? NULL
  351. : CONTAINING_RECORD(EditorList.Flink, NAT_EDITOR, Link);
  352. } else {
  353. //
  354. // This is a continuation. The context therefore contains
  355. // the key for the next editor.
  356. //
  357. Editor = NatLookupEditor(Key, NULL);
  358. }
  359. if (!Editor) {
  360. OutputBuffer->EnumerateCount = 0;
  361. OutputBuffer->EnumerateContext = 0;
  362. OutputBuffer->EnumerateTotalHint = EditorCount;
  363. *OutputBufferLength =
  364. FIELD_OFFSET(IP_NAT_ENUMERATE_EDITORS, EnumerateTable);
  365. KeReleaseSpinLock(&EditorLock, Irql);
  366. return STATUS_SUCCESS;
  367. }
  368. //
  369. // Compute the maximum number of entries we can store
  370. //
  371. Count =
  372. *OutputBufferLength -
  373. FIELD_OFFSET(IP_NAT_ENUMERATE_EDITORS, EnumerateTable);
  374. Count /= sizeof(IP_NAT_EDITOR);
  375. //
  376. // Walk the list storing mappings in the caller's buffer
  377. //
  378. Table = OutputBuffer->EnumerateTable;
  379. for (i = 0, Link = &Editor->Link; i < Count && Link != &EditorList;
  380. i++, Link = Link->Flink) {
  381. Editor = CONTAINING_RECORD(Link, NAT_EDITOR, Link);
  382. Table[i].Direction = EDITOR_KEY_DIRECTION(Editor->Key);
  383. Table[i].Protocol = EDITOR_KEY_PROTOCOL(Editor->Key);
  384. Table[i].Port = EDITOR_KEY_PORT(Editor->Key);
  385. }
  386. //
  387. // The enumeration is over; update the output structure
  388. //
  389. *OutputBufferLength =
  390. i * sizeof(IP_NAT_EDITOR) +
  391. FIELD_OFFSET(IP_NAT_ENUMERATE_EDITORS, EnumerateTable);
  392. OutputBuffer->EnumerateCount = i;
  393. OutputBuffer->EnumerateTotalHint = EditorCount;
  394. if (Link == &EditorList) {
  395. //
  396. // We reached the end of the editor list
  397. //
  398. OutputBuffer->EnumerateContext = 0;
  399. } else {
  400. //
  401. // Save the continuation context
  402. //
  403. OutputBuffer->EnumerateContext =
  404. CONTAINING_RECORD(Link, NAT_EDITOR, Link)->Key;
  405. }
  406. KeReleaseSpinLock(&EditorLock, Irql);
  407. return STATUS_SUCCESS;
  408. } // NatQueryEditorTable
  409. VOID
  410. NatShutdownEditorManagement(
  411. VOID
  412. )
  413. /*++
  414. Routine Description:
  415. This routine shuts down the editor-management module.
  416. Arguments:
  417. none.
  418. Return Value:
  419. none.
  420. --*/
  421. {
  422. PNAT_EDITOR Editor;
  423. KIRQL Irql;
  424. CALLTRACE(("NatShutdownEditorManagement\n"));
  425. KeAcquireSpinLock(&EditorLock, &Irql);
  426. //
  427. // Delete all editors
  428. //
  429. while (!IsListEmpty(&EditorList)) {
  430. Editor = CONTAINING_RECORD(EditorList.Flink, NAT_EDITOR, Link);
  431. RemoveEntryList(&Editor->Link);
  432. KeReleaseSpinLockFromDpcLevel(&EditorLock);
  433. NatCleanupEditor(Editor);
  434. KeAcquireSpinLockAtDpcLevel(&EditorLock);
  435. }
  436. KeReleaseSpinLock(&EditorLock, Irql);
  437. } // NatShutdownEditorManagement
  438. //
  439. // EDITOR HELPER ROUTINES
  440. //
  441. // These routines assume that references are held on the calling 'Interface',
  442. // 'Editor' and 'Mapping' but that none are locked. The caller is assumed
  443. // to be running at dispatch level, with the exception of the routine
  444. // 'NatEditorDeregister' which may be invoked at lower IRQL.
  445. //
  446. NTSTATUS
  447. NatEditorCreateTicket(
  448. IN PVOID InterfaceHandle,
  449. IN UCHAR Protocol,
  450. IN ULONG PrivateAddress,
  451. IN USHORT PrivatePort,
  452. IN ULONG RemoteAddress OPTIONAL,
  453. IN USHORT RemotePort OPTIONAL,
  454. OUT PULONG PublicAddress,
  455. OUT PUSHORT PublicPort
  456. )
  457. /*++
  458. Routine Description:
  459. This routine is called by editors to dynamically establish mappings for
  460. sessions.
  461. Arguments:
  462. InterfaceHandle - handle of interface over which the mapping is to be
  463. established; would have been passed in a 'DataHandler' call.
  464. Protocol - NAT_PROTOCOL_TCP or NAT_PROTOCOL_UDP
  465. PrivateAddress - IP address of the session's private endpoint
  466. PrivatePort - protocol port of the session's private endpoint
  467. PublicAddress - receives the public address of the ticket created
  468. PublicPort - receives the public port of the ticket created
  469. Return Value:
  470. NTSTATUS - success/failure code.
  471. --*/
  472. {
  473. NTSTATUS status;
  474. CALLTRACE(("NatEditorCreateTicket\n"));
  475. //
  476. // Lock the interface as expected by 'NatCreateTicket',
  477. // and make the new ticket
  478. //
  479. KeAcquireSpinLockAtDpcLevel(&((PNAT_INTERFACE)InterfaceHandle)->Lock);
  480. status =
  481. NatCreateTicket(
  482. (PNAT_INTERFACE)InterfaceHandle,
  483. Protocol,
  484. PrivateAddress,
  485. PrivatePort,
  486. RemoteAddress,
  487. RemotePort,
  488. 0,
  489. NULL,
  490. 0,
  491. PublicAddress,
  492. PublicPort
  493. );
  494. KeReleaseSpinLockFromDpcLevel(&((PNAT_INTERFACE)InterfaceHandle)->Lock);
  495. return status;
  496. } // NatEditorCreateTicket
  497. NTSTATUS
  498. NatEditorDeleteTicket(
  499. IN PVOID InterfaceHandle,
  500. IN ULONG PublicAddress,
  501. IN UCHAR Protocol,
  502. IN USHORT PublicPort,
  503. IN ULONG RemoteAddress OPTIONAL,
  504. IN USHORT RemotePort OPTIONAL
  505. )
  506. /*++
  507. Routine Description:
  508. This routine deletes a ticket created by 'NatEditorDeleteTicket'.
  509. Arguments:
  510. InterfaceHandle - handle of interface on which the ticket was issued
  511. Protocol - NAT_PROTOCOL_TCP or NAT_PROTOCOL_UDP
  512. PublicAddress - address of the ticket's public endpoint
  513. PublicPort - port of the ticket's public endpoint
  514. Return Value:
  515. NTSTATUS - indicates success/failure
  516. --*/
  517. {
  518. ULONG64 Key;
  519. ULONG64 RemoteKey;
  520. NTSTATUS status;
  521. CALLTRACE(("NatEditorDeleteTicket\n"));
  522. //
  523. // Lock the interface as expected by 'NatLookupAndDeleteTicket',
  524. // and delete the ticket
  525. //
  526. Key = MAKE_TICKET_KEY(Protocol, PublicAddress, PublicPort);
  527. RemoteKey = MAKE_TICKET_KEY(Protocol, RemoteAddress, RemotePort);
  528. KeAcquireSpinLockAtDpcLevel(&((PNAT_INTERFACE)InterfaceHandle)->Lock);
  529. status = NatLookupAndDeleteTicket(
  530. (PNAT_INTERFACE)InterfaceHandle,
  531. Key,
  532. RemoteKey
  533. );
  534. KeReleaseSpinLockFromDpcLevel(&((PNAT_INTERFACE)InterfaceHandle)->Lock);
  535. return status;
  536. } // NatEditorDeleteTicket
  537. NTSTATUS
  538. NatEditorDeregister(
  539. IN PVOID EditorHandle
  540. )
  541. /*++
  542. Routine Description:
  543. This routine removes an editor from the editor list,
  544. and dissociates it from all sessions it is currently editing.
  545. Arguments:
  546. EditorHandle - handle of the editor to be removed.
  547. Return Value:
  548. NTSTATUS - status code.
  549. --*/
  550. {
  551. PNAT_EDITOR Editor = (PNAT_EDITOR)EditorHandle;
  552. KIRQL Irql;
  553. CALLTRACE(("NatEditorDeregister\n"));
  554. KeAcquireSpinLock(&EditorLock, &Irql);
  555. Editor->Flags |= NAT_EDITOR_FLAG_DELETED;
  556. RemoveEntryList(&Editor->Link);
  557. KeReleaseSpinLock(&EditorLock, Irql);
  558. if (InterlockedDecrement(&Editor->ReferenceCount) > 0) {
  559. return STATUS_PENDING;
  560. }
  561. NatCleanupEditor(Editor);
  562. return STATUS_SUCCESS;
  563. } // NatEditorDeregister
  564. NTSTATUS
  565. NatEditorDissociateSession(
  566. IN PVOID EditorHandle,
  567. IN PVOID SessionHandle
  568. )
  569. /*++
  570. Routine Description:
  571. This routine is called by an editor to dissociate itself from a specific
  572. session.
  573. Arguments:
  574. EditorHandle - the editor which wishes to dissociate itself.
  575. SessionHandle - the session from which the editor is disssociating itself.
  576. Return Value:
  577. NTSTATUS - indicates success/failure
  578. Environment:
  579. Invoked at dispatch level with neither 'EditorLock' nor 'EditorMappingLock'
  580. held by the caller.
  581. --*/
  582. {
  583. PNAT_EDITOR Editor = (PNAT_EDITOR)EditorHandle;
  584. PNAT_DYNAMIC_MAPPING Mapping = (PNAT_DYNAMIC_MAPPING)SessionHandle;
  585. CALLTRACE(("NatEditorDissociateSession\n"));
  586. KeAcquireSpinLockAtDpcLevel(&EditorLock);
  587. if (Mapping->Editor != Editor) {
  588. KeReleaseSpinLockFromDpcLevel(&EditorLock);
  589. return STATUS_INVALID_PARAMETER;
  590. }
  591. KeAcquireSpinLockAtDpcLevel(&EditorMappingLock);
  592. NatMappingDetachEditor(Editor, Mapping);
  593. KeReleaseSpinLockFromDpcLevel(&EditorMappingLock);
  594. KeReleaseSpinLockFromDpcLevel(&EditorLock);
  595. return STATUS_SUCCESS;
  596. } // NatEditorDissociateSession
  597. NTSTATUS
  598. NatEditorEditSession(
  599. IN PVOID DataHandle,
  600. IN PVOID RecvBuffer,
  601. IN ULONG OldDataOffset,
  602. IN ULONG OldDataLength,
  603. IN PUCHAR NewData,
  604. IN ULONG NewDataLength
  605. )
  606. /*++
  607. Routine Description:
  608. This routine is invoked by an editor to replace one range of bytes
  609. in a packet with another range of bytes.
  610. The routine makes the necessary adjustments to TCP sequence numbers
  611. if the edition alters the size of a TCP segment.
  612. Arguments:
  613. EditorHandle - handle of the editor invoking this function.
  614. SessionHandle - the session whose data is to be edited.
  615. DataHandle - per-packet context passed to 'DataHandler'.
  616. RecvBuffer - the 'RecvBuffer' argument to 'DataHandler'.
  617. OldDataOffset - offset into 'RecvBuffer' of the range to be replaced
  618. OldDataLength - length of range to be replaced
  619. NewData - pointer to the bytes to serve as a replacement for 'OldData'
  620. NewDataLength - number of bytes in the replacement range.
  621. Return Value:
  622. NTSTATUS - indicates success/failure
  623. --*/
  624. {
  625. #define XLATECONTEXT ((PNAT_XLATE_CONTEXT)DataHandle)
  626. #define RECVBUFFER ((IPRcvBuf*)RecvBuffer)
  627. LONG Diff;
  628. IPRcvBuf* End;
  629. ULONG EndOffset;
  630. IPRcvBuf* NewEnd;
  631. ULONG NewEndOffset;
  632. BOOLEAN ResetIpHeader;
  633. ULONG Size;
  634. IPRcvBuf* Start;
  635. ULONG StartOffset;
  636. IPRcvBuf* Temp;
  637. PUCHAR TempBuffer;
  638. CALLTRACE(("NatEditorEditSession\n"));
  639. ResetIpHeader =
  640. ((PUCHAR)XLATECONTEXT->Header == XLATECONTEXT->RecvBuffer->ipr_buffer);
  641. //
  642. // Find the buffer which contains the start of the range to be edited
  643. //
  644. for (Start = (IPRcvBuf*)RecvBuffer, StartOffset = 0;
  645. Start && (StartOffset + Start->ipr_size) < OldDataOffset;
  646. StartOffset += Start->ipr_size, Start = Start->ipr_next) { }
  647. if (!Start) { return STATUS_INVALID_PARAMETER; }
  648. StartOffset = OldDataOffset - StartOffset;
  649. //
  650. // Find the buffer which contains the end of the range to be edited
  651. //
  652. for (End = Start, EndOffset = OldDataLength + StartOffset;
  653. End && EndOffset > End->ipr_size;
  654. EndOffset -= End->ipr_size, End = End->ipr_next) { }
  655. if (!End) { return STATUS_INVALID_PARAMETER; }
  656. //
  657. // Compute the change in length
  658. //
  659. Diff = NewDataLength - OldDataLength;
  660. //
  661. // If the length is decreasing, we MAY free some of the buffers.
  662. // If the length is increasing, we WILL grow the last buffer.
  663. //
  664. if (Diff < 0) {
  665. //
  666. // See how many buffers we will need for the new length
  667. //
  668. for (NewEnd = Start, NewEndOffset = NewDataLength + StartOffset;
  669. NewEnd && NewEndOffset > NewEnd->ipr_size;
  670. NewEndOffset -= NewEnd->ipr_size, NewEnd = NewEnd->ipr_next) { }
  671. //
  672. // Free all the buffers we can
  673. //
  674. if (NewEnd != End) {
  675. for (Temp = NewEnd->ipr_next; Temp != End; Temp = NewEnd->ipr_next) {
  676. NewEnd->ipr_next = Temp->ipr_next;
  677. Temp->ipr_next = NULL;
  678. IPFreeBuff(Temp);
  679. }
  680. }
  681. //
  682. // Copy over the remaining buffers
  683. //
  684. Size = min(NewDataLength, Start->ipr_size - StartOffset);
  685. RtlCopyMemory(Start->ipr_buffer + StartOffset, NewData, Size);
  686. NewData += Size;
  687. NewDataLength -= Size;
  688. for (Temp = Start->ipr_next; Temp != NewEnd->ipr_next;
  689. Temp = Temp->ipr_next) {
  690. Size = min(NewDataLength, Size);
  691. RtlCopyMemory(Temp->ipr_buffer, NewData, Size);
  692. NewData += Size;
  693. NewDataLength -= Size;
  694. }
  695. //
  696. // Now move up any data in the 'End' buffer
  697. //
  698. if (NewEnd == End) {
  699. RtlMoveMemory(
  700. End->ipr_buffer + NewEndOffset,
  701. End->ipr_buffer + EndOffset,
  702. End->ipr_size - EndOffset
  703. );
  704. End->ipr_size -= EndOffset - NewEndOffset;
  705. } else {
  706. NewEnd->ipr_size = NewEndOffset;
  707. End->ipr_size -= EndOffset;
  708. RtlMoveMemory(
  709. End->ipr_buffer,
  710. End->ipr_buffer + EndOffset,
  711. End->ipr_size
  712. );
  713. }
  714. }
  715. else
  716. if (Diff > 0) {
  717. IPRcvBuf SavedRcvBuf;
  718. //
  719. // We will have to reallocate the last buffer;
  720. // first save the old rcvbuf so we can free it
  721. // once we've copied out the old data
  722. //
  723. SavedRcvBuf = *End;
  724. SavedRcvBuf.ipr_next = NULL;
  725. Size = End->ipr_size;
  726. TempBuffer = End->ipr_buffer;
  727. End->ipr_size += Diff;
  728. if (!IPAllocBuff(End, End->ipr_size)) {
  729. TRACE(EDIT, ("NatEditorEditSession: allocation failed\n"));
  730. return STATUS_NO_MEMORY;
  731. }
  732. //
  733. // If there's only one buffer, we have to copy any non-edited data
  734. // at the start of the old buffer
  735. //
  736. if (Start == End && StartOffset) {
  737. RtlCopyMemory(
  738. Start->ipr_buffer,
  739. TempBuffer,
  740. StartOffset
  741. );
  742. }
  743. //
  744. // Copy any non-edited data that is at the end of the old buffer
  745. //
  746. if (Size != (EndOffset+1)) {
  747. RtlCopyMemory(
  748. End->ipr_buffer + EndOffset + Diff,
  749. TempBuffer + EndOffset,
  750. Size - EndOffset
  751. );
  752. }
  753. FreeIprBuff(&SavedRcvBuf);
  754. //
  755. // Now copy over the buffers
  756. //
  757. Size = min(NewDataLength, Size);
  758. RtlCopyMemory(Start->ipr_buffer + StartOffset, NewData, Size);
  759. NewData += Size;
  760. NewDataLength -= Size;
  761. for (Temp = Start->ipr_next; Temp != End->ipr_next;
  762. Temp = Temp->ipr_next) {
  763. Size = min(NewDataLength, Size);
  764. RtlCopyMemory(Temp->ipr_buffer, NewData, Size);
  765. NewData += Size;
  766. NewDataLength -= Size;
  767. }
  768. //
  769. // Set up for checksum computation below
  770. //
  771. NewEnd = End;
  772. NewEndOffset = EndOffset + Diff;
  773. }
  774. else {
  775. //
  776. // Equal length. We just walk through copying over existing data
  777. //
  778. Size = min(NewDataLength, Start->ipr_size - StartOffset);
  779. RtlCopyMemory(Start->ipr_buffer + StartOffset, NewData, Size);
  780. NewData += Size;
  781. NewDataLength -= Size;
  782. for (Temp = Start->ipr_next; Temp != End->ipr_next;
  783. Temp = Temp->ipr_next) {
  784. Size = min(NewDataLength, Size);
  785. RtlCopyMemory(Temp->ipr_buffer, NewData, Size);
  786. NewData += Size;
  787. NewDataLength -= Size;
  788. }
  789. NewEnd = End;
  790. NewEndOffset = EndOffset;
  791. }
  792. //
  793. // Reset the 'Protocol' fields of the context which may be pointing
  794. // to memory that was freed above.
  795. //
  796. if (ResetIpHeader) {
  797. XLATECONTEXT->Header = (PIP_HEADER)XLATECONTEXT->RecvBuffer->ipr_buffer;
  798. }
  799. NAT_BUILD_XLATE_CONTEXT(
  800. XLATECONTEXT,
  801. XLATECONTEXT->Header,
  802. XLATECONTEXT->DestinationType,
  803. XLATECONTEXT->RecvBuffer,
  804. XLATECONTEXT->SourceAddress,
  805. XLATECONTEXT->DestinationAddress
  806. );
  807. //
  808. // If this is a UDP packet, update the length field in the protocol header
  809. //
  810. if (Diff && XLATECONTEXT->Header->Protocol == NAT_PROTOCOL_UDP) {
  811. PUDP_HEADER UdpHeader = (PUDP_HEADER)XLATECONTEXT->ProtocolHeader;
  812. UdpHeader->Length = NTOHS(UdpHeader->Length);
  813. UdpHeader->Length += (SHORT)Diff;
  814. UdpHeader->Length = NTOHS(UdpHeader->Length);
  815. }
  816. //
  817. // Update the packet's context to reflect the changes made
  818. //
  819. XLATECONTEXT->Flags |= NAT_XLATE_FLAG_EDITED;
  820. XLATECONTEXT->Header->TotalLength =
  821. NTOHS(XLATECONTEXT->Header->TotalLength) + (SHORT)Diff;
  822. XLATECONTEXT->Header->TotalLength =
  823. NTOHS(XLATECONTEXT->Header->TotalLength);
  824. XLATECONTEXT->TcpSeqNumDelta += Diff;
  825. return STATUS_SUCCESS;
  826. #undef XLATECONTEXT
  827. #undef RECVBUFFER
  828. } // NatEditorEditSession
  829. VOID
  830. NatEditorQueryInfoSession(
  831. IN PVOID SessionHandle,
  832. OUT PULONG PrivateAddress OPTIONAL,
  833. OUT PUSHORT PrivatePort OPTIONAL,
  834. OUT PULONG RemoteAddress OPTIONAL,
  835. OUT PUSHORT RemotePort OPTIONAL,
  836. OUT PULONG PublicAddress OPTIONAL,
  837. OUT PUSHORT PublicPort OPTIONAL,
  838. OUT PIP_NAT_SESSION_MAPPING_STATISTICS Statistics OPTIONAL
  839. )
  840. /*++
  841. Routine Description:
  842. This routine is called by editors to retrieve information about a session.
  843. Arguments:
  844. SessionHandle - handle of the session about which to retrieve information
  845. PrivateAddress - receives the IP address of the session's private endpoint
  846. PrivatePort - receives the protocol port of the session's private endpoint
  847. RemoteAddress - receives the IP address of the session's remote endpoint
  848. RemotePort - receives the protocol port of the session's remote endpoint
  849. PublicAddress - receives the IP address of the session's public endpoint
  850. PublicPort - receives the protocol port of the session's public endpoint
  851. Statistics - receives any statistics for the mapping
  852. Return Value:
  853. none.
  854. --*/
  855. {
  856. KIRQL Irql;
  857. CALLTRACE(("NatEditorQueryInfoSession\n"));
  858. KeAcquireSpinLock(&MappingLock, &Irql);
  859. NatQueryInformationMapping(
  860. (PNAT_DYNAMIC_MAPPING)SessionHandle,
  861. NULL,
  862. PrivateAddress,
  863. PrivatePort,
  864. RemoteAddress,
  865. RemotePort,
  866. PublicAddress,
  867. PublicPort,
  868. Statistics
  869. );
  870. KeReleaseSpinLock(&MappingLock, Irql);
  871. } // NatEditorQueryInfoSession
  872. VOID
  873. NatEditorTimeoutSession(
  874. IN PVOID EditorHandle,
  875. IN PVOID SessionHandle
  876. )
  877. /*++
  878. Routine Description:
  879. This routine is invoked by an editor to indicate that a given session
  880. should be timed out at the earliest opportunity.
  881. Arguments:
  882. EditorHandle - the editor requesting the timeout
  883. SessionHandle - the session to be timed-out
  884. Return Value:
  885. none.
  886. --*/
  887. {
  888. KeAcquireSpinLockAtDpcLevel(&((PNAT_DYNAMIC_MAPPING)SessionHandle)->Lock);
  889. NatExpireMapping((PNAT_DYNAMIC_MAPPING)SessionHandle);
  890. KeReleaseSpinLockFromDpcLevel(&((PNAT_DYNAMIC_MAPPING)SessionHandle)->Lock);
  891. } // NatEditorTimeoutSession