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.

2995 lines
88 KiB

  1. // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil -*- (for GNU Emacs)
  2. //
  3. // Copyright (c) 1985-2000 Microsoft Corporation
  4. //
  5. // This file is part of the Microsoft Research IPv6 Network Protocol Stack.
  6. // You should have received a copy of the Microsoft End-User License Agreement
  7. // for this software along with this release; see the file "license.txt".
  8. // If not, please see http://www.research.microsoft.com/msripv6/license.htm,
  9. // or write to Microsoft Research, One Microsoft Way, Redmond, WA 98052-6399.
  10. //
  11. // Abstract:
  12. //
  13. // NT specific routines for dispatching and handling IRPs.
  14. //
  15. #include <oscfg.h>
  16. #include <ndis.h>
  17. #include <tdikrnl.h>
  18. #include <tdint.h>
  19. #include <tdistat.h>
  20. #include <tdiinfo.h>
  21. #include <ip6imp.h>
  22. #include <ip6def.h>
  23. #include <ntddip6.h>
  24. #include "queue.h"
  25. #include "transprt.h"
  26. #include "addr.h"
  27. #include "tcp.h"
  28. #include "udp.h"
  29. #include "raw.h"
  30. #include <ntddtcp.h>
  31. #include "tcpcfg.h"
  32. #include "tcpconn.h"
  33. #include "tdilocal.h"
  34. //
  35. // Macros
  36. //
  37. //* Convert100nsToMillisconds
  38. //
  39. // Converts time expressed in hundreds of nanoseconds to milliseconds.
  40. //
  41. // REVIEW: replace RtlExtendedMagicDivide with 64 bit compiler support?
  42. //
  43. // LARGE_INTEGER // Returns: Time in milliseconds.
  44. // Convert100nsToMilliseconds(
  45. // IN LARGE_INTEGER HnsTime); // Time in hundreds of nanoseconds.
  46. //
  47. #define SHIFT10000 13
  48. static LARGE_INTEGER Magic10000 = {0xe219652c, 0xd1b71758};
  49. #define Convert100nsToMilliseconds(HnsTime) \
  50. RtlExtendedMagicDivide((HnsTime), Magic10000, SHIFT10000)
  51. //
  52. // Global variables
  53. //
  54. extern PSECURITY_DESCRIPTOR TcpAdminSecurityDescriptor;
  55. extern PDEVICE_OBJECT TCPDeviceObject, UDPDeviceObject;
  56. extern PDEVICE_OBJECT IPDeviceObject;
  57. extern PDEVICE_OBJECT RawIPDeviceObject;
  58. //
  59. // Local types
  60. //
  61. typedef struct {
  62. PIRP Irp;
  63. PMDL InputMdl;
  64. PMDL OutputMdl;
  65. TCP_REQUEST_QUERY_INFORMATION_EX QueryInformation;
  66. } TCP_QUERY_CONTEXT, *PTCP_QUERY_CONTEXT;
  67. //
  68. // General external function prototypes
  69. //
  70. extern
  71. NTSTATUS
  72. IPDispatch(
  73. IN PDEVICE_OBJECT DeviceObject,
  74. IN PIRP Irp
  75. );
  76. //
  77. // Other external functions
  78. //
  79. void
  80. TCPAbortAndIndicateDisconnect(
  81. CONNECTION_CONTEXT ConnnectionContext
  82. );
  83. //
  84. // Local pageable function prototypes
  85. //
  86. NTSTATUS
  87. TCPDispatchDeviceControl(
  88. IN PIRP Irp,
  89. IN PIO_STACK_LOCATION IrpSp
  90. );
  91. NTSTATUS
  92. TCPCreate(
  93. IN PDEVICE_OBJECT DeviceObject,
  94. IN PIRP Irp,
  95. IN PIO_STACK_LOCATION IrpSp
  96. );
  97. NTSTATUS
  98. TCPAssociateAddress(
  99. IN PIRP Irp,
  100. IN PIO_STACK_LOCATION IrpSp
  101. );
  102. NTSTATUS
  103. TCPSetEventHandler(
  104. IN PIRP Irp,
  105. IN PIO_STACK_LOCATION IrpSp
  106. );
  107. NTSTATUS
  108. TCPQueryInformation(
  109. IN PIRP Irp,
  110. IN PIO_STACK_LOCATION IrpSp
  111. );
  112. FILE_FULL_EA_INFORMATION UNALIGNED *
  113. FindEA(
  114. PFILE_FULL_EA_INFORMATION StartEA,
  115. CHAR *TargetName,
  116. USHORT TargetNameLength
  117. );
  118. BOOLEAN
  119. IsAdminIoRequest(
  120. PIRP Irp,
  121. PIO_STACK_LOCATION IrpSp
  122. );
  123. BOOLEAN
  124. IsDHCPZeroAddress(
  125. TRANSPORT_ADDRESS UNALIGNED *AddrList
  126. );
  127. ULONG
  128. RawExtractProtocolNumber(
  129. IN PUNICODE_STRING FileName
  130. );
  131. NTSTATUS
  132. TCPEnumerateConnectionList(
  133. IN PIRP Irp,
  134. IN PIO_STACK_LOCATION IrpSp
  135. );
  136. //
  137. // Local helper routine prototypes.
  138. //
  139. ULONG
  140. TCPGetMdlChainByteCount(
  141. PMDL Mdl
  142. );
  143. //
  144. // All of this code is pageable.
  145. //
  146. #ifdef ALLOC_PRAGMA
  147. #pragma alloc_text(PAGE, TCPDispatchDeviceControl)
  148. #pragma alloc_text(PAGE, TCPCreate)
  149. #pragma alloc_text(PAGE, TCPAssociateAddress)
  150. #pragma alloc_text(PAGE, TCPSetEventHandler)
  151. #pragma alloc_text(PAGE, FindEA)
  152. #pragma alloc_text(PAGE, IsDHCPZeroAddress)
  153. #pragma alloc_text(PAGE, RawExtractProtocolNumber)
  154. #pragma alloc_text(PAGE, IsAdminIoRequest)
  155. #endif // ALLOC_PRAGMA
  156. //
  157. // Generic Irp completion and cancellation routines.
  158. //
  159. //* TCPDataRequestComplete - Completes a UDP/TCP send/receive request.
  160. //
  161. NTSTATUS // Returns: Nothing.
  162. TCPDataRequestComplete(
  163. void *Context, // A pointer to the IRP for this request.
  164. unsigned int Status, // The final TDI status of the request.
  165. unsigned int ByteCount) // Bytes sent/received information.
  166. {
  167. KIRQL oldIrql;
  168. PIRP irp;
  169. PIO_STACK_LOCATION irpSp;
  170. PTCP_CONTEXT tcpContext;
  171. PIRP item = NULL;
  172. irp = (PIRP) Context;
  173. irpSp = IoGetCurrentIrpStackLocation(irp);
  174. tcpContext = (PTCP_CONTEXT) irpSp->FileObject->FsContext;
  175. if (IoSetCancelRoutine(irp, NULL) == NULL) {
  176. IoAcquireCancelSpinLock(&oldIrql);
  177. IoReleaseCancelSpinLock(oldIrql);
  178. }
  179. KeAcquireSpinLock(&tcpContext->EndpointLock, &oldIrql);
  180. #if DBG
  181. IF_TCPDBG(TCP_DEBUG_CANCEL) {
  182. PLIST_ENTRY entry, listHead;
  183. PIRP item = NULL;
  184. if (irp->Cancel) {
  185. ASSERT(irp->CancelRoutine == NULL);
  186. listHead = &(tcpContext->CancelledIrpList);
  187. } else {
  188. listHead = &(tcpContext->PendingIrpList);
  189. }
  190. //
  191. // Verify that the Irp is on the appropriate list.
  192. //
  193. for (entry = listHead->Flink; entry != listHead;
  194. entry = entry->Flink) {
  195. item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
  196. if (item == irp) {
  197. RemoveEntryList(&(irp->Tail.Overlay.ListEntry));
  198. break;
  199. }
  200. }
  201. ASSERT(item == irp);
  202. }
  203. #endif
  204. ASSERT(tcpContext->ReferenceCount > 0);
  205. if (--(tcpContext->ReferenceCount) == 0) {
  206. IF_TCPDBG(TCP_DEBUG_CANCEL) {
  207. ASSERT(IsListEmpty(&(tcpContext->CancelledIrpList)));
  208. ASSERT(IsListEmpty(&(tcpContext->PendingIrpList)));
  209. }
  210. //
  211. // Set the cleanup event.
  212. //
  213. KeSetEvent(&(tcpContext->CleanupEvent), 0, FALSE);
  214. }
  215. IF_TCPDBG(TCP_DEBUG_IRP) {
  216. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  217. "TCPDataRequestComplete: "
  218. "Irp %lx fileobj %lx refcnt dec to %u\n",
  219. irp, irpSp->FileObject, tcpContext->ReferenceCount));
  220. }
  221. if (irp->Cancel || tcpContext->CancelIrps) {
  222. IF_TCPDBG(TCP_DEBUG_IRP) {
  223. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  224. "TCPDataRequestComplete: Irp %lx was cancelled\n", irp));
  225. }
  226. Status = (unsigned int) STATUS_CANCELLED;
  227. ByteCount = 0;
  228. }
  229. KeReleaseSpinLock(&tcpContext->EndpointLock, oldIrql);
  230. IF_TCPDBG(TCP_DEBUG_IRP) {
  231. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  232. "TCPDataRequestComplete: completing irp %lx, status %lx,"
  233. " byte count %lx\n", irp, Status, ByteCount));
  234. }
  235. irp->IoStatus.Status = (NTSTATUS) Status;
  236. irp->IoStatus.Information = ByteCount;
  237. IoCompleteRequest(irp, IO_NETWORK_INCREMENT);
  238. return Status;
  239. } // TCPDataRequestComplete
  240. //* TCPRequestComplete - Completes a TDI request.
  241. //
  242. // Completes a cancellable TDI request which returns no data by
  243. // calling TCPDataRequestComplete with a ByteCount of zero.
  244. //
  245. void // Returns: Nothing.
  246. TCPRequestComplete(
  247. void *Context, // A pointer to the IRP for this request.
  248. unsigned int Status, // The final TDI status of the request.
  249. unsigned int UnUsed) // An unused parameter.
  250. {
  251. UNREFERENCED_PARAMETER(UnUsed);
  252. TCPDataRequestComplete(Context, Status, 0);
  253. } // TCPRequestComplete
  254. //* TCPNonCancellableRequestComplete - Complete uncancellable TDI request.
  255. //
  256. // Completes a TDI request which cannot be cancelled.
  257. //
  258. void // Returns: Nothing.
  259. TCPNonCancellableRequestComplete(
  260. void *Context, // A pointer to the IRP for this request.
  261. unsigned int Status, // The final TDI status of the request.
  262. unsigned int UnUsed) // An unused parameter.
  263. {
  264. PIRP irp;
  265. PIO_STACK_LOCATION irpSp;
  266. UNREFERENCED_PARAMETER(UnUsed);
  267. irp = (PIRP) Context;
  268. irpSp = IoGetCurrentIrpStackLocation(irp);
  269. IF_TCPDBG(TCP_DEBUG_CLOSE) {
  270. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  271. "TCPNonCancellableRequestComplete: irp %lx status %lx\n",
  272. irp, Status));
  273. }
  274. //
  275. // Complete the IRP.
  276. //
  277. irp->IoStatus.Status = (NTSTATUS) Status;
  278. irp->IoStatus.Information = 0;
  279. IoCompleteRequest(irp, IO_NETWORK_INCREMENT);
  280. return;
  281. } // TCPNonCancellableRequestComplete
  282. //* TCPCancelComplete
  283. //
  284. void
  285. TCPCancelComplete(
  286. void *Context,
  287. unsigned int Unused1,
  288. unsigned int Unused2)
  289. {
  290. PFILE_OBJECT fileObject = (PFILE_OBJECT) Context;
  291. PTCP_CONTEXT tcpContext = (PTCP_CONTEXT) fileObject->FsContext;
  292. KIRQL oldIrql;
  293. UNREFERENCED_PARAMETER(Unused1);
  294. UNREFERENCED_PARAMETER(Unused2);
  295. KeAcquireSpinLock(&tcpContext->EndpointLock, &oldIrql);
  296. //
  297. // Remove the reference placed on the endpoint by the cancel routine.
  298. // The cancelled Irp will be completed by the completion routine for the
  299. // request.
  300. //
  301. if (--(tcpContext->ReferenceCount) == 0) {
  302. IF_TCPDBG(TCP_DEBUG_CANCEL) {
  303. ASSERT(IsListEmpty(&(tcpContext->CancelledIrpList)));
  304. ASSERT(IsListEmpty(&(tcpContext->PendingIrpList)));
  305. }
  306. //
  307. // Set the cleanup event.
  308. //
  309. KeReleaseSpinLock(&tcpContext->EndpointLock, oldIrql);
  310. KeSetEvent(&(tcpContext->CleanupEvent), 0, FALSE);
  311. return;
  312. }
  313. IF_TCPDBG(TCP_DEBUG_IRP) {
  314. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  315. "TCPCancelComplete: fileobj %lx refcnt dec to %u\n",
  316. fileObject, tcpContext->ReferenceCount));
  317. }
  318. KeReleaseSpinLock(&tcpContext->EndpointLock, oldIrql);
  319. return;
  320. } // TCPCancelComplete
  321. //* TCPCancelRequest - Cancels an outstanding Irp.
  322. //
  323. // Cancel an outstanding Irp.
  324. //
  325. VOID // Returns: Nothing.
  326. TCPCancelRequest(
  327. PDEVICE_OBJECT Device, // Pointer to the device object for this request.
  328. PIRP Irp) // Pointer to I/O request packet.
  329. {
  330. PIO_STACK_LOCATION irpSp;
  331. PTCP_CONTEXT tcpContext;
  332. NTSTATUS status = STATUS_SUCCESS;
  333. PFILE_OBJECT fileObject;
  334. UCHAR minorFunction;
  335. TDI_REQUEST request;
  336. KIRQL CancelIrql;
  337. irpSp = IoGetCurrentIrpStackLocation(Irp);
  338. fileObject = irpSp->FileObject;
  339. tcpContext = (PTCP_CONTEXT) fileObject->FsContext;
  340. minorFunction = irpSp->MinorFunction;
  341. CancelIrql = Irp->CancelIrql;
  342. KeAcquireSpinLockAtDpcLevel(&tcpContext->EndpointLock);
  343. ASSERT(Irp->Cancel);
  344. IoReleaseCancelSpinLock(DISPATCH_LEVEL);
  345. IF_TCPDBG(TCP_DEBUG_IRP) {
  346. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  347. "TCPCancelRequest: cancelling irp %lx, file object %lx\n",
  348. Irp, fileObject));
  349. }
  350. #if DBG
  351. IF_TCPDBG(TCP_DEBUG_CANCEL) {
  352. //
  353. // Verify that the Irp is on the pending list.
  354. //
  355. PLIST_ENTRY entry;
  356. PIRP item = NULL;
  357. for (entry = tcpContext->PendingIrpList.Flink;
  358. entry != &(tcpContext->PendingIrpList); entry = entry->Flink) {
  359. item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
  360. if (item == Irp) {
  361. RemoveEntryList( &(Irp->Tail.Overlay.ListEntry));
  362. break;
  363. }
  364. }
  365. ASSERT(item == Irp);
  366. InsertTailList(&(tcpContext->CancelledIrpList),
  367. &(Irp->Tail.Overlay.ListEntry));
  368. }
  369. #endif // DBG
  370. //
  371. // Add a reference so the object can't be closed while the cancel routine
  372. // is executing.
  373. //
  374. ASSERT(tcpContext->ReferenceCount > 0);
  375. tcpContext->ReferenceCount++;
  376. IF_TCPDBG(TCP_DEBUG_IRP) {
  377. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  378. "TCPCancelRequest: Irp %lx fileobj %lx refcnt inc to %u\n",
  379. Irp, fileObject, tcpContext->ReferenceCount));
  380. }
  381. //
  382. // Try to cancel the request.
  383. //
  384. switch(minorFunction) {
  385. case TDI_SEND:
  386. case TDI_RECEIVE:
  387. KeReleaseSpinLock(&tcpContext->EndpointLock, CancelIrql);
  388. ASSERT((PtrToUlong(fileObject->FsContext2)) == TDI_CONNECTION_FILE);
  389. #ifndef UDP_ONLY
  390. TCPAbortAndIndicateDisconnect(tcpContext->Handle.ConnectionContext);
  391. #endif
  392. break;
  393. case TDI_SEND_DATAGRAM:
  394. ASSERT(PtrToUlong(fileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE);
  395. TdiCancelSendDatagram(tcpContext->Handle.AddressHandle, Irp,
  396. &tcpContext->EndpointLock, CancelIrql);
  397. break;
  398. case TDI_RECEIVE_DATAGRAM:
  399. ASSERT(PtrToUlong(fileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE);
  400. TdiCancelReceiveDatagram(tcpContext->Handle.AddressHandle, Irp,
  401. &tcpContext->EndpointLock, CancelIrql);
  402. break;
  403. case TDI_DISASSOCIATE_ADDRESS:
  404. ASSERT(PtrToUlong(fileObject->FsContext2) == TDI_CONNECTION_FILE);
  405. //
  406. // This pends but is not cancellable. We put it thru the cancel code
  407. // anyway so a reference is made for it and so it can be tracked in
  408. // a debug build.
  409. //
  410. KeReleaseSpinLock(&tcpContext->EndpointLock, CancelIrql);
  411. break;
  412. default:
  413. //
  414. // Initiate a disconnect to cancel the request.
  415. //
  416. KeReleaseSpinLock(&tcpContext->EndpointLock, CancelIrql);
  417. request.Handle.ConnectionContext =
  418. tcpContext->Handle.ConnectionContext;
  419. request.RequestNotifyObject = TCPCancelComplete;
  420. request.RequestContext = fileObject;
  421. status = TdiDisconnect(&request, NULL, TDI_DISCONNECT_ABORT, NULL,
  422. NULL);
  423. break;
  424. }
  425. if (status != TDI_PENDING) {
  426. TCPCancelComplete(fileObject, 0, 0);
  427. }
  428. return;
  429. } // TCPCancelRequest
  430. //* TCPPrepareIrpForCancel
  431. //
  432. NTSTATUS
  433. TCPPrepareIrpForCancel(
  434. PTCP_CONTEXT TcpContext,
  435. PIRP Irp,
  436. PDRIVER_CANCEL CancelRoutine)
  437. {
  438. KIRQL oldIrql;
  439. //
  440. // Set up for cancellation.
  441. //
  442. KeAcquireSpinLock(&TcpContext->EndpointLock, &oldIrql);
  443. ASSERT(Irp->CancelRoutine == NULL);
  444. if (!Irp->Cancel) {
  445. IoMarkIrpPending(Irp);
  446. IoSetCancelRoutine(Irp, CancelRoutine);
  447. TcpContext->ReferenceCount++;
  448. IF_TCPDBG(TCP_DEBUG_IRP) {
  449. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  450. "TCPPrepareIrpForCancel: irp %lx fileobj %lx refcnt inc"
  451. " to %u\n", Irp,
  452. (IoGetCurrentIrpStackLocation(Irp))->FileObject,
  453. TcpContext->ReferenceCount));
  454. }
  455. #if DBG
  456. IF_TCPDBG(TCP_DEBUG_CANCEL) {
  457. PLIST_ENTRY entry;
  458. PIRP item = NULL;
  459. //
  460. // Verify that the Irp has not already been submitted.
  461. //
  462. for (entry = TcpContext->PendingIrpList.Flink;
  463. entry != &(TcpContext->PendingIrpList);
  464. entry = entry->Flink) {
  465. item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
  466. ASSERT(item != Irp);
  467. }
  468. for (entry = TcpContext->CancelledIrpList.Flink;
  469. entry != &(TcpContext->CancelledIrpList);
  470. entry = entry->Flink) {
  471. item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
  472. ASSERT(item != Irp);
  473. }
  474. InsertTailList(&(TcpContext->PendingIrpList),
  475. &(Irp->Tail.Overlay.ListEntry));
  476. }
  477. #endif // DBG
  478. KeReleaseSpinLock(&TcpContext->EndpointLock, oldIrql);
  479. return(STATUS_SUCCESS);
  480. }
  481. //
  482. // The IRP has already been cancelled. Complete it now.
  483. //
  484. IF_TCPDBG(TCP_DEBUG_IRP) {
  485. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  486. "TCP: irp %lx already cancelled, completing.\n", Irp));
  487. }
  488. KeReleaseSpinLock(&TcpContext->EndpointLock, oldIrql);
  489. Irp->IoStatus.Status = STATUS_CANCELLED;
  490. Irp->IoStatus.Information = 0;
  491. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  492. return(STATUS_CANCELLED);
  493. } // TCPPrepareIrpForCancel
  494. //
  495. // TDI functions.
  496. //
  497. //* TCPAssociateAddress - Handle TDI Associate Address IRP.
  498. //
  499. // Converts a TDI Associate Address IRP into a call to TdiAssociateAddress.
  500. //
  501. // This routine does not pend.
  502. //
  503. NTSTATUS // Returns: indication of whether the request was successful.
  504. TCPAssociateAddress(
  505. IN PIRP Irp, // I/O request packet.
  506. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  507. {
  508. NTSTATUS status;
  509. TDI_REQUEST request;
  510. PTCP_CONTEXT tcpContext;
  511. PTDI_REQUEST_KERNEL_ASSOCIATE associateInformation;
  512. PFILE_OBJECT fileObject;
  513. PAGED_CODE();
  514. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  515. request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
  516. associateInformation =
  517. (PTDI_REQUEST_KERNEL_ASSOCIATE) &(IrpSp->Parameters);
  518. //
  519. // Get the file object for the address. Then extract the Address Handle
  520. // from the TCP_CONTEXT associated with it.
  521. //
  522. status = ObReferenceObjectByHandle(associateInformation->AddressHandle,
  523. 0, *IoFileObjectType, Irp->RequestorMode,
  524. &fileObject, NULL);
  525. if (NT_SUCCESS(status)) {
  526. if ((fileObject->DeviceObject == TCPDeviceObject) &&
  527. (PtrToUlong(fileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE)) {
  528. tcpContext = (PTCP_CONTEXT) fileObject->FsContext;
  529. status = TdiAssociateAddress(&request,
  530. tcpContext->Handle.AddressHandle);
  531. ASSERT(status != STATUS_PENDING);
  532. ObDereferenceObject(fileObject);
  533. IF_TCPDBG(TCP_DEBUG_ASSOCIATE) {
  534. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  535. "TCPAssociateAddress complete on file object %lx\n",
  536. IrpSp->FileObject));
  537. }
  538. } else {
  539. ObDereferenceObject(fileObject);
  540. status = STATUS_INVALID_HANDLE;
  541. IF_TCPDBG(TCP_DEBUG_ASSOCIATE) {
  542. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  543. "TCPAssociateAddress: ObReference failed on object"
  544. " %lx, status %lx\n",
  545. associateInformation->AddressHandle, status));
  546. }
  547. }
  548. } else {
  549. IF_TCPDBG(TCP_DEBUG_ASSOCIATE) {
  550. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  551. "TCPAssociateAddress: ObReference failed on object %lx,"
  552. " status %lx\n", associateInformation->AddressHandle,
  553. status));
  554. }
  555. }
  556. return(status);
  557. }
  558. //* TCPDisassociateAddress - Handle TDI Disassociate Address IRP.
  559. //
  560. // Converts a TDI Disassociate Address IRP into a call to
  561. // TdiDisassociateAddress.
  562. NTSTATUS // Returns: Indication of whether the request was successful.
  563. TCPDisassociateAddress(
  564. IN PIRP Irp, // I/O request packet.
  565. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  566. {
  567. NTSTATUS status;
  568. TDI_REQUEST request;
  569. PTCP_CONTEXT tcpContext;
  570. IF_TCPDBG(TCP_DEBUG_ASSOCIATE) {
  571. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  572. "TCP disassociating address\n"));
  573. }
  574. ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE);
  575. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  576. request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
  577. request.RequestNotifyObject = TCPRequestComplete;
  578. request.RequestContext = Irp;
  579. status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
  580. if (NT_SUCCESS(status)) {
  581. status = TdiDisAssociateAddress(&request);
  582. if (status != TDI_PENDING) {
  583. TCPRequestComplete(Irp, status, 0);
  584. }
  585. //
  586. // Return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING.
  587. //
  588. return(TDI_PENDING);
  589. }
  590. return(status);
  591. } // TCPDisassociateAddress
  592. //* TCPConnect - Handle TDI Connect IRP.
  593. //
  594. // Converts a TDI Connect IRP into a call to TdiConnect.
  595. //
  596. NTSTATUS // Returns: Whether the request was successfully queued.
  597. TCPConnect(
  598. IN PIRP Irp, // Pointer to I/O request packet.
  599. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  600. {
  601. NTSTATUS status;
  602. PTCP_CONTEXT tcpContext;
  603. TDI_REQUEST request;
  604. PTDI_CONNECTION_INFORMATION requestInformation, returnInformation;
  605. PTDI_REQUEST_KERNEL_CONNECT connectRequest;
  606. LARGE_INTEGER millisecondTimeout;
  607. PLARGE_INTEGER requestTimeout;
  608. IF_TCPDBG(TCP_DEBUG_CONNECT) {
  609. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  610. "TCPConnect irp %lx, file object %lx\n", Irp,
  611. IrpSp->FileObject));
  612. }
  613. ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE);
  614. connectRequest = (PTDI_REQUEST_KERNEL_CONNECT) &(IrpSp->Parameters);
  615. requestInformation = connectRequest->RequestConnectionInformation;
  616. returnInformation = connectRequest->ReturnConnectionInformation;
  617. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  618. request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
  619. request.RequestNotifyObject = TCPRequestComplete;
  620. request.RequestContext = Irp;
  621. requestTimeout = (PLARGE_INTEGER) connectRequest->RequestSpecific;
  622. if (requestTimeout != NULL) {
  623. //
  624. // NT relative timeouts are negative. Negate first to get a positive
  625. // value to pass to the transport.
  626. //
  627. millisecondTimeout.QuadPart = -((*requestTimeout).QuadPart);
  628. millisecondTimeout = Convert100nsToMilliseconds(millisecondTimeout);
  629. } else {
  630. millisecondTimeout.LowPart = 0;
  631. millisecondTimeout.HighPart = 0;
  632. }
  633. ASSERT(millisecondTimeout.HighPart == 0);
  634. status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
  635. if (NT_SUCCESS(status)) {
  636. status = TdiConnect(&request, ((millisecondTimeout.LowPart != 0) ?
  637. &(millisecondTimeout.LowPart) : NULL),
  638. requestInformation, returnInformation);
  639. if (status != STATUS_PENDING) {
  640. TCPRequestComplete(Irp, status, 0);
  641. }
  642. //
  643. // Return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING.
  644. //
  645. return(STATUS_PENDING);
  646. }
  647. return(status);
  648. } // TCPConnect
  649. //* TCPDisconnect - Handler for TDI Disconnect IRP
  650. //
  651. // Converts a TDI Disconnect IRP into a call to TdiDisconnect.
  652. //
  653. NTSTATUS // Returns: whether the request was successfully queued.
  654. TCPDisconnect(
  655. IN PIRP Irp, // I/O request packet.
  656. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  657. {
  658. NTSTATUS status;
  659. PTCP_CONTEXT tcpContext;
  660. TDI_REQUEST request;
  661. PTDI_CONNECTION_INFORMATION requestInformation, returnInformation;
  662. PTDI_REQUEST_KERNEL_DISCONNECT disconnectRequest;
  663. LARGE_INTEGER millisecondTimeout;
  664. PLARGE_INTEGER requestTimeout;
  665. BOOLEAN abortive = FALSE;
  666. ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE);
  667. disconnectRequest = (PTDI_REQUEST_KERNEL_CONNECT) &(IrpSp->Parameters);
  668. requestInformation = disconnectRequest->RequestConnectionInformation;
  669. returnInformation = disconnectRequest->ReturnConnectionInformation;
  670. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  671. request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
  672. request.RequestContext = Irp;
  673. //
  674. // Set up the timeout value.
  675. //
  676. if (disconnectRequest->RequestSpecific != NULL) {
  677. requestTimeout = (PLARGE_INTEGER) disconnectRequest->RequestSpecific;
  678. if ((requestTimeout->LowPart == -1) &&
  679. (requestTimeout->HighPart == -1)) {
  680. millisecondTimeout.LowPart = requestTimeout->LowPart;
  681. millisecondTimeout.HighPart = 0;
  682. } else {
  683. //
  684. // NT relative timeouts are negative. Negate first to get a
  685. // positive value to pass to the transport.
  686. //
  687. millisecondTimeout.QuadPart = -((*requestTimeout).QuadPart);
  688. millisecondTimeout = Convert100nsToMilliseconds(
  689. millisecondTimeout);
  690. }
  691. } else {
  692. millisecondTimeout.LowPart = 0;
  693. millisecondTimeout.HighPart = 0;
  694. }
  695. ASSERT(millisecondTimeout.HighPart == 0);
  696. if (disconnectRequest->RequestFlags & TDI_DISCONNECT_ABORT) {
  697. //
  698. // Abortive disconnects cannot be cancelled and must use
  699. // a specific completion routine.
  700. //
  701. abortive = TRUE;
  702. IoMarkIrpPending(Irp);
  703. request.RequestNotifyObject = TCPNonCancellableRequestComplete;
  704. status = STATUS_SUCCESS;
  705. } else {
  706. //
  707. // Non-abortive disconnects can use the generic cancellation and
  708. // completion routines.
  709. //
  710. status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
  711. request.RequestNotifyObject = TCPRequestComplete;
  712. }
  713. IF_TCPDBG(TCP_DEBUG_CLOSE) {
  714. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  715. "TCPDisconnect "
  716. "irp %lx, flags %lx, fileobj %lx, abortive = %d\n",
  717. Irp, disconnectRequest->RequestFlags, IrpSp->FileObject,
  718. abortive));
  719. }
  720. if (NT_SUCCESS(status)) {
  721. status = TdiDisconnect(&request,((millisecondTimeout.LowPart != 0) ?
  722. &(millisecondTimeout.LowPart) : NULL),
  723. (ushort) disconnectRequest->RequestFlags,
  724. requestInformation, returnInformation);
  725. if (status != STATUS_PENDING) {
  726. if (abortive) {
  727. TCPNonCancellableRequestComplete(Irp, status, 0);
  728. } else {
  729. TCPRequestComplete(Irp, status, 0);
  730. }
  731. } else {
  732. IF_TCPDBG(TCP_DEBUG_CLOSE) {
  733. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  734. "TCPDisconnect pending irp %lx\n", Irp));
  735. }
  736. }
  737. //
  738. // return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING
  739. //
  740. return(STATUS_PENDING);
  741. }
  742. return(status);
  743. } // TCPDisconnect
  744. //* TCPListen - Handler for TDI Listen IRP.
  745. //
  746. // Converts a TDI Listen IRP into a call to TdiListen.
  747. //
  748. NTSTATUS // Returns: whether or not the request was successful.
  749. TCPListen(
  750. IN PIRP Irp, // I/O request packet.
  751. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  752. {
  753. NTSTATUS status;
  754. PTCP_CONTEXT tcpContext;
  755. TDI_REQUEST request;
  756. PTDI_CONNECTION_INFORMATION requestInformation, returnInformation;
  757. PTDI_REQUEST_KERNEL_LISTEN listenRequest;
  758. IF_TCPDBG(TCP_DEBUG_CONNECT) {
  759. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  760. "TCPListen irp %lx on file object %lx\n",
  761. Irp, IrpSp->FileObject));
  762. }
  763. ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE);
  764. listenRequest = (PTDI_REQUEST_KERNEL_CONNECT) &(IrpSp->Parameters);
  765. requestInformation = listenRequest->RequestConnectionInformation;
  766. returnInformation = listenRequest->ReturnConnectionInformation;
  767. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  768. request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
  769. request.RequestNotifyObject = TCPRequestComplete;
  770. request.RequestContext = Irp;
  771. status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
  772. if (NT_SUCCESS(status)) {
  773. status = TdiListen(&request, (ushort) listenRequest->RequestFlags,
  774. requestInformation, returnInformation);
  775. if (status != TDI_PENDING) {
  776. TCPRequestComplete(Irp, status, 0);
  777. }
  778. //
  779. // return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING
  780. //
  781. return(TDI_PENDING);
  782. }
  783. return(status);
  784. } // TCPListen
  785. //* TCPAccept - Handle a TDI Accept IRP.
  786. //
  787. // Converts a TDI Accept IRP into a call to TdiAccept.
  788. //
  789. NTSTATUS // Returns: whether the request was successfully queued.
  790. TCPAccept(
  791. IN PIRP Irp, // I/O request packet.
  792. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  793. {
  794. NTSTATUS status;
  795. PTCP_CONTEXT tcpContext;
  796. TDI_REQUEST request;
  797. PTDI_CONNECTION_INFORMATION requestInformation, returnInformation;
  798. PTDI_REQUEST_KERNEL_ACCEPT acceptRequest;
  799. IF_TCPDBG(TCP_DEBUG_CONNECT) {
  800. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  801. "TCPAccept irp %lx on file object %lx\n", Irp,
  802. IrpSp->FileObject));
  803. }
  804. ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE);
  805. acceptRequest = (PTDI_REQUEST_KERNEL_ACCEPT) &(IrpSp->Parameters);
  806. requestInformation = acceptRequest->RequestConnectionInformation;
  807. returnInformation = acceptRequest->ReturnConnectionInformation;
  808. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  809. request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
  810. request.RequestNotifyObject = TCPRequestComplete;
  811. request.RequestContext = Irp;
  812. status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
  813. if (NT_SUCCESS(status)) {
  814. status = TdiAccept(&request, requestInformation, returnInformation);
  815. if (status != TDI_PENDING) {
  816. TCPRequestComplete(Irp, status, 0);
  817. }
  818. //
  819. // Return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING.
  820. //
  821. return(TDI_PENDING);
  822. }
  823. return(status);
  824. } // TCPAccept
  825. //* TCPSendData - Handle TDI Send IRP.
  826. //
  827. // Converts a TDI Send IRP into a call to TdiSend.
  828. //
  829. NTSTATUS
  830. TCPSendData(
  831. IN PIRP Irp, // I/O request packet.
  832. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  833. {
  834. TDI_STATUS status;
  835. TDI_REQUEST request;
  836. PTCP_CONTEXT tcpContext;
  837. PTDI_REQUEST_KERNEL_SEND requestInformation;
  838. KIRQL oldIrql;
  839. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  840. ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE);
  841. requestInformation = (PTDI_REQUEST_KERNEL_SEND) &(IrpSp->Parameters);
  842. request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
  843. request.RequestNotifyObject = TCPDataRequestComplete;
  844. request.RequestContext = Irp;
  845. KeAcquireSpinLock(&tcpContext->EndpointLock, &oldIrql);
  846. IoSetCancelRoutine(Irp, TCPCancelRequest);
  847. if (!Irp->Cancel) {
  848. //
  849. // Set up for cancellation.
  850. //
  851. IoMarkIrpPending(Irp);
  852. tcpContext->ReferenceCount++;
  853. IF_TCPDBG(TCP_DEBUG_IRP) {
  854. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  855. "TCPSendData: irp %lx fileobj %lx refcnt inc to %u\n",
  856. Irp, IrpSp, tcpContext->ReferenceCount));
  857. }
  858. #if DBG
  859. IF_TCPDBG(TCP_DEBUG_CANCEL) {
  860. PLIST_ENTRY entry;
  861. PIRP item = NULL;
  862. //
  863. // Verify that the Irp has not already been submitted.
  864. //
  865. for (entry = tcpContext->PendingIrpList.Flink;
  866. entry != &(tcpContext->PendingIrpList);
  867. entry = entry->Flink) {
  868. item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
  869. ASSERT(item != Irp);
  870. }
  871. for (entry = tcpContext->CancelledIrpList.Flink;
  872. entry != &(tcpContext->CancelledIrpList);
  873. entry = entry->Flink) {
  874. item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
  875. ASSERT(item != Irp);
  876. }
  877. InsertTailList(&(tcpContext->PendingIrpList),
  878. &(Irp->Tail.Overlay.ListEntry));
  879. }
  880. #endif // DBG
  881. KeReleaseSpinLock(&tcpContext->EndpointLock, oldIrql);
  882. IF_TCPDBG(TCP_DEBUG_SEND) {
  883. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  884. "TCPSendData irp %lx sending %d bytes, flags %lx,"
  885. " fileobj %lx\n", Irp, requestInformation->SendLength,
  886. requestInformation->SendFlags, IrpSp->FileObject));
  887. }
  888. status = TdiSend(&request, (ushort) requestInformation->SendFlags,
  889. requestInformation->SendLength,
  890. (PNDIS_BUFFER) Irp->MdlAddress);
  891. if (status == TDI_PENDING) {
  892. IF_TCPDBG(TCP_DEBUG_SEND) {
  893. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  894. "TCPSendData pending irp %lx\n", Irp));
  895. }
  896. return(status);
  897. }
  898. //
  899. // The status is not pending. We reset the pending bit
  900. //
  901. IrpSp->Control &= ~SL_PENDING_RETURNED;
  902. if (status == TDI_SUCCESS) {
  903. ASSERT(requestInformation->SendLength == 0);
  904. status = TCPDataRequestComplete(Irp, status,
  905. requestInformation->SendLength);
  906. } else {
  907. IF_TCPDBG(TCP_DEBUG_SEND) {
  908. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  909. "TCPSendData - irp %lx send failed, status %lx\n",
  910. Irp, status));
  911. }
  912. status = TCPDataRequestComplete(Irp, status, 0);
  913. }
  914. } else {
  915. //
  916. // Irp was cancelled previously.
  917. //
  918. KeReleaseSpinLock(&tcpContext->EndpointLock, oldIrql);
  919. //
  920. // Ensure that the cancel-routine has executed.
  921. //
  922. IoAcquireCancelSpinLock(&oldIrql);
  923. IoReleaseCancelSpinLock(oldIrql);
  924. KeAcquireSpinLock(&tcpContext->EndpointLock, &oldIrql);
  925. IoSetCancelRoutine(Irp, NULL);
  926. KeReleaseSpinLock(&tcpContext->EndpointLock, oldIrql);
  927. IF_TCPDBG(TCP_DEBUG_SEND) {
  928. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  929. "TCPSendData: Irp %lx on fileobj %lx was cancelled\n",
  930. Irp, IrpSp->FileObject));
  931. }
  932. Irp->IoStatus.Status = STATUS_CANCELLED;
  933. Irp->IoStatus.Information = 0;
  934. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  935. status = STATUS_CANCELLED;
  936. }
  937. return(status);
  938. } // TCPSendData
  939. //* TCPReceiveData - Handler for TDI Receive IRP.
  940. //
  941. // Converts a TDI Receive IRP into a call to TdiReceive.
  942. //
  943. NTSTATUS // Returns: whether the request was successful.
  944. TCPReceiveData(
  945. IN PIRP Irp, // I/O request packet.
  946. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  947. {
  948. TDI_STATUS status;
  949. TDI_REQUEST request;
  950. PTCP_CONTEXT tcpContext;
  951. PTDI_REQUEST_KERNEL_RECEIVE requestInformation;
  952. KIRQL oldIrql;
  953. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  954. ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE);
  955. requestInformation = (PTDI_REQUEST_KERNEL_RECEIVE) &(IrpSp->Parameters);
  956. request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
  957. request.RequestNotifyObject = TCPDataRequestComplete;
  958. request.RequestContext = Irp;
  959. KeAcquireSpinLock(&tcpContext->EndpointLock, &oldIrql);
  960. IoSetCancelRoutine(Irp, TCPCancelRequest);
  961. if (!Irp->Cancel) {
  962. //
  963. // Set up for cancellation.
  964. //
  965. IoMarkIrpPending(Irp);
  966. tcpContext->ReferenceCount++;
  967. IF_TCPDBG(TCP_DEBUG_IRP) {
  968. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  969. "TCPReceiveData: irp %lx fileobj %lx refcnt inc to %u\n",
  970. Irp, IrpSp->FileObject, tcpContext->ReferenceCount));
  971. }
  972. #if DBG
  973. IF_TCPDBG(TCP_DEBUG_CANCEL) {
  974. PLIST_ENTRY entry;
  975. PIRP item = NULL;
  976. //
  977. // Verify that the Irp has not already been submitted.
  978. //
  979. for (entry = tcpContext->PendingIrpList.Flink;
  980. entry != &(tcpContext->PendingIrpList);
  981. entry = entry->Flink) {
  982. item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
  983. ASSERT(item != Irp);
  984. }
  985. for (entry = tcpContext->CancelledIrpList.Flink;
  986. entry != &(tcpContext->CancelledIrpList);
  987. entry = entry->Flink) {
  988. item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
  989. ASSERT(item != Irp);
  990. }
  991. InsertTailList(&(tcpContext->PendingIrpList),
  992. &(Irp->Tail.Overlay.ListEntry));
  993. }
  994. #endif // DBG
  995. KeReleaseSpinLock(&tcpContext->EndpointLock, oldIrql);
  996. IF_TCPDBG(TCP_DEBUG_RECEIVE) {
  997. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  998. "TCPReceiveData irp %lx receiving %d bytes flags %lx"
  999. " filobj %lx\n", Irp, requestInformation->ReceiveLength,
  1000. requestInformation->ReceiveFlags, IrpSp->FileObject));
  1001. }
  1002. status = TdiReceive(&request,
  1003. (ushort *) &(requestInformation->ReceiveFlags),
  1004. &(requestInformation->ReceiveLength),
  1005. (PNDIS_BUFFER) Irp->MdlAddress);
  1006. if (status == TDI_PENDING) {
  1007. IF_TCPDBG(TCP_DEBUG_RECEIVE) {
  1008. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1009. "TCPReceiveData: pending irp %lx\n", Irp));
  1010. }
  1011. return(status);
  1012. }
  1013. //
  1014. // The status is not pending. We reset the pending bit
  1015. //
  1016. IrpSp->Control &= ~SL_PENDING_RETURNED;
  1017. IF_TCPDBG(TCP_DEBUG_RECEIVE) {
  1018. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1019. "TCPReceiveData - irp %lx failed, status %lx\n",
  1020. Irp, status));
  1021. }
  1022. status = TCPDataRequestComplete(Irp, status, 0);
  1023. } else {
  1024. //
  1025. // Irp was cancelled previously.
  1026. //
  1027. KeReleaseSpinLock(&tcpContext->EndpointLock, oldIrql);
  1028. //
  1029. // Ensure that the cancel-routine has executed.
  1030. //
  1031. IoAcquireCancelSpinLock(&oldIrql);
  1032. IoReleaseCancelSpinLock(oldIrql);
  1033. KeAcquireSpinLock(&tcpContext->EndpointLock, &oldIrql);
  1034. IoSetCancelRoutine(Irp, NULL);
  1035. KeReleaseSpinLock(&tcpContext->EndpointLock, oldIrql);
  1036. IF_TCPDBG(TCP_DEBUG_SEND) {
  1037. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1038. "TCPReceiveData: Irp %lx on fileobj %lx was cancelled\n",
  1039. Irp, IrpSp->FileObject));
  1040. }
  1041. Irp->IoStatus.Status = STATUS_CANCELLED;
  1042. Irp->IoStatus.Information = 0;
  1043. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  1044. status = STATUS_CANCELLED;
  1045. }
  1046. return status;
  1047. } // TCPReceiveData
  1048. //* UDPSendDatagram -
  1049. //
  1050. NTSTATUS // Returns: whether the request was successfully queued.
  1051. UDPSendDatagram(
  1052. IN PIRP Irp, // I/O request packet.
  1053. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  1054. {
  1055. TDI_STATUS status;
  1056. TDI_REQUEST request;
  1057. PTCP_CONTEXT tcpContext;
  1058. PTDI_REQUEST_KERNEL_SENDDG datagramInformation;
  1059. ULONG bytesSent = 0;
  1060. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  1061. datagramInformation = (PTDI_REQUEST_KERNEL_SENDDG) &(IrpSp->Parameters);
  1062. ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) ==
  1063. TDI_TRANSPORT_ADDRESS_FILE);
  1064. request.Handle.AddressHandle = tcpContext->Handle.AddressHandle;
  1065. request.RequestNotifyObject = TCPDataRequestComplete;
  1066. request.RequestContext = Irp;
  1067. IF_TCPDBG(TCP_DEBUG_SEND_DGRAM) {
  1068. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1069. "UDPSendDatagram irp %lx sending %d bytes\n", Irp,
  1070. datagramInformation->SendLength));
  1071. }
  1072. status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
  1073. if (NT_SUCCESS(status)) {
  1074. status = TdiSendDatagram(&request,
  1075. datagramInformation->SendDatagramInformation,
  1076. datagramInformation->SendLength, &bytesSent,
  1077. (PNDIS_BUFFER) Irp->MdlAddress);
  1078. if (status == TDI_PENDING) {
  1079. return(status);
  1080. }
  1081. ASSERT(status != TDI_SUCCESS);
  1082. ASSERT(bytesSent == 0);
  1083. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INTERNAL_ERROR,
  1084. "UDPSendDatagram - irp %lx send failed, status %lx\n",
  1085. Irp, status));
  1086. TCPDataRequestComplete(Irp, status, bytesSent);
  1087. //
  1088. // Return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING.
  1089. //
  1090. return(TDI_PENDING);
  1091. }
  1092. return status;
  1093. } // UDPSendDatagram
  1094. //* UDPReceiveDatagram - Handle TDI ReceiveDatagram IRP.
  1095. //
  1096. // Converts a TDI ReceiveDatagram IRP into a call to TdiReceiveDatagram.
  1097. //
  1098. NTSTATUS // Returns: whether the request was successful.
  1099. UDPReceiveDatagram(
  1100. IN PIRP Irp, // I/O request packet.
  1101. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  1102. {
  1103. TDI_STATUS status;
  1104. TDI_REQUEST request;
  1105. PTCP_CONTEXT tcpContext;
  1106. PTDI_REQUEST_KERNEL_RECEIVEDG datagramInformation;
  1107. uint bytesReceived = 0;
  1108. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  1109. datagramInformation = (PTDI_REQUEST_KERNEL_RECEIVEDG) &(IrpSp->Parameters);
  1110. ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) ==
  1111. TDI_TRANSPORT_ADDRESS_FILE);
  1112. request.Handle.AddressHandle = tcpContext->Handle.AddressHandle;
  1113. request.RequestNotifyObject = TCPDataRequestComplete;
  1114. request.RequestContext = Irp;
  1115. IF_TCPDBG(TCP_DEBUG_RECEIVE_DGRAM) {
  1116. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1117. "UDPReceiveDatagram: irp %lx receiveing %d bytes\n", Irp,
  1118. datagramInformation->ReceiveLength));
  1119. }
  1120. status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
  1121. if (NT_SUCCESS(status)) {
  1122. status = TdiReceiveDatagram(&request,
  1123. datagramInformation->ReceiveDatagramInformation,
  1124. datagramInformation->ReturnDatagramInformation,
  1125. datagramInformation->ReceiveLength, &bytesReceived,
  1126. Irp->MdlAddress);
  1127. if (status == TDI_PENDING) {
  1128. return(status);
  1129. }
  1130. ASSERT(status != TDI_SUCCESS);
  1131. ASSERT(bytesReceived == 0);
  1132. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INTERNAL_ERROR,
  1133. "UDPReceiveDatagram: irp %lx send failed, status %lx\n",
  1134. Irp, status));
  1135. TCPDataRequestComplete(Irp, status, bytesReceived);
  1136. //
  1137. // Return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING.
  1138. //
  1139. return(TDI_PENDING);
  1140. }
  1141. return status;
  1142. } // UDPReceiveDatagram
  1143. //* TCPSetEventHandler - Handle TDI SetEventHandler IRP.
  1144. //
  1145. // Converts a TDI SetEventHandler IRP into a call to TdiSetEventHandler.
  1146. //
  1147. NTSTATUS // Returns: whether the request was successful.
  1148. TCPSetEventHandler(
  1149. IN PIRP Irp, // I/O request packet.
  1150. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  1151. {
  1152. NTSTATUS status;
  1153. PTDI_REQUEST_KERNEL_SET_EVENT event;
  1154. PTCP_CONTEXT tcpContext;
  1155. PAGED_CODE();
  1156. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  1157. event = (PTDI_REQUEST_KERNEL_SET_EVENT) &(IrpSp->Parameters);
  1158. IF_TCPDBG(TCP_DEBUG_EVENT_HANDLER) {
  1159. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1160. "TCPSetEventHandler: "
  1161. "irp %lx event %lx handler %lx context %lx\n", Irp,
  1162. event->EventType, event->EventHandler, event->EventContext));
  1163. }
  1164. status = TdiSetEvent(tcpContext->Handle.AddressHandle, event->EventType,
  1165. event->EventHandler, event->EventContext);
  1166. ASSERT(status != TDI_PENDING);
  1167. return(status);
  1168. } // TCPSetEventHandler
  1169. //* TCPQueryInformation - Handle a TDI QueryInformation IRP.
  1170. //
  1171. // Converts a TDI QueryInformation IRP into a call to TdiQueryInformation.
  1172. //
  1173. NTSTATUS // Returns: whether request was successful.
  1174. TCPQueryInformation(
  1175. IN PIRP Irp, // I/O request packet.
  1176. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  1177. {
  1178. TDI_REQUEST request;
  1179. TDI_STATUS status = STATUS_SUCCESS;
  1180. PTCP_CONTEXT tcpContext;
  1181. PTDI_REQUEST_KERNEL_QUERY_INFORMATION queryInformation;
  1182. uint isConn = FALSE;
  1183. uint dataSize = 0;
  1184. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  1185. queryInformation = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)
  1186. &(IrpSp->Parameters);
  1187. request.RequestNotifyObject = TCPDataRequestComplete;
  1188. request.RequestContext = Irp;
  1189. switch(queryInformation->QueryType) {
  1190. case TDI_QUERY_BROADCAST_ADDRESS:
  1191. ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) ==
  1192. TDI_CONTROL_CHANNEL_FILE);
  1193. request.Handle.ControlChannel = tcpContext->Handle.ControlChannel;
  1194. break;
  1195. case TDI_QUERY_PROVIDER_INFO:
  1196. //
  1197. // NetBT does this. Reinstate the ASSERT when it is fixed.
  1198. //
  1199. // ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) ==
  1200. // TDI_CONTROL_CHANNEL_FILE);
  1201. request.Handle.ControlChannel = tcpContext->Handle.ControlChannel;
  1202. break;
  1203. case TDI_QUERY_ADDRESS_INFO:
  1204. if (PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE) {
  1205. //
  1206. // This is a TCP connection object.
  1207. //
  1208. isConn = TRUE;
  1209. request.Handle.ConnectionContext =
  1210. tcpContext->Handle.ConnectionContext;
  1211. } else {
  1212. //
  1213. // This is an address object.
  1214. //
  1215. request.Handle.AddressHandle = tcpContext->Handle.AddressHandle;
  1216. }
  1217. break;
  1218. case TDI_QUERY_CONNECTION_INFO:
  1219. if (PtrToUlong(IrpSp->FileObject->FsContext2) != TDI_CONNECTION_FILE){
  1220. status = STATUS_INVALID_PARAMETER;
  1221. } else {
  1222. isConn = TRUE;
  1223. request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
  1224. }
  1225. break;
  1226. case TDI_QUERY_PROVIDER_STATISTICS:
  1227. request.Handle.ControlChannel = tcpContext->Handle.ControlChannel;
  1228. break;
  1229. default:
  1230. status = STATUS_NOT_IMPLEMENTED;
  1231. break;
  1232. }
  1233. if (NT_SUCCESS(status)) {
  1234. //
  1235. // This request isn't cancellable, but we put it through
  1236. // the cancel path because it handles some checks for us
  1237. // and tracks the irp.
  1238. //
  1239. status = TCPPrepareIrpForCancel(tcpContext, Irp, NULL);
  1240. if (NT_SUCCESS(status)) {
  1241. dataSize = TCPGetMdlChainByteCount(Irp->MdlAddress);
  1242. status = TdiQueryInformation(&request, queryInformation->QueryType,
  1243. Irp->MdlAddress, &dataSize, isConn);
  1244. if (status != TDI_PENDING) {
  1245. IrpSp->Control &= ~SL_PENDING_RETURNED;
  1246. status = TCPDataRequestComplete(Irp, status, dataSize);
  1247. return(status);
  1248. }
  1249. return(STATUS_PENDING);
  1250. }
  1251. return(status);
  1252. }
  1253. Irp->IoStatus.Status = (NTSTATUS) status;
  1254. Irp->IoStatus.Information = 0;
  1255. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  1256. return(status);
  1257. } // TCPQueryInformation
  1258. //* TCPQueryInformationExComplete - Complete a TdiQueryInformationEx request.
  1259. //
  1260. NTSTATUS
  1261. TCPQueryInformationExComplete(
  1262. void *Context, // A pointer to the IRP for this request.
  1263. unsigned int Status, // Final TDI status of the request.
  1264. unsigned int ByteCount) // Bytes returned in output buffer.
  1265. {
  1266. PTCP_QUERY_CONTEXT queryContext = (PTCP_QUERY_CONTEXT) Context;
  1267. ULONG bytesCopied;
  1268. if (NT_SUCCESS(Status)) {
  1269. //
  1270. // Copy the returned context to the input buffer.
  1271. //
  1272. TdiCopyBufferToMdl(&(queryContext->QueryInformation.Context), 0,
  1273. CONTEXT_SIZE, queryContext->InputMdl,
  1274. FIELD_OFFSET(TCP_REQUEST_QUERY_INFORMATION_EX,
  1275. Context),
  1276. &bytesCopied);
  1277. if (bytesCopied != CONTEXT_SIZE) {
  1278. Status = STATUS_INSUFFICIENT_RESOURCES;
  1279. ByteCount = 0;
  1280. }
  1281. }
  1282. //
  1283. // Unlock the user's buffers and free the MDLs describing them.
  1284. //
  1285. MmUnlockPages(queryContext->InputMdl);
  1286. IoFreeMdl(queryContext->InputMdl);
  1287. MmUnlockPages(queryContext->OutputMdl);
  1288. IoFreeMdl(queryContext->OutputMdl);
  1289. //
  1290. // Complete the request.
  1291. //
  1292. Status = TCPDataRequestComplete(queryContext->Irp, Status, ByteCount);
  1293. ExFreePool(queryContext);
  1294. return Status;
  1295. }
  1296. //* TCPQueryInformationEx - Handle a TDI QueryInformationEx IRP.
  1297. //
  1298. // Converts a TDI QueryInformationEx IRP into a call to TdiQueryInformationEx.
  1299. //
  1300. NTSTATUS // Returns: whether the request was successful.
  1301. TCPQueryInformationEx(
  1302. IN PIRP Irp, // I/O request packet.
  1303. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  1304. {
  1305. TDI_REQUEST request;
  1306. TDI_STATUS status = STATUS_SUCCESS;
  1307. PTCP_CONTEXT tcpContext;
  1308. uint size;
  1309. PTCP_REQUEST_QUERY_INFORMATION_EX InputBuffer;
  1310. PVOID OutputBuffer;
  1311. PMDL inputMdl = NULL;
  1312. PMDL outputMdl = NULL;
  1313. ULONG InputBufferLength, OutputBufferLength;
  1314. PTCP_QUERY_CONTEXT queryContext;
  1315. BOOLEAN inputLocked = FALSE;
  1316. BOOLEAN outputLocked = FALSE;
  1317. BOOLEAN inputBufferValid = FALSE;
  1318. PAGED_CODE();
  1319. IF_TCPDBG(TCP_DEBUG_INFO) {
  1320. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1321. "QueryInformationEx starting - irp %lx fileobj %lx\n",
  1322. Irp, IrpSp->FileObject));
  1323. }
  1324. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  1325. switch (PtrToUlong(IrpSp->FileObject->FsContext2)) {
  1326. case TDI_TRANSPORT_ADDRESS_FILE:
  1327. request.Handle.AddressHandle = tcpContext->Handle.AddressHandle;
  1328. break;
  1329. case TDI_CONNECTION_FILE:
  1330. request.Handle.ConnectionContext =
  1331. tcpContext->Handle.ConnectionContext;
  1332. break;
  1333. case TDI_CONTROL_CHANNEL_FILE:
  1334. request.Handle.ControlChannel = tcpContext->Handle.ControlChannel;
  1335. break;
  1336. default:
  1337. ASSERT(0);
  1338. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  1339. Irp->IoStatus.Information = 0;
  1340. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  1341. return(STATUS_INVALID_PARAMETER);
  1342. }
  1343. InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
  1344. OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  1345. //
  1346. // Validate the input parameters.
  1347. //
  1348. if (InputBufferLength >= sizeof(TCP_REQUEST_QUERY_INFORMATION_EX) &&
  1349. InputBufferLength < MAXLONG) {
  1350. inputBufferValid = TRUE;
  1351. } else {
  1352. inputBufferValid = FALSE;
  1353. }
  1354. if (inputBufferValid && (OutputBufferLength != 0)) {
  1355. OutputBuffer = Irp->UserBuffer;
  1356. InputBuffer = (PTCP_REQUEST_QUERY_INFORMATION_EX)
  1357. IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  1358. queryContext = ExAllocatePool(NonPagedPool, InputBufferLength
  1359. + FIELD_OFFSET(TCP_QUERY_CONTEXT, QueryInformation));
  1360. if (queryContext != NULL) {
  1361. status = TCPPrepareIrpForCancel(tcpContext, Irp, NULL);
  1362. if (!NT_SUCCESS(status)) {
  1363. ExFreePool(queryContext);
  1364. return(status);
  1365. }
  1366. //
  1367. // Allocate Mdls to describe the input and output buffers.
  1368. // Probe and lock the buffers.
  1369. //
  1370. try {
  1371. inputMdl = IoAllocateMdl(InputBuffer, InputBufferLength,
  1372. FALSE, TRUE, NULL);
  1373. outputMdl = IoAllocateMdl(OutputBuffer, OutputBufferLength,
  1374. FALSE, TRUE, NULL);
  1375. if ((inputMdl != NULL) && (outputMdl != NULL)) {
  1376. MmProbeAndLockPages(inputMdl, Irp->RequestorMode,
  1377. IoModifyAccess);
  1378. inputLocked = TRUE;
  1379. MmProbeAndLockPages(outputMdl, Irp->RequestorMode,
  1380. IoWriteAccess);
  1381. outputLocked = TRUE;
  1382. //
  1383. // Copy the input parameter to our pool block so
  1384. // TdiQueryInformationEx can manipulate it directly.
  1385. //
  1386. RtlCopyMemory(&(queryContext->QueryInformation),
  1387. InputBuffer,
  1388. InputBufferLength);
  1389. } else {
  1390. IF_TCPDBG(TCP_DEBUG_INFO) {
  1391. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1392. "QueryInfoEx: Couldn't allocate MDL\n"));
  1393. }
  1394. IrpSp->Control &= ~SL_PENDING_RETURNED;
  1395. status = STATUS_INSUFFICIENT_RESOURCES;
  1396. }
  1397. } except(EXCEPTION_EXECUTE_HANDLER) {
  1398. IF_TCPDBG(TCP_DEBUG_INFO) {
  1399. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1400. "QueryInfoEx: "
  1401. "exception copying input param %lx\n",
  1402. GetExceptionCode()));
  1403. }
  1404. status = GetExceptionCode();
  1405. }
  1406. if (NT_SUCCESS(status)) {
  1407. //
  1408. // It's finally time to do this thing.
  1409. //
  1410. size = TCPGetMdlChainByteCount(outputMdl);
  1411. queryContext->Irp = Irp;
  1412. queryContext->InputMdl = inputMdl;
  1413. queryContext->OutputMdl = outputMdl;
  1414. request.RequestNotifyObject = TCPQueryInformationExComplete;
  1415. request.RequestContext = queryContext;
  1416. status = TdiQueryInformationEx(&request,
  1417. &(queryContext->QueryInformation.ID),
  1418. outputMdl, &size,
  1419. &(queryContext->QueryInformation.Context),
  1420. InputBufferLength - FIELD_OFFSET(TCP_REQUEST_QUERY_INFORMATION_EX, Context));
  1421. if (status != TDI_PENDING) {
  1422. //
  1423. // Since status is not pending, clear the
  1424. // control flag to keep IO verifier happy.
  1425. //
  1426. IrpSp->Control &= ~SL_PENDING_RETURNED;
  1427. TCPQueryInformationExComplete(queryContext, status, size);
  1428. return(status);
  1429. }
  1430. IF_TCPDBG(TCP_DEBUG_INFO) {
  1431. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1432. "QueryInformationEx - "
  1433. "pending irp %lx fileobj %lx\n",
  1434. Irp, IrpSp->FileObject));
  1435. }
  1436. return(STATUS_PENDING);
  1437. }
  1438. //
  1439. // If we get here, something failed. Clean up.
  1440. //
  1441. if (inputMdl != NULL) {
  1442. if (inputLocked) {
  1443. MmUnlockPages(inputMdl);
  1444. }
  1445. IoFreeMdl(inputMdl);
  1446. }
  1447. if (outputMdl != NULL) {
  1448. if (outputLocked) {
  1449. MmUnlockPages(outputMdl);
  1450. }
  1451. IoFreeMdl(outputMdl);
  1452. }
  1453. ExFreePool(queryContext);
  1454. // Since status is not pending, clear the
  1455. // control flag to keep IO verifier happy.
  1456. IrpSp->Control &= ~SL_PENDING_RETURNED;
  1457. status = TCPDataRequestComplete(Irp, status, 0);
  1458. return(status);
  1459. } else {
  1460. IrpSp->Control &= ~SL_PENDING_RETURNED;
  1461. status = STATUS_INSUFFICIENT_RESOURCES;
  1462. IF_TCPDBG(TCP_DEBUG_INFO) {
  1463. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1464. "QueryInfoEx: Unable to allocate query context\n"));
  1465. }
  1466. }
  1467. } else {
  1468. status = STATUS_INVALID_PARAMETER;
  1469. IF_TCPDBG(TCP_DEBUG_INFO) {
  1470. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1471. "QueryInfoEx: Bad buffer len, OBufLen %d, InBufLen %d\n",
  1472. OutputBufferLength, InputBufferLength));
  1473. }
  1474. }
  1475. IF_TCPDBG(TCP_DEBUG_INFO) {
  1476. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1477. "QueryInformationEx complete - irp %lx, status %lx\n",
  1478. Irp, status));
  1479. }
  1480. Irp->IoStatus.Status = (NTSTATUS) status;
  1481. Irp->IoStatus.Information = 0;
  1482. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  1483. return(status);
  1484. }
  1485. //* TCPSetInformationEx - Handle TDI SetInformationEx IRP.
  1486. //
  1487. // Converts a TDI SetInformationEx IRP into a call to TdiSetInformationEx.
  1488. //
  1489. // This routine does not pend.
  1490. //
  1491. NTSTATUS // Returns: whether the request was successful.
  1492. TCPSetInformationEx(
  1493. IN PIRP Irp, // I/O request packet.
  1494. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  1495. {
  1496. TDI_REQUEST request;
  1497. TDI_STATUS status;
  1498. PTCP_CONTEXT tcpContext;
  1499. PTCP_REQUEST_SET_INFORMATION_EX setInformation;
  1500. PAGED_CODE();
  1501. IF_TCPDBG(TCP_DEBUG_INFO) {
  1502. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1503. "SetInformationEx - irp %lx fileobj %lx\n", Irp,
  1504. IrpSp->FileObject));
  1505. }
  1506. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  1507. setInformation = (PTCP_REQUEST_SET_INFORMATION_EX)
  1508. Irp->AssociatedIrp.SystemBuffer;
  1509. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  1510. FIELD_OFFSET(TCP_REQUEST_SET_INFORMATION_EX, Buffer) ||
  1511. IrpSp->Parameters.DeviceIoControl.InputBufferLength -
  1512. FIELD_OFFSET(TCP_REQUEST_SET_INFORMATION_EX, Buffer) < setInformation->BufferSize) {
  1513. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  1514. Irp->IoStatus.Information = 0;
  1515. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  1516. return (STATUS_INVALID_PARAMETER);
  1517. }
  1518. switch (PtrToUlong(IrpSp->FileObject->FsContext2)) {
  1519. case TDI_TRANSPORT_ADDRESS_FILE:
  1520. request.Handle.AddressHandle = tcpContext->Handle.AddressHandle;
  1521. break;
  1522. case TDI_CONNECTION_FILE:
  1523. request.Handle.ConnectionContext =
  1524. tcpContext->Handle.ConnectionContext;
  1525. break;
  1526. case TDI_CONTROL_CHANNEL_FILE:
  1527. request.Handle.ControlChannel = tcpContext->Handle.ControlChannel;
  1528. break;
  1529. default:
  1530. ASSERT(0);
  1531. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  1532. Irp->IoStatus.Information = 0;
  1533. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  1534. return(STATUS_INVALID_PARAMETER);
  1535. }
  1536. //
  1537. // Prevent non-privleged access (i.e. IOCTL_TCP_WSH_SET_INFORMATION_EX
  1538. // calls) from making changes outside of the transport layer.
  1539. // Privleged calls should be using IOCTL_TCP_SET_INFORMATION_EX instead.
  1540. //
  1541. if (IrpSp->Parameters.DeviceIoControl.IoControlCode ==
  1542. IOCTL_TCP_WSH_SET_INFORMATION_EX) {
  1543. uint Entity;
  1544. Entity = setInformation->ID.toi_entity.tei_entity;
  1545. if ((Entity != CO_TL_ENTITY) && (Entity != CL_TL_ENTITY) ) {
  1546. Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
  1547. Irp->IoStatus.Information = 0;
  1548. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  1549. return (STATUS_ACCESS_DENIED);
  1550. }
  1551. }
  1552. status = TCPPrepareIrpForCancel(tcpContext, Irp, NULL);
  1553. if (NT_SUCCESS(status)) {
  1554. request.RequestNotifyObject = TCPDataRequestComplete;
  1555. request.RequestContext = Irp;
  1556. status = TdiSetInformationEx(&request, &(setInformation->ID),
  1557. &(setInformation->Buffer[0]),
  1558. setInformation->BufferSize);
  1559. if (status != TDI_PENDING) {
  1560. IrpSp->Control &= ~SL_PENDING_RETURNED;
  1561. status = TCPDataRequestComplete(Irp, status, 0);
  1562. return(status);
  1563. }
  1564. IF_TCPDBG(TCP_DEBUG_INFO) {
  1565. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1566. "SetInformationEx - pending irp %lx fileobj %lx\n",
  1567. Irp, IrpSp->FileObject));
  1568. }
  1569. return(STATUS_PENDING);
  1570. }
  1571. IF_TCPDBG(TCP_DEBUG_INFO) {
  1572. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1573. "SetInformationEx complete - irp %lx\n", Irp));
  1574. }
  1575. //
  1576. // The irp has already been completed.
  1577. //
  1578. return(status);
  1579. }
  1580. #if 0
  1581. //* TCPEnumerateConnectionList -
  1582. //
  1583. // Processes a request to enumerate the workstation connection list.
  1584. //
  1585. // This routine does not pend.
  1586. //
  1587. NTSTATUS // Return: whether the request was successful.
  1588. TCPEnumerateConnectionList(
  1589. IN PIRP Irp, // I/O request packet.
  1590. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  1591. {
  1592. TCPConnectionListEntry *request;
  1593. TCPConnectionListEnum *response;
  1594. ULONG requestLength, responseLength;
  1595. NTSTATUS status;
  1596. PAGED_CODE();
  1597. request = (TCPConnectionListEntry *) Irp->AssociatedIrp.SystemBuffer;
  1598. response = (TCPConnectionListEnum *) request;
  1599. requestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
  1600. responseLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  1601. if (responseLength < sizeof(TCPConnectionListEnum)) {
  1602. status = STATUS_BUFFER_TOO_SMALL;
  1603. Irp->IoStatus.Information = 0;
  1604. } else {
  1605. EnumerateConnectionList((uchar *) (response + 1),
  1606. responseLength - sizeof(TCPConnectionListEnum),
  1607. &(response->tce_entries_returned),
  1608. &(response->tce_entries_available));
  1609. status = TDI_SUCCESS;
  1610. Irp->IoStatus.Information = sizeof(TCPConnectionListEnum) +
  1611. (response->tce_entries_returned * sizeof(TCPConnectionListEntry));
  1612. }
  1613. Irp->IoStatus.Status = status;
  1614. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  1615. return(status);
  1616. }
  1617. #endif
  1618. //* TCPCreate -
  1619. //
  1620. NTSTATUS // Returns: whether the request was successfully queued.
  1621. TCPCreate(
  1622. IN PDEVICE_OBJECT DeviceObject, // Device object for this request.
  1623. IN PIRP Irp, // I/O request packet.
  1624. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  1625. {
  1626. TDI_REQUEST Request;
  1627. NTSTATUS status;
  1628. FILE_FULL_EA_INFORMATION *ea;
  1629. FILE_FULL_EA_INFORMATION UNALIGNED *targetEA;
  1630. PTCP_CONTEXT tcpContext;
  1631. uint protocol;
  1632. PAGED_CODE();
  1633. tcpContext = ExAllocatePool(NonPagedPool, sizeof(TCP_CONTEXT));
  1634. if (tcpContext == NULL) {
  1635. return(STATUS_INSUFFICIENT_RESOURCES);
  1636. }
  1637. #if DBG
  1638. InitializeListHead(&(tcpContext->PendingIrpList));
  1639. InitializeListHead(&(tcpContext->CancelledIrpList));
  1640. #endif
  1641. tcpContext->ReferenceCount = 1; // Put initial reference on open object.
  1642. tcpContext->CancelIrps = FALSE;
  1643. KeInitializeEvent(&(tcpContext->CleanupEvent), SynchronizationEvent,
  1644. FALSE);
  1645. KeInitializeSpinLock(&tcpContext->EndpointLock);
  1646. ea = (PFILE_FULL_EA_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
  1647. //
  1648. // See if this is a Control Channel open.
  1649. //
  1650. if (!ea) {
  1651. IF_TCPDBG(TCP_DEBUG_OPEN) {
  1652. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1653. "TCPCreate: "
  1654. "Opening control channel for file object %lx\n",
  1655. IrpSp->FileObject));
  1656. }
  1657. tcpContext->Handle.ControlChannel = NULL;
  1658. IrpSp->FileObject->FsContext = tcpContext;
  1659. IrpSp->FileObject->FsContext2 = (PVOID) TDI_CONTROL_CHANNEL_FILE;
  1660. return(STATUS_SUCCESS);
  1661. }
  1662. //
  1663. // See if this is an Address Object open.
  1664. //
  1665. targetEA = FindEA(ea, TdiTransportAddress, TDI_TRANSPORT_ADDRESS_LENGTH);
  1666. if (targetEA != NULL) {
  1667. UCHAR optionsBuffer[3];
  1668. PUCHAR optionsPointer = optionsBuffer;
  1669. if (DeviceObject == TCPDeviceObject) {
  1670. protocol = IP_PROTOCOL_TCP;
  1671. }
  1672. else if (DeviceObject == UDPDeviceObject) {
  1673. protocol = IP_PROTOCOL_UDP;
  1674. ASSERT(optionsPointer - optionsBuffer <= 3);
  1675. if (IsDHCPZeroAddress((TRANSPORT_ADDRESS UNALIGNED *)
  1676. &(targetEA->EaName[targetEA->EaNameLength + 1]))) {
  1677. if (!IsAdminIoRequest(Irp, IrpSp)) {
  1678. ExFreePool(tcpContext);
  1679. return(STATUS_ACCESS_DENIED);
  1680. }
  1681. *optionsPointer = TDI_ADDRESS_OPTION_DHCP;
  1682. optionsPointer++;
  1683. }
  1684. ASSERT(optionsPointer - optionsBuffer <= 3);
  1685. } else {
  1686. //
  1687. // This is a raw ip open.
  1688. //
  1689. //
  1690. // Only administrators can create raw addresses
  1691. // unless this is allowed through registry.
  1692. //
  1693. if (!AllowUserRawAccess && !IsAdminIoRequest(Irp, IrpSp)) {
  1694. ExFreePool(tcpContext);
  1695. return(STATUS_ACCESS_DENIED);
  1696. }
  1697. protocol = RawExtractProtocolNumber(
  1698. &(IrpSp->FileObject->FileName));
  1699. //
  1700. // We need to protect the IPv6Send routine's packet rewriting
  1701. // code (for fragmentation, header inclusion, etc) from getting
  1702. // confused by malformed extension headers coming from user-land.
  1703. // So we disallow these types.
  1704. //
  1705. if ((protocol == 0xFFFFFFFF) ||
  1706. IsExtensionHeader((uchar)protocol)) {
  1707. ExFreePool(tcpContext);
  1708. return(STATUS_INVALID_PARAMETER);
  1709. }
  1710. *optionsPointer = TDI_ADDRESS_OPTION_RAW;
  1711. optionsPointer++;
  1712. }
  1713. if ((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
  1714. (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) {
  1715. *optionsPointer = TDI_ADDRESS_OPTION_REUSE;
  1716. optionsPointer++;
  1717. }
  1718. *optionsPointer = TDI_OPTION_EOL;
  1719. IF_TCPDBG(TCP_DEBUG_OPEN) {
  1720. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1721. "TCPCreate: Opening address for file object %lx\n",
  1722. IrpSp->FileObject));
  1723. }
  1724. status = TdiOpenAddress(&Request, (TRANSPORT_ADDRESS UNALIGNED *)
  1725. &(targetEA->EaName[targetEA->EaNameLength + 1]),
  1726. protocol, optionsBuffer);
  1727. if (NT_SUCCESS(status)) {
  1728. //
  1729. // Save off the handle to the AO passed back.
  1730. //
  1731. tcpContext->Handle.AddressHandle = Request.Handle.AddressHandle;
  1732. IrpSp->FileObject->FsContext = tcpContext;
  1733. IrpSp->FileObject->FsContext2 = (PVOID) TDI_TRANSPORT_ADDRESS_FILE;
  1734. } else {
  1735. ExFreePool(tcpContext);
  1736. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INTERNAL_ERROR,
  1737. "TdiOpenAddress failed, status %lx\n", status));
  1738. if (status == STATUS_ADDRESS_ALREADY_EXISTS) {
  1739. status = STATUS_SHARING_VIOLATION;
  1740. }
  1741. }
  1742. ASSERT(status != TDI_PENDING);
  1743. return(status);
  1744. }
  1745. //
  1746. // See if this is a Connection Object open.
  1747. //
  1748. targetEA = FindEA(ea, TdiConnectionContext, TDI_CONNECTION_CONTEXT_LENGTH);
  1749. if (targetEA != NULL) {
  1750. //
  1751. // This is an open of a Connection Object.
  1752. //
  1753. if (DeviceObject == TCPDeviceObject) {
  1754. IF_TCPDBG(TCP_DEBUG_OPEN) {
  1755. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1756. "TCPCreate: Opening connection for file object %lx\n",
  1757. IrpSp->FileObject));
  1758. }
  1759. if (targetEA->EaValueLength < sizeof(CONNECTION_CONTEXT)) {
  1760. status = STATUS_EA_LIST_INCONSISTENT;
  1761. } else {
  1762. status = TdiOpenConnection(&Request,
  1763. *((CONNECTION_CONTEXT UNALIGNED *)
  1764. &(targetEA->EaName[targetEA->EaNameLength + 1])));
  1765. }
  1766. if (NT_SUCCESS(status)) {
  1767. //
  1768. // Save off the Connection Context passed back.
  1769. //
  1770. tcpContext->Handle.ConnectionContext =
  1771. Request.Handle.ConnectionContext;
  1772. IrpSp->FileObject->FsContext = tcpContext;
  1773. IrpSp->FileObject->FsContext2 = (PVOID) TDI_CONNECTION_FILE;
  1774. } else {
  1775. ExFreePool(tcpContext);
  1776. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INTERNAL_ERROR,
  1777. "TdiOpenConnection failed, status %lx\n", status));
  1778. }
  1779. } else {
  1780. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_USER_ERROR,
  1781. "TCP: TdiOpenConnection issued on UDP device!\n"));
  1782. status = STATUS_INVALID_DEVICE_REQUEST;
  1783. ExFreePool(tcpContext);
  1784. }
  1785. ASSERT(status != TDI_PENDING);
  1786. return(status);
  1787. }
  1788. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_USER_ERROR,
  1789. "TCPCreate: didn't find any useful ea's\n"));
  1790. status = STATUS_INVALID_EA_NAME;
  1791. ExFreePool(tcpContext);
  1792. ASSERT(status != TDI_PENDING);
  1793. return(status);
  1794. } // TCPCreate
  1795. //* IsAdminIoRequest -
  1796. //
  1797. // (Lifted from AFD - AfdPerformSecurityCheck)
  1798. // Compares security context of the endpoint creator to that
  1799. // of the administrator and local system.
  1800. //
  1801. BOOLEAN // return TRUE if socket creator has admin or local system privilege
  1802. IsAdminIoRequest(
  1803. PIRP Irp, // Pointer to I/O request packet.
  1804. PIO_STACK_LOCATION IrpSp) // Pointer to the I/O stack location to use for this request.
  1805. {
  1806. BOOLEAN accessGranted;
  1807. PACCESS_STATE accessState;
  1808. PIO_SECURITY_CONTEXT securityContext;
  1809. PPRIVILEGE_SET privileges = NULL;
  1810. ACCESS_MASK grantedAccess;
  1811. PGENERIC_MAPPING GenericMapping;
  1812. ACCESS_MASK AccessMask = GENERIC_ALL;
  1813. NTSTATUS Status;
  1814. //
  1815. // Enable access to all the globally defined SIDs
  1816. //
  1817. GenericMapping = IoGetFileObjectGenericMapping();
  1818. RtlMapGenericMask(&AccessMask, GenericMapping);
  1819. securityContext = IrpSp->Parameters.Create.SecurityContext;
  1820. accessState = securityContext->AccessState;
  1821. SeLockSubjectContext(&accessState->SubjectSecurityContext);
  1822. accessGranted = SeAccessCheck(TcpAdminSecurityDescriptor,
  1823. &accessState->SubjectSecurityContext,
  1824. TRUE,
  1825. AccessMask,
  1826. 0,
  1827. &privileges,
  1828. IoGetFileObjectGenericMapping(),
  1829. (KPROCESSOR_MODE) ((IrpSp->Flags & SL_FORCE_ACCESS_CHECK)
  1830. ? UserMode
  1831. : Irp->RequestorMode),
  1832. &grantedAccess,
  1833. &Status);
  1834. if (privileges) {
  1835. (VOID) SeAppendPrivileges(accessState,
  1836. privileges);
  1837. SeFreePrivileges(privileges);
  1838. }
  1839. if (accessGranted) {
  1840. accessState->PreviouslyGrantedAccess |= grantedAccess;
  1841. accessState->RemainingDesiredAccess &= ~(grantedAccess | MAXIMUM_ALLOWED);
  1842. ASSERT(NT_SUCCESS(Status));
  1843. } else {
  1844. ASSERT(!NT_SUCCESS(Status));
  1845. }
  1846. SeUnlockSubjectContext(&accessState->SubjectSecurityContext);
  1847. return accessGranted;
  1848. } // IsAdminIoRequest
  1849. //* TCPCloseObjectComplete -
  1850. //
  1851. // Completes a TdiCloseConnectoin or TdiCloseAddress request.
  1852. //
  1853. void // Returns: Nothing.
  1854. TCPCloseObjectComplete(
  1855. void *Context, // Pointer to the IRP for this request.
  1856. unsigned int Status, // Final status of the operation.
  1857. unsigned int UnUsed) // Unused parameter.
  1858. {
  1859. KIRQL oldIrql;
  1860. PIRP irp;
  1861. PIO_STACK_LOCATION irpSp;
  1862. PTCP_CONTEXT tcpContext;
  1863. UNREFERENCED_PARAMETER(UnUsed);
  1864. irp = (PIRP) Context;
  1865. irpSp = IoGetCurrentIrpStackLocation(irp);
  1866. tcpContext = (PTCP_CONTEXT) irpSp->FileObject->FsContext;
  1867. irp->IoStatus.Status = Status;
  1868. IF_TCPDBG(TCP_DEBUG_CLEANUP) {
  1869. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1870. "TCPCloseObjectComplete on file object %lx\n",
  1871. irpSp->FileObject));
  1872. }
  1873. KeAcquireSpinLock(&tcpContext->EndpointLock, &oldIrql);
  1874. ASSERT(tcpContext->ReferenceCount > 0);
  1875. ASSERT(tcpContext->CancelIrps);
  1876. //
  1877. // Remove the initial reference that was put on by TCPCreate.
  1878. //
  1879. ASSERT(tcpContext->ReferenceCount > 0);
  1880. IF_TCPDBG(TCP_DEBUG_IRP) {
  1881. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1882. "TCPCloseObjectComplete: "
  1883. "irp %lx fileobj %lx refcnt dec to %u\n",
  1884. irp, irpSp, tcpContext->ReferenceCount - 1));
  1885. }
  1886. if (--(tcpContext->ReferenceCount) == 0) {
  1887. IF_TCPDBG(TCP_DEBUG_CANCEL) {
  1888. ASSERT(IsListEmpty(&(tcpContext->CancelledIrpList)));
  1889. ASSERT(IsListEmpty(&(tcpContext->PendingIrpList)));
  1890. }
  1891. KeReleaseSpinLock(&tcpContext->EndpointLock, oldIrql);
  1892. KeSetEvent(&(tcpContext->CleanupEvent), 0, FALSE);
  1893. return;
  1894. }
  1895. KeReleaseSpinLock(&tcpContext->EndpointLock, oldIrql);
  1896. return;
  1897. } // TCPCloseObjectComplete
  1898. //* TCPCleanup -
  1899. //
  1900. // Cancels all outstanding Irps on a TDI object by calling the close
  1901. // routine for the object. It then waits for them to be completed
  1902. // before returning.
  1903. //
  1904. // This routine blocks, but does not pend.
  1905. //
  1906. NTSTATUS // Returns: whether the request was successfully queued.
  1907. TCPCleanup(
  1908. IN PDEVICE_OBJECT DeviceObject, // Device object for this request.
  1909. IN PIRP Irp, // I/O request packet.
  1910. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  1911. {
  1912. KIRQL oldIrql;
  1913. PIRP cancelIrp = NULL;
  1914. PTCP_CONTEXT tcpContext;
  1915. NTSTATUS status;
  1916. TDI_REQUEST request;
  1917. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  1918. KeAcquireSpinLock(&tcpContext->EndpointLock, &oldIrql);
  1919. tcpContext->CancelIrps = TRUE;
  1920. KeResetEvent(&(tcpContext->CleanupEvent));
  1921. KeReleaseSpinLock(&tcpContext->EndpointLock, oldIrql);
  1922. //
  1923. // Now call the TDI close routine for this object to force all of its Irps
  1924. // to complete.
  1925. //
  1926. request.RequestNotifyObject = TCPCloseObjectComplete;
  1927. request.RequestContext = Irp;
  1928. switch (PtrToUlong(IrpSp->FileObject->FsContext2)) {
  1929. case TDI_TRANSPORT_ADDRESS_FILE:
  1930. IF_TCPDBG(TCP_DEBUG_CLOSE) {
  1931. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1932. "TCPCleanup: Closing address object on file object %lx\n",
  1933. IrpSp->FileObject));
  1934. }
  1935. request.Handle.AddressHandle = tcpContext->Handle.AddressHandle;
  1936. status = TdiCloseAddress(&request);
  1937. break;
  1938. case TDI_CONNECTION_FILE:
  1939. IF_TCPDBG(TCP_DEBUG_CLOSE) {
  1940. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1941. "TCPCleanup: "
  1942. "Closing Connection object on file object %lx\n",
  1943. IrpSp->FileObject));
  1944. }
  1945. request.Handle.ConnectionContext =
  1946. tcpContext->Handle.ConnectionContext;
  1947. status = TdiCloseConnection(&request);
  1948. break;
  1949. case TDI_CONTROL_CHANNEL_FILE:
  1950. IF_TCPDBG(TCP_DEBUG_CLOSE) {
  1951. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1952. "TCPCleanup: Closing Control Channel object on"
  1953. " file object %lx\n", IrpSp->FileObject));
  1954. }
  1955. status = STATUS_SUCCESS;
  1956. break;
  1957. default:
  1958. //
  1959. // This should never happen.
  1960. //
  1961. ASSERT(FALSE);
  1962. KeAcquireSpinLock(&tcpContext->EndpointLock, &oldIrql);
  1963. tcpContext->CancelIrps = FALSE;
  1964. KeReleaseSpinLock(&tcpContext->EndpointLock, oldIrql);
  1965. return(STATUS_INVALID_PARAMETER);
  1966. }
  1967. if (status != TDI_PENDING) {
  1968. TCPCloseObjectComplete(Irp, status, 0);
  1969. }
  1970. IF_TCPDBG(TCP_DEBUG_CLEANUP) {
  1971. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1972. "TCPCleanup: waiting for completion of Irps on"
  1973. " file object %lx\n", IrpSp->FileObject));
  1974. }
  1975. status = KeWaitForSingleObject(&(tcpContext->CleanupEvent), UserRequest,
  1976. KernelMode, FALSE, NULL);
  1977. ASSERT(NT_SUCCESS(status));
  1978. IF_TCPDBG(TCP_DEBUG_CLEANUP) {
  1979. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1980. "TCPCleanup: Wait on file object %lx finished\n",
  1981. IrpSp->FileObject));
  1982. }
  1983. //
  1984. // The cleanup Irp will be completed by the dispatch routine.
  1985. //
  1986. return(Irp->IoStatus.Status);
  1987. } // TCPCleanup
  1988. //* TCPClose -
  1989. //
  1990. // Dispatch routine for MJ_CLOSE IRPs. Performs final cleanup of the
  1991. // open endpoint.
  1992. //
  1993. // This request does not pend.
  1994. //
  1995. NTSTATUS // Returns: whether the request was successfully queued.
  1996. TCPClose(
  1997. IN PIRP Irp, // I/O request packet.
  1998. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  1999. {
  2000. PTCP_CONTEXT tcpContext;
  2001. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  2002. #if DBG
  2003. IF_TCPDBG(TCP_DEBUG_CANCEL) {
  2004. KIRQL oldIrql;
  2005. IoAcquireCancelSpinLock(&oldIrql);
  2006. ASSERT(tcpContext->ReferenceCount == 0);
  2007. ASSERT(IsListEmpty(&(tcpContext->PendingIrpList)));
  2008. ASSERT(IsListEmpty(&(tcpContext->CancelledIrpList)));
  2009. IoReleaseCancelSpinLock(oldIrql);
  2010. }
  2011. #endif // DBG
  2012. IF_TCPDBG(TCP_DEBUG_CLOSE) {
  2013. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  2014. "TCPClose on file object %lx\n", IrpSp->FileObject));
  2015. }
  2016. ExFreePool(tcpContext);
  2017. return(STATUS_SUCCESS);
  2018. } // TCPClose
  2019. //* TCPDispatchDeviceControl -
  2020. //
  2021. NTSTATUS // Returns: whether the request was successfully queued.
  2022. TCPDispatchDeviceControl(
  2023. IN PIRP Irp, // I/O request packet.
  2024. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  2025. {
  2026. NTSTATUS status;
  2027. PAGED_CODE();
  2028. //
  2029. // Set this in advance. Any IOCTL dispatch routine that cares about it
  2030. // will modify it itself.
  2031. //
  2032. Irp->IoStatus.Information = 0;
  2033. switch(IrpSp->Parameters.DeviceIoControl.IoControlCode) {
  2034. case IOCTL_TCP_QUERY_INFORMATION_EX:
  2035. return(TCPQueryInformationEx(Irp, IrpSp));
  2036. break;
  2037. case IOCTL_TCP_SET_INFORMATION_EX:
  2038. case IOCTL_TCP_WSH_SET_INFORMATION_EX:
  2039. return(TCPSetInformationEx(Irp, IrpSp));
  2040. break;
  2041. default:
  2042. status = STATUS_NOT_IMPLEMENTED;
  2043. break;
  2044. }
  2045. Irp->IoStatus.Status = status;
  2046. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  2047. return status;
  2048. } // TCPDispatchDeviceControl
  2049. //* TCPDispatchInternalDeviceControl -
  2050. //
  2051. // This is the dispatch routine for Internal Device Control IRPs.
  2052. // This is the hot path for kernel-mode clients.
  2053. //
  2054. NTSTATUS // Returns: whether the request was successfully queued.
  2055. TCPDispatchInternalDeviceControl(
  2056. IN PDEVICE_OBJECT DeviceObject, // Device object for target device.
  2057. IN PIRP Irp) // I/O request packet.
  2058. {
  2059. PIO_STACK_LOCATION irpSp;
  2060. NTSTATUS status;
  2061. if (DeviceObject != IPDeviceObject) {
  2062. irpSp = IoGetCurrentIrpStackLocation(Irp);
  2063. if (PtrToUlong(irpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE) {
  2064. //
  2065. // Send and receive are the performance path, so check for them
  2066. // right away.
  2067. //
  2068. if (irpSp->MinorFunction == TDI_SEND) {
  2069. return(TCPSendData(Irp, irpSp));
  2070. }
  2071. if (irpSp->MinorFunction == TDI_RECEIVE) {
  2072. return(TCPReceiveData(Irp, irpSp));
  2073. }
  2074. switch(irpSp->MinorFunction) {
  2075. case TDI_ASSOCIATE_ADDRESS:
  2076. status = TCPAssociateAddress(Irp, irpSp);
  2077. Irp->IoStatus.Status = status;
  2078. Irp->IoStatus.Information = 0;
  2079. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  2080. return(status);
  2081. case TDI_DISASSOCIATE_ADDRESS:
  2082. return(TCPDisassociateAddress(Irp, irpSp));
  2083. case TDI_CONNECT:
  2084. return(TCPConnect(Irp, irpSp));
  2085. case TDI_DISCONNECT:
  2086. return(TCPDisconnect(Irp, irpSp));
  2087. case TDI_LISTEN:
  2088. return(TCPListen(Irp, irpSp));
  2089. case TDI_ACCEPT:
  2090. return(TCPAccept(Irp, irpSp));
  2091. default:
  2092. break;
  2093. }
  2094. //
  2095. // Fall through.
  2096. //
  2097. }
  2098. else if (PtrToUlong(irpSp->FileObject->FsContext2) ==
  2099. TDI_TRANSPORT_ADDRESS_FILE) {
  2100. if (irpSp->MinorFunction == TDI_SEND_DATAGRAM) {
  2101. return(UDPSendDatagram(Irp, irpSp));
  2102. }
  2103. if (irpSp->MinorFunction == TDI_RECEIVE_DATAGRAM) {
  2104. return(UDPReceiveDatagram(Irp, irpSp));
  2105. }
  2106. if (irpSp->MinorFunction == TDI_SET_EVENT_HANDLER) {
  2107. status = TCPSetEventHandler(Irp, irpSp);
  2108. Irp->IoStatus.Status = status;
  2109. Irp->IoStatus.Information = 0;
  2110. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  2111. return(status);
  2112. }
  2113. //
  2114. // Fall through.
  2115. //
  2116. }
  2117. ASSERT(
  2118. (PtrToUlong(irpSp->FileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE)
  2119. ||
  2120. (PtrToUlong(irpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE)
  2121. ||
  2122. (PtrToUlong(irpSp->FileObject->FsContext2) == TDI_CONTROL_CHANNEL_FILE));
  2123. //
  2124. // These functions are common to all endpoint types.
  2125. //
  2126. switch(irpSp->MinorFunction) {
  2127. case TDI_QUERY_INFORMATION:
  2128. return(TCPQueryInformation(Irp, irpSp));
  2129. case TDI_SET_INFORMATION:
  2130. case TDI_ACTION:
  2131. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_USER_ERROR,
  2132. "TCP: Call to unimplemented TDI function 0x%p\n",
  2133. irpSp->MinorFunction));
  2134. status = STATUS_NOT_IMPLEMENTED;
  2135. break;
  2136. default:
  2137. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_USER_ERROR,
  2138. "TCP: call to invalid TDI function 0x%p\n",
  2139. irpSp->MinorFunction));
  2140. status = STATUS_INVALID_DEVICE_REQUEST;
  2141. }
  2142. ASSERT(status != TDI_PENDING);
  2143. Irp->IoStatus.Status = status;
  2144. Irp->IoStatus.Information = 0;
  2145. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  2146. return status;
  2147. }
  2148. return(IPDispatch(DeviceObject, Irp));
  2149. }
  2150. //* TCPDispatch -
  2151. //
  2152. // This is the generic dispatch routine for TCP/UDP/RawIP.
  2153. //
  2154. NTSTATUS // Returns: whether the request was successfully queued.
  2155. TCPDispatch(
  2156. IN PDEVICE_OBJECT DeviceObject, // Device object for target device.
  2157. IN PIRP Irp) // I/O request packet.
  2158. {
  2159. PIO_STACK_LOCATION irpSp;
  2160. NTSTATUS status;
  2161. if (DeviceObject != IPDeviceObject) {
  2162. irpSp = IoGetCurrentIrpStackLocation(Irp);
  2163. ASSERT(irpSp->MajorFunction != IRP_MJ_INTERNAL_DEVICE_CONTROL);
  2164. switch (irpSp->MajorFunction) {
  2165. case IRP_MJ_CREATE:
  2166. status = TCPCreate(DeviceObject, Irp, irpSp);
  2167. break;
  2168. case IRP_MJ_CLEANUP:
  2169. status = TCPCleanup(DeviceObject, Irp, irpSp);
  2170. break;
  2171. case IRP_MJ_CLOSE:
  2172. status = TCPClose(Irp, irpSp);
  2173. break;
  2174. case IRP_MJ_DEVICE_CONTROL:
  2175. status = TdiMapUserRequest(DeviceObject, Irp, irpSp);
  2176. if (status == STATUS_SUCCESS) {
  2177. return(TCPDispatchInternalDeviceControl(DeviceObject, Irp));
  2178. }
  2179. if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
  2180. IOCTL_TDI_QUERY_DIRECT_SEND_HANDLER) {
  2181. if (Irp->RequestorMode == KernelMode) {
  2182. *(PULONG_PTR)irpSp->Parameters.DeviceIoControl.Type3InputBuffer = (ULONG_PTR)TCPSendData;
  2183. status = STATUS_SUCCESS;
  2184. } else {
  2185. status = STATUS_ACCESS_DENIED;
  2186. }
  2187. break;
  2188. }
  2189. return(TCPDispatchDeviceControl(Irp,
  2190. IoGetCurrentIrpStackLocation(Irp)));
  2191. break;
  2192. case IRP_MJ_QUERY_SECURITY:
  2193. //
  2194. // This is generated on Raw endpoints. We don't do anything
  2195. // for it.
  2196. //
  2197. status = STATUS_INVALID_DEVICE_REQUEST;
  2198. break;
  2199. case IRP_MJ_WRITE:
  2200. case IRP_MJ_READ:
  2201. default:
  2202. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_USER_ERROR,
  2203. "TCPDispatch: Irp %lx unsupported major function 0x%lx\n",
  2204. irpSp, irpSp->MajorFunction));
  2205. status = STATUS_INVALID_DEVICE_REQUEST;
  2206. break;
  2207. }
  2208. ASSERT(status != TDI_PENDING);
  2209. Irp->IoStatus.Status = status;
  2210. Irp->IoStatus.Information = 0;
  2211. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  2212. return status;
  2213. }
  2214. return(IPDispatch(DeviceObject, Irp));
  2215. } // TCPDispatch
  2216. //
  2217. // Private utility functions
  2218. //
  2219. //* FindEA -
  2220. //
  2221. // Parses and extended attribute list for a given target attribute.
  2222. //
  2223. FILE_FULL_EA_INFORMATION UNALIGNED * // Returns: requested attribute or NULL.
  2224. FindEA(
  2225. PFILE_FULL_EA_INFORMATION StartEA, // First extended attribute in list.
  2226. CHAR *TargetName, // Name of target attribute.
  2227. USHORT TargetNameLength) // Length of above.
  2228. {
  2229. USHORT i;
  2230. BOOLEAN found;
  2231. FILE_FULL_EA_INFORMATION UNALIGNED *CurrentEA;
  2232. PAGED_CODE();
  2233. do {
  2234. found = TRUE;
  2235. CurrentEA = StartEA;
  2236. StartEA += CurrentEA->NextEntryOffset;
  2237. if (CurrentEA->EaNameLength != TargetNameLength) {
  2238. continue;
  2239. }
  2240. for (i=0; i < CurrentEA->EaNameLength; i++) {
  2241. if (CurrentEA->EaName[i] == TargetName[i]) {
  2242. continue;
  2243. }
  2244. found = FALSE;
  2245. break;
  2246. }
  2247. if (found) {
  2248. return(CurrentEA);
  2249. }
  2250. } while(CurrentEA->NextEntryOffset != 0);
  2251. return(NULL);
  2252. }
  2253. //* IsDHCPZeroAddress -
  2254. //
  2255. // Checks a TDI IP address list for an address from DHCP binding
  2256. // to the IP address zero. Normally, binding to zero means wildcard.
  2257. // For DHCP, it really means bind to an interface with an address of
  2258. // zero. This semantic is flagged by a special value in an unused
  2259. // portion of the address structure (ie. this is a kludge).
  2260. //
  2261. BOOLEAN // Returns: TRUE iff first IP address found had the flag set.
  2262. IsDHCPZeroAddress(
  2263. TRANSPORT_ADDRESS UNALIGNED *AddrList) // TDI transport address list
  2264. // passed in the create IRP.
  2265. {
  2266. int i; // Index variable.
  2267. TA_ADDRESS *CurrentAddr; // Address we're examining and may use.
  2268. // First, verify that someplace in Address is an address we can use.
  2269. CurrentAddr = (TA_ADDRESS *)AddrList->Address;
  2270. for (i = 0; i < AddrList->TAAddressCount; i++) {
  2271. if (CurrentAddr->AddressType == TDI_ADDRESS_TYPE_IP) {
  2272. if (CurrentAddr->AddressLength == TDI_ADDRESS_LENGTH_IP) {
  2273. TDI_ADDRESS_IP UNALIGNED *ValidAddr;
  2274. ValidAddr = (TDI_ADDRESS_IP UNALIGNED *)CurrentAddr->Address;
  2275. if (*((ULONG UNALIGNED *) ValidAddr->sin_zero) == 0x12345678) {
  2276. return TRUE;
  2277. }
  2278. } else {
  2279. return FALSE; // Wrong length for address.
  2280. }
  2281. } else {
  2282. CurrentAddr = (TA_ADDRESS *)
  2283. (CurrentAddr->Address + CurrentAddr->AddressLength);
  2284. }
  2285. }
  2286. return FALSE; // Didn't find a match.
  2287. }
  2288. //* TCPGetMdlChainByteCount -
  2289. //
  2290. // Sums the byte counts of each MDL in a chain.
  2291. //
  2292. ULONG // Returns: byte count of the MDL chain.
  2293. TCPGetMdlChainByteCount(
  2294. PMDL Mdl) // MDL chain to sum.
  2295. {
  2296. ULONG count = 0;
  2297. while (Mdl != NULL) {
  2298. count += MmGetMdlByteCount(Mdl);
  2299. Mdl = Mdl->Next;
  2300. }
  2301. return(count);
  2302. }
  2303. //* RawExtractProtocolNumber -
  2304. //
  2305. // Extracts the protocol number from the file object name.
  2306. //
  2307. ULONG // Returns: the protocol number or 0xFFFFFFFF on error.
  2308. RawExtractProtocolNumber(
  2309. IN PUNICODE_STRING FileName) // File name (Unicode).
  2310. {
  2311. PWSTR name;
  2312. UNICODE_STRING unicodeString;
  2313. USHORT length;
  2314. ULONG protocol;
  2315. NTSTATUS status;
  2316. PAGED_CODE();
  2317. name = FileName->Buffer;
  2318. if (FileName->Length < (sizeof(OBJ_NAME_PATH_SEPARATOR) + sizeof(WCHAR))) {
  2319. return(0xFFFFFFFF);
  2320. }
  2321. //
  2322. // Step over separator.
  2323. //
  2324. if (*name++ != OBJ_NAME_PATH_SEPARATOR) {
  2325. return(0xFFFFFFFF);
  2326. }
  2327. if (*name == UNICODE_NULL) {
  2328. return(0xFFFFFFFF);
  2329. }
  2330. //
  2331. // Convert the remaining name into a number.
  2332. //
  2333. RtlInitUnicodeString(&unicodeString, name);
  2334. status = RtlUnicodeStringToInteger(&unicodeString, 10, &protocol);
  2335. if (!NT_SUCCESS(status)) {
  2336. return(0xFFFFFFFF);
  2337. }
  2338. if (protocol > 255) {
  2339. return(0xFFFFFFFF);
  2340. }
  2341. return(protocol);
  2342. }