Leaked source code of windows server 2003
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.

495 lines
13 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. send.c
  5. Abstract:
  6. NDIS protocol entry points and utility routines to handle sending
  7. data.
  8. Environment:
  9. Kernel mode only.
  10. Revision History:
  11. arvindm 4/10/2000 Created
  12. --*/
  13. #include "precomp.h"
  14. #define __FILENUMBER 'DNES'
  15. NTSTATUS
  16. NdisuioWrite(
  17. IN PDEVICE_OBJECT pDeviceObject,
  18. IN PIRP pIrp
  19. )
  20. /*++
  21. Routine Description:
  22. Dispatch routine to handle IRP_MJ_WRITE.
  23. Arguments:
  24. pDeviceObject - pointer to our device object
  25. pIrp - Pointer to request packet
  26. Return Value:
  27. NT status code.
  28. --*/
  29. {
  30. PIO_STACK_LOCATION pIrpSp;
  31. ULONG DataLength;
  32. NTSTATUS NtStatus;
  33. NDIS_STATUS Status;
  34. PNDISUIO_OPEN_CONTEXT pOpenContext;
  35. PNDIS_PACKET pNdisPacket;
  36. PNDIS_BUFFER pNdisBuffer;
  37. NDISUIO_ETH_HEADER UNALIGNED *pEthHeader;
  38. #ifdef NDIS51
  39. PVOID CancelId;
  40. #endif
  41. UNREFERENCED_PARAMETER(pDeviceObject);
  42. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  43. pOpenContext = pIrpSp->FileObject->FsContext;
  44. pNdisPacket = NULL;
  45. do
  46. {
  47. if (pOpenContext == NULL)
  48. {
  49. DEBUGP(DL_WARN, ("Write: FileObject %p not yet associated with a device\n",
  50. pIrpSp->FileObject));
  51. NtStatus = STATUS_INVALID_HANDLE;
  52. break;
  53. }
  54. NUIO_STRUCT_ASSERT(pOpenContext, oc);
  55. if (pIrp->MdlAddress == NULL)
  56. {
  57. DEBUGP(DL_FATAL, ("Write: NULL MDL address on IRP %p\n", pIrp));
  58. NtStatus = STATUS_INVALID_PARAMETER;
  59. break;
  60. }
  61. //
  62. // Try to get a virtual address for the MDL.
  63. //
  64. #ifndef WIN9X
  65. pEthHeader = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority);
  66. if (pEthHeader == NULL)
  67. {
  68. DEBUGP(DL_FATAL, ("Write: MmGetSystemAddr failed for"
  69. " IRP %p, MDL %p\n",
  70. pIrp, pIrp->MdlAddress));
  71. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  72. break;
  73. }
  74. #else
  75. pEthHeader = MmGetSystemAddressForMdl(pIrp->MdlAddress); // for Win9X
  76. #endif
  77. //
  78. // Sanity-check the length.
  79. //
  80. DataLength = MmGetMdlByteCount(pIrp->MdlAddress);
  81. if (DataLength < sizeof(NDISUIO_ETH_HEADER))
  82. {
  83. DEBUGP(DL_WARN, ("Write: too small to be a valid packet (%d bytes)\n",
  84. DataLength));
  85. NtStatus = STATUS_BUFFER_TOO_SMALL;
  86. break;
  87. }
  88. if (DataLength > (pOpenContext->MaxFrameSize + sizeof(NDISUIO_ETH_HEADER)))
  89. {
  90. DEBUGP(DL_WARN, ("Write: Open %p: data length (%d)"
  91. " larger than max frame size (%d)\n",
  92. pOpenContext, DataLength, pOpenContext->MaxFrameSize));
  93. NtStatus = STATUS_INVALID_BUFFER_SIZE;
  94. break;
  95. }
  96. if (pEthHeader->EthType != Globals.EthType)
  97. {
  98. DEBUGP(DL_WARN, ("Write: Failing send with EthType %x\n",
  99. pEthHeader->EthType));
  100. NtStatus = STATUS_INVALID_PARAMETER;
  101. break;
  102. }
  103. if (!NUIO_MEM_CMP(pEthHeader->SrcAddr, pOpenContext->CurrentAddress, NUIO_MAC_ADDR_LEN))
  104. {
  105. DEBUGP(DL_WARN, ("Write: Failing with invalid Source address"));
  106. NtStatus = STATUS_INVALID_PARAMETER;
  107. break;
  108. }
  109. NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  110. if (!NUIO_TEST_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_ACTIVE))
  111. {
  112. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  113. DEBUGP(DL_FATAL, ("Write: Open %p is not bound"
  114. " or in low power state\n", pOpenContext));
  115. NtStatus = STATUS_INVALID_HANDLE;
  116. break;
  117. }
  118. //
  119. // Allocate a send packet.
  120. //
  121. NUIO_ASSERT(pOpenContext->SendPacketPool != NULL);
  122. NdisAllocatePacket(
  123. &Status,
  124. &pNdisPacket,
  125. pOpenContext->SendPacketPool);
  126. if (Status != NDIS_STATUS_SUCCESS)
  127. {
  128. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  129. DEBUGP(DL_FATAL, ("Write: open %p, failed to alloc send pkt\n",
  130. pOpenContext));
  131. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  132. break;
  133. }
  134. //
  135. // Allocate a send buffer if necessary.
  136. //
  137. if (pOpenContext->bRunningOnWin9x)
  138. {
  139. NdisAllocateBuffer(
  140. &Status,
  141. &pNdisBuffer,
  142. pOpenContext->SendBufferPool,
  143. pEthHeader,
  144. DataLength);
  145. if (Status != NDIS_STATUS_SUCCESS)
  146. {
  147. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  148. NdisFreePacket(pNdisPacket);
  149. DEBUGP(DL_FATAL, ("Write: open %p, failed to alloc send buf\n",
  150. pOpenContext));
  151. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  152. break;
  153. }
  154. }
  155. else
  156. {
  157. pNdisBuffer = pIrp->MdlAddress;
  158. }
  159. NdisInterlockedIncrement((PLONG)&pOpenContext->PendedSendCount);
  160. NUIO_REF_OPEN(pOpenContext); // pended send
  161. IoMarkIrpPending(pIrp);
  162. //
  163. // Initialize the packet ref count. This packet will be freed
  164. // when this count goes to zero.
  165. //
  166. NUIO_SEND_PKT_RSVD(pNdisPacket)->RefCount = 1;
  167. #ifdef NDIS51
  168. //
  169. // NDIS 5.1 supports cancelling sends. We set up a cancel ID on
  170. // each send packet (which maps to a Write IRP), and save the
  171. // packet pointer in the IRP. If the IRP gets cancelled, we use
  172. // NdisCancelSendPackets() to cancel the packet.
  173. //
  174. CancelId = NUIO_GET_NEXT_CANCEL_ID();
  175. NDIS_SET_PACKET_CANCEL_ID(pNdisPacket, CancelId);
  176. pIrp->Tail.Overlay.DriverContext[0] = (PVOID)pOpenContext;
  177. pIrp->Tail.Overlay.DriverContext[1] = (PVOID)pNdisPacket;
  178. NUIO_INSERT_TAIL_LIST(&pOpenContext->PendedWrites, &pIrp->Tail.Overlay.ListEntry);
  179. IoSetCancelRoutine(pIrp, NdisuioCancelWrite);
  180. #endif // NDIS51
  181. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  182. //
  183. // Set a back pointer from the packet to the IRP.
  184. //
  185. NUIO_IRP_FROM_SEND_PKT(pNdisPacket) = pIrp;
  186. NtStatus = STATUS_PENDING;
  187. pNdisBuffer->Next = NULL;
  188. NdisChainBufferAtFront(pNdisPacket, pNdisBuffer);
  189. #if SEND_DBG
  190. {
  191. PUCHAR pData;
  192. #ifndef WIN9X
  193. pData = MmGetSystemAddressForMdlSafe(pNdisBuffer, NormalPagePriority);
  194. NUIO_ASSERT(pEthHeader == pData);
  195. #else
  196. pData = MmGetSystemAddressForMdl(pNdisBuffer); // Win9x
  197. #endif
  198. DEBUGP(DL_VERY_LOUD,
  199. ("Write: MDL %p, MdlFlags %x, SystemAddr %p, %d bytes\n",
  200. pIrp->MdlAddress, pIrp->MdlAddress->MdlFlags, pData, DataLength));
  201. DEBUGPDUMP(DL_VERY_LOUD, pData, MIN(DataLength, 48));
  202. }
  203. #endif // SEND_DBG
  204. NdisSendPackets(pOpenContext->BindingHandle, &pNdisPacket, 1);
  205. }
  206. while (FALSE);
  207. if (NtStatus != STATUS_PENDING)
  208. {
  209. pIrp->IoStatus.Status = NtStatus;
  210. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  211. }
  212. return (NtStatus);
  213. }
  214. #ifdef NDIS51
  215. VOID
  216. NdisuioCancelWrite(
  217. IN PDEVICE_OBJECT pDeviceObject,
  218. IN PIRP pIrp
  219. )
  220. /*++
  221. Routine Description:
  222. Cancel a pending write IRP. This routine attempt to cancel the NDIS send.
  223. Arguments:
  224. pDeviceObject - pointer to our device object
  225. pIrp - IRP to be cancelled
  226. Return Value:
  227. None
  228. --*/
  229. {
  230. PNDISUIO_OPEN_CONTEXT pOpenContext;
  231. PLIST_ENTRY pIrpEntry;
  232. PNDIS_PACKET pNdisPacket;
  233. UNREFERENCED_PARAMETER(pDeviceObject);
  234. IoReleaseCancelSpinLock(pIrp->CancelIrql);
  235. //
  236. // The NDIS packet representing this Write IRP.
  237. //
  238. pNdisPacket = NULL;
  239. pOpenContext = (PNDISUIO_OPEN_CONTEXT) pIrp->Tail.Overlay.DriverContext[0];
  240. NUIO_STRUCT_ASSERT(pOpenContext, oc);
  241. //
  242. // Try to locate the IRP in the pended write queue. The send completion
  243. // routine may be running and might have removed it from there.
  244. //
  245. NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  246. for (pIrpEntry = pOpenContext->PendedWrites.Flink;
  247. pIrpEntry != &pOpenContext->PendedWrites;
  248. pIrpEntry = pIrpEntry->Flink)
  249. {
  250. if (pIrp == CONTAINING_RECORD(pIrpEntry, IRP, Tail.Overlay.ListEntry))
  251. {
  252. pNdisPacket = (PNDIS_PACKET) pIrp->Tail.Overlay.DriverContext[1];
  253. //
  254. // Place a reference on this packet so that it won't get
  255. // freed/reused until we are done with it.
  256. //
  257. NUIO_REF_SEND_PKT(pNdisPacket);
  258. break;
  259. }
  260. }
  261. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  262. if (pNdisPacket != NULL)
  263. {
  264. //
  265. // Either the send completion routine hasn't run, or we got a peak
  266. // at the IRP/packet before it had a chance to take it out of the
  267. // pending IRP queue.
  268. //
  269. // We do not complete the IRP here - note that we didn't dequeue it
  270. // above. This is because we always want the send complete routine to
  271. // complete the IRP. And this in turn is because the packet that was
  272. // prepared from the IRP has a buffer chain pointing to data associated
  273. // with this IRP. Therefore we cannot complete the IRP before the driver
  274. // below us is done with the data it pointed to.
  275. //
  276. //
  277. // Request NDIS to cancel this send. The result of this call is that
  278. // our SendComplete handler will be called (if not already called).
  279. //
  280. DEBUGP(DL_INFO, ("CancelWrite: cancelling pkt %p on Open %p\n",
  281. pNdisPacket, pOpenContext));
  282. NdisCancelSendPackets(
  283. pOpenContext->BindingHandle,
  284. NDIS_GET_PACKET_CANCEL_ID(pNdisPacket)
  285. );
  286. //
  287. // It is now safe to remove the reference we had placed on the packet.
  288. //
  289. NUIO_DEREF_SEND_PKT(pNdisPacket);
  290. }
  291. //
  292. // else the send completion routine has already picked up this IRP.
  293. //
  294. }
  295. #endif // NDIS51
  296. VOID
  297. NdisuioSendComplete(
  298. IN NDIS_HANDLE ProtocolBindingContext,
  299. IN PNDIS_PACKET pNdisPacket,
  300. IN NDIS_STATUS Status
  301. )
  302. /*++
  303. Routine Description:
  304. NDIS entry point called to signify completion of a packet send.
  305. We pick up and complete the Write IRP corresponding to this packet.
  306. NDIS 5.1:
  307. Arguments:
  308. ProtocolBindingContext - pointer to open context
  309. pNdisPacket - packet that completed send
  310. Status - status of send
  311. Return Value:
  312. None
  313. --*/
  314. {
  315. PIRP pIrp;
  316. PIO_STACK_LOCATION pIrpSp;
  317. PNDISUIO_OPEN_CONTEXT pOpenContext;
  318. pOpenContext = (PNDISUIO_OPEN_CONTEXT)ProtocolBindingContext;
  319. NUIO_STRUCT_ASSERT(pOpenContext, oc);
  320. pIrp = NUIO_IRP_FROM_SEND_PKT(pNdisPacket);
  321. if (pOpenContext->bRunningOnWin9x)
  322. {
  323. //
  324. // We would have attached our own NDIS_BUFFER. Take it out
  325. // and free it.
  326. //
  327. #ifndef NDIS51
  328. PNDIS_BUFFER pNdisBuffer;
  329. PVOID VirtualAddr;
  330. UINT BufferLength;
  331. UINT TotalLength;
  332. #endif
  333. #ifdef NDIS51
  334. NUIO_ASSERT(FALSE); // NDIS 5.1 not on Win9X!
  335. #else
  336. NdisGetFirstBufferFromPacket(
  337. pNdisPacket,
  338. &pNdisBuffer,
  339. &VirtualAddr,
  340. &BufferLength,
  341. &TotalLength);
  342. NUIO_ASSERT(pNdisBuffer != NULL);
  343. NdisFreeBuffer(pNdisBuffer);
  344. #endif
  345. }
  346. #ifdef NDIS51
  347. IoSetCancelRoutine(pIrp, NULL);
  348. NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  349. NUIO_REMOVE_ENTRY_LIST(&pIrp->Tail.Overlay.ListEntry);
  350. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  351. #endif
  352. //
  353. // We are done with the NDIS_PACKET:
  354. //
  355. NUIO_DEREF_SEND_PKT(pNdisPacket);
  356. //
  357. // Complete the Write IRP with the right status.
  358. //
  359. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  360. if (Status == NDIS_STATUS_SUCCESS)
  361. {
  362. pIrp->IoStatus.Information = pIrpSp->Parameters.Write.Length;
  363. pIrp->IoStatus.Status = STATUS_SUCCESS;
  364. }
  365. else
  366. {
  367. pIrp->IoStatus.Information = 0;
  368. pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  369. }
  370. DEBUGP(DL_INFO, ("SendComplete: packet %p/IRP %p/Length %d "
  371. "completed with status %x\n",
  372. pNdisPacket, pIrp, pIrp->IoStatus.Information, pIrp->IoStatus.Status));
  373. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  374. NdisInterlockedDecrement((PLONG)&pOpenContext->PendedSendCount);
  375. NUIO_DEREF_OPEN(pOpenContext); // send complete - dequeued send IRP
  376. }