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.

320 lines
8.1 KiB

  1. /*++
  2. Copyright (c) 1989, 1990, 1991 Microsoft Corporation
  3. Module Name:
  4. rcv.c
  5. Abstract:
  6. This module contains code which performs the following TDI services:
  7. o TdiReceive
  8. o TdiReceiveDatagram
  9. Author:
  10. David Beaver (dbeaver) 1-July-1991
  11. Environment:
  12. Kernel mode
  13. Revision History:
  14. --*/
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. NTSTATUS
  18. NbfTdiReceive(
  19. IN PIRP Irp
  20. )
  21. /*++
  22. Routine Description:
  23. This routine performs the TdiReceive request for the transport provider.
  24. Arguments:
  25. Irp - I/O Request Packet for this request.
  26. Return Value:
  27. NTSTATUS - status of operation.
  28. --*/
  29. {
  30. NTSTATUS status;
  31. PTP_CONNECTION connection;
  32. KIRQL oldirql;
  33. PIO_STACK_LOCATION irpSp;
  34. //
  35. // verify that the operation is taking place on a connection. At the same
  36. // time we do this, we reference the connection. This ensures it does not
  37. // get removed out from under us. Note also that we do the connection
  38. // lookup within a try/except clause, thus protecting ourselves against
  39. // really bogus handles
  40. //
  41. irpSp = IoGetCurrentIrpStackLocation (Irp);
  42. connection = irpSp->FileObject->FsContext;
  43. IF_NBFDBG (NBF_DEBUG_RCVENG) {
  44. NbfPrint2 ("NbfTdiReceive: Received IRP %lx on connection %lx\n",
  45. Irp, connection);
  46. }
  47. //
  48. // Check that this is really a connection.
  49. //
  50. if ((irpSp->FileObject->FsContext2 == UlongToPtr(NBF_FILE_TYPE_CONTROL)) ||
  51. (connection->Size != sizeof (TP_CONNECTION)) ||
  52. (connection->Type != NBF_CONNECTION_SIGNATURE)) {
  53. #if DBG
  54. NbfPrint2 ("TdiReceive: Invalid Connection %lx Irp %lx\n", connection, Irp);
  55. #endif
  56. return STATUS_INVALID_CONNECTION;
  57. }
  58. //
  59. // Initialize bytes transferred here.
  60. //
  61. Irp->IoStatus.Information = 0; // reset byte transfer count.
  62. // This reference is removed by NbfDestroyRequest.
  63. KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
  64. ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  65. if ((connection->Flags & CONNECTION_FLAGS_READY) == 0) {
  66. RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  67. Irp->IoStatus.Status = connection->Status;
  68. IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
  69. status = STATUS_PENDING;
  70. } else {
  71. KIRQL cancelIrql;
  72. //
  73. // Once the reference is in, LinkSpinLock will be valid.
  74. //
  75. NbfReferenceConnection("TdiReceive request", connection, CREF_RECEIVE_IRP);
  76. RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  77. IoAcquireCancelSpinLock(&cancelIrql);
  78. ACQUIRE_DPC_SPIN_LOCK (connection->LinkSpinLock);
  79. IRP_RECEIVE_IRP(irpSp) = Irp;
  80. IRP_RECEIVE_REFCOUNT(irpSp) = 1;
  81. #if DBG
  82. NbfReceives[NbfReceivesNext].Irp = Irp;
  83. NbfReceives[NbfReceivesNext].Request = NULL;
  84. NbfReceives[NbfReceivesNext].Connection = (PVOID)connection;
  85. NbfReceivesNext = (NbfReceivesNext++) % TRACK_TDI_LIMIT;
  86. #endif
  87. //
  88. // If this IRP has been cancelled, complete it now.
  89. //
  90. if (Irp->Cancel) {
  91. #if DBG
  92. NbfCompletedReceives[NbfCompletedReceivesNext].Irp = Irp;
  93. NbfCompletedReceives[NbfCompletedReceivesNext].Request = NULL;
  94. NbfCompletedReceives[NbfCompletedReceivesNext].Status = STATUS_CANCELLED;
  95. {
  96. ULONG i,j,k;
  97. PUCHAR va;
  98. PMDL mdl;
  99. mdl = Irp->MdlAddress;
  100. NbfCompletedReceives[NbfCompletedReceivesNext].Contents[0] = (UCHAR)0;
  101. i = 1;
  102. while (i<TRACK_TDI_CAPTURE) {
  103. if (mdl == NULL) break;
  104. va = MmGetSystemAddressForMdl (mdl);
  105. j = MmGetMdlByteCount (mdl);
  106. for (i=i,k=0;(i<TRACK_TDI_CAPTURE)&&(k<j);i++,k++) {
  107. NbfCompletedReceives[NbfCompletedReceivesNext].Contents[i] = *va++;
  108. }
  109. mdl = mdl->Next;
  110. }
  111. }
  112. NbfCompletedReceivesNext = (NbfCompletedReceivesNext++) % TRACK_TDI_LIMIT;
  113. #endif
  114. //
  115. // It is safe to do this with locks held.
  116. //
  117. NbfCompleteReceiveIrp (Irp, STATUS_CANCELLED, 0);
  118. RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
  119. IoReleaseCancelSpinLock(cancelIrql);
  120. } else {
  121. //
  122. // Insert onto the receive queue, and make the IRP
  123. // cancellable.
  124. //
  125. InsertTailList (&connection->ReceiveQueue,&Irp->Tail.Overlay.ListEntry);
  126. IoSetCancelRoutine(Irp, NbfCancelReceive);
  127. //
  128. // Release the cancel spinlock out of order. Since we were
  129. // already at dpc level when it was acquired, we don't
  130. // need to swap irqls.
  131. //
  132. ASSERT(cancelIrql == DISPATCH_LEVEL);
  133. IoReleaseCancelSpinLock(cancelIrql);
  134. //
  135. // This call releases the link spinlock, and references the
  136. // connection first if it needs to access it after
  137. // releasing the lock.
  138. //
  139. AwakenReceive (connection); // awaken if sleeping.
  140. }
  141. status = STATUS_PENDING;
  142. }
  143. KeLowerIrql (oldirql);
  144. return status;
  145. } /* TdiReceive */
  146. NTSTATUS
  147. NbfTdiReceiveDatagram(
  148. IN PIRP Irp
  149. )
  150. /*++
  151. Routine Description:
  152. This routine performs the TdiReceiveDatagram request for the transport
  153. provider. Receive datagrams just get queued up to an address, and are
  154. completed when a DATAGRAM or DATAGRAM_BROADCAST frame is received at
  155. the address.
  156. Arguments:
  157. Irp - I/O Request Packet for this request.
  158. Return Value:
  159. NTSTATUS - status of operation.
  160. --*/
  161. {
  162. NTSTATUS status;
  163. KIRQL oldirql;
  164. PTP_ADDRESS address;
  165. PTP_ADDRESS_FILE addressFile;
  166. PIO_STACK_LOCATION irpSp;
  167. KIRQL cancelIrql;
  168. //
  169. // verify that the operation is taking place on an address. At the same
  170. // time we do this, we reference the address. This ensures it does not
  171. // get removed out from under us. Note also that we do the address
  172. // lookup within a try/except clause, thus protecting ourselves against
  173. // really bogus handles
  174. //
  175. irpSp = IoGetCurrentIrpStackLocation (Irp);
  176. if (irpSp->FileObject->FsContext2 != (PVOID) TDI_TRANSPORT_ADDRESS_FILE) {
  177. return STATUS_INVALID_ADDRESS;
  178. }
  179. addressFile = irpSp->FileObject->FsContext;
  180. status = NbfVerifyAddressObject (addressFile);
  181. if (!NT_SUCCESS (status)) {
  182. return status;
  183. }
  184. #if DBG
  185. if (((PTDI_REQUEST_KERNEL_RECEIVEDG)(&irpSp->Parameters))->ReceiveLength > 0) {
  186. ASSERT (Irp->MdlAddress != NULL);
  187. }
  188. #endif
  189. address = addressFile->Address;
  190. IoAcquireCancelSpinLock(&cancelIrql);
  191. ACQUIRE_SPIN_LOCK (&address->SpinLock,&oldirql);
  192. if ((address->Flags & (ADDRESS_FLAGS_STOPPING | ADDRESS_FLAGS_CONFLICT)) != 0) {
  193. RELEASE_SPIN_LOCK (&address->SpinLock,oldirql);
  194. IoReleaseCancelSpinLock(cancelIrql);
  195. Irp->IoStatus.Information = 0;
  196. Irp->IoStatus.Status = (address->Flags & ADDRESS_FLAGS_STOPPING) ?
  197. STATUS_NETWORK_NAME_DELETED : STATUS_DUPLICATE_NAME;
  198. IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
  199. } else {
  200. //
  201. // If this IRP has been cancelled, then call the
  202. // cancel routine.
  203. //
  204. if (Irp->Cancel) {
  205. RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
  206. IoReleaseCancelSpinLock(cancelIrql);
  207. Irp->IoStatus.Information = 0;
  208. Irp->IoStatus.Status = STATUS_CANCELLED;
  209. IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
  210. } else {
  211. IoSetCancelRoutine(Irp, NbfCancelReceiveDatagram);
  212. NbfReferenceAddress ("Receive datagram", address, AREF_REQUEST);
  213. InsertTailList (&addressFile->ReceiveDatagramQueue,&Irp->Tail.Overlay.ListEntry);
  214. RELEASE_SPIN_LOCK (&address->SpinLock,oldirql);
  215. IoReleaseCancelSpinLock(cancelIrql);
  216. }
  217. }
  218. NbfDereferenceAddress ("Temp rcv datagram", address, AREF_VERIFY);
  219. return STATUS_PENDING;
  220. } /* TdiReceiveDatagram */