send.c
上传用户:yanxuanwei
上传日期:2008-05-17
资源大小:53k
文件大小:13k
源码类别:

驱动编程

开发平台:

Visual C++

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