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.
948 lines
25 KiB
948 lines
25 KiB
/*++
|
|
|
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
|
|
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
|
|
PURPOSE.
|
|
|
|
Module Name:
|
|
|
|
SendRCV.C
|
|
|
|
Abstract:
|
|
|
|
This module contains miniport functions for handling Send & Receive
|
|
packets and other helper routines called by these miniport functions.
|
|
|
|
In order to excercise the send and receive code path of this driver,
|
|
you should install more than one instance of the miniport. If there
|
|
is only one instance installed, the driver throws the send packet on
|
|
the floor and completes the send successfully. If there are more
|
|
instances present, it indicates the incoming send packet to the other
|
|
instances. For example, if there 3 instances: A, B, & C installed.
|
|
Packets coming in for A instance would be indicated to B & C; packets
|
|
coming into B would be indicated to C, & A; and packets coming to C
|
|
would be indicated to A & B.
|
|
|
|
Revision History:
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
#include "miniport.h"
|
|
|
|
|
|
VOID
|
|
MPSendPackets(
|
|
IN NDIS_HANDLE MiniportAdapterContext,
|
|
IN PPNDIS_PACKET PacketArray,
|
|
IN UINT NumberOfPackets)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Send Packet Array handler. Called by NDIS whenever a protocol
|
|
bound to our miniport sends one or more packets.
|
|
|
|
The input packet descriptor pointers have been ordered according
|
|
to the order in which the packets should be sent over the network
|
|
by the protocol driver that set up the packet array. The NDIS
|
|
library preserves the protocol-determined ordering when it submits
|
|
each packet array to MiniportSendPackets
|
|
|
|
As a deserialized driver, we are responsible for holding incoming send
|
|
packets in our internal queue until they can be transmitted over the
|
|
network and for preserving the protocol-determined ordering of packet
|
|
descriptors incoming to its MiniportSendPackets function.
|
|
A deserialized miniport driver must complete each incoming send packet
|
|
with NdisMSendComplete, and it cannot call NdisMSendResourcesAvailable.
|
|
|
|
Runs at IRQL <= DISPATCH_LEVEL
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterContext Pointer to our adapter context
|
|
PacketArray Set of packets to send
|
|
NumberOfPackets Length of above array
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PMP_ADAPTER Adapter;
|
|
NDIS_STATUS Status;
|
|
UINT PacketCount;
|
|
|
|
DEBUGP(MP_TRACE, ("---> MPSendPackets\n"));
|
|
|
|
Adapter = (PMP_ADAPTER)MiniportAdapterContext;
|
|
|
|
for(PacketCount=0;PacketCount < NumberOfPackets; PacketCount++)
|
|
{
|
|
//
|
|
// Check for a zero pointer
|
|
//
|
|
ASSERT(PacketArray[PacketCount]);
|
|
|
|
Status = NICSendPacket(Adapter, PacketArray[PacketCount]);
|
|
|
|
}
|
|
|
|
DEBUGP(MP_TRACE, ("<--- MPSendPackets\n"));
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
MPReturnPacket(
|
|
IN NDIS_HANDLE MiniportAdapterContext,
|
|
IN PNDIS_PACKET Packet)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
NDIS Miniport entry point called whenever protocols are done with
|
|
a packet that we had indicated up and they had queued up for returning
|
|
later.
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterContext - pointer to MP_ADAPTER structure
|
|
Packet - packet being returned.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PMP_ADAPTER Adapter = (PMP_ADAPTER) MiniportAdapterContext;
|
|
|
|
DEBUGP(MP_TRACE, ("---> MPReturnPacket\n"));
|
|
|
|
NICFreeRecvPacket(Adapter, Packet);
|
|
|
|
DEBUGP(MP_TRACE, ("<--- MPReturnPacket\n"));
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
NICSendPacket(
|
|
PMP_ADAPTER Adapter,
|
|
PNDIS_PACKET Packet)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine copies the packet content to a TCB, gets a receive packet,
|
|
associates the TCB buffer to this recive packet and queues
|
|
receive packet with the same data on one or more miniport instances
|
|
controlled by this driver. For receive path to be active, you have
|
|
to install more than one instance of this miniport.
|
|
|
|
Arguments:
|
|
|
|
Adapter - pointer to the MP_ADAPTER structure
|
|
Packet - packet to be transfered.
|
|
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS or NDIS_STATUS_PENDING
|
|
|
|
--*/
|
|
{
|
|
PMP_ADAPTER DestAdapter;
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
PTCB pTCB = NULL;
|
|
|
|
DEBUGP(MP_TRACE, ("--> NICSendPacket, Packet= %p\n", Packet));
|
|
|
|
//
|
|
// Go through the adapter list and queue packet for
|
|
// indication on them if there are any. Otherwise
|
|
// just drop the packet on the floor and tell NDIS that
|
|
// you have completed send.
|
|
//
|
|
NdisAcquireSpinLock(&GlobalData.Lock);
|
|
DestAdapter = (PMP_ADAPTER) &GlobalData.AdapterList;
|
|
|
|
while(MP_IS_READY(Adapter))
|
|
{
|
|
DestAdapter = (PMP_ADAPTER) DestAdapter->List.Flink;
|
|
if((PLIST_ENTRY)DestAdapter == &GlobalData.AdapterList)
|
|
{
|
|
//
|
|
// We have reached the end of the adapter list. So
|
|
//
|
|
break;
|
|
}
|
|
|
|
//
|
|
// We wouldn't transmit the packet if:
|
|
// a) The destination adapter is same as the Send Adapter.
|
|
// b) The destination adapter is not ready to receive packets.
|
|
// c) The packet itself is not worth transmitting.
|
|
//
|
|
if(DestAdapter == Adapter ||
|
|
!MP_IS_READY(DestAdapter) ||
|
|
!NICIsPacketTransmittable(DestAdapter, Packet))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
DEBUGP(MP_LOUD, ("Packet is accepted...\n"));
|
|
|
|
if(!pTCB)
|
|
{
|
|
pTCB = (PTCB) NdisInterlockedRemoveHeadList(
|
|
&Adapter->SendFreeList,
|
|
&Adapter->SendLock);
|
|
if(pTCB == NULL)
|
|
{
|
|
DEBUGP(MP_WARNING, ("Can't allocate a TCB......!\n"));
|
|
|
|
Status = NDIS_STATUS_PENDING;
|
|
|
|
//
|
|
// Not able to get TCB block for this send. So queue
|
|
// it for later transmission and break out of the loop.
|
|
//
|
|
NdisInterlockedInsertTailList(
|
|
&Adapter->SendWaitList,
|
|
(PLIST_ENTRY)&Packet->MiniportReserved[0],
|
|
&Adapter->SendLock);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
NdisInterlockedIncrement(&Adapter->nBusySend);
|
|
ASSERT(Adapter->nBusySend <= NIC_MAX_BUSY_SENDS);
|
|
//
|
|
// Copy the packet content into the TCB data buffer,
|
|
// assuming the NIC is doing a common buffer DMA. For
|
|
// scatter/gather DMA, this copy operation is not required.
|
|
// For efficiency, I could have avoided the copy operation
|
|
// in this driver and directly indicated the send buffers to
|
|
// other miniport instances since I'm holding the send packet
|
|
// until all the indicated packets are returned. Oh, well!
|
|
//
|
|
if(!NICCopyPacket(Adapter, pTCB, Packet)){
|
|
DEBUGP(MP_ERROR, ("NICCopyPacket failed\n"));
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Status = NDIS_STATUS_PENDING;
|
|
|
|
NICQueuePacketForRecvIndication(DestAdapter, pTCB);
|
|
|
|
} // while
|
|
|
|
NdisReleaseSpinLock(&GlobalData.Lock);
|
|
|
|
NDIS_SET_PACKET_STATUS(Packet, Status);
|
|
|
|
if(Status == NDIS_STATUS_SUCCESS ||
|
|
(pTCB && (NdisInterlockedDecrement(&pTCB->Ref) == 0)))
|
|
{
|
|
|
|
DEBUGP(MP_LOUD, ("Calling NdisMSendComplete \n"));
|
|
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
|
|
NdisMSendComplete(
|
|
Adapter->AdapterHandle,
|
|
Packet,
|
|
Status);
|
|
|
|
if(pTCB)
|
|
{
|
|
NICFreeSendTCB(Adapter, pTCB);
|
|
}
|
|
}
|
|
|
|
DEBUGP(MP_TRACE, ("<-- NICSendPacket Status = 0x%08x\n", Status));
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
NICQueuePacketForRecvIndication(
|
|
PMP_ADAPTER Adapter,
|
|
PTCB pTCB)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine queues the send packet in to the destination
|
|
adapters RecvWaitList and fires a timer DPC so that it
|
|
cab be indicated as soon as possible.
|
|
|
|
Arguments:
|
|
|
|
Adapter - pointer to the destination adapter structure
|
|
pTCB - pointer to TCB block
|
|
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
{
|
|
PNDIS_PACKET SendPacket = pTCB->OrgSendPacket;
|
|
PNDIS_PACKET RecvPacket = NULL;
|
|
PNDIS_BUFFER CurrentBuffer = NULL;
|
|
UINT NumPhysDesc, BufferCount, PacketLength, RecvPacketLength;
|
|
PLIST_ENTRY pEntry;
|
|
PRCB pRCB;
|
|
NDIS_STATUS Status;
|
|
|
|
|
|
DEBUGP(MP_TRACE, ("--> NICQueuePacketForRecvIndication\n"));
|
|
|
|
//
|
|
// Allocate memory for RCB.
|
|
//
|
|
pRCB = NdisAllocateFromNPagedLookasideList(&Adapter->RecvLookaside);
|
|
if(!pRCB)
|
|
{
|
|
DEBUGP(MP_ERROR, ("Failed to allocate memory for RCB\n"));
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Get a free recv packet descriptor from the list.
|
|
//
|
|
pEntry = (PLIST_ENTRY) NdisInterlockedRemoveHeadList(
|
|
&Adapter->RecvFreeList,
|
|
&Adapter->RecvLock);
|
|
if(!pEntry)
|
|
{
|
|
++Adapter->RcvResourceErrors;
|
|
NdisFreeToNPagedLookasideList(&Adapter->RecvLookaside, pRCB);
|
|
}
|
|
else
|
|
{
|
|
++Adapter->GoodReceives;
|
|
|
|
RecvPacket = CONTAINING_RECORD(pEntry, NDIS_PACKET, MiniportReserved);
|
|
|
|
//
|
|
// Prepare the recv packet
|
|
//
|
|
NdisReinitializePacket(RecvPacket);
|
|
*((PTCB *)RecvPacket->MiniportReserved) = pTCB;
|
|
|
|
//
|
|
// Chain the TCB buffers to the packet
|
|
//
|
|
NdisChainBufferAtBack(RecvPacket, pTCB->Buffer);
|
|
|
|
#if DBG
|
|
NdisQueryPacket(
|
|
RecvPacket,
|
|
NULL,
|
|
NULL,
|
|
&CurrentBuffer,
|
|
&RecvPacketLength);
|
|
|
|
ASSERT(CurrentBuffer == pTCB->Buffer);
|
|
|
|
NdisQueryPacket(
|
|
SendPacket,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&PacketLength);
|
|
|
|
if((RecvPacketLength != 60) && (RecvPacketLength != PacketLength))
|
|
{
|
|
DEBUGP(MP_ERROR, ("RecvPacketLength = %d, PacketLength = %d\n",
|
|
RecvPacketLength, PacketLength));
|
|
DEBUGP(MP_ERROR, ("RecvPacket = %p, Packet = %p\n",
|
|
RecvPacket, SendPacket));
|
|
ASSERT(FALSE);
|
|
}
|
|
#endif
|
|
|
|
NDIS_SET_PACKET_STATUS(RecvPacket, NDIS_STATUS_SUCCESS);
|
|
|
|
DEBUGP(MP_LOUD, ("RecvPkt= %p\n", RecvPacket));
|
|
|
|
//
|
|
// Initialize RCB
|
|
//
|
|
NdisInitializeListHead(&pRCB->List);
|
|
pRCB->Packet = RecvPacket;
|
|
|
|
//
|
|
// Increment the Ref count on the TCB to denote that it's being
|
|
// used. This reference will be removed when the indicated
|
|
// Recv packet finally returns from the protocol.
|
|
//
|
|
NdisInterlockedIncrement(&pTCB->Ref);
|
|
|
|
//
|
|
// Insert the packet in the recv wait queue to be picked up by
|
|
// the receive indication DPC.
|
|
//
|
|
NdisInterlockedIncrement(&Adapter->nBusyRecv);
|
|
ASSERT(Adapter->nBusyRecv <= NIC_MAX_BUSY_RECVS);
|
|
NdisInterlockedInsertTailList(
|
|
&Adapter->RecvWaitList,
|
|
&pRCB->List,
|
|
&Adapter->RecvLock);
|
|
|
|
//
|
|
// Fire a timer DPC. By specifing zero timeout, the DPC will
|
|
// be serviced whenever the next system timer interrupt arrives.
|
|
//
|
|
NdisMSetTimer(&Adapter->RecvTimer, 0);
|
|
|
|
}
|
|
|
|
DEBUGP(MP_TRACE, ("<-- NICQueuePacketForRecvIndication\n"));
|
|
}
|
|
|
|
VOID
|
|
NICIndicateReceiveTimerDpc(
|
|
IN PVOID SystemSpecific1,
|
|
IN PVOID FunctionContext,
|
|
IN PVOID SystemSpecific2,
|
|
IN PVOID SystemSpecific3)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Timer callback function for Receive Indication. Please note that receive
|
|
timer DPC is not required when you are talking to a real device. In real
|
|
miniports, this DPC is usually provided by NDIS as MPHandleInterrupt
|
|
callback whenever the device interrupts for receive indication.
|
|
|
|
Arguments:
|
|
|
|
FunctionContext - Pointer to our adapter
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
{
|
|
PMP_ADAPTER Adapter = (PMP_ADAPTER)FunctionContext;
|
|
PRCB pRCB = NULL;
|
|
PLIST_ENTRY pEntry = NULL;
|
|
|
|
DEBUGP(MP_TRACE, ("--->NICIndicateReceiveTimerDpc = %p\n", Adapter));
|
|
|
|
//
|
|
// Increment the ref count on the adapter to prevent the driver from
|
|
// unloding while the DPC is running. The Halt handler waits for the
|
|
// ref count to drop to zero before returning.
|
|
//
|
|
MP_INC_REF(Adapter);
|
|
|
|
//
|
|
// Remove the packet from waitlist and indicate it to the protocols
|
|
// above us.
|
|
//
|
|
while (pEntry = (PLIST_ENTRY) NdisInterlockedRemoveHeadList(
|
|
&Adapter->RecvWaitList,
|
|
&Adapter->RecvLock)) {
|
|
|
|
pRCB = CONTAINING_RECORD(pEntry, RCB, List);
|
|
|
|
ASSERT(pRCB);
|
|
ASSERT(pRCB->Packet);
|
|
|
|
DEBUGP(MP_LOUD, ("Indicating packet = %p\n", pRCB->Packet));
|
|
|
|
NdisMIndicateReceivePacket(
|
|
Adapter->AdapterHandle,
|
|
&pRCB->Packet,
|
|
1);
|
|
|
|
//
|
|
// We are done with RCB memory. So free it.
|
|
//
|
|
NdisFreeToNPagedLookasideList(&Adapter->RecvLookaside, pRCB);
|
|
|
|
}
|
|
|
|
MP_DEC_REF(Adapter);
|
|
DEBUGP(MP_TRACE, ("<---NICIndicateReceiveTimerDpc\n"));
|
|
}
|
|
|
|
VOID
|
|
NICFreeRecvPacket(
|
|
PMP_ADAPTER Adapter,
|
|
PNDIS_PACKET Packet)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adapter - pointer to the adapter structure
|
|
Packet - pointer to the receive packet
|
|
|
|
Arguments:
|
|
|
|
This is called by MPReturnPacket to free the Receive packet
|
|
indicated above. Since we have used the send-side TCB, we
|
|
will also carefully complete the pending SendPacket if we are
|
|
the last one to use the TCB buffers.
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
{
|
|
|
|
PTCB pTCB = *(PTCB *)Packet->MiniportReserved;
|
|
PMP_ADAPTER SendAdapter = (PMP_ADAPTER)pTCB->Adapter;
|
|
PNDIS_PACKET SendPacket = pTCB->OrgSendPacket;
|
|
PLIST_ENTRY pEntry;
|
|
|
|
DEBUGP(MP_TRACE, ("--> NICFreeRecvPacket\n"));
|
|
DEBUGP(MP_INFO, ("Adapter= %p FreePkt= %p Ref=%d\n",
|
|
SendAdapter, SendPacket, pTCB->Ref));
|
|
|
|
ASSERT(pTCB->Ref > 0);
|
|
ASSERT(Adapter);
|
|
//
|
|
// Put the packet back in the free list for reuse.
|
|
//
|
|
NdisInterlockedInsertTailList(
|
|
&Adapter->RecvFreeList,
|
|
(PLIST_ENTRY)&Packet->MiniportReserved[0],
|
|
&Adapter->RecvLock);
|
|
|
|
NdisInterlockedDecrement(&Adapter->nBusyRecv);
|
|
ASSERT(Adapter->nBusyRecv >= 0);
|
|
|
|
//
|
|
// Check to see whether we are the last one to use the TCB
|
|
// by decrementing the refcount. If so, complete the pending
|
|
// Send packet and free the TCB block for reuse.
|
|
//
|
|
if(NdisInterlockedDecrement(&pTCB->Ref) == 0)
|
|
{
|
|
NdisMSendComplete(
|
|
SendAdapter->AdapterHandle,
|
|
SendPacket,
|
|
NDIS_STATUS_SUCCESS);
|
|
|
|
NICFreeSendTCB(SendAdapter, pTCB);
|
|
//
|
|
// Before we exit, since we have the control, let use see if there any
|
|
// more packets waiting in the queue to be sent.
|
|
//
|
|
if(MP_IS_READY(SendAdapter))
|
|
{
|
|
pEntry = (PLIST_ENTRY) NdisInterlockedRemoveHeadList(
|
|
&SendAdapter->SendWaitList,
|
|
&SendAdapter->SendLock);
|
|
if(pEntry)
|
|
{
|
|
SendPacket = CONTAINING_RECORD(pEntry, NDIS_PACKET, MiniportReserved);
|
|
NICSendPacket(SendAdapter, SendPacket);
|
|
}
|
|
}
|
|
}
|
|
|
|
DEBUGP(MP_TRACE, ("<-- NICFreeRecvPacket\n"));
|
|
}
|
|
|
|
VOID
|
|
NICFreeSendTCB(
|
|
IN PMP_ADAPTER Adapter,
|
|
IN PTCB pTCB)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adapter - pointer to the adapter structure
|
|
pTCB - pointer to TCB block
|
|
|
|
Arguments:
|
|
|
|
This routine reinitializes the TCB block and puts it back
|
|
into the SendFreeList for reuse.
|
|
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
{
|
|
DEBUGP(MP_TRACE, ("--> NICFreeSendTCB %p\n", pTCB));
|
|
|
|
pTCB->OrgSendPacket = NULL;
|
|
pTCB->Buffer->Next = NULL;
|
|
|
|
ASSERT(!pTCB->Ref);
|
|
|
|
//
|
|
// Re adjust the length to the originl size
|
|
//
|
|
NdisAdjustBufferLength(pTCB->Buffer, NIC_BUFFER_SIZE);
|
|
|
|
//
|
|
// Insert the TCB back in the send free list
|
|
//
|
|
NdisAcquireSpinLock(&Adapter->SendLock);
|
|
NdisInitializeListHead(&pTCB->List);
|
|
InsertHeadList(&Adapter->SendFreeList, &pTCB->List);
|
|
NdisReleaseSpinLock(&Adapter->SendLock);
|
|
|
|
NdisInterlockedDecrement(&Adapter->nBusySend);
|
|
ASSERT(Adapter->nBusySend >= 0);
|
|
DEBUGP(MP_TRACE, ("<-- NICFreeSendTCB\n"));
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
NICFreeQueuedSendPackets(
|
|
PMP_ADAPTER Adapter
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the Halt or Reset handler to fail all
|
|
the queued up SendPackets because the device is either
|
|
gone, being stopped for resource rebalance, or reset.
|
|
|
|
Arguments:
|
|
|
|
Adapter - pointer to the adapter structure
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
{
|
|
PLIST_ENTRY pEntry;
|
|
PNDIS_PACKET Packet;
|
|
|
|
DEBUGP(MP_TRACE, ("--> NICFreeQueuedSendPackets\n"));
|
|
|
|
while(TRUE)
|
|
{
|
|
pEntry = (PLIST_ENTRY) NdisInterlockedRemoveHeadList(
|
|
&Adapter->SendWaitList,
|
|
&Adapter->SendLock);
|
|
if(!pEntry)
|
|
{
|
|
break;
|
|
}
|
|
|
|
Packet = CONTAINING_RECORD(pEntry, NDIS_PACKET, MiniportReserved);
|
|
NdisMSendComplete(
|
|
Adapter->AdapterHandle,
|
|
Packet,
|
|
NDIS_STATUS_FAILURE);
|
|
}
|
|
|
|
DEBUGP(MP_TRACE, ("<-- NICFreeQueuedSendPackets\n"));
|
|
|
|
}
|
|
|
|
VOID
|
|
NICFreeQueuedRecvPackets(
|
|
PMP_ADAPTER Adapter
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the Halt handler to fail all
|
|
the queued up RecvPackets if it succeeds in cancelling
|
|
the RecvIndicate timer DPC.
|
|
|
|
Arguments:
|
|
|
|
Adapter - pointer to the adapter structure
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
{
|
|
PLIST_ENTRY pEntry;
|
|
PRCB pRCB = NULL;
|
|
|
|
DEBUGP(MP_TRACE, ("--> NICFreeQueuedRecvPackets\n"));
|
|
|
|
while(TRUE)
|
|
{
|
|
pEntry = (PLIST_ENTRY) NdisInterlockedRemoveHeadList(
|
|
&Adapter->RecvWaitList,
|
|
&Adapter->RecvLock);
|
|
if(!pEntry)
|
|
{
|
|
break;
|
|
}
|
|
|
|
pRCB = CONTAINING_RECORD(pEntry, RCB, List);
|
|
|
|
ASSERT(pRCB);
|
|
ASSERT(pRCB->Packet);
|
|
|
|
NICFreeRecvPacket(Adapter, pRCB->Packet);
|
|
|
|
//
|
|
// We are done with RCB memory. So free it.
|
|
//
|
|
NdisFreeToNPagedLookasideList(&Adapter->RecvLookaside, pRCB);
|
|
|
|
}
|
|
|
|
DEBUGP(MP_TRACE, ("<-- NICFreeQueuedRecvPackets\n"));
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
NICIsPacketTransmittable(
|
|
PMP_ADAPTER Adapter,
|
|
PNDIS_PACKET Packet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routines checks to see whether the packet can be accepted
|
|
for transmission based on the currently programmed filter type
|
|
of the NIC and the mac address of the packet.
|
|
|
|
Arguments:
|
|
|
|
Adapter - pointer to the adapter structure
|
|
Packet - pointer to the send packet
|
|
|
|
|
|
Return Value:
|
|
|
|
True or False
|
|
|
|
--*/
|
|
{
|
|
int Equal;
|
|
UINT PacketLength;
|
|
PNDIS_BUFFER FirstBuffer;
|
|
PUCHAR Address;
|
|
UINT CurrentLength;
|
|
ULONG index;
|
|
BOOLEAN result = FALSE;
|
|
|
|
NdisGetFirstBufferFromPacket(
|
|
Packet,
|
|
&FirstBuffer,
|
|
&Address,
|
|
&CurrentLength,
|
|
&PacketLength);
|
|
|
|
|
|
DEBUGP(MP_LOUD,
|
|
("DestAdapter=%p, PacketFilter = 0x%08x\n",
|
|
Adapter,
|
|
Adapter->PacketFilter));
|
|
|
|
DEBUGP(MP_LOUD, ("Dest Address = %02x-%02x-%02x-%02x-%02x-%02x\n",
|
|
Address[0], Address[1], Address[2],
|
|
Address[3], Address[4], Address[5]));
|
|
|
|
do {
|
|
|
|
//
|
|
// If the NIC is in promiscuous mode, we will transmit anything
|
|
// and everything.
|
|
//
|
|
if(Adapter->PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS) {
|
|
result = TRUE;
|
|
break;
|
|
}
|
|
else if(ETH_IS_BROADCAST(Address)) {
|
|
//
|
|
// If it's a broadcast packet, check our filter settings to see
|
|
// we can transmit that.
|
|
//
|
|
if(Adapter->PacketFilter & NDIS_PACKET_TYPE_BROADCAST) {
|
|
result = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
else if(ETH_IS_MULTICAST(Address)) {
|
|
//
|
|
// If it's a multicast packet, check our filter settings to see
|
|
// we can transmit that.
|
|
//
|
|
if(Adapter->PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST) {
|
|
result = TRUE;
|
|
break;
|
|
}
|
|
else if(Adapter->PacketFilter & NDIS_PACKET_TYPE_MULTICAST) {
|
|
//
|
|
// Check to see if the multicast address is in our list
|
|
//
|
|
for(index=0; index < Adapter->ulMCListSize; index++) {
|
|
ETH_COMPARE_NETWORK_ADDRESSES_EQ(
|
|
Address,
|
|
Adapter->MCList[index],
|
|
&Equal);
|
|
if(Equal == 0){ // 0 Implies equality
|
|
result = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if(Adapter->PacketFilter & NDIS_PACKET_TYPE_DIRECTED) {
|
|
//
|
|
// This has to be a directed packet. If so, does packet source
|
|
// address match with the mac address of the NIC.
|
|
//
|
|
ETH_COMPARE_NETWORK_ADDRESSES_EQ(
|
|
Address,
|
|
Adapter->CurrentAddress,
|
|
&Equal);
|
|
if(Equal == 0){
|
|
result = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
//
|
|
// This is a junk packet. We can't transmit this.
|
|
//
|
|
result = FALSE;
|
|
|
|
}while(FALSE);
|
|
|
|
return result;
|
|
}
|
|
|
|
BOOLEAN
|
|
NICCopyPacket(
|
|
PMP_ADAPTER Adapter,
|
|
PTCB pTCB,
|
|
PNDIS_PACKET Packet)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine copies the packet data into the TCB data block.
|
|
|
|
Arguments:
|
|
|
|
Adapter - pointer to the MP_ADAPTER structure
|
|
pTCB - pointer to TCB block
|
|
Packet - packet to be transfered.
|
|
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
{
|
|
PNDIS_BUFFER MyBuffer;
|
|
PNDIS_BUFFER CurrentBuffer;
|
|
PVOID VirtualAddress;
|
|
UINT CurrentLength;
|
|
UINT BytesToCopy;
|
|
UINT BytesCopied = 0;
|
|
UINT BufferCount;
|
|
UINT PacketLength;
|
|
UINT DestBufferSize = NIC_BUFFER_SIZE;
|
|
PUCHAR pDest;
|
|
BOOLEAN bResult = TRUE;
|
|
|
|
DEBUGP(MP_TRACE, ("--> NICCopyPacket\n"));
|
|
|
|
pTCB->OrgSendPacket = Packet;
|
|
pTCB->Ref = 1;
|
|
|
|
MyBuffer = pTCB->Buffer;
|
|
pDest = pTCB->pData;
|
|
|
|
MyBuffer->Next = NULL;
|
|
|
|
NdisQueryPacket(Packet,
|
|
NULL,
|
|
&BufferCount,
|
|
&CurrentBuffer,
|
|
&PacketLength);
|
|
|
|
ASSERT(PacketLength <= NIC_BUFFER_SIZE);
|
|
|
|
BytesToCopy = min(PacketLength, NIC_BUFFER_SIZE);
|
|
|
|
if(BytesToCopy < ETH_MIN_PACKET_SIZE)
|
|
{
|
|
BytesToCopy = ETH_MIN_PACKET_SIZE; // padding
|
|
}
|
|
|
|
while(CurrentBuffer && DestBufferSize)
|
|
{
|
|
NdisQueryBufferSafe(
|
|
CurrentBuffer,
|
|
&VirtualAddress,
|
|
&CurrentLength,
|
|
NormalPagePriority);
|
|
|
|
if(VirtualAddress == NULL){
|
|
bResult = FALSE;
|
|
break;
|
|
}
|
|
|
|
CurrentLength = min(CurrentLength, DestBufferSize);
|
|
|
|
if(CurrentLength)
|
|
{
|
|
// Copy the data.
|
|
NdisMoveMemory(pDest, VirtualAddress, CurrentLength);
|
|
BytesCopied += CurrentLength;
|
|
DestBufferSize -= CurrentLength;
|
|
pDest += CurrentLength;
|
|
}
|
|
|
|
NdisGetNextBuffer(
|
|
CurrentBuffer,
|
|
&CurrentBuffer);
|
|
}
|
|
|
|
if(bResult) {
|
|
if(BytesCopied < BytesToCopy)
|
|
{
|
|
//
|
|
// This would be the case if the packet size is less than
|
|
// ETH_MIN_PACKET_SIZE
|
|
//
|
|
BytesCopied = BytesToCopy;
|
|
}
|
|
NdisAdjustBufferLength(MyBuffer, BytesCopied);
|
|
}
|
|
|
|
DEBUGP(MP_TRACE, ("<-- NICCopyPacket\n"));
|
|
|
|
return bResult;
|
|
}
|
|
|