⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 receive.c

📁 网络驱动开发
💻 C
📖 第 1 页 / 共 2 页
字号:
            pEthHeader->DstAddr[2],
            pEthHeader->DstAddr[3],
            pEthHeader->DstAddr[4],
            pEthHeader->DstAddr[5]));

        DEBUGP(MP_LOUD, ("Indicating packet = %p, Packet Length = %d\n", 
                            pRCB->Packet, PacketLength));

        NdisInterlockedIncrement(&pRCB->Ref);


        NDIS_SET_PACKET_STATUS(pRCB->Packet, NDIS_STATUS_SUCCESS);
        Adapter->nPacketsIndicated++;

        //
        // NDIS expects the indication to happen at DISPATCH_LEVEL if the
        // device is assinged any I/O resources in the IRP_MN_START_DEVICE_IRP.
        // Since this sample is flexible enough to be used as a standalone
        // virtual miniport talking to another device or part of a WDM stack for
        // devices consuming hw resources such as ISA, PCI, PCMCIA. I have to
        // do the following check. You should avoid raising the IRQL, if you
        // know for sure that your device wouldn't have any I/O resources. This
        // would be the case if your driver is talking to USB, 1394, etc.
        //
        if(Adapter->IsHardwareDevice){
            
            KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
            NdisMIndicateReceivePacket(Adapter->AdapterHandle,
                            &pRCB->Packet,
                            1);
            KeLowerIrql(oldIrql);            
            
        }else{
        
            NdisMIndicateReceivePacket(Adapter->AdapterHandle,
                            &pRCB->Packet,
                            1);
        }

    }else {
        DEBUGP(MP_VERY_LOUD, 
                ("Invalid packet or filter is not set packet = %p,Packet Length = %d\n",
                pRCB->Packet, PacketLength));        
    }            

}

VOID
NICFreeBusyRecvPackets(
    PMP_ADAPTER Adapter
    )
/*++

Routine Description:

    This function tries to cancel all the outstanding read IRP if it is not 
    already completed and frees the RCB block. This routine is called
    only by the Halt handler.
    
Arguments:

    Adapter    - pointer to the MP_ADAPTER structure
    
Return value:

    VOID
--*/
{ 
    PLIST_ENTRY         pEntry = NULL;
    PNDIS_PACKET        Packet = NULL;
    PRCB                pRCB = NULL;
    
    DEBUGP(MP_TRACE, ("--> NICFreeBusyRecvPackets\n"));

    if(!MP_TEST_FLAG(Adapter, fMP_RECV_SIDE_RESOURCE_ALLOCATED)){
        return;
    }
    
    NdisAcquireSpinLock(&Adapter->RecvLock);

    while(!IsListEmpty(&Adapter->RecvBusyList))
    {
        
        pEntry = (PLIST_ENTRY)RemoveHeadList(&Adapter->RecvBusyList);
        pRCB = CONTAINING_RECORD(pEntry, RCB, List);
        NdisInitializeListHead(&pRCB->List);
        
        NdisReleaseSpinLock(&Adapter->RecvLock); 
        
        
        if (InterlockedExchange((PVOID)&pRCB->IrpLock, IRPLOCK_CANCEL_STARTED) 
                                == IRPLOCK_CANCELABLE) {

            // 
            // We got it to the IRP before it was completed. We can cancel
            // the IRP without fear of losing it, as the completion routine
            // will not let go of the IRP until we say so.
            // 
            IoCancelIrp(pRCB->Irp);
            // 
            // Release the completion routine. If it already got there,
            // then we need to free it ourself. Otherwise, we got
            // through IoCancelIrp before the IRP completed entirely.
            // 
            if (InterlockedExchange((PVOID)&pRCB->IrpLock, IRPLOCK_CANCEL_COMPLETE) 
                                    == IRPLOCK_COMPLETED) {
                if(NdisInterlockedDecrement(&pRCB->Ref) == 0) {
                    NICFreeRCB(pRCB);
                } else {
                    ASSERTMSG("Only we have the right to free RCB\n", FALSE);                
                }
            }

        }

        NdisAcquireSpinLock(&Adapter->RecvLock);
        
    }

    NdisReleaseSpinLock(&Adapter->RecvLock); 

    DEBUGP(MP_TRACE, ("<-- NICFreeBusyRecvPackets\n"));
     
    return ;
}


VOID 
NICFreeRCB(
    IN PRCB pRCB)
/*++

Routine Description:

    pRCB      - pointer to RCB block
        
Arguments:

    This routine reinitializes the RCB block and puts it back
    into the RecvFreeList for reuse.
    

Return Value:

    VOID

--*/
{
    PMP_ADAPTER Adapter = pRCB->Adapter;
    
    DEBUGP(MP_TRACE, ("--> NICFreeRCB %p\n", pRCB));
    
    ASSERT(!pRCB->Buffer->Next); // should be NULL
    ASSERT(pRCB->Irp);    // shouldn't be NULL
    ASSERT(!pRCB->Ref); // should be 0
    ASSERT(pRCB->Adapter); // shouldn't be NULL

    IoReuseIrp(pRCB->Irp, STATUS_SUCCESS);    

    // 
    // Set the MDL field to NULL so that we don't end up double freeing the
    // MDL in our call to IoFreeIrp.
    // 
      
    pRCB->Irp->MdlAddress = NULL;
    
    //
    // Re adjust the length to the originl size
    //
    NdisAdjustBufferLength(pRCB->Buffer, NIC_BUFFER_SIZE);

    //
    // Insert the RCB back in the Recv free list     
    //
    NdisAcquireSpinLock(&Adapter->RecvLock);
    
    RemoveEntryList(&pRCB->List);
    
    InsertTailList(&Adapter->RecvFreeList, &pRCB->List);

    NdisInterlockedDecrement(&Adapter->nBusyRecv);
    ASSERT(Adapter->nBusyRecv >= 0);
    
    NdisReleaseSpinLock(&Adapter->RecvLock); 
    
    //
    // For performance, instead of scheduling a workitem at the end of
    // every read completion, we will do it only when the number of 
    // outstanding IRPs goes below NIC_SEND_LOW_WATERMARK.
    // We shouldn't queue a workitem if it's already scheduled and waiting in
    // the system workitem queue to be fired.
    //
    if((!NIC_SEND_LOW_WATERMARK || Adapter->nBusyRecv <= NIC_SEND_LOW_WATERMARK)
            && MP_TEST_FLAG(Adapter, fMP_POST_READS) && 
            (InterlockedExchange(&Adapter->IsReadWorkItemQueued, TRUE) == FALSE)) {

        Adapter->nReadWorkItemScheduled++;
        MP_INC_REF(Adapter);                   
        NdisScheduleWorkItem(&Adapter->ReadWorkItem);   
    }
    DEBUGP(MP_TRACE, ("<-- NICFreeRCB %d\n", Adapter->nBusyRecv));
    
}



BOOLEAN
NICIsPacketAcceptable(
    IN PMP_ADAPTER Adapter,
    IN PUCHAR   pDstMac
    )
/*++

Routine Description:

    Check if the destination address of a received packet
    matches the receive criteria of our adapter.
    
Arguments:

    Adapter    - pointer to the adapter structure
    pDstMac - Destination MAC address to compare


Return Value:

    True or False

--*/
{
    UINT            AddrCompareResult;
    ULONG           PacketFilter;
    BOOLEAN         bPacketMatch;
    BOOLEAN         bIsMulticast, bIsBroadcast;

    PacketFilter = Adapter->PacketFilter;

    bIsMulticast = ETH_IS_MULTICAST(pDstMac);
    bIsBroadcast = ETH_IS_BROADCAST(pDstMac);

    //
    // Handle the directed packet case first.
    //
    if (!bIsMulticast)
    {
        //
        // If the Adapter is not in promisc. mode, check if
        // the destination MAC address matches the local
        // address.
        //
        if ((PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS) == 0)
        {
            ETH_COMPARE_NETWORK_ADDRESSES_EQ(Adapter->CurrentAddress,
                                             pDstMac,
                                             &AddrCompareResult);

            bPacketMatch = ((AddrCompareResult == 0) &&
                           ((PacketFilter & NDIS_PACKET_TYPE_DIRECTED) != 0));
        }
        else
        {
            bPacketMatch = TRUE;
        }
     }
     else
     {
        //
        // Multicast or broadcast packet.
        //

        //
        // Indicate if the filter is set to promisc mode ...
        //
        if ((PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS)
                ||

            //
            // or if this is a broadcast packet and the filter
            // is set to receive all broadcast packets...
            //
            (bIsBroadcast &&
             (PacketFilter & NDIS_PACKET_TYPE_BROADCAST))
                ||

            //
            // or if this is a multicast packet, and the filter is
            // either set to receive all multicast packets, or
            // set to receive specific multicast packets. In the
            // latter case, indicate receive only if the destn
            // MAC address is present in the list of multicast
            // addresses set on the Adapter.
            //
            (!bIsBroadcast &&
             ((PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST) ||
              ((PacketFilter & NDIS_PACKET_TYPE_MULTICAST) &&
               NICIsMulticastMatch(Adapter, pDstMac))))
           )
        {
            bPacketMatch = TRUE;
        }
        else
        {
            //
            // No protocols above are interested in this
            // multicast/broadcast packet.
            //
            bPacketMatch = FALSE;
        }
    }

    return (bPacketMatch);
}

BOOLEAN
NICIsMulticastMatch(
    IN PMP_ADAPTER  Adapter,
    IN PUCHAR       pDstMac
    )
/*++

Routine Description:

    Check if the given multicast destination MAC address matches
    any of the multicast address entries set on the Adapter.

    NOTE: the caller is assumed to hold a READ/WRITE lock
    to the parent ADAPT structure. This is so that the multicast
    list on the Adapter is invariant for the duration of this call.

Arguments:

    Adapter  - Adapter to look in
    pDstMac - Destination MAC address to compare

Return Value:

    TRUE iff the address matches an entry in the Adapter

--*/
{
    ULONG           i;
    UINT            AddrCompareResult;

    for (i = 0; i < Adapter->ulMCListSize; i++)
    {
        ETH_COMPARE_NETWORK_ADDRESSES_EQ(Adapter->MCList[i],
                                         pDstMac,
                                         &AddrCompareResult);
        
        if (AddrCompareResult == 0)
        {
            break;
        }
    }

    return (i != Adapter->ulMCListSize);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -