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.

516 lines
13 KiB

  1. /*++
  2. Copyright (c) 1989-1993 Microsoft Corporation
  3. Module Name:
  4. receive.c
  5. Abstract:
  6. This module contains code which performs the following TDI services:
  7. o TdiReceiveDatagram
  8. Environment:
  9. Kernel mode
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. VOID
  15. IpxTransferDataComplete(
  16. IN NDIS_HANDLE BindingContext,
  17. IN PNDIS_PACKET NdisPacket,
  18. IN NDIS_STATUS NdisStatus,
  19. IN UINT BytesTransferred
  20. )
  21. /*++
  22. Routine Description:
  23. This routine receives control from the physical provider as an
  24. indication that an NdisTransferData has completed. We use this indication
  25. to complete any pended requests to our clients.
  26. Arguments:
  27. BindingContext - The Adapter Binding specified at initialization time.
  28. NdisPacket/RequestHandle - An identifier for the request that completed.
  29. NdisStatus - The completion status for the request.
  30. BytesTransferred - Number of bytes actually transferred.
  31. Return Value:
  32. None.
  33. --*/
  34. {
  35. PADAPTER Adapter = (PADAPTER)BindingContext;
  36. PIPX_RECEIVE_RESERVED Reserved = (PIPX_RECEIVE_RESERVED)(NdisPacket->ProtocolReserved);
  37. PREQUEST Request, LastRequest;
  38. PADDRESS_FILE AddressFile;
  39. ULONG ByteOffset;
  40. PLIST_ENTRY p;
  41. PDEVICE Device;
  42. switch (Reserved->Identifier) {
  43. case IDENTIFIER_IPX:
  44. if (!Reserved->pContext) {
  45. if (Reserved->SingleRequest) {
  46. //
  47. // The transfer was directly into the client buffer,
  48. // so simply complete the request.
  49. //
  50. Request = Reserved->SingleRequest;
  51. if (NdisStatus == NDIS_STATUS_SUCCESS) {
  52. IPX_DEBUG (RECEIVE, ("Transferred %d bytes\n", BytesTransferred));
  53. REQUEST_INFORMATION(Request) = BytesTransferred;
  54. REQUEST_STATUS(Request) = STATUS_SUCCESS;
  55. } else {
  56. IPX_DEBUG (RECEIVE, ("Transfer failed\n"));
  57. REQUEST_INFORMATION(Request) = 0;
  58. REQUEST_STATUS(Request) = STATUS_ADAPTER_HARDWARE_ERROR;
  59. }
  60. LastRequest = Request;
  61. Reserved->SingleRequest = NULL;
  62. } else {
  63. //
  64. // Multiple clients requested this datagram. Save
  65. // the last one to delay queueing it for completion.
  66. //
  67. LastRequest = LIST_ENTRY_TO_REQUEST (Reserved->Requests.Blink);
  68. while (TRUE) {
  69. p = RemoveHeadList (&Reserved->Requests);
  70. if (p == &Reserved->Requests) {
  71. break;
  72. }
  73. Request = LIST_ENTRY_TO_REQUEST(p);
  74. AddressFile = REQUEST_OPEN_CONTEXT(Request);
  75. if (AddressFile->ReceiveIpxHeader) {
  76. ByteOffset = 0;
  77. } else {
  78. ByteOffset = sizeof(IPX_HEADER);
  79. }
  80. if (NdisStatus == NDIS_STATUS_SUCCESS) {
  81. UINT BytesToTransfer = ((PTDI_REQUEST_KERNEL_RECEIVEDG)(REQUEST_PARAMETERS(Request)))->ReceiveLength;
  82. if (BytesToTransfer == 0) {
  83. BytesToTransfer= IpxGetChainedMDLLength(REQUEST_NDIS_BUFFER(Request));
  84. }
  85. #ifdef SUNDOWN
  86. // assume offset will not exceed 2^32.
  87. // REQUEST_INFORMATION(Request) is a ULONG_PTR
  88. // we are save to cast its address to PULONG.
  89. REQUEST_STATUS(Request) =
  90. TdiCopyBufferToMdl(
  91. Reserved->ReceiveBuffer->Data,
  92. (ULONG) (ByteOffset + REQUEST_INFORMATION(Request)),
  93. BytesToTransfer,
  94. REQUEST_NDIS_BUFFER(Request),
  95. 0,
  96. (PULONG) &REQUEST_INFORMATION(Request));
  97. #else
  98. REQUEST_STATUS(Request) =
  99. TdiCopyBufferToMdl(
  100. Reserved->ReceiveBuffer->Data,
  101. ByteOffset + REQUEST_INFORMATION(Request),
  102. BytesToTransfer,
  103. REQUEST_NDIS_BUFFER(Request),
  104. 0,
  105. &REQUEST_INFORMATION(Request));
  106. #endif
  107. } else {
  108. REQUEST_INFORMATION(Request) = 0;
  109. REQUEST_STATUS(Request) = STATUS_ADAPTER_HARDWARE_ERROR;
  110. }
  111. if (Request != LastRequest) {
  112. IPX_INSERT_TAIL_LIST(
  113. &Adapter->RequestCompletionQueue,
  114. REQUEST_LINKAGE(Request),
  115. Adapter->DeviceLock);
  116. }
  117. }
  118. //
  119. // Now free the receive buffer back.
  120. //
  121. IPX_PUSH_ENTRY_LIST(
  122. &Adapter->ReceiveBufferList,
  123. &Reserved->ReceiveBuffer->PoolLinkage,
  124. &Adapter->Device->SListsLock);
  125. Reserved->ReceiveBuffer = NULL;
  126. }
  127. } else {
  128. //IpxPrint0("IpxTransferDataComplete: Calling PassDgToRt\n");
  129. //ByteOffset = sizeof(IPX_HEADER);
  130. ByteOffset = 0;
  131. PassDgToRt(IpxDevice, Reserved->pContext, Reserved->Index,
  132. &Reserved->ReceiveBuffer->Data[ByteOffset],
  133. BytesTransferred);
  134. //
  135. // Free the memory allocated for options.
  136. //
  137. IpxFreeMemory(Reserved->pContext, sizeof(IPX_DATAGRAM_OPTIONS2),
  138. MEMORY_PACKET, "RT OPTIONS");
  139. //
  140. // Now free the receive buffer back.
  141. //
  142. IPX_PUSH_ENTRY_LIST(
  143. &Adapter->ReceiveBufferList,
  144. &Reserved->ReceiveBuffer->PoolLinkage,
  145. Adapter->DeviceLock);
  146. Reserved->ReceiveBuffer = NULL;
  147. }
  148. //
  149. // Now free the packet.
  150. //
  151. NdisReinitializePacket (NdisPacket);
  152. if (Reserved->OwnedByAddress) {
  153. // Reserved->Address->ReceivePacketInUse = FALSE;
  154. InterlockedDecrement(&Reserved->Address->ReceivePacketInUse);
  155. } else {
  156. Device = Adapter->Device;
  157. IPX_PUSH_ENTRY_LIST(
  158. &Device->ReceivePacketList,
  159. &Reserved->PoolLinkage,
  160. &Device->SListsLock);
  161. }
  162. if (!Reserved->pContext) {
  163. //
  164. // We Delay inserting the last request (or the only one)
  165. // until after we have put the packet back, to keep the
  166. // address around if needed (the address won't go away
  167. // until the last address file does, and the address file
  168. // won't go away until the datagram is completed).
  169. //
  170. IPX_INSERT_TAIL_LIST(
  171. &Adapter->RequestCompletionQueue,
  172. REQUEST_LINKAGE(LastRequest),
  173. Adapter->DeviceLock);
  174. }
  175. IpxReceiveComplete ((NDIS_HANDLE)Adapter);
  176. break;
  177. default:
  178. Device = Adapter->Device;
  179. (*Device->UpperDrivers[Reserved->Identifier].TransferDataCompleteHandler)(
  180. NdisPacket,
  181. NdisStatus,
  182. BytesTransferred);
  183. break;
  184. }
  185. } /* IpxTransferDataComplete */
  186. VOID
  187. IpxTransferData(
  188. OUT PNDIS_STATUS Status,
  189. IN NDIS_HANDLE NdisBindingHandle,
  190. IN NDIS_HANDLE MacReceiveContext,
  191. IN UINT ByteOffset,
  192. IN UINT BytesToTransfer,
  193. IN OUT PNDIS_PACKET Packet,
  194. OUT PUINT BytesTransferred
  195. )
  196. /*++
  197. Routine Description:
  198. This routine is called by all tightly bound clients instead of NdisTransferData.
  199. If this is a loopback packet, the transfer is done directly here, else NdisTransferData
  200. is called.
  201. Arguments:
  202. Status - status of operation
  203. NdisBindingHandle - Loopback cookie or Ndis context
  204. MacReceiveContext - Loopback packet or Mac context
  205. ByteOffset - Source offset
  206. BytesToTransfer - length of the transfer desired
  207. Packet - dest packet
  208. BytesTransferred - length of successful transfer
  209. Return Value:
  210. NTSTATUS - status of operation.
  211. --*/
  212. {
  213. //
  214. // If this is a loopback packet, copy the data directly
  215. //
  216. if (NdisBindingHandle == (PVOID)IPX_LOOPBACK_COOKIE) {
  217. IPX_DEBUG (LOOPB, ("LoopbXfer: src: %lx, dest: %lx, bytestoxfer: %lx\n",
  218. MacReceiveContext, Packet, BytesToTransfer));
  219. NdisCopyFromPacketToPacketSafe(
  220. Packet, // Destination
  221. 0, // DestinationOffset
  222. BytesToTransfer, // BytesToCopy
  223. (PNDIS_PACKET)MacReceiveContext, // Source
  224. ByteOffset, // SourceOffset
  225. BytesTransferred, // BytesCopied
  226. NormalPagePriority);
  227. *Status = ((*BytesTransferred == BytesToTransfer)? NDIS_STATUS_SUCCESS : NDIS_STATUS_RESOURCES);
  228. } else {
  229. NdisTransferData(
  230. Status,
  231. NdisBindingHandle,
  232. MacReceiveContext,
  233. ByteOffset,
  234. BytesToTransfer,
  235. Packet,
  236. BytesTransferred);
  237. }
  238. }
  239. NTSTATUS
  240. IpxTdiReceiveDatagram(
  241. IN PREQUEST Request
  242. )
  243. /*++
  244. Routine Description:
  245. This routine performs the TdiReceiveDatagram request for the transport
  246. provider. Receive datagrams just get queued up to an address, and are
  247. completed when a DATAGRAM or DATAGRAM_BROADCAST frame is received at
  248. the address.
  249. Arguments:
  250. Irp - I/O Request Packet for this request.
  251. Return Value:
  252. NTSTATUS - status of operation.
  253. --*/
  254. {
  255. PADDRESS Address;
  256. PADDRESS_FILE AddressFile;
  257. IPX_DEFINE_SYNC_CONTEXT (SyncContext)
  258. IPX_DEFINE_LOCK_HANDLE (LockHandle)
  259. //
  260. // Do a quick check of the validity of the address.
  261. //
  262. AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
  263. if ((AddressFile->Size != sizeof (ADDRESS_FILE)) ||
  264. (AddressFile->Type != IPX_ADDRESSFILE_SIGNATURE)) {
  265. return STATUS_INVALID_HANDLE;
  266. }
  267. Address = AddressFile->Address;
  268. if ((Address == NULL) ||
  269. (Address->Size != sizeof (ADDRESS)) ||
  270. (Address->Type != IPX_ADDRESS_SIGNATURE)) {
  271. return STATUS_INVALID_HANDLE;
  272. }
  273. IPX_BEGIN_SYNC (&SyncContext);
  274. IPX_GET_LOCK (&Address->Lock, &LockHandle);
  275. if (AddressFile->State != ADDRESSFILE_STATE_OPEN) {
  276. IPX_FREE_LOCK (&Address->Lock, LockHandle);
  277. IPX_END_SYNC (&SyncContext);
  278. return STATUS_INVALID_HANDLE;
  279. }
  280. InsertTailList (&AddressFile->ReceiveDatagramQueue, REQUEST_LINKAGE(Request));
  281. IoSetCancelRoutine (Request, IpxCancelReceiveDatagram);
  282. if (Request->Cancel) {
  283. (VOID)RemoveTailList (&AddressFile->ReceiveDatagramQueue);
  284. IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
  285. IPX_FREE_LOCK (&Address->Lock, LockHandle);
  286. IPX_END_SYNC (&SyncContext);
  287. return STATUS_CANCELLED;
  288. }
  289. IPX_DEBUG (RECEIVE, ("RDG posted on %lx\n", AddressFile));
  290. IpxReferenceAddressFileLock (AddressFile, AFREF_RCV_DGRAM);
  291. IPX_FREE_LOCK (&Address->Lock, LockHandle);
  292. IPX_END_SYNC (&SyncContext);
  293. return STATUS_PENDING;
  294. } /* IpxTdiReceiveDatagram */
  295. VOID
  296. IpxCancelReceiveDatagram(
  297. IN PDEVICE_OBJECT DeviceObject,
  298. IN PIRP Irp
  299. )
  300. /*++
  301. Routine Description:
  302. This routine is called by the I/O system to cancel a receive
  303. datagram. The datagram is found on the address file's receive
  304. datagram queue.
  305. NOTE: This routine is called with the CancelSpinLock held and
  306. is responsible for releasing it.
  307. Arguments:
  308. DeviceObject - Pointer to the device object for this driver.
  309. Irp - Pointer to the request packet representing the I/O request.
  310. Return Value:
  311. none.
  312. --*/
  313. {
  314. PLIST_ENTRY p;
  315. PADDRESS_FILE AddressFile;
  316. PADDRESS Address;
  317. PREQUEST Request = (PREQUEST)Irp;
  318. BOOLEAN Found;
  319. IPX_DEFINE_LOCK_HANDLE (LockHandle)
  320. CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
  321. (REQUEST_MINOR_FUNCTION(Request) == TDI_RECEIVE_DATAGRAM));
  322. CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_TRANSPORT_ADDRESS_FILE);
  323. AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
  324. Address = AddressFile->Address;
  325. Found = FALSE;
  326. IPX_GET_LOCK (&Address->Lock, &LockHandle);
  327. for (p = AddressFile->ReceiveDatagramQueue.Flink;
  328. p != &AddressFile->ReceiveDatagramQueue;
  329. p = p->Flink) {
  330. if (LIST_ENTRY_TO_REQUEST(p) == Request) {
  331. RemoveEntryList (p);
  332. Found = TRUE;
  333. break;
  334. }
  335. }
  336. IPX_FREE_LOCK (&Address->Lock, LockHandle);
  337. IoReleaseCancelSpinLock (Irp->CancelIrql);
  338. if (Found) {
  339. IPX_DEBUG(RECEIVE, ("Cancelled datagram on %lx\n", AddressFile));
  340. REQUEST_INFORMATION(Request) = 0;
  341. REQUEST_STATUS(Request) = STATUS_CANCELLED;
  342. IpxCompleteRequest (Request);
  343. ASSERT( DeviceObject->DeviceExtension == IpxDevice );
  344. IpxFreeRequest(IpxDevice, Request);
  345. IpxDereferenceAddressFile (AddressFile, AFREF_RCV_DGRAM);
  346. }
  347. } /* IpxCancelReceiveDatagram */