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.

500 lines
14 KiB

  1. /////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2001 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // buffer
  7. //
  8. // Abstract:
  9. // This module contains code which deals with receiving
  10. // data via posted user mode buffers
  11. //
  12. //////////////////////////////////////////////////////////
  13. #include "sysvars.h"
  14. //////////////////////////////////////////////////////////////
  15. // private constants, types, and prototypes
  16. //////////////////////////////////////////////////////////////
  17. const PCHAR strFunc1 = "TSPostReceiveBuffer";
  18. //const PCHAR strFunc2 = "TSFetchReceiveBuffer";
  19. const PCHAR strFuncP1 = "TSSampleReceiveBufferComplete";
  20. //
  21. // receive completion context. Also used to track what buffers have
  22. // been posted
  23. //
  24. struct USERBUF_INFO
  25. {
  26. USERBUF_INFO *pNextUserBufInfo; // next one in chain
  27. PMDL pLowerMdl; // mdl for lower irp
  28. PIRP pLowerIrp; // so can abort it...
  29. TDI_EVENT TdiEventCompleted; // abort completed
  30. ULONG ulBytesTransferred; // #bytes stored in mdl
  31. PUCHAR pucUserModeBuffer;
  32. PTDI_CONNECTION_INFORMATION
  33. pReceiveTdiConnectInfo;
  34. PTDI_CONNECTION_INFORMATION
  35. pReturnTdiConnectInfo;
  36. };
  37. typedef USERBUF_INFO *PUSERBUF_INFO;
  38. //
  39. // completion function
  40. //
  41. TDI_STATUS
  42. TSReceiveBufferComplete(
  43. PDEVICE_OBJECT DeviceObject,
  44. PIRP Irp,
  45. PVOID Context
  46. );
  47. //////////////////////////////////////////////////////////////
  48. // public functions
  49. //////////////////////////////////////////////////////////////
  50. // --------------------------------------------------------
  51. //
  52. // Function: TSPostReceiveBuffer
  53. //
  54. // Arguments: pGenericHeader -- AddressObject or Endpoint to post buffer for
  55. // pSendBuffer -- rest of arguments
  56. //
  57. // Returns: status of operation (STATUS_SUCCESS or a failure)
  58. //
  59. // Descript: This function posts a user mode buffer for receiving either
  60. // a datagram or a packet over a connection. The buffer will
  61. // be retrieved later by TSFetchReceiveBuffer
  62. //
  63. // --------------------------------------------------------
  64. NTSTATUS
  65. TSPostReceiveBuffer(PGENERIC_HEADER pGenericHeader,
  66. PSEND_BUFFER pSendBuffer)
  67. {
  68. ULONG ulDataLength = pSendBuffer->COMMAND_ARGS.SendArgs.ulBufferLength;
  69. PUCHAR pucDataBuffer = pSendBuffer->COMMAND_ARGS.SendArgs.pucUserModeBuffer;
  70. //
  71. // show debug, if it is turned on
  72. //
  73. if (ulDebugLevel & ulDebugShowCommand)
  74. {
  75. DebugPrint3("\nCommand = ulPOSTRECEIVEBUFFER\n"
  76. "FileObject = %p\n"
  77. "DataLength = %u\n"
  78. "Buffer = %p\n",
  79. pGenericHeader,
  80. ulDataLength,
  81. pucDataBuffer);
  82. }
  83. //
  84. // make sure we have a valid object to run on
  85. //
  86. PADDRESS_OBJECT pAddressObject;
  87. PENDPOINT_OBJECT pEndpoint;
  88. if (pGenericHeader->ulSignature == ulEndpointObject)
  89. {
  90. pEndpoint = (PENDPOINT_OBJECT)pGenericHeader;
  91. if (pEndpoint->fIsConnected)
  92. {
  93. pAddressObject = pEndpoint->pAddressObject;
  94. }
  95. else
  96. {
  97. return STATUS_UNSUCCESSFUL;
  98. }
  99. }
  100. else
  101. {
  102. pEndpoint = NULL;
  103. pAddressObject = (PADDRESS_OBJECT)pGenericHeader;
  104. }
  105. //
  106. // attempt to lock down the memory
  107. //
  108. PMDL pReceiveMdl = TSMakeMdlForUserBuffer(pucDataBuffer,
  109. ulDataLength,
  110. IoModifyAccess);
  111. if (!pReceiveMdl)
  112. {
  113. return STATUS_UNSUCCESSFUL;
  114. }
  115. //
  116. // allocate our context
  117. //
  118. PUSERBUF_INFO pUserBufInfo = NULL;
  119. PTDI_CONNECTION_INFORMATION pReceiveTdiConnectInfo = NULL;
  120. PTDI_CONNECTION_INFORMATION pReturnTdiConnectInfo = NULL;
  121. PIRP pLowerIrp = NULL;
  122. //
  123. // our context
  124. //
  125. if ((TSAllocateMemory((PVOID *)&pUserBufInfo,
  126. sizeof(USERBUF_INFO),
  127. strFunc1,
  128. "UserBufInfo")) != STATUS_SUCCESS)
  129. {
  130. goto cleanup;
  131. }
  132. //
  133. // do path specific allocations
  134. //
  135. if (pEndpoint)
  136. {
  137. pLowerIrp = TSAllocateIrp(pEndpoint->GenHead.pDeviceObject,
  138. NULL);
  139. }
  140. else
  141. {
  142. //
  143. // for datagrams, need the connection information structures
  144. //
  145. if ((TSAllocateMemory((PVOID *)&pReceiveTdiConnectInfo,
  146. sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TRANSADDR),
  147. strFunc1,
  148. "ReceiveTdiConnectionInformation")) != STATUS_SUCCESS)
  149. {
  150. goto cleanup;
  151. }
  152. if ((TSAllocateMemory((PVOID *)&pReturnTdiConnectInfo,
  153. sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TRANSADDR),
  154. strFunc1,
  155. "ReturnTdiConnectionInformation")) != STATUS_SUCCESS)
  156. {
  157. goto cleanup;
  158. }
  159. pLowerIrp = TSAllocateIrp(pAddressObject->GenHead.pDeviceObject,
  160. NULL);
  161. }
  162. //
  163. // everything is allocated at this point...
  164. //
  165. if (pLowerIrp)
  166. {
  167. //
  168. // common code -- mostly dealing with puserbuf structure
  169. // First, add it to the linked list
  170. //
  171. TSAcquireSpinLock(&pAddressObject->TdiSpinLock);
  172. if (pAddressObject->pTailUserBufInfo)
  173. {
  174. pAddressObject->pTailUserBufInfo->pNextUserBufInfo = pUserBufInfo;
  175. }
  176. else
  177. {
  178. pAddressObject->pHeadUserBufInfo = pUserBufInfo;
  179. }
  180. pAddressObject->pTailUserBufInfo = pUserBufInfo;
  181. TSReleaseSpinLock(&pAddressObject->TdiSpinLock);
  182. //
  183. // and fill in all fields that we can
  184. //
  185. pUserBufInfo->pLowerMdl = pReceiveMdl;
  186. pUserBufInfo->pLowerIrp = pLowerIrp;
  187. pUserBufInfo->ulBytesTransferred = 0;
  188. pUserBufInfo->pucUserModeBuffer = pucDataBuffer;
  189. pUserBufInfo->pReceiveTdiConnectInfo = pReceiveTdiConnectInfo;
  190. pUserBufInfo->pReturnTdiConnectInfo = pReturnTdiConnectInfo;
  191. TSInitializeEvent(&pUserBufInfo->TdiEventCompleted);
  192. //
  193. // now do what is necessary for each path..
  194. //
  195. if (pEndpoint)
  196. {
  197. //
  198. // set up the irp for the call
  199. //
  200. #pragma warning(disable: CONSTANT_CONDITIONAL)
  201. TdiBuildReceive(pLowerIrp,
  202. pEndpoint->GenHead.pDeviceObject,
  203. pEndpoint->GenHead.pFileObject,
  204. TSReceiveBufferComplete,
  205. pUserBufInfo,
  206. pReceiveMdl,
  207. 0, // flags
  208. ulDataLength);
  209. #pragma warning(default: CONSTANT_CONDITIONAL)
  210. NTSTATUS lStatus = IoCallDriver(pEndpoint->GenHead.pDeviceObject,
  211. pLowerIrp);
  212. if ((!NT_SUCCESS(lStatus)) && (ulDebugLevel & ulDebugShowCommand))
  213. {
  214. DebugPrint2(("%s: unexpected status for IoCallDriver [0x%08x]\n"),
  215. strFunc1,
  216. lStatus);
  217. }
  218. }
  219. //
  220. // else a datagram
  221. //
  222. else
  223. {
  224. pReturnTdiConnectInfo->RemoteAddress = (PUCHAR)pReturnTdiConnectInfo
  225. + sizeof(TDI_CONNECTION_INFORMATION);
  226. pReturnTdiConnectInfo->RemoteAddressLength = ulMAX_TABUFFER_LENGTH;
  227. //
  228. // set up the irp for the call
  229. //
  230. #pragma warning(disable: CONSTANT_CONDITIONAL)
  231. TdiBuildReceiveDatagram(pLowerIrp,
  232. pAddressObject->GenHead.pDeviceObject,
  233. pAddressObject->GenHead.pFileObject,
  234. TSReceiveBufferComplete,
  235. pUserBufInfo,
  236. pReceiveMdl,
  237. ulDataLength,
  238. pReceiveTdiConnectInfo,
  239. pReturnTdiConnectInfo,
  240. TDI_RECEIVE_NORMAL);
  241. #pragma warning(default: CONSTANT_CONDITIONAL)
  242. NTSTATUS lStatus = IoCallDriver(pAddressObject->GenHead.pDeviceObject,
  243. pLowerIrp);
  244. if ((!NT_SUCCESS(lStatus)) && (ulDebugLevel & ulDebugShowCommand))
  245. {
  246. DebugPrint2(("%s: unexpected status for IoCallDriver [0x%08x]\n"),
  247. strFunc1,
  248. lStatus);
  249. }
  250. }
  251. return STATUS_SUCCESS;
  252. }
  253. //
  254. // get here if there was an allocation failure
  255. // need to clean up everything else...
  256. //
  257. cleanup:
  258. if (pUserBufInfo)
  259. {
  260. TSFreeMemory(pUserBufInfo);
  261. }
  262. if (pReceiveTdiConnectInfo)
  263. {
  264. TSFreeMemory(pReceiveTdiConnectInfo);
  265. }
  266. if (pReturnTdiConnectInfo)
  267. {
  268. TSFreeMemory(pReturnTdiConnectInfo);
  269. }
  270. TSFreeUserBuffer(pReceiveMdl);
  271. return STATUS_INSUFFICIENT_RESOURCES;
  272. }
  273. // --------------------------------------------------------
  274. //
  275. // Function: TSFetchReceiveBuffer
  276. //
  277. // Arguments: pGenericHeader -- AddressObject or Endpoint to fetch buffer for
  278. // pReceiveBuffer -- for storing actual results
  279. //
  280. // Returns: status of operation (STATUS_SUCCESS)
  281. //
  282. // Descript: This function retrieves the user mode buffer posted earlier
  283. // by function TSPostReceiveBuffer
  284. //
  285. // --------------------------------------------------------
  286. NTSTATUS
  287. TSFetchReceiveBuffer(PGENERIC_HEADER pGenericHeader,
  288. PRECEIVE_BUFFER pReceiveBuffer)
  289. {
  290. //
  291. // show debug, if it is turned on
  292. //
  293. if (ulDebugLevel & ulDebugShowCommand)
  294. {
  295. DebugPrint1("\nCommand = ulFETCHRECEIVEBUFFER\n"
  296. "FileObject = %p\n",
  297. pGenericHeader);
  298. }
  299. //
  300. // make sure we have a valid object to run on
  301. //
  302. PADDRESS_OBJECT pAddressObject;
  303. if (pGenericHeader->ulSignature == ulEndpointObject)
  304. {
  305. PENDPOINT_OBJECT pEndpoint = (PENDPOINT_OBJECT)pGenericHeader;
  306. //
  307. // note: it is possible that connection has been broken but that
  308. // the buffer is still posted
  309. //
  310. pAddressObject = pEndpoint->pAddressObject;
  311. if (!pAddressObject)
  312. {
  313. return STATUS_UNSUCCESSFUL;
  314. }
  315. }
  316. else
  317. {
  318. pAddressObject = (PADDRESS_OBJECT)pGenericHeader;
  319. }
  320. //
  321. // ok, we got the address object. See if there are any user buffers
  322. // attached to it...
  323. //
  324. TSAcquireSpinLock(&pAddressObject->TdiSpinLock);
  325. PUSERBUF_INFO pUserBufInfo = pAddressObject->pHeadUserBufInfo;
  326. if (pUserBufInfo)
  327. {
  328. if (pUserBufInfo->pNextUserBufInfo)
  329. {
  330. pAddressObject->pHeadUserBufInfo = pUserBufInfo->pNextUserBufInfo;
  331. }
  332. else
  333. {
  334. pAddressObject->pHeadUserBufInfo = NULL;
  335. pAddressObject->pTailUserBufInfo = NULL;
  336. }
  337. }
  338. TSReleaseSpinLock(&pAddressObject->TdiSpinLock);
  339. if (!pUserBufInfo)
  340. {
  341. return STATUS_UNSUCCESSFUL;
  342. }
  343. //
  344. // ok, we got our buffer. See if it has completed
  345. // or if we need to abort it
  346. //
  347. if (pUserBufInfo->pLowerIrp)
  348. {
  349. IoCancelIrp(pUserBufInfo->pLowerIrp);
  350. TSWaitEvent(&pUserBufInfo->TdiEventCompleted);
  351. }
  352. //
  353. // it has finished. stuff the address and length into the receive
  354. // buffer, delete the UserBufInfo structure, and go home
  355. //
  356. pReceiveBuffer->RESULTS.RecvDgramRet.ulBufferLength = pUserBufInfo->ulBytesTransferred;
  357. pReceiveBuffer->RESULTS.RecvDgramRet.pucUserModeBuffer = pUserBufInfo->pucUserModeBuffer;
  358. TSFreeMemory(pUserBufInfo);
  359. return STATUS_SUCCESS;
  360. }
  361. /////////////////////////////////////////////////////////////
  362. // private functions
  363. /////////////////////////////////////////////////////////////
  364. // ---------------------------------------------------------
  365. //
  366. // Function: TSReceiveBufferComplete
  367. //
  368. // Arguments: pDeviceObject -- device object that called protocol
  369. // pIrp -- IRP used in the call
  370. // pContext -- context used for the call
  371. //
  372. // Returns: status of operation (STATUS_MORE_PROCESSING_REQUIRED)
  373. //
  374. // Descript: Gets the result of the command, unlock the buffer,
  375. // and does other necessary cleanup
  376. //
  377. // ---------------------------------------------------------
  378. #pragma warning(disable: UNREFERENCED_PARAM)
  379. TDI_STATUS
  380. TSReceiveBufferComplete(PDEVICE_OBJECT pDeviceObject,
  381. PIRP pLowerIrp,
  382. PVOID pvContext)
  383. {
  384. PUSERBUF_INFO pUserBufInfo = (PUSERBUF_INFO)pvContext;
  385. NTSTATUS lStatus = pLowerIrp->IoStatus.Status;
  386. ULONG ulBytesReceived = (ULONG)pLowerIrp->IoStatus.Information;
  387. if (NT_SUCCESS(lStatus))
  388. {
  389. if (ulDebugLevel & ulDebugShowCommand)
  390. {
  391. DebugPrint2("%s: BytesReceived = 0x%08x\n",
  392. strFuncP1,
  393. ulBytesReceived);
  394. }
  395. pUserBufInfo->ulBytesTransferred = ulBytesReceived;
  396. }
  397. else
  398. {
  399. if (ulDebugLevel & ulDebugShowCommand)
  400. {
  401. DebugPrint2("%s: Completed with status 0x%08x\n",
  402. strFuncP1,
  403. lStatus);
  404. }
  405. }
  406. //
  407. // now cleanup
  408. //
  409. TSFreeUserBuffer(pUserBufInfo->pLowerMdl);
  410. if (pUserBufInfo->pReturnTdiConnectInfo)
  411. {
  412. TSFreeMemory(pUserBufInfo->pReturnTdiConnectInfo);
  413. }
  414. if (pUserBufInfo->pReceiveTdiConnectInfo)
  415. {
  416. TSFreeMemory(pUserBufInfo->pReceiveTdiConnectInfo);
  417. }
  418. TSSetEvent(&pUserBufInfo->TdiEventCompleted);
  419. TSFreeIrp(pLowerIrp, NULL);
  420. pUserBufInfo->pLowerIrp = NULL;
  421. return TDI_MORE_PROCESSING;
  422. }
  423. #pragma warning(default: UNREFERENCED_PARAM)
  424. ///////////////////////////////////////////////////////////////////////////////
  425. // end of file buffer.cpp
  426. ///////////////////////////////////////////////////////////////////////////////