2629 lines
72 KiB
C
2629 lines
72 KiB
C
/*++
|
|
|
|
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 (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);
|
|
}
|
|
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;
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
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
|
|
//
|
|
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))
|
|
{
|
|
//
|
|
// 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;
|
|
PNDIS_PACKET_EXTENSION PktExt;
|
|
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;
|
|
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(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;
|
|
|
|
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))
|
|
{
|
|
ndisMLoopbackPacketX(Miniport, Packet);
|
|
}
|
|
|
|
if (!MINIPORT_TEST_PACKET_FLAG(Packet, fPACKET_SELF_DIRECTED))
|
|
{
|
|
//
|
|
// 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);
|
|
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_OPEN_BLOCK Open;
|
|
PNDIS_STACK_RESERVED NSR;
|
|
|
|
ASSERT_MINIPORT_LOCKED(Miniport);
|
|
|
|
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;
|
|
|
|
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
|
|
//
|
|
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, NSR);
|
|
|
|
//
|
|
// 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 Packet = PacketArray[i];
|
|
|
|
MINIPORT_CLEAR_PACKET_FLAG(Packet, fPACKET_PENDING);
|
|
VALIDATE_PACKET_OPEN(Packet);
|
|
}
|
|
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)
|
|
NEXT_PACKET_PENDING(Miniport, 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
|
|
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;
|
|
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) = -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 (ARGUMENT_PRESENT(LoopbackPacket))
|
|
{
|
|
*LoopbackPacket = pNewPacket;
|
|
MINIPORT_SET_PACKET_FLAG(pNewPacket, fPACKET_IS_LOOPBACK);
|
|
pNewPacket->Private.Flags = NdisGetPacketFlags(Packet) & NDIS_FLAGS_DONT_LOOPBACK;
|
|
}
|
|
} while (FALSE);
|
|
|
|
if (NDIS_STATUS_SUCCESS != Status)
|
|
{
|
|
if (NULL != pNewPacket)
|
|
{
|
|
pNewPacket = (PNDIS_PACKET)((PUCHAR)pNewPacket - SIZE_PACKET_STACKS);
|
|
FREE_POOL(pNewPacket);
|
|
}
|
|
|
|
*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;
|
|
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;
|
|
|
|
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;
|
|
PNDIS_STACK_RESERVED NSR;
|
|
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;
|
|
KIRQL OldIrql;
|
|
|
|
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;
|
|
|
|
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;
|
|
PNDIS_M_OPEN_BLOCK Open;
|
|
|
|
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 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;
|
|
|
|
VirtualAddress = MDL_ADDRESS_SAFE(CurrentBuffer, NormalPagePriority);
|
|
CurrentLength = MDL_SIZE(CurrentBuffer);
|
|
|
|
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;
|
|
}
|
|
|
|
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
|
|
|
|
--*/
|
|
{
|
|
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;
|
|
BOOLEAN LocalLock;
|
|
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;
|
|
PNDIS_PACKET_EXTENSION PktExt;
|
|
NDIS_STATUS Status;
|
|
BOOLEAN LocalLock;
|
|
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(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_OPEN_BLOCK Open;
|
|
PNDIS_STACK_RESERVED NSR;
|
|
|
|
ASSERT_MINIPORT_LOCKED(Miniport);
|
|
|
|
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, NSR);
|
|
|
|
//
|
|
// 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 Packet = PacketArray[i];
|
|
|
|
MINIPORT_CLEAR_PACKET_FLAG(Packet, fPACKET_PENDING);
|
|
VALIDATE_PACKET_OPEN(Packet);
|
|
}
|
|
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, NSR);
|
|
|
|
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);
|
|
}
|
|
|