mirror of https://github.com/lianthony/NT4.0
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.
3212 lines
69 KiB
3212 lines
69 KiB
/*++
|
|
|
|
Copyright (c) 1990-1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
sendm.c
|
|
|
|
Abstract:
|
|
|
|
Author:
|
|
|
|
Kyle Brandon (KyleB)
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <precomp.h>
|
|
#pragma hdrstop
|
|
|
|
#include "sendm.h"
|
|
|
|
//
|
|
// Define the module number for debug code.
|
|
//
|
|
#define MODULE_NUMBER MODULE_SENDM
|
|
|
|
VOID
|
|
ndisMCopyFromPacketToBuffer(
|
|
IN PNDIS_PACKET Packet,
|
|
IN UINT Offset,
|
|
IN UINT BytesToCopy,
|
|
OUT PCHAR Buffer,
|
|
OUT PUINT BytesCopied
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Copy from an ndis packet into a buffer.
|
|
|
|
Arguments:
|
|
|
|
Packet - The packet to copy from.
|
|
|
|
Offset - The offset from which to start the copy.
|
|
|
|
BytesToCopy - The number of bytes to copy from the packet.
|
|
|
|
Buffer - The destination of the copy.
|
|
|
|
BytesCopied - The number of bytes actually copied. Can be less then
|
|
BytesToCopy if the packet is shorter than BytesToCopy.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Holds the number of ndis buffers comprising the packet.
|
|
//
|
|
UINT NdisBufferCount;
|
|
|
|
//
|
|
// Points to the buffer from which we are extracting data.
|
|
//
|
|
PNDIS_BUFFER CurrentBuffer;
|
|
|
|
//
|
|
// Holds the virtual address of the current buffer.
|
|
//
|
|
PVOID VirtualAddress;
|
|
|
|
//
|
|
// Holds the length of the current buffer of the packet.
|
|
//
|
|
UINT CurrentLength;
|
|
|
|
//
|
|
// Keep a local variable of BytesCopied so we aren't referencing
|
|
// through a pointer.
|
|
//
|
|
UINT LocalBytesCopied = 0;
|
|
|
|
//
|
|
// Take care of boundary condition of zero length copy.
|
|
//
|
|
|
|
*BytesCopied = 0;
|
|
if (!BytesToCopy)
|
|
return;
|
|
|
|
//
|
|
// Get the first buffer.
|
|
//
|
|
|
|
NdisQueryPacket(Packet,
|
|
NULL,
|
|
&NdisBufferCount,
|
|
&CurrentBuffer,
|
|
NULL);
|
|
|
|
//
|
|
// Could have a null packet.
|
|
//
|
|
|
|
if (!NdisBufferCount)
|
|
return;
|
|
|
|
NdisQueryBuffer(CurrentBuffer, &VirtualAddress, &CurrentLength);
|
|
|
|
while (LocalBytesCopied < BytesToCopy)
|
|
{
|
|
if (CurrentLength == 0)
|
|
{
|
|
NdisGetNextBuffer(CurrentBuffer, &CurrentBuffer);
|
|
|
|
//
|
|
// We've reached the end of the packet. We return
|
|
// with what we've done so far. (Which must be shorter
|
|
// than requested.
|
|
//
|
|
|
|
if (!CurrentBuffer)
|
|
break;
|
|
|
|
NdisQueryBuffer(CurrentBuffer, &VirtualAddress, &CurrentLength);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Try to get us up to the point to start the copy.
|
|
//
|
|
|
|
if (Offset)
|
|
{
|
|
if (Offset > CurrentLength)
|
|
{
|
|
//
|
|
// What we want isn't in this buffer.
|
|
//
|
|
|
|
Offset -= CurrentLength;
|
|
CurrentLength = 0;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
VirtualAddress = (PCHAR)VirtualAddress + Offset;
|
|
CurrentLength -= Offset;
|
|
Offset = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Copy the data.
|
|
//
|
|
{
|
|
//
|
|
// Holds the amount of data to move.
|
|
//
|
|
UINT AmountToMove;
|
|
|
|
AmountToMove = ((CurrentLength <= (BytesToCopy - LocalBytesCopied)) ?
|
|
(CurrentLength):
|
|
(BytesToCopy - LocalBytesCopied));
|
|
|
|
MoveMemory(Buffer, VirtualAddress, AmountToMove);
|
|
|
|
Buffer = (PCHAR)Buffer + AmountToMove;
|
|
VirtualAddress = (PCHAR)VirtualAddress + AmountToMove;
|
|
|
|
LocalBytesCopied += AmountToMove;
|
|
CurrentLength -= AmountToMove;
|
|
}
|
|
}
|
|
|
|
*BytesCopied = LocalBytesCopied;
|
|
}
|
|
|
|
BOOLEAN
|
|
FASTCALL
|
|
ndisMIsLoopbackPacket(
|
|
IN PNDIS_MINIPORT_BLOCK Miniport,
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will determine if a packet needs to be looped back in
|
|
software. if the packet is any kind of loopback packet then it
|
|
will get placed on the loopback queue and a workitem will be queued
|
|
to process it later.
|
|
|
|
Arguments:
|
|
|
|
Miniport- Pointer to the miniport block to send the packet on.
|
|
Packet - Packet to check for loopback.
|
|
|
|
Return Value:
|
|
|
|
Returns TRUE if the packet is self-directed.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_BUFFER FirstBuffer;
|
|
UINT Length;
|
|
UINT Offset;
|
|
PUCHAR BufferAddress;
|
|
BOOLEAN Loopback;
|
|
BOOLEAN SelfDirected;
|
|
PNDIS_PACKET pNewPacket;
|
|
PUCHAR Buffer;
|
|
NDIS_STATUS Status;
|
|
PNDIS_BUFFER pNdisBuffer;
|
|
UINT HdrLength;
|
|
BOOLEAN ArcEncap = TRUE;
|
|
|
|
//
|
|
// We should not be here if the driver handles loopback.
|
|
//
|
|
ASSERT(Miniport->MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK);
|
|
ASSERT(MINIPORT_AT_DPC_LEVEL);
|
|
|
|
FirstBuffer = Packet->Private.Head;
|
|
BufferAddress = MDL_ADDRESS(FirstBuffer);
|
|
|
|
//
|
|
// If the card does not do loopback, then we check if
|
|
// we need to send it to ourselves, then if that is the
|
|
// case we also check for it being self-directed.
|
|
//
|
|
switch (Miniport->MediaType)
|
|
{
|
|
case NdisMedium802_3:
|
|
|
|
if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_LOOPBACK_DIRECTED))
|
|
{
|
|
if (ETH_IS_MULTICAST(BufferAddress))
|
|
{
|
|
Loopback = FALSE;
|
|
SelfDirected = FALSE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Packet is of type directed, now make sure that it
|
|
// is not self-directed.
|
|
//
|
|
ETH_COMPARE_NETWORK_ADDRESSES_EQ(
|
|
BufferAddress,
|
|
Miniport->EthDB->AdapterAddress,
|
|
&Loopback);
|
|
|
|
SelfDirected = FALSE;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Check for the miniports that don't do loopback.
|
|
//
|
|
EthShouldAddressLoopBackMacro(Miniport->EthDB,
|
|
BufferAddress,
|
|
&Loopback,
|
|
&SelfDirected);
|
|
break;
|
|
|
|
case NdisMedium802_5:
|
|
|
|
if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_LOOPBACK_DIRECTED))
|
|
{
|
|
BOOLEAN IsNotDirected;
|
|
TR_IS_NOT_DIRECTED(BufferAddress + 2, &IsNotDirected);
|
|
if (IsNotDirected)
|
|
{
|
|
Loopback = FALSE;
|
|
SelfDirected = FALSE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Packet is of type directed, now make sure that it
|
|
// is not self-directed.
|
|
//
|
|
TR_COMPARE_NETWORK_ADDRESSES_EQ(
|
|
BufferAddress + 2,
|
|
Miniport->TrDB->AdapterAddress,
|
|
&Loopback);
|
|
|
|
SelfDirected = FALSE;
|
|
|
|
break;
|
|
}
|
|
|
|
TrShouldAddressLoopBackMacro(Miniport->TrDB,
|
|
BufferAddress +2,
|
|
BufferAddress +8,
|
|
&Loopback,
|
|
&SelfDirected);
|
|
|
|
break;
|
|
|
|
case NdisMediumFddi:
|
|
|
|
if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_LOOPBACK_DIRECTED))
|
|
{
|
|
BOOLEAN IsMulticast;
|
|
|
|
FDDI_IS_MULTICAST(
|
|
BufferAddress + 1,
|
|
(BufferAddress[0] & 0x40) ?
|
|
FDDI_LENGTH_OF_LONG_ADDRESS :
|
|
FDDI_LENGTH_OF_SHORT_ADDRESS,
|
|
&IsMulticast);
|
|
if (IsMulticast)
|
|
{
|
|
Loopback = FALSE;
|
|
SelfDirected = FALSE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Packet is of type directed, now make sure that it
|
|
// is not self-directed.
|
|
//
|
|
FDDI_COMPARE_NETWORK_ADDRESSES_EQ(
|
|
BufferAddress + 1,
|
|
(BufferAddress[0] & 0x40) ?
|
|
Miniport->FddiDB->AdapterLongAddress :
|
|
Miniport->FddiDB->AdapterShortAddress,
|
|
(BufferAddress[0] & 0x40) ?
|
|
FDDI_LENGTH_OF_LONG_ADDRESS :
|
|
FDDI_LENGTH_OF_SHORT_ADDRESS,
|
|
&Loopback);
|
|
|
|
SelfDirected = FALSE;
|
|
|
|
break;
|
|
}
|
|
|
|
FddiShouldAddressLoopBackMacro(Miniport->FddiDB,
|
|
BufferAddress + 1, // Skip FC byte to dest address.
|
|
(BufferAddress[0] & 0x40) ?
|
|
FDDI_LENGTH_OF_LONG_ADDRESS :
|
|
FDDI_LENGTH_OF_SHORT_ADDRESS,
|
|
&Loopback,
|
|
&SelfDirected);
|
|
break;
|
|
|
|
case NdisMediumArcnet878_2:
|
|
|
|
//
|
|
// We just handle arcnet packets (encapsulated or not) in
|
|
// a totally different manner...
|
|
//
|
|
SelfDirected = ndisMArcnetSendLoopback(Miniport, Packet);
|
|
|
|
//
|
|
// Mark the packet as having been looped back.
|
|
//
|
|
MINIPORT_SET_PACKET_FLAG(Packet, fPACKET_HAS_BEEN_LOOPED_BACK);
|
|
|
|
return(SelfDirected);
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If it is not a loopback packet then get out of here.
|
|
//
|
|
if (!Loopback)
|
|
{
|
|
ASSERT(!SelfDirected);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Get the buffer length.
|
|
//
|
|
NdisQueryPacket(Packet, NULL, NULL, NULL, &Length);
|
|
Offset = 0;
|
|
|
|
//
|
|
// Allocate a buffer for the packet.
|
|
//
|
|
pNewPacket = (PNDIS_PACKET)ALLOC_FROM_POOL(Length +
|
|
sizeof(NDIS_PACKET) +
|
|
sizeof(NDIS_PACKET_OOB_DATA) +
|
|
sizeof(NDIS_PACKET_PRIVATE_EXTENSION) +
|
|
PROTOCOL_RESERVED_SIZE_IN_PACKET,
|
|
NDIS_TAG_LOOP_PKT);
|
|
if (pNewPacket != NULL)
|
|
{
|
|
//
|
|
// Get a pointer to the destination buffer.
|
|
//
|
|
Buffer = (PUCHAR)pNewPacket +
|
|
sizeof(NDIS_PACKET) +
|
|
sizeof(NDIS_PACKET_OOB_DATA) +
|
|
sizeof(NDIS_PACKET_PRIVATE_EXTENSION) +
|
|
PROTOCOL_RESERVED_SIZE_IN_PACKET;
|
|
|
|
ZeroMemory(pNewPacket,
|
|
sizeof(NDIS_PACKET) +
|
|
sizeof(NDIS_PACKET_OOB_DATA) +
|
|
sizeof(NDIS_PACKET_PRIVATE_EXTENSION) +
|
|
PROTOCOL_RESERVED_SIZE_IN_PACKET);
|
|
|
|
//
|
|
// Allocate an MDL for the packet.
|
|
//
|
|
NdisAllocateBuffer(&Status,
|
|
&pNdisBuffer,
|
|
NULL,
|
|
Buffer,
|
|
Length);
|
|
if (NDIS_STATUS_SUCCESS == Status)
|
|
{
|
|
//
|
|
// NdisChainBufferAtFront()
|
|
//
|
|
pNewPacket->Private.Head = pNdisBuffer;
|
|
pNewPacket->Private.Tail = pNdisBuffer;
|
|
|
|
pNewPacket->Private.NdisPacketOobOffset = (USHORT)sizeof(NDIS_PACKET) + PROTOCOL_RESERVED_SIZE_IN_PACKET;
|
|
|
|
ndisMCopyFromPacketToBuffer(Packet, // Packet to copy from.
|
|
Offset, // Offset from beginning of packet.
|
|
Length, // Number of bytes to copy.
|
|
Buffer, // The destination buffer.
|
|
&HdrLength);// The number of bytes copied.
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Clean up the memory allocated for the packet.
|
|
//
|
|
FREE_POOL(pNewPacket);
|
|
pNewPacket = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Do we have a packet built ?
|
|
//
|
|
if (NULL != pNewPacket)
|
|
{
|
|
//
|
|
// Mark the packet as having been looped back.
|
|
//
|
|
MINIPORT_SET_PACKET_FLAG(Packet, fPACKET_HAS_BEEN_LOOPED_BACK);
|
|
|
|
NDISM_LOG_PACKET(Miniport, Packet, pNewPacket, 'pool');
|
|
|
|
//
|
|
// Place the packet on the loopback queue.
|
|
//
|
|
if (NULL == Miniport->LoopbackHead)
|
|
{
|
|
Miniport->LoopbackHead = pNewPacket;
|
|
|
|
//
|
|
// If this is the first one on the loopback queue then we need
|
|
// to make sure that we pick it up later.
|
|
//
|
|
NDISM_DEFER_PROCESS_DEFERRED(Miniport);
|
|
}
|
|
else
|
|
{
|
|
PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LoopbackTail)->Next = pNewPacket;
|
|
}
|
|
|
|
Miniport->LoopbackTail = pNewPacket;
|
|
|
|
//
|
|
// Packet needs to have a workitem queued.
|
|
//
|
|
NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSendLoopback, NULL, NULL);
|
|
}
|
|
|
|
return(SelfDirected);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
FASTCALL
|
|
ndisMIndicateLoopback(
|
|
IN PNDIS_MINIPORT_BLOCK Miniport
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Checks if a packet needs to be loopbacked and does so if necessary.
|
|
|
|
NOTE: Must be called at DPC_LEVEL with lock HELD!
|
|
|
|
Arguments:
|
|
|
|
Miniport - Miniport to send to.
|
|
|
|
Packet - Packet to loopback.
|
|
|
|
Return Value:
|
|
|
|
FALSE if the packet should be sent on the net, TRUE if it is
|
|
a self-directed packet.
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT Length;
|
|
PUCHAR BufferAddress;
|
|
PNDIS_PACKET Packet, QueueHead;
|
|
PNDIS_PACKET_OOB_DATA pOob;
|
|
NDIS_STATUS Status;
|
|
BOOLEAN fReturnStatus = FALSE;
|
|
|
|
// We should not be here if the driver handles loopback
|
|
ASSERT(Miniport->MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK);
|
|
ASSERT(MINIPORT_AT_DPC_LEVEL);
|
|
|
|
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
|
|
{
|
|
NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
|
|
}
|
|
|
|
//
|
|
// Get a local copy of the loopback queue.
|
|
//
|
|
QueueHead = Miniport->LoopbackHead;
|
|
Miniport->LoopbackHead = NULL;
|
|
Miniport->LoopbackTail = NULL;
|
|
|
|
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
|
|
{
|
|
NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
|
|
}
|
|
|
|
//
|
|
// Loop through any loopback packets that are queue'd.
|
|
//
|
|
|
|
while (QueueHead != NULL)
|
|
{
|
|
//
|
|
// Grab the first loopback packet to indicate up.
|
|
//
|
|
Packet = QueueHead;
|
|
pOob = NDIS_OOB_DATA_FROM_PACKET(Packet);
|
|
pOob->Status = NDIS_STATUS_RESOURCES;
|
|
QueueHead = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next;
|
|
|
|
NDISM_LOG_PACKET(Miniport, Packet, NULL, 'i');
|
|
|
|
//
|
|
// Setup the packet references and packet array.
|
|
//
|
|
Miniport->LoopbackPacket = Packet;
|
|
BufferAddress = (PUCHAR)Packet +
|
|
sizeof(NDIS_PACKET) +
|
|
sizeof(NDIS_PACKET_OOB_DATA) +
|
|
sizeof(NDIS_PACKET_PRIVATE_EXTENSION) +
|
|
PROTOCOL_RESERVED_SIZE_IN_PACKET;
|
|
|
|
//
|
|
// For ethernet/token-ring/fddi/encapsulated arc-net, we want to
|
|
// indicate the packet using the receivepacket way.
|
|
//
|
|
switch (Miniport->MediaType)
|
|
{
|
|
case NdisMedium802_3:
|
|
pOob->HeaderSize = 14;
|
|
EthFilterDprIndicateReceivePacket(Miniport, &Packet, 1);
|
|
break;
|
|
|
|
case NdisMedium802_5:
|
|
pOob->HeaderSize = 14;
|
|
if (BufferAddress[8] & 0x80)
|
|
{
|
|
pOob->HeaderSize += (BufferAddress[14] & 0x1F);
|
|
}
|
|
TrFilterDprIndicateReceivePacket(Miniport, &Packet, 1);
|
|
break;
|
|
|
|
case NdisMediumFddi:
|
|
pOob->HeaderSize = (*BufferAddress & 0x40) ?
|
|
2 * FDDI_LENGTH_OF_LONG_ADDRESS + 1:
|
|
2 * FDDI_LENGTH_OF_SHORT_ADDRESS + 1;
|
|
|
|
FddiFilterDprIndicateReceivePacket(Miniport, &Packet, 1);
|
|
break;
|
|
}
|
|
|
|
ASSERT(NDIS_GET_PACKET_STATUS(Packet) != NDIS_STATUS_PENDING);
|
|
NdisFreeBuffer(Packet->Private.Head);
|
|
FREE_POOL(Packet);
|
|
}
|
|
|
|
Miniport->LoopbackPacket = NULL;
|
|
|
|
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
|
|
{
|
|
NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
|
|
}
|
|
|
|
//
|
|
// If there are more loopback packets on the loopback
|
|
// queue then we need to let process deferred know not to
|
|
// dequeue the loopback workitem.
|
|
//
|
|
if (Miniport->LoopbackHead != NULL)
|
|
{
|
|
fReturnStatus = TRUE;
|
|
}
|
|
|
|
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
|
|
{
|
|
NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
|
|
}
|
|
|
|
return(fReturnStatus);
|
|
}
|
|
|
|
BOOLEAN
|
|
FASTCALL
|
|
ndisMStartSendPacketsFullDuplex(
|
|
PNDIS_MINIPORT_BLOCK Miniport
|
|
)
|
|
{
|
|
BOOLEAN fReturn = FALSE;
|
|
#ifdef NDIS_NT
|
|
PNDIS_PACKET Packet;
|
|
PNDIS_PACKET PrevPacket;
|
|
NDIS_STATUS Status;
|
|
PNDIS_PACKET_RESERVED Reserved;
|
|
PNDIS_M_OPEN_BLOCK Open;
|
|
UINT Flags;
|
|
PPNDIS_PACKET pPktArray;
|
|
|
|
//
|
|
// Acquire the send lock.
|
|
//
|
|
ASSERT(MINIPORT_AT_DPC_LEVEL);
|
|
NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
|
|
|
|
NDISM_LOG_PACKET(Miniport, NULL, NULL, 'rfed');
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("==>ndisMStartSendPacketsFullDuplex\n"));
|
|
|
|
MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED);
|
|
|
|
//
|
|
// Loop and process sends.
|
|
//
|
|
while ((Miniport->SendResourcesAvailable != 0) &&
|
|
(Miniport->FirstPendingPacket != NULL))
|
|
{
|
|
UINT Count;
|
|
UINT ResourcesCount;
|
|
UINT NumberOfPackets;
|
|
|
|
//
|
|
// Initialize the packet array.
|
|
//
|
|
pPktArray = Miniport->PacketArray;
|
|
|
|
//
|
|
// Place as many packets as we can in the packet array to send
|
|
// to the miniport.
|
|
//
|
|
for (NumberOfPackets = 0;
|
|
(NumberOfPackets < Miniport->MaximumSendPackets) &&
|
|
(Miniport->FirstPendingPacket != NULL); )
|
|
{
|
|
//
|
|
// Grab the packet off of the pending queue.
|
|
//
|
|
Packet = Miniport->FirstPendingPacket;
|
|
Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
|
|
|
|
//
|
|
// Remove from pending queue
|
|
//
|
|
Miniport->FirstPendingPacket = Reserved->Next;
|
|
|
|
//
|
|
// Put on finish queue
|
|
//
|
|
PrevPacket = Miniport->LastMiniportPacket;
|
|
Miniport->LastMiniportPacket = Packet;
|
|
|
|
//
|
|
// Indicate the packet loopback if necessary.
|
|
//
|
|
if (((Miniport->MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK) ||
|
|
MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_LOOPBACK_DIRECTED)) &&
|
|
!MINIPORT_TEST_PACKET_FLAG(Packet, fPACKET_HAS_BEEN_LOOPED_BACK) &&
|
|
ndisMIsLoopbackPacket(Miniport, Packet))
|
|
{
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("Packet 0x%x is self-directed.\n", Packet));
|
|
|
|
//
|
|
// Get a pointer to the open block.
|
|
// DO NOT USE "Reserved->Open" TO CALL INTO THE MACRO!!!!!
|
|
//
|
|
Open = Reserved->Open;
|
|
|
|
//
|
|
// Complete the packet back to the binding.
|
|
//
|
|
NDISM_COMPLETE_SEND_FULL_DUPLEX(
|
|
Miniport,
|
|
Open,
|
|
Packet,
|
|
PrevPacket,
|
|
NDIS_STATUS_SUCCESS);
|
|
|
|
//
|
|
// No, we don't want to increment the counter for the
|
|
// miniport's packet array.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
NDISM_LOG_PACKET(Miniport, Packet, NULL, 'inim');
|
|
|
|
//
|
|
// We have to re-initialize this.
|
|
//
|
|
*pPktArray = Packet;
|
|
NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_SUCCESS);
|
|
|
|
//
|
|
// Increment the counter for the packet array index.
|
|
//
|
|
NumberOfPackets++;
|
|
pPktArray++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Are there any packets to send?
|
|
//
|
|
if (NumberOfPackets != 0)
|
|
{
|
|
//
|
|
// Get a temp pointer to our packet array.
|
|
//
|
|
pPktArray = Miniport->PacketArray;
|
|
Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Open;
|
|
|
|
//
|
|
// Pass the packet array down to the miniport.
|
|
//
|
|
(Open->SendPacketsHandler)(
|
|
Miniport->MiniportAdapterContext,
|
|
Miniport->PacketArray,
|
|
NumberOfPackets);
|
|
|
|
//
|
|
// First check to see if the LastMiniportPacket is NULL.
|
|
// If it is then the miniport called NdisMSendComplete()
|
|
// in our send context and we don't need to do anything more.
|
|
//
|
|
if (NULL == Miniport->LastMiniportPacket)
|
|
{
|
|
//
|
|
// We may still have packets pending to be sent down....
|
|
//
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Process the packet completion.
|
|
//
|
|
for (Count = 0; Count < NumberOfPackets; Count++, pPktArray++)
|
|
{
|
|
BOOLEAN fFoundPacket = FALSE;
|
|
|
|
//
|
|
// Try and find the packet on our miniport's packet queue.
|
|
//
|
|
Packet = Miniport->FirstPacket;
|
|
PrevPacket = NULL;
|
|
|
|
ASSERT(Packet != NULL);
|
|
|
|
//
|
|
// We are only going to travers the packet queue from the
|
|
// FirstPacket to the LastMiniportPacket.
|
|
// Why you ask? Well we need to make sure that the miniport
|
|
// didn't complete the packet we are now trying to complete
|
|
// with a call to NdisMSendComplete().
|
|
//
|
|
while (Packet != PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastMiniportPacket)->Next)
|
|
{
|
|
if (Packet == *pPktArray)
|
|
{
|
|
fFoundPacket = TRUE;
|
|
break;
|
|
}
|
|
|
|
PrevPacket = Packet;
|
|
Packet = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next;
|
|
}
|
|
|
|
//
|
|
// If we didn't find the packet on our queue then we need to
|
|
// go on to the next one since it MUST have been completed
|
|
// via NdisMSendComplete....
|
|
//
|
|
if (!fFoundPacket)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
Status = NDIS_GET_PACKET_STATUS(*pPktArray);
|
|
|
|
//
|
|
// Process the packet based on it's return status.
|
|
//
|
|
if (NDIS_STATUS_PENDING == Status)
|
|
{
|
|
NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'dnep');
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("Complete is pending\n"));
|
|
}
|
|
else if (NDIS_STATUS_RESOURCES != Status)
|
|
{
|
|
#if DBG
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'liaf');
|
|
}
|
|
else
|
|
{
|
|
NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'ccus');
|
|
}
|
|
#endif
|
|
|
|
ADD_RESOURCE(Miniport, 'F');
|
|
|
|
//
|
|
// Remove from the finish queue.
|
|
//
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("Completed packet 0x%x with status 0x%x\n",
|
|
*pPktArray,
|
|
Status));
|
|
|
|
//
|
|
// Fix up the packet queues.
|
|
//
|
|
if (Miniport->FirstPacket == *pPktArray)
|
|
{
|
|
Miniport->FirstPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Next;
|
|
|
|
if (Miniport->LastMiniportPacket == *pPktArray)
|
|
{
|
|
Miniport->LastMiniportPacket = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If we just completed the last packet then
|
|
// we need to update our last packet pointer.
|
|
//
|
|
PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Next;
|
|
if (*pPktArray == Miniport->LastPacket)
|
|
{
|
|
Miniport->LastPacket = PrevPacket;
|
|
}
|
|
|
|
//
|
|
// If we just complete the last miniport packet then
|
|
// the last miniport packet is the previous packet.
|
|
//
|
|
if (Miniport->LastMiniportPacket == *pPktArray)
|
|
{
|
|
Miniport->LastMiniportPacket = PrevPacket;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We need to save a pointer to the open so that we
|
|
// can dereference it after the completion.
|
|
//
|
|
Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Open;
|
|
|
|
NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
|
|
|
|
(Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)(
|
|
Open->ProtocolBindingContext,
|
|
*pPktArray,
|
|
Status);
|
|
|
|
NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Once we hit a return code of NDIS_STATUS_RESOURCES
|
|
// for a packet then we must break out and re-queue.
|
|
//
|
|
CLEAR_RESOURCE(Miniport, 'S');
|
|
MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// if there are any packets that returned NDIS_STATUS_RESOURCES
|
|
// then re-queue them.
|
|
//
|
|
if (Count != NumberOfPackets)
|
|
{
|
|
PNDIS_PACKET FinalPrevPacket = PrevPacket;
|
|
|
|
for (ResourcesCount = NumberOfPackets - 1, pPktArray = &Miniport->PacketArray[ResourcesCount];
|
|
ResourcesCount > Count;
|
|
ResourcesCount--, pPktArray--)
|
|
{
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("Packet 0x%x returned resources\n", *pPktArray));
|
|
|
|
NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'oser');
|
|
|
|
//
|
|
// Float the pointers.
|
|
//
|
|
Miniport->LastMiniportPacket = *(pPktArray - 1);
|
|
Miniport->FirstPendingPacket = *pPktArray;
|
|
}
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("Packet 0x%x returned resources\n", *pPktArray));
|
|
|
|
NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'oser');
|
|
|
|
//
|
|
// If this is the last packet on the miniport queue
|
|
// then NULL the last miniport packet out so we know there
|
|
// are no more.
|
|
//
|
|
if (Miniport->FirstPacket == *pPktArray)
|
|
{
|
|
Miniport->LastMiniportPacket = NULL;
|
|
Miniport->FirstPendingPacket = *pPktArray;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// There are other packets that are pending on
|
|
// the miniport queue.
|
|
//
|
|
Miniport->LastMiniportPacket = PrevPacket;
|
|
Miniport->FirstPendingPacket = *pPktArray;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("<==ndisMStartSendPacketsFullDuplex\n"));
|
|
|
|
//
|
|
// If there are no more resources available but
|
|
// there are still packets to send then we need to
|
|
// keep the workitem queue'd.
|
|
//
|
|
if ((0 == Miniport->SendResourcesAvailable) &&
|
|
(Miniport->FirstPendingPacket != NULL))
|
|
{
|
|
fReturn = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fReturn = FALSE;
|
|
}
|
|
|
|
NDISM_LOG_PACKET(Miniport, NULL, NULL, 'RFED');
|
|
|
|
NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
|
|
#endif
|
|
return(fReturn);
|
|
}
|
|
|
|
BOOLEAN
|
|
FASTCALL
|
|
ndisMStartSendsFullDuplex(
|
|
PNDIS_MINIPORT_BLOCK Miniport
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will process any pending sends for full-duplex miniports.
|
|
|
|
|
|
!!!!!!!NOTE!!!!!!!!
|
|
This routine MUST be called with the Miniport Lock NOT held!!!!
|
|
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN fReturn = FALSE;
|
|
#ifdef NDIS_NT
|
|
PNDIS_PACKET Packet;
|
|
PNDIS_PACKET PrevPacket;
|
|
NDIS_STATUS Status;
|
|
PNDIS_PACKET_RESERVED Reserved;
|
|
PNDIS_M_OPEN_BLOCK Open;
|
|
UINT Flags;
|
|
KIRQL OldIrql;
|
|
|
|
//
|
|
// Acquire the send lock.
|
|
//
|
|
NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
|
|
|
|
NDISM_LOG_PACKET(Miniport, NULL, NULL, 'rfed');
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("==>ndisMStartSendsFullDuplex\n"));
|
|
|
|
MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED);
|
|
|
|
//
|
|
// Loop and process sends.
|
|
//
|
|
while ((Miniport->SendResourcesAvailable != 0) &&
|
|
(Miniport->FirstPendingPacket != NULL))
|
|
{
|
|
//
|
|
// Grab the packet off of the pending queue.
|
|
//
|
|
Packet = Miniport->FirstPendingPacket;
|
|
Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
|
|
Open = Reserved->Open;
|
|
|
|
//
|
|
// Remove from pending queue
|
|
//
|
|
Miniport->FirstPendingPacket = Reserved->Next;
|
|
|
|
//
|
|
// Put on finish queue
|
|
//
|
|
PrevPacket = Miniport->LastMiniportPacket;
|
|
Miniport->LastMiniportPacket = Packet;
|
|
|
|
//
|
|
// Send the packet
|
|
//
|
|
NDISM_SEND_PACKET(Miniport, Open, Packet, &Status);
|
|
|
|
//
|
|
// Process the completion status of the packet.
|
|
//
|
|
if (NDIS_STATUS_PENDING == Status)
|
|
{
|
|
NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnep');
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("Complete is pending\n"));
|
|
}
|
|
else if (Status != NDIS_STATUS_RESOURCES)
|
|
{
|
|
NDISM_COMPLETE_SEND_FULL_DUPLEX(
|
|
Miniport,
|
|
Open,
|
|
Packet,
|
|
PrevPacket,
|
|
Status);
|
|
}
|
|
else
|
|
{
|
|
NDISM_COMPLETE_SEND_RESOURCES(Miniport, Packet, PrevPacket);
|
|
}
|
|
}
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("<==ndisMStartSendsFullDuplex\n"));
|
|
|
|
//
|
|
// If there are no more resources available but
|
|
// there are still packets to send then we need to
|
|
// keep the workitem queue'd.
|
|
//
|
|
if ((0 == Miniport->SendResourcesAvailable) &&
|
|
(Miniport->FirstPendingPacket != NULL))
|
|
{
|
|
fReturn = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fReturn = FALSE;
|
|
}
|
|
|
|
NDISM_LOG_PACKET(Miniport, NULL, NULL, 'RFED');
|
|
|
|
NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
|
|
#endif
|
|
return(fReturn);
|
|
}
|
|
|
|
BOOLEAN
|
|
FASTCALL
|
|
ndisMStartSendPackets(
|
|
PNDIS_MINIPORT_BLOCK Miniport
|
|
)
|
|
{
|
|
PNDIS_PACKET Packet;
|
|
PNDIS_PACKET PrevPacket;
|
|
NDIS_STATUS Status;
|
|
PNDIS_PACKET_RESERVED Reserved;
|
|
PNDIS_M_OPEN_BLOCK Open;
|
|
UINT Flags;
|
|
BOOLEAN fReturn;
|
|
PPNDIS_PACKET pPktArray;
|
|
|
|
ASSERT(MINIPORT_AT_DPC_LEVEL);
|
|
ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("==>ndisMStartSendPackets\n"));
|
|
NDISM_LOG_PACKET(Miniport, NULL, NULL, 'rfed');
|
|
|
|
MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED);
|
|
|
|
//
|
|
// Loop and process sends.
|
|
//
|
|
while ((Miniport->SendResourcesAvailable != 0) &&
|
|
(Miniport->FirstPendingPacket != NULL))
|
|
{
|
|
UINT Count;
|
|
UINT ResourcesCount;
|
|
UINT NumberOfPackets;
|
|
PNDIS_PACKET FirstPrevPacket = NULL;
|
|
|
|
//
|
|
// Initialize the packet array.
|
|
//
|
|
pPktArray = Miniport->PacketArray;
|
|
|
|
//
|
|
// Place as many packets as we can in the packet array to send
|
|
// to the miniport.
|
|
//
|
|
for (NumberOfPackets = 0;
|
|
(NumberOfPackets < Miniport->MaximumSendPackets) &&
|
|
(Miniport->FirstPendingPacket != NULL); )
|
|
{
|
|
//
|
|
// Grab the packet off of the pending queue.
|
|
//
|
|
Packet = Miniport->FirstPendingPacket;
|
|
Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
|
|
|
|
//
|
|
// Remove from pending queue
|
|
//
|
|
Miniport->FirstPendingPacket = Reserved->Next;
|
|
|
|
//
|
|
// Put on finish queue
|
|
//
|
|
PrevPacket = Miniport->LastMiniportPacket;
|
|
Miniport->LastMiniportPacket = Packet;
|
|
|
|
//
|
|
// Indicate the packet loopback if necessary.
|
|
//
|
|
if (((Miniport->MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK) ||
|
|
MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_LOOPBACK_DIRECTED)) &&
|
|
!MINIPORT_TEST_PACKET_FLAG(Packet, fPACKET_HAS_BEEN_LOOPED_BACK) &&
|
|
ndisMIsLoopbackPacket(Miniport, Packet))
|
|
{
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("Packet 0x%x is self-directed.\n", Packet));
|
|
|
|
//
|
|
// Get a pointer to our open block.
|
|
// DO NOT USE "Reserved->Open" TO CALL INTO THE MACRO SINCE IT
|
|
// WILL NOT BE VALID FOR THE LIFE OF THE MACRO!!!!!
|
|
//
|
|
Open = Reserved->Open;
|
|
|
|
//
|
|
// Complete the packet back to the binding.
|
|
//
|
|
NDISM_COMPLETE_SEND(
|
|
Miniport,
|
|
Open,
|
|
Packet,
|
|
PrevPacket,
|
|
NDIS_STATUS_SUCCESS);
|
|
|
|
//
|
|
// No, we don't want to increment the counter for the
|
|
// miniport's packet array.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
NDISM_LOG_PACKET(Miniport, Packet, NULL, 'inim');
|
|
|
|
//
|
|
// We have to re-initialize this.
|
|
//
|
|
*pPktArray = Packet;
|
|
NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_SUCCESS);
|
|
|
|
//
|
|
// Increment the counter for the packet array index.
|
|
//
|
|
NumberOfPackets++;
|
|
pPktArray++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Are there any packets to send?
|
|
//
|
|
if (NumberOfPackets != 0)
|
|
{
|
|
//
|
|
// Get a temp pointer to our packet array.
|
|
//
|
|
pPktArray = Miniport->PacketArray;
|
|
Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Open;
|
|
|
|
//
|
|
// Pass the packet array down to the miniport.
|
|
//
|
|
(Open->SendPacketsHandler)(
|
|
Miniport->MiniportAdapterContext,
|
|
Miniport->PacketArray,
|
|
NumberOfPackets);
|
|
|
|
//
|
|
// First check to see if the LastMiniportPacket is NULL.
|
|
// If it is then the miniport called NdisMSendComplete()
|
|
// in our send context and we don't need to do anything more.
|
|
//
|
|
if (NULL == Miniport->LastMiniportPacket)
|
|
{
|
|
//
|
|
// We may still have packets pending to be sent down....
|
|
//
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Process the packet completion.
|
|
//
|
|
for (Count = 0; Count < NumberOfPackets; Count++, pPktArray++)
|
|
{
|
|
BOOLEAN fFoundPacket = FALSE;
|
|
|
|
//
|
|
// Try and find the packet on our miniport's packet queue.
|
|
//
|
|
Packet = Miniport->FirstPacket;
|
|
PrevPacket = NULL;
|
|
|
|
ASSERT(Packet != NULL);
|
|
|
|
//
|
|
// We are only going to travers the packet queue from the
|
|
// FirstPacket to the LastMiniportPacket.
|
|
// Why you ask? Well we need to make sure that the miniport
|
|
// didn't complete the packet we are now trying to complete
|
|
// with a call to NdisMSendComplete().
|
|
//
|
|
while (Packet != PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastMiniportPacket)->Next)
|
|
{
|
|
if (Packet == *pPktArray)
|
|
{
|
|
fFoundPacket = TRUE;
|
|
break;
|
|
}
|
|
|
|
PrevPacket = Packet;
|
|
Packet = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next;
|
|
}
|
|
|
|
//
|
|
// If we didn't find the packet on our queue then we need to
|
|
// go on to the next one since it MUST have been completed
|
|
// via NdisMSendComplete....
|
|
//
|
|
if (!fFoundPacket)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
Status = NDIS_GET_PACKET_STATUS(*pPktArray);
|
|
|
|
//
|
|
// Process the packet based on it's return status.
|
|
//
|
|
if (NDIS_STATUS_PENDING == Status)
|
|
{
|
|
NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'dnep');
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("Complete is pending\n"));
|
|
}
|
|
else if (Status != NDIS_STATUS_RESOURCES)
|
|
{
|
|
#if DBG
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'liaf');
|
|
}
|
|
else
|
|
{
|
|
NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'ccus');
|
|
}
|
|
#endif
|
|
|
|
ADD_RESOURCE(Miniport, 'F');
|
|
|
|
//
|
|
// Remove from the finish queue.
|
|
//
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("Completed packet 0x%x with status 0x%x\n",
|
|
*pPktArray,
|
|
Status));
|
|
|
|
//
|
|
// Fix up the packet queues.
|
|
//
|
|
if (Miniport->FirstPacket == *pPktArray)
|
|
{
|
|
Miniport->FirstPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Next;
|
|
|
|
if (Miniport->LastMiniportPacket == *pPktArray)
|
|
{
|
|
Miniport->LastMiniportPacket = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If we just completed the last packet then
|
|
// we need to update our last packet pointer.
|
|
//
|
|
PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Next;
|
|
if (*pPktArray == Miniport->LastPacket)
|
|
{
|
|
Miniport->LastPacket = PrevPacket;
|
|
}
|
|
|
|
//
|
|
// If we just complete the last miniport packet then
|
|
// the last miniport packet is the previous packet.
|
|
//
|
|
if (Miniport->LastMiniportPacket == *pPktArray)
|
|
{
|
|
Miniport->LastMiniportPacket = PrevPacket;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We need to save a pointer to the open so that we
|
|
// can dereference it after the completion.
|
|
//
|
|
Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Open;
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
(Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)(
|
|
Open->ProtocolBindingContext,
|
|
*pPktArray,
|
|
Status);
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
|
|
("- Open 0x%x Reference 0x%x\n", Open, Open->References));
|
|
|
|
Open->References--;
|
|
|
|
DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
|
|
("==0 Open 0x%x Reference 0x%x\n",
|
|
PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Open,
|
|
PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray)->Open->References));
|
|
|
|
if (Open->References == 0)
|
|
{
|
|
ndisMFinishClose(Miniport, Open);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Once we hit a return code of NDIS_STATUS_RESOURCES
|
|
// for a packet then we must break out and re-queue.
|
|
//
|
|
CLEAR_RESOURCE(Miniport, 'S');
|
|
MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// if there are any packets that returned NDIS_STATUS_RESOURCES
|
|
// then re-queue them.
|
|
//
|
|
if (Count != NumberOfPackets)
|
|
{
|
|
PNDIS_PACKET FinalPrevPacket = PrevPacket;
|
|
|
|
for (ResourcesCount = NumberOfPackets - 1, pPktArray = &Miniport->PacketArray[ResourcesCount];
|
|
ResourcesCount > Count;
|
|
ResourcesCount--, pPktArray--)
|
|
{
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("Packet 0x%x returned resources\n", *pPktArray));
|
|
|
|
NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'oser');
|
|
|
|
//
|
|
// Float the pointers.
|
|
//
|
|
Miniport->LastMiniportPacket = *(pPktArray - 1);
|
|
Miniport->FirstPendingPacket = *pPktArray;
|
|
}
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("Packet 0x%x returned resources\n", *pPktArray));
|
|
|
|
NDISM_LOG_PACKET(Miniport, *pPktArray, NULL, 'oser');
|
|
|
|
//
|
|
// If this is the last packet on the miniport queue
|
|
// then NULL the last miniport packet out so we know there
|
|
// are no more.
|
|
//
|
|
if (Miniport->FirstPacket == *pPktArray)
|
|
{
|
|
Miniport->LastMiniportPacket = NULL;
|
|
Miniport->FirstPendingPacket = *pPktArray;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// There are other packets that are pending on
|
|
// the miniport queue.
|
|
//
|
|
Miniport->LastMiniportPacket = PrevPacket;
|
|
Miniport->FirstPendingPacket = *pPktArray;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
NDISM_LOG_PACKET(Miniport, NULL, NULL, 'RFED');
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("<==ndisMStartSendPackets\n"));
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
BOOLEAN
|
|
FASTCALL
|
|
ndisMStartSends(
|
|
PNDIS_MINIPORT_BLOCK Miniport
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Submits as many sends as possible to the mini-port.
|
|
|
|
Arguments:
|
|
|
|
Miniport - Miniport to send to.
|
|
|
|
Return Value:
|
|
|
|
If there are more packets to send but no resources to do it with
|
|
the this is TRUE to keep a workitem queue'd.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNDIS_PACKET Packet;
|
|
PNDIS_PACKET PrevPacket;
|
|
NDIS_STATUS Status;
|
|
PNDIS_PACKET_RESERVED Reserved;
|
|
PNDIS_M_OPEN_BLOCK Open;
|
|
UINT Flags;
|
|
BOOLEAN fReturn;
|
|
|
|
ASSERT(MINIPORT_AT_DPC_LEVEL);
|
|
ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("==>ndisMStartSends\n"));
|
|
|
|
MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED);
|
|
NDISM_LOG_PACKET(Miniport, NULL, NULL, 'rfed');
|
|
|
|
//
|
|
// Loop and process sends.
|
|
//
|
|
while ((Miniport->SendResourcesAvailable != 0) &&
|
|
(Miniport->FirstPendingPacket != NULL))
|
|
{
|
|
//
|
|
// Grab the packet off of the pending queue.
|
|
//
|
|
Packet = Miniport->FirstPendingPacket;
|
|
Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
|
|
Open = Reserved->Open;
|
|
|
|
NDISM_LOG_PACKET(Miniport, Packet, NULL, 's');
|
|
|
|
//
|
|
// Is this arcnet using ethernet encapsulation?
|
|
//
|
|
if (Miniport->MediaType == NdisMediumArcnet878_2)
|
|
{
|
|
//
|
|
// Build the header for arcnet.
|
|
//
|
|
Status = ndisMBuildArcnetHeader(Miniport, Open, Packet);
|
|
if (NDIS_STATUS_PENDING == Status)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Remove from pending queue
|
|
//
|
|
Miniport->FirstPendingPacket = Reserved->Next;
|
|
|
|
//
|
|
// Put on finish queue
|
|
//
|
|
PrevPacket = Miniport->LastMiniportPacket;
|
|
Miniport->LastMiniportPacket = Packet;
|
|
|
|
//
|
|
// Send the packet.
|
|
//
|
|
NDISM_SEND_PACKET(Miniport, Open, Packet, &Status);
|
|
|
|
//
|
|
// Process the packet pending completion status.
|
|
//
|
|
if (NDIS_STATUS_PENDING == Status)
|
|
{
|
|
NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnep');
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("Complete is pending\n"));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Clean-up arcnet's extra buffers.
|
|
//
|
|
if (Miniport->MediaType == NdisMediumArcnet878_2)
|
|
{
|
|
ndisMFreeArcnetHeader(Miniport, Packet);
|
|
}
|
|
|
|
//
|
|
// Handle the completion and resources cases.
|
|
//
|
|
if (Status != NDIS_STATUS_RESOURCES)
|
|
{
|
|
NDISM_COMPLETE_SEND(
|
|
Miniport,
|
|
Open,
|
|
Packet,
|
|
PrevPacket,
|
|
Status);
|
|
}
|
|
else
|
|
{
|
|
NDISM_COMPLETE_SEND_RESOURCES(Miniport, Packet, PrevPacket);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("<==ndisMStartSends\n"));
|
|
|
|
//
|
|
// If there are no more resources available but
|
|
// there are still packets to send then we need to
|
|
// keep the workitem queue'd.
|
|
//
|
|
if ((0 == Miniport->SendResourcesAvailable) &&
|
|
(Miniport->FirstPendingPacket != NULL))
|
|
{
|
|
fReturn = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fReturn = FALSE;
|
|
}
|
|
|
|
NDISM_LOG_PACKET(Miniport, NULL, NULL, 'RFED');
|
|
|
|
return(fReturn);
|
|
}
|
|
|
|
NDIS_STATUS FASTCALL
|
|
ndisMSyncSend(
|
|
IN PNDIS_MINIPORT_BLOCK Miniport,
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Submits an immediate send to a miniport. The miniport has
|
|
the send on the pending queue, and it is the only element on the send
|
|
queue. This routine is also called with the lock held.
|
|
|
|
Arguments:
|
|
|
|
Miniport - Miniport to send to.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNDIS_PACKET PrevPacket;
|
|
NDIS_STATUS Status;
|
|
PNDIS_PACKET_RESERVED Reserved;
|
|
PNDIS_M_OPEN_BLOCK Open;
|
|
UINT Flags;
|
|
|
|
ASSERT(MINIPORT_AT_DPC_LEVEL);
|
|
ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("Enter Sync send.\n"));
|
|
|
|
NDISM_LOG_PACKET(Miniport, Packet, NULL, 'cnys');
|
|
|
|
//
|
|
// Get the Open block that the send is for from the packet.
|
|
//
|
|
Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
|
|
Open = Reserved->Open;
|
|
|
|
//
|
|
// Remove from Queue
|
|
//
|
|
Miniport->FirstPendingPacket = Reserved->Next;
|
|
|
|
//
|
|
// Put on finish queue
|
|
//
|
|
PrevPacket = Miniport->LastMiniportPacket;
|
|
Miniport->LastMiniportPacket = Packet;
|
|
MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED);
|
|
|
|
//
|
|
// Send the packet.
|
|
//
|
|
NDISM_SEND_PACKET(Miniport, Open, Packet, &Status);
|
|
|
|
//
|
|
// Process the status of the send.
|
|
//
|
|
if (NDIS_STATUS_PENDING == Status)
|
|
{
|
|
NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnep');
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("Complete sync send is pending\n"));
|
|
|
|
return(NDIS_STATUS_PENDING);
|
|
}
|
|
|
|
//
|
|
// If send complete was called from the miniport's send handler
|
|
// then our local PrevPacket pointer may no longer be valid....
|
|
//
|
|
if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED))
|
|
{
|
|
MINIPORT_CLEAR_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED);
|
|
MiniportFindPacket(Miniport, Packet, &PrevPacket);
|
|
}
|
|
|
|
Miniport->LastMiniportPacket = PrevPacket;
|
|
|
|
if (Status != NDIS_STATUS_RESOURCES)
|
|
{
|
|
#if DBG
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
NDISM_LOG_PACKET(Miniport, Packet, NULL, 'liaf');
|
|
}
|
|
else
|
|
{
|
|
NDISM_LOG_PACKET(Miniport, Packet, NULL, 'ccus');
|
|
}
|
|
#endif
|
|
|
|
ADD_RESOURCE(Miniport, 'F');
|
|
|
|
//
|
|
// Remove from finish queue
|
|
//
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("Completed 0x%x\n", Status));
|
|
|
|
if (PrevPacket == NULL)
|
|
{
|
|
//
|
|
// Set up the next packet to send.
|
|
//
|
|
Miniport->FirstPacket = Reserved->Next;
|
|
}
|
|
else
|
|
{
|
|
PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next = Reserved->Next;
|
|
|
|
if (Packet == Miniport->LastPacket)
|
|
{
|
|
Miniport->LastPacket = PrevPacket;
|
|
}
|
|
}
|
|
|
|
DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
|
|
("- Open 0x%x Reference 0x%x\n", Open, Open->References));
|
|
|
|
Open->References--;
|
|
|
|
DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
|
|
("==0 Open 0x%x Reference 0x%x\n", Open, Open->References));
|
|
|
|
if (Open->References == 0)
|
|
ndisMFinishClose(Miniport, Open);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Status == NDIS_STATUS_RESOURCES!!!!
|
|
//
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("Deferring send\n"));
|
|
|
|
//
|
|
// Put on pending queue
|
|
//
|
|
Miniport->FirstPendingPacket = Packet;
|
|
|
|
NDISM_LOG_PACKET(Miniport, Packet, NULL, 'oser');
|
|
|
|
//
|
|
// Set flag
|
|
//
|
|
CLEAR_RESOURCE(Miniport, 'S');
|
|
|
|
Status = NDIS_STATUS_PENDING;
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
ndisMWanSend(
|
|
IN NDIS_HANDLE NdisBindingHandle,
|
|
IN NDIS_HANDLE NdisLinkHandle,
|
|
IN PVOID Packet
|
|
)
|
|
{
|
|
PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
|
|
BOOLEAN LocalLock;
|
|
NDIS_STATUS Status;
|
|
KIRQL OldIrql;
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
LOCK_MINIPORT(Miniport, LocalLock);
|
|
|
|
//
|
|
// Call MAC to send WAN packet
|
|
//
|
|
Status = ((PNDIS_M_WAN_SEND)(Miniport->DriverHandle->MiniportCharacteristics.SendHandler))(
|
|
Miniport->MiniportAdapterContext,
|
|
NdisLinkHandle,
|
|
Packet);
|
|
|
|
if (LocalLock)
|
|
{
|
|
//
|
|
// Process any changes that may have occured.
|
|
//
|
|
NDISM_PROCESS_DEFERRED(Miniport);
|
|
}
|
|
|
|
UNLOCK_MINIPORT(Miniport, LocalLock);
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
ndisMSendCompleteFullDuplex(
|
|
IN NDIS_HANDLE MiniportAdapterHandle,
|
|
IN PNDIS_PACKET Packet,
|
|
IN NDIS_STATUS Status
|
|
)
|
|
{
|
|
#ifdef NDIS_NT
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
|
|
PNDIS_M_OPEN_BLOCK Open;
|
|
PNDIS_PACKET_RESERVED Reserved;
|
|
LONG Thread;
|
|
BOOLEAN fAcquireMiniportLock = FALSE;
|
|
|
|
ASSERT(MINIPORT_AT_DPC_LEVEL);
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("==>ndisMSendCompleteFullDuplex\n"));
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("packet 0x%x\n", Packet));
|
|
|
|
//
|
|
// Acquire the send lock, unless it has alrady been acquired earlier
|
|
// by this thread....
|
|
//
|
|
Thread = InterlockedExchangeAdd(&Miniport->SendThread, 0);
|
|
if (CURRENT_THREAD != Thread)
|
|
{
|
|
//
|
|
// We need to try and grab the lock...
|
|
//
|
|
NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
|
|
}
|
|
|
|
MINIPORT_SET_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED);
|
|
|
|
//
|
|
// If the packet is not equal to the first packet then we have to find
|
|
// it because it may have completed out of order.
|
|
//
|
|
Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
|
|
|
|
if (Miniport->FirstPacket == Packet)
|
|
{
|
|
Miniport->FirstPacket = Reserved->Next;
|
|
|
|
if (Miniport->LastMiniportPacket == Packet)
|
|
{
|
|
Miniport->LastMiniportPacket = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PNDIS_PACKET PrevPacket;
|
|
|
|
//
|
|
// Search for the packet.
|
|
//
|
|
MiniportFindPacket(Miniport, Packet, &PrevPacket);
|
|
|
|
ASSERT(PrevPacket != NULL);
|
|
|
|
//
|
|
// If we just completed the last packet then
|
|
// we need to update our last packet pointer.
|
|
//
|
|
PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next = Reserved->Next;
|
|
if (Packet == Miniport->LastPacket)
|
|
{
|
|
Miniport->LastPacket = PrevPacket;
|
|
}
|
|
|
|
//
|
|
// If we just completed the last miniport packet then
|
|
// last miniport packet is the previous packet.
|
|
//
|
|
if (Miniport->LastMiniportPacket == Packet)
|
|
{
|
|
Miniport->LastMiniportPacket = PrevPacket;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Indicate to Protocol;
|
|
//
|
|
Open = Reserved->Open;
|
|
|
|
//
|
|
// Do we need to queue another workitem to process more sends?
|
|
//
|
|
if (Miniport->FirstPendingPacket != NULL)
|
|
{
|
|
NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
|
|
}
|
|
|
|
|
|
#if DBG
|
|
NDISM_LOG_PACKET(Miniport, NULL, NULL, 'pmoc');
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
NDISM_LOG_PACKET(Miniport, Packet, NULL, 'liaf');
|
|
}
|
|
else
|
|
{
|
|
NDISM_LOG_PACKET(Miniport, Packet, NULL, 'ccus');
|
|
}
|
|
#endif
|
|
|
|
ADD_RESOURCE(Miniport, 'P');
|
|
|
|
NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
|
|
|
|
//
|
|
// If the current thread has the miniport lock then we need to
|
|
// release it....
|
|
//
|
|
if (CURRENT_THREAD == Miniport->MiniportThread)
|
|
{
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
fAcquireMiniportLock = TRUE;
|
|
}
|
|
|
|
(Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)(
|
|
Open->ProtocolBindingContext,
|
|
Packet,
|
|
Status);
|
|
|
|
if (fAcquireMiniportLock)
|
|
{
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
}
|
|
|
|
//
|
|
// If the SendLock was acquired on entry then we need to make sure
|
|
// that it's acquired on exit...
|
|
//
|
|
if (CURRENT_THREAD == Thread)
|
|
{
|
|
NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
|
|
}
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("<==ndisMSendCompleteFullDuplex\n"));
|
|
#endif
|
|
}
|
|
|
|
VOID
|
|
NdisMSendComplete(
|
|
IN NDIS_HANDLE MiniportAdapterHandle,
|
|
IN PNDIS_PACKET Packet,
|
|
IN NDIS_STATUS Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function indicates the completion of a send.
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterHandle - points to the adapter block.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
|
|
PNDIS_M_OPEN_BLOCK Open;
|
|
PNDIS_PACKET_RESERVED Reserved;
|
|
PSINGLE_LIST_ENTRY Link;
|
|
|
|
ASSERT(MINIPORT_AT_DPC_LEVEL);
|
|
ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("==>ndisMSendComplete\n"));
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("packet 0x%x\n", Packet));
|
|
|
|
MINIPORT_SET_SEND_FLAG(Miniport, fMINIPORT_SEND_COMPLETE_CALLED);
|
|
|
|
//
|
|
// If the packet is not equal to the first packet then we have to find
|
|
// it because it may have completed out of order.
|
|
//
|
|
Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
|
|
|
|
if (Miniport->FirstPacket == Packet)
|
|
{
|
|
Miniport->FirstPacket = Reserved->Next;
|
|
|
|
if (Miniport->LastMiniportPacket == Packet)
|
|
{
|
|
Miniport->LastMiniportPacket = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PNDIS_PACKET PrevPacket;
|
|
|
|
//
|
|
// Search for the packet.
|
|
//
|
|
MiniportFindPacket(Miniport, Packet, &PrevPacket);
|
|
|
|
ASSERT(PrevPacket != NULL);
|
|
|
|
//
|
|
// If we just completed the last packet then
|
|
// we need to update our last packet pointer.
|
|
//
|
|
PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next = Reserved->Next;
|
|
if (Packet == Miniport->LastPacket)
|
|
{
|
|
Miniport->LastPacket = PrevPacket;
|
|
}
|
|
|
|
//
|
|
// If we just completed the last miniport packet then
|
|
// last miniport packet is the previous packet.
|
|
//
|
|
|
|
if (Miniport->LastMiniportPacket == Packet)
|
|
{
|
|
Miniport->LastMiniportPacket = PrevPacket;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Indicate to Protocol;
|
|
//
|
|
Open = Reserved->Open;
|
|
|
|
//
|
|
// If this is arcnet, then free the appended header.
|
|
//
|
|
if (Miniport->MediaType == NdisMediumArcnet878_2)
|
|
{
|
|
ndisMFreeArcnetHeader(Miniport, Packet);
|
|
}
|
|
|
|
#if DBG
|
|
NDISM_LOG_PACKET(Miniport, NULL, NULL, 'pmoc');
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
NDISM_LOG_PACKET(Miniport, Packet, NULL, 'liaf');
|
|
}
|
|
else
|
|
{
|
|
NDISM_LOG_PACKET(Miniport, Packet, NULL, 'ccus');
|
|
}
|
|
#endif
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
(Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)(
|
|
Open->ProtocolBindingContext,
|
|
Packet,
|
|
Status);
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
ADD_RESOURCE(Miniport, 'P');
|
|
|
|
DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
|
|
("- Open 0x%x Reference 0x%x\n", Open, Open->References));
|
|
|
|
Open->References--;
|
|
|
|
DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
|
|
("==0 Open 0x%x Reference 0x%x\n", Open, Open->References));
|
|
|
|
if (Open->References == 0)
|
|
{
|
|
ndisMFinishClose(Miniport,Open);
|
|
}
|
|
|
|
//
|
|
// Do we need to queue another workitem to process more sends?
|
|
//
|
|
if (Miniport->FirstPendingPacket != NULL)
|
|
{
|
|
NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
|
|
}
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("<==ndisMSendComplete\n"));
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisMWanSendComplete(
|
|
IN NDIS_HANDLE MiniportAdapterHandle,
|
|
IN PNDIS_PACKET Packet,
|
|
IN NDIS_STATUS Status
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function indicates the status is complete.
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterHandle - points to the adapter block.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
|
|
--*/
|
|
{
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
|
|
PNDIS_M_OPEN_BLOCK Open;
|
|
|
|
ASSERT(MINIPORT_AT_DPC_LEVEL);
|
|
ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
|
|
|
|
Open = Miniport->OpenQueue;
|
|
|
|
while (Open != NULL)
|
|
{
|
|
//
|
|
// Call Protocol to indicate status
|
|
//
|
|
|
|
NDISM_LOG_PACKET(Miniport, Packet, NULL, 'C');
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
(Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler) (
|
|
Open->ProtocolBindingContext,
|
|
Packet,
|
|
Status);
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
Open = Open->MiniportNextOpen;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
ndisMSendResourcesAvailableFullDuplex(
|
|
IN NDIS_HANDLE MiniportAdapterHandle
|
|
)
|
|
{
|
|
#ifdef NDIS_NT
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
|
|
LONG Thread;
|
|
|
|
ASSERT(MINIPORT_AT_DPC_LEVEL);
|
|
|
|
Thread = InterlockedExchangeAdd(&Miniport->SendThread, 0);
|
|
if (CURRENT_THREAD != Thread)
|
|
{
|
|
NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
|
|
}
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("==>ndisMSendResourcesAvailableFullDuplex\n"));
|
|
|
|
NDISM_LOG_PACKET(Miniport, NULL, NULL, 'aser');
|
|
ADD_RESOURCE(Miniport, 'V');
|
|
|
|
//
|
|
// Are there more sends to process?
|
|
//
|
|
if (Miniport->FirstPendingPacket != NULL)
|
|
{
|
|
NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
|
|
}
|
|
|
|
if (CURRENT_THREAD != Thread)
|
|
{
|
|
NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
|
|
}
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("<==ndisMSendResourcesAvailableFullDuplex\n"));
|
|
#endif
|
|
}
|
|
|
|
VOID
|
|
NdisMSendResourcesAvailable(
|
|
IN NDIS_HANDLE MiniportAdapterHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function indicates that some send resources are available and are free for
|
|
processing more sends.
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterHandle - points to the adapter block.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
|
|
--*/
|
|
{
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
|
|
|
|
ASSERT(MINIPORT_AT_DPC_LEVEL);
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("==>ndisMSendResourcesAvailable\n"));
|
|
|
|
ADD_RESOURCE(Miniport, 'V');
|
|
NDISM_LOG_PACKET(Miniport, NULL, NULL, 'aser');
|
|
|
|
//
|
|
// Are there more sends to process?
|
|
//
|
|
if (Miniport->FirstPendingPacket != NULL)
|
|
{
|
|
NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
|
|
}
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("<==ndisMSendResourcesAvailable\n"));
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// UPPER-EDGE SEND HANDLERS
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
NDIS_STATUS
|
|
ndisMSendFullDuplexToSendPackets(
|
|
IN NDIS_HANDLE NdisBindingHandle,
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_PENDING;
|
|
#ifdef NDIS_NT
|
|
PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
|
|
PNDIS_PACKET_RESERVED Reserved;
|
|
KIRQL OldIrql;
|
|
BOOLEAN fQueueWorkItem = FALSE;
|
|
BOOLEAN fDeferredSend = FALSE;
|
|
BOOLEAN LocalLock;
|
|
UINT Flags;
|
|
|
|
NDIS_ACQUIRE_SEND_SPIN_LOCK(Miniport, &OldIrql);
|
|
|
|
NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnes');
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("==>ndisMSendFullDuplexToSendPackets\n"));
|
|
|
|
//
|
|
// Initialize the packet info.
|
|
//
|
|
Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
|
|
Reserved->Next = NULL;
|
|
Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
|
|
|
|
//
|
|
// Place the packet on the packet queue.
|
|
//
|
|
if (Miniport->FirstPacket == NULL)
|
|
{
|
|
//
|
|
// Place the packet at the head of the queue.
|
|
//
|
|
Miniport->FirstPacket = Packet;
|
|
}
|
|
else
|
|
{
|
|
CHECK_FOR_DUPLICATE_PACKET(Miniport, Packet);
|
|
|
|
PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = Packet;
|
|
}
|
|
|
|
Miniport->LastPacket = Packet;
|
|
|
|
//
|
|
// This packet has not been looped back yet!
|
|
//
|
|
MINIPORT_CLEAR_PACKET_FLAG(Packet, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT));
|
|
|
|
//
|
|
// Check to see if a sync send is possible.
|
|
//
|
|
if (Miniport->FirstPendingPacket == NULL)
|
|
{
|
|
Miniport->FirstPendingPacket = Packet;
|
|
}
|
|
|
|
NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
|
|
|
|
NDISM_LOG_PACKET(Miniport, Packet, NULL, 'DNES');
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("<==ndisMSendFullDuplexToSendPackets\n"));
|
|
|
|
NDIS_RELEASE_SEND_SPIN_LOCK(Miniport, OldIrql);
|
|
#endif
|
|
return(Status);
|
|
}
|
|
|
|
VOID
|
|
ndisMSendPacketsFullDuplex(
|
|
IN PNDIS_OPEN_BLOCK NdisOpenBlock,
|
|
IN PPNDIS_PACKET PacketArray,
|
|
IN UINT NumberOfPackets
|
|
)
|
|
{
|
|
#ifdef NDIS_NT
|
|
PNDIS_M_OPEN_BLOCK NdisBindingHandle = (PNDIS_M_OPEN_BLOCK)NdisOpenBlock->MacBindingHandle;
|
|
PNDIS_MINIPORT_BLOCK Miniport = NdisBindingHandle->MiniportHandle;
|
|
PPNDIS_PACKET pPktArray;
|
|
PNDIS_PACKET_RESERVED Reserved;
|
|
BOOLEAN LocalLock;
|
|
KIRQL OldIrql;
|
|
UINT c;
|
|
|
|
NDIS_ACQUIRE_SEND_SPIN_LOCK(Miniport, &OldIrql);
|
|
|
|
NDISM_LOG_PACKET(Miniport, NULL, NULL, 'KPES');
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("==>ndisMSendPacketsFullDuplex\n"));
|
|
|
|
//
|
|
// Place the packets on the miniport queue.
|
|
//
|
|
for (c = 0, pPktArray = PacketArray;
|
|
c < NumberOfPackets;
|
|
c++, pPktArray++)
|
|
{
|
|
//
|
|
// Get the first packet....
|
|
//
|
|
NDIS_SET_PACKET_STATUS(*pPktArray, NDIS_STATUS_PENDING);
|
|
|
|
//
|
|
// Initialize the packet info.
|
|
//
|
|
Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray);
|
|
Reserved->Next = NULL;
|
|
Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
|
|
|
|
//
|
|
// Place the packet on the packet queue.
|
|
//
|
|
if (Miniport->FirstPacket == NULL)
|
|
{
|
|
//
|
|
// Place the packet at the head of the queue.
|
|
//
|
|
Miniport->FirstPacket = *pPktArray;
|
|
}
|
|
else
|
|
{
|
|
CHECK_FOR_DUPLICATE_PACKET(Miniport, *pPktArray);
|
|
|
|
PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = *pPktArray;
|
|
}
|
|
|
|
Miniport->LastPacket = *pPktArray;
|
|
|
|
//
|
|
// This packet has not been looped back yet!
|
|
//
|
|
MINIPORT_CLEAR_PACKET_FLAG(*pPktArray, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT));
|
|
|
|
//
|
|
// Check to see if a sync send is possible.
|
|
//
|
|
if (Miniport->FirstPendingPacket == NULL)
|
|
{
|
|
Miniport->FirstPendingPacket = *pPktArray;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Queue a workitem for the new sends.
|
|
//
|
|
NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
|
|
|
|
NDISM_LOG_PACKET(Miniport, NULL, NULL, 'KPES');
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("<==ndisMSendPacketsFullDuplex\n"));
|
|
|
|
NDIS_RELEASE_SEND_SPIN_LOCK(Miniport, OldIrql);
|
|
|
|
#endif
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
ndisMSendToSendPackets(
|
|
IN NDIS_HANDLE NdisBindingHandle,
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
{
|
|
PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
|
|
PNDIS_PACKET_RESERVED Reserved;
|
|
BOOLEAN LocalLock;
|
|
NDIS_STATUS Status = NDIS_STATUS_PENDING;
|
|
KIRQL OldIrql;
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
|
|
NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnes');
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("==>ndisMSendToSendPackets\n"));
|
|
|
|
//
|
|
// Increment the references on this open.
|
|
//
|
|
((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++;
|
|
|
|
DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
|
|
("+ Open 0x%x Reference 0x%x\n", NdisBindingHandle, ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References));
|
|
|
|
//
|
|
// Initialize the packet info.
|
|
//
|
|
Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
|
|
Reserved->Next = NULL;
|
|
Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
|
|
|
|
//
|
|
// Place the packet on the packet queue.
|
|
//
|
|
if (Miniport->FirstPacket == NULL)
|
|
{
|
|
//
|
|
// Place the packet at the head of the queue.
|
|
//
|
|
Miniport->FirstPacket = Packet;
|
|
}
|
|
else
|
|
{
|
|
CHECK_FOR_DUPLICATE_PACKET(Miniport, Packet);
|
|
|
|
PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = Packet;
|
|
}
|
|
|
|
Miniport->LastPacket = Packet;
|
|
|
|
//
|
|
// This packet has not been looped back yet!
|
|
//
|
|
MINIPORT_CLEAR_PACKET_FLAG(Packet, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT));
|
|
|
|
//
|
|
// Check to see if a sync send is possible.
|
|
//
|
|
if (Miniport->FirstPendingPacket == NULL)
|
|
{
|
|
Miniport->FirstPendingPacket = Packet;
|
|
}
|
|
|
|
NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
|
|
|
|
//
|
|
// Try to grab the local lock on the miniport block.
|
|
//
|
|
LOCK_MINIPORT(Miniport, LocalLock);
|
|
|
|
//
|
|
// If we have the local lock and there is not
|
|
// a reset in progress then fire off the send.
|
|
//
|
|
if (LocalLock)
|
|
{
|
|
//
|
|
// Process deferred.
|
|
//
|
|
NDISM_PROCESS_DEFERRED(Miniport);
|
|
}
|
|
|
|
UNLOCK_MINIPORT(Miniport, LocalLock);
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("<==ndisMSendToSendPackets\n"));
|
|
|
|
NDISM_LOG_PACKET(Miniport, Packet, NULL, 'DNES');
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
|
|
return(NDIS_STATUS_PENDING);
|
|
}
|
|
|
|
|
|
VOID
|
|
ndisMSendPackets(
|
|
IN PNDIS_OPEN_BLOCK NdisOpenBlock,
|
|
IN PPNDIS_PACKET PacketArray,
|
|
IN UINT NumberOfPackets
|
|
)
|
|
{
|
|
PNDIS_M_OPEN_BLOCK NdisBindingHandle = (PNDIS_M_OPEN_BLOCK)NdisOpenBlock->MacBindingHandle;
|
|
PNDIS_MINIPORT_BLOCK Miniport = NdisBindingHandle->MiniportHandle;
|
|
BOOLEAN LocalLock;
|
|
KIRQL OldIrql;
|
|
UINT c;
|
|
PNDIS_PACKET_RESERVED Reserved;
|
|
PPNDIS_PACKET pPktArray;;
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
NDISM_LOG_PACKET(Miniport, NULL, NULL, 'KPES');
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("==>ndisMSendPackets\n"));
|
|
|
|
//
|
|
// Place the packets on the miniport queue.
|
|
//
|
|
for (c = 0, pPktArray = PacketArray;
|
|
c < NumberOfPackets;
|
|
c++, pPktArray++)
|
|
{
|
|
//
|
|
// Get the first packet....
|
|
//
|
|
NDIS_SET_PACKET_STATUS(*pPktArray, NDIS_STATUS_PENDING);
|
|
|
|
//
|
|
// Initialize the packet info.
|
|
//
|
|
Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray);
|
|
Reserved->Next = NULL;
|
|
Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
|
|
|
|
//
|
|
// Increment the references on this open.
|
|
//
|
|
((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++;
|
|
|
|
DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
|
|
("+ Open 0x%x Reference 0x%x\n", NdisBindingHandle, ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References));
|
|
|
|
//
|
|
// Place the packet on the packet queue.
|
|
//
|
|
if (Miniport->FirstPacket == NULL)
|
|
{
|
|
//
|
|
// Place the packet at the head of the queue.
|
|
//
|
|
Miniport->FirstPacket = *pPktArray;
|
|
}
|
|
else
|
|
{
|
|
CHECK_FOR_DUPLICATE_PACKET(Miniport, *pPktArray);
|
|
|
|
PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = *pPktArray;
|
|
}
|
|
|
|
Miniport->LastPacket = *pPktArray;
|
|
|
|
//
|
|
// This packet has not been looped back yet!
|
|
//
|
|
MINIPORT_CLEAR_PACKET_FLAG(*pPktArray, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT));
|
|
|
|
//
|
|
// Check to see if a sync send is possible.
|
|
//
|
|
if (Miniport->FirstPendingPacket == NULL)
|
|
{
|
|
Miniport->FirstPendingPacket = *pPktArray;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Queue a workitem for the new sends.
|
|
//
|
|
NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
|
|
|
|
//
|
|
// Try to grab the local lock on the miniport block.
|
|
//
|
|
LOCK_MINIPORT(Miniport, LocalLock);
|
|
|
|
//
|
|
// If we have the local lock and there is not
|
|
// a reset in progress then fire off the send.
|
|
//
|
|
if (LocalLock)
|
|
{
|
|
//
|
|
// Process deferred.
|
|
//
|
|
NDISM_PROCESS_DEFERRED(Miniport);
|
|
}
|
|
|
|
UNLOCK_MINIPORT(Miniport, LocalLock);
|
|
|
|
NDISM_LOG_PACKET(Miniport, NULL, NULL, 'KPES');
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("<==ndisMSendPackets\n"));
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
}
|
|
|
|
VOID
|
|
ndisMSendPacketsFullDuplexToSend(
|
|
IN PNDIS_OPEN_BLOCK NdisOpenBlock,
|
|
IN PPNDIS_PACKET PacketArray,
|
|
IN UINT NumberOfPackets
|
|
)
|
|
{
|
|
#ifdef NDIS_NT
|
|
PNDIS_M_OPEN_BLOCK NdisBindingHandle = (PNDIS_M_OPEN_BLOCK)NdisOpenBlock->MacBindingHandle;
|
|
PNDIS_MINIPORT_BLOCK Miniport = NdisBindingHandle->MiniportHandle;
|
|
PNDIS_PACKET_RESERVED Reserved;
|
|
PPNDIS_PACKET pPktArray;
|
|
BOOLEAN LocalLock;
|
|
KIRQL OldIrql;
|
|
UINT c;
|
|
|
|
NDIS_ACQUIRE_SEND_SPIN_LOCK(Miniport, &OldIrql);
|
|
|
|
NDISM_LOG_PACKET(Miniport, NULL, NULL, 'kpes');
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("==>ndisMSendPacketsFullDuplexToSend\n"));
|
|
|
|
//
|
|
// Place the packets on the miniport queue.
|
|
//
|
|
for (c = 0, pPktArray = PacketArray;
|
|
c < NumberOfPackets;
|
|
c++, pPktArray++)
|
|
{
|
|
//
|
|
// Initialize the packet info.
|
|
//
|
|
Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray);
|
|
Reserved->Next = NULL;
|
|
Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
|
|
|
|
//
|
|
// Place the packet on the packet queue.
|
|
//
|
|
if (Miniport->FirstPacket == NULL)
|
|
{
|
|
//
|
|
// Place the packet at the head of the queue.
|
|
//
|
|
Miniport->FirstPacket = *pPktArray;
|
|
}
|
|
else
|
|
{
|
|
CHECK_FOR_DUPLICATE_PACKET(Miniport, *pPktArray);
|
|
|
|
PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = *pPktArray;
|
|
}
|
|
|
|
Miniport->LastPacket = *pPktArray;
|
|
|
|
//
|
|
// This packet has not been looped back yet.
|
|
//
|
|
MINIPORT_CLEAR_PACKET_FLAG(*pPktArray, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT));
|
|
|
|
//
|
|
// Check to see if a sync send is possible.
|
|
//
|
|
if (Miniport->FirstPendingPacket == NULL)
|
|
{
|
|
Miniport->FirstPendingPacket = *pPktArray;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Queue a workitem for the new sends.
|
|
//
|
|
NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
|
|
|
|
NDISM_LOG_PACKET(Miniport, NULL, NULL, 'KPES');
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("<==ndisMSendPacketsFullDuplexToSend\n"));
|
|
|
|
NDIS_RELEASE_SEND_SPIN_LOCK(Miniport, OldIrql);
|
|
#endif
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ndisMSendFullDuplex(
|
|
IN NDIS_HANDLE NdisBindingHandle,
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_PENDING;
|
|
#ifdef NDIS_NT
|
|
PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
|
|
PNDIS_PACKET_RESERVED Reserved;
|
|
KIRQL OldIrql;
|
|
BOOLEAN fQueueWorkItem = FALSE;
|
|
BOOLEAN fDeferredSend = FALSE;
|
|
BOOLEAN LocalLock;
|
|
UINT Flags;
|
|
|
|
NDIS_ACQUIRE_SEND_SPIN_LOCK(Miniport, &OldIrql);
|
|
|
|
NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnes');
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("==>ndisMSendFullDuplex\n"));
|
|
|
|
//
|
|
// Initialize the packet info.
|
|
//
|
|
Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
|
|
Reserved->Next = NULL;
|
|
Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
|
|
|
|
//
|
|
// Place the packet on the packet queue.
|
|
//
|
|
if (Miniport->FirstPacket == NULL)
|
|
{
|
|
//
|
|
// Place the packet at the head of the queue.
|
|
//
|
|
Miniport->FirstPacket = Packet;
|
|
}
|
|
else
|
|
{
|
|
CHECK_FOR_DUPLICATE_PACKET(Miniport, Packet);
|
|
|
|
PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = Packet;
|
|
}
|
|
|
|
Miniport->LastPacket = Packet;
|
|
|
|
//
|
|
// This packet has not been looped back yet and it does not
|
|
// contain any media specific information.
|
|
//
|
|
MINIPORT_CLEAR_PACKET_FLAG(Packet, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT));
|
|
|
|
if (NULL == Miniport->FirstPendingPacket)
|
|
{
|
|
Miniport->FirstPendingPacket = Packet;
|
|
}
|
|
|
|
NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
|
|
|
|
NDISM_LOG_PACKET(Miniport, Packet, NULL, 'DNES');
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("<==ndisMSendFullDuplex\n"));
|
|
|
|
NDIS_RELEASE_SEND_SPIN_LOCK(Miniport, OldIrql);
|
|
#endif
|
|
return(Status);
|
|
}
|
|
|
|
VOID
|
|
ndisMSendPacketsToSend(
|
|
IN PNDIS_OPEN_BLOCK NdisOpenBlock,
|
|
IN PPNDIS_PACKET PacketArray,
|
|
IN UINT NumberOfPackets
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will take a packet array and "thunk" it down for a
|
|
driver that does not support a send packet handler.
|
|
This involves queueing the packet array onto the miniport's packet queue
|
|
and sending them one at a time.
|
|
|
|
Arguments:
|
|
|
|
NdisBindingHandle - Pointer to the NDIS_OPEN_BLOCK.
|
|
PacketArray - Array of PNDIS_PACKET structures that are
|
|
to be sent to the miniport as NDIS_PACKETs.
|
|
NumberOfPackets - Number of elements in the PacketArray.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_M_OPEN_BLOCK NdisBindingHandle = (PNDIS_M_OPEN_BLOCK)NdisOpenBlock->MacBindingHandle;
|
|
PNDIS_MINIPORT_BLOCK Miniport = NdisBindingHandle->MiniportHandle;
|
|
PNDIS_PACKET Packet;
|
|
PNDIS_PACKET_RESERVED Reserved;
|
|
PPNDIS_PACKET pPktArray;
|
|
BOOLEAN LocalLock;
|
|
KIRQL OldIrql;
|
|
UINT c;
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
|
|
NDISM_LOG_PACKET(Miniport, NULL, NULL, 'kpes');
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("==>ndisMSendPacketsToSend\n"));
|
|
|
|
//
|
|
// Try to grab the local lock on the miniport block.
|
|
//
|
|
LOCK_MINIPORT(Miniport, LocalLock);
|
|
|
|
//
|
|
// Place the packets on the miniport queue.
|
|
//
|
|
for (c = 0, pPktArray = PacketArray;
|
|
c < NumberOfPackets;
|
|
c++, pPktArray++)
|
|
{
|
|
//
|
|
// Initialize the packet info.
|
|
//
|
|
Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(*pPktArray);
|
|
Reserved->Next = NULL;
|
|
Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
|
|
|
|
//
|
|
// Increment the references on this open.
|
|
//
|
|
((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++;
|
|
|
|
DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
|
|
("+ Open 0x%x Reference 0x%x\n", NdisBindingHandle, ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References));
|
|
|
|
//
|
|
// Place the packet on the packet queue.
|
|
//
|
|
if (Miniport->FirstPacket == NULL)
|
|
{
|
|
//
|
|
// Place the packet at the head of the queue.
|
|
//
|
|
Miniport->FirstPacket = *pPktArray;
|
|
}
|
|
else
|
|
{
|
|
CHECK_FOR_DUPLICATE_PACKET(Miniport, *pPktArray);
|
|
|
|
PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = *pPktArray;
|
|
}
|
|
|
|
Miniport->LastPacket = *pPktArray;
|
|
|
|
//
|
|
// This packet has not been looped back yet.
|
|
//
|
|
MINIPORT_CLEAR_PACKET_FLAG(*pPktArray, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT));
|
|
|
|
//
|
|
// Check to see if a sync send is possible.
|
|
//
|
|
if (Miniport->FirstPendingPacket == NULL)
|
|
{
|
|
Miniport->FirstPendingPacket = *pPktArray;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Queue a workitem for the new sends.
|
|
//
|
|
NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
|
|
|
|
//
|
|
// If we have the local lock and there is not
|
|
// a reset in progress then fire off the send.
|
|
//
|
|
if (LocalLock)
|
|
{
|
|
//
|
|
// Process deferred.
|
|
//
|
|
NDISM_PROCESS_DEFERRED(Miniport);
|
|
}
|
|
|
|
UNLOCK_MINIPORT(Miniport, LocalLock);
|
|
|
|
NDISM_LOG_PACKET(Miniport, NULL, NULL, 'KPES');
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("<==ndisMSendPacketsToSend\n"));
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ndisMSend(
|
|
IN NDIS_HANDLE NdisBindingHandle,
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
{
|
|
PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
|
|
PNDIS_PACKET_RESERVED Reserved;
|
|
BOOLEAN LocalLock;
|
|
BOOLEAN SyncSend = FALSE;
|
|
NDIS_STATUS Status = NDIS_STATUS_PENDING;
|
|
KIRQL OldIrql;
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
|
|
NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnes');
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("==>ndisMSend\n"));
|
|
|
|
//
|
|
// Try to grab the local lock on the miniport block.
|
|
//
|
|
LOCK_MINIPORT(Miniport, LocalLock);
|
|
|
|
//
|
|
// Increment the references on this open.
|
|
//
|
|
((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++;
|
|
|
|
DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
|
|
("+ Open 0x%x Reference 0x%x\n", NdisBindingHandle, ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References));
|
|
|
|
//
|
|
// Initialize the packet info.
|
|
//
|
|
Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
|
|
Reserved->Next = NULL;
|
|
Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
|
|
|
|
//
|
|
// Place the packet on the packet queue.
|
|
//
|
|
if (Miniport->FirstPacket == NULL)
|
|
{
|
|
//
|
|
// Place the packet at the head of the queue.
|
|
//
|
|
Miniport->FirstPacket = Packet;
|
|
}
|
|
else
|
|
{
|
|
CHECK_FOR_DUPLICATE_PACKET(Miniport, Packet);
|
|
|
|
PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastPacket)->Next = Packet;
|
|
}
|
|
|
|
Miniport->LastPacket = Packet;
|
|
|
|
//
|
|
// Mark the packet as not having been looped back yet.
|
|
//
|
|
MINIPORT_CLEAR_PACKET_FLAG(Packet, (fPACKET_HAS_BEEN_LOOPED_BACK | fPACKET_HAS_TIMED_OUT));
|
|
|
|
if (NULL == Miniport->FirstPendingPacket)
|
|
{
|
|
Miniport->FirstPendingPacket = Packet;
|
|
|
|
SyncSend = TRUE;
|
|
}
|
|
|
|
//
|
|
// If we have the local lock and there is not
|
|
// a reset in progress then fire off the send.
|
|
//
|
|
if (LocalLock)
|
|
{
|
|
//
|
|
// Can we do a sync send?
|
|
//
|
|
if (SyncSend && (Miniport->WorkQueue[NdisWorkItemHalt].Next == NULL))
|
|
{
|
|
//
|
|
// TODO: Make the call to sync send inline!!!
|
|
//
|
|
// Synchronous send.
|
|
//
|
|
Status = ndisMSyncSend(Miniport, Packet);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Process deferred.
|
|
//
|
|
NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
|
|
NDISM_PROCESS_DEFERRED(Miniport);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We can't get the local lock so queue a workitem
|
|
// to process the send later.
|
|
//
|
|
NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
|
|
}
|
|
|
|
UNLOCK_MINIPORT(Miniport, LocalLock);
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("<==ndisMSend\n"));
|
|
|
|
NDISM_LOG_PACKET(Miniport, Packet, (PVOID)Status, 'DNES');
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
VOID
|
|
ndisMSendPacketsToFullMac(
|
|
IN PNDIS_OPEN_BLOCK NdisOpenBlock,
|
|
IN PPNDIS_PACKET PacketArray,
|
|
IN UINT NumberOfPackets
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
UINT c;
|
|
UINT Flags;
|
|
PPNDIS_PACKET pPktArray;
|
|
NDIS_STATUS Status;
|
|
|
|
//
|
|
// Send the packets to the mac one at a time.
|
|
//
|
|
for (c = 0, pPktArray = PacketArray;
|
|
c < NumberOfPackets;
|
|
c++, pPktArray++)
|
|
{
|
|
//
|
|
// Send the packet to the mac driver.
|
|
//
|
|
Status = NdisOpenBlock->SendHandler(
|
|
NdisOpenBlock->MacBindingHandle,
|
|
*pPktArray);
|
|
|
|
//
|
|
// If the packet is not pending then complete it back to the protocol.
|
|
//
|
|
if (NDIS_STATUS_PENDING != Status)
|
|
{
|
|
//
|
|
// Call the protocol's complete handler....
|
|
//
|
|
(NdisOpenBlock->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)(
|
|
NdisOpenBlock->ProtocolBindingContext,
|
|
*pPktArray,
|
|
Status);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
ndisMResetWanSend(
|
|
IN NDIS_HANDLE NdisBindingHandle,
|
|
IN NDIS_HANDLE NdisLinkHandle,
|
|
IN PVOID Packet
|
|
)
|
|
{
|
|
PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("==>ndisMResetWanSend\n"));
|
|
|
|
NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnes');
|
|
NDISM_LOG_PACKET(Miniport, Packet, NULL, ' PIR');
|
|
NDISM_LOG_PACKET(Miniport, Packet, NULL, 'DNES');
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("ndisMResetWanSend: Reset in progress or Reset Requested\n"));
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("<==ndisMResetWanSend\n"));
|
|
|
|
return(NDIS_STATUS_RESET_IN_PROGRESS);
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ndisMResetSend(
|
|
IN NDIS_HANDLE NdisBindingHandle,
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("==>ndisMResetSend\n"));
|
|
|
|
NDISM_LOG_PACKET(Miniport, Packet, NULL, 'dnes');
|
|
NDISM_LOG_PACKET(Miniport, Packet, NULL, ' PIR');
|
|
NDISM_LOG_PACKET(Miniport, Packet, NULL, 'DNES');
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("ndisMResetSend: Reset in progress or Reset Requested\n"));
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("<==ndisMResetSend\n"));
|
|
|
|
return(NDIS_STATUS_RESET_IN_PROGRESS);
|
|
}
|
|
|
|
VOID
|
|
ndisMResetSendPackets(
|
|
IN PNDIS_OPEN_BLOCK NdisOpenBlock,
|
|
IN PPNDIS_PACKET PacketArray,
|
|
IN UINT NumberOfPackets
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PNDIS_M_OPEN_BLOCK NdisBindingHandle = (PNDIS_M_OPEN_BLOCK)NdisOpenBlock->MacBindingHandle;
|
|
PNDIS_MINIPORT_BLOCK Miniport = NdisBindingHandle->MiniportHandle;
|
|
UINT c;
|
|
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("==>ndisMResetSendPackets\n"));
|
|
|
|
NDISM_LOG_PACKET(Miniport, NULL, NULL, 'kpes');
|
|
|
|
for (c = 0; c < NumberOfPackets; c++)
|
|
{
|
|
NDISM_LOG_PACKET(Miniport, PacketArray[c], NULL, ' PIR');
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("ndisMResetSendPackets: Reset in progress or Reset Requested\n"));
|
|
|
|
//
|
|
// For send packets we need to call the completion handler....
|
|
//
|
|
(NdisBindingHandle->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler)(
|
|
NdisBindingHandle->ProtocolBindingContext,
|
|
PacketArray[c],
|
|
NDIS_STATUS_RESET_IN_PROGRESS);
|
|
}
|
|
|
|
NDISM_LOG_PACKET(Miniport, NULL, NULL, 'KPES');
|
|
|
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
|
("<==ndisMResetSendPackets\n"));
|
|
|
|
}
|
|
|
|
|