Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2680 lines
75 KiB

/*++
Copyright (c) 1990-1995 Microsoft Corporation
Module Name:
sendm.c
Abstract:
Author:
Jameel Hyder (JameelH)
Kyle Brandon (KyleB)
Environment:
Kernel mode
Revision History:
--*/
#include <precomp.h>
#pragma hdrstop
//
// Define the module number for debug code.
//
#define MODULE_NUMBER MODULE_SENDM
///////////////////////////////////////////////////////////////////////////////////////
//
// UPPER-EDGE SEND HANDLERS
//
///////////////////////////////////////////////////////////////////////////////////////
VOID
ndisMSendPackets(
IN NDIS_HANDLE NdisBindingHandle,
IN PPNDIS_PACKET PacketArray,
IN UINT NumberOfPackets
)
{
PNDIS_OPEN_BLOCK Open = (PNDIS_OPEN_BLOCK)NdisBindingHandle;
PNDIS_STACK_RESERVED NSR;
PNDIS_MINIPORT_BLOCK Miniport = Open->MiniportHandle;
BOOLEAN LocalLock;
NDIS_STATUS Status;
KIRQL OldIrql;
UINT c;
PPNDIS_PACKET pPktArray;;
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("==>ndisMSendPackets\n"));
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
Status = NDIS_STATUS_SUCCESS;
//
// Place the packets on the miniport queue.
//
for (c = 0, pPktArray = PacketArray;
c < NumberOfPackets;
c++, pPktArray++)
{
PNDIS_PACKET Packet = *pPktArray;
ASSERT(Packet != NULL);
ASSERT(Packet->Private.Head != NULL);
PUSH_PACKET_STACK(Packet);
NDIS_STACK_RESERVED_FROM_PACKET(Packet, &NSR)
CHECK_FOR_DUPLICATE_PACKET(Miniport, Packet);
if (Packet->Private.Head == NULL)
{
Status = NDIS_STATUS_FAILURE;
}
else
{
if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_DO_NOT_MAP_MDLS))
{
ndisMCheckPacketAndGetStatsOutAlreadyMapped(Miniport, Packet);
}
else
{
ndisMCheckPacketAndGetStatsOut(Miniport, Packet, &Status);
}
}
NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_PENDING);
MINIPORT_CLEAR_PACKET_FLAG(Packet, fPACKET_SELF_DIRECTED);
DBGPRINT(DBG_COMP_OPENREF, DBG_LEVEL_INFO,
("+ Open 0x%x Reference 0x%x\n", NdisBindingHandle, Open->References));
M_OPEN_INCREMENT_REF_INTERLOCKED(Open);
LINK_PACKET(Miniport, Packet, NSR, Open);
if (Status != NDIS_STATUS_SUCCESS)
{
NDISM_COMPLETE_SEND(Miniport, Packet, NSR, Status, TRUE, 0);
Status = NDIS_STATUS_SUCCESS;
}
else if (Miniport->FirstPendingPacket == NULL)
{
Miniport->FirstPendingPacket = Packet;
}
}
//
// Queue a workitem for the new sends.
//
NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL);
LOCK_MINIPORT(Miniport, LocalLock);
if (LocalLock)
{
//
// We have the local lock
//
NDISM_PROCESS_DEFERRED(Miniport);
UNLOCK_MINIPORT(Miniport, LocalLock);
}
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("<==ndisMSendPackets\n"));
}
VOID
ndisMSendPacketsX(
IN NDIS_HANDLE NdisBindingHandle,
IN PPNDIS_PACKET PacketArray,
IN UINT NumberOfPackets
)
{
PNDIS_OPEN_BLOCK Open = (PNDIS_OPEN_BLOCK)NdisBindingHandle;
PNDIS_MINIPORT_BLOCK Miniport = Open->MiniportHandle;
PNDIS_STACK_RESERVED NSR;
PPNDIS_PACKET pPktArray, pSend;
NDIS_STATUS Status;
UINT c, k = 0, Flags;
BOOLEAN SelfDirected;
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("==>ndisMSendPacketsX\n"));
DBGPRINT(DBG_COMP_OPENREF, DBG_LEVEL_INFO,
("+ Open 0x%x Reference 0x%x\n", NdisBindingHandle, Open->References));
Status = NDIS_STATUS_SUCCESS ;
for (c = k = 0, pPktArray = pSend = PacketArray;
c < NumberOfPackets;
c++, pPktArray++)
{
PNDIS_PACKET Packet = *pPktArray;
//
// Initialize the packets with the Open
//
ASSERT(Packet != NULL);
ASSERT(Packet->Private.Head != NULL);
PUSH_PACKET_STACK(Packet);
NDIS_STACK_RESERVED_FROM_PACKET(Packet, &NSR)
NSR->Open = Open;
M_OPEN_INCREMENT_REF_INTERLOCKED(Open);
MINIPORT_CLEAR_PACKET_FLAG(Packet, fPACKET_SELF_DIRECTED);
NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, ScatterGatherListPacketInfo) = NULL;
if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_DO_NOT_MAP_MDLS))
{
ndisMCheckPacketAndGetStatsOutAlreadyMapped(Miniport, Packet);
}
else
{
ndisMCheckPacketAndGetStatsOut(Miniport, Packet, &Status);
}
SelfDirected = FALSE;
if (Status == NDIS_STATUS_SUCCESS)
{
//
// if PmodeOpens > 0 and NumOpens > 1, then check to see if we should
// loop back the packet.
//
// we should also should loopback the packet if the protocol did not
// explicitly asked for the packet not to be looped back and we have a miniport
// that has indicated that it does not do loopback itself or it is in all_local
// mode
//
if (NDIS_CHECK_FOR_LOOPBACK(Miniport, Packet))
{
//
// Handle loopback
//
SelfDirected = ndisMLoopbackPacketX(Miniport, Packet);
}
}
//
// Is this self-directed or if we should drop it due to low-resources?
//
if ((Status != NDIS_STATUS_SUCCESS) ||
MINIPORT_TEST_PACKET_FLAG((Packet), fPACKET_SELF_DIRECTED) ||
SelfDirected)
{
//
// Complete the packet back to the protocol.
//
ndisMSendCompleteX(Miniport, Packet, Status);
if (k > 0)
{
ASSERT(MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_PACKET_ARRAY));
//
// Send down the packets so far and skip this one.
//
(Open->WSendPacketsHandler)(Miniport->MiniportAdapterContext,
pSend,
k);
pSend = pPktArray + 1;
k = 0;
}
}
else
{
//
// This needs to go on the wire
//
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_SG_LIST))
{
ndisMAllocSGList(Miniport, Packet);
}
else if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_PACKET_ARRAY))
{
MINIPORT_SET_PACKET_FLAG(Packet, fPACKET_PENDING);
k++;
}
else
{
NDIS_STATUS SendStatus;
//
// We need to send this down right away
//
NdisQuerySendFlags(Packet, &Flags);
MINIPORT_SET_PACKET_FLAG(Packet, fPACKET_PENDING);
SendStatus = (Open->WSendHandler)(Open->MiniportAdapterContext, Packet, Flags);
//
// If the packet is not pending then complete it.
//
if (SendStatus != NDIS_STATUS_PENDING)
{
ndisMSendCompleteX(Miniport, Packet, SendStatus);
}
}
}
}
//
// Pass the remaining packet array down to the miniport.
//
if (k > 0)
{
ASSERT(MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_PACKET_ARRAY));
(Open->WSendPacketsHandler)(Miniport->MiniportAdapterContext,
pSend,
k);
}
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("<==ndisMSendPacketsX\n"));
}
NDIS_STATUS
ndisMSend(
IN NDIS_HANDLE NdisBindingHandle,
IN PNDIS_PACKET Packet
)
{
PNDIS_OPEN_BLOCK Open = ((PNDIS_OPEN_BLOCK)NdisBindingHandle);
PNDIS_MINIPORT_BLOCK Miniport = Open->MiniportHandle;
PNDIS_STACK_RESERVED NSR;
NDIS_STATUS Status;
BOOLEAN LocalLock;
KIRQL OldIrql;
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("==>ndisMSend\n"));
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
ASSERT(Packet->Private.Head != NULL);
CHECK_FOR_DUPLICATE_PACKET(Miniport, Packet);
if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_DO_NOT_MAP_MDLS))
{
Status = NDIS_STATUS_SUCCESS;
//1 do we need to do this for miniports that support stat OID
//1 for bytes out?
ndisMCheckPacketAndGetStatsOutAlreadyMapped(Miniport, Packet);
}
else
{
ndisMCheckPacketAndGetStatsOut(Miniport, Packet, &Status);
}
if (Status == NDIS_STATUS_SUCCESS)
{
MINIPORT_CLEAR_PACKET_FLAG(Packet, fPACKET_SELF_DIRECTED);
//
// Increment the references on this open.
//
M_OPEN_INCREMENT_REF_INTERLOCKED(Open);
DBGPRINT(DBG_COMP_OPENREF, DBG_LEVEL_INFO,
("+ Open 0x%x Reference 0x%x\n", NdisBindingHandle, ((PNDIS_OPEN_BLOCK)NdisBindingHandle)->References));
PUSH_PACKET_STACK(Packet);
NDIS_STACK_RESERVED_FROM_PACKET(Packet, &NSR)
LINK_PACKET(Miniport, Packet, NSR, Open);
if (Miniport->FirstPendingPacket == NULL)
{
Miniport->FirstPendingPacket = Packet;
}
//
// If we have the local lock and there is no
// packet pending, then fire off a send.
//
LOCK_MINIPORT(Miniport, LocalLock);
NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL);
if (LocalLock)
{
NDISM_PROCESS_DEFERRED(Miniport);
}
Status = NDIS_STATUS_PENDING;
UNLOCK_MINIPORT(Miniport, LocalLock);
}
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("<==ndisMSend\n"));
return Status;
}
NDIS_STATUS
ndisMSendX(
IN NDIS_HANDLE NdisBindingHandle,
IN PNDIS_PACKET Packet
)
{
PNDIS_OPEN_BLOCK Open = (PNDIS_OPEN_BLOCK)NdisBindingHandle;
PNDIS_MINIPORT_BLOCK Miniport = Open->MiniportHandle;
PNDIS_STACK_RESERVED NSR;
UINT Flags;
UINT OpenRef;
NDIS_STATUS Status;
BOOLEAN SelfDirected;
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("==>ndisMSendX\n"));
ASSERT(Packet->Private.Head != NULL);
if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_DO_NOT_MAP_MDLS))
{
Status = NDIS_STATUS_SUCCESS;
ndisMCheckPacketAndGetStatsOutAlreadyMapped(Miniport, Packet);
}
else
{
ndisMCheckPacketAndGetStatsOut(Miniport, Packet, &Status);
}
if (Status != NDIS_STATUS_SUCCESS)
{
return NDIS_STATUS_RESOURCES;
}
MINIPORT_CLEAR_PACKET_FLAG(Packet, fPACKET_SELF_DIRECTED);
NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, ScatterGatherListPacketInfo) = NULL;
//
// Initialize the packet info.
//
PUSH_PACKET_STACK(Packet);
NDIS_STACK_RESERVED_FROM_PACKET(Packet, &NSR)
NSR->Open = Open;
//
// Increment the references on this open.
//
DBGPRINT(DBG_COMP_OPENREF, DBG_LEVEL_INFO,
("+ Open 0x%x Reference 0x%x\n", Open, Open->References));
M_OPEN_INCREMENT_REF_INTERLOCKED(Open);
//
// HANDLE loopback
//
if (NDIS_CHECK_FOR_LOOPBACK(Miniport, Packet))
{
SelfDirected = ndisMLoopbackPacketX(Miniport, Packet);
}
else
{
SelfDirected = FALSE;
}
if ((!MINIPORT_TEST_PACKET_FLAG(Packet, fPACKET_SELF_DIRECTED)) &&
(!SelfDirected))
{
//
// Does the driver support the SG method ?
//
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_SG_LIST))
{
ndisMAllocSGList(Miniport, Packet);
}
//
// Handle Send/SendPacket differently
//
else if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_PACKET_ARRAY))
{
//
// Pass the packet down to the miniport.
//
(Open->WSendPacketsHandler)(Miniport->MiniportAdapterContext,
&Packet,
1);
}
else
{
NdisQuerySendFlags(Packet, &Flags);
MINIPORT_SET_PACKET_FLAG(Packet, fPACKET_PENDING);
//1 what is in the Flags parameter below?
Status = (Open->WSendHandler)(Open->MiniportAdapterContext, Packet, Flags);
if (Status != NDIS_STATUS_PENDING)
{
ndisMSendCompleteX(Miniport, Packet, Status);
}
}
Status = NDIS_STATUS_PENDING;
}
else
{
//
// Remove the reference added earlier.
//
DBGPRINT(DBG_COMP_OPENREF, DBG_LEVEL_INFO,
("- Open 0x%x Reference 0x%x\n", Open, Open->References));
M_OPEN_DECREMENT_REF_INTERLOCKED(Open, OpenRef);
/*
* Make sure that an IM which shares send and receive packets on the same
* pool works fine with the check in the receive path.
*/
NSR->RefCount = 0;
POP_PACKET_STACK(Packet);
MINIPORT_CLEAR_PACKET_FLAG(Packet, fPACKET_CLEAR_ITEMS);
Status = NDIS_STATUS_SUCCESS;
}
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("<==ndisMSendX\n"));
return(Status);
}
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_STACK_RESERVED NSR;
ASSERT_MINIPORT_LOCKED(Miniport);
#if DBG
Miniport->cDpcSendCompletes++;
#endif
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("==>ndisMSendComplete\n"));
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("packet 0x%x\n", Packet));
ASSERT(Packet->Private.Head != NULL);
NDIS_STACK_RESERVED_FROM_PACKET(Packet, &NSR)
ASSERT(VALID_OPEN(NSR->Open));
ASSERT(MINIPORT_TEST_PACKET_FLAG(Packet, fPACKET_PENDING));
//
// Guard against double/bogus completions.
//
if (VALID_OPEN(NSR->Open) &&
MINIPORT_TEST_PACKET_FLAG(Packet, fPACKET_PENDING))
{
ASSERT(Packet != Miniport->FirstPendingPacket);
if (MINIPORT_TEST_PACKET_FLAG(Packet, fPACKET_DONT_COMPLETE))
{
//
// If the packet completed in the context of a SendPackets, then
// defer completion. It will get completed when we unwind.
//
NDIS_SET_PACKET_STATUS(Packet, Status);
MINIPORT_CLEAR_PACKET_FLAG(Packet, fPACKET_DONT_COMPLETE);
}
else
{
NDISM_COMPLETE_SEND(Miniport, Packet, NSR, Status, FALSE, 1);
}
}
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("<==ndisMSendComplete\n"));
}
VOID
ndisMSendCompleteX(
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_STACK_RESERVED NSR;
PNDIS_OPEN_BLOCK Open;
UINT OpenRef;
KIRQL OldIrql;
#if DBG
Miniport->cDpcSendCompletes++;
#endif
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("==>ndisMSendCompleteX\n"));
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("packet 0x%x\n", Packet));
ASSERT(Packet->Private.Head != NULL);
RAISE_IRQL_TO_DISPATCH(&OldIrql);
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_SG_LIST) &&
(NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, ScatterGatherListPacketInfo) != NULL))
{
ndisMFreeSGList(Miniport, Packet);
}
//
// Indicate to Protocol;
//
NDIS_STACK_RESERVED_FROM_PACKET(Packet, &NSR)
POP_PACKET_STACK(Packet);
Open = NSR->Open;
ASSERT(VALID_OPEN(Open));
NSR->Open = MAGIC_OPEN_I(6);
#if ARCNET
ASSERT (Miniport->MediaType != NdisMediumArcnet878_2);
#endif
MINIPORT_CLEAR_PACKET_FLAG(Packet, fPACKET_CLEAR_ITEMS);
/*
* Make sure that an IM which shares send and receive packets on the same
* pool works fine with the check in the receive path.
*/
CLEAR_WRAPPER_RESERVED(NSR);
(Open->SendCompleteHandler)(Open->ProtocolBindingContext,
Packet,
Status);
DBGPRINT(DBG_COMP_OPENREF, DBG_LEVEL_INFO,
("- Open 0x%x Reference 0x%x\n", Open, Open->References));
M_OPEN_DECREMENT_REF_INTERLOCKED(Open, OpenRef);
DBGPRINT(DBG_COMP_OPENREF, DBG_LEVEL_INFO,
("==0 Open 0x%x Reference 0x%x\n", Open, Open->References));
if (OpenRef == 0)
{
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
ndisMFinishClose(Open);
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
}
LOWER_IRQL(OldIrql, DISPATCH_LEVEL);
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("<==ndisMSendCompleteX\n"));
}
BOOLEAN
FASTCALL
ndisMStartSendPackets(
IN PNDIS_MINIPORT_BLOCK Miniport
)
{
PNDIS_PACKET Packet;
NDIS_STATUS Status;
PNDIS_STACK_RESERVED NSR;
PPNDIS_PACKET pPktArray;
PNDIS_PACKET PacketArray[SEND_PACKET_ARRAY];
UINT MaxPkts = Miniport->MaxSendPackets;
W_SEND_PACKETS_HANDLER SendPacketsHandler = Miniport->WSendPacketsHandler;
BOOLEAN SelfDirected;
ASSERT_MINIPORT_LOCKED(Miniport);
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("==>ndisMStartSendPackets\n"));
//
// We could possibly end up with a situation (with intermediate serialized
// miniports) where there are no packets down with the driver and we the
// resource window is closed. In such a case open it fully. We are seeing this
// with wlbs
//
//1 do we need this any more? we don't support serialized IM drivers
if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESOURCES_AVAILABLE) &&
(Miniport->FirstPendingPacket == NULL))
{
ADD_RESOURCE(Miniport, 'X');
}
//
// Work-around for a scenario we are hitting when PacketList is empty but FirstPendingPacket is NOT
// Not sure how this can happen - yet.
//
if (IsListEmpty(&Miniport->PacketList))
{
ASSERT (Miniport->FirstPendingPacket == NULL);
Miniport->FirstPendingPacket = NULL;
}
while ((Miniport->FirstPendingPacket != NULL) &&
MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESOURCES_AVAILABLE))
{
UINT Count;
UINT NumberOfPackets;
ASSERT(!IsListEmpty(&Miniport->PacketList));
//
// Initialize the packet array.
//
pPktArray = PacketArray;
//
// Place as many packets as we can in the packet array to send
// to the miniport.
//
for (NumberOfPackets = 0;
(NumberOfPackets < MaxPkts) && (Miniport->FirstPendingPacket != NULL);
NOTHING)
{
//
// Grab the packet off of the pending queue.
//
ASSERT(!IsListEmpty(&Miniport->PacketList));
Packet = Miniport->FirstPendingPacket;
ASSERT(Packet->Private.Head != NULL);
NDIS_STACK_RESERVED_FROM_PACKET(Packet, &NSR)
ASSERT(VALID_OPEN(NSR->Open));
NEXT_PACKET_PENDING(Miniport, Packet);
//
// Indicate the packet loopback if necessary.
//
if (NDIS_CHECK_FOR_LOOPBACK(Miniport, Packet))
{
//
// make sure the packet does not get looped back at lower levels.
// we will restore the original flag on send completion
//
SelfDirected = ndisMLoopbackPacketX(Miniport, Packet);
}
else
{
SelfDirected = FALSE;
}
if (SelfDirected)
{
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("Packet 0x%x is self-directed.\n", Packet));
//
// Complete the packet back to the binding.
//
NDISM_COMPLETE_SEND(Miniport, Packet, NSR, NDIS_STATUS_SUCCESS, TRUE, 2);
//
// No, we don't want to increment the counter for the
// miniport's packet array.
//
}
else
{
//
// We have to re-initialize this.
//
*pPktArray = Packet;
MINIPORT_SET_PACKET_FLAG(Packet, (fPACKET_DONT_COMPLETE | fPACKET_PENDING));
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)
{
break;
}
pPktArray = PacketArray;
{
//
// Pass the packet array down to the miniport.
//
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
(SendPacketsHandler)(Miniport->MiniportAdapterContext,
pPktArray,
NumberOfPackets);
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
}
//
// Process the packet completion.
//
for (Count = 0; Count < NumberOfPackets; Count++, pPktArray++)
{
Packet = *pPktArray;
ASSERT(Packet != NULL);
Status = NDIS_GET_PACKET_STATUS(*pPktArray);
MINIPORT_CLEAR_PACKET_FLAG(Packet, fPACKET_DONT_COMPLETE);
//
// Process the packet based on it's return status.
//
if (NDIS_STATUS_PENDING == Status)
{
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("Complete is pending\n"));
}
else if (Status != NDIS_STATUS_RESOURCES)
{
//
// Remove from the finish queue.
//
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("Completed packet 0x%x with status 0x%x\n",
Packet, Status));
NDIS_STACK_RESERVED_FROM_PACKET(Packet, &NSR)
if (VALID_OPEN(NSR->Open))
{
NDISM_COMPLETE_SEND(Miniport, Packet, NSR, Status, TRUE, 3);
}
}
else
{
//
// Once we hit a return code of NDIS_STATUS_RESOURCES
// for a packet then we must break out and re-queue.
//
UINT i;
Miniport->FirstPendingPacket = Packet;
CLEAR_RESOURCE(Miniport, 'S');
for (i = Count; i < NumberOfPackets; i++)
{
PNDIS_PACKET QueuedPacket = PacketArray[i];
MINIPORT_CLEAR_PACKET_FLAG(QueuedPacket, fPACKET_PENDING);
VALIDATE_PACKET_OPEN(QueuedPacket);
}
break;
}
}
}
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("<==ndisMStartSendPackets\n"));
return(FALSE);
}
BOOLEAN
FASTCALL
ndisMStartSends(
IN 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_STACK_RESERVED NSR;
NDIS_STATUS Status;
PNDIS_OPEN_BLOCK Open;
ASSERT_MINIPORT_LOCKED(Miniport);
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("==>ndisMStartSends\n"));
while ((Miniport->FirstPendingPacket != NULL) &&
MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESOURCES_AVAILABLE))
{
//
// Grab the packet off of the pending queue.
//
ASSERT(!IsListEmpty(&Miniport->PacketList));
Packet = Miniport->FirstPendingPacket;
ASSERT(Packet->Private.Head != NULL);
NDIS_STACK_RESERVED_FROM_PACKET(Packet, &NSR)
Open = NSR->Open;
ASSERT(VALID_OPEN(Open));
#if ARCNET
//
// 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)
{
break;
}
}
#endif
NEXT_PACKET_PENDING(Miniport, Packet);
NDISM_SEND_PACKET(Miniport, Open, Packet, &Status);
//
// Process the packet pending completion status.
//
if (NDIS_STATUS_PENDING == Status)
{
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("Complete is pending\n"));
}
else
{
MINIPORT_CLEAR_PACKET_FLAG(Packet, fPACKET_PENDING);
//
// Handle the completion and resources cases.
//
if (Status == NDIS_STATUS_RESOURCES)
{
NDISM_COMPLETE_SEND_RESOURCES(Miniport, NSR, Packet);
}
else
{
NDISM_COMPLETE_SEND(Miniport, Packet, NSR, Status, TRUE, 4);
}
}
}
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("<==ndisMStartSends\n"));
return(FALSE);
}
BOOLEAN
FASTCALL
ndisMIsLoopbackPacket(
IN PNDIS_MINIPORT_BLOCK Miniport,
IN PNDIS_PACKET Packet,
OUT PNDIS_PACKET * LoopbackPacket OPTIONAL
)
/*++
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, NotDirected;
PNDIS_PACKET pNewPacket = NULL;
PUCHAR Buffer;
NDIS_STATUS Status;
PNDIS_BUFFER pNdisBuffer = NULL;
UINT HdrLength;
LOCK_STATE LockState;
//
// We should not be here if the driver handles loopback.
//
Loopback = FALSE;
SelfDirected = FALSE;
FirstBuffer = Packet->Private.Head;
BufferAddress = MDL_ADDRESS_SAFE(FirstBuffer, HighPagePriority);
if (BufferAddress == NULL)
{
if (ARGUMENT_PRESENT(LoopbackPacket))
*LoopbackPacket = NULL;
return(FALSE);
}
//
// 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_FLAG(Miniport, fMINIPORT_SEND_LOOPBACK_DIRECTED))
{
if (!ETH_IS_MULTICAST(BufferAddress))
{
//
// Packet is of type directed, now make sure that it
// is not self-directed.
//
ETH_COMPARE_NETWORK_ADDRESSES_EQ(BufferAddress,
Miniport->EthDB->AdapterAddress,
&NotDirected);
if (!NotDirected)
{
SelfDirected = Loopback = TRUE;
break;
}
}
//
// since all_local is set we do loopback the packet
// ourselves
//
Loopback = TRUE;
break;
}
READ_LOCK_FILTER(Miniport, Miniport->EthDB, &LockState);
//
// Check for the miniports that don't do loopback.
//
EthShouldAddressLoopBackMacro(Miniport->EthDB,
BufferAddress,
&Loopback,
&SelfDirected);
READ_UNLOCK_FILTER(Miniport, Miniport->EthDB, &LockState);
break;
case NdisMedium802_5:
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_SEND_LOOPBACK_DIRECTED))
{
TR_IS_NOT_DIRECTED(BufferAddress + 2, &NotDirected);
if (!NotDirected)
{
//
// Packet is of type directed, now make sure that it
// is not self-directed.
//
TR_COMPARE_NETWORK_ADDRESSES_EQ(BufferAddress + 2,
Miniport->TrDB->AdapterAddress,
&NotDirected);
if (!NotDirected)
{
SelfDirected = Loopback = TRUE;
break;
}
}
//
// since all_local is set we do loopback the packet
// ourselves
//
Loopback = TRUE;
break;
}
READ_LOCK_FILTER(Miniport, Miniport->TrDB, &LockState);
TrShouldAddressLoopBackMacro(Miniport->TrDB,
BufferAddress +2,
BufferAddress +8,
&Loopback,
&SelfDirected);
READ_UNLOCK_FILTER(Miniport, Miniport->TrDB, &LockState);
break;
case NdisMediumFddi:
if (MINIPORT_TEST_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)
{
//
// 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,
&NotDirected);
if (!NotDirected)
{
SelfDirected = Loopback = TRUE;
break;
}
}
//
// since all_local is set we do loopback the packet
// ourselves
//
Loopback = TRUE;
break;
}
READ_LOCK_FILTER(Miniport, Miniport->FddiDB, &LockState);
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);
READ_UNLOCK_FILTER(Miniport, Miniport->FddiDB, &LockState);
break;
#if ARCNET
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.
//
return(SelfDirected);
break;
#endif
}
if (Loopback && (NdisGetPacketFlags(Packet) & NDIS_FLAGS_LOOPBACK_ONLY))
{
SelfDirected = TRUE;
}
//
// Mark packet with reserved bit to indicate that it is self-directed
//
if (SelfDirected)
{
MINIPORT_SET_PACKET_FLAG(Packet, fPACKET_SELF_DIRECTED);
}
//
// If it is not a loopback packet then get out of here.
//
if (!Loopback)
{
ASSERT(!SelfDirected);
return (NdisGetPacketFlags(Packet) & NDIS_FLAGS_LOOPBACK_ONLY) ? TRUE : FALSE;
}
do
{
PNDIS_STACK_RESERVED NSR;
UINT PktSize;
ULONG j;
//
//
// Get the buffer length.
//
NdisQueryPacketLength(Packet, &Length);
Offset = 0;
//
// Allocate a buffer for the packet.
//
PktSize = NdisPacketSize(PROTOCOL_RESERVED_SIZE_IN_PACKET);
pNewPacket = (PNDIS_PACKET)ALLOC_FROM_POOL(Length + PktSize, NDIS_TAG_LOOP_PKT);
if (NULL == pNewPacket)
{
Status = NDIS_STATUS_RESOURCES;
break;
}
//
// Get a pointer to the destination buffer.
//
ZeroMemory(pNewPacket, PktSize);
Buffer = (PUCHAR)pNewPacket + PktSize;
pNewPacket = (PNDIS_PACKET)((PUCHAR)pNewPacket + SIZE_PACKET_STACKS);
for (j = 0; j < ndisPacketStackSize; j++)
{
CURR_STACK_LOCATION(pNewPacket) = j;
NDIS_STACK_RESERVED_FROM_PACKET(pNewPacket, &NSR);
INITIALIZE_SPIN_LOCK(&NSR->Lock);
}
CURR_STACK_LOCATION(pNewPacket) = (ULONG)-1;
//
// Allocate an MDL for the packet.
//
NdisAllocateBuffer(&Status, &pNdisBuffer, NULL, Buffer, Length);
if (NDIS_STATUS_SUCCESS != Status)
{
break;
}
//
// NdisChainBufferAtFront()
//
pNewPacket->Private.Head = pNdisBuffer;
pNewPacket->Private.Tail = pNdisBuffer;
pNewPacket->Private.Pool = (PVOID)'pooL';
pNewPacket->Private.NdisPacketOobOffset = (USHORT)(PktSize - (SIZE_PACKET_STACKS +
sizeof(NDIS_PACKET_OOB_DATA) +
sizeof(NDIS_PACKET_EXTENSION)));
NDIS_SET_ORIGINAL_PACKET(pNewPacket, pNewPacket);
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.
if (HdrLength != Length)
{
Status = NDIS_STATUS_RESOURCES;
break;
}
if (ARGUMENT_PRESENT(LoopbackPacket))
{
*LoopbackPacket = pNewPacket;
MINIPORT_SET_PACKET_FLAG(pNewPacket, fPACKET_IS_LOOPBACK);
pNewPacket->Private.Flags = NdisGetPacketFlags(Packet) & NDIS_FLAGS_DONT_LOOPBACK;
pNewPacket->Private.Flags |= NDIS_FLAGS_IS_LOOPBACK_PACKET;
}
} while (FALSE);
if (NDIS_STATUS_SUCCESS != Status)
{
if (NULL != pNewPacket)
{
pNewPacket = (PNDIS_PACKET)((PUCHAR)pNewPacket - SIZE_PACKET_STACKS);
FREE_POOL(pNewPacket);
}
if (pNdisBuffer != NULL)
{
NdisFreeBuffer(pNdisBuffer);
}
*LoopbackPacket = NULL;
SelfDirected = FALSE;
}
return SelfDirected;
}
BOOLEAN
FASTCALL
ndisMLoopbackPacketX(
IN PNDIS_MINIPORT_BLOCK Miniport,
IN PNDIS_PACKET Packet
)
{
PNDIS_PACKET LoopbackPacket = NULL;
PNDIS_PACKET_OOB_DATA pOob;
PNDIS_STACK_RESERVED NSR;
PUCHAR BufferAddress;
KIRQL OldIrql = PASSIVE_LEVEL;
BOOLEAN fSelfDirected;
fSelfDirected = !MINIPORT_TEST_PACKET_FLAG(Packet, fPACKET_ALREADY_LOOPEDBACK) &&
ndisMIsLoopbackPacket(Miniport, Packet, &LoopbackPacket);
if ((LoopbackPacket != NULL) && (NdisMediumArcnet878_2 != Miniport->MediaType))
{
MINIPORT_SET_PACKET_FLAG(Packet, fPACKET_ALREADY_LOOPEDBACK);
pOob = NDIS_OOB_DATA_FROM_PACKET(LoopbackPacket);
NDIS_STACK_RESERVED_FROM_PACKET(Packet, &NSR);
pOob->Status = NDIS_STATUS_RESOURCES;
PNDIS_LB_REF_FROM_PNDIS_PACKET(LoopbackPacket)->Open = NSR->Open;
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_DESERIALIZE))
{
RAISE_IRQL_TO_DISPATCH(&OldIrql);
}
//
// For ethernet/token-ring/fddi/encapsulated arc-net, we want to
// indicate the packet using the receivepacket way.
//
if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_DESERIALIZE))
{
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
}
switch (Miniport->MediaType)
{
case NdisMedium802_3:
pOob->HeaderSize = 14;
ethFilterDprIndicateReceivePacket(Miniport, &LoopbackPacket, 1);
break;
case NdisMedium802_5:
pOob->HeaderSize = 14;
BufferAddress = (PUCHAR)LoopbackPacket + NdisPacketSize(PROTOCOL_RESERVED_SIZE_IN_PACKET) - SIZE_PACKET_STACKS;
if (BufferAddress[8] & 0x80)
{
pOob->HeaderSize += (BufferAddress[14] & 0x1F);
}
trFilterDprIndicateReceivePacket(Miniport, &LoopbackPacket, 1);
break;
case NdisMediumFddi:
BufferAddress = (PUCHAR)LoopbackPacket + NdisPacketSize(PROTOCOL_RESERVED_SIZE_IN_PACKET) - SIZE_PACKET_STACKS;
pOob->HeaderSize = (*BufferAddress & 0x40) ?
2 * FDDI_LENGTH_OF_LONG_ADDRESS + 1:
2 * FDDI_LENGTH_OF_SHORT_ADDRESS + 1;
fddiFilterDprIndicateReceivePacket(Miniport, &LoopbackPacket, 1);
break;
default:
ASSERT(0);
break;
}
if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_DESERIALIZE))
{
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
}
else
{
LOWER_IRQL(OldIrql, DISPATCH_LEVEL);
}
ASSERT(NDIS_GET_PACKET_STATUS(LoopbackPacket) != NDIS_STATUS_PENDING);
NdisFreeBuffer(LoopbackPacket->Private.Head);
LoopbackPacket = (PNDIS_PACKET)((PUCHAR)LoopbackPacket - SIZE_PACKET_STACKS);
FREE_POOL(LoopbackPacket);
}
return(fSelfDirected);
}
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;
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("==>ndisMSendResourcesAvailable\n"));
ASSERT(MINIPORT_AT_DPC_LEVEL);
ADD_RESOURCE(Miniport, 'V');
//
// Are there more sends to process?
//
if (Miniport->FirstPendingPacket != NULL)
{
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
ASSERT(!IsListEmpty(&Miniport->PacketList));
NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL);
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
}
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("<==ndisMSendResourcesAvailable\n"));
}
VOID
NdisMTransferDataComplete(
IN NDIS_HANDLE MiniportAdapterHandle,
IN PNDIS_PACKET Packet,
IN NDIS_STATUS Status,
IN UINT BytesTransferred
)
/*++
Routine Description:
This function indicates the completion of a transfer data request.
Arguments:
MiniportAdapterHandle - points to the adapter block.
Packet - The packet the data was copied into.
Status - Status of the operation.
BytesTransferred - Total number of bytes transferred.
Return Value:
None.
--*/
{
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
PNDIS_OPEN_BLOCK Open = NULL;
KIRQL OldIrql = PASSIVE_LEVEL;
ASSERT_MINIPORT_LOCKED(Miniport);
// GET_CURRENT_XFER_DATA_PACKET_STACK(Packet, Open);
GET_CURRENT_XFER_DATA_PACKET_STACK_AND_ZERO_OUT(Packet, Open);
if (Open)
{
POP_XFER_DATA_PACKET_STACK(Packet);
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_DESERIALIZE))
{
RAISE_IRQL_TO_DISPATCH(&OldIrql);
}
//
// Indicate to Protocol;
//
(Open->TransferDataCompleteHandler)(Open->ProtocolBindingContext,
Packet,
Status,
BytesTransferred);
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_DESERIALIZE))
{
LOWER_IRQL(OldIrql, DISPATCH_LEVEL);
}
}
}
NDIS_STATUS
ndisMTransferData(
IN NDIS_HANDLE NdisBindingHandle,
IN NDIS_HANDLE MacReceiveContext,
IN UINT ByteOffset,
IN UINT BytesToTransfer,
IN OUT PNDIS_PACKET Packet,
OUT PUINT BytesTransferred
)
{
PNDIS_OPEN_BLOCK Open = (PNDIS_OPEN_BLOCK)NdisBindingHandle;
PNDIS_MINIPORT_BLOCK Miniport = Open->MiniportHandle;
NDIS_STATUS Status;
ASSERT_MINIPORT_LOCKED(Miniport);
//
// Handle non-loopback (non-indicated) as the default case.
//
if ((MacReceiveContext == INDICATED_PACKET(Miniport)) &&
(INDICATED_PACKET(Miniport) != NULL))
{
PNDIS_PACKET_OOB_DATA pOob;
//
// This packet is a indicated (or possibly a loopback) packet
//
pOob = NDIS_OOB_DATA_FROM_PACKET((PNDIS_PACKET)MacReceiveContext);
NdisCopyFromPacketToPacketSafe(Packet,
0,
BytesToTransfer,
(PNDIS_PACKET)MacReceiveContext,
ByteOffset + pOob->HeaderSize,
BytesTransferred,
NormalPagePriority);
Status = (*BytesTransferred == BytesToTransfer) ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE;
}
else
{
PUSH_XFER_DATA_PACKET_STACK(Packet);
if (CONTAINING_RECORD(Packet, NDIS_PACKET_WRAPPER, Packet)->StackIndex.XferDataIndex >= 3 * ndisPacketStackSize)
{
POP_XFER_DATA_PACKET_STACK(Packet);
Status = NDIS_STATUS_RESOURCES;
}
else
{
PNDIS_BUFFER Buffer = Packet->Private.Head;
Status = NDIS_STATUS_SUCCESS;
if (!MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_DO_NOT_MAP_MDLS))
{
//
// miniport will not use safe APIs
// so map the buffers in destination packet
//
Buffer = Packet->Private.Head;
while (Buffer != NULL)
{
if (MDL_ADDRESS_SAFE(Buffer, HighPagePriority) == NULL)
{
Status = NDIS_STATUS_RESOURCES;
break;
}
Buffer = Buffer->Next;
}
}
if (Status == NDIS_STATUS_SUCCESS)
{
SET_CURRENT_XFER_DATA_PACKET_STACK(Packet, Open)
//
// Call Miniport.
//
Status = (Open->WTransferDataHandler)(Packet,
BytesTransferred,
Open->MiniportAdapterContext,
MacReceiveContext,
ByteOffset,
BytesToTransfer);
if (Status != NDIS_STATUS_PENDING)
{
SET_CURRENT_XFER_DATA_PACKET_STACK(Packet, 0);
POP_XFER_DATA_PACKET_STACK(Packet);
}
}
}
}
return Status;
}
NDIS_STATUS
ndisMWanSend(
IN NDIS_HANDLE NdisBindingHandle,
IN NDIS_HANDLE NdisLinkHandle,
IN PNDIS_WAN_PACKET Packet
)
{
PNDIS_OPEN_BLOCK Open = ((PNDIS_OPEN_BLOCK)NdisBindingHandle);
PNDIS_MINIPORT_BLOCK Miniport = Open->MiniportHandle;
NDIS_STATUS Status;
BOOLEAN LocalLock = FALSE;
KIRQL OldIrql = PASSIVE_LEVEL;
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("==>ndisMWanSend\n"));
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_PM_HALTING))
{
return NDIS_STATUS_FAILURE;
}
if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_DESERIALIZE))
{
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
LOCK_MINIPORT(Miniport, LocalLock);
}
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_DESERIALIZE) || LocalLock)
{
//
// Call Miniport to send WAN packet
//
if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_DESERIALIZE))
{
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
}
Status = (Miniport->DriverHandle->MiniportCharacteristics.WanSendHandler)(
Miniport->MiniportAdapterContext,
NdisLinkHandle,
Packet);
if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_DESERIALIZE))
{
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
}
//
// Process the status of the send.
//
if (NDIS_STATUS_PENDING == Status)
{
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("ndisMWanSend: send is pending\n"));
}
else
{
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("ndisMWanSend: Completed 0x%x\n", Status));
}
}
else
{
LINK_WAN_PACKET(Miniport, Packet);
Packet->MacReserved1 = NdisLinkHandle;
NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL);
if (LocalLock)
{
NDISM_PROCESS_DEFERRED(Miniport);
}
Status = NDIS_STATUS_PENDING;
}
if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_DESERIALIZE))
{
UNLOCK_MINIPORT(Miniport, LocalLock);
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
}
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("<==ndisMWanSend\n"));
return Status;
}
VOID
NdisMWanSendComplete(
IN NDIS_HANDLE MiniportAdapterHandle,
IN PNDIS_WAN_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_OPEN_BLOCK Open;
KIRQL OldIrql = PASSIVE_LEVEL;
ASSERT_MINIPORT_LOCKED(Miniport);
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("==>ndisMWanSendComplete\n"));
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("packet 0x%x\n", Packet));
ASSERT_MINIPORT_LOCKED(Miniport);
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_DESERIALIZE))
{
RAISE_IRQL_TO_DISPATCH(&OldIrql);
}
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
for (Open = Miniport->OpenQueue; Open != NULL; Open = Open->MiniportNextOpen)
{
//
// Call Protocol to complete open
//
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
(Open->ProtocolHandle->ProtocolCharacteristics.WanSendCompleteHandler)(
Open->ProtocolBindingContext,
Packet,
Status);
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
}
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_DESERIALIZE))
{
LOWER_IRQL(OldIrql, DISPATCH_LEVEL);
}
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("<==ndisMWanSendComplete\n"));
}
BOOLEAN
FASTCALL
ndisMStartWanSends(
IN PNDIS_MINIPORT_BLOCK Miniport
)
/*++
Routine Description:
Submits as many sends as possible to the WAN mini-port.
Arguments:
Miniport - Miniport to send to.
Return Value:
None
--*/
{
PNDIS_WAN_PACKET Packet;
PLIST_ENTRY Link;
NDIS_STATUS Status;
ASSERT_MINIPORT_LOCKED(Miniport);
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("==>ndisMStartSends\n"));
while (!IsListEmpty(&Miniport->PacketList))
{
Link = Miniport->PacketList.Flink;
Packet = CONTAINING_RECORD(Link, NDIS_WAN_PACKET, WanPacketQueue);
UNLINK_WAN_PACKET(Packet);
//
// Call Miniport to send WAN packet
//
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
Status = (Miniport->DriverHandle->MiniportCharacteristics.WanSendHandler)(
Miniport->MiniportAdapterContext,
Packet->MacReserved1,
Packet);
//
// Process the status of the send.
//
if (NDIS_STATUS_PENDING == Status)
{
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("ndisMWanSend: send is pending\n"));
}
else
{
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("ndisMWanSend: Completed 0x%x\n", Status));
NdisMWanSendComplete(Miniport, Packet, Status);
}
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
}
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("<==ndisMStartSends\n"));
return(FALSE);
}
VOID
ndisMCopyFromPacketToBuffer(
IN PNDIS_PACKET Packet,
IN UINT Offset,
IN UINT BytesToCopy,
OUT PUCHAR 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;
VirtualAddress = MDL_ADDRESS_SAFE(CurrentBuffer, NormalPagePriority);
CurrentLength = MDL_SIZE(CurrentBuffer);
if (VirtualAddress == NULL)
return;
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;
VirtualAddress = MDL_ADDRESS_SAFE(CurrentBuffer, NormalPagePriority);
if (VirtualAddress == NULL)
break;
CurrentLength = MDL_SIZE(CurrentBuffer);
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 = Buffer + AmountToMove;
VirtualAddress = (PCHAR)VirtualAddress + AmountToMove;
LocalBytesCopied += AmountToMove;
CurrentLength -= AmountToMove;
}
}
*BytesCopied = LocalBytesCopied;
}
NDIS_STATUS
ndisMRejectSend(
IN NDIS_HANDLE NdisBindingHandle,
IN PNDIS_PACKET Packet
)
/*++
Routine Description:
This routine handles any error cases where a protocol binds to an Atm
miniport and tries to use the normal NdisSend() call.
Arguments:
NdisBindingHandle - Handle returned by NdisOpenAdapter.
Packet - the Ndis packet to send
Return Value:
NDIS_STATUS - always fails
--*/
{
UNREFERENCED_PARAMETER(NdisBindingHandle);
UNREFERENCED_PARAMETER(Packet);
return(NDIS_STATUS_NOT_SUPPORTED);
}
VOID
ndisMRejectSendPackets(
IN PNDIS_OPEN_BLOCK OpenBlock,
IN PPNDIS_PACKET Packet,
IN UINT NumberOfPackets
)
/*++
Routine Description:
This routine handles any error cases where a protocol binds to an Atm
miniport and tries to use the normal NdisSend() call.
Arguments:
OpenBlock - Pointer to the NdisOpenBlock
Packet - Pointer to the array of packets to send
NumberOfPackets - self-explanatory
Return Value:
None - SendCompleteHandler is called for the protocol calling this.
--*/
{
UINT i;
for (i = 0; i < NumberOfPackets; i++)
{
MINIPORT_CLEAR_PACKET_FLAG(Packet[i], fPACKET_CLEAR_ITEMS);
(*OpenBlock->SendCompleteHandler)(OpenBlock->ProtocolBindingContext,
Packet[i],
NDIS_STATUS_NOT_SUPPORTED);
}
}
VOID
NdisIMCopySendPerPacketInfo(
IN PNDIS_PACKET DstPacket,
IN PNDIS_PACKET SrcPacket
)
/*++
Routine Description:
This routine is used by IM miniport and copies all relevant per packet info from
the SrcPacket to the DstPacket. Used in the Send Code path
Arguments:
DstPacket - Pointer to the destination packet
SrcPacket - Pointer to the Source Packet
Return Value:
--*/
{
PVOID * pDstInfo;
PVOID * pSrcInfo;
pDstInfo = NDIS_PACKET_EXTENSION_FROM_PACKET(DstPacket)->NdisPacketInfo;
pSrcInfo = NDIS_PACKET_EXTENSION_FROM_PACKET(SrcPacket)->NdisPacketInfo;
pDstInfo[TcpIpChecksumPacketInfo] = pSrcInfo[TcpIpChecksumPacketInfo];
pDstInfo[IpSecPacketInfo] = pSrcInfo[IpSecPacketInfo];
pDstInfo[TcpLargeSendPacketInfo] = pSrcInfo[TcpLargeSendPacketInfo];
pDstInfo[ClassificationHandlePacketInfo] = pSrcInfo[ClassificationHandlePacketInfo];
pDstInfo[Ieee8021pPriority] = pSrcInfo[Ieee8021pPriority];
pDstInfo[PacketCancelId] = pSrcInfo[PacketCancelId];
DstPacket->Private.NdisPacketFlags &= ~fPACKET_WRAPPER_RESERVED;
DstPacket->Private.NdisPacketFlags |= SrcPacket->Private.NdisPacketFlags & fPACKET_WRAPPER_RESERVED;
}
EXPORT
VOID
NdisIMCopySendCompletePerPacketInfo(
IN PNDIS_PACKET DstPacket,
IN PNDIS_PACKET SrcPacket
)
/*++
Routine Description:
This routine is used by IM miniport and copies all relevant per packet info from
the SrcPacket to the DstPacket. Used in the SendComplete Code path
Arguments:
DstPacket - Pointer to the destination packet
SrcPacket - Pointer to the Source Packet
Return Value:
--*/
{
PVOID * pDstInfo;
pDstInfo = NDIS_PACKET_EXTENSION_FROM_PACKET(DstPacket)->NdisPacketInfo;
pDstInfo[TcpLargeSendPacketInfo] = NDIS_PER_PACKET_INFO_FROM_PACKET(SrcPacket, TcpLargeSendPacketInfo);
}
VOID
ndisMSendPacketsSG(
IN NDIS_HANDLE NdisBindingHandle,
IN PPNDIS_PACKET PacketArray,
IN UINT NumberOfPackets
)
{
PNDIS_OPEN_BLOCK Open = (PNDIS_OPEN_BLOCK)NdisBindingHandle;
PNDIS_STACK_RESERVED NSR;
PNDIS_MINIPORT_BLOCK Miniport = Open->MiniportHandle;
NDIS_STATUS Status;
KIRQL OldIrql;
UINT c;
PPNDIS_PACKET pPktArray;;
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("==>ndisMSendPacketsSG\n"));
ASSERT(MINIPORT_TEST_FLAG(Miniport, fMINIPORT_SG_LIST));
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
Status = NDIS_STATUS_SUCCESS;
//
// Place the packets on the miniport queue.
//
for (c = 0, pPktArray = PacketArray;
c < NumberOfPackets;
c++, pPktArray++)
{
PNDIS_PACKET Packet = *pPktArray;
ASSERT(Packet != NULL);
PUSH_PACKET_STACK(Packet);
NDIS_STACK_RESERVED_FROM_PACKET(Packet, &NSR);
NSR->Open = Open;
CHECK_FOR_DUPLICATE_PACKET(Miniport, Packet);
if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_DO_NOT_MAP_MDLS))
{
ndisMCheckPacketAndGetStatsOutAlreadyMapped(Miniport, Packet);
}
else
{
ndisMCheckPacketAndGetStatsOut(Miniport, Packet, &Status);
}
NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_PENDING);
MINIPORT_CLEAR_PACKET_FLAG(Packet, fPACKET_SELF_DIRECTED);
DBGPRINT(DBG_COMP_OPENREF, DBG_LEVEL_INFO,
("+ Open 0x%x Reference 0x%x\n", NdisBindingHandle, Open->References));
M_OPEN_INCREMENT_REF_INTERLOCKED(Open);
if (Status != NDIS_STATUS_SUCCESS)
{
NDISM_COMPLETE_SEND_SG(Miniport, Packet, NSR, Status, TRUE, 0, FALSE);
}
else
{
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
ndisMAllocSGListS(Miniport, Packet);
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
}
}
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("<==ndisMSendPacketsSG\n"));
}
NDIS_STATUS
ndisMSendSG(
IN NDIS_HANDLE NdisBindingHandle,
IN PNDIS_PACKET Packet
)
/*++
Routine Description:
nsiaMSend for serialized drivers that handle SG lists
Arguments:
Return Value:
None.
--*/
{
PNDIS_OPEN_BLOCK Open = ((PNDIS_OPEN_BLOCK)NdisBindingHandle);
PNDIS_MINIPORT_BLOCK Miniport = Open->MiniportHandle;
PNDIS_STACK_RESERVED NSR;
NDIS_STATUS Status;
KIRQL OldIrql;
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("==>ndisMSendSG\n"));
ASSERT(MINIPORT_TEST_FLAG(Miniport, fMINIPORT_SG_LIST));
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
CHECK_FOR_DUPLICATE_PACKET(Miniport, Packet);
if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_DO_NOT_MAP_MDLS))
{
Status = NDIS_STATUS_SUCCESS;
ndisMCheckPacketAndGetStatsOutAlreadyMapped(Miniport, Packet);
}
else
{
ndisMCheckPacketAndGetStatsOut(Miniport, Packet, &Status);
}
if (Status == NDIS_STATUS_SUCCESS)
{
MINIPORT_CLEAR_PACKET_FLAG(Packet, fPACKET_SELF_DIRECTED);
//
// Increment the references on this open.
//
M_OPEN_INCREMENT_REF_INTERLOCKED(Open);
DBGPRINT(DBG_COMP_OPENREF, DBG_LEVEL_INFO,
("+ Open 0x%x Reference 0x%x\n", NdisBindingHandle, ((PNDIS_OPEN_BLOCK)NdisBindingHandle)->References));
PUSH_PACKET_STACK(Packet);
NDIS_STACK_RESERVED_FROM_PACKET(Packet, &NSR)
NSR->Open = Open;
Status = NDIS_STATUS_PENDING;
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
ndisMAllocSGListS(Miniport, Packet);
}
else
{
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
}
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("<==ndisMSendSG\n"));
return Status;
}
VOID
ndisMSendCompleteSG(
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_STACK_RESERVED NSR;
ASSERT_MINIPORT_LOCKED(Miniport);
#if DBG
Miniport->cDpcSendCompletes++;
#endif
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("==>ndisMSendCompleteSG\n"));
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("packet 0x%x\n", Packet));
NDIS_STACK_RESERVED_FROM_PACKET(Packet, &NSR)
ASSERT(VALID_OPEN(NSR->Open));
ASSERT(MINIPORT_TEST_PACKET_FLAG(Packet, fPACKET_PENDING));
//
// Guard against double/bogus completions.
//
if (VALID_OPEN(NSR->Open) &&
MINIPORT_TEST_PACKET_FLAG(Packet, fPACKET_PENDING))
{
ASSERT(Packet != Miniport->FirstPendingPacket);
if (MINIPORT_TEST_PACKET_FLAG(Packet, fPACKET_DONT_COMPLETE))
{
//
// If the packet completed in the context of a SendPackets, then
// defer completion. It will get completed when we unwind.
//
NDIS_SET_PACKET_STATUS(Packet, Status);
MINIPORT_CLEAR_PACKET_FLAG(Packet, fPACKET_DONT_COMPLETE);
}
else
{
NDISM_COMPLETE_SEND_SG(Miniport, Packet, NSR, Status, FALSE, 1, TRUE);
}
}
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("<==ndisMSendCompleteSG\n"));
}
BOOLEAN
FASTCALL
ndisMStartSendPacketsSG(
IN PNDIS_MINIPORT_BLOCK Miniport
)
{
PNDIS_PACKET Packet;
NDIS_STATUS Status;
PNDIS_STACK_RESERVED NSR;
PPNDIS_PACKET pPktArray;
PNDIS_PACKET PacketArray[SEND_PACKET_ARRAY];
UINT MaxPkts = Miniport->MaxSendPackets;
W_SEND_PACKETS_HANDLER SendPacketsHandler = Miniport->WSendPacketsHandler;
BOOLEAN SelfDirected;
ASSERT_MINIPORT_LOCKED(Miniport);
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("==>ndisMStartSendPacketsSG\n"));
//
// We could possibly end up with a situation (with intermediate serialized
// miniports) where there are no packets down with the driver and we the
// resource window is closed. In such a case open it fully. We are seeing this
// with wlbs
//
if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESOURCES_AVAILABLE) &&
(Miniport->FirstPendingPacket == NULL))
{
ADD_RESOURCE(Miniport, 'X');
}
//
// Work-around for a scenario we are hitting when PacketList is empty but FirstPendingPacket is NOT
// Not sure how this can happen - yet.
//
if (IsListEmpty(&Miniport->PacketList))
{
ASSERT (Miniport->FirstPendingPacket == NULL);
Miniport->FirstPendingPacket = NULL;
}
while ((Miniport->FirstPendingPacket != NULL) &&
MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESOURCES_AVAILABLE))
{
UINT Count;
UINT NumberOfPackets;
ASSERT(!IsListEmpty(&Miniport->PacketList));
//
// Initialize the packet array.
//
pPktArray = PacketArray;
//
// Place as many packets as we can in the packet array to send
// to the miniport.
//
for (NumberOfPackets = 0;
(NumberOfPackets < MaxPkts) && (Miniport->FirstPendingPacket != NULL);
NOTHING)
{
//
// Grab the packet off of the pending queue.
//
ASSERT(!IsListEmpty(&Miniport->PacketList));
Packet = Miniport->FirstPendingPacket;
NDIS_STACK_RESERVED_FROM_PACKET(Packet, &NSR)
ASSERT(VALID_OPEN(NSR->Open));
NEXT_PACKET_PENDING(Miniport, Packet);
//
// Indicate the packet loopback if necessary.
//
if (NDIS_CHECK_FOR_LOOPBACK(Miniport, Packet))
{
SelfDirected = ndisMLoopbackPacketX(Miniport, Packet);
}
else
{
SelfDirected = FALSE;
}
if (SelfDirected)
{
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("Packet 0x%x is self-directed.\n", Packet));
//
// Complete the packet back to the binding.
//
NDISM_COMPLETE_SEND_SG(Miniport, Packet, NSR, NDIS_STATUS_SUCCESS, TRUE, 2, TRUE);
//
// No, we don't want to increment the counter for the
// miniport's packet array.
//
}
else
{
//
// We have to re-initialize this.
//
*pPktArray = Packet;
MINIPORT_SET_PACKET_FLAG(Packet, (fPACKET_DONT_COMPLETE | fPACKET_PENDING));
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)
{
break;
}
pPktArray = PacketArray;
{
//
// Pass the packet array down to the miniport.
//
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
(SendPacketsHandler)(Miniport->MiniportAdapterContext,
pPktArray,
NumberOfPackets);
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
}
//
// Process the packet completion.
//
for (Count = 0; Count < NumberOfPackets; Count++, pPktArray++)
{
Packet = *pPktArray;
ASSERT(Packet != NULL);
Status = NDIS_GET_PACKET_STATUS(*pPktArray);
MINIPORT_CLEAR_PACKET_FLAG(Packet, fPACKET_DONT_COMPLETE);
//
// Process the packet based on it's return status.
//
if (NDIS_STATUS_PENDING == Status)
{
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("Complete is pending\n"));
}
else if (Status != NDIS_STATUS_RESOURCES)
{
//
// Remove from the finish queue.
//
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("Completed packet 0x%x with status 0x%x\n",
Packet, Status));
NDIS_STACK_RESERVED_FROM_PACKET(Packet, &NSR)
if (VALID_OPEN(NSR->Open))
{
NDISM_COMPLETE_SEND_SG(Miniport, Packet, NSR, Status, TRUE, 3, TRUE);
}
}
else
{
//
// Once we hit a return code of NDIS_STATUS_RESOURCES
// for a packet then we must break out and re-queue.
//
UINT i;
Miniport->FirstPendingPacket = Packet;
CLEAR_RESOURCE(Miniport, 'S');
for (i = Count; i < NumberOfPackets; i++)
{
PNDIS_PACKET QueuedPacket = PacketArray[i];
MINIPORT_CLEAR_PACKET_FLAG(QueuedPacket, fPACKET_PENDING);
VALIDATE_PACKET_OPEN(QueuedPacket);
}
break;
}
}
}
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("<==ndisMStartSendPacketsSG\n"));
return(FALSE);
}
BOOLEAN
FASTCALL
ndisMStartSendsSG(
IN 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_STACK_RESERVED NSR;
NDIS_STATUS Status;
PNDIS_OPEN_BLOCK Open;
ASSERT_MINIPORT_LOCKED(Miniport);
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("==>ndisMStartSendsSG\n"));
while ((Miniport->FirstPendingPacket != NULL) &&
MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESOURCES_AVAILABLE))
{
//
// Grab the packet off of the pending queue.
//
ASSERT(!IsListEmpty(&Miniport->PacketList));
Packet = Miniport->FirstPendingPacket;
NDIS_STACK_RESERVED_FROM_PACKET(Packet, &NSR)
NEXT_PACKET_PENDING(Miniport, Packet);
Open = NSR->Open;
ASSERT(VALID_OPEN(Open));
//
// we can use the same NDISM_SEND_PACKET we do for non SG miniports
//
NDISM_SEND_PACKET(Miniport, Open, Packet, &Status);
//
// Process the packet pending completion status.
//
if (NDIS_STATUS_PENDING == Status)
{
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("Complete is pending\n"));
}
else
{
MINIPORT_CLEAR_PACKET_FLAG(Packet, fPACKET_PENDING);
//
// Handle the completion and resources cases.
//
if (Status == NDIS_STATUS_RESOURCES)
{
NDISM_COMPLETE_SEND_RESOURCES(Miniport, NSR, Packet);
}
else
{
NDISM_COMPLETE_SEND_SG(Miniport, Packet, NSR, Status, TRUE, 4, TRUE);
}
}
}
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("<==ndisMStartSendsSG\n"));
return(FALSE);
}