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.

356 lines
8.6 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. sendrecv.c
  5. Abstract:
  6. This module contains the SPUDSendAndRecv service.
  7. Author:
  8. John Ballard (jballard) 21-Oct-1996
  9. Revision History:
  10. Keith Moore (keithmo) 04-Feb-1998
  11. Cleanup, added much needed comments.
  12. --*/
  13. #include "spudp.h"
  14. #ifdef ALLOC_PRAGMA
  15. #pragma alloc_text( PAGE, SPUDSendAndRecv )
  16. #endif
  17. //
  18. // Public functions.
  19. //
  20. NTSTATUS
  21. SPUDSendAndRecv(
  22. HANDLE hSocket,
  23. struct _AFD_SEND_INFO *sendInfo,
  24. struct _AFD_RECV_INFO *recvInfo,
  25. PSPUD_REQ_CONTEXT reqContext
  26. )
  27. /*++
  28. Routine Description:
  29. Batch send & receive request.
  30. Arguments:
  31. hSocket - The target socket for the request.
  32. sendInfo - Information describing the send.
  33. recvInfo - Information describing the receive.
  34. reqContext - The user-mode context for the request.
  35. Return Value:
  36. NTSTATUS - Completion status.
  37. --*/
  38. {
  39. NTSTATUS status;
  40. PFILE_OBJECT fileObject;
  41. IO_STATUS_BLOCK localIoStatus;
  42. PIRP irp;
  43. PIO_STACK_LOCATION irpSp;
  44. PSPUD_AFD_REQ_CONTEXT SpudReqContext;
  45. PVOID completionPort;
  46. //
  47. // Sanity check.
  48. //
  49. PAGED_CODE();
  50. status = SPUD_ENTER_SERVICE( "SPUDSendAndRecv", TRUE );
  51. if( !NT_SUCCESS(status) ) {
  52. return status;
  53. }
  54. BumpCount( CtrSendAndRecv );
  55. //
  56. // SPUD doesn't support kernel-mode callers. In fact, we don't
  57. // even build the "system stubs" necessary to invoke SPUD from
  58. // kernel-mode.
  59. //
  60. ASSERT( ExGetPreviousMode() == UserMode );
  61. try {
  62. //
  63. // Make sure we can write to reqContext
  64. //
  65. ProbeForWrite(
  66. reqContext,
  67. sizeof(SPUD_REQ_CONTEXT),
  68. sizeof(ULONG)
  69. );
  70. //
  71. // Make initial status invalid
  72. //
  73. reqContext->IoStatus1.Status = 0xffffffff;
  74. reqContext->IoStatus1.Information = 0;
  75. reqContext->IoStatus2.Status = 0xffffffff;
  76. reqContext->IoStatus2.Information = 0;
  77. reqContext->ReqType = SendAndRecv;
  78. reqContext->KernelReqInfo = SPUD_INVALID_REQ_HANDLE;
  79. //
  80. // Make sure the buffer looks good
  81. //
  82. ProbeForRead(
  83. recvInfo,
  84. sizeof(*recvInfo),
  85. sizeof(ULONG)
  86. );
  87. if( recvInfo->BufferCount < 1 ) {
  88. ExRaiseStatus( STATUS_INVALID_PARAMETER );
  89. }
  90. ProbeForRead(
  91. recvInfo->BufferArray,
  92. sizeof(*recvInfo->BufferArray),
  93. sizeof(ULONG)
  94. );
  95. ProbeForRead(
  96. recvInfo->BufferArray->buf,
  97. recvInfo->BufferArray->len,
  98. sizeof(UCHAR)
  99. );
  100. } except( EXCEPTION_EXECUTE_HANDLER ) {
  101. status = GetExceptionCode();
  102. SPUD_LEAVE_SERVICE( "SPUDSendAndRecv", status, FALSE );
  103. return status;
  104. }
  105. //
  106. // Reference the socket handle
  107. //
  108. status = ObReferenceObjectByHandle(
  109. hSocket,
  110. 0L,
  111. *IoFileObjectType,
  112. UserMode,
  113. (PVOID *)&fileObject,
  114. NULL
  115. );
  116. if( !NT_SUCCESS(status) ) {
  117. SPUD_LEAVE_SERVICE( "SPUDSendAndRecv", status, FALSE );
  118. return status;
  119. }
  120. TRACE_OB_REFERENCE( fileObject );
  121. //
  122. // If we haven't already cached the Device Object and FastIoControl
  123. // pointers, then do so now.
  124. //
  125. if( !SpudAfdDeviceObject ) {
  126. status = SpudGetAfdDeviceObject( fileObject );
  127. if( !NT_SUCCESS(status) ) {
  128. TRACE_OB_DEREFERENCE( fileObject );
  129. ObDereferenceObject( fileObject );
  130. status = STATUS_INVALID_DEVICE_REQUEST;
  131. SPUD_LEAVE_SERVICE( "SPUDSendAndRecv", status, FALSE );
  132. return status;
  133. }
  134. }
  135. //
  136. // Reference the completion port.
  137. //
  138. completionPort = SpudReferenceCompletionPort();
  139. if( completionPort == NULL ) {
  140. TRACE_OB_DEREFERENCE( fileObject );
  141. ObDereferenceObject( fileObject );
  142. status = STATUS_INVALID_DEVICE_REQUEST;
  143. SPUD_LEAVE_SERVICE( "SPUDSendAndRecv", status, FALSE );
  144. return status;
  145. }
  146. //
  147. // Let's check to see if fast io will work
  148. //
  149. if( SpudAfdFastIoDeviceControl(
  150. fileObject,
  151. TRUE,
  152. (PVOID)sendInfo,
  153. sizeof(AFD_SEND_INFO),
  154. NULL,
  155. 0,
  156. IOCTL_AFD_SEND,
  157. &localIoStatus,
  158. SpudAfdDeviceObject
  159. )) {
  160. BumpCount( CtrSendRecvFastSend );
  161. //
  162. // Lets remember the completion status for this operation
  163. //
  164. try {
  165. reqContext->IoStatus1 = localIoStatus;
  166. } except( EXCEPTION_EXECUTE_HANDLER) {
  167. localIoStatus.Status = GetExceptionCode();
  168. localIoStatus.Information = 0;
  169. }
  170. if( localIoStatus.Status == STATUS_SUCCESS ) {
  171. localIoStatus.Status = SpudAfdRecvFastReq(
  172. fileObject,
  173. recvInfo,
  174. reqContext
  175. );
  176. }
  177. //
  178. // If everything completed without pending then we can queue
  179. // a completion packet to the port now.
  180. //
  181. // Note that we must not queue a completion packet if the
  182. // request is failing in-line.
  183. //
  184. if( localIoStatus.Status != STATUS_PENDING ) {
  185. if( NT_SUCCESS(localIoStatus.Status) ) {
  186. localIoStatus.Status = IoSetIoCompletion(
  187. SpudCompletionPort, // IoCompletion
  188. reqContext, // KeyContext
  189. NULL, // ApcContext
  190. STATUS_SUCCESS, // IoStatus
  191. 0xFFFFFFFF, // IoStatusInformation
  192. TRUE // Quota
  193. );
  194. }
  195. TRACE_OB_DEREFERENCE( fileObject );
  196. ObDereferenceObject( fileObject );
  197. }
  198. //
  199. // At this point, we know the fast-path send has completed
  200. // in-line and the receive either completed in-line or has pended.
  201. // Since it is the receive code's responsibility to add any necessary
  202. // references to the completion port (and since we know the send
  203. // has not pended) we can remove the reference we added above.
  204. //
  205. SPUD_LEAVE_SERVICE( "SPUDSendAndRecv", localIoStatus.Status, TRUE );
  206. return localIoStatus.Status;
  207. }
  208. BumpCount( CtrSendRecvSlowSend );
  209. //
  210. // It looks like we will have to it the hard way.
  211. // We will now build an IRP for AFD.
  212. //
  213. KeClearEvent( &fileObject->Event );
  214. //
  215. // Allocate and initialize the IRP.
  216. //
  217. irp = IoAllocateIrp( SpudAfdDeviceObject->StackSize, TRUE );
  218. if( !irp ) {
  219. TRACE_OB_DEREFERENCE( fileObject );
  220. ObDereferenceObject( fileObject );
  221. status = STATUS_INSUFFICIENT_RESOURCES;
  222. SPUD_LEAVE_SERVICE( "SPUDSendAndRecv", status, TRUE );
  223. return status;
  224. }
  225. status = SpudAllocateRequestContext(
  226. &SpudReqContext,
  227. reqContext,
  228. recvInfo,
  229. irp,
  230. NULL
  231. );
  232. if( !NT_SUCCESS(status) ) {
  233. TRACE_OB_DEREFERENCE( fileObject );
  234. ObDereferenceObject( fileObject );
  235. IoFreeIrp( irp );
  236. SPUD_LEAVE_SERVICE( "SPUDSendAndRecv", status, TRUE );
  237. return status;
  238. }
  239. BumpCount( CtrSendRecvSlowRecv );
  240. irp->RequestorMode = UserMode;
  241. irp->Tail.Overlay.OriginalFileObject = fileObject;
  242. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  243. IoQueueThreadIrp( irp );
  244. irpSp = IoGetNextIrpStackLocation( irp );
  245. irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  246. irpSp->FileObject = fileObject;
  247. irpSp->DeviceObject = SpudAfdDeviceObject;
  248. // irpSp->Parameters.DeviceIoControl.OutputBufferLength = 0;
  249. irpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof(AFD_SEND_INFO);
  250. irpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_AFD_SEND;
  251. irpSp->Parameters.DeviceIoControl.Type3InputBuffer = sendInfo;
  252. IoSetCompletionRoutine(
  253. irp,
  254. SpudAfdContinueRecv,
  255. SpudReqContext,
  256. TRUE,
  257. TRUE,
  258. TRUE
  259. );
  260. IoCallDriver( SpudAfdDeviceObject, irp );
  261. status = STATUS_PENDING;
  262. SPUD_LEAVE_SERVICE( "SPUDSendAndRecv", status, FALSE );
  263. return status;
  264. } // SPUDSendAndRecv