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.

493 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. NdisProtWrite(
  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. PNDISPROT_OPEN_CONTEXT pOpenContext;
  35. PNDIS_PACKET pNdisPacket;
  36. PNDIS_BUFFER pNdisBuffer;
  37. NDISPROT_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. NPROT_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(NDISPROT_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(NDISPROT_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. //
  97. // To prevent applications from sending packets with spoofed
  98. // mac address, we will do the following check to make sure the source
  99. // address in the packet is same as the current MAC address of the NIC.
  100. //
  101. if ((pIrp->RequestorMode == UserMode) &&
  102. !NPROT_MEM_CMP(pEthHeader->SrcAddr, pOpenContext->CurrentAddress, NPROT_MAC_ADDR_LEN))
  103. {
  104. DEBUGP(DL_WARN, ("Write: Failing with invalid Source address"));
  105. NtStatus = STATUS_INVALID_PARAMETER;
  106. break;
  107. }
  108. NPROT_ACQUIRE_LOCK(&pOpenContext->Lock);
  109. if (!NPROT_TEST_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_ACTIVE))
  110. {
  111. NPROT_RELEASE_LOCK(&pOpenContext->Lock);
  112. DEBUGP(DL_FATAL, ("Write: Open %p is not bound"
  113. " or in low power state\n", pOpenContext));
  114. NtStatus = STATUS_INVALID_HANDLE;
  115. break;
  116. }
  117. //
  118. // Allocate a send packet.
  119. //
  120. NPROT_ASSERT(pOpenContext->SendPacketPool != NULL);
  121. NdisAllocatePacket(
  122. &Status,
  123. &pNdisPacket,
  124. pOpenContext->SendPacketPool);
  125. if (Status != NDIS_STATUS_SUCCESS)
  126. {
  127. NPROT_RELEASE_LOCK(&pOpenContext->Lock);
  128. DEBUGP(DL_FATAL, ("Write: open %p, failed to alloc send pkt\n",
  129. pOpenContext));
  130. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  131. break;
  132. }
  133. //
  134. // Allocate a send buffer if necessary.
  135. //
  136. if (pOpenContext->bRunningOnWin9x)
  137. {
  138. NdisAllocateBuffer(
  139. &Status,
  140. &pNdisBuffer,
  141. pOpenContext->SendBufferPool,
  142. pEthHeader,
  143. DataLength);
  144. if (Status != NDIS_STATUS_SUCCESS)
  145. {
  146. NPROT_RELEASE_LOCK(&pOpenContext->Lock);
  147. NdisFreePacket(pNdisPacket);
  148. DEBUGP(DL_FATAL, ("Write: open %p, failed to alloc send buf\n",
  149. pOpenContext));
  150. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  151. break;
  152. }
  153. }
  154. else
  155. {
  156. pNdisBuffer = pIrp->MdlAddress;
  157. }
  158. NdisInterlockedIncrement((PLONG)&pOpenContext->PendedSendCount);
  159. NPROT_REF_OPEN(pOpenContext); // pended send
  160. IoMarkIrpPending(pIrp);
  161. //
  162. // Initialize the packet ref count. This packet will be freed
  163. // when this count goes to zero.
  164. //
  165. NPROT_SEND_PKT_RSVD(pNdisPacket)->RefCount = 1;
  166. #ifdef NDIS51
  167. //
  168. // NDIS 5.1 supports cancelling sends. We set up a cancel ID on
  169. // each send packet (which maps to a Write IRP), and save the
  170. // packet pointer in the IRP. If the IRP gets cancelled, we use
  171. // NdisCancelSendPackets() to cancel the packet.
  172. //
  173. CancelId = NPROT_GET_NEXT_CANCEL_ID();
  174. NDIS_SET_PACKET_CANCEL_ID(pNdisPacket, CancelId);
  175. pIrp->Tail.Overlay.DriverContext[0] = (PVOID)pOpenContext;
  176. pIrp->Tail.Overlay.DriverContext[1] = (PVOID)pNdisPacket;
  177. NPROT_INSERT_TAIL_LIST(&pOpenContext->PendedWrites, &pIrp->Tail.Overlay.ListEntry);
  178. IoSetCancelRoutine(pIrp, NdisProtCancelWrite);
  179. #endif // NDIS51
  180. NPROT_RELEASE_LOCK(&pOpenContext->Lock);
  181. //
  182. // Set a back pointer from the packet to the IRP.
  183. //
  184. NPROT_IRP_FROM_SEND_PKT(pNdisPacket) = pIrp;
  185. NtStatus = STATUS_PENDING;
  186. pNdisBuffer->Next = NULL;
  187. NdisChainBufferAtFront(pNdisPacket, pNdisBuffer);
  188. #if SEND_DBG
  189. {
  190. PUCHAR pData;
  191. #ifndef WIN9X
  192. pData = MmGetSystemAddressForMdlSafe(pNdisBuffer, NormalPagePriority);
  193. NPROT_ASSERT(pEthHeader == pData);
  194. #else
  195. pData = MmGetSystemAddressForMdl(pNdisBuffer); // Win9x
  196. #endif
  197. DEBUGP(DL_VERY_LOUD,
  198. ("Write: MDL %p, MdlFlags %x, SystemAddr %p, %d bytes\n",
  199. pIrp->MdlAddress, pIrp->MdlAddress->MdlFlags, pData, DataLength));
  200. DEBUGPDUMP(DL_VERY_LOUD, pData, MIN(DataLength, 48));
  201. }
  202. #endif // SEND_DBG
  203. NdisSendPackets(pOpenContext->BindingHandle, &pNdisPacket, 1);
  204. }
  205. while (FALSE);
  206. if (NtStatus != STATUS_PENDING)
  207. {
  208. pIrp->IoStatus.Status = NtStatus;
  209. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  210. }
  211. return (NtStatus);
  212. }
  213. #ifdef NDIS51
  214. VOID
  215. NdisProtCancelWrite(
  216. IN PDEVICE_OBJECT pDeviceObject,
  217. IN PIRP pIrp
  218. )
  219. /*++
  220. Routine Description:
  221. Cancel a pending write IRP. This routine attempt to cancel the NDIS send.
  222. Arguments:
  223. pDeviceObject - pointer to our device object
  224. pIrp - IRP to be cancelled
  225. Return Value:
  226. None
  227. --*/
  228. {
  229. PNDISPROT_OPEN_CONTEXT pOpenContext;
  230. PLIST_ENTRY pIrpEntry;
  231. PNDIS_PACKET pNdisPacket;
  232. UNREFERENCED_PARAMETER(pDeviceObject);
  233. IoReleaseCancelSpinLock(pIrp->CancelIrql);
  234. //
  235. // The NDIS packet representing this Write IRP.
  236. //
  237. pNdisPacket = NULL;
  238. pOpenContext = (PNDISPROT_OPEN_CONTEXT) pIrp->Tail.Overlay.DriverContext[0];
  239. NPROT_STRUCT_ASSERT(pOpenContext, oc);
  240. //
  241. // Try to locate the IRP in the pended write queue. The send completion
  242. // routine may be running and might have removed it from there.
  243. //
  244. NPROT_ACQUIRE_LOCK(&pOpenContext->Lock);
  245. for (pIrpEntry = pOpenContext->PendedWrites.Flink;
  246. pIrpEntry != &pOpenContext->PendedWrites;
  247. pIrpEntry = pIrpEntry->Flink)
  248. {
  249. if (pIrp == CONTAINING_RECORD(pIrpEntry, IRP, Tail.Overlay.ListEntry))
  250. {
  251. pNdisPacket = (PNDIS_PACKET) pIrp->Tail.Overlay.DriverContext[1];
  252. //
  253. // Place a reference on this packet so that it won't get
  254. // freed/reused until we are done with it.
  255. //
  256. NPROT_REF_SEND_PKT(pNdisPacket);
  257. break;
  258. }
  259. }
  260. NPROT_RELEASE_LOCK(&pOpenContext->Lock);
  261. if (pNdisPacket != NULL)
  262. {
  263. //
  264. // Either the send completion routine hasn't run, or we got a peak
  265. // at the IRP/packet before it had a chance to take it out of the
  266. // pending IRP queue.
  267. //
  268. // We do not complete the IRP here - note that we didn't dequeue it
  269. // above. This is because we always want the send complete routine to
  270. // complete the IRP. And this in turn is because the packet that was
  271. // prepared from the IRP has a buffer chain pointing to data associated
  272. // with this IRP. Therefore we cannot complete the IRP before the driver
  273. // below us is done with the data it pointed to.
  274. //
  275. //
  276. // Request NDIS to cancel this send. The result of this call is that
  277. // our SendComplete handler will be called (if not already called).
  278. //
  279. DEBUGP(DL_INFO, ("CancelWrite: cancelling pkt %p on Open %p\n",
  280. pNdisPacket, pOpenContext));
  281. NdisCancelSendPackets(
  282. pOpenContext->BindingHandle,
  283. NDIS_GET_PACKET_CANCEL_ID(pNdisPacket)
  284. );
  285. //
  286. // It is now safe to remove the reference we had placed on the packet.
  287. //
  288. NPROT_DEREF_SEND_PKT(pNdisPacket);
  289. }
  290. //
  291. // else the send completion routine has already picked up this IRP.
  292. //
  293. }
  294. #endif // NDIS51
  295. VOID
  296. NdisProtSendComplete(
  297. IN NDIS_HANDLE ProtocolBindingContext,
  298. IN PNDIS_PACKET pNdisPacket,
  299. IN NDIS_STATUS Status
  300. )
  301. /*++
  302. Routine Description:
  303. NDIS entry point called to signify completion of a packet send.
  304. We pick up and complete the Write IRP corresponding to this packet.
  305. NDIS 5.1:
  306. Arguments:
  307. ProtocolBindingContext - pointer to open context
  308. pNdisPacket - packet that completed send
  309. Status - status of send
  310. Return Value:
  311. None
  312. --*/
  313. {
  314. PIRP pIrp;
  315. PIO_STACK_LOCATION pIrpSp;
  316. PNDISPROT_OPEN_CONTEXT pOpenContext;
  317. pOpenContext = (PNDISPROT_OPEN_CONTEXT)ProtocolBindingContext;
  318. NPROT_STRUCT_ASSERT(pOpenContext, oc);
  319. pIrp = NPROT_IRP_FROM_SEND_PKT(pNdisPacket);
  320. if (pOpenContext->bRunningOnWin9x)
  321. {
  322. //
  323. // We would have attached our own NDIS_BUFFER. Take it out
  324. // and free it.
  325. //
  326. #ifndef NDIS51
  327. PNDIS_BUFFER pNdisBuffer;
  328. PVOID VirtualAddr;
  329. UINT BufferLength;
  330. UINT TotalLength;
  331. #endif
  332. #ifdef NDIS51
  333. NPROT_ASSERT(FALSE); // NDIS 5.1 not on Win9X!
  334. #else
  335. NdisGetFirstBufferFromPacket(
  336. pNdisPacket,
  337. &pNdisBuffer,
  338. &VirtualAddr,
  339. &BufferLength,
  340. &TotalLength);
  341. NPROT_ASSERT(pNdisBuffer != NULL);
  342. NdisFreeBuffer(pNdisBuffer);
  343. #endif
  344. }
  345. #ifdef NDIS51
  346. IoSetCancelRoutine(pIrp, NULL);
  347. NPROT_ACQUIRE_LOCK(&pOpenContext->Lock);
  348. NPROT_REMOVE_ENTRY_LIST(&pIrp->Tail.Overlay.ListEntry);
  349. NPROT_RELEASE_LOCK(&pOpenContext->Lock);
  350. #endif
  351. //
  352. // We are done with the NDIS_PACKET:
  353. //
  354. NPROT_DEREF_SEND_PKT(pNdisPacket);
  355. //
  356. // Complete the Write IRP with the right status.
  357. //
  358. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  359. if (Status == NDIS_STATUS_SUCCESS)
  360. {
  361. pIrp->IoStatus.Information = pIrpSp->Parameters.Write.Length;
  362. pIrp->IoStatus.Status = STATUS_SUCCESS;
  363. }
  364. else
  365. {
  366. pIrp->IoStatus.Information = 0;
  367. pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  368. }
  369. DEBUGP(DL_INFO, ("SendComplete: packet %p/IRP %p/Length %d "
  370. "completed with status %x\n",
  371. pNdisPacket, pIrp, pIrp->IoStatus.Information, pIrp->IoStatus.Status));
  372. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  373. NdisInterlockedDecrement((PLONG)&pOpenContext->PendedSendCount);
  374. NPROT_DEREF_OPEN(pOpenContext); // send complete - dequeued send IRP
  375. }