📄 receive.c
字号:
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 + -