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

驱动编程

开发平台:

Visual C++

  1. /*++
  2. Copyright (c) 2000  Microsoft Corporation
  3. Module Name:
  4.     recv.c
  5. Abstract:
  6.     NDIS protocol entry points and utility routines to handle receiving
  7.     data.
  8. Environment:
  9.     Kernel mode only.
  10. Revision History:
  11.     arvindm     4/6/2000    Created
  12. --*/
  13. #include "precomp.h"
  14. #define __FILENUMBER 'VCER'
  15. NTSTATUS
  16. NdisuioRead(
  17.     IN PDEVICE_OBJECT       pDeviceObject,
  18.     IN PIRP                 pIrp
  19.     )
  20. /*++
  21. Routine Description:
  22.     Dispatch routine to handle IRP_MJ_READ. 
  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.     NTSTATUS                NtStatus;
  33.     PNDISUIO_OPEN_CONTEXT   pOpenContext;
  34.     pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  35.     pOpenContext = pIrpSp->FileObject->FsContext;
  36.     do
  37.     {
  38.         //
  39.         // Validate!
  40.         //
  41.         if (pOpenContext == NULL)
  42.         {
  43.             DEBUGP(DL_FATAL, ("Read: NULL FsContext on FileObject %pn",
  44.                         pIrpSp->FileObject));
  45.             NtStatus = STATUS_INVALID_HANDLE;
  46.             break;
  47.         }
  48.             
  49.         NUIO_STRUCT_ASSERT(pOpenContext, oc);
  50.         if (pIrp->MdlAddress == NULL)
  51.         {
  52.             DEBUGP(DL_FATAL, ("Read: NULL MDL address on IRP %pn", pIrp));
  53.             NtStatus = STATUS_INVALID_PARAMETER;
  54.             break;
  55.         }
  56.         //
  57.         // Try to get a virtual address for the MDL.
  58.         //
  59. #ifndef WIN9X
  60.         if (MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority) == NULL)
  61.         {
  62.             DEBUGP(DL_FATAL, ("Read: MmGetSystemAddr failed for IRP %p, MDL %pn",
  63.                     pIrp, pIrp->MdlAddress));
  64.             NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  65.             break;
  66.         }
  67. #endif
  68.         NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  69.         if (!NUIO_TEST_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_ACTIVE))
  70.         {
  71.             NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  72.             NtStatus = STATUS_INVALID_HANDLE;
  73.             break;
  74.         }
  75.         //
  76.         //  Add this IRP to the list of pended Read IRPs
  77.         //
  78.         NUIO_INSERT_TAIL_LIST(&pOpenContext->PendedReads, &pIrp->Tail.Overlay.ListEntry);
  79.         NUIO_REF_OPEN(pOpenContext);  // pended read IRP
  80.         pOpenContext->PendedReadCount++;
  81.         //
  82.         //  Set up the IRP for possible cancellation.
  83.         //
  84.         pIrp->Tail.Overlay.DriverContext[0] = (PVOID)pOpenContext;
  85.         IoMarkIrpPending(pIrp);
  86.         IoSetCancelRoutine(pIrp, NdisuioCancelRead);
  87.         NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  88.         NtStatus = STATUS_PENDING;
  89.         //
  90.         //  Run the service routine for reads.
  91.         //
  92.         ndisuioServiceReads(pOpenContext);
  93.         break;
  94.     }
  95.     while (FALSE);
  96.     if (NtStatus != STATUS_PENDING)
  97.     {
  98.         NUIO_ASSERT(NtStatus != STATUS_SUCCESS);
  99.         pIrp->IoStatus.Information = 0;
  100.         pIrp->IoStatus.Status = NtStatus;
  101.         IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  102.     }
  103.     return (NtStatus);
  104. }
  105. VOID
  106. NdisuioCancelRead(
  107.     IN PDEVICE_OBJECT               pDeviceObject,
  108.     IN PIRP                         pIrp
  109.     )
  110. /*++
  111. Routine Description:
  112.     Cancel a pending read IRP. We unlink the IRP from the open context
  113.     queue and complete it.
  114. Arguments:
  115.     pDeviceObject - pointer to our device object
  116.     pIrp - IRP to be cancelled
  117. Return Value:
  118.     None
  119. --*/
  120. {
  121.     PNDISUIO_OPEN_CONTEXT       pOpenContext;
  122.     PLIST_ENTRY                 pEnt;
  123.     PLIST_ENTRY                 pIrpEntry;
  124.     BOOLEAN                     Found;
  125.     IoReleaseCancelSpinLock(pIrp->CancelIrql);
  126.     Found = FALSE;
  127.     pOpenContext = (PNDISUIO_OPEN_CONTEXT) pIrp->Tail.Overlay.DriverContext[0];
  128.     NUIO_STRUCT_ASSERT(pOpenContext, oc);
  129.     NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  130.     //
  131.     //  Locate the IRP in the pended read queue and remove it if found.
  132.     //
  133.     for (pIrpEntry = pOpenContext->PendedReads.Flink;
  134.          pIrpEntry != &pOpenContext->PendedReads;
  135.          pIrpEntry = pIrpEntry->Flink)
  136.     {
  137.         if (pIrp == CONTAINING_RECORD(pIrpEntry, IRP, Tail.Overlay.ListEntry))
  138.         {
  139.             NUIO_REMOVE_ENTRY_LIST(&pIrp->Tail.Overlay.ListEntry);
  140.             pOpenContext->PendedReadCount--;
  141.             Found = TRUE;
  142.             break;
  143.         }
  144.     }
  145.     NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  146.     if (Found)
  147.     {
  148.         DEBUGP(DL_INFO, ("CancelRead: Open %p, IRP %pn", pOpenContext, pIrp));
  149.         pIrp->IoStatus.Status = STATUS_CANCELLED;
  150.         pIrp->IoStatus.Information = 0;
  151.         IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  152.         NUIO_DEREF_OPEN(pOpenContext); // Cancel removed pended Read
  153.     }
  154. }
  155.         
  156. VOID
  157. ndisuioServiceReads(
  158.     IN PNDISUIO_OPEN_CONTEXT        pOpenContext
  159.     )
  160. /*++
  161. Routine Description:
  162.     Utility routine to copy received data into user buffers and
  163.     complete READ IRPs.
  164. Arguments:
  165.     pOpenContext - pointer to open context
  166. Return Value:
  167.     None
  168. --*/
  169. {
  170.     PIRP                pIrp;
  171.     PLIST_ENTRY         pIrpEntry;
  172.     PNDIS_PACKET        pRcvPacket;
  173.     PLIST_ENTRY         pRcvPacketEntry;
  174.     PUCHAR              pSrc, pDst;
  175.     ULONG               BytesRemaining; // at pDst
  176.     PNDIS_BUFFER        pNdisBuffer;
  177.     ULONG               BytesAvailable;
  178.     DEBUGP(DL_VERY_LOUD, ("ServiceReads: open %p/%xn",
  179.             pOpenContext, pOpenContext->Flags));
  180.     NUIO_REF_OPEN(pOpenContext);  // temp ref - service reads
  181.     NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  182.     while (!NUIO_IS_LIST_EMPTY(&pOpenContext->PendedReads) &&
  183.            !NUIO_IS_LIST_EMPTY(&pOpenContext->RecvPktQueue))
  184.     {
  185.         //
  186.         //  Get the first pended Read IRP
  187.         //
  188.         pIrpEntry = pOpenContext->PendedReads.Flink;
  189.         pIrp = CONTAINING_RECORD(pIrpEntry, IRP, Tail.Overlay.ListEntry);
  190.         //
  191.         //  Check to see if it is being cancelled.
  192.         //
  193.         if (IoSetCancelRoutine(pIrp, NULL))
  194.         {
  195.             //
  196.             //  It isn't being cancelled, and can't be cancelled henceforth.
  197.             //
  198.             NUIO_REMOVE_ENTRY_LIST(pIrpEntry);
  199.             //
  200.             //  NOTE: we decrement PendedReadCount way below in the
  201.             //  while loop, to avoid letting through a thread trying
  202.             //  to unbind.
  203.             //
  204.         }
  205.         else
  206.         {
  207.             //
  208.             //  The IRP is being cancelled; let the cancel routine handle it.
  209.             //
  210.             DEBUGP(DL_INFO, ("ServiceReads: open %p, skipping cancelled IRP %pn",
  211.                     pOpenContext, pIrp));
  212.             continue;
  213.         }
  214.         //
  215.         //  Get the first queued receive packet
  216.         //
  217.         pRcvPacketEntry = pOpenContext->RecvPktQueue.Flink;
  218.         NUIO_REMOVE_ENTRY_LIST(pRcvPacketEntry);
  219.         pOpenContext->RecvPktCount --;
  220.         NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  221.         NUIO_DEREF_OPEN(pOpenContext);  // Service: dequeue rcv packet
  222.         pRcvPacket = NUIO_LIST_ENTRY_TO_RCV_PKT(pRcvPacketEntry);
  223.         //
  224.         //  Copy as much data as possible from the receive packet to
  225.         //  the IRP MDL.
  226.         //
  227. #ifndef WIN9X
  228.         pDst = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority);
  229.         NUIO_ASSERT(pDst != NULL);  // since it was already mapped
  230. #else
  231.         pDst = MmGetSystemAddressForMdl(pIrp->MdlAddress);  // Win9x
  232. #endif
  233.         BytesRemaining = MmGetMdlByteCount(pIrp->MdlAddress);
  234.         pNdisBuffer = pRcvPacket->Private.Head;
  235.         while (BytesRemaining && (pNdisBuffer != NULL))
  236.         {
  237. #ifndef WIN9X
  238.             NdisQueryBufferSafe(pNdisBuffer, &pSrc, &BytesAvailable, NormalPagePriority);
  239.             if (pSrc == NULL) 
  240.             {
  241.                 DEBUGP(DL_FATAL,
  242.                     ("ServiceReads: Open %p, QueryBuffer failed for buffer %pn",
  243.                             pOpenContext, pNdisBuffer));
  244.                 break;
  245.             }
  246. #else
  247.             NdisQueryBuffer(pNdisBuffer, &pSrc, &BytesAvailable);
  248. #endif
  249.             if (BytesAvailable)
  250.             {
  251.                 ULONG       BytesToCopy = MIN(BytesAvailable, BytesRemaining);
  252.                 NUIO_COPY_MEM(pDst, pSrc, BytesToCopy);
  253.                 BytesRemaining -= BytesToCopy;
  254.                 pDst += BytesToCopy;
  255.             }
  256.             NdisGetNextBuffer(pNdisBuffer, &pNdisBuffer);
  257.         }
  258.         //
  259.         //  Complete the IRP.
  260.         //
  261.         pIrp->IoStatus.Status = STATUS_SUCCESS;
  262.         pIrp->IoStatus.Information = MmGetMdlByteCount(pIrp->MdlAddress) - BytesRemaining;
  263.         DEBUGP(DL_INFO, ("ServiceReads: Open %p, IRP %p completed with %d bytesn",
  264.             pOpenContext, pIrp, pIrp->IoStatus.Information));
  265.         IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  266.         //
  267.         //  Free up the receive packet - back to the miniport if it
  268.         //  belongs to it, else reclaim it (local copy).
  269.         //
  270.         if (NdisGetPoolFromPacket(pRcvPacket) != pOpenContext->RecvPacketPool)
  271.         {
  272.             NdisReturnPackets(&pRcvPacket, 1);
  273.         }
  274.         else
  275.         {
  276.             ndisuioFreeReceivePacket(pOpenContext, pRcvPacket);
  277.         }
  278.         NUIO_DEREF_OPEN(pOpenContext);    // took out pended Read
  279.         NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  280.         pOpenContext->PendedReadCount--;
  281.     }
  282.     NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  283.     NUIO_DEREF_OPEN(pOpenContext);    // temp ref - service reads
  284. }
  285. NDIS_STATUS
  286. NdisuioReceive(
  287.     IN NDIS_HANDLE                  ProtocolBindingContext,
  288.     IN NDIS_HANDLE                  MacReceiveContext,
  289.     IN PVOID                        pHeaderBuffer,
  290.     IN UINT                         HeaderBufferSize,
  291.     IN PVOID                        pLookaheadBuffer,
  292.     IN UINT                         LookaheadBufferSize,
  293.     IN UINT                         PacketSize
  294.     )
  295. /*++
  296. Routine Description:
  297.     Our protocol receive handler called by NDIS, typically if we have
  298.     a miniport below that doesn't indicate packets.
  299.     We make a local packet/buffer copy of this data, queue it up, and
  300.     kick off the read service routine.
  301. Arguments:
  302.     ProtocolBindingContext - pointer to open context
  303.     MacReceiveContext - for use in NdisTransferData
  304.     pHeaderBuffer - pointer to data header
  305.     HeaderBufferSize - size of the above
  306.     pLookaheadBuffer - pointer to buffer containing lookahead data
  307.     LookaheadBufferSize - size of the above
  308.     PacketSize - size of the entire packet, minus header size.
  309. Return Value:
  310.     NDIS_STATUS_NOT_ACCEPTED - if this packet is uninteresting
  311.     NDIS_STATUS_SUCCESS - if we processed this successfully
  312. --*/
  313. {
  314.     PNDISUIO_OPEN_CONTEXT   pOpenContext;
  315.     NDIS_STATUS             Status;
  316.     PNDISUIO_ETH_HEADER     pEthHeader;
  317.     PNDIS_PACKET            pRcvPacket;
  318.     PUCHAR                  pRcvData;
  319.     UINT                    BytesTransferred;
  320.     PNDIS_BUFFER            pOriginalNdisBuffer, pPartialNdisBuffer;
  321.     pOpenContext = (PNDISUIO_OPEN_CONTEXT)ProtocolBindingContext;
  322.     NUIO_STRUCT_ASSERT(pOpenContext, oc);
  323.     pRcvPacket = NULL;
  324.     pRcvData = NULL;
  325.     Status = NDIS_STATUS_SUCCESS;
  326.     do
  327.     {
  328.         if (HeaderBufferSize != sizeof(NDISUIO_ETH_HEADER))
  329.         {
  330.             Status = NDIS_STATUS_NOT_ACCEPTED;
  331.             break;
  332.         }
  333.         pEthHeader = (PNDISUIO_ETH_HEADER)pHeaderBuffer;
  334.         //
  335.         //  Check the EtherType. If the Ether type indicates presence of
  336.         //  a tag, then the "real" Ether type is 4 bytes further down.
  337.         //
  338.         if (pEthHeader->EthType == NUIO_8021P_TAG_TYPE)
  339.         {
  340.             USHORT UNALIGNED *pEthType;
  341.             pEthType = (USHORT UNALIGNED *)((PUCHAR)&pEthHeader->EthType + 4);
  342.             if (*pEthType != Globals.EthType)
  343.             {
  344.                 Status = NDIS_STATUS_NOT_ACCEPTED;
  345.                 break;
  346.             }
  347.         }
  348.         else if (pEthHeader->EthType != Globals.EthType)
  349.         {
  350.             Status = NDIS_STATUS_NOT_ACCEPTED;
  351.             break;
  352.         }
  353.         //
  354.         //  Allocate resources for queueing this up.
  355.         //
  356.         pRcvPacket = ndisuioAllocateReceivePacket(
  357.                         pOpenContext,
  358.                         PacketSize + HeaderBufferSize,
  359.                         &pRcvData
  360.                         );
  361.         if (pRcvPacket == NULL)
  362.         {
  363.             Status = NDIS_STATUS_NOT_ACCEPTED;
  364.             break;
  365.         }
  366.         NdisMoveMappedMemory(pRcvData, pHeaderBuffer, HeaderBufferSize);
  367.         //
  368.         //  Check if the entire packet is within the lookahead.
  369.         //
  370.         if (PacketSize == LookaheadBufferSize)
  371.         {
  372.             NdisCopyLookaheadData(pRcvData+HeaderBufferSize,
  373.                                   pLookaheadBuffer,
  374.                                   LookaheadBufferSize,
  375.                                   pOpenContext->MacOptions);
  376.             //
  377.             //  Queue this up for receive processing, and
  378.             //  try to complete some read IRPs.
  379.             //
  380.             ndisuioQueueReceivePacket(pOpenContext, pRcvPacket);
  381.         }
  382.         else
  383.         {
  384.             //
  385.             //  Allocate an NDIS buffer to map the receive area
  386.             //  at an offset "HeaderBufferSize" from the current
  387.             //  start. This is so that NdisTransferData can copy
  388.             //  in at the right point in the destination buffer.
  389.             //
  390.             NdisAllocateBuffer(
  391.                 &Status,
  392.                 &pPartialNdisBuffer,
  393.                 pOpenContext->RecvBufferPool,
  394.                 pRcvData + HeaderBufferSize,
  395.                 PacketSize);
  396.             
  397.             if (Status == NDIS_STATUS_SUCCESS)
  398.             {
  399.                 //
  400.                 //  Unlink and save away the original NDIS Buffer
  401.                 //  that maps the full receive buffer.
  402.                 //
  403.                 NdisUnchainBufferAtFront(pRcvPacket, &pOriginalNdisBuffer);
  404.                 NUIO_RCV_PKT_TO_ORIGINAL_BUFFER(pRcvPacket) = pOriginalNdisBuffer;
  405.                 //
  406.                 //  Link in the partial buffer for NdisTransferData to
  407.                 //  operate on.
  408.                 //
  409.                 NdisChainBufferAtBack(pRcvPacket, pPartialNdisBuffer);
  410.                 DEBUGP(DL_LOUD, ("Receive: setting up for TransferData:"
  411.                         " Pkt %p, OriginalBuf %p, PartialBuf %pn",
  412.                         pRcvPacket, pOriginalNdisBuffer, pPartialNdisBuffer));
  413.                 NdisTransferData(
  414.                     &Status,
  415.                     pOpenContext->BindingHandle,
  416.                     MacReceiveContext,
  417.                     0,  // ByteOffset
  418.                     PacketSize,
  419.                     pRcvPacket,
  420.                     &BytesTransferred);
  421.             }
  422.             else
  423.             {
  424.                 //
  425.                 //  Failure handled below in TransferDataComplete.
  426.                 //
  427.                 BytesTransferred = 0;
  428.             }
  429.     
  430.             if (Status != NDIS_STATUS_PENDING)
  431.             {
  432.                 NdisuioTransferDataComplete(
  433.                     (NDIS_HANDLE)pOpenContext,
  434.                     pRcvPacket,
  435.                     Status,
  436.                     BytesTransferred);
  437.             }
  438.         }
  439.         break;
  440.     }
  441.     while (FALSE);
  442.     return Status;
  443.     DEBUGP(DL_LOUD, ("Receive: Open %p, Pkt %p, Size %dn",
  444.             pOpenContext, pRcvPacket, PacketSize));
  445. }
  446. VOID
  447. NdisuioTransferDataComplete(
  448.     IN NDIS_HANDLE                  ProtocolBindingContext,
  449.     IN PNDIS_PACKET                 pNdisPacket,
  450.     IN NDIS_STATUS                  TransferStatus,
  451.     IN UINT                         BytesTransferred
  452.     )
  453. /*++
  454. Routine Description:
  455.     NDIS entry point called to signal completion of a call to
  456.     NdisTransferData that had pended.
  457. Arguments:
  458.     ProtocolBindingContext - pointer to open context
  459.     pNdisPacket - our receive packet into which data is transferred
  460.     TransferStatus - status of the transfer
  461.     BytesTransferred - bytes copied into the packet.
  462. Return Value:
  463.     None
  464. --*/
  465. {
  466.     PNDISUIO_OPEN_CONTEXT   pOpenContext;
  467.     PNDIS_BUFFER            pOriginalBuffer, pPartialBuffer;
  468.     pOpenContext = (PNDISUIO_OPEN_CONTEXT)ProtocolBindingContext;
  469.     NUIO_STRUCT_ASSERT(pOpenContext, oc);
  470.     //
  471.     //  Check if an NDIS_BUFFER was created to map part of the receive buffer;
  472.     //  if so, free it and link back the original NDIS_BUFFER that maps
  473.     //  the full receive buffer to the packet.
  474.     //
  475.     pOriginalBuffer = NUIO_RCV_PKT_TO_ORIGINAL_BUFFER(pNdisPacket);
  476.     if (pOriginalBuffer != NULL)
  477.     {
  478.         //
  479.         //  We had stashed off the NDIS_BUFFER for the full receive
  480.         //  buffer in the packet reserved area. Unlink the partial
  481.         //  buffer and link in the full buffer.
  482.         //
  483.         NdisUnchainBufferAtFront(pNdisPacket, &pPartialBuffer);
  484.         NdisChainBufferAtBack(pNdisPacket, pOriginalBuffer);
  485.         DEBUGP(DL_LOUD, ("TransferComp: Pkt %p, OrigBuf %p, PartialBuf %pn",
  486.                 pNdisPacket, pOriginalBuffer, pPartialBuffer));
  487.         //
  488.         //  Free up the partial buffer.
  489.         //
  490.         NdisFreeBuffer(pPartialBuffer);
  491.     }
  492.     if (TransferStatus == NDIS_STATUS_SUCCESS)
  493.     {
  494.         //
  495.         //  Queue this up for receive processing, and
  496.         //  try to complete some read IRPs.
  497.         //
  498.         ndisuioQueueReceivePacket(pOpenContext, pNdisPacket);
  499.     }
  500.     else
  501.     {
  502.         ndisuioFreeReceivePacket(pOpenContext, pNdisPacket);
  503.     }
  504. }
  505. VOID
  506. NdisuioReceiveComplete(
  507.     IN NDIS_HANDLE                  ProtocolBindingContext
  508.     )
  509. /*++
  510. Routine Description:
  511.     Protocol entry point called by NDIS when the miniport
  512.     has finished indicating up a batch of receives.
  513.     We ignore this.
  514. Arguments:
  515.     ProtocolBindingContext - pointer to open context
  516. Return Value:
  517.     None
  518. --*/
  519. {
  520.     PNDISUIO_OPEN_CONTEXT   pOpenContext;
  521.     pOpenContext = (PNDISUIO_OPEN_CONTEXT)ProtocolBindingContext;
  522.     NUIO_STRUCT_ASSERT(pOpenContext, oc);
  523.     return;
  524. }
  525. INT
  526. NdisuioReceivePacket(
  527.     IN NDIS_HANDLE                  ProtocolBindingContext,
  528.     IN PNDIS_PACKET                 pNdisPacket
  529.     )
  530. /*++
  531. Routine Description:
  532.     Protocol entry point called by NDIS if the driver below
  533.     uses NDIS 4 style receive packet indications.
  534.     If the miniport allows us to hold on to this packet, we
  535.     use it as is, otherwise we make a copy.
  536. Arguments:
  537.     ProtocolBindingContext - pointer to open context
  538.     pNdisPacket - the packet being indicated up.
  539. Return Value:
  540.     None
  541. --*/
  542. {
  543.     PNDISUIO_OPEN_CONTEXT   pOpenContext;
  544.     PNDIS_BUFFER            pNdisBuffer;
  545.     UINT                    BufferLength;
  546.     PNDISUIO_ETH_HEADER     pEthHeader;
  547.     PNDIS_PACKET            pCopyPacket;
  548.     PUCHAR                  pCopyBuf;
  549.     UINT                    TotalPacketLength;
  550.     UINT                    BytesCopied;
  551.     INT                     RefCount = 0;
  552.     NDIS_STATUS             Status;
  553.     pOpenContext = (PNDISUIO_OPEN_CONTEXT)ProtocolBindingContext;
  554.     NUIO_STRUCT_ASSERT(pOpenContext, oc);
  555. #ifdef NDIS51
  556.     NdisGetFirstBufferFromPacketSafe(
  557.         pNdisPacket,
  558.         &pNdisBuffer,
  559.         &pEthHeader,
  560.         &BufferLength,
  561.         &TotalPacketLength,
  562.         NormalPagePriority);
  563.     if (pEthHeader == NULL)
  564.     {
  565.         //
  566.         //  The system is low on resources. Set up to handle failure
  567.         //  below.
  568.         //
  569.         BufferLength = 0;
  570.     }
  571. #else
  572.     NdisGetFirstBufferFromPacket(
  573.         pNdisPacket,
  574.         &pNdisBuffer,
  575.         &pEthHeader,
  576.         &BufferLength,
  577.         &TotalPacketLength);
  578. #endif
  579.     do
  580.     {
  581.         if (BufferLength < sizeof(NDISUIO_ETH_HEADER))
  582.         {
  583.             DEBUGP(DL_WARN,
  584.                 ("ReceivePacket: Open %p, runt pkt %p, first buffer length %dn",
  585.                     pOpenContext, pNdisPacket, BufferLength));
  586.             Status = NDIS_STATUS_NOT_ACCEPTED;
  587.             break;
  588.         }
  589.         //
  590.         //  Check the EtherType. If the Ether type indicates presence of
  591.         //  a tag, then the "real" Ether type is 4 bytes further down.
  592.         //
  593.         if (pEthHeader->EthType == NUIO_8021P_TAG_TYPE)
  594.         {
  595.             USHORT UNALIGNED *pEthType;
  596.             pEthType = (USHORT UNALIGNED *)((PUCHAR)&pEthHeader->EthType + 4);
  597.             if (*pEthType != Globals.EthType)
  598.             {
  599.                 Status = NDIS_STATUS_NOT_ACCEPTED;
  600.                 break;
  601.             }
  602.         }
  603.         else if (pEthHeader->EthType != Globals.EthType)
  604.         {
  605.             Status = NDIS_STATUS_NOT_ACCEPTED;
  606.             break;
  607.         }
  608.         DEBUGP(DL_LOUD, ("ReceivePacket: Open %p, interesting pkt %pn",
  609.                     pOpenContext, pNdisPacket));
  610.         //
  611.         //  If the miniport is out of resources, we can't queue
  612.         //  this packet - make a copy if this is so.
  613.         //
  614.         if ((NDIS_GET_PACKET_STATUS(pNdisPacket) == NDIS_STATUS_RESOURCES) ||
  615.             pOpenContext->bRunningOnWin9x)
  616.         {
  617.             pCopyPacket = ndisuioAllocateReceivePacket(
  618.                             pOpenContext,
  619.                             TotalPacketLength,
  620.                             &pCopyBuf
  621.                             );
  622.             
  623.             if (pCopyPacket == NULL)
  624.             {
  625.                 DEBUGP(DL_FATAL, ("ReceivePacket: Open %p, failed to"
  626.                     " alloc copy, %d bytesn", pOpenContext, TotalPacketLength));
  627.                 break;
  628.             }
  629.             NdisCopyFromPacketToPacket(
  630.                 pCopyPacket,
  631.                 0,
  632.                 TotalPacketLength,
  633.                 pNdisPacket,
  634.                 0,
  635.                 &BytesCopied);
  636.             
  637.             NUIO_ASSERT(BytesCopied == TotalPacketLength);
  638.             pNdisPacket = pCopyPacket;
  639.         }
  640.         else
  641.         {
  642.             //
  643.             //  We can queue the original packet - return
  644.             //  a packet reference count indicating that
  645.             //  we will call NdisReturnPackets when we are
  646.             //  done with this packet.
  647.             //
  648.             RefCount = 1;
  649.         }
  650.         //
  651.         //  Queue this up and service any pending Read IRPs.
  652.         //
  653.         ndisuioQueueReceivePacket(pOpenContext, pNdisPacket);
  654.         break;
  655.     }
  656.     while (FALSE);
  657.     return (RefCount);
  658. }
  659. VOID
  660. ndisuioQueueReceivePacket(
  661.     IN PNDISUIO_OPEN_CONTEXT        pOpenContext,
  662.     IN PNDIS_PACKET                 pRcvPacket
  663.     )
  664. /*++
  665. Routine Description:
  666.     Queue up a received packet on the open context structure.
  667.     If the queue size goes beyond a water mark, discard a packet
  668.     at the head of the queue.
  669.     Finally, run the queue service routine.
  670. Arguments:
  671.     
  672.     pOpenContext - pointer to open context
  673.     pRcvPacket - the received packet
  674. Return Value:
  675.     None
  676. --*/
  677. {
  678.     PLIST_ENTRY     pEnt;
  679.     PLIST_ENTRY     pDiscardEnt;
  680.     PNDIS_PACKET    pDiscardPkt;
  681.     do
  682.     {
  683.         pEnt = NUIO_RCV_PKT_TO_LIST_ENTRY(pRcvPacket);
  684.         NUIO_REF_OPEN(pOpenContext);    // queued rcv packet
  685.         NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  686.         //
  687.         //  Check if the binding is in the proper state to receive
  688.         //  this packet.
  689.         //
  690.         if (NUIO_TEST_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_ACTIVE) &&
  691.             (pOpenContext->PowerState == NetDeviceStateD0))
  692.         {
  693.             NUIO_INSERT_TAIL_LIST(&pOpenContext->RecvPktQueue, pEnt);
  694.             pOpenContext->RecvPktCount++;
  695.             DEBUGP(DL_VERY_LOUD, ("QueueReceivePacket: open %p,"
  696.                     " queued pkt %p, queue size %dn",
  697.                     pOpenContext, pRcvPacket, pOpenContext->RecvPktCount));
  698.         }
  699.         else
  700.         {
  701.             //
  702.             //  Received this packet when the binding is going away.
  703.             //  Drop this.
  704.             //
  705.             NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  706.             ndisuioFreeReceivePacket(pOpenContext, pRcvPacket);
  707.             NUIO_DEREF_OPEN(pOpenContext);  // dropped rcv packet - bad state
  708.             break;
  709.         }
  710.         //
  711.         //  Trim the queue if it has grown too big.
  712.         //
  713.         if (pOpenContext->RecvPktCount > MAX_RECV_QUEUE_SIZE)
  714.         {
  715.             //
  716.             //  Remove the head of the queue.
  717.             //
  718.             pDiscardEnt = pOpenContext->RecvPktQueue.Flink;
  719.             NUIO_REMOVE_ENTRY_LIST(pDiscardEnt);
  720.             pOpenContext->RecvPktCount --;
  721.             NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  722.             pDiscardPkt = NUIO_LIST_ENTRY_TO_RCV_PKT(pDiscardEnt);
  723.             ndisuioFreeReceivePacket(pOpenContext, pDiscardPkt);
  724.             NUIO_DEREF_OPEN(pOpenContext);  // dropped rcv packet - queue too long
  725.             DEBUGP(DL_INFO, ("QueueReceivePacket: open %p queue"
  726.                     " too long, discarded pkt %pn",
  727.                     pOpenContext, pDiscardPkt));
  728.         }
  729.         else
  730.         {
  731.             NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  732.         }
  733.         //
  734.         //  Run the receive queue service routine now.
  735.         //
  736.         ndisuioServiceReads(pOpenContext);
  737.     }
  738.     while (FALSE);
  739. }
  740. PNDIS_PACKET
  741. ndisuioAllocateReceivePacket(
  742.     IN PNDISUIO_OPEN_CONTEXT        pOpenContext,
  743.     IN UINT                         DataLength,
  744.     OUT PUCHAR *                    ppDataBuffer
  745.     )
  746. /*++
  747. Routine Description:
  748.     Allocate resources to copy and queue a received packet.
  749. Arguments:
  750.     pOpenContext - pointer to open context for received packet
  751.     DataLength - total length in bytes of the packet
  752.     ppDataBuffer - place to return pointer to allocated buffer
  753. Return Value:
  754.     Pointer to NDIS packet if successful, else NULL.
  755. --*/
  756. {
  757.     PNDIS_PACKET            pNdisPacket;
  758.     PNDIS_BUFFER            pNdisBuffer;
  759.     PUCHAR                  pDataBuffer;
  760.     NDIS_STATUS             Status;
  761.     pNdisPacket = NULL;
  762.     pNdisBuffer = NULL;
  763.     pDataBuffer = NULL;
  764.     do
  765.     {
  766.         NUIO_ALLOC_MEM(pDataBuffer, DataLength);
  767.         if (pDataBuffer == NULL)
  768.         {
  769.             DEBUGP(DL_FATAL, ("AllocRcvPkt: open %p, failed to alloc"
  770.                 " data buffer %d bytesn", pOpenContext, DataLength));
  771.             break;
  772.         }
  773.         //
  774.         //  Make this an NDIS buffer.
  775.         //
  776.         NdisAllocateBuffer(
  777.             &Status,
  778.             &pNdisBuffer,
  779.             pOpenContext->RecvBufferPool,
  780.             pDataBuffer,
  781.             DataLength);
  782.         
  783.         if (Status != NDIS_STATUS_SUCCESS)
  784.         {
  785.             DEBUGP(DL_FATAL, ("AllocateRcvPkt: open %p, failed to alloc"
  786.                 " NDIS buffer, %d bytesn", pOpenContext, DataLength));
  787.             break;
  788.         }
  789.         NdisAllocatePacket(&Status, &pNdisPacket, pOpenContext->RecvPacketPool);
  790.         if (Status != NDIS_STATUS_SUCCESS)
  791.         {
  792.             DEBUGP(DL_FATAL, ("AllocateRcvPkt: open %p, failed to alloc"
  793.                 " NDIS packet, %d bytesn", pOpenContext, DataLength));
  794.             break;
  795.         }
  796.         NDIS_SET_PACKET_STATUS(pNdisPacket, 0);
  797.         NUIO_RCV_PKT_TO_ORIGINAL_BUFFER(pNdisPacket) = NULL;
  798.         NdisChainBufferAtFront(pNdisPacket, pNdisBuffer);
  799.         *ppDataBuffer = pDataBuffer;
  800.         break;
  801.     }
  802.     while (FALSE);
  803.     if (pNdisPacket == NULL)
  804.     {
  805.         //
  806.         //  Clean up
  807.         //
  808.         if (pNdisBuffer != NULL)
  809.         {
  810.             NdisFreeBuffer(pNdisBuffer);
  811.         }
  812.         if (pDataBuffer != NULL)
  813.         {
  814.             NUIO_FREE_MEM(pDataBuffer);
  815.         }
  816.     }
  817.     return (pNdisPacket);
  818. }
  819. VOID
  820. ndisuioFreeReceivePacket(
  821.     IN PNDISUIO_OPEN_CONTEXT        pOpenContext,
  822.     IN PNDIS_PACKET                 pNdisPacket
  823.     )
  824. /*++
  825. Routine Description:
  826.     Free up all resources associated with a received packet. If this
  827.     is a local copy, free the packet to our receive pool, else return
  828.     this to the miniport.
  829. Arguments:
  830.     
  831.     pOpenContext - pointer to open context
  832.     pNdisPacket - pointer to packet to be freed.
  833. Return Value:
  834.     None
  835. --*/
  836. {
  837.     PNDIS_BUFFER        pNdisBuffer;
  838.     UINT                TotalLength;
  839.     UINT                BufferLength;
  840.     PUCHAR              pCopyData;
  841.     if (NdisGetPoolFromPacket(pNdisPacket) == pOpenContext->RecvPacketPool)
  842.     {
  843.         //
  844.         //  This is a local copy.
  845.         //
  846. #ifdef NDIS51
  847.         NdisGetFirstBufferFromPacketSafe(
  848.             pNdisPacket,
  849.             &pNdisBuffer,
  850.             (PVOID *)&pCopyData,
  851.             &BufferLength,
  852.             &TotalLength,
  853.             NormalPagePriority);
  854. #else
  855.         NdisGetFirstBufferFromPacket(
  856.             pNdisPacket,
  857.             &pNdisBuffer,
  858.             (PVOID *)&pCopyData,
  859.             &BufferLength,
  860.             &TotalLength);
  861. #endif
  862.         NUIO_ASSERT(BufferLength == TotalLength);
  863.         NUIO_ASSERT(pNdisBuffer != NULL);
  864.         NUIO_ASSERT(pCopyData != NULL); // we would have allocated non-paged pool
  865.         NdisFreePacket(pNdisPacket);
  866.         NdisFreeBuffer(pNdisBuffer);
  867.         NUIO_FREE_MEM(pCopyData);
  868.     }
  869.     else
  870.     {
  871.         NdisReturnPackets(&pNdisPacket, 1);
  872.     }
  873. }
  874.         
  875. VOID
  876. ndisuioCancelPendingReads(
  877.     IN PNDISUIO_OPEN_CONTEXT        pOpenContext
  878.     )
  879. /*++
  880. Routine Description:
  881.     Cancel any pending read IRPs queued on the given open.
  882. Arguments:
  883.     pOpenContext - pointer to open context
  884. Return Value:
  885.     None
  886. --*/
  887. {
  888.     PIRP                pIrp;
  889.     PLIST_ENTRY         pIrpEntry;
  890.     NUIO_REF_OPEN(pOpenContext);  // temp ref - cancel reads
  891.     NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  892.     while (!NUIO_IS_LIST_EMPTY(&pOpenContext->PendedReads))
  893.     {
  894.         //
  895.         //  Get the first pended Read IRP
  896.         //
  897.         pIrpEntry = pOpenContext->PendedReads.Flink;
  898.         pIrp = CONTAINING_RECORD(pIrpEntry, IRP, Tail.Overlay.ListEntry);
  899.         //
  900.         //  Check to see if it is being cancelled.
  901.         //
  902.         if (IoSetCancelRoutine(pIrp, NULL))
  903.         {
  904.             //
  905.             //  It isn't being cancelled, and can't be cancelled henceforth.
  906.             //
  907.             NUIO_REMOVE_ENTRY_LIST(pIrpEntry);
  908.             NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  909.             //
  910.             //  Complete the IRP.
  911.             //
  912.             pIrp->IoStatus.Status = STATUS_CANCELLED;
  913.             pIrp->IoStatus.Information = 0;
  914.             DEBUGP(DL_INFO, ("CancelPendingReads: Open %p, IRP %p cancelledn",
  915.                 pOpenContext, pIrp));
  916.             IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  917.             NUIO_DEREF_OPEN(pOpenContext);    // took out pended Read for cancelling
  918.             NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  919.             pOpenContext->PendedReadCount--;
  920.         }
  921.         else
  922.         {
  923.             //
  924.             //  It is being cancelled, let the cancel routine handle it.
  925.             //
  926.             NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  927.             //
  928.             //  Give the cancel routine some breathing space, otherwise
  929.             //  we might end up examining the same (cancelled) IRP over
  930.             //  and over again.
  931.             //
  932.             NUIO_SLEEP(1);
  933.             NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  934.         }
  935.     }
  936.     NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  937.     NUIO_DEREF_OPEN(pOpenContext);    // temp ref - cancel reads
  938. }
  939. VOID
  940. ndisuioFlushReceiveQueue(
  941.     IN PNDISUIO_OPEN_CONTEXT            pOpenContext
  942.     )
  943. /*++
  944. Routine Description:
  945.     Free any receive packets queued up on the specified open
  946. Arguments:
  947.     pOpenContext - pointer to open context
  948. Return Value:
  949.     None
  950. --*/
  951. {
  952.     PLIST_ENTRY         pRcvPacketEntry;
  953.     PNDIS_PACKET        pRcvPacket;
  954.     NUIO_REF_OPEN(pOpenContext);  // temp ref - flushRcvQueue
  955.     NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  956.     
  957.     while (!NUIO_IS_LIST_EMPTY(&pOpenContext->RecvPktQueue))
  958.     {
  959.         //
  960.         //  Get the first queued receive packet
  961.         //
  962.         pRcvPacketEntry = pOpenContext->RecvPktQueue.Flink;
  963.         NUIO_REMOVE_ENTRY_LIST(pRcvPacketEntry);
  964.         pOpenContext->RecvPktCount --;
  965.         NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  966.         pRcvPacket = NUIO_LIST_ENTRY_TO_RCV_PKT(pRcvPacketEntry);
  967.         DEBUGP(DL_LOUD, ("FlushReceiveQueue: open %p, pkt %pn",
  968.             pOpenContext, pRcvPacket));
  969.         ndisuioFreeReceivePacket(pOpenContext, pRcvPacket);
  970.         NUIO_DEREF_OPEN(pOpenContext);    // took out pended Read
  971.         NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  972.     }
  973.     NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  974.     NUIO_DEREF_OPEN(pOpenContext);    // temp ref - flushRcvQueue
  975. }