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.

5177 lines
141 KiB

  1. /*++
  2. Copyright (c) 1991-2000 Microsoft Corporation
  3. Module Name:
  4. ntdisp.c
  5. Abstract:
  6. NT specific routines for dispatching and handling IRPs.
  7. Author:
  8. Mike Massa (mikemas) Aug 13, 1993
  9. Revision History:
  10. Who When What
  11. -------- -------- ----------------------------------------------
  12. mikemas 08-13-93 created
  13. Notes:
  14. --*/
  15. #include "precomp.h"
  16. #include "addr.h"
  17. #include "tcp.h"
  18. #include "udp.h"
  19. #include "raw.h"
  20. #include "info.h"
  21. #include <tcpinfo.h>
  22. #include "tcpcfg.h"
  23. #include "secfltr.h"
  24. #include "tcpconn.h"
  25. #include "mdl2ndis.h"
  26. //
  27. // Macros
  28. //
  29. //++
  30. //
  31. // LARGE_INTEGER
  32. // CTEConvert100nsToMilliseconds(
  33. // IN LARGE_INTEGER HnsTime
  34. // );
  35. //
  36. // Routine Description:
  37. //
  38. // Converts time expressed in hundreds of nanoseconds to milliseconds.
  39. //
  40. // Arguments:
  41. //
  42. // HnsTime - Time in hundreds of nanoseconds.
  43. //
  44. // Return Value:
  45. //
  46. // Time in milliseconds.
  47. //
  48. //--
  49. #define SHIFT10000 13
  50. static LARGE_INTEGER Magic10000 =
  51. {0xe219652c, 0xd1b71758};
  52. #define CTEConvert100nsToMilliseconds(HnsTime) \
  53. RtlExtendedMagicDivide((HnsTime), Magic10000, SHIFT10000)
  54. #if ACC
  55. GENERIC_MAPPING AddressGenericMapping =
  56. {READ_CONTROL, READ_CONTROL, READ_CONTROL, READ_CONTROL};
  57. extern PSECURITY_DESCRIPTOR TcpAdminSecurityDescriptor;
  58. uint AllowUserRawAccess;
  59. #endif
  60. //
  61. // Global variables
  62. //
  63. extern PDEVICE_OBJECT TCPDeviceObject, UDPDeviceObject;
  64. extern PDEVICE_OBJECT IPDeviceObject;
  65. #if IPMCAST
  66. extern PDEVICE_OBJECT IpMcastDeviceObject;
  67. #endif
  68. extern PDEVICE_OBJECT RawIPDeviceObject;
  69. AddrObj *FindAddrObjWithPort(ushort Port);
  70. ReservedPortListEntry *BlockedPortList = NULL;
  71. extern uint LogPerPartitionSize;
  72. extern CTELock *pTWTCBTableLock;
  73. #define GET_PARTITION(i) (i >> (ulong) LogPerPartitionSize)
  74. extern ReservedPortListEntry *PortRangeList;
  75. extern uint TcpHostOpts;
  76. extern TCPInternalStats TStats;
  77. CACHE_LINE_ULONG CancelId = { 1 };
  78. //
  79. // Local types
  80. //
  81. typedef struct {
  82. PIRP Irp;
  83. PMDL InputMdl;
  84. PMDL OutputMdl;
  85. TCP_REQUEST_QUERY_INFORMATION_EX QueryInformation;
  86. } TCP_QUERY_CONTEXT, *PTCP_QUERY_CONTEXT;
  87. extern POBJECT_TYPE *IoFileObjectType;
  88. #if TRACE_EVENT
  89. //
  90. // CP Handler routine set/unset by WMI through IRP_MN_SET_TRACE_NOTIFY
  91. //
  92. PTDI_DATA_REQUEST_NOTIFY_ROUTINE TCPCPHandlerRoutine;
  93. #endif
  94. PIRP CanceledIrp = NULL;
  95. //
  96. // General external function prototypes
  97. //
  98. extern
  99. NTSTATUS
  100. IPDispatch(
  101. IN PDEVICE_OBJECT DeviceObject,
  102. IN PIRP Irp
  103. );
  104. #if IPMCAST
  105. NTSTATUS
  106. IpMcastDispatch(
  107. IN PDEVICE_OBJECT DeviceObject,
  108. IN PIRP Irp
  109. );
  110. #endif
  111. //
  112. // External TDI function prototypes
  113. //
  114. extern TDI_STATUS
  115. TdiOpenAddress(
  116. PTDI_REQUEST Request,
  117. TRANSPORT_ADDRESS UNALIGNED * AddrList,
  118. uint protocol,
  119. void *Reuse
  120. );
  121. extern TDI_STATUS
  122. TdiCloseAddress(
  123. PTDI_REQUEST Request
  124. );
  125. extern TDI_STATUS
  126. TdiOpenConnection(
  127. PTDI_REQUEST Request,
  128. PVOID Context
  129. );
  130. extern TDI_STATUS
  131. TdiCloseConnection(
  132. PTDI_REQUEST Request
  133. );
  134. extern TDI_STATUS
  135. TdiAssociateAddress(
  136. PTDI_REQUEST Request,
  137. HANDLE AddrHandle
  138. );
  139. extern TDI_STATUS
  140. TdiCancelDisAssociateAddress(
  141. PTDI_REQUEST Request
  142. );
  143. extern TDI_STATUS
  144. TdiDisAssociateAddress(
  145. PTDI_REQUEST Request
  146. );
  147. extern TDI_STATUS
  148. TdiConnect(
  149. PTDI_REQUEST Request,
  150. void *Timeout,
  151. PTDI_CONNECTION_INFORMATION RequestAddr,
  152. PTDI_CONNECTION_INFORMATION ReturnAddr
  153. );
  154. extern TDI_STATUS
  155. UDPConnect(
  156. PTDI_REQUEST Request,
  157. void *Timeout,
  158. PTDI_CONNECTION_INFORMATION RequestAddr,
  159. PTDI_CONNECTION_INFORMATION ReturnAddr
  160. );
  161. extern TDI_STATUS
  162. UDPDisconnect(
  163. PTDI_REQUEST Request,
  164. void *TO,
  165. PTDI_CONNECTION_INFORMATION DiscConnInfo,
  166. PTDI_CONNECTION_INFORMATION ReturnInfo
  167. );
  168. extern TDI_STATUS
  169. TdiListen(
  170. PTDI_REQUEST Request,
  171. ushort Flags,
  172. PTDI_CONNECTION_INFORMATION AcceptableAddr,
  173. PTDI_CONNECTION_INFORMATION ConnectedAddr
  174. );
  175. extern TDI_STATUS
  176. TdiAccept(
  177. PTDI_REQUEST Request,
  178. PTDI_CONNECTION_INFORMATION AcceptInfo,
  179. PTDI_CONNECTION_INFORMATION ConnectedInfo
  180. );
  181. extern TDI_STATUS
  182. TdiDisconnect(
  183. PTDI_REQUEST Request,
  184. void *TO,
  185. ushort Flags,
  186. PTDI_CONNECTION_INFORMATION DiscConnInfo,
  187. PTDI_CONNECTION_INFORMATION ReturnInfo
  188. );
  189. extern TDI_STATUS
  190. TdiSend(
  191. PTDI_REQUEST Request,
  192. ushort Flags,
  193. uint SendLength,
  194. PNDIS_BUFFER SendBuffer
  195. );
  196. extern TDI_STATUS
  197. TdiReceive(
  198. PTDI_REQUEST Request,
  199. ushort * Flags,
  200. uint * RcvLength,
  201. PNDIS_BUFFER Buffer
  202. );
  203. extern TDI_STATUS
  204. TdiSendDatagram(
  205. PTDI_REQUEST Request,
  206. PTDI_CONNECTION_INFORMATION ConnInfo,
  207. uint DataSize,
  208. uint * BytesSent,
  209. PNDIS_BUFFER Buffer
  210. );
  211. VOID
  212. TdiCancelSendDatagram(
  213. AddrObj * SrcAO,
  214. PVOID Context,
  215. KIRQL inHandle
  216. );
  217. extern TDI_STATUS
  218. TdiReceiveDatagram(
  219. PTDI_REQUEST Request,
  220. PTDI_CONNECTION_INFORMATION ConnInfo,
  221. PTDI_CONNECTION_INFORMATION ReturnInfo,
  222. uint RcvSize,
  223. uint * BytesRcvd,
  224. PNDIS_BUFFER Buffer
  225. );
  226. VOID
  227. TdiCancelReceiveDatagram(
  228. AddrObj * SrcAO,
  229. PVOID Context,
  230. KIRQL inHandle
  231. );
  232. extern TDI_STATUS
  233. TdiSetEvent(
  234. PVOID Handle,
  235. int Type,
  236. PVOID Handler,
  237. PVOID Context
  238. );
  239. extern TDI_STATUS
  240. TdiQueryInformation(
  241. PTDI_REQUEST Request,
  242. uint QueryType,
  243. PNDIS_BUFFER Buffer,
  244. uint * BytesReturned,
  245. uint IsConn
  246. );
  247. extern TDI_STATUS
  248. TdiSetInformation(
  249. PTDI_REQUEST Request,
  250. uint SetType,
  251. PNDIS_BUFFER Buffer,
  252. uint BufferSize,
  253. uint IsConn
  254. );
  255. extern TDI_STATUS
  256. TdiQueryInformationEx(
  257. PTDI_REQUEST Request,
  258. struct TDIObjectID *ID,
  259. PNDIS_BUFFER Buffer,
  260. uint * Size,
  261. void *Context
  262. );
  263. extern TDI_STATUS
  264. TdiSetInformationEx(
  265. PTDI_REQUEST Request,
  266. struct TDIObjectID *ID,
  267. void *Buffer,
  268. uint Size
  269. );
  270. extern TDI_STATUS
  271. TdiAction(
  272. PTDI_REQUEST Request,
  273. uint ActionType,
  274. PNDIS_BUFFER Buffer,
  275. uint BufferSize
  276. );
  277. extern
  278. NTSTATUS
  279. TCPDispatchPnPPower(
  280. IN PIRP Irp,
  281. IN PIO_STACK_LOCATION IrpSp
  282. );
  283. extern
  284. uint
  285. GetTCBInfo(
  286. PTCP_FINDTCB_RESPONSE TCBInfo,
  287. IPAddr Dest,
  288. IPAddr Src,
  289. ushort DestPort,
  290. ushort SrcPort
  291. );
  292. //
  293. // Other external functions
  294. //
  295. BOOLEAN
  296. TCPAbortAndIndicateDisconnect(
  297. uint ConnnectionContext, PVOID reqcontext, uint receive, KIRQL Handle
  298. );
  299. //
  300. // Local pageable function prototypes
  301. //
  302. NTSTATUS
  303. TCPDispatchDeviceControl(
  304. IN PIRP Irp,
  305. IN PIO_STACK_LOCATION IrpSp
  306. );
  307. NTSTATUS
  308. TCPCreate(
  309. IN PDEVICE_OBJECT DeviceObject,
  310. IN PIRP Irp,
  311. IN PIO_STACK_LOCATION IrpSp
  312. );
  313. NTSTATUS
  314. TCPAssociateAddress(
  315. IN PIRP Irp,
  316. IN PIO_STACK_LOCATION IrpSp
  317. );
  318. NTSTATUS
  319. TCPSetEventHandler(
  320. IN PIRP Irp,
  321. IN PIO_STACK_LOCATION IrpSp
  322. );
  323. NTSTATUS
  324. TCPQueryInformation(
  325. IN PIRP Irp,
  326. IN PIO_STACK_LOCATION IrpSp
  327. );
  328. FILE_FULL_EA_INFORMATION UNALIGNED *
  329. FindEA(
  330. PFILE_FULL_EA_INFORMATION StartEA,
  331. CHAR * TargetName,
  332. USHORT TargetNameLength
  333. );
  334. BOOLEAN
  335. IsDHCPZeroAddress(
  336. TRANSPORT_ADDRESS UNALIGNED * AddrList
  337. );
  338. ULONG
  339. RawExtractProtocolNumber(
  340. IN PUNICODE_STRING FileName
  341. );
  342. NTSTATUS
  343. TCPControlSecurityFilter(
  344. IN PIRP Irp,
  345. IN PIO_STACK_LOCATION IrpSp
  346. );
  347. NTSTATUS
  348. TCPProcessSecurityFilterRequest(
  349. IN PIRP Irp,
  350. IN PIO_STACK_LOCATION IrpSp
  351. );
  352. NTSTATUS
  353. TCPEnumerateSecurityFilter(
  354. IN PIRP Irp,
  355. IN PIO_STACK_LOCATION IrpSp
  356. );
  357. NTSTATUS
  358. TCPEnumerateConnectionList(
  359. IN PIRP Irp,
  360. IN PIO_STACK_LOCATION IrpSp
  361. );
  362. //
  363. // Local helper routine prototypes.
  364. //
  365. ULONG
  366. TCPGetMdlChainByteCount(
  367. PMDL Mdl
  368. );
  369. ULONG
  370. TCPGetNdisBufferChainByteCount(
  371. PNDIS_BUFFER pBuffer
  372. );
  373. #if ACC
  374. BOOLEAN
  375. IsAdminIoRequest(
  376. PIRP Irp,
  377. PIO_STACK_LOCATION IrpSp
  378. );
  379. #endif
  380. //
  381. // All of this code is pageable.
  382. //
  383. #if !MILLEN
  384. #ifdef ALLOC_PRAGMA
  385. #pragma alloc_text(PAGE, TCPCreate)
  386. #pragma alloc_text(PAGE, TCPSetEventHandler)
  387. #pragma alloc_text(PAGE, FindEA)
  388. #pragma alloc_text(PAGE, IsDHCPZeroAddress)
  389. #pragma alloc_text(PAGE, RawExtractProtocolNumber)
  390. #pragma alloc_text(PAGE, TCPControlSecurityFilter)
  391. #pragma alloc_text(PAGE, TCPProcessSecurityFilterRequest)
  392. #pragma alloc_text(PAGE, TCPEnumerateSecurityFilter)
  393. #pragma alloc_text(PAGE, TCPEnumerateSecurityFilter)
  394. #if ACC
  395. #pragma alloc_text(PAGE, IsAdminIoRequest)
  396. #endif
  397. #endif
  398. #endif // !MILLEN
  399. //
  400. // Generic Irp completion and cancellation routines.
  401. //
  402. NTSTATUS
  403. TCPDataRequestComplete(
  404. void *Context,
  405. unsigned int Status,
  406. unsigned int ByteCount
  407. )
  408. /*++
  409. Routine Description:
  410. Completes a UDP/TCP send/receive request.
  411. Arguments:
  412. Context - A pointer to the IRP for this request.
  413. Status - The final TDI status of the request.
  414. ByteCount - Bytes sent/received information.
  415. Return Value:
  416. None.
  417. Notes:
  418. --*/
  419. {
  420. KIRQL oldIrql;
  421. PIRP irp;
  422. PIO_STACK_LOCATION irpSp;
  423. PTCP_CONTEXT tcpContext;
  424. PIRP item = NULL;
  425. CTELockHandle CancelHandle;
  426. irp = (PIRP) Context;
  427. irpSp = IoGetCurrentIrpStackLocation(irp);
  428. tcpContext = (PTCP_CONTEXT) irpSp->FileObject->FsContext;
  429. FreeMdlToNdisBufferChain(irp);
  430. if (IoSetCancelRoutine(irp, NULL) == NULL) {
  431. // Cancel routine have been invoked and can possibly
  432. // still be running. However, it won't find this IRP
  433. // on the list (TCB or AO). Just make sure the cancel
  434. // routine got far enough to acquire the endpoint lock
  435. // before proceeding to do this ourselves.
  436. IoAcquireCancelSpinLock(&oldIrql);
  437. IoReleaseCancelSpinLock(oldIrql);
  438. }
  439. CTEGetLock(&tcpContext->EndpointLock, &CancelHandle);
  440. #if DBG
  441. IF_TCPDBG(TCP_DEBUG_CANCEL) {
  442. PLIST_ENTRY entry, listHead;
  443. PIRP item = NULL;
  444. if (irp->Cancel) {
  445. ASSERT(irp->CancelRoutine == NULL);
  446. listHead = &(tcpContext->CancelledIrpList);
  447. } else {
  448. listHead = &(tcpContext->PendingIrpList);
  449. }
  450. //
  451. // Verify that the Irp is on the appropriate list
  452. //
  453. for (entry = listHead->Flink;
  454. entry != listHead;
  455. entry = entry->Flink
  456. ) {
  457. item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
  458. if (item == irp) {
  459. RemoveEntryList(&(irp->Tail.Overlay.ListEntry));
  460. break;
  461. }
  462. }
  463. if ((item == NULL) && irp->Cancel) {
  464. listHead = &(tcpContext->PendingIrpList);
  465. for (entry = listHead->Flink; entry != listHead; entry = entry->Flink) {
  466. item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
  467. if (item == irp) {
  468. RemoveEntryList(&(irp->Tail.Overlay.ListEntry));
  469. break;
  470. }
  471. }
  472. }
  473. }
  474. #endif
  475. //note that if we are not holding cancel spinlock
  476. //cancel can be in progress already
  477. //it should be still okay since this irp is already dequeued
  478. //from ao/tcb
  479. ASSERT(tcpContext->ReferenceCount > 0);
  480. if (--(tcpContext->ReferenceCount) == 0) {
  481. IF_TCPDBG(TCP_DEBUG_CANCEL) {
  482. ASSERT(IsListEmpty(&(tcpContext->CancelledIrpList)));
  483. ASSERT(IsListEmpty(&(tcpContext->PendingIrpList)));
  484. }
  485. //
  486. // Set the cleanup event.
  487. //
  488. KeSetEvent(&(tcpContext->CleanupEvent), 0, FALSE);
  489. }
  490. IF_TCPDBG(TCP_DEBUG_IRP) {
  491. TCPTRACE((
  492. "TCPDataRequestComplete: Irp %lx fileobj %lx refcnt dec to %u\n",
  493. irp,
  494. irpSp->FileObject,
  495. tcpContext->ReferenceCount
  496. ));
  497. }
  498. if (!((Status == TDI_CANCELLED) && ByteCount)) {
  499. if (irp->Cancel || tcpContext->CancelIrps) {
  500. IF_TCPDBG(TCP_DEBUG_IRP) {
  501. TCPTRACE(("TCPDataRequestComplete: Irp %lx was cancelled\n", irp));
  502. }
  503. irp->IoStatus.Status = Status = (unsigned int)STATUS_CANCELLED;
  504. ByteCount = 0;
  505. }
  506. } else {
  507. Status = STATUS_SUCCESS;
  508. }
  509. CTEFreeLock(&tcpContext->EndpointLock, CancelHandle);
  510. IF_TCPDBG(TCP_DEBUG_IRP) {
  511. TCPTRACE((
  512. "TCPDataRequestComplete: completing irp %lx, status %lx, byte count %lx\n",
  513. irp,
  514. Status,
  515. ByteCount
  516. ));
  517. }
  518. irp->IoStatus.Status = (NTSTATUS) Status;
  519. irp->IoStatus.Information = ByteCount;
  520. IoCompleteRequest(irp, IO_NETWORK_INCREMENT);
  521. return Status;
  522. } // TCPDataRequestComplete
  523. void
  524. TCPRequestComplete(
  525. void *Context,
  526. unsigned int Status,
  527. unsigned int UnUsed
  528. )
  529. /*++
  530. Routine Description:
  531. Completes a cancellable TDI request which returns no data by
  532. calling TCPDataRequestComplete with a ByteCount of zero.
  533. Arguments:
  534. Context - A pointer to the IRP for this request.
  535. Status - The final TDI status of the request.
  536. UnUsed - An unused parameter
  537. Return Value:
  538. None.
  539. Notes:
  540. --*/
  541. {
  542. UNREFERENCED_PARAMETER(UnUsed);
  543. TCPDataRequestComplete(Context, Status, 0);
  544. } // TCPRequestComplete
  545. void
  546. TCPNonCancellableRequestComplete(
  547. void *Context,
  548. unsigned int Status,
  549. unsigned int UnUsed
  550. )
  551. /*++
  552. Routine Description:
  553. Completes a TDI request which cannot be cancelled.
  554. Arguments:
  555. Context - A pointer to the IRP for this request.
  556. Status - The final TDI status of the request.
  557. UnUsed - An unused parameter
  558. Return Value:
  559. None.
  560. Notes:
  561. --*/
  562. {
  563. PIRP irp;
  564. PIO_STACK_LOCATION irpSp;
  565. UNREFERENCED_PARAMETER(UnUsed);
  566. irp = (PIRP) Context;
  567. irpSp = IoGetCurrentIrpStackLocation(irp);
  568. IF_TCPDBG(TCP_DEBUG_CLOSE) {
  569. TCPTRACE((
  570. "TCPNonCancellableRequestComplete: irp %lx status %lx\n",
  571. irp,
  572. Status
  573. ));
  574. }
  575. //
  576. // Complete the IRP
  577. //
  578. irp->IoStatus.Status = (NTSTATUS) Status;
  579. irp->IoStatus.Information = 0;
  580. IoCompleteRequest(irp, IO_NETWORK_INCREMENT);
  581. return;
  582. } // TCPNonCancellableRequestComplete
  583. void
  584. TCPCancelComplete(
  585. void *Context,
  586. unsigned int Unused1,
  587. unsigned int Unused2
  588. )
  589. {
  590. PFILE_OBJECT fileObject = (PFILE_OBJECT) Context;
  591. PTCP_CONTEXT tcpContext = (PTCP_CONTEXT) fileObject->FsContext;
  592. KIRQL oldIrql;
  593. CTELockHandle CancelHandle;
  594. UNREFERENCED_PARAMETER(Unused1);
  595. UNREFERENCED_PARAMETER(Unused2);
  596. CTEGetLock(&tcpContext->EndpointLock, &CancelHandle);
  597. //
  598. // Remove the reference placed on the endpoint by the cancel routine.
  599. // The cancelled Irp will be completed by the completion routine for the
  600. // request.
  601. //
  602. if (--(tcpContext->ReferenceCount) == 0) {
  603. IF_TCPDBG(TCP_DEBUG_CANCEL) {
  604. ASSERT(IsListEmpty(&(tcpContext->CancelledIrpList)));
  605. ASSERT(IsListEmpty(&(tcpContext->PendingIrpList)));
  606. }
  607. //
  608. // Set the cleanup event after releasing the lock
  609. //
  610. CTEFreeLock(&tcpContext->EndpointLock, CancelHandle);
  611. KeSetEvent(&(tcpContext->CleanupEvent), 0, FALSE);
  612. return;
  613. }
  614. IF_TCPDBG(TCP_DEBUG_IRP) {
  615. TCPTRACE((
  616. "TCPCancelComplete: fileobj %lx refcnt dec to %u\n",
  617. fileObject,
  618. tcpContext->ReferenceCount
  619. ));
  620. }
  621. CTEFreeLock(&tcpContext->EndpointLock, CancelHandle);
  622. return;
  623. } // TCPCancelComplete
  624. VOID
  625. TCPCancelRequest(
  626. PDEVICE_OBJECT Device,
  627. PIRP Irp
  628. )
  629. /*++
  630. Routine Description:
  631. Cancels an outstanding Irp.
  632. Arguments:
  633. Device - Pointer to the device object for this request.
  634. Irp - Pointer to I/O request packet
  635. Return Value:
  636. None.
  637. --*/
  638. {
  639. PIO_STACK_LOCATION irpSp;
  640. PTCP_CONTEXT tcpContext;
  641. NTSTATUS status = STATUS_SUCCESS;
  642. PFILE_OBJECT fileObject;
  643. UCHAR minorFunction;
  644. TDI_REQUEST request;
  645. CTELockHandle CancelHandle;
  646. KIRQL oldirql;
  647. KIRQL UserIrql;
  648. irpSp = IoGetCurrentIrpStackLocation(Irp);
  649. fileObject = irpSp->FileObject;
  650. tcpContext = (PTCP_CONTEXT) fileObject->FsContext;
  651. minorFunction = irpSp->MinorFunction;
  652. CTEGetLock(&tcpContext->EndpointLock, &CancelHandle);
  653. ASSERT(Irp->Cancel);
  654. UserIrql = Irp->CancelIrql;
  655. IoReleaseCancelSpinLock(CancelHandle);
  656. IF_TCPDBG(TCP_DEBUG_IRP) {
  657. TCPTRACE((
  658. "TCPCancelRequest: cancelling irp %lx, file object %lx\n",
  659. Irp,
  660. fileObject
  661. ));
  662. }
  663. #if DBG
  664. IF_TCPDBG(TCP_DEBUG_CANCEL) {
  665. //
  666. // Remove the Irp if it is on the pending list and place it on
  667. // the cancel list.
  668. //
  669. PLIST_ENTRY entry;
  670. PIRP item = NULL;
  671. for (entry = tcpContext->PendingIrpList.Flink;
  672. entry != &(tcpContext->PendingIrpList);
  673. entry = entry->Flink
  674. ) {
  675. item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
  676. if (item == Irp) {
  677. RemoveEntryList(&(Irp->Tail.Overlay.ListEntry));
  678. break;
  679. }
  680. }
  681. InsertTailList(
  682. &(tcpContext->CancelledIrpList),
  683. &(Irp->Tail.Overlay.ListEntry)
  684. );
  685. }
  686. #endif // DBG
  687. //
  688. // Add a reference so the object can't be closed while the cancel routine
  689. // is executing.
  690. //
  691. ASSERT(tcpContext->ReferenceCount > 0);
  692. tcpContext->ReferenceCount++;
  693. IF_TCPDBG(TCP_DEBUG_IRP) {
  694. TCPTRACE((
  695. "TCPCancelRequest: Irp %lx fileobj %lx refcnt inc to %u\n",
  696. Irp,
  697. fileObject,
  698. tcpContext->ReferenceCount
  699. ));
  700. }
  701. //
  702. // Try to cancel the request.
  703. //
  704. switch (minorFunction) {
  705. case TDI_SEND:
  706. case TDI_RECEIVE:
  707. ASSERT((PtrToUlong(fileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE) ||
  708. (PtrToUlong(fileObject->FsContext2) == TDI_CONNECTION_FILE));
  709. if (PtrToUlong(fileObject->FsContext2) == TDI_CONNECTION_FILE) {
  710. if (TCPAbortAndIndicateDisconnect(
  711. PtrToUlong(tcpContext->Handle.ConnectionContext), Irp, (minorFunction == TDI_RECEIVE) ? 1 : 0, UserIrql)) { //
  712. Irp->IoStatus.Status = STATUS_CANCELLED;
  713. Irp->IoStatus.Information = 0;
  714. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  715. }
  716. break;
  717. } else if (PtrToUlong(fileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE) {
  718. TdiCancelSendDatagram(tcpContext->Handle.AddressHandle, Irp, UserIrql);
  719. break;
  720. } else {
  721. CTEFreeLock(&tcpContext->EndpointLock, UserIrql);
  722. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Connect on neither address/connect file\n"));
  723. break;
  724. }
  725. case TDI_SEND_DATAGRAM:
  726. ASSERT(PtrToUlong(fileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE);
  727. TdiCancelSendDatagram(tcpContext->Handle.AddressHandle, Irp, UserIrql);
  728. break;
  729. case TDI_RECEIVE_DATAGRAM:
  730. ASSERT(PtrToUlong(fileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE);
  731. TdiCancelReceiveDatagram(tcpContext->Handle.AddressHandle, Irp, UserIrql);
  732. break;
  733. case TDI_DISASSOCIATE_ADDRESS:
  734. ASSERT(PtrToUlong(fileObject->FsContext2) == TDI_CONNECTION_FILE);
  735. //
  736. // This pends but is not cancellable. We put it thru the cancel code
  737. // anyway so a reference is made for it and so it can be tracked in
  738. // a debug build.
  739. //
  740. CTEFreeLock(&tcpContext->EndpointLock, UserIrql);
  741. break;
  742. default:
  743. //
  744. // Initiate a disconnect to cancel the request.
  745. //
  746. CTEFreeLock(&tcpContext->EndpointLock, UserIrql);
  747. request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
  748. request.RequestNotifyObject = TCPCancelComplete;
  749. request.RequestContext = fileObject;
  750. status = TdiDisconnect(
  751. &request,
  752. NULL,
  753. TDI_DISCONNECT_ABORT,
  754. NULL,
  755. NULL
  756. );
  757. break;
  758. }
  759. if (status != TDI_PENDING) {
  760. TCPCancelComplete(fileObject, 0, 0);
  761. }
  762. return;
  763. } // TCPCancelRequest
  764. NTSTATUS
  765. TCPPrepareIrpForCancel(
  766. PTCP_CONTEXT TcpContext,
  767. PIRP Irp,
  768. PDRIVER_CANCEL CancelRoutine
  769. )
  770. {
  771. KIRQL oldIrql;
  772. CTELockHandle CancelHandle;
  773. ULONG LocalCancelId;
  774. //
  775. // Set up for cancellation
  776. //
  777. CTEGetLock(&TcpContext->EndpointLock, &CancelHandle);
  778. ASSERT(Irp->CancelRoutine == NULL);
  779. if (!Irp->Cancel && !TcpContext->Cleanup) {
  780. IoMarkIrpPending(Irp);
  781. IoSetCancelRoutine(Irp, CancelRoutine);
  782. TcpContext->ReferenceCount++;
  783. IF_TCPDBG(TCP_DEBUG_IRP) {
  784. TCPTRACE((
  785. "TCPPrepareIrpForCancel: irp %lx fileobj %lx refcnt inc to %u\n",
  786. Irp,
  787. (IoGetCurrentIrpStackLocation(Irp))->FileObject,
  788. TcpContext->ReferenceCount
  789. ));
  790. }
  791. #if DBG
  792. IF_TCPDBG(TCP_DEBUG_CANCEL) {
  793. PLIST_ENTRY entry;
  794. PIRP item = NULL;
  795. //
  796. // Verify that the Irp has not already been submitted.
  797. //
  798. for (entry = TcpContext->PendingIrpList.Flink;
  799. entry != &(TcpContext->PendingIrpList);
  800. entry = entry->Flink
  801. ) {
  802. item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
  803. ASSERT(item != Irp);
  804. }
  805. for (entry = TcpContext->CancelledIrpList.Flink;
  806. entry != &(TcpContext->CancelledIrpList);
  807. entry = entry->Flink
  808. ) {
  809. item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
  810. ASSERT(item != Irp);
  811. }
  812. InsertTailList(
  813. &(TcpContext->PendingIrpList),
  814. &(Irp->Tail.Overlay.ListEntry)
  815. );
  816. }
  817. #endif // DBG
  818. //Update monotonically increasing cancel ID and
  819. //remember this for later use
  820. while ((LocalCancelId = InterlockedIncrement(&CancelId.Value)) == 0) { }
  821. CTEFreeLock(&TcpContext->EndpointLock, CancelHandle);
  822. Irp->Tail.Overlay.DriverContext[1] = UlongToPtr(LocalCancelId);
  823. Irp->Tail.Overlay.DriverContext[0] = NULL;
  824. return (STATUS_SUCCESS);
  825. }
  826. //
  827. // The IRP has already been cancelled or endpoint in cleanup phase. Complete it now.
  828. //
  829. IF_TCPDBG(TCP_DEBUG_IRP) {
  830. TCPTRACE(("TCP: irp %lx already cancelled, completing.\n", Irp));
  831. }
  832. CTEFreeLock(&TcpContext->EndpointLock, CancelHandle);
  833. Irp->IoStatus.Status = STATUS_CANCELLED;
  834. Irp->IoStatus.Information = 0;
  835. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  836. return (STATUS_CANCELLED);
  837. } // TCPPrepareIrpForCancel
  838. //
  839. // TDI functions
  840. //
  841. NTSTATUS
  842. TCPAssociateAddress(
  843. IN PIRP Irp,
  844. IN PIO_STACK_LOCATION IrpSp
  845. )
  846. /*++
  847. Routine Description:
  848. Converts a TDI Associate Address IRP into a call to TdiAssociateAddress.
  849. Arguments:
  850. Irp - Pointer to I/O request packet
  851. IrpSp - Pointer to the current stack location in the Irp.
  852. Return Value:
  853. NTSTATUS -- Indicates whether the request was successful.
  854. Notes:
  855. This routine does not pend.
  856. --*/
  857. {
  858. NTSTATUS status;
  859. TDI_REQUEST request;
  860. PTCP_CONTEXT tcpContext;
  861. PTDI_REQUEST_KERNEL_ASSOCIATE associateInformation;
  862. PFILE_OBJECT fileObject;
  863. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPAssociateAddress(%x, %x)\n"),
  864. Irp, IrpSp));
  865. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  866. request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
  867. associateInformation = (PTDI_REQUEST_KERNEL_ASSOCIATE) & (IrpSp->Parameters);
  868. //
  869. // Get the file object for the address. Then extract the Address Handle
  870. // from the TCP_CONTEXT associated with it.
  871. //
  872. status = ObReferenceObjectByHandle(
  873. associateInformation->AddressHandle,
  874. 0,
  875. *IoFileObjectType,
  876. Irp->RequestorMode,
  877. &fileObject,
  878. NULL
  879. );
  880. if (NT_SUCCESS(status)) {
  881. if ((fileObject->DeviceObject == TCPDeviceObject) &&
  882. (PtrToUlong(fileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE)
  883. ) {
  884. BOOLEAN cleanup;
  885. CTELockHandle CancelHandle;
  886. tcpContext = (PTCP_CONTEXT) fileObject->FsContext;
  887. //if cleanup in progress, do not allow this operation.
  888. CTEGetLock(&tcpContext->EndpointLock, &CancelHandle);
  889. cleanup = tcpContext->Cleanup;
  890. CTEFreeLock(&tcpContext->EndpointLock, CancelHandle);
  891. status = STATUS_INVALID_HANDLE;
  892. if (!cleanup)
  893. status = TdiAssociateAddress(
  894. &request,
  895. tcpContext->Handle.AddressHandle
  896. );
  897. ASSERT(status != STATUS_PENDING);
  898. ObDereferenceObject(fileObject);
  899. IF_TCPDBG(TCP_DEBUG_ASSOCIATE) {
  900. TCPTRACE((
  901. "TCPAssociateAddress complete on file object %lx\n",
  902. IrpSp->FileObject
  903. ));
  904. }
  905. } else {
  906. ObDereferenceObject(fileObject);
  907. status = STATUS_INVALID_HANDLE;
  908. IF_TCPDBG(TCP_DEBUG_ASSOCIATE) {
  909. TCPTRACE((
  910. "TCPAssociateAddress: ObReference failed on object %lx, status %lx\n",
  911. associateInformation->AddressHandle,
  912. status
  913. ));
  914. }
  915. }
  916. } else {
  917. DEBUGMSG(DBG_ERROR && DBG_TDI,
  918. (DTEXT("TdiAssociateAddress: ObReference failure %x on handle %x\n"),
  919. status, associateInformation->AddressHandle));
  920. }
  921. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPAssociateAddress [%x]\n"), status));
  922. return (status);
  923. }
  924. NTSTATUS
  925. TCPDisassociateAddress(
  926. IN PIRP Irp,
  927. IN PIO_STACK_LOCATION IrpSp
  928. )
  929. /*++
  930. Routine Description:
  931. Converts a TDI Associate Address IRP into a call to TdiAssociateAddress.
  932. Arguments:
  933. Irp - Pointer to I/O request packet
  934. IrpSp - Pointer to the current stack location in the Irp.
  935. Return Value:
  936. NTSTATUS -- Indicates whether the request was successful.
  937. --*/
  938. {
  939. NTSTATUS status;
  940. TDI_REQUEST request;
  941. PTCP_CONTEXT tcpContext;
  942. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPDisassociateAddress \n")));
  943. IF_TCPDBG(TCP_DEBUG_ASSOCIATE) {
  944. TCPTRACE(("TCP disassociating address\n"));
  945. }
  946. ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE);
  947. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  948. request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
  949. request.RequestNotifyObject = TCPRequestComplete;
  950. request.RequestContext = Irp;
  951. status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
  952. if (NT_SUCCESS(status)) {
  953. status = TdiDisAssociateAddress(&request);
  954. if (status != TDI_PENDING) {
  955. TCPRequestComplete(Irp, status, 0);
  956. }
  957. //
  958. // return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING
  959. //
  960. return (TDI_PENDING);
  961. }
  962. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPDisassociateAddress \n")));
  963. return (status);
  964. } // TCPDisassociateAddress
  965. NTSTATUS
  966. TCPConnect(
  967. IN PIRP Irp,
  968. IN PIO_STACK_LOCATION IrpSp
  969. )
  970. /*++
  971. Routine Description:
  972. Converts a TDI Connect IRP into a call to TdiConnect.
  973. Arguments:
  974. Irp - Pointer to I/O request packet
  975. IrpSp - Pointer to the current stack location in the Irp.
  976. Return Value:
  977. NTSTATUS -- Indicates whether the request was successfully queued.
  978. --*/
  979. {
  980. NTSTATUS status;
  981. PTCP_CONTEXT tcpContext;
  982. TDI_REQUEST request;
  983. PTDI_CONNECTION_INFORMATION requestInformation, returnInformation;
  984. PTDI_REQUEST_KERNEL_CONNECT connectRequest;
  985. LARGE_INTEGER millisecondTimeout;
  986. PLARGE_INTEGER requestTimeout;
  987. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPConnect \n")));
  988. IF_TCPDBG(TCP_DEBUG_CONNECT) {
  989. TCPTRACE((
  990. "TCPConnect irp %lx, file object %lx\n",
  991. Irp,
  992. IrpSp->FileObject
  993. ));
  994. }
  995. ASSERT((PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE) ||
  996. (PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE));
  997. connectRequest = (PTDI_REQUEST_KERNEL_CONNECT) & (IrpSp->Parameters);
  998. requestInformation = connectRequest->RequestConnectionInformation;
  999. returnInformation = connectRequest->ReturnConnectionInformation;
  1000. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  1001. request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
  1002. request.RequestNotifyObject = TCPRequestComplete;
  1003. request.RequestContext = Irp;
  1004. requestTimeout = (PLARGE_INTEGER) connectRequest->RequestSpecific;
  1005. if (requestTimeout != NULL) {
  1006. //
  1007. // NT relative timeouts are negative. Negate first to get a positive
  1008. // value to pass to the transport.
  1009. //
  1010. millisecondTimeout.QuadPart = -((*requestTimeout).QuadPart);
  1011. millisecondTimeout = CTEConvert100nsToMilliseconds(
  1012. millisecondTimeout
  1013. );
  1014. } else {
  1015. millisecondTimeout.LowPart = 0;
  1016. millisecondTimeout.HighPart = 0;
  1017. }
  1018. ASSERT(millisecondTimeout.HighPart == 0);
  1019. status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
  1020. if (NT_SUCCESS(status)) {
  1021. if (PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE) {
  1022. status = TdiConnect(
  1023. &request,
  1024. ((millisecondTimeout.LowPart != 0) ?
  1025. &(millisecondTimeout.LowPart) : NULL),
  1026. requestInformation,
  1027. returnInformation
  1028. );
  1029. } else if (PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE) {
  1030. status = UDPConnect(
  1031. &request,
  1032. ((millisecondTimeout.LowPart != 0) ?
  1033. &(millisecondTimeout.LowPart) : NULL),
  1034. requestInformation,
  1035. returnInformation
  1036. );
  1037. } else {
  1038. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Connect on neither address/connect file\n"));
  1039. ASSERT(FALSE);
  1040. }
  1041. if (status != STATUS_PENDING) {
  1042. TCPRequestComplete(Irp, status, 0);
  1043. }
  1044. //
  1045. // return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING
  1046. //
  1047. return (STATUS_PENDING);
  1048. }
  1049. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPConnect \n")));
  1050. return (status);
  1051. } // TCPConnect
  1052. NTSTATUS
  1053. TCPDisconnect(
  1054. IN PIRP Irp,
  1055. IN PIO_STACK_LOCATION IrpSp
  1056. )
  1057. /*++
  1058. Routine Description:
  1059. Converts a TDI Disconnect IRP into a call to TdiDisconnect.
  1060. Arguments:
  1061. Irp - Pointer to I/O request packet
  1062. IrpSp - Pointer to the current stack location in the Irp.
  1063. Return Value:
  1064. NTSTATUS -- Indicates whether the request was successfully queued.
  1065. Notes:
  1066. Abortive disconnects may pend, but cannot be cancelled.
  1067. --*/
  1068. {
  1069. NTSTATUS status;
  1070. PTCP_CONTEXT tcpContext;
  1071. TDI_REQUEST request;
  1072. PTDI_CONNECTION_INFORMATION requestInformation, returnInformation;
  1073. PTDI_REQUEST_KERNEL_DISCONNECT disconnectRequest;
  1074. LARGE_INTEGER millisecondTimeout;
  1075. PLARGE_INTEGER requestTimeout;
  1076. BOOLEAN abortive = FALSE;
  1077. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPDisconnect \n")));
  1078. ASSERT((PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE) ||
  1079. (PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE));
  1080. disconnectRequest = (PTDI_REQUEST_KERNEL_CONNECT) & (IrpSp->Parameters);
  1081. requestInformation = disconnectRequest->RequestConnectionInformation;
  1082. returnInformation = disconnectRequest->ReturnConnectionInformation;
  1083. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  1084. request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
  1085. request.RequestContext = Irp;
  1086. //
  1087. // Set up the timeout value.
  1088. //
  1089. if (disconnectRequest->RequestSpecific != NULL) {
  1090. requestTimeout = (PLARGE_INTEGER) disconnectRequest->RequestSpecific;
  1091. if ((requestTimeout->LowPart == -1) && (requestTimeout->HighPart == -1)) {
  1092. // This is infinite time timeout period
  1093. // Just use 0 timeout value
  1094. millisecondTimeout.LowPart = 0;
  1095. millisecondTimeout.HighPart = 0;
  1096. } else {
  1097. //
  1098. // NT relative timeouts are negative. Negate first to get a
  1099. // positive value to pass to the transport.
  1100. //
  1101. millisecondTimeout.QuadPart = -((*requestTimeout).QuadPart);
  1102. millisecondTimeout = CTEConvert100nsToMilliseconds(
  1103. millisecondTimeout
  1104. );
  1105. }
  1106. } else {
  1107. millisecondTimeout.LowPart = 0;
  1108. millisecondTimeout.HighPart = 0;
  1109. }
  1110. if (disconnectRequest->RequestFlags & TDI_DISCONNECT_ABORT) {
  1111. //
  1112. // Abortive disconnects cannot be cancelled and must use
  1113. // a specific completion routine.
  1114. //
  1115. abortive = TRUE;
  1116. IoMarkIrpPending(Irp);
  1117. request.RequestNotifyObject = TCPNonCancellableRequestComplete;
  1118. status = STATUS_SUCCESS;
  1119. } else {
  1120. //
  1121. // Non-abortive disconnects can use the generic cancellation and
  1122. // completion routines.
  1123. //
  1124. status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
  1125. request.RequestNotifyObject = TCPRequestComplete;
  1126. }
  1127. IF_TCPDBG(TCP_DEBUG_CLOSE) {
  1128. TCPTRACE((
  1129. "TCPDisconnect irp %lx, flags %lx, fileobj %lx, abortive = %d\n",
  1130. Irp,
  1131. disconnectRequest->RequestFlags,
  1132. IrpSp->FileObject,
  1133. abortive
  1134. ));
  1135. }
  1136. if (NT_SUCCESS(status)) {
  1137. if (PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE) {
  1138. status = TdiDisconnect(
  1139. &request,
  1140. ((millisecondTimeout.LowPart != 0) ?
  1141. &(millisecondTimeout.LowPart) : NULL),
  1142. (ushort) disconnectRequest->RequestFlags,
  1143. requestInformation,
  1144. returnInformation
  1145. );
  1146. } else if (PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE) {
  1147. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"DisConnect on address file Irp %x \n", Irp));
  1148. status = UDPDisconnect(
  1149. &request,
  1150. ((millisecondTimeout.LowPart != 0) ?
  1151. &(millisecondTimeout.LowPart) : NULL),
  1152. requestInformation,
  1153. returnInformation
  1154. );
  1155. } else {
  1156. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"DisConnect on neither address/connect file\n"));
  1157. ASSERT(FALSE);
  1158. }
  1159. if (status != STATUS_PENDING) {
  1160. if (abortive) {
  1161. TCPNonCancellableRequestComplete(Irp, status, 0);
  1162. } else {
  1163. TCPRequestComplete(Irp, status, 0);
  1164. }
  1165. } else {
  1166. IF_TCPDBG(TCP_DEBUG_CLOSE) {
  1167. TCPTRACE(("TCPDisconnect pending irp %lx\n", Irp));
  1168. }
  1169. }
  1170. //
  1171. // return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING
  1172. //
  1173. return (STATUS_PENDING);
  1174. }
  1175. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPDisconnect \n")));
  1176. return (status);
  1177. } // TCPDisconnect
  1178. NTSTATUS
  1179. TCPListen(
  1180. IN PIRP Irp,
  1181. IN PIO_STACK_LOCATION IrpSp
  1182. )
  1183. /*++
  1184. Routine Description:
  1185. Converts a TDI Listen IRP into a call to TdiListen.
  1186. Arguments:
  1187. Irp - Pointer to I/O request packet
  1188. IrpSp - Pointer to the current stack location in the Irp.
  1189. Return Value:
  1190. NTSTATUS -- Indicates whether the request was successful.
  1191. --*/
  1192. {
  1193. NTSTATUS status;
  1194. PTCP_CONTEXT tcpContext;
  1195. TDI_REQUEST request;
  1196. PTDI_CONNECTION_INFORMATION requestInformation, returnInformation;
  1197. PTDI_REQUEST_KERNEL_LISTEN listenRequest;
  1198. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPListen \n")));
  1199. IF_TCPDBG(TCP_DEBUG_CONNECT) {
  1200. TCPTRACE((
  1201. "TCPListen irp %lx on file object %lx\n",
  1202. Irp,
  1203. IrpSp->FileObject
  1204. ));
  1205. }
  1206. ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE);
  1207. listenRequest = (PTDI_REQUEST_KERNEL_CONNECT) & (IrpSp->Parameters);
  1208. requestInformation = listenRequest->RequestConnectionInformation;
  1209. returnInformation = listenRequest->ReturnConnectionInformation;
  1210. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  1211. request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
  1212. request.RequestNotifyObject = TCPRequestComplete;
  1213. request.RequestContext = Irp;
  1214. status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
  1215. if (NT_SUCCESS(status)) {
  1216. status = TdiListen(
  1217. &request,
  1218. (ushort) listenRequest->RequestFlags,
  1219. requestInformation,
  1220. returnInformation
  1221. );
  1222. if (status != TDI_PENDING) {
  1223. TCPRequestComplete(Irp, status, 0);
  1224. }
  1225. //
  1226. // return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING
  1227. //
  1228. return (TDI_PENDING);
  1229. }
  1230. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPListen \n")));
  1231. return (status);
  1232. } // TCPListen
  1233. NTSTATUS
  1234. TCPAccept(
  1235. IN PIRP Irp,
  1236. IN PIO_STACK_LOCATION IrpSp
  1237. )
  1238. /*++
  1239. Routine Description:
  1240. Converts a TDI Accept IRP into a call to TdiAccept.
  1241. Arguments:
  1242. Irp - Pointer to I/O request packet
  1243. IrpSp - Pointer to the current stack location in the Irp.
  1244. Return Value:
  1245. NTSTATUS -- Indicates whether the request was successfully queued.
  1246. --*/
  1247. {
  1248. NTSTATUS status;
  1249. PTCP_CONTEXT tcpContext;
  1250. TDI_REQUEST request;
  1251. PTDI_CONNECTION_INFORMATION requestInformation, returnInformation;
  1252. PTDI_REQUEST_KERNEL_ACCEPT acceptRequest;
  1253. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPAccept \n")));
  1254. IF_TCPDBG(TCP_DEBUG_CONNECT) {
  1255. TCPTRACE((
  1256. "TCPAccept irp %lx on file object %lx\n", Irp,
  1257. IrpSp->FileObject
  1258. ));
  1259. }
  1260. ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE);
  1261. acceptRequest = (PTDI_REQUEST_KERNEL_ACCEPT) & (IrpSp->Parameters);
  1262. requestInformation = acceptRequest->RequestConnectionInformation;
  1263. returnInformation = acceptRequest->ReturnConnectionInformation;
  1264. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  1265. request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
  1266. request.RequestNotifyObject = TCPRequestComplete;
  1267. request.RequestContext = Irp;
  1268. status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
  1269. if (NT_SUCCESS(status)) {
  1270. status = TdiAccept(
  1271. &request,
  1272. requestInformation,
  1273. returnInformation
  1274. );
  1275. if (status != TDI_PENDING) {
  1276. TCPRequestComplete(Irp, status, 0);
  1277. }
  1278. //
  1279. // return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING
  1280. //
  1281. return (TDI_PENDING);
  1282. }
  1283. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPAccept \n")));
  1284. return (status);
  1285. } // TCPAccept
  1286. NTSTATUS
  1287. TCPSendData(
  1288. IN PIRP Irp,
  1289. IN PIO_STACK_LOCATION IrpSp
  1290. )
  1291. /*++
  1292. Routine Description:
  1293. Converts a TDI Send IRP into a call to TdiSend.
  1294. Arguments:
  1295. Irp - Pointer to I/O request packet
  1296. IrpSp - Pointer to the current stack location in the Irp.
  1297. Return Value:
  1298. NTSTATUS -- Indicates whether the request was successful.
  1299. --*/
  1300. {
  1301. TDI_STATUS status;
  1302. TDI_REQUEST request;
  1303. PTCP_CONTEXT tcpContext;
  1304. PTDI_REQUEST_KERNEL_SEND requestInformation;
  1305. KIRQL oldIrql;
  1306. CTELockHandle CancelHandle;
  1307. PNDIS_BUFFER pNdisBuffer;
  1308. ULONG LocalCancelId;
  1309. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPSendData \n")));
  1310. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  1311. ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE);
  1312. requestInformation = (PTDI_REQUEST_KERNEL_SEND) & (IrpSp->Parameters);
  1313. request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
  1314. request.RequestNotifyObject = TCPDataRequestComplete;
  1315. request.RequestContext = Irp;
  1316. ASSERT(Irp->CancelRoutine == NULL);
  1317. CTEGetLock(&tcpContext->EndpointLock, &CancelHandle);
  1318. IoSetCancelRoutine(Irp, TCPCancelRequest);
  1319. if (!Irp->Cancel) {
  1320. //
  1321. // Set up for cancellation
  1322. //
  1323. IoMarkIrpPending(Irp);
  1324. tcpContext->ReferenceCount++;
  1325. IF_TCPDBG(TCP_DEBUG_IRP) {
  1326. TCPTRACE((
  1327. "TCPSendData: irp %lx fileobj %lx refcnt inc to %u\n",
  1328. Irp,
  1329. IrpSp,
  1330. tcpContext->ReferenceCount
  1331. ));
  1332. }
  1333. #if DBG
  1334. IF_TCPDBG(TCP_DEBUG_CANCEL) {
  1335. PLIST_ENTRY entry;
  1336. PIRP item = NULL;
  1337. //
  1338. // Verify that the Irp has not already been submitted.
  1339. //
  1340. for (entry = tcpContext->PendingIrpList.Flink;
  1341. entry != &(tcpContext->PendingIrpList);
  1342. entry = entry->Flink
  1343. ) {
  1344. item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
  1345. ASSERT(item != Irp);
  1346. }
  1347. for (entry = tcpContext->CancelledIrpList.Flink;
  1348. entry != &(tcpContext->CancelledIrpList);
  1349. entry = entry->Flink
  1350. ) {
  1351. item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
  1352. ASSERT(item != Irp);
  1353. }
  1354. InsertTailList(
  1355. &(tcpContext->PendingIrpList),
  1356. &(Irp->Tail.Overlay.ListEntry)
  1357. );
  1358. }
  1359. #endif // DBG
  1360. //Update monotonically increasing cancel ID and
  1361. //remember this for later use
  1362. while ((LocalCancelId = InterlockedIncrement(&CancelId.Value)) == 0) { }
  1363. Irp->Tail.Overlay.DriverContext[1] = UlongToPtr(LocalCancelId);
  1364. Irp->Tail.Overlay.DriverContext[0] = NULL;
  1365. CTEFreeLock(&tcpContext->EndpointLock, CancelHandle);
  1366. IF_TCPDBG(TCP_DEBUG_SEND) {
  1367. TCPTRACE((
  1368. "TCPSendData irp %lx sending %d bytes, flags %lx, fileobj %lx\n",
  1369. Irp,
  1370. requestInformation->SendLength,
  1371. requestInformation->SendFlags,
  1372. IrpSp->FileObject
  1373. ));
  1374. }
  1375. status = ConvertMdlToNdisBuffer(Irp, Irp->MdlAddress, &pNdisBuffer);
  1376. if (status == TDI_SUCCESS) {
  1377. status = TdiSend(
  1378. &request,
  1379. (ushort) requestInformation->SendFlags,
  1380. requestInformation->SendLength,
  1381. pNdisBuffer
  1382. );
  1383. }
  1384. if (status == TDI_PENDING) {
  1385. IF_TCPDBG(TCP_DEBUG_SEND) {
  1386. TCPTRACE(("TCPSendData pending irp %lx\n", Irp));
  1387. }
  1388. return (status);
  1389. }
  1390. //
  1391. // The status is not pending. We reset the pending bit
  1392. //
  1393. IrpSp->Control &= ~SL_PENDING_RETURNED;
  1394. if (status == TDI_SUCCESS) {
  1395. ASSERT(requestInformation->SendLength == 0);
  1396. status = TCPDataRequestComplete(Irp, status, requestInformation->SendLength);
  1397. } else {
  1398. IF_TCPDBG(TCP_DEBUG_SEND) {
  1399. TCPTRACE((
  1400. "TCPSendData - irp %lx send failed, status %lx\n",
  1401. Irp,
  1402. status
  1403. ));
  1404. }
  1405. status = TCPDataRequestComplete(Irp, status, 0);
  1406. }
  1407. } else {
  1408. //
  1409. // Irp was cancelled previously.
  1410. //
  1411. CTEFreeLock(&tcpContext->EndpointLock, CancelHandle);
  1412. //Let cancel routine run
  1413. IoAcquireCancelSpinLock(&oldIrql);
  1414. IoReleaseCancelSpinLock(oldIrql);
  1415. CTEGetLock(&tcpContext->EndpointLock, &CancelHandle);
  1416. IoSetCancelRoutine(Irp, NULL);
  1417. IF_TCPDBG(TCP_DEBUG_SEND) {
  1418. TCPTRACE((
  1419. "TCPSendData: Irp %lx on fileobj %lx was cancelled\n",
  1420. Irp,
  1421. IrpSp->FileObject
  1422. ));
  1423. }
  1424. Irp->IoStatus.Status = STATUS_CANCELLED;
  1425. Irp->IoStatus.Information = 0;
  1426. CTEFreeLock(&tcpContext->EndpointLock, CancelHandle);
  1427. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  1428. status = STATUS_CANCELLED;
  1429. }
  1430. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPSendData \n")));
  1431. return (status);
  1432. } // TCPSendData
  1433. NTSTATUS
  1434. TCPReceiveData(
  1435. IN PIRP Irp,
  1436. IN PIO_STACK_LOCATION IrpSp
  1437. )
  1438. /*++
  1439. Routine Description:
  1440. Converts a TDI Receive IRP into a call to TdiReceive.
  1441. Arguments:
  1442. Irp - Pointer to I/O request packet
  1443. IrpSp - Pointer to the current stack location in the Irp.
  1444. Return Value:
  1445. NTSTATUS -- Indicates whether the request was successful.
  1446. --*/
  1447. {
  1448. TDI_STATUS status;
  1449. TDI_REQUEST request;
  1450. PTCP_CONTEXT tcpContext;
  1451. PTDI_REQUEST_KERNEL_RECEIVE requestInformation;
  1452. KIRQL oldIrql;
  1453. CTELockHandle CancelHandle;
  1454. PNDIS_BUFFER pNdisBuffer;
  1455. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPReceiveData \n")));
  1456. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  1457. ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE);
  1458. requestInformation = (PTDI_REQUEST_KERNEL_RECEIVE) & (IrpSp->Parameters);
  1459. request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
  1460. request.RequestNotifyObject = TCPDataRequestComplete;
  1461. request.RequestContext = Irp;
  1462. ASSERT(Irp->CancelRoutine == NULL);
  1463. CTEGetLock(&tcpContext->EndpointLock, &CancelHandle);
  1464. IoSetCancelRoutine(Irp, TCPCancelRequest);
  1465. if (!Irp->Cancel) {
  1466. //
  1467. // Set up for cancellation
  1468. //
  1469. IoMarkIrpPending(Irp);
  1470. tcpContext->ReferenceCount++;
  1471. IF_TCPDBG(TCP_DEBUG_IRP) {
  1472. TCPTRACE((
  1473. "TCPReceiveData: irp %lx fileobj %lx refcnt inc to %u\n",
  1474. Irp,
  1475. IrpSp->FileObject,
  1476. tcpContext->ReferenceCount
  1477. ));
  1478. }
  1479. #if DBG
  1480. IF_TCPDBG(TCP_DEBUG_CANCEL) {
  1481. PLIST_ENTRY entry;
  1482. PIRP item = NULL;
  1483. //
  1484. // Verify that the Irp has not already been submitted.
  1485. //
  1486. for (entry = tcpContext->PendingIrpList.Flink;
  1487. entry != &(tcpContext->PendingIrpList);
  1488. entry = entry->Flink
  1489. ) {
  1490. item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
  1491. ASSERT(item != Irp);
  1492. }
  1493. for (entry = tcpContext->CancelledIrpList.Flink;
  1494. entry != &(tcpContext->CancelledIrpList);
  1495. entry = entry->Flink
  1496. ) {
  1497. item = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
  1498. ASSERT(item != Irp);
  1499. }
  1500. InsertTailList(
  1501. &(tcpContext->PendingIrpList),
  1502. &(Irp->Tail.Overlay.ListEntry)
  1503. );
  1504. }
  1505. #endif // DBG
  1506. CTEFreeLock(&tcpContext->EndpointLock, CancelHandle);
  1507. IF_TCPDBG(TCP_DEBUG_RECEIVE) {
  1508. TCPTRACE((
  1509. "TCPReceiveData irp %lx receiving %d bytes flags %lx filobj %lx\n",
  1510. Irp,
  1511. requestInformation->ReceiveLength,
  1512. requestInformation->ReceiveFlags,
  1513. IrpSp->FileObject
  1514. ));
  1515. }
  1516. status = ConvertMdlToNdisBuffer(Irp, Irp->MdlAddress, &pNdisBuffer);
  1517. if (status == TDI_SUCCESS) {
  1518. status = TdiReceive(
  1519. &request,
  1520. (ushort *) & (requestInformation->ReceiveFlags),
  1521. &(requestInformation->ReceiveLength),
  1522. pNdisBuffer
  1523. );
  1524. }
  1525. if (status == TDI_PENDING) {
  1526. IF_TCPDBG(TCP_DEBUG_RECEIVE) {
  1527. TCPTRACE(("TCPReceiveData: pending irp %lx\n", Irp));
  1528. }
  1529. return (status);
  1530. }
  1531. //
  1532. // The status is not pending. We reset the pending bit
  1533. //
  1534. IrpSp->Control &= ~SL_PENDING_RETURNED;
  1535. // ASSERT(status != TDI_SUCCESS);
  1536. IF_TCPDBG(TCP_DEBUG_RECEIVE) {
  1537. TCPTRACE((
  1538. "TCPReceiveData - irp %lx failed, status %lx\n",
  1539. Irp,
  1540. status
  1541. ));
  1542. }
  1543. status = TCPDataRequestComplete(Irp, status, 0);
  1544. } else {
  1545. //
  1546. // Irp was cancelled previously.
  1547. //
  1548. CTEFreeLock(&tcpContext->EndpointLock, CancelHandle);
  1549. //Synchoronize with cancel routine by using both iocancelspinlocks
  1550. //and endpoint locks
  1551. IoAcquireCancelSpinLock(&oldIrql);
  1552. IoReleaseCancelSpinLock(oldIrql);
  1553. CTEGetLock(&tcpContext->EndpointLock, &CancelHandle);
  1554. IoSetCancelRoutine(Irp, NULL);
  1555. IF_TCPDBG(TCP_DEBUG_SEND) {
  1556. TCPTRACE((
  1557. "TCPReceiveData: Irp %lx on fileobj %lx was cancelled\n",
  1558. Irp,
  1559. IrpSp->FileObject
  1560. ));
  1561. }
  1562. Irp->IoStatus.Status = STATUS_CANCELLED;
  1563. Irp->IoStatus.Information = 0;
  1564. CTEFreeLock(&tcpContext->EndpointLock, CancelHandle);
  1565. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  1566. status = STATUS_CANCELLED;
  1567. }
  1568. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPReceiveData \n")));
  1569. return status;
  1570. } // TCPReceiveData
  1571. NTSTATUS
  1572. UDPSendData(
  1573. IN PIRP Irp,
  1574. IN PIO_STACK_LOCATION IrpSp
  1575. )
  1576. /*++
  1577. Routine Description:
  1578. Arguments:
  1579. Irp - Pointer to I/O request packet
  1580. IrpSp - Pointer to the current stack location in the Irp.
  1581. Return Value:
  1582. NTSTATUS -- Indicates whether the request was successfully queued.
  1583. --*/
  1584. {
  1585. TDI_STATUS status;
  1586. TDI_REQUEST request;
  1587. PTCP_CONTEXT tcpContext;
  1588. PTDI_REQUEST_KERNEL_SEND datagramInformation;
  1589. ULONG bytesSent = 0;
  1590. PNDIS_BUFFER pNdisBuffer;
  1591. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+UDPSendData \n")));
  1592. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  1593. datagramInformation = (PTDI_REQUEST_KERNEL_SEND) & (IrpSp->Parameters);
  1594. ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE);
  1595. request.Handle.AddressHandle = tcpContext->Handle.AddressHandle;
  1596. request.RequestNotifyObject = TCPDataRequestComplete;
  1597. request.RequestContext = Irp;
  1598. IF_TCPDBG(TCP_DEBUG_SEND_DGRAM) {
  1599. TCPTRACE((
  1600. "UDPSendData irp %lx sending %d bytes\n",
  1601. Irp,
  1602. datagramInformation->SendLength
  1603. ));
  1604. }
  1605. status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
  1606. if (NT_SUCCESS(status)) {
  1607. AddrObj *AO = request.Handle.AddressHandle;
  1608. if (AO && (AO->ao_flags & AO_CONNUDP_FLAG)) {
  1609. status = ConvertMdlToNdisBuffer(Irp, Irp->MdlAddress, &pNdisBuffer);
  1610. if (status == TDI_SUCCESS) {
  1611. status = TdiSendDatagram(
  1612. &request,
  1613. NULL,
  1614. datagramInformation->SendLength,
  1615. &bytesSent,
  1616. pNdisBuffer
  1617. );
  1618. }
  1619. if (status == TDI_PENDING) {
  1620. return (status);
  1621. }
  1622. } else {
  1623. status = TDI_ADDR_INVALID;
  1624. }
  1625. ASSERT(status != TDI_SUCCESS);
  1626. ASSERT(bytesSent == 0);
  1627. TCPTRACE((
  1628. "UDPSendData - irp %lx send failed, status %lx\n",
  1629. Irp,
  1630. status
  1631. ));
  1632. TCPDataRequestComplete(Irp, status, bytesSent);
  1633. //
  1634. // return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING
  1635. //
  1636. return (TDI_PENDING);
  1637. }
  1638. return status;
  1639. }
  1640. NTSTATUS
  1641. UDPSendDatagram(
  1642. IN PIRP Irp,
  1643. IN PIO_STACK_LOCATION IrpSp
  1644. )
  1645. /*++
  1646. Routine Description:
  1647. Arguments:
  1648. Irp - Pointer to I/O request packet
  1649. IrpSp - Pointer to the current stack location in the Irp.
  1650. Return Value:
  1651. NTSTATUS -- Indicates whether the request was successfully queued.
  1652. --*/
  1653. {
  1654. TDI_STATUS status;
  1655. TDI_REQUEST request;
  1656. PTCP_CONTEXT tcpContext;
  1657. PTDI_REQUEST_KERNEL_SENDDG datagramInformation;
  1658. ULONG bytesSent = 0;
  1659. PNDIS_BUFFER pNdisBuffer;
  1660. DEBUGMSG(DBG_TRACE && DBG_TDI && DBG_TX, (DTEXT("+UDPSendDatagram\n")));
  1661. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  1662. datagramInformation = (PTDI_REQUEST_KERNEL_SENDDG) & (IrpSp->Parameters);
  1663. ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE);
  1664. request.Handle.AddressHandle = tcpContext->Handle.AddressHandle;
  1665. request.RequestNotifyObject = TCPDataRequestComplete;
  1666. request.RequestContext = Irp;
  1667. IF_TCPDBG(TCP_DEBUG_SEND_DGRAM) {
  1668. TCPTRACE((
  1669. "UDPSendDatagram irp %lx sending %d bytes\n",
  1670. Irp,
  1671. datagramInformation->SendLength
  1672. ));
  1673. }
  1674. status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
  1675. if (NT_SUCCESS(status)) {
  1676. status = ConvertMdlToNdisBuffer(Irp, Irp->MdlAddress, &pNdisBuffer);
  1677. if (status == TDI_SUCCESS) {
  1678. status = TdiSendDatagram(
  1679. &request,
  1680. datagramInformation->SendDatagramInformation,
  1681. datagramInformation->SendLength,
  1682. &bytesSent,
  1683. pNdisBuffer
  1684. );
  1685. }
  1686. if (status == TDI_PENDING) {
  1687. return (status);
  1688. }
  1689. ASSERT(status != TDI_SUCCESS);
  1690. ASSERT(bytesSent == 0);
  1691. TCPTRACE((
  1692. "UDPSendDatagram - irp %lx send failed, status %lx\n",
  1693. Irp,
  1694. status
  1695. ));
  1696. TCPDataRequestComplete(Irp, status, bytesSent);
  1697. //
  1698. // return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING
  1699. //
  1700. return (TDI_PENDING);
  1701. }
  1702. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-UDPSendDatagram \n")));
  1703. return status;
  1704. } // UDPSendDatagram
  1705. NTSTATUS
  1706. UDPReceiveDatagram(
  1707. IN PIRP Irp,
  1708. IN PIO_STACK_LOCATION IrpSp
  1709. )
  1710. /*++
  1711. Routine Description:
  1712. Converts a TDI ReceiveDatagram IRP into a call to TdiReceiveDatagram.
  1713. Arguments:
  1714. Irp - Pointer to I/O request packet
  1715. IrpSp - Pointer to the current stack location in the Irp.
  1716. Return Value:
  1717. NTSTATUS -- Indicates whether the request was successful.
  1718. --*/
  1719. {
  1720. TDI_STATUS status;
  1721. TDI_REQUEST request;
  1722. PTCP_CONTEXT tcpContext;
  1723. PTDI_REQUEST_KERNEL_RECEIVEDG datagramInformation;
  1724. uint bytesReceived = 0;
  1725. PNDIS_BUFFER pNdisBuffer;
  1726. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+UDPReceiveDatagram \n")));
  1727. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  1728. datagramInformation = (PTDI_REQUEST_KERNEL_RECEIVEDG) & (IrpSp->Parameters);
  1729. ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE);
  1730. request.Handle.AddressHandle = tcpContext->Handle.AddressHandle;
  1731. request.RequestNotifyObject = TCPDataRequestComplete;
  1732. request.RequestContext = Irp;
  1733. IF_TCPDBG(TCP_DEBUG_RECEIVE_DGRAM) {
  1734. TCPTRACE((
  1735. "UDPReceiveDatagram: irp %lx receiveing %d bytes\n",
  1736. Irp,
  1737. datagramInformation->ReceiveLength
  1738. ));
  1739. }
  1740. status = TCPPrepareIrpForCancel(tcpContext, Irp, TCPCancelRequest);
  1741. if (NT_SUCCESS(status)) {
  1742. status = ConvertMdlToNdisBuffer(Irp, Irp->MdlAddress, &pNdisBuffer);
  1743. if (status == TDI_SUCCESS) {
  1744. status = TdiReceiveDatagram(
  1745. &request,
  1746. datagramInformation->ReceiveDatagramInformation,
  1747. datagramInformation->ReturnDatagramInformation,
  1748. datagramInformation->ReceiveLength,
  1749. &bytesReceived,
  1750. pNdisBuffer
  1751. );
  1752. }
  1753. if (status == TDI_PENDING) {
  1754. return (status);
  1755. }
  1756. ASSERT(status != TDI_SUCCESS);
  1757. ASSERT(bytesReceived == 0);
  1758. TCPTRACE((
  1759. "UDPReceiveDatagram: irp %lx send failed, status %lx\n",
  1760. Irp,
  1761. status
  1762. ));
  1763. TCPDataRequestComplete(Irp, status, bytesReceived);
  1764. //
  1765. // return PENDING because TCPPrepareIrpForCancel marks Irp as PENDING
  1766. //
  1767. return (TDI_PENDING);
  1768. }
  1769. return status;
  1770. } // UDPReceiveDatagram
  1771. NTSTATUS
  1772. TCPSetEventHandler(
  1773. IN PIRP Irp,
  1774. IN PIO_STACK_LOCATION IrpSp
  1775. )
  1776. /*++
  1777. Routine Description:
  1778. Converts a TDI SetEventHandler IRP into a call to TdiSetEventHandler.
  1779. Arguments:
  1780. Irp - Pointer to I/O request packet
  1781. IrpSp - Pointer to the current stack location in the Irp.
  1782. Return Value:
  1783. NTSTATUS -- Indicates whether the request was successful.
  1784. Notes:
  1785. This routine does not pend.
  1786. --*/
  1787. {
  1788. NTSTATUS status;
  1789. PTDI_REQUEST_KERNEL_SET_EVENT event;
  1790. PTCP_CONTEXT tcpContext;
  1791. PAGED_CODE();
  1792. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPSetEventHandler \n")));
  1793. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  1794. event = (PTDI_REQUEST_KERNEL_SET_EVENT) & (IrpSp->Parameters);
  1795. IF_TCPDBG(TCP_DEBUG_EVENT_HANDLER) {
  1796. TCPTRACE((
  1797. "TCPSetEventHandler: irp %lx event %lx handler %lx context %lx\n",
  1798. Irp,
  1799. event->EventType,
  1800. event->EventHandler,
  1801. event->EventContext
  1802. ));
  1803. }
  1804. status = TdiSetEvent(
  1805. tcpContext->Handle.AddressHandle,
  1806. event->EventType,
  1807. event->EventHandler,
  1808. event->EventContext
  1809. );
  1810. ASSERT(status != TDI_PENDING);
  1811. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPSetEventHandler \n")));
  1812. return (status);
  1813. } // TCPSetEventHandler
  1814. NTSTATUS
  1815. TCPQueryInformation(
  1816. IN PIRP Irp,
  1817. IN PIO_STACK_LOCATION IrpSp
  1818. )
  1819. /*++
  1820. Routine Description:
  1821. Converts a TDI QueryInformation IRP into a call to TdiQueryInformation.
  1822. Arguments:
  1823. Irp - Pointer to I/O request packet
  1824. IrpSp - Pointer to the current stack location in the Irp.
  1825. Return Value:
  1826. NTSTATUS -- Indicates whether the request was successful.
  1827. Notes:
  1828. --*/
  1829. {
  1830. TDI_REQUEST request;
  1831. TDI_STATUS status = STATUS_SUCCESS;
  1832. PTCP_CONTEXT tcpContext;
  1833. PTDI_REQUEST_KERNEL_QUERY_INFORMATION queryInformation;
  1834. uint isConn = FALSE;
  1835. uint dataSize = 0;
  1836. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPQueryInformation \n")));
  1837. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  1838. queryInformation = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)
  1839. & (IrpSp->Parameters);
  1840. request.RequestNotifyObject = TCPDataRequestComplete;
  1841. request.RequestContext = Irp;
  1842. switch (queryInformation->QueryType) {
  1843. case TDI_QUERY_BROADCAST_ADDRESS:
  1844. ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) ==
  1845. TDI_CONTROL_CHANNEL_FILE
  1846. );
  1847. request.Handle.ControlChannel = tcpContext->Handle.ControlChannel;
  1848. break;
  1849. case TDI_QUERY_PROVIDER_INFO:
  1850. //
  1851. // NetBT does this. Reinstate the ASSERT when it is fixed.
  1852. //
  1853. // ASSERT( ((int) IrpSp->FileObject->FsContext2) ==
  1854. // TDI_CONTROL_CHANNEL_FILE
  1855. // );
  1856. request.Handle.ControlChannel = tcpContext->Handle.ControlChannel;
  1857. break;
  1858. case TDI_QUERY_ADDRESS_INFO:
  1859. if (PtrToUlong(IrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE) {
  1860. //
  1861. // This is a TCP connection object.
  1862. //
  1863. isConn = TRUE;
  1864. request.Handle.ConnectionContext =
  1865. tcpContext->Handle.ConnectionContext;
  1866. } else {
  1867. //
  1868. // This is an address object
  1869. //
  1870. request.Handle.AddressHandle = tcpContext->Handle.AddressHandle;
  1871. }
  1872. break;
  1873. case TDI_QUERY_CONNECTION_INFO:
  1874. if (PtrToUlong(IrpSp->FileObject->FsContext2) != TDI_CONNECTION_FILE){
  1875. status = STATUS_INVALID_PARAMETER;
  1876. } else {
  1877. isConn = TRUE;
  1878. request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
  1879. }
  1880. break;
  1881. case TDI_QUERY_PROVIDER_STATISTICS:
  1882. //ASSERT(PtrToUlong(IrpSp->FileObject->FsContext2) ==
  1883. // TDI_CONTROL_CHANNEL_FILE
  1884. // );
  1885. request.Handle.ControlChannel = tcpContext->Handle.ControlChannel;
  1886. break;
  1887. default:
  1888. status = STATUS_NOT_IMPLEMENTED;
  1889. break;
  1890. }
  1891. if (NT_SUCCESS(status)) {
  1892. PNDIS_BUFFER pNdisBuffer;
  1893. //
  1894. // This request isn't cancellable, but we put it through
  1895. // the cancel path because it handles some checks for us
  1896. // and tracks the irp.
  1897. //
  1898. status = TCPPrepareIrpForCancel(tcpContext, Irp, NULL);
  1899. if (NT_SUCCESS(status)) {
  1900. dataSize = TCPGetMdlChainByteCount(Irp->MdlAddress);
  1901. status = ConvertMdlToNdisBuffer(Irp, Irp->MdlAddress, &pNdisBuffer);
  1902. if (status == TDI_SUCCESS) {
  1903. status = TdiQueryInformation(
  1904. &request,
  1905. queryInformation->QueryType,
  1906. pNdisBuffer,
  1907. &dataSize,
  1908. isConn
  1909. );
  1910. }
  1911. if (status != TDI_PENDING) {
  1912. IrpSp->Control &= ~SL_PENDING_RETURNED;
  1913. status = TCPDataRequestComplete(Irp, status, dataSize);
  1914. return (status);
  1915. }
  1916. return (STATUS_PENDING);
  1917. }
  1918. return (status);
  1919. }
  1920. Irp->IoStatus.Status = (NTSTATUS) status;
  1921. Irp->IoStatus.Information = 0;
  1922. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  1923. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPQueryInformation \n")));
  1924. return (status);
  1925. } // TCPQueryInformation
  1926. NTSTATUS
  1927. TCPQueryInformationExComplete(
  1928. void *Context,
  1929. unsigned int Status,
  1930. unsigned int ByteCount
  1931. )
  1932. /*++
  1933. Routine Description:
  1934. Completes a TdiQueryInformationEx request.
  1935. Arguments:
  1936. Context - A pointer to the IRP for this request.
  1937. Status - The final TDI status of the request.
  1938. ByteCount - Bytes returned in output buffer.
  1939. Return Value:
  1940. None.
  1941. Notes:
  1942. --*/
  1943. {
  1944. PTCP_QUERY_CONTEXT queryContext = (PTCP_QUERY_CONTEXT) Context;
  1945. ULONG bytesCopied;
  1946. DEBUGMSG(DBG_TRACE && DBG_TDI,
  1947. (DTEXT("+TCPQueryInformationExComplete(%x, %x, %d)\n"),
  1948. Context, Status, ByteCount));
  1949. if (NT_SUCCESS(Status)) {
  1950. //
  1951. // Copy the returned context to the input buffer.
  1952. //
  1953. #if defined(_WIN64)
  1954. if (IoIs32bitProcess(queryContext->Irp)) {
  1955. TdiCopyBufferToMdl(
  1956. &queryContext->QueryInformation.Context,
  1957. 0,
  1958. CONTEXT_SIZE,
  1959. queryContext->InputMdl,
  1960. FIELD_OFFSET(TCP_REQUEST_QUERY_INFORMATION_EX32, Context),
  1961. &bytesCopied
  1962. );
  1963. } else {
  1964. #endif // _WIN64
  1965. TdiCopyBufferToMdl(
  1966. &(queryContext->QueryInformation.Context),
  1967. 0,
  1968. CONTEXT_SIZE,
  1969. queryContext->InputMdl,
  1970. FIELD_OFFSET(TCP_REQUEST_QUERY_INFORMATION_EX, Context),
  1971. &bytesCopied
  1972. );
  1973. #if defined(_WIN64)
  1974. }
  1975. #endif // _WIN64
  1976. if (bytesCopied != CONTEXT_SIZE) {
  1977. Status = STATUS_INSUFFICIENT_RESOURCES;
  1978. ByteCount = 0;
  1979. }
  1980. }
  1981. //
  1982. // Unlock the user's buffers and free the MDLs describing them.
  1983. //
  1984. MmUnlockPages(queryContext->InputMdl);
  1985. IoFreeMdl(queryContext->InputMdl);
  1986. MmUnlockPages(queryContext->OutputMdl);
  1987. IoFreeMdl(queryContext->OutputMdl);
  1988. //
  1989. // Complete the request
  1990. //
  1991. Status = TCPDataRequestComplete(queryContext->Irp, Status, ByteCount);
  1992. CTEFreeMem(queryContext);
  1993. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPQueryInformationExComplete \n")));
  1994. return Status;
  1995. }
  1996. NTSTATUS
  1997. TCPQueryInformationEx(
  1998. IN PIRP Irp,
  1999. IN PIO_STACK_LOCATION IrpSp
  2000. )
  2001. /*++
  2002. Routine Description:
  2003. Converts a TDI QueryInformationEx IRP into a call to TdiQueryInformationEx.
  2004. Arguments:
  2005. Irp - Pointer to I/O request packet
  2006. IrpSp - Pointer to the current stack location in the Irp.
  2007. Return Value:
  2008. NTSTATUS -- Indicates whether the request was successful.
  2009. Notes:
  2010. --*/
  2011. {
  2012. TDI_REQUEST request;
  2013. TDI_STATUS status = STATUS_SUCCESS;
  2014. PTCP_CONTEXT tcpContext;
  2015. uint size;
  2016. PTCP_REQUEST_QUERY_INFORMATION_EX InputBuffer;
  2017. PVOID OutputBuffer;
  2018. PMDL inputMdl = NULL;
  2019. PMDL outputMdl = NULL;
  2020. ULONG InputBufferLength, OutputBufferLength;
  2021. PTCP_QUERY_CONTEXT queryContext;
  2022. BOOLEAN inputLocked = FALSE;
  2023. BOOLEAN outputLocked = FALSE;
  2024. #if defined(_WIN64)
  2025. BOOLEAN is32bitProcess = FALSE;
  2026. #endif // _WIN64
  2027. BOOLEAN inputBufferValid = FALSE;
  2028. ULONG AllocSize;
  2029. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPQueryInformationEx \n")));
  2030. IF_TCPDBG(TCP_DEBUG_INFO) {
  2031. TCPTRACE((
  2032. "QueryInformationEx starting - irp %lx fileobj %lx\n",
  2033. Irp,
  2034. IrpSp->FileObject
  2035. ));
  2036. }
  2037. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  2038. switch (PtrToUlong(IrpSp->FileObject->FsContext2)) {
  2039. case TDI_TRANSPORT_ADDRESS_FILE:
  2040. request.Handle.AddressHandle = tcpContext->Handle.AddressHandle;
  2041. break;
  2042. case TDI_CONNECTION_FILE:
  2043. request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
  2044. break;
  2045. case TDI_CONTROL_CHANNEL_FILE:
  2046. request.Handle.ControlChannel = tcpContext->Handle.ControlChannel;
  2047. break;
  2048. default:
  2049. ASSERT(0);
  2050. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  2051. Irp->IoStatus.Information = 0;
  2052. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  2053. return (STATUS_INVALID_PARAMETER);
  2054. }
  2055. InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
  2056. OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  2057. //
  2058. // Validate the input parameters
  2059. //
  2060. #if defined(_WIN64)
  2061. if (is32bitProcess = IoIs32bitProcess(Irp)) {
  2062. if (InputBufferLength >= sizeof(TCP_REQUEST_QUERY_INFORMATION_EX32) &&
  2063. InputBufferLength < MAXLONG) {
  2064. inputBufferValid = TRUE;
  2065. AllocSize =
  2066. FIELD_OFFSET(TCP_QUERY_CONTEXT, QueryInformation.Context) +
  2067. InputBufferLength -
  2068. FIELD_OFFSET(TCP_REQUEST_QUERY_INFORMATION_EX32, Context);
  2069. } else {
  2070. inputBufferValid = FALSE;
  2071. }
  2072. } else {
  2073. #endif // _WIN64
  2074. if (InputBufferLength >= sizeof(TCP_REQUEST_QUERY_INFORMATION_EX) &&
  2075. InputBufferLength < MAXLONG) {
  2076. inputBufferValid = TRUE;
  2077. AllocSize =
  2078. FIELD_OFFSET(TCP_QUERY_CONTEXT, QueryInformation) +
  2079. InputBufferLength;
  2080. } else {
  2081. inputBufferValid = FALSE;
  2082. }
  2083. #if defined(_WIN64)
  2084. }
  2085. #endif // _WIN64
  2086. if (inputBufferValid && OutputBufferLength != 0) {
  2087. OutputBuffer = Irp->UserBuffer;
  2088. InputBuffer =
  2089. (PTCP_REQUEST_QUERY_INFORMATION_EX)
  2090. IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  2091. queryContext = CTEAllocMem(AllocSize);
  2092. if (queryContext != NULL) {
  2093. status = TCPPrepareIrpForCancel(tcpContext, Irp, NULL);
  2094. if (!NT_SUCCESS(status)) {
  2095. CTEFreeMem(queryContext);
  2096. return (status);
  2097. }
  2098. //
  2099. // Allocate Mdls to describe the input and output buffers.
  2100. // Probe and lock the buffers.
  2101. //
  2102. try {
  2103. inputMdl = IoAllocateMdl(
  2104. InputBuffer,
  2105. InputBufferLength,
  2106. FALSE,
  2107. TRUE,
  2108. NULL
  2109. );
  2110. outputMdl = IoAllocateMdl(
  2111. OutputBuffer,
  2112. OutputBufferLength,
  2113. FALSE,
  2114. TRUE,
  2115. NULL
  2116. );
  2117. if ((inputMdl != NULL) && (outputMdl != NULL)) {
  2118. MmProbeAndLockPages(
  2119. inputMdl,
  2120. Irp->RequestorMode,
  2121. IoModifyAccess
  2122. );
  2123. inputLocked = TRUE;
  2124. MmProbeAndLockPages(
  2125. outputMdl,
  2126. Irp->RequestorMode,
  2127. IoWriteAccess
  2128. );
  2129. outputLocked = TRUE;
  2130. //
  2131. // Copy the input parameter to our pool block so
  2132. // TdiQueryInformationEx can manipulate it directly.
  2133. //
  2134. #if defined(_WIN64)
  2135. if (is32bitProcess) {
  2136. RtlCopyMemory(
  2137. &queryContext->QueryInformation,
  2138. InputBuffer,
  2139. FIELD_OFFSET(TCP_REQUEST_QUERY_INFORMATION_EX32, Context)
  2140. );
  2141. RtlCopyMemory(
  2142. &queryContext->QueryInformation.Context,
  2143. (PUCHAR)InputBuffer +
  2144. FIELD_OFFSET(TCP_REQUEST_QUERY_INFORMATION_EX32, Context),
  2145. InputBufferLength -
  2146. FIELD_OFFSET(TCP_REQUEST_QUERY_INFORMATION_EX32, Context)
  2147. );
  2148. } else {
  2149. #endif // _WIN64
  2150. RtlCopyMemory(
  2151. &queryContext->QueryInformation,
  2152. InputBuffer,
  2153. InputBufferLength
  2154. );
  2155. #if defined(_WIN64)
  2156. }
  2157. #endif // _WIN64
  2158. } else {
  2159. IF_TCPDBG(TCP_DEBUG_INFO) {
  2160. TCPTRACE(("QueryInfoEx: Couldn't allocate MDL\n"));
  2161. }
  2162. IrpSp->Control &= ~SL_PENDING_RETURNED;
  2163. status = STATUS_INSUFFICIENT_RESOURCES;
  2164. }
  2165. } except(EXCEPTION_EXECUTE_HANDLER) {
  2166. IF_TCPDBG(TCP_DEBUG_INFO) {
  2167. TCPTRACE((
  2168. "QueryInfoEx: exception copying input params %lx\n",
  2169. GetExceptionCode()
  2170. ));
  2171. }
  2172. status = GetExceptionCode();
  2173. }
  2174. if (NT_SUCCESS(status)) {
  2175. PNDIS_BUFFER OutputNdisBuf;
  2176. //
  2177. // It's finally time to do this thing.
  2178. //
  2179. size = TCPGetMdlChainByteCount(outputMdl);
  2180. queryContext->Irp = Irp;
  2181. queryContext->InputMdl = inputMdl;
  2182. queryContext->OutputMdl = outputMdl;
  2183. request.RequestNotifyObject = TCPQueryInformationExComplete;
  2184. request.RequestContext = queryContext;
  2185. status = ConvertMdlToNdisBuffer(Irp, outputMdl, &OutputNdisBuf);
  2186. if (status == TDI_SUCCESS) {
  2187. status = TdiQueryInformationEx(
  2188. &request,
  2189. &(queryContext->QueryInformation.ID),
  2190. OutputNdisBuf,
  2191. &size,
  2192. &(queryContext->QueryInformation.Context)
  2193. );
  2194. }
  2195. if (status != TDI_PENDING) {
  2196. // Since status is not pending, clear the
  2197. // control flag to keep IO verifier happy.
  2198. IrpSp->Control &= ~SL_PENDING_RETURNED;
  2199. status = TCPQueryInformationExComplete(
  2200. queryContext,
  2201. status,
  2202. size
  2203. );
  2204. return (status);
  2205. }
  2206. IF_TCPDBG(TCP_DEBUG_INFO) {
  2207. TCPTRACE((
  2208. "QueryInformationEx - pending irp %lx fileobj %lx\n",
  2209. Irp,
  2210. IrpSp->FileObject
  2211. ));
  2212. }
  2213. return (STATUS_PENDING);
  2214. }
  2215. //
  2216. // If we get here, something failed. Clean up.
  2217. //
  2218. if (inputMdl != NULL) {
  2219. if (inputLocked) {
  2220. MmUnlockPages(inputMdl);
  2221. }
  2222. IoFreeMdl(inputMdl);
  2223. }
  2224. if (outputMdl != NULL) {
  2225. if (outputLocked) {
  2226. MmUnlockPages(outputMdl);
  2227. }
  2228. IoFreeMdl(outputMdl);
  2229. }
  2230. CTEFreeMem(queryContext);
  2231. // Since status is not pending, clear the
  2232. // control flag to keep IO verifier happy.
  2233. IrpSp->Control &= ~SL_PENDING_RETURNED;
  2234. // This Irp may be in the process of cancellation
  2235. // get the real status used in irp completion
  2236. status = TCPDataRequestComplete(Irp, status, 0);
  2237. return (status);
  2238. } else {
  2239. IrpSp->Control &= ~SL_PENDING_RETURNED;
  2240. status = STATUS_INSUFFICIENT_RESOURCES;
  2241. IF_TCPDBG(TCP_DEBUG_INFO) {
  2242. TCPTRACE(("QueryInfoEx: Unable to allocate query context\n"));
  2243. }
  2244. }
  2245. } else {
  2246. status = STATUS_INVALID_PARAMETER;
  2247. IF_TCPDBG(TCP_DEBUG_INFO) {
  2248. TCPTRACE((
  2249. "QueryInfoEx: Bad buffer len, OBufLen %d, InBufLen %d\n",
  2250. OutputBufferLength, InputBufferLength
  2251. ));
  2252. }
  2253. }
  2254. IF_TCPDBG(TCP_DEBUG_INFO) {
  2255. TCPTRACE((
  2256. "QueryInformationEx complete - irp %lx, status %lx\n",
  2257. Irp,
  2258. status
  2259. ));
  2260. }
  2261. Irp->IoStatus.Status = (NTSTATUS) status;
  2262. Irp->IoStatus.Information = 0;
  2263. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  2264. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPQueryInformationEx \n")));
  2265. return (status);
  2266. }
  2267. NTSTATUS
  2268. TCPSetInformationEx(
  2269. IN PIRP Irp,
  2270. IN PIO_STACK_LOCATION IrpSp
  2271. )
  2272. /*++
  2273. Routine Description:
  2274. Converts a TDI SetInformationEx IRP into a call to TdiSetInformationEx.
  2275. Arguments:
  2276. Irp - Pointer to I/O request packet
  2277. IrpSp - Pointer to the current stack location in the Irp.
  2278. Return Value:
  2279. NTSTATUS -- Indicates whether the request was successful.
  2280. Notes:
  2281. This routine does not pend.
  2282. --*/
  2283. {
  2284. TDI_REQUEST request;
  2285. TDI_STATUS status;
  2286. PTCP_CONTEXT tcpContext;
  2287. PTCP_REQUEST_SET_INFORMATION_EX setInformation;
  2288. PAGED_CODE();
  2289. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPSetInformationEx \n")));
  2290. IF_TCPDBG(TCP_DEBUG_INFO) {
  2291. TCPTRACE((
  2292. "SetInformationEx - irp %lx fileobj %lx\n",
  2293. Irp,
  2294. IrpSp->FileObject
  2295. ));
  2296. }
  2297. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  2298. setInformation = (PTCP_REQUEST_SET_INFORMATION_EX)
  2299. Irp->AssociatedIrp.SystemBuffer;
  2300. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  2301. FIELD_OFFSET(TCP_REQUEST_SET_INFORMATION_EX, Buffer) ||
  2302. IrpSp->Parameters.DeviceIoControl.InputBufferLength -
  2303. FIELD_OFFSET(TCP_REQUEST_SET_INFORMATION_EX, Buffer) < setInformation->BufferSize) {
  2304. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  2305. Irp->IoStatus.Information = 0;
  2306. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  2307. return (STATUS_INVALID_PARAMETER);
  2308. }
  2309. switch (PtrToUlong(IrpSp->FileObject->FsContext2)) {
  2310. case TDI_TRANSPORT_ADDRESS_FILE:
  2311. request.Handle.AddressHandle = tcpContext->Handle.AddressHandle;
  2312. break;
  2313. case TDI_CONNECTION_FILE:
  2314. request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
  2315. break;
  2316. case TDI_CONTROL_CHANNEL_FILE:
  2317. request.Handle.ControlChannel = tcpContext->Handle.ControlChannel;
  2318. break;
  2319. default:
  2320. ASSERT(0);
  2321. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  2322. Irp->IoStatus.Information = 0;
  2323. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  2324. return (STATUS_INVALID_PARAMETER);
  2325. }
  2326. if (IrpSp->Parameters.DeviceIoControl.IoControlCode ==
  2327. IOCTL_TCP_WSH_SET_INFORMATION_EX) {
  2328. uint Entity;
  2329. Entity = setInformation->ID.toi_entity.tei_entity;
  2330. if ((Entity != CO_TL_ENTITY) && (Entity != CL_TL_ENTITY) ) {
  2331. Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
  2332. Irp->IoStatus.Information = 0;
  2333. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  2334. return (STATUS_ACCESS_DENIED);
  2335. }
  2336. }
  2337. status = TCPPrepareIrpForCancel(tcpContext, Irp, NULL);
  2338. if (NT_SUCCESS(status)) {
  2339. request.RequestNotifyObject = TCPDataRequestComplete;
  2340. request.RequestContext = Irp;
  2341. status = TdiSetInformationEx(
  2342. &request,
  2343. &(setInformation->ID),
  2344. &(setInformation->Buffer[0]),
  2345. setInformation->BufferSize
  2346. );
  2347. if (status != TDI_PENDING) {
  2348. DEBUGMSG(status != TDI_SUCCESS && DBG_ERROR && DBG_SETINFO,
  2349. (DTEXT("TCPSetInformationEx: TdiSetInformationEx failure %x\n"),
  2350. status));
  2351. IrpSp->Control &= ~SL_PENDING_RETURNED;
  2352. status = TCPDataRequestComplete(
  2353. Irp,
  2354. status,
  2355. 0
  2356. );
  2357. return (status);
  2358. }
  2359. IF_TCPDBG(TCP_DEBUG_INFO) {
  2360. TCPTRACE((
  2361. "SetInformationEx - pending irp %lx fileobj %lx\n",
  2362. Irp,
  2363. IrpSp->FileObject
  2364. ));
  2365. }
  2366. return (STATUS_PENDING);
  2367. }
  2368. IF_TCPDBG(TCP_DEBUG_INFO) {
  2369. TCPTRACE((
  2370. "SetInformationEx complete - irp %lx\n",
  2371. Irp
  2372. ));
  2373. }
  2374. //
  2375. // The irp has already been completed.
  2376. //
  2377. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPSetInformationEx \n")));
  2378. return (status);
  2379. }
  2380. NTSTATUS
  2381. TCPControlSecurityFilter(
  2382. IN PIRP Irp,
  2383. IN PIO_STACK_LOCATION IrpSp
  2384. )
  2385. /*++
  2386. Routine Description:
  2387. Processes a request to query or set the status of security filtering.
  2388. Arguments:
  2389. Irp - Pointer to I/O request packet
  2390. IrpSp - Pointer to the current stack location in the Irp.
  2391. Return Value:
  2392. NTSTATUS -- Indicates whether the request was successful.
  2393. Notes:
  2394. This routine does not pend.
  2395. --*/
  2396. {
  2397. PTCP_SECURITY_FILTER_STATUS request;
  2398. ULONG requestLength;
  2399. ULONG requestCode;
  2400. TDI_STATUS status = STATUS_SUCCESS;
  2401. PAGED_CODE();
  2402. Irp->IoStatus.Information = 0;
  2403. request = (PTCP_SECURITY_FILTER_STATUS) Irp->AssociatedIrp.SystemBuffer;
  2404. requestCode = IrpSp->Parameters.DeviceIoControl.IoControlCode;
  2405. if (requestCode == IOCTL_TCP_QUERY_SECURITY_FILTER_STATUS) {
  2406. requestLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  2407. if (requestLength < sizeof(TCP_SECURITY_FILTER_STATUS)) {
  2408. status = STATUS_INVALID_PARAMETER;
  2409. } else {
  2410. request->FilteringEnabled = IsSecurityFilteringEnabled();
  2411. Irp->IoStatus.Information = sizeof(TCP_SECURITY_FILTER_STATUS);
  2412. }
  2413. } else {
  2414. ASSERT(requestCode == IOCTL_TCP_SET_SECURITY_FILTER_STATUS);
  2415. requestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
  2416. if (requestLength < sizeof(TCP_SECURITY_FILTER_STATUS)) {
  2417. status = STATUS_INVALID_PARAMETER;
  2418. } else {
  2419. ControlSecurityFiltering(request->FilteringEnabled);
  2420. }
  2421. }
  2422. Irp->IoStatus.Status = status;
  2423. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  2424. return (status);
  2425. }
  2426. NTSTATUS
  2427. TCPProcessSecurityFilterRequest(
  2428. IN PIRP Irp,
  2429. IN PIO_STACK_LOCATION IrpSp
  2430. )
  2431. /*++
  2432. Routine Description:
  2433. Processes a request to add or delete a transport security filter.
  2434. Arguments:
  2435. Irp - Pointer to I/O request packet
  2436. IrpSp - Pointer to the current stack location in the Irp.
  2437. Return Value:
  2438. NTSTATUS -- Indicates whether the request was successful.
  2439. Notes:
  2440. This routine does not pend.
  2441. --*/
  2442. {
  2443. TCPSecurityFilterEntry *request;
  2444. ULONG requestLength;
  2445. ULONG i;
  2446. ULONG requestCode;
  2447. NTSTATUS status = STATUS_SUCCESS;
  2448. PAGED_CODE();
  2449. Irp->IoStatus.Information = 0;
  2450. request = (TCPSecurityFilterEntry *) Irp->AssociatedIrp.SystemBuffer;
  2451. requestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
  2452. requestCode = IrpSp->Parameters.DeviceIoControl.IoControlCode;
  2453. if (requestLength < sizeof(TCPSecurityFilterEntry)) {
  2454. status = STATUS_INVALID_PARAMETER;
  2455. } else {
  2456. if (requestCode == IOCTL_TCP_ADD_SECURITY_FILTER) {
  2457. status = AddValueSecurityFilter(
  2458. net_long(request->tsf_address),
  2459. request->tsf_protocol,
  2460. request->tsf_value
  2461. );
  2462. } else {
  2463. ASSERT(requestCode == IOCTL_TCP_DELETE_SECURITY_FILTER);
  2464. status = DeleteValueSecurityFilter(
  2465. net_long(request->tsf_address),
  2466. request->tsf_protocol,
  2467. request->tsf_value
  2468. );
  2469. }
  2470. }
  2471. Irp->IoStatus.Status = status;
  2472. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  2473. return (status);
  2474. }
  2475. NTSTATUS
  2476. TCPEnumerateSecurityFilter(
  2477. IN PIRP Irp,
  2478. IN PIO_STACK_LOCATION IrpSp
  2479. )
  2480. /*++
  2481. Routine Description:
  2482. Processes a request to enumerate a transport security filter list.
  2483. Arguments:
  2484. Irp - Pointer to I/O request packet
  2485. IrpSp - Pointer to the current stack location in the Irp.
  2486. Return Value:
  2487. NTSTATUS -- Indicates whether the request was successful.
  2488. Notes:
  2489. This routine does not pend.
  2490. --*/
  2491. {
  2492. TCPSecurityFilterEntry *request;
  2493. TCPSecurityFilterEnum *response;
  2494. ULONG requestLength, responseLength;
  2495. NTSTATUS status;
  2496. PAGED_CODE();
  2497. request = (TCPSecurityFilterEntry *) Irp->AssociatedIrp.SystemBuffer;
  2498. response = (TCPSecurityFilterEnum *) request;
  2499. requestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
  2500. responseLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  2501. if (requestLength < sizeof(TCPSecurityFilterEntry)) {
  2502. status = STATUS_INVALID_PARAMETER;
  2503. Irp->IoStatus.Information = 0;
  2504. } else if (responseLength < sizeof(TCPSecurityFilterEnum)) {
  2505. status = STATUS_BUFFER_TOO_SMALL;
  2506. Irp->IoStatus.Information = 0;
  2507. } else {
  2508. EnumerateSecurityFilters(
  2509. net_long(request->tsf_address),
  2510. request->tsf_protocol,
  2511. request->tsf_value,
  2512. (uchar *) (response + 1),
  2513. responseLength - sizeof(TCPSecurityFilterEnum),
  2514. &(response->tfe_entries_returned),
  2515. &(response->tfe_entries_available)
  2516. );
  2517. status = TDI_SUCCESS;
  2518. Irp->IoStatus.Information =
  2519. sizeof(TCPSecurityFilterEnum) +
  2520. (response->tfe_entries_returned * sizeof(TCPSecurityFilterEntry));
  2521. }
  2522. Irp->IoStatus.Status = status;
  2523. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  2524. return (status);
  2525. }
  2526. NTSTATUS
  2527. TCPReservePorts(
  2528. IN PIRP Irp,
  2529. IN PIO_STACK_LOCATION IrpSp
  2530. )
  2531. {
  2532. ULONG requestLength;
  2533. ULONG requestCode;
  2534. TDI_STATUS status = STATUS_SUCCESS;
  2535. PTCP_RESERVE_PORT_RANGE request;
  2536. CTELockHandle Handle;
  2537. //PAGED_CODE();
  2538. Irp->IoStatus.Information = 0;
  2539. request = (PTCP_RESERVE_PORT_RANGE) Irp->AssociatedIrp.SystemBuffer;
  2540. requestCode = IrpSp->Parameters.DeviceIoControl.IoControlCode;
  2541. requestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
  2542. if (requestLength < sizeof(TCP_RESERVE_PORT_RANGE)) {
  2543. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  2544. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  2545. return (STATUS_INVALID_PARAMETER);
  2546. }
  2547. if ((request->UpperRange >= request->LowerRange) &&
  2548. (request->LowerRange >= MIN_USER_PORT) &&
  2549. (request->UpperRange <= MaxUserPort)) {
  2550. if (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_TCP_RESERVE_PORT_RANGE) {
  2551. ReservedPortListEntry *ListEntry;
  2552. ListEntry = CTEAllocMem(sizeof(ReservedPortListEntry));
  2553. if (ListEntry) {
  2554. ListEntry->UpperRange = request->UpperRange;
  2555. ListEntry->LowerRange = request->LowerRange;
  2556. CTEGetLock(&AddrObjTableLock.Lock, &Handle);
  2557. ListEntry->next = PortRangeList;
  2558. PortRangeList = ListEntry;
  2559. CTEFreeLock(&AddrObjTableLock.Lock, Handle);
  2560. } else
  2561. status = STATUS_INSUFFICIENT_RESOURCES;
  2562. } else if (PortRangeList) {
  2563. //UNRESERVE
  2564. ReservedPortListEntry *ListEntry, *PrevEntry;
  2565. CTEGetLock(&AddrObjTableLock.Lock, &Handle);
  2566. ListEntry = PortRangeList;
  2567. PrevEntry = ListEntry;
  2568. status = STATUS_INVALID_PARAMETER;
  2569. while (ListEntry) {
  2570. if ((request->LowerRange <= ListEntry->LowerRange) &&
  2571. (request->UpperRange >= ListEntry->UpperRange)) {
  2572. //This list should be deleted.
  2573. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Deleting port range %d to %d\n", request->LowerRange, request->UpperRange));
  2574. if (PrevEntry == PortRangeList) {
  2575. PortRangeList = ListEntry->next;
  2576. CTEFreeMem(ListEntry);
  2577. ListEntry = PortRangeList;
  2578. } else {
  2579. PrevEntry->next = ListEntry->next;
  2580. CTEFreeMem(ListEntry);
  2581. ListEntry = PrevEntry->next;
  2582. }
  2583. status = STATUS_SUCCESS;
  2584. break;
  2585. } else {
  2586. PrevEntry = ListEntry;
  2587. ListEntry = ListEntry->next;
  2588. }
  2589. }
  2590. CTEFreeLock(&AddrObjTableLock.Lock, Handle);
  2591. }
  2592. } else
  2593. status = STATUS_INVALID_PARAMETER;
  2594. Irp->IoStatus.Status = status;
  2595. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  2596. return (status);
  2597. }
  2598. NTSTATUS
  2599. BlockTCPPorts(
  2600. IN PIRP Irp,
  2601. IN PIO_STACK_LOCATION IrpSp
  2602. )
  2603. {
  2604. TDI_STATUS status = STATUS_SUCCESS;
  2605. BOOLEAN ReservePorts;
  2606. ULONG NumberofPorts;
  2607. CTELockHandle Handle;
  2608. ULONG requestLength, responseLength;
  2609. PTCP_BLOCKPORTS_REQUEST request;
  2610. PULONG response;
  2611. Irp->IoStatus.Information = 0;
  2612. request = (PTCP_BLOCKPORTS_REQUEST) Irp->AssociatedIrp.SystemBuffer;
  2613. response = (PULONG) Irp->AssociatedIrp.SystemBuffer;
  2614. requestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
  2615. responseLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  2616. if (requestLength < sizeof(TCP_BLOCKPORTS_REQUEST)) {
  2617. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  2618. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  2619. return (STATUS_INVALID_PARAMETER);
  2620. }
  2621. ReservePorts = (uchar) request->ReservePorts;
  2622. if (ReservePorts) {
  2623. ushort LowerRange = MaxUserPort + 1;
  2624. ushort UpperRange = 65534;
  2625. uint NumberofPorts = request->NumberofPorts;
  2626. ReservedPortListEntry *tmpEntry = BlockedPortList, *ListEntry, *prevEntry = NULL;
  2627. AddrObj *ExistingAO;
  2628. uint PortsRemaining;
  2629. ushort Start;
  2630. ushort netStart;
  2631. ushort LeftEdge;
  2632. if (responseLength < sizeof(ULONG)) {
  2633. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  2634. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  2635. return (STATUS_INVALID_PARAMETER);
  2636. }
  2637. if ((UpperRange - LowerRange + 1) < (ushort) NumberofPorts) {
  2638. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  2639. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  2640. return (STATUS_INVALID_PARAMETER);
  2641. }
  2642. if (!NumberofPorts) {
  2643. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  2644. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  2645. return (STATUS_INVALID_PARAMETER);
  2646. }
  2647. CTEGetLock(&AddrObjTableLock.Lock, &Handle);
  2648. // its assumed that BlockedPortList is sorted in the order of port number range
  2649. Start = LowerRange;
  2650. PortsRemaining = NumberofPorts;
  2651. LeftEdge = Start;
  2652. while (Start < UpperRange) {
  2653. // check whether the current port lies in the reserved range
  2654. if ((tmpEntry) && ((Start >= tmpEntry->LowerRange) && (Start <= tmpEntry->UpperRange))) {
  2655. Start = tmpEntry->UpperRange + 1;
  2656. PortsRemaining = NumberofPorts;
  2657. LeftEdge = Start;
  2658. prevEntry = tmpEntry;
  2659. tmpEntry = tmpEntry->next;
  2660. } else {
  2661. // Start port doesn't lie in the current blocked range
  2662. // check whether somebody has done a bind to it
  2663. netStart = net_short(Start);
  2664. ExistingAO = FindAddrObjWithPort(netStart);
  2665. if (ExistingAO) {
  2666. Start++;
  2667. PortsRemaining = NumberofPorts;
  2668. LeftEdge = Start;
  2669. } else {
  2670. PortsRemaining--;
  2671. Start++;
  2672. if (!PortsRemaining) {
  2673. break;
  2674. }
  2675. }
  2676. }
  2677. }
  2678. // we have either found the range
  2679. // or we couldn't find a contiguous range
  2680. if (!PortsRemaining) {
  2681. // we found the range
  2682. // return the range
  2683. // LeftEdge <-> LeftEdge + NumberofPorts - 1
  2684. ListEntry = CTEAllocMem(sizeof(ReservedPortListEntry));
  2685. if (ListEntry) {
  2686. ListEntry->LowerRange = LeftEdge;
  2687. ListEntry->UpperRange = LeftEdge + NumberofPorts - 1;
  2688. // BlockedPortList is a sorted list
  2689. if (prevEntry) {
  2690. // insert it after prevEntry
  2691. ListEntry->next = prevEntry->next;
  2692. prevEntry->next = ListEntry;
  2693. } else {
  2694. // this has to be the first element in the list
  2695. ListEntry->next = BlockedPortList;
  2696. BlockedPortList = ListEntry;
  2697. }
  2698. Irp->IoStatus.Information = sizeof(ULONG);
  2699. *response = LeftEdge;
  2700. status = STATUS_SUCCESS;
  2701. } else {
  2702. // no resources
  2703. status = STATUS_INSUFFICIENT_RESOURCES;
  2704. }
  2705. } else {
  2706. // couldn't find the range
  2707. status = STATUS_INVALID_PARAMETER;
  2708. }
  2709. } else {
  2710. // unreserve the ports;
  2711. ReservedPortListEntry *CurrEntry = BlockedPortList;
  2712. ReservedPortListEntry *PrevEntry = NULL;
  2713. ULONG StartHandle;
  2714. StartHandle = request->StartHandle;
  2715. CTEGetLock(&AddrObjTableLock.Lock, &Handle);
  2716. status = STATUS_INVALID_PARAMETER;
  2717. while (CurrEntry) {
  2718. if (CurrEntry->LowerRange == StartHandle) {
  2719. // delete the entry
  2720. if (PrevEntry == NULL) {
  2721. // this is the first entry
  2722. BlockedPortList = CurrEntry->next;
  2723. } else {
  2724. // this is intermediate entry
  2725. PrevEntry->next = CurrEntry->next;
  2726. }
  2727. // free the current entry
  2728. CTEFreeMem(CurrEntry);
  2729. status = STATUS_SUCCESS;
  2730. break;
  2731. } else if (StartHandle > CurrEntry->UpperRange) {
  2732. PrevEntry = CurrEntry;
  2733. CurrEntry = CurrEntry->next;
  2734. } else {
  2735. // the list is sorted can't find the handle
  2736. break;
  2737. }
  2738. }
  2739. }
  2740. CTEFreeLock(&AddrObjTableLock.Lock, Handle);
  2741. Irp->IoStatus.Status = status;
  2742. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  2743. return (status);
  2744. }
  2745. NTSTATUS
  2746. TCPEnumerateConnectionList(
  2747. IN PIRP Irp,
  2748. IN PIO_STACK_LOCATION IrpSp
  2749. )
  2750. /*++
  2751. Routine Description:
  2752. Processes a request to enumerate the workstation connection list.
  2753. Arguments:
  2754. Irp - Pointer to I/O request packet
  2755. IrpSp - Pointer to the current stack location in the Irp.
  2756. Return Value:
  2757. NTSTATUS -- Indicates whether the request was successful.
  2758. Notes:
  2759. This routine does not pend.
  2760. --*/
  2761. {
  2762. TCPConnectionListEntry *request;
  2763. TCPConnectionListEnum *response;
  2764. ULONG requestLength, responseLength;
  2765. NTSTATUS status;
  2766. PAGED_CODE();
  2767. request = (TCPConnectionListEntry *) Irp->AssociatedIrp.SystemBuffer;
  2768. response = (TCPConnectionListEnum *) request;
  2769. requestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
  2770. responseLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  2771. if (responseLength < sizeof(TCPConnectionListEnum)) {
  2772. status = STATUS_BUFFER_TOO_SMALL;
  2773. Irp->IoStatus.Information = 0;
  2774. } else {
  2775. EnumerateConnectionList(
  2776. (uchar *) (response + 1),
  2777. responseLength - sizeof(TCPConnectionListEnum),
  2778. &(response->tce_entries_returned),
  2779. &(response->tce_entries_available)
  2780. );
  2781. status = TDI_SUCCESS;
  2782. Irp->IoStatus.Information =
  2783. sizeof(TCPConnectionListEnum) +
  2784. (response->tce_entries_returned * sizeof(TCPConnectionListEntry));
  2785. }
  2786. Irp->IoStatus.Status = status;
  2787. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  2788. return (status);
  2789. }
  2790. NTSTATUS
  2791. TCPCreate(
  2792. IN PDEVICE_OBJECT DeviceObject,
  2793. IN PIRP Irp,
  2794. IN PIO_STACK_LOCATION IrpSp
  2795. )
  2796. /*++
  2797. Routine Description:
  2798. Arguments:
  2799. DeviceObject - Pointer to the device object for this request.
  2800. Irp - Pointer to I/O request packet
  2801. IrpSp - Pointer to the current stack location in the Irp.
  2802. Return Value:
  2803. NTSTATUS -- Indicates whether the request was successfully queued.
  2804. --*/
  2805. {
  2806. TDI_REQUEST Request;
  2807. NTSTATUS status;
  2808. FILE_FULL_EA_INFORMATION *ea;
  2809. FILE_FULL_EA_INFORMATION UNALIGNED *targetEA;
  2810. PTCP_CONTEXT tcpContext;
  2811. uint protocol;
  2812. PAGED_CODE();
  2813. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPCreate \n")));
  2814. tcpContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(TCP_CONTEXT), 'cPCT');
  2815. if (tcpContext == NULL) {
  2816. return (STATUS_INSUFFICIENT_RESOURCES);
  2817. }
  2818. #if DBG
  2819. InitializeListHead(&(tcpContext->PendingIrpList));
  2820. InitializeListHead(&(tcpContext->CancelledIrpList));
  2821. #endif
  2822. tcpContext->ReferenceCount = 1; // put initial reference on open object
  2823. tcpContext->CancelIrps = FALSE;
  2824. KeInitializeEvent(&(tcpContext->CleanupEvent), SynchronizationEvent, FALSE);
  2825. CTEInitLock(&(tcpContext->EndpointLock));
  2826. tcpContext->Cleanup = FALSE;
  2827. ea = (PFILE_FULL_EA_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
  2828. //
  2829. // See if this is a Control Channel open.
  2830. //
  2831. if (!ea) {
  2832. IF_TCPDBG(TCP_DEBUG_OPEN) {
  2833. TCPTRACE((
  2834. "TCPCreate: Opening control channel for file object %lx\n",
  2835. IrpSp->FileObject
  2836. ));
  2837. }
  2838. tcpContext->Handle.ControlChannel = NULL;
  2839. IrpSp->FileObject->FsContext = tcpContext;
  2840. IrpSp->FileObject->FsContext2 = (PVOID) TDI_CONTROL_CHANNEL_FILE;
  2841. return (STATUS_SUCCESS);
  2842. }
  2843. //
  2844. // See if this is an Address Object open.
  2845. //
  2846. targetEA = FindEA(
  2847. ea,
  2848. TdiTransportAddress,
  2849. TDI_TRANSPORT_ADDRESS_LENGTH
  2850. );
  2851. if (targetEA != NULL) {
  2852. UCHAR optionsBuffer[3];
  2853. PUCHAR optionsPointer = optionsBuffer;
  2854. //Sanity check the address list. Should be bound by EaValueLength
  2855. {
  2856. TA_ADDRESS *tmpTA;
  2857. TRANSPORT_ADDRESS UNALIGNED *tmpTAList;
  2858. LONG Count = 1;
  2859. UINT tmpLen = 0;
  2860. UINT sizeof_TransportAddress = FIELD_OFFSET(TRANSPORT_ADDRESS, Address);
  2861. UINT sizeof_TAAddress = FIELD_OFFSET(TA_ADDRESS, Address);
  2862. if (ea->EaValueLength >= sizeof_TransportAddress + sizeof_TAAddress) {
  2863. tmpTAList = (TRANSPORT_ADDRESS UNALIGNED *)
  2864. & (targetEA->EaName[targetEA->EaNameLength + 1]);
  2865. Count = tmpTAList->TAAddressCount;
  2866. tmpLen = sizeof_TransportAddress;
  2867. tmpTA = (PTA_ADDRESS) tmpTAList->Address;
  2868. while (Count && ((tmpLen += sizeof_TAAddress) <= ea->EaValueLength)) {
  2869. tmpLen += tmpTA->AddressLength;
  2870. tmpTA = (PTA_ADDRESS) (tmpTA->Address + tmpTA->AddressLength);
  2871. Count--;
  2872. }
  2873. if (tmpLen > ea->EaValueLength) {
  2874. Count = 1;
  2875. }
  2876. }
  2877. if (Count) {
  2878. //Does not match what is stated in EA. Bail out
  2879. TCPTRACE(("TCPCreate: ea count and Ea Val length does not match for transport address's\n"));
  2880. status = STATUS_INVALID_EA_NAME;
  2881. ExFreePool(tcpContext);
  2882. ASSERT(status != TDI_PENDING);
  2883. return (status);
  2884. }
  2885. }
  2886. if (DeviceObject == TCPDeviceObject) {
  2887. protocol = PROTOCOL_TCP;
  2888. } else if (DeviceObject == UDPDeviceObject) {
  2889. protocol = PROTOCOL_UDP;
  2890. ASSERT(optionsPointer - optionsBuffer <= 3);
  2891. if (IsDHCPZeroAddress(
  2892. (TRANSPORT_ADDRESS UNALIGNED *)
  2893. & (targetEA->EaName[targetEA->EaNameLength + 1])
  2894. )) {
  2895. #if ACC
  2896. if (!IsAdminIoRequest(Irp, IrpSp)) {
  2897. ExFreePool(tcpContext);
  2898. return (STATUS_ACCESS_DENIED);
  2899. }
  2900. #endif
  2901. *optionsPointer = TDI_ADDRESS_OPTION_DHCP;
  2902. optionsPointer++;
  2903. }
  2904. ASSERT(optionsPointer - optionsBuffer <= 3);
  2905. } else {
  2906. //
  2907. // This is a raw ip open
  2908. //
  2909. #if ACC
  2910. //
  2911. // Only administrators can create raw addresses
  2912. // unless this is allowed through registry
  2913. //
  2914. if (!AllowUserRawAccess && !IsAdminIoRequest(Irp, IrpSp)) {
  2915. ExFreePool(tcpContext);
  2916. return (STATUS_ACCESS_DENIED);
  2917. }
  2918. #endif // ACC
  2919. protocol = RawExtractProtocolNumber(
  2920. &(IrpSp->FileObject->FileName)
  2921. );
  2922. if ((protocol == 0xFFFFFFFF) || (protocol == PROTOCOL_TCP)) {
  2923. ExFreePool(tcpContext);
  2924. return (STATUS_INVALID_PARAMETER);
  2925. }
  2926. }
  2927. if ((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
  2928. (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)
  2929. ) {
  2930. *optionsPointer = TDI_ADDRESS_OPTION_REUSE;
  2931. optionsPointer++;
  2932. }
  2933. *optionsPointer = TDI_OPTION_EOL;
  2934. IF_TCPDBG(TCP_DEBUG_OPEN) {
  2935. TCPTRACE((
  2936. "TCPCreate: Opening address for file object %lx\n",
  2937. IrpSp->FileObject
  2938. ));
  2939. }
  2940. #if ACC
  2941. Request.RequestContext = Irp;
  2942. #endif
  2943. status = TdiOpenAddress(
  2944. &Request,
  2945. (TRANSPORT_ADDRESS UNALIGNED *)
  2946. & (targetEA->EaName[targetEA->EaNameLength + 1]),
  2947. protocol,
  2948. optionsBuffer
  2949. );
  2950. if (NT_SUCCESS(status)) {
  2951. //
  2952. // Save off the handle to the AO passed back.
  2953. //
  2954. tcpContext->Handle.AddressHandle = Request.Handle.AddressHandle;
  2955. IrpSp->FileObject->FsContext = tcpContext;
  2956. IrpSp->FileObject->FsContext2 =
  2957. (PVOID) TDI_TRANSPORT_ADDRESS_FILE;
  2958. } else {
  2959. ExFreePool(tcpContext);
  2960. //TCPTRACE(("TdiOpenAddress failed, status %lx\n", status));
  2961. if (status == STATUS_ADDRESS_ALREADY_EXISTS) {
  2962. status = STATUS_SHARING_VIOLATION;
  2963. }
  2964. }
  2965. ASSERT(status != TDI_PENDING);
  2966. return (status);
  2967. }
  2968. //
  2969. // See if this is a Connection Object open.
  2970. //
  2971. targetEA = FindEA(
  2972. ea,
  2973. TdiConnectionContext,
  2974. TDI_CONNECTION_CONTEXT_LENGTH
  2975. );
  2976. if (targetEA != NULL) {
  2977. //
  2978. // This is an open of a Connection Object.
  2979. //
  2980. if (DeviceObject == TCPDeviceObject) {
  2981. IF_TCPDBG(TCP_DEBUG_OPEN) {
  2982. TCPTRACE((
  2983. "TCPCreate: Opening connection for file object %lx\n",
  2984. IrpSp->FileObject
  2985. ));
  2986. }
  2987. if (targetEA->EaValueLength < sizeof(CONNECTION_CONTEXT)) {
  2988. status = STATUS_EA_LIST_INCONSISTENT;
  2989. } else {
  2990. status = TdiOpenConnection(
  2991. &Request,
  2992. *((CONNECTION_CONTEXT UNALIGNED *)
  2993. & (targetEA->EaName[targetEA->EaNameLength + 1]))
  2994. );
  2995. }
  2996. if (NT_SUCCESS(status)) {
  2997. //
  2998. // Save off the Connection Context passed back.
  2999. //
  3000. tcpContext->Handle.ConnectionContext =
  3001. Request.Handle.ConnectionContext;
  3002. IrpSp->FileObject->FsContext = tcpContext;
  3003. IrpSp->FileObject->FsContext2 =
  3004. (PVOID) TDI_CONNECTION_FILE;
  3005. tcpContext->Conn = (UINT_PTR) Request.RequestContext;
  3006. } else {
  3007. ExFreePool(tcpContext);
  3008. TCPTRACE((
  3009. "TdiOpenConnection failed, status %lx\n",
  3010. status
  3011. ));
  3012. }
  3013. } else {
  3014. TCPTRACE((
  3015. "TCP: TdiOpenConnection issued on UDP device!\n"
  3016. ));
  3017. status = STATUS_INVALID_DEVICE_REQUEST;
  3018. ExFreePool(tcpContext);
  3019. }
  3020. ASSERT(status != TDI_PENDING);
  3021. return (status);
  3022. }
  3023. TCPTRACE(("TCPCreate: didn't find any useful ea's\n"));
  3024. status = STATUS_INVALID_EA_NAME;
  3025. ExFreePool(tcpContext);
  3026. ASSERT(status != TDI_PENDING);
  3027. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPCreate \n")));
  3028. return (status);
  3029. } // TCPCreate
  3030. #if ACC
  3031. BOOLEAN
  3032. IsAdminIoRequest(
  3033. PIRP Irp,
  3034. PIO_STACK_LOCATION IrpSp
  3035. )
  3036. /*++
  3037. Routine Description:
  3038. (Lifted from AFD - AfdPerformSecurityCheck)
  3039. Compares security context of the endpoint creator to that
  3040. of the administrator and local system.
  3041. Arguments:
  3042. Irp - Pointer to I/O request packet.
  3043. IrpSp - pointer to the IO stack location to use for this request.
  3044. Return Value:
  3045. TRUE - the socket creator has admin or local system privilige
  3046. FALSE - the socket creator is just a plain user
  3047. --*/
  3048. {
  3049. BOOLEAN accessGranted;
  3050. PACCESS_STATE accessState;
  3051. PIO_SECURITY_CONTEXT securityContext;
  3052. PPRIVILEGE_SET privileges = NULL;
  3053. ACCESS_MASK grantedAccess;
  3054. PGENERIC_MAPPING GenericMapping;
  3055. ACCESS_MASK AccessMask = GENERIC_ALL;
  3056. NTSTATUS Status;
  3057. //
  3058. // Enable access to all the globally defined SIDs
  3059. //
  3060. GenericMapping = IoGetFileObjectGenericMapping();
  3061. RtlMapGenericMask(&AccessMask, GenericMapping);
  3062. securityContext = IrpSp->Parameters.Create.SecurityContext;
  3063. accessState = securityContext->AccessState;
  3064. SeLockSubjectContext(&accessState->SubjectSecurityContext);
  3065. accessGranted = SeAccessCheck(
  3066. TcpAdminSecurityDescriptor,
  3067. &accessState->SubjectSecurityContext,
  3068. TRUE,
  3069. AccessMask,
  3070. 0,
  3071. &privileges,
  3072. IoGetFileObjectGenericMapping(),
  3073. (KPROCESSOR_MODE) ((IrpSp->Flags & SL_FORCE_ACCESS_CHECK)
  3074. ? UserMode
  3075. : Irp->RequestorMode),
  3076. &grantedAccess,
  3077. &Status
  3078. );
  3079. if (privileges) {
  3080. (VOID) SeAppendPrivileges(
  3081. accessState,
  3082. privileges
  3083. );
  3084. SeFreePrivileges(privileges);
  3085. }
  3086. if (accessGranted) {
  3087. accessState->PreviouslyGrantedAccess |= grantedAccess;
  3088. accessState->RemainingDesiredAccess &= ~(grantedAccess | MAXIMUM_ALLOWED);
  3089. ASSERT(NT_SUCCESS(Status));
  3090. } else {
  3091. ASSERT(!NT_SUCCESS(Status));
  3092. }
  3093. SeUnlockSubjectContext(&accessState->SubjectSecurityContext);
  3094. return accessGranted;
  3095. }
  3096. #endif
  3097. void
  3098. TCPCloseObjectComplete(
  3099. void *Context,
  3100. unsigned int Status,
  3101. unsigned int UnUsed
  3102. )
  3103. /*++
  3104. Routine Description:
  3105. Completes a TdiCloseConnectoin or TdiCloseAddress request.
  3106. Arguments:
  3107. Context - A pointer to the IRP for this request.
  3108. Status - The final status of the operation.
  3109. UnUsed - An unused parameter
  3110. Return Value:
  3111. None.
  3112. Notes:
  3113. --*/
  3114. {
  3115. KIRQL oldIrql;
  3116. PIRP irp;
  3117. PIO_STACK_LOCATION irpSp;
  3118. PTCP_CONTEXT tcpContext;
  3119. CTELockHandle CancelHandle;
  3120. UNREFERENCED_PARAMETER(UnUsed);
  3121. irp = (PIRP) Context;
  3122. irpSp = IoGetCurrentIrpStackLocation(irp);
  3123. tcpContext = (PTCP_CONTEXT) irpSp->FileObject->FsContext;
  3124. irp->IoStatus.Status = Status;
  3125. IF_TCPDBG(TCP_DEBUG_CLEANUP) {
  3126. TCPTRACE((
  3127. "TCPCloseObjectComplete on file object %lx\n",
  3128. irpSp->FileObject
  3129. ));
  3130. }
  3131. CTEGetLock(&tcpContext->EndpointLock, &CancelHandle);
  3132. ASSERT(tcpContext->ReferenceCount > 0);
  3133. ASSERT(tcpContext->CancelIrps);
  3134. //
  3135. // Remove the initial reference that was put on by TCPCreate.
  3136. //
  3137. ASSERT(tcpContext->ReferenceCount > 0);
  3138. IF_TCPDBG(TCP_DEBUG_IRP) {
  3139. TCPTRACE((
  3140. "TCPCloseObjectComplete: irp %lx fileobj %lx refcnt dec to %u\n",
  3141. irp,
  3142. irpSp,
  3143. tcpContext->ReferenceCount - 1
  3144. ));
  3145. }
  3146. if (--(tcpContext->ReferenceCount) == 0) {
  3147. IF_TCPDBG(TCP_DEBUG_CANCEL) {
  3148. ASSERT(IsListEmpty(&(tcpContext->CancelledIrpList)));
  3149. ASSERT(IsListEmpty(&(tcpContext->PendingIrpList)));
  3150. }
  3151. //
  3152. // Free the EndpointLock before setting CleanupEvent,
  3153. // as tcpContext can go away as soon as the event is signalled.
  3154. //
  3155. CTEFreeLock(&tcpContext->EndpointLock, CancelHandle);
  3156. KeSetEvent(&(tcpContext->CleanupEvent), 0, FALSE);
  3157. return;
  3158. }
  3159. CTEFreeLock(&tcpContext->EndpointLock, CancelHandle);
  3160. return;
  3161. } // TCPCleanupComplete
  3162. NTSTATUS
  3163. TCPCleanup(
  3164. IN PDEVICE_OBJECT DeviceObject,
  3165. IN PIRP Irp,
  3166. IN PIO_STACK_LOCATION IrpSp
  3167. )
  3168. /*++
  3169. Routine Description:
  3170. Cancels all outstanding Irps on a TDI object by calling the close
  3171. routine for the object. It then waits for them to be completed
  3172. before returning.
  3173. Arguments:
  3174. Irp - Pointer to I/O request packet
  3175. IrpSp - Pointer to the current stack location in the Irp.
  3176. Return Value:
  3177. NTSTATUS -- Indicates whether the request was successfully queued.
  3178. Notes:
  3179. This routine blocks, but does not pend.
  3180. --*/
  3181. {
  3182. KIRQL oldIrql;
  3183. PIRP cancelIrp = NULL;
  3184. PTCP_CONTEXT tcpContext;
  3185. NTSTATUS status;
  3186. TDI_REQUEST request;
  3187. CTELockHandle CancelHandle;
  3188. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPCleanup \n")));
  3189. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  3190. CTEGetLock(&tcpContext->EndpointLock, &CancelHandle);
  3191. tcpContext->CancelIrps = TRUE;
  3192. KeResetEvent(&(tcpContext->CleanupEvent));
  3193. if (tcpContext->Cleanup) {
  3194. #if DBG_VALIDITY_CHECK
  3195. //Double cleanup call!!!
  3196. DbgBreakPoint();
  3197. #endif
  3198. } else {
  3199. tcpContext->Cleanup = TRUE;
  3200. tcpContext->Irp = Irp;
  3201. }
  3202. CTEFreeLock(&tcpContext->EndpointLock, CancelHandle);
  3203. //
  3204. // Now call the TDI close routine for this object to force all of its Irps
  3205. // to complete.
  3206. //
  3207. request.RequestNotifyObject = TCPCloseObjectComplete;
  3208. request.RequestContext = Irp;
  3209. switch (PtrToUlong(IrpSp->FileObject->FsContext2)) {
  3210. case TDI_TRANSPORT_ADDRESS_FILE:
  3211. IF_TCPDBG(TCP_DEBUG_CLOSE) {
  3212. TCPTRACE((
  3213. "TCPCleanup: Closing address object on file object %lx\n",
  3214. IrpSp->FileObject
  3215. ));
  3216. }
  3217. request.Handle.AddressHandle = tcpContext->Handle.AddressHandle;
  3218. status = TdiCloseAddress(&request);
  3219. break;
  3220. case TDI_CONNECTION_FILE:
  3221. IF_TCPDBG(TCP_DEBUG_CLOSE) {
  3222. TCPTRACE((
  3223. "TCPCleanup: Closing Connection object on file object %lx\n",
  3224. IrpSp->FileObject
  3225. ));
  3226. }
  3227. request.Handle.ConnectionContext = tcpContext->Handle.ConnectionContext;
  3228. status = TdiCloseConnection(&request);
  3229. break;
  3230. case TDI_CONTROL_CHANNEL_FILE:
  3231. IF_TCPDBG(TCP_DEBUG_CLOSE) {
  3232. TCPTRACE((
  3233. "TCPCleanup: Closing Control Channel object on file object %lx\n",
  3234. IrpSp->FileObject
  3235. ));
  3236. }
  3237. status = STATUS_SUCCESS;
  3238. break;
  3239. default:
  3240. //
  3241. // This should never happen.
  3242. //
  3243. ASSERT(FALSE);
  3244. CTEGetLock(&tcpContext->EndpointLock, &CancelHandle);
  3245. tcpContext->CancelIrps = FALSE;
  3246. CTEFreeLock(&tcpContext->EndpointLock, CancelHandle);
  3247. return (STATUS_INVALID_PARAMETER);
  3248. }
  3249. if (status != TDI_PENDING) {
  3250. TCPCloseObjectComplete(Irp, status, 0);
  3251. }
  3252. IF_TCPDBG(TCP_DEBUG_CLEANUP) {
  3253. TCPTRACE((
  3254. "TCPCleanup: waiting for completion of Irps on file object %lx\n",
  3255. IrpSp->FileObject
  3256. ));
  3257. }
  3258. status = KeWaitForSingleObject(
  3259. &(tcpContext->CleanupEvent),
  3260. UserRequest,
  3261. KernelMode,
  3262. FALSE,
  3263. NULL
  3264. );
  3265. ASSERT(NT_SUCCESS(status));
  3266. IF_TCPDBG(TCP_DEBUG_CLEANUP) {
  3267. TCPTRACE((
  3268. "TCPCleanup: Wait on file object %lx finished\n",
  3269. IrpSp->FileObject
  3270. ));
  3271. }
  3272. //
  3273. // The cleanup Irp will be completed by the dispatch routine.
  3274. //
  3275. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPCleanup \n")));
  3276. return (Irp->IoStatus.Status);
  3277. } // TCPCleanup
  3278. NTSTATUS
  3279. TCPClose(
  3280. IN PIRP Irp,
  3281. IN PIO_STACK_LOCATION IrpSp
  3282. )
  3283. /*++
  3284. Routine Description:
  3285. Dispatch routine for MJ_CLOSE IRPs. Performs final cleanup of the
  3286. open endpoint.
  3287. Arguments:
  3288. Irp - Pointer to I/O request packet
  3289. IrpSp - Pointer to the current stack location in the Irp.
  3290. Return Value:
  3291. NTSTATUS -- Indicates whether the request was successfully queued.
  3292. Notes:
  3293. This request does not pend.
  3294. --*/
  3295. {
  3296. PTCP_CONTEXT tcpContext;
  3297. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPClose \n")));
  3298. tcpContext = (PTCP_CONTEXT) IrpSp->FileObject->FsContext;
  3299. #if DBG
  3300. IF_TCPDBG(TCP_DEBUG_CANCEL) {
  3301. KIRQL oldIrql;
  3302. IoAcquireCancelSpinLock(&oldIrql);
  3303. ASSERT(tcpContext->ReferenceCount == 0);
  3304. ASSERT(IsListEmpty(&(tcpContext->PendingIrpList)));
  3305. ASSERT(IsListEmpty(&(tcpContext->CancelledIrpList)));
  3306. IoReleaseCancelSpinLock(oldIrql);
  3307. }
  3308. #endif // DBG
  3309. IF_TCPDBG(TCP_DEBUG_CLOSE) {
  3310. TCPTRACE(("TCPClose on file object %lx\n", IrpSp->FileObject));
  3311. }
  3312. ExFreePool(tcpContext);
  3313. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPClose \n")));
  3314. return (STATUS_SUCCESS);
  3315. } // TCPClose
  3316. NTSTATUS
  3317. TCPDispatchDeviceControl(
  3318. IN PIRP Irp,
  3319. IN PIO_STACK_LOCATION IrpSp
  3320. )
  3321. /*++
  3322. Routine Description:
  3323. Arguments:
  3324. Irp - Pointer to I/O request packet
  3325. IrpSp - Pointer to the current stack location in the Irp.
  3326. Return Value:
  3327. NTSTATUS -- Indicates whether the request was successfully queued.
  3328. --*/
  3329. {
  3330. NTSTATUS status;
  3331. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("+TCPDispatchDeviceControl \n")));
  3332. //
  3333. // Set this in advance. Any IOCTL dispatch routine that cares about it
  3334. // will modify it itself.
  3335. //
  3336. Irp->IoStatus.Information = 0;
  3337. switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
  3338. case IOCTL_TCP_RCVWND:
  3339. // Allow this IOCTL to set the window size only
  3340. // if there are no established connections
  3341. if (TStats.ts_currestab == 0) {
  3342. PULONG request = Irp->AssociatedIrp.SystemBuffer;
  3343. ULONG tmp = DefaultRcvWin;
  3344. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) {
  3345. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  3346. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  3347. return STATUS_INVALID_PARAMETER;
  3348. }
  3349. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof(ULONG)) {
  3350. if ((LONG)*request > 0) {
  3351. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"setting global rcv window %d\n", *request));
  3352. if (!(TcpHostOpts & TCP_FLAG_WS) && *request > 0xFFFF) {
  3353. DefaultRcvWin = 0xFFFF;
  3354. } else {
  3355. uint rcvwinscale=0;
  3356. //
  3357. // Check for valid window size
  3358. // taking care of window scaling option
  3359. //
  3360. while ((rcvwinscale < TCP_MAX_WINSHIFT) &&
  3361. ((TCP_MAXWIN << rcvwinscale) < (LONG)*request)) {
  3362. rcvwinscale++;
  3363. }
  3364. if (rcvwinscale == TCP_MAX_WINSHIFT) {
  3365. DefaultRcvWin = TCP_MAXWIN << rcvwinscale;
  3366. } else {
  3367. DefaultRcvWin = *request;
  3368. }
  3369. }
  3370. }
  3371. }
  3372. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"returning global rcv window %d\n", *request));
  3373. *request = tmp;
  3374. status = STATUS_SUCCESS;
  3375. Irp->IoStatus.Information = sizeof(ULONG);
  3376. break;
  3377. } else {
  3378. status = STATUS_CONNECTION_ACTIVE;
  3379. }
  3380. case IOCTL_TCP_FINDTCB:
  3381. {
  3382. IPAddr Src;
  3383. IPAddr Dest;
  3384. ushort DestPort;
  3385. ushort SrcPort;
  3386. PTCP_FINDTCB_REQUEST request;
  3387. PTCP_FINDTCB_RESPONSE TCBInfo;
  3388. ULONG InfoBufferLen;
  3389. if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  3390. sizeof(TCP_FINDTCB_REQUEST)
  3391. )
  3392. ||
  3393. (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  3394. sizeof(TCP_FINDTCB_RESPONSE))
  3395. ) {
  3396. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  3397. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  3398. return STATUS_INVALID_PARAMETER;
  3399. }
  3400. request = Irp->AssociatedIrp.SystemBuffer;
  3401. Src = request->Src;
  3402. Dest = request->Dest;
  3403. DestPort = request->DestPort;
  3404. SrcPort = request->SrcPort;
  3405. InfoBufferLen = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  3406. TCBInfo = Irp->AssociatedIrp.SystemBuffer;
  3407. NdisZeroMemory(TCBInfo, sizeof(TCP_FINDTCB_RESPONSE));
  3408. status = GetTCBInfo(TCBInfo, Dest, Src, DestPort, SrcPort);
  3409. if (status == STATUS_SUCCESS) {
  3410. Irp->IoStatus.Information = sizeof(TCP_FINDTCB_RESPONSE);
  3411. } else {
  3412. Irp->IoStatus.Information = 0;
  3413. }
  3414. Irp->IoStatus.Status = status;
  3415. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  3416. return status;
  3417. break;
  3418. }
  3419. case IOCTL_TCP_QUERY_INFORMATION_EX:
  3420. return (TCPQueryInformationEx(Irp, IrpSp));
  3421. break;
  3422. case IOCTL_TCP_WSH_SET_INFORMATION_EX:
  3423. case IOCTL_TCP_SET_INFORMATION_EX:
  3424. return (TCPSetInformationEx(Irp, IrpSp));
  3425. break;
  3426. case IOCTL_TCP_QUERY_SECURITY_FILTER_STATUS:
  3427. case IOCTL_TCP_SET_SECURITY_FILTER_STATUS:
  3428. return (TCPControlSecurityFilter(Irp, IrpSp));
  3429. break;
  3430. case IOCTL_TCP_ADD_SECURITY_FILTER:
  3431. case IOCTL_TCP_DELETE_SECURITY_FILTER:
  3432. return (TCPProcessSecurityFilterRequest(Irp, IrpSp));
  3433. break;
  3434. case IOCTL_TCP_ENUMERATE_SECURITY_FILTER:
  3435. return (TCPEnumerateSecurityFilter(Irp, IrpSp));
  3436. break;
  3437. case IOCTL_TCP_RESERVE_PORT_RANGE:
  3438. case IOCTL_TCP_UNRESERVE_PORT_RANGE:
  3439. return (TCPReservePorts(Irp, IrpSp));
  3440. break;
  3441. case IOCTL_TCP_BLOCK_PORTS:
  3442. return (BlockTCPPorts(Irp, IrpSp));
  3443. break;
  3444. default:
  3445. status = STATUS_NOT_IMPLEMENTED;
  3446. break;
  3447. }
  3448. Irp->IoStatus.Status = status;
  3449. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  3450. DEBUGMSG(DBG_TRACE && DBG_TDI, (DTEXT("-TCPDispatchDeviceControl \n")));
  3451. return status;
  3452. } // TCPDispatchDeviceControl
  3453. #if TRACE_EVENT
  3454. NTSTATUS
  3455. TCPEventTraceControl(
  3456. IN PDEVICE_OBJECT DeviceObject,
  3457. IN PIRP Irp
  3458. )
  3459. /*++
  3460. Routine Description:
  3461. This routine handles any WMI requests for enabling/disabling Event
  3462. tracing.
  3463. Arguments:
  3464. DeviceObject - Context for the activity.
  3465. Irp - The device control argument block.
  3466. Return Value:
  3467. Status is returned.
  3468. --*/
  3469. {
  3470. NTSTATUS status;
  3471. ULONG retSize;
  3472. if (DeviceObject != IPDeviceObject) {
  3473. PIO_STACK_LOCATION irpSp;
  3474. ULONG bufferSize;
  3475. PVOID buffer;
  3476. irpSp = IoGetCurrentIrpStackLocation(Irp);
  3477. bufferSize = irpSp->Parameters.WMI.BufferSize;
  3478. buffer = irpSp->Parameters.WMI.Buffer;
  3479. switch (irpSp->MinorFunction) {
  3480. case IRP_MN_SET_TRACE_NOTIFY:
  3481. if (bufferSize < sizeof(PTDI_DATA_REQUEST_NOTIFY_ROUTINE)) {
  3482. status = STATUS_BUFFER_TOO_SMALL;
  3483. } else {
  3484. TCPCPHandlerRoutine = (PTDI_DATA_REQUEST_NOTIFY_ROUTINE)
  3485. * ((PVOID *) buffer);
  3486. status = STATUS_SUCCESS;
  3487. }
  3488. retSize = 0;
  3489. break;
  3490. case IRP_MN_REGINFO:
  3491. {
  3492. //
  3493. // Stub for now. TCP can register its Guids with WMI here
  3494. //
  3495. PWMIREGINFOW WmiRegInfo;
  3496. ULONG WmiRegInfoSize = sizeof(WMIREGINFOW);
  3497. status = STATUS_SUCCESS;
  3498. if (bufferSize >= WmiRegInfoSize) {
  3499. WmiRegInfo = (PWMIREGINFOW) buffer;
  3500. RtlZeroMemory(WmiRegInfo, WmiRegInfoSize);
  3501. WmiRegInfo->BufferSize = WmiRegInfoSize;
  3502. retSize = WmiRegInfoSize;
  3503. } else {
  3504. *(ULONG *) buffer = WmiRegInfoSize;
  3505. retSize = sizeof(ULONG);
  3506. }
  3507. break;
  3508. }
  3509. default:
  3510. TCPTRACE((
  3511. "TCPDispatch: Irp %lx unsupported minor function 0x%lx\n",
  3512. irpSp,
  3513. irpSp->MinorFunction
  3514. ));
  3515. retSize = 0;
  3516. status = STATUS_INVALID_DEVICE_REQUEST;
  3517. }
  3518. } else {
  3519. status = STATUS_INVALID_DEVICE_REQUEST;
  3520. retSize = 0;
  3521. }
  3522. Irp->IoStatus.Status = status;
  3523. Irp->IoStatus.Information = retSize;
  3524. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  3525. return status;
  3526. }
  3527. #endif
  3528. NTSTATUS
  3529. TCPDispatchInternalDeviceControl(
  3530. IN PDEVICE_OBJECT DeviceObject,
  3531. IN PIRP Irp
  3532. )
  3533. /*++
  3534. Routine Description:
  3535. This is the dispatch routine for Internal Device Control IRPs.
  3536. This is the hot path for kernel-mode clients.
  3537. Arguments:
  3538. DeviceObject - Pointer to device object for target device
  3539. Irp - Pointer to I/O request packet
  3540. Return Value:
  3541. NTSTATUS -- Indicates whether the request was successfully queued.
  3542. --*/
  3543. {
  3544. PIO_STACK_LOCATION irpSp;
  3545. NTSTATUS status;
  3546. DEBUGMSG(DBG_TRACE && DBG_TDI && DBG_VERBOSE,
  3547. (DTEXT("+TCPDispatchInternalDeviceControl \n")));
  3548. #if IPMCAST
  3549. if (DeviceObject == IpMcastDeviceObject) {
  3550. return IpMcastDispatch(DeviceObject,
  3551. Irp);
  3552. }
  3553. #endif
  3554. if (DeviceObject != IPDeviceObject) {
  3555. irpSp = IoGetCurrentIrpStackLocation(Irp);
  3556. if (PtrToUlong(irpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE) {
  3557. //
  3558. // Send and receive are the performance path, so check for them
  3559. // right away.
  3560. //
  3561. if (irpSp->MinorFunction == TDI_SEND) {
  3562. return (TCPSendData(Irp, irpSp));
  3563. }
  3564. if (irpSp->MinorFunction == TDI_RECEIVE) {
  3565. return (TCPReceiveData(Irp, irpSp));
  3566. }
  3567. switch (irpSp->MinorFunction) {
  3568. case TDI_ASSOCIATE_ADDRESS:
  3569. status = TCPAssociateAddress(Irp, irpSp);
  3570. Irp->IoStatus.Status = status;
  3571. Irp->IoStatus.Information = 0;
  3572. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  3573. return (status);
  3574. case TDI_DISASSOCIATE_ADDRESS:
  3575. return (TCPDisassociateAddress(Irp, irpSp));
  3576. case TDI_CONNECT:
  3577. return (TCPConnect(Irp, irpSp));
  3578. case TDI_DISCONNECT:
  3579. return (TCPDisconnect(Irp, irpSp));
  3580. case TDI_LISTEN:
  3581. return (TCPListen(Irp, irpSp));
  3582. case TDI_ACCEPT:
  3583. return (TCPAccept(Irp, irpSp));
  3584. default:
  3585. break;
  3586. }
  3587. //
  3588. // Fall through.
  3589. //
  3590. } else if (PtrToUlong(irpSp->FileObject->FsContext2) ==
  3591. TDI_TRANSPORT_ADDRESS_FILE
  3592. ) {
  3593. if (irpSp->MinorFunction == TDI_SEND) {
  3594. return (UDPSendData(Irp, irpSp));
  3595. }
  3596. if (irpSp->MinorFunction == TDI_SEND_DATAGRAM) {
  3597. return (UDPSendDatagram(Irp, irpSp));
  3598. }
  3599. if (irpSp->MinorFunction == TDI_RECEIVE_DATAGRAM) {
  3600. return (UDPReceiveDatagram(Irp, irpSp));
  3601. }
  3602. if (irpSp->MinorFunction == TDI_SET_EVENT_HANDLER) {
  3603. status = TCPSetEventHandler(Irp, irpSp);
  3604. Irp->IoStatus.Status = status;
  3605. Irp->IoStatus.Information = 0;
  3606. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  3607. return (status);
  3608. }
  3609. if (irpSp->MinorFunction == TDI_CONNECT) {
  3610. return (TCPConnect(Irp, irpSp));
  3611. }
  3612. if (irpSp->MinorFunction == TDI_DISCONNECT) {
  3613. return (TCPDisconnect(Irp, irpSp));
  3614. }
  3615. //
  3616. // Fall through.
  3617. //
  3618. }
  3619. ASSERT(
  3620. (PtrToUlong(irpSp->FileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE)
  3621. ||
  3622. (PtrToUlong(irpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE)
  3623. ||
  3624. (PtrToUlong(irpSp->FileObject->FsContext2) == TDI_CONTROL_CHANNEL_FILE)
  3625. );
  3626. //
  3627. // These functions are common to all endpoint types.
  3628. //
  3629. switch (irpSp->MinorFunction) {
  3630. case TDI_QUERY_INFORMATION:
  3631. return (TCPQueryInformation(Irp, irpSp));
  3632. case TDI_SET_INFORMATION:
  3633. case TDI_ACTION:
  3634. TCPTRACE((
  3635. "TCP: Call to unimplemented TDI function 0x%x\n",
  3636. irpSp->MinorFunction
  3637. ));
  3638. status = STATUS_NOT_IMPLEMENTED;
  3639. break;
  3640. default:
  3641. TCPTRACE((
  3642. "TCP: call to invalid TDI function 0x%x\n",
  3643. irpSp->MinorFunction
  3644. ));
  3645. status = STATUS_INVALID_DEVICE_REQUEST;
  3646. }
  3647. ASSERT(status != TDI_PENDING);
  3648. Irp->IoStatus.Status = status;
  3649. Irp->IoStatus.Information = 0;
  3650. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  3651. return status;
  3652. }
  3653. DEBUGMSG(DBG_TRACE && DBG_TDI && DBG_VERBOSE, (DTEXT("-TCPDispatchInternalDeviceControl \n")));
  3654. return (IPDispatch(DeviceObject, Irp));
  3655. }
  3656. NTSTATUS
  3657. TCPDispatch(
  3658. IN PDEVICE_OBJECT DeviceObject,
  3659. IN PIRP Irp
  3660. )
  3661. /*++
  3662. Routine Description:
  3663. This is the generic dispatch routine for TCP/UDP/RawIP.
  3664. Arguments:
  3665. DeviceObject - Pointer to device object for target device
  3666. Irp - Pointer to I/O request packet
  3667. Return Value:
  3668. NTSTATUS -- Indicates whether the request was successfully queued.
  3669. --*/
  3670. {
  3671. PIO_STACK_LOCATION irpSp;
  3672. NTSTATUS status;
  3673. DEBUGMSG(DBG_TRACE && DBG_TDI && DBG_VERBOSE, (DTEXT("+TCPDispatch(%x, %x) \n"), DeviceObject, Irp));
  3674. #if IPMCAST
  3675. if (DeviceObject == IpMcastDeviceObject) {
  3676. return IpMcastDispatch(DeviceObject,
  3677. Irp);
  3678. }
  3679. #endif
  3680. if (DeviceObject != IPDeviceObject) {
  3681. #if MILLEN
  3682. // Ensure that the driver context is zero'd for our use.
  3683. Irp->Tail.Overlay.DriverContext[0] = NULL;
  3684. #endif // MILLEN
  3685. Irp->IoStatus.Information = 0;
  3686. irpSp = IoGetCurrentIrpStackLocation(Irp);
  3687. ASSERT(irpSp->MajorFunction != IRP_MJ_INTERNAL_DEVICE_CONTROL);
  3688. switch (irpSp->MajorFunction) {
  3689. case IRP_MJ_CREATE:
  3690. status = TCPCreate(DeviceObject, Irp, irpSp);
  3691. break;
  3692. case IRP_MJ_CLEANUP:
  3693. status = TCPCleanup(DeviceObject, Irp, irpSp);
  3694. break;
  3695. case IRP_MJ_CLOSE:
  3696. status = TCPClose(Irp, irpSp);
  3697. break;
  3698. case IRP_MJ_DEVICE_CONTROL:
  3699. status = TdiMapUserRequest(DeviceObject, Irp, irpSp);
  3700. if (status == STATUS_SUCCESS) {
  3701. return (TCPDispatchInternalDeviceControl(DeviceObject, Irp));
  3702. }
  3703. if (irpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_TDI_QUERY_DIRECT_SEND_HANDLER) {
  3704. PULONG_PTR EntryPoint;
  3705. EntryPoint = irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  3706. try {
  3707. // Type3InputBuffer must be writeable by the caller.
  3708. if (Irp->RequestorMode != KernelMode) {
  3709. ProbeForWrite(EntryPoint,
  3710. sizeof(ULONG_PTR),
  3711. PROBE_ALIGNMENT(ULONG_PTR));
  3712. }
  3713. *EntryPoint = (ULONG_PTR) TCPSendData;
  3714. status = STATUS_SUCCESS;
  3715. }
  3716. except(EXCEPTION_EXECUTE_HANDLER) {
  3717. status = STATUS_INVALID_PARAMETER;
  3718. }
  3719. break;
  3720. }
  3721. return (TCPDispatchDeviceControl(
  3722. Irp,
  3723. IoGetCurrentIrpStackLocation(Irp)
  3724. ));
  3725. break;
  3726. case IRP_MJ_QUERY_SECURITY:
  3727. //
  3728. // This is generated on Raw endpoints. We don't do anything
  3729. // for it.
  3730. //
  3731. status = STATUS_INVALID_DEVICE_REQUEST;
  3732. break;
  3733. case IRP_MJ_PNP:
  3734. status = TCPDispatchPnPPower(Irp, irpSp);
  3735. break;
  3736. #if TRACE_EVENT
  3737. case IRP_MJ_SYSTEM_CONTROL:
  3738. return TCPEventTraceControl(DeviceObject, Irp);
  3739. #endif
  3740. case IRP_MJ_WRITE:
  3741. case IRP_MJ_READ:
  3742. default:
  3743. TCPTRACE((
  3744. "TCPDispatch: Irp %lx unsupported major function 0x%lx\n",
  3745. irpSp,
  3746. irpSp->MajorFunction
  3747. ));
  3748. status = STATUS_INVALID_DEVICE_REQUEST;
  3749. break;
  3750. }
  3751. ASSERT(status != TDI_PENDING);
  3752. Irp->IoStatus.Status = status;
  3753. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  3754. return status;
  3755. }
  3756. return (IPDispatch(DeviceObject, Irp));
  3757. } // TCPDispatch
  3758. //
  3759. // Private utility functions
  3760. //
  3761. FILE_FULL_EA_INFORMATION UNALIGNED *
  3762. FindEA(
  3763. PFILE_FULL_EA_INFORMATION StartEA,
  3764. CHAR * TargetName,
  3765. USHORT TargetNameLength
  3766. )
  3767. /*++
  3768. Routine Description:
  3769. Parses and extended attribute list for a given target attribute.
  3770. Arguments:
  3771. StartEA - the first extended attribute in the list.
  3772. TargetName - the name of the target attribute.
  3773. TargetNameLength - the length of the name of the target attribute.
  3774. Return Value:
  3775. A pointer to the requested attribute or NULL if the target wasn't found.
  3776. --*/
  3777. {
  3778. USHORT i;
  3779. BOOLEAN found;
  3780. FILE_FULL_EA_INFORMATION UNALIGNED *CurrentEA;
  3781. PAGED_CODE();
  3782. do {
  3783. found = TRUE;
  3784. CurrentEA = StartEA;
  3785. StartEA = (FILE_FULL_EA_INFORMATION *) ((PUCHAR) StartEA + CurrentEA->NextEntryOffset);
  3786. if (CurrentEA->EaNameLength != TargetNameLength) {
  3787. continue;
  3788. }
  3789. for (i = 0; i < CurrentEA->EaNameLength; i++) {
  3790. if (CurrentEA->EaName[i] == TargetName[i]) {
  3791. continue;
  3792. }
  3793. found = FALSE;
  3794. break;
  3795. }
  3796. if (found) {
  3797. return (CurrentEA);
  3798. }
  3799. } while (CurrentEA->NextEntryOffset != 0);
  3800. return (NULL);
  3801. }
  3802. BOOLEAN
  3803. IsDHCPZeroAddress(
  3804. TRANSPORT_ADDRESS UNALIGNED * AddrList
  3805. )
  3806. /*++
  3807. Routine Description:
  3808. Checks a TDI IP address list for an address from DHCP binding
  3809. to the IP address zero. Normally, binding to zero means wildcard.
  3810. For DHCP, it really means bind to an interface with an address of
  3811. zero. This semantic is flagged by a special value in an unused
  3812. portion of the address structure (ie. this is a kludge).
  3813. Arguments:
  3814. AddrList - The TDI transport address list passed in the create IRP.
  3815. Return Value:
  3816. TRUE if the first IP address found had the flag set. FALSE otherwise.
  3817. --*/
  3818. {
  3819. int i; // Index variable.
  3820. TA_ADDRESS *CurrentAddr; // Address we're examining and may use.
  3821. // First, verify that someplace in Address is an address we can use.
  3822. CurrentAddr = (PTA_ADDRESS) AddrList->Address;
  3823. for (i = 0; i < AddrList->TAAddressCount; i++) {
  3824. if (CurrentAddr->AddressType == TDI_ADDRESS_TYPE_IP) {
  3825. if (CurrentAddr->AddressLength == TDI_ADDRESS_LENGTH_IP) {
  3826. TDI_ADDRESS_IP UNALIGNED *ValidAddr;
  3827. ValidAddr = (TDI_ADDRESS_IP UNALIGNED *) CurrentAddr->Address;
  3828. if (*((ULONG UNALIGNED *) ValidAddr->sin_zero) == 0x12345678) {
  3829. return TRUE;
  3830. }
  3831. } else {
  3832. return FALSE; // Wrong length for address.
  3833. }
  3834. } else {
  3835. CurrentAddr = (PTA_ADDRESS)
  3836. (CurrentAddr->Address + CurrentAddr->AddressLength);
  3837. }
  3838. }
  3839. return FALSE; // Didn't find a match.
  3840. }
  3841. ULONG
  3842. TCPGetMdlChainByteCount(
  3843. PMDL Mdl
  3844. )
  3845. /*++
  3846. Routine Description:
  3847. Sums the byte counts of each MDL in a chain.
  3848. Arguments:
  3849. Mdl - Pointer to the MDL chain to sum.
  3850. Return Value:
  3851. The byte count of the MDL chain.
  3852. --*/
  3853. {
  3854. ULONG count = 0;
  3855. while (Mdl != NULL) {
  3856. count += MmGetMdlByteCount(Mdl);
  3857. Mdl = Mdl->Next;
  3858. }
  3859. return (count);
  3860. }
  3861. ULONG
  3862. TCPGetNdisBufferChainByteCount(
  3863. PNDIS_BUFFER pBuffer
  3864. )
  3865. {
  3866. ULONG cb = 0;
  3867. while (pBuffer != NULL) {
  3868. cb += NdisBufferLength(pBuffer);
  3869. pBuffer = NDIS_BUFFER_LINKAGE(pBuffer);
  3870. }
  3871. return cb;
  3872. }
  3873. ULONG
  3874. RawExtractProtocolNumber(
  3875. IN PUNICODE_STRING FileName
  3876. )
  3877. /*++
  3878. Routine Description:
  3879. Extracts the protocol number from the file object name.
  3880. Arguments:
  3881. FileName - The unicode file name.
  3882. Return Value:
  3883. The protocol number or 0xFFFFFFFF on error.
  3884. --*/
  3885. {
  3886. PWSTR name;
  3887. UNICODE_STRING unicodeString;
  3888. USHORT length;
  3889. ULONG protocol;
  3890. NTSTATUS status;
  3891. PAGED_CODE();
  3892. name = FileName->Buffer;
  3893. if (FileName->Length <
  3894. (sizeof(OBJ_NAME_PATH_SEPARATOR) + sizeof(WCHAR))
  3895. ) {
  3896. return (0xFFFFFFFF);
  3897. }
  3898. //
  3899. // Step over separator
  3900. //
  3901. if (*name++ != OBJ_NAME_PATH_SEPARATOR) {
  3902. return (0xFFFFFFFF);
  3903. }
  3904. if (*name == UNICODE_NULL) {
  3905. return (0xFFFFFFFF);
  3906. }
  3907. //
  3908. // Convert the remaining name into a number.
  3909. //
  3910. RtlInitUnicodeString(&unicodeString, name);
  3911. status = RtlUnicodeStringToInteger(
  3912. &unicodeString,
  3913. 10,
  3914. &protocol
  3915. );
  3916. if (!NT_SUCCESS(status)) {
  3917. return (0xFFFFFFFF);
  3918. }
  3919. if (protocol > 255) {
  3920. return (0xFFFFFFFF);
  3921. }
  3922. return (protocol);
  3923. }