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.

748 lines
23 KiB

  1. /*++
  2. Copyright (c) 1989-1993 Microsoft Corporation
  3. Module Name:
  4. Tdiout.c
  5. Abstract:
  6. This file represents the TDI interface on the bottom edge of NBT.
  7. The procedures herein conform to the TDI I/F spec. and then convert
  8. the information to NT specific Irps etc. This implementation can be
  9. changed out to run on another OS.
  10. Author:
  11. Jim Stewart (Jimst) 10-2-92
  12. Revision History:
  13. --*/
  14. #include "precomp.h" // procedure headings
  15. // function prototypes for completion routines used in this file
  16. NTSTATUS
  17. TdiSendDatagramCompletion(
  18. IN PDEVICE_OBJECT DeviceObject,
  19. IN PIRP pIrp,
  20. IN PVOID pSendbufferMdl
  21. );
  22. NTSTATUS
  23. TcpConnectComplete(
  24. IN PDEVICE_OBJECT DeviceObject,
  25. IN PIRP pIrp,
  26. IN PVOID pContext
  27. );
  28. NTSTATUS
  29. TcpDisconnectComplete(
  30. IN PDEVICE_OBJECT DeviceObject,
  31. IN PIRP pIrp,
  32. IN PVOID pContext
  33. );
  34. NTSTATUS
  35. SendSessionCompletionRoutine(
  36. IN PDEVICE_OBJECT DeviceObject,
  37. IN PIRP pIrp,
  38. IN PVOID pContext
  39. );
  40. // DEBUG
  41. VOID
  42. CheckIrpList(
  43. );
  44. //----------------------------------------------------------------------------
  45. NTSTATUS
  46. TdiSendDatagram(
  47. IN PTDI_REQUEST pRequestInfo,
  48. IN PTDI_CONNECTION_INFORMATION pSendDgramInfo,
  49. IN ULONG SendLength,
  50. OUT PULONG pSentSize,
  51. IN tDGRAM_SEND_TRACKING *pDgramTracker
  52. )
  53. /*++
  54. Routine Description:
  55. This routine sends a datagram to the transport
  56. Arguments:
  57. pSendBuffer - this is really an Mdl in NT land. It must be tacked on
  58. the end of the Mdl created for the Nbt datagram header.
  59. Return Value:
  60. The function value is the status of the operation.
  61. --*/
  62. {
  63. NTSTATUS status;
  64. PIRP pRequestIrp;
  65. PMDL pMdl;
  66. PDEVICE_OBJECT pDeviceObject;
  67. PFILE_OBJECT pFileObject;
  68. PVOID pCompletionRoutine;
  69. tBUFFER *pSendBuffer = &pDgramTracker->SendBuffer;
  70. // get an Irp to send the message in
  71. pFileObject = (PFILE_OBJECT)pRequestInfo->Handle.AddressHandle;
  72. pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
  73. status = GetIrp(&pRequestIrp); // get an Irp from the list
  74. if (NT_SUCCESS(status))
  75. {
  76. pRequestIrp->CancelRoutine = NULL;
  77. // set up the completion routine passed in from Udp Send using the APC
  78. // fields in the Irp that would normally be used to complete the request
  79. // back to the client - although we are really the client here so we can
  80. // use these fields our self!
  81. pRequestIrp->Overlay.AsynchronousParameters.UserApcRoutine =
  82. (PIO_APC_ROUTINE)pRequestInfo->RequestNotifyObject;
  83. pRequestIrp->Overlay.AsynchronousParameters.UserApcContext = (PVOID)pRequestInfo->RequestContext;
  84. // Allocate a MDL and set the head sizes correctly
  85. if (!(pMdl = IoAllocateMdl (pSendBuffer->pDgramHdr, pSendBuffer->HdrLength, FALSE, FALSE, NULL)))
  86. {
  87. REMOVE_FROM_LIST(&pRequestIrp->ThreadListEntry);
  88. ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
  89. &pRequestIrp->Tail.Overlay.ListEntry,
  90. &NbtConfig.LockInfo.SpinLock);
  91. status = STATUS_INSUFFICIENT_RESOURCES;
  92. }
  93. }
  94. else
  95. {
  96. IF_DBG(NBT_DEBUG_TDIOUT)
  97. KdPrint(("Nbt.TdiSendDatagram: Failed to get an Irp"));
  98. }
  99. // tack the client's send buffer (MDL) onto the end of the datagram header
  100. // Mdl, and then pass the irp on downward to the transport
  101. if (NT_SUCCESS(status) && pSendBuffer->pBuffer) {
  102. pMdl->Next = IoAllocateMdl (pSendBuffer->pBuffer, pSendBuffer->Length, FALSE, FALSE, NULL);
  103. if (pMdl->Next == NULL) {
  104. REMOVE_FROM_LIST(&pRequestIrp->ThreadListEntry);
  105. ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
  106. &pRequestIrp->Tail.Overlay.ListEntry,
  107. &NbtConfig.LockInfo.SpinLock);
  108. status = STATUS_INSUFFICIENT_RESOURCES;
  109. IoFreeMdl(pMdl);
  110. pMdl = NULL;
  111. }
  112. }
  113. if (!NT_SUCCESS(status))
  114. {
  115. if (pRequestInfo->RequestNotifyObject) // call the completion routine (if there is one)
  116. {
  117. NBT_DEREFERENCE_DEVICE (pDgramTracker->pDeviceContext, REF_DEV_UDP_SEND, FALSE);
  118. (*((NBT_COMPLETION)pRequestInfo->RequestNotifyObject))
  119. ((PVOID)pRequestInfo->RequestContext,
  120. STATUS_INSUFFICIENT_RESOURCES,
  121. 0L);
  122. }
  123. return(STATUS_PENDING); // so the Irp is not completed twice.
  124. }
  125. // Map the pages in memory...
  126. ASSERT(!pSendBuffer->pBuffer || pMdl->Next);
  127. MmBuildMdlForNonPagedPool(pMdl);
  128. if (pMdl->Next) {
  129. MmBuildMdlForNonPagedPool(pMdl->Next);
  130. }
  131. pCompletionRoutine = TdiSendDatagramCompletion;
  132. // store some context stuff in the Irp stack so we can call the completion
  133. // routine set by the Udpsend code...
  134. TdiBuildSendDatagram (pRequestIrp,
  135. pDeviceObject,
  136. pFileObject,
  137. pCompletionRoutine,
  138. (PVOID)pMdl->Next, // The completion routine will know that we have allocated an extra MDL
  139. pMdl,
  140. SendLength,
  141. pSendDgramInfo);
  142. CHECK_COMPLETION(pRequestIrp);
  143. status = IoCallDriver(pDeviceObject,pRequestIrp);
  144. *pSentSize = SendLength; // Fill in the SentSize
  145. // The transport always completes the IRP, so as long as the irp made it
  146. // to the transport it got completed. The return code from the transport
  147. // does not indicate if the irp was completed or not. The real status
  148. // of the operation is in the Irp Iostatus return code.
  149. // What we need to do is make sure NBT does not complete the irp AND the
  150. // transport complete the Irp. Therefore this routine returns
  151. // status pending if the Irp was passed to the transport, regardless of
  152. // the return code from the transport. This return code signals the caller
  153. // that the irp will be completed via the completion routine and the
  154. // actual status of the send can be found in the Irpss IoStatus.Status
  155. // variable.
  156. //
  157. // If the Caller of this routine gets a bad return code, they can assume
  158. // that this routine failed to give the Irp to the transport and it
  159. // is safe for them to complete the Irp themselves.
  160. //
  161. // If the Completion routine is set to null, then there is no danger
  162. // of the irp completing twice and this routine will return the transport
  163. // return code in that case.
  164. if (pRequestInfo->RequestNotifyObject)
  165. {
  166. return(STATUS_PENDING);
  167. }
  168. else
  169. {
  170. return(status);
  171. }
  172. }
  173. //----------------------------------------------------------------------------
  174. NTSTATUS
  175. TdiSendDatagramCompletion(
  176. IN PDEVICE_OBJECT DeviceObject,
  177. IN PIRP pIrp,
  178. IN PVOID pSendbufferMdl
  179. )
  180. /*++
  181. Routine Description:
  182. This routine handles the completion of a datagram send to the transport.
  183. It must call the client completion routine and free the Irp and Mdl.
  184. Arguments:
  185. Return Value:
  186. NTSTATUS - success or not
  187. --*/
  188. {
  189. KIRQL OldIrq;
  190. tDGRAM_SEND_TRACKING *pTracker = pIrp->Overlay.AsynchronousParameters.UserApcContext;
  191. tDEVICECONTEXT *pDeviceContext;
  192. // check for a completion routine of the clients to call...
  193. if (pIrp->Overlay.AsynchronousParameters.UserApcRoutine)
  194. {
  195. //
  196. // The Tracker can be free'ed in the routine below, so save the Device ptr
  197. //
  198. pDeviceContext = pTracker->pDeviceContext;
  199. (*((NBT_COMPLETION)pIrp->Overlay.AsynchronousParameters.UserApcRoutine))
  200. ((PVOID)pIrp->Overlay.AsynchronousParameters.UserApcContext,
  201. pIrp->IoStatus.Status,
  202. (ULONG)pIrp->IoStatus.Information); // sent length
  203. NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_UDP_SEND, FALSE);
  204. }
  205. // Don't depend on pIrp->MdlAddress->Next which may occassionally changed by others
  206. ASSERT((PMDL)pSendbufferMdl == pIrp->MdlAddress->Next);
  207. if (pSendbufferMdl) {
  208. IoFreeMdl((PMDL)pSendbufferMdl);
  209. }
  210. // deallocate the MDL.. this is done by the IO subsystem in IoCompleteRequest
  211. pIrp->MdlAddress->Next = NULL;
  212. IoFreeMdl(pIrp->MdlAddress);
  213. REMOVE_FROM_LIST(&pIrp->ThreadListEntry);
  214. ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
  215. &pIrp->Tail.Overlay.ListEntry,
  216. &NbtConfig.LockInfo.SpinLock);
  217. // return this status to stop the IO subsystem from further processing the
  218. // IRP - i.e. trying to complete it back to the initiating thread! -since
  219. // there is no initiating thread - we are the initiator
  220. return(STATUS_MORE_PROCESSING_REQUIRED);
  221. }
  222. //----------------------------------------------------------------------------
  223. PIRP
  224. NTAllocateNbtIrp(
  225. IN PDEVICE_OBJECT DeviceObject
  226. )
  227. /*++
  228. Routine Description:
  229. This routine allocates an irp by calling the IO system, and then it
  230. undoes the queuing of the irp to the current thread, since these are
  231. NBTs own irps, and should not be attached to a thread.
  232. Arguments:
  233. Return Value:
  234. NTSTATUS - success or not
  235. --*/
  236. {
  237. PIRP pIrp;
  238. // call the IO subsystem to allocate the irp
  239. pIrp = IoAllocateIrp(DeviceObject->StackSize,FALSE);
  240. if (!pIrp)
  241. {
  242. return(NULL);
  243. }
  244. //
  245. // Simply return a pointer to the packet.
  246. //
  247. return pIrp;
  248. }
  249. //----------------------------------------------------------------------------
  250. NTSTATUS
  251. TdiConnect(
  252. IN PTDI_REQUEST pRequestInfo,
  253. IN ULONG_PTR lTimeout,
  254. IN PTDI_CONNECTION_INFORMATION pSendInfo,
  255. IN PIRP pClientIrp
  256. )
  257. /*++
  258. Routine Description:
  259. This routine sends a connect request to the tranport provider, to setup
  260. a connection to the other side...
  261. Arguments:
  262. Return Value:
  263. The function value is the status of the operation.
  264. --*/
  265. {
  266. NTSTATUS status;
  267. PIRP pRequestIrp;
  268. PDEVICE_OBJECT pDeviceObject;
  269. PFILE_OBJECT pFileObject;
  270. // get an Irp to send the message in
  271. pFileObject = (PFILE_OBJECT)pRequestInfo->Handle.AddressHandle;
  272. pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
  273. // get an Irp from the list
  274. status = GetIrp(&pRequestIrp);
  275. if (!NT_SUCCESS(status))
  276. {
  277. IF_DBG(NBT_DEBUG_TDIOUT)
  278. KdPrint(("Nbt.TdiConnect: Failed to get an Irp"));
  279. // call the completion routine with this status
  280. (*((NBT_COMPLETION)pRequestInfo->RequestNotifyObject))
  281. ((PVOID)pRequestInfo->RequestContext,
  282. STATUS_INSUFFICIENT_RESOURCES,
  283. 0L);
  284. return(STATUS_PENDING);
  285. }
  286. pRequestIrp->CancelRoutine = NULL;
  287. // set up the completion routine passed in from Tcp SessionStart using the APC
  288. // fields in the Irp that would normally be used to complete the request
  289. // back to the client - although we are really the client here so we can
  290. // use these fields ourselves
  291. pRequestIrp->Overlay.AsynchronousParameters.UserApcRoutine =
  292. (PIO_APC_ROUTINE)pRequestInfo->RequestNotifyObject;
  293. pRequestIrp->Overlay.AsynchronousParameters.UserApcContext =
  294. (PVOID)pRequestInfo->RequestContext;
  295. // store some context stuff in the Irp stack so we can call the completion
  296. // routine set by the Udpsend code...
  297. TdiBuildConnect(
  298. pClientIrp,
  299. pDeviceObject,
  300. pFileObject,
  301. TcpConnectComplete,
  302. (PVOID)pRequestIrp, //context value passed to completion routine
  303. lTimeout, // use timeout on connect
  304. pSendInfo,
  305. NULL);
  306. pRequestIrp->MdlAddress = NULL;
  307. CHECK_COMPLETION(pClientIrp);
  308. status = IoCallDriver(pDeviceObject,pClientIrp);
  309. // the transport always completes the IRP, so we always return status pending
  310. return(STATUS_PENDING);
  311. }
  312. //----------------------------------------------------------------------------
  313. NTSTATUS
  314. TdiDisconnect(
  315. IN PTDI_REQUEST pRequestInfo,
  316. IN PVOID lTimeout,
  317. IN ULONG Flags,
  318. IN PTDI_CONNECTION_INFORMATION pSendInfo,
  319. IN PCTE_IRP pClientIrp,
  320. IN BOOLEAN Wait
  321. )
  322. /*++
  323. Routine Description:
  324. This routine sends a connect request to the tranport provider, to setup
  325. a connection to the other side...
  326. Arguments:
  327. pClientIrp - this is the irp that the client used when it issued an
  328. NbtDisconnect. We pass this irp to the transport so that
  329. the client can do a Ctrl C and cancel the irp if the
  330. disconnect takes too long.
  331. Return Value:
  332. The function value is the status of the operation.
  333. --*/
  334. {
  335. NTSTATUS status;
  336. PIRP pRequestIrp;
  337. PDEVICE_OBJECT pDeviceObject;
  338. PFILE_OBJECT pFileObject;
  339. // get an Irp to send the message in
  340. pFileObject = (PFILE_OBJECT)pRequestInfo->Handle.AddressHandle;
  341. pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
  342. status = GetIrp(&pRequestIrp);
  343. if (!NT_SUCCESS(status))
  344. {
  345. IF_DBG(NBT_DEBUG_TDIOUT)
  346. KdPrint(("Nbt.TdiDisconnect: Failed to get an Irp"));
  347. // call the completion routine will this status
  348. (*((NBT_COMPLETION)pRequestInfo->RequestNotifyObject))
  349. ((PVOID)pRequestInfo->RequestContext,
  350. STATUS_INSUFFICIENT_RESOURCES,
  351. 0L);
  352. return(STATUS_PENDING);
  353. }
  354. if (!pClientIrp)
  355. {
  356. // if no client irp was passed in, then just use our Irp
  357. pClientIrp = pRequestIrp;
  358. }
  359. pRequestIrp->CancelRoutine = NULL;
  360. // set up the completion routine passed in from Tcp SessionStart using the APC
  361. // fields in the Irp that would normally be used to complete the request
  362. // back to the client - although we are really the client here so we can
  363. // use these fields ourselves
  364. pRequestIrp->Overlay.AsynchronousParameters.UserApcRoutine =
  365. (PIO_APC_ROUTINE)pRequestInfo->RequestNotifyObject;
  366. pRequestIrp->Overlay.AsynchronousParameters.UserApcContext =
  367. (PVOID)pRequestInfo->RequestContext;
  368. // store some context stuff in the Irp stack so we can call the completion
  369. // routine set by the Udpsend code...
  370. // Note that pRequestIrp is passed to the completion routine as a context
  371. // value so we will know the routine to call for the client's completion.
  372. TdiBuildDisconnect(
  373. pClientIrp,
  374. pDeviceObject,
  375. pFileObject,
  376. TcpConnectComplete,
  377. (PVOID)pRequestIrp, //context value passed to completion routine
  378. lTimeout,
  379. Flags,
  380. NULL, // send connection info
  381. NULL); // return connection info
  382. pRequestIrp->MdlAddress = NULL;
  383. // if Wait is set, then this means do a synchronous disconnect and block
  384. // until the irp is returned.
  385. //
  386. if (Wait)
  387. {
  388. status = SubmitTdiRequest(pFileObject,pClientIrp);
  389. if (!NT_SUCCESS(status))
  390. {
  391. IF_DBG(NBT_DEBUG_TDIOUT)
  392. KdPrint (("Nbt.TdiDisconnect: ERROR -- SubmitTdiRequest returned <%x>\n", status));
  393. }
  394. //
  395. // return the irp to its pool
  396. //
  397. REMOVE_FROM_LIST(&pRequestIrp->ThreadListEntry);
  398. ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
  399. &pRequestIrp->Tail.Overlay.ListEntry,
  400. &NbtConfig.LockInfo.SpinLock);
  401. return(status);
  402. }
  403. else
  404. {
  405. CHECK_COMPLETION(pClientIrp);
  406. status = IoCallDriver(pDeviceObject,pClientIrp);
  407. // the transport always completes the IRP, so we always return status pending
  408. return(STATUS_PENDING);
  409. }
  410. }
  411. //----------------------------------------------------------------------------
  412. NTSTATUS
  413. TcpConnectComplete(
  414. IN PDEVICE_OBJECT DeviceObject,
  415. IN PIRP pIrp,
  416. IN PVOID pContext
  417. )
  418. /*++
  419. Routine Description:
  420. This routine handles the completion of a TCP session setup. The TCP
  421. connection is either setup or not depending on the status returned here.
  422. It must called the clients completion routine (in udpsend.c). Which should
  423. look after sending the NetBios sesion startup pdu across the TCP connection.
  424. The pContext value is actually one of NBTs irps that is JUST used to store
  425. the calling routines completion routine. The real Irp used is the original
  426. client's irp. This is done so that IoCancelIrp will cancel the connect
  427. properly.
  428. Arguments:
  429. Return Value:
  430. NTSTATUS - success or not
  431. --*/
  432. {
  433. KIRQL OldIrq;
  434. PIRP pMyIrp;
  435. pMyIrp = (PIRP)pContext;
  436. // check for a completion routine of the clients to call...
  437. if (pMyIrp->Overlay.AsynchronousParameters.UserApcRoutine)
  438. {
  439. (*((NBT_COMPLETION)pMyIrp->Overlay.AsynchronousParameters.UserApcRoutine))
  440. ((PVOID)pMyIrp->Overlay.AsynchronousParameters.UserApcContext,
  441. pIrp->IoStatus.Status,
  442. 0L);
  443. }
  444. REMOVE_FROM_LIST(&pMyIrp->ThreadListEntry);
  445. ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
  446. &pMyIrp->Tail.Overlay.ListEntry,
  447. &NbtConfig.LockInfo.SpinLock);
  448. // return this status to stop the IO subsystem from further processing the
  449. // IRP - i.e. trying to complete it back to the initiating thread! -since
  450. // there is not initiating thread - we are the initiator
  451. return(STATUS_MORE_PROCESSING_REQUIRED);
  452. }
  453. //----------------------------------------------------------------------------
  454. NTSTATUS
  455. TdiSend(
  456. IN PTDI_REQUEST pRequestInfo,
  457. IN USHORT sFlags,
  458. IN ULONG SendLength,
  459. OUT PULONG pSentSize,
  460. IN tBUFFER *pSendBuffer,
  461. IN ULONG Flags
  462. )
  463. /*++
  464. Routine Description:
  465. This routine sends a packet to the transport on a TCP connection
  466. Arguments:
  467. pSendBuffer - this is really an Mdl in NT land. It must be tacked on
  468. the end of the Mdl created for the Nbt datagram header.
  469. Return Value:
  470. The function value is the status of the operation.
  471. --*/
  472. {
  473. NTSTATUS status;
  474. PIRP pRequestIrp;
  475. PMDL pMdl;
  476. PDEVICE_OBJECT pDeviceObject;
  477. PFILE_OBJECT pFileObject;
  478. // get an Irp to send the message in
  479. pFileObject = (PFILE_OBJECT)pRequestInfo->Handle.AddressHandle;
  480. pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
  481. // get an Irp from the list
  482. status = GetIrp(&pRequestIrp);
  483. if (!NT_SUCCESS(status))
  484. {
  485. IF_DBG(NBT_DEBUG_TDIOUT)
  486. KdPrint(("Nbt.TdiSend: Failed to get an Irp"));
  487. // call the completion routine with this status
  488. if (pRequestInfo->RequestNotifyObject)
  489. {
  490. (*((NBT_COMPLETION)pRequestInfo->RequestNotifyObject))
  491. ((PVOID)pRequestInfo->RequestContext,
  492. STATUS_INSUFFICIENT_RESOURCES,
  493. 0L);
  494. }
  495. return(STATUS_INSUFFICIENT_RESOURCES);
  496. }
  497. pRequestIrp->CancelRoutine = NULL;
  498. // set up the completion routine passed in from Udp Send using the APC
  499. // fields in the Irp that would normally be used to complete the request
  500. // back to the client - although we are really the client here so we can
  501. // use these fields our self!
  502. pRequestIrp->Overlay.AsynchronousParameters.UserApcRoutine =
  503. (PIO_APC_ROUTINE)pRequestInfo->RequestNotifyObject;
  504. pRequestIrp->Overlay.AsynchronousParameters.UserApcContext =
  505. (PVOID)pRequestInfo->RequestContext;
  506. // get the MDL that is currently linked to the IRP (i.e. created at the
  507. // same time that we created the IRP list. Set the sizes correctly in
  508. // the MDL header.
  509. pMdl = IoAllocateMdl(
  510. pSendBuffer->pDgramHdr,
  511. pSendBuffer->HdrLength,
  512. FALSE,
  513. FALSE,
  514. NULL);
  515. if (!pMdl)
  516. {
  517. REMOVE_FROM_LIST(&pRequestIrp->ThreadListEntry);
  518. ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
  519. &pRequestIrp->Tail.Overlay.ListEntry,
  520. &NbtConfig.LockInfo.SpinLock);
  521. // call the completion routine will this status
  522. if (pRequestInfo->RequestNotifyObject)
  523. {
  524. (*((NBT_COMPLETION)pRequestInfo->RequestNotifyObject))
  525. ((PVOID)pRequestInfo->RequestContext,
  526. STATUS_INSUFFICIENT_RESOURCES,
  527. 0L);
  528. }
  529. return(STATUS_INSUFFICIENT_RESOURCES);
  530. }
  531. // Map the pages in memory...
  532. MmBuildMdlForNonPagedPool(pMdl);
  533. TdiBuildSend(
  534. pRequestIrp,
  535. pDeviceObject,
  536. pFileObject,
  537. SendSessionCompletionRoutine,
  538. NULL, //context value passed to completion routine
  539. pMdl,
  540. sFlags,
  541. SendLength); // include session hdr length (ULONG)
  542. //
  543. // tack the Client's buffer on the end, if there is one
  544. //
  545. if (pSendBuffer->Length)
  546. {
  547. pMdl->Next = pSendBuffer->pBuffer;
  548. }
  549. CHECK_COMPLETION(pRequestIrp);
  550. status = IoCallDriver(pDeviceObject,pRequestIrp);
  551. *pSentSize = SendLength; // the size we attempted to send
  552. return(status);
  553. }
  554. //----------------------------------------------------------------------------
  555. NTSTATUS
  556. SendSessionCompletionRoutine(
  557. IN PDEVICE_OBJECT DeviceObject,
  558. IN PIRP pIrp,
  559. IN PVOID pContext
  560. )
  561. /*++
  562. Routine Description:
  563. This routine handles the completion of a send to the transport.
  564. It must call any client supplied completion routine and free the Irp
  565. and Mdl back to its pool.
  566. Arguments:
  567. Return Value:
  568. NTSTATUS - success or not
  569. --*/
  570. {
  571. KIRQL OldIrq;
  572. //
  573. // check for a completion routine of the clients to call...
  574. //
  575. if (pIrp->Overlay.AsynchronousParameters.UserApcRoutine)
  576. {
  577. (*((NBT_COMPLETION)pIrp->Overlay.AsynchronousParameters.UserApcRoutine))
  578. ((PVOID)pIrp->Overlay.AsynchronousParameters.UserApcContext,
  579. pIrp->IoStatus.Status,
  580. (ULONG)pIrp->IoStatus.Information); // sent length
  581. }
  582. IoFreeMdl(pIrp->MdlAddress);
  583. REMOVE_FROM_LIST(&pIrp->ThreadListEntry);
  584. ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
  585. &pIrp->Tail.Overlay.ListEntry,
  586. &NbtConfig.LockInfo.SpinLock);
  587. //
  588. // return this status to stop the IO subsystem from further processing the
  589. // IRP - i.e. trying to complete it back to the initiating thread! -since
  590. // there is no initiating thread - we are the initiator
  591. //
  592. return(STATUS_MORE_PROCESSING_REQUIRED);
  593. }